@erclx/canon 4.121.0 → 4.123.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. package/claude/.claude-plugin/plugin.json +1 -1
  2. package/claude/skills/auto-ship/SKILL.md +6 -5
  3. package/claude/skills/auto-ship/references/tier-failures.md +7 -4
  4. package/claude/skills/backlog-triage/REQUIREMENT.md +47 -0
  5. package/claude/skills/backlog-triage/SKILL.md +139 -0
  6. package/claude/skills/canon-rollout/SKILL.md +6 -6
  7. package/claude/skills/context-fold/REQUIREMENT.md +75 -0
  8. package/claude/skills/context-fold/SKILL.md +162 -0
  9. package/claude/skills/{docs-fold → context-fold}/references/anchor-sweep.md +1 -1
  10. package/claude/skills/{docs-fold → context-fold}/references/classify.md +4 -2
  11. package/claude/skills/context-fold/references/context-refresh.md +48 -0
  12. package/claude/skills/context-fold/references/promoted-pages.md +29 -0
  13. package/claude/skills/context-fold/references/receipt-sweep.md +43 -0
  14. package/claude/skills/context-fold/references/unusable-baseline.md +25 -0
  15. package/claude/skills/{docs-fold → context-fold}/references/wireframe-sweep.md +1 -1
  16. package/claude/skills/docs-fold/REQUIREMENT.md +8 -58
  17. package/claude/skills/docs-fold/SKILL.md +3 -278
  18. package/claude/skills/docs-sync/REQUIREMENT.md +1 -1
  19. package/claude/skills/docs-sync/SKILL.md +1 -1
  20. package/claude/skills/draft-context/REQUIREMENT.md +2 -2
  21. package/claude/skills/draft-context/SKILL.md +3 -3
  22. package/claude/skills/draft-docs/REQUIREMENT.md +1 -1
  23. package/claude/skills/draft-ready/SKILL.md +1 -1
  24. package/claude/skills/draft-wireframes/REQUIREMENT.md +1 -1
  25. package/claude/skills/draft-wireframes/SKILL.md +2 -2
  26. package/claude/skills/git-pr/SKILL.md +8 -146
  27. package/claude/skills/git-pr/references/evidence.md +114 -0
  28. package/claude/skills/git-pr/references/labels.md +20 -0
  29. package/claude/skills/git-pr/references/task-number.md +26 -0
  30. package/claude/skills/git-ship/SKILL.md +5 -4
  31. package/claude/skills/memory-capture/REQUIREMENT.md +2 -2
  32. package/claude/skills/memory-capture/SKILL.md +19 -9
  33. package/claude/skills/memory-review/REQUIREMENT.md +5 -3
  34. package/claude/skills/memory-review/SKILL.md +22 -107
  35. package/claude/skills/memory-review/references/later-phases.md +111 -0
  36. package/claude/skills/memory-review/references/receipt-format.md +19 -3
  37. package/claude/skills/plan-feature/REQUIREMENT.md +1 -1
  38. package/claude/skills/review-address/REQUIREMENT.md +1 -1
  39. package/claude/skills/review-address/SKILL.md +1 -1
  40. package/claude/skills/review-branch/SKILL.md +1 -1
  41. package/claude/skills/role-orchestrator/SKILL.md +2 -2
  42. package/claude/skills/role-orchestrator/references/orchestrator-dispatch.md +1 -1
  43. package/claude/skills/role-orchestrator/references/orchestrator-parked.md +4 -2
  44. package/claude/skills/role-orchestrator/references/orchestrator-refill.md +2 -2
  45. package/claude/skills/session-resume/REQUIREMENT.md +1 -1
  46. package/claude/skills/session-resume/SKILL.md +4 -3
  47. package/claude/skills/session-worktree/SKILL.md +4 -10
  48. package/claude/skills/task-board/REQUIREMENT.md +1 -1
  49. package/claude/skills/task-board/SKILL.md +7 -81
  50. package/claude/skills/task-board/references/archive.md +54 -0
  51. package/claude/skills/task-board/references/decline.md +40 -0
  52. package/claude/skills/teach-workspace/SKILL.md +8 -105
  53. package/claude/skills/teach-workspace/references/lesson-craft.md +51 -1
  54. package/claude/skills/teach-workspace/references/promotion.md +41 -0
  55. package/docs/agents/architecture-record.md +26 -0
  56. package/docs/agents/commands.md +87 -154
  57. package/docs/agents/context-audit-checks.md +2 -20
  58. package/docs/agents/context-audit.md +1 -1
  59. package/docs/agents/context-classify.md +1 -1
  60. package/docs/agents/drift-surfaces.md +192 -0
  61. package/docs/agents/index.md +12 -4
  62. package/docs/agents/install-and-sync.md +2 -181
  63. package/docs/agents/markdown-audit-weight.md +73 -0
  64. package/docs/agents/markdown-audit.md +3 -90
  65. package/docs/agents/migrate.md +34 -0
  66. package/docs/agents/records-stale.md +62 -0
  67. package/docs/agents/records.md +5 -1
  68. package/docs/agents/sandbox.md +1 -1
  69. package/docs/agents/tasks-archive.md +81 -0
  70. package/docs/agents/tasks-plans.md +149 -0
  71. package/docs/agents/tasks-validate.md +131 -0
  72. package/docs/agents/tasks.md +7 -334
  73. package/docs/target-projects.md +3 -3
  74. package/docs/workflow/ai-workflow.md +34 -29
  75. package/docs/workflow/operating-model.md +1 -1
  76. package/governance/rules/claude/555-tasks.md +2 -1
  77. package/governance/rules/core/045-memory.md +1 -1
  78. package/package.json +1 -1
  79. package/src/claude/cases/setup.ts +1 -1
  80. package/src/claude/cases/workflow.ts +22 -1
  81. package/src/commands/records.ts +146 -0
  82. package/src/commands/sandbox.ts +6 -4
  83. package/src/commands/tasks.ts +39 -29
  84. package/src/context/classify/extract.ts +1 -1
  85. package/src/context/classify/ollama.ts +1 -1
  86. package/src/context/classify/run.ts +1 -1
  87. package/src/gate/measures.ts +1 -1
  88. package/src/gate/stages.ts +1 -0
  89. package/src/migrate/skill-names.ts +15 -2
  90. package/src/records/stale.ts +243 -0
  91. package/src/sandbox/expect.ts +1 -1
  92. package/src/tasks/archive.ts +223 -92
  93. package/src/tasks/reach.ts +1 -1
  94. package/src/tasks/record.ts +60 -17
  95. package/src/tasks/validate.ts +37 -4
  96. package/standards/board.md +136 -0
  97. package/standards/commit.md +5 -0
  98. package/standards/groundwork.md +25 -36
  99. package/standards/index.md +2 -1
  100. package/standards/memory.md +13 -1
  101. package/standards/plan.md +20 -34
  102. package/standards/readme.md +8 -77
  103. package/standards/requirements.md +2 -2
  104. package/standards/tasks.md +19 -126
  105. package/standards/versioning.md +1 -1
  106. package/tooling/astro/reference.md +1 -1
  107. package/tooling/base/configs/.husky/post-merge +1 -1
  108. package/tooling/base/configs/commitlint.config.js +27 -1
  109. package/tooling/base/reference.md +1 -1
  110. package/tooling/claude/reference.md +1 -1
  111. package/tooling/go/reference.md +1 -1
  112. package/tooling/nextjs/reference.md +1 -1
  113. package/tooling/php/reference.md +1 -1
  114. package/tooling/python/reference.md +1 -1
  115. package/tooling/vite-react/reference.md +1 -1
  116. package/tooling/web/reference.md +1 -1
