nexus-agents 2.150.4 → 2.151.1

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.
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/mcp/tools/consensus-vote.ts","../src/cli/voter-model-overrides.ts","../src/cli/vote-types.ts","../src/cli-adapters/codex-limits.ts","../src/cli/voter-prompts.ts","../src/cli/voter-response.ts","../src/cli/voter-execution.ts","../src/cli/voter-agents-deadline.ts","../src/cli/voter-agents.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/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/correlation-helpers.ts","../src/consensus/correlation-tracker.ts","../src/consensus/correlation-persistence.ts","../src/mcp/tools/consensus-vote-types.ts","../src/mcp/tools/consensus-vote-error-policy.ts","../src/audit/vote-record-store.ts","../src/audit/vote-record.ts","../src/orchestration/outcomes/outcome-store-persistence.ts","../src/mcp/tools/consensus-vote-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-result-store.ts","../src/mcp/jobs/job-abort-registry.ts","../src/mcp/jobs/job-idempotency.ts","../src/mcp/jobs/job-concurrency.ts","../src/mcp/jobs/run-as-job.ts"],"sourcesContent":["/* eslint-disable max-lines */ // Consensus voting — cohesive single module (governance: 400-600 OK)\n/**\n * nexus-agents/mcp - Consensus Vote Tool\n * @module mcp/tools/consensus-vote\n */\n\nimport { z } from 'zod';\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 toSdkCallbackWithBudgetCheck,\n getToolTimeout,\n} from '../middleware/tool-wrapper.js';\nimport { createSecureHandler, type HandlerContext } from '../middleware/secure-handler.js';\nimport {\n toolStructuredError,\n toolSuccess,\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/types-core.js';\nimport type { VoterRole, AgentVoteResult } from '../../cli/vote-types.js';\nimport { collectRealVotes } from '../../cli/voter-agents.js';\nimport { createConsensusEngine } from '../../consensus/engine.js';\nimport type {\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 MAX_PROPOSAL_LENGTH,\n VotingStrategySchema,\n VoteDecisionStatusSchema,\n VoteThresholdSchema,\n ConsensusVoteInputSchema,\n buildResponse,\n getDefaultErrorPolicy,\n isHigherOrderStrategy,\n shouldEscalateLowPosterior,\n} from './consensus-vote-types.js';\nimport { applyErrorPolicy } from './consensus-vote-error-policy.js';\nimport {\n recordVoteSuccess,\n recordVoteError,\n recordAuthenticVote,\n} from './consensus-vote-recording.js';\nimport type { VoteRecordPersistOutcome } from './consensus-vote-recording.js';\nimport { recordDecisionCost } from './decision-cost-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 { warnIfSimulatedOutsideTests } 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 { runAsJob } from '../jobs/run-as-job.js';\nimport { randomUUID } from 'node:crypto';\nimport type {\n VotingStrategy,\n ConsensusVoteInput,\n ConsensusVoteResponse,\n ExtendedVotingResult,\n} from './consensus-vote-types.js';\n\nexport type {\n VotingStrategy,\n ConsensusVoteInput,\n ConsensusVoteResponse,\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 ---\nfunction 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\nfunction 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\nfunction 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// --- 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): HigherOrderVotingResult | undefined {\n if (!isHigherOrderStrategy(strategy)) return undefined;\n const hovStrategy = new HigherOrderVotingStrategy();\n const tracker = getOrCreateCorrelationTracker();\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 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\n const tracker = getOrCreateCorrelationTracker();\n const id = `consensus-${String(getTimeProvider().now())}-${getRandomProvider().random().toString(36).slice(2, 9)}`;\n tracker.recordProposalVotes(id, llmVoteMap, outcome);\n logger.debug('Recorded votes to tracker', { proposalId: id, outcome });\n\n try {\n const persisted = createPersistedProposal(id, llmVoteMap, outcome);\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);\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/** Confidence threshold above which a contrarian rejection triggers escalation (#1799). */\nconst CONTRARIAN_ESCALATION_THRESHOLD = 0.8;\n\n/** Run a single contrarian agent to check for YAGNI/MISALIGNED/SECURITY_RISK (#1799). */\nasync function runContrarianCheck(\n proposal: string,\n log: ILogger\n): Promise<{ shouldEscalate: boolean; reason: string; confidence: number }> {\n try {\n const { executeExpert } = await import('../../pipeline/expert-bridge.js');\n const prompt = [\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 `Proposal: ${proposal.slice(0, 2000)}`,\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 const result = await executeExpert('architecture', prompt);\n if (!result.success) return { shouldEscalate: false, reason: '', confidence: 0 };\n\n const jsonMatch = result.text.match(/\\{[\\s\\S]*\\}/);\n if (jsonMatch === null) return { shouldEscalate: false, reason: '', confidence: 0 };\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 };\n }\n\n return { shouldEscalate: false, reason: '', confidence };\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 return { shouldEscalate: false, reason: '', confidence: 0 };\n }\n}\n\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 votes: readonly AgentVoteResult[];\n errorPolicy: ConsensusVoteInput['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 // #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 };\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 the escalated result, or `undefined` for \"no escalation, continue\n * with the quickMode result.\"\n */\nasync function maybeEscalateContrarian(\n input: ConsensusVoteInput,\n outcome: 'approved' | 'rejected',\n ctx: { strategy: VotingStrategy; posteriorApproval: number | undefined },\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?: { voteTimeoutMs?: number; gatewayAdapters?: readonly IModelAdapter[] | undefined }\n): Promise<ExtendedVotingResult | undefined> {\n if (!input.quickMode || outcome !== 'approved' || input.simulateVotes) return undefined;\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 executeVoting({ ...input, quickMode: false }, logger, opts);\n }\n\n const escalation = await runContrarianCheck(input.proposal, logger);\n if (!escalation.shouldEscalate) return undefined;\n logger.warn('Contrarian escalation: re-running with full vote', {\n reason: escalation.reason,\n confidence: escalation.confidence,\n });\n return executeVoting({ ...input, quickMode: false }, logger, opts);\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 */\n// eslint-disable-next-line max-lines-per-function -- see block comment above\nexport async function executeVoting(\n input: ConsensusVoteInput,\n logger: ILogger,\n opts?: { voteTimeoutMs?: number; gatewayAdapters?: readonly IModelAdapter[] | undefined }\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 });\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 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 recordVotesToTracker(votes, outcome, logger);\n\n const escalated = await maybeEscalateContrarian(\n input,\n outcome,\n { strategy, posteriorApproval: higherOrderResult?.posteriorApproval },\n logger,\n opts\n );\n if (escalated !== undefined) return escalated;\n\n return finalizeVotingResult({\n input,\n strategy,\n algorithm,\n engineResult,\n higherOrderResult,\n votes,\n outcome,\n cascaded,\n startTime,\n logger,\n });\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): 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 });\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 engineResult: ConsensusResult;\n higherOrderResult: ReturnType<typeof runHigherOrderVoting>;\n votes: readonly AgentVoteResult[];\n outcome: 'approved' | 'rejected';\n cascaded: boolean;\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 };\n if (args.higherOrderResult !== undefined) result.higherOrderResult = args.higherOrderResult;\n return result;\n}\n\n// --- Handler & Registration ---\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 */\nfunction recordVoteSideEffects(\n proposal: string,\n strategy: string,\n result: ExtendedVotingResult,\n logger: ILogger,\n ratifies?: string\n): {\n costSummary: ReturnType<typeof recordDecisionCost> | undefined;\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 committable\n // governance artifact 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 = recordAuthenticVote({\n proposal,\n strategy,\n result: result.result,\n votes: result.votes,\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 correlationId: decisionId,\n ...(ratifies !== undefined ? { ratifies } : {}),\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 let costSummary: ReturnType<typeof recordDecisionCost> | undefined;\n try {\n costSummary = recordDecisionCost({ decisionId, gate: 'consensus_vote', votes: result.votes });\n } catch (costError) {\n logger.warn('Per-decision cost rollup failed (non-fatal)', {\n error: getErrorMessage(costError),\n });\n costSummary = undefined;\n }\n return { costSummary, voteRecord };\n}\n\nasync function handleConsensusVote(\n deps: ConsensusVoteDeps,\n args: ConsensusVoteInput\n): Promise<{ ok: true; value: ConsensusVoteResponse } | { ok: false; error: string }> {\n const logger = deps.logger ?? createLogger({ tool: 'consensus_vote' });\n if (args.simulateVotes) warnIfSimulatedOutsideTests('consensus_vote', logger);\n try {\n const result = await executeVoting(args, logger, {\n ...(deps.gatewayAdapters !== undefined && { gatewayAdapters: deps.gatewayAdapters }),\n });\n const strategy = args.strategy ?? 'simple_majority';\n\n // Detect all-error votes: return structured error instead of fake \"rejected\" (#1552)\n const errorVotes = result.votes.filter((v) => v.source === 'error');\n if (errorVotes.length === result.votes.length && result.votes.length > 0) {\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(args.proposal, `All ${String(errorVotes.length)} voters failed: ${failures}`);\n return {\n ok: false,\n error: `All ${String(errorVotes.length)} voters failed. Failures: ${failures}`,\n };\n }\n\n recordVoteSuccess(\n args.proposal,\n strategy,\n result.result.outcome,\n result.totalTimeMs,\n result.votes\n );\n const { costSummary, voteRecord } = recordVoteSideEffects(\n args.proposal,\n strategy,\n result,\n logger,\n args.ratifies\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 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: when `cancel_job` lands while the vote is\n * in-flight, the existing collector unwinds via the AbortSignal plumbing\n * already in #3038 — `collectRealVotes` honors per-voter signals — and\n * the dispatcher writes whatever partial vote set landed before the\n * abort signal as the job result. That preserves audit visibility into\n * who voted before the cancel happened, instead of throwing away all\n * the work.\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 */\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 run: (_jobId, input) => handleConsensusVote(deps, input),\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 const data = result.value as unknown as Record<string, unknown>;\n return {\n ...toolSuccess(JSON.stringify(result.value, null, 2)),\n structuredContent: data,\n };\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 const strategy = validationResult.data.strategy ?? 'simple_majority';\n ctx.logger.debug('Starting consensus vote', {\n strategy,\n quickMode: validationResult.data.quickMode,\n ...(validationResult.data.mode !== undefined ? { mode: validationResult.data.mode } : {}),\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-mode dispatch.\n if (validationResult.data.mode === '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 asyncResult;\n }\n return runSyncConsensusVote(deps, notifier, validationResult.data);\n };\n}\n\n/** Output schema for consensus_vote tool (Issue #1117, #1246). */\nexport const CONSENSUS_VOTE_OUTPUT_SCHEMA = {\n proposal: z.string(),\n strategy: VotingStrategySchema,\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,\n approvalPercentage: z.number(),\n voteCounts: z.object({\n approve: z.number(),\n reject: z.number(),\n abstain: z.number(),\n error: z.number(),\n }),\n votes: z.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 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 threshold: VoteThresholdSchema.optional(),\n durationMs: z.number(),\n simulateVotes: z.boolean(),\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 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(),\n voteRecordNote: z.string().max(500).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 // #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};\n\n/** Advertised MCP input schema for consensus_vote (hoisted to keep the register fn within its line budget). */\nconst CONSENSUS_VOTE_TOOL_SCHEMA = {\n proposal: z.string().min(1).max(MAX_PROPOSAL_LENGTH).describe('Proposal text to vote on'),\n threshold: z\n .enum(['majority', 'supermajority', 'unanimous'])\n .optional()\n .describe('Voting threshold (legacy). Use strategy instead.'),\n strategy: VotingStrategySchema.optional().describe(\n 'Voting strategy: simple_majority (default), supermajority, unanimous, proof_of_learning, or higher_order'\n ),\n quickMode: z.boolean().optional().default(false).describe('Use 3 agents instead of 7'),\n simulateVotes: z\n .boolean()\n .optional()\n .default(false)\n .describe('TESTS ONLY — random output, must not be used for real decisions (#2319)'),\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\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 'Supports higher_order strategy for Bayesian-optimal aggregation with correlation awareness (Issue #514). ' +\n \"Supports async mode (mode: 'async') — 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\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 server.registerTool(\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 toSdkCallbackWithBudgetCheck(wrappedHandler, 'consensus_vote', timeoutMs, logger)\n );\n logger.info('Registered consensus_vote tool with secure handler and timeout protection');\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 * nexus-agents vote command types\n *\n * Type definitions for the consensus voting CLI command.\n *\n * (Source: Issue #212, Process Automation Epic #209)\n */\n\nimport type { ConsensusAlgorithm, Vote, ConsensusResult } from '../consensus/types.js';\nimport type { ErrorPolicy, VoteThreshold } from '../mcp/tools/consensus-vote-types.js';\n\n/**\n * Options for the vote command.\n */\nexport interface VoteCommandOptions {\n readonly proposal: string;\n readonly threshold?: VoteThreshold;\n /** Use simulated votes instead of LLM execution (maps from --dry-run CLI flag) */\n readonly dryRun?: boolean;\n readonly quick?: boolean;\n readonly verbose?: boolean;\n readonly createIssue?: boolean;\n readonly issueNumber?: number;\n /** Timeout per vote in milliseconds (default: 90000 per Issue #607) */\n readonly timeoutMs?: number;\n /**\n * How to treat voters that errored or timed out (#2630). When undefined,\n * the same per-strategy default `executeVoting` uses applies:\n * `fail_closed` for unanimous, `reduce_denominator` otherwise.\n */\n readonly errorPolicy?: ErrorPolicy;\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'\n | 'security'\n | 'devex'\n | 'ai_ml'\n | 'pm'\n | 'catfish'\n | '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 * Individual agent vote with metadata.\n */\nexport interface AgentVoteResult {\n readonly role: VoterRole;\n readonly vote: Vote;\n readonly processingTimeMs: number;\n /**\n * Source of the vote:\n * - 'llm': Real LLM execution\n * - 'simulation': Fallback simulation (opt-in only)\n * - 'error': Error during execution (Issue #523)\n */\n readonly source: 'llm' | 'simulation' | 'error';\n /** CLI that executed this vote (for adaptive routing feedback). */\n readonly cli?: string | undefined;\n /**\n * Model id that executed this vote, when known (e.g. 'claude-sonnet'). Carried\n * so per-decision cost aggregation can attribute spend per model (#3855). Absent\n * for error/simulation votes that never reached a model.\n */\n readonly model?: string | undefined;\n /**\n * Input tokens the adapter reported for this voter's LLM call, when known\n * (#3910). Propagated from `CompletionResponse.usage` so per-decision cost\n * aggregation resolves from `unmeasured` to MEASURED. Absent for\n * error/simulation votes that never reached a model, or for adapters that do\n * not report usage (CLI subscriptions) — those stay honestly `unmeasured`.\n */\n readonly inputTokens?: number | undefined;\n /**\n * Output tokens the adapter reported for this voter's LLM call, when known\n * (#3910). See {@link AgentVoteResult.inputTokens}.\n */\n readonly outputTokens?: number | undefined;\n /** Error message if vote fell back to simulation or encountered an error */\n readonly error?: string;\n}\n\n/**\n * Full voting result.\n */\nexport interface VotingResult {\n readonly proposal: string;\n readonly threshold: ConsensusAlgorithm;\n readonly result: ConsensusResult;\n readonly votes: readonly AgentVoteResult[];\n readonly totalTimeMs: number;\n /** Whether simulated votes were used instead of LLM execution */\n readonly simulateVotes: boolean;\n}\n\n/**\n * Vote verification hash for audit trail.\n */\nexport interface VoteHash {\n readonly role: VoterRole;\n readonly hash: string;\n readonly timestamp: string;\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/**\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 * 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/** Default project name used in voter prompts when no context is provided. */\nconst DEFAULT_PROJECT = 'nexus-agents';\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 — if 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 on your JSON response. NOT inside reasoning — top-level. The schema:\n\n\"findings\": [\n {\n \"summary\": \"One-line summary\",\n \"location\": \"path/file.ext:LINE\",\n \"severity\": \"critical\" | \"high\" | \"medium\" | \"low\",\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\nA finding only triggers strict request_changes if all 4 gate fields = \"passed\" AND named_assertion is substantive (>10 chars naming a concrete failure, not just \"passed\"). Findings missing any of those 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${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 CLAUDE.md\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\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.\n */\nconst REUSE_LADDER_CHECK = `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 nexus-agents 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\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 CLAUDE.md is specifically the rule this role\n enforces.\n\n${REUSE_LADDER_CHECK}\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(project: string = DEFAULT_PROJECT): 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 type { VoterRole } from './vote-types.js';\nimport { getErrorMessage, createLogger } from '../core/index.js';\n\n// ============================================================================\n// Error Classes\n// ============================================================================\n\n/**\n * Error thrown when vote response parsing fails and synthetic votes not allowed.\n * (Source: Issue #512 - Fail-safe voting response parsing)\n *\n * By default, parseVoteResponse throws this error when JSON parsing or validation\n * fails. To use synthetic fallback votes (NOT RECOMMENDED), pass\n * `allowSyntheticVote: true` to the options parameter.\n */\nexport class SyntheticVoteError extends Error {\n constructor(\n reason: string,\n public readonly rawOutput: string\n ) {\n super(\n `Vote response parsing failed: ${reason}. ` +\n 'To use synthetic fallback votes (NOT RECOMMENDED), set allowSyntheticVote: true'\n );\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 * Options for parseVoteResponse.\n */\nexport interface ParseVoteOptions {\n /**\n * Allow synthetic fallback votes when parsing fails.\n * Default: false (throws SyntheticVoteError)\n * (Source: Issue #512 - Fail-safe voting)\n */\n readonly allowSyntheticVote?: boolean;\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']).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});\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 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'] },\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(proposal: string): string {\n return `Evaluate the following proposal and provide your vote.\n\nPROPOSAL:\n${proposal}\n\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\n${VOTE_PROMPT_EXAMPLES}`;\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 */\nexport function extractJsonFromResponse(text: string): string {\n const jsonFence = /```json\\s*([\\s\\S]*?)```/i.exec(text);\n if (jsonFence?.[1] !== undefined) {\n return extractFirstJsonObject(jsonFence[1]) ?? jsonFence[1].trim();\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?.trimStart().startsWith('{') === true) {\n const obj = extractFirstJsonObject(inner);\n if (obj !== undefined) return obj;\n }\n }\n\n return extractFirstJsonObject(text) ?? text.trim();\n}\n\n/**\n * Creates a fallback vote when parsing fails.\n * Attempts to infer decision from text content.\n * ONLY used when allowSyntheticVote is explicitly true.\n * (Source: Issue #512 - Fail-safe voting)\n */\nfunction createFallbackVote(output: string, _role: VoterRole, reason: string): ParsedVote {\n const lower = output.toLowerCase();\n let decision: Vote['decision'] = 'abstain';\n\n // Simple keyword detection - heuristic only\n // Check reject keywords FIRST since \"disagree\" contains \"agree\" substring\n if (lower.includes('reject') || lower.includes('decline') || lower.includes('disagree')) {\n decision = 'reject';\n } else if (lower.includes('approve') || lower.includes('accept') || lower.includes('agree')) {\n decision = 'approve';\n }\n\n // Log warning about synthetic vote\n createLogger({ component: 'voter-response' }).warn(\n 'Creating synthetic vote (NOT parsed from LLM output)',\n { decision, reason }\n );\n\n return {\n decision,\n reasoning: `[SYNTHETIC: ${reason}] ${output.slice(0, 200)}`,\n confidence: 0.5,\n source: 'fallback', // Mark as synthetic\n };\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): ParsedVote {\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 source: 'parsed',\n };\n}\n\n/**\n * Parses vote response from LLM output.\n *\n * By default, throws SyntheticVoteError if parsing fails. To use synthetic\n * fallback votes (NOT RECOMMENDED), pass `allowSyntheticVote: true`.\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 * @param options - Parsing options including allowSyntheticVote\n * @returns ParsedVote with source tracking\n * @throws SyntheticVoteError if parsing fails and allowSyntheticVote is false\n */\nexport function parseVoteResponse(\n output: string,\n role: VoterRole,\n options?: ParseVoteOptions\n): ParsedVote {\n const allowSyntheticVote = options?.allowSyntheticVote ?? false;\n\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);\n }\n\n // Validation failed - throw or fallback based on config\n const reason = `Validation failed: ${validated.error.issues.map((e: { message: string }) => e.message).join(', ')}`;\n if (!allowSyntheticVote) {\n throw new SyntheticVoteError(reason, output);\n }\n return createFallbackVote(output, role, reason);\n } catch (error) {\n // If it's already a SyntheticVoteError, rethrow it\n if (error instanceof SyntheticVoteError) {\n throw error;\n }\n\n // Parse error - throw or fallback based on config\n const reason = getErrorMessage(error, 'Unknown parse error');\n if (!allowSyntheticVote) {\n throw new SyntheticVoteError(reason, output);\n }\n return createFallbackVote(output, role, reason);\n }\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 { VoterRole, AgentVoteResult } from './vote-types.js';\nimport type { IModelAdapter, CompletionRequest, ILogger } from '../core/index.js';\nimport { getRandomProvider } from '../core/index.js';\nimport { delay, withTimeout } from '../utils/async-utils.js';\nimport { VOTER_SYSTEM_PROMPTS, 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';\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/**\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 } 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 * 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): AgentVoteResult {\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 };\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 * Extracts text content from completion response.\n */\nexport function extractTextFromResponse(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 * 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: VoterRole,\n proposal: string,\n timeoutMs: number,\n withResponseFormat: boolean\n): CompletionRequest {\n const base: CompletionRequest = {\n messages: [\n { role: 'system', content: VOTER_SYSTEM_PROMPTS[role] },\n { role: 'user', content: buildVotePrompt(proposal) },\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).\n timeoutMs,\n signal: AbortSignal.timeout(timeoutMs),\n };\n return withResponseFormat\n ? { ...base, responseFormat: { type: 'json_schema', schema: VOTE_JSON_SCHEMA } }\n : base;\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 */\nfunction isStructuredOutputUnsupported(errorMessage: string): boolean {\n return /support tool use/i.test(errorMessage);\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}\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/** One completion attempt: build → complete (timeout-bounded) → extract text + usage. */\nasync function runVoteCompletion(\n role: VoterRole,\n proposal: string,\n adapter: IModelAdapter,\n timeoutMs: number,\n withResponseFormat: boolean\n): Promise<{ ok: true; output: string; usage: VoteUsage } | { ok: false; error: string }> {\n const request = buildVoteRequest(role, proposal, timeoutMs, withResponseFormat);\n const timeoutResult = await withTimeout(\n adapter.complete(request),\n timeoutMs,\n `Vote timeout after ${String(timeoutMs)}ms for role: ${role}`\n );\n if (!timeoutResult.ok) return { ok: false, error: timeoutResult.error };\n const response = timeoutResult.value;\n if (!response.ok) return { ok: false, error: response.error.message };\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.value.usage as unknown as\n | {\n inputTokens?: unknown;\n outputTokens?: unknown;\n }\n | undefined;\n const usage: VoteUsage = {\n inputTokens: readTokenCount(reported?.inputTokens),\n outputTokens: readTokenCount(reported?.outputTokens),\n };\n return { ok: true, output: extractTextFromResponse(response.value.content), usage };\n}\n\nexport async function executeSingleVoteAttempt(\n role: VoterRole,\n proposal: string,\n adapter: IModelAdapter,\n timeoutMs: number\n): Promise<\n { ok: true; vote: Vote; output: string; usage: VoteUsage } | { ok: false; error: string }\n> {\n let completion = await runVoteCompletion(role, proposal, adapter, timeoutMs, 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 (!completion.ok && isStructuredOutputUnsupported(completion.error)) {\n completion = await runVoteCompletion(role, proposal, adapter, timeoutMs, false);\n }\n if (!completion.ok) return { ok: false, error: completion.error };\n\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);\n return { ok: true, vote, output: completion.output, usage: completion.usage };\n } catch (error) {\n if (error instanceof SyntheticVoteError) {\n return { ok: false, error: `Vote parsing failed: ${error.message}` };\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}\n\n/**\n * Executes vote attempts with retry logic.\n * Returns the error message from last failed attempt, or undefined if successful.\n */\nexport async function executeWithRetries(\n opts: RetryOptions\n): Promise<{ vote: Vote; usage: VoteUsage; ok: true } | { error: string; ok: false }> {\n const { role, proposal, adapter, logger, timeoutMs, maxRetries } = opts;\n let lastError = '';\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n if (attempt > 0) {\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 logger.debug('Retrying vote execution', { role, attempt, delayMs, isRateLimit });\n await delay(delayMs);\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 result = await executeSingleVoteAttempt(role, proposal, adapter, timeoutMs);\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 { vote: result.vote, usage: result.usage, ok: true };\n }\n\n lastError = result.error;\n const rateLimited = isRateLimitError(lastError);\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: lastError,\n ...(rateLimited ? { rateLimited: true } : {}),\n });\n }\n\n return { error: lastError !== '' ? lastError : 'Unknown error after all retries', ok: false };\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, VoterRole } from './vote-types.js';\nimport { createErrorVoteResult, delay } from './voter-execution.js';\n\nexport interface VoteOptions {\n readonly timeoutMs: number;\n readonly maxRetries: number;\n readonly allowSimulation: boolean;\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 /** Vote launcher (injected by caller — typically executeAgentVote). */\n readonly voteFn: VoteFn;\n}\n\nconst DEADLINE_MESSAGE = 'overall consensus deadline exceeded';\n\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 * Per-key serializer (#3348). Returns a `run(key, fn)` that chains each fn\n * behind the previous fn for the same key, so at most one runs per key at a\n * time. Different keys run concurrently.\n *\n * Why: when several voter roles round-robin onto the SAME CLI, concurrent\n * subprocesses each trigger that CLI's OAuth access-token refresh. With\n * refresh-token rotation the first call rotates the token and the rest fail\n * with \"refresh token already used\". Serializing per CLI lets the cold-start\n * refresh complete before the next same-CLI call begins. Cross-CLI parallelism\n * is preserved (claude/gemini/codex still overlap).\n */\nfunction createKeyedSerializer(): <T>(key: string, fn: () => Promise<T>) => Promise<T> {\n const tails = new Map<string, Promise<unknown>>();\n return <T>(key: string, fn: () => Promise<T>): Promise<T> => {\n const prev = tails.get(key) ?? Promise.resolve();\n // Run fn whether the previous same-key call resolved or rejected.\n const run = prev.then(fn, fn);\n // Chain on a never-rejecting tail so one failure can't break ordering.\n tails.set(\n key,\n run.then(\n () => undefined,\n () => undefined\n )\n );\n return run;\n };\n}\n\nfunction raceWithDeadline(\n p: Promise<AgentVoteResult>,\n role: VoterRole,\n deadlineMs: number\n): Promise<AgentVoteResult> {\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 }, deadlineMs);\n });\n return Promise.race([p, timeoutP]).finally(() => {\n if (timer !== undefined) clearTimeout(timer);\n });\n}\n\nexport async function launchVotesWithOverallDeadline(\n input: LaunchVotesInput\n): Promise<readonly AgentVoteResult[]> {\n const {\n roles,\n proposal,\n roleAdapters,\n fallbackAdapter,\n logger,\n voteOptions,\n interDelay,\n overallDeadlineMs,\n voteFn,\n } = input;\n\n const startedAt = Date.now();\n const serialize = createKeyedSerializer();\n\n // One serialized, deadline-bounded vote attempt on a specific adapter.\n const voteOnAdapter = (role: VoterRole, adapter: IModelAdapter): Promise<AgentVoteResult> =>\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 serialize(adapterCliKey(adapter), () => {\n const remaining = Math.max(1, overallDeadlineMs - (Date.now() - startedAt));\n return raceWithDeadline(\n voteFn(role, proposal, adapter, logger, voteOptions),\n role,\n remaining\n );\n });\n\n const wrapped = roles.map(async (role, i): Promise<AgentVoteResult> => {\n if (i > 0 && interDelay > 0) await delay(interDelay);\n const adapter = roleAdapters.get(role) ?? fallbackAdapter;\n const primary = await voteOnAdapter(role, adapter);\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\n // once on the known-good fallback adapter so one bad CLI can't drop a voter.\n if (!shouldRetryOnFallback(primary, adapter, fallbackAdapter)) return primary;\n logger.warn('Voter failed on diverse adapter; retrying on fallback (#3587)', {\n role,\n failedCli: adapterCliKey(adapter),\n fallbackCli: adapterCliKey(fallbackAdapter),\n error: primary.error,\n });\n return voteOnAdapter(role, fallbackAdapter);\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 * 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 { VoterRole, AgentVoteResult } from './vote-types.js';\nimport { resolveVoterModelOverrides } from './voter-model-overrides.js';\nimport { VOTER_ROLES } from './vote-types.js';\nimport type { Vote } from '../consensus/types.js';\nimport type { VoteUsage } from './voter-execution.js';\nimport type { IModelAdapter, ILogger } from '../core/index.js';\nimport { createLogger, getTimeProvider, getErrorMessage } 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 { checkCodexConcurrency } from '../cli-adapters/codex-limits.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 type ParseVoteOptions,\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, getMcpSafeDeadlineMs } from '../config/timeouts.js';\nimport { launchVotesWithOverallDeadline } from './voter-agents-deadline.js';\n\n/**\n * Computes an overall wall-clock deadline for a consensus vote call (#1871).\n *\n * Acts as a safety net above per-vote timeouts: even if executeAgentVote's\n * internal withTimeout race fails to resolve (e.g. subprocess adapter hang),\n * this deadline bounds total wall time and lets partial results return.\n *\n * Formula: worst-case legitimate completion (timeoutMs * (maxRetries+1))\n * plus staggered launch headroom, plus `VOTE_TIMEOUTS.overallDeadlineBufferMs`.\n */\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// ============================================================================\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 * 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 */\nfunction buildLlmVoteResult(\n role: VoterRole,\n vote: Vote,\n usage: VoteUsage,\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 ...(usage.inputTokens !== undefined ? { inputTokens: usage.inputTokens } : {}),\n ...(usage.outputTokens !== undefined ? { outputTokens: usage.outputTokens } : {}),\n };\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 */\nexport async function executeAgentVote(\n role: VoterRole,\n proposal: string,\n adapter: IModelAdapter,\n logger: ILogger,\n options?: { timeoutMs?: number; maxRetries?: number; allowSimulation?: boolean }\n): Promise<AgentVoteResult> {\n const start = getTimeProvider().now();\n const timeoutMs = options?.timeoutMs ?? resolveVoteTimeout();\n const maxRetries = options?.maxRetries ?? VOTE_TIMEOUTS.maxRetries;\n const allowSimulation = options?.allowSimulation ?? false;\n\n logger.info('Executing vote', { role, model: adapter.modelId, provider: adapter.providerId });\n\n const result = await executeWithRetries({\n role,\n proposal,\n adapter,\n logger,\n timeoutMs,\n maxRetries,\n });\n const processingTimeMs = getTimeProvider().now() - start;\n\n if (result.ok) {\n logger.info('Vote completed', { role, model: adapter.modelId, decision: result.vote.decision });\n return buildLlmVoteResult(role, result.vote, result.usage, adapter, processingTimeMs);\n }\n\n // All retries exhausted\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 return createSimulationVoteResult(role, proposal, processingTimeMs, result.error);\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 return createErrorVoteResult(role, errorText, processingTimeMs);\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 /** 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}\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 */\nfunction resolveAdapter(\n options: CollectRealVotesOptions,\n logger: ILogger\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({ logger });\n return { adapter: registry.getDefault() };\n } catch (error) {\n return { error: getErrorMessage(error) };\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 */\nfunction 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/** Assigns a single adapter to all roles (fallback path). */\nfunction assignUniformAdapter(\n roles: readonly VoterRole[],\n adapter: IModelAdapter\n): Map<VoterRole, IModelAdapter> {\n const adapters = new Map<VoterRole, IModelAdapter>();\n for (const role of roles) adapters.set(role, adapter);\n return adapters;\n}\n\n/** Creates CLI-specific adapters for available CLIs via the unified registry. */\nfunction createCliAdapterMap(\n clis: readonly CliName[],\n logger: ILogger\n): Map<CliName, IModelAdapter> {\n const registry = getGlobalRegistry({ logger });\n const result = new Map<CliName, IModelAdapter>();\n for (const cli of clis) {\n result.set(cli, registry.getAdapterForCli(cli));\n }\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 round-robin.\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 round-robin. An unknown override id warns + falls\n // through to round-robin (handled in the resolver).\n const overrides = resolveVoterModelOverrides(roles, gatewayAdapters, logger);\n const roundRobinRoles = roles.filter((r) => !overrides.has(r));\n const assigned = assignRoundRobinAdapters(\n roundRobinRoles,\n gatewayAdapters.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 const distinctModels = new Set([...assigned.values()].map((a) => a.modelId));\n if (roles.length > 1 && distinctModels.size === 1) {\n logger.warn(\n 'Consensus panel collapsed to a single gateway model via overrides — votes may correlate',\n { model: [...distinctModels][0], roleCount: roles.length }\n );\n }\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\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, logger);\n if (cliAdapters.size <= 1) return assignUniformAdapter(roles, fallbackAdapter);\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. */\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 readonly voteOptions: { timeoutMs: number; maxRetries: number; allowSimulation: boolean };\n readonly interDelay: number;\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): Promise<readonly AgentVoteResult[]> {\n const { roles, proposal, roleAdapters, fallbackAdapter, logger, voteOptions, interDelay } = input;\n // Raw \"worst legitimate completion\" estimate — retained unchanged so the\n // formula still answers \"how long could this vote take in principle?\".\n const computedDeadlineMs = computeOverallConsensusDeadlineMs(\n voteOptions.timeoutMs,\n voteOptions.maxRetries,\n roles.length,\n interDelay\n );\n // Clamp below the outer MCP tool-wrapper timeout. Without this, the\n // middleware kills the promise chain before launchVotesWithOverallDeadline\n // can produce structured partial results — clients see a naked timeout\n // error instead of a `source: 'error' / error: 'overall consensus deadline\n // exceeded'` vote per stuck role. (Issue #2105)\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 launchVotesWithOverallDeadline({\n roles,\n proposal,\n roleAdapters,\n fallbackAdapter,\n logger,\n voteOptions,\n interDelay,\n overallDeadlineMs,\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 */\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 const timeoutMs = options.timeoutMs ?? resolveVoteTimeout();\n const maxRetries = options.maxRetries ?? VOTE_TIMEOUTS.maxRetries;\n\n if (simulate === true) {\n logger.info('Using simulation mode (explicitly requested)');\n return createSimulatedVotes(roles, proposal);\n }\n\n const adapterResult = resolveAdapter(options, logger);\n\n if ('error' in adapterResult) {\n logger.error('No adapter available for voting', undefined, { error: adapterResult.error });\n\n if (allowSimulation === true) {\n logger.warn('Falling back to simulation (allowSimulation=true)');\n return createSimulatedVotes(roles, proposal, 'No adapter available');\n }\n\n throw new NoAdapterError(\n `No adapter available for voting: ${adapterResult.error}. ` +\n 'Install a CLI (claude/gemini/codex) or set ANTHROPIC_API_KEY.'\n );\n }\n\n // Per Issue #845: Use diverse adapters when no explicit adapter is provided\n const roleAdapters =\n options.adapter !== undefined\n ? assignUniformAdapter(roles, adapterResult.adapter)\n : await resolveDiverseAdapters(roles, logger, adapterResult.adapter, options.gatewayAdapters);\n\n warnIfCodexConcurrencyExceeded(roleAdapters, logger);\n\n const voteOptions = { timeoutMs, maxRetries, allowSimulation: allowSimulation ?? false };\n const interDelay = options.interAgentDelayMs ?? DEFAULT_INTER_AGENT_DELAY_MS;\n\n return launchStaggeredVotes({\n roles,\n proposal,\n roleAdapters,\n fallbackAdapter: adapterResult.adapter,\n logger,\n voteOptions,\n interDelay,\n });\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/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 './types-core.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: 0.67) */\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 './types-core.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: 0.67) */\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 * Higher-order voting uses Bayesian-optimal aggregation that handles correlated\n * agents better than traditional independent voting assumptions.\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 /** Average internal independence score (lower = more independent) */\n readonly independenceScore: 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 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}\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});\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 */\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 /** Maximum correlation age in milliseconds before recalculation (default: 24h) */\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 /** Decay factor for old observations (0-1, default: 0.95) */\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 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 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 /**\n * Record a vote and its outcome for correlation tracking.\n */\n recordVote(agentId: string, vote: Vote, outcome: 'approved' | 'rejected'): 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 ): 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 if (subset.agentIds.length === 1) 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. Higher-order voting\n * uses Bayesian-optimal aggregation that handles correlated agents better,\n * resulting in more accurate consensus decisions.\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 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 - 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} from './types.js';\nimport { VOTING_THRESHOLDS } from './types.js';\nimport { HigherOrderVotingStrategy } from './higher-order-voting.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 reason: string;\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 (67% passes at\n * exactly 67%), strict `>` for simple-majority and proof-of-learning (a tie\n * at the threshold is not enough). Callers apply their own zero-denominator\n * guard before calling this.\n */\nfunction 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 * 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 (>=67% 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\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 * 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 return {\n approved,\n approvalPercentage,\n voteCounts: counts,\n weightedCounts,\n reason: approved\n ? `Approved with ${approvalPercentage.toFixed(1)}% weighted approval`\n : `Rejected with ${approvalPercentage.toFixed(1)}% weighted approval`,\n };\n }\n}\n\n/**\n * Calculate vote weight for an agent based on their performance history.\n * Weight ranges from 0.5 (no history) to 1.0 (perfect track record).\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 {\n ProposalId,\n ProposalState,\n ConsensusResult,\n ProposalStatus,\n ConsensusEngineConfig,\n} from './types.js';\nimport type { VotingOutcome } from './strategies.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 approvalPercentage: outcome.approvalPercentage,\n quorumReached: 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 = 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 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 approvalPercentage: outcome.approvalPercentage,\n quorumReached: 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 * 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 * 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-disable max-lines */\n// 426 lines — cohesive single-concern engine. Per governance, 400-600 OK if cohesive.\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 VOTING_THRESHOLDS,\n DEFAULT_INCREMENTAL_QUORUM_CONFIG,\n} from './types.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 const performance = this.agentPerformance.get(agentId);\n state.voteWeights.set(agentId, calculateVoteWeight(performance));\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 * Abstracts quorum validation across VotingProtocol, WeightedVoting, and ConsensusEngine.\n * Per redundancy-analysis.md Section 3.4 - consolidates three quorum implementations.\n *\n * @module consensus/quorum-validator\n * (Source: Issue #576, ADR-0003)\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 './types-core.js';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Agent record for eligibility checks and Byzantine detection.\n */\nexport interface AgentRecord {\n readonly agentId: string;\n readonly weight: number;\n readonly trustScore: number;\n readonly byzantineFlags?: number;\n readonly successRate?: number;\n readonly totalTasks?: number;\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 /** Enable Byzantine detection */\n readonly enableByzantineDetection?: boolean;\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: Agent records for eligibility checks */\n readonly agentRecords?: ReadonlyMap<string, AgentRecord>;\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 eligibleAgents: readonly string[];\n readonly reasoning: string;\n}\n\n/**\n * Eligibility check result.\n */\nexport type EligibilityResult =\n | { readonly eligible: true; readonly weight: number }\n | {\n readonly eligible: false;\n readonly reason: 'insufficient_weight' | 'low_trust' | 'byzantine_flagged' | 'excluded';\n readonly weight: number;\n };\n\n/**\n * Unified quorum validator interface.\n */\nexport interface IQuorumValidator {\n validateQuorum(input: QuorumValidationInput): QuorumValidationResult;\n getQuorumBreakdown(input: QuorumValidationInput): QuorumBreakdown;\n isAgentEligible(\n agentId: string,\n record: AgentRecord | undefined,\n config: QuorumValidationConfig\n ): EligibilityResult;\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\nconst DEFAULT_MIN_TRUST = 0.3;\nconst DEFAULT_MIN_WEIGHT = 0.1;\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 // Determine decision\n return this.buildReachedResult(breakdown);\n }\n\n getQuorumBreakdown(input: QuorumValidationInput): QuorumBreakdown {\n const { votes, agentWeights, config, agentRecords, requiredParticipants } = input;\n\n // Count votes\n const voteCounts = this.countVotes(votes);\n const eligibleAgents = this.getEligibleAgents(votes, agentRecords, config);\n\n // Calculate weights if applicable\n const { totalWeight, weightedCounts } = this.calculateWeights(\n votes,\n agentWeights,\n agentRecords,\n config\n );\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 ?? votes.size\n );\n\n return {\n totalVotes: votes.size,\n voteCounts,\n totalWeight,\n weightedCounts,\n threshold,\n actualQuorum,\n quorumReached,\n eligibleAgents,\n reasoning,\n };\n }\n\n isAgentEligible(\n agentId: string,\n record: AgentRecord | undefined,\n config: QuorumValidationConfig\n ): EligibilityResult {\n if (record === undefined) {\n return { eligible: true, weight: 1.0 }; // Default eligibility\n }\n\n // Check Byzantine flags\n if (config.enableByzantineDetection === true && (record.byzantineFlags ?? 0) > 0) {\n this.logger.debug('Agent flagged as Byzantine', { agentId, flags: record.byzantineFlags });\n return { eligible: false, reason: 'byzantine_flagged', weight: record.weight };\n }\n\n // Check trust score\n if (record.trustScore < DEFAULT_MIN_TRUST) {\n this.logger.debug('Agent trust score below threshold', {\n agentId,\n trustScore: record.trustScore,\n });\n return { eligible: false, reason: 'low_trust', weight: record.weight };\n }\n\n // Check weight\n if (record.weight < DEFAULT_MIN_WEIGHT) {\n this.logger.debug('Agent weight below threshold', { agentId, weight: record.weight });\n return { eligible: false, reason: 'insufficient_weight', weight: record.weight };\n }\n\n return { eligible: true, weight: record.weight };\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 getEligibleAgents(\n votes: ReadonlyMap<string, Vote>,\n agentRecords: ReadonlyMap<string, AgentRecord> | undefined,\n config: QuorumValidationConfig\n ): readonly string[] {\n const eligible: string[] = [];\n\n for (const agentId of votes.keys()) {\n const record = agentRecords?.get(agentId);\n const result = this.isAgentEligible(agentId, record, config);\n if (result.eligible) {\n eligible.push(agentId);\n }\n }\n\n return eligible;\n }\n\n private calculateWeights(\n votes: ReadonlyMap<string, Vote>,\n agentWeights: ReadonlyMap<string, number> | undefined,\n agentRecords: ReadonlyMap<string, AgentRecord> | 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, agentRecords, 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 agentRecords: ReadonlyMap<string, AgentRecord> | undefined,\n config: QuorumValidationConfig\n ): number {\n let weight = agentWeights?.get(agentId) ?? agentRecords?.get(agentId)?.weight ?? 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(\n voteCounts: VoteCounts,\n weightedCounts: WeightedVoteCounts | undefined,\n totalWeight: number | undefined,\n config: QuorumValidationConfig,\n requiredParticipants: number\n ): { threshold: number; actualQuorum: number; quorumReached: boolean; reasoning: string } {\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(weightedCounts, totalWeight, threshold);\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 ): { 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 );\n\n return { threshold, actualQuorum: totalWeight, quorumReached, reasoning };\n }\n\n private buildWeightedReasoning(\n quorumReached: boolean,\n totalWeight: number,\n threshold: number,\n approveRatio: number,\n rejectRatio: number\n ): string {\n if (!quorumReached) {\n return `Weighted quorum not reached: ${totalWeight.toFixed(2)} < ${String(threshold)}`;\n }\n if (approveRatio > rejectRatio) {\n return `Approval wins with weighted ratio ${formatPercentage(approveRatio, 1)}`;\n }\n if (rejectRatio > approveRatio) {\n return `Rejection wins with weighted ratio ${formatPercentage(rejectRatio, 1)}`;\n }\n return `No clear winner: approve=${formatPercentage(approveRatio, 1)}, reject=${formatPercentage(rejectRatio, 1)}`;\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 private buildReachedResult(breakdown: QuorumBreakdown): QuorumValidationResult {\n const { voteCounts, weightedCounts } = breakdown;\n\n // Determine winning decision\n const approves = weightedCounts?.approve ?? voteCounts.approve;\n const rejects = weightedCounts?.reject ?? voteCounts.reject;\n const total = weightedCounts?.totalWeight ?? voteCounts.total;\n\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/**\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 { 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 const allVoted = session.committee.every((agentId) => consensusRound.finalVotes.has(agentId));\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 EventBus 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 IEventBus,\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(eventBus: IEventBus, params: WeightUpdatedParams): 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(eventBus: IEventBus, params: PatternDetectedParams): 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(eventBus: IEventBus, params: AgentFlaggedParams): 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: IEventBus,\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 { IEventBus } 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?: IEventBus;\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 { IEventBus } 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: IEventBus | 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 * 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';\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 average absolute correlation within a subset.\n *\n * @param subset - Agent IDs in the subset\n * @param correlationMatrix - Correlation matrix\n * @returns Average absolute correlation (0 if no pairs)\n */\nexport function computeSubsetIndependenceScore(\n subset: readonly string[],\n correlationMatrix: CorrelationMatrix\n): number {\n if (subset.length < 2) return 0;\n\n let totalCorrelation = 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 totalCorrelation += Math.abs(correlation);\n pairs++;\n }\n }\n }\n }\n\n return pairs > 0 ? totalCorrelation / pairs : 0;\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 independenceScore = computeSubsetIndependenceScore(subset, correlationMatrix);\n const observationCount = computeSubsetObservationCount(subset, pairwiseHistory);\n\n subsets.push({\n id: `subset-${String(subsetId++)}`,\n agentIds: subset,\n independenceScore,\n observationCount,\n });\n }\n\n return subsets;\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} 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';\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 computeSubsetIndependenceScore,\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 pairwiseHistory: Map<AgentPairKey, MutablePairwiseHistory> = new Map();\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 logger.info('CorrelationTracker initialized', {\n maxObservationsPerAgent: this.config.maxObservationsPerAgent,\n maxProposals: this.config.maxProposals,\n });\n }\n\n recordVote(agentId: string, vote: Vote, outcome: 'approved' | 'rejected'): void {\n const proposalId = `proposal-${String(getTimeProvider().now())}-${getRandomProvider().random().toString(36).slice(2, 9)}`;\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 };\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 ): void {\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 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 };\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(proposalId, 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.pairwiseHistory) {\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.pairwiseHistory.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 subsets = partitionIntoIndependentGroups(\n agents,\n correlationMatrix,\n this.pairwiseHistory,\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 true;\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 const history = this.pairwiseHistory.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\n for (const [, history] of this.pairwiseHistory) {\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: this.pairwiseHistory.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.pairwiseHistory.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 /**\n * Evict the oldest pairwise history entry (by lastUpdated) when\n * maxTrackedPairs limit is exceeded.\n */\n private evictOldestPair(): void {\n if (this.pairwiseHistory.size <= this.config.maxTrackedPairs) return;\n\n let oldestKey: AgentPairKey | undefined;\n let oldestTime = Infinity;\n for (const [key, history] of this.pairwiseHistory) {\n const time = history.lastUpdated.getTime();\n if (time < oldestTime) {\n oldestTime = time;\n oldestKey = key;\n }\n }\n if (oldestKey !== undefined) {\n this.pairwiseHistory.delete(oldestKey);\n logger.debug('Evicted oldest pairwise history entry', {\n evictedKey: oldestKey,\n reason: 'maxTrackedPairs',\n remainingPairs: this.pairwiseHistory.size,\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(proposalId: string, 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 let history = this.pairwiseHistory.get(pairKey);\n\n if (history === undefined) {\n history = {\n pairKey,\n jointObservations: 0,\n agreements: 0,\n disagreements: 0,\n correlation: 0,\n lastUpdated: new Date(getTimeProvider().now()),\n };\n this.pairwiseHistory.set(pairKey, history);\n this.evictOldestPair();\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 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 first load (its entries are surfaced like any other history) and\n * is removed by `compactCorrelationData()` after consolidation. New writes\n * 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 { z } from 'zod';\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 type { Vote } from './types-core.js';\nimport { createCorrelationTracker } from './correlation-tracker.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 for forward compatibility. Bumped to 2 with the JSONL switch. */\nconst SCHEMA_VERSION = 2;\n\n// ============================================================================\n// Persisted Data Types\n// ============================================================================\n\n/**\n * A single persisted vote within a proposal.\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});\n\n/** Type for a persisted vote entry */\ntype PersistedVote = z.infer<typeof PersistedVoteSchema>;\n\n/**\n * A persisted proposal with its votes and outcome.\n * Stored as a replayable record so internal tracker state\n * is reconstructed through the public API.\n */\nconst 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\n/** Type for a persisted proposal entry */\ntype PersistedProposal = z.infer<typeof PersistedProposalSchema>;\n\n/**\n * Top-level persisted correlation data structure (legacy `correlations.json`).\n * Kept exported for back-compat — the JSONL format stores `PersistedProposal`\n * directly per line and has no wrapper.\n */\nexport const PersistedCorrelationDataSchema = z.object({\n version: z.number().int().positive(),\n proposals: z.array(PersistedProposalSchema),\n savedAt: z.iso.datetime(),\n});\n\n/** Validated persisted correlation data */\nexport type PersistedCorrelationData = z.infer<typeof PersistedCorrelationDataSchema>;\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\" (formerly the \"not found\" error case).\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// Compaction (consolidate JSONL + delete legacy json)\n// ============================================================================\n\n/**\n * Rewrites the JSONL store as a deduplicated, sorted snapshot and removes\n * the legacy `correlations.json` (if present). Safe to call periodically\n * (e.g., on session shutdown) to bound the JSONL's size.\n *\n * Within-process: this is the only operation that's NOT race-free across\n * processes. Two processes both running compaction simultaneously could\n * lose appends made between the read and the rename. Callers should\n * serialize compaction — invoke from one process per data dir, or guard\n * with a lockfile.\n */\nexport function compactCorrelationData(\n config: HigherOrderVotingConfig = DEFAULT_HIGHER_ORDER_CONFIG\n): Result<{ before: number; after: number }, Error> {\n const dirResult = ensureVotingDirectory();\n if (!dirResult.ok) return dirResult;\n\n const legacy = loadLegacyJsonProposals();\n const jsonl = loadJsonlProposals();\n const proposals = consolidate(legacy, jsonl, config.maxProposals);\n const before = legacy.length + jsonl.length;\n\n const jsonlPath = getCorrelationJsonlPath();\n const tempPath = `${jsonlPath}.tmp.${String(process.pid)}`;\n const body =\n proposals.map((p) => JSON.stringify(p)).join('\\n') + (proposals.length > 0 ? '\\n' : '');\n\n try {\n fs.writeFileSync(tempPath, body, { encoding: 'utf-8', mode: FILE_MODE });\n fs.renameSync(tempPath, jsonlPath);\n if (fs.existsSync(getCorrelationDataPath())) {\n fs.unlinkSync(getCorrelationDataPath());\n }\n return ok({ before, after: proposals.length });\n } catch (cause: unknown) {\n try {\n if (fs.existsSync(tempPath)) fs.unlinkSync(tempPath);\n } catch (cleanupErr: unknown) {\n logger.debug('Failed to clean up temp file during compaction', {\n path: tempPath,\n error: cleanupErr instanceof Error ? cleanupErr.message : String(cleanupErr),\n });\n }\n const error = cause instanceof Error ? cause : new Error(String(cause));\n return err(new Error(`Failed to compact correlation data: ${error.message}`));\n }\n}\n\n// ============================================================================\n// Persistent Tracker Factory\n// ============================================================================\n\n/**\n * Replays persisted proposals into a tracker via `recordProposalVotes()`,\n * reconstructing all internal state through the public API.\n */\nfunction replayProposals(\n tracker: ICorrelationTracker,\n proposals: readonly PersistedProposal[]\n): number {\n let replayed = 0;\n\n for (const proposal of proposals) {\n const votes = new Map<string, Vote>();\n\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\n tracker.recordProposalVotes(proposal.proposalId, votes, proposal.outcome);\n replayed++;\n }\n\n return replayed;\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\n// ============================================================================\n// Proposal Recording Helper\n// ============================================================================\n\n/**\n * Creates a persistable proposal record from vote data.\n *\n * Use this to build proposals that can be passed to `saveCorrelationData()`.\n *\n * @param proposalId - Unique proposal identifier\n * @param votes - Map of agent IDs to their votes\n * @param outcome - Final proposal outcome\n * @returns A persistable proposal record\n */\nexport function createPersistedProposal(\n proposalId: string,\n votes: ReadonlyMap<string, Vote>,\n outcome: 'approved' | 'rejected'\n): PersistedProposal {\n const persistedVotes: PersistedVote[] = [];\n\n for (const [agentId, vote] of votes) {\n persistedVotes.push({\n agentId,\n decision: vote.decision,\n confidence: vote.confidence,\n });\n }\n\n return {\n proposalId,\n votes: persistedVotes,\n outcome,\n timestamp: new Date().toISOString(),\n };\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\nimport { z } from 'zod';\nimport type { AgentVoteResult, VotingResult } from '../../cli/vote-types.js';\nimport { VOTER_ROLES } from '../../cli/vote-types.js';\nimport type { HigherOrderVotingResult } from '../../consensus/higher-order-types.js';\nimport type { DecisionCostSummary } from '../../observability/decision-cost.js';\nimport type { VoteRecordPersistOutcome } from './consensus-vote-recording.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)\n * - `higher_order`: Bayesian-optimal with correlation awareness (Issue #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 uses higher-order (Bayesian, correlation-aware) aggregation.\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 *\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(['reduce_denominator', 'count_as_abstain', 'fail_closed']);\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 * Fraction of total voters that, if errored, forces the vote to fail\n * regardless of `errorPolicy`. (#2630 — safety floor.)\n */\nexport const ERROR_FLOOR_FRACTION = 0.5;\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\nexport const ConsensusVoteInputSchema = z.object({\n proposal: z.string().min(1).max(MAX_PROPOSAL_LENGTH).describe('Proposal text to vote on'),\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 (Bayesian-optimal)'\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). 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-mode 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 (#3041 vote deferred this to Stage 4): when\n * a polling client calls `cancel_job` mid-vote, the dispatcher aborts\n * in-flight voters via the AbortSignal plumbing from #3038. The\n * resulting job result is `{ status: 'cancelled', partialVotes: [...] }`\n * with whatever voters completed before the abort signal — preserves\n * audit visibility into who voted before the cancel landed.\n *\n * Kept optional (no `.default()`) so the inferred type doesn't force\n * `mode: 'sync'` on every existing call site / test fixture.\n */\n mode: z\n .enum(['sync', 'async'])\n .optional()\n .describe(\n 'Dispatch mode (default: sync). Use \"async\" for higher-order strategies with 7 voters.'\n ),\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\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 /** Model used for this agent's vote (Issue #817). */\n modelUsed?: string;\n /** Structured rejection categories for reject→refine→re-vote loops (Issue #1213). */\n rejectionCategories?: readonly string[];\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/** Higher-Order Voting metadata (Issue #514). */\nexport interface HigherOrderMetadata {\n posteriorApproval: number;\n posteriorRejection: number;\n effectiveVoteCount: number;\n method: 'ow' | 'isp' | 'simple';\n usedCorrelationData: boolean;\n improvementOverBaseline: number;\n downweightedAgents: readonly string[];\n reasoning: string;\n}\n\nexport interface ConsensusVoteResponse {\n proposal: string;\n threshold?: VoteThreshold;\n strategy: VotingStrategy;\n decision: VoteDecisionStatus;\n approvalPercentage: number;\n voteCounts: { approve: number; reject: number; abstain: number; error: number };\n votes: AgentVoteSummary[];\n durationMs: number;\n simulateVotes: boolean;\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 * 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 * #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\n/** Extended voting result with optional Higher-Order metadata. */\nexport interface ExtendedVotingResult extends VotingResult {\n strategy: VotingStrategy;\n higherOrderResult?: HigherOrderVotingResult;\n /** Reason an error policy short-circuited the vote (#3124); surfaced on the response. */\n policyReason?: 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 };\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 * #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 * 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 */\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\n const allErrors = errorCount === result.votes.length && errorCount > 0;\n // #4053: an error-policy short-circuit (the >50% hard floor, or fail_closed)\n // VOIDED the vote because too many voters errored — that is \"couldn't get\n // enough valid votes\" (no_quorum), NOT the panel rejecting the proposal.\n // Reporting `rejected` when the responding voters actually approved is\n // misleading (e.g. quickMode 1 approve + 2 error → no_quorum, not rejected).\n // `policyReason` is set iff such a short-circuit occurred; it still rides the\n // response so callers see WHY there was no quorum.\n const errorVoidedVote = result.policyReason !== undefined;\n const decision: VoteDecisionStatus =\n errorVoidedVote || (!result.result.quorumReached && allErrors)\n ? 'no_quorum'\n : mapOutcomeToDecision(result.result.outcome);\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 },\n votes: result.votes.map(toAgentVoteSummary),\n durationMs: result.totalTimeMs,\n simulateVotes: result.simulateVotes,\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\n applyOptionalResponseFields(response, input, result, errorCount, costSummary);\n return response;\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 if (input.threshold !== undefined) {\n response.threshold = input.threshold;\n }\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 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 };\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 *\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-vote-types.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') {\n // Errors stay in the engine input but as abstain decisions.\n // The original `source: 'error'` is preserved so the per-voter\n // response shape and `voteCounts.error` still report the error.\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 * nexus-agents/audit - Authentic Vote Record Store (#3897, model revised #3927)\n *\n * Persists a completed `consensus_vote` to an append-only, tamper-evident\n * artifact at vote time. Authenticity rests on a payload-covering tamper-evident\n * record set + monotonic sequence ({@link verifyVoteRecordSet}), not on manual\n * YAML transcription.\n *\n * PATH RESOLUTION (#3991, design vote 7-0 Option B). The RUNTIME ledger now\n * routes through the canonical {@link nexusDataPath} resolver under the\n * `governance/` category, consistent with the 10+ other runtime stores — so it\n * works for sandbox and global-install layouts and always has a writable home:\n * - `NEXUS_VOTE_RECORDS_PATH` explicit override (absolute used as-is; relative\n * resolved against cwd per #3963) — the escape hatch, and the ONLY way to\n * reach the committed `<repo>/governance/vote-records.jsonl` ledger the\n * promotion gate (#3895) reads (a separate caller-commits/governor-gate\n * artifact, deferred — never auto-written);\n * - otherwise `nexusDataPath('governance', 'vote-records.jsonl')` →\n * `<sandbox-root>/.nexus-agents/governance/...` (sandbox),\n * `<repo>/.nexus-agents/governance/...` (repo-preferred, gitignored), or\n * `~/.nexus-agents/governance/vote-records.jsonl` (default / global install).\n * The pre-#3991 `findRepoRoot(cwd)/governance/...` default is GONE — it caused\n * the #3991 silent-skip on global installs (cwd not a repo → undefined → no\n * persist) AND tracked-file churn. The resolver now essentially always returns a\n * path, so the producer essentially always persists into `.nexus-agents`.\n *\n * DRY/drift hazard (DevEx, #3897). This is the AUTOMATED authoring path: the\n * record is written as a side effect of the live vote, so the committed artifact\n * cannot drift from what actually happened the way a hand-edited\n * `ratification-votes.yaml` entry can. Each record is self-hashed (covering its\n * `sequence`), so a forged/edited line breaks verification.\n *\n * MERGE SAFETY (#3927). The ledger is a SET, not a chain: `sequence` is assigned\n * as (max existing sequence)+1, and the self-hash excludes `previousHash`, so\n * two branches that each append from the same tip merge conflict-free under the\n * `governance/vote-records.jsonl merge=union` attribute. Duplicate sequences\n * from such a merge are a benign fork signal, not tampering.\n *\n * @module audit/vote-record-store\n */\n\nimport { appendFileSync, existsSync, mkdirSync, readFileSync } from 'node:fs';\nimport { dirname, isAbsolute, relative, resolve, sep } from 'node:path';\n\nimport type { ILogger } from '../core/index.js';\nimport { createLogger, getErrorMessage } from '../core/index.js';\nimport type { ConsensusResult, Vote } from '../consensus/types.js';\nimport type { AgentVoteResult } from '../cli/vote-types.js';\nimport { getNexusDataDir, nexusDataPath } from '../config/nexus-data-dir.js';\n\nimport type { VoteRecord, VoterSummary } from './vote-record.js';\nimport { VoteRecordSchema, computeVoteRecordHash, hashProposal } from './vote-record.js';\n\n/**\n * Repo-relative path of the COMMITTED governance ledger the promotion gate\n * (#3895) reads. As of #3991 the runtime store no longer auto-writes here — this\n * committed artifact is reached only via the {@link VOTE_RECORDS_PATH_ENV}\n * override (the separate caller-commits/governor-gate path, deferred). Kept\n * exported as the canonical relative location for the gate + override guidance.\n */\nexport const VOTE_RECORDS_REL_PATH = 'governance/vote-records.jsonl';\n\n/**\n * {@link nexusDataPath} category + filename for the RUNTIME ledger (#3991).\n * `governance` is a per-repo category in `nexus-data-dir.ts`, so with\n * `NEXUS_REPO_PREFERRED=1` (default) the runtime ledger lands in\n * `<repo>/.nexus-agents/governance/` (gitignored), under a sandbox root when\n * `NEXUS_SANDBOX` is set, and `~/.nexus-agents/governance/` otherwise.\n */\nconst VOTE_RECORDS_DATA_CATEGORY = 'governance';\nconst VOTE_RECORDS_FILENAME = 'vote-records.jsonl';\n\n/**\n * Env var to force the artifact path. When set non-empty it is used directly\n * (resolved to an absolute path — see {@link resolveVoteRecordsPath}) and the\n * canonical {@link nexusDataPath} resolution is skipped — the escape hatch for\n * targeting a specific location (e.g. the committed `<repo>/governance/...`\n * ledger the promotion gate reads, or a co-located/CI path).\n */\nexport const VOTE_RECORDS_PATH_ENV = 'NEXUS_VOTE_RECORDS_PATH';\n\n/** Max proposal chars retained in the human record (full text is hashed). */\nconst MAX_PROPOSAL_RECORD_CHARS = 500;\n\n/**\n * Actionable message for a write FAILURE (#3991). Since the runtime path now\n * routes through {@link nexusDataPath} it essentially always resolves; the\n * remaining failure mode is an unwritable data dir. Exported so the\n * `consensus_vote` result note can reuse the EXACT guidance the server WARN logs\n * — one source of truth. (Pre-#3991 this covered a no-repo-root skip; that case\n * no longer exists because the resolver always returns a path.)\n */\nexport function voteRecordWriteFailedMessage(path: string): string {\n return (\n 'Authentic vote record NOT persisted: the resolved data directory is not ' +\n `writable (${path}). Check filesystem permissions on the .nexus-agents data ` +\n `dir, or set ${VOTE_RECORDS_PATH_ENV} to a writable absolute file path. See ` +\n 'server logs for the underlying filesystem error.'\n );\n}\n\n/**\n * Map a consensus outcome to the recorded decision vocabulary. Mirrors the MCP\n * response's `buildResponse` so the persisted record and the response never\n * disagree (#4053): an error-policy short-circuit (`errorVoided`) or an\n * all-error / no-quorum void is `no_quorum`, not a genuine `rejected`.\n */\nfunction outcomeToDecision(\n result: ConsensusResult,\n votes: readonly AgentVoteResult[],\n errorVoided: boolean\n): VoteRecord['decision'] {\n if (result.outcome === 'approved') return 'approved';\n const errorCount = votes.filter((v) => v.source === 'error').length;\n const allErrors = errorCount === votes.length && errorCount > 0;\n if (errorVoided || (!result.quorumReached && allErrors)) return 'no_quorum';\n return 'rejected';\n}\n\n/** Build the per-voter summary from the (real) agent votes, skipping errors. */\nfunction toVoterSummaries(votes: readonly AgentVoteResult[]): VoterSummary[] {\n const summaries: VoterSummary[] = [];\n for (const v of votes) {\n if (v.source === 'error') continue;\n const vote: Vote = v.vote;\n summaries.push({ role: v.role, decision: vote.decision, confidence: vote.confidence });\n }\n return summaries;\n}\n\n/** Inputs for {@link buildVoteRecord} — the finalized vote data. */\nexport interface BuildVoteRecordInput {\n readonly id: string;\n readonly proposal: string;\n readonly strategy: VoteRecord['strategy'];\n readonly result: ConsensusResult;\n readonly votes: readonly AgentVoteResult[];\n /** #4053: vote voided by an error-policy short-circuit → record `no_quorum`. */\n readonly errorVoided?: boolean | undefined;\n readonly correlationId?: string | undefined;\n readonly recordedAt?: string | undefined;\n /**\n * The loop/strategy subject this vote RATIFIES (#3927 item 1). Set ONLY for a\n * ratification vote that backs an authority-tier promotion; bound into the\n * self-hash so the gate can trust it. Omitted on an ordinary vote.\n */\n readonly ratifies?: string | undefined;\n /**\n * Monotonic sequence number for this record (#3927). Defaults to 0 (first\n * record) when omitted; the producer ({@link persistVoteRecord}) supplies\n * (max existing sequence)+1.\n */\n readonly sequence?: number | undefined;\n /**\n * Advisory tip hash (audit texture only). NOT covered by the self-hash and\n * NOT verified — retained so a reviewer can see the write-time tip (#3927).\n */\n readonly previousHash?: string | undefined;\n}\n\n/**\n * Construct a fully self-hashed {@link VoteRecord} from a completed vote. Pure\n * (no I/O) so it is unit-testable and reusable by the gate seam. The self-hash\n * covers `sequence` but EXCLUDES `previousHash`, so the record is\n * position-independent (#3927). The proposal is hashed in full but stored\n * truncated.\n */\nexport function buildVoteRecord(input: BuildVoteRecordInput): VoteRecord {\n const proposalTruncated =\n input.proposal.length > MAX_PROPOSAL_RECORD_CHARS\n ? input.proposal.slice(0, MAX_PROPOSAL_RECORD_CHARS) + '...'\n : input.proposal;\n const payload: Omit<VoteRecord, 'hash'> = {\n version: '1.2',\n id: input.id,\n sequence: input.sequence ?? 0,\n recordedAt: input.recordedAt ?? new Date().toISOString(),\n proposalHash: hashProposal(input.proposal),\n proposal: proposalTruncated,\n strategy: input.strategy,\n decision: outcomeToDecision(input.result, input.votes, input.errorVoided ?? false),\n approvalPercentage: input.result.approvalPercentage,\n voteCounts: {\n approve: input.result.voteCounts.approve,\n reject: input.result.voteCounts.reject,\n abstain: input.result.voteCounts.abstain,\n total: input.result.voteCounts.total,\n },\n voters: toVoterSummaries(input.votes),\n ...(input.correlationId !== undefined ? { correlationId: input.correlationId } : {}),\n ...(input.ratifies !== undefined ? { ratifies: input.ratifies } : {}),\n ...(input.previousHash !== undefined ? { previousHash: input.previousHash } : {}),\n };\n return { ...payload, hash: computeVoteRecordHash(payload) };\n}\n\n/**\n * Read the current ledger tip (#3927): the max existing `sequence` (so the next\n * record gets max+1) and the last line's hash (advisory `previousHash` for audit\n * texture only). Returns `{ maxSequence: -1, lastHash: undefined }` for an empty\n * or unreadable file, so the first record lands at sequence 0.\n */\nfunction readLedgerTip(\n filePath: string,\n logger: ILogger\n): { maxSequence: number; lastHash: string | undefined } {\n if (!existsSync(filePath)) return { maxSequence: -1, lastHash: undefined };\n try {\n const { records } = readVoteRecords(filePath);\n if (records.length === 0) return { maxSequence: -1, lastHash: undefined };\n let maxSequence = -1;\n for (const record of records) {\n if (record.sequence > maxSequence) maxSequence = record.sequence;\n }\n const last = records[records.length - 1];\n return { maxSequence, lastHash: last?.hash };\n } catch (error: unknown) {\n logger.warn('Failed to read vote-record ledger tip', { error: getErrorMessage(error) });\n return { maxSequence: -1, lastHash: undefined };\n }\n}\n\n/**\n * Fail-closed path-traversal guard (#3991 security condition, 7-0 vote). Returns\n * `true` iff `target` resolves to an absolute path under `root` (or equal to it)\n * with no `..` segment escaping it. Both inputs are `resolve`d first so a\n * `..` embedded in the override (e.g. `<root>/../../etc/x`) is normalized and\n * caught: if the relative path from `root` to `target` starts with `..` (or is\n * itself absolute on a different volume), the target escaped and we reject.\n */\nfunction isWithin(root: string, target: string): boolean {\n const resolvedRoot = resolve(root);\n const resolvedTarget = resolve(target);\n if (resolvedTarget === resolvedRoot) return true;\n const rel = relative(resolvedRoot, resolvedTarget);\n return rel !== '' && !rel.startsWith('..') && !isAbsolute(rel);\n}\n\n/**\n * Resolve the RUNTIME vote-records ledger path (#3991, design vote 7-0). Routes\n * through the canonical {@link nexusDataPath} resolver so it supports sandbox and\n * global-install layouts and always has a writable home. Precedence:\n *\n * 1. {@link VOTE_RECORDS_PATH_ENV} (`NEXUS_VOTE_RECORDS_PATH`) when set\n * non-empty — resolved to an absolute path (an already-absolute value is\n * returned unchanged; a RELATIVE value is resolved against `process.cwd()`,\n * #3963). This is the explicit escape hatch and the ONLY way to target the\n * committed `<repo>/governance/vote-records.jsonl` ledger. The resolved\n * override is path-traversal validated against its own join base\n * (fail-closed): a relative override that escapes cwd via `..` is rejected.\n * 2. otherwise `nexusDataPath('governance', 'vote-records.jsonl')` →\n * a sandbox / repo-preferred / homedir `.nexus-agents/governance/` location.\n * Validated to stay within the resolved data root (fail-closed).\n *\n * Returns `undefined` only on a genuine resolver failure or a fail-closed\n * traversal rejection — NOT for the former \"no repo root\" case, which no longer\n * exists (#3991). The caller treats `undefined` as a write-failed/skip and\n * surfaces an actionable note. A whitespace-only override is treated as unset.\n */\nexport function resolveVoteRecordsPath(): string | undefined {\n const envPath = process.env[VOTE_RECORDS_PATH_ENV];\n if (envPath !== undefined && envPath.trim() !== '') {\n // Honor the absolute-path contract: a relative override is resolved against\n // process.cwd() rather than written verbatim (#3963). isAbsolute short-\n // circuits the common already-absolute case to a no-op for clarity.\n const resolved = isAbsolute(envPath) ? envPath : resolve(envPath);\n // Path-traversal validation (#3991): a relative override must not escape the\n // cwd it is joined against via `..`. An absolute override is the operator's\n // explicit choice (e.g. the committed governance ledger) and is honored as-is\n // — there is no enclosing data root to validate it against.\n if (!isAbsolute(envPath) && !isWithin(process.cwd(), resolved)) {\n return undefined;\n }\n return resolved;\n }\n // Canonical resolver: handles sandbox, repo-preferred, and homedir layouts.\n // nexusDataPath may root the result under the homedir/sandbox data dir OR,\n // when `governance` routes per-repo (NEXUS_REPO_PREFERRED), under\n // `<repo>/.nexus-agents` — so the base differs by layout.\n const resolved = nexusDataPath(VOTE_RECORDS_DATA_CATEGORY, VOTE_RECORDS_FILENAME);\n // Defense-in-depth (#3991): nexusDataPath joins a FIXED category + filename\n // (no caller/user input) so traversal is structurally impossible. But fail\n // closed against a future resolver regression: the result must be absolute,\n // end with the expected `governance/<file>` suffix, and live under a\n // recognized `.nexus-agents` data root — either the homedir/sandbox data dir\n // or, when `governance` routes per-repo, a `<repo>/.nexus-agents/governance/`\n // location (the base differs by layout, so we accept either).\n const expectedSuffix = `${VOTE_RECORDS_DATA_CATEGORY}${sep}${VOTE_RECORDS_FILENAME}`;\n const underHomedirRoot = isWithin(getNexusDataDir(), resolved);\n const underRepoDataDir = resolved.includes(\n `.nexus-agents${sep}${VOTE_RECORDS_DATA_CATEGORY}${sep}`\n );\n if (\n !isAbsolute(resolved) ||\n !resolved.endsWith(expectedSuffix) ||\n !(underHomedirRoot || underRepoDataDir)\n ) {\n return undefined;\n }\n return resolved;\n}\n\n/** Options for {@link persistVoteRecord}. `sequence`/`previousHash` are assigned by the store. */\nexport interface PersistVoteRecordOptions extends Omit<\n BuildVoteRecordInput,\n 'previousHash' | 'sequence'\n> {\n /**\n * Override the artifact path; takes precedence over {@link VOTE_RECORDS_PATH_ENV}\n * and the {@link nexusDataPath} resolution (see {@link resolveVoteRecordsPath}).\n */\n readonly filePath?: string | undefined;\n readonly logger?: ILogger | undefined;\n}\n\n/**\n * Persist an authentic vote record at vote time. Best-effort and append-only:\n * reads the ledger tip (max sequence + advisory last hash), assigns the next\n * monotonic `sequence`, builds a self-hashed record, and appends one JSON line.\n * Returns the written record (or undefined when the path could not be resolved /\n * the write failed) — persistence never throws into the vote path (an audit sink\n * must not break the operation it observes).\n *\n * RUNTIME LEDGER (#3991, design vote 7-0): the default path now routes through\n * {@link nexusDataPath} under `governance/`, so it essentially always resolves to\n * a writable `.nexus-agents/governance/` location (sandbox / repo-preferred /\n * homedir) and the server-side write essentially always succeeds. The committed\n * `<repo>/governance/vote-records.jsonl` ledger the promotion gate (#3895) reads\n * is a SEPARATE caller-commits artifact (deferred), reached only via the\n * {@link VOTE_RECORDS_PATH_ENV} override.\n *\n * Path precedence: `opts.filePath` > {@link VOTE_RECORDS_PATH_ENV} >\n * `nexusDataPath('governance', 'vote-records.jsonl')`.\n */\nexport function persistVoteRecord(opts: PersistVoteRecordOptions): VoteRecord | undefined {\n const logger = opts.logger ?? createLogger({ component: 'vote-record-store' });\n const filePath = opts.filePath ?? resolveVoteRecordsPath();\n if (filePath === undefined) {\n // Post-#3991 this is rare: the canonical resolver almost always returns a\n // path. It happens only on a fail-closed traversal rejection or resolver\n // failure — surface the write-failed guidance rather than the obsolete\n // \"no repo root\" message.\n logger.warn(voteRecordWriteFailedMessage('<unresolved>'), { id: opts.id });\n return undefined;\n }\n try {\n mkdirSync(dirname(filePath), { recursive: true });\n const { maxSequence, lastHash } = readLedgerTip(filePath, logger);\n const record = buildVoteRecord({\n ...opts,\n sequence: maxSequence + 1,\n previousHash: lastHash,\n });\n appendFileSync(filePath, JSON.stringify(record) + '\\n', 'utf-8');\n logger.info('Persisted authentic vote record', {\n id: record.id,\n decision: record.decision,\n path: filePath,\n });\n return record;\n } catch (error: unknown) {\n logger.warn('Failed to persist authentic vote record', {\n error: getErrorMessage(error),\n path: filePath,\n });\n return undefined;\n }\n}\n\n/**\n * Read the persisted vote-record set from disk. The GATE SEAM (#3897): a future\n * `check-authority-tier-drift.ts` revision resolves a `ratificationVoteRef`\n * against these records and rejects a set that fails {@link verifyVoteRecordSet}.\n * File-line order is NOT significant (#3927) — verification treats the records\n * as a set. Returns the parsed records and any line that failed to parse.\n */\nexport function readVoteRecords(filePath: string): {\n readonly records: VoteRecord[];\n readonly invalidLines: number[];\n} {\n if (!existsSync(filePath)) return { records: [], invalidLines: [] };\n return parseVoteRecordsText(readFileSync(filePath, 'utf-8'));\n}\n\n/**\n * Parse JSONL vote-record text into records + the 1-based line numbers that\n * failed to parse/validate. The disk-free core of {@link readVoteRecords}, split\n * out (#3927) so the authority-tier gate (`scripts/check-authority-tier-drift.ts`)\n * can resolve `ratificationVoteRef` against the committed ledger TEXT in a pure,\n * unit-testable path without touching the filesystem. Blank lines are skipped.\n * Order is NOT significant — the set is verified by {@link verifyVoteRecordSet}.\n */\nexport function parseVoteRecordsText(text: string): {\n readonly records: VoteRecord[];\n readonly invalidLines: number[];\n} {\n const records: VoteRecord[] = [];\n const invalidLines: number[] = [];\n const lines = text.split('\\n').filter((l) => l.trim() !== '');\n for (const [i, line] of lines.entries()) {\n try {\n const parsed = VoteRecordSchema.safeParse(JSON.parse(line));\n if (parsed.success) records.push(parsed.data);\n else invalidLines.push(i + 1);\n } catch {\n invalidLines.push(i + 1);\n }\n }\n return { records, invalidLines };\n}\n","/**\n * nexus-agents/audit - Authentic Vote Record (#3897, model revised #3927)\n *\n * A committed, append-only, tamper-EVIDENT record of a completed\n * `consensus_vote`, persisted at vote time so the authority-ladder promotion\n * gate (`scripts/check-authority-tier-drift.ts`, #3895) can rest authenticity\n * on a tamper-evident record set instead of on hand-transcribed YAML.\n *\n * MODEL: TAMPER-EVIDENT RECORD SET + MONOTONIC SEQUENCE (NOT a linear hash\n * chain). #3927 (design vote 7-0, Option B). The original #3897 design was a\n * LINEAR HASH CHAIN: each record's `hash` folded in the prior record's hash, so\n * the order of file lines was load-bearing. That model cannot survive a\n * concurrent-branch git merge — two branches that each append a record from the\n * same tip produce two records claiming the same `previousHash`, and any\n * merge-concatenation breaks the back-link check. The revised model treats the\n * ledger as an UNORDERED SET of self-hashed records plus a monotonic `sequence`\n * number: each record's hash is POSITION-INDEPENDENT (covers `sequence` but NOT\n * `previousHash`), so it is stable across merges and reorders. `previousHash`\n * is retained ADVISORILY for audit texture but does NOT participate in\n * verification. Omission is detected via SEQUENCE GAPS; concurrent forks (two\n * records sharing a sequence) are a BENIGN signal, not a failure.\n *\n * KNOWN GAP IN OMISSION DETECTION (#4011): sequence-gap detection only catches an\n * omission that leaves a HOLE in the `0..maxSeq` run. It does NOT catch the\n * deletion of a FORK PARTNER — when a sequence is shared by ≥2 records and one is\n * removed, the surviving partner still occupies that sequence, so no gap appears\n * and verification still returns `ok`. So a concurrent fork that resolved\n * `approved` + `rejected` can have its `rejected` partner silently dropped. This\n * is consistent with the residual-trust boundary (records are author-typed and\n * NOT yet cryptographically signed — signing is #3927 item 4): a commit-access\n * actor could equally have just never written the rejecting record, so this grants\n * no new capability. Closing it (cross-checking `forks`/`recordCount`, or\n * requiring fork partners to be co-present) is only meaningful once signing raises\n * the overall bar, and folds into #3927 item 4. See the audit-hash-chain threat\n * model for the disclosed boundary.\n *\n * WHY A DEDICATED PAYLOAD-COVERING HASH (and not the audit-event head hash).\n * The audit-event chain (`computeEventHash` in audit-logger.ts) hashes only the\n * stable HEAD fields (id/timestamp/category/action/outcome/actor/previousHash)\n * and intentionally NOT `metadata` — so riding a tier-transition-style metadata\n * payload would leave the vote `decision`/`approvalPercentage` OUTSIDE the\n * hash: an attacker could flip `rejected`→`approved` in the metadata without\n * breaking any hash. That defeats the whole point of #3897. This record instead\n * folds EVERY authenticity-bearing field — the proposal content hash, the\n * decision, the approval percentage, the vote counts, the per-voter summary,\n * and the `sequence` — into the self-hash, so editing any of them is detected\n * as a `hash_mismatch`. This is the tamper-evidence MVP; cryptographic\n * signing/provenance (binding the record to a key) is DEFERRED (#3897 follow-up).\n *\n * NOTE: the separate audit-event/tier-transition chain (`audit-logger.ts`) IS\n * still a real linear hash chain — it has a single-writer runtime and never\n * merges concurrent branches, so the chain model holds there. Only THIS ledger\n * (a multi-branch committable artifact) was converted to a record set.\n *\n * @module audit/vote-record\n */\n\nimport * as crypto from 'node:crypto';\n\nimport { z } from 'zod';\n\n/** Decision an `approved`/`rejected`/`no_quorum` consensus vote resolves to. */\nexport const VoteRecordDecisionSchema = z.enum(['approved', 'rejected', 'no_quorum']);\nexport type VoteRecordDecision = z.infer<typeof VoteRecordDecisionSchema>;\n\n/** Per-voter summary carried in an authentic vote record. */\nexport const VoterSummarySchema = z\n .object({\n role: z.string().min(1).max(100),\n decision: z.enum(['approve', 'reject', 'abstain']),\n confidence: z.number().min(0).max(1),\n })\n .strict();\nexport type VoterSummary = z.infer<typeof VoterSummarySchema>;\n\n/** The vote-count breakdown mirrored from the consensus engine result. */\nexport const VoteRecordCountsSchema = z\n .object({\n approve: z.number().int().nonnegative(),\n reject: z.number().int().nonnegative(),\n abstain: z.number().int().nonnegative(),\n total: z.number().int().nonnegative(),\n })\n .strict();\nexport type VoteRecordCounts = z.infer<typeof VoteRecordCountsSchema>;\n\n/**\n * One authentic, self-hashed vote record. The `hash` covers every authenticity\n * field INCLUDING `sequence` but EXCLUDING `previousHash`, so the record is\n * tamper-EVIDENT and POSITION-INDEPENDENT: any edit to a persisted line is\n * detected by {@link verifyVoteRecordSet} as a `hash_mismatch`, while reordering\n * file lines or merging concurrent branches does NOT break the hash.\n */\nexport const VoteRecordSchema = z\n .object({\n /**\n * Schema version. '1.1' marked the chain→record-set+sequence model (#3927);\n * '1.2' adds the optional `ratifies` subject-binding field (#3927 item 1).\n * Both are accepted — a 1.1 record (no `ratifies`) verifies unchanged because\n * `ratifies` is folded into the self-hash ONLY when present (see\n * {@link computeVoteRecordHash}).\n */\n version: z.enum(['1.1', '1.2']),\n /** Unique record id (also usable as a `ratificationVoteRef`). */\n id: z.string().min(1),\n /**\n * Monotonic sequence number (integer ≥ 0). Assigned as (max existing\n * sequence)+1 at write time. Sorted, the set of sequences must cover\n * 0..maxSeq with no gap (omission detection); DUPLICATE sequences are a\n * benign concurrent-fork signal, not tampering.\n */\n sequence: z.number().int().nonnegative(),\n /** ISO-8601 timestamp the vote was recorded. */\n recordedAt: z.string().min(1),\n /**\n * SHA-256 of the FULL proposal text. The proposal itself is truncated for\n * the human record (`proposal`), but the hash binds the record to the exact\n * proposal voted on — a later edit of `proposal` that changes meaning is\n * detectable by recomputing this hash from the original.\n */\n proposalHash: z.string().length(64),\n /** Truncated proposal text for the human/reviewer record. */\n proposal: z.string(),\n /** The voting strategy used. */\n strategy: z.enum([\n 'simple_majority',\n 'supermajority',\n 'unanimous',\n 'higher_order',\n 'opinion_wise',\n 'proof_of_learning',\n ]),\n /** The resolved decision. */\n decision: VoteRecordDecisionSchema,\n /** Approval fraction as a percentage (0-100). */\n approvalPercentage: z.number().min(0).max(100),\n /** Vote-count breakdown. */\n voteCounts: VoteRecordCountsSchema,\n /** Per-voter {role, decision, confidence} summary. */\n voters: z.array(VoterSummarySchema),\n /** Optional correlation/decision id linking to the cost rollup / trace. */\n correlationId: z.string().min(1).optional(),\n /**\n * The loop/strategy subject this vote RATIFIES (#3927 item 1). Present only on\n * a ratification vote; set at vote time and bound into the self-hash (so it is\n * tamper-evident). The authority-tier promotion gate\n * (`scripts/check-authority-tier-drift.ts`) resolves a transition's\n * `ratificationVoteRef` to a record and requires `ratifies === transition.subject`\n * (with `decision === 'approved'` and `strategy === 'higher_order'`). Absent on\n * an ordinary (non-ratification) vote; a 1.1 record never carries it.\n */\n ratifies: z.string().min(1).optional(),\n /**\n * ADVISORY hash of the tip record at write time (absent for the first).\n * Retained for audit texture but NOT covered by `hash` and NOT verified —\n * the record-set model is position-independent (#3927).\n */\n previousHash: z.string().length(64).optional(),\n /** SHA-256 over every field above EXCEPT `previousHash` (and except `hash`). */\n hash: z.string().length(64),\n })\n .strict();\nexport type VoteRecord = z.infer<typeof VoteRecordSchema>;\n\n/** The payload fields (everything except `hash`) — the self-hash projection. */\ntype VoteRecordPayload = Omit<VoteRecord, 'hash'>;\n\n/**\n * Compute the SHA-256 over the canonical payload projection. Unlike the\n * audit-event head hash, this folds in EVERY authenticity-bearing field (so a\n * flipped `decision` or altered `approvalPercentage` changes the hash — the\n * core #3897 property) AND the monotonic `sequence` (#3927) — but it EXCLUDES\n * `previousHash`, so the hash is position-independent and stable across\n * concurrent-branch merges and file reorders. The projection is built\n * field-by-field (not `JSON.stringify(record)`) so key-order is deterministic\n * regardless of how the object was constructed — and the NESTED objects\n * (`voteCounts` and each `voters[]` element) are likewise rebuilt field-by-field\n * in schema order (#3962). A formatter / `jq -S` / merge tool that reorders the\n * keys of a persisted record must NOT flip a legitimate record to\n * `hash_mismatch`: the hash is independent of key insertion order at every level.\n */\nexport function computeVoteRecordHash(payload: VoteRecordPayload): string {\n const base = {\n version: payload.version,\n id: payload.id,\n sequence: payload.sequence,\n recordedAt: payload.recordedAt,\n proposalHash: payload.proposalHash,\n proposal: payload.proposal,\n strategy: payload.strategy,\n decision: payload.decision,\n approvalPercentage: payload.approvalPercentage,\n // Rebuild voteCounts in schema order (approve, reject, abstain, total) so the\n // hash does not depend on how the nested object's keys were ordered (#3962).\n voteCounts: {\n approve: payload.voteCounts.approve,\n reject: payload.voteCounts.reject,\n abstain: payload.voteCounts.abstain,\n total: payload.voteCounts.total,\n },\n voters: payload.voters.map((v) => ({\n role: v.role,\n decision: v.decision,\n confidence: v.confidence,\n })),\n correlationId: payload.correlationId ?? null,\n };\n // `ratifies` (#3927) is folded in ONLY when present, appended after the stable\n // base fields. This keeps the projection BYTE-IDENTICAL to the pre-1.2 form for\n // any record without it — so every historical 1.1 record (which never carried\n // `ratifies`) re-hashes unchanged (back-compat). It stays fully tamper-evident:\n // adding, removing, or editing `ratifies` on a persisted record flips the hash\n // (an absent field re-hashes one way, a present field the other).\n const canonical = JSON.stringify(\n payload.ratifies !== undefined ? { ...base, ratifies: payload.ratifies } : base\n );\n return crypto.createHash('sha256').update(canonical).digest('hex');\n}\n\n/** SHA-256 of arbitrary text — used for the proposal content hash. */\nexport function hashProposal(proposal: string): string {\n return crypto.createHash('sha256').update(proposal).digest('hex');\n}\n\n/**\n * Discriminated result from {@link verifyVoteRecordSet}. On success it may\n * surface `forks` — the sequence numbers that appear on more than one record\n * (a benign concurrent-branch signal, NOT tampering). On failure it names the\n * tamper/omission signal: `hash_mismatch` (a record's content was edited),\n * `missing_hash` (a record carries no hash), or `sequence_gap` (a record is\n * missing from the 0..maxSeq run — an omission).\n *\n * NOT detected (#4011): the deletion of a fork PARTNER (a record sharing a\n * sequence with a survivor) leaves no gap, so `ok` stays true. Bounded by the\n * residual-trust boundary (author-typed records; signing deferred to #3927 item\n * 4) — see the module header.\n */\nexport type VoteRecordVerification =\n | { ok: true; recordCount: number; forks?: number[] }\n | {\n ok: false;\n reason: 'hash_mismatch' | 'missing_hash' | 'sequence_gap';\n recordIndex: number;\n recordId: string;\n detail: string;\n };\n\n/** Per-record self-hash check; null when the record passes. */\nfunction verifyVoteRecord(record: VoteRecord, index: number): VoteRecordVerification | null {\n if (record.hash.length === 0) {\n return {\n ok: false,\n reason: 'missing_hash',\n recordIndex: index,\n recordId: record.id,\n detail: `record at index ${String(index)} has no hash`,\n };\n }\n const recomputed = computeVoteRecordHash(record);\n if (recomputed !== record.hash) {\n return {\n ok: false,\n reason: 'hash_mismatch',\n recordIndex: index,\n recordId: record.id,\n detail: `record at index ${String(index)} stored hash=${record.hash} does not match recomputed=${recomputed}`,\n };\n }\n return null;\n}\n\n/** Tally of sequence number → how many records carry it, plus the max seen. */\ninterface SequenceCensus {\n readonly counts: ReadonlyMap<number, number>;\n readonly maxSeq: number;\n}\n\n/** Count how many records carry each sequence number and find the max. */\nfunction censusSequences(records: readonly VoteRecord[]): SequenceCensus {\n const counts = new Map<number, number>();\n let maxSeq = 0;\n for (const record of records) {\n counts.set(record.sequence, (counts.get(record.sequence) ?? 0) + 1);\n if (record.sequence > maxSeq) maxSeq = record.sequence;\n }\n return { counts, maxSeq };\n}\n\n/** First missing sequence in `0..maxSeq`, or null when the run is complete. */\nfunction firstSequenceGap({ counts, maxSeq }: SequenceCensus): number | null {\n for (let seq = 0; seq <= maxSeq; seq++) {\n if (!counts.has(seq)) return seq;\n }\n return null;\n}\n\n/** Sequence numbers carried by more than one record (concurrent forks), ascending. */\nfunction forkSequences({ counts }: SequenceCensus): number[] {\n const forks: number[] = [];\n for (const [seq, count] of counts) {\n if (count > 1) forks.push(seq);\n }\n forks.sort((a, b) => a - b);\n return forks;\n}\n\n/**\n * Verify a tamper-evident SET of vote records (#3927). For each record, the\n * self-hash must recompute from its payload (covers `sequence`, excludes\n * `previousHash`). Order of the array does NOT matter — it is a set, not a\n * chain. Semantics:\n *\n * - Any record whose content was edited → `hash_mismatch`. Empty hash →\n * `missing_hash`. Returns the first such record (array-order scan).\n * - The set of sequence numbers, sorted, must cover `0..maxSeq` with no missing\n * value. A GAP (an omitted/deleted record) → `sequence_gap` naming the first\n * missing sequence.\n * - DUPLICATE sequence numbers are a BENIGN concurrent-fork signal (two branches\n * appended from the same tip, then merged): NOT a failure. They are surfaced\n * on the success result as `forks` (the duplicated sequence numbers, ascending).\n *\n * LIMIT (#4011): because a duplicate sequence is benign, deleting ONE partner of a\n * fork leaves the survivor occupying that sequence — no gap, so this returns `ok`.\n * Sequence-gap omission detection therefore does NOT cover a deleted fork partner.\n * This is within the disclosed residual-trust boundary (author-typed records;\n * cryptographic signing is #3927 item 4); callers needing that guarantee must wait\n * for signing, not rely on `verification.ok` alone.\n *\n * An empty set verifies trivially.\n */\nexport function verifyVoteRecordSet(records: readonly VoteRecord[]): VoteRecordVerification {\n // 1) Self-hash every record (order-independent).\n for (let i = 0; i < records.length; i++) {\n const failure = verifyVoteRecord(records[i] as VoteRecord, i);\n if (failure !== null) return failure;\n }\n\n if (records.length === 0) return { ok: true, recordCount: 0 };\n\n // 2) Sequence coverage: 0..maxSeq with no gap (omission); forks are benign.\n const census = censusSequences(records);\n const gap = firstSequenceGap(census);\n if (gap !== null) {\n const anchor = records[0] as VoteRecord;\n return {\n ok: false,\n reason: 'sequence_gap',\n recordIndex: 0,\n recordId: anchor.id,\n detail: `sequence gap: missing sequence ${String(gap)} in run 0..${String(census.maxSeq)}`,\n };\n }\n\n const forks = forkSequences(census);\n return forks.length > 0\n ? { ok: true, recordCount: records.length, forks }\n : { ok: true, recordCount: records.length };\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\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 = TaskOutcomeSchema.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 * 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 } from '../../audit/vote-record.js';\nimport {\n persistVoteRecord,\n resolveVoteRecordsPath,\n voteRecordWriteFailedMessage,\n} from '../../audit/vote-record-store.js';\nimport { getToolMemory } from './tool-memory.js';\nimport {\n getOutcomeStore,\n categorizeOutcomeErrorMessage,\n} from '../../orchestration/outcomes/index.js';\nimport {\n DEFAULT_CLI,\n CLI_NAMES,\n type CliNameLiteral,\n} from '../../config/model-capabilities-types.js';\n\nconst logger = createLogger({ tool: 'consensus-vote' });\n\n/**\n * Records a successful consensus vote to session memory AND outcome store. 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 */\nexport function recordVoteSuccess(\n proposal: string,\n strategy: string,\n outcome: string,\n duration: number,\n votes?: readonly AgentVoteResult[]\n): void {\n const allSimulated =\n votes !== undefined && votes.length > 0 && 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: ${strategy} on \"${proposal.slice(0, 50)}\"`,\n challenges: [],\n durationMs: duration,\n });\n memory.recordLearning({\n pattern: `${strategy} vote → ${outcome}`,\n context: `proposal=\"${proposal.slice(0, 40)}\" duration=${String(duration)}ms`,\n confidence: 0.8,\n source: 'consensus-vote',\n });\n void memory.runPromotionPipeline().catch((error: unknown) => {\n logger.warn('Promotion pipeline failed', { error });\n });\n } catch (error: unknown) {\n logger.warn('Failed to record vote success to memory', { error: getErrorMessage(error) });\n }\n\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 (votes !== undefined) {\n recordVoteOutcomes(votes);\n }\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 * `'all-simulated'` (skipped by design) or `'write-failed'` (the data dir was\n * unwritable, or a fail-closed traversal rejection). Observability only.\n */\nexport type VoteRecordPersistOutcome =\n | { readonly persisted: true; readonly record: VoteRecord }\n | {\n readonly persisted: false;\n readonly reason: 'all-simulated' | 'write-failed';\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 * all-simulated runs (random output must not seed a committed 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 * - `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 */\nexport function recordAuthenticVote(args: {\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 /** #4053: vote voided by an error-policy short-circuit → persist `no_quorum`. */\n errorVoided?: boolean | undefined;\n}): VoteRecordPersistOutcome {\n const allSimulated = args.votes.length > 0 && 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 const record = persistVoteRecord({\n id,\n proposal: args.proposal,\n strategy: toRecordStrategy(args.strategy),\n result: args.result,\n votes: args.votes,\n ...(args.errorVoided !== undefined ? { errorVoided: args.errorVoided } : {}),\n ...(args.correlationId !== undefined ? { correlationId: args.correlationId } : {}),\n ...(args.ratifies !== undefined ? { ratifies: args.ratifies } : {}),\n logger,\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 { persisted: true, record };\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 * Each successful LLM vote contributes a sample to its CLI×category pair.\n * (Issue #1134 — cold start mitigation)\n */\nexport function recordVoteOutcomes(votes: readonly AgentVoteResult[]): 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: CliNameLiteral =\n vote.cli !== undefined && (CLI_NAMES as readonly string[]).includes(vote.cli)\n ? (vote.cli as CliNameLiteral)\n : DEFAULT_CLI;\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 // #2662 — carry the voter role so the stratified outcome report\n // can break consensus results down by role.\n voterRole: vote.role,\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 * 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 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, type ILogger } from '../../core/index.js';\nimport { computeCostUSD } from '../../learning/usage-log.js';\nimport { DecisionCostStore, type DecisionGate } from '../../observability/decision-cost-store.js';\nimport type {\n DecisionBillingMode,\n DecisionCostSummary,\n 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 id (#3855) and, where the adapter reported\n * it, token counts. When tokens are present we derive the api-mode cost via the\n * same registry-backed {@link computeCostUSD} the per-call usage log uses, so a\n * 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.\n */\nexport function votesToCostInputs(votes: readonly AgentVoteResult[]): VoterCostInput[] {\n return votes.map((v) => {\n const hasTokens = v.inputTokens !== undefined || v.outputTokens !== undefined;\n const input: VoterCostInput = {\n role: v.role,\n model: v.model,\n ...(v.inputTokens !== undefined ? { inputTokens: v.inputTokens } : {}),\n ...(v.outputTokens !== undefined ? { outputTokens: v.outputTokens } : {}),\n ...(hasTokens && v.model !== undefined\n ? { costUsd: computeCostUSD(v.model, v.inputTokens ?? 0, v.outputTokens ?? 0) }\n : {}),\n };\n return input;\n });\n}\n\nexport interface RecordDecisionCostOptions {\n /** Stable id for the decision (correlation id / jobId / proposal hash). */\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\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 gate: options.gate,\n voters,\n billingMode,\n timestamp,\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 — runtime safety net for `simulateVotes: true`.\n *\n * Simulated votes are random and exist only for unit tests and demos.\n * If a caller passes `simulateVotes: true` outside a test runner, this module\n * emits a one-shot stderr warning so the misuse cannot be silent.\n * (Source: Issue #2317, #2319)\n *\n * @module mcp/tools/simulation-guard\n */\n\nimport type { ILogger } from '../../core/index.js';\n\nconst WARNED = new Set<string>();\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 * If `simulate` is true and we are not in a test runner, log a one-shot\n * warning per (tool, process) pair via the supplied logger. Returns the\n * `simulate` value unchanged so it can be used inline.\n *\n * Why: `simulateVotes: true` is a unit-test affordance; using it as a\n * fallback when adapters are unavailable produces random \"decisions\" that\n * silently corrupt downstream behavior. A loud warning is the minimum\n * defense; #2319 also stops simulated runs from polluting tool memory.\n */\nexport function warnIfSimulatedOutsideTests(toolName: string, logger: ILogger): void {\n if (isTestRunner()) return;\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 * 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 `mode: '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, readFileSync, readdirSync, writeFileSync, chmodSync } 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-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});\nexport type JobResult = z.infer<typeof JobResultSchema>;\n\n/** Resolve the sidecar path for a given jobId. */\nfunction jobResultPath(jobId: string): string {\n // `jobs/result-<id>.json` — single segment past `jobs/` so\n // `nexusDataPathEnsure` makes the `jobs/` directory and returns\n // the file path.\n return nexusDataPathEnsure('jobs', `result-${jobId}.json`);\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 * 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(jobId: string, toolName: string): void {\n const path = jobResultPath(jobId);\n if (existsSync(path)) {\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 };\n persistJobRecord(path, record);\n logger.debug('Wrote pending job record', { jobId, toolName });\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 */\nexport function writeJobComplete(jobId: string, toolName: string, result: unknown): 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,\n };\n persistJobRecord(jobResultPath(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 */\nexport function writeJobFailed(jobId: string, toolName: string, error: string): 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 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,\n };\n persistJobRecord(jobResultPath(jobId), record);\n logger.debug('Wrote failed job record', { jobId, toolName, error });\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(jobId: string, toolName: string, reason?: string): void {\n const record: JobResult = {\n v: 1,\n jobId,\n toolName,\n status: 'cancelled',\n createdAt: readJobResult(jobId)?.createdAt ?? new Date().toISOString(),\n completedAt: new Date().toISOString(),\n ...(reason !== undefined ? { error: reason } : {}),\n };\n persistJobRecord(jobResultPath(jobId), record);\n logger.debug('Wrote cancelled job record', { jobId, toolName, reason });\n}\n\n/**\n * Read a job-result record. Returns `null` if the jobId is unknown\n * (file doesn't exist) or unreadable (corrupt JSON, schema mismatch).\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 const path = nexusDataPath('jobs', `result-${jobId}.json`);\n if (!existsSync(path)) return 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 * 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}\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 };\n}\n\nexport function listJobs(): JobSummary[] {\n const dir = nexusDataPath('jobs');\n if (!existsSync(dir)) return [];\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 [];\n }\n const summaries: JobSummary[] = [];\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) continue;\n summaries.push(toJobSummary(record));\n }\n // Newest first — matches typical \"what just happened\" discovery flow.\n return summaries.sort((a, b) => b.createdAt.localeCompare(a.createdAt));\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 * 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/** Read + schema-validate an index file. Returns `null` on miss / corruption. */\nfunction 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 * 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 type { ILogger } from '../../core/index.js';\nimport { toolSuccess, toolStructuredError, type ToolResult } from '../tools/tool-result.js';\nimport { writeJobComplete, writeJobFailed, writeJobPending } from './job-result-store.js';\nimport { registerJobAbort, unregisterJobAbort } from './job-abort-registry.js';\nimport { registerIdempotentJob, shortCircuitOrFreshJobId } from './job-idempotency.js';\nimport { release, suggestRetryAfterMs, tryAcquire } from './job-concurrency.js';\nimport { resolveClassGuardMs } from '../../config/timeouts.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, honoring NEXUS_TIMEOUT_MULTIPLIER\n * + the per-class override) bounds it. On expiry the job is recorded as failed\n * with `runaway guard exceeded` and the slot is released by the existing\n * `finally`. This 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/** Sentinel rejection used to distinguish a guard expiry from a body failure. */\nconst ASYNC_JOB_BODY_RUNAWAY_MESSAGE = 'runaway guard exceeded';\n\ninterface GuardHandles {\n /** Resolves only when the guard window elapses (never resolves on clear). */\n readonly expired: Promise<never>;\n /** Cancels the guard + near-timeout timers. */\n readonly clear: () => void;\n}\n\n/**\n * Builds a guard that rejects with the runaway sentinel after `guardMs`, and\n * emits a one-shot near-timeout WARN at {@link ASYNC_JOB_BODY_NEAR_TIMEOUT_THRESHOLD}.\n */\nfunction makeAsyncBodyGuard(\n jobId: string,\n toolName: string,\n guardMs: number,\n logger: ILogger | undefined\n): GuardHandles {\n let guardTimer: ReturnType<typeof setTimeout> | undefined;\n let warnTimer: ReturnType<typeof setTimeout> | undefined;\n const expired = new Promise<never>((_resolve, reject) => {\n 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 guardTimer = setTimeout(() => {\n reject(new Error(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 });\n return {\n expired,\n clear: () => {\n if (guardTimer !== undefined) clearTimeout(guardTimer);\n if (warnTimer !== undefined) clearTimeout(warnTimer);\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 mode: \"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 —\n * thread it into awaited operations to make cancellation actually stop the\n * work. Existing 2-arg callbacks remain valid (the trailing param is\n * ignored). Its resolved value is recorded as the job's `complete` result;\n * a rejection is recorded as `failed`.\n */\n readonly run: (jobId: string, input: I, signal: AbortSignal) => 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\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. `writeJobPending` + `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: pending record + idempotency index entry.\n writeJobPending(jobId, params.toolName);\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 */\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 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 try {\n // Race the body against the runaway-guard. On guard expiry the guard\n // rejects with the sentinel → recorded as failed below. On body settle the\n // guard is cleared so it can never fire afterward.\n const result = await Promise.race([\n params.run(jobId, params.input, controller.signal),\n guard.expired,\n ]);\n writeJobComplete(jobId, params.toolName, result);\n } catch (err: unknown) {\n const errObj = err instanceof Error ? err : new Error(String(err));\n params.logger?.error(`Async ${params.toolName} dispatch failed`, errObj, { jobId });\n writeJobFailed(jobId, params.toolName, errObj.message);\n } finally {\n guard.clear();\n unregisterJobAbort(jobId);\n release(params.toolName);\n }\n}\n"],"mappings":"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","names":["z","logger","logger","resolve","logger","logger","z","z","z","z","z","logger","err","logger","logger","logger","logger","z","logger","z","logger","z","z","appendFileSync","existsSync","mkdirSync","readFileSync","z","logger","existsSync","resolved","mkdirSync","appendFileSync","readFileSync","appendFileSync","readFileSync","writeFileSync","existsSync","logger","existsSync","readFileSync","writeFileSync","appendFileSync","logger","defaultLogger","logger","defaultLogger","logger","logger","existsSync","readFileSync","writeFileSync","z","logger","z","writeFileSync","existsSync","readFileSync","err","createHash","existsSync","readFileSync","writeFileSync","z","logger","z","createHash","existsSync","writeFileSync","readFileSync","err","logger","logger","logger","err","randomUUID","logger","z"]}