@aperant/framework 0.16.0 → 0.19.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 (174) hide show
  1. package/CHANGELOG.md +185 -1
  2. package/dist/cli/commands/ci-watch.mjs +49 -2
  3. package/dist/cli/commands/ci-watch.mjs.map +1 -1
  4. package/dist/cli/commands/commit.mjs +3 -3
  5. package/dist/cli/commands/commit.mjs.map +1 -1
  6. package/dist/cli/commands/event.mjs +16 -16
  7. package/dist/cli/commands/event.mjs.map +1 -1
  8. package/dist/cli/commands/merge-integrate.mjs +3 -3
  9. package/dist/cli/commands/merge-integrate.mjs.map +1 -1
  10. package/dist/cli/commands/produce.d.mts +9 -0
  11. package/dist/cli/commands/produce.d.mts.map +1 -0
  12. package/dist/cli/commands/produce.mjs +1345 -0
  13. package/dist/cli/commands/produce.mjs.map +1 -0
  14. package/dist/cli/commands/spar-resolve-partner.d.mts +9 -0
  15. package/dist/cli/commands/spar-resolve-partner.d.mts.map +1 -0
  16. package/dist/cli/commands/spar-resolve-partner.mjs +82 -0
  17. package/dist/cli/commands/spar-resolve-partner.mjs.map +1 -0
  18. package/dist/cli/commands/task.d.mts +16 -1
  19. package/dist/cli/commands/task.d.mts.map +1 -1
  20. package/dist/cli/commands/task.mjs +434 -266
  21. package/dist/cli/commands/task.mjs.map +1 -1
  22. package/dist/cli/config/gitignore-drift.d.mts.map +1 -1
  23. package/dist/cli/config/gitignore-drift.mjs +1 -0
  24. package/dist/cli/config/gitignore-drift.mjs.map +1 -1
  25. package/dist/cli/config/post-merge-sweep.d.mts.map +1 -1
  26. package/dist/cli/config/post-merge-sweep.mjs +1 -0
  27. package/dist/cli/config/post-merge-sweep.mjs.map +1 -1
  28. package/dist/cli/coordination/auto-emit-artifact-ready.mjs +5 -5
  29. package/dist/cli/coordination/auto-emit-artifact-ready.mjs.map +1 -1
  30. package/dist/cli/coordination/event-schema.d.mts +5 -3
  31. package/dist/cli/coordination/event-schema.d.mts.map +1 -1
  32. package/dist/cli/coordination/event-schema.mjs +245 -21
  33. package/dist/cli/coordination/event-schema.mjs.map +1 -1
  34. package/dist/cli/coordination/store.d.mts +2 -2
  35. package/dist/cli/coordination/store.mjs +4 -4
  36. package/dist/cli/coordination/store.mjs.map +1 -1
  37. package/dist/cli/dispatch.d.mts.map +1 -1
  38. package/dist/cli/dispatch.mjs +4 -0
  39. package/dist/cli/dispatch.mjs.map +1 -1
  40. package/dist/cli/help.d.mts.map +1 -1
  41. package/dist/cli/help.mjs +31 -0
  42. package/dist/cli/help.mjs.map +1 -1
  43. package/dist/cli/host/codex-config.d.mts +78 -0
  44. package/dist/cli/host/codex-config.d.mts.map +1 -0
  45. package/dist/cli/host/codex-config.mjs +169 -0
  46. package/dist/cli/host/codex-config.mjs.map +1 -0
  47. package/dist/cli/install/legacy-paths.d.mts.map +1 -1
  48. package/dist/cli/install/legacy-paths.mjs +2 -0
  49. package/dist/cli/install/legacy-paths.mjs.map +1 -1
  50. package/dist/cli/produce/blind-probe.d.mts +85 -0
  51. package/dist/cli/produce/blind-probe.d.mts.map +1 -0
  52. package/dist/cli/produce/blind-probe.mjs +217 -0
  53. package/dist/cli/produce/blind-probe.mjs.map +1 -0
  54. package/dist/cli/produce/claim.d.mts +188 -0
  55. package/dist/cli/produce/claim.d.mts.map +1 -0
  56. package/dist/cli/produce/claim.mjs +518 -0
  57. package/dist/cli/produce/claim.mjs.map +1 -0
  58. package/dist/cli/produce/done-gate.d.mts +87 -0
  59. package/dist/cli/produce/done-gate.d.mts.map +1 -0
  60. package/dist/cli/produce/done-gate.mjs +200 -0
  61. package/dist/cli/produce/done-gate.mjs.map +1 -0
  62. package/dist/cli/produce/events.d.mts +77 -0
  63. package/dist/cli/produce/events.d.mts.map +1 -0
  64. package/dist/cli/produce/events.mjs +126 -0
  65. package/dist/cli/produce/events.mjs.map +1 -0
  66. package/dist/cli/produce/evidence-oracle.d.mts +63 -0
  67. package/dist/cli/produce/evidence-oracle.d.mts.map +1 -0
  68. package/dist/cli/produce/evidence-oracle.mjs +122 -0
  69. package/dist/cli/produce/evidence-oracle.mjs.map +1 -0
  70. package/dist/cli/produce/ledger.d.mts +140 -0
  71. package/dist/cli/produce/ledger.d.mts.map +1 -0
  72. package/dist/cli/produce/ledger.mjs +272 -0
  73. package/dist/cli/produce/ledger.mjs.map +1 -0
  74. package/dist/cli/produce/probe-family.d.mts +53 -0
  75. package/dist/cli/produce/probe-family.d.mts.map +1 -0
  76. package/dist/cli/produce/probe-family.mjs +160 -0
  77. package/dist/cli/produce/probe-family.mjs.map +1 -0
  78. package/dist/cli/produce/projection.d.mts +55 -0
  79. package/dist/cli/produce/projection.d.mts.map +1 -0
  80. package/dist/cli/produce/projection.mjs +97 -0
  81. package/dist/cli/produce/projection.mjs.map +1 -0
  82. package/dist/cli/produce/run-id.d.mts +42 -0
  83. package/dist/cli/produce/run-id.d.mts.map +1 -0
  84. package/dist/cli/produce/run-id.mjs +79 -0
  85. package/dist/cli/produce/run-id.mjs.map +1 -0
  86. package/dist/cli/produce/saga.d.mts +180 -0
  87. package/dist/cli/produce/saga.d.mts.map +1 -0
  88. package/dist/cli/produce/saga.mjs +290 -0
  89. package/dist/cli/produce/saga.mjs.map +1 -0
  90. package/dist/cli/produce/scheduler.d.mts +165 -0
  91. package/dist/cli/produce/scheduler.d.mts.map +1 -0
  92. package/dist/cli/produce/scheduler.mjs +399 -0
  93. package/dist/cli/produce/scheduler.mjs.map +1 -0
  94. package/dist/cli/produce/setpoint.d.mts +52 -0
  95. package/dist/cli/produce/setpoint.d.mts.map +1 -0
  96. package/dist/cli/produce/setpoint.mjs +113 -0
  97. package/dist/cli/produce/setpoint.mjs.map +1 -0
  98. package/dist/cli/produce/verification-ttl.d.mts +75 -0
  99. package/dist/cli/produce/verification-ttl.d.mts.map +1 -0
  100. package/dist/cli/produce/verification-ttl.mjs +169 -0
  101. package/dist/cli/produce/verification-ttl.mjs.map +1 -0
  102. package/dist/cli/roadmap/{conductor-view.d.mts → showrunner-view.d.mts} +3 -3
  103. package/dist/cli/roadmap/showrunner-view.d.mts.map +1 -0
  104. package/dist/cli/roadmap/{conductor-view.mjs → showrunner-view.mjs} +7 -7
  105. package/dist/cli/roadmap/showrunner-view.mjs.map +1 -0
  106. package/dist/cli/wfrun/run.d.mts.map +1 -1
  107. package/dist/cli/wfrun/run.mjs +1 -0
  108. package/dist/cli/wfrun/run.mjs.map +1 -1
  109. package/dist/plugin/.claude-plugin/plugin.json +2 -1
  110. package/dist/plugin/skills/apt/SKILL.md +112 -38
  111. package/dist/plugin/skills/apt-debug/SKILL.md +14 -24
  112. package/dist/plugin/skills/apt-fan-out/SKILL.md +4 -4
  113. package/dist/plugin/skills/apt-handoff/SKILL.md +1 -1
  114. package/dist/plugin/skills/apt-plan/SKILL.md +5 -5
  115. package/dist/plugin/skills/apt-plan/adapters/{conductor.md → showrunner.md} +16 -16
  116. package/dist/plugin/skills/apt-produce/SKILL.md +606 -0
  117. package/dist/plugin/skills/apt-quick/SKILL.md +14 -22
  118. package/dist/plugin/skills/apt-run/SKILL.md +126 -3
  119. package/dist/plugin/skills/apt-ship/SKILL.md +2 -0
  120. package/dist/plugin/skills/apt-spar/SKILL.md +19 -9
  121. package/dist/plugin/skills/apt-watch-ci/SKILL.md +4 -4
  122. package/package.json +4 -4
  123. package/prompts/{conductor-framework-context.md → showrunner-framework-context.md} +1 -1
  124. package/prompts/{conductor-status-check.md → showrunner-status-check.md} +1 -1
  125. package/prompts/{conductor-sub-agent.md → showrunner-sub-agent.md} +6 -6
  126. package/prompts/{conductor-system.md → showrunner-system.md} +8 -8
  127. package/skills/apt/SKILL.md +112 -38
  128. package/skills/apt-debug/SKILL.md +14 -24
  129. package/skills/apt-fan-out/SKILL.md +4 -4
  130. package/skills/apt-handoff/SKILL.md +1 -1
  131. package/skills/apt-plan/SKILL.md +5 -5
  132. package/skills/apt-plan/adapters/{conductor.md → showrunner.md} +16 -16
  133. package/skills/apt-produce/SKILL.md +606 -0
  134. package/skills/apt-quick/SKILL.md +14 -22
  135. package/skills/apt-run/SKILL.md +126 -3
  136. package/skills/apt-ship/SKILL.md +2 -0
  137. package/skills/apt-spar/SKILL.md +19 -9
  138. package/skills/apt-watch-ci/SKILL.md +4 -4
  139. package/src/cli/commands/ci-watch.mjs +51 -2
  140. package/src/cli/commands/commit.mjs +3 -3
  141. package/src/cli/commands/event.mjs +16 -16
  142. package/src/cli/commands/merge-integrate.mjs +3 -3
  143. package/src/cli/commands/produce.mjs +1466 -0
  144. package/src/cli/commands/spar-resolve-partner.mjs +85 -0
  145. package/src/cli/commands/task.mjs +482 -285
  146. package/src/cli/config/gitignore-drift.mjs +1 -0
  147. package/src/cli/config/post-merge-sweep.mjs +1 -0
  148. package/src/cli/coordination/auto-emit-artifact-ready.mjs +5 -5
  149. package/src/cli/coordination/event-schema.d.ts +4 -2
  150. package/src/cli/coordination/event-schema.mjs +276 -21
  151. package/src/cli/coordination/store.mjs +4 -4
  152. package/src/cli/dispatch.mjs +4 -0
  153. package/src/cli/help.mjs +31 -0
  154. package/src/cli/host/codex-config.mjs +165 -0
  155. package/src/cli/install/legacy-paths.mjs +2 -0
  156. package/src/cli/produce/blind-probe.mjs +245 -0
  157. package/src/cli/produce/claim.mjs +543 -0
  158. package/src/cli/produce/done-gate.mjs +238 -0
  159. package/src/cli/produce/events.mjs +131 -0
  160. package/src/cli/produce/evidence-oracle.mjs +133 -0
  161. package/src/cli/produce/ledger.mjs +284 -0
  162. package/src/cli/produce/probe-family.mjs +168 -0
  163. package/src/cli/produce/projection.mjs +105 -0
  164. package/src/cli/produce/run-id.mjs +84 -0
  165. package/src/cli/produce/saga.mjs +303 -0
  166. package/src/cli/produce/scheduler.mjs +423 -0
  167. package/src/cli/produce/setpoint.mjs +122 -0
  168. package/src/cli/produce/verification-ttl.mjs +191 -0
  169. package/src/cli/roadmap/showrunner-view.d.ts +10 -0
  170. package/src/cli/roadmap/{conductor-view.mjs → showrunner-view.mjs} +6 -6
  171. package/src/cli/wfrun/run.mjs +1 -0
  172. package/dist/cli/roadmap/conductor-view.d.mts.map +0 -1
  173. package/dist/cli/roadmap/conductor-view.mjs.map +0 -1
  174. package/src/cli/roadmap/conductor-view.d.ts +0 -10