@@ -9,13 +9,15 @@ description: What memory review is for, the gaps it closes, and why every action
9
9
 
10
10
  Without this skill, the memory folder grows and never drains. Entries pile up restating rules a durable surface already carries, nothing decides which memory has earned a place in one, and a rule that does get promoted arrives verbatim in a file whose voice it does not match. The folder then reads as a second source of truth that no surface points at.
11
11
 
12
- A pen the caller cannot face is the same gap wearing a different shape. Routing at capture takes the domain facts and whatever the ownership test leaves stays, in whatever mix of types that is, so the folder still reaches a size nobody reads in one sitting. The full sweep is what an operator asks for when the cross-session duplicates are the point. An entry leaving the pen is archived rather than deleted, because a folder git does not hold gives a wrong bulk call no undo.
12
+ A pen too large to review whole is the same gap wearing a different shape. Routing at capture takes the domain facts and whatever the ownership test leaves stays, in whatever mix of types that is, so the folder reaches a size no single pass can read: every entry plus every promotion target runs to hundreds of thousands of tokens before one entry is classified. A review that cannot run drains nothing however often someone asks for it, so the pass takes a bounded batch in the order the stale verb reports and reads targets per entry. An entry leaving the pen is archived rather than deleted, because a folder git does not hold gives a wrong bulk call no undo.
13
13
 
14
14
  ## Must
15
15
 
16
- - Treat the folder as a holding pen, so every entry in scope leaves it as a promotion, a handoff, or an archive rather than surviving by default
16
+ - Treat the folder as a holding pen, so every entry in scope leaves it as a promotion, a handoff, or an archive, or stays only as a kept entry stamped with the date it was reviewed
17
+ - Take one bounded batch per pass in the order `canon records stale memory` reports, and stop rather than falling back to a full sweep when that verb is absent
18
+ - Stamp `reviewed` on every entry a pass keeps or skips, so the next batch moves on to entries nobody has read
17
19
  - Archive an entry out of the pen rather than deleting it, since nothing recovers a file from a gitignored folder
18
- - Hand a fact a context entry owns to `docs-fold` through the routing file, rather than editing the entry here
20
+ - Hand a fact a context entry owns to `context-fold` through the routing file, rather than editing the entry here
19
21
  - Verify the rule is not already stated or implied in the target before proposing a promotion, by reading the target rather than trusting the memory's claim about it
20
22
  - Rewrite a rule into the destination's voice instead of moving it unchanged
21
23
  - Write the proposal to a receipt on disk and take no action until the user decides per item
@@ -34,18 +34,23 @@ Propose is the entry point for a standalone run. The ship skills stop at capture
34
34
 
35
35
  ### Scope
36
36
 
37
- - **Full sweep:** classify every entry in the pen, including entries carried from earlier sessions, so cross-session duplicates merge into one rule.
37
+ - **Batch:** run `canon records stale memory --json` and take the first 25 entries whose `due` is true, in the order the record lists them. When fewer than 25 are due, take all of them and say so. Never pad a batch with an entry that is not due.
38
+ - **Named set:** when the user names entries, a list, or a slug, that set is the scope and overrides the verb's order. Propose nothing outside it.
39
+
40
+ A whole pen does not fit one pass. Every entry plus every promotion target reads as several hundred thousand tokens on a grown project, so a full sweep fails before it classifies anything. The batch is bounded by the receipt the operator approves, which stays short enough for one pass at 25 items.
41
+
42
+ Branch on the record rather than on the exit, which a shell function wrapping `canon` can flatten to zero. When the installed binary carries no `records stale` subcommand, or the record comes back with `ok: false`, stop: `❌ canon records stale is missing or refused. Update the canon CLI, since a review without it falls back to a full sweep that cannot run.` Never fall back to reading the whole pen.
38
43
 
39
44
  ### Step 1: read the memory folder
40
45
 
41
46
  Read in parallel from the project root:
42
47
 
43
- - `.canon/memory/index.md`: the generated index
44
- - every other top-level `*.md` file in `.canon/memory/`, never its `review/` or `archive/` subfolders: individual entries with frontmatter (`title`, `description`, `category`)
48
+ - `.canon/memory/index.md`: the generated index, which is what lets a batch entry find a duplicate outside the batch
49
+ - each entry in the batch, by name, never its `review/` or `archive/` subfolders: individual entries with frontmatter (`title`, `description`, `category`, and `reviewed` when a past pass kept it)
45
50
 
46
- ### Step 2: read promotion targets
51
+ ### Step 2: search promotion targets per entry
47
52
 
48
- Read in parallel from the project root. Skip any file or folder that does not exist.
53
+ Do not read every target up front. For each entry in the batch, grep the target set below for the entry's subject, taking two or three keywords from its title and rule, and read the files that hit. Read `canon/context/index.md` once for the **Promote to a context entry** route. Skip any file or folder that does not exist.
49
54
 
50
55
  - `CLAUDE.md`: project behavior rules and Content ownership section, still a read target for the absorbed-already check even though it takes no new promotion
51
56
  - every `SKILL.md` under `.claude/skills/`: domain-scoped internal skill bodies
@@ -54,11 +59,15 @@ Read in parallel from the project root. Skip any file or folder that does not ex
54
59
  - every `*.md` under `governance/rules/` in the toolkit repo, or `.claude/rules/` in a target project: coding-standards rules
55
60
  - every `*.md` under `internal/rules/` in the toolkit repo, or `.claude/rules/project/` in a target project: always-loaded rules a promote lands in
56
61
 
62
+ A target the grep missed turns a promote into a retire, and only the operator's pass catches that. Name the targets each item searched in its receipt entry so the miss is visible there.
63
+
57
64
  ### Step 3: classify each entry
58
65
 
59
- `.canon/memory/` is a holding pen. Default every entry to promote or retire on review. Skip is the rare exception, reserved for active task overlap or user-type memories with no in-repo target.
66
+ `.canon/memory/` is a holding pen. Default every entry to promote or retire on review. Keep is the exception, reserved for an entry still true that no surface owns, such as active task overlap or a user-type memory with no in-repo target.
60
67
 
61
- `memory-capture` routes a project fact naming a domain with a context entry to that entry, so a pen filled since routing shipped is mostly feedback: rules about how to work, which no context entry owns. Propose against what the pen holds rather than expecting the older mix. An entry carried from before routing may still name a domain that has a context entry, and that entry's action is **Promote to a context entry**, which hands it to `docs-fold` the same way capture does rather than editing the entry here.
68
+ An entry's `unresolved` list in the stale record names paths it cites that the tree no longer holds. Weigh it as evidence for **Retire**, or for a rewrite when the rule survives the move, and never read it as the verdict alone. A rule can outlive the file it happened to name.
69
+
70
+ `memory-capture` routes a project fact naming a domain with a context entry to that entry, so a pen filled since routing shipped is mostly feedback: rules about how to work, which no context entry owns. Propose against what the pen holds rather than expecting the older mix. An entry carried from before routing may still name a domain that has a context entry, and that entry's action is **Promote to a context entry**, which hands it to `context-fold` the same way capture does rather than editing the entry here.
62
71
 
63
72
  For each in-scope entry (see Scope), pick one action:
64
73
 
@@ -67,11 +76,12 @@ For each in-scope entry (see Scope), pick one action:
67
76
  - In a target project, append the rule to an existing file under `.claude/rules/project/` with `Edit`, since a project rule is project-owned and sync never overwrites it, or hand off to the `create-rule` skill when no existing file fits.
68
77
  - **Promote to a skill body**: the rule fires only when editing a specific path-scoped domain. Name the target skill.
69
78
  - **Promote to a standards file**: the rule is an authoring reference that belongs in the project's own standards folder as `<domain>.md`.
