From aee7793ddf1802c1574c2d23bf5acd823e7eba1e Mon Sep 17 00:00:00 2001 From: Craig Jennings Date: Sun, 31 May 2026 14:02:58 -0500 Subject: chore(ai): archive session record + sweep resolved tasks Move the completed solo-batch, rename-tool, and coverage-fan-out tasks into Resolved, and file the lint-org judgment items for the next daily-prep. --- ...4-01-solo-batch-coverage-fanout-rename-tool.org | 63 ++++ inbox/lint-followups.org | 6 + todo.org | 347 ++++++++++----------- 3 files changed, 238 insertions(+), 178 deletions(-) create mode 100644 .ai/sessions/2026-05-31-14-01-solo-batch-coverage-fanout-rename-tool.org create mode 100644 inbox/lint-followups.org diff --git a/.ai/sessions/2026-05-31-14-01-solo-batch-coverage-fanout-rename-tool.org b/.ai/sessions/2026-05-31-14-01-solo-batch-coverage-fanout-rename-tool.org new file mode 100644 index 0000000..01598f1 --- /dev/null +++ b/.ai/sessions/2026-05-31-14-01-solo-batch-coverage-fanout-rename-tool.org @@ -0,0 +1,63 @@ +#+TITLE: Session — solo-task batch, rename tool, coverage-summary fan-out +#+DATE: 2026-05-31 + +* Summary + +** Active Goal + +Started as one spec-review solo task and grew into a full no-approvals solo-task batch, then two larger tooling builds Craig directed interactively: a generic =.ai/= artifact-rename tool (dogfooded by renaming the drill-deck family to flashcard), and the coverage-summary fan-out across all four language bundles. + +** Decisions + +- Solo-task tagging (0989698): seven tasks tagged =:solo:=. A1 — leave the category-3 deepsat rule copies alone (no cross-repo dependency on private rulesets). B2 — hold the google-docs token-rotation helper (1050) until a real rotation lets write+verify happen together; not tagged solo. C2 — restructure both startup.org and triage-intake.org into the four-lane structure. +- No-approvals mode for the seven solo tasks: interaction gates off, review-code + voice + tests + session-log stay on. +- Rename tooling: build a script (not just a workflow doc), make it a general artifact renamer (handles scripts too), build it first and dogfood it on the flashcard rename. Renamed the whole family (workflow + four scripts + tests) for consistency, not just the workflow. +- Coverage fan-out: Elisp-first pilot, then Python/Go/TS. Go shipped as a coverage-only slice (no rule file yet). Each script written in the bundle's native language; the kernel is missing-file-as-0% + file-weighted project number; don't reimplement the per-file table the native reporter already prints. + +** Data Collected / Findings + +- Dogfooding the rename tool caught a real bug: it rewrote only the literal hyphen stem and missed the underscore module-name variant (drill_deck_stats in importlib). Fixed + tested. A SIGPIPE from piping the script to =head= mid-run left references half-rewritten once; the end-of-run integrity+sync checks caught the drift. Lesson: don't pipe it to a truncating reader. +- Modern =go test ./...= lists every module package in the profile at 0% even when untested, so Go's missing-file list is usually empty for in-module code — the detection earns its keep on build-tagged files and dirs outside =./...=. +- coverage.py and nyc aren't installed in this env: Python and TS scripts proven against faithful fixtures + CLI, not a live run. Go and Elisp were dogfooded against real reports. + +** Files Modified + +- =spec-review.org= — Phase 6 implementation-task enumeration (5641182). +- =scripts/workflow-integrity.py= + bats — workflow integrity checker (58434f4); later accepts "Summary" orientation heading (3640664). +- =.aiignore= + recursive-read convention (0f0905f); language rule-dup audit, left project-local (976d41c, a072f7c). +- =daily-prep.org= — triage delegated to the triage-intake engine (5438c31). +- =startup.org= + =triage-intake.org= — four-lane restructure, content-preservation-guarded (3640664). +- =languages/{elisp,python,go,typescript}/= — coverage-summary scripts + tests + Makefile fragments + gitignore; =make test= discovery for ERT/pytest/go test/node --test (b46619c, af478a4, 47ca509, ee903e4). +- =scripts/rename-ai-artifact.sh= + bats + =rename-artifact.org= workflow; flashcard family rename (ddf48dc). + +** Next Steps + +- Build out the real Go bundle (=go.md= / =go-testing.md= + =CLAUDE.md=) so the coverage slice becomes sync-maintainable (sync fingerprints on a rule file, which the slice lacks). +- First adopters of the Python and TS coverage scripts should sanity-check against a live =coverage json= / nyc run. +- Held: google-docs token-rotation helper (1050) — do it when a rotation is imminent. + +* Session Log + +** 2026-05-31 10:34 CDT — startup + +Fresh session, clean boot. Prior session wrapped cleanly (no session-context.org at start). Both repos current. The .ai/ sync dogfooded the new skip-when-dirty guard (rulesets clean → synced) and the AI_AGENT_ID session-context-path helper (unset → singleton). Inbox empty, no cross-agent messages, no stale tasks, no reminders/pending decisions, language bundle clean. + +** 2026-05-31 ~10:39 CDT — solo task: spec-review Phase 6 implementation-task enumeration + +Craig asked for remaining :solo: tasks; one was open ([#C] :feature:solo:, from a pearl handoff). Did it: added a Phase 6 step to =spec-review.org= that lifts a spec's =Implementation phases= section into a drop-in =todo.org= block (one =[#B]= TODO per phase + a test-surface entry mirroring =Acceptance criteria=); a spec lacking phase decomposition raises that as a finding instead of inventing phases. Added Exit Criterion 6 and a review-history entry. Mirror-synced, sync-check clean, full suite 409/1skip green. Task marked DONE. Committed 5641182, pushed. + +** 2026-05-31 ~10:50 CDT — solo-task review + tagging + +Craig: re-review every open task for true solo-ness. Walked all 18 bodies. Tagged seven =:solo:= (0989698) with each decision recorded in its task body (A1/B2/C2 above). Cadence check: inbox 0 pending. + +** 2026-05-31 ~10:55 CDT — no-approvals batch: the seven solo tasks + +No-approvals ON, scoped to the seven tasks. Items, in order, all committed + pushed: workflow-integrity checker (58434f4); .aiignore + recursive-read convention (0f0905f, after surfacing that the named walking scripts don't do whole-tree walks — Craig chose ship-file-skip-script-wiring); language rule-dup audit left project-local (976d41c); category-3 deepsat copies left alone (a072f7c); daily-prep→triage-intake delegation (5438c31); four-lane restructure of startup.org + triage-intake.org with a content-preservation guard (3640664); Elisp coverage-summary pilot (b46619c). Full suite green throughout. + +** 2026-05-31 ~13:00 CDT — rename tooling + flashcard rename + +Craig asked whether the flashcard workflow should be renamed, then to build a rename tool so the oversight (assuming renames are costly; missing scattered references) doesn't recur. Built =scripts/rename-ai-artifact.sh= (TDD, 9 bats): moves an artifact in both canonical + mirror trees, rewrites references on a token boundary plus the underscore module-name variant, skips =sessions/= history, runs workflow-integrity + sync-check. Added =rename-artifact.org= + INDEX entry. Dogfooded it on the whole drill-deck family → flashcard (workflow + flashcard-stats/sync/to-anki/diff-ids + tests). The dogfooding caught the underscore-variant bug and a SIGPIPE partial-rewrite (verify step caught the drift); both noted. Committed ddf48dc, pushed. + +** 2026-05-31 ~13:40 CDT — coverage-summary fan-out: Python, Go, TypeScript + +Fanned the Elisp pilot out to the other three bundles, each TDD, native-language parser, same kernel. Python (af478a4): coverage.py JSON, 12 pytest, new =languages/*/tests/test_*.py= discovery, added the bundle's missing gitignore-add.txt. Go (47ca509): cover.out parser in Go, black-box test in its own module, dogfooded against a live profile, coverage-only slice (no rule file → not sync-fingerprintable, documented). TypeScript (ee903e4): Istanbul json-summary parser in JS, node --test discovery, added gitignore-add.txt. Fan-out complete across all four bundles. Follow-up filed for the Go bundle buildout; task marked DONE. diff --git a/inbox/lint-followups.org b/inbox/lint-followups.org new file mode 100644 index 0000000..b581f80 --- /dev/null +++ b/inbox/lint-followups.org @@ -0,0 +1,6 @@ + +* 2026-05-31 lint-org follow-ups — todo.org +** TODO line 2418 — obsolete-properties-drawer — Incorrect contents for PROPERTIES drawer +** TODO line 2335 — obsolete-properties-drawer — Incorrect contents for PROPERTIES drawer +** TODO line 2321 — obsolete-properties-drawer — Incorrect contents for PROPERTIES drawer +** TODO line 2304 — obsolete-properties-drawer — Incorrect contents for PROPERTIES drawer diff --git a/todo.org b/todo.org index 9594a87..968aaaf 100644 --- a/todo.org +++ b/todo.org @@ -1074,110 +1074,6 @@ The flow tonight worked but took a handful of manual steps. One script collapses Decision (Craig, 2026-05-31): *hold until a token rotation is imminent.* The OAuth re-grant is a browser step that can't be triggered without revoking a live token, so the script can't be verified in isolation. Not marked =:solo:= — when a token actually needs rotating, write and verify in one pass (solo at that point). -** DONE [#C] Decide on category-3 rule copies in the deepsat tree :chore:quick:solo: -CLOSED: [2026-05-31 Sun] -Diffed 2026-05-31. Both copies (coding-rulesets vendored + orchestration_dashboard_mvp) are byte-identical to each other and stale against canonical: =testing.md= 221 lines behind with 5 lines unique to the copies (older wording or a small team tweak), =verification.md= 40 behind with nothing unique. Same older vendored version in both spots. Left untouched per the A1 decision — team-owned, and canonicalizing would create a cross-repo dependency on the private rulesets (the orchestration_dashboard_mvp pair is team-visible from Vrezh's PR thread). No files modified. -:PROPERTIES: -:LAST_REVIEWED: 2026-05-28 -:END: - -While symlinking personal-project =.claude/rules/= mirrors to the rulesets canonical on 2026-05-07, two locations didn't fit the "personal mirror → symlink" pattern and were left untouched pending judgment: - -- =~/projects/work/deepsat/code/coding-rulesets/claude-rules/{testing,verification}.md= — looks like a vendored team-shared copy. -- =~/projects/work/deepsat/code/orchestration_dashboard_mvp/.claude/rules/{testing,verification}.md= — could be project-specific overrides. - -For each: read the file, diff against the rulesets canonical, decide whether it's an intentional diverge (leave alone), stale (sync content), or should canonicalize (replace with symlink and accept the cross-repo dependency). The orchestration_dashboard_mvp pair is the project where Vrezh's PR review surfaced this whole thread, so any decision there has team-visibility implications. - -Decision (Craig, 2026-05-31): *leave team-tree copies alone.* Personal rulesets does not reach into team repos — canonicalizing would create a cross-repo dependency on the private rulesets, and the orchestration_dashboard_mvp copy is team-visible. This makes the task solo: diff each copy against canonical, record whether it's identical / drifted / overridden in the disposition, and close as "left alone (team-owned)" without modifying the team-tree files. - -** DONE [#C] Audit language-specific rule files for cross-project duplication :chore:solo: -CLOSED: [2026-05-31 Sun] -Audited 2026-05-31. Findings: in sync with canonical (=languages//claude/rules/=) — work =python-testing.md=, deepsat =typescript-testing.md=, =.emacs.d= =elisp-testing.md= + =elisp.md=. Drifted — =gloss= and =chime= (byte-identical to each other): =elisp-testing.md= 44 lines behind (canonical added Batch-Mode Reproducibility + Isolating Emacs State; zero lines unique to the copies), =elisp.md= one line behind (canonical expanded the edit-cohesively guidance). No project-specific additions anywhere — every copy is either current or purely stale. - -Disposition: *leave them project-local* (the task's own option). The language-rule copies in code projects are the bundle's deliberate copy-and-sync model, not the symlink pattern the generic rules (commits/testing/verification/subagents) use in personal doc-projects. =sync-language-bundle.sh= auto-fixes drifted bundle rules on each startup, so gloss/chime self-heal the moment those projects next boot — no canonicalize/symlink needed, and symlinking would fight the bundle model. Did not reach into work/deepsat/gloss/chime/.emacs.d from here (cross-project boundary; team copies left alone per the 2026-05-31 category-3 decision). -:PROPERTIES: -:LAST_REVIEWED: 2026-05-28 -:END: - -The four canonical rules (=commits=, =testing=, =verification=, =subagents=) are now symlinked across the five personal-project mirrors as of 2026-05-07. But several language-specific rule files exist in multiple project mirrors and may be duplicated or drifted: - -- =python-testing.md= in =~/projects/work/.claude/rules/= -- =typescript-testing.md= in =~/projects/work/deepsat/code/.claude/rules/= -- =elisp-testing.md= and =elisp.md= in =~/.emacs.d/=, =~/code/gloss/=, =~/code/chime/= - -The Elisp pair is the most suspicious — three repos using essentially the same rules. Audit: diff these across the projects, check for drift, then decide whether to canonicalize them under =~/code/rulesets/claude-rules/languages//= and symlink, or leave them as project-local. - -** DONE [#C] Refactor =daily-prep.org= to delegate to =triage-intake.org= for the triage section :chore:solo: -CLOSED: [2026-05-31 Sun] -Collapsed Phase 3's inline source scans (sub-steps 3b email / 3c mark-read / 3d Slack / 3e Linear / 3f PRs / 3g dedup, ~280 lines) into four: 3b runs the triage-intake engine, 3c surfaces today's reactive items as Day's Priorities thin links, 3d re-sorts by urgency, 3e writes the audit footer from the engine's coverage. Source coverage carries via the engine's Phase 0 two-dir glob (general + .ai/project-workflows/ plugins), so the work account's Gmail/Slack/Linear/GHE plugins still get scanned. Adapted the downstream refs (Prep Doc Structure rule, Heads-up FYI source, Recommended Approach Pattern reframed as engine-applied), removed the orphaned Linear-digest note, added a Living Document entry. Verified: workflow-integrity clean (no dangling script refs), sync-check clean, full suite green. daily-prep.org went 825 → 576 lines. -:PROPERTIES: -:LAST_REVIEWED: 2026-05-28 -:END: - -=daily-prep.org= still does its own inline triage (Gmail × 3 accounts, Slack, Linear, GHE PRs, calendars) as part of the full prep flow. =triage-intake.org= is now a source-agnostic engine that loads =triage-intake..org= plugins (refactored 2026-05-26), so daily-prep could call the engine and consume its synthesis instead of duplicating the source-scan logic. That DRYs up a large workflow and keeps both flows in sync when sources change — a source change now lives in one plugin that both flows pick up. - -Scope: -- Identify the sections in =daily-prep.org= that do the inline triage (the email / Slack / Linear / PR / calendar fan-out, plus the "Sources checked: ..." footer at the top of each generated prep doc). -- Replace those sections with "run the =triage-intake.org= engine" and adapt the downstream sections (Heads-up, Day's Priorities, Carry-forwards) to read the engine's synthesis output rather than the inline scan results. -- Verify the generated prep doc still has the same shape (Heads-up + Day's Priorities + Carry-forwards + Sources checked). -- Reconcile source coverage: daily-prep's inline triage scans work accounts (3 Gmail, Slack, Linear, GHE PRs) that are project-specific plugins under =.ai/project-workflows/=, not general plugins. The delegation must ensure the engine loads those project plugins (Phase 0 globs both dirs) so nothing daily-prep currently scans drops out. - -Origin: came up while authoring =triage-intake.org= on 2026-05-11; body refreshed after the engine/plugin refactor on 2026-05-26. - -** DONE [#C] Templatize =make coverage-summary= into the language bundles (Elisp pilot) :feature:solo: -CLOSED: [2026-05-31 Sun] -:PROPERTIES: -:LAST_REVIEWED: 2026-05-28 -:END: - -Done 2026-05-31 (Elisp pilot, the scoped milestone): ported the kernel into the elisp bundle as a self-contained =languages/elisp/claude/scripts/coverage-summary.el= (no coverage-core dependency), proven end-to-end against the real dotemacs SimpleCov report (93 tracked, 27 untested modules surfaced, project number 66.4%). The missing-file-as-0% + unit-weighted number is the kernel. Delivery: the script ships under =.claude/scripts/= (gitignored, auto-fixed on drift by =sync-language-bundle.sh=); =languages/elisp/coverage-makefile.txt= holds the project-owned Makefile fragment, seeded at project root by =install-lang.sh= and dropped into =.ai/inbox/= by sync when that convention exists. Tests: 12 ERT (=languages/elisp/tests/=, wired into =make test=), 5 new sync bats, 2 new install-lang bats. The fan-out to Python/Go/TS is the follow-up below. - -Borrow dotemacs's =make coverage-summary= into the language bundles. After =make coverage= writes a coverage file, =coverage-summary= prints per-unit covered/total with percentages, a unit-weighted project number, and a list of source files present on disk but missing from the coverage report. - -*The kernel — the only part worth building.* Weight the project number by file/module rather than by line, and count a source file absent from the report as 0% instead of omitting it. A module no test imports just doesn't appear in coverage.py or nyc output, so it silently fails to drag the number down. That missing-file detection is the value; everything else (per-file table, total) the built-in reporters already print, so don't reimplement those. - -*Scope Elisp-first.* Port the proven dotemacs version into the elisp bundle, prove the pattern end-to-end, then fan out. Don't open all four bundles at once. - -*Delivery (settled 2026-05-25).* Two rulesets-owned pieces per language: -- The summary *script* ships in the bundle under =.claude/= (inside the now-gitignored tooling footprint), copied in on install and auto-fixed on drift by =sync-language-bundle.sh=, never committed by the project. -- One *text file per language* holding the Makefile fragment (the =coverage-summary= target plus its =coverage= prerequisite) and a block recommending how to set up coverage for that language. The bundle never edits the project's own Makefile. - - *New project:* install copies that file in for the project to own. - - *Existing project:* sync drops the fragment into the project's =inbox/= rather than touching its Makefile — the project adopts it deliberately. - -*Prerequisite caveat.* The summary presumes a coverage harness exists (undercover, coverage.py, nyc, =go cover=). Several bundles may have no =make coverage= yet, so for those this task implies adding the harness first — or the per-language file documents it as a prereq. - -Per-language parser (the script is ~40 lines over each tool's output): -- Elisp: undercover SimpleCov JSON (=.coverage/simplecov.json=) — dotemacs/auto-dim scripts already parse this. -- Go: =go test -coverprofile=cover.out=; parse =cover.out= (simple text), or lean on =go tool cover -func=. -- Python: =coverage json= per-file JSON, or lean on =coverage report=. -- TypeScript/JS: nyc/Istanbul =coverage-final.json= / json-summary. - -Reference (dotemacs): =scripts/coverage-summary.el=, =modules/coverage-core.el=, and the =coverage= / =coverage-summary= Makefile targets. - -Origin: handoff from the .emacs.d session, 2026-05-25. - -** DONE [#C] Fan out coverage-summary across all language bundles :feature: -CLOSED: [2026-05-31 Sun] -:PROPERTIES: -:CREATED: [2026-05-31 Sun] -:END: - -Done 2026-05-31: coverage-summary now ships in all four bundles. Elisp pilot, then Python, Go, and TypeScript. Each parses its tool's report (SimpleCov / coverage.py JSON / Go cover.out / Istanbul json-summary), counts on-disk source files absent from the report as 0%, and file-weights the project number. The plumbing proved generic: =install-lang.sh= seeds the project-owned =coverage-makefile.txt= and ships the script into the gitignored =.claude/scripts/=; =make test= discovers ERT (=test-*.el=), pytest (=test_*.py=), =go test= (=*_test.go=), and =node --test= (=*.test.js=) under =languages/*/tests/=, each guarded on its toolchain. TypeScript and Go scripts were dogfooded (Go against a live profile, TS against the CLI); Python and TS weren't run against a live coverage tool (coverage.py / nyc not installed) — proven against faithful fixtures matching each tool's stable schema. - -Remaining follow-ups (not blockers): -- Go is a coverage-only slice — =languages/go/= has no rule file, so =sync-language-bundle.sh= can't fingerprint it and won't sync-maintain the script. Build out the real Go bundle (=go.md= / =go-testing.md= + =CLAUDE.md=) to close that. -- First real adopters of the Python and TS scripts should sanity-check against a live =coverage json= / nyc =coverage-summary.json= run. - -Original notes retained below for the next person. - -The Elisp pilot proved the pattern; Python and Go followed. The plumbing is generic: =install-lang.sh= seeds the fragment, and =make test= now discovers ERT (=test-*.el=), pytest (=test_*.py=), and =go test= (=*_test.go=) under =languages/*/tests/=. TypeScript is the last one. - -- TypeScript/JS: nyc/Istanbul =coverage-final.json= / =coverage-summary.json=. Same kernel: file-weighted project number, on-disk =*.ts=/=*.js= absent from the report counted as 0%. nyc prints its own table, so the script focuses on the missing-file list and the number. Needs a vitest/jest (or =node --test=) discovery path in =make test=, mirroring the go-test block. - -Notes for the next person, from the Python + Go runs: -- Python: parses coverage.py's =files[path].summary.{covered_lines,num_statements}= (stable since coverage 5.x), resolves report paths against the report's parent dir. Proven against a synthetic report, not a live =coverage json= run (coverage.py wasn't installed). Sanity-check against a real one. -- Go: =languages/go/= is a coverage-only slice with no rule file, so =sync-language-bundle.sh= can't fingerprint it (detection keys on a bundle's own =.claude/rules/*.md=). The script is delivered by =make install-lang LANG=go= but is not sync-maintained until the Go bundle gets a real rule file + =CLAUDE.md=. Building out that bundle is the natural companion task. Also: modern =go test ./...= already lists every module package in the profile at 0%, so the missing-file list is usually empty for in-module code; it earns its keep on build-tagged files and dirs outside =./...=. - ** TODO [#B] Cross-project pattern catalog :spec:thinking: :PROPERTIES: :LAST_REVIEWED: 2026-05-28 @@ -1293,80 +1189,6 @@ The voice skill earns its place when Craig sees the rewrite and recognizes it as Likely improves =/voice personal= output quality on PR bodies, commit messages, and email drafts. Compound interest over the long run. -** DONE [#C] Enumerate implementation tasks in =spec-review.org= Phase 6 :feature:solo: -CLOSED: [2026-05-31 Sun] -:PROPERTIES: -:CREATED: [2026-05-28 Thu] -:LAST_REVIEWED: 2026-05-28 -:END: -Added a Phase 6 step that lifts the spec's =Implementation phases= into a drop-in =todo.org= block (one =[#B]= per phase + a test-surface entry mirroring =Acceptance criteria=); a spec lacking phase decomposition raises that as a finding instead. Added Exit Criterion 6 and a review-history entry. Pure workflow-doc change. - -From pearl handoff 2026-05-28. =spec-review.org= Phase 6 currently says "log deferred work to =todo.org=: v1 implementation = [#B] ... vNext/someday = [#D]." That covers deferred and v1 in passing but doesn't lift the spec's =Implementation phases= section into a drop-in =todo.org= block. - -Proposed addition to Phase 6: a structured step that reads the spec's =Implementation phases= section and produces a =[#B] TODO= entry per phase (subject line, tags, one-line body, pointer back to spec), plus a final entry for the test surface (unit / integration / e2e / manual-verify mirroring the spec's =Acceptance criteria= when present). Emit under a new section "Implementation tasks (drop-in for todo.org)" in the review file. Format follows =todo-format.md= (terse heading, body holds context, tags on heading). - -Three wins: handoff is one paste not a re-read; forces specs to be implementable in pieces (a spec without a phase decomposition fails this step, surfacing the shape problem); closes the loop on =Acceptance criteria= as manual-verify entries. - -If the spec lacks an =Implementation phases= section, the step is the prompt to ask the author to add one before =Ready=. - -** DONE [#C] Add =.aiignore= for agent inventory exclusions :chore:solo: -CLOSED: [2026-05-31 Sun] -Shipped a gitignore-syntax =.aiignore= at the rulesets root (deps, build output, language caches, editor cruft, token artifacts, lockfiles-as-agent-read-skip) and documented the convention + defaults + lockfile policy in protocols.org ("Recursive Reads"). Per Craig's scope call (2026-05-31): did NOT wire audit.sh / diff-lang.sh / sync-language-bundle.sh — they do targeted finds over .ai/.claude/bundle dirs, never naive whole-tree walks, so honoring .aiignore there would be dead code. Script-side honoring belongs in a future catalog/inventory tool if one ships; the real consumer today is agent recursive reads (the protocols guidance). -:PROPERTIES: -:CREATED: [2026-05-28 Thu] -:LAST_REVIEWED: 2026-05-28 -:END: - -From the codex enhancement backlog (item #8). Filesystem scans by agents and helper scripts pick up =node_modules=, =__pycache__=, =.pytest_cache=, lockfiles, generated OAuth artifacts, and test caches, even when those are gitignored. Token waste during exploration and skewed project summaries. - -Scope: add a shared =.aiignore= file (or =rulesets-ignore.json= if a more structured format helps) listing default exclusions. Teach the scripts that walk the project (=audit.sh=, =diff-lang.sh=, =sync-language-bundle.sh=, future =catalog= work if any) to honor it. Document in =protocols.org= so agents know to consult it before naive recursive reads. - -Keep the lockfile policy explicit: ignored when a local skill dependency cache, tracked when reproducibility matters. - -** DONE [#C] Workflow test harness — drift + integrity tests :feature:solo: -CLOSED: [2026-05-31 Sun] -:PROPERTIES: -:CREATED: [2026-05-28 Thu] -:LAST_REVIEWED: 2026-05-28 -:END: - -From the codex enhancement backlog (item #10). Startup's drift check catches index-vs-directory mismatches but not deeper integrity: a workflow that references a script that's been renamed, a plugin whose parent engine has been deleted, a required section missing from a newly-added workflow. - -Scope: add =scripts/tests/workflow-integrity.bats= (or pytest equivalent) verifying: - -- Every =.org= file in =.ai/workflows/= is either indexed in =INDEX.org= or classifiable as a source plugin under an indexed engine. -- Every indexed workflow file actually exists. -- Every =file:= or shell-command reference inside a workflow to a script under =.ai/scripts/= or =scripts/= resolves to an existing file. -- Every source plugin maps to a parent workflow that exists and is indexed. -- Required sections (Overview, When to Use, the workflow's main phases) are present in each workflow. -- Workflow trigger phrases are unique enough to route — no two workflows claim the same exact trigger. - -Wire into =make test=. Run on the canonical =claude-templates/.ai/workflows/= as the source of truth. - -** DONE [#C] Token-tier pilot on largest workflows :feature:solo: -CLOSED: [2026-05-31 Sun] -:PROPERTIES: -:CREATED: [2026-05-28 Thu] -:LAST_REVIEWED: 2026-05-28 -:END: - -Done 2026-05-31: restructured both =startup.org= and =triage-intake.org= into the four-lane structure (Summary / Execution / Reference / History), preserving every existing instruction. triage-intake's reorder ran through a content-preservation guard (the multiset of content lines is unchanged; only heading depth and lane grouping moved). workflow-integrity, sync-check, and the full test suite pass. - -From the codex enhancement backlog (item #5), scope-limited to a pilot rather than a universal template change. - -Apply a standardized section structure to the largest workflow files first — =startup.org= and =triage-intake.org= are the prime candidates. Sections: - -- *Summary* / *Quick Contract* — one-screen purpose and outputs. -- *Execution* — the steps an agent must follow. -- *Reference* — examples, edge cases, rationale, old decisions. -- *History* / *Design Notes* — durable context not needed every run. - -Decision (Craig, 2026-05-31): *approved the four-lane structure (Summary/Execution/Reference/History) and the scope — restructure both =startup.org= and =triage-intake.org= now.* Makes the task solo: apply the lanes to both, preserving every existing instruction (reorganize, don't rewrite), verify the workflows still read coherently and the drift/integrity checks pass. - -Teach startup/routing to read =Summary= only at routing time, then =Execution= only for the selected workflow. Other sections become opt-in. - -After the pilot, evaluate: did the savings show up in real session token use? Did the structure constrain the workflow expressiveness too much? If yes to savings and no to constraint, expand to the next-largest workflows. If not, document why and stop. Don't templatize universally — shorter workflows don't need tiering. - * Rulesets Resolved ** DONE [#C] Fix =cj-scan= false positives on cj fences nested inside other =#+begin_*= blocks :bug: CLOSED: [2026-05-15 Fri] @@ -2476,3 +2298,172 @@ Touches: =.ai/protocols.org= (rename rule + recovery anchor), =.ai/workflows/sta Verification: simulate two agents sharing a project (separate AI_AGENT_ID values) and confirm session-context writes land in distinct files without interleaving. Parent: see [[Generic agent runtime support — Codex spec v0]] above for the larger arc this is sliced from. +** DONE [#C] Decide on category-3 rule copies in the deepsat tree :chore:quick:solo: +CLOSED: [2026-05-31 Sun] +Diffed 2026-05-31. Both copies (coding-rulesets vendored + orchestration_dashboard_mvp) are byte-identical to each other and stale against canonical: =testing.md= 221 lines behind with 5 lines unique to the copies (older wording or a small team tweak), =verification.md= 40 behind with nothing unique. Same older vendored version in both spots. Left untouched per the A1 decision — team-owned, and canonicalizing would create a cross-repo dependency on the private rulesets (the orchestration_dashboard_mvp pair is team-visible from Vrezh's PR thread). No files modified. +:PROPERTIES: +:LAST_REVIEWED: 2026-05-28 +:END: + +While symlinking personal-project =.claude/rules/= mirrors to the rulesets canonical on 2026-05-07, two locations didn't fit the "personal mirror → symlink" pattern and were left untouched pending judgment: + +- =~/projects/work/deepsat/code/coding-rulesets/claude-rules/{testing,verification}.md= — looks like a vendored team-shared copy. +- =~/projects/work/deepsat/code/orchestration_dashboard_mvp/.claude/rules/{testing,verification}.md= — could be project-specific overrides. + +For each: read the file, diff against the rulesets canonical, decide whether it's an intentional diverge (leave alone), stale (sync content), or should canonicalize (replace with symlink and accept the cross-repo dependency). The orchestration_dashboard_mvp pair is the project where Vrezh's PR review surfaced this whole thread, so any decision there has team-visibility implications. + +Decision (Craig, 2026-05-31): *leave team-tree copies alone.* Personal rulesets does not reach into team repos — canonicalizing would create a cross-repo dependency on the private rulesets, and the orchestration_dashboard_mvp copy is team-visible. This makes the task solo: diff each copy against canonical, record whether it's identical / drifted / overridden in the disposition, and close as "left alone (team-owned)" without modifying the team-tree files. +** DONE [#C] Audit language-specific rule files for cross-project duplication :chore:solo: +CLOSED: [2026-05-31 Sun] +Audited 2026-05-31. Findings: in sync with canonical (=languages//claude/rules/=) — work =python-testing.md=, deepsat =typescript-testing.md=, =.emacs.d= =elisp-testing.md= + =elisp.md=. Drifted — =gloss= and =chime= (byte-identical to each other): =elisp-testing.md= 44 lines behind (canonical added Batch-Mode Reproducibility + Isolating Emacs State; zero lines unique to the copies), =elisp.md= one line behind (canonical expanded the edit-cohesively guidance). No project-specific additions anywhere — every copy is either current or purely stale. + +Disposition: *leave them project-local* (the task's own option). The language-rule copies in code projects are the bundle's deliberate copy-and-sync model, not the symlink pattern the generic rules (commits/testing/verification/subagents) use in personal doc-projects. =sync-language-bundle.sh= auto-fixes drifted bundle rules on each startup, so gloss/chime self-heal the moment those projects next boot — no canonicalize/symlink needed, and symlinking would fight the bundle model. Did not reach into work/deepsat/gloss/chime/.emacs.d from here (cross-project boundary; team copies left alone per the 2026-05-31 category-3 decision). +:PROPERTIES: +:LAST_REVIEWED: 2026-05-28 +:END: + +The four canonical rules (=commits=, =testing=, =verification=, =subagents=) are now symlinked across the five personal-project mirrors as of 2026-05-07. But several language-specific rule files exist in multiple project mirrors and may be duplicated or drifted: + +- =python-testing.md= in =~/projects/work/.claude/rules/= +- =typescript-testing.md= in =~/projects/work/deepsat/code/.claude/rules/= +- =elisp-testing.md= and =elisp.md= in =~/.emacs.d/=, =~/code/gloss/=, =~/code/chime/= + +The Elisp pair is the most suspicious — three repos using essentially the same rules. Audit: diff these across the projects, check for drift, then decide whether to canonicalize them under =~/code/rulesets/claude-rules/languages//= and symlink, or leave them as project-local. +** DONE [#C] Refactor =daily-prep.org= to delegate to =triage-intake.org= for the triage section :chore:solo: +CLOSED: [2026-05-31 Sun] +Collapsed Phase 3's inline source scans (sub-steps 3b email / 3c mark-read / 3d Slack / 3e Linear / 3f PRs / 3g dedup, ~280 lines) into four: 3b runs the triage-intake engine, 3c surfaces today's reactive items as Day's Priorities thin links, 3d re-sorts by urgency, 3e writes the audit footer from the engine's coverage. Source coverage carries via the engine's Phase 0 two-dir glob (general + .ai/project-workflows/ plugins), so the work account's Gmail/Slack/Linear/GHE plugins still get scanned. Adapted the downstream refs (Prep Doc Structure rule, Heads-up FYI source, Recommended Approach Pattern reframed as engine-applied), removed the orphaned Linear-digest note, added a Living Document entry. Verified: workflow-integrity clean (no dangling script refs), sync-check clean, full suite green. daily-prep.org went 825 → 576 lines. +:PROPERTIES: +:LAST_REVIEWED: 2026-05-28 +:END: + +=daily-prep.org= still does its own inline triage (Gmail × 3 accounts, Slack, Linear, GHE PRs, calendars) as part of the full prep flow. =triage-intake.org= is now a source-agnostic engine that loads =triage-intake..org= plugins (refactored 2026-05-26), so daily-prep could call the engine and consume its synthesis instead of duplicating the source-scan logic. That DRYs up a large workflow and keeps both flows in sync when sources change — a source change now lives in one plugin that both flows pick up. + +Scope: +- Identify the sections in =daily-prep.org= that do the inline triage (the email / Slack / Linear / PR / calendar fan-out, plus the "Sources checked: ..." footer at the top of each generated prep doc). +- Replace those sections with "run the =triage-intake.org= engine" and adapt the downstream sections (Heads-up, Day's Priorities, Carry-forwards) to read the engine's synthesis output rather than the inline scan results. +- Verify the generated prep doc still has the same shape (Heads-up + Day's Priorities + Carry-forwards + Sources checked). +- Reconcile source coverage: daily-prep's inline triage scans work accounts (3 Gmail, Slack, Linear, GHE PRs) that are project-specific plugins under =.ai/project-workflows/=, not general plugins. The delegation must ensure the engine loads those project plugins (Phase 0 globs both dirs) so nothing daily-prep currently scans drops out. + +Origin: came up while authoring =triage-intake.org= on 2026-05-11; body refreshed after the engine/plugin refactor on 2026-05-26. +** DONE [#C] Templatize =make coverage-summary= into the language bundles (Elisp pilot) :feature:solo: +CLOSED: [2026-05-31 Sun] +:PROPERTIES: +:LAST_REVIEWED: 2026-05-28 +:END: + +Done 2026-05-31 (Elisp pilot, the scoped milestone): ported the kernel into the elisp bundle as a self-contained =languages/elisp/claude/scripts/coverage-summary.el= (no coverage-core dependency), proven end-to-end against the real dotemacs SimpleCov report (93 tracked, 27 untested modules surfaced, project number 66.4%). The missing-file-as-0% + unit-weighted number is the kernel. Delivery: the script ships under =.claude/scripts/= (gitignored, auto-fixed on drift by =sync-language-bundle.sh=); =languages/elisp/coverage-makefile.txt= holds the project-owned Makefile fragment, seeded at project root by =install-lang.sh= and dropped into =.ai/inbox/= by sync when that convention exists. Tests: 12 ERT (=languages/elisp/tests/=, wired into =make test=), 5 new sync bats, 2 new install-lang bats. The fan-out to Python/Go/TS is the follow-up below. + +Borrow dotemacs's =make coverage-summary= into the language bundles. After =make coverage= writes a coverage file, =coverage-summary= prints per-unit covered/total with percentages, a unit-weighted project number, and a list of source files present on disk but missing from the coverage report. + +*The kernel — the only part worth building.* Weight the project number by file/module rather than by line, and count a source file absent from the report as 0% instead of omitting it. A module no test imports just doesn't appear in coverage.py or nyc output, so it silently fails to drag the number down. That missing-file detection is the value; everything else (per-file table, total) the built-in reporters already print, so don't reimplement those. + +*Scope Elisp-first.* Port the proven dotemacs version into the elisp bundle, prove the pattern end-to-end, then fan out. Don't open all four bundles at once. + +*Delivery (settled 2026-05-25).* Two rulesets-owned pieces per language: +- The summary *script* ships in the bundle under =.claude/= (inside the now-gitignored tooling footprint), copied in on install and auto-fixed on drift by =sync-language-bundle.sh=, never committed by the project. +- One *text file per language* holding the Makefile fragment (the =coverage-summary= target plus its =coverage= prerequisite) and a block recommending how to set up coverage for that language. The bundle never edits the project's own Makefile. + - *New project:* install copies that file in for the project to own. + - *Existing project:* sync drops the fragment into the project's =inbox/= rather than touching its Makefile — the project adopts it deliberately. + +*Prerequisite caveat.* The summary presumes a coverage harness exists (undercover, coverage.py, nyc, =go cover=). Several bundles may have no =make coverage= yet, so for those this task implies adding the harness first — or the per-language file documents it as a prereq. + +Per-language parser (the script is ~40 lines over each tool's output): +- Elisp: undercover SimpleCov JSON (=.coverage/simplecov.json=) — dotemacs/auto-dim scripts already parse this. +- Go: =go test -coverprofile=cover.out=; parse =cover.out= (simple text), or lean on =go tool cover -func=. +- Python: =coverage json= per-file JSON, or lean on =coverage report=. +- TypeScript/JS: nyc/Istanbul =coverage-final.json= / json-summary. + +Reference (dotemacs): =scripts/coverage-summary.el=, =modules/coverage-core.el=, and the =coverage= / =coverage-summary= Makefile targets. + +Origin: handoff from the .emacs.d session, 2026-05-25. +** DONE [#C] Fan out coverage-summary across all language bundles :feature: +CLOSED: [2026-05-31 Sun] +:PROPERTIES: +:CREATED: [2026-05-31 Sun] +:END: + +Done 2026-05-31: coverage-summary now ships in all four bundles. Elisp pilot, then Python, Go, and TypeScript. Each parses its tool's report (SimpleCov / coverage.py JSON / Go cover.out / Istanbul json-summary), counts on-disk source files absent from the report as 0%, and file-weights the project number. The plumbing proved generic: =install-lang.sh= seeds the project-owned =coverage-makefile.txt= and ships the script into the gitignored =.claude/scripts/=; =make test= discovers ERT (=test-*.el=), pytest (=test_*.py=), =go test= (=*_test.go=), and =node --test= (=*.test.js=) under =languages/*/tests/=, each guarded on its toolchain. TypeScript and Go scripts were dogfooded (Go against a live profile, TS against the CLI); Python and TS weren't run against a live coverage tool (coverage.py / nyc not installed) — proven against faithful fixtures matching each tool's stable schema. + +Remaining follow-ups (not blockers): +- Go is a coverage-only slice — =languages/go/= has no rule file, so =sync-language-bundle.sh= can't fingerprint it and won't sync-maintain the script. Build out the real Go bundle (=go.md= / =go-testing.md= + =CLAUDE.md=) to close that. +- First real adopters of the Python and TS scripts should sanity-check against a live =coverage json= / nyc =coverage-summary.json= run. + +Original notes retained below for the next person. + +The Elisp pilot proved the pattern; Python and Go followed. The plumbing is generic: =install-lang.sh= seeds the fragment, and =make test= now discovers ERT (=test-*.el=), pytest (=test_*.py=), and =go test= (=*_test.go=) under =languages/*/tests/=. TypeScript is the last one. + +- TypeScript/JS: nyc/Istanbul =coverage-final.json= / =coverage-summary.json=. Same kernel: file-weighted project number, on-disk =*.ts=/=*.js= absent from the report counted as 0%. nyc prints its own table, so the script focuses on the missing-file list and the number. Needs a vitest/jest (or =node --test=) discovery path in =make test=, mirroring the go-test block. + +Notes for the next person, from the Python + Go runs: +- Python: parses coverage.py's =files[path].summary.{covered_lines,num_statements}= (stable since coverage 5.x), resolves report paths against the report's parent dir. Proven against a synthetic report, not a live =coverage json= run (coverage.py wasn't installed). Sanity-check against a real one. +- Go: =languages/go/= is a coverage-only slice with no rule file, so =sync-language-bundle.sh= can't fingerprint it (detection keys on a bundle's own =.claude/rules/*.md=). The script is delivered by =make install-lang LANG=go= but is not sync-maintained until the Go bundle gets a real rule file + =CLAUDE.md=. Building out that bundle is the natural companion task. Also: modern =go test ./...= already lists every module package in the profile at 0%, so the missing-file list is usually empty for in-module code; it earns its keep on build-tagged files and dirs outside =./...=. +** DONE [#C] Enumerate implementation tasks in =spec-review.org= Phase 6 :feature:solo: +CLOSED: [2026-05-31 Sun] +:PROPERTIES: +:CREATED: [2026-05-28 Thu] +:LAST_REVIEWED: 2026-05-28 +:END: +Added a Phase 6 step that lifts the spec's =Implementation phases= into a drop-in =todo.org= block (one =[#B]= per phase + a test-surface entry mirroring =Acceptance criteria=); a spec lacking phase decomposition raises that as a finding instead. Added Exit Criterion 6 and a review-history entry. Pure workflow-doc change. + +From pearl handoff 2026-05-28. =spec-review.org= Phase 6 currently says "log deferred work to =todo.org=: v1 implementation = [#B] ... vNext/someday = [#D]." That covers deferred and v1 in passing but doesn't lift the spec's =Implementation phases= section into a drop-in =todo.org= block. + +Proposed addition to Phase 6: a structured step that reads the spec's =Implementation phases= section and produces a =[#B] TODO= entry per phase (subject line, tags, one-line body, pointer back to spec), plus a final entry for the test surface (unit / integration / e2e / manual-verify mirroring the spec's =Acceptance criteria= when present). Emit under a new section "Implementation tasks (drop-in for todo.org)" in the review file. Format follows =todo-format.md= (terse heading, body holds context, tags on heading). + +Three wins: handoff is one paste not a re-read; forces specs to be implementable in pieces (a spec without a phase decomposition fails this step, surfacing the shape problem); closes the loop on =Acceptance criteria= as manual-verify entries. + +If the spec lacks an =Implementation phases= section, the step is the prompt to ask the author to add one before =Ready=. +** DONE [#C] Add =.aiignore= for agent inventory exclusions :chore:solo: +CLOSED: [2026-05-31 Sun] +Shipped a gitignore-syntax =.aiignore= at the rulesets root (deps, build output, language caches, editor cruft, token artifacts, lockfiles-as-agent-read-skip) and documented the convention + defaults + lockfile policy in protocols.org ("Recursive Reads"). Per Craig's scope call (2026-05-31): did NOT wire audit.sh / diff-lang.sh / sync-language-bundle.sh — they do targeted finds over .ai/.claude/bundle dirs, never naive whole-tree walks, so honoring .aiignore there would be dead code. Script-side honoring belongs in a future catalog/inventory tool if one ships; the real consumer today is agent recursive reads (the protocols guidance). +:PROPERTIES: +:CREATED: [2026-05-28 Thu] +:LAST_REVIEWED: 2026-05-28 +:END: + +From the codex enhancement backlog (item #8). Filesystem scans by agents and helper scripts pick up =node_modules=, =__pycache__=, =.pytest_cache=, lockfiles, generated OAuth artifacts, and test caches, even when those are gitignored. Token waste during exploration and skewed project summaries. + +Scope: add a shared =.aiignore= file (or =rulesets-ignore.json= if a more structured format helps) listing default exclusions. Teach the scripts that walk the project (=audit.sh=, =diff-lang.sh=, =sync-language-bundle.sh=, future =catalog= work if any) to honor it. Document in =protocols.org= so agents know to consult it before naive recursive reads. + +Keep the lockfile policy explicit: ignored when a local skill dependency cache, tracked when reproducibility matters. +** DONE [#C] Workflow test harness — drift + integrity tests :feature:solo: +CLOSED: [2026-05-31 Sun] +:PROPERTIES: +:CREATED: [2026-05-28 Thu] +:LAST_REVIEWED: 2026-05-28 +:END: + +From the codex enhancement backlog (item #10). Startup's drift check catches index-vs-directory mismatches but not deeper integrity: a workflow that references a script that's been renamed, a plugin whose parent engine has been deleted, a required section missing from a newly-added workflow. + +Scope: add =scripts/tests/workflow-integrity.bats= (or pytest equivalent) verifying: + +- Every =.org= file in =.ai/workflows/= is either indexed in =INDEX.org= or classifiable as a source plugin under an indexed engine. +- Every indexed workflow file actually exists. +- Every =file:= or shell-command reference inside a workflow to a script under =.ai/scripts/= or =scripts/= resolves to an existing file. +- Every source plugin maps to a parent workflow that exists and is indexed. +- Required sections (Overview, When to Use, the workflow's main phases) are present in each workflow. +- Workflow trigger phrases are unique enough to route — no two workflows claim the same exact trigger. + +Wire into =make test=. Run on the canonical =claude-templates/.ai/workflows/= as the source of truth. +** DONE [#C] Token-tier pilot on largest workflows :feature:solo: +CLOSED: [2026-05-31 Sun] +:PROPERTIES: +:CREATED: [2026-05-28 Thu] +:LAST_REVIEWED: 2026-05-28 +:END: + +Done 2026-05-31: restructured both =startup.org= and =triage-intake.org= into the four-lane structure (Summary / Execution / Reference / History), preserving every existing instruction. triage-intake's reorder ran through a content-preservation guard (the multiset of content lines is unchanged; only heading depth and lane grouping moved). workflow-integrity, sync-check, and the full test suite pass. + +From the codex enhancement backlog (item #5), scope-limited to a pilot rather than a universal template change. + +Apply a standardized section structure to the largest workflow files first — =startup.org= and =triage-intake.org= are the prime candidates. Sections: + +- *Summary* / *Quick Contract* — one-screen purpose and outputs. +- *Execution* — the steps an agent must follow. +- *Reference* — examples, edge cases, rationale, old decisions. +- *History* / *Design Notes* — durable context not needed every run. + +Decision (Craig, 2026-05-31): *approved the four-lane structure (Summary/Execution/Reference/History) and the scope — restructure both =startup.org= and =triage-intake.org= now.* Makes the task solo: apply the lanes to both, preserving every existing instruction (reorganize, don't rewrite), verify the workflows still read coherently and the drift/integrity checks pass. + +Teach startup/routing to read =Summary= only at routing time, then =Execution= only for the selected workflow. Other sections become opt-in. + +After the pilot, evaluate: did the savings show up in real session token use? Did the structure constrain the workflow expressiveness too much? If yes to savings and no to constraint, expand to the next-largest workflows. If not, document why and stop. Don't templatize universally — shorter workflows don't need tiering. -- cgit v1.2.3