@bridge_gpt/mcp-server 0.2.69 → 0.2.70

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 (151) hide show
  1. package/README.md +140 -292
  2. package/build/agent-launchers/claude-executor-adapter.js +17 -4
  3. package/build/agents.generated.js +4 -4
  4. package/build/artifact-diff.js +110 -0
  5. package/build/bin-entrypoint.js +36 -0
  6. package/build/bridge-permissions.js +23 -4
  7. package/build/claude-review-workflow-drift.js +3 -3
  8. package/build/codex-bridge-profile.js +1 -1
  9. package/build/commands.generated.js +6 -6
  10. package/build/conductor/bridge-api-client.js +598 -19
  11. package/build/conductor/bring-up-facts.js +9 -9
  12. package/build/conductor/doctor.js +466 -18
  13. package/build/conductor/epic-child-continuation.js +54 -3
  14. package/build/conductor/epic-implementer-cli.js +132 -34
  15. package/build/conductor/epic-runtime.js +2 -2
  16. package/build/conductor/epic-state.js +1 -1
  17. package/build/conductor/hook-runtime-qualification.js +1 -1
  18. package/build/conductor/install-doctor.js +4 -2
  19. package/build/conductor/launch-need-probes.js +337 -0
  20. package/build/conductor/local-merge.js +241 -56
  21. package/build/conductor/merge-credential.js +172 -0
  22. package/build/conductor/merge-execution-eligibility.js +1 -1
  23. package/build/conductor/merged-child-check.js +95 -0
  24. package/build/conductor/plan-trim.js +30 -0
  25. package/build/conductor/pr-ci-producer.js +1 -1
  26. package/build/conductor/readiness-cli.js +11 -6
  27. package/build/conductor/readiness-prerequisites.js +41 -0
  28. package/build/conductor/readiness-sections.js +345 -55
  29. package/build/conductor/readiness.js +99 -87
  30. package/build/conductor/recovery-cli.js +606 -21
  31. package/build/conductor/recovery-operations.js +306 -7
  32. package/build/conductor/repair-contract.js +47 -2
  33. package/build/conductor/repository-workflow-remedy.js +8 -6
  34. package/build/conductor/stored-merge-credential.js +76 -0
  35. package/build/conductor/stored-merge-token-probe.js +28 -0
  36. package/build/conductor/temporary-plan.js +50 -0
  37. package/build/conductor/wait-run-cli.js +759 -0
  38. package/build/conductor/worker-database-doctor-inspector.js +49 -0
  39. package/build/conductor-bin.js +2 -2
  40. package/build/conductor-claude-hook-bin.js +2 -2
  41. package/build/conductor-claude-hook-removed-stub-bin.js +2 -5
  42. package/build/conductor-removed-stub-bin.js +2 -5
  43. package/build/credential-store.js +356 -13
  44. package/build/docs.generated.js +26 -13
  45. package/build/doctor.js +94 -32
  46. package/build/drive-epic-help.js +212 -0
  47. package/build/drive-epic.js +1840 -373
  48. package/build/epic-ci-workflow-drift.js +77 -0
  49. package/build/epic-ci-workflow-install.js +183 -0
  50. package/build/epic-ci-workflow.js +157 -0
  51. package/build/epic-contract-context.js +326 -0
  52. package/build/epic-implementer-bin.js +57 -41
  53. package/build/epic-implementer-claude-hook-bin.js +2 -2
  54. package/build/escalation-reachability.js +134 -0
  55. package/build/executor/cleanup-report.js +99 -0
  56. package/build/executor/cli.js +12 -1
  57. package/build/executor/completion-contract.js +66 -11
  58. package/build/executor/completion-supervision.js +99 -0
  59. package/build/executor/delivery-outcome.js +179 -0
  60. package/build/executor/deps.js +3 -0
  61. package/build/executor/env.js +71 -0
  62. package/build/executor/failure-reason-codes.js +126 -0
  63. package/build/executor/heartbeat.js +38 -0
  64. package/build/executor/http-client.js +72 -0
  65. package/build/executor/integration-job.js +298 -5
  66. package/build/executor/job-errors.js +36 -6
  67. package/build/executor/job-runner.js +720 -36
  68. package/build/executor/likely-tests.js +36 -2
  69. package/build/executor/merge-job.js +145 -2
  70. package/build/executor/observation.js +73 -4
  71. package/build/executor/permissions.js +193 -97
  72. package/build/executor/preflight.js +14 -3
  73. package/build/executor/process-containment.js +28 -2
  74. package/build/executor/prompt-spec.js +50 -5
  75. package/build/executor/rebase-finalization.js +38 -3
  76. package/build/executor/reconcile-overlap-job.js +35 -7
  77. package/build/executor/required-work-ledger.js +236 -81
  78. package/build/executor/resume-pre-spawn.js +38 -1
  79. package/build/executor/runner.js +91 -3
  80. package/build/executor/test-clock.js +8 -0
  81. package/build/executor/types.js +37 -2
  82. package/build/executor/worker-cli-launcher.js +259 -0
  83. package/build/executor/worker-command.js +41 -4
  84. package/build/executor/worker-database-target.js +91 -0
  85. package/build/executor/worker-database.js +908 -0
  86. package/build/executor/worker-finalization.js +106 -0
  87. package/build/executor/worker-guard-hook.js +203 -0
  88. package/build/executor/worker-resources.js +47 -0
  89. package/build/executor/worker-verification-guidance.js +15 -2
  90. package/build/executor/worktree.js +303 -15
  91. package/build/executor-launch.js +11 -1
  92. package/build/generated-assets-doctor.js +9 -1
  93. package/build/generated-assets-health.js +13 -4
  94. package/build/generated-assets-legacy.js +39 -0
  95. package/build/generated-assets-paths.js +12 -1
  96. package/build/generated-assets-repair.js +4 -1
  97. package/build/generated-assets-test-support.js +12 -0
  98. package/build/github-remote.js +33 -0
  99. package/build/github-sign-in.js +62 -0
  100. package/build/index.js +1067 -536
  101. package/build/init.js +39 -1
  102. package/build/install-bridge-conductor-gate.js +78 -0
  103. package/build/install-bridge-conductor-setup.js +413 -0
  104. package/build/install-bridge-conductor.js +1226 -267
  105. package/build/install-bridge.js +376 -60
  106. package/build/mcp-install-state.js +8 -2
  107. package/build/merge-pull-request.js +6 -0
  108. package/build/merge-workflow-install.js +763 -345
  109. package/build/phase-result-artifacts.js +75 -20
  110. package/build/pipeline-orchestrator.js +247 -4
  111. package/build/pipelines.generated.js +35 -35
  112. package/build/plan-discovery.js +15 -2
  113. package/build/plan-execution-ledger.js +306 -17
  114. package/build/plan-phase-routing.js +48 -13
  115. package/build/plane/cli.js +105 -51
  116. package/build/plane/defaults.js +3 -0
  117. package/build/plane/plane-freshness.js +294 -0
  118. package/build/plane/schema-compatibility.js +137 -0
  119. package/build/plane/shutdown-deps.js +38 -0
  120. package/build/plane/shutdown.js +83 -8
  121. package/build/plane/terminal-run-cleanup.js +303 -0
  122. package/build/printed-remedy-commands.js +26 -4
  123. package/build/readiness-check.js +6 -2
  124. package/build/readiness-prerequisites.generated.js +532 -0
  125. package/build/readme.generated.js +1 -1
  126. package/build/setup-epic.js +400 -30
  127. package/build/shared-resources.generated.js +5 -0
  128. package/build/start-tickets.js +28 -15
  129. package/build/test-command-detection.js +247 -0
  130. package/build/test-command-validation.js +73 -0
  131. package/build/testing-config-client.js +150 -0
  132. package/build/ticket-delivery-artifacts.js +258 -0
  133. package/build/ticket-delivery-enrollment.js +306 -0
  134. package/build/ticket-delivery.js +205 -0
  135. package/build/ticket-review-summary.js +14 -0
  136. package/build/upgrade-cli.js +13 -0
  137. package/build/v2-readiness-requirements.js +552 -0
  138. package/build/version.generated.js +3 -3
  139. package/build/worker-guard-hook-bin.js +2 -2
  140. package/build/worktree-core.js +22 -7
  141. package/docs/BRIDGE-DIRECTORY-README.md +48 -0
  142. package/docs/EPIC-IMPLEMENTER-INSTALL.md +12 -867
  143. package/docs/EPIC-IMPLEMENTER.md +104 -63
  144. package/docs/epic-implementer/getting-started.md +131 -0
  145. package/docs/epic-implementer/self-hosting.md +133 -0
  146. package/package.json +3 -3
  147. package/pipelines/idea-to-ticket.json +1 -1
  148. package/pipelines/implement-ticket.json +8 -8
  149. package/pipelines/review-ticket.json +2 -2
  150. package/design-assets/favicon/favicon-32x32.png +0 -0
  151. package/design-assets/just-logo-rough-draft.png +0 -0