70
- - **Promote to a context entry**: the entry states a fact about a domain carrying an entry in `canon/context/index.md`. Append it to `.canon/tmp/handoff/memory-routing/<slug>.md` at the main worktree root, in the format `memory-capture` writes, and tell the user to run `/docs-fold` from a branch. Do not edit the context entry here. A project-identity or command fact takes this action when a context entry owns the subject, such as a development entry for commands, and **Retire** otherwise, naming a hand edit to `CLAUDE.md` as the reason. Memory review does not write the root file itself.
79
+ - **Promote to a context entry**: the entry states a fact about a domain carrying an entry in `canon/context/index.md`. Append it to `.canon/tmp/handoff/memory-routing/<slug>.md` at the main worktree root, in the format `memory-capture` writes, and tell the user to run `/context-fold` from a branch. Do not edit the context entry here. A project-identity or command fact takes this action when a context entry owns the subject, such as a development entry for commands, and **Retire** otherwise, naming a hand edit to `CLAUDE.md` as the reason. Memory review does not write the root file itself.
71
80
  - **Hand off to governance**: the rule is coding-standards class (typescript, testing, naming, error-handling, performance, logging, concurrency, planning), never a cross-domain behavior rule. Do not author the rule file inline. Never edit the synced `.claude/rules/` copies of toolkit rules, because `canon gov sync` overwrites them. Stop at handoff. This and **Promote to an always-loaded rule** never both claim one entry: class names the topic (coding-standards routes here), firing axis names the rest (applies-every-session routes to the rule promote).
72
81
  - In the toolkit repo, point the user at `internal-governance` and `${CLAUDE_SKILL_DIR}/../../standards/rule.md`, which own the source-of-truth rules under `governance/rules/`.
73
82
  - In a target project, point the user at the `create-rule` skill, which scaffolds a project-local rule under `.claude/rules/`.
74
83
  - **Retire**: the rule is stale, already absorbed into a durable surface, too vague to phrase as a rule, or a one-time incident narrative. Apply moves the file to `.canon/memory/archive/` rather than deleting it.
84
+ - **Keep**: the rule is still true and no durable surface owns it. The entry stays in the pen, and Apply stamps `reviewed` so the verb does not queue it again until the window lapses.
75
85
 
76
86
  Retire is an archive, not a deletion, which `${CLAUDE_SKILL_DIR}/../../standards/memory.md` states as the rule and this skill executes. The archive is worth less than a plan's, since a promoted entry survives in its destination and a stale one is discarded on purpose, which is why the move is cheap rather than free.
77
87
 
@@ -91,7 +101,7 @@ Rules that resist crisp one-line phrasing default to **Retire** over promote. Ne
91
101
 
92
102
  Derive `<slug>` per `${CLAUDE_SKILL_DIR}/../../standards/slug.md`. Fall back to `latest` on an empty result.
93
103
 
94
- Write the full proposal to `.canon/memory/review/memory-review-<slug>.md` at the main worktree root. Do not print it inline. Read `${CLAUDE_SKILL_DIR}/references/receipt-format.md` for the file structure, the item template, and how each action type varies the body. The four phases below rewrite items inside an existing receipt rather than authoring one, so none of them opens it.
104
+ Write the full proposal to `.canon/memory/review/memory-review-<slug>.md` at the main worktree root. Do not print it inline. Read `${CLAUDE_SKILL_DIR}/references/receipt-format.md` for the file structure, the item template, and how each action type varies the body. The four later phases rewrite items inside an existing receipt rather than authoring one, so none of them opens it.
95
105
 
96
106
  A phase changing items reads the receipt, applies every change for that phase, and writes the whole file back in one command. Batching is what keeps a per-item rewrite from costing a full read each time, and it is the only route from a linked worktree, where the guard above rules out editing a line in place.
97
107
 
