nexus-agents 8.131.1 → 8.131.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (26) hide show
  1. package/dist/{chunk-NEB2FSBW.js → chunk-5XMXBSPY.js} +3 -3
  2. package/dist/{chunk-2B55IL7S.js → chunk-AAE7F4CB.js} +7 -4
  3. package/dist/chunk-AAE7F4CB.js.map +1 -0
  4. package/dist/{chunk-QGXA3QXW.js → chunk-CGKENW3F.js} +93 -75
  5. package/dist/chunk-CGKENW3F.js.map +1 -0
  6. package/dist/{chunk-DFAT7RB7.js → chunk-FB4ZIOYS.js} +11 -12
  7. package/dist/chunk-FB4ZIOYS.js.map +1 -0
  8. package/dist/{chunk-ETJY6TMK.js → chunk-RWWPMTJK.js} +2 -2
  9. package/dist/{chunk-45AUQYWF.js → chunk-UETCXCAS.js} +193 -144
  10. package/dist/{chunk-45AUQYWF.js.map → chunk-UETCXCAS.js.map} +1 -1
  11. package/dist/cli.js +7 -7
  12. package/dist/cli.js.map +1 -1
  13. package/dist/{consensus-vote-K4SNLVKO.js → consensus-vote-6ISHSQ73.js} +4 -4
  14. package/dist/{improvement-review-UYDDYXIB.js → improvement-review-S65JP2NY.js} +4 -4
  15. package/dist/index.d.ts +3 -26
  16. package/dist/index.js +6 -6
  17. package/dist/{setup-data-dir-IYJGONN3.js → setup-data-dir-EVVWRHY2.js} +3 -3
  18. package/package.json +1 -1
  19. package/dist/chunk-2B55IL7S.js.map +0 -1
  20. package/dist/chunk-DFAT7RB7.js.map +0 -1
  21. package/dist/chunk-QGXA3QXW.js.map +0 -1
  22. /package/dist/{chunk-NEB2FSBW.js.map → chunk-5XMXBSPY.js.map} +0 -0
  23. /package/dist/{chunk-ETJY6TMK.js.map → chunk-RWWPMTJK.js.map} +0 -0
  24. /package/dist/{consensus-vote-K4SNLVKO.js.map → consensus-vote-6ISHSQ73.js.map} +0 -0
  25. /package/dist/{improvement-review-UYDDYXIB.js.map → improvement-review-S65JP2NY.js.map} +0 -0
  26. /package/dist/{setup-data-dir-IYJGONN3.js.map → setup-data-dir-EVVWRHY2.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/mcp/tools/consensus-vote.ts","../src/mcp/tools/async-dispatch-input.ts","../src/cli/voter-roles.ts","../src/consensus/decision/strategy.ts","../src/cli/voter-model-overrides.ts","../src/cli/voter-cli-access.ts","../src/cli/panel-independence.ts","../src/cli/voter-family-dealing.ts","../src/cli/voter-cancel.ts","../src/cli/voter-attempt-events.ts","../src/cli/voter-late-settlement.ts","../src/cli/voter-prompts.ts","../src/cli/voter-response.ts","../src/consensus/option-tally.ts","../src/cli/voter-response-text.ts","../src/cli/voter-attempt-log.ts","../src/cli/voter-fallback.ts","../src/cli/voter-attempt-usage.ts","../src/cli/voter-execution.ts","../src/cli/voter-agents-deadline.ts","../src/cli/voter-retry.ts","../src/cli-adapters/codex-limits.ts","../src/cli/voter-adapter-resolve.ts","../src/cli/panel-workspace.ts","../src/cli/voter-agents.ts","../src/cli/voter-project.ts","../src/mcp/tools/consensus-vote-option-gate.ts","../src/consensus/types-voting-protocol.ts","../src/consensus/types-weighted-voting.ts","../src/consensus/higher-order-types.ts","../src/consensus/higher-order-helpers.ts","../src/consensus/higher-order-voting.ts","../src/consensus/decision/verdict.ts","../src/consensus/strategies.ts","../src/consensus/result-builder.ts","../src/consensus/helpers.ts","../src/consensus/incremental-quorum.ts","../src/consensus/engine.ts","../src/consensus/quorum-validator.ts","../src/consensus/voting-protocol-helpers.ts","../src/consensus/voting-protocol.ts","../src/agents/collaboration/byzantine-events.ts","../src/consensus/weighted-voting-helpers.ts","../src/consensus/weighted-voting.ts","../src/consensus/subset-independence.ts","../src/consensus/correlation-helpers.ts","../src/consensus/correlation-model-partitions.ts","../src/consensus/correlation-tracker.ts","../src/consensus/correlation-persistence.ts","../src/consensus/correlation-persistence-records.ts","../src/mcp/tools/consensus-vote-types.ts","../src/cli/vote-diversity.ts","../src/mcp/tools/consensus-vote-option-detection.ts","../src/mcp/tools/consensus-vote-error-policy.ts","../src/utils/bounded-artifact.ts","../src/mcp/tools/consensus-vote-contrarian.ts","../src/mcp/tools/consensus-vote-recording.ts","../src/utils/file-lock.ts","../src/mcp/jobs/job-cancelled-partial-schema.ts","../src/mcp/jobs/job-result-store.ts","../src/mcp/jobs/job-id.ts","../src/mcp/jobs/job-idempotency.ts","../src/mcp/jobs/job-result-candidates.ts","../src/mcp/jobs/job-failure-detail.ts","../src/mcp/jobs/job-cancelled-partial.ts","../src/mcp/tools/consensus-vote-cancelled.ts","../src/orchestration/outcomes/outcome-store-persistence.ts","../src/orchestration/outcomes/outcome-served-model.ts","../src/mcp/tools/consensus-vote-completed-recording.ts","../src/mcp/tools/decision-cost-recording.ts","../src/mcp/tools/consensus-vote-signals.ts","../src/mcp/tools/simulation-guard.ts","../src/mcp/jobs/job-abort-registry.ts","../src/context/structured-task-state.ts","../src/context/structured-task-state-types.ts","../src/mcp/jobs/job-heartbeat-bridge.ts","../src/mcp/jobs/job-concurrency.ts","../src/mcp/jobs/run-as-job.ts"],"sourcesContent":["/* eslint-disable max-lines -- 856 lines as eslint counts them, above the 600 ceiling (.rules/governance.md); one consensus_vote tool surface: strategy resolution, cascade, option gate and async dispatch; split tracked in #6148 */\n/**\n * nexus-agents/mcp - Consensus Vote Tool\n * @module mcp/tools/consensus-vote\n */\n\nimport { randomUUID } from 'node:crypto';\nimport { z } from 'zod';\nimport { deprecatedModeWarning, resolveDispatch, withWarnings } from './async-dispatch-input.js';\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { ILogger } from '../../core/index.js';\nimport {\n createLogger,\n getErrorMessage,\n getTimeProvider,\n getRandomProvider,\n formatZodError,\n} from '../../core/index.js';\nimport type { IMcpNotifier } from '../mcp-notifier.js';\nimport { createMcpNotifier, NOOP_NOTIFIER, withProgressHeartbeat } from '../mcp-notifier.js';\nimport {\n wrapToolWithTimeout,\n toSdkCallbackWithTimeoutCheck,\n getToolTimeout,\n} from '../middleware/tool-wrapper.js';\nimport { createSecureHandler, type HandlerContext } from '../middleware/secure-handler.js';\nimport {\n registerStructuredTool,\n toolStructuredError,\n structuredToolSuccess,\n toolSuccessStructured,\n type ToolResult,\n type BaseMcpToolDeps,\n} from './tool-result.js';\nimport type { ConsensusAlgorithm, Vote, ConsensusResult, Proposal } from '../../consensus/types.js';\nimport { SUPERMAJORITY_THRESHOLD } from '../../consensus/decision/thresholds.js';\nimport type { VoterRole, AgentVoteResult } from '../../cli/vote-types.js';\nimport { getVoterRoles } from '../../cli/voter-roles.js';\nimport {\n getDefaultErrorPolicy,\n resolveStrategy,\n strategyToAlgorithm,\n} from '../../consensus/decision/strategy.js';\nimport { collectRealVotes } from '../../cli/voter-agents.js';\nimport { resolveAndLogVoterProject, type ResolvedVoterProject } from '../../cli/voter-project.js';\nimport { resolvePanelWorkspace } from '../../cli/panel-workspace.js';\nimport { evaluateOptionGate, optionThresholdFor } from './consensus-vote-option-gate.js';\nimport { createConsensusEngine } from '../../consensus/engine.js';\nimport type {\n CorrelationRecordContext,\n HigherOrderVotingResult,\n ICorrelationTracker,\n} from '../../consensus/higher-order-types.js';\nimport { HigherOrderVotingStrategy } from '../../consensus/index.js';\nimport {\n createPersistentCorrelationTracker,\n createPersistedProposal,\n saveCorrelationData,\n} from '../../consensus/correlation-persistence.js';\nimport {\n VotingStrategySchema,\n VoteDecisionStatusSchema,\n ContrarianCheckStatusSchema,\n VoteThresholdSchema,\n ConsensusVoteInputSchema,\n buildResponse,\n isHigherOrderStrategy,\n} from './consensus-vote-types.js';\nimport { resolveVoteDecision } from '../../consensus/decision/verdict.js';\nimport { applyErrorPolicy } from './consensus-vote-error-policy.js';\nimport { maybeEscalateContrarian } from './consensus-vote-contrarian.js';\nimport { recordVoteError } from './consensus-vote-recording.js';\nimport { recordCompletedVote, AllVotersFailedError } from './consensus-vote-completed-recording.js';\nimport { DecisionCostSummarySchema } from '../../observability/decision-cost.js';\nimport type { IModelAdapter } from '../../core/index.js';\nimport { emitVoteRejectedSignal } from './consensus-vote-signals.js';\nimport { getPipelineEventBus } from '../../pipeline/event-bus.js';\nimport { checkSimulationAllowed, simulationDeniedResult } from './simulation-guard.js';\nimport { getToolAnnotations } from '../tool-annotations.js';\n// #3045 / epic #2631 Stage 4 — async-mode dispatch + concurrency cap.\n// #3045 / epic #2631 Stage 4 — async-mode dispatch via the shared `runAsJob`\n// helper (#3729).\nimport {\n runAsJob,\n defaultCollisionEnvelope,\n type JobEnvelopeBuilders,\n} from '../jobs/run-as-job.js';\nimport {\n attachPartialsOnCancel,\n throwIfVoteCancelled,\n VoteCancelledError,\n} from './consensus-vote-cancelled.js';\nimport type {\n VotingStrategy,\n ConsensusVoteInput,\n ConsensusVoteResponse,\n ErrorPolicy,\n ExtendedVotingResult,\n} from './consensus-vote-types.js';\n\nexport type {\n VotingStrategy,\n ConsensusVoteInput,\n ConsensusVoteResponse,\n ContrarianCheckStatus,\n AgentVoteSummary,\n VoteDecisionStatus,\n HigherOrderMetadata,\n ExtendedVotingResult,\n} from './consensus-vote-types.js';\nexport { VotingStrategySchema, ConsensusVoteInputSchema } from './consensus-vote-types.js';\n\n// --- Correlation Tracker Singleton ---\n//\n// Lifecycle & memory model (documented per #3169):\n// * SCOPE: one process-wide, lazily-created instance shared by every\n// `consensus_vote` call. It accumulates cross-proposal voter agreement so\n// the higher_order strategy can down-weight correlated (redundant) voters.\n// One shared tracker is intentional — correlation signal is only useful\n// pooled across proposals.\n// * PERSISTENCE: backed by `createPersistentCorrelationTracker()`, which\n// hydrates from / appends to the on-disk correlation store, so the signal\n// survives restarts (the in-memory map is a hot cache over that store).\n// * MEMORY BOUND: NOT unbounded. The underlying `CorrelationTracker` is\n// FIFO-bounded by `maxProposals` / `maxObservationsPerAgent` (#521) —\n// oldest proposals are evicted once the cap is hit (eviction is logged at\n// debug in `correlation-tracker.ts`, so memory pressure is observable).\n// * RESET: `resetCorrelationTracker()` drops the instance; the next\n// `getOrCreateCorrelationTracker()` rebuilds it (re-hydrating from disk).\n// Test-isolation only. There is intentionally no per-milestone \"reset\n// between cycles\" coordinator API — eviction already bounds growth, and\n// clearing history mid-run would discard the signal the strategy needs.\nlet persistentCorrelationTracker: ICorrelationTracker | undefined;\n\n/**\n * Gets or creates the process-wide persistent CorrelationTracker (#517).\n * See the lifecycle / memory-bound / reset notes above the declaration (#3169).\n */\nfunction getOrCreateCorrelationTracker(): ICorrelationTracker {\n persistentCorrelationTracker ??= createPersistentCorrelationTracker();\n return persistentCorrelationTracker;\n}\n\n/**\n * Drops the singleton so the next {@link getOrCreateCorrelationTracker} rebuilds\n * it (re-hydrating from the persistent store). Test-isolation only. @internal\n */\nexport function resetCorrelationTracker(): void {\n persistentCorrelationTracker = undefined;\n}\n\n// --- Dependencies ---\nexport interface ConsensusVoteDeps extends BaseMcpToolDeps {\n /** MCP notifier for client-visible logging (Issue #974) */\n notifier?: IMcpNotifier | undefined;\n /**\n * In-process gateway model adapters (#4040). When the server has a configured\n * OpenAI-compatible gateway, voters route through these HTTP adapters instead\n * of shelling out to a CLI subprocess — no per-subprocess key forwarding, and\n * the nested-spawn deadlock (#4033) cannot occur. Omitted ⇒ CLI voter path.\n */\n gatewayAdapters?: readonly IModelAdapter[] | undefined;\n}\n\n// --- Strategy Resolution ---\n// `resolveStrategy`, `strategyToAlgorithm` and `getVoterRoles` moved to the\n// governed decision modules (#6000 step 1): `consensus/decision/strategy.ts`\n// and `cli/voter-roles.ts`. They were module-private here, so nothing is\n// re-exported.\n\n// --- Voting Execution ---\n/** Creates a synthetic ConsensusResult when all votes are errors (Issue #815). */\nfunction createEmptyConsensusResult(\n proposal: string,\n algorithm: ConsensusAlgorithm\n): ConsensusResult {\n const now = new Date().toISOString();\n return {\n proposalId: 'no-valid-votes',\n proposal: { title: 'MCP Consensus Vote', description: proposal, algorithm },\n outcome: 'rejected',\n votes: new Map<string, Vote>(),\n voteCounts: { approve: 0, reject: 0, abstain: 0, total: 0 },\n approvalPercentage: 0,\n quorumReached: false,\n startedAt: now,\n closedAt: now,\n durationMs: 0,\n };\n}\n\n/**\n * Creates a synthetic ConsensusResult for an error-policy short-circuit\n * (#2630). Reused for both the hard floor (errors > 50%) and `fail_closed`.\n * Stamps the reason on the proposal title and, since #3124, reports the TRUE\n * vote breakdown of the responding (non-error) voters instead of all-zeros —\n * the internal `outcome` stays `rejected` (the policy failed closed), but the\n * counts and `approvalPercentage` are honest (e.g. 6 approvals + 1 error →\n * approve:6, 100%). As of #4053 the user-facing `decision` for this short-circuit\n * is `no_quorum` (not `rejected`) — too many voters errored to reach a valid\n * consensus, which is distinct from the panel rejecting the proposal.\n */\nexport function createPolicyFailedResult(\n proposal: string,\n algorithm: ConsensusAlgorithm,\n reason: string,\n votes: readonly AgentVoteResult[]\n): ConsensusResult {\n const now = new Date().toISOString();\n const voteMap = new Map<string, Vote>();\n let approve = 0;\n let reject = 0;\n let abstain = 0;\n for (const v of votes) {\n if (v.source === 'error') continue; // errors surface separately, not as a decision\n voteMap.set(v.role, v.vote);\n if (v.vote.decision === 'approve') approve++;\n else if (v.vote.decision === 'reject') reject++;\n else abstain++;\n }\n const responding = approve + reject + abstain;\n return {\n proposalId: 'error-policy-short-circuit',\n proposal: { title: `MCP Consensus Vote — ${reason}`, description: proposal, algorithm },\n outcome: 'rejected',\n votes: voteMap,\n voteCounts: { approve, reject, abstain, total: responding },\n approvalPercentage: responding > 0 ? (approve / responding) * 100 : 0,\n quorumReached: false,\n startedAt: now,\n closedAt: now,\n durationMs: 0,\n };\n}\n\n/** Thresholds per algorithm for cascade detection. */\nconst CASCADE_THRESHOLDS: Record<string, number> = {\n majority: 0.5,\n supermajority: SUPERMAJORITY_THRESHOLD,\n unanimous: 1.0,\n};\n\n/** Detect if vote outcome is mathematically decided (#1765). */\nfunction detectEarlyCascade(\n algorithm: string,\n approvals: number,\n rejections: number,\n total: number\n): { decided: boolean; reason: string } {\n const threshold = CASCADE_THRESHOLDS[algorithm] ?? 0.5;\n if (total === 0) return { decided: false, reason: '' };\n\n // Unanimous: any rejection decides\n if (algorithm === 'unanimous' && rejections > 0) {\n return { decided: true, reason: `Unanimous rejected: ${String(rejections)} rejection(s)` };\n }\n // Approval locked: even if all remaining vote reject, approval holds\n if (approvals / total > threshold) {\n return {\n decided: true,\n reason: `Approval locked: ${String(approvals)}/${String(total)} > ${String(threshold)}`,\n };\n }\n // Rejection locked: even if all remaining vote approve, rejection holds\n const remaining = total - approvals - rejections;\n if ((approvals + remaining) / total < threshold) {\n return {\n decided: true,\n reason: `Rejection locked: max possible ${String(approvals + remaining)}/${String(total)} < ${String(threshold)}`,\n };\n }\n return { decided: false, reason: '' };\n}\n\n/**\n * Run the consensus engine over already-policy-applied votes.\n *\n * Callers MUST pass `engineVotes` produced by `applyErrorPolicy` (#2630)\n * — under `reduce_denominator` that means errors are already filtered;\n * under `count_as_abstain` errors have been converted to abstain\n * decisions but kept in the array. This function does no further\n * filtering on `source`.\n */\nasync function processVotesThroughEngine(\n engineVotes: readonly AgentVoteResult[],\n proposal: string,\n algorithm: ConsensusAlgorithm\n): Promise<ConsensusResult> {\n if (engineVotes.length === 0) return createEmptyConsensusResult(proposal, algorithm);\n\n const engine = createConsensusEngine();\n const engineProposal: Proposal = {\n title: 'MCP Consensus Vote',\n description: proposal,\n algorithm,\n };\n const proposalResult = await engine.propose(engineProposal);\n if (!proposalResult.ok)\n throw new Error(`Failed to create proposal: ${proposalResult.error.message}`, {\n cause: proposalResult.error,\n });\n\n const proposalId = proposalResult.value;\n for (const { role, vote } of engineVotes) await engine.vote(proposalId, role, vote);\n\n const resultRes = await engine.close(proposalId);\n if (!resultRes.ok)\n throw new Error(`Failed to close proposal: ${resultRes.error.message}`, {\n cause: resultRes.error,\n });\n return resultRes.value;\n}\n\nfunction runHigherOrderVoting(\n strategy: VotingStrategy,\n voteMap: Map<string, Vote>,\n logger: ILogger,\n context: CorrelationRecordContext\n): HigherOrderVotingResult | undefined {\n if (!isHigherOrderStrategy(strategy)) return undefined;\n const hovStrategy = new HigherOrderVotingStrategy();\n const tracker = getOrCreateCorrelationTracker();\n tracker.setCurrentModelPins?.(context.modelPins);\n const result = hovStrategy.aggregate(voteMap, tracker);\n logger.info('Higher-Order Voting complete', {\n method: result.method,\n decision: result.decision,\n posteriorApproval: result.posteriorApproval.toFixed(3),\n });\n return result;\n}\n\nfunction buildCorrelationContext(votes: readonly AgentVoteResult[]): CorrelationRecordContext {\n const modelPins = new Map<string, string>();\n const observedModels = new Map<string, string>();\n for (const vote of votes) {\n if (vote.pinnedModel !== undefined) modelPins.set(vote.role, vote.pinnedModel);\n if (vote.model !== undefined) observedModels.set(vote.role, vote.model);\n }\n return { modelPins, observedModels };\n}\n\nfunction recordVotesToTracker(\n votes: readonly AgentVoteResult[],\n outcome: 'approved' | 'rejected',\n logger: ILogger\n): void {\n // #3170: record the REAL (LLM) votes even when the panel is mixed-source,\n // rather than dropping ALL correlation data because one voter simulated/errored.\n // Recording the accurate LLM-only subset beats leaving the matrix permanently stale.\n const llmVotes = votes.filter((v) => v.source === 'llm');\n if (llmVotes.length < votes.length) {\n logger.warn('Recording only LLM votes to correlation tracker; excluding non-LLM votes', {\n recorded: llmVotes.length,\n excluded: votes.length - llmVotes.length,\n });\n }\n if (llmVotes.length === 0) return; // nothing real to record\n const llmVoteMap = new Map<string, Vote>();\n for (const v of llmVotes) llmVoteMap.set(v.role, v.vote);\n const context = buildCorrelationContext(llmVotes);\n\n const tracker = getOrCreateCorrelationTracker();\n const id = `consensus-${String(getTimeProvider().now())}-${getRandomProvider().random().toString(36).slice(2, 9)}`;\n tracker.recordProposalVotes(id, llmVoteMap, outcome, context);\n logger.debug('Recorded votes to tracker', { proposalId: id, outcome });\n\n try {\n const persisted = createPersistedProposal(id, llmVoteMap, outcome, context);\n const saveResult = saveCorrelationData([persisted]);\n if (!saveResult.ok) {\n logger.warn('Failed to persist correlation data', { error: saveResult.error.message });\n }\n } catch (error: unknown) {\n const message = getErrorMessage(error);\n logger.warn('Error persisting correlation data', { error: message });\n }\n}\n\n/** Process votes with cascade detection — extracted for max-lines-per-function (#1765). */\n/**\n * Run the engine + cascade-detection + higher-order voting against\n * already-policy-applied votes (#2630).\n *\n * Callers MUST pass `engineVotes` produced by `applyErrorPolicy` — no\n * filtering on `source` happens inside this function. Cascade-detection\n * counts and the higher-order voteMap are both built directly from\n * `engineVotes`.\n */\nasync function processVotesWithCascade(\n engineVotes: readonly AgentVoteResult[],\n opts: {\n totalRoles: number;\n proposal: string;\n algorithm: ConsensusAlgorithm;\n strategy: VotingStrategy;\n log: ILogger;\n }\n): Promise<{\n engineResult: ConsensusResult;\n voteMap: Map<string, Vote>;\n higherOrderResult: ReturnType<typeof runHigherOrderVoting>;\n outcome: 'approved' | 'rejected';\n cascaded: boolean;\n}> {\n const approvals = engineVotes.filter((v) => v.vote.decision === 'approve').length;\n const rejections = engineVotes.filter((v) => v.vote.decision === 'reject').length;\n const cascadeInfo = detectEarlyCascade(opts.algorithm, approvals, rejections, opts.totalRoles);\n\n if (cascadeInfo.decided) {\n opts.log.info('Vote cascade: outcome decided early', {\n approvals,\n rejections,\n total: opts.totalRoles,\n reason: cascadeInfo.reason,\n });\n }\n\n const engineResult = await processVotesThroughEngine(engineVotes, opts.proposal, opts.algorithm);\n const voteMap = new Map<string, Vote>();\n for (const { role, vote } of engineVotes) voteMap.set(role, vote);\n\n const higherOrderResult = cascadeInfo.decided\n ? undefined\n : runHigherOrderVoting(opts.strategy, voteMap, opts.log, buildCorrelationContext(engineVotes));\n const outcome: 'approved' | 'rejected' =\n engineResult.outcome === 'approved' ? 'approved' : 'rejected';\n\n return { engineResult, voteMap, higherOrderResult, outcome, cascaded: cascadeInfo.decided };\n}\n\n/** Execute a consensus vote with full strategy support. Exported for pipeline DRY (#1694). */\n/**\n * Build a short-circuit result for the error-policy gate (#2630). Called\n * when the hard floor (>50% errors) trips or `fail_closed` matches.\n * Logs the warning and returns the synthetic `ExtendedVotingResult` that\n * `executeVoting` propagates to the response builder.\n */\nfunction buildPolicyShortCircuitResult(args: {\n input: ConsensusVoteInput;\n strategy: VotingStrategy;\n algorithm: ConsensusAlgorithm;\n roles: readonly VoterRole[];\n votes: readonly AgentVoteResult[];\n /** The RESOLVED policy (`executeVotingInner` applied the default before calling). */\n errorPolicy: ErrorPolicy;\n reason: string;\n startTime: number;\n logger: ILogger;\n}): ExtendedVotingResult {\n args.logger.warn('Consensus vote short-circuited by error policy', {\n errorPolicy: args.errorPolicy,\n reason: args.reason,\n });\n const totalTimeMs = getTimeProvider().now() - args.startTime;\n return {\n proposal: args.input.proposal,\n threshold: args.algorithm,\n result: createPolicyFailedResult(args.input.proposal, args.algorithm, args.reason, args.votes),\n votes: args.votes,\n totalTimeMs,\n simulateVotes: args.input.simulateVotes,\n strategy: args.strategy,\n // #4132: thread the requested panel shape so the absolute_quorum predicate\n // in buildResponse has PANEL_SIZE + contrarian-presence even on a short-circuit.\n panelSize: args.roles.length,\n contrarianRequested: args.roles.includes('catfish'),\n // #6111: the short-circuit returns before the escalation gate, so the\n // quick-mode contrarian check never ran.\n contrarianCheck: 'skipped',\n // #3124: surface WHY a high-approval result is still 'rejected' so callers\n // don't mistake a fail-closed policy short-circuit for a genuine rejection.\n policyReason: args.reason,\n // #6211: the policy that short-circuited is the policy the record states.\n errorPolicy: args.errorPolicy,\n };\n}\n\n/*\n * Top-level voting flow: vote collection → error-policy gate → engine +\n * cascade → contrarian escalation → finalize. Further extraction\n * obscures control flow more than it helps; helpers already extracted\n * are applyErrorPolicy, buildPolicyShortCircuitResult,\n * maybeEscalateContrarian, finalizeVotingResult.\n */\nexport async function executeVoting(\n input: ConsensusVoteInput,\n logger: ILogger,\n opts?: {\n voteTimeoutMs?: number;\n /** CLI ratification checkout, retained through escalation. */\n workspace?: string | undefined;\n workspaceSha?: string | undefined;\n gatewayAdapters?: readonly IModelAdapter[] | undefined;\n /** #5393: stops LAUNCHING un-started voters when `cancel_job` fires. */\n signal?: AbortSignal | undefined;\n /** #6110: set only by the escalation re-vote, which reuses the outer resolution. */\n project?: ResolvedVoterProject | undefined;\n /**\n * Per-seat progress callback (#6162): the async-job heartbeat, fired as\n * each seat settles. Retained through the escalation re-vote.\n */\n onVoteCollected?: ((vote: AgentVoteResult) => void) | undefined;\n }\n): Promise<ExtendedVotingResult> {\n // #6110: resolve the target project ONCE per vote (the escalation re-vote\n // inherits it through opts) and stamp it on the result next to `decision`.\n const project = opts?.project ?? resolveAndLogVoterProject(input.project, logger);\n // #6258: the directory every seat is handed, resolved once and stamped on the\n // live result, so an `unverifiable` seat is diagnosable without stderr.\n const panelWorkspace = resolvePanelWorkspace(opts?.workspace);\n const result = await executeVotingInner(input, logger, { ...opts, project, panelWorkspace });\n // #6735 backstop: a cancel that landed after the seats settled (during the\n // contrarian check or escalation) must not stamp or record a decision either.\n throwIfVoteCancelled(opts?.signal, result.votes, result.votes.length);\n result.project = project;\n // A simulated panel pointed no seat at a directory, so it names none.\n if (!input.simulateVotes) result.workspace = panelWorkspace;\n // An escalated full-panel result was finalized (and recorded) by its recursive\n // executeVoting call. Remember that state so this outer quick-mode frame does\n // not persist the same full-panel proposal twice.\n const correlationAlreadyRecorded = result.decision !== undefined;\n // #4135: stamp the response-layer decision (incl. `no_quorum`) ONCE, using the\n // SAME `resolveVoteDecision` `buildResponse` consumes, so pipeline consumers can\n // honor a quorum void instead of misreading it as a rejection — without\n // recomputing the policy math (DRY; the decision can't diverge). `errorCount`\n // uses the identical definition `buildResponse` uses.\n const errorCount = result.votes.filter((v) => v.source === 'error').length;\n // #4472: when the proposal declared options, the leading option must clear\n // the bar too. Applied BEFORE the decision is stamped so the record and the\n // response both reflect the gated verdict — a veto that only reached the\n // response would leave the audit trail claiming an approval that did not\n // happen. No-op when no options were declared.\n applyOptionGate(input, result);\n result.decision = resolveVoteDecision(input, result, errorCount).decision;\n // #6735: the tracker write stays here, not after the ledger append. It runs\n // with no `await` since the backstop above, so a cancel observed before the\n // verdict never reaches it. A cancel that lands later (during the ledger-lock\n // wait) leaves this observation in place on purpose: it is per-voter\n // agreement from a panel whose every seat settled and whose verdict was\n // computed before the cancel. It is a statistic, not a decision record, and\n // it binds nothing. Moving it would change all five `executeVoting` callers.\n if (\n !correlationAlreadyRecorded &&\n (result.decision === 'approved' || result.decision === 'rejected')\n ) {\n recordVotesToTracker(result.votes, result.decision, logger);\n }\n return result;\n}\n\n/**\n * Veto an approved verdict whose declared-option split failed its bar.\n *\n * Mutates `result` in place: `executeVoting` owns it and has not yet published\n * it. Only ever flips approved to rejected, never the reverse — and the\n * resulting `decision` must be `rejected`, not `no_quorum` (#4529): the panel\n * convened and disagreed, which is the opposite of a voided vote.\n *\n * Exported for the composition test (#4529): the defect this guards against\n * lives in how this function's output feeds `resolveVoteDecision` on the very\n * next line of `executeVoting`, not in either function alone.\n */\nexport function applyOptionGate(input: ConsensusVoteInput, result: ExtendedVotingResult): void {\n const declaredOptions = input.options;\n if (declaredOptions === undefined || declaredOptions.length === 0) return;\n\n const outcome = evaluateOptionGate(\n result.votes,\n declaredOptions,\n optionThresholdFor(result.strategy, input.threshold),\n result.result.outcome === 'approved'\n );\n\n if (!outcome.vetoed) {\n result.optionGate = outcome.verdict;\n return;\n }\n\n result.result.outcome = 'rejected';\n // #4529: the reason rides on the verdict, NOT on policyReason. policyReason\n // means \"an error policy voided this vote\", and resolveVoteDecision\n // short-circuits any non-undefined value straight to `no_quorum` — so\n // borrowing the field filed a measured split as \"nothing was decided\", and\n // `--on-no-quorum=retry` then re-rolled the panel and discarded the dissent\n // the gate had just detected. Decided by a 7-voter higher_order panel\n // (6 approvers, all selecting this shape).\n result.optionGate =\n outcome.reason !== undefined ? { ...outcome.verdict, reason: outcome.reason } : outcome.verdict;\n}\n\n// eslint-disable-next-line max-lines-per-function -- see block comment above\nasync function executeVotingInner(\n input: ConsensusVoteInput,\n logger: ILogger,\n // Required here, normalized by `executeVoting`. Every `opts.` inside was a\n // branch against the same never-null value; taking the option away at this\n // boundary removes them all rather than adding one more (#5393).\n opts: {\n voteTimeoutMs?: number;\n /** CLI ratification checkout, retained through escalation. */\n workspace?: string | undefined;\n workspaceSha?: string | undefined;\n gatewayAdapters?: readonly IModelAdapter[] | undefined;\n /** #5393: stops LAUNCHING un-started voters when `cancel_job` fires. */\n signal?: AbortSignal | undefined;\n /** #6110: the target project, resolved once by `executeVoting`. */\n project: ResolvedVoterProject;\n /** #6258: the directory the seats are handed — the value `executeVoting` stamps. */\n panelWorkspace: string;\n /** #6162: per-seat heartbeat, forwarded to `collectRealVotes`. */\n onVoteCollected?: ((vote: AgentVoteResult) => void) | undefined;\n }\n): Promise<ExtendedVotingResult> {\n const strategy = resolveStrategy(input);\n const algorithm = strategyToAlgorithm(strategy);\n const roles = getVoterRoles(input.quickMode);\n const startTime = getTimeProvider().now();\n const errorPolicy = input.errorPolicy ?? getDefaultErrorPolicy(strategy);\n\n logger.info('Starting consensus vote', {\n strategy,\n algorithm,\n roleCount: roles.length,\n errorPolicy,\n });\n const votes = await collectRealVotes({\n roles,\n proposal: input.proposal,\n simulate: input.simulateVotes,\n ...(opts.voteTimeoutMs !== undefined && { timeoutMs: opts.voteTimeoutMs }),\n ...(opts.gatewayAdapters !== undefined && { gatewayAdapters: opts.gatewayAdapters }),\n declaredOptions: input.options,\n // #6110: every seat's system prompt names the caller's project.\n project: opts.project.name,\n workspace: opts.panelWorkspace,\n workspaceSha: opts.workspaceSha,\n signal: opts.signal,\n onVoteCollected: opts.onVoteCollected,\n });\n // #6735: a cancelled vote stops here, before the engine, with only the\n // seats that cast a vote — no verdict is computed from a partial panel.\n throwIfVoteCancelled(opts.signal, votes, roles.length);\n\n // Error-policy gate (#2630): hard floor + fail_closed + reduce_denominator /\n // count_as_abstain transformation. Engine sees the resulting shape.\n const policyDecision = applyErrorPolicy(votes, errorPolicy);\n if (policyDecision.shortCircuit) {\n return buildPolicyShortCircuitResult({\n input,\n strategy,\n algorithm,\n roles,\n votes,\n errorPolicy,\n reason: policyDecision.reason ?? 'error policy short-circuit',\n startTime,\n logger,\n });\n }\n\n // Check for early cascade and process votes (#1765)\n const { engineResult, higherOrderResult, outcome, cascaded } = await processVotesWithCascade(\n policyDecision.engineVotes,\n {\n totalRoles: roles.length,\n proposal: input.proposal,\n algorithm,\n strategy,\n log: logger,\n }\n );\n\n const escalation = await maybeEscalateContrarian(\n input,\n outcome,\n { strategy, posteriorApproval: higherOrderResult?.posteriorApproval, revote: executeVoting },\n logger,\n opts\n );\n // #6111: an escalated full-panel result reports the quick-mode check that\n // produced it (`ok` when the contrarian triggered the re-vote, `skipped` when\n // the posterior floor pre-empted the call), not the inner frame's `skipped`.\n if (escalation.escalated !== undefined) {\n return { ...escalation.escalated, contrarianCheck: escalation.contrarianCheck };\n }\n\n const finalized = finalizeVotingResult({\n input,\n strategy,\n algorithm,\n roles,\n engineResult,\n higherOrderResult,\n votes,\n outcome,\n cascaded,\n errorPolicy,\n startTime,\n logger,\n });\n // #4132: a contrarian check that errored under absolute_quorum voids the quorum\n // — stamp policyReason so buildResponse's existing ternary downgrades to\n // no_quorum, matching the errored-voter path. (Kept out of finalizeVotingResult\n // to hold executeVoting within its cyclomatic budget.)\n return applyContrarianDegrade(\n { ...finalized, contrarianCheck: escalation.contrarianCheck },\n escalation.degradeReason\n );\n}\n\n/**\n * #4132: stamp the contrarian-check-errored degrade reason onto a finalized\n * result (unless an upstream short-circuit already set one). A no-op when the\n * contrarian check ran cleanly (`degradeReason` undefined).\n */\nfunction applyContrarianDegrade(\n result: ExtendedVotingResult,\n degradeReason: string | undefined\n): ExtendedVotingResult {\n if (degradeReason === undefined || result.policyReason !== undefined) return result;\n return { ...result, policyReason: degradeReason };\n}\n\n/**\n * Run a consensus vote with a plain goal as the proposal, default settings\n * (real voters, default strategy). The strategy executor the unified `run`\n * entry point dispatches to for the `consensus` strategy (#3575). Non-simulated.\n */\nexport async function runConsensusForGoal(\n goal: string,\n logger: ILogger = createLogger({ tool: 'consensus_vote' }),\n gatewayAdapters?: readonly IModelAdapter[],\n /** #6162: per-seat heartbeat when the caller is an async job body. */\n onVoteCollected?: (vote: AgentVoteResult) => void,\n /** `run`'s async-job cancel signal (#6305): stops launching un-started voters. */\n signal?: AbortSignal\n): Promise<ExtendedVotingResult> {\n // Parse through the schema so defaults (quickMode, simulateVotes:false) apply.\n // #4042: thread the in-process gateway adapters so the run/MetaOrchestrator\n // consensus path routes voters through the gateway like consensus_vote (#4040),\n // not the CLI subprocess.\n return executeVoting(ConsensusVoteInputSchema.parse({ proposal: goal }), logger, {\n ...(gatewayAdapters !== undefined && { gatewayAdapters }),\n onVoteCollected,\n ...(signal !== undefined && { signal }),\n });\n}\n\n/** Build the final `ExtendedVotingResult` once the engine + cascade settle. */\nfunction finalizeVotingResult(args: {\n input: ConsensusVoteInput;\n strategy: VotingStrategy;\n algorithm: ConsensusAlgorithm;\n roles: readonly VoterRole[];\n engineResult: ConsensusResult;\n higherOrderResult: ReturnType<typeof runHigherOrderVoting>;\n votes: readonly AgentVoteResult[];\n outcome: 'approved' | 'rejected';\n cascaded: boolean;\n /** #6211: the RESOLVED policy the tally above was computed under. */\n errorPolicy: ErrorPolicy;\n startTime: number;\n logger: ILogger;\n}): ExtendedVotingResult {\n const totalTimeMs = getTimeProvider().now() - args.startTime;\n args.logger.info('Consensus vote completed', {\n strategy: args.strategy,\n outcome: args.outcome,\n durationMs: totalTimeMs,\n cascaded: args.cascaded,\n });\n const result: ExtendedVotingResult = {\n proposal: args.input.proposal,\n threshold: args.algorithm,\n result: args.engineResult,\n votes: args.votes,\n totalTimeMs,\n simulateVotes: args.input.simulateVotes,\n strategy: args.strategy,\n // #4132: PANEL_SIZE + contrarian-presence for the absolute_quorum predicate.\n panelSize: args.roles.length,\n contrarianRequested: args.roles.includes('catfish'),\n // #6211: carried to the persisted record; the response never needed it\n // because `buildResponse` still holds the input, but the record does not.\n errorPolicy: args.errorPolicy,\n };\n if (args.higherOrderResult !== undefined) result.higherOrderResult = args.higherOrderResult;\n return result;\n}\n\n// --- Handler & Registration ---\n/** What the tool input declared that the voting result does not carry. */\nfunction declaredByCaller(\n args: ConsensusVoteInput,\n signal?: AbortSignal,\n jobId?: string\n): Parameters<typeof recordCompletedVote>[3] {\n return {\n options: args.options,\n jobId,\n signal,\n ...(args.ratifies !== undefined ? { ratifies: args.ratifies } : {}),\n ...(args.ratifiesPr !== undefined ? { ratifiesPr: args.ratifiesPr } : {}),\n };\n}\n\nasync function handleConsensusVote(\n deps: ConsensusVoteDeps,\n args: ConsensusVoteInput,\n signal?: AbortSignal,\n /** #6162: `runAsJob`'s heartbeat, fired per settled seat. Absent in sync mode. */\n onVoteCollected?: (vote: AgentVoteResult) => void,\n jobId?: string\n): Promise<{ ok: true; value: ConsensusVoteResponse } | { ok: false; error: string }> {\n const logger = deps.logger ?? createLogger({ tool: 'consensus_vote' });\n try {\n const result = await executeVoting(args, logger, {\n ...(deps.gatewayAdapters !== undefined && { gatewayAdapters: deps.gatewayAdapters }),\n signal,\n onVoteCollected,\n });\n // #6735: the ledger append goes first. It throws VoteCancelledError when a\n // cancel landed during its lock wait, and a cancelled vote must not then\n // be recorded to memory or the outcome store as a success either.\n const { costSummary, voteRecord } = await recordCompletedVote(\n args.proposal,\n result,\n logger,\n declaredByCaller(args, signal, jobId)\n );\n // Close the self-tuning loop: a rejected vote emits signal.vote_rejected\n // onto the typed pipeline bus for the shadow TuneStage (#3147; #3289 Option 2).\n emitVoteRejectedSignal(result.result, getPipelineEventBus(), logger);\n return { ok: true, value: buildResponse(args, result, costSummary, voteRecord) };\n } catch (error) {\n if (error instanceof AllVotersFailedError) return { ok: false, error: error.message };\n // #6735: a cancel is not a vote failure — it reaches the async dispatcher,\n // which attaches the cast seats to the cancelled record.\n if (error instanceof VoteCancelledError) throw error;\n const message = getErrorMessage(error);\n const cause = error instanceof Error ? error : new Error(message);\n logger.error('Consensus vote failed', cause);\n recordVoteError(args.proposal, message);\n return { ok: false, error: `Voting failed: ${message}` };\n }\n}\n\ntype ConsensusVoteToolResponse = ToolResult;\n\n/**\n * Dispatch the vote on a background promise + return a pending envelope\n * (#3045 / epic #2631 Stage 4). Mirrors run_workflow / orchestrate.\n *\n * Cancellation semantics (#5393). This paragraph previously claimed\n * `collectRealVotes` \"honors per-voter signals\" via plumbing from #3038. It did\n * not — the function had no signal parameter at all, so `cancel_job` marked the\n * job cancelled while every remaining voter still ran. The comment describing a\n * capability that did not exist is plausibly why that went unnoticed.\n *\n * What happens now: the signal is threaded to the vote launcher, which checks it\n * after each stagger delay and does NOT launch the voters that have not started,\n * recording them as error results rather than as any decision. Since #6729 it\n * also reaches every seat's adapter call, combined with the seat's deadline, so\n * a voter in flight is aborted rather than left to run for the length of its\n * slowest seat while the job holds its concurrency slot. The job record stays\n * `cancelled` (the terminal writers no-op, #4022). Since #6735 the body stops\n * before any verdict and the seats that had cast a vote are attached to that\n * record as `cancelledPartial` — never as a decision, and never on the ledger.\n *\n * Concurrency cap is enforced via `tryAcquire('consensus_vote')`\n * (default 2; voting is 7-fan-out so caps multiply adapter load fast).\n */\n/**\n * Reject when the vote failed, so `runAsJob` records the job `failed` rather\n * than `complete` (#4362). Increment 2 (#4363) folds this fail-closed check into\n * `runAsJob` itself for every caller.\n *\n * Exported so the transform can be asserted without standing up a live voter\n * panel (the success path initializes the whole memory substrate).\n * @internal\n */\nexport async function unwrapVoteOrThrow(\n pending: ReturnType<typeof handleConsensusVote>\n): Promise<Awaited<ReturnType<typeof handleConsensusVote>>> {\n const result = await pending;\n if (!result.ok) throw new Error(result.error);\n return result;\n}\n\nfunction dispatchAsyncConsensusVote(\n deps: ConsensusVoteDeps,\n args: import('./consensus-vote-types.js').ConsensusVoteInput\n): ConsensusVoteToolResponse {\n // #3729: dispatch via the shared `runAsJob` helper — the exact sequence this\n // function used to inline. consensus_vote's only diff is the freshJobId; its\n // pending/busy/replay/collision envelopes are byte-for-byte the helper's\n // ToolResult defaults, so no per-tool `toEnvelope` is needed.\n return runAsJob<\n import('./consensus-vote-types.js').ConsensusVoteInput,\n Awaited<ReturnType<typeof handleConsensusVote>>\n >({\n toolName: 'consensus_vote',\n input: args,\n idempotencyKey: args.idempotencyKey,\n freshJobId: () => `job-vote-${randomUUID()}`,\n // #5066: structured envelopes — this tool declares an outputSchema, and\n // the SDK rejects a non-error result that carries no structured content.\n toEnvelope: ASYNC_ENVELOPES,\n // #6735: on a cancel the body throws VoteCancelledError; the seats it had\n // cast are attached to the `cancelled` record, which keeps its status.\n // #4362: `handleConsensusVote`'s `{ ok: false }` used to flow into the job\n // record verbatim, and `runAsJob` records `complete` for anything its `run`\n // callback RESOLVES — so a dead voter panel produced a job a caller polling\n // `get_job_result` read as a success. Reject instead, mirroring the sync\n // sibling's `toolStructuredError` on the same condition.\n // #5393: arity 4 — signal + #6162 progress. `runAsJob` derives\n // `signalAccepted` from `run.length`, so taking the signal is what makes the\n // job record say cancellation works — the claim follows the capability.\n // `progress` is the liveness heartbeat, fired as each seat settles, so a\n // panel allowed past the standard MCP ceiling is never called wedged while\n // its seats keep landing.\n run: (jobId, input, signal, progress) =>\n attachPartialsOnCancel(\n jobId,\n 'consensus_vote',\n unwrapVoteOrThrow(handleConsensusVote(deps, input, signal, progress, jobId))\n ),\n ...(deps.logger !== undefined ? { logger: deps.logger } : {}),\n });\n}\n\n/**\n * Run the synchronous vote path + format the response. Extracted from\n * the handler so the async-mode branch keeps the per-function size cap\n * (#3045 added a branch + dispatcher call site to the handler).\n */\nasync function runSyncConsensusVote(\n deps: ConsensusVoteDeps,\n notifier: IMcpNotifier,\n args: import('./consensus-vote-types.js').ConsensusVoteInput\n): Promise<ConsensusVoteToolResponse> {\n const result = await withProgressHeartbeat('consensus_vote', notifier, () =>\n handleConsensusVote(deps, args)\n );\n if (!result.ok) {\n return toolStructuredError({ errorCategory: 'internal', message: result.error });\n }\n for (const vote of result.value.votes) {\n notifier.debug('consensus_vote', {\n event: 'vote_collected',\n role: vote.role,\n decision: vote.decision,\n });\n }\n notifier.info('consensus_vote', {\n event: 'vote_complete',\n decision: result.value.decision,\n approvalPercentage: result.value.approvalPercentage,\n voteCount: result.value.votes.length,\n });\n // Untyped until 9.0 (#7049): the published AgentVoteSummary.rejectionCategories\n // is string[], wider than this tool's enum schema. Runtime strictness still\n // applies through registerStructuredTool.\n return toolSuccessStructured({ ...result.value });\n}\n\nfunction createConsensusVoteHandler(deps: ConsensusVoteDeps) {\n const notifier = deps.notifier ?? NOOP_NOTIFIER;\n return async (args: unknown, ctx: HandlerContext): Promise<ConsensusVoteToolResponse> => {\n const validationResult = ConsensusVoteInputSchema.safeParse(args);\n if (!validationResult.success) {\n return toolStructuredError({\n errorCategory: 'validation',\n message: `Validation error: ${formatZodError(validationResult.error)}`,\n });\n }\n // #4170: simulateVotes fails CLOSED outside test runners — checked in the\n // sync prelude BEFORE the async runAsJob dispatch so sync and async modes\n // reject identically (no pending envelope for a random panel).\n if (validationResult.data.simulateVotes) {\n const simCheck = checkSimulationAllowed('consensus_vote', ctx.logger);\n if (!simCheck.allowed) return simulationDeniedResult(simCheck.reason);\n }\n const strategy = validationResult.data.strategy ?? 'simple_majority';\n // #4968: `dispatch` is canonical; `mode` is the deprecated alias. A call\n // that sent only `mode` still runs, and says so in `_meta` warnings.\n const dispatch = resolveDispatch(validationResult.data);\n const modeWarning = deprecatedModeWarning(validationResult.data);\n ctx.logger.debug('Starting consensus vote', {\n strategy,\n quickMode: validationResult.data.quickMode,\n ...(dispatch !== undefined ? { dispatch } : {}),\n });\n notifier.info('consensus_vote', {\n event: 'vote_start',\n proposalLength: validationResult.data.proposal.length,\n strategy,\n });\n // #3045 / epic #2631 Stage 4 — async dispatch.\n if (dispatch === 'async') {\n const asyncResult = dispatchAsyncConsensusVote(deps, validationResult.data);\n notifier.info('consensus_vote', {\n event: 'vote_dispatched_async',\n proposalLength: validationResult.data.proposal.length,\n strategy,\n });\n return withWarnings(asyncResult, [modeWarning]);\n }\n return withWarnings(await runSyncConsensusVote(deps, notifier, validationResult.data), [\n modeWarning,\n ]);\n };\n}\n\n/**\n * Async-dispatch envelopes carrying `structuredContent` (#5066).\n *\n * `runAsJob`'s defaults are text-only. Because this tool declares an\n * `outputSchema`, the SDK requires structured content on every non-error\n * result, so every `mode: 'async'` call failed with -32602 — the mode the\n * tool's own description recommends for 7-voter panels.\n */\nconst ASYNC_ENVELOPES: JobEnvelopeBuilders<ToolResult> = {\n pending: (jobId) =>\n structuredToolSuccess(z.object(CONSENSUS_VOTE_OUTPUT_SCHEMA), {\n status: 'pending',\n jobId,\n pollTool: 'get_job_result',\n note: 'Poll via get_job_result({ jobId }) until status !== \"pending\".',\n }),\n busy: (retryAfterMs, toolName) =>\n structuredToolSuccess(z.object(CONSENSUS_VOTE_OUTPUT_SCHEMA), {\n status: 'busy',\n retryAfterMs,\n note: `Async-mode concurrency cap reached for ${toolName}. Retry later or use dispatch: \"sync\".`,\n }),\n replay: (jobId) =>\n structuredToolSuccess(z.object(CONSENSUS_VOTE_OUTPUT_SCHEMA), {\n status: 'replay',\n jobId,\n pollTool: 'get_job_result',\n note: 'Poll via get_job_result({ jobId }) until status !== \"pending\".',\n }),\n collision: defaultCollisionEnvelope,\n};\n\n/**\n * Output schema for consensus_vote tool (Issue #1117, #1246).\n *\n * Every vote field is optional because this tool has TWO response shapes and\n * `registerTool` takes a `ZodRawShape`, which cannot express a discriminated\n * union (#5066). `status` tells them apart: present means an async-dispatch\n * envelope, absent means a completed vote.\n *\n * What that gives up is requiredness. What it keeps is the guarantee that\n * actually protects the protocol: the SDK validates with\n * `additionalProperties: false`, so an UNDECLARED response field still fails\n * every call — the #5044 regression this schema exists to catch.\n */\nexport const CONSENSUS_VOTE_OUTPUT_SCHEMA = {\n /** Async-dispatch envelope discriminator — absent on a completed vote. */\n status: z.enum(['pending', 'busy', 'replay']).optional(),\n jobId: z.string().max(200).optional(),\n pollTool: z.literal('get_job_result').optional(),\n note: z.string().max(500).optional(),\n retryAfterMs: z.number().optional(),\n proposal: z.string().optional(),\n strategy: VotingStrategySchema.optional(),\n // Reuses the canonical VoteDecisionStatusSchema (single source) — a hand-listed\n // subset here (was ['approved','rejected','no_quorum']) omitted the reachable\n // 'timeout'/'pending' outcomes and made strict clients reject those votes (#4032).\n decision: VoteDecisionStatusSchema.optional(),\n approvalPercentage: z.number().optional(),\n voteCounts: z\n .object({\n approve: z.number(),\n reject: z.number(),\n abstain: z.number(),\n error: z.number(),\n /** #6094: seats that could not read the artifact; always present. */\n unverifiable: z.number(),\n })\n .optional(),\n // #6111: the quick-mode contrarian check is not a seat, so `voteCounts.error`\n // cannot count it. Present on every completed vote (`skipped` when it did not\n // run); optional here only because the async envelope shares this schema.\n contrarianCheck: ContrarianCheckStatusSchema.optional(),\n votes: z\n .array(\n z.object({\n role: z.string().max(100),\n decision: z.enum(['approve', 'reject', 'abstain']),\n confidence: z.number(),\n reasoning: z.string().max(4000),\n simulated: z.boolean(),\n error: z.boolean(),\n retried: z.boolean().optional(),\n retriedFrom: z\n .object({\n source: z.enum(['error', 'unverifiable']),\n error: z.string().optional(),\n errorTruncated: z.literal(true).optional(),\n })\n .optional(),\n /** #6094: present only when the seat could not read the artifact. */\n unverifiable: z.literal(true).optional(),\n /** #6115: present only when the seat answered elsewhere than assigned. */\n fallback: z\n .object({\n fromCli: z.string().max(100),\n fromModel: z.string().max(100).optional(),\n reason: z.enum(['rate-limit', 'capacity', 'auth', 'timeout', 'sandbox', 'unknown']),\n })\n .optional(),\n modelUsed: z.string().max(100).optional(),\n rejectionCategories: z\n .array(\n z.enum([\n 'YAGNI',\n 'DRY_VIOLATION',\n 'OVER_ENGINEERING',\n 'SCOPE_CREEP',\n 'SECURITY_RISK',\n 'MISALIGNED',\n 'INSUFFICIENT_EVIDENCE',\n ])\n )\n .optional(),\n })\n )\n .optional(),\n threshold: VoteThresholdSchema.optional(),\n durationMs: z.number().optional(),\n simulateVotes: z.boolean().optional(),\n // #6110: the project the panel judged and how the name was decided. Always\n // on the response; optional here like every field, because the async\n // `pending` envelope shares this schema.\n project: z\n .object({\n name: z.string().max(200),\n source: z.enum(['input', 'derived', 'default']),\n })\n .optional(),\n // #6258: the working directory the panel's seats were pointed at. Absent\n // when no live seat ran (simulated panel) and on the async envelope.\n workspace: z.string().max(4096).optional(),\n higherOrderMetadata: z\n .object({\n posteriorApproval: z.number(),\n posteriorRejection: z.number(),\n effectiveVoteCount: z.number(),\n method: z.enum(['ow', 'isp', 'simple']),\n appliedToDecision: z.boolean(),\n usedCorrelationData: z.boolean(),\n improvementOverBaseline: z.number(),\n downweightedAgents: z.array(z.string().max(100)).max(10),\n reasoning: z.string().max(2000),\n })\n .optional(),\n // #3124: explains a `rejected` decision that coexists with a high\n // approvalPercentage (an error-policy short-circuit, e.g. fail_closed).\n policyReason: z.string().max(200).optional(),\n // #3991: whether the authentic vote record was persisted at vote time. Post-\n // #3991 it routes through nexusDataPath under governance/, so true is the\n // normal case; false means all-simulated (skipped by design) or write-failed\n // (data dir unwritable) — voteRecordNote carries the actionable reason. Makes\n // a previously WARN-only skip visible to MCP callers.\n voteRecordPersisted: z.boolean().optional(),\n voteRecordNote: z.string().max(500).optional(),\n // #5130: the persisted record's id, so the caller-commits script can name it.\n voteRecordId: z.string().max(200).optional(),\n // #3587: set when the panel DEGRADED (some voters errored), so the decision\n // rests on fewer voters than requested. Part of the response since #3587 but\n // omitted from this schema until #4032 — its absence made a strict MCP client\n // reject any degraded-panel vote (`-32602 additional properties`).\n panelWarning: z.string().optional(),\n // #6115: distinct answering models and seats that answered elsewhere than\n // assigned. Always on the response (explicit zeros); optional here only\n // because the async `pending` envelope shares this schema.\n panelDiversity: z\n .object({\n distinctModels: z.number().int().nonnegative(),\n // #6606: distinct vendor families among the answering seats, and the\n // answering seats whose model names no recognised vendor.\n distinctFamilies: z.number().int().nonnegative(),\n unclassifiedSeats: z.number().int().nonnegative(),\n // #6660: answering seats whose model never resolved. Always set by\n // panelDiversityOf; optional so the published schema widens additively.\n unresolvedSeats: z.number().int().nonnegative().optional(),\n fallbacks: z.number().int().nonnegative(),\n })\n .optional(),\n // #3855: per-decision cost rollup. Same omission as panelWarning (#4032) — it\n // is present on the response whenever cost recording succeeds (common in `api`\n // billing mode). Shared schema lives with the type (single source of truth).\n costSummary: DecisionCostSummarySchema.optional(),\n // #4472: declared-option outcome. Present whenever the proposal declared\n // `options`. `unattributedApprovals` is part of the contract, not telemetry:\n // without it a caller cannot tell a real split from unreadable responses.\n optionOutcome: z\n .object({\n tally: z.array(z.object({ option: z.string(), count: z.number().int().nonnegative() })),\n leadingOption: z.string().optional(),\n leadingShare: z.number().min(0).max(1),\n approverCount: z.number().int().nonnegative(),\n selectedCount: z.number().int().nonnegative(),\n unattributedApprovals: z.number().int().nonnegative(),\n thresholdMet: z.boolean(),\n // #4529: present only on a veto. Declared here because a strict MCP\n // client rejects any property the advertised schema omits — the same\n // drift that made degraded-panel votes unusable before #4032.\n vetoReason: z.string().max(400).optional(),\n })\n .optional(),\n};\n\n/** Advertised MCP input schema for consensus_vote (hoisted to keep the register fn within its line budget). */\n/**\n * The schema advertised to MCP clients.\n *\n * Registered from {@link ConsensusVoteInputSchema}'s shape rather than\n * hand-copied. A subset drifts: `options` shipped internally in #4494 and was\n * unreachable through the tool until someone noticed, and `mode` stayed\n * unadvertised while this tool's own description told callers to pass it —\n * so the documented async path could not be invoked at all (#4969).\n */\nexport const CONSENSUS_VOTE_TOOL_SCHEMA = ConsensusVoteInputSchema.shape;\n\n/** Advertised MCP tool description for consensus_vote. */\nconst CONSENSUS_VOTE_DESCRIPTION =\n 'Execute multi-model consensus voting on a proposal. ' +\n 'Uses 7 roles by default (architect, security, devex, ai_ml, pm, catfish, scope_steward) ' +\n 'or 3 with quickMode (architect, security, scope_steward), voting with configurable strategies. ' +\n 'higher_order does NOT decide the verdict by correlation-aware aggregation (#4701): approve/reject ' +\n 'is a simple tally of the panel, so correlated voters each carry full independent weight. The ' +\n 'Bayesian correlation analysis is computed and feeds contrarian escalation only. Choose it for the ' +\n 'escalation behaviour, not for a weighted verdict. ' +\n \"Supports async dispatch (dispatch: 'async'; `mode` is a deprecated alias) — returns a jobId to poll via get_job_result. \" +\n 'Pass ratifies=<subject> to bind an authority-ladder ratification vote into its authentic record, ' +\n 'and ratifiesPr={pr, headSha} to bind a governor-path PR ratification to the head the panel saw (#5130); ' +\n 'the result carries voteRecordId for the caller-commits append. ' +\n 'If your proposal asks voters to choose among named alternatives, you MUST pass them in ' +\n '`options` (#4472) — the threshold is then measured over WHICH option won, and the record ' +\n 'carries the per-option tally plus selection coverage. WITHOUT `options` the tally is ' +\n 'approve/reject/abstain only, so every voter who engages returns `approve` and a 6-1 split on ' +\n 'which option persists as 7-0, 100% (#4452).';\n\n/**\n * Registers the consensus_vote tool with the MCP server.\n * Uses createSecureHandler (Issue #531) with timeout protection (Issue #271).\n * @category MCP\n */\nexport function registerConsensusVoteTool(server: McpServer, deps: ConsensusVoteDeps): void {\n const logger = deps.logger ?? createLogger({ tool: 'consensus_vote' });\n const notifier = deps.notifier ?? createMcpNotifier(server);\n const depsWithNotifier = { ...deps, notifier };\n\n const secureHandler = createSecureHandler(createConsensusVoteHandler(depsWithNotifier), {\n toolName: 'consensus_vote',\n rateLimiter: deps.rateLimiter,\n logger,\n });\n\n const timeoutMs = getToolTimeout('consensus_vote', deps.security);\n const wrappedHandler = wrapToolWithTimeout('consensus_vote', secureHandler, {\n timeoutMs,\n logger,\n });\n\n registerStructuredTool(\n server,\n 'consensus_vote',\n {\n description: CONSENSUS_VOTE_DESCRIPTION,\n inputSchema: CONSENSUS_VOTE_TOOL_SCHEMA,\n outputSchema: CONSENSUS_VOTE_OUTPUT_SCHEMA,\n annotations: getToolAnnotations('consensus_vote'),\n },\n toSdkCallbackWithTimeoutCheck(wrappedHandler, 'consensus_vote', timeoutMs, logger)\n );\n logger.info('Registered consensus_vote tool with secure handler and timeout protection');\n}\n","/**\n * The one async-dispatch input every async-capable MCP tool composes (#4968).\n *\n * Ten tools dispatch through `runAsJob`, and before this module they did not\n * agree on what the switch was called: `mode` on three (`consensus_vote`,\n * `run_workflow`, `orchestrate`), `dispatch` on seven. Because the advertised\n * schemas strip unknown keys, the WRONG spelling was silently ignored — a\n * caller sending `consensus_vote { dispatch: 'async' }` got a 97-second\n * synchronous run and no jobId. Panel decision (quick panel, 3 of 3): `dispatch`\n * is canonical everywhere, `mode` is accepted as a deprecated alias on the three\n * that had it (removal is next-major, #6225), and the wrong key is rejected\n * instead of dropped.\n *\n * Where the wrong-key rejection has to live. The MCP SDK builds\n * `z.object(inputSchema)` from the ADVERTISED shape and hands the handler the\n * parsed, already-stripped object (`validateToolInput` in\n * `@modelcontextprotocol/sdk/server/mcp.js`). So neither a `.refine()` on the\n * tool's internal schema nor a `z.preprocess` in the handler can see a key the\n * SDK removed — either would be a check that cannot fire on the real path\n * while passing every unit test that calls the handler directly. The only\n * schema element that sees the raw value of `mode` is a `mode` entry in the\n * advertised shape itself; {@link REJECTED_MODE_KEY} is that entry. It is the\n * \"declare the forbidden key with a never-type carrying the message\" form the\n * panel's architect seat named.\n *\n * @module mcp/tools/async-dispatch-input\n */\n\nimport { z } from 'zod';\n\n/** The two dispatch values. `undefined` is treated as `'sync'` by every handler. */\nexport const DISPATCH_MODES = ['sync', 'async'] as const;\n\nexport type DispatchMode = (typeof DISPATCH_MODES)[number];\n\n/** The enum both field builders return. */\nexport type DispatchEnum = z.ZodEnum<{ readonly sync: 'sync'; readonly async: 'async' }>;\n\n/** The type of {@link REJECTED_MODE_KEY}: absent is fine, any value is an error. */\nexport type RejectedModeKey = z.ZodOptional<z.ZodNever>;\n\n/** Next-major issue that removes the deprecated `mode` alias. */\nexport const MODE_ALIAS_REMOVAL_ISSUE = '#6225';\n\nconst DISPATCH_DESCRIPTION =\n \"Async dispatch (#4968). 'sync' (default): run inline and return the result. \" +\n \"'async': return { status: 'pending', jobId } immediately and run in the background; \" +\n 'poll get_job_result({ jobId }).';\n\n/** Error a wrong-key `mode: 'sync' | 'async'` produces on a tool whose switch is `dispatch`. */\nexport const WRONG_KEY_MODE_MESSAGE =\n '`mode` is not the async switch on this tool; send `dispatch: \"async\"` (or \"sync\") instead (#4968).';\n\n/** Error when a deprecated-`mode` tool receives both keys with different values. */\nexport function dispatchModeConflictMessage(dispatch: DispatchMode, mode: DispatchMode): string {\n return (\n `\\`dispatch: \"${dispatch}\"\\` and \\`mode: \"${mode}\"\\` disagree; send only \\`dispatch\\` ` +\n `(\\`mode\\` is a deprecated alias, removed in ${MODE_ALIAS_REMOVAL_ISSUE}).`\n );\n}\n\nfunction describeDispatch(note: string | undefined): string {\n return note === undefined ? DISPATCH_DESCRIPTION : `${DISPATCH_DESCRIPTION} ${note}`;\n}\n\n/**\n * The canonical field, optional: the parsed value is `undefined` when the\n * caller omits it. Tools whose parsed type materialises the default use\n * {@link dispatchFieldDefaultSync} instead — same enum, same description.\n *\n * @param note - Tool-specific suffix, e.g. \"Ignored for dryRun.\"\n */\nexport function dispatchField(note?: string): z.ZodOptional<DispatchEnum> {\n return z.enum(DISPATCH_MODES).optional().describe(describeDispatch(note));\n}\n\n/** {@link dispatchField} with `'sync'` materialised as the parsed default. */\nexport function dispatchFieldDefaultSync(note?: string): z.ZodDefault<DispatchEnum> {\n return z.enum(DISPATCH_MODES).default('sync').describe(describeDispatch(note));\n}\n\n/**\n * Advertised-shape entry for tools that have NO `mode` of their own. Any value\n * is rejected — `z.never` — with {@link WRONG_KEY_MODE_MESSAGE}, so the trap\n * the issue describes (`mode: 'async'` silently dropped, synchronous run)\n * fails loudly at the SDK's input validation. Absent is fine: `.optional()`.\n *\n * `run_dev_pipeline` cannot use this because its `mode` is a real field\n * (`'autonomous' | 'harness'`); it keeps its enum and routes the trap values\n * through {@link modeEnumErrorNamingDispatch}.\n */\nexport const REJECTED_MODE_KEY: RejectedModeKey = z\n .never({ error: WRONG_KEY_MODE_MESSAGE })\n .optional()\n .describe(\n \"Not an input of this tool. The async switch is `dispatch`; `mode: 'async'` is rejected (#4968).\"\n );\n\n/** Shape fragment for the `dispatch`-only tools: canonical field + wrong-key trap. */\nexport function asyncDispatchInput(note?: string): {\n dispatch: z.ZodOptional<DispatchEnum>;\n mode: RejectedModeKey;\n} {\n return { dispatch: dispatchField(note), mode: REJECTED_MODE_KEY };\n}\n\n/** {@link asyncDispatchInput} for tools whose parsed `dispatch` defaults to `'sync'`. */\nexport function asyncDispatchInputDefaultSync(note?: string): {\n dispatch: z.ZodDefault<DispatchEnum>;\n mode: RejectedModeKey;\n} {\n return { dispatch: dispatchFieldDefaultSync(note), mode: REJECTED_MODE_KEY };\n}\n\n/** Shape of the issue Zod hands an enum's `error` function; only `input` is read. */\ninterface EnumIssueInput {\n readonly input?: unknown;\n}\n\n/**\n * `error` function for a tool whose `mode` is a REAL enum with other values\n * (`run_dev_pipeline`). A trap value (`'sync' | 'async'`) gets\n * {@link WRONG_KEY_MODE_MESSAGE}; any other wrong value keeps Zod's own\n * \"expected one of …\" message (returning `undefined` defers to it).\n */\nexport function modeEnumErrorNamingDispatch(issue: EnumIssueInput): string | undefined {\n return isDispatchMode(issue.input) ? WRONG_KEY_MODE_MESSAGE : undefined;\n}\n\nfunction isDispatchMode(value: unknown): value is DispatchMode {\n return value === 'sync' || value === 'async';\n}\n\n/**\n * Shape fragment for the three tools that spelled the switch `mode`: the\n * canonical `dispatch` plus `mode` as a deprecated alias. Compose it into the\n * object AND apply {@link refineDispatchModeAgreement} on the object so a call\n * carrying both with different values is a validation error rather than a\n * silent precedence choice.\n */\nexport const DEPRECATED_MODE_ALIAS_INPUT = {\n dispatch: dispatchField(),\n mode: z\n .enum(DISPATCH_MODES)\n .optional()\n .describe(\n `DEPRECATED alias of \\`dispatch\\` (removed in the next major, ${MODE_ALIAS_REMOVAL_ISSUE}). ` +\n 'Send `dispatch` instead; a call that sends only `mode` still works and returns a deprecation warning.'\n ),\n};\n\n/** The parsed keys the resolution helpers read. */\nexport interface DispatchAliasInput {\n readonly dispatch?: DispatchMode | undefined;\n readonly mode?: DispatchMode | undefined;\n}\n\n/**\n * `superRefine` callback for a deprecated-`mode` tool's object schema: both\n * keys present with different values is an error naming both. Same value\n * twice is allowed (harmless redundancy).\n */\nexport function refineDispatchModeAgreement(value: DispatchAliasInput, ctx: z.RefinementCtx): void {\n if (value.dispatch === undefined || value.mode === undefined) return;\n if (value.dispatch === value.mode) return;\n ctx.addIssue({\n code: 'custom',\n path: ['dispatch'],\n message: dispatchModeConflictMessage(value.dispatch, value.mode),\n });\n}\n\n/**\n * The effective dispatch value on a deprecated-`mode` tool: `dispatch` wins,\n * `mode` fills in when `dispatch` is absent. The conflict case never reaches\n * here — {@link refineDispatchModeAgreement} rejects it at parse.\n */\nexport function resolveDispatch(input: DispatchAliasInput): DispatchMode | undefined {\n return input.dispatch ?? input.mode;\n}\n\n/**\n * The deprecation warning a deprecated-`mode` tool attaches when the caller\n * sent `mode` and not `dispatch`; `undefined` otherwise (nothing to warn about\n * when `dispatch` is present, whatever `mode` says).\n */\nexport function deprecatedModeWarning(input: DispatchAliasInput): string | undefined {\n if (input.mode === undefined || input.dispatch !== undefined) return undefined;\n return (\n `\\`mode: \"${input.mode}\"\\` is deprecated; send \\`dispatch: \"${input.mode}\"\\`. ` +\n `\\`mode\\` is removed in the next major (${MODE_ALIAS_REMOVAL_ISSUE}).`\n );\n}\n\n/**\n * `_meta` key carrying caller-facing warnings on a tool result (#4968).\n *\n * `_meta` is the result envelope's out-of-band channel — the error envelope\n * (`nexus-agents/error`, #2649) and the build stamp (`nexus-agents/build`,\n * #5008) already ride there, because `structuredContent` is validated against\n * each tool's `outputSchema` and `content[].text` is the payload. The value is\n * a `string[]`; absent when there is nothing to warn about.\n */\nexport const WARNINGS_META_KEY = 'nexus-agents/warnings';\n\n/** Result envelopes the warning helper can decorate: anything carrying `_meta`. */\nexport interface HasMeta {\n _meta?: Record<string, unknown>;\n}\n\n/**\n * Attach caller-facing warnings to a result under {@link WARNINGS_META_KEY},\n * preserving any `_meta` the tool already set (the async pending envelope\n * carries none; a structured error carries the error envelope). A missing or\n * empty warning list returns the result unchanged, so the key is present only\n * when it says something.\n */\nexport function withWarnings<T extends HasMeta>(\n result: T,\n warnings: readonly (string | undefined)[]\n): T {\n const present = warnings.filter((w): w is string => w !== undefined);\n if (present.length === 0) return result;\n const existing = result._meta?.[WARNINGS_META_KEY];\n const prior = Array.isArray(existing) ? existing.filter((w) => typeof w === 'string') : [];\n return { ...result, _meta: { ...result._meta, [WARNINGS_META_KEY]: [...prior, ...present] } };\n}\n","/**\n * nexus-agents/cli - Voter role configuration\n *\n * Which seats sit on a consensus panel, what each is told to evaluate, and\n * which subset the quick panel runs. Extracted from `cli/vote-types.ts` and\n * `mcp/tools/consensus-vote.ts` (#6000 step 1): a single edit here changes who\n * decides a vote, so the configuration lives apart from the routine result\n * types it used to share a file with. `vote-types.ts` re-exports the role\n * type and descriptions, so the public API is unchanged.\n *\n * @module cli/voter-roles\n */\n\n/**\n * Voter agent role definitions.\n *\n * `scope_steward` (#2185) was added 2026-04-25 to address a build-vs-buy\n * blind spot in the original 6-role panel: the panel approved a proposal\n * to build a USB-flasher CLI without flagging that Rufus already solves\n * the problem. The scope-steward role explicitly checks for existing tools\n * + biases toward \"don't build.\"\n */\nexport type VoterRole =\n 'architect' | 'security' | 'devex' | 'ai_ml' | 'pm' | 'catfish' | 'scope_steward';\n\n/**\n * Agent role descriptions for prompt generation.\n */\nexport const VOTER_ROLES: Record<VoterRole, string> = {\n architect: 'Software Architect - evaluates technical design, scalability, and maintainability',\n security:\n 'Security Engineer - evaluates security implications, vulnerabilities, and attack vectors',\n devex: 'Developer Experience - evaluates usability, documentation, and developer workflow',\n ai_ml: 'AI/ML Engineer - evaluates AI/ML aspects, model selection, and learning capabilities',\n pm: 'Product Manager - evaluates business value, user impact, and resource allocation',\n catfish:\n 'Contrarian Analyst - deliberately challenges proposals to prevent agreement bias (arXiv:2505.21503)',\n scope_steward:\n 'Scope Steward - asks whether to build at all; checks existing tools, biases toward kill-the-feature (#2185)',\n};\n\n/**\n * The seats a `consensus_vote` panel runs, by mode.\n *\n * Moved verbatim from `mcp/tools/consensus-vote.ts` (#6000 step 1): the panel\n * composition decides whether the contrarian is present, which the\n * `absolute_quorum` verdict depends on.\n */\nexport function getVoterRoles(quickMode: boolean): readonly VoterRole[] {\n // Default panel expanded to 7 roles 2026-04-25 — scope_steward added to\n // catch build-vs-buy blind spots (#2185). QuickMode substitutes\n // scope_steward for pm so fast triage covers existence-justification.\n return quickMode\n ? ['architect', 'security', 'scope_steward']\n : ['architect', 'security', 'devex', 'ai_ml', 'pm', 'catfish', 'scope_steward'];\n}\n","/**\n * nexus-agents/consensus/decision - Strategy resolution\n *\n * Which bar a `consensus_vote` call is measured against, and which error\n * policy it runs under when the caller named none. Extracted verbatim from\n * `mcp/tools/consensus-vote.ts` and `mcp/tools/consensus-vote-types.ts`\n * (#6000 step 1): `resolveStrategy` is where `strategy` silently discarded\n * `threshold` (#5315), so the resolution lives in a module that can be\n * governed on its own path. The types it reads stay in the MCP tool module —\n * they are imported type-only, so this module has no runtime edge into\n * `mcp/`.\n *\n * @module consensus/decision/strategy\n */\n\nimport type {\n ConsensusVoteInput,\n ErrorPolicy,\n VotingStrategy,\n} from '../../mcp/tools/consensus-vote-types.js';\nimport type { ConsensusAlgorithm } from '../types-core.js';\n\n// --- Strategy Resolution ---\nexport function resolveStrategy(input: ConsensusVoteInput): VotingStrategy {\n if (input.strategy !== undefined) return input.strategy;\n if (input.threshold !== undefined) {\n switch (input.threshold) {\n case 'majority':\n return 'simple_majority';\n case 'supermajority':\n return 'supermajority';\n case 'unanimous':\n return 'unanimous';\n }\n }\n return 'simple_majority';\n}\n\nexport function strategyToAlgorithm(strategy: VotingStrategy): ConsensusAlgorithm {\n if (strategy === 'higher_order') return 'higher_order';\n if (strategy === 'opinion_wise') return 'opinion_wise';\n return strategy;\n}\n\n/**\n * Default error policy per voting strategy.\n *\n * Only `unanimous` defaults to `fail_closed`: a missing/errored voter genuinely\n * breaks the unanimity guarantee, so the vote must void. Every other strategy —\n * including `higher_order` and its `opinion_wise` alias — defaults to\n * `reduce_denominator`: Bayesian/weighted aggregation over the *non-error*\n * voters is well-defined, so a single infra timeout (e.g. one slow voter's\n * adapter transport, #3304) should NOT fail-close an otherwise-unanimous result\n * (#3138). The >50% `ERROR_FLOOR_FRACTION` hard floor still voids any vote where\n * most voters errored. Callers can override via the `errorPolicy` input.\n */\nexport function getDefaultErrorPolicy(strategy: VotingStrategy): ErrorPolicy {\n if (strategy === 'unanimous') {\n return 'fail_closed';\n }\n return 'reduce_denominator';\n}\n","/**\n * nexus-agents/cli — per-role voter model overrides (#4055).\n *\n * Voters round-robin across the gateway's discovered models (#4040), so a role can\n * land on a model that fails on a particular gateway (e.g. a bodyless HTTP 400 for\n * specific model ids — #4049). This lets an operator PIN a known-good gateway model\n * for a role:\n *\n * NEXUS_VOTER_MODEL_<ROLE>=<bare gateway model id>\n * e.g. NEXUS_VOTER_MODEL_ARCHITECT=claude_4_5_opus\n *\n * The override is validated against the discovered gateway catalog: an id that is\n * NOT a live gateway model warns and falls back to round-robin for that role (no\n * hard failure). Roles without an override round-robin unchanged.\n *\n * @module cli/voter-model-overrides\n */\n\nimport type { ILogger, IModelAdapter } from '../core/index.js';\nimport type { VoterRole } from './vote-types.js';\n\n/** Env var name for a role's voter-model override (e.g. role `ai_ml` → `NEXUS_VOTER_MODEL_AI_ML`). */\nexport function voterModelOverrideEnvKey(role: VoterRole): string {\n return `NEXUS_VOTER_MODEL_${role.toUpperCase()}`;\n}\n\n/**\n * Resolve per-role gateway-model overrides from the environment, validated against\n * the discovered gateway adapters. Returns a map of ONLY the roles that have a\n * valid override (matched to a live gateway model by `modelId`); roles with no\n * override, or an override id not in the catalog, are omitted (and the latter is\n * warned) so the caller round-robins them as usual.\n *\n * Matching is exact on `modelId` first, then case-insensitive as a convenience.\n */\nexport function resolveVoterModelOverrides(\n roles: readonly VoterRole[],\n gatewayAdapters: readonly IModelAdapter[],\n logger: ILogger\n): Map<VoterRole, IModelAdapter> {\n const overrides = new Map<VoterRole, IModelAdapter>();\n if (gatewayAdapters.length === 0) return overrides;\n\n const byId = new Map<string, IModelAdapter>();\n for (const adapter of gatewayAdapters) byId.set(adapter.modelId, adapter);\n\n for (const role of roles) {\n const envKey = voterModelOverrideEnvKey(role);\n const raw = process.env[envKey];\n if (raw === undefined || raw.trim() === '') continue;\n const requested = raw.trim();\n\n const adapter =\n byId.get(requested) ??\n gatewayAdapters.find((a) => a.modelId.toLowerCase() === requested.toLowerCase());\n\n if (adapter === undefined) {\n logger.warn(\n `Voter model override ${envKey}=\"${requested}\" is not a discovered gateway model — ` +\n `falling back to round-robin for role \"${role}\".`,\n { role, requested, available: [...byId.keys()] }\n );\n continue;\n }\n overrides.set(role, adapter);\n }\n\n if (overrides.size > 0) {\n logger.info('Applied per-role voter model overrides (#4055)', {\n overrides: Object.fromEntries([...overrides].map(([r, a]) => [r, a.modelId])),\n });\n }\n return overrides;\n}\n","/**\n * Which CLIs may serve a voter seat (#6962).\n *\n * Every voter seat asks for read-only analysis (#6754). The CLI path deals\n * seats round-robin over the detected CLIs, so a CLI that cannot enforce that\n * mode got seats anyway, and each one refused: once agy (the gemini slot)\n * stopped declaring the mode, the security and catfish seats of the default\n * 7-seat panel errored on every vote. Dealing only over CLIs that declare the\n * mode keeps the panel whole; the families present are whatever CLIs remain.\n *\n * @module cli/voter-cli-access\n */\n\nimport type { ExecutionAccessMode } from '../core/index.js';\nimport { adapterEnforces } from '../cli-adapters/access-mode.js';\nimport { createCliAdapter } from '../cli-adapters/factory.js';\nimport type { CliName, ICliAdapter } from '../cli-adapters/types.js';\n\n/** The access mode every voter seat runs in (#6754). */\nexport const VOTER_ACCESS_MODE = 'read-only-analysis' satisfies ExecutionAccessMode;\n\n/** The adapter declarations the filter reads. */\ntype AccessDeclarations = Pick<ICliAdapter, 'enforcesReadOnlyAnalysis' | 'enforcesWorkspaceEdit'>;\n\n/** The CLIs that may serve a voter seat, and the ones dropped for not enforcing its mode. */\nexport interface VoterCliAccess {\n readonly serving: CliName[];\n readonly refused: CliName[];\n}\n\n/**\n * Split `clis` into those whose adapter declares {@link VOTER_ACCESS_MODE} and\n * those that do not, preserving order. Only the declaration is read; the\n * adapter is never run. `declarationsFor` is injectable for tests.\n */\nexport function clisServingVoterSeats(\n clis: readonly CliName[],\n declarationsFor: (cli: CliName) => AccessDeclarations = (cli) => createCliAdapter({ cli })\n): VoterCliAccess {\n const serving: CliName[] = [];\n const refused: CliName[] = [];\n for (const cli of clis) {\n const enforces = adapterEnforces(declarationsFor(cli), { accessMode: VOTER_ACCESS_MODE });\n (enforces ? serving : refused).push(cli);\n }\n return { serving, refused };\n}\n","/**\n * Reporting for consensus-panel model independence (#4983).\n *\n * Split from `voter-agents` so the verdict-to-log rendering is testable\n * without standing up a vote, and so the two call sites — assignment time and\n * after the votes are in — render the same verdict the same way.\n *\n * @module cli/panel-independence\n */\n\nimport type { ILogger, IModelAdapter } from '../core/index.js';\nimport { assessPanelIndependence } from '../config/model-equivalence.js';\nimport type { PanelIndependence } from '../config/model-equivalence.js';\nimport type { AgentVoteResult } from './vote-types.js';\n\n/**\n * When the check runs. Adapter detection is lazy (#811), so at `assignment`\n * every CLI adapter still reports a placeholder and an unmeasured verdict is\n * expected. By `post-vote` each has resolved, so unmeasured means the panel\n * finished without anyone being able to say whether its members were\n * independent — which is worth a warning.\n */\nexport type PanelCheckPhase = 'assignment' | 'post-vote';\n\n/**\n * Classifies the panel from its adapters' model ids and logs the verdict.\n *\n * A single-role panel cannot correlate with itself, so nothing is reported.\n */\nexport function reportPanelIndependence(\n adapters: readonly IModelAdapter[],\n roleCount: number,\n phase: PanelCheckPhase,\n logger: ILogger\n): void {\n reportPanelModelIndependence(\n adapters.map((adapter) => adapter.modelId),\n roleCount,\n phase,\n logger\n );\n}\n\n/** Reports independence from the models that successfully returned votes. */\nexport function reportVoteIndependence(results: readonly AgentVoteResult[], logger: ILogger): void {\n const successful = results.filter((result) => result.source === 'llm');\n reportPanelModelIndependence(\n successful.map((result) => result.model),\n successful.length,\n 'post-vote',\n logger\n );\n}\n\n/** Classifies and reports panel independence from observed model provenance. */\nfunction reportPanelModelIndependence(\n modelIds: readonly (string | undefined)[],\n roleCount: number,\n phase: PanelCheckPhase,\n logger: ILogger\n): void {\n if (roleCount <= 1) return;\n const verdict: PanelIndependence = assessPanelIndependence(modelIds);\n\n if (verdict.kind === 'collapsed') {\n logger.warn('Consensus panel ran on ONE model — votes may correlate', {\n model: verdict.model,\n roleCount,\n phase,\n });\n return;\n }\n if (verdict.kind === 'diverse') {\n logger.debug('Consensus panel spans distinct models', {\n distinctModels: verdict.distinct,\n roleCount,\n phase,\n });\n return;\n }\n const context = { unresolved: verdict.unresolved, total: verdict.total, roleCount };\n if (phase === 'post-vote') {\n logger.warn(\n 'Panel independence UNMEASURED after voting — cannot say whether votes correlate',\n context\n );\n return;\n }\n logger.debug(\n 'Panel independence not yet measurable (adapters have not detected their model)',\n context\n );\n}\n","/**\n * Family-first seat dealing for gateway voter panels (#6606).\n *\n * Seats used to be dealt round-robin over the gateway's LISTING order, so the\n * first N chat models took the panel. On a recorded three-family catalogue that\n * put 5 OpenAI, 2 Anthropic and 0 Google models on a 7-seat panel — listing\n * order is a property of the gateway, not of the models, and it decided how\n * independent the panel was.\n *\n * This deals each seat to the model FAMILY (vendor: Anthropic, OpenAI, Google,\n * ...) with the fewest seats so far, then to the least-used model inside that\n * family, best-ranked first (#6634). Seats already taken — operator pins — seed the counts, so the dealt\n * seats balance around them. Every tie is broken by a fixed order, so the\n * result does not depend on the order the gateway lists its models in.\n *\n * @module cli/voter-family-dealing\n */\n\nimport type { ILogger } from '../core/index.js';\nimport { canonicalModelKey, countDistinctModels } from '../config/model-equivalence.js';\nimport { resolveModelIdentitySync, type ModelVendor } from '../config/model-identity.js';\nimport { rankFamilyModels } from '../adapters/gateway-family-ranking.js';\nimport { createdOf } from '../adapters/gateway-family-slots.js';\n\n/**\n * The family a model belongs to for panel dealing and diversity counting: its\n * vendor, from the canonical identity parser. `unknown` when the id names no\n * recognised vendor.\n */\nexport function vendorFamilyOf(modelId: string): ModelVendor {\n return resolveModelIdentitySync(modelId).vendor;\n}\n\n/**\n * Tie-break order between families holding equally many seats. The three\n * gateway families come first in a fixed order; other recognised vendors\n * follow alphabetically; `unknown` is always last, as its own group.\n */\nconst FAMILY_PRIORITY: readonly ModelVendor[] = ['anthropic', 'openai', 'google'];\n\nfunction compareFamilies(a: ModelVendor, b: ModelVendor): number {\n const rank = (f: ModelVendor): number => {\n if (f === 'unknown') return Number.MAX_SAFE_INTEGER;\n const i = FAMILY_PRIORITY.indexOf(f);\n return i === -1 ? FAMILY_PRIORITY.length : i;\n };\n return rank(a) - rank(b) || a.localeCompare(b);\n}\n\n/**\n * Default within-family order (#6634): #6623's `rankFamilyModels`, best-first:\n * tier, then the discovery `created` stamp each candidate carries (used only\n * when every model of the family has one), then the id's generation, with the\n * id as the last tie-break. The ranking is total over the ids, so the order\n * does not depend on the order the gateway lists its models in.\n */\nfunction rankedOrder(candidates: readonly { readonly modelId: string }[]): readonly string[] {\n return rankFamilyModels(candidates.map((c) => ({ id: c.modelId, created: createdOf(c) })));\n}\n\ninterface DealOptions {\n /** Model ids already seated (pins); they seed the family and model counts. */\n readonly seated?: readonly string[];\n /** Orders one family's model ids best-first. Defaults to #6623's family ranking. */\n readonly rankWithinFamily?: (modelIds: readonly string[]) => readonly string[];\n}\n\n/** Identity key for \"same model\": canonical when resolvable, raw otherwise (#4390). */\nfunction identityKey(modelId: string): string {\n return canonicalModelKey(modelId) ?? `raw:${modelId}`;\n}\n\nfunction increment(counts: Map<string, number>, key: string): void {\n counts.set(key, (counts.get(key) ?? 0) + 1);\n}\n\n/** Groups candidates by family, each family ordered by the ranking seam. */\nfunction groupByFamily<T extends { readonly modelId: string }>(\n candidates: readonly T[],\n rank: (familyCandidates: readonly T[]) => readonly string[]\n): Map<ModelVendor, T[]> {\n const byFamily = new Map<ModelVendor, T[]>();\n for (const c of candidates) {\n const family = vendorFamilyOf(c.modelId);\n const list = byFamily.get(family) ?? [];\n list.push(c);\n byFamily.set(family, list);\n }\n for (const [family, list] of byFamily) {\n const order = rank(list);\n const position = (c: T): number => {\n const i = order.indexOf(c.modelId);\n return i === -1 ? order.length : i;\n };\n // Ties (an id the ranker dropped, or a duplicate id) fall back to lexical.\n byFamily.set(\n family,\n [...list].sort((a, b) => position(a) - position(b) || a.modelId.localeCompare(b.modelId))\n );\n }\n return byFamily;\n}\n\n/** The family with the fewest seats; ties by {@link compareFamilies}. */\nfunction leastSeatedFamily(\n families: readonly ModelVendor[],\n seats: Map<string, number>\n): ModelVendor {\n let best = families[0] as ModelVendor;\n for (const f of families.slice(1)) {\n const diff = (seats.get(f) ?? 0) - (seats.get(best) ?? 0);\n if (diff < 0 || (diff === 0 && compareFamilies(f, best) < 0)) best = f;\n }\n return best;\n}\n\n/**\n * Within a family: the model whose IDENTITY is least seated, then the model id\n * least seated, then rank order. Identity first, so two strings for one model\n * (`gpt-4o`, `openai/gpt-4o`) do not both take seats while a different model\n * sits idle.\n */\nfunction leastSeatedModel<T extends { readonly modelId: string }>(\n ranked: readonly T[],\n identitySeats: Map<string, number>,\n idSeats: Map<string, number>\n): T {\n let best = ranked[0] as T;\n const score = (c: T): [number, number] => [\n identitySeats.get(identityKey(c.modelId)) ?? 0,\n idSeats.get(c.modelId) ?? 0,\n ];\n for (const c of ranked.slice(1)) {\n const [ci, cm] = score(c);\n const [bi, bm] = score(best);\n if (ci < bi || (ci === bi && cm < bm)) best = c;\n }\n return best;\n}\n\n/**\n * Deal `seatCount` seats over `candidates`, families first. Returns one\n * candidate per seat, in seat order. Zero seats or zero candidates deal\n * nothing — an empty array, which the caller must treat as \"no assignment\".\n */\nexport function dealSeatsAcrossFamilies<T extends { readonly modelId: string }>(\n seatCount: number,\n candidates: readonly T[],\n options: DealOptions = {}\n): T[] {\n if (seatCount <= 0 || candidates.length === 0) return [];\n const custom = options.rankWithinFamily;\n const rank = (list: readonly T[]): readonly string[] =>\n custom === undefined ? rankedOrder(list) : custom(list.map((c) => c.modelId));\n const byFamily = groupByFamily(candidates, rank);\n const families = [...byFamily.keys()].sort(compareFamilies);\n\n const familySeats = new Map<string, number>();\n const identitySeats = new Map<string, number>();\n const idSeats = new Map<string, number>();\n const seat = (modelId: string): void => {\n increment(familySeats, vendorFamilyOf(modelId));\n increment(identitySeats, identityKey(modelId));\n increment(idSeats, modelId);\n };\n for (const pinned of options.seated ?? []) seat(pinned);\n\n const dealt: T[] = [];\n for (let i = 0; i < seatCount; i++) {\n const family = leastSeatedFamily(families, familySeats);\n const chosen = leastSeatedModel(byFamily.get(family) ?? [], identitySeats, idSeats);\n dealt.push(chosen);\n seat(chosen.modelId);\n }\n return dealt;\n}\n\n/**\n * #6606: a panel on several models of ONE family is still one vendor's\n * judgement. Warn when every assigned model is of the same recognised family;\n * unknown-vendor models cannot be judged either way and do not trigger it.\n */\nexport function warnIfSingleFamily(\n roleCount: number,\n assignedModels: readonly string[],\n logger: ILogger\n): void {\n const families = new Set(assignedModels.map(vendorFamilyOf));\n const [family] = families;\n if (roleCount > 1 && families.size === 1 && family !== undefined && family !== 'unknown') {\n logger.warn('Consensus panel collapsed to a single model family — votes may correlate', {\n family,\n distinctModels: countDistinctModels(assignedModels),\n roleCount,\n });\n }\n}\n","/**\n * Panel cancellation at the seat level (#6729).\n *\n * #5393 threaded `cancel_job`'s signal as far as the vote launcher, which\n * stopped LAUNCHING seats but let every seat already inside its adapter call\n * run to completion — minutes of quota after the cancel, with the job holding\n * its async concurrency slot until the slowest seat settled. These helpers\n * carry the same signal into each seat's adapter call.\n *\n * @module cli/voter-cancel\n */\nimport { raceAbort } from '../adapters/abort-utils.js';\nimport { delay } from '../utils/async-utils.js';\n\n/** The error a seat records when the panel was cancelled before or during its attempts. */\nconst SEAT_CANCELLED_MESSAGE = 'cancelled while this voter was in flight';\n\n/**\n * Read through a function (#5393): a narrowed `signal?.aborted` check is\n * unsound across an `await`, where the whole point is that it can flip.\n */\nexport function isCancelled(signal: AbortSignal | undefined): boolean {\n return signal?.aborted === true;\n}\n\n/**\n * The signal a seat's adapter call runs under: its own deadline and, when the\n * panel has one, its upstream abort (caller cancel or overall cutoff).\n * `AbortSignal.any` keeps the reason of whichever source fired — a\n * `TimeoutError` for either deadline, the caller's reason for a cancel — so\n * the adapter's classifier (#6709,\n * `isTimeoutAbortReason`) records a cancel as a cancel and a deadline as a\n * timeout.\n */\nexport function seatSignal(timeoutMs: number, cancel: AbortSignal | undefined): AbortSignal {\n const deadline = AbortSignal.timeout(timeoutMs);\n return cancel === undefined ? deadline : AbortSignal.any([deadline, cancel]);\n}\n\n/**\n * Await an adapter call unless the upstream signal aborts first. The signal is\n * also handed to the adapter, which stops its subprocess or request; this\n * covers an adapter that ignores it, so a cancelled seat is never awaited to\n * completion. Absent signal ⇒ a plain await.\n */\nexport function unlessCancelled<T>(call: Promise<T>, cancel: AbortSignal | undefined): Promise<T> {\n return raceAbort(call, cancel);\n}\n\n/** Stop retry backoff promptly when the upstream panel deadline/cancel fires. */\nexport async function waitForVoteRetry(\n delayMs: number,\n signal: AbortSignal | undefined\n): Promise<boolean> {\n try {\n await unlessCancelled(delay(delayMs), signal);\n return !isCancelled(signal);\n } catch (error: unknown) {\n if (isCancelled(signal)) return false;\n throw error;\n }\n}\n\n/** The failed-attempt result for a cancelled seat, keeping the last real error when there was one. */\nexport function cancelledSeat(lastError: string): { ok: false; error: string } {\n const error =\n lastError !== '' ? `${SEAT_CANCELLED_MESSAGE}: ${lastError}` : SEAT_CANCELLED_MESSAGE;\n return { ok: false, error };\n}\n\n/** True for an error that {@link cancelledSeat} produced, with or without a carried last error. */\nexport function isCancelledSeatError(error: string | undefined): boolean {\n return error?.startsWith(SEAT_CANCELLED_MESSAGE) === true;\n}\n","/**\n * In-memory observations for the existing decision-cost writer, not a store.\n * Response provenance/usage is frozen before parsing. Parsing classifications\n * are kept separately, then projected into one immutable event per response.\n * Snapshotting never waits for outstanding calls; later settlement cannot\n * change an earlier snapshot. Started calls without responses remain unobserved.\n */\nimport { randomUUID } from 'node:crypto';\nimport type { CompletionResponse, IModelAdapter } from '../core/index.js';\nimport type { AttemptTelemetry, VoterAttemptEvent } from '../observability/attempt-usage.js';\nimport type { AgentVoteResult, VotePromptContext, VoterRole } from './vote-types.js';\n\nexport type VoterAttemptKind = VoterAttemptEvent['attemptKind'];\ntype Observation = Omit<VoterAttemptEvent, 'outcome'>;\n\n/** Reuse the pass's collector or start a new execution chain. */\nexport function resolveAttemptCollector(context?: VotePromptContext): VoterAttemptCollector {\n return context?.attemptCollector ?? new VoterAttemptCollector();\n}\n\n/** Retry provenance follows the failed attempt's cause and retains the outer pass. */\nexport function voteRetryContext(\n context: VotePromptContext,\n attempt: number,\n parseFailed: boolean\n): VotePromptContext {\n return {\n ...context,\n attemptKind: attempt === 0 ? context.attemptKind : parseFailed ? 'parse_retry' : 'error_retry',\n withinRoleRetry: context.withinRoleRetry === true || context.attemptKind === 'role_retry',\n };\n}\nconst MAX_PROVENANCE_LENGTH = 120;\n\nfunction count(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isSafeInteger(value) && value >= 0 ? value : undefined;\n}\n\n/** Partial/placeholder/malformed input/output usage is explicitly unknown. */\nfunction responseUsage(response: CompletionResponse): VoterAttemptEvent['usage'] {\n const usage = response.usage;\n const input = count(usage?.inputTokens);\n const output = count(usage?.outputTokens);\n if (input === undefined || output === undefined || usage?.inputTokensMeasured === false)\n return Object.freeze({ kind: 'unknown' });\n return Object.freeze({ kind: 'reported', input, output, ...optionalUsageFields(usage) });\n}\n\nfunction optionalUsageFields(\n usage: CompletionResponse['usage']\n): Partial<Record<'cached' | 'reasoning' | 'cacheCreation', number>> {\n const out: Partial<Record<'cached' | 'reasoning' | 'cacheCreation', number>> = {};\n if (usage === undefined) return out;\n const fields = [\n ['cached', 'cachedInputTokens'],\n ['reasoning', 'reasoningTokens'],\n ['cacheCreation', 'cacheCreationInputTokens'],\n ] as const;\n for (const [key, field] of fields) {\n const value = count(Reflect.get(usage, field));\n if (value !== undefined) out[key] = value;\n }\n return out;\n}\n\n/** One execution chain, surviving its timeout result and raw promise settlement. */\nexport class VoterAttemptCollector {\n private observableAttempts = 0;\n private readonly observations: Observation[] = [];\n private readonly outcomes = new Map<string, 'parsed' | 'parse_failed' | 'superseded'>();\n private finalId: string | undefined;\n\n started(): void {\n this.observableAttempts++;\n }\n\n settled(\n role: VoterRole,\n adapter: IModelAdapter,\n response: CompletionResponse,\n attemptKind: VoterAttemptKind,\n withinRoleRetry?: boolean\n ): string {\n const id = randomUUID();\n const model = response.model || adapter.modelId;\n const name: unknown = Reflect.get(adapter, 'name');\n this.observations.push(\n Object.freeze({\n id,\n role,\n cli: (typeof name === 'string' && name !== '' ? name : adapter.providerId).slice(\n 0,\n MAX_PROVENANCE_LENGTH\n ),\n adapter: adapter.providerId.slice(0, MAX_PROVENANCE_LENGTH),\n ...(model !== '' && model !== 'pending-detection'\n ? { model: model.slice(0, MAX_PROVENANCE_LENGTH) }\n : {}),\n attemptKind,\n ...(withinRoleRetry === true ? { withinRoleRetry } : {}),\n usage: responseUsage(response),\n })\n );\n return id;\n }\n\n classified(id: string | undefined, outcome: 'parsed' | 'parse_failed'): void {\n if (id === undefined) return;\n this.outcomes.set(id, outcome);\n if (outcome === 'parsed') this.finalId = id;\n }\n\n discardFinal(): void {\n if (this.finalId !== undefined) this.outcomes.set(this.finalId, 'superseded');\n this.finalId = undefined;\n }\n\n snapshot(): AttemptTelemetry {\n const events = this.observations.map((event): VoterAttemptEvent => {\n const outcome =\n event.id === this.finalId ? 'final' : (this.outcomes.get(event.id) ?? 'superseded');\n return Object.freeze({ ...event, outcome });\n });\n return Object.freeze({\n events: Object.freeze(events),\n observableAttempts: this.observableAttempts,\n });\n }\n}\n\n/** Keep deadline-losing responses observable until the cost bridge reads the seat. */\nexport function withVoterAttemptTelemetry<T extends object>(\n result: T,\n snapshot: () => AttemptTelemetry\n): T & { readonly attemptTelemetry: AttemptTelemetry } {\n return Object.defineProperty({ ...result }, 'attemptTelemetry', {\n enumerable: true,\n get: snapshot,\n }) as T & { readonly attemptTelemetry: AttemptTelemetry };\n}\n\n/** Carry the replaced chain lazily, so a late response is not lost by a copy. */\nexport function carryVoterAttemptTelemetry(\n from: { readonly attemptTelemetry?: AttemptTelemetry | undefined } | undefined,\n onto: AgentVoteResult\n): AgentVoteResult {\n if (from?.attemptTelemetry === undefined && onto.attemptTelemetry === undefined) return onto;\n return withVoterAttemptTelemetry(onto, () => {\n const prior = from?.attemptTelemetry;\n const next = onto.attemptTelemetry;\n const events = [\n ...(prior?.events ?? []).map((event): VoterAttemptEvent =>\n Object.freeze({\n ...event,\n outcome: event.outcome === 'final' ? 'superseded' : event.outcome,\n })\n ),\n ...(next?.events ?? []),\n ];\n return Object.freeze({\n events: Object.freeze(events),\n observableAttempts: (prior?.observableAttempts ?? 0) + (next?.observableAttempts ?? 0),\n });\n });\n}\n\n/** Preserve late observation across result decoration, without modifying evidence. */\nexport function preserveVoterAttemptTelemetry<T extends object>(\n from: { readonly attemptTelemetry?: AttemptTelemetry | undefined },\n onto: T\n): T {\n const initial = from.attemptTelemetry;\n return initial === undefined\n ? onto\n : withVoterAttemptTelemetry(onto, () => from.attemptTelemetry ?? initial);\n}\n","/**\n * Lower-bound measurement of calls settling after the overall deadline (#6851).\n * Never-settling promises and process exit produce no event. Observing the raw\n * adapter call avoids raceAbort hiding its eventual response. No cost capture.\n */\nimport type { IModelAdapter, ILogger } from '../core/index.js';\nimport { getErrorMessage } from '../core/index.js';\nimport { isCallerAbortError } from '../cli-adapters/cli-error-helpers.js';\nimport { isCancelledSeatError } from './voter-cancel.js';\nimport { getAbortObservation } from '../adapters/abort-observation.js';\nimport { recordUsageEvent } from '../learning/usage-log.js';\nimport type { UsageMeasurement } from '../learning/usage-measurement.js';\nimport type { AgentVoteResult, VoterRole } from './vote-types.js';\n\ntype CompletionResult = Awaited<ReturnType<IModelAdapter['complete']>>;\ntype Settlement = AgentVoteResult | CompletionResult;\n\n/** Retain only reported counts; an empty usage object is absence, never zero. */\nfunction usageOf(value: object | undefined): UsageMeasurement['usage'] {\n const usage: NonNullable<UsageMeasurement['usage']> = {};\n const fields = [\n 'inputTokens',\n 'outputTokens',\n 'totalTokens',\n 'cachedInputTokens',\n 'cacheCreationInputTokens',\n ] as const;\n for (const field of fields) {\n const count: unknown = value === undefined ? undefined : Reflect.get(value, field);\n if (typeof count === 'number' && Number.isFinite(count) && count >= 0) usage[field] = count;\n }\n return Object.keys(usage).length === 0 ? undefined : usage;\n}\n\nfunction settlementFields(\n result: Settlement | undefined\n): Pick<UsageMeasurement, 'settled' | 'settledBy' | 'model' | 'usage'> {\n if (result === undefined) return { settled: 'error', settledBy: 'adapter' };\n if ('ok' in result) {\n return result.ok\n ? {\n settled: 'ok',\n settledBy: 'adapter',\n model: result.value.model,\n usage: usageOf(result.value.usage),\n }\n : { settled: 'error', settledBy: isCallerAbortError(result.error) ? 'abort' : 'adapter' };\n }\n // A voter function that settled with the seat-cancelled error ended because\n // the deadline aborted it, not because its adapter answered late.\n return {\n settled: result.source === 'error' ? 'error' : 'ok',\n settledBy:\n result.source === 'error' && isCancelledSeatError(result.error) ? 'abort' : 'adapter',\n model: result.model,\n usage: usageOf(result),\n };\n}\n\ninterface PendingCall {\n promise: Promise<CompletionResult> | undefined;\n tracked: boolean;\n}\n\nconst calls = new WeakMap<AbortSignal, PendingCall>();\n\n/** Observe the original adapter promise before cancellation can mask its result. */\nexport function trackVoterCompletion(\n call: Promise<CompletionResult>,\n signal: AbortSignal | undefined\n): Promise<CompletionResult> {\n const state = signal === undefined ? undefined : calls.get(signal);\n if (state === undefined) return call;\n state.tracked = true;\n state.promise = call;\n const clear = (): void => {\n if (state.promise === call) state.promise = undefined;\n };\n void call.then(clear, clear);\n return call;\n}\n\n/** `name` is not on IModelAdapter; only a string value may become the `cli` field. */\nfunction adapterName(adapter: IModelAdapter): string | undefined {\n const name: unknown = Reflect.get(adapter, 'name');\n return typeof name === 'string' && name !== '' ? name : undefined;\n}\n\nfunction writeMeasurement(\n adapter: IModelAdapter,\n role: VoterRole,\n reason: DOMException,\n deadlineAt: number,\n result: Settlement | undefined\n): void {\n const fields = settlementFields(result);\n const model = fields.model ?? adapter.modelId;\n recordUsageEvent({\n kind: 'measurement',\n event: 'voter_late_settlement',\n timestamp: new Date().toISOString(),\n role,\n cli: adapterName(adapter) ?? adapter.providerId,\n ...(model !== '' && model !== 'pending-detection' ? { model } : {}),\n msAfterDeadline: Math.max(0, Date.now() - deadlineAt),\n settled: fields.settled,\n settledBy: fields.settledBy,\n ...(fields.usage !== undefined ? { usage: fields.usage } : {}),\n ...getAbortObservation(reason),\n });\n}\n\n/** Register a call-scoped observer without replacing or mutating the adapter. */\nexport function observeLateVoter(\n adapter: IModelAdapter,\n role: VoterRole,\n logger: ILogger\n): {\n readonly register: (signal: AbortSignal) => void;\n readonly afterDeadline: (\n vote: Promise<AgentVoteResult>,\n reason: DOMException,\n deadlineAt: number\n ) => void;\n} {\n const state: PendingCall = { promise: undefined, tracked: false };\n return {\n register(signal): void {\n calls.set(signal, state);\n },\n afterDeadline(vote, reason, deadlineAt): void {\n // An instrumented seat in retry backoff has no call left to measure.\n if (state.tracked && state.promise === undefined) return;\n const write = (result: Settlement | undefined): void => {\n writeMeasurement(adapter, role, reason, deadlineAt, result);\n };\n // One continuation only: prefer the raw call when cancellation masks it.\n void (state.promise ?? vote)\n .then(write, () => {\n write(undefined);\n })\n .catch((error: unknown) => {\n try {\n logger.warn('Failed to persist late voter settlement measurement', {\n role,\n error: getErrorMessage(error),\n });\n } catch {\n // Even a failing logger must not reject into the process.\n }\n });\n },\n };\n}\n","/**\n * nexus-agents/cli - Voter System Prompts\n *\n * Role-specific system prompts for voter agents.\n *\n * @module cli/voter-prompts\n * (Source: Issue #226, extracted from voter-agents.ts for #272)\n */\n\nimport type { VoterRole } from './vote-types.js';\n\n/**\n * Default project name used in voter prompts when no context is provided —\n * this repository's own name. Exported so the resolver in `voter-project.ts`\n * (#6110) falls back to the same literal the prompts are snapshotted against.\n */\nexport const DEFAULT_VOTER_PROJECT = 'nexus-agents';\n\n/**\n * Where a voter is told the target project's governance rules live (#6110).\n *\n * This repository keeps them in `CLAUDE.md`, and the seven default prompts are\n * pinned byte-for-byte to that wording (`voter-prompts-project.test.ts`). A\n * consuming repository may have no such file, so a foreign target gets the\n * neutral phrase instead of a pointer at a file that may not exist.\n */\nfunction governanceRulesRef(project: string): string {\n return project === DEFAULT_VOTER_PROJECT ? 'CLAUDE.md' : \"the target project's governance rules\";\n}\n\n/**\n * Generate voter system prompts with optional project context.\n *\n * When nexus-agents MCP tools are used as a service for other projects,\n * the default \"nexus-agents project\" context causes voters to reject\n * proposals as MISALIGNED. This function allows injecting the target\n * project name so voters evaluate correctly.\n *\n * @param project - Project name/context to inject (defaults to 'nexus-agents')\n */\n/**\n * PR-review-mode addendum (#2244). Appended to every voter's prompt so the\n * format is reinforced at the system-prompt level, where role framing\n * dominates — the proposal-text-only approach in #2238 produced 0 verified\n * findings across 50 voter calls in #2241.\n *\n * The addendum is conditional on its face: voters reviewing a non-diff\n * proposal ignore it. Voters reviewing a diff get the explicit format +\n * few-shot example here, plus the same instructions in the proposal text.\n */\nfunction prReviewModeAddendum(): string {\n return `\nPR-review mode — return one JSON object with REQUIRED top-level decision, reasoning, and confidence on every verdict, including approve and abstain. decision is \"approve\", \"reject\", or \"abstain\"; reasoning is 10-4000 characters; confidence must be a number between 0 and 1 expressing your own assessment. Omitting findings never permits omitting confidence. Use this JSON envelope even if the proposal contains legacy YAML instructions.\n\nIf you are reviewing a code diff (not a proposal) AND you have at least one concrete defect that justifies blocking the merge, populate the OPTIONAL TOP-LEVEL \"findings\" field. NOT inside reasoning — top-level. Complete response examples:\n\nApprove without findings:\n\\`\\`\\`json\n{\n \"decision\": \"approve\",\n \"reasoning\": \"Read the diff and found no blocking defects. Existing tests cover the changed behavior.\",\n \"confidence\": 0.85\n}\n\\`\\`\\`\n\nReject with findings (severity may be critical, high, medium, low, or info):\n\\`\\`\\`json\n{\n\"decision\": \"reject\",\n\"reasoning\": \"The cited call path produces the concrete failure described in the finding.\",\n\"confidence\": 0.9,\n\"rejectionCategories\": [\"INSUFFICIENT_EVIDENCE\"],\n\n\"findings\": [\n {\n \"summary\": \"One-line summary\",\n \"location\": \"path/file.ext:LINE\",\n \"severity\": \"medium\",\n \"gate\": {\n \"reread_cited_line\": \"passed\",\n \"traced_call_path\": \"passed\",\n \"named_assertion\": \"Concrete failing assertion — what test would fail and how. Substantive, not 'passed'.\",\n \"ruled_out_language_non_issue\": \"passed\"\n },\n \"claim\": \"What is wrong and why it justifies blocking.\"\n }\n]\n}\n\\`\\`\\`\n\nA finding only triggers strict request_changes if its severity is medium or higher, all 4 gate fields = \"passed\" AND named_assertion is substantive (>10 chars naming a concrete failure, not just \"passed\"). Non-security low/info findings are reported but do not corroborate a verified blocker. Security-role findings are treated as at least medium. Request_changes votes still count toward soft blocking regardless of severity. Findings missing any of those gate checks surface as informational only — they do not block on their own. The 2026-04-25 audit (#2225) found a 100% false-positive rate when this gate wasn't enforced. If you're approving the diff, OMIT the findings field entirely. If reviewing a non-diff proposal, ignore this section.\n\nHistory note: an earlier prompt asked for YAML inside reasoning; that format was lossy across JSON serialization (#2245). Use the top-level JSON array above.`;\n}\n\n/** Common footer appended to all voter prompts. */\nfunction voterFooter(): string {\n return `\nWorkflow-test assessment (include in your reasoning):\n- Testability: Can changes be verified with automated tests?\n- Workflow integration: Does this fit existing CI/build/test pipelines?\n- Incremental verifiability: Can progress be measured at each step?\n\nWhen rejecting, classify your reasons using categories: YAGNI, DRY_VIOLATION, OVER_ENGINEERING, SCOPE_CREEP, SECURITY_RISK, MISALIGNED, INSUFFICIENT_EVIDENCE.\n\nIf you cannot read the artifact under review — a shell, sandbox, or repository read fails — answer \"abstain\" and begin your reasoning with \"UNVERIFIABLE: could not read the artifact\"; never vote on the description alone.\n${prReviewModeAddendum()}`;\n}\n\n/** Build the architect role prompt. */\nfunction architectPrompt(project: string): string {\n return `You are a Software Architect voting on technical proposals for the ${project} project.\n\nYour evaluation criteria:\n- Technical design quality and architectural soundness\n- Scalability and performance implications\n- Maintainability and code organization\n- Alignment with existing patterns (Result<T,E>, Zod validation, TypeScript best practices)\n- Integration complexity with current codebase\n${voterFooter()}\n\nBe direct and technical. Focus on structural implications.`;\n}\n\n/** Build the security role prompt. */\nfunction securityPrompt(project: string): string {\n return `You are a Security Engineer voting on proposals for the ${project} project.\n\nYour evaluation criteria:\n- Security vulnerabilities and attack vectors (OWASP Top 10)\n- Input validation and sanitization\n- Secrets management and credential handling\n- Path traversal and injection prevention\n- Rate limiting and resource exhaustion\n${voterFooter()}\n\nBe thorough about risks. Flag any security concerns.`;\n}\n\n/** Build the devex role prompt. */\nfunction devexPrompt(project: string): string {\n return `You are a Developer Experience Engineer voting on proposals for the ${project} project.\n\nYour evaluation criteria:\n- API usability and ergonomics\n- Documentation clarity and completeness\n- Learning curve for new developers\n- Testing and debugging experience\n- CLI/tool integration quality\n${voterFooter()}\n\nFocus on practical developer impact.`;\n}\n\n/** Build the AI/ML role prompt. */\nfunction aiMlPrompt(project: string): string {\n return `You are an AI/ML Engineer voting on proposals for the ${project} project.\n\nYour evaluation criteria:\n- Multi-agent coordination effectiveness\n- Model selection and routing strategies\n- Context management and token efficiency\n- Learning and adaptation capabilities\n- Consensus protocol design\n- Integration with LLM capabilities\n${voterFooter()}\n\nEvaluate AI/ML implications and opportunities.`;\n}\n\n/** Build the PM role prompt. */\nfunction pmPrompt(project: string): string {\n return `You are a Product Manager voting on proposals for the ${project} project.\n\nYour evaluation criteria:\n- Business value and user impact\n- Resource requirements and timeline\n- Risk assessment and mitigation\n- Priority relative to roadmap\n- Success metrics and validation approach\n- Alignment with project goals in ${governanceRulesRef(project)}\n${voterFooter()}\n\nBalance value against effort. Be pragmatic.`;\n}\n\n/** Build the catfish (contrarian) role prompt. */\nfunction catfishPrompt(project: string): string {\n return `You are a Contrarian Analyst (catfish agent) voting on proposals for the ${project} project.\n\nYour role is to prevent false consensus by deliberately challenging proposals.\nBased on research (arXiv:2505.21503), agreement bias in multi-agent voting leads\nto poor decisions when agents rubber-stamp proposals without genuine scrutiny.\n\nYour evaluation criteria:\n- What are the hidden costs, risks, or downsides not mentioned?\n- What assumptions are being made that might be wrong?\n- What alternatives were not considered?\n- What could go wrong in practice vs. theory?\n- Is there scope creep or unnecessary complexity?\n\nWorkflow-test assessment (include in your reasoning):\n- Testability: Is the proposal verifiable, or just theoretical?\n- Workflow integration: Will this actually work in existing pipelines?\n- Incremental verifiability: Can we tell if it's working at each stage?\n\nWhen rejecting, you MUST classify your reasons using categories: YAGNI, DRY_VIOLATION, OVER_ENGINEERING, SCOPE_CREEP, SECURITY_RISK, MISALIGNED, INSUFFICIENT_EVIDENCE.\n\nIf you cannot read the artifact under review — a shell, sandbox, or repository read fails — answer \"abstain\" and begin your reasoning with \"UNVERIFIABLE: could not read the artifact\"; never vote on the description alone.\n\nIMPORTANT: Your job is to find legitimate concerns, not to reject everything.\nIf after genuine scrutiny you find no significant issues, you MAY approve.\nBut your default posture is skeptical — look for what others might miss.\nHigh-confidence rejections with specific reasoning are your most valuable output.\n${prReviewModeAddendum()}`;\n}\n\n/**\n * Build the scope_steward role prompt (#2185).\n *\n * Different axis from `pm` (which prioritizes WHICH features to build) and\n * `catfish` (which doubts the framing). The steward asks: should we build\n * this AT ALL? Existing tools usually win; default bias is \"don't ship.\"\n */\n/**\n * Reuse-ladder check for the scope_steward (#4007, ponytail-inspired). Gates the\n * SIZE of a justified build by altitude — stop at the first rung that holds —\n * while hard-fencing the safety concerns that are never the thing cut. Hoisted to\n * module scope to keep {@link scopeStewardPrompt} within its line budget. Rung 3\n * names the target project (#6110): the default renders the pre-#6110 text.\n */\nfunction reuseLadderCheck(project: string): string {\n return `6. **Reuse ladder (implementation altitude).** When building IS justified,\n gate the SIZE of the build: stop at the first rung that holds, and say\n which one.\n 1. Does this need to exist at all? → no: skip it (YAGNI).\n 2. Standard library / language built-in? → use it.\n 3. Native platform feature or an existing ${project} substrate\n primitive (a canonical-path module, an existing voter/pipeline/\n store)? → use it.\n 4. An already-installed dependency? → use it.\n 5. One line? → one line.\n 6. Only then: the minimum that works.\n Lazy, NOT negligent — trust-boundary validation, error handling, security,\n and accessibility are NEVER the thing cut. The code is small because it is\n necessary, not golfed. Flag a proposal that reaches for rung 6 when an\n earlier rung holds as OVER_ENGINEERING.`;\n}\n\nfunction scopeStewardPrompt(project: string): string {\n return `You are a Scope Steward voting on proposals for the ${project} project.\n\nYour job is to gate against build-when-buy-would-do and feature sprawl.\nThe originating case (2026-04-24): a 6-role panel approved building a USB flasher\nCLI without anyone flagging that Rufus already solves the problem better, for the\nsame audience, with 100M+ installs of battle-tested code. This role exists to\ncatch that class of mistake.\n\nYour evaluation criteria — work through these mandatory checks in your reasoning:\n\n1. **Existing-tool check.** Search your knowledge for tools, libraries, or\n services that already solve the stated problem. Name them concretely\n (not \"there might be alternatives\" — actual names: Rufus, ripgrep,\n esbuild, etc.). If you can't name an alternative, say so explicitly.\n\n2. **Build-vs-buy math.** For each existing tool you named: what would we\n LOSE by adopting it (license, dependency surface, integration cost)?\n What would we GAIN by building our own (tighter integration, no extra\n binary, etc.)? Default lean: BUY. Building is justified only when the\n loss column is concrete and the gain column is load-bearing.\n\n3. **Mission alignment.** Does this proposal serve the project's stated\n mission, or is it scope drift? If drift, name the drift specifically.\n\n4. **Kill-the-feature option.** For every proposal, explicitly evaluate\n \"what if we just didn't do this?\" as a ranked option. Many proposals\n don't need to be built. Make the no-build case before the build case.\n\n5. **Sprawl audit.** Check whether similar functionality already exists\n in the codebase. If it does, recommend extending — not forking. The\n anti-sprawl policy in ${governanceRulesRef(project)} is specifically the rule this role\n enforces.\n\n${reuseLadderCheck(project)}\n\nDefault bias: REJECT proposals where an existing tool fits, even if our\nown implementation would be marginally nicer. Only approve when the\nexisting-tool check fails AND the kill-the-feature option is worse AND\nmission alignment is clear AND no comparable in-codebase functionality\nexists.\n\nFew-shot example of a textbook rejection:\n> Proposal: \"Add an aegis-boot subcommand to flash bootable USB sticks.\"\n> Steward response: \"REJECT (DON'T-BUILD). Rufus has solved this for the\n> same audience for 10+ years with 100M+ installs and battle-tested code.\n> Adopting Rufus loses nothing material; building our own loses\n> maintenance bandwidth indefinitely. Mission alignment: aegis-boot's\n> mission is verifiable boot, not USB tooling. Kill option clearly wins.\n> No prior in-codebase functionality. Recommend: point users at Rufus in\n> the docs and stop here.\"\n\n${voterFooter()}\n\nWhen rejecting, you MUST classify reasons (YAGNI, DRY_VIOLATION,\nOVER_ENGINEERING, SCOPE_CREEP, MISALIGNED). The steward's most common\ncategories are SCOPE_CREEP, YAGNI, and OVER_ENGINEERING.\n\nYou CAN approve. But your default posture is: \"this should not be built;\nprove me wrong with the build-vs-buy math.\"`;\n}\n\nexport function getVoterPrompts(\n project: string = DEFAULT_VOTER_PROJECT\n): Record<VoterRole, string> {\n return {\n architect: architectPrompt(project),\n security: securityPrompt(project),\n devex: devexPrompt(project),\n ai_ml: aiMlPrompt(project),\n pm: pmPrompt(project),\n catfish: catfishPrompt(project),\n scope_steward: scopeStewardPrompt(project),\n };\n}\n\n/**\n * Default prompts (backward compatible — uses 'nexus-agents' project context).\n */\nexport const VOTER_SYSTEM_PROMPTS: Record<VoterRole, string> = getVoterPrompts();\n\n/**\n * Base reasoning templates for simulated votes.\n *\n * scope_steward simulated reasoning intentionally reflects the role's\n * bias-toward-not-shipping posture (PM vote condition on #2185).\n */\nexport const SIMULATED_VOTE_REASONING: Record<VoterRole, string> = {\n architect: 'Evaluated technical design and architecture implications.',\n security: 'Reviewed security considerations and attack surface.',\n devex: 'Assessed developer experience and workflow impact.',\n ai_ml: 'Analyzed AI/ML capabilities and learning potential.',\n pm: 'Evaluated business value and resource requirements.',\n catfish: 'Challenged proposal assumptions and identified potential risks.',\n scope_steward:\n 'Checked existing tools, build-vs-buy math, kill-the-feature option; bias toward not shipping.',\n};\n","/**\n * nexus-agents voter response parsing\n *\n * Schema and parsing utilities for structured vote responses from LLM.\n *\n * (Source: Extracted from voter-agents.ts per Issue #285)\n */\n\nimport { z } from 'zod';\nimport type { Vote } from '../consensus/types.js';\nimport { matchDeclaredOption } from '../consensus/option-tally.js';\nimport type { VoterRole } from './vote-types.js';\nimport { getErrorMessage } from '../core/index.js';\n\n// ============================================================================\n// Error Classes\n// ============================================================================\n\n/**\n * Error thrown when vote response parsing fails.\n * (Source: Issue #512 - Fail-safe voting response parsing)\n *\n * parseVoteResponse always throws this error when JSON parsing or validation\n * fails — voting is fail-closed; no synthetic vote is ever fabricated (#4177\n * removed the opt-in `allowSyntheticVote` escape hatch, which had zero\n * production callers).\n */\nexport class SyntheticVoteError extends Error {\n constructor(\n reason: string,\n public readonly rawOutput: string\n ) {\n super(`Vote response parsing failed: ${reason}`);\n this.name = 'SyntheticVoteError';\n }\n}\n\n/**\n * Vote source tracking - indicates whether vote is real or synthetic.\n * (Source: Issue #512 - Voting integrity)\n */\nexport type ParsedVoteSource = 'parsed' | 'fallback';\n\n/**\n * Extended vote with source tracking.\n */\nexport interface ParsedVote extends Vote {\n readonly source: ParsedVoteSource;\n}\n\n// ============================================================================\n// Structured Vote Response Schema\n// ============================================================================\n\n/**\n * Pre-verified finding shape — voter emits this; downstream\n * `isFindingVerified` adds the derived `verified` flag.\n *\n * #2245 follow-up: voters previously asked to embed YAML findings inside\n * the JSON `reasoning` field. That format is lossy across JSON\n * serialization (backticks/newlines). The v4 retest produced 0 findings\n * across 9 request_changes voters because the LLM either dropped the\n * YAML to keep JSON valid, or produced invalid JSON the parser rejected.\n * Solution: expose findings as a top-level array on the vote response.\n */\nexport const RawFindingSchema = z.object({\n summary: z.string().min(1).max(500).describe('One-line summary of the issue'),\n location: z.string().min(1).max(200).describe('path/file.ext:line'),\n severity: z.enum(['critical', 'high', 'medium', 'low', 'info']).default('medium'),\n gate: z.object({\n reread_cited_line: z.enum(['passed', 'failed', 'skipped']).default('skipped'),\n traced_call_path: z.enum(['passed', 'failed', 'skipped']).default('skipped'),\n named_assertion: z\n .string()\n .default('')\n .describe('Concrete failing assertion — substantive, not a rubber-stamp word'),\n ruled_out_language_non_issue: z.enum(['passed', 'failed', 'skipped']).default('skipped'),\n }),\n claim: z.string().min(1).max(2000).describe('What is wrong and why it justifies blocking'),\n});\n\nexport type RawFinding = z.infer<typeof RawFindingSchema>;\n\n/**\n * Zod schema for parsing structured vote responses from LLM.\n */\nexport const VoteResponseSchema = z.object({\n decision: z.enum(['approve', 'reject', 'abstain']).describe('Your vote decision'),\n reasoning: z.string().min(10).max(4000).describe('Explanation for your vote (10-4000 chars)'),\n confidence: z.number().min(0).max(1).describe('Confidence level 0-1'),\n conditions: z.array(z.string()).optional().describe('Optional conditions for approval'),\n /** Structured rejection categories for reject→refine→re-vote loops (Issue #1213). */\n rejectionCategories: z\n .array(\n z.enum([\n 'YAGNI',\n 'DRY_VIOLATION',\n 'OVER_ENGINEERING',\n 'SCOPE_CREEP',\n 'SECURITY_RISK',\n 'MISALIGNED',\n 'INSUFFICIENT_EVIDENCE',\n ])\n )\n .optional()\n .describe('Rejection reason categories when decision is reject'),\n /** Top-level structured findings for PR-review mode (#2245 v4 follow-up).\n * Replaces the YAML-in-reasoning encoding that proved lossy. */\n findings: z.array(RawFindingSchema).optional().describe('Structured findings (PR review only)'),\n /** Chosen option when the proposal declared `options` (#4472). Validated\n * against the declared list by the caller; an unmatched value is dropped\n * rather than recorded, so a parse miss surfaces as absent. */\n selectedOption: z.string().optional().describe('Which declared option you choose'),\n});\n\nexport type VoteResponse = z.infer<typeof VoteResponseSchema>;\n\n/**\n * Hand-authored JSON Schema mirroring {@link VoteResponseSchema} (#3433).\n *\n * Used as the `input_schema` for a forced Claude `tool_use` call so the\n * ClaudeAdapter can honor `responseFormat: { type: 'json_schema' }` for votes.\n * `zod-to-json-schema` is intentionally NOT a dependency — this object is the\n * single source of truth for the JSON-Schema view of a vote response.\n *\n * Drift between this and `VoteResponseSchema` is caught by the contract test\n * in `voter-response.test.ts` (every Zod key must appear here and vice-versa).\n */\nexport const VOTE_JSON_SCHEMA: Record<string, unknown> = {\n type: 'object',\n additionalProperties: false,\n required: ['decision', 'reasoning', 'confidence'],\n properties: {\n decision: {\n type: 'string',\n enum: ['approve', 'reject', 'abstain'],\n description: 'Your vote decision',\n },\n reasoning: {\n type: 'string',\n minLength: 10,\n maxLength: 4000,\n description: 'Explanation for your vote (10-4000 chars)',\n },\n confidence: {\n type: 'number',\n minimum: 0,\n maximum: 1,\n description: 'Confidence level 0-1',\n },\n conditions: {\n type: 'array',\n items: { type: 'string' },\n description: 'Optional conditions for approval',\n },\n // #4472: without this, `additionalProperties: false` makes it impossible\n // for a structured-output voter to emit a selection at all.\n selectedOption: {\n type: 'string',\n description: 'Which declared option you choose (multi-option proposals only)',\n },\n rejectionCategories: {\n type: 'array',\n items: {\n type: 'string',\n enum: [\n 'YAGNI',\n 'DRY_VIOLATION',\n 'OVER_ENGINEERING',\n 'SCOPE_CREEP',\n 'SECURITY_RISK',\n 'MISALIGNED',\n 'INSUFFICIENT_EVIDENCE',\n ],\n },\n description: 'Rejection reason categories when decision is reject',\n },\n findings: {\n type: 'array',\n description: 'Structured findings (PR review only)',\n items: {\n type: 'object',\n additionalProperties: false,\n required: ['summary', 'location', 'severity', 'gate', 'claim'],\n properties: {\n summary: {\n type: 'string',\n minLength: 1,\n maxLength: 500,\n description: 'One-line summary of the issue',\n },\n location: {\n type: 'string',\n minLength: 1,\n maxLength: 200,\n description: 'path/file.ext:line',\n },\n severity: { type: 'string', enum: ['critical', 'high', 'medium', 'low', 'info'] },\n gate: {\n type: 'object',\n additionalProperties: false,\n required: [\n 'reread_cited_line',\n 'traced_call_path',\n 'named_assertion',\n 'ruled_out_language_non_issue',\n ],\n properties: {\n reread_cited_line: { type: 'string', enum: ['passed', 'failed', 'skipped'] },\n traced_call_path: { type: 'string', enum: ['passed', 'failed', 'skipped'] },\n named_assertion: {\n type: 'string',\n description: 'Concrete failing assertion — substantive, not a rubber-stamp word',\n },\n ruled_out_language_non_issue: {\n type: 'string',\n enum: ['passed', 'failed', 'skipped'],\n },\n },\n },\n claim: {\n type: 'string',\n minLength: 1,\n maxLength: 2000,\n description: 'What is wrong and why it justifies blocking',\n },\n },\n },\n },\n },\n};\n\n// ============================================================================\n// Vote Prompt Construction\n// ============================================================================\n\n/** Example responses appended to vote prompts. Kept as a constant to keep\n * `buildVotePrompt` under the max-lines-per-function lint cap. */\nconst VOTE_PROMPT_EXAMPLES = `Example approve response:\n{\n \"decision\": \"approve\",\n \"reasoning\": \"The proposal aligns with architectural patterns. Testability: high — unit tests can verify each component. Workflow integration: fits existing CI pipeline.\",\n \"confidence\": 0.85,\n \"conditions\": [\"Add unit tests before merge\"]\n}\n\nExample reject response:\n{\n \"decision\": \"reject\",\n \"reasoning\": \"This adds speculative abstractions for hypothetical future needs. Testability: unclear — no concrete test plan provided.\",\n \"confidence\": 0.80,\n \"rejectionCategories\": [\"YAGNI\", \"OVER_ENGINEERING\"]\n}\n\nExample PR-review request_changes response with structured findings:\n{\n \"decision\": \"reject\",\n \"reasoning\": \"Off-by-one in clampPageSize and missing null guard on response.timing — both visible in the diff.\",\n \"confidence\": 0.9,\n \"rejectionCategories\": [\"INSUFFICIENT_EVIDENCE\"],\n \"findings\": [\n {\n \"summary\": \"Off-by-one in clampPageSize\",\n \"location\": \"packages/nexus-agents/src/api/pagination.ts:18\",\n \"severity\": \"high\",\n \"gate\": {\n \"reread_cited_line\": \"passed\",\n \"traced_call_path\": \"passed\",\n \"named_assertion\": \"Test would assert clampPageSize(50, 100) === 50; this returns 49.\",\n \"ruled_out_language_non_issue\": \"passed\"\n },\n \"claim\": \"Function name says 'clamp to range' but returns requested-1 in the in-range path.\"\n }\n ]\n}`;\n\n/**\n * Constructs the user prompt for vote evaluation.\n * Includes workflow-test evaluation criteria (Issue #1212) and\n * rejection category instructions (Issue #1213).\n */\nexport function buildVotePrompt(\n proposal: string,\n options?: readonly string[],\n workspace?: string,\n workspaceSha?: string\n): string {\n return `Evaluate the following proposal and provide your vote.\n\nPROPOSAL:\n${proposal}\n${buildOptionsBlock(options)}${buildWorkspaceBlock(workspace, workspaceSha)}\nIn addition to your role-specific criteria, assess these workflow-test dimensions:\n- Testability: Can the proposed changes be verified with automated tests?\n- Workflow integration: Does this fit into existing CI/make/test workflows?\n- Incremental verifiability: Can progress be measured at each step?\n\nRespond with a JSON object containing:\n- decision: \"approve\", \"reject\", or \"abstain\"\n- reasoning: Explanation for your vote (10-4000 characters). Include your workflow-test assessment.\n- confidence: Number between 0 and 1\n- conditions: Optional array of conditions for approval\n- rejectionCategories: Required when rejecting. Array of categories from: YAGNI, DRY_VIOLATION, OVER_ENGINEERING, SCOPE_CREEP, SECURITY_RISK, MISALIGNED, INSUFFICIENT_EVIDENCE\n- findings: PR-REVIEW MODE ONLY. Optional top-level array of structured findings — see \"PR-review mode\" in the system prompt. OMIT this field entirely when reviewing a non-diff proposal or when approving a diff.\n${buildSelectionFieldDoc(options)}\n${VOTE_PROMPT_EXAMPLES}`;\n}\n\n/**\n * The OPTIONS block, present only when the proposal declares options (#4472).\n *\n * Empty string when none are declared, so a proposal without options produces\n * a prompt byte-identical to the pre-#4472 one.\n */\nexport function buildOptionsBlock(options?: readonly string[]): string {\n if (options === undefined || options.length === 0) return '';\n const list = options.map((o) => `- ${o}`).join('\\n');\n return `\nOPTIONS — choose exactly ONE of these and name it verbatim in \\`selectedOption\\`:\n${list}\n`;\n}\n\n/**\n * The REPOSITORY ACCESS block, present only when the caller names the\n * working directory the seats run in (#6254).\n *\n * On CLI-run governor panels a gemini seat abstained \"UNVERIFIABLE: could not\n * read the artifact ... no repository or accessible sandbox was provided\"\n * while the claude seats on the same panel read the head: nothing in either\n * prompt said where the tree was or that reading it was expected. This block\n * says both. It does not weaken the UNVERIFIABLE rule — a seat whose tools\n * genuinely cannot read the directory is still told to say so — and a\n * proposal that names nothing in the repository is still judged as written.\n *\n * Empty string when no workspace is given, so a caller with no tree to offer\n * (a direct `executeAgentVote`, a unit test) produces a prompt byte-identical\n * to the two-argument form and claims nothing it cannot back.\n */\nexport function buildWorkspaceBlock(workspace?: string, workspaceSha?: string): string {\n if (workspace === undefined || workspace === '') return '';\n if (workspaceSha !== undefined && workspaceSha !== '') {\n return `\nREPOSITORY ACCESS:\nThe repository under review is a detached scratch checkout of the ratified head ${workspaceSha} at ${workspace}. It is already at that commit — do NOT run git checkout/switch/reset/pull or modify files; read only.\nEvery seat's file and shell tools run there, and reading it is expected. Read the artifact before you vote; the proposal text is not a substitute for it. If your tools cannot read that directory, follow the UNVERIFIABLE rule in your instructions.\n`;\n }\n return `\nREPOSITORY ACCESS:\nThe repository under review is the working directory of this panel: ${workspace}\nEvery seat's file and shell tools run there, and reading it is expected. When the proposal refers to something in that repository — a PR head, a diff, the files it touches — read it there before you vote: the proposal text describes the artifact and is not a substitute for it. If your tools cannot read that directory, follow the UNVERIFIABLE rule in your instructions.\n`;\n}\n\n/** The `selectedOption` field doc, present only when options are declared. */\nfunction buildSelectionFieldDoc(options?: readonly string[]): string {\n if (options === undefined || options.length === 0) return '';\n return '- selectedOption: REQUIRED. Exactly one option from the OPTIONS list above, copied verbatim. Do not invent an option, combine two, or leave it blank — your selection is what the threshold is measured over.';\n}\n\n// ============================================================================\n// Vote Response Parsing\n// ============================================================================\n\n/**\n * Extract the FIRST balanced top-level JSON object from `text`, respecting\n * string literals + escapes so braces/brackets inside strings don't miscount\n * (#4131). Returns the object substring, or undefined if no `{` is present.\n *\n * If the object is TRUNCATED (containers still open at end-of-input — e.g. a\n * large findings-bearing vote cut off by the completion token cap), it returns a\n * best-effort repair: the open string is closed and the open `{`/`[` containers\n * are closed in order. Since a well-formed vote emits `decision`/`reasoning`/\n * `confidence` before the optional `findings` array, a truncation inside\n * `findings` still yields a parseable verdict. If the repair is still invalid,\n * the caller's JSON.parse throws exactly as before (no regression).\n */\n/** Mutable scan state for {@link extractFirstJsonObject}. */\ninterface JsonScanState {\n readonly closers: string[];\n inString: boolean;\n escaped: boolean;\n}\n\ntype ScanResult = 'complete' | 'unbalanced' | 'continue';\n\n/** Handle one char while inside a JSON string literal. */\nfunction stepInString(state: JsonScanState, ch: string): void {\n if (ch === '\\\\') state.escaped = true;\n else if (ch === '\"') state.inString = false;\n}\n\n/** Handle one structural (non-string) char, tracking open/close containers. */\nfunction stepStructural(state: JsonScanState, ch: string): ScanResult {\n if (ch === '\"') state.inString = true;\n else if (ch === '{') state.closers.push('}');\n else if (ch === '[') state.closers.push(']');\n else if (ch === '}' || ch === ']') {\n if (state.closers.pop() === undefined) return 'unbalanced';\n if (state.closers.length === 0) return 'complete';\n }\n return 'continue';\n}\n\n/** Advance the balanced-object scan by one char. Returns whether the object closed / broke. */\nfunction stepJsonScan(state: JsonScanState, ch: string): ScanResult {\n if (state.escaped) {\n state.escaped = false;\n return 'continue';\n }\n if (state.inString) {\n stepInString(state, ch);\n return 'continue';\n }\n return stepStructural(state, ch);\n}\n\n/** Best-effort close of an object truncated mid-scan (open string + open containers). */\nfunction repairTruncatedObject(fragment: string, state: JsonScanState): string {\n let repaired = state.inString ? `${fragment}\"` : fragment;\n for (let i = state.closers.length - 1; i >= 0; i--) {\n const closer = state.closers[i];\n if (closer !== undefined) repaired += closer;\n }\n return repaired;\n}\n\nfunction extractFirstJsonObject(text: string): string | undefined {\n const start = text.indexOf('{');\n if (start === -1) return undefined;\n const state: JsonScanState = { closers: [], inString: false, escaped: false };\n for (let i = start; i < text.length; i++) {\n const result = stepJsonScan(state, text[i] as string);\n if (result === 'complete') return text.slice(start, i + 1);\n if (result === 'unbalanced') return undefined;\n }\n // Loop ran off the end with containers still open ⇒ truncated; repair best-effort.\n return state.closers.length > 0 ? repairTruncatedObject(text.slice(start), state) : undefined;\n}\n\n/**\n * Extracts the JSON vote object from raw LLM response text (#4131).\n *\n * Robust to the ways a voter's output shape used to silently DROP the voter:\n * 1. Prefer an explicit ` ```json ` fence.\n * 2. Otherwise scan every fenced block and use the first whose content is a\n * JSON object — so a ` ```yaml findings ` block (pr-review mode) is SKIPPED\n * instead of being handed to JSON.parse (the `Unexpected token 'y'` drop).\n * 3. Otherwise take the first balanced JSON object anywhere in the text, so a\n * verdict followed by a trailing prose / YAML block still parses, and a\n * truncated object is repaired.\n * 4. Fallback: the trimmed text (JSON.parse will surface a real malformation).\n *\n * A fence's object is scanned from the fence opener with the string-aware\n * scanner, never cut at the next ` ``` ` (#6957): a pr_review voter quoting a\n * fenced regex inside its reasoning put a ` ``` ` INSIDE a JSON string, the\n * lazy fence match ended there, the truncation repair closed the object after\n * `reasoning`, and every such seat was rejected for a missing confidence.\n */\nexport function extractJsonFromResponse(text: string): string {\n const jsonFence = /```json\\s*([\\s\\S]*?)```/i.exec(text);\n if (jsonFence?.[1] !== undefined) {\n return (\n objectFromFenceBody(text, jsonFence, jsonFence[1]) ??\n extractFirstJsonObject(jsonFence[1]) ??\n jsonFence[1].trim()\n );\n }\n\n for (const match of text.matchAll(/```[a-zA-Z0-9]*\\s*([\\s\\S]*?)```/g)) {\n const inner = match[1];\n if (inner !== undefined) {\n const obj = objectFromFenceBody(text, match, inner);\n if (obj !== undefined) return obj;\n }\n }\n\n return extractFirstJsonObject(text) ?? text.trim();\n}\n\n/**\n * The balanced object that opens a fence's body, scanned in the FULL text from\n * the body's start so a ` ``` ` inside a JSON string does not end it (#6957).\n * Undefined when the body does not open with `{`.\n */\nfunction objectFromFenceBody(\n text: string,\n match: RegExpExecArray | RegExpMatchArray,\n body: string\n): string | undefined {\n if (!body.trimStart().startsWith('{') || match.index === undefined) return undefined;\n const bodyStart = match.index + match[0].length - '```'.length - body.length;\n return extractFirstJsonObject(text.slice(bodyStart));\n}\n\n/** Caps mirroring {@link VoteResponseSchema} (reasoning) + {@link RawFindingSchema} (claim). */\nconst REASONING_MAX_CHARS = 4000;\nconst CLAIM_MAX_CHARS = 2000;\nconst TRUNCATION_MARKER = ' …[truncated]';\n\n/** Truncate `s` to `max` chars with a marker; a no-op when already within cap. */\nfunction clampWithMarker(s: string, max: number): string {\n if (s.length <= max) return s;\n return s.slice(0, Math.max(0, max - TRUNCATION_MARKER.length)) + TRUNCATION_MARKER;\n}\n\n/**\n * Clamp the capped string fields of a parsed vote to their schema limits with a\n * truncation marker BEFORE validation (#4131). A thorough voter (esp. the\n * contrarian, which writes the most detailed findings) whose `reasoning` exceeds\n * the 4000-char cap previously hard-failed validation and was SILENTLY DROPPED\n * from the panel denominator. Clamping records a (clipped, clearly-marked) real\n * vote instead. Only shape (oversize strings) is repaired — a genuinely\n * malformed vote (missing decision, bad confidence) still fails `safeParse`.\n */\nfunction clampOversizeVoteStrings(parsed: unknown): unknown {\n if (typeof parsed !== 'object' || parsed === null) return parsed;\n const obj = { ...(parsed as Record<string, unknown>) };\n if (typeof obj['reasoning'] === 'string') {\n obj['reasoning'] = clampWithMarker(obj['reasoning'], REASONING_MAX_CHARS);\n }\n if (Array.isArray(obj['findings'])) {\n obj['findings'] = (obj['findings'] as unknown[]).map((finding): unknown => {\n if (\n typeof finding === 'object' &&\n finding !== null &&\n typeof (finding as Record<string, unknown>)['claim'] === 'string'\n ) {\n const f = finding as Record<string, unknown>;\n return { ...f, claim: clampWithMarker(f['claim'] as string, CLAIM_MAX_CHARS) };\n }\n return finding;\n });\n }\n return obj;\n}\n\n/** Maps a validated VoteResponse into a ParsedVote, threading optional fields. */\nfunction buildParsedVote(data: VoteResponse, options?: readonly string[]): ParsedVote {\n // #4472: resolve the voter's raw selection against the declared options.\n // An unmatched or absent selection stays absent — never defaulted — so the\n // tally can price it as unattributed rather than inventing agreement.\n const selectedOption =\n options === undefined ? undefined : matchDeclaredOption(data.selectedOption, options);\n return {\n decision: data.decision,\n reasoning: data.reasoning,\n confidence: data.confidence,\n ...(data.conditions !== undefined ? { conditions: data.conditions } : {}),\n ...(data.rejectionCategories !== undefined\n ? { rejectionCategories: data.rejectionCategories }\n : {}),\n ...(data.findings !== undefined ? { findings: data.findings } : {}),\n ...(selectedOption !== undefined ? { selectedOption } : {}),\n source: 'parsed',\n };\n}\n\n/**\n * Parses vote response from LLM output.\n *\n * Fail-closed: throws SyntheticVoteError if parsing or validation fails.\n * No synthetic vote is ever fabricated from unparseable output (#4177).\n *\n * (Source: Issue #512 - Fail-safe voting response parsing)\n *\n * @param output - Raw LLM output text\n * @param _role - Voter role for context\n * @returns ParsedVote with source tracking\n * @throws SyntheticVoteError if parsing or validation fails\n */\nexport function parseVoteResponse(\n output: string,\n _role: VoterRole,\n options?: readonly string[]\n): ParsedVote {\n try {\n const jsonStr = extractJsonFromResponse(output);\n const parsed = JSON.parse(jsonStr) as unknown;\n // #4131: clip oversize reasoning/claims (with a marker) so a thorough voter\n // records a real vote instead of being silently dropped on the char cap.\n const validated = VoteResponseSchema.safeParse(clampOversizeVoteStrings(parsed));\n\n if (validated.success) {\n return buildParsedVote(validated.data, options);\n }\n\n const reason = `Validation failed: ${validated.error.issues.map((e: { message: string }) => e.message).join(', ')}`;\n throw new SyntheticVoteError(reason, output);\n } catch (error) {\n // If it's already a SyntheticVoteError, rethrow it\n if (error instanceof SyntheticVoteError) {\n throw error;\n }\n\n throw new SyntheticVoteError(getErrorMessage(error, 'Unknown parse error'), output);\n }\n}\n","/**\n * Option-tally threshold evaluation for multi-option proposals (#4472).\n *\n * When a `consensus_vote` proposal declares named `options`, thresholds must be\n * measured over WHICH option voters chose, not over raw approve/reject counts.\n * Without this, `unanimous` is the *easiest* bar to clear on a multi-option\n * proposal: every voter approves while each picks something different, so a 6-1\n * split records as 7-0, 100% (#4452).\n *\n * ## Semantics: \"count in denominator, credit no option\"\n *\n * Decided by a 7-voter `higher_order` panel on #4472 (6-1 for this rule). An\n * approving voter whose selection is absent or matches no declared option stays\n * in the denominator and credits no option.\n *\n * The decisive property is that this is **monotone-downward**: an absent or\n * unmatched selection can only *lower* the leading option's share, never raise\n * it. Degradation is therefore a denial, never an escalation — the invariant an\n * enforcing governance gate requires (#4464). The rejected alternative\n * (excluding non-selectors from the denominator) reads 1 selector among 6\n * unparseable as 1/1 = 100% \"unanimous\", rebuilding the #4452 masking bug.\n *\n * No per-threshold special-casing is needed: any non-selecting approver caps the\n * leading share below 100%, so `unanimous` fails by arithmetic when the panel\n * cannot articulate one choice. Absence is disqualifying for unanimity by\n * construction.\n *\n * The accepted cost is false negatives — a genuinely unanimous panel with one\n * degraded response records 6/7 and misses the unanimous gate. On the governor\n * path that bias direction is correct: a retry, never a split laundered as\n * consensus.\n *\n * @module consensus/option-tally\n * (Source: Issue #4472)\n */\n\n/** Fraction of the leading option required to clear each threshold. */\nconst SUPERMAJORITY_SHARE = 2 / 3;\nconst MAJORITY_SHARE = 0.5;\n\n/** The thresholds this module can evaluate over an option tally. */\nexport type OptionThreshold = 'majority' | 'supermajority' | 'unanimous';\n\n/** One declared option and how many approving voters chose it. */\nexport interface OptionTallyEntry {\n readonly option: string;\n readonly count: number;\n}\n\n/** Minimal vote shape this module reads. */\nexport interface TallyableVote {\n readonly decision: 'approve' | 'reject' | 'abstain';\n readonly selectedOption?: string;\n}\n\nexport interface OptionTallyResult {\n /** Chosen options, descending by count, ties broken by label for determinism. */\n readonly tally: readonly OptionTallyEntry[];\n /** The most-chosen option, or undefined when nobody selected one. */\n readonly leadingOption?: string;\n readonly leadingCount: number;\n /** Denominator: every approving voter, selecting or not. */\n readonly approverCount: number;\n /** Approvers whose selection matched a declared option. */\n readonly selectedCount: number;\n /**\n * Approvers with no usable selection.\n *\n * Recorded explicitly because the share alone cannot distinguish dissent from\n * absence: `4 pick X + 3 unparseable` and a real 4/3 split both read 57%. The\n * panel made this field a condition of adopting these semantics — partial\n * coverage must be represented, not merely priced in.\n */\n readonly unattributedApprovals: number;\n /** `leadingCount / approverCount`, or 0 when nobody approved. */\n readonly leadingShare: number;\n}\n\nexport interface OptionThresholdVerdict extends OptionTallyResult {\n readonly threshold: OptionThreshold;\n readonly approved: boolean;\n}\n\n/**\n * Resolve a voter's raw selection to a declared option.\n *\n * Matching is trimmed and case-insensitive, and returns the *declared* spelling\n * so the tally never splits one option across spelling variants. Anything that\n * does not match exactly one declared option resolves to `undefined` — an\n * unmatched selection is treated as absent, never coerced onto a default,\n * because a defaulted option is a measurement that was never taken.\n */\nexport function matchDeclaredOption(\n raw: string | undefined,\n declaredOptions: readonly string[]\n): string | undefined {\n if (raw === undefined) return undefined;\n\n const normalized = raw.trim().toLowerCase();\n if (normalized === '') return undefined;\n\n return declaredOptions.find((option) => option.trim().toLowerCase() === normalized);\n}\n\n/** Build the option tally for a set of votes against the declared options. */\nexport function tallyOptions(\n votes: readonly TallyableVote[],\n declaredOptions: readonly string[]\n): OptionTallyResult {\n const approvers = votes.filter((v) => v.decision === 'approve');\n\n const counts = new Map<string, number>();\n let selectedCount = 0;\n\n for (const vote of approvers) {\n const matched = matchDeclaredOption(vote.selectedOption, declaredOptions);\n if (matched === undefined) continue;\n selectedCount += 1;\n counts.set(matched, (counts.get(matched) ?? 0) + 1);\n }\n\n const tally = [...counts.entries()]\n .map(([option, count]) => ({ option, count }))\n .sort((a, b) => (b.count !== a.count ? b.count - a.count : a.option.localeCompare(b.option)));\n\n const leader = tally[0];\n const approverCount = approvers.length;\n const leadingCount = leader?.count ?? 0;\n\n return {\n tally,\n ...(leader !== undefined ? { leadingOption: leader.option } : {}),\n leadingCount,\n approverCount,\n selectedCount,\n unattributedApprovals: approverCount - selectedCount,\n leadingShare: approverCount > 0 ? leadingCount / approverCount : 0,\n };\n}\n\n/**\n * Decide whether the leading option clears `threshold`.\n *\n * `unanimous` asks whether every approver chose the *same* option, which is\n * strictly stronger than \"everyone approved\" — the inversion #4472 exists to\n * correct. The share thresholds measure the leading option, so total approvals\n * no longer stand in for agreement.\n */\nexport function evaluateOptionThreshold(\n tally: OptionTallyResult,\n threshold: OptionThreshold\n): OptionThresholdVerdict {\n const approved = clears(tally, threshold);\n return { ...tally, threshold, approved };\n}\n\nfunction clears(tally: OptionTallyResult, threshold: OptionThreshold): boolean {\n // A panel in which nobody named an option has not agreed on one, whatever\n // its approval count says.\n if (tally.approverCount === 0 || tally.leadingCount === 0) return false;\n\n switch (threshold) {\n case 'unanimous':\n return tally.leadingCount === tally.approverCount;\n case 'supermajority':\n return tally.leadingShare >= SUPERMAJORITY_SHARE;\n case 'majority':\n return tally.leadingShare > MAJORITY_SHARE;\n }\n}\n","/**\n * Text extraction for a voter's completion response — the ONE seam every seat\n * passes through before its text becomes `reasoning` on a vote record.\n * Extracted from voter-execution.ts for the per-file line cap (#6269); the\n * behaviour and its tests (voter-execution.test.ts) are unchanged.\n *\n * @module cli/voter-response-text\n */\n\nimport { sanitizeOutput } from '../security/output-sanitizer.js';\n\n/**\n * Extracts text content from completion response.\n *\n * The result is passed through `sanitizeOutput` (#6267): the subprocess\n * adapter scrubs API keys from CLI stdout, but the API adapters (gateway,\n * SDK, Claude) return raw model text, and since #6194 this string becomes\n * the `reasoning` of a record committed to the public ledger. Scrubbing here\n * bounds every seat uniformly; already-scrubbed CLI text is unchanged.\n */\nexport function extractTextFromResponse(content: unknown): string {\n return sanitizeOutput(rawTextFromResponse(content));\n}\n\nfunction rawTextFromResponse(content: unknown): string {\n if (typeof content === 'string') {\n return content;\n }\n if (Array.isArray(content)) {\n return content\n .map((block) => {\n if (typeof block === 'object' && block !== null && 'type' in block) {\n const typed = block as { type: string; text?: string };\n if (typed.type === 'text' && typeof typed.text === 'string') {\n return typed.text;\n }\n }\n return '';\n })\n .join('');\n }\n return String(content);\n}\n\n/**\n * #3497: some backends don't silently ignore an unsupported `responseFormat`.\n * OpenRouter implements `json_schema` via provider tool-use, so a role routed to\n * a provider without tool-use returns a hard 404 \"No endpoints found that\n * support tool use\" instead of ignoring the field — silently shrinking the panel\n * (observed on devex/catfish). Detect it so the caller retries without it.\n */\nexport function isStructuredOutputUnsupported(errorMessage: string): boolean {\n return /support tool use/i.test(errorMessage);\n}\n","/**\n * Failed-attempt logging for the voter retry loop, and the rate-limit test it\n * classifies by. Extracted from `voter-execution.ts` (#6821) to keep that\n * module under the line cap; behaviour unchanged.\n *\n * @module cli/voter-attempt-log\n */\n\nimport type { ILogger } from '../core/index.js';\nimport type { VoterRole } from './vote-types.js';\nimport { isAuthFailureText } from '../cli-adapters/cli-error-envelope.js';\nimport { sanitizeOutput } from '../security/output-sanitizer.js';\n/**\n * Detects whether an error message indicates a rate-limit condition.\n * Delegates to canonical rate-limit-detector (DRY consolidation Issue #1596).\n */\nimport { isRateLimitLikeError, isDurableCapacityText } from '../adapters/rate-limit-detector.js';\n\n/** @see isRateLimitLikeError — re-exported for backward compatibility */\nexport function isRateLimitError(message: string): boolean {\n return isRateLimitLikeError(new Error(message));\n}\n\n/**\n * Record that a voter gave up its remaining attempts (#5359).\n *\n * A DURABLE capacity cap — a spend or usage ceiling on the credential — does\n * not clear in seconds, so the remaining attempts are guaranteed-futile. The\n * waste is not local either: `computeOverallConsensusDeadlineMs` budgets\n * `timeoutMs * (maxRetries + 1)` as a SHARED wall-clock deadline across the\n * panel, so burning it here starved a healthy voter on a different adapter in\n * four consecutive live runs. Failing fast hands the remaining budget to the\n * #3587 fallback, which is what actually recovers the voice.\n */\nexport function logAbandonedRetries(\n logger: ILogger,\n role: VoterRole,\n attempt: number,\n maxRetries: number,\n cause: 'durable capacity cap' | 'auth failure' | 'non-retryable error'\n): void {\n logger.warn(`${cause} — abandoning retries for this voter`, {\n role,\n attempt: attempt + 1,\n remainingAttemptsSkipped: maxRetries - attempt,\n });\n}\n\n/** One failed attempt, as {@link logFailedAttempt} reports it. */\ninterface FailedAttempt {\n readonly role: VoterRole;\n readonly attempt: number;\n readonly maxRetries: number;\n readonly attemptMs: number;\n readonly error: string;\n readonly retryable: boolean | undefined;\n /** Stderr the transport captured when the output was not a vote (#6269). */\n readonly cliStderr: string | undefined;\n /** The answer that failed to parse as a vote, when the transport completed (#6957). */\n readonly rawOutput?: string | undefined;\n}\n\n/** Longest raw-answer excerpt carried on the `Vote attempt failed` line (#6957). */\nconst LOGGED_RAW_OUTPUT_MAX_CHARS = 2000;\n\n/** Longest stderr excerpt carried on the `Vote attempt failed` line (#6269). */\nconst LOGGED_STDERR_MAX_CHARS = 200;\n\n/**\n * The first non-blank stderr line, secret-redacted and clipped: enough to name\n * the cause (an auth line, a sandbox failure) without a stack trace (#6269).\n */\nfunction loggedStderrLine(cliStderr: string): string {\n const first = cliStderr.split('\\n').find((line) => line.trim() !== '') ?? '';\n return sanitizeOutput(first.trim()).slice(0, LOGGED_STDERR_MAX_CHARS);\n}\n\n/**\n * Log one failed attempt's timing and classification. Returns the reason the\n * remaining attempts are futile — a DURABLE capacity cap (#5359) or an auth\n * failure (#6269: a retry on the same credential cannot clear it, and the\n * budget it would burn is what the #3587 fallback needs) — or `null` when the\n * caller should keep retrying. Explicit non-retryable adapter errors also\n * abandon the remaining attempts (#6846).\n */\nexport function logFailedAttempt(\n logger: ILogger,\n failed: FailedAttempt\n): 'durable capacity cap' | 'auth failure' | 'non-retryable error' | null {\n const { role, attempt, maxRetries, attemptMs, error, cliStderr } = failed;\n const rateLimited = isRateLimitError(error);\n const durableCap = isDurableCapacityText(error);\n const authFailure = isAuthFailureText(error);\n logger.info('Vote attempt timing', {\n role,\n attempt: attempt + 1,\n attemptMs,\n succeeded: false,\n rateLimited,\n });\n logger.warn('Vote attempt failed', {\n role,\n attempt: attempt + 1,\n maxRetries: maxRetries + 1,\n error,\n ...(rateLimited ? { rateLimited: true } : {}),\n ...(durableCap ? { durableCap: true } : {}),\n ...(authFailure ? { authFailure: true } : {}),\n ...(cliStderr !== undefined && cliStderr !== ''\n ? { cliStderr: loggedStderrLine(cliStderr) }\n : {}),\n // #6957: without the answer itself a rejected vote cannot be diagnosed.\n ...(failed.rawOutput !== undefined\n ? { rawOutputExcerpt: sanitizeOutput(failed.rawOutput).slice(0, LOGGED_RAW_OUTPUT_MAX_CHARS) }\n : {}),\n });\n if (durableCap) return 'durable capacity cap';\n if (authFailure) return 'auth failure';\n if (failed.retryable === false) return 'non-retryable error';\n return null;\n}\n","/**\n * Per-seat fallback disclosure (#6115).\n *\n * Three consecutive 7-seat ratification panels on 2026-09-13 answered every\n * seat on one gemini model: the three claude seats fell over (#3587) during a\n * claude capacity window, the two codex seats errored and landed on the same\n * sticky default, and the two gemini seats were native. Quorum was real,\n * independence was not, and nothing in the live result said so — the assigned\n * CLI was not recoverable and the fallover reason was only in a log line.\n *\n * This module stamps the assignment on every seat and, when a seat answered\n * elsewhere, the class of error that moved it. Classification reuses the\n * predicates the adapter layer already classifies by; it adds no taxonomy of\n * its own.\n *\n * @module cli/voter-fallback\n */\n\nimport type { IModelAdapter } from '../core/index.js';\nimport { isDurableCapacityText, isRateLimitText } from '../adapters/rate-limit-detector.js';\nimport { classifyExtractedError } from '../cli-adapters/cli-error-envelope.js';\nimport { isTimeoutText } from '../cli-adapters/cli-error-helpers.js';\nimport { UNRESOLVED_MODEL_ID } from '../config/model-equivalence.js';\nimport type { AgentVoteResult, FallbackReason, SeatFallback } from './vote-types.js';\nimport { UNVERIFIABLE_STDERR_RE } from './voter-unverifiable.js';\n\n/**\n * Strip the `cli-` prefix `CliToModelAdapter` and a pinned `ResilientAdapter`\n * put on `providerId`, so a seat's assignment reads `claude`, not `cli-claude`.\n * Any other id (a gateway provider, `resilient-proxy`) is returned unchanged.\n */\nexport function bareCliName(id: string): string {\n return id.startsWith('cli-') ? id.slice('cli-'.length) : id;\n}\n\n/**\n * Classify the error that moved a seat off its assigned adapter.\n *\n * Order matters and mirrors the adapter layer: a durable capacity cap is\n * checked before the transient rate-limit list because `RATE_LIMIT_PATTERNS`\n * is the union of both (#5359), and the #6094 sandbox signature before the\n * timeout words because a sandbox failure line can mention one.\n */\nexport function classifyFallbackReason(message: string): FallbackReason {\n if (isDurableCapacityText(message)) return 'capacity';\n if (isRateLimitText(message)) return 'rate-limit';\n if (classifyExtractedError(message, 'unknown').code === 'NOT_AUTHENTICATED') return 'auth';\n if (UNVERIFIABLE_STDERR_RE.test(message)) return 'sandbox';\n if (isTimeoutText(message)) return 'timeout';\n return 'unknown';\n}\n\n/** The assigned adapter's model when it had detected one; the placeholder is not disclosed. */\nfunction detectedModel(adapter: IModelAdapter): string | undefined {\n // `unknown`, not `string`: the interface promises a string, but an adapter\n // constructed without one reports undefined at runtime (#4983).\n const id: unknown = adapter.modelId;\n return typeof id === 'string' && id !== '' && id !== UNRESOLVED_MODEL_ID ? id : undefined;\n}\n\n/**\n * The assignment key as a bare CLI name, or undefined when the adapter had\n * none. `unknown` for the same reason as {@link detectedModel}: `adapterCliKey`\n * is typed string but reads `name ?? providerId`, and a bare test adapter has\n * neither.\n */\nfunction assignedCliOf(key: unknown): string | undefined {\n return typeof key === 'string' && key !== '' ? bareCliName(key) : undefined;\n}\n\n/**\n * The cross-CLI fallover disclosure for a seat assigned to `assigned` that\n * errored with `error` and was re-run on the fallback (#3587). A seat whose\n * adapter carried no id is disclosed as `unknown` — the fallover still\n * happened and the reason is still measured.\n */\nexport function crossCliFallback(\n assigned: IModelAdapter,\n assignedKey: string,\n error: string\n): SeatFallback {\n const fromModel = detectedModel(assigned);\n return {\n fromCli: assignedCliOf(assignedKey) ?? 'unknown',\n ...(fromModel !== undefined ? { fromModel } : {}),\n reason: classifyFallbackReason(error),\n };\n}\n\n/**\n * The in-family disclosure for a seat whose CLI answered on a different model\n * alias than requested (#6120): the claude adapter substitutes the next\n * registry alias after an out-of-credits envelope, which is a capacity class\n * by construction — it is the only condition that triggers the substitution.\n */\nexport function inFamilyFallback(cli: string, fromModel: string): SeatFallback {\n return { fromCli: bareCliName(cli), fromModel, reason: 'capacity' };\n}\n\n/**\n * Stamp the seat's assignment on a result, keeping any fallback the seat\n * already carries (the in-family one is set where the answer is built).\n */\nexport function withAssignedCli(result: AgentVoteResult, assignedKey: string): AgentVoteResult {\n const assignedCli = assignedCliOf(assignedKey);\n return assignedCli === undefined ? result : { ...result, assignedCli };\n}\n","/**\n * Where a seat's result is built from its attempts (#6821).\n *\n * {@link buildLlmVoteResult} puts the answering completion's usage and the\n * usage of every settled attempt on the seat. A seat's result is then rebuilt\n * at three points — the retry loop's error result, the cross-CLI fallback\n * (#3587) and the per-role retry pass (#5578). Each used to drop the earlier\n * result's billed completions; {@link carryAttemptUsage} folds them forward.\n * `buildLlmVoteResult` moved here from `voter-agents.ts`, which is at its\n * line cap.\n *\n * @module cli/voter-attempt-usage\n */\n\nimport {\n carryVoterAttemptTelemetry,\n preserveVoterAttemptTelemetry,\n} from './voter-attempt-events.js';\nimport type { AttemptTelemetry } from '../observability/attempt-usage.js';\nimport {\n mergeAttemptUsage,\n foldCompletionUsage,\n type AttemptUsage,\n} from '../observability/attempt-usage.js';\nimport type { IModelAdapter, CompletionResponse } from '../core/index.js';\nimport { isGatewayModelAdapter } from '../adapters/openai-compat-adapter.js';\nimport type { AgentVoteResult, VoterRole } from './vote-types.js';\nimport type { VoteOutcome, VoteUsage } from './voter-execution.js';\nimport { inFamilyFallback } from './voter-fallback.js';\n\n/**\n * `onto`, with `from`'s attempt usage added to its own. Unchanged when\n * neither carried any: the empty case stays absent, never a zero record.\n */\nexport function carryAttemptUsage(\n from:\n | {\n readonly attemptUsage?: AttemptUsage | undefined;\n readonly attemptTelemetry?: AttemptTelemetry | undefined;\n }\n | undefined,\n onto: AgentVoteResult\n): AgentVoteResult {\n const attemptUsage = mergeAttemptUsage(from?.attemptUsage, onto.attemptUsage);\n const decorated =\n attemptUsage === undefined\n ? onto\n : preserveVoterAttemptTelemetry(onto, { ...onto, attemptUsage });\n return carryVoterAttemptTelemetry(from, decorated);\n}\n\n/**\n * Builds the successful LLM `AgentVoteResult`, propagating the adapter-reported\n * per-call tokens so the decision-cost rollup attributes this voter as MEASURED,\n * not unmeasured (#3910). Only attaches a token field when the adapter actually\n * reported it — an absent count stays absent (⇒ unmeasured), never a fabricated 0.\n */\nexport function buildLlmVoteResult(\n role: VoterRole,\n { vote, usage, fallbackFrom, servedModel, attemptUsage }: VoteOutcome,\n adapter: IModelAdapter,\n processingTimeMs: number\n): AgentVoteResult {\n return {\n role,\n vote,\n processingTimeMs,\n source: 'llm',\n cli: adapter.providerId,\n model: adapter.modelId,\n // #6660: the model that answered, as the adapter reported it — the\n // outcome row names and prices this one, not the requested `model`.\n ...(servedModel !== undefined ? { servedModel } : {}),\n // #4392 step 4: which gateway arm served the seat, so the cost rollup\n // prices it by the arm's declaration and not the model id's list price.\n ...(isGatewayModelAdapter(adapter) ? { gatewayArm: adapter.gatewayArm } : {}),\n // #6115: the CLI answered on another model of its family (#6120) — a\n // capacity fallback by construction, disclosed on the seat.\n ...(fallbackFrom !== undefined\n ? { fallback: inFamilyFallback(adapter.providerId, fallbackFrom) }\n : {}),\n // #4472: surface the voter's choice at the result level, where the tally\n // and the record read it. Absent when no options were declared or the\n // selection matched none of them.\n ...(vote.selectedOption !== undefined ? { selectedOption: vote.selectedOption } : {}),\n ...(usage.inputTokens !== undefined ? { inputTokens: usage.inputTokens } : {}),\n ...(usage.outputTokens !== undefined ? { outputTokens: usage.outputTokens } : {}),\n ...(usage.cachedInputTokens !== undefined\n ? { cachedInputTokens: usage.cachedInputTokens }\n : {}),\n ...(usage.cacheCreationInputTokens !== undefined\n ? { cacheCreationInputTokens: usage.cacheCreationInputTokens }\n : {}),\n // #6821: every settled completion, not only the one answering above.\n attemptUsage,\n };\n}\n\n/** Read a usage token count when the adapter actually reported a number (#3910). */\nfunction readTokenCount(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined;\n}\n\n/** The answering response's legacy counters; attempt events are captured separately. */\nexport function readVoteUsage(response: CompletionResponse): VoteUsage {\n // #3910: capture the adapter-reported per-call usage so it can ride up into\n // the AgentVoteResult and feed the decision-cost rollup as MEASURED. Cast\n // through a loose shape: the type guarantees `usage`, but a real adapter (or a\n // partial response) may omit the counts — read each defensively so a\n // non-reporting call stays unmeasured rather than throwing or fabricating 0.\n const reported = response.usage as unknown as\n | {\n inputTokens?: unknown;\n outputTokens?: unknown;\n cachedInputTokens?: unknown;\n cacheCreationInputTokens?: unknown;\n }\n | undefined;\n const usage: VoteUsage = {\n inputTokens: readTokenCount(reported?.inputTokens),\n outputTokens: readTokenCount(reported?.outputTokens),\n // #4435: an `inputTokens: 2` next to 3,980 cached tokens tells a very\n // different story than `inputTokens: 2` alone.\n cachedInputTokens: readTokenCount(reported?.cachedInputTokens),\n cacheCreationInputTokens: readTokenCount(reported?.cacheCreationInputTokens),\n };\n return usage;\n}\n\n/** Fold an attempt's reported usage, when the transport returned a response. */\nexport function foldAttempt(\n acc: AttemptUsage | undefined,\n usage: VoteUsage | undefined\n): AttemptUsage | undefined {\n return usage === undefined ? acc : foldCompletionUsage(acc, usage);\n}\n","/**\n * nexus-agents voter execution utilities\n *\n * Vote execution helpers including result creation, timeout handling,\n * retry logic, and simulation fallback.\n *\n * (Source: Extracted from voter-agents.ts per Issue #285)\n */\n\nimport type { Vote } from '../consensus/types.js';\nimport type {\n VoterRole,\n AgentVoteResult,\n VoteCompletionArgs,\n VotePromptContext,\n} from './vote-types.js';\nimport type { IModelAdapter, CompletionRequest, ILogger } from '../core/index.js';\nimport { getRandomProvider } from '../core/index.js';\nimport { withTimeout } from '../utils/async-utils.js';\nimport {\n VoterAttemptCollector,\n withVoterAttemptTelemetry,\n voteRetryContext,\n type VoterAttemptKind,\n} from './voter-attempt-events.js';\nimport { trackVoterCompletion } from './voter-late-settlement.js';\nimport { cancelledSeat, isCancelled, seatSignal, unlessCancelled } from './voter-cancel.js';\nimport { waitForVoteRetry } from './voter-cancel.js';\nimport { getVoterPrompts, SIMULATED_VOTE_REASONING } from './voter-prompts.js';\nimport {\n buildVotePrompt,\n parseVoteResponse,\n SyntheticVoteError,\n VOTE_JSON_SCHEMA,\n} from './voter-response.js';\n\n// Import timeout constants from canonical source (Issue #984)\nimport {\n VOTE_TIMEOUTS,\n resolveVoteTimeout as _resolveVoteTimeout,\n validateTimeout as _validateTimeout,\n} from '../config/timeouts.js';\nimport { CLI_NAMES, type CliNameLiteral } from '../config/model-capabilities-types.js';\nimport { extractTextFromResponse, isStructuredOutputUnsupported } from './voter-response-text.js';\nimport { foldCompletionUsage, type AttemptUsage } from '../observability/attempt-usage.js';\n\nexport { extractTextFromResponse };\n\n/** Default vote timeout. Canonical source: `config/timeouts.ts`. */\nexport const DEFAULT_VOTE_TIMEOUT_MS = VOTE_TIMEOUTS.defaultMs;\n\n/** Resolves vote timeout with env var override. Canonical: `config/timeouts.ts`. */\nexport const resolveVoteTimeout = _resolveVoteTimeout;\n\n/** Maximum vote timeout. Canonical source: `config/timeouts.ts`. */\nexport const MAX_VOTE_TIMEOUT_MS = VOTE_TIMEOUTS.maxMs;\n\n/** Minimum vote timeout. Canonical source: `config/timeouts.ts`. */\nexport const MIN_VOTE_TIMEOUT_MS = VOTE_TIMEOUTS.minMs;\n\n/** Maximum retries per vote. Canonical source: `config/timeouts.ts`. */\nexport const DEFAULT_MAX_RETRIES = VOTE_TIMEOUTS.maxRetries;\n\n/**\n * Initial retry delay in milliseconds.\n */\nconst INITIAL_RETRY_DELAY_MS = 1_000;\n\n/**\n * Retry delay for rate-limit errors in milliseconds (Issue #1319).\n * Longer than standard to respect API rate limits.\n */\nexport const RATE_LIMIT_RETRY_DELAY_MS = 5_000;\n\n// Rate-limit detection and failed-attempt logging live in a sibling (#6821\n// made room here); `isRateLimitError` stays exported from this module.\nimport { isRateLimitError, logAbandonedRetries, logFailedAttempt } from './voter-attempt-log.js';\nimport { readVoteUsage, foldAttempt } from './voter-attempt-usage.js';\nimport { VOTER_ACCESS_MODE } from './voter-cli-access.js';\nexport { isRateLimitError };\n\n/**\n * Validates and clamps timeout to `[VOTE_TIMEOUTS.minMs, VOTE_TIMEOUTS.maxMs]`.\n *\n * **Canonical source:** `config/timeouts.ts`. This re-export exists for\n * back-compat — new code should import from `../config/timeouts.js`\n * directly (#2637).\n */\nexport const validateTimeout = _validateTimeout;\n\n// ============================================================================\n// Vote Result Helpers\n// ============================================================================\n\n/**\n * Creates an error vote result (abstain with error message).\n * Issue #523: Uses source: 'error' instead of 'llm' for accuracy.\n */\nexport function createErrorVoteResult(\n role: VoterRole,\n errorMsg: string,\n processingTimeMs: number,\n providerId?: string\n): AgentVoteResult {\n const bareCli =\n providerId?.startsWith('cli-') === true ? providerId.slice('cli-'.length) : providerId;\n const cli =\n bareCli !== undefined && (CLI_NAMES as readonly string[]).includes(bareCli)\n ? (bareCli as CliNameLiteral)\n : undefined;\n return {\n role,\n vote: {\n decision: 'abstain',\n reasoning: `[Error] Vote execution failed: ${errorMsg}`,\n confidence: 0,\n },\n processingTimeMs,\n source: 'error',\n error: errorMsg,\n ...(cli !== undefined ? { cli } : {}),\n };\n}\n\n/**\n * Creates a simulation vote result.\n */\nexport function createSimulationVoteResult(\n role: VoterRole,\n proposal: string,\n processingTimeMs: number,\n error?: string\n): AgentVoteResult {\n return {\n role,\n vote: simulateVote(role, proposal),\n processingTimeMs,\n source: 'simulation',\n ...(error !== undefined && { error }),\n };\n}\n\n/**\n * Creates simulated votes for multiple roles.\n */\nexport function createSimulatedVotes(\n roles: readonly VoterRole[],\n proposal: string,\n error?: string\n): readonly AgentVoteResult[] {\n const random = getRandomProvider();\n return roles.map((role) =>\n createSimulationVoteResult(role, proposal, random.randomInt(0, 100), error)\n );\n}\n\n/**\n * Role-specific vote distributions for simulation.\n * Each role has weighted probabilities reflecting their typical concerns:\n * - security: More skeptical, finds potential issues\n * - architect: Technically focused, generally supportive of good design\n * - devex: Balanced, considers usability\n * - ai_ml: Technically focused, evaluates AI aspects\n * - pm: Business focused, generally supportive of value\n *\n * Format: [approve_weight, reject_weight, abstain_weight]\n */\nconst ROLE_VOTE_DISTRIBUTIONS: Record<VoterRole, [number, number, number]> = {\n security: [40, 45, 15], // More skeptical - security concerns\n architect: [55, 30, 15], // Generally approving of good design\n devex: [50, 30, 20], // Balanced - considers usability\n ai_ml: [55, 30, 15], // Technical focus\n pm: [55, 25, 20], // Business focus - generally supportive\n catfish: [20, 65, 15], // Deliberately contrarian - challenges proposals (arXiv:2505.21503)\n scope_steward: [25, 60, 15], // Default-bias toward not shipping (#2185)\n};\n\n/**\n * Selects a decision based on weighted probabilities.\n */\nfunction selectWeightedDecision(\n weights: [number, number, number]\n): 'approve' | 'reject' | 'abstain' {\n const random = getRandomProvider();\n const total = weights[0] + weights[1] + weights[2];\n const rand = random.random() * total;\n\n if (rand < weights[0]) return 'approve';\n if (rand < weights[0] + weights[1]) return 'reject';\n return 'abstain';\n}\n\n/**\n * Fallback simulation when LLM is unavailable.\n * Uses role-specific vote distributions to provide more realistic simulation.\n * Clearly marks output as simulated.\n *\n * (Improved per Issue #453 - remove hardcoded 60% approve bias)\n */\nexport function simulateVote(role: VoterRole, proposal: string): Vote {\n const random = getRandomProvider();\n const weights = ROLE_VOTE_DISTRIBUTIONS[role];\n const decision = selectWeightedDecision(weights);\n\n // Confidence varies by decision type and role\n // Rejections tend to be higher confidence (found specific issue)\n // Approvals are moderate confidence (no issues found, but limited analysis)\n // Abstains are low confidence (insufficient information)\n let baseConfidence: number;\n if (decision === 'reject') {\n baseConfidence = 0.6 + random.random() * 0.3; // 0.6-0.9\n } else if (decision === 'approve') {\n baseConfidence = 0.5 + random.random() * 0.3; // 0.5-0.8\n } else {\n baseConfidence = 0.3 + random.random() * 0.2; // 0.3-0.5\n }\n\n return {\n decision,\n reasoning: `[Simulated - no LLM available] ${SIMULATED_VOTE_REASONING[role]} Proposal: \"${proposal.slice(0, 50)}...\"`,\n confidence: baseConfidence,\n };\n}\n\n// ============================================================================\n// Timeout and Retry Utilities\n// ============================================================================\n\n// Re-export from canonical source for backward compatibility\nexport { withTimeout, delay } from '../utils/async-utils.js';\n\n// ============================================================================\n// Vote Attempt Execution\n// ============================================================================\n\n/**\n * Executes a single vote attempt (no retries).\n *\n * By default, throws SyntheticVoteError if response parsing fails.\n * This ensures we only get real LLM votes, not synthetic fallbacks.\n * (Source: Issue #512 - Fail-safe voting)\n */\n/**\n * Builds the vote completion request. `withResponseFormat` toggles the native\n * structured-output ask (#3433): on for the first attempt, off for the #3497\n * retry against backends that route `json_schema` through provider tool-use.\n * The `parseVoteResponse` regex/Zod path below accepts prose-wrapped JSON, so\n * omitting `responseFormat` is safe — it just loses the schema-enforced shape.\n */\nfunction buildVoteRequest({\n role,\n proposal,\n timeoutMs,\n withResponseFormat,\n options,\n project,\n workspace,\n workspaceSha,\n signal,\n}: VoteCompletionArgs): CompletionRequest {\n const base: CompletionRequest = {\n messages: [\n // #6110: the seat judges the caller's target project, not this\n // repository's. `undefined` renders the `nexus-agents` default.\n { role: 'system', content: getVoterPrompts(project)[role] },\n // #6254: and the working directory the seats run in, so a seat with\n // file tools knows where the artifact is and that reading it is expected.\n { role: 'user', content: buildVotePrompt(proposal, options, workspace, workspaceSha) },\n ],\n // 4000 (#4131): headroom so a findings-bearing verdict (JSON envelope +\n // reasoning + structured findings) isn't cut mid-JSON by the token cap and\n // silently dropped. Was 2000 (#2245, up from 500); large contrarian findings\n // still overflowed it. Non-findings votes stop at natural completion, so the\n // higher cap adds no cost for them.\n maxTokens: 4000,\n temperature: 0.3, // Low temperature for consistent evaluations\n // Thread the vote budget so the CLI timeout doesn't fire first (#3304); pass\n // signal too for CLI-vs-API cancellation parity (#3036/#3304). #6729: the\n // signal also carries panel cancel and the overall cutoff, so neither\n // leaves the underlying adapter running after the seat is discarded.\n timeoutMs,\n ...(workspace !== undefined && workspace.trim() !== '' ? { workDir: workspace } : {}),\n // #6754: every seat — consensus_vote, pr_review and the other panels that\n // share this path — reads the artifact and answers; it never needs to run\n // commands, edit files or fetch. A CLI that cannot enforce that refuses\n // the seat, and the panel's error policy counts it.\n accessMode: VOTER_ACCESS_MODE,\n signal: seatSignal(timeoutMs, signal),\n };\n return withResponseFormat\n ? { ...base, responseFormat: { type: 'json_schema', schema: VOTE_JSON_SCHEMA } }\n : base;\n}\n\n/**\n * Per-call token usage reported by the adapter for one voter completion (#3910).\n * Propagated up so per-decision cost aggregation can attribute spend per voter.\n *\n * Token fields are OPTIONAL: an adapter that does not report usage (CLI\n * subscription, or a `usage` object missing the counts) leaves them `undefined`\n * so the voter stays honestly UNMEASURED downstream — never a fabricated 0.\n */\nexport interface VoteUsage {\n readonly inputTokens?: number | undefined;\n readonly outputTokens?: number | undefined;\n /** Input tokens read from an existing prompt cache, when reported (#4435). */\n readonly cachedInputTokens?: number | undefined;\n /** Input tokens spent writing the cache, when reported (#4435). */\n readonly cacheCreationInputTokens?: number | undefined;\n}\n\n/** One completion attempt: build → complete (timeout-bounded) → extract text + usage. */\nasync function runVoteCompletion(\n args: VoteCompletionArgs\n): Promise<Omit<VoteAttemptSuccess, 'vote'> | VoteAttemptFailure> {\n const collector = args.attemptCollector;\n let attemptEventId: string | undefined;\n collector?.started();\n // Observe the raw response BEFORE timeout/cancel racing can hide settlement.\n const call = args.adapter.complete(buildVoteRequest(args)).then((response) => {\n if (response.ok)\n attemptEventId = collector?.settled(\n args.role,\n args.adapter,\n response.value,\n args.attemptKind ?? 'initial',\n args.withinRoleRetry\n );\n return response;\n });\n const timeoutResult = await withTimeout(\n unlessCancelled(trackVoterCompletion(call, args.signal), args.signal),\n args.timeoutMs,\n `Vote timeout after ${String(args.timeoutMs)}ms for role: ${args.role}`\n );\n if (!timeoutResult.ok) return { ok: false, error: timeoutResult.error };\n const response = timeoutResult.value;\n if (!response.ok) {\n return { ok: false, error: response.error.message, retryable: response.error.retryable };\n }\n const usage = readVoteUsage(response.value);\n return {\n ok: true,\n output: extractTextFromResponse(response.value.content),\n attemptEventId,\n usage,\n // #6094: the transport's captured stderr rides up with the vote so the\n // caller can classify a seat that could not read the artifact from the\n // structured signal rather than from its prose.\n cliStderr: response.value.cliStderr,\n // #6115: the alias the seat asked for, when the CLI answered on another\n // one of its family (#6120) — the seat's result discloses it as a fallback.\n fallbackFrom: response.value.fallbackFrom,\n // #6660: the model the adapter reported answering — not `adapter.modelId`,\n // the alias requested. An empty report is no report.\n servedModel: response.value.model === '' ? undefined : response.value.model,\n };\n}\n\n/** A parsed vote plus what the transport reported alongside it. Module-private: its only consumer is the return type below. */\ninterface VoteAttemptSuccess {\n readonly ok: true;\n readonly vote: Vote;\n readonly output: string;\n readonly attemptEventId?: string | undefined;\n readonly usage: VoteUsage;\n /** Stderr the CLI transport captured for this completion, when any (#6094). */\n readonly cliStderr: string | undefined;\n /** The requested model alias when the CLI answered on another of its family (#6120). */\n readonly fallbackFrom: string | undefined;\n /** The model the adapter reported answering (#6660); undefined when it reported none. */\n readonly servedModel: string | undefined;\n}\n\n/** What the prompt carries beyond the proposal: declared options (#4472), the target project (#6110) and the working directory (#6254). */\n/**\n * A failed attempt. `cliStderr` is present only on the parse-failure branch —\n * the transport completed but the output was not a vote (#6269): it says WHY\n * the answer was empty. An adapter error carries its cause in `error`.\n */\ninterface VoteAttemptFailure {\n readonly ok: false;\n readonly error: string;\n /** Only explicit false suppresses retries; timeout and parse errors remain retryable. */\n readonly retryable?: boolean | undefined;\n readonly cliStderr?: string | undefined;\n /**\n * Parse-failure branch only (#6821): the transport completed and billed, so\n * its reported usage rides on the failure instead of being discarded.\n */\n readonly usage?: VoteUsage | undefined;\n /** Parse-failure branch only (#6957): the answer that was not a vote, for the failure log. */\n readonly rawOutput?: string | undefined;\n /**\n * Set by {@link executeWithRetries} (#6821): usage summed over every attempt\n * that settled with a response. Absent when none did.\n */\n readonly attemptUsage?: AttemptUsage | undefined;\n readonly attemptTelemetry?:\n import('../observability/attempt-usage.js').AttemptTelemetry | undefined;\n}\n\nexport async function executeSingleVoteAttempt(\n role: VoterRole,\n proposal: string,\n adapter: IModelAdapter,\n timeoutMs: number,\n context: VotePromptContext = {}\n): Promise<VoteAttemptSuccess | VoteAttemptFailure> {\n const completionArgs = {\n role,\n proposal,\n adapter,\n timeoutMs,\n project: context.project,\n workspace: context.workspace,\n ...context,\n };\n let completion = await runVoteCompletion({ ...completionArgs, withResponseFormat: true });\n // #3497: retry once WITHOUT responseFormat when the backend rejects the\n // tool-use-backed structured-output ask, so the panel keeps full strength.\n if (\n !completion.ok &&\n completion.retryable !== false &&\n isStructuredOutputUnsupported(completion.error)\n ) {\n completion = await runVoteCompletion({\n ...completionArgs,\n withResponseFormat: false,\n attemptKind: 'error_retry',\n });\n }\n if (!completion.ok) return completion;\n\n return parseVoteCompletion(completion, role, context);\n}\n\nfunction parseVoteCompletion(\n completion: Omit<VoteAttemptSuccess, 'vote'>,\n role: VoterRole,\n context: VotePromptContext\n): VoteAttemptSuccess | VoteAttemptFailure {\n try {\n // parseVoteResponse throws SyntheticVoteError if parsing fails — we only\n // accept real LLM votes, not synthetic fallbacks.\n const vote = parseVoteResponse(completion.output, role, context.options);\n context.attemptCollector?.classified(completion.attemptEventId, 'parsed');\n return {\n ok: true,\n vote,\n output: completion.output,\n usage: completion.usage,\n cliStderr: completion.cliStderr,\n fallbackFrom: completion.fallbackFrom,\n servedModel: completion.servedModel,\n };\n } catch (error) {\n if (error instanceof SyntheticVoteError) {\n context.attemptCollector?.classified(completion.attemptEventId, 'parse_failed');\n return {\n ok: false,\n error: `Vote parsing failed: ${error.message}`,\n cliStderr: completion.cliStderr,\n usage: completion.usage,\n rawOutput: error.rawOutput,\n };\n }\n throw error; // Re-throw unexpected errors\n }\n}\n\n/** Options for executeWithRetries. */\nexport interface RetryOptions {\n readonly role: VoterRole;\n readonly proposal: string;\n readonly adapter: IModelAdapter;\n readonly logger: ILogger;\n readonly timeoutMs: number;\n readonly maxRetries: number;\n /** Declared options for a multi-option proposal (#4472); absent for yes/no. */\n readonly options?: readonly string[] | undefined;\n /** Target project for the system prompt (#6110); absent ⇒ `nexus-agents`. */\n readonly project?: string | undefined;\n /** Working directory named in the user prompt (#6254); absent ⇒ no REPOSITORY ACCESS block. */\n readonly workspace?: string | undefined;\n readonly workspaceSha?: string | undefined;\n /**\n * Panel cancel or overall cutoff. Reaches the adapter call in flight,\n * combined with the per-attempt deadline, and stops further attempts.\n */\n readonly signal?: AbortSignal | undefined;\n readonly attemptCollector?: VoterAttemptCollector | undefined;\n readonly attemptKind?: VoterAttemptKind | undefined;\n readonly withinRoleRetry?: boolean | undefined;\n}\n\n/**\n * What a successful vote attempt hands the result builder: the parsed vote,\n * its usage, the transport's stderr (#6094) and any in-family model\n * substitution (#6120, disclosed as a fallback by #6115).\n */\nexport interface VoteOutcome {\n readonly vote: Vote;\n readonly usage: VoteUsage;\n readonly cliStderr: string | undefined;\n readonly fallbackFrom: string | undefined;\n /** The model the adapter reported answering (#6660); undefined when it reported none. */\n readonly servedModel: string | undefined;\n /**\n * Usage summed over EVERY attempt of this seat that settled with a response,\n * the answering one included (#6821). `usage` stays the answering\n * completion's own report.\n */\n readonly attemptUsage: AttemptUsage;\n readonly attemptTelemetry?:\n import('../observability/attempt-usage.js').AttemptTelemetry | undefined;\n}\n\n/** A failure carrying the seat's attempt usage, when any attempt settled. */\nfunction withAttemptUsage(\n failure: VoteAttemptFailure,\n attemptUsage: AttemptUsage | undefined\n): VoteAttemptFailure {\n const { usage: _single, rawOutput: _raw, ...rest } = failure;\n return attemptUsage === undefined ? rest : { ...rest, attemptUsage };\n}\n\n/** The success a retry loop returns: the answer plus every attempt's usage (#6821). */\nfunction toOutcome(\n result: VoteAttemptSuccess,\n prior: AttemptUsage | undefined\n): VoteOutcome & { ok: true } {\n const { vote, usage, cliStderr, fallbackFrom, servedModel } = result;\n const attemptUsage = foldCompletionUsage(prior, usage);\n return { vote, usage, cliStderr, fallbackFrom, servedModel, attemptUsage, ok: true };\n}\n\n/**\n * Executes vote attempts with retry logic. A failure carries the last\n * attempt's error; both outcomes carry the usage of every settled attempt.\n */\nexport async function executeWithRetries(\n opts: RetryOptions\n): Promise<(VoteOutcome & { ok: true }) | VoteAttemptFailure> {\n const collector = opts.attemptCollector ?? new VoterAttemptCollector();\n const result = await runVoteRetries({ ...opts, attemptCollector: collector });\n return withVoterAttemptTelemetry(result, () => collector.snapshot());\n}\n\nasync function waitForNextAttempt(\n opts: RetryOptions,\n attempt: number,\n lastError: string\n): Promise<boolean> {\n if (attempt === 0) return true;\n const isRateLimit = isRateLimitError(lastError);\n const baseDelay = isRateLimit ? RATE_LIMIT_RETRY_DELAY_MS : INITIAL_RETRY_DELAY_MS;\n const delayMs = baseDelay * Math.pow(2, attempt - 1);\n opts.logger.debug('Retrying vote execution', { role: opts.role, attempt, delayMs, isRateLimit });\n return waitForVoteRetry(delayMs, opts.signal);\n}\n\nasync function runVoteRetries(\n opts: RetryOptions\n): Promise<(VoteOutcome & { ok: true }) | VoteAttemptFailure> {\n const { role, proposal, adapter, logger, timeoutMs, maxRetries } = opts;\n let lastError = '';\n let parseFailed = false;\n // #6821: every settled completion is billed, so every one is recorded.\n let attemptUsage: AttemptUsage | undefined;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n // #6729: a cancelled panel makes no further adapter call, first or retry.\n if (isCancelled(opts.signal)) return withAttemptUsage(cancelledSeat(lastError), attemptUsage);\n if (!(await waitForNextAttempt(opts, attempt, lastError))) {\n return withAttemptUsage(cancelledSeat(lastError), attemptUsage);\n }\n\n // #2472: per-attempt timing breakdown so investigators can see which\n // retry succeeded (or which attempt blew the cap). Total vote time\n // is already captured at the call-site; this fills the per-attempt gap.\n const attemptStart = Date.now();\n const context = voteRetryContext(opts, attempt, parseFailed);\n const result = await executeSingleVoteAttempt(role, proposal, adapter, timeoutMs, context);\n const attemptMs = Date.now() - attemptStart;\n if (result.ok) {\n logger.info('Vote attempt timing', {\n role,\n attempt: attempt + 1,\n attemptMs,\n succeeded: true,\n });\n return toOutcome(result, attemptUsage);\n }\n\n attemptUsage = foldAttempt(attemptUsage, result.usage);\n lastError = result.error;\n // Only parse failures carry rawOutput, including an empty response.\n parseFailed = result.rawOutput !== undefined;\n const terminal = logFailedAttempt(logger, {\n role,\n attempt,\n maxRetries,\n attemptMs,\n error: lastError,\n retryable: result.retryable,\n cliStderr: result.cliStderr,\n rawOutput: result.rawOutput,\n });\n if (terminal !== null) {\n logAbandonedRetries(logger, role, attempt, maxRetries, terminal);\n if (result.retryable === false) return withAttemptUsage(result, attemptUsage);\n break;\n }\n }\n\n const error = lastError !== '' ? lastError : 'Unknown error after all retries';\n return withAttemptUsage({ error, ok: false }, attemptUsage);\n}\n","/**\n * Overall-deadline racing for consensus voting (Issue #1871).\n *\n * Defensive layer above per-vote timeouts: even if a single\n * executeAgentVote() promise never settles (subprocess adapter hang,\n * IPC wait that swallows timeout, etc.), this helper guarantees the\n * whole consensus call returns bounded partial results.\n *\n * Each role's vote promise is raced against a shared wall-clock\n * deadline. Any role whose promise has not settled when the deadline\n * fires is filled with createErrorVoteResult('overall consensus\n * deadline exceeded'), preserving role order so downstream aggregation\n * stays deterministic.\n */\nimport type { IModelAdapter, ILogger } from '../core/index.js';\nimport type { AgentVoteResult, SeatAttemptTiming, VoterRole } from './vote-types.js';\nimport { createErrorVoteResult, delay } from './voter-execution.js';\nimport { crossCliFallback, withAssignedCli } from './voter-fallback.js';\nimport { carryAttemptUsage } from './voter-attempt-usage.js';\nimport {\n VoterAttemptCollector,\n withVoterAttemptTelemetry,\n preserveVoterAttemptTelemetry,\n type VoterAttemptKind,\n} from './voter-attempt-events.js';\nimport { observeLateVoter } from './voter-late-settlement.js';\nimport { getMcpSafeDeadlineMs, VOTE_TIMEOUTS } from '../config/timeouts.js';\n\n/** Worst-case legitimate vote time plus stagger and buffer (#1871). */\nexport function computeOverallConsensusDeadlineMs(\n timeoutMs: number,\n maxRetries: number,\n roleCount: number,\n interDelayMs: number\n): number {\n const perVoteBudget = timeoutMs * (maxRetries + 1);\n const staggerBudget = Math.max(0, roleCount - 1) * interDelayMs;\n return perVoteBudget + staggerBudget + VOTE_TIMEOUTS.overallDeadlineBufferMs;\n}\n\n/** One deadline for first pass, backoff, and retry; clamped below the MCP wrapper (#2105). */\nexport function resolvePanelDeadline(\n timeoutMs: number,\n maxRetries: number,\n roleCount: number,\n interDelayMs: number,\n logger: ILogger\n): { overallDeadlineMs: number; deadlineAtMs: number } {\n const computedDeadlineMs = computeOverallConsensusDeadlineMs(\n timeoutMs,\n maxRetries,\n roleCount,\n interDelayMs\n );\n const overallDeadlineMs = getMcpSafeDeadlineMs(computedDeadlineMs, 'consensus_vote');\n if (overallDeadlineMs < computedDeadlineMs) {\n logger.debug('Consensus deadline clamped to MCP wrapper timeout', {\n computedDeadlineMs,\n overallDeadlineMs,\n });\n }\n return { overallDeadlineMs, deadlineAtMs: Date.now() + overallDeadlineMs };\n}\n\nexport interface VoteOptions {\n readonly timeoutMs: number;\n readonly maxRetries: number;\n readonly allowSimulation: boolean;\n /** The panel's cancel (#6729); combined with this seat's overall cutoff at launch. */\n readonly signal?: AbortSignal | undefined;\n readonly attemptCollector?: VoterAttemptCollector | undefined;\n readonly attemptKind?: VoterAttemptKind | undefined;\n readonly withinRoleRetry?: boolean | undefined;\n}\n\nexport type VoteFn = (\n role: VoterRole,\n proposal: string,\n adapter: IModelAdapter,\n logger: ILogger,\n options: VoteOptions\n) => Promise<AgentVoteResult>;\n\nexport interface LaunchVotesInput {\n readonly roles: readonly VoterRole[];\n readonly proposal: string;\n readonly roleAdapters: ReadonlyMap<VoterRole, IModelAdapter>;\n readonly fallbackAdapter: IModelAdapter;\n readonly logger: ILogger;\n readonly voteOptions: VoteOptions;\n readonly interDelay: number;\n readonly overallDeadlineMs: number;\n /** Absolute wall-clock cutoff shared with an optional per-role retry pass. */\n readonly deadlineAtMs?: number;\n /** Vote launcher (injected by caller — typically executeAgentVote). */\n readonly voteFn: VoteFn;\n /**\n * Called as each seat settles — first pass, fallback and retry alike — with\n * that seat's result (#6162). The async-job liveness heartbeat: a vote body\n * running past the standard MCP ceiling reports progress per seat through\n * this, so a panel whose seats keep landing is never failed as wedged.\n */\n readonly onVoteCollected?: ((vote: AgentVoteResult) => void) | undefined;\n /**\n * Cancellation for in-flight panels (#5393).\n *\n * Checked after each stagger delay, so a cancel stops LAUNCHING the voters\n * that have not started, and before the cross-CLI fallback. Aborting the\n * seats already in flight is not done here: the same signal rides in\n * `voteOptions` to each seat's adapter call (#6729), where it is combined\n * with the seat's deadline.\n *\n * Absent or un-aborted changes nothing.\n */\n readonly signal?: AbortSignal | undefined;\n}\n\nexport const DEADLINE_MESSAGE = 'overall consensus deadline exceeded';\n/**\n * #5393: reported for a voter the panel never launched. An ERROR result, never\n * a default decision — a cancelled voter returning `approve` would manufacture\n * consensus out of work that never ran.\n */\nconst CANCELLED_MESSAGE = 'cancelled before this voter was launched';\n\n/**\n * #3587: a voter routed to a diverse CLI that hard-fails (e.g. an OpenRouter\n * model without tool-use → \"no endpoints that support tool use\", which the\n * responseFormat retry can't fix) would silently shrink the panel. Retry once on\n * the known-good fallback adapter so one bad CLI cannot drop a voter.\n *\n * Should a failed vote be retried on the fallback adapter? Only when the diverse\n * adapter produced a genuine error (not the overall-deadline filler, which means\n * there's no time left) AND it wasn't already the fallback (#3587).\n */\nfunction shouldRetryOnFallback(\n result: AgentVoteResult,\n used: IModelAdapter,\n fallback: IModelAdapter\n): boolean {\n return (\n result.source === 'error' &&\n result.error !== DEADLINE_MESSAGE &&\n adapterCliKey(used) !== adapterCliKey(fallback)\n );\n}\n\n/** Stable per-CLI key for an adapter; CLI adapters carry the CLI name. */\nfunction adapterCliKey(adapter: IModelAdapter): string {\n return (adapter as { name?: string }).name ?? adapter.providerId;\n}\n\n/**\n * Preserve the panel resolver's primary assignment across fallback execution:\n * the model it pinned, and (#6115) the CLI it chose, which unlike the model is\n * known before detection and so survives the `pending-detection` placeholder.\n */\nfunction withAssignment(\n result: AgentVoteResult,\n pinnedModel: string,\n assignedKey: string\n): AgentVoteResult {\n return withAssignedCli({ ...result, pinnedModel }, assignedKey);\n}\n\n/**\n * How many same-CLI seats may run at once (#6103). The default is one — the\n * #3348 serialization: concurrent subprocesses of one CLI each triggered its\n * OAuth access-token refresh, and with refresh-token rotation the first call\n * rotated the token and the rest failed \"refresh token already used\".\n *\n * `cli-claude` is widened to two on measurement: the first `Seat timing`\n * readout (#6387 panel, 2026-09-16) put 871 s of a ~12-minute panel in the\n * claude lane's queue — fallback seats waited 244–398 s behind three primary\n * claude runs — and a probe of 15 concurrent `claude -p` calls (2- and\n * 3-way) produced no refresh error. A collision at an actual refresh is\n * still possible; it surfaces as a retried attempt (`voter-retry.ts`) and\n * as a second attempt on the seat's timing line, which is the signal to\n * narrow this again. Cross-CLI parallelism is unchanged.\n */\nconst CLI_LANE_WIDTH: Readonly<Record<string, number>> = { 'cli-claude': 2 };\nconst DEFAULT_LANE_WIDTH = 1;\n\n/** The lane width for a CLI key: the table's entry, else one. */\nfunction laneWidthOf(key: string): number {\n return Object.hasOwn(CLI_LANE_WIDTH, key)\n ? (CLI_LANE_WIDTH[key] ?? DEFAULT_LANE_WIDTH)\n : DEFAULT_LANE_WIDTH;\n}\n\n/**\n * Per-key lane (#3348, widened per key by {@link CLI_LANE_WIDTH} in #6103).\n * Returns a `run(key, fn)` that admits at most `laneWidthOf(key)` fns per\n * key at a time, in FIFO order; a rejected fn frees its slot like a resolved\n * one so one failure cannot wedge the lane. Different keys run concurrently.\n */\nfunction createKeyedSerializer(): <T>(key: string, fn: () => Promise<T>) => Promise<T> {\n const lanes = new Map<string, { active: number; waiting: (() => void)[] }>();\n const laneFor = (key: string): { active: number; waiting: (() => void)[] } => {\n const existing = lanes.get(key);\n if (existing !== undefined) return existing;\n const created = { active: 0, waiting: [] };\n lanes.set(key, created);\n return created;\n };\n return async <T>(key: string, fn: () => Promise<T>): Promise<T> => {\n const lane = laneFor(key);\n if (lane.active >= laneWidthOf(key)) {\n await new Promise<void>((resolve) => lane.waiting.push(resolve));\n }\n lane.active += 1;\n try {\n return await fn();\n } finally {\n lane.active -= 1;\n lane.waiting.shift()?.();\n }\n };\n}\n\nfunction raceWithDeadline(\n run: (signal: AbortSignal) => Promise<AgentVoteResult>,\n role: VoterRole,\n deadlineMs: number,\n cancel: AbortSignal | undefined,\n afterDeadline: (vote: Promise<AgentVoteResult>, reason: DOMException, deadlineAt: number) => void\n): Promise<AgentVoteResult> {\n const deadlineController = new AbortController();\n const signal =\n cancel === undefined\n ? deadlineController.signal\n : AbortSignal.any([deadlineController.signal, cancel]);\n let timer: ReturnType<typeof setTimeout> | undefined;\n const timeoutP = new Promise<AgentVoteResult>((resolve) => {\n timer = setTimeout(() => {\n resolve(createErrorVoteResult(role, DEADLINE_MESSAGE, deadlineMs));\n const reason = new DOMException(DEADLINE_MESSAGE, 'TimeoutError');\n // Resolve the recorded deadline error first: an adapter that reacts to\n // abort immediately must not turn this seat into a cancellation result.\n const deadlineAt = Date.now();\n deadlineController.abort(reason);\n afterDeadline(voteP, reason, deadlineAt);\n }, deadlineMs);\n });\n const voteP = Promise.resolve().then(() => run(signal));\n return Promise.race([voteP, timeoutP]).finally(() => {\n if (timer !== undefined) clearTimeout(timer);\n });\n}\n\n/**\n * Read through a function, not inline (#5393): after one\n * `signal?.aborted === true` check TypeScript narrows the field to `false` for\n * the rest of the enclosing closure, which is unsound across an `await` — the\n * whole point is that it can flip while a vote is in flight.\n */\nfunction cancelled(signal: AbortSignal | undefined): boolean {\n return signal?.aborted === true;\n}\n\n/** Both attempts travel with a recovered seat (#6103): the failed primary's timing first. */\nfunction withPrimaryAttempts(\n primary: AgentVoteResult,\n recovered: AgentVoteResult\n): AgentVoteResult {\n const carried = carryAttemptUsage(primary, recovered);\n return preserveVoterAttemptTelemetry(carried, {\n // #6821: the failed primary's settled completions were billed too.\n ...carried,\n timing: {\n attempts: [...(primary.timing?.attempts ?? []), ...(recovered.timing?.attempts ?? [])],\n },\n });\n}\n\ntype VoteOnAdapter = (\n role: VoterRole,\n adapter: IModelAdapter,\n fallback: boolean\n) => Promise<AgentVoteResult>;\n\n/** Start a seat only while the shared cutoff still has time. */\nfunction voteBeforeDeadline(\n input: LaunchVotesInput,\n role: VoterRole,\n adapter: IModelAdapter,\n remaining: number\n): Promise<AgentVoteResult> {\n if (remaining <= 0) {\n return Promise.resolve(createErrorVoteResult(role, DEADLINE_MESSAGE, input.overallDeadlineMs));\n }\n const observer = observeLateVoter(adapter, role, input.logger);\n const collector = new VoterAttemptCollector();\n const result = raceWithDeadline(\n (signal) => {\n observer.register(signal);\n return input.voteFn(role, input.proposal, adapter, input.logger, {\n ...input.voteOptions,\n attemptCollector: collector,\n signal,\n });\n },\n role,\n remaining,\n input.signal,\n (vote, reason, deadlineAt) => {\n // A measurement must never take down the deadline path: this runs in a\n // timer callback, where a throw is an uncaught exception (#6851).\n try {\n observer.afterDeadline(vote, reason, deadlineAt);\n } catch (error) {\n input.logger.warn('Late-settlement observer failed; deadline unaffected', {\n role,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n );\n return result.then((vote) => withVoterAttemptTelemetry(vote, () => collector.snapshot()));\n}\n\nasync function launchRoleVote(\n role: VoterRole,\n index: number,\n input: LaunchVotesInput,\n voteOnAdapter: VoteOnAdapter,\n deadlineAtMs: number\n): Promise<AgentVoteResult> {\n // A retry can begin with less time left than the nominal stagger delay.\n const staggerWaitMs = Math.min(input.interDelay, Math.max(0, deadlineAtMs - Date.now()));\n if (index > 0 && staggerWaitMs > 0) await delay(staggerWaitMs);\n const adapter = input.roleAdapters.get(role) ?? input.fallbackAdapter;\n const pinnedModel = adapter.modelId;\n const assignedKey = adapterCliKey(adapter);\n const stamp = (r: AgentVoteResult): AgentVoteResult =>\n preserveVoterAttemptTelemetry(r, withAssignment(r, pinnedModel, assignedKey));\n if (cancelled(input.signal)) {\n // Refused before any attempt: the timing says so with an empty list.\n return stamp({\n ...createErrorVoteResult(role, CANCELLED_MESSAGE, 0),\n timing: { attempts: [] },\n });\n }\n const primary = await voteOnAdapter(role, adapter, false);\n if (!shouldRetryOnFallback(primary, adapter, input.fallbackAdapter)) return stamp(primary);\n if (cancelled(input.signal)) return stamp(primary);\n input.logger.warn('Voter failed on diverse adapter; retrying on fallback (#3587)', {\n role,\n failedCli: assignedKey,\n fallbackCli: adapterCliKey(input.fallbackAdapter),\n error: primary.error,\n });\n const recovered = withPrimaryAttempts(\n primary,\n await voteOnAdapter(role, input.fallbackAdapter, true)\n );\n if (recovered.source === 'error') return stamp(recovered);\n // #6115: the seat ANSWERED somewhere other than where it was assigned. Say\n // where it was meant to answer and which error class moved it, so a panel\n // that collapsed onto one model during a capacity window is legible in the\n // result rather than only in this log line. A seat that errored on the\n // fallback too answered nowhere and carries no fallback.\n const fallback = crossCliFallback(adapter, assignedKey, primary.error ?? '');\n return stamp(preserveVoterAttemptTelemetry(recovered, { ...recovered, fallback }));\n}\n\nfunction createTimedVoteLauncher(input: LaunchVotesInput, deadlineAtMs: number): VoteOnAdapter {\n const serialize = createKeyedSerializer();\n\n // One serialized, deadline-bounded vote attempt on a specific adapter.\n // #6103: the attempt's timing rides on the result — queued (enqueue → start)\n // and ran (start → settle) — so a slow panel can be attributed to the lane\n // or to the model. The caller folds attempts into the seat's `timing`.\n const voteOnAdapter = (\n role: VoterRole,\n adapter: IModelAdapter,\n fallback: boolean\n ): Promise<AgentVoteResult> => {\n const cli = adapterCliKey(adapter);\n const enqueuedAt = Date.now();\n // Serialize per CLI so concurrent same-CLI calls don't race that CLI's\n // OAuth refresh (#3348). The deadline is measured when the vote actually\n // starts, so a queued role still gets a correct remaining budget.\n return serialize(cli, async () => {\n const runStartedAt = Date.now();\n const remaining = deadlineAtMs - runStartedAt;\n // A role can wait past the cutoff in a stagger or serialized CLI lane.\n // Record absence as an error; do not start an adapter with a fresh 1 ms.\n const result = await voteBeforeDeadline(\n {\n ...input,\n voteOptions: {\n ...input.voteOptions,\n attemptKind: fallback ? 'cli_fallback' : input.voteOptions.attemptKind,\n withinRoleRetry:\n input.voteOptions.withinRoleRetry === true ||\n input.voteOptions.attemptKind === 'role_retry',\n },\n },\n role,\n adapter,\n remaining\n );\n const attempt: SeatAttemptTiming = {\n cli,\n queuedMs: runStartedAt - enqueuedAt,\n ranMs: Date.now() - runStartedAt,\n fallback,\n };\n return withVoterAttemptTelemetry(\n { ...result, timing: { attempts: [...(result.timing?.attempts ?? []), attempt] } },\n () => result.attemptTelemetry ?? { events: [], observableAttempts: 0 }\n );\n });\n };\n\n return voteOnAdapter;\n}\n\nexport async function launchVotesWithOverallDeadline(\n input: LaunchVotesInput\n): Promise<readonly AgentVoteResult[]> {\n const { roles, logger, overallDeadlineMs } = input;\n\n const deadlineAtMs = input.deadlineAtMs ?? Date.now() + overallDeadlineMs;\n const voteOnAdapter = createTimedVoteLauncher(input, deadlineAtMs);\n\n const wrapped = roles.map((role, index) =>\n launchRoleVote(role, index, input, voteOnAdapter, deadlineAtMs).then((result) => {\n input.onVoteCollected?.(result);\n return result;\n })\n );\n\n const results = await Promise.all(wrapped);\n\n const expired = results.filter((r) => r.source === 'error' && r.error === DEADLINE_MESSAGE);\n if (expired.length > 0) {\n logger.warn('Consensus overall deadline reached; returning partial results', {\n totalRoles: roles.length,\n expiredRoles: expired.map((r) => r.role),\n overallDeadlineMs,\n });\n }\n return results;\n}\n","/**\n * Per-role retry of errored voter seats (#5578).\n *\n * Split out of `voter-agents.ts`, which was already at its 400-line cap.\n * @module cli/voter-retry\n */\n\nimport type { VoterRole, AgentVoteResult, RetriedFrom } from './vote-types.js';\nimport type { ILogger } from '../core/index.js';\nimport { clipForRecord } from '../audit/vote-record.js';\nimport { sleep } from '../utils/async-utils.js';\nimport { isAbsentSeat } from './voter-unverifiable.js';\nimport { isCancelled } from './voter-cancel.js';\nimport { DEADLINE_MESSAGE } from './voter-agents-deadline.js';\nimport { preserveVoterAttemptTelemetry } from './voter-attempt-events.js';\nimport { carryAttemptUsage } from './voter-attempt-usage.js';\n\n/**\n * C0 and C1 control characters, DEL included (#6246, security seat; the C1\n * range on the #6252 panel's rejection — `\\x9b` is the single-byte CSI,\n * equivalent to `ESC [`, so an ASCII-only range still let a terminal escape\n * through). A first-pass error string can be a subprocess's stderr; each of\n * these becomes one space so the carried cause cannot inject a line into the\n * summary row or the JSONL ledger line, nor an escape sequence into the\n * terminal.\n */\nconst CONTROL_CHARS_RE = /[\\x00-\\x1f\\x7f-\\x9f]/g;\n\n/**\n * What the retry is about to discard, carried onto the seat that replaces it\n * (#6246). `source` is the first pass's; `error` is its error string when it\n * had one — de-controlled, then bounded by the #5373 record clip so the marker\n * travels with it rather than a silent slice. Called only at the discard site,\n * so a seat that was never retried, or whose retry failed again, has no key.\n */\nfunction retriedFromOf(first: AgentVoteResult): RetriedFrom {\n const source = first.source === 'unverifiable' ? 'unverifiable' : 'error';\n if (first.error === undefined) return { source };\n const { text, truncated } = clipForRecord(first.error.replace(CONTROL_CHARS_RE, ' '));\n return { source, error: text, ...(truncated === true ? { errorTruncated: true as const } : {}) };\n}\n\n/**\n * Backoff before retrying an errored voter role (#5578).\n *\n * Short on purpose: a voter at `source: 'error'` has already exhausted the\n * resilient adapter's own retries and breaker, so this is not a backoff for\n * that adapter — it is a gap for a transient panel-wide condition (a rate\n * limit window, a stalled gateway) to clear.\n */\nexport const DEFAULT_ERRORED_ROLE_BACKOFF_MS = 3000;\n\n/** Keep failure retryability local to one panel, across both passes and result copies. */\nexport function createVoterRetryState(): {\n nonRetryableRoles: ReadonlySet<VoterRole>;\n onError: (role: VoterRole, retryable: boolean | undefined) => void;\n} {\n const nonRetryableRoles = new Set<VoterRole>();\n return {\n nonRetryableRoles,\n onError: (role, retryable) => {\n // A cross-CLI fallback can fail differently; track its latest failure.\n if (retryable === false) nonRetryableRoles.add(role);\n else nonRetryableRoles.delete(role);\n },\n };\n}\n\n/**\n * Re-launch retryable absent roles once, unless the panel deadline was exhausted.\n *\n * The panel launches once. A voter that errors is dropped: under\n * `reduce_denominator` its seat silently leaves the denominator, and under\n * `absolute_quorum` the whole vote voids to `no_quorum` and the caller replays\n * all N voters for a single failure. Retrying just the errored roles recovers\n * the seat for one extra call instead of N.\n *\n * The empty case is named: a panel with no absent voter issues no retry and\n * returns its results untouched. When any seat exhausts the shared overall\n * deadline, no seat gets a fresh whole-panel budget (#6811); their first-pass\n * results remain for the same quorum policy to decide.\n *\n * A role that errors again keeps its first-attempt result, so the existing\n * error policy still sees an errored seat and decides unchanged. This recovers\n * seats; it never manufactures one.\n *\n * An UNVERIFIABLE seat (#6094) is relaunched by the same call: it is an\n * absence, not a judgment. Exactly once — on the deterministic host failure a\n * second attempt is futile, so a retry that comes back unverifiable again\n * REPLACES the first result (marked `retried: true`) rather than looping, and\n * the panel records one entry for the role.\n */\n/** The absent seats to relaunch — none once the panel is cancelled (#6729). */\nfunction rolesToRetry(first: readonly AgentVoteResult[], options: RetryPassOptions): VoterRole[] {\n if (first.length === 0 || isCancelled(options.signal)) return [];\n // The launcher spent the shared overall budget; another pass would start a\n // fresh whole-panel deadline even for a different errored seat (#6811).\n if (first.some((v) => v.source === 'error' && v.error === DEADLINE_MESSAGE)) return [];\n return first\n .filter(\n (v) =>\n isAbsentSeat(v) && (v.source !== 'error' || options.nonRetryableRoles?.has(v.role) !== true)\n )\n .map((v) => v.role);\n}\n\ninterface RetryPassOptions {\n /** The panel cancel also suppresses the retry pass. */\n readonly signal?: AbortSignal | undefined;\n /** Shared wall-clock cutoff of both passes; absent for direct callers. */\n readonly deadlineAtMs?: number;\n /** Panel-local failure metadata; the public vote-result shape stays unchanged. */\n readonly nonRetryableRoles?: ReadonlySet<VoterRole>;\n}\n\nfunction retryWindowExpired(options: RetryPassOptions): boolean {\n return options.deadlineAtMs !== undefined && Date.now() >= options.deadlineAtMs;\n}\n\nasync function waitForRetryWindow(backoffMs: number, options: RetryPassOptions): Promise<boolean> {\n const remainingMs =\n options.deadlineAtMs === undefined ? backoffMs : options.deadlineAtMs - Date.now();\n const waitMs = Math.min(backoffMs, remainingMs);\n if (waitMs > 0) await sleep(waitMs);\n return !retryWindowExpired(options);\n}\n\nexport async function retryErroredRoles(\n first: readonly AgentVoteResult[],\n relaunch: (roles: readonly VoterRole[]) => Promise<readonly AgentVoteResult[]>,\n logger: ILogger,\n backoffMs: number,\n options: RetryPassOptions = {}\n): Promise<readonly AgentVoteResult[]> {\n const erroredRoles = rolesToRetry(first, options);\n if (erroredRoles.length === 0) return first;\n\n logger.warn('Retrying errored or unverifiable voter roles before aggregating (#5578, #6094)', {\n erroredRoles,\n unverifiableRoles: first.filter((v) => v.source === 'unverifiable').map((v) => v.role),\n of: first.length,\n });\n // A transient error near the end of the first pass may spend the remaining\n // budget in backoff without producing a deadline-error seat (#6811).\n if (!(await waitForRetryWindow(backoffMs, options))) return first;\n\n const retriedResults = await relaunch(erroredRoles);\n const firstByRole = new Map(first.map((v) => [v.role, v]));\n const recovered = new Map<VoterRole, AgentVoteResult>();\n for (const r of retriedResults) {\n if (r.source === 'error') continue;\n // #6246: this is where the first pass is discarded — carry what it was\n // before it goes, so the seat names both what it is and what it recovered\n // from. Every relaunched role has an absent first pass; the guard holds\n // the relaunch to that contract rather than carrying a `source` the first\n // pass never had.\n const prior = firstByRole.get(r.role);\n const from = prior !== undefined && isAbsentSeat(prior) ? retriedFromOf(prior) : undefined;\n const carried = carryAttemptUsage(prior, r);\n recovered.set(\n r.role,\n preserveVoterAttemptTelemetry(carried, {\n // #6821: the replaced first pass billed its completions too.\n ...carried,\n retried: true,\n ...(from !== undefined ? { retriedFrom: from } : {}),\n })\n );\n }\n const kept = keepFailedRetryUsage(first, retriedResults);\n if (recovered.size === 0) {\n logger.warn('Per-role retry recovered no voter — the panel stays degraded', { erroredRoles });\n return kept;\n }\n logger.info('Per-role retry recovered voters', {\n recoveredRoles: [...recovered.values()].filter((v) => v.source === 'llm').map((v) => v.role),\n stillUnverifiable: [...recovered.values()]\n .filter((v) => v.source === 'unverifiable')\n .map((v) => v.role),\n stillErrored: erroredRoles.filter((r) => !recovered.has(r)),\n });\n return kept.map((v) => recovered.get(v.role) ?? v);\n}\n\n/**\n * The first pass, with the usage of each retry that errored again folded into\n * its seat (#6821): the seat keeps its first result, but the failed retry's\n * settled completions were billed all the same.\n */\nfunction keepFailedRetryUsage(\n first: readonly AgentVoteResult[],\n retried: readonly AgentVoteResult[]\n): readonly AgentVoteResult[] {\n const failedByRole = new Map(retried.filter((r) => r.source === 'error').map((r) => [r.role, r]));\n return first.map((v) => {\n const failed = failedByRole.get(v.role);\n if (failed === undefined) return v;\n const carried = carryAttemptUsage(v, failed);\n return preserveVoterAttemptTelemetry(carried, {\n ...v,\n ...(carried.attemptUsage !== undefined ? { attemptUsage: carried.attemptUsage } : {}),\n });\n });\n}\n","/**\n * Codex CLI subagent limits (#2659, Epic D).\n *\n * Codex's `~/.codex/config.toml` `[agents]` section defaults to\n * `max_depth = 1` and `max_threads = 6` (verified against\n * developers.openai.com/codex config reference — the originating issue's\n * `max_thread_depth` key name was wrong).\n *\n * nexus-agents does NOT write the operator's global `~/.codex/config.toml`\n * (that would clobber operator-owned state) and does NOT silently\n * auto-flatten routing topology. Instead — Option C from the #2659 design\n * vote — it WARNS at fan-out time when a planned concurrency would exceed\n * Codex's defaults, so the operator can raise their own `[agents]` limits\n * or spread the panel across more CLIs. The two existing parallel-dispatch\n * sites are already conservative: `worker-dispatcher.ts` caps a wave at 3\n * concurrent workers, and `collectRealVotes` round-robins voter roles\n * across available CLIs. The warned case is the narrow one — a single-CLI\n * fallback where every voter role lands on Codex.\n *\n * @module cli-adapters/codex-limits\n * @see Issue #2659\n */\n\n/** Codex `[agents] max_depth` default — nested subagent depth. */\nexport const CODEX_DEFAULT_MAX_DEPTH = 1;\n\n/** Codex `[agents] max_threads` default — concurrent subagent threads. */\nexport const CODEX_DEFAULT_MAX_THREADS = 6;\n\n/**\n * A structured warning when `codexBoundConcurrency` parallel calls are\n * about to be dispatched to Codex, exceeding its default `max_threads`.\n * Returns `null` when within limits. Does not block — the operator stays\n * in control (Option C).\n */\nexport function checkCodexConcurrency(codexBoundConcurrency: number): string | null {\n if (codexBoundConcurrency <= CODEX_DEFAULT_MAX_THREADS) return null;\n return (\n `${String(codexBoundConcurrency)} parallel calls are bound for Codex, exceeding its ` +\n `default max_threads=${String(CODEX_DEFAULT_MAX_THREADS)}. Codex may queue or drop the ` +\n `excess. Raise [agents] max_threads in ~/.codex/config.toml, or spread the panel across ` +\n `more CLIs (claude/gemini) so fewer roles land on Codex.`\n );\n}\n\n// @export-no-consumer-yet — see #4555. Its sibling `checkCodexConcurrency` is\n// wired at `cli/voter-agents.ts:307`, but this one needs a *planned nesting\n// depth* and nothing in the tree tracks one: the voter fan-out is flat (voters\n// are leaf calls), and the only other `depth` values are MCTS and\n// reasoning-forest tree depths, which are unrelated concepts. So this was\n// written against information no caller has — wiring it means first\n// introducing depth tracking through the dispatch path, which is a feature and\n// not a missing line. Marked rather than deleted because the knowledge it\n// encodes (Codex `max_depth=1` rejects a nested spawn) is real and was added\n// deliberately in #2689.\n/**\n * A structured warning when a planned subagent nesting `depth` exceeds\n * Codex's default `max_depth`. Returns `null` when within limits.\n */\nexport function checkCodexDepth(depth: number): string | null {\n if (depth <= CODEX_DEFAULT_MAX_DEPTH) return null;\n return (\n `planned subagent nesting depth ${String(depth)} exceeds Codex's default ` +\n `max_depth=${String(CODEX_DEFAULT_MAX_DEPTH)}. Codex will reject the nested spawn. ` +\n `Raise [agents] max_depth in ~/.codex/config.toml, or flatten the expert chain.`\n );\n}\n","/**\n * Adapter resolution for a voter panel, and the documented no-adapter exit\n * (Issue #280): simulate when the caller explicitly allowed it, otherwise\n * throw.\n *\n * Split out of `voter-agents.ts` (#5578), which was at its 400-line cap.\n * @module cli/voter-adapter-resolve\n */\n\nimport type { IModelAdapter, ILogger } from '../core/index.js';\nimport { getErrorMessage } from '../core/index.js';\nimport { getGlobalRegistry } from '../adapters/unified-registry.js';\nimport { checkCodexConcurrency } from '../cli-adapters/codex-limits.js';\nimport type { VoterRole } from './vote-types.js';\n\n/** The adapter-bearing subset of the collect options this module needs. */\nexport interface AdapterResolveOptions {\n readonly adapter?: IModelAdapter | undefined;\n readonly gatewayAdapters?: readonly IModelAdapter[] | undefined;\n}\n\n/**\n * Error thrown when no adapter is available and simulation is disabled.\n */\nexport class NoAdapterError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'NoAdapterError';\n }\n}\n\n/**\n * Resolves the model adapter, handling errors per Issue #280.\n */\nexport function resolveAdapter(\n options: AdapterResolveOptions\n): { adapter: IModelAdapter } | { error: string } {\n try {\n if (options.adapter !== undefined) return { adapter: options.adapter };\n // #4040: prefer an in-process gateway adapter as the fallback so a\n // gateway-only environment (no CLIs installed) never hits the CLI registry,\n // which would throw \"No model adapter configured\".\n const gateway = options.gatewayAdapters;\n if (gateway !== undefined && gateway.length > 0 && gateway[0] !== undefined) {\n return { adapter: gateway[0] };\n }\n const registry = getGlobalRegistry();\n return { adapter: registry.getDefault() };\n } catch (error) {\n return { error: getErrorMessage(error) };\n }\n}\n\n/**\n * Resolve the adapter, or take the documented no-adapter exit (Issue #280):\n * simulate when the caller explicitly allowed it, otherwise throw.\n *\n * Extracted from `collectRealVotes` when #5578 pushed it past the 50-line and\n * complexity caps; behaviour is unchanged.\n */\nexport function resolveAdapterOrFail(\n options: AdapterResolveOptions,\n logger: ILogger,\n allowSimulation: boolean\n): { adapter: IModelAdapter } | { simulated: true } {\n const resolved = resolveAdapter(options);\n if (!('error' in resolved)) return resolved;\n\n logger.error('No adapter available for voting', undefined, { error: resolved.error });\n if (allowSimulation) {\n logger.warn('Falling back to simulation (allowSimulation=true)');\n return { simulated: true };\n }\n throw new NoAdapterError(\n `No adapter available for voting: ${resolved.error}. ` +\n 'Install a CLI (claude/gemini/codex) or set ANTHROPIC_API_KEY.'\n );\n}\n\n/**\n * #2659 — warn (don't block) when more voter roles land on Codex than its\n * default `max_threads`, e.g. a single-CLI fallback with a full panel.\n * Moved here from `voter-agents.ts` when the #6136/#6115 rebase put that\n * file over its line cap.\n */\nexport function warnIfCodexConcurrencyExceeded(\n roleAdapters: ReadonlyMap<VoterRole, IModelAdapter>,\n logger: ILogger\n): void {\n const codexBound = [...roleAdapters.values()].filter(\n (a) => (a as { name?: string }).name === 'codex'\n ).length;\n const warning = checkCodexConcurrency(codexBound);\n if (warning !== null) {\n logger.warn('Codex concurrency limit may be exceeded', { detail: warning });\n }\n}\n","/**\n * The working directory a consensus panel's seats are pointed at (#6258).\n *\n * One cwd per panel: the caller's explicit directory (the CLI's ratification\n * scratch checkout) or, absent one, `process.cwd()`. `collectRealVotes` hands\n * it to every seat and `executeVoting` stamps the same value on the live\n * result, so an `unverifiable` seat can be diagnosed without reading stderr.\n * Its own module so both call it without either importing the other's mocks.\n *\n * @module cli/panel-workspace\n */\n\n/** The directory a panel's seats are given: the caller's, else the process cwd. */\nexport function resolvePanelWorkspace(workspace: string | undefined): string {\n return workspace ?? process.cwd();\n}\n","/**\n * nexus-agents voter agents\n *\n * Real LLM-powered voter agents for consensus voting.\n * Replaces simulated voting with actual agent execution that\n * analyzes proposals.\n *\n * (Source: Issue #226, Sprint #229)\n * (Updated: Issue #280 - Fixed timeout handling, removed simulation fallback)\n * (Refactored: Issue #285 - Extracted response and execution utilities)\n *\n * File structure:\n * - voter-prompts.ts: System prompts for each voter role\n * - voter-response.ts: Response parsing and validation\n * - voter-execution.ts: Execution utilities (timeout, retry, result creation)\n * - voter-agents.ts: Main API (this file)\n */\n\nimport type {\n VoterRole,\n AgentVoteResult,\n VoteExecutionOverrides,\n VoteExecutionSettings,\n} from './vote-types.js';\nimport { resolveVoterModelOverrides } from './voter-model-overrides.js';\nimport { clisServingVoterSeats } from './voter-cli-access.js';\nimport { VOTER_ROLES } from './voter-roles.js';\nimport { createLogger, getTimeProvider, type IModelAdapter, type ILogger } from '../core/index.js';\nimport { getGlobalRegistry } from '../adapters/unified-registry.js';\nimport { getAvailableClis } from '../cli-adapters/factory.js';\nimport { authRemediation } from '../cli-adapters/cli-error-envelope.js';\nimport type { CliName } from '../cli-adapters/types.js';\nimport { countDistinctModels } from '../config/model-equivalence.js';\nimport { reportPanelIndependence, reportVoteIndependence } from './panel-independence.js';\nimport { dealSeatsAcrossFamilies, warnIfSingleFamily } from './voter-family-dealing.js';\nimport { DEFAULT_ERRORED_ROLE_BACKOFF_MS, retryErroredRoles } from './voter-retry.js';\nimport { createVoterRetryState } from './voter-retry.js';\nimport {\n NoAdapterError,\n resolveAdapterOrFail,\n warnIfCodexConcurrencyExceeded,\n} from './voter-adapter-resolve.js';\nimport {\n classifyUnverifiable,\n markUnverifiable,\n type UnverifiableReasoningRule,\n} from './voter-unverifiable.js';\nimport { resolveAttemptCollector, withVoterAttemptTelemetry } from './voter-attempt-events.js';\nimport { buildLlmVoteResult, carryAttemptUsage } from './voter-attempt-usage.js';\n\n// Re-exported: `exports/consensus.ts` and the voter tests import it from here (#5578 moved the class).\nexport { NoAdapterError };\nexport type { VoteExecutionOverrides } from './vote-types.js';\n\n// Re-export prompts for backward compatibility\nexport { VOTER_SYSTEM_PROMPTS, SIMULATED_VOTE_REASONING } from './voter-prompts.js';\n\n// Re-export response utilities for backward compatibility\nexport {\n VoteResponseSchema,\n type VoteResponse,\n buildVotePrompt,\n extractJsonFromResponse,\n parseVoteResponse,\n SyntheticVoteError,\n type ParsedVote,\n type ParsedVoteSource,\n} from './voter-response.js';\n\n// Re-export execution utilities for backward compatibility\nexport {\n DEFAULT_VOTE_TIMEOUT_MS,\n MAX_VOTE_TIMEOUT_MS,\n MIN_VOTE_TIMEOUT_MS,\n DEFAULT_MAX_RETRIES,\n RATE_LIMIT_RETRY_DELAY_MS,\n createErrorVoteResult,\n createSimulationVoteResult,\n createSimulatedVotes,\n simulateVote,\n isRateLimitError,\n withTimeout,\n delay,\n extractTextFromResponse,\n executeSingleVoteAttempt,\n resolveVoteTimeout,\n type RetryOptions,\n executeWithRetries,\n} from './voter-execution.js';\n\n// Import from execution module for internal use\nimport {\n createErrorVoteResult,\n createSimulationVoteResult,\n createSimulatedVotes,\n executeWithRetries,\n} from './voter-execution.js';\nimport { resolveVoteTimeout, VOTE_TIMEOUTS } from '../config/timeouts.js';\nimport { launchVotesWithOverallDeadline, resolvePanelDeadline } from './voter-agents-deadline.js';\nimport { resolvePanelWorkspace } from './panel-workspace.js';\nimport { ensureGatewayDiscovered } from '../adapters/gateway-rediscovery.js';\n\n// Preserve the established public import while the deadline owner lives beside the launcher.\nexport { computeOverallConsensusDeadlineMs } from './voter-agents-deadline.js';\n\n// ============================================================================\n// Agent Vote Execution\n// ============================================================================\n\n/**\n * Options for executing voter agents.\n */\n/** Default inter-agent delay to prevent rate limiting (ms). Raised from 1s to 2s (#1802). */\nexport const DEFAULT_INTER_AGENT_DELAY_MS = 2000;\n\nexport interface VoterAgentOptions {\n /** Logger instance */\n readonly logger?: ILogger;\n /** Model adapter to use (auto-selected if not provided) */\n readonly adapter?: IModelAdapter;\n /** Timeout per vote in milliseconds (default: 120000, override via NEXUS_VOTE_TIMEOUT_MS) */\n readonly timeoutMs?: number;\n /** Maximum retries per vote (default: 2) */\n readonly maxRetries?: number;\n /** Whether to allow simulation fallback (default: false per Issue #280) */\n readonly allowSimulation?: boolean;\n /** Delay between launching each agent vote to prevent rate limiting (default: 1000ms). Set to 0 to disable. */\n readonly interAgentDelayMs?: number;\n}\n\n// Re-export AgentVoteResult for convenience\nexport type { AgentVoteResult };\n\nconst defaultLogger = createLogger({ component: 'voter-agents' });\n\n/**\n * The parsed vote, or — when the seat could not read the artifact — the same\n * seat re-recorded as `unverifiable` with its returned decision discarded and\n * logged (#6094). Classification prefers the transport's stderr (structured)\n * over the reasoning text (fallback); the log names which one fired.\n */\nfunction finalizeParsedVote(\n built: AgentVoteResult,\n cliStderr: string | undefined,\n logger: ILogger\n): AgentVoteResult {\n const { role, model } = built;\n const signal = classifyUnverifiable(\n { cliStderr, reasoning: built.vote.reasoning },\n (rule: UnverifiableReasoningRule) => {\n logger.debug('Unverifiable reasoning fallback fired', { role, rule });\n }\n );\n if (signal === undefined) {\n logger.info('Vote completed', { role, model, decision: built.vote.decision });\n return built;\n }\n logger.warn('Seat could not read the artifact — recorded as unverifiable, decision discarded', {\n role,\n model,\n signal,\n discardedDecision: built.vote.decision,\n ...(built.selectedOption !== undefined ? { discardedOption: built.selectedOption } : {}),\n });\n return markUnverifiable(built, signal);\n}\n\n/**\n * Executes a real LLM vote for a single role with timeout and retry support.\n *\n * Per Issue #280: No simulation fallback by default. Returns error result\n * instead of simulated vote when execution fails.\n */\n/** Resolve per-call vote execution settings against their defaults. */\nfunction resolveVoteExecution(options: VoteExecutionOverrides = {}): VoteExecutionSettings {\n return {\n timeoutMs: options.timeoutMs ?? resolveVoteTimeout(),\n maxRetries: options.maxRetries ?? VOTE_TIMEOUTS.maxRetries,\n allowSimulation: options.allowSimulation ?? false,\n declaredOptions: options.declaredOptions,\n project: options.project,\n workspace: options.workspace,\n workspaceSha: options.workspaceSha,\n onError: options.onError,\n };\n}\n\nexport async function executeAgentVote(\n role: VoterRole,\n proposal: string,\n adapter: IModelAdapter,\n logger: ILogger,\n options?: VoteExecutionOverrides\n): Promise<AgentVoteResult> {\n const start = getTimeProvider().now();\n // `settings` is timeoutMs, maxRetries, project and workspace — the retry hop's own fields.\n const { allowSimulation, declaredOptions, ...settings } = resolveVoteExecution(options);\n\n logger.info('Executing vote', { role, model: adapter.modelId, provider: adapter.providerId });\n\n // #6729: the panel's cancel rides along so it reaches this seat's adapter call.\n const collector = resolveAttemptCollector(options);\n const attach = (vote: AgentVoteResult): AgentVoteResult =>\n withVoterAttemptTelemetry(vote, () => collector.snapshot());\n const retryOptions = {\n role,\n proposal,\n adapter,\n logger,\n ...settings,\n signal: options?.signal,\n attemptCollector: collector,\n attemptKind: options?.attemptKind,\n withinRoleRetry: options?.withinRoleRetry,\n };\n const result = await executeWithRetries({ ...retryOptions, options: declaredOptions });\n const processingTimeMs = getTimeProvider().now() - start;\n\n if (result.ok) {\n const built = buildLlmVoteResult(role, result, adapter, processingTimeMs);\n const finalized = finalizeParsedVote(built, result.cliStderr, logger);\n if (finalized.source !== 'llm') collector.discardFinal();\n return attach(finalized);\n }\n\n // Retries exhausted or explicitly refused by the adapter.\n options?.onError?.(role, result.retryable);\n logger.error('Vote execution failed after all retries', undefined, {\n role,\n model: adapter.modelId,\n errorMessage: result.error,\n });\n\n if (allowSimulation) {\n logger.warn('Falling back to simulation (allowSimulation=true)', { role });\n const simulated = createSimulationVoteResult(role, proposal, processingTimeMs, result.error);\n return attach(carryAttemptUsage(result, simulated));\n }\n\n // #3350: a stale-OAuth failure (e.g. codex \"refresh token already used\")\n // surfaces here as a raw fail-closed error with no operator signal. Append a\n // one-line `<cli> login` remediation when the error is an auth error. Vote\n // semantics are unchanged — this is still an error (abstain) vote.\n const remediation = authRemediation(result.error, adapter.providerId);\n const errorText = remediation === null ? result.error : `${result.error}\\n\\n${remediation}`;\n const errored = createErrorVoteResult(role, errorText, processingTimeMs, adapter.providerId);\n return attach(carryAttemptUsage(result, errored));\n}\n\n// ============================================================================\n// Batch Vote Collection\n// ============================================================================\n\n/**\n * Options for collecting votes from multiple agents.\n */\nexport interface CollectRealVotesOptions extends VoterAgentOptions {\n /** Repository checkout used by every panel seat. */\n readonly workspace?: string | undefined;\n readonly workspaceSha?: string | undefined;\n /** Voter roles to include */\n readonly roles: readonly VoterRole[];\n /** Proposal text */\n readonly proposal: string;\n /** Use simulation mode (explicit opt-in only) */\n readonly simulate?: boolean;\n /**\n * In-process gateway model adapters (#4040) — one per discovered gateway model.\n * When provided (and no explicit `adapter` override), voters route through these\n * HTTP adapters instead of shelling out to CLIs: roles are round-robined across\n * them for per-role model diversity, the API key stays in-process (no subprocess\n * env-forwarding), and the nested-spawn class (#4033) cannot occur. Empty/omitted\n * ⇒ the CLI round-robin path is used (unchanged).\n */\n readonly gatewayAdapters?: readonly IModelAdapter[] | undefined;\n /** Named alternatives for a multi-option proposal (#4472); each voter picks one. */\n readonly declaredOptions?: readonly string[] | undefined;\n /**\n * The project the panel is judging, already resolved and validated by the\n * caller (#6110). Reaches every seat's system prompt. Absent ⇒ `nexus-agents`.\n */\n readonly project?: string | undefined;\n /**\n * Cancellation for an in-flight panel. Stops LAUNCHING voters that have not\n * started (#5393), aborts the adapter call of every seat already in flight\n * (#6729), and skips the errored-seat retry pass. Absent changes nothing.\n */\n readonly signal?: AbortSignal | undefined;\n /**\n * Per-seat progress callback (#6162): invoked with each seat's result as it\n * settles, on every pass (first, fallback, retry). The async-job heartbeat\n * for vote bodies; absent changes nothing.\n */\n readonly onVoteCollected?: ((vote: AgentVoteResult) => void) | undefined;\n /**\n * Delay before the per-role retry of errored voters (#5578). Defaults to\n * {@link DEFAULT_ERRORED_ROLE_BACKOFF_MS}; 0 disables the wait, which is what\n * tests want. The retry itself is not optional — the panel applies it under\n * every error policy, per the #5578 design panel (option b, 6 of 6).\n */\n readonly erroredRoleBackoffMs?: number | undefined;\n /**\n * Seats already assigned by {@link assignPanelSeats} (#6003): a caller that\n * must know the panel's models BEFORE the vote (the pr_review budget reads\n * their windows) resolves the seats once and hands them back, so the panel\n * runs on exactly what it was budgeted for. Ignored when `adapter` is set.\n */\n readonly roleAdapters?: ReadonlyMap<VoterRole, IModelAdapter> | undefined;\n}\n\n/** Assigns a single adapter to all roles (fallback path). */\nfunction assignUniformAdapter(\n roles: readonly VoterRole[],\n adapter: IModelAdapter\n): Map<VoterRole, IModelAdapter> {\n return new Map(roles.map((role) => [role, adapter]));\n}\n\n/** Creates CLI-specific adapters for available CLIs via the unified registry. */\nfunction createCliAdapterMap(clis: readonly CliName[]): Map<CliName, IModelAdapter> {\n const registry = getGlobalRegistry();\n const result = new Map<CliName, IModelAdapter>();\n for (const cli of clis) result.set(cli, registry.getAdapterForCli(cli));\n return result;\n}\n\n/**\n * Creates diverse per-role adapters using all available CLIs (Issue #845).\n * Distributes roles across CLIs in round-robin fashion for model diversity.\n * Falls back to single adapter if only one CLI is available.\n */\n/**\n * Round-robin assign roles across a labeled adapter list (the shared diversity\n * primitive for both the CLI path and the gateway path #4040). `label` is the\n * model/CLI id surfaced in the assignment log so operators can confirm which\n * model each role used.\n */\nfunction assignRoundRobinAdapters(\n roles: readonly VoterRole[],\n entries: readonly { readonly label: string; readonly adapter: IModelAdapter }[],\n logger: ILogger,\n source: string\n): Map<VoterRole, IModelAdapter> {\n const adapters = new Map<VoterRole, IModelAdapter>();\n const assignments: Record<string, string> = {};\n for (let i = 0; i < roles.length; i++) {\n const role = roles[i];\n const entry = entries[i % entries.length];\n if (role === undefined || entry === undefined) continue;\n adapters.set(role, entry.adapter);\n assignments[role] = entry.label;\n }\n logger.info('Diverse adapters assigned', {\n source,\n count: entries.length,\n roleAssignments: assignments,\n });\n return adapters;\n}\n\n/**\n * Gateway path (#4040): assign roles across the in-process per-model gateway\n * adapters. A single model collapses to a uniform panel (warned). With multiple\n * models, per-role operator overrides (#4055) pin chosen roles to a known-good\n * model and the rest are dealt across model FAMILIES first, then across models\n * within a family (#6606) — never in the gateway's listing order.\n */\nexport function resolveGatewayRoleAdapters(\n roles: readonly VoterRole[],\n gatewayAdapters: readonly IModelAdapter[],\n fallbackAdapter: IModelAdapter,\n logger: ILogger\n): Map<VoterRole, IModelAdapter> {\n if (gatewayAdapters.length === 1) {\n // Consensus integrity: a multi-role panel on ONE model yields correlated votes\n // (the higher_order strategy can't down-weight what it can't tell apart). Warn\n // so operators configure the gateway with more models for a diverse panel.\n if (roles.length > 1) {\n logger.warn('Consensus panel collapsed to a single gateway model — votes may correlate', {\n model: gatewayAdapters[0]?.modelId,\n roleCount: roles.length,\n });\n }\n return assignUniformAdapter(roles, gatewayAdapters[0] ?? fallbackAdapter);\n }\n // #4055: per-role overrides (NEXUS_VOTER_MODEL_<ROLE>) pin a role to a known-good\n // gateway model; the rest are dealt. An unknown override id warns + falls\n // through to dealing (handled in the resolver).\n const overrides = resolveVoterModelOverrides(roles, gatewayAdapters, logger);\n const dealtRoles = roles.filter((r) => !overrides.has(r));\n // #6606: deal families first, balancing around the pinned seats. Round-robin\n // over the listing order seated 5 OpenAI, 2 Anthropic and 0 Google models on\n // a recorded three-family catalogue.\n const dealt = dealSeatsAcrossFamilies(dealtRoles.length, gatewayAdapters, {\n seated: [...overrides.values()].map((a) => a.modelId),\n });\n const assigned = assignRoundRobinAdapters(\n dealtRoles,\n dealt.map((a) => ({ label: a.modelId, adapter: a })),\n logger,\n 'gateway'\n );\n for (const [role, adapter] of overrides) assigned.set(role, adapter);\n // Consensus-integrity parity with the single-model path (#4055 review): warn if\n // the FINAL assignment collapsed every role onto one model — e.g. an operator\n // pinned all roles to the same override — since correlated votes defeat the panel.\n // #4390: compare CANONICAL model identity, not the raw strings. The same\n // weights arrive under different strings from different gateways —\n // `claude-sonnet-4-6`, `anthropic/claude-sonnet-4-6` and\n // `custom/claude-sonnet-4-6` are one model — so a raw-string set reported a\n // collapsed panel as diverse and the warning never fired.\n const assignedModels = [...assigned.values()].map((a) => a.modelId);\n if (roles.length > 1 && countDistinctModels(assignedModels) === 1) {\n logger.warn(\n 'Consensus panel collapsed to a single gateway model via overrides — votes may correlate',\n { model: assignedModels[0], roleCount: roles.length }\n );\n }\n warnIfSingleFamily(roles.length, assignedModels, logger);\n return assigned;\n}\n\nasync function resolveDiverseAdapters(\n roles: readonly VoterRole[],\n logger: ILogger,\n fallbackAdapter: IModelAdapter,\n gatewayAdapters?: readonly IModelAdapter[]\n): Promise<Map<VoterRole, IModelAdapter>> {\n // #4040: gateway path is preferred when configured.\n if (gatewayAdapters !== undefined && gatewayAdapters.length > 0) {\n return resolveGatewayRoleAdapters(roles, gatewayAdapters, fallbackAdapter, logger);\n }\n\n let availableClis: CliName[];\n try {\n availableClis = await getAvailableClis();\n } catch (e: unknown) {\n logger.warn('Failed to resolve available CLIs; falling back to single adapter', {\n error: String(e),\n });\n availableClis = [];\n }\n // #6962: every seat runs read-only analysis; a CLI that cannot enforce it\n // would refuse every seat dealt to it, so it is not dealt any.\n const access = clisServingVoterSeats(availableClis);\n if (access.refused.length > 0) {\n logger.info('CLIs excluded from voter seats: cannot enforce read-only analysis', {\n refused: access.refused,\n });\n }\n availableClis = access.serving;\n\n if (availableClis.length <= 1) {\n logger.info('Using single adapter for all roles', { cliCount: availableClis.length });\n return assignUniformAdapter(roles, fallbackAdapter);\n }\n\n const cliAdapters = createCliAdapterMap(availableClis);\n if (cliAdapters.size <= 1) return assignUniformAdapter(roles, fallbackAdapter);\n\n // #4390: distinct CLIs do NOT imply distinct models. Two arms can front the\n // same weights — opencode serving `anthropic/claude-sonnet-4-6` alongside the\n // claude CLI, for instance — and a panel spread across them is no more\n // independent than one on a single arm. The gateway path had this check; the\n // CLI path had none.\n // #4983: detection is lazy, so at assignment time every adapter still\n // reports the same `pending-detection` placeholder — which an equality check\n // reads as \"one model\" and warns on EVERY vote. Say unmeasured here and make\n // the real judgement in `warnIfPanelCorrelated`, after the votes have run and\n // each adapter has resolved.\n reportPanelIndependence([...cliAdapters.values()], roles.length, 'assignment', logger);\n\n return assignRoundRobinAdapters(\n roles,\n [...cliAdapters.entries()].map(([cli, adapter]) => ({ label: cli, adapter })),\n logger,\n 'cli'\n );\n}\n\n/** Options for staggered vote launching. */\n/** Caller-supplied vote execution overrides; unset fields take defaults. */\n\ninterface StaggeredVoteInput {\n readonly roles: readonly VoterRole[];\n readonly proposal: string;\n readonly roleAdapters: Map<VoterRole, IModelAdapter>;\n readonly fallbackAdapter: IModelAdapter;\n readonly logger: ILogger;\n /** Passed straight to executeAgentVote; declaredOptions per #4472. */\n readonly voteOptions: VoteExecutionSettings;\n readonly interDelay: number;\n /** Cancellation for the un-launched remainder of the panel (#5393). */\n readonly signal?: AbortSignal | undefined;\n /** Per-seat heartbeat (#6162), forwarded to the deadline launcher. */\n readonly onVoteCollected?: ((vote: AgentVoteResult) => void) | undefined;\n}\n\n/**\n * Launches votes with staggered delays to prevent rate limiting (Issue #1319)\n * and an overall wall-clock deadline to prevent indefinite hangs (Issue #1871).\n */\nasync function launchStaggeredVotes(\n input: StaggeredVoteInput,\n overallDeadlineMs: number,\n deadlineAtMs: number\n): Promise<readonly AgentVoteResult[]> {\n // `StaggeredVoteInput` is `LaunchVotesInput` minus the deadline and the\n // launcher, so the input passes through whole — including `signal` (#5393)\n // and `onVoteCollected` (#6162).\n return launchVotesWithOverallDeadline({\n ...input,\n overallDeadlineMs,\n deadlineAtMs,\n voteFn: executeAgentVote,\n });\n}\n\n/**\n * Collects votes from multiple voter agents.\n *\n * Per Issue #280: No automatic simulation fallback. If no adapter is\n * available and simulation is not explicitly enabled, throws NoAdapterError.\n * Per Issue #845: Uses diverse CLIs when multiple are available.\n */\n/**\n * The panel's seat → adapter assignment — ONE definition, used by the vote and\n * by anything that must know the panel's models before it runs (#6003). An\n * explicit `adapter` is uniform (Issue #280); pre-resolved `roleAdapters` are\n * used verbatim; else roles spread across gateway models / CLIs (Issue #845).\n */\nexport async function assignPanelSeats(\n fallbackAdapter: IModelAdapter,\n options: Pick<CollectRealVotesOptions, 'roles' | 'adapter' | 'gatewayAdapters' | 'roleAdapters'>,\n logger: ILogger\n): Promise<Map<VoterRole, IModelAdapter>> {\n if (options.adapter !== undefined) return assignUniformAdapter(options.roles, fallbackAdapter);\n if (options.roleAdapters !== undefined) return new Map(options.roleAdapters);\n return resolveDiverseAdapters(options.roles, logger, fallbackAdapter, options.gatewayAdapters);\n}\n\nasync function collectPanelPasses(\n input: StaggeredVoteInput,\n deadline: ReturnType<typeof resolvePanelDeadline>,\n nonRetryableRoles: ReadonlySet<VoterRole>,\n backoffMs: number\n): Promise<readonly AgentVoteResult[]> {\n const { overallDeadlineMs, deadlineAtMs } = deadline;\n const first = await launchStaggeredVotes(input, overallDeadlineMs, deadlineAtMs);\n return retryErroredRoles(\n first,\n (roles) =>\n launchStaggeredVotes(\n { ...input, roles, voteOptions: { ...input.voteOptions, attemptKind: 'role_retry' } },\n overallDeadlineMs,\n deadlineAtMs\n ),\n input.logger,\n backoffMs,\n { signal: input.signal, deadlineAtMs, nonRetryableRoles }\n );\n}\n\nexport async function collectRealVotes(\n options: CollectRealVotesOptions\n): Promise<readonly AgentVoteResult[]> {\n const logger = options.logger ?? defaultLogger;\n const { roles, proposal, simulate, allowSimulation } = options;\n\n if (simulate === true) {\n logger.info('Using simulation mode (explicitly requested)');\n return createSimulatedVotes(roles, proposal);\n }\n\n // #6608: a gateway down at boot is re-discovered here (backoff-bounded)\n // and fills `options.gatewayAdapters` in place before seats are assigned.\n await ensureGatewayDiscovered();\n const adapterResult = resolveAdapterOrFail(options, logger, allowSimulation === true);\n if ('simulated' in adapterResult)\n return createSimulatedVotes(roles, proposal, 'No adapter available');\n\n const roleAdapters = await assignPanelSeats(adapterResult.adapter, options, logger);\n\n warnIfCodexConcurrencyExceeded(roleAdapters, logger);\n\n // The same resolver executeAgentVote applies, so the two paths cannot drift\n // on a default. Carried through: timeoutMs / maxRetries / allowSimulation;\n // declaredOptions (#4472) into the prompt and the selection resolver; the\n // target project (#6110) into every system prompt; and the working\n // directory (#6358) — explicitly passed to every subprocess seat, which the\n // gemini arm now also gets as --add-dir — read once so every seat of the\n // panel names the same tree in its REPOSITORY ACCESS block.\n const workspace = resolvePanelWorkspace(options.workspace);\n const { nonRetryableRoles, onError } = createVoterRetryState();\n const voteOptions = resolveVoteExecution({ ...options, workspace, onError });\n const interDelay = options.interAgentDelayMs ?? DEFAULT_INTER_AGENT_DELAY_MS;\n\n const launchInput: StaggeredVoteInput = {\n roles,\n proposal,\n roleAdapters,\n fallbackAdapter: adapterResult.adapter,\n logger,\n voteOptions,\n interDelay,\n signal: options.signal,\n onVoteCollected: options.onVoteCollected,\n };\n // Clamp once, then share the same cutoff across both passes and backoff (#6811).\n const { overallDeadlineMs, deadlineAtMs } = resolvePanelDeadline(\n voteOptions.timeoutMs,\n voteOptions.maxRetries,\n roles.length,\n interDelay,\n logger\n );\n const results = await collectPanelPasses(\n launchInput,\n { overallDeadlineMs, deadlineAtMs },\n nonRetryableRoles,\n options.erroredRoleBackoffMs ?? DEFAULT_ERRORED_ROLE_BACKOFF_MS\n );\n\n // #4983/#5546: this is the only point the question is answerable. Assess the\n // successful result provenance, not the assigned adapters: a failed primary\n // may have been replaced by a vote from the shared fallback model.\n reportVoteIndependence(results, logger);\n return results;\n}\n\n/**\n * Gets a description for a voter role.\n */\nexport function getRoleDescription(role: VoterRole): string {\n return VOTER_ROLES[role];\n}\n","/**\n * nexus-agents/cli - Target project for the voter panel (#6110)\n *\n * `getVoterPrompts(project)` puts the project name into every voter's system\n * prompt, and until #6110 nothing ever passed one: a consuming repository got a\n * scope_steward judging its proposal against \"the nexus-agents project\". This\n * module answers \"which project is the panel judging?\" from three sources, in\n * order, and says which one answered:\n *\n * 1. `input` — the caller's explicit `project` (tool input or `--project`).\n * 2. `derived` — `owner/repo` parsed from the `origin` URL in the repo's\n * `.git/config`, else the nearest `package.json` `name`.\n * 3. `default` — `nexus-agents`, this repository's own name.\n *\n * Decided by a 7-voter panel (option C, 4 of 7; job\n * `job-consensus_vote-b97309d13ca77db9`) with two safeguards adopted from the\n * minority: the SOURCE is disclosed on the response so a forgotten input reads\n * as `default` next to the verdict instead of a silent mis-scope, and no\n * candidate — from any source — reaches a prompt unless it matches\n * {@link VOTER_PROJECT_PATTERN}. Derivation is a pure parse of files the\n * process can already read; it never spawns `git`.\n *\n * @module cli/voter-project\n */\n\nimport { readFileSync, statSync } from 'node:fs';\nimport { dirname, isAbsolute, join, resolve } from 'node:path';\nimport { z } from 'zod';\nimport type { ILogger } from '../core/index.js';\nimport { findRepoRoot } from '../config/repo-root-detection.js';\nimport { DEFAULT_VOTER_PROJECT } from './voter-prompts.js';\n\n/**\n * The only shape a project name may take before it is interpolated into a\n * prompt. Admits `owner/repo`, scoped npm names (`@scope/name`) and plain\n * package names; refuses whitespace, quotes and every shell metacharacter.\n */\nexport const VOTER_PROJECT_PATTERN = /^[A-Za-z0-9._/@-]{1,200}$/;\n\n/**\n * The optional `project` input every panel tool accepts (#6110, #6123):\n * `consensus_vote`, `pr_review` and `supply_chain_tradeoff_panel` share this\n * one field so the pattern and its description are stated once.\n */\nexport const VoterProjectInputSchema = z\n .string()\n .regex(VOTER_PROJECT_PATTERN)\n .optional()\n .describe(\n 'The project the panel is judging (#6110), e.g. `acme/widgets` — it replaces `nexus-agents` ' +\n \"in every voter's system prompt, so a consuming repository is not judged against this \" +\n \"one's mission and governance files. When omitted the name is DERIVED from the server's \" +\n 'working directory (the `origin` remote as `owner/repo`, else the nearest `package.json` ' +\n 'name) and falls back to `nexus-agents`; the response discloses which on `project.source`. ' +\n 'Letters, digits and `._/@-` only, at most 200 characters.'\n );\n\n/** Which of the three sources supplied the project name. */\nexport type VoterProjectSource = 'input' | 'derived' | 'default';\n\n/** The project the voter panel was told it is judging, and how that was decided. */\nexport interface ResolvedVoterProject {\n readonly name: string;\n readonly source: VoterProjectSource;\n}\n\n/** A candidate the resolver considered and refused, with the reason. */\nexport interface RejectedVoterProjectCandidate {\n readonly origin: 'input' | 'git-origin' | 'package-name';\n readonly candidate: string;\n readonly reason: string;\n}\n\n/** {@link ResolvedVoterProject} plus the candidates rejected on the way to it. */\nexport interface VoterProjectResolution extends ResolvedVoterProject {\n /** Rejected candidates in the order they were tried; empty when none were. */\n readonly rejected: readonly RejectedVoterProjectCandidate[];\n}\n\n/** Ancestor-walk cap; mirrors `findRepoRoot`'s guard against pathological trees. */\nconst MAX_ANCESTOR_DEPTH = 64;\n\n/** Longest `.git/config` or `package.json` the resolver will read. */\nconst MAX_READ_BYTES = 64 * 1024;\n\nfunction readBounded(path: string): string | undefined {\n try {\n if (statSync(path).size > MAX_READ_BYTES) return undefined;\n return readFileSync(path, 'utf-8');\n } catch {\n return undefined;\n }\n}\n\n/**\n * Locate the git config that holds the remotes for the repo containing `cwd`.\n *\n * A worktree's `.git` is a FILE (`gitdir: <path>`) whose gitdir carries a\n * `commondir` back-reference to the main repository's `.git`, where the remotes\n * live. Both hops are plain file reads.\n */\nfunction locateGitConfig(cwd: string): string | undefined {\n const repoRoot = findRepoRoot(cwd);\n if (repoRoot === null) return undefined;\n const dotGit = join(repoRoot, '.git');\n try {\n if (statSync(dotGit).isDirectory()) return join(dotGit, 'config');\n } catch {\n return undefined;\n }\n const gitdir = worktreeGitDir(repoRoot, dotGit);\n if (gitdir === undefined) return undefined;\n const commondir = readBounded(join(gitdir, 'commondir'))?.trim();\n const commonRoot =\n commondir === undefined || commondir === '' ? gitdir : resolve(gitdir, commondir);\n return join(commonRoot, 'config');\n}\n\n/** The gitdir a worktree's `.git` FILE points at, absolute; undefined when it is not one. */\nfunction worktreeGitDir(repoRoot: string, dotGitFile: string): string | undefined {\n const target = readBounded(dotGitFile)?.match(/^gitdir:\\s*(.+?)\\s*$/m)?.[1];\n if (target === undefined) return undefined;\n return isAbsolute(target) ? target : resolve(repoRoot, target);\n}\n\n/**\n * The `url` of `[remote \"origin\"]` in a git config, or undefined. Sections are\n * scanned by header so a `url` under another remote is never picked up.\n */\nfunction originUrlFromConfig(config: string): string | undefined {\n let inOrigin = false;\n for (const rawLine of config.split('\\n')) {\n const line = rawLine.trim();\n if (line.startsWith('[')) {\n inOrigin = /^\\[remote\\s+\"origin\"\\]$/.test(line);\n continue;\n }\n if (!inOrigin) continue;\n const match = line.match(/^url\\s*=\\s*(.+)$/);\n if (match?.[1] !== undefined) return match[1].trim();\n }\n return undefined;\n}\n\n/**\n * `owner/repo` from a git remote URL, or undefined when the URL has fewer than\n * two path segments. Handles `git@host:owner/repo(.git)`,\n * `scheme://[user@]host[:port]/owner/repo(.git)` and nested host paths (the\n * last two segments win).\n */\nfunction ownerRepoFromRemoteUrl(url: string): string | undefined {\n const schemeMatch = url.match(/^[a-z][a-z0-9+.-]*:\\/\\/[^/]+\\/(.+)$/i);\n const scpMatch = url.match(/^[^/@:]+@[^/:]+:(.+)$/);\n const path = schemeMatch?.[1] ?? scpMatch?.[1];\n if (path === undefined) return undefined;\n const segments = path\n .replace(/\\/+$/, '')\n .replace(/\\.git$/, '')\n .split('/')\n .filter((segment) => segment !== '');\n if (segments.length < 2) return undefined;\n return segments.slice(-2).join('/');\n}\n\n/** `name` of the nearest `package.json` at or above `cwd`, when it is a string. */\nfunction nearestPackageName(cwd: string): string | undefined {\n let current = resolve(cwd);\n for (let depth = 0; depth < MAX_ANCESTOR_DEPTH; depth++) {\n const raw = readBounded(join(current, 'package.json'));\n if (raw !== undefined) {\n try {\n const parsed: unknown = JSON.parse(raw);\n if (typeof parsed === 'object' && parsed !== null && 'name' in parsed) {\n return typeof parsed.name === 'string' ? parsed.name : undefined;\n }\n } catch {\n return undefined;\n }\n return undefined;\n }\n const parent = dirname(current);\n if (parent === current) return undefined;\n current = parent;\n }\n return undefined;\n}\n\n/** Why a candidate fails {@link VOTER_PROJECT_PATTERN}, or undefined when it passes. */\nfunction patternRejection(candidate: string): string | undefined {\n if (VOTER_PROJECT_PATTERN.test(candidate)) return undefined;\n return `does not match the project-name pattern ${VOTER_PROJECT_PATTERN.source}`;\n}\n\n/** The derived candidates in fallback order, each tagged with where it came from. */\nfunction derivedCandidates(cwd: string): ReadonlyArray<{\n origin: 'git-origin' | 'package-name';\n candidate: string | undefined;\n absentReason: string;\n}> {\n const configPath = locateGitConfig(cwd);\n const config = configPath === undefined ? undefined : readBounded(configPath);\n const originUrl = config === undefined ? undefined : originUrlFromConfig(config);\n const ownerRepo = originUrl === undefined ? undefined : ownerRepoFromRemoteUrl(originUrl);\n return [\n {\n origin: 'git-origin',\n candidate: ownerRepo,\n absentReason:\n originUrl === undefined\n ? 'no origin remote'\n : `origin URL carries no owner/repo path: ${originUrl}`,\n },\n { origin: 'package-name', candidate: nearestPackageName(cwd), absentReason: 'no package name' },\n ];\n}\n\n/**\n * Resolve the project the voter panel should judge against.\n *\n * `input` wins when it passes the pattern; otherwise the `origin` remote of the\n * repository containing `cwd`, then the nearest `package.json` name; otherwise\n * {@link DEFAULT_VOTER_PROJECT}. A candidate that fails the pattern is recorded\n * on `rejected` with its reason and the next source is tried — so the result\n * ALWAYS carries a name the prompt may safely interpolate, and the caller can\n * log exactly what was refused. Pure over the filesystem: no subprocess.\n */\nexport function resolveVoterProject(args: {\n readonly input?: string | undefined;\n readonly cwd: string;\n}): VoterProjectResolution {\n const rejected: RejectedVoterProjectCandidate[] = [];\n\n if (args.input !== undefined) {\n const reason = patternRejection(args.input);\n if (reason === undefined) return { name: args.input, source: 'input', rejected };\n rejected.push({ origin: 'input', candidate: args.input, reason });\n }\n\n for (const { origin, candidate, absentReason } of derivedCandidates(args.cwd)) {\n if (candidate === undefined) {\n // An absent candidate is not a rejection — nothing was refused. Only an\n // origin URL that EXISTED but carried no owner/repo is worth recording.\n if (origin === 'git-origin' && absentReason !== 'no origin remote') {\n rejected.push({ origin, candidate: '', reason: absentReason });\n }\n continue;\n }\n const reason = patternRejection(candidate);\n if (reason === undefined) return { name: candidate, source: 'derived', rejected };\n rejected.push({ origin, candidate, reason });\n }\n\n return { name: DEFAULT_VOTER_PROJECT, source: 'default', rejected };\n}\n\n/**\n * Resolve the project a panel judges and log it once per run: the chosen name\n * and source at info, and every candidate the pattern refused at warn with its\n * reason, so a `default` next to a verdict is explained. Shared by every tool\n * that runs a voter panel (#6123); each resolves ONCE per run.\n */\nexport function resolveAndLogVoterProject(\n input: string | undefined,\n logger: ILogger\n): ResolvedVoterProject {\n const { name, source, rejected } = resolveVoterProject({ input, cwd: process.cwd() });\n for (const r of rejected) {\n logger.warn('Voter project candidate rejected', {\n origin: r.origin,\n candidate: r.candidate,\n reason: r.reason,\n });\n }\n logger.info('Voter project resolved', { project: name, source });\n return { name, source };\n}\n","/**\n * Option gate for multi-option consensus votes (#4472, increment 2).\n *\n * When a proposal declares named `options`, clearing the ordinary\n * approve/reject bar is no longer sufficient: the leading option must clear the\n * threshold too. Without this, `unanimous` is the *easiest* bar on a\n * multi-option proposal, because every voter approves while choosing something\n * different and a 6-1 split records as 7-0, 100% (#4452).\n *\n * ## Composition, not replacement\n *\n * The gate is applied ON TOP of the existing strategy verdict — both bars must\n * be cleared. Three reasons:\n *\n * - **Rejections keep their meaning.** The option tally counts only approvers,\n * so on its own it would read \"4 approve for X, 3 reject\" as 4/4 unanimous.\n * The existing approve/reject gate already fails that case; composing keeps\n * it failing.\n * - **Monotone.** Adding a constraint can only make approval harder, so\n * declaring `options` can never turn a rejected vote into an approved one.\n * - **No-options behaviour is byte-identical**, because the gate is a no-op\n * when no options are declared — and `strategies.ts` stays untouched, which\n * matters on the governor path.\n *\n * The two measurements stay separate on the response: `approvalPercentage`\n * remains the approve/reject figure and the option share is reported alongside\n * it. Collapsing them into one number would hide which bar actually failed.\n *\n * @module mcp/tools/consensus-vote-option-gate\n * (Source: Issue #4472)\n */\n\nimport {\n evaluateOptionThreshold,\n tallyOptions,\n type OptionThreshold,\n type OptionThresholdVerdict,\n} from '../../consensus/option-tally.js';\n\n/**\n * The option verdict as `executeVoting` stores it, with the veto explanation\n * attached (#4529).\n *\n * The prose lives here rather than on {@link OptionThresholdVerdict} to keep\n * `consensus/option-tally.ts` a pure tally module, and rather than on\n * `policyReason` because that field means exactly one thing — \"an error policy\n * VOIDED this vote\". Borrowing it for a split made `resolveVoteDecision` stamp\n * `no_quorum` on a panel that had in fact convened and disagreed.\n */\nexport interface OptionGateVerdict extends OptionThresholdVerdict {\n /** Human-readable explanation, present only when the gate vetoed. */\n readonly reason?: string;\n}\nimport type { AgentVoteResult } from '../../cli/vote-types.js';\n\n/** Strategies whose bar the option gate mirrors. */\nconst STRATEGY_TO_OPTION_THRESHOLD: Record<string, OptionThreshold> = {\n unanimous: 'unanimous',\n supermajority: 'supermajority',\n simple_majority: 'majority',\n // higher_order and proof_of_learning aggregate differently; they are gated at\n // the majority bar so a declared-option split still cannot pass unnoticed.\n higher_order: 'majority',\n proof_of_learning: 'majority',\n opinion_wise: 'majority',\n};\n\n/**\n * Map a voting strategy (or legacy threshold) onto the option bar to apply.\n *\n * An unrecognised strategy falls back to `majority` rather than to \"no gate\",\n * so a strategy added later cannot silently opt out of option checking.\n */\nexport function optionThresholdFor(strategy: string, legacyThreshold?: string): OptionThreshold {\n if (legacyThreshold === 'unanimous') return 'unanimous';\n if (legacyThreshold === 'supermajority') return 'supermajority';\n return STRATEGY_TO_OPTION_THRESHOLD[strategy] ?? 'majority';\n}\n\nexport interface OptionGateOutcome {\n /** The tally + verdict, for reporting on the response and the record. */\n readonly verdict: OptionThresholdVerdict;\n /**\n * True when the gate vetoed an otherwise-approved vote. Drives the\n * human-readable reason; a vote already rejected on approvals is untouched.\n */\n readonly vetoed: boolean;\n /** Populated only when `vetoed`, explaining which bar failed and why. */\n readonly reason?: string;\n}\n\n/**\n * Evaluate the option gate for a completed vote.\n *\n * `approvedByStrategy` is the ordinary verdict. The returned `vetoed` flag is\n * true only when that verdict was `true` and the leading option failed its bar,\n * which is the sole case where this gate changes an outcome.\n */\nexport function evaluateOptionGate(\n votes: readonly AgentVoteResult[],\n declaredOptions: readonly string[],\n threshold: OptionThreshold,\n approvedByStrategy: boolean\n): OptionGateOutcome {\n const tally = tallyOptions(\n votes.map((v) => ({\n decision: v.vote.decision,\n ...(v.selectedOption !== undefined ? { selectedOption: v.selectedOption } : {}),\n })),\n declaredOptions\n );\n const verdict = evaluateOptionThreshold(tally, threshold);\n\n if (!approvedByStrategy || verdict.approved) {\n return { verdict, vetoed: false };\n }\n\n return { verdict, vetoed: true, reason: describeVeto(verdict) };\n}\n\n/**\n * Explain a veto in terms a caller can act on.\n *\n * Names the coverage explicitly, because a share alone cannot distinguish a\n * real split from unreadable responses — `4 pick X + 3 unparseable` and a\n * genuine 4/3 split both read 57%.\n */\nfunction describeVeto(verdict: OptionThresholdVerdict): string {\n const pct = (verdict.leadingShare * 100).toFixed(1);\n const leader =\n verdict.leadingOption !== undefined\n ? `leading option \"${verdict.leadingOption}\" held ${String(verdict.leadingCount)}/${String(verdict.approverCount)} approvers (${pct}%)`\n : 'no voter selected a declared option';\n\n const coverage =\n verdict.unattributedApprovals > 0\n ? ` ${String(verdict.unattributedApprovals)} of ${String(verdict.approverCount)} approvers recorded no usable selection, which lowers the leading share; their choice is unmeasured, not counted as dissent.`\n : '';\n\n return `Approvals cleared the ${verdict.threshold} bar, but the option split did not: ${leader}.${coverage}`;\n}\n","/**\n * nexus-agents/consensus - Multi-Round Voting Protocol Types\n *\n * Multi-Round Voting Protocol Types (Issue #100)\n * Based on arXiv:2512.21352 - Multi-Agent Committees for Code Review\n */\n\nimport { z } from 'zod';\nimport type { Vote } from './types-core.js';\nimport { SUPERMAJORITY_THRESHOLD } from './decision/thresholds.js';\nimport { OPERATION_CLASSES } from '../config/timeouts.js';\n\n/**\n * Default per-round voting timeout (#3734). A voting round guards a parallel\n * MULTI-LLM panel, so it derives from the central `multi-llm-panel` runaway-guard\n * (900s) — not the old accidental 60s, which killed legitimate slow voters.\n */\nconst VOTING_ROUND_DEFAULT_TIMEOUT_MS = OPERATION_CLASSES['multi-llm-panel'].guardMs;\n\n/**\n * Voting round phases.\n * - analysis: Independent analysis (Round 1)\n * - deliberation: Share findings and discuss (Round 2)\n * - consensus: Final vote on recommendations (Round 3)\n */\nexport const VotingRoundPhaseSchema = z.enum(['analysis', 'deliberation', 'consensus']);\nexport type VotingRoundPhase = z.infer<typeof VotingRoundPhaseSchema>;\n\n/**\n * Voting round status.\n */\nexport const VotingRoundStatusSchema = z.enum([\n 'pending',\n 'in_progress',\n 'awaiting_votes',\n 'completed',\n 'aborted',\n]);\nexport type VotingRoundStatus = z.infer<typeof VotingRoundStatusSchema>;\n\n/**\n * A finding submitted by an agent during analysis.\n */\nexport const AgentFindingSchema = z.object({\n agentId: z.string(),\n category: z.enum(['bug', 'security', 'performance', 'style', 'design', 'documentation', 'other']),\n severity: z.enum(['critical', 'major', 'minor', 'suggestion']),\n description: z.string().min(1),\n location: z.string().optional().describe('File path and line range if applicable'),\n suggestion: z.string().optional().describe('Recommended fix'),\n confidence: z.number().min(0).max(1),\n timestamp: z.iso.datetime().optional(),\n});\nexport type AgentFinding = z.infer<typeof AgentFindingSchema>;\n\n/**\n * Finding vote during deliberation.\n */\nexport const FindingVoteSchema = z.object({\n agentId: z.string(),\n findingId: z.string(),\n agree: z.boolean(),\n reasoning: z.string().optional(),\n amendedSeverity: z.enum(['critical', 'major', 'minor', 'suggestion']).optional(),\n});\nexport type FindingVote = z.infer<typeof FindingVoteSchema>;\n\n/**\n * A single voting round in the protocol.\n */\nexport interface VotingRound {\n id: string;\n phase: VotingRoundPhase;\n status: VotingRoundStatus;\n findings: Map<string, AgentFinding>; // findingId -> finding\n findingVotes: Map<string, FindingVote[]>; // findingId -> votes\n finalVotes: Map<string, Vote>; // agentId -> final vote\n startedAt: string;\n completedAt?: string;\n roundNumber: number;\n}\n\n/**\n * Configuration for the voting protocol.\n */\nexport interface VotingProtocolConfig {\n /** Number of agents in the committee (default: 3) */\n committeeSize: number;\n /** Maximum rounds before forcing decision (default: 3) */\n maxRounds: number;\n /** Timeout per round in milliseconds (default: multi-llm-panel guard, 900000) */\n roundTimeoutMs: number;\n /** Minimum agreement threshold (default: 2/3, approximately 0.667) */\n agreementThreshold: number;\n /** Enable anti-sycophancy detection (default: true) */\n enableAntiSycophancy: boolean;\n /** Similarity threshold for sycophancy detection (default: 0.8) */\n sycophancyThreshold: number;\n}\n\nexport const VotingProtocolConfigSchema = z.object({\n committeeSize: z.number().int().min(2).max(7).default(3),\n maxRounds: z.number().int().min(1).max(5).default(3),\n roundTimeoutMs: z.number().int().positive().default(VOTING_ROUND_DEFAULT_TIMEOUT_MS),\n agreementThreshold: z.number().min(0.5).max(1).default(SUPERMAJORITY_THRESHOLD),\n enableAntiSycophancy: z.boolean().default(true),\n sycophancyThreshold: z.number().min(0).max(1).default(0.8),\n});\n\nexport const DEFAULT_VOTING_PROTOCOL_CONFIG: VotingProtocolConfig = {\n committeeSize: 3,\n maxRounds: 3,\n roundTimeoutMs: VOTING_ROUND_DEFAULT_TIMEOUT_MS,\n // Default agreement level IS the supermajority (2/3) — single source (#3571).\n agreementThreshold: SUPERMAJORITY_THRESHOLD,\n enableAntiSycophancy: true,\n sycophancyThreshold: 0.8,\n};\n\n/**\n * Session state for a voting protocol instance.\n */\nexport interface VotingSession {\n id: string;\n topic: string;\n committee: string[]; // Agent IDs\n rounds: VotingRound[];\n currentRound: number;\n config: VotingProtocolConfig;\n status: 'active' | 'completed' | 'aborted';\n createdAt: string;\n completedAt?: string;\n finalResult?: VotingProtocolResult;\n}\n\n/**\n * Final result of a voting protocol session.\n */\nexport interface VotingProtocolResult {\n sessionId: string;\n topic: string;\n outcome: 'approved' | 'rejected' | 'needs_revision' | 'no_consensus';\n consolidatedFindings: ConsolidatedFinding[];\n roundSummaries: RoundSummary[];\n agreementScore: number;\n sycophancyDetected: boolean;\n totalDurationMs: number;\n participatingAgents: string[];\n}\n\n/**\n * A consolidated finding after deliberation.\n */\nexport interface ConsolidatedFinding {\n id: string;\n category: AgentFinding['category'];\n severity: AgentFinding['severity'];\n description: string;\n location?: string;\n suggestion?: string;\n supportingAgents: string[];\n agreementRatio: number;\n originalFindings: AgentFinding[];\n}\n\n/**\n * Summary of a single round.\n */\nexport interface RoundSummary {\n roundNumber: number;\n phase: VotingRoundPhase;\n findingsCount: number;\n votesCount: number;\n agreementScore: number;\n durationMs: number;\n}\n\n/**\n * Interface for the multi-round voting protocol.\n * (Source: Issue #100, arXiv:2512.21352)\n */\nexport interface IVotingProtocol {\n /** Create a new voting session with a committee */\n createSession(\n topic: string,\n committee: string[],\n config?: Partial<VotingProtocolConfig>\n ): VotingSession;\n\n /** Start the analysis round (Round 1) */\n startAnalysisRound(sessionId: string): Promise<VotingRound>;\n\n /** Submit findings from an agent during analysis */\n submitFindings(sessionId: string, agentId: string, findings: AgentFinding[]): Promise<void>;\n\n /** Start the deliberation round (Round 2) */\n startDeliberationRound(sessionId: string): Promise<VotingRound>;\n\n /** Vote on findings during deliberation */\n voteOnFinding(sessionId: string, vote: FindingVote): Promise<void>;\n\n /** Start the consensus round (Round 3) */\n startConsensusRound(sessionId: string): Promise<VotingRound>;\n\n /** Submit final vote during consensus */\n submitFinalVote(sessionId: string, agentId: string, vote: Vote): Promise<void>;\n\n /** Get the final result (closes session if complete) */\n getResult(sessionId: string): Promise<VotingProtocolResult | null>;\n\n /** Check for sycophancy in the current round */\n detectSycophancy(sessionId: string): SycophancyReport;\n\n /** Get the current session state */\n getSession(sessionId: string): VotingSession | undefined;\n}\n\n/**\n * Report from sycophancy detection.\n */\nexport interface SycophancyReport {\n detected: boolean;\n confidenceScore: number;\n indicators: SycophancyIndicator[];\n affectedAgents: string[];\n recommendation: string;\n}\n\n/**\n * Individual sycophancy indicator.\n */\nexport interface SycophancyIndicator {\n type: 'premature_consensus' | 'opinion_convergence' | 'confidence_inflation' | 'echo_chamber';\n description: string;\n severity: 'low' | 'medium' | 'high';\n agents: string[];\n}\n","/**\n * nexus-agents/consensus - Weighted Byzantine Voting Types\n *\n * Weighted Byzantine Voting Types (Issue #103)\n * Based on CP-WBFT (arXiv:2511.10400)\n */\n\nimport { z } from 'zod';\nimport type { Vote } from './types-core.js';\nimport { SUPERMAJORITY_THRESHOLD } from './decision/thresholds.js';\n\n/**\n * Task outcome STATUS for tracking agent performance — a 4-state vote status,\n * NOT an outcome row. Named `*Status` to avoid colliding with the canonical\n * outcome *record* `TaskOutcome` in orchestration/outcomes (#3146/#3226: the\n * two were unrelated types that happened to share the name `TaskOutcome`).\n */\nexport const TaskOutcomeStatusSchema = z.enum(['success', 'failure', 'partial', 'unknown']);\nexport type TaskOutcomeStatus = z.infer<typeof TaskOutcomeStatusSchema>;\n\n/**\n * Extended agent performance with Byzantine detection.\n */\nexport interface WeightedAgentRecord {\n readonly agentId: string;\n readonly totalTasks: number;\n readonly successfulTasks: number;\n readonly failedTasks: number;\n readonly partialTasks: number;\n readonly successRate: number;\n readonly weight: number;\n readonly trustScore: number;\n readonly byzantineFlags: number;\n readonly lastActive: Date;\n readonly createdAt: Date;\n}\n\nexport const WeightedAgentRecordSchema = z.object({\n agentId: z.string().min(1),\n totalTasks: z.number().int().nonnegative(),\n successfulTasks: z.number().int().nonnegative(),\n failedTasks: z.number().int().nonnegative(),\n partialTasks: z.number().int().nonnegative(),\n successRate: z.number().min(0).max(1),\n weight: z.number().min(0).max(1),\n trustScore: z.number().min(0).max(1),\n byzantineFlags: z.number().int().nonnegative(),\n lastActive: z.date(),\n createdAt: z.date(),\n});\n\n/**\n * Weighted consensus result.\n */\nexport interface WeightedConsensusResult {\n readonly decision: 'approve' | 'reject' | 'no_consensus';\n readonly weightedApproval: number;\n readonly weightedRejection: number;\n readonly totalWeight: number;\n readonly quorumReached: boolean;\n readonly byzantineDetected: boolean;\n readonly participatingAgents: readonly string[];\n readonly weightBreakdown: ReadonlyMap<string, number>;\n}\n\n/**\n * Configuration for weighted Byzantine voting.\n */\nexport interface WeightedVotingConfig {\n /** Minimum weight to participate in voting (default: 0.1) */\n readonly minWeight: number;\n /** Maximum Byzantine fault tolerance (default: 0.33) */\n readonly maxByzantineFraction: number;\n /** Weight decay factor per failed task (default: 0.9) */\n readonly weightDecayFactor: number;\n /** Weight recovery factor per successful task (default: 1.05) */\n readonly weightRecoveryFactor: number;\n /** Trust score required to vote (default: 0.3) */\n readonly minTrustScore: number;\n /** Byzantine flag threshold for exclusion (default: 3) */\n readonly byzantineFlagThreshold: number;\n /** Initial weight for new agents (default: 0.5) */\n readonly initialWeight: number;\n /** Quorum threshold for valid consensus (default: 2/3, approximately 0.667) */\n readonly quorumThreshold: number;\n}\n\nexport const WeightedVotingConfigSchema = z.object({\n minWeight: z.number().min(0).max(1).default(0.1),\n maxByzantineFraction: z.number().min(0).max(0.5).default(0.33),\n weightDecayFactor: z.number().min(0.5).max(1).default(0.9),\n weightRecoveryFactor: z.number().min(1).max(2).default(1.05),\n minTrustScore: z.number().min(0).max(1).default(0.3),\n byzantineFlagThreshold: z.number().int().positive().default(3),\n initialWeight: z.number().min(0).max(1).default(0.5),\n quorumThreshold: z.number().min(0.5).max(1).default(SUPERMAJORITY_THRESHOLD),\n});\n\nexport const DEFAULT_WEIGHTED_VOTING_CONFIG: WeightedVotingConfig = {\n minWeight: 0.1,\n maxByzantineFraction: 0.33,\n weightDecayFactor: 0.9,\n weightRecoveryFactor: 1.05,\n minTrustScore: 0.3,\n byzantineFlagThreshold: 3,\n initialWeight: 0.5,\n // Default quorum IS the supermajority (2/3) — single source (#3571).\n quorumThreshold: SUPERMAJORITY_THRESHOLD,\n};\n\n/**\n * Interface for weighted Byzantine voting.\n * (Source: Issue #103, arXiv:2511.10400 - CP-WBFT)\n */\nexport interface IWeightedVoting {\n /** Calculate vote weight for an agent */\n calculateWeight(agentId: string): number;\n\n /** Update agent performance based on task outcome */\n updatePerformance(agentId: string, outcome: TaskOutcomeStatus): void;\n\n /** Run weighted consensus on votes */\n weightedConsensus(votes: ReadonlyMap<string, Vote>): WeightedConsensusResult;\n\n /** Register a new agent */\n registerAgent(agentId: string): void;\n\n /** Get agent performance record */\n getAgentRecord(agentId: string): WeightedAgentRecord | undefined;\n\n /** Flag agent for Byzantine behavior */\n flagByzantine(agentId: string, reason: string): void;\n\n /** Get all agent records */\n getAllRecords(): readonly WeightedAgentRecord[];\n\n /** Check if agent can vote */\n canVote(agentId: string): boolean;\n\n /** Recalibrate all weights based on global performance */\n recalibrateWeights(): void;\n}\n","/**\n * nexus-agents/consensus - Higher-Order Voting Types\n *\n * Type definitions for Opinion-Wise (OW) and Independent Subset Partition (ISP)\n * voting methods that account for correlations between agent opinions.\n *\n * The correlation-aware aggregation these types describe is computed, but the\n * verdict is NOT taken from it: `calculateOutcome` tallies approve/reject as a\n * plain ratio, and the correlation posterior only drives contrarian escalation\n * (#4701).\n *\n * @module consensus/higher-order-types\n * (Source: Issue #333)\n */\n\nimport { z } from 'zod';\nimport type { Vote, VoteDecision } from './types-core.js';\n\n// ============================================================================\n// CORRELATION TYPES\n// ============================================================================\n\n/**\n * Pair of agent IDs for correlation tracking.\n * Stored as \"agentA:agentB\" where agentA < agentB lexicographically.\n */\nexport type AgentPairKey = `${string}:${string}`;\n\n/**\n * Creates a canonical agent pair key for correlation lookup.\n * Orders agents lexicographically to ensure consistent keys.\n */\nexport function createAgentPairKey(agentA: string, agentB: string): AgentPairKey {\n return agentA < agentB ? `${agentA}:${agentB}` : `${agentB}:${agentA}`;\n}\n\n/**\n * Extracts agent IDs from a pair key.\n */\nexport function parseAgentPairKey(key: AgentPairKey): [string, string] {\n const parts = key.split(':');\n if (parts.length !== 2 || parts[0] === undefined || parts[1] === undefined) {\n throw new Error(`Invalid agent pair key: ${key}`);\n }\n return [parts[0], parts[1]];\n}\n\n/**\n * Correlation coefficient between two agents' voting patterns.\n * Range: -1 (perfectly anti-correlated) to +1 (perfectly correlated).\n * 0 indicates independence.\n */\nexport const CorrelationCoefficientSchema = z.number().min(-1).max(1);\nexport type CorrelationCoefficient = z.infer<typeof CorrelationCoefficientSchema>;\n\n/**\n * Correlation matrix storing pairwise correlations between agents.\n */\nexport type CorrelationMatrix = Map<AgentPairKey, CorrelationCoefficient>;\n\n/**\n * A subset of agents that vote independently of each other.\n * Used in ISP (Independent Subset Partition) method.\n */\nexport interface IndependentSubset {\n /** Unique identifier for this subset */\n readonly id: string;\n /** Agent IDs in this independent subset */\n readonly agentIds: readonly string[];\n /**\n * Average internal independence score (lower = more independent).\n *\n * Averaged over the pairs that HAVE a correlation, so read it together with\n * {@link pairCoverage}: a subset whose pairs were measured at 0 and one whose\n * pairs were never observed both score 0, and 0 is the score that earns the\n * maximum posterior weight.\n */\n readonly independenceScore: number;\n /**\n * How many of the subset's agent pairs actually had a correlation, out of how\n * many exist.\n *\n * `observed < total` means {@link independenceScore} is an average over a\n * subset of the pairs — the unobserved ones contributed nothing rather than\n * being represented as unknown. A singleton has `total: 0`: there is no pair\n * to observe, so its score is not a measurement at all.\n */\n readonly pairCoverage: { readonly observed: number; readonly total: number };\n /** Number of observations supporting this grouping */\n readonly observationCount: number;\n}\n\nexport const IndependentSubsetSchema = z.object({\n id: z.string(),\n agentIds: z.array(z.string()),\n independenceScore: z.number().min(0).max(1),\n pairCoverage: z.object({\n observed: z.number().int().nonnegative(),\n total: z.number().int().nonnegative(),\n }),\n observationCount: z.number().int().nonnegative(),\n});\n\n// ============================================================================\n// VOTING HISTORY TYPES\n// ============================================================================\n\n/**\n * Record of a single voting observation for correlation tracking.\n */\nexport interface VotingObservation {\n /** Unique proposal ID */\n readonly proposalId: string;\n /** Agent who cast the vote */\n readonly agentId: string;\n /** The vote decision */\n readonly decision: VoteDecision;\n /** Confidence level (0-1) */\n readonly confidence: number;\n /** Whether the vote aligned with the final outcome */\n readonly alignedWithOutcome: boolean;\n /** Timestamp of the vote */\n readonly timestamp: Date;\n /** Pinned model identity used to select the correlation partition. */\n readonly modelKey?: string;\n /** Model that actually answered, retained for provenance only. */\n readonly observedModel?: string;\n}\n\nexport const VotingObservationSchema = z.object({\n proposalId: z.string(),\n agentId: z.string(),\n decision: z.enum(['approve', 'reject', 'abstain']),\n confidence: z.number().min(0).max(1),\n alignedWithOutcome: z.boolean(),\n timestamp: z.date(),\n modelKey: z.string().optional(),\n observedModel: z.string().optional(),\n});\n\n/** Model identities associated with one correlation-recording operation. */\nexport interface CorrelationRecordContext {\n /** Role-to-pinned-model map used for correlation partition selection. */\n readonly modelPins: ReadonlyMap<string, string>;\n /** Role-to-serving-model map retained only as observation provenance. */\n readonly observedModels?: ReadonlyMap<string, string>;\n}\n\n/**\n * Aggregated voting history for a pair of agents.\n */\nexport interface PairwiseVotingHistory {\n /** Agent pair key */\n readonly pairKey: AgentPairKey;\n /** Number of proposals where both agents voted */\n readonly jointObservations: number;\n /** Number of times both agents agreed */\n readonly agreements: number;\n /** Number of times agents disagreed */\n readonly disagreements: number;\n /** Computed correlation coefficient */\n readonly correlation: CorrelationCoefficient;\n /** Last update timestamp */\n readonly lastUpdated: Date;\n}\n\nexport const PairwiseVotingHistorySchema = z.object({\n pairKey: z.string() as z.ZodType<AgentPairKey>,\n jointObservations: z.number().int().nonnegative(),\n agreements: z.number().int().nonnegative(),\n disagreements: z.number().int().nonnegative(),\n correlation: CorrelationCoefficientSchema,\n lastUpdated: z.date(),\n});\n\n// ============================================================================\n// HIGHER-ORDER VOTING CONFIG\n// ============================================================================\n\n/**\n * Configuration for higher-order voting.\n * Correlation aggregates are lifetime evidence; retained records are count-bounded\n * by `maxProposals` FIFO and `maxObservationsPerAgent`, and active history is\n * partitioned by each role's pinned model. The legacy correlation lifetime keys\n * are deprecated and ignored.\n */\nexport interface HigherOrderVotingConfig {\n /** Minimum observations before using correlation data (default: 10) */\n readonly minObservationsForCorrelation: number;\n /** Correlation threshold to consider agents correlated (default: 0.3) */\n readonly correlationThreshold: number;\n /**\n * @deprecated Ignored since 8.x: correlation evidence is lifetime and partitioned by the role's pinned model (#5555); nothing reads this value. Removed in the next major (#5564).\n */\n readonly correlationMaxAgeMs: number;\n /** Independence threshold for ISP grouping (default: 0.2) */\n readonly independenceThreshold: number;\n /** Whether to fall back to simple voting when correlation data insufficient */\n readonly fallbackToSimpleVoting: boolean;\n /**\n * @deprecated Ignored since 8.x: correlation evidence is lifetime and partitioned by the role's pinned model (#5555); nothing reads this value. Removed in the next major (#5564).\n */\n readonly observationDecayFactor: number;\n /** Maximum observations to store per agent before FIFO eviction (default: 1000) */\n readonly maxObservationsPerAgent: number;\n /** Maximum total proposals to track before evicting oldest (default: 5000) */\n readonly maxProposals: number;\n /** Maximum pairwise history entries before LRU eviction (default: 100) */\n readonly maxTrackedPairs: number;\n}\n\nexport const HigherOrderVotingConfigSchema = z.object({\n minObservationsForCorrelation: z.number().int().positive().default(10),\n correlationThreshold: z.number().min(0).max(1).default(0.3),\n /**\n * @deprecated Ignored since 8.x: correlation evidence is lifetime and partitioned by the role's pinned model (#5555); nothing reads this value. Removed in the next major (#5564).\n */\n correlationMaxAgeMs: z.number().int().positive().default(86400000), // 24 hours\n independenceThreshold: z.number().min(0).max(1).default(0.2),\n fallbackToSimpleVoting: z.boolean().default(true),\n /**\n * @deprecated Ignored since 8.x: correlation evidence is lifetime and partitioned by the role's pinned model (#5555); nothing reads this value. Removed in the next major (#5564).\n */\n observationDecayFactor: z.number().min(0).max(1).default(0.95),\n maxObservationsPerAgent: z.number().int().positive().default(1000),\n maxProposals: z.number().int().positive().default(5000),\n maxTrackedPairs: z.number().int().positive().default(100),\n});\n\nexport const DEFAULT_HIGHER_ORDER_CONFIG: HigherOrderVotingConfig = {\n minObservationsForCorrelation: 10,\n correlationThreshold: 0.3,\n correlationMaxAgeMs: 86400000, // 24 hours\n independenceThreshold: 0.2,\n fallbackToSimpleVoting: true,\n observationDecayFactor: 0.95,\n maxObservationsPerAgent: 1000,\n maxProposals: 5000,\n maxTrackedPairs: 100,\n};\n\n// ============================================================================\n// HIGHER-ORDER VOTING RESULTS\n// ============================================================================\n\n/**\n * Result of Bayesian aggregation with correlation awareness.\n */\nexport interface HigherOrderVotingResult {\n /** Final decision */\n readonly decision: 'approve' | 'reject' | 'no_consensus';\n /** Posterior probability of approval */\n readonly posteriorApproval: number;\n /** Posterior probability of rejection */\n readonly posteriorRejection: number;\n /** Effective number of independent votes */\n readonly effectiveVoteCount: number;\n /** Whether correlation data was sufficient */\n readonly usedCorrelationData: boolean;\n /** Method used: 'ow' (opinion-wise), 'isp', or 'simple' (fallback) */\n readonly method: 'ow' | 'isp' | 'simple';\n /** Improvement over baseline majority voting (percentage points) */\n readonly improvementOverBaseline: number;\n /** Independent subsets used (if ISP method) */\n readonly independentSubsets?: readonly IndependentSubset[];\n /** Agents whose votes were down-weighted due to correlation */\n readonly downweightedAgents: readonly string[];\n /** Reasoning for the decision */\n readonly reasoning: string;\n}\n\nexport const HigherOrderVotingResultSchema = z.object({\n decision: z.enum(['approve', 'reject', 'no_consensus']),\n posteriorApproval: z.number().min(0).max(1),\n posteriorRejection: z.number().min(0).max(1),\n effectiveVoteCount: z.number().nonnegative(),\n usedCorrelationData: z.boolean(),\n method: z.enum(['ow', 'isp', 'simple']),\n improvementOverBaseline: z.number(),\n independentSubsets: z.array(IndependentSubsetSchema).optional(),\n downweightedAgents: z.array(z.string()),\n reasoning: z.string(),\n});\n\n// ============================================================================\n// CORRELATION TRACKER INTERFACE\n// ============================================================================\n\n/**\n * Statistics about correlation tracking.\n */\nexport interface CorrelationTrackerStats {\n /** Total agents being tracked */\n readonly totalAgents: number;\n /** Total agent pairs with correlation data */\n readonly trackedPairs: number;\n /** Total voting observations recorded */\n readonly totalObservations: number;\n /** Average correlation across all pairs */\n readonly averageCorrelation: number;\n /** Number of identified independent subsets */\n readonly independentSubsetCount: number;\n /** Pairs with sufficient data for correlation calculation */\n readonly pairsWithSufficientData: number;\n}\n\nexport const CorrelationTrackerStatsSchema = z.object({\n totalAgents: z.number().int().nonnegative(),\n trackedPairs: z.number().int().nonnegative(),\n totalObservations: z.number().int().nonnegative(),\n averageCorrelation: z.number(),\n independentSubsetCount: z.number().int().nonnegative(),\n pairsWithSufficientData: z.number().int().nonnegative(),\n});\n\n/**\n * Interface for correlation tracking between agents.\n */\nexport interface ICorrelationTracker {\n /** Select the active model partition for each pinned role. */\n setCurrentModelPins?(modelPins: ReadonlyMap<string, string>): void;\n\n /**\n * Record a vote and its outcome for correlation tracking.\n */\n recordVote(\n agentId: string,\n vote: Vote,\n outcome: 'approved' | 'rejected',\n context?: CorrelationRecordContext\n ): void;\n\n /**\n * Record votes from multiple agents for the same proposal.\n */\n recordProposalVotes(\n proposalId: string,\n votes: ReadonlyMap<string, Vote>,\n outcome: 'approved' | 'rejected',\n context?: CorrelationRecordContext\n ): void;\n\n /**\n * Compute the full correlation matrix for all tracked agents.\n */\n computeCorrelationMatrix(): CorrelationMatrix;\n\n /**\n * Get correlation between two specific agents.\n * Returns undefined if insufficient data.\n */\n getCorrelation(agentA: string, agentB: string): CorrelationCoefficient | undefined;\n\n /**\n * Identify groups of agents that vote independently.\n */\n identifyIndependentSubsets(): readonly IndependentSubset[];\n\n /**\n * Check if there is sufficient correlation data for a set of agents.\n */\n hasSufficientData(agentIds: readonly string[]): boolean;\n\n /**\n * Get statistics about the correlation tracker.\n */\n getStats(): CorrelationTrackerStats;\n\n /**\n * Clear all recorded data.\n */\n clear(): void;\n}\n\n// ============================================================================\n// OW VOTING INTERFACE\n// ============================================================================\n\n/**\n * Interface for Opinion-Wise higher-order voting.\n */\nexport interface IHigherOrderVoting {\n /**\n * Aggregate votes using Bayesian correlation-aware method.\n */\n aggregateWithCorrelation(\n votes: ReadonlyMap<string, Vote>,\n correlationMatrix: CorrelationMatrix\n ): HigherOrderVotingResult;\n\n /**\n * Estimate correlation matrix from voting history.\n */\n estimateCorrelation(tracker: ICorrelationTracker): CorrelationMatrix;\n\n /**\n * Compute result using Independent Subset Partition method.\n */\n computeISP(\n votes: ReadonlyMap<string, Vote>,\n independentSubsets: readonly IndependentSubset[]\n ): HigherOrderVotingResult;\n\n /**\n * Full pipeline: estimate correlation, compute result.\n *\n * `tracker` is OPTIONAL (#3173): when omitted, the instance uses the tracker\n * injected at construction (`OWVotingOptions.tracker`), letting higher-order\n * voting be reused as a building block without threading the tracker through\n * every call. A per-call `tracker` still wins. Throws if neither is available.\n */\n aggregate(\n votes: ReadonlyMap<string, Vote>,\n tracker?: ICorrelationTracker\n ): HigherOrderVotingResult;\n\n /**\n * Get the current configuration.\n */\n getConfig(): HigherOrderVotingConfig;\n}\n","/**\n * nexus-agents/consensus - Higher-Order Voting Helpers\n *\n * Helper functions for Opinion-Wise (OW) and Independent Subset Partition (ISP)\n * voting methods. Extracted from higher-order-voting.ts to maintain file size limits.\n *\n * @module consensus/higher-order-helpers\n * (Source: Issue #333, #339)\n */\n\nimport type { Vote } from './types-core.js';\nimport type {\n CorrelationMatrix,\n HigherOrderVotingResult,\n IndependentSubset,\n} from './higher-order-types.js';\nimport { createAgentPairKey } from './higher-order-types.js';\n\n/**\n * Result of Bayesian aggregation.\n */\nexport interface BayesianAggregateResult {\n readonly posteriorApproval: number;\n readonly posteriorRejection: number;\n readonly effectiveVoteCount: number;\n readonly downweightedAgents: string[];\n}\n\n/**\n * Result of subset aggregation.\n */\nexport interface SubsetAggregationResult {\n readonly subsetResults: Array<{ approval: number; rejection: number; weight: number }>;\n readonly downweightedAgents: string[];\n}\n\n/**\n * Result of combined subset results.\n */\nexport interface CombinedSubsetResult {\n readonly posteriorApproval: number;\n readonly posteriorRejection: number;\n readonly totalWeight: number;\n}\n\n/**\n * Check if there is sufficient correlation data for analysis.\n */\nexport function hasSufficientCorrelationData(\n agentIds: readonly string[],\n correlationMatrix: CorrelationMatrix\n): boolean {\n if (agentIds.length < 2) return false;\n\n let pairsWithData = 0;\n const totalPairs = (agentIds.length * (agentIds.length - 1)) / 2;\n\n for (let i = 0; i < agentIds.length; i++) {\n for (let j = i + 1; j < agentIds.length; j++) {\n const agentA = agentIds[i];\n const agentB = agentIds[j];\n if (agentA !== undefined && agentB !== undefined) {\n const pairKey = createAgentPairKey(agentA, agentB);\n if (correlationMatrix.has(pairKey)) {\n pairsWithData++;\n }\n }\n }\n }\n\n return pairsWithData >= Math.ceil(totalPairs * 0.5);\n}\n\n/**\n * Compute effective weights for agents based on correlations.\n * Reduces weights for highly correlated agents.\n */\nexport function computeEffectiveWeights(\n agentIds: readonly string[],\n correlationMatrix: CorrelationMatrix,\n correlationThreshold: number\n): Map<string, number> {\n const weights = new Map<string, number>();\n\n // Start with equal weights\n for (const agentId of agentIds) {\n weights.set(agentId, 1.0);\n }\n\n // Reduce weights for highly correlated agents\n for (let i = 0; i < agentIds.length; i++) {\n for (let j = i + 1; j < agentIds.length; j++) {\n const agentA = agentIds[i];\n const agentB = agentIds[j];\n if (agentA === undefined || agentB === undefined) continue;\n\n const pairKey = createAgentPairKey(agentA, agentB);\n const correlation = correlationMatrix.get(pairKey);\n\n if (correlation !== undefined && correlation > correlationThreshold) {\n // Reduce weight proportionally to correlation\n const reduction = correlation * 0.5;\n const currentWeightA = weights.get(agentA) ?? 1.0;\n const currentWeightB = weights.get(agentB) ?? 1.0;\n\n // Apply reduction to both agents (but less to avoid over-penalizing)\n weights.set(agentA, Math.max(0.1, currentWeightA - reduction * 0.5));\n weights.set(agentB, Math.max(0.1, currentWeightB - reduction * 0.5));\n }\n }\n }\n\n // NOTE (#3172, investigated + rejected): a \"restore uniform weights when all\n // collapse to the floor\" guard was considered but is incorrect. When agents\n // are equally correlated, equal downweighting is the CORRECT behavior (they\n // are equally redundant), and because the Bayesian aggregate is a weighted\n // average, scaling all weights equally is invariant — all-at-floor yields the\n // same posterior as uniform, so it is not degenerate. Restoring uniform would\n // wrongly treat correlated agents as independent and inflate the effective\n // vote count (guarded by the \"all perfectly correlated\" test).\n\n return weights;\n}\n\n/**\n * Perform Bayesian aggregation of votes with effective weights.\n */\nexport function bayesianAggregate(\n votes: ReadonlyMap<string, Vote>,\n effectiveWeights: Map<string, number>\n): BayesianAggregateResult {\n let weightedApproval = 0;\n let weightedRejection = 0;\n let totalWeight = 0;\n const downweightedAgents: string[] = [];\n\n for (const [agentId, vote] of votes) {\n const weight = effectiveWeights.get(agentId) ?? 1.0;\n\n // Track downweighted agents\n if (weight < 0.8) {\n downweightedAgents.push(agentId);\n }\n\n // Weight by confidence and effective weight\n const effectiveWeight = weight * vote.confidence;\n totalWeight += effectiveWeight;\n\n if (vote.decision === 'approve') {\n weightedApproval += effectiveWeight;\n } else if (vote.decision === 'reject') {\n weightedRejection += effectiveWeight;\n }\n // Abstains contribute to total weight but not to either side\n }\n\n const posteriorApproval = totalWeight > 0 ? weightedApproval / totalWeight : 0.5;\n const posteriorRejection = totalWeight > 0 ? weightedRejection / totalWeight : 0.5;\n const effectiveVoteCount = totalWeight;\n\n return { posteriorApproval, posteriorRejection, effectiveVoteCount, downweightedAgents };\n}\n\n/**\n * Aggregate votes within independent subsets.\n */\nexport function aggregateSubsets(\n votes: ReadonlyMap<string, Vote>,\n independentSubsets: readonly IndependentSubset[]\n): SubsetAggregationResult {\n const subsetResults: Array<{ approval: number; rejection: number; weight: number }> = [];\n const downweightedAgents: string[] = [];\n\n for (const subset of independentSubsets) {\n const subsetVotes = new Map<string, Vote>();\n for (const agentId of subset.agentIds) {\n const vote = votes.get(agentId);\n if (vote !== undefined) subsetVotes.set(agentId, vote);\n }\n if (subsetVotes.size === 0) continue;\n\n const { approval, rejection } = countSubsetVotes(subsetVotes);\n const weight = subsetVotes.size * (1 - subset.independenceScore);\n subsetResults.push({ approval, rejection, weight });\n\n // `downweightedAgents` is documented as \"agents whose votes were\n // down-weighted DUE TO CORRELATION\", and it is surfaced to MCP. This branch\n // used to push every singleton, which is subset CARDINALITY, not weight: a\n // singleton whose independence score is 0 gets `1 * (1 - 0) = 1`, the same\n // per-vote multiplier every other agent receives. There was no input for\n // which an ISP-reported downweighted agent actually carried less than its\n // unweighted vote. Measured now, matching what the opinion-wise path does\n // with the same field.\n if (weight < subsetVotes.size) downweightedAgents.push(...subset.agentIds);\n }\n return { subsetResults, downweightedAgents };\n}\n\n/**\n * Combine subset results into overall posterior probabilities.\n */\nexport function combineSubsetResults(\n subsetResults: readonly { approval: number; rejection: number; weight: number }[]\n): CombinedSubsetResult {\n let totalApproval = 0;\n let totalRejection = 0;\n let totalWeight = 0;\n for (const { approval, rejection, weight } of subsetResults) {\n totalApproval += approval * weight;\n totalRejection += rejection * weight;\n totalWeight += weight;\n }\n return {\n posteriorApproval: totalWeight > 0 ? totalApproval / totalWeight : 0.5,\n posteriorRejection: totalWeight > 0 ? totalRejection / totalWeight : 0.5,\n totalWeight,\n };\n}\n\n/**\n * Count votes within a subset, weighted by confidence.\n */\nexport function countSubsetVotes(votes: ReadonlyMap<string, Vote>): {\n approval: number;\n rejection: number;\n} {\n let approval = 0;\n let rejection = 0;\n\n for (const vote of votes.values()) {\n if (vote.decision === 'approve') {\n approval += vote.confidence;\n } else if (vote.decision === 'reject') {\n rejection += vote.confidence;\n }\n }\n\n const total = approval + rejection;\n return {\n approval: total > 0 ? approval / total : 0.5,\n rejection: total > 0 ? rejection / total : 0.5,\n };\n}\n\n/**\n * Determine decision based on posterior probabilities.\n */\nexport function determineHigherOrderDecision(\n posteriorApproval: number,\n posteriorRejection: number\n): 'approve' | 'reject' | 'no_consensus' {\n const diff = Math.abs(posteriorApproval - posteriorRejection);\n\n // Require significant margin for decision\n if (diff < 0.1) {\n return 'no_consensus';\n }\n\n return posteriorApproval > posteriorRejection ? 'approve' : 'reject';\n}\n\n/**\n * Perform simple majority aggregation (no correlation data).\n */\nexport function aggregateSimple(\n votes: ReadonlyMap<string, Vote>,\n buildReasoningFn: (\n decision: 'approve' | 'reject' | 'no_consensus',\n effectiveVotes: number,\n downweightedAgents: string[],\n method: 'ow' | 'isp' | 'simple'\n ) => string\n): HigherOrderVotingResult {\n let approve = 0;\n let reject = 0;\n let total = 0;\n\n for (const vote of votes.values()) {\n if (vote.decision === 'approve') {\n approve++;\n } else if (vote.decision === 'reject') {\n reject++;\n }\n if (vote.decision !== 'abstain') {\n total++;\n }\n }\n\n const posteriorApproval = total > 0 ? approve / total : 0.5;\n const posteriorRejection = total > 0 ? reject / total : 0.5;\n const decision = determineHigherOrderDecision(posteriorApproval, posteriorRejection);\n\n return {\n decision,\n posteriorApproval,\n posteriorRejection,\n effectiveVoteCount: total,\n usedCorrelationData: false,\n method: 'simple',\n improvementOverBaseline: 0,\n downweightedAgents: [],\n reasoning: buildReasoningFn(decision, total, [], 'simple'),\n };\n}\n\n/**\n * Calculate improvement over baseline.\n */\nexport function calculateImprovement(\n posteriorApproval: number,\n posteriorRejection: number,\n decision: 'approve' | 'reject' | 'no_consensus',\n baseline: HigherOrderVotingResult\n): number {\n // Improvement is measured by increased confidence in the same direction\n if (decision === 'no_consensus' || baseline.decision === 'no_consensus') {\n return 0;\n }\n\n const currentConfidence = decision === 'approve' ? posteriorApproval : posteriorRejection;\n const baselineConfidence =\n baseline.decision === 'approve' ? baseline.posteriorApproval : baseline.posteriorRejection;\n\n // Return improvement as percentage points\n return (currentConfidence - baselineConfidence) * 100;\n}\n\n/**\n * Build reasoning string for voting result.\n */\nexport function buildReasoning(\n decision: 'approve' | 'reject' | 'no_consensus',\n effectiveVotes: number,\n downweightedAgents: readonly string[],\n method: 'ow' | 'isp' | 'simple'\n): string {\n const methodName =\n method === 'ow'\n ? 'Opinion-Wise Bayesian aggregation'\n : method === 'isp'\n ? 'Independent Subset Partition'\n : 'simple majority voting';\n\n let reasoning = `Decision reached via ${methodName} with ${effectiveVotes.toFixed(1)} effective votes. `;\n\n if (downweightedAgents.length > 0) {\n reasoning += `${String(downweightedAgents.length)} agent(s) downweighted due to correlation. `;\n }\n\n if (decision === 'no_consensus') {\n reasoning += 'No consensus reached due to insufficient margin.';\n } else {\n reasoning += `Final decision: ${decision}.`;\n }\n\n return reasoning;\n}\n","/**\n * nexus-agents/consensus - Higher-Order Voting Implementation\n *\n * Implements Opinion-Wise (OW) and Independent Subset Partition (ISP) voting\n * methods that account for correlations between agent opinions.\n *\n * Traditional voting assumes independence between voters. The correlation-aware\n * aggregation here is designed for correlated agents, BUT NOTE (#4701): `calculateOutcome` — the `IVotingStrategy` entry point the\n * `ConsensusEngine` calls — uses `aggregateSimpleInternal` and ignores weights.\n * `aggregateWithCorrelation` is reached only via `runHigherOrderVoting`, whose\n * `posteriorApproval` feeds contrarian escalation, not the verdict. So selecting\n * `higher_order` does not currently buy a correlation-weighted approve/reject.\n *\n * @module consensus/higher-order-voting\n * (Source: Issue #333)\n */\n\nimport { createLogger } from '../core/logger.js';\nimport type { Vote, VoteCounts } from './types-core.js';\nimport type {\n IHigherOrderVoting,\n ICorrelationTracker,\n CorrelationMatrix,\n HigherOrderVotingConfig,\n HigherOrderVotingResult,\n IndependentSubset,\n} from './higher-order-types.js';\nimport { DEFAULT_HIGHER_ORDER_CONFIG } from './higher-order-types.js';\nimport type { IVotingStrategy, VotingOutcome } from './strategies.js';\nimport type { ConsensusAlgorithm } from './types-core.js';\nimport {\n hasSufficientCorrelationData,\n computeEffectiveWeights,\n bayesianAggregate,\n aggregateSubsets,\n combineSubsetResults,\n determineHigherOrderDecision,\n aggregateSimple,\n calculateImprovement,\n buildReasoning,\n} from './higher-order-helpers.js';\n\nconst logger = createLogger({ component: 'higher-order-voting' });\n\n/** Options for creating OWVoting instance. */\nexport interface OWVotingOptions {\n readonly config?: Partial<HigherOrderVotingConfig>;\n /**\n * Algorithm label this instance reports (#3168). Defaults to `simple_majority`\n * for backward compatibility; `HigherOrderVotingStrategy` sets `opinion_wise`.\n * Keeps the label consistent whether constructed directly or via a factory.\n */\n readonly algorithm?: ConsensusAlgorithm;\n /**\n * Correlation tracker this instance uses when {@link OWVoting.aggregate} is\n * called WITHOUT a per-call tracker (#3173). Injecting here lets higher-order\n * voting be reused as a building block (autonomous agents, test harnesses,\n * custom pipelines) without coupling to the MCP tool's process-wide singleton\n * or threading the tracker through every call. Omit it to keep the singleton\n * model — the MCP consensus path injects/passes its persistent tracker.\n */\n readonly tracker?: ICorrelationTracker;\n}\n\n/**\n * Opinion-Wise higher-order voting implementation.\n * Uses Bayesian aggregation with correlation awareness.\n */\nexport class OWVoting implements IHigherOrderVoting, IVotingStrategy {\n readonly algorithm: ConsensusAlgorithm;\n private readonly config: HigherOrderVotingConfig;\n /** #3173: tracker used when `aggregate` is called without a per-call one. */\n private readonly injectedTracker: ICorrelationTracker | undefined;\n\n constructor(options: OWVotingOptions = {}) {\n this.config = { ...DEFAULT_HIGHER_ORDER_CONFIG, ...options.config };\n // #3168: configurable so the label is correct whether built directly or via\n // a factory; defaults to simple_majority for backward compatibility.\n this.algorithm = options.algorithm ?? 'simple_majority';\n this.injectedTracker = options.tracker;\n logger.info('OWVoting initialized', { config: this.config, algorithm: this.algorithm });\n }\n\n /** IVotingStrategy implementation for integration with ConsensusEngine. */\n calculateOutcome(votes: Map<string, Vote>, _weights?: Map<string, number>): VotingOutcome {\n const result = this.aggregateSimpleInternal(votes);\n return this.toVotingOutcome(votes, result);\n }\n\n aggregateWithCorrelation(\n votes: ReadonlyMap<string, Vote>,\n correlationMatrix: CorrelationMatrix\n ): HigherOrderVotingResult {\n const agentIds = Array.from(votes.keys());\n const hasSufficientData = hasSufficientCorrelationData(agentIds, correlationMatrix);\n\n if (!hasSufficientData && this.config.fallbackToSimpleVoting) {\n // Issue #525: Log at INFO level for visibility\n logger.info('Insufficient correlation data, falling back to simple voting', {\n agentCount: agentIds.length,\n reason: 'insufficient_correlation_data',\n });\n return this.aggregateSimpleInternal(votes);\n }\n\n const effectiveWeights = computeEffectiveWeights(\n agentIds,\n correlationMatrix,\n this.config.correlationThreshold\n );\n\n const { posteriorApproval, posteriorRejection, effectiveVoteCount, downweightedAgents } =\n bayesianAggregate(votes, effectiveWeights);\n\n const decision = determineHigherOrderDecision(posteriorApproval, posteriorRejection);\n const baselineResult = this.aggregateSimpleInternal(votes);\n const improvementOverBaseline = calculateImprovement(\n posteriorApproval,\n posteriorRejection,\n decision,\n baselineResult\n );\n\n const result: HigherOrderVotingResult = {\n decision,\n posteriorApproval,\n posteriorRejection,\n effectiveVoteCount,\n usedCorrelationData: hasSufficientData,\n method: 'ow',\n improvementOverBaseline,\n downweightedAgents,\n reasoning: buildReasoning(decision, effectiveVoteCount, downweightedAgents, 'ow'),\n };\n\n logger.info('OW aggregation complete', {\n decision,\n posteriorApproval: posteriorApproval.toFixed(3),\n effectiveVotes: effectiveVoteCount.toFixed(2),\n downweightedAgents: downweightedAgents.length,\n });\n\n return result;\n }\n\n estimateCorrelation(tracker: ICorrelationTracker): CorrelationMatrix {\n return tracker.computeCorrelationMatrix();\n }\n\n computeISP(\n votes: ReadonlyMap<string, Vote>,\n independentSubsets: readonly IndependentSubset[]\n ): HigherOrderVotingResult {\n if (independentSubsets.length === 0) {\n // Issue #525: Log at INFO level for visibility\n logger.info('No independent subsets, falling back to simple voting', {\n reason: 'no_independent_subsets',\n });\n return this.aggregateSimpleInternal(votes);\n }\n\n const { subsetResults, downweightedAgents } = aggregateSubsets(votes, independentSubsets);\n const { posteriorApproval, posteriorRejection } = combineSubsetResults(subsetResults);\n const effectiveVoteCount = independentSubsets.length;\n const decision = determineHigherOrderDecision(posteriorApproval, posteriorRejection);\n\n const baselineResult = this.aggregateSimpleInternal(votes);\n const improvementOverBaseline = calculateImprovement(\n posteriorApproval,\n posteriorRejection,\n decision,\n baselineResult\n );\n\n const result: HigherOrderVotingResult = {\n decision,\n posteriorApproval,\n posteriorRejection,\n effectiveVoteCount,\n usedCorrelationData: true,\n method: 'isp',\n improvementOverBaseline,\n independentSubsets,\n downweightedAgents,\n reasoning: buildReasoning(decision, effectiveVoteCount, downweightedAgents, 'isp'),\n };\n\n logger.info('ISP aggregation complete', {\n decision,\n subsetCount: independentSubsets.length,\n posteriorApproval: posteriorApproval.toFixed(3),\n });\n\n return result;\n }\n\n aggregate(\n votes: ReadonlyMap<string, Vote>,\n tracker?: ICorrelationTracker\n ): HigherOrderVotingResult {\n // #3173: per-call tracker wins; otherwise use the one injected at construction.\n // Neither present is a programming error (no correlation data source available).\n const effectiveTracker = tracker ?? this.injectedTracker;\n if (effectiveTracker === undefined) {\n throw new Error(\n 'OWVoting.aggregate requires an ICorrelationTracker — pass it as an argument ' +\n 'or inject one via OWVotingOptions.tracker (#3173).'\n );\n }\n return this.aggregateWith(votes, effectiveTracker);\n }\n\n /** Core aggregation against a resolved tracker (#3173 — extracted from aggregate). */\n private aggregateWith(\n votes: ReadonlyMap<string, Vote>,\n tracker: ICorrelationTracker\n ): HigherOrderVotingResult {\n const agentIds = Array.from(votes.keys());\n\n if (!tracker.hasSufficientData(agentIds)) {\n if (this.config.fallbackToSimpleVoting) {\n // Issue #525: Log at INFO level for visibility\n logger.info('Insufficient data for correlation analysis, using simple voting', {\n agentCount: agentIds.length,\n reason: 'insufficient_tracker_data',\n });\n return this.aggregateSimpleInternal(votes);\n }\n }\n\n const correlationMatrix = tracker.computeCorrelationMatrix();\n const owResult = this.aggregateWithCorrelation(votes, correlationMatrix);\n\n const independentSubsets = tracker.identifyIndependentSubsets();\n if (independentSubsets.length > 1) {\n const ispResult = this.computeISP(votes, independentSubsets);\n const owConfidence = Math.abs(owResult.posteriorApproval - 0.5) * 2;\n const ispConfidence = Math.abs(ispResult.posteriorApproval - 0.5) * 2;\n\n if (ispConfidence > owConfidence) {\n logger.debug('Using ISP result over OW due to higher confidence');\n return ispResult;\n }\n }\n\n return owResult;\n }\n\n getConfig(): HigherOrderVotingConfig {\n return { ...this.config };\n }\n\n private aggregateSimpleInternal(votes: ReadonlyMap<string, Vote>): HigherOrderVotingResult {\n return aggregateSimple(votes, buildReasoning);\n }\n\n private toVotingOutcome(\n votes: Map<string, Vote>,\n result: HigherOrderVotingResult\n ): VotingOutcome {\n let approve = 0;\n let reject = 0;\n let abstain = 0;\n\n for (const vote of votes.values()) {\n if (vote.decision === 'approve') approve++;\n else if (vote.decision === 'reject') reject++;\n else abstain++;\n }\n\n const voteCounts: VoteCounts = { approve, reject, abstain, total: votes.size };\n\n // #4701: name the empty case, and name it the same way the other three\n // strategies do (`strategies.ts:136`, `:174`, `:210`). `aggregateSimple`\n // falls back to `posteriorApproval = 0.5` when nothing countable was cast,\n // which this method would otherwise publish as a measured-looking 50% —\n // absence rendered as a split. An all-abstain panel is reachable in\n // production: an errored voter and an unparseable response both abstain.\n if (approve + reject === 0) {\n return {\n approved: false,\n approvalPercentage: 0,\n voteCounts,\n reason: 'No votes cast (excluding abstentions)',\n };\n }\n\n const rawPercentage = result.posteriorApproval * 100;\n const approvalPercentage = Number.isFinite(rawPercentage) ? rawPercentage : 0;\n\n return {\n approved: result.decision === 'approve',\n approvalPercentage,\n voteCounts,\n reason: result.reasoning,\n };\n }\n}\n\n/** Creates a new OWVoting instance. */\nexport function createOWVoting(options?: OWVotingOptions): IHigherOrderVoting {\n return new OWVoting(options);\n}\n\n/**\n * Higher-order voting strategy for integration with VotingStrategyFactory.\n * Wraps OWVoting to provide IVotingStrategy interface.\n */\nexport class HigherOrderVotingStrategy extends OWVoting implements IVotingStrategy {\n constructor(options: OWVotingOptions = {}) {\n // #3168: set the algorithm label via the constructor so it survives\n // regardless of how the instance is created (no field-override divergence).\n super({ ...options, algorithm: options.algorithm ?? 'opinion_wise' });\n }\n}\n\n/** Creates a higher-order voting strategy for use with ConsensusEngine. */\nexport function createHigherOrderVotingStrategy(\n options?: OWVotingOptions\n): HigherOrderVotingStrategy {\n return new HigherOrderVotingStrategy(options);\n}\n","/**\n * nexus-agents/consensus/decision - Verdict computation\n *\n * The pure functions that turn a tally into a decision, extracted verbatim\n * (#6000 step 1) from the three files that used to hold them:\n *\n * - `evaluateThreshold` (from `consensus/strategies.ts`): ratio vs. bar — the\n * comparison behind the simple-majority, supermajority and proof-of-learning\n * strategies.\n * - `determineFinalStatus` (from `consensus/result-builder.ts`): quorum +\n * approval → the engine's `approved` / `rejected`.\n * - `mapOutcomeToDecision`, `resolveVoteDecision` and its helpers (from\n * `mcp/tools/consensus-vote-types.ts`): engine outcome + error policy →\n * the response-layer `approved` / `rejected` / `no_quorum`.\n *\n * What stays outside: the strategy classes that count votes and call\n * `evaluateThreshold` (`strategies.ts`), the engine's cascade and close\n * orchestration (`engine.ts`), the error-policy vote-list shaping that feeds\n * the engine (`consensus-vote-error-policy.ts`), and the response assembly in\n * `buildResponse`. Each previous home re-exports what moved, so the public\n * API is unchanged. Types from the MCP tool module are imported type-only, so\n * this module has no runtime edge into `mcp/`.\n *\n * @module consensus/decision/verdict\n */\n\nimport { isAbsentSeat } from '../../cli/voter-unverifiable.js';\nimport type {\n ConsensusVoteInput,\n ExtendedVotingResult,\n VoteDecisionStatus,\n VotingStrategy,\n} from '../../mcp/tools/consensus-vote-types.js';\nimport type { ProposalStatus } from '../types-core.js';\n\n// ============================================================================\n// Engine-level verdict\n// ============================================================================\n\n/**\n * Evaluates an approval ratio against a threshold — the shared math behind\n * the simple-majority, supermajority and proof-of-learning strategies.\n *\n * `inclusive` selects the comparison: `>=` for supermajority (an exact 2/3\n * passes), strict `>` for simple-majority and proof-of-learning (a tie at the\n * threshold is not enough). Callers apply their own zero-denominator guard\n * before calling this.\n */\nexport function evaluateThreshold(\n approveCount: number,\n votingTotal: number,\n threshold: number,\n inclusive: boolean\n): { approved: boolean; approvalPercentage: number } {\n const ratio = approveCount / votingTotal;\n return {\n approved: inclusive ? ratio >= threshold : ratio > threshold,\n approvalPercentage: ratio * 100,\n };\n}\n\n/**\n * Determine final status based on quorum and approval.\n */\nexport function determineFinalStatus(quorumReached: boolean, approved: boolean): ProposalStatus {\n if (!quorumReached || !approved) return 'rejected';\n return 'approved';\n}\n\n// ============================================================================\n// Response-level decision\n// ============================================================================\n\n/** Maps ProposalStatus to VoteDecisionStatus. */\nexport function mapOutcomeToDecision(outcome: string): VoteDecisionStatus {\n switch (outcome) {\n case 'approved':\n return 'approved';\n case 'rejected':\n return 'rejected';\n case 'timeout':\n return 'timeout';\n default:\n return 'pending';\n }\n}\n\n/**\n * #4132: the absolute approval fraction a strategy requires over the FULL panel.\n * `ceil(fraction * panelSize)` is the absolute number of approvals an\n * `absolute_quorum` verdict needs — an ABSOLUTE floor over every requested\n * voter, not a majority of the responders (which abstains/errors would shrink).\n * majority → 0.5, supermajority → 2/3, unanimous → 1.0; the higher_order family\n * and proof_of_learning follow the majority (0.5) baseline they tally against.\n */\nfunction absoluteQuorumFraction(strategy: VotingStrategy): number {\n switch (strategy) {\n case 'supermajority':\n return 2 / 3;\n case 'unanimous':\n return 1;\n default:\n return 0.5;\n }\n}\n\n/**\n * #5780: the smallest number of voters that must have cast approve-or-reject\n * before any ratio is applied to them.\n *\n * The gap this closes: every strategy measures its threshold over\n * `approve + reject`, and abstentions and errored seats leave that denominator\n * with no floor under it. `ERROR_FLOOR_FRACTION` voids a panel only when errors\n * EXCEED half, so one seat under it — 7 requested, 3 errored, 1 abstained —\n * left three respondents, and 2 approvals carried an architecture or security\n * vote at 66.7%.\n *\n * Two thirds of the requested panel, never fewer than three, never more than\n * the panel itself. That is one rule satisfying both figures the panel named\n * (7 → 5, quick 3 → 3); the `3` clamp is what makes quick mode require every\n * seat, since two thirds of 3 is 2.\n *\n * Deliberately about RESPONDENTS, not errors. `absolute_quorum` (#4132) voids\n * on an errored seat specifically, so an induced error cannot manufacture a\n * verdict; this is about how few voices decided, whatever silenced them — a\n * panel of 7 returning four abstentions and three votes has zero errors and\n * still should not decide. The two compose; neither replaces the other.\n */\nfunction minimumRespondents(panelSize: number): number {\n if (panelSize <= 0) return 0;\n return Math.min(panelSize, Math.max(Math.ceil((panelSize * 2) / 3), 3));\n}\n\n/** A vote decision plus the (optional) actionable reason a panel degraded. */\nexport interface VoteDecisionOutcome {\n readonly decision: VoteDecisionStatus;\n /** Set when the verdict degraded to `no_quorum` under absolute_quorum. */\n readonly degradeReason?: string;\n}\n\n/**\n * #4132: the absolute_quorum predicate (post-tally). Applied ONLY when\n * `errorPolicy === 'absolute_quorum'`; every other policy keeps the legacy\n * decision path untouched (opt-in).\n *\n * The invariant this enforces (anti-DoS): an induced voter error can NEVER\n * manufacture `approved` and NEVER manufacture `rejected` — errors force\n * `no_quorum`, a recoverable \"re-run the missing voice\" state. A GENUINE reject\n * (zero errors) still blocks. The happy path (all approve, zero errors,\n * contrarian present) stays `approved`.\n *\n * approved ⇔ errorCount === 0 AND (contrarian present-and-non-error, unless\n * quick-mode dropped it) AND approveCount >= ceil(frac * panel)\n * no_quorum ⇔ errorCount > 0 OR fewer results than `panelSize` requested (#6889) OR\n * the contrarian was requested but errored/missing\n * rejected ⇔ zero errors, contrarian present, engine rejected (genuine reject)\n * no_quorum ⇔ zero errors but the absolute approval floor was not met and there\n * is no genuine reject (abstain-heavy; recoverable)\n */\n/**\n * The \"an errored/absent voice voids the quorum\" half of the predicate. Returns\n * the actionable re-run reason when the panel had ANY error, or the contrarian\n * was required but errored/missing; `undefined` otherwise (clean panel).\n */\nfunction absoluteQuorumDegradeReason(\n result: ExtendedVotingResult,\n errorCount: number\n): string | undefined {\n const contrarianVote = result.votes.find((v) => v.role === 'catfish');\n const contrarianOk = contrarianVote !== undefined && !isAbsentSeat(contrarianVote);\n const contrarianDegraded = result.contrarianRequested === true && !contrarianOk;\n // #6094: a seat that could not read the artifact is an absence, not a\n // judgment, and degrades the quorum exactly as an errored seat does.\n const unverifiableRoles = result.votes\n .filter((v) => v.source === 'unverifiable')\n .map((v) => v.role);\n if (errorCount === 0 && unverifiableRoles.length === 0 && !contrarianDegraded) return undefined;\n\n const erroredRoles = result.votes.filter((v) => v.source === 'error').map((v) => v.role);\n const missingContrarian = contrarianDegraded && contrarianVote === undefined;\n const named = missingContrarian ? [...erroredRoles, 'catfish'] : erroredRoles;\n return `no_quorum: re-run — ${absentSeatClauses(named, unverifiableRoles).join('; ')} (absolute_quorum)`;\n}\n\n/** The \"[roles] errored\" and \"[roles] unverifiable\" clauses of the re-run reason. */\nfunction absentSeatClauses(\n erroredNames: readonly string[],\n unverifiable: readonly string[]\n): string[] {\n const clauses: string[] = [];\n if (erroredNames.length > 0 || unverifiable.length === 0) {\n const list = erroredNames.length > 0 ? erroredNames.join(', ') : 'contrarian';\n clauses.push(`voter(s) [${list}] errored`);\n }\n if (unverifiable.length > 0) {\n clauses.push(\n `voter(s) [${unverifiable.join(', ')}] unverifiable — could not read the artifact`\n );\n }\n return clauses;\n}\n\n/**\n * #6889: the re-run reason under absolute_quorum. A seat that returned no result\n * at all (including an empty panel) voids the verdict like an errored one, and a\n * co-occurring errored/unverifiable diagnosis is kept rather than shadowed.\n */\nfunction absoluteQuorumVoidReason(\n result: ExtendedVotingResult,\n errorCount: number,\n panel: number\n): string | undefined {\n const missing = panel - result.votes.length;\n const seatReason = absoluteQuorumDegradeReason(result, errorCount);\n if (missing <= 0) return seatReason;\n const missingClause = `${String(missing)} of ${String(panel)} requested voter(s) missing`;\n const seatClauses = seatReason\n ?.replace(/^no_quorum: re-run — /, '')\n .replace(/ \\(absolute_quorum\\)$/, '');\n const reasons = seatClauses === undefined ? missingClause : `${missingClause}; ${seatClauses}`;\n return `no_quorum: re-run — ${reasons} (absolute_quorum)`;\n}\n\nfunction computeAbsoluteQuorumDecision(\n result: ExtendedVotingResult,\n errorCount: number,\n allErrors: boolean\n): VoteDecisionOutcome {\n // The denominator is the panel that was REQUESTED, never less than returned.\n const panel = Math.max(result.panelSize ?? result.votes.length, result.votes.length);\n const degradeReason = absoluteQuorumVoidReason(result, errorCount, panel);\n if (degradeReason !== undefined) return { decision: 'no_quorum', degradeReason };\n\n // Zero errors, contrarian satisfied (or not required in quick mode).\n const needed = Math.ceil(absoluteQuorumFraction(result.strategy) * panel);\n const approveCount = result.votes.filter(\n (v) => v.source !== 'error' && v.vote.decision === 'approve'\n ).length;\n\n if (result.result.outcome === 'approved' && approveCount >= needed) {\n return { decision: 'approved' };\n }\n if (result.result.outcome === 'rejected' && !allErrors) {\n // A genuine reject (the engine rejected with zero errors) still blocks.\n return { decision: 'rejected' };\n }\n // Approved-by-responders but the absolute approval floor was not met (e.g.\n // abstain-heavy) — no error, no genuine reject, just not enough YES. Recoverable.\n return {\n decision: 'no_quorum',\n degradeReason: `no_quorum: absolute quorum not met (${String(approveCount)}/${String(needed)} approvals over ${String(panel)}-voter panel, absolute_quorum)`,\n };\n}\n\n/**\n * #5780: `no_quorum` when too few voices actually decided, or `undefined` when\n * the panel met its floor.\n *\n * `no_quorum` and not `rejected`: too few respondents is a statement about the\n * panel, not about the proposal, and it is recoverable by re-running the\n * missing seats — the same shape `absolute_quorum` uses for an errored voice.\n * Reporting it as a rejection would be a verdict the panel never reached.\n *\n * Applied ONLY to an approval, mirroring the asymmetry `absolute_quorum`\n * already encodes (\"A GENUINE reject still blocks\"). The harm in #5780 is that\n * too few voices can CARRY a decision; a rejection by too few blocks it, which\n * is the safe direction, and voiding that would add a re-run without\n * preventing anything. A thin reject is still visible in `panelCoverage`.\n */\nfunction respondentFloorOutcome(result: ExtendedVotingResult): VoteDecisionOutcome | undefined {\n if (result.result.outcome !== 'approved') return undefined;\n const panel = result.panelSize ?? result.votes.length;\n const floor = minimumRespondents(panel);\n const respondents = result.votes.filter(\n (v) => v.source !== 'error' && (v.vote.decision === 'approve' || v.vote.decision === 'reject')\n ).length;\n if (respondents >= floor) return undefined;\n return {\n decision: 'no_quorum',\n degradeReason: `no_quorum: ${String(respondents)} of ${String(panel)} voters decided; ${String(floor)} required before a ratio is applied (#5780)`,\n };\n}\n\n/**\n * Resolve the user-facing decision for a tallied vote. Keeps the pre-#4132 path\n * verbatim for every policy except `absolute_quorum`, which routes through\n * {@link computeAbsoluteQuorumDecision}.\n *\n * Exported (#4135) so `executeVoting` can stamp `ExtendedVotingResult.decision`\n * with the SAME computation `buildResponse` uses — the response-layer decision\n * (including `no_quorum`) is derived once, in one place, and can't diverge\n * between the engine result and the MCP response. The engine\n * `ConsensusResult.outcome` stays 2-valued; this is the widened view.\n * Under absolute_quorum, `result.panelSize` (the requested seat count) is the\n * denominator; a missing result voids the quorum like an errored one (#6889).\n */\nexport function resolveVoteDecision(\n input: ConsensusVoteInput,\n result: ExtendedVotingResult,\n errorCount: number\n): VoteDecisionOutcome {\n const allErrors = errorCount === result.votes.length && errorCount > 0;\n // #4053: an error-policy short-circuit (>50% hard floor, or fail_closed) VOIDED\n // the vote — that is no_quorum, not the panel rejecting. Applies to every policy.\n if (result.policyReason !== undefined || (!result.result.quorumReached && allErrors)) {\n return { decision: 'no_quorum' };\n }\n // #5780: the responder floor guards an APPROVAL under every policy and every\n // strategy — a denominator of three out of a requested seven is equally\n // unrepresentative whichever bar is measured over it.\n //\n // Ordered after `absolute_quorum`, not before, so that policy keeps its own\n // more specific degrade reason. The two are not redundant: absolute_quorum\n // guarantees `approveCount >= ceil(frac * panel)`, which subsumes the floor\n // at `supermajority` (5 approvals of 7) but NOT at `majority`, where 4\n // approvals over 4 respondents of a requested 7 clears it and still leaves\n // three voices unheard.\n if (input.errorPolicy === 'absolute_quorum') {\n const quorumOutcome = computeAbsoluteQuorumDecision(result, errorCount, allErrors);\n if (quorumOutcome.decision !== 'approved') return quorumOutcome;\n return respondentFloorOutcome(result) ?? quorumOutcome;\n }\n return (\n respondentFloorOutcome(result) ?? { decision: mapOutcomeToDecision(result.result.outcome) }\n );\n}\n","/**\n * nexus-agents/consensus - Voting Strategies\n *\n * Implementation of different voting strategies for consensus engine.\n * Supports simple majority, supermajority, unanimous, and proof-of-learning.\n */\n\nimport type {\n ConsensusAlgorithm,\n Vote,\n VoteCounts,\n WeightedVoteCounts,\n AgentPerformance,\n WeightBasis,\n} from './types.js';\nimport { VOTING_THRESHOLDS } from './decision/thresholds.js';\nimport { HigherOrderVotingStrategy } from './higher-order-voting.js';\n// The ratio-vs-bar comparison lives in the governed decision module (#6000 step 1).\nimport { evaluateThreshold } from './decision/verdict.js';\n\n/**\n * Interface for voting strategy implementations.\n */\nexport interface IVotingStrategy {\n readonly algorithm: ConsensusAlgorithm;\n calculateOutcome(votes: Map<string, Vote>, weights?: Map<string, number>): VotingOutcome;\n}\n\n/**\n * Result of a voting strategy calculation.\n */\nexport interface VotingOutcome {\n approved: boolean;\n approvalPercentage: number;\n voteCounts: VoteCounts;\n weightedCounts?: WeightedVoteCounts;\n /**\n * Present on weighted strategies only. Absent means the strategy does not\n * weight at all (simple majority, supermajority, unanimous) — which is\n * different from `'unweighted'`, meaning a weighted strategy ran with nothing\n * to weight by.\n */\n weightBasis?: WeightBasis;\n reason: string;\n}\n\n/**\n * Classifies a weighted tally by how many of its voters had a real weight\n * supplied (#5117).\n *\n * A voter absent from `weights` had no performance record; `countWeightedVotes`\n * already defaults such a voter to `1.0`, so the arithmetic is unchanged — the\n * absence is what carries the provenance.\n */\nfunction deriveWeightBasis(votes: Map<string, Vote>, weights: Map<string, number>): WeightBasis {\n let withRecord = 0;\n for (const agentId of votes.keys()) {\n if (weights.has(agentId)) withRecord++;\n }\n\n // The empty case, named rather than left to a default: zero voters carrying a\n // record — including the zero-voter case — is 'unweighted', never\n // 'performance'. Answering it with `withRecord === votes.size` would make\n // 0 === 0 report a full performance basis over nothing measured.\n if (withRecord === 0) return 'unweighted';\n return withRecord === votes.size ? 'performance' : 'partial';\n}\n\n/**\n * Base voting strategy with common functionality.\n */\nabstract class BaseVotingStrategy implements IVotingStrategy {\n abstract readonly algorithm: ConsensusAlgorithm;\n\n abstract calculateOutcome(votes: Map<string, Vote>, weights?: Map<string, number>): VotingOutcome;\n\n /**\n * Count votes by decision type.\n */\n protected countVotes(votes: Map<string, Vote>): VoteCounts {\n let approve = 0;\n let reject = 0;\n let abstain = 0;\n\n for (const vote of votes.values()) {\n switch (vote.decision) {\n case 'approve':\n approve++;\n break;\n case 'reject':\n reject++;\n break;\n case 'abstain':\n abstain++;\n break;\n }\n }\n\n return { approve, reject, abstain, total: votes.size };\n }\n\n /**\n * Calculate weighted vote counts using agent performance weights.\n */\n protected countWeightedVotes(\n votes: Map<string, Vote>,\n weights: Map<string, number>\n ): WeightedVoteCounts {\n let approve = 0;\n let reject = 0;\n let abstain = 0;\n let totalWeight = 0;\n\n for (const [agentId, vote] of votes.entries()) {\n const weight = weights.get(agentId) ?? 1.0;\n totalWeight += weight;\n\n switch (vote.decision) {\n case 'approve':\n approve += weight;\n break;\n case 'reject':\n reject += weight;\n break;\n case 'abstain':\n abstain += weight;\n break;\n }\n }\n\n return { approve, reject, abstain, totalWeight };\n }\n}\n\n/**\n * Simple majority voting strategy (>50% approval).\n */\nexport class SimpleMajorityStrategy extends BaseVotingStrategy {\n readonly algorithm: ConsensusAlgorithm = 'simple_majority';\n\n calculateOutcome(votes: Map<string, Vote>): VotingOutcome {\n const counts = this.countVotes(votes);\n const votingVotes = counts.approve + counts.reject; // Abstains don't count\n const threshold = VOTING_THRESHOLDS.simple_majority;\n\n if (votingVotes === 0) {\n return {\n approved: false,\n approvalPercentage: 0,\n voteCounts: counts,\n reason: 'No votes cast (excluding abstentions)',\n };\n }\n\n const { approved, approvalPercentage } = evaluateThreshold(\n counts.approve,\n votingVotes,\n threshold,\n false\n );\n\n return {\n approved,\n approvalPercentage,\n voteCounts: counts,\n reason: approved\n ? `Approved with ${approvalPercentage.toFixed(1)}% (>${String(threshold * 100)}% required)`\n : `Rejected with ${approvalPercentage.toFixed(1)}% (<=${String(threshold * 100)}% threshold)`,\n };\n }\n}\n\n/**\n * Supermajority voting strategy (at least 2/3 approval).\n */\nexport class SupermajorityStrategy extends BaseVotingStrategy {\n readonly algorithm: ConsensusAlgorithm = 'supermajority';\n\n calculateOutcome(votes: Map<string, Vote>): VotingOutcome {\n const counts = this.countVotes(votes);\n const votingVotes = counts.approve + counts.reject;\n const threshold = VOTING_THRESHOLDS.supermajority;\n\n if (votingVotes === 0) {\n return {\n approved: false,\n approvalPercentage: 0,\n voteCounts: counts,\n reason: 'No votes cast (excluding abstentions)',\n };\n }\n\n const { approved, approvalPercentage } = evaluateThreshold(\n counts.approve,\n votingVotes,\n threshold,\n true\n );\n const thresholdPercentage = (threshold * 100).toFixed(1);\n\n return {\n approved,\n approvalPercentage,\n voteCounts: counts,\n reason: approved\n ? `Approved with ${approvalPercentage.toFixed(1)}% (>=${thresholdPercentage}% required)`\n : `Rejected with ${approvalPercentage.toFixed(1)}% (<${thresholdPercentage}% threshold)`,\n };\n }\n}\n\n/**\n * Unanimous voting strategy (100% approval required).\n */\nexport class UnanimousStrategy extends BaseVotingStrategy {\n readonly algorithm: ConsensusAlgorithm = 'unanimous';\n\n calculateOutcome(votes: Map<string, Vote>): VotingOutcome {\n const counts = this.countVotes(votes);\n\n if (counts.total === 0) {\n return {\n approved: false,\n approvalPercentage: 0,\n voteCounts: counts,\n reason: 'No votes cast',\n };\n }\n\n // For unanimous, any rejection fails the proposal\n // Abstentions are allowed but don't count toward approval\n const approvalPercentage = counts.total > 0 ? (counts.approve / counts.total) * 100 : 0;\n\n if (counts.reject > 0) {\n return {\n approved: false,\n approvalPercentage,\n voteCounts: counts,\n reason: `Rejected: ${String(counts.reject)} rejection(s) cast (unanimous approval required)`,\n };\n }\n\n if (counts.approve === 0) {\n return {\n approved: false,\n approvalPercentage: 0,\n voteCounts: counts,\n reason: 'No approvals cast (at least one approval required)',\n };\n }\n\n return {\n approved: true,\n approvalPercentage,\n voteCounts: counts,\n reason: `Unanimously approved with ${String(counts.approve)} vote(s)`,\n };\n }\n}\n\n/**\n * Proof-of-learning weighted voting strategy.\n * Agents with better track records have more voting power.\n */\nexport class ProofOfLearningStrategy extends BaseVotingStrategy {\n readonly algorithm: ConsensusAlgorithm = 'proof_of_learning';\n\n calculateOutcome(votes: Map<string, Vote>, weights?: Map<string, number>): VotingOutcome {\n const counts = this.countVotes(votes);\n const effectiveWeights = weights ?? new Map<string, number>();\n const weightedCounts = this.countWeightedVotes(votes, effectiveWeights);\n const threshold = VOTING_THRESHOLDS.proof_of_learning;\n\n const votingWeight = weightedCounts.approve + weightedCounts.reject;\n\n if (votingWeight === 0) {\n return {\n approved: false,\n approvalPercentage: 0,\n voteCounts: counts,\n weightedCounts,\n reason: 'No weighted votes cast (excluding abstentions)',\n };\n }\n\n const { approved, approvalPercentage } = evaluateThreshold(\n weightedCounts.approve,\n votingWeight,\n threshold,\n false\n );\n\n const weightBasis = deriveWeightBasis(votes, effectiveWeights);\n const verdict = approved ? 'Approved' : 'Rejected';\n\n return {\n approved,\n approvalPercentage,\n voteCounts: counts,\n weightedCounts,\n weightBasis,\n reason: `${verdict} with ${approvalPercentage.toFixed(1)}% ${describeBasis(weightBasis)}`,\n };\n }\n}\n\n/**\n * The tail of the reason string, naming what the percentage was computed over.\n *\n * Calling an unweighted tally \"weighted approval\" is the misreport #5117 fixes:\n * the phrase invites a reader to believe voter track record moved the number\n * when nothing had ever recorded one.\n */\nfunction describeBasis(basis: WeightBasis): string {\n switch (basis) {\n case 'performance':\n return 'weighted approval (weights from voter performance history)';\n case 'partial':\n return 'partly weighted approval (some voters have no performance history; those count as 1.0)';\n case 'unweighted':\n return 'approval (UNWEIGHTED — no voter performance history recorded)';\n default: {\n const unreachable: never = basis;\n throw new Error(`Unhandled weight basis: ${String(unreachable)}`);\n }\n }\n}\n\n/**\n * Calculate vote weight for an agent based on their performance history.\n *\n * Weight ranges from 0.5 (never correct) to 1.0 (perfect track record). An\n * agent with NO history returns 1.0, not 0.5 — the doc used to say \"0.5 (no\n * history)\", which the code has never done (#5117). The distinction matters:\n * a 1.0 default is indistinguishable from a perfect record by value alone,\n * which is why callers must not infer \"was this measured?\" from the number.\n * `deriveWeightBasis` answers that from provenance instead.\n */\nexport function calculateVoteWeight(performance: AgentPerformance | undefined): number {\n if (performance === undefined || performance.totalVotes === 0) {\n return 1.0; // Default weight for new agents\n }\n\n // Weight = 0.5 + (successRate * 0.5)\n // This gives a range of 0.5 to 1.0 based on historical accuracy\n return 0.5 + performance.successRate * 0.5;\n}\n\n/**\n * Factory for creating voting strategies.\n */\nexport class VotingStrategyFactory {\n private readonly strategies: Map<ConsensusAlgorithm, IVotingStrategy>;\n\n constructor() {\n this.strategies = new Map<ConsensusAlgorithm, IVotingStrategy>([\n ['simple_majority', new SimpleMajorityStrategy()],\n ['supermajority', new SupermajorityStrategy()],\n ['unanimous', new UnanimousStrategy()],\n ['proof_of_learning', new ProofOfLearningStrategy()],\n ['opinion_wise', new HigherOrderVotingStrategy()],\n ['higher_order', new HigherOrderVotingStrategy()],\n ]);\n }\n\n /**\n * Get a voting strategy by algorithm type.\n */\n getStrategy(algorithm: ConsensusAlgorithm): IVotingStrategy {\n const strategy = this.strategies.get(algorithm);\n if (strategy === undefined) {\n throw new Error(`Unknown voting algorithm: ${algorithm}`);\n }\n return strategy;\n }\n\n /**\n * Register a custom voting strategy.\n */\n registerStrategy(strategy: IVotingStrategy): void {\n this.strategies.set(strategy.algorithm, strategy);\n }\n\n /**\n * Get all available algorithm types.\n */\n getAvailableAlgorithms(): ConsensusAlgorithm[] {\n return Array.from(this.strategies.keys());\n }\n}\n\n/**\n * Creates a voting strategy factory with default strategies.\n */\nexport function createStrategyFactory(): VotingStrategyFactory {\n return new VotingStrategyFactory();\n}\n","/**\n * nexus-agents/consensus - Result Builder\n *\n * Helper functions for building consensus results.\n */\n\nimport { getTimeProvider } from '../core/index.js';\nimport type { ProposalId, ProposalState, ConsensusResult, ConsensusEngineConfig } from './types.js';\nimport type { VotingOutcome } from './strategies.js';\nimport { determineFinalStatus } from './decision/verdict.js';\nimport { isQuorumReached } from './decision/quorum.js';\n\n/**\n * `determineFinalStatus` moved to `decision/verdict.ts` (#6000 step 1) so the\n * quorum + approval → outcome step can be governed on its own path.\n * Re-exported here so every existing import keeps resolving.\n *\n * The quorum comparison the three builders inlined moved to\n * `decision/quorum.ts` as `isQuorumReached` (#6180). It was never exported\n * from here, so nothing is re-exported: a verdict site reaches it only\n * through the governed module.\n */\nexport { determineFinalStatus } from './decision/verdict.js';\n\n/**\n * Build a pending result for an active proposal.\n */\nexport function buildPendingResult(\n state: ProposalState,\n proposalId: ProposalId,\n outcome: VotingOutcome,\n config: ConsensusEngineConfig\n): ConsensusResult {\n const now = new Date(getTimeProvider().now());\n return {\n proposalId,\n proposal: state.proposal,\n outcome: state.status === 'voting' ? 'pending' : state.status,\n votes: new Map(state.votes),\n voteCounts: outcome.voteCounts,\n weightedCounts: outcome.weightedCounts,\n weightBasis: outcome.weightBasis,\n approvalPercentage: outcome.approvalPercentage,\n quorumReached: isQuorumReached(state.votes.size, config.minVotersForQuorum),\n startedAt: state.startedAt.toISOString(),\n closedAt: now.toISOString(),\n durationMs: now.getTime() - state.startedAt.getTime(),\n };\n}\n\n/**\n * Build a final result for a closed proposal.\n */\nexport function buildFinalResult(\n state: ProposalState,\n proposalId: ProposalId,\n outcome: VotingOutcome,\n config: ConsensusEngineConfig\n): ConsensusResult {\n const now = new Date(getTimeProvider().now());\n const quorumReached = isQuorumReached(state.votes.size, config.minVotersForQuorum);\n const finalStatus = determineFinalStatus(quorumReached, outcome.approved);\n\n return {\n proposalId,\n proposal: state.proposal,\n outcome: finalStatus,\n votes: new Map(state.votes),\n voteCounts: outcome.voteCounts,\n weightedCounts: outcome.weightedCounts,\n weightBasis: outcome.weightBasis,\n approvalPercentage: outcome.approvalPercentage,\n quorumReached,\n startedAt: state.startedAt.toISOString(),\n closedAt: now.toISOString(),\n durationMs: now.getTime() - state.startedAt.getTime(),\n };\n}\n\n/**\n * Build a timeout result for an expired proposal.\n */\nexport function buildTimeoutResult(\n state: ProposalState,\n proposalId: ProposalId,\n outcome: VotingOutcome,\n config: ConsensusEngineConfig\n): ConsensusResult {\n const now = new Date(getTimeProvider().now());\n return {\n proposalId,\n proposal: state.proposal,\n outcome: 'timeout',\n votes: new Map(state.votes),\n voteCounts: outcome.voteCounts,\n weightedCounts: outcome.weightedCounts,\n weightBasis: outcome.weightBasis,\n approvalPercentage: outcome.approvalPercentage,\n quorumReached: isQuorumReached(state.votes.size, config.minVotersForQuorum),\n startedAt: state.startedAt.toISOString(),\n closedAt: now.toISOString(),\n durationMs: now.getTime() - state.startedAt.getTime(),\n };\n}\n","/**\n * nexus-agents/consensus - Helper Functions\n *\n * Utility functions for the consensus engine.\n */\n\nimport type { ProposalId } from './types.js';\nimport { getTimeProvider, getRandomProvider } from '../core/index.js';\n\n/**\n * Generate a unique proposal ID.\n */\nexport function generateProposalId(): ProposalId {\n const timestamp = getTimeProvider().now().toString(36);\n const random = getRandomProvider().random().toString(36).substring(2, 8);\n return `prop_${timestamp}_${random}`;\n}\n","/**\n * nexus-agents/consensus - Incremental Quorum\n *\n * Detects ambiguous voting scenarios and triggers voter pool expansion.\n * Complements agreement-based cascading (early termination when certain)\n * with expansion when uncertain.\n *\n * (Source: Issue #1408 — Incremental Quorum for Consensus Robustness)\n *\n * @module consensus/incremental-quorum\n */\n\nimport type { Vote } from './types.js';\n\n/**\n * Parameters for ambiguity detection.\n */\nexport interface AmbiguityParams {\n /** Minimum average confidence to avoid expansion. */\n readonly confidenceThreshold: number;\n /** If approval rate is within this band of the threshold, consider ambiguous. */\n readonly ambiguityBand: number;\n}\n\n/**\n * Determines if the current voting state is ambiguous.\n *\n * Ambiguity is detected when:\n * 1. Approval rate is within the ambiguity band of the threshold, OR\n * 2. Average voter confidence is below the confidence threshold\n *\n * @param votes - Current vote map\n * @param totalExpected - Total expected voters\n * @param threshold - Algorithm-specific approval threshold (0-1)\n * @param params - Ambiguity detection parameters\n * @returns true if the voting state is ambiguous\n */\nexport function isVotingAmbiguous(\n votes: ReadonlyMap<string, Vote>,\n totalExpected: number,\n threshold: number,\n params: AmbiguityParams\n): boolean {\n if (votes.size === 0) return false;\n\n let approvals = 0;\n let totalConfidence = 0;\n for (const vote of votes.values()) {\n if (vote.decision === 'approve') approvals++;\n totalConfidence += vote.confidence;\n }\n\n const approvalRate = approvals / totalExpected;\n const avgConfidence = totalConfidence / votes.size;\n\n // Check if approval rate is within the ambiguity band of threshold\n const lowerBand = threshold - params.ambiguityBand;\n const upperBand = threshold + params.ambiguityBand;\n const rateAmbiguous = approvalRate >= lowerBand && approvalRate <= upperBand;\n\n // Check if confidence is too low\n const confidenceAmbiguous = avgConfidence < params.confidenceThreshold;\n\n return rateAmbiguous || confidenceAmbiguous;\n}\n","/* eslint max-lines: [\"error\", { \"max\": 600, \"skipBlankLines\": true, \"skipComments\": true }] */\n// A BOUNDED ceiling, not `eslint-disable max-lines` (#5766).\n//\n// The file is 499 lines by the measure the rule uses (blanks and comments\n// skipped) and 715 by `wc -l`. Those are different units, and comparing them is\n// what went wrong here: the previous comment read the raw 715 against the\n// \"400-600 lines if cohesive\" band in .rules/governance.md:67 and concluded the\n// file \"sits well past the band it invoked\". By the rule's own counting it sits\n// INSIDE that band, so the original justification never stopped holding — only\n// the number quoted against it was measured differently.\n//\n// A blanket disable is why that could go unnoticed for so long: it silenced the\n// one check that knows the real count, leaving a hand-maintained number in a\n// comment as the only record, and hand-maintained numbers rot (this one drifted\n// from 426 to 711 to 715). The ceiling is set at 600 — the TOP of the governance\n// band — so the file is checked against the same band its justification cites,\n// and growing out of it fails the build instead of a comment quietly aging.\n\n/**\n * nexus-agents/consensus - Consensus Engine\n *\n * Core consensus engine implementation supporting multiple voting strategies.\n * Manages proposal lifecycle, vote collection, and outcome determination.\n */\n\nimport type { Result, ILogger } from '../core/index.js';\nimport { ok, err, AgentError, createLogger, getTimeProvider } from '../core/index.js';\nimport type {\n Proposal,\n ProposalId,\n Vote,\n ConsensusResult,\n ConsensusAlgorithm,\n AgentPerformance,\n ConsensusEngineConfig,\n ProposalState,\n ConsensusMetrics,\n ProposalCacheConfig,\n IncrementalQuorumConfig,\n VoterExpansionCallback,\n} from './types.js';\nimport {\n ProposalSchema,\n VoteSchema,\n DEFAULT_CONSENSUS_CONFIG,\n DEFAULT_INCREMENTAL_QUORUM_CONFIG,\n} from './types.js';\nimport { VOTING_THRESHOLDS } from './decision/thresholds.js';\nimport { VotingStrategyFactory, calculateVoteWeight, type VotingOutcome } from './strategies.js';\nimport { buildFinalResult, buildTimeoutResult, buildPendingResult } from './result-builder.js';\nimport { generateProposalId } from './helpers.js';\nimport { isVotingAmbiguous } from './incremental-quorum.js';\n\n/**\n * Error class for consensus-related failures.\n */\nexport class ConsensusError extends AgentError {\n constructor(message: string, context?: Record<string, unknown>) {\n super(message, context !== undefined ? { context } : {});\n this.name = 'ConsensusError';\n }\n}\n\n/**\n * Interface for the consensus engine.\n */\nexport interface IConsensusEngine {\n propose(proposal: Proposal): Promise<Result<ProposalId, ConsensusError>>;\n vote(proposalId: ProposalId, agentId: string, vote: Vote): Promise<Result<void, ConsensusError>>;\n getResult(proposalId: ProposalId): Promise<Result<ConsensusResult, ConsensusError>>;\n close(proposalId: ProposalId): Promise<Result<ConsensusResult, ConsensusError>>;\n getMetrics(): ConsensusMetrics;\n}\n\ninterface InternalMetrics {\n totalProposals: number;\n approvedProposals: number;\n rejectedProposals: number;\n timedOutProposals: number;\n totalDurationMs: number;\n totalVotes: number;\n algorithmUsage: Record<ConsensusAlgorithm, number>;\n}\n\n/**\n * Cache entry for proposal content-based caching (Issue #589).\n */\ninterface ProposalCacheEntry {\n readonly proposalId: ProposalId;\n readonly result: ConsensusResult;\n readonly cachedAt: number;\n}\n\n/**\n * Default proposal cache configuration.\n * Enabled by default to improve determinism (fitness audit recommendation).\n */\n/**\n * Hypothetical-vote stand-ins used by {@link ConsensusEngine.canCascadeEarly}\n * to probe the strategy's outcome under best/worst-case pending votes.\n * The actual `confidence` and `reasoning` fields are never inspected by\n * `IVotingStrategy.calculateOutcome` (all strategies count by `decision`),\n * but must satisfy `VoteSchema` (confidence in [0,1], reasoning non-empty).\n */\nconst HYPOTHETICAL_APPROVE: Vote = {\n decision: 'approve',\n confidence: 0.5,\n reasoning: 'hypothetical-cascade-probe',\n};\nconst HYPOTHETICAL_REJECT: Vote = {\n decision: 'reject',\n confidence: 0.5,\n reasoning: 'hypothetical-cascade-probe',\n};\n\nconst DEFAULT_PROPOSAL_CACHE_CONFIG: ProposalCacheConfig = {\n enabled: true,\n ttlMs: 3600000, // 1 hour\n maxEntries: 500,\n};\n\n/**\n * Consensus engine for multi-agent decision making.\n *\n * @example\n * ```typescript\n * const engine = new ConsensusEngine({ defaultTimeout: 30000 });\n * const proposalResult = await engine.propose({\n * title: 'Use microservices architecture',\n * description: 'Proposal to adopt microservices',\n * algorithm: 'supermajority',\n * });\n * if (proposalResult.ok) {\n * await engine.vote(proposalResult.value, 'agent-1', {\n * decision: 'approve',\n * confidence: 0.9,\n * reasoning: 'Good for scalability',\n * });\n * }\n * ```\n */\nexport class ConsensusEngine implements IConsensusEngine {\n private readonly proposals: Map<ProposalId, ProposalState> = new Map();\n private readonly closedProposals: Map<ProposalId, ConsensusResult> = new Map();\n private readonly agentPerformance: Map<string, AgentPerformance> = new Map();\n private readonly proposalContentCache: Map<string, ProposalCacheEntry> = new Map();\n private readonly strategyFactory: VotingStrategyFactory;\n private readonly config: ConsensusEngineConfig;\n private readonly cacheConfig: ProposalCacheConfig;\n private readonly quorumConfig: IncrementalQuorumConfig;\n private readonly logger: ILogger;\n private readonly metrics: InternalMetrics;\n private voterExpansionCallback?: VoterExpansionCallback;\n\n constructor(config?: Partial<ConsensusEngineConfig>, logger?: ILogger) {\n this.config = { ...DEFAULT_CONSENSUS_CONFIG, ...config };\n this.cacheConfig = { ...DEFAULT_PROPOSAL_CACHE_CONFIG, ...config?.proposalCache };\n this.quorumConfig = { ...DEFAULT_INCREMENTAL_QUORUM_CONFIG, ...config?.incrementalQuorum };\n this.logger = logger ?? createLogger({ component: 'ConsensusEngine' });\n this.strategyFactory = new VotingStrategyFactory();\n this.metrics = this.createInitialMetrics();\n }\n\n /**\n * Sets the callback for incremental quorum voter expansion (Issue #1408).\n * When ambiguous votes are detected, this callback requests additional voters.\n */\n setVoterExpansionCallback(callback: VoterExpansionCallback): void {\n this.voterExpansionCallback = callback;\n }\n\n propose(proposal: Proposal): Promise<Result<ProposalId, ConsensusError>> {\n const validation = ProposalSchema.safeParse(proposal);\n if (!validation.success) {\n return Promise.resolve(\n err(\n new ConsensusError(`Invalid proposal: ${validation.error.message}`, {\n errors: validation.error.issues,\n })\n )\n );\n }\n\n // Check cache for identical proposal content (Issue #589)\n if (this.cacheConfig.enabled) {\n const cachedEntry = this.getCachedResult(validation.data);\n if (cachedEntry !== undefined) {\n this.logger.debug('Returning cached proposal result', {\n cachedProposalId: cachedEntry.proposalId,\n cachedOutcome: cachedEntry.result.outcome,\n });\n return Promise.resolve(ok(cachedEntry.proposalId));\n }\n }\n\n if (this.proposals.size >= this.config.maxActiveProposals) {\n return Promise.resolve(\n err(\n new ConsensusError(\n `Maximum active proposals (${String(this.config.maxActiveProposals)}) reached`\n )\n )\n );\n }\n\n const proposalId = proposal.id ?? generateProposalId();\n const state = this.createProposalState(validation.data, proposalId);\n this.setupTimeout(state, proposalId, proposal.timeout);\n this.registerProposal(proposalId, state, proposal.algorithm);\n return Promise.resolve(ok(proposalId));\n }\n\n async vote(\n proposalId: ProposalId,\n agentId: string,\n vote: Vote\n ): Promise<Result<void, ConsensusError>> {\n const validationErr = this.validateVote(vote);\n if (validationErr !== undefined) return err(validationErr);\n\n const stateErr = this.validateProposalState(proposalId);\n if (stateErr !== undefined) return err(stateErr);\n\n const state = this.proposals.get(proposalId);\n if (state === undefined) {\n return err(new ConsensusError(`Proposal ${proposalId} not found`));\n }\n\n this.recordVote(state, agentId, vote);\n\n // Agreement-based cascade always takes priority\n if (this.canCascadeEarly(state)) {\n return this.closeInternal(proposalId).then((r) => (r.ok ? ok(undefined) : err(r.error)));\n }\n\n // All required voters voted — check for incremental quorum expansion\n if (this.allRequiredVotersVoted(state)) {\n // Re-entry guard (#2861): `tryExpandQuorum` awaits its callback and\n // then mutates `state.proposal.requiredVoters` / `expansionRounds`.\n // A concurrent `vote()` that also sees `allRequiredVotersVoted`\n // must NOT start a second expansion — that would invoke the\n // expansion callback twice and clobber the first expansion's\n // voter list. This vote is already recorded; return ok and let\n // the in-flight expansion settle.\n if (state.expansionInFlight === true) {\n return Promise.resolve(ok(undefined));\n }\n state.expansionInFlight = true;\n let expanded: boolean;\n try {\n expanded = await this.tryExpandQuorum(proposalId, state);\n } finally {\n state.expansionInFlight = false;\n }\n if (!expanded) {\n return this.closeInternal(proposalId).then((r) => (r.ok ? ok(undefined) : err(r.error)));\n }\n // Expansion succeeded — wait for new voters\n }\n\n return Promise.resolve(ok(undefined));\n }\n\n getResult(proposalId: ProposalId): Promise<Result<ConsensusResult, ConsensusError>> {\n const closedResult = this.closedProposals.get(proposalId);\n if (closedResult !== undefined) return Promise.resolve(ok(closedResult));\n\n const state = this.proposals.get(proposalId);\n if (state === undefined) {\n return Promise.resolve(err(new ConsensusError(`Proposal ${proposalId} not found`)));\n }\n\n const outcome = this.calculateOutcome(state);\n return Promise.resolve(ok(buildPendingResult(state, proposalId, outcome, this.config)));\n }\n\n close(proposalId: ProposalId): Promise<Result<ConsensusResult, ConsensusError>> {\n return this.closeInternal(proposalId);\n }\n\n getMetrics(): ConsensusMetrics {\n const completed =\n this.metrics.approvedProposals +\n this.metrics.rejectedProposals +\n this.metrics.timedOutProposals;\n return {\n totalProposals: this.metrics.totalProposals,\n approvedProposals: this.metrics.approvedProposals,\n rejectedProposals: this.metrics.rejectedProposals,\n timedOutProposals: this.metrics.timedOutProposals,\n averageDurationMs: completed > 0 ? this.metrics.totalDurationMs / completed : 0,\n averageVotesPerProposal: completed > 0 ? this.metrics.totalVotes / completed : 0,\n algorithmUsage: { ...this.metrics.algorithmUsage },\n };\n }\n\n updateAgentPerformance(agentId: string, wasCorrect: boolean): void {\n const existing = this.agentPerformance.get(agentId);\n const now = getTimeProvider().nowIso();\n\n if (existing === undefined) {\n this.agentPerformance.set(agentId, {\n agentId,\n totalVotes: 1,\n correctVotes: wasCorrect ? 1 : 0,\n successRate: wasCorrect ? 1.0 : 0.0,\n lastUpdated: now,\n });\n } else {\n const totalVotes = existing.totalVotes + 1;\n const correctVotes = existing.correctVotes + (wasCorrect ? 1 : 0);\n this.agentPerformance.set(agentId, {\n agentId,\n totalVotes,\n correctVotes,\n successRate: correctVotes / totalVotes,\n lastUpdated: now,\n });\n }\n }\n\n getAgentPerformance(agentId: string): AgentPerformance | undefined {\n return this.agentPerformance.get(agentId);\n }\n\n getActiveProposalCount(): number {\n return this.proposals.size;\n }\n\n private createProposalState(data: Proposal, proposalId: ProposalId): ProposalState {\n const now = new Date(getTimeProvider().now());\n return {\n proposal: { ...data, id: proposalId, createdAt: now.toISOString() },\n status: 'voting',\n votes: new Map(),\n voteWeights: new Map(),\n startedAt: now,\n };\n }\n\n private setupTimeout(state: ProposalState, proposalId: ProposalId, timeout?: number): void {\n const timeoutMs = timeout ?? this.config.defaultTimeout;\n state.timeoutId = setTimeout(() => {\n this.handleTimeout(proposalId);\n }, timeoutMs);\n }\n\n private registerProposal(\n proposalId: ProposalId,\n state: ProposalState,\n algorithm: ConsensusAlgorithm\n ): void {\n this.proposals.set(proposalId, state);\n this.metrics.totalProposals++;\n this.metrics.algorithmUsage[algorithm]++;\n this.logger.info('Proposal created', {\n proposalId,\n title: state.proposal.title,\n algorithm,\n timeout: this.config.defaultTimeout,\n });\n }\n\n private validateVote(vote: Vote): ConsensusError | undefined {\n const validation = VoteSchema.safeParse(vote);\n if (!validation.success) {\n return new ConsensusError(`Invalid vote: ${validation.error.message}`, {\n errors: validation.error.issues,\n });\n }\n return undefined;\n }\n\n private validateProposalState(proposalId: ProposalId): ConsensusError | undefined {\n const state = this.proposals.get(proposalId);\n if (state === undefined) {\n if (this.closedProposals.has(proposalId)) {\n return new ConsensusError(`Proposal ${proposalId} is already closed`);\n }\n return new ConsensusError(`Proposal ${proposalId} not found`);\n }\n if (state.status !== 'voting') {\n return new ConsensusError(`Proposal ${proposalId} is not accepting votes`, {\n status: state.status,\n });\n }\n return undefined;\n }\n\n private recordVote(state: ProposalState, agentId: string, vote: Vote): void {\n state.votes.set(agentId, {\n ...vote,\n timestamp: getTimeProvider().nowIso(),\n });\n if (state.proposal.algorithm === 'proof_of_learning') {\n // Only record a weight when a performance record actually EXISTS (#5117).\n // This used to call `calculateVoteWeight(undefined)`, which returns the\n // 1.0 new-agent default, so the map was fully populated whether or not\n // anything had ever been measured — and by the time the strategy saw it,\n // \"weighted at 1.0 because they are reliable\" and \"weighted at 1.0\n // because we know nothing\" were indistinguishable.\n //\n // Absence now carries that provenance. The arithmetic is unchanged:\n // `countWeightedVotes` already defaults a missing entry to 1.0.\n const performance = this.agentPerformance.get(agentId);\n if (performance !== undefined) {\n state.voteWeights.set(agentId, calculateVoteWeight(performance));\n }\n }\n this.logger.debug('Vote recorded', {\n proposalId: state.proposal.id,\n agentId,\n decision: vote.decision,\n confidence: vote.confidence,\n });\n }\n\n private closeInternal(proposalId: ProposalId): Promise<Result<ConsensusResult, ConsensusError>> {\n const state = this.proposals.get(proposalId);\n if (state === undefined) {\n const closed = this.closedProposals.get(proposalId);\n if (closed !== undefined) return Promise.resolve(ok(closed));\n return Promise.resolve(err(new ConsensusError(`Proposal ${proposalId} not found`)));\n }\n\n if (state.timeoutId !== undefined) clearTimeout(state.timeoutId);\n\n const outcome = this.calculateOutcome(state);\n const result = buildFinalResult(state, proposalId, outcome, this.config);\n this.finalize(proposalId, result, state.votes.size);\n return Promise.resolve(ok(result));\n }\n\n private handleTimeout(proposalId: ProposalId): void {\n const state = this.proposals.get(proposalId);\n if (state?.status !== 'voting') return;\n\n this.logger.warn('Proposal timed out', { proposalId, voteCount: state.votes.size });\n const outcome = this.calculateOutcome(state);\n const result = buildTimeoutResult(state, proposalId, outcome, this.config);\n this.proposals.delete(proposalId);\n this.addClosedProposal(proposalId, result);\n this.metrics.timedOutProposals++;\n this.metrics.totalDurationMs += result.durationMs;\n this.metrics.totalVotes += state.votes.size;\n }\n\n private finalize(proposalId: ProposalId, result: ConsensusResult, voteCount: number): void {\n this.proposals.delete(proposalId);\n this.addClosedProposal(proposalId, result);\n this.updateMetrics(result);\n\n // Cache successful results for determinism (Issue #589)\n if (\n this.cacheConfig.enabled &&\n (result.outcome === 'approved' || result.outcome === 'rejected')\n ) {\n this.addToCache(result.proposal, proposalId, result);\n }\n\n this.logger.info('Proposal closed', {\n proposalId,\n outcome: result.outcome,\n approvalPercentage: result.approvalPercentage.toFixed(1),\n voteCount,\n quorumReached: result.quorumReached,\n durationMs: result.durationMs,\n });\n }\n\n /**\n * Adds a closed proposal and evicts oldest entries if over limit.\n * Issue #549: Prevent unbounded memory growth in closedProposals Map.\n */\n private addClosedProposal(proposalId: ProposalId, result: ConsensusResult): void {\n // Evict oldest entries if at capacity (Map maintains insertion order)\n while (this.closedProposals.size >= this.config.maxClosedProposals) {\n const firstKey = this.closedProposals.keys().next();\n if (firstKey.done === true) break;\n const oldestKey = firstKey.value;\n this.closedProposals.delete(oldestKey);\n this.logger.debug('Evicted oldest closed proposal', { evictedId: oldestKey });\n }\n this.closedProposals.set(proposalId, result);\n }\n\n private calculateOutcome(state: ProposalState): VotingOutcome {\n const strategy = this.strategyFactory.getStrategy(state.proposal.algorithm);\n const outcome: VotingOutcome = strategy.calculateOutcome(state.votes, state.voteWeights);\n return outcome;\n }\n\n /**\n * Agreement-based cascading: close early when outcome is mathematically determined.\n *\n * #2822: the prior implementation computed approval rates against\n * `totalExpected = requiredVoters.length` and compared against\n * `VOTING_THRESHOLDS[algorithm]` directly. Every voting strategy\n * (`SimpleMajorityStrategy`, `SupermajorityStrategy`, `UnanimousStrategy`,\n * `ProofOfLearningStrategy`) uses `approve + reject` as its denominator —\n * abstains are explicitly excluded. The two diverged whenever abstains\n * were present, producing wrong-winner cascades (e.g. 5-voter supermajority\n * with [approve, abstain, abstain, abstain, pending] cascade-rejected even\n * though the strategy would approve at close).\n *\n * The fix delegates to the strategy itself: build a best-case (all pending\n * voters approve) and worst-case (all pending voters reject) hypothetical\n * vote map, call `strategy.calculateOutcome` on each, and cascade only\n * when both extremes yield the same outcome. This guarantees parity with\n * the strategy's denominator semantics by construction.\n */\n private canCascadeEarly(state: ProposalState): boolean {\n const required = state.proposal.requiredVoters;\n if (required === undefined || required.length === 0) return false;\n if (state.votes.size === 0) return false;\n\n const pending = required.filter((voter) => !state.votes.has(voter));\n if (pending.length === 0) return false; // All voted — handled by allRequiredVotersVoted\n\n const strategy = this.strategyFactory.getStrategy(state.proposal.algorithm);\n\n const bestCase = new Map<string, Vote>(state.votes);\n const worstCase = new Map<string, Vote>(state.votes);\n for (const voter of pending) {\n bestCase.set(voter, HYPOTHETICAL_APPROVE);\n worstCase.set(voter, HYPOTHETICAL_REJECT);\n }\n\n const bestOutcome = strategy.calculateOutcome(bestCase, state.voteWeights);\n const worstOutcome = strategy.calculateOutcome(worstCase, state.voteWeights);\n\n if (bestOutcome.approved !== worstOutcome.approved) return false;\n\n this.logger.info('Agreement cascade: outcome determined', {\n proposalId: state.proposal.id,\n outcome: bestOutcome.approved ? 'approve' : 'reject',\n votesCast: state.votes.size,\n pending: pending.length,\n algorithm: state.proposal.algorithm,\n });\n return true;\n }\n\n private allRequiredVotersVoted(state: ProposalState): boolean {\n const required = state.proposal.requiredVoters;\n if (required === undefined || required.length === 0) return false;\n return required.every((voterId) => state.votes.has(voterId));\n }\n\n /**\n * Attempts incremental quorum expansion when voting is ambiguous (Issue #1408).\n * Returns true if expansion occurred (wait for new voters), false to close immediately.\n */\n private async tryExpandQuorum(proposalId: ProposalId, state: ProposalState): Promise<boolean> {\n if (!this.quorumConfig.enabled) return false;\n if (this.voterExpansionCallback === undefined) return false;\n\n const rounds = state.expansionRounds ?? 0;\n if (rounds >= this.quorumConfig.maxExpansionRounds) return false;\n\n const required = state.proposal.requiredVoters;\n if (required === undefined) return false;\n\n const threshold = VOTING_THRESHOLDS[state.proposal.algorithm];\n const ambiguous = isVotingAmbiguous(state.votes, required.length, threshold, {\n confidenceThreshold: this.quorumConfig.confidenceThreshold,\n ambiguityBand: this.quorumConfig.ambiguityBand,\n });\n\n if (!ambiguous) return false;\n\n let newVoters: readonly string[];\n try {\n newVoters = await this.voterExpansionCallback(\n proposalId,\n required.length,\n this.quorumConfig.votersPerExpansion\n );\n } catch (err: unknown) {\n const error = err instanceof Error ? err : new Error(String(err));\n this.logger.warn('Incremental quorum: expansion callback threw; closing as-is', {\n proposalId,\n errorMessage: error.message,\n });\n return false;\n }\n\n if (newVoters.length === 0) {\n this.logger.info('Incremental quorum: no additional voters available', { proposalId });\n return false;\n }\n\n // Expand the required voters list\n state.proposal.requiredVoters = [...required, ...newVoters];\n state.expansionRounds = rounds + 1;\n\n this.logger.info('Incremental quorum: expanded voter pool', {\n proposalId,\n round: rounds + 1,\n newVoters: newVoters.length,\n totalVoters: state.proposal.requiredVoters.length,\n });\n\n return true;\n }\n\n private updateMetrics(result: ConsensusResult): void {\n this.metrics.totalDurationMs += result.durationMs;\n this.metrics.totalVotes += result.voteCounts.total;\n if (result.outcome === 'approved') this.metrics.approvedProposals++;\n else if (result.outcome === 'rejected') this.metrics.rejectedProposals++;\n else if (result.outcome === 'timeout') this.metrics.timedOutProposals++;\n }\n\n private createInitialMetrics(): InternalMetrics {\n return {\n totalProposals: 0,\n approvedProposals: 0,\n rejectedProposals: 0,\n timedOutProposals: 0,\n totalDurationMs: 0,\n totalVotes: 0,\n algorithmUsage: {\n simple_majority: 0,\n supermajority: 0,\n unanimous: 0,\n proof_of_learning: 0,\n opinion_wise: 0,\n higher_order: 0,\n },\n };\n }\n\n // ============================================================================\n // Proposal Content Caching (Issue #589)\n // ============================================================================\n\n /**\n * Creates a content hash for a proposal to enable cache lookups.\n * Hash is based on title, description, and algorithm (deterministic content).\n */\n private hashProposalContent(proposal: Proposal): string {\n const content = [proposal.title, proposal.description, proposal.algorithm].join('|');\n // Simple FNV-1a hash for fast deterministic hashing\n let hash = 2166136261;\n for (let i = 0; i < content.length; i++) {\n hash ^= content.charCodeAt(i);\n hash = Math.imul(hash, 16777619);\n }\n return (hash >>> 0).toString(16);\n }\n\n /**\n * Gets cached result for a proposal if it exists and hasn't expired.\n */\n private getCachedResult(proposal: Proposal): ProposalCacheEntry | undefined {\n const hash = this.hashProposalContent(proposal);\n const cached = this.proposalContentCache.get(hash);\n if (cached === undefined) return undefined;\n\n const now = getTimeProvider().now();\n if (now - cached.cachedAt > this.cacheConfig.ttlMs) {\n this.proposalContentCache.delete(hash);\n this.logger.debug('Cache entry expired', { hash });\n return undefined;\n }\n\n return cached;\n }\n\n /**\n * Adds a proposal result to the cache, evicting oldest entries if needed.\n */\n private addToCache(proposal: Proposal, proposalId: ProposalId, result: ConsensusResult): void {\n const hash = this.hashProposalContent(proposal);\n\n // Evict oldest entries if at capacity (Map maintains insertion order)\n while (this.proposalContentCache.size >= this.cacheConfig.maxEntries) {\n const firstKey = this.proposalContentCache.keys().next();\n if (firstKey.done === true) break;\n const oldestKey = firstKey.value;\n this.proposalContentCache.delete(oldestKey);\n this.logger.debug('Evicted oldest cache entry', { hash: oldestKey });\n }\n\n this.proposalContentCache.set(hash, {\n proposalId,\n result,\n cachedAt: getTimeProvider().now(),\n });\n this.logger.debug('Added proposal to cache', { hash, proposalId });\n }\n\n /**\n * Gets the current cache size (for testing/monitoring).\n */\n getCacheSize(): number {\n return this.proposalContentCache.size;\n }\n\n /**\n * Clears the proposal content cache (for testing/reset).\n */\n clearCache(): void {\n this.proposalContentCache.clear();\n this.logger.debug('Proposal cache cleared');\n }\n}\n\n/**\n * Create a consensus engine with the given configuration.\n *\n * @example\n * ```typescript\n * const engine = createConsensusEngine({\n * defaultTimeout: 60000,\n * maxActiveProposals: 10,\n * });\n * ```\n */\nexport function createConsensusEngine(\n config?: Partial<ConsensusEngineConfig>,\n logger?: ILogger\n): ConsensusEngine {\n return new ConsensusEngine(config, logger);\n}\n","/**\n * Unified Quorum Validator\n *\n * SCOPE, corrected (#4666). This module's docstring claimed it \"abstracts\n * quorum validation across VotingProtocol, WeightedVoting, and ConsensusEngine\"\n * and consolidates three implementations. It has exactly ONE consumer:\n * `voting-protocol-helpers.ts`. `WeightedVoting` and `ConsensusEngine` do not\n * use it. The intent from #576 was real; the consolidation did not happen, and\n * the doc has been describing the plan as though it were the state.\n *\n * A second, sharper caveat for anyone relying on this: `VotingProtocol` — the\n * one path that reaches here — has **no in-tree caller**. `createVotingProtocol`\n * is exported through `exports/consensus.ts` as public API and is constructed\n * only by tests. So this validator runs only for an external embedder.\n *\n * Agent eligibility screening was REMOVED here under #4666 (consensus_vote 7-0).\n * It could never exclude anyone: its sole caller passed no `AgentRecord`, and no\n * producer of trust scores or Byzantine flags exists anywhere in `src/`. The\n * breakdown nonetheless emitted an `eligibleAgents` list containing every voter,\n * which a machine consumer reads as evidence that screening ran — a comment\n * cannot travel with a serialized record. Git history holds the implementation\n * for whenever a real trust-score producer appears.\n *\n * @module consensus/quorum-validator\n * (Source: Issue #576, ADR-0003; scope corrected #4666)\n */\n\nimport { createLogger, formatPercentage, type ILogger } from '../core/index.js';\nimport type { ConsensusAlgorithm, Vote, VoteCounts, WeightedVoteCounts } from './types-core.js';\nimport { SUPERMAJORITY_THRESHOLD } from './decision/thresholds.js';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Quorum validation configuration.\n */\nexport interface QuorumValidationConfig {\n /** Algorithm type */\n readonly algorithm: ConsensusAlgorithm | 'weighted_byzantine';\n /** Numeric threshold (0-1 for percentage, 0-N for weighted sum) */\n readonly threshold: number;\n /** Minimum voters required */\n readonly minVoters: number;\n /** Apply confidence multiplier to weights */\n readonly confidenceMultiplier?: boolean;\n /** Include abstentions in quorum calculation */\n readonly includeAbstentions?: boolean;\n}\n\n/**\n * Input for quorum validation.\n */\nexport interface QuorumValidationInput {\n /** Votes cast by agent ID */\n readonly votes: ReadonlyMap<string, Vote>;\n /** Optional: Pre-calculated agent weights */\n readonly agentWeights?: ReadonlyMap<string, number>;\n /** Configuration */\n readonly config: QuorumValidationConfig;\n /** Optional: Required participant count (for ratio-based quorum) */\n readonly requiredParticipants?: number;\n}\n\n/**\n * Quorum validation result (discriminated union).\n */\nexport type QuorumValidationResult =\n | {\n readonly status: 'reached';\n readonly decision: 'approve' | 'reject';\n readonly confidence: number;\n readonly reasoning: string;\n }\n | {\n readonly status: 'not_reached';\n readonly reason: 'insufficient_votes' | 'insufficient_weight' | 'no_consensus';\n readonly details: string;\n }\n | { readonly status: 'invalid'; readonly error: string }\n | { readonly status: 'timeout'; readonly partial: boolean; readonly details: string };\n\n/**\n * Detailed quorum breakdown for observability.\n */\nexport interface QuorumBreakdown {\n readonly totalVotes: number;\n readonly voteCounts: VoteCounts;\n readonly totalWeight: number | undefined;\n readonly weightedCounts: WeightedVoteCounts | undefined;\n readonly threshold: number;\n readonly actualQuorum: number;\n readonly quorumReached: boolean;\n readonly reasoning: string;\n}\n\n/**\n * Unified quorum validator interface.\n */\nexport interface IQuorumValidator {\n validateQuorum(input: QuorumValidationInput): QuorumValidationResult;\n getQuorumBreakdown(input: QuorumValidationInput): QuorumBreakdown;\n}\n\n// ============================================================================\n// Implementation\n// ============================================================================\n\n/**\n * Default quorum thresholds by algorithm type.\n * Used for reference when config.threshold is not specified.\n */\nexport const DEFAULT_QUORUM_THRESHOLDS: Readonly<\n Record<ConsensusAlgorithm | 'weighted_byzantine', number>\n> = {\n simple_majority: 0.5,\n supermajority: SUPERMAJORITY_THRESHOLD,\n unanimous: 1.0,\n proof_of_learning: 0.5,\n opinion_wise: 0.5,\n higher_order: 0.5,\n // Byzantine fault tolerance also requires 2/3 — the same supermajority.\n weighted_byzantine: SUPERMAJORITY_THRESHOLD,\n};\n\n/**\n * Tolerance under which approve and reject tallies are an exact tie (#6051).\n *\n * Weighted tallies are sums of voter weights (optionally scaled by vote\n * confidence), so two panels that tie in exact arithmetic can differ at the\n * 1e-16 level in IEEE-754 (`0.1 + 0.2 + 1.0 !== 1.3`). A strict `===` would\n * call that a 2e-16 majority; this tolerance is far above float noise and far\n * below the smallest weight difference a caller could intend (weights are\n * conventionally in [0, 1] with a handful of decimals).\n */\nconst TIE_TOLERANCE = 1e-9;\n\n/** Inputs to the quorum-status calculation, grouped to stay within max-params. */\ninterface QuorumStatusInput {\n readonly voteCounts: VoteCounts;\n readonly weightedCounts: WeightedVoteCounts | undefined;\n readonly totalWeight: number | undefined;\n readonly config: QuorumValidationConfig;\n readonly requiredParticipants: number;\n /** Whether any voter had a weight SUPPLIED — provenance, not value (#5117). */\n readonly anyWeightSupplied: boolean;\n}\n\n/** Inputs to the weighted-quorum reasoning string. */\ninterface WeightedReasoningInput {\n readonly quorumReached: boolean;\n readonly totalWeight: number;\n readonly threshold: number;\n readonly approveRatio: number;\n readonly rejectRatio: number;\n /** False when no agent weights were supplied — the tally is a headcount. */\n readonly weighted: boolean;\n}\n\n/**\n * Unified quorum validator implementation.\n */\nexport class QuorumValidator implements IQuorumValidator {\n private readonly logger: ILogger;\n\n constructor(logger?: ILogger) {\n this.logger = logger ?? createLogger({ component: 'QuorumValidator' });\n }\n\n validateQuorum(input: QuorumValidationInput): QuorumValidationResult {\n const { votes, config } = input;\n\n // Validate input\n if (votes.size === 0) {\n return { status: 'invalid', error: 'No votes provided' };\n }\n\n // Calculate breakdown\n const breakdown = this.getQuorumBreakdown(input);\n\n // Check if quorum reached\n if (!breakdown.quorumReached) {\n return this.buildNotReachedResult(breakdown, config);\n }\n\n // A tie is not a decision (#6051). At the schema-minimum threshold (0.5)\n // both sides clear the bar, and the old `>=` tie-break reported a 3-3\n // panel as `approve` with the only tie signal (confidence 0) left for the\n // caller to notice. Keep the tie out of the reached path entirely.\n if (this.isTie(breakdown)) {\n return this.buildTieResult(breakdown);\n }\n\n // Determine decision\n return this.buildReachedResult(breakdown);\n }\n\n getQuorumBreakdown(input: QuorumValidationInput): QuorumBreakdown {\n const { votes, agentWeights, config, requiredParticipants } = input;\n\n // Count votes\n const voteCounts = this.countVotes(votes);\n\n // Calculate weights if applicable\n const { totalWeight, weightedCounts } = this.calculateWeights(votes, agentWeights, config);\n\n // Whether any voter actually had a weight SUPPLIED (#5117). Derived from\n // provenance — presence in `agentWeights` — not from whether a weight\n // differs from 1.0: an agent legitimately weighted 1.0 is not the same as\n // one nobody ever weighted, and numeric equality cannot tell them apart.\n const anyWeightSupplied = [...votes.keys()].some((id) => agentWeights?.has(id) === true);\n\n // Calculate quorum based on algorithm\n const { threshold, actualQuorum, quorumReached, reasoning } = this.calculateQuorumStatus({\n voteCounts,\n weightedCounts,\n totalWeight,\n config,\n requiredParticipants: requiredParticipants ?? votes.size,\n anyWeightSupplied,\n });\n\n return {\n totalVotes: votes.size,\n voteCounts,\n totalWeight,\n weightedCounts,\n threshold,\n actualQuorum,\n quorumReached,\n reasoning,\n };\n }\n\n private countVotes(votes: ReadonlyMap<string, Vote>): VoteCounts {\n let approve = 0;\n let reject = 0;\n let abstain = 0;\n\n for (const vote of votes.values()) {\n switch (vote.decision) {\n case 'approve':\n approve++;\n break;\n case 'reject':\n reject++;\n break;\n case 'abstain':\n abstain++;\n break;\n }\n }\n\n return { approve, reject, abstain, total: votes.size };\n }\n\n private calculateWeights(\n votes: ReadonlyMap<string, Vote>,\n agentWeights: ReadonlyMap<string, number> | undefined,\n config: QuorumValidationConfig\n ): { totalWeight: number | undefined; weightedCounts: WeightedVoteCounts | undefined } {\n // Skip weight calculation for simple algorithms\n if (config.algorithm === 'simple_majority' || config.algorithm === 'unanimous') {\n return { totalWeight: undefined, weightedCounts: undefined };\n }\n\n const counts = { totalWeight: 0, approve: 0, reject: 0, abstain: 0 };\n\n for (const [agentId, vote] of votes.entries()) {\n const weight = this.getVoteWeight(agentId, vote, agentWeights, config);\n counts.totalWeight += weight;\n this.addWeightToDecision(counts, vote.decision, weight);\n }\n\n return {\n totalWeight: counts.totalWeight,\n weightedCounts: {\n approve: counts.approve,\n reject: counts.reject,\n abstain: counts.abstain,\n totalWeight: counts.totalWeight,\n },\n };\n }\n\n private getVoteWeight(\n agentId: string,\n vote: Vote,\n agentWeights: ReadonlyMap<string, number> | undefined,\n config: QuorumValidationConfig\n ): number {\n let weight = agentWeights?.get(agentId) ?? 1.0;\n if (config.confidenceMultiplier === true) {\n weight *= vote.confidence;\n }\n return weight;\n }\n\n private addWeightToDecision(\n counts: { approve: number; reject: number; abstain: number },\n decision: 'approve' | 'reject' | 'abstain',\n weight: number\n ): void {\n counts[decision] += weight;\n }\n\n private calculateQuorumStatus(opts: QuorumStatusInput): {\n threshold: number;\n actualQuorum: number;\n quorumReached: boolean;\n reasoning: string;\n } {\n const {\n voteCounts,\n weightedCounts,\n totalWeight,\n config,\n requiredParticipants,\n anyWeightSupplied,\n } = opts;\n const threshold = config.threshold;\n\n // For weighted algorithms, use weighted counts\n if (weightedCounts !== undefined && totalWeight !== undefined && totalWeight > 0) {\n return this.calculateWeightedQuorum(\n weightedCounts,\n totalWeight,\n threshold,\n anyWeightSupplied\n );\n }\n\n // For simple algorithms, use vote counts\n return this.calculateSimpleQuorum(voteCounts, requiredParticipants, threshold, config);\n }\n\n private calculateWeightedQuorum(\n weightedCounts: WeightedVoteCounts,\n totalWeight: number,\n threshold: number,\n anyWeightSupplied: boolean\n ): { threshold: number; actualQuorum: number; quorumReached: boolean; reasoning: string } {\n const quorumReached = totalWeight >= threshold;\n const approveRatio = weightedCounts.approve / totalWeight;\n const rejectRatio = weightedCounts.reject / totalWeight;\n\n const reasoning = this.buildWeightedReasoning({\n quorumReached,\n totalWeight,\n threshold,\n approveRatio,\n rejectRatio,\n weighted: anyWeightSupplied,\n });\n\n return { threshold, actualQuorum: totalWeight, quorumReached, reasoning };\n }\n\n /**\n * Reasoning text for the weighted-quorum branch.\n *\n * `weighted` is qualified rather than asserted (#5117). `agentWeights` has no\n * non-test producer, so every real call reaches `getVoteWeight`'s `?? 1.0`\n * fallback and this branch describes a plain headcount as a weighted ratio.\n * The word is kept where weights genuinely varied and replaced where they\n * did not, so the reader can tell the two apart.\n */\n private buildWeightedReasoning(opts: WeightedReasoningInput): string {\n const { quorumReached, totalWeight, threshold, approveRatio, rejectRatio, weighted } = opts;\n const kind = weighted ? 'weighted' : 'unweighted (no agent weights supplied)';\n if (!quorumReached) {\n return `Quorum not reached: ${totalWeight.toFixed(2)} < ${String(threshold)} (${kind})`;\n }\n if (approveRatio > rejectRatio) {\n return `Approval wins with ${kind} ratio ${formatPercentage(approveRatio, 1)}`;\n }\n if (rejectRatio > approveRatio) {\n return `Rejection wins with ${kind} ratio ${formatPercentage(rejectRatio, 1)}`;\n }\n return `No clear winner: approve=${formatPercentage(approveRatio, 1)}, reject=${formatPercentage(rejectRatio, 1)} (${kind})`;\n }\n\n private calculateSimpleQuorum(\n voteCounts: VoteCounts,\n requiredParticipants: number,\n threshold: number,\n config: QuorumValidationConfig\n ): { threshold: number; actualQuorum: number; quorumReached: boolean; reasoning: string } {\n const activeVotes =\n config.includeAbstentions === true\n ? voteCounts.total\n : voteCounts.approve + voteCounts.reject;\n\n const total = requiredParticipants > 0 ? requiredParticipants : activeVotes;\n const approveRatio = total > 0 ? voteCounts.approve / total : 0;\n const rejectRatio = total > 0 ? voteCounts.reject / total : 0;\n\n const hasMinVoters = activeVotes >= config.minVoters;\n const quorumReached = hasMinVoters && (approveRatio >= threshold || rejectRatio >= threshold);\n\n const reasoning = this.buildSimpleReasoning({\n hasMinVoters,\n activeVotes,\n minVoters: config.minVoters,\n approveRatio,\n rejectRatio,\n threshold,\n });\n\n return {\n threshold,\n actualQuorum: Math.max(approveRatio, rejectRatio),\n quorumReached,\n reasoning,\n };\n }\n\n private buildSimpleReasoning(params: {\n hasMinVoters: boolean;\n activeVotes: number;\n minVoters: number;\n approveRatio: number;\n rejectRatio: number;\n threshold: number;\n }): string {\n const { hasMinVoters, activeVotes, minVoters, approveRatio, rejectRatio, threshold } = params;\n if (!hasMinVoters) {\n return `Insufficient voters: ${String(activeVotes)} < ${String(minVoters)}`;\n }\n if (approveRatio >= threshold) {\n return `Approval reaches threshold: ${formatPercentage(approveRatio, 1)} >= ${formatPercentage(threshold, 1)}`;\n }\n if (rejectRatio >= threshold) {\n return `Rejection reaches threshold: ${formatPercentage(rejectRatio, 1)} >= ${formatPercentage(threshold, 1)}`;\n }\n return `No decision reached threshold: approve=${formatPercentage(approveRatio, 1)}, reject=${formatPercentage(rejectRatio, 1)}`;\n }\n\n private buildNotReachedResult(\n breakdown: QuorumBreakdown,\n config: QuorumValidationConfig\n ): QuorumValidationResult {\n const { voteCounts, weightedCounts, threshold } = breakdown;\n\n if (voteCounts.total < config.minVoters) {\n return {\n status: 'not_reached',\n reason: 'insufficient_votes',\n details: `Only ${String(voteCounts.total)} votes, need ${String(config.minVoters)}`,\n };\n }\n\n if (weightedCounts !== undefined && weightedCounts.totalWeight < threshold) {\n return {\n status: 'not_reached',\n reason: 'insufficient_weight',\n details: `Weight ${weightedCounts.totalWeight.toFixed(2)} < threshold ${String(threshold)}`,\n };\n }\n\n return {\n status: 'not_reached',\n reason: 'no_consensus',\n details: breakdown.reasoning,\n };\n }\n\n /** The tallies a decision is drawn from: weighted when weights apply, else headcount. */\n private decisiveTallies(breakdown: QuorumBreakdown): {\n approves: number;\n rejects: number;\n total: number;\n } {\n const { voteCounts, weightedCounts } = breakdown;\n return {\n approves: weightedCounts?.approve ?? voteCounts.approve,\n rejects: weightedCounts?.reject ?? voteCounts.reject,\n total: weightedCounts?.totalWeight ?? voteCounts.total,\n };\n }\n\n private isTie(breakdown: QuorumBreakdown): boolean {\n const { approves, rejects } = this.decisiveTallies(breakdown);\n return Math.abs(approves - rejects) < TIE_TOLERANCE;\n }\n\n /**\n * A tie reuses the existing `no_consensus` variant rather than a new status\n * member (a new member is breaking for exhaustive switches downstream). The\n * tie survives in `details`, which is the only place it can be read from.\n */\n private buildTieResult(breakdown: QuorumBreakdown): QuorumValidationResult {\n const { approves, rejects } = this.decisiveTallies(breakdown);\n const kind = breakdown.weightedCounts === undefined ? '' : ' (weighted)';\n return {\n status: 'not_reached',\n reason: 'no_consensus',\n details: `tie: ${formatTally(approves)} approve vs ${formatTally(rejects)} reject${kind}; consensus not reached`,\n };\n }\n\n private buildReachedResult(breakdown: QuorumBreakdown): QuorumValidationResult {\n const { approves, rejects, total } = this.decisiveTallies(breakdown);\n\n // Determine winning decision. A tie never reaches here (`isTie` guards\n // the call), so the comparison is strict: `>=` would silently re-open the\n // tie-as-approval defect if the guard were ever removed (#6051).\n const decision: 'approve' | 'reject' = approves > rejects ? 'approve' : 'reject';\n const confidence = total > 0 ? Math.abs(approves - rejects) / total : 0;\n\n return {\n status: 'reached',\n decision,\n confidence,\n reasoning: breakdown.reasoning,\n };\n }\n}\n\n/** Integers print as counts (`3`); weighted sums keep two decimals (`1.30`). */\nfunction formatTally(value: number): string {\n return Number.isInteger(value) ? String(value) : value.toFixed(2);\n}\n\n/**\n * Creates a quorum validator instance.\n */\nexport function createQuorumValidator(logger?: ILogger): IQuorumValidator {\n return new QuorumValidator(logger);\n}\n","/**\n * Helper functions for the multi-round voting protocol.\n *\n * @module consensus/voting-protocol-helpers\n * (Source: Issue #100, arXiv:2512.21352)\n */\n\nimport type {\n VotingSession,\n VotingRound,\n VotingRoundPhase,\n VotingProtocolConfig,\n VotingProtocolResult,\n AgentFinding,\n Vote,\n ConsolidatedFinding,\n RoundSummary,\n SycophancyReport,\n SycophancyIndicator,\n} from './types.js';\nimport { createQuorumValidator, type QuorumValidationConfig } from './quorum-validator.js';\nimport { getTimeProvider, getRandomProvider } from '../core/index.js';\n\n/**\n * Generate a unique session ID.\n */\nexport function generateSessionId(): string {\n const time = getTimeProvider();\n const random = getRandomProvider();\n return `session_${String(time.now())}_${random.randomString(7)}`;\n}\n\n/**\n * Generate a unique finding ID.\n */\nexport function generateFindingId(): string {\n const time = getTimeProvider();\n const random = getRandomProvider();\n return `finding_${String(time.now())}_${random.randomString(7)}`;\n}\n\n/**\n * Generate a unique round ID.\n */\nexport function generateRoundId(): string {\n const time = getTimeProvider();\n const random = getRandomProvider();\n return `round_${String(time.now())}_${random.randomString(7)}`;\n}\n\n/**\n * Create a new voting round.\n */\nexport function createRound(phase: VotingRoundPhase, roundNumber: number): VotingRound {\n const time = getTimeProvider();\n return {\n id: generateRoundId(),\n phase,\n status: 'in_progress',\n findings: new Map(),\n findingVotes: new Map(),\n finalVotes: new Map(),\n startedAt: time.nowIso(),\n roundNumber,\n };\n}\n\n/**\n * Find the most common element in an array.\n */\nexport function mostCommon<T>(items: T[]): T | undefined {\n if (items.length === 0) return undefined;\n\n const counts = new Map<T, number>();\n items.forEach((item) => {\n counts.set(item, (counts.get(item) ?? 0) + 1);\n });\n\n let maxCount = 0;\n let result: T | undefined;\n counts.forEach((count, item) => {\n if (count > maxCount) {\n maxCount = count;\n result = item;\n }\n });\n\n return result;\n}\n\n/**\n * Calculate agreement score from votes.\n */\nexport function calculateAgreementScore(votes: Vote[]): number {\n if (votes.length < 2) return 1;\n\n const decisions = votes.map((v) => v.decision);\n const mostCommonDecision = mostCommon(decisions);\n const agreementCount = decisions.filter((d) => d === mostCommonDecision).length;\n\n return agreementCount / votes.length;\n}\n\n/**\n * Determine outcome from final votes using unified QuorumValidator.\n * Per ADR-0003, this delegates to the consolidated quorum logic.\n */\nexport function determineOutcome(\n votes: Vote[],\n config: VotingProtocolConfig\n): VotingProtocolResult['outcome'] {\n if (votes.length === 0) return 'no_consensus';\n\n // Convert array to Map for QuorumValidator\n const voteMap = new Map<string, Vote>();\n votes.forEach((vote, index) => {\n voteMap.set(`voter_${String(index)}`, vote);\n });\n\n // Create quorum config from voting protocol config\n const quorumConfig: QuorumValidationConfig = {\n algorithm: 'simple_majority',\n threshold: config.agreementThreshold,\n minVoters: 2, // Minimum for valid consensus\n };\n\n // Use unified QuorumValidator\n const validator = createQuorumValidator();\n const result = validator.validateQuorum({\n votes: voteMap,\n config: quorumConfig,\n });\n\n // Map QuorumValidationResult to VotingProtocolResult outcome\n if (result.status === 'reached') {\n return result.decision === 'approve' ? 'approved' : 'rejected';\n }\n\n // Check for mixed votes (needs revision)\n const approvals = votes.filter((v) => v.decision === 'approve').length;\n const rejections = votes.filter((v) => v.decision === 'reject').length;\n if (approvals > 0 && rejections > 0) return 'needs_revision';\n\n return 'no_consensus';\n}\n\n/**\n * Consolidate findings from deliberation round.\n */\nexport function consolidateFindings(session: VotingSession): ConsolidatedFinding[] {\n const deliberationRound = session.rounds[1];\n if (!deliberationRound) return [];\n\n const consolidated: ConsolidatedFinding[] = [];\n\n deliberationRound.findings.forEach((finding, findingId) => {\n const votes = deliberationRound.findingVotes.get(findingId) ?? [];\n const agreeVotes = votes.filter((v) => v.agree);\n const agreementRatio = votes.length > 0 ? agreeVotes.length / votes.length : 0;\n\n // Only include findings with some agreement\n if (agreementRatio >= 0.5) {\n // Determine final severity (use most common amended severity or original)\n const severityVotes = agreeVotes\n .filter((v) => v.amendedSeverity)\n .map((v) => v.amendedSeverity);\n const finalSeverity =\n severityVotes.length > 0\n ? (mostCommon(severityVotes) ?? finding.severity)\n : finding.severity;\n\n const consolidatedFinding: ConsolidatedFinding = {\n id: findingId,\n category: finding.category,\n severity: finalSeverity,\n description: finding.description,\n supportingAgents: agreeVotes.map((v) => v.agentId),\n agreementRatio,\n originalFindings: [finding],\n };\n if (finding.location !== undefined) {\n consolidatedFinding.location = finding.location;\n }\n if (finding.suggestion !== undefined) {\n consolidatedFinding.suggestion = finding.suggestion;\n }\n consolidated.push(consolidatedFinding);\n }\n });\n\n // Sort by severity and agreement\n return consolidated.sort((a, b) => {\n const severityOrder = { critical: 0, major: 1, minor: 2, suggestion: 3 };\n const sevDiff = severityOrder[a.severity] - severityOrder[b.severity];\n if (sevDiff !== 0) return sevDiff;\n return b.agreementRatio - a.agreementRatio;\n });\n}\n\n/**\n * Build round summaries from session.\n */\nexport function buildRoundSummaries(session: VotingSession): RoundSummary[] {\n const time = getTimeProvider();\n return session.rounds.map((round, index) => {\n const startTime = new Date(round.startedAt).getTime();\n const endTime =\n round.completedAt !== undefined ? new Date(round.completedAt).getTime() : time.now();\n\n let votesCount = 0;\n let agreementScore = 0;\n\n if (round.phase === 'deliberation') {\n // Count finding votes\n round.findingVotes.forEach((votes) => {\n votesCount += votes.length;\n const agreeCount = votes.filter((v) => v.agree).length;\n agreementScore += votes.length > 0 ? agreeCount / votes.length : 0;\n });\n const findingsCount = round.findingVotes.size;\n if (findingsCount > 0) {\n agreementScore /= findingsCount;\n }\n } else if (round.phase === 'consensus') {\n // Count final votes\n votesCount = round.finalVotes.size;\n const votes = Array.from(round.finalVotes.values());\n agreementScore = calculateAgreementScore(votes);\n }\n\n return {\n roundNumber: index + 1,\n phase: round.phase,\n findingsCount: round.findings.size,\n votesCount,\n agreementScore,\n durationMs: endTime - startTime,\n };\n });\n}\n\n// ============================================================================\n// Sycophancy Detection\n// ============================================================================\n\n/**\n * Check for premature consensus pattern.\n */\nexport function checkPrematureConsensus(session: VotingSession): SycophancyIndicator | null {\n const analysisRound = session.rounds[0];\n if (!analysisRound) return null;\n\n const agentFindings = new Map<string, AgentFinding[]>();\n analysisRound.findings.forEach((finding) => {\n const existing = agentFindings.get(finding.agentId) ?? [];\n existing.push(finding);\n agentFindings.set(finding.agentId, existing);\n });\n\n const allConfidences: number[] = [];\n analysisRound.findings.forEach((finding) => {\n allConfidences.push(finding.confidence);\n });\n\n const avgConfidence =\n allConfidences.length > 0\n ? allConfidences.reduce((a, b) => a + b, 0) / allConfidences.length\n : 0;\n\n if (avgConfidence > 0.95 && agentFindings.size >= 2) {\n return {\n type: 'premature_consensus',\n description: 'All agents showing unusually high confidence',\n severity: 'medium',\n agents: Array.from(agentFindings.keys()),\n };\n }\n\n return null;\n}\n\n/**\n * Check for opinion convergence pattern.\n */\nexport function checkOpinionConvergence(session: VotingSession): SycophancyIndicator | null {\n const deliberationRound = session.rounds[1];\n if (!deliberationRound) return null;\n\n let totalVotes = 0;\n let agreeVotes = 0;\n\n deliberationRound.findingVotes.forEach((votes) => {\n totalVotes += votes.length;\n agreeVotes += votes.filter((v) => v.agree).length;\n });\n\n const agreeRatio = totalVotes > 0 ? agreeVotes / totalVotes : 0;\n\n if (agreeRatio > session.config.sycophancyThreshold && totalVotes > 3) {\n const affectedAgents: string[] = [];\n deliberationRound.findingVotes.forEach((votes) => {\n votes.forEach((v) => {\n if (v.agree && !affectedAgents.includes(v.agentId)) {\n affectedAgents.push(v.agentId);\n }\n });\n });\n\n return {\n type: 'opinion_convergence',\n description: `${String(Math.round(agreeRatio * 100))}% agreement rate suggests possible opinion convergence`,\n severity: 'high',\n agents: affectedAgents,\n };\n }\n\n return null;\n}\n\n/**\n * Check for confidence inflation pattern.\n */\nexport function checkConfidenceInflation(session: VotingSession): SycophancyIndicator | null {\n const consensusRound = session.rounds[2];\n if (!consensusRound) return null;\n\n const votes = Array.from(consensusRound.finalVotes.values());\n if (votes.length < 2) return null;\n\n const confidences = votes.map((v) => v.confidence);\n const avgConfidence = confidences.reduce((a, b) => a + b, 0) / confidences.length;\n const allHigh = confidences.every((c) => c > 0.9);\n\n if (allHigh && avgConfidence > 0.95) {\n return {\n type: 'confidence_inflation',\n description: 'All agents reporting very high confidence suggests possible sycophancy',\n severity: 'medium',\n agents: Array.from(consensusRound.finalVotes.keys()),\n };\n }\n\n return null;\n}\n\n/**\n * Run all sycophancy detection checks.\n */\nexport function detectSycophancyPatterns(session: VotingSession): SycophancyReport {\n const indicators: SycophancyIndicator[] = [];\n const affectedAgents: string[] = [];\n\n const prematureConsensus = checkPrematureConsensus(session);\n if (prematureConsensus) {\n indicators.push(prematureConsensus);\n affectedAgents.push(...prematureConsensus.agents);\n }\n\n const opinionConvergence = checkOpinionConvergence(session);\n if (opinionConvergence) {\n indicators.push(opinionConvergence);\n affectedAgents.push(...opinionConvergence.agents);\n }\n\n const confidenceInflation = checkConfidenceInflation(session);\n if (confidenceInflation) {\n indicators.push(confidenceInflation);\n affectedAgents.push(...confidenceInflation.agents);\n }\n\n const detected = indicators.length > 0;\n const confidenceScore = Math.min(1, indicators.length * 0.3);\n const uniqueAffected = [...new Set(affectedAgents)];\n\n return {\n detected,\n confidenceScore,\n indicators,\n affectedAgents: uniqueAffected,\n recommendation: detected\n ? 'Consider requesting independent re-analysis or adding more diverse agents'\n : 'No sycophancy detected',\n };\n}\n","/**\n * Multi-Round Voting Protocol Implementation\n *\n * Implements a structured 3-round voting protocol for multi-agent code review\n * based on research showing 91.7-100% success rates vs 78% single-agent baseline.\n *\n * @module consensus/voting-protocol\n * (Source: Issue #100, arXiv:2512.21352 - Multi-Agent Committees)\n * (Source: arXiv:2509.23055 - Sycophancy Prevention)\n */\n\nimport { createLogger } from '../core/logger.js';\nimport { allOf } from '../utils/verdict-aggregation.js';\nimport { getTimeProvider } from '../core/index.js';\nimport type { ILogger } from '../core/index.js';\nimport type {\n IVotingProtocol,\n VotingSession,\n VotingRound,\n VotingProtocolConfig,\n VotingProtocolResult,\n AgentFinding,\n FindingVote,\n Vote,\n SycophancyReport,\n} from './types.js';\nimport {\n AgentFindingSchema,\n FindingVoteSchema,\n VoteSchema,\n DEFAULT_VOTING_PROTOCOL_CONFIG,\n} from './types.js';\nimport {\n generateSessionId,\n generateFindingId,\n createRound,\n consolidateFindings,\n buildRoundSummaries,\n determineOutcome,\n calculateAgreementScore,\n detectSycophancyPatterns,\n} from './voting-protocol-helpers.js';\n\nconst logger: ILogger = createLogger({ component: 'voting-protocol' });\n\n/**\n * Multi-round voting protocol for code review.\n */\nexport class VotingProtocol implements IVotingProtocol {\n private readonly sessions: Map<string, VotingSession> = new Map();\n private readonly logger: ILogger;\n\n constructor(customLogger?: ILogger) {\n this.logger = customLogger ?? logger;\n }\n\n /**\n * Create a new voting session with a committee.\n */\n createSession(\n topic: string,\n committee: string[],\n config?: Partial<VotingProtocolConfig>\n ): VotingSession {\n const sessionConfig = { ...DEFAULT_VOTING_PROTOCOL_CONFIG, ...config };\n\n if (committee.length < 2) {\n throw new Error('Committee must have at least 2 members');\n }\n\n if (committee.length > sessionConfig.committeeSize) {\n throw new Error(`Committee size exceeds maximum (${String(sessionConfig.committeeSize)})`);\n }\n\n const session: VotingSession = {\n id: generateSessionId(),\n topic,\n committee,\n rounds: [],\n currentRound: 0,\n config: sessionConfig,\n status: 'active',\n createdAt: getTimeProvider().nowIso(),\n };\n\n this.sessions.set(session.id, session);\n this.logger.info('Voting session created', {\n sessionId: session.id,\n topic,\n committeeSize: committee.length,\n });\n\n return session;\n }\n\n /**\n * Start the analysis round (Round 1).\n */\n startAnalysisRound(sessionId: string): Promise<VotingRound> {\n const session = this.getSessionOrThrow(sessionId);\n this.validateSessionActive(session);\n\n if (session.currentRound !== 0) {\n return Promise.reject(new Error('Analysis round can only be started as Round 1'));\n }\n\n const round = createRound('analysis', 1);\n session.rounds.push(round);\n session.currentRound = 1;\n\n this.logger.info('Analysis round started', { sessionId, roundId: round.id });\n return Promise.resolve(round);\n }\n\n /**\n * Submit findings from an agent during analysis.\n */\n submitFindings(sessionId: string, agentId: string, findings: AgentFinding[]): Promise<void> {\n const session = this.getSessionOrThrow(sessionId);\n this.validateSessionActive(session);\n\n const currentRound = this.getCurrentRound(session);\n if (currentRound.phase !== 'analysis') {\n return Promise.reject(new Error('Findings can only be submitted during analysis round'));\n }\n\n if (!session.committee.includes(agentId)) {\n return Promise.reject(new Error(`Agent ${agentId} is not a committee member`));\n }\n\n for (const finding of findings) {\n const validation = AgentFindingSchema.safeParse(finding);\n if (!validation.success) {\n return Promise.reject(new Error(`Invalid finding: ${validation.error.message}`));\n }\n\n const findingId = generateFindingId();\n const timestampedFinding = {\n ...validation.data,\n agentId,\n timestamp: getTimeProvider().nowIso(),\n };\n currentRound.findings.set(findingId, timestampedFinding);\n }\n\n this.logger.debug('Findings submitted', { sessionId, agentId, findingsCount: findings.length });\n return Promise.resolve();\n }\n\n /**\n * Start the deliberation round (Round 2).\n */\n startDeliberationRound(sessionId: string): Promise<VotingRound> {\n const session = this.getSessionOrThrow(sessionId);\n this.validateSessionActive(session);\n\n if (session.currentRound !== 1) {\n return Promise.reject(new Error('Deliberation round can only be started after analysis'));\n }\n\n const analysisRound = session.rounds[0];\n if (analysisRound) {\n analysisRound.status = 'completed';\n analysisRound.completedAt = getTimeProvider().nowIso();\n }\n\n if (session.config.enableAntiSycophancy) {\n const report = this.detectSycophancy(sessionId);\n if (report.detected) {\n this.logger.warn('Sycophancy detected before deliberation', {\n sessionId,\n indicators: report.indicators.length,\n });\n }\n }\n\n const round = createRound('deliberation', 2);\n if (analysisRound) {\n analysisRound.findings.forEach((finding, id) => {\n round.findings.set(id, finding);\n round.findingVotes.set(id, []);\n });\n }\n\n session.rounds.push(round);\n session.currentRound = 2;\n\n this.logger.info('Deliberation round started', {\n sessionId,\n roundId: round.id,\n findingsCount: round.findings.size,\n });\n return Promise.resolve(round);\n }\n\n /**\n * Vote on findings during deliberation.\n */\n voteOnFinding(sessionId: string, vote: FindingVote): Promise<void> {\n const session = this.getSessionOrThrow(sessionId);\n this.validateSessionActive(session);\n\n const currentRound = this.getCurrentRound(session);\n if (currentRound.phase !== 'deliberation') {\n return Promise.reject(new Error('Finding votes can only be submitted during deliberation'));\n }\n\n const validation = FindingVoteSchema.safeParse(vote);\n if (!validation.success) {\n return Promise.reject(new Error(`Invalid vote: ${validation.error.message}`));\n }\n\n if (!session.committee.includes(vote.agentId)) {\n return Promise.reject(new Error(`Agent ${vote.agentId} is not a committee member`));\n }\n\n if (!currentRound.findings.has(vote.findingId)) {\n return Promise.reject(new Error(`Finding ${vote.findingId} not found`));\n }\n\n const existingVotes = currentRound.findingVotes.get(vote.findingId) ?? [];\n const filtered = existingVotes.filter((v) => v.agentId !== vote.agentId);\n filtered.push(validation.data);\n currentRound.findingVotes.set(vote.findingId, filtered);\n\n this.logger.debug('Finding vote recorded', {\n sessionId,\n agentId: vote.agentId,\n findingId: vote.findingId,\n agree: vote.agree,\n });\n return Promise.resolve();\n }\n\n /**\n * Start the consensus round (Round 3).\n */\n startConsensusRound(sessionId: string): Promise<VotingRound> {\n const session = this.getSessionOrThrow(sessionId);\n this.validateSessionActive(session);\n\n if (session.currentRound !== 2) {\n return Promise.reject(new Error('Consensus round can only be started after deliberation'));\n }\n\n const deliberationRound = session.rounds[1];\n if (deliberationRound) {\n deliberationRound.status = 'completed';\n deliberationRound.completedAt = getTimeProvider().nowIso();\n }\n\n const round = createRound('consensus', 3);\n session.rounds.push(round);\n session.currentRound = 3;\n\n this.logger.info('Consensus round started', { sessionId, roundId: round.id });\n return Promise.resolve(round);\n }\n\n /**\n * Submit final vote during consensus.\n */\n submitFinalVote(sessionId: string, agentId: string, vote: Vote): Promise<void> {\n const session = this.getSessionOrThrow(sessionId);\n this.validateSessionActive(session);\n\n const currentRound = this.getCurrentRound(session);\n if (currentRound.phase !== 'consensus') {\n return Promise.reject(new Error('Final votes can only be submitted during consensus'));\n }\n\n const validation = VoteSchema.safeParse(vote);\n if (!validation.success) {\n return Promise.reject(new Error(`Invalid vote: ${validation.error.message}`));\n }\n\n if (!session.committee.includes(agentId)) {\n return Promise.reject(new Error(`Agent ${agentId} is not a committee member`));\n }\n\n currentRound.finalVotes.set(agentId, {\n ...validation.data,\n timestamp: getTimeProvider().nowIso(),\n });\n\n this.logger.debug('Final vote recorded', {\n sessionId,\n agentId,\n decision: vote.decision,\n confidence: vote.confidence,\n });\n return Promise.resolve();\n }\n\n /**\n * Get the final result.\n */\n getResult(sessionId: string): Promise<VotingProtocolResult | null> {\n const session = this.sessions.get(sessionId);\n if (!session) return Promise.resolve(null);\n\n if (session.status === 'completed' && session.finalResult) {\n return Promise.resolve(session.finalResult);\n }\n\n if (session.currentRound < 3) return Promise.resolve(null);\n\n const consensusRound = session.rounds[2];\n if (!consensusRound) return Promise.resolve(null);\n\n // whenEmpty = false: a committee of zero members has cast zero votes, and\n // `[].every()` used to report that as \"everyone voted\" — finalizing the\n // session as `completed` with an outcome derived from no ballots at all.\n // Zero voters is the absence of consensus, not unanimous consensus, so the\n // empty case takes the same path as a partial vote: no result, session stays\n // active, and the record never claims a vote that was never held. (#4581)\n const allVoted = allOf(\n session.committee,\n (agentId) => consensusRound.finalVotes.has(agentId),\n false\n );\n if (!allVoted) return Promise.resolve(null);\n\n const result = this.buildFinalResult(session);\n session.finalResult = result;\n session.status = 'completed';\n session.completedAt = getTimeProvider().nowIso();\n\n consensusRound.status = 'completed';\n consensusRound.completedAt = getTimeProvider().nowIso();\n\n this.logger.info('Voting session completed', {\n sessionId,\n outcome: result.outcome,\n agreementScore: result.agreementScore,\n consolidatedFindings: result.consolidatedFindings.length,\n });\n\n return Promise.resolve(result);\n }\n\n /**\n * Detect sycophancy patterns.\n */\n detectSycophancy(sessionId: string): SycophancyReport {\n const session = this.getSessionOrThrow(sessionId);\n return detectSycophancyPatterns(session);\n }\n\n /**\n * Get the current session state.\n */\n getSession(sessionId: string): VotingSession | undefined {\n return this.sessions.get(sessionId);\n }\n\n private getSessionOrThrow(sessionId: string): VotingSession {\n const session = this.sessions.get(sessionId);\n if (!session) {\n throw new Error(`Session ${sessionId} not found`);\n }\n return session;\n }\n\n private validateSessionActive(session: VotingSession): void {\n if (session.status !== 'active') {\n throw new Error(`Session ${session.id} is ${session.status}`);\n }\n }\n\n private getCurrentRound(session: VotingSession): VotingRound {\n const round = session.rounds[session.currentRound - 1];\n if (!round) {\n throw new Error(`No round ${String(session.currentRound)} found`);\n }\n return round;\n }\n\n private buildFinalResult(session: VotingSession): VotingProtocolResult {\n const startTime = new Date(session.createdAt).getTime();\n const endTime = getTimeProvider().now();\n\n const consolidatedFindingsList = consolidateFindings(session);\n const roundSummaries = buildRoundSummaries(session);\n\n const consensusRound = session.rounds[2];\n const finalVotes = consensusRound ? Array.from(consensusRound.finalVotes.values()) : [];\n const outcome = determineOutcome(finalVotes, session.config);\n const agreementScore = calculateAgreementScore(finalVotes);\n const sycophancyReport = detectSycophancyPatterns(session);\n\n return {\n sessionId: session.id,\n topic: session.topic,\n outcome,\n consolidatedFindings: consolidatedFindingsList,\n roundSummaries,\n agreementScore,\n sycophancyDetected: sycophancyReport.detected,\n totalDurationMs: endTime - startTime,\n participatingAgents: session.committee,\n };\n }\n}\n\n/**\n * Create a voting protocol instance.\n */\nexport function createVotingProtocol(customLogger?: ILogger): VotingProtocol {\n return new VotingProtocol(customLogger);\n}\n","/**\n * Byzantine Detection CollaborationEventBus Integration Helpers\n * (Source: Issue #218, Sprint #228)\n *\n * Provides helper functions for emitting Byzantine fault detection events.\n * Used by CP-WBFT weighted voting to report Byzantine behavior patterns.\n *\n * @module agents/collaboration/byzantine-events\n */\n\nimport type {\n ICollaborationEventBus,\n ByzantineWeightUpdatedEvent,\n ByzantinePatternDetectedEvent,\n ByzantineAgentFlaggedEvent,\n ByzantineCollusionSuspectedEvent,\n} from './event-bus-types.js';\nimport { createEvent } from './event-bus.js';\n\n// =============================================================================\n// Weight Update Events\n// =============================================================================\n\n/** Parameters for emitting byzantine.weight_updated event. */\nexport interface WeightUpdatedParams {\n readonly agentId: string;\n readonly previousWeight: number;\n readonly newWeight: number;\n readonly reason: 'performance_update' | 'flag_penalty' | 'recalibration';\n readonly sessionId?: string | undefined;\n readonly correlationId?: string | undefined;\n}\n\n/** Emits byzantine.weight_updated event when an agent's weight changes. */\nexport function emitWeightUpdated(\n eventBus: ICollaborationEventBus,\n params: WeightUpdatedParams\n): void {\n const event = createEvent<ByzantineWeightUpdatedEvent>(\n 'byzantine.weight_updated',\n {\n agentId: params.agentId,\n previousWeight: params.previousWeight,\n newWeight: params.newWeight,\n reason: params.reason,\n },\n {\n ...(params.sessionId !== undefined && { sessionId: params.sessionId }),\n ...(params.correlationId !== undefined && { correlationId: params.correlationId }),\n }\n );\n eventBus.emit(event);\n}\n\n// =============================================================================\n// Pattern Detection Events\n// =============================================================================\n\n/** Parameters for emitting byzantine.pattern_detected event. */\nexport interface PatternDetectedParams {\n readonly patternType: 'contrarian' | 'collusion';\n readonly agentIds: readonly string[];\n readonly confidence: number;\n readonly details: string;\n readonly sessionId?: string | undefined;\n readonly correlationId?: string | undefined;\n}\n\n/** Emits byzantine.pattern_detected event when Byzantine pattern is detected. */\nexport function emitPatternDetected(\n eventBus: ICollaborationEventBus,\n params: PatternDetectedParams\n): void {\n const event = createEvent<ByzantinePatternDetectedEvent>(\n 'byzantine.pattern_detected',\n {\n patternType: params.patternType,\n agentIds: params.agentIds,\n confidence: params.confidence,\n details: params.details,\n },\n {\n ...(params.sessionId !== undefined && { sessionId: params.sessionId }),\n ...(params.correlationId !== undefined && { correlationId: params.correlationId }),\n }\n );\n eventBus.emit(event);\n}\n\n// =============================================================================\n// Agent Flagged Events\n// =============================================================================\n\n/** Parameters for emitting byzantine.agent_flagged event. */\nexport interface AgentFlaggedParams {\n readonly agentId: string;\n readonly reason: string;\n readonly previousWeight: number;\n readonly canVote: boolean;\n readonly sessionId?: string | undefined;\n readonly correlationId?: string | undefined;\n}\n\n/** Emits byzantine.agent_flagged event when an agent is flagged as Byzantine. */\nexport function emitAgentFlagged(\n eventBus: ICollaborationEventBus,\n params: AgentFlaggedParams\n): void {\n const event = createEvent<ByzantineAgentFlaggedEvent>(\n 'byzantine.agent_flagged',\n {\n agentId: params.agentId,\n reason: params.reason,\n previousWeight: params.previousWeight,\n canVote: params.canVote,\n },\n {\n ...(params.sessionId !== undefined && { sessionId: params.sessionId }),\n ...(params.correlationId !== undefined && { correlationId: params.correlationId }),\n }\n );\n eventBus.emit(event);\n}\n\n// =============================================================================\n// Collusion Suspected Events\n// =============================================================================\n\n/** Parameters for emitting byzantine.collusion_suspected event. */\nexport interface CollusionSuspectedParams {\n readonly groupAgentIds: readonly string[];\n readonly groupSize: number;\n readonly votingBlock: number;\n readonly threshold: number;\n readonly sessionId?: string | undefined;\n readonly correlationId?: string | undefined;\n}\n\n/** Emits byzantine.collusion_suspected event when collusion pattern is suspected. */\nexport function emitCollusionSuspected(\n eventBus: ICollaborationEventBus,\n params: CollusionSuspectedParams\n): void {\n const event = createEvent<ByzantineCollusionSuspectedEvent>(\n 'byzantine.collusion_suspected',\n {\n groupAgentIds: params.groupAgentIds,\n groupSize: params.groupSize,\n votingBlock: params.votingBlock,\n threshold: params.threshold,\n },\n {\n ...(params.sessionId !== undefined && { sessionId: params.sessionId }),\n ...(params.correlationId !== undefined && { correlationId: params.correlationId }),\n }\n );\n eventBus.emit(event);\n}\n","/**\n * nexus-agents/consensus - Weighted Byzantine Voting Helpers\n *\n * Pure helper functions extracted from WeightedVoting class.\n * These functions are stateless and operate on parameters only.\n *\n * @module consensus/weighted-voting-helpers\n * (Source: Issue #103, arXiv:2511.10400 - CP-WBFT)\n */\n\nimport { getTimeProvider } from '../core/index.js';\nimport { clamp01 } from '../utils/math-utils.js';\nimport type { WeightedAgentRecord, WeightedConsensusResult, Vote } from './types.js';\nimport type { ICollaborationEventBus } from '../core/event-bus.js';\n\n/**\n * Mutable agent record for internal tracking.\n * Used internally by WeightedVoting class.\n */\nexport interface MutableAgentRecord {\n agentId: string;\n totalTasks: number;\n successfulTasks: number;\n failedTasks: number;\n partialTasks: number;\n successRate: number;\n weight: number;\n trustScore: number;\n byzantineFlags: number;\n byzantineReasons: string[];\n lastActive: Date;\n createdAt: Date;\n}\n\n/** Options for WeightedVoting constructor. */\nexport interface WeightedVotingOptions {\n /** Configuration for voting thresholds and weights. */\n config?: Partial<import('./types.js').WeightedVotingConfig>;\n /** Optional event bus for Byzantine detection events (Issue #218). */\n eventBus?: ICollaborationEventBus;\n /** Whether to emit Byzantine detection events (default: true if eventBus provided). */\n emitEvents?: boolean;\n}\n\n/**\n * Check if a vote is a low-confidence contrarian vote.\n * Used for Byzantine pattern detection.\n */\nexport function isLowConfidenceContrarian(vote: Vote, majorityApprove: boolean): boolean {\n const isContrarian = majorityApprove ? vote.decision === 'reject' : vote.decision === 'approve';\n return isContrarian && vote.confidence < 0.3;\n}\n\n/**\n * Compute the majority vote direction based on weighted votes.\n * Returns true if majority approves, false if majority rejects.\n */\nexport function computeMajorityDirection(\n voteArray: ReadonlyArray<readonly [string, Vote]>,\n weights: ReadonlyMap<string, number>\n): boolean {\n let totalApprove = 0;\n let totalReject = 0;\n for (const [agentId, vote] of voteArray) {\n const w = weights.get(agentId) ?? 0;\n if (vote.decision === 'approve') totalApprove += w;\n if (vote.decision === 'reject') totalReject += w;\n }\n return totalApprove > totalReject;\n}\n\n/**\n * Determine consensus decision based on vote tallies.\n */\nexport function determineDecision(\n approval: number,\n rejection: number,\n total: number,\n quorumReached: boolean,\n quorumThreshold: number\n): WeightedConsensusResult['decision'] {\n if (!quorumReached || total === 0) return 'no_consensus';\n const approvalRatio = approval / total;\n const rejectionRatio = rejection / total;\n if (approvalRatio > rejectionRatio && approvalRatio >= quorumThreshold) return 'approve';\n if (rejectionRatio > approvalRatio && rejectionRatio >= quorumThreshold) return 'reject';\n return 'no_consensus';\n}\n\n/**\n * Update derived metrics (success rate, trust score) on a mutable record.\n */\nexport function updateDerivedMetrics(record: MutableAgentRecord): void {\n // Update success rate\n if (record.totalTasks > 0) {\n const weightedSuccess = record.successfulTasks + record.partialTasks * 0.5;\n record.successRate = weightedSuccess / record.totalTasks;\n }\n\n // Update trust score based on weight and Byzantine flags\n const byzantinePenalty = Math.pow(0.7, record.byzantineFlags);\n record.trustScore = Math.min(1, record.weight * byzantinePenalty);\n}\n\n/**\n * Convert a mutable internal record to an immutable public record.\n */\nexport function toImmutableRecord(record: MutableAgentRecord): WeightedAgentRecord {\n return {\n agentId: record.agentId,\n totalTasks: record.totalTasks,\n successfulTasks: record.successfulTasks,\n failedTasks: record.failedTasks,\n partialTasks: record.partialTasks,\n successRate: record.successRate,\n weight: record.weight,\n trustScore: record.trustScore,\n byzantineFlags: record.byzantineFlags,\n lastActive: record.lastActive,\n createdAt: record.createdAt,\n };\n}\n\n/**\n * Create a vote signature for collusion detection.\n * Combines decision and confidence into a unique key.\n */\nexport function createVoteSignature(vote: Vote): string {\n return `${vote.decision}:${vote.confidence.toFixed(2)}`;\n}\n\n/**\n * Group votes by their signature for collusion pattern detection.\n */\nexport function groupVotesBySignature(\n voteArray: ReadonlyArray<readonly [string, Vote]>\n): Map<string, string[]> {\n const signatures = new Map<string, string[]>();\n for (const [agentId, vote] of voteArray) {\n const sig = createVoteSignature(vote);\n const agents = signatures.get(sig) ?? [];\n agents.push(agentId);\n signatures.set(sig, agents);\n }\n return signatures;\n}\n\n/**\n * Create a new mutable agent record with initial values.\n */\nexport function createAgentRecord(agentId: string, initialWeight: number): MutableAgentRecord {\n const now = new Date(getTimeProvider().now());\n return {\n agentId,\n totalTasks: 0,\n successfulTasks: 0,\n failedTasks: 0,\n partialTasks: 0,\n successRate: 0,\n weight: initialWeight,\n trustScore: initialWeight,\n byzantineFlags: 0,\n byzantineReasons: [],\n lastActive: now,\n createdAt: now,\n };\n}\n\n/**\n * Compute global success statistics from all agent records.\n */\nexport function computeGlobalStats(records: Iterable<MutableAgentRecord>): {\n globalSuccessRate: number;\n totalTasks: number;\n} {\n let totalSuccess = 0;\n let totalTasks = 0;\n\n for (const record of records) {\n totalSuccess += record.successfulTasks;\n totalTasks += record.totalTasks;\n }\n\n const globalSuccessRate = totalTasks > 0 ? totalSuccess / totalTasks : 0.5;\n return { globalSuccessRate, totalTasks };\n}\n\n/**\n * Calculate calibrated weight based on relative performance.\n */\nexport function calculateCalibratedWeight(\n record: MutableAgentRecord,\n globalSuccessRate: number,\n initialWeight: number\n): number {\n const relativePerformance = record.successRate / Math.max(0.01, globalSuccessRate);\n const calibratedWeight = clamp01(initialWeight * relativePerformance);\n // Smooth transition (50% old weight, 50% calibrated)\n return (record.weight + calibratedWeight) / 2;\n}\n\n/**\n * Apply weight change based on task outcome.\n */\nexport function applyOutcomeWeight(\n currentWeight: number,\n outcome: import('./types.js').TaskOutcomeStatus,\n decayFactor: number,\n recoveryFactor: number\n): number {\n switch (outcome) {\n case 'success':\n return Math.min(1, currentWeight * recoveryFactor);\n case 'failure':\n return Math.max(0, currentWeight * decayFactor);\n case 'partial':\n return Math.max(0, currentWeight * ((decayFactor + 1) / 2));\n case 'unknown':\n return currentWeight;\n }\n}\n","/**\n * nexus-agents/consensus - Weighted Byzantine Voting Implementation\n *\n * Implements CP-WBFT (arXiv:2511.10400) for weighted Byzantine fault-tolerant voting.\n * Agent votes are weighted by historical reliability with automatic trust calibration.\n *\n * @module consensus/weighted-voting\n * (Source: Issue #103, arXiv:2511.10400 - CP-WBFT)\n */\n\nimport { createLogger } from '../core/logger.js';\nimport { getTimeProvider } from '../core/index.js';\nimport type {\n IWeightedVoting,\n WeightedAgentRecord,\n WeightedConsensusResult,\n WeightedVotingConfig,\n TaskOutcomeStatus,\n Vote,\n} from './types.js';\nimport { DEFAULT_WEIGHTED_VOTING_CONFIG } from './types.js';\nimport type { ICollaborationEventBus } from '../core/event-bus.js';\nimport {\n emitWeightUpdated,\n emitPatternDetected,\n emitAgentFlagged,\n emitCollusionSuspected,\n} from '../agents/collaboration/byzantine-events.js';\nimport {\n type MutableAgentRecord,\n type WeightedVotingOptions,\n isLowConfidenceContrarian,\n computeMajorityDirection,\n determineDecision,\n updateDerivedMetrics,\n toImmutableRecord,\n groupVotesBySignature,\n createAgentRecord,\n computeGlobalStats,\n calculateCalibratedWeight,\n applyOutcomeWeight,\n} from './weighted-voting-helpers.js';\n\nexport type { WeightedVotingOptions } from './weighted-voting-helpers.js';\n\nconst logger = createLogger({ component: 'weighted-voting' });\n\n/**\n * Weighted Byzantine voting implementation.\n * Implements CP-WBFT pattern for fault-tolerant multi-agent consensus.\n */\nexport class WeightedVoting implements IWeightedVoting {\n private readonly records: Map<string, MutableAgentRecord> = new Map();\n private readonly config: WeightedVotingConfig;\n private readonly eventBus: ICollaborationEventBus | undefined;\n private readonly emitEvents: boolean;\n\n constructor(options: WeightedVotingOptions = {}) {\n this.config = { ...DEFAULT_WEIGHTED_VOTING_CONFIG, ...options.config };\n this.eventBus = options.eventBus ?? undefined;\n this.emitEvents = options.emitEvents ?? options.eventBus !== undefined;\n logger.info('WeightedVoting initialized', {\n config: this.config,\n eventsEnabled: this.emitEvents,\n });\n }\n\n calculateWeight(agentId: string): number {\n const record = this.records.get(agentId);\n if (record === undefined) return 0;\n return record.weight;\n }\n\n updatePerformance(agentId: string, outcome: TaskOutcomeStatus): void {\n let record = this.records.get(agentId);\n if (record === undefined) {\n this.registerAgent(agentId);\n record = this.records.get(agentId);\n if (record === undefined) return;\n }\n\n const previousWeight = record.weight;\n record.totalTasks += 1;\n record.lastActive = new Date(getTimeProvider().now());\n\n // Update task counts\n if (outcome === 'success') record.successfulTasks += 1;\n else if (outcome === 'failure') record.failedTasks += 1;\n else if (outcome === 'partial') record.partialTasks += 1;\n\n // Apply weight change\n record.weight = applyOutcomeWeight(\n record.weight,\n outcome,\n this.config.weightDecayFactor,\n this.config.weightRecoveryFactor\n );\n updateDerivedMetrics(record);\n this.emitWeightChange(agentId, previousWeight, record.weight, 'performance_update');\n\n logger.debug('Performance updated', {\n agentId,\n outcome,\n newWeight: record.weight,\n successRate: record.successRate,\n });\n }\n\n weightedConsensus(votes: ReadonlyMap<string, Vote>): WeightedConsensusResult {\n const { approval, rejection, total, agents, breakdown } = this.countVotes(votes);\n const byzantineDetected = this.detectByzantinePatterns(votes, breakdown);\n const quorumReached = total >= this.config.quorumThreshold;\n const decision = determineDecision(\n approval,\n rejection,\n total,\n quorumReached,\n this.config.quorumThreshold\n );\n\n const result: WeightedConsensusResult = {\n decision,\n weightedApproval: approval,\n weightedRejection: rejection,\n totalWeight: total,\n quorumReached,\n byzantineDetected,\n participatingAgents: agents,\n weightBreakdown: breakdown,\n };\n\n this.logConsensusResult(result);\n return result;\n }\n\n registerAgent(agentId: string): void {\n if (this.records.has(agentId)) {\n logger.debug('Agent already registered', { agentId });\n return;\n }\n const record = createAgentRecord(agentId, this.config.initialWeight);\n this.records.set(agentId, record);\n logger.info('Agent registered', { agentId, initialWeight: this.config.initialWeight });\n }\n\n getAgentRecord(agentId: string): WeightedAgentRecord | undefined {\n const record = this.records.get(agentId);\n if (record === undefined) return undefined;\n return toImmutableRecord(record);\n }\n\n flagByzantine(agentId: string, reason: string): void {\n const record = this.records.get(agentId);\n if (record === undefined) {\n logger.warn('Cannot flag unregistered agent', { agentId });\n return;\n }\n\n const previousWeight = record.weight;\n record.byzantineFlags += 1;\n record.byzantineReasons.push(reason);\n record.weight = Math.max(0, record.weight * 0.5);\n updateDerivedMetrics(record);\n\n const canStillVote = this.canVote(agentId);\n this.emitAgentFlaggedEvent(agentId, reason, previousWeight, canStillVote);\n this.emitWeightChange(agentId, previousWeight, record.weight, 'flag_penalty');\n\n logger.warn('Agent flagged for Byzantine behavior', {\n agentId,\n reason,\n totalFlags: record.byzantineFlags,\n newWeight: record.weight,\n });\n\n if (record.byzantineFlags >= this.config.byzantineFlagThreshold) {\n this.excludeAgent(record);\n }\n }\n\n getAllRecords(): readonly WeightedAgentRecord[] {\n return Array.from(this.records.values()).map((r) => toImmutableRecord(r));\n }\n\n canVote(agentId: string): boolean {\n const record = this.records.get(agentId);\n if (record === undefined) return false;\n return record.weight >= this.config.minWeight && record.trustScore >= this.config.minTrustScore;\n }\n\n recalibrateWeights(): void {\n const { globalSuccessRate, totalTasks } = computeGlobalStats(this.records.values());\n if (totalTasks === 0) return;\n\n for (const record of this.records.values()) {\n if (record.totalTasks < 3) continue;\n const previousWeight = record.weight;\n record.weight = calculateCalibratedWeight(\n record,\n globalSuccessRate,\n this.config.initialWeight\n );\n updateDerivedMetrics(record);\n this.emitWeightChange(record.agentId, previousWeight, record.weight, 'recalibration');\n }\n\n logger.info('Weights recalibrated', {\n agentCount: this.records.size,\n globalSuccessRate: globalSuccessRate.toFixed(3),\n });\n }\n\n // Private helpers\n\n private countVotes(votes: ReadonlyMap<string, Vote>): {\n approval: number;\n rejection: number;\n total: number;\n agents: string[];\n breakdown: Map<string, number>;\n } {\n let approval = 0;\n let rejection = 0;\n let total = 0;\n const agents: string[] = [];\n const breakdown = new Map<string, number>();\n\n for (const [agentId, vote] of votes) {\n if (!this.canVote(agentId)) {\n logger.warn('Agent cannot vote', { agentId, reason: 'insufficient weight or trust' });\n continue;\n }\n const weight = this.calculateWeight(agentId);\n breakdown.set(agentId, weight);\n agents.push(agentId);\n total += weight;\n const effectiveWeight = weight * vote.confidence;\n if (vote.decision === 'approve') approval += effectiveWeight;\n else if (vote.decision === 'reject') rejection += effectiveWeight;\n }\n return { approval, rejection, total, agents, breakdown };\n }\n\n private logConsensusResult(result: WeightedConsensusResult): void {\n logger.info('Weighted consensus calculated', {\n decision: result.decision,\n approval: result.weightedApproval.toFixed(3),\n rejection: result.weightedRejection.toFixed(3),\n totalWeight: result.totalWeight.toFixed(3),\n quorumReached: result.quorumReached,\n byzantineDetected: result.byzantineDetected,\n });\n }\n\n private emitWeightChange(\n agentId: string,\n prev: number,\n next: number,\n reason: 'performance_update' | 'flag_penalty' | 'recalibration'\n ): void {\n if (this.emitEvents && this.eventBus !== undefined && prev !== next) {\n emitWeightUpdated(this.eventBus, { agentId, previousWeight: prev, newWeight: next, reason });\n }\n }\n\n private emitAgentFlaggedEvent(\n agentId: string,\n reason: string,\n previousWeight: number,\n canVote: boolean\n ): void {\n if (this.emitEvents && this.eventBus !== undefined) {\n emitAgentFlagged(this.eventBus, { agentId, reason, previousWeight, canVote });\n }\n }\n\n private excludeAgent(record: MutableAgentRecord): void {\n const weightBefore = record.weight;\n record.trustScore = 0;\n record.weight = 0;\n this.emitWeightChange(record.agentId, weightBefore, 0, 'flag_penalty');\n logger.warn('Agent excluded from voting due to Byzantine behavior', {\n agentId: record.agentId,\n flags: record.byzantineFlags,\n });\n }\n\n private detectByzantinePatterns(\n votes: ReadonlyMap<string, Vote>,\n weights: Map<string, number>\n ): boolean {\n const voteArray = Array.from(votes.entries());\n if (voteArray.length < 3) return false;\n const majorityApprove = computeMajorityDirection(voteArray, weights);\n if (this.detectContrarianByzantine(voteArray, majorityApprove)) return true;\n return this.detectCollusionPattern(voteArray);\n }\n\n private detectContrarianByzantine(\n voteArray: Array<[string, Vote]>,\n majorityApprove: boolean\n ): boolean {\n const contrarianAgents: string[] = [];\n for (const [agentId, vote] of voteArray) {\n if (!isLowConfidenceContrarian(vote, majorityApprove)) continue;\n const record = this.records.get(agentId);\n if (record !== undefined && record.byzantineFlags >= 2) {\n contrarianAgents.push(agentId);\n }\n }\n if (contrarianAgents.length > 0) {\n this.emitContrarianPattern(contrarianAgents);\n return true;\n }\n return false;\n }\n\n private emitContrarianPattern(agents: string[]): void {\n if (this.emitEvents && this.eventBus !== undefined) {\n emitPatternDetected(this.eventBus, {\n patternType: 'contrarian',\n agentIds: agents,\n confidence: 0.8,\n details: `${String(agents.length)} agent(s) with Byzantine flags voting contrary to majority with low confidence`,\n });\n }\n }\n\n private detectCollusionPattern(voteArray: Array<[string, Vote]>): boolean {\n const voteSignatures = groupVotesBySignature(voteArray);\n const threshold = voteArray.length * 0.6;\n for (const [signature, agents] of voteSignatures.entries()) {\n if (agents.length >= 3 && agents.length > threshold) {\n this.emitCollusionEvents(agents, signature, voteArray.length);\n return true;\n }\n }\n return false;\n }\n\n private emitCollusionEvents(agents: string[], signature: string, totalVotes: number): void {\n if (this.emitEvents && this.eventBus !== undefined) {\n emitPatternDetected(this.eventBus, {\n patternType: 'collusion',\n agentIds: agents,\n confidence: Math.min(0.95, agents.length / totalVotes),\n details: `${String(agents.length)} agents voting identically: ${signature}`,\n });\n emitCollusionSuspected(this.eventBus, {\n groupAgentIds: agents,\n groupSize: agents.length,\n votingBlock: agents.length / totalVotes,\n threshold: 0.6,\n });\n }\n }\n}\n\n/** Create a weighted voting instance. */\nexport function createWeightedVoting(options?: WeightedVotingOptions): IWeightedVoting {\n return new WeightedVoting(options);\n}\n","/**\n * How independent a subset of agents is, and how much of it was measured.\n *\n * Its own module because the score and its coverage are one fact: the score\n * averages only the pairs present in the correlation matrix, so without the\n * coverage a subset whose pairs were MEASURED at 0 is indistinguishable from\n * one whose pairs were NEVER OBSERVED — and 0 earns the maximum posterior\n * weight in `aggregateSubsets`.\n *\n * @module consensus/subset-independence\n */\nimport type { CorrelationMatrix } from './higher-order-types.js';\nimport { createAgentPairKey } from './higher-order-types.js';\n\n/**\n * The independence score AND how much of the subset it was measured over.\n *\n * An unobserved pair counts as MAXIMALLY correlated (#5813, panel option B).\n * Before that it was dropped from the average, so a subset whose pairs were\n * MEASURED at 0 and one whose pairs were NEVER OBSERVED both scored 0 — and 0\n * earns the maximum posterior weight in `aggregateSubsets` (`size * (1 -\n * score)`). Absent evidence was credited as evidence of independence.\n *\n * The panel asked which error to optimise against and answered unanimously\n * among its approvers: over-weighting a secretly correlated bloc, not\n * under-weighting a genuinely independent voice. The first fabricates\n * independent evidence and cannot be recovered from; the second shrinks\n * monotonically as pairs are observed.\n *\n * `total` is C(n,2), so a singleton reports `{ observed: 0, total: 0 }`: no pair\n * exists to observe. It has no peer to correlate with, so there is nothing to\n * discount and it keeps full weight — an unmeasurABLE subset is not an\n * unmeasurED one. That falls out of the formula rather than needing a guard,\n * because zero total pairs means zero missing pairs to charge for.\n *\n * Equivalence worth knowing before anyone \"simplifies\" this: charging 1.0 per\n * missing pair is ALGEBRAICALLY IDENTICAL to scaling the weight by coverage,\n * `(observed/total) * (1 - score)` — the panel's options A and B were the same\n * formula. This spelling is the one that answers the singleton without a\n * 0/0 guard. Verified numerically to 8.9e-16 over 5000 random subsets.\n */\nexport function computeSubsetIndependence(\n subset: readonly string[],\n correlationMatrix: CorrelationMatrix\n): { score: number; observedPairs: number; totalPairs: number } {\n const totalPairs = (subset.length * (subset.length - 1)) / 2;\n if (subset.length < 2) return { score: 0, observedPairs: 0, totalPairs };\n\n let observedCorrelation = 0;\n let pairs = 0;\n\n for (let i = 0; i < subset.length; i++) {\n for (let j = i + 1; j < subset.length; j++) {\n const agentA = subset[i];\n const agentB = subset[j];\n if (agentA !== undefined && agentB !== undefined) {\n const pairKey = createAgentPairKey(agentA, agentB);\n const correlation = correlationMatrix.get(pairKey);\n if (correlation !== undefined) {\n observedCorrelation += Math.abs(correlation);\n pairs++;\n }\n }\n }\n }\n\n // Every unobserved pair contributes 1.0 — maximal correlation — so the\n // denominator is the pairs that EXIST, not the pairs that were seen. A\n // fully unobserved multi-agent subset scores 1 and earns weight 0: it\n // contributes nothing rather than everything.\n const unobservedPairs = totalPairs - pairs;\n return {\n score: (observedCorrelation + unobservedPairs) / totalPairs,\n observedPairs: pairs,\n totalPairs,\n };\n}\n","/**\n * nexus-agents/consensus - Correlation Helpers\n *\n * Helper functions for correlation tracking and independent subset partitioning.\n * Extracted from correlation-tracker.ts to maintain file size limits.\n *\n * @module consensus/correlation-helpers\n * (Source: Issue #339)\n */\n\nimport type {\n CorrelationMatrix,\n CorrelationCoefficient,\n IndependentSubset,\n VotingObservation,\n HigherOrderVotingConfig,\n AgentPairKey,\n} from './higher-order-types.js';\nimport { createAgentPairKey } from './higher-order-types.js';\nimport { computeSubsetIndependence } from './subset-independence.js';\n\n// ============================================================================\n// Pairwise History Types\n// ============================================================================\n\n/**\n * Internal mutable representation of pairwise history.\n */\nexport interface MutablePairwiseHistory {\n pairKey: AgentPairKey;\n jointObservations: number;\n agreements: number;\n disagreements: number;\n correlation: CorrelationCoefficient;\n lastUpdated: Date;\n}\n\n// ============================================================================\n// Vote Agreement\n// ============================================================================\n\n/**\n * Check if two observations are comparable (neither is an abstain).\n * Abstain votes should be excluded from correlation tracking.\n *\n * @param obsA - First observation\n * @param obsB - Second observation\n * @returns True if both observations have non-abstain decisions\n */\nexport function isComparable(obsA: VotingObservation, obsB: VotingObservation): boolean {\n return obsA.decision !== 'abstain' && obsB.decision !== 'abstain';\n}\n\n/**\n * Check if two votes agree.\n * Only call this after verifying isComparable() returns true.\n * Abstains are treated as neutral - neither agree nor disagree.\n *\n * @param obsA - First observation\n * @param obsB - Second observation\n * @returns True if votes agree, null if either is an abstain (neutral)\n */\nexport function votesAgree(obsA: VotingObservation, obsB: VotingObservation): boolean | null {\n if (obsA.decision === 'abstain' || obsB.decision === 'abstain') {\n return null; // Neutral — skip this pair (Issue #763)\n }\n return obsA.decision === obsB.decision;\n}\n\n/**\n * Check if a decision aligned with the outcome.\n *\n * @param decision - The voting decision\n * @param outcome - The final outcome\n * @returns True if decision aligned with outcome\n */\nexport function didAlignWithOutcome(decision: string, outcome: 'approved' | 'rejected'): boolean {\n if (decision === 'abstain') return true;\n return (\n (decision === 'approve' && outcome === 'approved') ||\n (decision === 'reject' && outcome === 'rejected')\n );\n}\n\n// ============================================================================\n// Correlation Computation\n// ============================================================================\n\n/**\n * Compute correlation coefficient from pairwise history.\n *\n * Simple correlation: (agreements - disagreements) / total\n * Range: -1 (always disagree) to +1 (always agree)\n *\n * @param history - Pairwise history\n * @returns Correlation coefficient\n */\nexport function computeCorrelationCoefficient(\n history: MutablePairwiseHistory\n): CorrelationCoefficient {\n const n = history.jointObservations;\n if (n === 0) return 0;\n\n // Map agreement/disagreement rates to [-1, 1] correlation\n // 0.5 agreement rate = 0 correlation (random)\n // 1.0 agreement rate = +1 correlation (perfect agreement)\n // 0.0 agreement rate = -1 correlation (perfect disagreement)\n const agreementRate = history.agreements / n;\n const disagreementRate = history.disagreements / n;\n\n return agreementRate - disagreementRate;\n}\n\n// ============================================================================\n// Independent Subset Partitioning\n// ============================================================================\n\n/**\n * Check if an agent is independent from all members of a subset.\n *\n * @param agent - Agent to check\n * @param subset - Existing subset members\n * @param correlationMatrix - Correlation matrix\n * @param independenceThreshold - Maximum correlation for independence\n * @returns True if agent is independent from subset\n */\nexport function isIndependentFromSubset(\n agent: string,\n subset: readonly string[],\n correlationMatrix: CorrelationMatrix,\n independenceThreshold: number\n): boolean {\n for (const member of subset) {\n const pairKey = createAgentPairKey(agent, member);\n const correlation = correlationMatrix.get(pairKey);\n\n // If we don't have data, assume independent\n if (correlation === undefined) continue;\n\n // If correlation exceeds threshold, not independent\n if (Math.abs(correlation) > independenceThreshold) {\n return false;\n }\n }\n return true;\n}\n\n/**\n * Compute the minimum observation count for pairs within a subset.\n *\n * @param subset - Agent IDs in the subset\n * @param pairwiseHistory - Map of pairwise histories\n * @returns Minimum observation count (0 if no history)\n */\nexport function computeSubsetObservationCount(\n subset: readonly string[],\n pairwiseHistory: ReadonlyMap<AgentPairKey, MutablePairwiseHistory>\n): number {\n let minObservations = Infinity;\n\n for (let i = 0; i < subset.length; i++) {\n for (let j = i + 1; j < subset.length; j++) {\n const agentA = subset[i];\n const agentB = subset[j];\n if (agentA !== undefined && agentB !== undefined) {\n const pairKey = createAgentPairKey(agentA, agentB);\n const history = pairwiseHistory.get(pairKey);\n if (history !== undefined) {\n minObservations = Math.min(minObservations, history.jointObservations);\n } else {\n minObservations = 0;\n }\n }\n }\n }\n\n return minObservations === Infinity ? 0 : minObservations;\n}\n\n/**\n * Partition agents into independent groups using greedy clustering.\n *\n * @param agents - List of agent IDs\n * @param correlationMatrix - Correlation matrix\n * @param pairwiseHistory - Map of pairwise histories\n * @param config - Higher-order voting configuration\n * @returns Array of independent subsets\n */\nexport function partitionIntoIndependentGroups(\n agents: readonly string[],\n correlationMatrix: CorrelationMatrix,\n pairwiseHistory: ReadonlyMap<AgentPairKey, MutablePairwiseHistory>,\n config: HigherOrderVotingConfig\n): IndependentSubset[] {\n if (agents.length === 0) return [];\n\n const subsets: IndependentSubset[] = [];\n const assigned = new Set<string>();\n let subsetId = 0;\n\n for (const agent of agents) {\n if (assigned.has(agent)) continue;\n\n const subset: string[] = [agent];\n assigned.add(agent);\n\n // Try to add other unassigned agents if they're independent\n for (const other of agents) {\n if (assigned.has(other)) continue;\n if (isIndependentFromSubset(other, subset, correlationMatrix, config.independenceThreshold)) {\n subset.push(other);\n assigned.add(other);\n }\n }\n\n const independence = computeSubsetIndependence(subset, correlationMatrix);\n const observationCount = computeSubsetObservationCount(subset, pairwiseHistory);\n\n subsets.push({\n id: `subset-${String(subsetId++)}`,\n agentIds: subset,\n independenceScore: independence.score,\n pairCoverage: { observed: independence.observedPairs, total: independence.totalPairs },\n observationCount,\n });\n }\n\n return subsets;\n}\n","/**\n * Model-keyed storage for pairwise correlation aggregates.\n * Extracted because adding partition lifecycle logic to correlation-tracker.ts\n * would exceed the repository's 400-line source-file limit.\n */\n\nimport type { ILogger } from '../core/logger.js';\nimport type { AgentPairKey } from './higher-order-types.js';\nimport { parseAgentPairKey } from './higher-order-types.js';\nimport {\n computeCorrelationCoefficient,\n type MutablePairwiseHistory,\n} from './correlation-helpers.js';\n\ntype ModelTuple = [string | null, string | null];\n\nfunction encodeModels(models: ModelTuple): string {\n return JSON.stringify(models);\n}\n\nfunction isModelTuple(value: unknown): value is ModelTuple {\n if (!Array.isArray(value) || value.length !== 2) return false;\n const values = value as unknown[];\n const first = values[0];\n const second = values[1];\n return (\n (first === null || typeof first === 'string') && (second === null || typeof second === 'string')\n );\n}\n\nfunction decodeModels(key: string): ModelTuple {\n const parsed = JSON.parse(key) as unknown;\n if (!isModelTuple(parsed)) throw new Error(`Invalid correlation model partition key: ${key}`);\n return parsed;\n}\n\nfunction mergeHistory(\n target: MutablePairwiseHistory,\n source: MutablePairwiseHistory\n): MutablePairwiseHistory {\n target.jointObservations += source.jointObservations;\n target.agreements += source.agreements;\n target.disagreements += source.disagreements;\n target.correlation = computeCorrelationCoefficient(target);\n if (source.lastUpdated > target.lastUpdated) target.lastUpdated = source.lastUpdated;\n return target;\n}\n\n/** Retains every model partition while projecting only the currently pinned one. */\nexport class CorrelationModelPartitions {\n private readonly histories = new Map<AgentPairKey, Map<string, MutablePairwiseHistory>>();\n private readonly currentModels = new Map<string, string>();\n\n constructor(\n private readonly maxTrackedPairs: number,\n private readonly logger: ILogger\n ) {}\n\n setCurrentPins(modelPins: ReadonlyMap<string, string>): void {\n for (const [role, newModel] of modelPins) this.setCurrentPin(role, newModel);\n }\n\n getActiveHistory(): Map<AgentPairKey, MutablePairwiseHistory> {\n const active = new Map<AgentPairKey, MutablePairwiseHistory>();\n for (const [pairKey, partitions] of this.histories) {\n const history = partitions.get(this.activePartitionKey(pairKey));\n if (history !== undefined) active.set(pairKey, history);\n }\n return active;\n }\n\n getOrCreate(pairKey: AgentPairKey, create: () => MutablePairwiseHistory): MutablePairwiseHistory {\n let partitions = this.histories.get(pairKey);\n if (partitions === undefined) {\n partitions = new Map();\n this.histories.set(pairKey, partitions);\n }\n const modelKey = this.activePartitionKey(pairKey);\n let history = partitions.get(modelKey);\n if (history === undefined) {\n history = create();\n partitions.set(modelKey, history);\n this.evictOldestIfNeeded();\n }\n return history;\n }\n\n clear(): void {\n this.histories.clear();\n this.currentModels.clear();\n }\n\n private setCurrentPin(role: string, newModel: string): void {\n const previousModel = this.currentModels.get(role);\n if (previousModel === undefined) {\n this.adoptUnkeyedHistory(role, newModel);\n this.currentModels.set(role, newModel);\n return;\n }\n if (previousModel === newModel) return;\n\n const partitionLeftSize = this.partitionSize(role);\n this.currentModels.set(role, newModel);\n const partitionEnteredSize = this.partitionSize(role);\n this.logger.info('Correlation model partition switched', {\n role,\n previousModel,\n newModel,\n partitionLeftSize,\n partitionEnteredSize,\n });\n }\n\n private activePartitionKey(pairKey: AgentPairKey): string {\n const [agentA, agentB] = parseAgentPairKey(pairKey);\n return encodeModels([\n this.currentModels.get(agentA) ?? null,\n this.currentModels.get(agentB) ?? null,\n ]);\n }\n\n private partitionSize(role: string): number {\n let size = 0;\n for (const [pairKey, partitions] of this.histories) {\n const [agentA, agentB] = parseAgentPairKey(pairKey);\n if (agentA !== role && agentB !== role) continue;\n size += partitions.get(this.activePartitionKey(pairKey))?.jointObservations ?? 0;\n }\n return size;\n }\n\n private adoptUnkeyedHistory(role: string, newModel: string): void {\n for (const [pairKey, partitions] of this.histories) {\n const [agentA, agentB] = parseAgentPairKey(pairKey);\n const index = agentA === role ? 0 : agentB === role ? 1 : undefined;\n if (index === undefined) continue;\n this.rekeyUnkeyedPartitions(partitions, index, newModel);\n }\n }\n\n private rekeyUnkeyedPartitions(\n partitions: Map<string, MutablePairwiseHistory>,\n index: 0 | 1,\n newModel: string\n ): void {\n for (const [oldKey, history] of [...partitions]) {\n const models = decodeModels(oldKey);\n if (models[index] !== null) continue;\n models[index] = newModel;\n const newKey = encodeModels(models);\n partitions.delete(oldKey);\n const existing = partitions.get(newKey);\n partitions.set(newKey, existing === undefined ? history : mergeHistory(existing, history));\n }\n }\n\n private evictOldestIfNeeded(): void {\n while (this.historyCount() > this.maxTrackedPairs) {\n const oldest = this.findOldest();\n if (oldest === undefined) return;\n const partitions = this.histories.get(oldest.pairKey);\n partitions?.delete(oldest.modelKey);\n if (partitions?.size === 0) this.histories.delete(oldest.pairKey);\n this.logger.debug('Evicted oldest pairwise history entry', {\n evictedKey: oldest.pairKey,\n reason: 'maxTrackedPairs',\n remainingPairs: this.historyCount(),\n });\n }\n }\n\n private historyCount(): number {\n let count = 0;\n for (const partitions of this.histories.values()) count += partitions.size;\n return count;\n }\n\n private findOldest(): { pairKey: AgentPairKey; modelKey: string } | undefined {\n let oldest: { pairKey: AgentPairKey; modelKey: string } | undefined;\n let oldestTime = Infinity;\n for (const [pairKey, partitions] of this.histories) {\n for (const [modelKey, history] of partitions) {\n if (history.lastUpdated.getTime() >= oldestTime) continue;\n oldest = { pairKey, modelKey };\n oldestTime = history.lastUpdated.getTime();\n }\n }\n return oldest;\n }\n}\n","/**\n * nexus-agents/consensus - Correlation Tracker\n *\n * Tracks voting history and computes pairwise correlations between agents.\n * Used by higher-order voting methods to account for agent dependencies.\n *\n * @module consensus/correlation-tracker\n * (Source: Issue #333)\n */\n\nimport { createLogger } from '../core/logger.js';\nimport { getTimeProvider, getRandomProvider } from '../core/index.js';\nimport type { Vote } from './types-core.js';\nimport type {\n ICorrelationTracker,\n CorrelationMatrix,\n CorrelationCoefficient,\n IndependentSubset,\n VotingObservation,\n HigherOrderVotingConfig,\n CorrelationTrackerStats,\n AgentPairKey,\n CorrelationRecordContext,\n} from './higher-order-types.js';\nimport { createAgentPairKey, DEFAULT_HIGHER_ORDER_CONFIG } from './higher-order-types.js';\nimport {\n type MutablePairwiseHistory,\n isComparable,\n votesAgree,\n didAlignWithOutcome,\n computeCorrelationCoefficient,\n partitionIntoIndependentGroups,\n} from './correlation-helpers.js';\nimport { CorrelationModelPartitions } from './correlation-model-partitions.js';\n\n// Re-export helper types and functions for convenience\nexport type { MutablePairwiseHistory } from './correlation-helpers.js';\nexport {\n isComparable,\n votesAgree,\n didAlignWithOutcome,\n computeCorrelationCoefficient,\n isIndependentFromSubset,\n computeSubsetObservationCount,\n partitionIntoIndependentGroups,\n} from './correlation-helpers.js';\n\nconst logger = createLogger({ component: 'correlation-tracker' });\n\n/**\n * Correlation tracker implementation.\n * Records voting history and computes pairwise agent correlations.\n *\n * Memory bounded: uses FIFO eviction when maxObservationsPerAgent or maxProposals limits reached.\n */\nexport class CorrelationTracker implements ICorrelationTracker {\n private readonly config: HigherOrderVotingConfig;\n private readonly observations: Map<string, VotingObservation[]> = new Map();\n private readonly modelPartitions;\n private readonly agentProposals: Map<string, Map<string, VotingObservation>> = new Map();\n /** Ordered list of proposal IDs for FIFO eviction */\n private readonly proposalOrder: string[] = [];\n private cachedSubsets: IndependentSubset[] | null = null;\n\n constructor(config?: Partial<HigherOrderVotingConfig>) {\n this.config = { ...DEFAULT_HIGHER_ORDER_CONFIG, ...config };\n this.modelPartitions = new CorrelationModelPartitions(this.config.maxTrackedPairs, logger);\n logger.info('CorrelationTracker initialized', {\n maxObservationsPerAgent: this.config.maxObservationsPerAgent,\n maxProposals: this.config.maxProposals,\n });\n }\n\n setCurrentModelPins(modelPins: ReadonlyMap<string, string>): void {\n this.modelPartitions.setCurrentPins(modelPins);\n this.invalidateCache();\n }\n\n recordVote(\n agentId: string,\n vote: Vote,\n outcome: 'approved' | 'rejected',\n context?: CorrelationRecordContext\n ): void {\n if (context !== undefined) this.setCurrentModelPins(context.modelPins);\n const proposalId = `proposal-${String(getTimeProvider().now())}-${getRandomProvider().random().toString(36).slice(2, 9)}`;\n const modelKey = context?.modelPins.get(agentId);\n const observedModel = context?.observedModels?.get(agentId);\n const observation: VotingObservation = {\n proposalId,\n agentId,\n decision: vote.decision,\n confidence: vote.confidence,\n alignedWithOutcome: didAlignWithOutcome(vote.decision, outcome),\n timestamp: new Date(getTimeProvider().now()),\n ...(modelKey !== undefined ? { modelKey } : {}),\n ...(observedModel !== undefined ? { observedModel } : {}),\n };\n this.storeObservation(agentId, observation);\n this.invalidateCache();\n }\n\n recordProposalVotes(\n proposalId: string,\n votes: ReadonlyMap<string, Vote>,\n outcome: 'approved' | 'rejected',\n context?: CorrelationRecordContext\n ): void {\n if (context !== undefined) this.setCurrentModelPins(context.modelPins);\n // FIFO eviction when proposal limit reached (Issue #521)\n this.evictOldProposalsIfNeeded();\n\n const proposalObservations: VotingObservation[] = [];\n\n for (const [agentId, vote] of votes) {\n const modelKey = context?.modelPins.get(agentId);\n const observedModel = context?.observedModels?.get(agentId);\n const observation: VotingObservation = {\n proposalId,\n agentId,\n decision: vote.decision,\n confidence: vote.confidence,\n alignedWithOutcome: didAlignWithOutcome(vote.decision, outcome),\n timestamp: new Date(getTimeProvider().now()),\n ...(modelKey !== undefined ? { modelKey } : {}),\n ...(observedModel !== undefined ? { observedModel } : {}),\n };\n this.storeObservation(agentId, observation);\n this.storeAgentProposal(agentId, proposalId, observation);\n proposalObservations.push(observation);\n }\n\n // Track proposal order for FIFO eviction\n this.proposalOrder.push(proposalId);\n\n this.updatePairwiseCorrelations(proposalObservations);\n this.invalidateCache();\n\n logger.debug('Recorded proposal votes', {\n proposalId,\n agentCount: votes.size,\n outcome,\n totalProposals: this.proposalOrder.length,\n });\n }\n\n computeCorrelationMatrix(): CorrelationMatrix {\n const matrix: CorrelationMatrix = new Map();\n\n for (const [pairKey, history] of this.getActivePairwiseHistory()) {\n if (history.jointObservations >= this.config.minObservationsForCorrelation) {\n matrix.set(pairKey, history.correlation);\n }\n }\n\n return matrix;\n }\n\n getCorrelation(agentA: string, agentB: string): CorrelationCoefficient | undefined {\n const pairKey = createAgentPairKey(agentA, agentB);\n const history = this.getActivePairwiseHistory().get(pairKey);\n\n if (history === undefined) return undefined;\n if (history.jointObservations < this.config.minObservationsForCorrelation) return undefined;\n\n return history.correlation;\n }\n\n identifyIndependentSubsets(): readonly IndependentSubset[] {\n if (this.cachedSubsets !== null) return this.cachedSubsets;\n\n const agents = this.getTrackedAgents();\n if (agents.length === 0) {\n this.cachedSubsets = [];\n return this.cachedSubsets;\n }\n\n const correlationMatrix = this.computeCorrelationMatrix();\n const activeHistory = this.getActivePairwiseHistory();\n const subsets = partitionIntoIndependentGroups(\n agents,\n correlationMatrix,\n activeHistory,\n this.config\n );\n\n this.cachedSubsets = subsets;\n logger.debug('Identified independent subsets', {\n agentCount: agents.length,\n subsetCount: subsets.length,\n });\n\n return subsets;\n }\n\n hasSufficientData(agentIds: readonly string[]): boolean {\n if (agentIds.length < 2) return false;\n\n let pairsWithData = 0;\n const totalPairs = (agentIds.length * (agentIds.length - 1)) / 2;\n const activeHistory = this.getActivePairwiseHistory();\n\n for (let i = 0; i < agentIds.length; i++) {\n for (let j = i + 1; j < agentIds.length; j++) {\n const agentA = agentIds[i];\n const agentB = agentIds[j];\n if (agentA !== undefined && agentB !== undefined) {\n const pairKey = createAgentPairKey(agentA, agentB);\n const history = activeHistory.get(pairKey);\n if (\n history !== undefined &&\n history.jointObservations >= this.config.minObservationsForCorrelation\n ) {\n pairsWithData++;\n }\n }\n }\n }\n\n // Require at least 50% of pairs to have sufficient data\n return pairsWithData >= totalPairs * 0.5;\n }\n\n getStats(): CorrelationTrackerStats {\n const agents = this.getTrackedAgents();\n // Used by callers to understand full correlation state\n void this.computeCorrelationMatrix();\n const subsets = this.identifyIndependentSubsets();\n\n let totalCorrelation = 0;\n let pairsWithSufficientData = 0;\n const activeHistory = this.getActivePairwiseHistory();\n\n for (const [, history] of activeHistory) {\n if (history.jointObservations >= this.config.minObservationsForCorrelation) {\n totalCorrelation += history.correlation;\n pairsWithSufficientData++;\n }\n }\n\n let totalObservations = 0;\n for (const obs of this.observations.values()) {\n totalObservations += obs.length;\n }\n\n return {\n totalAgents: agents.length,\n trackedPairs: activeHistory.size,\n totalObservations,\n averageCorrelation:\n pairsWithSufficientData > 0 ? totalCorrelation / pairsWithSufficientData : 0,\n independentSubsetCount: subsets.length,\n pairsWithSufficientData,\n };\n }\n\n clear(): void {\n this.observations.clear();\n this.modelPartitions.clear();\n this.agentProposals.clear();\n this.proposalOrder.length = 0;\n this.cachedSubsets = null;\n logger.info('CorrelationTracker cleared');\n }\n\n // ============================================================================\n // Private helpers\n // ============================================================================\n\n /**\n * Evict oldest proposals when maxProposals limit is reached.\n * Also cleans up agentProposals entries for evicted proposals.\n */\n private evictOldProposalsIfNeeded(): void {\n while (this.proposalOrder.length >= this.config.maxProposals) {\n const evictedProposalId = this.proposalOrder.shift();\n if (evictedProposalId === undefined) break;\n\n // Clean up agentProposals for the evicted proposal\n for (const [agentId, proposalMap] of this.agentProposals) {\n if (proposalMap.has(evictedProposalId)) {\n proposalMap.delete(evictedProposalId);\n // Clean up empty agent entries\n if (proposalMap.size === 0) {\n this.agentProposals.delete(agentId);\n }\n }\n }\n\n logger.debug('Evicted oldest proposal', {\n evictedProposalId,\n reason: 'maxProposals',\n remainingProposals: this.proposalOrder.length,\n });\n }\n }\n\n private storeObservation(agentId: string, observation: VotingObservation): void {\n let agentObs = this.observations.get(agentId);\n if (agentObs === undefined) {\n agentObs = [];\n this.observations.set(agentId, agentObs);\n }\n\n // FIFO eviction when per-agent limit reached (Issue #521)\n while (agentObs.length >= this.config.maxObservationsPerAgent) {\n const evicted = agentObs.shift();\n if (evicted !== undefined) {\n logger.debug('Evicted oldest observation for agent', {\n agentId,\n evictedProposalId: evicted.proposalId,\n reason: 'maxObservationsPerAgent',\n });\n }\n }\n\n agentObs.push(observation);\n }\n\n private storeAgentProposal(\n agentId: string,\n proposalId: string,\n observation: VotingObservation\n ): void {\n let agentProposalMap = this.agentProposals.get(agentId);\n if (agentProposalMap === undefined) {\n agentProposalMap = new Map();\n this.agentProposals.set(agentId, agentProposalMap);\n }\n agentProposalMap.set(proposalId, observation);\n }\n\n private updatePairwiseCorrelations(observations: VotingObservation[]): void {\n for (let i = 0; i < observations.length; i++) {\n for (let j = i + 1; j < observations.length; j++) {\n const obsA = observations[i];\n const obsB = observations[j];\n if (obsA === undefined || obsB === undefined) continue;\n\n const pairKey = createAgentPairKey(obsA.agentId, obsB.agentId);\n const history = this.modelPartitions.getOrCreate(pairKey, () => {\n return {\n pairKey,\n jointObservations: 0,\n agreements: 0,\n disagreements: 0,\n correlation: 0,\n lastUpdated: new Date(getTimeProvider().now()),\n };\n });\n\n // Skip abstain observations — they are neutral (Issue #763)\n if (!isComparable(obsA, obsB)) continue;\n\n history.jointObservations++;\n const agreed = votesAgree(obsA, obsB);\n if (agreed === true) {\n history.agreements++;\n } else {\n history.disagreements++;\n }\n\n history.correlation = computeCorrelationCoefficient(history);\n history.lastUpdated = new Date(getTimeProvider().now());\n }\n }\n }\n\n private getTrackedAgents(): string[] {\n return Array.from(this.observations.keys());\n }\n\n private getActivePairwiseHistory(): Map<AgentPairKey, MutablePairwiseHistory> {\n return this.modelPartitions.getActiveHistory();\n }\n\n private invalidateCache(): void {\n this.cachedSubsets = null;\n }\n}\n\n/**\n * Creates a new correlation tracker instance.\n */\nexport function createCorrelationTracker(\n config?: Partial<HigherOrderVotingConfig>\n): ICorrelationTracker {\n return new CorrelationTracker(config);\n}\n","/**\n * nexus-agents/consensus - Correlation Persistence\n *\n * Disk persistence for CorrelationTracker voting history. Enables Higher-Order\n * Voting (HOV) to accumulate correlation data across process restarts,\n * activating Bayesian correlation awareness.\n *\n * Storage: append-only JSONL at `~/.nexus-agents/voting/correlations.jsonl`\n * (mode 0o600). Each line is one `PersistedProposal`. Append-only avoids the\n * cross-process read-merge-rename race the previous `correlations.json`\n * design had (#2973): two processes voting concurrently each loaded N\n * entries, each merged their own proposal, each renamed over the same file,\n * losing the loser's proposal. Append guarantees atomic-per-line writes on\n * POSIX so concurrent writers are race-free.\n *\n * Reads dedupe by `proposalId` (last write wins) and apply FIFO eviction\n * past `maxProposals`. A legacy `correlations.json` is read alongside the\n * JSONL on every load (its entries are surfaced like any other history) and\n * is left in place: nothing consolidates or removes it (the compaction\n * routine #2992 shipped for that was never called and was deleted in #6425).\n * New writes always go to the JSONL.\n *\n * @module consensus/correlation-persistence\n * (Source: Issue #514; #2973 for the JSONL switch)\n */\n\nimport * as fs from 'node:fs';\nimport { nexusDataPath } from '../config/nexus-data-dir.js';\nimport type { Result } from '../core/result.js';\nimport { ok, err } from '../core/result.js';\nimport type { ILogger } from '../core/logger.js';\nimport { createLogger } from '../core/logger.js';\nimport type { ICorrelationTracker, HigherOrderVotingConfig } from './higher-order-types.js';\nimport { DEFAULT_HIGHER_ORDER_CONFIG } from './higher-order-types.js';\nimport { createCorrelationTracker } from './correlation-tracker.js';\nimport {\n PersistedCorrelationDataSchema,\n PersistedProposalSchema,\n replayProposals,\n type PersistedCorrelationData,\n type PersistedProposal,\n} from './correlation-persistence-records.js';\n\nexport {\n createPersistedProposal,\n PersistedCorrelationDataSchema,\n type PersistedCorrelationData,\n} from './correlation-persistence-records.js';\n\nconst logger: ILogger = createLogger({ component: 'correlation-persistence' });\n\n/** Subdirectory name under the resolved nexus data dir for voting data. */\nconst VOTING_SUBDIR = 'voting';\n\n/** Legacy single-JSON file (pre-#2973). Still read on load; never written. */\nconst CORRELATIONS_FILE = 'correlations.json';\n\n/** Active append-only JSONL store (#2973). */\nconst CORRELATIONS_JSONL_FILE = 'correlations.jsonl';\n\n/** File permissions: user read/write only */\nconst FILE_MODE = 0o600;\n\n/** Directory permissions: user read/write/execute only */\nconst DIR_MODE = 0o700;\n\n/** Schema version 3 adds optional pinned and observed model provenance. */\nconst SCHEMA_VERSION = 3;\n\n// ============================================================================\n// Path Helpers\n// ============================================================================\n\n/**\n * Returns the absolute path to the **legacy** correlation data file. Kept\n * for back-compat — new writes go through `getCorrelationJsonlPath()`.\n */\nexport function getCorrelationDataPath(): string {\n return nexusDataPath(VOTING_SUBDIR, CORRELATIONS_FILE);\n}\n\n/** Returns the absolute path to the active JSONL store (#2973). */\nexport function getCorrelationJsonlPath(): string {\n return nexusDataPath(VOTING_SUBDIR, CORRELATIONS_JSONL_FILE);\n}\n\n/**\n * Ensures the voting data directory exists with appropriate permissions.\n */\nfunction ensureVotingDirectory(): Result<void, Error> {\n const dirPath = nexusDataPath(VOTING_SUBDIR);\n try {\n fs.mkdirSync(dirPath, { recursive: true, mode: DIR_MODE });\n return ok(undefined);\n } catch (cause: unknown) {\n const error = cause instanceof Error ? cause : new Error(String(cause));\n return err(new Error(`Failed to create voting directory at ${dirPath}: ${error.message}`));\n }\n}\n\n// ============================================================================\n// Save (append-only, race-free across processes)\n// ============================================================================\n\n/**\n * Appends new proposals to the JSONL store. One line per proposal.\n *\n * POSIX `O_APPEND` (used implicitly by `appendFileSync` with `{flag: 'a'}`)\n * guarantees atomic writes for buffer sizes under `PIPE_BUF` (4 KB on Linux,\n * 512 B on macOS). Each line we write is a single `PersistedProposal` — well\n * under those limits in practice for the typical vote-panel size (3–7 voters).\n * Two processes calling this concurrently get all proposals persisted; no\n * read-merge-rename race possible because we never read or rename.\n *\n * @param proposals - Array of proposals with their votes and outcomes to persist\n * @param _config - Higher-order voting config (only `maxProposals` is consulted\n * on read; this writer is fully append-only)\n * @returns Result indicating success or failure\n */\nexport function saveCorrelationData(\n proposals: PersistedProposal[],\n // config kept in the signature for ABI compatibility with the legacy\n // implementation; the JSONL writer is append-only so we don't need it here.\n // FIFO truncation happens on read.\n _config: HigherOrderVotingConfig = DEFAULT_HIGHER_ORDER_CONFIG\n): Result<void, Error> {\n const dirResult = ensureVotingDirectory();\n if (!dirResult.ok) return dirResult;\n\n if (proposals.length === 0) return ok(undefined);\n\n const filePath = getCorrelationJsonlPath();\n\n try {\n const lines = proposals.map((p) => JSON.stringify(p)).join('\\n') + '\\n';\n fs.appendFileSync(filePath, lines, { encoding: 'utf-8', mode: FILE_MODE });\n\n logger.info('Correlation proposals appended', {\n path: filePath,\n proposalCount: proposals.length,\n });\n\n return ok(undefined);\n } catch (cause: unknown) {\n const error = cause instanceof Error ? cause : new Error(String(cause));\n return err(new Error(`Failed to append correlation data: ${error.message}`));\n }\n}\n\n// ============================================================================\n// Load (consolidates JSONL + legacy JSON, dedupes by proposalId, FIFO-truncates)\n// ============================================================================\n\n/** Read the legacy `correlations.json` if present; return [] otherwise. */\nfunction loadLegacyJsonProposals(): PersistedProposal[] {\n const filePath = getCorrelationDataPath();\n if (!fs.existsSync(filePath)) return [];\n\n let rawContent: string;\n try {\n rawContent = fs.readFileSync(filePath, { encoding: 'utf-8' });\n } catch (cause: unknown) {\n logger.warn('Failed to read legacy correlations.json', {\n path: filePath,\n error: cause instanceof Error ? cause.message : String(cause),\n });\n return [];\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(rawContent);\n } catch (cause: unknown) {\n logger.warn('Corrupt legacy correlations.json — skipping', {\n path: filePath,\n error: cause instanceof Error ? cause.message : String(cause),\n });\n return [];\n }\n\n const result = PersistedCorrelationDataSchema.safeParse(parsed);\n if (!result.success) {\n logger.warn('Invalid legacy correlations.json schema — skipping', {\n path: filePath,\n error: result.error.message,\n });\n return [];\n }\n return result.data.proposals;\n}\n\ntype LineResult = { kind: 'ok'; proposal: PersistedProposal } | { kind: 'skip'; reason: string };\n\n/** Parse one JSONL line into a typed result so the loader can stay below max-complexity. */\nfunction parseJsonlLine(line: string): LineResult {\n let parsed: unknown;\n try {\n parsed = JSON.parse(line);\n } catch (cause: unknown) {\n return {\n kind: 'skip',\n reason: `JSON.parse: ${cause instanceof Error ? cause.message : String(cause)}`,\n };\n }\n const result = PersistedProposalSchema.safeParse(parsed);\n if (!result.success) return { kind: 'skip', reason: `schema: ${result.error.message}` };\n return { kind: 'ok', proposal: result.data };\n}\n\n/** Read JSONL store, dropping malformed lines with a warn log. */\nfunction loadJsonlProposals(): PersistedProposal[] {\n const filePath = getCorrelationJsonlPath();\n if (!fs.existsSync(filePath)) return [];\n\n let content: string;\n try {\n content = fs.readFileSync(filePath, { encoding: 'utf-8' });\n } catch (cause: unknown) {\n logger.warn('Failed to read correlations.jsonl', {\n path: filePath,\n error: cause instanceof Error ? cause.message : String(cause),\n });\n return [];\n }\n\n const lines = content.split('\\n').filter((line) => line.trim() !== '');\n const proposals: PersistedProposal[] = [];\n let skippedCount = 0;\n let firstSkipReason: string | undefined;\n\n for (const line of lines) {\n const result = parseJsonlLine(line);\n if (result.kind === 'ok') {\n proposals.push(result.proposal);\n } else {\n skippedCount++;\n firstSkipReason ??= result.reason;\n }\n }\n\n if (skippedCount > 0) {\n logger.warn('Skipped malformed lines in correlations.jsonl', {\n path: filePath,\n skippedCount,\n totalLines: lines.length,\n firstSkipReason,\n });\n }\n\n return proposals;\n}\n\n/**\n * Combines proposals from both stores, dedupes by proposalId (later wins),\n * sorts by timestamp ascending, and FIFO-truncates to `maxProposals`.\n */\nfunction consolidate(\n legacyProposals: PersistedProposal[],\n jsonlProposals: PersistedProposal[],\n maxProposals: number\n): PersistedProposal[] {\n const proposalMap = new Map<string, PersistedProposal>();\n // Legacy first, then JSONL — JSONL entries override legacy if same id.\n for (const p of legacyProposals) proposalMap.set(p.proposalId, p);\n for (const p of jsonlProposals) proposalMap.set(p.proposalId, p);\n\n const all = Array.from(proposalMap.values()).sort((a, b) =>\n a.timestamp.localeCompare(b.timestamp)\n );\n return all.length > maxProposals ? all.slice(all.length - maxProposals) : all;\n}\n\n/**\n * Loads and validates correlation data from disk. Combines the JSONL store\n * with the legacy `correlations.json` (if present). Always returns an Ok\n * result when the directory exists; an empty proposals array means \"no\n * persisted history\".\n *\n * Returns an `err` when NEITHER the jsonl nor the legacy file exists — the\n * first-run case. An earlier revision of this comment said that error had been\n * removed; it had not, and a caller that skipped the branch hit it on first run.\n */\nexport function loadCorrelationData(\n config: HigherOrderVotingConfig = DEFAULT_HIGHER_ORDER_CONFIG\n): Result<PersistedCorrelationData, Error> {\n const jsonlPath = getCorrelationJsonlPath();\n const legacyPath = getCorrelationDataPath();\n const jsonlExists = fs.existsSync(jsonlPath);\n const legacyExists = fs.existsSync(legacyPath);\n\n if (!jsonlExists && !legacyExists) {\n return err(new Error(`Correlation data file not found: ${jsonlPath}`));\n }\n\n const legacy = loadLegacyJsonProposals();\n const jsonl = loadJsonlProposals();\n const proposals = consolidate(legacy, jsonl, config.maxProposals);\n\n logger.info('Correlation data loaded', {\n legacyCount: legacy.length,\n jsonlCount: jsonl.length,\n afterDedup: proposals.length,\n });\n\n return ok({\n version: SCHEMA_VERSION,\n proposals,\n savedAt: new Date().toISOString(),\n });\n}\n\n/**\n * Creates a correlation tracker pre-loaded with persisted history.\n *\n * On first run (no persisted data), returns a fresh tracker.\n * On subsequent runs, replays all stored proposals through the\n * tracker's public API to reconstruct correlation state.\n *\n * This enables Higher-Order Voting to accumulate enough history\n * across process restarts to activate Bayesian correlation awareness.\n *\n * @param config - Optional partial higher-order voting config\n * @returns A correlation tracker with any persisted history replayed\n */\nexport function createPersistentCorrelationTracker(\n config?: Partial<HigherOrderVotingConfig>\n): ICorrelationTracker {\n const tracker = createCorrelationTracker(config);\n\n const mergedConfig = { ...DEFAULT_HIGHER_ORDER_CONFIG, ...config };\n const loadResult = loadCorrelationData(mergedConfig);\n if (!loadResult.ok) {\n logger.info('Starting with fresh correlation tracker', {\n reason: loadResult.error.message,\n });\n return tracker;\n }\n\n const replayedCount = replayProposals(tracker, loadResult.value.proposals);\n\n logger.info('Correlation tracker restored from persistence', {\n replayedProposals: replayedCount,\n stats: tracker.getStats(),\n });\n\n return tracker;\n}\n","/** Schemas and replay helpers for persisted correlation proposal records. */\n\nimport { z } from 'zod';\nimport type { CorrelationRecordContext, ICorrelationTracker } from './higher-order-types.js';\nimport type { Vote } from './types-core.js';\n\nconst PersistedVoteSchema = z.object({\n agentId: z.string(),\n decision: z.enum(['approve', 'reject', 'abstain']),\n confidence: z.number().min(0).max(1),\n modelKey: z.string().optional(),\n observedModel: z.string().optional(),\n});\n\ntype PersistedVote = z.infer<typeof PersistedVoteSchema>;\n\nexport const PersistedProposalSchema = z.object({\n proposalId: z.string(),\n votes: z.array(PersistedVoteSchema),\n outcome: z.enum(['approved', 'rejected']),\n timestamp: z.iso.datetime(),\n});\n\nexport type PersistedProposal = z.infer<typeof PersistedProposalSchema>;\n\nexport const PersistedCorrelationDataSchema = z.object({\n version: z.number().int().positive(),\n proposals: z.array(PersistedProposalSchema),\n savedAt: z.iso.datetime(),\n});\n\nexport type PersistedCorrelationData = z.infer<typeof PersistedCorrelationDataSchema>;\n\n/** Build one replayable record without conflating assigned and observed models. */\nexport function createPersistedProposal(\n proposalId: string,\n votes: ReadonlyMap<string, Vote>,\n outcome: 'approved' | 'rejected',\n context?: CorrelationRecordContext\n): PersistedProposal {\n const persistedVotes: PersistedVote[] = [];\n for (const [agentId, vote] of votes) {\n const modelKey = context?.modelPins.get(agentId);\n const observedModel = context?.observedModels?.get(agentId);\n persistedVotes.push({\n agentId,\n decision: vote.decision,\n confidence: vote.confidence,\n ...(modelKey !== undefined ? { modelKey } : {}),\n ...(observedModel !== undefined ? { observedModel } : {}),\n });\n }\n return {\n proposalId,\n votes: persistedVotes,\n outcome,\n timestamp: new Date().toISOString(),\n };\n}\n\nfunction findReplayModelPins(proposals: readonly PersistedProposal[]): {\n first: ReadonlyMap<string, string>;\n latest: ReadonlyMap<string, string>;\n} {\n const firstModelPins = new Map<string, string>();\n const latestModelPins = new Map<string, string>();\n for (const proposal of proposals) {\n for (const vote of proposal.votes) {\n if (vote.modelKey !== undefined && !firstModelPins.has(vote.agentId)) {\n firstModelPins.set(vote.agentId, vote.modelKey);\n }\n if (vote.modelKey !== undefined) latestModelPins.set(vote.agentId, vote.modelKey);\n }\n }\n return { first: firstModelPins, latest: latestModelPins };\n}\n\nfunction buildReplayContext(\n votes: readonly PersistedVote[],\n firstModelPins: ReadonlyMap<string, string>\n): CorrelationRecordContext {\n const modelPins = new Map<string, string>();\n const observedModels = new Map<string, string>();\n for (const vote of votes) {\n const modelKey = vote.modelKey ?? firstModelPins.get(vote.agentId);\n if (modelKey !== undefined) modelPins.set(vote.agentId, modelKey);\n if (vote.observedModel !== undefined) observedModels.set(vote.agentId, vote.observedModel);\n }\n return { modelPins, observedModels };\n}\n\n/** Replay persisted records through the tracker's public recording contract. */\nexport function replayProposals(\n tracker: ICorrelationTracker,\n proposals: readonly PersistedProposal[]\n): number {\n const replayPins = findReplayModelPins(proposals);\n for (const proposal of proposals) {\n const votes = new Map<string, Vote>();\n for (const vote of proposal.votes) {\n votes.set(vote.agentId, {\n decision: vote.decision,\n reasoning: 'replayed from persistence',\n confidence: vote.confidence,\n });\n }\n tracker.recordProposalVotes(\n proposal.proposalId,\n votes,\n proposal.outcome,\n buildReplayContext(proposal.votes, replayPins.first)\n );\n }\n tracker.setCurrentModelPins?.(replayPins.latest);\n return proposals.length;\n}\n","/**\n * Types, schemas, and response helpers for the consensus_vote MCP tool.\n * Extracted from consensus-vote.ts for file size compliance (Issue #708).\n *\n * @module mcp/tools/consensus-vote-types\n */\n\n/* eslint-disable max-lines --\n * #4701: this file sat exactly at the 400-line cap, so adding\n * `HigherOrderMetadata.appliedToDecision` (a field plus its assignment) puts it\n * one over. Taking the exemption rather than splitting an 18-export types\n * module inside a two-line governance-fidelity fix. Second file this session to\n * hit the cap this way — see #4702 for the same situation in `audit-logger.ts`.\n * Do not keep adding here; split it.\n */\n\nimport { z } from 'zod';\nimport {\n DEPRECATED_MODE_ALIAS_INPUT,\n refineDispatchModeAgreement,\n} from './async-dispatch-input.js';\nimport type {\n AgentVoteResult,\n RetriedFrom,\n SeatFallback,\n VotingResult,\n} from '../../cli/vote-types.js';\nimport {\n panelDiversityOf,\n singleFamilyPanelWarning,\n singleModelPanelWarning,\n type PanelDiversity,\n} from '../../cli/vote-diversity.js';\nimport { VOTER_ROLES } from '../../cli/vote-types.js';\nimport {\n resolveVoterProject,\n VoterProjectInputSchema,\n type ResolvedVoterProject,\n} from '../../cli/voter-project.js';\nimport type { HigherOrderVotingResult } from '../../consensus/higher-order-types.js';\nimport type { OptionGateVerdict } from './consensus-vote-option-gate.js';\nimport type { DecisionCostSummary } from '../../observability/decision-cost.js';\nimport type { VoteRecordPersistOutcome } from './consensus-vote-recording.js';\nimport { VoteRecordPrBindingSchema } from '../../audit/vote-record.js';\nimport {\n SUPERMAJORITY_THRESHOLD,\n VOTING_THRESHOLDS,\n type ConsensusAlgorithm,\n} from '../../consensus/types-core.js';\nimport { checkUndeclaredOptions } from './consensus-vote-option-detection.js';\nimport { resolveVoteDecision } from '../../consensus/decision/verdict.js';\nimport { UNRESOLVED_MODEL_ID } from '../../config/model-equivalence.js';\n\n/** Maximum proposal length (memory bounds per Issue #435). */\nexport const MAX_PROPOSAL_LENGTH = 4000;\n\n// ============================================================================\n// Strategy Types\n// ============================================================================\n\n/**\n * Available consensus voting strategies.\n *\n * - `simple_majority`: Standard majority voting (>50%)\n * - `supermajority`: Requires >=67% approval\n * - `unanimous`: Requires 100% approval\n * - `proof_of_learning`: Weighted by agent performance (Issue #103). NOTE: weights come from\n * recorded voter history, and nothing writes that history today (#5234), so in practice this\n * currently behaves as simple_majority. The outcome reports `weightBasis: 'unweighted'` when\n * that is the case (#5117) rather than claiming a weighting that did not happen.\n * - `higher_order`: plain approve/reject tally at a 0.5 bar; its correlation\n * posterior drives contrarian escalation only, not the verdict (#4701, #514)\n * - `opinion_wise`: Alias for higher_order (Issue #333)\n */\nexport type VotingStrategy =\n | 'simple_majority'\n | 'supermajority'\n | 'unanimous'\n | 'proof_of_learning'\n | 'higher_order'\n | 'opinion_wise';\n\nexport const VotingStrategySchema = z.enum([\n 'simple_majority',\n 'supermajority',\n 'unanimous',\n 'proof_of_learning',\n 'higher_order',\n 'opinion_wise',\n]);\n\n/**\n * Whether a strategy takes the higher-order path (correlation analysis for\n * contrarian escalation; the verdict itself is a plain tally, #4701).\n * `opinion_wise` is a documented alias of `higher_order` (#333), so both must\n * take the higher-order path — gating on the literal `'higher_order'` silently\n * dropped opinion_wise to the plain engine with no higherOrderMetadata (#3271).\n */\nexport function isHigherOrderStrategy(strategy: VotingStrategy): boolean {\n return strategy === 'higher_order' || strategy === 'opinion_wise';\n}\n\n/**\n * Posterior-approval floor below which a `higher_order` quickMode *approval* is\n * escalated to the full voter panel (#3174). For Bayesian aggregation the\n * posterior is a first-class confidence signal: an approval whose posterior sits\n * near 0.5 means the 3-voter quick panel was barely decisive, which is exactly\n * the case where the extra voters are worth their cost. Mirrors the bare-constant\n * style of `CONTRARIAN_ESCALATION_THRESHOLD`. Set above any real posterior to\n * always escalate, or — since the gate also requires `posterior < floor` — a\n * floor of `0` disables posterior-based escalation entirely.\n */\nexport const HIGHER_ORDER_ESCALATION_POSTERIOR_FLOOR = 0.65;\n\n/**\n * Whether a quickMode approval should escalate to the full panel purely on a\n * borderline Bayesian posterior (#3174). Independent of the contrarian-agent\n * check — this catches low-confidence higher_order approvals that a clean\n * outcome string hides. Only fires for higher_order/opinion_wise (the strategies\n * with a meaningful posterior), on approvals, in quickMode, when the posterior\n * is known and below the floor.\n */\nexport function shouldEscalateLowPosterior(\n strategy: VotingStrategy,\n outcome: 'approved' | 'rejected',\n quickMode: boolean,\n posteriorApproval: number | undefined\n): boolean {\n return (\n quickMode &&\n outcome === 'approved' &&\n isHigherOrderStrategy(strategy) &&\n posteriorApproval !== undefined &&\n posteriorApproval < HIGHER_ORDER_ESCALATION_POSTERIOR_FLOOR\n );\n}\n\n// ============================================================================\n// Input / Output Schemas\n// ============================================================================\n\n/**\n * How error-source votes (timed-out or crashed voters) are counted toward\n * the threshold (#2630).\n *\n * - `reduce_denominator` (default for non-strict strategies): errors are\n * filtered out before the engine sees votes — denominator = non-error\n * votes. Best for operational decisions where you trust the responding\n * voters and infrastructure flake should not block the vote.\n * - `count_as_abstain`: error votes reach the engine as abstain. Behaves\n * conservatively — a timed-out voter effectively withholds approval\n * relative to the threshold. Use when you can't tell what the error\n * voter would have decided and want the math to reflect uncertainty.\n * - `fail_closed` (default for unanimous / higher_order): any error voids\n * the vote. Threshold math is not run. Use for security-critical or\n * breaking-change decisions where every voter must be heard.\n * - `absolute_quorum` (opt-in, #4132): an errored voter DEGRADES the panel\n * verdict to `no_quorum` instead of being silently dropped from the\n * denominator. Unlike `fail_closed` (which reports a rejection-flavored void),\n * `absolute_quorum` reports `no_quorum` — a recoverable \"re-run the missing\n * voice\" state that never manufactures `approved` NOR `rejected` from an\n * induced error. An approval requires ZERO errors, the contrarian (catfish)\n * present and non-error (unless quick-mode drops it), and an ABSOLUTE approval\n * count (`ceil(fraction * panelSize)` over the full requested panel — not just\n * a majority of the responders). A genuine reject (zero errors) still blocks.\n * The anti-DoS point: a voter you can knock offline can only ever force a\n * re-run, never flip the verdict.\n *\n * Regardless of policy, a hard floor applies: when errors exceed 50% of\n * total voters, the vote always fails. Catches \"all CLIs are down\" — a\n * 2-voter consensus is not a real consensus.\n */\nexport const ErrorPolicySchema = z.enum([\n 'reduce_denominator',\n 'count_as_abstain',\n 'fail_closed',\n 'absolute_quorum',\n]);\n\nexport type ErrorPolicy = z.infer<typeof ErrorPolicySchema>;\n\n/**\n * Threshold values accepted by the `--threshold` CLI flag and the\n * \\`threshold\\` MCP input field (#2638 — single source of truth).\n *\n * Maps to consensus algorithms via:\n * `majority → simple_majority`, `supermajority → supermajority`, `unanimous → unanimous`.\n *\n * Used as the canonical Zod schema for CLI parsing\n * (`cli.ts:parseThreshold`), validation (`cli-commands-validators.ts:isValidThreshold`),\n * and the `ConsensusVoteInputSchema.threshold` field.\n */\nexport const VoteThresholdSchema = z.enum(['majority', 'supermajority', 'unanimous']);\n\nexport type VoteThreshold = z.infer<typeof VoteThresholdSchema>;\n\n/**\n * `ERROR_FLOOR_FRACTION` moved to `consensus/decision/thresholds.ts` and\n * `getDefaultErrorPolicy` to `consensus/decision/strategy.ts` (#6000 step 1),\n * so the hard floor and the per-strategy policy default can be governed on\n * their own path. Re-exported here so every existing import keeps resolving.\n */\nexport { ERROR_FLOOR_FRACTION } from '../../consensus/decision/thresholds.js';\nexport { getDefaultErrorPolicy } from '../../consensus/decision/strategy.js';\n\nexport const ConsensusVoteInputSchema = z\n .object({\n proposal: z\n .string()\n .min(1)\n .max(MAX_PROPOSAL_LENGTH)\n .describe(\n 'Proposal text to vote on. If the proposal asks voters to choose among named ' +\n 'alternatives, declare them in `options` (#4472) — otherwise the tally records ' +\n 'approve/reject/abstain only, so every voter who engages returns `approve` and a 6-1 ' +\n 'split on WHICH option persists as 7-0, 100% (#4452). This is ENFORCED AS A WARNING, ' +\n 'not a refusal: a heuristic over the proposal text flags an apparent multi-option ' +\n 'proposal with no `options` and says so on `panelWarning` (#5360). The wording says ' +\n '\"declare\", not \"MUST\", because the warning is what the code actually holds — it is ' +\n 'tightened back only in the same change that promotes the warning to a refusal.'\n ),\n options: z\n .array(z.string().min(1).max(200))\n .min(2)\n .max(10)\n .optional()\n .describe(\n 'Named alternatives for a multi-option proposal (#4472). When present, the threshold must ' +\n 'ALSO be cleared by the leading option, in addition to the ordinary approve/reject bar: ' +\n '`unanimous` requires every approver to have chosen the SAME option, and ' +\n \"`supermajority`/`majority` measure the leading option's share of approvers. An \" +\n 'approving voter whose selection is absent or matches no declared option stays in the ' +\n 'denominator and credits no option, so a degraded response can only lower the leading ' +\n 'share, never raise it. Omit for an ordinary yes/no vote — behaviour is then unchanged.'\n ),\n project: VoterProjectInputSchema,\n threshold: VoteThresholdSchema.optional().describe(\n 'Voting threshold (legacy): majority, supermajority, unanimous. Use strategy instead.'\n ),\n strategy: VotingStrategySchema.optional().describe(\n 'Voting strategy: simple_majority (default), supermajority, unanimous, proof_of_learning, or higher_order (a plain majority tally whose correlation analysis only triggers contrarian escalation). ' +\n 'NOTE (#4452): thresholds are evaluated over approve/reject/abstain, not over which option a voter chose. On a ' +\n 'multi-option proposal even `unanimous` clears trivially — see the `proposal` field description.'\n ),\n errorPolicy: ErrorPolicySchema.optional().describe(\n 'How to treat voters that errored or timed out (#2630). Default: fail_closed for unanimous only; reduce_denominator for all other strategies incl. higher_order/opinion_wise (#3138 — a single infra timeout should not void an otherwise-unanimous vote). Opt-in absolute_quorum (#4132): an errored voter — especially the contrarian (catfish) — degrades the verdict to no_quorum (recoverable re-run) instead of being dropped from the denominator; never manufactures approved/rejected from an induced error. Regardless of policy, errors > 50% always fails.'\n ),\n quickMode: z\n .boolean()\n .optional()\n .default(false)\n .describe('Use 3 agents instead of the full 7-role panel for faster execution'),\n simulateVotes: z\n .boolean()\n .optional()\n .default(false)\n .describe(\n 'TESTS ONLY — when true, voters return random decisions. Output must not be used for real decisions. (#2319)'\n ),\n /**\n * Async dispatch (#3045, Stage 4 of epic #2631). Default `sync` —\n * backward-compat invariant. `async` returns `{ status: 'pending', jobId }`\n * immediately; caller polls `get_job_result(jobId)`. Per-tool cap via\n * `NEXUS_JOB_MAX_CONCURRENT_CONSENSUS_VOTE` (default 2 — voting is\n * 7-fan-out so concurrent jobs multiply adapter load fast).\n *\n * Cancellation semantics (#5393, #6729): when a polling client calls\n * `cancel_job` mid-vote, the job's AbortSignal stops launching voters\n * that have not started and aborts the adapter call of every voter in\n * flight (combined with each seat's own deadline, so a deadline is still\n * recorded as a timeout). The body then settles and releases its\n * async slot. The job record stays `{ status: 'cancelled' }` — a later\n * complete/failed write cannot change it (#4022) — and carries no\n * `result` and no decision: the body stops before the tally, so no\n * verdict is computed and nothing is appended to the vote-record ledger.\n * Once the body settles, the record gains `cancelledPartial:\n * { partialVotes, seatsCast, panelSize }` (#6735): the seats that had\n * cast a vote before the cancel (a seat aborted or never launched is not\n * counted), and how many of the panel that is — `seatsCast: 0` when none\n * had. Sidecar store only; a `NEXUS_JOB_RESULT_SOURCE=task_state` read\n * does not carry it. A poll between the cancel and the body settling\n * sees `cancelled` without the field. A cancel that lands during the\n * ledger-lock wait also appends nothing: the signal is re-checked inside\n * the lock, right before the append. Limitation: a cancel during a\n * quick-mode escalation re-vote records the full re-vote panel only\n * (`panelSize` 7). The quick-panel votes that triggered the escalation\n * are not included.\n *\n * The key is `dispatch` (#4968); `mode` is the deprecated alias this tool\n * used to spell it with, resolved as `dispatch ?? mode` by the handler and\n * rejected when the two disagree (the `superRefine` below). Both optional\n * (no `.default()`) so the inferred type doesn't force a value onto every\n * existing call site / test fixture.\n */\n ...DEPRECATED_MODE_ALIAS_INPUT,\n /**\n * Idempotency key for async-mode replay-safety (#3042 Stage 1c / epic\n * #2631). When set: identical (key, inputs) returns the existing job;\n * same key with different inputs fails closed with\n * `idempotency_key_collision`. Sync mode ignores this.\n */\n idempotencyKey: z\n .string()\n .min(1)\n .max(256)\n .optional()\n .describe(\n 'Replay-safe key for async-mode dispatch (#3042 Stage 1c). Same (key, inputs) returns existing jobId.'\n ),\n /**\n * Authority-tier ratification subject (#4004). Set ONLY when this vote\n * ratifies an authority-ladder promotion: the loop/strategy id (the\n * tier-transition `subject`) this vote authorizes. It is bound into the\n * persisted record's self-hash as `ratifies`, so the promotion gate\n * (`check-authority-tier-drift.ts`) can resolve a `ratificationVoteRef` to this\n * record and require `ratifies === transition.subject` (with decision=approved,\n * strategy=higher_order). Omit on an ordinary vote.\n */\n ratifies: z\n .string()\n .min(1)\n .max(256)\n .optional()\n .describe(\n 'Authority-tier ratification subject (#4004) — the loop/strategy id this vote ratifies for an authority-ladder promotion. Bound into the authentic vote record so the promotion gate can verify it. Omit for ordinary votes.'\n ),\n /**\n * Governor-path PR ratification binding (#5130 step 1). Set ONLY when this\n * vote ratifies a PR that touches governor-owned paths: the PR number and\n * the FULL head sha the panel reviewed. Bound into the persisted record's\n * self-hash as `ratifiesPr` (schema 1.10), so the caller-commits script\n * (`scripts/append-ratification-record.ts`) can copy the record into the\n * committed ledger and the governor gate (step 2) can require it to name\n * the PR under review at its head. Validated by the same schema the record\n * uses, so producer and ledger cannot disagree on the shape.\n */\n ratifiesPr: VoteRecordPrBindingSchema.optional().describe(\n 'Governor-path PR ratification binding (#5130): pr is the PR number and headSha the full 40-hex head sha the panel reviewed. Bound into the authentic vote record so the committed ledger and the governor gate can verify which PR, at which head, this panel ratified. Omit for ordinary votes.'\n ),\n // #4968: `dispatch` and the deprecated `mode` alias must agree when both are sent.\n })\n .superRefine(refineDispatchModeAgreement);\n\nexport type ConsensusVoteInput = z.infer<typeof ConsensusVoteInputSchema>;\n\n// ============================================================================\n// Response Types\n// ============================================================================\n\nexport interface AgentVoteSummary {\n role: string;\n decision: 'approve' | 'reject' | 'abstain';\n confidence: number;\n reasoning: string;\n simulated: boolean;\n /** True when this vote was generated from an error (Issue #815). */\n error: boolean;\n /**\n * Model this seat ran on (Issue #817). Populated since #6606 from the seat's\n * resolved model; absent when the seat resolved none (an errored seat that\n * never reached a model, or the lazy-detection placeholder). Clipped to\n * {@link MODEL_USED_MAX_CHARS} to fit the advertised output schema.\n */\n modelUsed?: string;\n /** Structured rejection categories for reject→refine→re-vote loops (Issue #1213). */\n rejectionCategories?: readonly string[];\n /**\n * True when this seat was recovered by the per-role retry (#6050).\n *\n * Present only when true. A retried seat is weaker evidence than a first-pass\n * one — the model was unavailable or timed out — so a caller reading a panel\n * result should be able to see that \"7 of 7 answered\" and \"6 answered, 1\n * recovered\" are different facts.\n */\n retried?: boolean;\n /** Which declared option this voter chose (#4472). Absent when the proposal\n * declared none, or the voter's selection matched none of them. */\n selectedOption?: string;\n /**\n * True when this seat could not read the artifact (#6094). Present only\n * when true. Its `decision` is always `abstain`; `voteCounts.unverifiable`\n * counts these seats separately so a blind seat is never read as a\n * considered abstention.\n */\n unverifiable?: true;\n /**\n * Present only when this seat answered on a different CLI or model than it\n * was assigned (#6115): where it was meant to answer and the adapter error\n * class that moved it. `panelDiversity.fallbacks` counts these seats.\n */\n fallback?: SeatFallback;\n /**\n * Present only when the per-role retry REPLACED this seat (#6246): the first\n * pass's source and, when it had one, its clipped error string. `retried`\n * says a recovery happened; this says what it recovered from.\n */\n retriedFrom?: RetriedFrom;\n}\n\n/**\n * Canonical set of decision statuses a vote response can carry. Single source\n * of truth: the `consensus_vote` MCP `outputSchema` reuses\n * {@link VoteDecisionStatusSchema} so the advertised enum can never be narrower\n * than what {@link buildResponse} emits (all five are reachable —\n * `no_quorum` on an all-error/no-quorum panel, the rest via\n * {@link mapOutcomeToDecision}). A narrower schema made strict MCP clients\n * reject `timeout`/`pending` votes with a `-32602`-class error (#4032).\n */\nexport const VoteDecisionStatusSchema = z.enum([\n 'approved',\n 'rejected',\n 'pending',\n 'timeout',\n 'no_quorum',\n]);\n\nexport type VoteDecisionStatus = z.infer<typeof VoteDecisionStatusSchema>;\n\n/**\n * Outcome of the quick-mode contrarian check (#6111).\n *\n * In quick mode the contrarian is a separate `executeExpert` call, not a seat\n * in `votes`, so `voteCounts.error` cannot count it: an errored check under\n * `absolute_quorum` yields `no_quorum` with `error: 0`. This names that voice.\n *\n * - `ok` — the check ran and returned a verdict (escalating or not).\n * - `errored` — the check ran and the contrarian voice was NOT obtained.\n * - `skipped` — the check did not run: full-panel mode (catfish is a seat),\n * simulated votes, a non-approved quick verdict, a posterior-confidence\n * escalation that pre-empted it, or an error-policy short-circuit.\n */\nexport const ContrarianCheckStatusSchema = z.enum(['ok', 'errored', 'skipped']);\n\nexport type ContrarianCheckStatus = z.infer<typeof ContrarianCheckStatusSchema>;\n\n/**\n * Narrows a response decision to the three-value vocabulary the audit record\n * uses (#4986).\n *\n * The response vocabulary is wider — it carries `timeout` and `pending` too —\n * so the narrowing has to be stated rather than left to a cast:\n *\n * - `timeout` becomes `no_quorum`. A panel that ran out of time reached no\n * quorum; it did not reject the proposal, and recording it as `rejected`\n * would attribute a verdict to voters who never gave one.\n * - `pending` returns `undefined`. A vote still in flight has no decision to\n * record, and inventing one would be worse than falling back.\n */\nexport function toRecordDecision(\n status: VoteDecisionStatus | undefined\n): 'approved' | 'rejected' | 'no_quorum' | undefined {\n switch (status) {\n case 'approved':\n case 'rejected':\n case 'no_quorum':\n return status;\n case 'timeout':\n return 'no_quorum';\n default:\n return undefined;\n }\n}\n\n/**\n * Higher-Order Voting metadata (Issue #514).\n *\n * ADVISORY, not the verdict (#4701). Read `appliedToDecision` before drawing\n * any conclusion from the rest of this object.\n */\nexport interface HigherOrderMetadata {\n posteriorApproval: number;\n posteriorRejection: number;\n effectiveVoteCount: number;\n /**\n * Aggregation used for THIS correlation-aware run — not necessarily the one\n * that produced `decision`. See {@link HigherOrderMetadata.appliedToDecision}.\n */\n method: 'ow' | 'isp' | 'simple';\n usedCorrelationData: boolean;\n improvementOverBaseline: number;\n downweightedAgents: readonly string[];\n reasoning: string;\n /**\n * Whether this correlation-aware result actually produced the response's\n * `decision` (#4701).\n *\n * Currently ALWAYS FALSE. The verdict comes from `ConsensusEngine.close()`,\n * which calls `HigherOrderVotingStrategy.calculateOutcome` — and that calls\n * `aggregateSimpleInternal`, a plain `approve / (approve + reject)` ratio\n * with no correlation input. This object is computed separately and consumed\n * only as metadata plus one escalation check.\n *\n * The field exists because the omission was actively misleading: `method`\n * can read `'ow'` while `downweightedAgents` is non-empty, from which any\n * reasonable reader concludes the correlation analysis decided the vote. It\n * did not — the \"seven voters that are really one opinion\" case is detected\n * here and then discarded.\n *\n * Making the decision genuinely correlation-aware changes governance\n * outcomes and is tracked separately; this field makes the current state\n * legible in the meantime, including in persisted vote records.\n */\n appliedToDecision: boolean;\n}\n\nexport interface ConsensusVoteResponse {\n proposal: string;\n threshold?: VoteThreshold;\n strategy: VotingStrategy;\n decision: VoteDecisionStatus;\n approvalPercentage: number;\n /**\n * `unverifiable` (#6094) counts seats that answered without reading the\n * artifact. Those seats are ALSO inside `abstain` (their legacy decision);\n * the bucket is always present, explicit 0 included — an absent key would\n * read as health.\n */\n voteCounts: {\n approve: number;\n reject: number;\n abstain: number;\n error: number;\n unverifiable: number;\n };\n /**\n * #6111: the quick-mode contrarian check, reported beside the tally because\n * `voteCounts.error` counts seats and the check is not one. Always present;\n * `skipped` is the named empty case (see {@link ContrarianCheckStatus}).\n */\n contrarianCheck: ContrarianCheckStatus;\n votes: AgentVoteSummary[];\n durationMs: number;\n simulateVotes: boolean;\n /**\n * #6110: the project every voter was told it is judging, and how that name\n * was decided — `input` (the caller's `project`), `derived` (the working\n * directory's `origin` remote or `package.json`), or `default`\n * (`nexus-agents`). Always present: a consuming repository that forgot the\n * input sees `default` next to the verdict instead of a silent mis-scope.\n */\n project: ResolvedVoterProject;\n /**\n * #6258: the working directory every seat was pointed at — the caller's\n * checkout, else the server's `process.cwd()`. Present-only: absent when no\n * live seat ran (a simulated panel) or the result bypassed `executeVoting`.\n */\n workspace?: string;\n higherOrderMetadata?: HigherOrderMetadata;\n /**\n * Set when an error policy short-circuited the vote (#2630/#3124). Explains a\n * `rejected` decision that may coexist with a high `approvalPercentage` — e.g.\n * `fail_closed: 1 voter(s) errored`. Absent on normally-tallied votes.\n */\n policyReason?: string;\n /**\n * Set when the panel was DEGRADED (#3587): some voters errored, so the\n * decision rests on fewer than the requested number of voters. Surfaces a\n * silently-shrunk panel so the result isn't read as a full-strength consensus.\n * Absent when every requested voter returned a real vote.\n */\n panelWarning?: string;\n /**\n * #6115: how many distinct models answered and how many seats answered\n * somewhere other than where they were assigned. Always present, explicit\n * zeros included — three consecutive 7-seat panels ran every seat on one\n * model after the claude and codex seats fell over, and the response read\n * identically to a three-model panel. `panelWarning` names a single-model\n * panel of 3+ seats.\n */\n panelDiversity: PanelDiversity;\n /**\n * Per-decision cost rollup (#3855): per-voter / per-model token + USD totals\n * for this governed decision. Rides the existing response — no new MCP tool.\n * Totals are a floor when `costSummary.unmeasuredVoters > 0` (voters whose\n * adapter reported no usage are counted as unmeasured, not a measured $0).\n */\n costSummary?: DecisionCostSummary;\n /**\n * #4472: declared-option outcome, present only when the proposal declared\n * `options`. Separate from `approvalPercentage` — that stays the\n * approve/reject figure — so a caller can tell WHICH bar failed.\n *\n * `unattributedApprovals` is load-bearing, not decoration: a share alone\n * cannot distinguish dissent from absence, since `4 pick X + 3 unparseable`\n * reads 57% exactly like a real 4/3 split.\n */\n optionOutcome?: {\n tally: ReadonlyArray<{ option: string; count: number }>;\n leadingOption?: string;\n leadingShare: number;\n approverCount: number;\n selectedCount: number;\n unattributedApprovals: number;\n thresholdMet: boolean;\n /**\n * #4529: why the gate vetoed, present only when it did. Carried here rather\n * than on `policyReason`, which means \"an error policy voided this vote\" —\n * a split is a decision, not a void, and conflating them let a retry policy\n * re-roll a panel that had already disagreed.\n */\n vetoReason?: string;\n };\n /**\n * #3991: whether the authentic vote record (#3897) was persisted at vote time.\n * Post-#3991 the runtime ledger routes through `nexusDataPath` under\n * `governance/`, so a writable `.nexus-agents/governance/` location almost\n * always exists and `true` is the normal case. `false` means the persist was\n * skipped (all votes simulated) or the write failed (data dir unwritable) —\n * see {@link voteRecordNote}. Surfaces to the MCP caller what was previously\n * only a server-side WARN.\n */\n voteRecordPersisted: boolean;\n /**\n * #3991: present only when {@link voteRecordPersisted} is `false` — the\n * actionable reason the record was not written (e.g. the data dir is unwritable\n * → fix permissions or set `NEXUS_VOTE_RECORDS_PATH` to a writable path).\n */\n voteRecordNote?: string;\n /**\n * #5130: the persisted record's `id`, present only when\n * {@link voteRecordPersisted} is `true`. The caller-commits script\n * (`scripts/append-ratification-record.ts --record-id`) is keyed on it, and\n * a job result carries it so `--job <jobId>` can find the record. Without\n * it nothing downstream of the vote could name the record it produced.\n */\n voteRecordId?: string;\n}\n\n/** Extended voting result with optional Higher-Order metadata. */\nexport interface ExtendedVotingResult extends VotingResult {\n strategy: VotingStrategy;\n /**\n * #4472: the declared-option tally + verdict, present only when the proposal\n * declared `options`. Reported alongside `approvalPercentage` rather than\n * folded into it, so a reader can tell which bar failed.\n */\n optionGate?: OptionGateVerdict;\n higherOrderResult?: HigherOrderVotingResult;\n /** Reason an error policy short-circuited the vote (#3124); surfaced on the response. */\n policyReason?: string;\n /**\n * #6211: the error policy the panel actually ran under — the EFFECTIVE value\n * `executeVoting` resolved (`input.errorPolicy ?? getDefaultErrorPolicy(strategy)`),\n * stamped on every path it returns through (the short-circuit and the\n * finalized result; an escalated re-vote carries its own). The persisted\n * vote record reads it from here so the ledger states the policy the vote\n * ran under rather than the raw input, which is absent whenever the caller\n * took the default. Absent only on results built by paths that never ran\n * `executeVoting` (direct unit constructions), where no policy was applied.\n */\n errorPolicy?: ErrorPolicy;\n /**\n * #4132: the FULL requested panel size (`roles.length`) — the absolute_quorum\n * predicate in {@link buildResponse} needs it to compute the absolute approval\n * floor `ceil(fraction * panelSize)`. Distinct from `votes.length`, which can\n * differ from the requested panel if the collector ever returns a short list.\n * When absent, the predicate falls back to `votes.length`.\n */\n panelSize?: number;\n /**\n * #4132: whether the contrarian (catfish) was in the requested panel. `--quick`\n * runs a 3-role panel WITHOUT catfish, so the absolute_quorum \"contrarian must\n * be present and non-error\" clause is skipped when this is false (the quick-mode\n * carve-out). True on the full 7-role panel.\n */\n contrarianRequested?: boolean;\n /**\n * #6111: outcome of the quick-mode contrarian check. Stamped by `executeVoting`\n * on every path (`skipped` when the check did not run). Absent only on results\n * built by paths that never ran `executeVoting` (direct unit calls to\n * `buildResponse`), which `buildResponse` reports as `skipped` — the check\n * genuinely did not run there.\n */\n contrarianCheck?: ContrarianCheckStatus;\n /**\n * #4135: the response-layer decision (incl. `no_quorum`) for this vote, computed\n * by {@link resolveVoteDecision}. Set by `executeVoting` right before it returns\n * so pipeline consumers (iterative-consensus, agent-executor, the CLI) can honor\n * a `no_quorum` void instead of misreading it as a rejection — WITHOUT recomputing\n * the policy math. The engine `ConsensusResult.outcome` stays 2-valued\n * (`approved`/`rejected`); this is the widened, opt-in-aware view. Absent on\n * results built by paths that never ran `executeVoting` (direct unit calls to\n * `buildResponse`), where consumers fall back to mapping the engine outcome.\n */\n decision?: VoteDecisionStatus;\n /**\n * #6110: the resolved target project, stamped by `executeVoting` alongside\n * `decision` so the CLI and the response disclose the same name and source.\n * Absent only on results built by paths that never ran `executeVoting`.\n */\n project?: ResolvedVoterProject;\n /**\n * #6258: the directory `executeVoting` handed every seat, stamped once per\n * panel. Absent on a simulated panel and on results that bypassed it.\n */\n workspace?: string;\n}\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n/** Converts AgentVoteResult to AgentVoteSummary for response. */\nexport function toAgentVoteSummary(result: AgentVoteResult): AgentVoteSummary {\n const roleName = VOTER_ROLES[result.role].split(' - ')[0] ?? result.role;\n return {\n role: roleName,\n decision: result.vote.decision,\n confidence: result.vote.confidence,\n reasoning: result.vote.reasoning,\n simulated: result.source === 'simulation',\n error: result.source === 'error',\n ...(result.vote.rejectionCategories !== undefined\n ? { rejectionCategories: result.vote.rejectionCategories }\n : {}),\n // #6050: a caller acting on the live result sees what the ledger will.\n // Present only when true, so a clean panel's response is unchanged.\n ...(result.retried === true ? { retried: true } : {}),\n // #6094: same rule for a seat that could not read the artifact.\n ...(result.source === 'unverifiable' ? { unverifiable: true as const } : {}),\n // #6115: and for a seat that answered elsewhere.\n ...(result.fallback !== undefined ? { fallback: result.fallback } : {}),\n // #6246: and for what a recovered seat was retried from.\n ...(result.retriedFrom !== undefined ? { retriedFrom: result.retriedFrom } : {}),\n // #6606: the per-seat model was only in `costSummary.perVoter`.\n ...modelUsedOf(result),\n };\n}\n\n/** The advertised `votes[].modelUsed` bound in the consensus_vote output schema. */\nconst MODEL_USED_MAX_CHARS = 100;\n\n/** `{ modelUsed }` for a seat that resolved a model; the placeholder is not one. */\nfunction modelUsedOf(result: AgentVoteResult): { modelUsed?: string } {\n const model = result.model;\n if (model === undefined || model === '' || model === UNRESOLVED_MODEL_ID) return {};\n return {\n modelUsed:\n model.length <= MODEL_USED_MAX_CHARS ? model : `${model.slice(0, MODEL_USED_MAX_CHARS - 1)}…`,\n };\n}\n\n/**\n * `mapOutcomeToDecision`, `VoteDecisionOutcome` and `resolveVoteDecision` (with\n * its absolute_quorum and respondent-floor helpers) moved to\n * `consensus/decision/verdict.ts` (#6000 step 1): they are the computation that\n * turns a tally plus an error policy into `approved` / `rejected` /\n * `no_quorum`, and now live where that computation can be governed on its own\n * path. Re-exported here so every existing import keeps resolving.\n */\nexport {\n mapOutcomeToDecision,\n resolveVoteDecision,\n type VoteDecisionOutcome,\n} from '../../consensus/decision/verdict.js';\n\n/**\n * #3587: partial panel degradation — some (but not all) voters errored, so the\n * decision rests on fewer voters than requested. Returns a warning string, or\n * undefined when the panel is full or entirely errored (the latter is already a\n * structured error elsewhere).\n */\nfunction panelDegradationWarning(errorCount: number, total: number): string | undefined {\n if (errorCount <= 0 || errorCount >= total) return undefined;\n return (\n `Panel degraded: ${String(errorCount)} of ${String(total)} voters errored; ` +\n `decision rests on ${String(total - errorCount)} voter(s).`\n );\n}\n\n/**\n * Append to `panelWarning` rather than assign: it has several writers and an\n * assignment would silently drop whichever fired first. A `undefined` text is\n * a no-op.\n */\nfunction appendPanelWarning(response: ConsensusVoteResponse, text: string | undefined): void {\n if (text === undefined) return;\n response.panelWarning =\n response.panelWarning === undefined ? text : `${response.panelWarning} ${text}`;\n}\n\n/**\n * #6094: seats that answered without reading the artifact. Their abstention\n * is already inside `voteCounts.abstain`; this says how many of those never\n * saw the thing they were asked to judge. Undefined when there are none —\n * the count itself is still rendered as an explicit 0 in `voteCounts`.\n */\nfunction unverifiableSeatsWarning(unverifiableCount: number, total: number): string | undefined {\n if (unverifiableCount <= 0) return undefined;\n return (\n `${String(unverifiableCount)} of ${String(total)} seat(s) could not read the artifact and ` +\n 'are recorded as unverifiable (counted as abstain in voteCounts; any decision they returned was discarded).'\n );\n}\n\n// ============================================================================\n// absolute_quorum (#4132)\n// ============================================================================\n\n/**\n * #4132: process-wide count of panels that DEGRADED to `no_quorum` under the\n * opt-in `absolute_quorum` policy. The evidence base a future default-flip rests\n * on — how often does an errored voice actually void a real panel? Incremented in\n * {@link buildResponse}; read via {@link getDegradedPanelCount}. There is no\n * metrics bus in this module, so this mirrors the bare module-level counter style\n * used elsewhere (e.g. the correlation-tracker singleton).\n */\nlet degradedPanelCount = 0;\n\n/** #4132: current degraded-panel count (see {@link degradedPanelCount}). */\nexport function getDegradedPanelCount(): number {\n return degradedPanelCount;\n}\n\n/** #4132: reset the degraded-panel counter. Test-isolation only. @internal */\nexport function resetDegradedPanelCount(): void {\n degradedPanelCount = 0;\n}\n\n/**\n * #4132: absolute_quorum response side-effects — increment the degraded-panel\n * telemetry counter and surface the actionable re-run reason on policyReason /\n * panelWarning (when an errored voter degraded the verdict without an upstream\n * short-circuit already setting result.policyReason). Extracted to hold\n * {@link buildResponse} within its cyclomatic budget.\n */\nfunction applyAbsoluteQuorumTelemetry(\n response: ConsensusVoteResponse,\n input: ConsensusVoteInput,\n decision: VoteDecisionStatus,\n degradeReason: string | undefined\n): void {\n // The evidence base for a future default-flip: how often does an errored voice\n // actually void a real panel?\n if (input.errorPolicy === 'absolute_quorum' && decision === 'no_quorum') {\n degradedPanelCount++;\n }\n if (degradeReason !== undefined) {\n response.policyReason ??= degradeReason;\n response.panelWarning ??= degradeReason;\n }\n}\n\n/**\n * Builds the response from voting result.\n *\n * `voteRecord` (#3991) is the structured authentic-vote-record persistence\n * outcome; when omitted (direct unit calls) `voteRecordPersisted` defaults to\n * `false` with no note. The live handler always supplies it.\n */\n/**\n * Name the bar a strategy actually enforces.\n *\n * Derived from {@link VOTING_THRESHOLDS} rather than a second hand-written\n * mapping, so it cannot drift from the value the engine compares against.\n * Strategies that are aliases (`higher_order`, `opinion_wise`) resolve to their\n * own 0.5 entry and therefore report `majority`, which is the point.\n */\nfunction appliedThresholdFor(strategy: VotingStrategy | undefined): VoteThreshold {\n const algorithm: ConsensusAlgorithm = strategy ?? 'simple_majority';\n const bar = VOTING_THRESHOLDS[algorithm];\n if (bar >= 1) return 'unanimous';\n if (bar >= SUPERMAJORITY_THRESHOLD) return 'supermajority';\n return 'majority';\n}\n\n/**\n * #6111: the contrarian-check status the response reports. `executeVoting`\n * stamps one on every path; a result that never went through it never ran the\n * check, so `skipped` is the truthful name for that absence — not a default\n * standing in for a measurement.\n */\nfunction contrarianCheckFor(result: ExtendedVotingResult): ContrarianCheckStatus {\n return result.contrarianCheck ?? 'skipped';\n}\n\n/**\n * The project disclosure for the response (#6110). `executeVoting` stamps the\n * resolution on the result; a direct call that bypassed it (unit tests) gets\n * the SAME resolution recomputed from the input — mirroring how `decision` is\n * handled above — so the field is always present and never a fabricated source.\n */\nfunction disclosedProject(\n input: ConsensusVoteInput,\n result: ExtendedVotingResult\n): ResolvedVoterProject {\n const { name, source } =\n result.project ?? resolveVoterProject({ input: input.project, cwd: process.cwd() });\n return { name, source };\n}\n\n/**\n * The workspace disclosure for the response (#6258): present-only, like the\n * stamp it copies — no directory is fabricated for a panel that never ran one.\n */\nfunction disclosedWorkspace(result: ExtendedVotingResult): { workspace?: string } {\n return result.workspace === undefined ? {} : { workspace: result.workspace };\n}\n\nexport function buildResponse(\n input: ConsensusVoteInput,\n result: ExtendedVotingResult,\n costSummary?: DecisionCostSummary,\n voteRecord?: VoteRecordPersistOutcome\n): ConsensusVoteResponse {\n const proposalTruncated =\n input.proposal.length > 200 ? input.proposal.slice(0, 200) + '...' : input.proposal;\n\n const errorCount = result.votes.filter((v) => v.source === 'error').length;\n const unverifiableCount = result.votes.filter((v) => v.source === 'unverifiable').length;\n\n // #4053 / #4132: the user-facing decision. An error-policy short-circuit (the\n // >50% hard floor, or fail_closed) VOIDED the vote — that is no_quorum, NOT the\n // panel rejecting. The opt-in absolute_quorum policy (#4132) additionally\n // degrades to no_quorum when ANY voter (especially the contrarian) errored, so\n // an induced error can never manufacture approved/rejected. Every other policy\n // keeps the legacy mapping. `degradeReason` (when present) is the actionable\n // \"re-run\" message; it rides the response as `policyReason`.\n //\n // #4135 (DRY): `executeVoting` already stamped `result.decision` via THIS same\n // `resolveVoteDecision`. Reuse it so the response decision can't diverge from the\n // one pipeline consumers read; recompute only for the `degradeReason` telemetry\n // and for direct unit calls that bypass `executeVoting` (where `decision` is absent).\n const resolved = resolveVoteDecision(input, result, errorCount);\n const decision = result.decision ?? resolved.decision;\n\n const response: ConsensusVoteResponse = {\n proposal: proposalTruncated,\n strategy: result.strategy,\n decision,\n approvalPercentage: result.result.approvalPercentage,\n voteCounts: {\n approve: result.result.voteCounts.approve,\n reject: result.result.voteCounts.reject,\n abstain: result.result.voteCounts.abstain,\n error: errorCount,\n unverifiable: unverifiableCount,\n },\n contrarianCheck: contrarianCheckFor(result),\n votes: result.votes.map(toAgentVoteSummary),\n durationMs: result.totalTimeMs,\n simulateVotes: result.simulateVotes,\n project: disclosedProject(input, result),\n ...disclosedWorkspace(result),\n // #6115: always present — a panel nobody answered is explicit zeros.\n panelDiversity: panelDiversityOf(result.votes),\n // #3991: surface the authentic-vote-record persistence outcome so a skipped\n // or failed persist is visible to the MCP caller (was WARN-only).\n voteRecordPersisted: voteRecord?.persisted ?? false,\n };\n if (voteRecord !== undefined && !voteRecord.persisted) {\n response.voteRecordNote = voteRecord.detail;\n }\n if (voteRecord?.persisted === true) {\n response.voteRecordId = voteRecord.record.id;\n }\n\n if (result.optionGate !== undefined) {\n response.optionOutcome = toOptionOutcome(result.optionGate);\n }\n\n applyOptionalResponseFields(response, input, result, errorCount, costSummary);\n applyAbsoluteQuorumTelemetry(response, input, decision, resolved.degradeReason);\n return response;\n}\n\n/** The #4472 declared-option block of the response, from the gate's verdict. */\nfunction toOptionOutcome(\n g: OptionGateVerdict\n): NonNullable<ConsensusVoteResponse['optionOutcome']> {\n return {\n tally: g.tally.map((t) => ({ option: t.option, count: t.count })),\n ...(g.leadingOption !== undefined ? { leadingOption: g.leadingOption } : {}),\n leadingShare: g.leadingShare,\n approverCount: g.approverCount,\n selectedCount: g.selectedCount,\n unattributedApprovals: g.unattributedApprovals,\n thresholdMet: g.approved,\n ...(g.reason !== undefined ? { vetoReason: g.reason } : {}),\n };\n}\n\n/**\n * Attach the optional response fields (threshold, policy reason, panel warning,\n * higher-order metadata, cost summary). Extracted from {@link buildResponse} to\n * keep its cyclomatic complexity within the lint budget (#3855).\n */\nfunction applyOptionalResponseFields(\n response: ConsensusVoteResponse,\n input: ConsensusVoteInput,\n result: ExtendedVotingResult,\n errorCount: number,\n costSummary?: DecisionCostSummary\n): void {\n // #5315: this echoed `input.threshold` verbatim. But `resolveStrategy`\n // ignores `threshold` entirely when `strategy` is also supplied, and\n // `higher_order` carries a 0.5 bar — so a caller passing\n // `strategy: 'higher_order'` + `threshold: 'supermajority'` (the pairing the\n // governance table itself prescribes) got a record naming a bar the vote\n // never had to clear. Observed live at 4-approve/3-reject, 57.1%, reported as\n // `threshold: 'supermajority'`.\n //\n // The field now names the bar the ENGINE enforced, taken from the strategy it\n // actually ran. The record is ratification evidence; it must state what it\n // measured, not what was asked for.\n response.threshold = appliedThresholdFor(result.strategy);\n if (result.policyReason !== undefined) {\n response.policyReason = result.policyReason;\n }\n const panelWarning = panelDegradationWarning(errorCount, result.votes.length);\n if (panelWarning !== undefined) {\n response.panelWarning = panelWarning;\n }\n // #6094: APPENDED, like the undeclared-options warning below — a third\n // writer that assigned would clobber whichever fired first.\n appendPanelWarning(\n response,\n unverifiableSeatsWarning(response.voteCounts.unverifiable, result.votes.length)\n );\n // #6115: a 3+ panel whose every answering seat ran on ONE model. Appended for\n // the same reason as the two above.\n appendPanelWarning(response, singleModelPanelWarning(result.votes));\n // #6606: several models of ONE family — same rule, appended.\n appendPanelWarning(response, singleFamilyPanelWarning(result.votes));\n // #5360: a proposal that names alternatives while `options` is undefined\n // records a split as uniform approval — every voter approves the ACT of\n // deciding, not a side. A 3-3 tie was recorded as `APPROVED 83.3%` that way.\n //\n // The all-approved signal is the sharper half: on a proposal that enumerates a\n // fork it is the observed signature, and unlike a reasoning-variance detector\n // it needs nothing the persisted record drops (#5339).\n //\n // APPENDED, not assigned. `panelWarning` already has two writers and a third\n // that clobbered would silently drop whichever fired first.\n const engaged = result.votes.length - errorCount;\n const undeclared = checkUndeclaredOptions(\n input.proposal,\n input.options,\n engaged > 0 && response.voteCounts.reject === 0 && response.voteCounts.abstain === 0\n );\n if (undeclared.flagged) appendPanelWarning(response, undeclared.warning);\n if (isHigherOrderStrategy(result.strategy) && result.higherOrderResult) {\n response.higherOrderMetadata = toHigherOrderMetadata(result.higherOrderResult);\n }\n if (costSummary !== undefined) {\n response.costSummary = costSummary;\n }\n}\n\n/** Maps a HigherOrderVotingResult to the response's metadata shape. */\nfunction toHigherOrderMetadata(r: HigherOrderVotingResult): HigherOrderMetadata {\n return {\n posteriorApproval: r.posteriorApproval,\n posteriorRejection: r.posteriorRejection,\n effectiveVoteCount: r.effectiveVoteCount,\n method: r.method,\n usedCorrelationData: r.usedCorrelationData,\n improvementOverBaseline: r.improvementOverBaseline,\n downweightedAgents: r.downweightedAgents,\n reasoning: r.reasoning,\n // #4701: the engine's `calculateOutcome` decides, and it aggregates simple.\n // Hardcoded false rather than computed, because there is currently no code\n // path where this result reaches the verdict — a computed `false` would\n // imply one exists.\n appliedToDecision: false,\n };\n}\n","/**\n * Panel model diversity (#6115).\n *\n * `costSummary.perModel` showed the final model per seat but not the ASSIGNED\n * one, so \"7 of 7 on gemini\" was visible only to someone who knew the\n * round-robin. This module measures what the response and the summary line\n * disclose: how many distinct models actually answered, and how many seats\n * answered somewhere other than where they were assigned.\n *\n * Shared by the MCP response (`consensus-vote-types`) and the CLI / GitHub\n * renderings (`vote-summary-lines`) so the two cannot drift.\n *\n * @module cli/vote-diversity\n */\n\nimport { countDistinctModels, UNRESOLVED_MODEL_ID } from '../config/model-equivalence.js';\nimport type { AgentVoteResult, SeatFallback } from './vote-types.js';\nimport { bareCliName } from './voter-fallback.js';\nimport { vendorFamilyOf } from './voter-family-dealing.js';\n\n/**\n * Always present on the response, explicit zeros included: an absent key\n * would read as a healthy spread, which is exactly what the three\n * single-model panels looked like.\n */\nexport interface PanelDiversity {\n /** Distinct models (by canonical identity, #4390) among the seats that answered. */\n readonly distinctModels: number;\n /**\n * Distinct model families — vendors: anthropic, openai, google, ... (#6606) —\n * among the seats that answered. A seat whose model names no recognised\n * vendor is counted in {@link unclassifiedSeats}, never as a family.\n */\n readonly distinctFamilies: number;\n /** Answering seats whose resolved model names no recognised vendor (#6606). */\n readonly unclassifiedSeats: number;\n /**\n * Answering seats whose model never resolved — absent, empty, or the\n * `pending-detection` placeholder (#6660). They sit in none of the other\n * counts, so without this one \"1 distinct, 1 family\" could describe a panel\n * where six of seven answering seats named no model at all.\n * {@link panelDiversityOf} always sets it, explicit zero included; optional\n * in the type only so the published shape widens additively.\n */\n readonly unresolvedSeats?: number;\n /** Seats that answered on a CLI or model other than the one assigned. */\n readonly fallbacks: number;\n}\n\n/** A seat that answered elsewhere, with where it landed. */\nexport interface SeatFallbackDetail {\n readonly role: AgentVoteResult['role'];\n readonly fallback: SeatFallback;\n /** The CLI that answered, bare (`gemini`), or `?` when the result carries none. */\n readonly toCli: string;\n readonly toModel: string | undefined;\n}\n\n/** The seats whose answer counts — the same subset `reportVoteIndependence` judges. */\nfunction answeringSeats(votes: readonly AgentVoteResult[]): AgentVoteResult[] {\n return votes.filter((v) => v.source === 'llm');\n}\n\n/** A seat's model when it resolved one; the placeholder is not a model. */\nfunction resolvedModel(v: AgentVoteResult): string | undefined {\n return v.model === undefined || v.model === '' || v.model === UNRESOLVED_MODEL_ID\n ? undefined\n : v.model;\n}\n\n/** Every answering seat that carries a fallback, in panel order. */\nexport function seatFallbacks(votes: readonly AgentVoteResult[]): SeatFallbackDetail[] {\n const out: SeatFallbackDetail[] = [];\n for (const v of answeringSeats(votes)) {\n if (v.fallback === undefined) continue;\n out.push({\n role: v.role,\n fallback: v.fallback,\n toCli: v.cli === undefined ? '?' : bareCliName(v.cli),\n toModel: resolvedModel(v),\n });\n }\n return out;\n}\n\n/**\n * Distinct answering models and fallback count. A panel nobody answered is\n * `{ 0, 0 }` — `countDistinctModels([])` is 0 and no seat can have fallen\n * over — which is the named empty case, not a claim of diversity.\n */\nexport function panelDiversityOf(votes: readonly AgentVoteResult[]): PanelDiversity {\n const resolved = answeringSeats(votes).map(resolvedModel);\n const models = resolved.filter((m): m is string => m !== undefined);\n const families = models.map(vendorFamilyOf);\n const classified = families.filter((f) => f !== 'unknown');\n return {\n distinctModels: countDistinctModels(models),\n distinctFamilies: new Set(classified).size,\n unclassifiedSeats: families.length - classified.length,\n unresolvedSeats: resolved.length - models.length,\n fallbacks: seatFallbacks(votes).length,\n };\n}\n\n/** Panels smaller than this cannot make a meaningful independence claim to weaken. */\nconst MIN_PANEL_FOR_DIVERSITY_WARNING = 3;\n\n/**\n * The warning for a panel of 3+ seats whose every answering seat ran on ONE\n * model. Undefined on a diverse panel, a small panel, a panel nobody answered\n * (the degradation warning already covers that one), and a panel where an\n * answering seat never resolved its model — \"all on one model\" is a claim,\n * and an unresolved seat is a seat the claim cannot cover (#4983).\n */\nexport function singleModelPanelWarning(votes: readonly AgentVoteResult[]): string | undefined {\n if (votes.length < MIN_PANEL_FOR_DIVERSITY_WARNING) return undefined;\n const answered = answeringSeats(votes);\n const models = answered.map(resolvedModel);\n const model = models[0];\n if (model === undefined || models.includes(undefined)) return undefined;\n if (panelDiversityOf(votes).distinctModels !== 1) return undefined;\n const silent = votes.length - answered.length;\n const missing = silent > 0 ? ` (${String(silent)} did not answer)` : '';\n return (\n `All ${String(answered.length)} seats answered on ${model}${missing}; ` +\n 'independence is weaker than assigned.'\n );\n}\n\n/**\n * The warning for a 3+ panel whose answering seats ran SEVERAL models of ONE\n * family (#6606): three Anthropic models are one vendor's judgement, however\n * distinct their ids. Undefined when the panel spans families, runs a single\n * model (the single-model warning names that one), is under 3 seats, or has\n * nobody answering — and when any answering seat is unresolved or\n * unclassified, because \"all one family\" is a claim that seat cannot support.\n */\nexport function singleFamilyPanelWarning(votes: readonly AgentVoteResult[]): string | undefined {\n if (votes.length < MIN_PANEL_FOR_DIVERSITY_WARNING) return undefined;\n const answered = answeringSeats(votes);\n const models = answered.map(resolvedModel);\n const model = models[0];\n if (model === undefined || models.includes(undefined)) return undefined;\n const { distinctModels, distinctFamilies, unclassifiedSeats } = panelDiversityOf(votes);\n if (distinctFamilies !== 1 || unclassifiedSeats > 0 || distinctModels < 2) return undefined;\n return (\n `All ${String(answered.length)} answering seats ran ${vendorFamilyOf(model)} models ` +\n `(${String(distinctModels)} distinct); independence is weaker than assigned.`\n );\n}\n","/**\n * Detects a multi-option proposal submitted WITHOUT declared `options` (#5360).\n *\n * #4452 established the failure: a proposal naming alternatives only in prose\n * records a split as uniform approval, because every voter returns `approve` —\n * approving the ACT of deciding, not a side. #4472 built the fix (`options`, a\n * `selectedOption` prompt, a threshold over the option tally). Nothing detected\n * when a caller should have used it, so the failure stayed reachable by\n * forgetting — and it recurred on a real architecture vote, where a 3–3 tie was\n * recorded as `APPROVED 83.3%`.\n *\n * A WARNING, not a refusal. The false-positive cost is unmeasured: a proposal\n * that merely mentions options would trip the patterns, and refusing a\n * governance vote on an unmeasured heuristic trades one failure for a worse one.\n * The promotion criteria live on the follow-up issue (#5422).\n *\n * The measurement (#5422): precision cannot be measured over the vote ledger,\n * which stores a 503-char proposal preview, so {@link detectUndeclaredOptions}\n * returns a structured verdict — fired / not-fired, the pattern, and a bounded\n * excerpt from the FULL proposal — that MCP and CLI record on every vote\n * alongside the decision-cost rollup. `scripts/undeclared-options-precision.ts`\n * reads those rows back for hand-labelling.\n *\n * @module mcp/tools/consensus-vote-option-detection\n */\n\nimport {\n UNDECLARED_OPTIONS_EXCERPT_CHARS,\n type UndeclaredOptionsDetectorRecord,\n} from '../../observability/decision-cost.js';\n\n/**\n * Prose shapes that name alternatives. Deliberately narrow — each must be a\n * phrase a caller uses when asking voters to CHOOSE, not merely to approve.\n *\n * Anchored and bounded: no nested quantifiers, so none can backtrack\n * catastrophically on a long proposal — pinned by a test, since the detector\n * runs on the FULL proposal (#5422). Exported so the precision reader can\n * print a per-pattern count, zero-hit patterns included.\n */\nexport const UNDECLARED_OPTION_PATTERNS: readonly RegExp[] = Object.freeze([\n // `Option A` and `OPTION A`, but NOT `option a` — the lowercase form appears\n // in ordinary prose (\"there is no option a caller can set\"), the capitalised\n // form is a heading. The motivating proposal used `Option A`; an\n // uppercase-only pattern would have missed the instance this exists for.\n /\\b(?:Option|OPTION) [A-Z0-9]\\b/,\n /\\bchoose between\\b/i,\n /\\bwhich of (?:the )?(?:these|those|the following)\\b/i,\n /\\bpick exactly one\\b/i,\n /\\bvote for exactly one\\b/i,\n]);\n\n/** Outcome of the check. A discriminated union so \"not checked\" cannot read as \"clean\". */\nexport type UndeclaredOptionsCheck =\n { readonly flagged: false } | { readonly flagged: true; readonly warning: string };\n\n/**\n * The detector's verdict as recorded for the precision measurement (#5422).\n *\n * `pattern` is the matching regex as written (`String(regex)`, flags included)\n * and `excerpt` is a window of at most {@link UNDECLARED_OPTIONS_EXCERPT_CHARS}\n * characters around the match, taken from the FULL proposal — the text the\n * ledger's preview drops. Both are absent on a not-fired verdict; the\n * not-fired row is still recorded for fired / total. Declared options yield\n * `applicable: false` with no fired verdict, since the detector did not run.\n */\ntype UndeclaredOptionsVerdict =\n | Omit<\n Extract<UndeclaredOptionsDetectorRecord, { fired: boolean }>,\n 'declaredOptionCount' | 'source'\n >\n | Omit<\n Extract<UndeclaredOptionsDetectorRecord, { applicable: false }>,\n 'declaredOptionCount' | 'source'\n >;\n\n/**\n * A window of {@link UNDECLARED_OPTIONS_EXCERPT_CHARS} around `[start, end)`,\n * centred on the match and clamped to the text so a short proposal comes back\n * whole rather than padded.\n */\nfunction excerptAround(text: string, start: number, end: number): string {\n const width = UNDECLARED_OPTIONS_EXCERPT_CHARS;\n if (text.length <= width) return text;\n const slack = Math.max(0, width - (end - start));\n let from = Math.max(0, start - Math.floor(slack / 2));\n const to = Math.min(text.length, from + width);\n from = Math.max(0, to - width);\n return text.slice(from, to);\n}\n\n/**\n * The pure verdict: does the proposal name alternatives while `options` is\n * absent, and where? Declared options (a non-empty array) mean the option-aware\n * tally is live, so the verdict is not applicable without consulting the patterns —\n * an empty array switches the tally off exactly as absence does.\n *\n * First matching pattern wins, in {@link UNDECLARED_OPTION_PATTERNS} order.\n */\nexport function detectUndeclaredOptions(\n proposal: string,\n declaredOptions: readonly string[] | undefined\n): UndeclaredOptionsVerdict {\n if (declaredOptions !== undefined && declaredOptions.length > 0) return { applicable: false };\n if (proposal === '') return { fired: false };\n for (const pattern of UNDECLARED_OPTION_PATTERNS) {\n const match = pattern.exec(proposal);\n if (match === null) continue;\n const start = match.index;\n return {\n fired: true,\n pattern: String(pattern),\n excerpt: excerptAround(proposal, start, start + match[0].length),\n };\n }\n return { fired: false };\n}\n\n/**\n * Does the proposal name alternatives while `options` is absent?\n *\n * `allEngagedApproved` is the second signal, and it is the sharper one (#5360,\n * from the review panel): when every non-errored voter returns `approve` on a\n * proposal that enumerates a fork, that is the observed signature of this exact\n * defect rather than a proposal that merely mentions the word \"option\". It is\n * available without the persisted reasoning that a full disagreement detector\n * would need (#5339).\n *\n * Pass `undefined` for `allEngagedApproved` when the votes are not yet known —\n * the check then rests on the prose alone and says so in the warning.\n */\nexport function checkUndeclaredOptions(\n proposal: string,\n declaredOptions: readonly string[] | undefined,\n allEngagedApproved?: boolean\n): UndeclaredOptionsCheck {\n // One pattern set: the warning and the recorded verdict must agree, or the\n // precision measured on the record says nothing about the warning (#5422).\n if (detectUndeclaredOptions(proposal, declaredOptions).fired !== true) return { flagged: false };\n\n const base =\n 'This proposal appears to name alternatives, but `options` was not declared, ' +\n 'so the tally records approve/reject only and cannot say WHICH alternative won ' +\n '(#4452, #5360). Re-run with `options` to record the option tally.';\n\n // Stated separately because it is evidence, not restatement: every voter\n // approving a proposal that enumerates a fork is the signature of voters\n // approving the act of deciding rather than a side.\n return {\n flagged: true,\n warning:\n allEngagedApproved === true\n ? `${base} Every non-errored voter returned \\`approve\\`, which is the signature of this defect.`\n : base,\n };\n}\n","/**\n * Error-policy handling for consensus_vote (#2630).\n *\n * When a voter errors or times out (`source === 'error'`), the response\n * shape already distinguishes it via `voteCounts.error` (see\n * consensus-vote-types.ts:188). What was missing: a configurable\n * decision policy for how those error voters interact with the strategy\n * threshold, plus a safety floor for \"too many errors to call a\n * consensus.\"\n *\n * Three policies, plus a hard floor:\n *\n * - `reduce_denominator` (default for non-strict strategies): errors\n * filtered out before the engine sees votes. Denominator = non-error\n * votes. Pragmatic for operational decisions.\n * - `count_as_abstain`: errors reach the engine as abstain. Conservative\n * — error voter is treated as having withheld approval.\n * - `fail_closed` (default for unanimous only, #3138): any error\n * short-circuits to vote-void.\n * - `absolute_quorum` (opt-in, #4132): errors reach the engine as abstain\n * (like `count_as_abstain`), but the post-tally predicate in\n * `buildResponse` degrades ANY errored panel to `no_quorum` — an induced\n * error can never manufacture `approved`/`rejected`. Does not short-circuit\n * here (below the hard floor); the degrade happens after the tally so a\n * genuine reject is preserved.\n *\n * Hard floor: if errors > `ERROR_FLOOR_FRACTION` of total voters, the\n * vote always fails regardless of policy. \"All CLIs are down\" is not a\n * consensus.\n *\n * @module mcp/tools/consensus-vote-error-policy\n */\n\nimport type { AgentVoteResult } from '../../cli/vote-types.js';\nimport type { ErrorPolicy } from './consensus-vote-types.js';\nimport { ERROR_FLOOR_FRACTION } from '../../consensus/decision/thresholds.js';\n\nexport interface ErrorPolicyDecision {\n /** True when the vote should short-circuit to failed without reaching the engine. */\n readonly shortCircuit: boolean;\n /** Human-readable reason when shortCircuit is true. */\n readonly reason?: string;\n /**\n * Votes to feed to the engine. Empty when shortCircuit is true.\n * Otherwise: errors filtered out (`reduce_denominator`) or converted\n * to abstain (`count_as_abstain`).\n */\n readonly engineVotes: readonly AgentVoteResult[];\n}\n\nfunction isHardFloorTripped(errorCount: number, totalCount: number): boolean {\n if (totalCount === 0) return false;\n return errorCount / totalCount > ERROR_FLOOR_FRACTION;\n}\n\n/**\n * Apply the configured error policy to the raw voter list. Returns a\n * decision describing whether the vote should short-circuit and what\n * votes (if any) should reach the consensus engine.\n *\n * The hard floor (`errors / total > ERROR_FLOOR_FRACTION`) takes\n * precedence over any policy — even `reduce_denominator` short-circuits\n * when most voters errored, because the remaining minority isn't a real\n * consensus.\n *\n * The per-voter response list is built from the ORIGINAL `votes` array\n * upstream; this helper only shapes what the engine sees.\n */\nexport function applyErrorPolicy(\n votes: readonly AgentVoteResult[],\n policy: ErrorPolicy\n): ErrorPolicyDecision {\n const errorVotes = votes.filter((v) => v.source === 'error');\n const errorCount = errorVotes.length;\n const totalCount = votes.length;\n\n if (isHardFloorTripped(errorCount, totalCount)) {\n return {\n shortCircuit: true,\n reason: `Errors exceeded ${String(Math.round(ERROR_FLOOR_FRACTION * 100))}% of voters (${String(errorCount)}/${String(totalCount)})`,\n engineVotes: [],\n };\n }\n\n if (policy === 'fail_closed' && errorCount > 0) {\n return {\n shortCircuit: true,\n reason: `fail_closed: ${String(errorCount)} voter(s) errored`,\n engineVotes: [],\n };\n }\n\n if (policy === 'count_as_abstain' || policy === 'absolute_quorum') {\n // Errors stay in the engine input but as abstain decisions — the engine sees\n // the FULL panel rather than a shrunk denominator. The original\n // `source: 'error'` is preserved so the per-voter response shape and\n // `voteCounts.error` still report the error, and (for #4132 absolute_quorum)\n // the post-tally predicate in buildResponse can still see the true errorCount.\n // absolute_quorum does NOT fail-close here — the >50% hard floor above still\n // applies, but a sub-floor error degrades to no_quorum in buildResponse, not\n // a short-circuit, so the engine outcome (a genuine reject) is preserved.\n return {\n shortCircuit: false,\n engineVotes: votes.map((v) =>\n v.source === 'error' ? { ...v, vote: { ...v.vote, decision: 'abstain' as const } } : v\n ),\n };\n }\n\n // reduce_denominator (default): errors filtered out before engine sees them.\n return {\n shortCircuit: false,\n engineVotes: votes.filter((v) => v.source !== 'error'),\n };\n}\n","/**\n * Bound an artifact to a prompt budget, and disclose the bound.\n *\n * CLAUDE.md: \"A review must consume the artifact, not a description of it. …\n * Bounded reads are legitimate — the Context budget is real and a large diff\n * cannot always be read whole — but the record must then state which portion\n * was reviewed. A partial review honestly labeled is fine; a partial review\n * recorded as complete is the failure.\"\n *\n * The shape follows `mcp/tools/pr-review-diff-budget.ts` (#4140), which\n * established it for `pr_review`: within budget the output is BYTE-IDENTICAL\n * and carries no note, so the ordinary case is unchanged; over budget a visible\n * note rides on the prompt and a machine-readable bound rides on the result.\n *\n * This is the character-oriented sibling of that file-oriented packer. Where a\n * diff can be packed by whole files (so a reviewed file is reviewed\n * completely), a free-text proposal has no such seam and is cut at a character\n * count — which makes disclosure more important, not less, since the cut can\n * land mid-sentence.\n *\n * @module utils/bounded-artifact\n */\n\n/** How much of an artifact a reviewer actually saw. */\nexport interface ArtifactBound {\n /** Characters the reviewer was shown. */\n readonly reviewedChars: number;\n /** Characters in the whole artifact. */\n readonly totalChars: number;\n /** True when the reviewer saw less than the whole artifact. */\n readonly partial: boolean;\n}\n\n/** An artifact bounded for a prompt, with the disclosure that must accompany it. */\nexport interface BoundedArtifact {\n /** The text to embed — the whole artifact when it fit. */\n readonly text: string;\n /** Visible note to place before the artifact; `''` when nothing was cut. */\n readonly note: string;\n /** Machine-readable bound for the record; `undefined` when nothing was cut. */\n readonly bound: ArtifactBound | undefined;\n}\n\n/**\n * Cut `text` to `budget` characters when it exceeds it, and produce the\n * disclosure.\n *\n * `label` names the artifact in the note — a reviewer told \"you are seeing part\n * of it\" needs to know part of what.\n *\n * Pure: no I/O, no model call, no logging.\n */\nexport function boundArtifactForReview(\n text: string,\n budget: number,\n label: string\n): BoundedArtifact {\n if (text.length <= budget) {\n return { text, note: '', bound: undefined };\n }\n return {\n text: text.slice(0, budget),\n note:\n `> NOTE: partial view — you are seeing the first ${String(budget)} of ` +\n `${String(text.length)} characters of the ${label}. Judge only what is shown, ` +\n `and treat insufficient visibility as itself a reason to raise a concern.`,\n bound: { reviewedChars: budget, totalChars: text.length, partial: true },\n };\n}\n","/**\n * Contrarian escalation for `quickMode` consensus votes (#1799, #3174, #4132,\n * #6111).\n *\n * A quick-mode approval is a 3-voter verdict. Before it stands, this module\n * either re-runs the vote with the full panel (a borderline Bayesian posterior,\n * or a single contrarian expert rejecting with high confidence) or, under\n * `absolute_quorum`, reports that the contrarian voice could not be obtained so\n * the verdict degrades to `no_quorum` instead of silently proceeding.\n *\n * Moved out of `consensus-vote.ts` as a pure extraction (#6148, row 1): the\n * only in-tree consumer is `executeVotingInner`. The full-panel re-vote is\n * INJECTED (`ctx.revote`) rather than imported, so this module does not\n * import the parent and the split introduces no import cycle.\n *\n * @module mcp/tools/consensus-vote-contrarian\n * (Source: Issue #6148)\n */\n\nimport type { ILogger, IModelAdapter } from '../../core/index.js';\nimport { boundArtifactForReview, type BoundedArtifact } from '../../utils/bounded-artifact.js';\nimport type { ResolvedVoterProject } from '../../cli/voter-project.js';\nimport type { AgentVoteResult } from '../../cli/vote-types.js';\nimport { buildOptionsBlock, buildWorkspaceBlock } from '../../cli/voter-response.js';\nimport { shouldEscalateLowPosterior } from './consensus-vote-types.js';\nimport type {\n ConsensusVoteInput,\n ContrarianCheckStatus,\n ExtendedVotingResult,\n VotingStrategy,\n} from './consensus-vote-types.js';\n\n/** Options forwarded unchanged to the full-panel re-vote (#4040, #5393, #6110). */\ninterface RevoteOpts {\n voteTimeoutMs?: number;\n gatewayAdapters?: readonly IModelAdapter[] | undefined;\n /** #5393: stops LAUNCHING un-started voters when `cancel_job` fires. */\n signal?: AbortSignal | undefined;\n /** #6110: already resolved by the outer frame; the re-vote reuses it. */\n project?: ResolvedVoterProject | undefined;\n workspace?: string | undefined;\n workspaceSha?: string | undefined;\n /** #6162: per-seat heartbeat, retained through the re-vote. */\n onVoteCollected?: ((vote: AgentVoteResult) => void) | undefined;\n}\n\n/**\n * The full-panel re-vote, supplied by the caller. `executeVoting` in\n * `consensus-vote.ts` satisfies it; declared here so the sibling never\n * imports the parent.\n */\ntype QuickModeRevote = (\n input: ConsensusVoteInput,\n logger: ILogger,\n opts?: RevoteOpts\n) => Promise<ExtendedVotingResult>;\n\n/** Confidence threshold above which a contrarian rejection triggers escalation (#1799). */\nconst CONTRARIAN_ESCALATION_THRESHOLD = 0.8;\n\n/**\n * Characters of the proposal the contrarian is shown.\n *\n * Unchanged from the value that was inline, so escalation behaviour on\n * ordinary proposals is identical; what changed is that exceeding it is now\n * disclosed to the contrarian rather than silently applied (#5301).\n */\nconst CONTRARIAN_PROPOSAL_BUDGET = 2000;\n\n/** Build the contrarian prompt with full declared options and any partial-proposal note. */\nfunction buildContrarianPrompt(\n bounded: BoundedArtifact,\n options: readonly string[] | undefined,\n opts?: RevoteOpts\n): string {\n const workspaceBlock = buildWorkspaceBlock(opts?.workspace, opts?.workspaceSha);\n return [\n 'You are a contrarian analyst. Your job is to find reasons this proposal should be REJECTED.',\n 'Look for: YAGNI (not needed), MISALIGNED (wrong tech/architecture), SECURITY_RISK, SCOPE_CREEP.',\n '',\n ...(workspaceBlock === '' ? [] : [workspaceBlock]),\n ...(bounded.note === '' ? [] : [bounded.note, '']),\n // Options are outside the proposal budget; the input schema bounds their labels.\n `Proposal: ${bounded.text}${buildOptionsBlock(options)}`,\n '',\n 'If you find a strong reason to reject, respond with JSON:',\n '{\"decision\":\"reject\",\"confidence\":0.0-1.0,\"reasoning\":\"your concern\"}',\n 'If the proposal is sound, respond with:',\n '{\"decision\":\"approve\",\"confidence\":0.0-1.0,\"reasoning\":\"why it is acceptable\"}',\n ].join('\\n');\n}\n\n/**\n * Record that the contrarian saw only part of the proposal.\n *\n * Logged rather than left silent because `shouldEscalate: false` is the same\n * value whether the contrarian read everything or 4% of it, so the envelope\n * alone cannot distinguish them.\n */\nfunction logPartialProposal(bounded: BoundedArtifact, log: ILogger): void {\n if (bounded.bound === undefined) return;\n log.info('Contrarian sees a partial proposal', {\n reviewedChars: bounded.bound.reviewedChars,\n totalChars: bounded.bound.totalChars,\n });\n}\n\n/**\n * Run a single contrarian agent to check for YAGNI/MISALIGNED/SECURITY_RISK\n * (#1799). `errored` (#4132) is true when the contrarian voice could NOT be\n * obtained (import/executeExpert failure, or the expert reported failure) — the\n * absolute_quorum policy routes that to `no_quorum` instead of silently\n * proceeding as if the contrarian approved.\n */\nasync function runContrarianCheck(\n proposal: string,\n options: readonly string[] | undefined,\n log: ILogger,\n opts?: RevoteOpts\n): Promise<{ shouldEscalate: boolean; reason: string; confidence: number; errored: boolean }> {\n try {\n const { executeExpert } = await import('../../pipeline/expert-bridge.js');\n // #5301: the proposal was cut to 2000 chars with no marker. A `pr_review`\n // proposal carries the whole diff whenever it fits the panel's context\n // (#6003; up to the 2 MB input cap), so the\n // contrarian could be deciding whether to escalate having seen ~4% of it —\n // the header region, where a diff is least informative — and returned the\n // same `shouldEscalate: false` it returns after reading the whole thing.\n const bounded = boundArtifactForReview(proposal, CONTRARIAN_PROPOSAL_BUDGET, 'proposal');\n logPartialProposal(bounded, log);\n const result = await executeExpert(\n 'architecture',\n buildContrarianPrompt(bounded, options, opts),\n {\n workDir: opts?.workspace,\n }\n );\n // Expert-bridge reported failure — the contrarian voice was NOT obtained.\n if (!result.success) return { shouldEscalate: false, reason: '', confidence: 0, errored: true };\n\n const jsonMatch = result.text.match(/\\{[\\s\\S]*\\}/);\n // The expert responded but emitted no structured concern — treat as \"no\n // escalation\" (it spoke, it just didn't flag a blocker), not an error.\n if (jsonMatch === null)\n return { shouldEscalate: false, reason: '', confidence: 0, errored: false };\n\n const parsed = JSON.parse(jsonMatch[0]) as {\n decision?: string;\n confidence?: number;\n reasoning?: string;\n };\n\n const isRejection = parsed.decision === 'reject';\n const confidence = typeof parsed.confidence === 'number' ? parsed.confidence : 0;\n const reasoning = typeof parsed.reasoning === 'string' ? parsed.reasoning : '';\n\n if (isRejection && confidence >= CONTRARIAN_ESCALATION_THRESHOLD) {\n log.info('Contrarian rejected with high confidence', {\n confidence,\n reasoning: reasoning.slice(0, 200),\n });\n return { shouldEscalate: true, reason: reasoning, confidence, errored: false };\n }\n\n return { shouldEscalate: false, reason: '', confidence, errored: false };\n } catch (error: unknown) {\n // Closes #2952 (medium): pre-fix the bare `catch {}` swallowed\n // `executeExpert` failures, JSON parse errors, and expert-bridge\n // import errors identically — the escalation guardrail silently\n // disabled itself with no log trail. Log + return the default\n // \"no escalation\" envelope so a contrarian-check infrastructure\n // bug is at least visible in operator logs.\n const message = error instanceof Error ? error.message : String(error);\n log.warn('Contrarian check failed; defaulting to no escalation', { error: message });\n // #4132: the contrarian voice was NOT obtained — errored:true so\n // absolute_quorum can degrade to no_quorum instead of silently proceeding.\n return { shouldEscalate: false, reason: '', confidence: 0, errored: true };\n }\n}\n\n/**\n * Escalation gate for `quickMode` approvals. Two independent triggers, both\n * re-running `executeVoting` with the full voter panel:\n *\n * 1. Posterior-confidence (#3174): for `higher_order`/`opinion_wise`, a borderline\n * Bayesian posterior (below `HIGHER_ORDER_ESCALATION_POSTERIOR_FLOOR`) means the\n * 3-voter quick panel was barely decisive — escalate without spending a\n * contrarian call. Checked first so a borderline posterior short-circuits it.\n * 2. Contrarian agent (#1799): run a single contrarian to catch\n * YAGNI / SECURITY_RISK / SCOPE_CREEP; escalate if it rejects with high\n * confidence.\n *\n * Returns:\n * - `{ escalated }` — a full-panel re-vote result to use instead;\n * - `{ degradeReason }` — (#4132, absolute_quorum only) the contrarian check\n * ERRORED, so the quickMode verdict must degrade to `no_quorum`;\n * - `{}` — no escalation, continue with the quickMode result.\n *\n * Every shape also carries `contrarianCheck` (#6111): what became of the\n * contrarian call itself — `skipped` when this gate returned before making it,\n * `errored` when it was made and the voice was not obtained (under every\n * policy, not only absolute_quorum — the policy decides the verdict, the field\n * reports the check), `ok` when it answered.\n */\nexport async function maybeEscalateContrarian(\n input: ConsensusVoteInput,\n outcome: 'approved' | 'rejected',\n ctx: {\n strategy: VotingStrategy;\n posteriorApproval: number | undefined;\n /** Required, not defaulted: the compiler names every call site (#6148). */\n revote: QuickModeRevote;\n },\n logger: ILogger,\n // Mirror executeVoting's opts so gateway routing (#4040) survives the escalation\n // re-vote — the object is forwarded by reference today, but the wider type makes\n // that contract explicit and refactor-safe.\n opts?: RevoteOpts\n): Promise<{\n escalated?: ExtendedVotingResult;\n degradeReason?: string;\n contrarianCheck: ContrarianCheckStatus;\n}> {\n if (!input.quickMode || outcome !== 'approved' || input.simulateVotes) {\n return { contrarianCheck: 'skipped' };\n }\n\n if (shouldEscalateLowPosterior(ctx.strategy, outcome, input.quickMode, ctx.posteriorApproval)) {\n logger.warn('Posterior-confidence escalation: re-running with full vote (#3174)', {\n strategy: ctx.strategy,\n posteriorApproval: ctx.posteriorApproval,\n });\n return {\n escalated: await ctx.revote({ ...input, quickMode: false }, logger, opts),\n contrarianCheck: 'skipped',\n };\n }\n\n const escalation = await runContrarianCheck(input.proposal, input.options, logger, opts);\n const contrarianCheck: ContrarianCheckStatus = escalation.errored ? 'errored' : 'ok';\n // #4132: under absolute_quorum, a contrarian check that ERRORED means the\n // contrarian voice was never heard — that voids the quorum (no_quorum), it is\n // not silently skipped. Only under absolute_quorum; every other policy keeps\n // the pre-#4132 behavior of proceeding with the quickMode result.\n if (escalation.errored && input.errorPolicy === 'absolute_quorum') {\n logger.warn('Contrarian check errored under absolute_quorum — degrading to no_quorum (#4132)');\n return {\n degradeReason: 'no_quorum: re-run — contrarian check errored (absolute_quorum quick-mode)',\n contrarianCheck,\n };\n }\n if (!escalation.shouldEscalate) return { contrarianCheck };\n logger.warn('Contrarian escalation: re-running with full vote', {\n reason: escalation.reason,\n confidence: escalation.confidence,\n });\n return {\n escalated: await ctx.revote({ ...input, quickMode: false }, logger, opts),\n contrarianCheck,\n };\n}\n","/**\n * Consensus Vote — Recording Helpers\n *\n * Memory and outcome store recording for consensus votes.\n * Extracted from consensus-vote.ts for file size compliance.\n *\n * @module mcp/tools/consensus-vote-recording\n * (Source: Issue #753 memory, Issue #1134 cold start)\n */\n\nimport {\n createLogger,\n getErrorMessage,\n getTimeProvider,\n getRandomProvider,\n} from '../../core/index.js';\nimport type { AgentVoteResult } from '../../cli/vote-types.js';\nimport type { ConsensusResult } from '../../consensus/types.js';\nimport type { VoteRecord, VoteRecordPrBinding } from '../../audit/vote-record.js';\nimport type { ErrorPolicy } from './consensus-vote-types.js';\nimport {\n persistVoteRecord,\n readVoteRecords,\n resolveVoteRecordsPath,\n voteRecordWriteFailedMessage,\n} from '../../audit/vote-record-store.js';\nimport { mkdirSync } from 'node:fs';\nimport { dirname } from 'node:path';\n\nimport { FileLockTimeoutError, withFileLock } from '../../utils/file-lock.js';\nimport { getToolMemory } from './tool-memory.js';\nimport { throwIfVoteCancelled, VoteCancelledError } from './consensus-vote-cancelled.js';\nimport {\n getOutcomeStore,\n categorizeOutcomeErrorMessage,\n} from '../../orchestration/outcomes/index.js';\nimport { CLI_NAMES, type CliNameLiteral } from '../../config/model-capabilities-types.js';\nimport { servedOutcomeFields } from '../../orchestration/outcomes/outcome-served-model.js';\n\nconst logger = createLogger({ tool: 'consensus-vote' });\n\n/**\n * Records a completed consensus vote to session memory and, when measured,\n * the learning and outcome stores. Best-effort.\n *\n * When every vote is simulated, this is a no-op: simulated votes are random\n * (#2319) and must not seed the learning store or outcome store, otherwise\n * test/demo runs poison real routing decisions.\n * A `no_quorum` decision records only the task occurrence because the panel\n * measured no verdict to learn from or feed into adaptive routing (#5544).\n */\nexport function recordVoteSuccess(args: {\n decisionId: string;\n proposal: string;\n strategy: string;\n decision: VoteRecord['decision'];\n durationMs: number;\n approvalPercentage?: number;\n votes?: readonly AgentVoteResult[];\n}): void {\n const allSimulated =\n args.votes !== undefined &&\n args.votes.length > 0 &&\n args.votes.every((v) => v.source === 'simulation');\n if (allSimulated) {\n logger.debug('Skipping memory + outcome recording — all votes simulated');\n return;\n }\n\n try {\n const memory = getToolMemory();\n memory.recordTask({\n approach: `Consensus vote: ${args.strategy} on \"${args.proposal.slice(0, 50)}\"`,\n challenges: [],\n durationMs: args.durationMs,\n });\n if (args.decision !== 'no_quorum') {\n memory.recordLearning({\n pattern: `${args.strategy} vote → ${args.decision}`,\n context: `proposal=\"${args.proposal.slice(0, 40)}\" duration=${String(args.durationMs)}ms`,\n confidence: learningConfidence(args.decision, args.approvalPercentage),\n source: 'consensus-vote',\n });\n void memory.runPromotionPipeline().catch((error: unknown) => {\n logger.warn('Promotion pipeline failed', { error });\n });\n }\n } catch (error: unknown) {\n logger.warn('Failed to record vote success to memory', { error: getErrorMessage(error) });\n }\n\n if (args.decision === 'no_quorum') return;\n // Also record to outcome store for adaptive routing feedback (#1551).\n // recordVoteOutcomes already filters per-vote `source === 'simulation'`,\n // but we keep the all-simulated guard above to skip the memory writes too.\n if (args.votes !== undefined) {\n recordVoteOutcomes(args.votes, args.decisionId);\n }\n}\n\nfunction learningConfidence(\n decision: Exclude<VoteRecord['decision'], 'no_quorum'>,\n approvalPercentage: number | undefined\n): number {\n if (approvalPercentage === undefined) return 0.8;\n const approvalConfidence = approvalPercentage / 100;\n return decision === 'approved' ? approvalConfidence : 1 - approvalConfidence;\n}\n\n/** Strategy values that map cleanly onto a {@link VoteRecord} strategy. */\nconst VOTE_RECORD_STRATEGIES: ReadonlySet<VoteRecord['strategy']> = new Set([\n 'simple_majority',\n 'supermajority',\n 'unanimous',\n 'higher_order',\n 'opinion_wise',\n 'proof_of_learning',\n]);\n\n/** Narrow an arbitrary strategy string to the record enum, defaulting safely. */\nfunction toRecordStrategy(strategy: string): VoteRecord['strategy'] {\n return VOTE_RECORD_STRATEGIES.has(strategy as VoteRecord['strategy'])\n ? (strategy as VoteRecord['strategy'])\n : 'simple_majority';\n}\n\n/**\n * Structured outcome of the best-effort authentic-vote-record persistence\n * (#3991). Surfaced in the `consensus_vote` result so an MCP caller can SEE\n * whether the record was written and, when not, WHY + how to fix — previously a\n * skipped/failed persist was only a server-side WARN invisible to MCP clients.\n *\n * Reason vocabulary (#3991, Option B). Since the runtime ledger now routes\n * through `nexusDataPath` under `governance/`, the path essentially always\n * resolves to a writable `.nexus-agents/governance/` location — so the normal\n * case is `persisted: true`. The former `'no-repo-root'` reason is OBSOLETE\n * (there is always a homedir/sandbox/repo fallback): a non-persist is now either\n * `'empty-panel'` or `'all-simulated'` (skipped by design), `'write-failed'`\n * (the data dir was unwritable, or a fail-closed traversal rejection), or\n * `'read-back-missed'` (the appended record could not be read back).\n */\nexport type VoteRecordPersistOutcome =\n | {\n readonly persisted: true;\n readonly record: VoteRecord;\n /** The ledger the record was written to AND read back from (#6531). */\n readonly path: string;\n }\n | {\n readonly persisted: false;\n /**\n * `read-back-missed` (#6531): the append returned, but the record is not\n * on the ledger under its id and hash. Never reported as written.\n */\n readonly reason: 'empty-panel' | 'all-simulated' | 'write-failed' | 'read-back-missed';\n readonly detail: string;\n };\n\n/**\n * Persist an authentic, self-hashed vote record (tamper-evident record set +\n * monotonic sequence, #3927) at vote time (#3897). Best-effort: a persist\n * failure must never fail the vote, so the store swallows + logs. Skips\n * empty panels (no seat attribution) and all-simulated runs (random output\n * must not seed a committed record). Errored seats remain attributed in the\n * input array, so an all-errored panel can still persist its no-quorum record.\n *\n * RUNTIME LEDGER (#3991, design vote 7-0 Option B): the path routes through\n * `nexusDataPath('governance', ...)`, landing in a writable\n * `.nexus-agents/governance/` location (sandbox / repo-preferred / homedir), so\n * `persisted: true` is the normal case. Returns a structured\n * {@link VoteRecordPersistOutcome} so the caller can surface a non-persist to MCP\n * clients:\n * - `empty-panel` — no seats were attributed; persistence is refused;\n * - `all-simulated` — every vote was simulated; a committed record would seed\n * governance from random output (#2319);\n * - `write-failed` — the data dir was unwritable (or a fail-closed traversal\n * rejection); `detail` carries the actionable unwritable-data-dir guidance.\n */\n/**\n * Everything {@link recordAuthenticVote} needs. Named rather than inline: the\n * doc comments the required fields deserve pushed the function past its\n * line cap, and the cap is there to be answered with a decision (#6008).\n */\ninterface RecordAuthenticVoteArgs {\n proposal: string;\n strategy: string;\n result: ConsensusResult;\n votes: readonly AgentVoteResult[];\n correlationId?: string | undefined;\n /** Authority-tier ratification subject (#4004) — bound into the record's self-hash. */\n ratifies?: string | undefined;\n /** Governor-path PR binding (#5130) — bound into the record's self-hash as `ratifiesPr`. */\n ratifiesPr?: VoteRecordPrBinding | undefined;\n /** #4053: vote voided by an error-policy short-circuit → persist `no_quorum`. */\n errorVoided?: boolean | undefined;\n /** Declared options; see `BuildVoteRecordInput.declaredOptions` (#6049). */\n declaredOptions: readonly string[] | undefined;\n /**\n * The decision `resolveVoteDecision` already produced for the response.\n *\n * Required — including its `undefined` case — because deriving it a second\n * time inside the record store is what let the chain say `approved` for a\n * vote the tool reported as `no_quorum` (#4986). A caller that has the\n * resolved decision must hand it over rather than let the store guess.\n */\n resolvedDecision: VoteRecord['decision'] | undefined;\n /**\n * The error policy the panel ran under (#6211, schema 1.11) — the EFFECTIVE\n * policy `executeVoting` stamped on its result, not the raw tool input.\n *\n * Required — including its `undefined` case — on the `resolvedDecision`\n * rule: both producers (the MCP handler and the CLI `vote` command) narrow\n * `ExtendedVotingResult` before reaching here, and an optional field is\n * exactly how #5362 lost `optionGate` at that narrowing with no compile\n * error. `undefined` is honest only for a result built without\n * `executeVoting`, where no policy was applied; the record then carries no\n * key and the ledger gate reports it as `unrecorded`.\n */\n errorPolicy: ErrorPolicy | undefined;\n /**\n * The async job's cancel signal (#6735). Checked inside the ledger lock,\n * synchronously before the append: the lock wait is async, so a cancel can\n * land after the vote's own checks and before the write. Absent in sync mode.\n */\n signal?: AbortSignal | undefined;\n}\n\nexport async function recordAuthenticVote(\n args: RecordAuthenticVoteArgs\n): Promise<VoteRecordPersistOutcome> {\n if (args.votes.length === 0) {\n const detail = 'Authentic vote record NOT persisted: empty panel has no voter attribution.';\n logger.warn(detail);\n return { persisted: false, reason: 'empty-panel', detail };\n }\n // Non-empty here (refused above), so `every` cannot answer the empty case.\n const allSimulated = args.votes.every((v) => v.source === 'simulation');\n if (allSimulated) {\n logger.debug('Skipping authentic vote record — all votes simulated');\n return {\n persisted: false,\n reason: 'all-simulated',\n detail:\n 'All votes were simulated; a committed vote record would seed governance ' +\n 'from random output (#2319), so persistence is skipped by design.',\n };\n }\n // Resolve the data-dir path up front (mirrors the store's own precedence: env\n // override > nexusDataPath) so a fail-closed/unwritable case surfaces an\n // actionable note carrying the resolved path. Post-#3991 this almost always\n // returns a path; `undefined` is the rare traversal-rejection/resolver-failure\n // case and is classified as write-failed.\n const resolvedPath = resolveVoteRecordsPath();\n if (resolvedPath === undefined) {\n const detail = voteRecordWriteFailedMessage('<unresolved>');\n // persistVoteRecord won't be reached below to log its own WARN, so emit here.\n logger.warn(detail);\n return { persisted: false, reason: 'write-failed', detail };\n }\n const id = `vote-${String(getTimeProvider().now())}-${getRandomProvider().random().toString(36).slice(2, 9)}`;\n let record: VoteRecord | undefined;\n try {\n record = await underLedgerLock(resolvedPath, () => {\n // #6735: no `await` between this check and the append, so a cancel that\n // landed during the lock wait appends nothing.\n throwIfVoteCancelled(args.signal, args.votes, args.votes.length);\n return persistVoteRecord(storeInput(args, id, resolvedPath));\n });\n } catch (error: unknown) {\n if (error instanceof VoteCancelledError) throw error;\n return lockFailure(resolvedPath, error);\n }\n if (record === undefined) {\n // The path resolved but the append threw (data dir unwritable) —\n // persistVoteRecord already WARNed with the underlying error + path. Surface\n // the actionable unwritable-data-dir guidance with the concrete path.\n return {\n persisted: false,\n reason: 'write-failed',\n detail: voteRecordWriteFailedMessage(resolvedPath),\n };\n }\n return confirmPersisted(record, resolvedPath);\n}\n\n/** The store input for one vote, written to `filePath`. */\nfunction storeInput(\n args: RecordAuthenticVoteArgs,\n id: string,\n filePath: string\n): Parameters<typeof persistVoteRecord>[0] {\n return {\n id,\n proposal: args.proposal,\n strategy: toRecordStrategy(args.strategy),\n result: args.result,\n votes: args.votes,\n declaredOptions: args.declaredOptions,\n resolvedDecision: args.resolvedDecision,\n ...(args.errorVoided !== undefined ? { errorVoided: args.errorVoided } : {}),\n ...(args.correlationId !== undefined ? { correlationId: args.correlationId } : {}),\n ...(args.ratifies !== undefined ? { ratifies: args.ratifies } : {}),\n ...(args.ratifiesPr !== undefined ? { ratifiesPr: args.ratifiesPr } : {}),\n ...(args.errorPolicy !== undefined ? { errorPolicy: args.errorPolicy } : {}),\n // #6531: write to the path resolved by the caller, so the read-back and the\n // path the caller prints are the file the store wrote.\n filePath,\n logger,\n };\n}\n\n/**\n * Run the store's append while holding the ledger's cross-process lock\n * (#6531). The store reads the ledger tip and then appends, synchronously,\n * so two PROCESSES appending at once took the same tip and wrote the same\n * sequence. The lock is taken here rather than inside the store to keep the\n * governor-path store unchanged; this recorder is the store's only production\n * writer. The wait is async (#6548 review): a contended ledger must not stall\n * the MCP server's event loop.\n */\nasync function underLedgerLock<T>(path: string, write: () => T): Promise<T> {\n mkdirSync(dirname(path), { recursive: true });\n return withFileLock(`${path}.lock`, write);\n}\n\n/** The outcome when the lock could not be taken (or its directory not created). */\nfunction lockFailure(path: string, error: unknown): VoteRecordPersistOutcome {\n logger.warn('Failed to take the vote-record ledger lock', {\n error: getErrorMessage(error),\n path,\n });\n const detail =\n error instanceof FileLockTimeoutError\n ? `Authentic vote record NOT persisted (${path}): timed out after ` +\n `${String(error.timeoutMs)}ms waiting for the ledger lock ${error.lockPath}, ` +\n 'held by another live process.'\n : voteRecordWriteFailedMessage(path);\n return { persisted: false, reason: 'write-failed', detail };\n}\n\n/** The outcome for an append that returned `record`: persisted only if it reads back (#6531). */\nfunction confirmPersisted(record: VoteRecord, path: string): VoteRecordPersistOutcome {\n if (ledgerHolds(path, record)) return { persisted: true, record, path };\n const detail =\n `record ${record.id} (sequence ${String(record.sequence)}) is not in ${path} ` +\n 'after the append; it was NOT persisted';\n logger.error(detail);\n return { persisted: false, reason: 'read-back-missed', detail };\n}\n\n/**\n * True when the ledger holds `record` under its id AND hash (#6531). Matching\n * the hash too means a different record that happens to share the id does not\n * count as this one. An unreadable ledger holds nothing.\n */\nfunction ledgerHolds(path: string, record: VoteRecord): boolean {\n try {\n return readVoteRecords(path).records.some(\n (onDisk) => onDisk.id === record.id && onDisk.hash === record.hash\n );\n } catch (error: unknown) {\n logger.warn('Vote-record read-back failed', { error: getErrorMessage(error), path });\n return false;\n }\n}\n\n/** Records a failed consensus vote to session memory. Best-effort. */\nexport function recordVoteError(proposal: string, errorMessage: string): void {\n try {\n const memory = getToolMemory();\n memory.recordError({\n error: `Consensus vote failed: ${errorMessage.slice(0, 150)}`,\n solution: 'Pending - vote execution failed',\n filePattern: 'mcp/tools/consensus-vote',\n });\n } catch (error: unknown) {\n logger.warn('Failed to record vote error', { error: getErrorMessage(error) });\n }\n}\n\n/**\n * Records per-vote outcomes to the outcome store for adaptive routing.\n * `success` means the seat answered (`source === 'llm'`), not that its answer\n * was validated. The decision ID joins these rows to the cost and vote records.\n * (Issue #1134 — cold start mitigation)\n */\nexport function recordVoteOutcomes(votes: readonly AgentVoteResult[], decisionId: string): void {\n try {\n const store = getOutcomeStore();\n const now = new Date().toISOString();\n for (const vote of votes) {\n if (vote.source === 'simulation') continue;\n const cliName =\n vote.cli !== undefined && (CLI_NAMES as readonly string[]).includes(vote.cli)\n ? (vote.cli as CliNameLiteral)\n : ('unknown' as const);\n const voteSuccess = vote.source === 'llm';\n store.append({\n id: `vote-${String(getTimeProvider().now())}-${getRandomProvider().random().toString(36).slice(2, 8)}`,\n cli: cliName,\n category: 'planning',\n model: 'consensus',\n success: voteSuccess,\n durationMs: vote.processingTimeMs,\n timestamp: now,\n source: 'consensus',\n // #6822 — joins this row to its DecisionCostRecord and VoteRecord.\n traceId: decisionId,\n // #2662 — carry the voter role so the stratified outcome report\n // can break consensus results down by role.\n voterRole: vote.role,\n // #6624 — `model` stays the `consensus` marker; the model that sat\n // this seat and its cost go beside it, priced like the vote rollup.\n // #6660 — the model the adapter REPORTED answering, never `vote.model`\n // (the alias requested): a seat that fell back to another model was\n // named, and priced, as the one it asked for.\n ...servedOutcomeFields({\n model: vote.servedModel,\n gatewayArm: vote.gatewayArm,\n inputTokens: vote.inputTokens,\n outputTokens: vote.outputTokens,\n }),\n ...(!voteSuccess && vote.error !== undefined\n ? {\n failureCategory: categorizeOutcomeErrorMessage(vote.error),\n errorMessage: vote.error.slice(0, 500),\n }\n : {}),\n });\n }\n } catch (error: unknown) {\n logger.debug('Best-effort vote outcome recording failed', { error: getErrorMessage(error) });\n }\n}\n","/**\n * Cross-process advisory file lock (#6531).\n *\n * A lock is a sibling file created with `O_CREAT | O_EXCL` (`'wx'`), so exactly\n * one process can create it. The holder writes a unique owner token into it —\n * `<host>:<pid>:<random>` — and on release removes it only while the token is\n * still its own.\n *\n * WHY a lock and not a bare `O_APPEND` write: an append-only ledger that stamps\n * each line with `max(sequence) + 1` has to READ the tip before it writes, and\n * `O_APPEND` makes only the write atomic. Two processes that read the same tip\n * wrote the same sequence (#6531). The read and the append share this lock.\n *\n * ASYNC (#6548 review): acquisition polls with `setTimeout`, so a contended\n * lock never blocks the event loop — the MCP server keeps serving while a vote\n * waits for the ledger.\n *\n * STALENESS. A lock is abandoned when its owner cannot release it:\n * - owner on THIS host: stale iff its pid is no longer running. A live holder\n * is never broken, however slow — breaking it would admit a second writer;\n * - owner on another host, or an unreadable token (a crash between create and\n * write, or a foreign format): stale iff older than `staleMs`.\n *\n * BREAKING WITHOUT ABA (#6548 review). \"Observe stale, then remove the path\" is\n * unsafe: between the two, another process may break the same stale lock and\n * acquire a fresh one, which the late remover then deletes — two writers.\n * Breakers therefore serialize on a second O_EXCL file, `<lock>.break`, and\n * under it RE-READ the lock and judge it again, removing it only if the lock\n * now at the path is itself stale. A lock acquired since the first look has a\n * live owner (or a fresh mtime) and is left alone. That judge-then-unlink is\n * safe because nothing else can change the path in between: acquirers only\n * create an ABSENT file, other breakers are excluded by `.break`, and a stale\n * owner does not release (a dead pid cannot; the cross-host/age rule is the\n * one residual — a holder slower than `staleMs` on another host).\n *\n * The `.break` file guards a few syscalls. If its owner died inside them it is\n * removed by the same liveness/age rule, without the token compare — a\n * residual that needs a crash inside that window plus two more concurrent\n * breakers.\n *\n * @module utils/file-lock\n */\n\nimport { closeSync, openSync, readFileSync, statSync, unlinkSync, writeSync } from 'node:fs';\nimport { randomBytes } from 'node:crypto';\nimport { hostname } from 'node:os';\n\n/** Tuning for {@link withFileLock}. All durations are milliseconds. */\nexport interface FileLockOptions {\n /** Give up acquiring after this long. Default 10 000. */\n readonly timeoutMs?: number | undefined;\n /** Age after which a lock whose owner cannot be checked is abandoned. Default 30 000. */\n readonly staleMs?: number | undefined;\n /** Base delay between acquisition attempts (jittered up to 2x). Default 15. */\n readonly retryMs?: number | undefined;\n /**\n * Test seam: runs after a lock is observed stale and before the break is\n * attempted — the window the ABA regression test parks a process in.\n */\n readonly onStaleObserved?: (() => void | Promise<void>) | undefined;\n}\n\nconst DEFAULT_TIMEOUT_MS = 10_000;\nconst DEFAULT_STALE_MS = 30_000;\nconst DEFAULT_RETRY_MS = 15;\n\n/** Thrown when the lock could not be acquired within `timeoutMs`. */\nexport class FileLockTimeoutError extends Error {\n constructor(\n readonly lockPath: string,\n readonly timeoutMs: number\n ) {\n super(`Timed out after ${String(timeoutMs)}ms waiting for lock ${lockPath}`);\n this.name = 'FileLockTimeoutError';\n }\n}\n\n/** What a lock file held when read. */\ninterface LockSnapshot {\n readonly token: string;\n readonly mtimeMs: number;\n}\n\nfunction errnoCode(error: unknown): string | undefined {\n if (typeof error !== 'object' || error === null) return undefined;\n const code = (error as { readonly code?: unknown }).code;\n return typeof code === 'string' ? code : undefined;\n}\n\nfunction newToken(): string {\n return `${hostname()}:${String(process.pid)}:${randomBytes(8).toString('hex')}`;\n}\n\n/** One attempt: true when this call created the lock file. */\nfunction tryCreate(lockPath: string, token: string): boolean {\n let fd: number;\n try {\n fd = openSync(lockPath, 'wx', 0o600);\n } catch (error: unknown) {\n if (errnoCode(error) === 'EEXIST') return false;\n throw error;\n }\n try {\n writeSync(fd, token);\n } finally {\n closeSync(fd);\n }\n return true;\n}\n\n/** The lock's token and mtime, or undefined when there is no lock. */\nfunction readLock(lockPath: string): LockSnapshot | undefined {\n try {\n const { mtimeMs } = statSync(lockPath);\n return { token: readFileSync(lockPath, 'utf-8'), mtimeMs };\n } catch (error: unknown) {\n if (errnoCode(error) === 'ENOENT') return undefined;\n throw error;\n }\n}\n\n/** True while `pid` is a running process (EPERM: running, owned by another user). */\nfunction isRunning(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch (error: unknown) {\n return errnoCode(error) === 'EPERM';\n }\n}\n\n/** The staleness rule in the module doc. */\nfunction isStale(lock: LockSnapshot, staleMs: number): boolean {\n const match = /^(.+):(\\d+):[0-9a-z]+$/.exec(lock.token);\n if (match?.[1] === hostname()) return !isRunning(Number(match[2]));\n return Date.now() - lock.mtimeMs > staleMs;\n}\n\n/** Remove the file only while it still carries `token`. */\nfunction removeIfOwned(path: string, token: string): void {\n if (readLock(path)?.token === token) unlinkSync(path);\n}\n\n/** Unlink, tolerating a file that is already gone. */\nfunction unlinkIfPresent(path: string): void {\n try {\n unlinkSync(path);\n } catch (error: unknown) {\n if (errnoCode(error) !== 'ENOENT') throw error;\n }\n}\n\n/**\n * Break `lockPath` if it is stale, removing only the exact lock judged stale.\n * Returns without breaking when another breaker holds `.break`; the caller\n * retries.\n */\nasync function breakIfStale(\n lockPath: string,\n staleMs: number,\n onStaleObserved: FileLockOptions['onStaleObserved']\n): Promise<void> {\n const seen = readLock(lockPath);\n if (seen === undefined || !isStale(seen, staleMs)) return;\n await onStaleObserved?.();\n\n const breakPath = `${lockPath}.break`;\n const breakToken = newToken();\n if (!tryCreate(breakPath, breakToken)) {\n const breaker = readLock(breakPath);\n if (breaker !== undefined && isStale(breaker, staleMs)) unlinkIfPresent(breakPath);\n return;\n }\n try {\n const now = readLock(lockPath);\n if (now !== undefined && isStale(now, staleMs)) {\n unlinkSync(lockPath);\n }\n } finally {\n removeIfOwned(breakPath, breakToken);\n }\n}\n\nfunction delay(ms: number): Promise<void> {\n return new Promise((resolveDelay) => setTimeout(resolveDelay, ms));\n}\n\n/**\n * Run `body` while holding the cross-process lock at `lockPath`. The directory\n * holding `lockPath` must exist.\n *\n * @throws {FileLockTimeoutError} when the lock is not acquired within\n * `timeoutMs`; `body` has not run in that case.\n */\nexport async function withFileLock<T>(\n lockPath: string,\n body: () => T | Promise<T>,\n options: FileLockOptions = {}\n): Promise<T> {\n const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const staleMs = options.staleMs ?? DEFAULT_STALE_MS;\n const retryMs = options.retryMs ?? DEFAULT_RETRY_MS;\n const token = newToken();\n const deadline = Date.now() + timeoutMs;\n while (!tryCreate(lockPath, token)) {\n await breakIfStale(lockPath, staleMs, options.onStaleObserved);\n if (Date.now() >= deadline) throw new FileLockTimeoutError(lockPath, timeoutMs);\n await delay(retryMs + Math.floor(Math.random() * retryMs));\n }\n try {\n return await body();\n } finally {\n removeIfOwned(lockPath, token);\n }\n}\n","/**\n * Schema of a cancelled vote's partials (#6735). A leaf module so both the\n * store (`job-result-store.ts`, which embeds it in `JobResultSchema`) and the\n * writer (`job-cancelled-partial.ts`, which imports the store) can use it\n * without an import cycle.\n *\n * @module mcp/jobs/job-cancelled-partial-schema\n */\n\nimport { z } from 'zod';\n\n/**\n * The votes a cancelled `consensus_vote` (#6735) or `pr_review` (#6750) had\n * cast before the cancel.\n *\n * This is NOT a decision and carries none. No verdict is computed from these\n * seats: a cancelled vote never reaches the engine, the vote-record ledger or\n * the correlation tracker, and a cancelled review writes no review record. `seatsCast` counts `partialVotes` (derived by the\n * writer, so the two cannot disagree) against `panelSize`, the seats the panel\n * convened, so a reader sees the coverage — `0` of `3` included — rather than\n * a tally that looks complete. The votes are the collector's own\n * `AgentVoteResult`s, typed `unknown` here because the store is tool-agnostic.\n */\nexport const CancelledPartialSchema = z.strictObject({\n partialVotes: z.array(z.unknown()),\n seatsCast: z.number().int().nonnegative(),\n panelSize: z.number().int().nonnegative(),\n});\nexport type CancelledPartial = z.infer<typeof CancelledPartialSchema>;\n","/**\n * Job-result store for async-mode MCP tools (#3042, Stage 1 of #2631).\n *\n * Persists the final result of a background-dispatched MCP tool\n * invocation to `<NEXUS_DATA_DIR>/jobs/result-<jobId>.json`. Lets a\n * caller dispatch a long-running tool via `dispatch: 'async'`, receive a\n * `jobId` immediately, and poll for the result via `get_job_result`\n * (or any other reader that imports `readJobResult`).\n *\n * **Why a sidecar file (not the structured-task-state log):** Stage 1\n * deliberately doesn't extend `StructuredTaskState` — that schema change\n * is Stage 2 (#3043). Putting the result in a sidecar file lets the\n * async-mode protocol ship and be validated end-to-end before the schema\n * migration lands. Once Stage 2 ships, this store can be deprecated:\n * `query_task_state` will return the result inline and the sidecar files\n * become legacy that the next cleanup sweep can remove.\n *\n * **Why per-repo storage (`jobs` is in `PER_REPO_SUBDIRS`):** a job\n * dispatched on repo A should not be pollable on repo B. The split\n * matches `tasks/state-orch-*.jsonl` which is also per-repo.\n *\n * Status lifecycle: `pending` → (`complete` | `failed` | `cancelled`).\n * `cancelled` isn't written by Stage 1 (no `cancel_job` yet — that's\n * a follow-up under the same Stage 1 umbrella) but the type space\n * carries it so the next PR doesn't churn the schema.\n *\n * @module mcp/jobs/job-result-store\n */\n\nimport { existsSync, readdirSync, unlinkSync, writeFileSync, chmodSync, mkdirSync } from 'node:fs';\nimport { dirname } from 'node:path';\n\nimport { z } from 'zod';\n\nimport { createLogger, getTimeProvider } from '../../core/index.js';\nimport { nexusDataPath, nexusDataPathEnsure } from '../../config/nexus-data-dir.js';\nimport { resolveClassGuardMs, type OperationClassName } from '../../config/timeouts.js';\nimport { sanitizeErrorDetails, sanitizeStringLeaves } from '../../security/output-sanitizer.js';\nimport { assertValidJobId } from './job-id.js';\nimport { VERSION } from '../../version.js';\nimport { readIndexEntry } from './job-idempotency.js';\nimport {\n candidateJobResultPaths,\n readJobResultAcrossCandidates,\n readJobResultFile,\n syncAlternateCandidates,\n} from './job-result-candidates.js';\n\nexport {\n candidateJobResultPaths,\n _setCandidatePathsResolverForTests,\n} from './job-result-candidates.js';\nexport { JobFailureDetailSchema, type JobFailureDetail } from './job-failure-detail.js';\nimport {\n JobFailureDetailSchema,\n type JobFailureDetail,\n validateAndSanitizeFailureDetail,\n} from './job-failure-detail.js';\nimport { CancelledPartialSchema } from './job-cancelled-partial-schema.js';\n\nconst logger = createLogger({ component: 'job-result-store' });\n\n/** Lifecycle status of a job-result record. */\nexport const JobStatusSchema = z.enum(['pending', 'complete', 'failed', 'cancelled']);\nexport type JobStatus = z.infer<typeof JobStatusSchema>;\n\n/**\n * One on-disk job-result record. Versioned so future readers can\n * tell which Stage wrote it — bump on schema break.\n */\nexport const JobResultSchema = z.object({\n /** Format version. Currently `1` — bump if the shape changes. */\n v: z.literal(1),\n jobId: z.string().min(1),\n /** Tool that was invoked (e.g. `orchestrate`). */\n toolName: z.string().min(1),\n status: JobStatusSchema,\n createdAt: z.iso.datetime(),\n /** Set when the job leaves `pending` — either via `complete` or `failed` or `cancelled`. */\n completedAt: z.iso.datetime().optional(),\n /**\n * Structured payload the synchronous mode would have returned. Present\n * only when `status === 'complete'`. Shape is tool-specific — readers\n * cast to the tool's known output type after status check.\n */\n result: z.unknown().optional(),\n /**\n * Failure message when `status === 'failed'`. Cannot be paired with\n * `result` — the discriminator is `status`.\n */\n error: z.string().optional(),\n /**\n * Structured failure detail when `status === 'failed'` (#4375).\n * Holds normalized adapter, transport, and category information without\n * raw response bodies or prompt strings.\n */\n failureDetail: JobFailureDetailSchema.optional(),\n /**\n * Machine-readable reason for a `failed` record that was NOT settled by the\n * process that ran the job (#6224). `abandoned` is written only by\n * {@link pruneJobRecords}: the record was `pending` past the runaway guard\n * (so no live process could still own it) AND past the retention window, and\n * the sweep rewrote it rather than deleting it. Absent on every record the\n * job's own process wrote — `error` alone carries those failures.\n */\n errorKind: z.literal('abandoned').optional(),\n /**\n * Whether the tool's `run` callback accepts `runAsJob`'s `AbortSignal`\n * (#4972).\n *\n * `cancel_job` writes a `cancelled` record whether or not the tool can act\n * on the signal — as `cancel-job-tool.ts` says, \"a tool that IGNORES the\n * signal still runs to completion… but its record stays `cancelled`\". A\n * reader of that record could not tell the two apart, so `cancelled` claimed\n * more than was known.\n *\n * This is a STRUCTURAL fact — the callback's arity — not a behavioural one.\n * A tool may accept the signal and never await on it, so `true` means\n * \"cancellation can reach this tool\", not \"the work stopped\". Absent means\n * the writer did not report it, which is not the same as `false`.\n */\n signalAccepted: z.boolean().optional(),\n /**\n * `VERSION` of the nexus-agents process that WROTE this record (#5008) —\n * i.e. the build that ran the job, not the build that reads it back.\n *\n * `get_job_result` is itself a wrapped tool, so its `_meta['nexus-agents/build']`\n * stamp (#5056) names the READER's build. After a mid-session global install\n * the reader and the producer differ, and only the record can say which\n * build produced the payload. Each writer re-stamps on its own transition,\n * so a terminal record names the process that settled it.\n *\n * Optional so v1 records written before this field existed still parse:\n * on a SIDECAR record, absence means \"produced before this field existed\",\n * not a version of `undefined`. A record adapted from the task-state log\n * (`jobResultFromTaskState`, selected by `NEXUS_JOB_RESULT_SOURCE=task_state`)\n * NEVER carries it — that log records no producer version — so a reader\n * must consult the source (`get_job_result`'s `producerVersionSource`)\n * before reading absence as age. The value is recorded verbatim, including\n * `'dev'` — readers MUST run it through {@link isMeasuredBuildVersion}\n * before treating two stamps as comparable.\n */\n producerVersion: z.string().optional(),\n /**\n * When the job body last heartbeat — `runAsJob`'s `progress()` callback,\n * `heartbeatJob`, or a pipeline-bus event the body emitted (#6162). Present\n * once the body has heartbeat at least once and carried onto the terminal\n * record, so a settled job still says when it last moved (a wedged `failed`\n * record: the last progress before the silence). Absence means \"no heartbeat\n * recorded\", never \"no progress\" — a body that predates the callback, or one\n * that never adopted it, leaves the field off. On a long guard the reaper in\n * `run-as-job.ts` fails a body that stops heartbeating as wedged, measuring\n * silence from this stamp (or from job start when there is none).\n */\n lastProgressAt: z.iso.datetime().optional(),\n /**\n * What a cancelled vote had collected when `cancel_job` fired (#6735).\n * Present only on a `cancelled` record, and only when the body settled after\n * the cancel and reported what it had. Written only by\n * `attachCancelledPartial` (`job-cancelled-partial.ts`), never by a status\n * transition.\n */\n cancelledPartial: CancelledPartialSchema.optional(),\n});\nexport type JobResult = z.infer<typeof JobResultSchema>;\n\n/**\n * The value `VERSION` takes when the build-time define is absent (a source\n * checkout run through tsx, or an unbundled test). Two local builds at\n * different commits both read this way.\n */\nconst UNMEASURED_BUILD_VERSION = 'dev';\n\n/**\n * Whether a recorded build version actually identifies a build (#5008).\n *\n * `false` for an absent or empty value and for `'dev'`. `'dev'` is what\n * `VERSION` reads without the build-time define, so two `'dev'` stamps say\n * nothing about whether the same code wrote them — treating that as a match\n * would be exactly the misreport the field exists to prevent. A reader that\n * compares producer to reader must gate the comparison on this.\n */\nexport function isMeasuredBuildVersion(version: string | undefined): boolean {\n return version !== undefined && version !== '' && version !== UNMEASURED_BUILD_VERSION;\n}\n\n/**\n * The operation class `runJobInBackground` guards every job body with. Spelled\n * here rather than imported from `run-as-job.ts` because that module imports\n * this one; the literal is typed against `OperationClassName` so a rename\n * there is a compile error here.\n */\nconst ASYNC_JOB_BODY_CLASS: OperationClassName = 'async-job-body';\n\n/**\n * Slack added to the resolved guard before a `pending` record is called\n * abandoned (#6224).\n *\n * The guard is a `setTimeout`, which fires no earlier than `guardMs` but later\n * under event-loop starvation, and the terminal `writeJobFailed` it triggers is\n * a synchronous JSON write. A record read in that gap is a live job that is\n * still in the guard's `finally`, not an abandoned one. 30 s covers a starved\n * loop plus the write; it is deliberately under a minute so the boundary stays\n * within the resolution operators reason about (the guard is quoted in hours).\n */\nconst ABANDONED_TERMINAL_WRITE_SLACK_MS = 30_000;\n\n/** The fields the abandoned verdict reads — a record and a summary both carry them. */\ntype AbandonedProbe = Pick<JobResult, 'status' | 'createdAt'>;\n\n/**\n * Whether a `pending` record describes work no process is still doing (#4976).\n *\n * The record is durable; the work is a detached in-process promise. If the\n * process dies mid-body no terminal writer ever runs, and `writeJobPending`\n * refuses to overwrite an existing file — so the record stays `pending`\n * forever and a caller polling `get_job_result` waits on work that no longer\n * exists.\n *\n * The anchor is objective rather than a guess: `async-job-body` is the runaway\n * guard `runAsJob` applies to every body, so a live job CANNOT still be pending\n * past it — it would have been recorded `failed` by the guard. The anchor is\n * the guard as RESOLVED for this process (`resolveClassGuardMs`, the same call\n * `runJobInBackground` makes), not the declared 3,600,000 ms base: since #6159\n * an operator may raise the guard to 7,200,000 ms via\n * `NEXUS_TIMEOUT_CLASS_ASYNC_JOB_BODY_MS` or `NEXUS_TIMEOUT_MULTIPLIER`, and\n * anchoring on the base reported a job 61 minutes into a live 2-hour body as\n * abandoned while its guard had 59 minutes left (#6224). Resolved on every\n * call, never cached, so a reader sees the environment the writer ran under.\n *\n * Reported rather than written back. The record is evidence of what was\n * observed; overwriting it on read would destroy that. This is the same\n * treatment `notVerified` gives an audit chain that verified nothing. The one\n * exception is {@link pruneJobRecords}, which rewrites an abandoned record\n * only once it is also past the retention window.\n *\n * Reads only `status` and `createdAt` ({@link AbandonedProbe}), so it takes a\n * {@link JobSummary} as well as a full record: `list_jobs` and\n * `get_job_result` flag the same job with the same predicate (#6726).\n */\nexport function isAbandonedJob(record: AbandonedProbe, nowMs: number): boolean {\n return isAbandonedAt(record, nowMs, abandonedAfterMs());\n}\n\n/**\n * Milliseconds a `pending` record may be old before no live process can own it:\n * the resolved `async-job-body` guard plus {@link ABANDONED_TERMINAL_WRITE_SLACK_MS}.\n */\nfunction abandonedAfterMs(): number {\n return resolveClassGuardMs(ASYNC_JOB_BODY_CLASS) + ABANDONED_TERMINAL_WRITE_SLACK_MS;\n}\n\n/** The predicate with the threshold already resolved — one resolution per sweep. */\nfunction isAbandonedAt(record: AbandonedProbe, nowMs: number, abandonedAfter: number): boolean {\n if (record.status !== 'pending') return false;\n // An unparseable `createdAt` yields NaN, and every NaN comparison is false —\n // so an unknown age reports \"not abandoned\" without a separate guard. That is\n // the right default: killing a job whose age cannot be read would be a guess.\n const startedMs = Date.parse(record.createdAt);\n return nowMs - startedMs > abandonedAfter;\n}\n\n/**\n * Resolve the sidecar path for a given jobId. Throws for an id outside the\n * minted format: writers only ever receive minted ids, so one that is not is a\n * defect, not a path to build.\n */\nfunction jobResultPath(jobId: string): string {\n assertValidJobId(jobId);\n const primary =\n candidateJobResultPaths(jobId)[0] ?? nexusDataPathEnsure('jobs', `result-${jobId}.json`);\n mkdirSync(dirname(primary), { recursive: true });\n return primary;\n}\n\n/**\n * Write a job sidecar record with 0600 perms (#3753 defense-in-depth — the\n * payload may carry job result data; restrict to the owner if NEXUS_DATA_DIR is\n * ever shared). `chmodSync` after write guarantees the mode even when overwriting\n * a pre-existing (default-umask) file, which the `writeFileSync` mode option skips.\n */\nfunction persistJobRecord(path: string, record: JobResult): void {\n writeFileSync(path, JSON.stringify(record, null, 2), { mode: 0o600 });\n chmodSync(path, 0o600);\n}\n\n/**\n * Persist `record` as `jobId`'s primary sidecar and mirror it to every other\n * candidate path — the one write step every writer shares. Applies NO status\n * guard: each writer decides whether it may write before calling this.\n * Exported for the writers in sibling modules (`job-cancelled-partial.ts`).\n * @internal\n */\nexport function persistJobRecordAcrossCandidates(jobId: string, record: JobResult): void {\n const primaryPath = jobResultPath(jobId);\n persistJobRecord(primaryPath, record);\n syncAlternateCandidates(jobId, primaryPath, record, logger, persistJobRecord);\n}\n\n/** The heartbeat a terminal writer carries forward from the record it replaces (#6162). */\nfunction carriedProgress(existing: JobResult | null): Pick<JobResult, 'lastProgressAt'> {\n return existing?.lastProgressAt !== undefined ? { lastProgressAt: existing.lastProgressAt } : {};\n}\n\n/**\n * Every writer below takes a trailing `producerVersion` defaulting to the\n * running server's `VERSION` (#5008). The parameter is the DI seam: a test\n * can write a version that differs from `VERSION` and prove the stamp\n * round-trips from the injected value rather than from an ambient constant.\n */\n\n/**\n * Write the initial `pending` record for a new job. Idempotent: if a\n * record for `jobId` already exists (e.g. operator restart re-runs the\n * same idempotencyKey — Stage 1 follow-up), this is a no-op.\n *\n * Caller responsibility: generate a fresh `jobId` per call (Stage 1\n * doesn't yet deduplicate via idempotencyKey — that's #3042 follow-up).\n */\nexport function writeJobPending(\n jobId: string,\n toolName: string,\n signalAccepted?: boolean,\n producerVersion: string = VERSION\n): void {\n const path = jobResultPath(jobId);\n if (existsSync(path) || readJobResult(jobId) !== null) {\n logger.debug('Job result file already exists — leaving in place', { jobId });\n return;\n }\n const record: JobResult = {\n v: 1,\n jobId,\n toolName,\n status: 'pending',\n createdAt: new Date().toISOString(),\n ...(signalAccepted !== undefined ? { signalAccepted } : {}),\n producerVersion,\n };\n persistJobRecord(path, record);\n logger.debug('Wrote pending job record', { jobId, toolName, signalAccepted });\n}\n\n/**\n * Replace the record with a terminal `complete` status carrying the\n * structured payload. Caller writes the SAME shape the sync mode would\n * have returned, so a polling client can use the result interchangeably.\n *\n * COMPLETE-AFTER-CANCEL guard (#4017): if the job was already `cancelled`\n * (e.g. `cancel_job` landed while the work was in-flight — `runAsJob` does not\n * yet abort the underlying work), this is a NO-OP so the cancellation is not\n * silently rewritten back to `complete`. Symmetric with the caller-side\n * cancel-after-complete guard documented on {@link writeJobCancelled}.\n *\n * Write-path redaction: every string leaf of `result` passes through\n * {@link sanitizeErrorDetails}, as the `failed` path's `error` does and as\n * the synchronous tool path does for `structuredContent`. Keys and non-string\n * values are left alone, so the structure a poller reads is unchanged.\n */\nexport function writeJobComplete(\n jobId: string,\n toolName: string,\n result: unknown,\n producerVersion: string = VERSION\n): void {\n const existing = readJobResult(jobId);\n if (existing?.status === 'cancelled') {\n logger.debug('Skipping complete write — job already cancelled (preserving cancellation)', {\n jobId,\n toolName,\n });\n return;\n }\n const record: JobResult = {\n v: 1,\n jobId,\n toolName,\n status: 'complete',\n createdAt: existing?.createdAt ?? new Date().toISOString(),\n completedAt: new Date().toISOString(),\n result: sanitizeStringLeaves(result, (text) => sanitizeErrorDetails(text)),\n producerVersion,\n ...carriedProgress(existing),\n };\n persistJobRecordAcrossCandidates(jobId, record);\n logger.debug('Wrote complete job record', { jobId, toolName });\n}\n\n/**\n * Terminal `failed` status. `error` is the human-readable failure message.\n * Like {@link writeJobComplete}, a NO-OP when the job is already `cancelled`\n * (#4017) so a post-cancel failure cannot rewrite the cancellation.\n *\n * Write-path redaction (#4375): sanitizes `error` and any string fields in\n * `failureDetail` via {@link sanitizeErrorDetails} before persisting to disk.\n */\nexport function writeJobFailed(\n jobId: string,\n toolName: string,\n error: string,\n producerVersion: string = VERSION,\n failureDetail?: JobFailureDetail\n): void {\n const existing = readJobResult(jobId);\n if (existing?.status === 'cancelled') {\n logger.debug('Skipping failed write — job already cancelled (preserving cancellation)', {\n jobId,\n toolName,\n });\n return;\n }\n const sanitizedError = sanitizeErrorDetails(error);\n const validatedDetail = validateAndSanitizeFailureDetail(failureDetail);\n\n const record: JobResult = {\n v: 1,\n jobId,\n toolName,\n status: 'failed',\n createdAt: existing?.createdAt ?? new Date().toISOString(),\n completedAt: new Date().toISOString(),\n error: sanitizedError,\n ...(validatedDetail !== undefined ? { failureDetail: validatedDetail } : {}),\n producerVersion,\n ...carriedProgress(existing),\n };\n persistJobRecordAcrossCandidates(jobId, record);\n logger.debug('Wrote failed job record', { jobId, toolName, error: sanitizedError });\n}\n\n/**\n * Heartbeat `jobId` (#6162): stamp `lastProgressAt` on its `pending` record,\n * at `at` (an ISO instant; defaults to the time provider's now). The heartbeat\n * half of the liveness contract: `runAsJob`'s `progress()` callback is this,\n * and a job body that holds its `jobId` but not the callback — the arity-0/1\n * adopters, which cannot declare the fourth `run` parameter without also\n * claiming the third (`signalAccepted` is derived from `run.length`, #4972) —\n * calls it directly. Either way a poller reading `pending` can tell slow from\n * stuck, and the liveness watchdog in `run-as-job.ts` measures silence from\n * the same stamp — the record is the one source of truth for \"last progress\".\n *\n * A no-op unless the record exists AND is `pending`. A heartbeat that lands\n * after `cancel_job`, after the runaway guard, or after the body settled must\n * not resurrect a terminal record; and an unknown jobId is not created — the\n * stamp decorates a dispatch, it does not constitute one. Every other field of\n * the record is carried verbatim, including the producer's version.\n */\nexport function heartbeatJob(\n jobId: string,\n at: string = new Date(getTimeProvider().now()).toISOString()\n): void {\n persistProgressStamp(jobId, at);\n}\n\n/**\n * Epoch ms of the recorded heartbeat, or `undefined` when the record has none\n * or cannot be read (#6162). The liveness reaper measures silence from this —\n * the record is the single source of truth for \"last progress\", for the\n * reaper and for every reader alike — falling back to job start on\n * `undefined`. An unparseable stamp is `undefined`, not `NaN`: a silence that\n * cannot be measured must not read as any particular length.\n */\nexport function readLastProgressMs(jobId: string): number | undefined {\n const at = readJobResult(jobId)?.lastProgressAt;\n if (at === undefined) return undefined;\n const ms = Date.parse(at);\n return Number.isNaN(ms) ? undefined : ms;\n}\n\nfunction persistProgressStamp(jobId: string, at: string): void {\n const existing = readJobResult(jobId);\n if (existing?.status !== 'pending') {\n logger.debug('Skipping progress stamp — job is not pending', {\n jobId,\n status: existing?.status ?? 'unknown',\n });\n return;\n }\n const updated: JobResult = { ...existing, lastProgressAt: at };\n persistJobRecordAcrossCandidates(jobId, updated);\n}\n\n/**\n * Terminal `cancelled` status — set by `cancel_job` (#3042 Stage 1b).\n *\n * Idempotent-by-design at the in-memory state level: if the record is\n * already `complete` / `failed` / `cancelled`, `cancel_job` reports\n * `already_complete` / `already_cancelled` to the caller and DOES NOT\n * overwrite the terminal record (per the #3041 vote Security flag —\n * cancel-after-complete must not rewrite history).\n *\n * The caller (cancel_job tool) checks the current status BEFORE calling\n * this; this writer trusts the caller and always overwrites. Guarding\n * here too would duplicate the guard but is cheap insurance — current\n * design: caller-side guard only.\n */\nexport function writeJobCancelled(\n jobId: string,\n toolName: string,\n reason?: string,\n producerVersion: string = VERSION\n): void {\n const existing = readJobResult(jobId);\n const sanitizedReason = reason !== undefined ? sanitizeErrorDetails(reason) : undefined;\n const record: JobResult = {\n v: 1,\n jobId,\n toolName,\n status: 'cancelled',\n createdAt: existing?.createdAt ?? new Date().toISOString(),\n completedAt: new Date().toISOString(),\n ...(sanitizedReason !== undefined ? { error: sanitizedReason } : {}),\n producerVersion,\n ...carriedProgress(existing),\n };\n persistJobRecordAcrossCandidates(jobId, record);\n logger.debug('Wrote cancelled job record', { jobId, toolName, reason: sanitizedReason });\n}\n\n/**\n * Read a job-result record across candidate data directories (#5472).\n * Returns `null` if the jobId is unknown (no candidate file exists) or\n * unreadable (corrupt JSON, schema mismatch).\n *\n * Checks all candidate paths (primary and shared). If multiple valid records\n * exist, terminal status outranks pending, cancellations are preserved (#4017),\n * and later timestamps break ties.\n *\n * Schema mismatch is treated as \"not found\" not \"error\" so a client\n * polling against a future-Stage record from an older nexus-agents\n * process doesn't crash — the request just looks like an unknown jobId\n * until the operator upgrades.\n */\nexport function readJobResult(jobId: string): JobResult | null {\n return readJobResultAcrossCandidates(jobId, logger);\n}\n\n/**\n * List job records under `<NEXUS_DATA_DIR>/jobs/` (#3046 Stage 5).\n *\n * Returns ALL records sorted by `createdAt` descending (newest first).\n * Caller filters by `toolName` / `status` via the `list_jobs` MCP tool —\n * we don't push the filter logic in here because tools change shape but\n * the store doesn't.\n *\n * **The result payloads are intentionally EXCLUDED** from each summary\n * — large complete-status records can be 1 MiB each (per Stage 2's\n * TASK_RESULT_MAX_BYTES cap), and `list_jobs` is meant for discovery,\n * not retrieval. Callers re-fetch full records via `get_job_result(jobId)`.\n *\n * Schema-mismatch + unreadable files are silently dropped (logged as\n * warnings), same policy as `readJobResult`.\n */\nexport interface JobSummary {\n readonly jobId: string;\n readonly toolName: string;\n readonly status: JobResult['status'];\n readonly createdAt: string;\n readonly completedAt?: string;\n /** True iff the record carries an error message (status === 'failed'). */\n readonly hasError: boolean;\n /** Last heartbeat from the job body (#6162); absent when none was recorded. */\n readonly lastProgressAt?: string;\n /**\n * Set by `list_jobs` when a `pending` job has outlived the runaway guard, so\n * no live process can still own it: the same {@link isAbandonedJob} verdict\n * `get_job_result` reports (#6726). Computed at read time, never stored;\n * absent means \"not abandoned\", and `status` stays `pending` as observed.\n */\n readonly abandoned?: boolean;\n}\n\n/** Project a full {@link JobResult} down to its {@link JobSummary} — shared by\n * the sidecar walk here and the task-state list source (#3693). */\nexport function toJobSummary(record: JobResult): JobSummary {\n return {\n jobId: record.jobId,\n toolName: record.toolName,\n status: record.status,\n createdAt: record.createdAt,\n hasError: record.error !== undefined,\n ...(record.completedAt !== undefined ? { completedAt: record.completedAt } : {}),\n ...(record.lastProgressAt !== undefined ? { lastProgressAt: record.lastProgressAt } : {}),\n };\n}\n\n/**\n * What a job listing could NOT read (#6038).\n *\n * `listJobs` returned a bare array, so two very different worlds produced `[]`:\n * \"there are no jobs\" and \"the jobs directory would not open\". And a sidecar\n * that failed `JobResultSchema` — a record written by a newer nexus-agents, or\n * half-written by a concurrent job — was skipped by deliberate policy in\n * `readJobResult` and then left no trace at all. `list_jobs` reported\n * `{\"count\":0,\"truncated\":false}` over both, and an operator or the autonomous\n * loop concludes nothing is pending and re-dispatches work already running.\n */\ninterface JobListDiagnostics {\n /** True when the jobs directory exists but could not be enumerated. */\n readonly dirUnreadable: boolean;\n /** Sidecar files that matched the naming pattern but failed to parse or validate. */\n readonly unparseableRecords: number;\n}\n\n/** Job summaries plus what the listing could not read. */\nexport interface JobListing {\n readonly jobs: JobSummary[];\n readonly diagnostics: JobListDiagnostics;\n}\n\nexport function listJobs(): JobSummary[] {\n return listJobsWithDiagnostics().jobs;\n}\n\n/** List jobs AND report what the listing could not read (#6038). */\nexport function listJobsWithDiagnostics(): JobListing {\n const dir = nexusDataPath('jobs');\n // An ABSENT directory is a measured absence: no jobs have ever been written.\n // That is different from a directory that exists and will not open.\n if (!existsSync(dir)) {\n return { jobs: [], diagnostics: { dirUnreadable: false, unparseableRecords: 0 } };\n }\n let entries: string[];\n try {\n entries = readdirSync(dir);\n } catch (err) {\n logger.warn('jobs directory unreadable', {\n dir,\n error: err instanceof Error ? err.message : String(err),\n });\n return { jobs: [], diagnostics: { dirUnreadable: true, unparseableRecords: 0 } };\n }\n const summaries: JobSummary[] = [];\n let unparseableRecords = 0;\n for (const entry of entries) {\n const match = /^result-(.+)\\.json$/.exec(entry);\n if (match === null) continue;\n const jobId = match[1];\n if (jobId === undefined) continue;\n const record = readJobResult(jobId);\n if (record === null) {\n unparseableRecords += 1;\n continue;\n }\n summaries.push(toJobSummary(record));\n }\n // Newest first — matches typical \"what just happened\" discovery flow.\n return {\n jobs: summaries.sort((a, b) => b.createdAt.localeCompare(a.createdAt)),\n diagnostics: { dirUnreadable: false, unparseableRecords },\n };\n}\n\n// ---------------------------------------------------------------------------\n// Retention (#6224, #4976 gap 2)\n// ---------------------------------------------------------------------------\n\n/**\n * How long a job record is kept after it settles.\n *\n * Seven days. The record is the only durable evidence an async tool ran, so\n * the window trades disk against auditability (#4976 asked for a decision\n * rather than a guess): a week covers the weekly end-to-end validation cadence\n * (CLAUDE.md, \"Periodic end-to-end validation\"), which is the longest-lived\n * reader of a job's result, and on the machine measured in #6224, 198 of 303\n * records were older than three days — a window of days, not hours, is what\n * bounds the store. The audit chain next door is kept forever on purpose; job\n * results are not the audit chain. A constant, not an env var: no consumer has\n * asked to tune it, and a knob nobody reads is the shape #2977 removed.\n */\nexport const JOB_RECORD_RETENTION_MS = 7 * 24 * 60 * 60 * 1000;\n\n/**\n * Minimum gap between two sweeps run from `runAsJob` in one process. A sweep\n * enumerates and parses every record, so running it on every dispatch would\n * put a directory walk on the async hot path; once an hour bounds that to the\n * scale of the guard itself.\n */\nconst JOB_PRUNE_SWEEP_INTERVAL_MS = 3_600_000;\n\n/** What one retention sweep did — or, with `dryRun`, would have done. */\nexport interface JobPruneCounts {\n /** Terminal records older than the window, removed. */\n readonly deleted: number;\n /** `pending` records past the guard AND the window, rewritten as `failed`. */\n readonly markedAbandoned: number;\n /** Records inside the window, or `pending` records the guard still covers. */\n readonly kept: number;\n /** Record or key files that would not parse — counted, never touched. */\n readonly unreadable: number;\n /**\n * Idempotency index entries (`key-*.json`, `job-idempotency.ts`) older than\n * the window whose job record no longer exists, removed. Counted apart from\n * `deleted` because they are not records: a key that outlives its record\n * would replay a jobId `get_job_result` cannot find, and the caller could\n * never dispatch under that key again.\n */\n readonly deletedKeys: number;\n}\n\ninterface PruneJobRecordsOptions {\n /** The sweep's notion of now, in epoch milliseconds. */\n readonly nowMs: number;\n /** Retention window in milliseconds; {@link JOB_RECORD_RETENTION_MS} in production. */\n readonly retentionMs: number;\n /** Count what would change and change nothing. */\n readonly dryRun?: boolean;\n}\n\n/**\n * Sweep `<NEXUS_DATA_DIR>/jobs/` (#6224, closing #4976 gap 2).\n *\n * Rules, in the order they are tested:\n *\n * - A terminal record (`complete` / `failed` / `cancelled`) whose `completedAt`\n * — `createdAt` when a legacy record has none — is older than `retentionMs`\n * is deleted. \"Older than\" is strict: a record exactly at the window is kept.\n * - A `pending` record that is abandoned ({@link isAbandonedJob}: older than the\n * resolved guard, so no live process can own it) AND older than the window is\n * rewritten as `failed` with `errorKind: 'abandoned'`. Never deleted: the\n * record is the only evidence the dispatch happened. This is the ONE path\n * that writes an abandoned verdict back; `get_job_result` keeps reporting it.\n * A `pending` record younger than either bound is kept — the guard may still\n * settle it, or a poller may still need to see it `pending`.\n * - A file matching `result-*.json` or `key-*.json` that fails to parse or\n * validate is counted as `unreadable` and left in place. It may have been\n * written by a newer build, or be mid-write by a concurrent job; deleting on\n * \"could not read\" would turn a parse error into data loss.\n * - An idempotency key entry (`key-*.json`) older than the window whose job\n * record is absent — deleted by this sweep or never written — is removed\n * AFTER the records pass, so a key and its record leave together. A key\n * inside the window is kept even without a record: it is registered right\n * after the pending write, so a young dangling key may be mid-dispatch.\n *\n * The guard is resolved ONCE per sweep, not once per record.\n *\n * Empty case: an absent or empty jobs directory returns all-zero counts. A\n * directory that exists but cannot be enumerated THROWS — reporting zeros\n * there would present \"could not look\" as \"nothing to do\".\n */\nexport function pruneJobRecords(options: PruneJobRecordsOptions): JobPruneCounts {\n const dir = nexusDataPath('jobs');\n if (!existsSync(dir)) {\n return { deleted: 0, markedAbandoned: 0, kept: 0, unreadable: 0, deletedKeys: 0 };\n }\n // Deliberately not wrapped: an unreadable directory is the caller's problem\n // to report, not a zero.\n const entries = readdirSync(dir);\n const sweep: SweepContext = {\n nowMs: options.nowMs,\n retentionMs: options.retentionMs,\n dryRun: options.dryRun === true,\n abandonedAfter: abandonedAfterMs(),\n };\n const counts = { deleted: 0, markedAbandoned: 0, kept: 0, unreadable: 0, deletedKeys: 0 };\n /** Records this pass deleted (or, dry-run, would have) — keys check against it. */\n const removedJobIds = new Set<string>();\n const keyEntries = entries.filter((entry) => /^key-.+\\.json$/.test(entry));\n for (const entry of entries) {\n const jobId = /^result-(.+)\\.json$/.exec(entry)?.[1];\n if (jobId === undefined) continue;\n const verdict = sweepRecord(jobId, entry, sweep);\n counts[verdict] += 1;\n if (verdict === 'deleted') removedJobIds.add(jobId);\n }\n for (const entry of keyEntries) {\n const verdict = sweepKeyEntry(entry, removedJobIds, sweep);\n if (verdict !== null) counts[verdict] += 1;\n }\n logger.debug('Job record sweep', { dir, ...counts, dryRun: sweep.dryRun });\n return counts;\n}\n\n/** One sweep's inputs, resolved once and threaded through every verdict. */\ninterface SweepContext {\n readonly nowMs: number;\n readonly retentionMs: number;\n readonly dryRun: boolean;\n /** {@link abandonedAfterMs}, resolved once per sweep. */\n readonly abandonedAfter: number;\n}\n\n/** What the sweep did with one record — each maps to a {@link JobPruneCounts} key. */\ntype RecordVerdict = 'deleted' | 'markedAbandoned' | 'kept' | 'unreadable';\n\n/** Apply the record rules to one `result-*.json` entry and report which fired. */\nfunction sweepRecord(jobId: string, entry: string, sweep: SweepContext): RecordVerdict {\n const path = nexusDataPath('jobs', entry);\n const fileRecord = readJobResultFile(path, jobId, logger);\n if (fileRecord === null) return 'unreadable';\n const record = readJobResult(jobId) ?? fileRecord;\n if (record.status === 'pending') {\n const pastGuard = isAbandonedAt(record, sweep.nowMs, sweep.abandonedAfter);\n const pastWindow = isOlderThan(record.createdAt, sweep.nowMs, sweep.retentionMs);\n if (!(pastGuard && pastWindow)) return 'kept';\n if (!sweep.dryRun) persistJobRecord(path, abandonedRecord(record, sweep.nowMs));\n return 'markedAbandoned';\n }\n const settledAt = record.completedAt ?? record.createdAt;\n if (!isOlderThan(settledAt, sweep.nowMs, sweep.retentionMs)) return 'kept';\n if (!sweep.dryRun) unlinkSync(path);\n return 'deleted';\n}\n\n/**\n * Apply the key rule to one `key-*.json` entry: `deletedKeys` when it is past\n * the window and its record is gone, `unreadable` when it will not parse, and\n * `null` (no count — keys are not records, so they are never \"kept\") otherwise.\n */\nfunction sweepKeyEntry(\n entry: string,\n removedJobIds: ReadonlySet<string>,\n sweep: SweepContext\n): 'deletedKeys' | 'unreadable' | null {\n const path = nexusDataPath('jobs', entry);\n const indexEntry = readIndexEntry(path);\n if (indexEntry === null) return 'unreadable';\n if (!isOlderThan(indexEntry.createdAt, sweep.nowMs, sweep.retentionMs)) return null;\n const recordGone =\n removedJobIds.has(indexEntry.jobId) ||\n !candidateJobResultPaths(indexEntry.jobId).some((p) => existsSync(p));\n if (!recordGone) return null;\n if (!sweep.dryRun) unlinkSync(path);\n return 'deletedKeys';\n}\n\n/**\n * Strictly older than `windowMs`. An unparseable timestamp yields NaN, and a\n * NaN comparison is false — an age that cannot be read is never \"old enough\".\n */\nfunction isOlderThan(isoTimestamp: string, nowMs: number, windowMs: number): boolean {\n return nowMs - Date.parse(isoTimestamp) > windowMs;\n}\n\n/**\n * The `failed` rewrite of an abandoned `pending` record. Every field of the\n * original survives (`createdAt`, `signalAccepted`, the tool); the original\n * producer's version moves into the message because `producerVersion` names\n * the writer that settled the record, and that is now the sweep.\n */\nfunction abandonedRecord(record: JobResult, nowMs: number): JobResult {\n const producer = record.producerVersion ?? 'unrecorded';\n return {\n ...record,\n status: 'failed',\n completedAt: new Date(nowMs).toISOString(),\n error:\n `abandoned: pending since ${record.createdAt} under producer ${producer}; ` +\n 'no process settled it within the runaway guard, and the retention sweep ' +\n 'marked it failed rather than deleting the evidence',\n errorKind: 'abandoned',\n producerVersion: VERSION,\n };\n}\n\n/**\n * Epoch ms of the last sweep this process ran, per jobs directory. Keyed by\n * directory rather than a single timestamp because `NEXUS_DATA_DIR` routes\n * per-repo state (#2872), so one process can serve more than one jobs\n * directory and each deserves its own hourly sweep. Bounded by the number of\n * distinct data dirs a process touches.\n */\nconst lastSweepAtMsByDir = new Map<string, number>();\n\n/**\n * Run {@link pruneJobRecords} with the production window if at least\n * {@link JOB_PRUNE_SWEEP_INTERVAL_MS} has passed since this process last swept\n * the current jobs directory (#6224). Called by `runAsJob` before every\n * pending write.\n *\n * A sweep that throws is logged and swallowed: retention must never block a\n * dispatch. The timestamp is taken BEFORE the sweep so a directory that keeps\n * failing is retried once an hour, not on every call.\n *\n * @returns The counts when a sweep ran, `null` when one was not due or failed.\n */\nexport function pruneJobRecordsIfDue(nowMs: number): JobPruneCounts | null {\n const dir = nexusDataPath('jobs');\n const lastSweepAtMs = lastSweepAtMsByDir.get(dir);\n if (lastSweepAtMs !== undefined && nowMs - lastSweepAtMs < JOB_PRUNE_SWEEP_INTERVAL_MS) {\n return null;\n }\n lastSweepAtMsByDir.set(dir, nowMs);\n try {\n return pruneJobRecords({ nowMs, retentionMs: JOB_RECORD_RETENTION_MS });\n } catch (err) {\n logger.warn('Job record sweep failed', {\n error: err instanceof Error ? err.message : String(err),\n });\n return null;\n }\n}\n","/**\n * Job-id format (input validation hardening).\n *\n * Job ids are minted by the server, never chosen freely by a caller. Every\n * mint site produces ids from `[A-Za-z0-9_-]`:\n *\n * - `<prefix>-<uuid>` — `rp-`, `dp-`, `sc-`, `rn-`, `gw-`, `pr-`, `es-`,\n * `job-vote-`, `job-rw-` (`freshJobId` in the async tools);\n * - `job-<tool_name>-<16 hex>` — idempotency-key dispatch (`job-idempotency.ts`);\n * - a bare `randomUUID()` — keyless fallback in `resolveIdempotency`;\n * - `tsk_<base36>_<base36>` — orchestrate (`generateTaskId`);\n * - a `run_dev_pipeline` `sessionId`, whose input schema already restricts it to\n * `^[a-zA-Z0-9_-]+$`, max 128.\n *\n * The id is interpolated into a sidecar file name, so it is validated both at\n * the tool schemas and at the path builders.\n *\n * @module mcp/jobs/job-id\n */\n\nimport { z } from 'zod';\n\n/** Longest accepted job id; matches the existing tool-schema bound. */\nexport const JOB_ID_MAX_LENGTH = 128;\n\n/** The character set every minted job id is drawn from, 1–128 characters. */\nexport const JOB_ID_PATTERN = /^[A-Za-z0-9_-]{1,128}$/;\n\n/** True when `jobId` has the minted format. The empty string is not a job id. */\nexport function isValidJobId(jobId: string): boolean {\n return JOB_ID_PATTERN.test(jobId);\n}\n\n/** Throws for an id outside the minted format; used where a path is about to be built. */\nexport function assertValidJobId(jobId: string): void {\n if (!isValidJobId(jobId)) {\n throw new Error('Invalid jobId: must contain only letters, digits, \"_\" and \"-\" (1-128)');\n }\n}\n\n/** Tool-schema field for a job id. */\nexport function jobIdSchema(description: string): z.ZodString {\n return z\n .string()\n .min(1)\n .max(JOB_ID_MAX_LENGTH)\n .regex(JOB_ID_PATTERN, 'jobId must contain only letters, digits, \"_\" and \"-\"')\n .describe(description);\n}\n","/**\n * Idempotency-key resolution for async-mode MCP tool dispatch (#3042 Stage 1c,\n * epic #2631). Lets a caller pass `idempotencyKey: \"<string>\"` and re-invoke\n * the same logical operation safely across sessions / process restarts.\n *\n * ## Contract\n *\n * - Key + matching inputs → returns the existing job's record (whatever\n * state — pending / complete / failed / cancelled). Caller polls\n * `get_job_result(jobId)` exactly as if it had dispatched fresh.\n * - Key + DIFFERENT inputs → fails closed with `idempotency_key_collision`.\n * Reusing a key with different inputs is almost certainly a caller bug;\n * silent merge would either hide a typo or leak the first call's result\n * into a second logical operation.\n * - No key → caller falls back to a fresh `randomUUID()` jobId (existing\n * behavior; this module is a no-op).\n *\n * ## Storage shape\n *\n * One file per (tool, key) tuple at:\n * `<NEXUS_DATA_DIR>/jobs/key-<sha256(tool + ':' + key)>.json`\n *\n * Record: `{ v: 1, tool, key, inputsHash, jobId, createdAt }`.\n *\n * Sharded by `(tool, key)` so two different tools using the same human key\n * don't collide. The filename is the hash so an attacker who reads the\n * directory listing can't recover the user-supplied key.\n *\n * @module mcp/jobs/job-idempotency\n */\n\nimport { createHash, randomUUID } from 'node:crypto';\nimport { existsSync, readFileSync, writeFileSync } from 'node:fs';\n\nimport { z } from 'zod';\n\nimport { createLogger } from '../../core/index.js';\nimport { nexusDataPath, nexusDataPathEnsure } from '../../config/nexus-data-dir.js';\n\nconst logger = createLogger({ component: 'job-idempotency' });\n\n/** Index-file record persisted per (tool, key). */\nexport const IdempotencyIndexEntrySchema = z.object({\n v: z.literal(1),\n /** MCP tool name (e.g. `orchestrate`, `run_workflow`, `consensus_vote`). */\n tool: z.string().min(1),\n /** Caller-supplied idempotency key. */\n key: z.string().min(1),\n /** sha256 of the canonical input JSON. */\n inputsHash: z.string().length(64),\n /** Existing jobId for this (tool, key, inputs) tuple. */\n jobId: z.string().min(1),\n /** ISO timestamp of first dispatch. */\n createdAt: z.iso.datetime(),\n});\nexport type IdempotencyIndexEntry = z.infer<typeof IdempotencyIndexEntrySchema>;\n\n/** Outcome of `resolveIdempotency` — discriminated by `kind`. */\nexport type IdempotencyResolution =\n | { readonly kind: 'fresh'; readonly jobId: string }\n | { readonly kind: 'replay'; readonly jobId: string; readonly entry: IdempotencyIndexEntry }\n | {\n readonly kind: 'collision';\n readonly existingInputsHash: string;\n readonly incomingInputsHash: string;\n readonly existingJobId: string;\n };\n\n/** sha256 hex of a string. */\nfunction sha256Hex(input: string): string {\n return createHash('sha256').update(input).digest('hex');\n}\n\n/**\n * Canonical JSON serialization for input hashing. Sorts object keys\n * recursively so `{a:1,b:2}` and `{b:2,a:1}` produce identical hashes.\n *\n * `undefined` values are dropped (JSON semantics); function values throw\n * — schema validation should have caught those upstream.\n */\nfunction canonicalJsonStringify(value: unknown): string {\n if (value === null || typeof value !== 'object') return JSON.stringify(value);\n if (Array.isArray(value)) return `[${value.map(canonicalJsonStringify).join(',')}]`;\n const entries = Object.entries(value as Record<string, unknown>)\n .filter(([, v]) => v !== undefined)\n .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0));\n return `{${entries.map(([k, v]) => `${JSON.stringify(k)}:${canonicalJsonStringify(v)}`).join(',')}}`;\n}\n\n/** Compute the inputs hash used to detect (tool, key) collisions. */\nexport function computeInputsHash(inputs: unknown): string {\n return sha256Hex(canonicalJsonStringify(inputs));\n}\n\n/** Compute the on-disk index path for a (tool, key) tuple. */\nfunction indexFilePath(tool: string, key: string): string {\n // Filename is hashed so a directory listing doesn't leak user keys.\n const filename = `key-${sha256Hex(`${tool}:${key}`)}.json`;\n return nexusDataPathEnsure('jobs', filename);\n}\n\n/** Read-only counterpart that doesn't create the parent directory. */\nfunction indexFilePathReadOnly(tool: string, key: string): string {\n const filename = `key-${sha256Hex(`${tool}:${key}`)}.json`;\n return nexusDataPath('jobs', filename);\n}\n\n/**\n * Resolve a dispatch request to one of three outcomes:\n *\n * - `fresh`: no prior index entry — caller dispatches a new job using the\n * returned `jobId`, then calls `registerIdempotentJob` to record the\n * index entry. The `jobId` is derived deterministically from\n * `(tool, key, inputsHash)` so concurrent dispatches with the same key\n * converge on the same id and don't double-dispatch.\n * - `replay`: an existing entry has the SAME `inputsHash` — caller skips\n * dispatch and returns the existing job's record (via `readJobResult`).\n * - `collision`: an existing entry has a DIFFERENT `inputsHash` — caller\n * fails closed. Reusing a key with different inputs is a programmer\n * error; silent merge would hide bugs.\n *\n * Callers should NOT call `registerIdempotentJob` when this returns\n * `replay` or `collision` — only on `fresh`.\n */\nexport function resolveIdempotency(\n tool: string,\n idempotencyKey: string | undefined,\n inputs: unknown,\n randomFallback: () => string = randomUUID\n): IdempotencyResolution {\n if (idempotencyKey === undefined || idempotencyKey === '') {\n return { kind: 'fresh', jobId: randomFallback() };\n }\n const incomingInputsHash = computeInputsHash(inputs);\n const path = indexFilePathReadOnly(tool, idempotencyKey);\n if (existsSync(path)) {\n const entry = readIndexEntry(path);\n if (entry !== null) {\n if (entry.inputsHash === incomingInputsHash) {\n return { kind: 'replay', jobId: entry.jobId, entry };\n }\n return {\n kind: 'collision',\n existingInputsHash: entry.inputsHash,\n incomingInputsHash,\n existingJobId: entry.jobId,\n };\n }\n // Index file present but unreadable — treat as fresh, log the breach.\n logger.warn('Idempotency index file unreadable; treating as fresh dispatch', { tool, path });\n }\n // Derive jobId deterministically so two concurrent requests with the\n // same (tool, key, inputs) converge on a single id even if both miss\n // the index lookup race.\n const jobId = `job-${tool}-${sha256Hex(`${tool}:${idempotencyKey}:${incomingInputsHash}`).slice(0, 16)}`;\n return { kind: 'fresh', jobId };\n}\n\n/**\n * Persist the index entry after a `fresh` dispatch. Idempotent — if the\n * file already exists (e.g. a concurrent dispatch raced ahead), the\n * existing entry stays in place. Safe to call without checking\n * `existsSync` first.\n */\nexport function registerIdempotentJob(params: {\n tool: string;\n idempotencyKey: string;\n inputs: unknown;\n jobId: string;\n}): void {\n const path = indexFilePath(params.tool, params.idempotencyKey);\n if (existsSync(path)) {\n logger.debug('Idempotency index entry already present; skipping write', {\n tool: params.tool,\n jobId: params.jobId,\n });\n return;\n }\n const entry: IdempotencyIndexEntry = {\n v: 1,\n tool: params.tool,\n key: params.idempotencyKey,\n inputsHash: computeInputsHash(params.inputs),\n jobId: params.jobId,\n createdAt: new Date().toISOString(),\n };\n writeFileSync(path, JSON.stringify(entry, null, 2));\n logger.debug('Wrote idempotency index entry', { tool: params.tool, jobId: params.jobId });\n}\n\n/**\n * Discriminated outcome of `shortCircuitOrFreshJobId` — `continue` means\n * the caller proceeds with dispatch on `jobId`; `shortCircuit` means the\n * caller returns the envelope `value` immediately and skips dispatch.\n */\nexport type ShortCircuitOutcome<TEnvelope> =\n | { readonly kind: 'continue'; readonly jobId: string }\n | { readonly kind: 'shortCircuit'; readonly value: TEnvelope };\n\n/**\n * One-call wrapper around `resolveIdempotency` that lets each dispatch\n * helper stay under the 50-line cap while keeping the shape of the\n * resulting envelope (toolSuccess / toolStructuredError / errorResponse)\n * tool-specific.\n *\n * Caller supplies:\n * - `replayEnvelope(jobId)` — wraps the per-tool \"replay\" envelope. Most\n * tools return a `{ status: 'replay', jobId, pollTool, note }` JSON\n * string via `toolSuccess`.\n * - `collisionEnvelope(existingJobId)` — wraps the error envelope when\n * the same key was reused with different inputs.\n *\n * On `continue`, the caller MUST call `registerIdempotentJob` after\n * writing the pending record so subsequent replays converge.\n */\nexport function shortCircuitOrFreshJobId<TEnvelope>(params: {\n tool: string;\n idempotencyKey: string | undefined;\n inputs: unknown;\n freshJobId: () => string;\n replayEnvelope: (jobId: string) => TEnvelope;\n collisionEnvelope: (existingJobId: string) => TEnvelope;\n}): ShortCircuitOutcome<TEnvelope> {\n const r = resolveIdempotency(\n params.tool,\n params.idempotencyKey,\n params.inputs,\n params.freshJobId\n );\n if (r.kind === 'collision') {\n return { kind: 'shortCircuit', value: params.collisionEnvelope(r.existingJobId) };\n }\n if (r.kind === 'replay') {\n return { kind: 'shortCircuit', value: params.replayEnvelope(r.jobId) };\n }\n return { kind: 'continue', jobId: r.jobId };\n}\n\n/**\n * Read + schema-validate an index file. Returns `null` on miss / corruption.\n * Exported for the retention sweep in `job-result-store.ts` (#6224), which\n * must read an entry to learn which job it points at before dropping it.\n */\nexport function readIndexEntry(path: string): IdempotencyIndexEntry | null {\n try {\n const raw = JSON.parse(readFileSync(path, 'utf-8')) as unknown;\n const parsed = IdempotencyIndexEntrySchema.safeParse(raw);\n if (!parsed.success) {\n logger.warn('Idempotency index file failed schema check', { path });\n return null;\n }\n return parsed.data;\n } catch (err) {\n logger.warn('Idempotency index file read failed', {\n path,\n error: err instanceof Error ? err.message : String(err),\n });\n return null;\n }\n}\n","/**\n * Candidate job-result resolution across data directories (#5472).\n *\n * When an MCP server starts, `activeWorkspaceRoot` is initially unset until\n * the client completes its `roots/list` handshake. Jobs dispatched during\n * this window land in `~/.nexus-agents/jobs/` (`nexusSharedPath`), while jobs\n * settled after root discovery land in `<repo>/.nexus-agents/jobs/` (`nexusDataPath`).\n *\n * This module resolves candidate paths, ranks records so terminal status\n * outranks stale pending records, and propagates updates across directories.\n *\n * @module mcp/jobs/job-result-candidates\n */\n\nimport { existsSync, readFileSync } from 'node:fs';\nimport { join } from 'node:path';\n\nimport { nexusDataPath, nexusSharedPath } from '../../config/nexus-data-dir.js';\nimport { findRepoRoot } from '../../config/repo-root-detection.js';\nimport type { ILogger } from '../../core/index.js';\nimport { JobResultSchema, type JobResult } from './job-result-store.js';\nimport { isValidJobId } from './job-id.js';\n\ntype CandidatePathsResolver = (jobId: string) => readonly string[] | undefined;\nlet candidatePathsResolverForTests: CandidatePathsResolver | undefined;\n\n/** Test helper — override candidate paths resolution for tests. */\nexport function _setCandidatePathsResolverForTests(\n resolver: CandidatePathsResolver | undefined\n): void {\n candidatePathsResolverForTests = resolver;\n}\n\nfunction getExplicitDataDir(): string | undefined {\n const env = process.env['NEXUS_DATA_DIR']?.trim();\n return env !== undefined && env.length > 0 ? env : undefined;\n}\n\nfunction appendUniquePath(paths: string[], candidate: string | null): void {\n if (candidate !== null && !paths.includes(candidate)) {\n paths.push(candidate);\n }\n}\n\n/**\n * Resolves all candidate paths where a job-result sidecar might reside (#5472).\n *\n * Returns all possible candidate paths for a given `jobId`:\n * 1. Primary path (`nexusDataPath('jobs', ...)`)\n * 2. Shared path (`nexusSharedPath('jobs', ...)`)\n * 3. Cwd-discovered repo path (if different and known)\n */\nexport function candidateJobResultPaths(\n jobId: string,\n resolvePrimary: (subdir: string, ...segments: string[]) => string = nexusDataPath,\n resolveShared: (subdir: string, ...segments: string[]) => string = nexusSharedPath,\n repoRootFinder: (start: string) => string | null = findRepoRoot\n): readonly string[] {\n // A job id is interpolated into a file name: an id outside the minted format\n // has no candidate path, so readers report it as not found.\n if (!isValidJobId(jobId)) return [];\n if (candidatePathsResolverForTests !== undefined) {\n const overridden = candidatePathsResolverForTests(jobId);\n if (overridden !== undefined) return overridden;\n }\n const filename = `result-${jobId}.json`;\n const primary = resolvePrimary('jobs', filename);\n if (getExplicitDataDir() !== undefined) {\n return [primary];\n }\n\n const paths: string[] = [primary];\n appendUniquePath(paths, resolveShared('jobs', filename));\n\n const cwdRepo = repoRootFinder(process.cwd());\n const cwdRepoPath = cwdRepo !== null ? join(cwdRepo, '.nexus-agents', 'jobs', filename) : null;\n appendUniquePath(paths, cwdRepoPath);\n\n return paths;\n}\n\nfunction compareTerminalRecords(a: JobResult, b: JobResult): number {\n if (a.status === 'cancelled' && b.status !== 'cancelled') return -1;\n if (b.status === 'cancelled' && a.status !== 'cancelled') return 1;\n\n const aSettled = Date.parse(a.completedAt ?? a.createdAt);\n const bSettled = Date.parse(b.completedAt ?? b.createdAt);\n if (Number.isFinite(aSettled) && Number.isFinite(bSettled) && aSettled !== bSettled) {\n return bSettled - aSettled;\n }\n return 0;\n}\n\nfunction comparePendingRecords(a: JobResult, b: JobResult): number {\n const aActivity = Date.parse(a.lastProgressAt ?? a.createdAt);\n const bActivity = Date.parse(b.lastProgressAt ?? b.createdAt);\n if (Number.isFinite(aActivity) && Number.isFinite(bActivity) && aActivity !== bActivity) {\n return bActivity - aActivity;\n }\n return 0;\n}\n\n/**\n * Compares two job records to determine which is more authoritative (#5472).\n *\n * Ranking rules:\n * 1. Terminal status (`complete`, `failed`, `cancelled`) outranks `pending`.\n * 2. Cancellation preservation (#4017): `cancelled` outranks `complete` and `failed`.\n * 3. If both are terminal (or neither is `cancelled`), later `completedAt ?? createdAt` wins.\n * 4. If both are `pending`, later `lastProgressAt ?? createdAt` wins.\n * 5. Stable tie-break (returns 0).\n */\nexport function compareJobRecords(a: JobResult, b: JobResult): number {\n const aTerminal = a.status !== 'pending';\n const bTerminal = b.status !== 'pending';\n\n if (aTerminal && !bTerminal) return -1;\n if (!aTerminal && bTerminal) return 1;\n\n return aTerminal ? compareTerminalRecords(a, b) : comparePendingRecords(a, b);\n}\n\n/**\n * Selects the winning job record among multiple candidate records (#5472),\n * carrying forward any recorded heartbeat (`lastProgressAt`) if the winner\n * lacks one.\n */\nexport function selectAuthoritativeJobRecord(records: readonly JobResult[]): JobResult {\n const sorted = [...records].sort(compareJobRecords);\n const winner = sorted[0];\n if (winner === undefined) {\n throw new Error('selectAuthoritativeJobRecord called with empty records');\n }\n\n if (winner.lastProgressAt !== undefined) {\n return winner;\n }\n\n for (const r of records) {\n if (r.lastProgressAt !== undefined) {\n return { ...winner, lastProgressAt: r.lastProgressAt };\n }\n }\n\n return winner;\n}\n\n/**\n * Read and validate a job-result file from disk. Returns null on parse/schema failure.\n */\nexport function readJobResultFile(path: string, jobId: string, logger: ILogger): JobResult | null {\n try {\n const raw = JSON.parse(readFileSync(path, 'utf-8')) as unknown;\n const parsed = JobResultSchema.safeParse(raw);\n if (!parsed.success) {\n logger.warn('Job result file failed schema check', { jobId, path });\n return null;\n }\n return parsed.data;\n } catch (err) {\n logger.warn('Job result file unreadable', {\n jobId,\n path,\n error: err instanceof Error ? err.message : String(err),\n });\n return null;\n }\n}\n\n/**\n * Read a job-result record across candidate data directories (#5472).\n */\nexport function readJobResultAcrossCandidates(jobId: string, logger: ILogger): JobResult | null {\n const candidates = candidateJobResultPaths(jobId);\n const records: JobResult[] = [];\n for (const path of candidates) {\n if (!existsSync(path)) continue;\n const record = readJobResultFile(path, jobId, logger);\n if (record !== null) {\n records.push(record);\n }\n }\n const first = records[0];\n if (first === undefined) return null;\n if (records.length === 1) return first;\n return selectAuthoritativeJobRecord(records);\n}\n\n/**\n * Syncs a settled or updated job record to any existing alternate candidate\n * paths (#5472) so readers looking at either repo or shared directories\n * immediately observe the current status.\n */\nexport function syncAlternateCandidates(\n jobId: string,\n primaryPath: string,\n record: JobResult,\n logger: ILogger,\n persistFn: (path: string, record: JobResult) => void\n): void {\n const candidates = candidateJobResultPaths(jobId);\n for (const candidatePath of candidates) {\n if (candidatePath === primaryPath) continue;\n if (!existsSync(candidatePath)) continue;\n try {\n persistFn(candidatePath, record);\n logger.debug('Synced job record to alternate candidate path', {\n jobId,\n path: candidatePath,\n status: record.status,\n });\n } catch (err) {\n logger.warn('Failed to sync job record to alternate candidate path', {\n jobId,\n path: candidatePath,\n error: err instanceof Error ? err.message : String(err),\n });\n }\n }\n}\n","/**\n * Structured adapter/transport failure detail in job records (#4375).\n *\n * Persisted on `failed` job records so readers of `get_job_result` can\n * programmatically distinguish adapter outages or capacity exhaustion\n * from application errors without parsing prose.\n *\n * @module mcp/jobs/job-failure-detail\n */\n\nimport { z } from 'zod';\nimport { sanitizeErrorDetails } from '../../security/output-sanitizer.js';\nimport { ERROR_ENVELOPE_META_KEY } from '../error-envelope.js';\n\n/**\n * Structured failure detail for adapter / transport failures (#4375).\n */\nexport const JobFailureDetailSchema = z.object({\n /** Identifier of the failing adapter (e.g. 'claude', 'codex', 'api:anthropic'). */\n adapter: z.string().min(1),\n /** Transport mechanism where the failure occurred (e.g. 'subprocess', 'mcp', 'stdio'). */\n transport: z.string().min(1),\n /** Normalized failure category (e.g. 'rate_limited', 'timeout', 'capacity_exhausted'). */\n category: z.string().min(1),\n});\nexport type JobFailureDetail = z.infer<typeof JobFailureDetailSchema>;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n\nfunction getNonEmptyString(value: unknown): string | undefined {\n return typeof value === 'string' && value.trim() !== '' ? value.trim() : undefined;\n}\n\n/**\n * Normalizes a raw category or code string into a snake_case failure category.\n */\nfunction normalizeFailureCategory(raw: string): string {\n return raw.trim().toLowerCase();\n}\n\n/**\n * Extracts category from a candidate object, falling back to message text for capacity_exhausted (#4373).\n */\nfunction extractCategory(candidate: Record<string, unknown>): string | undefined {\n const direct = getNonEmptyString(candidate.category) ?? getNonEmptyString(candidate.code);\n if (direct !== undefined) {\n return normalizeFailureCategory(direct);\n }\n const msg = getNonEmptyString(candidate.message);\n if (msg?.toLowerCase().includes('capacity_exhausted') === true) {\n return 'capacity_exhausted';\n }\n return undefined;\n}\n\n/**\n * Inspects an explicit failureDetail property if present.\n */\nfunction inspectExplicitFailureDetail(\n candidate: Record<string, unknown>\n): JobFailureDetail | undefined {\n if (!isRecord(candidate.failureDetail)) return undefined;\n const fd = candidate.failureDetail;\n const adapter = getNonEmptyString(fd.adapter);\n const transport = getNonEmptyString(fd.transport);\n const category = getNonEmptyString(fd.category);\n if (adapter !== undefined && transport !== undefined && category !== undefined) {\n return {\n adapter,\n transport,\n category: normalizeFailureCategory(category),\n };\n }\n return undefined;\n}\n\n/**\n * Inspects a single candidate record for adapter failure fields.\n */\nfunction inspectCandidateForDetail(\n candidate: Record<string, unknown>\n): JobFailureDetail | undefined {\n const explicit = inspectExplicitFailureDetail(candidate);\n if (explicit !== undefined) return explicit;\n\n const adapter = getNonEmptyString(candidate.adapter) ?? getNonEmptyString(candidate.cli);\n if (adapter === undefined) return undefined;\n\n const transport = getNonEmptyString(candidate.transport) ?? 'subprocess';\n const category = extractCategory(candidate);\n if (category === undefined) return undefined;\n\n return { adapter, transport, category };\n}\n\n/**\n * Inspects MCP error envelope or _meta metadata for failure details.\n */\nfunction inspectMetaForDetail(meta: unknown): JobFailureDetail | undefined {\n if (!isRecord(meta)) return undefined;\n const direct = inspectCandidateForDetail(meta);\n if (direct !== undefined) return direct;\n\n const env = meta[ERROR_ENVELOPE_META_KEY];\n if (isRecord(env) && isRecord(env.detail)) {\n return inspectCandidateForDetail(env.detail);\n }\n return undefined;\n}\n\n/**\n * Extracts structured adapter/transport failure detail from a caught error\n * or failure-shaped result (#4375).\n *\n * Inspects:\n * 1. An explicit `failureDetail` property\n * 2. CLI error structures (`cli`, `code`, `transport`)\n * 3. Generic adapter error shapes (`adapter`, `transport`, `category`)\n * 4. Nested `_meta` or MCP error envelope structures\n * 5. Nested `.error` or `.cause` properties\n *\n * Strips all excess properties (e.g. response bodies, prompt text, stack traces)\n * returning strictly `{ adapter, transport, category }`.\n *\n * @param source - Caught exception or failure-shaped job result\n * @returns Structured failure detail, or `undefined` if not an adapter/transport failure\n */\nexport function extractFailureDetail(source: unknown): JobFailureDetail | undefined {\n if (!isRecord(source)) return undefined;\n\n return (\n inspectCandidateForDetail(source) ??\n inspectMetaForDetail(source._meta) ??\n (isRecord(source.error) ? inspectCandidateForDetail(source.error) : undefined) ??\n (isRecord(source.cause) ? inspectCandidateForDetail(source.cause) : undefined)\n );\n}\n\n/**\n * Sanitizes all string fields in a failure detail and validates against the schema (#4375).\n * Returns undefined if detail is undefined.\n */\nexport function validateAndSanitizeFailureDetail(\n detail?: JobFailureDetail\n): JobFailureDetail | undefined {\n if (detail === undefined) return undefined;\n return JobFailureDetailSchema.parse({\n adapter: sanitizeErrorDetails(detail.adapter),\n transport: sanitizeErrorDetails(detail.transport),\n category: sanitizeErrorDetails(detail.category),\n });\n}\n","/**\n * The one writer allowed to touch a `cancelled` job record (#6735).\n *\n * A sibling of `job-result-store.ts`, which is at its line cap. The field's\n * shape is `CancelledPartialSchema` (`job-cancelled-partial-schema.ts`).\n *\n * @module mcp/jobs/job-cancelled-partial\n */\n\nimport { createLogger } from '../../core/index.js';\nimport { CancelledPartialSchema } from './job-cancelled-partial-schema.js';\nimport {\n persistJobRecordAcrossCandidates,\n readJobResult,\n type JobResult,\n} from './job-result-store.js';\n\nconst logger = createLogger({ component: 'job-cancelled-partial' });\n\n/**\n * Attach what a cancelled vote had cast to its `cancelled` record (#6735).\n * Returns whether the record was written.\n *\n * Why a separate writer and not a relaxed terminal writer: the #4017/#4022\n * rule — nothing rewrites a `cancelled` record — stays exactly as it is for\n * `writeJobComplete` / `writeJobFailed` / `heartbeatJob`. This writer is the\n * one exception, and it is narrow by construction:\n *\n * - it acts ONLY on a record that is already `cancelled` (a pending, complete\n * or failed record is left alone — it cannot be used to settle a job), and\n * only when the record's `toolName` is the caller's;\n * - it never changes `status`, `completedAt`, `error` or any other field — it\n * adds `cancelledPartial` and nothing else;\n * - first write wins: a record that already carries `cancelledPartial` is not\n * rewritten, so the partials cannot be replaced after the fact;\n * - `seatsCast` is derived from `partialVotes`, so the count cannot disagree\n * with the votes it counts.\n *\n * The cancel path cannot write this itself: `cancel_job` is tool-agnostic and\n * runs before the body has settled, so only the body knows what it collected.\n */\nexport function attachCancelledPartial(\n jobId: string,\n toolName: string,\n partial: { readonly partialVotes: readonly unknown[]; readonly panelSize: number }\n): boolean {\n const existing = readJobResult(jobId);\n if (\n existing?.status !== 'cancelled' ||\n existing.toolName !== toolName ||\n existing.cancelledPartial !== undefined\n ) {\n logger.debug('Skipping cancelled-partial write — record is not a bare cancelled record', {\n jobId,\n toolName,\n status: existing?.status ?? 'unknown',\n });\n return false;\n }\n const cancelledPartial = CancelledPartialSchema.parse({\n partialVotes: [...partial.partialVotes],\n seatsCast: partial.partialVotes.length,\n panelSize: partial.panelSize,\n });\n const updated: JobResult = { ...existing, cancelledPartial };\n persistJobRecordAcrossCandidates(jobId, updated);\n logger.debug('Attached partial votes to cancelled job record', {\n jobId,\n toolName,\n seatsCast: cancelledPartial.seatsCast,\n panelSize: cancelledPartial.panelSize,\n });\n return true;\n}\n","/**\n * A cancelled `consensus_vote` stops before any verdict and hands the votes it\n * had cast to the cancelled job record (#6735).\n *\n * Two defects shared one cause. `cancel_job` writes `cancelled` first, and\n * the body then ran on: it tallied whatever seats had answered, computed a\n * decision from that partial panel, recorded it to the correlation tracker and\n * appended it to the vote-record ledger — and then handed the result to\n * `writeJobComplete`, a no-op against a `cancelled` record (#4022). So the\n * ledger held a decision nobody asked for, and the job record held none of the\n * votes that had landed.\n *\n * Now `executeVoting` checks the job signal once the seats settle, and again\n * after the contrarian/escalation step. The ledger recorder checks it a last\n * time inside its file lock, right before the append, because the lock wait is\n * async. If it fired, each check throws {@link VoteCancelledError}, carrying\n * only the seats that cast a vote. Nothing downstream of that point runs: no engine, no decision, no\n * tracker, no ledger. The async dispatcher catches the error and attaches the\n * seats to the `cancelled` record through the store's one narrow writer.\n *\n * @module mcp/tools/consensus-vote-cancelled\n */\n\nimport { isTimeoutAbortReason } from '../../adapters/abort-utils.js';\nimport type { AgentVoteResult } from '../../cli/vote-types.js';\nimport { attachCancelledPartial } from '../jobs/job-cancelled-partial.js';\n\n/**\n * The job signal fired before the vote reached a verdict. Carries the seats\n * that cast a vote (every source except `error` — a seat aborted or never\n * launched by the cancel is an `error` result) and the panel size they were\n * cast against. Also thrown when the runaway guard aborts the job (`timedOut`,\n * and the message says so); that job is recorded `failed`, and the attach\n * below is then a no-op.\n */\nexport class VoteCancelledError extends Error {\n override readonly name = 'VoteCancelledError';\n\n constructor(\n readonly votesCast: readonly AgentVoteResult[],\n readonly panelSize: number,\n /** True when the runaway guard fired rather than `cancel_job`. */\n readonly timedOut = false\n ) {\n super(\n `${timedOut ? 'Vote timed out (runaway guard)' : 'Vote cancelled'} before a verdict: ` +\n `${String(votesCast.length)} of ${String(panelSize)} seats had cast a vote`\n );\n }\n}\n\n/**\n * Throw {@link VoteCancelledError} when `signal` has fired. Called once the\n * seats have settled and before anything reads them as a panel. No-op when\n * there is no signal (sync mode) or it has not fired.\n */\nexport function throwIfVoteCancelled(\n signal: AbortSignal | undefined,\n votes: readonly AgentVoteResult[],\n panelSize: number\n): void {\n if (signal?.aborted !== true) return;\n throw new VoteCancelledError(\n votes.filter((v) => v.source !== 'error'),\n panelSize,\n isTimeoutAbortReason(signal.reason)\n );\n}\n\n/**\n * Await an async vote body; on {@link VoteCancelledError}, attach the cast\n * seats to the job's `cancelled` record, then rethrow so `runAsJob` still\n * settles the job through its normal path (a no-op on the cancelled record).\n * `toolName` is the job's own tool — `consensus_vote`, or `pr_review` (#6750),\n * whose panel is collected by the same launcher.\n */\nexport async function attachPartialsOnCancel<T>(\n jobId: string,\n toolName: string,\n body: Promise<T>\n): Promise<T> {\n try {\n return await body;\n } catch (error: unknown) {\n if (error instanceof VoteCancelledError) {\n attachCancelledPartial(jobId, toolName, {\n partialVotes: error.votesCast,\n panelSize: error.panelSize,\n });\n }\n throw error;\n }\n}\n","/**\n * Persistent OutcomeStore — JSONL-backed cross-session persistence.\n *\n * Extends the in-memory OutcomeStore with disk-backed append-only\n * JSONL storage. Hydrates on construction, appends on every write.\n * Corrupt lines are skipped with a warning (graceful degradation).\n *\n * @module orchestration/outcomes/outcome-store-persistence\n * (Source: Issue #1009 — Cross-session persistence)\n */\n\nimport { appendFileSync, readFileSync, writeFileSync, existsSync } from 'node:fs';\n\nimport type { ILogger } from '../../core/index.js';\nimport { createLogger, getErrorMessage } from '../../core/index.js';\nimport { TaskOutcomeSchema } from './outcome-types.js';\nimport type { TaskOutcome } from './outcome-types.js';\nimport { OutcomeStore, registerPersistentOutcomeStoreFactory } from './outcome-store.js';\nimport type { OutcomeStoreConfig } from './outcome-store.js';\nimport { ensureLearningDir, getOutcomesFile } from '../../config/learning-persistence.js';\n\n// ============================================================================\n// Configuration\n// ============================================================================\n\n/**\n * Schema for hydrating persisted outcomes (#6538).\n *\n * Uses `.loose()` so that forward-compatible fields written by newer\n * versions (such as `routedBy`, `qualitySignals`, or future additions) are\n * retained across rewrite cycles (reclassification, purgeSkippedWorkers)\n * instead of being stripped by Zod's default unknown-key dropping.\n */\nconst PersistedOutcomeSchema = TaskOutcomeSchema.loose();\n\nexport interface PersistentOutcomeStoreConfig extends OutcomeStoreConfig {\n /** Override the file path (useful for testing). */\n readonly filePath?: string;\n /** Override the data directory (useful for testing). */\n readonly dataDir?: string;\n}\n\n// ============================================================================\n// Implementation\n// ============================================================================\n\n/**\n * OutcomeStore that persists entries to a JSONL file on disk.\n *\n * - Construction: hydrates from existing JSONL file (Zod-validates each line)\n * - Append: calls super.append() then appendFileSync one JSON line\n * - Corruption: bad lines are skipped with a warning log\n */\nexport class PersistentOutcomeStore extends OutcomeStore {\n private readonly filePath: string;\n private readonly logger: ILogger;\n\n constructor(config?: PersistentOutcomeStoreConfig, logger?: ILogger) {\n super(config);\n this.filePath = config?.filePath ?? getOutcomesFile();\n this.logger = logger ?? createLogger({ component: 'PersistentOutcomeStore' });\n\n const dataDir = config?.dataDir;\n ensureLearningDir(dataDir);\n this.hydrate();\n this.reclassifyHydrated();\n this.purgeSkippedOnHydrate();\n }\n\n /** Override append to persist each entry to disk. */\n override append(outcome: TaskOutcome): void {\n super.append(outcome);\n this.persistLine(outcome);\n }\n\n // ==========================================================================\n // Private\n // ==========================================================================\n\n /**\n * Reclassify hydrated entries that lack a failureCategory.\n * Bounded: reclassifyAll() skips success outcomes and already-classified\n * entries, so only unclassified failures are processed (#1457).\n */\n /**\n * Purge false failures from skipped workers on hydration (#1528).\n * These are 0ms non-success worker-* entries created before the\n * recording fix, representing routing decisions not real failures.\n */\n private purgeSkippedOnHydrate(): void {\n if (this.size === 0) return;\n const purged = this.purgeSkippedWorkers();\n if (purged > 0) {\n this.logger.info('Purged skipped-worker false failures from history', { purged });\n this.rewriteFile();\n }\n }\n\n private reclassifyHydrated(): void {\n if (this.size === 0) return;\n const reclassified = this.reclassifyAll();\n if (reclassified > 0) {\n this.logger.info('Reclassified hydrated outcomes with updated categories', {\n reclassified,\n });\n this.rewriteFile();\n }\n }\n\n private hydrate(): void {\n if (!existsSync(this.filePath)) {\n this.logger.debug('No outcomes file found, starting fresh', {\n path: this.filePath,\n });\n return;\n }\n\n try {\n const content = readFileSync(this.filePath, 'utf-8');\n const lines = content.split('\\n').filter((line) => line.trim().length > 0);\n let loaded = 0;\n let skipped = 0;\n\n for (const line of lines) {\n try {\n const parsed: unknown = JSON.parse(line);\n const result = PersistedOutcomeSchema.safeParse(parsed);\n if (result.success) {\n super.append(result.data);\n loaded++;\n } else {\n skipped++;\n }\n } catch (parseErr: unknown) {\n this.logger.debug('Skipping malformed outcome line during hydration', {\n error: getErrorMessage(parseErr),\n linePreview: line.slice(0, 80),\n });\n skipped++;\n }\n }\n\n this.logger.info('Hydrated outcomes from disk', {\n loaded,\n skipped,\n total: lines.length,\n path: this.filePath,\n });\n } catch (error: unknown) {\n const msg = getErrorMessage(error);\n this.logger.warn('Failed to hydrate outcomes from disk', {\n error: msg,\n path: this.filePath,\n });\n }\n }\n\n /** Rewrite the JSONL file from in-memory state after reclassification. */\n private rewriteFile(): void {\n try {\n const entries = this.query();\n const content = entries.map((e) => JSON.stringify(e)).join('\\n') + '\\n';\n writeFileSync(this.filePath, content, 'utf-8');\n } catch (error: unknown) {\n const msg = getErrorMessage(error);\n this.logger.warn('Failed to rewrite outcomes file after reclassification', {\n error: msg,\n path: this.filePath,\n });\n }\n }\n\n private persistLine(outcome: TaskOutcome): void {\n try {\n appendFileSync(this.filePath, JSON.stringify(outcome) + '\\n', 'utf-8');\n } catch (error: unknown) {\n const msg = getErrorMessage(error);\n this.logger.warn('Failed to persist outcome to disk', {\n error: msg,\n path: this.filePath,\n });\n }\n }\n}\n\n// Self-register factory so getOutcomeStore() can create PersistentOutcomeStore\n// without a circular top-level import.\nregisterPersistentOutcomeStoreFactory(() => new PersistentOutcomeStore());\n","/**\n * The served model and its cost on an outcome row (#6624).\n *\n * Three outcome writers put a marker in `TaskOutcome.model` instead of the\n * model that ran: the pipeline stages (`pipeline`), orchestrate workers\n * (`worker-<role>`) and consensus seats (`consensus`). Readers group on those\n * markers (the weather report and the aorchestra learnings key workers by\n * role through them), so the markers stay, and the model that answered goes\n * in `servedModel` beside them, with its cost.\n *\n * The cost comes from {@link servedCostDetail}, the wrapper the vote rollup\n * uses, so a row prices a call the way the usage log does. An unpriced model\n * is recorded as `priceBasis: 'unknown'` with no `costUsd`: an unknown, not $0.\n *\n * @module orchestration/outcomes/outcome-served-model\n */\n\nimport { servedCostDetail } from '../../cli-adapters/budget-arm-cost.js';\nimport type { EndpointArmId } from '../../cli-adapters/types-core.js';\nimport { priceBasisOf } from '../../learning/usage-log.js';\nimport type { TaskOutcome } from './outcome-types.js';\n\n/** What a writer knows about the call it is recording. */\nexport interface ServedCall {\n /** Model id the adapter reported serving the call; undefined when it reported none. */\n readonly model: string | undefined;\n /** Gateway arm that served the call, when a gateway model did. Prices by its declaration. */\n readonly gatewayArm?: EndpointArmId | undefined;\n /** Token counts the adapter reported; undefined when it reported none. */\n readonly inputTokens?: number | undefined;\n readonly outputTokens?: number | undefined;\n}\n\n/** The outcome fields {@link servedOutcomeFields} sets. */\ntype ServedOutcomeFields = Pick<TaskOutcome, 'servedModel' | 'costUsd' | 'priceBasis'>;\n\n/**\n * The `servedModel`, `costUsd` and `priceBasis` fields for an outcome row.\n *\n * - No call, or no served model: no fields. There is nothing to attribute.\n * - A served model without both token counts: `servedModel` only. No price is\n * looked up, so no basis is claimed and the cost stays unknown.\n * - Both token counts: the cost detail. `costUsd` is present only when a\n * price was found; an unpriced model reads `priceBasis: 'unknown'`.\n */\nexport function servedOutcomeFields(call: ServedCall | undefined): ServedOutcomeFields {\n const model = call?.model;\n if (call === undefined || model === undefined || model.length === 0) return {};\n const { inputTokens, outputTokens } = call;\n if (inputTokens === undefined || outputTokens === undefined) return { servedModel: model };\n const detail = servedCostDetail(call.gatewayArm, model, inputTokens, outputTokens);\n return {\n servedModel: model,\n priceBasis: priceBasisOf(detail),\n ...(detail.priced && { costUsd: detail.costUsd }),\n };\n}\n","/**\n * Shared post-vote recording for MCP and dev-pipeline decisions (#6872).\n * One correlation ID joins the ledger, decision cost and per-seat outcomes.\n * The ledger append runs first so cancellation cannot seed successful outcomes.\n *\n * @module mcp/tools/consensus-vote-completed-recording\n */\nimport type { DecisionGate } from '../../observability/decision-cost-store.js';\nimport { randomUUID } from 'node:crypto';\nimport { getTimeProvider, type ILogger } from '../../core/index.js';\nimport type { AgentVoteResult } from '../../cli/vote-types.js';\nimport type { VoteRecordPrBinding } from '../../audit/vote-record.js';\nimport {\n recordAuthenticVote,\n recordVoteSuccess,\n recordVoteError,\n type VoteRecordPersistOutcome,\n} from './consensus-vote-recording.js';\nimport { recordVoteDecisionCost } from './decision-cost-recording.js';\nimport { toRecordDecision, type ExtendedVotingResult } from './consensus-vote-types.js';\n\n/**\n * Context from the tool input the record needs but the voting result does not\n * carry: the declared options (#6053) and the two ratification bindings\n * (#4004, #5130).\n */\ninterface DeclaredByCaller {\n /** Which caller made the decision; defaults to the MCP `consensus_vote` gate. */\n readonly gate?: DecisionGate;\n /** Async runner provenance; omitted when no job ran the decision. */\n readonly jobId?: string | undefined;\n readonly options: readonly string[] | undefined;\n readonly ratifies?: string;\n readonly ratifiesPr?: VoteRecordPrBinding;\n /**\n * The async job's cancel signal (#6735), re-checked inside the ledger lock\n * right before the append. Absent in sync mode.\n */\n readonly signal?: AbortSignal | undefined;\n}\n\n/**\n * Best-effort post-vote side effects, extracted to keep `handleConsensusVote`\n * under the per-function line cap. Persists the authentic hash-chained vote\n * record (#3897) and rolls up per-decision cost (#3855), sharing one decision\n * id as the correlation key. Neither must fail the vote — both are guarded.\n *\n * Returns both the cost rollup and the structured vote-record persistence\n * outcome (#3991) so the handler can surface persistence visibility in the\n * result instead of leaving a skip as a server-only WARN.\n */\nasync function recordVoteSideEffects(\n proposal: string,\n result: ExtendedVotingResult,\n logger: ILogger,\n declared: DeclaredByCaller\n): Promise<{\n decisionId: string;\n costSummary: ReturnType<typeof recordVoteDecisionCost>;\n voteRecord: VoteRecordPersistOutcome;\n}> {\n const decisionId = `consensus-${String(getTimeProvider().now())}-${randomUUID().slice(0, 8)}`;\n // #3897: persist an authentic, hash-chained vote record to the runtime\n // vote ledger at vote time so the promotion gate/CI can rest\n // authenticity on the chain, not on hand-transcribed YAML. #4004: bind the\n // authority-tier ratification subject into the record when provided.\n const voteRecord = await recordAuthenticVote({\n proposal,\n strategy: result.strategy,\n result: result.result,\n votes: result.votes,\n declaredOptions: declared.options,\n // #4053: an error-policy short-circuit voided the vote → the PERSISTED record\n // must record `no_quorum`, matching the MCP response (not a stale `rejected`).\n errorVoided: result.policyReason !== undefined,\n // #4986: hand over the decision `resolveVoteDecision` already produced\n // (stamped on the result by `executeVoting`). `errorVoided` alone cannot\n // express an absolute_quorum void, whose reason is stamped on the response\n // and never on the result — so the record used to say `approved` for a vote\n // this tool reports as `no_quorum`.\n resolvedDecision: toRecordDecision(result.decision),\n // #6211: the EFFECTIVE policy `executeVoting` stamped, so a caller that\n // took the per-strategy default still gets `reduce_denominator` on the\n // ledger line rather than nothing.\n errorPolicy: result.errorPolicy,\n correlationId: decisionId,\n ...(declared.ratifies !== undefined ? { ratifies: declared.ratifies } : {}),\n // #5130: the PR binding takes the same hop as `ratifies`; the seam test\n // (`consensus-vote-ratifies-pr.test.ts`) reads it back off the ledger.\n ...(declared.ratifiesPr !== undefined ? { ratifiesPr: declared.ratifiesPr } : {}),\n signal: declared.signal,\n });\n // #3855: roll up + persist this decision's per-voter cost and ride it on the\n // existing response (no new MCP tool). A rollup failure must not fail the vote.\n const costSummary = recordVoteDecisionCost({\n decisionId,\n gate: declared.gate ?? 'consensus_vote',\n ...(declared.jobId !== undefined ? { jobId: declared.jobId } : {}),\n votes: result.votes,\n proposal,\n declaredOptions: declared.options,\n logger,\n });\n return { decisionId, costSummary, voteRecord };\n}\n\n/** Preserve MCP's distinct all-error response while sharing the recording guard. */\nexport class AllVotersFailedError extends Error {\n override readonly name = 'AllVotersFailedError';\n}\n\n/**\n * Detect all-error votes and return the structured error message instead of a\n * fake \"rejected\" (#1552); `null` when at least one seat answered. Empty case:\n * a panel with no votes at all is not \"all failed\" — it is `null` here and the\n * empty-panel guard in `recordCompletedVote` rejects it before recording.\n */\nfunction allVotersFailedError(\n votes: readonly AgentVoteResult[],\n proposal: string,\n logger: ILogger\n): string | null {\n const errorVotes = votes.filter((v) => v.source === 'error');\n if (errorVotes.length !== votes.length || votes.length === 0) return null;\n const failures = errorVotes.map((v) => `${v.role}: ${v.error ?? 'unknown error'}`).join('; ');\n logger.warn('All voters failed', { failureCount: errorVotes.length, failures });\n recordVoteError(proposal, `All ${String(errorVotes.length)} voters failed: ${failures}`);\n return `All ${String(errorVotes.length)} voters failed. Failures: ${failures}`;\n}\n\n/** Record one completed panel through the canonical ledger, cost and outcome writers. */\nexport async function recordCompletedVote(\n proposal: string,\n result: ExtendedVotingResult,\n logger: ILogger,\n declared: DeclaredByCaller = { options: undefined }\n): ReturnType<typeof recordVoteSideEffects> {\n const allFailed = allVotersFailedError(result.votes, proposal, logger);\n if (allFailed !== null) throw new AllVotersFailedError(allFailed);\n if (result.decision === undefined) {\n throw new Error('Consensus vote completed without a resolved decision');\n }\n if (result.votes.length === 0) {\n throw new Error('Consensus vote completed with an empty panel (no votes received)');\n }\n const recorded = await recordVoteSideEffects(proposal, result, logger, declared);\n recordVoteSuccess({\n decisionId: recorded.decisionId,\n proposal,\n strategy: result.strategy,\n decision: toRecordDecision(result.decision) ?? 'no_quorum',\n durationMs: result.totalTimeMs,\n approvalPercentage: result.result.approvalPercentage,\n votes: result.votes,\n });\n return recorded;\n}\n","/**\n * decision-cost-recording — attach a per-decision cost rollup to the EXISTING\n * consensus_vote / pr_review result + persist it.\n *\n * Source: Issue #3855 (epic #3854 child, M4).\n *\n * This is the consumer that rides the existing decision surfaces (#3855\n * explicitly forbids a new MCP tool — the 47-tool ceiling). It bridges a\n * panel's per-voter results into {@link VoterCostInput}s, reads the live billing\n * mode from `NEXUS_BILLING_MODE`, rolls them up via the pure\n * {@link rollupDecisionCost}, persists the summary to the {@link DecisionCostStore},\n * and returns the summary so the tool can attach it to its response.\n *\n * Per-voter token/cost is propagated where the adapter layer reported it; voters\n * with no usage — or whose model has no pricing anywhere in the registry chain\n * (#4165) — are folded in as UNMEASURED (not a measured $0) — see\n * {@link module:observability/decision-cost}. Record + measure ONLY — no routing\n * or weighting change.\n *\n * @module mcp/tools/decision-cost-recording\n */\n\nimport type { AgentVoteResult } from '../../cli/vote-types.js';\nimport { createLogger, getTimeProvider, getErrorMessage, type ILogger } from '../../core/index.js';\nimport { detectUndeclaredOptions } from './consensus-vote-option-detection.js';\nimport { servedCostDetail } from '../../cli-adapters/budget-arm-cost.js';\nimport { priceBasisOf, type CostDetail } from '../../learning/usage-log.js';\nimport { DecisionCostStore, type DecisionGate } from '../../observability/decision-cost-store.js';\nimport {\n UNKNOWN_MODEL,\n type DecisionBillingMode,\n type DecisionCostSummary,\n type UndeclaredOptionsDetectorRecord,\n type VoterCostInput,\n} from '../../observability/decision-cost.js';\n\n/** Resolve the active billing mode from env (default 'plan'). */\nexport function resolveBillingMode(): DecisionBillingMode {\n return process.env['NEXUS_BILLING_MODE'] === 'api' ? 'api' : 'plan';\n}\n\n/**\n * Bridge a panel's per-voter results into per-voter cost inputs.\n *\n * The vote result carries the model the adapter reported serving (#6663) and,\n * where the adapter reported them, token counts. When tokens are present we derive the api-mode cost via the\n * same registry-backed {@link computeCostDetail} the per-call usage log uses, so\n * a per-decision rollup and the per-call usage log price identically. When no\n * usage was reported the voter is left with no tokens/cost ⇒ unmeasured. A\n * seat carrying `gatewayArm` is priced by the gateway's declaration instead\n * ({@link voteCostDetail}, #4392 step 4).\n *\n * When the model resolves WITHOUT pricing anywhere in the registry chain\n * (#4165), `costUsd` is OMITTED — tokens are kept — so the rollup counts the\n * voter as UNMEASURED (#3855: missing cost is unmeasured, never a measured $0).\n *\n * Whenever a price WAS looked up, the resulting {@link PriceBasis} rides along\n * (#4406) so the recorded figure says whether it came from a vendor list rate\n * rather than reading as contract-accurate.\n */\n/**\n * Copy only the token counters the adapter actually reported. Every field is\n * spread conditionally so an absent counter stays absent — a fabricated 0\n * would read as a measurement (#4439).\n *\n * The cache figures ride along for visibility only: cost is still priced on\n * uncached input, because the registry carries no cache-read rate and pricing\n * the cached portion at the input rate would overstate spend (#4435).\n */\nfunction reportedTokenFields(v: AgentVoteResult): Partial<VoterCostInput> {\n return {\n ...(v.inputTokens !== undefined ? { inputTokens: v.inputTokens } : {}),\n ...(v.outputTokens !== undefined ? { outputTokens: v.outputTokens } : {}),\n ...(v.cachedInputTokens !== undefined ? { cachedInputTokens: v.cachedInputTokens } : {}),\n ...(v.cacheCreationInputTokens !== undefined\n ? { cacheCreationInputTokens: v.cacheCreationInputTokens }\n : {}),\n };\n}\n\n/**\n * The seat's cost detail, or `undefined` when nothing was looked up (no usage\n * reported). A seat that answered through a gateway (#4392 step 4,\n * `gatewayArm`) is priced by the arm's `NEXUS_GATEWAY_COST` declaration —\n * UNKNOWN when undeclared — never by the model id alone: a `claude-*` id a\n * gateway served used to roll up at Anthropic's list price as `'list'`.\n *\n * Priced by `servedModel`, the model the adapter reported answering, never by\n * `model`, the alias the seat requested (#6663): a seat that fell back to\n * another model was priced at the rate of the one it asked for. A seat that\n * reported usage but no served model has a cost nobody can price, so it reads\n * as unpriced (`'unknown'`, no `costUsd`) — never the requested alias's rate,\n * and never a measured $0.\n */\nfunction voteCostDetail(v: AgentVoteResult): CostDetail | undefined {\n const hasTokens = v.inputTokens !== undefined || v.outputTokens !== undefined;\n if (!hasTokens) return undefined;\n if (v.servedModel === undefined) return { costUsd: 0, priced: false, resolvedId: UNKNOWN_MODEL };\n return servedCostDetail(v.gatewayArm, v.servedModel, v.inputTokens ?? 0, v.outputTokens ?? 0);\n}\n\nexport function votesToCostInputs(votes: readonly AgentVoteResult[]): VoterCostInput[] {\n return votes.map((v) => {\n const detail = voteCostDetail(v);\n const input: VoterCostInput = {\n role: v.role,\n // #6663: the model that answered, the one the cost is priced at.\n model: v.servedModel,\n // #6115: the assignment beside the model that answered.\n ...(v.assignedCli !== undefined ? { assignedCli: v.assignedCli } : {}),\n ...reportedTokenFields(v),\n // #6821: every settled completion, beside the answering one's counters.\n ...(v.attemptUsage !== undefined ? { attemptUsage: v.attemptUsage } : {}),\n ...(v.attemptTelemetry !== undefined ? { attemptTelemetry: v.attemptTelemetry } : {}),\n ...(detail?.priced === true ? { costUsd: detail.costUsd } : {}),\n ...(detail?.pricingProvenance !== undefined\n ? { pricingProvenance: detail.pricingProvenance }\n : {}),\n // #4406 — state what kind of rate the cost rests on, but only when we\n // actually consulted the registry. No lookup ⇒ no claim (absent), which\n // is distinct from 'unknown' (\"we looked and there is no price\").\n ...(detail !== undefined ? { priceBasis: priceBasisOf(detail) } : {}),\n };\n return input;\n });\n}\n\nexport interface RecordDecisionCostOptions {\n /** Actual async job id; omitted for synchronous decisions. */\n readonly jobId?: string;\n /** Stable decision correlation id, independent of the async job id. */\n readonly decisionId: string;\n /** Which gate type incurred the cost. */\n readonly gate: DecisionGate;\n /** The panel's per-voter results. */\n readonly votes: readonly AgentVoteResult[];\n /** Override the store (testing). */\n readonly store?: DecisionCostStore;\n /** Override the billing mode (testing); defaults to the env-resolved mode. */\n readonly billingMode?: DecisionBillingMode;\n /** Override the logger (testing); defaults to a module logger. */\n readonly logger?: ILogger;\n /**\n * The undeclared-options detector's verdict on this vote (#5422). Passed\n * through to the store on every `consensus_vote`, fired or not; omitted by\n * `pr_review`, which runs no such detector.\n */\n readonly undeclaredOptionsDetector?: UndeclaredOptionsDetectorRecord;\n}\n\ninterface RecordVoteDecisionCostOptions extends Omit<\n RecordDecisionCostOptions,\n 'undeclaredOptionsDetector'\n> {\n readonly proposal: string;\n readonly declaredOptions: readonly string[] | undefined;\n readonly source?: 'cli' | 'mcp';\n}\n\n/** Record live detector telemetry from the full proposal, best effort for both vote entry points. */\nexport function recordVoteDecisionCost(\n options: RecordVoteDecisionCostOptions\n): DecisionCostSummary | undefined {\n // Empty and all-simulated panels provide no live detector measurement.\n if (options.votes.length === 0 || options.votes.every((v) => v.source === 'simulation'))\n return undefined;\n try {\n return recordDecisionCost({\n ...options,\n undeclaredOptionsDetector: {\n ...detectUndeclaredOptions(options.proposal, options.declaredOptions),\n declaredOptionCount: options.declaredOptions?.length ?? 0,\n ...(options.source !== undefined ? { source: options.source } : {}),\n },\n });\n } catch (error) {\n (options.logger ?? defaultLogger).warn('Per-decision cost rollup failed (non-fatal)', {\n error: getErrorMessage(error),\n });\n return undefined;\n }\n}\n\nconst defaultLogger = createLogger({ component: 'decision-cost-recording' });\n\n/**\n * Process-lifetime count of decision-cost rollups that FAILED to persist (#3910).\n *\n * The store is best-effort and never throws, so a dropped rollup is otherwise\n * invisible. Incrementing a counter (and logging — see {@link recordDecisionCost})\n * makes missing cost telemetry observable rather than silently swallowed. Reset\n * is test-only.\n */\nlet droppedCostRecordCount = 0;\n\n/** Read the count of decision-cost rollups dropped at persist time (#3910). */\nexport function getDroppedCostRecordCount(): number {\n return droppedCostRecordCount;\n}\n\n/**\n * Warn rate-limiter for dropped cost rollups (#3916).\n *\n * If the store goes unwritable (disk full / perms / I/O), a per-decision warn\n * would flood the logs and could degrade the main decision path — ironically\n * risking the never-fail invariant the warn exists to protect. So the warn is\n * rate-limited: emit it for the first {@link WARN_BURST} consecutive drops, then\n * at most once per {@link WARN_PERIOD} further drops. The COUNTER still\n * increments on EVERY drop (it stays exact regardless of suppression), and the\n * decision still never fails. The emitted warn carries `suppressedSinceLastWarn`\n * so a reader can see how many drops a single line stands in for.\n */\nconst WARN_BURST = 5;\nconst WARN_PERIOD = 1000;\n// Never stay silent longer than this on a SLOW leak (#3916): pure count-based\n// suppression (every 1000th) would hide ~999 drops for ~41 days at 1/hr. A\n// time escape surfaces a persistent low-rate failure within the window.\nconst WARN_MAX_SILENCE_MS = 60_000;\nlet warnCountSinceReset = 0;\nlet lastWarnAtMs = 0;\nlet warnClockOverrideMs: number | null = null;\n\n/** Testing seam: pin the warn-limiter clock (#3916). Pass null to use real time. */\nexport function _setWarnClockForTests(ms: number | null): void {\n warnClockOverrideMs = ms;\n}\n\nfunction warnNowMs(): number {\n return warnClockOverrideMs ?? Date.now();\n}\n\n/**\n * Whether this drop should emit a warn: the first {@link WARN_BURST} consecutive\n * drops, then every {@link WARN_PERIOD}-th, OR after {@link WARN_MAX_SILENCE_MS}\n * of silence (so a slow leak still surfaces rather than being suppressed for\n * thousands of drops). Side effect: anchors the silence timer on each emitted warn.\n */\nfunction shouldWarnForDrop(dropIndex: number): boolean {\n const now = warnNowMs();\n const countTrigger = dropIndex <= WARN_BURST || (dropIndex - WARN_BURST) % WARN_PERIOD === 0;\n const timeTrigger = dropIndex > WARN_BURST && now - lastWarnAtMs >= WARN_MAX_SILENCE_MS;\n if (countTrigger || timeTrigger) {\n lastWarnAtMs = now;\n return true;\n }\n return false;\n}\n\n/** Reset the dropped-cost-record counter and warn limiter (testing only, #3910/#3916). */\nexport function resetDroppedCostRecordCount(): void {\n droppedCostRecordCount = 0;\n warnCountSinceReset = 0;\n lastWarnAtMs = 0;\n warnClockOverrideMs = null;\n}\n\n/** Read how many dropped-cost warns have actually been emitted (testing, #3916). */\nexport function getDroppedCostWarnCount(): number {\n return warnCountSinceReset;\n}\n\n/**\n * Roll up + persist a decision's cost and return the summary for the response.\n *\n * Best-effort persistence: the store never throws into the caller (an\n * observability sink must not break the decision it observes), so on any\n * failure the rollup is still returned for the response. Riding the existing\n * surface — the caller attaches the returned `summary` to its result object.\n *\n * Non-silent drops (#3910): when the rollup fails to persist (fs error / schema\n * reject) the store reports `persisted: false`; we log a warning AND increment a\n * counter so dropped billing telemetry is visible, instead of vanishing. The\n * decision still proceeds — the summary is always returned.\n */\nexport function recordDecisionCost(options: RecordDecisionCostOptions): DecisionCostSummary {\n const billingMode = options.billingMode ?? resolveBillingMode();\n const voters = votesToCostInputs(options.votes);\n const store = options.store ?? new DecisionCostStore();\n const logger = options.logger ?? defaultLogger;\n const timestamp = new Date(getTimeProvider().now()).toISOString();\n const { record, persisted } = store.record({\n decisionId: options.decisionId,\n ...(options.jobId !== undefined ? { jobId: options.jobId } : {}),\n gate: options.gate,\n voters,\n billingMode,\n timestamp,\n ...(options.undeclaredOptionsDetector !== undefined\n ? { undeclaredOptionsDetector: options.undeclaredOptionsDetector }\n : {}),\n });\n if (!persisted) {\n // Count EVERY drop (stays exact); rate-limit only the warn so an unwritable\n // store can't flood the log per-decision and degrade the main path (#3916).\n droppedCostRecordCount += 1;\n if (shouldWarnForDrop(droppedCostRecordCount)) {\n const suppressedSinceLastWarn = droppedCostRecordCount - warnCountSinceReset - 1;\n warnCountSinceReset += 1;\n logger.warn('Decision-cost rollup dropped (failed to persist) — billing telemetry lost', {\n decisionId: options.decisionId,\n gate: options.gate,\n totalCostUsd: record.summary.totalCostUsd,\n totalTokens: record.summary.totalTokens,\n droppedCostRecordCount,\n suppressedSinceLastWarn,\n });\n }\n }\n return record.summary;\n}\n","/**\n * Consensus → pipeline-bus signal emitter (#3147, epic #3143 P2).\n *\n * Emits the `signal.vote_rejected` observability signal onto the typed pipeline\n * event bus when a consensus vote resolves to `rejected`, closing the\n * self-tuning loop (the shadow TuneStage consumes it). Lives at the MCP\n * integration layer ON PURPOSE: the pure `ConsensusEngine` stays decoupled from\n * the pipeline bus, preserving the `A = observability / B = messaging` boundary\n * adopted for #3289 (scope Option 2 — observability signals route through bus A,\n * the collaboration messaging bus is untouched).\n *\n * @module mcp/tools/consensus-vote-signals\n */\n\nimport { getErrorMessage, getTimeProvider } from '../../core/index.js';\nimport type { ILogger } from '../../core/index.js';\nimport type { ConsensusResult } from '../../consensus/types.js';\nimport type { IEventBus } from '../../pipeline/event-types.js';\n\n/** Distinct rejection categories across the reject votes, or undefined if none. */\nfunction rejectionRulesFrom(result: ConsensusResult): readonly string[] | undefined {\n const rules = new Set<string>();\n for (const vote of result.votes.values()) {\n if (vote.decision === 'reject' && vote.rejectionCategories !== undefined) {\n for (const category of vote.rejectionCategories) rules.add(category);\n }\n }\n return rules.size > 0 ? [...rules] : undefined;\n}\n\n/**\n * Emit `signal.vote_rejected` onto `bus` when `result.outcome === 'rejected'`.\n * No-op for any other outcome. Emission errors are swallowed and logged —\n * observability signalling must never break the vote path.\n */\nexport function emitVoteRejectedSignal(\n result: ConsensusResult,\n bus: IEventBus,\n logger: ILogger\n): void {\n if (result.outcome !== 'rejected') return;\n try {\n const rejectionRules = rejectionRulesFrom(result);\n bus.emit({\n type: 'signal.vote_rejected',\n timestamp: getTimeProvider().now(),\n proposalId: result.proposalId,\n approvalPercentage: result.approvalPercentage,\n ...(rejectionRules !== undefined ? { rejectionRules } : {}),\n });\n } catch (error) {\n logger.warn('Failed to emit signal.vote_rejected', { error: getErrorMessage(error) });\n }\n}\n","/**\n * Simulation Guard — fail-closed gate for `simulateVotes: true`.\n *\n * Simulated votes are random and exist only for unit tests and demos.\n * Outside a test runner a `simulateVotes: true` request is REJECTED unless\n * the operator explicitly opts in via `NEXUS_ALLOW_SIMULATE=1` — the field\n * is caller-supplied on the MCP input schemas, so warn-and-proceed let a\n * steered caller manufacture a governance approval from a random panel.\n * (Source: Issue #2317, #2319; fail-closed rework #4170)\n *\n * The guard NEVER throws: call sites sit inside pipeline try blocks whose\n * catch paths categorize as `internal` — a thrown denial would be\n * miscategorized. It returns a structured verdict instead.\n *\n * @module mcp/tools/simulation-guard\n */\n\nimport type { ILogger } from '../../core/index.js';\nimport { toolStructuredError, type ToolResult } from './tool-result.js';\n\nconst WARNED = new Set<string>();\n\n/** Explicit opt-in env var permitting simulated votes outside test runners (#4170). */\nconst ALLOW_SIMULATE_ENV = 'NEXUS_ALLOW_SIMULATE';\n\n/** Returns true when running under vitest or another test runner. */\nexport function isTestRunner(): boolean {\n return process.env.VITEST === 'true' || process.env.NODE_ENV === 'test';\n}\n\n/**\n * Verdict of {@link checkSimulationAllowed}. `optedIn` distinguishes the\n * test-runner path (false — nothing to surface) from the explicit\n * `NEXUS_ALLOW_SIMULATE=1` path (true — callers stamp `simulated: true`\n * on their output so a demo result can never pass as a real decision).\n */\nexport type SimulationCheckResult =\n | { readonly allowed: true; readonly optedIn: boolean }\n | { readonly allowed: false; readonly reason: string };\n\n/**\n * Decide whether a `simulateVotes: true` request may proceed (#4170):\n *\n * - test runner (VITEST/NODE_ENV) → allowed, `optedIn: false`;\n * - `NEXUS_ALLOW_SIMULATE=1` → allowed, `optedIn: true`, with the\n * one-shot RANDOM-output warning logged per (tool, process);\n * - otherwise → NOT allowed, with a reason naming the\n * opt-in env var. Never throws — see the module doc.\n */\nexport function checkSimulationAllowed(toolName: string, logger: ILogger): SimulationCheckResult {\n if (isTestRunner()) return { allowed: true, optedIn: false };\n if (process.env[ALLOW_SIMULATE_ENV] === '1') {\n warnOnce(toolName, logger);\n return { allowed: true, optedIn: true };\n }\n return {\n allowed: false,\n reason:\n `[${toolName}] simulateVotes=true is rejected outside test runners: simulated votes ` +\n `are RANDOM and must not produce real decisions (#4170). ` +\n `Set ${ALLOW_SIMULATE_ENV}=1 to explicitly opt in (demos only).`,\n };\n}\n\n/**\n * Shared denial envelope for a failed {@link checkSimulationAllowed}: the\n * three call sites (consensus_vote, run_pipeline, run_dev_pipeline) must\n * reject identically — `permission` category, detail naming the opt-in.\n */\nexport function simulationDeniedResult(reason: string): ToolResult {\n return toolStructuredError({\n errorCategory: 'permission',\n message: reason,\n detail: { optIn: `${ALLOW_SIMULATE_ENV}=1` },\n });\n}\n\n/**\n * One-shot warning per (tool, process) pair for the explicit opt-in path.\n * `simulateVotes: true` output is random; the warning keeps an opted-in demo\n * run from being silently mistaken for a real decision (#2319).\n */\nfunction warnOnce(toolName: string, logger: ILogger): void {\n if (WARNED.has(toolName)) return;\n WARNED.add(toolName);\n logger.warn(\n `[${toolName}] simulateVotes=true: output is RANDOM and reserved for tests/demos. Do not treat the result as a real decision.`\n );\n}\n\n/** Test-only: clear the warned-set so repeated tests can re-trigger the warning. */\nexport function _resetWarned(): void {\n WARNED.clear();\n}\n","/**\n * nexus-agents/mcp/jobs — per-job AbortController registry (#4086).\n *\n * `runAsJob` dispatches detached background work; `cancel_job` previously only\n * wrote a durable `cancelled` record but could not actually STOP the in-flight\n * work (run-as-job had no abort wiring, #4017). This registry closes that gap: a\n * dispatched job registers an `AbortController` keyed by `jobId`, the job body\n * receives `controller.signal`, and `cancel_job` calls {@link abortJob} to abort\n * it — so a tool that threads the signal into its awaited work is interrupted in\n * the same process. (Tools that ignore the signal still run to completion, but the\n * record is preserved as `cancelled` by the terminal-writer guards, #4022.)\n *\n * Process-local and same-process only (no IPC): a worker in another process must\n * still poll the durable record.\n *\n * @module mcp/jobs/job-abort-registry\n */\n\nconst controllers = new Map<string, AbortController>();\n\n/**\n * Register a fresh `AbortController` for `jobId` and return it. The dispatcher\n * passes its `signal` to the job body and must call {@link unregisterJobAbort}\n * when the job settles (whether it completed, failed, or was aborted).\n */\nexport function registerJobAbort(jobId: string): AbortController {\n const controller = new AbortController();\n controllers.set(jobId, controller);\n return controller;\n}\n\n/**\n * Abort the in-flight job's signal, if it is still registered. Returns true when a\n * live controller was found and aborted, false when the job is unknown / already\n * settled (in which case there is nothing in-flight to stop — the durable record\n * is the source of truth). The entry is removed so a late settle doesn't double-fire.\n */\nexport function abortJob(jobId: string, reason?: string): boolean {\n const controller = controllers.get(jobId);\n if (controller === undefined) return false;\n controllers.delete(jobId);\n controller.abort(reason ?? 'cancelled via cancel_job');\n return true;\n}\n\n/** Remove the controller for a settled job. Idempotent. */\nexport function unregisterJobAbort(jobId: string): void {\n controllers.delete(jobId);\n}\n\n/** Number of in-flight controllers (test/observability). @internal */\nexport function jobAbortRegistrySize(): number {\n return controllers.size;\n}\n","/**\n * Structured task state — JSONL append-only log (#2033).\n *\n * Writes a per-task log at `~/.nexus-agents/tasks/state-{taskId}.jsonl`\n * (overridable via `customDir` for tests). Replay reduces the log\n * forward to a current `StructuredTaskState` snapshot — suitable for\n * resume-after-restart and STATE.md-style inspection.\n * Security and error-handling characteristics:\n * - Directory mode 0o700, file mode 0o600\n * - Path-traversal validation on taskId\n * - `Result<T, Error>` returns, no exceptions for expected failures\n *\n * @module context/structured-task-state\n */\n\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { AsyncLocalStorage } from 'node:async_hooks';\nimport { nexusDataPath } from '../config/nexus-data-dir.js';\nimport type { Result } from '../core/result.js';\nimport { ok, err } from '../core/result.js';\nimport { createLogger } from '../core/logger.js';\nimport {\n StructuredTaskLogEntrySchema,\n TASK_RESULT_MAX_BYTES,\n type ProgressLedgerEntry,\n type ReflectAction,\n type StructuredTaskLogEntry,\n type StructuredTaskState,\n type TaskBlocker,\n type TaskCancellation,\n type TaskDecision,\n type TaskLedger,\n type TaskPosition,\n type TaskStage,\n} from './structured-task-state-types.js';\n\nconst logger = createLogger({ component: 'structured-task-state' });\n\n/** Subdirectory name under the resolved nexus data dir for task-state logs. */\nconst TASKS_SUBDIR = 'tasks';\n\nconst FILE_MODE = 0o600;\nconst DIR_MODE = 0o700;\n\nconst asyncTaskStateJob = new AsyncLocalStorage<string>();\n\n/** Run work whose task-state initialization must record async dispatch. @internal */\nexport function withAsyncTaskStateDispatch<T>(jobId: string, operation: () => T): T {\n return asyncTaskStateJob.run(jobId, operation);\n}\n\n/**\n * The jobId of the async dispatch the current async context belongs to, or\n * `undefined` outside any (#6162). The heartbeat bridge in `mcp/jobs` uses it\n * to attribute a pipeline-bus event to the job whose body emitted it.\n * @internal\n */\nexport function currentAsyncDispatchJobId(): string | undefined {\n return asyncTaskStateJob.getStore();\n}\n\nfunction getTasksDir(customDir?: string): string {\n if (customDir !== undefined) return path.resolve(customDir);\n return nexusDataPath(TASKS_SUBDIR);\n}\n\nfunction getLogPath(taskId: string, customDir?: string): string {\n return path.join(getTasksDir(customDir), `state-${taskId}.jsonl`);\n}\n\n/**\n * Enumerate the task ids that have a state log on disk (#3693). Walks the tasks\n * dir for `state-<taskId>.jsonl` files; returns `[]` when the dir is absent or\n * unreadable (best-effort, never throws). `customDir` steers the lookup for tests.\n */\nexport function listTaskStateIds(customDir?: string): string[] {\n const dir = getTasksDir(customDir);\n if (!fs.existsSync(dir)) return [];\n let entries: string[];\n try {\n entries = fs.readdirSync(dir);\n } catch (cause) {\n logger.warn('tasks directory unreadable', {\n dir,\n error: cause instanceof Error ? cause.message : String(cause),\n });\n return [];\n }\n const ids: string[] = [];\n for (const entry of entries) {\n const match = /^state-(.+)\\.jsonl$/.exec(entry);\n if (match?.[1] !== undefined) ids.push(match[1]);\n }\n return ids;\n}\n\nfunction validateTaskId(taskId: string): Result<string, Error> {\n if (taskId.includes('..') || taskId.includes('/') || taskId.includes('\\\\')) {\n return err(new Error('Invalid task ID: contains path traversal characters'));\n }\n if (taskId.length === 0 || taskId.length > 128) {\n return err(new Error('Invalid task ID: must be 1-128 characters'));\n }\n return ok(taskId);\n}\n\nfunction ensureTasksDir(customDir?: string): Result<string, Error> {\n const dirPath = getTasksDir(customDir);\n try {\n fs.mkdirSync(dirPath, { recursive: true, mode: DIR_MODE });\n return ok(dirPath);\n } catch (cause) {\n const e = cause instanceof Error ? cause : new Error(String(cause));\n return err(new Error(`Failed to create tasks directory at ${dirPath}: ${e.message}`));\n }\n}\n\n/** Append a log entry (no state computation). Pure I/O. */\nfunction appendLogEntry(\n taskId: string,\n entry: StructuredTaskLogEntry,\n customDir?: string\n): Result<void, Error> {\n const idCheck = validateTaskId(taskId);\n if (!idCheck.ok) return err(idCheck.error);\n const dirResult = ensureTasksDir(customDir);\n if (!dirResult.ok) return err(dirResult.error);\n\n const filePath = getLogPath(taskId, customDir);\n const line = JSON.stringify(entry) + '\\n';\n try {\n fs.appendFileSync(filePath, line, { mode: FILE_MODE });\n return ok(undefined);\n } catch (cause) {\n const e = cause instanceof Error ? cause : new Error(String(cause));\n return err(new Error(`Failed to write task state entry: ${e.message}`));\n }\n}\n\n/**\n * Initialize structured state for a new task. Writes the full initial\n * state as an `init` log entry. Safe to call once per taskId.\n */\nexport function initTaskState(state: StructuredTaskState, customDir?: string): Result<void, Error> {\n const isAsyncJob = asyncTaskStateJob.getStore() === state.taskId;\n const persistedState = isAsyncJob ? { ...state, dispatch: 'async' as const } : state;\n return appendLogEntry(\n state.taskId,\n { event: 'init', ts: state.updatedAt, state: persistedState },\n customDir\n );\n}\n\nexport function appendDecision(\n taskId: string,\n decision: TaskDecision,\n customDir?: string\n): Result<void, Error> {\n return appendLogEntry(taskId, { event: 'decision', ts: decision.ts, decision }, customDir);\n}\n\nexport function appendBlocker(\n taskId: string,\n blocker: TaskBlocker,\n customDir?: string\n): Result<void, Error> {\n return appendLogEntry(taskId, { event: 'blocker', ts: blocker.ts, blocker }, customDir);\n}\n\nexport function resolveBlocker(\n taskId: string,\n blockerIndex: number,\n resolvedAt: string,\n customDir?: string\n): Result<void, Error> {\n return appendLogEntry(\n taskId,\n { event: 'blocker_resolved', ts: resolvedAt, blockerIndex, resolvedAt },\n customDir\n );\n}\n\nexport function updateStage(\n taskId: string,\n stage: TaskStage,\n ts: string,\n customDir?: string\n): Result<void, Error> {\n return appendLogEntry(taskId, { event: 'stage', ts, stage }, customDir);\n}\n\nexport function updatePosition(\n taskId: string,\n position: TaskPosition,\n ts: string,\n customDir?: string\n): Result<void, Error> {\n return appendLogEntry(taskId, { event: 'position', ts, position }, customDir);\n}\n\n/**\n * Replace the Magentic-One Task Ledger atomically (#2278). The outer loop calls\n * this when it replans — facts/guesses/openQuestions are revised together so\n * downstream reflections are reading a consistent set.\n */\nexport function updateTaskLedger(\n taskId: string,\n ledger: TaskLedger,\n customDir?: string\n): Result<void, Error> {\n return appendLogEntry(taskId, { event: 'task_ledger', ts: ledger.updatedAt, ledger }, customDir);\n}\n\n/**\n * Append a Magentic-One Progress Ledger entry (#2278). Inner-loop reflection\n * after a step: was the plan still valid, are we stuck, what to do next.\n */\nexport function appendProgressLedgerEntry(\n taskId: string,\n entry: ProgressLedgerEntry,\n customDir?: string\n): Result<void, Error> {\n return appendLogEntry(taskId, { event: 'progress_ledger', ts: entry.ts, entry }, customDir);\n}\n\n/**\n * Append a tool-result payload (#3043 / epic #2631 Stage 2). Carries the\n * same shape the synchronous mode would have returned inline. Writers\n * should `updateStage(taskId, 'complete', ...)` immediately before so a\n * polling reader observes the terminal stage transition + result together.\n *\n * The payload is JSON-serialized to measure size; over-cap writes\n * (> `TASK_RESULT_MAX_BYTES`) get replaced with a typed truncation\n * marker. The cap is observable by the caller (the reducer surfaces\n * `state.result` as the truncation marker rather than the original) so\n * silent data loss is impossible.\n */\nexport function appendResult(\n taskId: string,\n result: unknown,\n ts: string,\n customDir?: string\n): Result<void, Error> {\n let payload: unknown = result;\n let serialized: string;\n try {\n serialized = JSON.stringify(result ?? null);\n } catch (cause) {\n const e = cause instanceof Error ? cause : new Error(String(cause));\n return err(new Error(`Failed to serialize result for task ${taskId}: ${e.message}`));\n }\n // Note: `Buffer.byteLength` is the right unit — JSON.stringify length is\n // UTF-16 code units, not the bytes that hit disk. For ASCII the two\n // coincide; for non-ASCII / emoji results the byte-count is what bounds\n // the actual storage cost.\n const bytes = Buffer.byteLength(serialized, 'utf-8');\n if (bytes > TASK_RESULT_MAX_BYTES) {\n payload = {\n truncated: true,\n originalBytes: bytes,\n maxBytes: TASK_RESULT_MAX_BYTES,\n note: 'Result exceeded TASK_RESULT_MAX_BYTES — original dropped at write time.',\n };\n logger.warn('Task result truncated at write', {\n taskId,\n bytes,\n max: TASK_RESULT_MAX_BYTES,\n });\n }\n return appendLogEntry(taskId, { event: 'result', ts, result: payload }, customDir);\n}\n\n/**\n * Append a cancellation marker (#3043 / epic #2631 Stage 2). Called by\n * `cancel_job`. The reducer is append-only: if a cancellation already\n * exists in the log, subsequent cancellation events are kept on disk\n * (for audit) but DON'T overwrite the original `requestedAt` — so a\n * malicious or buggy double-cancel can't rewrite history.\n */\nexport function appendCancellation(\n taskId: string,\n cancellation: TaskCancellation,\n customDir?: string\n): Result<void, Error> {\n return appendLogEntry(\n taskId,\n { event: 'cancellation', ts: cancellation.requestedAt, cancellation },\n customDir\n );\n}\n\n/**\n * Read the most recent ProgressLedger entry's suggested action — what\n * `Orchestrator.reflect()` returns. Returns `'continue'` when no progress-ledger\n * entries exist yet (default to \"no reflection has flagged a problem\"), and an\n * error if the task log itself can't be read.\n */\nexport function reflect(taskId: string, customDir?: string): Result<ReflectAction, Error> {\n const stateResult = readTaskState(taskId, customDir);\n if (!stateResult.ok) return err(stateResult.error);\n const ledger = stateResult.value.progressLedger;\n if (ledger === undefined || ledger.length === 0) return ok('continue');\n const last = ledger[ledger.length - 1];\n if (last === undefined) return ok('continue');\n return ok(last.suggestedAction);\n}\n\n/**\n * Read the log file and reduce it to the current state snapshot.\n *\n * Returns `err` when the file doesn't exist or no `init` entry is\n * present. Malformed lines are skipped with a warning (log, don't\n * fail).\n */\nexport function readTaskState(\n taskId: string,\n customDir?: string\n): Result<StructuredTaskState, Error> {\n const idCheck = validateTaskId(taskId);\n if (!idCheck.ok) return err(idCheck.error);\n\n const filePath = getLogPath(taskId, customDir);\n if (!fs.existsSync(filePath)) {\n return err(new Error(`No state log for task: ${taskId}`));\n }\n\n let content: string;\n try {\n content = fs.readFileSync(filePath, 'utf-8');\n } catch (cause) {\n const e = cause instanceof Error ? cause : new Error(String(cause));\n return err(new Error(`Failed to read state log: ${e.message}`));\n }\n\n const lines = content.split('\\n').filter((l) => l.length > 0);\n const entries: StructuredTaskLogEntry[] = [];\n for (const line of lines) {\n try {\n const parsed: unknown = JSON.parse(line);\n const validated = StructuredTaskLogEntrySchema.safeParse(parsed);\n if (validated.success) {\n entries.push(validated.data);\n } else {\n logger.warn('Skipping malformed task-state log entry', {\n taskId,\n error: validated.error.message,\n });\n }\n } catch (cause) {\n const msg = cause instanceof Error ? cause.message : String(cause);\n logger.warn('Skipping unparseable task-state log entry', { taskId, error: msg });\n }\n }\n\n return reduceLogEntries(taskId, entries);\n}\n\n/**\n * Fold a sequence of log entries into the final state. Exported so\n * tests can exercise the reducer without touching the filesystem.\n */\nexport function reduceLogEntries(\n taskId: string,\n entries: readonly StructuredTaskLogEntry[]\n): Result<StructuredTaskState, Error> {\n const init = entries.find((e) => e.event === 'init');\n if (init === undefined) {\n return err(new Error(`No init entry found for task: ${taskId}`));\n }\n const initState = init.state;\n if (initState.taskId !== taskId) {\n return err(\n new Error(`Task ID mismatch: log contains state for ${initState.taskId}, expected ${taskId}`)\n );\n }\n\n // #3043: monotonic version. Pre-Stage-2 logs lack the field; default\n // to 0 and start counting from there. Each non-init event bumps by 1.\n let state: StructuredTaskState = {\n ...initState,\n decisions: [...initState.decisions],\n blockers: initState.blockers.map((b) => ({ ...b })),\n version: initState.version ?? 0,\n // #3090: createdAt is fixed at the init entry's ts and never advances\n // (unlike updatedAt). Prefer an explicit createdAt on the init state,\n // else fall back to the init entry's ts.\n createdAt: initState.createdAt ?? init.ts,\n };\n\n for (const entry of entries) {\n if (entry === init) continue;\n state = applyLogEntry(state, entry);\n }\n return ok(state);\n}\n\n/** Apply a blockers-related event (#2033). */\nfunction applyBlockerEvent(\n state: StructuredTaskState,\n entry: Extract<StructuredTaskLogEntry, { event: 'blocker' | 'blocker_resolved' }>,\n nextVersion: number\n): StructuredTaskState {\n if (entry.event === 'blocker') {\n return {\n ...state,\n blockers: [...state.blockers, entry.blocker],\n updatedAt: entry.ts,\n version: nextVersion,\n };\n }\n return {\n ...state,\n blockers: state.blockers.map((b, i) =>\n i === entry.blockerIndex ? { ...b, resolved: entry.resolvedAt } : b\n ),\n updatedAt: entry.ts,\n version: nextVersion,\n };\n}\n\n/** Apply a simple scalar/ledger replacement event (no array merge). */\nfunction applyReplacementEvent(\n state: StructuredTaskState,\n entry: Extract<\n StructuredTaskLogEntry,\n { event: 'stage' | 'position' | 'task_ledger' | 'decision' | 'progress_ledger' }\n >,\n nextVersion: number\n): StructuredTaskState {\n switch (entry.event) {\n case 'decision':\n return {\n ...state,\n decisions: [...state.decisions, entry.decision],\n updatedAt: entry.ts,\n version: nextVersion,\n };\n case 'stage':\n return { ...state, stage: entry.stage, updatedAt: entry.ts, version: nextVersion };\n case 'position':\n return { ...state, position: entry.position, updatedAt: entry.ts, version: nextVersion };\n case 'task_ledger':\n return { ...state, taskLedger: entry.ledger, updatedAt: entry.ts, version: nextVersion };\n case 'progress_ledger':\n return {\n ...state,\n progressLedger: [...(state.progressLedger ?? []), entry.entry],\n updatedAt: entry.ts,\n version: nextVersion,\n };\n }\n}\n\n/**\n * Apply a result or cancellation event (#3043 / epic #2631 Stage 2). Result\n * always assigns; cancellation is append-only (in-memory keeps the FIRST\n * requestedAt across duplicate events).\n */\nfunction applyTerminalEvent(\n state: StructuredTaskState,\n entry: Extract<StructuredTaskLogEntry, { event: 'result' | 'cancellation' }>,\n nextVersion: number\n): StructuredTaskState {\n if (entry.event === 'result') {\n return { ...state, result: entry.result, updatedAt: entry.ts, version: nextVersion };\n }\n return {\n ...state,\n cancellation: state.cancellation ?? entry.cancellation,\n updatedAt: entry.ts,\n version: nextVersion,\n };\n}\n\n/**\n * Map each event tag to the apply-helper that owns it. Lets `applyLogEntry`\n * dispatch in one table lookup rather than a 10-case switch — the latter\n * trips the per-function complexity cap as the event set grows (#3043).\n */\nconst EVENT_CATEGORY: Record<\n StructuredTaskLogEntry['event'],\n 'init' | 'blocker' | 'replace' | 'terminal'\n> = {\n init: 'init',\n blocker: 'blocker',\n blocker_resolved: 'blocker',\n decision: 'replace',\n stage: 'replace',\n position: 'replace',\n task_ledger: 'replace',\n progress_ledger: 'replace',\n result: 'terminal',\n cancellation: 'terminal',\n};\n\nfunction applyLogEntry(\n state: StructuredTaskState,\n entry: StructuredTaskLogEntry\n): StructuredTaskState {\n const category = EVENT_CATEGORY[entry.event];\n if (category === 'init') return state;\n // #3043: every non-init event bumps the monotonic version. Calculated\n // here (not in each branch) so a new event type can't accidentally\n // forget to bump.\n const nextVersion = (state.version ?? 0) + 1;\n if (category === 'blocker') {\n return applyBlockerEvent(\n state,\n entry as Extract<StructuredTaskLogEntry, { event: 'blocker' | 'blocker_resolved' }>,\n nextVersion\n );\n }\n if (category === 'terminal') {\n return applyTerminalEvent(\n state,\n entry as Extract<StructuredTaskLogEntry, { event: 'result' | 'cancellation' }>,\n nextVersion\n );\n }\n return applyReplacementEvent(\n state,\n entry as Extract<\n StructuredTaskLogEntry,\n { event: 'decision' | 'stage' | 'position' | 'task_ledger' | 'progress_ledger' }\n >,\n nextVersion\n );\n}\n","/**\n * Structured task state — type definitions (#2033).\n *\n * Per-task state (decisions, blockers, stage, position) that a\n * long-running orchestration task mutates as it progresses. Designed\n * for the STATE.md-equivalent pattern from GSD — replacing ad-hoc\n * `memory_write` calls with a typed append-only log keyed by taskId.\n *\n * Serialized one-entry-per-JSONL-line so a later `query_trace` can\n * replay the full evolution, and resume-after-timeout reads the latest\n * state without replaying everything.\n *\n * @module context/structured-task-state-types\n */\n\nimport { z } from 'zod';\n\n/** Task execution lifecycle stages. */\nexport const TaskStageSchema = z.enum([\n 'planning',\n 'executing',\n 'verifying',\n 'complete',\n 'blocked',\n // #3091 / epic #2631: terminal failure stage. Distinct from `blocked`\n // (recoverable, still in-flight) — `failed` is terminal and maps to the\n // job-result `failed` status. Added so async-mode writers can record a\n // failed run in StructuredTaskState instead of the Stage-1 sidecar.\n 'failed',\n]);\nexport type TaskStage = z.infer<typeof TaskStageSchema>;\n\n/** A single recorded decision in the task evolution. */\nconst TaskDecisionSchema = z.object({\n ts: z.iso.datetime(),\n decision: z.string().min(1),\n rationale: z.string().min(1),\n});\nexport type TaskDecision = z.infer<typeof TaskDecisionSchema>;\n\n/** A blocker that stopped forward progress (optionally later resolved). */\nconst TaskBlockerSchema = z.object({\n ts: z.iso.datetime(),\n blocker: z.string().min(1),\n resolved: z.iso.datetime().optional(),\n});\nexport type TaskBlocker = z.infer<typeof TaskBlockerSchema>;\n\n/** Where the task currently is in its execution. */\nconst TaskPositionSchema = z.object({\n currentStep: z.string().min(1),\n nextStep: z.string().optional(),\n});\nexport type TaskPosition = z.infer<typeof TaskPositionSchema>;\n\n/**\n * Magentic-One Task Ledger — outer-loop \"facts and guesses\" about the task (#2278).\n *\n * Mirrors AutoGen's `magentic-one` Orchestrator pattern: the outer loop maintains\n * a ledger of verifiable facts, working assumptions (guesses), and open questions\n * the orchestrator still needs to resolve. The inner loop's `ProgressLedger`\n * decides whether to continue, replan (which triggers a TaskLedger refresh), or\n * escalate.\n *\n * Reference: microsoft.github.io/autogen — Magentic-One Task Ledger / Progress\n * Ledger pattern.\n */\nconst TaskLedgerSchema = z.object({\n /** Verifiable observations: what we have observed/measured/confirmed. */\n facts: z.array(z.string()),\n /** Working assumptions: useful guesses we proceed under, marked separately. */\n guesses: z.array(z.string()),\n /** Things we still need to figure out before the plan is sound. */\n openQuestions: z.array(z.string()),\n updatedAt: z.iso.datetime(),\n});\nexport type TaskLedger = z.infer<typeof TaskLedgerSchema>;\n\n/**\n * Magentic-One Progress Ledger — the inner-loop self-reflection at each step (#2278).\n *\n * After each step, the orchestrator (or whoever is driving) emits one\n * `ProgressLedgerEntry` summarizing whether the outer plan is still valid,\n * whether we are stuck, and what to do next. Append-only; the most recent entry's\n * `suggestedAction` is what `Orchestrator.reflect()` returns.\n */\nconst ReflectActionSchema = z.enum(['continue', 'revise_plan', 'escalate_to_human', 'abort']);\nexport type ReflectAction = z.infer<typeof ReflectActionSchema>;\n\nconst ProgressLedgerEntrySchema = z.object({\n ts: z.iso.datetime(),\n /** What just happened (the step we are reflecting on). */\n step: z.string().min(1),\n /** Is the outer Task Ledger plan still right after this step? */\n planStillValid: z.boolean(),\n /** Are we making progress, or have we stalled? */\n stuck: z.boolean(),\n /** What the orchestrator should do next based on this reflection. */\n suggestedAction: ReflectActionSchema,\n /** Why this action was chosen — required so future readers can audit the call. */\n rationale: z.string().min(1),\n});\nexport type ProgressLedgerEntry = z.infer<typeof ProgressLedgerEntrySchema>;\n\n/**\n * Cancellation marker for async-mode tools (#3043 / epic #2631 Stage 2).\n *\n * Append-only — once present, the cancellation timestamp can't be\n * cleared. `cancel_job` writes this; the task's run loop checks it at\n * safe-point boundaries to abort cleanly.\n */\nconst TaskCancellationSchema = z.object({\n requestedAt: z.iso.datetime(),\n /** Optional human-readable note carried back to the caller. */\n reason: z.string().max(1000).optional(),\n});\nexport type TaskCancellation = z.infer<typeof TaskCancellationSchema>;\n\n/**\n * Maximum serialized size of a `result` payload, in bytes\n * (#3043 / epic #2631 Stage 2). Caps result-retention DoS — a\n * misbehaving tool that wrote a 100 MiB result into the state log\n * would block reads of every other tool's state on the same data\n * dir while the reducer parses it. 1 MiB is generous for structured\n * payloads but bounds the worst case. `appendResult` truncates\n * over-cap writes to `{ truncated: true, originalBytes }` rather\n * than dropping them silently — so the caller can tell whether a\n * missing result was never written vs. dropped at write time.\n */\nexport const TASK_RESULT_MAX_BYTES = 1_048_576;\n\n/**\n * Structured state for a single long-running task.\n *\n * All arrays are append-only during the task's lifetime; a blocker can\n * be resolved by updating its `resolved` timestamp, but we do not\n * retroactively rewrite earlier entries.\n */\nexport const StructuredTaskStateSchema = z.object({\n taskId: z.string().min(1),\n /**\n * Marks state created by the shared async-job dispatcher (#5622).\n * Optional for backward compatibility; absence does not prove async dispatch.\n */\n dispatch: z.literal('async').optional(),\n stage: TaskStageSchema,\n decisions: z.array(TaskDecisionSchema),\n blockers: z.array(TaskBlockerSchema),\n position: TaskPositionSchema,\n /**\n * Magentic-One Task Ledger (#2278). Mutable single-object outer-loop state:\n * facts/guesses/openQuestions revised together when the plan is replanned.\n * Optional so the field can be added later without breaking existing logs.\n */\n taskLedger: TaskLedgerSchema.optional(),\n /**\n * Magentic-One Progress Ledger (#2278). Append-only inner-loop reflections.\n * Most recent entry's `suggestedAction` is what `reflect()` returns. Optional\n * for the same backward-compat reason as `taskLedger`.\n */\n progressLedger: z.array(ProgressLedgerEntrySchema).optional(),\n /**\n * Monotonic version counter (#3043 / epic #2631 Stage 2). Increments by\n * 1 on every write; polling clients use this to detect \"I missed a\n * transition\" and resync rather than silently observe a stale snapshot.\n *\n * Optional + defaulting-to-0 in the reducer for backward-compat — old\n * state logs (pre-Stage-2) don't carry it; the reducer treats their\n * baseline as v0 and starts counting from there.\n */\n version: z.number().int().nonnegative().optional(),\n /**\n * Tool result payload (#3043 / epic #2631 Stage 2). Set atomically\n * via the `result` log event when `stage === 'complete'`. Carries the\n * same shape the synchronous mode would have returned inline.\n *\n * Capped at `TASK_RESULT_MAX_BYTES` at write time; over-cap payloads\n * are replaced with `{ truncated: true, originalBytes }` so the\n * cap is observable rather than silent.\n *\n * Once Stage 2 (this) ships, Stage 3+ (#3044 / #3045) migrate the\n * orchestrate / run_workflow / consensus_vote async-mode writers\n * from the Stage-1 sidecar (`mcp/jobs/job-result-store.ts`) to this\n * field, then the sidecar files become legacy that the next cleanup\n * sweep can remove.\n */\n result: z.unknown().optional(),\n /**\n * Cancellation marker (#3043 / epic #2631 Stage 2). Set by `cancel_job`\n * — the running tool checks for this at safe-point boundaries (between\n * steps, between waves) and aborts via the AbortSignal plumbing from\n * #3035 / #3038. Append-only by construction (the reducer ignores a\n * second cancellation event).\n */\n cancellation: TaskCancellationSchema.optional(),\n /**\n * Creation timestamp (#3090 / epic #2631). Set by the reducer to the\n * `init` entry's `ts` and never mutated thereafter — `updatedAt` advances\n * with each write, but `createdAt` is fixed. Job-result readers need the\n * original creation time; `updatedAt` alone can't supply it once any\n * transition has been recorded. Optional for backward-compat with\n * pre-#3090 logs (the reducer backfills it from the init entry).\n */\n createdAt: z.iso.datetime().optional(),\n updatedAt: z.iso.datetime(),\n});\nexport type StructuredTaskState = z.infer<typeof StructuredTaskStateSchema>;\n\n/** Log entry types for the append-only journal. */\nexport const StructuredTaskLogEntrySchema = z.discriminatedUnion('event', [\n z.object({\n event: z.literal('init'),\n ts: z.iso.datetime(),\n state: StructuredTaskStateSchema,\n }),\n z.object({\n event: z.literal('decision'),\n ts: z.iso.datetime(),\n decision: TaskDecisionSchema,\n }),\n z.object({\n event: z.literal('blocker'),\n ts: z.iso.datetime(),\n blocker: TaskBlockerSchema,\n }),\n z.object({\n event: z.literal('blocker_resolved'),\n ts: z.iso.datetime(),\n /** Index of the blocker in the state's blockers[] array. */\n blockerIndex: z.number().int().nonnegative(),\n resolvedAt: z.iso.datetime(),\n }),\n z.object({\n event: z.literal('stage'),\n ts: z.iso.datetime(),\n stage: TaskStageSchema,\n }),\n z.object({\n event: z.literal('position'),\n ts: z.iso.datetime(),\n position: TaskPositionSchema,\n }),\n // Magentic-One Task Ledger replacement event — the outer loop revises the\n // entire ledger atomically when replanning. Always replaces, never partial.\n z.object({\n event: z.literal('task_ledger'),\n ts: z.iso.datetime(),\n ledger: TaskLedgerSchema,\n }),\n // Magentic-One Progress Ledger append event — one self-reflection per step.\n z.object({\n event: z.literal('progress_ledger'),\n ts: z.iso.datetime(),\n entry: ProgressLedgerEntrySchema,\n }),\n // #3043 / epic #2631 Stage 2 — tool result payload set when stage flips\n // to 'complete'. Written by appendResult; replayed into state.result.\n // The payload itself is `unknown` because each tool's result shape is\n // its own; readers cast after a status check.\n z.object({\n event: z.literal('result'),\n ts: z.iso.datetime(),\n result: z.unknown(),\n }),\n // #3043 / epic #2631 Stage 2 — cancellation marker. Append-only: the\n // reducer ignores a second cancellation event so a malicious or buggy\n // double-cancel can't rewrite the requestedAt timestamp.\n z.object({\n event: z.literal('cancellation'),\n ts: z.iso.datetime(),\n cancellation: TaskCancellationSchema,\n }),\n]);\nexport type StructuredTaskLogEntry = z.infer<typeof StructuredTaskLogEntrySchema>;\n","/**\n * Pipeline-bus → job heartbeat bridge (#6162).\n *\n * Pipeline bodies (`run_pipeline`, `run_dev_pipeline`, `run`, `orchestrate`)\n * already emit `stage.*` / `model.called` / `pipeline.*` events on the global\n * pipeline event bus as they progress. Rather than threading `progress()` into\n * every stage registry, `runAsJob` subscribes ONCE per job and treats any bus\n * event emitted from inside that job's async context as its heartbeat.\n *\n * Attribution is the load-bearing part. The bus is process-wide, so a naive\n * subscription would let a concurrent pipeline keep a wedged job alive — the\n * exact misreport the heartbeat exists to prevent. `runJobInBackground` runs\n * the body under `withAsyncTaskStateDispatch(jobId)`, an `AsyncLocalStorage`\n * scope that every await, timer and subprocess callback inside the body\n * inherits, and the bus invokes handlers synchronously inside `emit`; so the\n * store read in the handler names the job whose body emitted the event.\n *\n * Empty case: a body that emits nothing on either bus and never calls\n * `progress()` gets no heartbeat from this bridge — under a long guard it is\n * wedged by definition, which is the point.\n *\n * @module mcp/jobs/job-heartbeat-bridge\n */\n\nimport { currentAsyncDispatchJobId } from '../../context/structured-task-state.js';\nimport { stepBus } from '../../core/step-bus.js';\nimport { getPipelineEventBus } from '../../pipeline/event-bus.js';\nimport type { Unsubscribe } from '../../pipeline/event-types.js';\n\n/**\n * Subscribe `progress` to every pipeline-bus event AND every `stepBus` step\n * event emitted from inside `jobId`'s async context. The step bus carries\n * `withStep` activity — agent model calls, expert executions — which is how\n * `orchestrate`'s main phase (the Orchestrator agent's sequential model calls,\n * #6428) proves it is moving; `agents/heartbeat-monitor.ts` reads the same\n * signal for its session-health report. Returns the unsubscribe;\n * `runJobInBackground` calls it in its `finally` so a settled job stops\n * listening.\n */\nexport function bridgePipelineEventsToHeartbeat(jobId: string, progress: () => void): Unsubscribe {\n const onOwnEvent = (): void => {\n if (currentAsyncDispatchJobId() === jobId) progress();\n };\n const unsubscribePipeline = getPipelineEventBus().subscribe({}, onOwnEvent);\n stepBus.on('step', onOwnEvent);\n return () => {\n unsubscribePipeline();\n stepBus.off('step', onOwnEvent);\n };\n}\n","/**\n * Per-tool async-job concurrency cap (#3044 / epic #2631 Stage 3).\n *\n * Tracks in-flight async-mode dispatches in-process so a noisy caller\n * can't queue 1,000 long-running `run_workflow` invocations behind a\n * slow CLI and exhaust adapter slots. The cap is per-tool (each\n * registered tool gets its own slot count) and per-process — restarting\n * the MCP server resets the count, which is fine because the orphan\n * background promises die with it.\n *\n * Configuration order, lowest priority first:\n * 1. The per-tool default in `DEFAULT_JOB_CAPS` below.\n * 2. Environment override `NEXUS_JOB_MAX_CONCURRENT_<TOOL_UPPER>` —\n * tool name is uppercased + `_` for the env-var match. A value of\n * `0` disables async-mode for that tool entirely (`tryAcquire`\n * always returns busy).\n *\n * The Contrarian-vote flag from #3041 specifically asked for the cap\n * to land BEFORE async-mode expands past `orchestrate` (which has a\n * natural ceiling because it's depth-guarded). This module is the\n * primitive that satisfies that ask for `run_workflow` and later tools.\n *\n * @module mcp/jobs/job-concurrency\n */\n\nimport { createLogger } from '../../core/index.js';\n\nconst logger = createLogger({ component: 'job-concurrency' });\n\n/**\n * Default concurrent-job caps per tool. Numbers are starting points\n * informed by typical workload shape, NOT measured ceilings — re-tune\n * after observing actual job duration distributions in #2703 telemetry.\n *\n * `0` would disable async-mode for that tool; absence means \"no cap\"\n * (currently no tool falls into this category).\n */\nexport const DEFAULT_JOB_CAPS: Readonly<Record<string, number>> = {\n orchestrate: 3,\n run_workflow: 3,\n consensus_vote: 2,\n execute_expert: 4,\n // #3726: run_dev_pipeline is a heavy multi-agent pipeline (plan→vote→\n // decompose→implement→qa→security, each a live LLM call). Cap low — 2\n // concurrent real runs already saturate adapter slots on most hosts.\n run_dev_pipeline: 2,\n // #3730: run_pipeline is a multi-stage adaptive orchestrator with per-stage\n // experts (live LLM calls). Same shape as run_dev_pipeline — cap low at 2.\n run_pipeline: 2,\n // #3731: pr_review fans out to 5 live LLM voters in parallel. Same heavy\n // multi-llm-panel shape as consensus_vote — cap low at 2.\n pr_review: 2,\n // #3731: supply_chain_tradeoff_panel fans out to up to 7 live LLM voters in\n // parallel. Same heavy multi-llm-panel shape as consensus_vote — cap low at 2.\n supply_chain_tradeoff_panel: 2,\n // #3732: execute_spec runs a full spec DAG pipeline (parse→decompose→compile\n // →execute→validate→analyze, live multi-agent execution). Heavy — cap low at 2.\n execute_spec: 2,\n // #3732: run_graph_workflow runs up to ~100 expert nodes with checkpoints.\n // Heavy multi-node pipeline — cap low at 2.\n run_graph_workflow: 2,\n // #3732: run (execute:true) dispatches the heaviest engines (dev-pipeline/\n // pipeline) via the MetaDispatcher. Same heavy-pipeline shape — cap low at 2.\n run: 2,\n};\n\n/**\n * Default total cross-tool cap (defensive backstop, #3046 Stage 5).\n * Per-tool caps prevent a noisy single tool; the global cap prevents\n * 5 tools × 3 jobs each from saturating the host's adapter slots.\n *\n * Env override: `NEXUS_JOB_MAX_CONCURRENT_TOTAL`. Defaults to 10 —\n * comfortably above the sum of per-tool defaults (3+3+2+4=12 is also\n * fine because no realistic workload fills every tool simultaneously)\n * but stops runaway parallel fan-outs.\n */\nexport const DEFAULT_GLOBAL_JOB_CAP = 10;\n\n/** In-flight count per tool. Reset on process restart. */\nconst inFlight = new Map<string, number>();\n\n/** Returns the configured per-tool cap — env override beats default. */\nexport function getJobCap(toolName: string): number {\n const envKey = `NEXUS_JOB_MAX_CONCURRENT_${toolName.toUpperCase()}`;\n const envValue = process.env[envKey];\n if (envValue !== undefined && envValue !== '') {\n const parsed = Number(envValue);\n if (Number.isInteger(parsed) && parsed >= 0) {\n return parsed;\n }\n logger.warn('Invalid env override for job cap — ignoring', {\n tool: toolName,\n envKey,\n envValue,\n });\n }\n return DEFAULT_JOB_CAPS[toolName] ?? DEFAULT_GLOBAL_JOB_CAP;\n}\n\n/**\n * Returns the global cross-tool cap (#3046 Stage 5). Env override:\n * `NEXUS_JOB_MAX_CONCURRENT_TOTAL`. A value of `0` disables async-mode\n * across ALL tools simultaneously.\n */\nexport function getGlobalJobCap(): number {\n const envValue = process.env['NEXUS_JOB_MAX_CONCURRENT_TOTAL'];\n if (envValue !== undefined && envValue !== '') {\n const parsed = Number(envValue);\n if (Number.isInteger(parsed) && parsed >= 0) {\n return parsed;\n }\n logger.warn('Invalid env override for global job cap — ignoring', {\n envKey: 'NEXUS_JOB_MAX_CONCURRENT_TOTAL',\n envValue,\n });\n }\n return DEFAULT_GLOBAL_JOB_CAP;\n}\n\n/** Sum of in-flight counts across all tools (Stage 5 observability). */\nexport function getTotalInFlight(): number {\n let total = 0;\n for (const count of inFlight.values()) total += count;\n return total;\n}\n\n/** Current in-flight count for a tool (testing + observability helper). */\nexport function getInFlight(toolName: string): number {\n return inFlight.get(toolName) ?? 0;\n}\n\n/**\n * Attempt to acquire one slot. Returns `true` on success (caller MUST\n * `release()` exactly once when the job finishes / fails). Returns\n * `false` when EITHER cap is full — per-tool cap OR cross-tool global\n * cap (#3046 Stage 5). Caller responds synchronously with the busy\n * envelope (`{ status: 'busy', retryAfterMs }`).\n *\n * Atomicity note: Node.js is single-threaded between awaits, so this\n * read-then-write pattern is safe as long as no `await` interleaves\n * — and it doesn't here.\n */\nexport function tryAcquire(toolName: string): boolean {\n const cap = getJobCap(toolName);\n // Cap of 0 disables async-mode for the tool.\n if (cap === 0) return false;\n const current = inFlight.get(toolName) ?? 0;\n if (current >= cap) return false;\n // #3046 Stage 5: global cap check. Prevents 5 tools × 3 jobs each\n // saturating adapter slots even when each per-tool cap is satisfied.\n const globalCap = getGlobalJobCap();\n if (globalCap === 0) return false;\n if (getTotalInFlight() >= globalCap) return false;\n inFlight.set(toolName, current + 1);\n return true;\n}\n\n/**\n * Release one slot. Idempotent only in the trivial sense (calling twice\n * is a bug — the counter would underflow). Callers should pair every\n * `tryAcquire` returning `true` with exactly one `release` in a\n * `finally` block to be safe on both success and rejection paths.\n */\nexport function release(toolName: string): void {\n const current = inFlight.get(toolName) ?? 0;\n if (current === 0) {\n logger.warn('release() called with no in-flight count — caller bug', { tool: toolName });\n return;\n }\n inFlight.set(toolName, current - 1);\n}\n\n/**\n * Suggested retry interval for a busy response. Linear in current\n * load — at full cap, suggest 30s; halved as load shrinks. Pure\n * convenience for clients implementing exponential backoff.\n */\nexport function suggestRetryAfterMs(toolName: string): number {\n const cap = getJobCap(toolName);\n if (cap === 0) return 0; // never retry — async-mode is disabled\n const current = inFlight.get(toolName) ?? 0;\n // 30s base, scaled by fullness (clamped to [5s, 60s]).\n const base = 30_000 * (current / Math.max(1, cap));\n return Math.min(60_000, Math.max(5_000, base));\n}\n\n/** Reset all counters. Test-only — do not call from production code. */\nexport function _resetForTests(): void {\n inFlight.clear();\n}\n","/**\n * Shared async-job dispatcher — `runAsJob` (#3729 / epic #2631).\n *\n * Three tools (orchestrate, run_workflow, consensus_vote) implemented the\n * async-mode dispatcher VERBATIM: resolve idempotency → tryAcquire (busy\n * envelope on cap) → writeJobPending → registerIdempotentJob → fire a\n * detached background `run` that writes complete/failed + releases the slot\n * in a `finally` → return a synchronous `{ status: 'pending', jobId }`\n * envelope. This module extracts that sequence once so new long-running\n * tools (run_dev_pipeline, run_pipeline, …) opt into async with a few lines.\n *\n * The dispatcher sequence is FIXED here; the only per-tool variation is the\n * envelope shape (some tools use `ToolResult` via toolSuccess/\n * toolStructuredError, run_workflow uses its structurally-identical\n * `ToolResponse`). Callers that need a non-default envelope supply\n * `toEnvelope`; the default builders reproduce the orchestrate/consensus_vote\n * `ToolResult` envelopes byte-for-byte so faithful migration is a drop-in.\n *\n * @module mcp/jobs/run-as-job\n */\n\nimport { getTimeProvider, type ILogger } from '../../core/index.js';\nimport { toolSuccess, toolStructuredError, type ToolResult } from '../tools/tool-result.js';\nimport {\n pruneJobRecordsIfDue,\n writeJobComplete,\n writeJobFailed,\n writeJobPending,\n heartbeatJob,\n readLastProgressMs,\n} from './job-result-store.js';\nimport { extractFailureDetail } from './job-failure-detail.js';\nexport { extractFailureDetail } from './job-failure-detail.js';\nimport { registerJobAbort, unregisterJobAbort } from './job-abort-registry.js';\nimport { bridgePipelineEventsToHeartbeat } from './job-heartbeat-bridge.js';\nimport { registerIdempotentJob, shortCircuitOrFreshJobId } from './job-idempotency.js';\nimport { release, suggestRetryAfterMs, tryAcquire } from './job-concurrency.js';\nimport { MCP_TIMEOUTS, resolveClassGuardMs } from '../../config/timeouts.js';\nimport { withAsyncTaskStateDispatch } from '../../context/structured-task-state.js';\n\n/**\n * Async-job-body runaway-guard (#3734). A backgrounded job body has NO MCP\n * request timeout (that is the point of async mode), so without a ceiling a\n * wedged `run` would hold its concurrency slot and pending record forever.\n * The `async-job-body` operation class (3600s by default) bounds it.\n *\n * Because the body has no MCP request, it is the one class NOT ceilinged by\n * `MCP_TIMEOUTS.maxMs` (#5995, panel option 1). `NEXUS_TIMEOUT_MULTIPLIER` and\n * `NEXUS_TIMEOUT_CLASS_ASYNC_JOB_BODY_MS` raise it up to the class override\n * ceiling (7200000ms); a value past that is clamped and reported at startup by\n * `findIneffectiveVars`. The default is unchanged — the extra hour is opt-in,\n * and it costs something: a job holds its concurrency slot for as long as it\n * runs. Past the standard ceiling that cost is bounded by liveness (#6162): the\n * body must heartbeat via `progress()` or be failed as wedged at\n * {@link ASYNC_JOB_BODY_WEDGED_MISSED_HEARTBEATS} missed intervals. The guard a\n * job actually runs under is logged once at job start so real job durations\n * can be judged against it.\n *\n * On expiry the job's `AbortSignal` is aborted FIRST, with a `DOMException`\n * named `TimeoutError` (#6725), then the job is recorded as failed with\n * `runaway guard exceeded` and the slot is released by the existing `finally`.\n * The abort is what makes \"failed\" true of the work and not just of the record:\n * before it, the body kept making model calls after its slot went to another\n * job, and a later `cancel_job` could no longer reach it. The `TimeoutError`\n * reason is deliberate — `createCallerAbortCliError` classifies it as a real\n * `TIMEOUT` that counts on the CLI breaker (#6691/#6709), where a plain abort\n * would read as a caller cancel and be skipped. A body that ignores the signal\n * still runs on; the abort is the most the dispatcher can do in-process. This\n * is a runaway-guard, not an SLA — 1h is generous.\n */\nexport const ASYNC_JOB_BODY_GUARD_CLASS = 'async-job-body' as const;\n\n/**\n * Fraction of the async-job-body guard at which a near-timeout WARN is emitted\n * before the guard fires. Lower than the generic 0.8 so operators see a wedged\n * long-running job well before the (very high) ceiling trips.\n */\nexport const ASYNC_JOB_BODY_NEAR_TIMEOUT_THRESHOLD = 0.5;\n\n/** Message of the guard's rejection when the guard window elapses. */\nconst ASYNC_JOB_BODY_RUNAWAY_MESSAGE = 'runaway guard exceeded';\n\n/**\n * The guard's own rejection — runaway expiry or wedged verdict — as opposed to\n * a rejection from the body (#6725). Identified by class, not by message: a\n * body is free to throw an Error whose text happens to match, and that must not\n * be read as a guard expiry. Module-private: only the guard constructs it.\n */\nclass AsyncJobGuardExpiredError extends Error {\n override readonly name = 'AsyncJobGuardExpiredError';\n}\n\n/**\n * Liveness for a body allowed past the standard MCP ceiling (#6162 item 1).\n *\n * #6159 let an operator raise the guard from `MCP_TIMEOUTS.maxMs` (3.6M) to the\n * 7.2M class ceiling, and the only signals over the extra hour were the start\n * log and the 0.5 WARN — both say time passed, neither says the body is alive.\n * So a guard ABOVE the standard ceiling requires the body to prove progress:\n * `runAsJob` hands it a `progress()` heartbeat, and a watchdog fails the job as\n * wedged exactly one silence budget after its last heartbeat — releasing its\n * concurrency slot and recording `failed`, well before the guard would. The\n * watchdog is lazy: a timer armed for one budget that, on firing, measures the\n * silence from the record and re-arms for the exact remainder, so the verdict\n * lands at `lastHeartbeat + budget` wherever the heartbeat fell (#6428: a\n * poller ticking per interval held the slot for up to four intervals when the\n * heartbeat landed just after a tick). A guard at or under the standard\n * ceiling is not watched: those bodies never opted into anything and keep\n * their pre-#6162 behaviour.\n *\n * Interval = guard / {@link ASYNC_JOB_BODY_HEARTBEAT_INTERVAL_DIVISOR}; wedged\n * after {@link ASYNC_JOB_BODY_WEDGED_MISSED_HEARTBEATS} intervals of silence,\n * i.e. 3/8 of the guard — under the 0.5 near-timeout WARN fraction, so a silent\n * body is released before the WARN that used to be its only signal. On the\n * smallest watched guard (just over 3.6M) that is ~22.5 min of silence; on the\n * 7.2M ceiling, 45 min. Both exceed the `multi-llm-panel` class guard (15 min),\n * the longest single unit a body composes, so a body that heartbeats between\n * units is never wedged by one slow-but-alive unit; only a unit hung past its\n * own guard is. Module-private constants, not env vars: nothing reads a knob,\n * and the tests pin the numbers.\n *\n * A body that never calls `progress()` under a watched guard is wedged BY\n * DEFINITION — that is the point: opting into a longer guard is not opting into\n * a longer hang. The empty case (no heartbeat ever recorded) is measured from\n * job start, so such a body fails at exactly N intervals after dispatch.\n *\n * Not the same instrument as `agents/heartbeat-monitor.ts`: that monitor is\n * in-memory and reporting-only — it classifies an agent SESSION as healthy /\n * stalled / unmeasured for logs and the dashboard, and acts on nothing. This\n * watchdog is per JOB, durable through the job record, and its verdict frees a\n * concurrency slot and settles a record a poller reads. Both consume the same\n * `stepBus` progress signal; they answer different questions.\n */\nconst ASYNC_JOB_BODY_HEARTBEAT_INTERVAL_DIVISOR = 8;\n\n/** Missed heartbeat intervals after which a watched body is failed as wedged. */\nconst ASYNC_JOB_BODY_WEDGED_MISSED_HEARTBEATS = 3;\n\n/** Heartbeat handle for one job body: the callback plus its watch's teardown. */\ninterface LivenessWatch {\n /** The body's heartbeat — stamps the record and re-arms the watchdog. */\n readonly progress: () => void;\n /** Disarms the watchdog (no-op when the guard was not watched). */\n readonly clear: () => void;\n}\n\n/**\n * Build the heartbeat for one body and, when `guardMs` exceeds the standard\n * MCP ceiling, the watchdog that enforces it. The stamp is written under every\n * guard — a poller wants slow-vs-stuck regardless — only the watchdog is\n * gated. `onWedged` receives the failure the job is recorded with.\n *\n * Every heartbeat — the callback, `heartbeatJob(jobId)`, a bridged bus event —\n * goes through `heartbeatJob`, which stamps the record; nothing else is kept in\n * memory. When the timer fires it measures the silence from the record (empty\n * case: from job start): under budget, it re-arms for exactly the remainder;\n * otherwise the verdict quotes what `get_job_result` shows. So a body that\n * keeps heartbeating costs one file read per silence budget, and a body that\n * stops is failed at `lastHeartbeat + budget`, not at the next poll tick.\n */\nfunction makeLivenessWatch(\n jobId: string,\n guardMs: number,\n onWedged: (err: AsyncJobGuardExpiredError) => void\n): LivenessWatch {\n const startedAtMs = getTimeProvider().now();\n const progress = (): void => {\n heartbeatJob(jobId);\n };\n if (guardMs <= MCP_TIMEOUTS.maxMs) return { progress, clear: () => {} };\n\n const intervalMs = Math.floor(guardMs / ASYNC_JOB_BODY_HEARTBEAT_INTERVAL_DIVISOR);\n const silenceBudgetMs = intervalMs * ASYNC_JOB_BODY_WEDGED_MISSED_HEARTBEATS;\n let timer: ReturnType<typeof setTimeout> | undefined;\n const arm = (ms: number): void => {\n timer = setTimeout(onFire, ms);\n // Like the guard timers: never keep the event loop alive for the watchdog.\n timer.unref();\n };\n const onFire = (): void => {\n const silentMs = getTimeProvider().now() - (readLastProgressMs(jobId) ?? startedAtMs);\n if (silentMs < silenceBudgetMs) {\n arm(silenceBudgetMs - silentMs);\n return;\n }\n onWedged(new AsyncJobGuardExpiredError(`wedged (no progress for ${String(silentMs)} ms)`));\n };\n arm(silenceBudgetMs);\n return {\n progress,\n clear: () => {\n clearTimeout(timer);\n },\n };\n}\n\ninterface GuardHandles {\n /**\n * Rejects when the guard window elapses, or — under a guard past the\n * standard MCP ceiling — when the body goes\n * {@link ASYNC_JOB_BODY_WEDGED_MISSED_HEARTBEATS} intervals without a\n * heartbeat (#6162). Never settles on clear.\n */\n readonly expired: Promise<never>;\n /** The body's heartbeat (#6162). */\n readonly progress: () => void;\n /** Cancels the guard, near-timeout and liveness timers. */\n readonly clear: () => void;\n}\n\n/**\n * Builds a guard that rejects with the runaway sentinel after `guardMs`, emits\n * a one-shot near-timeout WARN at {@link ASYNC_JOB_BODY_NEAR_TIMEOUT_THRESHOLD},\n * and — past the standard MCP ceiling — rejects earlier with the wedged\n * failure when the body stops heartbeating ({@link makeLivenessWatch}).\n */\nfunction makeAsyncBodyGuard(\n jobId: string,\n toolName: string,\n guardMs: number,\n logger: ILogger | undefined\n): GuardHandles {\n // The executor runs synchronously, so `reject` is the promise's own by the\n // time any timer below can fire.\n let reject: (err: Error) => void = () => {};\n const expired = new Promise<never>((_resolve, rej) => {\n reject = rej;\n });\n const warnTimer = setTimeout(\n () => {\n logger?.warn(`Async ${toolName} job approaching runaway guard`, {\n jobId,\n guardMs,\n thresholdFraction: ASYNC_JOB_BODY_NEAR_TIMEOUT_THRESHOLD,\n });\n },\n Math.floor(guardMs * ASYNC_JOB_BODY_NEAR_TIMEOUT_THRESHOLD)\n );\n const guardTimer = setTimeout(() => {\n reject(new AsyncJobGuardExpiredError(ASYNC_JOB_BODY_RUNAWAY_MESSAGE));\n }, guardMs);\n // Don't keep the event loop alive solely for these timers.\n guardTimer.unref();\n warnTimer.unref();\n const liveness = makeLivenessWatch(jobId, guardMs, (err) => {\n reject(err);\n });\n return {\n expired,\n progress: liveness.progress,\n clear: () => {\n clearTimeout(guardTimer);\n clearTimeout(warnTimer);\n liveness.clear();\n },\n };\n}\n\n/**\n * Per-tool envelope builders. Every async dispatcher returns the same five\n * logical outcomes; only their wire shape differs. Supplying this lets a tool\n * that uses a different success/error factory (e.g. run_workflow's\n * `successResponse`/`errorResponse`) reuse the dispatcher unchanged.\n *\n * @template E - The tool's MCP envelope type (defaults to {@link ToolResult}).\n */\nexport interface JobEnvelopeBuilders<E> {\n /** `{ status: 'pending', jobId, pollTool, note }` — returned synchronously after dispatch. */\n readonly pending: (jobId: string) => E;\n /** `{ status: 'busy', retryAfterMs, note }` — concurrency cap reached. */\n readonly busy: (retryAfterMs: number, toolName: string) => E;\n /** `{ status: 'replay', jobId, pollTool, note }` — idempotency key matched a prior dispatch. */\n readonly replay: (jobId: string) => E;\n /** Error envelope — idempotency key reused with different inputs. */\n readonly collision: (existingJobId: string) => E;\n}\n\n/** Default pending envelope (orchestrate/consensus_vote shape). */\nexport function defaultPendingEnvelope(jobId: string): ToolResult {\n return toolSuccess(\n JSON.stringify({\n status: 'pending',\n jobId,\n pollTool: 'get_job_result',\n note: 'Poll via get_job_result({ jobId }) until status !== \"pending\".',\n })\n );\n}\n\n/** Default busy envelope (orchestrate/consensus_vote shape). */\nexport function defaultBusyEnvelope(retryAfterMs: number, toolName: string): ToolResult {\n return toolSuccess(\n JSON.stringify({\n status: 'busy',\n retryAfterMs,\n note: `Async-mode concurrency cap reached for ${toolName}. Retry later or use dispatch: \"sync\".`,\n })\n );\n}\n\n/** Default replay envelope (orchestrate/consensus_vote shape). */\nexport function defaultReplayEnvelope(jobId: string): ToolResult {\n return toolSuccess(\n JSON.stringify({\n status: 'replay',\n jobId,\n pollTool: 'get_job_result',\n note: 'Idempotency key matched a prior dispatch — poll get_job_result for current status.',\n })\n );\n}\n\n/** Default collision envelope (orchestrate/consensus_vote shape). */\nexport function defaultCollisionEnvelope(existingJobId: string): ToolResult {\n return toolStructuredError({\n errorCategory: 'validation',\n message: `Idempotency key already used with different inputs. Existing jobId: ${existingJobId}. Use a fresh key or omit it.`,\n });\n}\n\n/** The full default ({@link ToolResult}) envelope set. */\nexport const DEFAULT_JOB_ENVELOPES: JobEnvelopeBuilders<ToolResult> = {\n pending: defaultPendingEnvelope,\n busy: defaultBusyEnvelope,\n replay: defaultReplayEnvelope,\n collision: defaultCollisionEnvelope,\n};\n\n/**\n * Parameters for {@link runAsJob}.\n *\n * @template I - The tool's validated input type (hashed for idempotency,\n * passed to `run`).\n * @template R - The structured result `run` resolves to; recorded verbatim\n * via `writeJobComplete` and returned by a later `get_job_result(jobId)`.\n * @template E - The tool's envelope type (defaults to {@link ToolResult}).\n */\nexport interface RunAsJobParams<I, R, E = ToolResult> {\n /** MCP tool name — the idempotency / concurrency / job-store key. */\n readonly toolName: string;\n /** Validated tool input. Hashed for idempotency + passed to `run`. */\n readonly input: I;\n /** Caller-supplied idempotency key (optional). */\n readonly idempotencyKey?: string | undefined;\n /** Mints a fresh jobId when no idempotency short-circuit applies. */\n readonly freshJobId: () => string;\n /**\n * The detached background work. Receives the resolved `jobId` (so the\n * runner can thread it into a task-state log), the `input`, and an\n * `AbortSignal` (#4086) that fires when `cancel_job` cancels this job, or —\n * with a `TimeoutError` reason — when the runaway guard or wedged watchdog\n * expires (#6725). Thread it into awaited operations to make cancellation and\n * the guard actually stop the work. The fourth argument is the body's heartbeat (#6162): call\n * `progress()` after each unit of work (a seat, a stage, a fetch) to stamp\n * `lastProgressAt` on the pending record. Under a guard past the standard\n * MCP ceiling (`MCP_TIMEOUTS.maxMs`) the heartbeat is REQUIRED — a body that\n * goes {@link ASYNC_JOB_BODY_WEDGED_MISSED_HEARTBEATS} intervals without one\n * is failed as wedged and its slot released; a body that never calls it is\n * wedged by definition. Each call is a synchronous sidecar write, so call it\n * per unit of work, not per token. Existing 2- and 3-arg callbacks remain\n * valid (trailing params are ignored). Its resolved value is recorded as the\n * job's `complete` result; a rejection is recorded as `failed`.\n */\n readonly run: (jobId: string, input: I, signal: AbortSignal, progress: () => void) => Promise<R>;\n /** Per-tool envelope builders. Defaults to the {@link ToolResult} set. */\n readonly toEnvelope?: JobEnvelopeBuilders<E>;\n /** Optional logger for the background failure path. */\n readonly logger?: ILogger | undefined;\n /**\n * Opt out of the fail-closed result check (#4363), stating why.\n *\n * By default a `run` callback that RESOLVES a failure-shaped payload records\n * the job `failed` rather than `complete`. A handful of tools legitimately\n * resolve such a payload as their real answer. Those set\n * this field; the reason is logged whenever it actually suppresses a\n * detection, so an opted-out caller is a visible policy decision rather than\n * a silent kwarg.\n */\n readonly allowFailureShapedResult?: string | undefined;\n /**\n * Version stamped on every record this dispatch writes (#5008). Defaults to\n * the running server's `VERSION` — the build that runs the job, which is\n * what a later `get_job_result` from a different build needs to see. A\n * test injects a value that differs from `VERSION` to prove the stamp is\n * taken from this seam and not from the reader.\n */\n readonly producerVersion?: string | undefined;\n}\n\n/** A root envelope key whose value marks the payload as a failure (#4363). */\ninterface FailureShape {\n /** Which key tripped — recorded so the job record is debuggable. */\n readonly key: string;\n /** The payload's own message, when it carries one. */\n readonly detail: string | undefined;\n}\n\n/** Root envelope keys and the value that means \"this failed\". */\nconst FAILURE_KEYS: ReadonlyArray<{ key: string; failsWhen: boolean }> = [\n // toolStructuredError\n { key: 'isError', failsWhen: true },\n // handleConsensusVote and the other Result-shaped handlers\n { key: 'ok', failsWhen: false },\n // GraphPipelineResult / AdaptiveOrchestratorResult\n { key: 'success', failsWhen: false },\n];\n\n/** Root keys carrying a human-readable reason, in order of preference. */\nconst DETAIL_KEYS: readonly string[] = ['error', 'message'];\n\n/**\n * Render a failure shape for the job record. Names the key that tripped so the\n * record is debuggable, and carries the payload's own message when it has one —\n * a bare `failed` tells whoever polls the job nothing.\n */\nfunction describeFailureShape(failure: FailureShape): string {\n const suffix = failure.detail === undefined ? '' : `: ${failure.detail}`;\n return `Job result reported failure via '${failure.key}'${suffix}`;\n}\n\n/**\n * Detect a failure-shaped job payload, or null when the result is a success\n * (#4363).\n *\n * Inspects the payload's ROOT keys only. A deep scan would turn fail-open into\n * fail-wrong: a vote whose *decision* is `reject` and a pipeline summary listing\n * a stage it recovered from both carry a nested falsy `success`, and both are\n * successful jobs. Only the top-level envelope says whether the job itself\n * failed.\n *\n * Exported for tests.\n * @internal\n */\nexport function detectFailureShapedResult(result: unknown): FailureShape | null {\n if (typeof result !== 'object' || result === null) return null;\n const record = result as Record<string, unknown>;\n\n for (const { key, failsWhen } of FAILURE_KEYS) {\n if (record[key] === failsWhen) {\n const detailKey = DETAIL_KEYS.find((k) => typeof record[k] === 'string');\n return { key, detail: detailKey === undefined ? undefined : (record[detailKey] as string) };\n }\n }\n return null;\n}\n\n/**\n * Dispatch `run` as a detached background job and return a synchronous\n * envelope. Performs the EXACT sequence the three hand-rolled dispatchers\n * shared:\n *\n * 1. Resolve idempotency BEFORE acquiring a slot — a replay/collision must\n * not burn capacity a live caller could use.\n * 2. `tryAcquire(toolName)` — over-cap returns the `busy` envelope.\n * 3. `pruneJobRecordsIfDue` (#6224), then `writeJobPending` +\n * `registerIdempotentJob` (when a key was supplied).\n * 4. Fire-and-forget `run(jobId, input)`: on resolve `writeJobComplete`,\n * on reject `writeJobFailed`, `release` in a `finally`.\n * 5. Return the `pending` envelope (`{ status: 'pending', jobId, … }`).\n *\n * The background promise is intentionally not awaited — async mode exists\n * precisely because awaiting it would defeat the contract. Its rejection is\n * caught + recorded; nothing escapes unhandled.\n *\n * @returns The synchronous envelope: `pending` on dispatch, `busy` on cap,\n * `replay`/`collision` on an idempotency match.\n */\nexport function runAsJob<I, R, E = ToolResult>(params: RunAsJobParams<I, R, E>): E {\n const env = params.toEnvelope ?? (DEFAULT_JOB_ENVELOPES as unknown as JobEnvelopeBuilders<E>);\n\n // Step 1: idempotency resolves BEFORE the slot acquire.\n const idempotency = shortCircuitOrFreshJobId<E>({\n tool: params.toolName,\n idempotencyKey: params.idempotencyKey,\n inputs: params.input,\n freshJobId: params.freshJobId,\n replayEnvelope: env.replay,\n collisionEnvelope: env.collision,\n });\n if (idempotency.kind === 'shortCircuit') return idempotency.value;\n\n // Step 2: per-tool concurrency cap. Over-cap returns busy synchronously.\n if (!tryAcquire(params.toolName)) {\n return env.busy(suggestRetryAfterMs(params.toolName), params.toolName);\n }\n\n const jobId = idempotency.jobId;\n // Step 3: retention sweep, then pending record + idempotency index entry.\n // #6224: the store had no reaper (#4976 gap 2), so every dispatch left a\n // record forever. Bounded to one sweep per process per hour inside the\n // store; a failed sweep is logged there and never blocks the dispatch.\n pruneJobRecordsIfDue(getTimeProvider().now());\n // #4972: record whether this tool can even receive a cancel. `run.length`\n // is the callback's declared arity, so >= 3 means it takes the `signal`\n // parameter. Structural, not behavioural — see `signalAccepted`'s doc.\n writeJobPending(jobId, params.toolName, params.run.length >= 3, params.producerVersion);\n if (params.idempotencyKey !== undefined && params.idempotencyKey !== '') {\n registerIdempotentJob({\n tool: params.toolName,\n idempotencyKey: params.idempotencyKey,\n inputs: params.input,\n jobId,\n });\n }\n\n // Step 4: detached background run with terminal recording + slot release.\n void runJobInBackground(jobId, params);\n\n // Step 5: synchronous pending envelope.\n return env.pending(jobId);\n}\n\n/**\n * Fire-and-forget background runner. Exported (awaitable) so integration\n * tests can drive the dispatch deterministically instead of racing the\n * detached promise.\n * @internal\n */\nfunction settleJobResult<I, R, E>(\n jobId: string,\n params: RunAsJobParams<I, R, E>,\n result: unknown\n): void {\n const failure = detectFailureShapedResult(result);\n if (failure !== null && params.allowFailureShapedResult === undefined) {\n writeJobFailed(\n jobId,\n params.toolName,\n describeFailureShape(failure),\n params.producerVersion,\n extractFailureDetail(result)\n );\n return;\n }\n if (failure !== null) {\n params.logger?.warn(\n `Recorded a failure-shaped ${params.toolName} result as complete (opted out)`,\n { jobId, key: failure.key, reason: params.allowFailureShapedResult }\n );\n }\n writeJobComplete(jobId, params.toolName, result, params.producerVersion);\n}\n\n/**\n * Detached executor for `runAsJob`. Exported for tests so a test can drive\n * the background run deterministically without racing the dispatch envelope.\n *\n * @internal\n */\nexport async function runJobInBackground<I, R, E>(\n jobId: string,\n params: RunAsJobParams<I, R, E>\n): Promise<void> {\n const guardMs = resolveClassGuardMs(ASYNC_JOB_BODY_GUARD_CLASS);\n // Once per job, at info: the guard is operator-tunable (#5995), so the value\n // a job actually ran under is the record, not the config that produced it.\n params.logger?.info(`Async ${params.toolName} job started under runaway guard`, {\n jobId,\n guardMs,\n guardClass: ASYNC_JOB_BODY_GUARD_CLASS,\n });\n const guard = makeAsyncBodyGuard(jobId, params.toolName, guardMs, params.logger);\n // #4086: register an AbortController so cancel_job can stop this job's work. Its\n // signal is threaded into params.run; abort → run rejects → writeJobFailed, which\n // no-ops against the already-written `cancelled` record (#4022), preserving it.\n const controller = registerJobAbort(jobId);\n // #6162: pipeline bodies heartbeat through the stage events they already\n // emit; attributed to this job by the async context the body runs under.\n const unbridge = bridgePipelineEventsToHeartbeat(jobId, guard.progress);\n try {\n // Race the body against the runaway-guard. On guard expiry the guard\n // rejects with AsyncJobGuardExpiredError → the body is aborted and the job\n // recorded as failed below. On body settle the guard is cleared so it can\n // never fire afterward.\n const body = withAsyncTaskStateDispatch(jobId, () =>\n params.run(jobId, params.input, controller.signal, guard.progress)\n );\n const result = await Promise.race([body, guard.expired]);\n // #4363: `writeJobComplete` used to fire on ANY resolved value, so a\n // callback resolving a failure-shaped payload recorded `complete` and a\n // caller polling `get_job_result` read it as a success. Fail closed by\n // default — an opt-in predicate was rejected because \"caller forgot to\n // normalize\" would just become \"caller forgot to pass the predicate\".\n settleJobResult(jobId, params, result);\n } catch (err: unknown) {\n // #6725: the guard won the race, so the body is still running. Stop it\n // BEFORE recording failed and releasing the slot, so the record never\n // describes a job as over while its work continues. A body rejection is\n // NOT aborted: the body has already settled, and there is nothing to stop.\n if (err instanceof AsyncJobGuardExpiredError) {\n controller.abort(new DOMException(err.message, 'TimeoutError'));\n }\n const errObj = err instanceof Error ? err : new Error(String(err));\n params.logger?.error(`Async ${params.toolName} dispatch failed`, errObj, { jobId });\n writeJobFailed(\n jobId,\n params.toolName,\n errObj.message,\n params.producerVersion,\n extractFailureDetail(err)\n );\n } finally {\n unbridge();\n guard.clear();\n unregisterJobAbort(jobId);\n release(params.toolName);\n }\n}\n"],"mappings":"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","names":["randomUUID","z","logger","logger","logger","count","logger","z","count","z","logger","response","logger","logger","resolve","logger","logger","logger","z","z","path","logger","z","z","z","z","z","logger","err","logger","count","logger","logger","logger","count","logger","z","logger","z","z","logger","mkdirSync","dirname","readFileSync","statSync","path","delay","z","existsSync","unlinkSync","writeFileSync","mkdirSync","dirname","z","z","randomUUID","existsSync","readFileSync","z","logger","z","randomUUID","path","existsSync","readFileSync","err","existsSync","readFileSync","join","join","path","logger","readFileSync","err","existsSync","z","z","logger","z","mkdirSync","dirname","path","writeFileSync","existsSync","existsSync","err","logger","path","unlinkSync","logger","appendFileSync","readFileSync","writeFileSync","existsSync","logger","existsSync","readFileSync","writeFileSync","appendFileSync","logger","path","mkdirSync","dirname","randomUUID","defaultLogger","logger","defaultLogger","logger","randomUUID","logger","logger","fs","z","logger","FILE_MODE","DIR_MODE","logger","logger","logger","count","logger","logger","err","logger","randomUUID","z"]}