shapeup-sdlc 3.18.2 → 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.
Files changed (141) hide show
  1. package/.claude/settings.local.example.json +2 -3
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/AGENTS.md +115 -56
  4. package/README.md +101 -143
  5. package/SECURITY.md +16 -25
  6. package/agents/orient.md +14 -0
  7. package/agents/qa-edge-hunter.md +13 -0
  8. package/agents/spec-evaluator.md +14 -0
  9. package/agents/task-executor.md +14 -0
  10. package/bin/init.mjs +13 -16
  11. package/bin/lib/grant.mjs +8 -19
  12. package/commands/build.md +9 -14
  13. package/commands/eval.md +3 -3
  14. package/commands/hammer.md +9 -5
  15. package/commands/retro.md +12 -11
  16. package/commands/scopes.md +1 -12
  17. package/commands/ship.md +45 -88
  18. package/commands/wire.md +1 -8
  19. package/hooks/dispatch-receipt.mjs +94 -8
  20. package/hooks/hooks.json +0 -41
  21. package/hooks/lib/decision.mjs +6 -9
  22. package/hooks/lib/tier.mjs +50 -0
  23. package/hooks/sandbox-guard.mjs +140 -64
  24. package/kernel/gate.mjs +203 -22
  25. package/kernel/harness.mjs +20 -67
  26. package/kernel/init/run.mjs +175 -523
  27. package/kernel/lib/contract.mjs +9 -93
  28. package/kernel/lib/floor.mjs +64 -0
  29. package/kernel/lib/paths.mjs +39 -112
  30. package/kernel/order.mjs +157 -0
  31. package/kernel/probe/digest.mjs +2 -38
  32. package/kernel/schemas/domain.schema.json +146 -1125
  33. package/kernel/schemas/work-order.schema.json +8 -4
  34. package/kernel/schemas/work-result.schema.json +1 -1
  35. package/kernel/verify/envelope.mjs +2 -2
  36. package/kernel/verify/skills.mjs +27 -8
  37. package/kernel/verify/t0.mjs +2 -2
  38. package/package.json +4 -2
  39. package/skills/building/SKILL.md +144 -0
  40. package/skills/building/resources/gates.md +76 -0
  41. package/skills/building/resources/guidance.md +23 -0
  42. package/skills/{translator/references/preservation-rules.md → building/resources/intake-preservation.md} +1 -1
  43. package/skills/building/resources/intake.md +157 -0
  44. package/skills/building/resources/orders.md +69 -0
  45. package/skills/{ba-pitch-analyzer/references → building/resources/plan-references}/doc-schemas.md +1 -1
  46. package/skills/{ba-pitch-analyzer/references → building/resources/plan-references}/task-generation.md +13 -13
  47. package/skills/{ba-pitch-analyzer/references → building/resources/plan-references}/test-surface.md +6 -7
  48. package/skills/building/resources/plan-scopes.md +95 -0
  49. package/skills/building/resources/plan-spec.md +102 -0
  50. package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/_index.tmpl.md +1 -1
  51. package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/assess-report.tmpl.md +10 -11
  52. package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/run-state.tmpl.md +4 -4
  53. package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/scope-summary.tmpl.md +2 -2
  54. package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/synthesis.tmpl.md +4 -4
  55. package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/usecase.tmpl.md +2 -2
  56. package/skills/building/resources/plan-wire.md +82 -0
  57. package/skills/building/resources/plan.md +98 -0
  58. package/skills/building/resources/retro-research.md +60 -0
  59. package/skills/building/resources/retro-scan.md +49 -0
  60. package/skills/building/resources/retro.md +225 -0
  61. package/skills/building/resources/rounds.md +78 -0
  62. package/skills/building/resources/stop.md +127 -0
  63. package/skills/orient/SKILL.md +37 -37
  64. package/skills/qa-edge-hunter/SKILL.md +29 -14
  65. package/skills/shapeup/SKILL.md +5 -5
  66. package/skills/shapeup/resources/breadboarding.md +1 -1
  67. package/skills/shapeup/resources/context-compaction.md +5 -5
  68. package/skills/shapeup/resources/shaping.md +1 -1
  69. package/skills/spec-evaluator/SKILL.md +17 -21
  70. package/skills/spec-evaluator/references/dimension-contract.md +1 -1
  71. package/skills/spec-evaluator/references/dimensions/completeness.md +3 -3
  72. package/skills/spec-evaluator/references/dimensions/spec-conformance.md +1 -1
  73. package/skills/spec-evaluator/references/dimensions/test-surface-conformance.md +5 -5
  74. package/skills/task-executor/SKILL.md +11 -15
  75. package/commands/hill.md +0 -10
  76. package/hooks/gate-intake.mjs +0 -109
  77. package/hooks/gate-zerowork.mjs +0 -349
  78. package/hooks/tier-guard.mjs +0 -162
  79. package/kernel/compile.mjs +0 -1419
  80. package/kernel/init/fit.mjs +0 -199
  81. package/kernel/init/run-args.mjs +0 -206
  82. package/kernel/lib/breadboard.mjs +0 -165
  83. package/kernel/probe/attempts.mjs +0 -161
  84. package/kernel/probe/concurrency.mjs +0 -535
  85. package/kernel/probe/eval.mjs +0 -405
  86. package/kernel/probe/hunt.mjs +0 -104
  87. package/kernel/probe/leg.mjs +0 -229
  88. package/kernel/probe/owner.mjs +0 -142
  89. package/kernel/probe/requirements.mjs +0 -328
  90. package/kernel/probe/resume.mjs +0 -1110
  91. package/kernel/probe/rounds.mjs +0 -115
  92. package/kernel/probe/staged.mjs +0 -83
  93. package/kernel/probe/stats.mjs +0 -477
  94. package/kernel/probe/t0.mjs +0 -115
  95. package/kernel/reduce/board.mjs +0 -350
  96. package/kernel/reduce/graph.mjs +0 -482
  97. package/kernel/reduce/hill.mjs +0 -322
  98. package/kernel/reduce/ingest.mjs +0 -767
  99. package/kernel/reduce/leftovers.mjs +0 -159
  100. package/kernel/reduce/ship.mjs +0 -529
  101. package/kernel/reduce/snapshot.mjs +0 -291
  102. package/kernel/reduce/verdict.mjs +0 -172
  103. package/kernel/report/export.mjs +0 -384
  104. package/kernel/report/facts.mjs +0 -234
  105. package/kernel/verify/budget.mjs +0 -153
  106. package/kernel/verify/build.mjs +0 -428
  107. package/kernel/verify/dispatch.mjs +0 -114
  108. package/kernel/verify/spec.mjs +0 -975
  109. package/kernel/verify/trace.mjs +0 -604
  110. package/skills/ba-pitch-analyzer/SKILL.md +0 -204
  111. package/skills/coach/SKILL.md +0 -397
  112. package/skills/hill-chart/SKILL.md +0 -154
  113. package/skills/hill-chart/assets/dashboard.template.html +0 -1432
  114. package/skills/scope-architect/SKILL.md +0 -174
  115. package/skills/scope-hammer/SKILL.md +0 -231
  116. package/skills/solution-architect/SKILL.md +0 -158
  117. package/skills/tech-lead/SKILL.md +0 -151
  118. package/skills/tech-lead/references/gates.md +0 -605
  119. package/skills/tech-lead/references/protocol.md +0 -889
  120. package/skills/tech-lead/references/tiny-lane.md +0 -53
  121. package/skills/tech-lead/workflows/shapeup-run.js +0 -2187
  122. package/skills/translator/SKILL.md +0 -258
  123. /package/skills/{ba-pitch-analyzer/references → building/resources/plan-references}/contract-patterns.md +0 -0
  124. /package/skills/{ba-pitch-analyzer/references → building/resources/plan-references}/ddd-patterns.md +0 -0
  125. /package/skills/{ba-pitch-analyzer/references → building/resources/plan-references}/integration-analysis.md +0 -0
  126. /package/skills/{ba-pitch-analyzer/references → building/resources/plan-references}/ux-behavior-patterns.md +0 -0
  127. /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/api-feasibility.tmpl.md +0 -0
  128. /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/contracts/be-service.contract.tmpl.md +0 -0
  129. /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/contracts/offline-storage.contract.tmpl.md +0 -0
  130. /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/contracts/third-party-api.contract.tmpl.md +0 -0
  131. /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/cross-context/context-map.tmpl.md +0 -0
  132. /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/cross-context/event-choreography.tmpl.md +0 -0
  133. /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/cross-context/migration-plan.tmpl.md +0 -0
  134. /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/cross-context/team-handoff.tmpl.md +0 -0
  135. /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/domain-model.tmpl.md +0 -0
  136. /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/feedback.tmpl.md +0 -0
  137. /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/integration.tmpl.md +0 -0
  138. /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/task-board.tmpl.md +0 -0
  139. /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/task-spike.tmpl.md +0 -0
  140. /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/task.tmpl.md +0 -0
  141. /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/ux-behavior.tmpl.md +0 -0