@@ -99,105 +109,9 @@ Tell the user `✅ Wrote proposal to .canon/memory/review/memory-review-<slug>.m
99
109
 
100
110
  Rewrite the review file in place whenever the proposal changes mid-review. The file stays the source of truth for the current decisions.
101
111
 
102
- ## Challenge phase
103
-
104
- Trigger: user says "challenge the promotes", "challenge before apply", or asks for a high-bar pass. Run before Apply. No mutations to memory files or promotion targets. Review file only.
105
-
106
- 1. Read the latest `.canon/memory/review/memory-review-*.md` at the main root.
107
- 2. For each promote item, apply three tests:
108
- - **Absorbed**: grep the target surface for the rule's keywords. If already stated or implied, flip to retire.
109
- - **Delta**: if the rule is a nice-to-have next to existing bullets, flip to retire.
110
- - **Generality**: if the rule fires only on one literal trigger phrase, rewrite broader or flip to retire.
111
- 3. Rewrite the review file in place with the updated actions and a one-line reason under each flip.
112
-
113
- ## Discuss phase
114
-
115
- Trigger: user says "discuss", "respond to questions", or any `Decision:` value contains `?` or an unrecognized verb. No mutations to memory files or targets. Review file only. Multi-round.
116
-
117
- 1. Read the latest `.canon/memory/review/memory-review-*.md` at the main root.
118
- 2. For each item whose `Decision:` contains `?` or any unrecognized verb (anything other than `apply`, `skip`, `defer`):
119
- - Write a `Take:` line under `Decision:`, separated by exactly one blank line. If a `Take:` line already exists, overwrite it.
120
- - Format: pick + one-line reason. Max 2 sentences. Decision-help style. State the recommendation (`apply` / `skip` / `retire` / specific alternative) first, then the reason. Do not enumerate tradeoffs unless one changes the call.
121
- - Leave the H2 emoji as 📝 pending.
122
- 3. Skip items whose `Decision:` is `apply`, `skip`, `defer`, or empty.
123
- 4. End with: `💬 Discussed: <nums> | ⏩ Skipped (committed or empty): <nums>`. Remind the user to refine `Decision:` lines and re-ping with "discuss" for another round, or "apply" when ready to commit.
124
-
125
- Do not act on any item. Do not archive memory files. Do not edit promotion targets. Discuss only.
126
-
127
- ## Apply phase
128
-
129
- Trigger: user says "apply", "commit", "ship the review", or re-pings with no question items remaining. Mutates tracked promotion targets and moves memory files into the archive.
130
-
131
- Before applying any item, check the worktree state:
132
-
133
- ```bash
134
- [ "$(git rev-parse --git-dir 2>/dev/null)" = "$(git rev-parse --git-common-dir 2>/dev/null)" ] && echo "MAIN" || echo "LINKED"
135
- ```
136
-
137
- If the result is `MAIN`, stop and tell the user: `❌ Apply phase mutates tracked files. Run /session-worktree first.` Discuss and Challenge phases only touch `.canon/review/` scratch and run from anywhere.
138
-
139
- Before applying a promote to an always-loaded rule in the toolkit repo, load `internal-governance`, which owns `internal/rules/core/` and `governance/rules/core/` and is the only route that may author into either. In a target project, hand off to `create-rule` with no load, since `internal-governance` is a toolkit-internal skill under `.claude/skills/` that a target project never has. An `Edit` appending to an existing file under `.claude/rules/project/` needs no load either.
140
-
141
- Promotions are a separate concern from any feature in flight. Keep the promoted edits on their own commit. Do not fold an always-loaded-rule or skill-body change into a feature's commits, because a feature reviewer should not have to vet a change to how the agent operates.
142
-
143
- For each item, parse the `Decision:` line:
144
-
145
- - `apply` (or affirmative): run the proposed action, flip emoji to ✅.
146
- - `skip`: leave the memory in place, flip emoji to ⏭.
147
- - `defer` or empty: leave 📝 pending, take no action.
148
- - Contains `?` or unrecognized verb: leave 📝 pending, take no action. Do not respond. Discussion is the Discuss phase's job.
149
-
150
- Free-form text after the verb is a reason. Capture it in the receipt but do not let it change the action. When committing an item, strip any empty `Take:` line so the receipt stays clean. `Take:` lines with content stay as discussion history.
151
-
152
- Action by action type:
153
-
154
- - **Promote**: use `Edit` to insert the rewritten rule into the target surface, then archive the memory file. A promote to an always-loaded rule in the toolkit repo never reaches this line: it stops as a handoff to `internal-governance`, the same as **Hand off** below, and archives only on the user's explicit confirmation.
155
- - **Promote to a context entry**: append the fact to `.canon/tmp/handoff/memory-routing/<slug>.md` at the main worktree root, then archive the memory file. `docs-fold` folds it in on its next run from a branch, which is what keeps one skill writing context entries.
156
- - **Hand off**: do not edit governance. Archive the memory file only if the user confirmed the handoff explicitly. Otherwise leave it in place.
157
- - **Retire**: archive the memory file.
158
-
159
- Archiving means creating `.canon/memory/archive/` at the main worktree root and moving the file there under its original name, overwriting any file already at that name. Send the `mkdir -p` and a plain `mv`, routed the way `session-worktree` states for a main-root move. Never delete a memory entry. Nothing recovers one from a gitignored folder.
160
-
161
- Do not hand-edit `.canon/memory/index.md`. Once every archive move is done, regenerate it instead:
162
-
163
- ```bash
164
- canon indexes regen --no-stage --root <main-root> <main-root>/.canon/memory/index.md
165
- ```
166
-
167
- An archive move is a shell `mv`, which skips the index hook the way `session-worktree` states. Without this call the index keeps a row per archived entry and drifts exactly the way the hand-appended one did. Run it once after the last move rather than per item.
168
-
169
- Apply promotion edits one at a time via `Edit`. Claude Code's tool permission dialog is the confirmation gate per edit. Never rewrite a whole promotion target.
170
-
171
- This governs the tracked surfaces a promote lands in, which sit at `pwd` and take `Edit` from anywhere. The receipt and the memory entries are main-root scratch and follow the guard instead.
172
-
173
- As each item resolves, update its status in the review file: flip the H2 emoji from 📝 to ✅ for applied, ⏭ for skipped, 📦 for retired, or 🤝 for handed off. Refresh the summary block counts at the top. Do not delete the file here. The sweep below decides whether it goes.
174
-
175
- **Chat shortcut:** the user replies with `all`, `none`, a comma-separated list of numbers, or `skip <nums>`. Write the matching verb into the `Decision:` slot of every item the reply names, `apply` for `all` or a bare list and `skip` for a `skip` reply, then run the parse above against the file. A reply of `none` writes nothing. A slot the reply does not name keeps its own value, so the receipt stays the source of truth and an empty slot still means take no action.
176
-
177
- ### Sweep the receipt
178
-
179
- Count the items still pending once the parse above has run. An item is pending when its H2 carries 📝, or when its H2 carries no status emoji and its `Decision:` slot holds nothing the parse above would act on or skip, since a receipt written by hand or by an older binary may lack the marker. Apply leaves one pending on `defer`, on empty, and on any unrecognized verb, so a receipt reaching this point may still be holding decisions.
180
-
181
- Leave the receipt in place when any remain. When none do, collect it per the collection rule in `${CLAUDE_SKILL_DIR}/../../standards/memory.md`, which owns what a fold writes and which entry types take one.
182
-
183
- `docs-fold` Step 9 sweeps the same folder on the same rule once per shipped branch, and either may reach a receipt first. Whichever does, the other finds no file and moves on.
184
-
185
- End with: `✅ Applied: <nums> | ⏭ Skipped: <nums> | 📝 Pending: <nums>`. Omit empty buckets. If anything is pending, remind the user they can refine `Decision:` lines and re-ping, run "discuss" for question items, or commit a skip with `skip <nums>` in chat.
186
-
187
- ## Cleanup phase
188
-
189
- Trigger: user says "cleanup" or "delete the receipt" after Apply has run.
190
-
191
- Cleanup folds one receipt's skips and removes that receipt, and does nothing else. It is the fallback route now that Apply and `docs-fold` Step 9 each collect a resolved receipt on their own, so it reaches a file those two left behind rather than being the only collector. Apply is still the only phase that moves a memory entry out of the pen, and it does so per approved item into `.canon/memory/archive/`. A user asking to sweep stale memories wants Propose, which classifies entries and writes a decision slot per entry.
192
-
193
- If no `.canon/memory/review/memory-review-*.md` exists at the main root, stop: `✅ No review receipt to clean up.` Every other refusal in this skill carries a message, and the phase reads a receipt before it does anything else.
194
-
195
- 1. Read the latest `.canon/memory/review/memory-review-*.md` at the main root and confirm Apply has run against it. If any item is still pending, by the test the Apply sweep states, stop and name the pending numbers.
196
- 2. Collect it per the collection rule in `${CLAUDE_SKILL_DIR}/../../standards/memory.md`, folding each ⏭ skipped item before the file goes. The fold happens wherever a receipt is collected, so this phase runs the same rule the Apply sweep does.
197
- 3. Delete that one file. Leave every other receipt beside it in place, because the pending test above covers the file it read and nothing has tested the rest.
198
- 4. Leave every memory entry in the pen. A skip records the decline on the entry and keeps the file, and applied promotions, governance handoffs, and user-type memories each stay as the review left them.
112
+ ## Challenge, Discuss, Apply, and Cleanup phases
199
113
 
200
- Do not promote or archive a memory entry. The skip fold is the one rewrite this phase makes, and it records a decline on an entry that stays in the pen.
114
+ Each later phase runs on its own invocation against a receipt Propose already wrote, picked by the table above. Read `${CLAUDE_SKILL_DIR}/references/later-phases.md` on reaching any of them, for the phase's trigger, what it may mutate, its procedure, and the line it ends on. Challenge and Discuss rewrite the review file only, Apply stops on the main worktree, and Cleanup removes one receipt.
201
115
 
202
116
  ## After completion
203
117
 
@@ -207,6 +121,7 @@ Output one line per action taken in the most recent phase:
207
121
  - `✅ Handed off: .canon/memory/<memory-file> → governance`
208
122
  - `📦 Retired: .canon/memory/<memory-file> → .canon/memory/archive/`
209
123
  - `🗑 Swept: .canon/review/<review-file>, folded <n> skips`
124
+ - `📌 Kept: .canon/memory/<memory-file>, reviewed <date>`
210
125
  - `⏭ Kept: .canon/review/<review-file>, <n> items pending`
211
126
 
212
127
  If the user accepted nothing, output: `✅ No changes applied.`
@@ -0,0 +1,111 @@
1
+ ---
2
+ title: Memory review later phases
3
+ description: The Challenge, Discuss, Apply, and Cleanup phases of memory-review, each run on its own invocation against a receipt the Propose phase already wrote
4
+ ---
5
+
6
+ # Memory review later phases
7
+
8
+ The phases of `memory-review` after Propose. The session reads this file when the phase table in the skill picks Challenge, Discuss, Apply, or Cleanup, and reads only the section for that phase. The skill's Guards still hold for every phase here.
9
+
10
+ ## Challenge phase
11
+
12
+ Trigger: user says "challenge the promotes", "challenge before apply", or asks for a high-bar pass. Run before Apply. No mutations to memory files or promotion targets. Review file only.
13
+
14
+ 1. Read the latest `.canon/memory/review/memory-review-*.md` at the main root.
15
+ 2. For each promote item, apply three tests:
16
+ - **Absorbed**: grep the target surface for the rule's keywords. If already stated or implied, flip to retire.
17
+ - **Delta**: if the rule is a nice-to-have next to existing bullets, flip to retire.
18
+ - **Generality**: if the rule fires only on one literal trigger phrase, rewrite broader or flip to retire.
19
+ 3. Rewrite the review file in place with the updated actions and a one-line reason under each flip.
20
+
21
+ ## Discuss phase
22
+
23
+ Trigger: user says "discuss", "respond to questions", or any `Decision:` value contains `?` or an unrecognized verb. No mutations to memory files or targets. Review file only. Multi-round.
24
+
25
+ 1. Read the latest `.canon/memory/review/memory-review-*.md` at the main root.
26
+ 2. For each item whose `Decision:` contains `?` or any unrecognized verb (anything other than `apply`, `skip`, `defer`):
27
+ - Write a `Take:` line under `Decision:`, separated by exactly one blank line. If a `Take:` line already exists, overwrite it.
28
+ - Format: pick + one-line reason. Max 2 sentences. Decision-help style. State the recommendation (`apply` / `skip` / `retire` / specific alternative) first, then the reason. Do not enumerate tradeoffs unless one changes the call.
29
+ - Leave the H2 emoji as 📝 pending.
30
+ 3. Skip items whose `Decision:` is `apply`, `skip`, `defer`, or empty.
31
+ 4. End with: `💬 Discussed: <nums> | ⏩ Skipped (committed or empty): <nums>`. Remind the user to refine `Decision:` lines and re-ping with "discuss" for another round, or "apply" when ready to commit.
32
+
33
+ Do not act on any item. Do not archive memory files. Do not edit promotion targets. Discuss only.
34
+
35
+ ## Apply phase
36
+
37
+ Trigger: user says "apply", "commit", "ship the review", or re-pings with no question items remaining. Mutates tracked promotion targets and moves memory files into the archive.
38
+
39
+ Before applying any item, check the worktree state:
40
+
41
+ ```bash
42
+ [ "$(git rev-parse --git-dir 2>/dev/null)" = "$(git rev-parse --git-common-dir 2>/dev/null)" ] && echo "MAIN" || echo "LINKED"
43
+ ```
44
+
45
+ If the result is `MAIN`, stop and tell the user: `❌ Apply phase mutates tracked files. Run /session-worktree first.` Discuss and Challenge phases only touch `.canon/review/` scratch and run from anywhere.
46
+
47
+ Before applying a promote to an always-loaded rule in the toolkit repo, load `internal-governance`, which owns `internal/rules/core/` and `governance/rules/core/` and is the only route that may author into either. In a target project, hand off to `create-rule` with no load, since `internal-governance` is a toolkit-internal skill under `.claude/skills/` that a target project never has. An `Edit` appending to an existing file under `.claude/rules/project/` needs no load either.
48
+
49
+ Promotions are a separate concern from any feature in flight. Keep the promoted edits on their own commit. Do not fold an always-loaded-rule or skill-body change into a feature's commits, because a feature reviewer should not have to vet a change to how the agent operates.
50
+
51
+ For each item, parse the `Decision:` line:
52
+
53
+ - `apply` (or affirmative): run the proposed action, flip emoji to ✅.
54
+ - `skip`: leave the memory in place, stamp it reviewed as below, flip emoji to ⏭.
55
+ - `defer` or empty: leave 📝 pending, take no action.
56
+ - Contains `?` or unrecognized verb: leave 📝 pending, take no action. Do not respond. Discussion is the Discuss phase's job.
57
+
58
+ Free-form text after the verb is a reason. Capture it in the receipt but do not let it change the action. When committing an item, strip any empty `Take:` line so the receipt stays clean. `Take:` lines with content stay as discussion history.
59
+
60
+ Action by action type:
61
+
62
+ - **Promote**: use `Edit` to insert the rewritten rule into the target surface, then archive the memory file. A promote to an always-loaded rule in the toolkit repo never reaches this line: it stops as a handoff to `internal-governance`, the same as **Hand off** below, and archives only on the user's explicit confirmation.
63
+ - **Promote to a context entry**: append the fact to `.canon/tmp/handoff/memory-routing/<slug>.md` at the main worktree root, then archive the memory file. `context-fold` folds it in on its next run from a branch, which is what keeps one skill writing context entries.
64
+ - **Hand off**: do not edit governance. Archive the memory file only if the user confirmed the handoff explicitly. Otherwise leave it in place.
65
+ - **Retire**: archive the memory file.
66
+ - **Keep**: stamp the memory file reviewed as below, and flip the emoji to 📌.
67
+
68
+ Stamping means writing `reviewed: <today>` as a `YYYY-MM-DD` date into the entry's frontmatter, replacing any earlier value, and changing nothing else in the file. The entry is main-root scratch, so the stamp goes out as the same whole-file heredoc rewrite the Guards state. Stamp only an entry that stays in the pen, being a keep or a skip. A promote or a retire takes no stamp, since the entry leaves for the archive. The stamp is what takes a kept entry off the front of `canon records stale memory`'s queue, so an entry kept without one returns in the next batch.
69
+
70
+ Archiving means creating `.canon/memory/archive/` at the main worktree root and moving the file there under its original name, overwriting any file already at that name. Send the `mkdir -p` and a plain `mv`, routed the way `session-worktree` states for a main-root move. Never delete a memory entry. Nothing recovers one from a gitignored folder.
71
+
72
+ Do not hand-edit `.canon/memory/index.md`. Once every archive move and stamp is done, regenerate it instead:
73
+
74
+ ```bash
75
+ canon indexes regen --no-stage --root <main-root> <main-root>/.canon/memory/index.md
76
+ ```
77
+
78
+ An archive move is a shell `mv`, which skips the index hook the way `session-worktree` states. Without this call the index keeps a row per archived entry and drifts exactly the way the hand-appended one did. Run it once after the last move rather than per item.
79
+
80
+ Apply promotion edits one at a time via `Edit`. Claude Code's tool permission dialog is the confirmation gate per edit. Never rewrite a whole promotion target.
81
+
82
+ This governs the tracked surfaces a promote lands in, which sit at `pwd` and take `Edit` from anywhere. The receipt and the memory entries are main-root scratch and follow the skill's heredoc guard instead.
83
+
84
+ As each item resolves, update its status in the review file: flip the H2 emoji from 📝 to ✅ for applied, ⏭ for skipped, 📦 for retired, 📌 for kept, or 🤝 for handed off. Refresh the summary block counts at the top. Do not delete the file here. The sweep below decides whether it goes.
85
+
86
+ **Chat shortcut:** the user replies with `all`, `none`, a comma-separated list of numbers, or `skip <nums>`. Write the matching verb into the `Decision:` slot of every item the reply names, `apply` for `all` or a bare list and `skip` for a `skip` reply, then run the parse above against the file. A reply of `none` writes nothing. A slot the reply does not name keeps its own value, so the receipt stays the source of truth and an empty slot still means take no action.
87
+
88
+ ### Sweep the receipt
89
+
90
+ Count the items still pending once the parse above has run. An item is pending when its H2 carries 📝, or when its H2 carries no status emoji and its `Decision:` slot holds nothing the parse above would act on or skip, since a receipt written by hand or by an older binary may lack the marker. Apply leaves one pending on `defer`, on empty, and on any unrecognized verb, so a receipt reaching this point may still be holding decisions.
91
+
92
+ Leave the receipt in place when any remain. When none do, collect it per the collection rule in `${CLAUDE_SKILL_DIR}/../../standards/memory.md`, which owns what a fold writes and which entry types take one.
93
+
94
+ `context-fold` Step 9 sweeps the same folder on the same rule once per shipped branch, and either may reach a receipt first. Whichever does, the other finds no file and moves on.
95
+
96
+ End with: `✅ Applied: <nums> | ⏭ Skipped: <nums> | 📝 Pending: <nums>`. Omit empty buckets. If anything is pending, remind the user they can refine `Decision:` lines and re-ping, run "discuss" for question items, or commit a skip with `skip <nums>` in chat.
97
+
98
+ ## Cleanup phase
99
+
100
+ Trigger: user says "cleanup" or "delete the receipt" after Apply has run.
101
+
102
+ Cleanup folds one receipt's skips and removes that receipt, and does nothing else. It is the fallback route now that Apply and `context-fold` Step 9 each collect a resolved receipt on their own, so it reaches a file those two left behind rather than being the only collector. Apply is still the only phase that moves a memory entry out of the pen, and it does so per approved item into `.canon/memory/archive/`. A user asking to sweep stale memories wants Propose, which classifies entries and writes a decision slot per entry.
103
+
104
+ If no `.canon/memory/review/memory-review-*.md` exists at the main root, stop: `✅ No review receipt to clean up.` Every other refusal in this skill carries a message, and the phase reads a receipt before it does anything else.
105
+
106
+ 1. Read the latest `.canon/memory/review/memory-review-*.md` at the main root and confirm Apply has run against it. If any item is still pending, by the test the Apply sweep states, stop and name the pending numbers.
107
+ 2. Collect it per the collection rule in `${CLAUDE_SKILL_DIR}/../../standards/memory.md`, folding each ⏭ skipped item before the file goes. The fold happens wherever a receipt is collected, so this phase runs the same rule the Apply sweep does.
108
+ 3. Delete that one file. Leave every other receipt beside it in place, because the pending test above covers the file it read and nothing has tested the rest.
109
+ 4. Leave every memory entry in the pen. A skip records the decline on the entry and keeps the file, and applied promotions, governance handoffs, and user-type memories each stay as the review left them.
110
+
111
+ Do not promote or archive a memory entry. The skip fold is the one rewrite this phase makes, and it records a decline on an entry that stays in the pen.
@@ -16,9 +16,11 @@ Do not include a `Take:` slot in the template. Discuss inserts one directly unde
16
16
  ````plaintext
17
17
  # Memory review: <slug>
18
18
 
19
+ **Batch:** <n> of <due> due entries, in `canon records stale memory` order. <due minus n> stay due after this batch.
20
+
19
21
  **Pending:** <all numbers>
20
22
 
21
- Legend: ✅ applied · ⏭ skipped · 📦 retired · 🤝 handed off · 📝 pending
23
+ Legend: ✅ applied · ⏭ skipped · 📦 retired · 📌 kept · 🤝 handed off · 📝 pending
22
24
 
23
25
  How to respond: fill in `Decision:` per item (`apply`, `skip`, `defer`, or a question with `?`), then re-ping the skill. Say "discuss" for question rounds, "apply" to commit. Chat shortcut: `all`, `none`, or a list of numbers.
24
26
 
@@ -28,6 +30,8 @@ How to respond: fill in `Decision:` per item (`apply`, `skip`, `defer`, or a que
28
30
 
29
31
  Why: <one-line pulled from the memory's Why>
30
32
 
33
+ Searched: <the targets the grep hit and read>
34
+
31
35
  ```diff
