shapeup-sdlc 1.6.2 → 1.7.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.
- package/.claude-plugin/plugin.json +1 -1
- package/AGENTS.md +36 -103
- package/README.md +60 -67
- package/SECURITY.md +31 -16
- package/bin/init.mjs +24 -69
- package/commands/build.md +19 -0
- package/commands/eval.md +5 -4
- package/commands/scopes.md +5 -4
- package/commands/shape.md +1 -1
- package/commands/ship.md +37 -4
- package/hooks/anti-rationalization.mjs +7 -13
- package/hooks/compact-snapshot.mjs +5 -5
- package/hooks/gate-deadline.mjs +12 -16
- package/hooks/gate-intake.mjs +13 -14
- package/hooks/gate-l2.mjs +3 -3
- package/hooks/gate-zerowork.mjs +97 -16
- package/hooks/lib/decision.mjs +21 -13
- package/hooks/safety-spine.mjs +1 -1
- package/hooks/sandbox-guard.mjs +83 -47
- package/hooks/session-rehydrate.mjs +8 -9
- package/hooks/slop-cleaner.mjs +1 -1
- package/oracles/_shared.mjs +1 -1
- package/oracles/http-oracle.mjs +1 -1
- package/oracles/index.mjs +1 -1
- package/oracles/process-oracle.mjs +1 -1
- package/oracles/snapshot-oracle.mjs +1 -1
- package/oracles/test-oracle.mjs +1 -1
- package/package.json +3 -7
- package/skills/ba-pitch-analyzer/SKILL.md +20 -15
- package/skills/ba-pitch-analyzer/references/doc-schemas.md +1 -1
- package/skills/ba-pitch-analyzer/references/task-generation.md +6 -6
- package/skills/ba-pitch-analyzer/references/test-surface.md +1 -1
- package/skills/ba-pitch-analyzer/scripts/board-derive.mjs +5 -5
- package/skills/ba-pitch-analyzer/scripts/spec-lint.mjs +2 -2
- package/skills/coach/SKILL.md +3 -3
- package/skills/orient/SKILL.md +2 -1
- package/skills/qa-edge-hunter/SKILL.md +9 -39
- package/skills/scope-architect/SKILL.md +17 -12
- package/skills/scope-hammer/SKILL.md +5 -5
- package/skills/shapeup/SKILL.md +3 -3
- package/skills/shapeup/resources/context-compaction.md +4 -3
- package/skills/solution-architect/SKILL.md +18 -11
- package/skills/spec-evaluator/SKILL.md +12 -5
- package/skills/spec-evaluator/references/dimensions/_registry.md +2 -2
- package/skills/spec-evaluator/references/dimensions/completeness.md +1 -1
- package/skills/spec-evaluator/references/dimensions/integration.md +98 -67
- package/skills/spec-evaluator/references/dimensions/spec-conformance.md +4 -4
- package/skills/spec-evaluator/references/dimensions/test-surface-conformance.md +1 -1
- package/skills/spec-evaluator/references/probing.md +42 -23
- package/skills/spec-evaluator/references/report-schema.md +2 -2
- package/skills/spec-evaluator/scripts/verdict-ledger.mjs +1 -1
- package/skills/task-executor/SKILL.md +25 -12
- package/skills/tech-lead/SKILL.md +115 -438
- package/skills/tech-lead/references/delegation.md +38 -31
- package/skills/tech-lead/references/gates.md +75 -33
- package/skills/tech-lead/references/hard-rules.md +34 -0
- package/skills/tech-lead/references/invocation.md +2 -2
- package/skills/tech-lead/references/ledger-schema.md +17 -18
- package/skills/tech-lead/references/round-protocol.md +77 -27
- package/skills/tech-lead/references/state-model.md +1 -1
- package/skills/tech-lead/schemas/domain.schema.json +320 -148
- package/skills/tech-lead/schemas/gate-answers.schema.json +2 -2
- package/skills/tech-lead/schemas/work-result.schema.json +55 -17
- package/skills/tech-lead/scripts/aegis-digest.mjs +1 -1
- package/skills/tech-lead/scripts/budget-check.mjs +7 -13
- package/skills/tech-lead/scripts/compile-order.mjs +69 -22
- package/skills/tech-lead/scripts/fit-check.mjs +10 -10
- package/skills/tech-lead/scripts/gate-answers.mjs +11 -12
- package/skills/tech-lead/scripts/hill-derive.mjs +133 -0
- package/skills/tech-lead/scripts/ingest-result.mjs +7 -19
- package/skills/tech-lead/scripts/init-run.mjs +60 -18
- package/skills/tech-lead/scripts/lib/argv.mjs +1 -1
- package/skills/tech-lead/scripts/lib/contract-md.mjs +10 -10
- package/skills/tech-lead/scripts/lib/is-main.mjs +11 -12
- package/skills/tech-lead/scripts/lib/paths.mjs +15 -13
- package/skills/tech-lead/scripts/resume-state.mjs +387 -0
- package/skills/tech-lead/scripts/run-snapshot.mjs +1 -6
- package/skills/tech-lead/scripts/run-workflow.mjs +381 -0
- package/skills/tech-lead/scripts/ship-report.mjs +33 -2
- package/skills/tech-lead/scripts/stats.mjs +9 -10
- package/skills/tech-lead/scripts/t0-verify.mjs +4 -4
- package/skills/tech-lead/scripts/trace-lint.mjs +2 -2
- package/skills/tech-lead/workflows/shapeup-run.js +911 -0
- package/skills/translator/SKILL.md +2 -2
- package/skills/advisor-protocol/SKILL.md +0 -171
|
@@ -24,16 +24,16 @@ Invoked as `--order <path>`. Fields you may rely on (absent = unknown; surface i
|
|
|
24
24
|
|
|
25
25
|
| Field | What it is |
|
|
26
26
|
|---|---|
|
|
27
|
-
| `operation` | `analyze` (pitch → full spec tree + board) · `
|
|
27
|
+
| `operation` | `analyze` (pitch → full spec tree + board) · `reconcile` (fold discovered-ledger items into the board + UC invariants) · `retrofit-surface` (append `## Test Surface` to a pre-surface spec) · `coverage` (extract atomic requirement clauses → the SHARED `requirements.md` registry) |
|
|
28
28
|
| `payload.pitch` | The pitch/PRD path (analyze) |
|
|
29
29
|
| `payload.requirements` | (coverage) the REQ source to extract atomic clauses from — pitch / a customer-requirements doc / the use-case bodies. Absent → default to the pitch and record the choice in `assumptions[]` |
|
|
30
|
-
| `payload.lens` | `lite` \| `standard` \| `cross-context`. Absent → judge it: LITE for ≤2-week appetite, no third-party, ≤3 user-facing actions; STANDARD for multi-team, third-party, or bigger appetite; genuinely unclear → one binary question
|
|
30
|
+
| `payload.lens` | `lite` \| `standard` \| `cross-context`. Absent → judge it: LITE for ≤2-week appetite, no third-party, ≤3 user-facing actions; STANDARD for multi-team, third-party, or bigger appetite; genuinely unclear → one binary question, or `status: "escalated"` with the question in `deviations[]` |
|
|
31
31
|
| `payload.orient_dir` | The Scout's artifacts — `code-surface.md` IS your codebase map (do not re-scan), `discovered-seed.md` seeds task gen, `spike-*.md` feeds feasibility |
|
|
32
32
|
| `payload.spec_folder` / `payload.feature` | Where the committed tree lives / the slug |
|
|
33
33
|
| `payload.discovered_ledger` | (reconcile) the ledger whose raw `[+]`/`~` lines you fold in |
|
|
34
34
|
| `payload.kb_rules_path` | Team guidelines (read if present) — steering, never spec |
|
|
35
|
-
| `substrate.allowed / append_only / frozen` | Your write contract for THIS operation. The old frozen-zone prose is now data the sandbox hook enforces: respect it, and when an operation genuinely needs a file outside it, ESCALATE — never widen |
|
|
36
|
-
| `interaction.pause_gates` | Caller policy. `true` (standalone default): pause at the phase checkpoints below, max 2 questions each. `false`: run straight through, surfacing questions as `assumptions[]
|
|
35
|
+
| `substrate.allowed / append_only / frozen` | Your write contract for THIS operation. The old frozen-zone prose is now data the sandbox hook enforces (reading the order's envelope): respect it, and when an operation genuinely needs a file outside it, ESCALATE — never widen |
|
|
36
|
+
| `interaction.pause_gates` | Caller policy. `true` (standalone default): pause at the phase checkpoints below, max 2 questions each. `false`: run straight through, surfacing questions as `assumptions[]` (or `deviations[]` when they block) instead |
|
|
37
37
|
|
|
38
38
|
---
|
|
39
39
|
|
|
@@ -94,15 +94,13 @@ second path to green.
|
|
|
94
94
|
|
|
95
95
|
---
|
|
96
96
|
|
|
97
|
-
## The other
|
|
97
|
+
## The other three operations — same craft, different payload + whitelist
|
|
98
98
|
|
|
99
99
|
| Operation | Essence | Never |
|
|
100
100
|
|---|---|---|
|
|
101
|
-
| `
|
|
102
|
-
| `reconcile` | Verify `ledger.feature == payload.feature` (mismatch → STOP). Map each `[+]` Keep item → its owning UC; new task continues numbering (never renumber); `~`/Cut → synthesis "Hammered Out" row, no file. A Keep item asserting a new invariant → APPEND `[INV-NN]` + TS-INV row to that UC (append-only sections in your substrate). A new actor/action with no UC → `escalates[]` (spec-ambiguity): spawning a UC mid-cycle is silent re-shaping, the PO decides. Finish with board-derive (appetite overflow → report) + spec-lint | re-run phases 1–5; edit UC Steps; resolve the appetite HAMMER yourself |
|
|
101
|
+
| `reconcile` | Verify `ledger.feature == payload.feature` (mismatch → STOP). Map each `[+]` Keep item → its owning UC; new task continues numbering (never renumber); `~`/Cut → synthesis "Hammered Out" row, no file. A Keep item asserting a new invariant → APPEND `[INV-NN]` + TS-INV row to that UC (append-only sections in your substrate). A new actor/action with no UC → `status: "escalated"` + a `deviations[]` spec-ambiguity entry: spawning a UC mid-cycle is silent re-shaping, the PO decides. Finish with board-derive (appetite overflow → report) + spec-lint | re-run phases 1–5; edit UC Steps; resolve the appetite HAMMER yourself |
|
|
103
102
|
| `retrofit-surface` | Append `## Test Surface` (derived rows only, after Error Cases) to each UC of a pre-surface spec; an all-sources-empty UC gets the explicit empty-sources line | touch anything else — append-only substrate |
|
|
104
|
-
| `coverage` | Extract **atomic** customer requirement clauses from `payload.requirements` (default: the pitch) and write the SHARED `shapeup/<slug>/requirements.md` registry: one `\| REQ-id \| clause (verbatim) \| source \| status \| note \|` row per clause. Split compound sentences into one testable clause each —
|
|
105
|
-
|
|
103
|
+
| `coverage` | Extract **atomic** customer requirement clauses from `payload.requirements` (default: the pitch) and write the SHARED `shapeup/<slug>/requirements.md` registry: one `\| REQ-id \| clause (verbatim) \| source \| status \| note \|` row per clause. Split compound sentences into one testable clause each — a clause lost *inside* a bigger sentence is a requirement nothing can be traced to. **Assign REQ-ids ONCE and freeze them** (they behave like scope_id, never TASK-NNN — every `covers:` link rots otherwise): re-running, append new clauses with fresh ids, mark a removed clause `CUT (PO-approved)`, never renumber or delete. Status starts `covered` (a live requirement); only the PO sets `CUT`. The REQ source itself is frozen — the registry is a separate derived file | edit the REQ source; renumber existing REQ-ids; delete a dropped clause instead of marking it CUT; invent a requirement not in the source |
|
|
106
104
|
---
|
|
107
105
|
|
|
108
106
|
## Anti-rationalization table
|
|
@@ -115,12 +113,19 @@ second path to green.
|
|
|
115
113
|
| "My output looks complete, score it 92" | You don't grade yourself. spec-lint reports facts; the judge judges. |
|
|
116
114
|
| "The appetite overflow is small, drop a nice-to-have myself" | Overflow is a HAMMER gate for the caller. You report the fact and the candidate cuts. |
|
|
117
115
|
| "Re-scanning the codebase is safer than trusting orient" | code-surface.md IS the map. Re-scanning burns tokens and forks the truth. |
|
|
118
|
-
| "unlocks is quick to fill in by hand" | Hand-authored unlocks
|
|
116
|
+
| "unlocks is quick to fill in by hand" | Hand-authored unlocks drift asymmetric — observed, repeatedly. board-derive computes it. |
|
|
119
117
|
|
|
120
118
|
---
|
|
121
119
|
|
|
122
120
|
## Output contract — the WorkResult
|
|
123
121
|
|
|
122
|
+
**Escalation rule.** If you return `status: "escalated"`, the **first** entry in `deviations[]`
|
|
123
|
+
must be the blocker: one specific, answerable question plus the context needed to answer it.
|
|
124
|
+
Nothing else in the envelope carries it — there is no `escalates[]` field — so a vague entry, or
|
|
125
|
+
the question buried under other notes, reaches the human as "something went wrong" and costs a
|
|
126
|
+
round. Write it so someone without your context can answer it in one reply.
|
|
127
|
+
|
|
128
|
+
|
|
124
129
|
Domain artifacts land inside your substrate (the committed spec tree + the LOCAL board). Then
|
|
125
130
|
write `.shapeup/<slug>/results/<order-suffix>.json`:
|
|
126
131
|
|
|
@@ -129,9 +134,8 @@ write `.shapeup/<slug>/results/<order-suffix>.json`:
|
|
|
129
134
|
"schema_version": 1, "order_id": "<copied>", "worker": "ba-pitch-analyzer",
|
|
130
135
|
"status": "done | partial | escalated",
|
|
131
136
|
"artifacts": ["shapeup/<slug>/spec/domain-model.md", "…"],
|
|
132
|
-
"escalates": [ { "kind": "spec-ambiguity", "question": "New actor 'auditor' has no UC — add UC-07 or cut?" } ],
|
|
133
137
|
"assumptions": ["lens=standard — third-party PSP present"],
|
|
134
|
-
"deviations": [],
|
|
138
|
+
"deviations": [ "ESCALATE spec-ambiguity — New actor 'auditor' has no UC — add UC-07 or cut?" ],
|
|
135
139
|
"discoveries": [ { "marker": "+", "line": "appetite overflow 12h — candidate cuts: TASK-014, TASK-017" } ]
|
|
136
140
|
}
|
|
137
141
|
```
|
|
@@ -168,8 +172,9 @@ status flips for built work (ingest's job), scope contracts (scope-architect's),
|
|
|
168
172
|
```
|
|
169
173
|
|
|
170
174
|
Standalone keeps exactly two flags: the pitch input and `--lens`. Every retired flag is now
|
|
171
|
-
caller context: `--tasks-only` → a
|
|
172
|
-
order, `--
|
|
173
|
-
|
|
175
|
+
caller context: `--tasks-only`/`--from-discovered` → a reconcile order, `--surface-only` → a
|
|
176
|
+
retrofit-surface order, `--coverage` → a coverage order, `--remap`/`--split` → a
|
|
177
|
+
scope-architect `map-scopes` order,
|
|
178
|
+
`--status` → read `spec-lint.mjs`/`board-derive.mjs` output (zero LLM tokens),
|
|
174
179
|
`--auto`/`--skip-gate*` → `interaction.pause_gates`, `--upgrade` → an analyze order with the
|
|
175
180
|
standard lens over an existing lite tree (reconciliation pass: extend, never overwrite Steps).
|
|
@@ -152,7 +152,7 @@ status: draft | ready
|
|
|
152
152
|
> tasks carry `use_case_refs` (LOCAL, per-machine board); reverse lookup is always computed
|
|
153
153
|
> live (synthesis S-01, audit coverage) — never stored on the committed UC. Rule: **never
|
|
154
154
|
> declare a bidirectional field across the committed/local boundary** — task IDs renumber
|
|
155
|
-
> per machine (
|
|
155
|
+
> per machine (the board is regenerated locally), so a stored back-link is wrong on every machine
|
|
156
156
|
> but one. Tolerate (ignore) the field on pre-v3.3 specs; do not emit or update it.
|
|
157
157
|
|
|
158
158
|
Required sections: Summary (1 sentence), Preconditions, Input (TS interface), Steps
|
|
@@ -361,12 +361,12 @@ Slug rules:
|
|
|
361
361
|
## Link-Field Integrity (v3.3)
|
|
362
362
|
|
|
363
363
|
**`depends_on` is the single authoritative edge; `unlocks` is derived, never hand-authored.**
|
|
364
|
-
On EVERY board write — analyze,
|
|
364
|
+
On EVERY board write — analyze, reconcile — recompute (via
|
|
365
365
|
`board-derive.mjs --write`, never by hand) the `unlocks` field of every task on the board as the
|
|
366
366
|
exact inverse of the full board's `depends_on` graph, then write it. Adding one task that
|
|
367
367
|
declares `depends_on: [TASK-007]` therefore rewrites `TASK-007.unlocks` in the same pass.
|
|
368
368
|
"Write both sides when you remember" allows drift; a derived field cannot drift
|
|
369
|
-
(
|
|
369
|
+
(the old rule shipped boards carrying ten asymmetric edges). Audit L3-06 fails the board
|
|
370
370
|
on any asymmetric edge.
|
|
371
371
|
|
|
372
372
|
The same discipline has a boundary: it applies only when both sides live in the SAME root
|
|
@@ -584,12 +584,12 @@ This is scope hammering at the gate boundary — the overflow is surfaced, never
|
|
|
584
584
|
**Naming note:** the discovery ledger's "scope" sections (above) predate the formal Scope
|
|
585
585
|
Contract artifact below and name the same thing — a `discovery/ledger.md` scope heading MUST
|
|
586
586
|
match an existing `scope_id` from a `scopes/<scope-id>.md` contract, or (a Keep item
|
|
587
|
-
introducing new flow) become the seed for a new one via a scope-architect
|
|
587
|
+
introducing new flow) become the seed for a new one via a scope-architect `map-scopes` order. One concept, two touch points.
|
|
588
588
|
|
|
589
589
|
**Import/flow slicing (PA1 countermeasure).** Build a lightweight import graph over the task
|
|
590
590
|
board's touched files: for each file a task writes, note what it imports and what imports it
|
|
591
591
|
(grep for `import .* from ['"](\.\.?/[^'"]+)`-class patterns is sufficient — a full AST parser
|
|
592
|
-
is an optimization, not a prerequisite
|
|
592
|
+
is an optimization, not a prerequisite). Two files are in the same flow if
|
|
593
593
|
they sit on one call chain: a UI component → the API route it calls → the use case that route
|
|
594
594
|
invokes → the repository that use case depends on. Group tasks by flow, not by which top-level
|
|
595
595
|
directory their file lives in. A scope whose `allowed_file_substrate` is entirely `apps/web/**`
|
|
@@ -614,8 +614,8 @@ or entirely `apps/api/**` with no cross-layer flow is the PA1 failure mode — r
|
|
|
614
614
|
}
|
|
615
615
|
```
|
|
616
616
|
`hill_phase` is always written `UPHILL_UNKNOWN` at generation time — it is derived later from
|
|
617
|
-
mechanical T0/T1/seesaw facts, never declared by `ba
|
|
618
|
-
`null` until a scope-architect
|
|
617
|
+
mechanical T0/T1/seesaw facts, never declared by `ba`. `superseded_by` stays
|
|
618
|
+
`null` until a scope-architect `map-scopes` order retires this contract in favor of its replacements.
|
|
619
619
|
|
|
620
620
|
**PA2 size lint:** a scope whose `allowed_file_substrate` glob set resolves to more than ~15
|
|
621
621
|
files gets a ⚠️ from spec-lint PA2 (hard-cap configurable via pitch frontmatter `scope_size_cap`, default
|
|
@@ -7,7 +7,7 @@ source row below, it does not belong here (it belongs to exploratory QA, post-bu
|
|
|
7
7
|
**Why it exists.** `spec-conformance` grades the AC that were written; it cannot expand
|
|
8
8
|
them. The Test Surface is the systematic expansion — boundary values, negative cases,
|
|
9
9
|
error-code coverage — done once at spec time so the evaluator (`test-surface-conformance`
|
|
10
|
-
dimension) can probe it. Division of labor settled
|
|
10
|
+
dimension) can probe it. Division of labor, a settled design decision:
|
|
11
11
|
derivable tests = BA + Evaluator (this file); exploratory edges = `/qa-edge-hunter`,
|
|
12
12
|
post-PASS, on the running app.
|
|
13
13
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Board derivation (pure-skill architecture v1.0, plan §8.2).
|
|
3
3
|
//
|
|
4
4
|
// The mechanical half of the old ba-pitch-analyzer Phase 7b + v3.3 link-field rules — pure
|
|
5
|
-
// graph math a model should never re-derive (and
|
|
5
|
+
// graph math a model should never re-derive (and gets wrong: hand-authored inverses drift asymmetric
|
|
6
6
|
// edges came from hand-authored `unlocks`):
|
|
7
7
|
//
|
|
8
8
|
// • `unlocks` = the depends_on inverse, recomputed over the WHOLE board (--write persists
|
|
@@ -28,9 +28,9 @@ import { readAllContracts, splitFrontmatter, SCOPE_CONTRACT } from "../../tech-l
|
|
|
28
28
|
/**
|
|
29
29
|
* Read a list field from a frontmatter string, inline `[a, b]` or YAML block sequence alike.
|
|
30
30
|
*
|
|
31
|
-
*
|
|
31
|
+
* The SECOND instance of the same defect, in a second parser. This repo had two hand-rolled
|
|
32
32
|
* frontmatter readers: `contract-md.mjs` for the committed contracts, and this one for the board.
|
|
33
|
-
*
|
|
33
|
+
* It was fixed in the first, and this one still silently dropped a block sequence — so a board
|
|
34
34
|
* written as
|
|
35
35
|
* use_case_refs:
|
|
36
36
|
* - UC-01
|
|
@@ -163,8 +163,8 @@ export function driftCheck(tasks, scopes) {
|
|
|
163
163
|
* board, deleted before CLI output).
|
|
164
164
|
*/
|
|
165
165
|
export function derive({ cwd, slug, appetiteHours = null }) {
|
|
166
|
-
const
|
|
167
|
-
const tasks = parseBoard(
|
|
166
|
+
const boardDir = tasksDir(cwd, slug);
|
|
167
|
+
const tasks = parseBoard(boardDir);
|
|
168
168
|
const unlocks = deriveUnlocks(tasks);
|
|
169
169
|
const keepHours = tasks.filter((t) => t.status !== "cut").reduce((a, t) => a + t.hours, 0);
|
|
170
170
|
const packages = {};
|
|
@@ -159,7 +159,7 @@ export function lintStructure({ specDir, tasks }) {
|
|
|
159
159
|
}
|
|
160
160
|
}
|
|
161
161
|
}
|
|
162
|
-
// Task frontmatter + graph integrity (edge symmetry
|
|
162
|
+
// Task frontmatter + graph integrity (edge symmetry — the hand-authored-unlocks drift, mechanized).
|
|
163
163
|
const ids = new Set(tasks.map((t) => t.id));
|
|
164
164
|
const derived = deriveUnlocks(tasks);
|
|
165
165
|
for (const t of tasks) {
|
|
@@ -203,7 +203,7 @@ export function lint({ cwd, slug }) {
|
|
|
203
203
|
const tasks = parseBoard(tasksDir(cwd, slug));
|
|
204
204
|
const repoFiles = walkFiles(cwd);
|
|
205
205
|
const findings = [
|
|
206
|
-
//
|
|
206
|
+
// A contract whose table this parser cannot see reads as a contract that declared no
|
|
207
207
|
// table, and every rule below then passes for the part it could not read. Loud, not empty.
|
|
208
208
|
...contracts
|
|
209
209
|
.map(({ contract, path }) => ({ reason: unreadableReason(contract), scope: contract.scope_id || path }))
|
package/skills/coach/SKILL.md
CHANGED
|
@@ -41,8 +41,8 @@ they are the **complete** set of categories the gate may offer:
|
|
|
41
41
|
|
|
42
42
|
| Category | File | The worker reads it at | Good for |
|
|
43
43
|
|----------|------|------------------------|----------|
|
|
44
|
-
| `task-executor` | `shapeup/knowledge-base/task-executor.md` |
|
|
45
|
-
| `ba-pitch-analyzer` | `shapeup/knowledge-base/ba-pitch-analyzer.md` | Phase 1 (
|
|
44
|
+
| `task-executor` | `shapeup/knowledge-base/task-executor.md` | PLAN (context load) | implementation discipline, code style, surgical-change habits, recurring over/under-engineering |
|
|
45
|
+
| `ba-pitch-analyzer` | `shapeup/knowledge-base/ba-pitch-analyzer.md` | Phase 1 (INGEST) | scoping, task decomposition, DDD/spec habits, missed test-surface patterns |
|
|
46
46
|
| `qa-edge-hunter` | `shapeup/knowledge-base/qa-edge-hunter.md` | Phase Q1 (Charter Map) | recurring edge classes, lenses that keep finding bugs, areas worth probing |
|
|
47
47
|
|
|
48
48
|
**Not coachable.** `spec-evaluator` is deliberately excluded — the harness has a **single-judge**
|
|
@@ -54,7 +54,7 @@ say so plainly — do **not** force-fit it into a coachable category.
|
|
|
54
54
|
**Harness defect ≠ worker steering.** When the feedback's root cause is the *mechanism itself* —
|
|
55
55
|
a hook that fail-opens, a gate that reads the wrong file, two skill contracts that contradict
|
|
56
56
|
each other — no amount of steering a worker fixes it, and filing it as a KB rule misdiagnoses a
|
|
57
|
-
defect as a habit (
|
|
57
|
+
defect as a habit (a real case: an orchestration/hook defect filed as BA guidance,
|
|
58
58
|
on a premise the skill contracts contradict). That is what the `harness-defect` category below is
|
|
59
59
|
for: the coach records it in the committed defect register as a drafted **raw idea** for the
|
|
60
60
|
Betting Table — the debt-free path ("remaining findings + new feedback → new raw idea") — and it
|
package/skills/orient/SKILL.md
CHANGED
|
@@ -42,7 +42,8 @@ from `tech-lead`; it never reads or writes a shared run-state file.
|
|
|
42
42
|
## Input contract (pure worker)
|
|
43
43
|
|
|
44
44
|
Orchestrated, you are invoked as `--order <path>` (a WorkOrder): `payload.pitch` (the
|
|
45
|
-
kicked-off pitch path), `payload.stack` (sweep hint),
|
|
45
|
+
kicked-off pitch path), `payload.stack` (sweep hint), `payload.spec_folder` (the SHARED spec
|
|
46
|
+
deliverable dir) and `payload.feature` (the run slug), plus `substrate.allowed` naming your one
|
|
46
47
|
write surface — the orient output dir. Anything absent = unknown: confirm at GATE O-A
|
|
47
48
|
(standalone) or report it in the result's `deviations`, never guess. Standalone, the
|
|
48
49
|
`--pitch/--spec/--stack` flags below carry the same fields; the output dir derives from the
|
|
@@ -18,7 +18,7 @@ tech-lead: ... GATE L2 → EVAL → GATE L3 PASS ──► QA EDGE HUNT (you)
|
|
|
18
18
|
GATE L3 FAIL → fix round (never reaches you — conformance first, edges after)
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
-
**Division of labor (settled
|
|
21
|
+
**Division of labor (a settled design decision, not a convention):**
|
|
22
22
|
|
|
23
23
|
| Tier | Owner | When |
|
|
24
24
|
|---|---|---|
|
|
@@ -36,11 +36,11 @@ tech-lead: ... GATE L2 → EVAL → GATE L3 PASS ──► QA EDGE HUNT (you)
|
|
|
36
36
|
| Execute charters on the **running app** (session-based exploratory) | Read-only speculate from code ("this looks racy") — every finding needs a live repro |
|
|
37
37
|
| Return each finding in the WorkResult's `discoveries[]`, **always `~`** | Promote `~` → must-have (PO/TL at SHIP S.0; severity-hint is advice, not a decision) |
|
|
38
38
|
| Emit `qa/hunt-report.md` — charters run/cut, findings by lens | Render a verdict, score, or PASS/FAIL of any kind |
|
|
39
|
-
| `--recheck`: re-probe ONLY items promoted+fixed after triage | Run a second full hunt in the same cycle; fix code; touch task files; keep run-state |
|
|
40
39
|
|
|
41
40
|
Pure worker (harness rule: stateless workers, one stateful orchestrator). Its WorkOrder
|
|
42
41
|
carries `payload.feature`, `payload.spec_folder`, `payload.eval_report`, `payload.app_url`,
|
|
43
|
-
`payload.kb_rules_path` (
|
|
42
|
+
`payload.kb_rules_path`, and `payload.ledger` (the discovery ledger, READ-ONLY — covered-territory
|
|
43
|
+
context so a hunt does not re-report what is already known); its write surface is
|
|
44
44
|
`.shapeup/<feature>/qa/**` only. The Hunter never touches the discovery ledger itself —
|
|
45
45
|
ingest appends its `discoveries[]` under a `## Discovered` section, preserving single-writer
|
|
46
46
|
mechanically.
|
|
@@ -272,7 +272,6 @@ an order, the WorkResult envelope `.shapeup/<feature>/results/<order-suffix>.jso
|
|
|
272
272
|
|
|
273
273
|
```markdown
|
|
274
274
|
# Hunt Report — [feature] (round [r], [date])
|
|
275
|
-
mode: [full | degraded | recheck]
|
|
276
275
|
charters: [run]/[approved] · session units spent: [n]
|
|
277
276
|
out of bounds (excluded): […]
|
|
278
277
|
hammered out at GATE Q1 (not hunted): […]
|
|
@@ -282,7 +281,8 @@ hammered out at GATE Q1 (not hunted): […]
|
|
|
282
281
|
|---|---|---|---|
|
|
283
282
|
| ① Boundary | C-01, C-05 | 2 | 0 |
|
|
284
283
|
| … | | | |
|
|
285
|
-
→ details live in .shapeup/<feature>/discovery/ledger.md
|
|
284
|
+
→ details live in .shapeup/<feature>/discovery/ledger.md under the `## Discovered` section
|
|
285
|
+
ingest appends for this hunt's order
|
|
286
286
|
|
|
287
287
|
## Shaping-quality signal (advisory, for the PO — next cycle's input)
|
|
288
288
|
- lens ⑤ findings ≈ No-gos written loosely (breach routes left open)
|
|
@@ -298,48 +298,18 @@ No verdict line exists in this file by design. The Hunter's last words:
|
|
|
298
298
|
|
|
299
299
|
---
|
|
300
300
|
|
|
301
|
-
## `--recheck` mode (after triage promoted + fixed items)
|
|
302
|
-
|
|
303
|
-
```
|
|
304
|
-
Input: the promoted finding ids (from tech-lead) + the fix round's PASS EVAL report.
|
|
305
|
-
Q0 : hard checks only (app up, new EVAL PASS); no soft check, no charter map.
|
|
306
|
-
Hunt : re-run EXACTLY the recorded repro of each promoted finding — nothing else.
|
|
307
|
-
fixed → discoveries[] entry `{ "marker": "~", "line": "[QA-NNN] ✦ fixed r[N], verified" }`
|
|
308
|
-
(ingest annotates the ledger — annotate, never delete; the ledger is history)
|
|
309
|
-
not fixed → `{ "marker": "~", "line": "[QA-NNN] ✦ NOT fixed r[N]", "repro": "<fresh evidence>" }`
|
|
310
|
-
back to triage.
|
|
311
|
-
Report: append a `## Recheck (round [r])` section to .shapeup/<feature>/qa/hunt-report.md.
|
|
312
|
-
NEVER a second full hunt in the same cycle — new edges found while rechecking are
|
|
313
|
-
recorded `~` like any finding and wait for triage; they don't restart the loop.
|
|
314
|
-
```
|
|
315
|
-
|
|
316
|
-
---
|
|
317
|
-
|
|
318
301
|
## Invocation
|
|
319
302
|
|
|
320
303
|
```bash
|
|
321
|
-
# Orchestrated (how tech-lead calls it after first PASS) — the canonical form:
|
|
322
|
-
# compile-order --operation hunt --slug checkout-vnpay --worker qa-edge-hunter \
|
|
323
|
-
# --payload '{"eval_report": "…/EVAL-FEATURE-checkout-vnpay.md", "app_url": "http://localhost:3000"}'
|
|
324
|
-
/qa-edge-hunter --order .shapeup/checkout-vnpay/orders/hunt.json
|
|
325
|
-
|
|
326
|
-
# Standalone flags (the preamble shim compiles the same envelope)
|
|
327
|
-
/qa-edge-hunter --feature checkout-vnpay --spec shapeup/checkout-vnpay/spec/ \
|
|
328
|
-
--eval .shapeup/checkout-vnpay/evaluation/EVAL-FEATURE-checkout-vnpay.md \
|
|
329
|
-
--ledger .shapeup/checkout-vnpay/discovery/ledger.md --app http://localhost:3000
|
|
330
|
-
|
|
331
|
-
# Standalone (same arguments, human-invoked)
|
|
332
304
|
/qa-edge-hunter --feature checkout-vnpay --spec shapeup/checkout-vnpay/spec/ --app http://localhost:3000
|
|
333
305
|
# (--eval/--ledger default to the conventional paths under the LOCAL root .shapeup/<feature>/)
|
|
334
306
|
|
|
335
|
-
#
|
|
336
|
-
/qa-edge-hunter --recheck QA-001,QA-004 --feature checkout-vnpay --spec ... --app ...
|
|
337
|
-
|
|
338
|
-
# Escape hatches
|
|
307
|
+
# Escape hatch
|
|
339
308
|
--auto # skip GATE Q1 pause (charter list logged, not reviewed) — Q0 hard
|
|
340
309
|
# checks and the out-of-bounds question are NEVER skipped
|
|
341
|
-
|
|
342
|
-
|
|
310
|
+
|
|
311
|
+
# There is deliberately NO --lenses flag: the 6 lenses are fixed; narrow by cutting
|
|
312
|
+
# charters at GATE Q1 (or --auto + report).
|
|
343
313
|
```
|
|
344
314
|
|
|
345
315
|
### Progress Markers
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: scope-architect
|
|
3
|
-
description: "Use this skill to map
|
|
3
|
+
description: "Use this skill to map the vertical scopes of a feature — Shape Up's \"map the scopes\" (step 8) as committed, mechanically enforceable contracts. Triggers on: \"map the scopes\", \"write the scope contracts\", \"scope contract\", \"the discovered tasks don't fit any scope\", \"re-slice the substrate\" (operations map-scopes). Writes the committed scopes/*.md contracts by import-graph slicing along business flow, with write-whitelist substrates and e2e fixtures. NOT for decomposing a pitch into tasks (ba-pitch-analyzer) or cutting scope at ship time (scope-hammer)."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Scope Architect (pure worker v1.0)
|
|
@@ -19,11 +19,9 @@ anti-rationalization table.
|
|
|
19
19
|
|
|
20
20
|
| Field | What it is |
|
|
21
21
|
|---|---|
|
|
22
|
-
| `operation` | `map-scopes`
|
|
22
|
+
| `operation` | `map-scopes` — the only operation this skill has. It covers first slicing after the board exists, folding discovered items in, and re-slicing a stuck scope; the payload says which of those you are doing |
|
|
23
23
|
| `payload.feature` / `payload.spec_folder` | Slug + committed spec (read ux-behavior.md for manifests; usecases for flows) |
|
|
24
24
|
| `payload.tasks[]` | The board's tasks with their touched files — the slicing input |
|
|
25
|
-
| `payload.discovered_ledger` | (remap) items that fit no existing substrate |
|
|
26
|
-
| `payload.scope_id` | (split-scope) the stuck scope (`rounds_at_position ≥ 3`, or an approved substrate-expansion) |
|
|
27
25
|
| `substrate.allowed` | `scopes/*.md` + `scope-board.md` — your ONLY write surface |
|
|
28
26
|
|
|
29
27
|
## Core process
|
|
@@ -59,17 +57,17 @@ anti-rationalization table.
|
|
|
59
57
|
a fixture for unbuilt behavior
|
|
60
58
|
hill_phase: "UPHILL_UNKNOWN" — ALWAYS; phase is derived from
|
|
61
59
|
T0/T1/seesaw facts later,
|
|
62
|
-
never authored
|
|
60
|
+
never authored
|
|
63
61
|
4 LINT node "${CLAUDE_PLUGIN_ROOT}/skills/ba-pitch-analyzer/scripts/spec-lint.mjs" --slug <slug>
|
|
64
62
|
→ PA1 (directory alignment), PA2 (>~15 files), DISJOINT (undeclared overlap).
|
|
65
63
|
Fix reds by re-slicing, not by silencing.
|
|
66
64
|
5 BOARD regenerate scope-board.md (scope_id, topology, task count, substrate size, lint)
|
|
67
65
|
```
|
|
68
66
|
|
|
69
|
-
**
|
|
67
|
+
**Folding in a discovered item:** it joins the nearest scope only if the flow matches (extend that
|
|
70
68
|
substrate minimally); otherwise propose a NEW scope — never silently widen an existing one.
|
|
71
|
-
**
|
|
72
|
-
old one `superseded_by: [ids]` — never delete (branch and T0 history stay attributable).
|
|
69
|
+
**Re-slicing a stuck scope:** re-run step 1 on just that scope's task+file set → N new contracts;
|
|
70
|
+
mark the old one `superseded_by: [ids]` — never delete (branch and T0 history stay attributable).
|
|
73
71
|
|
|
74
72
|
## Anti-rationalization table
|
|
75
73
|
|
|
@@ -84,10 +82,17 @@ old one `superseded_by: [ids]` — never delete (branch and T0 history stay attr
|
|
|
84
82
|
|
|
85
83
|
## Output contract — the WorkResult
|
|
86
84
|
|
|
85
|
+
**Escalation rule.** If you return `status: "escalated"`, the **first** entry in `deviations[]`
|
|
86
|
+
must be the blocker: one specific, answerable question plus the context needed to answer it.
|
|
87
|
+
Nothing else in the envelope carries it — there is no `escalates[]` field — so a vague entry, or
|
|
88
|
+
the question buried under other notes, reaches the human as "something went wrong" and costs a
|
|
89
|
+
round. Write it so someone without your context can answer it in one reply.
|
|
90
|
+
|
|
91
|
+
|
|
87
92
|
`scopes/*.md` + `scope-board.md` in your substrate, then
|
|
88
93
|
`.shapeup/<slug>/results/<order-suffix>.json`: `status`, `artifacts[]` (the contracts
|
|
89
|
-
written/superseded), `
|
|
90
|
-
territory
|
|
94
|
+
written/superseded), `deviations[]` (e.g. a discovered item implying a new UC — the planner's
|
|
95
|
+
territory — and any lint warn left standing, with why). You never touch task files,
|
|
91
96
|
`tasks/_index.md`, spec docs, or run-state.
|
|
92
97
|
|
|
93
98
|
## Verification checklist
|
|
@@ -102,10 +107,10 @@ territory), `deviations[]` (any lint warn left standing and why). You never touc
|
|
|
102
107
|
## Invocation
|
|
103
108
|
|
|
104
109
|
```bash
|
|
105
|
-
# Orchestrated — compile-order --operation map-scopes
|
|
110
|
+
# Orchestrated — compile-order --operation map-scopes --worker scope-architect …
|
|
106
111
|
/scope-architect --order .shapeup/checkout-vnpay/orders/map-scopes.json
|
|
107
112
|
|
|
108
113
|
# Standalone shims (compile the same envelope)
|
|
109
114
|
/scope-architect --map shapeup/checkout-vnpay/
|
|
110
|
-
/scope-architect --split cart-creation shapeup/checkout-vnpay/
|
|
115
|
+
/scope-architect --map --split cart-creation shapeup/checkout-vnpay/ # re-slice one scope
|
|
111
116
|
```
|
|
@@ -11,7 +11,7 @@ live with today — not to a hypothetical perfect version. "Better than the base
|
|
|
11
11
|
enough to ship; "not as good as I imagined" is not a reason to keep building.
|
|
12
12
|
|
|
13
13
|
**Why this is its own skill, not tech-lead prose.** GATE H census pulls from several sources
|
|
14
|
-
that accumulate over a whole run (QA findings, discovered-task ledger,
|
|
14
|
+
that accumulate over a whole run (QA findings, discovered-task ledger, attempt-budget
|
|
15
15
|
overflows, per-scope inner-breaker trips) — a genuinely separate synthesis step from
|
|
16
16
|
orchestration. Splitting it out keeps `tech-lead` thin (it dispatches, this skill decides what
|
|
17
17
|
survives the hammer) and gives the census/cut-list/verdict logic one owner instead of being
|
|
@@ -22,10 +22,10 @@ re-derived inline at every SHIP.
|
|
|
22
22
|
## When this fires
|
|
23
23
|
|
|
24
24
|
```
|
|
25
|
-
1. All scopes reach FINISHED on the hill
|
|
25
|
+
1. All scopes reach FINISHED on the hill → normal stop, post-QA-hunt.
|
|
26
26
|
2. Outer circuit breaker trips: round_budget reaches 0 with scopes still uphill/downhill.
|
|
27
27
|
3. Inner circuit breaker trips: a scope's attempt_budget (default 5) is exhausted without a
|
|
28
|
-
T0-green result → queued as a hammer PROPOSAL (
|
|
28
|
+
T0-green result → queued as a hammer PROPOSAL (`hammer_proposals`),
|
|
29
29
|
judged here rather than immediately blocking the round.
|
|
30
30
|
```
|
|
31
31
|
Any of the three routes to this skill; the difference is only what's in the census (case 1 has
|
|
@@ -63,7 +63,7 @@ H0.1 Unresolved scopes (breaker cases only):
|
|
|
63
63
|
with the T0 failure that stalled them (from the last red t0/verdicts/*.json)
|
|
64
64
|
H0.2 QA findings (qa-edge-hunter's hunt-report.md, when present) — all `~` by default.
|
|
65
65
|
H0.3 Discovered-task ledger entries still open (discovery/ledger.md, `[+]`/`~` unresolved).
|
|
66
|
-
H0.4
|
|
66
|
+
H0.4 Attempt-budget hammer proposals (scopes that exhausted their T0 attempts during BUILD).
|
|
67
67
|
H0.5 Classify every item: MUST-HAVE (the pitch's core problem is unsolved without it) vs
|
|
68
68
|
NICE-TO-HAVE (`~`, improves but doesn't block the core promise). Default to NICE-TO-HAVE
|
|
69
69
|
unless the item traces directly to a pitch boundary or a scope's business_goal — a
|
|
@@ -87,7 +87,7 @@ customer suffers through today), never to a perfect ideal.
|
|
|
87
87
|
|
|
88
88
|
```
|
|
89
89
|
H1.1 Resolve the baseline: shapeup/<slug>/shaping/baseline.md if present (written at
|
|
90
|
-
shaping time
|
|
90
|
+
shaping time — first-class, not a pitch footnote). Absent →
|
|
91
91
|
degrade honestly: read the pitch's problem statement as the implicit baseline and flag
|
|
92
92
|
"baseline not first-class — comparison is approximate" in the report. Do not invent one.
|
|
93
93
|
H1.2 For each MUST-HAVE item from H0: "with this item cut/carried, is the shipped product
|
package/skills/shapeup/SKILL.md
CHANGED
|
@@ -33,7 +33,7 @@ This skill lazily loads detail from resource files. **Read the relevant resource
|
|
|
33
33
|
| `/shapeup breadboard-reflection` | `resources/breadboard-reflection.md` |
|
|
34
34
|
| `/shapeup full` | Read `resources/shaping.md` first, then `resources/breadboarding.md` before B-phases, and `resources/context-compaction.md` for the run digest |
|
|
35
35
|
|
|
36
|
-
> Resource paths are relative to this skill's directory.
|
|
36
|
+
> Resource paths are relative to this skill's directory (`resources/` beside this SKILL.md, wherever the plugin is installed).
|
|
37
37
|
> Multi-gate runs maintain a derived **decision digest** so each gate reads a compact slice instead of full prose — see `resources/context-compaction.md` and the "Run Workspace & Digest" section below.
|
|
38
38
|
|
|
39
39
|
---
|
|
@@ -374,8 +374,8 @@ Two roots, separated by artifact **nature** (full design →
|
|
|
374
374
|
- **Shared** root `shapeup/[slug]/` = what the team contributes to
|
|
375
375
|
(source + deliverable). **Local** root `.shapeup/[slug]/` = per-run scratch,
|
|
376
376
|
hidden and fully gitignorable. Add **one** line to `.gitignore`: `.shapeup/`.
|
|
377
|
-
No carve-out needed —
|
|
378
|
-
|
|
377
|
+
No carve-out needed — everything machine-written at run time, including the
|
|
378
|
+
harvest shards `.shapeup/metrics/*.jsonl`, lives under the local root.
|
|
379
379
|
- `digest.md` is the run's derived decision context (the 4-field, two-zone read
|
|
380
380
|
model the gates consume). It is **never** the source of truth and never crosses
|
|
381
381
|
a skill boundary — `ba-pitch-analyzer` reads `pitch.md`/`shaping.md`, never the
|
|
@@ -182,9 +182,10 @@ Everything keys off the feature `<slug>`. Two roots, split by **who needs it**:
|
|
|
182
182
|
- The **local** root `.shapeup/[slug]/` is per-run scratch + reports — hidden,
|
|
183
183
|
fully gitignorable, dies with the run. It is derived from the same `<slug>`.
|
|
184
184
|
- `.gitignore`: one line — `.shapeup/`. The whole local root is ignored; no
|
|
185
|
-
carve-out is needed because
|
|
186
|
-
signal
|
|
187
|
-
fact-only; see the tech-lead skill's SHIP step)
|
|
185
|
+
carve-out is needed because everything machine-written at run time lives there,
|
|
186
|
+
including the harvested signal shards `.shapeup/metrics/*.jsonl` (written by
|
|
187
|
+
the tech-lead at SHIP, fact-only; see the tech-lead skill's SHIP step). The
|
|
188
|
+
committed report surface is the frozen `shapeup/[slug]/REPORT.md`.
|
|
188
189
|
- All paths are **project-relative, resolved from the project root / cwd.** Never
|
|
189
190
|
`/mnt/...` — that is the claude.ai authoring sandbox and dies in a user repo.
|
|
190
191
|
|
|
@@ -7,9 +7,9 @@ description: "Use this skill to design how each use-case's engine integrates int
|
|
|
7
7
|
|
|
8
8
|
**Design the seam, or the engine ships orphaned.**
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
**zero call sites** in the app's composition root —
|
|
12
|
-
running application
|
|
10
|
+
This skill exists because a sizeable engine module can be built, fully tested, and still have
|
|
11
|
+
**zero call sites** in the app's composition root — green, and unreachable from the
|
|
12
|
+
running application; observed across multiple scopes in one run, not theorized. It closes that
|
|
13
13
|
hole at the front: before the scopes are sliced, it designs a committed **wiring map**
|
|
14
14
|
(`shapeup/<slug>/wiring-map.md`) that names, for every use case, the chain from the
|
|
15
15
|
engine module to a player-visible affordance — including **how** and **where** the engine attaches
|
|
@@ -29,7 +29,7 @@ Two payoffs, one artifact:
|
|
|
29
29
|
proving.
|
|
30
30
|
- **The slicer gets its integration seam up front.** Declaring each attachment *before*
|
|
31
31
|
`scope-architect` runs supplies the missing input behind the round-1 substrate-expansion
|
|
32
|
-
escalations —
|
|
32
|
+
escalations — repeated identical "declined by precedent" stalls. (This skill *front-loads* the
|
|
33
33
|
seam; it does not enforce the re-slice rule — that's a separate change.)
|
|
34
34
|
|
|
35
35
|
You are the **sole writer** of the wiring map, written **directly** (the same authority
|
|
@@ -73,14 +73,14 @@ guessed `main.js` would make the later oracle certify nothing.
|
|
|
73
73
|
3 WRITE shapeup/<slug>/wiring-map.md (WiringMap): {schema_version:1, feature,
|
|
74
74
|
entry_point (echo of the profile), entries[]}. One entry per use case. A UC whose
|
|
75
75
|
engine has no attachment path is exactly the gap this artifact exists to surface —
|
|
76
|
-
write the entry with the seam you INTEND and raise it in deviations[]
|
|
76
|
+
write the entry with the seam you INTEND and raise it in deviations[], so
|
|
77
77
|
the build knows the wiring it must close. Your craft ends here: WRITE, then return the
|
|
78
78
|
WorkResult. You do not run trace-lint — the orchestrator runs it advisory at L1b.
|
|
79
79
|
```
|
|
80
80
|
|
|
81
81
|
**No use case is exempt.** If a UC's engine genuinely has no player-facing seam (a pure
|
|
82
82
|
background job), say so in `wiring_seam` and name the boot/cron/init attachment that starts it — a
|
|
83
|
-
cron registration, a boot hook. "It's internal" is how
|
|
83
|
+
cron registration, a boot hook. "It's internal" is how an engine stays orphaned; there
|
|
84
84
|
is always an attachment to the entry point, or the code never runs.
|
|
85
85
|
|
|
86
86
|
## Anti-rationalization table
|
|
@@ -96,11 +96,18 @@ is always an attachment to the entry point, or the code never runs.
|
|
|
96
96
|
|
|
97
97
|
## Output contract — the WorkResult
|
|
98
98
|
|
|
99
|
+
**Escalation rule.** If you return `status: "escalated"`, the **first** entry in `deviations[]`
|
|
100
|
+
must be the blocker: one specific, answerable question plus the context needed to answer it.
|
|
101
|
+
Nothing else in the envelope carries it — there is no `escalates[]` field — so a vague entry, or
|
|
102
|
+
the question buried under other notes, reaches the human as "something went wrong" and costs a
|
|
103
|
+
round. Write it so someone without your context can answer it in one reply.
|
|
104
|
+
|
|
105
|
+
|
|
99
106
|
`wiring-map.md` in your substrate, then `.shapeup/<slug>/results/<order-suffix>.json`:
|
|
100
|
-
`status`, `artifacts[]` (the wiring map written), `
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
107
|
+
`status`, `artifacts[]` (the wiring map written), `assumptions[]` (engine paths
|
|
108
|
+
inferred from the domain model where the spec was silent), `deviations[]` (a missing profile, a
|
|
109
|
+
UC whose engine the spec never names — the planner's territory — a UC left with an uncertain
|
|
110
|
+
seam, or an engine with no attachment path, and why). You never touch spec docs,
|
|
104
111
|
`scopes/*.md`, `project-profile.md`, task files, or run-state.
|
|
105
112
|
|
|
106
113
|
## Verification checklist
|
|
@@ -110,7 +117,7 @@ uncertain seam, or an engine with no attachment path, and why). You never touch
|
|
|
110
117
|
- [ ] `entry_call_site` is a symbolic composition-root attachment resolved against the profile's `entry_point` — no invented line number, no guessed entry point
|
|
111
118
|
- [ ] `entry_point` echoes the profile — no independently-chosen seam
|
|
112
119
|
- [ ] The profile was READ, not guessed; a missing profile in orchestrated mode → ESCALATE, not an invented entry point
|
|
113
|
-
- [ ] Any UC whose engine has no attachment path is raised in `deviations[]
|
|
120
|
+
- [ ] Any UC whose engine has no attachment path is raised in `deviations[]` (the wiring the build must close), never silently dropped
|
|
114
121
|
- [ ] The WorkResult validates against `work-result.schema.json`
|
|
115
122
|
|
|
116
123
|
## Invocation
|
|
@@ -116,6 +116,13 @@ Done-when statements; `_index.md` Non-Go list. Which UCs are in scope comes from
|
|
|
116
116
|
|
|
117
117
|
## Output contract — the WorkResult
|
|
118
118
|
|
|
119
|
+
**Escalation rule.** If you return `status: "escalated"`, the **first** entry in `deviations[]`
|
|
120
|
+
must be the blocker: one specific, answerable question plus the context needed to answer it.
|
|
121
|
+
Nothing else in the envelope carries it — there is no `escalates[]` field — so a vague entry, or
|
|
122
|
+
the question buried under other notes, reaches the human as "something went wrong" and costs a
|
|
123
|
+
round. Write it so someone without your context can answer it in one reply.
|
|
124
|
+
|
|
125
|
+
|
|
119
126
|
1. Write the report `.shapeup/<slug>/evaluation/EVAL-FEATURE-<slug>.md` (or
|
|
120
127
|
`EVAL-<task_id>.md` for a per-task run) per `references/report-schema.md`: verdict,
|
|
121
128
|
per-dimension criteria table with confidence, stability block (flips), bug list (severity,
|
|
@@ -143,10 +150,10 @@ Done-when statements; `_index.md` Non-Go list. Which UCs are in scope comes from
|
|
|
143
150
|
```
|
|
144
151
|
|
|
145
152
|
**Every FAIL criterion's `evidence` MUST carry a `file:line` locator** — schema-enforced, not
|
|
146
|
-
advice:
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
and enforced nowhere; it is now
|
|
153
|
+
advice: the envelope is validated against `work-result.schema.json` at ingest and a locatorless
|
|
154
|
+
FAIL is rejected before any write. A PASS may cite plain output. (Observed, not theorized: a
|
|
155
|
+
correct FAIL verdict with no locator anywhere is unactionable without re-investigating — the
|
|
156
|
+
rule used to live in prose and be enforced nowhere; it is now data in `domain.schema.json`.)
|
|
150
157
|
|
|
151
158
|
The orchestrator's ingest appends the verdict ledger, un-ticks the `refuted` boxes, and sets
|
|
152
159
|
`eval_verdict` frontmatter. You never touch a task file, a board, or run-state — and you
|
|
@@ -209,5 +216,5 @@ summary — standalone has no orchestrator to ingest for you.
|
|
|
209
216
|
| Probe the RUNNING app, not the source alone | Apps that look right still break when used |
|
|
210
217
|
| Re-probe every FAIL; flip ⇒ confidence low | A single snapshot lies; the ledger makes it visible |
|
|
211
218
|
| Verdict-ledger lines are returned, appended by ingest, never rewritten | Verdict history is how a single-snapshot judge becomes measurable |
|
|
212
|
-
| A verdict on a scoped spec without a T0 citation is structurally invalid | T0 is a machine fact the generator cannot fabricate
|
|
219
|
+
| A verdict on a scoped spec without a T0 citation is structurally invalid | T0 is a machine fact the generator cannot fabricate |
|
|
213
220
|
| UI assertions target affordances only (test_id/role/data-state) | Layer-3 styling is frozen; grading it resurrects the freeze through the judge |
|