nexus-agents 8.53.0 → 8.53.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (25) hide show
  1. package/dist/{chunk-FIBDS4YM.js → chunk-5E6G4ARL.js} +3 -3
  2. package/dist/{chunk-6O5KVUNL.js → chunk-K3MBIJSC.js} +7 -7
  3. package/dist/{chunk-H26BXX5O.js → chunk-SZVDPMLV.js} +30 -14
  4. package/dist/chunk-SZVDPMLV.js.map +1 -0
  5. package/dist/{chunk-MCW5UHLN.js → chunk-VF2J3HSD.js} +2 -2
  6. package/dist/{chunk-G7LI2WHS.js → chunk-VGNESMSQ.js} +2 -2
  7. package/dist/{chunk-R2IUHK5B.js → chunk-YIGNWIG6.js} +2 -2
  8. package/dist/cli.d.ts +1 -1
  9. package/dist/cli.js +7 -7
  10. package/dist/{consensus-vote-DAHMWNUM.js → consensus-vote-KBUR4FJL.js} +4 -4
  11. package/dist/{consensus-vote-types-DHU2Ivac.d.ts → consensus-vote-types-CA7Xuzl3.d.ts} +2 -1
  12. package/dist/{improvement-review-MS3JZEWH.js → improvement-review-SXTHUBQA.js} +4 -4
  13. package/dist/index.d.ts +2 -2
  14. package/dist/index.js +6 -6
  15. package/dist/{setup-data-dir-3FTDURUQ.js → setup-data-dir-2R56FWLS.js} +3 -3
  16. package/package.json +1 -1
  17. package/dist/chunk-H26BXX5O.js.map +0 -1
  18. /package/dist/{chunk-FIBDS4YM.js.map → chunk-5E6G4ARL.js.map} +0 -0
  19. /package/dist/{chunk-6O5KVUNL.js.map → chunk-K3MBIJSC.js.map} +0 -0
  20. /package/dist/{chunk-MCW5UHLN.js.map → chunk-VF2J3HSD.js.map} +0 -0
  21. /package/dist/{chunk-G7LI2WHS.js.map → chunk-VGNESMSQ.js.map} +0 -0
  22. /package/dist/{chunk-R2IUHK5B.js.map → chunk-YIGNWIG6.js.map} +0 -0
  23. /package/dist/{consensus-vote-DAHMWNUM.js.map → consensus-vote-KBUR4FJL.js.map} +0 -0
  24. /package/dist/{improvement-review-MS3JZEWH.js.map → improvement-review-SXTHUBQA.js.map} +0 -0
  25. /package/dist/{setup-data-dir-3FTDURUQ.js.map → setup-data-dir-2R56FWLS.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/mcp/tools/consensus-vote.ts","../src/utils/bounded-artifact.ts","../src/cli/voter-model-overrides.ts","../src/cli/vote-types.ts","../src/cli-adapters/codex-limits.ts","../src/cli/panel-independence.ts","../src/cli/voter-unverifiable.ts","../src/cli/voter-retry.ts","../src/cli/voter-adapter-resolve.ts","../src/cli/voter-prompts.ts","../src/cli/voter-response.ts","../src/consensus/option-tally.ts","../src/cli/voter-execution.ts","../src/cli/voter-agents-deadline.ts","../src/cli/voter-agents.ts","../src/cli/voter-project.ts","../src/mcp/tools/consensus-vote-option-gate.ts","../src/consensus/types-voting-protocol.ts","../src/consensus/types-weighted-voting.ts","../src/consensus/higher-order-types.ts","../src/consensus/higher-order-helpers.ts","../src/consensus/higher-order-voting.ts","../src/consensus/strategies.ts","../src/consensus/result-builder.ts","../src/consensus/helpers.ts","../src/consensus/incremental-quorum.ts","../src/consensus/engine.ts","../src/consensus/quorum-validator.ts","../src/consensus/voting-protocol-helpers.ts","../src/consensus/voting-protocol.ts","../src/agents/collaboration/byzantine-events.ts","../src/consensus/weighted-voting-helpers.ts","../src/consensus/weighted-voting.ts","../src/consensus/subset-independence.ts","../src/consensus/correlation-helpers.ts","../src/consensus/correlation-model-partitions.ts","../src/consensus/correlation-tracker.ts","../src/consensus/correlation-persistence.ts","../src/consensus/correlation-persistence-records.ts","../src/mcp/tools/consensus-vote-types.ts","../src/mcp/tools/consensus-vote-option-detection.ts","../src/mcp/tools/consensus-vote-error-policy.ts","../src/audit/vote-record-store.ts","../src/audit/ledger-append.ts","../src/audit/source-checkout-guard.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/context/structured-task-state.ts","../src/context/structured-task-state-types.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 { boundArtifactForReview, type BoundedArtifact } from '../../utils/bounded-artifact.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 toolSuccessStructured,\n type ToolResult,\n type BaseMcpToolDeps,\n} from './tool-result.js';\nimport type { ConsensusAlgorithm, Vote, ConsensusResult, Proposal } from '../../consensus/types.js';\nimport { SUPERMAJORITY_THRESHOLD } from '../../consensus/types-core.js';\nimport type { VoterRole, AgentVoteResult } from '../../cli/vote-types.js';\nimport { collectRealVotes } from '../../cli/voter-agents.js';\nimport { resolveAndLogVoterProject, type ResolvedVoterProject } from '../../cli/voter-project.js';\nimport { evaluateOptionGate, optionThresholdFor } from './consensus-vote-option-gate.js';\nimport { createConsensusEngine } from '../../consensus/engine.js';\nimport type {\n CorrelationRecordContext,\n HigherOrderVotingResult,\n ICorrelationTracker,\n} from '../../consensus/higher-order-types.js';\nimport { HigherOrderVotingStrategy } from '../../consensus/index.js';\nimport {\n createPersistentCorrelationTracker,\n createPersistedProposal,\n saveCorrelationData,\n} from '../../consensus/correlation-persistence.js';\nimport {\n VotingStrategySchema,\n VoteDecisionStatusSchema,\n ContrarianCheckStatusSchema,\n VoteThresholdSchema,\n ConsensusVoteInputSchema,\n buildResponse,\n getDefaultErrorPolicy,\n isHigherOrderStrategy,\n shouldEscalateLowPosterior,\n resolveVoteDecision,\n toRecordDecision,\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 { checkSimulationAllowed, simulationDeniedResult } from './simulation-guard.js';\nimport { getToolAnnotations } from '../tool-annotations.js';\n// #3045 / epic #2631 Stage 4 — async-mode dispatch + concurrency cap.\n// #3045 / epic #2631 Stage 4 — async-mode dispatch via the shared `runAsJob`\n// helper (#3729).\nimport {\n runAsJob,\n defaultCollisionEnvelope,\n type JobEnvelopeBuilders,\n} from '../jobs/run-as-job.js';\nimport { randomUUID } from 'node:crypto';\nimport type {\n VotingStrategy,\n ConsensusVoteInput,\n ConsensusVoteResponse,\n ContrarianCheckStatus,\n ExtendedVotingResult,\n} from './consensus-vote-types.js';\n\nexport type {\n VotingStrategy,\n ConsensusVoteInput,\n ConsensusVoteResponse,\n ContrarianCheckStatus,\n AgentVoteSummary,\n VoteDecisionStatus,\n HigherOrderMetadata,\n ExtendedVotingResult,\n} from './consensus-vote-types.js';\nexport { VotingStrategySchema, ConsensusVoteInputSchema } from './consensus-vote-types.js';\n\n// --- Correlation Tracker Singleton ---\n//\n// Lifecycle & memory model (documented per #3169):\n// * SCOPE: one process-wide, lazily-created instance shared by every\n// `consensus_vote` call. It accumulates cross-proposal voter agreement so\n// the higher_order strategy can down-weight correlated (redundant) voters.\n// One shared tracker is intentional — correlation signal is only useful\n// pooled across proposals.\n// * PERSISTENCE: backed by `createPersistentCorrelationTracker()`, which\n// hydrates from / appends to the on-disk correlation store, so the signal\n// survives restarts (the in-memory map is a hot cache over that store).\n// * MEMORY BOUND: NOT unbounded. The underlying `CorrelationTracker` is\n// FIFO-bounded by `maxProposals` / `maxObservationsPerAgent` (#521) —\n// oldest proposals are evicted once the cap is hit (eviction is logged at\n// debug in `correlation-tracker.ts`, so memory pressure is observable).\n// * RESET: `resetCorrelationTracker()` drops the instance; the next\n// `getOrCreateCorrelationTracker()` rebuilds it (re-hydrating from disk).\n// Test-isolation only. There is intentionally no per-milestone \"reset\n// between cycles\" coordinator API — eviction already bounds growth, and\n// clearing history mid-run would discard the signal the strategy needs.\nlet persistentCorrelationTracker: ICorrelationTracker | undefined;\n\n/**\n * Gets or creates the process-wide persistent CorrelationTracker (#517).\n * See the lifecycle / memory-bound / reset notes above the declaration (#3169).\n */\nfunction getOrCreateCorrelationTracker(): ICorrelationTracker {\n persistentCorrelationTracker ??= createPersistentCorrelationTracker();\n return persistentCorrelationTracker;\n}\n\n/**\n * Drops the singleton so the next {@link getOrCreateCorrelationTracker} rebuilds\n * it (re-hydrating from the persistent store). Test-isolation only. @internal\n */\nexport function resetCorrelationTracker(): void {\n persistentCorrelationTracker = undefined;\n}\n\n// --- Dependencies ---\nexport interface ConsensusVoteDeps extends BaseMcpToolDeps {\n /** MCP notifier for client-visible logging (Issue #974) */\n notifier?: IMcpNotifier | undefined;\n /**\n * In-process gateway model adapters (#4040). When the server has a configured\n * OpenAI-compatible gateway, voters route through these HTTP adapters instead\n * of shelling out to a CLI subprocess — no per-subprocess key forwarding, and\n * the nested-spawn deadlock (#4033) cannot occur. Omitted ⇒ CLI voter path.\n */\n gatewayAdapters?: readonly IModelAdapter[] | undefined;\n}\n\n// --- Strategy Resolution ---\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 context: CorrelationRecordContext\n): HigherOrderVotingResult | undefined {\n if (!isHigherOrderStrategy(strategy)) return undefined;\n const hovStrategy = new HigherOrderVotingStrategy();\n const tracker = getOrCreateCorrelationTracker();\n tracker.setCurrentModelPins?.(context.modelPins);\n const result = hovStrategy.aggregate(voteMap, tracker);\n logger.info('Higher-Order Voting complete', {\n method: result.method,\n decision: result.decision,\n posteriorApproval: result.posteriorApproval.toFixed(3),\n });\n return result;\n}\n\nfunction buildCorrelationContext(votes: readonly AgentVoteResult[]): CorrelationRecordContext {\n const modelPins = new Map<string, string>();\n const observedModels = new Map<string, string>();\n for (const vote of votes) {\n if (vote.pinnedModel !== undefined) modelPins.set(vote.role, vote.pinnedModel);\n if (vote.model !== undefined) observedModels.set(vote.role, vote.model);\n }\n return { modelPins, observedModels };\n}\n\nfunction recordVotesToTracker(\n votes: readonly AgentVoteResult[],\n outcome: 'approved' | 'rejected',\n logger: ILogger\n): void {\n // #3170: record the REAL (LLM) votes even when the panel is mixed-source,\n // rather than dropping ALL correlation data because one voter simulated/errored.\n // Recording the accurate LLM-only subset beats leaving the matrix permanently stale.\n const llmVotes = votes.filter((v) => v.source === 'llm');\n if (llmVotes.length < votes.length) {\n logger.warn('Recording only LLM votes to correlation tracker; excluding non-LLM votes', {\n recorded: llmVotes.length,\n excluded: votes.length - llmVotes.length,\n });\n }\n if (llmVotes.length === 0) return; // nothing real to record\n const llmVoteMap = new Map<string, Vote>();\n for (const v of llmVotes) llmVoteMap.set(v.role, v.vote);\n const context = buildCorrelationContext(llmVotes);\n\n const tracker = getOrCreateCorrelationTracker();\n const id = `consensus-${String(getTimeProvider().now())}-${getRandomProvider().random().toString(36).slice(2, 9)}`;\n tracker.recordProposalVotes(id, llmVoteMap, outcome, context);\n logger.debug('Recorded votes to tracker', { proposalId: id, outcome });\n\n try {\n const persisted = createPersistedProposal(id, llmVoteMap, outcome, context);\n const saveResult = saveCorrelationData([persisted]);\n if (!saveResult.ok) {\n logger.warn('Failed to persist correlation data', { error: saveResult.error.message });\n }\n } catch (error: unknown) {\n const message = getErrorMessage(error);\n logger.warn('Error persisting correlation data', { error: message });\n }\n}\n\n/** Process votes with cascade detection — extracted for max-lines-per-function (#1765). */\n/**\n * Run the engine + cascade-detection + higher-order voting against\n * already-policy-applied votes (#2630).\n *\n * Callers MUST pass `engineVotes` produced by `applyErrorPolicy` — no\n * filtering on `source` happens inside this function. Cascade-detection\n * counts and the higher-order voteMap are both built directly from\n * `engineVotes`.\n */\nasync function processVotesWithCascade(\n engineVotes: readonly AgentVoteResult[],\n opts: {\n totalRoles: number;\n proposal: string;\n algorithm: ConsensusAlgorithm;\n strategy: VotingStrategy;\n log: ILogger;\n }\n): Promise<{\n engineResult: ConsensusResult;\n voteMap: Map<string, Vote>;\n higherOrderResult: ReturnType<typeof runHigherOrderVoting>;\n outcome: 'approved' | 'rejected';\n cascaded: boolean;\n}> {\n const approvals = engineVotes.filter((v) => v.vote.decision === 'approve').length;\n const rejections = engineVotes.filter((v) => v.vote.decision === 'reject').length;\n const cascadeInfo = detectEarlyCascade(opts.algorithm, approvals, rejections, opts.totalRoles);\n\n if (cascadeInfo.decided) {\n opts.log.info('Vote cascade: outcome decided early', {\n approvals,\n rejections,\n total: opts.totalRoles,\n reason: cascadeInfo.reason,\n });\n }\n\n const engineResult = await processVotesThroughEngine(engineVotes, opts.proposal, opts.algorithm);\n const voteMap = new Map<string, Vote>();\n for (const { role, vote } of engineVotes) voteMap.set(role, vote);\n\n const higherOrderResult = cascadeInfo.decided\n ? undefined\n : runHigherOrderVoting(opts.strategy, voteMap, opts.log, buildCorrelationContext(engineVotes));\n const outcome: 'approved' | 'rejected' =\n engineResult.outcome === 'approved' ? 'approved' : 'rejected';\n\n return { engineResult, voteMap, higherOrderResult, outcome, cascaded: cascadeInfo.decided };\n}\n\n/** Execute a consensus vote with full strategy support. Exported for pipeline DRY (#1694). */\n/** Confidence threshold above which a contrarian rejection triggers escalation (#1799). */\nconst CONTRARIAN_ESCALATION_THRESHOLD = 0.8;\n\n/**\n * Characters of the proposal the contrarian is shown.\n *\n * Unchanged from the value that was inline, so escalation behaviour on\n * ordinary proposals is identical; what changed is that exceeding it is now\n * disclosed to the contrarian rather than silently applied (#5301).\n */\nconst CONTRARIAN_PROPOSAL_BUDGET = 2000;\n\n/** Build the contrarian prompt, carrying the partial-view note when present. */\nfunction buildContrarianPrompt(bounded: BoundedArtifact): string {\n return [\n 'You are a contrarian analyst. Your job is to find reasons this proposal should be REJECTED.',\n 'Look for: YAGNI (not needed), MISALIGNED (wrong tech/architecture), SECURITY_RISK, SCOPE_CREEP.',\n '',\n ...(bounded.note === '' ? [] : [bounded.note, '']),\n `Proposal: ${bounded.text}`,\n '',\n 'If you find a strong reason to reject, respond with JSON:',\n '{\"decision\":\"reject\",\"confidence\":0.0-1.0,\"reasoning\":\"your concern\"}',\n 'If the proposal is sound, respond with:',\n '{\"decision\":\"approve\",\"confidence\":0.0-1.0,\"reasoning\":\"why it is acceptable\"}',\n ].join('\\n');\n}\n\n/**\n * Record that the contrarian saw only part of the proposal.\n *\n * Logged rather than left silent because `shouldEscalate: false` is the same\n * value whether the contrarian read everything or 4% of it, so the envelope\n * alone cannot distinguish them.\n */\nfunction logPartialProposal(bounded: BoundedArtifact, log: ILogger): void {\n if (bounded.bound === undefined) return;\n log.info('Contrarian sees a partial proposal', {\n reviewedChars: bounded.bound.reviewedChars,\n totalChars: bounded.bound.totalChars,\n });\n}\n\n/**\n * Run a single contrarian agent to check for YAGNI/MISALIGNED/SECURITY_RISK\n * (#1799). `errored` (#4132) is true when the contrarian voice could NOT be\n * obtained (import/executeExpert failure, or the expert reported failure) — the\n * absolute_quorum policy routes that to `no_quorum` instead of silently\n * proceeding as if the contrarian approved.\n */\nasync function runContrarianCheck(\n proposal: string,\n log: ILogger\n): Promise<{ shouldEscalate: boolean; reason: string; confidence: number; errored: boolean }> {\n try {\n const { executeExpert } = await import('../../pipeline/expert-bridge.js');\n // #5301: the proposal was cut to 2000 chars with no marker. A `pr_review`\n // proposal carries up to MAX_DIFF_LENGTH = 50_000 bytes of diff, so the\n // contrarian could be deciding whether to escalate having seen ~4% of it —\n // the header region, where a diff is least informative — and returned the\n // same `shouldEscalate: false` it returns after reading the whole thing.\n const bounded = boundArtifactForReview(proposal, CONTRARIAN_PROPOSAL_BUDGET, 'proposal');\n logPartialProposal(bounded, log);\n const result = await executeExpert('architecture', buildContrarianPrompt(bounded));\n // Expert-bridge reported failure — the contrarian voice was NOT obtained.\n if (!result.success) return { shouldEscalate: false, reason: '', confidence: 0, errored: true };\n\n const jsonMatch = result.text.match(/\\{[\\s\\S]*\\}/);\n // The expert responded but emitted no structured concern — treat as \"no\n // escalation\" (it spoke, it just didn't flag a blocker), not an error.\n if (jsonMatch === null)\n return { shouldEscalate: false, reason: '', confidence: 0, errored: false };\n\n const parsed = JSON.parse(jsonMatch[0]) as {\n decision?: string;\n confidence?: number;\n reasoning?: string;\n };\n\n const isRejection = parsed.decision === 'reject';\n const confidence = typeof parsed.confidence === 'number' ? parsed.confidence : 0;\n const reasoning = typeof parsed.reasoning === 'string' ? parsed.reasoning : '';\n\n if (isRejection && confidence >= CONTRARIAN_ESCALATION_THRESHOLD) {\n log.info('Contrarian rejected with high confidence', {\n confidence,\n reasoning: reasoning.slice(0, 200),\n });\n return { shouldEscalate: true, reason: reasoning, confidence, errored: false };\n }\n\n return { shouldEscalate: false, reason: '', confidence, errored: false };\n } catch (error: unknown) {\n // Closes #2952 (medium): pre-fix the bare `catch {}` swallowed\n // `executeExpert` failures, JSON parse errors, and expert-bridge\n // import errors identically — the escalation guardrail silently\n // disabled itself with no log trail. Log + return the default\n // \"no escalation\" envelope so a contrarian-check infrastructure\n // bug is at least visible in operator logs.\n const message = error instanceof Error ? error.message : String(error);\n log.warn('Contrarian check failed; defaulting to no escalation', { error: message });\n // #4132: the contrarian voice was NOT obtained — errored:true so\n // absolute_quorum can degrade to no_quorum instead of silently proceeding.\n return { shouldEscalate: false, reason: '', confidence: 0, errored: true };\n }\n}\n\n/**\n * Build a short-circuit result for the error-policy gate (#2630). Called\n * when the hard floor (>50% errors) trips or `fail_closed` matches.\n * Logs the warning and returns the synthetic `ExtendedVotingResult` that\n * `executeVoting` propagates to the response builder.\n */\nfunction buildPolicyShortCircuitResult(args: {\n input: ConsensusVoteInput;\n strategy: VotingStrategy;\n algorithm: ConsensusAlgorithm;\n roles: readonly VoterRole[];\n votes: readonly AgentVoteResult[];\n 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 // #4132: thread the requested panel shape so the absolute_quorum predicate\n // in buildResponse has PANEL_SIZE + contrarian-presence even on a short-circuit.\n panelSize: args.roles.length,\n contrarianRequested: args.roles.includes('catfish'),\n // #6111: the short-circuit returns before the escalation gate, so the\n // quick-mode contrarian check never ran.\n contrarianCheck: 'skipped',\n // #3124: surface WHY a high-approval result is still 'rejected' so callers\n // don't mistake a fail-closed policy short-circuit for a genuine rejection.\n policyReason: args.reason,\n };\n}\n\n/**\n * Escalation gate for `quickMode` approvals. Two independent triggers, both\n * re-running `executeVoting` with the full voter panel:\n *\n * 1. Posterior-confidence (#3174): for `higher_order`/`opinion_wise`, a borderline\n * Bayesian posterior (below `HIGHER_ORDER_ESCALATION_POSTERIOR_FLOOR`) means the\n * 3-voter quick panel was barely decisive — escalate without spending a\n * contrarian call. Checked first so a borderline posterior short-circuits it.\n * 2. Contrarian agent (#1799): run a single contrarian to catch\n * YAGNI / SECURITY_RISK / SCOPE_CREEP; escalate if it rejects with high\n * confidence.\n *\n * Returns:\n * - `{ escalated }` — a full-panel re-vote result to use instead;\n * - `{ degradeReason }` — (#4132, absolute_quorum only) the contrarian check\n * ERRORED, so the quickMode verdict must degrade to `no_quorum`;\n * - `{}` — no escalation, continue with the quickMode result.\n *\n * Every shape also carries `contrarianCheck` (#6111): what became of the\n * contrarian call itself — `skipped` when this gate returned before making it,\n * `errored` when it was made and the voice was not obtained (under every\n * policy, not only absolute_quorum — the policy decides the verdict, the field\n * reports the check), `ok` when it answered.\n */\nexport async function maybeEscalateContrarian(\n input: ConsensusVoteInput,\n outcome: 'approved' | 'rejected',\n ctx: { 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?: {\n voteTimeoutMs?: number;\n gatewayAdapters?: readonly IModelAdapter[] | undefined;\n /** #5393: stops LAUNCHING un-started voters when `cancel_job` fires. */\n signal?: AbortSignal | undefined;\n /** #6110: already resolved by the outer frame; the re-vote reuses it. */\n project?: ResolvedVoterProject | undefined;\n }\n): Promise<{\n escalated?: ExtendedVotingResult;\n degradeReason?: string;\n contrarianCheck: ContrarianCheckStatus;\n}> {\n if (!input.quickMode || outcome !== 'approved' || input.simulateVotes) {\n return { contrarianCheck: 'skipped' };\n }\n\n if (shouldEscalateLowPosterior(ctx.strategy, outcome, input.quickMode, ctx.posteriorApproval)) {\n logger.warn('Posterior-confidence escalation: re-running with full vote (#3174)', {\n strategy: ctx.strategy,\n posteriorApproval: ctx.posteriorApproval,\n });\n return {\n escalated: await executeVoting({ ...input, quickMode: false }, logger, opts),\n contrarianCheck: 'skipped',\n };\n }\n\n const escalation = await runContrarianCheck(input.proposal, logger);\n const contrarianCheck: ContrarianCheckStatus = escalation.errored ? 'errored' : 'ok';\n // #4132: under absolute_quorum, a contrarian check that ERRORED means the\n // contrarian voice was never heard — that voids the quorum (no_quorum), it is\n // not silently skipped. Only under absolute_quorum; every other policy keeps\n // the pre-#4132 behavior of proceeding with the quickMode result.\n if (escalation.errored && input.errorPolicy === 'absolute_quorum') {\n logger.warn('Contrarian check errored under absolute_quorum — degrading to no_quorum (#4132)');\n return {\n degradeReason: 'no_quorum: re-run — contrarian check errored (absolute_quorum quick-mode)',\n contrarianCheck,\n };\n }\n if (!escalation.shouldEscalate) return { contrarianCheck };\n logger.warn('Contrarian escalation: re-running with full vote', {\n reason: escalation.reason,\n confidence: escalation.confidence,\n });\n return {\n escalated: await executeVoting({ ...input, quickMode: false }, logger, opts),\n contrarianCheck,\n };\n}\n\n/*\n * Top-level voting flow: vote collection → error-policy gate → engine +\n * cascade → contrarian escalation → finalize. Further extraction\n * obscures control flow more than it helps; helpers already extracted\n * are applyErrorPolicy, buildPolicyShortCircuitResult,\n * maybeEscalateContrarian, finalizeVotingResult.\n */\nexport async function executeVoting(\n input: ConsensusVoteInput,\n logger: ILogger,\n opts?: {\n voteTimeoutMs?: number;\n gatewayAdapters?: readonly IModelAdapter[] | undefined;\n /** #5393: stops LAUNCHING un-started voters when `cancel_job` fires. */\n signal?: AbortSignal | undefined;\n /** #6110: set only by the escalation re-vote, which reuses the outer resolution. */\n project?: ResolvedVoterProject | undefined;\n }\n): Promise<ExtendedVotingResult> {\n // #6110: resolve the target project ONCE per vote (the escalation re-vote\n // inherits it through opts) and stamp it on the result next to `decision`.\n const project = opts?.project ?? resolveAndLogVoterProject(input.project, logger);\n const result = await executeVotingInner(input, logger, { ...opts, project });\n result.project = project;\n // An escalated full-panel result was finalized (and recorded) by its recursive\n // executeVoting call. Remember that state so this outer quick-mode frame does\n // not persist the same full-panel proposal twice.\n const correlationAlreadyRecorded = result.decision !== undefined;\n // #4135: stamp the response-layer decision (incl. `no_quorum`) ONCE, using the\n // SAME `resolveVoteDecision` `buildResponse` consumes, so pipeline consumers can\n // honor a quorum void instead of misreading it as a rejection — without\n // recomputing the policy math (DRY; the decision can't diverge). `errorCount`\n // uses the identical definition `buildResponse` uses.\n const errorCount = result.votes.filter((v) => v.source === 'error').length;\n // #4472: when the proposal declared options, the leading option must clear\n // the bar too. Applied BEFORE the decision is stamped so the record and the\n // response both reflect the gated verdict — a veto that only reached the\n // response would leave the audit trail claiming an approval that did not\n // happen. No-op when no options were declared.\n applyOptionGate(input, result);\n result.decision = resolveVoteDecision(input, result, errorCount).decision;\n if (\n !correlationAlreadyRecorded &&\n (result.decision === 'approved' || result.decision === 'rejected')\n ) {\n recordVotesToTracker(result.votes, result.decision, logger);\n }\n return result;\n}\n\n/**\n * Veto an approved verdict whose declared-option split failed its bar.\n *\n * Mutates `result` in place: `executeVoting` owns it and has not yet published\n * it. Only ever flips approved to rejected, never the reverse — and the\n * resulting `decision` must be `rejected`, not `no_quorum` (#4529): the panel\n * convened and disagreed, which is the opposite of a voided vote.\n *\n * Exported for the composition test (#4529): the defect this guards against\n * lives in how this function's output feeds `resolveVoteDecision` on the very\n * next line of `executeVoting`, not in either function alone.\n */\nexport function applyOptionGate(input: ConsensusVoteInput, result: ExtendedVotingResult): void {\n const declaredOptions = input.options;\n if (declaredOptions === undefined || declaredOptions.length === 0) return;\n\n const outcome = evaluateOptionGate(\n result.votes,\n declaredOptions,\n optionThresholdFor(result.strategy, input.threshold),\n result.result.outcome === 'approved'\n );\n\n if (!outcome.vetoed) {\n result.optionGate = outcome.verdict;\n return;\n }\n\n result.result.outcome = 'rejected';\n // #4529: the reason rides on the verdict, NOT on policyReason. policyReason\n // means \"an error policy voided this vote\", and resolveVoteDecision\n // short-circuits any non-undefined value straight to `no_quorum` — so\n // borrowing the field filed a measured split as \"nothing was decided\", and\n // `--on-no-quorum=retry` then re-rolled the panel and discarded the dissent\n // the gate had just detected. Decided by a 7-voter higher_order panel\n // (6 approvers, all selecting this shape).\n result.optionGate =\n outcome.reason !== undefined ? { ...outcome.verdict, reason: outcome.reason } : outcome.verdict;\n}\n\n// eslint-disable-next-line max-lines-per-function -- see block comment above\nasync function executeVotingInner(\n input: ConsensusVoteInput,\n logger: ILogger,\n // Required here, normalized by `executeVoting`. Every `opts.` inside was a\n // branch against the same never-null value; taking the option away at this\n // boundary removes them all rather than adding one more (#5393).\n opts: {\n voteTimeoutMs?: number;\n gatewayAdapters?: readonly IModelAdapter[] | undefined;\n /** #5393: stops LAUNCHING un-started voters when `cancel_job` fires. */\n signal?: AbortSignal | undefined;\n /** #6110: the target project, resolved once by `executeVoting`. */\n project: ResolvedVoterProject;\n }\n): Promise<ExtendedVotingResult> {\n const strategy = resolveStrategy(input);\n const algorithm = strategyToAlgorithm(strategy);\n const roles = getVoterRoles(input.quickMode);\n const startTime = getTimeProvider().now();\n const errorPolicy = input.errorPolicy ?? getDefaultErrorPolicy(strategy);\n\n logger.info('Starting consensus vote', {\n strategy,\n algorithm,\n roleCount: roles.length,\n errorPolicy,\n });\n const votes = await collectRealVotes({\n roles,\n proposal: input.proposal,\n simulate: input.simulateVotes,\n ...(opts.voteTimeoutMs !== undefined && { timeoutMs: opts.voteTimeoutMs }),\n ...(opts.gatewayAdapters !== undefined && { gatewayAdapters: opts.gatewayAdapters }),\n declaredOptions: input.options,\n // #6110: every seat's system prompt names the caller's project.\n project: opts.project.name,\n signal: opts.signal,\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 roles,\n votes,\n errorPolicy,\n reason: policyDecision.reason ?? 'error policy short-circuit',\n startTime,\n logger,\n });\n }\n\n // Check for early cascade and process votes (#1765)\n const { engineResult, higherOrderResult, outcome, cascaded } = await processVotesWithCascade(\n policyDecision.engineVotes,\n {\n totalRoles: roles.length,\n proposal: input.proposal,\n algorithm,\n strategy,\n log: logger,\n }\n );\n\n const escalation = await maybeEscalateContrarian(\n input,\n outcome,\n { strategy, posteriorApproval: higherOrderResult?.posteriorApproval },\n logger,\n opts\n );\n // #6111: an escalated full-panel result reports the quick-mode check that\n // produced it (`ok` when the contrarian triggered the re-vote, `skipped` when\n // the posterior floor pre-empted the call), not the inner frame's `skipped`.\n if (escalation.escalated !== undefined) {\n return { ...escalation.escalated, contrarianCheck: escalation.contrarianCheck };\n }\n\n const finalized = finalizeVotingResult({\n input,\n strategy,\n algorithm,\n roles,\n engineResult,\n higherOrderResult,\n votes,\n outcome,\n cascaded,\n startTime,\n logger,\n });\n // #4132: a contrarian check that errored under absolute_quorum voids the quorum\n // — stamp policyReason so buildResponse's existing ternary downgrades to\n // no_quorum, matching the errored-voter path. (Kept out of finalizeVotingResult\n // to hold executeVoting within its cyclomatic budget.)\n return applyContrarianDegrade(\n { ...finalized, contrarianCheck: escalation.contrarianCheck },\n escalation.degradeReason\n );\n}\n\n/**\n * #4132: stamp the contrarian-check-errored degrade reason onto a finalized\n * result (unless an upstream short-circuit already set one). A no-op when the\n * contrarian check ran cleanly (`degradeReason` undefined).\n */\nfunction applyContrarianDegrade(\n result: ExtendedVotingResult,\n degradeReason: string | undefined\n): ExtendedVotingResult {\n if (degradeReason === undefined || result.policyReason !== undefined) return result;\n return { ...result, policyReason: degradeReason };\n}\n\n/**\n * Run a consensus vote with a plain goal as the proposal, default settings\n * (real voters, default strategy). The strategy executor the unified `run`\n * entry point dispatches to for the `consensus` strategy (#3575). Non-simulated.\n */\nexport async function runConsensusForGoal(\n goal: string,\n logger: ILogger = createLogger({ tool: 'consensus_vote' }),\n gatewayAdapters?: readonly IModelAdapter[]\n): 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 roles: readonly VoterRole[];\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 // #4132: PANEL_SIZE + contrarian-presence for the absolute_quorum predicate.\n panelSize: args.roles.length,\n contrarianRequested: args.roles.includes('catfish'),\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 /**\n * Context from the tool input the record needs but the voting result does\n * not carry. Grouped rather than two more positional params: both answer\n * \"what did the caller declare\", and the sixth positional argument tipped\n * this past the max-params cap.\n */\n declared: { options: readonly string[] | undefined; 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 declaredOptions: declared.options,\n // #4053: an error-policy short-circuit voided the vote → the PERSISTED record\n // must record `no_quorum`, matching the MCP response (not a stale `rejected`).\n errorVoided: result.policyReason !== undefined,\n // #4986: hand over the decision `resolveVoteDecision` already produced\n // (stamped on the result by `executeVoting`). `errorVoided` alone cannot\n // express an absolute_quorum void, whose reason is stamped on the response\n // and never on the result — so the record used to say `approved` for a vote\n // this tool reports as `no_quorum`.\n resolvedDecision: toRecordDecision(result.decision),\n correlationId: decisionId,\n ...(declared.ratifies !== undefined ? { ratifies: declared.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 signal?: AbortSignal\n): Promise<{ ok: true; value: ConsensusVoteResponse } | { ok: false; error: string }> {\n const logger = deps.logger ?? createLogger({ tool: 'consensus_vote' });\n try {\n const result = await executeVoting(args, logger, {\n ...(deps.gatewayAdapters !== undefined && { gatewayAdapters: deps.gatewayAdapters }),\n signal,\n });\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 if (result.decision === undefined) {\n throw new Error('Consensus vote completed without a resolved decision');\n }\n recordVoteSuccess({\n proposal: args.proposal,\n strategy: result.strategy,\n decision: toRecordDecision(result.decision) ?? 'no_quorum',\n durationMs: result.totalTimeMs,\n approvalPercentage: result.result.approvalPercentage,\n votes: result.votes,\n });\n const { costSummary, voteRecord } = recordVoteSideEffects(\n args.proposal,\n result.strategy,\n result,\n logger,\n { options: args.options, ...(args.ratifies !== undefined ? { ratifies: 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 (#5393). This paragraph previously claimed\n * `collectRealVotes` \"honors per-voter signals\" via plumbing from #3038. It did\n * not — the function had no signal parameter at all, so `cancel_job` marked the\n * job cancelled while every remaining voter still ran. The comment describing a\n * capability that did not exist is plausibly why that went unnoticed.\n *\n * What happens now: the signal is threaded to the vote launcher, which checks it\n * after each stagger delay and does NOT launch the voters that have not started,\n * recording them as error results rather than as any decision. Votes already\n * in flight are left to settle — an adapter call is a subprocess or HTTP request\n * whose cost is already incurred, and abandoning it would lose the result\n * without saving the spend. The dispatcher still writes whatever landed, so\n * audit visibility into who voted before the cancel is preserved.\n *\n * Concurrency cap is enforced via `tryAcquire('consensus_vote')`\n * (default 2; voting is 7-fan-out so caps multiply adapter load fast).\n */\n/**\n * Reject when the vote failed, so `runAsJob` records the job `failed` rather\n * than `complete` (#4362). Increment 2 (#4363) folds this fail-closed check into\n * `runAsJob` itself for every caller.\n *\n * Exported so the transform can be asserted without standing up a live voter\n * panel (the success path initializes the whole memory substrate).\n * @internal\n */\nexport async function unwrapVoteOrThrow(\n pending: ReturnType<typeof handleConsensusVote>\n): Promise<Awaited<ReturnType<typeof handleConsensusVote>>> {\n const result = await pending;\n if (!result.ok) throw new Error(result.error);\n return result;\n}\n\nfunction dispatchAsyncConsensusVote(\n deps: ConsensusVoteDeps,\n args: import('./consensus-vote-types.js').ConsensusVoteInput\n): ConsensusVoteToolResponse {\n // #3729: dispatch via the shared `runAsJob` helper — the exact sequence this\n // function used to inline. consensus_vote's only diff is the freshJobId; its\n // pending/busy/replay/collision envelopes are byte-for-byte the helper's\n // ToolResult defaults, so no per-tool `toEnvelope` is needed.\n return runAsJob<\n import('./consensus-vote-types.js').ConsensusVoteInput,\n Awaited<ReturnType<typeof handleConsensusVote>>\n >({\n toolName: 'consensus_vote',\n input: args,\n idempotencyKey: args.idempotencyKey,\n freshJobId: () => `job-vote-${randomUUID()}`,\n // #5066: structured envelopes — this tool declares an outputSchema, and\n // the SDK rejects a non-error result that carries no structured content.\n toEnvelope: ASYNC_ENVELOPES,\n // #4362: `handleConsensusVote`'s `{ ok: false }` used to flow into the job\n // record verbatim, and `runAsJob` records `complete` for anything its `run`\n // callback RESOLVES — so a dead voter panel produced a job a caller polling\n // `get_job_result` read as a success. Reject instead, mirroring the sync\n // sibling's `toolStructuredError` on the same condition.\n // #5393: arity 3. `runAsJob` derives `signalAccepted` from `run.length`, so\n // taking the signal is what makes the job record say cancellation works —\n // the claim follows the capability instead of being asserted separately.\n run: (_jobId, input, signal) => unwrapVoteOrThrow(handleConsensusVote(deps, input, signal)),\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 // #4170: simulateVotes fails CLOSED outside test runners — checked in the\n // sync prelude BEFORE the async runAsJob dispatch so sync and async modes\n // reject identically (no pending envelope for a random panel).\n if (validationResult.data.simulateVotes) {\n const simCheck = checkSimulationAllowed('consensus_vote', ctx.logger);\n if (!simCheck.allowed) return simulationDeniedResult(simCheck.reason);\n }\n const strategy = validationResult.data.strategy ?? 'simple_majority';\n 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/**\n * Async-dispatch envelopes carrying `structuredContent` (#5066).\n *\n * `runAsJob`'s defaults are text-only. Because this tool declares an\n * `outputSchema`, the SDK requires structured content on every non-error\n * result, so every `mode: 'async'` call failed with -32602 — the mode the\n * tool's own description recommends for 7-voter panels.\n */\nconst ASYNC_ENVELOPES: JobEnvelopeBuilders<ToolResult> = {\n pending: (jobId) =>\n toolSuccessStructured({\n status: 'pending',\n jobId,\n pollTool: 'get_job_result',\n note: 'Poll via get_job_result({ jobId }) until status !== \"pending\".',\n }),\n busy: (retryAfterMs, toolName) =>\n toolSuccessStructured({\n status: 'busy',\n retryAfterMs,\n note: `Async-mode concurrency cap reached for ${toolName}. Retry later or use mode: \"sync\".`,\n }),\n replay: (jobId) =>\n toolSuccessStructured({\n status: 'replay',\n jobId,\n pollTool: 'get_job_result',\n note: 'Poll via get_job_result({ jobId }) until status !== \"pending\".',\n }),\n collision: defaultCollisionEnvelope,\n};\n\n/**\n * Output schema for consensus_vote tool (Issue #1117, #1246).\n *\n * Every vote field is optional because this tool has TWO response shapes and\n * `registerTool` takes a `ZodRawShape`, which cannot express a discriminated\n * union (#5066). `status` tells them apart: present means an async-dispatch\n * envelope, absent means a completed vote.\n *\n * What that gives up is requiredness. What it keeps is the guarantee that\n * actually protects the protocol: the SDK validates with\n * `additionalProperties: false`, so an UNDECLARED response field still fails\n * every call — the #5044 regression this schema exists to catch.\n */\nexport const CONSENSUS_VOTE_OUTPUT_SCHEMA = {\n /** Async-dispatch envelope discriminator — absent on a completed vote. */\n status: z.enum(['pending', 'busy', 'replay']).optional(),\n jobId: z.string().max(200).optional(),\n pollTool: z.literal('get_job_result').optional(),\n note: z.string().max(500).optional(),\n retryAfterMs: z.number().optional(),\n proposal: z.string().optional(),\n strategy: VotingStrategySchema.optional(),\n // Reuses the canonical VoteDecisionStatusSchema (single source) — a hand-listed\n // subset here (was ['approved','rejected','no_quorum']) omitted the reachable\n // 'timeout'/'pending' outcomes and made strict clients reject those votes (#4032).\n decision: VoteDecisionStatusSchema.optional(),\n approvalPercentage: z.number().optional(),\n voteCounts: z\n .object({\n approve: z.number(),\n reject: z.number(),\n abstain: z.number(),\n error: z.number(),\n /** #6094: seats that could not read the artifact; always present. */\n unverifiable: z.number(),\n })\n .optional(),\n // #6111: the quick-mode contrarian check is not a seat, so `voteCounts.error`\n // cannot count it. Present on every completed vote (`skipped` when it did not\n // run); optional here only because the async envelope shares this schema.\n contrarianCheck: ContrarianCheckStatusSchema.optional(),\n votes: z\n .array(\n z.object({\n role: z.string().max(100),\n decision: z.enum(['approve', 'reject', 'abstain']),\n confidence: z.number(),\n reasoning: z.string().max(4000),\n simulated: z.boolean(),\n error: z.boolean(),\n /** #6094: present only when the seat could not read the artifact. */\n unverifiable: z.literal(true).optional(),\n modelUsed: z.string().max(100).optional(),\n rejectionCategories: z\n .array(\n z.enum([\n 'YAGNI',\n 'DRY_VIOLATION',\n 'OVER_ENGINEERING',\n 'SCOPE_CREEP',\n 'SECURITY_RISK',\n 'MISALIGNED',\n 'INSUFFICIENT_EVIDENCE',\n ])\n )\n .optional(),\n })\n )\n .optional(),\n threshold: VoteThresholdSchema.optional(),\n durationMs: z.number().optional(),\n simulateVotes: z.boolean().optional(),\n // #6110: the project the panel judged and how the name was decided. Always\n // on the response; optional here like every field, because the async\n // `pending` envelope shares this schema.\n project: z\n .object({\n name: z.string().max(200),\n source: z.enum(['input', 'derived', 'default']),\n })\n .optional(),\n 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().optional(),\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 // #4472: declared-option outcome. Present whenever the proposal declared\n // `options`. `unattributedApprovals` is part of the contract, not telemetry:\n // without it a caller cannot tell a real split from unreadable responses.\n optionOutcome: z\n .object({\n tally: z.array(z.object({ option: z.string(), count: z.number().int().nonnegative() })),\n leadingOption: z.string().optional(),\n leadingShare: z.number().min(0).max(1),\n approverCount: z.number().int().nonnegative(),\n selectedCount: z.number().int().nonnegative(),\n unattributedApprovals: z.number().int().nonnegative(),\n thresholdMet: z.boolean(),\n // #4529: present only on a veto. Declared here because a strict MCP\n // client rejects any property the advertised schema omits — the same\n // drift that made degraded-panel votes unusable before #4032.\n vetoReason: z.string().max(400).optional(),\n })\n .optional(),\n};\n\n/** Advertised MCP input schema for consensus_vote (hoisted to keep the register fn within its line budget). */\n/**\n * The schema advertised to MCP clients.\n *\n * Registered from {@link ConsensusVoteInputSchema}'s shape rather than\n * hand-copied. A subset drifts: `options` shipped internally in #4494 and was\n * unreachable through the tool until someone noticed, and `mode` stayed\n * unadvertised while this tool's own description told callers to pass it —\n * so the documented async path could not be invoked at all (#4969).\n */\nexport const CONSENSUS_VOTE_TOOL_SCHEMA = ConsensusVoteInputSchema.shape;\n\n/** Advertised MCP tool description for consensus_vote. */\nconst CONSENSUS_VOTE_DESCRIPTION =\n 'Execute multi-model consensus voting on a proposal. ' +\n 'Uses 7 roles by default (architect, security, devex, ai_ml, pm, catfish, scope_steward) ' +\n 'or 3 with quickMode (architect, security, scope_steward), voting with configurable strategies. ' +\n 'higher_order does NOT decide the verdict by correlation-aware aggregation (#4701): approve/reject ' +\n 'is a simple tally of the panel, so correlated voters each carry full independent weight. The ' +\n 'Bayesian correlation analysis is computed and feeds contrarian escalation only. Choose it for the ' +\n 'escalation behaviour, not for a weighted verdict. ' +\n \"Supports async 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 'If your proposal asks voters to choose among named alternatives, you MUST pass them in ' +\n '`options` (#4472) — the threshold is then measured over WHICH option won, and the record ' +\n 'carries the per-option tally plus selection coverage. WITHOUT `options` the tally is ' +\n 'approve/reject/abstain only, so every voter who engages returns `approve` and a 6-1 split on ' +\n 'which option persists as 7-0, 100% (#4452).';\n\n/**\n * Registers the consensus_vote tool with the MCP server.\n * Uses createSecureHandler (Issue #531) with timeout protection (Issue #271).\n * @category MCP\n */\nexport function registerConsensusVoteTool(server: McpServer, deps: ConsensusVoteDeps): void {\n const logger = deps.logger ?? createLogger({ tool: 'consensus_vote' });\n const notifier = deps.notifier ?? createMcpNotifier(server);\n const depsWithNotifier = { ...deps, notifier };\n\n const secureHandler = createSecureHandler(createConsensusVoteHandler(depsWithNotifier), {\n toolName: 'consensus_vote',\n rateLimiter: deps.rateLimiter,\n logger,\n });\n\n const timeoutMs = getToolTimeout('consensus_vote', deps.security);\n const wrappedHandler = wrapToolWithTimeout('consensus_vote', secureHandler, {\n timeoutMs,\n logger,\n });\n\n 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 * Bound an artifact to a prompt budget, and disclose the bound.\n *\n * CLAUDE.md: \"A review must consume the artifact, not a description of it. …\n * Bounded reads are legitimate — the Context budget is real and a large diff\n * cannot always be read whole — but the record must then state which portion\n * was reviewed. A partial review honestly labeled is fine; a partial review\n * recorded as complete is the failure.\"\n *\n * The shape follows `mcp/tools/pr-review-diff-budget.ts` (#4140), which\n * established it for `pr_review`: within budget the output is BYTE-IDENTICAL\n * and carries no note, so the ordinary case is unchanged; over budget a visible\n * note rides on the prompt and a machine-readable bound rides on the result.\n *\n * This is the character-oriented sibling of that file-oriented packer. Where a\n * diff can be packed by whole files (so a reviewed file is reviewed\n * completely), a free-text proposal has no such seam and is cut at a character\n * count — which makes disclosure more important, not less, since the cut can\n * land mid-sentence.\n *\n * @module utils/bounded-artifact\n */\n\n/** How much of an artifact a reviewer actually saw. */\nexport interface ArtifactBound {\n /** Characters the reviewer was shown. */\n readonly reviewedChars: number;\n /** Characters in the whole artifact. */\n readonly totalChars: number;\n /** True when the reviewer saw less than the whole artifact. */\n readonly partial: boolean;\n}\n\n/** An artifact bounded for a prompt, with the disclosure that must accompany it. */\nexport interface BoundedArtifact {\n /** The text to embed — the whole artifact when it fit. */\n readonly text: string;\n /** Visible note to place before the artifact; `''` when nothing was cut. */\n readonly note: string;\n /** Machine-readable bound for the record; `undefined` when nothing was cut. */\n readonly bound: ArtifactBound | undefined;\n}\n\n/**\n * Cut `text` to `budget` characters when it exceeds it, and produce the\n * disclosure.\n *\n * `label` names the artifact in the note — a reviewer told \"you are seeing part\n * of it\" needs to know part of what.\n *\n * Pure: no I/O, no model call, no logging.\n */\nexport function boundArtifactForReview(\n text: string,\n budget: number,\n label: string\n): BoundedArtifact {\n if (text.length <= budget) {\n return { text, note: '', bound: undefined };\n }\n return {\n text: text.slice(0, budget),\n note:\n `> NOTE: partial view — you are seeing the first ${String(budget)} of ` +\n `${String(text.length)} characters of the ${label}. Judge only what is shown, ` +\n `and treat insufficient visibility as itself a reason to raise a concern.`,\n bound: { reviewedChars: budget, totalChars: text.length, partial: true },\n };\n}\n","/**\n * 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 * #4135: how the `vote` command maps a `no_quorum` decision — a quorum void\n * (a missing/errored voice under the opt-in `absolute_quorum` error policy, or an\n * error-policy short-circuit), which is DISTINCT from a genuine rejection.\n *\n * - `fail` (default): exit 1, exactly as a rejection would — back-compat.\n * - `exit2`: exit with a distinct code 2 so scripts can tell a quorum void apart\n * from an approval (0) or a rejection (1).\n * - `retry`: re-run the vote ONCE (the plan is fine, a voice was missing); if it\n * still cannot reach quorum, fall back to `fail` (exit 1).\n */\nexport type NoQuorumPolicy = 'fail' | 'exit2' | 'retry';\n\n/**\n * Options for the vote command.\n */\nexport interface VoteCommandOptions {\n readonly proposal: string;\n /**\n * Named alternatives for a multi-option proposal (#4472, #4941).\n *\n * Without these, the record of a three-way decision reads `approved` with a\n * null `optionTally` — it cannot say WHICH option won, which is the point of\n * asking a panel a multi-way question in the first place.\n */\n readonly options?: readonly 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 * #4135: how to map a `no_quorum` decision (a recoverable quorum void, not a\n * rejection). Default `fail` (exit 1) preserves back-compat. See\n * {@link NoQuorumPolicy}.\n */\n readonly onNoQuorum?: NoQuorumPolicy;\n /**\n * #6110: the project the panel judges (maps from `--project`). Replaces\n * `nexus-agents` in every voter's system prompt; derived from the working\n * directory when absent, and the summary discloses which source answered.\n */\n readonly project?: string;\n}\n\n/**\n * Voter agent role definitions.\n *\n * `scope_steward` (#2185) was added 2026-04-25 to address a build-vs-buy\n * blind spot in the original 6-role panel: the panel approved a proposal\n * to build a USB-flasher CLI without flagging that Rufus already solves\n * the problem. The scope-steward role explicitly checks for existing tools\n * + biases toward \"don't build.\"\n */\nexport type VoterRole =\n 'architect' | 'security' | 'devex' | 'ai_ml' | 'pm' | 'catfish' | 'scope_steward';\n\n/**\n * Agent role descriptions for prompt generation.\n */\nexport const VOTER_ROLES: Record<VoterRole, string> = {\n architect: 'Software Architect - evaluates technical design, scalability, and maintainability',\n security:\n 'Security Engineer - evaluates security implications, vulnerabilities, and attack vectors',\n devex: 'Developer Experience - evaluates usability, documentation, and developer workflow',\n ai_ml: 'AI/ML Engineer - evaluates AI/ML aspects, model selection, and learning capabilities',\n pm: 'Product Manager - evaluates business value, user impact, and resource allocation',\n catfish:\n 'Contrarian Analyst - deliberately challenges proposals to prevent agreement bias (arXiv:2505.21503)',\n scope_steward:\n 'Scope Steward - asks whether to build at all; checks existing tools, biases toward kill-the-feature (#2185)',\n};\n\n/**\n * Which evidence classified a seat as `unverifiable` (#6094).\n *\n * - `stderr`: the structured signal — the CLI transport captured a sandbox /\n * shell failure on stderr while serving the completion.\n * - `reasoning`: the fallback — the seat's own reasoning text said it could\n * not read the artifact: the `UNVERIFIABLE:` prefix, or an error string\n * with no recovery asserted (`UNVERIFIABLE_REASONING_RE`, #6104).\n */\nexport type UnverifiableSignal = 'stderr' | 'reasoning';\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 * - 'unverifiable': the seat answered but could not read the artifact\n * (#6094). A DISTINCT value, not a flag on `abstain`, so no aggregation\n * over `vote.decision` can fold it back into the abstain bucket. The\n * `vote.decision` is always `abstain` — an unverifiable seat never carries\n * approve/reject, whatever the model returned.\n */\n readonly source: 'llm' | 'simulation' | 'error' | 'unverifiable';\n /**\n * Present only when `source === 'unverifiable'`: which evidence classified\n * the seat (#6094). Lets an auditor tell a structured stderr signal from the\n * reasoning-text heuristic.\n */\n readonly unverifiableSignal?: UnverifiableSignal | undefined;\n /** CLI that executed this vote (for adaptive routing feedback). */\n readonly cli?: string | undefined;\n /**\n * Which named option this voter chose, when the proposal declared `options`\n * (#4452). Absent on an ordinary yes/no vote.\n *\n * The approve/reject/abstain tally cannot express option choice: on a\n * multi-option proposal every engaged voter returns `approve`, so a real 6-1\n * split records as unanimous. This is what makes the split recoverable\n * without parsing free-text `reasoning`.\n */\n readonly selectedOption?: string | undefined;\n /**\n * True when this vote came from the per-role retry of an errored seat\n * (#5578). A first-attempt vote never carries it.\n *\n * The panel launches once; a voter that errors is dropped, so under\n * `reduce_denominator` its seat silently leaves the denominator and under\n * `absolute_quorum` the whole vote voids and the caller replays all N\n * voters for a single failure. Retrying just the errored roles recovers the\n * seat for one extra call — and this flag is what makes the recovery\n * visible instead of indistinguishable from a clean first attempt.\n */\n readonly retried?: boolean | 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 * Model assigned to this role before execution. Unlike `model`, this stays on\n * the primary assignment when router failover serves the vote elsewhere.\n */\n readonly pinnedModel?: 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 /**\n * Input tokens read from an existing prompt cache, when the adapter\n * reported them (#4435). Separate from {@link inputTokens} because cache\n * reads bill at roughly a tenth of the uncached rate.\n */\n readonly cachedInputTokens?: number | undefined;\n /**\n * Input tokens spent writing the cache, when reported (#4435). Bills at\n * roughly 1.25x the uncached rate — the opposite end from a cache read.\n */\n readonly cacheCreationInputTokens?: 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// @export-no-consumer-yet — see #4555. Its sibling `checkCodexConcurrency` is\n// wired at `cli/voter-agents.ts:307`, but this one needs a *planned nesting\n// depth* and nothing in the tree tracks one: the voter fan-out is flat (voters\n// are leaf calls), and the only other `depth` values are MCTS and\n// reasoning-forest tree depths, which are unrelated concepts. So this was\n// written against information no caller has — wiring it means first\n// introducing depth tracking through the dispatch path, which is a feature and\n// not a missing line. Marked rather than deleted because the knowledge it\n// encodes (Codex `max_depth=1` rejects a nested spawn) is real and was added\n// deliberately in #2689.\n/**\n * A structured warning when a planned subagent nesting `depth` exceeds\n * Codex's default `max_depth`. Returns `null` when within limits.\n */\nexport function checkCodexDepth(depth: number): string | null {\n if (depth <= CODEX_DEFAULT_MAX_DEPTH) return null;\n return (\n `planned subagent nesting depth ${String(depth)} exceeds Codex's default ` +\n `max_depth=${String(CODEX_DEFAULT_MAX_DEPTH)}. Codex will reject the nested spawn. ` +\n `Raise [agents] max_depth in ~/.codex/config.toml, or flatten the expert chain.`\n );\n}\n","/**\n * Reporting for consensus-panel model independence (#4983).\n *\n * Split from `voter-agents` so the verdict-to-log rendering is testable\n * without standing up a vote, and so the two call sites — assignment time and\n * after the votes are in — render the same verdict the same way.\n *\n * @module cli/panel-independence\n */\n\nimport type { ILogger, IModelAdapter } from '../core/index.js';\nimport { assessPanelIndependence } from '../config/model-equivalence.js';\nimport type { PanelIndependence } from '../config/model-equivalence.js';\nimport type { AgentVoteResult } from './vote-types.js';\n\n/**\n * When the check runs. Adapter detection is lazy (#811), so at `assignment`\n * every CLI adapter still reports a placeholder and an unmeasured verdict is\n * expected. By `post-vote` each has resolved, so unmeasured means the panel\n * finished without anyone being able to say whether its members were\n * independent — which is worth a warning.\n */\nexport type PanelCheckPhase = 'assignment' | 'post-vote';\n\n/**\n * Classifies the panel from its adapters' model ids and logs the verdict.\n *\n * A single-role panel cannot correlate with itself, so nothing is reported.\n */\nexport function reportPanelIndependence(\n adapters: readonly IModelAdapter[],\n roleCount: number,\n phase: PanelCheckPhase,\n logger: ILogger\n): void {\n reportPanelModelIndependence(\n adapters.map((adapter) => adapter.modelId),\n roleCount,\n phase,\n logger\n );\n}\n\n/** Reports independence from the models that successfully returned votes. */\nexport function reportVoteIndependence(results: readonly AgentVoteResult[], logger: ILogger): void {\n const successful = results.filter((result) => result.source === 'llm');\n reportPanelModelIndependence(\n successful.map((result) => result.model),\n successful.length,\n 'post-vote',\n logger\n );\n}\n\n/** Classifies and reports panel independence from observed model provenance. */\nfunction reportPanelModelIndependence(\n modelIds: readonly (string | undefined)[],\n roleCount: number,\n phase: PanelCheckPhase,\n logger: ILogger\n): void {\n if (roleCount <= 1) return;\n const verdict: PanelIndependence = assessPanelIndependence(modelIds);\n\n if (verdict.kind === 'collapsed') {\n logger.warn('Consensus panel ran on ONE model — votes may correlate', {\n model: verdict.model,\n roleCount,\n phase,\n });\n return;\n }\n if (verdict.kind === 'diverse') {\n logger.debug('Consensus panel spans distinct models', {\n distinctModels: verdict.distinct,\n roleCount,\n phase,\n });\n return;\n }\n const context = { unresolved: verdict.unresolved, total: verdict.total, roleCount };\n if (phase === 'post-vote') {\n logger.warn(\n 'Panel independence UNMEASURED after voting — cannot say whether votes correlate',\n context\n );\n return;\n }\n logger.debug(\n 'Panel independence not yet measurable (adapters have not detected their model)',\n context\n );\n}\n","/**\n * A seat that could not read the artifact is `unverifiable` (#6094).\n *\n * Design panel on #6068 (option C, 6 of 6). Before this, a voter whose\n * sandboxed shell failed — `bwrap: loopback: Failed RTM_NEWADDR` on a\n * userns-restricted host — returned a parsed JSON vote and was recorded as an\n * ordinary `abstain` with `source: 'llm'`. The retry path never saw it, the\n * tally could not tell \"read it and abstained\" from \"never saw it\", and one\n * seat voted APPROVE on the proposal text after failing to read\n * (`vote-1789058788915-6lfrbuq`). A record that cannot represent absence\n * launders a blind seat as a considered one — the Mission's p1 class.\n *\n * Classification order: the structured signal first (stderr the CLI transport\n * captured while serving the completion), the reasoning text as a fallback.\n * Regex over prose both misses and false-positives, which is why it is the\n * fallback and why its constant is named — the six real ledger entries in\n * `voter-unverifiable.test.ts` are its regression set.\n *\n * @module cli/voter-unverifiable\n */\n\nimport type { AgentVoteResult, UnverifiableSignal } from './vote-types.js';\n\n/**\n * The structured signal: a sandbox / shell failure on the CLI's stderr. The\n * bubblewrap and landlock strings are what codex emits on a host where\n * `apparmor_restrict_unprivileged_userns=1` (Ubuntu 24.04+ default, #6093).\n */\nexport const UNVERIFIABLE_STDERR_RE =\n /\\bbwrap: |RTM_NEWADDR|\\bsandbox\\b[^\\n]*\\b(?:denied|failed|not permitted)\\b/i;\n\n/**\n * The fallback's error strings: the seat's own reasoning quotes a failed read.\n *\n * Anchored on the concrete phrases the six real ledger entries used. It\n * deliberately does NOT match a bare \"could not read\" — a seat that read the\n * artifact may say a comment \"could not be read easily\" and still have judged\n * the code. Since #6104 a match here is necessary but not sufficient: a seat\n * that quotes the error and then asserts a successful read (`RECOVERY_PHRASE_RE`\n * or `FILE_LINE_CITATION_RE`) keeps its vote. The `UNVERIFIABLE:` prefix the\n * voter prompt asks for is its own rule, `UNVERIFIABLE_PREFIX_RE`, and needs\n * no error string.\n */\nexport const UNVERIFIABLE_REASONING_RE =\n /\\bbwrap: |RTM_NEWADDR|\\b(?:repository|source|shell) (?:reads?|access|execution|inspection) failed\\b|\\bcould not (?:read|inspect) the artifact\\b/i;\n\n/**\n * The prefix `voter-prompts.ts` asks a blind seat to BEGIN its reasoning with.\n * Anchored at the start: a seat that mentions the word mid-sentence is quoting\n * the instruction, not obeying it.\n */\nconst UNVERIFIABLE_PREFIX_RE = /^\\s*UNVERIFIABLE:/i;\n\n/**\n * A `path/file.ext:LINE` citation — the location form the PR-review addendum\n * in `voter-prompts.ts` asks findings to use. A seat that cites a line read\n * the file. Requires a dotted extension before the colon so a clock time, a\n * ratio or a bare SHA does not count.\n */\nconst FILE_LINE_CITATION_RE = /(?:^|[\\s(`'\"])[\\w./-]*[\\w-]+\\.[a-z][a-z\\d]{0,5}:\\d+\\b/i;\n\n/**\n * The recovery phrases a seat writes when a first read failed and a later one\n * did not (#6104). ONE named list: extend it here, never inline. The two\n * strings the #6101 adversarial review executed are the first two rows.\n * Module-private, like the other two guards: behaviour is asserted through\n * `classifyUnverifiable`, so the regexes can change without a consumer.\n */\nconst RECOVERY_PHRASE_RE =\n /\\b(?:retry|second attempt|subsequent attempt|re-?run) succeeded\\b|\\bthen read\\b|\\bwas able to read\\b/i;\n\n/** Which sub-rule of the reasoning fallback fired; reported for the debug log. */\nexport type UnverifiableReasoningRule = 'prefix' | 'error_without_recovery';\n\n/** Evidence available after one completion: the transport's stderr, the parsed reasoning. */\nexport interface UnverifiableEvidence {\n readonly cliStderr?: string | undefined;\n readonly reasoning: string;\n}\n\n/** True when the reasoning asserts a successful read: a recovery phrase or a file:line citation. */\nfunction assertsSuccessfulRead(reasoning: string): boolean {\n return RECOVERY_PHRASE_RE.test(reasoning) || FILE_LINE_CITATION_RE.test(reasoning);\n}\n\n/**\n * Classify a parsed vote as unverifiable, naming which evidence did it, or\n * `undefined` when the seat gave no sign of having failed to read.\n *\n * The stderr signal is primary and unconditional. The reasoning fallback\n * fires on the `UNVERIFIABLE:` prefix, or on an error string only when the\n * reasoning does not also assert a successful read (#6104) — a seat that\n * quotes `bwrap:` and then says the retry succeeded read the artifact, and\n * discarding it was a measured false-positive class. `onReasoningRule`\n * receives the sub-rule that fired so the caller can log it.\n *\n * The empty case is named: no stderr and clean reasoning is a seat that read\n * the artifact, and its decision stands.\n */\nexport function classifyUnverifiable(\n evidence: UnverifiableEvidence,\n onReasoningRule?: (rule: UnverifiableReasoningRule) => void\n): UnverifiableSignal | undefined {\n const stderr = evidence.cliStderr ?? '';\n if (stderr !== '' && UNVERIFIABLE_STDERR_RE.test(stderr)) return 'stderr';\n const { reasoning } = evidence;\n if (UNVERIFIABLE_PREFIX_RE.test(reasoning)) {\n onReasoningRule?.('prefix');\n return 'reasoning';\n }\n if (UNVERIFIABLE_REASONING_RE.test(reasoning) && !assertsSuccessfulRead(reasoning)) {\n onReasoningRule?.('error_without_recovery');\n return 'reasoning';\n }\n return undefined;\n}\n\n/**\n * Re-record a parsed vote as an unverifiable seat.\n *\n * The decision the model returned is DISCARDED (the caller logs it): the seat\n * never carries approve/reject, and never a `selectedOption` — a blind seat\n * cannot have chosen. Confidence is 0 because there is no verdict to be\n * confident in. Everything that IS real provenance — the reasoning text, the\n * model, the CLI, the token counts — is kept.\n */\nexport function markUnverifiable(\n result: AgentVoteResult,\n signal: UnverifiableSignal\n): AgentVoteResult {\n const { selectedOption: _discarded, ...rest } = result;\n return {\n ...rest,\n source: 'unverifiable',\n unverifiableSignal: signal,\n vote: { ...result.vote, decision: 'abstain', confidence: 0 },\n };\n}\n\n/**\n * An absent seat: one that errored, or one that answered without having read\n * the artifact. Both are absences, not judgments — the per-role retry\n * relaunches them and `absolute_quorum` voids on them alike.\n */\nexport function isAbsentSeat(v: Pick<AgentVoteResult, 'source'>): boolean {\n return v.source === 'error' || v.source === 'unverifiable';\n}\n","/**\n * Per-role retry of errored voter seats (#5578).\n *\n * Split out of `voter-agents.ts`, which was already at its 400-line cap.\n * @module cli/voter-retry\n */\n\nimport type { VoterRole, AgentVoteResult } from './vote-types.js';\nimport type { ILogger } from '../core/index.js';\nimport { sleep } from '../utils/async-utils.js';\nimport { isAbsentSeat } from './voter-unverifiable.js';\n\n/**\n * Backoff before retrying an errored voter role (#5578).\n *\n * Short on purpose: a voter at `source: 'error'` has already exhausted the\n * resilient adapter's own retries and breaker, so this is not a backoff for\n * that adapter — it is a gap for a transient panel-wide condition (a rate\n * limit window, a stalled gateway) to clear.\n */\nexport const DEFAULT_ERRORED_ROLE_BACKOFF_MS = 3000;\n\n/**\n * Re-launch ONLY the roles that errored, once, and merge the results (#5578).\n *\n * The panel launches once. A voter that errors is dropped: under\n * `reduce_denominator` its seat silently leaves the denominator, and under\n * `absolute_quorum` the whole vote voids to `no_quorum` and the caller replays\n * all N voters for a single failure. Retrying just the errored roles recovers\n * the seat for one extra call instead of N.\n *\n * The empty case is the common one and is named here: a panel with no errored\n * voter issues no retry and returns its results untouched, so a healthy vote\n * costs exactly what it did before.\n *\n * A role that errors again keeps its first-attempt result, so the existing\n * error policy still sees an errored seat and decides unchanged. This recovers\n * seats; it never manufactures one.\n *\n * An UNVERIFIABLE seat (#6094) is relaunched by the same call: it is an\n * absence, not a judgment. Exactly once — on the deterministic host failure a\n * second attempt is futile, so a retry that comes back unverifiable again\n * REPLACES the first result (marked `retried: true`) rather than looping, and\n * the panel records one entry for the role.\n */\nexport async function retryErroredRoles(\n first: readonly AgentVoteResult[],\n relaunch: (roles: readonly VoterRole[]) => Promise<readonly AgentVoteResult[]>,\n logger: ILogger,\n backoffMs: number\n): Promise<readonly AgentVoteResult[]> {\n const erroredRoles = first.filter(isAbsentSeat).map((v) => v.role);\n if (erroredRoles.length === 0) return first;\n\n logger.warn('Retrying errored or unverifiable voter roles before aggregating (#5578, #6094)', {\n erroredRoles,\n unverifiableRoles: first.filter((v) => v.source === 'unverifiable').map((v) => v.role),\n of: first.length,\n });\n if (backoffMs > 0) await sleep(backoffMs);\n\n const retriedResults = await relaunch(erroredRoles);\n const recovered = new Map<VoterRole, AgentVoteResult>();\n for (const r of retriedResults) {\n if (r.source === 'error') continue;\n recovered.set(r.role, { ...r, retried: true });\n }\n if (recovered.size === 0) {\n logger.warn('Per-role retry recovered no voter — the panel stays degraded', { erroredRoles });\n return first;\n }\n logger.info('Per-role retry recovered voters', {\n recoveredRoles: [...recovered.values()].filter((v) => v.source === 'llm').map((v) => v.role),\n stillUnverifiable: [...recovered.values()]\n .filter((v) => v.source === 'unverifiable')\n .map((v) => v.role),\n stillErrored: erroredRoles.filter((r) => !recovered.has(r)),\n });\n return first.map((v) => recovered.get(v.role) ?? v);\n}\n","/**\n * Adapter resolution for a voter panel, and the documented no-adapter exit\n * (Issue #280): simulate when the caller explicitly allowed it, otherwise\n * throw.\n *\n * Split out of `voter-agents.ts` (#5578), which was at its 400-line cap.\n * @module cli/voter-adapter-resolve\n */\n\nimport type { IModelAdapter, ILogger } from '../core/index.js';\nimport { getErrorMessage } from '../core/index.js';\nimport { getGlobalRegistry } from '../adapters/unified-registry.js';\n\n/** The adapter-bearing subset of the collect options this module needs. */\nexport interface AdapterResolveOptions {\n readonly adapter?: IModelAdapter | undefined;\n readonly gatewayAdapters?: readonly IModelAdapter[] | undefined;\n}\n\n/**\n * Error thrown when no adapter is available and simulation is disabled.\n */\nexport class NoAdapterError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'NoAdapterError';\n }\n}\n\n/**\n * Resolves the model adapter, handling errors per Issue #280.\n */\nexport function resolveAdapter(\n options: AdapterResolveOptions\n): { adapter: IModelAdapter } | { error: string } {\n try {\n if (options.adapter !== undefined) return { adapter: options.adapter };\n // #4040: prefer an in-process gateway adapter as the fallback so a\n // gateway-only environment (no CLIs installed) never hits the CLI registry,\n // which would throw \"No model adapter configured\".\n const gateway = options.gatewayAdapters;\n if (gateway !== undefined && gateway.length > 0 && gateway[0] !== undefined) {\n return { adapter: gateway[0] };\n }\n const registry = getGlobalRegistry();\n return { adapter: registry.getDefault() };\n } catch (error) {\n return { error: getErrorMessage(error) };\n }\n}\n\n/**\n * Resolve the adapter, or take the documented no-adapter exit (Issue #280):\n * simulate when the caller explicitly allowed it, otherwise throw.\n *\n * Extracted from `collectRealVotes` when #5578 pushed it past the 50-line and\n * complexity caps; behaviour is unchanged.\n */\nexport function resolveAdapterOrFail(\n options: AdapterResolveOptions,\n logger: ILogger,\n allowSimulation: boolean\n): { adapter: IModelAdapter } | { simulated: true } {\n const resolved = resolveAdapter(options);\n if (!('error' in resolved)) return resolved;\n\n logger.error('No adapter available for voting', undefined, { error: resolved.error });\n if (allowSimulation) {\n logger.warn('Falling back to simulation (allowSimulation=true)');\n return { simulated: true };\n }\n throw new NoAdapterError(\n `No adapter available for voting: ${resolved.error}. ` +\n 'Install a CLI (claude/gemini/codex) or set ANTHROPIC_API_KEY.'\n );\n}\n","/**\n * nexus-agents/cli - Voter System Prompts\n *\n * Role-specific system prompts for voter agents.\n *\n * @module cli/voter-prompts\n * (Source: Issue #226, extracted from voter-agents.ts for #272)\n */\n\nimport type { VoterRole } from './vote-types.js';\n\n/**\n * Default project name used in voter prompts when no context is provided —\n * this repository's own name. Exported so the resolver in `voter-project.ts`\n * (#6110) falls back to the same literal the prompts are snapshotted against.\n */\nexport const DEFAULT_VOTER_PROJECT = 'nexus-agents';\n\n/**\n * Where a voter is told the target project's governance rules live (#6110).\n *\n * This repository keeps them in `CLAUDE.md`, and the seven default prompts are\n * pinned byte-for-byte to that wording (`voter-prompts-project.test.ts`). A\n * consuming repository may have no such file, so a foreign target gets the\n * neutral phrase instead of a pointer at a file that may not exist.\n */\nfunction governanceRulesRef(project: string): string {\n return project === DEFAULT_VOTER_PROJECT ? 'CLAUDE.md' : \"the target project's governance rules\";\n}\n\n/**\n * Generate voter system prompts with optional project context.\n *\n * When nexus-agents MCP tools are used as a service for other projects,\n * the default \"nexus-agents project\" context causes voters to reject\n * proposals as MISALIGNED. This function allows injecting the target\n * project name so voters evaluate correctly.\n *\n * @param project - Project name/context to inject (defaults to 'nexus-agents')\n */\n/**\n * PR-review-mode addendum (#2244). Appended to every voter's prompt so the\n * format is reinforced at the system-prompt level, where role framing\n * dominates — the proposal-text-only approach in #2238 produced 0 verified\n * findings across 50 voter calls in #2241.\n *\n * The addendum is conditional on its face: voters reviewing a non-diff\n * proposal ignore it. Voters reviewing a diff get the explicit format +\n * few-shot example here, plus the same instructions in the proposal text.\n */\nfunction prReviewModeAddendum(): string {\n return `\nPR-review mode — 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\nIf you cannot read the artifact under review — a shell, sandbox, or repository read fails — answer \"abstain\" and begin your reasoning with \"UNVERIFIABLE: could not read the artifact\"; never vote on the description alone.\n${prReviewModeAddendum()}`;\n}\n\n/** Build the architect role prompt. */\nfunction architectPrompt(project: string): string {\n return `You are a Software Architect voting on technical proposals for the ${project} project.\n\nYour evaluation criteria:\n- Technical design quality and architectural soundness\n- Scalability and performance implications\n- Maintainability and code organization\n- Alignment with existing patterns (Result<T,E>, Zod validation, TypeScript best practices)\n- Integration complexity with current codebase\n${voterFooter()}\n\nBe direct and technical. Focus on structural implications.`;\n}\n\n/** Build the security role prompt. */\nfunction securityPrompt(project: string): string {\n return `You are a Security Engineer voting on proposals for the ${project} project.\n\nYour evaluation criteria:\n- Security vulnerabilities and attack vectors (OWASP Top 10)\n- Input validation and sanitization\n- Secrets management and credential handling\n- Path traversal and injection prevention\n- Rate limiting and resource exhaustion\n${voterFooter()}\n\nBe thorough about risks. Flag any security concerns.`;\n}\n\n/** Build the devex role prompt. */\nfunction devexPrompt(project: string): string {\n return `You are a Developer Experience Engineer voting on proposals for the ${project} project.\n\nYour evaluation criteria:\n- API usability and ergonomics\n- Documentation clarity and completeness\n- Learning curve for new developers\n- Testing and debugging experience\n- CLI/tool integration quality\n${voterFooter()}\n\nFocus on practical developer impact.`;\n}\n\n/** Build the AI/ML role prompt. */\nfunction aiMlPrompt(project: string): string {\n return `You are an AI/ML Engineer voting on proposals for the ${project} project.\n\nYour evaluation criteria:\n- Multi-agent coordination effectiveness\n- Model selection and routing strategies\n- Context management and token efficiency\n- Learning and adaptation capabilities\n- Consensus protocol design\n- Integration with LLM capabilities\n${voterFooter()}\n\nEvaluate AI/ML implications and opportunities.`;\n}\n\n/** Build the PM role prompt. */\nfunction pmPrompt(project: string): string {\n return `You are a Product Manager voting on proposals for the ${project} project.\n\nYour evaluation criteria:\n- Business value and user impact\n- Resource requirements and timeline\n- Risk assessment and mitigation\n- Priority relative to roadmap\n- Success metrics and validation approach\n- Alignment with project goals in ${governanceRulesRef(project)}\n${voterFooter()}\n\nBalance value against effort. Be pragmatic.`;\n}\n\n/** Build the catfish (contrarian) role prompt. */\nfunction catfishPrompt(project: string): string {\n return `You are a Contrarian Analyst (catfish agent) voting on proposals for the ${project} project.\n\nYour role is to prevent false consensus by deliberately challenging proposals.\nBased on research (arXiv:2505.21503), agreement bias in multi-agent voting leads\nto poor decisions when agents rubber-stamp proposals without genuine scrutiny.\n\nYour evaluation criteria:\n- What are the hidden costs, risks, or downsides not mentioned?\n- What assumptions are being made that might be wrong?\n- What alternatives were not considered?\n- What could go wrong in practice vs. theory?\n- Is there scope creep or unnecessary complexity?\n\nWorkflow-test assessment (include in your reasoning):\n- Testability: Is the proposal verifiable, or just theoretical?\n- Workflow integration: Will this actually work in existing pipelines?\n- Incremental verifiability: Can we tell if it's working at each stage?\n\nWhen rejecting, you MUST classify your reasons using categories: YAGNI, DRY_VIOLATION, OVER_ENGINEERING, SCOPE_CREEP, SECURITY_RISK, MISALIGNED, INSUFFICIENT_EVIDENCE.\n\nIf you cannot read the artifact under review — a shell, sandbox, or repository read fails — answer \"abstain\" and begin your reasoning with \"UNVERIFIABLE: could not read the artifact\"; never vote on the description alone.\n\nIMPORTANT: Your job is to find legitimate concerns, not to reject everything.\nIf after genuine scrutiny you find no significant issues, you MAY approve.\nBut your default posture is skeptical — look for what others might miss.\nHigh-confidence rejections with specific reasoning are your most valuable output.\n${prReviewModeAddendum()}`;\n}\n\n/**\n * Build the scope_steward role prompt (#2185).\n *\n * Different axis from `pm` (which prioritizes WHICH features to build) and\n * `catfish` (which doubts the framing). The steward asks: should we build\n * this AT ALL? Existing tools usually win; default bias is \"don't ship.\"\n */\n/**\n * Reuse-ladder check for the scope_steward (#4007, ponytail-inspired). Gates the\n * SIZE of a justified build by altitude — stop at the first rung that holds —\n * while hard-fencing the safety concerns that are never the thing cut. Hoisted to\n * module scope to keep {@link scopeStewardPrompt} within its line budget. Rung 3\n * names the target project (#6110): the default renders the pre-#6110 text.\n */\nfunction reuseLadderCheck(project: string): string {\n return `6. **Reuse ladder (implementation altitude).** When building IS justified,\n gate the SIZE of the build: stop at the first rung that holds, and say\n which one.\n 1. Does this need to exist at all? → no: skip it (YAGNI).\n 2. Standard library / language built-in? → use it.\n 3. Native platform feature or an existing ${project} substrate\n primitive (a canonical-path module, an existing voter/pipeline/\n store)? → use it.\n 4. An already-installed dependency? → use it.\n 5. One line? → one line.\n 6. Only then: the minimum that works.\n Lazy, NOT negligent — trust-boundary validation, error handling, security,\n and accessibility are NEVER the thing cut. The code is small because it is\n necessary, not golfed. Flag a proposal that reaches for rung 6 when an\n earlier rung holds as OVER_ENGINEERING.`;\n}\n\nfunction scopeStewardPrompt(project: string): string {\n return `You are a Scope Steward voting on proposals for the ${project} project.\n\nYour job is to gate against build-when-buy-would-do and feature sprawl.\nThe originating case (2026-04-24): a 6-role panel approved building a USB flasher\nCLI without anyone flagging that Rufus already solves the problem better, for the\nsame audience, with 100M+ installs of battle-tested code. This role exists to\ncatch that class of mistake.\n\nYour evaluation criteria — work through these mandatory checks in your reasoning:\n\n1. **Existing-tool check.** Search your knowledge for tools, libraries, or\n services that already solve the stated problem. Name them concretely\n (not \"there might be alternatives\" — actual names: Rufus, ripgrep,\n esbuild, etc.). If you can't name an alternative, say so explicitly.\n\n2. **Build-vs-buy math.** For each existing tool you named: what would we\n LOSE by adopting it (license, dependency surface, integration cost)?\n What would we GAIN by building our own (tighter integration, no extra\n binary, etc.)? Default lean: BUY. Building is justified only when the\n loss column is concrete and the gain column is load-bearing.\n\n3. **Mission alignment.** Does this proposal serve the project's stated\n mission, or is it scope drift? If drift, name the drift specifically.\n\n4. **Kill-the-feature option.** For every proposal, explicitly evaluate\n \"what if we just didn't do this?\" as a ranked option. Many proposals\n don't need to be built. Make the no-build case before the build case.\n\n5. **Sprawl audit.** Check whether similar functionality already exists\n in the codebase. If it does, recommend extending — not forking. The\n anti-sprawl policy in ${governanceRulesRef(project)} is specifically the rule this role\n enforces.\n\n${reuseLadderCheck(project)}\n\nDefault bias: REJECT proposals where an existing tool fits, even if our\nown implementation would be marginally nicer. Only approve when the\nexisting-tool check fails AND the kill-the-feature option is worse AND\nmission alignment is clear AND no comparable in-codebase functionality\nexists.\n\nFew-shot example of a textbook rejection:\n> Proposal: \"Add an aegis-boot subcommand to flash bootable USB sticks.\"\n> Steward response: \"REJECT (DON'T-BUILD). Rufus has solved this for the\n> same audience for 10+ years with 100M+ installs and battle-tested code.\n> Adopting Rufus loses nothing material; building our own loses\n> maintenance bandwidth indefinitely. Mission alignment: aegis-boot's\n> mission is verifiable boot, not USB tooling. Kill option clearly wins.\n> No prior in-codebase functionality. Recommend: point users at Rufus in\n> the docs and stop here.\"\n\n${voterFooter()}\n\nWhen rejecting, you MUST classify reasons (YAGNI, DRY_VIOLATION,\nOVER_ENGINEERING, SCOPE_CREEP, MISALIGNED). The steward's most common\ncategories are SCOPE_CREEP, YAGNI, and OVER_ENGINEERING.\n\nYou CAN approve. But your default posture is: \"this should not be built;\nprove me wrong with the build-vs-buy math.\"`;\n}\n\nexport function getVoterPrompts(\n project: string = DEFAULT_VOTER_PROJECT\n): Record<VoterRole, string> {\n return {\n architect: architectPrompt(project),\n security: securityPrompt(project),\n devex: devexPrompt(project),\n ai_ml: aiMlPrompt(project),\n pm: pmPrompt(project),\n catfish: catfishPrompt(project),\n scope_steward: scopeStewardPrompt(project),\n };\n}\n\n/**\n * Default prompts (backward compatible — uses 'nexus-agents' project context).\n */\nexport const VOTER_SYSTEM_PROMPTS: Record<VoterRole, string> = getVoterPrompts();\n\n/**\n * Base reasoning templates for simulated votes.\n *\n * scope_steward simulated reasoning intentionally reflects the role's\n * bias-toward-not-shipping posture (PM vote condition on #2185).\n */\nexport const SIMULATED_VOTE_REASONING: Record<VoterRole, string> = {\n architect: 'Evaluated technical design and architecture implications.',\n security: 'Reviewed security considerations and attack surface.',\n devex: 'Assessed developer experience and workflow impact.',\n ai_ml: 'Analyzed AI/ML capabilities and learning potential.',\n pm: 'Evaluated business value and resource requirements.',\n catfish: 'Challenged proposal assumptions and identified potential risks.',\n scope_steward:\n 'Checked existing tools, build-vs-buy math, kill-the-feature option; bias toward not shipping.',\n};\n","/**\n * nexus-agents voter response parsing\n *\n * Schema and parsing utilities for structured vote responses from LLM.\n *\n * (Source: Extracted from voter-agents.ts per Issue #285)\n */\n\nimport { z } from 'zod';\nimport type { Vote } from '../consensus/types.js';\nimport { matchDeclaredOption } from '../consensus/option-tally.js';\nimport type { VoterRole } from './vote-types.js';\nimport { getErrorMessage } from '../core/index.js';\n\n// ============================================================================\n// Error Classes\n// ============================================================================\n\n/**\n * Error thrown when vote response parsing fails.\n * (Source: Issue #512 - Fail-safe voting response parsing)\n *\n * parseVoteResponse always throws this error when JSON parsing or validation\n * fails — voting is fail-closed; no synthetic vote is ever fabricated (#4177\n * removed the opt-in `allowSyntheticVote` escape hatch, which had zero\n * production callers).\n */\nexport class SyntheticVoteError extends Error {\n constructor(\n reason: string,\n public readonly rawOutput: string\n ) {\n super(`Vote response parsing failed: ${reason}`);\n this.name = 'SyntheticVoteError';\n }\n}\n\n/**\n * Vote source tracking - indicates whether vote is real or synthetic.\n * (Source: Issue #512 - Voting integrity)\n */\nexport type ParsedVoteSource = 'parsed' | 'fallback';\n\n/**\n * Extended vote with source tracking.\n */\nexport interface ParsedVote extends Vote {\n readonly source: ParsedVoteSource;\n}\n\n// ============================================================================\n// Structured Vote Response Schema\n// ============================================================================\n\n/**\n * Pre-verified finding shape — voter emits this; downstream\n * `isFindingVerified` adds the derived `verified` flag.\n *\n * #2245 follow-up: voters previously asked to embed YAML findings inside\n * the JSON `reasoning` field. That format is lossy across JSON\n * serialization (backticks/newlines). The v4 retest produced 0 findings\n * across 9 request_changes voters because the LLM either dropped the\n * YAML to keep JSON valid, or produced invalid JSON the parser rejected.\n * Solution: expose findings as a top-level array on the vote response.\n */\nexport const RawFindingSchema = z.object({\n summary: z.string().min(1).max(500).describe('One-line summary of the issue'),\n location: z.string().min(1).max(200).describe('path/file.ext:line'),\n severity: z.enum(['critical', 'high', 'medium', 'low']).default('medium'),\n gate: z.object({\n reread_cited_line: z.enum(['passed', 'failed', 'skipped']).default('skipped'),\n traced_call_path: z.enum(['passed', 'failed', 'skipped']).default('skipped'),\n named_assertion: z\n .string()\n .default('')\n .describe('Concrete failing assertion — substantive, not a rubber-stamp word'),\n ruled_out_language_non_issue: z.enum(['passed', 'failed', 'skipped']).default('skipped'),\n }),\n claim: z.string().min(1).max(2000).describe('What is wrong and why it justifies blocking'),\n});\n\nexport type RawFinding = z.infer<typeof RawFindingSchema>;\n\n/**\n * Zod schema for parsing structured vote responses from LLM.\n */\nexport const VoteResponseSchema = z.object({\n decision: z.enum(['approve', 'reject', 'abstain']).describe('Your vote decision'),\n reasoning: z.string().min(10).max(4000).describe('Explanation for your vote (10-4000 chars)'),\n confidence: z.number().min(0).max(1).describe('Confidence level 0-1'),\n conditions: z.array(z.string()).optional().describe('Optional conditions for approval'),\n /** Structured rejection categories for reject→refine→re-vote loops (Issue #1213). */\n rejectionCategories: z\n .array(\n z.enum([\n 'YAGNI',\n 'DRY_VIOLATION',\n 'OVER_ENGINEERING',\n 'SCOPE_CREEP',\n 'SECURITY_RISK',\n 'MISALIGNED',\n 'INSUFFICIENT_EVIDENCE',\n ])\n )\n .optional()\n .describe('Rejection reason categories when decision is reject'),\n /** Top-level structured findings for PR-review mode (#2245 v4 follow-up).\n * Replaces the YAML-in-reasoning encoding that proved lossy. */\n findings: z.array(RawFindingSchema).optional().describe('Structured findings (PR review only)'),\n /** Chosen option when the proposal declared `options` (#4472). Validated\n * against the declared list by the caller; an unmatched value is dropped\n * rather than recorded, so a parse miss surfaces as absent. */\n selectedOption: z.string().optional().describe('Which declared option you choose'),\n});\n\nexport type VoteResponse = z.infer<typeof VoteResponseSchema>;\n\n/**\n * Hand-authored JSON Schema mirroring {@link VoteResponseSchema} (#3433).\n *\n * Used as the `input_schema` for a forced Claude `tool_use` call so the\n * ClaudeAdapter can honor `responseFormat: { type: 'json_schema' }` for votes.\n * `zod-to-json-schema` is intentionally NOT a dependency — this object is the\n * single source of truth for the JSON-Schema view of a vote response.\n *\n * Drift between this and `VoteResponseSchema` is caught by the contract test\n * in `voter-response.test.ts` (every Zod key must appear here and vice-versa).\n */\nexport const VOTE_JSON_SCHEMA: Record<string, unknown> = {\n type: 'object',\n additionalProperties: false,\n required: ['decision', 'reasoning', 'confidence'],\n properties: {\n decision: {\n type: 'string',\n enum: ['approve', 'reject', 'abstain'],\n description: 'Your vote decision',\n },\n reasoning: {\n type: 'string',\n minLength: 10,\n maxLength: 4000,\n description: 'Explanation for your vote (10-4000 chars)',\n },\n confidence: {\n type: 'number',\n minimum: 0,\n maximum: 1,\n description: 'Confidence level 0-1',\n },\n conditions: {\n type: 'array',\n items: { type: 'string' },\n description: 'Optional conditions for approval',\n },\n // #4472: without this, `additionalProperties: false` makes it impossible\n // for a structured-output voter to emit a selection at all.\n selectedOption: {\n type: 'string',\n description: 'Which declared option you choose (multi-option proposals only)',\n },\n rejectionCategories: {\n type: 'array',\n items: {\n type: 'string',\n enum: [\n 'YAGNI',\n 'DRY_VIOLATION',\n 'OVER_ENGINEERING',\n 'SCOPE_CREEP',\n 'SECURITY_RISK',\n 'MISALIGNED',\n 'INSUFFICIENT_EVIDENCE',\n ],\n },\n description: 'Rejection reason categories when decision is reject',\n },\n findings: {\n type: 'array',\n description: 'Structured findings (PR review only)',\n items: {\n type: 'object',\n additionalProperties: false,\n required: ['summary', 'location', 'severity', 'gate', 'claim'],\n properties: {\n summary: {\n type: 'string',\n minLength: 1,\n maxLength: 500,\n description: 'One-line summary of the issue',\n },\n location: {\n type: 'string',\n minLength: 1,\n maxLength: 200,\n description: 'path/file.ext:line',\n },\n severity: { type: 'string', enum: ['critical', 'high', 'medium', 'low'] },\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, options?: readonly string[]): string {\n return `Evaluate the following proposal and provide your vote.\n\nPROPOSAL:\n${proposal}\n${buildOptionsBlock(options)}\nIn addition to your role-specific criteria, assess these workflow-test dimensions:\n- Testability: Can the proposed changes be verified with automated tests?\n- Workflow integration: Does this fit into existing CI/make/test workflows?\n- Incremental verifiability: Can progress be measured at each step?\n\nRespond with a JSON object containing:\n- decision: \"approve\", \"reject\", or \"abstain\"\n- reasoning: Explanation for your vote (10-4000 characters). Include your workflow-test assessment.\n- confidence: Number between 0 and 1\n- conditions: Optional array of conditions for approval\n- rejectionCategories: Required when rejecting. Array of categories from: YAGNI, DRY_VIOLATION, OVER_ENGINEERING, SCOPE_CREEP, SECURITY_RISK, MISALIGNED, INSUFFICIENT_EVIDENCE\n- findings: PR-REVIEW MODE ONLY. Optional top-level array of structured findings — see \"PR-review mode\" in the system prompt. OMIT this field entirely when reviewing a non-diff proposal or when approving a diff.\n${buildSelectionFieldDoc(options)}\n${VOTE_PROMPT_EXAMPLES}`;\n}\n\n/**\n * The OPTIONS block, present only when the proposal declares options (#4472).\n *\n * Empty string when none are declared, so a proposal without options produces\n * a prompt byte-identical to the pre-#4472 one.\n */\nfunction buildOptionsBlock(options?: readonly string[]): string {\n if (options === undefined || options.length === 0) return '';\n const list = options.map((o) => `- ${o}`).join('\\n');\n return `\nOPTIONS — choose exactly ONE of these and name it verbatim in \\`selectedOption\\`:\n${list}\n`;\n}\n\n/** The `selectedOption` field doc, present only when options are declared. */\nfunction buildSelectionFieldDoc(options?: readonly string[]): string {\n if (options === undefined || options.length === 0) return '';\n return '- selectedOption: REQUIRED. Exactly one option from the OPTIONS list above, copied verbatim. Do not invent an option, combine two, or leave it blank — your selection is what the threshold is measured over.';\n}\n\n// ============================================================================\n// Vote Response Parsing\n// ============================================================================\n\n/**\n * Extract the FIRST balanced top-level JSON object from `text`, respecting\n * string literals + escapes so braces/brackets inside strings don't miscount\n * (#4131). Returns the object substring, or undefined if no `{` is present.\n *\n * If the object is TRUNCATED (containers still open at end-of-input — e.g. a\n * large findings-bearing vote cut off by the completion token cap), it returns a\n * best-effort repair: the open string is closed and the open `{`/`[` containers\n * are closed in order. Since a well-formed vote emits `decision`/`reasoning`/\n * `confidence` before the optional `findings` array, a truncation inside\n * `findings` still yields a parseable verdict. If the repair is still invalid,\n * the caller's JSON.parse throws exactly as before (no regression).\n */\n/** Mutable scan state for {@link extractFirstJsonObject}. */\ninterface JsonScanState {\n readonly closers: string[];\n inString: boolean;\n escaped: boolean;\n}\n\ntype ScanResult = 'complete' | 'unbalanced' | 'continue';\n\n/** Handle one char while inside a JSON string literal. */\nfunction stepInString(state: JsonScanState, ch: string): void {\n if (ch === '\\\\') state.escaped = true;\n else if (ch === '\"') state.inString = false;\n}\n\n/** Handle one structural (non-string) char, tracking open/close containers. */\nfunction stepStructural(state: JsonScanState, ch: string): ScanResult {\n if (ch === '\"') state.inString = true;\n else if (ch === '{') state.closers.push('}');\n else if (ch === '[') state.closers.push(']');\n else if (ch === '}' || ch === ']') {\n if (state.closers.pop() === undefined) return 'unbalanced';\n if (state.closers.length === 0) return 'complete';\n }\n return 'continue';\n}\n\n/** Advance the balanced-object scan by one char. Returns whether the object closed / broke. */\nfunction stepJsonScan(state: JsonScanState, ch: string): ScanResult {\n if (state.escaped) {\n state.escaped = false;\n return 'continue';\n }\n if (state.inString) {\n stepInString(state, ch);\n return 'continue';\n }\n return stepStructural(state, ch);\n}\n\n/** Best-effort close of an object truncated mid-scan (open string + open containers). */\nfunction repairTruncatedObject(fragment: string, state: JsonScanState): string {\n let repaired = state.inString ? `${fragment}\"` : fragment;\n for (let i = state.closers.length - 1; i >= 0; i--) {\n const closer = state.closers[i];\n if (closer !== undefined) repaired += closer;\n }\n return repaired;\n}\n\nfunction extractFirstJsonObject(text: string): string | undefined {\n const start = text.indexOf('{');\n if (start === -1) return undefined;\n const state: JsonScanState = { closers: [], inString: false, escaped: false };\n for (let i = start; i < text.length; i++) {\n const result = stepJsonScan(state, text[i] as string);\n if (result === 'complete') return text.slice(start, i + 1);\n if (result === 'unbalanced') return undefined;\n }\n // Loop ran off the end with containers still open ⇒ truncated; repair best-effort.\n return state.closers.length > 0 ? repairTruncatedObject(text.slice(start), state) : undefined;\n}\n\n/**\n * Extracts the JSON vote object from raw LLM response text (#4131).\n *\n * Robust to the ways a voter's output shape used to silently DROP the voter:\n * 1. Prefer an explicit ` ```json ` fence.\n * 2. Otherwise scan every fenced block and use the first whose content is a\n * JSON object — so a ` ```yaml findings ` block (pr-review mode) is SKIPPED\n * instead of being handed to JSON.parse (the `Unexpected token 'y'` drop).\n * 3. Otherwise take the first balanced JSON object anywhere in the text, so a\n * verdict followed by a trailing prose / YAML block still parses, and a\n * truncated object is repaired.\n * 4. Fallback: the trimmed text (JSON.parse will surface a real malformation).\n */\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/** Caps mirroring {@link VoteResponseSchema} (reasoning) + {@link RawFindingSchema} (claim). */\nconst REASONING_MAX_CHARS = 4000;\nconst CLAIM_MAX_CHARS = 2000;\nconst TRUNCATION_MARKER = ' …[truncated]';\n\n/** Truncate `s` to `max` chars with a marker; a no-op when already within cap. */\nfunction clampWithMarker(s: string, max: number): string {\n if (s.length <= max) return s;\n return s.slice(0, Math.max(0, max - TRUNCATION_MARKER.length)) + TRUNCATION_MARKER;\n}\n\n/**\n * Clamp the capped string fields of a parsed vote to their schema limits with a\n * truncation marker BEFORE validation (#4131). A thorough voter (esp. the\n * contrarian, which writes the most detailed findings) whose `reasoning` exceeds\n * the 4000-char cap previously hard-failed validation and was SILENTLY DROPPED\n * from the panel denominator. Clamping records a (clipped, clearly-marked) real\n * vote instead. Only shape (oversize strings) is repaired — a genuinely\n * malformed vote (missing decision, bad confidence) still fails `safeParse`.\n */\nfunction clampOversizeVoteStrings(parsed: unknown): unknown {\n if (typeof parsed !== 'object' || parsed === null) return parsed;\n const obj = { ...(parsed as Record<string, unknown>) };\n if (typeof obj['reasoning'] === 'string') {\n obj['reasoning'] = clampWithMarker(obj['reasoning'], REASONING_MAX_CHARS);\n }\n if (Array.isArray(obj['findings'])) {\n obj['findings'] = (obj['findings'] as unknown[]).map((finding): unknown => {\n if (\n typeof finding === 'object' &&\n finding !== null &&\n typeof (finding as Record<string, unknown>)['claim'] === 'string'\n ) {\n const f = finding as Record<string, unknown>;\n return { ...f, claim: clampWithMarker(f['claim'] as string, CLAIM_MAX_CHARS) };\n }\n return finding;\n });\n }\n return obj;\n}\n\n/** Maps a validated VoteResponse into a ParsedVote, threading optional fields. */\nfunction buildParsedVote(data: VoteResponse, options?: readonly string[]): ParsedVote {\n // #4472: resolve the voter's raw selection against the declared options.\n // An unmatched or absent selection stays absent — never defaulted — so the\n // tally can price it as unattributed rather than inventing agreement.\n const selectedOption =\n options === undefined ? undefined : matchDeclaredOption(data.selectedOption, options);\n return {\n decision: data.decision,\n reasoning: data.reasoning,\n confidence: data.confidence,\n ...(data.conditions !== undefined ? { conditions: data.conditions } : {}),\n ...(data.rejectionCategories !== undefined\n ? { rejectionCategories: data.rejectionCategories }\n : {}),\n ...(data.findings !== undefined ? { findings: data.findings } : {}),\n ...(selectedOption !== undefined ? { selectedOption } : {}),\n source: 'parsed',\n };\n}\n\n/**\n * Parses vote response from LLM output.\n *\n * Fail-closed: throws SyntheticVoteError if parsing or validation fails.\n * No synthetic vote is ever fabricated from unparseable output (#4177).\n *\n * (Source: Issue #512 - Fail-safe voting response parsing)\n *\n * @param output - Raw LLM output text\n * @param _role - Voter role for context\n * @returns ParsedVote with source tracking\n * @throws SyntheticVoteError if parsing or validation fails\n */\nexport function parseVoteResponse(\n output: string,\n _role: VoterRole,\n options?: readonly string[]\n): ParsedVote {\n try {\n const jsonStr = extractJsonFromResponse(output);\n const parsed = JSON.parse(jsonStr) as unknown;\n // #4131: clip oversize reasoning/claims (with a marker) so a thorough voter\n // records a real vote instead of being silently dropped on the char cap.\n const validated = VoteResponseSchema.safeParse(clampOversizeVoteStrings(parsed));\n\n if (validated.success) {\n return buildParsedVote(validated.data, options);\n }\n\n const reason = `Validation failed: ${validated.error.issues.map((e: { message: string }) => e.message).join(', ')}`;\n throw new SyntheticVoteError(reason, output);\n } catch (error) {\n // If it's already a SyntheticVoteError, rethrow it\n if (error instanceof SyntheticVoteError) {\n throw error;\n }\n\n throw new SyntheticVoteError(getErrorMessage(error, 'Unknown parse error'), output);\n }\n}\n","/**\n * Option-tally threshold evaluation for multi-option proposals (#4472).\n *\n * When a `consensus_vote` proposal declares named `options`, thresholds must be\n * measured over WHICH option voters chose, not over raw approve/reject counts.\n * Without this, `unanimous` is the *easiest* bar to clear on a multi-option\n * proposal: every voter approves while each picks something different, so a 6-1\n * split records as 7-0, 100% (#4452).\n *\n * ## Semantics: \"count in denominator, credit no option\"\n *\n * Decided by a 7-voter `higher_order` panel on #4472 (6-1 for this rule). An\n * approving voter whose selection is absent or matches no declared option stays\n * in the denominator and credits no option.\n *\n * The decisive property is that this is **monotone-downward**: an absent or\n * unmatched selection can only *lower* the leading option's share, never raise\n * it. Degradation is therefore a denial, never an escalation — the invariant an\n * enforcing governance gate requires (#4464). The rejected alternative\n * (excluding non-selectors from the denominator) reads 1 selector among 6\n * unparseable as 1/1 = 100% \"unanimous\", rebuilding the #4452 masking bug.\n *\n * No per-threshold special-casing is needed: any non-selecting approver caps the\n * leading share below 100%, so `unanimous` fails by arithmetic when the panel\n * cannot articulate one choice. Absence is disqualifying for unanimity by\n * construction.\n *\n * The accepted cost is false negatives — a genuinely unanimous panel with one\n * degraded response records 6/7 and misses the unanimous gate. On the governor\n * path that bias direction is correct: a retry, never a split laundered as\n * consensus.\n *\n * @module consensus/option-tally\n * (Source: Issue #4472)\n */\n\n/** Fraction of the leading option required to clear each threshold. */\nconst SUPERMAJORITY_SHARE = 2 / 3;\nconst MAJORITY_SHARE = 0.5;\n\n/** The thresholds this module can evaluate over an option tally. */\nexport type OptionThreshold = 'majority' | 'supermajority' | 'unanimous';\n\n/** One declared option and how many approving voters chose it. */\nexport interface OptionTallyEntry {\n readonly option: string;\n readonly count: number;\n}\n\n/** Minimal vote shape this module reads. */\nexport interface TallyableVote {\n readonly decision: 'approve' | 'reject' | 'abstain';\n readonly selectedOption?: string;\n}\n\nexport interface OptionTallyResult {\n /** Chosen options, descending by count, ties broken by label for determinism. */\n readonly tally: readonly OptionTallyEntry[];\n /** The most-chosen option, or undefined when nobody selected one. */\n readonly leadingOption?: string;\n readonly leadingCount: number;\n /** Denominator: every approving voter, selecting or not. */\n readonly approverCount: number;\n /** Approvers whose selection matched a declared option. */\n readonly selectedCount: number;\n /**\n * Approvers with no usable selection.\n *\n * Recorded explicitly because the share alone cannot distinguish dissent from\n * absence: `4 pick X + 3 unparseable` and a real 4/3 split both read 57%. The\n * panel made this field a condition of adopting these semantics — partial\n * coverage must be represented, not merely priced in.\n */\n readonly unattributedApprovals: number;\n /** `leadingCount / approverCount`, or 0 when nobody approved. */\n readonly leadingShare: number;\n}\n\nexport interface OptionThresholdVerdict extends OptionTallyResult {\n readonly threshold: OptionThreshold;\n readonly approved: boolean;\n}\n\n/**\n * Resolve a voter's raw selection to a declared option.\n *\n * Matching is trimmed and case-insensitive, and returns the *declared* spelling\n * so the tally never splits one option across spelling variants. Anything that\n * does not match exactly one declared option resolves to `undefined` — an\n * unmatched selection is treated as absent, never coerced onto a default,\n * because a defaulted option is a measurement that was never taken.\n */\nexport function matchDeclaredOption(\n raw: string | undefined,\n declaredOptions: readonly string[]\n): string | undefined {\n if (raw === undefined) return undefined;\n\n const normalized = raw.trim().toLowerCase();\n if (normalized === '') return undefined;\n\n return declaredOptions.find((option) => option.trim().toLowerCase() === normalized);\n}\n\n/** Build the option tally for a set of votes against the declared options. */\nexport function tallyOptions(\n votes: readonly TallyableVote[],\n declaredOptions: readonly string[]\n): OptionTallyResult {\n const approvers = votes.filter((v) => v.decision === 'approve');\n\n const counts = new Map<string, number>();\n let selectedCount = 0;\n\n for (const vote of approvers) {\n const matched = matchDeclaredOption(vote.selectedOption, declaredOptions);\n if (matched === undefined) continue;\n selectedCount += 1;\n counts.set(matched, (counts.get(matched) ?? 0) + 1);\n }\n\n const tally = [...counts.entries()]\n .map(([option, count]) => ({ option, count }))\n .sort((a, b) => (b.count !== a.count ? b.count - a.count : a.option.localeCompare(b.option)));\n\n const leader = tally[0];\n const approverCount = approvers.length;\n const leadingCount = leader?.count ?? 0;\n\n return {\n tally,\n ...(leader !== undefined ? { leadingOption: leader.option } : {}),\n leadingCount,\n approverCount,\n selectedCount,\n unattributedApprovals: approverCount - selectedCount,\n leadingShare: approverCount > 0 ? leadingCount / approverCount : 0,\n };\n}\n\n/**\n * Decide whether the leading option clears `threshold`.\n *\n * `unanimous` asks whether every approver chose the *same* option, which is\n * strictly stronger than \"everyone approved\" — the inversion #4472 exists to\n * correct. The share thresholds measure the leading option, so total approvals\n * no longer stand in for agreement.\n */\nexport function evaluateOptionThreshold(\n tally: OptionTallyResult,\n threshold: OptionThreshold\n): OptionThresholdVerdict {\n const approved = clears(tally, threshold);\n return { ...tally, threshold, approved };\n}\n\nfunction clears(tally: OptionTallyResult, threshold: OptionThreshold): boolean {\n // A panel in which nobody named an option has not agreed on one, whatever\n // its approval count says.\n if (tally.approverCount === 0 || tally.leadingCount === 0) return false;\n\n switch (threshold) {\n case 'unanimous':\n return tally.leadingCount === tally.approverCount;\n case 'supermajority':\n return tally.leadingShare >= SUPERMAJORITY_SHARE;\n case 'majority':\n return tally.leadingShare > MAJORITY_SHARE;\n }\n}\n","/**\n * 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 { getVoterPrompts, SIMULATED_VOTE_REASONING } from './voter-prompts.js';\nimport {\n buildVotePrompt,\n parseVoteResponse,\n SyntheticVoteError,\n VOTE_JSON_SCHEMA,\n} from './voter-response.js';\n\n// Import timeout constants from canonical source (Issue #984)\nimport {\n VOTE_TIMEOUTS,\n resolveVoteTimeout as _resolveVoteTimeout,\n validateTimeout as _validateTimeout,\n} from '../config/timeouts.js';\nimport { CLI_NAMES, type CliNameLiteral } from '../config/model-capabilities-types.js';\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, isDurableCapacityText } from '../adapters/rate-limit-detector.js';\n\n/** @see isRateLimitLikeError — re-exported for backward compatibility */\nexport function isRateLimitError(message: string): boolean {\n return isRateLimitLikeError(new Error(message));\n}\n\n/**\n * Validates and clamps timeout to `[VOTE_TIMEOUTS.minMs, VOTE_TIMEOUTS.maxMs]`.\n *\n * **Canonical source:** `config/timeouts.ts`. This re-export exists for\n * back-compat — new code should import from `../config/timeouts.js`\n * directly (#2637).\n */\nexport const validateTimeout = _validateTimeout;\n\n// ============================================================================\n// Vote Result Helpers\n// ============================================================================\n\n/**\n * Creates an error vote result (abstain with error message).\n * Issue #523: Uses source: 'error' instead of 'llm' for accuracy.\n */\nexport function createErrorVoteResult(\n role: VoterRole,\n errorMsg: string,\n processingTimeMs: number,\n providerId?: string\n): AgentVoteResult {\n const bareCli =\n providerId?.startsWith('cli-') === true ? providerId.slice('cli-'.length) : providerId;\n const cli =\n bareCli !== undefined && (CLI_NAMES as readonly string[]).includes(bareCli)\n ? (bareCli as CliNameLiteral)\n : undefined;\n return {\n role,\n vote: {\n decision: 'abstain',\n reasoning: `[Error] Vote execution failed: ${errorMsg}`,\n confidence: 0,\n },\n processingTimeMs,\n source: 'error',\n error: errorMsg,\n ...(cli !== undefined ? { cli } : {}),\n };\n}\n\n/**\n * Creates a simulation vote result.\n */\nexport function createSimulationVoteResult(\n role: VoterRole,\n proposal: string,\n processingTimeMs: number,\n error?: string\n): AgentVoteResult {\n return {\n role,\n vote: simulateVote(role, proposal),\n processingTimeMs,\n source: 'simulation',\n ...(error !== undefined && { error }),\n };\n}\n\n/**\n * Creates simulated votes for multiple roles.\n */\nexport function createSimulatedVotes(\n roles: readonly VoterRole[],\n proposal: string,\n error?: string\n): readonly AgentVoteResult[] {\n const random = getRandomProvider();\n return roles.map((role) =>\n createSimulationVoteResult(role, proposal, random.randomInt(0, 100), error)\n );\n}\n\n/**\n * Role-specific vote distributions for simulation.\n * Each role has weighted probabilities reflecting their typical concerns:\n * - security: More skeptical, finds potential issues\n * - architect: Technically focused, generally supportive of good design\n * - devex: Balanced, considers usability\n * - ai_ml: Technically focused, evaluates AI aspects\n * - pm: Business focused, generally supportive of value\n *\n * Format: [approve_weight, reject_weight, abstain_weight]\n */\nconst ROLE_VOTE_DISTRIBUTIONS: Record<VoterRole, [number, number, number]> = {\n security: [40, 45, 15], // More skeptical - security concerns\n architect: [55, 30, 15], // Generally approving of good design\n devex: [50, 30, 20], // Balanced - considers usability\n ai_ml: [55, 30, 15], // Technical focus\n pm: [55, 25, 20], // Business focus - generally supportive\n catfish: [20, 65, 15], // Deliberately contrarian - challenges proposals (arXiv:2505.21503)\n scope_steward: [25, 60, 15], // Default-bias toward not shipping (#2185)\n};\n\n/**\n * Selects a decision based on weighted probabilities.\n */\nfunction selectWeightedDecision(\n weights: [number, number, number]\n): 'approve' | 'reject' | 'abstain' {\n const random = getRandomProvider();\n const total = weights[0] + weights[1] + weights[2];\n const rand = random.random() * total;\n\n if (rand < weights[0]) return 'approve';\n if (rand < weights[0] + weights[1]) return 'reject';\n return 'abstain';\n}\n\n/**\n * Fallback simulation when LLM is unavailable.\n * Uses role-specific vote distributions to provide more realistic simulation.\n * Clearly marks output as simulated.\n *\n * (Improved per Issue #453 - remove hardcoded 60% approve bias)\n */\nexport function simulateVote(role: VoterRole, proposal: string): Vote {\n const random = getRandomProvider();\n const weights = ROLE_VOTE_DISTRIBUTIONS[role];\n const decision = selectWeightedDecision(weights);\n\n // Confidence varies by decision type and role\n // Rejections tend to be higher confidence (found specific issue)\n // Approvals are moderate confidence (no issues found, but limited analysis)\n // Abstains are low confidence (insufficient information)\n let baseConfidence: number;\n if (decision === 'reject') {\n baseConfidence = 0.6 + random.random() * 0.3; // 0.6-0.9\n } else if (decision === 'approve') {\n baseConfidence = 0.5 + random.random() * 0.3; // 0.5-0.8\n } else {\n baseConfidence = 0.3 + random.random() * 0.2; // 0.3-0.5\n }\n\n return {\n decision,\n reasoning: `[Simulated - no LLM available] ${SIMULATED_VOTE_REASONING[role]} Proposal: \"${proposal.slice(0, 50)}...\"`,\n confidence: baseConfidence,\n };\n}\n\n// ============================================================================\n// Timeout and Retry Utilities\n// ============================================================================\n\n// Re-export from canonical source for backward compatibility\nexport { withTimeout, delay } from '../utils/async-utils.js';\n\n// ============================================================================\n// Vote Attempt Execution\n// ============================================================================\n\n/**\n * 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,\n proposal,\n timeoutMs,\n withResponseFormat,\n options,\n project,\n}: VoteCompletionArgs): CompletionRequest {\n const base: CompletionRequest = {\n messages: [\n // #6110: the seat judges the caller's target project, not this\n // repository's. `undefined` renders the `nexus-agents` default.\n { role: 'system', content: getVoterPrompts(project)[role] },\n { role: 'user', content: buildVotePrompt(proposal, options) },\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 /** Input tokens read from an existing prompt cache, when reported (#4435). */\n readonly cachedInputTokens?: number | undefined;\n /** Input tokens spent writing the cache, when reported (#4435). */\n readonly cacheCreationInputTokens?: number | undefined;\n}\n\n/** 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. */\ninterface VoteCompletionArgs {\n readonly role: VoterRole;\n readonly proposal: string;\n readonly adapter: IModelAdapter;\n readonly timeoutMs: number;\n readonly withResponseFormat: boolean;\n /** Declared options for a multi-option proposal (#4472). */\n readonly options?: readonly string[] | undefined;\n /**\n * The target project named in the system prompt (#6110). Required as a KEY\n * so a hop that forgets to pass it fails to compile; `undefined` is the\n * `nexus-agents` default.\n */\n readonly project: string | undefined;\n}\n\nasync function runVoteCompletion(\n args: VoteCompletionArgs\n): Promise<\n | { ok: true; output: string; usage: VoteUsage; cliStderr: string | undefined }\n | { ok: false; error: string }\n> {\n const { role, adapter, timeoutMs } = args;\n const request = buildVoteRequest(args);\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 cachedInputTokens?: unknown;\n cacheCreationInputTokens?: unknown;\n }\n | undefined;\n const usage: VoteUsage = {\n inputTokens: readTokenCount(reported?.inputTokens),\n outputTokens: readTokenCount(reported?.outputTokens),\n // #4435: an `inputTokens: 2` next to 3,980 cached tokens tells a very\n // different story than `inputTokens: 2` alone.\n cachedInputTokens: readTokenCount(reported?.cachedInputTokens),\n cacheCreationInputTokens: readTokenCount(reported?.cacheCreationInputTokens),\n };\n return {\n ok: true,\n output: extractTextFromResponse(response.value.content),\n usage,\n // #6094: the transport's captured stderr rides up with the vote so the\n // caller can classify a seat that could not read the artifact from the\n // structured signal rather than from its prose.\n cliStderr: response.value.cliStderr,\n };\n}\n\n/** A parsed vote plus what the transport reported alongside it. Module-private: its only consumer is the return type below. */\ninterface VoteAttemptSuccess {\n readonly ok: true;\n readonly vote: Vote;\n readonly output: string;\n readonly usage: VoteUsage;\n /** Stderr the CLI transport captured for this completion, when any (#6094). */\n readonly cliStderr: string | undefined;\n}\n\n/** What the prompt carries beyond the proposal: declared options (#4472) and the target project (#6110). */\ninterface VotePromptContext {\n readonly options?: readonly string[] | undefined;\n /** Target project for the system prompt; omitted ⇒ `nexus-agents`. */\n readonly project?: string | undefined;\n}\n\nexport async function executeSingleVoteAttempt(\n role: VoterRole,\n proposal: string,\n adapter: IModelAdapter,\n timeoutMs: number,\n context: VotePromptContext = {}\n): Promise<VoteAttemptSuccess | { ok: false; error: string }> {\n const { options, project } = context;\n const completionArgs = { role, proposal, adapter, timeoutMs, options, project };\n let completion = await runVoteCompletion({ ...completionArgs, withResponseFormat: true });\n // #3497: retry once WITHOUT responseFormat when the backend rejects the\n // tool-use-backed structured-output ask, so the panel keeps full strength.\n if (!completion.ok && isStructuredOutputUnsupported(completion.error)) {\n completion = await runVoteCompletion({ ...completionArgs, withResponseFormat: 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, options);\n return {\n ok: true,\n vote,\n output: completion.output,\n usage: completion.usage,\n cliStderr: completion.cliStderr,\n };\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 /** Declared options for a multi-option proposal (#4472); absent for yes/no. */\n readonly options?: readonly string[] | undefined;\n /** Target project for the system prompt (#6110); absent ⇒ `nexus-agents`. */\n readonly project?: string | undefined;\n}\n\n/**\n * Executes vote attempts with retry logic.\n * Returns the error message from last failed attempt, or undefined if successful.\n */\n/**\n * Record that a voter gave up its remaining attempts (#5359).\n *\n * A DURABLE capacity cap — a spend or usage ceiling on the credential — does\n * not clear in seconds, so the remaining attempts are guaranteed-futile. The\n * waste is not local either: `computeOverallConsensusDeadlineMs` budgets\n * `timeoutMs * (maxRetries + 1)` as a SHARED wall-clock deadline across the\n * panel, so burning it here starved a healthy voter on a different adapter in\n * four consecutive live runs. Failing fast hands the remaining budget to the\n * #3587 fallback, which is what actually recovers the voice.\n */\nfunction logAbandonedRetries(\n logger: ILogger,\n role: VoterRole,\n attempt: number,\n maxRetries: number\n): void {\n logger.warn('Durable capacity cap — abandoning retries for this voter', {\n role,\n attempt: attempt + 1,\n remainingAttemptsSkipped: maxRetries - attempt,\n });\n}\n\nexport async function executeWithRetries(\n opts: RetryOptions\n): Promise<\n | { vote: Vote; usage: VoteUsage; cliStderr: string | undefined; ok: true }\n | { error: string; ok: false }\n> {\n const { role, proposal, adapter, logger, timeoutMs, maxRetries, options, project } = 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 options,\n project,\n });\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, cliStderr: result.cliStderr, ok: true };\n }\n\n lastError = result.error;\n if (logFailedAttempt(logger, { role, attempt, maxRetries, attemptMs, error: lastError })) {\n logAbandonedRetries(logger, role, attempt, maxRetries);\n break;\n }\n }\n\n return { error: lastError !== '' ? lastError : 'Unknown error after all retries', ok: false };\n}\n\n/** One failed attempt, as {@link logFailedAttempt} reports it. */\ninterface FailedAttempt {\n readonly role: VoterRole;\n readonly attempt: number;\n readonly maxRetries: number;\n readonly attemptMs: number;\n readonly error: string;\n}\n\n/**\n * Log one failed attempt's timing and classification. Returns true when the\n * error is a DURABLE capacity cap, so the caller abandons the remaining\n * attempts (#5359). Extracted from {@link executeWithRetries} for the\n * per-function line cap.\n */\nfunction logFailedAttempt(logger: ILogger, failed: FailedAttempt): boolean {\n const { role, attempt, maxRetries, attemptMs, error } = failed;\n const rateLimited = isRateLimitError(error);\n const durableCap = isDurableCapacityText(error);\n logger.info('Vote attempt timing', {\n role,\n attempt: attempt + 1,\n attemptMs,\n succeeded: false,\n rateLimited,\n });\n logger.warn('Vote attempt failed', {\n role,\n attempt: attempt + 1,\n maxRetries: maxRetries + 1,\n error,\n ...(rateLimited ? { rateLimited: true } : {}),\n ...(durableCap ? { durableCap: true } : {}),\n });\n return durableCap;\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 * Cancellation for in-flight panels (#5393).\n *\n * Checked after each stagger delay, so a cancel stops LAUNCHING the voters\n * that have not started. Votes already in flight are left to settle — an\n * adapter call is a subprocess or an HTTP request whose cost is already\n * incurred, and abandoning it would lose the result without saving the spend.\n * The win is the remaining panel: cancelling a 7-voter vote after two have\n * run stops five model calls.\n *\n * Absent or un-aborted changes nothing.\n */\n readonly signal?: AbortSignal | undefined;\n}\n\nconst DEADLINE_MESSAGE = 'overall consensus deadline exceeded';\n/**\n * #5393: reported for a voter the panel never launched. An ERROR result, never\n * a default decision — a cancelled voter returning `approve` would manufacture\n * consensus out of work that never ran.\n */\nconst CANCELLED_MESSAGE = 'cancelled before this voter was launched';\n\n/**\n * #3587: a voter routed to a diverse CLI that hard-fails (e.g. an OpenRouter\n * model without tool-use → \"no endpoints that support tool use\", which the\n * responseFormat retry can't fix) would silently shrink the panel. Retry once on\n * the known-good fallback adapter so one bad CLI cannot drop a voter.\n *\n * Should a failed vote be retried on the fallback adapter? Only when the diverse\n * adapter produced a genuine error (not the overall-deadline filler, which means\n * there's no time left) AND it wasn't already the fallback (#3587).\n */\nfunction shouldRetryOnFallback(\n result: AgentVoteResult,\n used: IModelAdapter,\n fallback: IModelAdapter\n): boolean {\n return (\n result.source === 'error' &&\n result.error !== DEADLINE_MESSAGE &&\n adapterCliKey(used) !== adapterCliKey(fallback)\n );\n}\n\n/** Stable per-CLI key for an adapter; CLI adapters carry the CLI name. */\nfunction adapterCliKey(adapter: IModelAdapter): string {\n return (adapter as { name?: string }).name ?? adapter.providerId;\n}\n\n/** Preserve the panel resolver's primary assignment across fallback execution. */\nfunction withPinnedModel(result: AgentVoteResult, pinnedModel: string): AgentVoteResult {\n return { ...result, pinnedModel };\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\n/**\n * Read through a function, not inline (#5393): after one\n * `signal?.aborted === true` check TypeScript narrows the field to `false` for\n * the rest of the enclosing closure, which is unsound across an `await` — the\n * whole point is that it can flip while a vote is in flight.\n */\nfunction cancelled(signal: AbortSignal | undefined): boolean {\n return signal?.aborted === true;\n}\n\ntype VoteOnAdapter = (role: VoterRole, adapter: IModelAdapter) => Promise<AgentVoteResult>;\n\nasync function launchRoleVote(\n role: VoterRole,\n index: number,\n input: LaunchVotesInput,\n voteOnAdapter: VoteOnAdapter\n): Promise<AgentVoteResult> {\n if (index > 0 && input.interDelay > 0) await delay(input.interDelay);\n const adapter = input.roleAdapters.get(role) ?? input.fallbackAdapter;\n const pinnedModel = adapter.modelId;\n if (cancelled(input.signal)) {\n return withPinnedModel(createErrorVoteResult(role, CANCELLED_MESSAGE, 0), pinnedModel);\n }\n const primary = await voteOnAdapter(role, adapter);\n if (!shouldRetryOnFallback(primary, adapter, input.fallbackAdapter)) {\n return withPinnedModel(primary, pinnedModel);\n }\n if (cancelled(input.signal)) return withPinnedModel(primary, pinnedModel);\n input.logger.warn('Voter failed on diverse adapter; retrying on fallback (#3587)', {\n role,\n failedCli: adapterCliKey(adapter),\n fallbackCli: adapterCliKey(input.fallbackAdapter),\n error: primary.error,\n });\n return withPinnedModel(await voteOnAdapter(role, input.fallbackAdapter), pinnedModel);\n}\n\nexport async function launchVotesWithOverallDeadline(\n input: LaunchVotesInput\n): Promise<readonly AgentVoteResult[]> {\n const { roles, proposal, logger, voteOptions, overallDeadlineMs, voteFn } = 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((role, index) => launchRoleVote(role, index, input, voteOnAdapter));\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 } 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';\nimport { countDistinctModels } from '../config/model-equivalence.js';\nimport { reportPanelIndependence, reportVoteIndependence } from './panel-independence.js';\nimport { DEFAULT_ERRORED_ROLE_BACKOFF_MS, retryErroredRoles } from './voter-retry.js';\nimport { NoAdapterError, resolveAdapterOrFail } from './voter-adapter-resolve.js';\nimport {\n classifyUnverifiable,\n markUnverifiable,\n type UnverifiableReasoningRule,\n} from './voter-unverifiable.js';\n\n// Re-exported: `exports/consensus.ts` and the voter tests import it from here (#5578 moved the class).\nexport { NoAdapterError };\n\n// Re-export prompts for backward compatibility\nexport { VOTER_SYSTEM_PROMPTS, SIMULATED_VOTE_REASONING } from './voter-prompts.js';\n\n// Re-export response utilities for backward compatibility\nexport {\n VoteResponseSchema,\n type VoteResponse,\n buildVotePrompt,\n extractJsonFromResponse,\n parseVoteResponse,\n SyntheticVoteError,\n type ParsedVote,\n type ParsedVoteSource,\n} from './voter-response.js';\n\n// Re-export execution utilities for backward compatibility\nexport {\n DEFAULT_VOTE_TIMEOUT_MS,\n MAX_VOTE_TIMEOUT_MS,\n MIN_VOTE_TIMEOUT_MS,\n DEFAULT_MAX_RETRIES,\n RATE_LIMIT_RETRY_DELAY_MS,\n createErrorVoteResult,\n createSimulationVoteResult,\n createSimulatedVotes,\n simulateVote,\n isRateLimitError,\n withTimeout,\n delay,\n extractTextFromResponse,\n executeSingleVoteAttempt,\n resolveVoteTimeout,\n type RetryOptions,\n executeWithRetries,\n} from './voter-execution.js';\n\n// Import from execution module for internal use\nimport {\n createErrorVoteResult,\n createSimulationVoteResult,\n createSimulatedVotes,\n executeWithRetries,\n} from './voter-execution.js';\nimport { resolveVoteTimeout, VOTE_TIMEOUTS, 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 // #4472: surface the voter's choice at the result level, where the tally\n // and the record read it. Absent when no options were declared or the\n // selection matched none of them.\n ...(vote.selectedOption !== undefined ? { selectedOption: vote.selectedOption } : {}),\n ...(usage.inputTokens !== undefined ? { inputTokens: usage.inputTokens } : {}),\n ...(usage.outputTokens !== undefined ? { outputTokens: usage.outputTokens } : {}),\n ...(usage.cachedInputTokens !== undefined\n ? { cachedInputTokens: usage.cachedInputTokens }\n : {}),\n ...(usage.cacheCreationInputTokens !== undefined\n ? { cacheCreationInputTokens: usage.cacheCreationInputTokens }\n : {}),\n };\n}\n\n/**\n * The parsed vote, or — when the seat could not read the artifact — the same\n * seat re-recorded as `unverifiable` with its returned decision discarded and\n * logged (#6094). Classification prefers the transport's stderr (structured)\n * over the reasoning text (fallback); the log names which one fired.\n */\nfunction finalizeParsedVote(\n built: AgentVoteResult,\n cliStderr: string | undefined,\n logger: ILogger\n): AgentVoteResult {\n const { role, model } = built;\n const signal = classifyUnverifiable(\n { cliStderr, reasoning: built.vote.reasoning },\n (rule: UnverifiableReasoningRule) => {\n logger.debug('Unverifiable reasoning fallback fired', { role, rule });\n }\n );\n if (signal === undefined) {\n logger.info('Vote completed', { role, model, decision: built.vote.decision });\n return built;\n }\n logger.warn('Seat could not read the artifact — recorded as unverifiable, decision discarded', {\n role,\n model,\n signal,\n discardedDecision: built.vote.decision,\n ...(built.selectedOption !== undefined ? { discardedOption: built.selectedOption } : {}),\n });\n return markUnverifiable(built, signal);\n}\n\n/**\n * Executes a real LLM vote for a single role with timeout and retry support.\n *\n * Per Issue #280: No simulation fallback by default. Returns error result\n * instead of simulated vote when execution fails.\n */\n/** Resolve per-call vote execution settings against their defaults. */\nfunction resolveVoteExecution(options?: VoteExecutionOverrides): VoteExecutionSettings {\n return {\n timeoutMs: options?.timeoutMs ?? resolveVoteTimeout(),\n maxRetries: options?.maxRetries ?? VOTE_TIMEOUTS.maxRetries,\n allowSimulation: options?.allowSimulation ?? false,\n declaredOptions: options?.declaredOptions,\n project: options?.project,\n };\n}\n\nexport async function executeAgentVote(\n role: VoterRole,\n proposal: string,\n adapter: IModelAdapter,\n logger: ILogger,\n options?: VoteExecutionOverrides\n): Promise<AgentVoteResult> {\n const start = getTimeProvider().now();\n const { timeoutMs, maxRetries, allowSimulation, declaredOptions, project } =\n resolveVoteExecution(options);\n\n logger.info('Executing vote', { role, model: adapter.modelId, provider: adapter.providerId });\n\n const retryOptions = { role, proposal, adapter, logger, timeoutMs, maxRetries, project };\n const result = await executeWithRetries({ ...retryOptions, options: declaredOptions });\n const processingTimeMs = getTimeProvider().now() - start;\n\n if (result.ok) {\n const built = buildLlmVoteResult(role, result.vote, result.usage, adapter, processingTimeMs);\n return finalizeParsedVote(built, result.cliStderr, logger);\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, adapter.providerId);\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 /** Named alternatives for a multi-option proposal (#4472); each voter picks one. */\n readonly declaredOptions?: readonly string[] | undefined;\n /**\n * The project the panel is judging, already resolved and validated by the\n * caller (#6110). Reaches every seat's system prompt. Absent ⇒ `nexus-agents`.\n */\n readonly project?: string | undefined;\n /**\n * Cancellation for an in-flight panel (#5393). Stops LAUNCHING voters that\n * have not started; votes already in flight settle. Absent changes nothing.\n */\n readonly signal?: AbortSignal | undefined;\n /**\n * Delay before the per-role retry of errored voters (#5578). Defaults to\n * {@link DEFAULT_ERRORED_ROLE_BACKOFF_MS}; 0 disables the wait, which is what\n * tests want. The retry itself is not optional — the panel applies it under\n * every error policy, per the #5578 design panel (option b, 6 of 6).\n */\n readonly erroredRoleBackoffMs?: number | undefined;\n}\n\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(clis: readonly CliName[]): Map<CliName, IModelAdapter> {\n const registry = getGlobalRegistry();\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 // #4390: compare CANONICAL model identity, not the raw strings. The same\n // weights arrive under different strings from different gateways —\n // `claude-sonnet-4-6`, `anthropic/claude-sonnet-4-6` and\n // `custom/claude-sonnet-4-6` are one model — so a raw-string set reported a\n // collapsed panel as diverse and the warning never fired.\n const assignedModels = [...assigned.values()].map((a) => a.modelId);\n if (roles.length > 1 && countDistinctModels(assignedModels) === 1) {\n logger.warn(\n 'Consensus panel collapsed to a single gateway model via overrides — votes may correlate',\n { model: assignedModels[0], roleCount: roles.length }\n );\n }\n 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);\n if (cliAdapters.size <= 1) return assignUniformAdapter(roles, fallbackAdapter);\n\n // #4390: distinct CLIs do NOT imply distinct models. Two arms can front the\n // same weights — opencode serving `anthropic/claude-sonnet-4-6` alongside the\n // claude CLI, for instance — and a panel spread across them is no more\n // independent than one on a single arm. The gateway path had this check; the\n // CLI path had none.\n // #4983: detection is lazy, so at assignment time every adapter still\n // reports the same `pending-detection` placeholder — which an equality check\n // reads as \"one model\" and warns on EVERY vote. Say unmeasured here and make\n // the real judgement in `warnIfPanelCorrelated`, after the votes have run and\n // each adapter has resolved.\n reportPanelIndependence([...cliAdapters.values()], roles.length, 'assignment', logger);\n\n return assignRoundRobinAdapters(\n roles,\n [...cliAdapters.entries()].map(([cli, adapter]) => ({ label: cli, adapter })),\n logger,\n 'cli'\n );\n}\n\n/** Options for staggered vote launching. */\n/** Caller-supplied vote execution overrides; unset fields take defaults. */\nexport interface VoteExecutionOverrides {\n timeoutMs?: number;\n maxRetries?: number;\n allowSimulation?: boolean;\n /** Declared options for a multi-option proposal (#4472). */\n declaredOptions?: readonly string[] | undefined;\n /** Target project for the system prompts (#6110); absent ⇒ `nexus-agents`. */\n project?: string | undefined;\n}\n\n/** Resolved per-call vote execution settings. */\ninterface VoteExecutionSettings {\n timeoutMs: number;\n maxRetries: number;\n allowSimulation: boolean;\n declaredOptions?: readonly string[] | undefined;\n /** Required KEY (#6110): a hop that drops the target project fails to compile. */\n project: string | undefined;\n}\n\ninterface StaggeredVoteInput {\n readonly roles: readonly VoterRole[];\n readonly proposal: string;\n readonly roleAdapters: Map<VoterRole, IModelAdapter>;\n readonly fallbackAdapter: IModelAdapter;\n readonly logger: ILogger;\n /** Passed straight to executeAgentVote; declaredOptions per #4472. */\n readonly voteOptions: VoteExecutionSettings;\n readonly interDelay: number;\n /** Cancellation for the un-launched remainder of the panel (#5393). */\n readonly signal?: AbortSignal | undefined;\n}\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 signal: input.signal,\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 = resolveAdapterOrFail(options, logger, allowSimulation === true);\n if ('simulated' in adapterResult)\n return createSimulatedVotes(roles, proposal, 'No adapter available');\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 = {\n timeoutMs,\n maxRetries,\n allowSimulation: allowSimulation ?? false,\n // #4472: reaches executeAgentVote, which puts the declared options in the\n // prompt and resolves each voter's selection against them.\n declaredOptions: options.declaredOptions,\n // #6110: likewise the target project, into every seat's system prompt.\n project: options.project,\n };\n const interDelay = options.interAgentDelayMs ?? DEFAULT_INTER_AGENT_DELAY_MS;\n\n const launchInput: StaggeredVoteInput = {\n roles,\n proposal,\n roleAdapters,\n fallbackAdapter: adapterResult.adapter,\n logger,\n voteOptions,\n interDelay,\n signal: options.signal,\n };\n const firstPass = await launchStaggeredVotes(launchInput);\n // #5578: recover an errored seat with one extra call rather than losing it\n // (reduce_denominator) or replaying the whole panel (absolute_quorum).\n const results = await retryErroredRoles(\n firstPass,\n (retryRoles) => launchStaggeredVotes({ ...launchInput, roles: retryRoles }),\n logger,\n options.erroredRoleBackoffMs ?? DEFAULT_ERRORED_ROLE_BACKOFF_MS\n );\n\n // #4983/#5546: this is the only point the question is answerable. Assess the\n // successful result provenance, not the assigned adapters: a failed primary\n // may have been replaced by a vote from the shared fallback model.\n reportVoteIndependence(results, logger);\n return results;\n}\n\n/**\n * Gets a description for a voter role.\n */\nexport function getRoleDescription(role: VoterRole): string {\n return VOTER_ROLES[role];\n}\n","/**\n * nexus-agents/cli - Target project for the voter panel (#6110)\n *\n * `getVoterPrompts(project)` puts the project name into every voter's system\n * prompt, and until #6110 nothing ever passed one: a consuming repository got a\n * scope_steward judging its proposal against \"the nexus-agents project\". This\n * module answers \"which project is the panel judging?\" from three sources, in\n * order, and says which one answered:\n *\n * 1. `input` — the caller's explicit `project` (tool input or `--project`).\n * 2. `derived` — `owner/repo` parsed from the `origin` URL in the repo's\n * `.git/config`, else the nearest `package.json` `name`.\n * 3. `default` — `nexus-agents`, this repository's own name.\n *\n * Decided by a 7-voter panel (option C, 4 of 7; job\n * `job-consensus_vote-b97309d13ca77db9`) with two safeguards adopted from the\n * minority: the SOURCE is disclosed on the response so a forgotten input reads\n * as `default` next to the verdict instead of a silent mis-scope, and no\n * candidate — from any source — reaches a prompt unless it matches\n * {@link VOTER_PROJECT_PATTERN}. Derivation is a pure parse of files the\n * process can already read; it never spawns `git`.\n *\n * @module cli/voter-project\n */\n\nimport { readFileSync, statSync } from 'node:fs';\nimport { dirname, isAbsolute, join, resolve } from 'node:path';\nimport { z } from 'zod';\nimport type { ILogger } from '../core/index.js';\nimport { findRepoRoot } from '../config/repo-root-detection.js';\nimport { DEFAULT_VOTER_PROJECT } from './voter-prompts.js';\n\n/**\n * The only shape a project name may take before it is interpolated into a\n * prompt. Admits `owner/repo`, scoped npm names (`@scope/name`) and plain\n * package names; refuses whitespace, quotes and every shell metacharacter.\n */\nexport const VOTER_PROJECT_PATTERN = /^[A-Za-z0-9._/@-]{1,200}$/;\n\n/**\n * The optional `project` input every panel tool accepts (#6110, #6123):\n * `consensus_vote`, `pr_review` and `supply_chain_tradeoff_panel` share this\n * one field so the pattern and its description are stated once.\n */\nexport const VoterProjectInputSchema = z\n .string()\n .regex(VOTER_PROJECT_PATTERN)\n .optional()\n .describe(\n 'The project the panel is judging (#6110), e.g. `acme/widgets` — it replaces `nexus-agents` ' +\n \"in every voter's system prompt, so a consuming repository is not judged against this \" +\n \"one's mission and governance files. When omitted the name is DERIVED from the server's \" +\n 'working directory (the `origin` remote as `owner/repo`, else the nearest `package.json` ' +\n 'name) and falls back to `nexus-agents`; the response discloses which on `project.source`. ' +\n 'Letters, digits and `._/@-` only, at most 200 characters.'\n );\n\n/** Which of the three sources supplied the project name. */\nexport type VoterProjectSource = 'input' | 'derived' | 'default';\n\n/** The project the voter panel was told it is judging, and how that was decided. */\nexport interface ResolvedVoterProject {\n readonly name: string;\n readonly source: VoterProjectSource;\n}\n\n/** A candidate the resolver considered and refused, with the reason. */\nexport interface RejectedVoterProjectCandidate {\n readonly origin: 'input' | 'git-origin' | 'package-name';\n readonly candidate: string;\n readonly reason: string;\n}\n\n/** {@link ResolvedVoterProject} plus the candidates rejected on the way to it. */\nexport interface VoterProjectResolution extends ResolvedVoterProject {\n /** Rejected candidates in the order they were tried; empty when none were. */\n readonly rejected: readonly RejectedVoterProjectCandidate[];\n}\n\n/** Ancestor-walk cap; mirrors `findRepoRoot`'s guard against pathological trees. */\nconst MAX_ANCESTOR_DEPTH = 64;\n\n/** Longest `.git/config` or `package.json` the resolver will read. */\nconst MAX_READ_BYTES = 64 * 1024;\n\nfunction readBounded(path: string): string | undefined {\n try {\n if (statSync(path).size > MAX_READ_BYTES) return undefined;\n return readFileSync(path, 'utf-8');\n } catch {\n return undefined;\n }\n}\n\n/**\n * Locate the git config that holds the remotes for the repo containing `cwd`.\n *\n * A worktree's `.git` is a FILE (`gitdir: <path>`) whose gitdir carries a\n * `commondir` back-reference to the main repository's `.git`, where the remotes\n * live. Both hops are plain file reads.\n */\nfunction locateGitConfig(cwd: string): string | undefined {\n const repoRoot = findRepoRoot(cwd);\n if (repoRoot === null) return undefined;\n const dotGit = join(repoRoot, '.git');\n try {\n if (statSync(dotGit).isDirectory()) return join(dotGit, 'config');\n } catch {\n return undefined;\n }\n const gitdir = worktreeGitDir(repoRoot, dotGit);\n if (gitdir === undefined) return undefined;\n const commondir = readBounded(join(gitdir, 'commondir'))?.trim();\n const commonRoot =\n commondir === undefined || commondir === '' ? gitdir : resolve(gitdir, commondir);\n return join(commonRoot, 'config');\n}\n\n/** The gitdir a worktree's `.git` FILE points at, absolute; undefined when it is not one. */\nfunction worktreeGitDir(repoRoot: string, dotGitFile: string): string | undefined {\n const target = readBounded(dotGitFile)?.match(/^gitdir:\\s*(.+?)\\s*$/m)?.[1];\n if (target === undefined) return undefined;\n return isAbsolute(target) ? target : resolve(repoRoot, target);\n}\n\n/**\n * The `url` of `[remote \"origin\"]` in a git config, or undefined. Sections are\n * scanned by header so a `url` under another remote is never picked up.\n */\nfunction originUrlFromConfig(config: string): string | undefined {\n let inOrigin = false;\n for (const rawLine of config.split('\\n')) {\n const line = rawLine.trim();\n if (line.startsWith('[')) {\n inOrigin = /^\\[remote\\s+\"origin\"\\]$/.test(line);\n continue;\n }\n if (!inOrigin) continue;\n const match = line.match(/^url\\s*=\\s*(.+)$/);\n if (match?.[1] !== undefined) return match[1].trim();\n }\n return undefined;\n}\n\n/**\n * `owner/repo` from a git remote URL, or undefined when the URL has fewer than\n * two path segments. Handles `git@host:owner/repo(.git)`,\n * `scheme://[user@]host[:port]/owner/repo(.git)` and nested host paths (the\n * last two segments win).\n */\nfunction ownerRepoFromRemoteUrl(url: string): string | undefined {\n const schemeMatch = url.match(/^[a-z][a-z0-9+.-]*:\\/\\/[^/]+\\/(.+)$/i);\n const scpMatch = url.match(/^[^/@:]+@[^/:]+:(.+)$/);\n const path = schemeMatch?.[1] ?? scpMatch?.[1];\n if (path === undefined) return undefined;\n const segments = path\n .replace(/\\/+$/, '')\n .replace(/\\.git$/, '')\n .split('/')\n .filter((segment) => segment !== '');\n if (segments.length < 2) return undefined;\n return segments.slice(-2).join('/');\n}\n\n/** `name` of the nearest `package.json` at or above `cwd`, when it is a string. */\nfunction nearestPackageName(cwd: string): string | undefined {\n let current = resolve(cwd);\n for (let depth = 0; depth < MAX_ANCESTOR_DEPTH; depth++) {\n const raw = readBounded(join(current, 'package.json'));\n if (raw !== undefined) {\n try {\n const parsed: unknown = JSON.parse(raw);\n if (typeof parsed === 'object' && parsed !== null && 'name' in parsed) {\n return typeof parsed.name === 'string' ? parsed.name : undefined;\n }\n } catch {\n return undefined;\n }\n return undefined;\n }\n const parent = dirname(current);\n if (parent === current) return undefined;\n current = parent;\n }\n return undefined;\n}\n\n/** Why a candidate fails {@link VOTER_PROJECT_PATTERN}, or undefined when it passes. */\nfunction patternRejection(candidate: string): string | undefined {\n if (VOTER_PROJECT_PATTERN.test(candidate)) return undefined;\n return `does not match the project-name pattern ${VOTER_PROJECT_PATTERN.source}`;\n}\n\n/** The derived candidates in fallback order, each tagged with where it came from. */\nfunction derivedCandidates(cwd: string): ReadonlyArray<{\n origin: 'git-origin' | 'package-name';\n candidate: string | undefined;\n absentReason: string;\n}> {\n const configPath = locateGitConfig(cwd);\n const config = configPath === undefined ? undefined : readBounded(configPath);\n const originUrl = config === undefined ? undefined : originUrlFromConfig(config);\n const ownerRepo = originUrl === undefined ? undefined : ownerRepoFromRemoteUrl(originUrl);\n return [\n {\n origin: 'git-origin',\n candidate: ownerRepo,\n absentReason:\n originUrl === undefined\n ? 'no origin remote'\n : `origin URL carries no owner/repo path: ${originUrl}`,\n },\n { origin: 'package-name', candidate: nearestPackageName(cwd), absentReason: 'no package name' },\n ];\n}\n\n/**\n * Resolve the project the voter panel should judge against.\n *\n * `input` wins when it passes the pattern; otherwise the `origin` remote of the\n * repository containing `cwd`, then the nearest `package.json` name; otherwise\n * {@link DEFAULT_VOTER_PROJECT}. A candidate that fails the pattern is recorded\n * on `rejected` with its reason and the next source is tried — so the result\n * ALWAYS carries a name the prompt may safely interpolate, and the caller can\n * log exactly what was refused. Pure over the filesystem: no subprocess.\n */\nexport function resolveVoterProject(args: {\n readonly input?: string | undefined;\n readonly cwd: string;\n}): VoterProjectResolution {\n const rejected: RejectedVoterProjectCandidate[] = [];\n\n if (args.input !== undefined) {\n const reason = patternRejection(args.input);\n if (reason === undefined) return { name: args.input, source: 'input', rejected };\n rejected.push({ origin: 'input', candidate: args.input, reason });\n }\n\n for (const { origin, candidate, absentReason } of derivedCandidates(args.cwd)) {\n if (candidate === undefined) {\n // An absent candidate is not a rejection — nothing was refused. Only an\n // origin URL that EXISTED but carried no owner/repo is worth recording.\n if (origin === 'git-origin' && absentReason !== 'no origin remote') {\n rejected.push({ origin, candidate: '', reason: absentReason });\n }\n continue;\n }\n const reason = patternRejection(candidate);\n if (reason === undefined) return { name: candidate, source: 'derived', rejected };\n rejected.push({ origin, candidate, reason });\n }\n\n return { name: DEFAULT_VOTER_PROJECT, source: 'default', rejected };\n}\n\n/**\n * Resolve the project a panel judges and log it once per run: the chosen name\n * and source at info, and every candidate the pattern refused at warn with its\n * reason, so a `default` next to a verdict is explained. Shared by every tool\n * that runs a voter panel (#6123); each resolves ONCE per run.\n */\nexport function resolveAndLogVoterProject(\n input: string | undefined,\n logger: ILogger\n): ResolvedVoterProject {\n const { name, source, rejected } = resolveVoterProject({ input, cwd: process.cwd() });\n for (const r of rejected) {\n logger.warn('Voter project candidate rejected', {\n origin: r.origin,\n candidate: r.candidate,\n reason: r.reason,\n });\n }\n logger.info('Voter project resolved', { project: name, source });\n return { name, source };\n}\n","/**\n * Option gate for multi-option consensus votes (#4472, increment 2).\n *\n * When a proposal declares named `options`, clearing the ordinary\n * approve/reject bar is no longer sufficient: the leading option must clear the\n * threshold too. Without this, `unanimous` is the *easiest* bar on a\n * multi-option proposal, because every voter approves while choosing something\n * different and a 6-1 split records as 7-0, 100% (#4452).\n *\n * ## Composition, not replacement\n *\n * The gate is applied ON TOP of the existing strategy verdict — both bars must\n * be cleared. Three reasons:\n *\n * - **Rejections keep their meaning.** The option tally counts only approvers,\n * so on its own it would read \"4 approve for X, 3 reject\" as 4/4 unanimous.\n * The existing approve/reject gate already fails that case; composing keeps\n * it failing.\n * - **Monotone.** Adding a constraint can only make approval harder, so\n * declaring `options` can never turn a rejected vote into an approved one.\n * - **No-options behaviour is byte-identical**, because the gate is a no-op\n * when no options are declared — and `strategies.ts` stays untouched, which\n * matters on the governor path.\n *\n * The two measurements stay separate on the response: `approvalPercentage`\n * remains the approve/reject figure and the option share is reported alongside\n * it. Collapsing them into one number would hide which bar actually failed.\n *\n * @module mcp/tools/consensus-vote-option-gate\n * (Source: Issue #4472)\n */\n\nimport {\n evaluateOptionThreshold,\n tallyOptions,\n type OptionThreshold,\n type OptionThresholdVerdict,\n} from '../../consensus/option-tally.js';\n\n/**\n * The option verdict as `executeVoting` stores it, with the veto explanation\n * attached (#4529).\n *\n * The prose lives here rather than on {@link OptionThresholdVerdict} to keep\n * `consensus/option-tally.ts` a pure tally module, and rather than on\n * `policyReason` because that field means exactly one thing — \"an error policy\n * VOIDED this vote\". Borrowing it for a split made `resolveVoteDecision` stamp\n * `no_quorum` on a panel that had in fact convened and disagreed.\n */\nexport interface OptionGateVerdict extends OptionThresholdVerdict {\n /** Human-readable explanation, present only when the gate vetoed. */\n readonly reason?: string;\n}\nimport type { AgentVoteResult } from '../../cli/vote-types.js';\n\n/** Strategies whose bar the option gate mirrors. */\nconst STRATEGY_TO_OPTION_THRESHOLD: Record<string, OptionThreshold> = {\n unanimous: 'unanimous',\n supermajority: 'supermajority',\n simple_majority: 'majority',\n // higher_order and proof_of_learning aggregate differently; they are gated at\n // the majority bar so a declared-option split still cannot pass unnoticed.\n higher_order: 'majority',\n proof_of_learning: 'majority',\n opinion_wise: 'majority',\n};\n\n/**\n * Map a voting strategy (or legacy threshold) onto the option bar to apply.\n *\n * An unrecognised strategy falls back to `majority` rather than to \"no gate\",\n * so a strategy added later cannot silently opt out of option checking.\n */\nexport function optionThresholdFor(strategy: string, legacyThreshold?: string): OptionThreshold {\n if (legacyThreshold === 'unanimous') return 'unanimous';\n if (legacyThreshold === 'supermajority') return 'supermajority';\n return STRATEGY_TO_OPTION_THRESHOLD[strategy] ?? 'majority';\n}\n\nexport interface OptionGateOutcome {\n /** The tally + verdict, for reporting on the response and the record. */\n readonly verdict: OptionThresholdVerdict;\n /**\n * True when the gate vetoed an otherwise-approved vote. Drives the\n * human-readable reason; a vote already rejected on approvals is untouched.\n */\n readonly vetoed: boolean;\n /** Populated only when `vetoed`, explaining which bar failed and why. */\n readonly reason?: string;\n}\n\n/**\n * Evaluate the option gate for a completed vote.\n *\n * `approvedByStrategy` is the ordinary verdict. The returned `vetoed` flag is\n * true only when that verdict was `true` and the leading option failed its bar,\n * which is the sole case where this gate changes an outcome.\n */\nexport function evaluateOptionGate(\n votes: readonly AgentVoteResult[],\n declaredOptions: readonly string[],\n threshold: OptionThreshold,\n approvedByStrategy: boolean\n): OptionGateOutcome {\n const tally = tallyOptions(\n votes.map((v) => ({\n decision: v.vote.decision,\n ...(v.selectedOption !== undefined ? { selectedOption: v.selectedOption } : {}),\n })),\n declaredOptions\n );\n const verdict = evaluateOptionThreshold(tally, threshold);\n\n if (!approvedByStrategy || verdict.approved) {\n return { verdict, vetoed: false };\n }\n\n return { verdict, vetoed: true, reason: describeVeto(verdict) };\n}\n\n/**\n * Explain a veto in terms a caller can act on.\n *\n * Names the coverage explicitly, because a share alone cannot distinguish a\n * real split from unreadable responses — `4 pick X + 3 unparseable` and a\n * genuine 4/3 split both read 57%.\n */\nfunction describeVeto(verdict: OptionThresholdVerdict): string {\n const pct = (verdict.leadingShare * 100).toFixed(1);\n const leader =\n verdict.leadingOption !== undefined\n ? `leading option \"${verdict.leadingOption}\" held ${String(verdict.leadingCount)}/${String(verdict.approverCount)} approvers (${pct}%)`\n : 'no voter selected a declared option';\n\n const coverage =\n verdict.unattributedApprovals > 0\n ? ` ${String(verdict.unattributedApprovals)} of ${String(verdict.approverCount)} approvers recorded no usable selection, which lowers the leading share; their choice is unmeasured, not counted as dissent.`\n : '';\n\n return `Approvals cleared the ${verdict.threshold} bar, but the option split did not: ${leader}.${coverage}`;\n}\n","/**\n * nexus-agents/consensus - Multi-Round Voting Protocol Types\n *\n * Multi-Round Voting Protocol Types (Issue #100)\n * Based on arXiv:2512.21352 - Multi-Agent Committees for Code Review\n */\n\nimport { z } from 'zod';\nimport type { Vote } from './types-core.js';\nimport { SUPERMAJORITY_THRESHOLD } from './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: 2/3, approximately 0.667) */\n agreementThreshold: number;\n /** Enable anti-sycophancy detection (default: true) */\n enableAntiSycophancy: boolean;\n /** Similarity threshold for sycophancy detection (default: 0.8) */\n sycophancyThreshold: number;\n}\n\nexport const VotingProtocolConfigSchema = z.object({\n committeeSize: z.number().int().min(2).max(7).default(3),\n maxRounds: z.number().int().min(1).max(5).default(3),\n roundTimeoutMs: z.number().int().positive().default(VOTING_ROUND_DEFAULT_TIMEOUT_MS),\n agreementThreshold: z.number().min(0.5).max(1).default(SUPERMAJORITY_THRESHOLD),\n enableAntiSycophancy: z.boolean().default(true),\n sycophancyThreshold: z.number().min(0).max(1).default(0.8),\n});\n\nexport const DEFAULT_VOTING_PROTOCOL_CONFIG: VotingProtocolConfig = {\n committeeSize: 3,\n maxRounds: 3,\n roundTimeoutMs: VOTING_ROUND_DEFAULT_TIMEOUT_MS,\n // Default agreement level IS the supermajority (2/3) — single source (#3571).\n agreementThreshold: SUPERMAJORITY_THRESHOLD,\n enableAntiSycophancy: true,\n sycophancyThreshold: 0.8,\n};\n\n/**\n * Session state for a voting protocol instance.\n */\nexport interface VotingSession {\n id: string;\n topic: string;\n committee: string[]; // Agent IDs\n rounds: VotingRound[];\n currentRound: number;\n config: VotingProtocolConfig;\n status: 'active' | 'completed' | 'aborted';\n createdAt: string;\n completedAt?: string;\n finalResult?: VotingProtocolResult;\n}\n\n/**\n * Final result of a voting protocol session.\n */\nexport interface VotingProtocolResult {\n sessionId: string;\n topic: string;\n outcome: 'approved' | 'rejected' | 'needs_revision' | 'no_consensus';\n consolidatedFindings: ConsolidatedFinding[];\n roundSummaries: RoundSummary[];\n agreementScore: number;\n sycophancyDetected: boolean;\n totalDurationMs: number;\n participatingAgents: string[];\n}\n\n/**\n * A consolidated finding after deliberation.\n */\nexport interface ConsolidatedFinding {\n id: string;\n category: AgentFinding['category'];\n severity: AgentFinding['severity'];\n description: string;\n location?: string;\n suggestion?: string;\n supportingAgents: string[];\n agreementRatio: number;\n originalFindings: AgentFinding[];\n}\n\n/**\n * Summary of a single round.\n */\nexport interface RoundSummary {\n roundNumber: number;\n phase: VotingRoundPhase;\n findingsCount: number;\n votesCount: number;\n agreementScore: number;\n durationMs: number;\n}\n\n/**\n * Interface for the multi-round voting protocol.\n * (Source: Issue #100, arXiv:2512.21352)\n */\nexport interface IVotingProtocol {\n /** Create a new voting session with a committee */\n createSession(\n topic: string,\n committee: string[],\n config?: Partial<VotingProtocolConfig>\n ): VotingSession;\n\n /** Start the analysis round (Round 1) */\n startAnalysisRound(sessionId: string): Promise<VotingRound>;\n\n /** Submit findings from an agent during analysis */\n submitFindings(sessionId: string, agentId: string, findings: AgentFinding[]): Promise<void>;\n\n /** Start the deliberation round (Round 2) */\n startDeliberationRound(sessionId: string): Promise<VotingRound>;\n\n /** Vote on findings during deliberation */\n voteOnFinding(sessionId: string, vote: FindingVote): Promise<void>;\n\n /** Start the consensus round (Round 3) */\n startConsensusRound(sessionId: string): Promise<VotingRound>;\n\n /** Submit final vote during consensus */\n submitFinalVote(sessionId: string, agentId: string, vote: Vote): Promise<void>;\n\n /** Get the final result (closes session if complete) */\n getResult(sessionId: string): Promise<VotingProtocolResult | null>;\n\n /** Check for sycophancy in the current round */\n detectSycophancy(sessionId: string): SycophancyReport;\n\n /** Get the current session state */\n getSession(sessionId: string): VotingSession | undefined;\n}\n\n/**\n * Report from sycophancy detection.\n */\nexport interface SycophancyReport {\n detected: boolean;\n confidenceScore: number;\n indicators: SycophancyIndicator[];\n affectedAgents: string[];\n recommendation: string;\n}\n\n/**\n * Individual sycophancy indicator.\n */\nexport interface SycophancyIndicator {\n type: 'premature_consensus' | 'opinion_convergence' | 'confidence_inflation' | 'echo_chamber';\n description: string;\n severity: 'low' | 'medium' | 'high';\n agents: string[];\n}\n","/**\n * nexus-agents/consensus - Weighted Byzantine Voting Types\n *\n * Weighted Byzantine Voting Types (Issue #103)\n * Based on CP-WBFT (arXiv:2511.10400)\n */\n\nimport { z } from 'zod';\nimport type { Vote } from './types-core.js';\nimport { SUPERMAJORITY_THRESHOLD } from './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: 2/3, approximately 0.667) */\n readonly quorumThreshold: number;\n}\n\nexport const WeightedVotingConfigSchema = z.object({\n minWeight: z.number().min(0).max(1).default(0.1),\n maxByzantineFraction: z.number().min(0).max(0.5).default(0.33),\n weightDecayFactor: z.number().min(0.5).max(1).default(0.9),\n weightRecoveryFactor: z.number().min(1).max(2).default(1.05),\n minTrustScore: z.number().min(0).max(1).default(0.3),\n byzantineFlagThreshold: z.number().int().positive().default(3),\n initialWeight: z.number().min(0).max(1).default(0.5),\n quorumThreshold: z.number().min(0.5).max(1).default(SUPERMAJORITY_THRESHOLD),\n});\n\nexport const DEFAULT_WEIGHTED_VOTING_CONFIG: WeightedVotingConfig = {\n minWeight: 0.1,\n maxByzantineFraction: 0.33,\n weightDecayFactor: 0.9,\n weightRecoveryFactor: 1.05,\n minTrustScore: 0.3,\n byzantineFlagThreshold: 3,\n initialWeight: 0.5,\n // Default quorum IS the supermajority (2/3) — single source (#3571).\n quorumThreshold: SUPERMAJORITY_THRESHOLD,\n};\n\n/**\n * Interface for weighted Byzantine voting.\n * (Source: Issue #103, arXiv:2511.10400 - CP-WBFT)\n */\nexport interface IWeightedVoting {\n /** Calculate vote weight for an agent */\n calculateWeight(agentId: string): number;\n\n /** Update agent performance based on task outcome */\n updatePerformance(agentId: string, outcome: TaskOutcomeStatus): void;\n\n /** Run weighted consensus on votes */\n weightedConsensus(votes: ReadonlyMap<string, Vote>): WeightedConsensusResult;\n\n /** Register a new agent */\n registerAgent(agentId: string): void;\n\n /** Get agent performance record */\n getAgentRecord(agentId: string): WeightedAgentRecord | undefined;\n\n /** Flag agent for Byzantine behavior */\n flagByzantine(agentId: string, reason: string): void;\n\n /** Get all agent records */\n getAllRecords(): readonly WeightedAgentRecord[];\n\n /** Check if agent can vote */\n canVote(agentId: string): boolean;\n\n /** Recalibrate all weights based on global performance */\n recalibrateWeights(): void;\n}\n","/**\n * nexus-agents/consensus - Higher-Order Voting Types\n *\n * Type definitions for Opinion-Wise (OW) and Independent Subset Partition (ISP)\n * voting methods that account for correlations between agent opinions.\n *\n * 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 /**\n * Average internal independence score (lower = more independent).\n *\n * Averaged over the pairs that HAVE a correlation, so read it together with\n * {@link pairCoverage}: a subset whose pairs were measured at 0 and one whose\n * pairs were never observed both score 0, and 0 is the score that earns the\n * maximum posterior weight.\n */\n readonly independenceScore: number;\n /**\n * How many of the subset's agent pairs actually had a correlation, out of how\n * many exist.\n *\n * `observed < total` means {@link independenceScore} is an average over a\n * subset of the pairs — the unobserved ones contributed nothing rather than\n * being represented as unknown. A singleton has `total: 0`: there is no pair\n * to observe, so its score is not a measurement at all.\n */\n readonly pairCoverage: { readonly observed: number; readonly total: number };\n /** Number of observations supporting this grouping */\n readonly observationCount: number;\n}\n\nexport const IndependentSubsetSchema = z.object({\n id: z.string(),\n agentIds: z.array(z.string()),\n independenceScore: z.number().min(0).max(1),\n pairCoverage: z.object({\n observed: z.number().int().nonnegative(),\n total: z.number().int().nonnegative(),\n }),\n observationCount: z.number().int().nonnegative(),\n});\n\n// ============================================================================\n// VOTING HISTORY TYPES\n// ============================================================================\n\n/**\n * Record of a single voting observation for correlation tracking.\n */\nexport interface VotingObservation {\n /** Unique proposal ID */\n readonly proposalId: string;\n /** Agent who cast the vote */\n readonly agentId: string;\n /** The vote decision */\n readonly decision: VoteDecision;\n /** Confidence level (0-1) */\n readonly confidence: number;\n /** Whether the vote aligned with the final outcome */\n readonly alignedWithOutcome: boolean;\n /** Timestamp of the vote */\n readonly timestamp: Date;\n /** Pinned model identity used to select the correlation partition. */\n readonly modelKey?: string;\n /** Model that actually answered, retained for provenance only. */\n readonly observedModel?: string;\n}\n\nexport const VotingObservationSchema = z.object({\n proposalId: z.string(),\n agentId: z.string(),\n decision: z.enum(['approve', 'reject', 'abstain']),\n confidence: z.number().min(0).max(1),\n alignedWithOutcome: z.boolean(),\n timestamp: z.date(),\n modelKey: z.string().optional(),\n observedModel: z.string().optional(),\n});\n\n/** Model identities associated with one correlation-recording operation. */\nexport interface CorrelationRecordContext {\n /** Role-to-pinned-model map used for correlation partition selection. */\n readonly modelPins: ReadonlyMap<string, string>;\n /** Role-to-serving-model map retained only as observation provenance. */\n readonly observedModels?: ReadonlyMap<string, string>;\n}\n\n/**\n * Aggregated voting history for a pair of agents.\n */\nexport interface PairwiseVotingHistory {\n /** Agent pair key */\n readonly pairKey: AgentPairKey;\n /** Number of proposals where both agents voted */\n readonly jointObservations: number;\n /** Number of times both agents agreed */\n readonly agreements: number;\n /** Number of times agents disagreed */\n readonly disagreements: number;\n /** Computed correlation coefficient */\n readonly correlation: CorrelationCoefficient;\n /** Last update timestamp */\n readonly lastUpdated: Date;\n}\n\nexport const PairwiseVotingHistorySchema = z.object({\n pairKey: z.string() as z.ZodType<AgentPairKey>,\n jointObservations: z.number().int().nonnegative(),\n agreements: z.number().int().nonnegative(),\n disagreements: z.number().int().nonnegative(),\n correlation: CorrelationCoefficientSchema,\n lastUpdated: z.date(),\n});\n\n// ============================================================================\n// HIGHER-ORDER VOTING CONFIG\n// ============================================================================\n\n/**\n * Configuration for higher-order voting.\n * Correlation aggregates are lifetime evidence; retained records are count-bounded\n * by `maxProposals` FIFO and `maxObservationsPerAgent`, and active history is\n * partitioned by each role's pinned model. The legacy correlation lifetime keys\n * are deprecated and ignored.\n */\nexport interface HigherOrderVotingConfig {\n /** Minimum observations before using correlation data (default: 10) */\n readonly minObservationsForCorrelation: number;\n /** Correlation threshold to consider agents correlated (default: 0.3) */\n readonly correlationThreshold: number;\n /**\n * @deprecated Ignored since 8.x: correlation evidence is lifetime and partitioned by the role's pinned model (#5555); nothing reads this value. Removed in the next major (#5564).\n */\n readonly correlationMaxAgeMs: number;\n /** Independence threshold for ISP grouping (default: 0.2) */\n readonly independenceThreshold: number;\n /** Whether to fall back to simple voting when correlation data insufficient */\n readonly fallbackToSimpleVoting: boolean;\n /**\n * @deprecated Ignored since 8.x: correlation evidence is lifetime and partitioned by the role's pinned model (#5555); nothing reads this value. Removed in the next major (#5564).\n */\n readonly observationDecayFactor: number;\n /** Maximum observations to store per agent before FIFO eviction (default: 1000) */\n readonly maxObservationsPerAgent: number;\n /** Maximum total proposals to track before evicting oldest (default: 5000) */\n readonly maxProposals: number;\n /** Maximum pairwise history entries before LRU eviction (default: 100) */\n readonly maxTrackedPairs: number;\n}\n\nexport const HigherOrderVotingConfigSchema = z.object({\n minObservationsForCorrelation: z.number().int().positive().default(10),\n correlationThreshold: z.number().min(0).max(1).default(0.3),\n /**\n * @deprecated Ignored since 8.x: correlation evidence is lifetime and partitioned by the role's pinned model (#5555); nothing reads this value. Removed in the next major (#5564).\n */\n correlationMaxAgeMs: z.number().int().positive().default(86400000), // 24 hours\n independenceThreshold: z.number().min(0).max(1).default(0.2),\n fallbackToSimpleVoting: z.boolean().default(true),\n /**\n * @deprecated Ignored since 8.x: correlation evidence is lifetime and partitioned by the role's pinned model (#5555); nothing reads this value. Removed in the next major (#5564).\n */\n observationDecayFactor: z.number().min(0).max(1).default(0.95),\n maxObservationsPerAgent: z.number().int().positive().default(1000),\n maxProposals: z.number().int().positive().default(5000),\n maxTrackedPairs: z.number().int().positive().default(100),\n});\n\nexport const DEFAULT_HIGHER_ORDER_CONFIG: HigherOrderVotingConfig = {\n minObservationsForCorrelation: 10,\n correlationThreshold: 0.3,\n correlationMaxAgeMs: 86400000, // 24 hours\n independenceThreshold: 0.2,\n fallbackToSimpleVoting: true,\n observationDecayFactor: 0.95,\n maxObservationsPerAgent: 1000,\n maxProposals: 5000,\n maxTrackedPairs: 100,\n};\n\n// ============================================================================\n// HIGHER-ORDER VOTING RESULTS\n// ============================================================================\n\n/**\n * Result of Bayesian aggregation with correlation awareness.\n */\nexport interface HigherOrderVotingResult {\n /** Final decision */\n readonly decision: 'approve' | 'reject' | 'no_consensus';\n /** Posterior probability of approval */\n readonly posteriorApproval: number;\n /** Posterior probability of rejection */\n readonly posteriorRejection: number;\n /** Effective number of independent votes */\n readonly effectiveVoteCount: number;\n /** Whether correlation data was sufficient */\n readonly usedCorrelationData: boolean;\n /** Method used: 'ow' (opinion-wise), 'isp', or 'simple' (fallback) */\n readonly method: 'ow' | 'isp' | 'simple';\n /** Improvement over baseline majority voting (percentage points) */\n readonly improvementOverBaseline: number;\n /** Independent subsets used (if ISP method) */\n readonly independentSubsets?: readonly IndependentSubset[];\n /** Agents whose votes were down-weighted due to correlation */\n readonly downweightedAgents: readonly string[];\n /** Reasoning for the decision */\n readonly reasoning: string;\n}\n\nexport const HigherOrderVotingResultSchema = z.object({\n decision: z.enum(['approve', 'reject', 'no_consensus']),\n posteriorApproval: z.number().min(0).max(1),\n posteriorRejection: z.number().min(0).max(1),\n effectiveVoteCount: z.number().nonnegative(),\n usedCorrelationData: z.boolean(),\n method: z.enum(['ow', 'isp', 'simple']),\n improvementOverBaseline: z.number(),\n independentSubsets: z.array(IndependentSubsetSchema).optional(),\n downweightedAgents: z.array(z.string()),\n reasoning: z.string(),\n});\n\n// ============================================================================\n// CORRELATION TRACKER INTERFACE\n// ============================================================================\n\n/**\n * Statistics about correlation tracking.\n */\nexport interface CorrelationTrackerStats {\n /** Total agents being tracked */\n readonly totalAgents: number;\n /** Total agent pairs with correlation data */\n readonly trackedPairs: number;\n /** Total voting observations recorded */\n readonly totalObservations: number;\n /** Average correlation across all pairs */\n readonly averageCorrelation: number;\n /** Number of identified independent subsets */\n readonly independentSubsetCount: number;\n /** Pairs with sufficient data for correlation calculation */\n readonly pairsWithSufficientData: number;\n}\n\nexport const CorrelationTrackerStatsSchema = z.object({\n totalAgents: z.number().int().nonnegative(),\n trackedPairs: z.number().int().nonnegative(),\n totalObservations: z.number().int().nonnegative(),\n averageCorrelation: z.number(),\n independentSubsetCount: z.number().int().nonnegative(),\n pairsWithSufficientData: z.number().int().nonnegative(),\n});\n\n/**\n * Interface for correlation tracking between agents.\n */\nexport interface ICorrelationTracker {\n /** Select the active model partition for each pinned role. */\n setCurrentModelPins?(modelPins: ReadonlyMap<string, string>): void;\n\n /**\n * Record a vote and its outcome for correlation tracking.\n */\n recordVote(\n agentId: string,\n vote: Vote,\n outcome: 'approved' | 'rejected',\n context?: CorrelationRecordContext\n ): void;\n\n /**\n * Record votes from multiple agents for the same proposal.\n */\n recordProposalVotes(\n proposalId: string,\n votes: ReadonlyMap<string, Vote>,\n outcome: 'approved' | 'rejected',\n context?: CorrelationRecordContext\n ): void;\n\n /**\n * Compute the full correlation matrix for all tracked agents.\n */\n computeCorrelationMatrix(): CorrelationMatrix;\n\n /**\n * Get correlation between two specific agents.\n * Returns undefined if insufficient data.\n */\n getCorrelation(agentA: string, agentB: string): CorrelationCoefficient | undefined;\n\n /**\n * Identify groups of agents that vote independently.\n */\n identifyIndependentSubsets(): readonly IndependentSubset[];\n\n /**\n * Check if there is sufficient correlation data for a set of agents.\n */\n hasSufficientData(agentIds: readonly string[]): boolean;\n\n /**\n * Get statistics about the correlation tracker.\n */\n getStats(): CorrelationTrackerStats;\n\n /**\n * Clear all recorded data.\n */\n clear(): void;\n}\n\n// ============================================================================\n// OW VOTING INTERFACE\n// ============================================================================\n\n/**\n * Interface for Opinion-Wise higher-order voting.\n */\nexport interface IHigherOrderVoting {\n /**\n * Aggregate votes using Bayesian correlation-aware method.\n */\n aggregateWithCorrelation(\n votes: ReadonlyMap<string, Vote>,\n correlationMatrix: CorrelationMatrix\n ): HigherOrderVotingResult;\n\n /**\n * Estimate correlation matrix from voting history.\n */\n estimateCorrelation(tracker: ICorrelationTracker): CorrelationMatrix;\n\n /**\n * Compute result using Independent Subset Partition method.\n */\n computeISP(\n votes: ReadonlyMap<string, Vote>,\n independentSubsets: readonly IndependentSubset[]\n ): HigherOrderVotingResult;\n\n /**\n * Full pipeline: estimate correlation, compute result.\n *\n * `tracker` is OPTIONAL (#3173): when omitted, the instance uses the tracker\n * injected at construction (`OWVotingOptions.tracker`), letting higher-order\n * voting be reused as a building block without threading the tracker through\n * every call. A per-call `tracker` still wins. Throws if neither is available.\n */\n aggregate(\n votes: ReadonlyMap<string, Vote>,\n tracker?: ICorrelationTracker\n ): HigherOrderVotingResult;\n\n /**\n * Get the current configuration.\n */\n getConfig(): HigherOrderVotingConfig;\n}\n","/**\n * nexus-agents/consensus - Higher-Order Voting Helpers\n *\n * Helper functions for Opinion-Wise (OW) and Independent Subset Partition (ISP)\n * voting methods. Extracted from higher-order-voting.ts to maintain file size limits.\n *\n * @module consensus/higher-order-helpers\n * (Source: Issue #333, #339)\n */\n\nimport type { Vote } from './types-core.js';\nimport type {\n CorrelationMatrix,\n HigherOrderVotingResult,\n IndependentSubset,\n} from './higher-order-types.js';\nimport { createAgentPairKey } from './higher-order-types.js';\n\n/**\n * Result of Bayesian aggregation.\n */\nexport interface BayesianAggregateResult {\n readonly posteriorApproval: number;\n readonly posteriorRejection: number;\n readonly effectiveVoteCount: number;\n readonly downweightedAgents: string[];\n}\n\n/**\n * Result of subset aggregation.\n */\nexport interface SubsetAggregationResult {\n readonly subsetResults: Array<{ approval: number; rejection: number; weight: number }>;\n readonly downweightedAgents: string[];\n}\n\n/**\n * Result of combined subset results.\n */\nexport interface CombinedSubsetResult {\n readonly posteriorApproval: number;\n readonly posteriorRejection: number;\n readonly totalWeight: number;\n}\n\n/**\n * Check if there is sufficient correlation data for analysis.\n */\nexport function hasSufficientCorrelationData(\n agentIds: readonly string[],\n correlationMatrix: CorrelationMatrix\n): boolean {\n if (agentIds.length < 2) return false;\n\n let pairsWithData = 0;\n const totalPairs = (agentIds.length * (agentIds.length - 1)) / 2;\n\n for (let i = 0; i < agentIds.length; i++) {\n for (let j = i + 1; j < agentIds.length; j++) {\n const agentA = agentIds[i];\n const agentB = agentIds[j];\n if (agentA !== undefined && agentB !== undefined) {\n const pairKey = createAgentPairKey(agentA, agentB);\n if (correlationMatrix.has(pairKey)) {\n pairsWithData++;\n }\n }\n }\n }\n\n return pairsWithData >= Math.ceil(totalPairs * 0.5);\n}\n\n/**\n * Compute effective weights for agents based on correlations.\n * Reduces weights for highly correlated agents.\n */\nexport function computeEffectiveWeights(\n agentIds: readonly string[],\n correlationMatrix: CorrelationMatrix,\n correlationThreshold: number\n): Map<string, number> {\n const weights = new Map<string, number>();\n\n // Start with equal weights\n for (const agentId of agentIds) {\n weights.set(agentId, 1.0);\n }\n\n // Reduce weights for highly correlated agents\n for (let i = 0; i < agentIds.length; i++) {\n for (let j = i + 1; j < agentIds.length; j++) {\n const agentA = agentIds[i];\n const agentB = agentIds[j];\n if (agentA === undefined || agentB === undefined) continue;\n\n const pairKey = createAgentPairKey(agentA, agentB);\n const correlation = correlationMatrix.get(pairKey);\n\n if (correlation !== undefined && correlation > correlationThreshold) {\n // Reduce weight proportionally to correlation\n const reduction = correlation * 0.5;\n const currentWeightA = weights.get(agentA) ?? 1.0;\n const currentWeightB = weights.get(agentB) ?? 1.0;\n\n // Apply reduction to both agents (but less to avoid over-penalizing)\n weights.set(agentA, Math.max(0.1, currentWeightA - reduction * 0.5));\n weights.set(agentB, Math.max(0.1, currentWeightB - reduction * 0.5));\n }\n }\n }\n\n // NOTE (#3172, investigated + rejected): a \"restore uniform weights when all\n // collapse to the floor\" guard was considered but is incorrect. When agents\n // are equally correlated, equal downweighting is the CORRECT behavior (they\n // are equally redundant), and because the Bayesian aggregate is a weighted\n // average, scaling all weights equally is invariant — all-at-floor yields the\n // same posterior as uniform, so it is not degenerate. Restoring uniform would\n // wrongly treat correlated agents as independent and inflate the effective\n // vote count (guarded by the \"all perfectly correlated\" test).\n\n return weights;\n}\n\n/**\n * Perform Bayesian aggregation of votes with effective weights.\n */\nexport function bayesianAggregate(\n votes: ReadonlyMap<string, Vote>,\n effectiveWeights: Map<string, number>\n): BayesianAggregateResult {\n let weightedApproval = 0;\n let weightedRejection = 0;\n let totalWeight = 0;\n const downweightedAgents: string[] = [];\n\n for (const [agentId, vote] of votes) {\n const weight = effectiveWeights.get(agentId) ?? 1.0;\n\n // Track downweighted agents\n if (weight < 0.8) {\n downweightedAgents.push(agentId);\n }\n\n // Weight by confidence and effective weight\n const effectiveWeight = weight * vote.confidence;\n totalWeight += effectiveWeight;\n\n if (vote.decision === 'approve') {\n weightedApproval += effectiveWeight;\n } else if (vote.decision === 'reject') {\n weightedRejection += effectiveWeight;\n }\n // Abstains contribute to total weight but not to either side\n }\n\n const posteriorApproval = totalWeight > 0 ? weightedApproval / totalWeight : 0.5;\n const posteriorRejection = totalWeight > 0 ? weightedRejection / totalWeight : 0.5;\n const effectiveVoteCount = totalWeight;\n\n return { posteriorApproval, posteriorRejection, effectiveVoteCount, downweightedAgents };\n}\n\n/**\n * Aggregate votes within independent subsets.\n */\nexport function aggregateSubsets(\n votes: ReadonlyMap<string, Vote>,\n independentSubsets: readonly IndependentSubset[]\n): SubsetAggregationResult {\n const subsetResults: Array<{ approval: number; rejection: number; weight: number }> = [];\n const downweightedAgents: string[] = [];\n\n for (const subset of independentSubsets) {\n const subsetVotes = new Map<string, Vote>();\n for (const agentId of subset.agentIds) {\n const vote = votes.get(agentId);\n if (vote !== undefined) subsetVotes.set(agentId, vote);\n }\n if (subsetVotes.size === 0) continue;\n\n const { approval, rejection } = countSubsetVotes(subsetVotes);\n const weight = subsetVotes.size * (1 - subset.independenceScore);\n subsetResults.push({ approval, rejection, weight });\n\n // `downweightedAgents` is documented as \"agents whose votes were\n // down-weighted DUE TO CORRELATION\", and it is surfaced to MCP. This branch\n // used to push every singleton, which is subset CARDINALITY, not weight: a\n // singleton whose independence score is 0 gets `1 * (1 - 0) = 1`, the same\n // per-vote multiplier every other agent receives. There was no input for\n // which an ISP-reported downweighted agent actually carried less than its\n // unweighted vote. Measured now, matching what the opinion-wise path does\n // with the same field.\n if (weight < subsetVotes.size) downweightedAgents.push(...subset.agentIds);\n }\n return { subsetResults, downweightedAgents };\n}\n\n/**\n * Combine subset results into overall posterior probabilities.\n */\nexport function combineSubsetResults(\n subsetResults: readonly { approval: number; rejection: number; weight: number }[]\n): CombinedSubsetResult {\n let totalApproval = 0;\n let totalRejection = 0;\n let totalWeight = 0;\n for (const { approval, rejection, weight } of subsetResults) {\n totalApproval += approval * weight;\n totalRejection += rejection * weight;\n totalWeight += weight;\n }\n return {\n posteriorApproval: totalWeight > 0 ? totalApproval / totalWeight : 0.5,\n posteriorRejection: totalWeight > 0 ? totalRejection / totalWeight : 0.5,\n totalWeight,\n };\n}\n\n/**\n * Count votes within a subset, weighted by confidence.\n */\nexport function countSubsetVotes(votes: ReadonlyMap<string, Vote>): {\n approval: number;\n rejection: number;\n} {\n let approval = 0;\n let rejection = 0;\n\n for (const vote of votes.values()) {\n if (vote.decision === 'approve') {\n approval += vote.confidence;\n } else if (vote.decision === 'reject') {\n rejection += vote.confidence;\n }\n }\n\n const total = approval + rejection;\n return {\n approval: total > 0 ? approval / total : 0.5,\n rejection: total > 0 ? rejection / total : 0.5,\n };\n}\n\n/**\n * Determine decision based on posterior probabilities.\n */\nexport function determineHigherOrderDecision(\n posteriorApproval: number,\n posteriorRejection: number\n): 'approve' | 'reject' | 'no_consensus' {\n const diff = Math.abs(posteriorApproval - posteriorRejection);\n\n // Require significant margin for decision\n if (diff < 0.1) {\n return 'no_consensus';\n }\n\n return posteriorApproval > posteriorRejection ? 'approve' : 'reject';\n}\n\n/**\n * Perform simple majority aggregation (no correlation data).\n */\nexport function aggregateSimple(\n votes: ReadonlyMap<string, Vote>,\n buildReasoningFn: (\n decision: 'approve' | 'reject' | 'no_consensus',\n effectiveVotes: number,\n downweightedAgents: string[],\n method: 'ow' | 'isp' | 'simple'\n ) => string\n): HigherOrderVotingResult {\n let approve = 0;\n let reject = 0;\n let total = 0;\n\n for (const vote of votes.values()) {\n if (vote.decision === 'approve') {\n approve++;\n } else if (vote.decision === 'reject') {\n reject++;\n }\n if (vote.decision !== 'abstain') {\n total++;\n }\n }\n\n const posteriorApproval = total > 0 ? approve / total : 0.5;\n const posteriorRejection = total > 0 ? reject / total : 0.5;\n const decision = determineHigherOrderDecision(posteriorApproval, posteriorRejection);\n\n return {\n decision,\n posteriorApproval,\n posteriorRejection,\n effectiveVoteCount: total,\n usedCorrelationData: false,\n method: 'simple',\n improvementOverBaseline: 0,\n downweightedAgents: [],\n reasoning: buildReasoningFn(decision, total, [], 'simple'),\n };\n}\n\n/**\n * Calculate improvement over baseline.\n */\nexport function calculateImprovement(\n posteriorApproval: number,\n posteriorRejection: number,\n decision: 'approve' | 'reject' | 'no_consensus',\n baseline: HigherOrderVotingResult\n): number {\n // Improvement is measured by increased confidence in the same direction\n if (decision === 'no_consensus' || baseline.decision === 'no_consensus') {\n return 0;\n }\n\n const currentConfidence = decision === 'approve' ? posteriorApproval : posteriorRejection;\n const baselineConfidence =\n baseline.decision === 'approve' ? baseline.posteriorApproval : baseline.posteriorRejection;\n\n // Return improvement as percentage points\n return (currentConfidence - baselineConfidence) * 100;\n}\n\n/**\n * Build reasoning string for voting result.\n */\nexport function buildReasoning(\n decision: 'approve' | 'reject' | 'no_consensus',\n effectiveVotes: number,\n downweightedAgents: readonly string[],\n method: 'ow' | 'isp' | 'simple'\n): string {\n const methodName =\n method === 'ow'\n ? 'Opinion-Wise Bayesian aggregation'\n : method === 'isp'\n ? 'Independent Subset Partition'\n : 'simple majority voting';\n\n let reasoning = `Decision reached via ${methodName} with ${effectiveVotes.toFixed(1)} effective votes. `;\n\n if (downweightedAgents.length > 0) {\n reasoning += `${String(downweightedAgents.length)} agent(s) downweighted due to correlation. `;\n }\n\n if (decision === 'no_consensus') {\n reasoning += 'No consensus reached due to insufficient margin.';\n } else {\n reasoning += `Final decision: ${decision}.`;\n }\n\n return reasoning;\n}\n","/**\n * nexus-agents/consensus - Higher-Order Voting Implementation\n *\n * Implements Opinion-Wise (OW) and Independent Subset Partition (ISP) voting\n * methods that account for correlations between agent opinions.\n *\n * Traditional voting assumes independence between voters. Higher-order voting\n * uses Bayesian-optimal aggregation that handles correlated agents better,\n * BUT NOTE (#4701): `calculateOutcome` — the `IVotingStrategy` entry point the\n * `ConsensusEngine` calls — uses `aggregateSimpleInternal` and ignores weights.\n * `aggregateWithCorrelation` is reached only via `runHigherOrderVoting`, whose\n * `posteriorApproval` feeds contrarian escalation, not the verdict. So selecting\n * `higher_order` does not currently buy a correlation-weighted approve/reject.\n * 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 // #4701: name the empty case, and name it the same way the other three\n // strategies do (`strategies.ts:136`, `:174`, `:210`). `aggregateSimple`\n // falls back to `posteriorApproval = 0.5` when nothing countable was cast,\n // which this method would otherwise publish as a measured-looking 50% —\n // absence rendered as a split. An all-abstain panel is reachable in\n // production: an errored voter and an unparseable response both abstain.\n if (approve + reject === 0) {\n return {\n approved: false,\n approvalPercentage: 0,\n voteCounts,\n reason: 'No votes cast (excluding abstentions)',\n };\n }\n\n const rawPercentage = result.posteriorApproval * 100;\n const approvalPercentage = Number.isFinite(rawPercentage) ? rawPercentage : 0;\n\n return {\n approved: result.decision === 'approve',\n approvalPercentage,\n voteCounts,\n reason: result.reasoning,\n };\n }\n}\n\n/** Creates a new OWVoting instance. */\nexport function createOWVoting(options?: OWVotingOptions): IHigherOrderVoting {\n return new OWVoting(options);\n}\n\n/**\n * Higher-order voting strategy for integration with VotingStrategyFactory.\n * Wraps OWVoting to provide IVotingStrategy interface.\n */\nexport class HigherOrderVotingStrategy extends OWVoting implements IVotingStrategy {\n constructor(options: OWVotingOptions = {}) {\n // #3168: set the algorithm label via the constructor so it survives\n // regardless of how the instance is created (no field-override divergence).\n super({ ...options, algorithm: options.algorithm ?? 'opinion_wise' });\n }\n}\n\n/** Creates a higher-order voting strategy for use with ConsensusEngine. */\nexport function createHigherOrderVotingStrategy(\n options?: OWVotingOptions\n): HigherOrderVotingStrategy {\n return new HigherOrderVotingStrategy(options);\n}\n","/**\n * nexus-agents/consensus - Voting Strategies\n *\n * Implementation of different voting strategies for consensus engine.\n * Supports simple majority, supermajority, unanimous, and proof-of-learning.\n */\n\nimport type {\n ConsensusAlgorithm,\n Vote,\n VoteCounts,\n WeightedVoteCounts,\n AgentPerformance,\n WeightBasis,\n} from './types.js';\nimport { VOTING_THRESHOLDS } from './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 /**\n * Present on weighted strategies only. Absent means the strategy does not\n * weight at all (simple majority, supermajority, unanimous) — which is\n * different from `'unweighted'`, meaning a weighted strategy ran with nothing\n * to weight by.\n */\n weightBasis?: WeightBasis;\n reason: string;\n}\n\n/**\n * Classifies a weighted tally by how many of its voters had a real weight\n * supplied (#5117).\n *\n * A voter absent from `weights` had no performance record; `countWeightedVotes`\n * already defaults such a voter to `1.0`, so the arithmetic is unchanged — the\n * absence is what carries the provenance.\n */\nfunction deriveWeightBasis(votes: Map<string, Vote>, weights: Map<string, number>): WeightBasis {\n let withRecord = 0;\n for (const agentId of votes.keys()) {\n if (weights.has(agentId)) withRecord++;\n }\n\n // The empty case, named rather than left to a default: zero voters carrying a\n // record — including the zero-voter case — is 'unweighted', never\n // 'performance'. Answering it with `withRecord === votes.size` would make\n // 0 === 0 report a full performance basis over nothing measured.\n if (withRecord === 0) return 'unweighted';\n return withRecord === votes.size ? 'performance' : 'partial';\n}\n\n/**\n * Evaluates an approval ratio against a threshold — the shared math behind\n * the simple-majority, supermajority and proof-of-learning strategies.\n *\n * `inclusive` selects the comparison: `>=` for supermajority (an exact 2/3\n * passes), strict `>` for simple-majority and proof-of-learning (a tie at the\n * threshold is not enough). Callers apply their own zero-denominator guard\n * before calling this.\n */\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 (at least 2/3 approval).\n */\nexport class SupermajorityStrategy extends BaseVotingStrategy {\n readonly algorithm: ConsensusAlgorithm = 'supermajority';\n\n calculateOutcome(votes: Map<string, Vote>): VotingOutcome {\n const counts = this.countVotes(votes);\n const votingVotes = counts.approve + counts.reject;\n const threshold = VOTING_THRESHOLDS.supermajority;\n\n if (votingVotes === 0) {\n return {\n approved: false,\n approvalPercentage: 0,\n voteCounts: counts,\n reason: 'No votes cast (excluding abstentions)',\n };\n }\n\n const { approved, approvalPercentage } = evaluateThreshold(\n counts.approve,\n votingVotes,\n threshold,\n true\n );\n const thresholdPercentage = (threshold * 100).toFixed(1);\n\n return {\n approved,\n approvalPercentage,\n voteCounts: counts,\n reason: approved\n ? `Approved with ${approvalPercentage.toFixed(1)}% (>=${thresholdPercentage}% required)`\n : `Rejected with ${approvalPercentage.toFixed(1)}% (<${thresholdPercentage}% threshold)`,\n };\n }\n}\n\n/**\n * Unanimous voting strategy (100% approval required).\n */\nexport class UnanimousStrategy extends BaseVotingStrategy {\n readonly algorithm: ConsensusAlgorithm = 'unanimous';\n\n calculateOutcome(votes: Map<string, Vote>): VotingOutcome {\n const counts = this.countVotes(votes);\n\n if (counts.total === 0) {\n return {\n approved: false,\n approvalPercentage: 0,\n voteCounts: counts,\n reason: 'No votes cast',\n };\n }\n\n // For unanimous, any rejection fails the proposal\n // Abstentions are allowed but don't count toward approval\n const approvalPercentage = counts.total > 0 ? (counts.approve / counts.total) * 100 : 0;\n\n if (counts.reject > 0) {\n return {\n approved: false,\n approvalPercentage,\n voteCounts: counts,\n reason: `Rejected: ${String(counts.reject)} rejection(s) cast (unanimous approval required)`,\n };\n }\n\n if (counts.approve === 0) {\n return {\n approved: false,\n approvalPercentage: 0,\n voteCounts: counts,\n reason: 'No approvals cast (at least one approval required)',\n };\n }\n\n return {\n approved: true,\n approvalPercentage,\n voteCounts: counts,\n reason: `Unanimously approved with ${String(counts.approve)} vote(s)`,\n };\n }\n}\n\n/**\n * Proof-of-learning weighted voting strategy.\n * Agents with better track records have more voting power.\n */\nexport class ProofOfLearningStrategy extends BaseVotingStrategy {\n readonly algorithm: ConsensusAlgorithm = 'proof_of_learning';\n\n calculateOutcome(votes: Map<string, Vote>, weights?: Map<string, number>): VotingOutcome {\n const counts = this.countVotes(votes);\n const effectiveWeights = weights ?? new Map<string, number>();\n const weightedCounts = this.countWeightedVotes(votes, effectiveWeights);\n const threshold = VOTING_THRESHOLDS.proof_of_learning;\n\n const votingWeight = weightedCounts.approve + weightedCounts.reject;\n\n if (votingWeight === 0) {\n return {\n approved: false,\n approvalPercentage: 0,\n voteCounts: counts,\n weightedCounts,\n reason: 'No weighted votes cast (excluding abstentions)',\n };\n }\n\n const { approved, approvalPercentage } = evaluateThreshold(\n weightedCounts.approve,\n votingWeight,\n threshold,\n false\n );\n\n const weightBasis = deriveWeightBasis(votes, effectiveWeights);\n const verdict = approved ? 'Approved' : 'Rejected';\n\n return {\n approved,\n approvalPercentage,\n voteCounts: counts,\n weightedCounts,\n weightBasis,\n reason: `${verdict} with ${approvalPercentage.toFixed(1)}% ${describeBasis(weightBasis)}`,\n };\n }\n}\n\n/**\n * The tail of the reason string, naming what the percentage was computed over.\n *\n * Calling an unweighted tally \"weighted approval\" is the misreport #5117 fixes:\n * the phrase invites a reader to believe voter track record moved the number\n * when nothing had ever recorded one.\n */\nfunction describeBasis(basis: WeightBasis): string {\n switch (basis) {\n case 'performance':\n return 'weighted approval (weights from voter performance history)';\n case 'partial':\n return 'partly weighted approval (some voters have no performance history; those count as 1.0)';\n case 'unweighted':\n return 'approval (UNWEIGHTED — no voter performance history recorded)';\n default: {\n const unreachable: never = basis;\n throw new Error(`Unhandled weight basis: ${String(unreachable)}`);\n }\n }\n}\n\n/**\n * Calculate vote weight for an agent based on their performance history.\n *\n * Weight ranges from 0.5 (never correct) to 1.0 (perfect track record). An\n * agent with NO history returns 1.0, not 0.5 — the doc used to say \"0.5 (no\n * history)\", which the code has never done (#5117). The distinction matters:\n * a 1.0 default is indistinguishable from a perfect record by value alone,\n * which is why callers must not infer \"was this measured?\" from the number.\n * `deriveWeightBasis` answers that from provenance instead.\n */\nexport function calculateVoteWeight(performance: AgentPerformance | undefined): number {\n if (performance === undefined || performance.totalVotes === 0) {\n return 1.0; // Default weight for new agents\n }\n\n // Weight = 0.5 + (successRate * 0.5)\n // This gives a range of 0.5 to 1.0 based on historical accuracy\n return 0.5 + performance.successRate * 0.5;\n}\n\n/**\n * Factory for creating voting strategies.\n */\nexport class VotingStrategyFactory {\n private readonly strategies: Map<ConsensusAlgorithm, IVotingStrategy>;\n\n constructor() {\n this.strategies = new Map<ConsensusAlgorithm, IVotingStrategy>([\n ['simple_majority', new SimpleMajorityStrategy()],\n ['supermajority', new SupermajorityStrategy()],\n ['unanimous', new UnanimousStrategy()],\n ['proof_of_learning', new ProofOfLearningStrategy()],\n ['opinion_wise', new HigherOrderVotingStrategy()],\n ['higher_order', new HigherOrderVotingStrategy()],\n ]);\n }\n\n /**\n * Get a voting strategy by algorithm type.\n */\n getStrategy(algorithm: ConsensusAlgorithm): IVotingStrategy {\n const strategy = this.strategies.get(algorithm);\n if (strategy === undefined) {\n throw new Error(`Unknown voting algorithm: ${algorithm}`);\n }\n return strategy;\n }\n\n /**\n * Register a custom voting strategy.\n */\n registerStrategy(strategy: IVotingStrategy): void {\n this.strategies.set(strategy.algorithm, strategy);\n }\n\n /**\n * Get all available algorithm types.\n */\n getAvailableAlgorithms(): ConsensusAlgorithm[] {\n return Array.from(this.strategies.keys());\n }\n}\n\n/**\n * Creates a voting strategy factory with default strategies.\n */\nexport function createStrategyFactory(): VotingStrategyFactory {\n return new VotingStrategyFactory();\n}\n","/**\n * nexus-agents/consensus - Result Builder\n *\n * Helper functions for building consensus results.\n */\n\nimport { getTimeProvider } from '../core/index.js';\nimport type {\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 weightBasis: outcome.weightBasis,\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 weightBasis: outcome.weightBasis,\n approvalPercentage: outcome.approvalPercentage,\n quorumReached,\n startedAt: state.startedAt.toISOString(),\n closedAt: now.toISOString(),\n durationMs: now.getTime() - state.startedAt.getTime(),\n };\n}\n\n/**\n * Build a timeout result for an expired proposal.\n */\nexport function buildTimeoutResult(\n state: ProposalState,\n proposalId: ProposalId,\n outcome: VotingOutcome,\n config: ConsensusEngineConfig\n): ConsensusResult {\n const now = new Date(getTimeProvider().now());\n return {\n proposalId,\n proposal: state.proposal,\n outcome: 'timeout',\n votes: new Map(state.votes),\n voteCounts: outcome.voteCounts,\n weightedCounts: outcome.weightedCounts,\n weightBasis: outcome.weightBasis,\n approvalPercentage: outcome.approvalPercentage,\n quorumReached: 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 max-lines: [\"error\", { \"max\": 600, \"skipBlankLines\": true, \"skipComments\": true }] */\n// A BOUNDED ceiling, not `eslint-disable max-lines` (#5766).\n//\n// The file is 499 lines by the measure the rule uses (blanks and comments\n// skipped) and 715 by `wc -l`. Those are different units, and comparing them is\n// what went wrong here: the previous comment read the raw 715 against the\n// \"400-600 lines if cohesive\" band in .rules/governance.md:67 and concluded the\n// file \"sits well past the band it invoked\". By the rule's own counting it sits\n// INSIDE that band, so the original justification never stopped holding — only\n// the number quoted against it was measured differently.\n//\n// A blanket disable is why that could go unnoticed for so long: it silenced the\n// one check that knows the real count, leaving a hand-maintained number in a\n// comment as the only record, and hand-maintained numbers rot (this one drifted\n// from 426 to 711 to 715). The ceiling is set at 600 — the TOP of the governance\n// band — so the file is checked against the same band its justification cites,\n// and growing out of it fails the build instead of a comment quietly aging.\n\n/**\n * nexus-agents/consensus - Consensus Engine\n *\n * Core consensus engine implementation supporting multiple voting strategies.\n * Manages proposal lifecycle, vote collection, and outcome determination.\n */\n\nimport type { Result, ILogger } from '../core/index.js';\nimport { ok, err, AgentError, createLogger, getTimeProvider } from '../core/index.js';\nimport type {\n Proposal,\n ProposalId,\n Vote,\n ConsensusResult,\n ConsensusAlgorithm,\n AgentPerformance,\n ConsensusEngineConfig,\n ProposalState,\n ConsensusMetrics,\n ProposalCacheConfig,\n IncrementalQuorumConfig,\n VoterExpansionCallback,\n} from './types.js';\nimport {\n ProposalSchema,\n VoteSchema,\n DEFAULT_CONSENSUS_CONFIG,\n 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 // Only record a weight when a performance record actually EXISTS (#5117).\n // This used to call `calculateVoteWeight(undefined)`, which returns the\n // 1.0 new-agent default, so the map was fully populated whether or not\n // anything had ever been measured — and by the time the strategy saw it,\n // \"weighted at 1.0 because they are reliable\" and \"weighted at 1.0\n // because we know nothing\" were indistinguishable.\n //\n // Absence now carries that provenance. The arithmetic is unchanged:\n // `countWeightedVotes` already defaults a missing entry to 1.0.\n const performance = this.agentPerformance.get(agentId);\n if (performance !== undefined) {\n state.voteWeights.set(agentId, calculateVoteWeight(performance));\n }\n }\n this.logger.debug('Vote recorded', {\n proposalId: state.proposal.id,\n agentId,\n decision: vote.decision,\n confidence: vote.confidence,\n });\n }\n\n private closeInternal(proposalId: ProposalId): Promise<Result<ConsensusResult, ConsensusError>> {\n const state = this.proposals.get(proposalId);\n if (state === undefined) {\n const closed = this.closedProposals.get(proposalId);\n if (closed !== undefined) return Promise.resolve(ok(closed));\n return Promise.resolve(err(new ConsensusError(`Proposal ${proposalId} not found`)));\n }\n\n if (state.timeoutId !== undefined) clearTimeout(state.timeoutId);\n\n const outcome = this.calculateOutcome(state);\n const result = buildFinalResult(state, proposalId, outcome, this.config);\n this.finalize(proposalId, result, state.votes.size);\n return Promise.resolve(ok(result));\n }\n\n private handleTimeout(proposalId: ProposalId): void {\n const state = this.proposals.get(proposalId);\n if (state?.status !== 'voting') return;\n\n this.logger.warn('Proposal timed out', { proposalId, voteCount: state.votes.size });\n const outcome = this.calculateOutcome(state);\n const result = buildTimeoutResult(state, proposalId, outcome, this.config);\n this.proposals.delete(proposalId);\n this.addClosedProposal(proposalId, result);\n this.metrics.timedOutProposals++;\n this.metrics.totalDurationMs += result.durationMs;\n this.metrics.totalVotes += state.votes.size;\n }\n\n private finalize(proposalId: ProposalId, result: ConsensusResult, voteCount: number): void {\n this.proposals.delete(proposalId);\n this.addClosedProposal(proposalId, result);\n this.updateMetrics(result);\n\n // Cache successful results for determinism (Issue #589)\n if (\n this.cacheConfig.enabled &&\n (result.outcome === 'approved' || result.outcome === 'rejected')\n ) {\n this.addToCache(result.proposal, proposalId, result);\n }\n\n this.logger.info('Proposal closed', {\n proposalId,\n outcome: result.outcome,\n approvalPercentage: result.approvalPercentage.toFixed(1),\n voteCount,\n quorumReached: result.quorumReached,\n durationMs: result.durationMs,\n });\n }\n\n /**\n * Adds a closed proposal and evicts oldest entries if over limit.\n * Issue #549: Prevent unbounded memory growth in closedProposals Map.\n */\n private addClosedProposal(proposalId: ProposalId, result: ConsensusResult): void {\n // Evict oldest entries if at capacity (Map maintains insertion order)\n while (this.closedProposals.size >= this.config.maxClosedProposals) {\n const firstKey = this.closedProposals.keys().next();\n if (firstKey.done === true) break;\n const oldestKey = firstKey.value;\n this.closedProposals.delete(oldestKey);\n this.logger.debug('Evicted oldest closed proposal', { evictedId: oldestKey });\n }\n this.closedProposals.set(proposalId, result);\n }\n\n private calculateOutcome(state: ProposalState): VotingOutcome {\n const strategy = this.strategyFactory.getStrategy(state.proposal.algorithm);\n const outcome: VotingOutcome = strategy.calculateOutcome(state.votes, state.voteWeights);\n return outcome;\n }\n\n /**\n * Agreement-based cascading: close early when outcome is mathematically determined.\n *\n * #2822: the prior implementation computed approval rates against\n * `totalExpected = requiredVoters.length` and compared against\n * `VOTING_THRESHOLDS[algorithm]` directly. Every voting strategy\n * (`SimpleMajorityStrategy`, `SupermajorityStrategy`, `UnanimousStrategy`,\n * `ProofOfLearningStrategy`) uses `approve + reject` as its denominator —\n * abstains are explicitly excluded. The two diverged whenever abstains\n * were present, producing wrong-winner cascades (e.g. 5-voter supermajority\n * with [approve, abstain, abstain, abstain, pending] cascade-rejected even\n * though the strategy would approve at close).\n *\n * The fix delegates to the strategy itself: build a best-case (all pending\n * voters approve) and worst-case (all pending voters reject) hypothetical\n * vote map, call `strategy.calculateOutcome` on each, and cascade only\n * when both extremes yield the same outcome. This guarantees parity with\n * the strategy's denominator semantics by construction.\n */\n private canCascadeEarly(state: ProposalState): boolean {\n const required = state.proposal.requiredVoters;\n if (required === undefined || required.length === 0) return false;\n if (state.votes.size === 0) return false;\n\n const pending = required.filter((voter) => !state.votes.has(voter));\n if (pending.length === 0) return false; // All voted — handled by allRequiredVotersVoted\n\n const strategy = this.strategyFactory.getStrategy(state.proposal.algorithm);\n\n const bestCase = new Map<string, Vote>(state.votes);\n const worstCase = new Map<string, Vote>(state.votes);\n for (const voter of pending) {\n bestCase.set(voter, HYPOTHETICAL_APPROVE);\n worstCase.set(voter, HYPOTHETICAL_REJECT);\n }\n\n const bestOutcome = strategy.calculateOutcome(bestCase, state.voteWeights);\n const worstOutcome = strategy.calculateOutcome(worstCase, state.voteWeights);\n\n if (bestOutcome.approved !== worstOutcome.approved) return false;\n\n this.logger.info('Agreement cascade: outcome determined', {\n proposalId: state.proposal.id,\n outcome: bestOutcome.approved ? 'approve' : 'reject',\n votesCast: state.votes.size,\n pending: pending.length,\n algorithm: state.proposal.algorithm,\n });\n return true;\n }\n\n private allRequiredVotersVoted(state: ProposalState): boolean {\n const required = state.proposal.requiredVoters;\n if (required === undefined || required.length === 0) return false;\n return required.every((voterId) => state.votes.has(voterId));\n }\n\n /**\n * Attempts incremental quorum expansion when voting is ambiguous (Issue #1408).\n * Returns true if expansion occurred (wait for new voters), false to close immediately.\n */\n private async tryExpandQuorum(proposalId: ProposalId, state: ProposalState): Promise<boolean> {\n if (!this.quorumConfig.enabled) return false;\n if (this.voterExpansionCallback === undefined) return false;\n\n const rounds = state.expansionRounds ?? 0;\n if (rounds >= this.quorumConfig.maxExpansionRounds) return false;\n\n const required = state.proposal.requiredVoters;\n if (required === undefined) return false;\n\n const threshold = VOTING_THRESHOLDS[state.proposal.algorithm];\n const ambiguous = isVotingAmbiguous(state.votes, required.length, threshold, {\n confidenceThreshold: this.quorumConfig.confidenceThreshold,\n ambiguityBand: this.quorumConfig.ambiguityBand,\n });\n\n if (!ambiguous) return false;\n\n let newVoters: readonly string[];\n try {\n newVoters = await this.voterExpansionCallback(\n proposalId,\n required.length,\n this.quorumConfig.votersPerExpansion\n );\n } catch (err: unknown) {\n const error = err instanceof Error ? err : new Error(String(err));\n this.logger.warn('Incremental quorum: expansion callback threw; closing as-is', {\n proposalId,\n errorMessage: error.message,\n });\n return false;\n }\n\n if (newVoters.length === 0) {\n this.logger.info('Incremental quorum: no additional voters available', { proposalId });\n return false;\n }\n\n // Expand the required voters list\n state.proposal.requiredVoters = [...required, ...newVoters];\n state.expansionRounds = rounds + 1;\n\n this.logger.info('Incremental quorum: expanded voter pool', {\n proposalId,\n round: rounds + 1,\n newVoters: newVoters.length,\n totalVoters: state.proposal.requiredVoters.length,\n });\n\n return true;\n }\n\n private updateMetrics(result: ConsensusResult): void {\n this.metrics.totalDurationMs += result.durationMs;\n this.metrics.totalVotes += result.voteCounts.total;\n if (result.outcome === 'approved') this.metrics.approvedProposals++;\n else if (result.outcome === 'rejected') this.metrics.rejectedProposals++;\n else if (result.outcome === 'timeout') this.metrics.timedOutProposals++;\n }\n\n private createInitialMetrics(): InternalMetrics {\n return {\n totalProposals: 0,\n approvedProposals: 0,\n rejectedProposals: 0,\n timedOutProposals: 0,\n totalDurationMs: 0,\n totalVotes: 0,\n algorithmUsage: {\n simple_majority: 0,\n supermajority: 0,\n unanimous: 0,\n proof_of_learning: 0,\n opinion_wise: 0,\n higher_order: 0,\n },\n };\n }\n\n // ============================================================================\n // Proposal Content Caching (Issue #589)\n // ============================================================================\n\n /**\n * Creates a content hash for a proposal to enable cache lookups.\n * Hash is based on title, description, and algorithm (deterministic content).\n */\n private hashProposalContent(proposal: Proposal): string {\n const content = [proposal.title, proposal.description, proposal.algorithm].join('|');\n // Simple FNV-1a hash for fast deterministic hashing\n let hash = 2166136261;\n for (let i = 0; i < content.length; i++) {\n hash ^= content.charCodeAt(i);\n hash = Math.imul(hash, 16777619);\n }\n return (hash >>> 0).toString(16);\n }\n\n /**\n * Gets cached result for a proposal if it exists and hasn't expired.\n */\n private getCachedResult(proposal: Proposal): ProposalCacheEntry | undefined {\n const hash = this.hashProposalContent(proposal);\n const cached = this.proposalContentCache.get(hash);\n if (cached === undefined) return undefined;\n\n const now = getTimeProvider().now();\n if (now - cached.cachedAt > this.cacheConfig.ttlMs) {\n this.proposalContentCache.delete(hash);\n this.logger.debug('Cache entry expired', { hash });\n return undefined;\n }\n\n return cached;\n }\n\n /**\n * Adds a proposal result to the cache, evicting oldest entries if needed.\n */\n private addToCache(proposal: Proposal, proposalId: ProposalId, result: ConsensusResult): void {\n const hash = this.hashProposalContent(proposal);\n\n // Evict oldest entries if at capacity (Map maintains insertion order)\n while (this.proposalContentCache.size >= this.cacheConfig.maxEntries) {\n const firstKey = this.proposalContentCache.keys().next();\n if (firstKey.done === true) break;\n const oldestKey = firstKey.value;\n this.proposalContentCache.delete(oldestKey);\n this.logger.debug('Evicted oldest cache entry', { hash: oldestKey });\n }\n\n this.proposalContentCache.set(hash, {\n proposalId,\n result,\n cachedAt: getTimeProvider().now(),\n });\n this.logger.debug('Added proposal to cache', { hash, proposalId });\n }\n\n /**\n * Gets the current cache size (for testing/monitoring).\n */\n getCacheSize(): number {\n return this.proposalContentCache.size;\n }\n\n /**\n * Clears the proposal content cache (for testing/reset).\n */\n clearCache(): void {\n this.proposalContentCache.clear();\n this.logger.debug('Proposal cache cleared');\n }\n}\n\n/**\n * Create a consensus engine with the given configuration.\n *\n * @example\n * ```typescript\n * const engine = createConsensusEngine({\n * defaultTimeout: 60000,\n * maxActiveProposals: 10,\n * });\n * ```\n */\nexport function createConsensusEngine(\n config?: Partial<ConsensusEngineConfig>,\n logger?: ILogger\n): ConsensusEngine {\n return new ConsensusEngine(config, logger);\n}\n","/**\n * Unified Quorum Validator\n *\n * SCOPE, corrected (#4666). This module's docstring claimed it \"abstracts\n * quorum validation across VotingProtocol, WeightedVoting, and ConsensusEngine\"\n * and consolidates three implementations. It has exactly ONE consumer:\n * `voting-protocol-helpers.ts`. `WeightedVoting` and `ConsensusEngine` do not\n * use it. The intent from #576 was real; the consolidation did not happen, and\n * the doc has been describing the plan as though it were the state.\n *\n * A second, sharper caveat for anyone relying on this: `VotingProtocol` — the\n * one path that reaches here — has **no in-tree caller**. `createVotingProtocol`\n * is exported through `exports/consensus.ts` as public API and is constructed\n * only by tests. So this validator runs only for an external embedder.\n *\n * Agent eligibility screening was REMOVED here under #4666 (consensus_vote 7-0).\n * It could never exclude anyone: its sole caller passed no `AgentRecord`, and no\n * producer of trust scores or Byzantine flags exists anywhere in `src/`. The\n * breakdown nonetheless emitted an `eligibleAgents` list containing every voter,\n * which a machine consumer reads as evidence that screening ran — a comment\n * cannot travel with a serialized record. Git history holds the implementation\n * for whenever a real trust-score producer appears.\n *\n * @module consensus/quorum-validator\n * (Source: Issue #576, ADR-0003; scope corrected #4666)\n */\n\nimport { createLogger, formatPercentage, type ILogger } from '../core/index.js';\nimport type { ConsensusAlgorithm, Vote, VoteCounts, WeightedVoteCounts } from './types-core.js';\nimport { SUPERMAJORITY_THRESHOLD } from './types-core.js';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Quorum validation configuration.\n */\nexport interface QuorumValidationConfig {\n /** Algorithm type */\n readonly algorithm: ConsensusAlgorithm | 'weighted_byzantine';\n /** Numeric threshold (0-1 for percentage, 0-N for weighted sum) */\n readonly threshold: number;\n /** Minimum voters required */\n readonly minVoters: number;\n /** Apply confidence multiplier to weights */\n readonly confidenceMultiplier?: boolean;\n /** Include abstentions in quorum calculation */\n readonly includeAbstentions?: boolean;\n}\n\n/**\n * Input for quorum validation.\n */\nexport interface QuorumValidationInput {\n /** Votes cast by agent ID */\n readonly votes: ReadonlyMap<string, Vote>;\n /** Optional: Pre-calculated agent weights */\n readonly agentWeights?: ReadonlyMap<string, number>;\n /** Configuration */\n readonly config: QuorumValidationConfig;\n /** Optional: Required participant count (for ratio-based quorum) */\n readonly requiredParticipants?: number;\n}\n\n/**\n * Quorum validation result (discriminated union).\n */\nexport type QuorumValidationResult =\n | {\n readonly status: 'reached';\n readonly decision: 'approve' | 'reject';\n readonly confidence: number;\n readonly reasoning: string;\n }\n | {\n readonly status: 'not_reached';\n readonly reason: 'insufficient_votes' | 'insufficient_weight' | 'no_consensus';\n readonly details: string;\n }\n | { readonly status: 'invalid'; readonly error: string }\n | { readonly status: 'timeout'; readonly partial: boolean; readonly details: string };\n\n/**\n * Detailed quorum breakdown for observability.\n */\nexport interface QuorumBreakdown {\n readonly totalVotes: number;\n readonly voteCounts: VoteCounts;\n readonly totalWeight: number | undefined;\n readonly weightedCounts: WeightedVoteCounts | undefined;\n readonly threshold: number;\n readonly actualQuorum: number;\n readonly quorumReached: boolean;\n readonly reasoning: string;\n}\n\n/**\n * Unified quorum validator interface.\n */\nexport interface IQuorumValidator {\n validateQuorum(input: QuorumValidationInput): QuorumValidationResult;\n getQuorumBreakdown(input: QuorumValidationInput): QuorumBreakdown;\n}\n\n// ============================================================================\n// Implementation\n// ============================================================================\n\n/**\n * Default quorum thresholds by algorithm type.\n * Used for reference when config.threshold is not specified.\n */\nexport const DEFAULT_QUORUM_THRESHOLDS: Readonly<\n Record<ConsensusAlgorithm | 'weighted_byzantine', number>\n> = {\n simple_majority: 0.5,\n supermajority: SUPERMAJORITY_THRESHOLD,\n unanimous: 1.0,\n proof_of_learning: 0.5,\n opinion_wise: 0.5,\n higher_order: 0.5,\n // Byzantine fault tolerance also requires 2/3 — the same supermajority.\n weighted_byzantine: SUPERMAJORITY_THRESHOLD,\n};\n\n/**\n * Tolerance under which approve and reject tallies are an exact tie (#6051).\n *\n * Weighted tallies are sums of voter weights (optionally scaled by vote\n * confidence), so two panels that tie in exact arithmetic can differ at the\n * 1e-16 level in IEEE-754 (`0.1 + 0.2 + 1.0 !== 1.3`). A strict `===` would\n * call that a 2e-16 majority; this tolerance is far above float noise and far\n * below the smallest weight difference a caller could intend (weights are\n * conventionally in [0, 1] with a handful of decimals).\n */\nconst TIE_TOLERANCE = 1e-9;\n\n/** Inputs to the quorum-status calculation, grouped to stay within max-params. */\ninterface QuorumStatusInput {\n readonly voteCounts: VoteCounts;\n readonly weightedCounts: WeightedVoteCounts | undefined;\n readonly totalWeight: number | undefined;\n readonly config: QuorumValidationConfig;\n readonly requiredParticipants: number;\n /** Whether any voter had a weight SUPPLIED — provenance, not value (#5117). */\n readonly anyWeightSupplied: boolean;\n}\n\n/** Inputs to the weighted-quorum reasoning string. */\ninterface WeightedReasoningInput {\n readonly quorumReached: boolean;\n readonly totalWeight: number;\n readonly threshold: number;\n readonly approveRatio: number;\n readonly rejectRatio: number;\n /** False when no agent weights were supplied — the tally is a headcount. */\n readonly weighted: boolean;\n}\n\n/**\n * Unified quorum validator implementation.\n */\nexport class QuorumValidator implements IQuorumValidator {\n private readonly logger: ILogger;\n\n constructor(logger?: ILogger) {\n this.logger = logger ?? createLogger({ component: 'QuorumValidator' });\n }\n\n validateQuorum(input: QuorumValidationInput): QuorumValidationResult {\n const { votes, config } = input;\n\n // Validate input\n if (votes.size === 0) {\n return { status: 'invalid', error: 'No votes provided' };\n }\n\n // Calculate breakdown\n const breakdown = this.getQuorumBreakdown(input);\n\n // Check if quorum reached\n if (!breakdown.quorumReached) {\n return this.buildNotReachedResult(breakdown, config);\n }\n\n // A tie is not a decision (#6051). At the schema-minimum threshold (0.5)\n // both sides clear the bar, and the old `>=` tie-break reported a 3-3\n // panel as `approve` with the only tie signal (confidence 0) left for the\n // caller to notice. Keep the tie out of the reached path entirely.\n if (this.isTie(breakdown)) {\n return this.buildTieResult(breakdown);\n }\n\n // Determine decision\n return this.buildReachedResult(breakdown);\n }\n\n getQuorumBreakdown(input: QuorumValidationInput): QuorumBreakdown {\n const { votes, agentWeights, config, requiredParticipants } = input;\n\n // Count votes\n const voteCounts = this.countVotes(votes);\n\n // Calculate weights if applicable\n const { totalWeight, weightedCounts } = this.calculateWeights(votes, agentWeights, config);\n\n // Whether any voter actually had a weight SUPPLIED (#5117). Derived from\n // provenance — presence in `agentWeights` — not from whether a weight\n // differs from 1.0: an agent legitimately weighted 1.0 is not the same as\n // one nobody ever weighted, and numeric equality cannot tell them apart.\n const anyWeightSupplied = [...votes.keys()].some((id) => agentWeights?.has(id) === true);\n\n // Calculate quorum based on algorithm\n const { threshold, actualQuorum, quorumReached, reasoning } = this.calculateQuorumStatus({\n voteCounts,\n weightedCounts,\n totalWeight,\n config,\n requiredParticipants: requiredParticipants ?? votes.size,\n anyWeightSupplied,\n });\n\n return {\n totalVotes: votes.size,\n voteCounts,\n totalWeight,\n weightedCounts,\n threshold,\n actualQuorum,\n quorumReached,\n reasoning,\n };\n }\n\n private countVotes(votes: ReadonlyMap<string, Vote>): VoteCounts {\n let approve = 0;\n let reject = 0;\n let abstain = 0;\n\n for (const vote of votes.values()) {\n switch (vote.decision) {\n case 'approve':\n approve++;\n break;\n case 'reject':\n reject++;\n break;\n case 'abstain':\n abstain++;\n break;\n }\n }\n\n return { approve, reject, abstain, total: votes.size };\n }\n\n private calculateWeights(\n votes: ReadonlyMap<string, Vote>,\n agentWeights: ReadonlyMap<string, number> | undefined,\n config: QuorumValidationConfig\n ): { totalWeight: number | undefined; weightedCounts: WeightedVoteCounts | undefined } {\n // Skip weight calculation for simple algorithms\n if (config.algorithm === 'simple_majority' || config.algorithm === 'unanimous') {\n return { totalWeight: undefined, weightedCounts: undefined };\n }\n\n const counts = { totalWeight: 0, approve: 0, reject: 0, abstain: 0 };\n\n for (const [agentId, vote] of votes.entries()) {\n const weight = this.getVoteWeight(agentId, vote, agentWeights, config);\n counts.totalWeight += weight;\n this.addWeightToDecision(counts, vote.decision, weight);\n }\n\n return {\n totalWeight: counts.totalWeight,\n weightedCounts: {\n approve: counts.approve,\n reject: counts.reject,\n abstain: counts.abstain,\n totalWeight: counts.totalWeight,\n },\n };\n }\n\n private getVoteWeight(\n agentId: string,\n vote: Vote,\n agentWeights: ReadonlyMap<string, number> | undefined,\n config: QuorumValidationConfig\n ): number {\n let weight = agentWeights?.get(agentId) ?? 1.0;\n if (config.confidenceMultiplier === true) {\n weight *= vote.confidence;\n }\n return weight;\n }\n\n private addWeightToDecision(\n counts: { approve: number; reject: number; abstain: number },\n decision: 'approve' | 'reject' | 'abstain',\n weight: number\n ): void {\n counts[decision] += weight;\n }\n\n private calculateQuorumStatus(opts: QuorumStatusInput): {\n threshold: number;\n actualQuorum: number;\n quorumReached: boolean;\n reasoning: string;\n } {\n const {\n voteCounts,\n weightedCounts,\n totalWeight,\n config,\n requiredParticipants,\n anyWeightSupplied,\n } = opts;\n const threshold = config.threshold;\n\n // For weighted algorithms, use weighted counts\n if (weightedCounts !== undefined && totalWeight !== undefined && totalWeight > 0) {\n return this.calculateWeightedQuorum(\n weightedCounts,\n totalWeight,\n threshold,\n anyWeightSupplied\n );\n }\n\n // For simple algorithms, use vote counts\n return this.calculateSimpleQuorum(voteCounts, requiredParticipants, threshold, config);\n }\n\n private calculateWeightedQuorum(\n weightedCounts: WeightedVoteCounts,\n totalWeight: number,\n threshold: number,\n anyWeightSupplied: boolean\n ): { threshold: number; actualQuorum: number; quorumReached: boolean; reasoning: string } {\n const quorumReached = totalWeight >= threshold;\n const approveRatio = weightedCounts.approve / totalWeight;\n const rejectRatio = weightedCounts.reject / totalWeight;\n\n const reasoning = this.buildWeightedReasoning({\n quorumReached,\n totalWeight,\n threshold,\n approveRatio,\n rejectRatio,\n weighted: anyWeightSupplied,\n });\n\n return { threshold, actualQuorum: totalWeight, quorumReached, reasoning };\n }\n\n /**\n * Reasoning text for the weighted-quorum branch.\n *\n * `weighted` is qualified rather than asserted (#5117). `agentWeights` has no\n * non-test producer, so every real call reaches `getVoteWeight`'s `?? 1.0`\n * fallback and this branch describes a plain headcount as a weighted ratio.\n * The word is kept where weights genuinely varied and replaced where they\n * did not, so the reader can tell the two apart.\n */\n private buildWeightedReasoning(opts: WeightedReasoningInput): string {\n const { quorumReached, totalWeight, threshold, approveRatio, rejectRatio, weighted } = opts;\n const kind = weighted ? 'weighted' : 'unweighted (no agent weights supplied)';\n if (!quorumReached) {\n return `Quorum not reached: ${totalWeight.toFixed(2)} < ${String(threshold)} (${kind})`;\n }\n if (approveRatio > rejectRatio) {\n return `Approval wins with ${kind} ratio ${formatPercentage(approveRatio, 1)}`;\n }\n if (rejectRatio > approveRatio) {\n return `Rejection wins with ${kind} ratio ${formatPercentage(rejectRatio, 1)}`;\n }\n return `No clear winner: approve=${formatPercentage(approveRatio, 1)}, reject=${formatPercentage(rejectRatio, 1)} (${kind})`;\n }\n\n private calculateSimpleQuorum(\n voteCounts: VoteCounts,\n requiredParticipants: number,\n threshold: number,\n config: QuorumValidationConfig\n ): { threshold: number; actualQuorum: number; quorumReached: boolean; reasoning: string } {\n const activeVotes =\n config.includeAbstentions === true\n ? voteCounts.total\n : voteCounts.approve + voteCounts.reject;\n\n const total = requiredParticipants > 0 ? requiredParticipants : activeVotes;\n const approveRatio = total > 0 ? voteCounts.approve / total : 0;\n const rejectRatio = total > 0 ? voteCounts.reject / total : 0;\n\n const hasMinVoters = activeVotes >= config.minVoters;\n const quorumReached = hasMinVoters && (approveRatio >= threshold || rejectRatio >= threshold);\n\n const reasoning = this.buildSimpleReasoning({\n hasMinVoters,\n activeVotes,\n minVoters: config.minVoters,\n approveRatio,\n rejectRatio,\n threshold,\n });\n\n return {\n threshold,\n actualQuorum: Math.max(approveRatio, rejectRatio),\n quorumReached,\n reasoning,\n };\n }\n\n private buildSimpleReasoning(params: {\n hasMinVoters: boolean;\n activeVotes: number;\n minVoters: number;\n approveRatio: number;\n rejectRatio: number;\n threshold: number;\n }): string {\n const { hasMinVoters, activeVotes, minVoters, approveRatio, rejectRatio, threshold } = params;\n if (!hasMinVoters) {\n return `Insufficient voters: ${String(activeVotes)} < ${String(minVoters)}`;\n }\n if (approveRatio >= threshold) {\n return `Approval reaches threshold: ${formatPercentage(approveRatio, 1)} >= ${formatPercentage(threshold, 1)}`;\n }\n if (rejectRatio >= threshold) {\n return `Rejection reaches threshold: ${formatPercentage(rejectRatio, 1)} >= ${formatPercentage(threshold, 1)}`;\n }\n return `No decision reached threshold: approve=${formatPercentage(approveRatio, 1)}, reject=${formatPercentage(rejectRatio, 1)}`;\n }\n\n private buildNotReachedResult(\n breakdown: QuorumBreakdown,\n config: QuorumValidationConfig\n ): QuorumValidationResult {\n const { voteCounts, weightedCounts, threshold } = breakdown;\n\n if (voteCounts.total < config.minVoters) {\n return {\n status: 'not_reached',\n reason: 'insufficient_votes',\n details: `Only ${String(voteCounts.total)} votes, need ${String(config.minVoters)}`,\n };\n }\n\n if (weightedCounts !== undefined && weightedCounts.totalWeight < threshold) {\n return {\n status: 'not_reached',\n reason: 'insufficient_weight',\n details: `Weight ${weightedCounts.totalWeight.toFixed(2)} < threshold ${String(threshold)}`,\n };\n }\n\n return {\n status: 'not_reached',\n reason: 'no_consensus',\n details: breakdown.reasoning,\n };\n }\n\n /** The tallies a decision is drawn from: weighted when weights apply, else headcount. */\n private decisiveTallies(breakdown: QuorumBreakdown): {\n approves: number;\n rejects: number;\n total: number;\n } {\n const { voteCounts, weightedCounts } = breakdown;\n return {\n approves: weightedCounts?.approve ?? voteCounts.approve,\n rejects: weightedCounts?.reject ?? voteCounts.reject,\n total: weightedCounts?.totalWeight ?? voteCounts.total,\n };\n }\n\n private isTie(breakdown: QuorumBreakdown): boolean {\n const { approves, rejects } = this.decisiveTallies(breakdown);\n return Math.abs(approves - rejects) < TIE_TOLERANCE;\n }\n\n /**\n * A tie reuses the existing `no_consensus` variant rather than a new status\n * member (a new member is breaking for exhaustive switches downstream). The\n * tie survives in `details`, which is the only place it can be read from.\n */\n private buildTieResult(breakdown: QuorumBreakdown): QuorumValidationResult {\n const { approves, rejects } = this.decisiveTallies(breakdown);\n const kind = breakdown.weightedCounts === undefined ? '' : ' (weighted)';\n return {\n status: 'not_reached',\n reason: 'no_consensus',\n details: `tie: ${formatTally(approves)} approve vs ${formatTally(rejects)} reject${kind}; consensus not reached`,\n };\n }\n\n private buildReachedResult(breakdown: QuorumBreakdown): QuorumValidationResult {\n const { approves, rejects, total } = this.decisiveTallies(breakdown);\n\n // Determine winning decision. A tie never reaches here (`isTie` guards\n // the call), so the comparison is strict: `>=` would silently re-open the\n // tie-as-approval defect if the guard were ever removed (#6051).\n const decision: 'approve' | 'reject' = approves > rejects ? 'approve' : 'reject';\n const confidence = total > 0 ? Math.abs(approves - rejects) / total : 0;\n\n return {\n status: 'reached',\n decision,\n confidence,\n reasoning: breakdown.reasoning,\n };\n }\n}\n\n/** Integers print as counts (`3`); weighted sums keep two decimals (`1.30`). */\nfunction formatTally(value: number): string {\n return Number.isInteger(value) ? String(value) : value.toFixed(2);\n}\n\n/**\n * Creates a quorum validator instance.\n */\nexport function createQuorumValidator(logger?: ILogger): IQuorumValidator {\n return new QuorumValidator(logger);\n}\n","/**\n * Helper functions for the multi-round voting protocol.\n *\n * @module consensus/voting-protocol-helpers\n * (Source: Issue #100, arXiv:2512.21352)\n */\n\nimport type {\n VotingSession,\n VotingRound,\n VotingRoundPhase,\n VotingProtocolConfig,\n VotingProtocolResult,\n AgentFinding,\n Vote,\n ConsolidatedFinding,\n RoundSummary,\n SycophancyReport,\n SycophancyIndicator,\n} from './types.js';\nimport { createQuorumValidator, type QuorumValidationConfig } from './quorum-validator.js';\nimport { getTimeProvider, getRandomProvider } from '../core/index.js';\n\n/**\n * Generate a unique session ID.\n */\nexport function generateSessionId(): string {\n const time = getTimeProvider();\n const random = getRandomProvider();\n return `session_${String(time.now())}_${random.randomString(7)}`;\n}\n\n/**\n * Generate a unique finding ID.\n */\nexport function generateFindingId(): string {\n const time = getTimeProvider();\n const random = getRandomProvider();\n return `finding_${String(time.now())}_${random.randomString(7)}`;\n}\n\n/**\n * Generate a unique round ID.\n */\nexport function generateRoundId(): string {\n const time = getTimeProvider();\n const random = getRandomProvider();\n return `round_${String(time.now())}_${random.randomString(7)}`;\n}\n\n/**\n * Create a new voting round.\n */\nexport function createRound(phase: VotingRoundPhase, roundNumber: number): VotingRound {\n const time = getTimeProvider();\n return {\n id: generateRoundId(),\n phase,\n status: 'in_progress',\n findings: new Map(),\n findingVotes: new Map(),\n finalVotes: new Map(),\n startedAt: time.nowIso(),\n roundNumber,\n };\n}\n\n/**\n * Find the most common element in an array.\n */\nexport function mostCommon<T>(items: T[]): T | undefined {\n if (items.length === 0) return undefined;\n\n const counts = new Map<T, number>();\n items.forEach((item) => {\n counts.set(item, (counts.get(item) ?? 0) + 1);\n });\n\n let maxCount = 0;\n let result: T | undefined;\n counts.forEach((count, item) => {\n if (count > maxCount) {\n maxCount = count;\n result = item;\n }\n });\n\n return result;\n}\n\n/**\n * Calculate agreement score from votes.\n */\nexport function calculateAgreementScore(votes: Vote[]): number {\n if (votes.length < 2) return 1;\n\n const decisions = votes.map((v) => v.decision);\n const mostCommonDecision = mostCommon(decisions);\n const agreementCount = decisions.filter((d) => d === mostCommonDecision).length;\n\n return agreementCount / votes.length;\n}\n\n/**\n * Determine outcome from final votes using unified QuorumValidator.\n * Per ADR-0003, this delegates to the consolidated quorum logic.\n */\nexport function determineOutcome(\n votes: Vote[],\n config: VotingProtocolConfig\n): VotingProtocolResult['outcome'] {\n if (votes.length === 0) return 'no_consensus';\n\n // Convert array to Map for QuorumValidator\n const voteMap = new Map<string, Vote>();\n votes.forEach((vote, index) => {\n voteMap.set(`voter_${String(index)}`, vote);\n });\n\n // Create quorum config from voting protocol config\n const quorumConfig: QuorumValidationConfig = {\n algorithm: 'simple_majority',\n threshold: config.agreementThreshold,\n minVoters: 2, // Minimum for valid consensus\n };\n\n // Use unified QuorumValidator\n const validator = createQuorumValidator();\n const result = validator.validateQuorum({\n votes: voteMap,\n config: quorumConfig,\n });\n\n // Map QuorumValidationResult to VotingProtocolResult outcome\n if (result.status === 'reached') {\n return result.decision === 'approve' ? 'approved' : 'rejected';\n }\n\n // Check for mixed votes (needs revision)\n const approvals = votes.filter((v) => v.decision === 'approve').length;\n const rejections = votes.filter((v) => v.decision === 'reject').length;\n if (approvals > 0 && rejections > 0) return 'needs_revision';\n\n return 'no_consensus';\n}\n\n/**\n * Consolidate findings from deliberation round.\n */\nexport function consolidateFindings(session: VotingSession): ConsolidatedFinding[] {\n const deliberationRound = session.rounds[1];\n if (!deliberationRound) return [];\n\n const consolidated: ConsolidatedFinding[] = [];\n\n deliberationRound.findings.forEach((finding, findingId) => {\n const votes = deliberationRound.findingVotes.get(findingId) ?? [];\n const agreeVotes = votes.filter((v) => v.agree);\n const agreementRatio = votes.length > 0 ? agreeVotes.length / votes.length : 0;\n\n // Only include findings with some agreement\n if (agreementRatio >= 0.5) {\n // Determine final severity (use most common amended severity or original)\n const severityVotes = agreeVotes\n .filter((v) => v.amendedSeverity)\n .map((v) => v.amendedSeverity);\n const finalSeverity =\n severityVotes.length > 0\n ? (mostCommon(severityVotes) ?? finding.severity)\n : finding.severity;\n\n const consolidatedFinding: ConsolidatedFinding = {\n id: findingId,\n category: finding.category,\n severity: finalSeverity,\n description: finding.description,\n supportingAgents: agreeVotes.map((v) => v.agentId),\n agreementRatio,\n originalFindings: [finding],\n };\n if (finding.location !== undefined) {\n consolidatedFinding.location = finding.location;\n }\n if (finding.suggestion !== undefined) {\n consolidatedFinding.suggestion = finding.suggestion;\n }\n consolidated.push(consolidatedFinding);\n }\n });\n\n // Sort by severity and agreement\n return consolidated.sort((a, b) => {\n const severityOrder = { critical: 0, major: 1, minor: 2, suggestion: 3 };\n const sevDiff = severityOrder[a.severity] - severityOrder[b.severity];\n if (sevDiff !== 0) return sevDiff;\n return b.agreementRatio - a.agreementRatio;\n });\n}\n\n/**\n * Build round summaries from session.\n */\nexport function buildRoundSummaries(session: VotingSession): RoundSummary[] {\n const time = getTimeProvider();\n return session.rounds.map((round, index) => {\n const startTime = new Date(round.startedAt).getTime();\n const endTime =\n round.completedAt !== undefined ? new Date(round.completedAt).getTime() : time.now();\n\n let votesCount = 0;\n let agreementScore = 0;\n\n if (round.phase === 'deliberation') {\n // Count finding votes\n round.findingVotes.forEach((votes) => {\n votesCount += votes.length;\n const agreeCount = votes.filter((v) => v.agree).length;\n agreementScore += votes.length > 0 ? agreeCount / votes.length : 0;\n });\n const findingsCount = round.findingVotes.size;\n if (findingsCount > 0) {\n agreementScore /= findingsCount;\n }\n } else if (round.phase === 'consensus') {\n // Count final votes\n votesCount = round.finalVotes.size;\n const votes = Array.from(round.finalVotes.values());\n agreementScore = calculateAgreementScore(votes);\n }\n\n return {\n roundNumber: index + 1,\n phase: round.phase,\n findingsCount: round.findings.size,\n votesCount,\n agreementScore,\n durationMs: endTime - startTime,\n };\n });\n}\n\n// ============================================================================\n// Sycophancy Detection\n// ============================================================================\n\n/**\n * Check for premature consensus pattern.\n */\nexport function checkPrematureConsensus(session: VotingSession): SycophancyIndicator | null {\n const analysisRound = session.rounds[0];\n if (!analysisRound) return null;\n\n const agentFindings = new Map<string, AgentFinding[]>();\n analysisRound.findings.forEach((finding) => {\n const existing = agentFindings.get(finding.agentId) ?? [];\n existing.push(finding);\n agentFindings.set(finding.agentId, existing);\n });\n\n const allConfidences: number[] = [];\n analysisRound.findings.forEach((finding) => {\n allConfidences.push(finding.confidence);\n });\n\n const avgConfidence =\n allConfidences.length > 0\n ? allConfidences.reduce((a, b) => a + b, 0) / allConfidences.length\n : 0;\n\n if (avgConfidence > 0.95 && agentFindings.size >= 2) {\n return {\n type: 'premature_consensus',\n description: 'All agents showing unusually high confidence',\n severity: 'medium',\n agents: Array.from(agentFindings.keys()),\n };\n }\n\n return null;\n}\n\n/**\n * Check for opinion convergence pattern.\n */\nexport function checkOpinionConvergence(session: VotingSession): SycophancyIndicator | null {\n const deliberationRound = session.rounds[1];\n if (!deliberationRound) return null;\n\n let totalVotes = 0;\n let agreeVotes = 0;\n\n deliberationRound.findingVotes.forEach((votes) => {\n totalVotes += votes.length;\n agreeVotes += votes.filter((v) => v.agree).length;\n });\n\n const agreeRatio = totalVotes > 0 ? agreeVotes / totalVotes : 0;\n\n if (agreeRatio > session.config.sycophancyThreshold && totalVotes > 3) {\n const affectedAgents: string[] = [];\n deliberationRound.findingVotes.forEach((votes) => {\n votes.forEach((v) => {\n if (v.agree && !affectedAgents.includes(v.agentId)) {\n affectedAgents.push(v.agentId);\n }\n });\n });\n\n return {\n type: 'opinion_convergence',\n description: `${String(Math.round(agreeRatio * 100))}% agreement rate suggests possible opinion convergence`,\n severity: 'high',\n agents: affectedAgents,\n };\n }\n\n return null;\n}\n\n/**\n * Check for confidence inflation pattern.\n */\nexport function checkConfidenceInflation(session: VotingSession): SycophancyIndicator | null {\n const consensusRound = session.rounds[2];\n if (!consensusRound) return null;\n\n const votes = Array.from(consensusRound.finalVotes.values());\n if (votes.length < 2) return null;\n\n const confidences = votes.map((v) => v.confidence);\n const avgConfidence = confidences.reduce((a, b) => a + b, 0) / confidences.length;\n const allHigh = confidences.every((c) => c > 0.9);\n\n if (allHigh && avgConfidence > 0.95) {\n return {\n type: 'confidence_inflation',\n description: 'All agents reporting very high confidence suggests possible sycophancy',\n severity: 'medium',\n agents: Array.from(consensusRound.finalVotes.keys()),\n };\n }\n\n return null;\n}\n\n/**\n * Run all sycophancy detection checks.\n */\nexport function detectSycophancyPatterns(session: VotingSession): SycophancyReport {\n const indicators: SycophancyIndicator[] = [];\n const affectedAgents: string[] = [];\n\n const prematureConsensus = checkPrematureConsensus(session);\n if (prematureConsensus) {\n indicators.push(prematureConsensus);\n affectedAgents.push(...prematureConsensus.agents);\n }\n\n const opinionConvergence = checkOpinionConvergence(session);\n if (opinionConvergence) {\n indicators.push(opinionConvergence);\n affectedAgents.push(...opinionConvergence.agents);\n }\n\n const confidenceInflation = checkConfidenceInflation(session);\n if (confidenceInflation) {\n indicators.push(confidenceInflation);\n affectedAgents.push(...confidenceInflation.agents);\n }\n\n const detected = indicators.length > 0;\n const confidenceScore = Math.min(1, indicators.length * 0.3);\n const uniqueAffected = [...new Set(affectedAgents)];\n\n return {\n detected,\n confidenceScore,\n indicators,\n affectedAgents: uniqueAffected,\n recommendation: detected\n ? 'Consider requesting independent re-analysis or adding more diverse agents'\n : 'No sycophancy detected',\n };\n}\n","/**\n * Multi-Round Voting Protocol Implementation\n *\n * Implements a structured 3-round voting protocol for multi-agent code review\n * based on research showing 91.7-100% success rates vs 78% single-agent baseline.\n *\n * @module consensus/voting-protocol\n * (Source: Issue #100, arXiv:2512.21352 - Multi-Agent Committees)\n * (Source: arXiv:2509.23055 - Sycophancy Prevention)\n */\n\nimport { createLogger } from '../core/logger.js';\nimport { allOf } from '../utils/verdict-aggregation.js';\nimport { getTimeProvider } from '../core/index.js';\nimport type { ILogger } from '../core/index.js';\nimport type {\n IVotingProtocol,\n VotingSession,\n VotingRound,\n VotingProtocolConfig,\n VotingProtocolResult,\n AgentFinding,\n FindingVote,\n Vote,\n SycophancyReport,\n} from './types.js';\nimport {\n AgentFindingSchema,\n FindingVoteSchema,\n VoteSchema,\n DEFAULT_VOTING_PROTOCOL_CONFIG,\n} from './types.js';\nimport {\n generateSessionId,\n generateFindingId,\n createRound,\n consolidateFindings,\n buildRoundSummaries,\n determineOutcome,\n calculateAgreementScore,\n detectSycophancyPatterns,\n} from './voting-protocol-helpers.js';\n\nconst logger: ILogger = createLogger({ component: 'voting-protocol' });\n\n/**\n * Multi-round voting protocol for code review.\n */\nexport class VotingProtocol implements IVotingProtocol {\n private readonly sessions: Map<string, VotingSession> = new Map();\n private readonly logger: ILogger;\n\n constructor(customLogger?: ILogger) {\n this.logger = customLogger ?? logger;\n }\n\n /**\n * Create a new voting session with a committee.\n */\n createSession(\n topic: string,\n committee: string[],\n config?: Partial<VotingProtocolConfig>\n ): VotingSession {\n const sessionConfig = { ...DEFAULT_VOTING_PROTOCOL_CONFIG, ...config };\n\n if (committee.length < 2) {\n throw new Error('Committee must have at least 2 members');\n }\n\n if (committee.length > sessionConfig.committeeSize) {\n throw new Error(`Committee size exceeds maximum (${String(sessionConfig.committeeSize)})`);\n }\n\n const session: VotingSession = {\n id: generateSessionId(),\n topic,\n committee,\n rounds: [],\n currentRound: 0,\n config: sessionConfig,\n status: 'active',\n createdAt: getTimeProvider().nowIso(),\n };\n\n this.sessions.set(session.id, session);\n this.logger.info('Voting session created', {\n sessionId: session.id,\n topic,\n committeeSize: committee.length,\n });\n\n return session;\n }\n\n /**\n * Start the analysis round (Round 1).\n */\n startAnalysisRound(sessionId: string): Promise<VotingRound> {\n const session = this.getSessionOrThrow(sessionId);\n this.validateSessionActive(session);\n\n if (session.currentRound !== 0) {\n return Promise.reject(new Error('Analysis round can only be started as Round 1'));\n }\n\n const round = createRound('analysis', 1);\n session.rounds.push(round);\n session.currentRound = 1;\n\n this.logger.info('Analysis round started', { sessionId, roundId: round.id });\n return Promise.resolve(round);\n }\n\n /**\n * Submit findings from an agent during analysis.\n */\n submitFindings(sessionId: string, agentId: string, findings: AgentFinding[]): Promise<void> {\n const session = this.getSessionOrThrow(sessionId);\n this.validateSessionActive(session);\n\n const currentRound = this.getCurrentRound(session);\n if (currentRound.phase !== 'analysis') {\n return Promise.reject(new Error('Findings can only be submitted during analysis round'));\n }\n\n if (!session.committee.includes(agentId)) {\n return Promise.reject(new Error(`Agent ${agentId} is not a committee member`));\n }\n\n for (const finding of findings) {\n const validation = AgentFindingSchema.safeParse(finding);\n if (!validation.success) {\n return Promise.reject(new Error(`Invalid finding: ${validation.error.message}`));\n }\n\n const findingId = generateFindingId();\n const timestampedFinding = {\n ...validation.data,\n agentId,\n timestamp: getTimeProvider().nowIso(),\n };\n currentRound.findings.set(findingId, timestampedFinding);\n }\n\n this.logger.debug('Findings submitted', { sessionId, agentId, findingsCount: findings.length });\n return Promise.resolve();\n }\n\n /**\n * Start the deliberation round (Round 2).\n */\n startDeliberationRound(sessionId: string): Promise<VotingRound> {\n const session = this.getSessionOrThrow(sessionId);\n this.validateSessionActive(session);\n\n if (session.currentRound !== 1) {\n return Promise.reject(new Error('Deliberation round can only be started after analysis'));\n }\n\n const analysisRound = session.rounds[0];\n if (analysisRound) {\n analysisRound.status = 'completed';\n analysisRound.completedAt = getTimeProvider().nowIso();\n }\n\n if (session.config.enableAntiSycophancy) {\n const report = this.detectSycophancy(sessionId);\n if (report.detected) {\n this.logger.warn('Sycophancy detected before deliberation', {\n sessionId,\n indicators: report.indicators.length,\n });\n }\n }\n\n const round = createRound('deliberation', 2);\n if (analysisRound) {\n analysisRound.findings.forEach((finding, id) => {\n round.findings.set(id, finding);\n round.findingVotes.set(id, []);\n });\n }\n\n session.rounds.push(round);\n session.currentRound = 2;\n\n this.logger.info('Deliberation round started', {\n sessionId,\n roundId: round.id,\n findingsCount: round.findings.size,\n });\n return Promise.resolve(round);\n }\n\n /**\n * Vote on findings during deliberation.\n */\n voteOnFinding(sessionId: string, vote: FindingVote): Promise<void> {\n const session = this.getSessionOrThrow(sessionId);\n this.validateSessionActive(session);\n\n const currentRound = this.getCurrentRound(session);\n if (currentRound.phase !== 'deliberation') {\n return Promise.reject(new Error('Finding votes can only be submitted during deliberation'));\n }\n\n const validation = FindingVoteSchema.safeParse(vote);\n if (!validation.success) {\n return Promise.reject(new Error(`Invalid vote: ${validation.error.message}`));\n }\n\n if (!session.committee.includes(vote.agentId)) {\n return Promise.reject(new Error(`Agent ${vote.agentId} is not a committee member`));\n }\n\n if (!currentRound.findings.has(vote.findingId)) {\n return Promise.reject(new Error(`Finding ${vote.findingId} not found`));\n }\n\n const existingVotes = currentRound.findingVotes.get(vote.findingId) ?? [];\n const filtered = existingVotes.filter((v) => v.agentId !== vote.agentId);\n filtered.push(validation.data);\n currentRound.findingVotes.set(vote.findingId, filtered);\n\n this.logger.debug('Finding vote recorded', {\n sessionId,\n agentId: vote.agentId,\n findingId: vote.findingId,\n agree: vote.agree,\n });\n return Promise.resolve();\n }\n\n /**\n * Start the consensus round (Round 3).\n */\n startConsensusRound(sessionId: string): Promise<VotingRound> {\n const session = this.getSessionOrThrow(sessionId);\n this.validateSessionActive(session);\n\n if (session.currentRound !== 2) {\n return Promise.reject(new Error('Consensus round can only be started after deliberation'));\n }\n\n const deliberationRound = session.rounds[1];\n if (deliberationRound) {\n deliberationRound.status = 'completed';\n deliberationRound.completedAt = getTimeProvider().nowIso();\n }\n\n const round = createRound('consensus', 3);\n session.rounds.push(round);\n session.currentRound = 3;\n\n this.logger.info('Consensus round started', { sessionId, roundId: round.id });\n return Promise.resolve(round);\n }\n\n /**\n * Submit final vote during consensus.\n */\n submitFinalVote(sessionId: string, agentId: string, vote: Vote): Promise<void> {\n const session = this.getSessionOrThrow(sessionId);\n this.validateSessionActive(session);\n\n const currentRound = this.getCurrentRound(session);\n if (currentRound.phase !== 'consensus') {\n return Promise.reject(new Error('Final votes can only be submitted during consensus'));\n }\n\n const validation = VoteSchema.safeParse(vote);\n if (!validation.success) {\n return Promise.reject(new Error(`Invalid vote: ${validation.error.message}`));\n }\n\n if (!session.committee.includes(agentId)) {\n return Promise.reject(new Error(`Agent ${agentId} is not a committee member`));\n }\n\n currentRound.finalVotes.set(agentId, {\n ...validation.data,\n timestamp: getTimeProvider().nowIso(),\n });\n\n this.logger.debug('Final vote recorded', {\n sessionId,\n agentId,\n decision: vote.decision,\n confidence: vote.confidence,\n });\n return Promise.resolve();\n }\n\n /**\n * Get the final result.\n */\n getResult(sessionId: string): Promise<VotingProtocolResult | null> {\n const session = this.sessions.get(sessionId);\n if (!session) return Promise.resolve(null);\n\n if (session.status === 'completed' && session.finalResult) {\n return Promise.resolve(session.finalResult);\n }\n\n if (session.currentRound < 3) return Promise.resolve(null);\n\n const consensusRound = session.rounds[2];\n if (!consensusRound) return Promise.resolve(null);\n\n // whenEmpty = false: a committee of zero members has cast zero votes, and\n // `[].every()` used to report that as \"everyone voted\" — finalizing the\n // session as `completed` with an outcome derived from no ballots at all.\n // Zero voters is the absence of consensus, not unanimous consensus, so the\n // empty case takes the same path as a partial vote: no result, session stays\n // active, and the record never claims a vote that was never held. (#4581)\n const allVoted = allOf(\n session.committee,\n (agentId) => consensusRound.finalVotes.has(agentId),\n false\n );\n if (!allVoted) return Promise.resolve(null);\n\n const result = this.buildFinalResult(session);\n session.finalResult = result;\n session.status = 'completed';\n session.completedAt = getTimeProvider().nowIso();\n\n consensusRound.status = 'completed';\n consensusRound.completedAt = getTimeProvider().nowIso();\n\n this.logger.info('Voting session completed', {\n sessionId,\n outcome: result.outcome,\n agreementScore: result.agreementScore,\n consolidatedFindings: result.consolidatedFindings.length,\n });\n\n return Promise.resolve(result);\n }\n\n /**\n * Detect sycophancy patterns.\n */\n detectSycophancy(sessionId: string): SycophancyReport {\n const session = this.getSessionOrThrow(sessionId);\n return detectSycophancyPatterns(session);\n }\n\n /**\n * Get the current session state.\n */\n getSession(sessionId: string): VotingSession | undefined {\n return this.sessions.get(sessionId);\n }\n\n private getSessionOrThrow(sessionId: string): VotingSession {\n const session = this.sessions.get(sessionId);\n if (!session) {\n throw new Error(`Session ${sessionId} not found`);\n }\n return session;\n }\n\n private validateSessionActive(session: VotingSession): void {\n if (session.status !== 'active') {\n throw new Error(`Session ${session.id} is ${session.status}`);\n }\n }\n\n private getCurrentRound(session: VotingSession): VotingRound {\n const round = session.rounds[session.currentRound - 1];\n if (!round) {\n throw new Error(`No round ${String(session.currentRound)} found`);\n }\n return round;\n }\n\n private buildFinalResult(session: VotingSession): VotingProtocolResult {\n const startTime = new Date(session.createdAt).getTime();\n const endTime = getTimeProvider().now();\n\n const consolidatedFindingsList = consolidateFindings(session);\n const roundSummaries = buildRoundSummaries(session);\n\n const consensusRound = session.rounds[2];\n const finalVotes = consensusRound ? Array.from(consensusRound.finalVotes.values()) : [];\n const outcome = determineOutcome(finalVotes, session.config);\n const agreementScore = calculateAgreementScore(finalVotes);\n const sycophancyReport = detectSycophancyPatterns(session);\n\n return {\n sessionId: session.id,\n topic: session.topic,\n outcome,\n consolidatedFindings: consolidatedFindingsList,\n roundSummaries,\n agreementScore,\n sycophancyDetected: sycophancyReport.detected,\n totalDurationMs: endTime - startTime,\n participatingAgents: session.committee,\n };\n }\n}\n\n/**\n * Create a voting protocol instance.\n */\nexport function createVotingProtocol(customLogger?: ILogger): VotingProtocol {\n return new VotingProtocol(customLogger);\n}\n","/**\n * Byzantine Detection CollaborationEventBus Integration Helpers\n * (Source: Issue #218, Sprint #228)\n *\n * Provides helper functions for emitting Byzantine fault detection events.\n * Used by CP-WBFT weighted voting to report Byzantine behavior patterns.\n *\n * @module agents/collaboration/byzantine-events\n */\n\nimport type {\n ICollaborationEventBus,\n ByzantineWeightUpdatedEvent,\n ByzantinePatternDetectedEvent,\n ByzantineAgentFlaggedEvent,\n ByzantineCollusionSuspectedEvent,\n} from './event-bus-types.js';\nimport { createEvent } from './event-bus.js';\n\n// =============================================================================\n// Weight Update Events\n// =============================================================================\n\n/** Parameters for emitting byzantine.weight_updated event. */\nexport interface WeightUpdatedParams {\n readonly agentId: string;\n readonly previousWeight: number;\n readonly newWeight: number;\n readonly reason: 'performance_update' | 'flag_penalty' | 'recalibration';\n readonly sessionId?: string | undefined;\n readonly correlationId?: string | undefined;\n}\n\n/** Emits byzantine.weight_updated event when an agent's weight changes. */\nexport function emitWeightUpdated(\n eventBus: ICollaborationEventBus,\n params: WeightUpdatedParams\n): void {\n const event = createEvent<ByzantineWeightUpdatedEvent>(\n 'byzantine.weight_updated',\n {\n agentId: params.agentId,\n previousWeight: params.previousWeight,\n newWeight: params.newWeight,\n reason: params.reason,\n },\n {\n ...(params.sessionId !== undefined && { sessionId: params.sessionId }),\n ...(params.correlationId !== undefined && { correlationId: params.correlationId }),\n }\n );\n eventBus.emit(event);\n}\n\n// =============================================================================\n// Pattern Detection Events\n// =============================================================================\n\n/** Parameters for emitting byzantine.pattern_detected event. */\nexport interface PatternDetectedParams {\n readonly patternType: 'contrarian' | 'collusion';\n readonly agentIds: readonly string[];\n readonly confidence: number;\n readonly details: string;\n readonly sessionId?: string | undefined;\n readonly correlationId?: string | undefined;\n}\n\n/** Emits byzantine.pattern_detected event when Byzantine pattern is detected. */\nexport function emitPatternDetected(\n eventBus: ICollaborationEventBus,\n params: PatternDetectedParams\n): void {\n const event = createEvent<ByzantinePatternDetectedEvent>(\n 'byzantine.pattern_detected',\n {\n patternType: params.patternType,\n agentIds: params.agentIds,\n confidence: params.confidence,\n details: params.details,\n },\n {\n ...(params.sessionId !== undefined && { sessionId: params.sessionId }),\n ...(params.correlationId !== undefined && { correlationId: params.correlationId }),\n }\n );\n eventBus.emit(event);\n}\n\n// =============================================================================\n// Agent Flagged Events\n// =============================================================================\n\n/** Parameters for emitting byzantine.agent_flagged event. */\nexport interface AgentFlaggedParams {\n readonly agentId: string;\n readonly reason: string;\n readonly previousWeight: number;\n readonly canVote: boolean;\n readonly sessionId?: string | undefined;\n readonly correlationId?: string | undefined;\n}\n\n/** Emits byzantine.agent_flagged event when an agent is flagged as Byzantine. */\nexport function emitAgentFlagged(\n eventBus: ICollaborationEventBus,\n params: AgentFlaggedParams\n): void {\n const event = createEvent<ByzantineAgentFlaggedEvent>(\n 'byzantine.agent_flagged',\n {\n agentId: params.agentId,\n reason: params.reason,\n previousWeight: params.previousWeight,\n canVote: params.canVote,\n },\n {\n ...(params.sessionId !== undefined && { sessionId: params.sessionId }),\n ...(params.correlationId !== undefined && { correlationId: params.correlationId }),\n }\n );\n eventBus.emit(event);\n}\n\n// =============================================================================\n// Collusion Suspected Events\n// =============================================================================\n\n/** Parameters for emitting byzantine.collusion_suspected event. */\nexport interface CollusionSuspectedParams {\n readonly groupAgentIds: readonly string[];\n readonly groupSize: number;\n readonly votingBlock: number;\n readonly threshold: number;\n readonly sessionId?: string | undefined;\n readonly correlationId?: string | undefined;\n}\n\n/** Emits byzantine.collusion_suspected event when collusion pattern is suspected. */\nexport function emitCollusionSuspected(\n eventBus: ICollaborationEventBus,\n params: CollusionSuspectedParams\n): void {\n const event = createEvent<ByzantineCollusionSuspectedEvent>(\n 'byzantine.collusion_suspected',\n {\n groupAgentIds: params.groupAgentIds,\n groupSize: params.groupSize,\n votingBlock: params.votingBlock,\n threshold: params.threshold,\n },\n {\n ...(params.sessionId !== undefined && { sessionId: params.sessionId }),\n ...(params.correlationId !== undefined && { correlationId: params.correlationId }),\n }\n );\n eventBus.emit(event);\n}\n","/**\n * nexus-agents/consensus - Weighted Byzantine Voting Helpers\n *\n * Pure helper functions extracted from WeightedVoting class.\n * These functions are stateless and operate on parameters only.\n *\n * @module consensus/weighted-voting-helpers\n * (Source: Issue #103, arXiv:2511.10400 - CP-WBFT)\n */\n\nimport { getTimeProvider } from '../core/index.js';\nimport { clamp01 } from '../utils/math-utils.js';\nimport type { WeightedAgentRecord, WeightedConsensusResult, Vote } from './types.js';\nimport type { ICollaborationEventBus } from '../core/event-bus.js';\n\n/**\n * Mutable agent record for internal tracking.\n * Used internally by WeightedVoting class.\n */\nexport interface MutableAgentRecord {\n agentId: string;\n totalTasks: number;\n successfulTasks: number;\n failedTasks: number;\n partialTasks: number;\n successRate: number;\n weight: number;\n trustScore: number;\n byzantineFlags: number;\n byzantineReasons: string[];\n lastActive: Date;\n createdAt: Date;\n}\n\n/** Options for WeightedVoting constructor. */\nexport interface WeightedVotingOptions {\n /** Configuration for voting thresholds and weights. */\n config?: Partial<import('./types.js').WeightedVotingConfig>;\n /** Optional event bus for Byzantine detection events (Issue #218). */\n eventBus?: ICollaborationEventBus;\n /** Whether to emit Byzantine detection events (default: true if eventBus provided). */\n emitEvents?: boolean;\n}\n\n/**\n * Check if a vote is a low-confidence contrarian vote.\n * Used for Byzantine pattern detection.\n */\nexport function isLowConfidenceContrarian(vote: Vote, majorityApprove: boolean): boolean {\n const isContrarian = majorityApprove ? vote.decision === 'reject' : vote.decision === 'approve';\n return isContrarian && vote.confidence < 0.3;\n}\n\n/**\n * Compute the majority vote direction based on weighted votes.\n * Returns true if majority approves, false if majority rejects.\n */\nexport function computeMajorityDirection(\n voteArray: ReadonlyArray<readonly [string, Vote]>,\n weights: ReadonlyMap<string, number>\n): boolean {\n let totalApprove = 0;\n let totalReject = 0;\n for (const [agentId, vote] of voteArray) {\n const w = weights.get(agentId) ?? 0;\n if (vote.decision === 'approve') totalApprove += w;\n if (vote.decision === 'reject') totalReject += w;\n }\n return totalApprove > totalReject;\n}\n\n/**\n * Determine consensus decision based on vote tallies.\n */\nexport function determineDecision(\n approval: number,\n rejection: number,\n total: number,\n quorumReached: boolean,\n quorumThreshold: number\n): WeightedConsensusResult['decision'] {\n if (!quorumReached || total === 0) return 'no_consensus';\n const approvalRatio = approval / total;\n const rejectionRatio = rejection / total;\n if (approvalRatio > rejectionRatio && approvalRatio >= quorumThreshold) return 'approve';\n if (rejectionRatio > approvalRatio && rejectionRatio >= quorumThreshold) return 'reject';\n return 'no_consensus';\n}\n\n/**\n * Update derived metrics (success rate, trust score) on a mutable record.\n */\nexport function updateDerivedMetrics(record: MutableAgentRecord): void {\n // Update success rate\n if (record.totalTasks > 0) {\n const weightedSuccess = record.successfulTasks + record.partialTasks * 0.5;\n record.successRate = weightedSuccess / record.totalTasks;\n }\n\n // Update trust score based on weight and Byzantine flags\n const byzantinePenalty = Math.pow(0.7, record.byzantineFlags);\n record.trustScore = Math.min(1, record.weight * byzantinePenalty);\n}\n\n/**\n * Convert a mutable internal record to an immutable public record.\n */\nexport function toImmutableRecord(record: MutableAgentRecord): WeightedAgentRecord {\n return {\n agentId: record.agentId,\n totalTasks: record.totalTasks,\n successfulTasks: record.successfulTasks,\n failedTasks: record.failedTasks,\n partialTasks: record.partialTasks,\n successRate: record.successRate,\n weight: record.weight,\n trustScore: record.trustScore,\n byzantineFlags: record.byzantineFlags,\n lastActive: record.lastActive,\n createdAt: record.createdAt,\n };\n}\n\n/**\n * Create a vote signature for collusion detection.\n * Combines decision and confidence into a unique key.\n */\nexport function createVoteSignature(vote: Vote): string {\n return `${vote.decision}:${vote.confidence.toFixed(2)}`;\n}\n\n/**\n * Group votes by their signature for collusion pattern detection.\n */\nexport function groupVotesBySignature(\n voteArray: ReadonlyArray<readonly [string, Vote]>\n): Map<string, string[]> {\n const signatures = new Map<string, string[]>();\n for (const [agentId, vote] of voteArray) {\n const sig = createVoteSignature(vote);\n const agents = signatures.get(sig) ?? [];\n agents.push(agentId);\n signatures.set(sig, agents);\n }\n return signatures;\n}\n\n/**\n * Create a new mutable agent record with initial values.\n */\nexport function createAgentRecord(agentId: string, initialWeight: number): MutableAgentRecord {\n const now = new Date(getTimeProvider().now());\n return {\n agentId,\n totalTasks: 0,\n successfulTasks: 0,\n failedTasks: 0,\n partialTasks: 0,\n successRate: 0,\n weight: initialWeight,\n trustScore: initialWeight,\n byzantineFlags: 0,\n byzantineReasons: [],\n lastActive: now,\n createdAt: now,\n };\n}\n\n/**\n * Compute global success statistics from all agent records.\n */\nexport function computeGlobalStats(records: Iterable<MutableAgentRecord>): {\n globalSuccessRate: number;\n totalTasks: number;\n} {\n let totalSuccess = 0;\n let totalTasks = 0;\n\n for (const record of records) {\n totalSuccess += record.successfulTasks;\n totalTasks += record.totalTasks;\n }\n\n const globalSuccessRate = totalTasks > 0 ? totalSuccess / totalTasks : 0.5;\n return { globalSuccessRate, totalTasks };\n}\n\n/**\n * Calculate calibrated weight based on relative performance.\n */\nexport function calculateCalibratedWeight(\n record: MutableAgentRecord,\n globalSuccessRate: number,\n initialWeight: number\n): number {\n const relativePerformance = record.successRate / Math.max(0.01, globalSuccessRate);\n const calibratedWeight = clamp01(initialWeight * relativePerformance);\n // Smooth transition (50% old weight, 50% calibrated)\n return (record.weight + calibratedWeight) / 2;\n}\n\n/**\n * Apply weight change based on task outcome.\n */\nexport function applyOutcomeWeight(\n currentWeight: number,\n outcome: import('./types.js').TaskOutcomeStatus,\n decayFactor: number,\n recoveryFactor: number\n): number {\n switch (outcome) {\n case 'success':\n return Math.min(1, currentWeight * recoveryFactor);\n case 'failure':\n return Math.max(0, currentWeight * decayFactor);\n case 'partial':\n return Math.max(0, currentWeight * ((decayFactor + 1) / 2));\n case 'unknown':\n return currentWeight;\n }\n}\n","/**\n * nexus-agents/consensus - Weighted Byzantine Voting Implementation\n *\n * Implements CP-WBFT (arXiv:2511.10400) for weighted Byzantine fault-tolerant voting.\n * Agent votes are weighted by historical reliability with automatic trust calibration.\n *\n * @module consensus/weighted-voting\n * (Source: Issue #103, arXiv:2511.10400 - CP-WBFT)\n */\n\nimport { createLogger } from '../core/logger.js';\nimport { getTimeProvider } from '../core/index.js';\nimport type {\n IWeightedVoting,\n WeightedAgentRecord,\n WeightedConsensusResult,\n WeightedVotingConfig,\n TaskOutcomeStatus,\n Vote,\n} from './types.js';\nimport { DEFAULT_WEIGHTED_VOTING_CONFIG } from './types.js';\nimport type { ICollaborationEventBus } from '../core/event-bus.js';\nimport {\n emitWeightUpdated,\n emitPatternDetected,\n emitAgentFlagged,\n emitCollusionSuspected,\n} from '../agents/collaboration/byzantine-events.js';\nimport {\n type MutableAgentRecord,\n type WeightedVotingOptions,\n isLowConfidenceContrarian,\n computeMajorityDirection,\n determineDecision,\n updateDerivedMetrics,\n toImmutableRecord,\n groupVotesBySignature,\n createAgentRecord,\n computeGlobalStats,\n calculateCalibratedWeight,\n applyOutcomeWeight,\n} from './weighted-voting-helpers.js';\n\nexport type { WeightedVotingOptions } from './weighted-voting-helpers.js';\n\nconst logger = createLogger({ component: 'weighted-voting' });\n\n/**\n * Weighted Byzantine voting implementation.\n * Implements CP-WBFT pattern for fault-tolerant multi-agent consensus.\n */\nexport class WeightedVoting implements IWeightedVoting {\n private readonly records: Map<string, MutableAgentRecord> = new Map();\n private readonly config: WeightedVotingConfig;\n private readonly eventBus: ICollaborationEventBus | undefined;\n private readonly emitEvents: boolean;\n\n constructor(options: WeightedVotingOptions = {}) {\n this.config = { ...DEFAULT_WEIGHTED_VOTING_CONFIG, ...options.config };\n this.eventBus = options.eventBus ?? undefined;\n this.emitEvents = options.emitEvents ?? options.eventBus !== undefined;\n logger.info('WeightedVoting initialized', {\n config: this.config,\n eventsEnabled: this.emitEvents,\n });\n }\n\n calculateWeight(agentId: string): number {\n const record = this.records.get(agentId);\n if (record === undefined) return 0;\n return record.weight;\n }\n\n updatePerformance(agentId: string, outcome: TaskOutcomeStatus): void {\n let record = this.records.get(agentId);\n if (record === undefined) {\n this.registerAgent(agentId);\n record = this.records.get(agentId);\n if (record === undefined) return;\n }\n\n const previousWeight = record.weight;\n record.totalTasks += 1;\n record.lastActive = new Date(getTimeProvider().now());\n\n // Update task counts\n if (outcome === 'success') record.successfulTasks += 1;\n else if (outcome === 'failure') record.failedTasks += 1;\n else if (outcome === 'partial') record.partialTasks += 1;\n\n // Apply weight change\n record.weight = applyOutcomeWeight(\n record.weight,\n outcome,\n this.config.weightDecayFactor,\n this.config.weightRecoveryFactor\n );\n updateDerivedMetrics(record);\n this.emitWeightChange(agentId, previousWeight, record.weight, 'performance_update');\n\n logger.debug('Performance updated', {\n agentId,\n outcome,\n newWeight: record.weight,\n successRate: record.successRate,\n });\n }\n\n weightedConsensus(votes: ReadonlyMap<string, Vote>): WeightedConsensusResult {\n const { approval, rejection, total, agents, breakdown } = this.countVotes(votes);\n const byzantineDetected = this.detectByzantinePatterns(votes, breakdown);\n const quorumReached = total >= this.config.quorumThreshold;\n const decision = determineDecision(\n approval,\n rejection,\n total,\n quorumReached,\n this.config.quorumThreshold\n );\n\n const result: WeightedConsensusResult = {\n decision,\n weightedApproval: approval,\n weightedRejection: rejection,\n totalWeight: total,\n quorumReached,\n byzantineDetected,\n participatingAgents: agents,\n weightBreakdown: breakdown,\n };\n\n this.logConsensusResult(result);\n return result;\n }\n\n registerAgent(agentId: string): void {\n if (this.records.has(agentId)) {\n logger.debug('Agent already registered', { agentId });\n return;\n }\n const record = createAgentRecord(agentId, this.config.initialWeight);\n this.records.set(agentId, record);\n logger.info('Agent registered', { agentId, initialWeight: this.config.initialWeight });\n }\n\n getAgentRecord(agentId: string): WeightedAgentRecord | undefined {\n const record = this.records.get(agentId);\n if (record === undefined) return undefined;\n return toImmutableRecord(record);\n }\n\n flagByzantine(agentId: string, reason: string): void {\n const record = this.records.get(agentId);\n if (record === undefined) {\n logger.warn('Cannot flag unregistered agent', { agentId });\n return;\n }\n\n const previousWeight = record.weight;\n record.byzantineFlags += 1;\n record.byzantineReasons.push(reason);\n record.weight = Math.max(0, record.weight * 0.5);\n updateDerivedMetrics(record);\n\n const canStillVote = this.canVote(agentId);\n this.emitAgentFlaggedEvent(agentId, reason, previousWeight, canStillVote);\n this.emitWeightChange(agentId, previousWeight, record.weight, 'flag_penalty');\n\n logger.warn('Agent flagged for Byzantine behavior', {\n agentId,\n reason,\n totalFlags: record.byzantineFlags,\n newWeight: record.weight,\n });\n\n if (record.byzantineFlags >= this.config.byzantineFlagThreshold) {\n this.excludeAgent(record);\n }\n }\n\n getAllRecords(): readonly WeightedAgentRecord[] {\n return Array.from(this.records.values()).map((r) => toImmutableRecord(r));\n }\n\n canVote(agentId: string): boolean {\n const record = this.records.get(agentId);\n if (record === undefined) return false;\n return record.weight >= this.config.minWeight && record.trustScore >= this.config.minTrustScore;\n }\n\n recalibrateWeights(): void {\n const { globalSuccessRate, totalTasks } = computeGlobalStats(this.records.values());\n if (totalTasks === 0) return;\n\n for (const record of this.records.values()) {\n if (record.totalTasks < 3) continue;\n const previousWeight = record.weight;\n record.weight = calculateCalibratedWeight(\n record,\n globalSuccessRate,\n this.config.initialWeight\n );\n updateDerivedMetrics(record);\n this.emitWeightChange(record.agentId, previousWeight, record.weight, 'recalibration');\n }\n\n logger.info('Weights recalibrated', {\n agentCount: this.records.size,\n globalSuccessRate: globalSuccessRate.toFixed(3),\n });\n }\n\n // Private helpers\n\n private countVotes(votes: ReadonlyMap<string, Vote>): {\n approval: number;\n rejection: number;\n total: number;\n agents: string[];\n breakdown: Map<string, number>;\n } {\n let approval = 0;\n let rejection = 0;\n let total = 0;\n const agents: string[] = [];\n const breakdown = new Map<string, number>();\n\n for (const [agentId, vote] of votes) {\n if (!this.canVote(agentId)) {\n logger.warn('Agent cannot vote', { agentId, reason: 'insufficient weight or trust' });\n continue;\n }\n const weight = this.calculateWeight(agentId);\n breakdown.set(agentId, weight);\n agents.push(agentId);\n total += weight;\n const effectiveWeight = weight * vote.confidence;\n if (vote.decision === 'approve') approval += effectiveWeight;\n else if (vote.decision === 'reject') rejection += effectiveWeight;\n }\n return { approval, rejection, total, agents, breakdown };\n }\n\n private logConsensusResult(result: WeightedConsensusResult): void {\n logger.info('Weighted consensus calculated', {\n decision: result.decision,\n approval: result.weightedApproval.toFixed(3),\n rejection: result.weightedRejection.toFixed(3),\n totalWeight: result.totalWeight.toFixed(3),\n quorumReached: result.quorumReached,\n byzantineDetected: result.byzantineDetected,\n });\n }\n\n private emitWeightChange(\n agentId: string,\n prev: number,\n next: number,\n reason: 'performance_update' | 'flag_penalty' | 'recalibration'\n ): void {\n if (this.emitEvents && this.eventBus !== undefined && prev !== next) {\n emitWeightUpdated(this.eventBus, { agentId, previousWeight: prev, newWeight: next, reason });\n }\n }\n\n private emitAgentFlaggedEvent(\n agentId: string,\n reason: string,\n previousWeight: number,\n canVote: boolean\n ): void {\n if (this.emitEvents && this.eventBus !== undefined) {\n emitAgentFlagged(this.eventBus, { agentId, reason, previousWeight, canVote });\n }\n }\n\n private excludeAgent(record: MutableAgentRecord): void {\n const weightBefore = record.weight;\n record.trustScore = 0;\n record.weight = 0;\n this.emitWeightChange(record.agentId, weightBefore, 0, 'flag_penalty');\n logger.warn('Agent excluded from voting due to Byzantine behavior', {\n agentId: record.agentId,\n flags: record.byzantineFlags,\n });\n }\n\n private detectByzantinePatterns(\n votes: ReadonlyMap<string, Vote>,\n weights: Map<string, number>\n ): boolean {\n const voteArray = Array.from(votes.entries());\n if (voteArray.length < 3) return false;\n const majorityApprove = computeMajorityDirection(voteArray, weights);\n if (this.detectContrarianByzantine(voteArray, majorityApprove)) return true;\n return this.detectCollusionPattern(voteArray);\n }\n\n private detectContrarianByzantine(\n voteArray: Array<[string, Vote]>,\n majorityApprove: boolean\n ): boolean {\n const contrarianAgents: string[] = [];\n for (const [agentId, vote] of voteArray) {\n if (!isLowConfidenceContrarian(vote, majorityApprove)) continue;\n const record = this.records.get(agentId);\n if (record !== undefined && record.byzantineFlags >= 2) {\n contrarianAgents.push(agentId);\n }\n }\n if (contrarianAgents.length > 0) {\n this.emitContrarianPattern(contrarianAgents);\n return true;\n }\n return false;\n }\n\n private emitContrarianPattern(agents: string[]): void {\n if (this.emitEvents && this.eventBus !== undefined) {\n emitPatternDetected(this.eventBus, {\n patternType: 'contrarian',\n agentIds: agents,\n confidence: 0.8,\n details: `${String(agents.length)} agent(s) with Byzantine flags voting contrary to majority with low confidence`,\n });\n }\n }\n\n private detectCollusionPattern(voteArray: Array<[string, Vote]>): boolean {\n const voteSignatures = groupVotesBySignature(voteArray);\n const threshold = voteArray.length * 0.6;\n for (const [signature, agents] of voteSignatures.entries()) {\n if (agents.length >= 3 && agents.length > threshold) {\n this.emitCollusionEvents(agents, signature, voteArray.length);\n return true;\n }\n }\n return false;\n }\n\n private emitCollusionEvents(agents: string[], signature: string, totalVotes: number): void {\n if (this.emitEvents && this.eventBus !== undefined) {\n emitPatternDetected(this.eventBus, {\n patternType: 'collusion',\n agentIds: agents,\n confidence: Math.min(0.95, agents.length / totalVotes),\n details: `${String(agents.length)} agents voting identically: ${signature}`,\n });\n emitCollusionSuspected(this.eventBus, {\n groupAgentIds: agents,\n groupSize: agents.length,\n votingBlock: agents.length / totalVotes,\n threshold: 0.6,\n });\n }\n }\n}\n\n/** Create a weighted voting instance. */\nexport function createWeightedVoting(options?: WeightedVotingOptions): IWeightedVoting {\n return new WeightedVoting(options);\n}\n","/**\n * How independent a subset of agents is, and how much of it was measured.\n *\n * Its own module because the score and its coverage are one fact: the score\n * averages only the pairs present in the correlation matrix, so without the\n * coverage a subset whose pairs were MEASURED at 0 is indistinguishable from\n * one whose pairs were NEVER OBSERVED — and 0 earns the maximum posterior\n * weight in `aggregateSubsets`.\n *\n * @module consensus/subset-independence\n */\nimport type { CorrelationMatrix } from './higher-order-types.js';\nimport { createAgentPairKey } from './higher-order-types.js';\n\n/**\n * The independence score AND how much of the subset it was measured over.\n *\n * An unobserved pair counts as MAXIMALLY correlated (#5813, panel option B).\n * Before that it was dropped from the average, so a subset whose pairs were\n * MEASURED at 0 and one whose pairs were NEVER OBSERVED both scored 0 — and 0\n * earns the maximum posterior weight in `aggregateSubsets` (`size * (1 -\n * score)`). Absent evidence was credited as evidence of independence.\n *\n * The panel asked which error to optimise against and answered unanimously\n * among its approvers: over-weighting a secretly correlated bloc, not\n * under-weighting a genuinely independent voice. The first fabricates\n * independent evidence and cannot be recovered from; the second shrinks\n * monotonically as pairs are observed.\n *\n * `total` is C(n,2), so a singleton reports `{ observed: 0, total: 0 }`: no pair\n * exists to observe. It has no peer to correlate with, so there is nothing to\n * discount and it keeps full weight — an unmeasurABLE subset is not an\n * unmeasurED one. That falls out of the formula rather than needing a guard,\n * because zero total pairs means zero missing pairs to charge for.\n *\n * Equivalence worth knowing before anyone \"simplifies\" this: charging 1.0 per\n * missing pair is ALGEBRAICALLY IDENTICAL to scaling the weight by coverage,\n * `(observed/total) * (1 - score)` — the panel's options A and B were the same\n * formula. This spelling is the one that answers the singleton without a\n * 0/0 guard. Verified numerically to 8.9e-16 over 5000 random subsets.\n */\nexport function computeSubsetIndependence(\n subset: readonly string[],\n correlationMatrix: CorrelationMatrix\n): { score: number; observedPairs: number; totalPairs: number } {\n const totalPairs = (subset.length * (subset.length - 1)) / 2;\n if (subset.length < 2) return { score: 0, observedPairs: 0, totalPairs };\n\n let observedCorrelation = 0;\n let pairs = 0;\n\n for (let i = 0; i < subset.length; i++) {\n for (let j = i + 1; j < subset.length; j++) {\n const agentA = subset[i];\n const agentB = subset[j];\n if (agentA !== undefined && agentB !== undefined) {\n const pairKey = createAgentPairKey(agentA, agentB);\n const correlation = correlationMatrix.get(pairKey);\n if (correlation !== undefined) {\n observedCorrelation += Math.abs(correlation);\n pairs++;\n }\n }\n }\n }\n\n // Every unobserved pair contributes 1.0 — maximal correlation — so the\n // denominator is the pairs that EXIST, not the pairs that were seen. A\n // fully unobserved multi-agent subset scores 1 and earns weight 0: it\n // contributes nothing rather than everything.\n const unobservedPairs = totalPairs - pairs;\n return {\n score: (observedCorrelation + unobservedPairs) / totalPairs,\n observedPairs: pairs,\n totalPairs,\n };\n}\n","/**\n * nexus-agents/consensus - Correlation Helpers\n *\n * Helper functions for correlation tracking and independent subset partitioning.\n * Extracted from correlation-tracker.ts to maintain file size limits.\n *\n * @module consensus/correlation-helpers\n * (Source: Issue #339)\n */\n\nimport type {\n CorrelationMatrix,\n CorrelationCoefficient,\n IndependentSubset,\n VotingObservation,\n HigherOrderVotingConfig,\n AgentPairKey,\n} from './higher-order-types.js';\nimport { createAgentPairKey } from './higher-order-types.js';\nimport { computeSubsetIndependence } from './subset-independence.js';\n\n// ============================================================================\n// Pairwise History Types\n// ============================================================================\n\n/**\n * Internal mutable representation of pairwise history.\n */\nexport interface MutablePairwiseHistory {\n pairKey: AgentPairKey;\n jointObservations: number;\n agreements: number;\n disagreements: number;\n correlation: CorrelationCoefficient;\n lastUpdated: Date;\n}\n\n// ============================================================================\n// Vote Agreement\n// ============================================================================\n\n/**\n * Check if two observations are comparable (neither is an abstain).\n * Abstain votes should be excluded from correlation tracking.\n *\n * @param obsA - First observation\n * @param obsB - Second observation\n * @returns True if both observations have non-abstain decisions\n */\nexport function isComparable(obsA: VotingObservation, obsB: VotingObservation): boolean {\n return obsA.decision !== 'abstain' && obsB.decision !== 'abstain';\n}\n\n/**\n * Check if two votes agree.\n * Only call this after verifying isComparable() returns true.\n * Abstains are treated as neutral - neither agree nor disagree.\n *\n * @param obsA - First observation\n * @param obsB - Second observation\n * @returns True if votes agree, null if either is an abstain (neutral)\n */\nexport function votesAgree(obsA: VotingObservation, obsB: VotingObservation): boolean | null {\n if (obsA.decision === 'abstain' || obsB.decision === 'abstain') {\n return null; // Neutral — skip this pair (Issue #763)\n }\n return obsA.decision === obsB.decision;\n}\n\n/**\n * Check if a decision aligned with the outcome.\n *\n * @param decision - The voting decision\n * @param outcome - The final outcome\n * @returns True if decision aligned with outcome\n */\nexport function didAlignWithOutcome(decision: string, outcome: 'approved' | 'rejected'): boolean {\n if (decision === 'abstain') return true;\n return (\n (decision === 'approve' && outcome === 'approved') ||\n (decision === 'reject' && outcome === 'rejected')\n );\n}\n\n// ============================================================================\n// Correlation Computation\n// ============================================================================\n\n/**\n * Compute correlation coefficient from pairwise history.\n *\n * Simple correlation: (agreements - disagreements) / total\n * Range: -1 (always disagree) to +1 (always agree)\n *\n * @param history - Pairwise history\n * @returns Correlation coefficient\n */\nexport function computeCorrelationCoefficient(\n history: MutablePairwiseHistory\n): CorrelationCoefficient {\n const n = history.jointObservations;\n if (n === 0) return 0;\n\n // Map agreement/disagreement rates to [-1, 1] correlation\n // 0.5 agreement rate = 0 correlation (random)\n // 1.0 agreement rate = +1 correlation (perfect agreement)\n // 0.0 agreement rate = -1 correlation (perfect disagreement)\n const agreementRate = history.agreements / n;\n const disagreementRate = history.disagreements / n;\n\n return agreementRate - disagreementRate;\n}\n\n// ============================================================================\n// Independent Subset Partitioning\n// ============================================================================\n\n/**\n * Check if an agent is independent from all members of a subset.\n *\n * @param agent - Agent to check\n * @param subset - Existing subset members\n * @param correlationMatrix - Correlation matrix\n * @param independenceThreshold - Maximum correlation for independence\n * @returns True if agent is independent from subset\n */\nexport function isIndependentFromSubset(\n agent: string,\n subset: readonly string[],\n correlationMatrix: CorrelationMatrix,\n independenceThreshold: number\n): boolean {\n for (const member of subset) {\n const pairKey = createAgentPairKey(agent, member);\n const correlation = correlationMatrix.get(pairKey);\n\n // If we don't have data, assume independent\n if (correlation === undefined) continue;\n\n // If correlation exceeds threshold, not independent\n if (Math.abs(correlation) > independenceThreshold) {\n return false;\n }\n }\n return true;\n}\n\n/**\n * Compute the minimum observation count for pairs within a subset.\n *\n * @param subset - Agent IDs in the subset\n * @param pairwiseHistory - Map of pairwise histories\n * @returns Minimum observation count (0 if no history)\n */\nexport function computeSubsetObservationCount(\n subset: readonly string[],\n pairwiseHistory: ReadonlyMap<AgentPairKey, MutablePairwiseHistory>\n): number {\n let minObservations = Infinity;\n\n for (let i = 0; i < subset.length; i++) {\n for (let j = i + 1; j < subset.length; j++) {\n const agentA = subset[i];\n const agentB = subset[j];\n if (agentA !== undefined && agentB !== undefined) {\n const pairKey = createAgentPairKey(agentA, agentB);\n const history = pairwiseHistory.get(pairKey);\n if (history !== undefined) {\n minObservations = Math.min(minObservations, history.jointObservations);\n } else {\n minObservations = 0;\n }\n }\n }\n }\n\n return minObservations === Infinity ? 0 : minObservations;\n}\n\n/**\n * Partition agents into independent groups using greedy clustering.\n *\n * @param agents - List of agent IDs\n * @param correlationMatrix - Correlation matrix\n * @param pairwiseHistory - Map of pairwise histories\n * @param config - Higher-order voting configuration\n * @returns Array of independent subsets\n */\nexport function partitionIntoIndependentGroups(\n agents: readonly string[],\n correlationMatrix: CorrelationMatrix,\n pairwiseHistory: ReadonlyMap<AgentPairKey, MutablePairwiseHistory>,\n config: HigherOrderVotingConfig\n): IndependentSubset[] {\n if (agents.length === 0) return [];\n\n const subsets: IndependentSubset[] = [];\n const assigned = new Set<string>();\n let subsetId = 0;\n\n for (const agent of agents) {\n if (assigned.has(agent)) continue;\n\n const subset: string[] = [agent];\n assigned.add(agent);\n\n // Try to add other unassigned agents if they're independent\n for (const other of agents) {\n if (assigned.has(other)) continue;\n if (isIndependentFromSubset(other, subset, correlationMatrix, config.independenceThreshold)) {\n subset.push(other);\n assigned.add(other);\n }\n }\n\n const independence = computeSubsetIndependence(subset, correlationMatrix);\n const observationCount = computeSubsetObservationCount(subset, pairwiseHistory);\n\n subsets.push({\n id: `subset-${String(subsetId++)}`,\n agentIds: subset,\n independenceScore: independence.score,\n pairCoverage: { observed: independence.observedPairs, total: independence.totalPairs },\n observationCount,\n });\n }\n\n return subsets;\n}\n","/**\n * Model-keyed storage for pairwise correlation aggregates.\n * Extracted because adding partition lifecycle logic to correlation-tracker.ts\n * would exceed the repository's 400-line source-file limit.\n */\n\nimport type { ILogger } from '../core/logger.js';\nimport type { AgentPairKey } from './higher-order-types.js';\nimport { parseAgentPairKey } from './higher-order-types.js';\nimport {\n computeCorrelationCoefficient,\n type MutablePairwiseHistory,\n} from './correlation-helpers.js';\n\ntype ModelTuple = [string | null, string | null];\n\nfunction encodeModels(models: ModelTuple): string {\n return JSON.stringify(models);\n}\n\nfunction isModelTuple(value: unknown): value is ModelTuple {\n if (!Array.isArray(value) || value.length !== 2) return false;\n const values = value as unknown[];\n const first = values[0];\n const second = values[1];\n return (\n (first === null || typeof first === 'string') && (second === null || typeof second === 'string')\n );\n}\n\nfunction decodeModels(key: string): ModelTuple {\n const parsed = JSON.parse(key) as unknown;\n if (!isModelTuple(parsed)) throw new Error(`Invalid correlation model partition key: ${key}`);\n return parsed;\n}\n\nfunction mergeHistory(\n target: MutablePairwiseHistory,\n source: MutablePairwiseHistory\n): MutablePairwiseHistory {\n target.jointObservations += source.jointObservations;\n target.agreements += source.agreements;\n target.disagreements += source.disagreements;\n target.correlation = computeCorrelationCoefficient(target);\n if (source.lastUpdated > target.lastUpdated) target.lastUpdated = source.lastUpdated;\n return target;\n}\n\n/** Retains every model partition while projecting only the currently pinned one. */\nexport class CorrelationModelPartitions {\n private readonly histories = new Map<AgentPairKey, Map<string, MutablePairwiseHistory>>();\n private readonly currentModels = new Map<string, string>();\n\n constructor(\n private readonly maxTrackedPairs: number,\n private readonly logger: ILogger\n ) {}\n\n setCurrentPins(modelPins: ReadonlyMap<string, string>): void {\n for (const [role, newModel] of modelPins) this.setCurrentPin(role, newModel);\n }\n\n getActiveHistory(): Map<AgentPairKey, MutablePairwiseHistory> {\n const active = new Map<AgentPairKey, MutablePairwiseHistory>();\n for (const [pairKey, partitions] of this.histories) {\n const history = partitions.get(this.activePartitionKey(pairKey));\n if (history !== undefined) active.set(pairKey, history);\n }\n return active;\n }\n\n getOrCreate(pairKey: AgentPairKey, create: () => MutablePairwiseHistory): MutablePairwiseHistory {\n let partitions = this.histories.get(pairKey);\n if (partitions === undefined) {\n partitions = new Map();\n this.histories.set(pairKey, partitions);\n }\n const modelKey = this.activePartitionKey(pairKey);\n let history = partitions.get(modelKey);\n if (history === undefined) {\n history = create();\n partitions.set(modelKey, history);\n this.evictOldestIfNeeded();\n }\n return history;\n }\n\n clear(): void {\n this.histories.clear();\n this.currentModels.clear();\n }\n\n private setCurrentPin(role: string, newModel: string): void {\n const previousModel = this.currentModels.get(role);\n if (previousModel === undefined) {\n this.adoptUnkeyedHistory(role, newModel);\n this.currentModels.set(role, newModel);\n return;\n }\n if (previousModel === newModel) return;\n\n const partitionLeftSize = this.partitionSize(role);\n this.currentModels.set(role, newModel);\n const partitionEnteredSize = this.partitionSize(role);\n this.logger.info('Correlation model partition switched', {\n role,\n previousModel,\n newModel,\n partitionLeftSize,\n partitionEnteredSize,\n });\n }\n\n private activePartitionKey(pairKey: AgentPairKey): string {\n const [agentA, agentB] = parseAgentPairKey(pairKey);\n return encodeModels([\n this.currentModels.get(agentA) ?? null,\n this.currentModels.get(agentB) ?? null,\n ]);\n }\n\n private partitionSize(role: string): number {\n let size = 0;\n for (const [pairKey, partitions] of this.histories) {\n const [agentA, agentB] = parseAgentPairKey(pairKey);\n if (agentA !== role && agentB !== role) continue;\n size += partitions.get(this.activePartitionKey(pairKey))?.jointObservations ?? 0;\n }\n return size;\n }\n\n private adoptUnkeyedHistory(role: string, newModel: string): void {\n for (const [pairKey, partitions] of this.histories) {\n const [agentA, agentB] = parseAgentPairKey(pairKey);\n const index = agentA === role ? 0 : agentB === role ? 1 : undefined;\n if (index === undefined) continue;\n this.rekeyUnkeyedPartitions(partitions, index, newModel);\n }\n }\n\n private rekeyUnkeyedPartitions(\n partitions: Map<string, MutablePairwiseHistory>,\n index: 0 | 1,\n newModel: string\n ): void {\n for (const [oldKey, history] of [...partitions]) {\n const models = decodeModels(oldKey);\n if (models[index] !== null) continue;\n models[index] = newModel;\n const newKey = encodeModels(models);\n partitions.delete(oldKey);\n const existing = partitions.get(newKey);\n partitions.set(newKey, existing === undefined ? history : mergeHistory(existing, history));\n }\n }\n\n private evictOldestIfNeeded(): void {\n while (this.historyCount() > this.maxTrackedPairs) {\n const oldest = this.findOldest();\n if (oldest === undefined) return;\n const partitions = this.histories.get(oldest.pairKey);\n partitions?.delete(oldest.modelKey);\n if (partitions?.size === 0) this.histories.delete(oldest.pairKey);\n this.logger.debug('Evicted oldest pairwise history entry', {\n evictedKey: oldest.pairKey,\n reason: 'maxTrackedPairs',\n remainingPairs: this.historyCount(),\n });\n }\n }\n\n private historyCount(): number {\n let count = 0;\n for (const partitions of this.histories.values()) count += partitions.size;\n return count;\n }\n\n private findOldest(): { pairKey: AgentPairKey; modelKey: string } | undefined {\n let oldest: { pairKey: AgentPairKey; modelKey: string } | undefined;\n let oldestTime = Infinity;\n for (const [pairKey, partitions] of this.histories) {\n for (const [modelKey, history] of partitions) {\n if (history.lastUpdated.getTime() >= oldestTime) continue;\n oldest = { pairKey, modelKey };\n oldestTime = history.lastUpdated.getTime();\n }\n }\n return oldest;\n }\n}\n","/**\n * nexus-agents/consensus - Correlation Tracker\n *\n * Tracks voting history and computes pairwise correlations between agents.\n * Used by higher-order voting methods to account for agent dependencies.\n *\n * @module consensus/correlation-tracker\n * (Source: Issue #333)\n */\n\nimport { createLogger } from '../core/logger.js';\nimport { getTimeProvider, getRandomProvider } from '../core/index.js';\nimport type { Vote } from './types-core.js';\nimport type {\n ICorrelationTracker,\n CorrelationMatrix,\n CorrelationCoefficient,\n IndependentSubset,\n VotingObservation,\n HigherOrderVotingConfig,\n CorrelationTrackerStats,\n AgentPairKey,\n CorrelationRecordContext,\n} from './higher-order-types.js';\nimport { createAgentPairKey, DEFAULT_HIGHER_ORDER_CONFIG } from './higher-order-types.js';\nimport {\n type MutablePairwiseHistory,\n isComparable,\n votesAgree,\n didAlignWithOutcome,\n computeCorrelationCoefficient,\n partitionIntoIndependentGroups,\n} from './correlation-helpers.js';\nimport { CorrelationModelPartitions } from './correlation-model-partitions.js';\n\n// Re-export helper types and functions for convenience\nexport type { MutablePairwiseHistory } from './correlation-helpers.js';\nexport {\n isComparable,\n votesAgree,\n didAlignWithOutcome,\n computeCorrelationCoefficient,\n isIndependentFromSubset,\n computeSubsetObservationCount,\n partitionIntoIndependentGroups,\n} from './correlation-helpers.js';\n\nconst logger = createLogger({ component: 'correlation-tracker' });\n\n/**\n * Correlation tracker implementation.\n * Records voting history and computes pairwise agent correlations.\n *\n * Memory bounded: uses FIFO eviction when maxObservationsPerAgent or maxProposals limits reached.\n */\nexport class CorrelationTracker implements ICorrelationTracker {\n private readonly config: HigherOrderVotingConfig;\n private readonly observations: Map<string, VotingObservation[]> = new Map();\n private readonly modelPartitions;\n private readonly agentProposals: Map<string, Map<string, VotingObservation>> = new Map();\n /** Ordered list of proposal IDs for FIFO eviction */\n private readonly proposalOrder: string[] = [];\n private cachedSubsets: IndependentSubset[] | null = null;\n\n constructor(config?: Partial<HigherOrderVotingConfig>) {\n this.config = { ...DEFAULT_HIGHER_ORDER_CONFIG, ...config };\n this.modelPartitions = new CorrelationModelPartitions(this.config.maxTrackedPairs, logger);\n logger.info('CorrelationTracker initialized', {\n maxObservationsPerAgent: this.config.maxObservationsPerAgent,\n maxProposals: this.config.maxProposals,\n });\n }\n\n setCurrentModelPins(modelPins: ReadonlyMap<string, string>): void {\n this.modelPartitions.setCurrentPins(modelPins);\n this.invalidateCache();\n }\n\n recordVote(\n agentId: string,\n vote: Vote,\n outcome: 'approved' | 'rejected',\n context?: CorrelationRecordContext\n ): void {\n if (context !== undefined) this.setCurrentModelPins(context.modelPins);\n const proposalId = `proposal-${String(getTimeProvider().now())}-${getRandomProvider().random().toString(36).slice(2, 9)}`;\n const modelKey = context?.modelPins.get(agentId);\n const observedModel = context?.observedModels?.get(agentId);\n const observation: VotingObservation = {\n proposalId,\n agentId,\n decision: vote.decision,\n confidence: vote.confidence,\n alignedWithOutcome: didAlignWithOutcome(vote.decision, outcome),\n timestamp: new Date(getTimeProvider().now()),\n ...(modelKey !== undefined ? { modelKey } : {}),\n ...(observedModel !== undefined ? { observedModel } : {}),\n };\n this.storeObservation(agentId, observation);\n this.invalidateCache();\n }\n\n recordProposalVotes(\n proposalId: string,\n votes: ReadonlyMap<string, Vote>,\n outcome: 'approved' | 'rejected',\n context?: CorrelationRecordContext\n ): void {\n if (context !== undefined) this.setCurrentModelPins(context.modelPins);\n // FIFO eviction when proposal limit reached (Issue #521)\n this.evictOldProposalsIfNeeded();\n\n const proposalObservations: VotingObservation[] = [];\n\n for (const [agentId, vote] of votes) {\n const modelKey = context?.modelPins.get(agentId);\n const observedModel = context?.observedModels?.get(agentId);\n const observation: VotingObservation = {\n proposalId,\n agentId,\n decision: vote.decision,\n confidence: vote.confidence,\n alignedWithOutcome: didAlignWithOutcome(vote.decision, outcome),\n timestamp: new Date(getTimeProvider().now()),\n ...(modelKey !== undefined ? { modelKey } : {}),\n ...(observedModel !== undefined ? { observedModel } : {}),\n };\n this.storeObservation(agentId, observation);\n this.storeAgentProposal(agentId, proposalId, observation);\n proposalObservations.push(observation);\n }\n\n // Track proposal order for FIFO eviction\n this.proposalOrder.push(proposalId);\n\n this.updatePairwiseCorrelations(proposalObservations);\n this.invalidateCache();\n\n logger.debug('Recorded proposal votes', {\n proposalId,\n agentCount: votes.size,\n outcome,\n totalProposals: this.proposalOrder.length,\n });\n }\n\n computeCorrelationMatrix(): CorrelationMatrix {\n const matrix: CorrelationMatrix = new Map();\n\n for (const [pairKey, history] of this.getActivePairwiseHistory()) {\n if (history.jointObservations >= this.config.minObservationsForCorrelation) {\n matrix.set(pairKey, history.correlation);\n }\n }\n\n return matrix;\n }\n\n getCorrelation(agentA: string, agentB: string): CorrelationCoefficient | undefined {\n const pairKey = createAgentPairKey(agentA, agentB);\n const history = this.getActivePairwiseHistory().get(pairKey);\n\n if (history === undefined) return undefined;\n if (history.jointObservations < this.config.minObservationsForCorrelation) return undefined;\n\n return history.correlation;\n }\n\n identifyIndependentSubsets(): readonly IndependentSubset[] {\n if (this.cachedSubsets !== null) return this.cachedSubsets;\n\n const agents = this.getTrackedAgents();\n if (agents.length === 0) {\n this.cachedSubsets = [];\n return this.cachedSubsets;\n }\n\n const correlationMatrix = this.computeCorrelationMatrix();\n const activeHistory = this.getActivePairwiseHistory();\n const subsets = partitionIntoIndependentGroups(\n agents,\n correlationMatrix,\n activeHistory,\n this.config\n );\n\n this.cachedSubsets = subsets;\n logger.debug('Identified independent subsets', {\n agentCount: agents.length,\n subsetCount: subsets.length,\n });\n\n return subsets;\n }\n\n hasSufficientData(agentIds: readonly string[]): boolean {\n if (agentIds.length < 2) return false;\n\n let pairsWithData = 0;\n const totalPairs = (agentIds.length * (agentIds.length - 1)) / 2;\n const activeHistory = this.getActivePairwiseHistory();\n\n for (let i = 0; i < agentIds.length; i++) {\n for (let j = i + 1; j < agentIds.length; j++) {\n const agentA = agentIds[i];\n const agentB = agentIds[j];\n if (agentA !== undefined && agentB !== undefined) {\n const pairKey = createAgentPairKey(agentA, agentB);\n const history = activeHistory.get(pairKey);\n if (\n history !== undefined &&\n history.jointObservations >= this.config.minObservationsForCorrelation\n ) {\n pairsWithData++;\n }\n }\n }\n }\n\n // Require at least 50% of pairs to have sufficient data\n return pairsWithData >= totalPairs * 0.5;\n }\n\n getStats(): CorrelationTrackerStats {\n const agents = this.getTrackedAgents();\n // Used by callers to understand full correlation state\n void this.computeCorrelationMatrix();\n const subsets = this.identifyIndependentSubsets();\n\n let totalCorrelation = 0;\n let pairsWithSufficientData = 0;\n const activeHistory = this.getActivePairwiseHistory();\n\n for (const [, history] of activeHistory) {\n if (history.jointObservations >= this.config.minObservationsForCorrelation) {\n totalCorrelation += history.correlation;\n pairsWithSufficientData++;\n }\n }\n\n let totalObservations = 0;\n for (const obs of this.observations.values()) {\n totalObservations += obs.length;\n }\n\n return {\n totalAgents: agents.length,\n trackedPairs: activeHistory.size,\n totalObservations,\n averageCorrelation:\n pairsWithSufficientData > 0 ? totalCorrelation / pairsWithSufficientData : 0,\n independentSubsetCount: subsets.length,\n pairsWithSufficientData,\n };\n }\n\n clear(): void {\n this.observations.clear();\n this.modelPartitions.clear();\n this.agentProposals.clear();\n this.proposalOrder.length = 0;\n this.cachedSubsets = null;\n logger.info('CorrelationTracker cleared');\n }\n\n // ============================================================================\n // Private helpers\n // ============================================================================\n\n /**\n * Evict oldest proposals when maxProposals limit is reached.\n * Also cleans up agentProposals entries for evicted proposals.\n */\n private evictOldProposalsIfNeeded(): void {\n while (this.proposalOrder.length >= this.config.maxProposals) {\n const evictedProposalId = this.proposalOrder.shift();\n if (evictedProposalId === undefined) break;\n\n // Clean up agentProposals for the evicted proposal\n for (const [agentId, proposalMap] of this.agentProposals) {\n if (proposalMap.has(evictedProposalId)) {\n proposalMap.delete(evictedProposalId);\n // Clean up empty agent entries\n if (proposalMap.size === 0) {\n this.agentProposals.delete(agentId);\n }\n }\n }\n\n logger.debug('Evicted oldest proposal', {\n evictedProposalId,\n reason: 'maxProposals',\n remainingProposals: this.proposalOrder.length,\n });\n }\n }\n\n private storeObservation(agentId: string, observation: VotingObservation): void {\n let agentObs = this.observations.get(agentId);\n if (agentObs === undefined) {\n agentObs = [];\n this.observations.set(agentId, agentObs);\n }\n\n // FIFO eviction when per-agent limit reached (Issue #521)\n while (agentObs.length >= this.config.maxObservationsPerAgent) {\n const evicted = agentObs.shift();\n if (evicted !== undefined) {\n logger.debug('Evicted oldest observation for agent', {\n agentId,\n evictedProposalId: evicted.proposalId,\n reason: 'maxObservationsPerAgent',\n });\n }\n }\n\n agentObs.push(observation);\n }\n\n private storeAgentProposal(\n agentId: string,\n proposalId: string,\n observation: VotingObservation\n ): void {\n let agentProposalMap = this.agentProposals.get(agentId);\n if (agentProposalMap === undefined) {\n agentProposalMap = new Map();\n this.agentProposals.set(agentId, agentProposalMap);\n }\n agentProposalMap.set(proposalId, observation);\n }\n\n private updatePairwiseCorrelations(observations: VotingObservation[]): void {\n for (let i = 0; i < observations.length; i++) {\n for (let j = i + 1; j < observations.length; j++) {\n const obsA = observations[i];\n const obsB = observations[j];\n if (obsA === undefined || obsB === undefined) continue;\n\n const pairKey = createAgentPairKey(obsA.agentId, obsB.agentId);\n const history = this.modelPartitions.getOrCreate(pairKey, () => {\n return {\n pairKey,\n jointObservations: 0,\n agreements: 0,\n disagreements: 0,\n correlation: 0,\n lastUpdated: new Date(getTimeProvider().now()),\n };\n });\n\n // Skip abstain observations — they are neutral (Issue #763)\n if (!isComparable(obsA, obsB)) continue;\n\n history.jointObservations++;\n const agreed = votesAgree(obsA, obsB);\n if (agreed === true) {\n history.agreements++;\n } else {\n history.disagreements++;\n }\n\n history.correlation = computeCorrelationCoefficient(history);\n history.lastUpdated = new Date(getTimeProvider().now());\n }\n }\n }\n\n private getTrackedAgents(): string[] {\n return Array.from(this.observations.keys());\n }\n\n private getActivePairwiseHistory(): Map<AgentPairKey, MutablePairwiseHistory> {\n return this.modelPartitions.getActiveHistory();\n }\n\n private invalidateCache(): void {\n this.cachedSubsets = null;\n }\n}\n\n/**\n * Creates a new correlation tracker instance.\n */\nexport function createCorrelationTracker(\n config?: Partial<HigherOrderVotingConfig>\n): ICorrelationTracker {\n return new CorrelationTracker(config);\n}\n","/**\n * nexus-agents/consensus - Correlation Persistence\n *\n * Disk persistence for CorrelationTracker voting history. Enables Higher-Order\n * Voting (HOV) to accumulate correlation data across process restarts,\n * activating Bayesian correlation awareness.\n *\n * Storage: append-only JSONL at `~/.nexus-agents/voting/correlations.jsonl`\n * (mode 0o600). Each line is one `PersistedProposal`. Append-only avoids the\n * cross-process read-merge-rename race the previous `correlations.json`\n * design had (#2973): two processes voting concurrently each loaded N\n * entries, each merged their own proposal, each renamed over the same file,\n * losing the loser's proposal. Append guarantees atomic-per-line writes on\n * POSIX so concurrent writers are race-free.\n *\n * Reads dedupe by `proposalId` (last write wins) and apply FIFO eviction\n * past `maxProposals`. A legacy `correlations.json` is read alongside the\n * JSONL on 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 type { Result } from '../core/result.js';\nimport { ok, err } from '../core/result.js';\nimport type { ILogger } from '../core/logger.js';\nimport { createLogger } from '../core/logger.js';\nimport type { ICorrelationTracker, HigherOrderVotingConfig } from './higher-order-types.js';\nimport { DEFAULT_HIGHER_ORDER_CONFIG } from './higher-order-types.js';\nimport { createCorrelationTracker } from './correlation-tracker.js';\nimport {\n PersistedCorrelationDataSchema,\n PersistedProposalSchema,\n replayProposals,\n type PersistedCorrelationData,\n type PersistedProposal,\n} from './correlation-persistence-records.js';\n\nexport {\n createPersistedProposal,\n PersistedCorrelationDataSchema,\n type PersistedCorrelationData,\n} from './correlation-persistence-records.js';\n\nconst logger: ILogger = createLogger({ component: 'correlation-persistence' });\n\n/** Subdirectory name under the resolved nexus data dir for voting data. */\nconst VOTING_SUBDIR = 'voting';\n\n/** Legacy single-JSON file (pre-#2973). Still read on load; never written. */\nconst CORRELATIONS_FILE = 'correlations.json';\n\n/** Active append-only JSONL store (#2973). */\nconst CORRELATIONS_JSONL_FILE = 'correlations.jsonl';\n\n/** File permissions: user read/write only */\nconst FILE_MODE = 0o600;\n\n/** Directory permissions: user read/write/execute only */\nconst DIR_MODE = 0o700;\n\n/** Schema version 3 adds optional pinned and observed model provenance. */\nconst SCHEMA_VERSION = 3;\n\n// ============================================================================\n// Path Helpers\n// ============================================================================\n\n/**\n * Returns the absolute path to the **legacy** correlation data file. Kept\n * for back-compat — new writes go through `getCorrelationJsonlPath()`.\n */\nexport function getCorrelationDataPath(): string {\n return nexusDataPath(VOTING_SUBDIR, CORRELATIONS_FILE);\n}\n\n/** Returns the absolute path to the active JSONL store (#2973). */\nexport function getCorrelationJsonlPath(): string {\n return nexusDataPath(VOTING_SUBDIR, CORRELATIONS_JSONL_FILE);\n}\n\n/**\n * Ensures the voting data directory exists with appropriate permissions.\n */\nfunction ensureVotingDirectory(): Result<void, Error> {\n const dirPath = nexusDataPath(VOTING_SUBDIR);\n try {\n fs.mkdirSync(dirPath, { recursive: true, mode: DIR_MODE });\n return ok(undefined);\n } catch (cause: unknown) {\n const error = cause instanceof Error ? cause : new Error(String(cause));\n return err(new Error(`Failed to create voting directory at ${dirPath}: ${error.message}`));\n }\n}\n\n// ============================================================================\n// Save (append-only, race-free across processes)\n// ============================================================================\n\n/**\n * Appends new proposals to the JSONL store. One line per proposal.\n *\n * POSIX `O_APPEND` (used implicitly by `appendFileSync` with `{flag: 'a'}`)\n * guarantees atomic writes for buffer sizes under `PIPE_BUF` (4 KB on Linux,\n * 512 B on macOS). Each line we write is a single `PersistedProposal` — well\n * under those limits in practice for the typical vote-panel size (3–7 voters).\n * Two processes calling this concurrently get all proposals persisted; no\n * read-merge-rename race possible because we never read or rename.\n *\n * @param proposals - Array of proposals with their votes and outcomes to persist\n * @param _config - Higher-order voting config (only `maxProposals` is consulted\n * on read; this writer is fully append-only)\n * @returns Result indicating success or failure\n */\nexport function saveCorrelationData(\n proposals: PersistedProposal[],\n // config kept in the signature for ABI compatibility with the legacy\n // implementation; the JSONL writer is append-only so we don't need it here.\n // FIFO truncation happens on read.\n _config: HigherOrderVotingConfig = DEFAULT_HIGHER_ORDER_CONFIG\n): Result<void, Error> {\n const dirResult = ensureVotingDirectory();\n if (!dirResult.ok) return dirResult;\n\n if (proposals.length === 0) return ok(undefined);\n\n const filePath = getCorrelationJsonlPath();\n\n try {\n const lines = proposals.map((p) => JSON.stringify(p)).join('\\n') + '\\n';\n fs.appendFileSync(filePath, lines, { encoding: 'utf-8', mode: FILE_MODE });\n\n logger.info('Correlation proposals appended', {\n path: filePath,\n proposalCount: proposals.length,\n });\n\n return ok(undefined);\n } catch (cause: unknown) {\n const error = cause instanceof Error ? cause : new Error(String(cause));\n return err(new Error(`Failed to append correlation data: ${error.message}`));\n }\n}\n\n// ============================================================================\n// Load (consolidates JSONL + legacy JSON, dedupes by proposalId, FIFO-truncates)\n// ============================================================================\n\n/** Read the legacy `correlations.json` if present; return [] otherwise. */\nfunction loadLegacyJsonProposals(): PersistedProposal[] {\n const filePath = getCorrelationDataPath();\n if (!fs.existsSync(filePath)) return [];\n\n let rawContent: string;\n try {\n rawContent = fs.readFileSync(filePath, { encoding: 'utf-8' });\n } catch (cause: unknown) {\n logger.warn('Failed to read legacy correlations.json', {\n path: filePath,\n error: cause instanceof Error ? cause.message : String(cause),\n });\n return [];\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(rawContent);\n } catch (cause: unknown) {\n logger.warn('Corrupt legacy correlations.json — skipping', {\n path: filePath,\n error: cause instanceof Error ? cause.message : String(cause),\n });\n return [];\n }\n\n const result = PersistedCorrelationDataSchema.safeParse(parsed);\n if (!result.success) {\n logger.warn('Invalid legacy correlations.json schema — skipping', {\n path: filePath,\n error: result.error.message,\n });\n return [];\n }\n return result.data.proposals;\n}\n\ntype LineResult = { kind: 'ok'; proposal: PersistedProposal } | { kind: 'skip'; reason: string };\n\n/** Parse one JSONL line into a typed result so the loader can stay below max-complexity. */\nfunction parseJsonlLine(line: string): LineResult {\n let parsed: unknown;\n try {\n parsed = JSON.parse(line);\n } catch (cause: unknown) {\n return {\n kind: 'skip',\n reason: `JSON.parse: ${cause instanceof Error ? cause.message : String(cause)}`,\n };\n }\n const result = PersistedProposalSchema.safeParse(parsed);\n if (!result.success) return { kind: 'skip', reason: `schema: ${result.error.message}` };\n return { kind: 'ok', proposal: result.data };\n}\n\n/** Read JSONL store, dropping malformed lines with a warn log. */\nfunction loadJsonlProposals(): PersistedProposal[] {\n const filePath = getCorrelationJsonlPath();\n if (!fs.existsSync(filePath)) return [];\n\n let content: string;\n try {\n content = fs.readFileSync(filePath, { encoding: 'utf-8' });\n } catch (cause: unknown) {\n logger.warn('Failed to read correlations.jsonl', {\n path: filePath,\n error: cause instanceof Error ? cause.message : String(cause),\n });\n return [];\n }\n\n const lines = content.split('\\n').filter((line) => line.trim() !== '');\n const proposals: PersistedProposal[] = [];\n let skippedCount = 0;\n let firstSkipReason: string | undefined;\n\n for (const line of lines) {\n const result = parseJsonlLine(line);\n if (result.kind === 'ok') {\n proposals.push(result.proposal);\n } else {\n skippedCount++;\n firstSkipReason ??= result.reason;\n }\n }\n\n if (skippedCount > 0) {\n logger.warn('Skipped malformed lines in correlations.jsonl', {\n path: filePath,\n skippedCount,\n totalLines: lines.length,\n firstSkipReason,\n });\n }\n\n return proposals;\n}\n\n/**\n * Combines proposals from both stores, dedupes by proposalId (later wins),\n * sorts by timestamp ascending, and FIFO-truncates to `maxProposals`.\n */\nfunction consolidate(\n legacyProposals: PersistedProposal[],\n jsonlProposals: PersistedProposal[],\n maxProposals: number\n): PersistedProposal[] {\n const proposalMap = new Map<string, PersistedProposal>();\n // Legacy first, then JSONL — JSONL entries override legacy if same id.\n for (const p of legacyProposals) proposalMap.set(p.proposalId, p);\n for (const p of jsonlProposals) proposalMap.set(p.proposalId, p);\n\n const all = Array.from(proposalMap.values()).sort((a, b) =>\n a.timestamp.localeCompare(b.timestamp)\n );\n return all.length > maxProposals ? all.slice(all.length - maxProposals) : all;\n}\n\n/**\n * Loads and validates correlation data from disk. Combines the JSONL store\n * with the legacy `correlations.json` (if present). Always returns an Ok\n * result when the directory exists; an empty proposals array means \"no\n * persisted history\".\n *\n * Returns an `err` when NEITHER the jsonl nor the legacy file exists — the\n * first-run case. An earlier revision of this comment said that error had been\n * removed; it had not, and a caller that skipped the branch hit it on first run.\n */\nexport function loadCorrelationData(\n config: HigherOrderVotingConfig = DEFAULT_HIGHER_ORDER_CONFIG\n): Result<PersistedCorrelationData, Error> {\n const jsonlPath = getCorrelationJsonlPath();\n const legacyPath = getCorrelationDataPath();\n const jsonlExists = fs.existsSync(jsonlPath);\n const legacyExists = fs.existsSync(legacyPath);\n\n if (!jsonlExists && !legacyExists) {\n return err(new Error(`Correlation data file not found: ${jsonlPath}`));\n }\n\n const legacy = loadLegacyJsonProposals();\n const jsonl = loadJsonlProposals();\n const proposals = consolidate(legacy, jsonl, config.maxProposals);\n\n logger.info('Correlation data loaded', {\n legacyCount: legacy.length,\n jsonlCount: jsonl.length,\n afterDedup: proposals.length,\n });\n\n return ok({\n version: SCHEMA_VERSION,\n proposals,\n savedAt: new Date().toISOString(),\n });\n}\n\n// ============================================================================\n// 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 * Creates a correlation tracker pre-loaded with persisted history.\n *\n * On first run (no persisted data), returns a fresh tracker.\n * On subsequent runs, replays all stored proposals through the\n * tracker's public API to reconstruct correlation state.\n *\n * This enables Higher-Order Voting to accumulate enough history\n * across process restarts to activate Bayesian correlation awareness.\n *\n * @param config - Optional partial higher-order voting config\n * @returns A correlation tracker with any persisted history replayed\n */\nexport function createPersistentCorrelationTracker(\n config?: Partial<HigherOrderVotingConfig>\n): ICorrelationTracker {\n const tracker = createCorrelationTracker(config);\n\n const mergedConfig = { ...DEFAULT_HIGHER_ORDER_CONFIG, ...config };\n const loadResult = loadCorrelationData(mergedConfig);\n if (!loadResult.ok) {\n logger.info('Starting with fresh correlation tracker', {\n reason: loadResult.error.message,\n });\n return tracker;\n }\n\n const replayedCount = replayProposals(tracker, loadResult.value.proposals);\n\n logger.info('Correlation tracker restored from persistence', {\n replayedProposals: replayedCount,\n stats: tracker.getStats(),\n });\n\n return tracker;\n}\n","/** Schemas and replay helpers for persisted correlation proposal records. */\n\nimport { z } from 'zod';\nimport type { CorrelationRecordContext, ICorrelationTracker } from './higher-order-types.js';\nimport type { Vote } from './types-core.js';\n\nconst PersistedVoteSchema = z.object({\n agentId: z.string(),\n decision: z.enum(['approve', 'reject', 'abstain']),\n confidence: z.number().min(0).max(1),\n modelKey: z.string().optional(),\n observedModel: z.string().optional(),\n});\n\ntype PersistedVote = z.infer<typeof PersistedVoteSchema>;\n\nexport const PersistedProposalSchema = z.object({\n proposalId: z.string(),\n votes: z.array(PersistedVoteSchema),\n outcome: z.enum(['approved', 'rejected']),\n timestamp: z.iso.datetime(),\n});\n\nexport type PersistedProposal = z.infer<typeof PersistedProposalSchema>;\n\nexport const PersistedCorrelationDataSchema = z.object({\n version: z.number().int().positive(),\n proposals: z.array(PersistedProposalSchema),\n savedAt: z.iso.datetime(),\n});\n\nexport type PersistedCorrelationData = z.infer<typeof PersistedCorrelationDataSchema>;\n\n/** Build one replayable record without conflating assigned and observed models. */\nexport function createPersistedProposal(\n proposalId: string,\n votes: ReadonlyMap<string, Vote>,\n outcome: 'approved' | 'rejected',\n context?: CorrelationRecordContext\n): PersistedProposal {\n const persistedVotes: PersistedVote[] = [];\n for (const [agentId, vote] of votes) {\n const modelKey = context?.modelPins.get(agentId);\n const observedModel = context?.observedModels?.get(agentId);\n persistedVotes.push({\n agentId,\n decision: vote.decision,\n confidence: vote.confidence,\n ...(modelKey !== undefined ? { modelKey } : {}),\n ...(observedModel !== undefined ? { observedModel } : {}),\n });\n }\n return {\n proposalId,\n votes: persistedVotes,\n outcome,\n timestamp: new Date().toISOString(),\n };\n}\n\nfunction findReplayModelPins(proposals: readonly PersistedProposal[]): {\n first: ReadonlyMap<string, string>;\n latest: ReadonlyMap<string, string>;\n} {\n const firstModelPins = new Map<string, string>();\n const latestModelPins = new Map<string, string>();\n for (const proposal of proposals) {\n for (const vote of proposal.votes) {\n if (vote.modelKey !== undefined && !firstModelPins.has(vote.agentId)) {\n firstModelPins.set(vote.agentId, vote.modelKey);\n }\n if (vote.modelKey !== undefined) latestModelPins.set(vote.agentId, vote.modelKey);\n }\n }\n return { first: firstModelPins, latest: latestModelPins };\n}\n\nfunction buildReplayContext(\n votes: readonly PersistedVote[],\n firstModelPins: ReadonlyMap<string, string>\n): CorrelationRecordContext {\n const modelPins = new Map<string, string>();\n const observedModels = new Map<string, string>();\n for (const vote of votes) {\n const modelKey = vote.modelKey ?? firstModelPins.get(vote.agentId);\n if (modelKey !== undefined) modelPins.set(vote.agentId, modelKey);\n if (vote.observedModel !== undefined) observedModels.set(vote.agentId, vote.observedModel);\n }\n return { modelPins, observedModels };\n}\n\n/** Replay persisted records through the tracker's public recording contract. */\nexport function replayProposals(\n tracker: ICorrelationTracker,\n proposals: readonly PersistedProposal[]\n): number {\n const replayPins = findReplayModelPins(proposals);\n for (const proposal of proposals) {\n const votes = new Map<string, Vote>();\n for (const vote of proposal.votes) {\n votes.set(vote.agentId, {\n decision: vote.decision,\n reasoning: 'replayed from persistence',\n confidence: vote.confidence,\n });\n }\n tracker.recordProposalVotes(\n proposal.proposalId,\n votes,\n proposal.outcome,\n buildReplayContext(proposal.votes, replayPins.first)\n );\n }\n tracker.setCurrentModelPins?.(replayPins.latest);\n return proposals.length;\n}\n","/**\n * Types, schemas, and response helpers for the consensus_vote MCP tool.\n * Extracted from consensus-vote.ts for file size compliance (Issue #708).\n *\n * @module mcp/tools/consensus-vote-types\n */\n\n/* eslint-disable max-lines --\n * #4701: this file sat exactly at the 400-line cap, so adding\n * `HigherOrderMetadata.appliedToDecision` (a field plus its assignment) puts it\n * one over. Taking the exemption rather than splitting an 18-export types\n * module inside a two-line governance-fidelity fix. Second file this session to\n * hit the cap this way — see #4702 for the same situation in `audit-logger.ts`.\n * Do not keep adding here; split it.\n */\n\nimport { z } from 'zod';\nimport type { AgentVoteResult, VotingResult } from '../../cli/vote-types.js';\nimport { VOTER_ROLES } from '../../cli/vote-types.js';\nimport { isAbsentSeat } from '../../cli/voter-unverifiable.js';\nimport {\n resolveVoterProject,\n VoterProjectInputSchema,\n type ResolvedVoterProject,\n} from '../../cli/voter-project.js';\nimport type { HigherOrderVotingResult } from '../../consensus/higher-order-types.js';\nimport type { OptionGateVerdict } from './consensus-vote-option-gate.js';\nimport type { DecisionCostSummary } from '../../observability/decision-cost.js';\nimport type { VoteRecordPersistOutcome } from './consensus-vote-recording.js';\nimport {\n SUPERMAJORITY_THRESHOLD,\n VOTING_THRESHOLDS,\n type ConsensusAlgorithm,\n} from '../../consensus/types-core.js';\nimport { checkUndeclaredOptions } from './consensus-vote-option-detection.js';\n\n/** Maximum proposal length (memory bounds per Issue #435). */\nexport const MAX_PROPOSAL_LENGTH = 4000;\n\n// ============================================================================\n// Strategy Types\n// ============================================================================\n\n/**\n * Available consensus voting strategies.\n *\n * - `simple_majority`: Standard majority voting (>50%)\n * - `supermajority`: Requires >=67% approval\n * - `unanimous`: Requires 100% approval\n * - `proof_of_learning`: Weighted by agent performance (Issue #103). NOTE: weights come from\n * recorded voter history, and nothing writes that history today (#5234), so in practice this\n * currently behaves as simple_majority. The outcome reports `weightBasis: 'unweighted'` when\n * that is the case (#5117) rather than claiming a weighting that did not happen.\n * - `higher_order`: 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 * - `absolute_quorum` (opt-in, #4132): an errored voter DEGRADES the panel\n * verdict to `no_quorum` instead of being silently dropped from the\n * denominator. Unlike `fail_closed` (which reports a rejection-flavored void),\n * `absolute_quorum` reports `no_quorum` — a recoverable \"re-run the missing\n * voice\" state that never manufactures `approved` NOR `rejected` from an\n * induced error. An approval requires ZERO errors, the contrarian (catfish)\n * present and non-error (unless quick-mode drops it), and an ABSOLUTE approval\n * count (`ceil(fraction * panelSize)` over the full requested panel — not just\n * a majority of the responders). A genuine reject (zero errors) still blocks.\n * The anti-DoS point: a voter you can knock offline can only ever force a\n * re-run, never flip the verdict.\n *\n * Regardless of policy, a hard floor applies: when errors exceed 50% of\n * total voters, the vote always fails. Catches \"all CLIs are down\" — a\n * 2-voter consensus is not a real consensus.\n */\nexport const ErrorPolicySchema = z.enum([\n 'reduce_denominator',\n 'count_as_abstain',\n 'fail_closed',\n 'absolute_quorum',\n]);\n\nexport type ErrorPolicy = z.infer<typeof ErrorPolicySchema>;\n\n/**\n * Threshold values accepted by the `--threshold` CLI flag and the\n * \\`threshold\\` MCP input field (#2638 — single source of truth).\n *\n * Maps to consensus algorithms via:\n * `majority → simple_majority`, `supermajority → supermajority`, `unanimous → unanimous`.\n *\n * Used as the canonical Zod schema for CLI parsing\n * (`cli.ts:parseThreshold`), validation (`cli-commands-validators.ts:isValidThreshold`),\n * and the `ConsensusVoteInputSchema.threshold` field.\n */\nexport const VoteThresholdSchema = z.enum(['majority', 'supermajority', 'unanimous']);\n\nexport type VoteThreshold = z.infer<typeof VoteThresholdSchema>;\n\n/**\n * 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\n .string()\n .min(1)\n .max(MAX_PROPOSAL_LENGTH)\n .describe(\n 'Proposal text to vote on. If the proposal asks voters to choose among named ' +\n 'alternatives, declare them in `options` (#4472) — otherwise the tally records ' +\n 'approve/reject/abstain only, so every voter who engages returns `approve` and a 6-1 ' +\n 'split on WHICH option persists as 7-0, 100% (#4452). This is ENFORCED AS A WARNING, ' +\n 'not a refusal: a heuristic over the proposal text flags an apparent multi-option ' +\n 'proposal with no `options` and says so on `panelWarning` (#5360). The wording says ' +\n '\"declare\", not \"MUST\", because the warning is what the code actually holds — it is ' +\n 'tightened back only in the same change that promotes the warning to a refusal.'\n ),\n options: z\n .array(z.string().min(1).max(200))\n .min(2)\n .max(10)\n .optional()\n .describe(\n 'Named alternatives for a multi-option proposal (#4472). When present, the threshold must ' +\n 'ALSO be cleared by the leading option, in addition to the ordinary approve/reject bar: ' +\n '`unanimous` requires every approver to have chosen the SAME option, and ' +\n \"`supermajority`/`majority` measure the leading option's share of approvers. An \" +\n 'approving voter whose selection is absent or matches no declared option stays in the ' +\n 'denominator and credits no option, so a degraded response can only lower the leading ' +\n 'share, never raise it. Omit for an ordinary yes/no vote — behaviour is then unchanged.'\n ),\n project: VoterProjectInputSchema,\n threshold: VoteThresholdSchema.optional().describe(\n 'Voting threshold (legacy): majority, supermajority, unanimous. Use strategy instead.'\n ),\n strategy: VotingStrategySchema.optional().describe(\n 'Voting strategy: simple_majority (default), supermajority, unanimous, proof_of_learning, or higher_order (Bayesian-optimal). ' +\n 'NOTE (#4452): thresholds are evaluated over approve/reject/abstain, not over which option a voter chose. On a ' +\n 'multi-option proposal even `unanimous` clears trivially — see the `proposal` field description.'\n ),\n errorPolicy: ErrorPolicySchema.optional().describe(\n 'How to treat voters that errored or timed out (#2630). Default: fail_closed for unanimous only; reduce_denominator for all other strategies incl. higher_order/opinion_wise (#3138 — a single infra timeout should not void an otherwise-unanimous vote). Opt-in absolute_quorum (#4132): an errored voter — especially the contrarian (catfish) — degrades the verdict to no_quorum (recoverable re-run) instead of being dropped from the denominator; never manufactures approved/rejected from an induced error. Regardless of policy, errors > 50% always fails.'\n ),\n quickMode: z\n .boolean()\n .optional()\n .default(false)\n .describe('Use 3 agents instead of the full 7-role panel for faster execution'),\n simulateVotes: z\n .boolean()\n .optional()\n .default(false)\n .describe(\n 'TESTS ONLY — when true, voters return random decisions. Output must not be used for real decisions. (#2319)'\n ),\n /**\n * Async-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 * True when this seat was recovered by the per-role retry (#6050).\n *\n * Present only when true. A retried seat is weaker evidence than a first-pass\n * one — the model was unavailable or timed out — so a caller reading a panel\n * result should be able to see that \"7 of 7 answered\" and \"6 answered, 1\n * recovered\" are different facts.\n */\n retried?: boolean;\n /** Which declared option this voter chose (#4472). Absent when the proposal\n * declared none, or the voter's selection matched none of them. */\n selectedOption?: string;\n /**\n * True when this seat could not read the artifact (#6094). Present only\n * when true. Its `decision` is always `abstain`; `voteCounts.unverifiable`\n * counts these seats separately so a blind seat is never read as a\n * considered abstention.\n */\n unverifiable?: true;\n}\n\n/**\n * Canonical set of decision statuses a vote response can carry. Single source\n * of truth: the `consensus_vote` MCP `outputSchema` reuses\n * {@link VoteDecisionStatusSchema} so the advertised enum can never be narrower\n * than what {@link buildResponse} emits (all five are reachable —\n * `no_quorum` on an all-error/no-quorum panel, the rest via\n * {@link mapOutcomeToDecision}). A narrower schema made strict MCP clients\n * reject `timeout`/`pending` votes with a `-32602`-class error (#4032).\n */\nexport const VoteDecisionStatusSchema = z.enum([\n 'approved',\n 'rejected',\n 'pending',\n 'timeout',\n 'no_quorum',\n]);\n\nexport type VoteDecisionStatus = z.infer<typeof VoteDecisionStatusSchema>;\n\n/**\n * Outcome of the quick-mode contrarian check (#6111).\n *\n * In quick mode the contrarian is a separate `executeExpert` call, not a seat\n * in `votes`, so `voteCounts.error` cannot count it: an errored check under\n * `absolute_quorum` yields `no_quorum` with `error: 0`. This names that voice.\n *\n * - `ok` — the check ran and returned a verdict (escalating or not).\n * - `errored` — the check ran and the contrarian voice was NOT obtained.\n * - `skipped` — the check did not run: full-panel mode (catfish is a seat),\n * simulated votes, a non-approved quick verdict, a posterior-confidence\n * escalation that pre-empted it, or an error-policy short-circuit.\n */\nexport const ContrarianCheckStatusSchema = z.enum(['ok', 'errored', 'skipped']);\n\nexport type ContrarianCheckStatus = z.infer<typeof ContrarianCheckStatusSchema>;\n\n/**\n * Narrows a response decision to the three-value vocabulary the audit record\n * uses (#4986).\n *\n * The response vocabulary is wider — it carries `timeout` and `pending` too —\n * so the narrowing has to be stated rather than left to a cast:\n *\n * - `timeout` becomes `no_quorum`. A panel that ran out of time reached no\n * quorum; it did not reject the proposal, and recording it as `rejected`\n * would attribute a verdict to voters who never gave one.\n * - `pending` returns `undefined`. A vote still in flight has no decision to\n * record, and inventing one would be worse than falling back.\n */\nexport function toRecordDecision(\n status: VoteDecisionStatus | undefined\n): 'approved' | 'rejected' | 'no_quorum' | undefined {\n switch (status) {\n case 'approved':\n case 'rejected':\n case 'no_quorum':\n return status;\n case 'timeout':\n return 'no_quorum';\n default:\n return undefined;\n }\n}\n\n/**\n * Higher-Order Voting metadata (Issue #514).\n *\n * ADVISORY, not the verdict (#4701). Read `appliedToDecision` before drawing\n * any conclusion from the rest of this object.\n */\nexport interface HigherOrderMetadata {\n posteriorApproval: number;\n posteriorRejection: number;\n effectiveVoteCount: number;\n /**\n * Aggregation used for THIS correlation-aware run — not necessarily the one\n * that produced `decision`. See {@link HigherOrderMetadata.appliedToDecision}.\n */\n method: 'ow' | 'isp' | 'simple';\n usedCorrelationData: boolean;\n improvementOverBaseline: number;\n downweightedAgents: readonly string[];\n reasoning: string;\n /**\n * Whether this correlation-aware result actually produced the response's\n * `decision` (#4701).\n *\n * Currently ALWAYS FALSE. The verdict comes from `ConsensusEngine.close()`,\n * which calls `HigherOrderVotingStrategy.calculateOutcome` — and that calls\n * `aggregateSimpleInternal`, a plain `approve / (approve + reject)` ratio\n * with no correlation input. This object is computed separately and consumed\n * only as metadata plus one escalation check.\n *\n * The field exists because the omission was actively misleading: `method`\n * can read `'ow'` while `downweightedAgents` is non-empty, from which any\n * reasonable reader concludes the correlation analysis decided the vote. It\n * did not — the \"seven voters that are really one opinion\" case is detected\n * here and then discarded.\n *\n * Making the decision genuinely correlation-aware changes governance\n * outcomes and is tracked separately; this field makes the current state\n * legible in the meantime, including in persisted vote records.\n */\n appliedToDecision: boolean;\n}\n\nexport interface ConsensusVoteResponse {\n proposal: string;\n threshold?: VoteThreshold;\n strategy: VotingStrategy;\n decision: VoteDecisionStatus;\n approvalPercentage: number;\n /**\n * `unverifiable` (#6094) counts seats that answered without reading the\n * artifact. Those seats are ALSO inside `abstain` (their legacy decision);\n * the bucket is always present, explicit 0 included — an absent key would\n * read as health.\n */\n voteCounts: {\n approve: number;\n reject: number;\n abstain: number;\n error: number;\n unverifiable: number;\n };\n /**\n * #6111: the quick-mode contrarian check, reported beside the tally because\n * `voteCounts.error` counts seats and the check is not one. Always present;\n * `skipped` is the named empty case (see {@link ContrarianCheckStatus}).\n */\n contrarianCheck: ContrarianCheckStatus;\n votes: AgentVoteSummary[];\n durationMs: number;\n simulateVotes: boolean;\n /**\n * #6110: the project every voter was told it is judging, and how that name\n * was decided — `input` (the caller's `project`), `derived` (the working\n * directory's `origin` remote or `package.json`), or `default`\n * (`nexus-agents`). Always present: a consuming repository that forgot the\n * input sees `default` next to the verdict instead of a silent mis-scope.\n */\n project: ResolvedVoterProject;\n 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 * #4472: declared-option outcome, present only when the proposal declared\n * `options`. Separate from `approvalPercentage` — that stays the\n * approve/reject figure — so a caller can tell WHICH bar failed.\n *\n * `unattributedApprovals` is load-bearing, not decoration: a share alone\n * cannot distinguish dissent from absence, since `4 pick X + 3 unparseable`\n * reads 57% exactly like a real 4/3 split.\n */\n optionOutcome?: {\n tally: ReadonlyArray<{ option: string; count: number }>;\n leadingOption?: string;\n leadingShare: number;\n approverCount: number;\n selectedCount: number;\n unattributedApprovals: number;\n thresholdMet: boolean;\n /**\n * #4529: why the gate vetoed, present only when it did. Carried here rather\n * than on `policyReason`, which means \"an error policy voided this vote\" —\n * a split is a decision, not a void, and conflating them let a retry policy\n * re-roll a panel that had already disagreed.\n */\n vetoReason?: string;\n };\n /**\n * #3991: whether the authentic vote record (#3897) was persisted at vote time.\n * Post-#3991 the runtime ledger routes through `nexusDataPath` under\n * `governance/`, so a writable `.nexus-agents/governance/` location almost\n * always exists and `true` is the normal case. `false` means the persist was\n * skipped (all votes simulated) or the write failed (data dir unwritable) —\n * see {@link voteRecordNote}. Surfaces to the MCP caller what was previously\n * only a server-side WARN.\n */\n voteRecordPersisted: boolean;\n /**\n * #3991: present only when {@link voteRecordPersisted} is `false` — the\n * actionable reason the record was not written (e.g. the data dir is unwritable\n * → fix permissions or set `NEXUS_VOTE_RECORDS_PATH` to a writable path).\n */\n voteRecordNote?: string;\n}\n\n/** Extended voting result with optional Higher-Order metadata. */\nexport interface ExtendedVotingResult extends VotingResult {\n strategy: VotingStrategy;\n /**\n * #4472: the declared-option tally + verdict, present only when the proposal\n * declared `options`. Reported alongside `approvalPercentage` rather than\n * folded into it, so a reader can tell which bar failed.\n */\n optionGate?: OptionGateVerdict;\n higherOrderResult?: HigherOrderVotingResult;\n /** Reason an error policy short-circuited the vote (#3124); surfaced on the response. */\n policyReason?: string;\n /**\n * #4132: the FULL requested panel size (`roles.length`) — the absolute_quorum\n * predicate in {@link buildResponse} needs it to compute the absolute approval\n * floor `ceil(fraction * panelSize)`. Distinct from `votes.length`, which can\n * differ from the requested panel if the collector ever returns a short list.\n * When absent, the predicate falls back to `votes.length`.\n */\n panelSize?: number;\n /**\n * #4132: whether the contrarian (catfish) was in the requested panel. `--quick`\n * runs a 3-role panel WITHOUT catfish, so the absolute_quorum \"contrarian must\n * be present and non-error\" clause is skipped when this is false (the quick-mode\n * carve-out). True on the full 7-role panel.\n */\n contrarianRequested?: boolean;\n /**\n * #6111: outcome of the quick-mode contrarian check. Stamped by `executeVoting`\n * on every path (`skipped` when the check did not run). Absent only on results\n * built by paths that never ran `executeVoting` (direct unit calls to\n * `buildResponse`), which `buildResponse` reports as `skipped` — the check\n * genuinely did not run there.\n */\n contrarianCheck?: ContrarianCheckStatus;\n /**\n * #4135: the response-layer decision (incl. `no_quorum`) for this vote, computed\n * by {@link resolveVoteDecision}. Set by `executeVoting` right before it returns\n * so pipeline consumers (iterative-consensus, agent-executor, the CLI) can honor\n * a `no_quorum` void instead of misreading it as a rejection — WITHOUT recomputing\n * the policy math. The engine `ConsensusResult.outcome` stays 2-valued\n * (`approved`/`rejected`); this is the widened, opt-in-aware view. Absent on\n * results built by paths that never ran `executeVoting` (direct unit calls to\n * `buildResponse`), where consumers fall back to mapping the engine outcome.\n */\n decision?: VoteDecisionStatus;\n /**\n * #6110: the resolved target project, stamped by `executeVoting` alongside\n * `decision` so the CLI and the response disclose the same name and source.\n * Absent only on results built by paths that never ran `executeVoting`.\n */\n project?: ResolvedVoterProject;\n}\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n/** Converts AgentVoteResult to AgentVoteSummary for response. */\nexport function toAgentVoteSummary(result: AgentVoteResult): AgentVoteSummary {\n const roleName = VOTER_ROLES[result.role].split(' - ')[0] ?? result.role;\n return {\n role: roleName,\n decision: result.vote.decision,\n confidence: result.vote.confidence,\n reasoning: result.vote.reasoning,\n simulated: result.source === 'simulation',\n error: result.source === 'error',\n ...(result.vote.rejectionCategories !== undefined\n ? { rejectionCategories: result.vote.rejectionCategories }\n : {}),\n // #6050: a caller acting on the live result sees what the ledger will.\n // Present only when true, so a clean panel's response is unchanged.\n ...(result.retried === true ? { retried: true } : {}),\n // #6094: same rule for a seat that could not read the artifact.\n ...(result.source === 'unverifiable' ? { unverifiable: true as const } : {}),\n };\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 * Append to `panelWarning` rather than assign: it has several writers and an\n * assignment would silently drop whichever fired first. A `undefined` text is\n * a no-op.\n */\nfunction appendPanelWarning(response: ConsensusVoteResponse, text: string | undefined): void {\n if (text === undefined) return;\n response.panelWarning =\n response.panelWarning === undefined ? text : `${response.panelWarning} ${text}`;\n}\n\n/**\n * #6094: seats that answered without reading the artifact. Their abstention\n * is already inside `voteCounts.abstain`; this says how many of those never\n * saw the thing they were asked to judge. Undefined when there are none —\n * the count itself is still rendered as an explicit 0 in `voteCounts`.\n */\nfunction unverifiableSeatsWarning(unverifiableCount: number, total: number): string | undefined {\n if (unverifiableCount <= 0) return undefined;\n return (\n `${String(unverifiableCount)} of ${String(total)} seat(s) could not read the artifact and ` +\n 'are recorded as unverifiable (counted as abstain in voteCounts; any decision they returned was discarded).'\n );\n}\n\n// ============================================================================\n// absolute_quorum (#4132)\n// ============================================================================\n\n/**\n * #4132: process-wide count of panels that DEGRADED to `no_quorum` under the\n * opt-in `absolute_quorum` policy. The evidence base a future default-flip rests\n * on — how often does an errored voice actually void a real panel? Incremented in\n * {@link buildResponse}; read via {@link getDegradedPanelCount}. There is no\n * metrics bus in this module, so this mirrors the bare module-level counter style\n * used elsewhere (e.g. the correlation-tracker singleton).\n */\nlet degradedPanelCount = 0;\n\n/** #4132: current degraded-panel count (see {@link degradedPanelCount}). */\nexport function getDegradedPanelCount(): number {\n return degradedPanelCount;\n}\n\n/** #4132: reset the degraded-panel counter. Test-isolation only. @internal */\nexport function resetDegradedPanelCount(): void {\n degradedPanelCount = 0;\n}\n\n/**\n * #4132: the absolute approval fraction a strategy requires over the FULL panel.\n * `ceil(fraction * panelSize)` is the absolute number of approvals an\n * `absolute_quorum` verdict needs — an ABSOLUTE floor over every requested\n * voter, not a majority of the responders (which abstains/errors would shrink).\n * majority → 0.5, supermajority → 2/3, unanimous → 1.0; the higher_order family\n * and proof_of_learning follow the majority (0.5) baseline they tally against.\n */\nfunction absoluteQuorumFraction(strategy: VotingStrategy): number {\n switch (strategy) {\n case 'supermajority':\n return 2 / 3;\n case 'unanimous':\n return 1;\n default:\n return 0.5;\n }\n}\n\n/**\n * #5780: the smallest number of voters that must have cast approve-or-reject\n * before any ratio is applied to them.\n *\n * The gap this closes: every strategy measures its threshold over\n * `approve + reject`, and abstentions and errored seats leave that denominator\n * with no floor under it. `ERROR_FLOOR_FRACTION` voids a panel only when errors\n * EXCEED half, so one seat under it — 7 requested, 3 errored, 1 abstained —\n * left three respondents, and 2 approvals carried an architecture or security\n * vote at 66.7%.\n *\n * Two thirds of the requested panel, never fewer than three, never more than\n * the panel itself. That is one rule satisfying both figures the panel named\n * (7 → 5, quick 3 → 3); the `3` clamp is what makes quick mode require every\n * seat, since two thirds of 3 is 2.\n *\n * Deliberately about RESPONDENTS, not errors. `absolute_quorum` (#4132) voids\n * on an errored seat specifically, so an induced error cannot manufacture a\n * verdict; this is about how few voices decided, whatever silenced them — a\n * panel of 7 returning four abstentions and three votes has zero errors and\n * still should not decide. The two compose; neither replaces the other.\n */\nfunction minimumRespondents(panelSize: number): number {\n if (panelSize <= 0) return 0;\n return Math.min(panelSize, Math.max(Math.ceil((panelSize * 2) / 3), 3));\n}\n\n/** A vote decision plus the (optional) actionable reason a panel degraded. */\nexport interface VoteDecisionOutcome {\n readonly decision: VoteDecisionStatus;\n /** Set when the verdict degraded to `no_quorum` under absolute_quorum. */\n readonly degradeReason?: string;\n}\n\n/**\n * #4132: the absolute_quorum predicate (post-tally). Applied ONLY when\n * `errorPolicy === 'absolute_quorum'`; every other policy keeps the legacy\n * decision path untouched (opt-in).\n *\n * The invariant this enforces (anti-DoS): an induced voter error can NEVER\n * manufacture `approved` and NEVER manufacture `rejected` — errors force\n * `no_quorum`, a recoverable \"re-run the missing voice\" state. A GENUINE reject\n * (zero errors) still blocks. The happy path (all approve, zero errors,\n * contrarian present) stays `approved`.\n *\n * approved ⇔ errorCount === 0 AND (contrarian present-and-non-error, unless\n * quick-mode dropped it) AND approveCount >= ceil(frac * panel)\n * no_quorum ⇔ errorCount > 0 OR the contrarian was requested but errored/missing\n * rejected ⇔ zero errors, contrarian present, engine rejected (genuine reject)\n * no_quorum ⇔ zero errors but the absolute approval floor was not met and there\n * is no genuine reject (abstain-heavy; recoverable)\n */\n/**\n * The \"an errored/absent voice voids the quorum\" half of the predicate. Returns\n * the actionable re-run reason when the panel had ANY error, or the contrarian\n * was required but errored/missing; `undefined` otherwise (clean panel).\n */\nfunction absoluteQuorumDegradeReason(\n result: ExtendedVotingResult,\n errorCount: number\n): string | undefined {\n const contrarianVote = result.votes.find((v) => v.role === 'catfish');\n const contrarianOk = contrarianVote !== undefined && !isAbsentSeat(contrarianVote);\n const contrarianDegraded = result.contrarianRequested === true && !contrarianOk;\n // #6094: a seat that could not read the artifact is an absence, not a\n // judgment, and degrades the quorum exactly as an errored seat does.\n const unverifiableRoles = result.votes\n .filter((v) => v.source === 'unverifiable')\n .map((v) => v.role);\n if (errorCount === 0 && unverifiableRoles.length === 0 && !contrarianDegraded) return undefined;\n\n const erroredRoles = result.votes.filter((v) => v.source === 'error').map((v) => v.role);\n const missingContrarian = contrarianDegraded && contrarianVote === undefined;\n const named = missingContrarian ? [...erroredRoles, 'catfish'] : erroredRoles;\n return `no_quorum: re-run — ${absentSeatClauses(named, unverifiableRoles).join('; ')} (absolute_quorum)`;\n}\n\n/** The \"[roles] errored\" and \"[roles] unverifiable\" clauses of the re-run reason. */\nfunction absentSeatClauses(\n erroredNames: readonly string[],\n unverifiable: readonly string[]\n): string[] {\n const clauses: string[] = [];\n if (erroredNames.length > 0 || unverifiable.length === 0) {\n const list = erroredNames.length > 0 ? erroredNames.join(', ') : 'contrarian';\n clauses.push(`voter(s) [${list}] errored`);\n }\n if (unverifiable.length > 0) {\n clauses.push(\n `voter(s) [${unverifiable.join(', ')}] unverifiable — could not read the artifact`\n );\n }\n return clauses;\n}\n\nfunction computeAbsoluteQuorumDecision(\n result: ExtendedVotingResult,\n errorCount: number,\n allErrors: boolean\n): VoteDecisionOutcome {\n const degradeReason = absoluteQuorumDegradeReason(result, errorCount);\n if (degradeReason !== undefined) return { decision: 'no_quorum', degradeReason };\n\n // Zero errors, contrarian satisfied (or not required in quick mode).\n const panel = result.panelSize ?? result.votes.length;\n const needed = Math.ceil(absoluteQuorumFraction(result.strategy) * panel);\n const approveCount = result.votes.filter(\n (v) => v.source !== 'error' && v.vote.decision === 'approve'\n ).length;\n\n if (result.result.outcome === 'approved' && approveCount >= needed) {\n return { decision: 'approved' };\n }\n if (result.result.outcome === 'rejected' && !allErrors) {\n // A genuine reject (the engine rejected with zero errors) still blocks.\n return { decision: 'rejected' };\n }\n // Approved-by-responders but the absolute approval floor was not met (e.g.\n // abstain-heavy) — no error, no genuine reject, just not enough YES. Recoverable.\n return {\n decision: 'no_quorum',\n degradeReason: `no_quorum: absolute quorum not met (${String(approveCount)}/${String(needed)} approvals over ${String(panel)}-voter panel, absolute_quorum)`,\n };\n}\n\n/**\n * #5780: `no_quorum` when too few voices actually decided, or `undefined` when\n * the panel met its floor.\n *\n * `no_quorum` and not `rejected`: too few respondents is a statement about the\n * panel, not about the proposal, and it is recoverable by re-running the\n * missing seats — the same shape `absolute_quorum` uses for an errored voice.\n * Reporting it as a rejection would be a verdict the panel never reached.\n *\n * Applied ONLY to an approval, mirroring the asymmetry `absolute_quorum`\n * already encodes (\"A GENUINE reject still blocks\"). The harm in #5780 is that\n * too few voices can CARRY a decision; a rejection by too few blocks it, which\n * is the safe direction, and voiding that would add a re-run without\n * preventing anything. A thin reject is still visible in `panelCoverage`.\n */\nfunction respondentFloorOutcome(result: ExtendedVotingResult): VoteDecisionOutcome | undefined {\n if (result.result.outcome !== 'approved') return undefined;\n const panel = result.panelSize ?? result.votes.length;\n const floor = minimumRespondents(panel);\n const respondents = result.votes.filter(\n (v) => v.source !== 'error' && (v.vote.decision === 'approve' || v.vote.decision === 'reject')\n ).length;\n if (respondents >= floor) return undefined;\n return {\n decision: 'no_quorum',\n degradeReason: `no_quorum: ${String(respondents)} of ${String(panel)} voters decided; ${String(floor)} required before a ratio is applied (#5780)`,\n };\n}\n\n/**\n * Resolve the user-facing decision for a tallied vote. Keeps the pre-#4132 path\n * verbatim for every policy except `absolute_quorum`, which routes through\n * {@link computeAbsoluteQuorumDecision}.\n *\n * Exported (#4135) so `executeVoting` can stamp `ExtendedVotingResult.decision`\n * with the SAME computation `buildResponse` uses — the response-layer decision\n * (including `no_quorum`) is derived once, in one place, and can't diverge\n * between the engine result and the MCP response. The engine\n * `ConsensusResult.outcome` stays 2-valued; this is the widened view.\n */\nexport function resolveVoteDecision(\n input: ConsensusVoteInput,\n result: ExtendedVotingResult,\n errorCount: number\n): VoteDecisionOutcome {\n const allErrors = errorCount === result.votes.length && errorCount > 0;\n // #4053: an error-policy short-circuit (>50% hard floor, or fail_closed) VOIDED\n // the vote — that is no_quorum, not the panel rejecting. Applies to every policy.\n if (result.policyReason !== undefined || (!result.result.quorumReached && allErrors)) {\n return { decision: 'no_quorum' };\n }\n // #5780: the responder floor guards an APPROVAL under every policy and every\n // strategy — a denominator of three out of a requested seven is equally\n // unrepresentative whichever bar is measured over it.\n //\n // Ordered after `absolute_quorum`, not before, so that policy keeps its own\n // more specific degrade reason. The two are not redundant: absolute_quorum\n // guarantees `approveCount >= ceil(frac * panel)`, which subsumes the floor\n // at `supermajority` (5 approvals of 7) but NOT at `majority`, where 4\n // approvals over 4 respondents of a requested 7 clears it and still leaves\n // three voices unheard.\n if (input.errorPolicy === 'absolute_quorum') {\n const quorumOutcome = computeAbsoluteQuorumDecision(result, errorCount, allErrors);\n if (quorumOutcome.decision !== 'approved') return quorumOutcome;\n return respondentFloorOutcome(result) ?? quorumOutcome;\n }\n return (\n respondentFloorOutcome(result) ?? { decision: mapOutcomeToDecision(result.result.outcome) }\n );\n}\n\n/**\n * #4132: absolute_quorum response side-effects — increment the degraded-panel\n * telemetry counter and surface the actionable re-run reason on policyReason /\n * panelWarning (when an errored voter degraded the verdict without an upstream\n * short-circuit already setting result.policyReason). Extracted to hold\n * {@link buildResponse} within its cyclomatic budget.\n */\nfunction applyAbsoluteQuorumTelemetry(\n response: ConsensusVoteResponse,\n input: ConsensusVoteInput,\n decision: VoteDecisionStatus,\n degradeReason: string | undefined\n): void {\n // The evidence base for a future default-flip: how often does an errored voice\n // actually void a real panel?\n if (input.errorPolicy === 'absolute_quorum' && decision === 'no_quorum') {\n degradedPanelCount++;\n }\n if (degradeReason !== undefined) {\n response.policyReason ??= degradeReason;\n response.panelWarning ??= degradeReason;\n }\n}\n\n/**\n * Builds the response from voting result.\n *\n * `voteRecord` (#3991) is the structured authentic-vote-record persistence\n * outcome; when omitted (direct unit calls) `voteRecordPersisted` defaults to\n * `false` with no note. The live handler always supplies it.\n */\n/**\n * Name the bar a strategy actually enforces.\n *\n * Derived from {@link VOTING_THRESHOLDS} rather than a second hand-written\n * mapping, so it cannot drift from the value the engine compares against.\n * Strategies that are aliases (`higher_order`, `opinion_wise`) resolve to their\n * own 0.5 entry and therefore report `majority`, which is the point.\n */\nfunction appliedThresholdFor(strategy: VotingStrategy | undefined): VoteThreshold {\n const algorithm: ConsensusAlgorithm = strategy ?? 'simple_majority';\n const bar = VOTING_THRESHOLDS[algorithm];\n if (bar >= 1) return 'unanimous';\n if (bar >= SUPERMAJORITY_THRESHOLD) return 'supermajority';\n return 'majority';\n}\n\n/**\n * #6111: the contrarian-check status the response reports. `executeVoting`\n * stamps one on every path; a result that never went through it never ran the\n * check, so `skipped` is the truthful name for that absence — not a default\n * standing in for a measurement.\n */\nfunction contrarianCheckFor(result: ExtendedVotingResult): ContrarianCheckStatus {\n return result.contrarianCheck ?? 'skipped';\n}\n\n/**\n * The project disclosure for the response (#6110). `executeVoting` stamps the\n * resolution on the result; a direct call that bypassed it (unit tests) gets\n * the SAME resolution recomputed from the input — mirroring how `decision` is\n * handled above — so the field is always present and never a fabricated source.\n */\nfunction disclosedProject(\n input: ConsensusVoteInput,\n result: ExtendedVotingResult\n): ResolvedVoterProject {\n const { name, source } =\n result.project ?? resolveVoterProject({ input: input.project, cwd: process.cwd() });\n return { name, source };\n}\n\nexport function buildResponse(\n input: ConsensusVoteInput,\n result: ExtendedVotingResult,\n costSummary?: DecisionCostSummary,\n voteRecord?: VoteRecordPersistOutcome\n): ConsensusVoteResponse {\n const proposalTruncated =\n input.proposal.length > 200 ? input.proposal.slice(0, 200) + '...' : input.proposal;\n\n const errorCount = result.votes.filter((v) => v.source === 'error').length;\n const unverifiableCount = result.votes.filter((v) => v.source === 'unverifiable').length;\n\n // #4053 / #4132: the user-facing decision. An error-policy short-circuit (the\n // >50% hard floor, or fail_closed) VOIDED the vote — that is no_quorum, NOT the\n // panel rejecting. The opt-in absolute_quorum policy (#4132) additionally\n // degrades to no_quorum when ANY voter (especially the contrarian) errored, so\n // an induced error can never manufacture approved/rejected. Every other policy\n // keeps the legacy mapping. `degradeReason` (when present) is the actionable\n // \"re-run\" message; it rides the response as `policyReason`.\n //\n // #4135 (DRY): `executeVoting` already stamped `result.decision` via THIS same\n // `resolveVoteDecision`. Reuse it so the response decision can't diverge from the\n // one pipeline consumers read; recompute only for the `degradeReason` telemetry\n // and for direct unit calls that bypass `executeVoting` (where `decision` is absent).\n const resolved = resolveVoteDecision(input, result, errorCount);\n const decision = result.decision ?? resolved.decision;\n\n const response: ConsensusVoteResponse = {\n proposal: proposalTruncated,\n strategy: result.strategy,\n decision,\n approvalPercentage: result.result.approvalPercentage,\n voteCounts: {\n approve: result.result.voteCounts.approve,\n reject: result.result.voteCounts.reject,\n abstain: result.result.voteCounts.abstain,\n error: errorCount,\n unverifiable: unverifiableCount,\n },\n contrarianCheck: contrarianCheckFor(result),\n votes: result.votes.map(toAgentVoteSummary),\n durationMs: result.totalTimeMs,\n simulateVotes: result.simulateVotes,\n project: disclosedProject(input, result),\n // #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 if (result.optionGate !== undefined) {\n response.optionOutcome = toOptionOutcome(result.optionGate);\n }\n\n applyOptionalResponseFields(response, input, result, errorCount, costSummary);\n applyAbsoluteQuorumTelemetry(response, input, decision, resolved.degradeReason);\n return response;\n}\n\n/** The #4472 declared-option block of the response, from the gate's verdict. */\nfunction toOptionOutcome(\n g: OptionGateVerdict\n): NonNullable<ConsensusVoteResponse['optionOutcome']> {\n return {\n tally: g.tally.map((t) => ({ option: t.option, count: t.count })),\n ...(g.leadingOption !== undefined ? { leadingOption: g.leadingOption } : {}),\n leadingShare: g.leadingShare,\n approverCount: g.approverCount,\n selectedCount: g.selectedCount,\n unattributedApprovals: g.unattributedApprovals,\n thresholdMet: g.approved,\n ...(g.reason !== undefined ? { vetoReason: g.reason } : {}),\n };\n}\n\n/**\n * Attach the optional response fields (threshold, policy reason, panel warning,\n * higher-order metadata, cost summary). Extracted from {@link buildResponse} to\n * keep its cyclomatic complexity within the lint budget (#3855).\n */\nfunction applyOptionalResponseFields(\n response: ConsensusVoteResponse,\n input: ConsensusVoteInput,\n result: ExtendedVotingResult,\n errorCount: number,\n costSummary?: DecisionCostSummary\n): void {\n // #5315: this echoed `input.threshold` verbatim. But `resolveStrategy`\n // ignores `threshold` entirely when `strategy` is also supplied, and\n // `higher_order` carries a 0.5 bar — so a caller passing\n // `strategy: 'higher_order'` + `threshold: 'supermajority'` (the pairing the\n // governance table itself prescribes) got a record naming a bar the vote\n // never had to clear. Observed live at 4-approve/3-reject, 57.1%, reported as\n // `threshold: 'supermajority'`.\n //\n // The field now names the bar the ENGINE enforced, taken from the strategy it\n // actually ran. The record is ratification evidence; it must state what it\n // measured, not what was asked for.\n response.threshold = appliedThresholdFor(result.strategy);\n if (result.policyReason !== undefined) {\n response.policyReason = result.policyReason;\n }\n const panelWarning = panelDegradationWarning(errorCount, result.votes.length);\n if (panelWarning !== undefined) {\n response.panelWarning = panelWarning;\n }\n // #6094: APPENDED, like the undeclared-options warning below — a third\n // writer that assigned would clobber whichever fired first.\n appendPanelWarning(\n response,\n unverifiableSeatsWarning(response.voteCounts.unverifiable, result.votes.length)\n );\n // #5360: a proposal that names alternatives while `options` is undefined\n // records a split as uniform approval — every voter approves the ACT of\n // deciding, not a side. A 3-3 tie was recorded as `APPROVED 83.3%` that way.\n //\n // The all-approved signal is the sharper half: on a proposal that enumerates a\n // fork it is the observed signature, and unlike a reasoning-variance detector\n // it needs nothing the persisted record drops (#5339).\n //\n // APPENDED, not assigned. `panelWarning` already has two writers and a third\n // that clobbered would silently drop whichever fired first.\n const engaged = result.votes.length - errorCount;\n const undeclared = checkUndeclaredOptions(\n input.proposal,\n input.options,\n engaged > 0 && response.voteCounts.reject === 0 && response.voteCounts.abstain === 0\n );\n if (undeclared.flagged) appendPanelWarning(response, undeclared.warning);\n if (isHigherOrderStrategy(result.strategy) && result.higherOrderResult) {\n response.higherOrderMetadata = toHigherOrderMetadata(result.higherOrderResult);\n }\n if (costSummary !== undefined) {\n response.costSummary = costSummary;\n }\n}\n\n/** Maps a HigherOrderVotingResult to the response's metadata shape. */\nfunction toHigherOrderMetadata(r: HigherOrderVotingResult): HigherOrderMetadata {\n return {\n posteriorApproval: r.posteriorApproval,\n posteriorRejection: r.posteriorRejection,\n effectiveVoteCount: r.effectiveVoteCount,\n method: r.method,\n usedCorrelationData: r.usedCorrelationData,\n improvementOverBaseline: r.improvementOverBaseline,\n downweightedAgents: r.downweightedAgents,\n reasoning: r.reasoning,\n // #4701: the engine's `calculateOutcome` decides, and it aggregates simple.\n // Hardcoded false rather than computed, because there is currently no code\n // path where this result reaches the verdict — a computed `false` would\n // imply one exists.\n appliedToDecision: false,\n };\n}\n","/**\n * Detects a multi-option proposal submitted WITHOUT declared `options` (#5360).\n *\n * #4452 established the failure: a proposal naming alternatives only in prose\n * records a split as uniform approval, because every voter returns `approve` —\n * approving the ACT of deciding, not a side. #4472 built the fix (`options`, a\n * `selectedOption` prompt, a threshold over the option tally). Nothing detected\n * when a caller should have used it, so the failure stayed reachable by\n * forgetting — and it recurred on a real architecture vote, where a 3–3 tie was\n * recorded as `APPROVED 83.3%`.\n *\n * A WARNING, not a refusal. The false-positive cost is unmeasured: a proposal\n * that merely mentions options would trip the patterns, and refusing a\n * governance vote on an unmeasured heuristic trades one failure for a worse one.\n * The promotion criteria and the measurement live on the follow-up issue.\n *\n * @module mcp/tools/consensus-vote-option-detection\n */\n\n/**\n * Prose shapes that name alternatives. Deliberately narrow — each must be a\n * phrase a caller uses when asking voters to CHOOSE, not merely to approve.\n *\n * Anchored and bounded: no nested quantifiers, so none can backtrack\n * catastrophically on a long proposal.\n */\nconst MULTI_OPTION_PATTERNS: readonly RegExp[] = Object.freeze([\n // `Option A` and `OPTION A`, but NOT `option a` — the lowercase form appears\n // in ordinary prose (\"there is no option a caller can set\"), the capitalised\n // form is a heading. The motivating proposal used `Option A`; an\n // uppercase-only pattern would have missed the instance this exists for.\n /\\b(?:Option|OPTION) [A-Z0-9]\\b/,\n /\\bchoose between\\b/i,\n /\\bwhich of (?:the )?(?:these|those|the following)\\b/i,\n /\\bpick exactly one\\b/i,\n /\\bvote for exactly one\\b/i,\n]);\n\n/** Outcome of the check. A discriminated union so \"not checked\" cannot read as \"clean\". */\nexport type UndeclaredOptionsCheck =\n { readonly flagged: false } | { readonly flagged: true; readonly warning: string };\n\n/**\n * Does the proposal name alternatives while `options` is absent?\n *\n * `allEngagedApproved` is the second signal, and it is the sharper one (#5360,\n * from the review panel): when every non-errored voter returns `approve` on a\n * proposal that enumerates a fork, that is the observed signature of this exact\n * defect rather than a proposal that merely mentions the word \"option\". It is\n * available without the persisted reasoning that a full disagreement detector\n * would need (#5339).\n *\n * Pass `undefined` for `allEngagedApproved` when the votes are not yet known —\n * the check then rests on the prose alone and says so in the warning.\n */\nexport function checkUndeclaredOptions(\n proposal: string,\n declaredOptions: readonly string[] | undefined,\n allEngagedApproved?: boolean\n): UndeclaredOptionsCheck {\n // Declared options mean the option-aware tally is live; nothing to warn about.\n if (declaredOptions !== undefined && declaredOptions.length > 0) return { flagged: false };\n if (proposal === '') return { flagged: false };\n if (!MULTI_OPTION_PATTERNS.some((p) => p.test(proposal))) return { flagged: false };\n\n const base =\n 'This proposal appears to name alternatives, but `options` was not declared, ' +\n 'so the tally records approve/reject only and cannot say WHICH alternative won ' +\n '(#4452, #5360). Re-run with `options` to record the option tally.';\n\n // Stated separately because it is evidence, not restatement: every voter\n // approving a proposal that enumerates a fork is the signature of voters\n // approving the act of deciding rather than a side.\n return {\n flagged: true,\n warning:\n allEngagedApproved === true\n ? `${base} Every non-errored voter returned \\`approve\\`, which is the signature of this defect.`\n : base,\n };\n}\n","/**\n * Error-policy handling for consensus_vote (#2630).\n *\n * When a voter errors or times out (`source === 'error'`), the response\n * shape already distinguishes it via `voteCounts.error` (see\n * consensus-vote-types.ts:188). What was missing: a configurable\n * decision policy for how those error voters interact with the strategy\n * threshold, plus a safety floor for \"too many errors to call a\n * consensus.\"\n *\n * Three policies, plus a hard floor:\n *\n * - `reduce_denominator` (default for non-strict strategies): errors\n * filtered out before the engine sees votes. Denominator = non-error\n * votes. Pragmatic for operational decisions.\n * - `count_as_abstain`: errors reach the engine as abstain. Conservative\n * — error voter is treated as having withheld approval.\n * - `fail_closed` (default for unanimous only, #3138): any error\n * short-circuits to vote-void.\n * - `absolute_quorum` (opt-in, #4132): errors reach the engine as abstain\n * (like `count_as_abstain`), but the post-tally predicate in\n * `buildResponse` degrades ANY errored panel to `no_quorum` — an induced\n * error can never manufacture `approved`/`rejected`. Does not short-circuit\n * here (below the hard floor); the degrade happens after the tally so a\n * genuine reject is preserved.\n *\n * Hard floor: if errors > `ERROR_FLOOR_FRACTION` of total voters, the\n * vote always fails regardless of policy. \"All CLIs are down\" is not a\n * consensus.\n *\n * @module mcp/tools/consensus-vote-error-policy\n */\n\nimport type { AgentVoteResult } from '../../cli/vote-types.js';\nimport type { ErrorPolicy } from './consensus-vote-types.js';\nimport { ERROR_FLOOR_FRACTION } from './consensus-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' || policy === 'absolute_quorum') {\n // Errors stay in the engine input but as abstain decisions — the engine sees\n // the FULL panel rather than a shrunk denominator. The original\n // `source: 'error'` is preserved so the per-voter response shape and\n // `voteCounts.error` still report the error, and (for #4132 absolute_quorum)\n // the post-tally predicate in buildResponse can still see the true errorCount.\n // absolute_quorum does NOT fail-close here — the >50% hard floor above still\n // applies, but a sub-floor error degrades to no_quorum in buildResponse, not\n // a short-circuit, so the engine outcome (a genuine reject) is preserved.\n return {\n shortCircuit: false,\n engineVotes: votes.map((v) =>\n v.source === 'error' ? { ...v, vote: { ...v.vote, decision: 'abstain' as const } } : v\n ),\n };\n }\n\n // reduce_denominator (default): errors filtered out before engine sees them.\n return {\n shortCircuit: false,\n engineVotes: votes.filter((v) => v.source !== 'error'),\n };\n}\n","/**\n * 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 { serializeValidatedRecord } from './ledger-append.js';\nimport { assertNotSourceCheckoutWrite } from './source-checkout-guard.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';\nimport { UNRESOLVED_MODEL_ID } from '../config/model-equivalence.js';\n\nimport type {\n VoteRecord,\n VoteRecordOptionCount,\n VoteRecordOptionCoverage,\n VoteRecordPanelCoverage,\n VoterSummary,\n} from './vote-record.js';\nimport {\n VoteRecordSchema,\n computeVoteRecordHash,\n hashProposal,\n MAX_VOTER_REASONING_CHARS,\n} 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 // #6054: `undefined` from the store now has TWO causes — an unwritable path,\n // or a record the read schema would reject (refused before it became\n // durable). This text reaches the MCP caller, so it must not assert the\n // filesystem cause it cannot distinguish; the server log names which.\n `Authentic vote record NOT persisted (${path}). Either the resolved data ` +\n 'directory is not writable, or the record was refused because the read ' +\n 'schema would reject it. The server log line \"Failed to persist authentic ' +\n 'vote record\" carries the cause — a filesystem error, or the offending field. ' +\n `For the path case, check permissions on the .nexus-agents data dir or set ` +\n `${VOTE_RECORDS_PATH_ENV} to a writable absolute file path.`\n );\n}\n\n/**\n * Fallback mapping from a consensus outcome to the recorded decision, for\n * callers with no resolved decision to hand over.\n *\n * The void checks come FIRST. They used to sit below an\n * `if (result.outcome === 'approved') return 'approved'` short-circuit, which\n * meant `errorVoided` could only ever rescue a `rejected` — a voided vote whose\n * engine outcome was `approved` persisted as a genuine approval while the tool\n * reported `no_quorum` (#4986). #4053 fixed one half of that and the ordering\n * hid the other.\n *\n * This still cannot see a void the caller knows about but the\n * {@link ConsensusResult} does not express — the `absolute_quorum` path stamps\n * its reason on the response, never on the result — which is why\n * `resolvedDecision` exists and why this is only the fallback.\n */\nfunction outcomeToDecision(\n result: ConsensusResult,\n votes: readonly AgentVoteResult[],\n errorVoided: boolean\n): VoteRecord['decision'] {\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 if (result.outcome === 'approved') return 'approved';\n // Only an actual `rejected` is a rejection. `ProposalStatus` also carries\n // `timeout` / `pending` / `voting` / `closed`, and the previous\n // everything-else-is-rejected default recorded a panel that never concluded\n // as one that voted the proposal down (#4986).\n if (result.outcome === 'rejected') return 'rejected';\n return 'no_quorum';\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 // An errored voter has no entry here at all; `panelCoverage` names it\n // (#5738). So an entry with `reasoning: ''` means a live voter returned\n // nothing, which is distinguishable from a seat that never answered.\n if (v.source === 'error') continue;\n const vote: Vote = v.vote;\n summaries.push({\n role: v.role,\n decision: vote.decision,\n confidence: vote.confidence,\n ...reasoningFields(vote.reasoning),\n // #6050: carried, not dropped. `voter-retry.ts` has set this on every\n // recovered seat since it was written and nothing read it, so the record\n // said \"7 of 7 answered cleanly\" for a panel that needed a retry.\n ...(v.retried === true ? { retried: true as const } : {}),\n // #6091: the seat's model, so the ledger can say which model answered.\n // The pending-detection placeholder is not a model and is not recorded.\n ...(v.model !== undefined && v.model !== UNRESOLVED_MODEL_ID ? { model: v.model } : {}),\n // #6094: a seat that answered without reading the artifact. Its\n // `decision` is abstain; this flag is what keeps it from reading as a\n // considered abstention.\n ...(v.source === 'unverifiable' ? { unverifiable: true as const } : {}),\n });\n }\n return summaries;\n}\n\n/**\n * The stored reasoning, clipped with a marker rather than silently (#5373).\n *\n * A truncated argument that does not say it was truncated is the failure this\n * field exists to fix — on #5228 a contrarian rejection was clipped\n * mid-sentence and its grounds were unrecoverable.\n */\nfunction reasoningFields(reasoning: string): { reasoning: string; reasoningTruncated?: true } {\n if (reasoning.length <= MAX_VOTER_REASONING_CHARS) return { reasoning };\n return {\n reasoning: reasoning.slice(0, MAX_VOTER_REASONING_CHARS),\n reasoningTruncated: true,\n };\n}\n\n/**\n * The decision to persist: the caller's resolved answer when it has one, else\n * the {@link outcomeToDecision} fallback.\n */\nfunction recordDecisionFor(input: BuildVoteRecordInput): VoteRecord['decision'] {\n return (\n input.resolvedDecision ??\n outcomeToDecision(input.result, input.votes, input.errorVoided ?? false)\n );\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 /**\n * The options the proposal DECLARED, if any (#6049).\n *\n * Required rather than optional — including its `undefined` case — for the\n * same reason `resolvedDecision` below is: a new call site that omits it\n * would silently inherit \"no options were declared\", which is the exact\n * confusion this field exists to remove. The compiler names every caller.\n */\n readonly declaredOptions: readonly string[] | undefined;\n /** #4053: vote voided by an error-policy short-circuit → record `no_quorum`. */\n readonly errorVoided?: boolean | undefined;\n /**\n * The decision the caller already resolved for this vote, recorded verbatim.\n *\n * `resolveVoteDecision` computes the authoritative three-valued answer once,\n * for the response. Re-deriving it here from `result.outcome` is what let the\n * two disagree (#4986), so a caller that has it MUST pass it. Required rather\n * than optional — including its `undefined` case — so the compiler names\n * every call site instead of letting a new one inherit the fallback in\n * silence.\n */\n readonly resolvedDecision: VoteRecord['decision'] | 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 */\n/**\n * Counts how many voters chose each named option (#4452).\n *\n * Returns `undefined` when no vote carries a `selectedOption` — an ordinary\n * yes/no vote — so the record stays on the pre-1.3 hash projection and every\n * historical record keeps verifying.\n *\n * Options are emitted in DESCENDING count, ties broken by option label, so the\n * tally is deterministic regardless of voter order. That matters: the array is\n * hash-covered, and a set of votes that differed only in arrival order must not\n * produce two different hashes.\n */\n/**\n * Derive the option tally and its coverage together (#4472, #6049).\n *\n * They travel as a pair: coverage without a tally says nothing, and a tally\n * without coverage is the ambiguity #4472 fixed.\n *\n * #6049: the pair is now keyed on whether options were DECLARED, not on whether\n * anyone picked one. `tallySelectedOptions` returns undefined when no approver\n * has a usable selection, and coverage used to be nulled along with it — so the\n * fields vanished at exactly the coverage extreme they exist to record. A panel\n * that unanimously approved while every selection failed `matchDeclaredOption`\n * persisted as `decision: rejected, approvalPercentage: 100` with NO option\n * fields at all, and an auditor filtering `optionTally !== undefined` to find\n * multi-option votes skipped the very case most worth reviewing.\n *\n * The builder could not tell \"no options declared\" from \"options declared,\n * nothing selected\" because it only saw the votes. It is told now.\n *\n * An ordinary yes/no vote still emits neither field, keeping it on the pre-1.3\n * hash projection so every historical record keeps verifying.\n */\nfunction deriveOptionFields(\n votes: readonly AgentVoteResult[],\n declaredOptions: readonly string[] | undefined\n): {\n optionTally: VoteRecordOptionCount[] | undefined;\n optionCoverage: VoteRecordOptionCoverage | undefined;\n} {\n const tallied = tallySelectedOptions(votes);\n const hadOptions = declaredOptions !== undefined && declaredOptions.length > 0;\n if (!hadOptions && tallied === undefined) {\n // A genuine yes/no vote: neither field, pre-1.3 projection.\n return { optionTally: undefined, optionCoverage: undefined };\n }\n // Declared options always produce both, even when the tally is empty. An\n // empty tally beside `selectedCount: 0` is the honest encoding of \"declared,\n // nothing attributable\" — which is a measurement, not an absence.\n return { optionTally: tallied ?? [], optionCoverage: coverageOf(votes) };\n}\n\n/**\n * Schema version implied by the option fields present.\n *\n * 1.8 carries a voter `model` or an `unverifiable` seat, 1.7 a retried voter\n * seat, 1.6 voter reasoning, 1.5 panel coverage, 1.4 option coverage, 1.3 a\n * bare tally (historical only — a tally now always travels with coverage),\n * 1.2 neither.\n */\nfunction recordVersion(\n optionTally: VoteRecordOptionCount[] | undefined,\n optionCoverage: VoteRecordOptionCoverage | undefined,\n panelCoverage: VoteRecordPanelCoverage | undefined,\n voters: readonly VoterSummary[]\n): '1.2' | '1.3' | '1.4' | '1.5' | '1.6' | '1.7' | '1.8' {\n // 1.8 first, on the same tier logic as 1.7: both new fields are orthogonal\n // to the tiers below, and a reader needs to know from the version alone\n // whether voter entries may carry them (#6091, #6094).\n if (voters.some((v) => v.model !== undefined || v.unverifiable === true)) return '1.8';\n // 1.7: `retried` is ORTHOGONAL to the tiers below it, not a refinement\n // of one. A retried seat implies an errored seat, so it usually co-occurs\n // with 1.5's panelCoverage — but a reader needs to know from the version\n // alone whether voter entries may carry the field (#6050).\n if (voters.some((v) => v.retried === true)) return '1.7';\n if (voters.some((v) => v.reasoning !== undefined)) return '1.6';\n if (panelCoverage !== undefined) return '1.5';\n if (optionCoverage !== undefined) return '1.4';\n return optionTally !== undefined ? '1.3' : '1.2';\n}\n\n/**\n * Panel coverage (#5738): what the panel asked for versus what answered.\n *\n * `toVoterSummaries` drops voters at `source: 'error'` and `voteCounts` counts\n * only responders, so without this the record cannot distinguish a genuine\n * three-voter panel from a seven-voter panel that lost four. Returns undefined\n * when every requested voter responded — absence keeps a clean record on the\n * pre-1.5 hash projection.\n */\nfunction panelCoverageOf(votes: readonly AgentVoteResult[]): VoteRecordPanelCoverage | undefined {\n const erroredRoles = votes.filter((v) => v.source === 'error').map((v) => v.role);\n if (erroredRoles.length === 0) return undefined;\n return {\n requested: votes.length,\n responded: votes.length - erroredRoles.length,\n errored: erroredRoles.length,\n erroredRoles,\n };\n}\n\n/**\n * Selection coverage over the approving voters (#4472).\n *\n * Counts approvers, not all voters: a rejecter chose no option because they\n * rejected the proposal, which the approve/reject counts already record.\n */\nfunction coverageOf(votes: readonly AgentVoteResult[]): VoteRecordOptionCoverage {\n const approvers = votes.filter((v) => v.vote.decision === 'approve');\n const selectedCount = approvers.filter((v) => v.selectedOption !== undefined).length;\n return {\n approverCount: approvers.length,\n selectedCount,\n unattributedApprovals: approvers.length - selectedCount,\n };\n}\n\nfunction tallySelectedOptions(\n votes: readonly AgentVoteResult[]\n): VoteRecordOptionCount[] | undefined {\n const counts = new Map<string, number>();\n for (const v of votes) {\n // Approvers only. The threshold is evaluated over approvers, so a tally\n // that counted rejecters would describe a different population than the\n // verdict it accompanies — and would disagree with `optionCoverage`,\n // which is approvers-only. Found by e2e validation when a rejecting voter\n // named an option and the record credited it (#4472 follow-up).\n if (v.vote.decision !== 'approve') continue;\n if (v.selectedOption === undefined) continue;\n counts.set(v.selectedOption, (counts.get(v.selectedOption) ?? 0) + 1);\n }\n if (counts.size === 0) return undefined;\n return [...counts.entries()]\n .map(([option, count]) => ({ option, count }))\n .sort((a, b) => (b.count !== a.count ? b.count - a.count : a.option.localeCompare(b.option)));\n}\n\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 // #4452: derive the per-option distribution from the votes themselves, so a\n // multi-option split is recoverable from the structured record instead of by\n // parsing seven free-text `reasoning` fields. Absent when the PROPOSAL\n // declared no options, which keeps an ordinary yes/no record on the pre-1.3\n // projection. (#6049 corrected this: the rule was \"no voter selected one\",\n // which is a different question and is why a declared-options vote with no\n // parseable selection lost its option fields entirely.)\n const { optionTally, optionCoverage } = deriveOptionFields(input.votes, input.declaredOptions);\n const panelCoverage = panelCoverageOf(input.votes);\n const voters = toVoterSummaries(input.votes);\n const payload: Omit<VoteRecord, 'hash'> = {\n version: recordVersion(optionTally, optionCoverage, panelCoverage, voters),\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: recordDecisionFor(input),\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,\n ...(input.correlationId !== undefined ? { correlationId: input.correlationId } : {}),\n ...(input.ratifies !== undefined ? { ratifies: input.ratifies } : {}),\n ...(optionTally !== undefined ? { optionTally } : {}),\n ...(optionCoverage !== undefined ? { optionCoverage } : {}),\n ...(panelCoverage !== undefined ? { panelCoverage } : {}),\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 // Before the try (#6070, same shape as the pr-review store): a swallowed\n // guard would silently skip the write and hide the very mistake it exists to\n // surface. The tracked `<repo>/governance/vote-records.jsonl` is reachable\n // via the env override, and the promotion gate trusts whatever is in it.\n assertNotSourceCheckoutWrite(filePath, VOTE_RECORDS_REL_PATH, VOTE_RECORDS_PATH_ENV);\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 // #6054: validate against the schema the READ path uses before anything is\n // durable. A throw here lands in the catch below as warn + undefined — the\n // contract a failed write already has — instead of an unreadable line the\n // chain has moved past and no consumer of `invalidLines` will ever surface.\n appendFileSync(filePath, serializeValidatedRecord(VoteRecordSchema, record, 'vote'), '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 * Validate-before-append for the hash-chained JSONL ledgers (#6054).\n *\n * Both ledger writers (`vote-record-store`, `pr-review-record-store`) had the\n * same shape: build a record, `JSON.stringify` it, `appendFileSync`. The only\n * schema check was on the READ path, so a builder could emit a record the schema\n * rejects, the append succeeded, and the line surfaced later as an\n * `invalidLines` entry that no non-test consumer reads. #6049 shipped exactly\n * that: `optionTally: []` against a `.min(1)` the write path never checked.\n *\n * For an append-only, hash-chained artifact that direction is wrong. An\n * unreadable line cannot be repaired in place — the chain has moved past it —\n * so the cheapest moment to reject a malformed record is before it is durable.\n * The unusual record is the one most worth auditing and the one most likely to\n * trip a constraint, so the silent drop lands on the cases that matter most.\n *\n * ONE guard rather than two, so the two ledgers cannot drift on what \"valid\"\n * means at write time. It THROWS; each store's existing `try` turns that into\n * its `logger.warn` + `undefined` contract, which is what a caller already gets\n * for a failed write. Persistence still never throws into the vote path.\n *\n * @module audit/ledger-append\n */\n\nimport type { ZodType } from 'zod';\nimport { formatZodIssueWithRoot } from '../core/zod-helpers.js';\n\n/** Stable prefix so a log reader (or a test) can find the refusal by string. */\nexport const UNREADABLE_RECORD_PREFIX = 'refusing to persist an unreadable';\n\n/**\n * Serialize `record` as one ledger line, or throw when the schema that will be\n * used to READ it back rejects it. The thrown message names the ledger and the\n * failing paths, so the log entry says which field — not merely that a write\n * failed.\n *\n * VALIDATE, DO NOT RE-EMIT. The first version returned `JSON.stringify(parsed.data)`\n * — Zod's rebuilt object — and an adversarial review executed both stores to\n * show the bytes CHANGED for every valid record: Zod rebuilds objects in\n * schema-shape key order, the builders emit in a different order, so the record\n * returned to the caller and the line on disk no longer serialized identically.\n * The hash survived only because it is computed over a projection. That is the\n * #6065 class — a rebuilt object leaking resolution order into bytes — and a\n * \"valid records are unchanged\" claim that was false. The schema is consulted\n * for its verdict only; what is written is the caller's own object.\n */\nexport function serializeValidatedRecord<T>(\n schema: ZodType<T>,\n record: T,\n ledgerName: string\n): string {\n const parsed = schema.safeParse(record);\n if (!parsed.success) {\n const paths = parsed.error.issues.map(formatZodIssueWithRoot).join('; ');\n throw new Error(`${UNREADABLE_RECORD_PREFIX} ${ledgerName} record: ${paths}`);\n }\n const line = JSON.stringify(record);\n // Validate what will be READ, not only what was handed in. A ratification\n // seat named the gap and a probe confirmed it: `.strict()` checks own keys, so\n // an object whose prototype carries `toJSON()` passes validation while\n // `JSON.stringify` writes something else entirely. The builders never hand\n // the guard such an object, but the guard is an exported helper and the\n // property has to hold for any caller. The same check closes every\n // JSON-lossy value at once (a non-finite number becoming `null`, a Date\n // becoming a string) rather than enumerating them. Bytes are unchanged: the\n // line written is still the caller's own serialization.\n const roundTrip = schema.safeParse(JSON.parse(line) as unknown);\n if (!roundTrip.success) {\n const paths = roundTrip.error.issues.map(formatZodIssueWithRoot).join('; ');\n throw new Error(\n `${UNREADABLE_RECORD_PREFIX} ${ledgerName} record: JSON round-trip changed it — ${paths}`\n );\n }\n return line + '\\n';\n}\n","/**\n * nexus-agents/audit - Source-checkout write guard (#4415, shared since #6070).\n *\n * Both committable, hash-chained JSONL ledgers (`governance/pr-review-records.jsonl`,\n * `governance/vote-records.jsonl`) are tracked in the source checkout and read\n * by a gate that treats their contents as evidence: the governor-review gate\n * (#3831) and the authority-tier promotion gate (#3895) respectively. A test\n * that appends to one of them manufactures a record that self-hashes cleanly\n * and is indistinguishable from a real verdict — which is exactly how #4415\n * happened, and it was noticed only because `git status` showed a tracked file\n * dirty.\n *\n * The pr-review store carried this guard privately from #4415; the vote store\n * had none, and its `NEXUS_VOTE_RECORDS_PATH` override honours an absolute path\n * as-is by design, so the tracked ledger was reachable from any test that set\n * the env var (#6070). One definition, parameterised on the tracked path and\n * the per-ledger env var, keeps the two stores from drifting apart again.\n *\n * Callers MUST invoke {@link assertNotSourceCheckoutWrite} BEFORE their `try`:\n * a swallowed guard would silently skip the write and hide the very mistake it\n * exists to surface.\n *\n * @module audit/source-checkout-guard\n */\n\nimport { join, resolve } from 'node:path';\n\nimport { findRepoRoot } from '../config/repo-root-detection.js';\n\n/** True when running under a test runner (vitest sets `VITEST`). */\nexport function isUnderTestRunner(): boolean {\n return process.env['VITEST'] !== undefined || process.env['NODE_ENV'] === 'test';\n}\n\n/**\n * Refuse to WRITE the source checkout's own tracked chain from a test (#4415).\n *\n * `governance/pr-review-records.jsonl` is tracked and hash-chained. During\n * #4412 a test appended three fabricated verdicts to it — they chained\n * correctly onto each other, so `verify_audit_chain` would have read a valid\n * chain containing fake reviews. They were noticed only because `git status`\n * showed a tracked file dirty before a commit.\n *\n * A fabricated record that hash-chains cleanly is worse than a corrupt file:\n * it is indistinguishable from a real one. The threat model already scopes the\n * chain as tamper-*evident*, which only holds if we do not manufacture\n * plausible entries ourselves.\n *\n * Guards the DESTINATION, not how it was derived — an explicit `filePath` or\n * env var pointing at the same file is the same harm. Resolution itself stays\n * unguarded: the stores' path resolvers are queries, and tests legitimately\n * assert their fall-through behaviour (#4278/#4312) without writing anything.\n *\n * The comparison is EQUALITY of resolved paths, not a prefix test: a sibling\n * such as `<tracked>.bak` is a different file and a legitimate fixture target.\n *\n * A throwaway repo — the shape a legitimate persistence test uses — is\n * untouched. Outside a test runner the guard is inert.\n *\n * @param filePath - the destination the caller is about to append to.\n * @param trackedRelPath - the ledger's path relative to the repo root, e.g.\n * `governance/vote-records.jsonl`.\n * @param overrideEnvVar - the per-ledger env var named in the refusal so the\n * reader knows which escape hatch to use. The remedy says where to POINT it\n * (a throwaway path), not merely to set it: for the vote store the env var\n * is usually the very thing that reached the tracked file, and neither\n * store's persist function takes a `repoPath` option (#6081).\n */\nexport function assertNotSourceCheckoutWrite(\n filePath: string,\n trackedRelPath: string,\n overrideEnvVar: string\n): void {\n if (!isUnderTestRunner()) return;\n const here = findRepoRoot(process.cwd());\n if (here === null) return;\n if (resolve(filePath) !== resolve(join(here, trackedRelPath))) return;\n throw new Error(\n `Refusing to write ${filePath} from a test run (#4415): this is the source ` +\n \"checkout's tracked, hash-chained audit file, and a fabricated record that \" +\n 'chains cleanly is indistinguishable from a real verdict. ' +\n `Point ${overrideEnvVar} (or the explicit filePath) at a throwaway path such ` +\n 'as a temp directory.'\n );\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. */\n/** Selection coverage for a multi-option vote (#4472). */\nexport const VoteRecordOptionCoverageSchema = z\n .object({\n /** Every approving voter, selecting or not — the tally's denominator. */\n approverCount: z.number().int().nonnegative(),\n /** Approvers whose selection matched a declared option. */\n selectedCount: z.number().int().nonnegative(),\n /** Approvers with no usable selection; their choice is unmeasured. */\n unattributedApprovals: z.number().int().nonnegative(),\n })\n .strict();\nexport type VoteRecordOptionCoverage = z.infer<typeof VoteRecordOptionCoverageSchema>;\n\n/**\n * How much of the requested panel actually voted (#5738, schema 1.5).\n *\n * `voteCounts` and `voters` describe the voters that RESPONDED. An errored\n * voter is dropped from both, so a seven-role panel that lost four of them\n * persisted as a clean three-voter record — and under `reduce_denominator`\n * (the default for every strategy but `unanimous`) a 6-of-7 panel with one\n * dead voter recorded as a unanimous six-voter approval. That is the record a\n * human spot-check of a governor-path merge reads.\n *\n * Measured before this landed: 23 of 199 records in the live ledger carried a\n * denominator that was neither the full panel nor quick mode, with nothing in\n * the record saying why.\n *\n * Same shape of fix as `optionCoverage` (#4472) and for the same reason:\n * recording what did NOT arrive is what makes a partial measurement legible AS\n * partial. Absent when every requested voter responded.\n *\n * Module-private: only the record schema below and the derived type have a\n * consumer. Its two siblings, `VoteRecordOptionCountSchema` and\n * `VoteRecordOptionCoverageSchema`, are exported and the producer/consumer\n * gate already lists both as dead exports — no reason to add a third.\n */\nconst VoteRecordPanelCoverageSchema = z\n .object({\n /** Voters the panel asked for. */\n requested: z.number().int().nonnegative(),\n /** Voters that returned a usable vote — the denominator of `voteCounts`. */\n responded: z.number().int().nonnegative(),\n /** Voters that errored or timed out. */\n errored: z.number().int().nonnegative(),\n /** The roles behind `errored`, in panel order. */\n erroredRoles: z.array(z.string().min(1).max(100)),\n })\n .strict();\nexport type VoteRecordPanelCoverage = z.infer<typeof VoteRecordPanelCoverageSchema>;\n\n/**\n * Longest reasoning kept per voter (#5373). Mirrors the CLI display guard from\n * #5372 rather than inventing a second number. A clipped entry says so on\n * itself — a silently truncated argument is the failure this field exists to\n * fix.\n */\nexport const MAX_VOTER_REASONING_CHARS = 20_000;\n\n/**\n * The declared field ORDER here is not load-bearing (#6057): canonical hash order\n * comes from `VOTER_SUMMARY_KEYS` below, which is compile-checked against this\n * schema in both directions. Adding a field here without adding it there is a\n * build error, not a silently unhashed field.\n */\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 * The voter's stated grounds (#5373, schema 1.6).\n *\n * `generateVoteHash` already hashed `{role, decision, reasoning}` and then\n * discarded the text, so the chain attested to a value it did not store and\n * nobody could re-verify the hash without re-obtaining the reasoning. On\n * #5228 a contrarian rejection was clipped mid-sentence in the terminal, the\n * grounds were unrecoverable, and the same defect resurfaced a round later —\n * one round of a 7-voter panel is 7-13 minutes of model time, and the\n * objection was right both times.\n *\n * Stored whole rather than sampled. Warn-mode near-misses are emitted per\n * TOOL CALL, thousands a day; votes are emitted per PANEL, dozens a day at\n * most, so ~17 KB per vote is not the same growth problem.\n *\n * Absence is not an empty argument: an errored voter has no entry in\n * `voters` at all (see `panelCoverage`), so `reasoning: ''` means a live\n * voter returned nothing, which is itself a signal.\n */\n reasoning: z.string().max(MAX_VOTER_REASONING_CHARS).optional(),\n /** True when `reasoning` was clipped to {@link MAX_VOTER_REASONING_CHARS}. */\n reasoningTruncated: z.literal(true).optional(),\n /**\n * True when this seat was recovered by the per-role retry (#6050, schema 1.7).\n *\n * `voter-retry.ts` has set `retried: true` on recovered results since it was\n * written, and `vote-types.ts` states the reason: the flag is \"what makes the\n * recovery visible instead of indistinguishable from a clean first attempt\".\n * It had one producer and ZERO consumers — both summarizers and the record\n * dropped it — so the field existed, was documented, and never reached\n * anything that could act on it.\n *\n * A retried seat is weaker evidence than a first-pass one: the model was\n * unavailable or timed out, and the recovery ran under different conditions.\n * For a ratification vote on a governor-path change, \"7 of 7 answered\" and\n * \"6 answered, 1 recovered on retry\" are different facts about the scrutiny\n * the change received, and the record stated the first for both.\n *\n * `literal(true)` and optional, on the `reasoningTruncated` rule: a clean\n * seat carries no key, so its entry re-hashes byte-identical and every\n * historical record still verifies.\n */\n retried: z.literal(true).optional(),\n /**\n * Registry model id the seat ran on (#6091, schema 1.8).\n *\n * The seat→model mapping is round-robin over the available CLIs plus\n * `NEXUS_VOTER_MODEL_<ROLE>` pins, so it is not recoverable from the\n * ledger after the fact: 1844 voter entries across 278 records carried no\n * model. \"When an agent's output becomes evidence, its provenance travels\n * with it\" — a tally that says `scope_steward: approve` without saying\n * which model answered cannot be audited for the #6068 failure class.\n * Present-only, on the `retried` rule; absent when the result carried no\n * model or only the pending-detection placeholder.\n */\n model: z.string().min(1).max(200).optional(),\n /**\n * True when the seat could not read the artifact (#6094, schema 1.8).\n *\n * `decision` is `abstain` for such a seat, so without this flag the record\n * could not tell \"read it and abstained\" from \"never saw it\" — and one\n * ledger entry (`vote-1789058788915-6lfrbuq`) shows a seat that APPROVED\n * on the proposal text after failing to read. `literal(true)` and\n * present-only, so every pre-1.8 entry re-hashes byte-identical.\n */\n unverifiable: z.literal(true).optional(),\n })\n .strict();\nexport type VoterSummary = z.infer<typeof VoterSummarySchema>;\n\n/**\n * Identity at runtime; an exhaustiveness constraint at compile time (#6077).\n *\n * The tuple literal only type-checks when every `keyof VoterSummary` appears\n * in it: `[keyof VoterSummary] extends [T[number]]` is `unknown` (no-op\n * intersection) when the tuple is complete and `never` when a schema key is\n * missing, so the argument becomes unassignable. Drop `retried` from the tuple\n * below and this call is a `tsc` error, not a silently unhashed field.\n *\n * This exists INSTEAD of a standalone sentinel const because a sentinel\n * survives lint only through the `^_` unused-vars ignore pattern and can be\n * deleted by a dead-code pass with no test failing — the \"check that can vanish\n * without a failing test\" class. Bound to the tuple's initialization, the check\n * cannot be removed separately from the thing it checks. The `satisfies` on the\n * literal still catches the other direction (a key the schema lacks).\n */\nfunction defineVoterKeys<T extends readonly (keyof VoterSummary)[]>(\n keys: T & ([keyof VoterSummary] extends [T[number]] ? unknown : never)\n): T {\n return keys;\n}\n\n/**\n * THE canonical voter-entry field order (#6057). One source, three consumers:\n * the hash projection iterates it, the schema is checked against it at compile\n * time in both directions, and the builder's output is asserted against it.\n *\n * An EXPLICIT tuple, not `Object.keys(VoterSummarySchema.shape)`, on the\n * ratification panel's refinement: canonical hash order must not depend on the\n * order someone declared keys in a schema, because a formatter or a readability\n * reorder would then silently move every historical hash. Reordering the SCHEMA\n * changes nothing; reordering THIS tuple fails the pinned maximal golden.\n *\n * `satisfies` catches a key the schema lacks (direction 1); the\n * {@link defineVoterKeys} constraint catches a schema key this tuple lacks\n * (direction 2). Both are compile errors, so the \"schema-only field\" failure\n * mode is closed at build time.\n *\n * DO NOT REORDER. The pinned literal in vote-record.test.ts is the guard.\n */\nconst VOTER_SUMMARY_KEYS = defineVoterKeys([\n 'role',\n 'decision',\n 'confidence',\n 'reasoning',\n 'reasoningTruncated',\n 'retried',\n // 1.8 (#6091, #6094): appended after `retried`, present-only, so a 1.7\n // entry projects byte-identically.\n 'model',\n 'unverifiable',\n] as const satisfies readonly (keyof VoterSummary)[]);\n\n/**\n * Project one voter entry for the canonical hash: every key in\n * {@link VOTER_SUMMARY_KEYS}, in that order, PRESENT-ONLY. An absent optional is\n * omitted, never emitted as `null` — that is what keeps every pre-1.7 record's\n * canonical string byte-identical. The two optional flags are `literal(true)`,\n * so `!== undefined` is exactly the old `=== true`.\n */\nfunction projectVoterSummary(v: VoterSummary): Partial<VoterSummary> {\n const out: Record<string, unknown> = {};\n for (const key of VOTER_SUMMARY_KEYS) {\n if (v[key] !== undefined) out[key] = v[key];\n }\n return out;\n}\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 option's share of a multi-option vote (#4452).\n *\n * The approve/reject/abstain tally cannot express WHICH option a voter chose, so\n * a real 6-1 split over options A and C persists as `approve: 7` — indis-\n * tinguishable from genuine unanimity. This carries the distribution.\n */\nexport const VoteRecordOptionCountSchema = z\n .object({\n /** The option label as declared in the proposal (e.g. 'A'). */\n option: z.string().min(1),\n /** How many voters selected it. */\n count: z.number().int().nonnegative(),\n })\n .strict();\nexport type VoteRecordOptionCount = z.infer<typeof VoteRecordOptionCountSchema>;\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', '1.3', '1.4', '1.5', '1.6', '1.7', '1.8']),\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 * Per-option distribution for a multi-option proposal (#4452, schema 1.3).\n *\n * Present only when the vote declared `options`. Absent on an ordinary\n * yes/no vote, and absent on every 1.1/1.2 record — which is why it is\n * folded into the self-hash ONLY when present (see\n * {@link computeVoteRecordHash}), exactly as `ratifies` was.\n *\n * Without this, a 6-1 or 5-2 option split is recorded as `approve: 7` and\n * reads as unanimous. Threshold semantics invert too: `unanimous` becomes\n * the EASIEST bar to clear, because every engaged voter approves while\n * choosing different things.\n */\n // No `.min(1)` (#6049). The rule this field's own docstring states is\n // \"present only when the vote declared `options`\" -- keyed on DECLARATION,\n // not on whether anyone picked one. `.min(1)` encoded the older, narrower\n // rule, so once the builder started emitting `[]` for \"declared, nothing\n // attributable\" the record appended fine and then failed to parse on read:\n // `too_small, minimum 1`. The write path does not validate, so the line\n // landed in the ledger and `parseVoteRecordsText` silently dropped it --\n // the case most worth auditing became the one no reader could see.\n //\n // Relaxing is a pure widening: no previously-valid record changes meaning\n // or hash, and no persisted record can currently hold an empty tally.\n optionTally: z.array(VoteRecordOptionCountSchema).optional(),\n /**\n * Selection coverage for a multi-option vote (#4472, schema 1.4).\n *\n * `optionTally` alone cannot distinguish dissent from absence: `4 pick X\n * + 3 unreadable` and a genuine 4/3 split both leave a leading share of\n * 57%. Recording how many approvers produced no usable selection is what\n * makes a partial measurement legible AS partial — the condition every\n * voter attached to adopting the \"credit no option\" rule.\n */\n optionCoverage: VoteRecordOptionCoverageSchema.optional(),\n /**\n * Panel coverage (#5738, schema 1.5). Present only when at least one\n * requested voter failed to return a vote; absent keeps a clean panel on\n * the pre-1.5 projection, so every historical record still verifies.\n */\n panelCoverage: VoteRecordPanelCoverageSchema.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 * Append the optional fields to the canonical projection, each ONLY when\n * present, in schema order.\n *\n * This is the back-compat rule the whole record set depends on: a record\n * without an optional field re-hashes byte-identical to the form that predates\n * it, so every historical record still verifies. It stays tamper-evident —\n * adding, removing or editing one of these on a persisted record flips the\n * hash.\n *\n * Extracted from {@link computeVoteRecordHash} when `panelCoverage` (#5738)\n * pushed that function past the 50-line cap.\n */\nfunction foldOptionalFields(base: object, payload: VoteRecordPayload): object {\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 // `optionTally` (#4452) is folded in on the same principle as `ratifies`:\n // ONLY when present, appended after the stable base, with each entry rebuilt\n // field-by-field in schema order. A record without it re-hashes byte-identical\n // to the pre-1.3 form, so every historical record still verifies.\n const withTally =\n payload.optionTally !== undefined\n ? {\n ...base,\n optionTally: payload.optionTally.map((o) => ({ option: o.option, count: o.count })),\n }\n : base;\n // `optionCoverage` (#4472, schema 1.4) follows the same append-when-present\n // rule, inserted after `optionTally` and before `ratifies` so the canonical\n // order matches the schema order. Absent ⇒ byte-identical to the 1.3 form.\n const withCoverage =\n payload.optionCoverage !== undefined\n ? {\n ...withTally,\n optionCoverage: {\n approverCount: payload.optionCoverage.approverCount,\n selectedCount: payload.optionCoverage.selectedCount,\n unattributedApprovals: payload.optionCoverage.unattributedApprovals,\n },\n }\n : withTally;\n // `panelCoverage` (#5738, schema 1.5) follows the same append-when-present\n // rule, after `optionCoverage` and before `ratifies`. Absent ⇒ byte-identical\n // to the 1.4 form, so every historical record re-hashes unchanged.\n const withPanel =\n payload.panelCoverage !== undefined\n ? {\n ...withCoverage,\n panelCoverage: {\n requested: payload.panelCoverage.requested,\n responded: payload.panelCoverage.responded,\n errored: payload.panelCoverage.errored,\n erroredRoles: [...payload.panelCoverage.erroredRoles],\n },\n }\n : withCoverage;\n return payload.ratifies !== undefined ? { ...withPanel, ratifies: payload.ratifies } : withPanel;\n}\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 // `reasoning` / `reasoningTruncated` (#5373, schema 1.6) are appended per\n // entry ONLY when present, on the same rule as the record-level optional\n // fields: a pre-1.6 voter entry re-hashes byte-identical, so every\n // historical record still verifies, while editing or removing a stored\n // reasoning flips the hash.\n voters: payload.voters.map(projectVoterSummary),\n correlationId: payload.correlationId ?? null,\n };\n const canonical = JSON.stringify(foldOptionalFields(base, payload));\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 | {\n ok: true;\n recordCount: number;\n forks?: number[];\n /**\n * Set when the verified set was EMPTY, so nothing was checked (#5818).\n *\n * `ok: true` alone does not distinguish a verified set from an absent\n * one — the \"default reported as a measurement\" shape the mission text\n * rules out. Same field name, value and meaning as `verifyChain`'s\n * `notVerified: 'empty'` (`audit-logger.ts`), which was added for exactly\n * this reason; two of the verifiers in this directory already spoke that\n * vocabulary and these two did not.\n *\n * The verdict is deliberately still `ok: true`: an empty ledger is not\n * evidence of tampering, and failing on it would block every governor PR\n * while the ledger has no producer. It is the CALLER's job to say\n * \"verified nothing\" rather than printing a bare pass.\n */\n notVerified?: 'empty';\n }\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, notVerified: 'empty' };\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 { CLI_NAMES, type CliNameLiteral } from '../../config/model-capabilities-types.js';\n\nconst logger = createLogger({ tool: 'consensus-vote' });\n\n/**\n * Records a completed consensus vote to session memory and, when measured,\n * the learning and outcome stores. Best-effort.\n *\n * When every vote is simulated, this is a no-op: simulated votes are random\n * (#2319) and must not seed the learning store or outcome store, otherwise\n * test/demo runs poison real routing decisions.\n * A `no_quorum` decision records only the task occurrence because the panel\n * measured no verdict to learn from or feed into adaptive routing (#5544).\n */\nexport function recordVoteSuccess(args: {\n proposal: string;\n strategy: string;\n decision: VoteRecord['decision'];\n durationMs: number;\n approvalPercentage?: number;\n votes?: readonly AgentVoteResult[];\n}): void {\n const allSimulated =\n args.votes !== undefined &&\n args.votes.length > 0 &&\n args.votes.every((v) => v.source === 'simulation');\n if (allSimulated) {\n logger.debug('Skipping memory + outcome recording — all votes simulated');\n return;\n }\n\n try {\n const memory = getToolMemory();\n memory.recordTask({\n approach: `Consensus vote: ${args.strategy} on \"${args.proposal.slice(0, 50)}\"`,\n challenges: [],\n durationMs: args.durationMs,\n });\n if (args.decision !== 'no_quorum') {\n memory.recordLearning({\n pattern: `${args.strategy} vote → ${args.decision}`,\n context: `proposal=\"${args.proposal.slice(0, 40)}\" duration=${String(args.durationMs)}ms`,\n confidence: learningConfidence(args.decision, args.approvalPercentage),\n source: 'consensus-vote',\n });\n void memory.runPromotionPipeline().catch((error: unknown) => {\n logger.warn('Promotion pipeline failed', { error });\n });\n }\n } catch (error: unknown) {\n logger.warn('Failed to record vote success to memory', { error: getErrorMessage(error) });\n }\n\n if (args.decision === 'no_quorum') return;\n // Also record to outcome store for adaptive routing feedback (#1551).\n // recordVoteOutcomes already filters per-vote `source === 'simulation'`,\n // but we keep the all-simulated guard above to skip the memory writes too.\n if (args.votes !== undefined) {\n recordVoteOutcomes(args.votes);\n }\n}\n\nfunction learningConfidence(\n decision: Exclude<VoteRecord['decision'], 'no_quorum'>,\n approvalPercentage: number | undefined\n): number {\n if (approvalPercentage === undefined) return 0.8;\n const approvalConfidence = approvalPercentage / 100;\n return decision === 'approved' ? approvalConfidence : 1 - approvalConfidence;\n}\n\n/** Strategy values that map cleanly onto a {@link VoteRecord} strategy. */\nconst VOTE_RECORD_STRATEGIES: ReadonlySet<VoteRecord['strategy']> = new Set([\n 'simple_majority',\n 'supermajority',\n 'unanimous',\n 'higher_order',\n 'opinion_wise',\n 'proof_of_learning',\n]);\n\n/** Narrow an arbitrary strategy string to the record enum, defaulting safely. */\nfunction toRecordStrategy(strategy: string): VoteRecord['strategy'] {\n return VOTE_RECORD_STRATEGIES.has(strategy as VoteRecord['strategy'])\n ? (strategy as VoteRecord['strategy'])\n : 'simple_majority';\n}\n\n/**\n * Structured outcome of the best-effort authentic-vote-record persistence\n * (#3991). Surfaced in the `consensus_vote` result so an MCP caller can SEE\n * whether the record was written and, when not, WHY + how to fix — previously a\n * skipped/failed persist was only a server-side WARN invisible to MCP clients.\n *\n * Reason vocabulary (#3991, Option B). Since the runtime ledger now routes\n * through `nexusDataPath` under `governance/`, the path essentially always\n * resolves to a writable `.nexus-agents/governance/` location — so the normal\n * case is `persisted: true`. The former `'no-repo-root'` reason is OBSOLETE\n * (there is always a homedir/sandbox/repo fallback): a non-persist is now either\n * `'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 */\n/**\n * Everything {@link recordAuthenticVote} needs. Named rather than inline: the\n * doc comments the required fields deserve pushed the function past its\n * line cap, and the cap is there to be answered with a decision (#6008).\n */\ninterface RecordAuthenticVoteArgs {\n proposal: string;\n strategy: string;\n result: ConsensusResult;\n votes: readonly AgentVoteResult[];\n correlationId?: string | undefined;\n /** Authority-tier ratification subject (#4004) — bound into the record's self-hash. */\n ratifies?: string | undefined;\n /** #4053: vote voided by an error-policy short-circuit → persist `no_quorum`. */\n errorVoided?: boolean | undefined;\n /** Declared options; see `BuildVoteRecordInput.declaredOptions` (#6049). */\n declaredOptions: readonly string[] | undefined;\n /**\n * The decision `resolveVoteDecision` already produced for the response.\n *\n * Required — including its `undefined` case — because deriving it a second\n * time inside the record store is what let the chain say `approved` for a\n * vote the tool reported as `no_quorum` (#4986). A caller that has the\n * resolved decision must hand it over rather than let the store guess.\n */\n resolvedDecision: VoteRecord['decision'] | undefined;\n}\n\nexport function recordAuthenticVote(args: RecordAuthenticVoteArgs): 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 declaredOptions: args.declaredOptions,\n resolvedDecision: args.resolvedDecision,\n ...(args.errorVoided !== undefined ? { errorVoided: args.errorVoided } : {}),\n ...(args.correlationId !== undefined ? { correlationId: args.correlationId } : {}),\n ...(args.ratifies !== undefined ? { ratifies: args.ratifies } : {}),\n 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 =\n vote.cli !== undefined && (CLI_NAMES as readonly string[]).includes(vote.cli)\n ? (vote.cli as CliNameLiteral)\n : ('unknown' as const);\n const voteSuccess = vote.source === 'llm';\n store.append({\n id: `vote-${String(getTimeProvider().now())}-${getRandomProvider().random().toString(36).slice(2, 8)}`,\n cli: cliName,\n category: 'planning',\n model: 'consensus',\n success: voteSuccess,\n durationMs: vote.processingTimeMs,\n timestamp: now,\n source: 'consensus',\n // #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 — or whose model has no pricing anywhere in the registry chain\n * (#4165) — are folded in as UNMEASURED (not a measured $0) — see\n * {@link module:observability/decision-cost}. Record + measure ONLY — no routing\n * or weighting change.\n *\n * @module mcp/tools/decision-cost-recording\n */\n\nimport type { AgentVoteResult } from '../../cli/vote-types.js';\nimport { createLogger, getTimeProvider, type ILogger } from '../../core/index.js';\nimport { computeCostDetail, priceBasisOf } 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 computeCostDetail} the per-call usage log uses, so\n * a per-decision rollup and the per-call usage log price identically. When no\n * usage was reported the voter is left with no tokens/cost ⇒ unmeasured.\n *\n * When the model resolves WITHOUT pricing anywhere in the registry chain\n * (#4165), `costUsd` is OMITTED — tokens are kept — so the rollup counts the\n * voter as UNMEASURED (#3855: missing cost is unmeasured, never a measured $0).\n *\n * Whenever a price WAS looked up, the resulting {@link PriceBasis} rides along\n * (#4406) so the recorded figure says whether it came from a vendor list rate\n * rather than reading as contract-accurate.\n */\n/**\n * Copy only the token counters the adapter actually reported. Every field is\n * spread conditionally so an absent counter stays absent — a fabricated 0\n * would read as a measurement (#4439).\n *\n * The cache figures ride along for visibility only: cost is still priced on\n * uncached input, because the registry carries no cache-read rate and pricing\n * the cached portion at the input rate would overstate spend (#4435).\n */\nfunction reportedTokenFields(v: AgentVoteResult): Partial<VoterCostInput> {\n return {\n ...(v.inputTokens !== undefined ? { inputTokens: v.inputTokens } : {}),\n ...(v.outputTokens !== undefined ? { outputTokens: v.outputTokens } : {}),\n ...(v.cachedInputTokens !== undefined ? { cachedInputTokens: v.cachedInputTokens } : {}),\n ...(v.cacheCreationInputTokens !== undefined\n ? { cacheCreationInputTokens: v.cacheCreationInputTokens }\n : {}),\n };\n}\n\nexport function votesToCostInputs(votes: readonly AgentVoteResult[]): VoterCostInput[] {\n return votes.map((v) => {\n const hasTokens = v.inputTokens !== undefined || v.outputTokens !== undefined;\n const detail =\n hasTokens && v.model !== undefined\n ? computeCostDetail(v.model, v.inputTokens ?? 0, v.outputTokens ?? 0)\n : undefined;\n const input: VoterCostInput = {\n role: v.role,\n model: v.model,\n ...reportedTokenFields(v),\n ...(detail?.priced === true ? { costUsd: detail.costUsd } : {}),\n // #4406 — state what kind of rate the cost rests on, but only when we\n // actually consulted the registry. No lookup ⇒ no claim (absent), which\n // is distinct from 'unknown' (\"we looked and there is no price\").\n ...(detail !== undefined ? { priceBasis: priceBasisOf(detail) } : {}),\n };\n return input;\n });\n}\n\nexport interface RecordDecisionCostOptions {\n /** 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 — fail-closed gate for `simulateVotes: true`.\n *\n * Simulated votes are random and exist only for unit tests and demos.\n * Outside a test runner a `simulateVotes: true` request is REJECTED unless\n * the operator explicitly opts in via `NEXUS_ALLOW_SIMULATE=1` — the field\n * is caller-supplied on the MCP input schemas, so warn-and-proceed let a\n * steered caller manufacture a governance approval from a random panel.\n * (Source: Issue #2317, #2319; fail-closed rework #4170)\n *\n * The guard NEVER throws: call sites sit inside pipeline try blocks whose\n * catch paths categorize as `internal` — a thrown denial would be\n * miscategorized. It returns a structured verdict instead.\n *\n * @module mcp/tools/simulation-guard\n */\n\nimport type { ILogger } from '../../core/index.js';\nimport { toolStructuredError, type ToolResult } from './tool-result.js';\n\nconst WARNED = new Set<string>();\n\n/** Explicit opt-in env var permitting simulated votes outside test runners (#4170). */\nexport const ALLOW_SIMULATE_ENV = 'NEXUS_ALLOW_SIMULATE';\n\n/** Returns true when running under vitest or another test runner. */\nexport function isTestRunner(): boolean {\n return process.env.VITEST === 'true' || process.env.NODE_ENV === 'test';\n}\n\n/**\n * Verdict of {@link checkSimulationAllowed}. `optedIn` distinguishes the\n * test-runner path (false — nothing to surface) from the explicit\n * `NEXUS_ALLOW_SIMULATE=1` path (true — callers stamp `simulated: true`\n * on their output so a demo result can never pass as a real decision).\n */\nexport type SimulationCheckResult =\n | { readonly allowed: true; readonly optedIn: boolean }\n | { readonly allowed: false; readonly reason: string };\n\n/**\n * Decide whether a `simulateVotes: true` request may proceed (#4170):\n *\n * - test runner (VITEST/NODE_ENV) → allowed, `optedIn: false`;\n * - `NEXUS_ALLOW_SIMULATE=1` → allowed, `optedIn: true`, with the\n * one-shot RANDOM-output warning logged per (tool, process);\n * - otherwise → NOT allowed, with a reason naming the\n * opt-in env var. Never throws — see the module doc.\n */\nexport function checkSimulationAllowed(toolName: string, logger: ILogger): SimulationCheckResult {\n if (isTestRunner()) return { allowed: true, optedIn: false };\n if (process.env[ALLOW_SIMULATE_ENV] === '1') {\n warnOnce(toolName, logger);\n return { allowed: true, optedIn: true };\n }\n return {\n allowed: false,\n reason:\n `[${toolName}] simulateVotes=true is rejected outside test runners: simulated votes ` +\n `are RANDOM and must not produce real decisions (#4170). ` +\n `Set ${ALLOW_SIMULATE_ENV}=1 to explicitly opt in (demos only).`,\n };\n}\n\n/**\n * Shared denial envelope for a failed {@link checkSimulationAllowed}: the\n * three call sites (consensus_vote, run_pipeline, run_dev_pipeline) must\n * reject identically — `permission` category, detail naming the opt-in.\n */\nexport function simulationDeniedResult(reason: string): ToolResult {\n return toolStructuredError({\n errorCategory: 'permission',\n message: reason,\n detail: { optIn: `${ALLOW_SIMULATE_ENV}=1` },\n });\n}\n\n/**\n * One-shot warning per (tool, process) pair for the explicit opt-in path.\n * `simulateVotes: true` output is random; the warning keeps an opted-in demo\n * run from being silently mistaken for a real decision (#2319).\n */\nfunction warnOnce(toolName: string, logger: ILogger): void {\n if (WARNED.has(toolName)) return;\n WARNED.add(toolName);\n logger.warn(\n `[${toolName}] simulateVotes=true: output is RANDOM and reserved for tests/demos. Do not treat the result as a real decision.`\n );\n}\n\n/** Test-only: clear the warned-set so repeated tests can re-trigger the warning. */\nexport function _resetWarned(): void {\n WARNED.clear();\n}\n","/**\n * 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';\nimport { OPERATION_CLASSES } from '../../config/timeouts.js';\nimport { VERSION } from '../../version.js';\n\nconst logger = createLogger({ component: 'job-result-store' });\n\n/** Lifecycle status of a job-result record. */\nexport const JobStatusSchema = z.enum(['pending', 'complete', 'failed', 'cancelled']);\nexport type JobStatus = z.infer<typeof JobStatusSchema>;\n\n/**\n * One on-disk job-result record. Versioned so future readers can\n * tell which Stage wrote it — bump on schema break.\n */\nexport const JobResultSchema = z.object({\n /** Format version. Currently `1` — bump if the shape changes. */\n v: z.literal(1),\n jobId: z.string().min(1),\n /** Tool that was invoked (e.g. `orchestrate`). */\n toolName: z.string().min(1),\n status: JobStatusSchema,\n createdAt: z.iso.datetime(),\n /** Set when the job leaves `pending` — either via `complete` or `failed` or `cancelled`. */\n completedAt: z.iso.datetime().optional(),\n /**\n * Structured payload the synchronous mode would have returned. Present\n * only when `status === 'complete'`. Shape is tool-specific — readers\n * cast to the tool's known output type after status check.\n */\n result: z.unknown().optional(),\n /**\n * Failure message when `status === 'failed'`. Cannot be paired with\n * `result` — the discriminator is `status`.\n */\n error: z.string().optional(),\n /**\n * Whether the tool's `run` callback accepts `runAsJob`'s `AbortSignal`\n * (#4972).\n *\n * `cancel_job` writes a `cancelled` record whether or not the tool can act\n * on the signal — as `cancel-job-tool.ts` says, \"a tool that IGNORES the\n * signal still runs to completion… but its record stays `cancelled`\". A\n * reader of that record could not tell the two apart, so `cancelled` claimed\n * more than was known.\n *\n * This is a STRUCTURAL fact — the callback's arity — not a behavioural one.\n * A tool may accept the signal and never await on it, so `true` means\n * \"cancellation can reach this tool\", not \"the work stopped\". Absent means\n * the writer did not report it, which is not the same as `false`.\n */\n signalAccepted: z.boolean().optional(),\n /**\n * `VERSION` of the nexus-agents process that WROTE this record (#5008) —\n * i.e. the build that ran the job, not the build that reads it back.\n *\n * `get_job_result` is itself a wrapped tool, so its `_meta['nexus-agents/build']`\n * stamp (#5056) names the READER's build. After a mid-session global install\n * the reader and the producer differ, and only the record can say which\n * build produced the payload. Each writer re-stamps on its own transition,\n * so a terminal record names the process that settled it.\n *\n * Optional so v1 records written before this field existed still parse:\n * on a SIDECAR record, absence means \"produced before this field existed\",\n * not a version of `undefined`. A record adapted from the task-state log\n * (`jobResultFromTaskState`, selected by `NEXUS_JOB_RESULT_SOURCE=task_state`)\n * NEVER carries it — that log records no producer version — so a reader\n * must consult the source (`get_job_result`'s `producerVersionSource`)\n * before reading absence as age. The value is recorded verbatim, including\n * `'dev'` — readers MUST run it through {@link isMeasuredBuildVersion}\n * before treating two stamps as comparable.\n */\n producerVersion: z.string().optional(),\n});\nexport type JobResult = z.infer<typeof JobResultSchema>;\n\n/**\n * The value `VERSION` takes when the build-time define is absent (a source\n * checkout run through tsx, or an unbundled test). Two local builds at\n * different commits both read this way.\n */\nconst UNMEASURED_BUILD_VERSION = 'dev';\n\n/**\n * Whether a recorded build version actually identifies a build (#5008).\n *\n * `false` for an absent or empty value and for `'dev'`. `'dev'` is what\n * `VERSION` reads without the build-time define, so two `'dev'` stamps say\n * nothing about whether the same code wrote them — treating that as a match\n * would be exactly the misreport the field exists to prevent. A reader that\n * compares producer to reader must gate the comparison on this.\n */\nexport function isMeasuredBuildVersion(version: string | undefined): boolean {\n return version !== undefined && version !== '' && version !== UNMEASURED_BUILD_VERSION;\n}\n\n/**\n * Whether a `pending` record describes work no process is still doing (#4976).\n *\n * The record is durable; the work is a detached in-process promise. If the\n * process dies mid-body no terminal writer ever runs, and `writeJobPending`\n * refuses to overwrite an existing file — so the record stays `pending`\n * forever and a caller polling `get_job_result` waits on work that no longer\n * exists.\n *\n * The anchor is objective rather than a guess: `async-job-body` (3600s) is the\n * runaway guard `runAsJob` applies to every body, so a live job CANNOT still be\n * pending past it — it would have been recorded `failed` by the guard.\n *\n * Reported rather than written back. The record is evidence of what was\n * observed; overwriting it on read would destroy that. This is the same\n * treatment `notVerified` gives an audit chain that verified nothing.\n */\nexport function isAbandonedJob(record: JobResult, nowMs: number): boolean {\n if (record.status !== 'pending') return false;\n // An unparseable `createdAt` yields NaN, and every NaN comparison is false —\n // so an unknown age reports \"not abandoned\" without a separate guard. That is\n // the right default: killing a job whose age cannot be read would be a guess.\n const startedMs = Date.parse(record.createdAt);\n return nowMs - startedMs > OPERATION_CLASSES['async-job-body'].guardMs;\n}\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 * Every writer below takes a trailing `producerVersion` defaulting to the\n * running server's `VERSION` (#5008). The parameter is the DI seam: a test\n * can write a version that differs from `VERSION` and prove the stamp\n * round-trips from the injected value rather than from an ambient constant.\n */\n\n/**\n * Write the initial `pending` record for a new job. Idempotent: if a\n * record for `jobId` already exists (e.g. operator restart re-runs the\n * same idempotencyKey — Stage 1 follow-up), this is a no-op.\n *\n * Caller responsibility: generate a fresh `jobId` per call (Stage 1\n * doesn't yet deduplicate via idempotencyKey — that's #3042 follow-up).\n */\nexport function writeJobPending(\n jobId: string,\n toolName: string,\n signalAccepted?: boolean,\n producerVersion: string = VERSION\n): void {\n const path = jobResultPath(jobId);\n if (existsSync(path)) {\n logger.debug('Job result file already exists — leaving in place', { jobId });\n return;\n }\n const record: JobResult = {\n v: 1,\n jobId,\n toolName,\n status: 'pending',\n createdAt: new Date().toISOString(),\n ...(signalAccepted !== undefined ? { signalAccepted } : {}),\n producerVersion,\n };\n persistJobRecord(path, record);\n logger.debug('Wrote pending job record', { jobId, toolName, signalAccepted });\n}\n\n/**\n * Replace the record with a terminal `complete` status carrying the\n * structured payload. Caller writes the SAME shape the sync mode would\n * have returned, so a polling client can use the result interchangeably.\n *\n * COMPLETE-AFTER-CANCEL guard (#4017): if the job was already `cancelled`\n * (e.g. `cancel_job` landed while the work was in-flight — `runAsJob` does not\n * yet abort the underlying work), this is a NO-OP so the cancellation is not\n * silently rewritten back to `complete`. Symmetric with the caller-side\n * cancel-after-complete guard documented on {@link writeJobCancelled}.\n */\nexport function writeJobComplete(\n jobId: string,\n toolName: string,\n result: unknown,\n producerVersion: string = VERSION\n): void {\n const existing = readJobResult(jobId);\n if (existing?.status === 'cancelled') {\n logger.debug('Skipping complete write — job already cancelled (preserving cancellation)', {\n jobId,\n toolName,\n });\n return;\n }\n const record: JobResult = {\n v: 1,\n jobId,\n toolName,\n status: 'complete',\n createdAt: existing?.createdAt ?? new Date().toISOString(),\n completedAt: new Date().toISOString(),\n result,\n producerVersion,\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(\n jobId: string,\n toolName: string,\n error: string,\n producerVersion: string = VERSION\n): void {\n const existing = readJobResult(jobId);\n if (existing?.status === 'cancelled') {\n logger.debug('Skipping failed write — job already cancelled (preserving cancellation)', {\n jobId,\n toolName,\n });\n return;\n }\n const 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 producerVersion,\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(\n jobId: string,\n toolName: string,\n reason?: string,\n producerVersion: string = VERSION\n): 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 producerVersion,\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\n/**\n * What a job listing could NOT read (#6038).\n *\n * `listJobs` returned a bare array, so two very different worlds produced `[]`:\n * \"there are no jobs\" and \"the jobs directory would not open\". And a sidecar\n * that failed `JobResultSchema` — a record written by a newer nexus-agents, or\n * half-written by a concurrent job — was skipped by deliberate policy in\n * `readJobResult` and then left no trace at all. `list_jobs` reported\n * `{\"count\":0,\"truncated\":false}` over both, and an operator or the autonomous\n * loop concludes nothing is pending and re-dispatches work already running.\n */\ninterface JobListDiagnostics {\n /** True when the jobs directory exists but could not be enumerated. */\n readonly dirUnreadable: boolean;\n /** Sidecar files that matched the naming pattern but failed to parse or validate. */\n readonly unparseableRecords: number;\n}\n\n/** Job summaries plus what the listing could not read. */\nexport interface JobListing {\n readonly jobs: JobSummary[];\n readonly diagnostics: JobListDiagnostics;\n}\n\nexport function listJobs(): JobSummary[] {\n return listJobsWithDiagnostics().jobs;\n}\n\n/** List jobs AND report what the listing could not read (#6038). */\nexport function listJobsWithDiagnostics(): JobListing {\n const dir = nexusDataPath('jobs');\n // An ABSENT directory is a measured absence: no jobs have ever been written.\n // That is different from a directory that exists and will not open.\n if (!existsSync(dir)) {\n return { jobs: [], diagnostics: { dirUnreadable: false, unparseableRecords: 0 } };\n }\n let entries: string[];\n try {\n entries = readdirSync(dir);\n } catch (err) {\n logger.warn('jobs directory unreadable', {\n dir,\n error: err instanceof Error ? err.message : String(err),\n });\n return { jobs: [], diagnostics: { dirUnreadable: true, unparseableRecords: 0 } };\n }\n const summaries: JobSummary[] = [];\n let unparseableRecords = 0;\n for (const entry of entries) {\n const match = /^result-(.+)\\.json$/.exec(entry);\n if (match === null) continue;\n const jobId = match[1];\n if (jobId === undefined) continue;\n const record = readJobResult(jobId);\n if (record === null) {\n unparseableRecords += 1;\n continue;\n }\n summaries.push(toJobSummary(record));\n }\n // Newest first — matches typical \"what just happened\" discovery flow.\n return {\n jobs: summaries.sort((a, b) => b.createdAt.localeCompare(a.createdAt)),\n diagnostics: { dirUnreadable: false, unparseableRecords },\n };\n}\n","/**\n * 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 * Structured task state — JSONL append-only log (#2033).\n *\n * Writes a per-task log at `~/.nexus-agents/tasks/state-{taskId}.jsonl`\n * (overridable via `customDir` for tests). Replay reduces the log\n * forward to a current `StructuredTaskState` snapshot — suitable for\n * resume-after-restart and STATE.md-style inspection.\n *\n * Mirrors the session-journal pattern in `context/session-journal.ts`:\n * - Directory mode 0o700, file mode 0o600\n * - Path-traversal validation on taskId\n * - `Result<T, Error>` returns, no exceptions for expected failures\n *\n * @module context/structured-task-state\n */\n\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { AsyncLocalStorage } from 'node:async_hooks';\nimport { nexusDataPath } from '../config/nexus-data-dir.js';\nimport type { Result } from '../core/result.js';\nimport { ok, err } from '../core/result.js';\nimport { createLogger } from '../core/logger.js';\nimport {\n StructuredTaskLogEntrySchema,\n TASK_RESULT_MAX_BYTES,\n type ProgressLedgerEntry,\n type ReflectAction,\n type StructuredTaskLogEntry,\n type StructuredTaskState,\n type TaskBlocker,\n type TaskCancellation,\n type TaskDecision,\n type TaskLedger,\n type TaskPosition,\n type TaskStage,\n} from './structured-task-state-types.js';\n\nconst logger = createLogger({ component: 'structured-task-state' });\n\n/** Subdirectory name under the resolved nexus data dir for task-state logs. */\nconst TASKS_SUBDIR = 'tasks';\n\nconst FILE_MODE = 0o600;\nconst DIR_MODE = 0o700;\n\nconst asyncTaskStateJob = new AsyncLocalStorage<string>();\n\n/** Run work whose task-state initialization must record async dispatch. @internal */\nexport function withAsyncTaskStateDispatch<T>(jobId: string, operation: () => T): T {\n return asyncTaskStateJob.run(jobId, operation);\n}\n\nfunction getTasksDir(customDir?: string): string {\n if (customDir !== undefined) return path.resolve(customDir);\n return nexusDataPath(TASKS_SUBDIR);\n}\n\nfunction getLogPath(taskId: string, customDir?: string): string {\n return path.join(getTasksDir(customDir), `state-${taskId}.jsonl`);\n}\n\n/**\n * Enumerate the task ids that have a state log on disk (#3693). Walks the tasks\n * dir for `state-<taskId>.jsonl` files; returns `[]` when the dir is absent or\n * unreadable (best-effort, never throws). `customDir` steers the lookup for tests.\n */\nexport function listTaskStateIds(customDir?: string): string[] {\n const dir = getTasksDir(customDir);\n if (!fs.existsSync(dir)) return [];\n let entries: string[];\n try {\n entries = fs.readdirSync(dir);\n } catch (cause) {\n logger.warn('tasks directory unreadable', {\n dir,\n error: cause instanceof Error ? cause.message : String(cause),\n });\n return [];\n }\n const ids: string[] = [];\n for (const entry of entries) {\n const match = /^state-(.+)\\.jsonl$/.exec(entry);\n if (match?.[1] !== undefined) ids.push(match[1]);\n }\n return ids;\n}\n\nfunction validateTaskId(taskId: string): Result<string, Error> {\n if (taskId.includes('..') || taskId.includes('/') || taskId.includes('\\\\')) {\n return err(new Error('Invalid task ID: contains path traversal characters'));\n }\n if (taskId.length === 0 || taskId.length > 128) {\n return err(new Error('Invalid task ID: must be 1-128 characters'));\n }\n return ok(taskId);\n}\n\nfunction ensureTasksDir(customDir?: string): Result<string, Error> {\n const dirPath = getTasksDir(customDir);\n try {\n fs.mkdirSync(dirPath, { recursive: true, mode: DIR_MODE });\n return ok(dirPath);\n } catch (cause) {\n const e = cause instanceof Error ? cause : new Error(String(cause));\n return err(new Error(`Failed to create tasks directory at ${dirPath}: ${e.message}`));\n }\n}\n\n/** Append a log entry (no state computation). Pure I/O. */\nfunction appendLogEntry(\n taskId: string,\n entry: StructuredTaskLogEntry,\n customDir?: string\n): Result<void, Error> {\n const idCheck = validateTaskId(taskId);\n if (!idCheck.ok) return err(idCheck.error);\n const dirResult = ensureTasksDir(customDir);\n if (!dirResult.ok) return err(dirResult.error);\n\n const filePath = getLogPath(taskId, customDir);\n const line = JSON.stringify(entry) + '\\n';\n try {\n fs.appendFileSync(filePath, line, { mode: FILE_MODE });\n return ok(undefined);\n } catch (cause) {\n const e = cause instanceof Error ? cause : new Error(String(cause));\n return err(new Error(`Failed to write task state entry: ${e.message}`));\n }\n}\n\n/**\n * Initialize structured state for a new task. Writes the full initial\n * state as an `init` log entry. Safe to call once per taskId.\n */\nexport function initTaskState(state: StructuredTaskState, customDir?: string): Result<void, Error> {\n const isAsyncJob = asyncTaskStateJob.getStore() === state.taskId;\n const persistedState = isAsyncJob ? { ...state, dispatch: 'async' as const } : state;\n return appendLogEntry(\n state.taskId,\n { event: 'init', ts: state.updatedAt, state: persistedState },\n customDir\n );\n}\n\nexport function appendDecision(\n taskId: string,\n decision: TaskDecision,\n customDir?: string\n): Result<void, Error> {\n return appendLogEntry(taskId, { event: 'decision', ts: decision.ts, decision }, customDir);\n}\n\nexport function appendBlocker(\n taskId: string,\n blocker: TaskBlocker,\n customDir?: string\n): Result<void, Error> {\n return appendLogEntry(taskId, { event: 'blocker', ts: blocker.ts, blocker }, customDir);\n}\n\nexport function resolveBlocker(\n taskId: string,\n blockerIndex: number,\n resolvedAt: string,\n customDir?: string\n): Result<void, Error> {\n return appendLogEntry(\n taskId,\n { event: 'blocker_resolved', ts: resolvedAt, blockerIndex, resolvedAt },\n customDir\n );\n}\n\nexport function updateStage(\n taskId: string,\n stage: TaskStage,\n ts: string,\n customDir?: string\n): Result<void, Error> {\n return appendLogEntry(taskId, { event: 'stage', ts, stage }, customDir);\n}\n\nexport function updatePosition(\n taskId: string,\n position: TaskPosition,\n ts: string,\n customDir?: string\n): Result<void, Error> {\n return appendLogEntry(taskId, { event: 'position', ts, position }, customDir);\n}\n\n/**\n * Replace the Magentic-One Task Ledger atomically (#2278). The outer loop calls\n * this when it replans — facts/guesses/openQuestions are revised together so\n * downstream reflections are reading a consistent set.\n */\nexport function updateTaskLedger(\n taskId: string,\n ledger: TaskLedger,\n customDir?: string\n): Result<void, Error> {\n return appendLogEntry(taskId, { event: 'task_ledger', ts: ledger.updatedAt, ledger }, customDir);\n}\n\n/**\n * Append a Magentic-One Progress Ledger entry (#2278). Inner-loop reflection\n * after a step: was the plan still valid, are we stuck, what to do next.\n */\nexport function appendProgressLedgerEntry(\n taskId: string,\n entry: ProgressLedgerEntry,\n customDir?: string\n): Result<void, Error> {\n return appendLogEntry(taskId, { event: 'progress_ledger', ts: entry.ts, entry }, customDir);\n}\n\n/**\n * Append a tool-result payload (#3043 / epic #2631 Stage 2). Carries the\n * same shape the synchronous mode would have returned inline. Writers\n * should `updateStage(taskId, 'complete', ...)` immediately before so a\n * polling reader observes the terminal stage transition + result together.\n *\n * The payload is JSON-serialized to measure size; over-cap writes\n * (> `TASK_RESULT_MAX_BYTES`) get replaced with a typed truncation\n * marker. The cap is observable by the caller (the reducer surfaces\n * `state.result` as the truncation marker rather than the original) so\n * silent data loss is impossible.\n */\nexport function appendResult(\n taskId: string,\n result: unknown,\n ts: string,\n customDir?: string\n): Result<void, Error> {\n let payload: unknown = result;\n let serialized: string;\n try {\n serialized = JSON.stringify(result ?? null);\n } catch (cause) {\n const e = cause instanceof Error ? cause : new Error(String(cause));\n return err(new Error(`Failed to serialize result for task ${taskId}: ${e.message}`));\n }\n // Note: `Buffer.byteLength` is the right unit — JSON.stringify length is\n // UTF-16 code units, not the bytes that hit disk. For ASCII the two\n // coincide; for non-ASCII / emoji results the byte-count is what bounds\n // the actual storage cost.\n const bytes = Buffer.byteLength(serialized, 'utf-8');\n if (bytes > TASK_RESULT_MAX_BYTES) {\n payload = {\n truncated: true,\n originalBytes: bytes,\n maxBytes: TASK_RESULT_MAX_BYTES,\n note: 'Result exceeded TASK_RESULT_MAX_BYTES — original dropped at write time.',\n };\n logger.warn('Task result truncated at write', {\n taskId,\n bytes,\n max: TASK_RESULT_MAX_BYTES,\n });\n }\n return appendLogEntry(taskId, { event: 'result', ts, result: payload }, customDir);\n}\n\n/**\n * Append a cancellation marker (#3043 / epic #2631 Stage 2). Called by\n * `cancel_job`. The reducer is append-only: if a cancellation already\n * exists in the log, subsequent cancellation events are kept on disk\n * (for audit) but DON'T overwrite the original `requestedAt` — so a\n * malicious or buggy double-cancel can't rewrite history.\n */\nexport function appendCancellation(\n taskId: string,\n cancellation: TaskCancellation,\n customDir?: string\n): Result<void, Error> {\n return appendLogEntry(\n taskId,\n { event: 'cancellation', ts: cancellation.requestedAt, cancellation },\n customDir\n );\n}\n\n/**\n * Read the most recent ProgressLedger entry's suggested action — what\n * `Orchestrator.reflect()` returns. Returns `'continue'` when no progress-ledger\n * entries exist yet (default to \"no reflection has flagged a problem\"), and an\n * error if the task log itself can't be read.\n */\nexport function reflect(taskId: string, customDir?: string): Result<ReflectAction, Error> {\n const stateResult = readTaskState(taskId, customDir);\n if (!stateResult.ok) return err(stateResult.error);\n const ledger = stateResult.value.progressLedger;\n if (ledger === undefined || ledger.length === 0) return ok('continue');\n const last = ledger[ledger.length - 1];\n if (last === undefined) return ok('continue');\n return ok(last.suggestedAction);\n}\n\n/**\n * Read the log file and reduce it to the current state snapshot.\n *\n * Returns `err` when the file doesn't exist or no `init` entry is\n * present. Malformed lines are skipped with a warning (log, don't\n * fail) — same policy as the session-journal replay.\n */\nexport function readTaskState(\n taskId: string,\n customDir?: string\n): Result<StructuredTaskState, Error> {\n const idCheck = validateTaskId(taskId);\n if (!idCheck.ok) return err(idCheck.error);\n\n const filePath = getLogPath(taskId, customDir);\n if (!fs.existsSync(filePath)) {\n return err(new Error(`No state log for task: ${taskId}`));\n }\n\n let content: string;\n try {\n content = fs.readFileSync(filePath, 'utf-8');\n } catch (cause) {\n const e = cause instanceof Error ? cause : new Error(String(cause));\n return err(new Error(`Failed to read state log: ${e.message}`));\n }\n\n const lines = content.split('\\n').filter((l) => l.length > 0);\n const entries: StructuredTaskLogEntry[] = [];\n for (const line of lines) {\n try {\n const parsed: unknown = JSON.parse(line);\n const validated = StructuredTaskLogEntrySchema.safeParse(parsed);\n if (validated.success) {\n entries.push(validated.data);\n } else {\n logger.warn('Skipping malformed task-state log entry', {\n taskId,\n error: validated.error.message,\n });\n }\n } catch (cause) {\n const msg = cause instanceof Error ? cause.message : String(cause);\n logger.warn('Skipping unparseable task-state log entry', { taskId, error: msg });\n }\n }\n\n return reduceLogEntries(taskId, entries);\n}\n\n/**\n * Fold a sequence of log entries into the final state. Exported so\n * tests can exercise the reducer without touching the filesystem.\n */\nexport function reduceLogEntries(\n taskId: string,\n entries: readonly StructuredTaskLogEntry[]\n): Result<StructuredTaskState, Error> {\n const init = entries.find((e) => e.event === 'init');\n if (init === undefined) {\n return err(new Error(`No init entry found for task: ${taskId}`));\n }\n const initState = init.state;\n if (initState.taskId !== taskId) {\n return err(\n new Error(`Task ID mismatch: log contains state for ${initState.taskId}, expected ${taskId}`)\n );\n }\n\n // #3043: monotonic version. Pre-Stage-2 logs lack the field; default\n // to 0 and start counting from there. Each non-init event bumps by 1.\n let state: StructuredTaskState = {\n ...initState,\n decisions: [...initState.decisions],\n blockers: initState.blockers.map((b) => ({ ...b })),\n version: initState.version ?? 0,\n // #3090: createdAt is fixed at the init entry's ts and never advances\n // (unlike updatedAt). Prefer an explicit createdAt on the init state,\n // else fall back to the init entry's ts.\n createdAt: initState.createdAt ?? init.ts,\n };\n\n for (const entry of entries) {\n if (entry === init) continue;\n state = applyLogEntry(state, entry);\n }\n return ok(state);\n}\n\n/** Apply a blockers-related event (#2033). */\nfunction applyBlockerEvent(\n state: StructuredTaskState,\n entry: Extract<StructuredTaskLogEntry, { event: 'blocker' | 'blocker_resolved' }>,\n nextVersion: number\n): StructuredTaskState {\n if (entry.event === 'blocker') {\n return {\n ...state,\n blockers: [...state.blockers, entry.blocker],\n updatedAt: entry.ts,\n version: nextVersion,\n };\n }\n return {\n ...state,\n blockers: state.blockers.map((b, i) =>\n i === entry.blockerIndex ? { ...b, resolved: entry.resolvedAt } : b\n ),\n updatedAt: entry.ts,\n version: nextVersion,\n };\n}\n\n/** Apply a simple scalar/ledger replacement event (no array merge). */\nfunction applyReplacementEvent(\n state: StructuredTaskState,\n entry: Extract<\n StructuredTaskLogEntry,\n { event: 'stage' | 'position' | 'task_ledger' | 'decision' | 'progress_ledger' }\n >,\n nextVersion: number\n): StructuredTaskState {\n switch (entry.event) {\n case 'decision':\n return {\n ...state,\n decisions: [...state.decisions, entry.decision],\n updatedAt: entry.ts,\n version: nextVersion,\n };\n case 'stage':\n return { ...state, stage: entry.stage, updatedAt: entry.ts, version: nextVersion };\n case 'position':\n return { ...state, position: entry.position, updatedAt: entry.ts, version: nextVersion };\n case 'task_ledger':\n return { ...state, taskLedger: entry.ledger, updatedAt: entry.ts, version: nextVersion };\n case 'progress_ledger':\n return {\n ...state,\n progressLedger: [...(state.progressLedger ?? []), entry.entry],\n updatedAt: entry.ts,\n version: nextVersion,\n };\n }\n}\n\n/**\n * Apply a result or cancellation event (#3043 / epic #2631 Stage 2). Result\n * always assigns; cancellation is append-only (in-memory keeps the FIRST\n * requestedAt across duplicate events).\n */\nfunction applyTerminalEvent(\n state: StructuredTaskState,\n entry: Extract<StructuredTaskLogEntry, { event: 'result' | 'cancellation' }>,\n nextVersion: number\n): StructuredTaskState {\n if (entry.event === 'result') {\n return { ...state, result: entry.result, updatedAt: entry.ts, version: nextVersion };\n }\n return {\n ...state,\n cancellation: state.cancellation ?? entry.cancellation,\n updatedAt: entry.ts,\n version: nextVersion,\n };\n}\n\n/**\n * Map each event tag to the apply-helper that owns it. Lets `applyLogEntry`\n * dispatch in one table lookup rather than a 10-case switch — the latter\n * trips the per-function complexity cap as the event set grows (#3043).\n */\nconst EVENT_CATEGORY: Record<\n StructuredTaskLogEntry['event'],\n 'init' | 'blocker' | 'replace' | 'terminal'\n> = {\n init: 'init',\n blocker: 'blocker',\n blocker_resolved: 'blocker',\n decision: 'replace',\n stage: 'replace',\n position: 'replace',\n task_ledger: 'replace',\n progress_ledger: 'replace',\n result: 'terminal',\n cancellation: 'terminal',\n};\n\nfunction applyLogEntry(\n state: StructuredTaskState,\n entry: StructuredTaskLogEntry\n): StructuredTaskState {\n const category = EVENT_CATEGORY[entry.event];\n if (category === 'init') return state;\n // #3043: every non-init event bumps the monotonic version. Calculated\n // here (not in each branch) so a new event type can't accidentally\n // forget to bump.\n const nextVersion = (state.version ?? 0) + 1;\n if (category === 'blocker') {\n return applyBlockerEvent(\n state,\n entry as Extract<StructuredTaskLogEntry, { event: 'blocker' | 'blocker_resolved' }>,\n nextVersion\n );\n }\n if (category === 'terminal') {\n return applyTerminalEvent(\n state,\n entry as Extract<StructuredTaskLogEntry, { event: 'result' | 'cancellation' }>,\n nextVersion\n );\n }\n return applyReplacementEvent(\n state,\n entry as Extract<\n StructuredTaskLogEntry,\n { event: 'decision' | 'stage' | 'position' | 'task_ledger' | 'progress_ledger' }\n >,\n nextVersion\n );\n}\n","/**\n * Structured task state — type definitions (#2033).\n *\n * Per-task state (decisions, blockers, stage, position) that a\n * long-running orchestration task mutates as it progresses. Designed\n * for the STATE.md-equivalent pattern from GSD — replacing ad-hoc\n * `memory_write` calls with a typed append-only log keyed by taskId.\n *\n * Serialized one-entry-per-JSONL-line so a later `query_trace` can\n * replay the full evolution, and resume-after-timeout reads the latest\n * state without replaying everything.\n *\n * @module context/structured-task-state-types\n */\n\nimport { z } from 'zod';\n\n/** Task execution lifecycle stages. */\nexport const TaskStageSchema = z.enum([\n 'planning',\n 'executing',\n 'verifying',\n 'complete',\n 'blocked',\n // #3091 / epic #2631: terminal failure stage. Distinct from `blocked`\n // (recoverable, still in-flight) — `failed` is terminal and maps to the\n // job-result `failed` status. Added so async-mode writers can record a\n // failed run in StructuredTaskState instead of the Stage-1 sidecar.\n 'failed',\n]);\nexport type TaskStage = z.infer<typeof TaskStageSchema>;\n\n/** A single recorded decision in the task evolution. */\nexport const TaskDecisionSchema = z.object({\n ts: z.iso.datetime(),\n decision: z.string().min(1),\n rationale: z.string().min(1),\n});\nexport type TaskDecision = z.infer<typeof TaskDecisionSchema>;\n\n/** A blocker that stopped forward progress (optionally later resolved). */\nexport const TaskBlockerSchema = z.object({\n ts: z.iso.datetime(),\n blocker: z.string().min(1),\n resolved: z.iso.datetime().optional(),\n});\nexport type TaskBlocker = z.infer<typeof TaskBlockerSchema>;\n\n/** Where the task currently is in its execution. */\nexport const TaskPositionSchema = z.object({\n currentStep: z.string().min(1),\n nextStep: z.string().optional(),\n});\nexport type TaskPosition = z.infer<typeof TaskPositionSchema>;\n\n/**\n * Magentic-One Task Ledger — outer-loop \"facts and guesses\" about the task (#2278).\n *\n * Mirrors AutoGen's `magentic-one` Orchestrator pattern: the outer loop maintains\n * a ledger of verifiable facts, working assumptions (guesses), and open questions\n * the orchestrator still needs to resolve. The inner loop's `ProgressLedger`\n * decides whether to continue, replan (which triggers a TaskLedger refresh), or\n * escalate.\n *\n * Reference: microsoft.github.io/autogen — Magentic-One Task Ledger / Progress\n * Ledger pattern.\n */\nexport const TaskLedgerSchema = z.object({\n /** Verifiable observations: what we have observed/measured/confirmed. */\n facts: z.array(z.string()),\n /** Working assumptions: useful guesses we proceed under, marked separately. */\n guesses: z.array(z.string()),\n /** Things we still need to figure out before the plan is sound. */\n openQuestions: z.array(z.string()),\n updatedAt: z.iso.datetime(),\n});\nexport type TaskLedger = z.infer<typeof TaskLedgerSchema>;\n\n/**\n * Magentic-One Progress Ledger — the inner-loop self-reflection at each step (#2278).\n *\n * After each step, the orchestrator (or whoever is driving) emits one\n * `ProgressLedgerEntry` summarizing whether the outer plan is still valid,\n * whether we are stuck, and what to do next. Append-only; the most recent entry's\n * `suggestedAction` is what `Orchestrator.reflect()` returns.\n */\nexport const ReflectActionSchema = z.enum([\n 'continue',\n 'revise_plan',\n 'escalate_to_human',\n 'abort',\n]);\nexport type ReflectAction = z.infer<typeof ReflectActionSchema>;\n\nexport const ProgressLedgerEntrySchema = z.object({\n ts: z.iso.datetime(),\n /** What just happened (the step we are reflecting on). */\n step: z.string().min(1),\n /** Is the outer Task Ledger plan still right after this step? */\n planStillValid: z.boolean(),\n /** Are we making progress, or have we stalled? */\n stuck: z.boolean(),\n /** What the orchestrator should do next based on this reflection. */\n suggestedAction: ReflectActionSchema,\n /** Why this action was chosen — required so future readers can audit the call. */\n rationale: z.string().min(1),\n});\nexport type ProgressLedgerEntry = z.infer<typeof ProgressLedgerEntrySchema>;\n\n/**\n * Cancellation marker for async-mode tools (#3043 / epic #2631 Stage 2).\n *\n * Append-only — once present, the cancellation timestamp can't be\n * cleared. `cancel_job` writes this; the task's run loop checks it at\n * safe-point boundaries to abort cleanly.\n */\nexport const TaskCancellationSchema = z.object({\n requestedAt: z.iso.datetime(),\n /** Optional human-readable note carried back to the caller. */\n reason: z.string().max(1000).optional(),\n});\nexport type TaskCancellation = z.infer<typeof TaskCancellationSchema>;\n\n/**\n * Maximum serialized size of a `result` payload, in bytes\n * (#3043 / epic #2631 Stage 2). Caps result-retention DoS — a\n * misbehaving tool that wrote a 100 MiB result into the state log\n * would block reads of every other tool's state on the same data\n * dir while the reducer parses it. 1 MiB is generous for structured\n * payloads but bounds the worst case. `appendResult` truncates\n * over-cap writes to `{ truncated: true, originalBytes }` rather\n * than dropping them silently — so the caller can tell whether a\n * missing result was never written vs. dropped at write time.\n */\nexport const TASK_RESULT_MAX_BYTES = 1_048_576;\n\n/**\n * Structured state for a single long-running task.\n *\n * All arrays are append-only during the task's lifetime; a blocker can\n * be resolved by updating its `resolved` timestamp, but we do not\n * retroactively rewrite earlier entries.\n */\nexport const StructuredTaskStateSchema = z.object({\n taskId: z.string().min(1),\n /**\n * Marks state created by the shared async-job dispatcher (#5622).\n * Optional for backward compatibility; absence does not prove async dispatch.\n */\n dispatch: z.literal('async').optional(),\n stage: TaskStageSchema,\n decisions: z.array(TaskDecisionSchema),\n blockers: z.array(TaskBlockerSchema),\n position: TaskPositionSchema,\n /**\n * Magentic-One Task Ledger (#2278). Mutable single-object outer-loop state:\n * facts/guesses/openQuestions revised together when the plan is replanned.\n * Optional so the field can be added later without breaking existing logs.\n */\n taskLedger: TaskLedgerSchema.optional(),\n /**\n * Magentic-One Progress Ledger (#2278). Append-only inner-loop reflections.\n * Most recent entry's `suggestedAction` is what `reflect()` returns. Optional\n * for the same backward-compat reason as `taskLedger`.\n */\n progressLedger: z.array(ProgressLedgerEntrySchema).optional(),\n /**\n * Monotonic version counter (#3043 / epic #2631 Stage 2). Increments by\n * 1 on every write; polling clients use this to detect \"I missed a\n * transition\" and resync rather than silently observe a stale snapshot.\n *\n * Optional + defaulting-to-0 in the reducer for backward-compat — old\n * state logs (pre-Stage-2) don't carry it; the reducer treats their\n * baseline as v0 and starts counting from there.\n */\n version: z.number().int().nonnegative().optional(),\n /**\n * Tool result payload (#3043 / epic #2631 Stage 2). Set atomically\n * via the `result` log event when `stage === 'complete'`. Carries the\n * same shape the synchronous mode would have returned inline.\n *\n * Capped at `TASK_RESULT_MAX_BYTES` at write time; over-cap payloads\n * are replaced with `{ truncated: true, originalBytes }` so the\n * cap is observable rather than silent.\n *\n * Once Stage 2 (this) ships, Stage 3+ (#3044 / #3045) migrate the\n * orchestrate / run_workflow / consensus_vote async-mode writers\n * from the Stage-1 sidecar (`mcp/jobs/job-result-store.ts`) to this\n * field, then the sidecar files become legacy that the next cleanup\n * sweep can remove.\n */\n result: z.unknown().optional(),\n /**\n * Cancellation marker (#3043 / epic #2631 Stage 2). Set by `cancel_job`\n * — the running tool checks for this at safe-point boundaries (between\n * steps, between waves) and aborts via the AbortSignal plumbing from\n * #3035 / #3038. Append-only by construction (the reducer ignores a\n * second cancellation event).\n */\n cancellation: TaskCancellationSchema.optional(),\n /**\n * Creation timestamp (#3090 / epic #2631). Set by the reducer to the\n * `init` entry's `ts` and never mutated thereafter — `updatedAt` advances\n * with each write, but `createdAt` is fixed. Job-result readers need the\n * original creation time; `updatedAt` alone can't supply it once any\n * transition has been recorded. Optional for backward-compat with\n * pre-#3090 logs (the reducer backfills it from the init entry).\n */\n createdAt: z.iso.datetime().optional(),\n updatedAt: z.iso.datetime(),\n});\nexport type StructuredTaskState = z.infer<typeof StructuredTaskStateSchema>;\n\n/** Log entry types for the append-only journal. */\nexport const StructuredTaskLogEntrySchema = z.discriminatedUnion('event', [\n z.object({\n event: z.literal('init'),\n ts: z.iso.datetime(),\n state: StructuredTaskStateSchema,\n }),\n z.object({\n event: z.literal('decision'),\n ts: z.iso.datetime(),\n decision: TaskDecisionSchema,\n }),\n z.object({\n event: z.literal('blocker'),\n ts: z.iso.datetime(),\n blocker: TaskBlockerSchema,\n }),\n z.object({\n event: z.literal('blocker_resolved'),\n ts: z.iso.datetime(),\n /** Index of the blocker in the state's blockers[] array. */\n blockerIndex: z.number().int().nonnegative(),\n resolvedAt: z.iso.datetime(),\n }),\n z.object({\n event: z.literal('stage'),\n ts: z.iso.datetime(),\n stage: TaskStageSchema,\n }),\n z.object({\n event: z.literal('position'),\n ts: z.iso.datetime(),\n position: TaskPositionSchema,\n }),\n // Magentic-One Task Ledger replacement event — the outer loop revises the\n // entire ledger atomically when replanning. Always replaces, never partial.\n z.object({\n event: z.literal('task_ledger'),\n ts: z.iso.datetime(),\n ledger: TaskLedgerSchema,\n }),\n // Magentic-One Progress Ledger append event — one self-reflection per step.\n z.object({\n event: z.literal('progress_ledger'),\n ts: z.iso.datetime(),\n entry: ProgressLedgerEntrySchema,\n }),\n // #3043 / epic #2631 Stage 2 — tool result payload set when stage flips\n // to 'complete'. Written by appendResult; replayed into state.result.\n // The payload itself is `unknown` because each tool's result shape is\n // its own; readers cast after a status check.\n z.object({\n event: z.literal('result'),\n ts: z.iso.datetime(),\n result: z.unknown(),\n }),\n // #3043 / epic #2631 Stage 2 — cancellation marker. Append-only: the\n // reducer ignores a second cancellation event so a malicious or buggy\n // double-cancel can't rewrite the requestedAt timestamp.\n z.object({\n event: z.literal('cancellation'),\n ts: z.iso.datetime(),\n cancellation: TaskCancellationSchema,\n }),\n]);\nexport type StructuredTaskLogEntry = z.infer<typeof StructuredTaskLogEntrySchema>;\n","/**\n * 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';\nimport { withAsyncTaskStateDispatch } from '../../context/structured-task-state.js';\n\n/**\n * Async-job-body runaway-guard (#3734). A backgrounded job body has NO MCP\n * request timeout (that is the point of async mode), so without a ceiling a\n * wedged `run` would hold its concurrency slot and pending record forever.\n * The `async-job-body` operation class (3600s) bounds it.\n *\n * It does NOT honour NEXUS_TIMEOUT_MULTIPLIER or the per-class override\n * UPWARDS, which this comment used to claim (#5785). The class is declared at\n * exactly `MCP_TIMEOUTS.maxMs`, and `describeClassGuard` re-clamps to that\n * ceiling, so for this class alone both knobs can only LOWER the guard —\n * `NEXUS_TIMEOUT_CLASS_ASYNC_JOB_BODY_MS=7200000` resolves to 3600000. That is\n * reported at startup by `findIneffectiveVars`, naming the variable and the\n * reason, so it is disclosed rather than silent; the comment was the last place\n * still asserting otherwise.\n *\n * Whether the MCP REQUEST ceiling should bound a body that by construction has\n * no MCP request is tracked separately in #5995. 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 * Opt out of the fail-closed result check (#4363), stating why.\n *\n * By default a `run` callback that RESOLVES a failure-shaped payload records\n * the job `failed` rather than `complete`. A handful of tools legitimately\n * resolve such a payload as their real answer — `consensus_vote` records the\n * partial vote set collected before a `cancel_job`, for instance. Those set\n * this field; the reason is logged whenever it actually suppresses a\n * detection, so an opted-out caller is a visible policy decision rather than\n * a silent kwarg.\n */\n readonly allowFailureShapedResult?: string | undefined;\n /**\n * Version stamped on every record this dispatch writes (#5008). Defaults to\n * the running server's `VERSION` — the build that runs the job, which is\n * what a later `get_job_result` from a different build needs to see. A\n * test injects a value that differs from `VERSION` to prove the stamp is\n * taken from this seam and not from the reader.\n */\n readonly producerVersion?: string | undefined;\n}\n\n/** A root envelope key whose value marks the payload as a failure (#4363). */\ninterface FailureShape {\n /** Which key tripped — recorded so the job record is debuggable. */\n readonly key: string;\n /** The payload's own message, when it carries one. */\n readonly detail: string | undefined;\n}\n\n/** Root envelope keys and the value that means \"this failed\". */\nconst FAILURE_KEYS: ReadonlyArray<{ key: string; failsWhen: boolean }> = [\n // toolStructuredError\n { key: 'isError', failsWhen: true },\n // handleConsensusVote and the other Result-shaped handlers\n { key: 'ok', failsWhen: false },\n // GraphPipelineResult / AdaptiveOrchestratorResult\n { key: 'success', failsWhen: false },\n];\n\n/** Root keys carrying a human-readable reason, in order of preference. */\nconst DETAIL_KEYS: readonly string[] = ['error', 'message'];\n\n/**\n * Render a failure shape for the job record. Names the key that tripped so the\n * record is debuggable, and carries the payload's own message when it has one —\n * a bare `failed` tells whoever polls the job nothing.\n */\nfunction describeFailureShape(failure: FailureShape): string {\n const suffix = failure.detail === undefined ? '' : `: ${failure.detail}`;\n return `Job result reported failure via '${failure.key}'${suffix}`;\n}\n\n/**\n * Detect a failure-shaped job payload, or null when the result is a success\n * (#4363).\n *\n * Inspects the payload's ROOT keys only. A deep scan would turn fail-open into\n * fail-wrong: a vote whose *decision* is `reject` and a pipeline summary listing\n * a stage it recovered from both carry a nested falsy `success`, and both are\n * successful jobs. Only the top-level envelope says whether the job itself\n * failed.\n *\n * Exported for tests.\n * @internal\n */\nexport function detectFailureShapedResult(result: unknown): FailureShape | null {\n if (typeof result !== 'object' || result === null) return null;\n const record = result as Record<string, unknown>;\n\n for (const { key, failsWhen } of FAILURE_KEYS) {\n if (record[key] === failsWhen) {\n const detailKey = DETAIL_KEYS.find((k) => typeof record[k] === 'string');\n return { key, detail: detailKey === undefined ? undefined : (record[detailKey] as string) };\n }\n }\n return null;\n}\n\n/**\n * Dispatch `run` as a detached background job and return a synchronous\n * envelope. Performs the EXACT sequence the three hand-rolled dispatchers\n * shared:\n *\n * 1. Resolve idempotency BEFORE acquiring a slot — a replay/collision must\n * not burn capacity a live caller could use.\n * 2. `tryAcquire(toolName)` — over-cap returns the `busy` envelope.\n * 3. `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 // #4972: record whether this tool can even receive a cancel. `run.length`\n // is the callback's declared arity, so >= 3 means it takes the `signal`\n // parameter. Structural, not behavioural — see `signalAccepted`'s doc.\n writeJobPending(jobId, params.toolName, params.run.length >= 3, params.producerVersion);\n if (params.idempotencyKey !== undefined && params.idempotencyKey !== '') {\n registerIdempotentJob({\n tool: params.toolName,\n idempotencyKey: params.idempotencyKey,\n inputs: params.input,\n jobId,\n });\n }\n\n // Step 4: detached background run with terminal recording + slot release.\n void runJobInBackground(jobId, params);\n\n // Step 5: synchronous pending envelope.\n return env.pending(jobId);\n}\n\n/**\n * Fire-and-forget background runner. Exported (awaitable) so integration\n * tests can drive the dispatch deterministically instead of racing the\n * detached promise.\n * @internal\n */\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 body = withAsyncTaskStateDispatch(jobId, () =>\n params.run(jobId, params.input, controller.signal)\n );\n const result = await Promise.race([body, guard.expired]);\n // #4363: `writeJobComplete` used to fire on ANY resolved value, so a\n // callback resolving a failure-shaped payload recorded `complete` and a\n // caller polling `get_job_result` read it as a success. Fail closed by\n // default — an opt-in predicate was rejected because \"caller forgot to\n // normalize\" would just become \"caller forgot to pass the predicate\".\n const failure = detectFailureShapedResult(result);\n if (failure !== null && params.allowFailureShapedResult === undefined) {\n writeJobFailed(jobId, params.toolName, describeFailureShape(failure), params.producerVersion);\n } else {\n if (failure !== null) {\n params.logger?.warn(\n `Recorded a failure-shaped ${params.toolName} result as complete (opted out)`,\n { jobId, key: failure.key, reason: params.allowFailureShapedResult }\n );\n }\n writeJobComplete(jobId, params.toolName, result, params.producerVersion);\n }\n } 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, params.producerVersion);\n } finally {\n guard.clear();\n unregisterJobAbort(jobId);\n release(params.toolName);\n }\n}\n"],"mappings":"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","names":["z","logger","logger","logger","logger","logger","resolve","logger","logger","z","z","path","logger","z","z","z","z","z","logger","err","logger","logger","logger","logger","logger","z","logger","logger","z","z","appendFileSync","existsSync","mkdirSync","readFileSync","dirname","isAbsolute","resolve","join","resolve","resolve","join","z","path","logger","existsSync","resolve","isAbsolute","resolved","mkdirSync","dirname","appendFileSync","readFileSync","appendFileSync","readFileSync","writeFileSync","existsSync","logger","existsSync","readFileSync","writeFileSync","appendFileSync","logger","defaultLogger","logger","defaultLogger","logger","logger","existsSync","readFileSync","writeFileSync","z","logger","z","path","writeFileSync","existsSync","readFileSync","err","existsSync","err","logger","createHash","existsSync","readFileSync","writeFileSync","z","logger","z","createHash","path","existsSync","writeFileSync","readFileSync","err","logger","logger","fs","z","logger","FILE_MODE","DIR_MODE","logger","logger","logger","err","randomUUID","logger","z"]}