@@ -1,3 +1,4 @@
1
+ import { mergeReadinessPrerequisites, formatReadinessPrerequisites } from "./readiness-prerequisites.js";
1
2
  /**
2
3
  * The consolidated ADVISORY epic-implementer readiness gate (BAPI-1055, AC-6/AC-7).
3
4
  *
@@ -28,7 +29,8 @@
28
29
  * are all failures, not passes.
29
30
  *
30
31
  * **Containment.** The authoritative refusals are unchanged and live elsewhere:
31
- * `V2_READINESS_REQUIREMENTS` in `drive-epic.ts` remains the SOLE hard
32
+ * `V2_READINESS_REQUIREMENTS` (declared in `v2-readiness-requirements.ts` since
33
+ * BAPI-1452 and consumed by `drive-epic.ts`) remains the SOLE hard
32
34
  * route-selection predicate, and the server-side admission (A1b.1/A1b.2) remains
33
35
  * the sole hard refusal. `plane up`'s own blocking preflight still refuses a
34
36
  * bring-up on its own terms. This gate contributes to none of those decisions:
@@ -61,7 +63,8 @@
61
63
  *
62
64
  * **What replaced it.** BAPI-1136 de-personalized the merge: it now authenticates
63
65
  * with one explicitly configured, customer-held credential
64
- * (`BAPI_LOCAL_MERGE_TOKEN` or `BAPI_MACHINE_MERGE_TOKEN`) and never with the
66
+ * (`GITHUB_MERGE_TOKEN` — BAPI-1452's canonical local key, formerly
67
+ * `BAPI_LOCAL_MERGE_TOKEN` — or `BAPI_MACHINE_MERGE_TOKEN`) and never with the
65
68
  * ambient session. So the second check was RE-POINTED, not removed —
66
69
  * `conductor.gh-cli` still asks whether `gh` exists, and
67
70
  * `conductor.merge-credential` asks whether a credential is configured. Removing
@@ -92,17 +95,22 @@
92
95
  * unrelated additive change look like a breaking one here, or worse, hide a real
93
96
  * one.
94
97
  */
