shapeup-sdlc 1.6.2

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 (135) hide show
  1. package/.claude/settings.local.example.json +20 -0
  2. package/.claude-plugin/marketplace.json +16 -0
  3. package/.claude-plugin/plugin.json +18 -0
  4. package/.env.shapeup.example +14 -0
  5. package/AGENTS.md +133 -0
  6. package/LICENSE +21 -0
  7. package/README.md +362 -0
  8. package/SECURITY.md +72 -0
  9. package/bin/init.mjs +329 -0
  10. package/commands/build.md +14 -0
  11. package/commands/eval.md +15 -0
  12. package/commands/hammer.md +12 -0
  13. package/commands/orient.md +11 -0
  14. package/commands/qa.md +12 -0
  15. package/commands/retro.md +13 -0
  16. package/commands/scopes.md +14 -0
  17. package/commands/shape.md +12 -0
  18. package/commands/ship.md +53 -0
  19. package/commands/wire.md +11 -0
  20. package/hooks/anti-rationalization.mjs +244 -0
  21. package/hooks/compact-snapshot.mjs +47 -0
  22. package/hooks/gate-deadline.mjs +151 -0
  23. package/hooks/gate-intake.mjs +110 -0
  24. package/hooks/gate-l2.mjs +161 -0
  25. package/hooks/gate-zerowork.mjs +264 -0
  26. package/hooks/hooks.json +118 -0
  27. package/hooks/lib/decision.mjs +183 -0
  28. package/hooks/safety-spine.mjs +296 -0
  29. package/hooks/sandbox-guard.mjs +172 -0
  30. package/hooks/session-rehydrate.mjs +109 -0
  31. package/hooks/slop-cleaner.mjs +176 -0
  32. package/oracles/_shared.mjs +46 -0
  33. package/oracles/http-oracle.mjs +155 -0
  34. package/oracles/index.mjs +36 -0
  35. package/oracles/process-oracle.mjs +146 -0
  36. package/oracles/snapshot-oracle.mjs +119 -0
  37. package/oracles/test-oracle.mjs +138 -0
  38. package/package.json +49 -0
  39. package/skills/advisor-protocol/SKILL.md +171 -0
  40. package/skills/ba-pitch-analyzer/SKILL.md +175 -0
  41. package/skills/ba-pitch-analyzer/assets/templates/_index.tmpl.md +84 -0
  42. package/skills/ba-pitch-analyzer/assets/templates/api-feasibility.tmpl.md +65 -0
  43. package/skills/ba-pitch-analyzer/assets/templates/assess-report.tmpl.md +127 -0
  44. package/skills/ba-pitch-analyzer/assets/templates/contracts/be-service.contract.tmpl.md +62 -0
  45. package/skills/ba-pitch-analyzer/assets/templates/contracts/offline-storage.contract.tmpl.md +92 -0
  46. package/skills/ba-pitch-analyzer/assets/templates/contracts/third-party-api.contract.tmpl.md +66 -0
  47. package/skills/ba-pitch-analyzer/assets/templates/cross-context/context-map.tmpl.md +64 -0
  48. package/skills/ba-pitch-analyzer/assets/templates/cross-context/event-choreography.tmpl.md +77 -0
  49. package/skills/ba-pitch-analyzer/assets/templates/cross-context/migration-plan.tmpl.md +104 -0
  50. package/skills/ba-pitch-analyzer/assets/templates/cross-context/team-handoff.tmpl.md +79 -0
  51. package/skills/ba-pitch-analyzer/assets/templates/domain-model.tmpl.md +79 -0
  52. package/skills/ba-pitch-analyzer/assets/templates/feedback.tmpl.md +87 -0
  53. package/skills/ba-pitch-analyzer/assets/templates/integration.tmpl.md +64 -0
  54. package/skills/ba-pitch-analyzer/assets/templates/run-state.tmpl.md +77 -0
  55. package/skills/ba-pitch-analyzer/assets/templates/scope-summary.tmpl.md +105 -0
  56. package/skills/ba-pitch-analyzer/assets/templates/synthesis.tmpl.md +215 -0
  57. package/skills/ba-pitch-analyzer/assets/templates/task-board.tmpl.md +35 -0
  58. package/skills/ba-pitch-analyzer/assets/templates/task-spike.tmpl.md +86 -0
  59. package/skills/ba-pitch-analyzer/assets/templates/task.tmpl.md +84 -0
  60. package/skills/ba-pitch-analyzer/assets/templates/usecase.tmpl.md +105 -0
  61. package/skills/ba-pitch-analyzer/assets/templates/ux-behavior.tmpl.md +65 -0
  62. package/skills/ba-pitch-analyzer/references/contract-patterns.md +152 -0
  63. package/skills/ba-pitch-analyzer/references/ddd-patterns.md +173 -0
  64. package/skills/ba-pitch-analyzer/references/doc-schemas.md +275 -0
  65. package/skills/ba-pitch-analyzer/references/integration-analysis.md +152 -0
  66. package/skills/ba-pitch-analyzer/references/task-generation.md +623 -0
  67. package/skills/ba-pitch-analyzer/references/test-surface.md +102 -0
  68. package/skills/ba-pitch-analyzer/references/ux-behavior-patterns.md +269 -0
  69. package/skills/ba-pitch-analyzer/scripts/board-derive.mjs +241 -0
  70. package/skills/ba-pitch-analyzer/scripts/spec-lint.mjs +239 -0
  71. package/skills/coach/SKILL.md +202 -0
  72. package/skills/orient/SKILL.md +262 -0
  73. package/skills/qa-edge-hunter/SKILL.md +369 -0
  74. package/skills/scope-architect/SKILL.md +111 -0
  75. package/skills/scope-hammer/SKILL.md +186 -0
  76. package/skills/shapeup/SKILL.md +403 -0
  77. package/skills/shapeup/resources/breadboard-reflection.md +88 -0
  78. package/skills/shapeup/resources/breadboarding.md +334 -0
  79. package/skills/shapeup/resources/context-compaction.md +240 -0
  80. package/skills/shapeup/resources/framing-doc.md +92 -0
  81. package/skills/shapeup/resources/kickoff-doc.md +95 -0
  82. package/skills/shapeup/resources/shaping.md +194 -0
  83. package/skills/shapeup/resources/spike.md +86 -0
  84. package/skills/solution-architect/SKILL.md +129 -0
  85. package/skills/spec-evaluator/README.md +93 -0
  86. package/skills/spec-evaluator/SKILL.md +213 -0
  87. package/skills/spec-evaluator/references/anti-leniency.md +50 -0
  88. package/skills/spec-evaluator/references/dimension-contract.md +126 -0
  89. package/skills/spec-evaluator/references/dimensions/_registry.md +40 -0
  90. package/skills/spec-evaluator/references/dimensions/completeness.md +102 -0
  91. package/skills/spec-evaluator/references/dimensions/integration.md +129 -0
  92. package/skills/spec-evaluator/references/dimensions/performance.md +48 -0
  93. package/skills/spec-evaluator/references/dimensions/security.md +60 -0
  94. package/skills/spec-evaluator/references/dimensions/spec-conformance.md +134 -0
  95. package/skills/spec-evaluator/references/dimensions/tdd-surface.md +110 -0
  96. package/skills/spec-evaluator/references/dimensions/test-surface-conformance.md +100 -0
  97. package/skills/spec-evaluator/references/probing.md +177 -0
  98. package/skills/spec-evaluator/references/report-schema.md +101 -0
  99. package/skills/spec-evaluator/references/verdict-ledger.md +92 -0
  100. package/skills/spec-evaluator/scripts/verdict-ledger.mjs +166 -0
  101. package/skills/task-executor/SKILL.md +194 -0
  102. package/skills/tech-lead/README.md +71 -0
  103. package/skills/tech-lead/SKILL.md +459 -0
  104. package/skills/tech-lead/references/delegation.md +254 -0
  105. package/skills/tech-lead/references/gates.md +379 -0
  106. package/skills/tech-lead/references/invocation.md +45 -0
  107. package/skills/tech-lead/references/ledger-schema.md +214 -0
  108. package/skills/tech-lead/references/round-protocol.md +184 -0
  109. package/skills/tech-lead/references/state-model.md +66 -0
  110. package/skills/tech-lead/references/tiny-lane.md +52 -0
  111. package/skills/tech-lead/schemas/domain.schema.json +2294 -0
  112. package/skills/tech-lead/schemas/gate-answers.schema.json +92 -0
  113. package/skills/tech-lead/schemas/work-order.schema.json +21 -0
  114. package/skills/tech-lead/schemas/work-result.schema.json +40 -0
  115. package/skills/tech-lead/scripts/aegis-digest.mjs +124 -0
  116. package/skills/tech-lead/scripts/budget-check.mjs +156 -0
  117. package/skills/tech-lead/scripts/compile-order.mjs +518 -0
  118. package/skills/tech-lead/scripts/fit-check.mjs +196 -0
  119. package/skills/tech-lead/scripts/gate-answers.mjs +338 -0
  120. package/skills/tech-lead/scripts/ingest-result.mjs +270 -0
  121. package/skills/tech-lead/scripts/init-run.mjs +326 -0
  122. package/skills/tech-lead/scripts/lib/argv.mjs +224 -0
  123. package/skills/tech-lead/scripts/lib/contract-md.mjs +481 -0
  124. package/skills/tech-lead/scripts/lib/is-main.mjs +82 -0
  125. package/skills/tech-lead/scripts/lib/paths.mjs +278 -0
  126. package/skills/tech-lead/scripts/lib/ratchet-tree.mjs +112 -0
  127. package/skills/tech-lead/scripts/run-snapshot.mjs +269 -0
  128. package/skills/tech-lead/scripts/ship-report.mjs +275 -0
  129. package/skills/tech-lead/scripts/stats.mjs +423 -0
  130. package/skills/tech-lead/scripts/t0-verify.mjs +470 -0
  131. package/skills/tech-lead/scripts/trace-lint.mjs +367 -0
  132. package/skills/tech-lead/scripts/validate-envelope.mjs +283 -0
  133. package/skills/translator/README.md +66 -0
  134. package/skills/translator/SKILL.md +258 -0
  135. package/skills/translator/references/preservation-rules.md +102 -0
