@ericrisco/rsc 1.0.5 → 1.0.7
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/manifest.json +1 -1
- package/package.json +1 -1
- package/scripts/eval-lint.sh +52 -1
- package/scripts/install-apply.js +27 -1
- package/scripts/skill-rubric.md +1 -1
- package/skills/analyze/SKILL.md +22 -0
- package/skills/author-skill/references/eval-authoring.md +3 -3
- package/skills/building-agents/evals/cases.yaml +1 -1
- package/skills/clarify/SKILL.md +22 -0
- package/skills/constitution/SKILL.md +22 -0
- package/skills/course-storytelling/evals/cases.yaml +3 -3
- package/skills/plan/SKILL.md +22 -0
- package/skills/review/SKILL.md +22 -0
package/manifest.json
CHANGED
package/package.json
CHANGED
package/scripts/eval-lint.sh
CHANGED
|
@@ -7,6 +7,16 @@ set -euo pipefail
|
|
|
7
7
|
# >= 5 should_trigger entries
|
|
8
8
|
# >= 4 should_not_trigger entries
|
|
9
9
|
# >= 1 capability scenario
|
|
10
|
+
# every should_not_trigger route_to resolves (see below)
|
|
11
|
+
#
|
|
12
|
+
# route_to is the one that used to be decorative: the rubric listed "route_to names a
|
|
13
|
+
# real skill" as a deterministic gate and nothing checked it, so evals accumulated
|
|
14
|
+
# routes to skills that were never authored. Each value must now be one of:
|
|
15
|
+
# - a real catalog skill id (a directory under skills/ with a SKILL.md)
|
|
16
|
+
# - "none" — deliberately nothing to route to
|
|
17
|
+
# - "external:<name>" — a skill outside this catalog, on purpose. Some skills
|
|
18
|
+
# legitimately defer to tools that ship elsewhere; the prefix makes that a
|
|
19
|
+
# visible, greppable claim instead of a typo indistinguishable from drift.
|
|
10
20
|
#
|
|
11
21
|
# Uses python3 for real YAML parsing when available. If python3 is missing,
|
|
12
22
|
# falls back to a basic structural grep check and SKIPs the deep validation
|
|
@@ -36,7 +46,7 @@ warned_skip=0
|
|
|
36
46
|
validate_py() {
|
|
37
47
|
cy="$1"
|
|
38
48
|
CASES_YAML="$cy" MIN_TRIGGER="$MIN_TRIGGER" MIN_NOT_TRIGGER="$MIN_NOT_TRIGGER" \
|
|
39
|
-
MIN_CAPABILITY="$MIN_CAPABILITY" python3 - <<'PYEOF'
|
|
49
|
+
MIN_CAPABILITY="$MIN_CAPABILITY" VALID_IDS="$VALID_IDS" python3 - <<'PYEOF'
|
|
40
50
|
import os, sys
|
|
41
51
|
try:
|
|
42
52
|
import yaml
|
|
@@ -72,7 +82,39 @@ st = count("should_trigger")
|
|
|
72
82
|
sn = count("should_not_trigger")
|
|
73
83
|
cap = count("capability")
|
|
74
84
|
|
|
85
|
+
# --- route_to resolution -------------------------------------------------------
|
|
86
|
+
# Accepts a real catalog id, "none", or "external:<name>". A value may be a list,
|
|
87
|
+
# or a string holding several targets separated by comma / | / " or ".
|
|
88
|
+
valid = set(filter(None, os.environ.get("VALID_IDS", "").split(",")))
|
|
89
|
+
NOTHING = {"none", "n/a", "-", ""}
|
|
90
|
+
bad_routes = []
|
|
91
|
+
|
|
92
|
+
def targets(value):
|
|
93
|
+
items = value if isinstance(value, list) else [value]
|
|
94
|
+
out = []
|
|
95
|
+
for item in items:
|
|
96
|
+
for part in str(item).replace("|", ",").replace(" or ", ",").split(","):
|
|
97
|
+
out.append(part.strip().strip("`"))
|
|
98
|
+
return out
|
|
99
|
+
|
|
100
|
+
for case in (data.get("should_not_trigger") or []):
|
|
101
|
+
if not isinstance(case, dict) or case.get("route_to") is None:
|
|
102
|
+
continue
|
|
103
|
+
for t in targets(case["route_to"]):
|
|
104
|
+
low = t.lower()
|
|
105
|
+
if low in NOTHING:
|
|
106
|
+
continue
|
|
107
|
+
if low.startswith("external:"):
|
|
108
|
+
if not low[len("external:"):].strip():
|
|
109
|
+
bad_routes.append('"external:" with no name')
|
|
110
|
+
continue
|
|
111
|
+
if valid and t not in valid:
|
|
112
|
+
bad_routes.append(t)
|
|
113
|
+
|
|
75
114
|
reasons = []
|
|
115
|
+
if bad_routes:
|
|
116
|
+
uniq = sorted(set(bad_routes))
|
|
117
|
+
reasons.append("route_to does not resolve: %s (use a real skill id, \"none\", or \"external:<name>\")" % ", ".join(uniq))
|
|
76
118
|
if st < 0:
|
|
77
119
|
reasons.append("should_trigger is not a list")
|
|
78
120
|
elif st < mt:
|
|
@@ -112,8 +154,17 @@ validate_grep() {
|
|
|
112
154
|
|
|
113
155
|
echo "eval-lint: scanning $SKILLS_DIR"
|
|
114
156
|
echo "minimums: should_trigger>=$MIN_TRIGGER should_not_trigger>=$MIN_NOT_TRIGGER capability>=$MIN_CAPABILITY"
|
|
157
|
+
echo "route_to must resolve: a catalog skill id, \"none\", or \"external:<name>\""
|
|
115
158
|
echo
|
|
116
159
|
|
|
160
|
+
# The set of real skill ids, built once from disk — the same surface the router sees.
|
|
161
|
+
VALID_IDS=""
|
|
162
|
+
for sp in "$SKILLS_DIR"/*; do
|
|
163
|
+
[ -f "$sp/SKILL.md" ] || continue
|
|
164
|
+
VALID_IDS="$VALID_IDS,$(basename "$sp")"
|
|
165
|
+
done
|
|
166
|
+
VALID_IDS="${VALID_IDS#,}"
|
|
167
|
+
|
|
117
168
|
# Iterate skills deterministically; bash 3.2-safe (no mapfile).
|
|
118
169
|
for skill_path in "$SKILLS_DIR"/*; do
|
|
119
170
|
[ -d "$skill_path" ] || continue
|
package/scripts/install-apply.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { rmSync, existsSync, cpSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { rmSync, existsSync, cpSync, mkdirSync, readFileSync, writeFileSync, appendFileSync } from 'node:fs';
|
|
3
3
|
import { join, dirname } from 'node:path';
|
|
4
4
|
import { fileURLToPath } from 'node:url';
|
|
5
5
|
import { planInstall } from './install-plan.js';
|
|
@@ -112,9 +112,35 @@ export async function applyInstall({ skillIds, target, home, cwd = process.cwd()
|
|
|
112
112
|
writeState(paths.stateFile, state);
|
|
113
113
|
mkdirSync(dirname(versionFile(cwd)), { recursive: true });
|
|
114
114
|
writeFileSync(versionFile(cwd), CLI_VERSION + '\n');
|
|
115
|
+
ignoreLocalState(cwd);
|
|
115
116
|
return { ...state, backup };
|
|
116
117
|
}
|
|
117
118
|
|
|
119
|
+
// `.rsc/` holds local machine state — hook scripts, install markers, the sello's
|
|
120
|
+
// seals, the automation-gap log. None of it belongs in a user's repository, and the
|
|
121
|
+
// gap log in particular is prose about what happened in their project: a routine
|
|
122
|
+
// `git add -A` would publish it. Nothing used to keep that out, so add the entry.
|
|
123
|
+
//
|
|
124
|
+
// Additive and idempotent by construction: append one line to an existing
|
|
125
|
+
// .gitignore, never rewrite or reorder it, and never create the file in a directory
|
|
126
|
+
// that is not a git repository.
|
|
127
|
+
export function ignoreLocalState(cwd = process.cwd()) {
|
|
128
|
+
if (!existsSync(join(cwd, '.git'))) return null;
|
|
129
|
+
const gi = join(cwd, '.gitignore');
|
|
130
|
+
let text = '';
|
|
131
|
+
try { text = existsSync(gi) ? readFileSync(gi, 'utf8') : ''; } catch { return null; }
|
|
132
|
+
const already = text.split('\n').some((l) => {
|
|
133
|
+
const s = l.trim().replace(/\/$/, '');
|
|
134
|
+
return s === '.rsc' || s === '/.rsc';
|
|
135
|
+
});
|
|
136
|
+
if (already) return null;
|
|
137
|
+
const prefix = text === '' ? '' : (text.endsWith('\n') ? '' : '\n');
|
|
138
|
+
try {
|
|
139
|
+
appendFileSync(gi, `${prefix}\n# rsc local state (hooks, seals, logs) — machine-local, never committed\n.rsc/\n`);
|
|
140
|
+
return gi;
|
|
141
|
+
} catch { return null; }
|
|
142
|
+
}
|
|
143
|
+
|
|
118
144
|
export function listInstalled({ target, home, cwd = process.cwd() }) {
|
|
119
145
|
const paths = targetPaths(target, home, cwd);
|
|
120
146
|
return Object.keys(readState(paths.stateFile).skills);
|
package/scripts/skill-rubric.md
CHANGED
|
@@ -16,7 +16,7 @@ dishonest 9.
|
|
|
16
16
|
| 3 | **Body craft & progressive disclosure** | 0.15 | **The smallest body that routes correctly** — ≤400 lines is a ceiling, not a target, and there is no minimum: a skill that does its job in 60 lines scores higher than the same skill padded to 200. Every `references/` file is pointed to inline from this body (an unlinked reference is never loaded, so it is dead weight). rsc voice, every fence language-tagged, a checklist/decision table only where the flow branches, an anti-patterns table present. |
|
|
17
17
|
| 4 | **Correctness, grounding & freshness** | **0.25** | Every load-bearing claim is accurate and **current (2025–2026)**: real library/API versions, no hallucinated flags/endpoints. The spec cites **authoritative sources with dates**; nothing rests on stale or invented facts. This is the heaviest dimension by design. |
|
|
18
18
|
| 5 | **Actionability** | 0.15 | Concrete and runnable: real numbers, paths, commands, decision rules — not adjectives. A practitioner could act from it without leaving the skill. |
|
|
19
|
-
| 6 | **Evals quality** | 0.10 | ≥5 `should_trigger` (incl. non-obvious), ≥4 `should_not_trigger` each with a `route_to` that
|
|
19
|
+
| 6 | **Evals quality** | 0.10 | ≥5 `should_trigger` (incl. non-obvious), ≥4 `should_not_trigger` each with a `route_to` that resolves — a **real** catalog id, `none`, or `external:<name>` (enforced by `eval-lint`), ≥1 `capability` with a meaningful `must_include` rubric. The cases are genuine, not filler. |
|
|
20
20
|
| 7 | **Originality & safety** | 0.10 | rsc voice, not a clone of any external catalog (no borrowed urgency blocks / rationalization tables / `*-reviewer-prompt.md` conventions / verbatim flowcharts). `verify.sh` present iff there is a checkable artifact. No destructive or unsafe advice presented without guardrails. |
|
|
21
21
|
|
|
22
22
|
**Weighted score** = Σ(subscore × weight), rounded to 1 decimal. **Ship gate: ≥ 8.5.**
|
package/skills/analyze/SKILL.md
CHANGED
|
@@ -101,6 +101,28 @@ Render it at the dial's verbosity. Do not log a decision to `decisions.md` — a
|
|
|
101
101
|
| Siding with the plan when it contradicts the constitution | The constitution wins by definition — flag CRITICAL. If the principle itself is wrong, that is a `constitution` change the user makes, not a quiet override here. |
|
|
102
102
|
| Guessing what a vague requirement meant | Guessing defeats the gate. Mark AMBIGUOUS and route to `clarify`; do not encode your guess. |
|
|
103
103
|
|
|
104
|
+
## Result envelope
|
|
105
|
+
|
|
106
|
+
End with the parseable block every SDD phase shares, so the dispatcher can chain without
|
|
107
|
+
interpreting prose (contract: `../sdd/SKILL.md`):
|
|
108
|
+
|
|
109
|
+
```json result-envelope
|
|
110
|
+
{
|
|
111
|
+
"status": "complete|blocked|failed",
|
|
112
|
+
"executive_summary": "Cross-read of spec/plan/tasks against the constitution; findings ranked.",
|
|
113
|
+
"artifact": "02-DOCS/wiki/sdd/analysis/<slug>.md",
|
|
114
|
+
"next_recommended": "implement",
|
|
115
|
+
"risk": "low|medium|high",
|
|
116
|
+
"skill_resolution": {
|
|
117
|
+
"used": ["analyze"],
|
|
118
|
+
"missing": [],
|
|
119
|
+
"fallback": [],
|
|
120
|
+
"compact_rules": ["Read adversarially across artifacts, not inside one.", "A finding without a location is an opinion."]
|
|
121
|
+
},
|
|
122
|
+
"evidence": ["report path exists", "blockers listed with artifact + location", "constitution conflicts named"]
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
104
126
|
## Next in the chain
|
|
105
127
|
|
|
106
128
|
On `GATE: PASS` (or once the user consciously accepts the remaining MEDIUM/LOW findings), proceed to **`implement`** — execute the tasks with TDD discipline, delegating concrete test tooling to the relevant stack skill (`fastapi`, `nextjs`, `go`, `flutter`, `postgresdb`). On `GATE: BLOCKED`, route each CRITICAL/HIGH finding to its owning phase (`clarify`, `plan`, `tasks`, or `constitution`), let the user resolve, then re-run `analyze`. The gate only opens once.
|
|
@@ -17,7 +17,7 @@ Everything lives in `evals/cases.yaml` (the cases) and `evals/README.md` (how to
|
|
|
17
17
|
|
|
18
18
|
`scripts/eval-lint.sh` parses every `cases.yaml` and fails the build only on the **structural minimums**: that `evals/cases.yaml` exists, that `should_trigger`, `should_not_trigger`, and `capability` are present as lists, and that their item counts meet **≥ 5 / ≥ 4 / ≥ 1**. (Without python3+PyYAML it degrades to a presence-only key check.) Run it before shipping to catch a missing or undersized section.
|
|
19
19
|
|
|
20
|
-
It
|
|
20
|
+
It also resolves every `route_to`: each value must be a real catalog skill id, `none`, or `external:<name>` for a skill that deliberately lives outside this catalog — a stale route now fails the build. What it still does **not** read: whether each `should_not_trigger` actually carries a `route_to`, whether your `should_trigger` set includes a genuinely non-obvious or non-English phrasing, and whether each `capability` scenario has a real `must_include` rubric of gradeable points. Those are **author and review responsibilities**: verify them by hand (and in the self-audit / code-review pass) before shipping. A green eval-lint means the shape is right, not that the cases are good.
|
|
21
21
|
|
|
22
22
|
## cases.yaml structure
|
|
23
23
|
|
|
@@ -33,7 +33,7 @@ should_trigger:
|
|
|
33
33
|
|
|
34
34
|
should_not_trigger:
|
|
35
35
|
- prompt: "A near-miss that looks close but belongs elsewhere."
|
|
36
|
-
route_to: "sibling-id" # a
|
|
36
|
+
route_to: "sibling-id" # a real catalog id, "none", or "external:<name>" — checked by eval-lint
|
|
37
37
|
why: "Why it is NOT this skill and why the sibling owns it."
|
|
38
38
|
# … ≥ 4 total
|
|
39
39
|
|
|
@@ -53,7 +53,7 @@ capability:
|
|
|
53
53
|
|
|
54
54
|
## Writing good `should_not_trigger` cases
|
|
55
55
|
|
|
56
|
-
These are where descriptions get sharpened. Each near-miss should be genuinely tempting — adjacent in topic but owned by a sibling. The `route_to` must name a skill that **exists in this repo
|
|
56
|
+
These are where descriptions get sharpened. Each near-miss should be genuinely tempting — adjacent in topic but owned by a sibling. The `route_to` must name a skill that **exists in this repo** — `eval-lint` fails the build otherwise. If the right owner genuinely ships outside this catalog, say so with `external:<name>` rather than inventing an id: the prefix makes the claim visible instead of indistinguishable from drift. Pick the siblings most likely to be confused with this one and write a case that disambiguates each.
|
|
57
57
|
|
|
58
58
|
For `author-skill`, the natural confusables are `specify`/`plan` (building a feature, not a skill), `building-agents` (agent loops), `harness` (generic docs/wiki), and `init` (bootstrapping). Route each near-miss to whichever it truly belongs to.
|
|
59
59
|
|
|
@@ -24,7 +24,7 @@ should_not_trigger:
|
|
|
24
24
|
route_to: "none"
|
|
25
25
|
why: "One-shot throwaway prompt with no tools/eval/production path — the skill says just call the SDK directly."
|
|
26
26
|
- prompt: "Tune Anthropic prompt caching and extended thinking in our anthropic-only client.py to cut latency on a file that only imports the anthropic SDK."
|
|
27
|
-
route_to: "claude-api"
|
|
27
|
+
route_to: "external:claude-api"
|
|
28
28
|
why: "Single-vendor Anthropic-SDK internals tuning in a file that only imports anthropic defers to the dedicated Anthropic skill; this skill stays multi-provider."
|
|
29
29
|
- prompt: "Write the pgvector schema and an HNSW-indexed nearest-neighbour SQL query, plus tuning advice — just the database side, no LLM calls."
|
|
30
30
|
route_to: "postgresdb"
|
package/skills/clarify/SKILL.md
CHANGED
|
@@ -113,6 +113,28 @@ After baking back, the spec line becomes a bounded, testable behavior with accep
|
|
|
113
113
|
|
|
114
114
|
The gate is passed when the spec, constitution and profile were all read (settled questions cited, not re-asked); all ten taxonomy categories were considered; only the build-changing gaps were put to the user, as dial-sized decisions with recommendations; every answer is baked into the spec body with observable acceptance criteria, logged under `## Clarifications` and bounded under `## Out of scope`; and the final re-read opened no new gap.
|
|
115
115
|
|
|
116
|
+
## Result envelope
|
|
117
|
+
|
|
118
|
+
End with the parseable block every SDD phase shares, so the dispatcher can chain without
|
|
119
|
+
interpreting prose (contract: `../sdd/SKILL.md`):
|
|
120
|
+
|
|
121
|
+
```json result-envelope
|
|
122
|
+
{
|
|
123
|
+
"status": "complete|blocked|failed",
|
|
124
|
+
"executive_summary": "Open points resolved; the spec is de-risked and ready to plan against.",
|
|
125
|
+
"artifact": "02-DOCS/wiki/sdd/specs/<slug>.md",
|
|
126
|
+
"next_recommended": "plan",
|
|
127
|
+
"risk": "low|medium|high",
|
|
128
|
+
"skill_resolution": {
|
|
129
|
+
"used": ["clarify"],
|
|
130
|
+
"missing": [],
|
|
131
|
+
"fallback": [],
|
|
132
|
+
"compact_rules": ["Ask only what changes the spec.", "An unanswered question is recorded, never invented."]
|
|
133
|
+
},
|
|
134
|
+
"evidence": ["answers folded back into the spec", "remaining open points listed with their owner"]
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
116
138
|
## Next in the chain
|
|
117
139
|
|
|
118
140
|
Hand off to **`plan`** — turn the now-sharp spec into a technical implementation plan (architecture, interfaces, data flow, testing strategy, risks), deferring stack specifics to the relevant stack skill. The chain continues: clarify → **plan** → tasks → analyze → implement → verify → review → ship. `debug` is callable any time if what you are "clarifying" turns out to be a runtime fault, not a spec gap.
|
|
@@ -132,6 +132,28 @@ This skill's `02-DOCS` record is the constitution at `02-DOCS/wiki/sdd/constitut
|
|
|
132
132
|
|
|
133
133
|
Every later rsc-sdd phase reads this file before it works. The harness maintains and improves the article over the life of the project; this skill is the place that ratifies and amends it.
|
|
134
134
|
|
|
135
|
+
## Result envelope
|
|
136
|
+
|
|
137
|
+
End with the parseable block every SDD phase shares, so the dispatcher can chain without
|
|
138
|
+
interpreting prose (contract: `../sdd/SKILL.md`):
|
|
139
|
+
|
|
140
|
+
```json result-envelope
|
|
141
|
+
{
|
|
142
|
+
"status": "complete|blocked|failed",
|
|
143
|
+
"executive_summary": "Constitution written with N numbered, testable rules the later phases inherit.",
|
|
144
|
+
"artifact": "02-DOCS/wiki/sdd/constitution.md",
|
|
145
|
+
"next_recommended": "specify",
|
|
146
|
+
"risk": "low|medium|high",
|
|
147
|
+
"skill_resolution": {
|
|
148
|
+
"used": ["constitution"],
|
|
149
|
+
"missing": [],
|
|
150
|
+
"fallback": [],
|
|
151
|
+
"compact_rules": ["Principles are inherited constraints, not choices to re-make.", "Every rule is testable or it is a preference."]
|
|
152
|
+
},
|
|
153
|
+
"evidence": ["constitution path exists", "rules numbered and testable", "decisions log appended"]
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
135
157
|
## Next in the chain
|
|
136
158
|
|
|
137
159
|
The constitution is the guardrail; now describe what to build. Hand off to **`../specify/SKILL.md`** — turn a fuzzy intent into a spec (what & why, no implementation), grounded in these principles. The full chain: **constitution → specify → clarify → plan → tasks → analyze → implement → verify → review → ship** (with `debug`, `worktrees`, `parallel` callable on demand). The dispatcher is `../sdd/SKILL.md`.
|
|
@@ -22,14 +22,14 @@ should_not_trigger:
|
|
|
22
22
|
route_to: "marketing"
|
|
23
23
|
why: "Sales/landing copy for the course is marketing's domain. The skill teaches; it never bolts a pitch on, and explicitly defers selling words to marketing."
|
|
24
24
|
- prompt: "Audit module 14 of my course for gaps, redundancy, anachronisms, and outdated stack references, and give me a written report."
|
|
25
|
-
route_to: "review-content"
|
|
25
|
+
route_to: "external:review-content"
|
|
26
26
|
why: "Diagnostic content-audit pass with a written report. The skill says run review-content first and bring findings here; it rebuilds, it does not audit."
|
|
27
27
|
- prompt: "Design a color system, typography scale, and diagram style for my course slides."
|
|
28
28
|
route_to: "design"
|
|
29
29
|
why: "Pure visual system / pixels. The skill defers the visual layer to design; it owns narrative, not aesthetics."
|
|
30
30
|
- prompt: "Fact-check whether the historical claims in my lesson about the origins of TCP are actually accurate, with sources."
|
|
31
|
-
route_to: "
|
|
32
|
-
why: "Pure fact-checking/research of subject matter, not reframing teaching. The skill forbids inventing proof and defers verification to deep-research."
|
|
31
|
+
route_to: "research-ops"
|
|
32
|
+
why: "Pure fact-checking/research of subject matter, not reframing teaching. The skill forbids inventing proof and defers verification to a research pass — `research-ops` in this catalog, a deep-research tool where the environment provides one."
|
|
33
33
|
|
|
34
34
|
capability:
|
|
35
35
|
- scenario: "A learner profile already exists and is complete in 02-DOCS/wiki/teaching/. The user gives a flat, definition-only lesson on 'idempotency' for a mid-level backend course and asks to make it land."
|
package/skills/plan/SKILL.md
CHANGED
|
@@ -141,6 +141,28 @@ regardless. (`implement` re-checks this as a hard gate before its first commit.)
|
|
|
141
141
|
- Concrete framework/ORM/test-runner mechanics → the stack skill (`../fastapi/SKILL.md`,
|
|
142
142
|
`../nextjs/SKILL.md`, `../go/SKILL.md`, `../flutter/SKILL.md`, `../postgresdb/SKILL.md`).
|
|
143
143
|
|
|
144
|
+
## Result envelope
|
|
145
|
+
|
|
146
|
+
End with the parseable block every SDD phase shares, so the dispatcher can chain without
|
|
147
|
+
interpreting prose (contract: `../sdd/SKILL.md`):
|
|
148
|
+
|
|
149
|
+
```json result-envelope
|
|
150
|
+
{
|
|
151
|
+
"status": "complete|blocked|failed",
|
|
152
|
+
"executive_summary": "Technical plan derived from the clarified spec, with the isolation decision made.",
|
|
153
|
+
"artifact": "02-DOCS/wiki/sdd/plans/<slug>.md",
|
|
154
|
+
"next_recommended": "tasks",
|
|
155
|
+
"risk": "low|medium|high",
|
|
156
|
+
"skill_resolution": {
|
|
157
|
+
"used": ["plan"],
|
|
158
|
+
"missing": [],
|
|
159
|
+
"fallback": [],
|
|
160
|
+
"compact_rules": ["The plan answers HOW; the spec owns WHAT.", "Name the isolation choice before the build starts."]
|
|
161
|
+
},
|
|
162
|
+
"evidence": ["plan path exists", "each spec acceptance criterion has an approach", "risks and rollback stated"]
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
144
166
|
## Next in the chain
|
|
145
167
|
|
|
146
168
|
Plan written, indexed, decisions logged → propose isolation (above), then hand off to
|
package/skills/review/SKILL.md
CHANGED
|
@@ -237,6 +237,28 @@ Review is mostly a conversation, but two artifacts persist into the harness wiki
|
|
|
237
237
|
|
|
238
238
|
Index both in `02-DOCS/wiki/index.md` (the Knowledge map; root `CLAUDE.md` keeps only a short pointer) under the `sdd/` topic — the harness owns that map; this skill just keeps its rows honest.
|
|
239
239
|
|
|
240
|
+
## Result envelope
|
|
241
|
+
|
|
242
|
+
End with the parseable block every SDD phase shares, so the dispatcher can chain without
|
|
243
|
+
interpreting prose (contract: `../sdd/SKILL.md`):
|
|
244
|
+
|
|
245
|
+
```json result-envelope
|
|
246
|
+
{
|
|
247
|
+
"status": "complete|blocked|failed",
|
|
248
|
+
"executive_summary": "Adversarial review against spec/plan/constitution; verdict and blocking findings.",
|
|
249
|
+
"artifact": "02-DOCS/wiki/sdd/reviews/<slug>.md",
|
|
250
|
+
"next_recommended": "ship",
|
|
251
|
+
"risk": "low|medium|high",
|
|
252
|
+
"skill_resolution": {
|
|
253
|
+
"used": ["review"],
|
|
254
|
+
"missing": [],
|
|
255
|
+
"fallback": [],
|
|
256
|
+
"compact_rules": ["Rank or it is noise: blocker / should-fix / nit.", "A finding without a repro is a question, not a defect."]
|
|
257
|
+
},
|
|
258
|
+
"evidence": ["verdict stated (APPROVE | APPROVE WITH NITS | CHANGES REQUESTED)", "each blocker carries location + repro + fix"]
|
|
259
|
+
}
|
|
260
|
+
```
|
|
261
|
+
|
|
240
262
|
## Next in the chain
|
|
241
263
|
|
|
242
264
|
When the diff carries an **APPROVE** / **APPROVE WITH NITS** verdict and every blocker is resolved, hand off to **ship** — close the branch via PR / merge / cleanup, with **git authorship as Eric, never Claude**. If the review came back **CHANGES REQUESTED**, the loop goes back to **implement** (fix), then **verify** (re-prove green), then back here for re-review. Don't ship a diff that hasn't earned its verdict.
|