mandrel 2.20.0 → 2.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/README.md +1 -1
- package/.agents/agents/story-worker.md +15 -0
- package/.agents/instructions.md +14 -17
- package/.agents/rules/git-conventions.md +1 -1
- package/.agents/rules/known-tooling-behavior.md +114 -0
- package/.agents/scripts/check-context-budget.js +134 -2
- package/.agents/scripts/deliver-light.js +72 -8
- package/.agents/scripts/lib/audit-suite/selector.js +275 -162
- package/.agents/scripts/lib/config/temp-paths.js +113 -7
- package/.agents/scripts/lib/feedback-loop/graduator-core.js +604 -57
- package/.agents/scripts/lib/feedback-loop/retro-proposals-graduator.js +72 -21
- package/.agents/scripts/lib/label-constants.js +12 -1
- package/.agents/scripts/lib/observability/runtime-friction.js +13 -1
- package/.agents/scripts/lib/observability/signals-writer.js +133 -14
- package/.agents/scripts/lib/observability/source-classifier.js +131 -1
- package/.agents/scripts/lib/orchestration/code-review.js +12 -0
- package/.agents/scripts/lib/orchestration/complexity-gate.js +119 -52
- package/.agents/scripts/lib/orchestration/deliver-recover.js +253 -6
- package/.agents/scripts/lib/orchestration/light-suitability.js +194 -11
- package/.agents/scripts/lib/orchestration/resolve-stories.js +17 -14
- package/.agents/scripts/lib/orchestration/retro-proposals.js +0 -0
- package/.agents/scripts/lib/orchestration/review-providers/degraded-gates.js +222 -0
- package/.agents/scripts/lib/orchestration/review-providers/findings-renderer.js +18 -3
- package/.agents/scripts/lib/orchestration/review-providers/native.js +82 -126
- package/.agents/scripts/lib/orchestration/review-providers/review-provider-factory.js +10 -0
- package/.agents/scripts/lib/orchestration/review-providers/scoped-lint.js +300 -0
- package/.agents/scripts/lib/orchestration/run-epilogue.js +51 -1
- package/.agents/scripts/lib/orchestration/single-story-close/gate-log.js +11 -1
- package/.agents/scripts/lib/orchestration/single-story-close/phases/code-review.js +18 -8
- package/.agents/scripts/lib/orchestration/single-story-close/phases/review-outcome.js +66 -0
- package/.agents/scripts/lib/orchestration/single-story-close/runner.js +1 -1
- package/.agents/scripts/lib/orchestration/story-close/phases/code-review.js +5 -1
- package/.agents/scripts/lib/orchestration/story-deliver-terminal.js +117 -4
- package/.agents/scripts/lib/orchestration/story-follow-ups.js +305 -10
- package/.agents/scripts/lib/story-body/story-body.js +248 -174
- package/.agents/scripts/lib/temp-retention.js +23 -8
- package/.agents/scripts/resolve-stories.js +52 -33
- package/.agents/scripts/single-story-confirm-merge.js +6 -8
- package/.agents/workflows/helpers/deliver-digest.md +8 -6
- package/.agents/workflows/helpers/deliver-light.md +45 -5
- package/.agents/workflows/helpers/deliver-reference.md +15 -12
- package/.agents/workflows/helpers/deliver-story-reference.md +56 -21
- package/.agents/workflows/helpers/deliver-story.md +8 -5
- package/.agents/workflows/helpers/plan-reference.md +5 -4
- package/docs/CHANGELOG.md +28 -0
- package/package.json +1 -1
|
@@ -158,14 +158,13 @@ function readMaxWaitSecondsFlag() {
|
|
|
158
158
|
* Resolve the PR number for the Story branch when one was not passed on
|
|
159
159
|
* the CLI. Probes `gh pr list --head <branch> --state all` (the merged PR
|
|
160
160
|
* is no longer `open`, so `--state all` is required). Returns `null` when
|
|
161
|
-
* no PR is found.
|
|
161
|
+
* no PR is found. Exported for testing.
|
|
162
162
|
*
|
|
163
|
-
* @param {{
|
|
163
|
+
* @param {{ storyBranch: string, gh: object }} args
|
|
164
164
|
* @returns {Promise<number|null>}
|
|
165
165
|
*/
|
|
166
|
-
async function resolvePrNumber({
|
|
166
|
+
export async function resolvePrNumber({ storyBranch, gh }) {
|
|
167
167
|
try {
|
|
168
|
-
void cwd;
|
|
169
168
|
const rows = await gh.pr.list(
|
|
170
169
|
['--head', storyBranch, '--state', 'all'],
|
|
171
170
|
['number', 'url'],
|
|
@@ -204,7 +203,7 @@ async function logConfirmResult(result, terminal, config) {
|
|
|
204
203
|
status: terminal?.status,
|
|
205
204
|
},
|
|
206
205
|
});
|
|
207
|
-
emitTerminalEnvelope(terminal);
|
|
206
|
+
emitTerminalEnvelope(terminal, { config });
|
|
208
207
|
await emitTerminalFriction({ envelope: terminal, config });
|
|
209
208
|
return { success: terminal.status !== 'failed', result, terminal };
|
|
210
209
|
}
|
|
@@ -293,11 +292,11 @@ function buildConfirmTerminal({
|
|
|
293
292
|
});
|
|
294
293
|
}
|
|
295
294
|
|
|
296
|
-
async function resolveConfirmPrNumber({ prParam,
|
|
295
|
+
async function resolveConfirmPrNumber({ prParam, storyBranch, gh }) {
|
|
297
296
|
const rawPr = prParam ?? readPrFlag();
|
|
298
297
|
let prNumber = Number.parseInt(String(rawPr ?? ''), 10);
|
|
299
298
|
if (!Number.isInteger(prNumber) || prNumber <= 0) {
|
|
300
|
-
prNumber = await resolvePrNumber({
|
|
299
|
+
prNumber = await resolvePrNumber({ storyBranch, gh });
|
|
301
300
|
}
|
|
302
301
|
return Number.isInteger(prNumber) && prNumber > 0 ? prNumber : null;
|
|
303
302
|
}
|
|
@@ -340,7 +339,6 @@ export async function runConfirmMerge({
|
|
|
340
339
|
|
|
341
340
|
const prNumber = await resolveConfirmPrNumber({
|
|
342
341
|
prParam,
|
|
343
|
-
cwd,
|
|
344
342
|
storyBranch,
|
|
345
343
|
gh,
|
|
346
344
|
});
|
|
@@ -20,16 +20,18 @@ description: >-
|
|
|
20
20
|
|
|
21
21
|
## 1. Dispatch — where the engine runs
|
|
22
22
|
|
|
23
|
-
Read `stories[].dispatchMode` from the `resolve-stories.js` envelope.
|
|
24
|
-
|
|
23
|
+
Read `stories[].dispatchMode` from the `resolve-stories.js` envelope.
|
|
24
|
+
`inline` names one indivisible resource — **the router's own session** — so one
|
|
25
|
+
rule produces it:
|
|
25
26
|
|
|
26
27
|
1. **Run topology.** A run resolving **one** Story is `inline`
|
|
27
28
|
whatever its shape — sub-agent isolation is load-bearing only against a
|
|
28
29
|
*concurrent* sibling racing the same checkout, and a one-Story run has none.
|
|
29
|
-
2. **
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
2. **Every other run is `subagent`.** A multi-Story run dispatches every Story
|
|
31
|
+
as a sub-agent however trivial its shape: a lite body does not conjure a
|
|
32
|
+
second session for a sibling to run in, and the wave tick may hand you the
|
|
33
|
+
whole set on one beat. Shape still sets ceremony and is reported alongside;
|
|
34
|
+
the `route::lite` label is a human-visible hint, never the control signal.
|
|
33
35
|
|
|
34
36
|
`inline` removes model-side fan-out only — no `story-worker` boot, no fresh
|
|
35
37
|
acceptance-critic spawn. **`subagent` and `inline` run the same engine**: same
|
|
@@ -49,7 +49,9 @@ multi-capability enumeration). Size is enforced where ground truth is available:
|
|
|
49
49
|
the diff backstop in step 4. Do not talk yourself past that one.
|
|
50
50
|
|
|
51
51
|
Sensitivity is the exception and stays absolute: a footprint touching an auth,
|
|
52
|
-
crypto, billing, or migration class routes `full` however small or mechanical
|
|
52
|
+
crypto, billing, or migration class routes `full` however small or mechanical —
|
|
53
|
+
and unlike a ceiling, it is **not overridable** (§ Recording a proceed-light
|
|
54
|
+
answer).
|
|
53
55
|
|
|
54
56
|
## Four invariants (do not skip one)
|
|
55
57
|
|
|
@@ -58,9 +60,11 @@ crypto, billing, or migration class routes `full` however small or mechanical.
|
|
|
58
60
|
**and** a ledgered model verdict with a recorded reason. Both must agree on
|
|
59
61
|
`lite`.
|
|
60
62
|
2. **Over-scope stops — it never hard-fails.** An over-ceiling prompt STOPS and
|
|
61
|
-
asks the operator to escalate to `/plan` or proceed light.
|
|
62
|
-
|
|
63
|
-
(§
|
|
63
|
+
asks the operator to escalate to `/plan` or proceed light. **Both answers
|
|
64
|
+
are executable** — `--operator-proceed-light` records the second one
|
|
65
|
+
(§ Recording a proceed-light answer). Under `--yes` it fails closed to an
|
|
66
|
+
**`escalated` terminal envelope** that ends the session (§ Escalation is
|
|
67
|
+
terminal).
|
|
64
68
|
3. **Diff-derived backstop.** After implementation the ACTUAL change set is
|
|
65
69
|
re-checked — the diff is the real scope signal — and an over-ceiling diff is
|
|
66
70
|
blocked rather than landed.
|
|
@@ -89,7 +93,10 @@ crypto, billing, or migration class routes `full` however small or mechanical.
|
|
|
89
93
|
`nextCommands`. Continue to step 2.
|
|
90
94
|
- **`ask-operator`** — predicted scope exceeds the light ceilings. STOP and
|
|
91
95
|
ask the operator to escalate to `/plan` or proceed light. Do not proceed
|
|
92
|
-
on your own. This is a **question, not a terminal** — wait for the answer
|
|
96
|
+
on your own. This is a **question, not a terminal** — wait for the answer,
|
|
97
|
+
then act on it: *escalate* leaves for `/plan`, *proceed light* re-runs the
|
|
98
|
+
same command with `--operator-proceed-light "<their reason>"`
|
|
99
|
+
(§ Recording a proceed-light answer).
|
|
93
100
|
- **over-scope under `--yes`** — no `action` to branch on: the gate emits an
|
|
94
101
|
**`escalated` terminal envelope** instead (exit 2). § Escalation is
|
|
95
102
|
terminal governs; you are finished.
|
|
@@ -144,6 +151,39 @@ crypto, billing, or migration class routes `full` however small or mechanical.
|
|
|
144
151
|
[`deliver-digest.md`](deliver-digest.md) § 5 — every close
|
|
145
152
|
gate runs byte-identical to the full path.
|
|
146
153
|
|
|
154
|
+
## Recording a proceed-light answer {#recording-a-proceed-light-answer}
|
|
155
|
+
|
|
156
|
+
The gate offers the operator two options, so **both** have to be executable.
|
|
157
|
+
Re-run the identical gate command with their answer appended:
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
node .agents/scripts/deliver-light.js --prompt "<prompt>" … \
|
|
161
|
+
--operator-proceed-light "<the operator's reason, in their words>"
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
The gate then proceeds light, records the decision in the receipt Story, and
|
|
165
|
+
returns it on the envelope's `override`. Do **not** instead re-shape the
|
|
166
|
+
prediction — shrinking `--refactors` until the gate stops objecting is
|
|
167
|
+
under-declaring the footprint, which is the one thing the coarse design must
|
|
168
|
+
not reward.
|
|
169
|
+
|
|
170
|
+
It is deliberately narrow, and a refusal is printed rather than silent:
|
|
171
|
+
|
|
172
|
+
- **Only a size prediction is waivable** — change kinds, magnitude,
|
|
173
|
+
uncertainty, deployable span. A sensitive-path class, a
|
|
174
|
+
migration-with-consumers span, and an unknown footprint (undeclared, glob,
|
|
175
|
+
no acceptance, unclassifiable) are refused: those are risk, not size, and
|
|
176
|
+
§ Scope by effort keeps them absolute.
|
|
177
|
+
- **The ledgered verdict still stands on its own.** The override substitutes
|
|
178
|
+
for the predicted *shape* only; `--route lite --reason "<why>"` is still
|
|
179
|
+
required.
|
|
180
|
+
- **Attended-only.** With `--yes` it is a usage error, not a quiet no-op —
|
|
181
|
+
an unattended run has no operator whose answer this could be, and over-scope
|
|
182
|
+
there still fails closed (§ Escalation is terminal).
|
|
183
|
+
|
|
184
|
+
What licenses this at all is step 4: the operator waives a *guess*, never the
|
|
185
|
+
diff backstop, which re-checks the actual change set against ground truth.
|
|
186
|
+
|
|
147
187
|
## Escalation is terminal {#escalation-is-terminal}
|
|
148
188
|
|
|
149
189
|
Over-scope under `--yes` emits a schema-validated `story-deliver-terminal`
|
|
@@ -61,23 +61,26 @@ a cache write at full rate; an inline continuation is a cache read at ~10%).
|
|
|
61
61
|
retained in full for multi-Story waves, and the rule changes **where** the
|
|
62
62
|
engine runs, never what runs — gates, PR, and terminal envelope are identical.
|
|
63
63
|
|
|
64
|
-
**
|
|
65
|
-
read the Story's `dispatchMode` from the resolver envelope
|
|
66
|
-
(`stories[].dispatchMode`,
|
|
67
|
-
`lib/orchestration/complexity-gate.js`
|
|
68
|
-
|
|
69
|
-
sensitive-path classes; the `route::lite` label is a human-visible hint only,
|
|
70
|
-
never the control signal, so a lost or never-written label cannot misroute
|
|
71
|
-
delivery): a Story with `dispatchMode: "inline"` executes
|
|
72
|
-
[`deliver-story.md`](deliver-story.md) **inline in this session** — no
|
|
64
|
+
**Read the mode; never infer it from shape.** Before spawning
|
|
65
|
+
anything, read the Story's `dispatchMode` from the resolver envelope
|
|
66
|
+
(`stories[].dispatchMode`, produced by `resolveStoryDispatchMode` in
|
|
67
|
+
`lib/orchestration/complexity-gate.js`). A Story with `dispatchMode: "inline"`
|
|
68
|
+
executes [`deliver-story.md`](deliver-story.md) **inline in this session** — no
|
|
73
69
|
`story-worker` sub-agent boot and no fresh acceptance-critic sub-agents
|
|
74
70
|
(sub-agent boots are the dominant deliver-phase token cost at trivial scope) —
|
|
75
71
|
threading the same `docsDigestPath` / `checklistPath` / change-set discipline
|
|
76
72
|
as a spawned worker. Inline removes model-side fan-out only: every
|
|
77
73
|
`single-story-close.js` gate, the PR to `main`, and the terminal envelope are
|
|
78
|
-
identical.
|
|
79
|
-
|
|
80
|
-
|
|
74
|
+
identical.
|
|
75
|
+
|
|
76
|
+
**A trivial shape does not buy that session.** Only the
|
|
77
|
+
one-Story rule above yields `inline`; every Story of a multi-Story run comes
|
|
78
|
+
back `subagent` however lite its body, because the ready set below may offer
|
|
79
|
+
several Stories on one beat and a session cannot be split between them. The
|
|
80
|
+
Story's derived shape is still reported (it sets ceremony, and a sensitive
|
|
81
|
+
footprint keeps the fresh acceptance critic), and the `route::lite` label
|
|
82
|
+
remains a human-visible hint only, never the control signal — a lost or
|
|
83
|
+
never-written label cannot misroute delivery.
|
|
81
84
|
|
|
82
85
|
**Dispatch each `ready` Story (role-scoped by default).** When
|
|
83
86
|
`delivery.routing.roleScopedAgents` is enabled (the **default**) and the host
|
|
@@ -133,23 +133,25 @@ and the `rules/security-baseline.md` MUSTs all run exactly as for a
|
|
|
133
133
|
full-ceremony Story. The lite route's `preserves` field is the machine-readable
|
|
134
134
|
record of those non-negotiables; there is no lite-specific gate bypass.
|
|
135
135
|
|
|
136
|
-
**Deliver derives the route from the Story body's shape
|
|
137
|
-
Persist stamps a lite cohort's Stories with the
|
|
138
|
-
*human-visible hint only* (and ledgers the authored
|
|
139
|
-
reason plus per-Story shape evidence — on the
|
|
140
|
-
checkpoint); the label is never the control signal.
|
|
141
|
-
route from the fetched Story body via
|
|
142
|
-
(`lib/orchestration/complexity-gate.js`) — the same
|
|
143
|
-
`deriveChangeLevel` applies to the landed diff at close:
|
|
144
|
-
acceptance count, creates-vs-refactors mix, sensitive-path
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
136
|
+
**Deliver derives the route from the Story body's shape — and the
|
|
137
|
+
dispatch mode from the run.** Persist stamps a lite cohort's Stories with the
|
|
138
|
+
`route::lite` label as a *human-visible hint only* (and ledgers the authored
|
|
139
|
+
verdict — recorded reason plus per-Story shape evidence — on the
|
|
140
|
+
`story-plan-state` checkpoint); the label is never the control signal.
|
|
141
|
+
`/deliver` computes the route from the fetched Story body via
|
|
142
|
+
`resolveStoryDispatchMode` (`lib/orchestration/complexity-gate.js`) — the same
|
|
143
|
+
shape taxonomy `deriveChangeLevel` applies to the landed diff at close:
|
|
144
|
+
`changes[]` count, acceptance count, creates-vs-refactors mix, sensitive-path
|
|
145
|
+
classes. A footprint intersecting a sensitive-path class derives `full` —
|
|
146
|
+
sensitivity wins, and the Story keeps its fresh acceptance critic.
|
|
147
|
+
|
|
148
|
+
That derived route sets ceremony. It does **not** set the dispatch mode,
|
|
149
|
+
because `inline` names one indivisible resource — the router's own session —
|
|
150
|
+
and only run topology can say whether it is free: a **single-Story run**
|
|
151
|
+
executes inline, and every Story of a multi-Story run dispatches as a
|
|
152
|
+
`story-worker` sub-agent whatever its shape — a lite shape makes the work
|
|
153
|
+
cheap, it does not conjure a second session for a sibling. Inline
|
|
154
|
+
execution changes the isolation only: the engine, every script gate, and the
|
|
153
155
|
terminal envelope are byte-identical either way.
|
|
154
156
|
|
|
155
157
|
---
|
|
@@ -247,10 +249,10 @@ Resolve fresh-vs-inline acceptance critics per AC-cluster with
|
|
|
247
249
|
floor forces `fresh`). Review depth reads the same derived level via
|
|
248
250
|
`review-depth.js` inside close, so the two decisions cannot disagree.
|
|
249
251
|
|
|
250
|
-
**
|
|
251
|
-
|
|
252
|
-
acceptance critic **inline** — do not spawn fresh-context critic
|
|
253
|
-
regardless of what the profile would otherwise resolve. The self-eval rigor
|
|
252
|
+
**Inline-dispatch override.** When the Story dispatches
|
|
253
|
+
`inline` (`resolveStoryDispatchMode` → `inline`, i.e. a single-Story run), run
|
|
254
|
+
every acceptance critic **inline** — do not spawn fresh-context critic
|
|
255
|
+
sub-agents regardless of what the profile would otherwise resolve. The self-eval rigor
|
|
254
256
|
(scoring each `acceptance[]` item against the one computed change set, with
|
|
255
257
|
`verify[]` output as evidence) is unchanged; only the sub-agent boot is
|
|
256
258
|
removed. Hard gates are untouched.
|
|
@@ -745,6 +747,39 @@ unconfirmed merge is a **contract violation** — the parent cannot distinguish
|
|
|
745
747
|
"still working" from "done but silent". `pending` is the honest,
|
|
746
748
|
machine-readable alternative: "not finished, here is exactly how to continue."
|
|
747
749
|
|
|
750
|
+
### The envelope also lands on disk
|
|
751
|
+
|
|
752
|
+
Stdout has exactly one reader — the turn that launched the close — and that
|
|
753
|
+
reader is not always still listening. A child that reports progress and ends
|
|
754
|
+
its turn while its close is mid-gate-chain is behaving reasonably, but the
|
|
755
|
+
envelope it never relayed is gone, and reconstructing the Story's state from
|
|
756
|
+
labels costs a recovery round trip plus a full resume of the child. Observed
|
|
757
|
+
four times across three workers in a single consumer run, on unrelated
|
|
758
|
+
footprints, and not new to that run.
|
|
759
|
+
|
|
760
|
+
So `emitTerminalEnvelope` — the one writer behind every emit site — also
|
|
761
|
+
persists the validated envelope to
|
|
762
|
+
`<tempRoot>/orchestration/story-deliver-terminal-<storyId>.json`:
|
|
763
|
+
|
|
764
|
+
- **It is the same object**, not a summary. Read it and branch exactly as you
|
|
765
|
+
would on stdout; the copy is written before the markers are, so a caller
|
|
766
|
+
that saw them can rely on the file.
|
|
767
|
+
- **It is best-effort.** A failed write returns null and changes nothing about
|
|
768
|
+
the emitted envelope or the exit code — a landed PR must never become a
|
|
769
|
+
crash because a temp directory was unwritable.
|
|
770
|
+
- **It is a fallback, not a licence.** A worker still holds its turn until the
|
|
771
|
+
envelope arrives; see [`agents/story-worker.md`](../../agents/story-worker.md).
|
|
772
|
+
|
|
773
|
+
`deliver-recover.js` reads the same artifact, plus the freshness of
|
|
774
|
+
`close-gates-<storyId>.log`, to split the one genuinely ambiguous row of its
|
|
775
|
+
table. `agent::executing` with no PR used to answer "Implementation never
|
|
776
|
+
finished" — false for the whole duration of a close, whose gates and push
|
|
777
|
+
happen before any PR exists, and actively hazardous, because acting on its
|
|
778
|
+
re-init suggestion can put a second close on one PR. It now answers
|
|
779
|
+
`close-in-flight` (a gate log touched inside the window: wait, then re-probe)
|
|
780
|
+
or `close-envelope-on-disk` (the close already reached a verdict: relay it),
|
|
781
|
+
and falls back to the original verdict only when neither artifact exists.
|
|
782
|
+
|
|
748
783
|
### Exit-code compatibility note (`--no-wait-merge`)
|
|
749
784
|
|
|
750
785
|
Every close flag keeps its meaning, but the **exit code** of a
|
|
@@ -22,8 +22,8 @@ mandatoryReads: [deliver-digest.md]
|
|
|
22
22
|
|
|
23
23
|
## Overview
|
|
24
24
|
|
|
25
|
-
The **one** delivery engine in v2 — every Story (a
|
|
26
|
-
|
|
25
|
+
The **one** delivery engine in v2 — every Story (a **one-Story** run
|
|
26
|
+
goes inline with inline critics; engine, gates, envelope byte-identical):
|
|
27
27
|
|
|
28
28
|
```text
|
|
29
29
|
single-story-init.js → implement + commits → derived-level ceremony
|
|
@@ -148,10 +148,13 @@ budget is exhausted. Reference § Step 7.
|
|
|
148
148
|
|
|
149
149
|
## Recovering a stranded Story {#recover}
|
|
150
150
|
|
|
151
|
-
|
|
152
|
-
|
|
151
|
+
**Lost envelope first: read it off disk.** Close persists each to
|
|
152
|
+
`temp/orchestration/story-deliver-terminal-<storyId>.json`; branch on it per
|
|
153
|
+
digest § 5. Otherwise (killed run, re-run refusal, merged-but-label-stale)
|
|
154
|
+
do not guess — probe **read-only** with
|
|
153
155
|
`node .agents/scripts/deliver-recover.js --story <storyId>`; it prints the
|
|
154
|
-
**one** next command with its evidence, never a menu.
|
|
156
|
+
**one** next command with its evidence, never a menu. A live close answers
|
|
157
|
+
`close-in-flight`: wait, never re-init underneath it.
|
|
155
158
|
|
|
156
159
|
## Idempotence & constraints
|
|
157
160
|
|
|
@@ -120,10 +120,11 @@ decision:
|
|
|
120
120
|
lite cohort's Stories with **`route::lite`** as a *human-visible hint only* —
|
|
121
121
|
`/deliver` computes the route from each fetched Story body via the same shape
|
|
122
122
|
function at dispatch, so neither a lost label nor an unread marker can
|
|
123
|
-
misroute delivery: a lite-shaped Story
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
the
|
|
123
|
+
misroute delivery: a lite-shaped Story derives `lite` even with the label
|
|
124
|
+
absent, and a sensitive-footprint Story routes `full` and keeps its fresh
|
|
125
|
+
critic even with the label present. The derived route sets ceremony, not
|
|
126
|
+
where the engine runs — sub-agent boots are collapsed by a **single-Story
|
|
127
|
+
run**, never by a trivial shape. The `route::*` axis stays runtime-derived: hand-authored
|
|
127
128
|
`route::*` entries in `labels[]` are dropped by persist.
|
|
128
129
|
|
|
129
130
|
The knobs (`planning.complexityGate.{enabled, maxArtifacts}`) are documented
|
package/docs/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,34 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [2.22.0](https://github.com/dsj1984/mandrel/compare/mandrel-v2.21.0...mandrel-v2.22.0) (2026-07-30)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Fixed
|
|
9
|
+
|
|
10
|
+
* **context-budget:** hold agentBoot baseline rows in sync with the tree (refs [#4830](https://github.com/dsj1984/mandrel/issues/4830)) ([#4831](https://github.com/dsj1984/mandrel/issues/4831)) ([8a14f8b](https://github.com/dsj1984/mandrel/commit/8a14f8b85951819ef391382355fa2ba4d7998d43))
|
|
11
|
+
* correct the always-on instruction spine and give its budget one honest definition (refs [#4821](https://github.com/dsj1984/mandrel/issues/4821)) ([#4822](https://github.com/dsj1984/mandrel/issues/4822)) ([436d7f0](https://github.com/dsj1984/mandrel/commit/436d7f05d36bd35a6b1a934f19e9a85b37b69f93))
|
|
12
|
+
* feedback-loop: give an auto-filed issue a stable identity, an actionable body, and no path to the live API from a test ([#4837](https://github.com/dsj1984/mandrel/issues/4837)) ([#4838](https://github.com/dsj1984/mandrel/issues/4838)) ([43bbf57](https://github.com/dsj1984/mandrel/commit/43bbf578fc129c9b15ad068925722732fd264c7f))
|
|
13
|
+
* make an inline dispatch verdict mean the engine can actually run inline (refs [#4829](https://github.com/dsj1984/mandrel/issues/4829)) ([#4832](https://github.com/dsj1984/mandrel/issues/4832)) ([f554830](https://github.com/dsj1984/mandrel/commit/f55483085eb201aa126275bb0ed6250fc5a452a3))
|
|
14
|
+
* make the framework limb of the feedback loop reachable (refs [#4824](https://github.com/dsj1984/mandrel/issues/4824)) ([#4827](https://github.com/dsj1984/mandrel/issues/4827)) ([91816a2](https://github.com/dsj1984/mandrel/commit/91816a2dceda127a0cdf1ad3f48f53d7770cbf0b))
|
|
15
|
+
* make the friction roll-up file its proposals and make an all-empty result legible (refs [#4828](https://github.com/dsj1984/mandrel/issues/4828)) ([#4835](https://github.com/dsj1984/mandrel/issues/4835)) ([c017f9a](https://github.com/dsj1984/mandrel/commit/c017f9a9145122b15e41b55a9126a35171f3f1b9))
|
|
16
|
+
* review: stop the scoped-lint gate failing open silently, and fix why its runner cannot execute ([#4839](https://github.com/dsj1984/mandrel/issues/4839)) ([#4840](https://github.com/dsj1984/mandrel/issues/4840)) ([8f3f007](https://github.com/dsj1984/mandrel/commit/8f3f0072abef020439d555af698829ebfc8900f8))
|
|
17
|
+
* rules: ship a known-tooling-behavior rule so measured gate quirks stop being rediscovered per session ([#4825](https://github.com/dsj1984/mandrel/issues/4825)) ([#4826](https://github.com/dsj1984/mandrel/issues/4826)) ([2c20403](https://github.com/dsj1984/mandrel/commit/2c2040318055026307518de57b1433c11c56efc1))
|
|
18
|
+
* **test:** probe bins on either path separator so [#4839](https://github.com/dsj1984/mandrel/issues/4839)'s tests pass on Windows ([#4841](https://github.com/dsj1984/mandrel/issues/4841)) ([98e6048](https://github.com/dsj1984/mandrel/commit/98e6048774b7483717931d0b4a63179800815941))
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
### Changed
|
|
22
|
+
|
|
23
|
+
* restore clean-code gate headroom: cover CRAP-capacity shells, flatten selectAudits, table-drive story-body parsing ([#4842](https://github.com/dsj1984/mandrel/issues/4842)) ([#4843](https://github.com/dsj1984/mandrel/issues/4843)) ([cc5dc5e](https://github.com/dsj1984/mandrel/commit/cc5dc5e7eaf423612495441f0f8f9007dbb9b8a4))
|
|
24
|
+
|
|
25
|
+
## [2.21.0](https://github.com/dsj1984/mandrel/compare/mandrel-v2.20.0...mandrel-v2.21.0) (2026-07-28)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
### Added
|
|
29
|
+
|
|
30
|
+
* deliver-light: make the gate's `proceed-light` answer representable, attended-only, and auditable ([#4815](https://github.com/dsj1984/mandrel/issues/4815)) ([#4817](https://github.com/dsj1984/mandrel/issues/4817)) ([74aa28e](https://github.com/dsj1984/mandrel/commit/74aa28e57d0192bcad698461d600806a77de092f))
|
|
31
|
+
* persist the close terminal envelope and teach recovery a live-close state (refs [#4816](https://github.com/dsj1984/mandrel/issues/4816)) ([#4819](https://github.com/dsj1984/mandrel/issues/4819)) ([ffa61d8](https://github.com/dsj1984/mandrel/commit/ffa61d8f56f39c33705bfa379cefdcaaeb523115))
|
|
32
|
+
|
|
5
33
|
## [2.20.0](https://github.com/dsj1984/mandrel/compare/mandrel-v2.19.0...mandrel-v2.20.0) (2026-07-27)
|
|
6
34
|
|
|
7
35
|
|
package/package.json
CHANGED