32
36
  + <rewritten rule text>
33
37
  ```
@@ -38,11 +42,23 @@ Decision:
38
42
 
39
43
  `<memory-file>`
40
44
 
41
- Reason: <one-line reason>
45
+ Reason: <one-line reason, naming any unresolved path the stale record listed>
46
+
47
+ Searched: <the targets the grep hit and read>
48
+
49
+ Decision:
50
+
51
+ ## 3. 📝 Keep
52
+
53
+ `<memory-file>`
54
+
55
+ Reason: <one-line reason no surface owns the rule>
56
+
57
+ Searched: <the targets the grep hit and read>
42
58
 
43
59
  Decision:
44
60
  ````
45
61
 
46
62
  ## Variation by action
47
63
 
48
- For Hand off items, the body is a pointer to the governance target instead of a rewritten rule: `internal-governance` and `${CLAUDE_SKILL_DIR}/../../standards/rule.md` in the toolkit repo, or the `create-rule` skill in a target project. For a Promote to an always-loaded rule item, the H2 target names the rule file path the rule lands in, `<target>` in the template above, being an existing path under `internal/rules/core/` or `governance/rules/core/` in the toolkit repo, or under `.claude/rules/project/` in a target project, or the `create-rule` pointer when no existing file fits. For Retire items, skip the rewrite block. Every item gets a `Decision:` slot regardless of action. `Take:` is added only when a question response is needed.
64
+ For Hand off items, the body is a pointer to the governance target instead of a rewritten rule: `internal-governance` and `${CLAUDE_SKILL_DIR}/../../standards/rule.md` in the toolkit repo, or the `create-rule` skill in a target project. For a Promote to an always-loaded rule item, the H2 target names the rule file path the rule lands in, `<target>` in the template above, being an existing path under `internal/rules/core/` or `governance/rules/core/` in the toolkit repo, or under `.claude/rules/project/` in a target project, or the `create-rule` pointer when no existing file fits. For Retire and Keep items, skip the rewrite block. A batch holding fewer than 25 entries says so in the `**Batch:**` line, and a scope the user named replaces that line with `**Batch:** named by the user, <n> entries`. Every item gets a `Decision:` slot regardless of action. `Take:` is added only when a question response is needed.
@@ -35,4 +35,4 @@ Without this skill, implementation starts before anyone knows what it touches. A
35
35
 
36
36
  - Executing the plan, which is the ship pipeline
37
37
  - Task-board state, which `task-board` owns. A plan links to its task and does not create one.
38
- - Reconciling the planning docs after the work lands, which `docs-fold` owns
38
+ - Reconciling the planning docs after the work lands, which `context-fold` owns
@@ -52,6 +52,6 @@ A declined finding fails on a third axis, which is where its reason ends up. A w
52
52
 
53
53
  - Writing the review, which `review-pr` owns. The split is by side of the channel: that one posts findings from an independent session and this one is the worker's return leg.
54
54
  - Staging, committing, and pushing the follow-up, which `git-followup` owns under this skill's direction
55
- - Refreshing the `.claude/` docs the fixes made stale, which `docs-fold` owns
55
+ - Refreshing the `.claude/` docs the fixes made stale, which `context-fold` owns
56
56
  - Re-reviewing its own fixes, which hands back to the orchestrator
57
57
  - Re-reading a rewritten branch, which `review-pr` absorbs by testing whether the prior reviewed commit still reaches the head and paying for a full pass when it does not
@@ -46,7 +46,7 @@ Do not push a red follow-up.
46
46
 
47
47
  ## Step 4: refresh stale docs
48
48
 
49
- The fixes may have changed or added behavior that `.claude/` context entries, docs, or wireframes describe. Refresh them with the `docs-fold` skill, which maps the changed files to the entries that reference them and rewrites the stale sections. Do not reimplement that mapping here. When a fix adds a new capability with no existing entry, `docs-fold` flags it rather than creating one.
49
+ The fixes may have changed or added behavior that `.claude/` context entries, docs, or wireframes describe. Refresh them with the `context-fold` skill, which maps the changed files to the entries that reference them and rewrites the stale sections. Do not reimplement that mapping here. When a fix adds a new capability with no existing entry, `context-fold` flags it rather than creating one.
50
50
 
51
51
  ## Step 5: rebase a stale branch
52
52
 
@@ -121,7 +121,7 @@ If there are no findings, write `✅ No findings.` to the file with a timestamp.
121
121
 
122
122
  The `.canon/review/` directory is gitignored. Do not stage or commit the file.
123
123
 
124
- The report is disposable. It outlives the ship chain that reads it, and `docs-fold` sweeps it once the branch it names is gone, because the durable record of what a review found is the comment `review-pr` posts on the pull request. A review run on a branch that never opens one leaves nothing behind once that branch is gone, so fold anything worth keeping into the pull request body or a task finding while the report is still on disk.
124
+ The report is disposable. It outlives the ship chain that reads it, and `context-fold` sweeps it once the branch it names is gone, because the durable record of what a review found is the comment `review-pr` posts on the pull request. A review run on a branch that never opens one leaves nothing behind once that branch is gone, so fold anything worth keeping into the pull request body or a task finding while the report is still on disk.
125
125
 
126
126
  ### Chat output
127
127
 
@@ -35,7 +35,7 @@ Then output the state of play so the human knows what to launch, review, and mer
35
35
 
36
36
  `priority.md` is the ordering source. `index.md` sorts by filename and says nothing about order, so read the sequence from the first and never infer it from the second. When `priority.md` is absent, report the queue and say the order is unrecorded.
37
37
 
38
- Row position under `## Needs a plan` is what gets planned next, top first, per `${CLAUDE_SKILL_DIR}/../../standards/tasks.md`. `backlog.md` carries what nobody is scheduling and is explicitly unordered, so read it for what exists and never as a queue. Report a backlog count rather than its rows, since listing them puts the length back in front of the reader the cut took it away from. This read reports how many rows exist and nothing about whether each still belongs there. `references/orchestrator-parked.md` is what re-tests a backlog row's currency, on its own trigger below.
38
+ Row position under `## Needs a plan` is what gets planned next, top first, per `${CLAUDE_SKILL_DIR}/../../standards/board.md`. `backlog.md` carries what nobody is scheduling and is explicitly unordered, so read it for what exists and never as a queue. Report a backlog count rather than its rows, since listing them puts the length back in front of the reader the cut took it away from. This read reports how many rows exist and nothing about whether each still belongs there. `references/orchestrator-parked.md` is what re-tests a backlog row's currency, on its own trigger below.
39
39
 
