@algosuite/vo-mcp 0.2.0-beta.39 → 0.2.0-beta.40

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.
@@ -291,6 +291,7 @@ var VO_HEADLESS_PNPM_TOOL = "Bash(pnpm *)";
291
291
  var VO_HEADLESS_PNPM_FROM_DIR_TOOL = "Bash(pnpm --dir *)";
292
292
  var VO_RESEARCH_TOOLS = ["WebFetch", "WebSearch"];
293
293
  var VO_WORKFLOW_TOOLS = ["Workflow"];
294
+ var VO_CONSENSUS_TOOLS = ["mcp__vo-mcp__vo_consensus_judgment", "mcp__vo-mcp__vo_verify_answer"];
294
295
  var SAFE_PERMISSION_MODES = /* @__PURE__ */ new Set(["acceptEdits", "plan", "default", "dontAsk", "delegate"]);
295
296
  function normalizeClaudePermissionMode(value) {
296
297
  const normalized = String(value ?? "").trim() || DEFAULT_PERMISSION_MODE;
@@ -305,8 +306,10 @@ function buildClaudeArgs({ permissionMode = DEFAULT_PERMISSION_MODE, maxTurns, m
305
306
  const research = noWeb ? [] : VO_RESEARCH_TOOLS;
306
307
  const noWorkflow = noWeb || String(env?.VO_CODE_RUNNER_NO_WORKFLOW ?? "").trim() === "1";
307
308
  const workflow = researchHarness === true && !noWorkflow ? VO_WORKFLOW_TOOLS : [];
309
+ const noConsensus = String(env?.VO_CODE_RUNNER_NO_CONSENSUS ?? "").trim() === "1";
310
+ const consensus = noConsensus ? [] : VO_CONSENSUS_TOOLS;
308
311
  const baseTools = effectivePermissionMode === DEFAULT_PERMISSION_MODE ? [VO_SESSION_STATE_TOOL, VO_HEADLESS_PNPM_TOOL, VO_HEADLESS_PNPM_FROM_DIR_TOOL] : [VO_SESSION_STATE_TOOL];
309
- const allowedTools = [...baseTools, ...research, ...workflow].join(",");
312
+ const allowedTools = [...baseTools, ...consensus, ...research, ...workflow].join(",");
310
313
  const args = [
311
314
  "-p",
312
315
  "--output-format",
@@ -3494,8 +3494,10 @@ function buildClaudeArgs({ permissionMode = DEFAULT_PERMISSION_MODE, maxTurns, m
3494
3494
  const research = noWeb ? [] : VO_RESEARCH_TOOLS;
3495
3495
  const noWorkflow = noWeb || String(env2?.VO_CODE_RUNNER_NO_WORKFLOW ?? "").trim() === "1";
3496
3496
  const workflow = researchHarness === true && !noWorkflow ? VO_WORKFLOW_TOOLS : [];
3497
+ const noConsensus = String(env2?.VO_CODE_RUNNER_NO_CONSENSUS ?? "").trim() === "1";
3498
+ const consensus = noConsensus ? [] : VO_CONSENSUS_TOOLS;
3497
3499
  const baseTools = effectivePermissionMode === DEFAULT_PERMISSION_MODE ? [VO_SESSION_STATE_TOOL, VO_HEADLESS_PNPM_TOOL, VO_HEADLESS_PNPM_FROM_DIR_TOOL] : [VO_SESSION_STATE_TOOL];
3498
- const allowedTools = [...baseTools, ...research, ...workflow].join(",");
3500
+ const allowedTools = [...baseTools, ...consensus, ...research, ...workflow].join(",");
3499
3501
  const args = [
3500
3502
  "-p",
3501
3503
  "--output-format",
@@ -3521,7 +3523,7 @@ function buildClaudeArgs({ permissionMode = DEFAULT_PERMISSION_MODE, maxTurns, m
3521
3523
  args.push(...context7McpArgs(env2));
3522
3524
  return args;
3523
3525
  }
3524
- var DEFAULT_PERMISSION_MODE, VO_SESSION_STATE_TOOL, VO_HEADLESS_PNPM_TOOL, VO_HEADLESS_PNPM_FROM_DIR_TOOL, VO_RESEARCH_TOOLS, VO_WORKFLOW_TOOLS, SAFE_PERMISSION_MODES;
3526
+ var DEFAULT_PERMISSION_MODE, VO_SESSION_STATE_TOOL, VO_HEADLESS_PNPM_TOOL, VO_HEADLESS_PNPM_FROM_DIR_TOOL, VO_RESEARCH_TOOLS, VO_WORKFLOW_TOOLS, VO_CONSENSUS_TOOLS, SAFE_PERMISSION_MODES;
3525
3527
  var init_claude_args = __esm({
3526
3528
  "../../scripts/virtual-office/code-runner/claude-args.mjs"() {
3527
3529
  "use strict";
@@ -3532,6 +3534,7 @@ var init_claude_args = __esm({
3532
3534
  VO_HEADLESS_PNPM_FROM_DIR_TOOL = "Bash(pnpm --dir *)";
3533
3535
  VO_RESEARCH_TOOLS = ["WebFetch", "WebSearch"];
3534
3536
  VO_WORKFLOW_TOOLS = ["Workflow"];
3537
+ VO_CONSENSUS_TOOLS = ["mcp__vo-mcp__vo_consensus_judgment", "mcp__vo-mcp__vo_verify_answer"];
3535
3538
  SAFE_PERMISSION_MODES = /* @__PURE__ */ new Set(["acceptEdits", "plan", "default", "dontAsk", "delegate"]);
3536
3539
  }
3537
3540
  });
@@ -6009,7 +6012,39 @@ function resolveOverlapScript({
6009
6012
  }
6010
6013
  return { scriptPath: joinFn(worktreeDir), trusted: false };
6011
6014
  }
6012
- var TRUSTED_OVERLAP_CANDIDATES, CREDENTIAL_ENV_KEYS;
6015
+ function parseDirectOverlapPrs(output) {
6016
+ const text = String(output || "");
6017
+ const start = text.search(/^##\s+.*Direct File Overlaps/mu);
6018
+ if (start < 0) return [];
6019
+ const rest = text.slice(start);
6020
+ const next = rest.slice(2).search(/^##\s+/mu);
6021
+ const section = next < 0 ? rest : rest.slice(0, next + 2);
6022
+ return [...new Set([...section.matchAll(/^###\s+PR\s+#(\d+)/gmu)].map((m) => Number(m[1])))];
6023
+ }
6024
+ function overlapPublishPolicy(overlap) {
6025
+ const output = String(overlap?.output || "");
6026
+ const blockedBy = parseDirectOverlapPrs(output);
6027
+ const gateReason = blockedBy.length > 0 ? `direct file overlap with ${blockedBy.map((n) => `#${n}`).join(", ")}` : `gate refused without a direct-overlap section: ${(output.split("\n").find((l) => /aborting|unavailable|conflict|error/iu.test(l)) || output.split("\n")[0] || "no output").trim().slice(0, 160)}`;
6028
+ const refs = blockedBy.length > 0 ? blockedBy.map((n) => `#${n}`).join(", ") : "unresolved";
6029
+ const bodyPrefix = [
6030
+ `> \u26A0\uFE0F **${OVERLAP_BLOCKED_MARKER}: ${refs}** \u2014 ${gateReason}. The runner published this as a DRAFT to preserve the finished work instead of failing the task. Do NOT mark ready or merge before the overlap is resolved (the draft flag is the only merge guard); then refresh this branch on current main and mark it ready. Auto-merge was NOT armed.`,
6031
+ "",
6032
+ "<details><summary>local overlap gate output</summary>",
6033
+ "",
6034
+ "```",
6035
+ output.slice(0, 6e3),
6036
+ "```",
6037
+ "</details>",
6038
+ ""
6039
+ ].join("\n");
6040
+ return { draft: true, overlapDraft: true, blockedBy, gateReason, bodyPrefix };
6041
+ }
6042
+ function applyOverlapPublishPolicy({ overlap, draft, body }) {
6043
+ if (overlap?.ok) return { draft, body, overlapDraft: false, overlapBlockedBy: [], gateReason: "" };
6044
+ const policy = overlapPublishPolicy(overlap);
6045
+ return { draft: true, body: `${policy.bodyPrefix}${body ?? ""}`, overlapDraft: true, overlapBlockedBy: policy.blockedBy, gateReason: policy.gateReason };
6046
+ }
6047
+ var TRUSTED_OVERLAP_CANDIDATES, CREDENTIAL_ENV_KEYS, OVERLAP_BLOCKED_MARKER;
6013
6048
  var init_pr_overlap_gate = __esm({
6014
6049
  "../../scripts/virtual-office/code-runner/pr-overlap-gate.mjs"() {
6015
6050
  "use strict";
@@ -6027,6 +6062,7 @@ var init_pr_overlap_gate = __esm({
6027
6062
  "OPENAI_API_KEY",
6028
6063
  "CURSOR_API_KEY"
6029
6064
  ]);
6065
+ OVERLAP_BLOCKED_MARKER = "VO-PUBLISH-OVERLAP-BLOCKED";
6030
6066
  }
6031
6067
  });
6032
6068
 
@@ -6042,6 +6078,9 @@ function editExistingPrMetadata(worktreeDir, prNumber, { title, body, env: env2,
6042
6078
  function markExistingPrReady(worktreeDir, prNumber, { env: env2, runFn } = {}) {
6043
6079
  return runFn("gh", ["pr", "ready", String(prNumber)], worktreeDir, { env: env2 });
6044
6080
  }
6081
+ function demoteExistingPrToDraft(worktreeDir, prNumber, { env: env2, runFn } = {}) {
6082
+ return runFn("gh", ["pr", "ready", "--undo", String(prNumber)], worktreeDir, { env: env2 });
6083
+ }
6045
6084
  function publicationTitlePrompt(task = {}) {
6046
6085
  const prompt = String(task.prompt || "");
6047
6086
  if (!task.resumed_from) return prompt;
@@ -6050,11 +6089,13 @@ function publicationTitlePrompt(task = {}) {
6050
6089
  return original.split(/\n\n(?:Operator follow-up instructions|Treat these as task-scoped)/u)[0].trim() || prompt;
6051
6090
  }
6052
6091
  async function syncExistingPrAsync(worktreeDir, existing, options = {}) {
6053
- const { title, body, draft = false, env: env2, runFn } = options;
6092
+ const { title, body, draft = false, demoteToDraft = false, env: env2, runFn } = options;
6054
6093
  await editExistingPrMetadata(worktreeDir, existing.number, { title, body, env: env2, runFn });
6055
6094
  const markedReady = !draft && existing.isDraft;
6056
6095
  if (markedReady) await markExistingPrReady(worktreeDir, existing.number, { env: env2, runFn });
6057
- return { markedReady };
6096
+ const demoted = draft && demoteToDraft && existing.isDraft === false;
6097
+ if (demoted) await demoteExistingPrToDraft(worktreeDir, existing.number, { env: env2, runFn });
6098
+ return { markedReady, demoted };
6058
6099
  }
6059
6100
  var init_existing_pr_publication = __esm({
6060
6101
  "../../scripts/virtual-office/code-runner/existing-pr-publication.mjs"() {
@@ -6939,8 +6980,9 @@ async function openCodeTaskPrAsync(worktreeDir, files, {
6939
6980
  env: githubToken ? installationTokenEnv(githubToken) : process.env,
6940
6981
  excludePrNumber: supersedesPrNumber
6941
6982
  });
6942
- if (!overlap.ok) throw new Error(`local PR overlap gate blocked publish:
6943
- ${overlap.output}`);
6983
+ const policy = applyOverlapPublishPolicy({ overlap, draft, body });
6984
+ ({ draft, body } = policy);
6985
+ const { overlapDraft, overlapBlockedBy } = policy;
6944
6986
  const tokenUsed = await retryTransientAsync(
6945
6987
  () => pushBranchAsync(worktreeDir, branch, githubToken, {
6946
6988
  runCommand,
@@ -6959,6 +7001,7 @@ ${overlap.output}`);
6959
7001
  title: compactTitle(title),
6960
7002
  body,
6961
7003
  draft,
7004
+ demoteToDraft: overlapDraft,
6962
7005
  env: authToken ? installationTokenEnv(authToken) : void 0,
6963
7006
  runFn: runCommand
6964
7007
  }), { onRetry: gitRetryLog("gh pr sync") });
@@ -6986,6 +7029,8 @@ ${overlap.output}`);
6986
7029
  truncated,
6987
7030
  resumed: true,
6988
7031
  markedReady,
7032
+ overlapDraft,
7033
+ overlapBlockedBy,
6989
7034
  ...autoMerge2,
6990
7035
  ...superseded2
6991
7036
  };
@@ -7020,7 +7065,7 @@ ${overlap.output}`);
7020
7065
  runCommand,
7021
7066
  onCleanupWarning
7022
7067
  });
7023
- return { prUrl, prNumber, branch: prBranch, truncated, ...autoMerge, ...superseded };
7068
+ return { prUrl, prNumber, branch: prBranch, truncated, overlapDraft, overlapBlockedBy, ...autoMerge, ...superseded };
7024
7069
  }
7025
7070
  var sleep;
7026
7071
  var init_publish_async = __esm({
@@ -7124,6 +7169,7 @@ function buildDispatchOnboarding({ repo = "Algosuite-ai/Nexus" } = {}) {
7124
7169
  `You are an AlgoHQ-dispatched coding agent working in a fresh worktree of ${repo}.`,
7125
7170
  "You were dispatched by the operator (greylor, a non-coder founder) to do the TASK at the end of this message.",
7126
7171
  "Before writing ANY code, you MUST read the onboarding docs below \u2014 they are mandatory, not optional. Your worktree auto-loads CLAUDE.md, but the rest are NOT auto-loaded; open and read them.",
7172
+ "Token discipline: the reads below are bounded on purpose (a Claude Code session that read every listed doc end-to-end spent ~$2.40 / ~260K cache-write tokens before its first edit on 2026-08-16). Follow the per-item scoping notes, and beyond this list read only what your task actually touches.",
7127
7173
  "",
7128
7174
  "MANDATORY READS (read these FIRST, in order):",
7129
7175
  reads,
@@ -7180,7 +7226,7 @@ var init_dispatch_onboarding = __esm({
7180
7226
  "use strict";
7181
7227
  init_skill_catalog();
7182
7228
  MANDATORY_READS = [
7183
- "CLAUDE.md (repo root \u2014 Claude-specific rules; auto-loaded, but READ it)",
7229
+ "CLAUDE.md (repo root \u2014 Claude-specific rules; Claude Code sessions have it AUTO-LOADED \u2014 do NOT Read it again there, that re-spends ~18K tokens; Codex/Cursor/other agents must READ it)",
7184
7230
  'AGENTS.md (repo root \u2014 cross-vendor rules + "Onboarding for a lane"; NOT auto-loaded)',
7185
7231
  "README.md (repo root \u2014 product context)",
7186
7232
  "docs/current/virtual-office-agent-charter.md",
@@ -7189,9 +7235,9 @@ var init_dispatch_onboarding = __esm({
7189
7235
  "docs/current/evidence-grounded-consensus-testing.md",
7190
7236
  "docs/vo/ADR-001-verification-oracle-not-orchestrator-2026-05-29.md (AlgoHQ verifies + signs; human approves merges; NO autonomous bot-merge / headless triggers)",
7191
7237
  "docs/vo/vo-adr-002-two-plane-moat.md (fat secret server / thin dumb client)",
7192
- "docs/vo/vo-roadmap-2026-05-26.md (the live roadmap \u2014 read its Change log tail for current state)",
7238
+ 'docs/vo/vo-roadmap-2026-05-26.md (the live roadmap; ~50K tokens \u2014 read its "## 10. Change log" section (the last ~90 lines, via Read offset) for current state, then Grep/Read ONLY the section holding any status row your task must flip; never read it end-to-end)',
7193
7239
  "the nearest scoped CLAUDE.md for any directory you edit",
7194
- "for AlgoTax work: docs/current/algotax-progressive-return-roadmap.md + docs/current/algotax-coverage-roadmap.md",
7240
+ "for AlgoTax work: docs/current/algotax-progressive-return-roadmap.md + docs/current/algotax-coverage-roadmap.md (together ~100K tokens \u2014 read each file's section index and ONLY the sections your task touches; a full read leaves no budget for the work)",
7195
7241
  "docs/current/pr-live-stewardship-doctrine.md (own EVERY PR to LIVE-VERIFIED; never let the operator discover a red PR or a backed-up deploy)"
7196
7242
  ];
7197
7243
  NON_NEGOTIABLES = [
@@ -7206,7 +7252,7 @@ var init_dispatch_onboarding = __esm({
7206
7252
  "A handoff or roadmap line is a CLAIM, not evidence \u2014 verify shipped state against `git show origin/main:<path>`, never the stale local main tree.",
7207
7253
  `MANDATORY FOR EVERY ALGOHQ PR (cloud-run/vo-*, packages/vo-mcp, packages/consensus-engine, packages/vo-ratchets, packages/vo-arch-defaults, scripts/virtual-office, vo-claude-plugin): record a dated Change-log entry IN THE SAME PR via EITHER appending to the "\xA7 10 Change log" of docs/vo/vo-roadmap-2026-05-26.md OR (PREFERRED) creating docs/vo/roadmap-log/<YYYY-MM-DD>-<short-slug>.md (fragments avoid conflicts when PRs ship concurrently) and flip any status the work shipped. CI enforces this (check-vo-roadmap-discipline.mjs); bypass ONLY via "VO-ROADMAP-ALLOW: <reason>" in the PR body. The roadmap is the single source of truth \u2014 if you didn't update it, you didn't ship. Finish line = MERGED + DEPLOYED + LIVE-VERIFIED.`,
7208
7254
  "Every UI change ships against docs/current/ui-trust-standard.md and adds AlgoHQ QA tester coverage; verify in a real browser, not selector-presence.",
7209
- "UNATTENDED VERIFICATION: no human can approve shell prompts. Run `pnpm ...` directly from the worktree root. For a standalone nested project with its own pnpm-lock.yaml, use `pnpm --dir <project> install --frozen-lockfile --prefer-offline --ignore-scripts --config.confirmModulesPurge=false`, then `pnpm --dir <project> ...` for its focused tests/type-check. These two pnpm forms are pre-authorized; do not skip local verification or wait for approval.",
7255
+ 'UNATTENDED VERIFICATION: no human can approve shell prompts. Run `pnpm ...` directly from the worktree root. For a standalone nested project with its own pnpm-lock.yaml, use `pnpm --dir <project> install --frozen-lockfile --prefer-offline --ignore-scripts --config.confirmModulesPurge=false`, then `pnpm --dir <project> ...` for its focused tests/type-check. These two pnpm forms are pre-authorized; do not skip local verification or wait for approval. Bare `node <script>` is NOT pre-authorized and will be denied \u2014 run repo gates via their aliases (`pnpm run check:<gate>`, see package.json "scripts") or as `pnpm exec node scripts/<path>.mjs`; a denial is not a reason to skip the gate or hand-write its generated output.',
7210
7256
  'PR \u2192 LIVE is YOUR job end-to-end \u2014 the operator must NEVER be the one to discover a red PR or a backed-up deploy. Own every PR from branch \u2192 CI \u2192 merge \u2192 functions deploy \u2192 LIVE-VERIFIED. "Done" = the functions you changed are actually SERVING in prod in every region; prove it with `node scripts/ci/prove-pr-live.mjs --pr <N>` \u2014 a merge / green deploy checkmark / homepage 200 is NOT proof. If a function staled, re-deploy ONLY the affected functions (targeted), never a full deploy. If you hit a usage/rate limit, STOP cleanly with the PR obligation OPEN \u2014 the watchdog auto-resumes when it resets; do not abandon it. See docs/current/pr-live-stewardship-doctrine.md.',
7211
7257
  `CONTEXT DEPTH IS NOT A REASON TO STOP. "I'm deep in context / fresh context would be better / I'll checkpoint" is the SAME premature-stop failure as doing 20 minutes of work instead of 6 hours \u2014 there is no quality cliff before compaction and the harness carries work forward. Keep BUILDING until the task is genuinely DONE; delicate or fleet-governing work means be CAREFUL, not stop. The ONLY valid pauses are real blockers: an operator decision is required, a dependency is not merged, or a hard external wait.`
7212
7258
  ];
@@ -7229,24 +7275,30 @@ function matchGovernedStakes(task) {
7229
7275
  function composeMethodologyBlock(task) {
7230
7276
  const shape = classifyTaskShape(task);
7231
7277
  const stakes = matchGovernedStakes(task);
7278
+ const roadmapOverlay = shape !== "roadmap-advance" && isUiRoadmapDispatch(task);
7232
7279
  const lines = [
7233
- `## Methodology (auto-composed: ${shape}${stakes ? `, governed-stakes: ${stakes}` : ""})`,
7280
+ `## Methodology (auto-composed: ${shape}${roadmapOverlay ? " + roadmap-driven" : ""}${stakes ? `, governed-stakes: ${stakes}` : ""})`,
7234
7281
  ...UNIVERSAL_DIRECTIVES.map((d) => `- ${d}`),
7235
7282
  ...(SHAPE_DIRECTIVES[shape] || []).map((d) => `- ${d}`),
7283
+ ...roadmapOverlay ? SHAPE_DIRECTIVES["roadmap-advance"].map((d) => `- ${d}`) : [],
7236
7284
  ...stakes ? CONSENSUS_DIRECTIVES.map((d) => `- ${d}`) : []
7237
7285
  ];
7238
7286
  return { shape, stakes, block: lines.join("\n") };
7239
7287
  }
7288
+ function isUiRoadmapDispatch(task) {
7289
+ return UI_ROADMAP_DISPATCH_MARKER.test(String(task?.prompt || ""));
7290
+ }
7240
7291
  function withMethodology(prompt, task) {
7241
7292
  const { shape, stakes, block } = composeMethodologyBlock(task);
7242
7293
  return { shape, stakes, prompt: `${prompt ?? ""}
7243
7294
 
7244
7295
  ${block}` };
7245
7296
  }
7246
- var SHAPE_RULES, GOVERNED_STAKES_PATTERN, RESEARCH_WORKFLOW_DIRECTIVE, CONSENSUS_DIRECTIVES, UNIVERSAL_DIRECTIVES, SHAPE_DIRECTIVES;
7297
+ var UI_ROADMAP_DISPATCH_MARKER, SHAPE_RULES, GOVERNED_STAKES_PATTERN, RESEARCH_WORKFLOW_DIRECTIVE, CONSENSUS_DIRECTIVES, UNIVERSAL_DIRECTIVES, SHAPE_DIRECTIVES;
7247
7298
  var init_methodology_composer = __esm({
7248
7299
  "../../scripts/virtual-office/code-runner/methodology-composer.mjs"() {
7249
7300
  "use strict";
7301
+ UI_ROADMAP_DISPATCH_MARKER = /^\s*work on\s+[^\n]{1,200}?\s+roadmap task:/iu;
7250
7302
  SHAPE_RULES = [
7251
7303
  {
7252
7304
  shape: "recovery",
@@ -7270,7 +7322,10 @@ var init_methodology_composer = __esm({
7270
7322
  },
7271
7323
  {
7272
7324
  shape: "design",
7273
- matches: (_task, prompt) => /\b(design doc|architecture|architect|adr\b|lane brief|write a plan|propose (a|the) (design|plan|approach))\b/iu.test(prompt)
7325
+ // Live-test finding 2026-08-16 (task a47be49f): "Implement PHASE 0 of <design doc>"
7326
+ // classified as design and skipped the delivery directives. An implement/build/
7327
+ // ship verb in the opening clause means the design already exists.
7328
+ matches: (_task, prompt) => !/^\s*(implement|build|ship|execute|apply|land)\b/iu.test(prompt) && /\b(design doc|architecture|architect|adr\b|lane brief|write a plan|propose (a|the) (design|plan|approach))\b/iu.test(prompt)
7274
7329
  },
7275
7330
  {
7276
7331
  shape: "chore",
@@ -7284,6 +7339,7 @@ var init_methodology_composer = __esm({
7284
7339
  "If the consensus tools are not available in this session, say exactly that in the PR body instead of silently skipping \u2014 an unverified governed claim must be visible, never implied."
7285
7340
  ];
7286
7341
  UNIVERSAL_DIRECTIVES = [
7342
+ 'Before finishing, REHEARSE the repo gates your diff will hit and fix failures locally. HOW: bare `node <script>` is DENIED in this session (only `pnpm \u2026` is pre-authorized) \u2014 run whole-tree gates through their package.json aliases (`pnpm run check:<gate>`, e.g. `pnpm run check:algobooks-model-tiering`, `pnpm run check:hollow-tests`) or as `pnpm exec node scripts/...`; never conclude "cannot run" and hand-write a generated artifact. Diff-scoped gates (base...head, committed refs) cannot see your UNCOMMITTED edits, so satisfy their rule by construction: any roadmap-doc change under docs/current or docs/vo -> run `pnpm run roadmap:progress && pnpm exec node scripts/sync-roadmap-progress.mjs` and keep the regenerated artifacts in your diff (board drift gate); any top-level `.ts` directly under functions-core-tax/src/tax/ (not tests, not tax-year-thresholds.ts, not nested dirs; even a comment-only edit counts) -> in docs/current/algotax-coverage-roadmap.md the file MUST have a row in the callable Status table (most `algobooks-*.ts` files have NONE \u2014 add an honest row first, or the gate fails with "has no row"), then either change that row\'s Status or append a dated Update Log line that NAMES the changed file\'s basename (a dated line that does not name the file still fails); ONLY for a comment-only / no-behavior diff you may instead end your final summary with a line `VO-ALLOW-NO-AUDIT-UPDATE: <reason>` (it lands in the PR body the gate reads) \u2014 never when logic changed \u2014 tax-audit ratchet; a new entry in REQUIRED_GATE_INVOCATIONS -> classify it in scripts/ci/check-main-health-core.mjs (anti-drift test); new test files -> no Date.now()/new Date() fixtures and 4+ real assertions (clock-fixture + hollow-test gates); a .github/workflows edit may be rejected at push (the runner token lacks the workflows scope) -> say so in your final summary instead of retrying. Live tests 2026-08-16: four dispatched PRs bounced on exactly these.',
7287
7343
  "Verification is a stage, not a vibe: before publishing, run the tests/build your change touches and cite their actual output. A claim without execution evidence is not done.",
7288
7344
  "Work to completion or end with an explicit failure reason. Do not stop because time has passed; stop when the evidence says the work is done \u2014 or state exactly what is blocking.",
7289
7345
  "Default to doing the work yourself in this session. Spawn parallel subagents ONLY for pieces that are genuinely independent and independently verifiable \u2014 and verify their results yourself before integrating; never let unreviewed parallel output merge into shared files.",
@@ -7299,7 +7355,7 @@ var init_methodology_composer = __esm({
7299
7355
  RESEARCH_WORKFLOW_DIRECTIVE
7300
7356
  ],
7301
7357
  "roadmap-advance": [
7302
- "Update the roadmap doc status, regenerate the roadmap board if the doc changed, and add the roadmap-log fragment IN THIS SAME PR \u2014 a roadmap task that does not move the roadmap did not happen.",
7358
+ "Update the roadmap doc status, regenerate the roadmap board if the doc changed (`pnpm run roadmap:progress && pnpm exec node scripts/sync-roadmap-progress.mjs`), and add the dated log entry \u2014 the roadmap doc's own Update Log / Change log section for a product roadmap, or a docs/vo/roadmap-log fragment for the HQ roadmap \u2014 IN THIS SAME PR; a roadmap task that does not move the roadmap did not happen.",
7303
7359
  "A NEW roadmap doc must be OWNED: cite its path from an owning docs/lanes/<slug>.md brief (create the brief in this same PR if the lane has none) \u2014 the roadmap-shape gate blocks any uncited roadmap doc, and four dispatched roadmap PRs hit exactly that wall on 2026-08-14."
7304
7360
  ],
7305
7361
  design: [
@@ -12624,6 +12680,10 @@ async function finalizePublishedPr({
12624
12680
  await closeCancelledReplacementPr({ pr, worktreeDir, githubToken, log: log2, runCommand });
12625
12681
  return true;
12626
12682
  }
12683
+ const overlapBlocked = pr.overlapDraft === true;
12684
+ const blockedRefs = Array.isArray(pr.overlapBlockedBy) && pr.overlapBlockedBy.length > 0 ? pr.overlapBlockedBy.map((n) => `#${n}`).join(", ") : "unresolved (see PR body for the gate report)";
12685
+ const overlapNote = overlapBlocked ? ` as DRAFT \u2014 overlap-blocked by ${blockedRefs} (finished work preserved; mark ready after the overlap is resolved)` : "";
12686
+ const fixDispatchGuard = overlapBlocked ? { allowFixDispatch: false } : {};
12627
12687
  let resumeQueued = false;
12628
12688
  if (cfg.watchEnabled) {
12629
12689
  try {
@@ -12642,7 +12702,11 @@ async function finalizePublishedPr({
12642
12702
  max_attempts: cfg.watchRepairChainMax ?? 3,
12643
12703
  per_attempt_budget_usd: cfg.watchRepairBudgetUsd ?? 1
12644
12704
  },
12645
- ...!task.repair_chain && String(task.prompt || "").includes("[VO-CI-FIX]") ? { allowFixDispatch: false } : {}
12705
+ // A CI-fix task, or a DRAFT published only because the local overlap gate
12706
+ // blocked it, must not spend repair attempts: the overlap resolves when the
12707
+ // blocking PR merges, not by editing this branch.
12708
+ ...!task.repair_chain && String(task.prompt || "").includes("[VO-CI-FIX]") ? { allowFixDispatch: false } : {},
12709
+ ...fixDispatchGuard
12646
12710
  });
12647
12711
  } catch (error) {
12648
12712
  await closeCancelledReplacementPr({
@@ -12674,7 +12738,8 @@ async function finalizePublishedPr({
12674
12738
  attempt: 0,
12675
12739
  max_attempts: cfg.watchRepairChainMax ?? 3,
12676
12740
  per_attempt_budget_usd: cfg.watchRepairBudgetUsd ?? 1
12677
- }
12741
+ },
12742
+ ...fixDispatchGuard
12678
12743
  });
12679
12744
  }
12680
12745
  log2(`task ${id}: rate-limit continuation ${resumeQueued ? "queued for due-time scheduler" : "queue write failed; watcher fallback armed"}`);
@@ -12687,11 +12752,15 @@ async function finalizePublishedPr({
12687
12752
  log: log2,
12688
12753
  patch: {
12689
12754
  status: "pr_opened",
12690
- message: `opened ${pr.prUrl}`,
12755
+ message: `opened ${pr.prUrl}${overlapNote}`,
12691
12756
  pr_url: pr.prUrl,
12692
12757
  pr_number: pr.prNumber,
12693
12758
  pr_branch: pr.branch,
12694
- result: partial ? partialPrContinuationResult(run, 2e3, rateLimitResume ? "rate_limited" : null) : String(run.summary).slice(0, 2e3),
12759
+ result: (() => {
12760
+ const prefix = overlapBlocked ? `[VO-PUBLISH-OVERLAP-BLOCKED: ${blockedRefs}] ` : "";
12761
+ const room = 2e3 - prefix.length;
12762
+ return `${prefix}${partial ? partialPrContinuationResult(run, room, rateLimitResume ? "rate_limited" : null) : String(run.summary).slice(0, room)}`;
12763
+ })(),
12695
12764
  ...runOutcomePatch(run),
12696
12765
  ...terminalLedgerPatch(run)
12697
12766
  // decision_request / consensus_receipt_id parsed from the agent's final text (2026-08-15)