@iceinvein/agent-skills 0.23.8 → 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.
- package/package.json +1 -1
- package/skills/index.json +3 -3
- package/skills/magpie/README.md +1 -1
- package/skills/magpie/SKILL.md +2 -2
- package/skills/magpie/evals/README.md +22 -8
- package/skills/magpie/evals/bare-invocation-goes-local/case.yaml +4 -0
- package/skills/magpie/evals/bare-invocation-goes-local/fixture.sh +159 -0
- package/skills/magpie/evals/bare-invocation-goes-local/graders/branch-was-reachable.md +5 -0
- package/skills/magpie/evals/bare-invocation-goes-local/graders/never-went-to-a-pr.md +7 -0
- package/skills/magpie/evals/bare-invocation-goes-local/graders/setup-ran-local.md +6 -0
- package/skills/magpie/evals/bare-invocation-goes-local/prompt.md +11 -0
- package/skills/magpie/evals/baselines/claude-opus-5-5.json +27 -3
- package/skills/magpie/evals/rules.json +8 -0
- package/skills/magpie/scripts/__tests__/skill-lint.test.ts +8 -0
- package/skills/magpie/skill.json +1 -1
- package/skills/sluice/SKILL.md +13 -0
- package/skills/sluice/evals/README.md +5 -2
- package/skills/sluice/evals/deep-plan-checks-the-intent/case.yaml +4 -0
- package/skills/sluice/evals/deep-plan-checks-the-intent/fixture.sh +124 -0
- package/skills/sluice/evals/deep-plan-checks-the-intent/graders/announces-deep-channel.md +12 -0
- package/skills/sluice/evals/deep-plan-checks-the-intent/graders/checker-dispatched.md +12 -0
- package/skills/sluice/evals/deep-plan-checks-the-intent/graders/no-source-edit.md +11 -0
- package/skills/sluice/evals/deep-plan-checks-the-intent/graders/no-source-write.md +11 -0
- package/skills/sluice/evals/deep-plan-checks-the-intent/graders/signoff-reports-the-check.md +16 -0
- package/skills/sluice/evals/deep-plan-checks-the-intent/graders/sluice-fired.md +5 -0
- package/skills/sluice/evals/deep-plan-checks-the-intent/graders/spec-has-an-intent-map.md +19 -0
- package/skills/sluice/evals/deep-plan-checks-the-intent/graders/stopped-for-signoff.md +8 -0
- package/skills/sluice/evals/deep-plan-checks-the-intent/prompt.md +20 -0
- package/skills/sluice/evals/deep-plan-checks-the-plan/case.yaml +4 -0
- package/skills/sluice/evals/deep-plan-checks-the-plan/fixture.sh +178 -0
- package/skills/sluice/evals/deep-plan-checks-the-plan/graders/announces-deep-channel.md +12 -0
- package/skills/sluice/evals/deep-plan-checks-the-plan/graders/every-decision-built.md +15 -0
- package/skills/sluice/evals/deep-plan-checks-the-plan/graders/no-source-edit.md +11 -0
- package/skills/sluice/evals/deep-plan-checks-the-plan/graders/no-source-write.md +11 -0
- package/skills/sluice/evals/deep-plan-checks-the-plan/graders/plan-checker-dispatched.md +11 -0
- package/skills/sluice/evals/deep-plan-checks-the-plan/graders/plan-cites-the-spec.md +7 -0
- package/skills/sluice/evals/deep-plan-checks-the-plan/graders/sluice-fired.md +5 -0
- package/skills/sluice/evals/deep-plan-checks-the-plan/graders/stops-at-preflight.md +14 -0
- package/skills/sluice/evals/deep-plan-checks-the-plan/graders/validate-ran.md +9 -0
- package/skills/sluice/evals/deep-plan-checks-the-plan/prompt.md +12 -0
- package/skills/sluice/evals/deep-plan-reads-the-prior-spec/case.yaml +4 -0
- package/skills/sluice/evals/deep-plan-reads-the-prior-spec/fixture.sh +125 -0
- package/skills/sluice/evals/deep-plan-reads-the-prior-spec/graders/announces-deep-channel.md +12 -0
- package/skills/sluice/evals/deep-plan-reads-the-prior-spec/graders/context-cites-the-prior-spec.md +6 -0
- package/skills/sluice/evals/deep-plan-reads-the-prior-spec/graders/design-follows-the-prior-spec.md +21 -0
- package/skills/sluice/evals/deep-plan-reads-the-prior-spec/graders/design-written-to-docs.md +5 -0
- package/skills/sluice/evals/deep-plan-reads-the-prior-spec/graders/no-source-edit.md +11 -0
- package/skills/sluice/evals/deep-plan-reads-the-prior-spec/graders/no-source-write.md +11 -0
- package/skills/sluice/evals/deep-plan-reads-the-prior-spec/graders/sluice-fired.md +5 -0
- package/skills/sluice/evals/deep-plan-reads-the-prior-spec/prompt.md +17 -0
- package/skills/sluice/evals/rules.json +24 -0
- package/skills/sluice/references/deep-channel.md +145 -8
- package/skills/sluice/scripts/plan.sh +115 -4
- package/skills/sluice/skill.json +2 -2
|
@@ -84,6 +84,30 @@
|
|
|
84
84
|
"deep-plan-traces-the-example"
|
|
85
85
|
]
|
|
86
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
|
+
},
|
|
87
111
|
{
|
|
88
112
|
"id": "deep-stops-for-plan-and-pre-flight",
|
|
89
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.
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
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,58 @@ 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
|
+
|
|
186
263
|
## The trace
|
|
187
264
|
|
|
188
265
|
A design written from the shape of the code (which functions exist, which slots
|
|
@@ -212,15 +289,73 @@ the spec on approval):
|
|
|
212
289
|
what the design does instead. An empty list is a result, not a skipped
|
|
213
290
|
step.
|
|
214
291
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
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.
|
|
218
297
|
|
|
219
298
|
The trace is what the sign-off is signing: a design without the section is
|
|
220
299
|
incomplete, however good the rest reads. It is not a prototype and not a hunt;
|
|
221
300
|
anything that only shows at runtime (routing, timing, a renderer) stays with
|
|
222
301
|
the hunt after the flip.
|
|
223
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
|
+
|
|
224
359
|
## Pre-flight
|
|
225
360
|
|
|
226
361
|
Design signed off, plan written, nothing built yet. Before Task 1, stop once
|
|
@@ -530,7 +665,9 @@ who will carry it out, only your partner's read of work you will do yourself.
|
|
|
530
665
|
Task isolation is gone, so
|
|
531
666
|
`run.json` and the record now carry all of the state that outlives compaction
|
|
532
667
|
and matter more, not less. And fresh context is unavailable, which was the entire thing
|
|
533
|
-
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.
|
|
534
671
|
|
|
535
672
|
One thing does not change: the work still owes a review. Reading your own diff
|
|
536
673
|
is not one, and the table below still names which tasks needed the stronger
|
|
@@ -13,6 +13,11 @@
|
|
|
13
13
|
#
|
|
14
14
|
# validate prints one line per finding. An error means the plan cannot be
|
|
15
15
|
# dispatched as written; a warning is a judgement call left to its author.
|
|
16
|
+
# Besides the plan's own skeleton, it reads the spec the plan's **Spec:** line
|
|
17
|
+
# names (a relative path from the plan's repo root, or from the plan's own
|
|
18
|
+
# directory outside a repo) and checks every "### D<n>." decision
|
|
19
|
+
# there is built by some task's **Builds:** line, and that no task builds one the
|
|
20
|
+
# spec does not have.
|
|
16
21
|
# import seeds the run state's task rows from the plan, so the ids, names, the
|
|
17
22
|
# flip, the effort marks and the tiers come from the file rather than from a
|
|
18
23
|
# dozen hand-typed commands. It is safe to re-run: a status, a review mark or a
|
|
@@ -57,10 +62,19 @@ usage() {
|
|
|
57
62
|
# than free markdown. Fenced blocks are skipped: a plan carries signatures and
|
|
58
63
|
# commands in them, and a `- [ ]` inside a fence is an example, not a step.
|
|
59
64
|
PARSER='
|
|
60
|
-
BEGIN {
|
|
65
|
+
BEGIN {
|
|
66
|
+
SEP = sprintf("%c", 31)
|
|
67
|
+
# The one form a Builds line takes, said once for every message that asks for it.
|
|
68
|
+
BUILDS_HINT = "write D<n>, or none, <why>"
|
|
69
|
+
}
|
|
61
70
|
|
|
62
71
|
function trim(s) { gsub(/^[ \t]+|[ \t]+$/, "", s); return s }
|
|
63
72
|
|
|
73
|
+
# Single-quoted for system(). The quote is built rather than written because
|
|
74
|
+
# this program is itself a single-quoted shell string, and an embedded quote
|
|
75
|
+
# becomes '"'"' because a backslash in a gsub replacement differs between awks.
|
|
76
|
+
function shq(s, q) { q = sprintf("%c", 39); gsub(q, q "\"" q "\"" q, s); return q s q }
|
|
77
|
+
|
|
64
78
|
# Symbols on one side of a Contract line. The two sides are read differently
|
|
65
79
|
# because a mistake costs differently on each.
|
|
66
80
|
#
|
|
@@ -145,6 +159,17 @@ fenced { next }
|
|
|
145
159
|
|
|
146
160
|
/^# Plan:/ { has_title = 1 }
|
|
147
161
|
|
|
162
|
+
# Before the first task only: a Spec line inside a task is that task naming a
|
|
163
|
+
# file, not the plan naming its design.
|
|
164
|
+
ntasks == 0 && /^\*\*Spec:\*\*/ {
|
|
165
|
+
spec_path = trim(substr($0, length("**Spec:**") + 1))
|
|
166
|
+
# Older plans write the path as code with prose after it, so a backticked
|
|
167
|
+
# span is the path and the rest is commentary.
|
|
168
|
+
if (match(spec_path, /`[^`]+`/)) spec_path = trim(substr(spec_path, RSTART + 1, RLENGTH - 2))
|
|
169
|
+
has_spec = 1
|
|
170
|
+
next
|
|
171
|
+
}
|
|
172
|
+
|
|
148
173
|
/^## / {
|
|
149
174
|
in_rules = (tolower($0) ~ /^## ground rules/) ? 1 : 0
|
|
150
175
|
if (in_rules) has_rules_heading = 1
|
|
@@ -249,6 +274,27 @@ in_rules && /^- / { nrules++ }
|
|
|
249
274
|
next
|
|
250
275
|
}
|
|
251
276
|
|
|
277
|
+
/^\*\*Builds:\*\*/ {
|
|
278
|
+
has_builds[cur] = 1
|
|
279
|
+
body = trim(substr($0, length("**Builds:**") + 1))
|
|
280
|
+
# Validate-only, like the spec coverage below: a plan that imported before
|
|
281
|
+
# Builds lines existed must not be refused over one it cannot parse.
|
|
282
|
+
if (body == "") {
|
|
283
|
+
if (check_spec) finding("error", "task " cur " has an empty Builds line; " BUILDS_HINT)
|
|
284
|
+
next
|
|
285
|
+
}
|
|
286
|
+
if (tolower(body) ~ /^none([ \t,.;:]|$)/) next
|
|
287
|
+
n = split(body, parts, /[, \t]+/)
|
|
288
|
+
for (i = 1; i <= n; i++) {
|
|
289
|
+
# Authors write the line as prose, so "D2." closing a sentence is D2.
|
|
290
|
+
sub(/[.;:]+$/, "", parts[i])
|
|
291
|
+
if (parts[i] == "") continue
|
|
292
|
+
if (parts[i] ~ /^D[0-9]+$/) builds[cur] = builds[cur] " " parts[i]
|
|
293
|
+
else if (check_spec) finding("error", "task " cur " Builds " parts[i] ", which is not a decision id; " BUILDS_HINT)
|
|
294
|
+
}
|
|
295
|
+
next
|
|
296
|
+
}
|
|
297
|
+
|
|
252
298
|
/^\*\*Flips:\*\*/ { has_flips[cur] = 1; nflips++; flips_list = flips_list (flips_list == "" ? "" : ", ") cur; next }
|
|
253
299
|
/^\*\*Review:\*\*/ { has_review[cur] = 1; next }
|
|
254
300
|
/^\*\*Model:\*\*/ { has_model[cur] = 1; next }
|
|
@@ -323,6 +369,62 @@ END {
|
|
|
323
369
|
}
|
|
324
370
|
}
|
|
325
371
|
|
|
372
|
+
# Gated, because only validate reads the spec. Import is run from wherever
|
|
373
|
+
# the run state lives, so a relative Spec path need not resolve there, and a
|
|
374
|
+
# plan already validated should not be refused over it.
|
|
375
|
+
if (check_spec) {
|
|
376
|
+
spec_file = spec_path
|
|
377
|
+
if (spec_path != "" && spec_path !~ /^\//) spec_file = ENVIRON["SLUICE_SPEC_BASE"] "/" spec_path
|
|
378
|
+
if (!has_spec) {
|
|
379
|
+
finding("error", "no **Spec:** line, so nothing ties the plan to the design it builds")
|
|
380
|
+
} else if (spec_path == "") {
|
|
381
|
+
# Checked before the read: getline on an empty filename is a fatal
|
|
382
|
+
# awk error, which would surface as the plan being unreadable.
|
|
383
|
+
finding("error", "the **Spec:** line names no path")
|
|
384
|
+
} else if (system("test -e " shq(spec_file)) != 0) {
|
|
385
|
+
finding("error", "**Spec:** names " spec_path ", which does not exist")
|
|
386
|
+
} else if (system("test -d " shq(spec_file)) == 0) {
|
|
387
|
+
# Asked before the read: BSD awk aborts on getline from a directory,
|
|
388
|
+
# which would surface as the plan being unreadable.
|
|
389
|
+
finding("error", "**Spec:** names " spec_path ", which is a directory, not a file")
|
|
390
|
+
} else if ((getline line < spec_file) < 0) {
|
|
391
|
+
finding("error", "**Spec:** names " spec_path ", which exists but cannot be read")
|
|
392
|
+
} else {
|
|
393
|
+
# The first line is already in hand from the existence probe above.
|
|
394
|
+
sfenced = 0; ndec = 0
|
|
395
|
+
do {
|
|
396
|
+
if (line ~ /^[ \t]*```/) { sfenced = 1 - sfenced; continue }
|
|
397
|
+
if (sfenced || line !~ /^### D[0-9]+\./) continue
|
|
398
|
+
match(line, /D[0-9]+/)
|
|
399
|
+
d = substr(line, RSTART, RLENGTH)
|
|
400
|
+
if (!(d in decision)) { decision[d] = 1; dec_order[++ndec] = d }
|
|
401
|
+
} while ((getline line < spec_file) > 0)
|
|
402
|
+
close(spec_file)
|
|
403
|
+
if (ndec == 0)
|
|
404
|
+
finding("error", "the spec " spec_path " has no \"### D<n>.\" decisions, so no task can say which one it builds")
|
|
405
|
+
}
|
|
406
|
+
for (i = 1; i <= ntasks; i++) {
|
|
407
|
+
id = order[i]
|
|
408
|
+
if (!(id in has_builds)) {
|
|
409
|
+
# An error, not a warning: `none, <why>` is how a task says it
|
|
410
|
+
# builds nothing, so a task without the line has left it unsaid.
|
|
411
|
+
finding("error", "task " id " has no Builds line; " BUILDS_HINT)
|
|
412
|
+
continue
|
|
413
|
+
}
|
|
414
|
+
n = split(builds[id], cited, " ")
|
|
415
|
+
for (j = 1; j <= n; j++) {
|
|
416
|
+
if (cited[j] == "") continue
|
|
417
|
+
built[cited[j]] = 1
|
|
418
|
+
if (ndec > 0 && !(cited[j] in decision))
|
|
419
|
+
finding("error", "task " id " Builds " cited[j] ", which the spec does not have")
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
if (ntasks > 0)
|
|
423
|
+
for (i = 1; i <= ndec; i++)
|
|
424
|
+
if (!(dec_order[i] in built))
|
|
425
|
+
finding("error", "spec decision " dec_order[i] " is built by no task")
|
|
426
|
+
}
|
|
427
|
+
|
|
326
428
|
for (p in owners) {
|
|
327
429
|
n = split(owners[p], who, " ")
|
|
328
430
|
if (n < 2) continue
|
|
@@ -389,8 +491,17 @@ END {
|
|
|
389
491
|
# FINDINGS (newline-separated sev\tmsg), TASKROWS (newline-separated), NERR,
|
|
390
492
|
# NWARN.
|
|
391
493
|
parse_plan() {
|
|
392
|
-
local plan="$1" raw
|
|
393
|
-
|
|
494
|
+
local plan="$1" check_spec="${2-0}" raw
|
|
495
|
+
# A relative Spec path names a file from the plan's repo root, the way plans
|
|
496
|
+
# write it (docs/specs/...), so validate means the same thing from any cwd.
|
|
497
|
+
# Outside a repo there is no root, and the plan's own directory stands in.
|
|
498
|
+
# CDPATH is cleared because a cd it steers prints where it went, which would
|
|
499
|
+
# land in plan_dir. The base reaches awk through the environment: a -v value
|
|
500
|
+
# has its backslash escapes processed, and a path may hold a backslash.
|
|
501
|
+
local plan_dir spec_base
|
|
502
|
+
plan_dir="$(CDPATH= cd -- "$(dirname -- "$plan")" && pwd)" || { err "could not read $plan"; exit 4; }
|
|
503
|
+
spec_base="$(git -C "$plan_dir" rev-parse --show-toplevel 2>/dev/null)" || spec_base="$plan_dir"
|
|
504
|
+
raw="$(SLUICE_SPEC_BASE="$spec_base" awk -v check_spec="$check_spec" "$PARSER" "$plan")" || { err "could not read $plan"; exit 4; }
|
|
394
505
|
|
|
395
506
|
local summary
|
|
396
507
|
summary="$(printf '%s\n' "$raw" | grep "^summary$SEP" | head -1)"
|
|
@@ -421,7 +532,7 @@ case "$SUB" in
|
|
|
421
532
|
shift
|
|
422
533
|
[ $# -eq 0 ] || { err "unknown argument: $1"; exit 4; }
|
|
423
534
|
|
|
424
|
-
parse_plan "$PLAN"
|
|
535
|
+
parse_plan "$PLAN" 1
|
|
425
536
|
|
|
426
537
|
head="$(basename "$PLAN"): $(plural "$NTASKS" task)"
|
|
427
538
|
[ "$FLIP" != "0" ] && head="$head, flip at task $FLIP"
|
package/skills/sluice/skill.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sluice",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Routes work by change shape into four channels (bypass, fast, main, deep) and applies only the rules each channel needs, so a one-line fix does not pay the cost of a multi-subsystem build. Carries nine rules as one-liners in the router and the full treatment in references read only on friction. Checks the finished plan with plan.sh validate rather than trusting it to memory, seeds the run state from it, keeps a deep run's task breakdown in .sluice/run.json so a statusline segment, one status command and a SessionStart hook can answer where the run is (the hook prints a live run at every session start, compaction included), lists every live deep run and routed fast or main session on the machine in one board.sh view (drawn once, watched, or as JSON), and closes each run with a ledger read out of the session transcript: elapsed, tools, tokens, and what each dispatched agent cost where the transcript recorded it. Two Stop hooks hold a handback: one refuses a tree that moved since its last recorded check, the other refuses a changed existing test not proven to fail on the session's starting code (or recorded with a reason). Claude Code only; stands down where the superpowers pipeline governs the repo.",
|
|
3
|
+
"version": "0.28.0",
|
|
4
|
+
"description": "Routes work by change shape into four channels (bypass, fast, main, deep) and applies only the rules each channel needs, so a one-line fix does not pay the cost of a multi-subsystem build. Carries nine rules as one-liners in the router and the full treatment in references read only on friction. Deep runs read the repo before designing, map the spec's intent to its decisions, and check spec against intent and plan against spec with a fresh reader, with plan.sh validate enforcing that every decision is covered. Checks the finished plan with plan.sh validate rather than trusting it to memory, seeds the run state from it, keeps a deep run's task breakdown in .sluice/run.json so a statusline segment, one status command and a SessionStart hook can answer where the run is (the hook prints a live run at every session start, compaction included), lists every live deep run and routed fast or main session on the machine in one board.sh view (drawn once, watched, or as JSON), and closes each run with a ledger read out of the session transcript: elapsed, tools, tokens, and what each dispatched agent cost where the transcript recorded it. Two Stop hooks hold a handback: one refuses a tree that moved since its last recorded check, the other refuses a changed existing test not proven to fail on the session's starting code (or recorded with a reason). Claude Code only; stands down where the superpowers pipeline governs the repo.",
|
|
5
5
|
"author": "iceinvein",
|
|
6
6
|
"type": "prompt",
|
|
7
7
|
"tools": [
|