mandrel 1.91.0 → 1.92.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 (109) hide show
  1. package/.agents/README.md +5 -5
  2. package/.agents/docs/SDLC.md +75 -107
  3. package/.agents/docs/configuration.md +1 -1
  4. package/.agents/docs/quality-gates.md +8 -7
  5. package/.agents/docs/workflows.md +4 -10
  6. package/.agents/instructions.md +2 -2
  7. package/.agents/schemas/agentrc.schema.json +1 -1
  8. package/.agents/schemas/lifecycle/README.md +2 -1
  9. package/.agents/schemas/lifecycle/ledger-record.schema.json +1 -1
  10. package/.agents/schemas/risk-verdict.schema.json +14 -1
  11. package/.agents/scripts/README.md +0 -46
  12. package/.agents/scripts/analyze-execution.js +76 -1
  13. package/.agents/scripts/check-doc-links.js +3 -0
  14. package/.agents/scripts/check-workflow-cli-lint.js +208 -0
  15. package/.agents/scripts/epic-audit-recheck.js +1 -1
  16. package/.agents/scripts/epic-plan-clarity.js +16 -6
  17. package/.agents/scripts/epic-plan-decompose.js +37 -59
  18. package/.agents/scripts/epic-plan-healthcheck.js +39 -6
  19. package/.agents/scripts/epic-plan-spec.js +41 -168
  20. package/.agents/scripts/epic-reconcile.js +7 -1
  21. package/.agents/scripts/lib/Logger.js +4 -4
  22. package/.agents/scripts/lib/audit-suite/index.js +4 -5
  23. package/.agents/scripts/lib/audit-suite/runner.js +6 -4
  24. package/.agents/scripts/lib/audit-suite/selector.js +2 -3
  25. package/.agents/scripts/lib/bdd-runner-detect.js +1 -1
  26. package/.agents/scripts/lib/command-header.js +20 -0
  27. package/.agents/scripts/lib/config/github.js +1 -3
  28. package/.agents/scripts/lib/config-settings-schema.js +4 -3
  29. package/.agents/scripts/lib/degraded-mode.js +1 -1
  30. package/.agents/scripts/lib/label-constants.js +18 -3
  31. package/.agents/scripts/lib/label-taxonomy.js +14 -3
  32. package/.agents/scripts/lib/mutation/baseline-snapshot.js +7 -6
  33. package/.agents/scripts/lib/orchestration/consolidation-precondition.js +18 -8
  34. package/.agents/scripts/lib/orchestration/context-hydration-engine.js +3 -4
  35. package/.agents/scripts/lib/orchestration/docs-digest.js +2 -2
  36. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/persist-helpers.js +4 -0
  37. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/persist.js +22 -12
  38. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/authoring-context.js +6 -1
  39. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-diff.js +18 -2
  40. package/.agents/scripts/{lifecycle-diff.js → lib/orchestration/lifecycle/ledger-diff.js} +10 -76
  41. package/.agents/scripts/lib/orchestration/lifecycle/listeners/acceptance-reconciler.js +1 -1
  42. package/.agents/scripts/lib/orchestration/plan-context.js +510 -0
  43. package/.agents/scripts/lib/orchestration/plan-critic-conditions.js +177 -0
  44. package/.agents/scripts/lib/orchestration/plan-metrics.js +445 -0
  45. package/.agents/scripts/lib/orchestration/plan-persist/amend.js +359 -0
  46. package/.agents/scripts/lib/orchestration/plan-persist/delivery-mode.js +127 -0
  47. package/.agents/scripts/lib/orchestration/plan-persist/run-plan-persist.js +978 -0
  48. package/.agents/scripts/lib/orchestration/plan-persist/summary.js +191 -0
  49. package/.agents/scripts/lib/orchestration/plan-reachability.js +160 -0
  50. package/.agents/scripts/lib/orchestration/plan-runner/worktree-sweep.js +3 -3
  51. package/.agents/scripts/lib/orchestration/planning-risk.js +1 -1
  52. package/.agents/scripts/lib/orchestration/spec-freshness.js +1 -1
  53. package/.agents/scripts/lib/orchestration/ticketing/bulk.js +1 -1
  54. package/.agents/scripts/lib/orchestration/ticketing/reads.js +11 -2
  55. package/.agents/scripts/lib/plan-phase-cleanup.js +16 -0
  56. package/.agents/scripts/lib/presentation/manifest-persistence.js +2 -3
  57. package/.agents/scripts/lib/templates/spec-author-prompts.js +74 -0
  58. package/.agents/scripts/plan-context.js +186 -0
  59. package/.agents/scripts/plan-critics.js +227 -0
  60. package/.agents/scripts/plan-persist.js +383 -0
  61. package/.agents/scripts/pr-watch-with-update.js +8 -7
  62. package/.agents/scripts/run-lint.js +10 -11
  63. package/.agents/scripts/story-plan.js +19 -7
  64. package/.agents/scripts/sync-claude-commands.js +10 -5
  65. package/.agents/skills/core/knowledge-transfer/SKILL.md +11 -7
  66. package/.agents/workflows/audit-documentation.md +5 -7
  67. package/.agents/workflows/audit-lighthouse.md +1 -0
  68. package/.agents/workflows/audit-security.md +1 -0
  69. package/.agents/workflows/audit-to-stories.md +16 -5
  70. package/.agents/workflows/git-deliver.md +76 -243
  71. package/.agents/workflows/helpers/_merge-conflict-template.md +1 -1
  72. package/.agents/workflows/helpers/code-review.md +7 -6
  73. package/.agents/workflows/helpers/deliver-epic.md +5 -4
  74. package/.agents/workflows/helpers/plan-epic-reference.md +109 -96
  75. package/.agents/workflows/helpers/plan-epic.md +246 -999
  76. package/.agents/workflows/helpers/plan-story.md +14 -14
  77. package/.agents/workflows/helpers/scope-triage-gate.md +6 -4
  78. package/.agents/workflows/helpers/single-story-deliver.md +5 -4
  79. package/.agents/workflows/helpers/worktree-lifecycle.md +9 -7
  80. package/.agents/workflows/mandrel-update.md +144 -466
  81. package/.agents/workflows/plan.md +73 -143
  82. package/docs/CHANGELOG.md +13 -0
  83. package/lib/cli/registry.js +21 -3
  84. package/package.json +1 -1
  85. package/.agents/schemas/loop-unit.schema.json +0 -70
  86. package/.agents/scripts/assert-branch.js +0 -81
  87. package/.agents/scripts/check-loop-units.js +0 -204
  88. package/.agents/scripts/detect-merges.js +0 -111
  89. package/.agents/scripts/git-pr-quality-gate.js +0 -205
  90. package/.agents/scripts/git-rebase-and-resolve.js +0 -234
  91. package/.agents/scripts/hierarchy-gate.js +0 -192
  92. package/.agents/scripts/hydrate-context.js +0 -179
  93. package/.agents/scripts/lib/loop-units/validate-loop-unit.js +0 -197
  94. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/cli.js +0 -167
  95. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/cli-args.js +0 -69
  96. package/.agents/scripts/lib/orchestration/plan-runner/plan-router.js +0 -86
  97. package/.agents/scripts/loc-delta.js +0 -205
  98. package/.agents/scripts/render-manifest.js +0 -143
  99. package/.agents/scripts/run-audit-suite.js +0 -97
  100. package/.agents/scripts/select-audits.js +0 -155
  101. package/.agents/scripts/update-mutation-baseline.js +0 -189
  102. package/.agents/workflows/explain.md +0 -118
  103. package/.agents/workflows/git-merge-pr.md +0 -377
  104. package/.agents/workflows/helpers/epic-plan-decompose.md +0 -22
  105. package/.agents/workflows/helpers/epic-plan-spec.md +0 -22
  106. package/.agents/workflows/loops/README.md +0 -65
  107. package/.agents/workflows/loops/fix-failing-tests.md +0 -74
  108. package/.agents/workflows/loops/nightly-audit.md +0 -81
  109. package/.agents/workflows/loops/watch-ci.md +0 -68
