@bridge_gpt/mcp-server 0.2.66 → 0.2.68

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 (171) hide show
  1. package/README.md +421 -83
  2. package/build/agent-capabilities/probes.js +15 -5
  3. package/build/agent-launchers/claude-executor-adapter.js +70 -16
  4. package/build/agent-launchers/executor-adapter.js +7 -4
  5. package/build/agents.generated.js +22 -2
  6. package/build/bitbucket-workspace-remote.js +136 -0
  7. package/build/bootstrap-project-identity.js +24 -0
  8. package/build/bounded-wait.js +67 -10
  9. package/build/bridge-permissions.js +829 -0
  10. package/build/claude-settings.js +18 -0
  11. package/build/cli-help.js +21 -0
  12. package/build/command-assets-doctor.js +24 -70
  13. package/build/command-provisioning.js +29 -5
  14. package/build/commands.generated.js +12 -12
  15. package/build/conductor/bridge-api-client.js +857 -1
  16. package/build/conductor/bring-up-facts.js +1 -1
  17. package/build/conductor/command-drift-production.js +92 -0
  18. package/build/conductor/command-drift.js +89 -0
  19. package/build/conductor/doctor.js +72 -29
  20. package/build/conductor/epic-branch-ci-inspection.js +1375 -0
  21. package/build/conductor/epic-implementer-cli.js +98 -28
  22. package/build/conductor/errors.js +4 -3
  23. package/build/conductor/gate-discovery.js +890 -0
  24. package/build/conductor/guided-repair.js +6 -2
  25. package/build/conductor/hook-runtime-qualification.js +1 -1
  26. package/build/conductor/install-doctor.js +15 -3
  27. package/build/conductor/json-output.js +63 -0
  28. package/build/conductor/merge-execution-contract.js +27 -8
  29. package/build/conductor/merge-execution-eligibility.js +3 -2
  30. package/build/conductor/pr-ci-producer.js +1 -1
  31. package/build/conductor/readiness-cli.js +113 -12
  32. package/build/conductor/readiness-sections.js +410 -9
  33. package/build/conductor/readiness.js +388 -33
  34. package/build/conductor/recovery-cli.js +310 -12
  35. package/build/conductor/recovery-operations.js +167 -3
  36. package/build/conductor/repair-contract.js +54 -3
  37. package/build/conductor/repository-workflow-remedy.js +125 -0
  38. package/build/conductor/tools.js +2 -2
  39. package/build/conductor-bundle-artifacts.js +8 -0
  40. package/build/connect-bitbucket-api.js +41 -6
  41. package/build/connect-bitbucket.js +106 -33
  42. package/build/credential-store.js +207 -47
  43. package/build/docs.generated.js +62 -3
  44. package/build/doctor.js +92 -1
  45. package/build/drive-epic-key.js +6 -5
  46. package/build/drive-epic.js +129 -61
  47. package/build/epic-coherence-input.js +2 -1
  48. package/build/epic-coherence-input.test-fixtures.js +4 -3
  49. package/build/epic-implementer-bin.js +1379 -28
  50. package/build/epic-implementer-bundle-cli.js +2 -2
  51. package/build/epic-workarounds-path.js +39 -0
  52. package/build/executor/cli.js +33 -2
  53. package/build/executor/completion-contract.js +66 -10
  54. package/build/executor/completion-supervision.js +4 -0
  55. package/build/executor/deps.js +4 -1
  56. package/build/executor/env.js +19 -0
  57. package/build/executor/gate-qualification-job.js +499 -0
  58. package/build/executor/guarded-fast-forward-push.js +129 -0
  59. package/build/executor/heartbeat.js +1 -1
  60. package/build/executor/http-client.js +20 -0
  61. package/build/executor/integration-job.js +122 -8
  62. package/build/executor/job-errors.js +33 -1
  63. package/build/executor/job-runner.js +813 -87
  64. package/build/executor/likely-tests.js +290 -0
  65. package/build/executor/live-worker-registry.js +1 -1
  66. package/build/executor/observation.js +37 -3
  67. package/build/executor/packaged-recipe.js +106 -0
  68. package/build/executor/permissions.js +115 -28
  69. package/build/executor/platform.js +1 -1
  70. package/build/executor/preflight.js +112 -26
  71. package/build/executor/process-containment.js +36 -12
  72. package/build/executor/process.js +15 -7
  73. package/build/executor/prompt-spec.js +33 -1
  74. package/build/executor/recently-failed-tests-file.js +71 -0
  75. package/build/executor/reconcile-overlap-job.js +41 -23
  76. package/build/executor/required-verification.js +1 -1
  77. package/build/executor/required-work-ledger.js +111 -18
  78. package/build/executor/resume-pre-spawn.js +2 -0
  79. package/build/executor/retirement.js +69 -0
  80. package/build/executor/runner.js +122 -13
  81. package/build/executor/service-unit.js +7 -1
  82. package/build/executor/test-clock.js +15 -0
  83. package/build/executor/types.js +32 -0
  84. package/build/executor/viewer-tabs.js +58 -8
  85. package/build/executor/worker-command.js +23 -7
  86. package/build/executor/worker-diagnostics.js +37 -0
  87. package/build/executor/worker-finalization.js +113 -34
  88. package/build/executor/worker-guard-hook.js +316 -58
  89. package/build/executor/worker-log.js +4 -3
  90. package/build/executor/worker-verification-guidance.js +37 -0
  91. package/build/executor/worktree.js +166 -8
  92. package/build/first-build-advisory.js +97 -0
  93. package/build/generated-assets-advisory.js +14 -0
  94. package/build/generated-assets-catalog.js +66 -0
  95. package/build/generated-assets-context.js +46 -0
  96. package/build/generated-assets-dependencies.js +26 -0
  97. package/build/generated-assets-doctor.js +50 -0
  98. package/build/generated-assets-health.js +65 -0
  99. package/build/generated-assets-host.js +17 -0
  100. package/build/generated-assets-inventory.js +17 -0
  101. package/build/generated-assets-paths.js +60 -0
  102. package/build/generated-assets-publisher.js +133 -0
  103. package/build/generated-assets-remedy.js +25 -0
  104. package/build/generated-assets-repair.js +72 -0
  105. package/build/generated-assets-session.js +71 -0
  106. package/build/generated-assets-test-support.js +35 -0
  107. package/build/index.js +1224 -1054
  108. package/build/init.js +54 -177
  109. package/build/install-bridge-conductor-gate.js +1372 -0
  110. package/build/install-bridge-conductor.js +296 -41
  111. package/build/install-bridge.js +547 -40
  112. package/build/mcp-install-state.js +50 -4
  113. package/build/merge-workflow-install.js +3 -4
  114. package/build/phase-context-git-probe.js +68 -0
  115. package/build/phase-result-artifacts.js +173 -5
  116. package/build/pipeline-utils.js +6 -2
  117. package/build/pipelines.generated.js +34 -160
  118. package/build/plan-execution-ledger.js +2 -32
  119. package/build/plane/alembic-head.js +12 -3
  120. package/build/plane/base-worktree-guard.js +147 -0
  121. package/build/plane/cli.js +217 -17
  122. package/build/plane/code-snapshot.js +468 -0
  123. package/build/plane/defaults.js +48 -3
  124. package/build/plane/endpoint.js +41 -0
  125. package/build/plane/manifest.js +136 -2
  126. package/build/plane/member-roster.js +94 -19
  127. package/build/plane/preflight.js +83 -2
  128. package/build/plane/process-cwd.js +67 -0
  129. package/build/plane/restart.js +542 -0
  130. package/build/plane/shutdown.js +31 -0
  131. package/build/plane/status.js +143 -8
  132. package/build/plane/supervisor.js +586 -179
  133. package/build/plane/types.js +54 -2
  134. package/build/printed-remedy-commands.js +52 -0
  135. package/build/readiness-check.js +1 -1
  136. package/build/readme.generated.js +1 -1
  137. package/build/repair-assets.js +93 -0
  138. package/build/review-generation.js +22 -0
  139. package/build/run-unit-tests-launcher.js +130 -49
  140. package/build/secret-redaction.js +33 -0
  141. package/build/setup-epic.js +152 -22
  142. package/build/sfcc/config.js +9 -0
  143. package/build/sfcc/credentials.js +100 -38
  144. package/build/sfcc/hostname.js +67 -0
  145. package/build/sfcc/permissions.js +17 -13
  146. package/build/sfcc/register.js +1 -1
  147. package/build/sfcc/tool-wrapper.js +39 -43
  148. package/build/sfcc/write-grants.js +17 -11
  149. package/build/sfcc/write-result.js +4 -3
  150. package/build/sfcc/writes-site-preference.js +20 -8
  151. package/build/start-tickets-prereqs.js +70 -16
  152. package/build/start-tickets.js +208 -36
  153. package/build/tool-error-envelope.js +61 -0
  154. package/build/tool-surface-gating.js +36 -0
  155. package/build/upgrade-cli.js +55 -1
  156. package/build/version.generated.js +3 -3
  157. package/build/visual-diff.js +22 -1
  158. package/build/worker-guard-hook-bin.js +4 -6
  159. package/build/worker-guard-hook-main.js +47 -0
  160. package/build/worktree-core.js +145 -6
  161. package/docs/EPIC-IMPLEMENTER-INSTALL.md +867 -0
  162. package/docs/EPIC-IMPLEMENTER.md +728 -0
  163. package/docs/install/mcp-tool-integrations.md +24 -15
  164. package/docs/install/sfcc-integration.md +12 -4
  165. package/package.json +3 -3
  166. package/pipelines/greenfield-setup.json +4 -128
  167. package/pipelines/implement-ticket.json +3 -2
  168. package/pipelines/plan-epic.json +0 -5
  169. package/pipelines/review-ticket.json +1 -1
  170. package/docs/CONDUCTOR.md +0 -605
  171. package/pipelines/idea-to-pr.json +0 -49