@@ -0,0 +1,157 @@
1
+ #!/usr/bin/env node
2
+ // harness order — set and retire the pointers the fence reads.
3
+ //
4
+ // harness.mjs order open --slug <slug> --order <path>
5
+ // harness.mjs order close --slug <slug> --status <shipped|escalated|aborted> [--cause <text>]
6
+ //
7
+ // WHY THIS IS A VERB AND NOT A FILE EDIT. The substrate fence defers (allows) every write while no
8
+ // active-order pointer exists, so a pointer the loop forgot to set turns the fence off without a
9
+ // single failing check. `open` names the live order and refuses an order that is not parseable JSON
10
+ // carrying a slug, so a malformed pointer cannot be written. `close` is the other half: it retires
11
+ // both pointers and records the ending — status, cause, timestamp — so a run that ended stops
12
+ // fencing the checkout, and the ending is a row instead of a recollection.
13
+ //
14
+ // A `shipped` ENDING RESTS ON A SIGN-OFF. The ship gate refuses `ship` over a census that did not clear
15
+ // the run, a QA hunt the run owed and never paid, or a worker that ran below the model floor — and none
16
+ // of that held if the loop could write `status: shipped` without crossing the gate at all. So `close
17
+ // --status shipped` reads the gate ledger and refuses unless a Ship Sign-off row of THIS run says `ship`;
18
+ // the close record names the sign-off it rests on. `escalated` and `aborted` need no row: an honest
19
+ // ending is never refused.
20
+ //
21
+ // Exit 0 done · 1 refused (the order is unreadable, or a `shipped` close with no sign-off) · 2 malformed
22
+ // input. `open` also stamps the order's `compiled_at` with the current time.
23
+
24
+ import { mkdirSync, writeFileSync, readFileSync, existsSync, rmSync } from "node:fs";
25
+ import { dirname, join, resolve } from "node:path";
26
+ import { runArgs } from "./lib/argv.mjs";
27
+ import { activeOrder, activeScope, localRoot, insideRunTrace, gates as gatesPath, readRunId } from "./lib/paths.mjs";
28
+ import { validate, SCHEMAS_DIR } from "./verify/envelope.mjs";
29
+
30
+ /** The endings a run may record. */
31
+ export const CLOSE_STATUSES = ["shipped", "escalated", "aborted"];
32
+
33
+ /** The typed argv contract (see `./lib/argv.mjs`). */
34
+ export const ARGV_SPEC = {
35
+ usage: "harness.mjs order open --slug <slug> --order <path> | order close --slug <slug> --status <shipped|escalated|aborted> [--cause <text>]",
36
+ _: { arity: 0, max: 0, name: "(no positional operands)" },
37
+ slug: { type: "str", required: true },
38
+ order: { type: "path" },
39
+ status: { type: "enum", values: CLOSE_STATUSES },
40
+ cause: { type: "str" },
41
+ cwd: { type: "path" },
42
+ };
43
+
44
+ /**
45
+ * Stamp the order with the real time, write the active-order pointer, then read it back.
46
+ *
47
+ * THE STAMP IS THE KERNEL'S, NOT THE LOOP'S. The fence decides an order is answered when its result
48
+ * is at least as new as the order's `compiled_at`, so a time the loop typed by hand and got wrong —
49
+ * a few minutes in the future — keeps the order live after its worker has returned and stalls every
50
+ * write the run makes. A real run did exactly that; the clock is read here instead.
51
+ *
52
+ * @param {string} cwd - Project root.
53
+ * @param {string} slug - Feature slug.
54
+ * @param {string} orderPath - Path to the order the pointer names.
55
+ * @returns {{ok: boolean, reason?: string}} Whether the pointer reads back as written.
56
+ */
57
+ export function openOrder(cwd, slug, orderPath) {
58
+ let order;
59
+ try { order = JSON.parse(readFileSync(orderPath, "utf8")); }
60
+ catch (e) { return { ok: false, reason: `order is not readable JSON: ${e.message}` }; }
61
+ if (!order || typeof order !== "object") return { ok: false, reason: "order is not an object" };
62
+ // The same check the dispatch gate makes, made BEFORE the order is armed: an invalid order that was
63
+ // opened first is live with no way to be edited (the fence freezes it) and no way to be withdrawn.
64
+ const schema = JSON.parse(readFileSync(join(SCHEMAS_DIR, "work-order.schema.json"), "utf8"));
65
+ const { valid, errors } = validate(order, schema);
66
+ if (!valid) return { ok: false, reason: `order fails the order schema, so it was not opened: ${errors.slice(0, 5).join("; ")}` };
67
+ order.compiled_at = new Date().toISOString();
68
+ writeFileSync(orderPath, `${JSON.stringify(order, null, 2)}\n`);
69
+ const p = activeOrder(cwd);
70
+ mkdirSync(dirname(p), { recursive: true });
71
+ writeFileSync(p, `${JSON.stringify({ slug, order_path: orderPath }, null, 2)}\n`);
72
+ const back = JSON.parse(readFileSync(p, "utf8"));
73
+ return back.slug === slug && back.order_path === orderPath
74
+ ? { ok: true }
75
+ : { ok: false, reason: `pointer read back as ${JSON.stringify(back)}` };
76
+ }
77
+
78
+ /**
79
+ * This run's Ship Sign-off row that says `ship`, or null.
80
+ *
81
+ * Read off the gate ledger, keyed by the run id the receipt carries: a sign-off of an earlier run of the
82
+ * same feature is not this run's, and a row that stopped for the PO (`ask`) or was answered otherwise is
83
+ * not a sign-off. With no readable receipt (no run id) any ship row of the slug counts — there is nothing
84
+ * to key by, and refusing would hold a run to a key it never had.
85
+ *
86
+ * @param {string} cwd - Project root.
87
+ * @param {string} slug - Feature slug.
88
+ * @returns {(object|null)} The latest qualifying row, or null when none exists.
89
+ */
90
+ export function shipSignOff(cwd, slug) {
91
+ const runId = readRunId(cwd, slug);
92
+ let text = "";
93
+ try { text = readFileSync(gatesPath(cwd, slug), "utf8"); } catch { return null; }
94
+ let found = null;
95
+ for (const line of text.split("\n")) {
96
+ let row; try { row = JSON.parse(line); } catch { continue; }
97
+ if (row?.gate === "L4" && row.status === "ok" && row.decision === "ship" && (!runId || row.run_id === runId)) found = row;
98
+ }
99
+ return found;
100
+ }
101
+
102
+ /**
103
+ * Retire both pointers and record the ending.
104
+ *
105
+ * @param {string} cwd - Project root.
106
+ * @param {string} slug - Feature slug.
107
+ * @param {string} status - One of {@link CLOSE_STATUSES}.
108
+ * @param {string} [cause] - Why the run ended.
109
+ * @param {object} [extra] - Further fields of the record, e.g. the sign-off a `shipped` ending rests on.
110
+ * @returns {{status: string, cause: (string|null), at: string}} The recorded close.
111
+ */
112
+ export function closeRun(cwd, slug, status, cause, extra = {}) {
113
+ const close = { status, cause: cause || null, at: new Date().toISOString(), ...extra };
114
+ const dir = localRoot(cwd, slug);
115
+ mkdirSync(dir, { recursive: true });
116
+ writeFileSync(join(dir, "close.json"), `${JSON.stringify(close, null, 2)}\n`);
117
+ rmSync(activeOrder(cwd), { force: true });
118
+ rmSync(activeScope(cwd), { force: true });
119
+ return close;
120
+ }
121
+
122
+ /**
123
+ * @param {string[]} rawArgv - `open` or `close`, then flags.
124
+ * @returns {void} Exits with the documented code.
125
+ */
126
+ export function cli(rawArgv) {
127
+ const [action, ...rest] = rawArgv;
128
+ const args = runArgs(ARGV_SPEC, rest);
129
+ const cwd = args.cwd || process.cwd();
130
+ if (insideRunTrace(cwd)) { console.error(`✋ order: ${resolve(cwd)} is inside a run trace (.shapeup/); run it from the project root.`); process.exit(2); }
131
+ if (action === "open") {
132
+ if (!args.order) { console.error("order open: --order <path> is required"); process.exit(2); }
133
+ const r = openOrder(cwd, args.slug, resolve(cwd, args.order));
134
+ if (!r.ok) { console.error(`✋ order open: ${r.reason}`); process.exit(1); }
135
+ console.log(JSON.stringify({ ok: true, slug: args.slug, order: args.order }));
136
+ process.exit(0);
137
+ }
138
+ if (action === "close") {
139
+ if (!args.status) { console.error("order close: --status is required"); process.exit(2); }
140
+ let extra = {};
141
+ if (args.status === "shipped") {
142
+ const row = shipSignOff(cwd, args.slug);
143
+ if (!row) {
144
+ const runId = readRunId(cwd, args.slug);
145
+ console.error(`✋ order close: no Ship Sign-off row says "ship" for ${runId ? `run ${runId}` : `slug ${args.slug}`}, so the run ` +
146
+ `cannot be recorded as shipped. Resolve GATE L4 first (harness.mjs gate --resolve L4 --slug ${args.slug} …), or close it as ` +
147
+ `escalated or aborted, which need no sign-off.`);
148
+ process.exit(1);
149
+ }
150
+ extra = { signed_off_at: row.at ?? null, signed_off_by: row.source ?? null };
151
+ }
152
+ console.log(JSON.stringify({ ok: true, ...closeRun(cwd, args.slug, args.status, args.cause, extra) }));
153
+ process.exit(0);
154
+ }
155
+ console.error("usage: harness.mjs order open|close …");
156
+ process.exit(2);
157
+ }
@@ -1,4 +1,3 @@
1
- #!/usr/bin/env node
2
1
  // AEGIS digester — compresses a failed verification into the triples the next attempt reads.
