mandrel 1.76.0 → 1.78.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/docs/configuration.md +2 -2
- package/.agents/docs/workflows.md +19 -0
- package/.agents/schemas/agentrc.schema.json +1 -1
- package/.agents/schemas/dispatch-manifest.json +1 -1
- package/.agents/schemas/lifecycle/loop.tick.schema.json +20 -0
- package/.agents/schemas/loop-unit.schema.json +70 -0
- package/.agents/schemas/validation-evidence.schema.json +2 -1
- package/.agents/scripts/audit-to-stories.js +43 -1
- package/.agents/scripts/check-doc-links.js +24 -1
- package/.agents/scripts/check-loop-units.js +204 -0
- package/.agents/scripts/epic-deliver-prepare.js +31 -0
- package/.agents/scripts/evidence-gate.js +48 -12
- package/.agents/scripts/generate-workflows-doc.js +37 -4
- package/.agents/scripts/lib/audit-to-stories/build-story-body.js +141 -34
- package/.agents/scripts/lib/cli-args.js +6 -0
- package/.agents/scripts/lib/close-validation/process.js +61 -5
- package/.agents/scripts/lib/close-validation/runner.js +42 -9
- package/.agents/scripts/lib/config/temp-paths.js +1 -1
- package/.agents/scripts/lib/config/worktree-isolation.js +18 -3
- package/.agents/scripts/lib/config-resolver.js +4 -1
- package/.agents/scripts/lib/config-settings-schema-delivery.js +1 -1
- package/.agents/scripts/lib/git-branch-lifecycle.js +90 -0
- package/.agents/scripts/lib/loop-units/validate-loop-unit.js +197 -0
- package/.agents/scripts/lib/mandrel-catalog.js +36 -0
- package/.agents/scripts/lib/orchestration/auto-merge-cwd.js +128 -0
- package/.agents/scripts/lib/orchestration/column-sync.js +88 -9
- package/.agents/scripts/lib/orchestration/lifecycle/emit-loop-tick.js +183 -0
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-armer.js +20 -2
- package/.agents/scripts/lib/orchestration/project-meta-cache.js +238 -0
- package/.agents/scripts/lib/orchestration/reassert-status-column.js +3 -1
- package/.agents/scripts/lib/orchestration/single-story-close/phases/auto-merge.js +25 -2
- package/.agents/scripts/lib/orchestration/single-story-close/phases/close-validation.js +80 -14
- package/.agents/scripts/lib/orchestration/single-story-close/runner.js +74 -25
- package/.agents/scripts/lib/orchestration/story-close/phases/locked-pipeline.js +10 -1
- package/.agents/scripts/lib/orchestration/ticket-validator-conflicts.js +48 -1
- package/.agents/scripts/lib/orchestration/ticket-validator-sizing.js +148 -4
- package/.agents/scripts/lib/orchestration/ticketing/transition.js +8 -1
- package/.agents/scripts/lib/story-body/story-body.js +76 -7
- package/.agents/scripts/lib/story-init/branch-initializer.js +29 -43
- package/.agents/scripts/lib/story-init/hierarchy-tracer.js +25 -4
- package/.agents/scripts/lib/story-init/task-graph-builder.js +22 -12
- package/.agents/scripts/lib/templates/decomposer-prompts.js +23 -0
- package/.agents/scripts/lib/validation-evidence.js +63 -25
- package/.agents/scripts/lib/worktree/node-modules-strategy.js +239 -31
- package/.agents/scripts/providers/github/branch-protection.js +1 -1
- package/.agents/scripts/providers/github/errors.js +53 -2
- package/.agents/scripts/providers/github/labels.js +1 -1
- package/.agents/scripts/providers/github/projects-v2-graphql.js +1 -1
- package/.agents/scripts/resync-status-column.js +5 -0
- package/.agents/scripts/run-coverage.js +85 -45
- package/.agents/scripts/run-lint.js +11 -0
- package/.agents/scripts/single-story-init.js +22 -29
- package/.agents/scripts/story-init.js +38 -63
- package/.agents/scripts/story-phase.js +46 -4
- package/.agents/scripts/sync-claude-commands.js +112 -29
- package/.agents/scripts/update-maintainability-baseline.js +19 -76
- package/.agents/skills/core/epic-plan-decompose-author/SKILL.md +5 -3
- package/.agents/workflows/helpers/acceptance-self-eval.md +27 -0
- package/.agents/workflows/helpers/deliver-epic.md +19 -2
- package/.agents/workflows/helpers/epic-deliver-story.md +50 -14
- package/.agents/workflows/helpers/single-story-deliver.md +12 -0
- package/.agents/workflows/loops/README.md +65 -0
- package/.agents/workflows/loops/fix-failing-tests.md +74 -0
- package/.agents/workflows/loops/nightly-audit.md +71 -0
- package/.agents/workflows/loops/watch-ci.md +68 -0
- package/docs/CHANGELOG.md +51 -0
- package/package.json +1 -1
- package/.agents/scripts/providers/github/transient-retry.js +0 -62
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: >-
|
|
3
|
+
Interval watch loop that polls a pull request's CI checks until they settle.
|
|
4
|
+
Each round runs `gh pr checks` and reports the delta; the host (`/loop 5m`)
|
|
5
|
+
owns the cadence and re-invokes the unit on its schedule. verify is optional
|
|
6
|
+
for an interval loop — the externally-scheduled host owns iteration, so this
|
|
7
|
+
unit ships the action and goal, not a terminating oracle.
|
|
8
|
+
loop:
|
|
9
|
+
cadence: interval
|
|
10
|
+
goal: >-
|
|
11
|
+
Keep an eye on the current pull request's required CI checks each interval,
|
|
12
|
+
surfacing the first failed or stuck check the moment it appears so a human
|
|
13
|
+
can act before the checks finish.
|
|
14
|
+
maxRounds: 60
|
|
15
|
+
onExhaust: report
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
# /loops:watch-ci — poll a PR's checks until they settle
|
|
19
|
+
|
|
20
|
+
An **interval watch loop**. The host (`/loop <interval> /loops:watch-ci`, e.g.
|
|
21
|
+
`/loop 5m …`) owns the cadence and re-runs this unit on each tick. Because the
|
|
22
|
+
host schedules iteration externally, this unit carries **no `verify` oracle** —
|
|
23
|
+
per the loop-unit schema, `verify` is required only for `self-paced` cadence and
|
|
24
|
+
optional for `interval` / `cron`. The unit's job each round is to observe and
|
|
25
|
+
report, not to converge.
|
|
26
|
+
|
|
27
|
+
## Action
|
|
28
|
+
|
|
29
|
+
Each interval:
|
|
30
|
+
|
|
31
|
+
1. **Read the current check state.** Run `gh pr checks` for the PR under watch
|
|
32
|
+
(the host supplies the PR number, or it is inferred from the current
|
|
33
|
+
branch's open PR). Capture the per-check status: pending, passed, or failed.
|
|
34
|
+
2. **Compute the delta since last round.** Compare against the prior round's
|
|
35
|
+
snapshot. A check that flipped `pending → failed` is the headline; a check
|
|
36
|
+
that flipped `pending → passed` is progress.
|
|
37
|
+
3. **Surface failures immediately.** On the first failed or cancelled required
|
|
38
|
+
check, report it — name the check, link the run, and quote the first error
|
|
39
|
+
line if cheaply available — so a human can act before the rest of the matrix
|
|
40
|
+
finishes. Do not wait for the whole suite to settle to raise a red check.
|
|
41
|
+
4. **Report and yield.** Emit a one-line status summary
|
|
42
|
+
(`N passed, M pending, K failed`) and return control to the host, which
|
|
43
|
+
sleeps until the next interval.
|
|
44
|
+
|
|
45
|
+
## Goal & done-signal
|
|
46
|
+
|
|
47
|
+
- **Goal:** the operator learns about a CI failure on the watched PR as early as
|
|
48
|
+
the polling interval allows, and knows when all required checks have gone
|
|
49
|
+
green.
|
|
50
|
+
- **Done-signal:** all required checks have a terminal status (every check
|
|
51
|
+
passed, or at least one has failed). An interval loop has no self-evaluated
|
|
52
|
+
oracle — the host stops the loop when the operator cancels it, when a failure
|
|
53
|
+
is surfaced and acted on, or when `maxRounds` is reached.
|
|
54
|
+
- **Backstop:** `maxRounds: 60`. At a 5-minute interval that is ~5 hours of
|
|
55
|
+
watching; `onExhaust: report` emits a final status and stops rather than
|
|
56
|
+
polling forever on a wedged check.
|
|
57
|
+
|
|
58
|
+
## Stop & escalate
|
|
59
|
+
|
|
60
|
+
- **A required check failed.** Surface it and let the operator decide whether to
|
|
61
|
+
keep watching the remaining checks or stop. A failed required check is the
|
|
62
|
+
signal the watch existed to catch.
|
|
63
|
+
- **The PR cannot be resolved** (no open PR for the branch, `gh` not
|
|
64
|
+
authenticated, the PR was merged or closed out from under the watch). Report
|
|
65
|
+
the condition and stop — there is nothing left to watch.
|
|
66
|
+
- **`maxRounds` is reached with checks still pending.** Emit a final summary of
|
|
67
|
+
the stuck checks (`onExhaust: report`) so the operator can investigate the
|
|
68
|
+
wedged run.
|
package/docs/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,57 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [1.78.0](https://github.com/dsj1984/mandrel/compare/mandrel-v1.77.0...mandrel-v1.78.0) (2026-06-24)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Added
|
|
9
|
+
|
|
10
|
+
* Epic [#4284](https://github.com/dsj1984/mandrel/issues/4284) ([#4297](https://github.com/dsj1984/mandrel/issues/4297)) ([0f7c543](https://github.com/dsj1984/mandrel/commit/0f7c543e1ceb1c38ac425c388e338e3bfaaec49e))
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
* **baselines:** apply ignoreGlobs in the maintainability baseline CLI diff-scope branch (refs [#4293](https://github.com/dsj1984/mandrel/issues/4293)) ([#4294](https://github.com/dsj1984/mandrel/issues/4294)) ([c0c7dd5](https://github.com/dsj1984/mandrel/commit/c0c7dd5948314800e5a9d5808fb5eb0b01b09833))
|
|
16
|
+
* **close-validation:** treat biome "No files were processed" as a clean format-gate skip (refs [#4292](https://github.com/dsj1984/mandrel/issues/4292)) ([#4295](https://github.com/dsj1984/mandrel/issues/4295)) ([bf6840d](https://github.com/dsj1984/mandrel/commit/bf6840dd69abbece4eb221797e6432519b6614a0))
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
|
|
21
|
+
* **github-provider:** unify the two divergent withTransientRetry into one canonical primitive (refs [#4298](https://github.com/dsj1984/mandrel/issues/4298)) ([#4299](https://github.com/dsj1984/mandrel/issues/4299)) ([e5668dc](https://github.com/dsj1984/mandrel/commit/e5668dcca73b37c37d38e52e1eb8d2930a0e1790))
|
|
22
|
+
|
|
23
|
+
## [1.77.0](https://github.com/dsj1984/mandrel/compare/mandrel-v1.76.0...mandrel-v1.77.0) (2026-06-24)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
### Added
|
|
27
|
+
|
|
28
|
+
* **close-validation:** unify evidence keyspace — critic verify[] sharing + standalone parity (refs [#4250](https://github.com/dsj1984/mandrel/issues/4250)) ([#4266](https://github.com/dsj1984/mandrel/issues/4266)) ([0555f3b](https://github.com/dsj1984/mandrel/commit/0555f3b0aaeabfb09c2ab02ed2bf7f5182a96c28))
|
|
29
|
+
* **decompose-gates:** emit a deterministic soft missing-reason-to-exist finding + document reason_to_exist in the author SKILL (refs [#4273](https://github.com/dsj1984/mandrel/issues/4273)) ([#4280](https://github.com/dsj1984/mandrel/issues/4280)) ([98d3d5b](https://github.com/dsj1984/mandrel/commit/98d3d5b3d4ba8aa1c5485f5728e44bda09a6f3d3))
|
|
30
|
+
* **decompose:** single-source the binding-vs-advisory authoring altitude + New-File Contract into the decomposer prompt (refs [#4272](https://github.com/dsj1984/mandrel/issues/4272)) ([#4279](https://github.com/dsj1984/mandrel/issues/4279)) ([3fc9adb](https://github.com/dsj1984/mandrel/commit/3fc9adb848226e4ef90463e31d5cbabb3f350c7f))
|
|
31
|
+
* **deliver:** add --epic/--branch flags to story-phase.js and drop duplicate closing snapshot (refs [#4256](https://github.com/dsj1984/mandrel/issues/4256)) ([#4261](https://github.com/dsj1984/mandrel/issues/4261)) ([0f75eda](https://github.com/dsj1984/mandrel/commit/0f75eda48568d136803cd714ab0fd04bc341033d))
|
|
32
|
+
* overhaul worktree install: copy-on-write node_modules + correct, PM-aware retry ([#4249](https://github.com/dsj1984/mandrel/issues/4249)) ([#4267](https://github.com/dsj1984/mandrel/issues/4267)) ([ce92a71](https://github.com/dsj1984/mandrel/commit/ce92a71b47a7851a04ce4d48ce6fa16c9ea41988))
|
|
33
|
+
* persist Projects v2 board metadata to a disk cache ([#4252](https://github.com/dsj1984/mandrel/issues/4252)) ([#4263](https://github.com/dsj1984/mandrel/issues/4263)) ([277d9ec](https://github.com/dsj1984/mandrel/commit/277d9ecd8ac05fa291bb873a57966fc67d768205))
|
|
34
|
+
* **story-body:** add optional advisory non_goals negative-scope section (refs [#4275](https://github.com/dsj1984/mandrel/issues/4275)) ([#4281](https://github.com/dsj1984/mandrel/issues/4281)) ([e118482](https://github.com/dsj1984/mandrel/commit/e118482aa5aa6ae2874c1da9d470d8c53b26bdf8))
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
### Fixed
|
|
38
|
+
|
|
39
|
+
* **decompose-gates:** parse string Story bodies in sizing/conflict gates (refs [#4271](https://github.com/dsj1984/mandrel/issues/4271)) ([#4277](https://github.com/dsj1984/mandrel/issues/4277)) ([6c804a4](https://github.com/dsj1984/mandrel/commit/6c804a4b6645f0742ba21ef145a5dc5a351b21bb))
|
|
40
|
+
* rebuild the audit-to-stories Story body to the canonical inline-contract shape and gate it before issue creation ([#4270](https://github.com/dsj1984/mandrel/issues/4270)) ([#4278](https://github.com/dsj1984/mandrel/issues/4278)) ([058ff7b](https://github.com/dsj1984/mandrel/commit/058ff7b13ec799c11ed2ddf134adaf82c289168f))
|
|
41
|
+
* **single-story-close:** release assignee-lease on recoverable-blocked exits (refs [#4257](https://github.com/dsj1984/mandrel/issues/4257)) ([#4268](https://github.com/dsj1984/mandrel/issues/4268)) ([108fa5f](https://github.com/dsj1984/mandrel/commit/108fa5f834121bf53c5cb59005415ea30b6e990f))
|
|
42
|
+
* **story-body:** close section on unrecognized heading to stop content bleed (refs [#4274](https://github.com/dsj1984/mandrel/issues/4274)) ([#4276](https://github.com/dsj1984/mandrel/issues/4276)) ([808d508](https://github.com/dsj1984/mandrel/commit/808d5080fee460f24cae8ef43b2c8c1b442de1f3))
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
### Performance
|
|
46
|
+
|
|
47
|
+
* **coverage:** make run-coverage.js host-aware for --test-concurrency (refs [#4254](https://github.com/dsj1984/mandrel/issues/4254)) ([#4260](https://github.com/dsj1984/mandrel/issues/4260)) ([0078195](https://github.com/dsj1984/mandrel/commit/0078195afeee50fafefdaf4dea3d59b33b172cc6))
|
|
48
|
+
* **deliver:** resolve Epic once and thread --prd/--tech-spec into story-init (refs [#4253](https://github.com/dsj1984/mandrel/issues/4253)) ([#4269](https://github.com/dsj1984/mandrel/issues/4269)) ([8dbc006](https://github.com/dsj1984/mandrel/commit/8dbc006882379ccdfb5dca90d8d8bca11c2dbb0e))
|
|
49
|
+
* **story-init:** short-circuit childless 2-tier sub-issues + Search probe in buildTaskGraph (refs [#4251](https://github.com/dsj1984/mandrel/issues/4251)) ([#4265](https://github.com/dsj1984/mandrel/issues/4265)) ([7c8fcd2](https://github.com/dsj1984/mandrel/commit/7c8fcd21a9c781bd2e4592d7c8e7b4bf8476cd22))
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
### Changed
|
|
53
|
+
|
|
54
|
+
* **story-init:** single-home the duplicated branch-seed action switch (refs [#4255](https://github.com/dsj1984/mandrel/issues/4255)) ([#4264](https://github.com/dsj1984/mandrel/issues/4264)) ([7a6f2ec](https://github.com/dsj1984/mandrel/commit/7a6f2ec9c2e7ce0b680c620e9bb52541ec37db1b))
|
|
55
|
+
|
|
5
56
|
## [1.76.0](https://github.com/dsj1984/mandrel/compare/mandrel-v1.75.0...mandrel-v1.76.0) (2026-06-20)
|
|
6
57
|
|
|
7
58
|
|
package/package.json
CHANGED
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* transient-retry — shared retry-with-backoff for GitHub provider calls.
|
|
3
|
-
*
|
|
4
|
-
* Resilience for flaky connections (e.g. cell hotspots): retry ONLY on
|
|
5
|
-
* connectivity blips, never on auth / scope / not-found / already-exists /
|
|
6
|
-
* validation errors. Works for both surfaces the provider uses:
|
|
7
|
-
* - the gh CLI path — errors carry the Go HTTP error on `err.stderr`
|
|
8
|
-
* (e.g. `dial tcp ...: i/o timeout`); and
|
|
9
|
-
* - the direct `fetch` path — errors are a `TypeError: fetch failed` with
|
|
10
|
-
* the real reason on `err.cause` (e.g. `ETIMEDOUT`, `ENOTFOUND`).
|
|
11
|
-
*
|
|
12
|
-
* Retrying a non-idempotent create is acceptable for the dominant hotspot
|
|
13
|
-
* failure (`dial tcp ... i/o timeout` means the connection never opened, so
|
|
14
|
-
* the request never reached GitHub). Callers still gate retry per call so
|
|
15
|
-
* the genuinely non-idempotent project-create can opt out.
|
|
16
|
-
*/
|
|
17
|
-
|
|
18
|
-
const TRANSIENT_RE =
|
|
19
|
-
/i\/o timeout|dial tcp|TLS handshake timeout|connection reset|connection refused|temporary failure|could not resolve host|no such host|network is unreachable|socket hang up|fetch failed|ConnectTimeoutError|UND_ERR_CONNECT_TIMEOUT|ETIMEDOUT|ECONNRESET|ECONNREFUSED|ENOTFOUND|EAI_AGAIN|\b50[234]\b/i;
|
|
20
|
-
|
|
21
|
-
/** True when an error looks like a retryable network/connectivity blip. */
|
|
22
|
-
export function isTransientNetworkError(err) {
|
|
23
|
-
const hay = [
|
|
24
|
-
err?.stderr,
|
|
25
|
-
err?.message,
|
|
26
|
-
err?.code,
|
|
27
|
-
err?.cause?.message,
|
|
28
|
-
err?.cause?.code,
|
|
29
|
-
]
|
|
30
|
-
.filter(Boolean)
|
|
31
|
-
.join(' ');
|
|
32
|
-
return TRANSIENT_RE.test(hay);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Run `fn`, retrying with exponential backoff ONLY on transient network
|
|
37
|
-
* errors (1s, 2s, 4s by default). Non-transient errors throw immediately so
|
|
38
|
-
* real failures stay loud. `sleep` is injectable for tests.
|
|
39
|
-
*
|
|
40
|
-
* @template T
|
|
41
|
-
* @param {() => Promise<T>} fn
|
|
42
|
-
* @param {{ retries?: number, baseDelayMs?: number,
|
|
43
|
-
* sleep?: (ms: number) => Promise<void> }} [opts]
|
|
44
|
-
* @returns {Promise<T>}
|
|
45
|
-
*/
|
|
46
|
-
export async function withTransientRetry(
|
|
47
|
-
fn,
|
|
48
|
-
{
|
|
49
|
-
retries = 3,
|
|
50
|
-
baseDelayMs = 1000,
|
|
51
|
-
sleep = (ms) => new Promise((r) => setTimeout(r, ms)),
|
|
52
|
-
} = {},
|
|
53
|
-
) {
|
|
54
|
-
for (let attempt = 0; ; attempt++) {
|
|
55
|
-
try {
|
|
56
|
-
return await fn();
|
|
57
|
-
} catch (err) {
|
|
58
|
-
if (attempt >= retries || !isTransientNetworkError(err)) throw err;
|
|
59
|
-
await sleep(baseDelayMs * 2 ** attempt);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
}
|