@@ -0,0 +1,728 @@
1
+ # Epic Implementer — driving a multi-ticket epic
2
+
3
+ The **Epic Implementer** drives a multi-ticket epic from an approved plan to
4
+ `done`. It dispatches each child ticket to an agent, watches CI and review, merges
5
+ each child PR, and re-indexes the repository after each merge.
6
+
7
+ > **Naming.** The Epic Implementer used to be called the "Conductor". It was
8
+ > renamed in BAPI-1077 to BAPI-1083, BAPI-1190, BAPI-1232, and BAPI-1233. A few
9
+ > real identifiers still carry the old name and are spelled as-is below: the
10
+ > `--conductor` flag on `start-tickets`, the `install conductor` subcommand, the
11
+ > `mcp_server/src/conductor/` source directory, and two retired `conductor` bins.
12
+
13
+ It has two parts. Keep them apart when you read this guide:
14
+
15
+ | Part | What it is | Opt-in? |
16
+ | --- | --- | --- |
17
+ | **The v2 engine** | A server-side **reconciler** plus a local **executor**. This is what drives an epic. | No. It runs for every epic run. |
18
+ | **The observability layer** | A local event ledger, Claude Code lifecycle hooks, optional git hooks, and a supervisor tab for `start-tickets --conductor` runs. | Yes, per run, with `--conductor`. |
19
+
20
+ For the everyday `start-tickets` flags, see
21
+ [README → CLI Subcommands](../README.md#cli-subcommands).
22
+
23
+ ## How the v2 engine works
24
+
25
+ | Half | Where it runs | What it does |
26
+ | --- | --- | --- |
27
+ | **Reconciler** | Server-side, on the Bridge API worker, about every 30s | Picks up every run whose status is `active`, evaluates each ticket's gates, and queues executor jobs. It is the **only** component that decides a transition. Nothing to install or schedule. |
28
+ | **Executor** | Locally, on your machine | Polls for jobs, claims them, spawns worker agents, and heartbeats. Workers report facts; the reconciler decides. |
29
+
30
+ **Run statuses** are `planning`, `pending_approval`, `active`, `blocked`,
31
+ `abandoned`, and `done`. A paused, quarantined, or stopped run is `blocked` with a
32
+ typed run-control record that says why and what clears it.
33
+
34
+ **Ticket statuses** are `planned`, `spec_review`, `implementing`, `ci`,
35
+ `code_review`, `merging`, `parsing`, `smoke`, `needs_human`, `done`, and
36
+ `abandoned`. A ticket that needs a person **parks** as `needs_human`. See
37
+ [Recovering a parked run](#recovering-a-stuck-or-parked-run).
38
+
39
+ **The v1 `epic-implementer epic-tick` command is frozen.** It throws
40
+ `EPIC_TICK_V1_FROZEN` and advances nothing. There is nothing to schedule
41
+ locally. If you registered an epic-tick schedule with an older release, remove
42
+ it; it is a dead timer.
43
+
44
+ ## Drive an epic: `drive-epic`
45
+
46
+ `drive-epic` is the **one entry point** for running an epic. It reads the
47
+ server's readiness report and routes to exactly one path. You never choose
48
+ between engines.
49
+
50
+ ```
51
+ npx -y @bridge_gpt/mcp-server drive-epic BAPI-405 \
52
+ --plan-file docs/tmp/epic-plans/<slug>/epic-plan.dag.json
53
+ ```
54
+
55
+ Run it from a Git checkout of the target repository. In one command it:
56
+
57
+ 1. Checks readiness and, for an unattended run, the unattended prerequisites.
58
+ A check that fails here creates nothing.
59
+ 2. Validates the plan with the server's real validator, then creates and approves
60
+ the run (it delegates this to `setup-epic`).
61
+ 3. Starts a **run-scoped executor** for the run in the background (BAPI-1279). It
62
+ claims only that run's jobs, logs to `.bridge/executors/<run>.log`, and exits by
63
+ itself when the run is `done` or `abandoned`. Re-running `drive-epic` for the
64
+ same live run never starts a second one.
65
+
66
+ **Finding the plan.** `--plan-file` is optional. Without it, `drive-epic` looks
67
+ for `{docs_dir}/epic-plans/*/epic-plan.meta.json` naming this epic, where
68
+ `docs_dir` is `BAPI_DOCS_DIR` or `docs/tmp`. It uses exactly one match. No match,
69
+ or more than one, stops with the paths it found. The plan files come from the
70
+ epic planning flow (`/define-tickets` for an epic, or `/plan-epic`).
71
+
72
+ **A live run with no plan.** If the epic already has a live run and you pass no
73
+ plan, `drive-epic` creates nothing. It makes sure the run has an executor and
74
+ reports it.
75
+
76
+ **Preview first.** `--dry-run` resolves the target, reads readiness and any live
77
+ run, finds the plan, and runs the server's plan validation. It changes nothing.
78
+ Add `--json` for one machine-readable document. It exits `0` for create or
79
+ attach, and `1` for refuse or stop.
80
+
81
+ ### Main flags
82
+
83
+ | Flag | Meaning |
84
+ | --- | --- |
85
+ | `--plan-file <path>` | The plan DAG. Optional (see above). |
86
+ | `--repo <name>` | Repo name. Default: `BAPI_REPO_NAME` or `.bridge/config`. |
87
+ | `--feature-branch <name>` | Use your own epic branch name. |
88
+ | `--into-base` | Opt out of the epic branch; child PRs target the base branch. |
89
+ | `--attended` | Opt out of the unattended default (see below). |
90
+ | `--policy-file <path>` | The **complete** run policy, applied when the run is created. |
91
+ | `--review-policy <src>` | The review policy for this run only: `repository_policy`, `verdict_protocol`, `native_review_decision`, or `none`. Omit it and the server stamps `repository_policy` at first approval for a new feature-branch run. `verdict_protocol` (AI review) is an explicit opt-in. An already-approved run with no stored policy is unchanged and still resolves to `verdict_protocol`. |
92
+ | `--replace-policy` | Allow replacing a live run's stored policy with `--policy-file`. |
93
+ | `--launch-profile <name>` | Use a host-local launch profile approved by `install conductor --launch-profile <name>`. `BAPI_EPIC_LAUNCH_PROFILE` selects one too; the flag wins. |
94
+ | `--base-url <url>` | Explicit Bridge API target. It must agree with a profile. |
95
+ | `--dry-run`, `--json` | Read-only preview (see above). |
96
+
97
+ **Target.** With no profile, `--base-url`, or `BAPI_BASE_URL`, `drive-epic`
98
+ targets production.
99
+
100
+ ### Unattended by default
101
+
102
+ A run on an epic branch is created **unattended**. Child PRs merge automatically
103
+ into the epic branch. The one **integration PR** from the epic branch into the
104
+ base branch stays human-gated: a person merges it. Pass `--attended` to opt out;
105
+ the run then has no auto-merge authorization.
106
+
107
+ An unattended run needs three things. Each is refused **by name** before any run
108
+ is created, and `drive-epic --dry-run` lists them:
109
+
110
+ | Prerequisite | How to satisfy it |
111
+ | --- | --- |
112
+ | Repository consent | On by default. The repository owner can switch "Allow unattended Epic Implementer runs" off and on in the Bridge admin panel's Setup page. |
113
+ | An escalation channel | A `--policy-file` that declares `notify.webhook_url`, **or** an email address on the account. `notify.local_sink` does not count. |
114
+ | Repository readiness | `.github/workflows/epic-implementer-ci.yml` confirmed on the default branch, plus `.github/workflows/claude-review.yml` when the run uses AI review (`verdict_protocol`). A first-approval feature-branch run with no policy set needs no review workflow. The refusal names what is missing. |
115
+
116
+ **Merge-execution eligibility.** If the repository cannot perform a merge without
117
+ a standing write credential, `setup-epic` refuses with
118
+ `merge_execution_ineligible`, names the remedy
119
+ `npx -y @bridge_gpt/mcp-server install conductor --merge-workflow --codeowner <@org/team|@user>`
120
+ (replace the placeholder with the one `@user` or `@org/team` who should review the
121
+ workflow file; Bridge cannot infer it), and ends with `No run was created.`
122
+ This applies to attended and unattended runs alike.
123
+
124
+ ### Branch strategy
125
+
126
+ A plan with **two or more** nodes runs on a dedicated `epic/<KEY>` branch. Every
127
+ child PR targets that branch, and one **draft** integration PR targets the base
128
+ branch.
129
+
130
+ | You want | Pass |
131
+ |---|---|
132
+ | The epic branch on a plan with 2 or more nodes | *nothing* — it is the default |
133
+ | Your own branch name, or a branch for a single-node plan | `--feature-branch <name>` |
134
+ | Direct-to-base (the pre-BAPI-1009 behavior) | `--into-base` |
135
+
136
+ A single-node plan keeps the base branch by default. `--feature-branch` and
137
+ `--into-base` together are a parse error.
138
+
139
+ On an epic-branch run, a shadow-index check that cannot be proven right away
140
+ **holds, then parks**: independent tickets go on, a dependent ticket waits, and
141
+ past the deadline it parks as `needs_human`. The run's gate snapshot carries a
142
+ `shadow_hold` object naming the reason and the recovery.
143
+
144
+ ### `setup-epic` (what `drive-epic` delegates to)
145
+
146
+ `setup-epic --epic-key <KEY> --plan-file <path>` creates the run, stores the
147
+ plan, and approves it. `drive-epic` calls it for you; call it yourself only when
148
+ you need its lower-level flags (`--plan-version`, `--local-only`).
149
+
150
+ - It validates the plan locally (unique keys, resolvable `depends_on`, no cycles),
151
+ then with the server's real validator, **before** creating anything. A bad plan
152
+ creates no run and incurs no automation-start charge.
153
+ - It is **idempotent**: re-running on an epic with a live run reuses that run.
154
+ - `--dry-run` runs the server's validation and stops. `--dry-run --local-only`
155
+ skips the server and is labeled `partial (local checks only)`.
156
+
157
+ Unlike `drive-epic`, `setup-epic` does not start an executor.
158
+
159
+ ### One command for the whole session: `/drive-epic-run`
160
+
161
+ The `/drive-epic-run <EPIC> [<plan path>]` slash command wraps all of this for an
162
+ agent session. It previews with `drive-epic --dry-run`, asks you once, creates the
163
+ run through `drive-epic`, and then watches the run until it is terminal. It may
164
+ apply one sanctioned recovery verb at a time, within a fixed scope and budget, and
165
+ records each one. It never edits gate state or code.
166
+
167
+ ## The executor
168
+
169
+ `drive-epic` starts the executor for you. Start one by hand only for a durable
170
+ host or a manual recovery:
171
+
172
+ ```
173
+ npx -y @bridge_gpt/mcp-server executor --repo <name> --epic-run-id <id>
174
+ ```
175
+
176
+ - **A claim scope is required** (BAPI-1026). Pass exactly one of
177
+ `--epic-run-id <id>` (repeatable) or `--repo-wide`. With neither, the executor
178
+ refuses to start.
179
+ - **A base URL is required.** Pass `--base-url` or set `BAPI_BASE_URL`. The
180
+ executor never falls back to production.
181
+ - `--exit-when-run-terminal` exits once the one `--epic-run-id` run is finished.
182
+ - `--once` runs a single claim cycle. `--max-concurrent` defaults to 1.
183
+ - `executor watch <job-id>` attaches read-only to a job's worker log.
184
+ - `executor install-service --executor-id <id> ...` writes one launchd (macOS) or
185
+ systemd (Linux) user unit so an executor survives a reboot. For the guided,
186
+ consented setup, use `install conductor` instead.
187
+
188
+ > **Running against a local Bridge API server? Do not use `npx`.** The published
189
+ > package often lags the server's source. A newer server can send a `prompt_spec`
190
+ > the older executor rejects (`ContractError.Prompt ... unsupported placeholder`).
191
+ > Build and run the local tree so both come from the same commit:
192
+ >
193
+ > ```
194
+ > cd mcp_server && npm run build
195
+ > node mcp_server/build/index.js executor --repo <name> --epic-run-id <id>
196
+ > ```
197
+
198
+ **The plane.** `plane up|status|down` brings up a whole local stack in one
199
+ command: the Bridge API server, the dead-man observer, the reconciler worker, and
200
+ scoped executor lanes. It is for operators who run the Bridge API server
201
+ themselves, and it runs executors from that checkout's `mcp_server/build/`.
202
+ `drive-epic` starts or attaches to a plane on its own when `BAPI_BASE_URL` names
203
+ the local plane endpoint.
204
+
205
+ ## The CI gate
206
+
207
+ Each ticket's `ci` gate reads `policy_json.required_checks` and waits for those
208
+ checks at the ticket PR's **current head SHA**.
209
+
210
+ **The server stamps the CI gate at first approval** when your policy declares
211
+ neither `required_checks` nor `no_ci_gate`:
212
+
213
+ 1. If the repository's default done gate (`done_gate_config`, see
214
+ [below](#supervisor-config)) lists required checks, those become the run's
215
+ `required_checks`.
216
+ 2. Otherwise, on an epic-branch run that auto-merges, and whose plan declares no
217
+ node-level checks, the server records `no_ci_gate: true`. That run's `ci` gate
218
+ passes without CI.
219
+ 3. Otherwise nothing is stamped.
220
+
221
+ **With a confirmed gate profile (BAPI-1390)** the stamp follows the profile
222
+ instead, and always records `gate_profile_revision` and a `gate_profile_snapshot`
223
+ that later profile edits never change:
224
+
225
+ | Profile kind | Stamped when no CI key and no node checks | Auto-merge |
226
+ |---|---|---|
227
+ | `provider` / `mixed` | `required_checks` = the confirmed provider checks | kept (`mixed` needs both executor rollout switches on) |
228
+ | `local` | `no_ci_gate: true`; each merge gated by executor verification of the profile's commands | kept on an epic-branch run with both switches on, else `false` (`local_gate_verification_disabled`) |
229
+ | `none` | `no_ci_gate: true` | always `false` — every child merge waits for `merge-child` |
230
+
231
+ A plan with node-level checks never gets `no_ci_gate` from the profile. An
232
+ operator `no_ci_gate` under `provider`/`mixed` is kept; under `none` with
233
+ auto-merge it is refused (`operator_ci_key_conflicts_with_gate`). A run-level or
234
+ plan-level `required_checks` that drops a confirmed provider check is refused.
235
+
236
+ **Gate-profile evidence bounds.** Before an unattended auto-merging run is
237
+ admitted, every confirmed provider check must have **reported** (passing or not)
238
+ on one of the last **12 default-branch commits** or **8 previously merged PR
239
+ heads** from the last **90 days**, read under a fixed request budget. PRs of the
240
+ run being admitted never count.
241
+
242
+ | Admission reason | Meaning | Remedy |
243
+ |---|---|---|
244
+ | `provider_check_unseen` | The named check never reported in that window | Make the check report on the default branch once, or edit the gate profile |
245
+ | `provider_evidence_unavailable` | The walk could not finish (rate limit, permission, truncation, moving head) | Retry readiness; escalate to Bridge operations if it persists |
246
+ | `local_command_unqualified` | No current passing executor qualification for the profile's revision and command digests | Qualify the local commands, then retry |
247
+ | `migration_guard_unset` | Root `alembic.ini` present and no confirmed member marked as the migration guard | Mark a confirmed check or command as `migration_guard` |
248
+
249
+ Readiness also shows two **warn-only** rows: a confirmed check not seen on PRs
250
+ into epic branches, and an epic-branch search that was unavailable. Neither
251
+ changes the admission verdict.
252
+
253
+ A history report proves a check **name** reported; it does **not** authenticate
254
+ which CI produced it. The current-head green check and the executor
255
+ verification still gate every merge, and a never-reported grandfathered check
256
+ cannot enable auto-merge. A repository configured before profiles (legacy
257
+ `--required-check`) keeps the two-file workflow path with no reinstall.
258
+ Rollback: pause new auto-merge admissions and roll forward.
259
+
260
+ A run left with **no** effective check and **no** `no_ci_gate` declaration does
261
+ not pass trivially. Its tickets **park** (`required_checks_empty_no_mode`). An
262
+ auto-merge run on the base branch with no check parks as `required_checks_empty`.
263
+
264
+ To set the checks yourself, put them in the policy file:
265
+
266
+ ```json
267
+ { "required_checks": ["epic-implementer-ci / gate"] }
268
+ ```
269
+
270
+ To change the policy of a live run, re-run with `--policy-file`. An identical
271
+ policy is a no-op. A different one is refused with a redacted diff unless you add
272
+ `--replace-policy`. For a targeted change, use `epic-implementer patch-policy`.
273
+
274
+ **Once gated:**
275
+
276
+ - A complete **red** check enters the bounded `ci_fix` repair path. A missing or
277
+ still-running check stays pending.
278
+ - A green result from an **older head** never satisfies the gate after a rebase
279
+ or force-push.
280
+ - In Bridge's own `epic-implementer-ci` workflow, PRs from forks, bots, and
281
+ branches other than same-repository `feature/BAPI-*` and `epic/**` get an
282
+ immediate green. That is cost control, not proof the suites ran.
283
+
284
+ ## Plan metadata: `touched_files`
285
+
286
+ **Plan-time file-overlap serialization is on by default**
287
+ (`planner_file_overlap_serialization_enabled`). Before the plan is stored, two
288
+ sibling tickets that predict overlapping files gain a dependency edge. Siblings
289
+ with disjoint files stay parallel.
290
+
291
+ `touched_files` is that prediction. It is optional and never checked against the
292
+ real diff:
293
+
294
+ | In the node | Meaning | Result |
295
+ |---|---|---|
296
+ | Field **absent** | The node opts out of serialization | Accepted. No edge is added for it. |
297
+ | `"touched_files": []` | "This ticket predicts no overlap" | Accepted as declared and empty. |
298
+ | Present but **malformed** | Not a list, or a blank, absolute, or non-string path | **400** (`VALIDATION`) |
299
+
300
+ Paths are relative to the repository root.
301
+
302
+ ```json
303
+ {
304
+ "plan_version": 1,
305
+ "nodes": [
306
+ { "ticket_key": "BAPI-405", "status": "planned", "depends_on": [],
307
+ "touched_files": ["api/routes/jira_api.py"] }
308
+ ],
309
+ "edges": []
310
+ }
311
+ ```
312
+
313
+ Declare it anyway. `setup-epic --dry-run` warns when it is missing; that is a
314
+ planning-quality signal, not a predicted failure. Serialization only **adds**
315
+ edges, so your own `depends_on` and `touched_files` combine safely.
316
+
317
+ Serialization is a scheduling aid, not a safety net. If a sibling's merge makes a
318
+ PR conflict, the reconciler sees it and routes the ticket to a rebase job, whether
319
+ or not the node declared `touched_files`.
320
+
321
+ ## Recovering a stuck or parked run
322
+
323
+ **Diagnose first:**
324
+
325
+ - The `explain_run` MCP tool explains why a run, or one ticket, is stuck: current
326
+ gate, latest observation, outstanding jobs, lease, blockers, and head SHA.
327
+ - The `get_epic_snapshot` MCP tool returns the full run state.
328
+ - `notifications --repo <repo> --run <epic-key|run-id> [--follow]` prints the
329
+ run's notification feed.
330
+ - `epic-implementer epic-status --epic-key <KEY>` prints a read-only health summary.
331
+
332
+ Both MCP tools need the `epic_implementer` profile group (see
333
+ [MCP profile](#mcp-profile)).
334
+
335
+ **Then apply one verb.** These are CLI-only (never MCP tools) and run as
336
+ `npx -y @bridge_gpt/mcp-server epic-implementer <verb> ...` or through the
337
+ `epic-implementer` bin. Each takes `--epic-run-id <id>`.
338
+
339
+ | Verb | What it does |
340
+ | --- | --- |
341
+ | `stop-run` | Stop the run: block dispatch and cancel queued work. The record stays. |
342
+ | `abandon-run` | Abandon the run. Terminal and irreversible. |
343
+ | `resume-run [--clear-quarantine]` | Resume a paused run (a quarantined one only with the flag). |
344
+ | `unpark --ticket-key <key>` | Move a `needs_human` ticket back into its gates. |
345
+ | `adopt-current-head-and-unpark --ticket-key <key>` | Recover a ticket parked by a PR-head change: adopt the current head and unpark. |
346
+ | `continue-child --ticket-key <key> [--reason <text>]` | Continue a parked child's current attempt without a reset. |
347
+ | `continuation-receipt --ticket-key <key> [--request-id <id>]` | Read-only: whether a continuation request committed. |
348
+ | `resume-ci --ticket-key <key>` | Resume a child parked on a CI stop once CI is green. |
349
+ | `dispatch-remediation --ticket-key <key> --context-file <path>` | Queue a repair job carrying your notes (at most 16384 bytes). |
350
+ | `merge-child --pr <number>` | Merge the run's child PR through the shared merge service. |
351
+ | `scope-reparse --scope-id <scope>` | Re-drive the run's own index scope and schedule its parse. |
352
+ | `scope-catch-up --scope-id <scope>` | Replay merges the run's scope did not observe. |
353
+ | `patch-policy --patch-file <path>` | Merge-patch (RFC 7396) the run's policy. Protected paths are refused. |
354
+
355
+ Most verbs accept `--json`. A replay that changes nothing prints
356
+ `committed: false` and exits `0`. A refusal carries the server's closed code, such
357
+ as `TICKET_NOT_IN_RUN`.
358
+
359
+ **Check prerequisites.** `epic-implementer readiness` is a read-only advisory
360
+ report of every prerequisite (install, doctor, plane preflight, and server), each
361
+ with one named fix. It never runs a fix and always exits `0`.
362
+ `epic-implementer doctor` reports local health read-only.
363
+
364
+ ## Setting up a repository: `install conductor`
365
+
366
+ `npx -y @bridge_gpt/mcp-server install conductor` bootstraps a repository for the
367
+ Epic Implementer. It runs a read-only doctor first, then asks for consent before
368
+ each write: the supervisor project defaults, an optional `claude-review` workflow,
369
+ adding `epic_implementer` to your MCP config, and the local git hooks.
370
+
371
+ `npx -y @bridge_gpt/mcp-server install conductor --merge-workflow --codeowner <@org/team|@user>`
372
+ generates the merge workflow and its CODEOWNERS fragment, pushes a branch with your own git, and
373
+ opens a PR with your own `gh`. It never merges that PR. Replace
374
+ `<@org/team|@user>` with the one reviewer of the workflow file before running;
375
+ Bridge cannot infer it.
376
+
377
+ ## MCP profile
378
+
379
+ The Epic Implementer MCP tools are `get_epic_snapshot` and `explain_run`. They
380
+ register only when `BRIDGE_MCP_PROFILE` includes the `epic_implementer` group (or
381
+ `full`). The default profile is `core`, which does not include them.
382
+
383
+ ```
384
+ BRIDGE_MCP_PROFILE=core,epic_implementer
385
+ ```
386
+
387
+ The old `conductor` profile token is retired and ignored. `epic-implementer
388
+ doctor` flags it.
389
+
390
+ ## Binaries
391
+
392
+ | Bin | Purpose |
393
+ | --- | --- |
394
+ | `epic-implementer` | The CLI: the recovery verbs above, `readiness`, `doctor`, `epic-status`, `approve-plan`, `install-git-hooks`, and the observability-layer ledger commands (`emit-event`, `supervise`, `send-message`, `check-messages`, `purge`, `git-hook`, `file-scope-guard`). |
395
+ | `epic-implementer-claude-hook` | The Claude Code lifecycle hook for `--conductor` runs. |
396
+ | `conductor`, `conductor-claude-hook` | Retired names (renamed by BAPI-1080). They print a fixed migration message and exit `1`. |
397
+
398
+ The same CLI is available as the `epic-implementer` subcommand:
399
+ `npx -y @bridge_gpt/mcp-server epic-implementer <command>`.
400
+
401
+ ## Environment-variable names and the legacy-name refusal (BAPI-1190)
402
+
403
+ Every Epic Implementer environment variable uses the `BAPI_EPIC_IMPLEMENTER_`
404
+ prefix. The worker Node path is `EPIC_IMPLEMENTER_NODE_PATH`. These replaced the
405
+ old names by a plain token swap: `CONDUCTOR` became `EPIC_IMPLEMENTER` and the
406
+ rest stayed the same. For example, the run-id variable is now
407
+ `BAPI_EPIC_IMPLEMENTER_RUN_ID`. There are no aliases and no dual reads.
408
+
409
+ The three dead-man variables that the Python worker reads were renamed the same
410
+ way: `EPIC_IMPLEMENTER_DEAD_MAN_ONLY`, `EPIC_IMPLEMENTER_DEADMAN_CHANNEL_TYPE`, and
411
+ `EPIC_IMPLEMENTER_DEADMAN_DESTINATION_REF`.
412
+
413
+ **Old names are refused, not ignored.** If any `BAPI_CONDUCTOR_*` variable,
414
+ `CONDUCTOR_NODE_PATH`, or an old `CONDUCTOR_DEAD_MAN_ONLY` /
415
+ `CONDUCTOR_DEADMAN_*` name is set, these entry points refuse:
416
+
417
+ | Entry point | On an old name |
418
+ |---|---|
419
+ | MCP server (bare startup) and every `npx @bridge_gpt/mcp-server <subcommand>` | stderr diagnostic, exit `1`, before any spawn, network call, ledger open, or file write |
420
+ | `epic-implementer` bin | stderr diagnostic, exit `1`, before argv reaches the CLI |
421
+ | `plane up` preflight | refused as the first check, before anything starts |
422
+ | `epic-implementer-claude-hook` bin | same stderr diagnostic, **exit `0`**, no ledger event |
423
+ | Bridge API `worker.py` (dead-man names only) | refuses at boot |
424
+
425
+ The hook exits `0` because a hook must never block the Claude tool loop. The two
426
+ retired `conductor` bins are not guarded; they already fail with a fixed message.
427
+
428
+ The diagnostic lists **every** offending key, sorted, in one message, with its
429
+ successor, a "retired — remove it" note, or generic advice for an unknown name. It
430
+ prints **key names only, never values**, because these variables can hold secrets.
431
+ Stale names usually live in shell profiles, hand-edited executor service units, or
432
+ CI settings.
433
+
434
+ **Version skew.** A worker environment injected by an **older** package still
435
+ carries old names, so a **newer** process started inside it refuses to start. This
436
+ is intended. Re-spawn the worker so the launcher and the process it starts use the
437
+ same package version. If that does not fix it, send the MCP package owner both
438
+ versions and the offending **key names only**.
439
+
440
+ The executor's worker-environment filter also strips both prefixes and both
441
+ node-path spellings, so an old name never reaches a worker it spawns.
442
+
443
+ ## Observability layer (`--conductor`, opt-in, BAPI-394)
444
+
445
+ This layer is **off by default**. It is separate from the v2 engine and never
446
+ decides a transition. Without `--conductor`, `start-tickets` produces no
447
+ `BAPI_EPIC_IMPLEMENTER_*` env, supervisor tab, or message-relay prompt.
448
+
449
+ With `start-tickets --conductor`, a run mints one `run_id`, writes a `run.started`
450
+ event to the local ledger (`~/.config/bridge/events.db`), attributes each worker by
451
+ `worker_id`, ticket key, and worktree path, and opens a supervisor tab. With
452
+ **Claude Code**, it also adds a lifecycle hook to each worktree's
453
+ `.claude/settings.local.json` (keeping existing hooks). The hook streams
454
+ `run.started`, `run.stopped`, and `agent.notification` events, plus `tool.intent`
455
+ with `BAPI_EPIC_IMPLEMENTER_ENABLE_PRE_TOOL_USE=1`.
456
+
457
+ - Worker identity passes only through secret-free env scoped to one tab. No
458
+ credential is ever placed in env, the hook command, or run metadata.
459
+ - Override labels with `BAPI_EPIC_IMPLEMENTER_GATE_NAME` and
460
+ `BAPI_EPIC_IMPLEMENTER_SUPERVISOR_MODE`.
461
+ - Observability is best-effort. A failure never blocks a spawn, and `--dry-run`
462
+ has no side effects.
463
+ - Each worker's `BRIDGE_MCP_PROFILE` becomes the parent's resolved groups **plus**
464
+ `epic_implementer`, so the worker gets the two Epic Implementer tools. A plain
465
+ `start-tickets` run keeps the parent profile.
466
+
467
+ Inspect the stream with `epic-implementer doctor`. See also
468
+ [README → Environment Variables](../README.md#environment-variables).
469
+
470
+ ## `epic-implementer install-git-hooks` (BAPI-395)
471
+
472
+ Installs local git hooks that emit git events into the local ledger:
473
+
474
+ ```
475
+ epic-implementer install-git-hooks [--json]
476
+ ```
477
+
478
+ The hooks are **local, unversioned, opportunistic, and bypassable**. They live in
479
+ the worktree's git hooks directory (from `git rev-parse --git-common-dir`), add
480
+ only a clearly delimited managed block (keeping your own hook content), run the
481
+ producer **detached in the background** so a commit is never blocked, and end in
482
+ `|| true`. A directory that is not a git worktree, or an existing hook that looks
483
+ binary or unsafe, is left alone and reported as a **degraded optional
484
+ capability**, never a fatal error. The hooks are `post-commit` (emits
485
+ `git.commit_created`) and `reference-transaction` (emits `worktree.changed` for
486
+ committed ref updates).
487
+
488
+ Missing hooks do **not** block anything. `epic-implementer doctor` reports hook
489
+ state read-only, and the reconciler drives CI polling and gates either way.
490
+
491
+ ### Durable hook installation (BAPI-1290)
492
+
493
+ A managed hook embeds one absolute entry path and runs it on every commit for as
494
+ long as the hook exists. So the installer embeds only a **qualified persistent
495
+ runtime** and refuses anything that can disappear under it.
496
+
497
+ **Supported installation.** Install the package persistently, then install the
498
+ hooks from that install:
499
+
500
+ ```bash
501
+ npm i -g @bridge_gpt/mcp-server
502
+ epic-implementer install-git-hooks
503
+ ```
504
+
505
+ A user-owned persistent prefix (`npm i -g --prefix <dir>`, with `<dir>/bin` on
506
+ PATH) works the same way. The hook embeds the fixed entry
507
+ `<prefix>/lib/node_modules/@bridge_gpt/mcp-server/build/epic-implementer-bin.js`
508
+ (POSIX single-quoted) and launches it with `node` from PATH. It never embeds npm's
509
+ `.bin` shim and never pins `process.execPath`.
510
+
511
+ Running the installer through `npx` works only as a front door: it looks up an
512
+ **already installed** global package with a bounded, offline `npm root -g` and
513
+ embeds that. With no qualified persistent install, it refuses.
514
+
515
+ **What "qualified" means.** Before touching any hook, the installer checks,
516
+ read-only:
517
+
518
+ | Check | Refusal classification |
519
+ |---|---|
520
+ | The entry is not inside the prunable `_npx` cache | `ephemeral-cache` |
521
+ | The canonical entry is a regular `build/epic-implementer-bin.js` | `missing` |
522
+ | It is not the retired `conductor-bin.js` name | `legacy-name` |
523
+ | It sits at `…/node_modules/@bridge_gpt/mcp-server/build/`, and the adjacent `package.json` has that `name`, a compatible `version` (`>=0.2.0 <1.0.0`), and `bin.epic-implementer` → `./build/epic-implementer-bin.js` | `unqualified-runtime` |
524
+ | The platform is macOS or Linux | `unqualified-runtime` |
525
+ | `node` from PATH launches the entry's private probe within 15 seconds | `node-unavailable` / `unknown` |
526
+ | That Node is an even LTS line ≥ 20 | `unqualified-runtime` |
527
+ | `better-sqlite3` loads for that Node | `native-unavailable` |
528
+
529
+ A refusal exits 1, prints only the classification and a fixed action (never a
530
+ path or error text), and leaves both hooks unchanged. Hooks are optional: a
531
+ refusal never blocks the engine.
532
+
533
+ **Qualified matrix.** Recorded evidence, not inference:
534
+
535
+ | OS | Install | Node | Native | Status |
536
+ |---|---|---|---|---|
537
+ | macOS 26 (Darwin 25.6, arm64) | persistent `npm i -g --prefix` (npm 11.13.0) | v24.16.0 (ABI 137) | better-sqlite3 13.0.3 | qualified by `packaged-git-hooks-lifetime.test.ts` |
538
+ | Linux | persistent `npm i -g` | even LTS ≥ 20 | better-sqlite3 13.x | accepted by policy; **not yet locally qualified** |
539
+ | Windows | any | any | any | **unqualified** — always refused |
540
+ | Any | `npx` cache only, version-manager switches (nvm/fnm/volta), other layouts | — | — | **unqualified** |
541
+
542
+ **Publication.** The installer plans both hooks before writing either. It refuses
543
+ a symlinked, non-regular, unreadable, or binary hook and changes nothing. Each
544
+ hook is written to a temporary file in the same directory, re-checked, and renamed
545
+ atomically over the target. A hook edited in the meantime is left alone
546
+ (`intervening-edit`). If one hook publishes and the other does not, the result is
547
+ `PARTIAL` (exit 1); re-running converges to one managed block per hook.
548
+
549
+ **Diagnosis.** `epic-implementer doctor` (and `install doctor`) report each hook's
550
+ `state` and `usable` verdict read-only. A hook that points into the npx cache
551
+ (`ephemeral-cache`), at a removed install (`missing`), at the retired name
552
+ (`legacy-name`), or at a runtime whose native binding no longer loads
553
+ (`native-unavailable`) is **unavailable**. The raw embedded path appears only in
554
+ `--json` output (`embedded_bin_path`).
555
+
556
+ **Repairing old cache-backed hooks.** Hooks installed from `npx` before BAPI-1290
557
+ point into the npx cache. Install persistently (`npm i -g @bridge_gpt/mcp-server`),
558
+ then re-run `epic-implementer install-git-hooks` (or `install conductor` and
559
+ accept the local-observability consent). The managed block is replaced in place.
560
+
561
+ **Upgrades and rollback.** `npm i -g @bridge_gpt/mcp-server@<version>` replaces
562
+ the package in place, so hooks keep working without a rewrite. To roll back,
563
+ install the previous version the same way, then run `epic-implementer doctor`.
564
+
565
+ **What is not promised.** Events that happen while hook delivery is unavailable
566
+ are **lost and not replayed**. Commits are never blocked or slowed, and the engine
567
+ never depends on hooks.
568
+
569
+ ## Supervisor config
570
+
571
+ > **These are not config fields.** They used to be `conductor_done_gate` and
572
+ > `conductor_auto_merge_enabled` on the generic config-field route. BAPI-438 moved
573
+ > them to dedicated supervisor endpoints. Setting them through
574
+ > `PUT /jira/config-field/...` returns **HTTP 400 "Invalid config field"**, which
575
+ > is correct.
576
+
577
+ Each setting has a per-repo **project default** and a per-epic override:
578
+
579
+ | Setting | Endpoint (project default) |
580
+ | --- | --- |
581
+ | `done_gate_config` | `PUT /jira/epic-runs/supervisor-setup/defaults/?repo_name=<repo>` |
582
+ | `auto_merge_enabled`, `merge_approval_required` | `PUT /jira/epic-runs/supervisor-config/defaults/?repo_name=<repo>` |
583
+
584
+ Swap `…/defaults/` for `…/runs/{epic_key}/…` to scope a setting to one epic. The
585
+ matching `GET` returns the effective value with a `source` of `epic`,
586
+ `project_default`, or `none` (nothing configured; fails closed).
587
+
588
+ Since BAPI-1288 every project-default write is protected. Removing a configured
589
+ requirement needs a preview (`POST …/defaults/preview/`) and the exact approval it
590
+ returns. Turning `auto_merge_enabled` **on**, or dropping a required
591
+ `merge_approval_required`, on the project default is refused
592
+ (`409 NON_RELAXABLE`); ask Bridge support.
593
+
594
+ ### `done_gate_config`
595
+
596
+ Defines the done gate. It supports one condition, `required_ci_checks_green`:
597
+
598
+ ```json
599
+ {
600
+ "enabled": true,
601
+ "conditions": [
602
+ { "type": "required_ci_checks_green", "required_checks": ["build", "test"] }
603
+ ]
604
+ }
605
+ ```
606
+
607
+ It serves two readers:
608
+
609
+ - **The v2 engine** takes its first-approval `required_checks` stamp from the
610
+ project default's checks (see [The CI gate](#the-ci-gate)).
611
+ - **The `merge_pull_request` tool and the observability-layer supervisor** emit
612
+ `gate.met` (once per repo, PR, head SHA, and config) only when every listed
613
+ check is present, complete, and green for the PR head. An unset, disabled,
614
+ malformed, or empty config emits nothing.
615
+
616
+ ### `auto_merge_enabled`
617
+
618
+ This switch governs the `merge_pull_request` tool and the observability-layer
619
+ supervisor. It does **not** govern v2 epic merges: those read only the run's
620
+ `policy_json.v2_auto_merge_enabled`, which an unattended epic-branch run sets on.
621
+
622
+ **For the switch's own consumers, auto-merge is off by default.**
623
+
624
+ - **Off, unset, or unconfigured → dry-run.** The supervisor records a
625
+ `merge.dry_run` event and merges nothing.
626
+ - **On → autonomous merge** when the gate is met and the guards pass.
627
+ - **Kill-switch.** Set it to `false` to stop autonomous merges at once. The
628
+ protected merge endpoint re-checks the flag itself.
629
+
630
+ Merge authority is **deterministic code, never an LLM**. Every guard is bound to
631
+ **PR number + expected head SHA** (never a branch name): the enablement flag, the
632
+ PR still open, **no head-SHA drift** between gate and merge, and required checks
633
+ **re-validated green right before the merge**.
634
+
635
+ A TTL lease keyed by `merge:{repo}:{pr}:{head_sha}:{gate}` makes merging
636
+ crash-safe and race-safe; an existing `merge.succeeded` for that key is terminal.
637
+ The caller never holds VCS write credentials: it calls
638
+ `POST /vcs/pull-requests/{pr_number}/merge`, which owns the privileged merge. The
639
+ results are `merge.dry_run`, `merge.attempted`, `merge.succeeded`,
640
+ `merge.failed` (retryable), and `merge.pending_approval` (waits for a human).
641
+ **`merge.succeeded` is the only terminal merge event.**
642
+
643
+ **Who performs the write (BAPI-832).** GitHub's merge endpoint needs
644
+ `contents: write`, and the Bridge GPT App is `contents: read`. So two paths merge
645
+ with the operator's local `gh` session instead of the App token:
646
+
647
+ - the executor's `merge` job; and
648
+ - the `merge_pull_request` MCP tool, which receives `approved_for_local_execution`,
649
+ merges locally, and reports to `POST /vcs/pull-requests/{pr_number}/merge/complete`.
650
+
651
+ The server still owns every decision: the guards, the lease, and the final record.
652
+ The mode is `merge_execution` on the supervisor config (`local` by default,
653
+ `server` when the App holds `contents: write`). A caller that dies mid-merge is
654
+ recovered by lease expiry; a retry reports `already_merged` if the merge landed.
655
+
656
+ ## Worker ledger hardening (BAPI-527)
657
+
658
+ This section applies to the observability layer. It keeps a worker's own ledger
659
+ calls reliable. It is not a completion backstop.
660
+
661
+ **The invariant: the worker Node never loads `better-sqlite3`.** Worker ledger
662
+ operations run through `epic-implementer-bin.js` under the Node that owns the
663
+ ledger. Dispatch passes that Node to each worker as `EPIC_IMPLEMENTER_NODE_PATH`,
664
+ and the packaged `epic-implementer-bin.js` path as
665
+ `BAPI_EPIC_IMPLEMENTER_CLI_FILE`. The worker side shells out with a fixed list
666
+ argv through `execFile` (never a shell string) and sends event JSON over stdin, so
667
+ payloads never enter the argument list. Processes that own the ledger (the CLI and
668
+ supervisor) call the store directly. The local ledger store is at schema version 8.
669
+
670
+ **Fail loud, never fall back.** A missing or invalid `EPIC_IMPLEMENTER_NODE_PATH`,
671
+ or a missing `BAPI_EPIC_IMPLEMENTER_CLI_FILE`, returns the
672
+ `LEDGER_SUBPROCESS_RUNTIME_UNAVAILABLE` (503) envelope with a path-free
673
+ `details: { env_var, reason }`. It never falls back to the worker's own Node.
674
+ `EPIC_IMPLEMENTER_NODE_PATH` is non-secret and is never written to `.mcp.json`.
675
+
676
+ **Rejected alternatives.**
677
+
678
+ - **Local HTTP sidecar** (a ledger daemon on a port): port conflicts, zombie
679
+ processes, and token handling, all too much for a file-backed ledger.
680
+ - **WASM / pure-JS SQLite in the worker**: it gives up `better-sqlite3`'s proven
681
+ WAL behavior and fits poorly with a database file shared by several processes.
682
+
683
+ ### Three protective guarantees
684
+
685
+ 1. **Ledger operations are isolated from the worker.** A Node ABI mismatch
686
+ degrades a worker convenience, never the whole session.
687
+
688
+ 2. **Non-mutating dispatch.** Dispatch resolves the base with a fetch-only
689
+ `origin/<base>` lookup and cuts new worktrees from that SHA. It never checks
690
+ out, fast-forwards, force-moves, or stashes your live checkout. A live-source
691
+ guard also refuses dispatch when the base repo path equals your live dev-server
692
+ checkout:
693
+ - `BAPI_EPIC_IMPLEMENTER_LIVE_SOURCE_PATH` — the checkout to protect.
694
+ - `BAPI_EPIC_IMPLEMENTER_ALLOW_LIVE_SOURCE_DISPATCH` — a truthy override that
695
+ turns a collision into a loud warning.
696
+ `doctor` reports the guard state (`not-configured`, `safe`, or `collision`).
697
+
698
+ 3. **Parse runs in a separate process.** The post-merge re-index runs outside the
699
+ API server's event loop, so the server stays responsive during a parse. A
700
+ merged ticket enters `parsing` and moves on only after the parse succeeds. A failed parse is retried within a budget and then parks the ticket
701
+ as `needs_human`; it never silently wedges the epic.
702
+
703
+ ### Local likely-test discovery
704
+
705
+ Run `epic-implementer likely-tests --base <sha>` with the executor's immutable,
706
+ full 40-character comparison commit, after committing and before the first push.
707
+ Fallback: `npx -y -p @bridge_gpt/mcp-server epic-implementer likely-tests --base <sha>`.
708
+ Refresh after additional commits. Map references through the repository's declared
709
+ targeted runner; references are data, never commands.
710
+
711
+ This local read-only command returns zero even on invalid input or discovery failure.
712
+ Stdout contains only one reference per line; stderr contains fixed advisory notes.
713
+ Recent failures come first, then explicit `.bridge/verification-hints.json` pins,
714
+ then sorted tracked tests containing literal changed-path/import references.
715
+ Exact duplicates are removed before the 100-reference output limit.
716
+
717
+ The optional worker-worktree `.conductor/recently-failed-tests.json` is
718
+ `{"version":1,"tests":["most-recent-first reference"],"truncated":false}`. Child 3
719
+ owns writing it before each spawn. The shared parser keeps at most 20 references,
720
+ each at most 512 characters, without controls or line separators. Verification hints
721
+ use `{"version":1,"pins":[{"paths":["src/file.ts","src/package/"],"tests":["reference"]}]}`;
722
+ file paths match exactly and directory prefixes match directory boundaries.
723
+
724
+ Reads reject symlinks and traversal. Limits: 256 KiB per scanned or optional JSON
725
+ file, 16 MiB scanned text, 10,000 sorted candidates, 10 seconds per Git subprocess,
726
+ and 4 MiB Git output. Missing recent failures are silent. Disclose unavailable,
727
+ malformed, unreadable, truncated, or unmappable coverage in the existing handoff.
728
+ Retain available targeted verification; do not run a whole suite as fallback.