@@ -1,22 +0,0 @@
1
- ---
2
- description: >-
3
- Thin pointer — Phase 8 (decompose) of sprint planning now lives entirely in
4
- `helpers/plan-epic.md`. This file is kept only so pre-existing links to
5
- `helpers/epic-plan-decompose.md` still resolve.
6
- ---
7
-
8
- # Sprint Plan — Decompose Phase (thin pointer)
9
-
10
- > **Superseded.** This file used to carry its own Phase 8 step-by-step
11
- > procedure — a drifted duplicate of the authoritative one, and a pre-skill
12
- > pattern. Story #4403 collapsed it: the full, current Phase 8 procedure
13
- > (context gathering, the
14
- > [`epic-plan-decompose-author`](../../skills/core/epic-plan-decompose-author/SKILL.md)
15
- > skill activation, the Phase 8.3 consolidation / Phase 8.4 reachability /
16
- > Phase 8.5 pre-mortem critic passes, the persist call, cross-validation, and
17
- > cleanup) lives in
18
- > [`helpers/plan-epic.md` § Phase 8](plan-epic.md#phase-8-work-breakdown-decomposition).
19
- > Read that section — do not resurrect an inline copy here.
20
-
21
- The complementary Phase 7 pointer is
22
- [`helpers/epic-plan-spec.md`](epic-plan-spec.md).
@@ -1,22 +0,0 @@
1
- ---
2
- description: >-
3
- Thin pointer — Phase 7 (spec) of sprint planning now lives entirely in
4
- `helpers/plan-epic.md`. This file is kept only so pre-existing links to
5
- `helpers/epic-plan-spec.md` still resolve.
6
- ---
7
-
8
- # Sprint Plan — Spec Phase (thin pointer)
9
-
10
- > **Superseded.** This file used to carry its own Phase 7 step-by-step
11
- > procedure — a drifted duplicate of the authoritative one, and a pre-skill
12
- > pattern that instructed inline authoring from the envelope's
13
- > (now-retired) `systemPrompts` field. Story #4403 collapsed it: the full,
14
- > current Phase 7 procedure (context gathering, the
15
- > [`epic-plan-spec-author`](../../skills/core/epic-plan-spec-author/SKILL.md)
16
- > skill activation, the persist call and its folded Tech Spec section gate,
17
- > review routing, freshness/BDD advisories, and cleanup) lives in
18
- > [`helpers/plan-epic.md` § Phase 7](plan-epic.md#phase-7-epic-planning-tech-spec--acceptance-spec).
19
- > Read that section — do not resurrect an inline copy here.
20
-
21
- The complementary Phase 8 pointer is
22
- [`helpers/epic-plan-decompose.md`](epic-plan-decompose.md).
@@ -1,65 +0,0 @@
1
- # Loop units (`.agents/workflows/loops/`)
2
-
3
- A **loop unit** is a markdown file that defines one unit of *recurring* work
4
- with a checkable definition of done. Each file's leading YAML frontmatter
5
- carries a `loop:` block — a cadence, a goal, an optional `verify` oracle, a
6
- round cap, and an exhaustion policy — validated against
7
- [`.agents/schemas/loop-unit.schema.json`](../../schemas/loop-unit.schema.json)
8
- by `node .agents/scripts/check-loop-units.js` (wired into `npm run lint`).
9
-
10
- This directory is the **one** namespaced exception to the flat slash-command
11
- projection. Files here project to `.claude/commands/loops/<name>.md` and are
12
- invoked as the namespaced `/loops:<name>` command (flat fallback
13
- `/loops-<name>` on hosts that flatten subdirectory commands). Every other
14
- top-level workflow projects flat as `/<name>`; `helpers/` is not projected at
15
- all.
16
-
17
- ## What a loop unit is — and is not
18
-
19
- A loop unit ships **content and contract**, not a runner. It declares:
20
-
21
- - **the action** — what one round does;
22
- - **the goal** — the standing objective each round works toward;
23
- - **the `verify` oracle** — the runnable check that proves a round is complete
24
- (required for `self-paced` cadence, optional for `interval` / `cron`); and
25
- - **the observability / escalation contract** — the `maxRounds` backstop, the
26
- `onExhaust` policy, and the explicit "stop & escalate" conditions in the body.
27
-
28
- It does **not** ship the loop driver. **Cadence and iteration are owned by the
29
- host** — Claude Code's built-in `/loop` (self-paced or interval) and
30
- `/schedule` (cron). Mandrel deliberately ships **no** `/goal` or `/loop`
31
- runner of its own. The full rationale, and why this division exists, is fixed
32
- in the ADR:
33
-
34
- > [`docs/decisions/loop-units-division-of-labor.md`](../../../docs/decisions/loop-units-division-of-labor.md)
35
- > — *Loop units: mandrel owns content + oracle + contract; the host owns
36
- > cadence + iteration; no runner shipped.*
37
-
38
- Read that ADR before adding a runner, a scheduler, or a `/goal` command to the
39
- framework — the decision to **not** build one is deliberate.
40
-
41
- ## Cadence → host mapping
42
-
43
- | Cadence | `verify` | Driven by | Starter unit |
44
- | ------------- | -------- | --------------------------------- | -------------------------------------------------------------- |
45
- | `self-paced` | required | `/loop` (no interval) | [`fix-failing-tests.md`](fix-failing-tests.md) — red → green |
46
- | `interval` | optional | `/loop <interval>` (e.g. `/loop 5m`) | [`watch-ci.md`](watch-ci.md) — poll a PR's checks |
47
- | `cron` | optional | `/schedule` (cron-driven) | [`nightly-audit.md`](nightly-audit.md) — nightly audit sweep |
48
-
49
- A `self-paced` unit **must** carry a `verify` oracle because nothing external
50
- paces it — the oracle is the only signal that tells the host when to stop.
51
- `interval` and `cron` units are paced by an external scheduler, so a
52
- terminating oracle is optional; they observe, report, and yield each tick.
53
-
54
- ## Authoring a new loop unit
55
-
56
- 1. Create `.agents/workflows/loops/<name>.md` with a `loop:` frontmatter block
57
- (`cadence` + `goal` required; add `verify` for `self-paced`).
58
- 2. Give it a `description:` so it shows up in the generated catalog
59
- ([`.agents/docs/workflows.md`](../../docs/workflows.md), **Loops namespace**).
60
- 3. Body sections: **Action** (what one round does), **Goal & done-signal** (the
61
- objective and the oracle/stop check), **Stop & escalate** (when to hand back
62
- rather than loop).
63
- 4. Run `node .agents/scripts/check-loop-units.js` (or `npm run lint`) to
64
- validate the frontmatter, then `npm run sync:commands` to project it to
65
- `/loops:<name>` and `npm run docs:gen` to refresh the catalog.
@@ -1,74 +0,0 @@
1
- ---
2
- description: >-
3
- Self-paced convergence loop that drives a red test suite to green. Each round
4
- reads the latest failure, applies the smallest fix, and re-runs the verify
5
- oracle (`npm test`); the loop terminates when the oracle exits 0. The host
6
- (`/loop`) owns iteration and pacing — mandrel supplies the action, the goal,
7
- and the terminating oracle.
8
- loop:
9
- cadence: self-paced
10
- goal: >-
11
- Drive the project's test suite from red to green by fixing the root cause of
12
- each failure, one round at a time, until the verify oracle passes.
13
- verify: npm test
14
- maxRounds: 10
15
- onExhaust: hand-back
16
- ---
17
-
18
- # /loops:fix-failing-tests — drive a red suite to green
19
-
20
- A **self-paced convergence loop**. The host (`/loop` with no interval) decides
21
- when to run the next round; this unit supplies the action each round performs,
22
- the standing goal, and the runnable `verify` oracle that tells the host when to
23
- stop. When `npm test` exits 0, the goal is met and the loop terminates.
24
-
25
- > **Scope.** This loop fixes the **root cause** of failing tests. It does not
26
- > delete, skip, `.only`, or weaken assertions to force a green bar — that is an
27
- > escalation condition, not a round (see **Stop & escalate** below).
28
-
29
- ## Action
30
-
31
- Each round:
32
-
33
- 1. **Read the latest failure.** Run the verify oracle (`npm test`) and read the
34
- first failing assertion — name, file, and the expected-vs-actual diff. Fix
35
- one failure cluster per round; do not fan out across unrelated failures in a
36
- single round.
37
- 2. **Diagnose the root cause.** Decide whether the failure is in the production
38
- code under test or in the test's own setup/expectation. Prefer the
39
- smallest change that makes the assertion honest — fix the code when the test
40
- encodes the intended contract; fix the test only when it asserts the wrong
41
- thing and you can state why in one sentence.
42
- 3. **Apply the smallest fix.** Make the minimal edit that addresses the
43
- diagnosed cause. Avoid speculative refactors — convergence depends on each
44
- round changing exactly one thing.
45
- 4. **Re-run the oracle.** Run `npm test` again. A reduced failure count is
46
- progress; a new failure introduced by the fix means the diagnosis was wrong
47
- — revert and re-diagnose rather than stacking another fix on top.
48
-
49
- ## Goal & done-signal
50
-
51
- - **Goal:** the test suite passes — every test green, no skipped-to-hide
52
- failures.
53
- - **Done-signal (the oracle):** `npm test` exits 0. This is the single
54
- terminating check the host `/loop` evaluates after each round. When it
55
- passes, stop — the loop is complete.
56
- - **Backstop:** `maxRounds: 10`. If the oracle is still red after ten rounds,
57
- the `onExhaust: hand-back` policy returns control to the caller with a
58
- summary rather than looping indefinitely.
59
-
60
- ## Stop & escalate
61
-
62
- Stop the loop and hand back (do **not** keep iterating) when:
63
-
64
- - **The same failure survives the same class of fix twice.** Per the
65
- anti-thrashing protocol, a repeated fix against an unchanged failure means
66
- the diagnosis is wrong — stop and report what you tried.
67
- - **A fix would weaken the contract.** If the only way to make the bar green is
68
- to delete a test, add `.skip` / `.only`, or relax an assertion to match buggy
69
- behaviour, that is a product decision, not a loop round. Stop and surface it.
70
- - **The failure is environmental, not a code defect** (missing service, absent
71
- credential, a flaky timing-dependent test). The loop cannot converge on an
72
- external cause — report the blocker so the operator can resolve it.
73
- - **`maxRounds` is reached with the oracle still red.** Hand back a summary of
74
- the remaining failures and the rounds spent.
@@ -1,81 +0,0 @@
1
- ---
2
- description: >-
3
- Cron maintenance loop that runs a nightly audit sweep over the repository and
4
- files actionable findings. Each run executes the audit workflows and routes
5
- the results; the host (`/schedule` or a cron-driven `/loop`) owns the cadence.
6
- verify is optional for a cron loop — the scheduler owns iteration, so this
7
- unit ships the action and goal, not a terminating oracle.
8
- loop:
9
- cadence: cron
10
- goal: >-
11
- Keep the repository's standing health surfaced by running the audit sweep on
12
- a nightly schedule and turning each fresh finding into an actionable, deduped
13
- record so regressions are caught within a day rather than at release time.
14
- maxRounds: 30
15
- onExhaust: report
16
- ---
17
-
18
- # /loops:nightly-audit — scheduled maintenance audit sweep
19
-
20
- A **cron maintenance loop**. The host (`/schedule`, or a cron-driven `/loop`)
21
- owns the cadence and fires this unit once per scheduled window — typically
22
- overnight. Because the scheduler owns iteration, this unit carries **no
23
- `verify` oracle**: per the loop-unit schema, `verify` is required only for
24
- `self-paced` cadence and optional for `interval` / `cron`. Each run is a single
25
- sweep that observes, records, and yields until the next scheduled tick.
26
-
27
- ## Action
28
-
29
- Each scheduled run:
30
-
31
- 1. **Run the audit sweep.** Execute the relevant audit workflows for the repo
32
- (`/audit-security`, `/audit-clean-code`, `/audit-dependencies`,
33
- `/audit-quality`, and any others the project relies on). Each audit writes a
34
- structured `temp/audits/audit-*-results.md` report — that is the canonical
35
- artifact this loop consumes, not free-form prose. Because these audits are
36
- **independent** of one another, a scheduled run **may fan them out to
37
- parallel sub-agents** (one per audit) rather than walking them serially:
38
- dispatch one general-purpose sub-agent per lens, each instructed to read
39
- its `/audit-<lens>` workflow and write the structured report. Each
40
- sub-agent returns only its structured report; the scheduler/host owns the
41
- fan-out just as it owns the cadence, and each per-audit strategy
42
- (sequential or orchestrated) is unchanged by running under its own
43
- sub-agent. (The former `/deliver` Phase 4 audit-orchestrator pattern this
44
- note used to cite was retired by Story #4412, which folded the Epic-close
45
- lens walk into the Phase 5 code-review pass.)
46
- 2. **Diff against the prior night.** Compare the fresh findings against the last
47
- sweep's reports and against already-open Issues. A finding seen before is
48
- not new signal; only genuinely fresh or regressed findings warrant a record.
49
- 3. **Route fresh findings.** Hand the new findings to `/audit-to-stories`, which
50
- deduplicates against existing Issues by fingerprint and either chains into
51
- `/plan` or opens standalone Stories. Do not open raw duplicate Issues —
52
- dedup is the loop's job, not the operator's.
53
- 4. **Report and yield.** Emit a short digest (sweeps run, new findings, Issues
54
- opened or updated) and return control to the scheduler, which sleeps until
55
- the next cron window.
56
-
57
- ## Goal & done-signal
58
-
59
- - **Goal:** the repository's health regressions are caught and turned into
60
- actionable, deduplicated records within a day, without a human remembering to
61
- run the audits by hand.
62
- - **Done-signal:** the nightly sweep completed and every fresh finding has been
63
- routed to a record (or explicitly judged a non-finding). A cron loop has no
64
- self-evaluated oracle — the scheduler owns whether the loop runs again; this
65
- unit simply finishes the night's sweep and yields.
66
- - **Backstop:** `maxRounds: 30`. Roughly a month of nightly runs;
67
- `onExhaust: report` emits a final digest and stops so a long-lived schedule
68
- is renewed deliberately rather than running unbounded.
69
-
70
- ## Stop & escalate
71
-
72
- - **An audit cannot run** (a required tool is missing, the audit harness errors,
73
- the working tree is dirty in a way that invalidates the sweep). Report the
74
- failure for that audit and continue with the others — do not abort the whole
75
- night because one audit broke.
76
- - **A finding is high-severity and time-sensitive** (an exposed secret, a
77
- critical CVE reachable in production). Surface it loudly in the digest rather
78
- than letting it sit as one row among many — a nightly cadence is too slow for
79
- an actively-exploitable finding.
80
- - **`maxRounds` is reached.** Emit a final digest (`onExhaust: report`) so the
81
- operator can renew or retire the schedule deliberately.
@@ -1,68 +0,0 @@
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.