@@ -0,0 +1,119 @@
1
+ #!/usr/bin/env node
2
+ // `snapshot` oracle for the evaluation contract (Stage G, step 4b of the audit).
3
+ //
4
+ // Deliverable: a generator or a pure refactor — something whose acceptance is "produces exactly
5
+ // this output". The oracle runs the deliverable, captures its stdout, and diffs it against a
6
+ // committed *golden* file. An empty diff is PASS; any difference is FAIL with the unified diff as
7
+ // evidence. This is the natural oracle for "the refactor changed nothing observable" and for
8
+ // code/text generators.
9
+ //
10
+ // Invariants (carried from the evaluator's design):
11
+ // • Probe behavior, not code presence — the verdict cites the diff of observed output.
12
+ // • Absence of evidence = FAIL — a probe that cannot run, or a missing golden, FAILs.
13
+ // • One verdict per criterion.
14
+ //
15
+ // Contract shape:
16
+ // { "oracle": "snapshot", "criteria": [
17
+ // { "id": "S1", "desc": "greets by name",
18
+ // "probe": { "argv": ["Ada"], "stdin": "" },
19
+ // "golden": "greet.Ada.golden.txt" } ] }
20
+ // `golden` is resolved relative to the contract file (baseDir). Trailing whitespace on each
21
+ // line and a single trailing newline are normalized so a benign EOL diff is not a false FAIL.
22
+ //
23
+ // Library use: import { runContract } from ".../snapshot-oracle.mjs"
24
+ // CLI use: node snapshot-oracle.mjs <contract.json> "<command to run the deliverable>"
25
+ // exit 0 = all PASS, 1 = ≥1 FAIL, 2 = usage/contract error.
26
+
27
+ import { spawnSync } from "node:child_process";
28
+ import { readFileSync, existsSync } from "node:fs";
29
+ import { dirname, isAbsolute, join } from "node:path";
30
+ import { CRASH_RE, formatReport } from "./_shared.mjs";
31
+ import { isMain } from "../skills/tech-lead/scripts/lib/is-main.mjs";
32
+
33
+ // Normalize so trailing spaces and final-newline differences never cause a spurious FAIL.
34
+ function normalize(s) {
35
+ return s.replace(/\r\n/g, "\n").split("\n").map((l) => l.replace(/[ \t]+$/, "")).join("\n").replace(/\n+$/, "\n");
36
+ }
37
+
38
+ // Minimal line-level unified diff (no deps). Returns "" when identical.
39
+ function unifiedDiff(expected, actual) {
40
+ const a = normalize(expected).split("\n");
41
+ const b = normalize(actual).split("\n");
42
+ if (a.join("\n") === b.join("\n")) return "";
43
+ const lines = ["--- golden", "+++ actual"];
44
+ const max = Math.max(a.length, b.length);
45
+ for (let i = 0; i < max; i++) {
46
+ if (a[i] === b[i]) { if (a[i] !== undefined) lines.push(` ${a[i]}`); }
47
+ else {
48
+ if (a[i] !== undefined) lines.push(`- ${a[i]}`);
49
+ if (b[i] !== undefined) lines.push(`+ ${b[i]}`);
50
+ }
51
+ }
52
+ return lines.join("\n");
53
+ }
54
+
55
+ function spawnProbe(cmd, probe) {
56
+ const [bin, ...baseArgs] = String(cmd).split(/\s+/).filter(Boolean);
57
+ const res = spawnSync(bin, [...baseArgs, ...(probe.argv || [])], {
58
+ encoding: "utf8",
59
+ cwd: probe.cwd,
60
+ timeout: probe.timeout_ms || 10_000,
61
+ input: probe.stdin,
62
+ });
63
+ return {
64
+ code: res.status,
65
+ stdout: res.stdout || "",
66
+ combined: (res.stdout || "") + (res.stderr || ""),
67
+ spawnError: res.error?.message,
68
+ };
69
+ }
70
+
71
+ export function runContract({ cmd, criteria, baseDir = "." }) {
72
+ const results = [];
73
+ let fails = 0;
74
+ for (const c of criteria) {
75
+ let g;
76
+ try {
77
+ if (!c.golden) throw new Error("criterion has no `golden` file");
78
+ const goldenPath = isAbsolute(c.golden) ? c.golden : join(baseDir, c.golden);
79
+ if (!existsSync(goldenPath)) throw new Error(`golden file not found: ${c.golden}`);
80
+ const golden = readFileSync(goldenPath, "utf8");
81
+ const r = spawnProbe(cmd, c.probe || {});
82
+ if (r.spawnError) throw new Error(`could not run deliverable: ${r.spawnError}`);
83
+ if (CRASH_RE.test(r.combined)) {
84
+ g = { pass: false, evidence: `deliverable crashed (stack trace / panic in output): ${JSON.stringify(r.combined.trim().slice(0, 120))}` };
85
+ } else {
86
+ const diff = unifiedDiff(golden, r.stdout);
87
+ g = diff
88
+ ? { pass: false, evidence: `output differs from golden (exit ${r.code}):\n${diff}` }
89
+ : { pass: true, evidence: `identical to golden (${normalize(golden).split("\n").filter(Boolean).length} lines, exit ${r.code})` };
90
+ }
91
+ } catch (e) {
92
+ g = { pass: false, evidence: `probe threw: ${e.message}` }; // absence of evidence = FAIL
93
+ }
94
+ if (!g.pass) fails++;
95
+ results.push({ id: c.id, desc: c.desc, ...g });
96
+ }
97
+ return { fails, results };
98
+ }
99
+
100
+ export { formatReport };
101
+
102
+ // --- CLI entry ---------------------------------------------------------------
103
+ if (isMain(import.meta.url)) {
104
+ const contractPath = process.argv[2];
105
+ const cmd = process.argv[3];
106
+ if (!contractPath || !cmd) {
107
+ console.error('usage: node snapshot-oracle.mjs <contract.json> "<command to run the deliverable>"');
108
+ process.exit(2);
109
+ }
110
+ let contract;
111
+ try { contract = JSON.parse(readFileSync(contractPath, "utf8")); }
112
+ catch (e) { console.error(`cannot read contract ${contractPath}: ${e.message}`); process.exit(2); }
113
+ if (!Array.isArray(contract.criteria) || contract.criteria.length === 0) {
114
+ console.error(`contract ${contractPath} has no criteria[]`); process.exit(2);
115
+ }
116
+ const summary = runContract({ cmd, criteria: contract.criteria, baseDir: dirname(contractPath) });
117
+ console.log(formatReport(`snapshot oracle: ${contractPath}`, summary));
118
+ process.exit(summary.fails === 0 ? 0 : 1);
119
+ }
@@ -0,0 +1,138 @@
1
+ #!/usr/bin/env node
2
+ // `test` oracle for the evaluation contract (Stage G, step 4a of the audit).
3
+ //
4
+ // Deliverable: a library / module whose acceptance is "its own test suite is green".
5
+ // The oracle runs the project's test command and grades the OBSERVED suite result —
6
+ // exit code, executed-test count, and failing-test names — never the source.
7
+ //
8
+ // Why this oracle exists: a CLI is judged by `process`, a web app by `ui`, but a *library*
9
+ // has no runtime surface to drive — its contract is its tests. (probing.md "TDD-1": a suite
10
+ // that runs zero tests is NOT green, so `min_tests` defaults to 1.)
11
+ //
12
+ // Invariants (carried from the evaluator's design):
13
+ // • Probe behavior, not code presence — the verdict cites the suite's own output.
14
+ // • Absence of evidence = FAIL — a suite that cannot run, or runs nothing, FAILs.
15
+ // • One verdict per criterion.
16
+ //
17
+ // Contract shape:
18
+ // { "oracle": "test", "criteria": [
19
+ // { "id": "T1", "desc": "suite green",
20
+ // "probe": { "cmd": "node --test ./mathx.test.mjs", "cwd": "." },
21
+ // "expect": { "exit": "==0", "min_tests": 1, "no_failures": true } } ] }
22
+ //
23
+ // `cmd` resolution: criterion.probe.cmd overrides the contract/CLI default. The parser
24
+ // understands node:test TAP (`# pass/# fail/# tests`, `ok`/`not ok`) and mocha-style
25
+ // "N passing / M failing"; falls back to counting TAP `ok`/`not ok` lines.
26
+ //
27
+ // Library use: import { runContract } from ".../test-oracle.mjs"
28
+ // CLI use: node test-oracle.mjs <contract.json> ["default test command"]
29
+ // exit 0 = all PASS, 1 = ≥1 FAIL, 2 = usage/contract error.
30
+
31
+ import { spawnSync } from "node:child_process";
32
+ import { readFileSync } from "node:fs";
33
+ import { matchNum, toRegExp, formatReport } from "./_shared.mjs";
34
+ import { isMain } from "../skills/tech-lead/scripts/lib/is-main.mjs";
35
+
36
+ // Parse common test-runner output into { total, pass, fail, failing[] }.
37
+ function parseSuite(out) {
38
+ const r = { total: null, pass: null, fail: null, failing: [] };
39
+
40
+ // node:test summary lines — TAP reporter prefixes with `#`, the default spec reporter with `ℹ`.
41
+ const mt = out.match(/^[#ℹ]\s*tests\s+(\d+)/m);
42
+ const mp = out.match(/^[#ℹ]\s*pass\s+(\d+)/m);
43
+ const mf = out.match(/^[#ℹ]\s*fail\s+(\d+)/m);
44
+ if (mt) r.total = Number(mt[1]);
45
+ if (mp) r.pass = Number(mp[1]);
46
+ if (mf) r.fail = Number(mf[1]);
47
+
48
+ // mocha / jest-ish summary
49
+ if (r.pass === null) { const m = out.match(/(\d+)\s+passing/); if (m) r.pass = Number(m[1]); }
50
+ if (r.fail === null) { const m = out.match(/(\d+)\s+failing/); if (m) r.fail = Number(m[1]); }
51
+
52
+ // failing test names from TAP `not ok N - name`
53
+ for (const m of out.matchAll(/^not ok\s+\d+\s+-\s+(.+)$/gm)) r.failing.push(m[1].trim());
54
+
55
+ // Fallback: count raw TAP result lines if no summary was emitted.
56
+ if (r.total === null) {
57
+ const oks = (out.match(/^ok\s+\d+/gm) || []).length;
58
+ const noks = (out.match(/^not ok\s+\d+/gm) || []).length;
59
+ if (oks + noks > 0) { r.total = oks + noks; r.pass = oks; r.fail = noks; }
60
+ }
61
+ return r;
62
+ }
63
+
64
+ function runSuite(cmd, probe) {
65
+ const [bin, ...baseArgs] = String(cmd).split(/\s+/).filter(Boolean);
66
+ const res = spawnSync(bin, [...baseArgs, ...(probe.argv || [])], {
67
+ encoding: "utf8",
68
+ cwd: probe.cwd,
69
+ timeout: probe.timeout_ms || 60_000,
70
+ });
71
+ const out = (res.stdout || "") + (res.stderr || "");
72
+ return { code: res.status, out, spawnError: res.error?.message, parsed: parseSuite(out) };
73
+ }
74
+
75
+ function grade(expect, r) {
76
+ const reasons = [];
77
+ let pass = true;
78
+ const p = r.parsed;
79
+
80
+ if (r.spawnError) { pass = false; reasons.push(`suite did not run: ${r.spawnError}`); }
81
+ if (!matchNum(expect.exit ?? "==0", r.code)) { pass = false; reasons.push(`suite exit ${r.code} ≠ expected ${expect.exit ?? "==0"}`); }
82
+
83
+ const minTests = expect.min_tests ?? 1;
84
+ if (p.total === null) { pass = false; reasons.push("no test results parsed (suite produced no recognizable output)"); }
85
+ else if (p.total < minTests) { pass = false; reasons.push(`only ${p.total} test(s) ran, need ≥${minTests}`); }
86
+
87
+ if ((expect.no_failures ?? true) && (p.fail ?? 0) > 0) {
88
+ pass = false; reasons.push(`${p.fail} failing: ${p.failing.join(", ") || "(names unparsed)"}`);
89
+ }
90
+ if (expect.stdout !== undefined && !toRegExp(expect.stdout).test(r.out)) {
91
+ pass = false; reasons.push(`output does not match ${expect.stdout}`);
92
+ }
93
+
94
+ const evidence =
95
+ `suite exit ${r.code}; tests=${p.total ?? "?"} pass=${p.pass ?? "?"} fail=${p.fail ?? "?"}` +
96
+ (p.failing.length ? `; failing=[${p.failing.join("; ")}]` : "") +
97
+ (reasons.length ? ` [${reasons.join("; ")}]` : "");
98
+ return { pass, evidence };
99
+ }
100
+
101
+ export function runContract({ cmd, criteria }) {
102
+ const results = [];
103
+ let fails = 0;
104
+ for (const c of criteria) {
105
+ let g;
106
+ try {
107
+ const useCmd = (c.probe && c.probe.cmd) || cmd;
108
+ if (!useCmd) throw new Error("no test command (criterion.probe.cmd or contract default)");
109
+ g = grade(c.expect || {}, runSuite(useCmd, c.probe || {}));
110
+ } catch (e) {
111
+ g = { pass: false, evidence: `probe threw: ${e.message}` }; // absence of evidence = FAIL
112
+ }
113
+ if (!g.pass) fails++;
114
+ results.push({ id: c.id, desc: c.desc, ...g });
115
+ }
116
+ return { fails, results };
117
+ }
118
+
119
+ export { formatReport };
120
+
121
+ // --- CLI entry ---------------------------------------------------------------
122
+ if (isMain(import.meta.url)) {
123
+ const contractPath = process.argv[2];
124
+ const defaultCmd = process.argv[3];
125
+ if (!contractPath) {
126
+ console.error('usage: node test-oracle.mjs <contract.json> ["default test command"]');
127
+ process.exit(2);
128
+ }
129
+ let contract;
130
+ try { contract = JSON.parse(readFileSync(contractPath, "utf8")); }
131
+ catch (e) { console.error(`cannot read contract ${contractPath}: ${e.message}`); process.exit(2); }
132
+ if (!Array.isArray(contract.criteria) || contract.criteria.length === 0) {
133
+ console.error(`contract ${contractPath} has no criteria[]`); process.exit(2);
134
+ }
135
+ const summary = runContract({ cmd: defaultCmd || contract.cmd, criteria: contract.criteria });
136
+ console.log(formatReport(`test oracle: ${contractPath}`, summary));
137
+ process.exit(summary.fails === 0 ? 0 : 1);
138
+ }
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "shapeup-sdlc",
3
+ "version": "1.6.2",
4
+ "description": "Shape Up for coding agents — with gates the agent can't talk its way past. Harness for Claude Code, compiled to Cursor, Antigravity and Codex.",
5
+ "bin": {
6
+ "shapeup-sdlc": "bin/init.mjs"
7
+ },
8
+ "files": [
9
+ "bin/",
10
+ "skills/",
11
+ "!skills/**/evals/**",
12
+ "hooks/",
13
+ "commands/",
14
+ "oracles/",
15
+ ".claude-plugin/",
16
+ "AGENTS.md",
17
+ ".env.shapeup.example",
18
+ ".claude/settings.local.example.json",
19
+ "SECURITY.md"
20
+ ],
21
+ "repository": {
22
+ "type": "git",
23
+ "url": "git+https://github.com/nguyenvanphituoc/shapeup-sdlc-plugin.git"
24
+ },
25
+ "homepage": "https://github.com/nguyenvanphituoc/shapeup-sdlc-plugin#readme",
26
+ "bugs": {
27
+ "url": "https://github.com/nguyenvanphituoc/shapeup-sdlc-plugin/issues"
28
+ },
29
+ "publishConfig": {
30
+ "access": "public"
31
+ },
32
+ "engines": {
33
+ "node": ">=18"
34
+ },
35
+ "scripts": {
36
+ "test": "node tests/structural.mjs",
37
+ "demo": "node tools/demo/record-demo.mjs",
38
+ "distribute": "node tools/distribute.js"
39
+ },
40
+ "keywords": [
41
+ "shapeup",
42
+ "sdlc",
43
+ "cursor",
44
+ "antigravity",
45
+ "claude-code"
46
+ ],
47
+ "author": "Liberty Nguyen",
48
+ "license": "MIT"
49
+ }
@@ -0,0 +1,171 @@
1
+ ---
2
+ name: advisor-protocol
3
+ description: "Use this skill whenever a harness worker (task-executor, scope-architect) hits a decision it cannot make alone during Build Vertically — a design decision, a spec ambiguity, or a request to write outside its scope's substrate — and needs it adjudicated under a budget instead of guessed or asked ad hoc. Trigger on: \"escalate this decision\", \"ESCALATE\", \"adjudicate this ambiguity\", \"ask the advisor\", \"substrate expansion request\", \"resolve this design decision within budget\", \"how many escalations does this scope have left\". Also triggers when tech-lead needs to answer a worker's structured ESCALATE return during a build round."
4
+ ---
5
+
6
+ # Advisor Protocol (ESCALATE grammar + budgets)
7
+
8
+ The mechanism behind Shape Up's "advisor, not micromanager" posture (design spec v1.1 DD-1,
9
+ DD-8). A worker mid-attempt hits something it genuinely cannot decide alone — not "what should
10
+ I name this variable" (that's Principle A, resolved silently or at the worker's own gate), but
11
+ a decision whose wrong guess is expensive: a design trade-off the spec left open, a spec
12
+ ambiguity that changes behavior, or a file the worker needs to touch outside its scope's
13
+ `allowed_file_substrate`. Instead of guessing or opening an unbounded chat with the PO, the
14
+ worker emits one structured `ESCALATE` return and this skill adjudicates it.
15
+
16
+ **Why this exists as its own skill, not inline PO chat.** Zero-memory handoff (design spec
17
+ §3.6) means every attempt gets a *fresh* context — no chat history. An answer given once must
18
+ survive every future reset for that scope. This skill is what turns a transient Q&A into a
19
+ persisted decision: it writes the answer to the round-ledger (committed, Tier A) the moment
20
+ it's made, and every future brief for that scope reads it back. Escalation memory lives in
21
+ files, not in chat (DD-8).
22
+
23
+ ---
24
+
25
+ ## The ESCALATE grammar
26
+
27
+ A worker never asks a free-form question mid-attempt. It returns a structured block and stops
28
+ work on the blocked AC/file until an answer comes back:
29
+
30
+ ```yaml
31
+ ESCALATE:
32
+ scope_id: cart-creation
33
+ round: 2
34
+ attempt: 3
35
+ kind: design-decision | spec-ambiguity | substrate-expansion
36
+ question: "Contract leaves cart-total rounding unspecified — round half-up or banker's rounding?"
37
+ options: ["round half-up (matches existing order-total code)", "banker's rounding (matches contract's other money fields)"]
38
+ default_if_silent: "round half-up" # optional — see --unattended below
39
+ ```
40
+
41
+ Three kinds, three different resolution paths (below). `default_if_silent` is optional — a
42
+ worker proposes it when it has a reasonable, low-risk fallback; the advisor is never forced to
43
+ accept it.
44
+
45
+ ---
46
+
47
+ ## Budget
48
+
49
+ **≤3 ESCALATEs per scope per round** (design spec §3.3). Counted per `scope_id` + `round`, reset
50
+ each new round. The budget exists so a struggling scope surfaces as *stuck* (routed to the
51
+ hill's stuck-split rule, ≥3 rounds at the same position → forced scope-architect split order) rather than
52
+ draining PO attention one question at a time.
53
+
54
+ ```
55
+ 1st–3rd ESCALATE this scope/round → adjudicate normally (below).
56
+ 4th+ → do NOT ask again. Apply the most conservative resolution
57
+ (narrowest scope, no substrate expansion, closest precedent)
58
+ and flag it as a GATE-H hammer proposal: "scope exceeded its
59
+ escalation budget — question N unresolved, applied [X]".
60
+ The worker's attempt continues with that resolution.
61
+ ```
62
+
63
+ Exceeding budget is never a hard stop — Build Vertically must keep moving; it's a signal that
64
+ this scope needs GATE H's attention, not a excuse to freeze the round.
65
+
66
+ ---
67
+
68
+ ## Adjudication (in order — cheapest resolution wins)
69
+
70
+ ```
71
+ 1. Precedent check (free, no PO time):
72
+ Search this run's round-ledger.md "Decisions" section (this scope AND sibling scopes) and
73
+ shapeup/knowledge-base/*.md for an already-answered question that is the same or a
74
+ clear superset of this one. Found → reuse verbatim, log "resolved by precedent: [ref]",
75
+ do NOT count against budget (a repeat question is a zero-memory artifact, not a new decision).
76
+
77
+ 2. kind: substrate-expansion:
78
+ Never silently approved. Present the requested path(s) + why the worker says it needs them.
79
+ PO/TL approves → dispatch a scope-architect remap order to add the path to the scope contract's
80
+ `shared_substrate` (never hand-edit the contract — `ba` is its sole writer, F.5). PO/TL
81
+ declines → worker re-plans within its existing substrate; log the decline as a decision too
82
+ (prevents re-asking).
83
+
84
+ 3. kind: design-decision | spec-ambiguity, interactive/--auto:
85
+ Print the ESCALATE block verbatim + budget remaining for this scope/round. Ask (max 1):
86
+ pick an option / provide a different answer / defer to default_if_silent if offered.
87
+ Never answer on the PO's behalf — a wrong silent guess here is exactly what zero-memory
88
+ handoff makes expensive to unwind later.
89
+
90
+ 4. --unattended (no PO available):
91
+ default_if_silent present → apply it, log "auto-resolved (default, unattended)".
92
+ No default offered → apply the most conservative option (narrowest scope / least
93
+ irreversible) and flag it as a GATE-H hammer proposal for PO review before ship — the
94
+ run must not block, but an unattended guess is never allowed to hide from the PO forever.
95
+ ```
96
+
97
+ ---
98
+
99
+ ## Persistence — the decision must survive a reset
100
+
101
+ The instant an ESCALATE is answered (any path above), append one row to the run's committed
102
+ `round-ledger.md` "Decisions" section — never batch it for later, never keep it only in the
103
+ current session (a crash before the next promotion point would lose it):
104
+
105
+ ```
106
+ | Round | Scope | Kind | Question | Answer | Resolved by |
107
+ |-------|-------|------|----------|--------|-------------|
108
+ | 2 | cart-creation | design-decision | cart-total rounding | round half-up | PO (interactive) |
109
+ ```
110
+
111
+ Every subsequent isolated brief for that scope (task-executor's zero-memory handoff, design
112
+ spec §3.6) includes the full decisions table for its `scope_id` — this is how an answer given
113
+ once in round 2 is still known in round 5's fresh-context attempt without replaying any chat
114
+ history.
115
+
116
+ ---
117
+
118
+ ## Envelope contract — the domain layer
119
+
120
+ Orchestrated, this skill is dispatched like every worker: a **WorkOrder** in (`--order <path>`,
121
+ operation `adjudicate`), a **WorkResult** out. The standalone flags below map 1:1 onto the
122
+ payload fields registered for this worker in the central domain registry
123
+ (`skills/tech-lead/schemas/domain.schema.json`, `x-payload-by-worker`):
124
+
125
+ | Payload field | Standalone flag | Meaning |
126
+ |---|---|---|
127
+ | `payload.ledger` | `--ledger` | The run's committed `round-ledger.md` — every answer persists here |
128
+ | `payload.escalate` | `--escalate` | The worker's ESCALATE block to adjudicate (the `EscalateBlock` grammar above) |
129
+ | `payload.scope_id` | `--scope` | The scope the budget is counted against |
130
+ | `payload.round` | `--round` | The round the budget/decision is counted against |
131
+
132
+ The WorkResult may carry only `files_touched`, `artifacts`, `assumptions`, `deviations`
133
+ (`x-result-by-worker`): the adjudicated Decision itself persists to the committed round-ledger,
134
+ never to the envelope, so it survives every zero-memory reset.
135
+
136
+ ---
137
+
138
+ ## Invocation
139
+
140
+ ```bash
141
+ # Adjudicate one ESCALATE return from a worker (typical: tech-lead calls this mid-round)
142
+ /advisor-protocol --ledger shapeup/checkout-vnpay/round-ledger.md --escalate '<ESCALATE yaml>'
143
+
144
+ # Check remaining budget for a scope this round (worker or tech-lead, before emitting ESCALATE)
145
+ /advisor-protocol --budget --scope cart-creation --round 2 --ledger shapeup/checkout-vnpay/round-ledger.md
146
+
147
+ # Headless run — no PO available; apply defaults / conservative fallback, flag the rest for GATE H
148
+ /advisor-protocol --unattended --ledger ... --escalate '<ESCALATE yaml>'
149
+ ```
150
+
151
+ ### Flags
152
+ | Flag | Effect |
153
+ |------|--------|
154
+ | `--ledger <path>` | The run's committed `round-ledger.md` (decisions persist here) |
155
+ | `--escalate <yaml\|path>` | The worker's ESCALATE block to adjudicate |
156
+ | `--budget --scope <id> --round <N>` | Report remaining ESCALATE budget for a scope this round, no adjudication |
157
+ | `--unattended` | No PO available — apply defaults/conservative fallback per rule 4 above |
158
+
159
+ ---
160
+
161
+ ## Hard Rules (never override without explicit user instruction)
162
+
163
+ | Rule | Rationale |
164
+ |------|-----------|
165
+ | A worker never guesses a design decision or spec ambiguity silently | The whole point of ESCALATE — wrong silent guesses are the expensive failure mode zero-memory handoff amplifies |
166
+ | Substrate-expansion is never auto-approved | PA3 (cross-scope contamination) exists precisely because agents self-justify "just this once" writes |
167
+ | Budget is ≤3/scope/round; exceeding it never blocks the round | Signals a stuck scope to GATE L2's stuck-split rule instead of freezing Build Vertically |
168
+ | Every answer is persisted to the committed round-ledger the instant it's given | Zero-memory handoff means the *only* place a decision survives is a file, not a session |
169
+ | Precedent reuse never counts against budget | A repeat question is a zero-memory artifact, not a new decision — don't penalize the worker for context loss |
170
+ | An unattended conservative resolution is always flagged for GATE H | An automated guess must stay visible to the PO before ship, never silently absorbed |
171
+ | This skill never designs, builds, or judges | Advisor, not a fifth worker — it adjudicates, it does not decide scope or verify code |
@@ -0,0 +1,175 @@
1
+ ---
2
+ name: ba-pitch-analyzer
3
+ description: "Use this skill whenever a user provides a product requirement, pitch, or feature description and wants it broken down into structured, executable development tasks. Triggers on: \"analyze this pitch\", \"break this into tasks\", \"generate tasks from requirement\", \"act as BA\", \"create spec from PRD\", \"turn this into dev tasks\", or any request to decompose a feature into DDD-structured documents and tasks; also on Shape Up, bounded context, domain model, or use cases, and on a tech-lead --order dispatch. Produces a linked pitch → domain model → use cases → tasks document tree with BDD scenarios and a derived Test Surface."
4
+ ---
5
+
6
+ # BA Pitch Analyzer (spec-analyzer, pure worker v4.0)
7
+
8
+ **Decompose the pitch into a spec a machine can build and a judge can grade — invent nothing.**
9
+
10
+ Converts a Shape Up pitch (or any product requirement) into a fully linked document tree:
11
+ `_index` → `domain-model` → `ux-behavior` → `usecases/` → `integration` → `tasks/` — Obsidian
12
+ wikilinks + shared frontmatter taxonomy, navigable from pitch to atomic task.
13
+
14
+ You are the *planner* in a planner → doer → judge harness, and a pure worker: the order tells
15
+ you which operation to run and which files you may write; you return everything else as data.
16
+ You keep **no state** — no run-state.md, no pitch-hash cache, no counters. Same order in →
17
+ same artifacts out.
18
+
19
+ ---
20
+
21
+ ## Input contract — the WorkOrder
22
+
23
+ Invoked as `--order <path>`. Fields you may rely on (absent = unknown; surface it, never guess):
24
+
25
+ | Field | What it is |
26
+ |---|---|
27
+ | `operation` | `analyze` (pitch → full spec tree + board) · `generate-board` (regenerate the LOCAL board from the committed spec) · `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
+ | `payload.pitch` | The pitch/PRD path (analyze) |
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 / one `escalates[]` entry |
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
+ | `payload.spec_folder` / `payload.feature` | Where the committed tree lives / the slug |
33
+ | `payload.discovered_ledger` | (reconcile) the ledger whose raw `[+]`/`~` lines you fold in |
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[]`/`escalates[]` instead |
37
+
38
+ ---
39
+
40
+ ## Core craft — the analysis pipeline (operation: analyze)
41
+
42
+ Phases, each with a checkpoint (pause only per `interaction`). Read the reference file before
43
+ its phase; templates live in `assets/templates/`.
44
+
45
+ ```
46
+ 1 INGEST pitch + orient artifacts + KB. Extract slug, appetite, in/out boundaries,
47
+ rabbit holes, third-party mentions. No files written yet.
48
+ 1b FEASIBILITY (third-party/API/SDK/webhook mentioned) verification questions + fallback
49
+ scope per API-NN → api-feasibility.md
50
+ 2 DDD bounded contexts, aggregates (new vs extended), value objects, domain events,
51
+ repository interfaces → domain-model.md [references/ddd-patterns.md]
52
+ 2b CONTRACTS (standard lens) typed Request/Response/Error per repository; two-pass rule:
53
+ unresolvable at spec time → `⏳ TBD — verify in TASK-NNN-spike-…`, resolved
54
+ post-SPIKE with citation → contracts/ [references/contract-patterns.md]
55
+ 3 UX per screen: state table (idle→loading→error→success), error cases with
56
+ message+action, ASCII flows → ux-behavior.md [references/ux-behavior-patterns.md]
57
+ 4 USE CASES one file per actor+action: typed Input/Output, numbered Steps, all error
58
+ cases with codes, ## System Flow (UI→API→UC→Repo→DB), ## Test Surface
59
+ (DERIVED ONLY from D1 Invariants · D2 Error Cases · D3 Contract shape ·
60
+ D4 No-gos — a sourceless test idea is a spec gap to raise, never a row to
61
+ invent) → usecases/ [references/test-surface.md]
62
+ 5 INTEGRATION (standard lens) cross-system data flows, events, silent-failure risks
63
+ → integration.md [references/integration-analysis.md]
64
+ 6 TASKS atomic, ordered, executable → tasks/ (LOCAL root; the one uncommitted branch
65
+ of the tree — regenerable, machine-local) [references/task-generation.md]
66
+ 7 DERIVE+LINT mechanical, not yours to grade:
67
+ node "${CLAUDE_PLUGIN_ROOT}/skills/ba-pitch-analyzer/scripts/board-derive.mjs" --slug <slug> --write
68
+ (unlocks = depends_on inverse; Σ hours; critical path; appetite arithmetic —
69
+ overflow is a fact you REPORT for the caller's HAMMER gate, never resolve)
70
+ node "${CLAUDE_PLUGIN_ROOT}/skills/ba-pitch-analyzer/scripts/spec-lint.mjs" --slug <slug>
71
+ (structure, wikilinks, edge symmetry — fix reds, then re-run; you never
72
+ self-grade with a hand-walked checklist)
73
+ → scope-summary.md + synthesis.md (traceability matrix, risk register,
74
+ dependency graph — the JUDGMENT layers over board-derive's numbers)
75
+ 8 INDEX _index.md (pitch digest + document map) + feedback.md template
76
+ ```
77
+
78
+ **Task generation rules (the craft that makes tasks executable):**
79
+ - One task = one verifiable change (one package, one concern); AC checkable by running commands.
80
+ - `depends_on` explicit; `unlocks` NEVER hand-authored — board-derive recomputes it.
81
+ - Contract-first: an implementation task touching a repository requires its contract file
82
+ (else generate the contract-stub task first); third-party + `⏳ TBD` → the SPIKE task
83
+ precedes and blocks it (`time_box_hours` hard cap, `api_ref`, `blocks[]`).
84
+ - AC Trigger Matrix (full rules in references/task-generation.md): conditional rendering →
85
+ 🔁 Inverse Conditions; data fetching → 📭 Empty & Null States; numeric limits → 🔢 Boundary
86
+ Values; FEAT + user actor or cross-layer → 🧪 BDD Scenarios; ≥1 service boundary →
87
+ 🔗 Integration Flow; not triggered → remove the section entirely.
88
+ - After all implementation tasks: one integration-test task (DB round-trip, auth rejection,
89
+ cross-service BDD).
90
+
91
+ **Coverage trust = UC.** Every task carries `use_case_refs`; a task with none is an orphan
92
+ (red). An invariant-backed regression task still anchors to its owning UC — there is no
93
+ second path to green.
94
+
95
+ ---
96
+
97
+ ## The other four operations — same craft, different payload + whitelist
98
+
99
+ | Operation | Essence | Never |
100
+ |---|---|---|
101
+ | `generate-board` | Re-derive the full task set fresh from the committed `usecases/` + `domain-model.md` (+ scope contracts if present — tasks respect their substrates). Numbering restarts at TASK-001. Initialize `status` from committed mechanical truth at SCOPE granularity (a scope with hill shard FINISHED → its tasks start `done`) — never join on task id; ids renumber per machine, the scope is the stable key. Then board-derive `--write` + regenerate scope-summary.md | touch the committed spec docs (frozen in your substrate) |
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 |
103
+ | `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 — the audit's dropped clauses ("side-step OR lure enemies into traps", "low-res world textures") were *lost inside* a bigger sentence. **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 |
105
+
106
+ ---
107
+
108
+ ## Anti-rationalization table
109
+
110
+ | Excuse | Reality |
111
+ |---|---|
112
+ | "This test idea is obviously worth a row" | No D1–D4 source = no row. Raise it as a spec gap; inventing rows is how the judge ends up grading fiction. |
113
+ | "The discovered item obviously fits UC-03" | Run the actor/action match. 'Obviously' is how UCs silently widen — no match → ESCALATE. |
114
+ | "I'll fix the UC steps while reconciling" | Steps are frozen in your substrate. A step change is re-shaping — the PO's call, not yours. |
115
+ | "My output looks complete, score it 92" | You don't grade yourself. spec-lint reports facts; the judge judges. |
116
+ | "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
+ | "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 produced 10 asymmetric edges (KB-BA-001). board-derive computes it. |
119
+
120
+ ---
121
+
122
+ ## Output contract — the WorkResult
123
+
124
+ Domain artifacts land inside your substrate (the committed spec tree + the LOCAL board). Then
125
+ write `.shapeup/<slug>/results/<order-suffix>.json`:
126
+
127
+ ```json
128
+ {
129
+ "schema_version": 1, "order_id": "<copied>", "worker": "ba-pitch-analyzer",
130
+ "status": "done | partial | escalated",
131
+ "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
+ "assumptions": ["lens=standard — third-party PSP present"],
134
+ "deviations": [],
135
+ "discoveries": [ { "marker": "+", "line": "appetite overflow 12h — candidate cuts: TASK-014, TASK-017" } ]
136
+ }
137
+ ```
138
+
139
+ You do NOT write: `run-state.md` (dead — the orchestrator owns run truth), `tasks/_index.md`
140
+ status flips for built work (ingest's job), scope contracts (scope-architect's), or any
141
+ `discovered_rounds` counter (the orchestrator counts rounds).
142
+
143
+ ---
144
+
145
+ ## Verification checklist
146
+
147
+ - [ ] Every file written matches the operation's substrate (allowed/append_only respected)
148
+ - [ ] Every task has `use_case_refs`, explicit `depends_on`, command-verifiable AC
149
+ - [ ] No hand-authored `unlocks`; board-derive ran `--write` after the last board change
150
+ - [ ] spec-lint reports 0 red (or each remaining red is explained in `deviations[]`)
151
+ - [ ] Test Surface rows all cite a D1–D4 source; gaps raised, not filled
152
+ - [ ] Appetite overflow (if any) reported as a discovery, not self-resolved
153
+ - [ ] The WorkResult validates against `work-result.schema.json`
154
+
155
+ ---
156
+
157
+ ## Invocation
158
+
159
+ ```bash
160
+ # Orchestrated (tech-lead MAP SCOPES / round boundaries) — the canonical form
161
+ /ba-pitch-analyzer --order .shapeup/checkout-vnpay/orders/analyze.json
162
+
163
+ # Standalone — the preamble shim compiles the order (mode: standalone, pause_gates: true):
164
+ # node "${CLAUDE_PLUGIN_ROOT}/skills/tech-lead/scripts/compile-order.mjs" --operation analyze --slug <slug> \
165
+ # --worker ba-pitch-analyzer --payload '{"pitch": "docs/pitch.md", "lens": "standard"}'
166
+ /ba-pitch-analyzer docs/pitch.md # operation: analyze, lens judged
167
+ /ba-pitch-analyzer --lens standard docs/pitch.md # lens pinned
168
+ ```
169
+
170
+ Standalone keeps exactly two flags: the pitch input and `--lens`. Every retired flag is now
171
+ caller context: `--tasks-only` → a generate-board order, `--from-discovered` → a reconcile
172
+ order, `--surface-only` → a retrofit-surface order, `--remap`/`--split` → scope-architect
173
+ orders, `--status` → read `spec-lint.mjs`/`board-derive.mjs` output (zero LLM tokens),
174
+ `--auto`/`--skip-gate*` → `interaction.pause_gates`, `--upgrade` → an analyze order with the
175
+ standard lens over an existing lite tree (reconciliation pass: extend, never overwrite Steps).