40
40
  No surface carries cross-version sequencing, so report none. A row's `Waiting on` cell states why that row sits where it does, and reasoning spanning several rows reaches this session only through whoever remembers it. Say nothing about an active version, since nothing in the tree states one and a version asserted from the board is the unsourced claim this omission exists against.
41
41
 
@@ -85,7 +85,7 @@ The tracked-file boundary collides with `CLAUDE.md`, which says to handle a smal
85
85
 
86
86
  Record a change identified while orchestrating against the task that owns it, fold one no task owns into the next task touching the same surface, and file a task only when no such task exists or is expected. Run `review-branch` when the boundary is crossed anyway, since a branch-diff pass is not independent and is the only check a self-authored change can get.
87
87
 
88
- Filing a row states the defect and the surface it was seen on, and stops there. The extent and the cause belong to whoever plans it, so a row names neither a count of how far the defect reaches nor the mechanism behind it. Say in a plain sentence in the task file that the count was not taken, where the row's shape invites one, rather than in a marker of any prescribed form. The board's own cell has no room for it, since `${CLAUDE_SKILL_DIR}/../../standards/tasks.md` caps a `Waiting on` cell at two clauses.
88
+ Filing a row states the defect and the surface it was seen on, and stops there. The extent and the cause belong to whoever plans it, so a row names neither a count of how far the defect reaches nor the mechanism behind it. Say in a plain sentence in the task file that the count was not taken, where the row's shape invites one, rather than in a marker of any prescribed form. The board's own cell has no room for it, since `${CLAUDE_SKILL_DIR}/../../standards/board.md` caps a `Waiting on` cell at two clauses.
89
89
 