95
- import { PRINTED_CHECK_NAME_INSTRUCTION, PRINTED_CONDUCTOR_EXECUTOR_INSTALL_COMMAND, PRINTED_CONDUCTOR_INSTALL_COMMAND, PRINTED_CONNECT_GITHUB_COMMAND, PRINTED_EXECUTOR_ID_INSTRUCTION, PRINTED_QUALIFY_GATE_COMMAND, } from "../printed-remedy-commands.js";
98
+ import { CONSUMER_GUIDE_POINTER, PRINTED_CHECK_NAME_INSTRUCTION, PRINTED_CONDUCTOR_EXECUTOR_INSTALL_COMMAND, PRINTED_CONDUCTOR_INSTALL_COMMAND, PRINTED_CONNECT_GITHUB_COMMAND, PRINTED_EXECUTOR_ID_INSTRUCTION, PRINTED_QUALIFY_GATE_COMMAND, } from "../printed-remedy-commands.js";
96
99
  import { mapConductorDoctorReportToReadinessChecks, } from "./doctor.js";
97
100
  import { mapInstallStatusChecksToReadinessChecks, } from "../install-doctor.js";
98
101
  import { mapPlanePreflightToReadinessChecks, } from "../plane/preflight.js";
99
102
  import { runConductorInstallDoctor, } from "./install-doctor.js";
100
103
  import { BRING_UP_SECTION_LABELS, describeGateProfile, describeGateProfileWarning, effectiveReviewModeIsRepositoryPolicy, EPIC_BRANCH_CI_SECTION_IDS, epicBranchCiSections, presentRequiredChecks, quotedSubject, } from "./readiness-sections.js";
101
104
  import { classifyBringUpFacts } from "./bring-up-facts.js";
105
+ import { projectReadinessRowBlocking, providerRepositoryCheck, resolvedMergeModeCheck, } from "../v2-readiness-requirements.js";
102
106
  import { CI_WORKFLOW_PATH, REVIEW_WORKFLOW_PATH, ciWorkflowRemedy, repositoryWorkflowRemedy, } from "./repository-workflow-remedy.js";
103
107
  import { classifyMergeExecutionEligibility, MERGE_EXECUTION_INELIGIBLE_REMEDIATION, MERGE_EXECUTION_UNVERIFIABLE_REMEDIATION, } from "./merge-execution-eligibility.js";
104
108
  import { createReadinessCheck, createReadinessCheckSafely, summarizeReadinessChecks, validateReadinessChecks, } from "../readiness-check.js";
105
109
  import { ADMISSION_EVIDENCE_SCHEMA_VERSION, gateProfileWaivesCiWorkflow, } from "./bridge-api-client.js";
110
+ import { ESCALATION_REACHABILITY_REMEDY, emailTransportDetailForChannel, isFailedEmailTransportDiagnostic, resolveEffectiveEscalationChannel, } from "../escalation-reachability.js";
111
+ // BAPI-1490 — the reachability row lives in a neutral module so drive-epic can build it
112
+ // without referencing this gate; it is re-exported here for gate consumers.
113
+ export { ESCALATION_REACHABILITY_CHECK_ID, buildEscalationReachabilityCheck, } from "../escalation-reachability.js";
106
114
  /** This report's own schema version. See the module docstring. */
107
115
  export const CONDUCTOR_READINESS_GATE_SCHEMA_VERSION = 1;
108
116
  /** Fixed statement carried in every report, so no consumer can mistake it for a gate. */
@@ -115,11 +123,18 @@ export const CONDUCTOR_READINESS_ADVISORY_NOTICE = "Advisory only. This report n
115
123
  // ---------------------------------------------------------------------------
116
124
  /** The complete server-side prerequisite set, in render order. */
