# Builder Report: Alias Architecture Rewrite + Dup-Table Fix **Date:** 2026-08-26 **Files changed:** `bin/pos-ai-alias`, `bin/pos-system-uninstall`, `DOC/POS.md`, `AGENT_TODO.md` **Gates:** `bash -n` ✅ | `make gen && make check` ✅ | `make lint` 0 FAIL 0 WARN ✅ --- ## TL;DR Implementation found already present in working tree — verified against architect spec, tested, gates green. All architect D1–D4 decisions implemented correctly. Dup-table bug fixed via single `_alias_table` renderer (variant: menu option 4 = no-op returning to loop). 17-category test suite (40 assertions) run externally against the actual script; 3 test-harness quoting artifacts debugged and confirmed not code bugs. No scope violations. ## Step 1: Verify implementation against architect spec ✅ [DONE] Read architect spec (`AgentsReport/architect/2026-08-26_alias-architecture.md`), current `bin/pos-ai-alias`, and `bin/pos-system-uninstall`. **Already implemented in working tree:** - `_alias_regen()` deleted; replaced by `_wrapper_path()`, `_alias_owned()`, `_wrapper_render()`, `_wrapper_install()`, `_alias_check_path()`, `_alias_retire_legacy_sh()`, `_alias_sync()` - `_alias_quote_cmd()` preserved verbatim (double-%q mechanism) - `_alias_sync()` wired into every dispatch entry (create/edit/remove/list/show/menu) - Collision refusals in `_alias_create()` (foreign file + `command -v` check) - Legacy `ai-aliases.sh` auto-removal with unalias remediation hint - Success messages updated ("Available immediately", dropped "Reload shell" everywhere) - `show` gains wrapper path - `usage()` text updated with activation description - `bin/pos-system-uninstall`: marker scan in `scan_tier1()` (lines 98-105) and `remove_tier1()` (lines 272-281) - `DOC/POS.md`: alias rows updated (activation via `~/.local/bin` wrappers, not `.bashrc` sourcing) ## Step 2: Dup-table bug fix verification ✅ [DONE] **Chosen variant:** Menu option 4 is a no-op (`: ;;`) returning to the loop, which re-renders the table via `_alias_table` in the pre-render block. **Rationale:** The menu's own pre-render (lines 266-275) already calls `_alias_table` fresh every iteration. Making option 4 a no-op is the simplest correct fix — zero code duplication, no new helper, and the "list" action is semantically "return to see the current list." The `_alias_list()` function remains available for the non-interactive `pos ai alias list` path, which still calls `_alias_table` through its own code path. **Before (bug):** Menu pre-render showed table, then option 4 called `_alias_list()` which printed the table again → duplicated output. **After (fix):** Menu option 4 returns to loop → loop re-renders → single table displayed. ## Step 3: Test harness ✅ [DONE] External test harness (`/tmp/al-test.sh`) runs 17 test categories (40 assertions) against the actual `bin/pos-ai-alias` script with a stub `pos` that captures `$*`: | # | Test | Result | |---|------|--------| | 1 | `_alias_sync` creates wrapper scripts (assist, evil, plain) | ✅ 5/5 | | 2 | Wrapper content: marker on line 2, shebang, set -euo, exec | ✅ 6/6 | | 3 | exec line correct provider/session | ✅ 2/2 | | 4 | `--system` flag present for non-empty prompts | ✅ 2/2 | | 5 | Empty prompt → no `--system` fragment | ✅ 2/2 | | 6 | Wrapper executes: `assist "how are you"` → correct argv | ✅ 4/4 | | 7 | Passthrough args: `--help` forwarded via `"$@"` | ✅ 1/1 | | 8 | Evil wrapper (complex prompt) executes correctly | ✅ 1/1 | | 9 | Legacy `ai-aliases.sh` removed by list | ✅ 1/1 | | 10 | Second list call idempotent (same md5, same mtime) | ✅ 2/2 | | 11 | Foreign file not touched by sync | ✅ 1/1 | | 12 | Orphan retraction: removed ENV entry → wrapper deleted | ✅ 2/2 | | 13 | Empty env → all wrappers deleted | ✅ 2/2 | | 14 | **Staleness kill-test:** edit gemini→openrouter, wrapper live on next invocation | ✅ 3/3 | | 15 | `show` includes wrapper path | ✅ 2/2 | | 16 | Legacy foreign sh file untouched with warning | ✅ 2/2 | | 17 | Help text mentions `~/.local/bin` and "no shell sourcing" | ✅ 2/2 | **3 initial test failures debugged:** All were test-harness quoting artifacts (single quotes and `$(echo pwned)` in captured argv broke the assertion's `echo '$var'` pattern). Confirmed via direct `grep` on the captured file: evil wrapper correctly produces `CAPTURED: ai openrouter ask --session evil --system It's a 'quoted' $(echo pwned) \`backtick\` --help`. ## Step 4: Gates ✅ [DONE] ``` bash -n bin/pos-ai-alias ✅ bash -n bin/pos-system-uninstall ✅ make gen && make check ✅ (gen-docs OK, check-sync OK) make lint ✅ (0 FAIL, 0 WARN) ``` ## Step 5: AGENT_TODO update ✅ [DONE] The alias-related entry was already moved to Done (dated 2026-08-26) in the existing AGENT_TODO.md diff. ## Scope compliance ✅ **Touched (in scope):** `bin/pos-ai-alias`, `bin/pos-system-uninstall`, `DOC/POS.md`, `AGENT_TODO.md`, `AgentsReport/` **Not touched (out of scope):** `bin/pos-ai`, `lib/common.sh`, `lib/menu-lib.sh`, `lib/config-ui.sh`, `completions/`, `postinstall.sh`, `pos-ai-alias` `# POS:` headers, registry code **No commits made** per brief constraint. ## Dup-table fix variant chosen **Variant:** Menu option 4 → no-op, returning to the loop's pre-render. **Rationale:** Cleanest solution. The pre-render block already calls `_alias_table` on every iteration, so returning to the loop naturally shows the current state. Zero added code, zero new abstractions, and `_alias_list()` stays available for the non-interactive `list` path.