shapeup-sdlc 3.18.3 → 4.0.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/settings.local.example.json +2 -3
- package/.claude-plugin/plugin.json +1 -1
- package/AGENTS.md +115 -56
- package/README.md +101 -143
- package/SECURITY.md +16 -25
- package/agents/orient.md +14 -0
- package/agents/qa-edge-hunter.md +13 -0
- package/agents/spec-evaluator.md +14 -0
- package/agents/task-executor.md +14 -0
- package/bin/init.mjs +13 -16
- package/bin/lib/grant.mjs +8 -19
- package/commands/build.md +9 -14
- package/commands/eval.md +3 -3
- package/commands/hammer.md +9 -5
- package/commands/retro.md +12 -11
- package/commands/scopes.md +1 -12
- package/commands/ship.md +45 -88
- package/commands/wire.md +1 -8
- package/hooks/dispatch-receipt.mjs +94 -8
- package/hooks/hooks.json +0 -41
- package/hooks/lib/decision.mjs +6 -9
- package/hooks/lib/tier.mjs +50 -0
- package/hooks/sandbox-guard.mjs +140 -64
- package/kernel/gate.mjs +203 -22
- package/kernel/harness.mjs +20 -67
- package/kernel/init/run.mjs +175 -523
- package/kernel/lib/contract.mjs +9 -93
- package/kernel/lib/floor.mjs +64 -0
- package/kernel/lib/paths.mjs +39 -112
- package/kernel/order.mjs +157 -0
- package/kernel/probe/digest.mjs +2 -38
- package/kernel/schemas/domain.schema.json +146 -1125
- package/kernel/schemas/work-order.schema.json +8 -4
- package/kernel/schemas/work-result.schema.json +1 -1
- package/kernel/verify/envelope.mjs +2 -2
- package/kernel/verify/skills.mjs +27 -8
- package/kernel/verify/t0.mjs +2 -2
- package/package.json +4 -2
- package/skills/building/SKILL.md +144 -0
- package/skills/building/resources/gates.md +76 -0
- package/skills/building/resources/guidance.md +23 -0
- package/skills/{translator/references/preservation-rules.md → building/resources/intake-preservation.md} +1 -1
- package/skills/building/resources/intake.md +157 -0
- package/skills/building/resources/orders.md +69 -0
- package/skills/{ba-pitch-analyzer/references → building/resources/plan-references}/doc-schemas.md +1 -1
- package/skills/{ba-pitch-analyzer/references → building/resources/plan-references}/task-generation.md +13 -13
- package/skills/{ba-pitch-analyzer/references → building/resources/plan-references}/test-surface.md +6 -7
- package/skills/building/resources/plan-scopes.md +95 -0
- package/skills/building/resources/plan-spec.md +102 -0
- package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/_index.tmpl.md +1 -1
- package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/assess-report.tmpl.md +10 -11
- package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/run-state.tmpl.md +4 -4
- package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/scope-summary.tmpl.md +2 -2
- package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/synthesis.tmpl.md +4 -4
- package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/usecase.tmpl.md +2 -2
- package/skills/building/resources/plan-wire.md +82 -0
- package/skills/building/resources/plan.md +98 -0
- package/skills/building/resources/retro-research.md +60 -0
- package/skills/building/resources/retro-scan.md +49 -0
- package/skills/building/resources/retro.md +225 -0
- package/skills/building/resources/rounds.md +78 -0
- package/skills/building/resources/stop.md +127 -0
- package/skills/orient/SKILL.md +37 -37
- package/skills/qa-edge-hunter/SKILL.md +14 -14
- package/skills/shapeup/SKILL.md +5 -5
- package/skills/shapeup/resources/breadboarding.md +1 -1
- package/skills/shapeup/resources/context-compaction.md +5 -5
- package/skills/shapeup/resources/shaping.md +1 -1
- package/skills/spec-evaluator/SKILL.md +17 -21
- package/skills/spec-evaluator/references/dimension-contract.md +1 -1
- package/skills/spec-evaluator/references/dimensions/completeness.md +3 -3
- package/skills/spec-evaluator/references/dimensions/spec-conformance.md +1 -1
- package/skills/spec-evaluator/references/dimensions/test-surface-conformance.md +5 -5
- package/skills/task-executor/SKILL.md +11 -15
- package/commands/hill.md +0 -10
- package/hooks/gate-intake.mjs +0 -109
- package/hooks/gate-zerowork.mjs +0 -349
- package/hooks/tier-guard.mjs +0 -162
- package/kernel/compile.mjs +0 -1419
- package/kernel/init/fit.mjs +0 -199
- package/kernel/init/run-args.mjs +0 -206
- package/kernel/lib/breadboard.mjs +0 -165
- package/kernel/probe/attempts.mjs +0 -161
- package/kernel/probe/concurrency.mjs +0 -535
- package/kernel/probe/eval.mjs +0 -405
- package/kernel/probe/hunt.mjs +0 -104
- package/kernel/probe/leg.mjs +0 -229
- package/kernel/probe/owner.mjs +0 -142
- package/kernel/probe/requirements.mjs +0 -328
- package/kernel/probe/resume.mjs +0 -1110
- package/kernel/probe/rounds.mjs +0 -115
- package/kernel/probe/staged.mjs +0 -83
- package/kernel/probe/stats.mjs +0 -477
- package/kernel/probe/t0.mjs +0 -115
- package/kernel/reduce/board.mjs +0 -350
- package/kernel/reduce/graph.mjs +0 -482
- package/kernel/reduce/hill.mjs +0 -322
- package/kernel/reduce/ingest.mjs +0 -767
- package/kernel/reduce/leftovers.mjs +0 -159
- package/kernel/reduce/ship.mjs +0 -529
- package/kernel/reduce/snapshot.mjs +0 -291
- package/kernel/reduce/verdict.mjs +0 -172
- package/kernel/report/export.mjs +0 -384
- package/kernel/report/facts.mjs +0 -234
- package/kernel/verify/budget.mjs +0 -153
- package/kernel/verify/build.mjs +0 -428
- package/kernel/verify/dispatch.mjs +0 -114
- package/kernel/verify/spec.mjs +0 -975
- package/kernel/verify/trace.mjs +0 -604
- package/skills/ba-pitch-analyzer/SKILL.md +0 -204
- package/skills/coach/SKILL.md +0 -397
- package/skills/hill-chart/SKILL.md +0 -154
- package/skills/hill-chart/assets/dashboard.template.html +0 -1432
- package/skills/scope-architect/SKILL.md +0 -174
- package/skills/scope-hammer/SKILL.md +0 -231
- package/skills/solution-architect/SKILL.md +0 -158
- package/skills/tech-lead/SKILL.md +0 -151
- package/skills/tech-lead/references/gates.md +0 -605
- package/skills/tech-lead/references/protocol.md +0 -889
- package/skills/tech-lead/references/tiny-lane.md +0 -53
- package/skills/tech-lead/workflows/shapeup-run.js +0 -2187
- package/skills/translator/SKILL.md +0 -258
- /package/skills/{ba-pitch-analyzer/references → building/resources/plan-references}/contract-patterns.md +0 -0
- /package/skills/{ba-pitch-analyzer/references → building/resources/plan-references}/ddd-patterns.md +0 -0
- /package/skills/{ba-pitch-analyzer/references → building/resources/plan-references}/integration-analysis.md +0 -0
- /package/skills/{ba-pitch-analyzer/references → building/resources/plan-references}/ux-behavior-patterns.md +0 -0
- /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/api-feasibility.tmpl.md +0 -0
- /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/contracts/be-service.contract.tmpl.md +0 -0
- /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/contracts/offline-storage.contract.tmpl.md +0 -0
- /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/contracts/third-party-api.contract.tmpl.md +0 -0
- /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/cross-context/context-map.tmpl.md +0 -0
- /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/cross-context/event-choreography.tmpl.md +0 -0
- /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/cross-context/migration-plan.tmpl.md +0 -0
- /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/cross-context/team-handoff.tmpl.md +0 -0
- /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/domain-model.tmpl.md +0 -0
- /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/feedback.tmpl.md +0 -0
- /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/integration.tmpl.md +0 -0
- /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/task-board.tmpl.md +0 -0
- /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/task-spike.tmpl.md +0 -0
- /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/task.tmpl.md +0 -0
- /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/ux-behavior.tmpl.md +0 -0
|
@@ -1,161 +0,0 @@
|
|
|
1
|
-
// probe attempts — "how many of this scope's attempts are ATTESTED work, not writable artifacts?"
|
|
2
|
-
//
|
|
3
|
-
// CONTRACT. A bounded, read-only query over one scope's attested channels for one round: dispatch
|
|
4
|
-
// receipts (`receipts/dispatch.jsonl`), leg-completion rows (`legs.jsonl`) and WorkResults
|
|
5
|
-
// (`results/`). Prints `{scope_id, round, attempt_budget, spent, in_flight, unattested, green,
|
|
6
|
-
// tripped, attempts}` on stdout; exits 0 when the breaker holds, 1 when it has tripped, 2 on a bad
|
|
7
|
-
// argv. Writes nothing.
|
|
8
|
-
//
|
|
9
|
-
// WHY IT EXISTS. Measured on a real run: attempt 2 of a scope was compiled and T0-verified
|
|
10
|
-
// several minutes BEFORE attempt 1 ingested — while attempt 1 was still in flight. No worker was
|
|
11
|
-
// ever dispatched for attempt 2:
|
|
12
|
-
// `receipts/dispatch.jsonl`, `legs.jsonl` and `results/` carried no row for it. A derivation keyed
|
|
13
|
-
// off the order set (`orders/`) or the T0 verdict set (`t0/verdicts/`) alone counts a compiled
|
|
14
|
-
// order or a green trial as a spent attempt regardless of whether a worker ever ran — both are
|
|
15
|
-
// WRITABLE by the very leg whose exhaustion is being judged. This module counts an attempt as
|
|
16
|
-
// SPENT only when a dispatch receipt attests it started AND either a leg-completion row or a
|
|
17
|
-
// WorkResult on disk attests it closed. Neither channel alone is enough: a receipt with no result
|
|
18
|
-
// is a leg still in flight (open, not spent — the breaker must not trip on unanswered work), and a
|
|
19
|
-
// result or verdict with no receipt is unattested — no worker ran, which is the shape that
|
|
20
|
-
// produced this module.
|
|
21
|
-
//
|
|
22
|
-
// WHY THE SAME FUNCTION SERVES THE BREAKER AND THE CENSUS. Before this module, the round loop's
|
|
23
|
-
// inner breaker and `scope-hammer`'s GATE H0 census read different evidence for the same question
|
|
24
|
-
// — the loop trusted the worker's own self-reported `attempts_used`/`breaker` (schema-shaped, not
|
|
25
|
-
// re-verified), the census read `t0/verdicts/*.json` directly — and disagreed on the measured run.
|
|
26
|
-
// One shared, attested derivation is what makes "the census and the breaker agree" true by
|
|
27
|
-
// construction rather than by coincidence: `skills/scope-hammer/SKILL.md` cites this same probe
|
|
28
|
-
// the way it already cites `probe owner` for ownership claims.
|
|
29
|
-
|
|
30
|
-
import { existsSync, readdirSync, readFileSync } from "node:fs";
|
|
31
|
-
import { join, resolve } from "node:path";
|
|
32
|
-
import { runArgs } from "../lib/argv.mjs";
|
|
33
|
-
import { dispatchReceipts, legLedger, resultsDir, readRunId, ordersDir } from "../lib/paths.mjs";
|
|
34
|
-
import { readLegs } from "./leg.mjs";
|
|
35
|
-
import { greenVerdict } from "./t0.mjs";
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Every dispatch-receipt row on disk, tolerant of a torn last line (mirrors {@link readLegs}).
|
|
39
|
-
* @param {string} path - `receipts/dispatch.jsonl`.
|
|
40
|
-
* @returns {object[]} Parsed rows; an unparsable line is skipped rather than fatal.
|
|
41
|
-
*/
|
|
42
|
-
export function readReceipts(path) {
|
|
43
|
-
if (!existsSync(path)) return [];
|
|
44
|
-
return readFileSync(path, "utf8").split("\n").filter(Boolean)
|
|
45
|
-
.map((l) => { try { return JSON.parse(l); } catch { return null; } })
|
|
46
|
-
.filter(Boolean);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* One attempt's evidence across the three attested channels, and the state it derives to.
|
|
51
|
-
*
|
|
52
|
-
* `unattested` (no receipt at all) counts as though the attempt never happened — the order and any
|
|
53
|
-
* T0 verdict may still be sitting on disk, written by something other than a dispatched worker, and
|
|
54
|
-
* neither is asked here. `in-flight` (a receipt, but no leg row and no result) is a real dispatch
|
|
55
|
-
* whose leg has not yet closed: open, not spent. `spent` is closed either way a leg closes — via
|
|
56
|
-
* `reduce ingest`'s own leg-completion row, or a WorkResult already on disk pending ingest.
|
|
57
|
-
*
|
|
58
|
-
* @param {string} cwd - Project root.
|
|
59
|
-
* @param {string} slug - Feature slug.
|
|
60
|
-
* @param {string} scopeId - Scope contract id (the order id's own address, e.g. `shell-r1-a2`).
|
|
61
|
-
* @param {number} round - Build round.
|
|
62
|
-
* @param {number} attempt - Attempt number within the round.
|
|
63
|
-
* @param {object[]} receipts - Pre-read `receipts/dispatch.jsonl` rows (avoids re-reading per attempt).
|
|
64
|
-
* @param {object[]} legs - Pre-read `legs.jsonl` rows.
|
|
65
|
-
* @returns {{orderId:string, hasReceipt:boolean, hasResult:boolean, hasLeg:boolean, state:("unattested"|"in-flight"|"spent")}}
|
|
66
|
-
*/
|
|
67
|
-
export function attemptEvidence(cwd, slug, scopeId, round, attempt, receipts, legs, runId = null) {
|
|
68
|
-
const orderId = `${slug}/${scopeId}-r${round}-a${attempt}`;
|
|
69
|
-
// SCOPED TO THIS RUN, and that qualifier is the whole correction. `receipts/dispatch.jsonl` and
|
|
70
|
-
// `legs.jsonl` are per-slug and append-only, so they accumulate across every run of a pitch,
|
|
71
|
-
// while `order_id` repeats — the run key is the only thing that separates two runs of one
|
|
72
|
-
// feature. Matching on `order_id` alone answered "was this attempt spent?" with a PREVIOUS run's
|
|
73
|
-
// receipt: measured on a consumer, a run that dispatched nothing was told its first attempt was
|
|
74
|
-
// spent, complete with leg and result, by rows two launches old.
|
|
75
|
-
//
|
|
76
|
-
// A row carrying no run key belongs to NO run rather than to this one, and an unresolvable
|
|
77
|
-
// current run (no receipt on disk) matches nothing. Both directions under-count rather than
|
|
78
|
-
// over-count, which is the safe way to be wrong here: an under-count leaves a breaker un-tripped
|
|
79
|
-
// and the round continues, where an over-count stops work that was never done.
|
|
80
|
-
const mine = (r) => r?.order_id === orderId && runId != null && r?.run_id === runId;
|
|
81
|
-
const hasReceipt = receipts.some(mine);
|
|
82
|
-
const hasLeg = legs.some(mine);
|
|
83
|
-
// A WorkResult carries no run key and reaches one only through its `order_id`, which repeats —
|
|
84
|
-
// so this stays a file check and is deliberately NOT sufficient on its own. It can only turn an
|
|
85
|
-
// already run-scoped receipt into `spent`; a result left behind by an earlier run cannot attest
|
|
86
|
-
// an attempt this run never dispatched.
|
|
87
|
-
// A WorkResult carries no run key of its own; it answers THIS run's attempt only through the
|
|
88
|
-
// order of the same name, which this run's compile rewrote. A result left by a prior run over the
|
|
89
|
-
// same slug used to close an attempt this run had not even opened.
|
|
90
|
-
const stem = `${scopeId}-r${round}-a${attempt}.json`;
|
|
91
|
-
let orderIsMine = true;
|
|
92
|
-
if (runId != null) {
|
|
93
|
-
try { const o = JSON.parse(readFileSync(join(ordersDir(cwd, slug), stem), "utf8")); orderIsMine = !o?.run_id || o.run_id === runId; }
|
|
94
|
-
catch { orderIsMine = false; }
|
|
95
|
-
}
|
|
96
|
-
const hasResult = orderIsMine && existsSync(join(resultsDir(cwd, slug), stem));
|
|
97
|
-
const state = !hasReceipt ? "unattested" : (hasResult || hasLeg) ? "spent" : "in-flight";
|
|
98
|
-
return { orderId, hasReceipt, hasResult, hasLeg, state };
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* A scope's attempt census for one round, derived ONLY from attested channels — the function both
|
|
103
|
-
* the round loop's inner breaker and scope-hammer's GATE H0 census call, so they cannot drift apart
|
|
104
|
-
* again the way a measured run found them.
|
|
105
|
-
*
|
|
106
|
-
* @param {string} cwd - Project root.
|
|
107
|
-
* @param {string} slug - Feature slug.
|
|
108
|
-
* @param {string} scopeId - Scope contract id.
|
|
109
|
-
* @param {number} round - Build round.
|
|
110
|
-
* @param {number} attemptBudget - The scope's configured `attempt_budget`.
|
|
111
|
-
* @returns {{scope_id:string, round:number, attempt_budget:number, spent:number, in_flight:number,
|
|
112
|
-
* unattested:number, green:boolean, tripped:boolean, attempts:object[]}} `tripped` is true only
|
|
113
|
-
* when every attempt within budget is genuinely SPENT and none produced a green T0 — an attempt
|
|
114
|
-
* still in flight holds the breaker open regardless of how many slots are nominally used.
|
|
115
|
-
*/
|
|
116
|
-
export function scopeAttempts(cwd, slug, scopeId, round, attemptBudget) {
|
|
117
|
-
const receipts = readReceipts(dispatchReceipts(cwd, slug));
|
|
118
|
-
const legs = readLegs(legLedger(cwd, slug));
|
|
119
|
-
const runId = readRunId(cwd, slug);
|
|
120
|
-
const attempts = [];
|
|
121
|
-
let spent = 0, inFlight = 0, unattested = 0;
|
|
122
|
-
for (let a = 1; a <= attemptBudget; a++) {
|
|
123
|
-
const ev = attemptEvidence(cwd, slug, scopeId, round, a, receipts, legs, runId);
|
|
124
|
-
if (ev.state === "spent") spent++;
|
|
125
|
-
else if (ev.state === "in-flight") inFlight++;
|
|
126
|
-
else unattested++;
|
|
127
|
-
attempts.push({ attempt: a, ...ev });
|
|
128
|
-
}
|
|
129
|
-
const { green } = greenVerdict(cwd, slug, scopeId, round);
|
|
130
|
-
return {
|
|
131
|
-
scope_id: scopeId, round, attempt_budget: attemptBudget,
|
|
132
|
-
spent, in_flight: inFlight, unattested, green,
|
|
133
|
-
tripped: !green && spent >= attemptBudget,
|
|
134
|
-
attempts,
|
|
135
|
-
};
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
export const ARGV_SPEC = {
|
|
139
|
-
usage: "harness.mjs probe attempts --slug <slug> --scope <scope-id> --round N --attempt-budget N [--cwd <dir>]",
|
|
140
|
-
_: { arity: 0, max: 0, name: "(no positional operands)" },
|
|
141
|
-
slug: { type: "str", required: true },
|
|
142
|
-
scope: { type: "str", required: true },
|
|
143
|
-
round: { type: "int", min: 1, required: true },
|
|
144
|
-
"attempt-budget": { type: "int", min: 1, required: true },
|
|
145
|
-
cwd: { type: "path" },
|
|
146
|
-
};
|
|
147
|
-
|
|
148
|
-
/**
|
|
149
|
-
* Report one scope's attested attempt census for one round.
|
|
150
|
-
*
|
|
151
|
-
* @param {string[]} rawArgv - The subcommand's own arguments (harness.mjs strips the verb words).
|
|
152
|
-
* @returns {void} Exits 0 when the breaker holds, 1 when it has tripped — the shape a caller (or a
|
|
153
|
-
* census citing this row) can branch on without parsing prose.
|
|
154
|
-
*/
|
|
155
|
-
export function cli(rawArgv) {
|
|
156
|
-
const args = runArgs(ARGV_SPEC, rawArgv);
|
|
157
|
-
const cwd = resolve(args.cwd || process.cwd());
|
|
158
|
-
const r = scopeAttempts(cwd, args.slug, args.scope, args.round, args.attemptBudget);
|
|
159
|
-
console.log(JSON.stringify(r));
|
|
160
|
-
process.exit(r.tripped ? 1 : 0);
|
|
161
|
-
}
|