90
90
  A finding placed into another task's `## Findings` is filing under a second name and takes the same rule. An unverified cause costs more than an unverified count, since a count fails loudly at the first re-measurement while a mechanism nobody opened the module to check sends real work in the wrong direction.
91
91
 
@@ -70,7 +70,7 @@ Take the comparison at the file path rather than at a folder above it. `canon ta
70
70
 
71
71
  The finding names which row contributed the containing path, and a bare-folder cell reports as a claim of its own beside the findings. Read that output as a candidate list, settle each pair by file, and narrow the cell that over-claimed rather than discounting the collision it caused.
72
72
 
73
- A declared set is what a branch sets out to write rather than a bound on it, so this gate clears against a prediction and the branch outgrows it hours later. A track can cross the set it cleared against and still merge clean, which is a gate reporting disjoint while a real overlap stood. Two classes account for nearly all of the crossing. The ship chain's own steps write past every plan, since `canon:docs-fold` refreshes whichever context entry a change reaches and `canon:docs-sync` reaches the public docs, and neither surface is one a planner can name before the change exists. The drift stages `bun run check` regenerates and asserts are the second, together with the test and sandbox siblings a source change drags in. Nothing here prevents either, because the files at issue are written long after this gate clears. What reads the other end is `canon tasks plan-reach`, which `canon:git-ship` runs at step 5 against the branch's own diff, so a crossing this gate could not see is named before the pull request opens rather than after it merges.
73
+ A declared set is what a branch sets out to write rather than a bound on it, so this gate clears against a prediction and the branch outgrows it hours later. A track can cross the set it cleared against and still merge clean, which is a gate reporting disjoint while a real overlap stood. Two classes account for nearly all of the crossing. The ship chain's own steps write past every plan, since `canon:context-fold` refreshes whichever context entry a change reaches and `canon:docs-sync` reaches the public docs, and neither surface is one a planner can name before the change exists. The drift stages `bun run check` regenerates and asserts are the second, together with the test and sandbox siblings a source change drags in. Nothing here prevents either, because the files at issue are written long after this gate clears. What reads the other end is `canon tasks plan-reach`, which `canon:git-ship` runs at step 5 against the branch's own diff, so a crossing this gate could not see is named before the pull request opens rather than after it merges.
74
74
 
75
75
  Disjointness is necessary and not sufficient, so hold a candidate whose sets do not touch when a stated reason serializes it, and write the reason on the hold. One row creating a skill and another auditing that catalog and counting it write nothing in common, and dispatching both still leaves the audit counting a denominator that moves underneath it. Nothing verifies that a reason was written, so the rule holds only while the dispatcher applies it.
76
76
 
@@ -17,7 +17,7 @@ The sweep's own question stays distinct from this one. It asks which parked row
17
17
 
18
18
  Every row under `## Up next` and `## Needs a plan` in `.canon/tasks/priority.md`. A `## Run now` row carries no blocker by definition, so the pass skips it. On the idle trigger, also every row in `.canon/tasks/backlog.md` when the file exists, per the trigger split above. Resolve the board, the backlog, and each task file at the main worktree root, the way `session-worktree` does.
19
19
 
20
- Take the board rows in board order and finish one before opening the next. Clearing a row changes what the next row collides with, so a pass that measures every row first and writes afterwards writes against a board it has already invalidated. On the idle trigger, walk the backlog after the board, in the file's own filename order, since `${CLAUDE_SKILL_DIR}/../../standards/tasks.md` fixes that file as unordered and nothing about a row's position there means anything to preserve mid-pass.
20
+ Take the board rows in board order and finish one before opening the next. Clearing a row changes what the next row collides with, so a pass that measures every row first and writes afterwards writes against a board it has already invalidated. On the idle trigger, walk the backlog after the board, in the file's own filename order, since `${CLAUDE_SKILL_DIR}/../../standards/board.md` fixes that file as unordered and nothing about a row's position there means anything to preserve mid-pass.
21
21
 
22
22
  ## Re-testing a row
23
23
 
