Skip to content

feat(session-flow): adopt claim-provenance and constraint re-scan rules from handoff audit - #1560

Merged
kyle-sexton merged 3 commits into
mainfrom
feat/1477-handoff-hardening-audit
Jul 26, 2026
Merged

feat(session-flow): adopt claim-provenance and constraint re-scan rules from handoff audit#1560
kyle-sexton merged 3 commits into
mainfrom
feat/1477-handoff-hardening-audit

Conversation

@kyle-sexton

Copy link
Copy Markdown
Contributor

Closes #1477

What

Hardening audit of session-flow:handoff against the mattpocock/skills handoff-failure corpus (#186 / #306 / #617 / #482, all fetched live 2026-07-26). Per-finding verdicts recorded on #1477 (audit comment): finding 1 covered (two sub-items adopted/rejected), finding 2 adopted, finding 3 covered, finding 4 covered (cleanup sub-item rejected). This PR lands the two adoptions:

  • Claim provenance (reference/structure.md): a status claim may be stated plainly only when this session verified it; anything inherited (a prior handoff's assertion, an issue label, a remembered state) carries an explicit UNVERIFIED (<source>) marker — an inherited claim is a claim to falsify, not a fact to forward. Closes the laundering gap behind upstream's real incident (an unverified "not built yet" forwarded as fact caused a feature to be rebuilt).
  • Constraints re-scan (reference/structure.md): before closing "Constraints that must hold", re-scan the conversation for but / except / unless / "the exception is" / "the corner case" — mid-discussion constraints that never rose to a top-line bullet are the category a resuming session ships as a bug.

Plus session-flow 0.17.12 → 0.17.13 and the CHANGELOG entry.

Local review outcomes (obtained before PR creation)

  • /code-review (headless, claude -p, diff main...HEAD): 1 finding — the provenance paragraph's "(see the evidence rule in the citing skill's gotchas)" pointed at a file one of the two citing skills doesn't ship, and load-on-demand for the other. Fixed in 805de420 by dropping the cross-reference (the evidence rule already lives in structure.md's own Completion criteria section). Review also explicitly cleared: changelog parity (--check and --check-bump pass), patch-bump precedent, UNVERIFIED (<source>) reusing the existing repo-wide marker convention, line-wrap conformance, and non-duplication vs reanchor/orient read-side checks.
  • /security-review (headless, claude -p): no security vulnerabilities identified, confidence 0.95 — diff introduces no executable code, no shell invocation, no path construction, no credential handling; prose-only guidance changes.

Verification

  • plugins/session-flow/skills/handoff/evals/evals.json schema-valid against plugins/skill-quality/reference/evals.schema.json (the repo CI's eval verification bar).
  • markdownlint clean on both edited files.
  • Skill contract gate does not fire (reference-doc-only diff; no files under skills/ changed).

Related

🤖 Generated with Claude Code

https://claude.ai/code/session_018qLeNKmcBFxZgsfEksLomX

kyle-sexton and others added 2 commits July 26, 2026 12:28
…es from handoff audit (#1477)

Audit of session-flow:handoff against the mattpocock/skills handoff-failure
corpus (#186/#306/#617/#482, fetched live) found two write-side gaps with
demonstrated upstream failure modes and no existing guard in the template:

- Claim provenance: inherited claims (prior handoff assertions, issue labels,
  remembered state) must carry an explicit UNVERIFIED (<source>) marker — an
  inherited claim is a claim to falsify, not a fact to forward. The existing
  fresh-reads discipline governed only what the writing session could probe.
- Constraints re-scan: before closing "Constraints that must hold", re-scan
  the conversation for but/except/unless/"the exception is"/"the corner case"
  — mid-discussion constraints that never rose to a top-line bullet are the
  category a resuming session ships as a bug.

The other audited findings were already covered (decision-archive template
sections 7/8/9 with anti-summary framing; resume prompt leads with an execute
instruction; durable <memory_dir>/handoffs/ location with chain continuity);
verdict detail recorded on #1477.

Verification: markdownlint clean on both edited files; handoff evals.json
schema-valid against skill-quality's evals.schema.json (repo CI's eval bar);
skill contract gate does not fire (no files under skills/ changed).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018qLeNKmcBFxZgsfEksLomX
…nance rule

The parenthetical pointed at "the citing skill's gotchas", but structure.md
has two citing skills and continue-in-background ships no gotchas file; for
handoff the file is load-on-demand, so the delegated rule is not guaranteed
in context. The met/unmet evidence rule the reference gestured at already
lives in this document's own Completion criteria section.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018qLeNKmcBFxZgsfEksLomX
@claude

claude Bot commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 1m 43s —— View job


PR Review

  • Gather context and read changed files
  • Review reference/structure.md additions (claim-provenance + constraint re-scan)
  • Review CHANGELOG.md entry for correctness and format
  • Review plugin.json version bump
  • Check alignment with CLAUDE.md guidelines
  • Post final review

Overall: approve. This is a tight, well-scoped change. No blocking issues. A few observations below.


reference/structure.md

Claim-provenance rule (lines 43–49)

The rule is correctly placed at the body-sections level (before any ### subsection), following the same bold-paragraph convention used by the adjacent "Layering is not truncation" and "Every section is always present" rules. The explicit Completion-criteria callout at the end of the paragraph is a useful reminder since [x]/[ ] marks are the most visually prominent place an inherited claim could silently launder.

The scope is intentionally narrow: "A status claim" rather than "any claim." That's the right call — it matches the upstream failure mode (state-of-the-world assertions), not the wider set of decisions or rationale that other sections own. The UNVERIFIED (<source>) marker reuses an established repo-wide convention, confirmed across 11 files.

Constraint re-scan rule (lines 85–88)

Signal-word list (but, except, unless, "the exception is", "the corner case") is concrete and actionable — no exhaustiveness needed here, these are the highest-yield patterns. Placement after "Only things that would actually break something" flows naturally: the rule first defines what belongs in the section, then tells the writer how to catch what they missed.

One note: "the corner case" uses a comma-less list through the italic phrases but switches to quoted strings for the last two. This is stylistically intentional (the italic phrases are single words; the quoted ones are multi-word phrases), but a reader skimming quickly could miss the last two entries since the visual rhythm shifts. Low-severity — the content is clear.


CHANGELOG.md

(lines 3–23)

Entry is accurate, the sub-bullets' stated rationale ("nothing in the existing template guarded it", "no recall step for constraints buried inside accepted decisions") matches what was added. Format is consistent with adjacent entries. [0.17.13] header carries no date — consistent with the immediately prior [0.17.12] entry (both are dateless), so no inconsistency introduced.


plugin.json

(line 5)

Patch bump 0.17.12 → 0.17.13 is the correct semver tier for additive documentation-only additions. No new skills or config keys, so the description and userConfig blocks are correctly unchanged.


No security issues. Prose-only guidance changes with no executable code, shell invocation, path construction, or credential handling. Consistent with the /security-review outcome noted in the PR body.

@claude

claude Bot commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 1m 11s —— View job


Security Review — PR #1560

  • Load tools
  • Fetch PR diff
  • Read changed files
  • Apply security analysis
  • Post findings

No security vulnerabilities identified.

This PR is a prose-only diff across three files. The security surface is minimal; here is the full reasoning for each changed file.

plugins/session-flow/.claude-plugin/plugin.json

Version field bumped 0.17.12 → 0.17.13. No schema fields added or removed, no new permission grants, no new userConfig keys, no MCP server entries. The change is a one-line string mutation with no security impact.

plugins/session-flow/CHANGELOG.md

Plain-text prose. No executable content, no templating, no credential references. No security impact.

plugins/session-flow/reference/structure.md

Two paragraphs added; one word changed in a follow-up fix. Analyzed by threat class:

Threat class Finding
Injection (command / path / template) No user-controlled input is introduced. The UNVERIFIED (<source>) marker is a document convention, not an executed template. The existing bash write-procedure block (lines 274–323) was not modified by this PR.
Credential / secret handling None introduced.
Trust-boundary weakening The provenance rule strengthens trust boundaries: inherited claims now require an explicit UNVERIFIED (<source>) marker rather than passing silently as facts. This is a security-positive change.
Logic flaw creating an exploitable condition The provenance rule and constraint re-scan rule are advisory guidance for AI agents writing handoff documents. No branch, gate, or enforcement mechanism is introduced that could be bypassed or manipulated.
Authorization / access-control gap Not applicable — reference documentation with no access control surface.
GitHub Actions dangerous patterns No .github/workflows files changed.
Supply-chain / dependency risk No package pins, action refs, or external dependencies touched.

The UNVERIFIED (<source>) convention was already present repo-wide (the PR description confirms this is a reuse of an existing marker, not a new convention). The constraint re-scan keyword list (but, except, unless, "the exception is", "the corner case") is plain prose with no runtime evaluation path.

Confidence: 0.97. The only residual uncertainty is that I reviewed documentation-layer guidance rather than executable code — there is no runtime surface to trace a data-flow through, so the confidence ceiling for a purely-prose diff is inherently below 1.0.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 805de420ef

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread plugins/session-flow/reference/structure.md Outdated
Comment thread plugins/session-flow/reference/structure.md Outdated
…ssless transcript post-compaction

Two review-thread gaps in the handoff-hardening PR (#1477):

- Claim provenance lived only in structure.md, which the prompt-only
  path never walks — an inherited status could ride an inline
  remaining-work bullet with no UNVERIFIED (<source>) marker. Hoisted
  the rule to save-point.md as a "mandatory on BOTH paths" section
  (mirroring the existing redaction pass), with structure.md and
  skills/handoff/SKILL.md's checklist (both full and prompt-only)
  pointing at it. continue-in-background inherits the fix for free —
  its own checklist already defers to the engine doc's save-point
  items rather than restating them.
- The constraints re-scan targeted "the conversation," but after an
  unexpected compaction that's the summarizer's output, not the
  original turns it's supposed to catch caveats in. The section must
  now say explicitly whether it re-scanned the lossless on-disk
  transcript (retro's parser reads the same record) or is disclosing
  that pre-compaction turns went unscanned — silence reads as the
  latter never having happened, never as a pass.

Verification: markdownlint clean; skill-quality's check-changed-skills.sh
and check-skill-portability.sh pass against origin/main for the
changed handoff skill file.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@claude

claude Bot commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 1m 26s —— View job


PR Review — Follow-up Push (a3fe8cc)

  • Read changed files in current HEAD
  • Check what the latest commit (a3fe8cc) added relative to the Codex findings
  • Assess whether Codex P2 findings are now addressed
  • Post review summary

Overall: approve. Both Codex P2 findings are directly addressed by this commit. No new issues introduced.


Codex P2.1 — Provenance marking on prompt-only path

Finding: The provenance rule lived only in structure.md, which the prompt-only path never walks; an inherited status could ride an inline remaining-work bullet with no UNVERIFIED (<source>) marker.

Fix assessment: Cleanly resolved.

  • The rule was hoisted to save-point.md's new "Claim provenance" section, labeled "mandatory on BOTH paths" — the same framing used by the adjacent redaction pass. Structural parity with the redaction pattern is the right call; both are pre-emit gates.
  • structure.md now forwards to save-point.md for the full-path body sections rather than re-stating the rule.
  • SKILL.md's prompt-only checklist gets its own tick with inline-bullet-specific language, closing the gap identified by Codex. The commit message correctly notes that continue-in-background inherits the fix for free through its deferred-to-engine-doc pattern.

Codex P2.2 — Re-scan the lossless transcript after compaction

Finding: After an unexpected compaction, the model-visible conversation is the summarizer's output. The constraint re-scan as written cannot recover caveats the summarizer discarded.

Fix assessment: Cleanly resolved with appropriate tradeoffs.

The new structure.md compaction block establishes a binary disclosure requirement:

  1. Re-scanned the lossless on-disk transcript — with an actionable pointer to the retro parser and a worked example (/session-flow:running-retro "2. Resolve inputs")
  2. Did not re-scan, and the section says so explicitly

The "detect from a concrete signal, never infer" instruction is the right call: it prevents false positives (spurious disclosures when no compaction happened) without creating a third silent option. If a compaction is not surfaced by any visible signal, the rule correctly can't guard against it — but when one IS visible (the primary use-case Codex flagged: SKILL.md line 78's "last turn had an unexpected compaction"), the binary disclosure kicks in.

The worked example paths (retro's parser, /session-flow:running-retro) are concrete enough for a live agent to follow.


Minor observations

  • The save-point.md "Claim provenance" section correctly handles prompt-only's specific failure mode: it names the inline remaining-work bullet explicitly, not just "the handoff artifact."
  • The constraint re-scan rule tightened "re-scan the conversation" to just "re-scan for …" — sensible now that "the conversation" is defined downstream in the compaction block rather than assumed to be a reliable surface.
  • CHANGELOG for [0.17.13] is updated correctly in the same commit, with both additions described accurately; no version bump needed (this is still 0.17.13 material).

No issues requiring another revision.

@claude

claude Bot commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 1m 33s —— View job


Security Review — PR #1560

  • Load tools
  • Fetch PR diff
  • Read changed files
  • Apply security analysis
  • Post findings

No security vulnerabilities identified.

Five files changed across three commits; all are prose-only. Full reasoning by threat class:

plugins/session-flow/.claude-plugin/plugin.json

Version field bumped 0.17.12 → 0.17.13. No permission grants added or removed, no new userConfig keys, no MCP server entries, no schema fields altered. Zero security surface.

plugins/session-flow/CHANGELOG.md

Plain-text prose. No executable content, no credential references, no evaluated templates. Zero security surface.

plugins/session-flow/reference/save-point.md — new "Claim provenance" section (lines 63–76)

Threat class Finding
Injection No user-controlled input is introduced. UNVERIFIED (<source>) is a documentary convention written by the model into a markdown file; <source> is free-form prose, not an evaluated template or shell expansion. No injection surface.
Trust-boundary weakening The opposite: the rule narrows trust from inherited assertions to this-session-verified facts. Anything that does not meet that bar must carry an explicit marker. Security-positive.
Credential / secret handling None introduced. The existing redaction pass (lines 53–61, unchanged) already gates secrets before any write or prompt emission; the new provenance rule operates on logical state-of-the-world claims, not credentials.
Logic flaw The rule governs both full and prompt-only paths explicitly (line 71: "This governs both paths, not just the full path's body sections"). The prior Codex finding (prompt-only gap) was addressed in a3fe8cc — the rule now lives in save-point.md where both paths walk it, not solely in structure.md. No residual gap.
Authorization / access control Not applicable — guidance prose.

plugins/session-flow/reference/structure.md — provenance cross-reference + compaction re-scan rule (lines 43–47, 84–106)

Threat class Finding
Injection No executable code added. The compaction section (lines 84–106) references ${CLAUDE_PLUGIN_ROOT}/skills/retro/scripts/parse_transcript.py — this is a plugin-controlled path variable, not user-supplied input; no injection surface.
Compaction-aware re-scan (lines 89–106) The rule requires the section to disclose one of two things: (a) the lossless on-disk transcript was re-scanned, or (b) only the model-visible (possibly compacted) conversation was scanned and it says so explicitly. Both branches are valid; neither creates a bypassable gate or an exploitable condition — the rule is advisory guidance, not an enforcement mechanism with a security-meaningful failure mode.
Trust-boundary Provenance cross-reference (line 43) points at save-point.md's "Claim provenance" rule, tightening rather than loosening the boundary.
Supply chain No action refs, package pins, or external dependencies touched.

plugins/session-flow/skills/handoff/SKILL.md — four checklist lines (lines 127, 141–142)

New tick items add "Claim provenance applied" to both the full-path and prompt-only post-write checklists, each referencing the engine doc. These are model-facing audit gates. No executable code, no data flow, no security impact.


Confidence: 0.97. Residual uncertainty is the nature of reviewing AI-guidance prose rather than executable code — there is no runtime data-flow to trace, so the ceiling for a purely-prose diff is inherently below 1.0. Within that ceiling I see no issue.

@kyle-sexton
kyle-sexton merged commit 5db4e98 into main Jul 26, 2026
31 checks passed
@kyle-sexton
kyle-sexton deleted the feat/1477-handoff-hardening-audit branch July 26, 2026 17:20
kyle-sexton added a commit that referenced this pull request Jul 29, 2026
…ow continuation router (#1603)

Closes #1475
Closes #1476

## What

One branch for the companion pair, per both issues' "likely one PR"
note.

**context-guard 0.4.0 — zone-crossing hooks + window-class token bands
(#1475).**

- `hooks/hooks.json` registers four fail-open handlers, each with a
co-located contract-test suite: `zone-crossing-inject.sh` (PostToolBatch
+ UserPromptSubmit; injects continuation guidance via
`additionalContext` once per transition into a worse zone — silent on
unchanged/improving/`unknown`; PostToolBatch's once-per-batch semantics
replace the per-tool dedupe a PostToolUse design would have needed),
`zone-gate.sh` (PreToolUse over
`Write|Edit|NotebookEdit|Agent|Workflow`; active only in `blocking` mode
on a fresh dumb-zone snapshot past a grace budget; handoff-path writes,
reads, Bash, and Skill never gated — no deadlock by construction),
`post-compact-mark.sh` (PostCompact; persists the evidence-degraded
marker, re-arms the grace budget, prunes stale markers).
- Resolver v2: two zone shapes combined conservatively — percentage
bands over `used_percentage` (distance to compaction; upstream computes
it input-only) and window-class token bands over occupancy =
`total_input_tokens + total_output_tokens` (distance to quality loss;
200k class 100k/160k, 1M class 200k/400k — declared judgment defaults,
provenance table on #1475). Combination rule stated verbatim in the
reader contract; plausibility guard covers the pre-2.1.132 cumulative
token-field semantics; `zones.json` gains an optional
per-shape-validated `token_bands` (absent = zero-config, every v1 file
keeps working); percentage keys retained with a recorded retirement
trigger.
- Config per `docs/conventions/hook-config-delivery` channel B with
in-script defaults; three new `userConfig` options; telemetry producers
registered with data schemas; both known inliners migrated
(plugin-quality (now 0.3.0) context-gate + setup seeder) and the reader
contract's promised consumer drift-check lane now actually exists
(`plugin-quality/scripts/zones-inline-drift.test.sh`, runs in
plugin-gate).

**session-flow 0.17.19 — workflow end-of-phase continuation router
(#1476).**

- New `context/continuation.md` spoke + `continue` argument mode + a
default-mode phase-boundary step. Outcome set derived from the
mechanisms the plugin actually installs plus built-ins (continue /
`/clear` / handoff / continue-in-background / clean-stop / `/compact`);
`reconcile`/`orient` deliberately non-terminals; every ordering edge
carries its stated purpose (machine-loss asked first, zero-cost exits
before writing mechanisms, compact last as the model-written lossy
summary at the least-intelligent point — tradeoff pointer to handoff's
"Fork beats compaction when the window is deep", not a restatement).
Zone input presence-gated on the reader contract with **no inlined band
values**; honors the evidence-degraded marker. Documents the worker
handoff-relay convention (worker writes its own handoff, returns the
path only).

**CI fix (needed by this PR, correct independently):**
`check-shell-portability.sh` now exempts registered cross-plugin sync
copies (`scripts/cross-plugin-source-registry.txt`) — a synced
`hooks/hook-utils.sh` copy can never carry a local fix or annotation, so
the source is where the gate belongs; surfaced by this PR adding the
first new copy since the GNU-regex-escape tokens went active (line
1114's bash glob `[\<\>]` is not a GNU regex escape). Repro-first suite
case included.

## Local review outcomes (obtained before PR creation)

- **/code-review** (headless, isolated worktree, full diff vs main): **5
findings, all fixed in `40aa5b69` with failing-test-first repros**, plus
2 suspicions it checked and cleared itself. (1) PostCompact marker
silently unwritten for realistic payload sizes (measured 80KB+ lost to
the single bounded stdin read on Git Bash pipes) → all three hooks now
use a plugin-local chunked drain loop (`hooks/payload.sh`, the tee's
proven `read -N` pattern) with 130–150KB regression tests; (2) same root
cause failed the blocking gate open for exactly the biggest writes
(verified: 2.8KB Write denied, 133KB Write allowed) → same fix +
regression test; (3) the evidence-degraded marker was write-only and the
grace reset let compaction disarm the gate → both zone consumers now
treat a marked session as effectively dumb regardless of the resolved
word, per the contract's own rule; (4) large batch payloads could skip
injections → chunked reader; (5) `.compacted` markers never pruned →
14-day sweep matching the tee's. An earlier same-content review pass on
the pre-rebase branch had also run every repo gate itself (portability
incl. its 108-case self-test, silent-skips, changelog parity,
validate-plugins, all five new/changed suites) — all pass.
- **/security-review** (headless, two runs — pre-rebase full diff, then
final HEAD incl. the CI-checker change): **no vulnerabilities at the
reporting bar in either run**. Cleared explicitly: session_id path
containment at all four entry points (hostile-id regression tests),
hand-built JSON via charset-constrained values + `jq --arg`, no
reflection of untrusted payload content into the model channel, strict
ISO gate before `date -d`, no dynamic command construction, `umask
077`/`chmod 700` on state writes, and the portability exemption opens no
silent-divergence hole (byte-identity gate owns those copies).
Deliberate non-findings recorded in the review outputs (gate-bypass
shapes are quality-control, not a security boundary; documented
fail-open).

## Verification

- New/updated suites all green at the current head:
`context-zone.test.sh` 73/73, `zone-gate.test.sh` 24/24,
`zone-crossing-inject.test.sh` 18/18, `post-compact-mark.test.sh` 16/16,
`statusline-tee.test.sh` 47/47, `zones-inline-drift.test.sh` 11/11,
`check-shell-portability.test.sh` 109/109.
- `validate-plugins.sh` clean; `sync-hook-utils.sh --check` reports all
15 copies matching `lib/`; portability vs `origin/main`, silent-skip,
cross-plugin-source-drift, plugin-manifest-presence, skill-leaf-names,
and changelog-parity (`--check` and `--check-bump`) all clean. The
repo's own `plugin-gate` on CI is the authoritative full-suite run.
- Rebased/merged onto main repeatedly as the base moved. Version lanes
re-slotted each time: plugin-quality 0.2.0→0.3.0 atop upstream 0.2.2;
session-flow walked 0.17.14→0.17.19 as main shipped 0.17.17 and 0.17.18
underneath this branch.

## Review-queue drain

All ten Codex review threads fixed and resolved, each verified against
the merged tree rather than taken on the commit message: the gate
grace-counter race (replaced with an O_APPEND byte counter), the
`08`-as-octal grace budget, the pre-2.1.132 cumulative-token semantics
(now gated on an explicit `cli_version` floor), the reader contract's
capability table (now per-shape, so the table and the combination rule
can no longer derive different zones), the setup skill conflating
registration with activation, leftover diff3 merge markers, the
unreachable `continue-in-background` outcome (explicit-background is now
question 1), the injector's write-only zone state, and the PostCompact
marker's false `status:ok`.

Three further findings arrived in a review body rather than as threads.
Two were real and are fixed here: both stateful hooks fell back to a
`.`-relative state root, and zone-gate's handoff-exemption path
extraction bypassed the file's own jq helper. One was a false positive —
the portability checker's registry comparison quotes its RHS, so
globbing is already inactive; a repro-first case now pins that. Details
and the platform probe are in the PR comments.

## Related

- #1475, #1476 (implemented here); #1477 / PR #1560 (merged sibling);
#1478 (research these hooks build on — statusline-tee remains the
interactive source, hooks fail open elsewhere); #1479 (orchestrate
audit; the router documents the handoff-relay convention it flagged).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

https://claude.ai/code/session_018qLeNKmcBFxZgsfEksLomX

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
kyle-sexton added a commit that referenced this pull request Aug 19, 2026
… caveat (#3019)

Closes #2956

## Summary

Implements the AI Hero course lane 1 wording changes for
`session-flow:handoff`: a routing-signals table mapping situation to
save-point form, the session-chain/retrospective use named first-class
in "When to invoke", the general do-not-duplicate rule, the
promote-content-never-file rule, and the worktree caveat in the engine
doc's destination section. `find-handoff`'s detection contract is
untouched.

## Fix

- **`skills/handoff/SKILL.md` — "When to invoke"**: names the
session-chain use first-class (the escape-and-resume cadence whose
handoff files carry the `session_id`/`previous_handoff` chain
`/session-flow:retro` walks for retrospective reconstruction) alongside
the upstream boundary-crossing taxonomy (colleague, other repo or
checkout, other agent, forked mid-phase side task) — the UNION the lane
decided. A new "Routing signals — which form to use when" table maps:
deep-window escape with chain value → full file (default); small
follow-ups, no chain value → prompt-only with its documented retro-gap
cost; differing next-session focus → either form plus the purpose
argument; AFK-but-work-continues → the sibling `continue-in-background`
skill (explicit user request only); machine may go away → `clean-stop`
semantics; boundary crossing → full file plus purpose plus the `Handoff
origin:` line. The table's AFK row absorbs the former standalone "Going
AFK" paragraph (same content, one home).
- **`skills/handoff/SKILL.md` — new "Reference other artifacts; promote
durable value" section**: states the do-not-duplicate rule mirroring
upstream (content captured in specs, plans, ADRs, issues, commits, or
diffs is referenced by path or URL, never restated — the existing
"Summarize; never transcribe" per-section guidance stated as a general
rule) and the promote-content-never-file rule (durable value is promoted
into a committed artifact — topic contract, issue, PR body — while the
handoff file stays ephemeral and uncommitted; cleanup of `handoffs/`
remains user-controlled removal, never silent expiry — no expiry
behavior added anywhere, confirming the #1477 finding-4 rejection).
- **`reference/save-point.md` — "Where save-points live"**: adds the
worktree caveat — a save-point written inside a `git worktree` checkout
resolves its memory root within that worktree and dies with `git
worktree remove`; acceptable only when the worktree completes as a
merged PR unit; when pausing un-merged worktree work, write from the
main checkout or rely on `/session-flow:clean-stop`'s
preserve-before-remove step (which already inspects ignored content
before removal and names "generated handoff data" explicitly — the
existing cross-reference from worktree-touching tooling).
- **Versioning**: session-flow `0.25.0` → `0.26.0` with the matching
CHANGELOG entry.

## Verification

- `bash scripts/validate-plugins.sh` — all manifests and the catalog
validated.
- `npx markdownlint-cli2` on the four touched markdown files — 0 issues.
- `bash scripts/check-changelog-parity.sh --check`, `--check-bump
origin/main`, `--check-order` — all pass (83 changelogs, newest-first,
bump matched by entry).
- `bash scripts/check-changed-skills.sh origin/main` — PASS, 0 errors
(one soft-target warning: SKILL.md 230/500 lines against the 200-line
soft target; the local mawk `REcompile` panics are the known #3005
artifact, non-failing).
- Acceptance criteria walked: routing table present with session-chain
use first-class; do-not-duplicate rule stated; worktree caveat in the
destination section; promote rule stated with no expiry behavior;
`skills/find-handoff/` and the detection-contract section of
`save-point.md`'s resume-prompt shape untouched by the diff.

## Related

Refs #2899 (lane 1 decision record), `docs/upstream/aihero-course.md`
lane 1 rows. Refs #1477 / PR #1560 (cleanup sub-item rejection this
confirms). Refs #2955 / PR #3017 (purpose argument, sibling item the
routing table's purpose rows build on). Refs #3005 (mawk artifact noted
in Verification).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

https://claude.ai/code/session_01QbfCrj3X9FfGL7VRZYmrn4

---
_Generated by [Claude
Code](https://claude.ai/code/session_01QbfCrj3X9FfGL7VRZYmrn4)_

---------

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

session-flow/handoff: hardening audit vs mattpocock/skills handoff issue corpus (#186/#306/#617/#482)

1 participant