3
2
  //
4
3
  // Distills raw build/test/Playwright logs into {file, line, core_message} triples so a
@@ -10,9 +9,8 @@
10
9
  // diagnostic that names a file but no line number (a resource-compiler error, for example)
11
10
  // still yields its file — `line` stays null rather than being guessed at.
12
11
  //
13
- // Zero dependencies, zero network — same discipline as oracles/*.
14
-
15
- import { runArgs } from "../lib/argv.mjs";
12
+ // A library, not a subcommand: `verify t0` imports `digest` to compress what a red
13
+ // run printed. Zero dependencies, zero network — same discipline as oracles/*.
16
14
 
17
15
  const PATTERNS = [
18
16
  // Node stack frame: " at fn (path/to/file.js:12:34)" or " at path/to/file.js:12:34"
@@ -118,37 +116,3 @@ export function digest(rawText) {
118
116
  return true;
119
117
  });
120
118
  }
121
-
122
- // --- CLI ---------------------------------------------------------------------
123
- /** The typed argv contract (see `./lib/argv.mjs`). A bare `-`, or nothing, means stdin. */
124
- export const ARGV_SPEC = {
125
- usage: "harness.mjs probe digest [<log-file>|-] (no file → stdin)",
126
- _: { arity: 0, max: 1, name: "log-file" },
127
- };
128
-
129
- /**
130
- * Digest a build log into AEGIS triples on stdout.
131
- *
132
- * @param {string[]} rawArgv - The subcommand's own arguments (harness.mjs strips the verb words).
133
- * @returns {(Promise<void>|void)} Settles when the subcommand has written its output; most paths
134
- * call `process.exit()` with the subcommand's documented code rather than returning.
135
- */
136
- export async function cli(rawArgv) {
137
- const arg = runArgs(ARGV_SPEC, rawArgv)._[0];
138
- let raw;
139
- if (arg && arg !== "-") {
140
- const { readFileSync } = await import("node:fs");
141
- raw = readFileSync(arg, "utf8");
142
- } else {
143
- raw = await new Promise((resolve) => {
144
- let d = "";
145
- process.stdin.on("data", (c) => (d += c));
146
- process.stdin.on("end", () => resolve(d));
147
- process.stdin.on("error", () => resolve(""));
148
- });
149
- }
150
- const triples = digest(raw);
151
- console.log(JSON.stringify(triples, null, 2));
152
- process.exit(0);
153
- }
154
-