@iceinvein/agent-skills 0.23.7 → 0.23.9

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 (65) hide show
  1. package/package.json +1 -1
  2. package/skills/index.json +3 -3
  3. package/skills/magpie/README.md +1 -1
  4. package/skills/magpie/SKILL.md +2 -2
  5. package/skills/magpie/evals/README.md +22 -8
  6. package/skills/magpie/evals/bare-invocation-goes-local/case.yaml +4 -0
  7. package/skills/magpie/evals/bare-invocation-goes-local/fixture.sh +159 -0
  8. package/skills/magpie/evals/bare-invocation-goes-local/graders/branch-was-reachable.md +5 -0
  9. package/skills/magpie/evals/bare-invocation-goes-local/graders/never-went-to-a-pr.md +7 -0
  10. package/skills/magpie/evals/bare-invocation-goes-local/graders/setup-ran-local.md +6 -0
  11. package/skills/magpie/evals/bare-invocation-goes-local/prompt.md +11 -0
  12. package/skills/magpie/evals/baselines/claude-opus-5-5.json +27 -3
  13. package/skills/magpie/evals/rules.json +8 -0
  14. package/skills/magpie/scripts/__tests__/skill-lint.test.ts +8 -0
  15. package/skills/magpie/skill.json +1 -1
  16. package/skills/sluice/SKILL.md +21 -0
  17. package/skills/sluice/evals/README.md +6 -2
  18. package/skills/sluice/evals/deep-plan-checks-the-intent/case.yaml +4 -0
  19. package/skills/sluice/evals/deep-plan-checks-the-intent/fixture.sh +124 -0
  20. package/skills/sluice/evals/deep-plan-checks-the-intent/graders/announces-deep-channel.md +12 -0
  21. package/skills/sluice/evals/deep-plan-checks-the-intent/graders/checker-dispatched.md +12 -0
  22. package/skills/sluice/evals/deep-plan-checks-the-intent/graders/no-source-edit.md +11 -0
  23. package/skills/sluice/evals/deep-plan-checks-the-intent/graders/no-source-write.md +11 -0
  24. package/skills/sluice/evals/deep-plan-checks-the-intent/graders/signoff-reports-the-check.md +16 -0
  25. package/skills/sluice/evals/deep-plan-checks-the-intent/graders/sluice-fired.md +5 -0
  26. package/skills/sluice/evals/deep-plan-checks-the-intent/graders/spec-has-an-intent-map.md +19 -0
  27. package/skills/sluice/evals/deep-plan-checks-the-intent/graders/stopped-for-signoff.md +8 -0
  28. package/skills/sluice/evals/deep-plan-checks-the-intent/prompt.md +20 -0
  29. package/skills/sluice/evals/deep-plan-checks-the-plan/case.yaml +4 -0
  30. package/skills/sluice/evals/deep-plan-checks-the-plan/fixture.sh +178 -0
  31. package/skills/sluice/evals/deep-plan-checks-the-plan/graders/announces-deep-channel.md +12 -0
  32. package/skills/sluice/evals/deep-plan-checks-the-plan/graders/every-decision-built.md +15 -0
  33. package/skills/sluice/evals/deep-plan-checks-the-plan/graders/no-source-edit.md +11 -0
  34. package/skills/sluice/evals/deep-plan-checks-the-plan/graders/no-source-write.md +11 -0
  35. package/skills/sluice/evals/deep-plan-checks-the-plan/graders/plan-checker-dispatched.md +11 -0
  36. package/skills/sluice/evals/deep-plan-checks-the-plan/graders/plan-cites-the-spec.md +7 -0
  37. package/skills/sluice/evals/deep-plan-checks-the-plan/graders/sluice-fired.md +5 -0
  38. package/skills/sluice/evals/deep-plan-checks-the-plan/graders/stops-at-preflight.md +14 -0
  39. package/skills/sluice/evals/deep-plan-checks-the-plan/graders/validate-ran.md +9 -0
  40. package/skills/sluice/evals/deep-plan-checks-the-plan/prompt.md +12 -0
  41. package/skills/sluice/evals/deep-plan-reads-the-prior-spec/case.yaml +4 -0
  42. package/skills/sluice/evals/deep-plan-reads-the-prior-spec/fixture.sh +125 -0
  43. package/skills/sluice/evals/deep-plan-reads-the-prior-spec/graders/announces-deep-channel.md +12 -0
  44. package/skills/sluice/evals/deep-plan-reads-the-prior-spec/graders/context-cites-the-prior-spec.md +6 -0
  45. package/skills/sluice/evals/deep-plan-reads-the-prior-spec/graders/design-follows-the-prior-spec.md +21 -0
  46. package/skills/sluice/evals/deep-plan-reads-the-prior-spec/graders/design-written-to-docs.md +5 -0
  47. package/skills/sluice/evals/deep-plan-reads-the-prior-spec/graders/no-source-edit.md +11 -0
  48. package/skills/sluice/evals/deep-plan-reads-the-prior-spec/graders/no-source-write.md +11 -0
  49. package/skills/sluice/evals/deep-plan-reads-the-prior-spec/graders/sluice-fired.md +5 -0
  50. package/skills/sluice/evals/deep-plan-reads-the-prior-spec/prompt.md +17 -0
  51. package/skills/sluice/evals/deep-plan-traces-the-example/case.yaml +4 -0
  52. package/skills/sluice/evals/deep-plan-traces-the-example/fixture.sh +151 -0
  53. package/skills/sluice/evals/deep-plan-traces-the-example/graders/announces-deep-channel.md +12 -0
  54. package/skills/sluice/evals/deep-plan-traces-the-example/graders/design-written-to-docs.md +5 -0
  55. package/skills/sluice/evals/deep-plan-traces-the-example/graders/no-source-edit.md +11 -0
  56. package/skills/sluice/evals/deep-plan-traces-the-example/graders/no-source-write.md +11 -0
  57. package/skills/sluice/evals/deep-plan-traces-the-example/graders/sluice-fired.md +5 -0
  58. package/skills/sluice/evals/deep-plan-traces-the-example/graders/spec-has-a-trace.md +7 -0
  59. package/skills/sluice/evals/deep-plan-traces-the-example/graders/stopped-for-signoff.md +8 -0
  60. package/skills/sluice/evals/deep-plan-traces-the-example/graders/trace-finds-no-accepted-slide.md +27 -0
  61. package/skills/sluice/evals/deep-plan-traces-the-example/prompt.md +17 -0
  62. package/skills/sluice/evals/rules.json +36 -2
  63. package/skills/sluice/references/deep-channel.md +180 -5
  64. package/skills/sluice/scripts/plan.sh +115 -4
  65. package/skills/sluice/skill.json +2 -2
