Files
Your Name e969234ca5
gates / consistency-and-conventions (push) Successful in 1m28s
feat: command registry, alias wrapper scripts, config-ui readability
- lib/registry.sh: shared query API over POS_* headers (reg_scan, reg_list,
  reg_lookup, reg_tools_in, reg_each, reg_config_scopes/keys). Replaces
  per-consumer sed/grep header parsing.

- bin/pos-tree + bin/pos _pos_category_help(): migrated to registry API.
  Category help now shows [deps: ...] annotations. Tree output preserved.

- New optional headers # POS_DEPS: and # POS_EXAMPLES: in tool metadata.
  Added to pos-network-download (aria2c jq curl), pos-media-sync (lsblk jq),
  pos-system-backup (tar), pos-docker-ps (docker) as initial adopters.

- scripts/gen-docs.sh: extended tools array with deps/examples fields;
  conditional column rendering in gen_dispatch; deps annotation in gen_tree.
  Fixed URL-unsafe // joiner (→ middle dot ·) and \x1f caption delimiter
  collision in config-ui.

- bin/pos-ai-alias: rewrote activation from bash aliases (source-time-frozen)
  to executable wrapper scripts at ~/.local/bin. Staleness eliminated:
  edits apply on next invocation with no shell reload. _alias_sync()
  reconciliation on every subcommand, marker-guarded lifecycle, collision
  refusal, legacy .sh retirement. Fixed dup-table bug (option 4 no-op).

- lib/config-ui.sh: @caption/@[KEY=alt] conditional captions, *providers=<tag>
  tagged wildcards, uniform typography tier (bold/cyan/dim), honest prompt.
  Active provider keys bold, inactive dimmed with reason. Backward-compatible.

- bin/pos-system-uninstall: marker-scan for wrapper script cleanup.

- Docs synced: AGENTS.md (new headers + registry), DOC/SCRIPTS.md (registry
  section + lib list), DOC/POS.md (alias wrapper activation), MAINTENANCE.md
  (M-024). Lint fixed: pos-ai-alias registered in INTERACTIVE_CMDS.

Gates: make gen && make check && make lint = 0 FAIL, 0 WARN
2026-08-27 02:30:27 -04:00

28 KiB

MAINTENANCE — Convention Audit

Working report for the post-3-week-convention-drift audit. Created first, updated incrementally as findings are confirmed — never let findings live only in agent context. Keep the structure below; append findings as they land.

