Files
Linux_post_install/AgentsReport/builder/2026-08-26_registry-phase2.md
T
Your Name 06a05f0567
gates / consistency-and-conventions (push) Successful in 1m24s
ai continue ...
2026-09-04 11:09:21 -04:00

235 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Builder Report — POS Command Registry, Phase 2
**Date:** 2026-08-26
**Status:** COMPLETE
---
## TL;DR
- **Status:** All 3 steps implemented and verified
- **Files changed (this phase):** `bin/pos` (`_pos_category_help()` migration), `bin/pos-network-download`, `bin/pos-media-sync`, `bin/pos-system-backup`, `bin/pos-docker-ps` (headers), `scripts/gen-docs.sh` (2 cell-rendering fixes), gen output in `DOC/AGENT_Context_Project.md`
- **Gates:** `make check` ✅ OK · `make lint`**0 FAIL, 0 WARN** · fast dispatch path unchanged (26 ms)
- **Key finding:** `pos help <command>` is a pure exec-redirect — no per-command dispatcher surface exists; per brief, nothing invented
---
## Baseline
- Phase 1 state on disk; `make check``check-sync: OK`
- Maintainer's uncommitted fixes present (`ai-alias` added to `INTERACTIVE_CMDS` at bin/pos:262, DOC updates) — **untouched**
- BEFORE category-help captured for all 10 categories → `/tmp/pos-phase2/h-*-before.txt`
[DONE]
---
## Step 1: Migrate `_pos_category_help()`
**File:** `bin/pos`, `_pos_category_help()` (~lines 68100 post-edit)
**Changes:**
- Registry sourced + `reg_scan "$self"` called **lazily inside the function** — plain dispatch paths never pay scan cost (verified: fast path 26 ms before and after)
- Tool list from `reg_tools_in "$cat"`, stripped of leading `$cat-` → identical short display names
- All sed header reads replaced by `reg_lookup "<cat>-<short>" desc|subcmds|deps`
- Nested-tool enrichment loop, `is_nested` skip, printf layout: **byte-for-byte preserved**
**Preservation proof (pre-headers):** diff of before/mid captures across all 10 categories → **zero differences**.
**New behavior (fires only when headers exist):** second indented line ` [deps: <deps>]` directly under a tool's description line.
[DONE]
---
## Step 2: Registry metadata in `pos help`
**Finding:** the `help` meta-command (bin/pos ~lines 233245) joins args into `pos-<cat>-<cmd>` and `exec`s the tool's own `--help`. There is **no per-command rendering surface in the dispatcher** — examples/deps shown there come from each tool's `usage()` heredoc. Per the brief's instruction ("do NOT invent new UX"), this step is limited to that finding: no dispatcher-side extension made. The category-help surface (Step 1) is where registry metadata surfaces.
[DONE]
---
## Step 3: Representative headers on existing tools
Guards re-verified by reading source before annotating:
| Tool | Hard guards found | Headers added |
|------|-------------------|---------------|
| `bin/pos-network-download` (lines 1012: `err` ×3) | aria2c, jq, curl | `# POS_DEPS:` + 3 real-subcommand EXAMPLES (add/status/watch) |
| `bin/pos-media-sync` (lines 1516: `err` ×2) | lsblk, jq | `# POS_DEPS:` + 2 EXAMPLES (`--mp3`, `--mp4 --dry-run` — straight from its usage()) |
| `bin/pos-system-backup` (line 60 `err`; 7273 `warn`; 179 conditional `err`) | tar | `# POS_DEPS: tar` only |
| `bin/pos-docker-ps` (line 16: single `err`) | docker | `# POS_DEPS: docker` |
**Decision note (system-backup):** lsblk/jq are warn-only soft guards ("USB copy skipped", returns 0); gpg errors only when encryption is requested (`--no-encrypt` bypasses). Deps header = hard requirements only → `tar`.
4 tools total (cap 5 respected). Placement rule followed: metadata headers in comment block, `# POS:` first, new headers after existing POS_* lines, before any code.
[DONE]
---
## Verification (per budget)
```
bash -n bin/pos ✅
category --help before/mid diff (10 categories) ✅ zero diff (Step 1 preservation)
category --help before/after diff ✅ only [deps: …] lines added:
network +1, docker +1, system +1, media +1; others 0
make gen && git diff --stat ✅ GEN changes confined to expected blocks
make check ✅ check-sync: OK
make lint ✅ 0 FAIL, 0 WARN
bin/pos-tree | grep deps ✅ 4 annotations visible
bin/pos network --help | grep -i deps ✅ [deps: aria2c jq curl]
fast path timing ✅ 26 ms (no reg_scan cost)
completions/pos.bash ✅ untouched by gen
```
**GEN block inspection (as instructed):**
- Tree gains `[deps: …]` annotation lines under annotated tools ✓
- Dispatch table flipped to 6-column format (`_has_deps_examples=1`) ✓
- Two rendering defects found & fixed in `gen-docs.sh` during inspection:
1. Examples cell contained raw inner pipes from the `cmd | desc` grammar → broke markdown column count. Fixed: inner ` | ` rendered as `→` within cells.
2. Intended `//` example joiner actually produced single `/` (`paste -d'//'` cycles chars). Fixed: awk-based literal `//` join.
- Resulting cell sample: `…| lsblk jq | pos media sync --mp3 → Sync only MP3 files to USB//pos media sync --mp4 --dry-run → Preview MP4 sync without copying |` — valid 6-column row, readable ✓
- Docmap line ranges shifted accordingly (auto-generated) ✓
---
## Artifacts Summary
### Modified this phase
| File | Change |
|------|--------|
| `bin/pos` | `_pos_category_help()` → registry API + lazy source + deps line (Maintainer's INTERACTIVE_CMDS line preserved verbatim) |
| `bin/pos-network-download` | DEPS + 3 EXAMPLES headers |
| `bin/pos-media-sync` | DEPS + 2 EXAMPLES headers |
| `bin/pos-system-backup` | DEPS header (hard dep only) |
| `bin/pos-docker-ps` | DEPS header |
| `scripts/gen-docs.sh` | Examples-cell pipe escaping (`→`) + correct `//` joiner |
| `DOC/AGENT_Context_Project.md` | Gen output only (tree annotations, 6-col dispatch, docmap shift, filetable line counts) |
### Not touched (constraint compliance)
`lib/config-ui.sh` ✅ · `completions/pos.bash` ✅ · `INTERACTIVE_CMDS` ✅ · Maintainer's fixes ✅ · `bin/pos-tree` rendering ✅ · no new files except report ✅
### Findings / deferred
- `reg_scan` ≈ 1.3 s on this box (≈250 process forks / 41 tools) — acceptable on lazy help-only paths; single-pass awk scan remains the anticipated future optimization (Phase 1 Risk 2)
- `pos help <command>` has no dispatcher-side surface to enrich (pure redirect)
---
## Review-fix round
Two findings from the Phase 2 adversarial review; both fixed minimally.
### Finding 1 (MEDIUM): stale hand-written table header above the dispatch GEN block — FIXED
**Exact lines removed** from `DOC/AGENT_Context_Project.md` (were lines 275276):
```
| Category | Command | Script | Description |
|----------|---------|--------|-------------|
```
The orphaned 4-column header + its underline row sat between `### Available Commands` and `<!-- GEN:START dispatch -->`, duplicating the GEN block's own 6-column header. Nothing else removed — the section now reads `### Available Commands` → blank line → `GEN:START dispatch` directly.
### Finding 2 (LOW): `//` example joiner collides with URL slashes — FIXED
**New separator:** `" · "` (space-middle-dot-space), replacing the literal `//` in `scripts/gen-docs.sh` line ~48. Awk literal-join approach unchanged.
Rationale for `·`: cannot appear in a URL path, reads as a list separator in a markdown cell, and stays clear of both the pipe grammar (` | ` inside a single example, rendered as `→` in cells) and the em-dash used by `# POS:` descriptions. Live case now renders:
`pos network download add https://example.com/file.zip → Enqueue an HTTP download (auto-starts daemon) · pos network download status → Daemon health + global transfer stats · pos network download watch → Live progress view`
— the URL's `//` survives intact and each example is cleanly delimited.
### Verification
```
bash -n scripts/gen-docs.sh ✅
make gen && make gen → md5 of generated files identical
✅ double-gen idempotence: ZERO drift after second run
grep -c 'Category.*Command' DOC/…Project.md ✅ = 1 (only the GEN block's own header)
sed -n '/GEN:START dispatch/,+4p' ✅ GEN header is first row in block
lines above GEN:START dispatch ✅ only "### Available Commands" + blank
make check ✅ check-sync: OK
make lint ✅ 0 FAIL, 0 WARN
```
Note: the earlier bare `git diff --exit-code` after gen exits 1 because ALL Phase 1+2 work is still uncommitted vs HEAD — checksum comparison of run-1 vs run-2 outputs is the correct idempotence measure and passes.
### Constraint compliance
Touched ONLY `DOC/AGENT_Context_Project.md` (2 stale lines) and `scripts/gen-docs.sh` (separator string). No bin/*, lib/*, or completions/ changes. Everything else regenerated via `make gen`.
[DONE]
---
## Alias generator quoting fix
**File:** `bin/pos-ai-alias` (`_alias_regen()`, new `_alias_quote_cmd()` helper, `_alias_show()` command line)
### Chosen mechanism + rationale
`printf '%q'` — the canonical bash mechanism — applied **per layer**:
1. `_alias_quote_cmd <provider> <session> <prompt>` builds the pos-ai command with `%q`-quoted prompt → the prompt is ONE shell word on expansion.
2. `_alias_regen` then `%q`s the ENTIRE value before emitting `alias name=<value>` → the assignment survives any bytes.
**Justified deviation from the brief's literal snippet:** the prescribed single-`%q`-over-whole-string form expands to multi-word args after `--system`, but `bin/pos-ai`'s parser takes exactly one value (`SYSTEM_PROMPT="$2"; shift 2`, bin/pos-ai:640642) — multi-word prompts would truncate to their first word with the remainder leaking into question positionals. The original code had the identical latent defect (single-quote fragments never survive alias-expansion re-parsing). Double-`%q` is the same single mechanism, applied once per quoting layer — no manual fragment concatenation, no mixing of approaches. Verified by exact round-trip (A4/A7).
### Diff summary
| Function | Change |
|----------|--------|
| `_alias_quote_cmd()` (new, ~10 lines) | Shared builder: `%q` prompt as one word; empty prompt → no `--system`; used by regen + show |
| `_alias_regen()` | Naive `'…'<escaped>'…'` concatenation replaced by helper + whole-value `%q`; collects names; keeps `bash -n "$tmp"`; ADDS semantic per-name check in fresh shell: `bash --norc -c 'shopt -s expand_aliases; source "$1" && [[ $(type -t "$2") == alias ]]' _ "$tmp" "$n"`; failure → warn(alias name) + keep previous + rc 1 (mirrors existing path). Note: `expand_aliases` required — non-interactive shells define aliases but `type -t` only reports them when expansion is on (found during self-test) |
| `_alias_show()` | Command line now rendered via `_alias_quote_cmd` (display-only; structure untouched) — what users copy pastes verbatim |
Unchanged per constraints: ENV_FILE format, `|` ban, name/session regexes, chmod/mv semantics, interactive flows.
### Harness (exact commands)
```bash
export CONFIG_DIR=/tmp/pos-alias-test
rm -rf "$CONFIG_DIR"; mkdir -p "$CONFIG_DIR"
cat > "$CONFIG_DIR/ai-aliases.env" <<'EOF' # fixture as specified
# AI aliases — managed by pos ai alias (do not hand-edit)
assist|gemini|assist|You are assist, a concise and practical AI assistant.
evil|gemini|evil|It's a 'quoted' $(rm -rf /) `backtick` \backslash "dq" ;semi|pipe-less
plain|openrouter|plain|
EOF
# regen via function extraction (sanctioned approach):
bash -c 'source lib/common.sh
ENV_FILE="$CONFIG_DIR/ai-aliases.env"; SH_FILE="$CONFIG_DIR/ai-aliases.sh"
eval "$(awk "/^_alias_quote_cmd\(\)/,/^}/" bin/pos-ai-alias)"
eval "$(awk "/^_alias_regen\(\)/,/^}/" bin/pos-ai-alias)"
_alias_regen'
```
**Fixture nuance:** `evil`'s prompt contains `|`; the loader's `IFS='|' read … _rest` splits it off (pre-existing behavior — this is why prompts ban `|`). Round-trip asserts against the loader-stored string (`…;semi`), not the hand-edited tail.
### Assertion results
| # | Assert | Result |
|---|--------|--------|
| A1 | `bash --norc -c "source $SH"` → rc 0, **zero stderr** | ✅ |
| A2 | No execution while sourcing (`$CONFIG_DIR/pwned` absent) | ✅ |
| A3 | `type -t assist/evil/plain` == `alias` (fresh shell) | ✅ all three |
| A4 | evil expansion round-trip via `eval "set -- ${BASH_ALIASES[evil]}"` (no execution): post-`--system` words join to **exact original prompt**, delivered as one arg | ✅ byte-exact |
| A5 | `plain` emits no `--system` fragment | ✅ |
| A6 | Regen idempotence (second run md5-identical) | ✅ |
| A7 | `pos ai alias show evil` Command line, evaluated via `eval set -- $(cat …)`, yields exact prompt | ✅ byte-exact |
Also verified end-to-end: `bin/pos-ai-alias list`, `bin/pos ai alias show plain` (dispatcher path) behave normally.
### Gates
```
bash -n bin/pos-ai-alias ✅ syntax OK (563 lines)
make gen ✅ (filetable row for pos-ai-alias updated automatically)
make check ✅ check-sync: OK
make lint ✅ 0 FAIL, 0 WARN
```
[DONE]