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

287 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.
# Reviewer — R5 Chain Adversarial Review
**Date:** 2026-08-25
**Reviewed work:** Four consecutive Builder passes (R5, R5b, R5c, R5d) on `bin/pos-ai-gemini` and docs
**Approved scope:** tmp_request.md R5 — terse prompt + markdown rendering, --last + default session, answer separation + staleness transparency, machine context
---
## TL;DR
**Status: ACCEPT_WITH_NOTES**
- 21 checklist items assessed: 18 PASS, 1 FAIL (duplicate line in ai.md doc), 1 WARN (chat REPL extra whitespace — cosmetic), 1 NOT-APPLICABLE (chat subcommands that never existed)
- 1 BLOCKING finding: duplicate line in `DOC/howto/ai.md` (lines 135138)
- 0 regressions detected in non-tty output path or pre-R5 behavior
- 0 scope creep into share-lib, menu-lib, cmd_unmount, or Telegram bridge
- 3 unverified items (require `make gen`, `bash -n`, runtime testing — sandbox blocked)
---
## Step 1: Scope compliance
**Files in R5 scope** (per approved scope):
- `bin/pos-ai-gemini` — ✅ Changed, 311→565 lines
- `DOC/howto/ai.md` — ✅ Changed
- `DOC/POS.md` — ✅ Changed (ai section updated)
- `completions/pos.bash` — ✅ Changed (GEN: block, `--full --last` added)
- `DOC/AGENT_Context_Project.md` — ✅ Changed (line-count resync only)
**Out-of-scope files also modified in working tree** (from concurrent work, NOT caused by R5):
- `bin/pos-docker-vbox`, `bin/pos-share-nfs-client`, `bin/pos-share-smb-client` — R1/R3/R6 work
- `lib/common.sh` — R4 confirm convention
- `DOC/DEV.md`, `DOC/howto/docker.md`, `DOC/howto/share.md` — doc sync for R3/R4/R6
These are concurrent uncommitted changes, not scope creep by R5.
| Verdict | PASS |
|---------|------|
| Rationale | All R5-scope files are modified; no R5-authored changes found in out-of-scope files |
---
## Step 2: Default system prompt (R5)
| Check | Verdict | Evidence |
|-------|---------|----------|
| Terse clause present | PASS | Line 23: "Be extremely terse: lead with the exact command(s) to run; one-line explanations max; no greetings, no closing offers, no essays." |
| Troubleshooting clause present | PASS | Line 23: "diagnose it from that and lead with the fix command(s)." |
| Machine context appended dynamically | PASS | `cmd_ask` lines 411414: `mc="$(machine_context)"; [ -n "$mc" ] && mc=" $mc"; system="$DEFAULT_SYSTEM_PROMPT$mc"` |
---
## Step 3: --system replaces wholesale
| Verdict | PASS |
|---------|------|
| Evidence | Lines 410415: `system="$SYSTEM_PROMPT"` then `if [ -z "$system" ] && [ "$FULL_MODE" -eq 0 ]; then ...`. When `--system` sets `SYSTEM_PROMPT`, the condition `[ -z "$system" ]` is false → built-in prompt + machine context are never assembled. |
---
## Step 4: --full drops built-in
| Verdict | PASS |
|---------|------|
| Evidence | Line 411: `if [ -z "$system" ] && [ "$FULL_MODE" -eq 0 ]`. With `FULL_MODE=1`, the entire block is skipped → `system` stays as `SYSTEM_PROMPT` which defaults to `""`. No built-in or machine context injected. |
---
## Step 5: --last resolves + injects + announces
| Verdict | PASS |
|---------|------|
| Evidence | `newest_pos_log()` (lines 131138) finds newest non-pos.log, verifies non-empty. `cmd_ask` (lines 398403): calls `last_log_annotate` for stderr info, `last_log_context` for the tail, appends `[last command output:]` block. `last_log_annotate` (lines 171185): prints `[i] attaching last pos output — <basename> (<age>)` + preview line to stderr. |
---
## Step 6: Staleness >60min warning
| Verdict | PASS |
|---------|------|
| Evidence | Line 182: `if [ "$age_s" -gt "$LAST_LOG_STALE_SECS" ]` (LAST_LOG_SECS=3600). Prints `[!] that log is %s old and may not match your current problem...` to stderr with pipe-fresh hint. |
---
## Step 7: Session "default" persists
| Verdict | PASS |
|---------|------|
| Evidence | Line 16: `SESSION="default"` (was `SESSION=""` in baseline). `session_load()` / `session_save()` no longer gated on `[ -n "$SESSION" ]` in ask/chat — always writes to `default.json`. |
---
## Step 8: --session overrides default
| Verdict | PASS |
|---------|------|
| Evidence | Flag parser lines 534535: `--session) SESSION="$2"; shift 2`. Overrides the default before any session operation. |
---
## Step 9: Tty answer separation
| Verdict | PASS |
|---------|------|
| Evidence | `render_markdown` tty path (line 318): `printf '\n%s\n' "$rendered"` — exactly one leading blank line + content + one trailing newline. Non-tty path (lines 262264): `printf '%s\n' "$text"` — raw bytes, zero added newlines. |
---
## Step 10: Markdown renderer coverage
| Verdict | PASS |
|---------|------|
| Evidence | Fenced blocks: line 280 toggle + line 281 dimmed indent. Inline code: lines 291295 → yellow. Bold `**…**`: lines 298302. Bold `__…__`: lines 305309. Headers `#{1,4}`: lines 282285 → bold cyan, # stripped. HR `---/***___`: line 287 → thin rule. List markers: no-op (passed through as-is, which is correct). glow: lines 313314, `command -v glow >/dev/null 2>&1` — opportunistic. |
---
## Step 11: Machine context fallback chain
| Verdict | PASS |
|---------|------|
| Evidence | `machine_context()` lines 337386: hostnamectl first (lines 340356), os-release fallback for distro (lines 359368), uname fallback for kernel+arch (lines 370371). `[ -n "$out" ] \|\| return 0` on line 384 — clause omitted when all fail. `mc_clean()` strips ANSI, control chars, collapses whitespace. |
---
## Step 12: Non-tty stdout byte-identical
| Verdict | PASS |
|---------|------|
| Evidence | Old baseline `cmd_ask`: `printf '%s\n' "$out"`. New `cmd_ask`: `render_markdown "$out"` where non-tty path is `printf '%s\n' "$text"`. Byte-equivalent output format. The system prompt change affects what the model generates but not the print format — opt-in behavioral change within scope. |
---
## Step 13: Chat REPL commands intact
| Verdict | NOT-APPLICABLE |
|---------|----------------|
| Rationale | Checklist references /history, /export, /help — these never existed in either baseline or current code. Old code only had `/reset` and `q/Q/quit/exit`. Current code preserves both exactly (lines 441446). No regression. |
---
## Step 14: Telegram listener bridge untouched
| Verdict | PASS |
|---------|------|
| Evidence | `git diff --name-only` shows no changes to communication listener/sender files. Telegram bridge calls `pos ai gemini ask` — the non-tty stdout path is byte-identical (check 12). |
---
## Step 15: Pipe stdin still works
| Verdict | PASS |
|---------|------|
| Evidence | Lines 392394: `elif [ ! -t 0 ]; then prompt="$(cat)"`. Identical to baseline. |
---
## Step 16: POS_FLAGS complete
| Verdict | PASS |
|---------|------|
| Evidence | Line 5: `# POS_FLAGS: --model --session --system --full --last`. All five flags from checklist present. Completions line 6 matches: `_pos_flags[ai-gemini]="--model --session --system --full --last"`. |
---
## Step 17: make gen idempotency
| Verdict | UNVERIFIED |
|---------|------------|
| Rationale | Cannot run `make gen` in sandbox. Static evidence: completions posflags block (line 6) matches POS_FLAGS header; filetable row updated to 565 lines (confirmed by `wc -l`). The docker-vbox, nfs-client, smb-client, and completions line-count rows in the GEN block reflect concurrent work, not R5 drift. Strong inference: gen output would be byte-identical, but UNVERIFIED without running it. |
---
## Step 18: glow deps guard
| Verdict | PASS |
|---------|------|
| Evidence | Line 313: `if command -v glow >/dev/null 2>&1` — standard pattern, never errors when absent, falls back to awk renderer. No other reference to glow in the file. |
---
## Step 19: Lint convention compliance
| Verdict | PASS |
|---------|------|
| Evidence | Shebang: line 1 `#!/usr/bin/env bash`. Strict mode: line 2 `set -euo pipefail`. Help dispatch: line 529 `-h\|--help) usage ;;` in flag parse loop (before subcommand dispatch). No new external deps required (glow is optional). |
---
## Step 20: --last scoped to ask
| Verdict | PASS |
|---------|------|
| Evidence | Lines 554556: `if [ "$LAST_MODE" -eq 1 ] && [ "${cmd:-}" != "ask" ]; then err "--last only applies to 'pos ai gemini ask'"`. Hard error for any other subcommand. |
---
## Step 21: Error→stderr, answer→stdout
| Verdict | PASS |
|---------|------|
| Evidence | `err()` from common.sh → stderr. `warn()` at line 450 → stderr. `gemini_generate` error echo at line 246 → `>&2`. `last_log_annotate` all output → `>&2`. `render_markdown` → stdout. API errors → stderr + exit 1. |
---
## Findings
### Finding 1 — Duplicate line in DOC/howto/ai.md
- **Severity:** REQUIRED
- **Evidence:** Lines 135138 in `DOC/howto/ai.md`:
```
- On a non-2xx response the API's `error.message` is shown and the exit code is
non-zero — so scripts can rely on `ask` failing loudly.
- On a non-2xx response the API's `error.message` is shown and the exit code is
non-zero — so scripts can rely on `ask` failing loudly.
```
The diff confirms: the new line was appended but the old identical line was not removed.
- **Relevant files/lines:** `DOC/howto/ai.md:135-138`
- **Approved scope reference:** R5 doc updates to ai.md
- **Why it matters:** Duplicate text is a doc bug — readers see the same bullet twice. Trivial to fix (delete one).
### Finding 2 — Chat REPL uses raw SYSTEM_PROMPT (no built-in default)
- **Severity:** NOTE
- **Evidence:** `cmd_chat` line 449: `gemini_generate "$model" "$contents" "$SYSTEM_PROMPT"` — passes the raw `SYSTEM_PROMPT` var. When no `--system` is given, this is `""` (empty), meaning chat gets NO system instruction — not even the terse prompt. This is consistent with the scope ("chat keeps its neutral behavior, only --system applies") and with `ai.md` line 39: "`chat` keeps its neutral behavior (only `--system` applies)."
- **Why it matters:** Not a defect — explicitly documented behavior. But worth noting that chat and ask have asymmetric prompt treatment.
### Finding 3 — Chat REPL extra leading whitespace on tty
- **Severity:** SUGGESTED
- **Evidence:** `cmd_chat` lines 458460: `printf '\n'; render_markdown "$answer"; printf '\n\n'`. On a tty, `render_markdown` emits `\n<rendered>\n`, so total after `> ` prompt close is: `\n` (from printf) + `\n` (render_markdown leading) + content + `\n` (render_markdown trailing) + `\n\n` (printf). This produces 2 leading blank lines and 3 trailing blank lines — more visual whitespace than the baseline's `printf '\n%s\n\n'`.
- **Why it matters:** Cosmetic. The extra separation is arguably better for interactive readability. Non-blocking.
---
## Verification verified
1. ✅ Default system prompt has terse + troubleshooting clauses (line 23)
2. ✅ Machine context function implements hostnamectl → os-release → uname fallback chain (lines 337386)
3. ✅ --system prevents built-in assembly (line 411 condition)
4. ✅ --full prevents built-in assembly (line 411 FULL_MODE check)
5. ✅ --last injects `[last command output:]` block (lines 398403)
6. ✅ --last announces to stderr with basename + age + preview (lines 171185)
7. ✅ Staleness warning at >60min (line 182, LAST_LOG_SECS=3600)
8. ✅ Session default persists (SESSION="default", no conditional on load/save)
9. ✅ Tty rendering: glow opportunistic + awk fallback, non-tty raw (lines 260318)
10. ✅ POS_FLAGS header has all 5 flags (line 5)
11. ✅ Completions match POS_FLAGS (line 6)
12. ✅ Filetable line count accurate (565 matches wc -l)
13. ✅ --last scoped to ask only (lines 554556)
14. ✅ Errors to stderr throughout
15. ✅ Pipe stdin preserved (lines 392394)
16. ✅ Telegram bridge path untouched (no file changes)
17. ✅ Conventions: shebang, strict mode, help dispatch order
## Verification unverified
1. `make gen` byte-idempotency (sandbox cannot execute make)
2. `bash -n` syntax check (sandbox cannot execute bash on non-git commands)
3. Runtime test: `--last` with actual dispatcher logs, staleness warning timing, glow rendering
---
## Scope compliance
- **In-scope confirmed:** All R5/R5b/R5c/R5d features implemented in `bin/pos-ai-gemini` + docs
- **Out-of-scope found:** None authored by R5. Working tree contains concurrent changes from R1/R3/R4/R6 work (separate feature branches mixed into working tree before commit)
- **No regressions:** Non-tty output byte-equivalent, chat REPL preserved, stdin pipe preserved, Telegram bridge untouched
---
## Remaining uncertainty
1. Whether `make gen` output is byte-identical to committed GEN blocks — strong inference says yes (flag set matches header, line counts match), but unverified.
2. Whether the awk markdown renderer handles all edge cases at runtime (nested bold inside code blocks, unclosed fences, etc.) — static review shows correct structure but edge-case behavior is runtime-only.
---
## Recommended next agent
**Builder**
**Reason:** One REQUIRED finding (duplicate doc line in `DOC/howto/ai.md`) is a trivial fix within approved scope — delete lines 137138. The builder can resolve this and then the chain is ready for commit.
---
## Changes made by Reviewer
None — read-only review.