@@ -0,0 +1,151 @@
1
+ #!/usr/bin/env bash
2
+ # A deck app where the ticket's own example fails the obvious design. The deck
3
+ # store looks slides up by the title of their accepted version, and only the
4
+ # canvas ever accepts one, so the smoke deck, built in chat, has no accepted
5
+ # slides and the lookup the ticket says to reuse finds nothing. Nothing in the
6
+ # code is wrong; the trap is in designing from which functions exist instead of
7
+ # walking the example through the data. The README fixes where the design goes, so the graders can read it,
8
+ # what an unaccepted slide is called, and what writes slide text, because
9
+ # without them each is a fork the run rightly asks before writing any design.
10
+ set -euo pipefail
11
+
12
+ mkdir -p src/chat src/deck src/canvas data/decks tests docs/specs
13
+
14
+ cat > package.json <<'JSON'
15
+ {
16
+ "name": "decks",
17
+ "version": "0.9.0",
18
+ "type": "module",
19
+ "scripts": {
20
+ "test": "node --test \"tests/*.test.js\""
21
+ }
22
+ }
23
+ JSON
24
+
25
+ cat > src/deck/store.js <<'JS'
26
+ import { readFileSync, writeFileSync } from "node:fs";
27
+
28
+ const path = (id) => new URL(`../../data/decks/${id}.json`, import.meta.url);
29
+
30
+ export function loadDeck(id) {
31
+ return JSON.parse(readFileSync(path(id), "utf8"));
32
+ }
33
+
34
+ export function saveDeck(deck) {
35
+ writeFileSync(path(deck.id), JSON.stringify(deck, null, 2) + "\n");
36
+ }
37
+
38
+ // A slide's title is the title of the version the user accepted on the canvas.
39
+ export function findSlideByTitle(deck, title) {
40
+ const wanted = title.trim().toLowerCase();
41
+ return deck.slides.find((slide) => {
42
+ const accepted = slide.versions[slide.accepted];
43
+ return accepted !== undefined && accepted.title.toLowerCase() === wanted;
44
+ });
45
+ }
46
+ JS
47
+
48
+ cat > src/deck/redraft.js <<'JS'
49
+ // Appends a new version; the canvas decides whether the user accepts it.
50
+ export function redraftSlide(slide, draft) {
51
+ slide.versions.push({ title: draft.title, body: draft.body });
52
+ return slide.versions.length - 1;
53
+ }
54
+ JS
55
+
56
+ cat > src/deck/draft.js <<'JS'
57
+ // Slide text comes from the model; callers pass the completion so tests can stub it.
58
+ export async function draftSlide(version, instruction, complete) {
59
+ const text = await complete(
60
+ `Rewrite this slide. ${instruction}\nTitle: ${version.title}\nBody: ${version.body}`,
61
+ );
62
+ const [title, ...body] = text.trim().split("\n");
63
+ return { title: title.replace(/^Title:\s*/, ""), body: body.join("\n").replace(/^Body:\s*/, "") };
64
+ }
65
+ JS
66
+
67
+ cat > src/canvas/accept.js <<'JS'
68
+ export function accept(slide, versionIndex) {
69
+ if (slide.versions[versionIndex] === undefined) {
70
+ throw new Error(`no version ${versionIndex} on slide ${slide.id}`);
71
+ }
72
+ slide.accepted = versionIndex;
73
+ }
74
+ JS
75
+
76
+ cat > src/chat/build-deck.js <<'JS'
77
+ export function buildDeck(id, outline) {
78
+ return {
79
+ id,
80
+ slides: outline.map((item, index) => ({
81
+ id: `s${index + 1}`,
82
+ accepted: null,
83
+ versions: [{ title: item.title, body: item.body }],
84
+ })),
85
+ };
86
+ }
87
+ JS
88
+
89
+ cat > src/chat/router.js <<'JS'
90
+ export function route(message) {
91
+ if (/^(prepare|build|make)\b.*\bslides?\b/i.test(message)) {
92
+ return { intent: "build-deck" };
93
+ }
94
+ return { intent: "chat" };
95
+ }
96
+ JS
97
+
98
+ cat > data/decks/smoke.json <<'JSON'
99
+ {
100
+ "id": "smoke",
101
+ "slides": [
102
+ {
103
+ "id": "s1",
104
+ "accepted": null,
105
+ "versions": [{ "title": "Why a pilot", "body": "Three sites asked for it." }]
106
+ },
107
+ {
108
+ "id": "s2",
109
+ "accepted": null,
110
+ "versions": [{ "title": "Pilot Stages", "body": "Recruit, run for six weeks, review." }]
111
+ },
112
+ {
113
+ "id": "s3",
114
+ "accepted": null,
115
+ "versions": [{ "title": "Next steps", "body": "Pick the sites by May." }]
116
+ }
117
+ ]
118
+ }
119
+ JSON
120
+
121
+ cat > tests/store.test.js <<'JS'
122
+ import assert from "node:assert/strict";
123
+ import { test } from "node:test";
124
+ import { findSlideByTitle } from "../src/deck/store.js";
125
+
126
+ test("a slide is found by the title of its accepted version", () => {
127
+ const deck = { slides: [{ id: "s1", accepted: 0, versions: [{ title: "Pilot Stages" }] }] };
128
+ assert.equal(findSlideByTitle(deck, "pilot stages").id, "s1");
129
+ });
130
+ JS
131
+
132
+ cat > README.md <<'MD'
133
+ # decks
134
+
135
+ Chat builds a deck (`src/chat/build-deck.js`), the canvas lets a user accept a
136
+ slide version (`src/canvas/accept.js`), and the deck store reads and writes
137
+ `data/decks/<id>.json`. Until a user accepts a version, a slide shows, and is
138
+ called by, its latest one. Slide text, for a new deck or a redraft, comes from
139
+ `draftSlide` in `src/deck/draft.js`. `data/decks/smoke.json` is the smoke deck QA runs
140
+ tickets against. `npm test` runs the suite.
141
+
142
+ ## Designs
143
+
144
+ A ticket's design goes in `docs/specs/<ticket>.md`, for example
145
+ `docs/specs/DEK-12.md`, and its plan in `docs/plans/<ticket>.md`.
146
+ MD
147
+ touch docs/specs/.gitkeep
148
+
149
+ git init --quiet
150
+ git add -A
151
+ git -c user.email=fixture@example.com -c user.name=fixture commit --quiet -m "decks 0.9.0"
@@ -0,0 +1,12 @@
1
+ ---
2
+ type: regex
3
+ # The trace carries SKILL.md's own routing table, which names every channel, so
4
+ # `contains` passes whenever the skill loads. Anchor on the two ways the agent
5
+ # routes instead, the same ones run-stats.sh meters: a Bash call that invokes
6
+ # `status.sh route deep` (a quoted mention, as in a grep, does not count), or the
7
+ # words opening an assistant message or following a label such as "Sluice:".
8
+ pattern: '"command":"(?:(?:[^"\\]|\\.)*?(?:[\s/]|\\[nt]))?status\.sh(?:\\"|'')?(?:\s|\\[nt])+route(?:\s|\\[nt])+deep(?:\s|\\[nt]|[;&|]|")|"text":"(?:[^.!?\n"]{0,100}[:=]\s*)?[\s*_#>\\]*deep channel'
9
+ flags: i
10
+ target: trace
11
+ weight: 2
12
+ ---
@@ -0,0 +1,5 @@
1
+ ---
2
+ type: file_exists
3
+ path: 'docs/specs/DEK-41.md'
4
+ weight: 2
5
+ ---
@@ -0,0 +1,11 @@
1
+ ---
2
+ type: tool_used
3
+ # The run plans and stops for sign-off, so no Edit may land under src/ or
4
+ # tests/. Bash is left out of the case's tools, so these two are the only ways
5
+ # code could change.
6
+ tool: Edit
7
+ input_match: '"file_path"\s*:\s*"(?:[^"]*/)?(?:src|tests)/'
8
+ min: 0
9
+ max: 0
10
+ weight: 2
11
+ ---
@@ -0,0 +1,11 @@
1
+ ---
2
+ type: tool_used
3
+ # The run plans and stops for sign-off, so no Write may land under src/ or
4
+ # tests/. Bash is left out of the case's tools, so these two are the only ways
5
+ # code could change.
6
+ tool: Write
7
+ input_match: '"file_path"\s*:\s*"(?:[^"]*/)?(?:src|tests)/'
8
+ min: 0
9
+ max: 0
10
+ weight: 2
11
+ ---
@@ -0,0 +1,5 @@
1
+ ---
2
+ type: tool_used
3
+ tool: Skill
4
+ input_match: '"skill"\s*:\s*"(?:[\w-]+:)?sluice"'
5
+ ---
@@ -0,0 +1,7 @@
1
+ ---
2
+ type: regex
3
+ pattern: '^#{2,3}\s*Trace\b'
4
+ flags: m
5
+ target: { source: file, path: docs/specs/DEK-41.md }
6
+ weight: 2
7
+ ---
@@ -0,0 +1,8 @@
1
+ ---
2
+ type: llm
3
+ ---
4
+
5
+ The agent was asked to plan a ticket that spans the chat router, the deck store and the redraft path.
6
+
7
+ PASS if the final message hands a written design back for sign-off: it says where the design was written and asks for approval, or otherwise makes clear it is waiting before any code is written.
8
+ FAIL if the final message reports implementation work as done, moves straight into building, or presents the design as settled with no sign-off asked for.
@@ -0,0 +1,27 @@
1
+ ---
2
+ type: llm
3
+ focus: { source: file, path: docs/specs/DEK-41.md }
4
+ weight: 3
5
+ ---
6
+
7
+ This is the design for a ticket whose example is "Redraft the Pilot Stages
8
+ slide to lead with the pilot outcome" on the smoke deck. In the repo,
9
+ `findSlideByTitle` matches only on the title of a slide's accepted version,
10
+ only the canvas ever sets `accepted`, and every slide in
11
+ `data/decks/smoke.json` has `"accepted": null`. So the lookup the ticket says
12
+ to reuse finds no slide for the ticket's own example.
13
+
14
+ Judge the section under the design's Trace heading for the walk, and the rest
15
+ of the design only for the lookup it settles on.
16
+
17
+ PASS if the Trace section quotes the ticket's example, walks it through the
18
+ smoke deck's actual data, and records there that its slides have no accepted
19
+ version (so the existing lookup returns nothing), and the design builds the
20
+ slide lookup around that, consistent with the
21
+ README (an unaccepted slide is called by its latest version): for example,
22
+ matching the accepted version's title when there is one and the latest
23
+ version's otherwise.
24
+ FAIL if there is no Trace section, if the accepted-slide finding appears only
25
+ outside it, if the design reuses `findSlideByTitle` or the accepted version as
26
+ it stands, or if the accepted state is mentioned only as a general risk
27
+ without saying what the smoke deck holds.
@@ -0,0 +1,17 @@
1
+ ---
2
+ name: deep-plan-traces-the-example
3
+ description: A deep plan whose ticket example contradicts the obvious design. Pins a Trace section in the spec that walks the example through the fixture's real data before sign-off.
4
+ tags: [routing, deep, write]
5
+ max_turns: 25
6
+ timeout_seconds: 900
7
+ allowed_tools: [Read, Glob, Grep, Skill, Write]
8
+ expected_outcome: Announces the deep channel, writes docs/specs/DEK-41.md with a Trace section that runs the ticket's sentence against the smoke deck, finds its slides have no accepted version, designs around that, and stops for sign-off without code.
9
+ ---
10
+
11
+ Plan DEK-41 for us.
12
+
13
+ > Let people revise a single slide from chat. Example, on the smoke deck:
14
+ > "Redraft the Pilot Stages slide to lead with the pilot outcome" should redraft
15
+ > that slide and leave the rest alone. The chat router needs a revise intent;
16
+ > finding the slide and saving the redraft should reuse what the deck store and
17
+ > the redraft path already do.
@@ -31,7 +31,8 @@
31
31
  "origin": "docs/specs/2026-08-07-sluice-design.md",
