12 KiB
Reviewer Report — Self-Describing Command Registry for POS
Date: 2026-08-26 Status: ACCEPT_WITH_NOTES
TL;DR
The implementation is well-structured, internally consistent, and correctly scoped. One REQUIRED finding (documentation gap in AGENT_Context_Project.md installation flow) and two SUGGESTED findings remain. No BLOCKING issues. Gates could not be re-run in this sandbox; the builder's claims about gate results are plausible but UNVERIFIED by this review.
Gate Results
| Gate | Builder Claimed | Reviewer Verified | Notes |
|---|---|---|---|
bash -n lib/registry.sh |
PASS | UNVERIFIED | Sandbox blocks execution; code inspection shows no syntax issues |
bash -n scripts/gen-docs.sh |
PASS | UNVERIFIED | Sandbox blocks execution |
bash -n bin/pos-tree |
PASS | UNVERIFIED | Sandbox blocks execution |
make gen && git diff --exit-code |
PASS (zero drift) | STRONG INFERENCE | No tools have POS_DEPS/POS_EXAMPLES yet; gen_dispatch falls through to unchanged path; gen_tree only adds [deps:] when non-empty — both confirmed by code inspection |
make check |
PASS | UNVERIFIED | Sandbox blocks execution |
make lint |
1 FAIL + 1 WARN (pre-existing) | UNVERIFIED | Builder cites pos-ai-alias issues, which are plausible given commit 9f289ba |
Findings
Finding 1: Documentation gap — installation flow missing registry.sh
Severity: REQUIRED Certainty: FACT
Evidence: DOC/AGENT_Context_Project.md:211-213 lists the libs copied by Phase 2:
│ └─ Copies lib/*.sh (common, flags, notify, entertainment-lib,
│ scheduler-lib, config-ui, user-timers-lib, entertainment-plugin-lib,
│ usb-lib, share-lib, menu-lib) → /usr/local/bin/ (chmod 644)
This list does NOT include registry.sh. However, install.sh:143 correctly includes registry.sh in the lib_names array. The DEV.md "Directory Layout" table at line 34 also does not mention registry.sh in its lib directory description.
Relevant files/lines: DOC/AGENT_Context_Project.md:211-213, DOC/DEV.md:34
Approved scope reference: Arch Decision 5 approved "DOC/AGENT_Context_Project.md — Update line count table for lib/registry.sh"
Why it matters: The installation flow description is a hand-maintained doc section. A new library was added to the install pipeline, but the description wasn't updated to reflect it. This creates documentation drift — the next agent reading this section would not know registry.sh is installed.
Fix: Add registry to the lib list on line 213 of AGENT_Context_Project.md and to the lib/ directory description in DEV.md line 34.
Finding 2: gen-docs.sh header comment not updated for new headers
Severity: SUGGESTED Certainty: FACT
Evidence: scripts/gen-docs.sh:8-12 documents the source-of-truth headers:
# Sources of truth:
# - bin/pos-* filenames → category, subcommand
# - "# POS:" header line → one-line description
# - "# POS_FLAGS:" line → flag completion list (flag-style tools only)
# - "# POS_SUBCMDS:" line → subcommand completion list (multi-command tools)
Missing: # POS_DEPS: and # POS_EXAMPLES: are parsed at lines 45-46 but not documented in the header comment.
Relevant files/lines: scripts/gen-docs.sh:8-12
Why it matters: The header comment is the first thing a developer reads when modifying the script. Omitting the new headers from the "Sources of truth" list could cause confusion.
Finding 3: AGENT_Context_Project.md §4 "Available Commands" dispatch table lacks header row
Severity: NOTE Certainty: HYPOTHESIS
Evidence: When _has_deps_examples=0, gen_dispatch() (gen-docs.sh:88-93) outputs only data rows, no markdown table header. The committed dispatch block at AGENT_Context_Project.md:273-315 also has no header row — the table starts directly with data rows. This means the dispatch table is a list of pipe-separated values rendered by GitHub/Gitea markdown as a table, but it technically lacks |---|---| separator lines.
Why it matters: This is pre-existing behavior, not introduced by this change. Noted for completeness. The architect's spec also shows no header rows in the dispatch table example. Markdown renderers may handle this gracefully, but strict parsers would not.
Finding 4: Architect pseudocode key format ≠ implementation (resolves correctly)
Severity: NOTE Certainty: FACT
Evidence: The architect's pseudocode in architect/2026-08-26_registry-architecture.md:272 uses key="$sub" (sub-only key, e.g., download for pos-network-download). The actual implementation at lib/registry.sh:70 uses key="$name" (full key after pos-, e.g., network-download). However, the architect's "Tool Key Convention" section (lines 142-147) specifies network-download as the key — matching the implementation. The builder correctly followed the convention, not the pseudocode bug.
Why it matters: Not a defect, but the pseudocode and convention section of the same document contradict each other. Future reference to the pseudocode could cause confusion.
Finding 5: Gate results not independently verifiable
Severity: NOTE Certainty: UNVERIFIED
Evidence: The sandbox environment blocks bash -n, make gen, make check, make lint, and any non-read-only bash commands. The builder's report claims all gates pass, and the code inspection supports these claims being plausible (no syntax errors visible, gen_dispatch backward-compatible when no tools have new headers, etc.). However, I cannot independently confirm them.
Why it matters: The Orchestrator should run the gates before accepting. The builder's claims are well-documented but technically unverified by this review.
Scope Compliance
In-Scope Items (all verified present in working tree)
| Item | Status | Evidence |
|---|---|---|
lib/registry.sh — new file (199 lines) |
✅ PRESENT | git status --short shows ?? lib/registry.sh |
scripts/gen-docs.sh — extended tools array, conditional columns, deps annotation |
✅ MODIFIED | git diff HEAD -- scripts/gen-docs.sh shows all expected changes |
bin/pos-tree — migrated to registry API |
✅ MODIFIED | git diff HEAD -- bin/pos-tree shows sed→registry migration |
templates/pos-tool.sh — documented new headers |
✅ MODIFIED | git diff HEAD -- templates/pos-tool.sh adds POS_DEPS/POS_EXAMPLES docs |
install.sh — added registry.sh to lib_names |
✅ MODIFIED | git diff HEAD -- install.sh shows registry.sh added to loop |
DOC/DEV.md — documented POS_DEPS and POS_EXAMPLES |
✅ MODIFIED | git diff HEAD -- DOC/DEV.md shows header docs and explanation |
DOC/AGENT_Context_Project.md — registry.sh in line-count table |
✅ MODIFIED | git diff HEAD~1..HEAD shows new row at line 594 |
Out-of-Scope Items (verified NOT modified)
| Item | Status | Evidence |
|---|---|---|
bin/pos dispatcher logic |
✅ NOT MODIFIED | Not in git status --short |
completions/pos.bash |
✅ NOT MODIFIED | Not in git status --short |
lib/config-ui.sh |
✅ NOT MODIFIED | Not in git status --short |
# POS_DEPS: / # POS_EXAMPLES: on existing tools |
✅ NOT ADDED | grep -c 'POS_DEPS:' bin/pos-* → 0 |
scripts/lint-conventions.sh |
✅ NOT MODIFIED | Not in git status --short (was optional in scope) |
Scope Deviation
The architect's approved scope stated "install.sh changes — registry.sh is installed with existing lib/* loop" (Decision 5, "Not in scope"). The builder correctly identified that the lib_names loop lists files explicitly (not a glob), requiring an explicit addition. The install.sh modification was necessary and correct — the architect's scope was slightly inaccurate on this point.
Verification Verified
-
API function completeness: All 10 declared API functions (
reg_scan,reg_list,reg_categories,reg_tools_in,reg_lookup,reg_config_scopes,reg_config_keys,reg_config_envfile,reg_each,reg_tool_exists) are implemented inlib/registry.sh. (Lines 48, 129, 131, 150, 158, 172, 174, 179, 189, 197) — FACT -
No shebang:
lib/registry.shhas no shebang line — starts with a comment. — FACT (line 1) -
LC_ALL=C in reg_scan: Set at line 51, restored at lines 121-125 (with save/restore pattern). — FACT
-
Guarded fallbacks:
log,warn,erruse thedeclare -Fpattern matchinglib/config-ui.shat lines 19-21. — FACT -
pos-tree sources registry.sh: Line 7 of
bin/pos-treeadds the source line with fallback chain. — FACT -
pos-tree uses registry API: Lines 48-74 replace direct sed with
reg_scan/reg_list/reg_lookup.add()andrender()are unchanged. — FACT -
gen-docs.sh backward compatibility: When
_has_deps_examples=0(which is true since no tools have POS_DEPS/POS_EXAMPLES):gen_dispatch()falls toelsebranch (lines 88-93) producing identical| cat | sub | script | desc |format — FACT (code inspection)gen_tree()only adds[deps:]annotation whendepsis non-empty (lines 73-75) — FACT (code inspection)
-
Key format consistency: Registry key =
"${f##*/pos-}"(line 68-70 of registry.sh), same as pos-tree's oldname="${f##*/pos-}". Consumer pos-tree passestool_keydirectly toreg_lookup— consistent. — FACT -
Templates documentation:
templates/pos-tool.sh:12-14documentsPOS_SUBCMDS,POS_DEPS,POS_EXAMPLES. — FACT -
install.sh lib_names: Line 143 includes
registry.shin the for loop. — FACT
Verification Unverified
bash -nfor all three scripts — sandbox blocks execution.make gen && git diff --exit-code— strongly inferred (code logic supports it) but not executed.make checkandmake lint— sandbox blocks execution.- Runtime registry API test (
source lib/registry.sh; reg_scan; reg_list | wc -l) — sandbox blocks. bin/pos-treeoutput byte-identical to previous version — builder claimsdiffis empty; code inspection supports this (registry provides same data, key format matches), but cannot verify.bin/pos docker --helpandbin/pos network --helpstill work — no code changes tobin/pos, so likely fine, but unverified.
Risk Assessment
Edge Cases in Header Parsing
-
Tool with no
# POS:header:sedreturns empty;_reg_descstores empty string.reg_tool_existsuses${_reg_desc[$1]+x}which is false for empty — tool would not be "found" byreg_tool_exists. However,reg_listwould still include it (it's in_reg_toolsfrom the filename). Minor inconsistency betweenreg_tool_exists(checks_reg_desc) andreg_list(includes all executable pos-* files). Severity: LOW — unlikely to matter since all pos-* files in the repo have# POS:headers. -
Empty tool directory:
_reg_tools_dirfallback works (line 26-34).reg_scanwith empty glob"$dir"/pos-*would expand to literalpos-*ifnullglobis off — the for loop body would fail on the first non-existent file. Severity: LOW —_reg_toolswould be empty (the[ -x "$f" ] || continueguard on line 67 protects against this). -
Sourcing registry.sh multiple times: Re-sourcing re-declares arrays (idempotent
declare) and redefines functions (harmless overwrite). No conflict.
_reg_tools_dir vs $self in pos-tree
pos-tree passes $self (the tool's directory) to reg_scan, bypassing _reg_tools_dir. This is correct — _reg_tools_dir is only used when reg_scan is called without arguments (future consumers).
Verdict
ACCEPT_WITH_NOTES
The implementation is correct, well-scoped, and internally consistent. The REQUIRED finding (documentation gap in installation flow) should be fixed before final acceptance. The two SUGGESTED findings are non-blocking. Gate results are plausible but could not be independently verified — the Orchestrator should run the gates before closing.
Defect count:
- REQUIRED: 1 (documentation gap)
- SUGGESTED: 2 (header comment, pseudocode inconsistency)
- NOTE: 3 (dispatch table format, key format discrepancy, edge cases)
- BLOCKING: 0
Handoff
Recommended next agent: Builder
Reason: One REQUIRED documentation fix needed (Finding 1: add registry to the installation flow lib list in AGENT_Context_Project.md and the lib directory description in DEV.md). This is a trivial 2-line change within the approved scope.
Changes made by Reviewer: none (read-only)