117
125
  export const SERVER_READINESS_DESCRIPTORS = [
126
+ // BAPI-1452 — the launch summary order: the Setup-page unattended posture
127
+ // first, then the supporting merge facts. The hard-coded `auto-merge` and
128
+ // `merge-approval` rows are RETIRED: an unattended run's own merges are
129
+ // authorized by the run and this one switch, not by the legacy repository
130
+ // merge flags, so reporting those flags here described a decision they no
131
+ // longer make.
132
+ { id: "unattended-posture", label: "Unattended posture (Setup page)" },
133
+ { id: "resolved-merge-mode", label: "Resolved merge mode" },
134
+ { id: "provider-repository", label: "Provider repository" },
118
135
  { id: "supervisor-setup", label: "Supervisor setup" },
119
136
  { id: "supervisor-config", label: "Supervisor configuration" },
120
137
  { id: "supervisor-required-checks", label: "Supervisor required CI checks" },
121
- { id: "auto-merge", label: "Auto-merge posture" },
122
- { id: "merge-approval", label: "Merge approval configuration" },
123
138
  { id: "review-policy", label: "Review policy" },
124
139
  { id: "github-credentials", label: "GitHub App credentials" },
125
140
  { id: "github-actions-permission", label: "GitHub App actions permission" },
@@ -149,7 +164,6 @@ export const SERVER_READINESS_DESCRIPTORS = [
149
164
  // BAPI-1102 — the two unattended repository prerequisites plus the aggregate the
150
165
  // third unattended refusal reads. Noun phrases, like every row above: these
151
166
  // render as list items under a source heading, not as sentences.
152
- { id: "unattended-consent", label: "Repository unattended consent" },
153
167
  { id: "unattended-notify-default", label: "Escalation channel (webhook or email)" },
154
168
  { id: "repository-workflow-readiness", label: "Repository workflow readiness" },
155
169
  ];
@@ -176,33 +190,32 @@ const SERVER_FAILURE_COPY = {
176
190
  const SERVER_REMEDIATIONS = {
177
191
  supervisorSetup: `run \`${PRINTED_CONDUCTOR_INSTALL_COMMAND}\` (or \`setup-epic\`) for this repository to write the project-default supervisor posture. ${PRINTED_CHECK_NAME_INSTRUCTION}`,
178
192
  supervisorConfig: `run \`${PRINTED_CONDUCTOR_INSTALL_COMMAND}\` for this repository to write the project-default supervisor configuration. ${PRINTED_CHECK_NAME_INSTRUCTION}`,
179
- mergeApproval: "set the merge-approval requirement explicitly in the supervisor configuration rather than leaving it unset.",
180
193
  reviewPolicyMissing: "set the repository review-policy default so the merge path and the code_review gate read the same signal.",
181
194
  reviewPolicyDivergent: "align the repository review-policy default with the done gate's review_state condition, or confirm the difference is intended.",
182
195
  githubCredentials: `connect GitHub from the Bridge setup UI or run \`${PRINTED_CONNECT_GITHUB_COMMAND}\` so owner, repository id, and installation id all resolve.`,
183
196
  actionsProbeFailed: "re-run once credentials resolve; the permission could not be checked, which is not the same as confirmed-missing.",
184
- actionsMissing: "grant the GitHub App `actions: write`; without it the conductor's workflow rerun lane fails open on 403.",
197
+ actionsMissing: "grant the GitHub App `actions: write`; without it the workflow rerun lane fails open on 403.",
185
198
  reconcilerUnreadable: "retry once the Bridge API is reachable; reconciler liveness is unknown here, not confirmed stale.",
186
199
  // BAPI-1360: the frozen `epic-tick` command is never named. The reconciler runs
187
200
  // inside the worker, so the first check is that the worker is up, then the run's
188
201
  // own status.
189
202
  reconcilerStale: "check the worker first (`server.worker-present`), then inspect the stalled run with `epic-implementer epic-status`.",
190
203
  executorUnreadable: "retry once the Bridge API is reachable; no executor readiness claim is ever made from local state.",
191
- executorNeverSeen: `provision and start an executor (\`${PRINTED_CONDUCTOR_EXECUTOR_INSTALL_COMMAND}\` or \`executor install-service\`); readiness comes only from a live server observation. ${PRINTED_CHECK_NAME_INSTRUCTION} ${PRINTED_EXECUTOR_ID_INSTRUCTION}`,
192
- executorNoneObservedNoRuns: `no action is needed to launch: \`drive-epic\` starts a run-scoped executor. To keep an executor running between runs, install one with \`${PRINTED_CONDUCTOR_EXECUTOR_INSTALL_COMMAND}\` or \`executor install-service\`. ${PRINTED_CHECK_NAME_INSTRUCTION} ${PRINTED_EXECUTOR_ID_INSTRUCTION}`,
193
- executorStale: "restart the executor service; it was observed once and has gone quiet past the server's staleness threshold.",
194
- reviewWorkflowUnknown: "re-run; the default branch's review workflow could not be evaluated, which is not the same as it being absent.",
195
- reviewWorkflowIncomplete: "install the claude-review workflow template on the default branch so it emits both the run id and the reviewed SHA the verdict protocol reads.",
196
- ciWorkflowUnknown: "re-run; the default branch's conductor CI workflow could not be evaluated, which is not the same as the guard being absent.",
204
+ executorNeverSeen: `provision and start an executor (\`${PRINTED_CONDUCTOR_EXECUTOR_INSTALL_COMMAND}\` or \`executor install-service\`); readiness comes only from a live server observation. ${PRINTED_CHECK_NAME_INSTRUCTION} ${PRINTED_EXECUTOR_ID_INSTRUCTION} See ${CONSUMER_GUIDE_POINTER}.`,
205
+ executorNoneObservedNoRuns: `no action is needed to launch: \`drive-epic\` starts a run-scoped executor. To keep an executor running between runs, install one with \`${PRINTED_CONDUCTOR_EXECUTOR_INSTALL_COMMAND}\` or \`executor install-service\`. ${PRINTED_CHECK_NAME_INSTRUCTION} ${PRINTED_EXECUTOR_ID_INSTRUCTION} See ${CONSUMER_GUIDE_POINTER}.`,
206
+ executorStale: `restart the executor service; it was observed once and has gone quiet past the server's staleness threshold. See ${CONSUMER_GUIDE_POINTER}.`,
207
+ reviewWorkflowUnknown: `re-run; the default branch's review workflow could not be evaluated, which is not the same as it being absent (see ${CONSUMER_GUIDE_POINTER}).`,
208
+ reviewWorkflowIncomplete: `install the claude-review workflow template on the default branch so it emits both the run id and the reviewed SHA the verdict protocol reads (see ${CONSUMER_GUIDE_POINTER}).`,
209
+ ciWorkflowUnknown: `re-run; the default branch's Epic Implementer CI workflow could not be evaluated, which is not the same as the guard being absent (see ${CONSUMER_GUIDE_POINTER}).`,
197
210
  // BAPI-1359: the missing-guard remedy is built by `ciWorkflowRemedy` (the shared
198
211
  // formatter), because its wording depends on WHY the guard is missing — a
199
212
  // confirmed Alembic chain, an older server, or an unreadable answer.
200
- olderServer: "upgrade the Bridge API deploy so it reports this fact; its state is unknown here, not healthy.",
213
+ olderServer: "retry later; the server did not report this fact, so its state is unknown here, not healthy. If it persists, email info@bridgegpt.ai.",
201
214
  // BAPI-1102. Each names the ONE action that clears it, and none of them
202
215
  // mentions a webhook URL, a destination, or any configuration value.
203
216
  // BAPI-1273: consent defaults ON; the repository owner switches it on the
204
217
  // admin panel's Setup page. No MCP or CLI surface ever writes it.
205
- unattendedConsent: "turn on 'Allow unattended Epic Implementer runs' on the repository's Setup page in the Bridge admin panel, or run setup with --attended. If it is already on, contact Bridge support.",
218
+ unattendedConsent: "turn on 'Allow unattended Epic Implementer runs' on the repository's Setup page in the Bridge admin panel, or run setup with --attended. If it is already on, email info@bridgegpt.ai.",
206
219
  unattendedNotifyDefault: "supply a --policy-file declaring notify.webhook_url, or add an email address to the account so escalation alerts can be emailed, or run setup with --attended; an unattended run must have a working escalation channel, and notify.local_sink is not one.",
207
220
  // BAPI-1359: the `repository-workflow-readiness` remedy is built by
208
221
  // `repositoryWorkflowRemedy` (the shared formatter) from the SAME report, so it
@@ -221,7 +234,9 @@ const SERVER_REMEDIATIONS = {
221
234
  * and its own threshold values are reported as given, and
222
235
  * `V2_READINESS_REQUIREMENTS` is neither imported nor duplicated here — two
223
236
  * implementations of one classification drift, and this one is advisory while
224
- * that one decides a route.
237
+ * that one decides a route. BAPI-1452: the per-row applicability flag comes
238
+ * from that catalog's shared projection (`projectReadinessRowBlocking`), so this
239
+ * report repeats the requirements' answer instead of forming its own.
225
240
  *
226
241
  * Uncertainty is never healthy. `actions_probe_succeeded === false`, an
227
242
  * unreadable liveness read, `executor.ready === null`, and a field an older
@@ -233,7 +248,7 @@ const SERVER_REMEDIATIONS = {
233
248
  * Passing `null` (with a `failure` kind) yields the full descriptor set as
234
249
  * failures, so an unreachable server loses no prerequisite from the report.
235
250
  */
236
- export function mapServerReadinessToChecks(readiness, failure = "unreachable") {
251
+ export function mapServerReadinessToChecks(readiness, failure = "unreachable", callerChannel) {
237
252
  if (readiness === null) {
238
253
  const copy = SERVER_FAILURE_COPY[failure];
239
254
  return SERVER_READINESS_DESCRIPTORS.map(({ id, label }) => createReadinessCheck({
@@ -282,21 +297,17 @@ export function mapServerReadinessToChecks(readiness, failure = "unreachable") {
282
297
  ? {}
283
298
  : { remediation: requiredChecks.remediation }),
284
299
  });
285
- // Auto-merge OFF is a posture, not a gap: an operator may deliberately merge
286
- // by hand. Reported, never remediated.
287
- outcomes.push({
288
- id: "auto-merge",
289
- status: "pass",
290
- detail: s.auto_merge_enabled ? "auto-merge enabled" : "auto-merge disabled (operator posture)",
291
- });
292
- outcomes.push(s.merge_approval_required_set
293
- ? { id: "merge-approval", status: "pass", detail: "merge-approval requirement is set explicitly" }
294
- : {
295
- id: "merge-approval",
296
- status: "warn",
297
- detail: "the merge-approval requirement is unset, so the merge path falls back to its default",
298
- remediation: SERVER_REMEDIATIONS.mergeApproval,
300
+ // BAPI-1452 — the retired `auto-merge` / `merge-approval` rows used to sit
301
+ // here. The supporting merge facts come from the shared builders, so this
302
+ // report and drive-epic's launch summary word them identically.
303
+ for (const fact of [resolvedMergeModeCheck(readiness), providerRepositoryCheck(readiness)]) {
304
+ outcomes.push({
305
+ id: fact.id.slice("server.".length),
306
+ status: fact.status,
307
+ detail: fact.detail ?? fact.label,
308
+ ...(fact.remediation !== undefined ? { remediation: fact.remediation } : {}),
299
309
  });
310
+ }
300
311
  outcomes.push(reviewPolicyOutcome(readiness));
301
312
  outcomes.push(g.credentials_complete
302
313
  ? {
@@ -359,25 +370,47 @@ export function mapServerReadinessToChecks(readiness, failure = "unreachable") {
359
370
  });
360
371
  // BAPI-1260 — appended ONLY when the server reported the block, so every
361
372
  // pre-BAPI-1260 report keeps exactly the descriptor set above.
373
+ //
374
+ // BAPI-1452 — the row flags come from the SHARED requirement projection,
375
+ // never from this report's own judgement: a row is flagged exactly when an
376
+ // applicable requirement governs it. This report still decides nothing.
362
377
  return [
363
- ...described,
378
+ ...projectReadinessRowBlocking(described),
364
379
  ...admissionEvidenceChecks(readiness),
365
380
  // BAPI-1390 — appended ONLY when the server reported a gate profile.
366
381
  ...gateProfileChecks(readiness),
367
382
  // BAPI-1405 — always three warn-only epic-branch CI rows. An older server
368
- // that omits the block renders them as "Unreported — upgrade the server",
383
+ // that omits the block renders them as "Unreported by the server",
369
384
  // never as "no warning".
370
385
  ...epicBranchCiChecks(readiness),
371
- ...genericDiagnosticChecks(readiness),
386
+ ...genericDiagnosticChecks(readiness, callerChannel),
372
387
  ];
373
388
  }
374
- function genericDiagnosticChecks(readiness) {
389
+ function genericDiagnosticChecks(readiness, callerChannel) {
390
+ // BAPI-1495 — the same resolver the reachability row uses, so both agree.
391
+ const channel = resolveEffectiveEscalationChannel(readiness, callerChannel);
375
392
  return (readiness.diagnostics ?? []).map((diagnostic, index) => {
376
393
  const inapplicable = diagnostic.applicability === "inapplicable";
377
394
  const declared = diagnostic.severity !== null && diagnostic.applicability !== null;
378
395
  const satisfied = declared && diagnostic.verdict === "passed" && diagnostic.applicability === "applicable";
379
396
  const advisory = diagnostic.severity === "advisory";
380
- const status = !declared ? "fail" : inapplicable ? "skip" : satisfied ? "pass" : advisory ? "warn" : "fail";
397
+ // BAPI-1490 — a known failed email transport is a warning with fixed copy,
398
+ // whatever the diagnostic's severity: it reports that no person is told, and
399
+ // this report never blocks.
400
+ const transportNotLive = isFailedEmailTransportDiagnostic(diagnostic);
401
+ const status = transportNotLive
402
+ ? "warn"
403
+ : !declared ? "fail" : inapplicable ? "skip" : satisfied ? "pass" : advisory ? "warn" : "fail";
404
+ if (transportNotLive) {
405
+ return createReadinessCheckSafely({
406
+ id: `server.diagnostic-${index + 1}-${diagnostic.id.replace(/[_.]/g, "-")}`,
407
+ source: "server",
408
+ label: `Server diagnostic ${diagnostic.id}`,
409
+ status,
410
+ detail: emailTransportDetailForChannel(channel),
411
+ remediation: ESCALATION_REACHABILITY_REMEDY,
412
+ });
413
+ }
381
414
  return createReadinessCheckSafely({
382
415
  id: `server.diagnostic-${index + 1}-${diagnostic.id.replace(/[_.]/g, "-")}`,
383
416
  source: "server",
@@ -404,9 +437,9 @@ const ADMISSION_EVIDENCE_LABELS = {
404
437
  };
405
438
  /** Who acts, in fixed prose. Never a value from the payload. */
406
439
  const ADMISSION_OWNER_REMEDIATION = {
407
- operator: "the operator re-runs guided setup (`install conductor --launch-profile <name>`) and re-observes.",
440
+ operator: "the operator re-runs guided setup (`install conductor`) and re-observes.",
408
441
  repository_admin: "a repository administrator resolves it (unattended consent is the 'Allow unattended Epic Implementer runs' toggle on the repository's Setup page in the Bridge admin panel); setup never grants it.",
409
- bridge_operations: "escalate to Bridge operations; this is not something an operator command can change.",
442
+ bridge_operations: "email info@bridgegpt.ai; this is not something an operator command can change.",
410
443
  };
411
444
  /** The retired and current Bridge CI gate names, spelled once for the fixed remedies. */
412
445
  const RETIRED_GATE_NAME = "conductor-ci / gate";
@@ -462,11 +495,11 @@ function gateProfileReasonRemedy(reason, verdict, subject) {
462
495
  case "provider_evidence_unavailable":
463
496
  return (`Bridge could not read the provider's check history for ${quotedSubject(subject, "a gate-profile check")} ` +
464
497
  `(${PROVIDER_EVIDENCE_WINDOW}), so it is unknown, not absent. Re-run readiness; if it persists, ` +
465
- "escalate to Bridge operations.");
498
+ "email info@bridgegpt.ai.");
466
499
  case "local_command_unqualified":
467
500
  return verdict === "unable_to_verify"
468
501
  ? `the qualification of the local gate command ${quotedSubject(subject, "in the gate profile")} could not ` +
469
- "be read, so it is unknown, not qualified. Re-run readiness; if it persists, escalate to Bridge operations."
502
+ "be read, so it is unknown, not qualified. Re-run readiness; if it persists, email info@bridgegpt.ai."
470
503
  : `the local gate command ${quotedSubject(subject, "in the gate profile")} is not qualified for the current ` +
471
504
  "gate-profile revision (unqualified or stale). Qualify it with " +
472
505
  `\`${PRINTED_QUALIFY_GATE_COMMAND}\`, or have a repository administrator ` +
@@ -516,7 +549,7 @@ export function gateProfileChecks(readiness) {
516
549
  status: "fail",
517
550
  detail: `${profile.read_failed ? "the stored gate profile could not be read" : "the stored gate profile is malformed"} — ${detail}`,
518
551
  remediation: profile.read_failed
519
- ? "re-run readiness; if it persists, escalate to Bridge operations."
552
+ ? "re-run readiness; if it persists, email info@bridgegpt.ai."
520
553
  : "a repository administrator re-saves the gate profile; setup never grants it.",
521
554
  });
522
555
  }
@@ -574,7 +607,7 @@ export function gateProfileChecks(readiness) {
574
607
  * these rows never fail, never hold a launch, and feed no verdict.
575
608
  *
576
609
  * Unlike `gateProfileChecks`, an absent or `null` block (older server) still
577
- * yields the three rows, each `warn` with "Unreported — upgrade the server" and
610
+ * yields the three rows, each `warn` with "Unreported by the server" and
578
611
  * the upgrade remediation. Emitting nothing would read as "no warning", which
579
612
  * is the wrong answer: the server simply did not say. Omitted and `null` render
580
613
  * identically. The install doctor's own copies of these sections are filtered
@@ -720,7 +753,7 @@ function unattendedOutcomes(readiness) {
720
753
  const u = readiness.unattended;
721
754
  if (u === null) {
722
755
  return [
723
- "unattended-consent",
756
+ "unattended-posture",
724
757
  "unattended-notify-default",
725
758
  "repository-workflow-readiness",
726
759
  ].map((id) => ({
@@ -733,12 +766,12 @@ function unattendedOutcomes(readiness) {
733
766
  return [
734
767
  u.conductor_allowed
735
768
  ? {
736
- id: "unattended-consent",
769
+ id: "unattended-posture",
737
770
  status: "pass",
738
771
  detail: "this repository has consented to unattended Epic Implementer runs",
739
772
  }
740
773
  : {
741
- id: "unattended-consent",
774
+ id: "unattended-posture",
742
775
  status: "warn",
743
776
  detail: "unattended runs are off for this repository — an unattended run will be refused before it is created",
744
777
  remediation: SERVER_REMEDIATIONS.unattendedConsent,
@@ -760,7 +793,7 @@ function unattendedOutcomes(readiness) {
760
793
  // reported by the server and is never rendered here.
761
794
  id: "unattended-notify-default",
762
795
  status: "pass",
763
- detail: "No webhook declared; escalation alerts will be emailed to the account's email address",
796
+ detail: "No repository webhook default; a run's policy may declare notify.webhook_url, otherwise escalation alerts are emailed to the account's email address",
764
797
  }
765
798
  : {
766
799
  id: "unattended-notify-default",
@@ -1029,7 +1062,7 @@ function reviewWorkflowOutcome(readiness) {
1029
1062
  id: "review-workflow",
1030
1063
  status: "fail",
1031
1064
  detail: "this Bridge API deploy did not report the review-workflow facts",
1032
- remediation: SERVER_REMEDIATIONS.olderServer,
1065
+ remediation: `${SERVER_REMEDIATIONS.olderServer} See ${CONSUMER_GUIDE_POINTER}.`,
1033
1066
  };
1034
1067
  }
1035
1068
  if (!w.probe_succeeded) {
@@ -1089,7 +1122,7 @@ function ciWorkflowOutcome(readiness) {
1089
1122
  id: "conductor-ci-workflow",
1090
1123
  status: "fail",
1091
1124
  detail: "this Bridge API deploy did not report the epic-implementer-ci workflow facts",
1092
- remediation: SERVER_REMEDIATIONS.olderServer,
1125
+ remediation: `${SERVER_REMEDIATIONS.olderServer} See ${CONSUMER_GUIDE_POINTER}.`,
1093
1126
  };
1094
1127
  }
1095
1128
  if (!c.probe_succeeded) {
@@ -1097,8 +1130,8 @@ function ciWorkflowOutcome(readiness) {
1097
1130
  id: "conductor-ci-workflow",
1098
1131
  status: "fail",
1099
1132
  detail: c.workflow_present
1100
- ? "the conductor CI workflow is present but could not be evaluated"
1101
- : "the conductor CI workflow could not be found or read on the default branch",
1133
+ ? "the Epic Implementer CI workflow is present but could not be evaluated"
1134
+ : "the Epic Implementer CI workflow could not be found or read on the default branch",
1102
1135
  remediation: SERVER_REMEDIATIONS.ciWorkflowUnknown,
1103
1136
  };
1104
1137
  }
@@ -1115,7 +1148,7 @@ function ciWorkflowOutcome(readiness) {
1115
1148
  return {
1116
1149
  id: "conductor-ci-workflow",
1117
1150
  status: "pass",
1118
- detail: "the default branch's conductor CI workflow runs the migration guard",
1151
+ detail: "the default branch's Epic Implementer CI workflow runs the migration guard",
1119
1152
  };
1120
1153
  }
1121
1154
  // BAPI-1359 — the guard is conditional on an Alembic chain. Three explicit
@@ -1133,7 +1166,7 @@ function ciWorkflowOutcome(readiness) {
1133
1166
  return {
1134
1167
  id: "conductor-ci-workflow",
1135
1168
  status: "fail",
1136
- detail: "the Alembic check could not be read, so it is not known whether the conductor CI workflow needs the migration guard",
1169
+ detail: "the Alembic check could not be read, so it is not known whether the Epic Implementer CI workflow needs the migration guard",
1137
1170
  remediation: ciWorkflowRemedy(c),
1138
1171
  };
1139
1172
  }
@@ -1141,10 +1174,10 @@ function ciWorkflowOutcome(readiness) {
1141
1174
  id: "conductor-ci-workflow",
1142
1175
  status: "warn",
1143
1176
  detail: c.migration_guard_required === true && c.migration_chain_probe_succeeded === true
1144
- ? "the conductor CI workflow does not run the migration guard, which this repository requires because it has alembic.ini on its default branch"
1177
+ ? "the Epic Implementer CI workflow does not run the migration guard, which this repository requires because it has alembic.ini on its default branch"
1145
1178
  : // An older server (no new fields) or a partial report: keep today's
1146
1179
  // wording and today's behavior, and claim nothing about alembic.ini.
1147
- "the conductor CI workflow does not run the migration guard",
1180
+ "the Epic Implementer CI workflow does not run the migration guard",
1148
1181
  remediation: ciWorkflowRemedy(c),
1149
1182
  };
1150
1183
  }
@@ -1263,7 +1296,7 @@ export async function collectConductorReadinessGate(deps) {
1263
1296
  ...mapPlanePreflightToReadinessChecks(planeResult, deps.planeNotApplicable, {
1264
1297
  ...(deps.epicRunId !== undefined ? { epicRunId: deps.epicRunId } : {}),
1265
1298
  }),
1266
- ...mapServerReadinessToChecks(installReport?.readiness ?? null, classifyServerFailure(installReport)),
1299
+ ...mapServerReadinessToChecks(installReport?.readiness ?? null, classifyServerFailure(installReport), deps.callerChannel),
1267
1300
  ];
1268
1301
  // Validate the ASSEMBLED report, not just the pieces: an injected collector or
1269
1302
  // a future adapter could hand over an entry that violates the contract, and a
@@ -1276,7 +1309,15 @@ export async function collectConductorReadinessGate(deps) {
1276
1309
  repoName: deps.repoName ?? null,
1277
1310
  unavailableSources,
1278
1311
  checks: validated,
1312
+ prerequisites: mergeReadinessPrerequisites(validated, installReport?.readiness?.prerequisites),
1313
+ is_production: installReport?.readiness?.is_production,
1279
1314
  ...(installReport?.readiness?.diagnostics ? { diagnostics: installReport.readiness.diagnostics } : {}),
1315
+ ...(installReport?.readiness?.escalation_channel !== undefined
1316
+ ? { escalation_channel: installReport.readiness.escalation_channel }
1317
+ : {}),
1318
+ ...(installReport?.readiness?.webhook_last_delivery !== undefined
1319
+ ? { webhook_last_delivery: installReport.readiness.webhook_last_delivery }
1320
+ : {}),
1280
1321
  summary: summarizeReadinessChecks(validated),
1281
1322
  };
1282
1323
  }
@@ -1354,35 +1395,6 @@ function readinessTag(status) {
1354
1395
  * remediation — so neither rendering can show an operator a finding the other
1355
1396
  * hides. It computes no overall verdict, because there is none to compute.
1356
1397
  */
1357
- export function formatConductorReadinessGateReport(report) {
1358
- const lines = [
1359
- "Conductor readiness (advisory)",
1360
- "══════════════════════════════",
1361
- `schema version: ${report.schemaVersion}`,
1362
- `repository: ${report.repoName ?? "unresolved"}`,
1363
- "",
1364
- ];
1365
- for (const source of ["install", "conductor", "plane", "server"]) {
1366
- const group = report.checks.filter((check) => check.source === source);
1367
- if (group.length === 0)
1368
- continue;
1369
- lines.push(`[${source}]`);
1370
- for (const check of group) {
1371
- lines.push(` ${readinessTag(check.status)} ${check.label} (${check.id})`);
1372
- if (check.detail)
1373
- lines.push(` ${check.detail}`);
1374
- if (check.remediation)
1375
- lines.push(` → ${check.remediation}`);
1376
- }
1377
- lines.push("");
1378
- }
1379
- const { pass, warn, fail, skip } = report.summary;
1380
- lines.push(`summary: ${pass} pass, ${warn} warn, ${fail} fail, ${skip} skip`);
1381
- if (report.unavailableSources.length > 0) {
1382
- lines.push(`sources that could not be collected: ${report.unavailableSources.join(", ")} ` +
1383
- "(their prerequisites above are reported as failures, not as passes)");
1384
- }
1385
- lines.push("");
1386
- lines.push(report.advisory);
1387
- return lines.join("\n");
1398
+ export function formatConductorReadinessGateReport(report, options = {}) {
1399
+ return formatReadinessPrerequisites(report.prerequisites ?? mergeReadinessPrerequisites(report.checks), { all: options.all, isProduction: report.is_production }).join('\n');
1388
1400
  }