32
32
  "cases": [
33
33
  "deep-plan-across-subsystems",
34
- "deep-plan-asks-the-fork"
34
+ "deep-plan-asks-the-fork",
35
+ "deep-plan-traces-the-example"
35
36
  ]
36
37
  },
37
38
  {
@@ -63,7 +64,8 @@
63
64
  "origin": "docs/specs/2026-08-07-sluice-design.md",
64
65
  "cases": [
65
66
  "deep-plan-across-subsystems",
66
- "deep-plan-asks-the-fork"
67
+ "deep-plan-asks-the-fork",
68
+ "deep-plan-traces-the-example"
67
69
  ]
68
70
  },
69
71
  {
@@ -74,6 +76,38 @@
74
76
  "deep-plan-asks-the-fork"
75
77
  ]
76
78
  },
79
+ {
80
+ "id": "deep-design-traces-the-example",
81
+ "states": "SKILL.md: Deep channel",
82
+ "origin": "commit:7decf60",
83
+ "cases": [
84
+ "deep-plan-traces-the-example"
85
+ ]
86
+ },
87
+ {
88
+ "id": "deep-reads-the-ground-before-the-design",
89
+ "states": "references/deep-channel.md: The ground",
90
+ "origin": "docs/specs/2026-10-21-sluice-deep-alignment.md",
91
+ "cases": [
92
+ "deep-plan-reads-the-prior-spec"
93
+ ]
94
+ },
95
+ {
96
+ "id": "deep-checks-the-spec-against-the-intent",
97
+ "states": "references/deep-channel.md: The alignment checks",
98
+ "origin": "docs/specs/2026-10-21-sluice-deep-alignment.md",
99
+ "cases": [
100
+ "deep-plan-checks-the-intent"
101
+ ]
102
+ },
103
+ {
104
+ "id": "deep-checks-the-plan-against-the-spec",
105
+ "states": "references/deep-channel.md: The alignment checks",
106
+ "origin": "docs/specs/2026-10-21-sluice-deep-alignment.md",
107
+ "cases": [
108
+ "deep-plan-checks-the-plan"
109
+ ]
110
+ },
77
111
  {
78
112
  "id": "deep-stops-for-plan-and-pre-flight",
79
113
  "states": "SKILL.md: Deep channel",
@@ -8,6 +8,19 @@
8
8
  message convention is one of them, written out at literal value along with
9
9
  anything the repo forbids a message from carrying. An implementer arrives
10
10
  with its own defaults and will use them on anything you left unsaid.
11
+ - A **Spec** line, `**Spec:** <path>` directly under the title, names the
12
+ signed-off design the plan builds. It is a line rather than a mention in
13
+ the Goal because `plan.sh validate` reads the spec's `### D<n>.` decisions
14
+ from that path, and a path written into prose gives it nothing to parse. A
15
+ relative path is read from the plan's repo root, as `docs/specs/...`, so
16
+ validate means the same thing from any directory; outside a git repo it is
17
+ read from the plan's own directory.
18
+ - A **Builds** line on every task names the decisions it builds,
19
+ `**Builds:** D1, D3`, or `**Builds:** none, <why>` for a task such as a
20
+ version bump that builds none. Validate checks coverage from these lines
21
+ and nothing else: every decision built by some task, no task building one
22
+ the spec lacks. Step prose mentioning `D1` does not count, because a docs
23
+ task that reads its work back "against D1 to D4" builds none of them.
11
24
  - No implementer sees a neighbouring task, so each task carries a
12
25
  **Contract**, not optional: a symbol absent from it does not exist for
13
26
  whoever builds the task. `Needs` names what this task calls but another
@@ -54,18 +67,26 @@ Most of what this section asks for needs no judgement to check: a `Needs` no
54
67
  task `Offers`, a "TBD", a step deferring to a neighbour, a missing `Contract`,
55
68
  a plan with no flip or two of them, an `Effort` mark on a task the tier table
56
69
  sends to tier 3, a `Model` mark anywhere. Those come back as errors with the
57
- task number on them. The warnings are the judgement calls left to you: a step
58
- with no proof, a `Needs` satisfied only by a later task, two tasks whose
59
- `Touches` overlap. Reading the plan yourself catches these on a good day, and
60
- the point of a check is the other kind of day.
70
+ task number on them. It also checks the plan against its spec, and a miss
71
+ there is an error too: a Spec line naming a readable file whose decisions are
72
+ `### D<n>.` headings, a Builds line on every task of `D<n>` ids or
73
+ `none, <why>`, every decision built and none invented. Each message says what
74
+ to fix, and names the task where one is at fault, so read them as validate
75
+ prints them. The
76
+ warnings are the judgement calls left to you: a step with no proof, a `Needs`
77
+ satisfied only by a later task, two tasks whose `Touches` overlap. Reading
78
+ the plan yourself catches these on a good day, and the point of a check is
79
+ the other kind of day.
61
80
 
62
81
  ```
63
82
  # Plan: <topic>
83
+ **Spec:** <path to the signed-off design>
64
84
  ## Ground Rules
65
85
  - <exact value>
66
86
  ### Task N: <name>
67
87
  **Contract:** Needs: <sig> | Offers: <sig>
68
88
  **Touches:** <path> (new) | <path> (edit) | <path> (test)
89
+ **Builds:** <D<n>, ..., or none and why>
69
90
  **Flips:** <what changes, from what, or omit>
70
91
  **Review:** <reason, or omit>
71
92
  **Effort:** <low, and why the work is mechanical, or omit>
@@ -118,6 +139,10 @@ Pre-flight lands in both, which is the one deliberate overlap: `run.json` holds
118
139
  the answer, so the file can say whether the stop happened at all, and the record
119
140
  holds the reason, so a reader can tell whether it should have gone that way.
120
141
  Those rows come first and open the record for the same reason they always did.
142
+ The outcomes of the intent check and the plan check sit among those opening
143
+ rows, each with its finding count and what came of them: both ran before the
144
+ record existed, so they are held until it opens, as pre-flight's answers are,
145
+ and written in with them.
121
146
 
122
147
  Where it goes follows the repo if the repo has a convention, and
123
148
  `docs/plans/YYYY-MM-DD-<topic>-record.md` if it does not. It belongs to you
@@ -183,6 +208,154 @@ on it, and let the next instruction start the plan. Nothing else about this
183
208
  section changes, because the obligation was never the mode's, only the
184
209
  enforcement was.
185
210
 
211
+ ## The ground
212
+
213
+ Read the repo before you walk anything through it. A prior spec often settles
214
+ the very fork you were about to ask about, and "anything you can settle from
215
+ the repo is not that fork" only holds once the repo has been read: until then
216
+ every fork looks like your partner's, and every pattern looks like yours to
217
+ invent. So the ground comes first, then the trace, then the fork question,
218
+ then the draft.
219
+
220
+ Ask for three things, each cited by path:
221
+
222
+ 1. **Prior designs.** Specs and plans under the repo's spec and plan
223
+ directories that touch the same subsystems or files, and what each settled
224
+ that the new design must build on, supersede or leave alone.
225
+ 2. **The code beside the path.** How the nearest similar feature is built (its
226
+ shape, where its state lives, how it is tested), so the design matches the
227
+ repo rather than inventing a pattern beside it.
228
+ 3. **Stated constraints.** Repo instructions, CI gates, the test runner and its
229
+ conventions, and release steps that the design or its plan will answer to.
230
+
231
+ Dispatch it as a read-only Explore agent where the harness has one, for the
232
+ reason the reviewer is dispatched: the file dumps fill its context instead of
233
+ yours, and you only need what it concluded. Where there is no dispatch, it is
234
+ your own read, with the same three questions. Either way the findings go into
235
+ the spec's `## Context`, one line each with the path it came from, so the
236
+ intent check and every later reader can see what the design was built on and
237
+ go and look.
238
+
239
+ A design whose `## Context` cites no earlier spec, when one covers the same
240
+ scripts, is the gap this section exists to close. Read for it rather than
241
+ assuming there is none.
242
+
243
+ The spec has a fixed shape, because the intent check reads it by section:
244
+
245
+ ```
246
+ # Design: <topic>
247
+ ## Intent
248
+ ## Context
249
+ ## Decisions
250
+ ### D1. <title>
251
+ ## Out of scope
252
+ ## Trace
253
+ ```
254
+
255
+ `## Intent` holds the request quoted verbatim, each question asked through
256
+ `AskUserQuestion` with the answer it got, and a table mapping each ask to the
257
+ `D<n>` decisions that deliver it, or to `## Out of scope` with the reason.
258
+ Decisions are headed `### D<n>. <title>`, which is what `plan.sh validate`
259
+ reads. Out of scope is its own section and never a numbered decision, because
260
+ a decision is something a task builds, and one no task could build would fail
261
+ the plan's coverage check for being honest.
262
+
263
+ ## The trace
264
+
265
+ A design written from the shape of the code (which functions exist, which slots
266
+ they fill) can be sound on paper and still fail the request's own example,
267
+ and nothing after it notices: per-task reviews read each task against its own
268
+ text, and the hunt runs once every task is done. So walk the request through
269
+ the system as it stands before you draft, and give the design a `## Trace`
270
+ section that records the walk (in the plan file under plan mode, carried into
271
+ the spec on approval):
272
+
273
+ 1. **The example, verbatim.** Quote the sentence, command or scenario the
274
+ request gives. Where it gives none, write the acceptance criterion as one
275
+ concrete case and say that you did.
276
+ 2. **Through the real data.** Follow that case step by step through the rows,
277
+ files or fixtures it would touch, as they exist now rather than as the
278
+ design assumes them: read the record, run the query, open the fixture, and
279
+ cite what each step read. "A deck built in chat has no accepted slides" is
280
+ a fact one read away, and a design keyed on accepted slides is wrong without
281
+ it.
282
+ 3. **What each reused path requires and writes.** For every function the
283
+ design reuses, its preconditions and its side effects, read from the code
284
+ and not from its name. Run the example a second time where the request
285
+ implies a repeat (a redraft of a redraft, an edit after an edit), because
286
+ what the first pass wrote is what the second pass reads.
287
+ 4. **What the walk ruled out.** Each place it contradicted the obvious design
288
+ (the reuse the request suggests, the first shape that came to mind), and
289
+ what the design does instead. An empty list is a result, not a skipped
290
+ step.
291
+
292
+ The order is the ground, the walk, the fork, the draft. Walking after the
293
+ ground and before the fork is what puts a fork where **The design stop and
294
+ plan mode** wants it: one the walk turns up only your partner can settle is
295
+ asked before the design is written, and the trace goes into the design with
296
+ the answer.
297
+
298
+ The trace is what the sign-off is signing: a design without the section is
299
+ incomplete, however good the rest reads. It is not a prototype and not a hunt;
300
+ anything that only shows at runtime (routing, timing, a renderer) stays with
301
+ the hunt after the flip.
302
+
303
+ ## The alignment checks
304
+
305
+ A spec can mention every ask and deliver none of them, and a plan can cite
306
+ every decision and build half of one. Its author reads past both, because the
307
+ author knows what was meant. So each of the two stops gets a fresh reader
308
+ first: a dispatch with fresh context on this session's model and effort,
309
+ never downshifted, as with the final review, since a cheaper reader is the one
310
+ that misses a gap in meaning.
311
+
312
+ **The intent check runs before sign-off**, once the draft and its trace are
313
+ written and before `ExitPlanMode` or the prose stop. Send it the path the
314
+ design is drafted at, the harness's plan file under plan mode and the spec
315
+ file otherwise, and ask it to read the design's `## Intent` section by that
316
+ name, then:
317
+
318
+ - Does each ask in `## Intent` reach a decision that actually delivers it, not
319
+ one that merely mentions it?
320
+ - Is any decision traceable to no ask, an addition nobody asked for?
321
+ - Is any ask dropped, or moved to Out of scope without a reason?
322
+ - Does the design honour every answer recorded in `## Intent` and every
323
+ constraint in `## Context`?
324
+
325
+ Run it before the stop rather than after because a partner who signs first
326
+ signs a spec whose gaps were not yet known. On a redraft after the stop, run
327
+ it again only if a decision changed, since the map is what it reads.
328
+
329
+ **The plan check runs after `plan.sh validate` is clean and before
330
+ pre-flight**'s questions, with the spec and plan paths both in the brief:
331
+
332
+ - Does each task citing `D<n>` actually build what `D<n>` says? Across its
333
+ tasks, is each decision covered whole rather than in part?
334
+ - Does any task build something listed in Out of scope, or a shape the Trace
335
+ ruled out?
336
+ - Do the Ground Rules contradict a constraint in the spec's Context?
337
+ - Does the `Flips` task turn on what the spec says turns on?
338
+
339
+ Validate has already settled what a parser can, so this reader is spent on
340
+ what it cannot: whether the words of a task do what the words of a decision
341
+ say.
342
+
343
+ Fix each finding you agree with, in the draft for the intent check and in the
344
+ plan for the plan check, before the stop; the spec is signed by the time the
345
+ plan check runs, so nothing it finds edits the spec.
346
+ What you dispute goes into that stop's message, one line each, so your partner
347
+ signs with the disagreements in view rather than finding them later. The
348
+ sign-off message says the intent check ran, how many findings it returned and
349
+ how many were fixed; a stop that says nothing about it reads the same as one
350
+ where it never ran. After the plan check's fixes, re-run `plan.sh validate`,
351
+ because a fix to a Builds line is exactly what validate checks and the check
352
+ it passed was on the plan before the fix. Both outcomes go into the run
353
+ record's opening rows when it opens, for the reason that section gives.
354
+
355
+ Without dispatch there is no fresh reader to send. Say so at the stop and ask
356
+ the same questions yourself, as **When dispatch is unavailable** says for
357
+ review: your own read is weaker, and your partner should know it was yours.
358
+
186
359
  ## Pre-flight
187
360
 
188
361
  Design signed off, plan written, nothing built yet. Before Task 1, stop once
@@ -492,7 +665,9 @@ who will carry it out, only your partner's read of work you will do yourself.
492
665
  Task isolation is gone, so
493
666
  `run.json` and the record now carry all of the state that outlives compaction
494
667
  and matter more, not less. And fresh context is unavailable, which was the entire thing
495
- review was buying.
668
+ review was buying. The alignment checks fall back to your own read of the
669
+ same questions, and you say so at the stop, so the sign-off is not mistaken
670
+ for one a fresh reader cleared.
496
671
 
497
672
  One thing does not change: the work still owes a review. Reading your own diff
498
673
  is not one, and the table below still names which tasks needed the stronger