aboutsummaryrefslogtreecommitdiff
path: root/working
diff options
context:
space:
mode:
Diffstat (limited to 'working')
-rw-r--r--working/context-engineering-rightsizing/metrics.org269
-rw-r--r--working/context-engineering-rightsizing/proposals.org350
-rw-r--r--working/context-engineering-rightsizing/rollout.org371
-rw-r--r--working/lint-org-example-block/report-from-home.org21
-rw-r--r--working/question-capture-pattern/proposal-from-archsetup.org15
-rw-r--r--working/triage-account-guard/companion-note-from-home.org5
-rw-r--r--working/triage-account-guard/proposed.diff11
-rw-r--r--working/triage-account-guard/triage-intake.personal-gmail.org.proposed74
-rw-r--r--working/voice-term-density/SKILL.md.proposed511
-rw-r--r--working/voice-term-density/profile.diff36
-rw-r--r--working/voice-term-density/proposal-from-work.org42
-rw-r--r--working/voice-term-density/skill.diff58
-rw-r--r--working/voice-term-density/voice-profile.org.proposed1643
-rw-r--r--working/working-dir-orphan-check/proposal-from-work.org12
-rw-r--r--working/working-dir-orphan-check/proposed.diff24
-rw-r--r--working/working-dir-orphan-check/wrap-it-up.org.proposed651
16 files changed, 4093 insertions, 0 deletions
diff --git a/working/context-engineering-rightsizing/metrics.org b/working/context-engineering-rightsizing/metrics.org
new file mode 100644
index 0000000..e7ff189
--- /dev/null
+++ b/working/context-engineering-rightsizing/metrics.org
@@ -0,0 +1,269 @@
+#+TITLE: Context-Engineering Rightsizing — Metrics and Stop Conditions
+#+AUTHOR: Craig Jennings
+#+DATE: 2026-07-27
+
+* Who is holding the instrument
+
+Most of what follows would be measured by me, about changes to my own
+instructions, in a direction I have an obvious interest in. Self-reported
+compliance is unreliable, and it is unreliable in a predictable direction: I
+will under-report misses I didn't notice, because not noticing is the failure.
+
+That is the argument for weighting mechanical detectors over my judgment
+wherever both exist. =lint-org= does not have a stake. Neither does a token
+count, a =git diff=, or you seeing a window on the wrong workspace. Where a
+claim can only be assessed by my self-report, it is marked below as judgment
+rather than measurement, and it should be discounted accordingly.
+
+* Part 1 — Which claims are testable
+
+Each post makes separable claims. Some can be tested here cheaply, some need an
+eval harness we don't have, and inventing a metric for the second group would be
+worse than admitting it.
+
+** Testable now, with existing instrumentation
+
+*** T1 — Report-everything beats pre-filtering (Opus 5 guide)
+
+*Claim.* A review told to be conservative reports less; reporting everything and
+filtering separately surfaces more real issues.
+
+*Test.* A true A/B, runnable today with no waiting. Take three past diffs with
+known outcomes. Run =/review-code= under current rules and under the
+report-all-then-filter version. Compare findings that survive verification.
+
+*Metric.* Real findings per pass, and false-positive rate. The claim holds if
+report-all finds more real issues without the false-positive rate rising
+enough to drown them.
+
+*Why this one first.* It is the only claim in the three posts we can settle in
+an afternoon instead of a week.
+
+*** T2 — Progressive disclosure preserves behavior (context-engineering post)
+
+*Claim.* Moving guidance out of always-loaded context into on-demand loading
+doesn't degrade adherence.
+
+*ANSWERED 2026-07-27 for the deterministic half.* =/context= in a live work
+session lists 17 generic rules under Memory files, with the three path-scoped
+ones absent. Path-scoping is a glob match rather than a model judgment, so it
+either fires or doesn't, and it fires. That half needs no trial and no miss-rate
+metric.
+
+*Still open for the semantic half.* Rules whose condition can't be a glob
+("when a commit is in play") route to skills, where triggering *is* a model
+judgment. Everything in Part 2 applies there and only there.
+
+*A caution the answer doesn't cover.* Path-scoping fires when Claude *reads* a
+matching file. A session that writes an org file without reading one first
+never triggers =todo-format.md=. Edit requires a prior read, so edits to
+existing files are safe; creating a new org file from scratch is the gap. Worth
+watching rather than blocking on.
+
+*** T3a — The token baseline was wrong by 45% [SETTLED]
+
+Word counts converted at a guessed ~1.3 tokens per word. The live number is
+2.28. =commits.md= is 12,800 tokens, not the ~7,000 estimated, and
+=claude-rules/= was ~57,800 tokens per session before today rather than the
+~33,000 implied.
+
+The lesson is narrower than "measure better." I had a real measurement
+available the whole time — =/context= reports per-file token counts — and used
+an estimate instead because the estimate was easier to compute from inside the
+repo. Reach for the instrument that reports the actual quantity.
+
+*** T3 — Deliverables run long without explicit calibration (Opus 5 guide)
+
+*Claim.* Files written to disk are longer than the task needs.
+
+*Test.* Measure what already exists. Word counts of the last twenty session
+archives, the specs in =docs/specs/=, and =todo.org= task bodies. Then add a
+length-calibration instruction and measure the next ten.
+
+*Metric.* Median words per artifact, before and after. Paired with a judgment
+call on whether anything useful was lost, which is the part I can't measure.
+
+*Baseline worth taking now,* since it costs one command and the before-number
+disappears the moment we change anything.
+
+*** T4 — Lower effort holds quality [WITHDRAWN 2026-07-27]
+
+Dropped with P4. The goal is output quality first, and this claim trades
+quality for cost, so testing it would answer a question we've decided not to
+act on either way.
+
+*** T4 (original text, retained for the record)
+
+*Claim.* =low= and =medium= produce strong quality at a fraction of the tokens.
+
+*Test.* Sentry fires hourly and does the same passes each time. Run a week at
+default, a week at =medium=, on the same repo state where possible.
+
+*Metric.* Tokens per fire, and findings per fire. The claim holds if findings
+per fire holds within noise while token cost drops materially.
+
+*Confound to respect.* Sentry's input changes night to night, so findings-per-
+fire is noisy. Two weeks is probably the floor for a readable signal, and the
+result will still be suggestive rather than conclusive.
+
+*** T5 — Duplicate and conflicting instructions cost something (both posts)
+
+*Claim.* Overlapping guidance across surfaces makes the model work harder to
+reconcile.
+
+*Test.* Partially measurable. The duplication itself is countable — Phase 5's
+three axes. Whether removing it improves anything is not measurable without
+evals.
+
+*Metric.* Count of rules stated on more than one surface, driven to zero. That
+measures the cleanup, not the benefit. Honest framing: we're removing a known
+cost, not demonstrating a gain.
+
+** Not testable here — judgment calls, and they should be labelled as such
+
+*** J1 — Examples constrain the exploration space
+
+The post asserts this and I have no way to test it. Removing the examples from
+=commits.md= and observing "things seem fine" is not evidence. This one gets
+adopted on the post's authority or not at all, and I'd lean toward *not*
+stripping examples that encode your taste, since the same post says skills
+should encode exactly that.
+
+*** J2 — Removing verification instructions loses no quality
+
+The claim underneath C1. Testing it properly means running the same tasks with
+and without =verification.md= and comparing error escape rates, which needs a
+task suite we don't have. What we *can* measure is the cost side — tool calls
+and tokens spent on verification per task — but not what it prevents.
+
+Asymmetric risk: the cost of over-verification is tokens, and the cost of
+under-verification is a false completion claim reaching you. Those are not
+equally bad, which argues for keeping the honesty core regardless of what a
+test would show.
+
+*** J3 — Unknowns-discovery reduces rework
+
+Long-horizon and confounded by everything else. Adopt on judgment.
+
+*** J4 — Rich references beat prose descriptions
+
+=ui-prototyping.md= already assumes it and it has worked. That's one project's
+experience, not a measurement, but it's the evidence we have.
+
+* Part 2 — Pilot go/no-go
+
+** The denominator problem
+
+The obvious metric is a miss rate, and the obvious trap is that a rule nobody
+exercised shows zero misses and reads as a pass. Every result below is
+therefore reported as *misses per exposure*, and a rule with too few exposures
+returns no verdict rather than a passing one.
+
+*Exposure* means a session did work in the rule's domain: edited an org table,
+touched a spec's lifecycle, displayed a keymap, captured a window, ran a UI
+spec.
+
+*Minimum exposures before a rule's result counts: 3.* Below that, extend the
+window or swap the rule for one that gets exercised more.
+
+** Primary metric
+
+Misses per exposure, per rule, where a miss is the guidance not being applied
+when it should have been.
+
+| Result per rule | Verdict |
+|----------------------------+----------------------------------------|
+| 0 misses in 3+ exposures | Pass |
+|----------------------------+----------------------------------------|
+| 1 miss, detector caught it | Pass with note; record the miss |
+|----------------------------+----------------------------------------|
+| 2 or more misses | Turn back that rule |
+|----------------------------+----------------------------------------|
+| Miss reached a commit | Turn back now, don't wait for the week |
+|----------------------------+----------------------------------------|
+| Miss reached a project | Turn back now, and see abandon triggers|
+|----------------------------+----------------------------------------|
+| Under 3 exposures | No verdict; extend or swap the rule |
+|----------------------------+----------------------------------------|
+
+** Secondary metrics
+
+- *Token delta.* Measured directly. Expected around 3,000 words. This is the
+ only guaranteed benefit, so if the primary metric fails, we know exactly what
+ we were buying and can decide it wasn't worth it.
+- *Correction cost.* When a miss happens, how long to fix. A misformatted table
+ is seconds. This is what distinguishes an acceptable miss rate from an
+ unacceptable one, and it is why the threshold tightens in Phase 4.
+- *False-trigger rate.* A skill loading when it isn't needed spends tokens for
+ nothing. Worth watching, not worth blocking on.
+
+** Turn back versus abandon
+
+Two different actions, and conflating them would over-react to a single bad
+rule.
+
+*Turn back a rule* — revert that one file to always-loaded. Triggered by 2+
+misses on that rule, or any miss reaching a commit. The rest of the pilot
+continues. Cost: one revert.
+
+*Abandon the rollout* — stop at Phase 0 and keep the current architecture.
+Triggered by any of:
+
+- Three or more of the six rules turn back.
+- A miss reaches another project through the sync.
+- The pattern of misses shows the skill index isn't the fix, meaning D2 was the
+ wrong lever and there's no obvious next one.
+
+*Proceed to Phase 3* requires: at least four of six rules pass, no miss reached
+a commit, and the token drop landed near expectation.
+
+** Threshold scales with blast radius
+
+The pilot tolerates one caught miss per rule because the worst case is a badly
+formatted table. Phase 4 moves =commits.md=, where the worst case is an
+unattributed commit or a leaked path in a public artifact.
+
+*Phase 4 threshold is zero.* One miss on an attribution, scope, or grading rule
+turns that rule back immediately, with no pass-with-note tier. Stated now so
+it isn't negotiated later under the pressure of wanting the phase to succeed.
+
+* Part 3 — Baselines to capture before anything changes
+
+Cheap now, impossible to reconstruct later:
+
+1. Always-loaded word count per surface. Captured: 32,123 total.
+2. Median word count of the last twenty session archives, the specs, and open
+ task bodies. For T3.
+3. Sentry tokens per fire and findings per fire, from the existing metrics
+ file. For T4.
+4. Findings per pass from the last several =/review-code= runs. For T1.
+
+Item 1 is done. The rest are one session's work and should happen before
+Phase 0 changes the review skill, since that change contaminates item 4.
+
+* Instrument reliability — the day's second lesson
+
+The plan weights mechanical detectors over self-report because they have no
+stake. Two failed on 2026-07-27, both reporting success while doing damage:
+=wrap-org-table.el= reflowed a table into a worse shape and =lint-org= then
+certified it clean, and the wrap-teardown hook consumed a two-hour-old sentinel
+and killed a live work session that had done nothing wrong.
+
+Neither invalidates the preference for mechanical detectors, which is still
+right. Both narrow the claim: a detector has no stake, but it can be
+confidently wrong, and a green check from a guard that never looked at the
+thing is indistinguishable from a green check that did. When a detector clears
+a moved rule, the useful question is whether it actually evaluated it, not just
+whether it reported clean.
+
+* What this can and cannot tell us
+
+It can tell us whether on-demand loading fires reliably here, whether
+report-everything finds more real bugs, whether artifacts shrink usefully, and
+what lower effort costs in findings.
+
+It cannot tell us whether examples constrain, whether removing verification
+instructions is safe, or whether unknowns-discovery reduces rework. Those stay
+judgment calls made on the posts' authority and your read, and they should be
+labelled that way in whatever we write down afterward — so that a future session
+doesn't mistake an adopted opinion for a tested result.
diff --git a/working/context-engineering-rightsizing/proposals.org b/working/context-engineering-rightsizing/proposals.org
new file mode 100644
index 0000000..1300a7b
--- /dev/null
+++ b/working/context-engineering-rightsizing/proposals.org
@@ -0,0 +1,350 @@
+#+TITLE: Context-Engineering Rightsizing — Proposals
+#+AUTHOR: Craig Jennings
+#+DATE: 2026-07-27
+
+* Status
+
+Proposals only. Nothing here is applied. Source: three Anthropic posts Craig
+supplied 2026-07-27 — the Claude 5 context-engineering post (2026-07-24), the
+Opus 5 prompting guide, and the Fable 5 field guide (2026-07-06).
+
+* Goal
+
+Output quality and results first. Token reduction is a real goal and worth
+having, but it is the second one, and where the two conflict quality wins.
+Craig's framing, 2026-07-27: the concern is agents having the freedom to
+produce at their highest capacity, unbound by guardrails that constrain them or
+work against them.
+
+That reordering matters more than it sounds. Anthropic's 80% figure was a
+*finding* — they cut and quality held — not a target. Aimed at directly it
+optimizes the thing we don't care about, and P4 below is the proposal that
+falls to it.
+
+* The measurement (corrected 2026-07-27 from live =/context=)
+
+The original figures in this document were word counts converted at a guessed
+ratio, and they understated by about 45%. A =/context= run in a live work
+session gave the real numbers:
+
+| Surface | Tokens |
+|------------------------------------+--------|
+| =claude-rules/= before this session | 57,800 |
+|------------------------------------+--------|
+| =claude-rules/= now (17 files) | 44,410 |
+|------------------------------------+--------|
+| Path-scoped out (3 files) | 13,390 |
+|------------------------------------+--------|
+
+The real ratio is 2.28 tokens per word, not the ~1.3 assumed. =commits.md=
+alone is 12,800 tokens, not the ~7,000 estimated. Every earlier figure here
+should be read as low.
+
+** Two loading paths, not one
+
+The original framing called 32,123 words "always-loaded" and was wrong to
+lump them. They arrive by different mechanisms:
+
+- *Memory files* — =claude-rules/= (via the =~/.claude/rules/= symlinks),
+ =CLAUDE.md=, project =.claude/rules/=, and auto-memory's =MEMORY.md=. Loaded
+ at session start by the harness. This is the 44,410 above, plus CLAUDE.md and
+ project rules.
+- *Read during startup* — =protocols.org= and the workflow files. These never
+ appear under Memory files in =/context=; the startup workflow reads them, so
+ they land in Messages. Still a real per-session cost, but a different lever:
+ they shrink by editing the workflow, not by scoping a rule.
+
+Conflating the two made =protocols.org= look like it competed with
+=commits.md= for the same fix. It doesn't.
+
+** What the harness says on its own
+
+=/context= ends with its own suggestion: prune =commits.md= (12.8k),
+=testing.md= (6.3k), and =MEMORY.md= (5.5k). That is the Phase 4 target list,
+arrived at independently. Worth treating as corroboration rather than
+coincidence.
+
+* Proposals
+
+Ranked by value. Each carries my confidence and what I think the real risk is.
+
+** P1 — Progressive disclosure for =claude-rules/= [high value, highest risk]
+
+*Change.* Split the twenty rule files into two tiers.
+
+- *Always-loaded core* (target under 3,000 words): the genuine invariants that
+ must fire without being summoned. The no-AI-attribution rule, the
+ cross-project boundary stop, the no-popup-menus and no-reverse-video output
+ constraints, the =date=-before-timestamps rule, and a short index naming
+ which skill covers what.
+- *On-demand tier*: everything procedural, converted to skills whose
+ descriptions trigger them. =commits.md= becomes a publish skill that loads
+ when a commit or PR is in play. =todo-format.md= loads when an org todo file
+ is touched. =testing.md=, =working-files.md=, =docs-lifecycle.md=,
+ =org-tables.md=, =keybinding-display.md= likewise.
+
+*Why.* This is the post's central move, and the token math is the argument.
+
+*The real risk, stated plainly.* A rule that isn't loaded can't fire. Skill
+triggering is probabilistic in a way that always-resident text isn't. The
+failure mode is silent: a session commits without the voice pass because the
+publish skill didn't trigger, and nothing announces the miss. That's the same
+silent-failure shape as the two probe defects fixed this morning.
+
+*Mitigation.* Anything whose violation is expensive and hard to reverse stays
+in the always-loaded core, whatever its length. The split is by *blast radius*,
+not by word count. And the migration goes one file at a time with a live trial,
+not as a single cutover.
+
+*Confidence.* High that the direction is right. Medium on where exactly each
+line falls — that's a judgment call per rule, and worth walking together.
+
+** P2 — Stop pre-filtering review findings [high value, low risk]
+
+*Change.* =review-code/SKILL.md:251= says "Drop Low-confidence issues before
+the final report." Line 434 repeats it. Replace with: report every finding
+carrying an explicit confidence label, then filter in a named second pass.
+
+*Why.* The Opus 5 guide is specific about this: "If your review prompt says
+'only report high-severity issues' or 'be conservative,' the model may follow
+that instruction literally and report less; ask it to report everything and
+filter in a separate pass instead." The guide also reports that on this model
+the extra findings are mostly real rather than false positives, which is the
+premise the drop-rule was written against.
+
+*Confidence.* High. This is the most directly-actionable finding in the three
+posts, and it names the exact pattern the skill implements.
+
+** P3 — Add the unknowns-discovery practices [medium value, low risk]
+
+The field guide describes eight practices. The sweep found these absent:
+=unknown unknowns= framing (0 files), =implementation notes= (0), =quiz= (0).
+Present but thin: =blind spot= (1 file), =interview= (2), =pitch= (1).
+=brainstorm= appears in 5 and =references= is well covered by
+=ui-prototyping.md=, which already runs ahead of the post.
+
+*Change.* Add a blind-spot-pass practice and an interview practice, and an
+implementation-notes convention for long builds (a scratch file logging
+deviations from plan, which then feeds the retrospective). Add the quiz pattern
+to the review or wrap surface.
+
+*Placement matters.* These go in the on-demand tier from P1, never the
+always-loaded core — otherwise this proposal fights the one above it.
+
+*Confidence.* Medium-high on the practices being useful. Lower on the quiz,
+which may not fit how you actually work.
+
+** P4 — Effort calibration [DROPPED 2026-07-27 — trades quality for cost]
+
+*Change.* Sentry, work-the-backlog, and the no-approvals speedrun run many
+passes at default effort. The Opus 5 guide says to use =low= and =medium=
+liberally as the primary cost control wherever quality holds, stepping up only
+for demanding work.
+
+*Why.* Sentry fires hourly. Effort is the lever with the largest cost
+multiple, and most sentry passes are mechanical sweeps.
+
+*Dropped.* Lowering effort buys tokens by spending quality, which is exactly
+backwards under the goal above. Revisit only if a specific pass proves
+genuinely mechanical and a cost problem shows up on its own.
+
+** P5 — Positive framing over prohibition [PROMOTED — now the top quality lever]
+
+*Change.* =commits.md= carries 41 prohibition markers (NEVER / DO NOT /
+MANDATORY / CRITICAL) across 5,561 words. =todo-format.md= 21,
+=testing.md= 19. Rewrite the ones that aren't hard invariants as positive
+descriptions of the wanted behavior.
+
+*Why.* The Opus 5 guide: "Positive examples of the communication style you want
+tend to be more effective than instructions about what not to do."
+
+*Keep as prohibitions:* the AI-attribution rule and anything else where the
+worst case is genuinely unacceptable. Those earn their emphasis.
+
+*Promoted 2026-07-27.* Ranked low when the score was token savings. Under a
+quality-first goal this is the proposal that most directly targets guardrails
+working against good output, which is the stated concern. It still rides along
+with the Phase 4 edits rather than running as its own campaign, because every
+file it touches is a file those phases open anyway.
+
+** P6 — Deduplicate the two always-loaded surfaces [medium value, low risk]
+
+=protocols.org= restates rules that also live in =claude-rules/=: the
+cross-project boundary, the working-files convention, the AI-attribution ban,
+inbox cadence. Both are loaded every session, so each duplicated rule is paid
+for twice, and the two copies can drift apart.
+
+*Change.* One home per rule. =protocols.org= keeps the pointer, the rule file
+keeps the content — or the reverse, but not both.
+
+*Confidence.* High on the duplication being real, medium on which surface
+should own each rule.
+
+* Conflicts — your call, not mine to inherit
+
+Two places where a post contradicts something this system arrived at
+deliberately. I'm flagging rather than adopting.
+
+** C1 — =verification.md= versus the over-verification warning
+
+The Opus 5 guide says: "If your prompt contains explicit verification
+instructions ('include a final verification step for any non-trivial task',
+'use a subagent to verify'), remove them: instructions like these cause
+over-verification on Claude Opus 5, and removing them reduces wasted tokens
+with no loss in quality."
+
+=verification.md= is 1,486 always-loaded words of exactly that shape. But the
+two aren't the same thing, and the distinction decides the answer:
+
+- Its *honesty core* — don't claim tests pass without running them, "unable to
+ verify" is a required outcome, replace beliefs with evidence — is about
+ truthful reporting, not about adding verification steps. The guide doesn't
+ argue against it.
+- Its *process injection* — green baseline before starting, full suite as its
+ own step before every commit — is the shape the guide names.
+
+*My read:* keep the honesty core, shorten it, and let the process injection
+move into the publish skill where it fires only when publishing. *My
+confidence: medium*, and this is the one I'd most want you to overrule if it
+feels wrong. It's also the rule closest to your standing "never guess, always
+check" direction, so the guide's advice and your stated preference genuinely
+pull against each other here.
+
+** C2 — =subagents.md= versus the delegation warning
+
+The guide says "do not use subagents to verify or double-check your own work."
+=subagents.md= has a review-gate cadence and a rule to dispatch a *fix*
+subagent rather than repairing in the orchestrator's context.
+
+*My read:* the fix-subagent rule is about context pollution, not verification,
+so it survives. The review-gate cadence is closer to the flagged pattern and
+wants a look. Most of =subagents.md= already matches the guide's advice — it
+argues against spawning for small work and against letting the agent pick its
+own scope, which is what the guide asks for. *Confidence: medium-high.*
+
+* One thing the posts would change about this document
+
+Both the context-engineering post and the field guide argue that a rich
+reference beats a prose description — an HTML artifact, a test suite, source
+code. This proposal document is prose in org, which is your reading format and
+the right call for a decision doc. Worth noting the tension rather than
+silently ignoring it: for the *next* artifact in this line of work, an HTML
+comparison of the before and after rule tree would likely beat another org
+file.
+
+* Scope proposal for the consistency sweep
+
+The audit behind this document was targeted, not exhaustive — I checked the
+claims the posts made and measured the surface. A real inconsistency sweep over
+20 rule files, 47 workflows, and the skills is its own pass.
+
+Proposed scope, in order:
+
+1. *Contradictions between always-loaded surfaces* — the P6 duplication set,
+ read side by side for drift rather than just counted.
+2. *Stale facts* — assertions about tools, paths, and behavior that were true
+ when written. The spot check found the =agent-page= to =agent-text= rename
+ correctly handled, so this may be in better shape than expected.
+3. *Instructions that contradict each other across files* — the failure the
+ context-engineering post opens with. This is the expensive one and the most
+ valuable.
+
+Sizing: item 1 is an afternoon, item 2 is mechanical, item 3 is the real work.
+
+* From your side of the desk
+
+Everything above treats these files as the agent's context, to be rightsized.
+That was the smaller question. Read as *your prompts* — the map you hand every
+project — the finding is different, and it's the one worth acting on.
+
+** The bottleneck this system was built for has moved
+
+Counting the workflows by what they're for: 41 are execution and hygiene
+(publish, task grading, inbox routing, session archiving, calendar, email,
+sync), 6 are discovery and design (the spec trio, retrospective, code-quality,
+readability-audit). Roughly seven to one.
+
+That ratio was correct when the risk was the model doing things wrong. The
+field guide's claim is that the risk moved: "Claude Fable is the first model
+where I find the quality of the work is bottlenecked by my ability to clarify
+its unknowns." If that's true here too, the system is heavily invested in the
+half of the problem that got easier and thin on the half that didn't.
+
+Not an argument to delete the execution machinery. It's load-bearing, and
+hygiene that runs itself is exactly what you want automated. The argument is
+that *the growth has all been on one side*, and the next increment of quality
+probably comes from the other one.
+
+** The instructions don't practice what they demand
+
+Three concrete cases, all checkable:
+
+- =commits.md= says "Brief. Terse is preferred. A one-sentence body beats a
+ paragraph saying the same thing." It is 5,561 words, the longest file in the
+ set.
+- =interaction.md= bans bold and code spans in chat output because they render
+ as reverse video. The rule files carry 591 bold markers.
+- =testing.md= mandates TDD as "non-negotiable" and follows with a table of
+ eight rationalizations to refuse. That's the repeat-yourself-and-overconstrain
+ shape the context-engineering post retired, applied to a rule the model no
+ longer needs argued into.
+
+This matters beyond tidiness. An instruction whose own form contradicts its
+content is a mixed signal of exactly the kind the post opens with — the
+model spends effort reconciling "be terse" against a source that isn't.
+
+** Over-specification has a cost you're paying, not me
+
+The field guide: "If you are too specific, Claude will follow your instructions
+even when a pivot may be more appropriate. If you are too vague, Claude will
+often make choices and assumptions based on industry best practices that may
+not be a fit."
+
+The workflows are phase-numbered and gate-heavy. For repeatable operations —
+wrap-up, publish, inbox — that precision is right and should stay. For the
+creative surfaces it's a straitjacket: a spec workflow that prescribes its own
+phases forecloses the pivot that a brainstorm was supposed to surface. The
+system doesn't currently distinguish those two classes, and it should. Same
+file format, opposite optimal specificity.
+
+** Which gates are guardrails and which are preference
+
+The approval gates (publish, inbox shared-asset, spec) were written when the
+worst case was an agent shipping something wrong. Some of them you'd want
+regardless, because you want to be in the loop on what goes out under your
+name. Those are preference and should never be cut.
+
+Others are pure guardrail, and the context-engineering post's argument applies:
+"these constraints were once needed to avoid worst case scenarios, we have
+since found we can delete many of them."
+
+I can't tell the two apart from the files — they read identically. Only you
+know which gates you'd keep if the agent were perfectly reliable. That
+separation is the highest-leverage thing you could tell me, and it's not
+something I should guess at.
+
+** One map, many territories
+
+Every project loads the same 32,000 words. The finances project loads the TDD
+mandate and the full publish machinery. =.emacs.d= loads the org-table
+standard. Some of that is right (the universal rules genuinely are universal)
+and some is the map/territory mismatch the field guide names.
+
+The language-bundle mechanism already solves this for =languages/=. Nothing
+equivalent exists for the rules layer.
+
+** What's already right
+
+Worth saying, because the list above is all deficit:
+
+- =ui-prototyping.md= is the field guide's brainstorm-and-prototype practice,
+ written down before the post and in more detail than the post gives it.
+- The spec spine (decisions plus implementation phases) is the guide's
+ implementation-plan pattern.
+- =session-context.org= is the implementation-notes pattern, and it already
+ captures deviations and dead ends.
+- =retrospective.org= exists.
+
+So the practices are partly here. What's missing is that they're framed as
+*process compliance* rather than as *unknowns discovery*, and none of them fire
+at the moment the guide says they pay off — before scope is set.
diff --git a/working/context-engineering-rightsizing/rollout.org b/working/context-engineering-rightsizing/rollout.org
new file mode 100644
index 0000000..d641ce7
--- /dev/null
+++ b/working/context-engineering-rightsizing/rollout.org
@@ -0,0 +1,371 @@
+#+TITLE: Context-Engineering Rightsizing — Rollout Schedule
+#+AUTHOR: Craig Jennings
+#+DATE: 2026-07-27
+
+* Why this is phased rather than done in one pass
+
+The change is a bet that on-demand loading fires as reliably as always-resident
+text. That bet is cheap to test and expensive to assume. Every phase below
+either produces evidence or spends evidence already earned. Nothing
+load-bearing moves before the mechanism has been watched working.
+
+The second reason is blast radius. Everything here rides the template sync into
+every project on its next startup, so a bad phase is not contained to this
+repo. The early phases are chosen so a failure is visible and harmless.
+
+* A finding that changes the plan
+
+The harness system prompt already carries most of what the Opus 5 guide
+recommends adding. Its task-scope block, its correction-narration block, and
+its subagent-delegation cap are present nearly verbatim. The
+context-engineering post's replacement comment guidance ("write code that reads
+like the surrounding code") is present as the post's own new wording.
+
+Two consequences:
+
+1. *Do not "apply the posts" by adding their suggested prompt blocks.* They are
+ already live. Adding them to =claude-rules/= would create exactly the
+ duplicate-and-conflict problem the first post opens with, while making the
+ token count worse.
+2. *There is a third deduplication axis.* The proposals named =protocols.org=
+ against =claude-rules/=. There is also =claude-rules/= against the harness
+ system prompt, and that one is invisible from inside the repo. Any rule that
+ restates harness guidance is pure cost.
+
+This is why the posts' value here is subtractive, not additive.
+
+* Status — 2026-07-27, end of first working session
+
+Phase 0 and the deterministic half of Phase 1 are done and verified in a live
+session. The pilot's central question is answered, which changes what remains.
+
+** Shipped
+
+- =paths:= frontmatter on the three rules that already declared a file-type
+ scope in prose (=todo-format=, =org-tables=, =emacs=), plus a =lint.sh=
+ checker that catches the prose/frontmatter mismatch, plus a heading check
+ taught to skip frontmatter. Commit 0adcb1a.
+- Generic rules no longer ship per project. =install-lang= stopped copying them
+ and =sync-language-bundle= sweeps what earlier installs left, guarded on the
+ global rule existing. Swept 20 files each from work and =.emacs.d=. Commit
+ 7ea1d7b.
+- The live session anchor is gitignored, so rulesets stops reporting
+ sync-blocked for the whole of every session. Same commit.
+
+** Verified in a live work session
+
+=/context= lists 17 generic rules under Memory files. =todo-format.md=,
+=org-tables.md=, and =emacs.md= are absent, and only =python-testing.md= and
+=publishing.md= come from the project's own rules directory.
+
+So *path-scoping works at user level* and *the de-duplication holds*. Both were
+open questions this morning.
+
+** What that changes
+
+Path-scoping is a glob match, not a model judgment. It is deterministic, so the
+silent-miss risk the whole pilot was designed around does not apply to it. That
+splits the remaining work in two:
+
+1. *Path-scopable* — any rule whose scope is a file type or directory. Ships
+ immediately, no trial, no detectors. =docs-lifecycle.md= is the obvious next
+ one (=docs/**=), and parts of =working-files.md= may qualify.
+2. *Semantic* — rules whose condition can't be written as a glob ("any spec
+ with a non-trivial UI", "when a commit is in play"). These still need the
+ skills route, and they are the only place the pilot's detectors and stop
+ conditions apply.
+
+=commits.md= is the case that matters: 12,800 tokens, the single largest item,
+and almost all of it is publish machinery that only applies when a commit is in
+play. That is a task scope rather than a path scope, so it is the skills route
+and the real test of the risky tier.
+
+** Correction carried from the live numbers
+
+Earlier phases in this document quote word counts converted at a guessed ratio
+and understate by about 45%. The real ratio is 2.28 tokens per word. Read the
+targets below as token figures needing that correction, and see proposals.org
+for the corrected table.
+
+** A pattern worth designing around
+
+Two mechanical guards failed in the same day, both mine, both reporting success
+while doing damage: =wrap-org-table.el= reflowed a table into a worse shape and
+=lint-org= then certified it clean, and the wrap-teardown hook consumed a
+two-hour-old sentinel and killed a live work session.
+
+This plan leans on mechanical detectors precisely because they have no stake in
+the outcome. Both incidents say that is necessary but not sufficient — a
+detector can be confidently wrong. Whatever Phase 3 decides, the verification
+step should include "did the guard's own claim get checked," not just "did the
+guard report clean."
+
+* Phase 0 — Free wins [DONE except /doctor]
+
+*Scope.* Three items that interact with nothing.
+
+1. Fix the review-finding pre-filter (P2). =review-code/SKILL.md= lines 251 and
+ 434 tell the reviewer to drop low-confidence findings before reporting.
+ Replace with report-everything-labelled, filter in a named second pass.
+2. Run =/doctor=. The context-engineering post says Anthropic shipped these
+ practices as a command that rightsizes skills and =CLAUDE.md=. Its output is
+ free evidence, and it may disagree with this plan, which is worth knowing
+ before executing it.
+3. Record the harness-overlap finding above where it will be seen at the moment
+ it matters — a note in the rules index, not buried in this document.
+
+*Reasoning.* None of these depend on the pilot's outcome, and item 2 could
+change the plan.
+
+*Decision needed:* none.
+
+*Success criteria.* Review skill reports with confidence labels and a separate
+filter step. =/doctor= output read and reconciled against this schedule.
+
+*Rollback.* Single revert; nothing downstream depends on it.
+
+* Phase 1 — The pilot migration [deterministic half DONE; semantic half pending]
+
+*Scope.* Six rule files move from always-loaded to on-demand skills. Roughly
+3,000 words, about 12% of the rules surface.
+
+| File | Words | How a silent miss would be caught |
+|-----------------------+-------+-------------------------------------------|
+| =org-tables.md= | 464 | =lint-org= checker =org-table-standard= |
+|-----------------------+-------+-------------------------------------------|
+| =docs-lifecycle.md= | 582 | spec status-board grep; =lint-org= checkers |
+|-----------------------+-------+-------------------------------------------|
+| =ui-prototyping.md= | 696 | =spec-review= verifies the process ran |
+|-----------------------+-------+-------------------------------------------|
+| =keybinding-display.md= | 505 | you see the wrong format immediately |
+|-----------------------+-------+-------------------------------------------|
+| =desktop-capture.md= | 458 | a window lands on your active workspace |
+|-----------------------+-------+-------------------------------------------|
+| =patterns.md= | 291 | already only a pointer; nothing to miss |
+|-----------------------+-------+-------------------------------------------|
+
+*Reasoning — the selection rule matters more than the list.* These were not
+picked for being small or cheap. They were picked because *a failure to fire is
+detectable*. Four have a mechanical checker or workflow gate that catches the
+miss; two produce an error you see within seconds. That is what makes the pilot
+an experiment rather than a hope.
+
+=daily-drivers.md= and =emacs.md= were considered and held back. Both are
+low-risk in content, but a miss on either surfaces slowly — as drift on the
+other machine, or as a stale daemon — so neither would tell us anything within
+the trial window.
+
+*Decisions needed.*
+
+- *D1 — Confirm the pilot set.* Six files as listed, or trim further. My
+ recommendation is the six: fewer than that and the trial may not exercise the
+ mechanism enough to learn from.
+- *D2 — Does the always-loaded core carry a skill index?* A one-line-per-skill
+ list naming what exists and when it applies. It costs perhaps 200 words and
+ should materially improve trigger reliability, since the model can see that a
+ rule exists even when its content isn't loaded. My recommendation is yes, and
+ the pilot is the right place to test whether the index is what does the work.
+
+*Success criteria.* Always-loaded surface drops to about 29,000 words. All six
+skills exist with trigger descriptions. Suite green, sync clean, every project
+picks up the change on next startup without drift.
+
+*Rollback.* One revert restores the files to =claude-rules/=. The skills can
+stay in place harmlessly.
+
+* Phase 2 — Live trial (one week of real sessions, no work required)
+
+*Scope.* Use the system normally. Do not compensate for the pilot by mentioning
+the moved rules — that would invalidate the result.
+
+*Reasoning.* This is the phase that buys everything after it. The question is
+narrow and answerable: when work touches one of the six domains, does the skill
+fire without prompting?
+
+*What gets recorded.* Each session that touches a pilot domain notes one line
+in the session log: which domain, whether the skill fired, and whether the
+detector caught anything. At the end of the week that's a short table rather
+than an impression.
+
+*Decision needed:* none during the trial.
+
+*Success criteria.* Defined in advance so the verdict isn't argued after the
+fact:
+
+- *Pass* — no detector fires on a moved rule, or any miss is caught by its
+ detector and corrected in the same session.
+- *Fail* — a miss reaches a commit, or the same rule misses twice.
+- *Ambiguous* — no session touched the domain. That is not a pass; extend the
+ window or move a rule that gets exercised more.
+
+*Rollback.* Revert on a Fail, and the plan stops at Phase 0.
+
+* Phase 3 — Go/no-go and the gate separation (one session)
+
+*Scope.* Read the trial table, decide whether the mechanism is trusted, and
+separate the approval gates.
+
+*Reasoning.* The gate separation is the highest-leverage input in the whole
+plan, and it sits here rather than earlier for one reason: if Phase 2 fails,
+the question is moot, because nothing more moves either way.
+
+*Decision needed.*
+
+- *D3 — Which gates are preference and which are guardrail?* Every approval gate
+ in the system reads identically in the files. Some you would keep even if the
+ agent were perfectly reliable, because you want to see what goes out under
+ your name. Others exist because the worst case used to be worse. The list to
+ walk: the publish approval gate, the inbox shared-asset approval, the
+ spec-review flip, the wrap certification, and the no-approvals mode's carve
+ outs.
+
+ Preference gates are untouchable and stay always-loaded regardless of length.
+ Guardrail gates are candidates for relaxation on the posts' argument. I can
+ prepare the list with my read of each, but the answers are yours.
+
+*Success criteria.* Every gate labelled. The label determines what Phase 4 may
+move.
+
+* Phase 4 — The load-bearing files (two or three sessions)
+
+*Scope.* =commits.md= (5,561), =todo-format.md= (4,494), =testing.md= (2,824),
+=working-files.md= (950), =subagents.md= (1,041). About 15,000 words, the bulk
+of the remaining surface.
+
+The split within each file is by blast radius, not by length. =commits.md= is
+the worked example: the AI-attribution ban and the content-scope rule stay
+always-loaded and get shorter, while the publish flow, the message format, and
+the voice mechanics become the publish skill that loads when a commit is in
+play.
+
+*Reasoning.* This is where the token math actually pays. It runs last because
+it is where a silent miss is expensive: an unattributed commit, a leaked path,
+an ungraded task.
+
+*Decision needed.*
+
+- *D4 — Resolve the =verification.md= conflict (C1).* The Opus 5 guide says
+ explicit verification instructions cause over-verification and should be
+ removed. Your standing direction is never guess, always check. My read is
+ that these are compatible because they address different things: the honesty
+ core (don't claim a green suite you didn't run) stays, and the process
+ injection (green baseline before starting, suite as its own step) moves into
+ the publish skill. But it is your rule and your call, and this decision blocks
+ =commits.md= moving because the two files reference each other.
+
+*Success criteria.* Always-loaded surface under about 8,000 words. Two full
+weeks of sessions with no attribution, scope, or grading miss.
+
+*Rollback.* Per-file, since each moves independently.
+
+* Phase 5 — Deduplication (one session)
+
+*Scope.* Three axes, in increasing order of payoff:
+
+1. =protocols.org= against =claude-rules/= — the cross-project boundary,
+ working-files, AI-attribution, and inbox cadence are each stated twice.
+2. =claude-rules/= against the harness system prompt — the finding at the top
+ of this document. Invisible from inside the repo and therefore never audited.
+3. Within =claude-rules/= — rules that restate each other.
+
+*Decision needed.*
+
+- *D5 — Which surface owns each duplicated rule.* Generally the more specific
+ one should own the content and the more general should carry a pointer, but
+ there are cases where the reverse is right.
+
+*Success criteria.* Each rule stated once. A stated rule for where new rules go,
+so the duplication doesn't regrow.
+
+* Phase 6 — Terseness and positive framing (rides along with Phases 4 and 5)
+
+*Scope.* Rewrite prohibitions that aren't hard invariants as positive
+descriptions. Cut the files that don't practice what they demand: =commits.md=
+arguing terseness at 5,561 words, =testing.md= arguing an eight-row table
+against rationalizations the model no longer needs talked out of, 591 bold
+markers in files that ban bold in output.
+
+*Reasoning.* Not a separate campaign. Every file opened in Phases 4 and 5 gets
+this pass while it's open, because doing it separately means editing everything
+twice.
+
+*Decision needed:* none. This is style, and the voice skill already owns the
+standard.
+
+* Phase 7 — Discovery practices (after the surface is down)
+
+*Scope.* The field guide's missing practices: a blind-spot pass, an interview
+pattern, an implementation-notes convention for long builds, and possibly the
+quiz.
+
+*Reasoning.* Deliberately last, for two reasons. It adds surface, which fights
+every phase before it, so it should land only once there is room. And the
+seven-to-one execution-to-discovery ratio is the finding most likely to change
+how the system actually feels to use, which makes it worth doing carefully
+rather than early.
+
+*Decision needed.*
+
+- *D6 — Which practices you actually want.* I have low confidence on the quiz
+ fitting how you work, and medium-high on the rest.
+
+* Phase 8 — Effort calibration [DROPPED 2026-07-27]
+
+*Scope.* Set effort levels for the unattended loops: sentry's hourly fires,
+work-the-backlog, the no-approvals speedrun.
+
+*Dropped.* Buys tokens by spending quality, which inverts the stated goal.
+D7 is withdrawn with it.
+
+*Decision needed.*
+
+- *D7 — Accepted quality floor for unattended passes.* A sentry sweep that runs
+ cheaper but misses one finding per night may be a good trade or a bad one.
+ That's a preference, not a measurement.
+
+* Ongoing — The consistency sweep
+
+Runs alongside, not as a phase. Each file opened in Phases 4 through 6 gets read
+for contradictions and stale facts while it's open, and findings go to a running
+list rather than being fixed opportunistically. The expensive item — instructions
+that contradict each other across files — is what the first post opens with and
+what this whole exercise is downstream of.
+
+* Decisions, collected
+
+| ID | Decision | Needed by |
+|----+----------------------------------------------+-----------|
+| D1 | Confirm the six-file pilot set | Phase 1 |
+|----+----------------------------------------------+-----------|
+| D2 | Skill index in the always-loaded core? | Phase 1 |
+|----+----------------------------------------------+-----------|
+| D3 | Which gates are preference vs guardrail | Phase 3 |
+|----+----------------------------------------------+-----------|
+| D4 | Resolve the verification.md conflict | Phase 4 |
+|----+----------------------------------------------+-----------|
+| D5 | Which surface owns each duplicated rule | Phase 5 |
+|----+----------------------------------------------+-----------|
+| D6 | Which discovery practices you want | Phase 7 |
+|----+----------------------------------------------+-----------|
+| D7 | Quality floor for unattended passes | Phase 8 |
+|----+----------------------------------------------+-----------|
+
+Only D1 and D2 are needed to start.
+
+* The number this is aiming at
+
+| Stage | Always-loaded words |
+|-------------------+---------------------|
+| Today | 32,123 |
+|-------------------+---------------------|
+| After Phase 1 | 29,100 |
+|-------------------+---------------------|
+| After Phase 4 | under 8,000 |
+|-------------------+---------------------|
+| After Phase 5 | under 6,000 |
+|-------------------+---------------------|
+
+Roughly an 80% reduction, which lands near what Anthropic reported. That
+symmetry is a coincidence worth distrusting rather than aiming for: the target
+is whatever survives the blast-radius test, and if that turns out to be 12,000
+words then 12,000 words is the right answer.
diff --git a/working/lint-org-example-block/report-from-home.org b/working/lint-org-example-block/report-from-home.org
new file mode 100644
index 0000000..0b9f4d3
--- /dev/null
+++ b/working/lint-org-example-block/report-from-home.org
@@ -0,0 +1,21 @@
+#+TITLE: lint-org.el bug: invalid-block false positive on an example
+#+SOURCE: from home
+#+DATE: 2026-07-24 12:48:05 -0500
+
+lint-org.el bug: invalid-block false positive on an example block containing a heading line.
+
+Repro: an org file with
+
+ #+begin_example
+ ** Feature Name or Topic
+ #+end_example
+
+reports BOTH delimiters as judgment findings — 'Possible incomplete block "#+begin_example"' on the begin line and 'Possible incomplete block "#+end_example"' on the end line — even though the block is correctly paired. The trigger is the literal '** ' heading line inside the block body; the checker appears to treat it as a structural break rather than block content, so it loses track of the open block.
+
+Seen in home's .ai/notes.org (the PENDING DECISIONS section documents its own task format inside an example block, which is a legitimate and common shape for a docs file). These are the only 2 findings left in that file after I cleaned up the real defects, so they're pure noise now and they'll recur on any org file that documents org syntax inside an example block.
+
+Suggested fix: while inside a begin_example/begin_src block, skip structural parsing of the body entirely until the matching #+end_ line. Example and src blocks are verbatim by definition, so nothing inside them should be read as a heading, a timestamp, or a block delimiter.
+
+Worth noting the same class of bug would hit a src block containing '#+end_example' or similar as literal text.
+
+Context on what surfaced it: home's notes.org had 17 lint findings that had been dismissed as false positives across several sessions. 15 were real — the file used markdown '**bold**' where org wants single asterisks, so it rendered as literal asterisks and looked heading-shaped to the checker. Fixing the markup cleared those. That left these 2, which are the genuine checker bug. The lesson for the checker's credibility: a persistent block of 'known false positives' hid 15 real defects, because nobody re-examined the pile once it got labeled.
diff --git a/working/question-capture-pattern/proposal-from-archsetup.org b/working/question-capture-pattern/proposal-from-archsetup.org
new file mode 100644
index 0000000..22a978d
--- /dev/null
+++ b/working/question-capture-pattern/proposal-from-archsetup.org
@@ -0,0 +1,15 @@
+#+TITLE: Workflow idea from Craig (2026-07-24, via archsetup roam inb
+#+SOURCE: from archsetup
+#+DATE: 2026-07-24 00:26:22 -0500
+
+Workflow idea from Craig (2026-07-24, via archsetup roam inbox) — worth adopting across projects.
+
+The pattern: Craig drops a QUESTION into the roam inbox as a capture (not a task to build — a thing he wants explained). The agent retrieves it during a sentry / inbox-processing pass, and instead of trying to answer it autonomously, holds it and ANSWERS IT WHEN BACK IN CONVERSATION with Craig. The task closes once the answer is given and Craig has responded.
+
+His words: 'This is a format I'll probably use quite a lot. I'll ask the question, you can retrieve it during sentry, then you can answer it when we're back in conversation.'
+
+Why it's useful: it decouples question-capture (async, whenever it occurs to him) from answer-delivery (synchronous, in a live session where he can follow up). It also keeps the agent from burning autonomous cycles guessing at an answer he'd rather discuss.
+
+Suggested shape for a rule: a roam-inbox item phrased as a question (or tagged so) is NOT auto-answered during unattended processing. The agent surfaces it at the next live conversation, answers, and closes on Craig's acknowledgement. Distinct from a VERIFY (which waits on Craig's INPUT to proceed) — here the agent owes the answer, Craig owes only the acknowledgement.
+
+Concrete instance that spawned this: 'why does the cursor not appear over the desktop when the world-clock wallpaper is on?' — answered live in the archsetup session (the projected face's CSS sets cursor:none; over the bare desktop the pointer is over that full-monitor WebKit page, so it vanishes).
diff --git a/working/triage-account-guard/companion-note-from-home.org b/working/triage-account-guard/companion-note-from-home.org
new file mode 100644
index 0000000..92157ca
--- /dev/null
+++ b/working/triage-account-guard/companion-note-from-home.org
@@ -0,0 +1,5 @@
+#+TITLE: Companion to the triage-intake.personal-gmail.org file just
+#+SOURCE: from home
+#+DATE: 2026-07-23 23:38:56 -0500
+
+Companion to the triage-intake.personal-gmail.org file just sent: added a Verify-account-binding guard under Scan. Why: on 2026-07-23 a home sentry triage fire used mcp__claude_ai_Gmail expecting personal Gmail and instead pulled 201 unread DeepSat WORK messages — that MCP is bound to the work account and its name gives no hint. The plugin already correctly specifies mcp__google-docs-personal; the gap was that nothing made the agent verify the binding before trusting (and then acting on) the results. The guard: confirm a sample result's to: is craigmartinjennings@gmail.com before classifying; if wrong or unavailable, fall back to the local mu mirror (maildir /gmail, sync first) rather than another MCP. Verified account→tool mapping 2026-07-23: google-docs-personal=personal gmail, google-docs-work=deepsat, claude_ai_Gmail=deepsat(work-bound); maildirs gmail/cmail/dmail = craigmartinjennings@gmail.com / c@cjennings.net / craig.jennings@deepsat.com. No engine change needed — the engine is account-agnostic by design; the guard belongs in the plugin. Consider whether cmail (bridge script, account-fixed by construction) needs any analogous note — I judged not.
diff --git a/working/triage-account-guard/proposed.diff b/working/triage-account-guard/proposed.diff
new file mode 100644
index 0000000..0eda2f6
--- /dev/null
+++ b/working/triage-account-guard/proposed.diff
@@ -0,0 +1,11 @@
+--- .ai/workflows/triage-intake.personal-gmail.org 2026-07-16 10:42:14.461682666 -0500
++++ working/triage-account-guard/triage-intake.personal-gmail.org.proposed 2026-07-23 23:38:44.358507825 -0500
+@@ -27,6 +27,8 @@
+
+ ⚠ *Do NOT add =-category:promotions -category:social=.* That filter masked 67 promo+social messages across two runs (2026-05-04, 2026-05-06), both needing a follow-up sweep. Pull the full unfiltered set; the trash-leaning bias in Classify handles promotions and social directly.
+
++⚠ *Verify the account binding before trusting the scan.* =mcp__google-docs-personal= must resolve to =craigmartinjennings@gmail.com=. Several Gmail-capable MCPs are connected and they bind to *different* accounts — =mcp__claude_ai_Gmail= is bound to the DeepSat *work* account, and its name gives no hint of that. A wrong-account scan returns a plausible mailbox that is the wrong person's, and every hygiene action in the close then fires on the wrong inbox (this happened 2026-07-23: a sweep used =claude_ai_Gmail= and pulled 201 unread *DeepSat work* messages instead of personal). Guard, every scan: confirm a sample result's =to:= is =craigmartinjennings@gmail.com= before classifying. If it isn't, or if =google-docs-personal= is unavailable, do NOT reach for another MCP — use the local mu mirror: sync first (=mbsync gmail && mu index=; the index lags), then =mu find 'maildir:/gmail/INBOX AND flag:unread AND date:<anchor>..now'=. The three accounts and their maildirs: =gmail= = craigmartinjennings@gmail.com, =cmail= = c@cjennings.net, =dmail= = craig.jennings@deepsat.com (work — out of scope from a home session, whichever tool reaches it).
++
+ ⚠ *The MCP caps at =maxResults=100= and exposes NO =pageToken= parameter.* The response carries a =nextPageToken=, but the tool can't consume it, so a pile over 100 is silently truncated — the tail below the cap never gets classified, and every later anchored sweep skips it (it predates the new anchor). This is exactly how a 300+ backlog accumulated invisibly by 2026-07-08. Two consequences:
+
+ - *Never treat a 100-row result as complete.* When a scan returns exactly 100, walk the tail in *date slices*: re-query with =before:<oldest-full-day-seen>= (day resolution), repeat until a page returns fewer than 100, dedupe by message id across slices (the day-resolution boundary overlaps).
diff --git a/working/triage-account-guard/triage-intake.personal-gmail.org.proposed b/working/triage-account-guard/triage-intake.personal-gmail.org.proposed
new file mode 100644
index 0000000..d66ed0b
--- /dev/null
+++ b/working/triage-account-guard/triage-intake.personal-gmail.org.proposed
@@ -0,0 +1,74 @@
+#+TITLE: Triage Intake — Personal Gmail Source
+#+AUTHOR: Craig Jennings
+#+DATE: 2026-05-26
+
+# Source plugin for the triage-intake engine. See triage-intake.org for the
+# contract and the Phase A-D orchestration. This file declares ONE source.
+
+* Source: personal-gmail
+:PROPERTIES:
+:ORDER: 20
+:ENABLED: mcp google-docs-personal present
+:ANCHOR: epoch
+:SUBAGENT_OVER: 50
+:END:
+
+** Scan
+
+Personal Gmail unread in the inbox since the anchor:
+
+#+begin_src text
+mcp__google-docs-personal__listMessages q="is:unread in:inbox after:<anchor-epoch>" maxResults=100
+#+end_src
+
+⚠ *Express every anchor cutoff as the literal UNIX epoch* — =after:1784177122= and =before:1784177122= for the same anchor, never the =YYYY/MM/DD= form. This governs *both* anchored queries: the scan above and the backlog-residue probe below. They must meet at the same instant or mail falls between them permanently. Gmail's day-resolution operators fail two different ways: =after:YYYY/MM/DD HH:MM:SS= is not valid syntax at all — Gmail parses the space as a term separator, treats =HH:MM:SS= as a search term that never matches, and returns 0 results, silently masking unread mail — while =before:YYYY/MM/DD= is valid but excludes the named day entirely, so pairing it with a second-resolution scan leaves the whole anchor day covered by neither query. The engine supplies =<anchor-epoch>= because this source declares =ANCHOR: epoch=.
+
+The rule binds the *anchor* windows only. The date-slice walk below deliberately uses =before:<oldest-full-day-seen>= at day resolution — safe there because consecutive slices overlap and get deduped by message id.
+
+⚠ *Do NOT add =-category:promotions -category:social=.* That filter masked 67 promo+social messages across two runs (2026-05-04, 2026-05-06), both needing a follow-up sweep. Pull the full unfiltered set; the trash-leaning bias in Classify handles promotions and social directly.
+
+⚠ *Verify the account binding before trusting the scan.* =mcp__google-docs-personal= must resolve to =craigmartinjennings@gmail.com=. Several Gmail-capable MCPs are connected and they bind to *different* accounts — =mcp__claude_ai_Gmail= is bound to the DeepSat *work* account, and its name gives no hint of that. A wrong-account scan returns a plausible mailbox that is the wrong person's, and every hygiene action in the close then fires on the wrong inbox (this happened 2026-07-23: a sweep used =claude_ai_Gmail= and pulled 201 unread *DeepSat work* messages instead of personal). Guard, every scan: confirm a sample result's =to:= is =craigmartinjennings@gmail.com= before classifying. If it isn't, or if =google-docs-personal= is unavailable, do NOT reach for another MCP — use the local mu mirror: sync first (=mbsync gmail && mu index=; the index lags), then =mu find 'maildir:/gmail/INBOX AND flag:unread AND date:<anchor>..now'=. The three accounts and their maildirs: =gmail= = craigmartinjennings@gmail.com, =cmail= = c@cjennings.net, =dmail= = craig.jennings@deepsat.com (work — out of scope from a home session, whichever tool reaches it).
+
+⚠ *The MCP caps at =maxResults=100= and exposes NO =pageToken= parameter.* The response carries a =nextPageToken=, but the tool can't consume it, so a pile over 100 is silently truncated — the tail below the cap never gets classified, and every later anchored sweep skips it (it predates the new anchor). This is exactly how a 300+ backlog accumulated invisibly by 2026-07-08. Two consequences:
+
+- *Never treat a 100-row result as complete.* When a scan returns exactly 100, walk the tail in *date slices*: re-query with =before:<oldest-full-day-seen>= (day resolution), repeat until a page returns fewer than 100, dedupe by message id across slices (the day-resolution boundary overlaps).
+- *Never report =resultSizeEstimate= as a count.* It's unreliable — observed stuck at "201" across three different queries whose real union exceeded 300.
+
+*** Backlog-residue check (every sweep — cheap, mandatory)
+
+The anchored scan is blind to anything unread from *before* the anchor. After it, run one probe for pre-anchor residue:
+
+#+begin_src text
+mcp__google-docs-personal__listMessages q="is:unread in:inbox before:<anchor-epoch>" maxResults=5
+#+end_src
+
+The cutoff is the epoch, matching the scan's =after:<anchor-epoch>= — see the epoch rule above.
+
+If it returns any messages, surface one loud line in the sweep summary: "Backlog: unread predating the anchor exists (N+ shown; date-slice to inventory)" and offer a backlog sweep. Never fold the residue into a quiet sweep — an anchored "no changes" claim is only true for the window the scan saw. (Added 2026-07-08 after ~300 pre-anchor unread accumulated unseen; the probe returns actual messages, so it works where the estimate lies. Shipped with a day-resolution cutoff that hid the entire anchor day; fixed to epoch 2026-07-16 after a home sweep reported the backlog clear while two July-15 messages sat unread.)
+
+** Classify
+
+Bias: *trash-leaning* — personal Gmail is high noise volume.
+
+- *Noise-trash:* newsletters, Substacks, retail/SaaS marketing, social digests, redundant aggregator digests (Notion/Miro daily), wrong-recipient mail, past-event calendar artifacts.
+- *Noise-keep:* receipts, order confirmations, statements — low value but worth the audit trail.
+- *FYI:* substantive personal mail with no action owed.
+- *Action:* an explicit ask, a reply owed, a time-sensitive personal matter.
+
+** Render
+
+#+begin_example
+**Personal Gmail — N unread.** <one-line classification summary>
+- Action: <items, if any, with thread links>
+- FYI: <items, if any>
+- Noise: N trash candidates, M keep
+#+end_example
+
+Omit the block if zero unread.
+
+** Actions
+
+- trash :: =mcp__google-docs-personal__trashMessage= id=<message-id> (recoverable from Gmail Trash for 30 days)
+- mark-read :: =mcp__google-docs-personal__modifyMessageLabels= id=<message-id> removeLabelIds=["UNREAD"]
+- star+read :: =mcp__google-docs-personal__modifyMessageLabels= id=<message-id> addLabelIds=["STARRED"] removeLabelIds=["UNREAD"]
+- attach-fetch:: =.ai/scripts/gmail-fetch-attachments.py --profile personal --message-id <message-id> --output-dir <PATH>=
diff --git a/working/voice-term-density/SKILL.md.proposed b/working/voice-term-density/SKILL.md.proposed
new file mode 100644
index 0000000..97507ff
--- /dev/null
+++ b/working/voice-term-density/SKILL.md.proposed
@@ -0,0 +1,511 @@
+---
+name: voice
+description: |
+ Multi-pass prose editor with three modes. General mode (default) edits arbitrary writing — research notes, essays, anyone's README prose — by walking 32 patterns: Wikipedia's Signs of AI Writing patterns plus universal good-writing rules (long-word → short-word, active-over-passive, comma splices, cliché flag, jargon-fragment-in-prose rewrite, corporate-speak nominalizations, term-translation density). Prose mode adds Craig's writing-voice patterns for prose he authors or sends — emails, documents, notes — on top of general (em-dash zero-tolerance, no-emphasis-formatting, contractions, semicolons → periods, sentence-split, felt-experience cut, sentence-fragment rewrite, terse-cut, single-sentence cadence, parenthetical asides, declarative-register marker). Personal mode is for publish artifacts only (commits, PR titles + bodies, PR review comments) and adds the artifact-mechanics patterns on top of prose (first-person rewrite, public-artifact scope flag, praise/correction asymmetry, finding stems, comma budget) plus per-artifact terseness budgets. Prose mode also carries one correspondence-only pattern (recipient-priority ordering) that personal mode skips. Total 48 patterns; one editorial review covers all relevant ones for the chosen mode, with an attestation receipt for the high-recurrence set. Replaces the standalone humanizer skill. Use when editing prose. Do NOT use for code, structured data, or plain bullet lists where fragments are valid.
+allowed-tools:
+ - Read
+ - Write
+ - Edit
+ - Grep
+ - Glob
+ - AskUserQuestion
+---
+
+# Voice: Humanizer + Universal + Personal Style Passes
+
+You are a writing editor that walks a numbered pattern list against a piece of text and rewrites each problematic section. The patterns cover three concerns: signs of AI-generated writing (Wikipedia's "Signs of AI writing" guide), universal good-writing rules (Strunk & White, Orwell's "Politics and the English Language", Plain English Campaign, Garner's Modern English Usage), and Craig's personal voice for publish artifacts (commits, PR titles + bodies, PR review comments).
+
+## Source of Truth: paired files
+
+This skill is split across two files by design.
+
+- **`voice/SKILL.md`** (this file) — the thin rule-set. Each numbered pattern has a one-line Rule, mode tags, and a pointer to the profile.
+- **`voice/references/voice-profile.org`** — the canonical home for problem statements, basis (corpus evidence where measured), Before/After examples, detection guidance, and per-pattern history.
+
+**Pairing rule.** Every change to a pattern lands in both files. A SKILL.md edit without a profile update is incomplete. A profile update without a SKILL.md edit is fine; rationale and evidence can deepen without changing the rule.
+
+**At invocation, load both.** The Rule lines here tell you what to do. The profile entries tell you how to do it, with worked examples. Apply each pattern by consulting both.
+
+## Modes
+
+Three modes determine which patterns to walk. They nest: prose is general plus Craig's writing-voice patterns; personal is prose plus the artifact-mechanics patterns.
+
+- **General** (default) — apply patterns **#1-31** and **#48** (term-translation density, a universal clarity rule that happens to carry a later number). Use for writing whose author isn't Craig and that isn't a publish artifact: research notes you're editing for someone else, a quoted passage, README prose for a shared project, any third-party text. Output is well-edited human-sounding prose, but does not impose Craig's voice (first-person, contractions, em-dash elimination) — those conflict with academic, literary, or formal registers that aren't his.
+- **Prose** — apply **#1-31** plus the patterns tagged **(prose + personal)**: em-dash zero-tolerance (#13), contractions (#34), semicolons → periods (#33), sentence-split (#35), felt-experience cut (#36), sentence-fragment rewrite (#37), terse-cut (#38), no-emphasis-formatting (#41), single-sentence cadence (#43), parenthetical asides (#44), and the declarative-register marker (#45) — plus **#47 (recipient-priority ordering)** when the piece is correspondence (email, Signal, a letter). Use for prose Craig authors or sends in his own voice that isn't a publish artifact: emails, documents he writes or hands to someone, working notes, journal entries. This is the mode that finally applies his actual writing voice to the documents he most wants it on. It skips the artifact-mechanics patterns (#32, #39, #40, #42) — those assume a commit or PR and misfire on free prose (a document is legitimately third-person; a journal has no public-scope concern; praise/correction asymmetry and finding stems are PR-review rules).
+- **Personal** — apply **#1-46** and **#48**. Use only for publish artifacts: commits, PR titles + bodies, and PR review comments. Adds the artifact-mechanics patterns (#32 first-person rewrite, #39 public-artifact scope flag, #40 praise/correction asymmetry, #42 finding stems, #46 comma budget) on top of everything prose mode walks. #47 is the lone exception to the nesting — it is correspondence-only, and a publish artifact is never a reply to someone's news, so personal mode stops at #46.
+
+If invoked without a mode argument, default to general. Prose mode is invoked explicitly with `/voice prose` (emails, authored documents). Personal-context callers (`commits.md` publish flow, `respond-to-cj-comments.md`) invoke `/voice personal`.
+
+## Personal-Mode Artifact Budgets
+
+Terse is a budget, not an adjective. Each publish-artifact type has a target shape; the walk checks the draft against it. Exceeding a budget needs a reason the reader will thank you for.
+
+| Artifact | Budget |
+|----------|--------|
+| Commit body | Skip entirely when the subject line carries the change. Otherwise short paragraphs: the constraint, bug, or tradeoff. No play-by-play. |
+| PR description | Problem / Fix / Why / Testing, each section tight. |
+| PR review summary | Lead with the substantive pointer, verdict closes it. No praise, not even a bare positive (#40). Verdict formulas ("Approving.", "Requesting changes.") are valid sentences here. |
+| Inline pin (finding) | ~4 sentences in stems shape (#42): where the bug is, the fix, why it's better. |
+| Praise comment (inline only) | One sentence naming what's good. Nothing else (#40). Never in the summary body. |
+| Follow-up approval after prior feedback was addressed | Exactly "Approved." |
+
+## Your Task
+
+When given text to edit:
+
+1. **Identify which patterns apply** — Scan for the patterns numbered below. General mode walks #1-31 and #48. Prose mode adds the patterns tagged **(prose + personal)**, plus #47 when the piece is correspondence. Personal mode adds the **(personal only)** ones instead — patterns #1-46 and #48, never #47.
+2. **Rewrite problematic sections** — Replace each detected pattern with its rewrite.
+3. **Preserve meaning** — Keep the core message intact.
+4. **Maintain voice** — Match the intended tone (formal, casual, technical, academic, literary).
+5. **Add soul where the register supports it** — see Personality and Soul below, and note its mode limits.
+6. **Run the closing passes in order** — terse cut last among rewrites, then the anti-AI audit on the final text, then the attestation block. The Process section below is the authoritative order.
+
+## Personality and Soul
+
+**Mode note.** This section applies in general and prose modes, where the register supports personality. Personal mode (publish artifacts) skips soul-injection: a commit message or review comment needs clarity and brevity, not pulse. "Let some mess in" and "have opinions" pull directly against the artifact budgets, and the budgets win.
+
+Avoiding AI patterns is half the job. Sterile, voiceless writing is just as obvious as slop. Good writing has a human behind it.
+
+### Signs of soulless writing (even if technically clean)
+- Every sentence is the same length and structure
+- No opinions, just neutral reporting
+- No acknowledgment of uncertainty or mixed feelings
+- No first-person perspective when the register supports it
+- No humor, no edge, no personality
+- Reads like a Wikipedia article or press release
+
+### How to add voice
+
+**Have opinions.** Don't just report facts — react to them. "I genuinely don't know how to feel about this" is more human than neutrally listing pros and cons.
+
+**Vary the rhythm.** Short punchy sentences. Then longer ones that take their time getting where they're going. Mix it up.
+
+**Acknowledge complexity.** Real humans have mixed feelings. "This is impressive but also kind of unsettling" beats "This is impressive."
+
+**Use "I" when it fits the register.** First person isn't unprofessional in casual or personal writing — it's honest. Skip in academic prose where third-person is conventional.
+
+**Let some mess in.** Perfect structure feels algorithmic. Tangents, asides, and half-formed thoughts are human.
+
+**Be specific about feelings.** Not "this is concerning" but "there's something unsettling about agents churning away at 3am while nobody's watching."
+
+### Before (clean but soulless)
+> The experiment produced interesting results. The agents generated 3 million lines of code. Some developers were impressed while others were skeptical. The implications remain unclear.
+
+### After (has a pulse)
+> I genuinely don't know how to feel about this one. 3 million lines of code, generated while the humans presumably slept. Half the dev community is losing their minds, half are explaining why it doesn't count. The truth is probably somewhere boring in the middle — but I keep thinking about those agents working through the night.
+
+## Content Patterns
+
+### 1. Undue Emphasis on Significance, Legacy, and Broader Trends [general]
+
+**Rule.** Strip statements that puff up importance by claiming an arbitrary aspect represents or contributes to a broader trend, and watch for phrases like "stands as", "testament to", "pivotal moment", "evolving landscape", "marks a shift".
+
+See `voice/references/voice-profile.org` §1 for problem, basis, examples, and history.
+
+### 2. Undue Emphasis on Notability and Media Coverage [general]
+
+**Rule.** Cut notability claims that list sources without giving the substance. Replace "cited in X, Y, Z" with the actual argument made in one of them.
+
+See `voice/references/voice-profile.org` §2 for problem, basis, examples, and history.
+
+### 3. Superficial Analyses with -ing Endings [general]
+
+**Rule.** Cut tacked-on present-participle phrases (highlighting, ensuring, reflecting, contributing to, fostering, showcasing) that add fake depth without new information.
+
+See `voice/references/voice-profile.org` §3 for problem, basis, examples, and history.
+
+### 4. Promotional and Advertisement-like Language [general]
+
+**Rule.** Remove travel-brochure adjectives (vibrant, breathtaking, nestled, stunning, renowned, must-visit) and replace promotional framing with concrete facts.
+
+See `voice/references/voice-profile.org` §4 for problem, basis, examples, and history.
+
+### 5. Vague Attributions and Weasel Words [general]
+
+**Rule.** Replace vague attributions (experts say, observers have cited, industry reports, some critics argue) with a named source plus the specific claim.
+
+See `voice/references/voice-profile.org` §5 for problem, basis, examples, and history.
+
+### 6. Outline-like "Challenges and Future Prospects" Sections [general]
+
+**Rule.** Delete formulaic "Despite its... faces challenges" wrap-ups and "Future Outlook" boilerplate, replacing with the actual events that happened.
+
+See `voice/references/voice-profile.org` §6 for problem, basis, examples, and history.
+
+## Language and Grammar Patterns
+
+### 7. Overused "AI Vocabulary" Words [general]
+
+**Rule.** Flag and rewrite around the high-frequency AI vocabulary list (delve, comprehensive, crucial, pivotal, intricate, tapestry, testament, underscore, vibrant, showcase, and the others), with "comprehensive" as a soft flag because corpus shows it as genuine Craig vocabulary he chooses to use sparingly.
+
+See `voice/references/voice-profile.org` §7 for problem, basis, examples, and history.
+
+### 8. Avoidance of "is"/"are" (Copula Avoidance) [general]
+
+**Rule.** Replace elaborate copula substitutes (serves as, stands as, represents, boasts, features) with plain "is" or "has".
+
+See `voice/references/voice-profile.org` §8 for problem, basis, examples, and history.
+
+### 9. Negative Parallelisms [general]
+
+**Rule.** Rewrite "not only X but Y" and "it's not just about X, it's Y" constructions as a single direct claim.
+
+See `voice/references/voice-profile.org` §9 for problem, basis, examples, and history.
+
+### 10. Rule of Three Overuse [general]
+
+**Rule.** Break the reflexive three-item list pattern when the third item is filler. Collapse to one or two specific items.
+
+See `voice/references/voice-profile.org` §10 for problem, basis, examples, and history.
+
+### 11. Elegant Variation (Synonym Cycling) [general]
+
+**Rule.** Stop cycling synonyms for the same referent across consecutive sentences. Repeat the noun, or merge the sentences.
+
+See `voice/references/voice-profile.org` §11 for problem, basis, examples, and history.
+
+### 12. False Ranges [general]
+
+**Rule.** Rewrite "from X to Y" constructions where X and Y are not on the same scale. List the items plainly instead.
+
+See `voice/references/voice-profile.org` §12 for problem, basis, examples, and history.
+
+## Style Patterns
+
+### 13. Em Dash Overuse [general: overuse-reduction · prose/personal: zero-tolerance]
+
+**Rule.** Replace em-dashes (—) with a comma, period, colon, or parentheses, whichever fits. Zero-tolerance in prose and personal modes holds everywhere in the text, including inside example blocks, code-fence prose, and quoted material. The zero-tolerance rule is chosen self-discipline, not a reflection of Craig's pre-rule habit (corpus: 3.49/1000 words).
+
+See `voice/references/voice-profile.org` §13 for problem, basis, examples, and history.
+
+### 14. Overuse of Boldface [general]
+
+**Rule.** Strip mechanical boldface used to call out terms, acronyms, or phrases in running prose. Bold survives only for structural emphasis the document genuinely needs.
+
+See `voice/references/voice-profile.org` §14 for problem, basis, examples, and history.
+
+### 15. Inline-Header Vertical Lists [general]
+
+**Rule.** Collapse bullet lists whose items start with a bold header plus colon into running prose, unless the list structure is genuinely the right shape.
+
+See `voice/references/voice-profile.org` §15 for problem, basis, examples, and history.
+
+### 16. Title Case in Headings [general]
+
+**Rule.** Lowercase headings that are reflexively title-cased. Sentence case is the default unless the project's house style is title case.
+
+See `voice/references/voice-profile.org` §16 for problem, basis, examples, and history.
+
+### 17. Emojis [general]
+
+**Rule.** Remove decorative emojis from headings, bullets, and prose unless the document is a register where emoji is genuinely intended.
+
+See `voice/references/voice-profile.org` §17 for problem, basis, examples, and history.
+
+### 18. Curly Quotation Marks [general]
+
+**Rule.** Convert curly quotation marks to straight ASCII quotes.
+
+See `voice/references/voice-profile.org` §18 for problem, basis, examples, and history.
+
+## Communication Patterns
+
+### 19. Collaborative Communication Artifacts [general]
+
+**Rule.** Strip chatbot correspondence framing ("I hope this helps", "Let me know if...", "Here is an overview of...", "Certainly!", "Of course!") that leaked into the body.
+
+See `voice/references/voice-profile.org` §19 for problem, basis, examples, and history.
+
+### 20. Knowledge-Cutoff Disclaimers [general]
+
+**Rule.** Remove training-cutoff hedges ("as of my last update", "while specific details are scarce", "based on available information") and either commit to a fact or omit the claim.
+
+See `voice/references/voice-profile.org` §20 for problem, basis, examples, and history.
+
+### 21. Sycophantic/Servile Tone [general]
+
+**Rule.** Cut servile opener phrases ("Great question!", "You're absolutely right", "That's an excellent point") and proceed straight to the substance.
+
+See `voice/references/voice-profile.org` §21 for problem, basis, examples, and history.
+
+## Filler and Hedging
+
+### 22. Filler Phrases [general]
+
+**Rule.** Compress wordy filler ("in order to" to "to", "due to the fact that" to "because", "at this point in time" to "now", "has the ability to" to "can", "it is important to note that" to nothing).
+
+See `voice/references/voice-profile.org` §22 for problem, basis, examples, and history.
+
+### 23. Excessive Hedging [general]
+
+**Rule.** Strip stacked hedges ("could potentially possibly", "might have some effect") down to a single appropriate qualifier.
+
+See `voice/references/voice-profile.org` §23 for problem, basis, examples, and history.
+
+### 24. Generic Positive Conclusions [general]
+
+**Rule.** Replace vague upbeat endings ("the future looks bright", "exciting times lie ahead", "a step in the right direction") with a concrete fact or cut the closer entirely.
+
+See `voice/references/voice-profile.org` §24 for problem, basis, examples, and history.
+
+### 25. Hyphenated Word Pair Overuse [general]
+
+**Rule.** Drop reflexive hyphens from common modifier pairs (cross-functional, data-driven, decision-making, well-known, high-quality, real-time, long-term) where humans hyphenate inconsistently. Less common or genuinely technical compound modifiers can keep their hyphens.
+
+See `voice/references/voice-profile.org` §25 for problem, basis, examples, and history.
+
+## Universal Good-Writing Rules
+
+These six patterns extend the AI-detection patterns above with canonical good-writing rules from Strunk & White's *The Elements of Style*, Orwell's *Politics and the English Language*, the Plain English Campaign, and Garner's *Modern English Usage*. They apply in both modes — they target prose smells with no register conflict.
+
+### 26. Long Word → Short Word [general]
+
+**Rule.** Swap long Latinate words for their short Anglo-Saxon equivalents per the Plain English wordlist (utilize to use, facilitate to help, ascertain to find out, methodology to method, prior to to before, optimal to best).
+
+See `voice/references/voice-profile.org` §26 for problem, basis, examples, and history.
+
+### 27. Active Over Passive Voice [general]
+
+**Rule.** Rewrite passive constructions to active when the actor is recoverable from context. Flag rather than auto-rewrite when the actor genuinely doesn't matter.
+
+See `voice/references/voice-profile.org` §27 for problem, basis, examples, and history.
+
+### 28. Comma Splices [general]
+
+**Rule.** Split two independent clauses joined only by a comma into two sentences or join them with a conjunction. In personal mode the semicolon escape route is blocked by #33.
+
+See `voice/references/voice-profile.org` §28 for problem, basis, examples, and history.
+
+### 29. Cliché Flag [general]
+
+**Rule.** Replace business and conversational clichés (at the end of the day, leverage as a verb, low-hanging fruit, circle back, touch base, move the needle, keep it loose) with the plain meaning, including in casual register where "it's fine, it's casual" is the tell.
+
+See `voice/references/voice-profile.org` §29 for problem, basis, examples, and history.
+
+### 30. Jargon-Fragment → Complete Sentence [general]
+
+**Rule.** Rewrite telegraphic sentence fragments inside prose paragraphs as complete sentences with subject and verb. Headings and bullet items are exempt because fragments are valid there.
+
+See `voice/references/voice-profile.org` §30 for problem, basis, examples, and history.
+
+### 31. Noun-ified Verbs [general]
+
+**Rule.** Replace corporate-speak noun-ifications (the ask, a learn, the spend, a build, the reveal, the lift) with the real noun (the request, the lesson, the budget, the system, the finding). Philosophical nominalizations are not targets.
+
+See `voice/references/voice-profile.org` §31 for problem, basis, examples, and history.
+
+## Craig's Voice (prose + personal modes)
+
+These patterns carry Craig's writing voice. Most apply in **both** prose mode (emails, documents, notes he authors) and personal mode (commits, PRs, PR comments) — tagged **(prose + personal)**. Five are publish-artifact-specific — tagged **(personal only)** — because they assume a commit or PR and misfire on free prose: #32 (first-person rewrite) wrongly imposes "I did X" voice on a document that's legitimately third-person, #39 (public-artifact scope flag) has nothing to guard in a private journal, #40 (praise/correction asymmetry) and #42 (finding stems) are PR-review rules, and #46 (comma budget) is scoped to publish artifacts by Craig's 2026-07-20 directive. One — #47 (recipient-priority ordering) — runs the other way: prose-only and narrower still, firing solely on correspondence, because ordering a reply around the recipient's news has no meaning for a commit or a document addressed to nobody. General mode skips all of them — it edits text that isn't Craig's, where contractions, em-dash elimination, and first-person would conflict with academic, literary, or formal registers.
+
+### 32. First-Person Voice Rewrite [personal]
+
+**Rule.** Rewrite impersonal third-person publish-artifact bodies into first person ("I added X", "I kept Y because..."). The commit subject line stays imperative per Conventional Commits. Skip for mechanical changes where the subject alone carries the message.
+
+See `voice/references/voice-profile.org` §32 for problem, basis, examples, and history.
+
+### 33. Semicolon → Period or Comma [prose · personal]
+
+**Rule.** Replace semicolons with a period (split into two sentences) or a comma (when the clauses are tightly coupled) in Craig's authored prose. A formal long-form document can keep the semicolon, but the default is to split. Chosen self-discipline, not habit-reflection (corpus: 3.16/1000 words).
+
+See `voice/references/voice-profile.org` §33 for problem, basis, examples, and history.
+
+### 34. Contractions [prose · personal]
+
+**Rule.** Prefer contractions in Craig's prose (it's, that's, don't, we're, I'd, won't) unless a negation or emphasis genuinely needs the uncontracted weight.
+
+See `voice/references/voice-profile.org` §34 for problem, basis, examples, and history.
+
+### 35. Sentence Split on Conjunctions [prose · personal]
+
+**Rule.** Split sentences that stack three or four clauses joined by "so", "and", "but" into two or three shorter sentences when the split does not lose meaning. Academic or literary registers can keep long sentences.
+
+See `voice/references/voice-profile.org` §35 for problem, basis, examples, and history.
+
+### 36. Felt-Experience Narration [prose · personal]
+
+**Rule.** Cut phrases that tell the reader how the change will feel or how often the writer will use it ("I'll feel this every time", "this will be a relief", "I'm excited about", "this is huge"). State what changed and let the reader decide.
+
+See `voice/references/voice-profile.org` §36 for problem, basis, examples, and history.
+
+### 37. Sentence Fragments → Complete [prose · personal]
+
+**Rule.** Rewrite every sentence fragment inside a prose paragraph in Craig's authored text as a complete sentence with subject and verb. Bullets and headings can stay fragments. This is the stricter cousin of general-mode #30. **Exemption:** verdict formulas in PR review summaries ("Approving.", "Requesting changes.", "Approved.") are house style and stay — rewriting them imposes the rule where Craig's calibrated voice already decided otherwise.
+
+See `voice/references/voice-profile.org` §37 for problem, basis, examples, and history.
+
+### 38. Terse Cut — Omit Needless Words [prose · personal]
+
+**Rule.** Two cuts. First, strip soft rhetorical padding ("worth noting", "it's important to understand", "as you can see", "needless to say", "obviously", "of course", "in essence", "fundamentally"). Then run the general Orwell sweep the padding list only samples: read each sentence and cut or collapse every word and clause that can go without losing meaning — verbose verb phrases ("already merged via" → "landed on"), restated subjects, throat-clearing lead-ins, clauses whose content the reader already has. The forcing test is per sentence: try to delete half of it and keep only what changes meaning. This is a real walk step, not a wordlist match — a draft that clears the named padding can still run a third too long on ordinary verbosity. Academic writing retains the transition markers, so the aggressive cut is prose and personal only.
+
+See `voice/references/voice-profile.org` §38 for problem, basis, examples, and history.
+
+### 39. Public-Artifact Scope Check [personal]
+
+**Rule.** Flag (do not auto-rewrite) local absolute paths, private repo names, and personal-tooling references (anything under `claude-rules/`, `.ai/`, `.claude/`, or naming personal skills) in publish artifacts. Surface each match as a WARN line so the author resolves manually.
+
+See `voice/references/voice-profile.org` §39 for problem, basis, examples, and history.
+
+### 40. Praise vs Correction Asymmetry [personal]
+
+**Rule.** Praise on a PR review is short and unjustified (the author knows why their good change is good). Correction always explains the why, gently and briefly, the way a mentor would. Never as a verdict from on high. **Verification narration is the same defect as justified praise:** "I traced X and it's safe because..." pads the compliment with the reviewer's homework. Tracing the code is the reviewer's job, not content for the comment — if verification found a problem, the problem gets the words; if it found nothing, it gets zero words. **An approve summary carries no praise at all** — not even a bare positive ("Clean.", "Solid fix."). Lead the summary with the substantive pointer (the design note pinned inline) and close with the verdict: "One design note inline, not a blocker. Approving." An approve with nothing to flag is just "Approving." Short unjustified praise survives only as an inline pin on the line it refers to, never in the summary body.
+
+See `voice/references/voice-profile.org` §40 for problem, basis, examples, and history.
+
+### 41. No Emphasis Formatting [prose · personal]
+
+**Rule.** Remove emphasis markup (bold, italics, underscore-wrapped words) used to stress a phrase in Craig's prose, and rephrase so the stress lives in word choice and sentence shape. Structural markup stays: headings, defined terms on first use, code spans for literal identifiers.
+
+See `voice/references/voice-profile.org` §41 for problem, basis, examples, and history.
+
+### 42. Finding Stems — One Claim Per Sentence [personal]
+
+**Rule.** A PR review finding is built from clean stems, each a straightforward sentence carrying one claim: (1) where the bug is, (2) the way(s) to fix it, (3) why that's better. Cut context sentences that don't change what the author does next (ticket history, design archaeology). Rewrite the anti-pattern shapes: hedged gerund chains ("the real bug looks like the model emitting a partial set"), compressed trade-off clauses ("I'd rather X, or Y, than lose Z"), multi-claim sentences chained through so-clauses or "and", and fixes buried after a mid-sentence colon. A sentence can pass #38 terse and still tangle three claims — #38 shortens, #42 untangles.
+
+See `voice/references/voice-profile.org` §42 for problem, basis, examples, and history.
+
+### 43. Single-Sentence Paragraph Cadence Is a Feature [prose · personal]
+
+**Rule.** A one-sentence paragraph is a finished thought, not a fragment. "Shifts angle" means shifts *topic*: break paragraphs at a topic boundary, even when both sides are one sentence. Within a single topic, do the opposite — consolidate its sentences into one paragraph even when each is a complete thought, up to a ceiling of about five or six sentences, past which find a natural break. The never-merge instruction protects the break *between* topics, which is where Craig's cadence lives (corpus: 41-74% of his paragraphs are exactly one sentence, depending on register); it never licenses fragmenting one topic across several paragraphs. See #47 for the ordering of those topics in a reply.
+
+See `voice/references/voice-profile.org` §43 for problem, basis, examples, and history.
+
+### 44. Parenthetical Asides Are Part of the Voice [prose · personal]
+
+**Rule.** Parentheses for asides, clarifications, and scope-narrowing are Craig's voice (corpus: 23 opening parens per 1000 words). Don't strip them in a cleanup pass. They're also the preferred landing spot for em-dash replacements under #13.
+
+See `voice/references/voice-profile.org` §44 for problem, basis, examples, and history.
+
+### 45. Declarative Register Marker [prose · personal, advisory]
+
+**Rule.** Craig's prose is declarative (corpus: 0.33 question marks per 1000 words). When a draft contains a rhetorical question, flag it for a second look — it's usually AI rhetoric, not his register. Genuine questions to the reader (a review asking the author's intent, an email asking for a decision) stay. Advisory: flag, don't auto-rewrite.
+
+See `voice/references/voice-profile.org` §45 for problem, basis, examples, and history.
+
+### 46. Comma Budget — Max Two Per Sentence [personal]
+
+**Rule.** No sentence carries more than two commas. Rewrite the third comma away: split the sentence, move a clause into a parenthetical (#44) or behind a colon, or break an inline serial list into bullets or its own sentence. Count prose commas only — commas inside code spans, quoted log lines, and literal strings don't count toward the budget.
+
+See `voice/references/voice-profile.org` §46 for problem, basis, examples, and history.
+
+### 47. Recipient-Priority Ordering [prose — correspondence only]
+
+**Rule.** In a reply, lead with what matters most to the *recipient*, not with what's easiest to answer or the order they wrote it. Their news outranks your logistics, and a direct question they asked can sort *below* personal news they shared, because the news is what they care about. Leading with the easy answer reads as transactional. Correspondence-scoped: it needs a recipient, so it fires on email, Signal, and letters, and has no referent in a journal, a working note, or any document addressed to nobody. This is the one prose-mode pattern that does not carry into personal mode — a commit or PR review is not a reply to someone's news.
+
+See `voice/references/voice-profile.org` §47 for problem, basis, examples, and history.
+
+### 48. Term-Translation Density [general]
+
+**Rule.** A sentence that forces the reader to stop and translate more than one specialized term (an acronym, a coined phrase, a product name) is too dense. One such term is fine; two or more in one sentence means rewrite it: split the sentence, gloss one term inline in a parenthetical (#44), or drop to plain language. The test is the reader's parse, not the writer's familiarity, and it is audience-relative — a term the whole audience shares (SAR to a defense team) carries no translation load, while a term only the writer holds (a coined "detect-then-contextualize", or ViT and VLM stacked in one clause) does. Distinct from #7 (which flags specific AI-vocabulary words) and #30 (which rewrites telegraphic fragments): this one measures jargon density per sentence against the reader's translation load.
+
+See `voice/references/voice-profile.org` §48 for problem, basis, examples, and history.
+
+## Process
+
+1. Read the input text carefully. Confirm the mode (general, prose, or personal) — invocation argument or context. If a file path was given, that file is the deliverable: the final text gets written back to it in step 7.
+2. Walk patterns 1-31 and 48 in general mode; add the (prose + personal) patterns in prose mode, plus #47 when the piece is correspondence; walk patterns 1-46 and 48 in personal mode.
+3. For each pattern, scan the text. If a match is found, rewrite it according to the pattern's rule. Patterns #39 and #45 emit flags without rewriting.
+4. After walking all patterns, ensure the revised text:
+ - Sounds natural when read aloud
+ - Varies sentence structure
+ - Uses specific details over vague claims
+ - Maintains appropriate tone for the register
+5. **Terse pass — mandatory, last rewrite pass (prose + personal modes).** Walk pattern #38 again as a standalone action: read each sentence and try to cut it in half, keeping only the words that change meaning. Run it on its own here, not folded into step 3's walk — it is the most-skipped pattern and the bloat it catches is the first thing a reader notices. General mode skips this step — academic and third-party registers keep their transition markers.
+6. **Anti-AI audit — on the final text.** Prompt: "What makes the below so obviously AI generated?" Answer briefly with remaining tells, then revise. This runs *after* the terse pass so the audited text is the text that ships. If the audit triggers rewrites, re-apply the #38 per-sentence test to every changed sentence before proceeding.
+7. **Write-back.** If the invocation supplied a file path, write the final text to that file now and say so. The publish flow posts from the file (`git commit -F`, `gh pr create --body-file`), so a final text that lives only in chat is a drift bug waiting to post the un-voiced version.
+8. **Attestation block (prose + personal modes).** The high-recurrence patterns — the ones with a documented failure history — each get one explicit line: pattern, checked, match or no match, action taken. Current high-recurrence set: **#13 (em-dash), #37 (fragments), #38 (terse), #40 (praise asymmetry), #42 (finding stems), #46 (comma budget)**. This is a receipt, not a summary: a pattern with no match still gets its line. When a pattern in this set fails in the wild despite the receipt, escalate it the way #38 was escalated; when one holds clean for a long stretch, it can rotate out.
+9. Present the final version per the Output Format below.
+
+## Output Format
+
+### Compact (default for personal-mode artifacts under ~25 lines: commit messages, review summaries + pins, short PR bodies)
+
+1. **Final text** — exactly what will be posted, nothing else above it
+2. **Pattern-39 warnings** — WARN lines, if any
+3. **Fired** — one line listing patterns that fired (e.g., "fired: #13, #38, #42")
+4. **Attestation** — the high-recurrence receipt block (one line per pattern)
+5. **Write-back note** — "written back to <path>" when a file path was supplied
+
+The compact format exists because the deliverable must not drown in ceremony: for a three-sentence review comment, printing a draft rewrite, a final rewrite, and an audit Q&A buries the text the gate needs to read, and a long scaffold is easy to print without doing the work. The attestation block is the anti-performative check — it names the patterns that actually fail in practice.
+
+### Full (long-form prose, general mode, or on request)
+
+1. **Draft rewrite** — the text after walking all applicable patterns
+2. **Mode used** — general, prose, or personal
+3. **What makes the below so obviously AI generated?** — brief bullets
+4. **Final rewrite** — revised after the anti-AI audit (and post-audit terse re-check)
+5. **Pattern-39 warnings** (personal mode only)
+6. **Summary of changes** — list of patterns that fired
+7. **Attestation block** (prose + personal)
+8. **Write-back note** — when a file path was supplied
+
+## Full Example — Personal Mode (compact output)
+
+**Before** (a commit message draft from a model, supplied at `/tmp/commit-empty-guard.md`):
+> Adds new validator for empty input handling.
+>
+> The previous validation logic in `~/code/rulesets/voice/SKILL.md` allowed empty strings to leak through to the database layer; this change introduces a guard at the API boundary that returns a 400 response when the input field is empty or contains only whitespace, ensuring data integrity is maintained throughout the request lifecycle. It is worth noting that this does not affect the upstream caller, and we are excited about the productivity gains this will provide.
+>
+> Furthermore, the new pattern leverages our existing validation framework to deliver a robust, scalable, and maintainable solution.
+
+**Output:**
+
+**Final text:**
+> feat(api): add empty-input guard at the validator boundary
+>
+> I added a guard that rejects empty or whitespace-only input fields at the API boundary with a 400 response. The previous flow let empty values leak through to the database layer.
+>
+> The change doesn't affect the upstream caller. The new pattern reuses the existing validation framework.
+
+**Pattern-39 warnings:**
+- WARN: original draft line 3: `~/code/rulesets/voice/SKILL.md` — local absolute path. State the underlying validation behavior instead.
+
+**Fired:** #3 (-ing analysis), #4 (promotional), #10 (rule of three), #29 (cliché: "leverages"), #32 (first-person), #33 (semicolon), #34 (contractions), #36 (felt-experience), #38 (terse: "It is worth noting")
+
+**Attestation:**
+- #13 em-dash: checked — no match
+- #37 fragments: checked — no match
+- #38 terse: checked — fired ("It is worth noting that" cut; final per-sentence pass ran)
+- #40 praise asymmetry: checked — not applicable (commit, not review)
+- #42 finding stems: checked — not applicable (commit, not review finding)
+
+**Write-back:** written back to /tmp/commit-empty-guard.md
+
+## Full Example — General Mode
+
+**Before** (a paragraph from a research note):
+> The Statistical Institute of Catalonia was officially established in 1989, marking a pivotal moment in the evolution of regional statistics in Spain. This initiative was part of a broader movement across Spain to decentralize administrative functions and enhance regional governance. The institute serves as a vital component of the regional statistical landscape, showcasing how decentralized data collection can foster more accurate regional reporting.
+
+**Mode used:** general
+
+**Draft rewrite:**
+> The Statistical Institute of Catalonia was established in 1989 to collect and publish regional statistics independently from Spain's national statistics office. It was part of a wider movement to decentralize administrative functions across Spain. Decentralized data collection produces more accurate regional reporting than the previous centralized approach.
+
+**What makes the below so obviously AI generated?**
+- The phrase "more accurate regional reporting than the previous centralized approach" still has a slight summary-paragraph rhythm. A human writer might just say what changed and stop.
+
+**Final rewrite:**
+> The Statistical Institute of Catalonia was established in 1989 to collect and publish regional statistics independently from Spain's national statistics office. It was part of a wider movement to decentralize administrative functions across Spain. Regional reporting got more accurate after the change.
+
+**Summary of changes:**
+- Patterns that fired in general mode: #1 (significance inflation: "pivotal moment", "evolution of"), #4 (promotional: "vital component"), #3 (-ing analysis: "showcasing how... can foster"), #8 (copula avoidance: "serves as"), #26 (long-word: removed Latinate constructions). General mode skipped patterns #32-45 (Craig's-voice patterns — prose and personal modes only).
+
+## Reference
+
+This skill draws from:
+- [Wikipedia: Signs of AI writing](https://en.wikipedia.org/wiki/Wikipedia:Signs_of_AI_writing) — patterns #1-25, maintained by WikiProject AI Cleanup.
+- Strunk & White, *The Elements of Style* — patterns #28 (comma splices), #26 (omit needless words, supplemented by humanizer pattern #22).
+- Orwell, *Politics and the English Language* — patterns #26 (short over long), #27 (active over passive), #29 (cliché).
+- Plain English Campaign — pattern #26 (Plain English wordlist).
+- Garner, *Modern English Usage* — pattern #26 (word-pair preferences).
+- Craig's voice rules from `claude-rules/commits.md` (Voice and Focus section) — patterns #32-42, split across prose mode (his authored prose and email) and personal mode (publish artifacts).
+- Craig's directive, 2026-07-20 (archsetup session) — pattern #46 (comma budget), personal mode.
+- Craig's edit of a Signal reply, 2026-07-23 (home session) — pattern #47 (recipient-priority ordering) and the #43 topic-vs-angle calibration, prose/correspondence.
+- Craig's edit of a customer-partner email, 2026-07-23 (work session) — pattern #48 (term-translation density), general.
+- Corpus measurement (2026-05-29 phases 1-2, documented in the profile) — patterns #43-45 and the calibration notes on #7, #13, #33.
+
+Key insight (Wikipedia, paraphrased): LLMs use statistical algorithms to guess what should come next. The result tends toward the most statistically likely text that applies to the widest variety of cases. Patterns #1-25 detect that signature.
+
+Key insight (Orwell): "If it is possible to cut a word out, always cut it out." Patterns #22, #23, #26, #38 act on this rule at increasing levels of aggressiveness depending on register.
+
+Key insight (2026-06-10): the patterns that fail in practice aren't missing rules — they're present rules walked without receipts. The attestation block exists because "walk all 45" is a prose instruction, and prose instructions about diligence don't survive contact; named per-pattern receipts do.
diff --git a/working/voice-term-density/profile.diff b/working/voice-term-density/profile.diff
new file mode 100644
index 0000000..3134ebf
--- /dev/null
+++ b/working/voice-term-density/profile.diff
@@ -0,0 +1,36 @@
+--- voice/references/voice-profile.org 2026-07-23 23:24:57.119185940 -0500
++++ /tmp/profile.proposed 2026-07-23 23:29:48.169642034 -0500
+@@ -1611,3 +1611,33 @@
+
+ *** History
+ - 2026-07-23: added from the home session drafting a Signal reply. The first handoff proposed two new patterns and flagged a conflict with §43; the superseding design resolved that the conflict was a misreading of §43 (angle = topic), leaving one genuinely new pattern here and a calibration to §43. Prose/correspondence-scoped per Craig — email and Signal are prose, not publish artifacts.
++
++** §48 Term-Translation Density
++
++*** Modes
++General mode, so it runs in all three (general, prose, personal). It's a universal clarity rule in the Orwell / Plain English family, not a Craig-voice trait, and it reads to anyone editing any prose. The later number is an artifact of when it was added, not a scope signal.
++
++*** Rule
++A sentence that forces the reader to stop and translate more than one specialized term (an acronym, a coined phrase, a product name) is too dense. One is fine; two or more in one sentence means rewrite: split the sentence, gloss one term in a parenthetical, or drop to plain language. The test is the reader's parse, not the writer's familiarity, and it is audience-relative.
++
++*** Problem
++A writer fluent in the domain doesn't feel the translation cost of the terms, so a sentence stacking three of them reads as normal to the author and stalls the reader on every clause. Density is the metric, not any single word: two coined terms in one sentence is worse than a paragraph that introduces the same two one at a time. Audience-relative, because SAR to a defense team is shared vocabulary carrying no load, while a coined phrase only the writer holds carries full load for everyone else.
++
++*** Basis
++Craig's edit of a customer-partner email, 2026-07-23 (work session), where one sentence stacked three terms and he flagged it. Distinct from #7 (specific AI-vocabulary words) and #30 (telegraphic fragments); this measures jargon density per sentence.
++
++*** Before (one sentence, three terms the reader must translate)
++#+begin_example
++A ViT detector gating a VLM for enrichment is close to our own detect-then-contextualize direction.
++#+end_example
++
++*** After (split, glossed, plain)
++#+begin_example
++Their setup is a fast detector that hands off to a heavier model for a closer read. That mirrors our own two-stage approach (find it first, then work out what it is).
++#+end_example
++
++*** Detection
++Count the specialized terms in each sentence that a member of the intended audience would have to stop and translate. Two or more is the trigger. Acronyms, coined phrases, and product names count; shared-vocabulary terms for that audience don't.
++
++*** History
++- 2026-07-23: proposed by Craig from the work session, drafting a customer-partner email. Placed in general mode (universal clarity rule); numbered #48, after the prose-only #47.
diff --git a/working/voice-term-density/proposal-from-work.org b/working/voice-term-density/proposal-from-work.org
new file mode 100644
index 0000000..d19e5ca
--- /dev/null
+++ b/working/voice-term-density/proposal-from-work.org
@@ -0,0 +1,42 @@
+#+TITLE: New voice pattern proposed by Craig (2026-07-23, from the wo
+#+SOURCE: from work
+#+DATE: 2026-07-23 23:26:24 -0500
+
+New voice pattern proposed by Craig (2026-07-23, from the work project): term-translation density.
+
+THE RULE Craig stated: if a reader has to stop and mentally translate more than one specialized term in a single sentence, the sentence should be rewritten.
+
+Proposed pattern text for SKILL.md (place, number, and mode-tag per your taxonomy — see notes below):
+
+ Term-translation density. A sentence that forces the reader to stop and
+ translate more than one specialized term (acronym, coined phrase, product
+ name) is too dense. One such term is fine; two or more in one sentence means
+ rewrite it: split the sentence, gloss one term inline in a parenthetical, or
+ drop to plain language. The test is the reader's parse, not the writer's
+ familiarity. It is audience-relative: terms the whole audience shares (SAR to
+ a defense team) carry no translation load, but terms only the writer holds (a
+ coined 'detect-then-contextualize', or ViT and VLM stacked in one clause) do.
+
+Worked before/after for the profile entry (this is the live case that prompted it):
+ Before: A ViT detector gating a VLM for enrichment is close to our own
+ detect-then-contextualize direction.
+ After: Their setup is a fast detector that hands off to a heavier model for a
+ closer read. That mirrors our own two-stage approach (find it first,
+ then work out what it is).
+
+Placement notes for your call:
+- Mode: I'd put it in GENERAL (applies in all three modes), because it's a
+ universal clarity rule in the Orwell / Plain English family, not a Craig-voice
+ quirk. It reads to anyone editing any prose.
+- Related but distinct from existing patterns: #7 (AI-vocab words) is about
+ which words; #30 (jargon-fragment) is about fragments. This one is about
+ jargon DENSITY per sentence and the reader's translation load. Worth a
+ cross-reference, not a merge.
+- Pairing rule: it needs the one-line Rule in SKILL.md AND a profile entry
+ (problem, basis, before/after, detection). The before/after above is ready.
+- The skill just went to 47 patterns (recipient-priority ordering added to
+ prose). This would be the next number in whatever scheme you're using.
+
+No rush. It came up drafting a customer-partner email tonight where one sentence
+stacked three terms and Craig flagged it. Applying it by hand worked; he wants it
+in the regular pass so it's caught automatically.
diff --git a/working/voice-term-density/skill.diff b/working/voice-term-density/skill.diff
new file mode 100644
index 0000000..56f8d0d
--- /dev/null
+++ b/working/voice-term-density/skill.diff
@@ -0,0 +1,58 @@
+--- voice/SKILL.md 2026-07-23 23:24:04.995899857 -0500
++++ /tmp/skill.proposed 2026-07-23 23:29:48.167295513 -0500
+@@ -1,7 +1,7 @@
+ ---
+ name: voice
+ description: |
+- Multi-pass prose editor with three modes. General mode (default) edits arbitrary writing — research notes, essays, anyone's README prose — by walking 31 patterns: Wikipedia's Signs of AI Writing patterns plus universal good-writing rules (long-word → short-word, active-over-passive, comma splices, cliché flag, jargon-fragment-in-prose rewrite, corporate-speak nominalizations). Prose mode adds Craig's writing-voice patterns for prose he authors or sends — emails, documents, notes — on top of general (em-dash zero-tolerance, no-emphasis-formatting, contractions, semicolons → periods, sentence-split, felt-experience cut, sentence-fragment rewrite, terse-cut, single-sentence cadence, parenthetical asides, declarative-register marker). Personal mode is for publish artifacts only (commits, PR titles + bodies, PR review comments) and adds the artifact-mechanics patterns on top of prose (first-person rewrite, public-artifact scope flag, praise/correction asymmetry, finding stems, comma budget) plus per-artifact terseness budgets. Prose mode also carries one correspondence-only pattern (recipient-priority ordering) that personal mode skips. Total 47 patterns; one editorial review covers all relevant ones for the chosen mode, with an attestation receipt for the high-recurrence set. Replaces the standalone humanizer skill. Use when editing prose. Do NOT use for code, structured data, or plain bullet lists where fragments are valid.
++ Multi-pass prose editor with three modes. General mode (default) edits arbitrary writing — research notes, essays, anyone's README prose — by walking 32 patterns: Wikipedia's Signs of AI Writing patterns plus universal good-writing rules (long-word → short-word, active-over-passive, comma splices, cliché flag, jargon-fragment-in-prose rewrite, corporate-speak nominalizations, term-translation density). Prose mode adds Craig's writing-voice patterns for prose he authors or sends — emails, documents, notes — on top of general (em-dash zero-tolerance, no-emphasis-formatting, contractions, semicolons → periods, sentence-split, felt-experience cut, sentence-fragment rewrite, terse-cut, single-sentence cadence, parenthetical asides, declarative-register marker). Personal mode is for publish artifacts only (commits, PR titles + bodies, PR review comments) and adds the artifact-mechanics patterns on top of prose (first-person rewrite, public-artifact scope flag, praise/correction asymmetry, finding stems, comma budget) plus per-artifact terseness budgets. Prose mode also carries one correspondence-only pattern (recipient-priority ordering) that personal mode skips. Total 48 patterns; one editorial review covers all relevant ones for the chosen mode, with an attestation receipt for the high-recurrence set. Replaces the standalone humanizer skill. Use when editing prose. Do NOT use for code, structured data, or plain bullet lists where fragments are valid.
+ allowed-tools:
+ - Read
+ - Write
+@@ -30,9 +30,9 @@
+
+ Three modes determine which patterns to walk. They nest: prose is general plus Craig's writing-voice patterns; personal is prose plus the artifact-mechanics patterns.
+
+-- **General** (default) — apply patterns **#1-31**. Use for writing whose author isn't Craig and that isn't a publish artifact: research notes you're editing for someone else, a quoted passage, README prose for a shared project, any third-party text. Output is well-edited human-sounding prose, but does not impose Craig's voice (first-person, contractions, em-dash elimination) — those conflict with academic, literary, or formal registers that aren't his.
++- **General** (default) — apply patterns **#1-31** and **#48** (term-translation density, a universal clarity rule that happens to carry a later number). Use for writing whose author isn't Craig and that isn't a publish artifact: research notes you're editing for someone else, a quoted passage, README prose for a shared project, any third-party text. Output is well-edited human-sounding prose, but does not impose Craig's voice (first-person, contractions, em-dash elimination) — those conflict with academic, literary, or formal registers that aren't his.
+ - **Prose** — apply **#1-31** plus the patterns tagged **(prose + personal)**: em-dash zero-tolerance (#13), contractions (#34), semicolons → periods (#33), sentence-split (#35), felt-experience cut (#36), sentence-fragment rewrite (#37), terse-cut (#38), no-emphasis-formatting (#41), single-sentence cadence (#43), parenthetical asides (#44), and the declarative-register marker (#45) — plus **#47 (recipient-priority ordering)** when the piece is correspondence (email, Signal, a letter). Use for prose Craig authors or sends in his own voice that isn't a publish artifact: emails, documents he writes or hands to someone, working notes, journal entries. This is the mode that finally applies his actual writing voice to the documents he most wants it on. It skips the artifact-mechanics patterns (#32, #39, #40, #42) — those assume a commit or PR and misfire on free prose (a document is legitimately third-person; a journal has no public-scope concern; praise/correction asymmetry and finding stems are PR-review rules).
+-- **Personal** — apply **#1-46**. Use only for publish artifacts: commits, PR titles + bodies, and PR review comments. Adds the artifact-mechanics patterns (#32 first-person rewrite, #39 public-artifact scope flag, #40 praise/correction asymmetry, #42 finding stems, #46 comma budget) on top of everything prose mode walks. #47 is the lone exception to the nesting — it is correspondence-only, and a publish artifact is never a reply to someone's news, so personal mode stops at #46.
++- **Personal** — apply **#1-46** and **#48**. Use only for publish artifacts: commits, PR titles + bodies, and PR review comments. Adds the artifact-mechanics patterns (#32 first-person rewrite, #39 public-artifact scope flag, #40 praise/correction asymmetry, #42 finding stems, #46 comma budget) on top of everything prose mode walks. #47 is the lone exception to the nesting — it is correspondence-only, and a publish artifact is never a reply to someone's news, so personal mode stops at #46.
+
+ If invoked without a mode argument, default to general. Prose mode is invoked explicitly with `/voice prose` (emails, authored documents). Personal-context callers (`commits.md` publish flow, `respond-to-cj-comments.md`) invoke `/voice personal`.
+
+@@ -53,7 +53,7 @@
+
+ When given text to edit:
+
+-1. **Identify which patterns apply** — Scan for the patterns numbered below. General mode walks #1-31 only. Prose mode adds the patterns tagged **(prose + personal)**, plus #47 when the piece is correspondence. Personal mode adds the **(personal only)** ones instead — patterns #1-46, never #47.
++1. **Identify which patterns apply** — Scan for the patterns numbered below. General mode walks #1-31 and #48. Prose mode adds the patterns tagged **(prose + personal)**, plus #47 when the piece is correspondence. Personal mode adds the **(personal only)** ones instead — patterns #1-46 and #48, never #47.
+ 2. **Rewrite problematic sections** — Replace each detected pattern with its rewrite.
+ 3. **Preserve meaning** — Keep the core message intact.
+ 4. **Maintain voice** — Match the intended tone (formal, casual, technical, academic, literary).
+@@ -394,10 +394,16 @@
+
+ See `voice/references/voice-profile.org` §47 for problem, basis, examples, and history.
+
++### 48. Term-Translation Density [general]
++
++**Rule.** A sentence that forces the reader to stop and translate more than one specialized term (an acronym, a coined phrase, a product name) is too dense. One such term is fine; two or more in one sentence means rewrite it: split the sentence, gloss one term inline in a parenthetical (#44), or drop to plain language. The test is the reader's parse, not the writer's familiarity, and it is audience-relative — a term the whole audience shares (SAR to a defense team) carries no translation load, while a term only the writer holds (a coined "detect-then-contextualize", or ViT and VLM stacked in one clause) does. Distinct from #7 (which flags specific AI-vocabulary words) and #30 (which rewrites telegraphic fragments): this one measures jargon density per sentence against the reader's translation load.
++
++See `voice/references/voice-profile.org` §48 for problem, basis, examples, and history.
++
+ ## Process
+
+ 1. Read the input text carefully. Confirm the mode (general, prose, or personal) — invocation argument or context. If a file path was given, that file is the deliverable: the final text gets written back to it in step 7.
+-2. Walk patterns 1-31 in general mode; add the (prose + personal) patterns in prose mode, plus #47 when the piece is correspondence; walk patterns 1-46 in personal mode.
++2. Walk patterns 1-31 and 48 in general mode; add the (prose + personal) patterns in prose mode, plus #47 when the piece is correspondence; walk patterns 1-46 and 48 in personal mode.
+ 3. For each pattern, scan the text. If a match is found, rewrite it according to the pattern's rule. Patterns #39 and #45 emit flags without rewriting.
+ 4. After walking all patterns, ensure the revised text:
+ - Sounds natural when read aloud
+@@ -495,6 +501,7 @@
+ - Craig's voice rules from `claude-rules/commits.md` (Voice and Focus section) — patterns #32-42, split across prose mode (his authored prose and email) and personal mode (publish artifacts).
+ - Craig's directive, 2026-07-20 (archsetup session) — pattern #46 (comma budget), personal mode.
+ - Craig's edit of a Signal reply, 2026-07-23 (home session) — pattern #47 (recipient-priority ordering) and the #43 topic-vs-angle calibration, prose/correspondence.
++- Craig's edit of a customer-partner email, 2026-07-23 (work session) — pattern #48 (term-translation density), general.
+ - Corpus measurement (2026-05-29 phases 1-2, documented in the profile) — patterns #43-45 and the calibration notes on #7, #13, #33.
+
+ Key insight (Wikipedia, paraphrased): LLMs use statistical algorithms to guess what should come next. The result tends toward the most statistically likely text that applies to the widest variety of cases. Patterns #1-25 detect that signature.
diff --git a/working/voice-term-density/voice-profile.org.proposed b/working/voice-term-density/voice-profile.org.proposed
new file mode 100644
index 0000000..7f26c03
--- /dev/null
+++ b/working/voice-term-density/voice-profile.org.proposed
@@ -0,0 +1,1643 @@
+#+TITLE: Voice Profile: canonical source-of-truth for the voice skill
+#+DATE: 2026-05-29
+#+SOURCE: rulesets session 2026-05-29
+
+* How this combines with SKILL.md (pairing rule)
+
+This file is the canonical source-of-truth for the voice skill's rationale, evidence, examples, and history. =voice/SKILL.md= holds the thin rule-set: one-line directives per pattern, mode applicability, and a pointer back here. Everything else (Problem, Basis, Before/After, Detection guidance, History) lives in the per-pattern sections below.
+
+Pairing rule. Every change to =voice/SKILL.md= MUST land alongside the corresponding update in this file. The two are normatively paired. A SKILL.md edit without a profile update is incomplete. A profile update without a SKILL.md edit is fine (rationale or evidence can deepen without changing the rule).
+
+Pattern numbering in both files matches: SKILL.md's =### N. <Name>= maps to this file's =* §N <Name>= section. Mode tags use the same vocabulary: =general=, =prose=, =personal=.
+
+When the agent runs =/voice=, it reads SKILL.md for the rules and consults this file for the examples and basis it needs to apply each pattern correctly.
+
+* Corpus
+
+** Phase 1 (2026-05-29): git commit bodies
+
+Git commit bodies authored by Craig Jennings across all repos under =~/code/= and =~/projects/=. After cleanup (subject lines, trailers, URL-only lines, AI-attribution lines, blank-run collapse):
+
+- 5355 raw commits, 1895 with non-trivial bodies
+- 128608 words, 912400 characters
+- 33 repos contributing; top sources: archsetup (703), rulesets (621), work (565), archangel (455), home (395)
+
+One register (deliberate technical prose). The view is useful but narrow on its own.
+
+** Phase 2 (2026-05-29): email + GitHub PR bodies + PR review comments
+
+Four sub-corpora added so the rules can be tested across registers.
+
+- *Personal email* (gmail + cmail, sent-only, body ≥50 words after cleanup): 1139 messages, 283,092 words.
+- *Work email* (dmail, same filter): 22 messages, 3910 words. Small sample.
+- *PR descriptions* (github.com, author cjennings, body ≥100 chars after cleanup): 9 PRs, 1613 words. Small sample.
+- *PR review comments* (github.com, author cjennings, ≥20 words): 3 comments, 256 words. Tiny sample. Public GHE work isn't in this index.
+
+Signatures, quoted replies, and forwarded blocks stripped before analysis. Stats streamed; no corpus files written to disk.
+
+** Cross-register findings (the key result of Phase 2)
+
+The most important Phase 2 result is that *register splits matter*. Phase 1's signal from commit prose does not generalize cleanly to conversational prose.
+
+| Metric (per 1000 words) | Commits | Personal email | Work email | PR bodies | PR comments |
+|--------------------------+---------+----------------+------------+-----------+-------------|
+| Em-dash | 3.49 | 0.28 | 2.05 | 0.62 | 0.00 |
+| Semicolon | 3.16 | 0.64 | 0.26 | 0.62 | 0.00 |
+| Contractions | 3.57 | 38.52 | 28.13 | 17.36 | 50.78 |
+| Standalone "I" | 3.85 | 36.91 | 23.79 | 8.68 | 42.97 |
+| "we" | 0.22 | 8.18 | 14.83 | 1.24 | 0.00 |
+| "I'm" | 0.07 | 6.04 | 3.58 | 1.24 | 7.81 |
+
+Three observations:
+
+1. Em-dashes and semicolons are concentrated in commit prose, not conversational prose. The personal-mode rules on those (§13 and §33) hold up under Phase 2, but the basis shifts: the rules mostly enforce what is already true for email and PR comments. Commit prose is the outlier register that needs the rule, not the universal pattern.
+2. Contractions invert. Commits suppress contractions; email and PR-review prose use them heavily (38 to 50 per 1000). The Phase 1 contraction rule (§34) is strongly confirmed in the registers where contractions are most expected.
+3. The Phase 1 curiosity (I'm/I'll surprisingly rare relative to standalone "I") was a register effect, not a personal preference. In personal email, "I'm" runs 6.04 per 1000 vs standalone I at 36.91 — ratio close to natural English. Commit prose is the outlier where "I am" beats "I'm".
+
+AI-writing tells stay near zero across all five corpora. "leverage" surfaces 18 times in personal email (0.064 per 1000) — small but the only non-zero hit on the watch-list outside commits. All other watch-words clock 0 to 4 per corpus.
+
+* Findings against the 41 SKILL.md patterns
+
+** Strongly confirmed by the corpus
+
+*Pattern 17 (no emojis).* Zero emojis in corpus. Confirmed.
+
+*Pattern 7 (AI vocabulary).* "delve" 0. "embark" 0. "navigate the" 0. "in the realm of" 0. "seamless" 0. "moreover" 0. "furthermore" 0. "in conclusion" 0. "additionally" 1. "robust" 1. "leverage" 1. Rule confirmed for 11 of 12 watch-words. (One exception below.)
+
+*Pattern 22 (filler).* "moreover" / "furthermore" / "additionally" / "in conclusion": all zero or one occurrence. Filler-phrase avoidance confirmed.
+
+*Pattern 32 (first-person rewrite).* Standalone "I" at 3.85 per 1000 words. Craig writes first-person heavily. This is real, not aspirational.
+
+*Pattern 34 (contractions).* 459 contractions total (3.57 per 1000). Top hits: =doesn't= (92), =don't= (59), =isn't= (46), =it's= (43), =can't= (40), =that's= (34). Rule confirmed.
+
+*Pattern 38 (terse cut).* 41.1% of paragraphs are single-sentence. Craig writes terse. Paragraph breaks land after one complete thought even when short. Confirmed indirectly via paragraph structure.
+
+** Aspirational (corpus contradicts, but the rule is intentional self-discipline)
+
+*Pattern 13 (em-dash zero-tolerance, personal mode).* Corpus rate: 3.49 em-dashes per 1000 words. Comparable to AI-generated prose. Craig USES em-dashes regularly in commit bodies. The rule overrides his habit, it doesn't reflect it. Suggested rewording: drop the "LLMs use em dashes more than humans" framing; keep the zero-tolerance directive but rationale becomes "Craig's published voice (commit messages going forward, PR bodies, emails) drops em-dashes by choice because it reads cleaner and avoids a common AI tell, regardless of his pre-rule habit." Honest about the source.
+
+*Pattern 33 (semicolons → period/comma).* Corpus rate: 3.16 semicolons per 1000. Craig uses semicolons regularly. Same shape as #13: rule is self-discipline, not habit-reflection. Suggested rewording: acknowledge the rule overrides habit rather than implying it codifies one.
+
+These two rules are still valuable. Em-dashes and semicolons both read cleaner when absent from short imperative-leaning prose. But the SKILL.md should say "this is a rule I've decided to follow," not "this is how I already write."
+
+** Worth challenging
+
+*Pattern 7 watch-word "comprehensive".* 42 occurrences in corpus (~0.33 per 1000). All other AI-tell watch-words clock near zero. "comprehensive" appears to be genuine vocabulary for Craig in technical contexts ("comprehensive test coverage", "comprehensive audit"). Suggested change: pull "comprehensive" out of the watch-list, or carve out a "watch in clusters, not solo" note that flags only when "comprehensive" co-occurs with other AI-tell words.
+
+** Worth adding (corpus surfaces traits the rules don't capture)
+
+*Single-sentence paragraph cadence.* 41.1% of paragraphs are exactly one sentence. This is distinctive. Most prose-style guides advise multi-sentence paragraphs. Suggested addition (prose + personal): a positive pattern noting "a one-sentence paragraph is a finished thought, not a fragment. Break paragraphs after one complete thought when the next thought shifts angle, even if both are short." Anti-rule against "merge short paragraphs into multi-sentence ones."
+
+*Parenthetical density.* 23.07 opening parens per 1000 words. Heavy parenthetical use covers asides, clarifications, and scope-narrowing in parens. Currently no rule addresses this either way. Could add a positive pattern: "parentheses for asides are part of the voice. Don't strip them in a 'clean prose' pass."
+
+*Question-mark rarity.* 0.33 per 1000. Craig's prose is declarative. He states things, rarely asks them. Worth noting as a register marker (when /voice personal output has questions, double-check whether they're contextual or AI rhetoric).
+
+** Out of corpus (commits don't test these, Phase 2 needed)
+
+- *Pattern 13 in long-form prose.* Commit bodies are short. Email and PR bodies may show different em-dash rates.
+- *Pattern 14 (boldface).* Org-mode bold uses =*word*=, not detectable by simple grep. Markdown bold rare in commits.
+- *Pattern 16 (title case in headings).* Commits don't carry headings.
+- *Pattern 19 (collaborative artifacts).* Not present in commit bodies.
+- *Pattern 35 (sentence split on conjunctions).* Average sentence is 18.81 words, median 14, with 28% of sentences 21+ words. Long-sentence rate is moderate. Need to inspect actual sentences to know if they're conjunction-stitched. Defer.
+- *Pattern 36 (felt-experience cut).* Commit bodies wouldn't carry felt-experience prose. Email + journal corpus needed.
+- *Pattern 37 (sentence fragments).* 9.7% of sentences are 1-5 words. Some are legitimate ("All eight pass."), some may be fragments. Can't tell from word-count alone. Defer to a pass that does syntactic detection.
+- *Pattern 39 (public-artifact scope).* The corpus IS the public artifacts. The check is circular. Defer.
+- *Pattern 40 (praise vs correction asymmetry).* Not detectable in commit bodies. Email or PR-review corpus needed.
+
+** Curiosities (resolved by Phase 2)
+
+- *=I'm=* (9 occurrences) and *=I'll=* (2 occurrences) were surprisingly rare in Phase 1 relative to standalone =I= (495 occurrences). Phase 2 resolved this. Personal email shows I'm at 1710 occurrences (6.04 per 1000), I'll at 865 (3.06), I've at 458 (1.62), I'd at 384 (1.36). The Phase 1 rarity was a register effect, not a personal preference. Commit prose uniquely suppresses contractions; conversational prose runs them at near-natural English rate.
+
+* Suggested deltas
+
+*All six deltas landed 2026-06-10* via the voice-skill revision from the work-project session: 1 and 2 are in the §13/§33 rule lines and entries, 3 is the §7 soft-flag, 4-6 became patterns §43-§45. The list is kept as the record of what was proposed on 2026-05-29.
+
+Six concrete edits to =voice/SKILL.md=, all of which can land independently:
+
+1. *#13 (Em-Dash).* Drop the "LLMs use em dashes more than humans" framing in the personal-mode section. Restate the zero-tolerance rule as self-discipline ("Craig's published voice drops em-dashes by choice"), not habit-reflection. Cite: corpus rate 3.49/1000, AI-comparable.
+
+2. *#33 (Semicolons).* Same shape. Restate as self-discipline. Cite: corpus rate 3.16/1000.
+
+3. *#7 (AI Vocabulary).* Remove "comprehensive" from the watch-list, OR add a note that "comprehensive" alone is acceptable; flag only when it co-occurs with =delve= / =leverage= / =robust= / =seamless= / =moreover= etc. Cite: 42 occurrences, all other watch-words at 0 or 1.
+
+4. *NEW pattern (prose + personal): "Single-sentence paragraph cadence is a feature."* 41.1% of corpus paragraphs are exactly one sentence. A one-sentence paragraph is a finished thought, not a fragment. The voice pass should not merge short paragraphs into multi-sentence ones.
+
+5. *NEW pattern (prose + personal): "Parentheses for asides are part of the voice."* 23 opening parens per 1000 words. Heavy parenthetical use is distinctive. Don't strip parenthetical asides in a "clean prose" pass.
+
+6. *Register marker (advisory, not a rewrite rule): "Declarative is the default."* 0.33 question marks per 1000. Voice personal output that contains rhetorical questions should be checked. They're often AI rhetoric, not Craig's register.
+
+* What Phase 2 would add
+
+- Email corpus (gmail + cmail, sent-only, long-form): different register, especially long-form prose flow.
+- PR bodies and review comments: longer prose, deliberate register, includes the praise/correction asymmetry test ground.
+- Slack messages: casual register, contraction rate, sentence-fragment rate.
+- Syntactic detection: distinguish fragments from terse complete sentences for pattern #37.
+- Long-form documents (résumé, proposals if any): single register but high prose density.
+
+* Per-pattern entries
+
+All patterns are entered below per the pairing rule above, §1 through §45, matching SKILL.md's numbering.
+
+** §1 Undue Emphasis on Significance, Legacy, and Broader Trends
+
+*** Modes
+General mode only. Prose and personal inherit it.
+
+*** Rule
+Strip statements that puff up importance by claiming an arbitrary aspect represents or contributes to a broader trend. Watch for phrases like "stands as", "serves as", "testament to", "vital role", "pivotal moment", "evolving landscape", "marks a shift", "reflects broader", "setting the stage for", "indelible mark", "deeply rooted". Replace with a concrete fact or cut the sentence entirely.
+
+*** Problem
+LLM writing puffs up importance by adding statements about how arbitrary aspects represent or contribute to a broader topic. Watch-list words: stands/serves as, is a testament/reminder, a vital/significant/crucial/pivotal/key role/moment, underscores/highlights its importance/significance, reflects broader, symbolizing its ongoing/enduring/lasting, contributing to the, setting the stage for, marking/shaping the, represents/marks a shift, key turning point, evolving landscape, focal point, indelible mark, deeply rooted.
+
+*** Basis
+Observation-derived (Wikipedia "Signs of AI Writing").
+
+*** Before
+#+begin_example
+The Statistical Institute of Catalonia was officially established in 1989, marking a pivotal moment in the evolution of regional statistics in Spain. This initiative was part of a broader movement across Spain to decentralize administrative functions and enhance regional governance.
+#+end_example
+
+*** After
+#+begin_example
+The Statistical Institute of Catalonia was established in 1989 to collect and publish regional statistics independently from Spain's national statistics office.
+#+end_example
+
+*** History
+- Original SKILL.md entry: significance and broader-trend puffery, with watch-list phrases drawn from Wikipedia's AI-writing guide.
+- 2026-05-29: migrated to this file as the canonical home per the pairing rule.
+
+** §2 Undue Emphasis on Notability and Media Coverage
+
+*** Modes
+General mode only. Prose and personal inherit it.
+
+*** Rule
+Cut notability claims that list sources without giving the substance. Replace "cited in The New York Times, BBC, Financial Times" with the actual argument made in one of them.
+
+*** Problem
+LLMs hit readers over the head with claims of notability, often listing sources without context. Watch-list words: independent coverage, local/regional/national media outlets, written by a leading expert, active social media presence.
+
+*** Basis
+Observation-derived (Wikipedia "Signs of AI Writing").
+
+*** Before
+#+begin_example
+Her views have been cited in The New York Times, BBC, Financial Times, and The Hindu. She maintains an active social media presence with over 500,000 followers.
+#+end_example
+
+*** After
+#+begin_example
+In a 2024 New York Times interview, she argued that AI regulation should focus on outcomes rather than methods.
+#+end_example
+
+*** History
+- Original SKILL.md entry: notability inflation through bare source lists.
+- 2026-05-29: migrated to this file as the canonical home per the pairing rule.
+
+** §3 Superficial Analyses with -ing Endings
+
+*** Modes
+General mode only. Prose and personal inherit it.
+
+*** Rule
+Cut tacked-on present-participle phrases (highlighting, underscoring, emphasizing, ensuring, reflecting, symbolizing, contributing to, cultivating, fostering, encompassing, showcasing) that add fake depth without new information.
+
+*** Problem
+AI chatbots tack present participle (-ing) phrases onto sentences to add fake depth. Watch-list words: highlighting, underscoring, emphasizing, ensuring, reflecting, symbolizing, contributing to, cultivating, fostering, encompassing, showcasing.
+
+*** Basis
+Observation-derived (Wikipedia "Signs of AI Writing").
+
+*** Before
+#+begin_example
+The temple's color palette of blue, green, and gold resonates with the region's natural beauty, symbolizing Texas bluebonnets, the Gulf of Mexico, and the diverse Texan landscapes, reflecting the community's deep connection to the land.
+#+end_example
+
+*** After
+#+begin_example
+The temple uses blue, green, and gold colors. The architect said these were chosen to reference local bluebonnets and the Gulf coast.
+#+end_example
+
+*** History
+- Original SKILL.md entry: -ing phrase tacking for fake analytical depth.
+- 2026-05-29: migrated to this file as the canonical home per the pairing rule.
+
+** §4 Promotional and Advertisement-like Language
+
+*** Modes
+General mode only. Prose and personal inherit it.
+
+*** Rule
+Remove travel-brochure adjectives (vibrant, breathtaking, nestled, stunning, renowned, must-visit, profound, rich figurative use) and replace promotional framing with concrete facts about the subject.
+
+*** Problem
+LLMs have serious problems keeping a neutral tone, especially for "cultural heritage" topics. Watch-list words: boasts a, vibrant, rich (figurative), profound, enhancing its, showcasing, exemplifies, commitment to, natural beauty, nestled, in the heart of, groundbreaking (figurative), renowned, breathtaking, must-visit, stunning.
+
+*** Basis
+Observation-derived (Wikipedia "Signs of AI Writing").
+
+*** Before
+#+begin_example
+Nestled within the breathtaking region of Gonder in Ethiopia, Alamata Raya Kobo stands as a vibrant town with a rich cultural heritage and stunning natural beauty.
+#+end_example
+
+*** After
+#+begin_example
+Alamata Raya Kobo is a town in the Gonder region of Ethiopia, known for its weekly market and 18th-century church.
+#+end_example
+
+*** History
+- Original SKILL.md entry: travel-brochure adjective patterns.
+- 2026-05-29: migrated to this file as the canonical home per the pairing rule.
+
+** §5 Vague Attributions and Weasel Words
+
+*** Modes
+General mode only. Prose and personal inherit it.
+
+*** Rule
+Replace vague attributions (experts say, observers have cited, industry reports, some critics argue, several sources) with a named source plus the specific claim made.
+
+*** Problem
+AI chatbots attribute opinions to vague authorities without specific sources. Watch-list words: Industry reports, Observers have cited, Experts argue, Some critics argue, several sources or publications (when few cited).
+
+*** Basis
+Observation-derived (Wikipedia "Signs of AI Writing").
+
+*** Before
+#+begin_example
+Due to its unique characteristics, the Haolai River is of interest to researchers and conservationists. Experts believe it plays a crucial role in the regional ecosystem.
+#+end_example
+
+*** After
+#+begin_example
+The Haolai River supports several endemic fish species, according to a 2019 survey by the Chinese Academy of Sciences.
+#+end_example
+
+*** History
+- Original SKILL.md entry: vague-authority attribution patterns.
+- 2026-05-29: migrated to this file as the canonical home per the pairing rule.
+
+** §6 Outline-like "Challenges and Future Prospects" Sections
+
+*** Modes
+General mode only. Prose and personal inherit it.
+
+*** Rule
+Delete formulaic "Despite its prosperity, X faces challenges" wrap-ups and "Future Outlook" boilerplate. Replace with the actual events that happened or omit the section.
+
+*** Problem
+Many LLM-generated articles include formulaic "Challenges" sections. Watch-list words: "Despite its... faces several challenges...", "Despite these challenges", "Challenges and Legacy", "Future Outlook".
+
+*** Basis
+Observation-derived (Wikipedia "Signs of AI Writing").
+
+*** Before
+#+begin_example
+Despite its industrial prosperity, Korattur faces challenges typical of urban areas, including traffic congestion and water scarcity. Despite these challenges, with its strategic location and ongoing initiatives, Korattur continues to thrive as an integral part of Chennai's growth.
+#+end_example
+
+*** After
+#+begin_example
+Traffic congestion increased after 2015 when three new IT parks opened. The municipal corporation began a stormwater drainage project in 2022 to address recurring floods.
+#+end_example
+
+*** History
+- Original SKILL.md entry: outline-template "Challenges and Future Prospects" sections.
+- 2026-05-29: migrated to this file as the canonical home per the pairing rule.
+
+** §7 Overused "AI Vocabulary" Words
+
+*** Modes
+General mode only. Prose and personal inherit it.
+
+*** Rule
+Flag and rewrite around the high-frequency AI vocabulary list. Watch-list words: Additionally, align with, comprehensive, crucial, delve, emphasizing, enduring, enhance, fostering, garner, highlight (verb), interplay, intricate or intricacies, key (adjective), landscape (abstract noun), pivotal, showcase, tapestry (abstract noun), testament, underscore (verb), valuable, vibrant. "comprehensive" is a soft flag because the corpus shows it as genuine Craig vocabulary he chooses to use sparingly. Suggest an alternative ("full", "complete", "thorough", or rewording to drop the adjective) and let Craig decide per instance.
+
+*** Problem
+These words appear far more frequently in post-2023 text. They often co-occur.
+
+*** Basis
+Corpus-measured across registers (2026-05-29). Phase 1 git commits: "comprehensive" 42 occurrences, every other watch-word 0 or 1. Phase 2 conversational and PR corpora: "comprehensive" 1 in personal email, 0 in work email, PR descriptions, and PR review comments. "leverage" 18 in personal email, 0 to 1 elsewhere. Every other watch-word stays at 0 to 4 across all five corpora.
+
+Two takeaways. First, "comprehensive" is concentrated in commit prose (technical-doc register: "comprehensive test coverage", "comprehensive audit") and almost absent from conversational prose. Craig has chosen to keep it on the watch-list because he is consciously trying to use it sparingly. Second, "leverage" earns a soft watch in personal email even though the rest of the list stays clean. The two together suggest the rule should flag-and-suggest individual hits in technical prose without treating any single watch-word as automatic disqualification.
+
+*** Before
+#+begin_example
+Additionally, a distinctive feature of Somali cuisine is the incorporation of camel meat. An enduring testament to Italian colonial influence is the widespread adoption of pasta in the local culinary landscape, showcasing how these dishes have integrated into the traditional diet.
+#+end_example
+
+*** After
+#+begin_example
+Somali cuisine also includes camel meat, which is considered a delicacy. Pasta dishes, introduced during Italian colonization, remain common, especially in the south.
+#+end_example
+
+*** History
+- Original SKILL.md entry: high-frequency post-2023 AI vocabulary list.
+- 2026-05-29 (commit =c3cf9a5=): note on "comprehensive" added with corpus measurement and soft-flag guidance.
+- 2026-05-29: migrated to this file as the canonical home per the pairing rule.
+
+** §8 Avoidance of "is"/"are" (Copula Avoidance)
+
+*** Modes
+General mode only. Prose and personal inherit it.
+
+*** Rule
+Replace elaborate copula substitutes (serves as, stands as, marks, represents, boasts, features, offers) with plain "is" or "has".
+
+*** Problem
+LLMs substitute elaborate constructions for simple copulas. Watch-list words: serves as, stands as, marks, represents (a), boasts, features, offers (a).
+
+*** Basis
+Observation-derived (Wikipedia "Signs of AI Writing").
+
+*** Before
+#+begin_example
+Gallery 825 serves as LAAA's exhibition space for contemporary art. The gallery features four separate spaces and boasts over 3,000 square feet.
+#+end_example
+
+*** After
+#+begin_example
+Gallery 825 is LAAA's exhibition space for contemporary art. The gallery has four rooms totaling 3,000 square feet.
+#+end_example
+
+*** History
+- Original SKILL.md entry: copula avoidance patterns.
+- 2026-05-29: migrated to this file as the canonical home per the pairing rule.
+
+** §9 Negative Parallelisms
+
+*** Modes
+General mode only. Prose and personal inherit it.
+
+*** Rule
+Rewrite "not only X but Y" and "it's not just about X, it's Y" constructions as a single direct claim.
+
+*** Problem
+Constructions like "Not only...but..." or "It's not just about..., it's..." are overused as a way to claim depth.
+
+*** Basis
+Observation-derived (Wikipedia "Signs of AI Writing").
+
+*** Before
+#+begin_example
+It's not just about the beat riding under the vocals; it's part of the aggression and atmosphere. It's not merely a song, it's a statement.
+#+end_example
+
+*** After
+#+begin_example
+The heavy beat adds to the aggressive tone.
+#+end_example
+
+*** History
+- Original SKILL.md entry: negative-parallelism stock phrasing.
+- 2026-05-29: migrated to this file as the canonical home per the pairing rule.
+
+** §10 Rule of Three Overuse
+
+*** Modes
+General mode only. Prose and personal inherit it.
+
+*** Rule
+Break the reflexive three-item list pattern when the third item is filler. Collapse to one or two specific items.
+
+*** Problem
+LLMs force ideas into groups of three to appear comprehensive. The third item is usually filler chosen to fit the cadence, not because it adds substance.
+
+*** Basis
+Observation-derived (Wikipedia "Signs of AI Writing").
+
+*** Before
+#+begin_example
+The event features keynote sessions, panel discussions, and networking opportunities. Attendees can expect innovation, inspiration, and industry insights.
+#+end_example
+
+*** After
+#+begin_example
+The event includes talks and panels. There's also time for informal networking between sessions.
+#+end_example
+
+*** History
+- Original SKILL.md entry: rule-of-three cadence overuse.
+- 2026-05-29: migrated to this file as the canonical home per the pairing rule.
+
+** §11 Elegant Variation (Synonym Cycling)
+
+*** Modes
+General mode only. Prose and personal inherit it.
+
+*** Rule
+Stop cycling synonyms for the same referent across consecutive sentences. Repeat the noun, or merge the sentences.
+
+*** Problem
+AI has repetition-penalty code causing excessive synonym substitution. The protagonist becomes the main character becomes the central figure becomes the hero, all referring to the same person.
+
+*** Basis
+Observation-derived (Wikipedia "Signs of AI Writing").
+
+*** Before
+#+begin_example
+The protagonist faces many challenges. The main character must overcome obstacles. The central figure eventually triumphs. The hero returns home.
+#+end_example
+
+*** After
+#+begin_example
+The protagonist faces many challenges but eventually triumphs and returns home.
+#+end_example
+
+*** History
+- Original SKILL.md entry: elegant-variation synonym cycling driven by repetition penalty.
+- 2026-05-29: migrated to this file as the canonical home per the pairing rule.
+
+** §12 False Ranges
+
+*** Modes
+General mode only. Prose and personal inherit it.
+
+*** Rule
+Rewrite "from X to Y" constructions where X and Y are not on the same scale. List the items plainly instead.
+
+*** Problem
+LLMs use "from X to Y" constructions where X and Y are not on a meaningful scale ("from the Big Bang to dark matter") to imply comprehensive sweep.
+
+*** Basis
+Observation-derived (Wikipedia "Signs of AI Writing").
+
+*** Before
+#+begin_example
+Our journey through the universe has taken us from the singularity of the Big Bang to the grand cosmic web, from the birth and death of stars to the enigmatic dance of dark matter.
+#+end_example
+
+*** After
+#+begin_example
+The book covers the Big Bang, star formation, and current theories about dark matter.
+#+end_example
+
+*** History
+- Original SKILL.md entry: false-range "from X to Y" constructions.
+- 2026-05-29: migrated to this file as the canonical home per the pairing rule.
+
+** §13 Em Dash Overuse
+
+*** Modes
+General mode: overuse-reduction.
+Prose + personal modes: zero-tolerance.
+
+*** Rule
+Replace em-dashes (=—=) with a comma, period, colon, or parentheses, whichever fits. Zero-tolerance in prose and personal modes holds *everywhere in the text*, including inside example blocks, code-fence prose, and quoted material. An em-dash in a quoted line still gets replaced.
+
+*** Problem
+Craig's published voice drops em-dashes by choice: they read cleaner absent from short imperative-leaning prose and their overuse is a common AI tell (LLMs use em dashes more than the median human writer, mimicking "punchy" sales writing). The rule is chosen self-discipline, not a reflection of his pre-rule habit — the corpus shows he used them regularly in commit bodies.
+
+*** Basis
+Phase 1 corpus (git commits, 128k words): 3.49 em-dashes per 1000 words. Comparable to AI-generated prose. Phase 2 corpus reveals a sharp register split: personal email 0.28 per 1000, work email 2.05, PR descriptions 0.62, PR review comments 0.00. Em-dashes are concentrated in commit prose, almost absent from email and PR review prose. The zero-tolerance rule in prose and personal modes mostly enforces what is already true for non-commit registers. The rule still earns its place because commit prose is the high-volume register where the AI-tell em-dash habit shows up. Self-discipline, not habit-reflection, for the commit register specifically.
+
+*** Before
+#+begin_example
+The term is primarily promoted by Dutch institutions—not by the people themselves. You don't say "Netherlands, Europe" as an address—yet this mislabeling continues—even in official documents.
+#+end_example
+
+*** After
+#+begin_example
+The term is primarily promoted by Dutch institutions, not by the people themselves. You don't say "Netherlands, Europe" as an address, yet this mislabeling continues in official documents.
+#+end_example
+
+*** History
+- Original SKILL.md entry: rule scoped to general overuse-reduction.
+- 2026-05-26 (commit =4fac2a0=): prose mode added, rule strengthened to zero-tolerance in prose and personal.
+- 2026-05-29 (commit =c3cf9a5=): Note on basis added with corpus measurement.
+- 2026-05-29: migrated to this file as the canonical home per the pairing rule.
+- 2026-06-10: the self-discipline reframing (a "Suggested deltas" item from 2026-05-29, never applied) moved from the findings section into the entry proper and into the SKILL.md rule line. Craig's call, from the work-project session.
+
+** §14 Overuse of Boldface
+
+*** Modes
+General mode only. Prose and personal inherit it. Pattern §41 is the related Craig-voice rule covering emphasis-by-formatting in his authored prose.
+
+*** Rule
+Strip mechanical boldface used to call out terms, acronyms, or phrases in running prose. Bold survives only for structural emphasis the document genuinely needs.
+
+*** Problem
+AI chatbots emphasize phrases in boldface mechanically. Acronyms, names, and key terms get wrapped in bold even when the surrounding sentence already gives them stress.
+
+*** Basis
+Observation-derived (Wikipedia "Signs of AI Writing").
+
+*** Before
+#+begin_example
+It blends **OKRs (Objectives and Key Results)**, **KPIs (Key Performance Indicators)**, and visual strategy tools such as the **Business Model Canvas (BMC)** and **Balanced Scorecard (BSC)**.
+#+end_example
+
+*** After
+#+begin_example
+It blends OKRs, KPIs, and visual strategy tools like the Business Model Canvas and Balanced Scorecard.
+#+end_example
+
+*** History
+- Original SKILL.md entry: mechanical boldface around terms and acronyms.
+- 2026-05-29: migrated to this file as the canonical home per the pairing rule.
+
+** §15 Inline-Header Vertical Lists
+
+*** Modes
+General mode only. Prose and personal inherit it.
+
+*** Rule
+Collapse bullet lists whose items start with a bold header plus colon into running prose, unless the list structure is genuinely the right shape.
+
+*** Problem
+AI outputs lists where items start with bolded headers followed by colons, often when a paragraph would carry the same content more naturally.
+
+*** Basis
+Observation-derived (Wikipedia "Signs of AI Writing").
+
+*** Before
+#+begin_example
+- **User Experience:** The user experience has been significantly improved with a new interface.
+- **Performance:** Performance has been enhanced through optimized algorithms.
+- **Security:** Security has been strengthened with end-to-end encryption.
+#+end_example
+
+*** After
+#+begin_example
+The update improves the interface, speeds up load times through optimized algorithms, and adds end-to-end encryption.
+#+end_example
+
+*** History
+- Original SKILL.md entry: inline-header vertical list pattern.
+- 2026-05-29: migrated to this file as the canonical home per the pairing rule.
+
+** §16 Title Case in Headings
+
+*** Modes
+General mode only. Prose and personal inherit it.
+
+*** Rule
+Lowercase headings that are reflexively title-cased. Sentence case is the default unless the project's house style is title case.
+
+*** Problem
+AI chatbots capitalize all main words in headings even when the surrounding document uses sentence case.
+
+*** Basis
+Observation-derived (Wikipedia "Signs of AI Writing").
+
+*** Before
+#+begin_example
+## Strategic Negotiations And Global Partnerships
+#+end_example
+
+*** After
+#+begin_example
+## Strategic negotiations and global partnerships
+#+end_example
+
+*** History
+- Original SKILL.md entry: reflexive title-case in headings.
+- 2026-05-29: migrated to this file as the canonical home per the pairing rule.
+
+** §17 Emojis
+
+*** Modes
+General mode only. Prose and personal inherit it.
+
+*** Rule
+Remove decorative emojis from headings, bullets, and prose unless the document is a register where emoji is genuinely intended.
+
+*** Problem
+AI chatbots often decorate headings or bullet points with emojis to add visual structure that the prose itself does not need.
+
+*** Basis
+Corpus-measured: 2026-05-29 commit corpus shows zero emojis. The rule reflects established practice.
+
+*** Before
+#+begin_example
+🚀 **Launch Phase:** The product launches in Q3
+💡 **Key Insight:** Users prefer simplicity
+✅ **Next Steps:** Schedule follow-up meeting
+#+end_example
+
+*** After
+#+begin_example
+The product launches in Q3. User research showed a preference for simplicity. Next step: schedule a follow-up meeting.
+#+end_example
+
+*** History
+- Original SKILL.md entry: decorative emoji in headings and bullets.
+- 2026-05-29: migrated to this file as the canonical home per the pairing rule.
+
+** §18 Curly Quotation Marks
+
+*** Modes
+General mode only. Prose and personal inherit it.
+
+*** Rule
+Convert curly quotation marks to straight ASCII quotes.
+
+*** Problem
+ChatGPT uses curly quotes instead of straight quotes, which is a recognizable tell in technical and source-controlled writing.
+
+*** Basis
+Observation-derived (Wikipedia "Signs of AI Writing").
+
+*** Before
+#+begin_example
+He said “the project is on track” but others disagreed.
+#+end_example
+
+*** After
+#+begin_example
+He said "the project is on track" but others disagreed.
+#+end_example
+
+*** History
+- Original SKILL.md entry: curly-quote substitution.
+- 2026-05-29: migrated to this file as the canonical home per the pairing rule.
+
+** §19 Collaborative Communication Artifacts
+
+*** Modes
+General mode only. Prose and personal inherit it.
+
+*** Rule
+Strip chatbot correspondence framing ("I hope this helps", "Let me know if...", "Here is an overview of...", "Certainly!", "Of course!", "Would you like...") that leaked into the body.
+
+*** Problem
+Text meant as chatbot correspondence gets pasted as content, carrying the assistant's framing into a document that should stand alone. Watch-list words: I hope this helps, Of course!, Certainly!, You're absolutely right!, Would you like..., let me know, here is a...
+
+*** Basis
+Observation-derived (Wikipedia "Signs of AI Writing").
+
+*** Before
+#+begin_example
+Here is an overview of the French Revolution. I hope this helps! Let me know if you'd like me to expand on any section.
+#+end_example
+
+*** After
+#+begin_example
+The French Revolution began in 1789 when financial crisis and food shortages led to widespread unrest.
+#+end_example
+
+*** History
+- Original SKILL.md entry: collaborative-communication artifacts pasted as content.
+- 2026-05-29: migrated to this file as the canonical home per the pairing rule.
+
+** §20 Knowledge-Cutoff Disclaimers
+
+*** Modes
+General mode only. Prose and personal inherit it.
+
+*** Rule
+Remove training-cutoff hedges ("as of my last update", "while specific details are scarce", "based on available information") and either commit to a fact or omit the claim.
+
+*** Problem
+AI disclaimers about incomplete information get left in text, signaling the model's uncertainty rather than the author's. Watch-list words: as of [date], Up to my last training update, While specific details are limited or scarce, based on available information.
+
+*** Basis
+Observation-derived (Wikipedia "Signs of AI Writing").
+
+*** Before
+#+begin_example
+While specific details about the company's founding are not extensively documented in readily available sources, it appears to have been established sometime in the 1990s.
+#+end_example
+
+*** After
+#+begin_example
+The company was founded in 1994, according to its registration documents.
+#+end_example
+
+*** History
+- Original SKILL.md entry: knowledge-cutoff hedging.
+- 2026-05-29: migrated to this file as the canonical home per the pairing rule.
+
+** §21 Sycophantic/Servile Tone
+
+*** Modes
+General mode only. Prose and personal inherit it.
+
+*** Rule
+Cut servile opener phrases ("Great question!", "You're absolutely right", "That's an excellent point") and proceed straight to the substance.
+
+*** Problem
+Overly positive, people-pleasing language reads as performance rather than communication and signals AI assistant register.
+
+*** Basis
+Observation-derived (Wikipedia "Signs of AI Writing").
+
+*** Before
+#+begin_example
+Great question! You're absolutely right that this is a complex topic. That's an excellent point about the economic factors.
+#+end_example
+
+*** After
+#+begin_example
+The economic factors you mentioned are relevant here.
+#+end_example
+
+*** History
+- Original SKILL.md entry: sycophantic and servile opener patterns.
+- 2026-05-29: migrated to this file as the canonical home per the pairing rule.
+
+** §22 Filler Phrases
+
+*** Modes
+General mode only. Prose and personal inherit it. Pattern §38 is the stricter cousin for Craig's authored prose.
+
+*** Rule
+Compress wordy filler to plain equivalents: "in order to" to "to", "due to the fact that" to "because", "at this point in time" to "now", "in the event that" to "if", "has the ability to" to "can", "it is important to note that" to nothing, "for the purpose of" to "to", "in spite of the fact that" to "although", "a great deal of" to "much", "at this juncture" to "now".
+
+*** Problem
+Wordy filler stretches a sentence without adding precision. Cutting it shortens the prose and sharpens the claim.
+
+*** Basis
+Corpus-measured: 2026-05-29 commit corpus shows "moreover", "furthermore", "additionally", "in conclusion" all at zero or one occurrence. Filler-phrase avoidance confirmed at the watch-list level.
+
+*** Before
+#+begin_example
+In order to achieve this goal, we need to allocate resources due to the fact that the team has the ability to deliver. At this point in time, it is important to note that the data shows progress.
+#+end_example
+
+*** After
+#+begin_example
+To achieve this, we need to allocate resources because the team can deliver. The data shows progress.
+#+end_example
+
+*** Detection
+The original SKILL.md entry uses a Before to After substitution table:
+- "In order to achieve this goal" to "To achieve this"
+- "Due to the fact that it was raining" to "Because it was raining"
+- "At this point in time" to "Now"
+- "In the event that you need help" to "If you need help"
+- "The system has the ability to process" to "The system can process"
+- "It is important to note that the data shows" to "The data shows"
+- "For the purpose of" to "To"
+- "In spite of the fact that" to "Although"
+- "A great deal of" to "Much"
+- "At this juncture" to "Now"
+
+*** History
+- Original SKILL.md entry: wordy filler phrase substitutions.
+- 2026-05-29: migrated to this file as the canonical home per the pairing rule.
+
+** §23 Excessive Hedging
+
+*** Modes
+General mode only. Prose and personal inherit it.
+
+*** Rule
+Strip stacked hedges ("could potentially possibly", "might have some effect") down to a single appropriate qualifier.
+
+*** Problem
+Over-qualifying statements weakens them without adding accuracy. One hedge does the job that three do.
+
+*** Basis
+Observation-derived (Strunk and White, Garner).
+
+*** Before
+#+begin_example
+It could potentially possibly be argued that the policy might have some effect on outcomes.
+#+end_example
+
+*** After
+#+begin_example
+The policy may affect outcomes.
+#+end_example
+
+*** History
+- Original SKILL.md entry: stacked hedge reduction.
+- 2026-05-29: migrated to this file as the canonical home per the pairing rule.
+
+** §24 Generic Positive Conclusions
+
+*** Modes
+General mode only. Prose and personal inherit it.
+
+*** Rule
+Replace vague upbeat endings ("the future looks bright", "exciting times lie ahead", "a step in the right direction") with a concrete fact or cut the closer entirely.
+
+*** Problem
+Vague upbeat endings give the document the shape of a press release without making any specific claim.
+
+*** Basis
+Observation-derived (Wikipedia "Signs of AI Writing").
+
+*** Before
+#+begin_example
+The future looks bright for the company. Exciting times lie ahead as they continue their journey toward excellence. This represents a major step in the right direction.
+#+end_example
+
+*** After
+#+begin_example
+The company plans to open two more locations next year.
+#+end_example
+
+*** History
+- Original SKILL.md entry: generic positive conclusion boilerplate.
+- 2026-05-29: migrated to this file as the canonical home per the pairing rule.
+
+** §25 Hyphenated Word Pair Overuse
+
+*** Modes
+General mode only. Prose and personal inherit it.
+
+*** Rule
+Drop reflexive hyphens from common modifier pairs (third-party, cross-functional, client-facing, data-driven, decision-making, well-known, high-quality, real-time, long-term, end-to-end) where humans hyphenate inconsistently. Less common or genuinely technical compound modifiers can keep their hyphens.
+
+*** Problem
+AI hyphenates common word pairs with perfect consistency. Humans rarely hyphenate these uniformly, and when they do, it is inconsistent. The uniformity itself is the tell.
+
+*** Basis
+Observation-derived (Wikipedia "Signs of AI Writing").
+
+*** Before
+#+begin_example
+The cross-functional team delivered a high-quality, data-driven report on our client-facing tools. Their decision-making process was well-known for being thorough and detail-oriented.
+#+end_example
+
+*** After
+#+begin_example
+The cross functional team delivered a high quality, data driven report on our client facing tools. Their decision making process was known for being thorough and detail oriented.
+#+end_example
+
+*** History
+- Original SKILL.md entry: hyphenated common-modifier overuse.
+- 2026-05-29: migrated to this file as the canonical home per the pairing rule.
+
+** §26 Long Word → Short Word
+
+*** Modes
+General mode only. Prose and personal inherit it.
+
+*** Rule
+Swap long Latinate words for their short Anglo-Saxon equivalents per the Plain English wordlist: utilize to use, commence to start or begin, terminate to end, facilitate to help, demonstrate to show, sufficient to enough, prior to to before, subsequent to to after, approximately to about, endeavor to try, ascertain to find out, assistance to help, obtain to get, modification to change, implement to carry out, optimal to best, regarding to about, methodology to method, "in the event of" to "if".
+
+*** Problem
+Long Latinate words signal effortful writing without adding precision. Anglo-Saxon roots are shorter and clearer.
+
+*** Basis
+Observation-derived (Strunk and White, Orwell, Plain English Campaign, Garner).
+
+*** Before
+#+begin_example
+The system will utilize advanced algorithms to facilitate optimal performance. Prior to deployment, we must ascertain that the methodology is sufficient.
+#+end_example
+
+*** After
+#+begin_example
+The system uses algorithms to get the best performance. Before deployment, we must check that the method works.
+#+end_example
+
+*** History
+- Original SKILL.md entry: Plain English wordlist substitutions.
+- 2026-05-29: migrated to this file as the canonical home per the pairing rule.
+
+** §27 Active Over Passive Voice
+
+*** Modes
+General mode only. Prose and personal inherit it.
+
+*** Rule
+Rewrite passive constructions to active when the actor is recoverable from context. Flag rather than auto-rewrite when the actor genuinely does not matter, because passive is sometimes the right choice in technical contexts.
+
+*** Problem
+Passive voice hides who did what. Active voice is shorter and clearer in most cases. Skip when the actor genuinely does not matter (technical writing about an inanimate process: "the table was created in 2024" can stay passive).
+
+*** Basis
+Observation-derived (Strunk and White, Orwell).
+
+*** Before
+#+begin_example
+The migration was run by the deployment script. The bug was introduced in commit abc123. The fix was applied by the team.
+#+end_example
+
+*** After
+#+begin_example
+The deployment script ran the migration. Commit abc123 introduced the bug. The team applied the fix.
+#+end_example
+
+*** Detection
+"to be" plus past-participle patterns where the actor is recoverable from context.
+
+*** History
+- Original SKILL.md entry: active-over-passive with suggestion-only treatment in v1.
+- 2026-05-29: migrated to this file as the canonical home per the pairing rule.
+
+** §28 Comma Splices
+
+*** Modes
+General mode only. Prose and personal inherit it. The semicolon escape route is blocked in personal mode by §33.
+
+*** Rule
+Split two independent clauses joined only by a comma into two sentences or join them with a conjunction. In general mode a semicolon is an acceptable repair. In personal mode the semicolon is itself a target (§33), so prefer the period.
+
+*** Problem
+Comma splices read as run-ons. Either split into two sentences, join with a conjunction, or use a semicolon (in personal mode this becomes a period).
+
+*** Basis
+Observation-derived (Strunk and White).
+
+*** Before
+#+begin_example
+The build failed, the test suite reported three errors.
+#+end_example
+
+*** After
+#+begin_example
+The build failed. The test suite reported three errors.
+#+end_example
+
+*** Detection
+Two independent clauses joined only by a comma.
+
+*** History
+- Original SKILL.md entry: comma-splice repair.
+- 2026-05-29: migrated to this file as the canonical home per the pairing rule.
+
+** §29 Cliché Flag
+
+*** Modes
+General mode only. Prose and personal inherit it.
+
+*** Rule
+Replace business and conversational clichés with the plain meaning, including in casual register where "it's fine, it's casual" is the tell. Watch-list phrases: at the end of the day, moving forward, going forward, at this juncture, circle back, low-hanging fruit, deep dive, leverage (as verb), synergy, take it offline, ducks in a row, boil the ocean, pivot (corporate sense), keep it loose, keep it casual, touch base, circle up, hit the ground running, move the needle, on the same page, no-brainer, win-win.
+
+*** Problem
+Clichés signal effortful prose without saying anything specific. Replace with the actual meaning. A casual, friendly, or conversational register is not a license to keep a cliché. Cut it there too. If you catch yourself justifying one as "it's fine, it's casual," that is the tell. Craig flagged this on 2026-05-22 when "keep it loose" slipped through as "acceptable casual." That is exactly the miss this note prevents.
+
+*** Basis
+Observation-derived (Orwell, Garner).
+
+*** Before
+#+begin_example
+At the end of the day, we need to leverage our core competencies and circle back on the low-hanging fruit.
+#+end_example
+
+*** After
+#+begin_example
+We need to use what we already do well and start with the easiest improvements first.
+#+end_example
+
+*** History
+- Original SKILL.md entry: business and conversational cliché list.
+- 2026-05-22: Craig added "keep it loose" / "keep it casual" after a miss in earlier output.
+- 2026-05-29: migrated to this file as the canonical home per the pairing rule.
+
+** §30 Jargon-Fragment → Complete Sentence
+
+*** Modes
+General mode only. Prose and personal inherit it. Pattern §37 is the stricter cousin for Craig's authored prose.
+
+*** Rule
+Rewrite telegraphic sentence fragments inside prose paragraphs as complete sentences with subject and verb. Headings and bullet items are exempt because fragments are valid there.
+
+*** Problem
+Telegraphic fragments in prose paragraphs read as bullet-style notes leaking into running text. They lose the connective tissue a complete sentence carries.
+
+*** Basis
+Observation-derived (Strunk and White).
+
+*** Before
+#+begin_example
+The new function handles edge cases. Empty input throws. Whitespace gets trimmed. Returns null on no match.
+#+end_example
+
+*** After
+#+begin_example
+The new function handles edge cases. It throws on empty input, trims whitespace, and returns null when no match is found.
+#+end_example
+
+*** Detection
+Sentence-like fragments inside prose paragraphs that read as bullet-list shorthand. Headings and bullet items are exempt because fragments are valid there.
+
+*** History
+- Original SKILL.md entry: jargon-fragment rewrite for prose paragraphs.
+- 2026-05-29: migrated to this file as the canonical home per the pairing rule.
+
+** §31 Noun-ified Verbs
+
+*** Modes
+General mode only. Prose and personal inherit it.
+
+*** Rule
+Replace corporate-speak noun-ifications with the real noun: "the ask" to "the request", "a learn" to "the lesson", "the spend" to "the budget", "a build" to "the system" or "the prototype", "the reveal" to "the announcement", "the lift" to "the effort", "the get" to "the result". Philosophical nominalizations ("the becoming", "the unfolding") are not targets.
+
+*** Problem
+Corporate-speak nominalization reads as performance. The real nouns are shorter and clearer. Watch-list: the ask, a learn, the spend, a build, the reveal, a do, the lift, the get, the say.
+
+*** Basis
+Observation-derived (Garner; Craig's voice rules in claude-rules/commits.md).
+
+*** Before
+#+begin_example
+The ask was for a quick build. After the reveal, we'll do a learn.
+#+end_example
+
+*** After
+#+begin_example
+The request was for a quick prototype. After the announcement, we'll review what worked.
+#+end_example
+
+*** History
+- Original SKILL.md entry: corporate-speak nominalization.
+- 2026-05-29: migrated to this file as the canonical home per the pairing rule.
+
+** §32 First-Person Voice Rewrite
+
+*** Modes
+Personal mode only. General and prose skip it because a research note, a document, or anyone else's text is legitimately third-person.
+
+*** Rule
+Rewrite impersonal third-person publish-artifact bodies into first person ("I added X", "I missed Y", "I kept Z because..."). The commit subject line stays imperative per Conventional Commits ("feat: add support for X"). The body shifts to first person. Skip the rewrite for mechanical changes (a chore version bump, a typo fix) where the subject alone carries the message.
+
+*** Problem
+Impersonal third-person ("Add support for X", "The change adds Y") reads as press-release voice in a commit body or PR description. First-person ("I added X", "I kept Y because...") sounds like one engineer talking to another.
+
+*** Basis
+Corpus-measured across registers (2026-05-29): standalone "I" runs 3.85 per 1000 words in git commits, 36.91 in personal email, 23.79 in work email, 8.68 in PR descriptions, 42.97 in PR review comments. First-person density is roughly 10x higher in conversational registers than in commits. Craig writes first-person heavily across the board, but commit prose under-uses "I" relative to natural English. The rule strengthens the under-using register without overreaching: it asks the publish-artifact body to write the way the email body already does.
+
+*** Before
+#+begin_example
+Adds the new validation step before saving. The previous flow allowed empty values to leak into the database. This change blocks them at the API boundary.
+#+end_example
+
+*** After
+#+begin_example
+I added a validation step before saving. The previous flow let empty values leak into the database. I'm blocking them at the API boundary now.
+#+end_example
+
+*** Detection
+Impersonal third-person construction in a publish-artifact body where first-person fits naturally.
+
+*** History
+- Original SKILL.md entry: first-person rewrite for publish artifacts.
+- 2026-05-29: migrated to this file as the canonical home per the pairing rule.
+
+** §33 Semicolon → Period or Comma
+
+*** Modes
+Prose and personal modes. General mode keeps semicolons because academic and literary registers use them legitimately.
+
+*** Rule
+Replace semicolons with a period (split into two sentences) or a comma (when the clauses are tightly coupled) in Craig's authored prose: emails, documents, working notes, commit-message bodies, PR descriptions, PR review comments. A formal long-form document can keep the semicolon, but the default is to split. Chosen self-discipline, not habit-reflection.
+
+*** Problem
+Craig's published voice drops semicolons by choice. They make the writing feel unnecessarily literary, the period-split usually reads better, and dropping them removes one common AI tell. The rule overrides his pre-rule habit rather than codifying one — the corpus shows he used semicolons regularly in commit prose.
+
+*** Basis
+Corpus-measured across registers (2026-05-29): semicolons run 3.16 per 1000 words in git commits, 0.64 in personal email, 0.26 in work email, 0.62 in PR descriptions, 0.00 in PR review comments. Same register split as em-dashes (§13). Semicolons are concentrated in commit prose; conversational prose almost never uses them. The rule mostly enforces what is already true for non-commit registers. It earns its place because commit prose is the register where Craig's habit and the AI-tell pattern overlap.
+
+*** Before
+#+begin_example
+I added the validation; the previous flow allowed empty values to leak through.
+#+end_example
+
+*** After
+#+begin_example
+I added the validation. The previous flow allowed empty values to leak through.
+#+end_example
+
+*** Detection
+Semicolons in prose Craig authors: emails, documents, working notes, commit-message bodies, PR descriptions, PR review comments.
+
+*** History
+- Original SKILL.md entry: semicolon to period or comma in Craig's authored prose.
+- 2026-05-29 (commit =c3cf9a5=): basis note added with corpus measurement reframing the rule as self-discipline.
+- 2026-05-29: migrated to this file as the canonical home per the pairing rule.
+- 2026-06-10: the self-discipline reframing (a "Suggested deltas" item from 2026-05-29, never applied) moved from the findings section into the entry proper and into the SKILL.md rule line. Craig's call, from the work-project session.
+
+** §34 Contractions
+
+*** Modes
+Prose and personal modes. General mode skips because academic, literary, and formal registers often prefer uncontracted forms.
+
+*** Rule
+Prefer contractions in Craig's prose (it's, that's, don't, we're, I'd, won't) unless a negation or emphasis genuinely needs the uncontracted weight.
+
+*** Problem
+Uncontracted English reads stiff in a short prose body unless a negation or emphasis needs the weight. Prefer contractions in his prose: emails, documents, commit and PR bodies.
+
+*** Basis
+Corpus-measured across registers (2026-05-29). Contraction rate per 1000 words: git commits 3.57, personal email 38.52, work email 28.13, PR descriptions 17.36, PR review comments 50.78. Commit prose is the outlier register that suppresses contractions; conversational and PR-review prose use them heavily, near the natural-English rate. The Phase 1 curiosity (I'm 9 occurrences vs standalone I at 495 in commits) was a register effect, not a personal preference. Personal email runs I'm at 6.04 per 1000 vs standalone I at 36.91, ratio close to natural English. Top contractions in personal email: i'm 1710, it's 928, i'll 865, don't 632, you're 567, i've 458, that's 433, i'd 384, we're 307, didn't 299. The rule confirms across the board, with the strongest evidence from the conversational registers where contractions are most expected.
+
+*** Before
+#+begin_example
+It is worth noting that the change does not break the existing flow. We are confident that this is the right approach.
+#+end_example
+
+*** After
+#+begin_example
+It's worth noting the change doesn't break the existing flow. We're confident this is the right approach.
+#+end_example
+
+*** Detection
+Uncontracted forms in publish-artifact prose where the contraction reads more naturally. Note pattern §38 catches "worth noting" as rhetorical padding. The example above shows isolated transformation. In practice both passes apply.
+
+*** History
+- Original SKILL.md entry: contractions preferred in Craig's authored prose.
+- 2026-05-29: migrated to this file as the canonical home per the pairing rule.
+
+** §35 Sentence Split on Conjunctions
+
+*** Modes
+Prose and personal modes. General mode skips because academic and literary registers use long compound sentences deliberately.
+
+*** Rule
+Split sentences that stack three or four clauses joined by "so", "and", "but" into two or three shorter sentences when the split does not lose meaning.
+
+*** Problem
+Long compound sentences read easier as two or three shorter ones in a prose or publish-artifact body. Skip in academic or literary prose where deliberate long sentences are the register.
+
+*** Basis
+Observation-derived (Craig's voice rules in claude-rules/commits.md). Corpus context: average sentence is 18.81 words, median 14, with 28% of sentences at 21+ words. Long-sentence rate is moderate. Inspection of actual sentences for conjunction-stitching is deferred to Phase 2.
+
+*** Before
+#+begin_example
+I added the validation step before saving so empty values get blocked at the API boundary, and I also added a regression test that exercises the empty-string case, but I did not change the upstream caller because that's a separate concern.
+#+end_example
+
+*** After
+#+begin_example
+I added the validation step before saving so empty values get blocked at the API boundary. I added a regression test that exercises the empty-string case. I didn't change the upstream caller because that's a separate concern.
+#+end_example
+
+*** Detection
+Sentences that stack three or four clauses with commas and conjunctions ("so", "and", "but") where splitting on a conjunction would not lose meaning.
+
+*** History
+- Original SKILL.md entry: sentence split on conjunctions for Craig's authored prose.
+- 2026-05-29: migrated to this file as the canonical home per the pairing rule.
+
+** §36 Felt-Experience Narration
+
+*** Modes
+Prose and personal modes. General mode skips because third-party prose is legitimately allowed to describe how something feels.
+
+*** Rule
+Cut phrases that tell the reader how the change will feel or how often the writer will use it ("I'll feel this every time I commit", "this will be a relief", "I'm excited about", "this is going to be huge"). State what changed and let the reader decide what to do with it.
+
+*** Problem
+Felt-experience phrases read as performance, not communication. They tell the reader how the writer wants them to receive the change rather than describing the change.
+
+*** Basis
+Observation-derived (Craig's voice rules in claude-rules/commits.md). Commit-body corpus would not carry felt-experience prose; email and journal corpus deferred to Phase 2.
+
+*** Before
+#+begin_example
+I'm so excited about this — I'll feel the speedup every time I run the build. This is going to be a huge relief.
+#+end_example
+
+*** After
+#+begin_example
+The build now finishes in roughly half the time it used to take.
+#+end_example
+
+*** Detection
+Phrases that tell the reader how the change will feel or how often the writer will use it.
+
+*** History
+- Original SKILL.md entry: felt-experience narration cut for Craig's authored prose.
+- 2026-05-29: migrated to this file as the canonical home per the pairing rule.
+
+** §37 Sentence Fragments → Complete
+
+*** Modes
+Prose and personal modes. General mode keeps the softer §30, which exempts more, because the strong "every sentence" rule is Craig's voice and should not be imposed on third-party text.
+
+*** Rule
+Rewrite every sentence fragment inside a prose paragraph in Craig's authored text as a complete sentence with subject and verb. Bullets and headings can stay fragments. Exemption: verdict formulas in PR review summaries ("Approving.", "Requesting changes.", "Approved.") are house style and stay — rewriting them imposes the rule where Craig's calibrated voice already decided otherwise.
+
+*** Problem
+Bullet shorthand leaking into running prose ("Two changes." "Fix incoming." "Body as decision log.") reads as bullet-list notes pasted into a paragraph. Every prose sentence needs a subject and a verb in prose and personal modes.
+
+*** Basis
+Observation-derived (Craig's voice rules in claude-rules/commits.md). Corpus context: 9.7% of sentences are 1-5 words. Some are legitimate single-word claims ("All eight pass."), some may be fragments. Word count alone cannot distinguish. Syntactic detection deferred to Phase 2.
+
+*** Before
+#+begin_example
+Big change to the validator. Three new patterns. Test coverage up. Old behavior preserved.
+#+end_example
+
+*** After
+#+begin_example
+I made a big change to the validator. There are three new patterns and the test coverage is up. The old behavior is preserved.
+#+end_example
+
+*** Detection
+Sentence fragments inside prose paragraphs in any text Craig authors: an email, a document, a working note, a commit or PR body. Bullets and headings remain fair game for fragments.
+
+*** History
+- Original SKILL.md entry: sentence-fragment rewrite for Craig's authored prose.
+- 2026-05-29: migrated to this file as the canonical home per the pairing rule.
+- 2026-06-10: verdict-formula exemption added. The skill survived in practice by being selectively ignored on "Approving." / "Requesting changes." / "Approved.", and selective ignoring is the same muscle that skips real patterns. Documenting the exception removes one standing occasion for judgment-override. Craig's call, from the work-project session.
+
+** §38 Terse Cut — Omit Needless Words
+
+*** Modes
+Prose and personal modes. General mode keeps the softer §22 because academic registers retain "worth noting" and "it's important to understand" as legitimate transition markers.
+
+*** Rule
+Two cuts. First strip the soft rhetorical padding ("worth noting", "it's important to understand", "as you can see", "needless to say", "obviously", "of course", "in essence", "fundamentally"). Then run the general omit-needless-words sweep the padding list only samples: read each sentence and cut or collapse every word and clause that can go without losing meaning, not only the named phrases. Forcing test, per sentence: try to delete half of it and keep only what changes meaning.
+
+*** Execution position (prose + personal)
+§38 is not just one pattern in the walk — it is the mandatory *last* pass before any draft is presented. The SKILL.md Process makes it an explicit standalone final step, run after every other pattern. The reason is empirical: a draft that cleared the other 40 patterns still routinely runs a third too long, because ordinary verbosity matches no named trigger and the categorical detectors come back clean while the text is still bloated. Folded into the general walk, §38 gets glossed as a wordlist match. As a separate final step it gets the real per-sentence "delete half of it" sweep. A public draft shown without this pass is a defect in the same class as skipping the skill entirely.
+
+*** Problem
+Tier 1 omit-needless-words (§26) catches rigid offenders ("the fact that", "in order to"). The original §38 added a named padding list ("worth noting", "obviously"). But a draft can clear both and still run a third too long, because ordinary verbosity matches no named trigger: "that already merged via" for "landed on", "with it still in the PR, the same fix lands" for "keeping it re-lands the fix", restated subjects, throat-clearing lead-ins, clauses the reader already has. Those slip the categorical detectors silently — the walk comes back clean while the text is still bloated. So §38 is a real walk step, not a wordlist match: after the named padding, read each sentence and try to delete half of it. Academic registers keep the transition markers, so the aggressive cut stays prose and personal only.
+
+*** Basis
+Corpus-measured across registers (2026-05-29). Single-sentence-paragraph rate: git commits 41.1%, personal email 57.4%, work email 44.5%, PR descriptions 74.4%, PR review comments 50.0%. The terse-paragraph cadence is even more pronounced in conversational and PR-description prose than in commits. Craig writes terse across registers, with the highest density in deliberate PR descriptions where each paragraph carries one focused thought. Confirmed indirectly via paragraph structure across all five corpora.
+
+*** Before
+#+begin_example
+It's worth noting that the change doesn't break the existing flow. Needless to say, the test suite is green. Obviously, this means we can ship.
+#+end_example
+
+*** After
+#+begin_example
+The change doesn't break the existing flow. The test suite is green. We can ship.
+#+end_example
+
+*** Before (generic verbosity, no named padding)
+#+begin_example
+This try/except is the same isolation change that already merged via #203. With it still in the PR, the same production fix lands under a second ticket, which is what the test: label means.
+#+end_example
+
+*** After
+#+begin_example
+This try/except already landed on development via #203. Keeping it re-lands a merged fix under a second ticket, like the test: label says.
+#+end_example
+
+This second pair carries no padding phrase from the named list. Every cut is ordinary verbosity: "is the same isolation change that already merged via" collapses to "already landed on", "With it still in the PR, the same production fix lands" to "Keeping it re-lands a merged fix", "which is what ... means" to "like ... says". A wordlist match finds nothing here; the per-sentence "delete half of it" test finds all of it.
+
+*** Detection
+Two passes. (1) Named padding phrases: "worth noting", "it's important to understand", "as you can see", "needless to say", "obviously", "of course", "in essence", "fundamentally". (2) Ordinary verbosity beyond the list: verbose verb phrases ("already merged via" → "landed on"), restated subjects, throat-clearing lead-ins, and any clause whose content the reader already has. The forcing test for pass 2 is per sentence: try to delete half of it and keep only what changes meaning.
+
+*** History
+- Original SKILL.md entry: rhetorical-padding cut for Craig's authored prose.
+- 2026-05-29: migrated to this file as the canonical home per the pairing rule.
+- 2026-06-02: generalized from a named-padding-list detector to a real omit-needless-words walk step. A PR-review comment cleared the §22/§23/§26/§38-padding patterns yet still ran a third too long on ordinary verbosity; the wordlist matched none of it. Renamed "Rhetorical Padding" to "Omit Needless Words", added the per-sentence "delete half of it" forcing test and the generic-verbosity example pair above. Craig's call.
+- 2026-06-05: elevated to the mandatory final pass in the SKILL.md Process (new step 7). The pattern existed and was being walked, but got glossed as one of 41; a commit message went out needing two manual Orwell-walk requests before it read terse. Made it an explicit standalone last step that runs before any draft is shown, so the terse cut happens before Craig sees the draft rather than after he asks for it. Added the "Execution position" subsection above. Craig's call.
+
+** §39 Public-Artifact Scope Check
+
+*** Modes
+Personal mode only. General and prose skip because a private journal or a third-party document has no public-scope concern. Flag only; no auto-rewrite.
+
+*** Rule
+Flag (do not auto-rewrite) local absolute paths, private repo names, and personal-tooling references in publish artifacts. Surface each match as a WARN line so the author resolves manually. Output format:
+#+begin_example
+WARN: line 12: "/home/cjennings/code/rulesets" — local absolute path in commit body
+WARN: line 18: "claude-rules/commits.md" — personal-tooling reference; state the underlying reason instead
+#+end_example
+
+*** Problem
+Commit messages, PR descriptions, PR comments, and Linear ticket bodies are visible to teammates and anyone with read access. References to the writer's personal layout are noise to a reader who cannot reproduce it. Auto-masking risks silently editing meaningful content because a legitimate file path mention may be load-bearing, and only the author can tell.
+
+*** Basis
+Observation-derived (Craig's voice rules in claude-rules/commits.md, Content scope section). Corpus is the public artifacts themselves, so confirmation is circular. Deferred to Phase 2.
+
+*** Detection
+Local absolute paths (=/home/<user>/...=, =/Users/<user>/...=), private repo names (any repo not in this project's known public set), personal-tooling references (humanizer, voice, commits.md, anything under =claude-rules/=, anything under =.ai/= or =.claude/=).
+
+*** History
+- Original SKILL.md entry: public-artifact scope flag for personal mode.
+- 2026-05-29: migrated to this file as the canonical home per the pairing rule.
+
+** §40 Praise vs Correction Asymmetry
+
+*** Modes
+Personal mode only. General and prose skip because the rule assumes a PR review context.
+
+*** Rule
+Praise on a PR review is short and unjustified (the author knows why their good change is good), and it survives only as an inline pin on the line it refers to. Correction always explains the why, gently and briefly, the way a mentor would, never as a verdict from on high. Keep it brief either way.
+
+On an approve summary: no praise at all, not even a bare positive ("Clean.", "Solid fix."). Lead with the substantive pointer — the design note pinned inline — and close with the verdict; an approve with nothing to flag is just "Approving." "Clean fix on the stacking bug, the tri-state is the right level to solve it at, and the tests cover the edges. Approving." becomes "One design note inline, not a blocker. Approving." (or just "Approving." with nothing to flag). Cut any clause that describes, justifies, or compliments the change — if a clause references what the code does, why it works, or how good it is, delete it.
+
+On a finding or change-request: always give the why, gently and briefly. Not "Move this to a helper." but "I'd pull this into one helper — three copies of the same rule means the next change has to touch all three, and missing one brings the bug back."
+
+Verification narration is the same defect as justified praise. "I traced X and it's safe because..." pads the compliment with the reviewer's homework. Tracing the code is the reviewer's job, not content for the comment — if verification found a problem, the problem gets the words; if it found nothing, it gets zero words.
+
+*** Problem
+Praise and correction call for opposite treatment. The author already knows why their good change is good, so justifying praise reads as flattery. Correction is the reverse. Behavior only changes when the reason lands, so a finding, change-request, or inline coaching note must always explain the why. And the why is delivered gently, the way a kind coach or mentor would.
+
+*** Basis
+Observation-derived (Craig's voice rules in claude-rules/commits.md, Voice and Focus section). PR-review corpus needed for empirical measurement. Deferred to Phase 2.
+
+*** Before
+#+begin_example
+Nice clean migration, the provider mocks and the Normal/Boundary/Error cases are all covered which is exactly what I'd want here. Approving. Also rename `x`.
+#+end_example
+
+*** After
+#+begin_example
+One naming note inline, not a blocker. Approving.
+#+end_example
+
+The rename rationale (`x` reads as a generic placeholder; the next person won't know it's the resolved provider without tracing it) lives in the inline pin, not the summary — the summary points, the pin teaches.
+
+*** Before (verification narration)
+#+begin_example
+All three fixes look right. I traced useMapActions and the unmount cleanup is safe because the hook returns a memoized object, and the provider wraps the whole app so neither call site lands on the no-op path.
+#+end_example
+
+*** After
+#+begin_example
+Approving.
+#+end_example
+
+Nothing to flag, so the summary is the bare verdict. The old "All three fixes are clean and well-aimed" is itself praise, and praise is now cut from the approve summary entirely.
+
+*** Detection
+In a PR review summary or comment: any praise on an approve summary (including a bare positive), a praise clause that explains why the good thing is good, a praise clause followed by the verification work that supports it, or a finding or change-request that states what to fix without saying why.
+
+*** History
+- Original SKILL.md entry: praise-versus-correction asymmetry for PR review.
+- 2026-05-29: migrated to this file as the canonical home per the pairing rule.
+- 2026-06-10: verification-narration variant added after the third recurrence — a review draft praised a fix and then narrated the verification supporting the praise (the #236 draft). Added to the SKILL.md rule line and the high-recurrence attestation set. Craig's call, from the work-project session.
+- 2026-07-11: bare-positive carve-out removed. An approve summary now carries no praise at all, not even "Clean." / "Solid fix." — lead with the substantive pointer, close with the verdict. Craig's ruling from a DeepSat review session (approved "One design note inline, not a blocker. Approving."). Same change applied to review-code's Posted Summary Voice and commits.md Shape 1.
+
+** §41 No Emphasis Formatting
+
+*** Modes
+Prose and personal modes. General mode keeps the related but mechanical §14 (boldface strip). §41 carries Craig's own principle and covers italics and underscores too.
+
+*** Rule
+Remove emphasis markup (bold, italics, underscore-wrapped words) used to stress a phrase in Craig's prose, and rephrase so the stress lives in word choice and sentence shape. Structural markup stays: headings, defined terms on first use where the convention is house style, code spans for literal identifiers.
+
+*** Problem
+Craig makes his points with words, not formatting. Emphasis markup is a crutch. When a sentence leans on bold or italics to land, the wording is not doing the work. The fix is not to delete the markup and leave a flat sentence. It is to rephrase so the stress lives in the word choice and sentence shape. This is the same principle behind his terminal-rendering rule in chat, but here it is about the writing itself, not the display.
+
+*** Basis
+Observation-derived (Craig's voice rules in claude-rules/interaction.md, No Reverse-Video Highlighting rule). Org-mode bold uses =*word*= rather than Markdown =**word**= so corpus grep for Markdown emphasis is not directly applicable. Corpus measurement deferred to Phase 2.
+
+*** Before
+#+begin_example
+This is **really** important: you must run the migration *before* deploying, or the app will crash.
+#+end_example
+
+*** After
+#+begin_example
+Run the migration before deploying. Skip that step and the app crashes on the first request.
+#+end_example
+
+*** Detection
+Bold (=**...**=), italic (=*...*= or =_..._=), or underscore-wrapped words used to emphasize a phrase in Craig's prose.
+
+*** History
+- Original SKILL.md entry: no emphasis formatting for Craig's authored prose.
+- 2026-05-29: migrated to this file as the canonical home per the pairing rule.
+
+** §42 Finding Stems — One Claim Per Sentence
+
+*** Modes
+Personal mode only. General and prose skip because the rule assumes a PR review finding.
+
+*** Rule
+A PR review finding is built from clean stems, each a straightforward sentence carrying one claim: (1) where the bug is, (2) the way(s) to fix it, (3) why that's better. Cut context sentences that don't change what the author does next (ticket history, design archaeology). Rewrite the anti-pattern shapes: hedged gerund chains ("the real bug looks like the model emitting a partial set"), compressed trade-off clauses ("I'd rather X, or Y, than lose Z"), multi-claim sentences chained through so-clauses or "and", and fixes buried after a mid-sentence colon.
+
+*** Problem
+Craig named detangling overly complex or overly wordy Claude-drafted PR review text as THE key issue he fights in PR reviews, and the reason he gates every review draft. The tangles passed all 41 then-existing patterns — §38 shortens but doesn't untangle; a sentence can be terse and still carry three claims. §40 governs praise; this governs how finding text is constructed.
+
+*** Basis
+Observation-derived from PR #233 (2026-06-10): a review comment shipped with hedged gerund chains and compressed trade-off clauses that cleared the full walk. The three Before/After pairs below are Craig-approved rewrites from that PR.
+
+*** Before (multi-claim opener + context sentence)
+#+begin_example
+POST fixes the wipe but it's additive: it no-ops on an empty list and never removes, so "cancel all partners" and any de-selection silently stop working. PUT came from SE-195 so the confirm could reconcile the full set. The real bug is upstream: on a new tasking the confirm emits only the new provider, not the full set. Fix that, or merge with the mission's current providers before the PUT. Either way removal keeps working.
+#+end_example
+
+*** After
+#+begin_example
+POST is additive: it no-ops on an empty list and never removes. That breaks "cancel all partners" and any de-selection. The real bug is upstream: on a new tasking the confirm emits only the new provider, not the full set. Fix that, or merge with the mission's current providers before the PUT, and removal keeps working.
+#+end_example
+
+The SE-195 context sentence is cut because it doesn't change the author's next action.
+
+*** Before (hedged gerund chain + compressed trade-off — the calibration case Craig pulled up)
+#+begin_example
+The real bug looks like the model emitting a partial set on a new tasking. I'd rather fix what the confirm emits, or merge client-side before the PUT, than lose removal.
+#+end_example
+
+*** After (where / fix / payoff)
+#+begin_example
+The real bug is upstream: on a new tasking the confirm emits only the new provider, not the full set. Fix that, or merge with the mission's current providers before the PUT. Either way removal keeps working.
+#+end_example
+
+*** Before (claims joined with "and"; fix buried after a mid-sentence colon)
+#+begin_example
+The prefix check catches any message starting with "confirm ", and the options block exists so the LLM can resolve "number 2" style references. A typed "confirm number 2" loses the list it needs. The card click already sends a self-describing "confirm <id>": pass an explicit parameter through sendAgentMessage and strip only on that path.
+#+end_example
+
+*** After
+#+begin_example
+The prefix check strips the options block from any typed message starting with "confirm ", so "confirm number 2" loses the list the LLM needs to resolve it. Strip on the card-click path instead, with an explicit parameter passed through sendAgentMessage. The click already sends a self-describing "confirm <id>", so stripping is safe there.
+#+end_example
+
+*** Detection
+In a PR review finding: a sentence carrying more than one claim (chained through so-clauses, "and", or a mid-sentence colon hiding the fix), a hedged gerund chain where a direct claim belongs, a compressed trade-off clause, or a context sentence that doesn't change the author's next action.
+
+*** History
+- 2026-06-10: created from the PR #233 calibration session. Proposed in the work project's stems handoff, landed via the consolidated voice-skill revision. Included in the high-recurrence attestation set from day one. Craig's call.
+
+** §43 Single-Sentence Paragraph Cadence Is a Feature
+
+*** Modes
+Prose and personal modes. General mode skips because third-party registers legitimately prefer multi-sentence paragraphs.
+
+*** Rule
+A one-sentence paragraph is a finished thought, not a fragment. "Shifts angle" means shifts *topic*: break paragraphs at a topic boundary, even when both sides are one sentence. Within a single topic, consolidate its sentences into one paragraph even when each is complete, up to a ceiling of about five or six sentences, past which find a natural break. The never-merge instruction protects the break *between* topics; it never licenses fragmenting one topic across several paragraphs.
+
+*** Problem
+Most prose-style guides advise multi-sentence paragraphs, so a generic cleanup pass merges Craig's short paragraphs and erases a distinctive feature of his voice. This is a protective pattern: it guards an existing trait rather than correcting a defect.
+
+The 2026-07-23 boundary refinement addresses the opposite failure, discovered the same day: reading "angle" at *sentence* granularity, so that three sentences all about one topic (a baking run, a mixer, tortillas) got split into three paragraphs as if each were a new angle. That fragments one topic and reads as a checklist rather than a person talking. Angle means topic. #43 governs the break between topics; consolidation fills in what happens within one, which the original rule never specified. The two are one rule seen from both sides, not a rule in tension with #47.
+
+*** Basis
+Corpus-measured (2026-05-29). Single-sentence-paragraph rate: git commits 41.1%, personal email 57.4%, work email 44.5%, PR descriptions 74.4%, PR review comments 50.0%. Between 41% and 74% of Craig's paragraphs are exactly one sentence, depending on register.
+
+*** Before (a cleanup pass merging short paragraphs)
+#+begin_example
+The build now finishes in half the time, and the cache no longer invalidates on every run, which means the CI queue clears faster too.
+#+end_example
+
+*** After
+#+begin_example
+The build now finishes in half the time.
+
+The cache no longer invalidates on every run, so the CI queue clears faster too.
+#+end_example
+
+*** Detection
+An edit pass that merged short paragraphs, or a draft whose paragraphs each stack multiple shifted angles that would read better broken apart.
+
+*** History
+- 2026-05-29: surfaced by the Phase 1-2 corpus measurement as a "worth adding" trait; filed as suggested delta 4.
+- 2026-06-10: promoted from the suggested-deltas list into a numbered pattern. Craig's call, from the work-project session.
+- 2026-07-23: boundary refined (angle means topic; within-topic consolidation to a ~5-6 sentence ceiling; never-merge reframed as across-topic protection). From a home session drafting a Signal reply, where the original rule was misread at sentence granularity. Paired with the new §47.
+
+** §44 Parenthetical Asides Are Part of the Voice
+
+*** Modes
+Prose and personal modes. General mode skips because third-party text owns its own aside conventions.
+
+*** Rule
+Parentheses for asides, clarifications, and scope-narrowing are Craig's voice. Don't strip them in a cleanup pass. They're also the preferred landing spot for em-dash replacements under §13.
+
+*** Problem
+Generic style passes treat parentheticals as clutter and strip them. For Craig they carry asides, clarifications, and scope-narrowing, and removing them flattens the voice. Protective pattern, like §43.
+
+*** Basis
+Corpus-measured (2026-05-29): 23.07 opening parens per 1000 words across the commit corpus. Heavy parenthetical use is distinctive and consistent.
+
+*** Before (a cleanup pass stripping the aside)
+#+begin_example
+The sync runs on every startup. It skips lockfiles. It also skips build output.
+#+end_example
+
+*** After
+#+begin_example
+The sync runs on every startup (skipping lockfiles and build output).
+#+end_example
+
+*** Detection
+An edit pass that removed parenthetical asides present in the source text, or an em-dash replacement under §13 where parentheses fit better than a comma or period.
+
+*** History
+- 2026-05-29: surfaced by the Phase 1-2 corpus measurement as a "worth adding" trait; filed as suggested delta 5.
+- 2026-06-10: promoted from the suggested-deltas list into a numbered pattern, with the §13 landing-spot note. Craig's call, from the work-project session.
+
+** §45 Declarative Register Marker
+
+*** Modes
+Prose and personal modes, advisory. Flag only; no auto-rewrite. General mode skips.
+
+*** Rule
+Craig's prose is declarative. When a draft contains a rhetorical question, flag it for a second look — it's usually AI rhetoric, not his register. Genuine questions to the reader (a review asking the author's intent, an email asking for a decision) stay.
+
+*** Problem
+AI drafts reach for rhetorical questions ("So what does this mean for the build?") as a transition device. Craig states things; he rarely asks them. A rhetorical question in his voice is a tell, but a genuine question is legitimate content, so the pattern flags rather than rewrites.
+
+*** Basis
+Corpus-measured (2026-05-29): 0.33 question marks per 1000 words across the commit corpus. His prose register is declarative.
+
+*** Before (rhetorical transition flagged)
+#+begin_example
+So what does this change for the deploy flow? The staging gate now runs before the canary, which means a bad build never reaches it.
+#+end_example
+
+*** After
+#+begin_example
+The staging gate now runs before the canary, so a bad build never reaches it.
+#+end_example
+
+*** Detection
+A question mark in a draft in Craig's voice. Flag it; keep genuine questions to the reader, rewrite rhetorical ones as declarative claims.
+
+*** History
+- 2026-05-29: surfaced by the Phase 1-2 corpus measurement as a register marker; filed as suggested delta 6.
+- 2026-06-10: promoted from the suggested-deltas list into a numbered advisory pattern. Craig's call, from the work-project session.
+
+** §46 Comma Budget — Max Two Per Sentence
+
+*** Modes
+Personal mode only. Prose and general modes skip.
+
+*** Rule
+No sentence carries more than two commas. Rewrite the third comma away: split the sentence, move a clause into a parenthetical (§44) or behind a colon, or break an inline serial list into bullets or its own sentence. Count prose commas only — commas inside code spans, quoted log lines, and literal strings (version numbers, paths) don't count toward the budget.
+
+*** Problem
+Three or more commas in one sentence almost always mark stacked clauses or an inline list doing a paragraph's work. The sentence reads fine to its author and lands as a pileup on the reader. The comma count is a mechanical proxy the walk can enforce, where "don't stack clauses" is prose advice that gets skipped.
+
+*** Basis
+Craig's directive, 2026-07-20 (archsetup session, while gating a Hyprland issue draft): "no more than two commas per sentence. we should add that to the /voice personal pass."
+
+*** Before (spec-sheet line with three commas, from the draft that prompted the rule)
+#+begin_example
+System: Arch Linux, kernel 6.18.25-lts, AMD Strix Halo (Radeon 8060S), no plugins loaded.
+#+end_example
+
+*** After
+#+begin_example
+System: Arch Linux, kernel 6.18.25-lts. GPU: AMD Strix Halo (Radeon 8060S). No plugins loaded.
+#+end_example
+
+*** Detection
+Count commas per sentence on the final text. A sentence at three or more gets restructured, not trimmed to exactly the budget — the third comma is the symptom, the stacked structure is the target.
+
+*** History
+- 2026-07-20: added at Craig's direction from the archsetup session. Scoped to personal mode; broaden to prose only if he asks. Added to the attestation high-recurrence set at birth — a mechanical count is cheap to receipt, and new discipline fails silently without one.
+
+** §47 Recipient-Priority Ordering
+
+*** Modes
+Prose mode, and only when the piece is correspondence (email, Signal, a letter). It needs a recipient, so it has no referent in a journal, a working note, or any document addressed to nobody, and it does not carry into personal mode — a commit or PR review is not a reply to someone's news. General mode skips it with the rest of Craig's voice patterns. This is the one pattern narrower than a whole mode, and the only prose pattern personal mode does not also walk.
+
+*** Rule
+In a reply, lead with what matters most to the recipient, not with what's easiest to answer or the order they wrote it. Their news outranks your logistics. A direct question they asked can sort below personal news they shared, because the news is what they care about.
+
+*** Problem
+The easy draft answers the explicit question first and orders the rest as it arrived. That reads as transactional — logistics before the person. Ordering by what the recipient cares about is what makes a reply read as one person talking to another rather than a ticket being closed. Nothing else in the skill governs the *order* of a reply's contents; the other patterns act within a paragraph or a sentence.
+
+*** Basis
+Craig's edit of a Signal reply to his sister, 2026-07-23 (home session). His framing: "start with what would be the most important things to her."
+
+*** Before (first draft — opens with the only explicit question, cooking split across three paragraphs)
+#+begin_example
+Yes, I do subscribe to MasterClass — happy to share what I've watched.
+
+That's amazing about the sourdough. English muffins from scratch is no joke.
+
+The home-roasted deli meat sounds incredible.
+
+A stand mixer would make the bread a lot easier — worth it if you're baking this much.
+
+And 30 pounds — that's huge. So happy for you.
+#+end_example
+
+*** After (Craig's order — weight first, one cooking paragraph, then the question, then the close)
+#+begin_example
+Thirty-plus pounds — that is huge, and I'm so happy for you. That's real work.
+
+And the cooking. Sourdough, English muffins, tortillas, home-roasted deli meat from scratch — that's a whole kitchen you've built, and a stand mixer would make the bread much easier if you're baking at this volume, so I say go for it. I want to hear how the tortillas come out.
+
+Yes, I subscribe to MasterClass — I'll send you what I've been watching.
+
+I miss you and I love you. Send me a few times that work for a call.
+#+end_example
+
+The cooking paragraph runs seven sentences, a hair over the §43 ceiling. Craig called it an exception rather than re-cut a message that had already gone out. The guard is the rule; this paragraph is one sentence over it; both facts stay in the record, because a real example at the boundary teaches it better than a clean one.
+
+*** Detection
+A reply whose opening answers a logistical or yes/no question while the recipient's substantive news sits lower. Reorder so the news they'd most want acknowledged leads.
+
+*** History
+- 2026-07-23: added from the home session drafting a Signal reply. The first handoff proposed two new patterns and flagged a conflict with §43; the superseding design resolved that the conflict was a misreading of §43 (angle = topic), leaving one genuinely new pattern here and a calibration to §43. Prose/correspondence-scoped per Craig — email and Signal are prose, not publish artifacts.
+
+** §48 Term-Translation Density
+
+*** Modes
+General mode, so it runs in all three (general, prose, personal). It's a universal clarity rule in the Orwell / Plain English family, not a Craig-voice trait, and it reads to anyone editing any prose. The later number is an artifact of when it was added, not a scope signal.
+
+*** Rule
+A sentence that forces the reader to stop and translate more than one specialized term (an acronym, a coined phrase, a product name) is too dense. One is fine; two or more in one sentence means rewrite: split the sentence, gloss one term in a parenthetical, or drop to plain language. The test is the reader's parse, not the writer's familiarity, and it is audience-relative.
+
+*** Problem
+A writer fluent in the domain doesn't feel the translation cost of the terms, so a sentence stacking three of them reads as normal to the author and stalls the reader on every clause. Density is the metric, not any single word: two coined terms in one sentence is worse than a paragraph that introduces the same two one at a time. Audience-relative, because SAR to a defense team is shared vocabulary carrying no load, while a coined phrase only the writer holds carries full load for everyone else.
+
+*** Basis
+Craig's edit of a customer-partner email, 2026-07-23 (work session), where one sentence stacked three terms and he flagged it. Distinct from #7 (specific AI-vocabulary words) and #30 (telegraphic fragments); this measures jargon density per sentence.
+
+*** Before (one sentence, three terms the reader must translate)
+#+begin_example
+A ViT detector gating a VLM for enrichment is close to our own detect-then-contextualize direction.
+#+end_example
+
+*** After (split, glossed, plain)
+#+begin_example
+Their setup is a fast detector that hands off to a heavier model for a closer read. That mirrors our own two-stage approach (find it first, then work out what it is).
+#+end_example
+
+*** Detection
+Count the specialized terms in each sentence that a member of the intended audience would have to stop and translate. Two or more is the trigger. Acronyms, coined phrases, and product names count; shared-vocabulary terms for that audience don't.
+
+*** History
+- 2026-07-23: proposed by Craig from the work session, drafting a customer-partner email. Placed in general mode (universal clarity rule); numbered #48, after the prose-only #47.
diff --git a/working/working-dir-orphan-check/proposal-from-work.org b/working/working-dir-orphan-check/proposal-from-work.org
new file mode 100644
index 0000000..d7d82b2
--- /dev/null
+++ b/working/working-dir-orphan-check/proposal-from-work.org
@@ -0,0 +1,12 @@
+#+TITLE: Convention proposal from Craig's roam inbox (2026-07-23 inbo
+#+SOURCE: from work
+#+DATE: 2026-07-23 15:28:00 -0500
+
+Convention proposal from Craig's roam inbox (2026-07-23 inbox-zero from the work project):
+
+Every project should have a working/ and a temp/ directory.
+- working/ holds files currently being worked on before archiving, in a subdirectory named for the project/task. NOT gitignored — pushed to remote.
+- temp/ holds throwaway files (discarded prototypes, etc). Gitignored, not pushed, deleted as part of the wrap-up sequence.
+- When a task completes, any files it left in working/ are always (via a soft hook if possible) archived or moved to temp/. No files related to a DONE task/project should remain in working/.
+
+Note for the skeptical review: this convention already largely exists in working-files.md (working/ tracked from creation; temp/ gitignored for throwaway). The genuinely new asks here are (a) the automatic soft-hook that empties working/ on task DONE, and (b) temp/ deletion wired into wrap-up. Worth checking what's already implemented vs what this adds before treating it as net-new.
diff --git a/working/working-dir-orphan-check/proposed.diff b/working/working-dir-orphan-check/proposed.diff
new file mode 100644
index 0000000..03452dc
--- /dev/null
+++ b/working/working-dir-orphan-check/proposed.diff
@@ -0,0 +1,24 @@
+--- claude-templates/.ai/workflows/wrap-it-up.org 2026-07-23 08:39:07.467575608 -0500
++++ /tmp/wu2.org 2026-07-23 20:49:55.500740517 -0500
+@@ -189,6 +189,21 @@
+ emacs --batch -q -l .ai/scripts/todo-cleanup.el --archive-done --check todo.org
+ #+end_src
+
++*** Flag orphaned working/ directories
++
++#+begin_src bash
++for d in working/*/; do
++ [ -d "$d" ] || continue
++ s=$(basename "$d")
++ grep -q "working/$s/" todo.org 2>/dev/null || { echo "ORPHAN: $d (no todo.org reference)"; continue; }
++ awk -v s="$s" '/^\*\* /{h=$0} $0 ~ "working/" s "/" {print (h ~ /^\*\* (DONE|CANCELLED)/ ? "CLOSED-TASK: working/" s "/ — " h : "") ; exit}' todo.org
++done
++#+end_src
++
++Report only — never move or delete anything here. A =working/<slug>/= whose backing task is closed (or which no task references at all) is a filing candidate per =working-files.md=: rename each file individually and move it flat into its permanent home, then remove the empty directory.
++
++Filing is deliberately a judgment step and stays manual. Deciding each artifact's permanent home and giving it a meaningful name is what makes =assets/= searchable later, and it's also the moment you notice which artifacts aren't worth keeping. An automatic sweep would skip exactly that review, and sweeping to =temp/= would destroy the artifacts outright, since =temp/= is cleared just below.
++
+ *** Clear temp/
+
+ #+begin_src bash
diff --git a/working/working-dir-orphan-check/wrap-it-up.org.proposed b/working/working-dir-orphan-check/wrap-it-up.org.proposed
new file mode 100644
index 0000000..ff50a3f
--- /dev/null
+++ b/working/working-dir-orphan-check/wrap-it-up.org.proposed
@@ -0,0 +1,651 @@
+#+TITLE: Session Wrap-Up Workflow
+#+AUTHOR: Craig Jennings
+#+DATE: 2026-04-20
+
+* Overview
+
+This workflow defines the process for ending a Claude Code session cleanly. It finalizes the session record, commits + pushes all work, and provides a warm handoff. A bare wrap also tears the session down (kills the ai-term buffer + tmux session, restoring geometry); a qualified wrap keeps the buffer, and a shutdown wrap powers the machine off. The teardown variants are set by the trigger phrase (see Teardown mode below) and act only at the very end, in Step 6.
+
+Triggered by Craig saying "wrap it up," "that's a wrap," "let's call it a wrap," or similar.
+
+* The Session Record
+
+Throughout the session, =.ai/session-context.org= has been maintained with:
+- =* Summary= — structured distillation (empty or draft during session)
+- =* Session Log= — chronological narrative of what happened, written as you go
+
+At wrap-up, this file becomes the permanent session record by being renamed to =.ai/sessions/YYYY-MM-DD-HH-MM-description.org=. No transcription elsewhere. The file IS the record.
+
+* Exit Criteria
+
+The wrap-up is complete when:
+
+1. *Summary is written.* The =* Summary= section of =.ai/session-context.org= is populated by reading the =* Session Log= — Active Goal, Decisions, Data Collected / Findings, Files Modified, Next Steps.
+2. *File is archived.* =.ai/session-context.org= has been renamed to =.ai/sessions/YYYY-MM-DD-HH-MM-description.org=. The old path no longer exists.
+3. *todo.org is clean.* Cleanup script ran. Any auto-fixes are staged for the wrap-up commit. Orphan planning lines surfaced for manual fix if there are any.
+4. *Linear board is honest* (skip if project doesn't use Linear). Any Dev-Review ticket whose PR has merged was moved to Done or PM Acceptance per the classification rule.
+5. *Git state is clean.* All changes committed + pushed to all remotes. Working tree clean.
+6. *Valediction delivered.* Brief, warm closing with key accomplishments and reminders, ending with =session wrapped.= on its own line as the signoff marker.
+
+The absence of =.ai/session-context.org= is the signal that the last session wrapped up cleanly. Its presence at session start means the previous session was interrupted.
+
+* Teardown mode (set from the trigger phrase)
+
+The wrap itself — Steps 1 through 5 — is identical in every mode. The trigger phrase only decides what Step 6 does once commit + push and the valediction are done. Resolve the mode from the phrase before starting:
+
+- *Teardown* (the default) — bare "wrap it up", "that's a wrap", "let's call it a wrap". The full wrap, then Step 6 kills the ai-term buffer + the =aiv-<project>= tmux session (which takes =claude= with it) and restores the saved window geometry. This is Craig's typical end-of-day case.
+- *No-teardown* — "wrap it up with summary" or "wrap it up and summarize". The full wrap, but Step 6 leaves the buffer and session intact so the summary stays readable. The explicit qualifier is what opts out of teardown.
+- *Shutdown* — "wrap it up and shutdown". The full wrap, then Step 6 gates on this being the only live ai-term session and powers the machine off. Shutdown supersedes teardown (killing the buffer is moot if the box is going down).
+
+Why teardown waits for Step 6 and runs through a hook, never inline: teardown kills the very tmux session =claude= runs in, so an inline kill would cut the valediction off before it renders. Step 6 instead drops a sentinel after everything else is verified, and the =Stop= hook (=ai-wrap-teardown.sh=) does the actual teardown when this response ends — by which point the valediction has already been delivered.
+
+This depends on three functions in =.emacs.d/modules/ai-term.el= (=cj/ai-term-quit=, =cj/ai-term-live-count=, =cj/ai-term-shutdown-countdown=) and on the =Stop= hook being wired in =settings.json= (=hooks/settings-snippet.json=). If =emacsclient= or the daemon is unreachable, the sentinel is cleared and the session simply stays up — teardown degrades to a no-op, never a wedge.
+
+* The Workflow
+
+** Step 0: Refuse if sentry is live
+
+Before anything else, check whether sentry is running in this project. Sentry holds the working tree on its =sentry/<date>-<host>= branch and commits unattended; wrapping underneath it would archive the session anchor and tear down the buffer while the loop is still firing into it. If sentry's single-runner lock is held, stop and point at the shutdown path:
+
+#+begin_src bash
+proj="$(basename "$(git rev-parse --show-toplevel 2>/dev/null || pwd)")"
+if [ -x .ai/scripts/agent-lock ] && .ai/scripts/agent-lock status "sentry-$proj" | grep -q '^held'; then
+ echo "sentry is active — say 'stop sentry' first"
+ exit 1
+fi
+#+end_src
+
+The stop-sentry operation (defined in =sentry.org=) owns the shutdown: it cancels the loop, disposes of the branch, and walks the approval queue. Wrap-up carries only this one guard; a =stale= lock (a crashed fire) doesn't block — only a live =held= lock does.
+
+** Step 1: Finalize the Summary
+
+*** Work the Before-Close Queue (before the Summary)
+
+If the session anchor (=.ai/session-context.org=) carries a =* Before-Close Queue= heading with items, work them now, oldest-first, before writing the Summary, so any resulting edits ride this wrap's commit and get described in it. The queue is the "put X on the list" shorthand (see =protocols.org=, Colloquialisms and Expansions): session-scoped work Craig deferred to wrap time.
+
+Per item: do it if it's clear and bounded, or promote it to a =todo.org= task if it turns out to need its own session. Never drop an item silently. Remove each line as it's handled; if one can't be finished, surface it in the valediction (Step 5) and either leave a follow-up task or state why it's dropped.
+
+If there's no =* Before-Close Queue= heading, or it's empty, this step is a silent no-op.
+
+*** Early KB reflection (capture while fresh, before the Summary)
+
+Before distilling the Summary, while the session is still fresh, ask: what did this session learn worth remembering, for yourself or a future agent? Reflect and stage any candidate durable facts — a decision and its why, an environment gotcha, a reference pointer, a transferable lesson. Self-answer silently; this adds no interactive turn (Craig already authorized the wrap). The candidates flow straight into the KB promotion check below, which does the actual writing and the receipt — this is the capture half, that is the commit half, one pipeline, one receipt. Reflecting here rather than reconstructing learnings after the Summary is the point: the early ask is what keeps the receipt from defaulting to "promoted 0" out of fatigue.
+
+Read through the =* Session Log= in =.ai/session-context.org=. Populate (or refine) the =* Summary= section:
+
+- *Active Goal* — one or two sentences describing the session's focus
+- *Decisions* — key choices made, with enough context to recall the /why/
+- *Data Collected / Findings* — anything concrete (measurements, root causes, paths, discoveries)
+- *Files Modified* — what was changed, with one-line rationale per significant file
+- *Next Steps* — what should happen in the next session
+
+Don't repeat everything from the Log in the Summary. The Summary is distillation — pull out what's load-bearing. The Log stays in the file and is available if a future reader wants detail.
+
+*** KB promotion check (and the one-line instrumentation receipt)
+
+Before closing the Summary, ask: did this session learn anything worth promoting to the agent knowledge base? The bar is =knowledge-base.md='s inclusion criteria — durable facts with cross-project or cross-machine value (decisions and their why, environment gotchas, reference pointers, transferable lessons). Promote each qualifying fact as one =agents/= node per the rule's schema (work-classified projects skip the write per the boundary; the check still runs so the receipt below is honest).
+
+Then add one line at the end of the Summary, always, even when nothing moved:
+
+#+begin_example
+KB: promoted 2 / consulted yes
+#+end_example
+
+"promoted N" counts nodes written this session (0 most sessions); "consulted yes-no" records whether any KB query informed the session's work. The line is the input to the spec's 30-day success-metrics checkpoint — grepping session archives for =KB:= answers "are agents actually using this?" without any other instrumentation. A session that skips the line breaks the metric, so it's part of the Summary contract, not optional.
+
+** Step 2: Pick a description + rename
+
+Read the Summary's Active Goal and the prominent entries in the Session Log. Pick a 4-6 word description that would make sense as a git-commit-message-series summary for the whole session.
+
+Good descriptions are concrete nouns/verbs:
+- =docs-ai-migration-and-ai-launcher=
+- =mybitch-usb-disconnect-diagnosis=
+- =ratio-system-health-check=
+- =orchestration-dashboard-bug-triage=
+
+Avoid vague ones:
+- =session-work= (useless)
+- =various-improvements= (useless)
+- =updates= (useless)
+
+Get current time and rename:
+
+#+begin_src bash
+mkdir -p .ai/sessions
+now=$(date +%Y-%m-%d-%H-%M)
+# Resolve the AI_AGENT_ID-aware source path (see protocols.org "Agent-scoped
+# path"); fall back to the singleton if the helper isn't present.
+sc=$(.ai/scripts/session-context-path 2>/dev/null || echo .ai/session-context.org)
+# Under multi-agent, fold the agent id into the archive name so two agents
+# wrapping in the same minute don't collide. Single-agent: no segment.
+idseg="${AI_AGENT_ID:+${AI_AGENT_ID}-}"
+mv "$sc" ".ai/sessions/${now}-${idseg}DESCRIPTION.org"
+#+end_src
+
+Replace =DESCRIPTION= with your picked slug. (=AI_AGENT_ID= should be filename-safe and unique per run; the recommended =host.project.runtime.<epoch>= shape is both. The epoch on the tail keeps a re-run of the same logical agent from resolving to a prior run's leftover anchor. See protocols.org "Agent-scoped path".)
+
+** Step 3: todo.org cleanup (hygiene + archive completed work)
+
+If the project has a =todo.org= at its root, run the cleanup script before committing. Two passes, both fast and idempotent: a hygiene pass and an archive pass.
+
+*** Roam inbox sweep (inbox roam mode)
+
+Before the cleanup scripts, sweep the roam global inbox (=~/org/roam/inbox.org=) for items that belong to this project, so any imported tasks get linted and ride the wrap commit. Delegate to [[file:inbox.org][inbox.org]] roam mode for the claimed set.
+
+#+begin_src bash
+[ -f "$HOME/org/roam/inbox.org" ] && grep -cE '^\*\* ' "$HOME/org/roam/inbox.org" || true
+#+end_src
+
+Skip-fast when nothing matches: if the roam clone isn't on this machine, or no item is prefixed for this project, this is a silent no-op. When claimed items exist, run roam mode's Phase B–D (file each into =todo.org=, then remove them from the shared inbox and let =roam-sync= commit + push the edit). Report the total count and how many appeared related to this project, per roam mode's scan-summary rule.
+
+*** Hygiene pass
+
+It catches a recurring pattern: org sometimes leaves noise lines like =- State "X" from "X" [date]= when a state-change log lands outside a =:LOGBOOK:= drawer and the state didn't actually change. These lines carry no information and they break org's planning-line parser by wedging between the heading and =DEADLINE:=/=SCHEDULED:=, which kicks the entry out of agenda views.
+
+#+begin_src bash
+[ -f todo.org ] && emacs --batch -q -l .ai/scripts/todo-cleanup.el todo.org
+#+end_src
+
+The script is fast (under half a second on a 4000-line file) and idempotent — if there's nothing to fix, it reports zero changes and exits clean.
+
+What it does:
+
+1. *Auto-deletes* bogus state-log lines (matched on identical from/to states). Any deletions show up in the wrap-up commit's diff, so they get reviewed before push.
+2. *Reports* "orphan planning lines" — entries whose body has =DEADLINE:= or =SCHEDULED:= but =org-entry-get= can't read it (some other malformation kept it out of canonical position). The script doesn't auto-rewrite these because the right fix depends on whether real state-log history needs preserving — surface them and fix manually if they matter for the agenda.
+
+Run the report-only variant first if you want to see what would change without writing:
+
+#+begin_src bash
+emacs --batch -q -l .ai/scripts/todo-cleanup.el --check todo.org
+#+end_src
+
+*** Convert done sub-tasks to dated entries
+
+#+begin_src bash
+[ -f todo.org ] && emacs --batch -q -l .ai/scripts/todo-cleanup.el --convert-subtasks todo.org
+#+end_src
+
+=--convert-subtasks= rewrites every heading at level 3 or deeper whose TODO state is DONE/CANCELLED/FAILED into a dated event-log entry (=<stars> YYYY-MM-DD Day @ HH:MM:SS -ZZZZ <text>=), dropping the keyword, priority cookie, and tags, and removing the now-redundant =CLOSED:= line. This enforces the =todo-format.md= depth rule that a completed *sub-task* (a heading under a parent task) becomes dated history, not a lingering DONE keyword — a shape an interactive org close (=org-log-done= → DONE + CLOSED) never applies and =--archive-done= (level-2 only) never reaches. The timestamp comes from each entry's own =CLOSED= cookie; a date-only close yields =00:00:00=. Heading text is kept verbatim. Idempotent (an already-dated heading has no keyword to match), and a done sub-task with no parseable =CLOSED= is flagged and left alone rather than stamped with a fabricated date.
+
+Run this *before* =--archive-done= so that when a completed level-2 parent is archived, its sub-tasks already carry their dated form. Any rewrites show up in the wrap-up commit's diff for review before push.
+
+Preview without writing:
+
+#+begin_src bash
+emacs --batch -q -l .ai/scripts/todo-cleanup.el --convert-subtasks --check todo.org
+#+end_src
+
+*** Archive completed work
+
+#+begin_src bash
+[ -f todo.org ] && emacs --batch -q -l .ai/scripts/todo-cleanup.el --archive-done todo.org
+#+end_src
+
+=--archive-done= moves every level-2 subtree whose TODO state is DONE or CANCELLED out of the project's "Open Work" section and into its "Resolved" section, subtree intact. The two sections are matched by a unique level-1 heading containing "Open Work" (case-insensitive) and one containing "Resolved" — if either is missing or ambiguous, the file is skipped with a message, no crash. Only direct level-2 children move; a DONE entry nested under an open parent stays put. Idempotent; any moves show up in the wrap-up commit's diff for review before push.
+
+Preview the moves without writing:
+
+#+begin_src bash
+emacs --batch -q -l .ai/scripts/todo-cleanup.el --archive-done --check todo.org
+#+end_src
+
+*** Flag orphaned working/ directories
+
+#+begin_src bash
+for d in working/*/; do
+ [ -d "$d" ] || continue
+ s=$(basename "$d")
+ grep -q "working/$s/" todo.org 2>/dev/null || { echo "ORPHAN: $d (no todo.org reference)"; continue; }
+ awk -v s="$s" '/^\*\* /{h=$0} $0 ~ "working/" s "/" {print (h ~ /^\*\* (DONE|CANCELLED)/ ? "CLOSED-TASK: working/" s "/ — " h : "") ; exit}' todo.org
+done
+#+end_src
+
+Report only — never move or delete anything here. A =working/<slug>/= whose backing task is closed (or which no task references at all) is a filing candidate per =working-files.md=: rename each file individually and move it flat into its permanent home, then remove the empty directory.
+
+Filing is deliberately a judgment step and stays manual. Deciding each artifact's permanent home and giving it a meaningful name is what makes =assets/= searchable later, and it's also the moment you notice which artifacts aren't worth keeping. An automatic sweep would skip exactly that review, and sweeping to =temp/= would destroy the artifacts outright, since =temp/= is cleared just below.
+
+*** Clear temp/
+
+#+begin_src bash
+[ -d temp ] && find temp -mindepth 1 -delete && echo "temp/ cleared"
+#+end_src
+
+=temp/= holds throwaway artifacts — discarded prototypes, scratch output, intermediate data (see =working-files.md=). It's gitignored in every project, so nothing here rides a commit and nothing is recoverable from git once deleted. Clearing it at wrap is what keeps ephemeral work from silting up across sessions, and it's the counterpart to =working/=, which is tracked and *never* cleared here.
+
+Two guards. Confirm before deleting if =temp/= holds anything a reasonable reader would call in-progress rather than throwaway — misfiled work belongs in =working/=, so move it there instead of deleting it. And skip the step entirely in a project where =temp/= is not gitignored, since that means the project is using the directory for something else.
+
+*** Sync child priorities
+
+#+begin_src bash
+[ -f todo.org ] && emacs --batch -q -l .ai/scripts/todo-cleanup.el --sync-child-priority todo.org
+#+end_src
+
+=--sync-child-priority= walks every heading with a priority cookie =[#A]=–=[#D]= and, for each of its direct child headings whose own priority cookie is /lower/ (later in the alphabet — D is below A), bumps the child to match the parent. Down-only: parents are never bumped up to match a higher-priority child. Children without a priority cookie are left alone, as are parents without one. The walk visits parents before descendants, so a multi-level chain (=[#A]= → =[#B]= → =[#D]=) collapses to the top priority in a single pass. Idempotent.
+
+Opt-out for deliberately-lower children: tag the heading =:no-sync:= (the literal six-character tag, including the hyphen). The script matches the tag literally on the heading line, so it works whether or not the surrounding emacs config has extended =org-tag-re= to allow hyphens.
+
+#+begin_example
+*** TODO [#D] Follow-up: VAD :no-sync:
+#+end_example
+
+Use this for =Follow-up:=, =Spike:=, =Stretch:= sub-tasks that are deliberately deprioritized below their parent — without the tag, the wrap-up would silently bump them back up.
+
+Preview the bumps without writing:
+
+#+begin_src bash
+emacs --batch -q -l .ai/scripts/todo-cleanup.el --check-child-priority todo.org
+#+end_src
+
+(=--check-child-priority= is the report-only alias for =--sync-child-priority --check=.)
+
+*** Lint org files (mechanical sweep, judgments deferred)
+
+#+begin_src bash
+if [ -n "$LINT_ORG_FOLLOWUPS" ]; then
+ followups="$LINT_ORG_FOLLOWUPS"
+elif [ -d "./inbox" ]; then
+ followups="./inbox/lint-followups.org"
+else
+ followups=".ai/lint-followups.org"
+fi
+[ -f todo.org ] && emacs --batch -q -l .ai/scripts/lint-org.el \
+ --fix --followups-file="$followups" todo.org
+#+end_src
+
+The =--fix= flag is required for the writes: lint-org's CLI default is
+report-only (a linter reports, it doesn't write), and this wrap-up pass is
+the deliberate exception that applies fixes — its diff rides the wrap-up
+commit for review.
+
+=lint-org= runs =org-lint= over =todo.org=, auto-applies four mechanical
+categories (=item-number= counters, bare =#+begin_src= → =#+begin_example=,
+multi-line planning-info merged onto one line, =**X.**= → =*X.*=), and
+appends every remaining judgment item (broken file links, invalid fuzzy
+links, verbatim-asterisk inside body prose, suspicious src-block languages)
+to the follow-ups file as a dated org section. Mechanical fixes show up in
+the wrap-up commit's diff for review before push.
+
+The follow-up path defaults to =./inbox/lint-followups.org= in the current
+project (where the next morning's daily-prep merges it in). If the project
+doesn't have an =inbox/= directory, the script falls back to
+=.ai/lint-followups.org= inside the current project. Override with
+=LINT_ORG_FOLLOWUPS=<path>= in the environment if needed — useful for
+routing all wrap-up output to a single shared inbox across projects.
+
+Each project's own =inbox/= is the right default because daily-prep reads
+that project's inbox at startup. Hardcoding a single project's path
+(formerly =~/projects/work/inbox/=) routed every project's wrap-up findings
+into the wrong inbox.
+
+Preview without writing — same flags as =--check= on the other scripts:
+
+#+begin_src bash
+[ -f todo.org ] && emacs --batch -q -l .ai/scripts/lint-org.el --check todo.org
+#+end_src
+
+The wrap-up never blocks on judgment items — they're deferred by design.
+For an interactive walk of the judgments mid-day, run =/lint-org todo.org=.
+
+*** Inbox sanity check (surface unprocessed handoffs)
+
+If the project has an =inbox/= directory, verify it holds nothing but =.gitkeep=, =lint-followups.org= (the lint-org pipeline file the next morning's daily-prep consumes), and any explicitly-deferred =PROCESSED-*= files before the wrap completes. An inbox that arrived at session start with handoffs from other projects, or that received handoffs mid-session, needs =inbox.org= process mode to run and apply its value-gate dispositions. Wrapping with a dirty inbox silently defers the work to next session and accumulates handoff debt that the sender can't see.
+
+#+begin_src bash
+unprocessed=$(find inbox -maxdepth 1 -type f \
+ ! -name '.gitkeep' \
+ ! -name 'lint-followups.org' \
+ ! -name 'PROCESSED-*' \
+ 2>/dev/null | wc -l)
+if [ "$unprocessed" -gt 0 ]; then
+ echo "wrap-up: inbox/ has $unprocessed unprocessed item(s). Run inbox.org process mode before wrapping, or explicitly defer each item with a one-line reason in the valediction."
+ find inbox -maxdepth 1 -type f \
+ ! -name '.gitkeep' \
+ ! -name 'lint-followups.org' \
+ ! -name 'PROCESSED-*' \
+ -printf ' %f\n'
+fi
+#+end_src
+
+If the count is zero or the project has no =inbox/= directory, the check is a silent no-op. If non-zero, the wrap is incomplete by default. The user resolves each item (process now, defer with reason in the valediction, or delete with rationale) before the validation checklist passes.
+
+The check exempts =lint-followups.org= explicitly because lint-org runs earlier in the same wrap-up workflow and writes its judgment items to that file in =inbox/= by design. The file is a pipeline artifact for the next morning's =daily-prep=, not a handoff that needs the value gate.
+
+This integrates with =inbox.org= process mode, which stamps =:LAST_INBOX_PROCESS:= in =notes.org='s *Workflow State* section on completion. Wrap-up doesn't double-stamp. It only ensures the inbox carries nothing but the expected pipeline artifacts at session end.
+
+*** Cross-project router (optional — route filed keepers to their home projects)
+
+Runs directly after the inbox sanity check. The split between the two: the sanity check *gates* the wrap (a dirty inbox blocks until resolved); the router is *optional* (skipping it never blocks anything — the candidates just stay local until a future wrap). Spec: =docs/specs/wrapup-routing-spec.org= (D7/D8/D9).
+
+The candidate set is exactly the local tasks carrying a =:ROUTE_CANDIDATE:= property — keepers that inbox process mode filed this session whose inferred home is another project. Never scan the standing backlog.
+
+#+begin_src bash
+.ai/scripts/route-batch --list
+#+end_src
+
+*Empty set = zero interaction.* =--list= prints nothing when there are no candidates; continue the wrap silently — no prompt, no "0 items" line.
+
+When candidates exist, surface the batch as one line per task — the task heading, the destination project, the delivery mode (=inbox-send= file handoff), and the engine's confidence — then offer exactly two options: *go* (route the whole batch) or *skip* (leave everything local). Derive each confidence label by running the engine on the task's heading + body (=python3 .ai/scripts/route_recommend.py --item "..." --exclude "$(basename "$PWD")"=); label weak matches visibly ("weak — verify the destination") so a low-confidence route gets a human glance before the keystroke.
+
+On *go*:
+
+#+begin_src bash
+.ai/scripts/route-batch --go
+#+end_src
+
+Per candidate, the helper writes the task's subtree (children ride along; =:ROUTE_CANDIDATE:= stripped, headings promoted to top level) to a one-task handoff, delivers it via =inbox-send <destination> --file= (so the =from-<this-project>= provenance is stamped and the destination's inbox process mode dispositions it as a single item), and only after a successful send removes the subtree from the local =todo.org= — a single-file local edit the wrap is already committing. A failed send leaves that task in place and exits non-zero; report it and continue the wrap. Never write the destination's =todo.org= directly; its own inbox processing files the task per its conventions.
+
+On *skip*, leave every candidate in place, marker included — they resurface next wrap.
+
+Mis-routes are recoverable: the receiving project rejects via inbox process mode's reject-from-another-project flow, which returns the item to this project's inbox with the rationale. That reject path is why removing the local source on send is safe.
+
+*** Review-habit health check (surface a slipped daily task-review)
+
+The daily task-review habit walks the open top-level tasks on a rotating cycle, stamping =:LAST_REVIEWED:= as it goes (see =task-review.org=). This check is the watchdog for that habit. When tasks have gone too long unreviewed, the habit has slipped, and the wrap-up says so in one line — it does not re-list the tasks.
+
+=task-review-staleness.sh= counts top-level =[#A]= / =[#B]= / =[#C]= tasks (TODO/DOING/VERIFY) whose =:LAST_REVIEWED:= is missing or older than the threshold. Threshold 30 days is about 2.5 review cycles of slack at the default batch size — one missed week is fine, three weeks signals a problem.
+
+#+begin_src bash
+if [ -n "$LINT_ORG_FOLLOWUPS" ]; then
+ followups="$LINT_ORG_FOLLOWUPS"
+elif [ -d "./inbox" ]; then
+ followups="./inbox/lint-followups.org"
+else
+ followups=".ai/lint-followups.org"
+fi
+if [ -f todo.org ]; then
+ stale=$(.ai/scripts/task-review-staleness.sh todo.org 30 2>/dev/null || echo 0)
+ if [ "$stale" -gt 0 ]; then
+ printf "\n* %s — Task-review health: %s top-level [#A]/[#B]/[#C] tasks unreviewed for >30 days (daily review may have slipped)\n" \
+ "$(date '+%Y-%m-%d %a')" "$stale" >> "$followups"
+ fi
+fi
+#+end_src
+
+A non-zero count writes one summary line and nothing else — the per-task walk is the review habit's job, not the wrap-up's. This supersedes the old date-coverage scan, which flagged every dateless =[#A]= / =[#B]= task on the wrong assumption that high-priority work needs a date. No-date is a valid resting state for research and watch-list tasks; staleness, not datelessness, is the real signal.
+
+** Step 3.5: Linear ticket-state hygiene (skip if project doesn't use Linear)
+
+If the project uses Linear and has any tickets currently in *Dev Review* assigned to Craig, sweep them before the wrap-up commit. The check is fast and keeps the board honest — tickets stuck in Dev Review after their PR merges hide actual work-in-progress.
+
+#+begin_src
+mcp__linear__list_issues assignee="me" state="Dev Review" limit=50
+#+end_src
+
+For each result, look up the linked PR (the =gitBranchName= field on the issue maps to a =headRefName= on the project's GitHub remote — use =gh pr list --author <github-login> --state all --json number,state,headRefName,mergedAt,title=).
+
+*Assumption:* the =gh= lookup expects a GitHub-family host. It holds today because the only Linear-using project (DeepSat) lives on =deepsat.ghe.com=, where =gh= talks to the GHE API. A future Linear-using project on a non-GitHub host (GitLab, Gitea, Bitbucket) would need a provider-agnostic PR lookup here — update this step when that happens.
+
+If a Dev-Review ticket's PR is *merged*, propose a move:
+
+- *Done* — chores, refactors, test-coverage backfills, dead-code removal, e2e-flake fixes, anything with no PM-visible behavior change. PR titles prefixed =chore:=, =test:=, =refactor:=, =docs:= almost always belong here.
+- *PM Acceptance* — real behavior fixes or new features a PM (or end user) could verify by clicking through the app. PR titles prefixed =fix:=, =feat:= usually belong here unless the change is invisible to users.
+
+When in doubt, ask Craig per ticket. Don't auto-pick. After Craig confirms, move via =mcp__linear__save_issue= with =state="Done"= or =state="PM Acceptance"=. Several can run in parallel.
+
+Skip the step entirely if the project doesn't use Linear (e.g. personal projects, the rulesets repo).
+
+** Step 4: Git commit + push
+
+*** Step 4.0: Commit template-sync churn first (consuming projects)
+
+The startup workflow's Phase A rsyncs template updates from rulesets into this project's =.ai/= (=protocols.org=, =workflows/=, =scripts/=) every session that rulesets has advanced. Nothing commits that churn, so without this step it accumulates across sessions and eventually blocks Phase A.0's auto-fast-forward (git refuses to ff a dirty tree). Commit it here, as its own =chore:= commit, before the session-work commit — so the sync stays separate from what the session actually shipped and the tree ends clean.
+
+The guard is conservative: only auto-commit a dirty synced path when it matches the rulesets canonical byte-for-byte (a modified/new file equals canonical, or a deletion pairs with a file retired upstream). If any synced path is dirty but /doesn't/ match canonical — a local hand-edit to a file that's supposed to be sync-managed — surface it and don't auto-commit. Anything outside the three synced paths is untouched here; the normal Step 4 commit and the worktree-leftover step handle it.
+
+#+begin_src bash
+# Skip in the rulesets repo itself: there .ai/ is a committed mirror of
+# claude-templates/.ai/, kept in sync by the pre-commit hook and committed
+# alongside template edits — not downstream sync churn. The presence of
+# claude-templates/.ai/ in this repo is the tell.
+if [ ! -d claude-templates/.ai ] && [ -d "$HOME/code/rulesets/claude-templates/.ai" ]; then
+ canon="$HOME/code/rulesets/claude-templates/.ai"
+ safe=1
+ commitlist=()
+ while IFS= read -r line; do
+ f="${line:3}" # strip the 2-char status + space
+ rel="${f#.ai/}"
+ if [ -e "$f" ] && [ -e "$canon/$rel" ] && diff -q "$f" "$canon/$rel" >/dev/null 2>&1; then
+ commitlist+=("$f") # modified/new here, matches canonical
+ elif [ ! -e "$f" ] && [ ! -e "$canon/$rel" ]; then
+ commitlist+=("$f") # deleted here AND retired upstream
+ else
+ safe=0 # synced path dirty but != canonical
+ fi
+ done < <(git status --porcelain -- .ai/protocols.org .ai/workflows/ .ai/scripts/)
+
+ if [ "$safe" -eq 1 ] && [ "${#commitlist[@]}" -gt 0 ]; then
+ git add -- "${commitlist[@]}"
+ git commit -q -m "chore: sync .ai tooling from templates"
+ echo "wrap-up: committed ${#commitlist[@]} synced .ai file(s) as a template-sync chore."
+ elif [ "$safe" -eq 0 ]; then
+ echo "wrap-up: synced .ai paths are dirty but not all match rulesets canonical — NOT auto-committing. Resolve manually:"
+ git status --porcelain -- .ai/protocols.org .ai/workflows/ .ai/scripts/ | sed 's/^/ /'
+ fi
+fi
+#+end_src
+
+The commit isn't pushed here — the push step below pushes the current branch, which carries both this chore commit and the session-work commit. A crashed session that never reaches wrap-up leaves the churn for the next startup, which surfaces it (see startup.org Phase C) so it never silently accumulates.
+
+*** Review changes
+
+#+begin_src bash
+git status
+git diff --stat
+#+end_src
+
+Decide the scope of the wrap-up commit. Usually everything that changed during the session goes into one commit. If anything is intentionally not part of this session's work (pre-existing WIP, unrelated files), leave it out.
+
+*** Stage
+
+Add the renamed session file and all other session changes:
+
+#+begin_src bash
+git add .ai/sessions/ [other modified paths]
+#+end_src
+
+Do NOT blindly =git add .= — review what's being staged so unrelated dirty state isn't dragged in.
+
+*** Commit
+
+Commit message rules (also see protocols.org "Git Commit Requirements"):
+
+- Subject line: concise, describes what /shipped/. Use conventional prefixes (=docs:=, =refactor:=, =fix:=, =feat:=, =chore:=) — NEVER =session:=.
+- Body: 1-3 terse sentences describing what was accomplished.
+- NO Claude Code attribution. NO =Co-Authored-By=. NO references to =notes.org=, =session-context.org=, =.ai/sessions/=, "session wrap-up", or session timestamps.
+
+*Wrap-up commits skip the inline-approval gate.* The =commits.md= rule that requires writing the message to =/tmp/commit-<slug>.md=, printing inline, and waiting for an approve / request-changes / open-in-editor response does *not* apply to wrap-up commits. The wrap-up flow is meant to be quick — Craig has already authorized the wrap by triggering the workflow ("wrap it up"), and stopping again to approve a commit message disrupts the cadence.
+
+Still apply =/voice personal= silently before committing so the message reads cleanly. Just don't print and ask. Commit directly with the cleaned message.
+
+If a wrap-up commit needs Craig's eyes for a content reason (sensitive change, unusual scope, something he flagged earlier), surface it explicitly. Otherwise commit and move on.
+
+Example:
+#+begin_example
+docs: restructure docs/ to .ai/ and unify aix+hey into ai launcher
+
+Hidden .ai/ now holds Claude tooling; project-level docs/ reserved
+for user-facing docs. Single 'ai' launcher (fzf multi + smart tmux
++ git-aware fetch/pull) replaces the aix script and hey alias.
+#+end_example
+
+Use heredoc for multi-line:
+#+begin_src bash
+git commit -m "$(cat <<'EOF'
+subject line here
+
+body sentences here.
+EOF
+)"
+#+end_src
+
+*** Push to all remotes
+
+#+begin_src bash
+git remote -v
+#+end_src
+
+Push the current branch to every remote (some repos have multiple remotes — a primary host plus one or more mirrors, or different remotes for different audiences — and the loop keeps all of them current):
+
+#+begin_src bash
+current=$(git symbolic-ref --short HEAD)
+for r in $(git remote); do git push "$r" "$current"; done
+#+end_src
+
+Then push every other local branch with a tracking upstream to its tracking remote. This catches feature branches that advanced during the session but aren't the one being wrapped up — without it, work-in-progress branches stay local-only and are at risk if the machine dies before the next wrap-up.
+
+#+begin_src bash
+git for-each-ref --format='%(refname:short) %(upstream:remotename)' refs/heads/ | \
+while read branch remote; do
+ [ "$branch" = "$current" ] && continue
+ if [ -z "$remote" ]; then
+ echo " $branch: no tracking upstream — skipped (push manually with 'git push -u')"
+ else
+ git push "$remote" "$branch"
+ fi
+done
+#+end_src
+
+Behavior:
+- *Tracked branches* → pushed to their upstream remote.
+- *Untracked branches* (no upstream set) → surfaced, not pushed. Craig sets the upstream manually with =git push -u <remote> <branch>= when he's ready. Auto-creating an upstream would commit to a remote choice the workflow can't make safely.
+- *Diverged or rejected pushes* → surface and stop. Don't force-push from this workflow; resolve manually.
+
+*** Resolve every worktree leftover
+
+#+begin_src bash
+git status --short
+#+end_src
+
+*Default policy: end every session with an empty =git status=.* The wrap is incomplete while anything remains dirty. There is no "leave it alone" default — every leftover gets an active resolution. The only way for a file to stay dirty across the wrap is the user explicitly saying "defer this one, leave it dirty." Surface each leftover with a concrete recommendation; the user has to actively opt out for the dirt to persist.
+
+This inverts the older "intentional carryover" default, which let pre-existing dirty state accumulate across sessions silently. Carryover that lives for days or weeks is almost always one of: a forgotten commit from a prior wrap, a stale change that should be discarded, or genuine in-flight work that needs an explicit stash/branch home. None of those should default to "leave it dirty."
+
+**** Three kinds of leftover
+
+| Pattern | What it is | Recommended action (apply unless user defers) |
+|---+---+---|
+| Generated, runtime, or lock files that no human edits — e.g., =.claude/scheduled_tasks.lock=, =.pytest_cache/=, build outputs, IDE state, editor swap files | *Runtime artifact* — created by tooling or the harness, not by the user, and shouldn't be tracked | Add the matching pattern to =.gitignore= (project-level, not =~/.gitignore_global=). For tracked files, =git rm --cached <path>=. Stage =.gitignore= and any =rm --cached= changes in *one* follow-up commit (=chore: gitignore X=), push. Re-run =git status= to confirm clean. |
+| Modified or created during the session but not staged into the wrap-up commit | *Forgotten change* — real session work that should have been in the wrap commit but missed it | Stage and create a follow-up commit. Don't =--amend= the wrap-up commit once pushed (diverging history without a clear win). Push the follow-up to all remotes. |
+| Was dirty at session start and still dirty at session end — work this session deliberately didn't touch | *Pre-existing dirt that needs a decision* — could be a missed commit from a prior wrap, stale abandoned work, or real in-flight work without a home | Investigate (show diff + check the originating session). Recommend one of: (a) commit now if the work is complete, (b) stash with a descriptive message if it's genuine WIP, (c) =git checkout -- <path>= / =git clean -f <path>= if stale and unwanted, (d) move to a feature branch if it's longer-running, (e) user explicitly defers and accepts the dirt. Do not silently leave dirty. |
+
+**** Per-file flow
+
+For each leftover line in =git status --short=:
+
+1. Identify which of the three kinds above it matches.
+2. State what the file is (one line) and the recommended action.
+3. Apply the action unless the user explicitly defers.
+4. Re-run =git status --short= after each follow-up commit until empty (or until every remaining line is an explicit user-deferred entry).
+
+The pre-existing-dirt case (third row) is the one this rule most cares about. Treat each pre-existing-dirty file as a question that must get an answer this session, not as "carryover that's fine to inherit." A file that was dirty for a week before this session probably isn't going to get cleaner by waiting another week. Look at the diff, check the originating session's notes, and recommend a real resolution.
+
+**** When the user defers
+
+If the user does say "leave this one dirty for now" after seeing the recommendation, that is fine — log the deferral in the valediction so the next session knows it was an explicit choice, not a miss. Format: "Deferred (per Craig's decision today): =path/to/file= — <one-line reason>". Without that note, the next session can't distinguish "we agreed to defer" from "we forgot again."
+
+** Step 5: Valediction
+
+Brief, warm closing. 3-4 sentences max.
+
+Include:
+- What was accomplished (specific, not generic)
+- What's ready for next session
+- Any critical reminders or deadlines
+
+Tone: warm but professional. No emoji unless Craig has explicitly requested. Acknowledge effort when session was long or difficult.
+
+End on a clear signoff: the *last* line of the valediction is always =session wrapped.= on its own line (lowercase, with the period, nothing after it). It's the unmistakable end-of-session marker, so don't trail it with another sentence. This is the last user-facing output — Step 6's teardown is silent.
+
+Example:
+#+begin_example
+That's a wrap. Today we restructured the entire claude-templates
+ecosystem: docs/ → .ai/ across all 23 projects, unified aix + hey
+into a single 'ai' launcher with git-aware fetch/pull, and cleaned
+up 4 code projects on velox. Both machines fully in sync.
+
+Two things to pick up next: the chime README WIP (your inline notes
+from earlier) and archsetup's layout-navigate tests. Both are
+ratio-local uncommitted state.
+
+Good session. Talk tomorrow.
+
+session wrapped.
+#+end_example
+
+** Step 6: Session teardown (mode-dependent)
+
+The last action of the wrap, and only after Step 4's commit + push is verified and the Step 5 valediction is composed. The teardown itself happens when this response ends (via the =Stop= hook), so the valediction always renders first. Act by the mode resolved up front:
+
+*** No-teardown mode
+
+Do nothing. The buffer, the =aiv-<project>= tmux session, and =claude= all stay up so the summary stays readable. The wrap is complete.
+
+*** Teardown mode (default)
+
+Confirm commit + push succeeded (Exit Criteria 5 — never tear down over unpushed work), then drop the sentinel:
+
+#+begin_src bash
+touch "/tmp/ai-wrap-teardown-$(basename "$PWD")"
+#+end_src
+
+That is the whole step. Don't run any =tmux kill-session=, =emacsclient=, or buffer kill inline — the =Stop= hook reads the sentinel when this response ends and runs =cj/ai-term-quit=, which kills the =aiv-<project>= session (taking =claude= with it), kills the vterm buffer, and restores geometry. The basename of =$PWD= is the key the hook matches, so the sentinel names the session it tears down.
+
+*** Shutdown mode
+
+Confirm commit + push succeeded, then evaluate the safety gate *before* committing to the shutdown — never power the box off out from under another live session:
+
+#+begin_src bash
+emacsclient -e '(cj/ai-term-live-count)'
+#+end_src
+
+- *Count > 1* — another ai-term session is alive. ABORT the shutdown. List the other live =aiv-*= sessions, drop *no* sentinel, and tell Craig in the valediction that it fell back to a normal wrap (no poweroff, no teardown). This gate is the load-bearing safety of the whole feature.
+- *Count = 1* — this session is the only one. Drop the shutdown sentinel:
+
+ #+begin_src bash
+ touch "/tmp/ai-wrap-shutdown-$(basename "$PWD")"
+ #+end_src
+
+ The =Stop= hook fires =cj/ai-term-shutdown-countdown= when this response ends: it re-checks the gate, runs an abort-able 10→1 countdown in the Emacs echo area (=C-g= cancels), then =sudo shutdown now=. Shutdown supersedes teardown — do *not* also drop the teardown sentinel.
+
+If =emacsclient= isn't resolvable or the daemon is down, the gate can't run — abort the shutdown, fall back to a normal wrap, and say so. Don't power off on an unverifiable gate.
+
+* Common Mistakes to Avoid
+
+1. *Skipping Step 1 (Summary)* — the file becomes the record; an empty Summary makes it hard to scan at catch-up
+2. *Vague description in filename* — =2026-04-20-updates.org= is useless next to =2026-04-20-13-45-docs-ai-migration.org=
+3. *=git add .= without review* — drags in unrelated dirty state
+4. *=session:= prefix in commit message* — explicitly forbidden; use real change categories
+5. *Claude-tooling references in commit message* — describes tooling, not what shipped
+6. *Forgetting to push to all remotes* — check =git remote -v=, push to each
+7. *Leaving =.ai/session-context.org= in place* — its presence means "interrupted session", confuses next startup
+8. *Long preachy valediction* — brief beats thorough
+9. *Leaving runtime/generated files dirty without gitignoring them* — pollutes every future =git status= and erodes trust in "working tree clean" as a signal. Fix =.gitignore= during the wrap, not later.
+10. *Treating "was dirty at session start, still dirty now" as fine by default* — that's how a forgotten commit from two sessions ago turns into "carryover" for two weeks. Every pre-existing dirty file needs an active resolution recommendation this session. Deferral is allowed only with an explicit user choice, logged in the valediction.
+
+* Validation Checklist
+
+Before considering wrap-up complete:
+
+- [ ] =.ai/session-context.org= =* Summary= section populated
+- [ ] The Summary ends with the =KB: promoted N / consulted yes-no= line (promotion check ran)
+- [ ] File renamed to =.ai/sessions/YYYY-MM-DD-HH-MM-description.org=
+- [ ] =.ai/session-context.org= no longer exists
+- [ ] =todo-cleanup.el= ran — hygiene pass + =--convert-subtasks= + =--archive-done= + =--sync-child-priority= (if =todo.org= exists at project root)
+- [ ] =lint-org.el= ran on =todo.org= — mechanical fixes applied, judgments appended to follow-ups file (if =todo.org= exists)
+- [ ] Any orphan-planning-line warnings reviewed (fix or accept)
+- [ ] Inbox carries nothing but expected pipeline artifacts (=.gitkeep=, =lint-followups.org=, =PROCESSED-*= prefixes), OR each remaining handoff has an explicit deferral logged in the valediction
+- [ ] Linear Dev-Review sweep ran; any merged-PR tickets moved to Done or PM Acceptance (skip if project doesn't use Linear)
+- [ ] Template-sync churn committed as its own =chore: sync .ai tooling from templates= (consuming projects only; skipped in rulesets), or surfaced if a synced path didn't match canonical
+- [ ] After wrap-up commit + push, =git status --short= is empty OR every remaining line has an explicit user-deferred decision logged in the valediction
+- [ ] Each leftover was investigated and the user saw a concrete resolution recommendation
+- [ ] Runtime artifacts added to =.gitignore=, follow-up commit pushed, =git status= re-verified
+- [ ] Forgotten changes committed in a follow-up and pushed
+- [ ] Pre-existing dirty files resolved (committed / stashed / discarded / moved to a feature branch) or explicitly deferred with a one-line reason in the valediction
+- [ ] Current branch pushed to ALL remotes (verified with =git remote -v=)
+- [ ] All other local branches with a tracking upstream pushed to their remote
+- [ ] Any untracked-upstream branches surfaced for manual =git push -u=
+- [ ] Step 6 teardown matches the trigger phrase: no-teardown leaves the buffer; teardown drops only =/tmp/ai-wrap-teardown-<project>=; shutdown gates on =cj/ai-term-live-count= = 1 and drops only =/tmp/ai-wrap-shutdown-<project>=
+- [ ] No teardown/shutdown sentinel was dropped before commit + push was verified
+- [ ] Shutdown aborted (fell back to normal wrap, logged in the valediction) when another =aiv-*= session was live or the gate couldn't run
+- [ ] Commit message follows format (no =session:=, no Claude attribution)
+- [ ] Valediction delivered (brief, specific, warm)