@@ -35,12 +35,14 @@ Write the result into the row. A re-test reported in chat is lost at the next co
35
35
 
36
36
  ## Re-testing a backlog row
37
37
 
38
- A backlog row carries no blocker cell, since `${CLAUDE_SKILL_DIR}/../../standards/tasks.md` fixes `backlog.md` as a flat list of links with no state of its own. The five kinds above test what a blocker names, and a backlog row names none, so this pass asks the board-or-backlog question the standard already states instead: has the work in front of the row landed, or has the world changed under it. Read the answer from the task file's own `## Findings` and its origin line (`Plan:`, `Groundwork:`, `Intake:`, or `Issue:`), which name what the row was filed against and whether the fact behind it still holds.
38
+ A backlog row carries no blocker cell, since `${CLAUDE_SKILL_DIR}/../../standards/board.md` fixes `backlog.md` as a flat list of links with no state of its own. The five kinds above test what a blocker names, and a backlog row names none, so this pass asks the board-or-backlog question the standard already states instead: has the work in front of the row landed, or has the world changed under it. Read the answer from the task file's own `## Findings` and its origin line (`Plan:`, `Groundwork:`, `Intake:`, or `Issue:`), which name what the row was filed against and whether the fact behind it still holds.
39
39
 
40
40
  Clearing a row answers yes to that question. It is not a count of how long the row has waited: `## Two results that are not a re-test` below refuses age as evidence for a board row, and it refuses it here on the same ground, since a row untouched for weeks is not more clearable than one added yesterday.
41
41
 
42
42
  A row this test clears moves out of `backlog.md` and onto the bottom of `## Needs a plan`, carrying a `Waiting on` cell that states what changed and ends with the word `last`. `canon tasks validate`'s ordering check reads `last` as the ordinal bottom placement already claims, and a cell stating only what changed matches neither that check's ordinal reading nor its rank reading, which raises the finding this pass would then have written against its own row. The next refill sweep's promotion step still orders the row against the rest of that heading the way it orders every other row there, per step 5 under `## Refilling the ready queue` in `role-orchestrator`.
43
43
 
44
+ This pass only clears a row upward. Declining or archiving a backlog row is `backlog-triage`, which files a verdict for every row and applies the ones the operator approved.
45
+
44
46
  ## Two ways a re-test goes wrong
45
47
 
46
48
  Both return a confident wrong answer rather than an error, which is why each gets a step of its own.
@@ -14,7 +14,7 @@ It counts unclaimed plans against workers rather than reading the reserve in ste
14
14
  1. Run `gh pr list --state open` and `git log --oneline -8`. Report any pull request whose review has not been posted and stop for that one first.
15
15
  2. For each pull request merged since the last sweep, place every finding it produced. Route a finding that changes a rule to the standard or rule that states it, one that changes another task to that task's Findings, and one that overturns a groundwork lean to that folder marked answered. Never leave a finding in a pull request thread alone.
16
16
  3. Archive what closed.
17
- - A task whose outcomes are all `[x]` runs `docs-fold` for the plan sweep, then `task-board` to archive
17
+ - A task whose outcomes are all `[x]` runs `context-fold` for the plan sweep, then `task-board` to archive
18
18
  - A task whose outcomes describe standing policy rather than a deliverable never closes on its own, so hand it to a worker to encode the policy where it is enforced, then cut the outcomes with the reason recorded and archive once that branch merges. Encoding it from this session would write a tracked file, which `## Boundaries` in the skill body forbids.
19
19
  4. Read `.canon/tasks/priority.md` and count entries under its `## Run now` heading that carry a written plan. Keep one in reserve beyond what is running.
20
20
  5. Promote from the top of `## Needs a plan`, which is where the last sweep recorded what to plan next. Depart from that order when something has changed under it and say what changed, since a position nobody honors is the ordering going stale on the surface built to hold it. What sets the order in the first place is whether a task establishes functionality rather than how old it is, so prefer a task that adds or proves a mechanism over one that trims, tidies, or audits an existing surface.
@@ -53,4 +53,4 @@ Promoting, demoting, and archiving a row all write `.canon/tasks/priority.md`, a
53
53
  - Re-resolve every Plan pointer after anything archives a plan
54
54
  - Read the file back after writing it, since the row that lands is the row a worker acts on
55
55
 
56
- A Plan pointer goes stale from a branch this board never sees. `docs-fold` moves a plan to `.canon/plans/archive/` and rewrites the citation in the task file alone, so a row for a task still on the board keeps pointing into `.canon/plans/` at a file that has moved. Workers running the ship chain on their own branches archive plans this board still cites, and the board reads as correct until a pointer is followed.
56
+ A Plan pointer goes stale from a branch this board never sees. `context-fold` moves a plan to `.canon/plans/archive/` and rewrites the citation in the task file alone, so a row for a task still on the board keeps pointing into `.canon/plans/` at a file that has moved. Workers running the ship chain on their own branches archive plans this board still cites, and the board reads as correct until a pointer is followed.
@@ -45,5 +45,5 @@ A resume is a read, and a session that treats it as a cleanup pass offers to arc
45
45
  - Writing a handoff, which happens at the close of a session rather than at its start. This skill names the standard that governs one and follows it no further.
46
46
  - The sections a role adds over the core handoff, which belong to that role's own surface
47
47
  - Archiving a shipped task out of the folder: `task-board`
48
- - Archiving a plan and marking an outcome, which `docs-fold` does when the work ships
48
+ - Archiving a plan and marking an outcome, which `context-fold` does when the work ships
49
49
  - Implementing the item it recommends, which is the next request rather than part of this one
@@ -14,13 +14,14 @@ Read these in parallel, skipping any that do not exist:
14
14
  - the newest `.canon/compact/*.md`, then the newest `.canon/tasks/session-*.md`: the handoff a previous session wrote before a compaction. The first is the note `session-compact` writes, and the second is the board-side map per `${CLAUDE_SKILL_DIR}/../../standards/session.md`, which stays readable. Whichever exists leads the report rather than the reads, and both lead it when both exist.
15
15
  - `.canon/tasks/index.md`: the folder catalog. Read this before any individual task file, and take the task list from it by dropping the `index`, `priority`, `backlog`, and `session-` rows, which are siblings rather than tasks.
16
16
  - `.canon/plans/*.md`: execution detail for in-progress tasks
17
- - `.canon/memory/index.md` and any memory files relevant to the top backlog item
18
17
 
19
18
  Then read only the task files the summary needs, typically the top one. Do not read the whole folder.
20
19
 
20
+ Once the top task is known, grep `.canon/memory/index.md` for two or three terms from its title and read at most three of the entries whose rows match. Never read the index whole, since a grown pen's index runs to hundreds of rows and the report shows three at most. With no top task, or no row matching, read no memory entry and say nothing about it.
21
+
21
22
  Most projects carry no handoff. Say nothing about its absence, since a line reporting it every run trains a reader to skip the line on the run where a handoff exists.
22
23
 
23
- If all four surfaces are absent or empty, stop: `✅ No tracked work found. Start a new task.`
24
+ If the handoff, task, and plan surfaces are all absent or empty, stop: `✅ No tracked work found. Start a new task.`
24
25
 
25
26
  ## Step 2: summarize
26
27
 
@@ -32,7 +33,7 @@ Output these sections, omitting the first when no handoff was found:
32
33
 
33
34
  **Active plans:** one line per file in `.canon/plans/`, linking each to its task file in `.canon/tasks/`. Say "None" if empty.
34
35
 
35
- **Relevant context:** two or three memory entries that inform the top backlog item. Skip if none apply.
36
+ **Relevant context:** the memory entries Step 1 matched to the top backlog item, three at most. Skip if none matched.
36
37
 
37
38
  ## Step 3: recommend
38
39