@bridge_gpt/mcp-server 0.2.56 → 0.2.58
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -6
- package/build/codex-bridge-profile.js +155 -0
- package/build/codex-home.js +7 -0
- package/build/codex-launch-scope.js +23 -7
- package/build/commands.generated.js +2 -2
- package/build/cursor-agent-progress.js +72 -0
- package/build/doctor.js +8 -1
- package/build/epic-implementer-bin.js +4 -4
- package/build/index.js +98 -94
- package/build/install-bridge.js +48 -1
- package/build/install-doctor.js +1 -1
- package/build/mcp-host-config.js +4 -0
- package/build/mcp-host-targets.js +3 -0
- package/build/pipelines.generated.js +4 -4
- package/build/readme.generated.js +1 -1
- package/build/start-tickets.js +95 -24
- package/build/version.generated.js +3 -3
- package/package.json +1 -1
- package/pipelines/implement-ticket.json +2 -2
- package/pipelines/review-ticket.json +1 -1
package/build/install-bridge.js
CHANGED
|
@@ -152,6 +152,7 @@ import { provisionHostTarget, createDefaultVendorProcessDeps, inspectBridgeApiPr
|
|
|
152
152
|
import { adaptBridgeEntryForHostTarget, } from "./mcp-host-entry-adapter.js";
|
|
153
153
|
import { MCP_SERVER_NAME, MCP_PACKAGE_NAME, resolveRegistrationKey, } from "./mcp-identity.js";
|
|
154
154
|
import { DUPLICATE_REGISTRATION_GUIDANCE } from "./launcher-config-inspection.js";
|
|
155
|
+
import { codexHome, configureBridgeCodexProfile, inspectBridgeCodexProfile } from "./codex-bridge-profile.js";
|
|
155
156
|
import { recordInstalledConductorCapability, recordInstalledExecutorServiceUnit, recordInstalledProjectArtifact, writeMcpInstallState, } from "./mcp-install-state.js";
|
|
156
157
|
// BAPI-1207: opt-in cross-platform agent notes (AGENTS.md / CLAUDE.md).
|
|
157
158
|
import { AGENT_GUIDANCE } from "./agent-guidance.generated.js";
|
|
@@ -517,6 +518,10 @@ export function getInstallBridgeUsage(baseUrl = DEFAULT_BAPI_BASE_URL) {
|
|
|
517
518
|
" manual continuation instead). --tools= (empty) is",
|
|
518
519
|
" an explicit empty selection: it writes nothing and",
|
|
519
520
|
" launches nothing.",
|
|
521
|
+
" --codex-profile on|off Opt in to Bridge workflow MCP approvals for",
|
|
522
|
+
" Codex workers, or explicitly decline. With a",
|
|
523
|
+
" Codex TTY selection, the installer asks",
|
|
524
|
+
" with Yes as the default (press Enter).",
|
|
520
525
|
" --force Overwrite an existing real BAPI_API_KEY in a",
|
|
521
526
|
" host config (or in the credential store) without",
|
|
522
527
|
" prompting. It does NOT bypass the git-tracked",
|
|
@@ -614,6 +619,7 @@ export function parseInstallBridgeArgs(argv) {
|
|
|
614
619
|
let invite;
|
|
615
620
|
let email;
|
|
616
621
|
let tools;
|
|
622
|
+
let codexProfile;
|
|
617
623
|
// Track SUPPLIED-ness separately from the values: `--invite` is legitimately
|
|
618
624
|
// valueless (prompt path) and `--api-key ""` is still a contradiction with it.
|
|
619
625
|
let inviteSupplied = false;
|
|
@@ -699,6 +705,16 @@ export function parseInstallBridgeArgs(argv) {
|
|
|
699
705
|
i = r.nextIndex;
|
|
700
706
|
continue;
|
|
701
707
|
}
|
|
708
|
+
if (arg === "--codex-profile" || arg.startsWith("--codex-profile=")) {
|
|
709
|
+
const r = readValue(arg, "--codex-profile", i);
|
|
710
|
+
if ("error" in r)
|
|
711
|
+
return { status: "error", message: r.error };
|
|
712
|
+
if (r.value !== "on" && r.value !== "off")
|
|
713
|
+
return { status: "error", message: "--codex-profile must be on or off." };
|
|
714
|
+
codexProfile = r.value;
|
|
715
|
+
i = r.nextIndex;
|
|
716
|
+
continue;
|
|
717
|
+
}
|
|
702
718
|
if (arg === "--agent" || arg.startsWith("--agent=")) {
|
|
703
719
|
const r = readValue(arg, "--agent", i);
|
|
704
720
|
if ("error" in r)
|
|
@@ -749,7 +765,7 @@ export function parseInstallBridgeArgs(argv) {
|
|
|
749
765
|
}
|
|
750
766
|
return {
|
|
751
767
|
status: "ok",
|
|
752
|
-
options: { apiKey, repo, force, dryRun, agentName, invite, inviteMode: inviteSupplied, email, tools },
|
|
768
|
+
options: { apiKey, repo, force, dryRun, agentName, invite, inviteMode: inviteSupplied, email, tools, codexProfile },
|
|
753
769
|
};
|
|
754
770
|
}
|
|
755
771
|
/**
|
|
@@ -4932,6 +4948,15 @@ export async function runInstallBridgeCli(argv, overrides = {}) {
|
|
|
4932
4948
|
// global (Codex) or manual (Windsurf) target is provisioned by the
|
|
4933
4949
|
// registry-driven emitter after the connectivity check.
|
|
4934
4950
|
const selectedPlatforms = await resolveSelectedHostPlatforms(deps, options);
|
|
4951
|
+
if (options.codexProfile && !selectedPlatforms.includes("codex")) {
|
|
4952
|
+
errorLog("Error: --codex-profile requires Codex in --tools or the interactive selection.");
|
|
4953
|
+
return 1;
|
|
4954
|
+
}
|
|
4955
|
+
let codexProfileChoice = options.codexProfile;
|
|
4956
|
+
if (selectedPlatforms.includes("codex") && !options.dryRun && !codexProfileChoice && deps.isTTY && deps.promptLine) {
|
|
4957
|
+
const answer = (await deps.promptLine("Install the opt-in Bridge Codex approval profile for spawned workers? (Y/n) ")).trim().toLowerCase();
|
|
4958
|
+
codexProfileChoice = answer === "" || answer === "y" || answer === "yes" ? "on" : "off";
|
|
4959
|
+
}
|
|
4935
4960
|
const targets = hostConfigTargetsForPlatforms(selectedPlatforms);
|
|
4936
4961
|
// Read-only detection (safe in dry-run) of global-config editors we can't write.
|
|
4937
4962
|
const manualEditors = await detectManualEditors(deps);
|
|
@@ -5712,6 +5737,28 @@ export async function runInstallBridgeCli(argv, overrides = {}) {
|
|
|
5712
5737
|
errorLog(" That host was left untouched. Re-run install-bridge once one entry is removed.");
|
|
5713
5738
|
return 1;
|
|
5714
5739
|
}
|
|
5740
|
+
if (selectedPlatforms.includes("codex")) {
|
|
5741
|
+
const home = codexHome(deps.env, deps.homedir());
|
|
5742
|
+
try {
|
|
5743
|
+
const profileDeps = {
|
|
5744
|
+
readFile: deps.readFile,
|
|
5745
|
+
writeFile: (p, data) => deps.writeFile(p, data, { encoding: "utf-8", mode: 0o600 }),
|
|
5746
|
+
mkdir: deps.mkdir,
|
|
5747
|
+
};
|
|
5748
|
+
const result = codexProfileChoice
|
|
5749
|
+
? await configureBridgeCodexProfile(home, codexProfileChoice === "on" ? "enable" : "decline", profileDeps)
|
|
5750
|
+
: await inspectBridgeCodexProfile(home, deps.readFile);
|
|
5751
|
+
if (result.status === "active")
|
|
5752
|
+
log(" Codex Bridge approval profile installed; spawned workers use --profile bridge.");
|
|
5753
|
+
else if (result.status === "declined" || result.status === "missing")
|
|
5754
|
+
log(" Codex Bridge approval profile inactive; spawned workers use existing Codex approvals. Opt in with --codex-profile=on.");
|
|
5755
|
+
else
|
|
5756
|
+
log(` Codex Bridge approval profile ${result.status}; spawned workers will not use it. Inspect ${home}/bridge.config.toml and rerun with --codex-profile=on.`);
|
|
5757
|
+
}
|
|
5758
|
+
catch {
|
|
5759
|
+
log(" Codex Bridge approval profile could not be configured; spawned workers will not use it. Inspect CODEX_HOME and rerun with --codex-profile=on.");
|
|
5760
|
+
}
|
|
5761
|
+
}
|
|
5715
5762
|
// Legacy manual-editor instructions cover editors that are DETECTED but were
|
|
5716
5763
|
// NOT part of the selection (so the emitter above did not handle them). The two
|
|
5717
5764
|
// editors are suppressed INDEPENDENTLY: Codex is dropped when it was selected
|
package/build/install-doctor.js
CHANGED
|
@@ -104,7 +104,7 @@ export async function resolveInstallDoctorTarget(deps) {
|
|
|
104
104
|
break;
|
|
105
105
|
}
|
|
106
106
|
}
|
|
107
|
-
return { repoName, repoSource, baseUrl: baseUrl ?? DEFAULT_BASE_URL };
|
|
107
|
+
return { repoName, repoSource, baseUrl: (baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "") };
|
|
108
108
|
}
|
|
109
109
|
/** Classify a thrown probe failure into the closed category vocabulary. */
|
|
110
110
|
function classifyProbeFailure(error) {
|
package/build/mcp-host-config.js
CHANGED
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
* rather than reserialize unrelated content.
|
|
29
29
|
*/
|
|
30
30
|
import { VERSION } from "./version.generated.js";
|
|
31
|
+
import { codexHome } from "./codex-home.js";
|
|
31
32
|
import { refreshBridgeApiPackageSpec } from "./init.js";
|
|
32
33
|
import { hostAdapterForTarget, } from "./mcp-host-targets.js";
|
|
33
34
|
import { adaptBridgeEntryForHostTarget, } from "./mcp-host-entry-adapter.js";
|
|
@@ -56,6 +57,9 @@ function dirnameOf(p) {
|
|
|
56
57
|
}
|
|
57
58
|
/** Resolve a target's absolute path from injected cwd/homedir. */
|
|
58
59
|
export function resolveTargetAbsPath(target, ctx) {
|
|
60
|
+
if (target.id === "codex" && ctx.env?.CODEX_HOME) {
|
|
61
|
+
return `${codexHome(ctx.env, ctx.homedir)}/config.toml`;
|
|
62
|
+
}
|
|
59
63
|
if (target.scope === "project") {
|
|
60
64
|
if (!target.relPath)
|
|
61
65
|
throw new Error(`${target.id} missing relPath`);
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
* platform is a matter of adding one entry to {@link MCP_HOST_TARGETS} plus its
|
|
16
16
|
* `PlatformId` union member.
|
|
17
17
|
*/
|
|
18
|
+
import { codexHome } from "./codex-home.js";
|
|
18
19
|
// ---------------------------------------------------------------------------
|
|
19
20
|
// Path helpers (pure)
|
|
20
21
|
// ---------------------------------------------------------------------------
|
|
@@ -190,6 +191,8 @@ export function getManualHostTargets() {
|
|
|
190
191
|
* Project targets resolve below `ctx.cwd`; global targets below `ctx.homedir`.
|
|
191
192
|
*/
|
|
192
193
|
export function resolveHostTargetPath(target, ctx) {
|
|
194
|
+
if (target.id === "codex" && ctx.env?.CODEX_HOME)
|
|
195
|
+
return `${codexHome(ctx.env, ctx.homedir)}/config.toml`;
|
|
193
196
|
if (target.scope === "project") {
|
|
194
197
|
if (!target.relPath) {
|
|
195
198
|
throw new Error(`project target ${target.id} is missing relPath`);
|
|
@@ -390,11 +390,11 @@ export const PIPELINES = {
|
|
|
390
390
|
"tool": "request_plan_generation",
|
|
391
391
|
"params": {
|
|
392
392
|
"ticket_number": "{ticket_key}",
|
|
393
|
-
"wait_for_result":
|
|
393
|
+
"wait_for_result": false,
|
|
394
394
|
"save_locally": true,
|
|
395
395
|
"provider": "{provider}"
|
|
396
396
|
},
|
|
397
|
-
"description": "
|
|
397
|
+
"description": "Submit implementation-plan generation without waiting through an MCP client deadline. Re-entry-safe: the backend reuses a fresh existing plan (reused: true, no new run). force is reserved for deliberate regeneration; this step never sets it. On a dropped connection or other ambiguous submission outcome, use get_plan to inspect the existing run — never reissue this step automatically."
|
|
398
398
|
},
|
|
399
399
|
{
|
|
400
400
|
"type": "agent_task",
|
|
@@ -827,7 +827,7 @@ export const PIPELINES = {
|
|
|
827
827
|
{
|
|
828
828
|
"type": "agent_task",
|
|
829
829
|
"id": "wait-for-ticket-review",
|
|
830
|
-
"instruction": "FIRST, check whether a review was actually submitted. The previous step runs with `on_error: warn_and_continue`, so a rejected submission (a 402, 403 or 500 from the generate endpoint, or a dropped connection) lets the pipeline continue into this step. If that step returned an error message rather than its submission confirmation or a `recovery_get` envelope, do NOT wait: nothing is running, and `wait_for_ticket_review` cannot tell \"never submitted\" from \"still running\" — it would read `pending` in every window until the caller's own timeout. Treat a failed submission as a terminal failure, report the error the previous step gave, and take the verdict contract's `revise` path.\n\nOtherwise, wait for the review submitted by the previous step to finish, using repeated BOUNDED windows.\n\nCall `wait_for_ticket_review` with `ticket_number` set to the ticket key. Each call
|
|
830
|
+
"instruction": "FIRST, check whether a review was actually submitted. The previous step runs with `on_error: warn_and_continue`, so a rejected submission (a 402, 403 or 500 from the generate endpoint, or a dropped connection) lets the pipeline continue into this step. If that step returned an error message rather than its submission confirmation or a `recovery_get` envelope, do NOT wait: nothing is running, and `wait_for_ticket_review` cannot tell \"never submitted\" from \"still running\" — it would read `pending` in every window until the caller's own timeout. Treat a failed submission as a terminal failure, report the error the previous step gave, and take the verdict contract's `revise` path.\n\nOtherwise, wait for the review submitted by the previous step to finish, using repeated BOUNDED windows.\n\nCall `wait_for_ticket_review` with `ticket_number` set to the ticket key. Each call uses the default 20-second window (set `budget_ms: 20000` explicitly if needed); do not use a longer window, because some MCP clients time out before a pending result arrives. The tool returns a JSON body with a `state` field:\n\n- `state: \"pending\"` — NORMAL and expected. The review is still running. Call the tool again immediately. Do NOT sleep, do NOT poll in a shell loop, and do NOT re-run `request_ticket_review`: re-submitting starts a second billable multi-model review and abandons the one already in flight.\n- `state: \"ready\"` — the review is over. BAPI-1121: a ready result has ALREADY persisted exactly the accepted documents and reconciled the canonical source files — it writes every leg in `saved_legs` to its canonical path and removes the stale canonical file for every leg in `withheld_legs`. Do NOT call `get_clarifying_questions` or `get_ticket_critique` after a ready result; those retrieval calls were removed from this recipe because reading them again could reintroduce exactly the stale content the wait just withheld. Treat `saved_legs` as the authoritative source set for the next steps, not file presence.\n - `freshness_basis: \"generation\"` is the normal case: `advanced_legs`/`saved_legs` are current-review evidence, proven newer than the submission. Any leg in `withheld_legs` was delivered but NOT proven current — surface its `reason` (`generation_not_advanced` or `identity_unreadable`) as a visible warning; do not describe the result as an ordinary cost-saved one-leg review when a withholding occurred. A leg in `absent_legs` with `reason: \"not_delivered\"` is an ordinary policy omission (e.g. an Easy-ticket clarify-only review) unless its status also flags it as policy-expected, in which case call that out too.\n - `freshness_basis: \"terminality_only\"` means no submission baseline was available (e.g. a resumed session) — `advanced_legs` is empty by construction and `saved_legs` was accepted on terminal delivery alone. Surface this prominently as a DEGRADED-freshness warning: the saved artifact(s) may be indistinguishable from a prior attachment, and the downstream identity-footer agreement check is the remaining backstop. Retain this warning when reporting to the next steps rather than treating a `terminality_only` ready result as equivalent to a `generation`-backed one.\n - If the result instead carries `state: \"error\"` alongside a persistence failure (an `ARTIFACT_PERSISTENCE_FAILED` `error`/`status`/`message` envelope), HALT rather than proceeding with whatever files happen to exist on disk — report the failure; the accepted legs already on disk before the failure are named in the envelope and are not lost, but nothing new was persisted for this window.\n- `state: \"error\"` — terminal. Report the `reason` and stop; the review will not complete on its own. `UPSTREAM_TERMINAL` means the review failed or expired server-side — take the verdict contract's `revise` path; do NOT open another wait window and do NOT re-run `request_ticket_review`. `INVALID_RESPONSE` means the delivered document could not be read.\n\nKeep looping on `pending` for as long as this session's own budget allows. There is no iteration cap here: the bound is the caller's — for the conductor's spec-review worker that is the existing 120-minute job timeout, which produces the ordinary liveness outcome if the review never lands. Never fabricate a verdict or a review result from a pending state.",
|
|
831
831
|
"description": "Wait for the submitted review in repeated bounded windows; a ready result has already persisted the accepted documents and reconciled the canonical files (BAPI-1121). Resumable: a pending result is a normal observation, not a failure.",
|
|
832
832
|
"on_error": "halt"
|
|
833
833
|
},
|
|
@@ -885,7 +885,7 @@ export const INSTRUCTIONS = {
|
|
|
885
885
|
"evaluate-and-recommend.md": "Evaluate the clarifying questions and ticket critiques generated for {ticket_key} against the actual codebase, then decorate every actionable item with the resolution guidance the reviewer will need on the decision page. The result is a single combined review-and-resolution document.\n\n## Phase 0 — Grounding & Audit Setup\n\nBefore gathering any source documents, extract the codebase-grounding context produced by the preceding `fresh_base` (`action: \"materialize\"`) pipeline step:\n\n- Read the `fresh_base` materialize tool result from earlier in this session. It returns JSON `{ base_sha, base_branch, fresh_base_root }` — or, when `no_refresh_base` was set, `{ base_sha: \"local-stale\", fresh_base_root: <original repo root> }`.\n- Retain `fresh_base_root` and `base_sha` for the rest of this procedure. Every codebase read in Phase 1 / Phase 2 below is grounded against `fresh_base_root`. `fresh_base_root` is also the exact value you must pass to the pipeline's later `fresh_base` (`action: \"cleanup\"`) step — it is a *runtime* value returned by the tool call, not a static recipe variable, so pass the real path string you captured here, not any placeholder text shown in the step's params.\n- If the materialize step's result contains an `error` field and `no_refresh_base` was NOT set, this is the fail-loud condition the recipe's `on_error: \"halt\"` exists for: stop here, do not fall back to grounding against your own working directory, and report the failure (name the attempted base branch and the remediation — retry, or rerun with `--no-refresh-base`).\n\n**Metadata Audit Header** — the very first content of the generated review-and-resolution document, before any other section, must be:\n\n```\n**Base SHA**: <base_sha>\n**Base Branch**: <base_branch, or \"(local, in-place)\" when base_sha is \"local-stale\">\n**Grounding Status**: <Freshly Materialized | Stale/In-Place Fallback>\n```\n\n- `Grounding Status` is **Freshly Materialized** whenever `base_sha` is a real commit SHA (the normal path).\n- `Grounding Status` is **Stale/In-Place Fallback** whenever `base_sha` is exactly `local-stale` (the `--no-refresh-base` opt-out path). In this case, immediately follow the header with a prominent, bold, high-contrast warning block, for example:\n\n > **⚠ STALE GROUNDING — `--no-refresh-base` was used.** This review evaluated the codebase as checked out locally, NOT a freshly-fetched `origin/<base>`. `file:line` citations may reflect uncommitted or unmerged local state.\n\n**Codebase grounding rule**: Ground ALL file reads and codebase searches exclusively against the `fresh_base_root` directory extracted above. Do NOT read codebase files from your default working directory or session cwd — `fresh_base_root` is the only trustworthy source of truth for `file:line` citations in this procedure.\n\n**Original-repo rule**: Ticket docs, `{docs_dir}` inputs, and ALL output paths stay in the ORIGINAL repository, never the `fresh_base_root` temp dir. This includes the ticket-fetch call below, the clarifying-questions / critique source documents, and the saved review-and-resolution output file (see the Save rule at the bottom). Do NOT redirect any of these into `fresh_base_root`.\n\n**Path hygiene rule**: Every `file:line` citation and Codebase Evidence entry in the output document MUST be repo-relative — strip the `fresh_base_root` absolute-path prefix before writing it down. A citation must never contain a temp-dir / `/tmp/...`-style absolute path (write `src/foo.ts:10`, never `/tmp/bridge-review-.../src/foo.ts:10`).\n\n1. Fetch the current ticket description using the `get_ticket` tool with ticket_number `{ticket_key}` exactly once at the top of this procedure.\n\n2. **Manifest authority (BAPI-1121).** The preceding `wait_for_ticket_review` step's ready result carries the authoritative `saved_legs` (plus `advanced_legs`, `withheld_legs`, `absent_legs`, and `freshness_basis`) — that wait persisted exactly those documents and already removed the canonical file for any withheld leg. Determine which source documents to gather from `saved_legs`, NOT from checking which files exist on disk: a leg's canonical file existing is a content LOCATION, never independent evidence that this review delivered it.\n\n - Read the source document only for a leg present in `saved_legs`, from its canonical path: `{docs_dir}/clarifying-questions/{ticket_key}-clarifying-questions.md` for `clarify`, `{docs_dir}/ticket-critiques/{ticket_key}-ticket-quality-critique.md` for `critique`.\n - A leg in `withheld_legs` or `absent_legs` must NOT be read or evaluated, even if a file happens to exist at its canonical path — a withheld leg's file was deliberately removed by the wait, and an absent leg's is either not present or, if one is, is not this review's output.\n - `advanced_legs` means strictly generation-proven current-review output. Under `freshness_basis: \"terminality_only\"` (no submission baseline was available to the wait), `advanced_legs` is intentionally empty even though `saved_legs` holds every terminally-delivered leg — surface this in the document's Round Agreement Summary as a degraded-freshness note (the artifacts may be indistinguishable from a prior attachment; the identity-footer agreement check downstream is the remaining backstop), rather than treating a `terminality_only` result as an ordinary fresh review.\n - **Stop and report** if a leg listed in `saved_legs` is missing or unreadable at its canonical content location — the wait's persisted manifest and the actual filesystem state have diverged, which is not a condition to paper over.\n - **Stop and report** if `saved_legs` is empty — no current-review source can be vouched for, so producing an evaluation from whatever happens to be on disk would silently source a review nobody delivered.\n\n After a second-opinion run, each document you DO gather has this shape:\n\n - A top-level H1 (`# Ticket Analysis` for clarifier docs, `# Ticket Quality Critique` for critique docs) followed by an italic provider-attribution line of the form `_This analysis was generated by GPT|Claude|Gemini._`. The attribution names the LLM family that produced the **first round**.\n - The first-round questions / critique items, exactly as written by the first-round model.\n - **Inline second-opinion blockquotes** nested directly under each prior item the second round addressed. Each blockquote starts with `> **Second opinion (<provider>) - <stance>.**` where `<provider>` is `GPT|Claude|Gemini` and `<stance>` is `concurrence|refinement|disagreement`. The blockquote is followed by `> *Citations: <comma-separated grounding refs>*`. Items the second round did **not** comment on have no blockquote — that is the \"weak concurrence\" signal. Use the provider name in the blockquote header to attribute the comment to the second-round LLM family in your evaluation prose where helpful.\n - A **`## New in Second Opinion`** tail block listing items the second round added on top of the first round. Immediately under the H2 you will find a second italic attribution line of the form `_These additional points were raised by GPT|Claude|Gemini._` — this names the second-round LLM family. Sub-headings are agent-specific:\n - Clarifier docs: `### New Requirements Questions` and `### New Technical Questions` — numbering continues from the prior section.\n - Critique docs: `### New Requested Changes` and `### New Points to Consider` — numbering continues from the prior section.\n Each new item has its own `*Citations: ...*` line.\n - A final **`## Second Opinion Summary`** footer (1-3 sentences) capturing the second round's overall position. This always renders, even when the second round had no inline comments and no new items.\n\n **Legacy fallback shape**: in rare cases (model lacks JSON-schema support, the JSON call failed, or the response could not be parsed), the document may instead end with `\\n\\n---\\n\\n` followed by a `## Second Opinion` section containing `### Response to Prior Items` and `### Additional Points` subsections. If you detect this fallback shape, treat it equivalently: subsection responses tagged `concurrence` map to weak/strong concurrence (use the body length to disambiguate — bare one-line concurrences are weak), `refinement`/`disagreement` map to the disagree buckets, and items under `### Additional Points` map to the gap-captured bucket below.\n\n **Partial-source-doc tolerance (manifest-driven, BAPI-1121)**: a leg absent from `saved_legs` because it is in `absent_legs` (an ordinary policy omission — e.g. an Easy-ticket clarify-only review) is skipped silently; produce items only for the leg(s) actually in `saved_legs`. Do not fail. If `saved_legs` contains neither leg, still write the combined output file at `{docs_dir}/review/{ticket_key}-review-and-resolution.md` with the standard top-level sections (`Confirmed Improvements`, `Needs Scrutiny`, `Open Questions`, `Round Agreement Summary`) present but no emitted E-items in any section — this preserves downstream file-existence expectations for the capture-review-decisions step. This is different from the stop-and-report cases just above: an *absent* leg is a normal shape to omit, a `saved_legs`-listed leg that cannot be read is not.\n\n3. Determine **Round Agreement** for every clarifying question and critique point using these rules:\n\n - **Both rounds agree (weak concurrence)** — the prior item has NO inline blockquote AND is not in `## New in Second Opinion`. The second round did not object to the point and did not consider it important enough to comment on. Briefly validate the answer's groundedness against the codebase. If validation surfaces concerns, demote this item to **rounds disagree** (single round only depth) and treat as Needs Scrutiny.\n - **Both rounds agree (strong concurrence)** — the prior item carries an inline `> **Second opinion (<provider>) - concurrence.** ...` blockquote. The second round explicitly reinforced the prior point. Reuse the blockquote's `*Citations:*` as starting evidence; verify briefly.\n - **Rounds disagree (refinement)** — the prior item carries an inline `> **Second opinion (<provider>) - refinement.** ...` blockquote. The second round modified or added detail. Apply full disagreement-depth analysis; reuse blockquote citations.\n - **Rounds disagree (disagreement)** — the prior item carries an inline `> **Second opinion (<provider>) - disagreement.** ...` blockquote. The second round contradicts the prior. Apply full disagreement-depth analysis; categorize the outcome based on which position the codebase supports.\n - **Gap captured** — the item lives under `## New in Second Opinion > ### New <category>` (one of: New Requirements Questions, New Technical Questions, New Requested Changes, New Points to Consider). Apply the two-axis check below. Reuse the new item's `*Citations:*` as starting evidence.\n - **Single round only** — the document has none of the above markers (no inline blockquotes, no `## New in Second Opinion` block, no `## Second Opinion Summary` footer). The pipeline ran only one round. Treat every item as a disagreement: cite 2+ codebase locations and give full analytical depth.\n\n Apply these depth and categorization rules:\n\n - **Both rounds agree (weak concurrence)**: 1 codebase citation, 1-2 sentence assessment confirming grounding. Categorize as Confirmed Improvement if grounded; demote to Needs Scrutiny if validation finds problems.\n - **Both rounds agree (strong concurrence)**: 1 codebase citation (may reuse a blockquote citation), 1-2 sentence assessment. Categorize as Confirmed Improvement.\n - **Rounds disagree (refinement or disagreement)**: 2+ codebase citations, 3-4 sentence assessment that explicitly weighs the prior-round position against the second-opinion position. Categorize based on which position the evidence supports. Always include both positions in the Assessment.\n - **Gap captured — two-axis check** (for items in `## New in Second Opinion`):\n - If both the question is grounded in the codebase/standards AND the best-guess answer is sensible → **Confirmed Improvement** with a 1-2 sentence assessment and 1 citation.\n - If the question is genuine but the best-guess answer is flawed → **Needs Scrutiny**. Cite 2+ files. Use disagreement-depth.\n - If the question itself does not hold up → **Needs Scrutiny** with evidence of what the code actually does. Disagreement-depth.\n - If neither codebase nor standards can settle the question → **Open Questions**. Disagreement-depth.\n - **Single round only**: Treat as a disagreement — cite 2+ codebase locations and give full analytical depth.\n\n For critique points (Requested Changes and Points to Consider), apply the same Round Agreement rules. The signal locations are inline `> **Second opinion (<provider>) - ...**` blockquotes nested under items in `### Requested Changes` / `### Points to Consider`, and gap-captured items under `## New in Second Opinion > ### New Requested Changes` / `### New Points to Consider`.\n\n **Depth calibration**:\n - When Round Agreement is `both rounds agree (weak concurrence)`, `both rounds agree (strong concurrence)`, or `gap captured` (passes both axes), keep Assessment to 1-2 sentences and Codebase Evidence to 1 citation — the validation step or the consensus does the heavy lifting.\n - When Round Agreement is `rounds disagree (refinement)`, `rounds disagree (disagreement)`, or `single round only`, Assessment should be 3-4 sentences and Codebase Evidence should cite 2+ files explaining the discrepancy.\n - A `gap captured` item that FAILS the two-axis check uses the disagreement depth, not the gap-captured depth.\n - A `weak concurrence` item that FAILS your validation gets demoted: change Round Agreement to `rounds disagree (single round only)`, expand Assessment to 3-4 sentences, and add a 2nd citation.\n\n **Source field conventions** — the `**Source**` string disambiguates where in the source doc the item lives so the downstream `capture-review-decisions` step can route the rewrite correctly. Use these forms:\n\n - **Weak concurrence (silent prior item)**: `Clarifying Q3 (prior round, weak concurrence)` or `Critique: Requested Change 2 (prior round, weak concurrence)`.\n - **Strong concurrence (explicit blockquote)**: `Clarifying Q9 (prior round, concurrence inline)` or `Critique: Points to Consider 1 (prior round, concurrence inline)`.\n - **Refinement (inline blockquote)**: `Clarifying Q3 (prior round, refinement inline)`.\n - **Disagreement (inline blockquote)**: `Clarifying Q5 (prior round, disagreement inline)`.\n - **Gap captured (tail-block item)**: `Clarifying Q11 (new in second opinion → New Requirements Questions)` or `Critique: Requested Change N+1 (new in second opinion → New Requested Changes)`. Always spell out the sub-section name after the arrow — capture-review-decisions uses it to find the rewrite target.\n - **Single round only**: `Clarifying Q3 (single round)`.\n\n## Phase 1 — Evaluate and classify every item\n\nNumber every item sequentially across all sections (E-1, E-2, E-3, …). When the same underlying issue is raised in BOTH the clarifying-questions doc and the critique doc, consolidate it into a SINGLE E-item rather than emitting one per source, and cite both origins in its `**Source**` field (e.g. `Clarifying Q3 + Critique: Requested Change 2`); keep the numbering sequential with no gaps. Classify every clarifying question and every critique point into exactly one of three buckets using the Round Agreement rules, codebase groundedness checks, and the `gap captured` two-axis check before producing any recommendation decoration:\n\n- **Confirmed Improvements**: Suggestions that are grounded and would genuinely improve the ticket by closing significant gaps or correcting design issues. Includes weak-concurrence items that passed validation, strong-concurrence items, and `gap captured` items that passed both axes.\n- **Needs Scrutiny**: Suggestions based on inaccurate codebase assumptions, with evidence of the actual code behavior. Includes `gap captured` items that failed either axis, weak-concurrence items demoted by validation, and the loser of any rounds-disagree pair.\n- **Open Questions**: Legitimate ambiguities that require human input to resolve.\n\nPhase 1 must complete before Phase 2 begins — do not start decorating an item with a decision tree, recommendation index, or clarity fields until classification is final.\n\n## Phase 2 — Decorate actionable items with resolution guidance\n\nPhase 2 applies **only** to items in the `Needs Scrutiny` and `Open Questions` buckets. Confirmed Improvements remain compact and undecorated (see \"Confirmed Improvements output\" below).\n\nFor every actionable (Needs Scrutiny / Open Questions) item, produce the following template using these stable labels:\n\n```\n### E-<sequential number>: <concise title>\n\n**Source**: <where this item lives in the source doc — see Source field conventions above>\n\n**Round Agreement**: <one of the six values> — <1 sentence on what the second round contributed>\n\n**Confidence**: <High|Medium|Low>\n\n**Resolution path**: <\"resolve at your desk\" or \"needs a conversation\">\n\n**Decision tree**:\n- If <condition 1>, then <action 1>. See `file:line`. <1-2 sentence rationale.>\n- If <condition 2>, then <action 2>. See `file:line`. <1-2 sentence rationale.>\n- If <condition 3>, then <action 3>. See `file:line`. <1-2 sentence rationale.>\n\n**Recommendation Index**: <0-based index of the recommended branch in the decision tree above>\n\n**Recommendation**: <which branch the evidence best supports and why, 1-2 sentences>\n\n**Original question**: <the clarifying-question or critique point as it was originally raised, sourced verbatim or near-verbatim from the original clarifying-questions / critique docs. Light rephrasing is allowed; do NOT introduce new technical content. Soft cap ~30 words.>\n\n**Option consequences**:\n- <consequence for branch 1 — describe the behavioral consequence of choosing this option, not its rationale. ~25 words.>\n- <consequence for branch 2 — same shape. ~25 words.>\n- <consequence for branch 3 — same shape. ~25 words.>\n\n**Why it matters**: <one concrete sentence on the impact this decision has on the ticket, the users, or the affected code paths. Soft cap ~40 words.>\n\n**Recommendation explanation**: <explain why the recommended branch is the best choice, tied to the codebase evidence and the consequences of each option. Soft cap ~60 words.>\n\n**Assessment**: <three-point structure>\n1. **State the original suggestion**: What did the clarifying question or critique point propose?\n2. **State the codebase evidence**: What does the actual code show about this suggestion?\n3. **State the implication**: Does the evidence confirm the suggestion, contradict it, or leave it unresolved?\n\n**Codebase Evidence**:\n- `path/to/file.ts:42` — <what this line/block demonstrates>\n- `path/to/other.ts:110-125` — <what this range demonstrates>\n\n<If no direct codebase evidence exists, state: \"No direct codebase evidence found.\">\n```\n\n**Writing quality**: Write each Assessment as if explaining to a colleague who has NOT read the original clarifying questions or critique documents. Each assessment should be self-contained and understandable without cross-referencing the source material. The three-point Assessment structure ensures every assessment tells a complete story rather than assuming the reader already knows what was suggested and why.\n\n**Decision tree rules**:\n- Each decision tree must have **2–4 branches**. Do not exceed 4 and do not produce only 1.\n- **Strict lower bound — reclassify on single-branch items**: If you can think of only one branch for a `Needs Scrutiny` or `Open Questions` item — that is, the resolution is effectively forced — you must reclassify the item as a **Confirmed Improvement** instead of emitting a single-branch decision tree. The 2-branch lower bound is a hard rule; do not work around it by stretching to a contrived second branch. If a single answer is genuinely the only path, the item belongs in Confirmed Improvements.\n- Each branch must end with a concrete, actionable step (not \"investigate further\").\n- Cite relevant code in `file:line` format where possible. If no code reference exists, omit the citation rather than fabricating one.\n- Cap each branch at 2-3 sentences total (including the action and rationale).\n- `**Recommendation Index**` must be the 0-based index of the recommended branch in the decision tree above. The first branch is index 0, the second is index 1, etc.\n- **Option consequences** must be a list parallel to the decision-tree branches: one entry per branch, in the same order. Describe the behavioral consequence of choosing that option, not its rationale.\n- **\"resolve at your desk\"**: The item can be resolved through technical investigation — reading code, running tests, or checking configuration. No stakeholder input needed.\n- **\"needs a conversation\"**: The item involves a product decision, scope question, or cross-team dependency that cannot be resolved from the codebase alone.\n\n**Confidence Tags** — assign confidence based on codebase evidence strength:\n- **High**: Cite specific `file:line` references that directly support the assessment.\n- **Medium**: Reference related code patterns or architectural conventions, but not the exact code in question.\n- **Low**: No direct codebase evidence. Assessment is based on general reasoning or domain knowledge.\n\n### Confirmed Improvements output\n\nRender each Confirmed Improvement as a single bullet in a compact list. No headings per item, no decision trees, no clarity-field decoration:\n\n- **E-<number>: <title>** — Source: <source string>; Round Agreement: <one of the six values>; Confidence: <High|Medium|Low>. <recommended action, 1 sentence.>\n\nThe compact bullet still includes `Source`, `Round Agreement`, `Confidence`, and the one-sentence recommended action so `capture-review-decisions.md` can map these items to its `clear_improvements` array.\n\n## Round Agreement Summary\n\nAfter all items are processed, produce a summary section that groups items by round agreement status:\n\n### Points of Disagreement\nFor items where the evaluation marked `rounds disagree (refinement)`, `rounds disagree (disagreement)`, or `single round only` — including `gap captured` items that failed the two-axis check and landed in Needs Scrutiny — list as bullets with the E-number, the nature of the disagreement, and a 1-sentence explanation of why this disagreement matters for the ticket (e.g., it indicates an architectural ambiguity, a scope question, or a standards gap).\n\nIf no items were marked as disagreements, write: \"All reviewed points had round consensus. No disagreement-driven risks identified.\"\n\n### Points of Agreement\nSplit this section into two sub-bullets to surface the difference between the second round explicitly reinforcing a point versus tacitly accepting it:\n\n**Strong agreement** — items where the evaluation marked `both rounds agree (strong concurrence)`. The second round took the trouble to write an explicit `concurrence` blockquote; this is a soft signal that the point is important enough that the second round wanted to underline it. List as bullets with the E-number and a half-sentence noting the shared conclusion.\n\n**Weak agreement** — items where the evaluation marked `both rounds agree (weak concurrence)`. The second round did not object and did not consider the item important enough to comment on; the local agent's brief validation found no concerns. List as bullets with the E-number and a half-sentence noting the conclusion. Lower priority for human review than strong-agreement items.\n\nIf a sub-bullet has no items, omit it (rather than writing a \"no items\" note for each — keep the section tidy).\n\n### Gaps Captured by Second Round\nFor items where the evaluation marked `gap captured` (sound second-opinion Additional Points confirmed as Confirmed Improvements): list as bullets with the E-number and a half-sentence noting the gap the second round surfaced. These items did not require a decision — they are already in Confirmed Improvements — but are surfaced here so the reviewer sees what the second-round analysis added on top of the first round.\n\nIf no gaps were captured, write: \"The second round did not surface any net-new confirmed improvements.\"\n\n## Edge Cases\n\n- If the evaluation contains zero items in Needs Scrutiny, write: \"No items flagged for scrutiny. All reviewed suggestions were either confirmed or remain open questions.\"\n- If the evaluation contains zero items in Open Questions, write: \"No open questions identified. All ambiguities were resolved through codebase analysis.\"\n- If both Needs Scrutiny and Open Questions are empty, include only the Confirmed Improvements section and add a summary: \"All suggestions from the review were confirmed as grounded improvements. No decision trees are needed.\"\n- If `saved_legs` contains neither leg, still write the combined file with the standard top-level sections present but no emitted E-items rather than failing.\n\n## Example of a Well-Written E-Item (Weak Concurrence — Confirmed Improvement)\n\n### E-2: Caching of analysis-type lookups\n\n**Source**: Clarifying Q4 (prior round, weak concurrence)\n\n**Round Agreement**: both rounds agree (weak concurrence) — the second round did not comment on this item; brief validation confirms the answer is grounded.\n\n**Assessment**: The prior round suggested caching `ANALYSIS_TYPES` lookups in a module-level variable to avoid repeated DB round trips. The codebase already does this at `src/python/learn_repository/__init__.py:14`, so the suggestion is grounded and the second round's silence is consistent with tacit agreement.\n\n**Codebase Evidence**:\n- `src/python/learn_repository/__init__.py:14` — module-level constant pattern is the established convention\n\n(Confirmed Improvements compact bullet form: **E-2: Caching of analysis-type lookups** — Source: Clarifying Q4 (prior round, weak concurrence); Round Agreement: both rounds agree (weak concurrence); Confidence: High. Confirm the existing module-level cache and add a short comment naming the pattern.)\n\n## Example of a Well-Written E-Item (Strong Concurrence — Confirmed Improvement)\n\n### E-4: Sequential per-type review_repository fan-out\n\n**Source**: Clarifying Technical Q2 (prior round, concurrence inline)\n\n**Round Agreement**: both rounds agree (strong concurrence) — the second round explicitly reinforced the prior recommendation, citing per-type lock release simplicity as the deciding factor.\n\n**Assessment**: The prior round recommended sequential per-type execution; the second-opinion blockquote reinforced this, noting that the per-type lock release contract becomes trivial under sequential execution. `review_repository` already uses internal `asyncio.gather` for chunk-level concurrency, so wrapping it in another concurrency layer would not buy throughput and would complicate the abort/finally cleanup contract.\n\n**Codebase Evidence**:\n- `src/python/learn_repository/review_repository.py:369-387` — review_repository internally gathers chunks with return_exceptions=True\n\n## Example of a Well-Written E-Item (Rounds Disagree — Needs Scrutiny with full clarity fields)\n\n### E-5: Authentication middleware placement for new endpoint\n\n**Source**: Clarifying Q2 (prior round, disagreement inline)\n\n**Round Agreement**: rounds disagree (disagreement) — the prior round recommended adding auth at the router level; the second-opinion blockquote argued the existing middleware stack already covers it.\n\n**Confidence**: High\n\n**Resolution path**: resolve at your desk\n\n**Decision tree**:\n- If the global middleware stack already enforces auth on `/api/*` routes, then drop the explicit `Depends(require_api_key)` from the new endpoint. See `main.py:45-52`.\n- If routers each opt in to auth via dependencies, then add `Depends(require_api_key)` to the new endpoint. See `api/routes/__init__.py:18-30`.\n- If only certain `/api/*` sub-paths need auth, then carve out a sub-router with its own dependency. See `api/routes/__init__.py:18-30`.\n\n**Recommendation Index**: 1\n\n**Recommendation**: The existing routers each opt in to auth, so the new endpoint must do the same. Adding `Depends(require_api_key)` is the smallest correct change.\n\n**Original question**: Should the new `/api/exports` endpoint declare an explicit auth dependency, or is it covered by the global middleware?\n\n**Option consequences**:\n- Endpoint becomes publicly reachable; protected data leaks via the new path.\n- Endpoint requires a valid API key, matching every other `/api/*` route.\n- Adds a parallel router; doubles the auth surface that has to be kept consistent.\n\n**Why it matters**: Authentication on `/api/exports` directly determines whether protected data leaks; the wrong default is a security regression, not a stylistic choice.\n\n**Recommendation explanation**: The codebase pattern in `api/routes/__init__.py:18-30` shows each router declaring its own `Depends(require_api_key)`. Following that convention adds two lines, keeps auth uniform across endpoints, and avoids a parallel sub-router that future maintainers would have to keep in sync.\n\n**Assessment**: The prior round suggested that the new `/api/exports` endpoint needs an explicit `Depends(require_api_key)` guard because it is not covered by the global middleware. The second opinion disagreed, claiming the middleware stack in `main.py` handles authentication for all `/api/*` routes. Codebase analysis shows that `main.py:45-52` applies rate limiting globally but authentication is applied per-router in `api/routes/__init__.py:18-30` — each router must opt in via `Depends(require_api_key)`. This supports the prior round's position: the new endpoint needs an explicit auth dependency.\n\n**Codebase Evidence**:\n- `main.py:45-52` — global middleware applies rate limiting and CORS, but not authentication\n- `api/routes/__init__.py:18-30` — each router includes its own auth dependency; there is no catch-all auth middleware\n\n## Example of a Well-Written E-Item (Gap Captured — Confirmed Improvement)\n\n### E-7: Missing Alembic migration for new role-scope column\n\n**Source**: Critique: Requested Change N+1 (new in second opinion → New Requested Changes)\n\n**Round Agreement**: gap captured — the second opinion surfaced a missing migration that the prior round did not raise, and recommended adding an Alembic revision.\n\n**Assessment**: The ticket introduces a new `role_scope` column on the `users` table but does not mention a migration. The second opinion flagged this gap and recommended adding an Alembic revision; both the gap and the recommendation are grounded, since `db/alembic/versions/` is the established location for schema changes per the project's database guide.\n\n**Codebase Evidence**:\n- `db/alembic/versions/` — all schema changes land here as autogenerated revisions\n\n## Save rule\n\nSave the combined review-and-resolution document to `{docs_dir}/review/{ticket_key}-review-and-resolution.md`. Output only the combined review-and-resolution document — no meta-commentary.\n\n## Return\n\nConfirm \"Review-and-resolution document written to `{docs_dir}/review/{ticket_key}-review-and-resolution.md`.\" and report the total count of E-items captured.\n",
|
|
886
886
|
"execute-epic-research.md": "Execute the research plan and write findings.\n\n## Instructions\n\n1. Read the research plan from `{docs_dir}/epic-plans/{epic_slug}/research-plan.md`.\n\n2. Execute the plan based on the Research Mode:\n\n **If mode is `deep`**:\n - Call the `request_deep_research` MCP tool with:\n - `query`: the Deep Research Query from the plan\n - `context`: \"Bridge API is a Python/FastAPI application with PostgreSQL, LiteLLM, and Pinecone. This research supports epic planning for: {epic_description}\"\n - `wait_for_result`: true\n - `save_locally`: true\n - If deep research fails, log a warning and fall back to web searches using the Web Search Topics from the plan. Do NOT halt.\n\n **If mode is `web`**:\n - Perform web searches for each topic listed in the plan.\n - Capture relevant findings from each search.\n\n **If mode is `none`**:\n - Write a brief note: \"No external research needed. Proceeding with codebase exploration.\"\n\n3. Write all findings to `{docs_dir}/epic-plans/{epic_slug}/research-findings.md` with this structure:\n\n```markdown\n# Research Findings\n\n## Mode\n{deep | web | none}\n\n## Findings\n{Synthesized research results organized by topic. Include source references where applicable.}\n\n## Key Takeaways\n{Bullet points summarizing the most important findings that will inform the codebase exploration and epic decomposition.}\n```\n\n## Return\n\nConfirm research findings were written to `{docs_dir}/epic-plans/{epic_slug}/research-findings.md` and report the mode used (`deep`, `web`, or `none`) plus a one-line summary of the key takeaways.\n",
|
|
887
887
|
"execute-plan-verification.md": "Execute the remaining plan steps for ticket {ticket_key} — faithfully — before the pull request opens.\n\nThe production phase authored the artifacts and the checkpoint pushed them to origin.\nThis phase runs everything else the plan asked for: its review steps, its\ntest-execution steps, and — when the plan authored one — its rendered-UI remediation\nloop.\n\n**This phase runs the plan as written.** It has no fixed depth and no cost-based\nnarrowing rule. If the plan says to grep for every call site of a changed signature,\ngrep for every call site. If it supplies a test command, run that command. A step is\nnot narrowed, substituted, or dropped because it is expensive or slow — that judgment\nis what removed a whole class of plan steps from execution in the first place.\n\nRunning before the pull request is deliberate. The remediation loop *changes code*.\nRunning it after the PR opened would guarantee the PR's first head carried the\nun-iterated first draft, and would pay `claude-review` plus `conductor-ci` on every\none of up to three cycles. The work is durable on origin throughout; it is simply not\nexternally visible until the PR opens a moment later.\n\n**Tool and scope boundary.** Use only the tools this recipe names, the repo's own tooling, and MCP\ncapabilities provisioned for this repository. Keep all work confined to this worktree unless\nexplicitly told to do otherwise.\n\n**Execution mode for this run: `{execution_mode}`.** Under `orchestrated`\n(a server-side orchestrator) orchestration appends the routed phase context and\nparses the fenced result envelope you return. Under `inline` (`get_pipeline_recipe`)\nthere is no orchestrator: you obtain routing and the prior ledger with a tool call, and\nyou record your result with one. Follow the branch that matches wherever the two are\nnamed.\n\n---\n\n## Step 1 — Confirm the Checkpoint Is Durable\n\nBefore starting any long-running work:\n\n1. Run `git rev-parse --abbrev-ref HEAD` and `git rev-parse HEAD`.\n2. Confirm the checkpoint SHA recorded by `checkpoint-work.md` is present on origin —\n `git ls-remote --heads origin <branch>`. The recorded checkpoint comes from the\n routed context's `checkpoint` block when **orchestrated**, and from the `checkpoint`\n field `get_phase_context` returns in Step 2 when **inline**.\n\nIf the branch is not on origin, or HEAD and the recorded checkpoint disagree, **stop and report it**. This phase is long; entering it without recoverable work reintroduces\nthe failure the checkpoint exists to prevent.\n\n## Step 2 — Determine What You Own\n\n1. Call `get_plan` for `{ticket_key}` to retrieve the plan body.\n2. Obtain your routing and the prior ledger, by mode:\n - **orchestrated** — read the **Routed phase context** block appended to this\n instruction. `ownedSteps` lists the exact step IDs this phase must settle;\n `ledger` carries what earlier phases already recorded.\n - **inline** — call `get_phase_context` with `ticket_key` `{ticket_key}` and\n `phase` `pre_pr_verification`. It returns `ownedSteps`, the merged `ledger`,\n `terminalStepIds`, and the durable `checkpoint` Step 1 needs.\n3. Do not re-run a step the ledger already records as `executed` or `adapted` unless a\n correction since then invalidated its evidence. Settle such a step in your phase\n result anyway, with evidence naming the prior record — every owned step must be\n reported, and one you correctly skipped is settled, not missing.\n4. Name the routing source you used when you report, either the routed phase context\n or the `routingSource` value the tool returned.\n\nIf `get_phase_context` reports an error, or the routed context is absent or its\nmetadata status is not `ok`, say so plainly and execute every remaining review,\ntest-execution, and rendered-UI step in the plan. When routing is unavailable here the\nsafe failure is to run more, not less — this phase only verifies, so over-running costs\ntime, while under-running ships unverified work.\n\n## Step 3 — Execute in Plan Order\n\nWork through your owned steps in their original plan order — review steps,\nplan-authored test commands, static searches, architecture-conformance checks, runtime checks,\nand rendered-UI remediation.\n\nRun each command the plan supplies, as the plan supplies it.\n\n### Mechanical adaptation, and its boundary\n\nYou may correct a step **mechanically**, in exactly three ways:\n\n- **locator-correction** — a cited path, file, symbol, or selector has moved or is\n absent (a `docs/tmp/` citation missing from the worktree is the common case, since\n those paths are gitignored). Use the correct locator, or proceed without the\n material, and record it.\n- **repository-command-correction** — the step names a command that is not this\n repository's actual command. Use the real one.\n- **equivalent-implementation-recognized** — what the step asks for already exists in\n equivalent form.\n\n**Escalate** anything involving design, schema, public API, dependencies, or security.\nThose change what the step asks for rather than how it is addressed.\n\nA capability the environment genuinely cannot provide, and a check that genuinely\nrequires an open pull request, are handed forward to the post-PR gap-closing phase as\n`escalated` with that reason recorded. Everything else is executed here.\n\n**Never silently skip a step.** Every owned step ends as `executed`, `adapted`,\n`escalated`, or `unrun-advisory` — the last only when the plan itself declared that range advisory.\n\n## Step 4 — Rendered-UI Remediation\n\nWhen the plan authored a rendered-UI loop, run it as written:\n\n1. Render the actual implementation.\n2. Score every dimension of the plan's fixed rubric, recording the completed table —\n dimension, score, one-sentence reason, and fix attempted — for that cycle.\n3. Apply the accepted fixes.\n4. Stop as soon as the plan's threshold is met; otherwise repeat, to the plan's\n three-cycle cap.\n5. If the cap is reached with dimensions still below threshold, record the final\n scores and the unresolved defects as an **escalation**. Do not claim acceptance.\n\nThe rubric table and the accepted fixes are the evidence that the loop ran. Carry them\nin this step's record.\n\n## Step 5 — Publish Every Material Change Immediately\n\nAfter each material code change:\n\n1. Stage the specific files, commit, and **push immediately**. The commit and its push\n are one consecutive sequence, never separated by another check. An unpushed\n correction is invisible to the pull request, to CI, and to the reconciler.\n2. Run `git rev-parse HEAD` and record the new pushed SHA.\n\nThen continue with the next verification action. Do not batch several cycles of\nchanges behind a single push — the point of pushing immediately is that the next\nlong-running action cannot strand them.\n\n## Step 6 — Report Honestly\n\nRecord the exact command run, its observed result, and on failure the relevant detail:\nfailing test names, error output, diagnostic lines. Report all of it, including\nfailures you did not fix.\n\n**Do not issue a gate verdict.** Do not write that CI passed, that the gate is met, or\nthat the review is approved. Those states are decided by the `ci` and `code_review`\ngates and observed by the reconciler, never asserted by this phase. Worker\nself-verification has reported green while the full suite was red; that is why the\ngates decide and this phase only observes.\n\n## Return\n\nReport the branch, the latest pushed SHA, every command run with its observed outcome,\nevery correction commit pushed, and every unresolved finding.\n\nThen record the machine-readable phase result, by mode.\n\n### orchestrated\n\nEnd your result with the envelope in a fenced block tagged `bapi-phase-result`.\nOrchestration validates it against the steps you own and persists it as durable state;\nan owned step you do not report will be rejected.\n\n```bapi-phase-result\n{\"version\":1,\"phase\":\"pre_pr_verification\",\"lastCommitSha\":\"<sha>\",\"records\":[{\"stepId\":12,\"provenanceClass\":\"final_plan_review\",\"disposition\":\"executed\",\"evidence\":\"grepped all call sites of changed signature; 4 found, all updated\"}]}\n```\n\n### inline\n\nCall the `record_phase_result` tool with `ticket_key` `{ticket_key}` and\n`phase_result` set to that same envelope object. The tool validates it against the\nsteps you own and persists it to the durable ledger; an owned step you do not report\nis rejected there. **Do not also emit a fenced `bapi-phase-result` block** — nothing\nparses one on this path.\n\nThe tool call is this phase's final action, **not the end of your turn.** When it\nreturns successfully, continue immediately with the next recipe step —\n`commit-and-push.md`, then the pull request. Stopping here leaves verified work with no\npull request, which is how an earlier run stranded four pushed correction commits.\n\nIf the call fails, fix what it reports and call it again.\n",
|
|
888
|
-
"execute-plan.md": "Execute the production obligations of the AI-generated implementation plan for ticket {ticket_key}.\n\nThis is the **production phase**. It authors artifacts. It is followed immediately by\na deterministic checkpoint (`checkpoint-work.md`) that commits and pushes everything\nproduced here, and then by the pre-PR verification phase\n(`execute-plan-verification.md`) that runs the plan's remaining steps.\n\nThe phase boundary is about *what kind of work* each phase does, not about postponing\ninconvenient work. This phase writes code, tests, migrations, fixtures, and\nconfiguration. It does not run the plan's review steps, its test-execution steps, or\nits rendered-UI remediation loop — those belong to the pre-PR verification phase,\nwhich owns them explicitly and will execute them. They are routed, not deferred:\nevery step in the plan is assigned to a phase, and the phase that owns a step is\nrequired to settle it.\n\n**Tool and scope boundary.** Use only the tools this recipe names, the repo's own tooling, and MCP\ncapabilities provisioned for this repository. Keep all work confined to this worktree unless\nexplicitly told to do otherwise.\n\n**Execution mode for this run: `{execution_mode}`.** Two executors run this file and\nthey differ in exactly one respect — who keeps the durable record:\n\n- `orchestrated` — a server-side orchestrator drives the recipe. Orchestration\n appends the routed phase context below, and it parses, validates, and persists the\n fenced result envelope you return.\n- `inline` — `get_pipeline_recipe` returned the recipe and you are executing every\n step yourself. **No orchestrator is watching.** Nothing appends routed context and\n nothing reads a returned envelope. You derive your own routing and record your own\n result, both through tool calls, and then you keep going to the next recipe step.\n\nFollow the branch that matches the mode above wherever the two are named.\n\n---\n\n## Step 1 — Retrieve the Plan and Your Routing\n\n1. Call the `get_plan` tool for `{ticket_key}` to retrieve the plan body.\n2. Derive the total number of steps from the returned plan.\n3. Determine your owned set, by mode:\n - **orchestrated** — read the **Routed phase context** block appended to this\n instruction. It carries `ownedSteps` — the exact step IDs this phase must\n settle — and `ledger`, the durable record of work already completed.\n - **inline** — call the `get_phase_context` tool with `ticket_key`\n `{ticket_key}` and `phase` `produce`. It returns the same `ownedSteps`,\n `ownedRanges`, and `ledger`, derived server-side from the plan's provenance\n metadata by the same code the orchestrator uses.\n4. Announce: **\"Plan contains N steps. This phase owns M of them.\"** — and name the\n routing source you used, either the routed phase context or the `routingSource`\n value `get_phase_context` returned. Silence about the source is what made an\n earlier run's ownership claim unauditable.\n\nIf `get_phase_context` reports an error, or the routed context is absent or reports\n`plan_metadata_status` other than `ok`, **stop before making any production change**\nand report the reason. Do **not** infer ownership by keyword-matching the plan prose;\nguessing ownership from prose is what let an entire class of steps go unexecuted, and\nproducing artifacts against a routing you cannot verify is worse than producing none.\n\nThe local file at `{docs_dir}/plans/{ticket_key}-plan.md` is a saved copy of the same\nplan and may be used as a reference.\n\n## Step 2 — Re-entry Check\n\nA retry after a checkpoint re-enters this phase against a worktree that may already\ncontain the produced work. Before executing anything:\n\n1. Run `git status --porcelain` and `git rev-parse HEAD`.\n2. If the durable ledger already records a step as `executed` or `adapted`, that work\n is done. Do not redo it and do not apply it a second time. Inline, that ledger is\n the `ledger` / `terminalStepIds` `get_phase_context` returned; orchestrated, it is\n the `ledger` in the routed context. Report such a step as `executed` again in your\n phase result, with evidence naming the prior record — the phase result must settle\n every owned step, and a step you skipped because it was already done is settled,\n not missing.\n3. If the ledger is empty but the worktree or the current HEAD already contains the\n artifacts a step calls for, verify the existing artifact is equivalent to what the\n step asks for and record the step as `executed`, noting that it was already\n present. Creating it again risks duplicating or clobbering it.\n\nRe-entry is normal — recovery runs (`ci_fix`, `remediate`, `rebase`) re-enter this\nrecipe from step 1 and reuse the existing plan. Treat an already-satisfied step as\nsatisfied, not as a reason to start over.\n\n## Step 3 — Execute Each Owned Production Step in Order\n\nFor each step in the plan, in strict plan order:\n\n1. **Announce** before starting: **\"Step X of N: <step title from plan>\"**\n2. **Execute** its production work, making the code changes it directs.\n3. **Confirm** after completing: **\"Step X complete — <brief summary>.\"**\n\n### Rules\n\n- **Produce every implementation artifact the plan asks for.** Production code,\n test code, database migrations, generated-source inputs, fixtures, and\n configuration files are all authored in this phase. A step that creates a test file is production\n work and must be completed here — only the *execution* of that test belongs to the\n next phase.\n- **Leave verification actions inside later ranges alone.** Steps you do not own are\n executed by the phase that owns them, which runs before the pull request opens. Do\n not run them here, and do not treat them as skipped.\n- Preserve strict plan order and sequential order within a step. Do not reorder or\n combine steps.\n- **This phase has no commit or push authority of its own.** `checkpoint-work.md` runs\n immediately after it and owns `git commit` and `git push` for the work produced\n here. Do not commit or push ad hoc — a deterministic step owns that boundary\n precisely so the durability guarantee does not depend on prose.\n- Lightweight commands needed to *perform* a change are fine — listing or reading\n files, searching the codebase, inspecting git state, running a code generator whose\n output a later edit consumes.\n- Do not create the pull request. `create-pr.md` owns that.\n\n### When a step's premise is false\n\nA plan step sometimes cites something that is not there. Generated plans routinely\nreference `docs/tmp/` files that are absent from a worktree, because those paths are\ngitignored. That is a **discovery case**, not a failure: locate the equivalent\nmaterial, or proceed without it, and record a locator adaptation.\n\nYou may adapt **mechanically**, and only in these three ways:\n\n- **locator-correction** — the step names a path, file, symbol, or selector that has\n moved or does not exist, and you use the correct one.\n- **repository-command-correction** — the step names a command that is not this\n repository's actual command, and you use the real one.\n- **equivalent-implementation-recognized** — the change the step asks for already\n exists in an equivalent form.\n\nAnything touching **design, schema, public API, dependencies, or security escalates.**\nThose are not corrections to how a step is addressed; they are changes to what it\nasks for, and that decision is not yours to make silently.\n\nRecord every adaptation with the original premise, the correction made, and a one-line\nrationale. **Never silently skip a step.** A step you cannot execute is `escalated`\nwith a reason — a step that vanishes without a record is the exact defect this\nprotocol exists to remove.\n\nIf a requirement is ambiguous because the plan lacks ticket detail, call the\n`get_ticket` tool with `ticket_number` set to `{ticket_key}`, use only the fields\nrelevant to the unresolved requirement, and continue. Do not call `get_ticket`\nunconditionally — `get_plan` in Step 1 remains the sole unconditional context\nretrieval.\n\n## Step 4 — Final Audit\n\n1. Re-enumerate every step you own from the routed context.\n2. Confirm each one has a terminal disposition: `executed`, `adapted`, `escalated`, or\n `unrun-advisory` (the last only when the plan itself declares that range advisory).\n3. Announce: **\"Audit complete — M of M owned steps settled.\"**\n\n## Return\n\nReport production coverage: which owned steps were executed, which were mechanically\nadapted and how, and which were escalated and why.\n\nThen record the machine-readable phase result. **How you record it depends on the\nmode**, and the difference is not cosmetic — it is the difference between a durable\nrecord and a message to nobody.\n\n### orchestrated\n\nEnd your result with the envelope in a fenced block tagged `bapi-phase-result`.\nOrchestration parses this block, validates it against the steps you own, and persists\nit as durable state that survives an approval pause and a resumed session. A step you\nowned but did not report will be rejected.\n\n```bapi-phase-result\n{\"version\":1,\"phase\":\"produce\",\"records\":[{\"stepId\":1,\"provenanceClass\":\"implementation\",\"disposition\":\"executed\",\"evidence\":\"created src/foo.py and its migration\"}]}\n```\n\n### inline\n\nCall the `record_phase_result` tool with `ticket_key` `{ticket_key}` and\n`phase_result` set to that same envelope object. The tool validates it against the\nsteps you own and persists it to the durable ledger; a step you owned but did not\nreport is rejected there, and an owned step left unsettled fails the call rather than\ndisappearing. **Do not also emit a fenced `bapi-phase-result` block** — inline there is\nno orchestration to parse one, and a text envelope addressed to nobody is exactly what\nused to end the turn here.\n\nThe tool call is this phase's final action. **It is not the end of your turn.** When it\nreturns successfully the produce phase is complete and the *next recipe step* —\n`checkpoint-work.md`, which pushes everything you just produced — begins immediately.\nContinue to it in the same turn. Stopping here strands the work you just authored in an\nuncommitted worktree, which is the single most damaging way this pipeline has failed.\n\nIf the call fails, fix what it reports and call it again. Do not proceed past a failed\nrecording: an unrecorded phase result means the next phase reads an empty ledger and\nredoes work you already did.\n",
|
|
888
|
+
"execute-plan.md": "Execute the production obligations of the AI-generated implementation plan for ticket {ticket_key}.\n\nThis is the **production phase**. It authors artifacts. It is followed immediately by\na deterministic checkpoint (`checkpoint-work.md`) that commits and pushes everything\nproduced here, and then by the pre-PR verification phase\n(`execute-plan-verification.md`) that runs the plan's remaining steps.\n\nThe phase boundary is about *what kind of work* each phase does, not about postponing\ninconvenient work. This phase writes code, tests, migrations, fixtures, and\nconfiguration. It does not run the plan's review steps, its test-execution steps, or\nits rendered-UI remediation loop — those belong to the pre-PR verification phase,\nwhich owns them explicitly and will execute them. They are routed, not deferred:\nevery step in the plan is assigned to a phase, and the phase that owns a step is\nrequired to settle it.\n\n**Tool and scope boundary.** Use only the tools this recipe names, the repo's own tooling, and MCP\ncapabilities provisioned for this repository. Keep all work confined to this worktree unless\nexplicitly told to do otherwise.\n\n**Execution mode for this run: `{execution_mode}`.** Two executors run this file and\nthey differ in exactly one respect — who keeps the durable record:\n\n- `orchestrated` — a server-side orchestrator drives the recipe. Orchestration\n appends the routed phase context below, and it parses, validates, and persists the\n fenced result envelope you return.\n- `inline` — `get_pipeline_recipe` returned the recipe and you are executing every\n step yourself. **No orchestrator is watching.** Nothing appends routed context and\n nothing reads a returned envelope. You derive your own routing and record your own\n result, both through tool calls, and then you keep going to the next recipe step.\n\nFollow the branch that matches the mode above wherever the two are named.\n\n---\n\n## Step 1 — Retrieve the Plan and Your Routing\n\n1. Call `get_plan` for `{ticket_key}` with `budget_ms: 20000` and `save_locally: true`. This opens one bounded wait window for the plan submitted by the prior step. A JSON `state: \"pending\"` is normal: call `get_plan` again with the same arguments, without sleeping or re-running `request_plan_generation`. Repeat until the tool returns plan markdown. A JSON `state: \"error\"` is terminal; report its reason and stop. If the prior submission failed unambiguously, stop without waiting. Preserve the plan markdown as the source for the remaining steps.\n2. Derive the total number of steps from the returned plan.\n3. Determine your owned set, by mode:\n - **orchestrated** — read the **Routed phase context** block appended to this\n instruction. It carries `ownedSteps` — the exact step IDs this phase must\n settle — and `ledger`, the durable record of work already completed.\n - **inline** — call the `get_phase_context` tool with `ticket_key`\n `{ticket_key}` and `phase` `produce`. It returns the same `ownedSteps`,\n `ownedRanges`, and `ledger`, derived server-side from the plan's provenance\n metadata by the same code the orchestrator uses.\n4. Announce: **\"Plan contains N steps. This phase owns M of them.\"** — and name the\n routing source you used, either the routed phase context or the `routingSource`\n value `get_phase_context` returned. Silence about the source is what made an\n earlier run's ownership claim unauditable.\n\nIf `get_phase_context` reports an error, or the routed context is absent or reports\n`plan_metadata_status` other than `ok`, **stop before making any production change**\nand report the reason. Do **not** infer ownership by keyword-matching the plan prose;\nguessing ownership from prose is what let an entire class of steps go unexecuted, and\nproducing artifacts against a routing you cannot verify is worse than producing none.\n\nThe local file at `{docs_dir}/plans/{ticket_key}-plan.md` is a saved copy of the same\nplan and may be used as a reference.\n\n## Step 2 — Re-entry Check\n\nA retry after a checkpoint re-enters this phase against a worktree that may already\ncontain the produced work. Before executing anything:\n\n1. Run `git status --porcelain` and `git rev-parse HEAD`.\n2. If the durable ledger already records a step as `executed` or `adapted`, that work\n is done. Do not redo it and do not apply it a second time. Inline, that ledger is\n the `ledger` / `terminalStepIds` `get_phase_context` returned; orchestrated, it is\n the `ledger` in the routed context. Report such a step as `executed` again in your\n phase result, with evidence naming the prior record — the phase result must settle\n every owned step, and a step you skipped because it was already done is settled,\n not missing.\n3. If the ledger is empty but the worktree or the current HEAD already contains the\n artifacts a step calls for, verify the existing artifact is equivalent to what the\n step asks for and record the step as `executed`, noting that it was already\n present. Creating it again risks duplicating or clobbering it.\n\nRe-entry is normal — recovery runs (`ci_fix`, `remediate`, `rebase`) re-enter this\nrecipe from step 1 and reuse the existing plan. Treat an already-satisfied step as\nsatisfied, not as a reason to start over.\n\n## Step 3 — Execute Each Owned Production Step in Order\n\nFor each step in the plan, in strict plan order:\n\n1. **Announce** before starting: **\"Step X of N: <step title from plan>\"**\n2. **Execute** its production work, making the code changes it directs.\n3. **Confirm** after completing: **\"Step X complete — <brief summary>.\"**\n\n### Rules\n\n- **Produce every implementation artifact the plan asks for.** Production code,\n test code, database migrations, generated-source inputs, fixtures, and\n configuration files are all authored in this phase. A step that creates a test file is production\n work and must be completed here — only the *execution* of that test belongs to the\n next phase.\n- **Leave verification actions inside later ranges alone.** Steps you do not own are\n executed by the phase that owns them, which runs before the pull request opens. Do\n not run them here, and do not treat them as skipped.\n- Preserve strict plan order and sequential order within a step. Do not reorder or\n combine steps.\n- **This phase has no commit or push authority of its own.** `checkpoint-work.md` runs\n immediately after it and owns `git commit` and `git push` for the work produced\n here. Do not commit or push ad hoc — a deterministic step owns that boundary\n precisely so the durability guarantee does not depend on prose.\n- Lightweight commands needed to *perform* a change are fine — listing or reading\n files, searching the codebase, inspecting git state, running a code generator whose\n output a later edit consumes.\n- Do not create the pull request. `create-pr.md` owns that.\n\n### When a step's premise is false\n\nA plan step sometimes cites something that is not there. Generated plans routinely\nreference `docs/tmp/` files that are absent from a worktree, because those paths are\ngitignored. That is a **discovery case**, not a failure: locate the equivalent\nmaterial, or proceed without it, and record a locator adaptation.\n\nYou may adapt **mechanically**, and only in these three ways:\n\n- **locator-correction** — the step names a path, file, symbol, or selector that has\n moved or does not exist, and you use the correct one.\n- **repository-command-correction** — the step names a command that is not this\n repository's actual command, and you use the real one.\n- **equivalent-implementation-recognized** — the change the step asks for already\n exists in an equivalent form.\n\nAnything touching **design, schema, public API, dependencies, or security escalates.**\nThose are not corrections to how a step is addressed; they are changes to what it\nasks for, and that decision is not yours to make silently.\n\nRecord every adaptation with the original premise, the correction made, and a one-line\nrationale. **Never silently skip a step.** A step you cannot execute is `escalated`\nwith a reason — a step that vanishes without a record is the exact defect this\nprotocol exists to remove.\n\nIf a requirement is ambiguous because the plan lacks ticket detail, call the\n`get_ticket` tool with `ticket_number` set to `{ticket_key}`, use only the fields\nrelevant to the unresolved requirement, and continue. Do not call `get_ticket`\nunconditionally — `get_plan` in Step 1 remains the sole unconditional context\nretrieval.\n\n## Step 4 — Final Audit\n\n1. Re-enumerate every step you own from the routed context.\n2. Confirm each one has a terminal disposition: `executed`, `adapted`, `escalated`, or\n `unrun-advisory` (the last only when the plan itself declares that range advisory).\n3. Announce: **\"Audit complete — M of M owned steps settled.\"**\n\n## Return\n\nReport production coverage: which owned steps were executed, which were mechanically\nadapted and how, and which were escalated and why.\n\nThen record the machine-readable phase result. **How you record it depends on the\nmode**, and the difference is not cosmetic — it is the difference between a durable\nrecord and a message to nobody.\n\n### orchestrated\n\nEnd your result with the envelope in a fenced block tagged `bapi-phase-result`.\nOrchestration parses this block, validates it against the steps you own, and persists\nit as durable state that survives an approval pause and a resumed session. A step you\nowned but did not report will be rejected.\n\n```bapi-phase-result\n{\"version\":1,\"phase\":\"produce\",\"records\":[{\"stepId\":1,\"provenanceClass\":\"implementation\",\"disposition\":\"executed\",\"evidence\":\"created src/foo.py and its migration\"}]}\n```\n\n### inline\n\nCall the `record_phase_result` tool with `ticket_key` `{ticket_key}` and\n`phase_result` set to that same envelope object. The tool validates it against the\nsteps you own and persists it to the durable ledger; a step you owned but did not\nreport is rejected there, and an owned step left unsettled fails the call rather than\ndisappearing. **Do not also emit a fenced `bapi-phase-result` block** — inline there is\nno orchestration to parse one, and a text envelope addressed to nobody is exactly what\nused to end the turn here.\n\nThe tool call is this phase's final action. **It is not the end of your turn.** When it\nreturns successfully the produce phase is complete and the *next recipe step* —\n`checkpoint-work.md`, which pushes everything you just produced — begins immediately.\nContinue to it in the same turn. Stopping here strands the work you just authored in an\nuncommitted worktree, which is the single most damaging way this pipeline has failed.\n\nIf the call fails, fix what it reports and call it again. Do not proceed past a failed\nrecording: an unrecorded phase result means the next phase reads an empty ledger and\nredoes work you already did.\n",
|
|
889
889
|
"execute-research.md": "Execute the research plan and produce a consolidated research pack.\n\n## Inputs\n\n- Research plan: `{docs_dir}/idea-to-ticket/{slug}-{run_id}/research-plan.json`.\n- Run manifest: `{docs_dir}/idea-to-ticket/{slug}-{run_id}/run-manifest.json`.\n\n## Instructions\n\n1. Read `{docs_dir}/idea-to-ticket/{slug}-{run_id}/research-plan.json`. Execute only the tools listed in `selected_tools`. Do not invoke any tool that is not in that list.\n\n2. For each selected tool:\n - **codebase_search**: search the local working tree using the listed `codebase_search_topics`. Capture file paths, function names, and short excerpts as evidence.\n - **web_search**: run narrow, targeted searches for each item in `web_search_topics`. Capture the source URL and a short summary for each result.\n - **deep_research**: run the deep research query exactly once with the planned `deep_research_query`. Capture the consolidated answer plus the cited URLs.\n\n3. Tool failures must be recorded, not silently dropped:\n - If a tool returns an error, missing-credential message, or empty result, record the failure under `per_tool_failures` in the research pack and continue with the remaining tools.\n - A partial research pack is preferable to no research pack. Do not halt the pipeline because one tool failed.\n\n4. Write two artifacts to the run directory:\n - `{docs_dir}/idea-to-ticket/{slug}-{run_id}/research-pack.md` — a human-readable consolidated brief. It must include these sections:\n - **Evidence table** — a structured list of evidence rows: claim, source (file path / URL), and tool that produced it. Render as a bulleted list, not a markdown table (BAPI-320 hygiene).\n - **Codebase references** — file paths and function names worth citing in the ticket.\n - **External references** — only present when web/deep search ran; URL + short summary per item.\n - **Unresolved unknowns** — questions the research could not answer.\n - **Per-tool failures** — any tool that failed, with the failure reason.\n - `{docs_dir}/idea-to-ticket/{slug}-{run_id}/research-pack.json` — machine-readable counterpart with the same evidence rows, references, unresolved unknowns, and per-tool failures arrays.\n\n5. Mark research failures as warnings in `research-pack.json` so downstream steps can branch on them: include `partial: true` when any selected tool failed.\n\n## Return\n\nConfirm `research-pack.md` and `research-pack.json` were written, and list any tools that failed.\n",
|
|
890
890
|
"explore-epic-codebase.md": "Perform a holistic, epic-level codebase exploration.\n\n## Epic Description\n\n{epic_description}\n\n## Instructions\n\n1. Read the research findings from `{docs_dir}/epic-plans/{epic_slug}/research-findings.md` to establish context. If the file does not exist or is empty, proceed without it.\n\n2. Explore the codebase with a focus on breadth rather than depth. The goal is to build a \"lay of the land\" understanding for the entire epic, not to deeply analyze any single sub-task. Search by filename pattern, search file contents by text pattern, and read relevant files to find:\n - Files, modules, and directories relevant to the epic\n - Architectural patterns used in similar features\n - Integration points and dependencies between modules\n - Existing conventions for the type of work this epic involves\n - Database models, API routes, agent flows, and utilities that may be affected\n\n3. Build a mental model of:\n - What exists today that relates to the epic\n - What patterns and conventions are used in similar features\n - What dependencies, data flows, and integration points are involved\n - What areas of the codebase will likely need changes\n\n4. Write the exploration findings to `{docs_dir}/epic-plans/{epic_slug}/codebase-exploration.md` with this structure:\n\n```markdown\n# Codebase Exploration\n\n## Architecture Overview\n{High-level description of how the relevant parts of the codebase are structured.}\n\n## Relevant Code Areas\n{List of key files, modules, and directories with brief descriptions of their relevance to the epic.}\n\n## Existing Patterns\n{Patterns and conventions discovered that should be followed when implementing the epic.}\n\n## Integration Points\n{Dependencies, data flows, and integration points that the epic will need to account for.}\n\n## Potential Challenges\n{Any architectural constraints, technical debt, or complexity that could affect implementation.}\n```\n\n## Return\n\nConfirm the codebase exploration was written to `{docs_dir}/epic-plans/{epic_slug}/codebase-exploration.md` and return a concise summary of the discovered codebase areas, naming the key files and patterns relevant to the epic.\n",
|
|
891
891
|
"explore-epic-subtasks.md": "Perform focused code explorations for each approved sub-task.\n\n## Instructions\n\n1. Read the approved decomposition from `{docs_dir}/epic-plans/{epic_slug}/epic-plan.md`.\n\n2. Create the explorations directory:\n ```\n mkdir -p {docs_dir}/epic-plans/{epic_slug}/explorations/\n ```\n\n3. For each sub-task in the decomposition, perform a focused exploration:\n - Search for specific files and patterns relevant to the sub-task\n - Identify implementation options and tradeoffs\n - Reference the holistic codebase exploration (`{docs_dir}/epic-plans/{epic_slug}/codebase-exploration.md`) and research findings (`{docs_dir}/epic-plans/{epic_slug}/research-findings.md`) for context\n - Default to lightweight exploration — only go deeper when the holistic exploration left significant gaps for a specific sub-task\n\n4. Write an exploration document for each sub-task to `{docs_dir}/epic-plans/{epic_slug}/explorations/NN-{subtask-slug}.md` (using zero-padded numbering, e.g., `01-add-pipeline-json.md`, `02-create-instruction-files.md`).\n\n5. Each exploration document MUST include these exactly named sections:\n\n```markdown\n# {Sub-task title}\n\n## Context\n{Brief description of the sub-task scope and its role within the epic.}\n\n## Relevant Code\n{Specific files, functions, and patterns relevant to this sub-task. Reference with file_path:line_number format.}\n\n## Implementation Options\n{Viable approaches for implementing the sub-task. For each option: description, pros, cons.}\n\n## Recommendation\n{Which option to pursue and why. Include any caveats or risks.}\n```\n\n6. **Word count guidance**: Target 300-500 words per document. Keep the exploration lightweight. Only exceed this limit if the holistic codebase exploration left significant gaps for a specific sub-task.\n\n## Return\n\nConfirm one exploration document was written per sub-task under `{docs_dir}/epic-plans/{epic_slug}/explorations/` and return a concise summary of the discovered code areas and recommended approaches across the sub-tasks.\n",
|