diff options
Diffstat (limited to 'todo.org')
| -rw-r--r-- | todo.org | 190 |
1 files changed, 91 insertions, 99 deletions
@@ -39,39 +39,6 @@ Tags are assigned and refreshed by =task-audit=; =task-review= keeps them honest * Rulesets Open Work -** DONE [#B] Sentry workflow — build from spec :feature: -CLOSED: [2026-07-19 Sun] -:PROPERTIES: -:SPEC_ID: f6c51f27-d7a2-4b63-9ff9-5ba005a66dfb -:END: -Built the sentry supervisor workflow from the spec -([[file:docs/specs/2026-07-14-sentry-workflow-spec.org][sentry workflow spec]], now IMPLEMENTED). Four phases, each committed and -pushed in no-approvals + auto-flush mode; full suite green throughout. The overnight -live trial is handed to Craig as a manual-testing task (below); its findings file as -follow-ups. -*** 2026-07-19 Sun @ 04:52:00 -0500 Built the agent-lock helper + 18 bats tests -=.ai/scripts/agent-lock= (canonical =claude-templates/.ai/scripts/=, mirror synced): -mkdir-atomic acquire, PID/host/ISO-timestamp metadata, mtime-based staleness reclaim -(atomic-rename claim so two acquirers can't double-acquire — caught by the pre-commit -review), heartbeat refresh, acquire/release/status/path subcommands, XDG_RUNTIME_DIR -home with =~/.cache= fallback. Commit a8b6cf4. -*** 2026-07-19 Sun @ 04:56:00 -0500 Built the sentry.org engine + INDEX entry -=.ai/workflows/sentry.org= (mirror synced): :COMMIT_AUTONOMY: entry ticket, the -interactive entry gates, ff-only reconcile, =sentry/<date>-<host>= branch mechanics, -the ten-pass probe→work→session-context→commit runner, digest + morning-approval -queue, skip-not-degrade safety, spine-excluded dirty checks + fire-end digest commit, -multi-day stall notify, the stop-sentry operation. All 10 decisions and 12 findings -reflected. Commit ccc9c26. -*** 2026-07-19 Sun @ 05:00:00 -0500 Wired the roam writers + wrap-up guard -knowledge-base.md and inbox.org core §5 acquire the roam-write lock and edit-plus- -trigger (roam-sync stays sole committer); roam-sync.sh header updated to match; -wrap-it-up.org gained a Step 0 active-sentry guard; triage-intake.org notes its -sentry-pass role. Graceful degradation when agent-lock is absent. Commit c6383e9. -*** 2026-07-19 Sun @ 05:04:00 -0500 Verified suite green + flipped spec to IMPLEMENTED -=make test= green at HEAD (pytest 393, ERT + bats all pass, exit 0). Flipped the spec -keyword DOING → IMPLEMENTED with a dated history line and mirrored the Metadata Status. -Filed the overnight live trial as a structured manual-testing task. - ** TODO Manual testing and validation *** Sentry — entry gates fire with Craig present What we're verifying: the interactive entry gates stop for the right states and start the loop only on a clean, green baseline. @@ -205,27 +172,6 @@ session needs its own contract (mutation rights, async surfacing, dedup state across runs) — same open questions inbox.org logs for unattended auto inbox zero. Take up only if the interactive shape proves too narrow. -** DONE [#C] ai launcher hardening — bug hunt + refactor pass :refactor:solo: -CLOSED: [2026-07-19 Sun] -:PROPERTIES: -:CREATED: [2026-07-13 Mon] -:LAST_REVIEWED: 2026-07-19 -:END: -Resolved across two commits (113e8d8 net, 2b619f1 refactor). Brought the 17 uncovered functions under characterization tests (launcher tests 9 → 42), extracted the git/tmux decision logic into four pure cores (_git_prep_action, _order_windows, _match_window_id, _git_is_dirty) each with a Normal/Boundary/Error set, and dispositioned the footgun audit + /refactor pass. Objective floor met: shellcheck clean, shfmt -i 2 -ci consistent, make test green before and after, live black-box smoke correct for claude and codex. Honest limit: attach_session and the full end-to-end of single/multi/fetch stay partially covered (their terminal step attaches to tmux or blocks on fzf, can't run headless). Their decision logic was extracted into the netted cores. The interactive runtime picker stayed out of scope (a design call, filed on the generic-agent-runtime parent). -Harden =claude-templates/bin/ai= (the agent-session launcher, 540 lines, 22 functions). Origin: roam inbox 2026-07-13, phrased open-endedly ("find bugs until none visible, refactor until nothing worthwhile remains"). Rescoped 2026-07-19 with measurable acceptance criteria per =todo-format.md='s "Making an open-ended task measurable," which is what makes it =:solo:=. The four moves: - -1. *Bound the surface.* The 22 functions are the done-set. *Covered* (behaviorally, via =scripts/tests/ai-launcher-runtime.bats=, 9 tests over the runtime path): =resolve_agent_cmd=, =build_runtime_choices=, =pick_runtime=, =build_instructions=, the print modes. *Uncovered* (the 17 to bring under test): =usage=, =check_deps=, =attach_session=, =create_window=, =maybe_add_candidate=, =build_candidates=, =fetch_candidates=, =git_status_indicator=, =annotate_candidates=, =auto_pull_if_clean=, =read_selections=, =sort_windows=, =find_window_id=, =prep_git_single=, =attach_mode=, =single_mode=, =multi_mode=, =print_launch_mode=. - -2. *Net the behavior.* Characterization tests (Normal/Boundary/Error per unit, per =testing.md=) over the uncovered surface. The pure/near-pure ones take the category set directly: =git_status_indicator=, =maybe_add_candidate= (dedup), =annotate_candidates= (formatting), =read_selections= (selection parse), =usage=. The =tmux=/=git=-coupled ones (=sort_windows='s ordering, =create_window=, =attach_session=, =find_window_id=, =prep_git_single=, =auto_pull_if_clean=) get their pure decision logic extracted into helpers that take plain inputs and return plain results — that extraction *is* the hardening — with the I/O calls left as thin wrappers. - -3. *Disposition every finding.* (a) A bash-footgun audit per function, each cell fixed / n-a / filed: unquoted expansions + word-splitting, =set -euo pipefail= gaps and where errexit is intentionally off, subshell state loss, exit-code propagation, ordering/races in =sort_windows= + window creation, and the git-prep error paths (=prep_git_single= / =auto_pull_if_clean= on a dirty tree, detached HEAD, no upstream). (b) A =/refactor= pass, each finding applied (tests green) or declined with a one-line reason. - -4. *Objective floor.* =shellcheck= clean, =shfmt=-consistent, =make test= green before and after, and every uncovered function above has its characterization set (a per-function checklist — =kcov= isn't installed; install it if a single coverage number is wanted). Plus ~3 functional tests over the launch pipelines (=single_mode=, =multi_mode=, =attach_mode=) against a throwaway =tmux= session, for the composition bugs no per-function unit can see. - -*Qualifying answer:* a dispositioned report — surface split covered/uncovered, tests before → after, =shellcheck=/=shfmt= result, the footgun matrix fully dispositioned, the =/refactor= findings fully dispositioned, all green. Not "no bugs remain" (unprovable) — "every enumerated path passes its characterization set and clears the audit." - -*Out of this task's =:solo:= scope:* an interactive runtime picker. It's a feature carrying a design/preference call (does Craig want it, what shape), which is deliberation, not hardening — file it separately if wanted. The runtime-selection arc (claude/codex shipped; ollama/qwen pending the model-floor eval) stays on the generic-agent-runtime parent. - ** TODO [#B] Extend ui-prototyping rule with build-to-prototype :feature: :PROPERTIES: :CREATED: [2026-07-11 Sat] @@ -247,16 +193,6 @@ Open question from the roam inbox (2026-07-11): could the startup sequence for . :END: From the roam inbox (2026-07-11): work in progress in one project shouldn't stop the sync gate. Idea: keep all diffs/changes in a =working/= directory and exclude it (and its subdirectories) from the sync gate. Many projects run at once, so their WIP files need to be grouped. Also add a per-project count of when the gate tripped, tracked as a metric to investigate. Distinct from the 2026-07-02 policy (untracked/gitignored changes already pass — this is about *tracked* WIP under =working/=). Verify how the gate detects dirtiness today before designing. -** DONE [#C] Put install-ai on PATH, launchable as =install-ai= :chore:quick:solo: -CLOSED: [2026-07-18 Sat] -:PROPERTIES: -:CREATED: [2026-07-11 Sat] -:LAST_REVIEWED: 2026-07-13 -:END: -From the roam inbox (2026-07-11): make install-ai launchable as =install-ai= (no =.sh=) from PATH. dotfiles needs a copy that stays in sync with the rulesets canonical — decide whether the startup script-sync already covers it or a dedicated mechanism is needed. - -Resolved: added =claude-templates/bin/install-ai=, a thin launcher that resolves its own path through the symlink chain and execs =scripts/install-ai.sh=. =make install='s existing bin loop symlinks it into =~/.local/bin/install-ai= (same mechanism as =ai= and =agent-page=), so no dedicated sync and no dotfiles copy — the symlink always points at the canonical. 3 launcher bats added (incl. symlink-invocation resolution). Verified live: =install-ai --help= runs from PATH. - ** TODO [#B] Document (and own) the Signal pager :feature:spec: :PROPERTIES: :CREATED: [2026-07-11 Sat] @@ -378,16 +314,6 @@ Design (Craig, 2026-06-28, supersedes the two proposed options): make the exempt *** 2026-07-19 Sun @ 18:41:00 -0500 Reconciled the flashcard multi-tag tooling into canonical Commit a14e43b. Broadened =CARD_RE= in both =flashcard-to-anki.py= and =flashcard-stats.py= so a heading is a card when =drill= is among its tag block (=:fundamental:drill:=), bounded card bodies by any L1/L2 heading (=HEADING_RE=), and added =--tag-filter= (subset emit) + =--guid-salt= (distinct GUID space) to to-anki, plus a drill-membership guard to stats. Re-derived against the current canonical rather than copying the preserved 2026-06-17 files, which predated the =#+TITLE= fix (060a938) and would have reverted it. parse()'s 3rd element is now the Anki-tag list; existing parse tests moved to that contract, new tests cover multi-tag / tag-filter / guid-salt / stats count, and a =flashcard-sync.bats= case guards the count. The real 465/100 check needs the work deck; verified end-to-end on a synthetic deck (2 cards → 1 with =--tag-filter fundamental=) through real genanki. Speedrun task 2 of 2. -** DONE [#C] coverage-summary.el documented as a local-only helper :chore:quick:solo: -CLOSED: [2026-07-18 Sat] -:PROPERTIES: -:CREATED: [2026-06-22 Mon] -:LAST_REVIEWED: 2026-07-13 -:END: -The elisp bundle installs =coverage-summary.el= into =.claude/scripts/=, gitignored in code projects, so CI can't run =make coverage-summary= against it. Decision (Craig, 2026-06-28): keep it in =.claude/scripts/= and document it as a local-only helper — don't ship it to a tracked =scripts/= dir, don't expect CI to run it. Remaining work (docs only, no move): state the local-only status in the script's header comment and wherever =make coverage-summary= is described, so the gitignored install reads as intentional rather than a gap. Note: emacs-wttrin rewrote its copy's header to claim a tracked =scripts/= home, which now contradicts this decision and should be reverted on their side. Surfaced 2026-06-21 during the coverage-summary autoloads bugfix (commit fb86736). - -Resolved: documented the local-only status in the =coverage-summary.el= commentary header and in =elisp-testing.md='s "Measuring it" section — the gitignored install now reads as intentional, not a coverage gap. Sent emacs-wttrin a handoff to revert its contradicting header claim. - ** TODO [#C] Agent-KB / memory-sync — work + unknown-project write refusal :test: :PROPERTIES: :LAST_REVIEWED: 2026-07-13 @@ -1380,6 +1306,97 @@ having a skill to generate or check OV-1-shaped artifacts. Don't build speculatively — defense-specific notations are narrow enough that each skill should be driven by a concrete contract need, not aspiration. +* Rulesets Resolved +** CANCELLED [#C] ntfy phone channel as general two-way agent-comms :feature:spec: +CLOSED: [2026-07-13 Mon] +:PROPERTIES: +:CREATED: [2026-06-20 Sat] +:LAST_REVIEWED: 2026-06-24 +:END: +Killed at the 2026-07-13 task review: home retired and tore down the ntfy channel on 2026-07-04, so this proposal's transport no longer exists. Its living successors are the Signal pager ([#B] task above — one identity on velox, runbook pending) and agent-page (shipped 2026-07-13), which cover the send half; two-way (read-replies) rides the Signal runbook. +Proposal from the home project (2026-06-17): promote the self-hosted ntfy-over-Tailscale phone channel it built and verified on ratio into a general two-way agent-comms tool rulesets owns. Full proposal: [[file:docs/design/2026-06-17-ntfy-agent-comms-proposal.org]] (as-built runbook stays in the home project at =working/phone-notifications/spec.org=). What rulesets would decide: canonicalize =phone-notify= (send) plus a new =phone-recv= (check-since) as synced bin scripts; the per-machine config/secret convention (token in =~/.config/phone-notify/config= chmod 600 today, vs GPG-encrypted in dotfiles); a reference =ntfy-inbound-handler= plus systemd user-unit for event-driven delivery (Tier A subscriber routes inbound to inbox/notify, Tier B inbound spawns an agent session, Tier C notify a live session — harness research); approval-button workflows for the commits.md gates when Craig is away from the desk (tap-to-approve, the high-value concrete use); and the relationship to the retired cross-agent-comms scripts (ntfy may be the transport they lacked). Worked via =spec-create=. Blocks the triage-intake phone-push task below. +** DONE [#B] Org-table helpers corrupt example blocks :bug:solo: +CLOSED: [2026-07-14 Tue] +:PROPERTIES: +:CREATED: [2026-07-11 Sat] +:LAST_REVIEWED: 2026-07-13 +:END: +Fixed in 951b6fc, test-first. Both defects landed as filed (block-type-aware scanning in both helpers; lint-org CLI report-only by default, writes behind --fix), plus the true corruption path found during the work: wrap-org-table's load-time CLI dispatch fired on lint-org's require and reformatted lint-org's file arguments. Entry-script guard added. The named regression test (example block byte-identical) is in the suite. +=wrap-org-table.el= and =lint-org.el= both scan for =/^\s*|/= lines and rewrite them as org tables without skipping =#+begin_example=/=src=/=quote= regions, so ASCII art using pipe characters gets mangled into bordered tables. Reproduced 2026-07-09 in the work project against an architecture doc with a pipe/=v= flow diagram; a plain indented block became a table with =|---|= rules between every line. Two separable defects: (1) table detection is line-based — both helpers should use =org-element-at-point= / =org-in-block-p= to skip example/src/quote/verse blocks; (2) =lint-org.el= mutates its input on disk with no confirmation — passing five files reformatted all five (one by 1949 lines). A linter must report, not write; put the reformat behind an explicit =--fix= flag. + +Grading (severity × frequency, per todo-format.md): Critical severity (silent org data loss; recoverable here only because the content was git-staged) × rare-edge-case frequency (fires only when a mixed table+example file is passed to the helper) = P2 = [#B]. + +Regression test: run =wrap-org-table.el= against a file containing a =#+begin_example= block whose lines start with =|= and assert the block is byte-identical afterward. Source: work handoff 2026-07-09 (=inbox/2026-07-09-1341-from-work-bug-data-loss-wrap-org-table-el-and.org=). +** DONE [#B] Sentry workflow — build from spec :feature: +CLOSED: [2026-07-19 Sun] +:PROPERTIES: +:SPEC_ID: f6c51f27-d7a2-4b63-9ff9-5ba005a66dfb +:END: +Built the sentry supervisor workflow from the spec +([[file:docs/specs/2026-07-14-sentry-workflow-spec.org][sentry workflow spec]], now IMPLEMENTED). Four phases, each committed and +pushed in no-approvals + auto-flush mode; full suite green throughout. The overnight +live trial is handed to Craig as a manual-testing task (below); its findings file as +follow-ups. +*** 2026-07-19 Sun @ 04:52:00 -0500 Built the agent-lock helper + 18 bats tests +=.ai/scripts/agent-lock= (canonical =claude-templates/.ai/scripts/=, mirror synced): +mkdir-atomic acquire, PID/host/ISO-timestamp metadata, mtime-based staleness reclaim +(atomic-rename claim so two acquirers can't double-acquire — caught by the pre-commit +review), heartbeat refresh, acquire/release/status/path subcommands, XDG_RUNTIME_DIR +home with =~/.cache= fallback. Commit a8b6cf4. +*** 2026-07-19 Sun @ 04:56:00 -0500 Built the sentry.org engine + INDEX entry +=.ai/workflows/sentry.org= (mirror synced): :COMMIT_AUTONOMY: entry ticket, the +interactive entry gates, ff-only reconcile, =sentry/<date>-<host>= branch mechanics, +the ten-pass probe→work→session-context→commit runner, digest + morning-approval +queue, skip-not-degrade safety, spine-excluded dirty checks + fire-end digest commit, +multi-day stall notify, the stop-sentry operation. All 10 decisions and 12 findings +reflected. Commit ccc9c26. +*** 2026-07-19 Sun @ 05:00:00 -0500 Wired the roam writers + wrap-up guard +knowledge-base.md and inbox.org core §5 acquire the roam-write lock and edit-plus- +trigger (roam-sync stays sole committer); roam-sync.sh header updated to match; +wrap-it-up.org gained a Step 0 active-sentry guard; triage-intake.org notes its +sentry-pass role. Graceful degradation when agent-lock is absent. Commit c6383e9. +*** 2026-07-19 Sun @ 05:04:00 -0500 Verified suite green + flipped spec to IMPLEMENTED +=make test= green at HEAD (pytest 393, ERT + bats all pass, exit 0). Flipped the spec +keyword DOING → IMPLEMENTED with a dated history line and mirrored the Metadata Status. +Filed the overnight live trial as a structured manual-testing task. +** DONE [#C] ai launcher hardening — bug hunt + refactor pass :refactor:solo: +CLOSED: [2026-07-19 Sun] +:PROPERTIES: +:CREATED: [2026-07-13 Mon] +:LAST_REVIEWED: 2026-07-19 +:END: +Resolved across two commits (113e8d8 net, 2b619f1 refactor). Brought the 17 uncovered functions under characterization tests (launcher tests 9 → 42), extracted the git/tmux decision logic into four pure cores (_git_prep_action, _order_windows, _match_window_id, _git_is_dirty) each with a Normal/Boundary/Error set, and dispositioned the footgun audit + /refactor pass. Objective floor met: shellcheck clean, shfmt -i 2 -ci consistent, make test green before and after, live black-box smoke correct for claude and codex. Honest limit: attach_session and the full end-to-end of single/multi/fetch stay partially covered (their terminal step attaches to tmux or blocks on fzf, can't run headless). Their decision logic was extracted into the netted cores. The interactive runtime picker stayed out of scope (a design call, filed on the generic-agent-runtime parent). +Harden =claude-templates/bin/ai= (the agent-session launcher, 540 lines, 22 functions). Origin: roam inbox 2026-07-13, phrased open-endedly ("find bugs until none visible, refactor until nothing worthwhile remains"). Rescoped 2026-07-19 with measurable acceptance criteria per =todo-format.md='s "Making an open-ended task measurable," which is what makes it =:solo:=. The four moves: + +1. *Bound the surface.* The 22 functions are the done-set. *Covered* (behaviorally, via =scripts/tests/ai-launcher-runtime.bats=, 9 tests over the runtime path): =resolve_agent_cmd=, =build_runtime_choices=, =pick_runtime=, =build_instructions=, the print modes. *Uncovered* (the 17 to bring under test): =usage=, =check_deps=, =attach_session=, =create_window=, =maybe_add_candidate=, =build_candidates=, =fetch_candidates=, =git_status_indicator=, =annotate_candidates=, =auto_pull_if_clean=, =read_selections=, =sort_windows=, =find_window_id=, =prep_git_single=, =attach_mode=, =single_mode=, =multi_mode=, =print_launch_mode=. + +2. *Net the behavior.* Characterization tests (Normal/Boundary/Error per unit, per =testing.md=) over the uncovered surface. The pure/near-pure ones take the category set directly: =git_status_indicator=, =maybe_add_candidate= (dedup), =annotate_candidates= (formatting), =read_selections= (selection parse), =usage=. The =tmux=/=git=-coupled ones (=sort_windows='s ordering, =create_window=, =attach_session=, =find_window_id=, =prep_git_single=, =auto_pull_if_clean=) get their pure decision logic extracted into helpers that take plain inputs and return plain results — that extraction *is* the hardening — with the I/O calls left as thin wrappers. + +3. *Disposition every finding.* (a) A bash-footgun audit per function, each cell fixed / n-a / filed: unquoted expansions + word-splitting, =set -euo pipefail= gaps and where errexit is intentionally off, subshell state loss, exit-code propagation, ordering/races in =sort_windows= + window creation, and the git-prep error paths (=prep_git_single= / =auto_pull_if_clean= on a dirty tree, detached HEAD, no upstream). (b) A =/refactor= pass, each finding applied (tests green) or declined with a one-line reason. + +4. *Objective floor.* =shellcheck= clean, =shfmt=-consistent, =make test= green before and after, and every uncovered function above has its characterization set (a per-function checklist — =kcov= isn't installed; install it if a single coverage number is wanted). Plus ~3 functional tests over the launch pipelines (=single_mode=, =multi_mode=, =attach_mode=) against a throwaway =tmux= session, for the composition bugs no per-function unit can see. + +*Qualifying answer:* a dispositioned report — surface split covered/uncovered, tests before → after, =shellcheck=/=shfmt= result, the footgun matrix fully dispositioned, the =/refactor= findings fully dispositioned, all green. Not "no bugs remain" (unprovable) — "every enumerated path passes its characterization set and clears the audit." + +*Out of this task's =:solo:= scope:* an interactive runtime picker. It's a feature carrying a design/preference call (does Craig want it, what shape), which is deliberation, not hardening — file it separately if wanted. The runtime-selection arc (claude/codex shipped; ollama/qwen pending the model-floor eval) stays on the generic-agent-runtime parent. +** DONE [#C] Put install-ai on PATH, launchable as =install-ai= :chore:quick:solo: +CLOSED: [2026-07-18 Sat] +:PROPERTIES: +:CREATED: [2026-07-11 Sat] +:LAST_REVIEWED: 2026-07-13 +:END: +From the roam inbox (2026-07-11): make install-ai launchable as =install-ai= (no =.sh=) from PATH. dotfiles needs a copy that stays in sync with the rulesets canonical — decide whether the startup script-sync already covers it or a dedicated mechanism is needed. + +Resolved: added =claude-templates/bin/install-ai=, a thin launcher that resolves its own path through the symlink chain and execs =scripts/install-ai.sh=. =make install='s existing bin loop symlinks it into =~/.local/bin/install-ai= (same mechanism as =ai= and =agent-page=), so no dedicated sync and no dotfiles copy — the symlink always points at the canonical. 3 launcher bats added (incl. symlink-invocation resolution). Verified live: =install-ai --help= runs from PATH. +** DONE [#C] coverage-summary.el documented as a local-only helper :chore:quick:solo: +CLOSED: [2026-07-18 Sat] +:PROPERTIES: +:CREATED: [2026-06-22 Mon] +:LAST_REVIEWED: 2026-07-13 +:END: +The elisp bundle installs =coverage-summary.el= into =.claude/scripts/=, gitignored in code projects, so CI can't run =make coverage-summary= against it. Decision (Craig, 2026-06-28): keep it in =.claude/scripts/= and document it as a local-only helper — don't ship it to a tracked =scripts/= dir, don't expect CI to run it. Remaining work (docs only, no move): state the local-only status in the script's header comment and wherever =make coverage-summary= is described, so the gitignored install reads as intentional rather than a gap. Note: emacs-wttrin rewrote its copy's header to claim a tracked =scripts/= home, which now contradicts this decision and should be reverted on their side. Surfaced 2026-06-21 during the coverage-summary autoloads bugfix (commit fb86736). + +Resolved: documented the local-only status in the =coverage-summary.el= commentary header and in =elisp-testing.md='s "Measuring it" section — the gitignored install now reads as intentional, not a coverage gap. Sent emacs-wttrin a handoff to revert its contradicting header claim. ** DONE [#B] todo-cleanup.el dated-seal archiving :feature:solo: CLOSED: [2026-07-18 Sat] Redefine =--archive-done= aging from a 7-day roll-into-one-file model to a @@ -1405,7 +1422,6 @@ Changes to =.ai/scripts/todo-cleanup.el= (canonical in TDD, canonical-then-mirror per the sync-check invariant. Home's planning-line strip proposal (filed alongside) also touches todo-cleanup.el =--convert-subtasks= — the two can be built as one batch. - ** DONE [#B] Strip stale planning lines on dated completion + lint backstop :feature:solo: CLOSED: [2026-07-18 Sat] Two linked fixes so a closed sub-task can't keep polluting the org agenda. Origin: @@ -1432,7 +1448,6 @@ but nothing strips the planning line, and an interactive org close only stamps Build notes: the checker's regex must key on "no TODO keyword" so it never flags a live TODO that legitimately carries a SCHEDULED. TDD, canonical-then-mirror. Batches with the dated-seal task above (both touch todo-cleanup.el). - ** DONE [#B] Enforce the task-boundary inbox check via a hook :feature: CLOSED: [2026-07-19 Sun] Resolved with the soft-nudge design (94e54f6). New =hooks/inbox-boundary-check.sh= Stop hook blocks the yield once + injects the pending count when =inbox-status -q= exits 1, steps aside on the harness re-entry (=stop_hook_active=) so a mid-task pause never wedges, self-skips on no-inbox/no-inbox-status/clean. Wired ahead of =ai-wrap-teardown= in =.claude/settings.json= (which the live =~/.claude/settings.json= symlinks to) + the snippet; glob-installed by =make install-hooks=. 6 bats (pending/clean/re-entry/no-inbox/absent-status/project-name). protocols.org Inbox Monitoring Cadence now notes the enforcement. Live-verified on ratio (clean inbox no-ops, pending fixture blocks); velox synced + hook linked. The UserPromptSubmit visibility complement stayed unbuilt (optional in the design) — file separately if wanted. @@ -1500,7 +1515,6 @@ No hook can perfectly tell "a unit of work finished" from "the agent paused for other reason" — the harness exposes only "the turn is ending," not "a task is ending." The design leans on those two being usually the same in Craig's workflow. That's the tradeoff hard-block vs soft-nudge is really about. - ** DONE [#B] "Colloquialisms and Expansions" + "the list" before-close-queue convention :feature: CLOSED: [2026-07-19 Sun] Resolved (approved in the speedrun). New =* Colloquialisms and Expansions= section in =protocols.org= documents both shorthands: "put X on the list" → append to a session-scoped Before-Close Queue (=* Before-Close Queue= heading in the session anchor, resets on archive, todo.org for must-outlive items); "tell <project> <msg>" → =inbox-send=. =wrap-it-up.org= Step 1 gained a "Work the Before-Close Queue (before the Summary)" sub-step so queued work rides the wrap commit, unfinished items surfaced in the valediction. Design calls: reference in protocols.org not per-project notes.org (synced = shared norm); queue in the session anchor as home did; wrap step at the front of Step 1, not a new half-step (keeps the "Steps 1-5" framing). 4 documentation-integrity bats (=before-close-queue.bats=). Canonical + mirror synced. The UserPromptSubmit-style variant wasn't in scope. @@ -1534,25 +1548,3 @@ section vs a new shipped reference file); where the queue itself lives (home use insertion point (before the teardown/valediction, alongside the roam-inbox sub-step). Then it's a synced-file change (canonical-then-mirror) + a test that the wrap step drains the queue. - -* Rulesets Resolved -** CANCELLED [#C] ntfy phone channel as general two-way agent-comms :feature:spec: -CLOSED: [2026-07-13 Mon] -:PROPERTIES: -:CREATED: [2026-06-20 Sat] -:LAST_REVIEWED: 2026-06-24 -:END: -Killed at the 2026-07-13 task review: home retired and tore down the ntfy channel on 2026-07-04, so this proposal's transport no longer exists. Its living successors are the Signal pager ([#B] task above — one identity on velox, runbook pending) and agent-page (shipped 2026-07-13), which cover the send half; two-way (read-replies) rides the Signal runbook. -Proposal from the home project (2026-06-17): promote the self-hosted ntfy-over-Tailscale phone channel it built and verified on ratio into a general two-way agent-comms tool rulesets owns. Full proposal: [[file:docs/design/2026-06-17-ntfy-agent-comms-proposal.org]] (as-built runbook stays in the home project at =working/phone-notifications/spec.org=). What rulesets would decide: canonicalize =phone-notify= (send) plus a new =phone-recv= (check-since) as synced bin scripts; the per-machine config/secret convention (token in =~/.config/phone-notify/config= chmod 600 today, vs GPG-encrypted in dotfiles); a reference =ntfy-inbound-handler= plus systemd user-unit for event-driven delivery (Tier A subscriber routes inbound to inbox/notify, Tier B inbound spawns an agent session, Tier C notify a live session — harness research); approval-button workflows for the commits.md gates when Craig is away from the desk (tap-to-approve, the high-value concrete use); and the relationship to the retired cross-agent-comms scripts (ntfy may be the transport they lacked). Worked via =spec-create=. Blocks the triage-intake phone-push task below. -** DONE [#B] Org-table helpers corrupt example blocks :bug:solo: -CLOSED: [2026-07-14 Tue] -:PROPERTIES: -:CREATED: [2026-07-11 Sat] -:LAST_REVIEWED: 2026-07-13 -:END: -Fixed in 951b6fc, test-first. Both defects landed as filed (block-type-aware scanning in both helpers; lint-org CLI report-only by default, writes behind --fix), plus the true corruption path found during the work: wrap-org-table's load-time CLI dispatch fired on lint-org's require and reformatted lint-org's file arguments. Entry-script guard added. The named regression test (example block byte-identical) is in the suite. -=wrap-org-table.el= and =lint-org.el= both scan for =/^\s*|/= lines and rewrite them as org tables without skipping =#+begin_example=/=src=/=quote= regions, so ASCII art using pipe characters gets mangled into bordered tables. Reproduced 2026-07-09 in the work project against an architecture doc with a pipe/=v= flow diagram; a plain indented block became a table with =|---|= rules between every line. Two separable defects: (1) table detection is line-based — both helpers should use =org-element-at-point= / =org-in-block-p= to skip example/src/quote/verse blocks; (2) =lint-org.el= mutates its input on disk with no confirmation — passing five files reformatted all five (one by 1949 lines). A linter must report, not write; put the reformat behind an explicit =--fix= flag. - -Grading (severity × frequency, per todo-format.md): Critical severity (silent org data loss; recoverable here only because the content was git-staged) × rare-edge-case frequency (fires only when a mixed table+example file is passed to the helper) = P2 = [#B]. - -Regression test: run =wrap-org-table.el= against a file containing a =#+begin_example= block whose lines start with =|= and assert the block is byte-identical afterward. Source: work handoff 2026-07-09 (=inbox/2026-07-09-1341-from-work-bug-data-loss-wrap-org-table-el-and.org=). |