@@ -0,0 +1,399 @@
1
+ /**
2
+ * @internal
3
+ * produce/scheduler.mjs — the deterministic WSJF/WIP "what-next-under-budget"
4
+ * brain (M5, ID-M5-01/ID-M5-02).
5
+ *
6
+ * A NEW CONSUMER that FOLDS the existing M1/M3/M4 projections into a WSJF
7
+ * (Weighted Shortest Job First) ranking of the READY milestones + a WIP-limited
8
+ * pick. It reads `projectRoadmap` (M1 status/order/title), `projectLedger` (M3
9
+ * open acceptance criteria per milestone), `listRegressions` + the run's latest
10
+ * `produce.ttl.reverified` result (M4 unresolved regression), and its OWN small
11
+ * meta-fold over `produce.roadmap.milestone_added` (the additive depends_on /
12
+ * priority / size fields). It NEVER writes to those modules — projection.mjs /
13
+ * ledger.mjs / saga.mjs / verification-ttl.mjs stay BYTE-UNTOUCHED (ID-M5-02).
14
+ *
15
+ * The math is pure integer arithmetic over recorded folds — NO LLM, NO model id
16
+ * (scheduler.mjs is in the produce-no-hardcoded-models.guard scan list, AC11),
17
+ * NO daemon, NO loop. `computeSchedule` emits NO event (a pure read); the wake
18
+ * `tick` is the ONLY writer of `produce.schedule.computed` (ID-M5-06).
19
+ *
20
+ * WSJF(m) = CostOfDelay(m) / JobSize(m)
21
+ * CostOfDelay(m) = W_REGRESS·regression_flag(m) // 5·{0|1}
22
+ * + W_BLOCK ·blocking_count(m) // 3·(# milestones depending on m)
23
+ * + W_VALUE ·open_criteria(m) // 2·(M3 open criteria bound to m)
24
+ * + priority(m) // + optional declared priority (default 0)
25
+ * JobSize(m) = declared_size(m) > 0 ? declared_size(m) : max(open_criteria(m), 1)
26
+ *
27
+ * open_criteria deliberately appears in BOTH the CoD value term AND (as the
28
+ * fallback) in JobSize — standard WSJF (prefer small, high-value jobs); a
29
+ * declared --size decouples them (ID-M5-01). ready_queue is sorted WSJF
30
+ * descending → roadmap first-seen order → milestone_id, a total stable order so
31
+ * two folds of the same log are byte-identical.
32
+ */
33
+ import { existsSync, readFileSync } from 'node:fs';
34
+ import { join } from 'node:path';
35
+ import { readProduceRunEventsMatching } from './events.mjs';
36
+ import { projectLedger } from './ledger.mjs';
37
+ import { projectRoadmap } from './projection.mjs';
38
+ import { listRegressions } from './verification-ttl.mjs';
39
+ /**
40
+ * WSJF cost-of-delay weights (ID-M5-01). Fixed integer constants — the ordering
41
+ * is intentional: a shipped-but-regressed milestone is user-facing breakage
42
+ * (most urgent) > a milestone blocking many downstream ones > a milestone with
43
+ * more open value locked behind it > a human-declared priority nudge.
44
+ */
45
+ export const W_REGRESS = 5;
46
+ export const W_BLOCK = 3;
47
+ export const W_VALUE = 2;
48
+ /** The default WIP cap when neither a flag nor config supplies one (ID-M5-05). */
49
+ export const DEFAULT_WIP_LIMIT = 1;
50
+ /**
51
+ * Load `.aperant/config.json` defensively (mirrors roadmap/backend-adapter.mjs).
52
+ * Returns `{}` on any read/parse failure so the WIP resolver never throws.
53
+ *
54
+ * @param {string} projectDir
55
+ * @returns {Record<string, unknown>}
56
+ */
57
+ function loadConfig(projectDir) {
58
+ const p = join(projectDir, '.aperant', 'config.json');
59
+ if (!existsSync(p))
60
+ return {};
61
+ try {
62
+ const parsed = JSON.parse(readFileSync(p, 'utf-8'));
63
+ return parsed && typeof parsed === 'object' ? parsed : {};
64
+ }
65
+ catch {
66
+ return {};
67
+ }
68
+ }
69
+ /**
70
+ * Resolve the WIP cap deterministically (ID-M5-05):
71
+ * `--wip <n>` flag → `.aperant/config.json :: produce.wip` → default 1. A
72
+ * non-numeric / negative / bare `--wip` value is ignored (falls through). The
73
+ * cap is the max number of CONCURRENT in_progress milestones the loop will run.
74
+ *
75
+ * @param {string} projectDir
76
+ * @param {Map<string, string | true>} flags
77
+ * @returns {number}
78
+ */
79
+ export function resolveWipLimit(projectDir, flags) {
80
+ const flagVal = flags && typeof flags.get === 'function' ? flags.get('wip') : undefined;
81
+ if (typeof flagVal === 'string') {
82
+ const n = Number.parseInt(flagVal, 10);
83
+ if (Number.isFinite(n) && n >= 0)
84
+ return n;
85
+ }
86
+ const cfg = loadConfig(projectDir);
87
+ const produceCfg = cfg && typeof cfg.produce === 'object' && cfg.produce !== null ? cfg.produce : null;
88
+ if (produceCfg && Number.isFinite(produceCfg.wip) && Number(produceCfg.wip) >= 0) {
89
+ return Math.trunc(Number(produceCfg.wip));
90
+ }
91
+ return DEFAULT_WIP_LIMIT;
92
+ }
93
+ /**
94
+ * Fold the run's `produce.roadmap.milestone_added` events into the per-milestone
95
+ * scheduling metadata carried as ADDITIVE optional fields on that event
96
+ * (ID-M5-03): `depends_on` (string[]), `priority` (int, default 0), `size`
97
+ * (positive int | null). An M1-style milestone (added with no new flags) folds
98
+ * to `{ depends_on: [], priority: 0, size: null }` — byte-identical behavior.
99
+ * First-seen wins (idempotent re-adds never clobber).
100
+ *
101
+ * @param {string} projectDir
102
+ * @param {string} runId
103
+ * @returns {Map<string, { depends_on: string[], priority: number, size: number | null }>}
104
+ */
105
+ export function readMilestoneMeta(projectDir, runId) {
106
+ const events = readProduceRunEventsMatching(projectDir, runId, (op) => op === 'produce.roadmap.milestone_added');
107
+ const meta = new Map();
108
+ for (const e of events) {
109
+ const d = e.data || {};
110
+ const id = typeof d.milestone_id === 'string' ? d.milestone_id : null;
111
+ if (!id || meta.has(id))
112
+ continue;
113
+ const dependsOn = Array.isArray(d.depends_on)
114
+ ? d.depends_on.filter((x) => typeof x === 'string' && x.length > 0)
115
+ : [];
116
+ const priority = Number.isFinite(d.priority) ? Math.trunc(Number(d.priority)) : 0;
117
+ const size = Number.isFinite(d.size) && Number(d.size) > 0 ? Math.trunc(Number(d.size)) : null;
118
+ meta.set(id, { depends_on: dependsOn, priority, size });
119
+ }
120
+ return meta;
121
+ }
122
+ /**
123
+ * CostOfDelay = 5·regression + 3·blocking + 2·open_criteria + priority (all
124
+ * integer). Absent fields default to 0.
125
+ *
126
+ * @param {{ regressionFlag?: number, blockingCount?: number, openCriteria?: number, priority?: number }} args
127
+ * @returns {number}
128
+ */
129
+ export function computeCostOfDelay({ regressionFlag = 0, blockingCount = 0, openCriteria = 0, priority = 0, } = {}) {
130
+ return (W_REGRESS * (regressionFlag ? 1 : 0) +
131
+ W_BLOCK * blockingCount +
132
+ W_VALUE * openCriteria +
133
+ priority);
134
+ }
135
+ /**
136
+ * JobSize = declared_size when positive, else the open-criteria count floored at
137
+ * 1 (never 0 — a criteria-less, size-less milestone is the smallest job = 1, so
138
+ * WSJF never divides by zero). ID-M5-01.
139
+ *
140
+ * @param {{ declaredSize?: number | null, openCriteria?: number }} args
141
+ * @returns {number}
142
+ */
143
+ export function computeJobSize({ declaredSize = null, openCriteria = 0 } = {}) {
144
+ if (Number.isFinite(declaredSize) && Number(declaredSize) > 0)
145
+ return Math.trunc(Number(declaredSize));
146
+ return Math.max(openCriteria, 1);
147
+ }
148
+ /**
149
+ * WSJF = CostOfDelay / JobSize. JobSize is guaranteed ≥ 1 (computeJobSize) so
150
+ * this never divides by zero.
151
+ *
152
+ * @param {number} costOfDelay
153
+ * @param {number} jobSize
154
+ * @returns {number}
155
+ */
156
+ export function computeWsjf(costOfDelay, jobSize) {
157
+ return costOfDelay / (jobSize > 0 ? jobSize : 1);
158
+ }
159
+ /**
160
+ * True iff milestone `milestoneId` has an UNRESOLVED M4 verification-TTL
161
+ * regression — it appears in `listRegressions` AND its latest recorded
162
+ * `produce.ttl.reverified` result is not `pass` (ID-M5-07). A subsequent
163
+ * `--result pass` re-verify resolves it (latest result becomes `pass`).
164
+ *
165
+ * @param {string} projectDir
166
+ * @param {string} runId
167
+ * @param {string} milestoneId
168
+ * @returns {boolean}
169
+ */
170
+ export function hasUnresolvedRegression(projectDir, runId, milestoneId) {
171
+ const regressed = listRegressions(projectDir, runId).some((r) => r.milestone_id === milestoneId);
172
+ if (!regressed)
173
+ return false;
174
+ const reverifies = readProduceRunEventsMatching(projectDir, runId, (op) => op === 'produce.ttl.reverified');
175
+ let latestResult = null;
176
+ for (const e of reverifies) {
177
+ const d = e.data || {};
178
+ if (d.milestone_id === milestoneId && typeof d.result === 'string')
179
+ latestResult = d.result;
180
+ }
181
+ return latestResult !== 'pass';
182
+ }
183
+ /**
184
+ * A ranked ready-queue entry with its WSJF terms exposed.
185
+ *
186
+ * @typedef {Object} ScheduleEntry
187
+ * @property {string} milestone_id
188
+ * @property {string} title
189
+ * @property {string} status
190
+ * @property {number} wsjf
191
+ * @property {number} cost_of_delay
192
+ * @property {number} job_size
193
+ * @property {number} open_criteria
194
+ * @property {number} blocking_count
195
+ * @property {number} priority
196
+ * @property {boolean} regressed
197
+ */
198
+ /**
199
+ * The pure schedule combiner (ID-M5-02). Folds the existing projections + the
200
+ * meta-fold + regressions into a WSJF-ranked `ready_queue`, a `blocked` list
201
+ * (with `blocked_by` = the not-done deps), the `in_progress` accounting, and a
202
+ * WIP-limited `pick` of the top `wip_available` ready milestones. Emits NO
203
+ * event and mutates no module (a pure read).
204
+ *
205
+ * Ready-set membership: a `planned` milestone is READY iff every `depends_on`
206
+ * id resolves to a roadmap milestone with status `done` (an unknown dep fails
207
+ * closed = unmet); otherwise it goes to `blocked`. A `done` milestone with an
208
+ * unresolved M4 regression re-enters the ready set tagged regressed:true.
209
+ *
210
+ * @param {string} projectDir
211
+ * @param {string} runId
212
+ * @param {{ wipLimit?: number }} [opts]
213
+ * @returns {{
214
+ * run_id: string,
215
+ * wip_limit: number,
216
+ * wip_in_use: number,
217
+ * wip_available: number,
218
+ * ready_queue: ScheduleEntry[],
219
+ * blocked: Array<{ milestone_id: string, title: string, blocked_by: string[] }>,
220
+ * in_progress: Array<{ milestone_id: string, title: string }>,
221
+ * pick: ScheduleEntry[],
222
+ * reason: string,
223
+ * cycle: string[] | null,
224
+ * }}
225
+ */
226
+ export function computeSchedule(projectDir, runId, { wipLimit = 1 } = {}) {
227
+ const roadmap = projectRoadmap(projectDir, runId);
228
+ const ledger = projectLedger(projectDir, runId);
229
+ const meta = readMilestoneMeta(projectDir, runId);
230
+ // M3 open acceptance criteria per milestone.
231
+ const openByMilestone = new Map();
232
+ for (const c of ledger.criteria) {
233
+ if (c.status === 'open' && typeof c.milestone_id === 'string') {
234
+ openByMilestone.set(c.milestone_id, (openByMilestone.get(c.milestone_id) || 0) + 1);
235
+ }
236
+ }
237
+ // blocking_count(m) = # of milestones whose depends_on includes m.
238
+ const blockingCount = new Map();
239
+ for (const m of roadmap.milestones) {
240
+ const dm = meta.get(m.id);
241
+ for (const dep of dm ? dm.depends_on : []) {
242
+ blockingCount.set(dep, (blockingCount.get(dep) || 0) + 1);
243
+ }
244
+ }
245
+ const statusById = new Map(roadmap.milestones.map((m) => [m.id, m.status]));
246
+ const firstSeenOrder = new Map(roadmap.milestones.map((m, i) => [m.id, i]));
247
+ const inProgress = roadmap.milestones
248
+ .filter((m) => m.status === 'in_progress')
249
+ .map((m) => ({ milestone_id: m.id, title: m.title }));
250
+ const wipInUse = inProgress.length;
251
+ const wipAvailable = Math.max(0, wipLimit - wipInUse);
252
+ /** Build a ranked ready-queue entry with its WSJF terms exposed. */
253
+ const buildEntry = (m, regressed) => {
254
+ const dm = meta.get(m.id) || { depends_on: [], priority: 0, size: null };
255
+ const openCriteria = openByMilestone.get(m.id) || 0;
256
+ const blocking = blockingCount.get(m.id) || 0;
257
+ const costOfDelay = computeCostOfDelay({
258
+ regressionFlag: regressed ? 1 : 0,
259
+ blockingCount: blocking,
260
+ openCriteria,
261
+ priority: dm.priority,
262
+ });
263
+ const jobSize = computeJobSize({ declaredSize: dm.size, openCriteria });
264
+ return {
265
+ milestone_id: m.id,
266
+ title: m.title,
267
+ status: m.status,
268
+ wsjf: computeWsjf(costOfDelay, jobSize),
269
+ cost_of_delay: costOfDelay,
270
+ job_size: jobSize,
271
+ open_criteria: openCriteria,
272
+ blocking_count: blocking,
273
+ priority: dm.priority,
274
+ regressed,
275
+ };
276
+ };
277
+ // Ready set = { planned with all deps done } ∪ { done with an unresolved M4
278
+ // regression } (ID-M5-07). A regressed `done` milestone re-enters ready_queue
279
+ // tagged regressed:true; its regression_flag gives it the W_REGRESS=5 CoD
280
+ // weight, so it ranks toward the top and competes for a WIP slot — the loop
281
+ // defends what it shipped. WIP still counts roadmap `in_progress` ONLY (a
282
+ // regressed done milestone is a candidate, not counted as in_progress).
283
+ const readyQueue = [];
284
+ const blocked = [];
285
+ for (const m of roadmap.milestones) {
286
+ if (m.status === 'planned') {
287
+ const dm = meta.get(m.id) || { depends_on: [], priority: 0, size: null };
288
+ // An unknown dep fails closed = unmet (ID-M5-04).
289
+ const notDone = dm.depends_on.filter((dep) => statusById.get(dep) !== 'done');
290
+ if (notDone.length === 0) {
291
+ readyQueue.push(buildEntry(m, false));
292
+ }
293
+ else {
294
+ blocked.push({ milestone_id: m.id, title: m.title, blocked_by: notDone });
295
+ }
296
+ }
297
+ else if (m.status === 'done' && hasUnresolvedRegression(projectDir, runId, m.id)) {
298
+ readyQueue.push(buildEntry(m, true));
299
+ }
300
+ }
301
+ sortReadyQueue(readyQueue, firstSeenOrder);
302
+ const pick = readyQueue.slice(0, wipAvailable);
303
+ // A dependency cycle among not-done milestones means none can EVER become
304
+ // ready — surface it as a diagnostic rather than a misleading silent idle
305
+ // (ID-M5-04). The cyclic milestones simply never enter ready_queue.
306
+ const cycle = detectDependencyCycle(roadmap, meta);
307
+ let reason;
308
+ if (wipAvailable === 0)
309
+ reason = 'wip_saturated';
310
+ else if (readyQueue.length === 0)
311
+ reason = cycle ? 'dependency_cycle_detected' : 'no_ready_milestones';
312
+ else
313
+ reason = 'scheduled';
314
+ return {
315
+ run_id: runId,
316
+ wip_limit: wipLimit,
317
+ wip_in_use: wipInUse,
318
+ wip_available: wipAvailable,
319
+ ready_queue: readyQueue,
320
+ blocked,
321
+ in_progress: inProgress,
322
+ pick,
323
+ reason,
324
+ cycle,
325
+ };
326
+ }
327
+ /**
328
+ * Minimal inline DFS over the NOT-DONE dependency sub-graph (ID-M5-04). An edge
329
+ * m → dep exists when m depends on dep AND dep is itself a not-done roadmap
330
+ * milestone (a `done` dep is satisfied; an UNKNOWN dep is a leaf — it can't form
331
+ * a cycle). Returns the offending cycle's milestone ids (the recursion-stack
332
+ * slice from the re-entered gray node), or `null` when the sub-graph is acyclic.
333
+ * Deterministic — iterates in roadmap first-seen order.
334
+ *
335
+ * @param {{ milestones: Array<{ id: string, status: string }> }} roadmap
336
+ * @param {Map<string, { depends_on: string[] }>} meta
337
+ * @returns {string[] | null}
338
+ */
339
+ function detectDependencyCycle(roadmap, meta) {
340
+ const nodes = roadmap.milestones.filter((m) => m.status !== 'done').map((m) => m.id);
341
+ const nodeSet = new Set(nodes);
342
+ const depsOf = (id) => (meta.get(id)?.depends_on ?? []).filter((dep) => nodeSet.has(dep));
343
+ const WHITE = 0;
344
+ const GRAY = 1;
345
+ const BLACK = 2;
346
+ const color = new Map(nodes.map((n) => [n, WHITE]));
347
+ const stack = [];
348
+ let found = null;
349
+ const visit = (n) => {
350
+ if (found)
351
+ return;
352
+ color.set(n, GRAY);
353
+ stack.push(n);
354
+ for (const dep of depsOf(n)) {
355
+ if (found)
356
+ return;
357
+ const c = color.get(dep);
358
+ if (c === GRAY) {
359
+ found = stack.slice(stack.indexOf(dep));
360
+ return;
361
+ }
362
+ if (c === WHITE)
363
+ visit(dep);
364
+ }
365
+ stack.pop();
366
+ color.set(n, BLACK);
367
+ };
368
+ for (const n of nodes) {
369
+ if (found)
370
+ break;
371
+ if (color.get(n) === WHITE)
372
+ visit(n);
373
+ }
374
+ return found;
375
+ }
376
+ /**
377
+ * Sort a ready-queue in place: WSJF descending → roadmap first-seen order →
378
+ * milestone_id lexicographic. A total, stable order so two folds of the same
379
+ * log are byte-identical (ID-M5-01 tie-break).
380
+ *
381
+ * @param {Array<{ wsjf: number, milestone_id: string }>} queue
382
+ * @param {Map<string, number>} firstSeenOrder
383
+ */
384
+ function sortReadyQueue(queue, firstSeenOrder) {
385
+ queue.sort((a, b) => {
386
+ if (b.wsjf !== a.wsjf)
387
+ return b.wsjf - a.wsjf;
388
+ const ao = firstSeenOrder.get(a.milestone_id) ?? 0;
389
+ const bo = firstSeenOrder.get(b.milestone_id) ?? 0;
390
+ if (ao !== bo)
391
+ return ao - bo;
392
+ if (a.milestone_id < b.milestone_id)
393
+ return -1;
394
+ if (a.milestone_id > b.milestone_id)
395
+ return 1;
396
+ return 0;
397
+ });
398
+ }
399
+ //# sourceMappingURL=scheduler.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scheduler.mjs","sourceRoot":"","sources":["../../../src/cli/produce/scheduler.mjs"],"names":[],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * sha256 of the canonical JSON of the setpoint's immutable core.
3
+ *
4
+ * @param {{ run_id: string, outcome: string, frozen_at: string }} core
5
+ * @returns {string}
6
+ */
7
+ export function computeSetpointHash(core: {
8
+ run_id: string;
9
+ outcome: string;
10
+ frozen_at: string;
11
+ }): string;
12
+ /**
13
+ * The setpoint.json path for a given run dir.
14
+ * @param {string} runDir
15
+ * @returns {string}
16
+ */
17
+ export function setpointPathFor(runDir: string): string;
18
+ /**
19
+ * Exclusive-create write of the setpoint. Uses `openSync(path, 'wx')` on the
20
+ * FINAL path (NOT a tmp+rename) so a SECOND write throws EEXIST — the setpoint
21
+ * is immutable. Any attempt to overwrite an existing setpoint throws.
22
+ *
23
+ * @param {string} setpointPath
24
+ * @param {object} setpoint
25
+ */
26
+ export function writeSetpointExclusive(setpointPath: string, setpoint: object): void;
27
+ /**
28
+ * Read + parse the frozen setpoint for a run dir. Returns null when absent or
29
+ * malformed (never throws).
30
+ *
31
+ * @param {string} runDir
32
+ * @returns {object | null}
33
+ */
34
+ export function readSetpoint(runDir: string): object | null;
35
+ /**
36
+ * Freeze the setpoint for a run, idempotently. If already frozen, returns the
37
+ * byte-identical stored setpoint with `reused: true`. Otherwise writes it once
38
+ * via exclusive create and returns `reused: false`.
39
+ *
40
+ * @param {string} runDir
41
+ * @param {{ run_id: string, outcome: string }} args
42
+ * @param {Date} [now]
43
+ * @returns {{ reused: boolean, setpoint: object }}
44
+ */
45
+ export function freezeSetpoint(runDir: string, { run_id, outcome }: {
46
+ run_id: string;
47
+ outcome: string;
48
+ }, now?: Date): {
49
+ reused: boolean;
50
+ setpoint: object;
51
+ };
52
+ //# sourceMappingURL=setpoint.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setpoint.d.mts","sourceRoot":"","sources":["../../../src/cli/produce/setpoint.mjs"],"names":[],"mappings":"AAoCA;;;;;GAKG;AACH,0CAHW;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GACpD,MAAM,CAIlB;AAED;;;;GAIG;AACH,wCAHW,MAAM,GACJ,MAAM,CAIlB;AAED;;;;;;;GAOG;AACH,qDAHW,MAAM,YACN,MAAM,QAYhB;AAED;;;;;;GAMG;AACH,qCAHW,MAAM,GACJ,MAAM,GAAG,IAAI,CAUzB;AAED;;;;;;;;;GASG;AACH,uCALW,MAAM,uBACN;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,QACnC,IAAI,GACF;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAqBjD"}
@@ -0,0 +1,113 @@
1
+ /**
2
+ * @internal
3
+ * produce/setpoint.mjs — the FROZEN acceptance setpoint (M1, ID-02).
4
+ *
5
+ * The setpoint is the fixed external reference the parent spar requires
6
+ * instead of the Showrunner's moving opinion. It is written ONCE via
7
+ * `openSync(path, 'wx')` (exclusive create) — a second write throws EEXIST, so
8
+ * the reference cannot drift. `produce start` on a run whose setpoint already
9
+ * exists is idempotent-reuse: it returns the byte-identical stored setpoint,
10
+ * NEVER an overwrite.
11
+ *
12
+ * File shape: `{ run_id, outcome, frozen_at, setpoint_hash }` where
13
+ * `setpoint_hash = sha256(canonical JSON of { run_id, outcome, frozen_at })`.
14
+ */
15
+ import { createHash } from 'node:crypto';
16
+ import { closeSync, existsSync, fsyncSync, mkdirSync, openSync, readFileSync, writeSync, } from 'node:fs';
17
+ import { dirname, join } from 'node:path';
18
+ /** Stable-key-order JSON of the hashable setpoint core. */
19
+ function canonicalSetpointJson(core) {
20
+ return JSON.stringify({
21
+ run_id: core.run_id,
22
+ outcome: core.outcome,
23
+ frozen_at: core.frozen_at,
24
+ });
25
+ }
26
+ /**
27
+ * sha256 of the canonical JSON of the setpoint's immutable core.
28
+ *
29
+ * @param {{ run_id: string, outcome: string, frozen_at: string }} core
30
+ * @returns {string}
31
+ */
32
+ export function computeSetpointHash(core) {
33
+ return createHash('sha256').update(canonicalSetpointJson(core)).digest('hex');
34
+ }
35
+ /**
36
+ * The setpoint.json path for a given run dir.
37
+ * @param {string} runDir
38
+ * @returns {string}
39
+ */
40
+ export function setpointPathFor(runDir) {
41
+ return join(runDir, 'setpoint.json');
42
+ }
43
+ /**
44
+ * Exclusive-create write of the setpoint. Uses `openSync(path, 'wx')` on the
45
+ * FINAL path (NOT a tmp+rename) so a SECOND write throws EEXIST — the setpoint
46
+ * is immutable. Any attempt to overwrite an existing setpoint throws.
47
+ *
48
+ * @param {string} setpointPath
49
+ * @param {object} setpoint
50
+ */
51
+ export function writeSetpointExclusive(setpointPath, setpoint) {
52
+ mkdirSync(dirname(setpointPath), { recursive: true });
53
+ const payload = `${JSON.stringify(setpoint, null, 2)}\n`;
54
+ const fd = openSync(setpointPath, 'wx'); // throws EEXIST when already frozen
55
+ try {
56
+ writeSync(fd, payload, 0, 'utf-8');
57
+ fsyncSync(fd);
58
+ }
59
+ finally {
60
+ closeSync(fd);
61
+ }
62
+ }
63
+ /**
64
+ * Read + parse the frozen setpoint for a run dir. Returns null when absent or
65
+ * malformed (never throws).
66
+ *
67
+ * @param {string} runDir
68
+ * @returns {object | null}
69
+ */
70
+ export function readSetpoint(runDir) {
71
+ const p = setpointPathFor(runDir);
72
+ if (!existsSync(p))
73
+ return null;
74
+ try {
75
+ return JSON.parse(readFileSync(p, 'utf-8'));
76
+ }
77
+ catch {
78
+ return null;
79
+ }
80
+ }
81
+ /**
82
+ * Freeze the setpoint for a run, idempotently. If already frozen, returns the
83
+ * byte-identical stored setpoint with `reused: true`. Otherwise writes it once
84
+ * via exclusive create and returns `reused: false`.
85
+ *
86
+ * @param {string} runDir
87
+ * @param {{ run_id: string, outcome: string }} args
88
+ * @param {Date} [now]
89
+ * @returns {{ reused: boolean, setpoint: object }}
90
+ */
91
+ export function freezeSetpoint(runDir, { run_id, outcome }, now = new Date()) {
92
+ const existing = readSetpoint(runDir);
93
+ if (existing)
94
+ return { reused: true, setpoint: existing };
95
+ const frozen_at = now.toISOString();
96
+ const core = { run_id, outcome, frozen_at };
97
+ const setpoint = { ...core, setpoint_hash: computeSetpointHash(core) };
98
+ try {
99
+ writeSetpointExclusive(setpointPathFor(runDir), setpoint);
100
+ }
101
+ catch (e) {
102
+ // Lost a concurrent race — the winner's file is authoritative; re-read
103
+ // it byte-identically rather than overwriting (ID-02).
104
+ if (e && e.code === 'EEXIST') {
105
+ const winner = readSetpoint(runDir);
106
+ if (winner)
107
+ return { reused: true, setpoint: winner };
108
+ }
109
+ throw e;
110
+ }
111
+ return { reused: false, setpoint };
112
+ }
113
+ //# sourceMappingURL=setpoint.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setpoint.mjs","sourceRoot":"","sources":["../../../src/cli/produce/setpoint.mjs"],"names":[],"mappings":"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"}
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Select a DETERMINISTIC rotating sample of already-`done` milestones STALE
3
+ * against HEAD (ID-M4-03 / AC7). REUSES `selectSweepSample` for the rotation
4
+ * order (fewest/oldest last-probe-run first), then annotates each candidate with
5
+ * staleness against `headSha` and FILTERS OUT the FRESH ones (last re-verified
6
+ * against the current HEAD). Returns the first `sample` STALE candidates. An
7
+ * absent HEAD sha fails closed (nothing selected).
8
+ *
9
+ * @param {string} projectDir
10
+ * @param {string} runId
11
+ * @param {{ headSha: string, sample?: number }} args
12
+ * @returns {{ run_id: string, head_sha: string | null, sample_size: number,
13
+ * selected: Array<{ milestone_id: string, title: string, last_reverify_head_sha: string | null, last_reverify_at: string | null, stale: boolean }> }}
14
+ */
15
+ export function selectTtlReverifySample(projectDir: string, runId: string, { headSha, sample }?: {
16
+ headSha: string;
17
+ sample?: number;
18
+ }): {
19
+ run_id: string;
20
+ head_sha: string | null;
21
+ sample_size: number;
22
+ selected: Array<{
23
+ milestone_id: string;
24
+ title: string;
25
+ last_reverify_head_sha: string | null;
26
+ last_reverify_at: string | null;
27
+ stale: boolean;
28
+ }>;
29
+ };
30
+ /**
31
+ * Record a scheduled TTL re-verify RUN against HEAD (ID-M4-03). REUSES the M2
32
+ * cross-family guard (refuses a same-family re-verify, or when no implementer
33
+ * family is recorded). Appends `produce.ttl.reverified {run_id, milestone_id,
34
+ * head_sha, result}`; on `result === 'fail'` ALSO appends
35
+ * `produce.ttl.regression_detected` AND fires the FORWARD compensator via
36
+ * saga.mjs::compensatePhase({phase:'verify', reason:'ttl_regression@<sha>'}) — a
37
+ * revert-branch + reopen + re-plan, NEVER a merged-PR rollback. A `pass`
38
+ * refreshes verification against the new HEAD and logs no regression.
39
+ *
40
+ * @param {string} projectDir
41
+ * @param {{ runId: string, milestoneId: string, result: string, probeFamily: string, headSha: string }} args
42
+ * @returns {{ ok: true, result: string, probe_family: string, head_sha: string, regression: boolean, compensator: object | null }
43
+ * | { ok: false, reason: string }}
44
+ */
45
+ export function recordTtlReverify(projectDir: string, { runId, milestoneId, result, probeFamily, headSha }: {
46
+ runId: string;
47
+ milestoneId: string;
48
+ result: string;
49
+ probeFamily: string;
50
+ headSha: string;
51
+ }): {
52
+ ok: true;
53
+ result: string;
54
+ probe_family: string;
55
+ head_sha: string;
56
+ regression: boolean;
57
+ compensator: object | null;
58
+ } | {
59
+ ok: false;
60
+ reason: string;
61
+ };
62
+ /**
63
+ * Read-only fold of the run's `produce.ttl.regression_detected` events (for saga
64
+ * status / canary context). Chronological order.
65
+ *
66
+ * @param {string} projectDir
67
+ * @param {string} runId
68
+ * @returns {Array<{ milestone_id: string | null, head_sha: string | null, t: string | null }>}
69
+ */
70
+ export function listRegressions(projectDir: string, runId: string): Array<{
71
+ milestone_id: string | null;
72
+ head_sha: string | null;
73
+ t: string | null;
74
+ }>;
75
+ //# sourceMappingURL=verification-ttl.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verification-ttl.d.mts","sourceRoot":"","sources":["../../../src/cli/produce/verification-ttl.mjs"],"names":[],"mappings":"AAiEA;;;;;;;;;;;;;GAaG;AACH,oDANW,MAAM,SACN,MAAM,wBACN;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAClC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IACvE,QAAQ,EAAE,KAAK,CAAC;QAAE,YAAY,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,sBAAsB,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC,CAAA;CAAE,CAiCtJ;AAED;;;;;;;;;;;;;;GAcG;AACH,8CALW,MAAM,wDACN;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAC1F;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,OAAO,CAAC;IAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GAC3H;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CA4CnC;AAED;;;;;;;GAOG;AACH,4CAJW,MAAM,SACN,MAAM,GACJ,KAAK,CAAC;IAAE,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC,CAa7F"}