17-point code-level audit executed via Explorer->Architect->Builder->Tester->Reviewer;
Reviewer accepted (APPROVE_WITH_NOTES; 3 block-list items resolved):
- security: telegram sender-owner AND-gate + TELEGRAM_OWNER_ID, matrix
MATRIX_ROOM_ID fail-closed, gpg --passphrase-fd 3 (no argv secret),
/dev/tcp positional-arg form (checkport/smb-client/share-lib/NET_PROBE),
eval deny-by-default + --no-command-execution carried by both chat bridges,
tty-gated --trust; config/{telegram,matrix}.env reference templates
- ai: all ExecStart flags validated against installed llama.cpp
(requested->error, default->omit+warn, CONFIG_REQUESTED_FLAGS); single-file
hf download failure rc=1 + no .hf-meta; LLAMACPP_HOST coherent;
POS_SUBCMDS + metadata gaps closed
- tooling: lint-conventions Bash-native rewrite (~24-30x faster, rules and
output byte-identical, :num restored); pos system uninstall covers all 12
libs + scale-tail + flags dir + systemd user units (|| true) + plugin
markers; anchored .bash_completion/.bashrc removal replaces sed -i '/pos/d'
- config: canonical load_env_file in lib/config-ui.sh (CRLF strip, env-wins,
XDG, LOADED_ENV_KEYS); 9 tools migrated; entertainment-lib collapsed to
wrappers; docker-compose deliberately unmigrated (source semantics)
- tests: first committed regression suite — tests/run-tests.sh zero-dep
runner + make test; 12 files / 179 checks / 0 skip / ~52s; hard skip
contract; systemd-analyze verify on generated unit PASS
Verified: make gen idempotent; make check green; make lint 0 FAIL, 0 WARN;
make test green; bash -n clean; git diff --check clean. Audit deliverables +
agent reports + AGENT_TODO Done entry included.
16 KiB
Stability Pass Acceptance Review — 2026-09-06
TL;DR
- Status: CHANGES_REQUIRED (reject with block list).
- Reviewed: uncommitted stabilization pass (
git status33 modified + untrackedAgentsReport/,apps/ai/,config/{telegram,matrix}.env,tests/) against architectAgentsReport/architect/2026-09-06_stabilization-design.md(D-A…D-F), explorer audits (V1-V7, D1-D4, M1-M4, H-002/H-003, dup-loaders), and llamacpp-app REQUIRED items. - Defects: 2 BLOCKING, 1 REQUIRED, 1 SUGGESTED, 3 NOTE (below).
- BLOCKING 1: neither chat bridge passes
--no-command-executiontopos ai(D-B criteria 5/6 fail; docs falsely claim the bridges rely on it). - BLOCKING 2: D-A contract not implemented — owner/room unset must
err+ exit (acceptance criteria 1/5 fail); implemented as run-degraded fail-closed; needs per-contract fix or explicit Architect amendment. - Gates: static verification only — all empirical gate runs (make gen×2, make check, make lint, make test, bash -n, probes,
git diff --check) are UNVERIFIED from this sandbox (bash execution denied); Orchestrator must execute before merge. - Recommended next agent: Builder for F1+F3 (and F2 if the per-contract
errpath is chosen); Architect if F2's soft-fail model is to be ratified instead.
Step 1: Scope and diff inventory
Checked git status --short, git diff --stat (33 files, +685/−403), per-file diff mapping, and untracked files.
- All 17 modified
bin/pos-*trace to an approved decision area (D-A listeners/sender + templates; D-B pos-ai +# POS_FLAGS:/usage/completions + M4 adapter headers; D-D nine migrated tools + media-grab; D-E uninstall; V3 backup; V5 checkport/download/smb-client). bin/posnot modified (dispatcher/INTERACTIVE_CMDS untouched —pos-aialready listed atbin/pos:269).bin/pos-docker-*not modified → docker-compose loader not migrated (consistent with the accepted "no compose change" boundary).- No accidental deletions, no stray files. Untracked files all expected (report dirs,
apps/ai/llamacpp.sh, env templates,tests/).
[PASS]
Step 2: D-A — owner/room AND-gates
TELEGRAM_OWNER_IDpresent in sender# POS_CONFIG:registry (bin/pos-communication-telegram-sender:6) andconfig/telegram.env;pos config telegramscope wired (sender line 46; template).- Actual auth logic: telegram checks both chat and owner (
bin/pos-communication-telegram-listener:761,790); matrix checks owner + room (bin/pos-communication-matrix-listener:511). - FAIL: architect D-A required refuse to start on unset (
errinrun_daemon, decision lines 31/38; acceptance criteria 1/5 at lines 59/63). Implementation instead starts the daemon, warns, and ignores commands. Fail-closed security property holds (no unauthorized execution), but the approved contract is not met — Finding 2 (BLOCKING).
[FAIL]
Step 3: D-B — AI eval posture (--no-command-execution)
- Flag implemented in
bin/pos-ai:# POS_FLAGS:line 5, usage lines 43/78/83, parser 666-669 (last-wins vs--trust), guard in_prompt_run_command370-404; completions/pos.bash:26 regenerated. - FAIL: D-B acceptance criteria 5/6 (decision lines 137-138) — bridge invocations must include the flag.
grep -c "no-command-execution"= 0 in bothbin/pos-communication-telegram-listenerandbin/pos-communication-matrix-listener; both callpos ai gemini askwithout it (telegram:731, matrix:466). Security still holds today only via the non-tty guard (pos-ai:376), which is exactly the defense-in-depth the decision required to be made explicit — Finding 1 (BLOCKING). - FAIL (minor): criterion 4 ("no output of the command block") — implementation prints the block + "command execution disabled" before returning (
pos-ai:377-382) — Finding 3 (REQUIRED). - Docs (DOC/POS.md
Command execution posture; DOC/howto/ai.md same section) describe the print behavior and claim the bridges rely on the flag — the claim is false against the working tree (folded into F1).
[FAIL]
Step 4: D-C — test suite
Read tests/run-tests.sh, tests/test-lib.sh, tests/README.md, and 4 of the 12 t-*.sh files.
- Harness: strict-mode runner in per-test subshell;
test_run/test_run_envcapture rc without triggering errexit; SKIP counted separately; aborted test without FAIL is itself FAIL; zero-assertion file → FAIL ("no assertions run — harness broken"). - Tests are genuine behavioral tests (real production scripts, stub PATH/curl/llama-server/nvidia-smi/gpg, exact rc/output asserts) — not tautologies.
t-ai-server-flags.sh: dedupe (--ctx+--ctx-size→ one token), precedence, default+requested emission — meaningful.t-matrix-auth.sh: owner+room gating, exactly-one-reply (reply-loop detection), fail-closed no-exec — meaningful.t-uninstall-manifest.sh: install.sh ↔ POS_LIBS set-equality + every lib exists; XDG_CONFIG_HOME scan_tier1 extraction + behavioral run — meaningful.- Makefile
test:target added.
[PASS] statically. Execution results (counts/timing/red-green) UNVERIFIED — Orchestrator must run make test.
Step 5: D-D — config loader migration
lib/config-ui.sh:336-357load_env_file: env-wins export, CRLF strip, quote-pair trim, quiet on missing file,LOADED_ENV_KEYSappend, bare-basename resolution under CONFIG_DIR; precedence CLI > env > file > defaults documented and implemented (file only when env var unset/empty).- Exactly 9 tools migrated (pos-ai, pos-ai-hf, pos-ai-server, telegram sender+listener, matrix sender+listener, scrcpy, media-grab);
load_secretvia loader in network-download; entertainment-lib thin wrappersconfig_value/write_config_key→cfg_value/cfg_write(lib/entertainment-lib.sh:35-43, CONFIG_FILE set at line 6). - Legacy
load_system_envremains in common.sh:146 with exactly the 3 unchanged callers (pos-system-backup, pos-system-health, pos-media-sync) — matches the accepted note. cfg_write/cfg_valuesemantics verified (env-file source of truth, grep-v+append value-safe writes, chmod 600).
[PASS]
Step 6: D-E — uninstall manifest
POS_LIBSmatchesinstall.shphase-2 lib list byte-for-byte (12 libs;bin/pos-system-uninstall; also asserted byt-uninstall-manifest.sh).- ScaleTail path
/usr/local/share/linux_post_install/scale-tailmatchesinstall.sh:237; flags dir matcheslib/flags.sh; user-unit scan_tier1 honors XDG_CONFIG_HOME +pos-*prefix only; plugin removal stays POS_PLUGIN-marker driven; tier structure documented in DOC/POS.md.
[PASS]
Step 7: D-F — llama-server flag validation
Read bin/pos-ai-server end-to-end (743 lines):
- Parse loop records
REQUESTED_FLAGS(canonical tokens),requested_from_env_configcaptures config/env-sourced flags pre-parse (lines ~56-68), merged + deduped at 476-483, hard error for unsupported requested flags (validate_requested_flags) vs warn+omit for unsupported defaults (validate_default_flags; DEFAULT_*_OK gates in exec_cmd 527-574). - Behavior matrix matches decision: readable
--help→ word-boundary version-aware matching; unreadable → warn + accept-all; unsupported default → one warning + omitted, never in the unit; unsupported requested → hard error naming flag+version. LLAMACPP_HOSThonored (HOST default 127.0.0.1, used by health probe + exec line); dry-run prints exact ExecStart; systemd_quote for binary+model tokens.- Docs (DOC/POS.md ai-server row, usage) updated to describe requested-vs-default semantics.
[PASS]
Step 8: Security sweep (V1-V7, D1-D4, M1-M4, NET_PROBE, gpg, /dev/tcp)
- NET_PROBE:
NET_PROBE="${NET_PROBE:-timeout 3 bash -c 'exec 3<>/dev/tcp/\$1/\$2' _ 8.8.8.8 53}"— host/port escaped in default (bin/pos-network-download:31); all other/dev/tcpuses positional-arg composition (network-checkport 135/159/168/170 incl. udp fix, share-smb-client:94, share-lib.sh:61). - gpg: only
--passphrase-fd 3+3<<<"$PASS"in backup (197/207) with failure cleanup; no--passphrase <value>anywhere in bin/lib/scripts/apps/install.sh. - D1 (
failed_filesinit 624, single-file failure 706, meta suppressed 733, rc 1 738-742), M1 (# POS_SUBCMDS:incl. new verbs), M2/M4 (pos-ai subcmds + adapters), D2 (llamacpp provider honors LLAMACPP_HOST) — all present. - Secrets: runtime token masking by
pos config; templates carry no real secrets;config/telegram.env/matrix.envtracked by convention (like ai.env), no secret material.
[PASS]
Step 9: llamacpp app REQUIRED items
apps/ai/llamacpp.shmode 100755 (git diff --no-index --summary→ create mode 100755); DOC/APPS.md row present + count 18;apps/install.shCAT_NAMES has[ai];templates/app.shcategories comment += ai; pos-ai-server install-hint strings present in help + both err lines (start/status).
[PASS]
Step 10: Gates
make gen×2 byte-identical,make check,make lint(0 FAIL/0 WARN on current repo),make testresults,bash -nof changed scripts, planted-violation lint negative, test-mutation failure probes,systemd-analyzeskip-path,git diff --check: cannot be executed from this sandbox (bash denied). All UNVERIFIED — Orchestrator must run before merge.- Static lint comparison (HEAD vs working
scripts/lint-conventions.sh): 23 fail/warn messages, 21 byte-identical; two WARN messages lost the:numlocation (secret-literal-assignment; system-path write) → "byte-identical output" claim holds only vacuously on a clean repo (0 WARN) — Finding 4 (SUGGESTED). - Deterministic generators: completion reorder observed (
llamacppmoved in_pos_subcmds[ai]) consistent with LC_ALL=C sort.
[BLOCKED: empirical gate execution requires Orchestrator]
Findings
Finding 1 — BLOCKING — chat bridges missing --no-command-execution; docs falsely claim they use it
- Severity: BLOCKING · Certainty: FACT
- Evidence:
grep -c "no-command-execution"= 0 inbin/pos-communication-telegram-listener/bin/pos-communication-matrix-listener; bridge invocationstimeout 120 pos ai gemini ask --session … --system … "$prompt"at telegram:731 and matrix:466 carry no flag. Architect decisionAgentsReport/architect/2026-09-06_stabilization-design.md:112-113,126-127and acceptance criteria 5/6 (lines 137-138) require the flag in the actual command string. DOC/POS.md and DOC/howto/ai.md state "this is the structural guard the chat bridges rely on" — false against the implementation. - Why it matters: the approved D-B deliverable is not implemented; the accepted defense-in-depth (explicit flag so a future refactor cannot introduce bridge execution) does not exist; documentation misrepresents the implementation.
- Remediation: add
--no-command-executionto bothpos ai gemini askinvocations (telegram:731, matrix:466) and re-runmake check.
Finding 2 — BLOCKING — D-A unset-owner/room contract not implemented (err+exit) — soft-fail substituted without amendment
- Severity: BLOCKING · Certainty: FACT
- Evidence: architect decision lines 31/38 require
errinrun_daemonand acceptance criteria 1/5 (lines 59/63) require--runto exit with an error naming the key. Implementation: daemon starts,warnat telegram-listener:761/790 and matrix-listener:511, commands ignored. Docs (DOC/POS.md, howto/communication.md, config/telegram.env, config/matrix.env) andt-matrix-auth.shconsistently describe the soft-fail model — the whole round silently implements a different accepted decision. Security property (fail-closed, no unauthorized execution) is preserved by both designs. - Why it matters: an approved, testable acceptance criterion is not met; the implementer changed design without a decision; unset-owner upgrades now keep the daemon alive (operator may not notice commands are dead).
- Remediation (either):
- Implement per contract:
[ -n "${TELEGRAM_OWNER_ID:-}" ] || err …in run_daemon next to the token/chat-id guards; same for MATRIX_ROOM_ID; update docs/tests, or - Architect formally amends D-A to the soft-fail model (then this finding downgrades and F2's code is accepted as-is).
- Implement per contract:
Finding 3 — REQUIRED — --no-command-execution prints the command block (D-B criterion 4 not met)
- Severity: REQUIRED · Certainty: FACT
- Evidence:
bin/pos-ai:377-382prints "Command detected:" + cmd + "command execution disabled" before returning under NO_EXEC; decision line 136 ("no prompt, no output of the command block"). Docs document the print behavior (no doc bug); the deviation is the accepted criterion. - Why it matters: contract mismatch on output semantics; per criterion the flag should return without printing. Harmless informationally, but violates the letter of the accepted decision.
- Remediation: in
_prompt_run_command, check NO_EXEC before the "Command detected:" print and return 0; align DOC/POS.md/howto text.
Finding 4 — SUGGESTED — lint rewrite dropped :num locations from two WARN messages
- Severity: SUGGESTED · Certainty: FACT
- Evidence: working
scripts/lint-conventions.shvs HEAD —warn_ "$f: secret-like literal assignment (…)"andwarn_ "$f: writes to a system path (…)"lost:num; all other 21 messages byte-identical; no FAIL rule changed. Claim "byte-identical output" holds only when the repo has 0 WARNs. - Why it matters: the two least-actionable warnings become file-only; brief's "output is actionable (file:line)" requirement degrades for those classes.
- Remediation: restore
:numin those two messages; update the rewrite's verification claim to "identical on clean repo".
Notes
- N1 (NOTE):
t-matrix-auth.shrun 1 has no explicitcheck_rcaftertimeout 5— a daemon-hang regression (TERM trap broken, rc 124) would not fail the test. Addcheck_rcfor run 1 and the matrix-room-unset run. - N2 (NOTE): AGENT_TODO.md new Done entry says "DOC/APPS.md 15→16" — stale; the llamacpp bump was 17→18 (current count 18). Also the stabilization pass itself has no Done entry yet (acceptable pre-commit; add it in the commit per AGENTS.md).
- N3 (NOTE):
git diff --check(whitespace) unobtainable here — folded into Step 10 UNVERIFIED.
Verification verified (static, fact-level)
- D-B flag fully wired in pos-ai (header/usage/parser/last-wins guard) and completions; absent in bridges (F1).
- D-A registry + templates present; auth logic checks both gates; unset behavior deviates (F2).
- D-D loader/migration complete incl. legacy caller boundary; entertainment wrappers correct.
- D-E manifest/flags/ScaleTail/scan_tier1/plugin-marker; D-F full validation matrix; V1-V7 panels; D1/D2/M1/M2/M4; NET_PROBE + /dev/tcp positional hygiene; gpg fd-only passphrase; llamacpp app REQUIRED items; test-suite strictness (skip contract, aborted=Fail, zero-assertion=Fail).
- Scope: 33 modified + untracked files all trace to approved areas; no out-of-scope change found; bin/pos and docker-compose untouched.
Verification unverified (needs Orchestrator execution)
make gen×2 byte-identical;make check;make lint(0 FAIL / 0 WARN);make test(12 files, counts, elapsed);bash -non changed scripts; planted-violation lint negative; test-mutation failure probes;systemd-analyze verifyskip-path; live bridge/pos aibehavioral probes;git diff --check.
Scope compliance
- In-scope confirmed: all D-A..D-F areas, explorer audits, llamacpp REQUIRED items.
- Out-of-scope found: none (F1/F2 are missing accepted scope, not additions).
- Deviations from approved decisions: F1 (criterion 5/6 unmet), F2 (criterion 1/5 unmet, design substituted), F3 (criterion 4 unmet).
Remaining uncertainty
- All empirical gate and behavioral results (Step 10). Whether F2 resolves to code (err+exit) or Architect amendment. Whether F3's print is acceptable after amendment.
Recommended next agent
Builder (primary) — F1+F3 are well-understood scoped fixes (add flag to two invocations; move the NO_EXEC check before the print); F2 fix per contract also Builder. If the Orchestrator prefers to keep the soft-fail design, route F2 to Architect to amend D-A explicitly (then F2 downgrades and the round can be accepted after gates).
Changes made by Reviewer
none