Files
Linux_post_install/AgentsReport/builder/2026-09-06_stab-tooling.md
T
Your Name d817c37652
gates / consistency-and-conventions (push) Successful in 26s
fix: stabilization pass — fail-closed auth, ai flag validation, lint/config/security hardening, regression tests
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.
2026-09-06 07:25:44 -04:00

10 KiB
Raw Blame History

Builder Report — 2026-09-06 — Stabilization: Tooling track (lint perf, D-E uninstall, H-002/H-003)

Scope (per brief): scripts/lint-conventions.sh, bin/pos-system-uninstall, DOC/POS.md (system uninstall row only if factual); NOT touched: other files listed in the brief. lib/install-manifest.sh is NOT created — see D-E.

TL;DR

  • Status: DONE — all 3 steps implemented, probed, gated.
  • Files in scope changed by me: scripts/lint-conventions.sh (rewrite), bin/pos-system-uninstall (D-E/H-002/H-003), DOC/POS.md (system-uninstall row only), plus gen output in DOC/AGENT_Context_Project.md + completions/pos.bash (reflecting the whole shared tree, incl. parallel tracks).
  • D-E explicitly says do NOT create lib/install-manifest.sh — the brief's manifest is conditional ("if D-E specifies it"); it does not, so I implement D-E's actual decision (extend bin/pos-system-uninstall directly, no manifest file).
  • Baseline make lint = 145.9 s (measured, time); final = 4.38 s, 0 FAIL, 0 WARN, output byte-identical to original (differential test). make check OK; make gen idempotent.
  • H-002/H-003 probes pass: exact-literal + anchored awk removal removes only pos-owned lines; comments, user PATH/MY_POS_REPO lines, repos/dispose/compose completion, and unrelated.service all survive.
  • Remaining risk: real-machine removal path validated via fixtures only (no live uninstall run) — see Step 3.

Step plan

  1. Lint performance rewrite (Task 1).
  2. D-E uninstall extensions + H-002/H-003 + surviving-artifacts docs (Tasks 2, 3).
  3. Probes + full gates.

Step 1: Lint performance rewrite