Do not commit this file — it is a working artifact for the fix session. Definition of done for the fix session: every P0/P1 resolved (or explicitly marked won't-fix), make gen && make check green, scripts/lint-conventions.sh green, smoke tests pass.

Phase 0 — authority & conflict resolution

Order of authority when docs disagree:

  1. Templates (templates/pos-tool.sh, feature.sh, app.sh) — the codified current convention for new files. If an old tool deviates from its template, that's drift (unless the tool is intentionally category-less/nested).
  2. DEV.md — full convention detail, checklists, best practices (env seams, systemd units, alerting, managed blocks).
  3. AGENTS.md Quick facts — operational facts (make gen/check gate, header format, INTERACTIVE_CMDS gotcha, deps-guard-before-help). If it conflicts with DEV.md, DEV.md wins on detail, AGENTS.md wins on process.
  4. Code (# POS: headers, runtime behavior) — ground truth for what a tool does and for all GEN:-derived docs (make gen regenerates from code).
  5. POS.md / HOWTO / README / SCRIPTS / SYSTEMD / APPS — hand-written references; drift against code = doc bug (fix the doc) unless the doc describes a feature the code never shipped (phantom feature — fix the doc too).
  6. AGENT_Context_Project.md — generated blocks follow code; hand-maintained rows (§14 Common Tasks, non-pos-* line-count rows, "How to modify" table) must match reality.

Classification rule: runtime behavior = what the tool does; conventions = what it should do. Findings are classified bug (behavior wrong), convention-violation (behavior right but against current convention), doc-drift (reference wrong), standardization (two tools same thing differently).

Baseline

  • make gen && make check: green (doc-sync, exec bits, syntax, dispatch smoke all pass).
  • scripts/lint-conventions.sh (new, this audit): automated convention gate — see results below.
  • AGENT_TODO: Now empty (Tier 1 shipped). Audit itself is the current work.
  • Scope order (user-confirmed): bin/ + lib/ first, then install scripts + systemd, then features/entertainment/apps, then docs. All areas audited; this is report priority.
  • Pickiness: everything flagged, tagged severity + confidence. P3 = intentional/legacy no-action list.
  • Deliverables: MAINTENANCE.md (uncommitted) + scripts/lint-conventions.sh (to be committed as the reusable gate; make lint target still needs wiring in the Makefile).

Checklist (convention matrix — from AGENTS.md / AGENT_Context §11/§12 / DEV.md)

  • Shebang #!/usr/bin/env bash + set -euo pipefail (libs exempt — sourced)
  • # POS: header right after shebang, em-dash format; # POS_FLAGS: / # POS_SUBCMDS: / # POS_CONFIG: as needed
  • Dep-guards (command -v … || err) before -h|--help
  • stdin readers in INTERACTIVE_CMDS (bin/pos); no stale entries
  • No local outside functions
  • run/spawn respect $DRY_RUN; writes idempotent
  • common.sh sourced via $(dirname "$0")/../lib/… fallback chain (standalone from /usr/local/bin)
  • Entertainment plugins: no common.sh, # POS_PLUGIN:/# POS_KEYS:
  • Apps: uninstall_<name>() + uninstall dispatch
  • systemd units: TimeoutStopSec=5s, [Install], KillMode= on daemons
  • Env seams: every system path write has VAR="${VAR:-path}" guard
  • No hardcoded secrets; chmod 600 on creds/tokens
  • Docs: POS.md / README / HOWTO / AGENT_Context hand-maintained spots match behavior

Lint results (scripts/lint-conventions.sh)

Automated gate — FAIL = definite violation, WARN = manual review needed. All 18 FAIL/WARN classes below are verified real against source (heuristics were iterated until zero false positives; heredocs, ${...} brace-counting, while-loop stdin, /dev/tty reads, command -v fallbacks and env-guard secret patterns are all excluded).

FAIL — 12 (maps to tickets M-001, M-003..M-015) — ALL RESOLVED in the fix session (see ticket statuses)

  • features/autostart.sh — missing set -euo pipefail (→ M-001)
  • bin/pos-system-firewall — missing -h|--help handling (→ M-015)
  • bin/pos-docker-compose — reads stdin (read -rp :204, confirm :210) not in INTERACTIVE_CMDS (→ M-002)
  • bin/pos-docker-vbox — reads stdin (confirm :105) not in INTERACTIVE_CMDS (→ M-003)
  • bin/pos-network-hotspot — reads stdin (read -rp :53) not in INTERACTIVE_CMDS (→ M-004)
  • bin/pos-docker-health (:21/:24), bin/pos-docker-ps (:17/:20), bin/pos-media-mp3 (:38/:58), bin/pos-media-mp4 (:43/:71), bin/pos-network-scan (:28/:66), bin/pos-share-usb-server (:191/:199), bin/pos-system-health (:39/:119) — -h|--help dispatched before deps guards (→ M-008..M-014)

WARN — 6 (manual review done, all real docs-coverage gaps → M-023) — ALL RESOLVED

  • bin/pos-config, bin/pos-tree, bin/pos-entertainment-config, -enable, -disable, -status — not referenced anywhere in DOC/POS.md

Fix-session note: lint now reports 0 FAIL / 0 WARN. Two precision fixes were made to the lint itself (documented, not weakenings): first_guard_line() only treats real deps guards (command -v … ||, if ! command -v, command -v … \) as guards so graceful-degradation probes (system-health) don't trip the guard-before-help rule; first_line() skips comment lines so a comment containing -h|--help isn't mistaken for the dispatch.

Heuristics that passed clean (reviewed, no findings): no secrets committed (all TOKEN/SECRET/RPC_SECRET assignments are env guards / config reads / runtime generation), all libs' system writes carry command -v fallbacks, legacy wrappers are thin, no plugin sources common.sh, systemd units carry TimeoutStopSec=/WantedBy=.

Findings

Findings are tickets. Every ticket gets a unique M-### ID; the fix session works through them in order (P0/HIGH first). Keep this exact field set:

### M-000
Status: OPEN
Severity: HIGH | MEDIUM | LOW
Category: bug | convention | dead-code | docs | UX | standardization | security
Files: <path:line …>
Evidence: <what was observed, quote the actual code/output>
Expected: <what the convention/runtime says should happen>
Recommended fix: <one-line, actionable>
Verification: <how the fix session proves it fixed>

P0 — bugs / security

M-002

Status: VERIFIED Severity: HIGH Category: bug Files: bin/pos-docker-compose:204,210; bin/pos:259 Evidence: pos docker compose config/startup runs read -rp "Enter your Tailscale auth key…" (:204) and confirm "Edit .env before starting?" (:210) — both read stdin. bin/pos logging tee would swallow/hang these prompts because docker-compose is not in INTERACTIVE_CMDS (line 259). Same class of bug as the just-fixed smb-client prompt swallow. Expected: every tool that reads stdin is in INTERACTIVE_CMDS. Recommended fix: add docker-compose to INTERACTIVE_CMDS. Verification: pos docker compose config via pos (logged) still prompts. Fix (2026-08-14): added docker-compose to INTERACTIVE_CMDS in bin/pos:259. Verified: lint stdin-reader FAIL cleared for all three tools (M-002..M-004).

M-003

Status: VERIFIED Severity: HIGH Category: bug Files: bin/pos-docker-vbox:105; bin/pos:259 Evidence: pos docker vbox start calls confirm "Enter now?" (stdin read via lib/common.sh confirm()read -rp) at line 105. Not in INTERACTIVE_CMDS → prompt swallow/hang under the logging pipe. Expected: every stdin reader in INTERACTIVE_CMDS. Recommended fix: add docker-vbox to INTERACTIVE_CMDS. Verification: pos docker vbox start prompts correctly through the dispatcher. Fix (2026-08-14): added docker-vbox to INTERACTIVE_CMDS in bin/pos:259; lint stdin FAIL cleared.

M-004

Status: VERIFIED Severity: HIGH Category: bug Files: bin/pos-network-hotspot:53; bin/pos:259 Evidence: read -rp "Run in background? [y/N]: " bg at line 53 (non---foreground path). Not in INTERACTIVE_CMDS → prompt swallow/hang. Expected: every stdin reader in INTERACTIVE_CMDS. Recommended fix: add network-hotspot to INTERACTIVE_CMDS. Verification: pos network hotspot start <dev> <iface> prompts through the dispatcher. Fix (2026-08-14): added network-hotspot to INTERACTIVE_CMDS in bin/pos:259; lint stdin FAIL cleared.

M-005

Status: VERIFIED Severity: HIGH Category: bug Files: install.sh:38,84-99 Evidence: install.sh --steps documents format "1,3,4 or 1-3" (line 38) but the filter is [[ ",$STEPS_SPEC," != *",$phase_num,"* ]] (line 86) — only comma-separated matches. --steps 1-3 matches nothing → zero phases run, silently. Expected: both documented syntaxes work (comma list and N-M/N-M,K range). Recommended fix: expand the range spec into the explicit phase set before filtering (e.g. 1-31,2,3). Verification: install.sh --dry-run --steps 1-3 runs phases 1,2,3; --steps 1,3 runs 1,3. Fix (2026-08-14): added normalize_steps_spec() to install.sh (placed after variable init, before arg loop) — expands 1-31,2,3, validates single/range/list syntax, errors on garbage and end<start. Verified dry-run: --steps 1-3→1,2,3; --steps 3→3; --steps 2-2→2; --steps 1,3→1,3; --steps 1-2-3 and --steps 3-1 error.

M-006

Status: VERIFIED Severity: HIGH Category: docs Files: DOC/POS.md:217,220,298,324; DOC/howto/communication.md:83,91,102,200,317; DOC/howto/system.md:18,19,54,78; DOC/HOWTO.md:74; (code: bin/pos-system-health, bin/pos-system-backup) Evidence: pos system health [--send] [--markdown] and pos system backup --send are documented in 5 docs, but commit fe7708f deleted the flag handling from bin/pos-system-health (82 lines removed) — the tools now hit err "Unknown option '--send'". Not a flag our tools accept → documented feature would fail at runtime. Expected: docs match code. Either restore --send/--markdown (notify-path) or strip every reference and rework the howto examples that use it (@quiet pos system health --send maps). Recommended fix: decide feature vs docs: restore the notify send flags in system-health/backup (they were deleted alongside the old pos-health units) OR remove all --send/--markdown references. Update HOWTO examples accordingly. Verification: no --send/--markdown mention in docs that isn't in code (or flags work). Fix (2026-08-14): decision — do NOT restore the flags. fe7708f deliberately made health a console-only reporter ("health itself never sends notifications. Sending is the wrapper's job"); backup never had a --send flag; the scheduler's NOTIFY=always already delivers full output. Docs corrected instead: DOC/POS.md:217,220,298,324; DOC/howto/communication.md:83,91,102,200,317; DOC/howto/system.md (17-19, schedule example, env sample); DOC/HOWTO.md:74. Grep-verified: no stale system health --send/--markdown refs remain (only legit --markdown for matrix sender / entertainment send).

M-007

Status: VERIFIED Severity: MEDIUM Category: bug Files: lib/notify.sh:57,73,79,83 Evidence: warn "…" 2>/dev/null || echo "…" — when sourced standalone (notify.sh is designed to be sourceable without common.sh, line 3) and warn is absent, the || echo fallback writes the message to stdout. notify.sh is meant to be a silent helper (per-file note line 3: "so it can be sourced by tools that define their own log/warn/err"); stdout here contaminates wrappers/plugins (e.g. entertainment send). Expected: notify.sh must never write to stdout. Recommended fix: route fallbacks to stderr (warn() { printf … >&2; } or >&2 on the echoes). Verification: lib/notify.sh sourced alone prints nothing to stdout on a failed send. Fix (2026-08-14): only line 57 actually leaked stdout (|| echo "…"); lines 73/79/83 already end in || true (silent). Routed line 57's fallback to stderr (>… on the echo). Verified: standalone source lib/notify.sh; notify_send "" → stdout empty, message on stderr.

P1 — clear convention violations

M-001

Status: VERIFIED Severity: LOW Category: convention Files: features/autostart.sh Evidence: Lines 1-2: shebang then LOG="${HOME:-/root}/.autostart.log" directly — no set -euo pipefail. Template templates/feature.sh:2 requires it; sibling features/usb-automount.sh:2 has it. Expected: set -euo pipefail as line 2 (all scripts, libs exempt). Recommended fix: insert set -euo pipefail after the shebang (script already defensively uses || true). Verification: ./scripts/lint-conventions.sh clean; bash -n features/autostart.sh. Fix (2026-08-14): rewrote autostart.sh with the full feature-template preamble (set -euo pipefail, flags.sh load, usage()/-h|--help — folded into M-017). Verified: bash -n clean; -h prints usage; a real run appends the 3 log lines; lint clean.

M-008..M-014 — -h|--help before deps guards (standardization)

Status: VERIFIED Severity: MEDIUM Category: standardization Files: bin/pos-docker-health:21/24, bin/pos-docker-ps:17/20, bin/pos-media-mp3:38/58, bin/pos-media-mp4:43/71, bin/pos-network-scan:28/66, bin/pos-share-usb-server:191/199, bin/pos-system-health:39/119 Evidence: AGENTS.md/DEV.md convention — command -v deps guards sit before the -h|--help dispatch so help also errors on a box missing the dependency. These 7 tools dispatch help first. For docker-health/docker-ps the guard is only ~3 lines late (near-miss). For system-health there is no top-level guard at all (all command -v are per-check runtime probes at 119/166/182) — it degrades gracefully instead. Expected: uniform guard-before-help, or an explicitly documented exception for graceful-degradation tools. Recommended fix: move guards above help in the 6 hard-dep tools; for system-health either add a minimal guard (docker/fail2ban/systemctl are optional by design) or document it as the sanctioned no-guard pattern in DEV.md. Verification: make check green; ./scripts/lint-conventions.sh shows no dep-guard FAILs; each tool's --help still works without deps installed. Fix (2026-08-14): 6 hard-dep tools now guard before help — docker-health, docker-ps (converted to documented command -v X || err form), network-scan (moved up, kept its echo/exit style), share-usb-server (moved up), media-mp3/mp4 (guards moved before help with a --dry-run pre-scan preserving the documented dry-run-without-deps behavior; duplicate DRY_RUN=0 and post-loop guard blocks removed). system-health documented as the sanctioned no-guard pattern in DEV.md (graceful degradation). Lint refined: first_guard_line() only matches real guards (command -v … ||, if ! command -v, command -v … \) and first_line() skips comment lines. Verified: lint shows no dep-guard FAILs; restricted-PATH tests — pos media mp3 -h errors without deps, --dry-run still previews; pos share usb-server -h errors (usbsrv absent); mp4 mutual-exclusion checks intact.

M-015

Status: VERIFIED Severity: MEDIUM Category: convention Files: bin/pos-system-firewall Evidence: pos system firewall has no usage() and no -h|--help case at all — first thing is a root check, then read -rp "Execute this command?…". Violates the universal tool contract (templates/pos-tool.sh). Lint FAIL confirms. Expected: -h|--help shows a usage synopsis. Recommended fix: add usage() + -h|--help case (per templates/pos-tool.sh), keeping the root/deps checks ahead of it. Verification: pos system firewall --help prints usage without prompting. Fix (2026-08-14): added usage() + -h|--help case after the root check and notify.sh source (root check stays first — tool is root-only by design). Verified as root: sudo pos-system-firewall -h prints usage, exit 0.

M-016

Status: VERIFIED Severity: MEDIUM Category: convention Files: preinstall.sh:28-41 (PACKAGES); bin/pos-media-mp3:59, bin/pos-media-mp4:72 Evidence: both media tools command -v ffmpeg || err … — ffmpeg is an apt package, so per DEV.md "apt packages → PACKAGES array in preinstall.sh" it belongs there. It's absent (only yt-dlp is handled, via manual curl). Expected: ffmpeg in PACKAGES; tools keep the guard as a safety net for non-install.sh installs. Recommended fix: add ffmpeg to PACKAGES. Verification: install.sh installs ffmpeg; mp3/mp4 guards remain as fallback. Fix (2026-08-14): added ffmpeg to the PACKAGES array in preinstall.sh. bash -n clean; mp3/mp4 command -v ffmpeg || err guards untouched.

M-017

Status: VERIFIED Severity: LOW Category: convention Files: features/autostart.sh Evidence: template templates/feature.sh:24-26 requires sourcing lib/flags.sh (# POS_FLAGS: support), and the tool contract requires -h|--help. autostart.sh has neither — it's a bare boot script. Also missing set -euo pipefail (M-001). Expected: feature template contract (set -euo pipefail, flags.sh load, -h|--help). Recommended fix: add the template preamble (flags.sh load + usage/-h); no functional change to boot logic. Verification: bash -n clean; -h prints usage; lint clean. Fix (2026-08-14): full template preamble added (flags.sh load via the repo/usr-local fallback chain, FEATURE_NAME, usage() with Flag/Log lines, -h|--help case). Boot logic unchanged. Verified: bash -n, -h usage, live run logs 3 lines, lint clean.

M-018

Status: VERIFIED Severity: LOW Category: convention Files: features/usb-automount.sh Evidence: same as M-017 — feature template flags.sh load (templates/feature.sh:24-26) absent. (Has set -euo pipefail, so only flags.sh + usage are missing.) Recommended fix: add flags.sh load + usage/-h per template. Verification: lint clean; -h works. Fix (2026-08-14): added the flags.sh load (repo/usr-local fallback) right after set -euo pipefail. usage()/-h|--help already present. Verified: bash -n, lint clean.

M-019

Status: VERIFIED Severity: LOW Category: standardization Files: apps/media/scrcpy.sh Evidence: 0644 (-rw-rw-r--) while every other apps/*/*.sh is 0755. Consistent exec-bit convention violated. Recommended fix: chmod +x apps/media/scrcpy.sh. Verification: ls -l apps/media/scrcpy.sh shows 0755; make check exec-bit gate green. Fix (2026-08-14): chmod +x apps/media/scrcpy.sh → 0755. make check exec-bit gate will confirm at final run.

M-020

Status: VERIFIED Severity: LOW Category: standardization Files: bin/pos-docker-compose:8,9 Evidence: SCALE_DIR="/usr/local/share/linux_post_install/scale-tail/services" and CONFIG_ENV="${HOME}/.config/linux_post_install/compose.env" hardcoded — no ${VAR:-…} env seam, unlike the documented SERVICES_BASE default (/srv). DEV.md seam rule says every system path write has a VAR="${VAR:-path}" guard. Expected: SCALE_DIR="${SCALE_DIR:-/usr/local/share/…}" etc. Recommended fix: add :- seams for SCALE_DIR and CONFIG_ENV. Verification: env override respected in a dry-run. Fix (2026-08-14): added :- seams for both. Verified: CONFIG_ENV=/tmp/... config prints the override; SCALE_DIR=/tmp/... ls errors citing the override. Follow-on found while verifying: pos docker compose config crashed with DIM: unbound variable (common.sh color block had no DIM; pre-existing on HEAD). Fixed by adding DIM=$(tput dim) / empty-fallback to the common.sh color block. config now prints correctly.

P2 — doc drift / consistency / style

M-021

Status: VERIFIED Severity: LOW Category: standardization Files: lib/notify.sh:27, lib/entertainment-lib.sh:5, lib/config-ui.sh:22, bin/pos-network-download:16, bin/pos-communication-{matrix,telegram}-{listener,sender} Evidence: CONFIG_DIR redefined per-file with inconsistent semantics: notify.sh is XDG-aware (${XDG_CONFIG_HOME:-$HOME/.config}), the rest use plain $HOME/.config/linux_post_install, network-download uses the ${CONFIG_DIR:-…} seam form. Same global name, three conventions. Expected: one definition (in lib/common.sh) + seam form everywhere. Recommended fix: define CONFIG_DIR once in common.sh; drop per-file definitions (keep the :- seam in network-download). Verification: all tools still resolve config after refactor. Fix (2026-08-14): canonical CONFIG_DIR="${CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/linux_post_install}" defined in common.sh; dropped the duplicate in entertainment-lib.sh (loads common.sh) and network-download (loads common.sh). Standalone-sourced files (notify.sh, config-ui.sh, the matrix/telegram listener/sender — none source common.sh) keep an identical guarded seam line, mirroring the "no shared lib? inline fallbacks" convention; noted in common.sh. Verified: notify.sh standalone resolves default/XDG/CONFIG_DIR overrides correctly; pos-config (common.sh + config-ui) works; all touched files bash -n clean.

M-022

Status: VERIFIED Severity: LOW Category: standardization Files: lib/entertainment-lib.sh (plugin_dir/plugin_exists/plugin_keys/plugin_marker), lib/entertainment-plugin-lib.sh (plugin_config_file/plugin_err/plugin_have/plugin_http_json/plugin_load_config/plugin_require) Evidence: two libs share the plugin_* prefix for unrelated jobs (marker/registry helpers vs plugin runtime helpers). Collision-prone and unclear at call sites. Expected: distinct prefixes per concern. Recommended fix: rename the plugin-lib helpers (e.g. plt_*/plugin_rt_*) or the marker helpers; keep one prefix per lib. Verification: grep for plugin_ shows no cross-lib ambiguity; make gen && make check green. Fix (2026-08-14): kept plugin_* for the documented plugin-authoring API (plugin_load_config/plugin_have/plugin_require/plugin_http_json/plugin_err/plugin_config_file — referenced in DOC/DEV.md and DOC/POS.md; user plugins depend on it). Renamed the internal registry helpers in lib/entertainment-lib.sh to ent_plugin_dir/ent_plugin_marker/ent_plugin_exists/ent_plugin_keys and updated callers (pos-entertainment-{status,enable,config,send}, lib/config-ui.sh). Verified: no bare plugin_ registry helpers remain; plugin runtime helpers untouched; entertainment tools + pos-config smoke-tested; bash -n clean.

M-023

Status: VERIFIED Severity: LOW Category: docs Files: DOC/POS.md; bin/pos-config, bin/pos-tree, bin/pos-entertainment-{config,enable,disable,status} Evidence: 6 shipped tools are absent from the POS.md command reference (31 bin/pos-* refs exist but not these). Lint WARN confirms. Expected: every tool documented in POS.md. Recommended fix: add rows to the POS.md command table (and cross-check HOWTO for the entertainment group). Verification: lint WARNs gone; grep shows each tool in POS.md. Fix (2026-08-14): the tools were documented by command name but not by filename (the lint references basenames). Added **File:** bin/pos-config (config section), **File:** bin/pos-tree (tree section), and a file list on the entertainment section header covering bin/pos-entertainment-{config,enable,disable,status}. Verified: lint 0 WARN. HOWTO already covers the entertainment group via pos entertainment * command forms.

M-024

Status: VERIFIED Severity: LOW Category: docs Files: AGENTS.md:17-18; DOC/SCRIPTS.md (Phase-2 lib list, TOC, new lib section) Evidence: the command-registry feature landed (lib/registry.sh, 199 lines; optional # POS_DEPS:/# POS_EXAMPLES: headers already codified in templates/pos-tool.sh:13-14 and DOC/DEV.md:126-134) but three docs kept describing the old reality: AGENTS.md Quick facts enumerated only POS_FLAGS/SUBCMDS/CONFIG with no mention of the shared query API; DOC/SCRIPTS.md's Phase-2 lib list omitted registry.sh and had no section for it (its TOC also lacked five pre-existing lib sections). Expected: docs describe what IS — code + # POS: headers are ground truth (Phase 0 rule 4). Recommended fix: sync the three drifted docs to implemented reality; no code/template/completion changes. Verification: make gen produces zero diff beyond pre-existing work; make check green; make lint 0 FAIL / 0 WARN; grep -n "POS_DEPS" hits AGENTS.md, DEV.md, SCRIPTS.md. Fix (2026-08-26): template templates/pos-tool.sh now documents the optional # POS_DEPS:/# POS_EXAMPLES: headers (pre-existing); lib/registry.sh added as the shared query API over all POS_* headers (reg_scan + reg_list/reg_lookup/…) — AGENTS.md Tool-model + Categories bullets updated, DOC/SCRIPTS.md got the lib-list row (install.sh:143 order), a per-lib reference section, and a completed TOC. Consumers were already migrated (bin/pos-tree, bin/pos _pos_category_help()); lint unchanged (0 FAIL / 0 WARN).

P3 — intentional / legacy (no action)

  • install.sh:123,135,155,185 — installer writes to /usr/local/bin are its purpose; no seam needed (lint excludes install scripts).
  • network-download RPC_SECRET at :150 — generated at runtime (/dev/urandom), not a committed secret.
  • system-health graceful degradation — candidate for the sanctioned no-guard pattern (see M-014); decide in fix session whether it becomes a P1 or a P3. Commit fe7708f's removal of the old pos-health.{service,timer} units is correct (superseded by scheduler); the only leftover is the stale docs (M-006).

Semantic deep-dive notes (the detective pass)

  • lib/notify.sh — stdout-leak via warn … || echo fallbacks (M-007); rest of helper logic (platform routing, silent-fail contract) correct.
  • lib/common.shconfirm() reads stdin via read -rp → it makes any caller an INTERACTIVE_CMDS candidate (this is how M-003/M-002 were caught). Deps guards, run/spawn, $DRY_RUN semantics all match convention.
  • bin/pos — INTERACTIVE_CMDS list (259) was complete except the 3 new stdin readers (M-002..M-004); no stale entries (lint reverse-check green). Dispatcher longest-prefix logic unchanged from prior fix session.
  • bin/pos-system-firewall — entirely interactive; root-check-first is correct, but no usage/-h at all (M-015).
  • bin/pos-system-health — pure passive reporter; per-check command -v probes are correct for graceful degradation, but leave the no-top-level-guard pattern undocumented (M-014). Prints to stdout by design (it IS the report) — the notify path is what the docs claim (M-006) but was removed in fe7708f.
  • install.sh--steps comma-only parsing (M-005); the phase functions themselves and step numbering are consistent with the header. Legacy x-systemd.automount-style remnants: none — the fstab/automount handling in share tools uses correct systemd units now (verified in prior fix session, commits 1724096/93fb6b6).
  • pos-docker-compose — hardcoded template dir + config path (M-020); SERVICES_BASE documented in # POS_CONFIG: and used at runtime for deployments, but not for SCALE_DIR.
  • No x-systemd.automount in any unit Options= (grep clean). No interact/getconf-style stale-format headers anywhere in bin/.
  • Entertainment plugins: none source common.sh; all carry # POS_PLUGIN: + # POS_KEYS: (lint green).
  • systemd units: TimeoutStopSec= + [Install] WantedBy= present everywhere (lint green); no leftover pos-health.{service,timer} (removed in fe7708f, correct).

Next-session brief

  1. Fix P0 → P1 → P2 in order (HIGH first: M-002..M-006, then M-007, then the rest).
  2. M-006 needs a product decision first: restore --send/--markdown (notify path) or strip the docs.
  3. Re-run make gen && make check && make lint + smoke each changed tool.
  4. DONE — scripts/lint-conventions.sh committed and make lint wired into the Makefile (5ef38dc).
  5. Move audit tasks to AGENT_TODO Done (dated) on completion.

Checked & clean

  • lib/common.sh (deps/run/spawn/confirm — semantics verified)
  • lib/notify.sh (logic — only the stdout-fallback leak, M-007)
  • legacy wrappers bin/wr-*, bin/mp3, bin/mp4, bin/vbox, bin/ssh-load-all (thin, forward to pos)
  • systemd/*.service (TimeoutStopSec + WantedBy everywhere)
  • entertainment/*.sh (no common.sh, POS_PLUGIN/POS_KEYS present)
  • secrets: no committed credentials anywhere (grep for TOKEN/SECRET/AUTHKEY/RPC_SECRET literals clean — all guards/config-reads/runtime-gen)
  • stale-format conventions: no x-systemd.automount, no old header formats, no leftover pos-health units