Refactored scripts/lint-conventions.sh hot paths to bash-native parsing:

  • Merged per-line uses_stdin + top-level-local scans (was printf | sed | tail × 3 forks per line) into ONE single-pass per-file read with heredoc-delimiter state via [[ =~ ]].
  • Folded # POS: header / em-dash / posline / first -h|--help line into the same loop.
  • Shebang via read -r first < "$f"; POS.md coverage via one preloaded cat + [[ ]]; secret-literal + system-path scans → bash [[ =~ ]] with cheap string gates; deleted dead last_line().
  • System-path outer filter ((\btee\b|>>?)[^#]*?(path)) reimplemented faithfully (_syspath_outer — no fork, global _SI), preserving the no-#-between-operator-and-path semantics that bash =~ cannot replicate.

Verification:

  • bash -n OK.
  • Differential test vs git show HEAD:scripts/lint-conventions.sh: outputs byte-identical (both exit 0, 0 FAIL, 0 WARN).
  • Negative test (broken tool): all expected FAIL/WARNs fire; skipped per-file checks on missing POS header match original continue.
  • Timings (time bash scripts/lint-conventions.sh): before 145.9 s → after 4.79 s (~30x). time make lint before: >120 s (timed out at 145.9 s for the bare script); after: see gates below.

[DONE]


Step 2: D-E install/uninstall + H-002/H-003

D-E reconciliation — NO lib/install-manifest.sh

D-E (architect decision stabilization-design.md:399-401) explicitly says: "Do NOT introduce a full manifest abstraction (like lib/install-manifest.sh) — that would be a larger refactor inconsistent with the current 'list-based' approach". The brief's manifest requirement was conditional ("If D-E specifies lib/install-manifest.sh"); it does not. Per the scope rule (necessary-to-complete vs better-design), I implemented D-E's actual decision: one source of truth inside bin/pos-system-uninstall (singleton POS_LIBS array + PATH_LINE/COMPLETION_LINE/HOOK_PATTERN constants + installed_plugins() helper) used by both scan and remove — the removal list is no longer two hardcoded places. Nothing else in the codebase was introduced.

Changes to bin/pos-system-uninstall

  • Libs (D-E 1): POS_LIBS = all 12 libs from install.sh phase 2 (common.sh flags.sh notify.sh entertainment-lib.sh scheduler-lib.sh config-ui.sh user-timers-lib.sh entertainment-plugin-lib.sh usb-lib.sh share-lib.sh menu-lib.sh registry.sh); scan + remove loops both read the single array. Verified byte-identical to install.sh:143.
  • ScaleTail + flags store (D-E 2): scan + remove for /usr/local/share/linux_post_install/scale-tail/ and /flags/, then rmdir the parent if empty.
  • User systemd units (D-E 3): scan + remove $XDG_CONFIG_HOME/$HOME/.config/systemd/user/pos-* (disable --now + rm, || true wrapped; daemon-reload at end). unrelated.service probe survives.
  • De-hardcoded entertainment plugins (D-E 4): installed_plugins() discovers installed plugins by # POS_PLUGIN: marker (matching install.sh's directory-driven install), used by scan + remove.
  • H-002 (D-E 5): .bash_completion sed -i '/pos/d' replaced with anchored awk '/^[[:space:]]*source[[:space:]].*pos\.bash/ { next } { print }' + mktemp + chmod --reference + count.
  • H-003 (D-E 6): .bashrc sed removals replaced with exact-literal awk removal of postinstall.sh's PATH_LINE + COMPLETION_LINE and anchored HOOK_PATTERN='^[[:space:]]*source[[:space:]].*pos-ai-hook\.sh' (comment-safe per D-E acceptance criterion 5). Note: the old /linux_post_install.*PATH/d never removed the real PATH_LINE anyway (that literal has no linux_post_install substring); the new code removes the installer's actual line.
  • Surviving artifacts (D-E 7): usage() documents deliberately NOT removed: apt packages, /usr/local/bin/yt-dlp, ~/.config/rclone/, ~/.ssh/authorized_keys additions, config/data tiers.
  • DOC/POS.md: system-uninstall row Tier 1 description updated (factual): adds user units + ScaleTail + flags store.

Probes (all pass)

  1. H-002/H-003 fixture .bashrc (15 lines incl. unrelated pos lines + comments) → 3 lines removed (PATH_LINE, COMPLETION_LINE, hook source); custom MY_POS_REPO, user PATH, # source pos.bash comments survive.
  2. Fixture .bash_completion (7 lines incl. repos/dispose/compose) → 1 line removed (source pos.bash); repos/dispose/compose and comment survive.
  3. scan_tier1 (HOME fixture): finds exact bashrc/bash_completion lines + pos-aria2.service, pos-entertainment-weather.timer user units; does NOT find unrelated.service or unrelated completion lines.
  4. remove block replication: REMOVED_COUNT=6 (3 bashrc + 1 completion + 2 user units); unrelated content + unrelated.service survive; systemctl --user fails gracefully (|| true, no session).
  5. Inventory: POS_LIBS == install.sh lib list (12 names identical); 13th lib/pos-ai-hook.sh is not installed by install.sh phase 2 (correctly not in POS_LIBS).

[DONE]


Step 3: Gates + hygiene

Gate results (final state)

  • bash -n scripts/lint-conventions.sh bin/pos-system-uninstall → OK.
  • make gen ×2 → idempotent (gen-docs: write OK both runs; second run produces the same diff, no drift).
  • make checkcheck-sync: OK (exit 0).
  • time make lint0 FAIL, 0 WARN (convention lint), 4.38 s (second run 6.26 s; final measured 4.38 s). Baseline was 145.9 s for the bare script and >120 s (timeout) for make lint → ~30x speedup. Rapid repeat runs no longer leave the shell spinning (no more per-line fork storms).
  • Gen output note: make gen regenerated DOC/AGENT_Context_Project.md + completions/pos.bash from the shared working tree. The diff includes my expected bin/pos-system-uninstall row-count update (435→517 lines) plus the other parallel tracks' already-uncommitted changes (bin/pos-ai-server, bin/pos-ai, bin/pos-system-backup, communication listeners, etc.). No POS headers/dirs were touched by me; gen is byte-order deterministic (LC_ALL=C), CI's git diff --exit-code will see the whole tree's refresh.

Hybrid conflict check (shared working tree)

Final git status shows many files modified by parallel Builder tracks (stab-ai, stab-security: bin/pos-ai*, bin/pos-communication-*, bin/pos-network-checkport, bin/pos-share-smb-client, bin/pos-system-backup, lib/share-lib.sh, lib/ai-providers/llamacpp.sh, apps/install.sh, templates/app.sh, DOC/howto/*, DOC/APPS.md, AGENT_TODO.md, config/*.env). These were NOT edited by me — my changed-file set is exactly:

  1. scripts/lint-conventions.sh (rewritten; 213 changed lines vs HEAD)
  2. bin/pos-system-uninstall (D-E + H-002/H-003; 150 changed lines vs HEAD)
  3. DOC/POS.md — only the pos system uninstall row (all other rows in the file diff belong to other tracks)
  4. DOC/AGENT_Context_Project.md + completions/pos.bash — gen output including, among others, my uninstall row count
  5. AgentsReport/builder/2026-09-06_stab-tooling.md (this report)

No protected/brief-excluded file was touched by me; no out-of-scope change made.

DOC/SCRIPTS.md + DOC/DEV.md

Not touched: no manifest was created (D-E rejected it), so the brief's "only if the manifest needs documenting" condition does not apply. No new documentation needed.

[DONE]


Final status

  • Scope: lint perf (Task 1) + D-E uninstall coverage (Task 2) + H-002/H-003 safe removal (Task 3) + surviving-artifacts docs (D-E 7). All implemented; no scope expansion.
  • Timings: make lint 145.9 s → 4.38 s (~30x). Differential: output byte-identical to original.
  • Probes: all pass (H-002/H-003 fixture removal, scan_tier1 with HOME override, remove-block replication, POS_LIBS==install.sh inventory).
  • Gates: bash -n OK, make gen idempotent, make check OK, make lint 0 FAIL, 0 WARN.
  • Deferred/risks:
    1. The real-machine removal path (removing live /usr/local/bin, /etc/systemd, ScaleTail dirs) was NOT executed here — validated via fixture/sandbox probes only. A dry-run pass on a real install is doable via the tool's own scan display (pos system uninstall interactive scan shows Tier 1 entries before any removal).
    2. lib/pos-ai-hook.sh (13th lib file) is intentionally not in POS_LIBS because install.sh phase 2 doesn't install it; the uninstaller already removes ~/.local/bin/pos-ai-hook.sh separately — no action.
    3. Other parallel tracks' edits are interleaved in the shared tree; my in-scope files are scripts/lint-conventions.sh, bin/pos-system-uninstall, DOC/POS.md (one row).
  • Recommended next agent: Reviewer (independent adversarial review of the uninstall diff + lint rewrite), then Orchestrator to coordinate the shared-tree commit once the parallel tracks land.