nexus-agents 8.89.4 → 8.91.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{ast-rule-runner-NOWNF5QY.js → ast-rule-runner-SD665GB7.js} +3 -3
- package/dist/{child-mcp-config-UBKF4SOL.js → child-mcp-config-BG3QNALD.js} +2 -2
- package/dist/{chunk-SXS2YQUK.js → chunk-2N7XWZPW.js} +4 -4
- package/dist/{chunk-4W4S6OBP.js → chunk-4KMNLWAC.js} +4 -4
- package/dist/{chunk-DGW6C2PT.js → chunk-5GI6Z5VE.js} +5 -4
- package/dist/chunk-5GI6Z5VE.js.map +1 -0
- package/dist/{chunk-U2C6V65K.js → chunk-C3HMZJ3R.js} +2 -2
- package/dist/{chunk-YYVBEHM3.js → chunk-C6Q2NUIH.js} +4 -4
- package/dist/{chunk-NRSAOTT7.js → chunk-ERTDJU7Y.js} +26 -12
- package/dist/chunk-ERTDJU7Y.js.map +1 -0
- package/dist/{chunk-P2RI4DGX.js → chunk-F2H3MCEV.js} +31 -8
- package/dist/{chunk-P2RI4DGX.js.map → chunk-F2H3MCEV.js.map} +1 -1
- package/dist/{chunk-XM2GVJPE.js → chunk-FPX55ON5.js} +7 -7
- package/dist/{chunk-6YQ55DOE.js → chunk-HBXAYO3C.js} +5 -5
- package/dist/{chunk-H7PL2D5A.js → chunk-HD3FTCV4.js} +5 -5
- package/dist/{chunk-6ZPHMRJQ.js → chunk-HPE3UQLT.js} +3 -3
- package/dist/{chunk-GPEGBNGB.js → chunk-HUCILYVO.js} +2 -2
- package/dist/{chunk-RQBI56JN.js → chunk-IDASIJE6.js} +2 -2
- package/dist/{chunk-3E4BZR3V.js → chunk-JWHIFEI3.js} +2 -2
- package/dist/{chunk-UR2KFP6P.js → chunk-KCWEMSU2.js} +2 -2
- package/dist/{chunk-SFHIXQGK.js → chunk-NFP7WQ22.js} +2 -2
- package/dist/{chunk-K6IVHUEK.js → chunk-NMJDOOYZ.js} +3 -3
- package/dist/{chunk-YBW45NIZ.js → chunk-NMZ5ZKEO.js} +2 -2
- package/dist/{chunk-YT7EP2B6.js → chunk-O3MSZUQM.js} +2 -2
- package/dist/{chunk-5JZ635RM.js → chunk-OJM75DDY.js} +3 -3
- package/dist/{chunk-GLG667IV.js → chunk-QCWY3GTZ.js} +2 -2
- package/dist/{chunk-YG3UYPKL.js → chunk-RMDG3OFS.js} +2 -2
- package/dist/{chunk-F3PIVN3B.js → chunk-S6FK47MZ.js} +2 -2
- package/dist/{chunk-LBYA22G5.js → chunk-SJH5U5XT.js} +10 -10
- package/dist/{chunk-2C5ABWLK.js → chunk-SMKBETIX.js} +2 -2
- package/dist/{chunk-NBVYSGSS.js → chunk-UWYNIMDF.js} +99 -63
- package/dist/{chunk-NBVYSGSS.js.map → chunk-UWYNIMDF.js.map} +1 -1
- package/dist/{chunk-5XCRXV43.js → chunk-VI5TF3KF.js} +2 -2
- package/dist/{chunk-P5ND7MWI.js → chunk-VIDSDHSQ.js} +8 -8
- package/dist/{chunk-LVL6WCWK.js → chunk-VLBXRQIA.js} +2 -2
- package/dist/{chunk-PEN5XFMP.js → chunk-WDGEJIWW.js} +2 -2
- package/dist/{chunk-XS3IJG4V.js → chunk-XT7VZSS3.js} +5 -3
- package/dist/chunk-XT7VZSS3.js.map +1 -0
- package/dist/{chunk-R57JPKHJ.js → chunk-ZP7LYABJ.js} +2 -2
- package/dist/{chunk-TFZDHQ45.js → chunk-ZVHJMROO.js} +4 -4
- package/dist/{cli-circuit-breaker-IFVKXCHQ.js → cli-circuit-breaker-GOH6U32K.js} +3 -3
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +88 -84
- package/dist/cli.js.map +1 -1
- package/dist/{composite-router-7LFS4CMF.js → composite-router-RMEHBA3J.js} +2 -2
- package/dist/{consensus-vote-SA2KVDQA.js → consensus-vote-BO7S3XSQ.js} +16 -16
- package/dist/{consensus-vote-types-DhmacUE7.d.ts → consensus-vote-types-BdptpuQK.d.ts} +6 -0
- package/dist/{context-retriever-V7OWZW7R.js → context-retriever-TWAN22PW.js} +8 -8
- package/dist/{doctor-deep-GJPTXS2N.js → doctor-deep-HRZ77NYS.js} +3 -3
- package/dist/{doctor-live-ET5O7O2D.js → doctor-live-VGOABDSJ.js} +10 -10
- package/dist/{expert-bridge-G656VGZG.js → expert-bridge-PFR7ZNWK.js} +4 -4
- package/dist/{factory-BQBFECEV.js → factory-DJPYG3WR.js} +9 -9
- package/dist/{factory-N34PTEMW.js → factory-JCVKAI7P.js} +5 -5
- package/dist/{improvement-review-YIXDCEX4.js → improvement-review-FXXRLLGX.js} +5 -5
- package/dist/index.d.ts +22 -2
- package/dist/index.js +30 -30
- package/dist/{init-opencode-33EU3PD6.js → init-opencode-KTIHOYIU.js} +5 -5
- package/dist/issue-triage-OCTW33O3.js +16 -0
- package/dist/{pr-reviewer-helpers-ZDAJARQ7.js → pr-reviewer-helpers-V67TZHNM.js} +4 -4
- package/dist/{registry-command-AB7KP7DK.js → registry-command-43IZQOAP.js} +2 -2
- package/dist/{repo-security-plan-YV3ZFKGO.js → repo-security-plan-OXMSNBOS.js} +3 -3
- package/dist/{research-helpers-synthesize-EOHUBGH3.js → research-helpers-synthesize-IBBRMZEY.js} +4 -4
- package/dist/{routing-memory-34JWGSAI.js → routing-memory-S3H3D6Z2.js} +2 -2
- package/dist/{session-memory-QGIJCM7P.js → session-memory-UO42CU2H.js} +3 -3
- package/dist/{setup-config-3KBMBPCN.js → setup-config-RGTKEVTD.js} +3 -3
- package/dist/{setup-custom-api-652FK232.js → setup-custom-api-PQ3PR2RR.js} +4 -4
- package/dist/setup-data-dir-BGG6ETH6.js +32 -0
- package/dist/{tool-memory-SPPCBLKQ.js → tool-memory-ZMLCOQH6.js} +5 -5
- package/dist/{unified-registry-ZOLSOVYN.js → unified-registry-HWBSGSOM.js} +10 -10
- package/dist/{weather-report-OHHDUNX3.js → weather-report-MZCA7Y6K.js} +2 -2
- package/package.json +1 -1
- package/dist/chunk-DGW6C2PT.js.map +0 -1
- package/dist/chunk-NRSAOTT7.js.map +0 -1
- package/dist/chunk-XS3IJG4V.js.map +0 -1
- package/dist/issue-triage-URFEVDIX.js +0 -16
- package/dist/setup-data-dir-XJMN4ALO.js +0 -32
- /package/dist/{ast-rule-runner-NOWNF5QY.js.map → ast-rule-runner-SD665GB7.js.map} +0 -0
- /package/dist/{child-mcp-config-UBKF4SOL.js.map → child-mcp-config-BG3QNALD.js.map} +0 -0
- /package/dist/{chunk-SXS2YQUK.js.map → chunk-2N7XWZPW.js.map} +0 -0
- /package/dist/{chunk-4W4S6OBP.js.map → chunk-4KMNLWAC.js.map} +0 -0
- /package/dist/{chunk-U2C6V65K.js.map → chunk-C3HMZJ3R.js.map} +0 -0
- /package/dist/{chunk-YYVBEHM3.js.map → chunk-C6Q2NUIH.js.map} +0 -0
- /package/dist/{chunk-XM2GVJPE.js.map → chunk-FPX55ON5.js.map} +0 -0
- /package/dist/{chunk-6YQ55DOE.js.map → chunk-HBXAYO3C.js.map} +0 -0
- /package/dist/{chunk-H7PL2D5A.js.map → chunk-HD3FTCV4.js.map} +0 -0
- /package/dist/{chunk-6ZPHMRJQ.js.map → chunk-HPE3UQLT.js.map} +0 -0
- /package/dist/{chunk-GPEGBNGB.js.map → chunk-HUCILYVO.js.map} +0 -0
- /package/dist/{chunk-RQBI56JN.js.map → chunk-IDASIJE6.js.map} +0 -0
- /package/dist/{chunk-3E4BZR3V.js.map → chunk-JWHIFEI3.js.map} +0 -0
- /package/dist/{chunk-UR2KFP6P.js.map → chunk-KCWEMSU2.js.map} +0 -0
- /package/dist/{chunk-SFHIXQGK.js.map → chunk-NFP7WQ22.js.map} +0 -0
- /package/dist/{chunk-K6IVHUEK.js.map → chunk-NMJDOOYZ.js.map} +0 -0
- /package/dist/{chunk-YBW45NIZ.js.map → chunk-NMZ5ZKEO.js.map} +0 -0
- /package/dist/{chunk-YT7EP2B6.js.map → chunk-O3MSZUQM.js.map} +0 -0
- /package/dist/{chunk-5JZ635RM.js.map → chunk-OJM75DDY.js.map} +0 -0
- /package/dist/{chunk-GLG667IV.js.map → chunk-QCWY3GTZ.js.map} +0 -0
- /package/dist/{chunk-YG3UYPKL.js.map → chunk-RMDG3OFS.js.map} +0 -0
- /package/dist/{chunk-F3PIVN3B.js.map → chunk-S6FK47MZ.js.map} +0 -0
- /package/dist/{chunk-LBYA22G5.js.map → chunk-SJH5U5XT.js.map} +0 -0
- /package/dist/{chunk-2C5ABWLK.js.map → chunk-SMKBETIX.js.map} +0 -0
- /package/dist/{chunk-5XCRXV43.js.map → chunk-VI5TF3KF.js.map} +0 -0
- /package/dist/{chunk-P5ND7MWI.js.map → chunk-VIDSDHSQ.js.map} +0 -0
- /package/dist/{chunk-LVL6WCWK.js.map → chunk-VLBXRQIA.js.map} +0 -0
- /package/dist/{chunk-PEN5XFMP.js.map → chunk-WDGEJIWW.js.map} +0 -0
- /package/dist/{chunk-R57JPKHJ.js.map → chunk-ZP7LYABJ.js.map} +0 -0
- /package/dist/{chunk-TFZDHQ45.js.map → chunk-ZVHJMROO.js.map} +0 -0
- /package/dist/{cli-circuit-breaker-IFVKXCHQ.js.map → cli-circuit-breaker-GOH6U32K.js.map} +0 -0
- /package/dist/{composite-router-7LFS4CMF.js.map → composite-router-RMEHBA3J.js.map} +0 -0
- /package/dist/{consensus-vote-SA2KVDQA.js.map → consensus-vote-BO7S3XSQ.js.map} +0 -0
- /package/dist/{context-retriever-V7OWZW7R.js.map → context-retriever-TWAN22PW.js.map} +0 -0
- /package/dist/{doctor-deep-GJPTXS2N.js.map → doctor-deep-HRZ77NYS.js.map} +0 -0
- /package/dist/{doctor-live-ET5O7O2D.js.map → doctor-live-VGOABDSJ.js.map} +0 -0
- /package/dist/{expert-bridge-G656VGZG.js.map → expert-bridge-PFR7ZNWK.js.map} +0 -0
- /package/dist/{factory-BQBFECEV.js.map → factory-DJPYG3WR.js.map} +0 -0
- /package/dist/{factory-N34PTEMW.js.map → factory-JCVKAI7P.js.map} +0 -0
- /package/dist/{improvement-review-YIXDCEX4.js.map → improvement-review-FXXRLLGX.js.map} +0 -0
- /package/dist/{init-opencode-33EU3PD6.js.map → init-opencode-KTIHOYIU.js.map} +0 -0
- /package/dist/{issue-triage-URFEVDIX.js.map → issue-triage-OCTW33O3.js.map} +0 -0
- /package/dist/{pr-reviewer-helpers-ZDAJARQ7.js.map → pr-reviewer-helpers-V67TZHNM.js.map} +0 -0
- /package/dist/{registry-command-AB7KP7DK.js.map → registry-command-43IZQOAP.js.map} +0 -0
- /package/dist/{repo-security-plan-YV3ZFKGO.js.map → repo-security-plan-OXMSNBOS.js.map} +0 -0
- /package/dist/{research-helpers-synthesize-EOHUBGH3.js.map → research-helpers-synthesize-IBBRMZEY.js.map} +0 -0
- /package/dist/{routing-memory-34JWGSAI.js.map → routing-memory-S3H3D6Z2.js.map} +0 -0
- /package/dist/{session-memory-QGIJCM7P.js.map → session-memory-UO42CU2H.js.map} +0 -0
- /package/dist/{setup-config-3KBMBPCN.js.map → setup-config-RGTKEVTD.js.map} +0 -0
- /package/dist/{setup-custom-api-652FK232.js.map → setup-custom-api-PQ3PR2RR.js.map} +0 -0
- /package/dist/{setup-data-dir-XJMN4ALO.js.map → setup-data-dir-BGG6ETH6.js.map} +0 -0
- /package/dist/{tool-memory-SPPCBLKQ.js.map → tool-memory-ZMLCOQH6.js.map} +0 -0
- /package/dist/{unified-registry-ZOLSOVYN.js.map → unified-registry-HWBSGSOM.js.map} +0 -0
- /package/dist/{weather-report-OHHDUNX3.js.map → weather-report-MZCA7Y6K.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/mcp/tools/consensus-vote.ts","../src/mcp/tools/async-dispatch-input.ts","../src/cli/voter-roles.ts","../src/consensus/decision/strategy.ts","../src/cli/voter-model-overrides.ts","../src/cli/panel-independence.ts","../src/audit/vote-record.ts","../src/audit/reasoning-commitment.ts","../src/audit/redaction-record.ts","../src/audit/record-signature-schema.ts","../src/cli/voter-unverifiable.ts","../src/cli/voter-retry.ts","../src/cli-adapters/codex-limits.ts","../src/cli/voter-adapter-resolve.ts","../src/cli/voter-fallback.ts","../src/cli/voter-prompts.ts","../src/cli/voter-response.ts","../src/consensus/option-tally.ts","../src/cli/voter-response-text.ts","../src/cli/voter-execution.ts","../src/cli/voter-agents-deadline.ts","../src/cli/panel-workspace.ts","../src/cli/voter-agents.ts","../src/cli/voter-project.ts","../src/mcp/tools/consensus-vote-option-gate.ts","../src/consensus/types-voting-protocol.ts","../src/consensus/types-weighted-voting.ts","../src/consensus/higher-order-types.ts","../src/consensus/higher-order-helpers.ts","../src/consensus/higher-order-voting.ts","../src/consensus/decision/verdict.ts","../src/consensus/strategies.ts","../src/consensus/result-builder.ts","../src/consensus/helpers.ts","../src/consensus/incremental-quorum.ts","../src/consensus/engine.ts","../src/consensus/quorum-validator.ts","../src/consensus/voting-protocol-helpers.ts","../src/consensus/voting-protocol.ts","../src/agents/collaboration/byzantine-events.ts","../src/consensus/weighted-voting-helpers.ts","../src/consensus/weighted-voting.ts","../src/consensus/subset-independence.ts","../src/consensus/correlation-helpers.ts","../src/consensus/correlation-model-partitions.ts","../src/consensus/correlation-tracker.ts","../src/consensus/correlation-persistence.ts","../src/consensus/correlation-persistence-records.ts","../src/mcp/tools/consensus-vote-types.ts","../src/cli/vote-diversity.ts","../src/mcp/tools/consensus-vote-option-detection.ts","../src/mcp/tools/consensus-vote-error-policy.ts","../src/utils/bounded-artifact.ts","../src/mcp/tools/consensus-vote-contrarian.ts","../src/audit/vote-record-store.ts","../src/audit/ledger-append.ts","../src/audit/source-checkout-guard.ts","../src/mcp/tools/consensus-vote-recording.ts","../src/utils/file-lock.ts","../src/orchestration/outcomes/outcome-store-persistence.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-idempotency.ts","../src/mcp/jobs/job-result-candidates.ts","../src/mcp/jobs/job-failure-detail.ts","../src/mcp/jobs/job-abort-registry.ts","../src/context/structured-task-state.ts","../src/context/structured-task-state-types.ts","../src/mcp/jobs/job-heartbeat-bridge.ts","../src/mcp/jobs/job-concurrency.ts","../src/mcp/jobs/run-as-job.ts"],"sourcesContent":["/* eslint-disable max-lines -- 856 lines as eslint counts them, above the 600 ceiling (.rules/governance.md); one consensus_vote tool surface: strategy resolution, cascade, option gate and async dispatch; split tracked in #6148 */\n/**\n * nexus-agents/mcp - Consensus Vote Tool\n * @module mcp/tools/consensus-vote\n */\n\nimport { z } from 'zod';\nimport { deprecatedModeWarning, resolveDispatch, withWarnings } from './async-dispatch-input.js';\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { ILogger } from '../../core/index.js';\nimport {\n createLogger,\n getErrorMessage,\n getTimeProvider,\n getRandomProvider,\n formatZodError,\n} from '../../core/index.js';\nimport type { IMcpNotifier } from '../mcp-notifier.js';\nimport { createMcpNotifier, NOOP_NOTIFIER, withProgressHeartbeat } from '../mcp-notifier.js';\nimport {\n wrapToolWithTimeout,\n toSdkCallbackWithTimeoutCheck,\n getToolTimeout,\n} from '../middleware/tool-wrapper.js';\nimport { createSecureHandler, type HandlerContext } from '../middleware/secure-handler.js';\nimport {\n 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/decision/thresholds.js';\nimport type { VoterRole, AgentVoteResult } from '../../cli/vote-types.js';\nimport { getVoterRoles } from '../../cli/voter-roles.js';\nimport {\n getDefaultErrorPolicy,\n resolveStrategy,\n strategyToAlgorithm,\n} from '../../consensus/decision/strategy.js';\nimport { collectRealVotes } from '../../cli/voter-agents.js';\nimport { resolveAndLogVoterProject, type ResolvedVoterProject } from '../../cli/voter-project.js';\nimport { resolvePanelWorkspace } from '../../cli/panel-workspace.js';\nimport { evaluateOptionGate, optionThresholdFor } from './consensus-vote-option-gate.js';\nimport { createConsensusEngine } from '../../consensus/engine.js';\nimport type {\n CorrelationRecordContext,\n HigherOrderVotingResult,\n ICorrelationTracker,\n} from '../../consensus/higher-order-types.js';\nimport { HigherOrderVotingStrategy } from '../../consensus/index.js';\nimport {\n createPersistentCorrelationTracker,\n createPersistedProposal,\n saveCorrelationData,\n} from '../../consensus/correlation-persistence.js';\nimport {\n VotingStrategySchema,\n VoteDecisionStatusSchema,\n ContrarianCheckStatusSchema,\n VoteThresholdSchema,\n ConsensusVoteInputSchema,\n buildResponse,\n isHigherOrderStrategy,\n toRecordDecision,\n} from './consensus-vote-types.js';\nimport { resolveVoteDecision } from '../../consensus/decision/verdict.js';\nimport { applyErrorPolicy } from './consensus-vote-error-policy.js';\nimport { maybeEscalateContrarian } from './consensus-vote-contrarian.js';\nimport {\n recordVoteSuccess,\n recordVoteError,\n recordAuthenticVote,\n} from './consensus-vote-recording.js';\nimport type { VoteRecordPersistOutcome } from './consensus-vote-recording.js';\nimport type { VoteRecordPrBinding } from '../../audit/vote-record.js';\nimport { recordDecisionCost } from './decision-cost-recording.js';\nimport { detectUndeclaredOptions } from './consensus-vote-option-detection.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 ErrorPolicy,\n ExtendedVotingResult,\n} from './consensus-vote-types.js';\n\nexport type {\n VotingStrategy,\n ConsensusVoteInput,\n ConsensusVoteResponse,\n ContrarianCheckStatus,\n AgentVoteSummary,\n VoteDecisionStatus,\n HigherOrderMetadata,\n ExtendedVotingResult,\n} from './consensus-vote-types.js';\nexport { VotingStrategySchema, ConsensusVoteInputSchema } from './consensus-vote-types.js';\n\n// --- Correlation Tracker Singleton ---\n//\n// Lifecycle & memory model (documented per #3169):\n// * SCOPE: one process-wide, lazily-created instance shared by every\n// `consensus_vote` call. It accumulates cross-proposal voter agreement so\n// the higher_order strategy can down-weight correlated (redundant) voters.\n// One shared tracker is intentional — correlation signal is only useful\n// pooled across proposals.\n// * PERSISTENCE: backed by `createPersistentCorrelationTracker()`, which\n// hydrates from / appends to the on-disk correlation store, so the signal\n// survives restarts (the in-memory map is a hot cache over that store).\n// * MEMORY BOUND: NOT unbounded. The underlying `CorrelationTracker` is\n// FIFO-bounded by `maxProposals` / `maxObservationsPerAgent` (#521) —\n// oldest proposals are evicted once the cap is hit (eviction is logged at\n// debug in `correlation-tracker.ts`, so memory pressure is observable).\n// * RESET: `resetCorrelationTracker()` drops the instance; the next\n// `getOrCreateCorrelationTracker()` rebuilds it (re-hydrating from disk).\n// Test-isolation only. There is intentionally no per-milestone \"reset\n// between cycles\" coordinator API — eviction already bounds growth, and\n// clearing history mid-run would discard the signal the strategy needs.\nlet persistentCorrelationTracker: ICorrelationTracker | undefined;\n\n/**\n * Gets or creates the process-wide persistent CorrelationTracker (#517).\n * See the lifecycle / memory-bound / reset notes above the declaration (#3169).\n */\nfunction getOrCreateCorrelationTracker(): ICorrelationTracker {\n persistentCorrelationTracker ??= createPersistentCorrelationTracker();\n return persistentCorrelationTracker;\n}\n\n/**\n * Drops the singleton so the next {@link getOrCreateCorrelationTracker} rebuilds\n * it (re-hydrating from the persistent store). Test-isolation only. @internal\n */\nexport function resetCorrelationTracker(): void {\n persistentCorrelationTracker = undefined;\n}\n\n// --- Dependencies ---\nexport interface ConsensusVoteDeps extends BaseMcpToolDeps {\n /** MCP notifier for client-visible logging (Issue #974) */\n notifier?: IMcpNotifier | undefined;\n /**\n * In-process gateway model adapters (#4040). When the server has a configured\n * OpenAI-compatible gateway, voters route through these HTTP adapters instead\n * of shelling out to a CLI subprocess — no per-subprocess key forwarding, and\n * the nested-spawn deadlock (#4033) cannot occur. Omitted ⇒ CLI voter path.\n */\n gatewayAdapters?: readonly IModelAdapter[] | undefined;\n}\n\n// --- Strategy Resolution ---\n// `resolveStrategy`, `strategyToAlgorithm` and `getVoterRoles` moved to the\n// governed decision modules (#6000 step 1): `consensus/decision/strategy.ts`\n// and `cli/voter-roles.ts`. They were module-private here, so nothing is\n// re-exported.\n\n// --- Voting Execution ---\n/** Creates a synthetic ConsensusResult when all votes are errors (Issue #815). */\nfunction createEmptyConsensusResult(\n proposal: string,\n algorithm: ConsensusAlgorithm\n): ConsensusResult {\n const now = new Date().toISOString();\n return {\n proposalId: 'no-valid-votes',\n proposal: { title: 'MCP Consensus Vote', description: proposal, algorithm },\n outcome: 'rejected',\n votes: new Map<string, Vote>(),\n voteCounts: { approve: 0, reject: 0, abstain: 0, total: 0 },\n approvalPercentage: 0,\n quorumReached: false,\n startedAt: now,\n closedAt: now,\n durationMs: 0,\n };\n}\n\n/**\n * Creates a synthetic ConsensusResult for an error-policy short-circuit\n * (#2630). Reused for both the hard floor (errors > 50%) and `fail_closed`.\n * Stamps the reason on the proposal title and, since #3124, reports the TRUE\n * vote breakdown of the responding (non-error) voters instead of all-zeros —\n * the internal `outcome` stays `rejected` (the policy failed closed), but the\n * counts and `approvalPercentage` are honest (e.g. 6 approvals + 1 error →\n * approve:6, 100%). As of #4053 the user-facing `decision` for this short-circuit\n * is `no_quorum` (not `rejected`) — too many voters errored to reach a valid\n * consensus, which is distinct from the panel rejecting the proposal.\n */\nexport function createPolicyFailedResult(\n proposal: string,\n algorithm: ConsensusAlgorithm,\n reason: string,\n votes: readonly AgentVoteResult[]\n): ConsensusResult {\n const now = new Date().toISOString();\n const voteMap = new Map<string, Vote>();\n let approve = 0;\n let reject = 0;\n let abstain = 0;\n for (const v of votes) {\n if (v.source === 'error') continue; // errors surface separately, not as a decision\n voteMap.set(v.role, v.vote);\n if (v.vote.decision === 'approve') approve++;\n else if (v.vote.decision === 'reject') reject++;\n else abstain++;\n }\n const responding = approve + reject + abstain;\n return {\n proposalId: 'error-policy-short-circuit',\n proposal: { title: `MCP Consensus Vote — ${reason}`, description: proposal, algorithm },\n outcome: 'rejected',\n votes: voteMap,\n voteCounts: { approve, reject, abstain, total: responding },\n approvalPercentage: responding > 0 ? (approve / responding) * 100 : 0,\n quorumReached: false,\n startedAt: now,\n closedAt: now,\n durationMs: 0,\n };\n}\n\n/** Thresholds per algorithm for cascade detection. */\nconst CASCADE_THRESHOLDS: Record<string, number> = {\n majority: 0.5,\n supermajority: SUPERMAJORITY_THRESHOLD,\n unanimous: 1.0,\n};\n\n/** Detect if vote outcome is mathematically decided (#1765). */\nfunction detectEarlyCascade(\n algorithm: string,\n approvals: number,\n rejections: number,\n total: number\n): { decided: boolean; reason: string } {\n const threshold = CASCADE_THRESHOLDS[algorithm] ?? 0.5;\n if (total === 0) return { decided: false, reason: '' };\n\n // Unanimous: any rejection decides\n if (algorithm === 'unanimous' && rejections > 0) {\n return { decided: true, reason: `Unanimous rejected: ${String(rejections)} rejection(s)` };\n }\n // Approval locked: even if all remaining vote reject, approval holds\n if (approvals / total > threshold) {\n return {\n decided: true,\n reason: `Approval locked: ${String(approvals)}/${String(total)} > ${String(threshold)}`,\n };\n }\n // Rejection locked: even if all remaining vote approve, rejection holds\n const remaining = total - approvals - rejections;\n if ((approvals + remaining) / total < threshold) {\n return {\n decided: true,\n reason: `Rejection locked: max possible ${String(approvals + remaining)}/${String(total)} < ${String(threshold)}`,\n };\n }\n return { decided: false, reason: '' };\n}\n\n/**\n * Run the consensus engine over already-policy-applied votes.\n *\n * Callers MUST pass `engineVotes` produced by `applyErrorPolicy` (#2630)\n * — under `reduce_denominator` that means errors are already filtered;\n * under `count_as_abstain` errors have been converted to abstain\n * decisions but kept in the array. This function does no further\n * filtering on `source`.\n */\nasync function processVotesThroughEngine(\n engineVotes: readonly AgentVoteResult[],\n proposal: string,\n algorithm: ConsensusAlgorithm\n): Promise<ConsensusResult> {\n if (engineVotes.length === 0) return createEmptyConsensusResult(proposal, algorithm);\n\n const engine = createConsensusEngine();\n const engineProposal: Proposal = {\n title: 'MCP Consensus Vote',\n description: proposal,\n algorithm,\n };\n const proposalResult = await engine.propose(engineProposal);\n if (!proposalResult.ok)\n throw new Error(`Failed to create proposal: ${proposalResult.error.message}`, {\n cause: proposalResult.error,\n });\n\n const proposalId = proposalResult.value;\n for (const { role, vote } of engineVotes) await engine.vote(proposalId, role, vote);\n\n const resultRes = await engine.close(proposalId);\n if (!resultRes.ok)\n throw new Error(`Failed to close proposal: ${resultRes.error.message}`, {\n cause: resultRes.error,\n });\n return resultRes.value;\n}\n\nfunction runHigherOrderVoting(\n strategy: VotingStrategy,\n voteMap: Map<string, Vote>,\n logger: ILogger,\n context: CorrelationRecordContext\n): HigherOrderVotingResult | undefined {\n if (!isHigherOrderStrategy(strategy)) return undefined;\n const hovStrategy = new HigherOrderVotingStrategy();\n const tracker = getOrCreateCorrelationTracker();\n tracker.setCurrentModelPins?.(context.modelPins);\n const result = hovStrategy.aggregate(voteMap, tracker);\n logger.info('Higher-Order Voting complete', {\n method: result.method,\n decision: result.decision,\n posteriorApproval: result.posteriorApproval.toFixed(3),\n });\n return result;\n}\n\nfunction buildCorrelationContext(votes: readonly AgentVoteResult[]): CorrelationRecordContext {\n const modelPins = new Map<string, string>();\n const observedModels = new Map<string, string>();\n for (const vote of votes) {\n if (vote.pinnedModel !== undefined) modelPins.set(vote.role, vote.pinnedModel);\n if (vote.model !== undefined) observedModels.set(vote.role, vote.model);\n }\n return { modelPins, observedModels };\n}\n\nfunction recordVotesToTracker(\n votes: readonly AgentVoteResult[],\n outcome: 'approved' | 'rejected',\n logger: ILogger\n): void {\n // #3170: record the REAL (LLM) votes even when the panel is mixed-source,\n // rather than dropping ALL correlation data because one voter simulated/errored.\n // Recording the accurate LLM-only subset beats leaving the matrix permanently stale.\n const llmVotes = votes.filter((v) => v.source === 'llm');\n if (llmVotes.length < votes.length) {\n logger.warn('Recording only LLM votes to correlation tracker; excluding non-LLM votes', {\n recorded: llmVotes.length,\n excluded: votes.length - llmVotes.length,\n });\n }\n if (llmVotes.length === 0) return; // nothing real to record\n const llmVoteMap = new Map<string, Vote>();\n for (const v of llmVotes) llmVoteMap.set(v.role, v.vote);\n const context = buildCorrelationContext(llmVotes);\n\n const tracker = getOrCreateCorrelationTracker();\n const id = `consensus-${String(getTimeProvider().now())}-${getRandomProvider().random().toString(36).slice(2, 9)}`;\n tracker.recordProposalVotes(id, llmVoteMap, outcome, context);\n logger.debug('Recorded votes to tracker', { proposalId: id, outcome });\n\n try {\n const persisted = createPersistedProposal(id, llmVoteMap, outcome, context);\n const saveResult = saveCorrelationData([persisted]);\n if (!saveResult.ok) {\n logger.warn('Failed to persist correlation data', { error: saveResult.error.message });\n }\n } catch (error: unknown) {\n const message = getErrorMessage(error);\n logger.warn('Error persisting correlation data', { error: message });\n }\n}\n\n/** Process votes with cascade detection — extracted for max-lines-per-function (#1765). */\n/**\n * Run the engine + cascade-detection + higher-order voting against\n * already-policy-applied votes (#2630).\n *\n * Callers MUST pass `engineVotes` produced by `applyErrorPolicy` — no\n * filtering on `source` happens inside this function. Cascade-detection\n * counts and the higher-order voteMap are both built directly from\n * `engineVotes`.\n */\nasync function processVotesWithCascade(\n engineVotes: readonly AgentVoteResult[],\n opts: {\n totalRoles: number;\n proposal: string;\n algorithm: ConsensusAlgorithm;\n strategy: VotingStrategy;\n log: ILogger;\n }\n): Promise<{\n engineResult: ConsensusResult;\n voteMap: Map<string, Vote>;\n higherOrderResult: ReturnType<typeof runHigherOrderVoting>;\n outcome: 'approved' | 'rejected';\n cascaded: boolean;\n}> {\n const approvals = engineVotes.filter((v) => v.vote.decision === 'approve').length;\n const rejections = engineVotes.filter((v) => v.vote.decision === 'reject').length;\n const cascadeInfo = detectEarlyCascade(opts.algorithm, approvals, rejections, opts.totalRoles);\n\n if (cascadeInfo.decided) {\n opts.log.info('Vote cascade: outcome decided early', {\n approvals,\n rejections,\n total: opts.totalRoles,\n reason: cascadeInfo.reason,\n });\n }\n\n const engineResult = await processVotesThroughEngine(engineVotes, opts.proposal, opts.algorithm);\n const voteMap = new Map<string, Vote>();\n for (const { role, vote } of engineVotes) voteMap.set(role, vote);\n\n const higherOrderResult = cascadeInfo.decided\n ? undefined\n : runHigherOrderVoting(opts.strategy, voteMap, opts.log, buildCorrelationContext(engineVotes));\n const outcome: 'approved' | 'rejected' =\n engineResult.outcome === 'approved' ? 'approved' : 'rejected';\n\n return { engineResult, voteMap, higherOrderResult, outcome, cascaded: cascadeInfo.decided };\n}\n\n/** Execute a consensus vote with full strategy support. Exported for pipeline DRY (#1694). */\n/**\n * Build a short-circuit result for the error-policy gate (#2630). Called\n * when the hard floor (>50% errors) trips or `fail_closed` matches.\n * Logs the warning and returns the synthetic `ExtendedVotingResult` that\n * `executeVoting` propagates to the response builder.\n */\nfunction buildPolicyShortCircuitResult(args: {\n input: ConsensusVoteInput;\n strategy: VotingStrategy;\n algorithm: ConsensusAlgorithm;\n roles: readonly VoterRole[];\n votes: readonly AgentVoteResult[];\n /** The RESOLVED policy (`executeVotingInner` applied the default before calling). */\n errorPolicy: ErrorPolicy;\n reason: string;\n startTime: number;\n logger: ILogger;\n}): ExtendedVotingResult {\n args.logger.warn('Consensus vote short-circuited by error policy', {\n errorPolicy: args.errorPolicy,\n reason: args.reason,\n });\n const totalTimeMs = getTimeProvider().now() - args.startTime;\n return {\n proposal: args.input.proposal,\n threshold: args.algorithm,\n result: createPolicyFailedResult(args.input.proposal, args.algorithm, args.reason, args.votes),\n votes: args.votes,\n totalTimeMs,\n simulateVotes: args.input.simulateVotes,\n strategy: args.strategy,\n // #4132: thread the requested panel shape so the absolute_quorum predicate\n // in buildResponse has PANEL_SIZE + contrarian-presence even on a short-circuit.\n panelSize: args.roles.length,\n contrarianRequested: args.roles.includes('catfish'),\n // #6111: the short-circuit returns before the escalation gate, so the\n // quick-mode contrarian check never ran.\n contrarianCheck: 'skipped',\n // #3124: surface WHY a high-approval result is still 'rejected' so callers\n // don't mistake a fail-closed policy short-circuit for a genuine rejection.\n policyReason: args.reason,\n // #6211: the policy that short-circuited is the policy the record states.\n errorPolicy: args.errorPolicy,\n };\n}\n\n/*\n * Top-level voting flow: vote collection → error-policy gate → engine +\n * cascade → contrarian escalation → finalize. Further extraction\n * obscures control flow more than it helps; helpers already extracted\n * are applyErrorPolicy, buildPolicyShortCircuitResult,\n * maybeEscalateContrarian, finalizeVotingResult.\n */\nexport async function executeVoting(\n input: ConsensusVoteInput,\n logger: ILogger,\n opts?: {\n voteTimeoutMs?: number;\n /** CLI ratification checkout, retained through escalation. */\n workspace?: string | undefined;\n workspaceSha?: string | undefined;\n gatewayAdapters?: readonly IModelAdapter[] | undefined;\n /** #5393: stops LAUNCHING un-started voters when `cancel_job` fires. */\n signal?: AbortSignal | undefined;\n /** #6110: set only by the escalation re-vote, which reuses the outer resolution. */\n project?: ResolvedVoterProject | undefined;\n /**\n * Per-seat progress callback (#6162): the async-job heartbeat, fired as\n * each seat settles. Retained through the escalation re-vote.\n */\n onVoteCollected?: ((vote: AgentVoteResult) => void) | undefined;\n }\n): Promise<ExtendedVotingResult> {\n // #6110: resolve the target project ONCE per vote (the escalation re-vote\n // inherits it through opts) and stamp it on the result next to `decision`.\n const project = opts?.project ?? resolveAndLogVoterProject(input.project, logger);\n // #6258: the directory every seat is handed, resolved once and stamped on the\n // live result, so an `unverifiable` seat is diagnosable without stderr.\n const panelWorkspace = resolvePanelWorkspace(opts?.workspace);\n const result = await executeVotingInner(input, logger, { ...opts, project, panelWorkspace });\n result.project = project;\n // A simulated panel pointed no seat at a directory, so it names none.\n if (!input.simulateVotes) result.workspace = panelWorkspace;\n // An escalated full-panel result was finalized (and recorded) by its recursive\n // executeVoting call. Remember that state so this outer quick-mode frame does\n // not persist the same full-panel proposal twice.\n const correlationAlreadyRecorded = result.decision !== undefined;\n // #4135: stamp the response-layer decision (incl. `no_quorum`) ONCE, using the\n // SAME `resolveVoteDecision` `buildResponse` consumes, so pipeline consumers can\n // honor a quorum void instead of misreading it as a rejection — without\n // recomputing the policy math (DRY; the decision can't diverge). `errorCount`\n // uses the identical definition `buildResponse` uses.\n const errorCount = result.votes.filter((v) => v.source === 'error').length;\n // #4472: when the proposal declared options, the leading option must clear\n // the bar too. Applied BEFORE the decision is stamped so the record and the\n // response both reflect the gated verdict — a veto that only reached the\n // response would leave the audit trail claiming an approval that did not\n // happen. No-op when no options were declared.\n applyOptionGate(input, result);\n result.decision = resolveVoteDecision(input, result, errorCount).decision;\n if (\n !correlationAlreadyRecorded &&\n (result.decision === 'approved' || result.decision === 'rejected')\n ) {\n recordVotesToTracker(result.votes, result.decision, logger);\n }\n return result;\n}\n\n/**\n * Veto an approved verdict whose declared-option split failed its bar.\n *\n * Mutates `result` in place: `executeVoting` owns it and has not yet published\n * it. Only ever flips approved to rejected, never the reverse — and the\n * resulting `decision` must be `rejected`, not `no_quorum` (#4529): the panel\n * convened and disagreed, which is the opposite of a voided vote.\n *\n * Exported for the composition test (#4529): the defect this guards against\n * lives in how this function's output feeds `resolveVoteDecision` on the very\n * next line of `executeVoting`, not in either function alone.\n */\nexport function applyOptionGate(input: ConsensusVoteInput, result: ExtendedVotingResult): void {\n const declaredOptions = input.options;\n if (declaredOptions === undefined || declaredOptions.length === 0) return;\n\n const outcome = evaluateOptionGate(\n result.votes,\n declaredOptions,\n optionThresholdFor(result.strategy, input.threshold),\n result.result.outcome === 'approved'\n );\n\n if (!outcome.vetoed) {\n result.optionGate = outcome.verdict;\n return;\n }\n\n result.result.outcome = 'rejected';\n // #4529: the reason rides on the verdict, NOT on policyReason. policyReason\n // means \"an error policy voided this vote\", and resolveVoteDecision\n // short-circuits any non-undefined value straight to `no_quorum` — so\n // borrowing the field filed a measured split as \"nothing was decided\", and\n // `--on-no-quorum=retry` then re-rolled the panel and discarded the dissent\n // the gate had just detected. Decided by a 7-voter higher_order panel\n // (6 approvers, all selecting this shape).\n result.optionGate =\n outcome.reason !== undefined ? { ...outcome.verdict, reason: outcome.reason } : outcome.verdict;\n}\n\n// eslint-disable-next-line max-lines-per-function -- see block comment above\nasync function executeVotingInner(\n input: ConsensusVoteInput,\n logger: ILogger,\n // Required here, normalized by `executeVoting`. Every `opts.` inside was a\n // branch against the same never-null value; taking the option away at this\n // boundary removes them all rather than adding one more (#5393).\n opts: {\n voteTimeoutMs?: number;\n /** CLI ratification checkout, retained through escalation. */\n workspace?: string | undefined;\n workspaceSha?: string | undefined;\n gatewayAdapters?: readonly IModelAdapter[] | undefined;\n /** #5393: stops LAUNCHING un-started voters when `cancel_job` fires. */\n signal?: AbortSignal | undefined;\n /** #6110: the target project, resolved once by `executeVoting`. */\n project: ResolvedVoterProject;\n /** #6258: the directory the seats are handed — the value `executeVoting` stamps. */\n panelWorkspace: string;\n /** #6162: per-seat heartbeat, forwarded to `collectRealVotes`. */\n onVoteCollected?: ((vote: AgentVoteResult) => void) | undefined;\n }\n): Promise<ExtendedVotingResult> {\n const strategy = resolveStrategy(input);\n const algorithm = strategyToAlgorithm(strategy);\n const roles = getVoterRoles(input.quickMode);\n const startTime = getTimeProvider().now();\n const errorPolicy = input.errorPolicy ?? getDefaultErrorPolicy(strategy);\n\n logger.info('Starting consensus vote', {\n strategy,\n algorithm,\n roleCount: roles.length,\n errorPolicy,\n });\n const votes = await collectRealVotes({\n roles,\n proposal: input.proposal,\n simulate: input.simulateVotes,\n ...(opts.voteTimeoutMs !== undefined && { timeoutMs: opts.voteTimeoutMs }),\n ...(opts.gatewayAdapters !== undefined && { gatewayAdapters: opts.gatewayAdapters }),\n declaredOptions: input.options,\n // #6110: every seat's system prompt names the caller's project.\n project: opts.project.name,\n workspace: opts.panelWorkspace,\n workspaceSha: opts.workspaceSha,\n signal: opts.signal,\n onVoteCollected: opts.onVoteCollected,\n });\n\n // Error-policy gate (#2630): hard floor + fail_closed + reduce_denominator /\n // count_as_abstain transformation. Engine sees the resulting shape.\n const policyDecision = applyErrorPolicy(votes, errorPolicy);\n if (policyDecision.shortCircuit) {\n return buildPolicyShortCircuitResult({\n input,\n strategy,\n algorithm,\n roles,\n votes,\n errorPolicy,\n reason: policyDecision.reason ?? 'error policy short-circuit',\n startTime,\n logger,\n });\n }\n\n // Check for early cascade and process votes (#1765)\n const { engineResult, higherOrderResult, outcome, cascaded } = await processVotesWithCascade(\n policyDecision.engineVotes,\n {\n totalRoles: roles.length,\n proposal: input.proposal,\n algorithm,\n strategy,\n log: logger,\n }\n );\n\n const escalation = await maybeEscalateContrarian(\n input,\n outcome,\n { strategy, posteriorApproval: higherOrderResult?.posteriorApproval, revote: executeVoting },\n logger,\n opts\n );\n // #6111: an escalated full-panel result reports the quick-mode check that\n // produced it (`ok` when the contrarian triggered the re-vote, `skipped` when\n // the posterior floor pre-empted the call), not the inner frame's `skipped`.\n if (escalation.escalated !== undefined) {\n return { ...escalation.escalated, contrarianCheck: escalation.contrarianCheck };\n }\n\n const finalized = finalizeVotingResult({\n input,\n strategy,\n algorithm,\n roles,\n engineResult,\n higherOrderResult,\n votes,\n outcome,\n cascaded,\n errorPolicy,\n startTime,\n logger,\n });\n // #4132: a contrarian check that errored under absolute_quorum voids the quorum\n // — stamp policyReason so buildResponse's existing ternary downgrades to\n // no_quorum, matching the errored-voter path. (Kept out of finalizeVotingResult\n // to hold executeVoting within its cyclomatic budget.)\n return applyContrarianDegrade(\n { ...finalized, contrarianCheck: escalation.contrarianCheck },\n escalation.degradeReason\n );\n}\n\n/**\n * #4132: stamp the contrarian-check-errored degrade reason onto a finalized\n * result (unless an upstream short-circuit already set one). A no-op when the\n * contrarian check ran cleanly (`degradeReason` undefined).\n */\nfunction applyContrarianDegrade(\n result: ExtendedVotingResult,\n degradeReason: string | undefined\n): ExtendedVotingResult {\n if (degradeReason === undefined || result.policyReason !== undefined) return result;\n return { ...result, policyReason: degradeReason };\n}\n\n/**\n * Run a consensus vote with a plain goal as the proposal, default settings\n * (real voters, default strategy). The strategy executor the unified `run`\n * entry point dispatches to for the `consensus` strategy (#3575). Non-simulated.\n */\nexport async function runConsensusForGoal(\n goal: string,\n logger: ILogger = createLogger({ tool: 'consensus_vote' }),\n gatewayAdapters?: readonly IModelAdapter[],\n /** #6162: per-seat heartbeat when the caller is an async job body. */\n onVoteCollected?: (vote: AgentVoteResult) => void\n): Promise<ExtendedVotingResult> {\n // Parse through the schema so defaults (quickMode, simulateVotes:false) apply.\n // #4042: thread the in-process gateway adapters so the run/MetaOrchestrator\n // consensus path routes voters through the gateway like consensus_vote (#4040),\n // not the CLI subprocess.\n return executeVoting(ConsensusVoteInputSchema.parse({ proposal: goal }), logger, {\n ...(gatewayAdapters !== undefined && { gatewayAdapters }),\n onVoteCollected,\n });\n}\n\n/** Build the final `ExtendedVotingResult` once the engine + cascade settle. */\nfunction finalizeVotingResult(args: {\n input: ConsensusVoteInput;\n strategy: VotingStrategy;\n algorithm: ConsensusAlgorithm;\n roles: readonly VoterRole[];\n engineResult: ConsensusResult;\n higherOrderResult: ReturnType<typeof runHigherOrderVoting>;\n votes: readonly AgentVoteResult[];\n outcome: 'approved' | 'rejected';\n cascaded: boolean;\n /** #6211: the RESOLVED policy the tally above was computed under. */\n errorPolicy: ErrorPolicy;\n startTime: number;\n logger: ILogger;\n}): ExtendedVotingResult {\n const totalTimeMs = getTimeProvider().now() - args.startTime;\n args.logger.info('Consensus vote completed', {\n strategy: args.strategy,\n outcome: args.outcome,\n durationMs: totalTimeMs,\n cascaded: args.cascaded,\n });\n const result: ExtendedVotingResult = {\n proposal: args.input.proposal,\n threshold: args.algorithm,\n result: args.engineResult,\n votes: args.votes,\n totalTimeMs,\n simulateVotes: args.input.simulateVotes,\n strategy: args.strategy,\n // #4132: PANEL_SIZE + contrarian-presence for the absolute_quorum predicate.\n panelSize: args.roles.length,\n contrarianRequested: args.roles.includes('catfish'),\n // #6211: carried to the persisted record; the response never needed it\n // because `buildResponse` still holds the input, but the record does not.\n errorPolicy: args.errorPolicy,\n };\n if (args.higherOrderResult !== undefined) result.higherOrderResult = args.higherOrderResult;\n return result;\n}\n\n// --- Handler & Registration ---\n/**\n * Context from the tool input the record needs but the voting result does not\n * carry: the declared options (#6053) and the two ratification bindings\n * (#4004, #5130).\n */\ninterface DeclaredByCaller {\n readonly options: readonly string[] | undefined;\n readonly ratifies?: string;\n readonly ratifiesPr?: VoteRecordPrBinding;\n}\n\n/**\n * Best-effort post-vote side effects, extracted to keep `handleConsensusVote`\n * under the per-function line cap. Persists the authentic hash-chained vote\n * record (#3897) and rolls up per-decision cost (#3855), sharing one decision\n * id as the correlation key. Neither must fail the vote — both are guarded.\n *\n * Returns both the cost rollup and the structured vote-record persistence\n * outcome (#3991) so the handler can surface persistence visibility in the\n * result instead of leaving a skip as a server-only WARN.\n */\nasync function recordVoteSideEffects(\n proposal: string,\n strategy: string,\n result: ExtendedVotingResult,\n logger: ILogger,\n /**\n * Grouped rather than positional params: all answer \"what did the caller\n * declare\", and the sixth positional argument tipped this past the\n * max-params cap.\n */\n declared: DeclaredByCaller\n): Promise<{\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 = await 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 // #6211: the EFFECTIVE policy `executeVoting` stamped, so a caller that\n // took the per-strategy default still gets `reduce_denominator` on the\n // ledger line rather than nothing.\n errorPolicy: result.errorPolicy,\n correlationId: decisionId,\n ...(declared.ratifies !== undefined ? { ratifies: declared.ratifies } : {}),\n // #5130: the PR binding takes the same hop as `ratifies`; the seam test\n // (`consensus-vote-ratifies-pr.test.ts`) reads it back off the ledger.\n ...(declared.ratifiesPr !== undefined ? { ratifiesPr: declared.ratifiesPr } : {}),\n });\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({\n decisionId,\n gate: 'consensus_vote',\n votes: result.votes,\n // #5422: the detector's verdict, recorded on EVERY vote so the not-fired\n // rows are the denominator. Computed here, where the FULL proposal is in\n // hand — the ledger keeps a 503-char preview, which is why precision\n // cannot be measured there. Same patterns as the `panelWarning` in\n // `buildResponse`, so the measured precision is the warning's precision.\n undeclaredOptionsDetector: {\n ...detectUndeclaredOptions(proposal, declared.options),\n declaredOptionCount: declared.options?.length ?? 0,\n },\n });\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\n/** What the tool input declared that the voting result does not carry. */\nfunction declaredByCaller(args: ConsensusVoteInput): DeclaredByCaller {\n return {\n options: args.options,\n ...(args.ratifies !== undefined ? { ratifies: args.ratifies } : {}),\n ...(args.ratifiesPr !== undefined ? { ratifiesPr: args.ratifiesPr } : {}),\n };\n}\n\n/**\n * Detect all-error votes and return the structured error message instead of a\n * fake \"rejected\" (#1552); `null` when at least one seat answered. Empty case:\n * a panel with no votes at all is not \"all failed\" — it is `null` here and the\n * missing decision is caught by the caller.\n */\nfunction allVotersFailedError(\n votes: readonly AgentVoteResult[],\n proposal: string,\n logger: ILogger\n): string | null {\n const errorVotes = votes.filter((v) => v.source === 'error');\n if (errorVotes.length !== votes.length || votes.length === 0) return null;\n const failures = errorVotes.map((v) => `${v.role}: ${v.error ?? 'unknown error'}`).join('; ');\n logger.warn('All voters failed', { failureCount: errorVotes.length, failures });\n recordVoteError(proposal, `All ${String(errorVotes.length)} voters failed: ${failures}`);\n return `All ${String(errorVotes.length)} voters failed. Failures: ${failures}`;\n}\n\nasync function handleConsensusVote(\n deps: ConsensusVoteDeps,\n args: ConsensusVoteInput,\n signal?: AbortSignal,\n /** #6162: `runAsJob`'s heartbeat, fired per settled seat. Absent in sync mode. */\n onVoteCollected?: (vote: AgentVoteResult) => void\n): Promise<{ ok: true; value: ConsensusVoteResponse } | { ok: false; error: string }> {\n const logger = deps.logger ?? createLogger({ tool: 'consensus_vote' });\n try {\n const result = await executeVoting(args, logger, {\n ...(deps.gatewayAdapters !== undefined && { gatewayAdapters: deps.gatewayAdapters }),\n signal,\n onVoteCollected,\n });\n const allFailed = allVotersFailedError(result.votes, args.proposal, logger);\n if (allFailed !== null) return { ok: false, error: allFailed };\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 } = await recordVoteSideEffects(\n args.proposal,\n result.strategy,\n result,\n logger,\n declaredByCaller(args)\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 4 — signal + #6162 progress. `runAsJob` derives\n // `signalAccepted` from `run.length`, so taking the signal is what makes the\n // job record say cancellation works — the claim follows the capability.\n // `progress` is the liveness heartbeat, fired as each seat settles, so a\n // panel allowed past the standard MCP ceiling is never called wedged while\n // its seats keep landing.\n run: (_jobId, input, signal, progress) =>\n unwrapVoteOrThrow(handleConsensusVote(deps, input, signal, progress)),\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 // #4968: `dispatch` is canonical; `mode` is the deprecated alias. A call\n // that sent only `mode` still runs, and says so in `_meta` warnings.\n const dispatch = resolveDispatch(validationResult.data);\n const modeWarning = deprecatedModeWarning(validationResult.data);\n ctx.logger.debug('Starting consensus vote', {\n strategy,\n quickMode: validationResult.data.quickMode,\n ...(dispatch !== undefined ? { dispatch } : {}),\n });\n notifier.info('consensus_vote', {\n event: 'vote_start',\n proposalLength: validationResult.data.proposal.length,\n strategy,\n });\n // #3045 / epic #2631 Stage 4 — async dispatch.\n if (dispatch === 'async') {\n const asyncResult = dispatchAsyncConsensusVote(deps, validationResult.data);\n notifier.info('consensus_vote', {\n event: 'vote_dispatched_async',\n proposalLength: validationResult.data.proposal.length,\n strategy,\n });\n return withWarnings(asyncResult, [modeWarning]);\n }\n return withWarnings(await runSyncConsensusVote(deps, notifier, validationResult.data), [\n modeWarning,\n ]);\n };\n}\n\n/**\n * Async-dispatch envelopes carrying `structuredContent` (#5066).\n *\n * `runAsJob`'s defaults are text-only. Because this tool declares an\n * `outputSchema`, the SDK requires structured content on every non-error\n * result, so every `mode: 'async'` call failed with -32602 — the mode the\n * tool's own description recommends for 7-voter panels.\n */\nconst ASYNC_ENVELOPES: JobEnvelopeBuilders<ToolResult> = {\n pending: (jobId) =>\n 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 dispatch: \"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 /** #6115: present only when the seat answered elsewhere than assigned. */\n fallback: z\n .object({\n fromCli: z.string().max(100),\n fromModel: z.string().max(100).optional(),\n reason: z.enum(['rate-limit', 'capacity', 'auth', 'timeout', 'sandbox', 'unknown']),\n })\n .optional(),\n modelUsed: z.string().max(100).optional(),\n rejectionCategories: z\n .array(\n z.enum([\n 'YAGNI',\n 'DRY_VIOLATION',\n 'OVER_ENGINEERING',\n 'SCOPE_CREEP',\n 'SECURITY_RISK',\n 'MISALIGNED',\n 'INSUFFICIENT_EVIDENCE',\n ])\n )\n .optional(),\n })\n )\n .optional(),\n threshold: VoteThresholdSchema.optional(),\n durationMs: z.number().optional(),\n simulateVotes: z.boolean().optional(),\n // #6110: the project the panel judged and how the name was decided. Always\n // on the response; optional here like every field, because the async\n // `pending` envelope shares this schema.\n project: z\n .object({\n name: z.string().max(200),\n source: z.enum(['input', 'derived', 'default']),\n })\n .optional(),\n // #6258: the working directory the panel's seats were pointed at. Absent\n // when no live seat ran (simulated panel) and on the async envelope.\n workspace: z.string().max(4096).optional(),\n higherOrderMetadata: z\n .object({\n posteriorApproval: z.number(),\n posteriorRejection: z.number(),\n effectiveVoteCount: z.number(),\n method: z.enum(['ow', 'isp', 'simple']),\n usedCorrelationData: z.boolean(),\n improvementOverBaseline: z.number(),\n downweightedAgents: z.array(z.string().max(100)).max(10),\n reasoning: z.string().max(2000),\n })\n .optional(),\n // #3124: explains a `rejected` decision that coexists with a high\n // approvalPercentage (an error-policy short-circuit, e.g. fail_closed).\n policyReason: z.string().max(200).optional(),\n // #3991: whether the authentic vote record was persisted at vote time. Post-\n // #3991 it routes through nexusDataPath under governance/, so true is the\n // normal case; false means all-simulated (skipped by design) or write-failed\n // (data dir unwritable) — voteRecordNote carries the actionable reason. Makes\n // a previously WARN-only skip visible to MCP callers.\n voteRecordPersisted: z.boolean().optional(),\n voteRecordNote: z.string().max(500).optional(),\n // #5130: the persisted record's id, so the caller-commits script can name it.\n voteRecordId: z.string().max(200).optional(),\n // #3587: set when the panel DEGRADED (some voters errored), so the decision\n // rests on fewer voters than requested. Part of the response since #3587 but\n // omitted from this schema until #4032 — its absence made a strict MCP client\n // reject any degraded-panel vote (`-32602 additional properties`).\n panelWarning: z.string().optional(),\n // #6115: distinct answering models and seats that answered elsewhere than\n // assigned. Always on the response (explicit zeros); optional here only\n // because the async `pending` envelope shares this schema.\n panelDiversity: z\n .object({\n distinctModels: z.number().int().nonnegative(),\n fallbacks: z.number().int().nonnegative(),\n })\n .optional(),\n // #3855: per-decision cost rollup. Same omission as panelWarning (#4032) — it\n // is present on the response whenever cost recording succeeds (common in `api`\n // billing mode). Shared schema lives with the type (single source of truth).\n costSummary: DecisionCostSummarySchema.optional(),\n // #4472: declared-option outcome. Present whenever the proposal declared\n // `options`. `unattributedApprovals` is part of the contract, not telemetry:\n // without it a caller cannot tell a real split from unreadable responses.\n optionOutcome: z\n .object({\n tally: z.array(z.object({ option: z.string(), count: z.number().int().nonnegative() })),\n leadingOption: z.string().optional(),\n leadingShare: z.number().min(0).max(1),\n approverCount: z.number().int().nonnegative(),\n selectedCount: z.number().int().nonnegative(),\n unattributedApprovals: z.number().int().nonnegative(),\n thresholdMet: z.boolean(),\n // #4529: present only on a veto. Declared here because a strict MCP\n // client rejects any property the advertised schema omits — the same\n // drift that made degraded-panel votes unusable before #4032.\n vetoReason: z.string().max(400).optional(),\n })\n .optional(),\n};\n\n/** Advertised MCP input schema for consensus_vote (hoisted to keep the register fn within its line budget). */\n/**\n * The schema advertised to MCP clients.\n *\n * Registered from {@link ConsensusVoteInputSchema}'s shape rather than\n * hand-copied. A subset drifts: `options` shipped internally in #4494 and was\n * unreachable through the tool until someone noticed, and `mode` stayed\n * unadvertised while this tool's own description told callers to pass it —\n * so the documented async path could not be invoked at all (#4969).\n */\nexport const CONSENSUS_VOTE_TOOL_SCHEMA = ConsensusVoteInputSchema.shape;\n\n/** Advertised MCP tool description for consensus_vote. */\nconst CONSENSUS_VOTE_DESCRIPTION =\n 'Execute multi-model consensus voting on a proposal. ' +\n 'Uses 7 roles by default (architect, security, devex, ai_ml, pm, catfish, scope_steward) ' +\n 'or 3 with quickMode (architect, security, scope_steward), voting with configurable strategies. ' +\n 'higher_order does NOT decide the verdict by correlation-aware aggregation (#4701): approve/reject ' +\n 'is a simple tally of the panel, so correlated voters each carry full independent weight. The ' +\n 'Bayesian correlation analysis is computed and feeds contrarian escalation only. Choose it for the ' +\n 'escalation behaviour, not for a weighted verdict. ' +\n \"Supports async dispatch (dispatch: 'async'; `mode` is a deprecated alias) — returns a jobId to poll via get_job_result. \" +\n 'Pass ratifies=<subject> to bind an authority-ladder ratification vote into its authentic record, ' +\n 'and ratifiesPr={pr, headSha} to bind a governor-path PR ratification to the head the panel saw (#5130); ' +\n 'the result carries voteRecordId for the caller-commits append. ' +\n 'If your proposal asks voters to choose among named alternatives, you MUST pass them in ' +\n '`options` (#4472) — the threshold is then measured over WHICH option won, and the record ' +\n 'carries the per-option tally plus selection coverage. WITHOUT `options` the tally is ' +\n 'approve/reject/abstain only, so every voter who engages returns `approve` and a 6-1 split on ' +\n 'which option persists as 7-0, 100% (#4452).';\n\n/**\n * Registers the consensus_vote tool with the MCP server.\n * Uses createSecureHandler (Issue #531) with timeout protection (Issue #271).\n * @category MCP\n */\nexport function registerConsensusVoteTool(server: McpServer, deps: ConsensusVoteDeps): void {\n const logger = deps.logger ?? createLogger({ tool: 'consensus_vote' });\n const notifier = deps.notifier ?? createMcpNotifier(server);\n const depsWithNotifier = { ...deps, notifier };\n\n const secureHandler = createSecureHandler(createConsensusVoteHandler(depsWithNotifier), {\n toolName: 'consensus_vote',\n rateLimiter: deps.rateLimiter,\n logger,\n });\n\n const timeoutMs = getToolTimeout('consensus_vote', deps.security);\n const wrappedHandler = wrapToolWithTimeout('consensus_vote', secureHandler, {\n timeoutMs,\n logger,\n });\n\n 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 toSdkCallbackWithTimeoutCheck(wrappedHandler, 'consensus_vote', timeoutMs, logger)\n );\n logger.info('Registered consensus_vote tool with secure handler and timeout protection');\n}\n","/**\n * The one async-dispatch input every async-capable MCP tool composes (#4968).\n *\n * Ten tools dispatch through `runAsJob`, and before this module they did not\n * agree on what the switch was called: `mode` on three (`consensus_vote`,\n * `run_workflow`, `orchestrate`), `dispatch` on seven. Because the advertised\n * schemas strip unknown keys, the WRONG spelling was silently ignored — a\n * caller sending `consensus_vote { dispatch: 'async' }` got a 97-second\n * synchronous run and no jobId. Panel decision (quick panel, 3 of 3): `dispatch`\n * is canonical everywhere, `mode` is accepted as a deprecated alias on the three\n * that had it (removal is next-major, #6225), and the wrong key is rejected\n * instead of dropped.\n *\n * Where the wrong-key rejection has to live. The MCP SDK builds\n * `z.object(inputSchema)` from the ADVERTISED shape and hands the handler the\n * parsed, already-stripped object (`validateToolInput` in\n * `@modelcontextprotocol/sdk/server/mcp.js`). So neither a `.refine()` on the\n * tool's internal schema nor a `z.preprocess` in the handler can see a key the\n * SDK removed — either would be a check that cannot fire on the real path\n * while passing every unit test that calls the handler directly. The only\n * schema element that sees the raw value of `mode` is a `mode` entry in the\n * advertised shape itself; {@link REJECTED_MODE_KEY} is that entry. It is the\n * \"declare the forbidden key with a never-type carrying the message\" form the\n * panel's architect seat named.\n *\n * @module mcp/tools/async-dispatch-input\n */\n\nimport { z } from 'zod';\n\n/** The two dispatch values. `undefined` is treated as `'sync'` by every handler. */\nexport const DISPATCH_MODES = ['sync', 'async'] as const;\n\nexport type DispatchMode = (typeof DISPATCH_MODES)[number];\n\n/** The enum both field builders return. */\nexport type DispatchEnum = z.ZodEnum<{ readonly sync: 'sync'; readonly async: 'async' }>;\n\n/** The type of {@link REJECTED_MODE_KEY}: absent is fine, any value is an error. */\nexport type RejectedModeKey = z.ZodOptional<z.ZodNever>;\n\n/** Next-major issue that removes the deprecated `mode` alias. */\nexport const MODE_ALIAS_REMOVAL_ISSUE = '#6225';\n\nconst DISPATCH_DESCRIPTION =\n \"Async dispatch (#4968). 'sync' (default): run inline and return the result. \" +\n \"'async': return { status: 'pending', jobId } immediately and run in the background; \" +\n 'poll get_job_result({ jobId }).';\n\n/** Error a wrong-key `mode: 'sync' | 'async'` produces on a tool whose switch is `dispatch`. */\nexport const WRONG_KEY_MODE_MESSAGE =\n '`mode` is not the async switch on this tool; send `dispatch: \"async\"` (or \"sync\") instead (#4968).';\n\n/** Error when a deprecated-`mode` tool receives both keys with different values. */\nexport function dispatchModeConflictMessage(dispatch: DispatchMode, mode: DispatchMode): string {\n return (\n `\\`dispatch: \"${dispatch}\"\\` and \\`mode: \"${mode}\"\\` disagree; send only \\`dispatch\\` ` +\n `(\\`mode\\` is a deprecated alias, removed in ${MODE_ALIAS_REMOVAL_ISSUE}).`\n );\n}\n\nfunction describeDispatch(note: string | undefined): string {\n return note === undefined ? DISPATCH_DESCRIPTION : `${DISPATCH_DESCRIPTION} ${note}`;\n}\n\n/**\n * The canonical field, optional: the parsed value is `undefined` when the\n * caller omits it. Tools whose parsed type materialises the default use\n * {@link dispatchFieldDefaultSync} instead — same enum, same description.\n *\n * @param note - Tool-specific suffix, e.g. \"Ignored for dryRun.\"\n */\nexport function dispatchField(note?: string): z.ZodOptional<DispatchEnum> {\n return z.enum(DISPATCH_MODES).optional().describe(describeDispatch(note));\n}\n\n/** {@link dispatchField} with `'sync'` materialised as the parsed default. */\nexport function dispatchFieldDefaultSync(note?: string): z.ZodDefault<DispatchEnum> {\n return z.enum(DISPATCH_MODES).default('sync').describe(describeDispatch(note));\n}\n\n/**\n * Advertised-shape entry for tools that have NO `mode` of their own. Any value\n * is rejected — `z.never` — with {@link WRONG_KEY_MODE_MESSAGE}, so the trap\n * the issue describes (`mode: 'async'` silently dropped, synchronous run)\n * fails loudly at the SDK's input validation. Absent is fine: `.optional()`.\n *\n * `run_dev_pipeline` cannot use this because its `mode` is a real field\n * (`'autonomous' | 'harness'`); it keeps its enum and routes the trap values\n * through {@link modeEnumErrorNamingDispatch}.\n */\nexport const REJECTED_MODE_KEY: RejectedModeKey = z\n .never({ error: WRONG_KEY_MODE_MESSAGE })\n .optional()\n .describe(\n \"Not an input of this tool. The async switch is `dispatch`; `mode: 'async'` is rejected (#4968).\"\n );\n\n/** Shape fragment for the `dispatch`-only tools: canonical field + wrong-key trap. */\nexport function asyncDispatchInput(note?: string): {\n dispatch: z.ZodOptional<DispatchEnum>;\n mode: RejectedModeKey;\n} {\n return { dispatch: dispatchField(note), mode: REJECTED_MODE_KEY };\n}\n\n/** {@link asyncDispatchInput} for tools whose parsed `dispatch` defaults to `'sync'`. */\nexport function asyncDispatchInputDefaultSync(note?: string): {\n dispatch: z.ZodDefault<DispatchEnum>;\n mode: RejectedModeKey;\n} {\n return { dispatch: dispatchFieldDefaultSync(note), mode: REJECTED_MODE_KEY };\n}\n\n/** Shape of the issue Zod hands an enum's `error` function; only `input` is read. */\ninterface EnumIssueInput {\n readonly input?: unknown;\n}\n\n/**\n * `error` function for a tool whose `mode` is a REAL enum with other values\n * (`run_dev_pipeline`). A trap value (`'sync' | 'async'`) gets\n * {@link WRONG_KEY_MODE_MESSAGE}; any other wrong value keeps Zod's own\n * \"expected one of …\" message (returning `undefined` defers to it).\n */\nexport function modeEnumErrorNamingDispatch(issue: EnumIssueInput): string | undefined {\n return isDispatchMode(issue.input) ? WRONG_KEY_MODE_MESSAGE : undefined;\n}\n\nfunction isDispatchMode(value: unknown): value is DispatchMode {\n return value === 'sync' || value === 'async';\n}\n\n/**\n * Shape fragment for the three tools that spelled the switch `mode`: the\n * canonical `dispatch` plus `mode` as a deprecated alias. Compose it into the\n * object AND apply {@link refineDispatchModeAgreement} on the object so a call\n * carrying both with different values is a validation error rather than a\n * silent precedence choice.\n */\nexport const DEPRECATED_MODE_ALIAS_INPUT = {\n dispatch: dispatchField(),\n mode: z\n .enum(DISPATCH_MODES)\n .optional()\n .describe(\n `DEPRECATED alias of \\`dispatch\\` (removed in the next major, ${MODE_ALIAS_REMOVAL_ISSUE}). ` +\n 'Send `dispatch` instead; a call that sends only `mode` still works and returns a deprecation warning.'\n ),\n};\n\n/** The parsed keys the resolution helpers read. */\nexport interface DispatchAliasInput {\n readonly dispatch?: DispatchMode | undefined;\n readonly mode?: DispatchMode | undefined;\n}\n\n/**\n * `superRefine` callback for a deprecated-`mode` tool's object schema: both\n * keys present with different values is an error naming both. Same value\n * twice is allowed (harmless redundancy).\n */\nexport function refineDispatchModeAgreement(value: DispatchAliasInput, ctx: z.RefinementCtx): void {\n if (value.dispatch === undefined || value.mode === undefined) return;\n if (value.dispatch === value.mode) return;\n ctx.addIssue({\n code: 'custom',\n path: ['dispatch'],\n message: dispatchModeConflictMessage(value.dispatch, value.mode),\n });\n}\n\n/**\n * The effective dispatch value on a deprecated-`mode` tool: `dispatch` wins,\n * `mode` fills in when `dispatch` is absent. The conflict case never reaches\n * here — {@link refineDispatchModeAgreement} rejects it at parse.\n */\nexport function resolveDispatch(input: DispatchAliasInput): DispatchMode | undefined {\n return input.dispatch ?? input.mode;\n}\n\n/**\n * The deprecation warning a deprecated-`mode` tool attaches when the caller\n * sent `mode` and not `dispatch`; `undefined` otherwise (nothing to warn about\n * when `dispatch` is present, whatever `mode` says).\n */\nexport function deprecatedModeWarning(input: DispatchAliasInput): string | undefined {\n if (input.mode === undefined || input.dispatch !== undefined) return undefined;\n return (\n `\\`mode: \"${input.mode}\"\\` is deprecated; send \\`dispatch: \"${input.mode}\"\\`. ` +\n `\\`mode\\` is removed in the next major (${MODE_ALIAS_REMOVAL_ISSUE}).`\n );\n}\n\n/**\n * `_meta` key carrying caller-facing warnings on a tool result (#4968).\n *\n * `_meta` is the result envelope's out-of-band channel — the error envelope\n * (`nexus-agents/error`, #2649) and the build stamp (`nexus-agents/build`,\n * #5008) already ride there, because `structuredContent` is validated against\n * each tool's `outputSchema` and `content[].text` is the payload. The value is\n * a `string[]`; absent when there is nothing to warn about.\n */\nexport const WARNINGS_META_KEY = 'nexus-agents/warnings';\n\n/** Result envelopes the warning helper can decorate: anything carrying `_meta`. */\nexport interface HasMeta {\n _meta?: Record<string, unknown>;\n}\n\n/**\n * Attach caller-facing warnings to a result under {@link WARNINGS_META_KEY},\n * preserving any `_meta` the tool already set (the async pending envelope\n * carries none; a structured error carries the error envelope). A missing or\n * empty warning list returns the result unchanged, so the key is present only\n * when it says something.\n */\nexport function withWarnings<T extends HasMeta>(\n result: T,\n warnings: readonly (string | undefined)[]\n): T {\n const present = warnings.filter((w): w is string => w !== undefined);\n if (present.length === 0) return result;\n const existing = result._meta?.[WARNINGS_META_KEY];\n const prior = Array.isArray(existing) ? existing.filter((w) => typeof w === 'string') : [];\n return { ...result, _meta: { ...result._meta, [WARNINGS_META_KEY]: [...prior, ...present] } };\n}\n","/**\n * nexus-agents/cli - Voter role configuration\n *\n * Which seats sit on a consensus panel, what each is told to evaluate, and\n * which subset the quick panel runs. Extracted from `cli/vote-types.ts` and\n * `mcp/tools/consensus-vote.ts` (#6000 step 1): a single edit here changes who\n * decides a vote, so the configuration lives apart from the routine result\n * types it used to share a file with. `vote-types.ts` re-exports the role\n * type and descriptions, so the public API is unchanged.\n *\n * @module cli/voter-roles\n */\n\n/**\n * Voter agent role definitions.\n *\n * `scope_steward` (#2185) was added 2026-04-25 to address a build-vs-buy\n * blind spot in the original 6-role panel: the panel approved a proposal\n * to build a USB-flasher CLI without flagging that Rufus already solves\n * the problem. The scope-steward role explicitly checks for existing tools\n * + biases toward \"don't build.\"\n */\nexport type VoterRole =\n 'architect' | 'security' | 'devex' | 'ai_ml' | 'pm' | 'catfish' | 'scope_steward';\n\n/**\n * Agent role descriptions for prompt generation.\n */\nexport const VOTER_ROLES: Record<VoterRole, string> = {\n architect: 'Software Architect - evaluates technical design, scalability, and maintainability',\n security:\n 'Security Engineer - evaluates security implications, vulnerabilities, and attack vectors',\n devex: 'Developer Experience - evaluates usability, documentation, and developer workflow',\n ai_ml: 'AI/ML Engineer - evaluates AI/ML aspects, model selection, and learning capabilities',\n pm: 'Product Manager - evaluates business value, user impact, and resource allocation',\n catfish:\n 'Contrarian Analyst - deliberately challenges proposals to prevent agreement bias (arXiv:2505.21503)',\n scope_steward:\n 'Scope Steward - asks whether to build at all; checks existing tools, biases toward kill-the-feature (#2185)',\n};\n\n/**\n * The seats a `consensus_vote` panel runs, by mode.\n *\n * Moved verbatim from `mcp/tools/consensus-vote.ts` (#6000 step 1): the panel\n * composition decides whether the contrarian is present, which the\n * `absolute_quorum` verdict depends on.\n */\nexport function getVoterRoles(quickMode: boolean): readonly VoterRole[] {\n // Default panel expanded to 7 roles 2026-04-25 — scope_steward added to\n // catch build-vs-buy blind spots (#2185). QuickMode substitutes\n // scope_steward for pm so fast triage covers existence-justification.\n return quickMode\n ? ['architect', 'security', 'scope_steward']\n : ['architect', 'security', 'devex', 'ai_ml', 'pm', 'catfish', 'scope_steward'];\n}\n","/**\n * nexus-agents/consensus/decision - Strategy resolution\n *\n * Which bar a `consensus_vote` call is measured against, and which error\n * policy it runs under when the caller named none. Extracted verbatim from\n * `mcp/tools/consensus-vote.ts` and `mcp/tools/consensus-vote-types.ts`\n * (#6000 step 1): `resolveStrategy` is where `strategy` silently discarded\n * `threshold` (#5315), so the resolution lives in a module that can be\n * governed on its own path. The types it reads stay in the MCP tool module —\n * they are imported type-only, so this module has no runtime edge into\n * `mcp/`.\n *\n * @module consensus/decision/strategy\n */\n\nimport type {\n ConsensusVoteInput,\n ErrorPolicy,\n VotingStrategy,\n} from '../../mcp/tools/consensus-vote-types.js';\nimport type { ConsensusAlgorithm } from '../types-core.js';\n\n// --- Strategy Resolution ---\nexport function resolveStrategy(input: ConsensusVoteInput): VotingStrategy {\n if (input.strategy !== undefined) return input.strategy;\n if (input.threshold !== undefined) {\n switch (input.threshold) {\n case 'majority':\n return 'simple_majority';\n case 'supermajority':\n return 'supermajority';\n case 'unanimous':\n return 'unanimous';\n }\n }\n return 'simple_majority';\n}\n\nexport function strategyToAlgorithm(strategy: VotingStrategy): ConsensusAlgorithm {\n if (strategy === 'higher_order') return 'higher_order';\n if (strategy === 'opinion_wise') return 'opinion_wise';\n return strategy;\n}\n\n/**\n * Default error policy per voting strategy.\n *\n * Only `unanimous` defaults to `fail_closed`: a missing/errored voter genuinely\n * breaks the unanimity guarantee, so the vote must void. Every other strategy —\n * including `higher_order` and its `opinion_wise` alias — defaults to\n * `reduce_denominator`: Bayesian/weighted aggregation over the *non-error*\n * voters is well-defined, so a single infra timeout (e.g. one slow voter's\n * adapter transport, #3304) should NOT fail-close an otherwise-unanimous result\n * (#3138). The >50% `ERROR_FLOOR_FRACTION` hard floor still voids any vote where\n * most voters errored. Callers can override via the `errorPolicy` input.\n */\nexport function getDefaultErrorPolicy(strategy: VotingStrategy): ErrorPolicy {\n if (strategy === 'unanimous') {\n return 'fail_closed';\n }\n return 'reduce_denominator';\n}\n","/**\n * nexus-agents/cli — per-role voter model overrides (#4055).\n *\n * Voters round-robin across the gateway's discovered models (#4040), so a role can\n * land on a model that fails on a particular gateway (e.g. a bodyless HTTP 400 for\n * specific model ids — #4049). This lets an operator PIN a known-good gateway model\n * for a role:\n *\n * NEXUS_VOTER_MODEL_<ROLE>=<bare gateway model id>\n * e.g. NEXUS_VOTER_MODEL_ARCHITECT=claude_4_5_opus\n *\n * The override is validated against the discovered gateway catalog: an id that is\n * NOT a live gateway model warns and falls back to round-robin for that role (no\n * hard failure). Roles without an override round-robin unchanged.\n *\n * @module cli/voter-model-overrides\n */\n\nimport type { ILogger, IModelAdapter } from '../core/index.js';\nimport type { VoterRole } from './vote-types.js';\n\n/** Env var name for a role's voter-model override (e.g. role `ai_ml` → `NEXUS_VOTER_MODEL_AI_ML`). */\nexport function voterModelOverrideEnvKey(role: VoterRole): string {\n return `NEXUS_VOTER_MODEL_${role.toUpperCase()}`;\n}\n\n/**\n * Resolve per-role gateway-model overrides from the environment, validated against\n * the discovered gateway adapters. Returns a map of ONLY the roles that have a\n * valid override (matched to a live gateway model by `modelId`); roles with no\n * override, or an override id not in the catalog, are omitted (and the latter is\n * warned) so the caller round-robins them as usual.\n *\n * Matching is exact on `modelId` first, then case-insensitive as a convenience.\n */\nexport function resolveVoterModelOverrides(\n roles: readonly VoterRole[],\n gatewayAdapters: readonly IModelAdapter[],\n logger: ILogger\n): Map<VoterRole, IModelAdapter> {\n const overrides = new Map<VoterRole, IModelAdapter>();\n if (gatewayAdapters.length === 0) return overrides;\n\n const byId = new Map<string, IModelAdapter>();\n for (const adapter of gatewayAdapters) byId.set(adapter.modelId, adapter);\n\n for (const role of roles) {\n const envKey = voterModelOverrideEnvKey(role);\n const raw = process.env[envKey];\n if (raw === undefined || raw.trim() === '') continue;\n const requested = raw.trim();\n\n const adapter =\n byId.get(requested) ??\n gatewayAdapters.find((a) => a.modelId.toLowerCase() === requested.toLowerCase());\n\n if (adapter === undefined) {\n logger.warn(\n `Voter model override ${envKey}=\"${requested}\" is not a discovered gateway model — ` +\n `falling back to round-robin for role \"${role}\".`,\n { role, requested, available: [...byId.keys()] }\n );\n continue;\n }\n overrides.set(role, adapter);\n }\n\n if (overrides.size > 0) {\n logger.info('Applied per-role voter model overrides (#4055)', {\n overrides: Object.fromEntries([...overrides].map(([r, a]) => [r, a.modelId])),\n });\n }\n return overrides;\n}\n","/**\n * 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 * 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;\n * a signature is OPTIONAL until the #3927 item 4 phase-3 cutover): 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 * SIGNATURE (#3927 item 4, phases 1-2). A record MAY carry `signature`: a\n * detached `ssh-keygen -Y sign` signature, namespace\n * {@link VOTE_RECORD_SIGNATURE_NAMESPACE}, over the record's committed `hash`\n * string. It is OUTSIDE the self-hash (it is made over the hash) and is\n * verified separately by `vote-record-signature.ts` against the committed\n * `governance/allowed_signers`. `verifyVoteRecordSet` does NOT check it: the\n * set verifier answers \"was any record edited\", the signature verifier answers\n * \"did a listed key sign this hash\", and the gate reports the two side by side.\n * What a signature proves is key ACCESS from the signing environment, not a\n * human's presence — see the threat model and #6257.\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\nimport {\n HEX_256_PATTERN,\n findReasoningCommitmentDefect,\n isReasoningDigestTier,\n reasoningCommitmentShapeDefect,\n} from './reasoning-commitment.js';\nimport {\n findRedactionDefect,\n redactedRecordReports,\n redactedRolesByTarget,\n type RedactedRecordReport,\n type RedactionFailureReason,\n type RedactionRecord,\n} from './redaction-record.js';\nimport { VoteRecordSignatureSchema } from './record-signature-schema.js';\n\nexport {\n VOTE_RECORD_SIGNATURE_NAMESPACE,\n VoteRecordSignatureSchema,\n} from './record-signature-schema.js';\nexport type { VoteRecordSignature } from './record-signature-schema.js';\nimport { censusSequences, firstSequenceGap, forkSequences } from './sequence-census.js';\nimport type { CompleteKeys } from './voter-keys-constraint.js';\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 * Clip a voter-entry text to {@link MAX_VOTER_REASONING_CHARS} with a marker\n * (#5373): the returned `truncated` is the flag the record stores beside the\n * text (`reasoningTruncated`, `retriedFrom.errorTruncated`), present only when\n * the clip fired. ONE clip for every bounded voter string — the builder's\n * `reasoningFields` and the live retry's carried cause (#6246) both call this,\n * so there is one number and one marker rule, not a silent slice somewhere.\n */\nexport function clipForRecord(text: string): { text: string; truncated?: true } {\n if (text.length <= MAX_VOTER_REASONING_CHARS) return { text };\n return { text: text.slice(0, MAX_VOTER_REASONING_CHARS), truncated: true };\n}\n\n/**\n * What a recovered seat was retried from, as recorded (#6246, schema 1.12).\n * Module-private on the `SeatFallbackRecordSchema` rule: only\n * `VoterSummarySchema` consumes it. `source` is the live `RetriedFrom['source']`\n * spelled out — an `enum`, not a bare string, so a record cannot claim a first\n * pass the retry never replaces (a `'llm'` seat is not retried) — and the two\n * are held equal by a type test. `error` shares the #5373 bound and marker\n * with `reasoning`: the live retry clips with {@link clipForRecord} before the\n * value reaches the builder, and the schema refuses anything longer.\n */\nconst RetriedFromRecordSchema = z\n .object({\n /** The first pass's `source`: errored, or answered without reading. */\n source: z.enum(['error', 'unverifiable']),\n /** The first pass's `error` string, when it had one; already clipped. */\n error: z.string().max(MAX_VOTER_REASONING_CHARS).optional(),\n /** True when `error` was clipped to {@link MAX_VOTER_REASONING_CHARS}. */\n errorTruncated: z.literal(true).optional(),\n })\n .strict();\n\n/**\n * A seat's fallback as recorded (#6115, schema 1.9). Module-private on the\n * `VoteRecordPanelCoverageSchema` rule: only `VoterSummarySchema` consumes it.\n * The `reason` enum is the live `FallbackReason` spelled out — an `enum` rather\n * than a bare string so a record cannot carry a class the adapter layer never\n * emits — and the two are held equal by a type test.\n */\nconst SeatFallbackRecordSchema = z\n .object({\n /** The CLI the seat was assigned to, bare (`claude`, not `cli-claude`). */\n fromCli: z.string().min(1).max(100),\n /** The model the assigned adapter had detected, when it had one. */\n fromModel: z.string().min(1).max(200).optional(),\n /** The adapter-layer class of the error that moved the seat. */\n reason: z.enum(['rate-limit', 'capacity', 'auth', 'timeout', 'sandbox', 'unknown']),\n })\n .strict();\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 * The CLI the round-robin or `NEXUS_VOTER_MODEL_<ROLE>` pin chose for the\n * seat, as a bare name (#6115, schema 1.9). `model` says where a seat\n * answered; this says where it was MEANT to. Three consecutive 7-seat\n * ratification panels on 2026-09-13 answered every seat on one gemini\n * model while the assignment was three claude, two codex, two gemini,\n * and the 1.8 record showed seven identical `model` values with nothing\n * that said five of them were substitutes. Present-only, on the `model`\n * rule; absent on a result built outside the panel launcher.\n */\n assignedCli: z.string().min(1).max(100).optional(),\n /**\n * Present only when the seat answered on a different CLI or model than\n * assigned (#6115, schema 1.9): the exact `SeatFallback` shape the live\n * result carries, rebuilt field-by-field. `fromCli` is the assigned CLI,\n * `fromModel` the model it had detected (absent when it never did — the\n * pending-detection placeholder is not a model), `reason` the adapter\n * layer's error class. The vocabulary is compile-checked against the live\n * `FallbackReason` in vote-record.test.ts; a class one side learns alone\n * would either refuse every record that carries it (#6054) or accept one\n * no producer can write.\n */\n fallback: SeatFallbackRecordSchema.optional(),\n /**\n * Present only when the per-role retry REPLACED this seat (#6246, schema\n * 1.12): the first pass's source and, when it had one, its clipped error\n * string. `retried` (1.7) says a recovery happened; this says what it\n * recovered from. On the #6241 panel a seat recorded `retried: true,\n * unverifiable: true` after a first pass that errored on two response-parse\n * failures, and nothing in the record joined the two — a reader of the\n * ledger and the log together concluded the parse errors had been\n * misclassified (#6244). Rebuilt field-by-field on the `fallback` rule; the\n * `source` vocabulary is compile-checked against the live `RetriedFrom`.\n */\n retriedFrom: RetriedFromRecordSchema.optional(),\n /**\n * The per-entry salt of the reasoning commitment (#6263, schema 1.13;\n * #5748 step 1, panel option A amended with a salt). 32 random bytes as\n * lowercase hex, minted by `mintReasoningNonce` (reasoning-commitment.ts)\n * once per entry.\n *\n * The nonce is the OPENING of the commitment, together with `reasoning`:\n * on the digest tier the record hash folds ONLY `reasoningDigest`, and\n * both text and nonce travel on the record outside the hash\n * (`reasoningTruncated` stays hashed). The salt is the secret (#6274\n * panel 1): hashed, it could not be dropped at redaction without\n * breaking the hash and the #3927 signature; public, it would let\n * `sha256(nonce ‖ guess)` confirm low-entropy reasoning once the text is\n * gone. Outside the hash, a redaction (#6264) drops text and nonce\n * together while the original hash — and any signature over it — still\n * verifies, and the 256-bit unknown salt keeps the digest opaque. The\n * record-level refinement below holds the three together: on 1.13 text\n * and nonce are present or absent TOGETHER and an entry with reasoning\n * carries the digest; on every older tier it carries neither key (there\n * they would be unhashed decoration).\n */\n reasoningNonce: z.string().regex(HEX_256_PATTERN).optional(),\n /**\n * `sha256(reasoningNonce ‖ reasoning)` as lowercase hex (#6263, schema\n * 1.13) — see `computeReasoningDigest` in reasoning-commitment.ts. The\n * commitment to the text: {@link verifyVoteRecordSet} re-opens it\n * whenever nonce and text are both present, so a text edited without\n * re-committing is a `hash_mismatch` exactly as it was when the text\n * itself was folded. A digest nobody re-opens would be a check that\n * cannot fail.\n */\n reasoningDigest: z.string().regex(HEX_256_PATTERN).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: {@link CompleteKeys} is `unknown` (no-op intersection) when the tuple\n * is complete and `never` when a schema key is missing, so the argument becomes\n * unassignable. Drop `retried` from the tuple below and this call is a `tsc`\n * 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 *\n * The constraint itself lives in `voter-keys-constraint.ts` so that a type test\n * can probe it (#6092): if a TypeScript release stopped resolving it to `never`\n * for an incomplete tuple, `pnpm typecheck` fails there, not silently here.\n */\nfunction defineVoterKeys<T extends readonly (keyof VoterSummary)[]>(\n keys: T & CompleteKeys<keyof VoterSummary, T>\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 // 1.9 (#6115): appended after `unverifiable`, present-only, so a 1.8 entry\n // projects byte-identically. `fallback` is the first nested voter field;\n // `projectSeatFallback` rebuilds it in its own canonical order.\n 'assignedCli',\n 'fallback',\n // 1.12 (#6246): appended after `fallback`, present-only, so a 1.11 entry\n // projects byte-identically. Nested; `projectRetriedFrom` rebuilds it in\n // its own canonical order.\n 'retriedFrom',\n // 1.13 (#6263): appended after `retriedFrom`, present-only. Only\n // `reasoningDigest` is ever folded, and only on the digest tier, where\n // `reasoning` above is NOT (`reasoningTruncated` stays folded on every\n // tier); `reasoningNonce` is listed because every schema key must be (the\n // `defineVoterKeys` constraint) but projects to absent on EVERY tier — it\n // is the opening's salt, never hash-covered. `projectVoterField` keys the\n // swap on the record version, so a 1.12 entry still projects\n // byte-identically.\n 'reasoningNonce',\n 'reasoningDigest',\n] as const satisfies readonly (keyof VoterSummary)[]);\n\n/**\n * The 1.13 keys — outside the hash on every TEXT tier, where the schema\n * refuses them anyway (they would be unhashed decoration there).\n */\nconst REASONING_TIER_KEYS: ReadonlySet<keyof VoterSummary> = new Set([\n 'reasoningNonce',\n 'reasoningDigest',\n]);\n\n/**\n * The OPENING of the commitment — outside the hash on the DIGEST tier: the\n * raw text and its salt, `reasoningNonce`. Both, not the text alone (#6274\n * panel 1): the hash folds only `reasoningDigest`, so a redaction (#6264) can drop\n * text and nonce together while the hash and any signature over it verify\n * unchanged, and the unknown 256-bit salt keeps the digest an opaque\n * commitment rather than a dictionary target. The clip marker\n * `reasoningTruncated` is a boolean with no privacy content that redaction\n * keeps, so it stays folded on every tier like any other present-only key — an\n * unhashed marker would let \"this argument was clipped\" be erased from a\n * committed record without `hash_mismatch` (#6274 review).\n */\nconst REASONING_OPENING_KEYS: ReadonlySet<keyof VoterSummary> = new Set([\n 'reasoning',\n 'reasoningNonce',\n]);\n\n/** The record's fallback shape; `VoterSummary['fallback']` minus its optionality. */\ntype VoterSummaryFallback = NonNullable<VoterSummary['fallback']>;\n\n/** The record's retried-from shape; `VoterSummary['retriedFrom']` minus its optionality. */\ntype VoterSummaryRetriedFrom = NonNullable<VoterSummary['retriedFrom']>;\n\n/**\n * Identity at runtime; an exhaustiveness constraint at compile time, on the\n * {@link defineVoterKeys} rule. `rest` is what {@link projectSeatFallback}'s\n * destructure did NOT name, and only `{}` is assignable to\n * `Record<string, never>` — so a key added to `SeatFallbackRecordSchema`\n * without the projector learning it is a `tsc` error at the projection, not a\n * silently unhashed nested field (ratification note on #6179).\n */\nfunction noUnprojectedKeys(rest: Record<string, never>): Record<string, never> {\n return rest;\n}\n\n/**\n * Rebuild a seat's fallback in canonical order — `fromCli`, `fromModel` (only\n * when present), `reason` — so the hash does not depend on how the nested\n * object's keys were ordered (#3962, the `voteCounts` rule applied one level\n * deeper). Shared with the builder (`vote-record-store.ts`), so the entry the\n * ledger line carries and the entry the hash covers are the same projection.\n *\n * The destructure is exhaustive: {@link noUnprojectedKeys} makes the\n * remainder a compile error unless it is empty. Add a field to the fallback\n * schema and this function stops compiling until the field is placed in the\n * canonical order below.\n */\nexport function projectSeatFallback(f: VoterSummaryFallback): VoterSummaryFallback {\n const { fromCli, fromModel, reason, ...rest } = f;\n noUnprojectedKeys(rest);\n return {\n fromCli,\n ...(fromModel !== undefined ? { fromModel } : {}),\n reason,\n };\n}\n\n/**\n * Rebuild what a seat was retried from in canonical order — `source`, `error`\n * (only when present), `errorTruncated` (only when present) — on the\n * {@link projectSeatFallback} rule (#6246): the hash does not depend on how the\n * nested object's keys were ordered, and the builder shares the projection so\n * the ledger line and the hash cover the same object. The destructure is\n * exhaustive on the {@link noUnprojectedKeys} rule.\n */\nexport function projectRetriedFrom(r: VoterSummaryRetriedFrom): VoterSummaryRetriedFrom {\n const { source, error, errorTruncated, ...rest } = r;\n noUnprojectedKeys(rest);\n return {\n source,\n ...(error !== undefined ? { error } : {}),\n ...(errorTruncated !== undefined ? { errorTruncated } : {}),\n };\n}\n\n/**\n * One voter field for the canonical hash. The two nested keys are rebuilt by\n * their own projectors; every other value is a scalar and is carried as-is.\n *\n * `digestTier` (#6263) is the one place the fold depends on the record's\n * tier: on the digest tier the opening keys (text and nonce) project to\n * ABSENT and the digest is carried; on every other tier the 1.13 keys project\n * to absent and the text is carried exactly as it was — the pinned 1.7–1.12\n * goldens are the guard. The clip marker is carried on BOTH sides of the\n * swap; the nonce on NEITHER. Keyed on the tier and not on key presence so\n * that a stray digest on an old record, or a stray text on a new one, cannot\n * change what the hash covers (the schema refuses both shapes; this makes the\n * fold not depend on that refusal).\n */\nfunction projectVoterField(v: VoterSummary, key: keyof VoterSummary, digestTier: boolean): unknown {\n if (digestTier ? REASONING_OPENING_KEYS.has(key) : REASONING_TIER_KEYS.has(key)) return undefined;\n if (key === 'fallback') {\n return v.fallback === undefined ? undefined : projectSeatFallback(v.fallback);\n }\n if (key === 'retriedFrom') {\n return v.retriedFrom === undefined ? undefined : projectRetriedFrom(v.retriedFrom);\n }\n return v[key];\n}\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 optional flags are `literal(true)`,\n * so `!== undefined` is exactly the old `=== true`.\n */\nfunction projectVoterSummary(v: VoterSummary, digestTier: boolean): Partial<VoterSummary> {\n const out: Record<string, unknown> = {};\n for (const key of VOTER_SUMMARY_KEYS) {\n const value = projectVoterField(v, key, digestTier);\n if (value !== undefined) out[key] = value;\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/** A full 40-hex lowercase commit sha — an abbreviated or uppercase form is not a binding. */\nconst GIT_SHA_PATTERN = /^[0-9a-f]{40}$/;\n\n/**\n * The `{pr, headSha}` binding of a PR-ratification vote (#5130 step 1, schema\n * 1.10). `pr` is the PR number the panel ratified; `headSha` is the full head\n * commit the panel saw. Exported for the `consensus_vote` input schema and the\n * caller-commits append script, so producer, record and script validate the\n * same shape.\n */\nexport const VoteRecordPrBindingSchema = z\n .object({\n pr: z.number().int().positive(),\n headSha: z.string().regex(GIT_SHA_PATTERN, 'expected a full 40-hex lowercase commit sha'),\n })\n .strict();\nexport type VoteRecordPrBinding = z.infer<typeof VoteRecordPrBindingSchema>;\n\n/**\n * Rebuild a PR binding in canonical order — `pr`, then `headSha` — so the hash\n * does not depend on the object's key order (#3962, the `voteCounts` rule).\n * Shared with the builder (`vote-record-store.ts`) on the\n * {@link projectSeatFallback} rule: the object the ledger line carries and the\n * object the hash covers are the same projection.\n */\nexport function projectPrBinding(b: VoteRecordPrBinding): VoteRecordPrBinding {\n return { pr: b.pr, headSha: b.headSha };\n}\n\n/**\n * The error policy a panel ran under, as recorded (#6211, schema 1.11).\n * Module-private on the `SeatFallbackRecordSchema` rule: only\n * `VoteRecordSchema` consumes it. The enum is the live `ErrorPolicy`\n * (`mcp/tools/consensus-vote-types.ts`) spelled out — an `enum` rather than a\n * bare string so a record cannot claim a policy the tool never runs — and the\n * two are held equal by a type test in vote-record.test.ts, so neither side\n * can drift alone.\n */\nconst VoteRecordErrorPolicySchema = z.enum([\n 'reduce_denominator',\n 'count_as_abstain',\n 'fail_closed',\n 'absolute_quorum',\n]);\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 * '1.10' adds the optional `ratifiesPr` PR-binding (#5130); '1.11' the\n * optional `errorPolicy` (#6211); '1.12' the per-voter `retriedFrom`\n * (#6246); '1.13' the per-voter `reasoningNonce` + `reasoningDigest`\n * and — the one tier that changes what an EXISTING key means to the\n * hash — folds those instead of `reasoning` (#6263; the clip marker\n * `reasoningTruncated` stays folded). Every tier is accepted — a 1.1 record\n * (no `ratifies`) verifies unchanged because each optional is folded into\n * the self-hash ONLY when present (see {@link computeVoteRecordHash}).\n * Tiers are labels, not ordered numbers: '1.10' follows '1.9' by\n * convention only and nothing compares them.\n */\n version: z.enum([\n '1.1',\n '1.2',\n '1.3',\n '1.4',\n '1.5',\n '1.6',\n '1.7',\n '1.8',\n '1.9',\n '1.10',\n '1.11',\n '1.12',\n '1.13',\n ]),\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 * The PR this vote RATIFIES, bound to the head the panel saw (#5130 step 1,\n * schema 1.10; panel decision Q1 option A, 5 of 6). Present only on a\n * governor-path ratification vote; hash-covered like `ratifies`, so a\n * record cannot be repointed at a different PR or a later push without\n * breaking its hash. The governor gate (step 2, #5779/#5131) resolves the\n * record from the committed ledger and requires `pr` to be the PR under\n * review and `headSha` to be its head (or `head^` when `head` touches only\n * the ledger — the caller-commits tip). Absent on every pre-1.10 record.\n *\n * A SEPARATE key rather than a structured encoding of `ratifies`: that\n * field is the authority-ladder SUBJECT, compared by string equality to\n * `transition.subject` and grouped by `conflictingRatifiedSubjects`; no\n * resolver parses it. Overloading it would give one field two consumers\n * with two equality rules. The two may coexist on one record.\n */\n ratifiesPr: VoteRecordPrBindingSchema.optional(),\n /**\n * The error policy the panel actually ran under (#6211, schema 1.11): the\n * EFFECTIVE policy after `consensus_vote` applied the per-strategy default\n * (`input.errorPolicy ?? getDefaultErrorPolicy(strategy)`), not the raw\n * input the caller may have omitted. Hash-covered, present-only.\n *\n * Before this tier the policy reached the RESPONSE only, so the governor\n * ledger gate (`scripts/governor-ledger-evidence.ts`) could not say which\n * policy a whole-panel ratification was configured with: under\n * `absolute_quorum` an errored seat voids the vote, so the one\n * ledger-observable trace of a different policy was an approved record\n * with `panelCoverage.errored > 0` — and a whole panel under\n * `reduce_denominator` looked exactly like one under `absolute_quorum`.\n * The gate's `wrong-error-policy` verdict reads this field; a record\n * without it (every pre-1.11 record) keeps the panel-coverage inference\n * and is reported as `errorPolicy: unrecorded`.\n */\n errorPolicy: VoteRecordErrorPolicySchema.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 /**\n * Detached SSH signature over the committed `hash` (#3927 item 4, phase\n * 1). The SECOND field outside the self-hash, on `previousHash`'s rule\n * but for the opposite reason: `previousHash` is excluded because it is\n * positional, this because it is made OVER the hash and cannot be inside\n * it. Present-only; absent on every record appended before phase 2 and\n * on any appended without a configured signing key.\n *\n * NOT a schema tier. `version` is hash-covered, and the signature is\n * applied after the committed hash is final (the append script\n * re-sequences, re-hashes, then signs), so a signed 1.11 record is still a\n * 1.11 record and hashes identically with or without this field. A record\n * that lacks it is `unsigned-record` to the verifier\n * (`vote-record-signature.ts`), and the gate reports that informationally\n * until the phase-3 cutover constant makes it a refusal.\n */\n signature: VoteRecordSignatureSchema.optional(),\n /**\n * SHA-256 over every field above EXCEPT `previousHash` and `signature`\n * (and except `hash`).\n */\n hash: z.string().length(64),\n })\n .strict()\n // #6263: the reasoning-commitment keys are tier-bound (see\n // `reasoningCommitmentShapeDefect`). A record that breaks the rule would\n // carry a field its hash does not cover, so the line is refused at write\n // time (#6054) and by every reader, at the voter key that is wrong.\n .superRefine((record, ctx) => {\n const digestTier = isReasoningDigestTier(record.version);\n for (const [i, v] of record.voters.entries()) {\n const defect = reasoningCommitmentShapeDefect(digestTier, v);\n if (defect !== null) {\n ctx.addIssue({ code: 'custom', path: ['voters', i, defect.key], message: defect.message });\n }\n }\n });\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 const withRatifies =\n payload.ratifies !== undefined ? { ...withPanel, ratifies: payload.ratifies } : withPanel;\n // `ratifiesPr` (#5130, schema 1.10) follows on the same rule: present-only,\n // after `ratifies`, rebuilt field-by-field (`pr`, then `headSha`) so the\n // hash does not depend on the binding's key order. Absent ⇒ byte-identical\n // to the 1.9 form; the pinned 1.9 golden is the guard.\n const withPrBinding =\n payload.ratifiesPr !== undefined\n ? { ...withRatifies, ratifiesPr: projectPrBinding(payload.ratifiesPr) }\n : withRatifies;\n // `errorPolicy` (#6211, schema 1.11) is the LAST key: present-only, after\n // `ratifiesPr`, a scalar carried as-is. Absent ⇒ byte-identical to the 1.10\n // form; the pinned 1.10 golden is the guard.\n return payload.errorPolicy !== undefined\n ? { ...withPrBinding, errorPolicy: payload.errorPolicy }\n : withPrBinding;\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, and it EXCLUDES `signature`,\n * which is made over the hash and so cannot be inside it. 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. On the digest tier (#6263, schema 1.13) the\n // entry folds `reasoningDigest` INSTEAD of the text, and the salt\n // `reasoningNonce` stays outside the hash with the text (the clip marker\n // stays folded); the text is bound by the digest, which\n // `verifyVoteRecordSet` re-opens with the nonce.\n voters: payload.voters.map((v) =>\n projectVoterSummary(v, isReasoningDigestTier(payload.version))\n ),\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) — and `redacted`, the\n * per-record third answer (#6264): each record whose voter openings were\n * dropped under a redaction record that names it. On failure it names the\n * tamper/omission signal: `hash_mismatch` (a record's content was edited, or\n * an opening is absent with NO redaction record naming it — the empty case),\n * `missing_hash` (a record carries no hash), `sequence_gap` (a record is\n * missing from the 0..maxSeq run — an omission), or `redaction_unbound` (a\n * redaction record names nothing it can bind to; `recordIndex` then indexes\n * the REDACTIONS array, as the detail says).\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 /** Every record verified — vote records AND redaction records. */\n recordCount: number;\n forks?: number[];\n /** Present only when at least one record is redacted; never `[]`. */\n redacted?: readonly RedactedRecordReport[];\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 | VoteRecordVerificationFailure;\n\n/** The failure branch of {@link VoteRecordVerification}. */\ninterface VoteRecordVerificationFailure {\n ok: false;\n reason: 'hash_mismatch' | 'missing_hash' | 'sequence_gap' | RedactionFailureReason;\n recordIndex: number;\n recordId: string;\n detail: string;\n}\n\n/** One failure, spelled once. */\nfunction fail(\n reason: VoteRecordVerificationFailure['reason'],\n recordIndex: number,\n recordId: string,\n detail: string\n): VoteRecordVerificationFailure {\n return { ok: false, reason, recordIndex, recordId, detail };\n}\n\n/** No roles: what a record no redaction record names is checked against. */\nconst NO_ROLES: ReadonlySet<string> = new Set();\n\n/**\n * Per-record self-hash check; null when the record passes. `redactedRoles`\n * are the voter roles the set's redaction records name on THIS record\n * (#6264) — the commitment check admits an opening-less digest for exactly\n * those roles and refuses it for every other.\n */\nfunction verifyVoteRecord(\n record: VoteRecord,\n index: number,\n redactedRoles: ReadonlySet<string>\n): VoteRecordVerificationFailure | null {\n const at = `record at index ${String(index)}`;\n if (record.hash.length === 0) return fail('missing_hash', index, record.id, `${at} has no hash`);\n const recomputed = computeVoteRecordHash(record);\n if (recomputed !== record.hash) {\n const detail = `${at} stored hash=${record.hash} does not match recomputed=${recomputed}`;\n return fail('hash_mismatch', index, record.id, detail);\n }\n // #6263: on the digest tier the hash above cannot see the reasoning text\n // or its nonce, so the commitment is re-opened here. Reported as\n // `hash_mismatch`, not a fourth reason: it is the same fact — a stored\n // field no longer matches what the record attests — and every consumer of\n // the reason set keeps its meaning. An opening dropped under a redaction\n // record naming the entry is not a defect (#6264); dropped under none, it is.\n const commitment = findReasoningCommitmentDefect(record, redactedRoles);\n if (commitment !== null) {\n return fail(\n 'hash_mismatch',\n index,\n record.id,\n `${at} reasoning commitment broken: ${commitment}`\n );\n }\n return null;\n}\n\n/**\n * Verify a tamper-evident SET of vote records (#3927) and the redaction\n * records that name them (#6264). For each record, the self-hash must\n * recompute from its payload (covers `sequence`, excludes `previousHash`).\n * Order of the arrays does NOT matter — it is a set, not a 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 * - A digest-tier voter entry whose opening (text + nonce) is absent is\n * `redacted` when a redaction record names its record id and role, and is\n * reported as such on the success result; absent with NO such record it is\n * `hash_mismatch` (the named empty case). A redaction record that names\n * nothing it can bind to → `redaction_unbound`, never ok. The target's\n * hash is unchanged by a redaction, so a signature over it still verifies.\n * - The set of sequence numbers — vote AND redaction records — sorted, must\n * cover `0..maxSeq` with no missing value. A GAP (an omitted/deleted record)\n * → `sequence_gap` naming the first 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. `redactions` defaults to none, which is\n * fail-closed: a caller that omits them reads a redacted ledger as\n * `hash_mismatch` (and its redaction lines as a `sequence_gap`), never as ok.\n */\nexport function verifyVoteRecordSet(\n records: readonly VoteRecord[],\n redactions: readonly RedactionRecord[] = []\n): VoteRecordVerification {\n // 1) Self-hash every record (order-independent), each against the roles\n // the redaction records name on it.\n const redactedRoles = redactedRolesByTarget(redactions);\n for (let i = 0; i < records.length; i++) {\n const record = records[i] as VoteRecord;\n const failure = verifyVoteRecord(record, i, redactedRoles.get(record.id) ?? NO_ROLES);\n if (failure !== null) return failure;\n }\n // 2) Redaction records: self-hash, then bind each to a redacted commitment.\n const redaction = findRedactionDefect(redactions, records);\n if (redaction !== null) return { ok: false, ...redaction };\n\n if (records.length === 0) return { ok: true, recordCount: 0, notVerified: 'empty' };\n\n // 3) Sequence coverage over BOTH kinds: 0..maxSeq with no gap (omission);\n // forks are benign.\n const census = censusSequences([...records, ...redactions]);\n const gap = firstSequenceGap(census);\n if (gap !== null) {\n const detail = `sequence gap: missing sequence ${String(gap)} in run 0..${String(census.maxSeq)}`;\n return fail('sequence_gap', 0, (records[0] as VoteRecord).id, detail);\n }\n\n const forks = forkSequences(census);\n const redacted = redactedRecordReports(records, redactions);\n return {\n ok: true,\n recordCount: records.length + redactions.length,\n ...(forks.length > 0 ? { forks } : {}),\n ...(redacted.length > 0 ? { redacted } : {}),\n };\n}\n","/**\n * nexus-agents/audit - Reasoning commitment for the vote record (#6263,\n * #5748 step 1; panel decision 2026-09-14, option A amended with a salt)\n *\n * The committed governance ledger holds each voter's model-written reasoning\n * INSIDE the record hash, so nothing can ever be removed from it without a\n * `hash_mismatch`. On the digest tier (schema 1.13) a voter entry instead\n * carries a per-entry salt, `reasoningNonce`, and a commitment to the text,\n * `reasoningDigest = sha256(reasoningNonce ‖ reasoning)`; the record hash\n * folds ONLY the digest. The OPENING — the text AND the nonce — travels on\n * the record outside the hash, and the verifier re-opens the commitment\n * whenever both are present — so while the opening is there the tier is\n * exactly as tamper-evident as the one before it (editing text or nonce\n * alone breaks the re-opening; editing both to another opening is a second\n * preimage), and when a redaction drops text and nonce together (#6264)\n * the original hash, and any signature over it, still verifies.\n *\n * The salt is the contrarian's amendment, and it is the SECRET, which is why\n * it must be outside the hash (#6274 panel 1 rejected the fold that hashed\n * it): an unsalted or public-salted digest over low-entropy boilerplate\n * prose is dictionary-attackable once the plaintext is gone —\n * `sha256(nonce ‖ guess)` confirms the guess — while a hashed salt could not\n * be dropped at redaction without breaking the hash and the signature. With\n * the 256-bit nonce dropped alongside the text the digest is an opaque\n * commitment: no offline guessing. One fresh nonce per ENTRY, not per record,\n * so two seats that answered with the same boilerplate do not reveal it\n * through equal digests.\n *\n * Split out of `vote-record.ts` when the tier pushed that file past the\n * line cap. Structural parameter types (not `VoterSummary`) so this module\n * imports nothing from the record module and there is no cycle.\n *\n * @module audit/reasoning-commitment\n */\n\nimport * as crypto from 'node:crypto';\n\n/** A 32-byte value as lowercase hex — the shape of `reasoningNonce` and `reasoningDigest`. */\nexport const HEX_256_PATTERN = /^[0-9a-f]{64}$/;\n\n/**\n * A fresh per-entry salt for the reasoning commitment: 32 bytes from\n * `crypto.randomBytes`, as lowercase hex.\n */\nexport function mintReasoningNonce(): string {\n return crypto.randomBytes(32).toString('hex');\n}\n\n/**\n * The commitment a digest-tier voter entry makes to its reasoning:\n * `sha256(reasoningNonce ‖ reasoning)`, over the UTF-8 bytes of the 64-char\n * hex nonce followed by the UTF-8 bytes of the text AS STORED (already\n * clipped by `clipForRecord`), so anyone can re-open it from the record\n * alone: `printf '%s%s' \"$nonce\" \"$reasoning\" | sha256sum`. The nonce is\n * fixed-width, so the concatenation is unambiguous.\n */\nexport function computeReasoningDigest(reasoningNonce: string, reasoning: string): string {\n return crypto.createHash('sha256').update(reasoningNonce).update(reasoning).digest('hex');\n}\n\n/**\n * The tiers whose voter hash folds the salted reasoning digest instead of the\n * text. A set, not an equality, so a later tier can keep the same fold rule\n * without a version comparison (step 2, #6264, needed no new tier: a redacted\n * record keeps its version because the hash covers it). Tiers are labels:\n * membership here is the ONLY thing that decides the fold, so an older record\n * is never re-projected by a version comparison.\n */\nconst REASONING_DIGEST_TIERS: ReadonlySet<string> = new Set(['1.13']);\n\n/** True when `version` is a tier whose voter hash folds the digest, not the text. */\nexport function isReasoningDigestTier(version: string): boolean {\n return REASONING_DIGEST_TIERS.has(version);\n}\n\n/** The three voter fields the commitment rule reads; every other field is irrelevant to it. */\nexport interface ReasoningCommitmentFields {\n readonly role: string;\n readonly reasoning?: string | undefined;\n readonly reasoningNonce?: string | undefined;\n readonly reasoningDigest?: string | undefined;\n}\n\n/** A broken commitment SHAPE, at the voter key that is wrong. */\nexport interface ReasoningCommitmentShapeDefect {\n readonly key: 'reasoning' | 'reasoningNonce' | 'reasoningDigest';\n readonly message: string;\n}\n\n/** On a text-hashing tier the digest keys are unhashed decoration: neither may be present. */\nfunction textTierShapeDefect(v: ReasoningCommitmentFields): ReasoningCommitmentShapeDefect | null {\n if (v.reasoningNonce !== undefined) {\n return { key: 'reasoningNonce', message: 'reasoningNonce is a 1.13 key' };\n }\n if (v.reasoningDigest !== undefined) {\n return { key: 'reasoningDigest', message: 'reasoningDigest is a 1.13 key' };\n }\n return null;\n}\n\n/**\n * On the digest tier two rules hold the keys together. The OPENING rule:\n * text ⇔ nonce — both present or both absent, because the two are opened and\n * dropped as one (a text without its salt cannot be re-opened; a salt without\n * its text opens nothing). The COMMITMENT rule: any entry that has reasoning\n * carries `reasoningDigest`, the one hash-covered key. A digest with NO\n * opening at all (text and nonce both absent) is a SHAPE this tier admits\n * (#6264): it is what a redacted entry looks like, and whether it IS one is\n * not a question of shape — {@link findReasoningCommitmentDefect} answers it\n * from the redaction records in the set, and refuses it when none names the\n * entry.\n */\nfunction digestTierShapeDefect(\n v: ReasoningCommitmentFields\n): ReasoningCommitmentShapeDefect | null {\n const hasText = v.reasoning !== undefined;\n const hasNonce = v.reasoningNonce !== undefined;\n if (hasText && !hasNonce) {\n return { key: 'reasoningNonce', message: 'reasoning without its reasoningNonce' };\n }\n if (hasNonce && !hasText) {\n return { key: 'reasoning', message: 'reasoningNonce without the reasoning it opens' };\n }\n if (hasText && v.reasoningDigest === undefined) {\n return { key: 'reasoningDigest', message: 'reasoning without its reasoningDigest' };\n }\n return null;\n}\n\n/**\n * What a voter entry's reasoning commitment must look like on its tier, or\n * `null` when it does. One rule, two consumers: the record schema's\n * refinement turns a defect into a parse issue at the named key (so the\n * write path and every reader refuse the line), and the verifier turns it\n * into a `hash_mismatch` (so a typed record that never went through the\n * schema still cannot verify).\n */\nexport function reasoningCommitmentShapeDefect(\n digestTier: boolean,\n v: ReasoningCommitmentFields\n): ReasoningCommitmentShapeDefect | null {\n return digestTier ? digestTierShapeDefect(v) : textTierShapeDefect(v);\n}\n\n/**\n * The first voter entry whose reasoning commitment is broken, as a message\n * naming the entry, or `null` when every commitment is sound.\n *\n * Three checks per entry: the shape rule ({@link reasoningCommitmentShapeDefect});\n * when nonce and text are both present, the commitment itself,\n * `reasoningDigest === sha256(nonce ‖ reasoning)`; and when the digest is\n * present with NO opening, that `redactedRoles` names the entry's role —\n * the roles the redaction records in the set name on THIS record (#6264).\n * The last is the named empty case: an opening gone with nothing recording\n * its removal is the defect, not a redaction. On the digest tier the record\n * hash cannot see the text OR the nonce, so THIS is what makes a text or\n * nonce edited or dropped in place a verification failure rather than a\n * silent change: the hash still matches, the commitment does not. A digest\n * nobody re-opens would be a check that cannot fail.\n *\n * Used by `verifyVoteRecordSet` and by the caller-commits append script,\n * which vets a source record's self-hash alone (its sequence census would\n * misread a lone record) and needs the same commitment check so an edited\n * text is refused BEFORE the committed line is written, not by the\n * read-back afterwards. `redactedRoles` is REQUIRED so every caller states\n * what it knows: the append script passes the empty set, because a record\n * copied into the committed ledger must carry its openings.\n */\nexport function findReasoningCommitmentDefect(\n record: {\n readonly version: string;\n readonly voters: readonly ReasoningCommitmentFields[];\n },\n redactedRoles: ReadonlySet<string>\n): string | null {\n const digestTier = isReasoningDigestTier(record.version);\n for (const [i, v] of record.voters.entries()) {\n const where = `voters[${String(i)}] (${v.role})`;\n const shape = reasoningCommitmentShapeDefect(digestTier, v);\n if (shape !== null) return `${where}: ${shape.message}`;\n if (v.reasoningNonce === undefined || v.reasoning === undefined) {\n if (v.reasoningDigest !== undefined && !redactedRoles.has(v.role)) {\n return `${where}: reasoning commitment with its opening absent and no redaction record naming it (#6264)`;\n }\n continue;\n }\n const recomputed = computeReasoningDigest(v.reasoningNonce, v.reasoning);\n if (recomputed !== v.reasoningDigest) {\n return (\n `${where}: stored reasoningDigest=${String(v.reasoningDigest)} does not match ` +\n `sha256(reasoningNonce ‖ reasoning)=${recomputed} — the reasoning was edited without re-committing`\n );\n }\n }\n return null;\n}\n","/**\n * nexus-agents/audit - Redaction record for the vote ledger (#6264, #5748\n * step 2; panel decision 2026-09-14 option A amended, corrected by the #6274\n * panel so the nonce sits outside the hash)\n *\n * A REDACTION is the one sanctioned edit of a committed vote record: the\n * OPENING of a voter's reasoning commitment — the text and its salt,\n * `reasoning` + `reasoningNonce` — is dropped, and the hash-covered\n * `reasoningDigest` stays. Because the digest tier folds only the digest\n * (`vote-record.ts`, #6263), the record's hash — and any signature over it —\n * is unchanged by the drop; the 256-bit unknown salt leaves the digest an\n * opaque commitment nobody can dictionary-check.\n *\n * What makes it an EDIT rather than TAMPERING is this record: a self-hashed\n * line appended at the ledger's next `sequence` that names the target record,\n * the voter roles whose openings were dropped, who did it, when and why. The\n * verifier (`verifyVoteRecordSet`) answers `redacted` for an entry whose\n * opening is absent ONLY when a redaction record here names that record id\n * and role; the opening absent with no such record is `hash_mismatch` — the\n * named empty case — and a redaction record that names nothing it can bind\n * to (no such record, a target not at an earlier sequence, no such role, a\n * role with no commitment, or a role whose opening is still present) is\n * `redaction_unbound`, never ok.\n *\n * What a redaction does NOT remove: the tally, the decision, the clip marker\n * `reasoningTruncated`, and the digest all stay hash-covered and legible; and\n * nothing here touches git history — a plaintext already committed stays in\n * earlier commits until a history rewrite the ledger tooling does not perform\n * (#6265's README states this).\n *\n * Structural parameter types (`ReasoningCommitmentFields`, not `VoterSummary`)\n * so this module imports nothing from the record module and there is no cycle.\n *\n * @module audit/redaction-record\n */\n\nimport * as crypto from 'node:crypto';\n\nimport { z } from 'zod';\n\nimport type { ReasoningCommitmentFields } from './reasoning-commitment.js';\nimport { VoteRecordSignatureSchema } from './record-signature-schema.js';\n\n/**\n * One redaction. `kind` is the ledger-line discriminator: a vote record has\n * no `kind`, so the parser routes a `kind: 'redaction'` line here and every\n * other line to `VoteRecordSchema`. `targetVoterRoles` is `.min(1)` because a\n * redaction that names no role redacts nothing — the empty redaction is\n * refused, not accepted as a no-op. `.strict()` on the record-schema rule: an\n * unknown key would be a field the hash does not cover.\n */\nexport const RedactionRecordSchema = z\n .object({\n kind: z.literal('redaction'),\n /** Unique record id, on the vote-record rule. */\n id: z.string().min(1),\n /** Monotonic sequence number, shared with the vote records of the same ledger. */\n sequence: z.number().int().nonnegative(),\n /** The `id` of the vote record whose entries were redacted. */\n targetId: z.string().min(1),\n /** The voter roles on the target whose openings were dropped; never empty. */\n targetVoterRoles: z.array(z.string().min(1).max(100)).min(1),\n /** ISO-8601 timestamp of the redaction. */\n at: z.string().min(1),\n /** Who sanctioned it — author-typed, on the residual-trust boundary of every record. */\n by: z.string().min(1).max(200),\n /** Why. Bounded so the reason cannot itself become the thing that needs redacting. */\n reason: z.string().min(1).max(2000),\n /** SHA-256 over every field above. */\n hash: z.string().length(64),\n /**\n * Optional SSH signature over `hash`, OUTSIDE the hash (#6372) — the same\n * envelope a vote record carries, verified by `vote-record-signature.ts`\n * at the record's `at`. A signed and an unsigned redaction hash the same.\n */\n signature: VoteRecordSignatureSchema.optional(),\n })\n .strict();\nexport type RedactionRecord = z.infer<typeof RedactionRecordSchema>;\n\n/** The payload fields (everything except `hash` and `signature`) — the self-hash projection. */\nexport type RedactionRecordPayload = Omit<RedactionRecord, 'hash' | 'signature'>;\n\n/**\n * SHA-256 over the canonical projection, built field-by-field in schema order\n * (never `JSON.stringify(record)`) so the hash is independent of key insertion\n * order — the `computeVoteRecordHash` rule (#3962). `targetVoterRoles` is\n * folded in the order written: reordering the roles of a persisted redaction\n * is an edit and reads as one.\n */\nexport function computeRedactionRecordHash(payload: RedactionRecordPayload): string {\n const canonical = JSON.stringify({\n kind: payload.kind,\n id: payload.id,\n sequence: payload.sequence,\n targetId: payload.targetId,\n targetVoterRoles: [...payload.targetVoterRoles],\n at: payload.at,\n by: payload.by,\n reason: payload.reason,\n });\n return crypto.createHash('sha256').update(canonical).digest('hex');\n}\n\n/** Build a self-hashed redaction record. The producer (`scripts/redact-vote-record.ts`, #6265) and the tests share this one constructor. */\nexport function buildRedactionRecord(\n input: Omit<RedactionRecordPayload, 'kind' | 'targetVoterRoles'> & {\n readonly targetVoterRoles: readonly string[];\n }\n): RedactionRecord {\n const payload: RedactionRecordPayload = {\n kind: 'redaction',\n id: input.id,\n sequence: input.sequence,\n targetId: input.targetId,\n targetVoterRoles: [...input.targetVoterRoles],\n at: input.at,\n by: input.by,\n reason: input.reason,\n };\n return { ...payload, hash: computeRedactionRecordHash(payload) };\n}\n\n/**\n * Drop the OPENING — `reasoning` and `reasoningNonce`, together — of every\n * voter entry whose role is in `roles`; every other entry, and every other\n * key of a named entry (the digest, the clip marker, the tally fields), is\n * returned as-is. This is the whole edit a redaction makes to a vote record;\n * the record hash does not change (`computeVoteRecordHash` folds neither key\n * on the digest tier).\n */\nexport function redactVoterOpenings<V extends ReasoningCommitmentFields>(\n voters: readonly V[],\n roles: ReadonlySet<string>\n): Omit<V, 'reasoning' | 'reasoningNonce'>[] {\n return voters.map((v) => {\n if (!roles.has(v.role)) return v;\n const { reasoning: _reasoning, reasoningNonce: _reasoningNonce, ...rest } = v;\n return rest;\n });\n}\n\n/** The reasons a redaction record can fail; `verifyVoteRecordSet` folds them into its reason set. */\nexport type RedactionFailureReason = 'hash_mismatch' | 'missing_hash' | 'redaction_unbound';\n\n/** A failed redaction record, shaped like the verifier's failure minus `ok`. */\nexport interface RedactionVerificationFailure {\n readonly reason: RedactionFailureReason;\n /** Index into the REDACTIONS array the verifier was given; the detail says so. */\n readonly recordIndex: number;\n readonly recordId: string;\n readonly detail: string;\n}\n\n/**\n * One verified record's redaction state, reported per record on an `ok`\n * verification — the third answer beside ok and `hash_mismatch` (#6264).\n * `voterRoles` are the roles whose openings are gone, sorted and unique;\n * `redactionIds` every redaction record that names this record, in the order\n * given (two records naming the same entry are idempotent — see\n * {@link findRedactionDefect}).\n */\nexport interface RedactedRecordReport {\n readonly recordId: string;\n readonly voterRoles: readonly string[];\n readonly redactionIds: readonly string[];\n}\n\n/** What the binding rule reads off a target record. */\ninterface RedactionTarget {\n readonly id: string;\n readonly sequence: number;\n readonly voters: readonly ReasoningCommitmentFields[];\n}\n\n/** The roles every redaction record names, keyed by target record id. */\nexport function redactedRolesByTarget(\n redactions: readonly RedactionRecord[]\n): ReadonlyMap<string, ReadonlySet<string>> {\n const byTarget = new Map<string, Set<string>>();\n for (const r of redactions) {\n const roles = byTarget.get(r.targetId) ?? new Set<string>();\n for (const role of r.targetVoterRoles) roles.add(role);\n byTarget.set(r.targetId, roles);\n }\n return byTarget;\n}\n\n/**\n * Why one redaction record does not bind to a redacted commitment, or `null`\n * when it does. A redaction binds when its target exists AT AN EARLIER\n * SEQUENCE and EVERY named role is a voter on it whose entry carries\n * `reasoningDigest` with the opening (text and nonce) ABSENT. Anything else\n * is a record that claims a removal the ledger does not show: no such\n * record, a target at or past the redaction's own sequence (an honest ledger\n * appends the redaction only after the target is committed, so this order\n * cannot be produced — #6345), no such role, a role that never had a\n * commitment, or — the misreport — a role whose text is still there. A\n * second redaction naming an already-redacted entry binds\n * exactly as the first did (idempotent): two branches can each append one\n * and merge under `merge=union`, and refusing that would make a merged\n * ledger invalid for doing the right thing twice.\n */\nfunction redactionBindingDefect(\n r: RedactionRecord,\n targets: readonly RedactionTarget[]\n): string | null {\n const matched = targets.filter((t) => t.id === r.targetId);\n if (matched.length === 0) return `targetId '${r.targetId}' matches no record in the set`;\n for (const target of matched) {\n if (target.sequence >= r.sequence) {\n return `at sequence ${String(r.sequence)} is not past its target '${target.id}' at sequence ${String(target.sequence)} — a redaction can only follow the record it redacts`;\n }\n for (const role of r.targetVoterRoles) {\n const entries = target.voters.filter((v) => v.role === role);\n if (entries.length === 0) {\n return `names role '${role}', which is not a voter on '${target.id}'`;\n }\n for (const v of entries) {\n if (v.reasoningDigest === undefined) {\n return `names role '${role}' on '${target.id}', which carries no reasoning commitment`;\n }\n if (v.reasoning !== undefined || v.reasoningNonce !== undefined) {\n return `names role '${role}' on '${target.id}' whose opening is still present — the redaction is recorded but not applied`;\n }\n }\n }\n }\n return null;\n}\n\n/**\n * The first redaction record that fails, or `null` when every one passes.\n * Two checks per record: its own self-hash (a redaction record is tamper-\n * evident like every other line — `missing_hash` / `hash_mismatch`), then\n * the binding rule ({@link redactionBindingDefect}) → `redaction_unbound`.\n * Self-hashes are checked for ALL records before any binding, so a tampered\n * line is named as tampered rather than as unbound.\n */\nexport function findRedactionDefect(\n redactions: readonly RedactionRecord[],\n targets: readonly RedactionTarget[]\n): RedactionVerificationFailure | null {\n for (const [i, r] of redactions.entries()) {\n const at = `redaction record at index ${String(i)}`;\n if (r.hash.length === 0) {\n return {\n reason: 'missing_hash',\n recordIndex: i,\n recordId: r.id,\n detail: `${at} has no hash`,\n };\n }\n const recomputed = computeRedactionRecordHash(r);\n if (recomputed !== r.hash) {\n return {\n reason: 'hash_mismatch',\n recordIndex: i,\n recordId: r.id,\n detail: `${at} stored hash=${r.hash} does not match recomputed=${recomputed}`,\n };\n }\n }\n for (const [i, r] of redactions.entries()) {\n const defect = redactionBindingDefect(r, targets);\n if (defect !== null) {\n return {\n reason: 'redaction_unbound',\n recordIndex: i,\n recordId: r.id,\n detail: `redaction record '${r.id}' at index ${String(i)} ${defect}`,\n };\n }\n }\n return null;\n}\n\n/**\n * The per-record `redacted` reports for a set whose redactions all bind:\n * one per target record, in the order the RECORDS were given, naming the\n * roles (sorted, unique) and every redaction record that names it.\n */\nexport function redactedRecordReports(\n records: readonly { readonly id: string }[],\n redactions: readonly RedactionRecord[]\n): RedactedRecordReport[] {\n const roles = redactedRolesByTarget(redactions);\n const reports: RedactedRecordReport[] = [];\n for (const record of records) {\n const named = roles.get(record.id);\n if (named === undefined) continue;\n reports.push({\n recordId: record.id,\n voterRoles: [...named].sort(),\n redactionIds: redactions.filter((r) => r.targetId === record.id).map((r) => r.id),\n });\n }\n return reports;\n}\n","/**\n * The signature envelope every committed ledger record — a vote record\n * (`vote-record.ts`) or a redaction record (`redaction-record.ts`, #6372) —\n * may carry OUTSIDE its hash. Lives in its own module because both record\n * modules import it and `vote-record.ts` already imports `redaction-record.ts`.\n *\n * @module audit/record-signature-schema\n */\nimport { z } from 'zod';\n\n/**\n * The `ssh-keygen -Y` namespace every vote-record signature is made and\n * verified under (#3927 item 4). A namespace binds a signature to ONE\n * purpose: a key that also signs git commits (`git`) or files (`file`) cannot\n * have one of those signatures replayed as a ratification, and the committed\n * `governance/allowed_signers` restricts the operator's key to this namespace\n * alone. Pinned by a literal test; a drift here turns every existing\n * signature into `bad-signature` (ssh-keygen: \"namespace does not match\").\n */\nexport const VOTE_RECORD_SIGNATURE_NAMESPACE = 'nexus-vote-record';\n\n/**\n * A detached SSH signature over the record's committed `hash` (#3927 item 4,\n * phase 1; panel decision option B, 5 of 6).\n *\n * `keyId` is the principal the signature claims — the identity the verifier\n * looks up in `governance/allowed_signers` (`ssh-keygen -Y verify -I`).\n * `namespace` is the literal above, carried on the record so a reader can see\n * what the signature was made under without re-deriving it. `sig` is the\n * armored `-----BEGIN SSH SIGNATURE-----` block exactly as `ssh-keygen -Y\n * sign` emits it.\n *\n * The SIGNED MESSAGE IS THE `hash` STRING (64 lowercase hex characters, no\n * newline) — never a re-serialised JSON form of the record. The #3927 re-vote's\n * contrarian objected that JSON canonicalisation is brittle across runtimes;\n * signing the hash makes that moot, because one TypeScript projection already\n * produces the hash and every gate consumes it, and a second verifier in any\n * language verifies the signature over that string without re-canonicalising.\n * Signing the hash also signs everything the hash covers, `sequence` included,\n * so the chain position is signed too.\n */\nexport const VoteRecordSignatureSchema = z\n .object({\n /** The allowed_signers principal, e.g. `williamzujkowski@nexus-agents`. */\n keyId: z.string().min(1).max(200),\n namespace: z.literal(VOTE_RECORD_SIGNATURE_NAMESPACE),\n /** The armored SSH signature block, verbatim. */\n sig: z.string().min(1).max(8192),\n })\n .strict();\nexport type VoteRecordSignature = z.infer<typeof VoteRecordSignatureSchema>;\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, RetriedFrom } from './vote-types.js';\nimport type { ILogger } from '../core/index.js';\nimport { clipForRecord } from '../audit/vote-record.js';\nimport { sleep } from '../utils/async-utils.js';\nimport { isAbsentSeat } from './voter-unverifiable.js';\n\n/**\n * C0 and C1 control characters, DEL included (#6246, security seat; the C1\n * range on the #6252 panel's rejection — `\\x9b` is the single-byte CSI,\n * equivalent to `ESC [`, so an ASCII-only range still let a terminal escape\n * through). A first-pass error string can be a subprocess's stderr; each of\n * these becomes one space so the carried cause cannot inject a line into the\n * summary row or the JSONL ledger line, nor an escape sequence into the\n * terminal.\n */\nconst CONTROL_CHARS_RE = /[\\x00-\\x1f\\x7f-\\x9f]/g;\n\n/**\n * What the retry is about to discard, carried onto the seat that replaces it\n * (#6246). `source` is the first pass's; `error` is its error string when it\n * had one — de-controlled, then bounded by the #5373 record clip so the marker\n * travels with it rather than a silent slice. Called only at the discard site,\n * so a seat that was never retried, or whose retry failed again, has no key.\n */\nfunction retriedFromOf(first: AgentVoteResult): RetriedFrom {\n const source = first.source === 'unverifiable' ? 'unverifiable' : 'error';\n if (first.error === undefined) return { source };\n const { text, truncated } = clipForRecord(first.error.replace(CONTROL_CHARS_RE, ' '));\n return { source, error: text, ...(truncated === true ? { errorTruncated: true as const } : {}) };\n}\n\n/**\n * Backoff before retrying an errored voter role (#5578).\n *\n * Short on purpose: a voter at `source: 'error'` has already exhausted the\n * resilient adapter's own retries and breaker, so this is not a backoff for\n * that adapter — it is a gap for a transient panel-wide condition (a rate\n * limit window, a stalled gateway) to clear.\n */\nexport const DEFAULT_ERRORED_ROLE_BACKOFF_MS = 3000;\n\n/**\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 firstByRole = new Map(first.map((v) => [v.role, v]));\n const recovered = new Map<VoterRole, AgentVoteResult>();\n for (const r of retriedResults) {\n if (r.source === 'error') continue;\n // #6246: this is where the first pass is discarded — carry what it was\n // before it goes, so the seat names both what it is and what it recovered\n // from. Every relaunched role has an absent first pass; the guard holds\n // the relaunch to that contract rather than carrying a `source` the first\n // pass never had.\n const prior = firstByRole.get(r.role);\n const from = prior !== undefined && isAbsentSeat(prior) ? retriedFromOf(prior) : undefined;\n recovered.set(r.role, {\n ...r,\n retried: true,\n ...(from !== undefined ? { retriedFrom: from } : {}),\n });\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 * Codex CLI subagent limits (#2659, Epic D).\n *\n * Codex's `~/.codex/config.toml` `[agents]` section defaults to\n * `max_depth = 1` and `max_threads = 6` (verified against\n * developers.openai.com/codex config reference — the originating issue's\n * `max_thread_depth` key name was wrong).\n *\n * nexus-agents does NOT write the operator's global `~/.codex/config.toml`\n * (that would clobber operator-owned state) and does NOT silently\n * auto-flatten routing topology. Instead — Option C from the #2659 design\n * vote — it WARNS at fan-out time when a planned concurrency would exceed\n * Codex's defaults, so the operator can raise their own `[agents]` limits\n * or spread the panel across more CLIs. The two existing parallel-dispatch\n * sites are already conservative: `worker-dispatcher.ts` caps a wave at 3\n * concurrent workers, and `collectRealVotes` round-robins voter roles\n * across available CLIs. The warned case is the narrow one — a single-CLI\n * fallback where every voter role lands on Codex.\n *\n * @module cli-adapters/codex-limits\n * @see Issue #2659\n */\n\n/** Codex `[agents] max_depth` default — nested subagent depth. */\nexport const CODEX_DEFAULT_MAX_DEPTH = 1;\n\n/** Codex `[agents] max_threads` default — concurrent subagent threads. */\nexport const CODEX_DEFAULT_MAX_THREADS = 6;\n\n/**\n * A structured warning when `codexBoundConcurrency` parallel calls are\n * about to be dispatched to Codex, exceeding its default `max_threads`.\n * Returns `null` when within limits. Does not block — the operator stays\n * in control (Option C).\n */\nexport function checkCodexConcurrency(codexBoundConcurrency: number): string | null {\n if (codexBoundConcurrency <= CODEX_DEFAULT_MAX_THREADS) return null;\n return (\n `${String(codexBoundConcurrency)} parallel calls are bound for Codex, exceeding its ` +\n `default max_threads=${String(CODEX_DEFAULT_MAX_THREADS)}. Codex may queue or drop the ` +\n `excess. Raise [agents] max_threads in ~/.codex/config.toml, or spread the panel across ` +\n `more CLIs (claude/gemini) so fewer roles land on Codex.`\n );\n}\n\n// @export-no-consumer-yet — see #4555. Its sibling `checkCodexConcurrency` is\n// wired at `cli/voter-agents.ts:307`, but this one needs a *planned nesting\n// depth* and nothing in the tree tracks one: the voter fan-out is flat (voters\n// are leaf calls), and the only other `depth` values are MCTS and\n// reasoning-forest tree depths, which are unrelated concepts. So this was\n// written against information no caller has — wiring it means first\n// introducing depth tracking through the dispatch path, which is a feature and\n// not a missing line. Marked rather than deleted because the knowledge it\n// encodes (Codex `max_depth=1` rejects a nested spawn) is real and was added\n// deliberately in #2689.\n/**\n * A structured warning when a planned subagent nesting `depth` exceeds\n * Codex's default `max_depth`. Returns `null` when within limits.\n */\nexport function checkCodexDepth(depth: number): string | null {\n if (depth <= CODEX_DEFAULT_MAX_DEPTH) return null;\n return (\n `planned subagent nesting depth ${String(depth)} exceeds Codex's default ` +\n `max_depth=${String(CODEX_DEFAULT_MAX_DEPTH)}. Codex will reject the nested spawn. ` +\n `Raise [agents] max_depth in ~/.codex/config.toml, or flatten the expert chain.`\n );\n}\n","/**\n * Adapter resolution for a voter panel, and the documented no-adapter exit\n * (Issue #280): simulate when the caller explicitly allowed it, otherwise\n * throw.\n *\n * Split out of `voter-agents.ts` (#5578), which was at its 400-line cap.\n * @module cli/voter-adapter-resolve\n */\n\nimport type { IModelAdapter, ILogger } from '../core/index.js';\nimport { getErrorMessage } from '../core/index.js';\nimport { getGlobalRegistry } from '../adapters/unified-registry.js';\nimport { checkCodexConcurrency } from '../cli-adapters/codex-limits.js';\nimport type { VoterRole } from './vote-types.js';\n\n/** The adapter-bearing subset of the collect options this module needs. */\nexport interface AdapterResolveOptions {\n readonly adapter?: IModelAdapter | undefined;\n readonly gatewayAdapters?: readonly IModelAdapter[] | undefined;\n}\n\n/**\n * Error thrown when no adapter is available and simulation is disabled.\n */\nexport class NoAdapterError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'NoAdapterError';\n }\n}\n\n/**\n * Resolves the model adapter, handling errors per Issue #280.\n */\nexport function resolveAdapter(\n options: AdapterResolveOptions\n): { adapter: IModelAdapter } | { error: string } {\n try {\n if (options.adapter !== undefined) return { adapter: options.adapter };\n // #4040: prefer an in-process gateway adapter as the fallback so a\n // gateway-only environment (no CLIs installed) never hits the CLI registry,\n // which would throw \"No model adapter configured\".\n const gateway = options.gatewayAdapters;\n if (gateway !== undefined && gateway.length > 0 && gateway[0] !== undefined) {\n return { adapter: gateway[0] };\n }\n const registry = getGlobalRegistry();\n return { adapter: registry.getDefault() };\n } catch (error) {\n return { error: getErrorMessage(error) };\n }\n}\n\n/**\n * Resolve the adapter, or take the documented no-adapter exit (Issue #280):\n * simulate when the caller explicitly allowed it, otherwise throw.\n *\n * Extracted from `collectRealVotes` when #5578 pushed it past the 50-line and\n * complexity caps; behaviour is unchanged.\n */\nexport function resolveAdapterOrFail(\n options: AdapterResolveOptions,\n logger: ILogger,\n allowSimulation: boolean\n): { adapter: IModelAdapter } | { simulated: true } {\n const resolved = resolveAdapter(options);\n if (!('error' in resolved)) return resolved;\n\n logger.error('No adapter available for voting', undefined, { error: resolved.error });\n if (allowSimulation) {\n logger.warn('Falling back to simulation (allowSimulation=true)');\n return { simulated: true };\n }\n throw new NoAdapterError(\n `No adapter available for voting: ${resolved.error}. ` +\n 'Install a CLI (claude/gemini/codex) or set ANTHROPIC_API_KEY.'\n );\n}\n\n/**\n * #2659 — warn (don't block) when more voter roles land on Codex than its\n * default `max_threads`, e.g. a single-CLI fallback with a full panel.\n * Moved here from `voter-agents.ts` when the #6136/#6115 rebase put that\n * file over its line cap.\n */\nexport function warnIfCodexConcurrencyExceeded(\n roleAdapters: ReadonlyMap<VoterRole, IModelAdapter>,\n logger: ILogger\n): void {\n const codexBound = [...roleAdapters.values()].filter(\n (a) => (a as { name?: string }).name === 'codex'\n ).length;\n const warning = checkCodexConcurrency(codexBound);\n if (warning !== null) {\n logger.warn('Codex concurrency limit may be exceeded', { detail: warning });\n }\n}\n","/**\n * Per-seat fallback disclosure (#6115).\n *\n * Three consecutive 7-seat ratification panels on 2026-09-13 answered every\n * seat on one gemini model: the three claude seats fell over (#3587) during a\n * claude capacity window, the two codex seats errored and landed on the same\n * sticky default, and the two gemini seats were native. Quorum was real,\n * independence was not, and nothing in the live result said so — the assigned\n * CLI was not recoverable and the fallover reason was only in a log line.\n *\n * This module stamps the assignment on every seat and, when a seat answered\n * elsewhere, the class of error that moved it. Classification reuses the\n * predicates the adapter layer already classifies by; it adds no taxonomy of\n * its own.\n *\n * @module cli/voter-fallback\n */\n\nimport type { IModelAdapter } from '../core/index.js';\nimport { isDurableCapacityText, isRateLimitText } from '../adapters/rate-limit-detector.js';\nimport { classifyExtractedError } from '../cli-adapters/cli-error-envelope.js';\nimport { isTimeoutText } from '../cli-adapters/cli-error-helpers.js';\nimport { UNRESOLVED_MODEL_ID } from '../config/model-equivalence.js';\nimport type { AgentVoteResult, FallbackReason, SeatFallback } from './vote-types.js';\nimport { UNVERIFIABLE_STDERR_RE } from './voter-unverifiable.js';\n\n/**\n * Strip the `cli-` prefix `CliToModelAdapter` and a pinned `ResilientAdapter`\n * put on `providerId`, so a seat's assignment reads `claude`, not `cli-claude`.\n * Any other id (a gateway provider, `resilient-proxy`) is returned unchanged.\n */\nexport function bareCliName(id: string): string {\n return id.startsWith('cli-') ? id.slice('cli-'.length) : id;\n}\n\n/**\n * Classify the error that moved a seat off its assigned adapter.\n *\n * Order matters and mirrors the adapter layer: a durable capacity cap is\n * checked before the transient rate-limit list because `RATE_LIMIT_PATTERNS`\n * is the union of both (#5359), and the #6094 sandbox signature before the\n * timeout words because a sandbox failure line can mention one.\n */\nexport function classifyFallbackReason(message: string): FallbackReason {\n if (isDurableCapacityText(message)) return 'capacity';\n if (isRateLimitText(message)) return 'rate-limit';\n if (classifyExtractedError(message, 'unknown').code === 'NOT_AUTHENTICATED') return 'auth';\n if (UNVERIFIABLE_STDERR_RE.test(message)) return 'sandbox';\n if (isTimeoutText(message)) return 'timeout';\n return 'unknown';\n}\n\n/** The assigned adapter's model when it had detected one; the placeholder is not disclosed. */\nfunction detectedModel(adapter: IModelAdapter): string | undefined {\n // `unknown`, not `string`: the interface promises a string, but an adapter\n // constructed without one reports undefined at runtime (#4983).\n const id: unknown = adapter.modelId;\n return typeof id === 'string' && id !== '' && id !== UNRESOLVED_MODEL_ID ? id : undefined;\n}\n\n/**\n * The assignment key as a bare CLI name, or undefined when the adapter had\n * none. `unknown` for the same reason as {@link detectedModel}: `adapterCliKey`\n * is typed string but reads `name ?? providerId`, and a bare test adapter has\n * neither.\n */\nfunction assignedCliOf(key: unknown): string | undefined {\n return typeof key === 'string' && key !== '' ? bareCliName(key) : undefined;\n}\n\n/**\n * The cross-CLI fallover disclosure for a seat assigned to `assigned` that\n * errored with `error` and was re-run on the fallback (#3587). A seat whose\n * adapter carried no id is disclosed as `unknown` — the fallover still\n * happened and the reason is still measured.\n */\nexport function crossCliFallback(\n assigned: IModelAdapter,\n assignedKey: string,\n error: string\n): SeatFallback {\n const fromModel = detectedModel(assigned);\n return {\n fromCli: assignedCliOf(assignedKey) ?? 'unknown',\n ...(fromModel !== undefined ? { fromModel } : {}),\n reason: classifyFallbackReason(error),\n };\n}\n\n/**\n * The in-family disclosure for a seat whose CLI answered on a different model\n * alias than requested (#6120): the claude adapter substitutes the next\n * registry alias after an out-of-credits envelope, which is a capacity class\n * by construction — it is the only condition that triggers the substitution.\n */\nexport function inFamilyFallback(cli: string, fromModel: string): SeatFallback {\n return { fromCli: bareCliName(cli), fromModel, reason: 'capacity' };\n}\n\n/**\n * Stamp the seat's assignment on a result, keeping any fallback the seat\n * already carries (the in-family one is set where the answer is built).\n */\nexport function withAssignedCli(result: AgentVoteResult, assignedKey: string): AgentVoteResult {\n const assignedCli = assignedCliOf(assignedKey);\n return assignedCli === undefined ? result : { ...result, assignedCli };\n}\n","/**\n * 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(\n proposal: string,\n options?: readonly string[],\n workspace?: string,\n workspaceSha?: string\n): string {\n return `Evaluate the following proposal and provide your vote.\n\nPROPOSAL:\n${proposal}\n${buildOptionsBlock(options)}${buildWorkspaceBlock(workspace, workspaceSha)}\nIn addition to your role-specific criteria, assess these workflow-test dimensions:\n- Testability: Can the proposed changes be verified with automated tests?\n- Workflow integration: Does this fit into existing CI/make/test workflows?\n- Incremental verifiability: Can progress be measured at each step?\n\nRespond with a JSON object containing:\n- decision: \"approve\", \"reject\", or \"abstain\"\n- reasoning: Explanation for your vote (10-4000 characters). Include your workflow-test assessment.\n- confidence: Number between 0 and 1\n- conditions: Optional array of conditions for approval\n- rejectionCategories: Required when rejecting. Array of categories from: YAGNI, DRY_VIOLATION, OVER_ENGINEERING, SCOPE_CREEP, SECURITY_RISK, MISALIGNED, INSUFFICIENT_EVIDENCE\n- findings: PR-REVIEW MODE ONLY. Optional top-level array of structured findings — see \"PR-review mode\" in the system prompt. OMIT this field entirely when reviewing a non-diff proposal or when approving a diff.\n${buildSelectionFieldDoc(options)}\n${VOTE_PROMPT_EXAMPLES}`;\n}\n\n/**\n * The OPTIONS block, present only when the proposal declares options (#4472).\n *\n * Empty string when none are declared, so a proposal without options produces\n * a prompt byte-identical to the pre-#4472 one.\n */\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/**\n * The REPOSITORY ACCESS block, present only when the caller names the\n * working directory the seats run in (#6254).\n *\n * On CLI-run governor panels a gemini seat abstained \"UNVERIFIABLE: could not\n * read the artifact ... no repository or accessible sandbox was provided\"\n * while the claude seats on the same panel read the head: nothing in either\n * prompt said where the tree was or that reading it was expected. This block\n * says both. It does not weaken the UNVERIFIABLE rule — a seat whose tools\n * genuinely cannot read the directory is still told to say so — and a\n * proposal that names nothing in the repository is still judged as written.\n *\n * Empty string when no workspace is given, so a caller with no tree to offer\n * (a direct `executeAgentVote`, a unit test) produces a prompt byte-identical\n * to the two-argument form and claims nothing it cannot back.\n */\nexport function buildWorkspaceBlock(workspace?: string, workspaceSha?: string): string {\n if (workspace === undefined || workspace === '') return '';\n if (workspaceSha !== undefined && workspaceSha !== '') {\n return `\nREPOSITORY ACCESS:\nThe repository under review is a detached scratch checkout of the ratified head ${workspaceSha} at ${workspace}. It is already at that commit — do NOT run git checkout/switch/reset/pull or modify files; read only.\nEvery seat's file and shell tools run there, and reading it is expected. Read the artifact before you vote; the proposal text is not a substitute for it. If your tools cannot read that directory, follow the UNVERIFIABLE rule in your instructions.\n`;\n }\n return `\nREPOSITORY ACCESS:\nThe repository under review is the working directory of this panel: ${workspace}\nEvery seat's file and shell tools run there, and reading it is expected. When the proposal refers to something in that repository — a PR head, a diff, the files it touches — read it there before you vote: the proposal text describes the artifact and is not a substitute for it. If your tools cannot read that directory, follow the UNVERIFIABLE rule in your instructions.\n`;\n}\n\n/** The `selectedOption` field doc, present only when options are declared. */\nfunction buildSelectionFieldDoc(options?: readonly string[]): string {\n if (options === undefined || options.length === 0) return '';\n return '- selectedOption: REQUIRED. Exactly one option from the OPTIONS list above, copied verbatim. Do not invent an option, combine two, or leave it blank — your selection is what the threshold is measured over.';\n}\n\n// ============================================================================\n// Vote Response Parsing\n// ============================================================================\n\n/**\n * Extract the FIRST balanced top-level JSON object from `text`, respecting\n * string literals + escapes so braces/brackets inside strings don't miscount\n * (#4131). Returns the object substring, or undefined if no `{` is present.\n *\n * If the object is TRUNCATED (containers still open at end-of-input — e.g. a\n * large findings-bearing vote cut off by the completion token cap), it returns a\n * best-effort repair: the open string is closed and the open `{`/`[` containers\n * are closed in order. Since a well-formed vote emits `decision`/`reasoning`/\n * `confidence` before the optional `findings` array, a truncation inside\n * `findings` still yields a parseable verdict. If the repair is still invalid,\n * the caller's JSON.parse throws exactly as before (no regression).\n */\n/** Mutable scan state for {@link extractFirstJsonObject}. */\ninterface JsonScanState {\n readonly closers: string[];\n inString: boolean;\n escaped: boolean;\n}\n\ntype ScanResult = 'complete' | 'unbalanced' | 'continue';\n\n/** Handle one char while inside a JSON string literal. */\nfunction stepInString(state: JsonScanState, ch: string): void {\n if (ch === '\\\\') state.escaped = true;\n else if (ch === '\"') state.inString = false;\n}\n\n/** Handle one structural (non-string) char, tracking open/close containers. */\nfunction stepStructural(state: JsonScanState, ch: string): ScanResult {\n if (ch === '\"') state.inString = true;\n else if (ch === '{') state.closers.push('}');\n else if (ch === '[') state.closers.push(']');\n else if (ch === '}' || ch === ']') {\n if (state.closers.pop() === undefined) return 'unbalanced';\n if (state.closers.length === 0) return 'complete';\n }\n return 'continue';\n}\n\n/** Advance the balanced-object scan by one char. Returns whether the object closed / broke. */\nfunction stepJsonScan(state: JsonScanState, ch: string): ScanResult {\n if (state.escaped) {\n state.escaped = false;\n return 'continue';\n }\n if (state.inString) {\n stepInString(state, ch);\n return 'continue';\n }\n return stepStructural(state, ch);\n}\n\n/** Best-effort close of an object truncated mid-scan (open string + open containers). */\nfunction repairTruncatedObject(fragment: string, state: JsonScanState): string {\n let repaired = state.inString ? `${fragment}\"` : fragment;\n for (let i = state.closers.length - 1; i >= 0; i--) {\n const closer = state.closers[i];\n if (closer !== undefined) repaired += closer;\n }\n return repaired;\n}\n\nfunction extractFirstJsonObject(text: string): string | undefined {\n const start = text.indexOf('{');\n if (start === -1) return undefined;\n const state: JsonScanState = { closers: [], inString: false, escaped: false };\n for (let i = start; i < text.length; i++) {\n const result = stepJsonScan(state, text[i] as string);\n if (result === 'complete') return text.slice(start, i + 1);\n if (result === 'unbalanced') return undefined;\n }\n // Loop ran off the end with containers still open ⇒ truncated; repair best-effort.\n return state.closers.length > 0 ? repairTruncatedObject(text.slice(start), state) : undefined;\n}\n\n/**\n * Extracts the JSON vote object from raw LLM response text (#4131).\n *\n * Robust to the ways a voter's output shape used to silently DROP the voter:\n * 1. Prefer an explicit ` ```json ` fence.\n * 2. Otherwise scan every fenced block and use the first whose content is a\n * JSON object — so a ` ```yaml findings ` block (pr-review mode) is SKIPPED\n * instead of being handed to JSON.parse (the `Unexpected token 'y'` drop).\n * 3. Otherwise take the first balanced JSON object anywhere in the text, so a\n * verdict followed by a trailing prose / YAML block still parses, and a\n * truncated object is repaired.\n * 4. Fallback: the trimmed text (JSON.parse will surface a real malformation).\n */\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 * Text extraction for a voter's completion response — the ONE seam every seat\n * passes through before its text becomes `reasoning` on a vote record.\n * Extracted from voter-execution.ts for the per-file line cap (#6269); the\n * behaviour and its tests (voter-execution.test.ts) are unchanged.\n *\n * @module cli/voter-response-text\n */\n\nimport { sanitizeOutput } from '../security/output-sanitizer.js';\n\n/**\n * Extracts text content from completion response.\n *\n * The result is passed through `sanitizeOutput` (#6267): the subprocess\n * adapter scrubs API keys from CLI stdout, but the API adapters (gateway,\n * SDK, Claude) return raw model text, and since #6194 this string becomes\n * the `reasoning` of a record committed to the public ledger. Scrubbing here\n * bounds every seat uniformly; already-scrubbed CLI text is unchanged.\n */\nexport function extractTextFromResponse(content: unknown): string {\n return sanitizeOutput(rawTextFromResponse(content));\n}\n\nfunction rawTextFromResponse(content: unknown): string {\n if (typeof content === 'string') {\n return content;\n }\n if (Array.isArray(content)) {\n return content\n .map((block) => {\n if (typeof block === 'object' && block !== null && 'type' in block) {\n const typed = block as { type: string; text?: string };\n if (typed.type === 'text' && typeof typed.text === 'string') {\n return typed.text;\n }\n }\n return '';\n })\n .join('');\n }\n return String(content);\n}\n","/**\n * 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';\nimport { isAuthFailureText } from '../cli-adapters/cli-error-envelope.js';\nimport { sanitizeOutput } from '../security/output-sanitizer.js';\nimport { extractTextFromResponse } from './voter-response-text.js';\n\nexport { extractTextFromResponse };\n\n/** Default vote timeout. Canonical source: `config/timeouts.ts`. */\nexport const DEFAULT_VOTE_TIMEOUT_MS = VOTE_TIMEOUTS.defaultMs;\n\n/** Resolves vote timeout with env var override. Canonical: `config/timeouts.ts`. */\nexport const resolveVoteTimeout = _resolveVoteTimeout;\n\n/** Maximum vote timeout. Canonical source: `config/timeouts.ts`. */\nexport const MAX_VOTE_TIMEOUT_MS = VOTE_TIMEOUTS.maxMs;\n\n/** Minimum vote timeout. Canonical source: `config/timeouts.ts`. */\nexport const MIN_VOTE_TIMEOUT_MS = VOTE_TIMEOUTS.minMs;\n\n/** Maximum retries per vote. Canonical source: `config/timeouts.ts`. */\nexport const DEFAULT_MAX_RETRIES = VOTE_TIMEOUTS.maxRetries;\n\n/**\n * Initial retry delay in milliseconds.\n */\nconst INITIAL_RETRY_DELAY_MS = 1_000;\n\n/**\n * Retry delay for rate-limit errors in milliseconds (Issue #1319).\n * Longer than standard to respect API rate limits.\n */\nexport const RATE_LIMIT_RETRY_DELAY_MS = 5_000;\n\n/**\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 * Executes a single vote attempt (no retries).\n *\n * By default, throws SyntheticVoteError if response parsing fails.\n * This ensures we only get real LLM votes, not synthetic fallbacks.\n * (Source: Issue #512 - Fail-safe voting)\n */\n/**\n * Builds the vote completion request. `withResponseFormat` toggles the native\n * structured-output ask (#3433): on for the first attempt, off for the #3497\n * retry against backends that route `json_schema` through provider tool-use.\n * The `parseVoteResponse` regex/Zod path below accepts prose-wrapped JSON, so\n * omitting `responseFormat` is safe — it just loses the schema-enforced shape.\n */\nfunction buildVoteRequest({\n role,\n proposal,\n timeoutMs,\n withResponseFormat,\n options,\n project,\n workspace,\n workspaceSha,\n}: VoteCompletionArgs): CompletionRequest {\n const base: CompletionRequest = {\n messages: [\n // #6110: the seat judges the caller's target project, not this\n // repository's. `undefined` renders the `nexus-agents` default.\n { role: 'system', content: getVoterPrompts(project)[role] },\n // #6254: and the working directory the seats run in, so a seat with\n // file tools knows where the artifact is and that reading it is expected.\n { role: 'user', content: buildVotePrompt(proposal, options, workspace, workspaceSha) },\n ],\n // 4000 (#4131): headroom so a findings-bearing verdict (JSON envelope +\n // reasoning + structured findings) isn't cut mid-JSON by the token cap and\n // silently dropped. Was 2000 (#2245, up from 500); large contrarian findings\n // still overflowed it. Non-findings votes stop at natural completion, so the\n // higher cap adds no cost for them.\n maxTokens: 4000,\n temperature: 0.3, // Low temperature for consistent evaluations\n // Thread the vote budget so the CLI timeout doesn't fire first (#3304); pass\n // signal too for CLI-vs-API cancellation parity (#3036/#3304).\n timeoutMs,\n ...(workspace !== undefined && workspace.trim() !== '' ? { workDir: workspace } : {}),\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 * The working directory every seat's tools run in (#6254), named in the\n * user prompt. Required as a KEY for the same reason as `project`;\n * `undefined` renders no REPOSITORY ACCESS block.\n */\n readonly workspace: string | undefined;\n readonly workspaceSha?: string | undefined;\n}\n\nasync function runVoteCompletion(args: VoteCompletionArgs): Promise<\n | {\n ok: true;\n output: string;\n usage: VoteUsage;\n cliStderr: string | undefined;\n fallbackFrom: string | undefined;\n }\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 // #6115: the alias the seat asked for, when the CLI answered on another\n // one of its family (#6120) — the seat's result discloses it as a fallback.\n fallbackFrom: response.value.fallbackFrom,\n };\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 /** The requested model alias when the CLI answered on another of its family (#6120). */\n readonly fallbackFrom: string | undefined;\n}\n\n/** What the prompt carries beyond the proposal: declared options (#4472), the target project (#6110) and the working directory (#6254). */\ninterface VotePromptContext {\n readonly options?: readonly string[] | undefined;\n /** Target project for the system prompt; omitted ⇒ `nexus-agents`. */\n readonly project?: string | undefined;\n /** Working directory named in the user prompt; omitted ⇒ no REPOSITORY ACCESS block. */\n readonly workspace?: string | undefined;\n readonly workspaceSha?: string | undefined;\n}\n\n/**\n * A failed attempt. `cliStderr` is present only on the parse-failure branch —\n * the transport completed but the output was not a vote (#6269): it says WHY\n * the answer was empty. An adapter error carries its cause in `error`.\n */\ninterface VoteAttemptFailure {\n readonly ok: false;\n readonly error: string;\n readonly cliStderr?: 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 | VoteAttemptFailure> {\n const completionArgs = {\n role,\n proposal,\n adapter,\n timeoutMs,\n project: context.project,\n workspace: context.workspace,\n ...context,\n };\n let completion = await runVoteCompletion({ ...completionArgs, withResponseFormat: true });\n // #3497: retry once WITHOUT responseFormat when the backend rejects the\n // tool-use-backed structured-output ask, so the panel keeps full strength.\n if (!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, context.options);\n return {\n ok: true,\n vote,\n output: completion.output,\n usage: completion.usage,\n cliStderr: completion.cliStderr,\n fallbackFrom: completion.fallbackFrom,\n };\n } catch (error) {\n if (error instanceof SyntheticVoteError) {\n return {\n ok: false,\n error: `Vote parsing failed: ${error.message}`,\n cliStderr: completion.cliStderr,\n };\n }\n throw error; // Re-throw unexpected errors\n }\n}\n\n/** Options for executeWithRetries. */\nexport interface RetryOptions {\n readonly role: VoterRole;\n readonly proposal: string;\n readonly adapter: IModelAdapter;\n readonly logger: ILogger;\n readonly timeoutMs: number;\n readonly maxRetries: number;\n /** Declared options for a multi-option proposal (#4472); absent for yes/no. */\n readonly options?: readonly string[] | undefined;\n /** Target project for the system prompt (#6110); absent ⇒ `nexus-agents`. */\n readonly project?: string | undefined;\n /** Working directory named in the user prompt (#6254); absent ⇒ no REPOSITORY ACCESS block. */\n readonly workspace?: string | undefined;\n readonly workspaceSha?: string | undefined;\n}\n\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 cause: 'durable capacity cap' | 'auth failure'\n): void {\n logger.warn(`${cause} — abandoning retries for this voter`, {\n role,\n attempt: attempt + 1,\n remainingAttemptsSkipped: maxRetries - attempt,\n });\n}\n\n/**\n * What a successful vote attempt hands the result builder: the parsed vote,\n * its usage, the transport's stderr (#6094) and any in-family model\n * substitution (#6120, disclosed as a fallback by #6115).\n */\nexport interface VoteOutcome {\n readonly vote: Vote;\n readonly usage: VoteUsage;\n readonly cliStderr: string | undefined;\n readonly fallbackFrom: string | undefined;\n}\n\nexport async function executeWithRetries(\n opts: RetryOptions\n): Promise<(VoteOutcome & { ok: true }) | { error: string; ok: false }> {\n const { role, proposal, adapter, logger, timeoutMs, maxRetries } = opts;\n let lastError = '';\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n if (attempt > 0) {\n const isRateLimit = isRateLimitError(lastError);\n const baseDelay = isRateLimit ? RATE_LIMIT_RETRY_DELAY_MS : INITIAL_RETRY_DELAY_MS;\n const delayMs = baseDelay * Math.pow(2, attempt - 1);\n logger.debug('Retrying vote execution', { role, attempt, delayMs, isRateLimit });\n await delay(delayMs);\n }\n\n // #2472: per-attempt timing breakdown so investigators can see which\n // retry succeeded (or which attempt blew the cap). Total vote time\n // is already captured at the call-site; this fills the per-attempt gap.\n const attemptStart = Date.now();\n const result = await executeSingleVoteAttempt(role, proposal, adapter, timeoutMs, opts);\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 const { vote, usage, cliStderr, fallbackFrom } = result;\n return { vote, usage, cliStderr, fallbackFrom, ok: true };\n }\n\n lastError = result.error;\n const terminal = logFailedAttempt(logger, {\n role,\n attempt,\n maxRetries,\n attemptMs,\n error: lastError,\n cliStderr: result.cliStderr,\n });\n if (terminal !== null) {\n logAbandonedRetries(logger, role, attempt, maxRetries, terminal);\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 /** Stderr the transport captured when the output was not a vote (#6269). */\n readonly cliStderr: string | undefined;\n}\n\n/** Longest stderr excerpt carried on the `Vote attempt failed` line (#6269). */\nconst LOGGED_STDERR_MAX_CHARS = 200;\n\n/**\n * The first non-blank stderr line, secret-redacted and clipped: enough to name\n * the cause (an auth line, a sandbox failure) without a stack trace (#6269).\n */\nfunction loggedStderrLine(cliStderr: string): string {\n const first = cliStderr.split('\\n').find((line) => line.trim() !== '') ?? '';\n return sanitizeOutput(first.trim()).slice(0, LOGGED_STDERR_MAX_CHARS);\n}\n\n/**\n * Log one failed attempt's timing and classification. Returns the reason the\n * remaining attempts are futile — a DURABLE capacity cap (#5359) or an auth\n * failure (#6269: a retry on the same credential cannot clear it, and the\n * budget it would burn is what the #3587 fallback needs) — or `null` when the\n * caller should keep retrying.\n */\nfunction logFailedAttempt(\n logger: ILogger,\n failed: FailedAttempt\n): 'durable capacity cap' | 'auth failure' | null {\n const { role, attempt, maxRetries, attemptMs, error, cliStderr } = failed;\n const rateLimited = isRateLimitError(error);\n const durableCap = isDurableCapacityText(error);\n const authFailure = isAuthFailureText(error);\n logger.info('Vote attempt timing', {\n role,\n attempt: attempt + 1,\n attemptMs,\n succeeded: false,\n rateLimited,\n });\n logger.warn('Vote attempt failed', {\n role,\n attempt: attempt + 1,\n maxRetries: maxRetries + 1,\n error,\n ...(rateLimited ? { rateLimited: true } : {}),\n ...(durableCap ? { durableCap: true } : {}),\n ...(authFailure ? { authFailure: true } : {}),\n ...(cliStderr !== undefined && cliStderr !== ''\n ? { cliStderr: loggedStderrLine(cliStderr) }\n : {}),\n });\n if (durableCap) return 'durable capacity cap';\n if (authFailure) return 'auth failure';\n return null;\n}\n","/**\n * Overall-deadline racing for consensus voting (Issue #1871).\n *\n * Defensive layer above per-vote timeouts: even if a single\n * executeAgentVote() promise never settles (subprocess adapter hang,\n * IPC wait that swallows timeout, etc.), this helper guarantees the\n * whole consensus call returns bounded partial results.\n *\n * Each role's vote promise is raced against a shared wall-clock\n * deadline. Any role whose promise has not settled when the deadline\n * fires is filled with createErrorVoteResult('overall consensus\n * deadline exceeded'), preserving role order so downstream aggregation\n * stays deterministic.\n */\nimport type { IModelAdapter, ILogger } from '../core/index.js';\nimport type { AgentVoteResult, SeatAttemptTiming, VoterRole } from './vote-types.js';\nimport { createErrorVoteResult, delay } from './voter-execution.js';\nimport { crossCliFallback, withAssignedCli } from './voter-fallback.js';\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 * Called as each seat settles — first pass, fallback and retry alike — with\n * that seat's result (#6162). The async-job liveness heartbeat: a vote body\n * running past the standard MCP ceiling reports progress per seat through\n * this, so a panel whose seats keep landing is never failed as wedged.\n */\n readonly onVoteCollected?: ((vote: AgentVoteResult) => void) | undefined;\n /**\n * Cancellation for in-flight panels (#5393).\n *\n * Checked after each stagger delay, so a cancel stops LAUNCHING the voters\n * that have not started. 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/**\n * Preserve the panel resolver's primary assignment across fallback execution:\n * the model it pinned, and (#6115) the CLI it chose, which unlike the model is\n * known before detection and so survives the `pending-detection` placeholder.\n */\nfunction withAssignment(\n result: AgentVoteResult,\n pinnedModel: string,\n assignedKey: string\n): AgentVoteResult {\n return withAssignedCli({ ...result, pinnedModel }, assignedKey);\n}\n\n/**\n * How many same-CLI seats may run at once (#6103). The default is one — the\n * #3348 serialization: concurrent subprocesses of one CLI each triggered its\n * OAuth access-token refresh, and with refresh-token rotation the first call\n * rotated the token and the rest failed \"refresh token already used\".\n *\n * `cli-claude` is widened to two on measurement: the first `Seat timing`\n * readout (#6387 panel, 2026-09-16) put 871 s of a ~12-minute panel in the\n * claude lane's queue — fallback seats waited 244–398 s behind three primary\n * claude runs — and a probe of 15 concurrent `claude -p` calls (2- and\n * 3-way) produced no refresh error. A collision at an actual refresh is\n * still possible; it surfaces as a retried attempt (`voter-retry.ts`) and\n * as a second attempt on the seat's timing line, which is the signal to\n * narrow this again. Cross-CLI parallelism is unchanged.\n */\nconst CLI_LANE_WIDTH: Readonly<Record<string, number>> = { 'cli-claude': 2 };\nconst DEFAULT_LANE_WIDTH = 1;\n\n/** The lane width for a CLI key: the table's entry, else one. */\nfunction laneWidthOf(key: string): number {\n return Object.hasOwn(CLI_LANE_WIDTH, key)\n ? (CLI_LANE_WIDTH[key] ?? DEFAULT_LANE_WIDTH)\n : DEFAULT_LANE_WIDTH;\n}\n\n/**\n * Per-key lane (#3348, widened per key by {@link CLI_LANE_WIDTH} in #6103).\n * Returns a `run(key, fn)` that admits at most `laneWidthOf(key)` fns per\n * key at a time, in FIFO order; a rejected fn frees its slot like a resolved\n * one so one failure cannot wedge the lane. Different keys run concurrently.\n */\nfunction createKeyedSerializer(): <T>(key: string, fn: () => Promise<T>) => Promise<T> {\n const lanes = new Map<string, { active: number; waiting: (() => void)[] }>();\n const laneFor = (key: string): { active: number; waiting: (() => void)[] } => {\n const existing = lanes.get(key);\n if (existing !== undefined) return existing;\n const created = { active: 0, waiting: [] };\n lanes.set(key, created);\n return created;\n };\n return async <T>(key: string, fn: () => Promise<T>): Promise<T> => {\n const lane = laneFor(key);\n if (lane.active >= laneWidthOf(key)) {\n await new Promise<void>((resolve) => lane.waiting.push(resolve));\n }\n lane.active += 1;\n try {\n return await fn();\n } finally {\n lane.active -= 1;\n lane.waiting.shift()?.();\n }\n };\n}\n\nfunction raceWithDeadline(\n 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\n/** Both attempts travel with a recovered seat (#6103): the failed primary's timing first. */\nfunction withPrimaryAttempts(\n primary: AgentVoteResult,\n recovered: AgentVoteResult\n): AgentVoteResult {\n return {\n ...recovered,\n timing: {\n attempts: [...(primary.timing?.attempts ?? []), ...(recovered.timing?.attempts ?? [])],\n },\n };\n}\n\ntype VoteOnAdapter = (\n role: VoterRole,\n adapter: IModelAdapter,\n fallback: boolean\n) => Promise<AgentVoteResult>;\n\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 const assignedKey = adapterCliKey(adapter);\n const stamp = (r: AgentVoteResult): AgentVoteResult =>\n withAssignment(r, pinnedModel, assignedKey);\n if (cancelled(input.signal)) {\n // Refused before any attempt: the timing says so with an empty list.\n return stamp({\n ...createErrorVoteResult(role, CANCELLED_MESSAGE, 0),\n timing: { attempts: [] },\n });\n }\n const primary = await voteOnAdapter(role, adapter, false);\n if (!shouldRetryOnFallback(primary, adapter, input.fallbackAdapter)) return stamp(primary);\n if (cancelled(input.signal)) return stamp(primary);\n input.logger.warn('Voter failed on diverse adapter; retrying on fallback (#3587)', {\n role,\n failedCli: assignedKey,\n fallbackCli: adapterCliKey(input.fallbackAdapter),\n error: primary.error,\n });\n const recovered = withPrimaryAttempts(\n primary,\n await voteOnAdapter(role, input.fallbackAdapter, true)\n );\n if (recovered.source === 'error') return stamp(recovered);\n // #6115: the seat ANSWERED somewhere other than where it was assigned. Say\n // where it was meant to answer and which error class moved it, so a panel\n // that collapsed onto one model during a capacity window is legible in the\n // result rather than only in this log line. A seat that errored on the\n // fallback too answered nowhere and carries no fallback.\n const fallback = crossCliFallback(adapter, assignedKey, primary.error ?? '');\n return stamp({ ...recovered, fallback });\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 // #6103: the attempt's timing rides on the result — queued (enqueue → start)\n // and ran (start → settle) — so a slow panel can be attributed to the lane\n // or to the model. The caller folds attempts into the seat's `timing`.\n const voteOnAdapter = (\n role: VoterRole,\n adapter: IModelAdapter,\n fallback: boolean\n ): Promise<AgentVoteResult> => {\n const cli = adapterCliKey(adapter);\n const enqueuedAt = Date.now();\n // Serialize per CLI so concurrent same-CLI calls don't race that CLI's\n // OAuth refresh (#3348). The deadline is measured when the vote actually\n // starts, so a queued role still gets a correct remaining budget.\n return serialize(cli, async () => {\n const runStartedAt = Date.now();\n const remaining = Math.max(1, overallDeadlineMs - (runStartedAt - startedAt));\n const result = await raceWithDeadline(\n voteFn(role, proposal, adapter, logger, voteOptions),\n role,\n remaining\n );\n const attempt: SeatAttemptTiming = {\n cli,\n queuedMs: runStartedAt - enqueuedAt,\n ranMs: Date.now() - runStartedAt,\n fallback,\n };\n return { ...result, timing: { attempts: [...(result.timing?.attempts ?? []), attempt] } };\n });\n };\n\n const wrapped = roles.map((role, index) =>\n launchRoleVote(role, index, input, voteOnAdapter).then((result) => {\n input.onVoteCollected?.(result);\n return result;\n })\n );\n\n const results = await Promise.all(wrapped);\n\n const expired = results.filter((r) => r.source === 'error' && r.error === DEADLINE_MESSAGE);\n if (expired.length > 0) {\n logger.warn('Consensus overall deadline reached; returning partial results', {\n totalRoles: roles.length,\n expiredRoles: expired.map((r) => r.role),\n overallDeadlineMs,\n });\n }\n return results;\n}\n","/**\n * The working directory a consensus panel's seats are pointed at (#6258).\n *\n * One cwd per panel: the caller's explicit directory (the CLI's ratification\n * scratch checkout) or, absent one, `process.cwd()`. `collectRealVotes` hands\n * it to every seat and `executeVoting` stamps the same value on the live\n * result, so an `unverifiable` seat can be diagnosed without reading stderr.\n * Its own module so both call it without either importing the other's mocks.\n *\n * @module cli/panel-workspace\n */\n\n/** The directory a panel's seats are given: the caller's, else the process cwd. */\nexport function resolvePanelWorkspace(workspace: string | undefined): string {\n return workspace ?? process.cwd();\n}\n","/**\n * nexus-agents voter agents\n *\n * Real LLM-powered voter agents for consensus voting.\n * Replaces simulated voting with actual agent execution that\n * analyzes proposals.\n *\n * (Source: Issue #226, Sprint #229)\n * (Updated: Issue #280 - Fixed timeout handling, removed simulation fallback)\n * (Refactored: Issue #285 - Extracted response and execution utilities)\n *\n * File structure:\n * - voter-prompts.ts: System prompts for each voter role\n * - voter-response.ts: Response parsing and validation\n * - voter-execution.ts: Execution utilities (timeout, retry, result creation)\n * - voter-agents.ts: Main API (this file)\n */\n\nimport type { VoterRole, AgentVoteResult } from './vote-types.js';\nimport { resolveVoterModelOverrides } from './voter-model-overrides.js';\nimport { VOTER_ROLES } from './voter-roles.js';\nimport { createLogger, getTimeProvider, type IModelAdapter, type ILogger } from '../core/index.js';\nimport { getGlobalRegistry } from '../adapters/unified-registry.js';\nimport { isGatewayModelAdapter } from '../adapters/openai-compat-adapter.js';\nimport { getAvailableClis } from '../cli-adapters/factory.js';\nimport { authRemediation } from '../cli-adapters/cli-error-envelope.js';\nimport type { CliName } from '../cli-adapters/types.js';\nimport { countDistinctModels } from '../config/model-equivalence.js';\nimport { reportPanelIndependence, reportVoteIndependence } from './panel-independence.js';\nimport { DEFAULT_ERRORED_ROLE_BACKOFF_MS, retryErroredRoles } from './voter-retry.js';\nimport {\n NoAdapterError,\n resolveAdapterOrFail,\n warnIfCodexConcurrencyExceeded,\n} from './voter-adapter-resolve.js';\nimport {\n classifyUnverifiable,\n markUnverifiable,\n type UnverifiableReasoningRule,\n} from './voter-unverifiable.js';\nimport { inFamilyFallback } from './voter-fallback.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 type VoteOutcome,\n} from './voter-execution.js';\nimport { resolveVoteTimeout, VOTE_TIMEOUTS, getMcpSafeDeadlineMs } from '../config/timeouts.js';\nimport { launchVotesWithOverallDeadline } from './voter-agents-deadline.js';\nimport { resolvePanelWorkspace } from './panel-workspace.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, usage, fallbackFrom }: VoteOutcome,\n adapter: IModelAdapter,\n processingTimeMs: number\n): AgentVoteResult {\n return {\n role,\n vote,\n processingTimeMs,\n source: 'llm',\n cli: adapter.providerId,\n model: adapter.modelId,\n // #4392 step 4: which gateway arm served the seat, so the cost rollup\n // prices it by the arm's declaration and not the model id's list price.\n ...(isGatewayModelAdapter(adapter) ? { gatewayArm: adapter.gatewayArm } : {}),\n // #6115: the CLI answered on another model of its family (#6120) — a\n // capacity fallback by construction, disclosed on the seat.\n ...(fallbackFrom !== undefined\n ? { fallback: inFamilyFallback(adapter.providerId, fallbackFrom) }\n : {}),\n // #4472: surface the voter's choice at the result level, where the tally\n // and the record read it. Absent when no options were declared or the\n // selection matched none of them.\n ...(vote.selectedOption !== undefined ? { selectedOption: vote.selectedOption } : {}),\n ...(usage.inputTokens !== undefined ? { inputTokens: usage.inputTokens } : {}),\n ...(usage.outputTokens !== undefined ? { outputTokens: usage.outputTokens } : {}),\n ...(usage.cachedInputTokens !== undefined\n ? { cachedInputTokens: usage.cachedInputTokens }\n : {}),\n ...(usage.cacheCreationInputTokens !== undefined\n ? { cacheCreationInputTokens: usage.cacheCreationInputTokens }\n : {}),\n };\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 workspace: options.workspace,\n workspaceSha: options.workspaceSha,\n };\n}\n\nexport async function executeAgentVote(\n role: VoterRole,\n proposal: string,\n adapter: IModelAdapter,\n logger: ILogger,\n options?: VoteExecutionOverrides\n): Promise<AgentVoteResult> {\n const start = getTimeProvider().now();\n // `settings` is timeoutMs, maxRetries, project and workspace — the retry hop's own fields.\n const { allowSimulation, declaredOptions, ...settings } = resolveVoteExecution(options);\n\n logger.info('Executing vote', { role, model: adapter.modelId, provider: adapter.providerId });\n\n const retryOptions = { role, proposal, adapter, logger, ...settings };\n const result = await executeWithRetries({ ...retryOptions, options: declaredOptions });\n const processingTimeMs = getTimeProvider().now() - start;\n\n if (result.ok) {\n const built = buildLlmVoteResult(role, result, adapter, processingTimeMs);\n 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 /** Repository checkout used by every panel seat. */\n readonly workspace?: string | undefined;\n readonly workspaceSha?: string | undefined;\n /** Voter roles to include */\n readonly roles: readonly VoterRole[];\n /** Proposal text */\n readonly proposal: string;\n /** Use simulation mode (explicit opt-in only) */\n readonly simulate?: boolean;\n /**\n * In-process gateway model adapters (#4040) — one per discovered gateway model.\n * When provided (and no explicit `adapter` override), voters route through these\n * HTTP adapters instead of shelling out to CLIs: roles are round-robined across\n * them for per-role model diversity, the API key stays in-process (no subprocess\n * env-forwarding), and the nested-spawn class (#4033) cannot occur. Empty/omitted\n * ⇒ the CLI round-robin path is used (unchanged).\n */\n readonly gatewayAdapters?: readonly IModelAdapter[] | undefined;\n /** Named alternatives for a multi-option proposal (#4472); each voter picks one. */\n readonly declaredOptions?: readonly string[] | undefined;\n /**\n * The project the panel is judging, already resolved and validated by the\n * caller (#6110). Reaches every seat's system prompt. Absent ⇒ `nexus-agents`.\n */\n readonly project?: string | undefined;\n /**\n * Cancellation for an in-flight panel (#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 * Per-seat progress callback (#6162): invoked with each seat's result as it\n * settles, on every pass (first, fallback, retry). The async-job heartbeat\n * for vote bodies; absent changes nothing.\n */\n readonly onVoteCollected?: ((vote: AgentVoteResult) => void) | undefined;\n /**\n * Delay before the per-role retry of errored voters (#5578). Defaults to\n * {@link DEFAULT_ERRORED_ROLE_BACKOFF_MS}; 0 disables the wait, which is what\n * tests want. The retry itself is not optional — the panel applies it under\n * every error policy, per the #5578 design panel (option b, 6 of 6).\n */\n readonly erroredRoleBackoffMs?: number | undefined;\n /**\n * Seats already assigned by {@link assignPanelSeats} (#6003): a caller that\n * must know the panel's models BEFORE the vote (the pr_review budget reads\n * their windows) resolves the seats once and hands them back, so the panel\n * runs on exactly what it was budgeted for. Ignored when `adapter` is set.\n */\n readonly roleAdapters?: ReadonlyMap<VoterRole, IModelAdapter> | undefined;\n}\n\n/** Assigns a single adapter to all roles (fallback path). */\nfunction assignUniformAdapter(\n roles: readonly VoterRole[],\n adapter: IModelAdapter\n): Map<VoterRole, IModelAdapter> {\n 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) result.set(cli, registry.getAdapterForCli(cli));\n return result;\n}\n\n/**\n * Creates diverse per-role adapters using all available CLIs (Issue #845).\n * Distributes roles across CLIs in round-robin fashion for model diversity.\n * Falls back to single adapter if only one CLI is available.\n */\n/**\n * Round-robin assign roles across a labeled adapter list (the shared diversity\n * primitive for both the CLI path and the gateway path #4040). `label` is the\n * model/CLI id surfaced in the assignment log so operators can confirm which\n * model each role used.\n */\nfunction assignRoundRobinAdapters(\n roles: readonly VoterRole[],\n entries: readonly { readonly label: string; readonly adapter: IModelAdapter }[],\n logger: ILogger,\n source: string\n): Map<VoterRole, IModelAdapter> {\n const adapters = new Map<VoterRole, IModelAdapter>();\n const assignments: Record<string, string> = {};\n for (let i = 0; i < roles.length; i++) {\n const role = roles[i];\n const entry = entries[i % entries.length];\n if (role === undefined || entry === undefined) continue;\n adapters.set(role, entry.adapter);\n assignments[role] = entry.label;\n }\n logger.info('Diverse adapters assigned', {\n source,\n count: entries.length,\n roleAssignments: assignments,\n });\n return adapters;\n}\n\n/**\n * Gateway path (#4040): assign roles across the in-process per-model gateway\n * adapters. A single model collapses to a uniform panel (warned). With multiple\n * models, per-role operator overrides (#4055) pin chosen roles to a known-good\n * model and the rest 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 /** Working directory named in every user prompt (#6254); absent ⇒ no REPOSITORY ACCESS block. */\n workspace?: string | undefined;\n /** Ratified commit when workspace is a detached scratch checkout. */\n workspaceSha?: 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 /** Required KEY (#6254), for the same reason. */\n workspace: string | undefined;\n workspaceSha: 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 /** Per-seat heartbeat (#6162), forwarded to the deadline launcher. */\n readonly onVoteCollected?: ((vote: AgentVoteResult) => void) | undefined;\n}\n\n/**\n * Launches votes with staggered delays to prevent rate limiting (Issue #1319)\n * and an overall wall-clock deadline to prevent indefinite hangs (Issue #1871).\n */\nasync function launchStaggeredVotes(\n input: StaggeredVoteInput\n): Promise<readonly AgentVoteResult[]> {\n const { roles, 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 // `StaggeredVoteInput` is `LaunchVotesInput` minus the deadline and the\n // launcher, so the input passes through whole — including `signal` (#5393)\n // and `onVoteCollected` (#6162).\n return launchVotesWithOverallDeadline({ ...input, overallDeadlineMs, voteFn: executeAgentVote });\n}\n\n/**\n * Collects votes from multiple voter agents.\n *\n * Per Issue #280: No automatic simulation fallback. If no adapter is\n * available and simulation is not explicitly enabled, throws NoAdapterError.\n * Per Issue #845: Uses diverse CLIs when multiple are available.\n */\n/**\n * The panel's seat → adapter assignment — ONE definition, used by the vote and\n * by anything that must know the panel's models before it runs (#6003). An\n * explicit `adapter` is uniform (Issue #280); pre-resolved `roleAdapters` are\n * used verbatim; else roles spread across gateway models / CLIs (Issue #845).\n */\nexport async function assignPanelSeats(\n fallbackAdapter: IModelAdapter,\n options: Pick<CollectRealVotesOptions, 'roles' | 'adapter' | 'gatewayAdapters' | 'roleAdapters'>,\n logger: ILogger\n): Promise<Map<VoterRole, IModelAdapter>> {\n if (options.adapter !== undefined) return assignUniformAdapter(options.roles, fallbackAdapter);\n if (options.roleAdapters !== undefined) return new Map(options.roleAdapters);\n return resolveDiverseAdapters(options.roles, logger, fallbackAdapter, options.gatewayAdapters);\n}\n\nexport async function collectRealVotes(\n options: CollectRealVotesOptions\n): Promise<readonly AgentVoteResult[]> {\n const logger = options.logger ?? defaultLogger;\n const { roles, proposal, simulate, allowSimulation } = options;\n\n if (simulate === true) {\n logger.info('Using simulation mode (explicitly requested)');\n return createSimulatedVotes(roles, proposal);\n }\n\n const adapterResult = resolveAdapterOrFail(options, logger, allowSimulation === true);\n if ('simulated' in adapterResult)\n return createSimulatedVotes(roles, proposal, 'No adapter available');\n\n const roleAdapters = await assignPanelSeats(adapterResult.adapter, options, logger);\n\n warnIfCodexConcurrencyExceeded(roleAdapters, logger);\n\n // The same resolver executeAgentVote applies, so the two paths cannot drift\n // on a default. Carried through: timeoutMs / maxRetries / allowSimulation;\n // declaredOptions (#4472) into the prompt and the selection resolver; the\n // target project (#6110) into every system prompt; and the working\n // directory (#6358) — explicitly passed to every subprocess seat, which the\n // gemini arm now also gets as --add-dir — read once so every seat of the\n // panel names the same tree in its REPOSITORY ACCESS block.\n const workspace = resolvePanelWorkspace(options.workspace);\n const voteOptions = resolveVoteExecution({ ...options, workspace });\n const interDelay = options.interAgentDelayMs ?? DEFAULT_INTER_AGENT_DELAY_MS;\n\n const launchInput: StaggeredVoteInput = {\n roles,\n proposal,\n roleAdapters,\n fallbackAdapter: adapterResult.adapter,\n logger,\n voteOptions,\n interDelay,\n signal: options.signal,\n onVoteCollected: options.onVoteCollected,\n };\n 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 './decision/thresholds.js';\nimport { OPERATION_CLASSES } from '../config/timeouts.js';\n\n/**\n * Default per-round voting timeout (#3734). A voting round guards a parallel\n * MULTI-LLM panel, so it derives from the central `multi-llm-panel` runaway-guard\n * (900s) — not the old accidental 60s, which killed legitimate slow voters.\n */\nconst VOTING_ROUND_DEFAULT_TIMEOUT_MS = OPERATION_CLASSES['multi-llm-panel'].guardMs;\n\n/**\n * Voting round phases.\n * - analysis: Independent analysis (Round 1)\n * - deliberation: Share findings and discuss (Round 2)\n * - consensus: Final vote on recommendations (Round 3)\n */\nexport const VotingRoundPhaseSchema = z.enum(['analysis', 'deliberation', 'consensus']);\nexport type VotingRoundPhase = z.infer<typeof VotingRoundPhaseSchema>;\n\n/**\n * Voting round status.\n */\nexport const VotingRoundStatusSchema = z.enum([\n 'pending',\n 'in_progress',\n 'awaiting_votes',\n 'completed',\n 'aborted',\n]);\nexport type VotingRoundStatus = z.infer<typeof VotingRoundStatusSchema>;\n\n/**\n * A finding submitted by an agent during analysis.\n */\nexport const AgentFindingSchema = z.object({\n agentId: z.string(),\n category: z.enum(['bug', 'security', 'performance', 'style', 'design', 'documentation', 'other']),\n severity: z.enum(['critical', 'major', 'minor', 'suggestion']),\n description: z.string().min(1),\n location: z.string().optional().describe('File path and line range if applicable'),\n suggestion: z.string().optional().describe('Recommended fix'),\n confidence: z.number().min(0).max(1),\n timestamp: z.iso.datetime().optional(),\n});\nexport type AgentFinding = z.infer<typeof AgentFindingSchema>;\n\n/**\n * Finding vote during deliberation.\n */\nexport const FindingVoteSchema = z.object({\n agentId: z.string(),\n findingId: z.string(),\n agree: z.boolean(),\n reasoning: z.string().optional(),\n amendedSeverity: z.enum(['critical', 'major', 'minor', 'suggestion']).optional(),\n});\nexport type FindingVote = z.infer<typeof FindingVoteSchema>;\n\n/**\n * A single voting round in the protocol.\n */\nexport interface VotingRound {\n id: string;\n phase: VotingRoundPhase;\n status: VotingRoundStatus;\n findings: Map<string, AgentFinding>; // findingId -> finding\n findingVotes: Map<string, FindingVote[]>; // findingId -> votes\n finalVotes: Map<string, Vote>; // agentId -> final vote\n startedAt: string;\n completedAt?: string;\n roundNumber: number;\n}\n\n/**\n * Configuration for the voting protocol.\n */\nexport interface VotingProtocolConfig {\n /** Number of agents in the committee (default: 3) */\n committeeSize: number;\n /** Maximum rounds before forcing decision (default: 3) */\n maxRounds: number;\n /** Timeout per round in milliseconds (default: multi-llm-panel guard, 900000) */\n roundTimeoutMs: number;\n /** Minimum agreement threshold (default: 2/3, approximately 0.667) */\n agreementThreshold: number;\n /** Enable anti-sycophancy detection (default: true) */\n enableAntiSycophancy: boolean;\n /** Similarity threshold for sycophancy detection (default: 0.8) */\n sycophancyThreshold: number;\n}\n\nexport const VotingProtocolConfigSchema = z.object({\n committeeSize: z.number().int().min(2).max(7).default(3),\n maxRounds: z.number().int().min(1).max(5).default(3),\n roundTimeoutMs: z.number().int().positive().default(VOTING_ROUND_DEFAULT_TIMEOUT_MS),\n agreementThreshold: z.number().min(0.5).max(1).default(SUPERMAJORITY_THRESHOLD),\n enableAntiSycophancy: z.boolean().default(true),\n sycophancyThreshold: z.number().min(0).max(1).default(0.8),\n});\n\nexport const DEFAULT_VOTING_PROTOCOL_CONFIG: VotingProtocolConfig = {\n committeeSize: 3,\n maxRounds: 3,\n roundTimeoutMs: VOTING_ROUND_DEFAULT_TIMEOUT_MS,\n // Default agreement level IS the supermajority (2/3) — single source (#3571).\n agreementThreshold: SUPERMAJORITY_THRESHOLD,\n enableAntiSycophancy: true,\n sycophancyThreshold: 0.8,\n};\n\n/**\n * Session state for a voting protocol instance.\n */\nexport interface VotingSession {\n id: string;\n topic: string;\n committee: string[]; // Agent IDs\n rounds: VotingRound[];\n currentRound: number;\n config: VotingProtocolConfig;\n status: 'active' | 'completed' | 'aborted';\n createdAt: string;\n completedAt?: string;\n finalResult?: VotingProtocolResult;\n}\n\n/**\n * Final result of a voting protocol session.\n */\nexport interface VotingProtocolResult {\n sessionId: string;\n topic: string;\n outcome: 'approved' | 'rejected' | 'needs_revision' | 'no_consensus';\n consolidatedFindings: ConsolidatedFinding[];\n roundSummaries: RoundSummary[];\n agreementScore: number;\n sycophancyDetected: boolean;\n totalDurationMs: number;\n participatingAgents: string[];\n}\n\n/**\n * A consolidated finding after deliberation.\n */\nexport interface ConsolidatedFinding {\n id: string;\n category: AgentFinding['category'];\n severity: AgentFinding['severity'];\n description: string;\n location?: string;\n suggestion?: string;\n supportingAgents: string[];\n agreementRatio: number;\n originalFindings: AgentFinding[];\n}\n\n/**\n * Summary of a single round.\n */\nexport interface RoundSummary {\n roundNumber: number;\n phase: VotingRoundPhase;\n findingsCount: number;\n votesCount: number;\n agreementScore: number;\n durationMs: number;\n}\n\n/**\n * Interface for the multi-round voting protocol.\n * (Source: Issue #100, arXiv:2512.21352)\n */\nexport interface IVotingProtocol {\n /** Create a new voting session with a committee */\n createSession(\n topic: string,\n committee: string[],\n config?: Partial<VotingProtocolConfig>\n ): VotingSession;\n\n /** Start the analysis round (Round 1) */\n startAnalysisRound(sessionId: string): Promise<VotingRound>;\n\n /** Submit findings from an agent during analysis */\n submitFindings(sessionId: string, agentId: string, findings: AgentFinding[]): Promise<void>;\n\n /** Start the deliberation round (Round 2) */\n startDeliberationRound(sessionId: string): Promise<VotingRound>;\n\n /** Vote on findings during deliberation */\n voteOnFinding(sessionId: string, vote: FindingVote): Promise<void>;\n\n /** Start the consensus round (Round 3) */\n startConsensusRound(sessionId: string): Promise<VotingRound>;\n\n /** Submit final vote during consensus */\n submitFinalVote(sessionId: string, agentId: string, vote: Vote): Promise<void>;\n\n /** Get the final result (closes session if complete) */\n getResult(sessionId: string): Promise<VotingProtocolResult | null>;\n\n /** Check for sycophancy in the current round */\n detectSycophancy(sessionId: string): SycophancyReport;\n\n /** Get the current session state */\n getSession(sessionId: string): VotingSession | undefined;\n}\n\n/**\n * Report from sycophancy detection.\n */\nexport interface SycophancyReport {\n detected: boolean;\n confidenceScore: number;\n indicators: SycophancyIndicator[];\n affectedAgents: string[];\n recommendation: string;\n}\n\n/**\n * Individual sycophancy indicator.\n */\nexport interface SycophancyIndicator {\n type: 'premature_consensus' | 'opinion_convergence' | 'confidence_inflation' | 'echo_chamber';\n description: string;\n severity: 'low' | 'medium' | 'high';\n agents: string[];\n}\n","/**\n * nexus-agents/consensus - Weighted Byzantine Voting Types\n *\n * Weighted Byzantine Voting Types (Issue #103)\n * Based on CP-WBFT (arXiv:2511.10400)\n */\n\nimport { z } from 'zod';\nimport type { Vote } from './types-core.js';\nimport { SUPERMAJORITY_THRESHOLD } from './decision/thresholds.js';\n\n/**\n * Task outcome STATUS for tracking agent performance — a 4-state vote status,\n * NOT an outcome row. Named `*Status` to avoid colliding with the canonical\n * outcome *record* `TaskOutcome` in orchestration/outcomes (#3146/#3226: the\n * two were unrelated types that happened to share the name `TaskOutcome`).\n */\nexport const TaskOutcomeStatusSchema = z.enum(['success', 'failure', 'partial', 'unknown']);\nexport type TaskOutcomeStatus = z.infer<typeof TaskOutcomeStatusSchema>;\n\n/**\n * Extended agent performance with Byzantine detection.\n */\nexport interface WeightedAgentRecord {\n readonly agentId: string;\n readonly totalTasks: number;\n readonly successfulTasks: number;\n readonly failedTasks: number;\n readonly partialTasks: number;\n readonly successRate: number;\n readonly weight: number;\n readonly trustScore: number;\n readonly byzantineFlags: number;\n readonly lastActive: Date;\n readonly createdAt: Date;\n}\n\nexport const WeightedAgentRecordSchema = z.object({\n agentId: z.string().min(1),\n totalTasks: z.number().int().nonnegative(),\n successfulTasks: z.number().int().nonnegative(),\n failedTasks: z.number().int().nonnegative(),\n partialTasks: z.number().int().nonnegative(),\n successRate: z.number().min(0).max(1),\n weight: z.number().min(0).max(1),\n trustScore: z.number().min(0).max(1),\n byzantineFlags: z.number().int().nonnegative(),\n lastActive: z.date(),\n createdAt: z.date(),\n});\n\n/**\n * Weighted consensus result.\n */\nexport interface WeightedConsensusResult {\n readonly decision: 'approve' | 'reject' | 'no_consensus';\n readonly weightedApproval: number;\n readonly weightedRejection: number;\n readonly totalWeight: number;\n readonly quorumReached: boolean;\n readonly byzantineDetected: boolean;\n readonly participatingAgents: readonly string[];\n readonly weightBreakdown: ReadonlyMap<string, number>;\n}\n\n/**\n * Configuration for weighted Byzantine voting.\n */\nexport interface WeightedVotingConfig {\n /** Minimum weight to participate in voting (default: 0.1) */\n readonly minWeight: number;\n /** Maximum Byzantine fault tolerance (default: 0.33) */\n readonly maxByzantineFraction: number;\n /** Weight decay factor per failed task (default: 0.9) */\n readonly weightDecayFactor: number;\n /** Weight recovery factor per successful task (default: 1.05) */\n readonly weightRecoveryFactor: number;\n /** Trust score required to vote (default: 0.3) */\n readonly minTrustScore: number;\n /** Byzantine flag threshold for exclusion (default: 3) */\n readonly byzantineFlagThreshold: number;\n /** Initial weight for new agents (default: 0.5) */\n readonly initialWeight: number;\n /** Quorum threshold for valid consensus (default: 2/3, approximately 0.667) */\n readonly quorumThreshold: number;\n}\n\nexport const WeightedVotingConfigSchema = z.object({\n minWeight: z.number().min(0).max(1).default(0.1),\n maxByzantineFraction: z.number().min(0).max(0.5).default(0.33),\n weightDecayFactor: z.number().min(0.5).max(1).default(0.9),\n weightRecoveryFactor: z.number().min(1).max(2).default(1.05),\n minTrustScore: z.number().min(0).max(1).default(0.3),\n byzantineFlagThreshold: z.number().int().positive().default(3),\n initialWeight: z.number().min(0).max(1).default(0.5),\n quorumThreshold: z.number().min(0.5).max(1).default(SUPERMAJORITY_THRESHOLD),\n});\n\nexport const DEFAULT_WEIGHTED_VOTING_CONFIG: WeightedVotingConfig = {\n minWeight: 0.1,\n maxByzantineFraction: 0.33,\n weightDecayFactor: 0.9,\n weightRecoveryFactor: 1.05,\n minTrustScore: 0.3,\n byzantineFlagThreshold: 3,\n initialWeight: 0.5,\n // Default quorum IS the supermajority (2/3) — single source (#3571).\n quorumThreshold: SUPERMAJORITY_THRESHOLD,\n};\n\n/**\n * Interface for weighted Byzantine voting.\n * (Source: Issue #103, arXiv:2511.10400 - CP-WBFT)\n */\nexport interface IWeightedVoting {\n /** Calculate vote weight for an agent */\n calculateWeight(agentId: string): number;\n\n /** Update agent performance based on task outcome */\n updatePerformance(agentId: string, outcome: TaskOutcomeStatus): void;\n\n /** Run weighted consensus on votes */\n weightedConsensus(votes: ReadonlyMap<string, Vote>): WeightedConsensusResult;\n\n /** Register a new agent */\n registerAgent(agentId: string): void;\n\n /** Get agent performance record */\n getAgentRecord(agentId: string): WeightedAgentRecord | undefined;\n\n /** Flag agent for Byzantine behavior */\n flagByzantine(agentId: string, reason: string): void;\n\n /** Get all agent records */\n getAllRecords(): readonly WeightedAgentRecord[];\n\n /** Check if agent can vote */\n canVote(agentId: string): boolean;\n\n /** Recalibrate all weights based on global performance */\n recalibrateWeights(): void;\n}\n","/**\n * nexus-agents/consensus - Higher-Order Voting Types\n *\n * Type definitions for Opinion-Wise (OW) and Independent Subset Partition (ISP)\n * voting methods that account for correlations between agent opinions.\n *\n * 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/decision - Verdict computation\n *\n * The pure functions that turn a tally into a decision, extracted verbatim\n * (#6000 step 1) from the three files that used to hold them:\n *\n * - `evaluateThreshold` (from `consensus/strategies.ts`): ratio vs. bar — the\n * comparison behind the simple-majority, supermajority and proof-of-learning\n * strategies.\n * - `determineFinalStatus` (from `consensus/result-builder.ts`): quorum +\n * approval → the engine's `approved` / `rejected`.\n * - `mapOutcomeToDecision`, `resolveVoteDecision` and its helpers (from\n * `mcp/tools/consensus-vote-types.ts`): engine outcome + error policy →\n * the response-layer `approved` / `rejected` / `no_quorum`.\n *\n * What stays outside: the strategy classes that count votes and call\n * `evaluateThreshold` (`strategies.ts`), the engine's cascade and close\n * orchestration (`engine.ts`), the error-policy vote-list shaping that feeds\n * the engine (`consensus-vote-error-policy.ts`), and the response assembly in\n * `buildResponse`. Each previous home re-exports what moved, so the public\n * API is unchanged. Types from the MCP tool module are imported type-only, so\n * this module has no runtime edge into `mcp/`.\n *\n * @module consensus/decision/verdict\n */\n\nimport { isAbsentSeat } from '../../cli/voter-unverifiable.js';\nimport type {\n ConsensusVoteInput,\n ExtendedVotingResult,\n VoteDecisionStatus,\n VotingStrategy,\n} from '../../mcp/tools/consensus-vote-types.js';\nimport type { ProposalStatus } from '../types-core.js';\n\n// ============================================================================\n// Engine-level verdict\n// ============================================================================\n\n/**\n * Evaluates an approval ratio against a threshold — the shared math behind\n * the simple-majority, supermajority and proof-of-learning strategies.\n *\n * `inclusive` selects the comparison: `>=` for supermajority (an exact 2/3\n * passes), strict `>` for simple-majority and proof-of-learning (a tie at the\n * threshold is not enough). Callers apply their own zero-denominator guard\n * before calling this.\n */\nexport function evaluateThreshold(\n approveCount: number,\n votingTotal: number,\n threshold: number,\n inclusive: boolean\n): { approved: boolean; approvalPercentage: number } {\n const ratio = approveCount / votingTotal;\n return {\n approved: inclusive ? ratio >= threshold : ratio > threshold,\n approvalPercentage: ratio * 100,\n };\n}\n\n/**\n * Determine final status based on quorum and approval.\n */\nexport function determineFinalStatus(quorumReached: boolean, approved: boolean): ProposalStatus {\n if (!quorumReached || !approved) return 'rejected';\n return 'approved';\n}\n\n// ============================================================================\n// Response-level decision\n// ============================================================================\n\n/** Maps ProposalStatus to VoteDecisionStatus. */\nexport function mapOutcomeToDecision(outcome: string): VoteDecisionStatus {\n switch (outcome) {\n case 'approved':\n return 'approved';\n case 'rejected':\n return 'rejected';\n case 'timeout':\n return 'timeout';\n default:\n return 'pending';\n }\n}\n\n/**\n * #4132: the absolute approval fraction a strategy requires over the FULL panel.\n * `ceil(fraction * panelSize)` is the absolute number of approvals an\n * `absolute_quorum` verdict needs — an ABSOLUTE floor over every requested\n * voter, not a majority of the responders (which abstains/errors would shrink).\n * majority → 0.5, supermajority → 2/3, unanimous → 1.0; the higher_order family\n * and proof_of_learning follow the majority (0.5) baseline they tally against.\n */\nfunction absoluteQuorumFraction(strategy: VotingStrategy): number {\n switch (strategy) {\n case 'supermajority':\n return 2 / 3;\n case 'unanimous':\n return 1;\n default:\n return 0.5;\n }\n}\n\n/**\n * #5780: the smallest number of voters that must have cast approve-or-reject\n * before any ratio is applied to them.\n *\n * The gap this closes: every strategy measures its threshold over\n * `approve + reject`, and abstentions and errored seats leave that denominator\n * with no floor under it. `ERROR_FLOOR_FRACTION` voids a panel only when errors\n * EXCEED half, so one seat under it — 7 requested, 3 errored, 1 abstained —\n * left three respondents, and 2 approvals carried an architecture or security\n * vote at 66.7%.\n *\n * Two thirds of the requested panel, never fewer than three, never more than\n * the panel itself. That is one rule satisfying both figures the panel named\n * (7 → 5, quick 3 → 3); the `3` clamp is what makes quick mode require every\n * seat, since two thirds of 3 is 2.\n *\n * Deliberately about RESPONDENTS, not errors. `absolute_quorum` (#4132) voids\n * on an errored seat specifically, so an induced error cannot manufacture a\n * verdict; this is about how few voices decided, whatever silenced them — a\n * panel of 7 returning four abstentions and three votes has zero errors and\n * still should not decide. The two compose; neither replaces the other.\n */\nfunction minimumRespondents(panelSize: number): number {\n if (panelSize <= 0) return 0;\n return Math.min(panelSize, Math.max(Math.ceil((panelSize * 2) / 3), 3));\n}\n\n/** A vote decision plus the (optional) actionable reason a panel degraded. */\nexport interface VoteDecisionOutcome {\n readonly decision: VoteDecisionStatus;\n /** Set when the verdict degraded to `no_quorum` under absolute_quorum. */\n readonly degradeReason?: string;\n}\n\n/**\n * #4132: the absolute_quorum predicate (post-tally). Applied ONLY when\n * `errorPolicy === 'absolute_quorum'`; every other policy keeps the legacy\n * decision path untouched (opt-in).\n *\n * The invariant this enforces (anti-DoS): an induced voter error can NEVER\n * manufacture `approved` and NEVER manufacture `rejected` — errors force\n * `no_quorum`, a recoverable \"re-run the missing voice\" state. A GENUINE reject\n * (zero errors) still blocks. The happy path (all approve, zero errors,\n * contrarian present) stays `approved`.\n *\n * approved ⇔ errorCount === 0 AND (contrarian present-and-non-error, unless\n * quick-mode dropped it) AND approveCount >= ceil(frac * panel)\n * no_quorum ⇔ errorCount > 0 OR 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 * nexus-agents/consensus - Voting Strategies\n *\n * Implementation of different voting strategies for consensus engine.\n * Supports simple majority, supermajority, unanimous, and proof-of-learning.\n */\n\nimport type {\n ConsensusAlgorithm,\n Vote,\n VoteCounts,\n WeightedVoteCounts,\n AgentPerformance,\n WeightBasis,\n} from './types.js';\nimport { VOTING_THRESHOLDS } from './decision/thresholds.js';\nimport { HigherOrderVotingStrategy } from './higher-order-voting.js';\n// The ratio-vs-bar comparison lives in the governed decision module (#6000 step 1).\nimport { evaluateThreshold } from './decision/verdict.js';\n\n/**\n * Interface for voting strategy implementations.\n */\nexport interface IVotingStrategy {\n readonly algorithm: ConsensusAlgorithm;\n calculateOutcome(votes: Map<string, Vote>, weights?: Map<string, number>): VotingOutcome;\n}\n\n/**\n * Result of a voting strategy calculation.\n */\nexport interface VotingOutcome {\n approved: boolean;\n approvalPercentage: number;\n voteCounts: VoteCounts;\n weightedCounts?: WeightedVoteCounts;\n /**\n * Present on weighted strategies only. Absent means the strategy does not\n * weight at all (simple majority, supermajority, unanimous) — which is\n * different from `'unweighted'`, meaning a weighted strategy ran with nothing\n * to weight by.\n */\n weightBasis?: WeightBasis;\n reason: string;\n}\n\n/**\n * Classifies a weighted tally by how many of its voters had a real weight\n * supplied (#5117).\n *\n * A voter absent from `weights` had no performance record; `countWeightedVotes`\n * already defaults such a voter to `1.0`, so the arithmetic is unchanged — the\n * absence is what carries the provenance.\n */\nfunction deriveWeightBasis(votes: Map<string, Vote>, weights: Map<string, number>): WeightBasis {\n let withRecord = 0;\n for (const agentId of votes.keys()) {\n if (weights.has(agentId)) withRecord++;\n }\n\n // The empty case, named rather than left to a default: zero voters carrying a\n // record — including the zero-voter case — is 'unweighted', never\n // 'performance'. Answering it with `withRecord === votes.size` would make\n // 0 === 0 report a full performance basis over nothing measured.\n if (withRecord === 0) return 'unweighted';\n return withRecord === votes.size ? 'performance' : 'partial';\n}\n\n/**\n * Base voting strategy with common functionality.\n */\nabstract class BaseVotingStrategy implements IVotingStrategy {\n abstract readonly algorithm: ConsensusAlgorithm;\n\n abstract calculateOutcome(votes: Map<string, Vote>, weights?: Map<string, number>): VotingOutcome;\n\n /**\n * Count votes by decision type.\n */\n protected countVotes(votes: Map<string, Vote>): VoteCounts {\n let approve = 0;\n let reject = 0;\n let abstain = 0;\n\n for (const vote of votes.values()) {\n switch (vote.decision) {\n case 'approve':\n approve++;\n break;\n case 'reject':\n reject++;\n break;\n case 'abstain':\n abstain++;\n break;\n }\n }\n\n return { approve, reject, abstain, total: votes.size };\n }\n\n /**\n * Calculate weighted vote counts using agent performance weights.\n */\n protected countWeightedVotes(\n votes: Map<string, Vote>,\n weights: Map<string, number>\n ): WeightedVoteCounts {\n let approve = 0;\n let reject = 0;\n let abstain = 0;\n let totalWeight = 0;\n\n for (const [agentId, vote] of votes.entries()) {\n const weight = weights.get(agentId) ?? 1.0;\n totalWeight += weight;\n\n switch (vote.decision) {\n case 'approve':\n approve += weight;\n break;\n case 'reject':\n reject += weight;\n break;\n case 'abstain':\n abstain += weight;\n break;\n }\n }\n\n return { approve, reject, abstain, totalWeight };\n }\n}\n\n/**\n * Simple majority voting strategy (>50% approval).\n */\nexport class SimpleMajorityStrategy extends BaseVotingStrategy {\n readonly algorithm: ConsensusAlgorithm = 'simple_majority';\n\n calculateOutcome(votes: Map<string, Vote>): VotingOutcome {\n const counts = this.countVotes(votes);\n const votingVotes = counts.approve + counts.reject; // Abstains don't count\n const threshold = VOTING_THRESHOLDS.simple_majority;\n\n if (votingVotes === 0) {\n return {\n approved: false,\n approvalPercentage: 0,\n voteCounts: counts,\n reason: 'No votes cast (excluding abstentions)',\n };\n }\n\n const { approved, approvalPercentage } = evaluateThreshold(\n counts.approve,\n votingVotes,\n threshold,\n false\n );\n\n return {\n approved,\n approvalPercentage,\n voteCounts: counts,\n reason: approved\n ? `Approved with ${approvalPercentage.toFixed(1)}% (>${String(threshold * 100)}% required)`\n : `Rejected with ${approvalPercentage.toFixed(1)}% (<=${String(threshold * 100)}% threshold)`,\n };\n }\n}\n\n/**\n * Supermajority voting strategy (at least 2/3 approval).\n */\nexport class SupermajorityStrategy extends BaseVotingStrategy {\n readonly algorithm: ConsensusAlgorithm = 'supermajority';\n\n calculateOutcome(votes: Map<string, Vote>): VotingOutcome {\n const counts = this.countVotes(votes);\n const votingVotes = counts.approve + counts.reject;\n const threshold = VOTING_THRESHOLDS.supermajority;\n\n if (votingVotes === 0) {\n return {\n approved: false,\n approvalPercentage: 0,\n voteCounts: counts,\n reason: 'No votes cast (excluding abstentions)',\n };\n }\n\n const { approved, approvalPercentage } = evaluateThreshold(\n counts.approve,\n votingVotes,\n threshold,\n true\n );\n const thresholdPercentage = (threshold * 100).toFixed(1);\n\n return {\n approved,\n approvalPercentage,\n voteCounts: counts,\n reason: approved\n ? `Approved with ${approvalPercentage.toFixed(1)}% (>=${thresholdPercentage}% required)`\n : `Rejected with ${approvalPercentage.toFixed(1)}% (<${thresholdPercentage}% threshold)`,\n };\n }\n}\n\n/**\n * Unanimous voting strategy (100% approval required).\n */\nexport class UnanimousStrategy extends BaseVotingStrategy {\n readonly algorithm: ConsensusAlgorithm = 'unanimous';\n\n calculateOutcome(votes: Map<string, Vote>): VotingOutcome {\n const counts = this.countVotes(votes);\n\n if (counts.total === 0) {\n return {\n approved: false,\n approvalPercentage: 0,\n voteCounts: counts,\n reason: 'No votes cast',\n };\n }\n\n // For unanimous, any rejection fails the proposal\n // Abstentions are allowed but don't count toward approval\n const approvalPercentage = counts.total > 0 ? (counts.approve / counts.total) * 100 : 0;\n\n if (counts.reject > 0) {\n return {\n approved: false,\n approvalPercentage,\n voteCounts: counts,\n reason: `Rejected: ${String(counts.reject)} rejection(s) cast (unanimous approval required)`,\n };\n }\n\n if (counts.approve === 0) {\n return {\n approved: false,\n approvalPercentage: 0,\n voteCounts: counts,\n reason: 'No approvals cast (at least one approval required)',\n };\n }\n\n return {\n approved: true,\n approvalPercentage,\n voteCounts: counts,\n reason: `Unanimously approved with ${String(counts.approve)} vote(s)`,\n };\n }\n}\n\n/**\n * Proof-of-learning weighted voting strategy.\n * Agents with better track records have more voting power.\n */\nexport class ProofOfLearningStrategy extends BaseVotingStrategy {\n readonly algorithm: ConsensusAlgorithm = 'proof_of_learning';\n\n calculateOutcome(votes: Map<string, Vote>, weights?: Map<string, number>): VotingOutcome {\n const counts = this.countVotes(votes);\n const effectiveWeights = weights ?? new Map<string, number>();\n const weightedCounts = this.countWeightedVotes(votes, effectiveWeights);\n const threshold = VOTING_THRESHOLDS.proof_of_learning;\n\n const votingWeight = weightedCounts.approve + weightedCounts.reject;\n\n if (votingWeight === 0) {\n return {\n approved: false,\n approvalPercentage: 0,\n voteCounts: counts,\n weightedCounts,\n reason: 'No weighted votes cast (excluding abstentions)',\n };\n }\n\n const { approved, approvalPercentage } = evaluateThreshold(\n weightedCounts.approve,\n votingWeight,\n threshold,\n false\n );\n\n const weightBasis = deriveWeightBasis(votes, effectiveWeights);\n const verdict = approved ? 'Approved' : 'Rejected';\n\n return {\n approved,\n approvalPercentage,\n voteCounts: counts,\n weightedCounts,\n weightBasis,\n reason: `${verdict} with ${approvalPercentage.toFixed(1)}% ${describeBasis(weightBasis)}`,\n };\n }\n}\n\n/**\n * The tail of the reason string, naming what the percentage was computed over.\n *\n * Calling an unweighted tally \"weighted approval\" is the misreport #5117 fixes:\n * the phrase invites a reader to believe voter track record moved the number\n * when nothing had ever recorded one.\n */\nfunction describeBasis(basis: WeightBasis): string {\n switch (basis) {\n case 'performance':\n return 'weighted approval (weights from voter performance history)';\n case 'partial':\n return 'partly weighted approval (some voters have no performance history; those count as 1.0)';\n case 'unweighted':\n return 'approval (UNWEIGHTED — no voter performance history recorded)';\n default: {\n const unreachable: never = basis;\n throw new Error(`Unhandled weight basis: ${String(unreachable)}`);\n }\n }\n}\n\n/**\n * Calculate vote weight for an agent based on their performance history.\n *\n * Weight ranges from 0.5 (never correct) to 1.0 (perfect track record). An\n * agent with NO history returns 1.0, not 0.5 — the doc used to say \"0.5 (no\n * history)\", which the code has never done (#5117). The distinction matters:\n * a 1.0 default is indistinguishable from a perfect record by value alone,\n * which is why callers must not infer \"was this measured?\" from the number.\n * `deriveWeightBasis` answers that from provenance instead.\n */\nexport function calculateVoteWeight(performance: AgentPerformance | undefined): number {\n if (performance === undefined || performance.totalVotes === 0) {\n return 1.0; // Default weight for new agents\n }\n\n // Weight = 0.5 + (successRate * 0.5)\n // This gives a range of 0.5 to 1.0 based on historical accuracy\n return 0.5 + performance.successRate * 0.5;\n}\n\n/**\n * Factory for creating voting strategies.\n */\nexport class VotingStrategyFactory {\n private readonly strategies: Map<ConsensusAlgorithm, IVotingStrategy>;\n\n constructor() {\n this.strategies = new Map<ConsensusAlgorithm, IVotingStrategy>([\n ['simple_majority', new SimpleMajorityStrategy()],\n ['supermajority', new SupermajorityStrategy()],\n ['unanimous', new UnanimousStrategy()],\n ['proof_of_learning', new ProofOfLearningStrategy()],\n ['opinion_wise', new HigherOrderVotingStrategy()],\n ['higher_order', new HigherOrderVotingStrategy()],\n ]);\n }\n\n /**\n * Get a voting strategy by algorithm type.\n */\n getStrategy(algorithm: ConsensusAlgorithm): IVotingStrategy {\n const strategy = this.strategies.get(algorithm);\n if (strategy === undefined) {\n throw new Error(`Unknown voting algorithm: ${algorithm}`);\n }\n return strategy;\n }\n\n /**\n * Register a custom voting strategy.\n */\n registerStrategy(strategy: IVotingStrategy): void {\n this.strategies.set(strategy.algorithm, strategy);\n }\n\n /**\n * Get all available algorithm types.\n */\n getAvailableAlgorithms(): ConsensusAlgorithm[] {\n return Array.from(this.strategies.keys());\n }\n}\n\n/**\n * Creates a voting strategy factory with default strategies.\n */\nexport function createStrategyFactory(): VotingStrategyFactory {\n return new VotingStrategyFactory();\n}\n","/**\n * nexus-agents/consensus - Result Builder\n *\n * Helper functions for building consensus results.\n */\n\nimport { getTimeProvider } from '../core/index.js';\nimport type { ProposalId, ProposalState, ConsensusResult, ConsensusEngineConfig } from './types.js';\nimport type { VotingOutcome } from './strategies.js';\nimport { determineFinalStatus } from './decision/verdict.js';\nimport { isQuorumReached } from './decision/quorum.js';\n\n/**\n * `determineFinalStatus` moved to `decision/verdict.ts` (#6000 step 1) so the\n * quorum + approval → outcome step can be governed on its own path.\n * Re-exported here so every existing import keeps resolving.\n *\n * The quorum comparison the three builders inlined moved to\n * `decision/quorum.ts` as `isQuorumReached` (#6180). It was never exported\n * from here, so nothing is re-exported: a verdict site reaches it only\n * through the governed module.\n */\nexport { determineFinalStatus } from './decision/verdict.js';\n\n/**\n * Build a pending result for an active proposal.\n */\nexport function buildPendingResult(\n state: ProposalState,\n proposalId: ProposalId,\n outcome: VotingOutcome,\n config: ConsensusEngineConfig\n): ConsensusResult {\n const now = new Date(getTimeProvider().now());\n return {\n proposalId,\n proposal: state.proposal,\n outcome: state.status === 'voting' ? 'pending' : state.status,\n votes: new Map(state.votes),\n voteCounts: outcome.voteCounts,\n weightedCounts: outcome.weightedCounts,\n weightBasis: outcome.weightBasis,\n approvalPercentage: outcome.approvalPercentage,\n quorumReached: isQuorumReached(state.votes.size, config.minVotersForQuorum),\n startedAt: state.startedAt.toISOString(),\n closedAt: now.toISOString(),\n durationMs: now.getTime() - state.startedAt.getTime(),\n };\n}\n\n/**\n * Build a final result for a closed proposal.\n */\nexport function buildFinalResult(\n state: ProposalState,\n proposalId: ProposalId,\n outcome: VotingOutcome,\n config: ConsensusEngineConfig\n): ConsensusResult {\n const now = new Date(getTimeProvider().now());\n const quorumReached = isQuorumReached(state.votes.size, config.minVotersForQuorum);\n const finalStatus = determineFinalStatus(quorumReached, outcome.approved);\n\n return {\n proposalId,\n proposal: state.proposal,\n outcome: finalStatus,\n votes: new Map(state.votes),\n voteCounts: outcome.voteCounts,\n weightedCounts: outcome.weightedCounts,\n weightBasis: outcome.weightBasis,\n approvalPercentage: outcome.approvalPercentage,\n quorumReached,\n startedAt: state.startedAt.toISOString(),\n closedAt: now.toISOString(),\n durationMs: now.getTime() - state.startedAt.getTime(),\n };\n}\n\n/**\n * Build a timeout result for an expired proposal.\n */\nexport function buildTimeoutResult(\n state: ProposalState,\n proposalId: ProposalId,\n outcome: VotingOutcome,\n config: ConsensusEngineConfig\n): ConsensusResult {\n const now = new Date(getTimeProvider().now());\n return {\n proposalId,\n proposal: state.proposal,\n outcome: 'timeout',\n votes: new Map(state.votes),\n voteCounts: outcome.voteCounts,\n weightedCounts: outcome.weightedCounts,\n weightBasis: outcome.weightBasis,\n approvalPercentage: outcome.approvalPercentage,\n quorumReached: isQuorumReached(state.votes.size, config.minVotersForQuorum),\n startedAt: state.startedAt.toISOString(),\n closedAt: now.toISOString(),\n durationMs: now.getTime() - state.startedAt.getTime(),\n };\n}\n","/**\n * nexus-agents/consensus - Helper Functions\n *\n * Utility functions for the consensus engine.\n */\n\nimport type { ProposalId } from './types.js';\nimport { getTimeProvider, getRandomProvider } from '../core/index.js';\n\n/**\n * Generate a unique proposal ID.\n */\nexport function generateProposalId(): ProposalId {\n const timestamp = getTimeProvider().now().toString(36);\n const random = getRandomProvider().random().toString(36).substring(2, 8);\n return `prop_${timestamp}_${random}`;\n}\n","/**\n * nexus-agents/consensus - Incremental Quorum\n *\n * Detects ambiguous voting scenarios and triggers voter pool expansion.\n * Complements agreement-based cascading (early termination when certain)\n * with expansion when uncertain.\n *\n * (Source: Issue #1408 — Incremental Quorum for Consensus Robustness)\n *\n * @module consensus/incremental-quorum\n */\n\nimport type { Vote } from './types.js';\n\n/**\n * Parameters for ambiguity detection.\n */\nexport interface AmbiguityParams {\n /** Minimum average confidence to avoid expansion. */\n readonly confidenceThreshold: number;\n /** If approval rate is within this band of the threshold, consider ambiguous. */\n readonly ambiguityBand: number;\n}\n\n/**\n * Determines if the current voting state is ambiguous.\n *\n * Ambiguity is detected when:\n * 1. Approval rate is within the ambiguity band of the threshold, OR\n * 2. Average voter confidence is below the confidence threshold\n *\n * @param votes - Current vote map\n * @param totalExpected - Total expected voters\n * @param threshold - Algorithm-specific approval threshold (0-1)\n * @param params - Ambiguity detection parameters\n * @returns true if the voting state is ambiguous\n */\nexport function isVotingAmbiguous(\n votes: ReadonlyMap<string, Vote>,\n totalExpected: number,\n threshold: number,\n params: AmbiguityParams\n): boolean {\n if (votes.size === 0) return false;\n\n let approvals = 0;\n let totalConfidence = 0;\n for (const vote of votes.values()) {\n if (vote.decision === 'approve') approvals++;\n totalConfidence += vote.confidence;\n }\n\n const approvalRate = approvals / totalExpected;\n const avgConfidence = totalConfidence / votes.size;\n\n // Check if approval rate is within the ambiguity band of threshold\n const lowerBand = threshold - params.ambiguityBand;\n const upperBand = threshold + params.ambiguityBand;\n const rateAmbiguous = approvalRate >= lowerBand && approvalRate <= upperBand;\n\n // Check if confidence is too low\n const confidenceAmbiguous = avgConfidence < params.confidenceThreshold;\n\n return rateAmbiguous || confidenceAmbiguous;\n}\n","/* eslint max-lines: [\"error\", { \"max\": 600, \"skipBlankLines\": true, \"skipComments\": true }] */\n// A BOUNDED ceiling, not `eslint-disable max-lines` (#5766).\n//\n// The file is 499 lines by the measure the rule uses (blanks and comments\n// skipped) and 715 by `wc -l`. Those are different units, and comparing them is\n// what went wrong here: the previous comment read the raw 715 against the\n// \"400-600 lines if cohesive\" band in .rules/governance.md:67 and concluded the\n// file \"sits well past the band it invoked\". By the rule's own counting it sits\n// INSIDE that band, so the original justification never stopped holding — only\n// the number quoted against it was measured differently.\n//\n// A blanket disable is why that could go unnoticed for so long: it silenced the\n// one check that knows the real count, leaving a hand-maintained number in a\n// comment as the only record, and hand-maintained numbers rot (this one drifted\n// from 426 to 711 to 715). The ceiling is set at 600 — the TOP of the governance\n// band — so the file is checked against the same band its justification cites,\n// and growing out of it fails the build instead of a comment quietly aging.\n\n/**\n * nexus-agents/consensus - Consensus Engine\n *\n * Core consensus engine implementation supporting multiple voting strategies.\n * Manages proposal lifecycle, vote collection, and outcome determination.\n */\n\nimport type { Result, ILogger } from '../core/index.js';\nimport { ok, err, AgentError, createLogger, getTimeProvider } from '../core/index.js';\nimport type {\n Proposal,\n ProposalId,\n Vote,\n ConsensusResult,\n ConsensusAlgorithm,\n AgentPerformance,\n ConsensusEngineConfig,\n ProposalState,\n ConsensusMetrics,\n ProposalCacheConfig,\n IncrementalQuorumConfig,\n VoterExpansionCallback,\n} from './types.js';\nimport {\n ProposalSchema,\n VoteSchema,\n DEFAULT_CONSENSUS_CONFIG,\n DEFAULT_INCREMENTAL_QUORUM_CONFIG,\n} from './types.js';\nimport { VOTING_THRESHOLDS } from './decision/thresholds.js';\nimport { VotingStrategyFactory, calculateVoteWeight, type VotingOutcome } from './strategies.js';\nimport { buildFinalResult, buildTimeoutResult, buildPendingResult } from './result-builder.js';\nimport { generateProposalId } from './helpers.js';\nimport { isVotingAmbiguous } from './incremental-quorum.js';\n\n/**\n * Error class for consensus-related failures.\n */\nexport class ConsensusError extends AgentError {\n constructor(message: string, context?: Record<string, unknown>) {\n super(message, context !== undefined ? { context } : {});\n this.name = 'ConsensusError';\n }\n}\n\n/**\n * Interface for the consensus engine.\n */\nexport interface IConsensusEngine {\n propose(proposal: Proposal): Promise<Result<ProposalId, ConsensusError>>;\n vote(proposalId: ProposalId, agentId: string, vote: Vote): Promise<Result<void, ConsensusError>>;\n getResult(proposalId: ProposalId): Promise<Result<ConsensusResult, ConsensusError>>;\n close(proposalId: ProposalId): Promise<Result<ConsensusResult, ConsensusError>>;\n getMetrics(): ConsensusMetrics;\n}\n\ninterface InternalMetrics {\n totalProposals: number;\n approvedProposals: number;\n rejectedProposals: number;\n timedOutProposals: number;\n totalDurationMs: number;\n totalVotes: number;\n algorithmUsage: Record<ConsensusAlgorithm, number>;\n}\n\n/**\n * Cache entry for proposal content-based caching (Issue #589).\n */\ninterface ProposalCacheEntry {\n readonly proposalId: ProposalId;\n readonly result: ConsensusResult;\n readonly cachedAt: number;\n}\n\n/**\n * Default proposal cache configuration.\n * Enabled by default to improve determinism (fitness audit recommendation).\n */\n/**\n * Hypothetical-vote stand-ins used by {@link ConsensusEngine.canCascadeEarly}\n * to probe the strategy's outcome under best/worst-case pending votes.\n * The actual `confidence` and `reasoning` fields are never inspected by\n * `IVotingStrategy.calculateOutcome` (all strategies count by `decision`),\n * but must satisfy `VoteSchema` (confidence in [0,1], reasoning non-empty).\n */\nconst HYPOTHETICAL_APPROVE: Vote = {\n decision: 'approve',\n confidence: 0.5,\n reasoning: 'hypothetical-cascade-probe',\n};\nconst HYPOTHETICAL_REJECT: Vote = {\n decision: 'reject',\n confidence: 0.5,\n reasoning: 'hypothetical-cascade-probe',\n};\n\nconst DEFAULT_PROPOSAL_CACHE_CONFIG: ProposalCacheConfig = {\n enabled: true,\n ttlMs: 3600000, // 1 hour\n maxEntries: 500,\n};\n\n/**\n * Consensus engine for multi-agent decision making.\n *\n * @example\n * ```typescript\n * const engine = new ConsensusEngine({ defaultTimeout: 30000 });\n * const proposalResult = await engine.propose({\n * title: 'Use microservices architecture',\n * description: 'Proposal to adopt microservices',\n * algorithm: 'supermajority',\n * });\n * if (proposalResult.ok) {\n * await engine.vote(proposalResult.value, 'agent-1', {\n * decision: 'approve',\n * confidence: 0.9,\n * reasoning: 'Good for scalability',\n * });\n * }\n * ```\n */\nexport class ConsensusEngine implements IConsensusEngine {\n private readonly proposals: Map<ProposalId, ProposalState> = new Map();\n private readonly closedProposals: Map<ProposalId, ConsensusResult> = new Map();\n private readonly agentPerformance: Map<string, AgentPerformance> = new Map();\n private readonly proposalContentCache: Map<string, ProposalCacheEntry> = new Map();\n private readonly strategyFactory: VotingStrategyFactory;\n private readonly config: ConsensusEngineConfig;\n private readonly cacheConfig: ProposalCacheConfig;\n private readonly quorumConfig: IncrementalQuorumConfig;\n private readonly logger: ILogger;\n private readonly metrics: InternalMetrics;\n private voterExpansionCallback?: VoterExpansionCallback;\n\n constructor(config?: Partial<ConsensusEngineConfig>, logger?: ILogger) {\n this.config = { ...DEFAULT_CONSENSUS_CONFIG, ...config };\n this.cacheConfig = { ...DEFAULT_PROPOSAL_CACHE_CONFIG, ...config?.proposalCache };\n this.quorumConfig = { ...DEFAULT_INCREMENTAL_QUORUM_CONFIG, ...config?.incrementalQuorum };\n this.logger = logger ?? createLogger({ component: 'ConsensusEngine' });\n this.strategyFactory = new VotingStrategyFactory();\n this.metrics = this.createInitialMetrics();\n }\n\n /**\n * Sets the callback for incremental quorum voter expansion (Issue #1408).\n * When ambiguous votes are detected, this callback requests additional voters.\n */\n setVoterExpansionCallback(callback: VoterExpansionCallback): void {\n this.voterExpansionCallback = callback;\n }\n\n propose(proposal: Proposal): Promise<Result<ProposalId, ConsensusError>> {\n const validation = ProposalSchema.safeParse(proposal);\n if (!validation.success) {\n return Promise.resolve(\n err(\n new ConsensusError(`Invalid proposal: ${validation.error.message}`, {\n errors: validation.error.issues,\n })\n )\n );\n }\n\n // Check cache for identical proposal content (Issue #589)\n if (this.cacheConfig.enabled) {\n const cachedEntry = this.getCachedResult(validation.data);\n if (cachedEntry !== undefined) {\n this.logger.debug('Returning cached proposal result', {\n cachedProposalId: cachedEntry.proposalId,\n cachedOutcome: cachedEntry.result.outcome,\n });\n return Promise.resolve(ok(cachedEntry.proposalId));\n }\n }\n\n if (this.proposals.size >= this.config.maxActiveProposals) {\n return Promise.resolve(\n err(\n new ConsensusError(\n `Maximum active proposals (${String(this.config.maxActiveProposals)}) reached`\n )\n )\n );\n }\n\n const proposalId = proposal.id ?? generateProposalId();\n const state = this.createProposalState(validation.data, proposalId);\n this.setupTimeout(state, proposalId, proposal.timeout);\n this.registerProposal(proposalId, state, proposal.algorithm);\n return Promise.resolve(ok(proposalId));\n }\n\n async vote(\n proposalId: ProposalId,\n agentId: string,\n vote: Vote\n ): Promise<Result<void, ConsensusError>> {\n const validationErr = this.validateVote(vote);\n if (validationErr !== undefined) return err(validationErr);\n\n const stateErr = this.validateProposalState(proposalId);\n if (stateErr !== undefined) return err(stateErr);\n\n const state = this.proposals.get(proposalId);\n if (state === undefined) {\n return err(new ConsensusError(`Proposal ${proposalId} not found`));\n }\n\n this.recordVote(state, agentId, vote);\n\n // Agreement-based cascade always takes priority\n if (this.canCascadeEarly(state)) {\n return this.closeInternal(proposalId).then((r) => (r.ok ? ok(undefined) : err(r.error)));\n }\n\n // All required voters voted — check for incremental quorum expansion\n if (this.allRequiredVotersVoted(state)) {\n // Re-entry guard (#2861): `tryExpandQuorum` awaits its callback and\n // then mutates `state.proposal.requiredVoters` / `expansionRounds`.\n // A concurrent `vote()` that also sees `allRequiredVotersVoted`\n // must NOT start a second expansion — that would invoke the\n // expansion callback twice and clobber the first expansion's\n // voter list. This vote is already recorded; return ok and let\n // the in-flight expansion settle.\n if (state.expansionInFlight === true) {\n return Promise.resolve(ok(undefined));\n }\n state.expansionInFlight = true;\n let expanded: boolean;\n try {\n expanded = await this.tryExpandQuorum(proposalId, state);\n } finally {\n state.expansionInFlight = false;\n }\n if (!expanded) {\n return this.closeInternal(proposalId).then((r) => (r.ok ? ok(undefined) : err(r.error)));\n }\n // Expansion succeeded — wait for new voters\n }\n\n return Promise.resolve(ok(undefined));\n }\n\n getResult(proposalId: ProposalId): Promise<Result<ConsensusResult, ConsensusError>> {\n const closedResult = this.closedProposals.get(proposalId);\n if (closedResult !== undefined) return Promise.resolve(ok(closedResult));\n\n const state = this.proposals.get(proposalId);\n if (state === undefined) {\n return Promise.resolve(err(new ConsensusError(`Proposal ${proposalId} not found`)));\n }\n\n const outcome = this.calculateOutcome(state);\n return Promise.resolve(ok(buildPendingResult(state, proposalId, outcome, this.config)));\n }\n\n close(proposalId: ProposalId): Promise<Result<ConsensusResult, ConsensusError>> {\n return this.closeInternal(proposalId);\n }\n\n getMetrics(): ConsensusMetrics {\n const completed =\n this.metrics.approvedProposals +\n this.metrics.rejectedProposals +\n this.metrics.timedOutProposals;\n return {\n totalProposals: this.metrics.totalProposals,\n approvedProposals: this.metrics.approvedProposals,\n rejectedProposals: this.metrics.rejectedProposals,\n timedOutProposals: this.metrics.timedOutProposals,\n averageDurationMs: completed > 0 ? this.metrics.totalDurationMs / completed : 0,\n averageVotesPerProposal: completed > 0 ? this.metrics.totalVotes / completed : 0,\n algorithmUsage: { ...this.metrics.algorithmUsage },\n };\n }\n\n updateAgentPerformance(agentId: string, wasCorrect: boolean): void {\n const existing = this.agentPerformance.get(agentId);\n const now = getTimeProvider().nowIso();\n\n if (existing === undefined) {\n this.agentPerformance.set(agentId, {\n agentId,\n totalVotes: 1,\n correctVotes: wasCorrect ? 1 : 0,\n successRate: wasCorrect ? 1.0 : 0.0,\n lastUpdated: now,\n });\n } else {\n const totalVotes = existing.totalVotes + 1;\n const correctVotes = existing.correctVotes + (wasCorrect ? 1 : 0);\n this.agentPerformance.set(agentId, {\n agentId,\n totalVotes,\n correctVotes,\n successRate: correctVotes / totalVotes,\n lastUpdated: now,\n });\n }\n }\n\n getAgentPerformance(agentId: string): AgentPerformance | undefined {\n return this.agentPerformance.get(agentId);\n }\n\n getActiveProposalCount(): number {\n return this.proposals.size;\n }\n\n private createProposalState(data: Proposal, proposalId: ProposalId): ProposalState {\n const now = new Date(getTimeProvider().now());\n return {\n proposal: { ...data, id: proposalId, createdAt: now.toISOString() },\n status: 'voting',\n votes: new Map(),\n voteWeights: new Map(),\n startedAt: now,\n };\n }\n\n private setupTimeout(state: ProposalState, proposalId: ProposalId, timeout?: number): void {\n const timeoutMs = timeout ?? this.config.defaultTimeout;\n state.timeoutId = setTimeout(() => {\n this.handleTimeout(proposalId);\n }, timeoutMs);\n }\n\n private registerProposal(\n proposalId: ProposalId,\n state: ProposalState,\n algorithm: ConsensusAlgorithm\n ): void {\n this.proposals.set(proposalId, state);\n this.metrics.totalProposals++;\n this.metrics.algorithmUsage[algorithm]++;\n this.logger.info('Proposal created', {\n proposalId,\n title: state.proposal.title,\n algorithm,\n timeout: this.config.defaultTimeout,\n });\n }\n\n private validateVote(vote: Vote): ConsensusError | undefined {\n const validation = VoteSchema.safeParse(vote);\n if (!validation.success) {\n return new ConsensusError(`Invalid vote: ${validation.error.message}`, {\n errors: validation.error.issues,\n });\n }\n return undefined;\n }\n\n private validateProposalState(proposalId: ProposalId): ConsensusError | undefined {\n const state = this.proposals.get(proposalId);\n if (state === undefined) {\n if (this.closedProposals.has(proposalId)) {\n return new ConsensusError(`Proposal ${proposalId} is already closed`);\n }\n return new ConsensusError(`Proposal ${proposalId} not found`);\n }\n if (state.status !== 'voting') {\n return new ConsensusError(`Proposal ${proposalId} is not accepting votes`, {\n status: state.status,\n });\n }\n return undefined;\n }\n\n private recordVote(state: ProposalState, agentId: string, vote: Vote): void {\n state.votes.set(agentId, {\n ...vote,\n timestamp: getTimeProvider().nowIso(),\n });\n if (state.proposal.algorithm === 'proof_of_learning') {\n // Only record a weight when a performance record actually EXISTS (#5117).\n // This used to call `calculateVoteWeight(undefined)`, which returns the\n // 1.0 new-agent default, so the map was fully populated whether or not\n // anything had ever been measured — and by the time the strategy saw it,\n // \"weighted at 1.0 because they are reliable\" and \"weighted at 1.0\n // because we know nothing\" were indistinguishable.\n //\n // Absence now carries that provenance. The arithmetic is unchanged:\n // `countWeightedVotes` already defaults a missing entry to 1.0.\n const performance = this.agentPerformance.get(agentId);\n if (performance !== undefined) {\n state.voteWeights.set(agentId, calculateVoteWeight(performance));\n }\n }\n this.logger.debug('Vote recorded', {\n proposalId: state.proposal.id,\n agentId,\n decision: vote.decision,\n confidence: vote.confidence,\n });\n }\n\n private closeInternal(proposalId: ProposalId): Promise<Result<ConsensusResult, ConsensusError>> {\n const state = this.proposals.get(proposalId);\n if (state === undefined) {\n const closed = this.closedProposals.get(proposalId);\n if (closed !== undefined) return Promise.resolve(ok(closed));\n return Promise.resolve(err(new ConsensusError(`Proposal ${proposalId} not found`)));\n }\n\n if (state.timeoutId !== undefined) clearTimeout(state.timeoutId);\n\n const outcome = this.calculateOutcome(state);\n const result = buildFinalResult(state, proposalId, outcome, this.config);\n this.finalize(proposalId, result, state.votes.size);\n return Promise.resolve(ok(result));\n }\n\n private handleTimeout(proposalId: ProposalId): void {\n const state = this.proposals.get(proposalId);\n if (state?.status !== 'voting') return;\n\n this.logger.warn('Proposal timed out', { proposalId, voteCount: state.votes.size });\n const outcome = this.calculateOutcome(state);\n const result = buildTimeoutResult(state, proposalId, outcome, this.config);\n this.proposals.delete(proposalId);\n this.addClosedProposal(proposalId, result);\n this.metrics.timedOutProposals++;\n this.metrics.totalDurationMs += result.durationMs;\n this.metrics.totalVotes += state.votes.size;\n }\n\n private finalize(proposalId: ProposalId, result: ConsensusResult, voteCount: number): void {\n this.proposals.delete(proposalId);\n this.addClosedProposal(proposalId, result);\n this.updateMetrics(result);\n\n // Cache successful results for determinism (Issue #589)\n if (\n this.cacheConfig.enabled &&\n (result.outcome === 'approved' || result.outcome === 'rejected')\n ) {\n this.addToCache(result.proposal, proposalId, result);\n }\n\n this.logger.info('Proposal closed', {\n proposalId,\n outcome: result.outcome,\n approvalPercentage: result.approvalPercentage.toFixed(1),\n voteCount,\n quorumReached: result.quorumReached,\n durationMs: result.durationMs,\n });\n }\n\n /**\n * Adds a closed proposal and evicts oldest entries if over limit.\n * Issue #549: Prevent unbounded memory growth in closedProposals Map.\n */\n private addClosedProposal(proposalId: ProposalId, result: ConsensusResult): void {\n // Evict oldest entries if at capacity (Map maintains insertion order)\n while (this.closedProposals.size >= this.config.maxClosedProposals) {\n const firstKey = this.closedProposals.keys().next();\n if (firstKey.done === true) break;\n const oldestKey = firstKey.value;\n this.closedProposals.delete(oldestKey);\n this.logger.debug('Evicted oldest closed proposal', { evictedId: oldestKey });\n }\n this.closedProposals.set(proposalId, result);\n }\n\n private calculateOutcome(state: ProposalState): VotingOutcome {\n const strategy = this.strategyFactory.getStrategy(state.proposal.algorithm);\n const outcome: VotingOutcome = strategy.calculateOutcome(state.votes, state.voteWeights);\n return outcome;\n }\n\n /**\n * Agreement-based cascading: close early when outcome is mathematically determined.\n *\n * #2822: the prior implementation computed approval rates against\n * `totalExpected = requiredVoters.length` and compared against\n * `VOTING_THRESHOLDS[algorithm]` directly. Every voting strategy\n * (`SimpleMajorityStrategy`, `SupermajorityStrategy`, `UnanimousStrategy`,\n * `ProofOfLearningStrategy`) uses `approve + reject` as its denominator —\n * abstains are explicitly excluded. The two diverged whenever abstains\n * were present, producing wrong-winner cascades (e.g. 5-voter supermajority\n * with [approve, abstain, abstain, abstain, pending] cascade-rejected even\n * though the strategy would approve at close).\n *\n * The fix delegates to the strategy itself: build a best-case (all pending\n * voters approve) and worst-case (all pending voters reject) hypothetical\n * vote map, call `strategy.calculateOutcome` on each, and cascade only\n * when both extremes yield the same outcome. This guarantees parity with\n * the strategy's denominator semantics by construction.\n */\n private canCascadeEarly(state: ProposalState): boolean {\n const required = state.proposal.requiredVoters;\n if (required === undefined || required.length === 0) return false;\n if (state.votes.size === 0) return false;\n\n const pending = required.filter((voter) => !state.votes.has(voter));\n if (pending.length === 0) return false; // All voted — handled by allRequiredVotersVoted\n\n const strategy = this.strategyFactory.getStrategy(state.proposal.algorithm);\n\n const bestCase = new Map<string, Vote>(state.votes);\n const worstCase = new Map<string, Vote>(state.votes);\n for (const voter of pending) {\n bestCase.set(voter, HYPOTHETICAL_APPROVE);\n worstCase.set(voter, HYPOTHETICAL_REJECT);\n }\n\n const bestOutcome = strategy.calculateOutcome(bestCase, state.voteWeights);\n const worstOutcome = strategy.calculateOutcome(worstCase, state.voteWeights);\n\n if (bestOutcome.approved !== worstOutcome.approved) return false;\n\n this.logger.info('Agreement cascade: outcome determined', {\n proposalId: state.proposal.id,\n outcome: bestOutcome.approved ? 'approve' : 'reject',\n votesCast: state.votes.size,\n pending: pending.length,\n algorithm: state.proposal.algorithm,\n });\n return true;\n }\n\n private allRequiredVotersVoted(state: ProposalState): boolean {\n const required = state.proposal.requiredVoters;\n if (required === undefined || required.length === 0) return false;\n return required.every((voterId) => state.votes.has(voterId));\n }\n\n /**\n * Attempts incremental quorum expansion when voting is ambiguous (Issue #1408).\n * Returns true if expansion occurred (wait for new voters), false to close immediately.\n */\n private async tryExpandQuorum(proposalId: ProposalId, state: ProposalState): Promise<boolean> {\n if (!this.quorumConfig.enabled) return false;\n if (this.voterExpansionCallback === undefined) return false;\n\n const rounds = state.expansionRounds ?? 0;\n if (rounds >= this.quorumConfig.maxExpansionRounds) return false;\n\n const required = state.proposal.requiredVoters;\n if (required === undefined) return false;\n\n const threshold = VOTING_THRESHOLDS[state.proposal.algorithm];\n const ambiguous = isVotingAmbiguous(state.votes, required.length, threshold, {\n confidenceThreshold: this.quorumConfig.confidenceThreshold,\n ambiguityBand: this.quorumConfig.ambiguityBand,\n });\n\n if (!ambiguous) return false;\n\n let newVoters: readonly string[];\n try {\n newVoters = await this.voterExpansionCallback(\n proposalId,\n required.length,\n this.quorumConfig.votersPerExpansion\n );\n } catch (err: unknown) {\n const error = err instanceof Error ? err : new Error(String(err));\n this.logger.warn('Incremental quorum: expansion callback threw; closing as-is', {\n proposalId,\n errorMessage: error.message,\n });\n return false;\n }\n\n if (newVoters.length === 0) {\n this.logger.info('Incremental quorum: no additional voters available', { proposalId });\n return false;\n }\n\n // Expand the required voters list\n state.proposal.requiredVoters = [...required, ...newVoters];\n state.expansionRounds = rounds + 1;\n\n this.logger.info('Incremental quorum: expanded voter pool', {\n proposalId,\n round: rounds + 1,\n newVoters: newVoters.length,\n totalVoters: state.proposal.requiredVoters.length,\n });\n\n return true;\n }\n\n private updateMetrics(result: ConsensusResult): void {\n this.metrics.totalDurationMs += result.durationMs;\n this.metrics.totalVotes += result.voteCounts.total;\n if (result.outcome === 'approved') this.metrics.approvedProposals++;\n else if (result.outcome === 'rejected') this.metrics.rejectedProposals++;\n else if (result.outcome === 'timeout') this.metrics.timedOutProposals++;\n }\n\n private createInitialMetrics(): InternalMetrics {\n return {\n totalProposals: 0,\n approvedProposals: 0,\n rejectedProposals: 0,\n timedOutProposals: 0,\n totalDurationMs: 0,\n totalVotes: 0,\n algorithmUsage: {\n simple_majority: 0,\n supermajority: 0,\n unanimous: 0,\n proof_of_learning: 0,\n opinion_wise: 0,\n higher_order: 0,\n },\n };\n }\n\n // ============================================================================\n // Proposal Content Caching (Issue #589)\n // ============================================================================\n\n /**\n * Creates a content hash for a proposal to enable cache lookups.\n * Hash is based on title, description, and algorithm (deterministic content).\n */\n private hashProposalContent(proposal: Proposal): string {\n const content = [proposal.title, proposal.description, proposal.algorithm].join('|');\n // Simple FNV-1a hash for fast deterministic hashing\n let hash = 2166136261;\n for (let i = 0; i < content.length; i++) {\n hash ^= content.charCodeAt(i);\n hash = Math.imul(hash, 16777619);\n }\n return (hash >>> 0).toString(16);\n }\n\n /**\n * Gets cached result for a proposal if it exists and hasn't expired.\n */\n private getCachedResult(proposal: Proposal): ProposalCacheEntry | undefined {\n const hash = this.hashProposalContent(proposal);\n const cached = this.proposalContentCache.get(hash);\n if (cached === undefined) return undefined;\n\n const now = getTimeProvider().now();\n if (now - cached.cachedAt > this.cacheConfig.ttlMs) {\n this.proposalContentCache.delete(hash);\n this.logger.debug('Cache entry expired', { hash });\n return undefined;\n }\n\n return cached;\n }\n\n /**\n * Adds a proposal result to the cache, evicting oldest entries if needed.\n */\n private addToCache(proposal: Proposal, proposalId: ProposalId, result: ConsensusResult): void {\n const hash = this.hashProposalContent(proposal);\n\n // Evict oldest entries if at capacity (Map maintains insertion order)\n while (this.proposalContentCache.size >= this.cacheConfig.maxEntries) {\n const firstKey = this.proposalContentCache.keys().next();\n if (firstKey.done === true) break;\n const oldestKey = firstKey.value;\n this.proposalContentCache.delete(oldestKey);\n this.logger.debug('Evicted oldest cache entry', { hash: oldestKey });\n }\n\n this.proposalContentCache.set(hash, {\n proposalId,\n result,\n cachedAt: getTimeProvider().now(),\n });\n this.logger.debug('Added proposal to cache', { hash, proposalId });\n }\n\n /**\n * Gets the current cache size (for testing/monitoring).\n */\n getCacheSize(): number {\n return this.proposalContentCache.size;\n }\n\n /**\n * Clears the proposal content cache (for testing/reset).\n */\n clearCache(): void {\n this.proposalContentCache.clear();\n this.logger.debug('Proposal cache cleared');\n }\n}\n\n/**\n * Create a consensus engine with the given configuration.\n *\n * @example\n * ```typescript\n * const engine = createConsensusEngine({\n * defaultTimeout: 60000,\n * maxActiveProposals: 10,\n * });\n * ```\n */\nexport function createConsensusEngine(\n config?: Partial<ConsensusEngineConfig>,\n logger?: ILogger\n): ConsensusEngine {\n return new ConsensusEngine(config, logger);\n}\n","/**\n * Unified Quorum Validator\n *\n * SCOPE, corrected (#4666). This module's docstring claimed it \"abstracts\n * quorum validation across VotingProtocol, WeightedVoting, and ConsensusEngine\"\n * and consolidates three implementations. It has exactly ONE consumer:\n * `voting-protocol-helpers.ts`. `WeightedVoting` and `ConsensusEngine` do not\n * use it. The intent from #576 was real; the consolidation did not happen, and\n * the doc has been describing the plan as though it were the state.\n *\n * A second, sharper caveat for anyone relying on this: `VotingProtocol` — the\n * one path that reaches here — has **no in-tree caller**. `createVotingProtocol`\n * is exported through `exports/consensus.ts` as public API and is constructed\n * only by tests. So this validator runs only for an external embedder.\n *\n * Agent eligibility screening was REMOVED here under #4666 (consensus_vote 7-0).\n * It could never exclude anyone: its sole caller passed no `AgentRecord`, and no\n * producer of trust scores or Byzantine flags exists anywhere in `src/`. The\n * breakdown nonetheless emitted an `eligibleAgents` list containing every voter,\n * which a machine consumer reads as evidence that screening ran — a comment\n * cannot travel with a serialized record. Git history holds the implementation\n * for whenever a real trust-score producer appears.\n *\n * @module consensus/quorum-validator\n * (Source: Issue #576, ADR-0003; scope corrected #4666)\n */\n\nimport { createLogger, formatPercentage, type ILogger } from '../core/index.js';\nimport type { ConsensusAlgorithm, Vote, VoteCounts, WeightedVoteCounts } from './types-core.js';\nimport { SUPERMAJORITY_THRESHOLD } from './decision/thresholds.js';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Quorum validation configuration.\n */\nexport interface QuorumValidationConfig {\n /** Algorithm type */\n readonly algorithm: ConsensusAlgorithm | 'weighted_byzantine';\n /** Numeric threshold (0-1 for percentage, 0-N for weighted sum) */\n readonly threshold: number;\n /** Minimum voters required */\n readonly minVoters: number;\n /** Apply confidence multiplier to weights */\n readonly confidenceMultiplier?: boolean;\n /** Include abstentions in quorum calculation */\n readonly includeAbstentions?: boolean;\n}\n\n/**\n * Input for quorum validation.\n */\nexport interface QuorumValidationInput {\n /** Votes cast by agent ID */\n readonly votes: ReadonlyMap<string, Vote>;\n /** Optional: Pre-calculated agent weights */\n readonly agentWeights?: ReadonlyMap<string, number>;\n /** Configuration */\n readonly config: QuorumValidationConfig;\n /** Optional: Required participant count (for ratio-based quorum) */\n readonly requiredParticipants?: number;\n}\n\n/**\n * Quorum validation result (discriminated union).\n */\nexport type QuorumValidationResult =\n | {\n readonly status: 'reached';\n readonly decision: 'approve' | 'reject';\n readonly confidence: number;\n readonly reasoning: string;\n }\n | {\n readonly status: 'not_reached';\n readonly reason: 'insufficient_votes' | 'insufficient_weight' | 'no_consensus';\n readonly details: string;\n }\n | { readonly status: 'invalid'; readonly error: string }\n | { readonly status: 'timeout'; readonly partial: boolean; readonly details: string };\n\n/**\n * Detailed quorum breakdown for observability.\n */\nexport interface QuorumBreakdown {\n readonly totalVotes: number;\n readonly voteCounts: VoteCounts;\n readonly totalWeight: number | undefined;\n readonly weightedCounts: WeightedVoteCounts | undefined;\n readonly threshold: number;\n readonly actualQuorum: number;\n readonly quorumReached: boolean;\n readonly reasoning: string;\n}\n\n/**\n * Unified quorum validator interface.\n */\nexport interface IQuorumValidator {\n validateQuorum(input: QuorumValidationInput): QuorumValidationResult;\n getQuorumBreakdown(input: QuorumValidationInput): QuorumBreakdown;\n}\n\n// ============================================================================\n// Implementation\n// ============================================================================\n\n/**\n * Default quorum thresholds by algorithm type.\n * Used for reference when config.threshold is not specified.\n */\nexport const DEFAULT_QUORUM_THRESHOLDS: Readonly<\n Record<ConsensusAlgorithm | 'weighted_byzantine', number>\n> = {\n simple_majority: 0.5,\n supermajority: SUPERMAJORITY_THRESHOLD,\n unanimous: 1.0,\n proof_of_learning: 0.5,\n opinion_wise: 0.5,\n higher_order: 0.5,\n // Byzantine fault tolerance also requires 2/3 — the same supermajority.\n weighted_byzantine: SUPERMAJORITY_THRESHOLD,\n};\n\n/**\n * Tolerance under which approve and reject tallies are an exact tie (#6051).\n *\n * Weighted tallies are sums of voter weights (optionally scaled by vote\n * confidence), so two panels that tie in exact arithmetic can differ at the\n * 1e-16 level in IEEE-754 (`0.1 + 0.2 + 1.0 !== 1.3`). A strict `===` would\n * call that a 2e-16 majority; this tolerance is far above float noise and far\n * below the smallest weight difference a caller could intend (weights are\n * conventionally in [0, 1] with a handful of decimals).\n */\nconst TIE_TOLERANCE = 1e-9;\n\n/** Inputs to the quorum-status calculation, grouped to stay within max-params. */\ninterface QuorumStatusInput {\n readonly voteCounts: VoteCounts;\n readonly weightedCounts: WeightedVoteCounts | undefined;\n readonly totalWeight: number | undefined;\n readonly config: QuorumValidationConfig;\n readonly requiredParticipants: number;\n /** Whether any voter had a weight SUPPLIED — provenance, not value (#5117). */\n readonly anyWeightSupplied: boolean;\n}\n\n/** Inputs to the weighted-quorum reasoning string. */\ninterface WeightedReasoningInput {\n readonly quorumReached: boolean;\n readonly totalWeight: number;\n readonly threshold: number;\n readonly approveRatio: number;\n readonly rejectRatio: number;\n /** False when no agent weights were supplied — the tally is a headcount. */\n readonly weighted: boolean;\n}\n\n/**\n * Unified quorum validator implementation.\n */\nexport class QuorumValidator implements IQuorumValidator {\n private readonly logger: ILogger;\n\n constructor(logger?: ILogger) {\n this.logger = logger ?? createLogger({ component: 'QuorumValidator' });\n }\n\n validateQuorum(input: QuorumValidationInput): QuorumValidationResult {\n const { votes, config } = input;\n\n // Validate input\n if (votes.size === 0) {\n return { status: 'invalid', error: 'No votes provided' };\n }\n\n // Calculate breakdown\n const breakdown = this.getQuorumBreakdown(input);\n\n // Check if quorum reached\n if (!breakdown.quorumReached) {\n return this.buildNotReachedResult(breakdown, config);\n }\n\n // A tie is not a decision (#6051). At the schema-minimum threshold (0.5)\n // both sides clear the bar, and the old `>=` tie-break reported a 3-3\n // panel as `approve` with the only tie signal (confidence 0) left for the\n // caller to notice. Keep the tie out of the reached path entirely.\n if (this.isTie(breakdown)) {\n return this.buildTieResult(breakdown);\n }\n\n // Determine decision\n return this.buildReachedResult(breakdown);\n }\n\n getQuorumBreakdown(input: QuorumValidationInput): QuorumBreakdown {\n const { votes, agentWeights, config, requiredParticipants } = input;\n\n // Count votes\n const voteCounts = this.countVotes(votes);\n\n // Calculate weights if applicable\n const { totalWeight, weightedCounts } = this.calculateWeights(votes, agentWeights, config);\n\n // Whether any voter actually had a weight SUPPLIED (#5117). Derived from\n // provenance — presence in `agentWeights` — not from whether a weight\n // differs from 1.0: an agent legitimately weighted 1.0 is not the same as\n // one nobody ever weighted, and numeric equality cannot tell them apart.\n const anyWeightSupplied = [...votes.keys()].some((id) => agentWeights?.has(id) === true);\n\n // Calculate quorum based on algorithm\n const { threshold, actualQuorum, quorumReached, reasoning } = this.calculateQuorumStatus({\n voteCounts,\n weightedCounts,\n totalWeight,\n config,\n requiredParticipants: requiredParticipants ?? votes.size,\n anyWeightSupplied,\n });\n\n return {\n totalVotes: votes.size,\n voteCounts,\n totalWeight,\n weightedCounts,\n threshold,\n actualQuorum,\n quorumReached,\n reasoning,\n };\n }\n\n private countVotes(votes: ReadonlyMap<string, Vote>): VoteCounts {\n let approve = 0;\n let reject = 0;\n let abstain = 0;\n\n for (const vote of votes.values()) {\n switch (vote.decision) {\n case 'approve':\n approve++;\n break;\n case 'reject':\n reject++;\n break;\n case 'abstain':\n abstain++;\n break;\n }\n }\n\n return { approve, reject, abstain, total: votes.size };\n }\n\n private calculateWeights(\n votes: ReadonlyMap<string, Vote>,\n agentWeights: ReadonlyMap<string, number> | undefined,\n config: QuorumValidationConfig\n ): { totalWeight: number | undefined; weightedCounts: WeightedVoteCounts | undefined } {\n // Skip weight calculation for simple algorithms\n if (config.algorithm === 'simple_majority' || config.algorithm === 'unanimous') {\n return { totalWeight: undefined, weightedCounts: undefined };\n }\n\n const counts = { totalWeight: 0, approve: 0, reject: 0, abstain: 0 };\n\n for (const [agentId, vote] of votes.entries()) {\n const weight = this.getVoteWeight(agentId, vote, agentWeights, config);\n counts.totalWeight += weight;\n this.addWeightToDecision(counts, vote.decision, weight);\n }\n\n return {\n totalWeight: counts.totalWeight,\n weightedCounts: {\n approve: counts.approve,\n reject: counts.reject,\n abstain: counts.abstain,\n totalWeight: counts.totalWeight,\n },\n };\n }\n\n private getVoteWeight(\n agentId: string,\n vote: Vote,\n agentWeights: ReadonlyMap<string, number> | undefined,\n config: QuorumValidationConfig\n ): number {\n let weight = agentWeights?.get(agentId) ?? 1.0;\n if (config.confidenceMultiplier === true) {\n weight *= vote.confidence;\n }\n return weight;\n }\n\n private addWeightToDecision(\n counts: { approve: number; reject: number; abstain: number },\n decision: 'approve' | 'reject' | 'abstain',\n weight: number\n ): void {\n counts[decision] += weight;\n }\n\n private calculateQuorumStatus(opts: QuorumStatusInput): {\n threshold: number;\n actualQuorum: number;\n quorumReached: boolean;\n reasoning: string;\n } {\n const {\n voteCounts,\n weightedCounts,\n totalWeight,\n config,\n requiredParticipants,\n anyWeightSupplied,\n } = opts;\n const threshold = config.threshold;\n\n // For weighted algorithms, use weighted counts\n if (weightedCounts !== undefined && totalWeight !== undefined && totalWeight > 0) {\n return this.calculateWeightedQuorum(\n weightedCounts,\n totalWeight,\n threshold,\n anyWeightSupplied\n );\n }\n\n // For simple algorithms, use vote counts\n return this.calculateSimpleQuorum(voteCounts, requiredParticipants, threshold, config);\n }\n\n private calculateWeightedQuorum(\n weightedCounts: WeightedVoteCounts,\n totalWeight: number,\n threshold: number,\n anyWeightSupplied: boolean\n ): { threshold: number; actualQuorum: number; quorumReached: boolean; reasoning: string } {\n const quorumReached = totalWeight >= threshold;\n const approveRatio = weightedCounts.approve / totalWeight;\n const rejectRatio = weightedCounts.reject / totalWeight;\n\n const reasoning = this.buildWeightedReasoning({\n quorumReached,\n totalWeight,\n threshold,\n approveRatio,\n rejectRatio,\n weighted: anyWeightSupplied,\n });\n\n return { threshold, actualQuorum: totalWeight, quorumReached, reasoning };\n }\n\n /**\n * Reasoning text for the weighted-quorum branch.\n *\n * `weighted` is qualified rather than asserted (#5117). `agentWeights` has no\n * non-test producer, so every real call reaches `getVoteWeight`'s `?? 1.0`\n * fallback and this branch describes a plain headcount as a weighted ratio.\n * The word is kept where weights genuinely varied and replaced where they\n * did not, so the reader can tell the two apart.\n */\n private buildWeightedReasoning(opts: WeightedReasoningInput): string {\n const { quorumReached, totalWeight, threshold, approveRatio, rejectRatio, weighted } = opts;\n const kind = weighted ? 'weighted' : 'unweighted (no agent weights supplied)';\n if (!quorumReached) {\n return `Quorum not reached: ${totalWeight.toFixed(2)} < ${String(threshold)} (${kind})`;\n }\n if (approveRatio > rejectRatio) {\n return `Approval wins with ${kind} ratio ${formatPercentage(approveRatio, 1)}`;\n }\n if (rejectRatio > approveRatio) {\n return `Rejection wins with ${kind} ratio ${formatPercentage(rejectRatio, 1)}`;\n }\n return `No clear winner: approve=${formatPercentage(approveRatio, 1)}, reject=${formatPercentage(rejectRatio, 1)} (${kind})`;\n }\n\n private calculateSimpleQuorum(\n voteCounts: VoteCounts,\n requiredParticipants: number,\n threshold: number,\n config: QuorumValidationConfig\n ): { threshold: number; actualQuorum: number; quorumReached: boolean; reasoning: string } {\n const activeVotes =\n config.includeAbstentions === true\n ? voteCounts.total\n : voteCounts.approve + voteCounts.reject;\n\n const total = requiredParticipants > 0 ? requiredParticipants : activeVotes;\n const approveRatio = total > 0 ? voteCounts.approve / total : 0;\n const rejectRatio = total > 0 ? voteCounts.reject / total : 0;\n\n const hasMinVoters = activeVotes >= config.minVoters;\n const quorumReached = hasMinVoters && (approveRatio >= threshold || rejectRatio >= threshold);\n\n const reasoning = this.buildSimpleReasoning({\n hasMinVoters,\n activeVotes,\n minVoters: config.minVoters,\n approveRatio,\n rejectRatio,\n threshold,\n });\n\n return {\n threshold,\n actualQuorum: Math.max(approveRatio, rejectRatio),\n quorumReached,\n reasoning,\n };\n }\n\n private buildSimpleReasoning(params: {\n hasMinVoters: boolean;\n activeVotes: number;\n minVoters: number;\n approveRatio: number;\n rejectRatio: number;\n threshold: number;\n }): string {\n const { hasMinVoters, activeVotes, minVoters, approveRatio, rejectRatio, threshold } = params;\n if (!hasMinVoters) {\n return `Insufficient voters: ${String(activeVotes)} < ${String(minVoters)}`;\n }\n if (approveRatio >= threshold) {\n return `Approval reaches threshold: ${formatPercentage(approveRatio, 1)} >= ${formatPercentage(threshold, 1)}`;\n }\n if (rejectRatio >= threshold) {\n return `Rejection reaches threshold: ${formatPercentage(rejectRatio, 1)} >= ${formatPercentage(threshold, 1)}`;\n }\n return `No decision reached threshold: approve=${formatPercentage(approveRatio, 1)}, reject=${formatPercentage(rejectRatio, 1)}`;\n }\n\n private buildNotReachedResult(\n breakdown: QuorumBreakdown,\n config: QuorumValidationConfig\n ): QuorumValidationResult {\n const { voteCounts, weightedCounts, threshold } = breakdown;\n\n if (voteCounts.total < config.minVoters) {\n return {\n status: 'not_reached',\n reason: 'insufficient_votes',\n details: `Only ${String(voteCounts.total)} votes, need ${String(config.minVoters)}`,\n };\n }\n\n if (weightedCounts !== undefined && weightedCounts.totalWeight < threshold) {\n return {\n status: 'not_reached',\n reason: 'insufficient_weight',\n details: `Weight ${weightedCounts.totalWeight.toFixed(2)} < threshold ${String(threshold)}`,\n };\n }\n\n return {\n status: 'not_reached',\n reason: 'no_consensus',\n details: breakdown.reasoning,\n };\n }\n\n /** The tallies a decision is drawn from: weighted when weights apply, else headcount. */\n private decisiveTallies(breakdown: QuorumBreakdown): {\n approves: number;\n rejects: number;\n total: number;\n } {\n const { voteCounts, weightedCounts } = breakdown;\n return {\n approves: weightedCounts?.approve ?? voteCounts.approve,\n rejects: weightedCounts?.reject ?? voteCounts.reject,\n total: weightedCounts?.totalWeight ?? voteCounts.total,\n };\n }\n\n private isTie(breakdown: QuorumBreakdown): boolean {\n const { approves, rejects } = this.decisiveTallies(breakdown);\n return Math.abs(approves - rejects) < TIE_TOLERANCE;\n }\n\n /**\n * A tie reuses the existing `no_consensus` variant rather than a new status\n * member (a new member is breaking for exhaustive switches downstream). The\n * tie survives in `details`, which is the only place it can be read from.\n */\n private buildTieResult(breakdown: QuorumBreakdown): QuorumValidationResult {\n const { approves, rejects } = this.decisiveTallies(breakdown);\n const kind = breakdown.weightedCounts === undefined ? '' : ' (weighted)';\n return {\n status: 'not_reached',\n reason: 'no_consensus',\n details: `tie: ${formatTally(approves)} approve vs ${formatTally(rejects)} reject${kind}; consensus not reached`,\n };\n }\n\n private buildReachedResult(breakdown: QuorumBreakdown): QuorumValidationResult {\n const { approves, rejects, total } = this.decisiveTallies(breakdown);\n\n // Determine winning decision. A tie never reaches here (`isTie` guards\n // the call), so the comparison is strict: `>=` would silently re-open the\n // tie-as-approval defect if the guard were ever removed (#6051).\n const decision: 'approve' | 'reject' = approves > rejects ? 'approve' : 'reject';\n const confidence = total > 0 ? Math.abs(approves - rejects) / total : 0;\n\n return {\n status: 'reached',\n decision,\n confidence,\n reasoning: breakdown.reasoning,\n };\n }\n}\n\n/** Integers print as counts (`3`); weighted sums keep two decimals (`1.30`). */\nfunction formatTally(value: number): string {\n return Number.isInteger(value) ? String(value) : value.toFixed(2);\n}\n\n/**\n * Creates a quorum validator instance.\n */\nexport function createQuorumValidator(logger?: ILogger): IQuorumValidator {\n return new QuorumValidator(logger);\n}\n","/**\n * Helper functions for the multi-round voting protocol.\n *\n * @module consensus/voting-protocol-helpers\n * (Source: Issue #100, arXiv:2512.21352)\n */\n\nimport type {\n VotingSession,\n VotingRound,\n VotingRoundPhase,\n VotingProtocolConfig,\n VotingProtocolResult,\n AgentFinding,\n Vote,\n ConsolidatedFinding,\n RoundSummary,\n SycophancyReport,\n SycophancyIndicator,\n} from './types.js';\nimport { createQuorumValidator, type QuorumValidationConfig } from './quorum-validator.js';\nimport { getTimeProvider, getRandomProvider } from '../core/index.js';\n\n/**\n * Generate a unique session ID.\n */\nexport function generateSessionId(): string {\n const time = getTimeProvider();\n const random = getRandomProvider();\n return `session_${String(time.now())}_${random.randomString(7)}`;\n}\n\n/**\n * Generate a unique finding ID.\n */\nexport function generateFindingId(): string {\n const time = getTimeProvider();\n const random = getRandomProvider();\n return `finding_${String(time.now())}_${random.randomString(7)}`;\n}\n\n/**\n * Generate a unique round ID.\n */\nexport function generateRoundId(): string {\n const time = getTimeProvider();\n const random = getRandomProvider();\n return `round_${String(time.now())}_${random.randomString(7)}`;\n}\n\n/**\n * Create a new voting round.\n */\nexport function createRound(phase: VotingRoundPhase, roundNumber: number): VotingRound {\n const time = getTimeProvider();\n return {\n id: generateRoundId(),\n phase,\n status: 'in_progress',\n findings: new Map(),\n findingVotes: new Map(),\n finalVotes: new Map(),\n startedAt: time.nowIso(),\n roundNumber,\n };\n}\n\n/**\n * Find the most common element in an array.\n */\nexport function mostCommon<T>(items: T[]): T | undefined {\n if (items.length === 0) return undefined;\n\n const counts = new Map<T, number>();\n items.forEach((item) => {\n counts.set(item, (counts.get(item) ?? 0) + 1);\n });\n\n let maxCount = 0;\n let result: T | undefined;\n counts.forEach((count, item) => {\n if (count > maxCount) {\n maxCount = count;\n result = item;\n }\n });\n\n return result;\n}\n\n/**\n * Calculate agreement score from votes.\n */\nexport function calculateAgreementScore(votes: Vote[]): number {\n if (votes.length < 2) return 1;\n\n const decisions = votes.map((v) => v.decision);\n const mostCommonDecision = mostCommon(decisions);\n const agreementCount = decisions.filter((d) => d === mostCommonDecision).length;\n\n return agreementCount / votes.length;\n}\n\n/**\n * Determine outcome from final votes using unified QuorumValidator.\n * Per ADR-0003, this delegates to the consolidated quorum logic.\n */\nexport function determineOutcome(\n votes: Vote[],\n config: VotingProtocolConfig\n): VotingProtocolResult['outcome'] {\n if (votes.length === 0) return 'no_consensus';\n\n // Convert array to Map for QuorumValidator\n const voteMap = new Map<string, Vote>();\n votes.forEach((vote, index) => {\n voteMap.set(`voter_${String(index)}`, vote);\n });\n\n // Create quorum config from voting protocol config\n const quorumConfig: QuorumValidationConfig = {\n algorithm: 'simple_majority',\n threshold: config.agreementThreshold,\n minVoters: 2, // Minimum for valid consensus\n };\n\n // Use unified QuorumValidator\n const validator = createQuorumValidator();\n const result = validator.validateQuorum({\n votes: voteMap,\n config: quorumConfig,\n });\n\n // Map QuorumValidationResult to VotingProtocolResult outcome\n if (result.status === 'reached') {\n return result.decision === 'approve' ? 'approved' : 'rejected';\n }\n\n // Check for mixed votes (needs revision)\n const approvals = votes.filter((v) => v.decision === 'approve').length;\n const rejections = votes.filter((v) => v.decision === 'reject').length;\n if (approvals > 0 && rejections > 0) return 'needs_revision';\n\n return 'no_consensus';\n}\n\n/**\n * Consolidate findings from deliberation round.\n */\nexport function consolidateFindings(session: VotingSession): ConsolidatedFinding[] {\n const deliberationRound = session.rounds[1];\n if (!deliberationRound) return [];\n\n const consolidated: ConsolidatedFinding[] = [];\n\n deliberationRound.findings.forEach((finding, findingId) => {\n const votes = deliberationRound.findingVotes.get(findingId) ?? [];\n const agreeVotes = votes.filter((v) => v.agree);\n const agreementRatio = votes.length > 0 ? agreeVotes.length / votes.length : 0;\n\n // Only include findings with some agreement\n if (agreementRatio >= 0.5) {\n // Determine final severity (use most common amended severity or original)\n const severityVotes = agreeVotes\n .filter((v) => v.amendedSeverity)\n .map((v) => v.amendedSeverity);\n const finalSeverity =\n severityVotes.length > 0\n ? (mostCommon(severityVotes) ?? finding.severity)\n : finding.severity;\n\n const consolidatedFinding: ConsolidatedFinding = {\n id: findingId,\n category: finding.category,\n severity: finalSeverity,\n description: finding.description,\n supportingAgents: agreeVotes.map((v) => v.agentId),\n agreementRatio,\n originalFindings: [finding],\n };\n if (finding.location !== undefined) {\n consolidatedFinding.location = finding.location;\n }\n if (finding.suggestion !== undefined) {\n consolidatedFinding.suggestion = finding.suggestion;\n }\n consolidated.push(consolidatedFinding);\n }\n });\n\n // Sort by severity and agreement\n return consolidated.sort((a, b) => {\n const severityOrder = { critical: 0, major: 1, minor: 2, suggestion: 3 };\n const sevDiff = severityOrder[a.severity] - severityOrder[b.severity];\n if (sevDiff !== 0) return sevDiff;\n return b.agreementRatio - a.agreementRatio;\n });\n}\n\n/**\n * Build round summaries from session.\n */\nexport function buildRoundSummaries(session: VotingSession): RoundSummary[] {\n const time = getTimeProvider();\n return session.rounds.map((round, index) => {\n const startTime = new Date(round.startedAt).getTime();\n const endTime =\n round.completedAt !== undefined ? new Date(round.completedAt).getTime() : time.now();\n\n let votesCount = 0;\n let agreementScore = 0;\n\n if (round.phase === 'deliberation') {\n // Count finding votes\n round.findingVotes.forEach((votes) => {\n votesCount += votes.length;\n const agreeCount = votes.filter((v) => v.agree).length;\n agreementScore += votes.length > 0 ? agreeCount / votes.length : 0;\n });\n const findingsCount = round.findingVotes.size;\n if (findingsCount > 0) {\n agreementScore /= findingsCount;\n }\n } else if (round.phase === 'consensus') {\n // Count final votes\n votesCount = round.finalVotes.size;\n const votes = Array.from(round.finalVotes.values());\n agreementScore = calculateAgreementScore(votes);\n }\n\n return {\n roundNumber: index + 1,\n phase: round.phase,\n findingsCount: round.findings.size,\n votesCount,\n agreementScore,\n durationMs: endTime - startTime,\n };\n });\n}\n\n// ============================================================================\n// Sycophancy Detection\n// ============================================================================\n\n/**\n * Check for premature consensus pattern.\n */\nexport function checkPrematureConsensus(session: VotingSession): SycophancyIndicator | null {\n const analysisRound = session.rounds[0];\n if (!analysisRound) return null;\n\n const agentFindings = new Map<string, AgentFinding[]>();\n analysisRound.findings.forEach((finding) => {\n const existing = agentFindings.get(finding.agentId) ?? [];\n existing.push(finding);\n agentFindings.set(finding.agentId, existing);\n });\n\n const allConfidences: number[] = [];\n analysisRound.findings.forEach((finding) => {\n allConfidences.push(finding.confidence);\n });\n\n const avgConfidence =\n allConfidences.length > 0\n ? allConfidences.reduce((a, b) => a + b, 0) / allConfidences.length\n : 0;\n\n if (avgConfidence > 0.95 && agentFindings.size >= 2) {\n return {\n type: 'premature_consensus',\n description: 'All agents showing unusually high confidence',\n severity: 'medium',\n agents: Array.from(agentFindings.keys()),\n };\n }\n\n return null;\n}\n\n/**\n * Check for opinion convergence pattern.\n */\nexport function checkOpinionConvergence(session: VotingSession): SycophancyIndicator | null {\n const deliberationRound = session.rounds[1];\n if (!deliberationRound) return null;\n\n let totalVotes = 0;\n let agreeVotes = 0;\n\n deliberationRound.findingVotes.forEach((votes) => {\n totalVotes += votes.length;\n agreeVotes += votes.filter((v) => v.agree).length;\n });\n\n const agreeRatio = totalVotes > 0 ? agreeVotes / totalVotes : 0;\n\n if (agreeRatio > session.config.sycophancyThreshold && totalVotes > 3) {\n const affectedAgents: string[] = [];\n deliberationRound.findingVotes.forEach((votes) => {\n votes.forEach((v) => {\n if (v.agree && !affectedAgents.includes(v.agentId)) {\n affectedAgents.push(v.agentId);\n }\n });\n });\n\n return {\n type: 'opinion_convergence',\n description: `${String(Math.round(agreeRatio * 100))}% agreement rate suggests possible opinion convergence`,\n severity: 'high',\n agents: affectedAgents,\n };\n }\n\n return null;\n}\n\n/**\n * Check for confidence inflation pattern.\n */\nexport function checkConfidenceInflation(session: VotingSession): SycophancyIndicator | null {\n const consensusRound = session.rounds[2];\n if (!consensusRound) return null;\n\n const votes = Array.from(consensusRound.finalVotes.values());\n if (votes.length < 2) return null;\n\n const confidences = votes.map((v) => v.confidence);\n const avgConfidence = confidences.reduce((a, b) => a + b, 0) / confidences.length;\n const allHigh = confidences.every((c) => c > 0.9);\n\n if (allHigh && avgConfidence > 0.95) {\n return {\n type: 'confidence_inflation',\n description: 'All agents reporting very high confidence suggests possible sycophancy',\n severity: 'medium',\n agents: Array.from(consensusRound.finalVotes.keys()),\n };\n }\n\n return null;\n}\n\n/**\n * Run all sycophancy detection checks.\n */\nexport function detectSycophancyPatterns(session: VotingSession): SycophancyReport {\n const indicators: SycophancyIndicator[] = [];\n const affectedAgents: string[] = [];\n\n const prematureConsensus = checkPrematureConsensus(session);\n if (prematureConsensus) {\n indicators.push(prematureConsensus);\n affectedAgents.push(...prematureConsensus.agents);\n }\n\n const opinionConvergence = checkOpinionConvergence(session);\n if (opinionConvergence) {\n indicators.push(opinionConvergence);\n affectedAgents.push(...opinionConvergence.agents);\n }\n\n const confidenceInflation = checkConfidenceInflation(session);\n if (confidenceInflation) {\n indicators.push(confidenceInflation);\n affectedAgents.push(...confidenceInflation.agents);\n }\n\n const detected = indicators.length > 0;\n const confidenceScore = Math.min(1, indicators.length * 0.3);\n const uniqueAffected = [...new Set(affectedAgents)];\n\n return {\n detected,\n confidenceScore,\n indicators,\n affectedAgents: uniqueAffected,\n recommendation: detected\n ? 'Consider requesting independent re-analysis or adding more diverse agents'\n : 'No sycophancy detected',\n };\n}\n","/**\n * Multi-Round Voting Protocol Implementation\n *\n * Implements a structured 3-round voting protocol for multi-agent code review\n * based on research showing 91.7-100% success rates vs 78% single-agent baseline.\n *\n * @module consensus/voting-protocol\n * (Source: Issue #100, arXiv:2512.21352 - Multi-Agent Committees)\n * (Source: arXiv:2509.23055 - Sycophancy Prevention)\n */\n\nimport { createLogger } from '../core/logger.js';\nimport { allOf } from '../utils/verdict-aggregation.js';\nimport { getTimeProvider } from '../core/index.js';\nimport type { ILogger } from '../core/index.js';\nimport type {\n IVotingProtocol,\n VotingSession,\n VotingRound,\n VotingProtocolConfig,\n VotingProtocolResult,\n AgentFinding,\n FindingVote,\n Vote,\n SycophancyReport,\n} from './types.js';\nimport {\n AgentFindingSchema,\n FindingVoteSchema,\n VoteSchema,\n DEFAULT_VOTING_PROTOCOL_CONFIG,\n} from './types.js';\nimport {\n generateSessionId,\n generateFindingId,\n createRound,\n consolidateFindings,\n buildRoundSummaries,\n determineOutcome,\n calculateAgreementScore,\n detectSycophancyPatterns,\n} from './voting-protocol-helpers.js';\n\nconst logger: ILogger = createLogger({ component: 'voting-protocol' });\n\n/**\n * Multi-round voting protocol for code review.\n */\nexport class VotingProtocol implements IVotingProtocol {\n private readonly sessions: Map<string, VotingSession> = new Map();\n private readonly logger: ILogger;\n\n constructor(customLogger?: ILogger) {\n this.logger = customLogger ?? logger;\n }\n\n /**\n * Create a new voting session with a committee.\n */\n createSession(\n topic: string,\n committee: string[],\n config?: Partial<VotingProtocolConfig>\n ): VotingSession {\n const sessionConfig = { ...DEFAULT_VOTING_PROTOCOL_CONFIG, ...config };\n\n if (committee.length < 2) {\n throw new Error('Committee must have at least 2 members');\n }\n\n if (committee.length > sessionConfig.committeeSize) {\n throw new Error(`Committee size exceeds maximum (${String(sessionConfig.committeeSize)})`);\n }\n\n const session: VotingSession = {\n id: generateSessionId(),\n topic,\n committee,\n rounds: [],\n currentRound: 0,\n config: sessionConfig,\n status: 'active',\n createdAt: getTimeProvider().nowIso(),\n };\n\n this.sessions.set(session.id, session);\n this.logger.info('Voting session created', {\n sessionId: session.id,\n topic,\n committeeSize: committee.length,\n });\n\n return session;\n }\n\n /**\n * Start the analysis round (Round 1).\n */\n startAnalysisRound(sessionId: string): Promise<VotingRound> {\n const session = this.getSessionOrThrow(sessionId);\n this.validateSessionActive(session);\n\n if (session.currentRound !== 0) {\n return Promise.reject(new Error('Analysis round can only be started as Round 1'));\n }\n\n const round = createRound('analysis', 1);\n session.rounds.push(round);\n session.currentRound = 1;\n\n this.logger.info('Analysis round started', { sessionId, roundId: round.id });\n return Promise.resolve(round);\n }\n\n /**\n * Submit findings from an agent during analysis.\n */\n submitFindings(sessionId: string, agentId: string, findings: AgentFinding[]): Promise<void> {\n const session = this.getSessionOrThrow(sessionId);\n this.validateSessionActive(session);\n\n const currentRound = this.getCurrentRound(session);\n if (currentRound.phase !== 'analysis') {\n return Promise.reject(new Error('Findings can only be submitted during analysis round'));\n }\n\n if (!session.committee.includes(agentId)) {\n return Promise.reject(new Error(`Agent ${agentId} is not a committee member`));\n }\n\n for (const finding of findings) {\n const validation = AgentFindingSchema.safeParse(finding);\n if (!validation.success) {\n return Promise.reject(new Error(`Invalid finding: ${validation.error.message}`));\n }\n\n const findingId = generateFindingId();\n const timestampedFinding = {\n ...validation.data,\n agentId,\n timestamp: getTimeProvider().nowIso(),\n };\n currentRound.findings.set(findingId, timestampedFinding);\n }\n\n this.logger.debug('Findings submitted', { sessionId, agentId, findingsCount: findings.length });\n return Promise.resolve();\n }\n\n /**\n * Start the deliberation round (Round 2).\n */\n startDeliberationRound(sessionId: string): Promise<VotingRound> {\n const session = this.getSessionOrThrow(sessionId);\n this.validateSessionActive(session);\n\n if (session.currentRound !== 1) {\n return Promise.reject(new Error('Deliberation round can only be started after analysis'));\n }\n\n const analysisRound = session.rounds[0];\n if (analysisRound) {\n analysisRound.status = 'completed';\n analysisRound.completedAt = getTimeProvider().nowIso();\n }\n\n if (session.config.enableAntiSycophancy) {\n const report = this.detectSycophancy(sessionId);\n if (report.detected) {\n this.logger.warn('Sycophancy detected before deliberation', {\n sessionId,\n indicators: report.indicators.length,\n });\n }\n }\n\n const round = createRound('deliberation', 2);\n if (analysisRound) {\n analysisRound.findings.forEach((finding, id) => {\n round.findings.set(id, finding);\n round.findingVotes.set(id, []);\n });\n }\n\n session.rounds.push(round);\n session.currentRound = 2;\n\n this.logger.info('Deliberation round started', {\n sessionId,\n roundId: round.id,\n findingsCount: round.findings.size,\n });\n return Promise.resolve(round);\n }\n\n /**\n * Vote on findings during deliberation.\n */\n voteOnFinding(sessionId: string, vote: FindingVote): Promise<void> {\n const session = this.getSessionOrThrow(sessionId);\n this.validateSessionActive(session);\n\n const currentRound = this.getCurrentRound(session);\n if (currentRound.phase !== 'deliberation') {\n return Promise.reject(new Error('Finding votes can only be submitted during deliberation'));\n }\n\n const validation = FindingVoteSchema.safeParse(vote);\n if (!validation.success) {\n return Promise.reject(new Error(`Invalid vote: ${validation.error.message}`));\n }\n\n if (!session.committee.includes(vote.agentId)) {\n return Promise.reject(new Error(`Agent ${vote.agentId} is not a committee member`));\n }\n\n if (!currentRound.findings.has(vote.findingId)) {\n return Promise.reject(new Error(`Finding ${vote.findingId} not found`));\n }\n\n const existingVotes = currentRound.findingVotes.get(vote.findingId) ?? [];\n const filtered = existingVotes.filter((v) => v.agentId !== vote.agentId);\n filtered.push(validation.data);\n currentRound.findingVotes.set(vote.findingId, filtered);\n\n this.logger.debug('Finding vote recorded', {\n sessionId,\n agentId: vote.agentId,\n findingId: vote.findingId,\n agree: vote.agree,\n });\n return Promise.resolve();\n }\n\n /**\n * Start the consensus round (Round 3).\n */\n startConsensusRound(sessionId: string): Promise<VotingRound> {\n const session = this.getSessionOrThrow(sessionId);\n this.validateSessionActive(session);\n\n if (session.currentRound !== 2) {\n return Promise.reject(new Error('Consensus round can only be started after deliberation'));\n }\n\n const deliberationRound = session.rounds[1];\n if (deliberationRound) {\n deliberationRound.status = 'completed';\n deliberationRound.completedAt = getTimeProvider().nowIso();\n }\n\n const round = createRound('consensus', 3);\n session.rounds.push(round);\n session.currentRound = 3;\n\n this.logger.info('Consensus round started', { sessionId, roundId: round.id });\n return Promise.resolve(round);\n }\n\n /**\n * Submit final vote during consensus.\n */\n submitFinalVote(sessionId: string, agentId: string, vote: Vote): Promise<void> {\n const session = this.getSessionOrThrow(sessionId);\n this.validateSessionActive(session);\n\n const currentRound = this.getCurrentRound(session);\n if (currentRound.phase !== 'consensus') {\n return Promise.reject(new Error('Final votes can only be submitted during consensus'));\n }\n\n const validation = VoteSchema.safeParse(vote);\n if (!validation.success) {\n return Promise.reject(new Error(`Invalid vote: ${validation.error.message}`));\n }\n\n if (!session.committee.includes(agentId)) {\n return Promise.reject(new Error(`Agent ${agentId} is not a committee member`));\n }\n\n currentRound.finalVotes.set(agentId, {\n ...validation.data,\n timestamp: getTimeProvider().nowIso(),\n });\n\n this.logger.debug('Final vote recorded', {\n sessionId,\n agentId,\n decision: vote.decision,\n confidence: vote.confidence,\n });\n return Promise.resolve();\n }\n\n /**\n * Get the final result.\n */\n getResult(sessionId: string): Promise<VotingProtocolResult | null> {\n const session = this.sessions.get(sessionId);\n if (!session) return Promise.resolve(null);\n\n if (session.status === 'completed' && session.finalResult) {\n return Promise.resolve(session.finalResult);\n }\n\n if (session.currentRound < 3) return Promise.resolve(null);\n\n const consensusRound = session.rounds[2];\n if (!consensusRound) return Promise.resolve(null);\n\n // whenEmpty = false: a committee of zero members has cast zero votes, and\n // `[].every()` used to report that as \"everyone voted\" — finalizing the\n // session as `completed` with an outcome derived from no ballots at all.\n // Zero voters is the absence of consensus, not unanimous consensus, so the\n // empty case takes the same path as a partial vote: no result, session stays\n // active, and the record never claims a vote that was never held. (#4581)\n const allVoted = allOf(\n session.committee,\n (agentId) => consensusRound.finalVotes.has(agentId),\n false\n );\n if (!allVoted) return Promise.resolve(null);\n\n const result = this.buildFinalResult(session);\n session.finalResult = result;\n session.status = 'completed';\n session.completedAt = getTimeProvider().nowIso();\n\n consensusRound.status = 'completed';\n consensusRound.completedAt = getTimeProvider().nowIso();\n\n this.logger.info('Voting session completed', {\n sessionId,\n outcome: result.outcome,\n agreementScore: result.agreementScore,\n consolidatedFindings: result.consolidatedFindings.length,\n });\n\n return Promise.resolve(result);\n }\n\n /**\n * Detect sycophancy patterns.\n */\n detectSycophancy(sessionId: string): SycophancyReport {\n const session = this.getSessionOrThrow(sessionId);\n return detectSycophancyPatterns(session);\n }\n\n /**\n * Get the current session state.\n */\n getSession(sessionId: string): VotingSession | undefined {\n return this.sessions.get(sessionId);\n }\n\n private getSessionOrThrow(sessionId: string): VotingSession {\n const session = this.sessions.get(sessionId);\n if (!session) {\n throw new Error(`Session ${sessionId} not found`);\n }\n return session;\n }\n\n private validateSessionActive(session: VotingSession): void {\n if (session.status !== 'active') {\n throw new Error(`Session ${session.id} is ${session.status}`);\n }\n }\n\n private getCurrentRound(session: VotingSession): VotingRound {\n const round = session.rounds[session.currentRound - 1];\n if (!round) {\n throw new Error(`No round ${String(session.currentRound)} found`);\n }\n return round;\n }\n\n private buildFinalResult(session: VotingSession): VotingProtocolResult {\n const startTime = new Date(session.createdAt).getTime();\n const endTime = getTimeProvider().now();\n\n const consolidatedFindingsList = consolidateFindings(session);\n const roundSummaries = buildRoundSummaries(session);\n\n const consensusRound = session.rounds[2];\n const finalVotes = consensusRound ? Array.from(consensusRound.finalVotes.values()) : [];\n const outcome = determineOutcome(finalVotes, session.config);\n const agreementScore = calculateAgreementScore(finalVotes);\n const sycophancyReport = detectSycophancyPatterns(session);\n\n return {\n sessionId: session.id,\n topic: session.topic,\n outcome,\n consolidatedFindings: consolidatedFindingsList,\n roundSummaries,\n agreementScore,\n sycophancyDetected: sycophancyReport.detected,\n totalDurationMs: endTime - startTime,\n participatingAgents: session.committee,\n };\n }\n}\n\n/**\n * Create a voting protocol instance.\n */\nexport function createVotingProtocol(customLogger?: ILogger): VotingProtocol {\n return new VotingProtocol(customLogger);\n}\n","/**\n * Byzantine Detection CollaborationEventBus Integration Helpers\n * (Source: Issue #218, Sprint #228)\n *\n * Provides helper functions for emitting Byzantine fault detection events.\n * Used by CP-WBFT weighted voting to report Byzantine behavior patterns.\n *\n * @module agents/collaboration/byzantine-events\n */\n\nimport type {\n ICollaborationEventBus,\n ByzantineWeightUpdatedEvent,\n ByzantinePatternDetectedEvent,\n ByzantineAgentFlaggedEvent,\n ByzantineCollusionSuspectedEvent,\n} from './event-bus-types.js';\nimport { createEvent } from './event-bus.js';\n\n// =============================================================================\n// Weight Update Events\n// =============================================================================\n\n/** Parameters for emitting byzantine.weight_updated event. */\nexport interface WeightUpdatedParams {\n readonly agentId: string;\n readonly previousWeight: number;\n readonly newWeight: number;\n readonly reason: 'performance_update' | 'flag_penalty' | 'recalibration';\n readonly sessionId?: string | undefined;\n readonly correlationId?: string | undefined;\n}\n\n/** Emits byzantine.weight_updated event when an agent's weight changes. */\nexport function emitWeightUpdated(\n eventBus: ICollaborationEventBus,\n params: WeightUpdatedParams\n): void {\n const event = createEvent<ByzantineWeightUpdatedEvent>(\n 'byzantine.weight_updated',\n {\n agentId: params.agentId,\n previousWeight: params.previousWeight,\n newWeight: params.newWeight,\n reason: params.reason,\n },\n {\n ...(params.sessionId !== undefined && { sessionId: params.sessionId }),\n ...(params.correlationId !== undefined && { correlationId: params.correlationId }),\n }\n );\n eventBus.emit(event);\n}\n\n// =============================================================================\n// Pattern Detection Events\n// =============================================================================\n\n/** Parameters for emitting byzantine.pattern_detected event. */\nexport interface PatternDetectedParams {\n readonly patternType: 'contrarian' | 'collusion';\n readonly agentIds: readonly string[];\n readonly confidence: number;\n readonly details: string;\n readonly sessionId?: string | undefined;\n readonly correlationId?: string | undefined;\n}\n\n/** Emits byzantine.pattern_detected event when Byzantine pattern is detected. */\nexport function emitPatternDetected(\n eventBus: ICollaborationEventBus,\n params: PatternDetectedParams\n): void {\n const event = createEvent<ByzantinePatternDetectedEvent>(\n 'byzantine.pattern_detected',\n {\n patternType: params.patternType,\n agentIds: params.agentIds,\n confidence: params.confidence,\n details: params.details,\n },\n {\n ...(params.sessionId !== undefined && { sessionId: params.sessionId }),\n ...(params.correlationId !== undefined && { correlationId: params.correlationId }),\n }\n );\n eventBus.emit(event);\n}\n\n// =============================================================================\n// Agent Flagged Events\n// =============================================================================\n\n/** Parameters for emitting byzantine.agent_flagged event. */\nexport interface AgentFlaggedParams {\n readonly agentId: string;\n readonly reason: string;\n readonly previousWeight: number;\n readonly canVote: boolean;\n readonly sessionId?: string | undefined;\n readonly correlationId?: string | undefined;\n}\n\n/** Emits byzantine.agent_flagged event when an agent is flagged as Byzantine. */\nexport function emitAgentFlagged(\n eventBus: ICollaborationEventBus,\n params: AgentFlaggedParams\n): void {\n const event = createEvent<ByzantineAgentFlaggedEvent>(\n 'byzantine.agent_flagged',\n {\n agentId: params.agentId,\n reason: params.reason,\n previousWeight: params.previousWeight,\n canVote: params.canVote,\n },\n {\n ...(params.sessionId !== undefined && { sessionId: params.sessionId }),\n ...(params.correlationId !== undefined && { correlationId: params.correlationId }),\n }\n );\n eventBus.emit(event);\n}\n\n// =============================================================================\n// Collusion Suspected Events\n// =============================================================================\n\n/** Parameters for emitting byzantine.collusion_suspected event. */\nexport interface CollusionSuspectedParams {\n readonly groupAgentIds: readonly string[];\n readonly groupSize: number;\n readonly votingBlock: number;\n readonly threshold: number;\n readonly sessionId?: string | undefined;\n readonly correlationId?: string | undefined;\n}\n\n/** Emits byzantine.collusion_suspected event when collusion pattern is suspected. */\nexport function emitCollusionSuspected(\n eventBus: ICollaborationEventBus,\n params: CollusionSuspectedParams\n): void {\n const event = createEvent<ByzantineCollusionSuspectedEvent>(\n 'byzantine.collusion_suspected',\n {\n groupAgentIds: params.groupAgentIds,\n groupSize: params.groupSize,\n votingBlock: params.votingBlock,\n threshold: params.threshold,\n },\n {\n ...(params.sessionId !== undefined && { sessionId: params.sessionId }),\n ...(params.correlationId !== undefined && { correlationId: params.correlationId }),\n }\n );\n eventBus.emit(event);\n}\n","/**\n * nexus-agents/consensus - Weighted Byzantine Voting Helpers\n *\n * Pure helper functions extracted from WeightedVoting class.\n * These functions are stateless and operate on parameters only.\n *\n * @module consensus/weighted-voting-helpers\n * (Source: Issue #103, arXiv:2511.10400 - CP-WBFT)\n */\n\nimport { getTimeProvider } from '../core/index.js';\nimport { clamp01 } from '../utils/math-utils.js';\nimport type { WeightedAgentRecord, WeightedConsensusResult, Vote } from './types.js';\nimport type { ICollaborationEventBus } from '../core/event-bus.js';\n\n/**\n * Mutable agent record for internal tracking.\n * Used internally by WeightedVoting class.\n */\nexport interface MutableAgentRecord {\n agentId: string;\n totalTasks: number;\n successfulTasks: number;\n failedTasks: number;\n partialTasks: number;\n successRate: number;\n weight: number;\n trustScore: number;\n byzantineFlags: number;\n byzantineReasons: string[];\n lastActive: Date;\n createdAt: Date;\n}\n\n/** Options for WeightedVoting constructor. */\nexport interface WeightedVotingOptions {\n /** Configuration for voting thresholds and weights. */\n config?: Partial<import('./types.js').WeightedVotingConfig>;\n /** Optional event bus for Byzantine detection events (Issue #218). */\n eventBus?: ICollaborationEventBus;\n /** Whether to emit Byzantine detection events (default: true if eventBus provided). */\n emitEvents?: boolean;\n}\n\n/**\n * Check if a vote is a low-confidence contrarian vote.\n * Used for Byzantine pattern detection.\n */\nexport function isLowConfidenceContrarian(vote: Vote, majorityApprove: boolean): boolean {\n const isContrarian = majorityApprove ? vote.decision === 'reject' : vote.decision === 'approve';\n return isContrarian && vote.confidence < 0.3;\n}\n\n/**\n * Compute the majority vote direction based on weighted votes.\n * Returns true if majority approves, false if majority rejects.\n */\nexport function computeMajorityDirection(\n voteArray: ReadonlyArray<readonly [string, Vote]>,\n weights: ReadonlyMap<string, number>\n): boolean {\n let totalApprove = 0;\n let totalReject = 0;\n for (const [agentId, vote] of voteArray) {\n const w = weights.get(agentId) ?? 0;\n if (vote.decision === 'approve') totalApprove += w;\n if (vote.decision === 'reject') totalReject += w;\n }\n return totalApprove > totalReject;\n}\n\n/**\n * Determine consensus decision based on vote tallies.\n */\nexport function determineDecision(\n approval: number,\n rejection: number,\n total: number,\n quorumReached: boolean,\n quorumThreshold: number\n): WeightedConsensusResult['decision'] {\n if (!quorumReached || total === 0) return 'no_consensus';\n const approvalRatio = approval / total;\n const rejectionRatio = rejection / total;\n if (approvalRatio > rejectionRatio && approvalRatio >= quorumThreshold) return 'approve';\n if (rejectionRatio > approvalRatio && rejectionRatio >= quorumThreshold) return 'reject';\n return 'no_consensus';\n}\n\n/**\n * Update derived metrics (success rate, trust score) on a mutable record.\n */\nexport function updateDerivedMetrics(record: MutableAgentRecord): void {\n // Update success rate\n if (record.totalTasks > 0) {\n const weightedSuccess = record.successfulTasks + record.partialTasks * 0.5;\n record.successRate = weightedSuccess / record.totalTasks;\n }\n\n // Update trust score based on weight and Byzantine flags\n const byzantinePenalty = Math.pow(0.7, record.byzantineFlags);\n record.trustScore = Math.min(1, record.weight * byzantinePenalty);\n}\n\n/**\n * Convert a mutable internal record to an immutable public record.\n */\nexport function toImmutableRecord(record: MutableAgentRecord): WeightedAgentRecord {\n return {\n agentId: record.agentId,\n totalTasks: record.totalTasks,\n successfulTasks: record.successfulTasks,\n failedTasks: record.failedTasks,\n partialTasks: record.partialTasks,\n successRate: record.successRate,\n weight: record.weight,\n trustScore: record.trustScore,\n byzantineFlags: record.byzantineFlags,\n lastActive: record.lastActive,\n createdAt: record.createdAt,\n };\n}\n\n/**\n * Create a vote signature for collusion detection.\n * Combines decision and confidence into a unique key.\n */\nexport function createVoteSignature(vote: Vote): string {\n return `${vote.decision}:${vote.confidence.toFixed(2)}`;\n}\n\n/**\n * Group votes by their signature for collusion pattern detection.\n */\nexport function groupVotesBySignature(\n voteArray: ReadonlyArray<readonly [string, Vote]>\n): Map<string, string[]> {\n const signatures = new Map<string, string[]>();\n for (const [agentId, vote] of voteArray) {\n const sig = createVoteSignature(vote);\n const agents = signatures.get(sig) ?? [];\n agents.push(agentId);\n signatures.set(sig, agents);\n }\n return signatures;\n}\n\n/**\n * Create a new mutable agent record with initial values.\n */\nexport function createAgentRecord(agentId: string, initialWeight: number): MutableAgentRecord {\n const now = new Date(getTimeProvider().now());\n return {\n agentId,\n totalTasks: 0,\n successfulTasks: 0,\n failedTasks: 0,\n partialTasks: 0,\n successRate: 0,\n weight: initialWeight,\n trustScore: initialWeight,\n byzantineFlags: 0,\n byzantineReasons: [],\n lastActive: now,\n createdAt: now,\n };\n}\n\n/**\n * Compute global success statistics from all agent records.\n */\nexport function computeGlobalStats(records: Iterable<MutableAgentRecord>): {\n globalSuccessRate: number;\n totalTasks: number;\n} {\n let totalSuccess = 0;\n let totalTasks = 0;\n\n for (const record of records) {\n totalSuccess += record.successfulTasks;\n totalTasks += record.totalTasks;\n }\n\n const globalSuccessRate = totalTasks > 0 ? totalSuccess / totalTasks : 0.5;\n return { globalSuccessRate, totalTasks };\n}\n\n/**\n * Calculate calibrated weight based on relative performance.\n */\nexport function calculateCalibratedWeight(\n record: MutableAgentRecord,\n globalSuccessRate: number,\n initialWeight: number\n): number {\n const relativePerformance = record.successRate / Math.max(0.01, globalSuccessRate);\n const calibratedWeight = clamp01(initialWeight * relativePerformance);\n // Smooth transition (50% old weight, 50% calibrated)\n return (record.weight + calibratedWeight) / 2;\n}\n\n/**\n * Apply weight change based on task outcome.\n */\nexport function applyOutcomeWeight(\n currentWeight: number,\n outcome: import('./types.js').TaskOutcomeStatus,\n decayFactor: number,\n recoveryFactor: number\n): number {\n switch (outcome) {\n case 'success':\n return Math.min(1, currentWeight * recoveryFactor);\n case 'failure':\n return Math.max(0, currentWeight * decayFactor);\n case 'partial':\n return Math.max(0, currentWeight * ((decayFactor + 1) / 2));\n case 'unknown':\n return currentWeight;\n }\n}\n","/**\n * nexus-agents/consensus - Weighted Byzantine Voting Implementation\n *\n * Implements CP-WBFT (arXiv:2511.10400) for weighted Byzantine fault-tolerant voting.\n * Agent votes are weighted by historical reliability with automatic trust calibration.\n *\n * @module consensus/weighted-voting\n * (Source: Issue #103, arXiv:2511.10400 - CP-WBFT)\n */\n\nimport { createLogger } from '../core/logger.js';\nimport { getTimeProvider } from '../core/index.js';\nimport type {\n IWeightedVoting,\n WeightedAgentRecord,\n WeightedConsensusResult,\n WeightedVotingConfig,\n TaskOutcomeStatus,\n Vote,\n} from './types.js';\nimport { DEFAULT_WEIGHTED_VOTING_CONFIG } from './types.js';\nimport type { ICollaborationEventBus } from '../core/event-bus.js';\nimport {\n emitWeightUpdated,\n emitPatternDetected,\n emitAgentFlagged,\n emitCollusionSuspected,\n} from '../agents/collaboration/byzantine-events.js';\nimport {\n type MutableAgentRecord,\n type WeightedVotingOptions,\n isLowConfidenceContrarian,\n computeMajorityDirection,\n determineDecision,\n updateDerivedMetrics,\n toImmutableRecord,\n groupVotesBySignature,\n createAgentRecord,\n computeGlobalStats,\n calculateCalibratedWeight,\n applyOutcomeWeight,\n} from './weighted-voting-helpers.js';\n\nexport type { WeightedVotingOptions } from './weighted-voting-helpers.js';\n\nconst logger = createLogger({ component: 'weighted-voting' });\n\n/**\n * Weighted Byzantine voting implementation.\n * Implements CP-WBFT pattern for fault-tolerant multi-agent consensus.\n */\nexport class WeightedVoting implements IWeightedVoting {\n private readonly records: Map<string, MutableAgentRecord> = new Map();\n private readonly config: WeightedVotingConfig;\n private readonly eventBus: ICollaborationEventBus | undefined;\n private readonly emitEvents: boolean;\n\n constructor(options: WeightedVotingOptions = {}) {\n this.config = { ...DEFAULT_WEIGHTED_VOTING_CONFIG, ...options.config };\n this.eventBus = options.eventBus ?? undefined;\n this.emitEvents = options.emitEvents ?? options.eventBus !== undefined;\n logger.info('WeightedVoting initialized', {\n config: this.config,\n eventsEnabled: this.emitEvents,\n });\n }\n\n calculateWeight(agentId: string): number {\n const record = this.records.get(agentId);\n if (record === undefined) return 0;\n return record.weight;\n }\n\n updatePerformance(agentId: string, outcome: TaskOutcomeStatus): void {\n let record = this.records.get(agentId);\n if (record === undefined) {\n this.registerAgent(agentId);\n record = this.records.get(agentId);\n if (record === undefined) return;\n }\n\n const previousWeight = record.weight;\n record.totalTasks += 1;\n record.lastActive = new Date(getTimeProvider().now());\n\n // Update task counts\n if (outcome === 'success') record.successfulTasks += 1;\n else if (outcome === 'failure') record.failedTasks += 1;\n else if (outcome === 'partial') record.partialTasks += 1;\n\n // Apply weight change\n record.weight = applyOutcomeWeight(\n record.weight,\n outcome,\n this.config.weightDecayFactor,\n this.config.weightRecoveryFactor\n );\n updateDerivedMetrics(record);\n this.emitWeightChange(agentId, previousWeight, record.weight, 'performance_update');\n\n logger.debug('Performance updated', {\n agentId,\n outcome,\n newWeight: record.weight,\n successRate: record.successRate,\n });\n }\n\n weightedConsensus(votes: ReadonlyMap<string, Vote>): WeightedConsensusResult {\n const { approval, rejection, total, agents, breakdown } = this.countVotes(votes);\n const byzantineDetected = this.detectByzantinePatterns(votes, breakdown);\n const quorumReached = total >= this.config.quorumThreshold;\n const decision = determineDecision(\n approval,\n rejection,\n total,\n quorumReached,\n this.config.quorumThreshold\n );\n\n const result: WeightedConsensusResult = {\n decision,\n weightedApproval: approval,\n weightedRejection: rejection,\n totalWeight: total,\n quorumReached,\n byzantineDetected,\n participatingAgents: agents,\n weightBreakdown: breakdown,\n };\n\n this.logConsensusResult(result);\n return result;\n }\n\n registerAgent(agentId: string): void {\n if (this.records.has(agentId)) {\n logger.debug('Agent already registered', { agentId });\n return;\n }\n const record = createAgentRecord(agentId, this.config.initialWeight);\n this.records.set(agentId, record);\n logger.info('Agent registered', { agentId, initialWeight: this.config.initialWeight });\n }\n\n getAgentRecord(agentId: string): WeightedAgentRecord | undefined {\n const record = this.records.get(agentId);\n if (record === undefined) return undefined;\n return toImmutableRecord(record);\n }\n\n flagByzantine(agentId: string, reason: string): void {\n const record = this.records.get(agentId);\n if (record === undefined) {\n logger.warn('Cannot flag unregistered agent', { agentId });\n return;\n }\n\n const previousWeight = record.weight;\n record.byzantineFlags += 1;\n record.byzantineReasons.push(reason);\n record.weight = Math.max(0, record.weight * 0.5);\n updateDerivedMetrics(record);\n\n const canStillVote = this.canVote(agentId);\n this.emitAgentFlaggedEvent(agentId, reason, previousWeight, canStillVote);\n this.emitWeightChange(agentId, previousWeight, record.weight, 'flag_penalty');\n\n logger.warn('Agent flagged for Byzantine behavior', {\n agentId,\n reason,\n totalFlags: record.byzantineFlags,\n newWeight: record.weight,\n });\n\n if (record.byzantineFlags >= this.config.byzantineFlagThreshold) {\n this.excludeAgent(record);\n }\n }\n\n getAllRecords(): readonly WeightedAgentRecord[] {\n return Array.from(this.records.values()).map((r) => toImmutableRecord(r));\n }\n\n canVote(agentId: string): boolean {\n const record = this.records.get(agentId);\n if (record === undefined) return false;\n return record.weight >= this.config.minWeight && record.trustScore >= this.config.minTrustScore;\n }\n\n recalibrateWeights(): void {\n const { globalSuccessRate, totalTasks } = computeGlobalStats(this.records.values());\n if (totalTasks === 0) return;\n\n for (const record of this.records.values()) {\n if (record.totalTasks < 3) continue;\n const previousWeight = record.weight;\n record.weight = calculateCalibratedWeight(\n record,\n globalSuccessRate,\n this.config.initialWeight\n );\n updateDerivedMetrics(record);\n this.emitWeightChange(record.agentId, previousWeight, record.weight, 'recalibration');\n }\n\n logger.info('Weights recalibrated', {\n agentCount: this.records.size,\n globalSuccessRate: globalSuccessRate.toFixed(3),\n });\n }\n\n // Private helpers\n\n private countVotes(votes: ReadonlyMap<string, Vote>): {\n approval: number;\n rejection: number;\n total: number;\n agents: string[];\n breakdown: Map<string, number>;\n } {\n let approval = 0;\n let rejection = 0;\n let total = 0;\n const agents: string[] = [];\n const breakdown = new Map<string, number>();\n\n for (const [agentId, vote] of votes) {\n if (!this.canVote(agentId)) {\n logger.warn('Agent cannot vote', { agentId, reason: 'insufficient weight or trust' });\n continue;\n }\n const weight = this.calculateWeight(agentId);\n breakdown.set(agentId, weight);\n agents.push(agentId);\n total += weight;\n const effectiveWeight = weight * vote.confidence;\n if (vote.decision === 'approve') approval += effectiveWeight;\n else if (vote.decision === 'reject') rejection += effectiveWeight;\n }\n return { approval, rejection, total, agents, breakdown };\n }\n\n private logConsensusResult(result: WeightedConsensusResult): void {\n logger.info('Weighted consensus calculated', {\n decision: result.decision,\n approval: result.weightedApproval.toFixed(3),\n rejection: result.weightedRejection.toFixed(3),\n totalWeight: result.totalWeight.toFixed(3),\n quorumReached: result.quorumReached,\n byzantineDetected: result.byzantineDetected,\n });\n }\n\n private emitWeightChange(\n agentId: string,\n prev: number,\n next: number,\n reason: 'performance_update' | 'flag_penalty' | 'recalibration'\n ): void {\n if (this.emitEvents && this.eventBus !== undefined && prev !== next) {\n emitWeightUpdated(this.eventBus, { agentId, previousWeight: prev, newWeight: next, reason });\n }\n }\n\n private emitAgentFlaggedEvent(\n agentId: string,\n reason: string,\n previousWeight: number,\n canVote: boolean\n ): void {\n if (this.emitEvents && this.eventBus !== undefined) {\n emitAgentFlagged(this.eventBus, { agentId, reason, previousWeight, canVote });\n }\n }\n\n private excludeAgent(record: MutableAgentRecord): void {\n const weightBefore = record.weight;\n record.trustScore = 0;\n record.weight = 0;\n this.emitWeightChange(record.agentId, weightBefore, 0, 'flag_penalty');\n logger.warn('Agent excluded from voting due to Byzantine behavior', {\n agentId: record.agentId,\n flags: record.byzantineFlags,\n });\n }\n\n private detectByzantinePatterns(\n votes: ReadonlyMap<string, Vote>,\n weights: Map<string, number>\n ): boolean {\n const voteArray = Array.from(votes.entries());\n if (voteArray.length < 3) return false;\n const majorityApprove = computeMajorityDirection(voteArray, weights);\n if (this.detectContrarianByzantine(voteArray, majorityApprove)) return true;\n return this.detectCollusionPattern(voteArray);\n }\n\n private detectContrarianByzantine(\n voteArray: Array<[string, Vote]>,\n majorityApprove: boolean\n ): boolean {\n const contrarianAgents: string[] = [];\n for (const [agentId, vote] of voteArray) {\n if (!isLowConfidenceContrarian(vote, majorityApprove)) continue;\n const record = this.records.get(agentId);\n if (record !== undefined && record.byzantineFlags >= 2) {\n contrarianAgents.push(agentId);\n }\n }\n if (contrarianAgents.length > 0) {\n this.emitContrarianPattern(contrarianAgents);\n return true;\n }\n return false;\n }\n\n private emitContrarianPattern(agents: string[]): void {\n if (this.emitEvents && this.eventBus !== undefined) {\n emitPatternDetected(this.eventBus, {\n patternType: 'contrarian',\n agentIds: agents,\n confidence: 0.8,\n details: `${String(agents.length)} agent(s) with Byzantine flags voting contrary to majority with low confidence`,\n });\n }\n }\n\n private detectCollusionPattern(voteArray: Array<[string, Vote]>): boolean {\n const voteSignatures = groupVotesBySignature(voteArray);\n const threshold = voteArray.length * 0.6;\n for (const [signature, agents] of voteSignatures.entries()) {\n if (agents.length >= 3 && agents.length > threshold) {\n this.emitCollusionEvents(agents, signature, voteArray.length);\n return true;\n }\n }\n return false;\n }\n\n private emitCollusionEvents(agents: string[], signature: string, totalVotes: number): void {\n if (this.emitEvents && this.eventBus !== undefined) {\n emitPatternDetected(this.eventBus, {\n patternType: 'collusion',\n agentIds: agents,\n confidence: Math.min(0.95, agents.length / totalVotes),\n details: `${String(agents.length)} agents voting identically: ${signature}`,\n });\n emitCollusionSuspected(this.eventBus, {\n groupAgentIds: agents,\n groupSize: agents.length,\n votingBlock: agents.length / totalVotes,\n threshold: 0.6,\n });\n }\n }\n}\n\n/** Create a weighted voting instance. */\nexport function createWeightedVoting(options?: WeightedVotingOptions): IWeightedVoting {\n return new WeightedVoting(options);\n}\n","/**\n * How independent a subset of agents is, and how much of it was measured.\n *\n * Its own module because the score and its coverage are one fact: the score\n * averages only the pairs present in the correlation matrix, so without the\n * coverage a subset whose pairs were MEASURED at 0 is indistinguishable from\n * one whose pairs were NEVER OBSERVED — and 0 earns the maximum posterior\n * weight in `aggregateSubsets`.\n *\n * @module consensus/subset-independence\n */\nimport type { CorrelationMatrix } from './higher-order-types.js';\nimport { createAgentPairKey } from './higher-order-types.js';\n\n/**\n * The independence score AND how much of the subset it was measured over.\n *\n * An unobserved pair counts as MAXIMALLY correlated (#5813, panel option B).\n * Before that it was dropped from the average, so a subset whose pairs were\n * MEASURED at 0 and one whose pairs were NEVER OBSERVED both scored 0 — and 0\n * earns the maximum posterior weight in `aggregateSubsets` (`size * (1 -\n * score)`). Absent evidence was credited as evidence of independence.\n *\n * The panel asked which error to optimise against and answered unanimously\n * among its approvers: over-weighting a secretly correlated bloc, not\n * under-weighting a genuinely independent voice. The first fabricates\n * independent evidence and cannot be recovered from; the second shrinks\n * monotonically as pairs are observed.\n *\n * `total` is C(n,2), so a singleton reports `{ observed: 0, total: 0 }`: no pair\n * exists to observe. It has no peer to correlate with, so there is nothing to\n * discount and it keeps full weight — an unmeasurABLE subset is not an\n * unmeasurED one. That falls out of the formula rather than needing a guard,\n * because zero total pairs means zero missing pairs to charge for.\n *\n * Equivalence worth knowing before anyone \"simplifies\" this: charging 1.0 per\n * missing pair is ALGEBRAICALLY IDENTICAL to scaling the weight by coverage,\n * `(observed/total) * (1 - score)` — the panel's options A and B were the same\n * formula. This spelling is the one that answers the singleton without a\n * 0/0 guard. Verified numerically to 8.9e-16 over 5000 random subsets.\n */\nexport function computeSubsetIndependence(\n subset: readonly string[],\n correlationMatrix: CorrelationMatrix\n): { score: number; observedPairs: number; totalPairs: number } {\n const totalPairs = (subset.length * (subset.length - 1)) / 2;\n if (subset.length < 2) return { score: 0, observedPairs: 0, totalPairs };\n\n let observedCorrelation = 0;\n let pairs = 0;\n\n for (let i = 0; i < subset.length; i++) {\n for (let j = i + 1; j < subset.length; j++) {\n const agentA = subset[i];\n const agentB = subset[j];\n if (agentA !== undefined && agentB !== undefined) {\n const pairKey = createAgentPairKey(agentA, agentB);\n const correlation = correlationMatrix.get(pairKey);\n if (correlation !== undefined) {\n observedCorrelation += Math.abs(correlation);\n pairs++;\n }\n }\n }\n }\n\n // Every unobserved pair contributes 1.0 — maximal correlation — so the\n // denominator is the pairs that EXIST, not the pairs that were seen. A\n // fully unobserved multi-agent subset scores 1 and earns weight 0: it\n // contributes nothing rather than everything.\n const unobservedPairs = totalPairs - pairs;\n return {\n score: (observedCorrelation + unobservedPairs) / totalPairs,\n observedPairs: pairs,\n totalPairs,\n };\n}\n","/**\n * nexus-agents/consensus - Correlation Helpers\n *\n * Helper functions for correlation tracking and independent subset partitioning.\n * Extracted from correlation-tracker.ts to maintain file size limits.\n *\n * @module consensus/correlation-helpers\n * (Source: Issue #339)\n */\n\nimport type {\n CorrelationMatrix,\n CorrelationCoefficient,\n IndependentSubset,\n VotingObservation,\n HigherOrderVotingConfig,\n AgentPairKey,\n} from './higher-order-types.js';\nimport { createAgentPairKey } from './higher-order-types.js';\nimport { computeSubsetIndependence } from './subset-independence.js';\n\n// ============================================================================\n// Pairwise History Types\n// ============================================================================\n\n/**\n * Internal mutable representation of pairwise history.\n */\nexport interface MutablePairwiseHistory {\n pairKey: AgentPairKey;\n jointObservations: number;\n agreements: number;\n disagreements: number;\n correlation: CorrelationCoefficient;\n lastUpdated: Date;\n}\n\n// ============================================================================\n// Vote Agreement\n// ============================================================================\n\n/**\n * Check if two observations are comparable (neither is an abstain).\n * Abstain votes should be excluded from correlation tracking.\n *\n * @param obsA - First observation\n * @param obsB - Second observation\n * @returns True if both observations have non-abstain decisions\n */\nexport function isComparable(obsA: VotingObservation, obsB: VotingObservation): boolean {\n return obsA.decision !== 'abstain' && obsB.decision !== 'abstain';\n}\n\n/**\n * Check if two votes agree.\n * Only call this after verifying isComparable() returns true.\n * Abstains are treated as neutral - neither agree nor disagree.\n *\n * @param obsA - First observation\n * @param obsB - Second observation\n * @returns True if votes agree, null if either is an abstain (neutral)\n */\nexport function votesAgree(obsA: VotingObservation, obsB: VotingObservation): boolean | null {\n if (obsA.decision === 'abstain' || obsB.decision === 'abstain') {\n return null; // Neutral — skip this pair (Issue #763)\n }\n return obsA.decision === obsB.decision;\n}\n\n/**\n * Check if a decision aligned with the outcome.\n *\n * @param decision - The voting decision\n * @param outcome - The final outcome\n * @returns True if decision aligned with outcome\n */\nexport function didAlignWithOutcome(decision: string, outcome: 'approved' | 'rejected'): boolean {\n if (decision === 'abstain') return true;\n return (\n (decision === 'approve' && outcome === 'approved') ||\n (decision === 'reject' && outcome === 'rejected')\n );\n}\n\n// ============================================================================\n// Correlation Computation\n// ============================================================================\n\n/**\n * Compute correlation coefficient from pairwise history.\n *\n * Simple correlation: (agreements - disagreements) / total\n * Range: -1 (always disagree) to +1 (always agree)\n *\n * @param history - Pairwise history\n * @returns Correlation coefficient\n */\nexport function computeCorrelationCoefficient(\n history: MutablePairwiseHistory\n): CorrelationCoefficient {\n const n = history.jointObservations;\n if (n === 0) return 0;\n\n // Map agreement/disagreement rates to [-1, 1] correlation\n // 0.5 agreement rate = 0 correlation (random)\n // 1.0 agreement rate = +1 correlation (perfect agreement)\n // 0.0 agreement rate = -1 correlation (perfect disagreement)\n const agreementRate = history.agreements / n;\n const disagreementRate = history.disagreements / n;\n\n return agreementRate - disagreementRate;\n}\n\n// ============================================================================\n// Independent Subset Partitioning\n// ============================================================================\n\n/**\n * Check if an agent is independent from all members of a subset.\n *\n * @param agent - Agent to check\n * @param subset - Existing subset members\n * @param correlationMatrix - Correlation matrix\n * @param independenceThreshold - Maximum correlation for independence\n * @returns True if agent is independent from subset\n */\nexport function isIndependentFromSubset(\n agent: string,\n subset: readonly string[],\n correlationMatrix: CorrelationMatrix,\n independenceThreshold: number\n): boolean {\n for (const member of subset) {\n const pairKey = createAgentPairKey(agent, member);\n const correlation = correlationMatrix.get(pairKey);\n\n // If we don't have data, assume independent\n if (correlation === undefined) continue;\n\n // If correlation exceeds threshold, not independent\n if (Math.abs(correlation) > independenceThreshold) {\n return false;\n }\n }\n return true;\n}\n\n/**\n * Compute the minimum observation count for pairs within a subset.\n *\n * @param subset - Agent IDs in the subset\n * @param pairwiseHistory - Map of pairwise histories\n * @returns Minimum observation count (0 if no history)\n */\nexport function computeSubsetObservationCount(\n subset: readonly string[],\n pairwiseHistory: ReadonlyMap<AgentPairKey, MutablePairwiseHistory>\n): number {\n let minObservations = Infinity;\n\n for (let i = 0; i < subset.length; i++) {\n for (let j = i + 1; j < subset.length; j++) {\n const agentA = subset[i];\n const agentB = subset[j];\n if (agentA !== undefined && agentB !== undefined) {\n const pairKey = createAgentPairKey(agentA, agentB);\n const history = pairwiseHistory.get(pairKey);\n if (history !== undefined) {\n minObservations = Math.min(minObservations, history.jointObservations);\n } else {\n minObservations = 0;\n }\n }\n }\n }\n\n return minObservations === Infinity ? 0 : minObservations;\n}\n\n/**\n * Partition agents into independent groups using greedy clustering.\n *\n * @param agents - List of agent IDs\n * @param correlationMatrix - Correlation matrix\n * @param pairwiseHistory - Map of pairwise histories\n * @param config - Higher-order voting configuration\n * @returns Array of independent subsets\n */\nexport function partitionIntoIndependentGroups(\n agents: readonly string[],\n correlationMatrix: CorrelationMatrix,\n pairwiseHistory: ReadonlyMap<AgentPairKey, MutablePairwiseHistory>,\n config: HigherOrderVotingConfig\n): IndependentSubset[] {\n if (agents.length === 0) return [];\n\n const subsets: IndependentSubset[] = [];\n const assigned = new Set<string>();\n let subsetId = 0;\n\n for (const agent of agents) {\n if (assigned.has(agent)) continue;\n\n const subset: string[] = [agent];\n assigned.add(agent);\n\n // Try to add other unassigned agents if they're independent\n for (const other of agents) {\n if (assigned.has(other)) continue;\n if (isIndependentFromSubset(other, subset, correlationMatrix, config.independenceThreshold)) {\n subset.push(other);\n assigned.add(other);\n }\n }\n\n const independence = computeSubsetIndependence(subset, correlationMatrix);\n const observationCount = computeSubsetObservationCount(subset, pairwiseHistory);\n\n subsets.push({\n id: `subset-${String(subsetId++)}`,\n agentIds: subset,\n independenceScore: independence.score,\n pairCoverage: { observed: independence.observedPairs, total: independence.totalPairs },\n observationCount,\n });\n }\n\n return subsets;\n}\n","/**\n * Model-keyed storage for pairwise correlation aggregates.\n * Extracted because adding partition lifecycle logic to correlation-tracker.ts\n * would exceed the repository's 400-line source-file limit.\n */\n\nimport type { ILogger } from '../core/logger.js';\nimport type { AgentPairKey } from './higher-order-types.js';\nimport { parseAgentPairKey } from './higher-order-types.js';\nimport {\n computeCorrelationCoefficient,\n type MutablePairwiseHistory,\n} from './correlation-helpers.js';\n\ntype ModelTuple = [string | null, string | null];\n\nfunction encodeModels(models: ModelTuple): string {\n return JSON.stringify(models);\n}\n\nfunction isModelTuple(value: unknown): value is ModelTuple {\n if (!Array.isArray(value) || value.length !== 2) return false;\n const values = value as unknown[];\n const first = values[0];\n const second = values[1];\n return (\n (first === null || typeof first === 'string') && (second === null || typeof second === 'string')\n );\n}\n\nfunction decodeModels(key: string): ModelTuple {\n const parsed = JSON.parse(key) as unknown;\n if (!isModelTuple(parsed)) throw new Error(`Invalid correlation model partition key: ${key}`);\n return parsed;\n}\n\nfunction mergeHistory(\n target: MutablePairwiseHistory,\n source: MutablePairwiseHistory\n): MutablePairwiseHistory {\n target.jointObservations += source.jointObservations;\n target.agreements += source.agreements;\n target.disagreements += source.disagreements;\n target.correlation = computeCorrelationCoefficient(target);\n if (source.lastUpdated > target.lastUpdated) target.lastUpdated = source.lastUpdated;\n return target;\n}\n\n/** Retains every model partition while projecting only the currently pinned one. */\nexport class CorrelationModelPartitions {\n private readonly histories = new Map<AgentPairKey, Map<string, MutablePairwiseHistory>>();\n private readonly currentModels = new Map<string, string>();\n\n constructor(\n private readonly maxTrackedPairs: number,\n private readonly logger: ILogger\n ) {}\n\n setCurrentPins(modelPins: ReadonlyMap<string, string>): void {\n for (const [role, newModel] of modelPins) this.setCurrentPin(role, newModel);\n }\n\n getActiveHistory(): Map<AgentPairKey, MutablePairwiseHistory> {\n const active = new Map<AgentPairKey, MutablePairwiseHistory>();\n for (const [pairKey, partitions] of this.histories) {\n const history = partitions.get(this.activePartitionKey(pairKey));\n if (history !== undefined) active.set(pairKey, history);\n }\n return active;\n }\n\n getOrCreate(pairKey: AgentPairKey, create: () => MutablePairwiseHistory): MutablePairwiseHistory {\n let partitions = this.histories.get(pairKey);\n if (partitions === undefined) {\n partitions = new Map();\n this.histories.set(pairKey, partitions);\n }\n const modelKey = this.activePartitionKey(pairKey);\n let history = partitions.get(modelKey);\n if (history === undefined) {\n history = create();\n partitions.set(modelKey, history);\n this.evictOldestIfNeeded();\n }\n return history;\n }\n\n clear(): void {\n this.histories.clear();\n this.currentModels.clear();\n }\n\n private setCurrentPin(role: string, newModel: string): void {\n const previousModel = this.currentModels.get(role);\n if (previousModel === undefined) {\n this.adoptUnkeyedHistory(role, newModel);\n this.currentModels.set(role, newModel);\n return;\n }\n if (previousModel === newModel) return;\n\n const partitionLeftSize = this.partitionSize(role);\n this.currentModels.set(role, newModel);\n const partitionEnteredSize = this.partitionSize(role);\n this.logger.info('Correlation model partition switched', {\n role,\n previousModel,\n newModel,\n partitionLeftSize,\n partitionEnteredSize,\n });\n }\n\n private activePartitionKey(pairKey: AgentPairKey): string {\n const [agentA, agentB] = parseAgentPairKey(pairKey);\n return encodeModels([\n this.currentModels.get(agentA) ?? null,\n this.currentModels.get(agentB) ?? null,\n ]);\n }\n\n private partitionSize(role: string): number {\n let size = 0;\n for (const [pairKey, partitions] of this.histories) {\n const [agentA, agentB] = parseAgentPairKey(pairKey);\n if (agentA !== role && agentB !== role) continue;\n size += partitions.get(this.activePartitionKey(pairKey))?.jointObservations ?? 0;\n }\n return size;\n }\n\n private adoptUnkeyedHistory(role: string, newModel: string): void {\n for (const [pairKey, partitions] of this.histories) {\n const [agentA, agentB] = parseAgentPairKey(pairKey);\n const index = agentA === role ? 0 : agentB === role ? 1 : undefined;\n if (index === undefined) continue;\n this.rekeyUnkeyedPartitions(partitions, index, newModel);\n }\n }\n\n private rekeyUnkeyedPartitions(\n partitions: Map<string, MutablePairwiseHistory>,\n index: 0 | 1,\n newModel: string\n ): void {\n for (const [oldKey, history] of [...partitions]) {\n const models = decodeModels(oldKey);\n if (models[index] !== null) continue;\n models[index] = newModel;\n const newKey = encodeModels(models);\n partitions.delete(oldKey);\n const existing = partitions.get(newKey);\n partitions.set(newKey, existing === undefined ? history : mergeHistory(existing, history));\n }\n }\n\n private evictOldestIfNeeded(): void {\n while (this.historyCount() > this.maxTrackedPairs) {\n const oldest = this.findOldest();\n if (oldest === undefined) return;\n const partitions = this.histories.get(oldest.pairKey);\n partitions?.delete(oldest.modelKey);\n if (partitions?.size === 0) this.histories.delete(oldest.pairKey);\n this.logger.debug('Evicted oldest pairwise history entry', {\n evictedKey: oldest.pairKey,\n reason: 'maxTrackedPairs',\n remainingPairs: this.historyCount(),\n });\n }\n }\n\n private historyCount(): number {\n let count = 0;\n for (const partitions of this.histories.values()) count += partitions.size;\n return count;\n }\n\n private findOldest(): { pairKey: AgentPairKey; modelKey: string } | undefined {\n let oldest: { pairKey: AgentPairKey; modelKey: string } | undefined;\n let oldestTime = Infinity;\n for (const [pairKey, partitions] of this.histories) {\n for (const [modelKey, history] of partitions) {\n if (history.lastUpdated.getTime() >= oldestTime) continue;\n oldest = { pairKey, modelKey };\n oldestTime = history.lastUpdated.getTime();\n }\n }\n return oldest;\n }\n}\n","/**\n * nexus-agents/consensus - Correlation Tracker\n *\n * Tracks voting history and computes pairwise correlations between agents.\n * Used by higher-order voting methods to account for agent dependencies.\n *\n * @module consensus/correlation-tracker\n * (Source: Issue #333)\n */\n\nimport { createLogger } from '../core/logger.js';\nimport { getTimeProvider, getRandomProvider } from '../core/index.js';\nimport type { Vote } from './types-core.js';\nimport type {\n ICorrelationTracker,\n CorrelationMatrix,\n CorrelationCoefficient,\n IndependentSubset,\n VotingObservation,\n HigherOrderVotingConfig,\n CorrelationTrackerStats,\n AgentPairKey,\n CorrelationRecordContext,\n} from './higher-order-types.js';\nimport { createAgentPairKey, DEFAULT_HIGHER_ORDER_CONFIG } from './higher-order-types.js';\nimport {\n type MutablePairwiseHistory,\n isComparable,\n votesAgree,\n didAlignWithOutcome,\n computeCorrelationCoefficient,\n partitionIntoIndependentGroups,\n} from './correlation-helpers.js';\nimport { CorrelationModelPartitions } from './correlation-model-partitions.js';\n\n// Re-export helper types and functions for convenience\nexport type { MutablePairwiseHistory } from './correlation-helpers.js';\nexport {\n isComparable,\n votesAgree,\n didAlignWithOutcome,\n computeCorrelationCoefficient,\n isIndependentFromSubset,\n computeSubsetObservationCount,\n partitionIntoIndependentGroups,\n} from './correlation-helpers.js';\n\nconst logger = createLogger({ component: 'correlation-tracker' });\n\n/**\n * Correlation tracker implementation.\n * Records voting history and computes pairwise agent correlations.\n *\n * Memory bounded: uses FIFO eviction when maxObservationsPerAgent or maxProposals limits reached.\n */\nexport class CorrelationTracker implements ICorrelationTracker {\n private readonly config: HigherOrderVotingConfig;\n private readonly observations: Map<string, VotingObservation[]> = new Map();\n private readonly modelPartitions;\n private readonly agentProposals: Map<string, Map<string, VotingObservation>> = new Map();\n /** Ordered list of proposal IDs for FIFO eviction */\n private readonly proposalOrder: string[] = [];\n private cachedSubsets: IndependentSubset[] | null = null;\n\n constructor(config?: Partial<HigherOrderVotingConfig>) {\n this.config = { ...DEFAULT_HIGHER_ORDER_CONFIG, ...config };\n this.modelPartitions = new CorrelationModelPartitions(this.config.maxTrackedPairs, logger);\n logger.info('CorrelationTracker initialized', {\n maxObservationsPerAgent: this.config.maxObservationsPerAgent,\n maxProposals: this.config.maxProposals,\n });\n }\n\n setCurrentModelPins(modelPins: ReadonlyMap<string, string>): void {\n this.modelPartitions.setCurrentPins(modelPins);\n this.invalidateCache();\n }\n\n recordVote(\n agentId: string,\n vote: Vote,\n outcome: 'approved' | 'rejected',\n context?: CorrelationRecordContext\n ): void {\n if (context !== undefined) this.setCurrentModelPins(context.modelPins);\n const proposalId = `proposal-${String(getTimeProvider().now())}-${getRandomProvider().random().toString(36).slice(2, 9)}`;\n const modelKey = context?.modelPins.get(agentId);\n const observedModel = context?.observedModels?.get(agentId);\n const observation: VotingObservation = {\n proposalId,\n agentId,\n decision: vote.decision,\n confidence: vote.confidence,\n alignedWithOutcome: didAlignWithOutcome(vote.decision, outcome),\n timestamp: new Date(getTimeProvider().now()),\n ...(modelKey !== undefined ? { modelKey } : {}),\n ...(observedModel !== undefined ? { observedModel } : {}),\n };\n this.storeObservation(agentId, observation);\n this.invalidateCache();\n }\n\n recordProposalVotes(\n proposalId: string,\n votes: ReadonlyMap<string, Vote>,\n outcome: 'approved' | 'rejected',\n context?: CorrelationRecordContext\n ): void {\n if (context !== undefined) this.setCurrentModelPins(context.modelPins);\n // FIFO eviction when proposal limit reached (Issue #521)\n this.evictOldProposalsIfNeeded();\n\n const proposalObservations: VotingObservation[] = [];\n\n for (const [agentId, vote] of votes) {\n const modelKey = context?.modelPins.get(agentId);\n const observedModel = context?.observedModels?.get(agentId);\n const observation: VotingObservation = {\n proposalId,\n agentId,\n decision: vote.decision,\n confidence: vote.confidence,\n alignedWithOutcome: didAlignWithOutcome(vote.decision, outcome),\n timestamp: new Date(getTimeProvider().now()),\n ...(modelKey !== undefined ? { modelKey } : {}),\n ...(observedModel !== undefined ? { observedModel } : {}),\n };\n this.storeObservation(agentId, observation);\n this.storeAgentProposal(agentId, proposalId, observation);\n proposalObservations.push(observation);\n }\n\n // Track proposal order for FIFO eviction\n this.proposalOrder.push(proposalId);\n\n this.updatePairwiseCorrelations(proposalObservations);\n this.invalidateCache();\n\n logger.debug('Recorded proposal votes', {\n proposalId,\n agentCount: votes.size,\n outcome,\n totalProposals: this.proposalOrder.length,\n });\n }\n\n computeCorrelationMatrix(): CorrelationMatrix {\n const matrix: CorrelationMatrix = new Map();\n\n for (const [pairKey, history] of this.getActivePairwiseHistory()) {\n if (history.jointObservations >= this.config.minObservationsForCorrelation) {\n matrix.set(pairKey, history.correlation);\n }\n }\n\n return matrix;\n }\n\n getCorrelation(agentA: string, agentB: string): CorrelationCoefficient | undefined {\n const pairKey = createAgentPairKey(agentA, agentB);\n const history = this.getActivePairwiseHistory().get(pairKey);\n\n if (history === undefined) return undefined;\n if (history.jointObservations < this.config.minObservationsForCorrelation) return undefined;\n\n return history.correlation;\n }\n\n identifyIndependentSubsets(): readonly IndependentSubset[] {\n if (this.cachedSubsets !== null) return this.cachedSubsets;\n\n const agents = this.getTrackedAgents();\n if (agents.length === 0) {\n this.cachedSubsets = [];\n return this.cachedSubsets;\n }\n\n const correlationMatrix = this.computeCorrelationMatrix();\n const activeHistory = this.getActivePairwiseHistory();\n const subsets = partitionIntoIndependentGroups(\n agents,\n correlationMatrix,\n activeHistory,\n this.config\n );\n\n this.cachedSubsets = subsets;\n logger.debug('Identified independent subsets', {\n agentCount: agents.length,\n subsetCount: subsets.length,\n });\n\n return subsets;\n }\n\n hasSufficientData(agentIds: readonly string[]): boolean {\n if (agentIds.length < 2) return false;\n\n let pairsWithData = 0;\n const totalPairs = (agentIds.length * (agentIds.length - 1)) / 2;\n const activeHistory = this.getActivePairwiseHistory();\n\n for (let i = 0; i < agentIds.length; i++) {\n for (let j = i + 1; j < agentIds.length; j++) {\n const agentA = agentIds[i];\n const agentB = agentIds[j];\n if (agentA !== undefined && agentB !== undefined) {\n const pairKey = createAgentPairKey(agentA, agentB);\n const history = activeHistory.get(pairKey);\n if (\n history !== undefined &&\n history.jointObservations >= this.config.minObservationsForCorrelation\n ) {\n pairsWithData++;\n }\n }\n }\n }\n\n // Require at least 50% of pairs to have sufficient data\n return pairsWithData >= totalPairs * 0.5;\n }\n\n getStats(): CorrelationTrackerStats {\n const agents = this.getTrackedAgents();\n // Used by callers to understand full correlation state\n void this.computeCorrelationMatrix();\n const subsets = this.identifyIndependentSubsets();\n\n let totalCorrelation = 0;\n let pairsWithSufficientData = 0;\n const activeHistory = this.getActivePairwiseHistory();\n\n for (const [, history] of activeHistory) {\n if (history.jointObservations >= this.config.minObservationsForCorrelation) {\n totalCorrelation += history.correlation;\n pairsWithSufficientData++;\n }\n }\n\n let totalObservations = 0;\n for (const obs of this.observations.values()) {\n totalObservations += obs.length;\n }\n\n return {\n totalAgents: agents.length,\n trackedPairs: activeHistory.size,\n totalObservations,\n averageCorrelation:\n pairsWithSufficientData > 0 ? totalCorrelation / pairsWithSufficientData : 0,\n independentSubsetCount: subsets.length,\n pairsWithSufficientData,\n };\n }\n\n clear(): void {\n this.observations.clear();\n this.modelPartitions.clear();\n this.agentProposals.clear();\n this.proposalOrder.length = 0;\n this.cachedSubsets = null;\n logger.info('CorrelationTracker cleared');\n }\n\n // ============================================================================\n // Private helpers\n // ============================================================================\n\n /**\n * Evict oldest proposals when maxProposals limit is reached.\n * Also cleans up agentProposals entries for evicted proposals.\n */\n private evictOldProposalsIfNeeded(): void {\n while (this.proposalOrder.length >= this.config.maxProposals) {\n const evictedProposalId = this.proposalOrder.shift();\n if (evictedProposalId === undefined) break;\n\n // Clean up agentProposals for the evicted proposal\n for (const [agentId, proposalMap] of this.agentProposals) {\n if (proposalMap.has(evictedProposalId)) {\n proposalMap.delete(evictedProposalId);\n // Clean up empty agent entries\n if (proposalMap.size === 0) {\n this.agentProposals.delete(agentId);\n }\n }\n }\n\n logger.debug('Evicted oldest proposal', {\n evictedProposalId,\n reason: 'maxProposals',\n remainingProposals: this.proposalOrder.length,\n });\n }\n }\n\n private storeObservation(agentId: string, observation: VotingObservation): void {\n let agentObs = this.observations.get(agentId);\n if (agentObs === undefined) {\n agentObs = [];\n this.observations.set(agentId, agentObs);\n }\n\n // FIFO eviction when per-agent limit reached (Issue #521)\n while (agentObs.length >= this.config.maxObservationsPerAgent) {\n const evicted = agentObs.shift();\n if (evicted !== undefined) {\n logger.debug('Evicted oldest observation for agent', {\n agentId,\n evictedProposalId: evicted.proposalId,\n reason: 'maxObservationsPerAgent',\n });\n }\n }\n\n agentObs.push(observation);\n }\n\n private storeAgentProposal(\n agentId: string,\n proposalId: string,\n observation: VotingObservation\n ): void {\n let agentProposalMap = this.agentProposals.get(agentId);\n if (agentProposalMap === undefined) {\n agentProposalMap = new Map();\n this.agentProposals.set(agentId, agentProposalMap);\n }\n agentProposalMap.set(proposalId, observation);\n }\n\n private updatePairwiseCorrelations(observations: VotingObservation[]): void {\n for (let i = 0; i < observations.length; i++) {\n for (let j = i + 1; j < observations.length; j++) {\n const obsA = observations[i];\n const obsB = observations[j];\n if (obsA === undefined || obsB === undefined) continue;\n\n const pairKey = createAgentPairKey(obsA.agentId, obsB.agentId);\n const history = this.modelPartitions.getOrCreate(pairKey, () => {\n return {\n pairKey,\n jointObservations: 0,\n agreements: 0,\n disagreements: 0,\n correlation: 0,\n lastUpdated: new Date(getTimeProvider().now()),\n };\n });\n\n // Skip abstain observations — they are neutral (Issue #763)\n if (!isComparable(obsA, obsB)) continue;\n\n history.jointObservations++;\n const agreed = votesAgree(obsA, obsB);\n if (agreed === true) {\n history.agreements++;\n } else {\n history.disagreements++;\n }\n\n history.correlation = computeCorrelationCoefficient(history);\n history.lastUpdated = new Date(getTimeProvider().now());\n }\n }\n }\n\n private getTrackedAgents(): string[] {\n return Array.from(this.observations.keys());\n }\n\n private getActivePairwiseHistory(): Map<AgentPairKey, MutablePairwiseHistory> {\n return this.modelPartitions.getActiveHistory();\n }\n\n private invalidateCache(): void {\n this.cachedSubsets = null;\n }\n}\n\n/**\n * Creates a new correlation tracker instance.\n */\nexport function createCorrelationTracker(\n config?: Partial<HigherOrderVotingConfig>\n): ICorrelationTracker {\n return new CorrelationTracker(config);\n}\n","/**\n * nexus-agents/consensus - Correlation Persistence\n *\n * Disk persistence for CorrelationTracker voting history. Enables Higher-Order\n * Voting (HOV) to accumulate correlation data across process restarts,\n * activating Bayesian correlation awareness.\n *\n * Storage: append-only JSONL at `~/.nexus-agents/voting/correlations.jsonl`\n * (mode 0o600). Each line is one `PersistedProposal`. Append-only avoids the\n * cross-process read-merge-rename race the previous `correlations.json`\n * design had (#2973): two processes voting concurrently each loaded N\n * entries, each merged their own proposal, each renamed over the same file,\n * losing the loser's proposal. Append guarantees atomic-per-line writes on\n * POSIX so concurrent writers are race-free.\n *\n * Reads dedupe by `proposalId` (last write wins) and apply FIFO eviction\n * past `maxProposals`. A legacy `correlations.json` is read alongside the\n * JSONL on every load (its entries are surfaced like any other history) and\n * is left in place: nothing consolidates or removes it (the compaction\n * routine #2992 shipped for that was never called and was deleted in #6425).\n * New writes always go to the JSONL.\n *\n * @module consensus/correlation-persistence\n * (Source: Issue #514; #2973 for the JSONL switch)\n */\n\nimport * as fs from 'node:fs';\nimport { nexusDataPath } from '../config/nexus-data-dir.js';\nimport type { Result } from '../core/result.js';\nimport { ok, err } from '../core/result.js';\nimport type { ILogger } from '../core/logger.js';\nimport { createLogger } from '../core/logger.js';\nimport type { ICorrelationTracker, HigherOrderVotingConfig } from './higher-order-types.js';\nimport { DEFAULT_HIGHER_ORDER_CONFIG } from './higher-order-types.js';\nimport { createCorrelationTracker } from './correlation-tracker.js';\nimport {\n PersistedCorrelationDataSchema,\n PersistedProposalSchema,\n replayProposals,\n type PersistedCorrelationData,\n type PersistedProposal,\n} from './correlation-persistence-records.js';\n\nexport {\n createPersistedProposal,\n PersistedCorrelationDataSchema,\n type PersistedCorrelationData,\n} from './correlation-persistence-records.js';\n\nconst logger: ILogger = createLogger({ component: 'correlation-persistence' });\n\n/** Subdirectory name under the resolved nexus data dir for voting data. */\nconst VOTING_SUBDIR = 'voting';\n\n/** Legacy single-JSON file (pre-#2973). Still read on load; never written. */\nconst CORRELATIONS_FILE = 'correlations.json';\n\n/** Active append-only JSONL store (#2973). */\nconst CORRELATIONS_JSONL_FILE = 'correlations.jsonl';\n\n/** File permissions: user read/write only */\nconst FILE_MODE = 0o600;\n\n/** Directory permissions: user read/write/execute only */\nconst DIR_MODE = 0o700;\n\n/** Schema version 3 adds optional pinned and observed model provenance. */\nconst SCHEMA_VERSION = 3;\n\n// ============================================================================\n// Path Helpers\n// ============================================================================\n\n/**\n * Returns the absolute path to the **legacy** correlation data file. Kept\n * for back-compat — new writes go through `getCorrelationJsonlPath()`.\n */\nexport function getCorrelationDataPath(): string {\n return nexusDataPath(VOTING_SUBDIR, CORRELATIONS_FILE);\n}\n\n/** Returns the absolute path to the active JSONL store (#2973). */\nexport function getCorrelationJsonlPath(): string {\n return nexusDataPath(VOTING_SUBDIR, CORRELATIONS_JSONL_FILE);\n}\n\n/**\n * Ensures the voting data directory exists with appropriate permissions.\n */\nfunction ensureVotingDirectory(): Result<void, Error> {\n const dirPath = nexusDataPath(VOTING_SUBDIR);\n try {\n fs.mkdirSync(dirPath, { recursive: true, mode: DIR_MODE });\n return ok(undefined);\n } catch (cause: unknown) {\n const error = cause instanceof Error ? cause : new Error(String(cause));\n return err(new Error(`Failed to create voting directory at ${dirPath}: ${error.message}`));\n }\n}\n\n// ============================================================================\n// Save (append-only, race-free across processes)\n// ============================================================================\n\n/**\n * Appends new proposals to the JSONL store. One line per proposal.\n *\n * POSIX `O_APPEND` (used implicitly by `appendFileSync` with `{flag: 'a'}`)\n * guarantees atomic writes for buffer sizes under `PIPE_BUF` (4 KB on Linux,\n * 512 B on macOS). Each line we write is a single `PersistedProposal` — well\n * under those limits in practice for the typical vote-panel size (3–7 voters).\n * Two processes calling this concurrently get all proposals persisted; no\n * read-merge-rename race possible because we never read or rename.\n *\n * @param proposals - Array of proposals with their votes and outcomes to persist\n * @param _config - Higher-order voting config (only `maxProposals` is consulted\n * on read; this writer is fully append-only)\n * @returns Result indicating success or failure\n */\nexport function saveCorrelationData(\n proposals: PersistedProposal[],\n // config kept in the signature for ABI compatibility with the legacy\n // implementation; the JSONL writer is append-only so we don't need it here.\n // FIFO truncation happens on read.\n _config: HigherOrderVotingConfig = DEFAULT_HIGHER_ORDER_CONFIG\n): Result<void, Error> {\n const dirResult = ensureVotingDirectory();\n if (!dirResult.ok) return dirResult;\n\n if (proposals.length === 0) return ok(undefined);\n\n const filePath = getCorrelationJsonlPath();\n\n try {\n const lines = proposals.map((p) => JSON.stringify(p)).join('\\n') + '\\n';\n fs.appendFileSync(filePath, lines, { encoding: 'utf-8', mode: FILE_MODE });\n\n logger.info('Correlation proposals appended', {\n path: filePath,\n proposalCount: proposals.length,\n });\n\n return ok(undefined);\n } catch (cause: unknown) {\n const error = cause instanceof Error ? cause : new Error(String(cause));\n return err(new Error(`Failed to append correlation data: ${error.message}`));\n }\n}\n\n// ============================================================================\n// Load (consolidates JSONL + legacy JSON, dedupes by proposalId, FIFO-truncates)\n// ============================================================================\n\n/** Read the legacy `correlations.json` if present; return [] otherwise. */\nfunction loadLegacyJsonProposals(): PersistedProposal[] {\n const filePath = getCorrelationDataPath();\n if (!fs.existsSync(filePath)) return [];\n\n let rawContent: string;\n try {\n rawContent = fs.readFileSync(filePath, { encoding: 'utf-8' });\n } catch (cause: unknown) {\n logger.warn('Failed to read legacy correlations.json', {\n path: filePath,\n error: cause instanceof Error ? cause.message : String(cause),\n });\n return [];\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(rawContent);\n } catch (cause: unknown) {\n logger.warn('Corrupt legacy correlations.json — skipping', {\n path: filePath,\n error: cause instanceof Error ? cause.message : String(cause),\n });\n return [];\n }\n\n const result = PersistedCorrelationDataSchema.safeParse(parsed);\n if (!result.success) {\n logger.warn('Invalid legacy correlations.json schema — skipping', {\n path: filePath,\n error: result.error.message,\n });\n return [];\n }\n return result.data.proposals;\n}\n\ntype LineResult = { kind: 'ok'; proposal: PersistedProposal } | { kind: 'skip'; reason: string };\n\n/** Parse one JSONL line into a typed result so the loader can stay below max-complexity. */\nfunction parseJsonlLine(line: string): LineResult {\n let parsed: unknown;\n try {\n parsed = JSON.parse(line);\n } catch (cause: unknown) {\n return {\n kind: 'skip',\n reason: `JSON.parse: ${cause instanceof Error ? cause.message : String(cause)}`,\n };\n }\n const result = PersistedProposalSchema.safeParse(parsed);\n if (!result.success) return { kind: 'skip', reason: `schema: ${result.error.message}` };\n return { kind: 'ok', proposal: result.data };\n}\n\n/** Read JSONL store, dropping malformed lines with a warn log. */\nfunction loadJsonlProposals(): PersistedProposal[] {\n const filePath = getCorrelationJsonlPath();\n if (!fs.existsSync(filePath)) return [];\n\n let content: string;\n try {\n content = fs.readFileSync(filePath, { encoding: 'utf-8' });\n } catch (cause: unknown) {\n logger.warn('Failed to read correlations.jsonl', {\n path: filePath,\n error: cause instanceof Error ? cause.message : String(cause),\n });\n return [];\n }\n\n const lines = content.split('\\n').filter((line) => line.trim() !== '');\n const proposals: PersistedProposal[] = [];\n let skippedCount = 0;\n let firstSkipReason: string | undefined;\n\n for (const line of lines) {\n const result = parseJsonlLine(line);\n if (result.kind === 'ok') {\n proposals.push(result.proposal);\n } else {\n skippedCount++;\n firstSkipReason ??= result.reason;\n }\n }\n\n if (skippedCount > 0) {\n logger.warn('Skipped malformed lines in correlations.jsonl', {\n path: filePath,\n skippedCount,\n totalLines: lines.length,\n firstSkipReason,\n });\n }\n\n return proposals;\n}\n\n/**\n * Combines proposals from both stores, dedupes by proposalId (later wins),\n * sorts by timestamp ascending, and FIFO-truncates to `maxProposals`.\n */\nfunction consolidate(\n legacyProposals: PersistedProposal[],\n jsonlProposals: PersistedProposal[],\n maxProposals: number\n): PersistedProposal[] {\n const proposalMap = new Map<string, PersistedProposal>();\n // Legacy first, then JSONL — JSONL entries override legacy if same id.\n for (const p of legacyProposals) proposalMap.set(p.proposalId, p);\n for (const p of jsonlProposals) proposalMap.set(p.proposalId, p);\n\n const all = Array.from(proposalMap.values()).sort((a, b) =>\n a.timestamp.localeCompare(b.timestamp)\n );\n return all.length > maxProposals ? all.slice(all.length - maxProposals) : all;\n}\n\n/**\n * Loads and validates correlation data from disk. Combines the JSONL store\n * with the legacy `correlations.json` (if present). Always returns an Ok\n * result when the directory exists; an empty proposals array means \"no\n * persisted history\".\n *\n * Returns an `err` when NEITHER the jsonl nor the legacy file exists — the\n * first-run case. An earlier revision of this comment said that error had been\n * removed; it had not, and a caller that skipped the branch hit it on first run.\n */\nexport function loadCorrelationData(\n config: HigherOrderVotingConfig = DEFAULT_HIGHER_ORDER_CONFIG\n): Result<PersistedCorrelationData, Error> {\n const jsonlPath = getCorrelationJsonlPath();\n const legacyPath = getCorrelationDataPath();\n const jsonlExists = fs.existsSync(jsonlPath);\n const legacyExists = fs.existsSync(legacyPath);\n\n if (!jsonlExists && !legacyExists) {\n return err(new Error(`Correlation data file not found: ${jsonlPath}`));\n }\n\n const legacy = loadLegacyJsonProposals();\n const jsonl = loadJsonlProposals();\n const proposals = consolidate(legacy, jsonl, config.maxProposals);\n\n logger.info('Correlation data loaded', {\n legacyCount: legacy.length,\n jsonlCount: jsonl.length,\n afterDedup: proposals.length,\n });\n\n return ok({\n version: SCHEMA_VERSION,\n proposals,\n savedAt: new Date().toISOString(),\n });\n}\n\n/**\n * Creates a correlation tracker pre-loaded with persisted history.\n *\n * On first run (no persisted data), returns a fresh tracker.\n * On subsequent runs, replays all stored proposals through the\n * tracker's public API to reconstruct correlation state.\n *\n * This enables Higher-Order Voting to accumulate enough history\n * across process restarts to activate Bayesian correlation awareness.\n *\n * @param config - Optional partial higher-order voting config\n * @returns A correlation tracker with any persisted history replayed\n */\nexport function createPersistentCorrelationTracker(\n config?: Partial<HigherOrderVotingConfig>\n): ICorrelationTracker {\n const tracker = createCorrelationTracker(config);\n\n const mergedConfig = { ...DEFAULT_HIGHER_ORDER_CONFIG, ...config };\n const loadResult = loadCorrelationData(mergedConfig);\n if (!loadResult.ok) {\n logger.info('Starting with fresh correlation tracker', {\n reason: loadResult.error.message,\n });\n return tracker;\n }\n\n const replayedCount = replayProposals(tracker, loadResult.value.proposals);\n\n logger.info('Correlation tracker restored from persistence', {\n replayedProposals: replayedCount,\n stats: tracker.getStats(),\n });\n\n return tracker;\n}\n","/** Schemas and replay helpers for persisted correlation proposal records. */\n\nimport { z } from 'zod';\nimport type { CorrelationRecordContext, ICorrelationTracker } from './higher-order-types.js';\nimport type { Vote } from './types-core.js';\n\nconst PersistedVoteSchema = z.object({\n agentId: z.string(),\n decision: z.enum(['approve', 'reject', 'abstain']),\n confidence: z.number().min(0).max(1),\n modelKey: z.string().optional(),\n observedModel: z.string().optional(),\n});\n\ntype PersistedVote = z.infer<typeof PersistedVoteSchema>;\n\nexport const PersistedProposalSchema = z.object({\n proposalId: z.string(),\n votes: z.array(PersistedVoteSchema),\n outcome: z.enum(['approved', 'rejected']),\n timestamp: z.iso.datetime(),\n});\n\nexport type PersistedProposal = z.infer<typeof PersistedProposalSchema>;\n\nexport const PersistedCorrelationDataSchema = z.object({\n version: z.number().int().positive(),\n proposals: z.array(PersistedProposalSchema),\n savedAt: z.iso.datetime(),\n});\n\nexport type PersistedCorrelationData = z.infer<typeof PersistedCorrelationDataSchema>;\n\n/** Build one replayable record without conflating assigned and observed models. */\nexport function createPersistedProposal(\n proposalId: string,\n votes: ReadonlyMap<string, Vote>,\n outcome: 'approved' | 'rejected',\n context?: CorrelationRecordContext\n): PersistedProposal {\n const persistedVotes: PersistedVote[] = [];\n for (const [agentId, vote] of votes) {\n const modelKey = context?.modelPins.get(agentId);\n const observedModel = context?.observedModels?.get(agentId);\n persistedVotes.push({\n agentId,\n decision: vote.decision,\n confidence: vote.confidence,\n ...(modelKey !== undefined ? { modelKey } : {}),\n ...(observedModel !== undefined ? { observedModel } : {}),\n });\n }\n return {\n proposalId,\n votes: persistedVotes,\n outcome,\n timestamp: new Date().toISOString(),\n };\n}\n\nfunction findReplayModelPins(proposals: readonly PersistedProposal[]): {\n first: ReadonlyMap<string, string>;\n latest: ReadonlyMap<string, string>;\n} {\n const firstModelPins = new Map<string, string>();\n const latestModelPins = new Map<string, string>();\n for (const proposal of proposals) {\n for (const vote of proposal.votes) {\n if (vote.modelKey !== undefined && !firstModelPins.has(vote.agentId)) {\n firstModelPins.set(vote.agentId, vote.modelKey);\n }\n if (vote.modelKey !== undefined) latestModelPins.set(vote.agentId, vote.modelKey);\n }\n }\n return { first: firstModelPins, latest: latestModelPins };\n}\n\nfunction buildReplayContext(\n votes: readonly PersistedVote[],\n firstModelPins: ReadonlyMap<string, string>\n): CorrelationRecordContext {\n const modelPins = new Map<string, string>();\n const observedModels = new Map<string, string>();\n for (const vote of votes) {\n const modelKey = vote.modelKey ?? firstModelPins.get(vote.agentId);\n if (modelKey !== undefined) modelPins.set(vote.agentId, modelKey);\n if (vote.observedModel !== undefined) observedModels.set(vote.agentId, vote.observedModel);\n }\n return { modelPins, observedModels };\n}\n\n/** Replay persisted records through the tracker's public recording contract. */\nexport function replayProposals(\n tracker: ICorrelationTracker,\n proposals: readonly PersistedProposal[]\n): number {\n const replayPins = findReplayModelPins(proposals);\n for (const proposal of proposals) {\n const votes = new Map<string, Vote>();\n for (const vote of proposal.votes) {\n votes.set(vote.agentId, {\n decision: vote.decision,\n reasoning: 'replayed from persistence',\n confidence: vote.confidence,\n });\n }\n tracker.recordProposalVotes(\n proposal.proposalId,\n votes,\n proposal.outcome,\n buildReplayContext(proposal.votes, replayPins.first)\n );\n }\n tracker.setCurrentModelPins?.(replayPins.latest);\n return proposals.length;\n}\n","/**\n * Types, schemas, and response helpers for the consensus_vote MCP tool.\n * Extracted from consensus-vote.ts for file size compliance (Issue #708).\n *\n * @module mcp/tools/consensus-vote-types\n */\n\n/* eslint-disable max-lines --\n * #4701: this file sat exactly at the 400-line cap, so adding\n * `HigherOrderMetadata.appliedToDecision` (a field plus its assignment) puts it\n * one over. Taking the exemption rather than splitting an 18-export types\n * module inside a two-line governance-fidelity fix. Second file this session to\n * hit the cap this way — see #4702 for the same situation in `audit-logger.ts`.\n * Do not keep adding here; split it.\n */\n\nimport { z } from 'zod';\nimport {\n DEPRECATED_MODE_ALIAS_INPUT,\n refineDispatchModeAgreement,\n} from './async-dispatch-input.js';\nimport type {\n AgentVoteResult,\n RetriedFrom,\n SeatFallback,\n VotingResult,\n} from '../../cli/vote-types.js';\nimport {\n panelDiversityOf,\n singleModelPanelWarning,\n type PanelDiversity,\n} from '../../cli/vote-diversity.js';\nimport { VOTER_ROLES } from '../../cli/vote-types.js';\nimport {\n resolveVoterProject,\n VoterProjectInputSchema,\n type ResolvedVoterProject,\n} from '../../cli/voter-project.js';\nimport type { HigherOrderVotingResult } from '../../consensus/higher-order-types.js';\nimport type { OptionGateVerdict } from './consensus-vote-option-gate.js';\nimport type { DecisionCostSummary } from '../../observability/decision-cost.js';\nimport type { VoteRecordPersistOutcome } from './consensus-vote-recording.js';\nimport { VoteRecordPrBindingSchema } from '../../audit/vote-record.js';\nimport {\n SUPERMAJORITY_THRESHOLD,\n VOTING_THRESHOLDS,\n type ConsensusAlgorithm,\n} from '../../consensus/types-core.js';\nimport { checkUndeclaredOptions } from './consensus-vote-option-detection.js';\nimport { resolveVoteDecision } from '../../consensus/decision/verdict.js';\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 * `ERROR_FLOOR_FRACTION` moved to `consensus/decision/thresholds.ts` and\n * `getDefaultErrorPolicy` to `consensus/decision/strategy.ts` (#6000 step 1),\n * so the hard floor and the per-strategy policy default can be governed on\n * their own path. Re-exported here so every existing import keeps resolving.\n */\nexport { ERROR_FLOOR_FRACTION } from '../../consensus/decision/thresholds.js';\nexport { getDefaultErrorPolicy } from '../../consensus/decision/strategy.js';\n\nexport const ConsensusVoteInputSchema = z\n .object({\n proposal: z\n .string()\n .min(1)\n .max(MAX_PROPOSAL_LENGTH)\n .describe(\n 'Proposal text to vote on. If the proposal asks voters to choose among named ' +\n 'alternatives, declare them in `options` (#4472) — otherwise the tally records ' +\n 'approve/reject/abstain only, so every voter who engages returns `approve` and a 6-1 ' +\n 'split on WHICH option persists as 7-0, 100% (#4452). This is ENFORCED AS A WARNING, ' +\n 'not a refusal: a heuristic over the proposal text flags an apparent multi-option ' +\n 'proposal with no `options` and says so on `panelWarning` (#5360). The wording says ' +\n '\"declare\", not \"MUST\", because the warning is what the code actually holds — it is ' +\n 'tightened back only in the same change that promotes the warning to a refusal.'\n ),\n options: z\n .array(z.string().min(1).max(200))\n .min(2)\n .max(10)\n .optional()\n .describe(\n 'Named alternatives for a multi-option proposal (#4472). When present, the threshold must ' +\n 'ALSO be cleared by the leading option, in addition to the ordinary approve/reject bar: ' +\n '`unanimous` requires every approver to have chosen the SAME option, and ' +\n \"`supermajority`/`majority` measure the leading option's share of approvers. An \" +\n 'approving voter whose selection is absent or matches no declared option stays in the ' +\n 'denominator and credits no option, so a degraded response can only lower the leading ' +\n 'share, never raise it. Omit for an ordinary yes/no vote — behaviour is then unchanged.'\n ),\n project: VoterProjectInputSchema,\n threshold: VoteThresholdSchema.optional().describe(\n 'Voting threshold (legacy): majority, supermajority, unanimous. Use strategy instead.'\n ),\n strategy: VotingStrategySchema.optional().describe(\n 'Voting strategy: simple_majority (default), supermajority, unanimous, proof_of_learning, or higher_order (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 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 * The key is `dispatch` (#4968); `mode` is the deprecated alias this tool\n * used to spell it with, resolved as `dispatch ?? mode` by the handler and\n * rejected when the two disagree (the `superRefine` below). Both optional\n * (no `.default()`) so the inferred type doesn't force a value onto every\n * existing call site / test fixture.\n */\n ...DEPRECATED_MODE_ALIAS_INPUT,\n /**\n * Idempotency key for async-mode replay-safety (#3042 Stage 1c / epic\n * #2631). When set: identical (key, inputs) returns the existing job;\n * same key with different inputs fails closed with\n * `idempotency_key_collision`. Sync mode ignores this.\n */\n idempotencyKey: z\n .string()\n .min(1)\n .max(256)\n .optional()\n .describe(\n 'Replay-safe key for async-mode dispatch (#3042 Stage 1c). Same (key, inputs) returns existing jobId.'\n ),\n /**\n * Authority-tier ratification subject (#4004). Set ONLY when this vote\n * ratifies an authority-ladder promotion: the loop/strategy id (the\n * tier-transition `subject`) this vote authorizes. It is bound into the\n * persisted record's self-hash as `ratifies`, so the promotion gate\n * (`check-authority-tier-drift.ts`) can resolve a `ratificationVoteRef` to this\n * record and require `ratifies === transition.subject` (with decision=approved,\n * strategy=higher_order). Omit on an ordinary vote.\n */\n ratifies: z\n .string()\n .min(1)\n .max(256)\n .optional()\n .describe(\n 'Authority-tier ratification subject (#4004) — the loop/strategy id this vote ratifies for an authority-ladder promotion. Bound into the authentic vote record so the promotion gate can verify it. Omit for ordinary votes.'\n ),\n /**\n * Governor-path PR ratification binding (#5130 step 1). Set ONLY when this\n * vote ratifies a PR that touches governor-owned paths: the PR number and\n * the FULL head sha the panel reviewed. Bound into the persisted record's\n * self-hash as `ratifiesPr` (schema 1.10), so the caller-commits script\n * (`scripts/append-ratification-record.ts`) can copy the record into the\n * committed ledger and the governor gate (step 2) can require it to name\n * the PR under review at its head. Validated by the same schema the record\n * uses, so producer and ledger cannot disagree on the shape.\n */\n ratifiesPr: VoteRecordPrBindingSchema.optional().describe(\n 'Governor-path PR ratification binding (#5130): pr is the PR number and headSha the full 40-hex head sha the panel reviewed. Bound into the authentic vote record so the committed ledger and the governor gate can verify which PR, at which head, this panel ratified. Omit for ordinary votes.'\n ),\n // #4968: `dispatch` and the deprecated `mode` alias must agree when both are sent.\n })\n .superRefine(refineDispatchModeAgreement);\n\nexport type ConsensusVoteInput = z.infer<typeof ConsensusVoteInputSchema>;\n\n// ============================================================================\n// Response Types\n// ============================================================================\n\nexport interface AgentVoteSummary {\n role: string;\n decision: 'approve' | 'reject' | 'abstain';\n confidence: number;\n reasoning: string;\n simulated: boolean;\n /** True when this vote was generated from an error (Issue #815). */\n error: boolean;\n /** 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 * Present only when this seat answered on a different CLI or model than it\n * was assigned (#6115): where it was meant to answer and the adapter error\n * class that moved it. `panelDiversity.fallbacks` counts these seats.\n */\n fallback?: SeatFallback;\n /**\n * Present only when the per-role retry REPLACED this seat (#6246): the first\n * pass's source and, when it had one, its clipped error string. `retried`\n * says a recovery happened; this says what it recovered from.\n */\n retriedFrom?: RetriedFrom;\n}\n\n/**\n * Canonical set of decision statuses a vote response can carry. Single source\n * of truth: the `consensus_vote` MCP `outputSchema` reuses\n * {@link VoteDecisionStatusSchema} so the advertised enum can never be narrower\n * than what {@link buildResponse} emits (all five are reachable —\n * `no_quorum` on an all-error/no-quorum panel, the rest via\n * {@link mapOutcomeToDecision}). A narrower schema made strict MCP clients\n * reject `timeout`/`pending` votes with a `-32602`-class error (#4032).\n */\nexport const VoteDecisionStatusSchema = z.enum([\n 'approved',\n 'rejected',\n 'pending',\n 'timeout',\n 'no_quorum',\n]);\n\nexport type VoteDecisionStatus = z.infer<typeof VoteDecisionStatusSchema>;\n\n/**\n * Outcome of the quick-mode contrarian check (#6111).\n *\n * In quick mode the contrarian is a separate `executeExpert` call, not a seat\n * in `votes`, so `voteCounts.error` cannot count it: an errored check under\n * `absolute_quorum` yields `no_quorum` with `error: 0`. This names that voice.\n *\n * - `ok` — the check ran and returned a verdict (escalating or not).\n * - `errored` — the check ran and the contrarian voice was NOT obtained.\n * - `skipped` — the check did not run: full-panel mode (catfish is a seat),\n * simulated votes, a non-approved quick verdict, a posterior-confidence\n * escalation that pre-empted it, or an error-policy short-circuit.\n */\nexport const ContrarianCheckStatusSchema = z.enum(['ok', 'errored', 'skipped']);\n\nexport type ContrarianCheckStatus = z.infer<typeof ContrarianCheckStatusSchema>;\n\n/**\n * Narrows a response decision to the three-value vocabulary the audit record\n * uses (#4986).\n *\n * The response vocabulary is wider — it carries `timeout` and `pending` too —\n * so the narrowing has to be stated rather than left to a cast:\n *\n * - `timeout` becomes `no_quorum`. A panel that ran out of time reached no\n * quorum; it did not reject the proposal, and recording it as `rejected`\n * would attribute a verdict to voters who never gave one.\n * - `pending` returns `undefined`. A vote still in flight has no decision to\n * record, and inventing one would be worse than falling back.\n */\nexport function toRecordDecision(\n status: VoteDecisionStatus | undefined\n): 'approved' | 'rejected' | 'no_quorum' | undefined {\n switch (status) {\n case 'approved':\n case 'rejected':\n case 'no_quorum':\n return status;\n case 'timeout':\n return 'no_quorum';\n default:\n return undefined;\n }\n}\n\n/**\n * Higher-Order Voting metadata (Issue #514).\n *\n * ADVISORY, not the verdict (#4701). Read `appliedToDecision` before drawing\n * any conclusion from the rest of this object.\n */\nexport interface HigherOrderMetadata {\n posteriorApproval: number;\n posteriorRejection: number;\n effectiveVoteCount: number;\n /**\n * Aggregation used for THIS correlation-aware run — not necessarily the one\n * that produced `decision`. See {@link HigherOrderMetadata.appliedToDecision}.\n */\n method: 'ow' | 'isp' | 'simple';\n usedCorrelationData: boolean;\n improvementOverBaseline: number;\n downweightedAgents: readonly string[];\n reasoning: string;\n /**\n * Whether this correlation-aware result actually produced the response's\n * `decision` (#4701).\n *\n * Currently ALWAYS FALSE. The verdict comes from `ConsensusEngine.close()`,\n * which calls `HigherOrderVotingStrategy.calculateOutcome` — and that calls\n * `aggregateSimpleInternal`, a plain `approve / (approve + reject)` ratio\n * with no correlation input. This object is computed separately and consumed\n * only as metadata plus one escalation check.\n *\n * The field exists because the omission was actively misleading: `method`\n * can read `'ow'` while `downweightedAgents` is non-empty, from which any\n * reasonable reader concludes the correlation analysis decided the vote. It\n * did not — the \"seven voters that are really one opinion\" case is detected\n * here and then discarded.\n *\n * Making the decision genuinely correlation-aware changes governance\n * outcomes and is tracked separately; this field makes the current state\n * legible in the meantime, including in persisted vote records.\n */\n appliedToDecision: boolean;\n}\n\nexport interface ConsensusVoteResponse {\n proposal: string;\n threshold?: VoteThreshold;\n strategy: VotingStrategy;\n decision: VoteDecisionStatus;\n approvalPercentage: number;\n /**\n * `unverifiable` (#6094) counts seats that answered without reading the\n * artifact. Those seats are ALSO inside `abstain` (their legacy decision);\n * the bucket is always present, explicit 0 included — an absent key would\n * read as health.\n */\n voteCounts: {\n approve: number;\n reject: number;\n abstain: number;\n error: number;\n unverifiable: number;\n };\n /**\n * #6111: the quick-mode contrarian check, reported beside the tally because\n * `voteCounts.error` counts seats and the check is not one. Always present;\n * `skipped` is the named empty case (see {@link ContrarianCheckStatus}).\n */\n contrarianCheck: ContrarianCheckStatus;\n votes: AgentVoteSummary[];\n durationMs: number;\n simulateVotes: boolean;\n /**\n * #6110: the project every voter was told it is judging, and how that name\n * was decided — `input` (the caller's `project`), `derived` (the working\n * directory's `origin` remote or `package.json`), or `default`\n * (`nexus-agents`). Always present: a consuming repository that forgot the\n * input sees `default` next to the verdict instead of a silent mis-scope.\n */\n project: ResolvedVoterProject;\n /**\n * #6258: the working directory every seat was pointed at — the caller's\n * checkout, else the server's `process.cwd()`. Present-only: absent when no\n * live seat ran (a simulated panel) or the result bypassed `executeVoting`.\n */\n workspace?: string;\n higherOrderMetadata?: HigherOrderMetadata;\n /**\n * Set when an error policy short-circuited the vote (#2630/#3124). Explains a\n * `rejected` decision that may coexist with a high `approvalPercentage` — e.g.\n * `fail_closed: 1 voter(s) errored`. Absent on normally-tallied votes.\n */\n policyReason?: string;\n /**\n * Set when the panel was DEGRADED (#3587): some voters errored, so the\n * decision rests on fewer than the requested number of voters. Surfaces a\n * silently-shrunk panel so the result isn't read as a full-strength consensus.\n * Absent when every requested voter returned a real vote.\n */\n panelWarning?: string;\n /**\n * #6115: how many distinct models answered and how many seats answered\n * somewhere other than where they were assigned. Always present, explicit\n * zeros included — three consecutive 7-seat panels ran every seat on one\n * model after the claude and codex seats fell over, and the response read\n * identically to a three-model panel. `panelWarning` names a single-model\n * panel of 3+ seats.\n */\n panelDiversity: PanelDiversity;\n /**\n * Per-decision cost rollup (#3855): per-voter / per-model token + USD totals\n * for this governed decision. Rides the existing response — no new MCP tool.\n * Totals are a floor when `costSummary.unmeasuredVoters > 0` (voters whose\n * adapter reported no usage are counted as unmeasured, not a measured $0).\n */\n costSummary?: DecisionCostSummary;\n /**\n * #4472: declared-option outcome, present only when the proposal declared\n * `options`. Separate from `approvalPercentage` — that stays the\n * approve/reject figure — so a caller can tell WHICH bar failed.\n *\n * `unattributedApprovals` is load-bearing, not decoration: a share alone\n * cannot distinguish dissent from absence, since `4 pick X + 3 unparseable`\n * reads 57% exactly like a real 4/3 split.\n */\n optionOutcome?: {\n tally: ReadonlyArray<{ option: string; count: number }>;\n leadingOption?: string;\n leadingShare: number;\n approverCount: number;\n selectedCount: number;\n unattributedApprovals: number;\n thresholdMet: boolean;\n /**\n * #4529: why the gate vetoed, present only when it did. Carried here rather\n * than on `policyReason`, which means \"an error policy voided this vote\" —\n * a split is a decision, not a void, and conflating them let a retry policy\n * re-roll a panel that had already disagreed.\n */\n vetoReason?: string;\n };\n /**\n * #3991: whether the authentic vote record (#3897) was persisted at vote time.\n * Post-#3991 the runtime ledger routes through `nexusDataPath` under\n * `governance/`, so a writable `.nexus-agents/governance/` location almost\n * always exists and `true` is the normal case. `false` means the persist was\n * skipped (all votes simulated) or the write failed (data dir unwritable) —\n * see {@link voteRecordNote}. Surfaces to the MCP caller what was previously\n * only a server-side WARN.\n */\n voteRecordPersisted: boolean;\n /**\n * #3991: present only when {@link voteRecordPersisted} is `false` — the\n * actionable reason the record was not written (e.g. the data dir is unwritable\n * → fix permissions or set `NEXUS_VOTE_RECORDS_PATH` to a writable path).\n */\n voteRecordNote?: string;\n /**\n * #5130: the persisted record's `id`, present only when\n * {@link voteRecordPersisted} is `true`. The caller-commits script\n * (`scripts/append-ratification-record.ts --record-id`) is keyed on it, and\n * a job result carries it so `--job <jobId>` can find the record. Without\n * it nothing downstream of the vote could name the record it produced.\n */\n voteRecordId?: string;\n}\n\n/** Extended voting result with optional Higher-Order metadata. */\nexport interface ExtendedVotingResult extends VotingResult {\n strategy: VotingStrategy;\n /**\n * #4472: the declared-option tally + verdict, present only when the proposal\n * declared `options`. Reported alongside `approvalPercentage` rather than\n * folded into it, so a reader can tell which bar failed.\n */\n optionGate?: OptionGateVerdict;\n higherOrderResult?: HigherOrderVotingResult;\n /** Reason an error policy short-circuited the vote (#3124); surfaced on the response. */\n policyReason?: string;\n /**\n * #6211: the error policy the panel actually ran under — the EFFECTIVE value\n * `executeVoting` resolved (`input.errorPolicy ?? getDefaultErrorPolicy(strategy)`),\n * stamped on every path it returns through (the short-circuit and the\n * finalized result; an escalated re-vote carries its own). The persisted\n * vote record reads it from here so the ledger states the policy the vote\n * ran under rather than the raw input, which is absent whenever the caller\n * took the default. Absent only on results built by paths that never ran\n * `executeVoting` (direct unit constructions), where no policy was applied.\n */\n errorPolicy?: ErrorPolicy;\n /**\n * #4132: the FULL requested panel size (`roles.length`) — the absolute_quorum\n * predicate in {@link buildResponse} needs it to compute the absolute approval\n * floor `ceil(fraction * panelSize)`. Distinct from `votes.length`, which can\n * differ from the requested panel if the collector ever returns a short list.\n * When absent, the predicate falls back to `votes.length`.\n */\n panelSize?: number;\n /**\n * #4132: whether the contrarian (catfish) was in the requested panel. `--quick`\n * runs a 3-role panel WITHOUT catfish, so the absolute_quorum \"contrarian must\n * be present and non-error\" clause is skipped when this is false (the quick-mode\n * carve-out). True on the full 7-role panel.\n */\n contrarianRequested?: boolean;\n /**\n * #6111: outcome of the quick-mode contrarian check. Stamped by `executeVoting`\n * on every path (`skipped` when the check did not run). Absent only on results\n * built by paths that never ran `executeVoting` (direct unit calls to\n * `buildResponse`), which `buildResponse` reports as `skipped` — the check\n * genuinely did not run there.\n */\n contrarianCheck?: ContrarianCheckStatus;\n /**\n * #4135: the response-layer decision (incl. `no_quorum`) for this vote, computed\n * by {@link resolveVoteDecision}. Set by `executeVoting` right before it returns\n * so pipeline consumers (iterative-consensus, agent-executor, the CLI) can honor\n * a `no_quorum` void instead of misreading it as a rejection — WITHOUT recomputing\n * the policy math. The engine `ConsensusResult.outcome` stays 2-valued\n * (`approved`/`rejected`); this is the widened, opt-in-aware view. Absent on\n * results built by paths that never ran `executeVoting` (direct unit calls to\n * `buildResponse`), where consumers fall back to mapping the engine outcome.\n */\n decision?: VoteDecisionStatus;\n /**\n * #6110: the resolved target project, stamped by `executeVoting` alongside\n * `decision` so the CLI and the response disclose the same name and source.\n * Absent only on results built by paths that never ran `executeVoting`.\n */\n project?: ResolvedVoterProject;\n /**\n * #6258: the directory `executeVoting` handed every seat, stamped once per\n * panel. Absent on a simulated panel and on results that bypassed it.\n */\n workspace?: string;\n}\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n/** Converts AgentVoteResult to AgentVoteSummary for response. */\nexport function toAgentVoteSummary(result: AgentVoteResult): AgentVoteSummary {\n const roleName = VOTER_ROLES[result.role].split(' - ')[0] ?? result.role;\n return {\n role: roleName,\n decision: result.vote.decision,\n confidence: result.vote.confidence,\n reasoning: result.vote.reasoning,\n simulated: result.source === 'simulation',\n error: result.source === 'error',\n ...(result.vote.rejectionCategories !== undefined\n ? { rejectionCategories: result.vote.rejectionCategories }\n : {}),\n // #6050: a caller acting on the live result sees what the ledger will.\n // Present only when true, so a clean panel's response is unchanged.\n ...(result.retried === true ? { retried: true } : {}),\n // #6094: same rule for a seat that could not read the artifact.\n ...(result.source === 'unverifiable' ? { unverifiable: true as const } : {}),\n // #6115: and for a seat that answered elsewhere.\n ...(result.fallback !== undefined ? { fallback: result.fallback } : {}),\n // #6246: and for what a recovered seat was retried from.\n ...(result.retriedFrom !== undefined ? { retriedFrom: result.retriedFrom } : {}),\n };\n}\n\n/**\n * `mapOutcomeToDecision`, `VoteDecisionOutcome` and `resolveVoteDecision` (with\n * its absolute_quorum and respondent-floor helpers) moved to\n * `consensus/decision/verdict.ts` (#6000 step 1): they are the computation that\n * turns a tally plus an error policy into `approved` / `rejected` /\n * `no_quorum`, and now live where that computation can be governed on its own\n * path. Re-exported here so every existing import keeps resolving.\n */\nexport {\n mapOutcomeToDecision,\n resolveVoteDecision,\n type VoteDecisionOutcome,\n} from '../../consensus/decision/verdict.js';\n\n/**\n * #3587: partial panel degradation — some (but not all) voters errored, so the\n * decision rests on fewer voters than requested. Returns a warning string, or\n * undefined when the panel is full or entirely errored (the latter is already a\n * structured error elsewhere).\n */\nfunction panelDegradationWarning(errorCount: number, total: number): string | undefined {\n if (errorCount <= 0 || errorCount >= total) return undefined;\n return (\n `Panel degraded: ${String(errorCount)} of ${String(total)} voters errored; ` +\n `decision rests on ${String(total - errorCount)} voter(s).`\n );\n}\n\n/**\n * Append to `panelWarning` rather than assign: it has several writers and an\n * assignment would silently drop whichever fired first. A `undefined` text is\n * a no-op.\n */\nfunction appendPanelWarning(response: ConsensusVoteResponse, text: string | undefined): void {\n if (text === undefined) return;\n response.panelWarning =\n response.panelWarning === undefined ? text : `${response.panelWarning} ${text}`;\n}\n\n/**\n * #6094: seats that answered without reading the artifact. Their abstention\n * is already inside `voteCounts.abstain`; this says how many of those never\n * saw the thing they were asked to judge. Undefined when there are none —\n * the count itself is still rendered as an explicit 0 in `voteCounts`.\n */\nfunction unverifiableSeatsWarning(unverifiableCount: number, total: number): string | undefined {\n if (unverifiableCount <= 0) return undefined;\n return (\n `${String(unverifiableCount)} of ${String(total)} seat(s) could not read the artifact and ` +\n 'are recorded as unverifiable (counted as abstain in voteCounts; any decision they returned was discarded).'\n );\n}\n\n// ============================================================================\n// absolute_quorum (#4132)\n// ============================================================================\n\n/**\n * #4132: process-wide count of panels that DEGRADED to `no_quorum` under the\n * opt-in `absolute_quorum` policy. The evidence base a future default-flip rests\n * on — how often does an errored voice actually void a real panel? Incremented in\n * {@link buildResponse}; read via {@link getDegradedPanelCount}. There is no\n * metrics bus in this module, so this mirrors the bare module-level counter style\n * used elsewhere (e.g. the correlation-tracker singleton).\n */\nlet degradedPanelCount = 0;\n\n/** #4132: current degraded-panel count (see {@link degradedPanelCount}). */\nexport function getDegradedPanelCount(): number {\n return degradedPanelCount;\n}\n\n/** #4132: reset the degraded-panel counter. Test-isolation only. @internal */\nexport function resetDegradedPanelCount(): void {\n degradedPanelCount = 0;\n}\n\n/**\n * #4132: absolute_quorum response side-effects — increment the degraded-panel\n * telemetry counter and surface the actionable re-run reason on policyReason /\n * panelWarning (when an errored voter degraded the verdict without an upstream\n * short-circuit already setting result.policyReason). Extracted to hold\n * {@link buildResponse} within its cyclomatic budget.\n */\nfunction applyAbsoluteQuorumTelemetry(\n response: ConsensusVoteResponse,\n input: ConsensusVoteInput,\n decision: VoteDecisionStatus,\n degradeReason: string | undefined\n): void {\n // The evidence base for a future default-flip: how often does an errored voice\n // actually void a real panel?\n if (input.errorPolicy === 'absolute_quorum' && decision === 'no_quorum') {\n degradedPanelCount++;\n }\n if (degradeReason !== undefined) {\n response.policyReason ??= degradeReason;\n response.panelWarning ??= degradeReason;\n }\n}\n\n/**\n * Builds the response from voting result.\n *\n * `voteRecord` (#3991) is the structured authentic-vote-record persistence\n * outcome; when omitted (direct unit calls) `voteRecordPersisted` defaults to\n * `false` with no note. The live handler always supplies it.\n */\n/**\n * Name the bar a strategy actually enforces.\n *\n * Derived from {@link VOTING_THRESHOLDS} rather than a second hand-written\n * mapping, so it cannot drift from the value the engine compares against.\n * Strategies that are aliases (`higher_order`, `opinion_wise`) resolve to their\n * own 0.5 entry and therefore report `majority`, which is the point.\n */\nfunction appliedThresholdFor(strategy: VotingStrategy | undefined): VoteThreshold {\n const algorithm: ConsensusAlgorithm = strategy ?? 'simple_majority';\n const bar = VOTING_THRESHOLDS[algorithm];\n if (bar >= 1) return 'unanimous';\n if (bar >= SUPERMAJORITY_THRESHOLD) return 'supermajority';\n return 'majority';\n}\n\n/**\n * #6111: the contrarian-check status the response reports. `executeVoting`\n * stamps one on every path; a result that never went through it never ran the\n * check, so `skipped` is the truthful name for that absence — not a default\n * standing in for a measurement.\n */\nfunction contrarianCheckFor(result: ExtendedVotingResult): ContrarianCheckStatus {\n return result.contrarianCheck ?? 'skipped';\n}\n\n/**\n * The project disclosure for the response (#6110). `executeVoting` stamps the\n * resolution on the result; a direct call that bypassed it (unit tests) gets\n * the SAME resolution recomputed from the input — mirroring how `decision` is\n * handled above — so the field is always present and never a fabricated source.\n */\nfunction disclosedProject(\n input: ConsensusVoteInput,\n result: ExtendedVotingResult\n): ResolvedVoterProject {\n const { name, source } =\n result.project ?? resolveVoterProject({ input: input.project, cwd: process.cwd() });\n return { name, source };\n}\n\n/**\n * The workspace disclosure for the response (#6258): present-only, like the\n * stamp it copies — no directory is fabricated for a panel that never ran one.\n */\nfunction disclosedWorkspace(result: ExtendedVotingResult): { workspace?: string } {\n return result.workspace === undefined ? {} : { workspace: result.workspace };\n}\n\nexport function buildResponse(\n input: ConsensusVoteInput,\n result: ExtendedVotingResult,\n costSummary?: DecisionCostSummary,\n voteRecord?: VoteRecordPersistOutcome\n): ConsensusVoteResponse {\n const proposalTruncated =\n input.proposal.length > 200 ? input.proposal.slice(0, 200) + '...' : input.proposal;\n\n const errorCount = result.votes.filter((v) => v.source === 'error').length;\n const unverifiableCount = result.votes.filter((v) => v.source === 'unverifiable').length;\n\n // #4053 / #4132: the user-facing decision. An error-policy short-circuit (the\n // >50% hard floor, or fail_closed) VOIDED the vote — that is no_quorum, NOT the\n // panel rejecting. The opt-in absolute_quorum policy (#4132) additionally\n // degrades to no_quorum when ANY voter (especially the contrarian) errored, so\n // an induced error can never manufacture approved/rejected. Every other policy\n // keeps the legacy mapping. `degradeReason` (when present) is the actionable\n // \"re-run\" message; it rides the response as `policyReason`.\n //\n // #4135 (DRY): `executeVoting` already stamped `result.decision` via THIS same\n // `resolveVoteDecision`. Reuse it so the response decision can't diverge from the\n // one pipeline consumers read; recompute only for the `degradeReason` telemetry\n // and for direct unit calls that bypass `executeVoting` (where `decision` is absent).\n const resolved = resolveVoteDecision(input, result, errorCount);\n const decision = result.decision ?? resolved.decision;\n\n const response: ConsensusVoteResponse = {\n proposal: proposalTruncated,\n strategy: result.strategy,\n decision,\n approvalPercentage: result.result.approvalPercentage,\n voteCounts: {\n approve: result.result.voteCounts.approve,\n reject: result.result.voteCounts.reject,\n abstain: result.result.voteCounts.abstain,\n error: errorCount,\n unverifiable: unverifiableCount,\n },\n contrarianCheck: contrarianCheckFor(result),\n votes: result.votes.map(toAgentVoteSummary),\n durationMs: result.totalTimeMs,\n simulateVotes: result.simulateVotes,\n project: disclosedProject(input, result),\n ...disclosedWorkspace(result),\n // #6115: always present — a panel nobody answered is explicit zeros.\n panelDiversity: panelDiversityOf(result.votes),\n // #3991: surface the authentic-vote-record persistence outcome so a skipped\n // or failed persist is visible to the MCP caller (was WARN-only).\n voteRecordPersisted: voteRecord?.persisted ?? false,\n };\n if (voteRecord !== undefined && !voteRecord.persisted) {\n response.voteRecordNote = voteRecord.detail;\n }\n if (voteRecord?.persisted === true) {\n response.voteRecordId = voteRecord.record.id;\n }\n\n if (result.optionGate !== undefined) {\n response.optionOutcome = toOptionOutcome(result.optionGate);\n }\n\n applyOptionalResponseFields(response, input, result, errorCount, costSummary);\n applyAbsoluteQuorumTelemetry(response, input, decision, resolved.degradeReason);\n return response;\n}\n\n/** The #4472 declared-option block of the response, from the gate's verdict. */\nfunction toOptionOutcome(\n g: OptionGateVerdict\n): NonNullable<ConsensusVoteResponse['optionOutcome']> {\n return {\n tally: g.tally.map((t) => ({ option: t.option, count: t.count })),\n ...(g.leadingOption !== undefined ? { leadingOption: g.leadingOption } : {}),\n leadingShare: g.leadingShare,\n approverCount: g.approverCount,\n selectedCount: g.selectedCount,\n unattributedApprovals: g.unattributedApprovals,\n thresholdMet: g.approved,\n ...(g.reason !== undefined ? { vetoReason: g.reason } : {}),\n };\n}\n\n/**\n * Attach the optional response fields (threshold, policy reason, panel warning,\n * higher-order metadata, cost summary). Extracted from {@link buildResponse} to\n * keep its cyclomatic complexity within the lint budget (#3855).\n */\nfunction applyOptionalResponseFields(\n response: ConsensusVoteResponse,\n input: ConsensusVoteInput,\n result: ExtendedVotingResult,\n errorCount: number,\n costSummary?: DecisionCostSummary\n): void {\n // #5315: this echoed `input.threshold` verbatim. But `resolveStrategy`\n // ignores `threshold` entirely when `strategy` is also supplied, and\n // `higher_order` carries a 0.5 bar — so a caller passing\n // `strategy: 'higher_order'` + `threshold: 'supermajority'` (the pairing the\n // governance table itself prescribes) got a record naming a bar the vote\n // never had to clear. Observed live at 4-approve/3-reject, 57.1%, reported as\n // `threshold: 'supermajority'`.\n //\n // The field now names the bar the ENGINE enforced, taken from the strategy it\n // actually ran. The record is ratification evidence; it must state what it\n // measured, not what was asked for.\n response.threshold = appliedThresholdFor(result.strategy);\n if (result.policyReason !== undefined) {\n response.policyReason = result.policyReason;\n }\n const panelWarning = panelDegradationWarning(errorCount, result.votes.length);\n if (panelWarning !== undefined) {\n response.panelWarning = panelWarning;\n }\n // #6094: APPENDED, like the undeclared-options warning below — a third\n // writer that assigned would clobber whichever fired first.\n appendPanelWarning(\n response,\n unverifiableSeatsWarning(response.voteCounts.unverifiable, result.votes.length)\n );\n // #6115: a 3+ panel whose every answering seat ran on ONE model. Appended for\n // the same reason as the two above.\n appendPanelWarning(response, singleModelPanelWarning(result.votes));\n // #5360: a proposal that names alternatives while `options` is undefined\n // records a split as uniform approval — every voter approves the ACT of\n // deciding, not a side. A 3-3 tie was recorded as `APPROVED 83.3%` that way.\n //\n // The all-approved signal is the sharper half: on a proposal that enumerates a\n // fork it is the observed signature, and unlike a reasoning-variance detector\n // it needs nothing the persisted record drops (#5339).\n //\n // APPENDED, not assigned. `panelWarning` already has two writers and a third\n // that clobbered would silently drop whichever fired first.\n const engaged = result.votes.length - errorCount;\n const undeclared = checkUndeclaredOptions(\n input.proposal,\n input.options,\n engaged > 0 && response.voteCounts.reject === 0 && response.voteCounts.abstain === 0\n );\n if (undeclared.flagged) appendPanelWarning(response, undeclared.warning);\n if (isHigherOrderStrategy(result.strategy) && result.higherOrderResult) {\n response.higherOrderMetadata = toHigherOrderMetadata(result.higherOrderResult);\n }\n if (costSummary !== undefined) {\n response.costSummary = costSummary;\n }\n}\n\n/** Maps a HigherOrderVotingResult to the response's metadata shape. */\nfunction toHigherOrderMetadata(r: HigherOrderVotingResult): HigherOrderMetadata {\n return {\n posteriorApproval: r.posteriorApproval,\n posteriorRejection: r.posteriorRejection,\n effectiveVoteCount: r.effectiveVoteCount,\n method: r.method,\n usedCorrelationData: r.usedCorrelationData,\n improvementOverBaseline: r.improvementOverBaseline,\n downweightedAgents: r.downweightedAgents,\n reasoning: r.reasoning,\n // #4701: the engine's `calculateOutcome` decides, and it aggregates simple.\n // Hardcoded false rather than computed, because there is currently no code\n // path where this result reaches the verdict — a computed `false` would\n // imply one exists.\n appliedToDecision: false,\n };\n}\n","/**\n * Panel model diversity (#6115).\n *\n * `costSummary.perModel` showed the final model per seat but not the ASSIGNED\n * one, so \"7 of 7 on gemini\" was visible only to someone who knew the\n * round-robin. This module measures what the response and the summary line\n * disclose: how many distinct models actually answered, and how many seats\n * answered somewhere other than where they were assigned.\n *\n * Shared by the MCP response (`consensus-vote-types`) and the CLI / GitHub\n * renderings (`vote-summary-lines`) so the two cannot drift.\n *\n * @module cli/vote-diversity\n */\n\nimport { countDistinctModels, UNRESOLVED_MODEL_ID } from '../config/model-equivalence.js';\nimport type { AgentVoteResult, SeatFallback } from './vote-types.js';\nimport { bareCliName } from './voter-fallback.js';\n\n/**\n * Always present on the response, explicit zeros included: an absent key\n * would read as a healthy spread, which is exactly what the three\n * single-model panels looked like.\n */\nexport interface PanelDiversity {\n /** Distinct models (by canonical identity, #4390) among the seats that answered. */\n readonly distinctModels: number;\n /** Seats that answered on a CLI or model other than the one assigned. */\n readonly fallbacks: number;\n}\n\n/** A seat that answered elsewhere, with where it landed. */\nexport interface SeatFallbackDetail {\n readonly role: AgentVoteResult['role'];\n readonly fallback: SeatFallback;\n /** The CLI that answered, bare (`gemini`), or `?` when the result carries none. */\n readonly toCli: string;\n readonly toModel: string | undefined;\n}\n\n/** The seats whose answer counts — the same subset `reportVoteIndependence` judges. */\nfunction answeringSeats(votes: readonly AgentVoteResult[]): AgentVoteResult[] {\n return votes.filter((v) => v.source === 'llm');\n}\n\n/** A seat's model when it resolved one; the placeholder is not a model. */\nfunction resolvedModel(v: AgentVoteResult): string | undefined {\n return v.model === undefined || v.model === '' || v.model === UNRESOLVED_MODEL_ID\n ? undefined\n : v.model;\n}\n\n/** Every answering seat that carries a fallback, in panel order. */\nexport function seatFallbacks(votes: readonly AgentVoteResult[]): SeatFallbackDetail[] {\n const out: SeatFallbackDetail[] = [];\n for (const v of answeringSeats(votes)) {\n if (v.fallback === undefined) continue;\n out.push({\n role: v.role,\n fallback: v.fallback,\n toCli: v.cli === undefined ? '?' : bareCliName(v.cli),\n toModel: resolvedModel(v),\n });\n }\n return out;\n}\n\n/**\n * Distinct answering models and fallback count. A panel nobody answered is\n * `{ 0, 0 }` — `countDistinctModels([])` is 0 and no seat can have fallen\n * over — which is the named empty case, not a claim of diversity.\n */\nexport function panelDiversityOf(votes: readonly AgentVoteResult[]): PanelDiversity {\n const models = answeringSeats(votes)\n .map(resolvedModel)\n .filter((m): m is string => m !== undefined);\n return {\n distinctModels: countDistinctModels(models),\n fallbacks: seatFallbacks(votes).length,\n };\n}\n\n/** Panels smaller than this cannot make a meaningful independence claim to weaken. */\nconst MIN_PANEL_FOR_DIVERSITY_WARNING = 3;\n\n/**\n * The warning for a panel of 3+ seats whose every answering seat ran on ONE\n * model. Undefined on a diverse panel, a small panel, a panel nobody answered\n * (the degradation warning already covers that one), and a panel where an\n * answering seat never resolved its model — \"all on one model\" is a claim,\n * and an unresolved seat is a seat the claim cannot cover (#4983).\n */\nexport function singleModelPanelWarning(votes: readonly AgentVoteResult[]): string | undefined {\n if (votes.length < MIN_PANEL_FOR_DIVERSITY_WARNING) return undefined;\n const answered = answeringSeats(votes);\n const models = answered.map(resolvedModel);\n const model = models[0];\n if (model === undefined || models.includes(undefined)) return undefined;\n if (panelDiversityOf(votes).distinctModels !== 1) return undefined;\n const silent = votes.length - answered.length;\n const missing = silent > 0 ? ` (${String(silent)} did not answer)` : '';\n return (\n `All ${String(answered.length)} seats answered on ${model}${missing}; ` +\n 'independence is weaker than assigned.'\n );\n}\n","/**\n * Detects a multi-option proposal submitted WITHOUT declared `options` (#5360).\n *\n * #4452 established the failure: a proposal naming alternatives only in prose\n * records a split as uniform approval, because every voter returns `approve` —\n * approving the ACT of deciding, not a side. #4472 built the fix (`options`, a\n * `selectedOption` prompt, a threshold over the option tally). Nothing detected\n * when a caller should have used it, so the failure stayed reachable by\n * forgetting — and it recurred on a real architecture vote, where a 3–3 tie was\n * recorded as `APPROVED 83.3%`.\n *\n * A WARNING, not a refusal. The false-positive cost is unmeasured: a proposal\n * that merely mentions options would trip the patterns, and refusing a\n * governance vote on an unmeasured heuristic trades one failure for a worse one.\n * The promotion criteria live on the follow-up issue (#5422).\n *\n * The measurement (#5422): precision cannot be measured over the vote ledger,\n * which stores a 503-char proposal preview, so {@link detectUndeclaredOptions}\n * returns a structured verdict — fired / not-fired, the pattern, and a bounded\n * excerpt from the FULL proposal — that `consensus_vote` records on every vote\n * alongside the decision-cost rollup. `scripts/undeclared-options-precision.ts`\n * reads those rows back for hand-labelling.\n *\n * @module mcp/tools/consensus-vote-option-detection\n */\n\nimport { UNDECLARED_OPTIONS_EXCERPT_CHARS } from '../../observability/decision-cost.js';\n\n/**\n * Prose shapes that name alternatives. Deliberately narrow — each must be a\n * phrase a caller uses when asking voters to CHOOSE, not merely to approve.\n *\n * Anchored and bounded: no nested quantifiers, so none can backtrack\n * catastrophically on a long proposal — pinned by a test, since the detector\n * runs on the FULL proposal (#5422). Exported so the precision reader can\n * print a per-pattern count, zero-hit patterns included.\n */\nexport const UNDECLARED_OPTION_PATTERNS: readonly RegExp[] = Object.freeze([\n // `Option A` and `OPTION A`, but NOT `option a` — the lowercase form appears\n // in ordinary prose (\"there is no option a caller can set\"), the capitalised\n // form is a heading. The motivating proposal used `Option A`; an\n // uppercase-only pattern would have missed the instance this exists for.\n /\\b(?:Option|OPTION) [A-Z0-9]\\b/,\n /\\bchoose between\\b/i,\n /\\bwhich of (?:the )?(?:these|those|the following)\\b/i,\n /\\bpick exactly one\\b/i,\n /\\bvote for exactly one\\b/i,\n]);\n\n/** Outcome of the check. A discriminated union so \"not checked\" cannot read as \"clean\". */\nexport type UndeclaredOptionsCheck =\n { readonly flagged: false } | { readonly flagged: true; readonly warning: string };\n\n/**\n * The detector's verdict as recorded for the precision measurement (#5422).\n *\n * `pattern` is the matching regex as written (`String(regex)`, flags included)\n * and `excerpt` is a window of at most {@link UNDECLARED_OPTIONS_EXCERPT_CHARS}\n * characters around the match, taken from the FULL proposal — the text the\n * ledger's preview drops. Both are absent on a not-fired verdict; the\n * not-fired row is still recorded, because it is the denominator.\n */\ninterface UndeclaredOptionsVerdict {\n readonly fired: boolean;\n readonly pattern?: string;\n readonly excerpt?: string;\n}\n\n/**\n * A window of {@link UNDECLARED_OPTIONS_EXCERPT_CHARS} around `[start, end)`,\n * centred on the match and clamped to the text so a short proposal comes back\n * whole rather than padded.\n */\nfunction excerptAround(text: string, start: number, end: number): string {\n const width = UNDECLARED_OPTIONS_EXCERPT_CHARS;\n if (text.length <= width) return text;\n const slack = Math.max(0, width - (end - start));\n let from = Math.max(0, start - Math.floor(slack / 2));\n const to = Math.min(text.length, from + width);\n from = Math.max(0, to - width);\n return text.slice(from, to);\n}\n\n/**\n * The pure verdict: does the proposal name alternatives while `options` is\n * absent, and where? Declared options (a non-empty array) mean the option-aware\n * tally is live, so the verdict is not-fired without consulting the patterns —\n * an empty array switches the tally off exactly as absence does.\n *\n * First matching pattern wins, in {@link UNDECLARED_OPTION_PATTERNS} order.\n */\nexport function detectUndeclaredOptions(\n proposal: string,\n declaredOptions: readonly string[] | undefined\n): UndeclaredOptionsVerdict {\n if (declaredOptions !== undefined && declaredOptions.length > 0) return { fired: false };\n if (proposal === '') return { fired: false };\n for (const pattern of UNDECLARED_OPTION_PATTERNS) {\n const match = pattern.exec(proposal);\n if (match === null) continue;\n const start = match.index;\n return {\n fired: true,\n pattern: String(pattern),\n excerpt: excerptAround(proposal, start, start + match[0].length),\n };\n }\n return { fired: false };\n}\n\n/**\n * Does the proposal name alternatives while `options` is absent?\n *\n * `allEngagedApproved` is the second signal, and it is the sharper one (#5360,\n * from the review panel): when every non-errored voter returns `approve` on a\n * proposal that enumerates a fork, that is the observed signature of this exact\n * defect rather than a proposal that merely mentions the word \"option\". It is\n * available without the persisted reasoning that a full disagreement detector\n * would need (#5339).\n *\n * Pass `undefined` for `allEngagedApproved` when the votes are not yet known —\n * the check then rests on the prose alone and says so in the warning.\n */\nexport function checkUndeclaredOptions(\n proposal: string,\n declaredOptions: readonly string[] | undefined,\n allEngagedApproved?: boolean\n): UndeclaredOptionsCheck {\n // One pattern set: the warning and the recorded verdict must agree, or the\n // precision measured on the record says nothing about the warning (#5422).\n if (!detectUndeclaredOptions(proposal, declaredOptions).fired) return { flagged: false };\n\n const base =\n 'This proposal appears to name alternatives, but `options` was not declared, ' +\n 'so the tally records approve/reject only and cannot say WHICH alternative won ' +\n '(#4452, #5360). Re-run with `options` to record the option tally.';\n\n // Stated separately because it is evidence, not restatement: every voter\n // approving a proposal that enumerates a fork is the signature of voters\n // approving the act of deciding rather than a side.\n return {\n flagged: true,\n warning:\n allEngagedApproved === true\n ? `${base} Every non-errored voter returned \\`approve\\`, which is the signature of this defect.`\n : base,\n };\n}\n","/**\n * Error-policy handling for consensus_vote (#2630).\n *\n * When a voter errors or times out (`source === 'error'`), the response\n * shape already distinguishes it via `voteCounts.error` (see\n * consensus-vote-types.ts:188). What was missing: a configurable\n * decision policy for how those error voters interact with the strategy\n * threshold, plus a safety floor for \"too many errors to call a\n * consensus.\"\n *\n * Three policies, plus a hard floor:\n *\n * - `reduce_denominator` (default for non-strict strategies): errors\n * filtered out before the engine sees votes. Denominator = non-error\n * votes. Pragmatic for operational decisions.\n * - `count_as_abstain`: errors reach the engine as abstain. Conservative\n * — error voter is treated as having withheld approval.\n * - `fail_closed` (default for unanimous only, #3138): any error\n * short-circuits to vote-void.\n * - `absolute_quorum` (opt-in, #4132): errors reach the engine as abstain\n * (like `count_as_abstain`), but the post-tally predicate in\n * `buildResponse` degrades ANY errored panel to `no_quorum` — an induced\n * error can never manufacture `approved`/`rejected`. Does not short-circuit\n * here (below the hard floor); the degrade happens after the tally so a\n * genuine reject is preserved.\n *\n * Hard floor: if errors > `ERROR_FLOOR_FRACTION` of total voters, the\n * vote always fails regardless of policy. \"All CLIs are down\" is not a\n * consensus.\n *\n * @module mcp/tools/consensus-vote-error-policy\n */\n\nimport type { AgentVoteResult } from '../../cli/vote-types.js';\nimport type { ErrorPolicy } from './consensus-vote-types.js';\nimport { ERROR_FLOOR_FRACTION } from '../../consensus/decision/thresholds.js';\n\nexport interface ErrorPolicyDecision {\n /** True when the vote should short-circuit to failed without reaching the engine. */\n readonly shortCircuit: boolean;\n /** Human-readable reason when shortCircuit is true. */\n readonly reason?: string;\n /**\n * Votes to feed to the engine. Empty when shortCircuit is true.\n * Otherwise: errors filtered out (`reduce_denominator`) or converted\n * to abstain (`count_as_abstain`).\n */\n readonly engineVotes: readonly AgentVoteResult[];\n}\n\nfunction isHardFloorTripped(errorCount: number, totalCount: number): boolean {\n if (totalCount === 0) return false;\n return errorCount / totalCount > ERROR_FLOOR_FRACTION;\n}\n\n/**\n * Apply the configured error policy to the raw voter list. Returns a\n * decision describing whether the vote should short-circuit and what\n * votes (if any) should reach the consensus engine.\n *\n * The hard floor (`errors / total > ERROR_FLOOR_FRACTION`) takes\n * precedence over any policy — even `reduce_denominator` short-circuits\n * when most voters errored, because the remaining minority isn't a real\n * consensus.\n *\n * The per-voter response list is built from the ORIGINAL `votes` array\n * upstream; this helper only shapes what the engine sees.\n */\nexport function applyErrorPolicy(\n votes: readonly AgentVoteResult[],\n policy: ErrorPolicy\n): ErrorPolicyDecision {\n const errorVotes = votes.filter((v) => v.source === 'error');\n const errorCount = errorVotes.length;\n const totalCount = votes.length;\n\n if (isHardFloorTripped(errorCount, totalCount)) {\n return {\n shortCircuit: true,\n reason: `Errors exceeded ${String(Math.round(ERROR_FLOOR_FRACTION * 100))}% of voters (${String(errorCount)}/${String(totalCount)})`,\n engineVotes: [],\n };\n }\n\n if (policy === 'fail_closed' && errorCount > 0) {\n return {\n shortCircuit: true,\n reason: `fail_closed: ${String(errorCount)} voter(s) errored`,\n engineVotes: [],\n };\n }\n\n if (policy === 'count_as_abstain' || policy === 'absolute_quorum') {\n // Errors stay in the engine input but as abstain decisions — the engine sees\n // the FULL panel rather than a shrunk denominator. The original\n // `source: 'error'` is preserved so the per-voter response shape and\n // `voteCounts.error` still report the error, and (for #4132 absolute_quorum)\n // the post-tally predicate in buildResponse can still see the true errorCount.\n // absolute_quorum does NOT fail-close here — the >50% hard floor above still\n // applies, but a sub-floor error degrades to no_quorum in buildResponse, not\n // a short-circuit, so the engine outcome (a genuine reject) is preserved.\n return {\n shortCircuit: false,\n engineVotes: votes.map((v) =>\n v.source === 'error' ? { ...v, vote: { ...v.vote, decision: 'abstain' as const } } : v\n ),\n };\n }\n\n // reduce_denominator (default): errors filtered out before engine sees them.\n return {\n shortCircuit: false,\n engineVotes: votes.filter((v) => v.source !== 'error'),\n };\n}\n","/**\n * Bound an artifact to a prompt budget, and disclose the bound.\n *\n * CLAUDE.md: \"A review must consume the artifact, not a description of it. …\n * Bounded reads are legitimate — the Context budget is real and a large diff\n * cannot always be read whole — but the record must then state which portion\n * was reviewed. A partial review honestly labeled is fine; a partial review\n * recorded as complete is the failure.\"\n *\n * The shape follows `mcp/tools/pr-review-diff-budget.ts` (#4140), which\n * established it for `pr_review`: within budget the output is BYTE-IDENTICAL\n * and carries no note, so the ordinary case is unchanged; over budget a visible\n * note rides on the prompt and a machine-readable bound rides on the result.\n *\n * This is the character-oriented sibling of that file-oriented packer. Where a\n * diff can be packed by whole files (so a reviewed file is reviewed\n * completely), a free-text proposal has no such seam and is cut at a character\n * count — which makes disclosure more important, not less, since the cut can\n * land mid-sentence.\n *\n * @module utils/bounded-artifact\n */\n\n/** How much of an artifact a reviewer actually saw. */\nexport interface ArtifactBound {\n /** Characters the reviewer was shown. */\n readonly reviewedChars: number;\n /** Characters in the whole artifact. */\n readonly totalChars: number;\n /** True when the reviewer saw less than the whole artifact. */\n readonly partial: boolean;\n}\n\n/** An artifact bounded for a prompt, with the disclosure that must accompany it. */\nexport interface BoundedArtifact {\n /** The text to embed — the whole artifact when it fit. */\n readonly text: string;\n /** Visible note to place before the artifact; `''` when nothing was cut. */\n readonly note: string;\n /** Machine-readable bound for the record; `undefined` when nothing was cut. */\n readonly bound: ArtifactBound | undefined;\n}\n\n/**\n * Cut `text` to `budget` characters when it exceeds it, and produce the\n * disclosure.\n *\n * `label` names the artifact in the note — a reviewer told \"you are seeing part\n * of it\" needs to know part of what.\n *\n * Pure: no I/O, no model call, no logging.\n */\nexport function boundArtifactForReview(\n text: string,\n budget: number,\n label: string\n): BoundedArtifact {\n if (text.length <= budget) {\n return { text, note: '', bound: undefined };\n }\n return {\n text: text.slice(0, budget),\n note:\n `> NOTE: partial view — you are seeing the first ${String(budget)} of ` +\n `${String(text.length)} characters of the ${label}. Judge only what is shown, ` +\n `and treat insufficient visibility as itself a reason to raise a concern.`,\n bound: { reviewedChars: budget, totalChars: text.length, partial: true },\n };\n}\n","/**\n * Contrarian escalation for `quickMode` consensus votes (#1799, #3174, #4132,\n * #6111).\n *\n * A quick-mode approval is a 3-voter verdict. Before it stands, this module\n * either re-runs the vote with the full panel (a borderline Bayesian posterior,\n * or a single contrarian expert rejecting with high confidence) or, under\n * `absolute_quorum`, reports that the contrarian voice could not be obtained so\n * the verdict degrades to `no_quorum` instead of silently proceeding.\n *\n * Moved out of `consensus-vote.ts` as a pure extraction (#6148, row 1): the\n * only in-tree consumer is `executeVotingInner`. The full-panel re-vote is\n * INJECTED (`ctx.revote`) rather than imported, so this module does not\n * import the parent and the split introduces no import cycle.\n *\n * @module mcp/tools/consensus-vote-contrarian\n * (Source: Issue #6148)\n */\n\nimport type { ILogger, IModelAdapter } from '../../core/index.js';\nimport { boundArtifactForReview, type BoundedArtifact } from '../../utils/bounded-artifact.js';\nimport type { ResolvedVoterProject } from '../../cli/voter-project.js';\nimport type { AgentVoteResult } from '../../cli/vote-types.js';\nimport { buildWorkspaceBlock } from '../../cli/voter-response.js';\nimport { shouldEscalateLowPosterior } from './consensus-vote-types.js';\nimport type {\n ConsensusVoteInput,\n ContrarianCheckStatus,\n ExtendedVotingResult,\n VotingStrategy,\n} from './consensus-vote-types.js';\n\n/** Options forwarded unchanged to the full-panel re-vote (#4040, #5393, #6110). */\ninterface RevoteOpts {\n voteTimeoutMs?: number;\n gatewayAdapters?: readonly IModelAdapter[] | undefined;\n /** #5393: stops LAUNCHING un-started voters when `cancel_job` fires. */\n signal?: AbortSignal | undefined;\n /** #6110: already resolved by the outer frame; the re-vote reuses it. */\n project?: ResolvedVoterProject | undefined;\n workspace?: string | undefined;\n workspaceSha?: string | undefined;\n /** #6162: per-seat heartbeat, retained through the re-vote. */\n onVoteCollected?: ((vote: AgentVoteResult) => void) | undefined;\n}\n\n/**\n * The full-panel re-vote, supplied by the caller. `executeVoting` in\n * `consensus-vote.ts` satisfies it; declared here so the sibling never\n * imports the parent.\n */\ntype QuickModeRevote = (\n input: ConsensusVoteInput,\n logger: ILogger,\n opts?: RevoteOpts\n) => Promise<ExtendedVotingResult>;\n\n/** Confidence threshold above which a contrarian rejection triggers escalation (#1799). */\nconst CONTRARIAN_ESCALATION_THRESHOLD = 0.8;\n\n/**\n * Characters of the proposal the contrarian is shown.\n *\n * Unchanged from the value that was inline, so escalation behaviour on\n * ordinary proposals is identical; what changed is that exceeding it is now\n * disclosed to the contrarian rather than silently applied (#5301).\n */\nconst CONTRARIAN_PROPOSAL_BUDGET = 2000;\n\n/** Build the contrarian prompt, carrying the partial-view note when present. */\nfunction buildContrarianPrompt(bounded: BoundedArtifact, opts?: RevoteOpts): string {\n const workspaceBlock = buildWorkspaceBlock(opts?.workspace, opts?.workspaceSha);\n return [\n 'You are a contrarian analyst. Your job is to find reasons this proposal should be REJECTED.',\n 'Look for: YAGNI (not needed), MISALIGNED (wrong tech/architecture), SECURITY_RISK, SCOPE_CREEP.',\n '',\n ...(workspaceBlock === '' ? [] : [workspaceBlock]),\n ...(bounded.note === '' ? [] : [bounded.note, '']),\n `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 opts?: RevoteOpts\n): Promise<{ shouldEscalate: boolean; reason: string; confidence: number; errored: boolean }> {\n try {\n const { executeExpert } = await import('../../pipeline/expert-bridge.js');\n // #5301: the proposal was cut to 2000 chars with no marker. A `pr_review`\n // proposal carries the whole diff whenever it fits the panel's context\n // (#6003; up to the 2 MB input cap), so the\n // contrarian could be deciding whether to escalate having seen ~4% of it —\n // the header region, where a diff is least informative — and returned the\n // same `shouldEscalate: false` it returns after reading the whole thing.\n const bounded = boundArtifactForReview(proposal, CONTRARIAN_PROPOSAL_BUDGET, 'proposal');\n logPartialProposal(bounded, log);\n const result = await executeExpert('architecture', buildContrarianPrompt(bounded, opts), {\n workDir: opts?.workspace,\n });\n // Expert-bridge reported failure — the contrarian voice was NOT obtained.\n if (!result.success) return { shouldEscalate: false, reason: '', confidence: 0, errored: true };\n\n const jsonMatch = result.text.match(/\\{[\\s\\S]*\\}/);\n // The expert responded but emitted no structured concern — treat as \"no\n // escalation\" (it spoke, it just didn't flag a blocker), not an error.\n if (jsonMatch === null)\n return { shouldEscalate: false, reason: '', confidence: 0, errored: false };\n\n const parsed = JSON.parse(jsonMatch[0]) as {\n decision?: string;\n confidence?: number;\n reasoning?: string;\n };\n\n const isRejection = parsed.decision === 'reject';\n const confidence = typeof parsed.confidence === 'number' ? parsed.confidence : 0;\n const reasoning = typeof parsed.reasoning === 'string' ? parsed.reasoning : '';\n\n if (isRejection && confidence >= CONTRARIAN_ESCALATION_THRESHOLD) {\n log.info('Contrarian rejected with high confidence', {\n confidence,\n reasoning: reasoning.slice(0, 200),\n });\n return { shouldEscalate: true, reason: reasoning, confidence, errored: false };\n }\n\n return { shouldEscalate: false, reason: '', confidence, errored: false };\n } catch (error: unknown) {\n // Closes #2952 (medium): pre-fix the bare `catch {}` swallowed\n // `executeExpert` failures, JSON parse errors, and expert-bridge\n // import errors identically — the escalation guardrail silently\n // disabled itself with no log trail. Log + return the default\n // \"no escalation\" envelope so a contrarian-check infrastructure\n // bug is at least visible in operator logs.\n const message = error instanceof Error ? error.message : String(error);\n log.warn('Contrarian check failed; defaulting to no escalation', { error: message });\n // #4132: the contrarian voice was NOT obtained — errored:true so\n // absolute_quorum can degrade to no_quorum instead of silently proceeding.\n return { shouldEscalate: false, reason: '', confidence: 0, errored: true };\n }\n}\n\n/**\n * Escalation gate for `quickMode` approvals. Two independent triggers, both\n * re-running `executeVoting` with the full voter panel:\n *\n * 1. Posterior-confidence (#3174): for `higher_order`/`opinion_wise`, a borderline\n * Bayesian posterior (below `HIGHER_ORDER_ESCALATION_POSTERIOR_FLOOR`) means the\n * 3-voter quick panel was barely decisive — escalate without spending a\n * contrarian call. Checked first so a borderline posterior short-circuits it.\n * 2. Contrarian agent (#1799): run a single contrarian to catch\n * YAGNI / SECURITY_RISK / SCOPE_CREEP; escalate if it rejects with high\n * confidence.\n *\n * Returns:\n * - `{ escalated }` — a full-panel re-vote result to use instead;\n * - `{ degradeReason }` — (#4132, absolute_quorum only) the contrarian check\n * ERRORED, so the quickMode verdict must degrade to `no_quorum`;\n * - `{}` — no escalation, continue with the quickMode result.\n *\n * Every shape also carries `contrarianCheck` (#6111): what became of the\n * contrarian call itself — `skipped` when this gate returned before making it,\n * `errored` when it was made and the voice was not obtained (under every\n * policy, not only absolute_quorum — the policy decides the verdict, the field\n * reports the check), `ok` when it answered.\n */\nexport async function maybeEscalateContrarian(\n input: ConsensusVoteInput,\n outcome: 'approved' | 'rejected',\n ctx: {\n strategy: VotingStrategy;\n posteriorApproval: number | undefined;\n /** Required, not defaulted: the compiler names every call site (#6148). */\n revote: QuickModeRevote;\n },\n logger: ILogger,\n // Mirror executeVoting's opts so gateway routing (#4040) survives the escalation\n // re-vote — the object is forwarded by reference today, but the wider type makes\n // that contract explicit and refactor-safe.\n opts?: RevoteOpts\n): Promise<{\n escalated?: ExtendedVotingResult;\n degradeReason?: string;\n contrarianCheck: ContrarianCheckStatus;\n}> {\n if (!input.quickMode || outcome !== 'approved' || input.simulateVotes) {\n return { contrarianCheck: 'skipped' };\n }\n\n if (shouldEscalateLowPosterior(ctx.strategy, outcome, input.quickMode, ctx.posteriorApproval)) {\n logger.warn('Posterior-confidence escalation: re-running with full vote (#3174)', {\n strategy: ctx.strategy,\n posteriorApproval: ctx.posteriorApproval,\n });\n return {\n escalated: await ctx.revote({ ...input, quickMode: false }, logger, opts),\n contrarianCheck: 'skipped',\n };\n }\n\n const escalation = await runContrarianCheck(input.proposal, logger, opts);\n const contrarianCheck: ContrarianCheckStatus = escalation.errored ? 'errored' : 'ok';\n // #4132: under absolute_quorum, a contrarian check that ERRORED means the\n // contrarian voice was never heard — that voids the quorum (no_quorum), it is\n // not silently skipped. Only under absolute_quorum; every other policy keeps\n // the pre-#4132 behavior of proceeding with the quickMode result.\n if (escalation.errored && input.errorPolicy === 'absolute_quorum') {\n logger.warn('Contrarian check errored under absolute_quorum — degrading to no_quorum (#4132)');\n return {\n degradeReason: 'no_quorum: re-run — contrarian check errored (absolute_quorum quick-mode)',\n contrarianCheck,\n };\n }\n if (!escalation.shouldEscalate) return { contrarianCheck };\n logger.warn('Contrarian escalation: re-running with full vote', {\n reason: escalation.reason,\n confidence: escalation.confidence,\n });\n return {\n escalated: await ctx.revote({ ...input, quickMode: false }, logger, opts),\n contrarianCheck,\n };\n}\n","/**\n * 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 for targeting a\n * specific file. The committed `<repo>/governance/vote-records.jsonl`\n * ledger the gates read is NOT written by this store at all: it is fed by\n * the caller-commits path, `scripts/append-ratification-record.ts`, which\n * copies ONE verified, PR-bound record out of the runtime store (#5130\n * step 1; the deferral this comment used to record is resolved);\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 VoteRecordPrBinding,\n VoterSummary,\n} from './vote-record.js';\nimport { computeReasoningDigest, mintReasoningNonce } from './reasoning-commitment.js';\nimport type { RedactionRecord } from './redaction-record.js';\nimport { RedactionRecordSchema } from './redaction-record.js';\nimport {\n VoteRecordSchema,\n clipForRecord,\n computeVoteRecordHash,\n hashProposal,\n projectPrBinding,\n projectRetriedFrom,\n projectSeatFallback,\n} from './vote-record.js';\n\n/**\n * Repo-relative path of the COMMITTED governance ledger the gates read\n * (`check-authority-tier-drift.ts` #3895; the governor gate's ledger read is\n * #5130 step 2). As of #3991 the runtime store never auto-writes here. The\n * committed ledger is fed by the caller-commits path (#5130 step 1):\n * `scripts/append-ratification-record.ts` copies one verified, `ratifiesPr`-\n * bound, approved record out of the runtime store, re-sequenced into this\n * ledger, and the caller commits it in the PR it ratifies. The\n * {@link VOTE_RECORDS_PATH_ENV} override can still point the runtime store here\n * directly; the source-checkout guard refuses that from a test run (#6070).\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 // #6115: where the seat was assigned, and — when it answered elsewhere —\n // the fallback the live result stated. `model` alone showed seven\n // identical values on a panel assigned three ways and could not say so.\n ...(v.assignedCli !== undefined ? { assignedCli: v.assignedCli } : {}),\n ...(v.fallback !== undefined ? { fallback: projectSeatFallback(v.fallback) } : {}),\n // #6246: what the per-role retry replaced, so the record names both the\n // seat's final state and the state it recovered from. The live retry\n // already clipped and de-controlled the cause; this is projection only.\n ...(v.retriedFrom !== undefined ? { retriedFrom: projectRetriedFrom(v.retriedFrom) } : {}),\n });\n }\n return summaries;\n}\n\n/**\n * The stored reasoning, clipped with a marker rather than silently (#5373),\n * and the salted commitment to it (#6263, schema 1.13).\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 *\n * The digest is over the text AS STORED — after the clip — so the commitment\n * re-opens from the record alone; a digest over the unclipped text could\n * never be verified once the tail is gone. One fresh nonce per entry.\n */\nfunction reasoningFields(reasoning: string): {\n reasoning: string;\n reasoningTruncated?: true;\n reasoningNonce: string;\n reasoningDigest: string;\n} {\n const { text, truncated } = clipForRecord(reasoning);\n const reasoningNonce = mintReasoningNonce();\n return {\n reasoning: text,\n ...(truncated === true ? { reasoningTruncated: true as const } : {}),\n reasoningNonce,\n reasoningDigest: computeReasoningDigest(reasoningNonce, text),\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 * The PR this vote ratifies, bound to the head the panel saw (#5130 step 1,\n * schema 1.10). Set ONLY for a governor-path ratification vote; hash-covered\n * so the gate can trust it. Omitted on an ordinary vote.\n */\n readonly ratifiesPr?: VoteRecordPrBinding | undefined;\n /**\n * The error policy the panel ran under (#6211, schema 1.11) — the EFFECTIVE\n * policy `executeVoting` resolved (`input.errorPolicy ??\n * getDefaultErrorPolicy(strategy)`), never the raw tool input. Hash-covered\n * so the governor ledger gate can trust it. Optional here because the\n * builder is also the fixture path for gate tests; the producer-facing\n * `RecordAuthenticVoteArgs` requires it (including its `undefined` case) so\n * the compiler names every live call site.\n */\n readonly errorPolicy?: VoteRecord['errorPolicy'] | 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.13 carries a voter `reasoningDigest` (#6263) — every entry with stored\n * reasoning does, so every record with a responding voter is 1.13 and the\n * tiers below are reachable only through a panel with no voter entry — 1.12\n * a voter `retriedFrom` (#6246), 1.11 a record-level\n * `errorPolicy` (#6211), 1.10 a record-level `ratifiesPr` PR binding (#5130),\n * 1.9 a voter `assignedCli` or `fallback`, 1.8 a voter `model` or an\n * `unverifiable` seat, 1.7 a retried voter seat, 1.6 voter reasoning, 1.5\n * panel coverage, 1.4 option coverage, 1.3 a bare tally (historical only — a\n * tally now always travels with coverage), 1.2 neither.\n */\nfunction recordVersion(\n optionTally: VoteRecordOptionCount[] | undefined,\n optionCoverage: VoteRecordOptionCoverage | undefined,\n panelCoverage: VoteRecordPanelCoverage | undefined,\n voters: readonly VoterSummary[],\n /** The two record-level optionals the caller supplies directly (grouped: max-params). */\n recordLevel: Pick<BuildVoteRecordInput, 'ratifiesPr' | 'errorPolicy'>\n): Exclude<VoteRecord['version'], '1.1'> {\n const voterTier = voterTierOf(voters);\n // 1.13 first (#6263): the digest changes what the hash COVERS for the\n // reasoning keys, so a reader must know from the version alone which fold\n // rule applies; it outranks every tier below, record-level ones included.\n if (voterTier === '1.13') return '1.13';\n // 1.12 next: a carried first-pass cause is orthogonal to every tier below\n // — it co-occurs with `retried` (1.7) but a retried seat need not carry one\n // — and a reader needs to know from the version alone whether a voter entry\n // may carry it (#6246). It is the one voter tier ABOVE the record-level\n // tiers, so it is checked before them.\n if (voterTier === '1.12') return '1.12';\n // 1.11 next: the policy is record-level and orthogonal to every tier\n // below, and a reader needs to know from the version alone whether the\n // record may carry it (#6211).\n if (recordLevel.errorPolicy !== undefined) return '1.11';\n // 1.10 next: the binding is record-level and orthogonal to every voter\n // tier below, on the same rule (#5130).\n if (recordLevel.ratifiesPr !== undefined) return '1.10';\n if (voterTier !== undefined) return voterTier;\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 * The tier the voter entries alone imply, or undefined when no entry carries\n * a field above 1.5. Split from {@link recordVersion} when 1.12 (#6246) pushed\n * it past the complexity cap; the ordering comments are the tier rule.\n */\nfunction voterTierOf(\n voters: readonly VoterSummary[]\n): '1.6' | '1.7' | '1.8' | '1.9' | '1.12' | '1.13' | undefined {\n if (voters.some((v) => v.reasoningDigest !== undefined)) return '1.13';\n if (voters.some((v) => v.retriedFrom !== undefined)) return '1.12';\n // 1.9, on the same tier logic as 1.8: either key alone lifts the tier, so\n // a reader knows from the version whether a seat's assignment and fallover\n // may be on its entry (#6115).\n if (voters.some((v) => v.assignedCli !== undefined || v.fallback !== undefined)) return '1.9';\n // 1.8, same rule: both fields are orthogonal to the tiers below, and a\n // reader needs to know from the version alone whether voter entries may\n // 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 return undefined;\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 — UNLESS `always` is set: a PR-bound record (#5130,\n * 1.10 by construction, no older projection to keep) carries its coverage\n * even when whole, because the ratification gate refuses a bound record whose\n * coverage is absent rather than reading absence as whole (#6213).\n */\nfunction panelCoverageOf(\n votes: readonly AgentVoteResult[],\n always: boolean\n): VoteRecordPanelCoverage | undefined {\n const erroredRoles = votes.filter((v) => v.source === 'error').map((v) => v.role);\n if (erroredRoles.length === 0 && !always) 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\n/**\n * The two ratification bindings, each present only when supplied: the\n * authority-ladder subject (#3927 item 1) and the PR binding (#5130). The PR\n * binding is rebuilt field-by-field on the `voteCounts` rule — the object the\n * caller passed is not the object the ledger line carries.\n */\nfunction ratificationBindings(\n input: Pick<BuildVoteRecordInput, 'ratifies' | 'ratifiesPr'>\n): Pick<VoteRecord, 'ratifies' | 'ratifiesPr'> {\n return {\n ...(input.ratifies !== undefined ? { ratifies: input.ratifies } : {}),\n ...(input.ratifiesPr !== undefined ? { ratifiesPr: projectPrBinding(input.ratifiesPr) } : {}),\n };\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, input.ratifiesPr !== undefined);\n const voters = toVoterSummaries(input.votes);\n const payload: Omit<VoteRecord, 'hash'> = {\n version: recordVersion(optionTally, optionCoverage, panelCoverage, voters, input),\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 ...ratificationBindings(input),\n ...(optionTally !== undefined ? { optionTally } : {}),\n ...(optionCoverage !== undefined ? { optionCoverage } : {}),\n ...(panelCoverage !== undefined ? { panelCoverage } : {}),\n // #6211: the effective error policy, present-only, on the `ratifiesPr` rule.\n ...(input.errorPolicy !== undefined ? { errorPolicy: input.errorPolicy } : {}),\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 // #6264: a redaction record holds a sequence of its own, so the tip is\n // read over BOTH kinds — or the next vote would land on the redaction's\n // sequence and read as a fork. The advisory `previousHash` is the hash of\n // the highest-sequence record, whichever kind (the later of equals wins);\n // on an append-only ledger with no fork that is the last line, as before.\n const { records, redactions } = readVoteRecords(filePath);\n const all: readonly { readonly sequence: number; readonly hash: string }[] = [\n ...records,\n ...redactions,\n ];\n if (all.length === 0) return { maxSequence: -1, lastHash: undefined };\n let tip = all[0] as { sequence: number; hash: string };\n for (const record of all) {\n if (record.sequence >= tip.sequence) tip = record;\n }\n return { maxSequence: tip.sequence, lastHash: tip.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 gates read is a SEPARATE\n * caller-commits artifact, fed by `scripts/append-ratification-record.ts`\n * (#5130 step 1) from the records this function writes.\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): ParsedVoteLedger {\n if (!existsSync(filePath)) return { records: [], redactions: [], invalidLines: [] };\n return parseVoteRecordsText(readFileSync(filePath, 'utf-8'));\n}\n\n/** What a ledger's lines parse into: the two record kinds, and the lines that are neither. */\nexport interface ParsedVoteLedger {\n readonly records: VoteRecord[];\n /** Redaction records (#6264), by their `kind: 'redaction'` line discriminator. */\n readonly redactions: RedactionRecord[];\n readonly invalidLines: number[];\n}\n\n/** True for a parsed line whose `kind` says it is a redaction record. */\nfunction isRedactionLine(value: unknown): boolean {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as { readonly kind?: unknown }).kind === 'redaction'\n );\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 * which takes BOTH arrays: a redaction line (#6264) is routed to its own\n * schema by `kind`; every other line is a vote record, and a vote record\n * carries no `kind`.\n */\nexport function parseVoteRecordsText(text: string): ParsedVoteLedger {\n const records: VoteRecord[] = [];\n const redactions: RedactionRecord[] = [];\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 value: unknown = JSON.parse(line);\n if (isRedactionLine(value)) {\n const parsed = RedactionRecordSchema.safeParse(value);\n if (parsed.success) redactions.push(parsed.data);\n else invalidLines.push(i + 1);\n continue;\n }\n const parsed = VoteRecordSchema.safeParse(value);\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, redactions, 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 * Consensus Vote — Recording Helpers\n *\n * Memory and outcome store recording for consensus votes.\n * Extracted from consensus-vote.ts for file size compliance.\n *\n * @module mcp/tools/consensus-vote-recording\n * (Source: Issue #753 memory, Issue #1134 cold start)\n */\n\nimport {\n createLogger,\n getErrorMessage,\n getTimeProvider,\n getRandomProvider,\n} from '../../core/index.js';\nimport type { AgentVoteResult } from '../../cli/vote-types.js';\nimport type { ConsensusResult } from '../../consensus/types.js';\nimport type { VoteRecord, VoteRecordPrBinding } from '../../audit/vote-record.js';\nimport type { ErrorPolicy } from './consensus-vote-types.js';\nimport {\n persistVoteRecord,\n readVoteRecords,\n resolveVoteRecordsPath,\n voteRecordWriteFailedMessage,\n} from '../../audit/vote-record-store.js';\nimport { mkdirSync } from 'node:fs';\nimport { dirname } from 'node:path';\n\nimport { FileLockTimeoutError, withFileLock } from '../../utils/file-lock.js';\nimport { getToolMemory } from './tool-memory.js';\nimport {\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 | {\n readonly persisted: true;\n readonly record: VoteRecord;\n /** The ledger the record was written to AND read back from (#6531). */\n readonly path: string;\n }\n | {\n readonly persisted: false;\n /**\n * `read-back-missed` (#6531): the append returned, but the record is not\n * on the ledger under its id and hash. Never reported as written.\n */\n readonly reason: 'all-simulated' | 'write-failed' | 'read-back-missed';\n readonly detail: string;\n };\n\n/**\n * Persist an authentic, self-hashed vote record (tamper-evident record set +\n * monotonic sequence, #3927) at vote time (#3897). Best-effort: a persist\n * failure must never fail the vote, so the store swallows + logs. Skips\n * 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 /** Governor-path PR binding (#5130) — bound into the record's self-hash as `ratifiesPr`. */\n ratifiesPr?: VoteRecordPrBinding | undefined;\n /** #4053: vote voided by an error-policy short-circuit → persist `no_quorum`. */\n errorVoided?: boolean | undefined;\n /** Declared options; see `BuildVoteRecordInput.declaredOptions` (#6049). */\n declaredOptions: readonly string[] | undefined;\n /**\n * The decision `resolveVoteDecision` already produced for the response.\n *\n * Required — including its `undefined` case — because deriving it a second\n * time inside the record store is what let the chain say `approved` for a\n * vote the tool reported as `no_quorum` (#4986). A caller that has the\n * resolved decision must hand it over rather than let the store guess.\n */\n resolvedDecision: VoteRecord['decision'] | undefined;\n /**\n * The error policy the panel ran under (#6211, schema 1.11) — the EFFECTIVE\n * policy `executeVoting` stamped on its result, not the raw tool input.\n *\n * Required — including its `undefined` case — on the `resolvedDecision`\n * rule: both producers (the MCP handler and the CLI `vote` command) narrow\n * `ExtendedVotingResult` before reaching here, and an optional field is\n * exactly how #5362 lost `optionGate` at that narrowing with no compile\n * error. `undefined` is honest only for a result built without\n * `executeVoting`, where no policy was applied; the record then carries no\n * key and the ledger gate reports it as `unrecorded`.\n */\n errorPolicy: ErrorPolicy | undefined;\n}\n\nexport async function recordAuthenticVote(\n args: RecordAuthenticVoteArgs\n): Promise<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 let record: VoteRecord | undefined;\n try {\n record = await underLedgerLock(resolvedPath, () =>\n persistVoteRecord(storeInput(args, id, resolvedPath))\n );\n } catch (error: unknown) {\n return lockFailure(resolvedPath, error);\n }\n if (record === undefined) {\n // The path resolved but the append threw (data dir unwritable) —\n // persistVoteRecord already WARNed with the underlying error + path. Surface\n // the actionable unwritable-data-dir guidance with the concrete path.\n return {\n persisted: false,\n reason: 'write-failed',\n detail: voteRecordWriteFailedMessage(resolvedPath),\n };\n }\n return confirmPersisted(record, resolvedPath);\n}\n\n/** The store input for one vote, written to `filePath`. */\nfunction storeInput(\n args: RecordAuthenticVoteArgs,\n id: string,\n filePath: string\n): Parameters<typeof persistVoteRecord>[0] {\n return {\n id,\n proposal: args.proposal,\n strategy: toRecordStrategy(args.strategy),\n result: args.result,\n votes: args.votes,\n declaredOptions: args.declaredOptions,\n resolvedDecision: args.resolvedDecision,\n ...(args.errorVoided !== undefined ? { errorVoided: args.errorVoided } : {}),\n ...(args.correlationId !== undefined ? { correlationId: args.correlationId } : {}),\n ...(args.ratifies !== undefined ? { ratifies: args.ratifies } : {}),\n ...(args.ratifiesPr !== undefined ? { ratifiesPr: args.ratifiesPr } : {}),\n ...(args.errorPolicy !== undefined ? { errorPolicy: args.errorPolicy } : {}),\n // #6531: write to the path resolved by the caller, so the read-back and the\n // path the caller prints are the file the store wrote.\n filePath,\n logger,\n };\n}\n\n/**\n * Run the store's append while holding the ledger's cross-process lock\n * (#6531). The store reads the ledger tip and then appends, synchronously,\n * so two PROCESSES appending at once took the same tip and wrote the same\n * sequence. The lock is taken here rather than inside the store to keep the\n * governor-path store unchanged; this recorder is the store's only production\n * writer. The wait is async (#6548 review): a contended ledger must not stall\n * the MCP server's event loop.\n */\nasync function underLedgerLock<T>(path: string, write: () => T): Promise<T> {\n mkdirSync(dirname(path), { recursive: true });\n return withFileLock(`${path}.lock`, write);\n}\n\n/** The outcome when the lock could not be taken (or its directory not created). */\nfunction lockFailure(path: string, error: unknown): VoteRecordPersistOutcome {\n logger.warn('Failed to take the vote-record ledger lock', {\n error: getErrorMessage(error),\n path,\n });\n const detail =\n error instanceof FileLockTimeoutError\n ? `Authentic vote record NOT persisted (${path}): timed out after ` +\n `${String(error.timeoutMs)}ms waiting for the ledger lock ${error.lockPath}, ` +\n 'held by another live process.'\n : voteRecordWriteFailedMessage(path);\n return { persisted: false, reason: 'write-failed', detail };\n}\n\n/** The outcome for an append that returned `record`: persisted only if it reads back (#6531). */\nfunction confirmPersisted(record: VoteRecord, path: string): VoteRecordPersistOutcome {\n if (ledgerHolds(path, record)) return { persisted: true, record, path };\n const detail =\n `record ${record.id} (sequence ${String(record.sequence)}) is not in ${path} ` +\n 'after the append; it was NOT persisted';\n logger.error(detail);\n return { persisted: false, reason: 'read-back-missed', detail };\n}\n\n/**\n * True when the ledger holds `record` under its id AND hash (#6531). Matching\n * the hash too means a different record that happens to share the id does not\n * count as this one. An unreadable ledger holds nothing.\n */\nfunction ledgerHolds(path: string, record: VoteRecord): boolean {\n try {\n return readVoteRecords(path).records.some(\n (onDisk) => onDisk.id === record.id && onDisk.hash === record.hash\n );\n } catch (error: unknown) {\n logger.warn('Vote-record read-back failed', { error: getErrorMessage(error), path });\n return false;\n }\n}\n\n/** Records a failed consensus vote to session memory. Best-effort. */\nexport function recordVoteError(proposal: string, errorMessage: string): void {\n try {\n const memory = getToolMemory();\n memory.recordError({\n error: `Consensus vote failed: ${errorMessage.slice(0, 150)}`,\n solution: 'Pending - vote execution failed',\n filePattern: 'mcp/tools/consensus-vote',\n });\n } catch (error: unknown) {\n logger.warn('Failed to record vote error', { error: getErrorMessage(error) });\n }\n}\n\n/**\n * Records per-vote outcomes to the outcome store for adaptive routing.\n * 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 * Cross-process advisory file lock (#6531).\n *\n * A lock is a sibling file created with `O_CREAT | O_EXCL` (`'wx'`), so exactly\n * one process can create it. The holder writes a unique owner token into it —\n * `<host>:<pid>:<random>` — and on release removes it only while the token is\n * still its own.\n *\n * WHY a lock and not a bare `O_APPEND` write: an append-only ledger that stamps\n * each line with `max(sequence) + 1` has to READ the tip before it writes, and\n * `O_APPEND` makes only the write atomic. Two processes that read the same tip\n * wrote the same sequence (#6531). The read and the append share this lock.\n *\n * ASYNC (#6548 review): acquisition polls with `setTimeout`, so a contended\n * lock never blocks the event loop — the MCP server keeps serving while a vote\n * waits for the ledger.\n *\n * STALENESS. A lock is abandoned when its owner cannot release it:\n * - owner on THIS host: stale iff its pid is no longer running. A live holder\n * is never broken, however slow — breaking it would admit a second writer;\n * - owner on another host, or an unreadable token (a crash between create and\n * write, or a foreign format): stale iff older than `staleMs`.\n *\n * BREAKING WITHOUT ABA (#6548 review). \"Observe stale, then remove the path\" is\n * unsafe: between the two, another process may break the same stale lock and\n * acquire a fresh one, which the late remover then deletes — two writers.\n * Breakers therefore serialize on a second O_EXCL file, `<lock>.break`, and\n * under it RE-READ the lock and judge it again, removing it only if the lock\n * now at the path is itself stale. A lock acquired since the first look has a\n * live owner (or a fresh mtime) and is left alone. That judge-then-unlink is\n * safe because nothing else can change the path in between: acquirers only\n * create an ABSENT file, other breakers are excluded by `.break`, and a stale\n * owner does not release (a dead pid cannot; the cross-host/age rule is the\n * one residual — a holder slower than `staleMs` on another host).\n *\n * The `.break` file guards a few syscalls. If its owner died inside them it is\n * removed by the same liveness/age rule, without the token compare — a\n * residual that needs a crash inside that window plus two more concurrent\n * breakers.\n *\n * @module utils/file-lock\n */\n\nimport { closeSync, openSync, readFileSync, statSync, unlinkSync, writeSync } from 'node:fs';\nimport { randomBytes } from 'node:crypto';\nimport { hostname } from 'node:os';\n\n/** Tuning for {@link withFileLock}. All durations are milliseconds. */\nexport interface FileLockOptions {\n /** Give up acquiring after this long. Default 10 000. */\n readonly timeoutMs?: number | undefined;\n /** Age after which a lock whose owner cannot be checked is abandoned. Default 30 000. */\n readonly staleMs?: number | undefined;\n /** Base delay between acquisition attempts (jittered up to 2x). Default 15. */\n readonly retryMs?: number | undefined;\n /**\n * Test seam: runs after a lock is observed stale and before the break is\n * attempted — the window the ABA regression test parks a process in.\n */\n readonly onStaleObserved?: (() => void | Promise<void>) | undefined;\n}\n\nconst DEFAULT_TIMEOUT_MS = 10_000;\nconst DEFAULT_STALE_MS = 30_000;\nconst DEFAULT_RETRY_MS = 15;\n\n/** Thrown when the lock could not be acquired within `timeoutMs`. */\nexport class FileLockTimeoutError extends Error {\n constructor(\n readonly lockPath: string,\n readonly timeoutMs: number\n ) {\n super(`Timed out after ${String(timeoutMs)}ms waiting for lock ${lockPath}`);\n this.name = 'FileLockTimeoutError';\n }\n}\n\n/** What a lock file held when read. */\ninterface LockSnapshot {\n readonly token: string;\n readonly mtimeMs: number;\n}\n\nfunction errnoCode(error: unknown): string | undefined {\n if (typeof error !== 'object' || error === null) return undefined;\n const code = (error as { readonly code?: unknown }).code;\n return typeof code === 'string' ? code : undefined;\n}\n\nfunction newToken(): string {\n return `${hostname()}:${String(process.pid)}:${randomBytes(8).toString('hex')}`;\n}\n\n/** One attempt: true when this call created the lock file. */\nfunction tryCreate(lockPath: string, token: string): boolean {\n let fd: number;\n try {\n fd = openSync(lockPath, 'wx', 0o600);\n } catch (error: unknown) {\n if (errnoCode(error) === 'EEXIST') return false;\n throw error;\n }\n try {\n writeSync(fd, token);\n } finally {\n closeSync(fd);\n }\n return true;\n}\n\n/** The lock's token and mtime, or undefined when there is no lock. */\nfunction readLock(lockPath: string): LockSnapshot | undefined {\n try {\n const { mtimeMs } = statSync(lockPath);\n return { token: readFileSync(lockPath, 'utf-8'), mtimeMs };\n } catch (error: unknown) {\n if (errnoCode(error) === 'ENOENT') return undefined;\n throw error;\n }\n}\n\n/** True while `pid` is a running process (EPERM: running, owned by another user). */\nfunction isRunning(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch (error: unknown) {\n return errnoCode(error) === 'EPERM';\n }\n}\n\n/** The staleness rule in the module doc. */\nfunction isStale(lock: LockSnapshot, staleMs: number): boolean {\n const match = /^(.+):(\\d+):[0-9a-z]+$/.exec(lock.token);\n if (match?.[1] === hostname()) return !isRunning(Number(match[2]));\n return Date.now() - lock.mtimeMs > staleMs;\n}\n\n/** Remove the file only while it still carries `token`. */\nfunction removeIfOwned(path: string, token: string): void {\n if (readLock(path)?.token === token) unlinkSync(path);\n}\n\n/** Unlink, tolerating a file that is already gone. */\nfunction unlinkIfPresent(path: string): void {\n try {\n unlinkSync(path);\n } catch (error: unknown) {\n if (errnoCode(error) !== 'ENOENT') throw error;\n }\n}\n\n/**\n * Break `lockPath` if it is stale, removing only the exact lock judged stale.\n * Returns without breaking when another breaker holds `.break`; the caller\n * retries.\n */\nasync function breakIfStale(\n lockPath: string,\n staleMs: number,\n onStaleObserved: FileLockOptions['onStaleObserved']\n): Promise<void> {\n const seen = readLock(lockPath);\n if (seen === undefined || !isStale(seen, staleMs)) return;\n await onStaleObserved?.();\n\n const breakPath = `${lockPath}.break`;\n const breakToken = newToken();\n if (!tryCreate(breakPath, breakToken)) {\n const breaker = readLock(breakPath);\n if (breaker !== undefined && isStale(breaker, staleMs)) unlinkIfPresent(breakPath);\n return;\n }\n try {\n const now = readLock(lockPath);\n if (now !== undefined && isStale(now, staleMs)) {\n unlinkSync(lockPath);\n }\n } finally {\n removeIfOwned(breakPath, breakToken);\n }\n}\n\nfunction delay(ms: number): Promise<void> {\n return new Promise((resolveDelay) => setTimeout(resolveDelay, ms));\n}\n\n/**\n * Run `body` while holding the cross-process lock at `lockPath`. The directory\n * holding `lockPath` must exist.\n *\n * @throws {FileLockTimeoutError} when the lock is not acquired within\n * `timeoutMs`; `body` has not run in that case.\n */\nexport async function withFileLock<T>(\n lockPath: string,\n body: () => T | Promise<T>,\n options: FileLockOptions = {}\n): Promise<T> {\n const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const staleMs = options.staleMs ?? DEFAULT_STALE_MS;\n const retryMs = options.retryMs ?? DEFAULT_RETRY_MS;\n const token = newToken();\n const deadline = Date.now() + timeoutMs;\n while (!tryCreate(lockPath, token)) {\n await breakIfStale(lockPath, staleMs, options.onStaleObserved);\n if (Date.now() >= deadline) throw new FileLockTimeoutError(lockPath, timeoutMs);\n await delay(retryMs + Math.floor(Math.random() * retryMs));\n }\n try {\n return await body();\n } finally {\n removeIfOwned(lockPath, token);\n }\n}\n","/**\n * Persistent OutcomeStore — JSONL-backed cross-session persistence.\n *\n * Extends the in-memory OutcomeStore with disk-backed append-only\n * JSONL storage. Hydrates on construction, appends on every write.\n * Corrupt lines are skipped with a warning (graceful degradation).\n *\n * @module orchestration/outcomes/outcome-store-persistence\n * (Source: Issue #1009 — Cross-session persistence)\n */\n\nimport { appendFileSync, readFileSync, writeFileSync, existsSync } from 'node:fs';\n\nimport type { ILogger } from '../../core/index.js';\nimport { createLogger, getErrorMessage } from '../../core/index.js';\nimport { TaskOutcomeSchema } from './outcome-types.js';\nimport type { TaskOutcome } from './outcome-types.js';\nimport { OutcomeStore, registerPersistentOutcomeStoreFactory } from './outcome-store.js';\nimport type { OutcomeStoreConfig } from './outcome-store.js';\nimport { ensureLearningDir, getOutcomesFile } from '../../config/learning-persistence.js';\n\n// ============================================================================\n// Configuration\n// ============================================================================\n\n/**\n * Schema for hydrating persisted outcomes (#6538).\n *\n * Uses `.loose()` so that forward-compatible fields written by newer\n * versions (such as `routedBy`, `qualitySignals`, or future additions) are\n * retained across rewrite cycles (reclassification, purgeSkippedWorkers)\n * instead of being stripped by Zod's default unknown-key dropping.\n */\nconst PersistedOutcomeSchema = TaskOutcomeSchema.loose();\n\nexport interface PersistentOutcomeStoreConfig extends OutcomeStoreConfig {\n /** Override the file path (useful for testing). */\n readonly filePath?: string;\n /** Override the data directory (useful for testing). */\n readonly dataDir?: string;\n}\n\n// ============================================================================\n// Implementation\n// ============================================================================\n\n/**\n * OutcomeStore that persists entries to a JSONL file on disk.\n *\n * - Construction: hydrates from existing JSONL file (Zod-validates each line)\n * - Append: calls super.append() then appendFileSync one JSON line\n * - Corruption: bad lines are skipped with a warning log\n */\nexport class PersistentOutcomeStore extends OutcomeStore {\n private readonly filePath: string;\n private readonly logger: ILogger;\n\n constructor(config?: PersistentOutcomeStoreConfig, logger?: ILogger) {\n super(config);\n this.filePath = config?.filePath ?? getOutcomesFile();\n this.logger = logger ?? createLogger({ component: 'PersistentOutcomeStore' });\n\n const dataDir = config?.dataDir;\n ensureLearningDir(dataDir);\n this.hydrate();\n this.reclassifyHydrated();\n this.purgeSkippedOnHydrate();\n }\n\n /** Override append to persist each entry to disk. */\n override append(outcome: TaskOutcome): void {\n super.append(outcome);\n this.persistLine(outcome);\n }\n\n // ==========================================================================\n // Private\n // ==========================================================================\n\n /**\n * Reclassify hydrated entries that lack a failureCategory.\n * Bounded: reclassifyAll() skips success outcomes and already-classified\n * entries, so only unclassified failures are processed (#1457).\n */\n /**\n * Purge false failures from skipped workers on hydration (#1528).\n * These are 0ms non-success worker-* entries created before the\n * recording fix, representing routing decisions not real failures.\n */\n private purgeSkippedOnHydrate(): void {\n if (this.size === 0) return;\n const purged = this.purgeSkippedWorkers();\n if (purged > 0) {\n this.logger.info('Purged skipped-worker false failures from history', { purged });\n this.rewriteFile();\n }\n }\n\n private reclassifyHydrated(): void {\n if (this.size === 0) return;\n const reclassified = this.reclassifyAll();\n if (reclassified > 0) {\n this.logger.info('Reclassified hydrated outcomes with updated categories', {\n reclassified,\n });\n this.rewriteFile();\n }\n }\n\n private hydrate(): void {\n if (!existsSync(this.filePath)) {\n this.logger.debug('No outcomes file found, starting fresh', {\n path: this.filePath,\n });\n return;\n }\n\n try {\n const content = readFileSync(this.filePath, 'utf-8');\n const lines = content.split('\\n').filter((line) => line.trim().length > 0);\n let loaded = 0;\n let skipped = 0;\n\n for (const line of lines) {\n try {\n const parsed: unknown = JSON.parse(line);\n const result = PersistedOutcomeSchema.safeParse(parsed);\n if (result.success) {\n super.append(result.data);\n loaded++;\n } else {\n skipped++;\n }\n } catch (parseErr: unknown) {\n this.logger.debug('Skipping malformed outcome line during hydration', {\n error: getErrorMessage(parseErr),\n linePreview: line.slice(0, 80),\n });\n skipped++;\n }\n }\n\n this.logger.info('Hydrated outcomes from disk', {\n loaded,\n skipped,\n total: lines.length,\n path: this.filePath,\n });\n } catch (error: unknown) {\n const msg = getErrorMessage(error);\n this.logger.warn('Failed to hydrate outcomes from disk', {\n error: msg,\n path: this.filePath,\n });\n }\n }\n\n /** Rewrite the JSONL file from in-memory state after reclassification. */\n private rewriteFile(): void {\n try {\n const entries = this.query();\n const content = entries.map((e) => JSON.stringify(e)).join('\\n') + '\\n';\n writeFileSync(this.filePath, content, 'utf-8');\n } catch (error: unknown) {\n const msg = getErrorMessage(error);\n this.logger.warn('Failed to rewrite outcomes file after reclassification', {\n error: msg,\n path: this.filePath,\n });\n }\n }\n\n private persistLine(outcome: TaskOutcome): void {\n try {\n appendFileSync(this.filePath, JSON.stringify(outcome) + '\\n', 'utf-8');\n } catch (error: unknown) {\n const msg = getErrorMessage(error);\n this.logger.warn('Failed to persist outcome to disk', {\n error: msg,\n path: this.filePath,\n });\n }\n }\n}\n\n// Self-register factory so getOutcomeStore() can create PersistentOutcomeStore\n// without a circular top-level import.\nregisterPersistentOutcomeStoreFactory(() => new PersistentOutcomeStore());\n","/**\n * 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 { gatewayCostDetail } from '../../cli-adapters/budget-arm-cost.js';\nimport { computeCostDetail, priceBasisOf, type CostDetail } from '../../learning/usage-log.js';\nimport { DecisionCostStore, type DecisionGate } from '../../observability/decision-cost-store.js';\nimport type {\n DecisionBillingMode,\n DecisionCostSummary,\n UndeclaredOptionsDetectorRecord,\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. A\n * seat carrying `gatewayArm` is priced by the gateway's declaration instead\n * ({@link voteCostDetail}, #4392 step 4).\n *\n * When the model resolves WITHOUT pricing anywhere in the registry chain\n * (#4165), `costUsd` is OMITTED — tokens are kept — so the rollup counts the\n * voter as UNMEASURED (#3855: missing cost is unmeasured, never a measured $0).\n *\n * Whenever a price WAS looked up, the resulting {@link PriceBasis} rides along\n * (#4406) so the recorded figure says whether it came from a vendor list rate\n * rather than reading as contract-accurate.\n */\n/**\n * Copy only the token counters the adapter actually reported. Every field is\n * spread conditionally so an absent counter stays absent — a fabricated 0\n * would read as a measurement (#4439).\n *\n * The cache figures ride along for visibility only: cost is still priced on\n * uncached input, because the registry carries no cache-read rate and pricing\n * the cached portion at the input rate would overstate spend (#4435).\n */\nfunction reportedTokenFields(v: AgentVoteResult): Partial<VoterCostInput> {\n return {\n ...(v.inputTokens !== undefined ? { inputTokens: v.inputTokens } : {}),\n ...(v.outputTokens !== undefined ? { outputTokens: v.outputTokens } : {}),\n ...(v.cachedInputTokens !== undefined ? { cachedInputTokens: v.cachedInputTokens } : {}),\n ...(v.cacheCreationInputTokens !== undefined\n ? { cacheCreationInputTokens: v.cacheCreationInputTokens }\n : {}),\n };\n}\n\n/**\n * The seat's cost detail, or `undefined` when nothing was looked up (no usage\n * reported, or no model). A seat that answered through a gateway (#4392 step\n * 4, `gatewayArm`) is priced by the arm's `NEXUS_GATEWAY_COST` declaration —\n * UNKNOWN when undeclared — never by the model id alone: a `claude-*` id a\n * gateway served used to roll up at Anthropic's list price as `'list'`.\n */\nfunction voteCostDetail(v: AgentVoteResult): CostDetail | undefined {\n const hasTokens = v.inputTokens !== undefined || v.outputTokens !== undefined;\n if (!hasTokens || v.model === undefined) return undefined;\n const input = v.inputTokens ?? 0;\n const output = v.outputTokens ?? 0;\n if (v.gatewayArm !== undefined) return gatewayCostDetail(v.gatewayArm, v.model, input, output);\n return computeCostDetail(v.model, input, output);\n}\n\nexport function votesToCostInputs(votes: readonly AgentVoteResult[]): VoterCostInput[] {\n return votes.map((v) => {\n const detail = voteCostDetail(v);\n const input: VoterCostInput = {\n role: v.role,\n model: v.model,\n // #6115: the assignment beside the model that answered.\n ...(v.assignedCli !== undefined ? { assignedCli: v.assignedCli } : {}),\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 * The undeclared-options detector's verdict on this vote (#5422). Passed\n * through to the store on every `consensus_vote`, fired or not; omitted by\n * `pr_review`, which runs no such detector.\n */\n readonly undeclaredOptionsDetector?: UndeclaredOptionsDetectorRecord;\n}\n\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 ...(options.undeclaredOptionsDetector !== undefined\n ? { undeclaredOptionsDetector: options.undeclaredOptionsDetector }\n : {}),\n });\n if (!persisted) {\n // Count EVERY drop (stays exact); rate-limit only the warn so an unwritable\n // store can't flood the log per-decision and degrade the main path (#3916).\n droppedCostRecordCount += 1;\n if (shouldWarnForDrop(droppedCostRecordCount)) {\n const suppressedSinceLastWarn = droppedCostRecordCount - warnCountSinceReset - 1;\n warnCountSinceReset += 1;\n logger.warn('Decision-cost rollup dropped (failed to persist) — billing telemetry lost', {\n decisionId: options.decisionId,\n gate: options.gate,\n totalCostUsd: record.summary.totalCostUsd,\n totalTokens: record.summary.totalTokens,\n droppedCostRecordCount,\n suppressedSinceLastWarn,\n });\n }\n }\n return record.summary;\n}\n","/**\n * Consensus → pipeline-bus signal emitter (#3147, epic #3143 P2).\n *\n * Emits the `signal.vote_rejected` observability signal onto the typed pipeline\n * event bus when a consensus vote resolves to `rejected`, closing the\n * self-tuning loop (the shadow TuneStage consumes it). Lives at the MCP\n * integration layer ON PURPOSE: the pure `ConsensusEngine` stays decoupled from\n * the pipeline bus, preserving the `A = observability / B = messaging` boundary\n * adopted for #3289 (scope Option 2 — observability signals route through bus A,\n * the collaboration messaging bus is untouched).\n *\n * @module mcp/tools/consensus-vote-signals\n */\n\nimport { getErrorMessage, getTimeProvider } from '../../core/index.js';\nimport type { ILogger } from '../../core/index.js';\nimport type { ConsensusResult } from '../../consensus/types.js';\nimport type { IEventBus } from '../../pipeline/event-types.js';\n\n/** Distinct rejection categories across the reject votes, or undefined if none. */\nfunction rejectionRulesFrom(result: ConsensusResult): readonly string[] | undefined {\n const rules = new Set<string>();\n for (const vote of result.votes.values()) {\n if (vote.decision === 'reject' && vote.rejectionCategories !== undefined) {\n for (const category of vote.rejectionCategories) rules.add(category);\n }\n }\n return rules.size > 0 ? [...rules] : undefined;\n}\n\n/**\n * Emit `signal.vote_rejected` onto `bus` when `result.outcome === 'rejected'`.\n * No-op for any other outcome. Emission errors are swallowed and logged —\n * observability signalling must never break the vote path.\n */\nexport function emitVoteRejectedSignal(\n result: ConsensusResult,\n bus: IEventBus,\n logger: ILogger\n): void {\n if (result.outcome !== 'rejected') return;\n try {\n const rejectionRules = rejectionRulesFrom(result);\n bus.emit({\n type: 'signal.vote_rejected',\n timestamp: getTimeProvider().now(),\n proposalId: result.proposalId,\n approvalPercentage: result.approvalPercentage,\n ...(rejectionRules !== undefined ? { rejectionRules } : {}),\n });\n } catch (error) {\n logger.warn('Failed to emit signal.vote_rejected', { error: getErrorMessage(error) });\n }\n}\n","/**\n * Simulation Guard — fail-closed gate for `simulateVotes: true`.\n *\n * Simulated votes are random and exist only for unit tests and demos.\n * Outside a test runner a `simulateVotes: true` request is REJECTED unless\n * the operator explicitly opts in via `NEXUS_ALLOW_SIMULATE=1` — the field\n * is caller-supplied on the MCP input schemas, so warn-and-proceed let a\n * steered caller manufacture a governance approval from a random panel.\n * (Source: Issue #2317, #2319; fail-closed rework #4170)\n *\n * The guard NEVER throws: call sites sit inside pipeline try blocks whose\n * catch paths categorize as `internal` — a thrown denial would be\n * miscategorized. It returns a structured verdict instead.\n *\n * @module mcp/tools/simulation-guard\n */\n\nimport type { ILogger } from '../../core/index.js';\nimport { toolStructuredError, type ToolResult } from './tool-result.js';\n\nconst WARNED = new Set<string>();\n\n/** Explicit opt-in env var permitting simulated votes outside test runners (#4170). */\nconst ALLOW_SIMULATE_ENV = 'NEXUS_ALLOW_SIMULATE';\n\n/** Returns true when running under vitest or another test runner. */\nexport function isTestRunner(): boolean {\n return process.env.VITEST === 'true' || process.env.NODE_ENV === 'test';\n}\n\n/**\n * Verdict of {@link checkSimulationAllowed}. `optedIn` distinguishes the\n * test-runner path (false — nothing to surface) from the explicit\n * `NEXUS_ALLOW_SIMULATE=1` path (true — callers stamp `simulated: true`\n * on their output so a demo result can never pass as a real decision).\n */\nexport type SimulationCheckResult =\n | { readonly allowed: true; readonly optedIn: boolean }\n | { readonly allowed: false; readonly reason: string };\n\n/**\n * Decide whether a `simulateVotes: true` request may proceed (#4170):\n *\n * - test runner (VITEST/NODE_ENV) → allowed, `optedIn: false`;\n * - `NEXUS_ALLOW_SIMULATE=1` → allowed, `optedIn: true`, with the\n * one-shot RANDOM-output warning logged per (tool, process);\n * - otherwise → NOT allowed, with a reason naming the\n * opt-in env var. Never throws — see the module doc.\n */\nexport function checkSimulationAllowed(toolName: string, logger: ILogger): SimulationCheckResult {\n if (isTestRunner()) return { allowed: true, optedIn: false };\n if (process.env[ALLOW_SIMULATE_ENV] === '1') {\n warnOnce(toolName, logger);\n return { allowed: true, optedIn: true };\n }\n return {\n allowed: false,\n reason:\n `[${toolName}] simulateVotes=true is rejected outside test runners: simulated votes ` +\n `are RANDOM and must not produce real decisions (#4170). ` +\n `Set ${ALLOW_SIMULATE_ENV}=1 to explicitly opt in (demos only).`,\n };\n}\n\n/**\n * Shared denial envelope for a failed {@link checkSimulationAllowed}: the\n * three call sites (consensus_vote, run_pipeline, run_dev_pipeline) must\n * reject identically — `permission` category, detail naming the opt-in.\n */\nexport function simulationDeniedResult(reason: string): ToolResult {\n return toolStructuredError({\n errorCategory: 'permission',\n message: reason,\n detail: { optIn: `${ALLOW_SIMULATE_ENV}=1` },\n });\n}\n\n/**\n * One-shot warning per (tool, process) pair for the explicit opt-in path.\n * `simulateVotes: true` output is random; the warning keeps an opted-in demo\n * run from being silently mistaken for a real decision (#2319).\n */\nfunction warnOnce(toolName: string, logger: ILogger): void {\n if (WARNED.has(toolName)) return;\n WARNED.add(toolName);\n logger.warn(\n `[${toolName}] simulateVotes=true: output is RANDOM and reserved for tests/demos. Do not treat the result as a real decision.`\n );\n}\n\n/** Test-only: clear the warned-set so repeated tests can re-trigger the warning. */\nexport function _resetWarned(): void {\n WARNED.clear();\n}\n","/**\n * Job-result store for async-mode MCP tools (#3042, Stage 1 of #2631).\n *\n * Persists the final result of a background-dispatched MCP tool\n * invocation to `<NEXUS_DATA_DIR>/jobs/result-<jobId>.json`. Lets a\n * caller dispatch a long-running tool via `dispatch: 'async'`, receive a\n * `jobId` immediately, and poll for the result via `get_job_result`\n * (or any other reader that imports `readJobResult`).\n *\n * **Why a sidecar file (not the structured-task-state log):** Stage 1\n * deliberately doesn't extend `StructuredTaskState` — that schema change\n * is Stage 2 (#3043). Putting the result in a sidecar file lets the\n * async-mode protocol ship and be validated end-to-end before the schema\n * migration lands. Once Stage 2 ships, this store can be deprecated:\n * `query_task_state` will return the result inline and the sidecar files\n * become legacy that the next cleanup sweep can remove.\n *\n * **Why per-repo storage (`jobs` is in `PER_REPO_SUBDIRS`):** a job\n * dispatched on repo A should not be pollable on repo B. The split\n * matches `tasks/state-orch-*.jsonl` which is also per-repo.\n *\n * Status lifecycle: `pending` → (`complete` | `failed` | `cancelled`).\n * `cancelled` isn't written by Stage 1 (no `cancel_job` yet — that's\n * a follow-up under the same Stage 1 umbrella) but the type space\n * carries it so the next PR doesn't churn the schema.\n *\n * @module mcp/jobs/job-result-store\n */\n\nimport { existsSync, readdirSync, unlinkSync, writeFileSync, chmodSync, mkdirSync } from 'node:fs';\nimport { dirname } from 'node:path';\n\nimport { z } from 'zod';\n\nimport { createLogger, getTimeProvider } from '../../core/index.js';\nimport { nexusDataPath, nexusDataPathEnsure } from '../../config/nexus-data-dir.js';\nimport { resolveClassGuardMs, type OperationClassName } from '../../config/timeouts.js';\nimport { sanitizeErrorDetails } from '../../security/output-sanitizer.js';\nimport { VERSION } from '../../version.js';\nimport { readIndexEntry } from './job-idempotency.js';\nimport {\n candidateJobResultPaths,\n readJobResultAcrossCandidates,\n readJobResultFile,\n syncAlternateCandidates,\n} from './job-result-candidates.js';\n\nexport {\n candidateJobResultPaths,\n _setCandidatePathsResolverForTests,\n} from './job-result-candidates.js';\nexport { JobFailureDetailSchema, type JobFailureDetail } from './job-failure-detail.js';\nimport {\n JobFailureDetailSchema,\n type JobFailureDetail,\n validateAndSanitizeFailureDetail,\n} from './job-failure-detail.js';\n\nconst logger = createLogger({ component: 'job-result-store' });\n\n/** Lifecycle status of a job-result record. */\nexport const JobStatusSchema = z.enum(['pending', 'complete', 'failed', 'cancelled']);\nexport type JobStatus = z.infer<typeof JobStatusSchema>;\n\n/**\n * One on-disk job-result record. Versioned so future readers can\n * tell which Stage wrote it — bump on schema break.\n */\nexport const JobResultSchema = z.object({\n /** Format version. Currently `1` — bump if the shape changes. */\n v: z.literal(1),\n jobId: z.string().min(1),\n /** Tool that was invoked (e.g. `orchestrate`). */\n toolName: z.string().min(1),\n status: JobStatusSchema,\n createdAt: z.iso.datetime(),\n /** Set when the job leaves `pending` — either via `complete` or `failed` or `cancelled`. */\n completedAt: z.iso.datetime().optional(),\n /**\n * Structured payload the synchronous mode would have returned. Present\n * only when `status === 'complete'`. Shape is tool-specific — readers\n * cast to the tool's known output type after status check.\n */\n result: z.unknown().optional(),\n /**\n * Failure message when `status === 'failed'`. Cannot be paired with\n * `result` — the discriminator is `status`.\n */\n error: z.string().optional(),\n /**\n * Structured failure detail when `status === 'failed'` (#4375).\n * Holds normalized adapter, transport, and category information without\n * raw response bodies or prompt strings.\n */\n failureDetail: JobFailureDetailSchema.optional(),\n /**\n * Machine-readable reason for a `failed` record that was NOT settled by the\n * process that ran the job (#6224). `abandoned` is written only by\n * {@link pruneJobRecords}: the record was `pending` past the runaway guard\n * (so no live process could still own it) AND past the retention window, and\n * the sweep rewrote it rather than deleting it. Absent on every record the\n * job's own process wrote — `error` alone carries those failures.\n */\n errorKind: z.literal('abandoned').optional(),\n /**\n * Whether the tool's `run` callback accepts `runAsJob`'s `AbortSignal`\n * (#4972).\n *\n * `cancel_job` writes a `cancelled` record whether or not the tool can act\n * on the signal — as `cancel-job-tool.ts` says, \"a tool that IGNORES the\n * signal still runs to completion… but its record stays `cancelled`\". A\n * reader of that record could not tell the two apart, so `cancelled` claimed\n * more than was known.\n *\n * This is a STRUCTURAL fact — the callback's arity — not a behavioural one.\n * A tool may accept the signal and never await on it, so `true` means\n * \"cancellation can reach this tool\", not \"the work stopped\". Absent means\n * the writer did not report it, which is not the same as `false`.\n */\n signalAccepted: z.boolean().optional(),\n /**\n * `VERSION` of the nexus-agents process that WROTE this record (#5008) —\n * i.e. the build that ran the job, not the build that reads it back.\n *\n * `get_job_result` is itself a wrapped tool, so its `_meta['nexus-agents/build']`\n * stamp (#5056) names the READER's build. After a mid-session global install\n * the reader and the producer differ, and only the record can say which\n * build produced the payload. Each writer re-stamps on its own transition,\n * so a terminal record names the process that settled it.\n *\n * Optional so v1 records written before this field existed still parse:\n * on a SIDECAR record, absence means \"produced before this field existed\",\n * not a version of `undefined`. A record adapted from the task-state log\n * (`jobResultFromTaskState`, selected by `NEXUS_JOB_RESULT_SOURCE=task_state`)\n * NEVER carries it — that log records no producer version — so a reader\n * must consult the source (`get_job_result`'s `producerVersionSource`)\n * before reading absence as age. The value is recorded verbatim, including\n * `'dev'` — readers MUST run it through {@link isMeasuredBuildVersion}\n * before treating two stamps as comparable.\n */\n producerVersion: z.string().optional(),\n /**\n * When the job body last heartbeat — `runAsJob`'s `progress()` callback,\n * `heartbeatJob`, or a pipeline-bus event the body emitted (#6162). Present\n * once the body has heartbeat at least once and carried onto the terminal\n * record, so a settled job still says when it last moved (a wedged `failed`\n * record: the last progress before the silence). Absence means \"no heartbeat\n * recorded\", never \"no progress\" — a body that predates the callback, or one\n * that never adopted it, leaves the field off. On a long guard the reaper in\n * `run-as-job.ts` fails a body that stops heartbeating as wedged, measuring\n * silence from this stamp (or from job start when there is none).\n */\n lastProgressAt: z.iso.datetime().optional(),\n});\nexport type JobResult = z.infer<typeof JobResultSchema>;\n\n/**\n * The value `VERSION` takes when the build-time define is absent (a source\n * checkout run through tsx, or an unbundled test). Two local builds at\n * different commits both read this way.\n */\nconst UNMEASURED_BUILD_VERSION = 'dev';\n\n/**\n * Whether a recorded build version actually identifies a build (#5008).\n *\n * `false` for an absent or empty value and for `'dev'`. `'dev'` is what\n * `VERSION` reads without the build-time define, so two `'dev'` stamps say\n * nothing about whether the same code wrote them — treating that as a match\n * would be exactly the misreport the field exists to prevent. A reader that\n * compares producer to reader must gate the comparison on this.\n */\nexport function isMeasuredBuildVersion(version: string | undefined): boolean {\n return version !== undefined && version !== '' && version !== UNMEASURED_BUILD_VERSION;\n}\n\n/**\n * The operation class `runJobInBackground` guards every job body with. Spelled\n * here rather than imported from `run-as-job.ts` because that module imports\n * this one; the literal is typed against `OperationClassName` so a rename\n * there is a compile error here.\n */\nconst ASYNC_JOB_BODY_CLASS: OperationClassName = 'async-job-body';\n\n/**\n * Slack added to the resolved guard before a `pending` record is called\n * abandoned (#6224).\n *\n * The guard is a `setTimeout`, which fires no earlier than `guardMs` but later\n * under event-loop starvation, and the terminal `writeJobFailed` it triggers is\n * a synchronous JSON write. A record read in that gap is a live job that is\n * still in the guard's `finally`, not an abandoned one. 30 s covers a starved\n * loop plus the write; it is deliberately under a minute so the boundary stays\n * within the resolution operators reason about (the guard is quoted in hours).\n */\nconst ABANDONED_TERMINAL_WRITE_SLACK_MS = 30_000;\n\n/**\n * Whether a `pending` record describes work no process is still doing (#4976).\n *\n * The record is durable; the work is a detached in-process promise. If the\n * process dies mid-body no terminal writer ever runs, and `writeJobPending`\n * refuses to overwrite an existing file — so the record stays `pending`\n * forever and a caller polling `get_job_result` waits on work that no longer\n * exists.\n *\n * The anchor is objective rather than a guess: `async-job-body` is the runaway\n * guard `runAsJob` applies to every body, so a live job CANNOT still be pending\n * past it — it would have been recorded `failed` by the guard. The anchor is\n * the guard as RESOLVED for this process (`resolveClassGuardMs`, the same call\n * `runJobInBackground` makes), not the declared 3,600,000 ms base: since #6159\n * an operator may raise the guard to 7,200,000 ms via\n * `NEXUS_TIMEOUT_CLASS_ASYNC_JOB_BODY_MS` or `NEXUS_TIMEOUT_MULTIPLIER`, and\n * anchoring on the base reported a job 61 minutes into a live 2-hour body as\n * abandoned while its guard had 59 minutes left (#6224). Resolved on every\n * call, never cached, so a reader sees the environment the writer ran under.\n *\n * Reported rather than written back. The record is evidence of what was\n * observed; overwriting it on read would destroy that. This is the same\n * treatment `notVerified` gives an audit chain that verified nothing. The one\n * exception is {@link pruneJobRecords}, which rewrites an abandoned record\n * only once it is also past the retention window.\n */\nexport function isAbandonedJob(record: JobResult, nowMs: number): boolean {\n return isAbandonedAt(record, nowMs, abandonedAfterMs());\n}\n\n/**\n * Milliseconds a `pending` record may be old before no live process can own it:\n * the resolved `async-job-body` guard plus {@link ABANDONED_TERMINAL_WRITE_SLACK_MS}.\n */\nfunction abandonedAfterMs(): number {\n return resolveClassGuardMs(ASYNC_JOB_BODY_CLASS) + ABANDONED_TERMINAL_WRITE_SLACK_MS;\n}\n\n/** The predicate with the threshold already resolved — one resolution per sweep. */\nfunction isAbandonedAt(record: JobResult, nowMs: number, abandonedAfter: number): boolean {\n if (record.status !== 'pending') return false;\n // An unparseable `createdAt` yields NaN, and every NaN comparison is false —\n // so an unknown age reports \"not abandoned\" without a separate guard. That is\n // the right default: killing a job whose age cannot be read would be a guess.\n const startedMs = Date.parse(record.createdAt);\n return nowMs - startedMs > abandonedAfter;\n}\n\n/** Resolve the sidecar path for a given jobId. */\nfunction jobResultPath(jobId: string): string {\n const primary =\n candidateJobResultPaths(jobId)[0] ?? nexusDataPathEnsure('jobs', `result-${jobId}.json`);\n mkdirSync(dirname(primary), { recursive: true });\n return primary;\n}\n\n/**\n * Write a job sidecar record with 0600 perms (#3753 defense-in-depth — the\n * payload may carry job result data; restrict to the owner if NEXUS_DATA_DIR is\n * ever shared). `chmodSync` after write guarantees the mode even when overwriting\n * a pre-existing (default-umask) file, which the `writeFileSync` mode option skips.\n */\nfunction persistJobRecord(path: string, record: JobResult): void {\n writeFileSync(path, JSON.stringify(record, null, 2), { mode: 0o600 });\n chmodSync(path, 0o600);\n}\n\n/** The heartbeat a terminal writer carries forward from the record it replaces (#6162). */\nfunction carriedProgress(existing: JobResult | null): Pick<JobResult, 'lastProgressAt'> {\n return existing?.lastProgressAt !== undefined ? { lastProgressAt: existing.lastProgressAt } : {};\n}\n\n/**\n * Every writer below takes a trailing `producerVersion` defaulting to the\n * running server's `VERSION` (#5008). The parameter is the DI seam: a test\n * can write a version that differs from `VERSION` and prove the stamp\n * round-trips from the injected value rather than from an ambient constant.\n */\n\n/**\n * Write the initial `pending` record for a new job. Idempotent: if a\n * record for `jobId` already exists (e.g. operator restart re-runs the\n * same idempotencyKey — Stage 1 follow-up), this is a no-op.\n *\n * Caller responsibility: generate a fresh `jobId` per call (Stage 1\n * doesn't yet deduplicate via idempotencyKey — that's #3042 follow-up).\n */\nexport function writeJobPending(\n jobId: string,\n toolName: string,\n signalAccepted?: boolean,\n producerVersion: string = VERSION\n): void {\n const path = jobResultPath(jobId);\n if (existsSync(path) || readJobResult(jobId) !== null) {\n logger.debug('Job result file already exists — leaving in place', { jobId });\n return;\n }\n const record: JobResult = {\n v: 1,\n jobId,\n toolName,\n status: 'pending',\n createdAt: new Date().toISOString(),\n ...(signalAccepted !== undefined ? { signalAccepted } : {}),\n producerVersion,\n };\n persistJobRecord(path, record);\n logger.debug('Wrote pending job record', { jobId, toolName, signalAccepted });\n}\n\n/**\n * Replace the record with a terminal `complete` status carrying the\n * structured payload. Caller writes the SAME shape the sync mode would\n * have returned, so a polling client can use the result interchangeably.\n *\n * COMPLETE-AFTER-CANCEL guard (#4017): if the job was already `cancelled`\n * (e.g. `cancel_job` landed while the work was in-flight — `runAsJob` does not\n * yet abort the underlying work), this is a NO-OP so the cancellation is not\n * silently rewritten back to `complete`. Symmetric with the caller-side\n * cancel-after-complete guard documented on {@link writeJobCancelled}.\n */\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 ...carriedProgress(existing),\n };\n const primaryPath = jobResultPath(jobId);\n persistJobRecord(primaryPath, record);\n syncAlternateCandidates(jobId, primaryPath, record, logger, persistJobRecord);\n logger.debug('Wrote complete job record', { jobId, toolName });\n}\n\n/**\n * Terminal `failed` status. `error` is the human-readable failure message.\n * Like {@link writeJobComplete}, a NO-OP when the job is already `cancelled`\n * (#4017) so a post-cancel failure cannot rewrite the cancellation.\n *\n * Write-path redaction (#4375): sanitizes `error` and any string fields in\n * `failureDetail` via {@link sanitizeErrorDetails} before persisting to disk.\n */\nexport function writeJobFailed(\n jobId: string,\n toolName: string,\n error: string,\n producerVersion: string = VERSION,\n failureDetail?: JobFailureDetail\n): void {\n const existing = readJobResult(jobId);\n if (existing?.status === 'cancelled') {\n logger.debug('Skipping failed write — job already cancelled (preserving cancellation)', {\n jobId,\n toolName,\n });\n return;\n }\n const sanitizedError = sanitizeErrorDetails(error);\n const validatedDetail = validateAndSanitizeFailureDetail(failureDetail);\n\n const record: JobResult = {\n v: 1,\n jobId,\n toolName,\n status: 'failed',\n createdAt: existing?.createdAt ?? new Date().toISOString(),\n completedAt: new Date().toISOString(),\n error: sanitizedError,\n ...(validatedDetail !== undefined ? { failureDetail: validatedDetail } : {}),\n producerVersion,\n ...carriedProgress(existing),\n };\n const primaryPath = jobResultPath(jobId);\n persistJobRecord(primaryPath, record);\n syncAlternateCandidates(jobId, primaryPath, record, logger, persistJobRecord);\n logger.debug('Wrote failed job record', { jobId, toolName, error: sanitizedError });\n}\n\n/**\n * Heartbeat `jobId` (#6162): stamp `lastProgressAt` on its `pending` record,\n * at `at` (an ISO instant; defaults to the time provider's now). The heartbeat\n * half of the liveness contract: `runAsJob`'s `progress()` callback is this,\n * and a job body that holds its `jobId` but not the callback — the arity-0/1\n * adopters, which cannot declare the fourth `run` parameter without also\n * claiming the third (`signalAccepted` is derived from `run.length`, #4972) —\n * calls it directly. Either way a poller reading `pending` can tell slow from\n * stuck, and the liveness watchdog in `run-as-job.ts` measures silence from\n * the same stamp — the record is the one source of truth for \"last progress\".\n *\n * A no-op unless the record exists AND is `pending`. A heartbeat that lands\n * after `cancel_job`, after the runaway guard, or after the body settled must\n * not resurrect a terminal record; and an unknown jobId is not created — the\n * stamp decorates a dispatch, it does not constitute one. Every other field of\n * the record is carried verbatim, including the producer's version.\n */\nexport function heartbeatJob(\n jobId: string,\n at: string = new Date(getTimeProvider().now()).toISOString()\n): void {\n persistProgressStamp(jobId, at);\n}\n\n/**\n * Epoch ms of the recorded heartbeat, or `undefined` when the record has none\n * or cannot be read (#6162). The liveness reaper measures silence from this —\n * the record is the single source of truth for \"last progress\", for the\n * reaper and for every reader alike — falling back to job start on\n * `undefined`. An unparseable stamp is `undefined`, not `NaN`: a silence that\n * cannot be measured must not read as any particular length.\n */\nexport function readLastProgressMs(jobId: string): number | undefined {\n const at = readJobResult(jobId)?.lastProgressAt;\n if (at === undefined) return undefined;\n const ms = Date.parse(at);\n return Number.isNaN(ms) ? undefined : ms;\n}\n\nfunction persistProgressStamp(jobId: string, at: string): void {\n const existing = readJobResult(jobId);\n if (existing?.status !== 'pending') {\n logger.debug('Skipping progress stamp — job is not pending', {\n jobId,\n status: existing?.status ?? 'unknown',\n });\n return;\n }\n const updated: JobResult = { ...existing, lastProgressAt: at };\n const primaryPath = jobResultPath(jobId);\n persistJobRecord(primaryPath, updated);\n syncAlternateCandidates(jobId, primaryPath, updated, logger, persistJobRecord);\n}\n\n/**\n * Terminal `cancelled` status — set by `cancel_job` (#3042 Stage 1b).\n *\n * Idempotent-by-design at the in-memory state level: if the record is\n * already `complete` / `failed` / `cancelled`, `cancel_job` reports\n * `already_complete` / `already_cancelled` to the caller and DOES NOT\n * overwrite the terminal record (per the #3041 vote Security flag —\n * cancel-after-complete must not rewrite history).\n *\n * The caller (cancel_job tool) checks the current status BEFORE calling\n * this; this writer trusts the caller and always overwrites. Guarding\n * here too would duplicate the guard but is cheap insurance — current\n * design: caller-side guard only.\n */\nexport function writeJobCancelled(\n jobId: string,\n toolName: string,\n reason?: string,\n producerVersion: string = VERSION\n): void {\n const existing = readJobResult(jobId);\n const sanitizedReason = reason !== undefined ? sanitizeErrorDetails(reason) : undefined;\n const record: JobResult = {\n v: 1,\n jobId,\n toolName,\n status: 'cancelled',\n createdAt: existing?.createdAt ?? new Date().toISOString(),\n completedAt: new Date().toISOString(),\n ...(sanitizedReason !== undefined ? { error: sanitizedReason } : {}),\n producerVersion,\n ...carriedProgress(existing),\n };\n const primaryPath = jobResultPath(jobId);\n persistJobRecord(primaryPath, record);\n syncAlternateCandidates(jobId, primaryPath, record, logger, persistJobRecord);\n logger.debug('Wrote cancelled job record', { jobId, toolName, reason: sanitizedReason });\n}\n\n/**\n * Read a job-result record across candidate data directories (#5472).\n * Returns `null` if the jobId is unknown (no candidate file exists) or\n * unreadable (corrupt JSON, schema mismatch).\n *\n * Checks all candidate paths (primary and shared). If multiple valid records\n * exist, terminal status outranks pending, cancellations are preserved (#4017),\n * and later timestamps break ties.\n *\n * Schema mismatch is treated as \"not found\" not \"error\" so a client\n * polling against a future-Stage record from an older nexus-agents\n * process doesn't crash — the request just looks like an unknown jobId\n * until the operator upgrades.\n */\nexport function readJobResult(jobId: string): JobResult | null {\n return readJobResultAcrossCandidates(jobId, logger);\n}\n\n/**\n * List job records under `<NEXUS_DATA_DIR>/jobs/` (#3046 Stage 5).\n *\n * Returns ALL records sorted by `createdAt` descending (newest first).\n * Caller filters by `toolName` / `status` via the `list_jobs` MCP tool —\n * we don't push the filter logic in here because tools change shape but\n * the store doesn't.\n *\n * **The result payloads are intentionally EXCLUDED** from each summary\n * — large complete-status records can be 1 MiB each (per Stage 2's\n * TASK_RESULT_MAX_BYTES cap), and `list_jobs` is meant for discovery,\n * not retrieval. Callers re-fetch full records via `get_job_result(jobId)`.\n *\n * Schema-mismatch + unreadable files are silently dropped (logged as\n * warnings), same policy as `readJobResult`.\n */\nexport interface JobSummary {\n readonly jobId: string;\n readonly toolName: string;\n readonly status: JobResult['status'];\n readonly createdAt: string;\n readonly completedAt?: string;\n /** True iff the record carries an error message (status === 'failed'). */\n readonly hasError: boolean;\n /** Last heartbeat from the job body (#6162); absent when none was recorded. */\n readonly lastProgressAt?: string;\n}\n\n/** Project a full {@link JobResult} down to its {@link JobSummary} — shared by\n * the sidecar walk here and the task-state list source (#3693). */\nexport function toJobSummary(record: JobResult): JobSummary {\n return {\n jobId: record.jobId,\n toolName: record.toolName,\n status: record.status,\n createdAt: record.createdAt,\n hasError: record.error !== undefined,\n ...(record.completedAt !== undefined ? { completedAt: record.completedAt } : {}),\n ...(record.lastProgressAt !== undefined ? { lastProgressAt: record.lastProgressAt } : {}),\n };\n}\n\n/**\n * What a job listing could NOT read (#6038).\n *\n * `listJobs` returned a bare array, so two very different worlds produced `[]`:\n * \"there are no jobs\" and \"the jobs directory would not open\". And a sidecar\n * that failed `JobResultSchema` — a record written by a newer nexus-agents, or\n * half-written by a concurrent job — was skipped by deliberate policy in\n * `readJobResult` and then left no trace at all. `list_jobs` reported\n * `{\"count\":0,\"truncated\":false}` over both, and an operator or the autonomous\n * loop concludes nothing is pending and re-dispatches work already running.\n */\ninterface JobListDiagnostics {\n /** True when the jobs directory exists but could not be enumerated. */\n readonly dirUnreadable: boolean;\n /** Sidecar files that matched the naming pattern but failed to parse or validate. */\n readonly unparseableRecords: number;\n}\n\n/** Job summaries plus what the listing could not read. */\nexport interface JobListing {\n readonly jobs: JobSummary[];\n readonly diagnostics: JobListDiagnostics;\n}\n\nexport function listJobs(): JobSummary[] {\n return listJobsWithDiagnostics().jobs;\n}\n\n/** List jobs AND report what the listing could not read (#6038). */\nexport function listJobsWithDiagnostics(): JobListing {\n const dir = nexusDataPath('jobs');\n // An ABSENT directory is a measured absence: no jobs have ever been written.\n // That is different from a directory that exists and will not open.\n if (!existsSync(dir)) {\n return { jobs: [], diagnostics: { dirUnreadable: false, unparseableRecords: 0 } };\n }\n let entries: string[];\n try {\n entries = readdirSync(dir);\n } catch (err) {\n logger.warn('jobs directory unreadable', {\n dir,\n error: err instanceof Error ? err.message : String(err),\n });\n return { jobs: [], diagnostics: { dirUnreadable: true, unparseableRecords: 0 } };\n }\n const summaries: JobSummary[] = [];\n let unparseableRecords = 0;\n for (const entry of entries) {\n const match = /^result-(.+)\\.json$/.exec(entry);\n if (match === null) continue;\n const jobId = match[1];\n if (jobId === undefined) continue;\n const record = readJobResult(jobId);\n if (record === null) {\n unparseableRecords += 1;\n continue;\n }\n summaries.push(toJobSummary(record));\n }\n // Newest first — matches typical \"what just happened\" discovery flow.\n return {\n jobs: summaries.sort((a, b) => b.createdAt.localeCompare(a.createdAt)),\n diagnostics: { dirUnreadable: false, unparseableRecords },\n };\n}\n\n// ---------------------------------------------------------------------------\n// Retention (#6224, #4976 gap 2)\n// ---------------------------------------------------------------------------\n\n/**\n * How long a job record is kept after it settles.\n *\n * Seven days. The record is the only durable evidence an async tool ran, so\n * the window trades disk against auditability (#4976 asked for a decision\n * rather than a guess): a week covers the weekly end-to-end validation cadence\n * (CLAUDE.md, \"Periodic end-to-end validation\"), which is the longest-lived\n * reader of a job's result, and on the machine measured in #6224, 198 of 303\n * records were older than three days — a window of days, not hours, is what\n * bounds the store. The audit chain next door is kept forever on purpose; job\n * results are not the audit chain. A constant, not an env var: no consumer has\n * asked to tune it, and a knob nobody reads is the shape #2977 removed.\n */\nexport const JOB_RECORD_RETENTION_MS = 7 * 24 * 60 * 60 * 1000;\n\n/**\n * Minimum gap between two sweeps run from `runAsJob` in one process. A sweep\n * enumerates and parses every record, so running it on every dispatch would\n * put a directory walk on the async hot path; once an hour bounds that to the\n * scale of the guard itself.\n */\nconst JOB_PRUNE_SWEEP_INTERVAL_MS = 3_600_000;\n\n/** What one retention sweep did — or, with `dryRun`, would have done. */\nexport interface JobPruneCounts {\n /** Terminal records older than the window, removed. */\n readonly deleted: number;\n /** `pending` records past the guard AND the window, rewritten as `failed`. */\n readonly markedAbandoned: number;\n /** Records inside the window, or `pending` records the guard still covers. */\n readonly kept: number;\n /** Record or key files that would not parse — counted, never touched. */\n readonly unreadable: number;\n /**\n * Idempotency index entries (`key-*.json`, `job-idempotency.ts`) older than\n * the window whose job record no longer exists, removed. Counted apart from\n * `deleted` because they are not records: a key that outlives its record\n * would replay a jobId `get_job_result` cannot find, and the caller could\n * never dispatch under that key again.\n */\n readonly deletedKeys: number;\n}\n\ninterface PruneJobRecordsOptions {\n /** The sweep's notion of now, in epoch milliseconds. */\n readonly nowMs: number;\n /** Retention window in milliseconds; {@link JOB_RECORD_RETENTION_MS} in production. */\n readonly retentionMs: number;\n /** Count what would change and change nothing. */\n readonly dryRun?: boolean;\n}\n\n/**\n * Sweep `<NEXUS_DATA_DIR>/jobs/` (#6224, closing #4976 gap 2).\n *\n * Rules, in the order they are tested:\n *\n * - A terminal record (`complete` / `failed` / `cancelled`) whose `completedAt`\n * — `createdAt` when a legacy record has none — is older than `retentionMs`\n * is deleted. \"Older than\" is strict: a record exactly at the window is kept.\n * - A `pending` record that is abandoned ({@link isAbandonedJob}: older than the\n * resolved guard, so no live process can own it) AND older than the window is\n * rewritten as `failed` with `errorKind: 'abandoned'`. Never deleted: the\n * record is the only evidence the dispatch happened. This is the ONE path\n * that writes an abandoned verdict back; `get_job_result` keeps reporting it.\n * A `pending` record younger than either bound is kept — the guard may still\n * settle it, or a poller may still need to see it `pending`.\n * - A file matching `result-*.json` or `key-*.json` that fails to parse or\n * validate is counted as `unreadable` and left in place. It may have been\n * written by a newer build, or be mid-write by a concurrent job; deleting on\n * \"could not read\" would turn a parse error into data loss.\n * - An idempotency key entry (`key-*.json`) older than the window whose job\n * record is absent — deleted by this sweep or never written — is removed\n * AFTER the records pass, so a key and its record leave together. A key\n * inside the window is kept even without a record: it is registered right\n * after the pending write, so a young dangling key may be mid-dispatch.\n *\n * The guard is resolved ONCE per sweep, not once per record.\n *\n * Empty case: an absent or empty jobs directory returns all-zero counts. A\n * directory that exists but cannot be enumerated THROWS — reporting zeros\n * there would present \"could not look\" as \"nothing to do\".\n */\nexport function pruneJobRecords(options: PruneJobRecordsOptions): JobPruneCounts {\n const dir = nexusDataPath('jobs');\n if (!existsSync(dir)) {\n return { deleted: 0, markedAbandoned: 0, kept: 0, unreadable: 0, deletedKeys: 0 };\n }\n // Deliberately not wrapped: an unreadable directory is the caller's problem\n // to report, not a zero.\n const entries = readdirSync(dir);\n const sweep: SweepContext = {\n nowMs: options.nowMs,\n retentionMs: options.retentionMs,\n dryRun: options.dryRun === true,\n abandonedAfter: abandonedAfterMs(),\n };\n const counts = { deleted: 0, markedAbandoned: 0, kept: 0, unreadable: 0, deletedKeys: 0 };\n /** Records this pass deleted (or, dry-run, would have) — keys check against it. */\n const removedJobIds = new Set<string>();\n const keyEntries = entries.filter((entry) => /^key-.+\\.json$/.test(entry));\n for (const entry of entries) {\n const jobId = /^result-(.+)\\.json$/.exec(entry)?.[1];\n if (jobId === undefined) continue;\n const verdict = sweepRecord(jobId, entry, sweep);\n counts[verdict] += 1;\n if (verdict === 'deleted') removedJobIds.add(jobId);\n }\n for (const entry of keyEntries) {\n const verdict = sweepKeyEntry(entry, removedJobIds, sweep);\n if (verdict !== null) counts[verdict] += 1;\n }\n logger.debug('Job record sweep', { dir, ...counts, dryRun: sweep.dryRun });\n return counts;\n}\n\n/** One sweep's inputs, resolved once and threaded through every verdict. */\ninterface SweepContext {\n readonly nowMs: number;\n readonly retentionMs: number;\n readonly dryRun: boolean;\n /** {@link abandonedAfterMs}, resolved once per sweep. */\n readonly abandonedAfter: number;\n}\n\n/** What the sweep did with one record — each maps to a {@link JobPruneCounts} key. */\ntype RecordVerdict = 'deleted' | 'markedAbandoned' | 'kept' | 'unreadable';\n\n/** Apply the record rules to one `result-*.json` entry and report which fired. */\nfunction sweepRecord(jobId: string, entry: string, sweep: SweepContext): RecordVerdict {\n const path = nexusDataPath('jobs', entry);\n const fileRecord = readJobResultFile(path, jobId, logger);\n if (fileRecord === null) return 'unreadable';\n const record = readJobResult(jobId) ?? fileRecord;\n if (record.status === 'pending') {\n const pastGuard = isAbandonedAt(record, sweep.nowMs, sweep.abandonedAfter);\n const pastWindow = isOlderThan(record.createdAt, sweep.nowMs, sweep.retentionMs);\n if (!(pastGuard && pastWindow)) return 'kept';\n if (!sweep.dryRun) persistJobRecord(path, abandonedRecord(record, sweep.nowMs));\n return 'markedAbandoned';\n }\n const settledAt = record.completedAt ?? record.createdAt;\n if (!isOlderThan(settledAt, sweep.nowMs, sweep.retentionMs)) return 'kept';\n if (!sweep.dryRun) unlinkSync(path);\n return 'deleted';\n}\n\n/**\n * Apply the key rule to one `key-*.json` entry: `deletedKeys` when it is past\n * the window and its record is gone, `unreadable` when it will not parse, and\n * `null` (no count — keys are not records, so they are never \"kept\") otherwise.\n */\nfunction sweepKeyEntry(\n entry: string,\n removedJobIds: ReadonlySet<string>,\n sweep: SweepContext\n): 'deletedKeys' | 'unreadable' | null {\n const path = nexusDataPath('jobs', entry);\n const indexEntry = readIndexEntry(path);\n if (indexEntry === null) return 'unreadable';\n if (!isOlderThan(indexEntry.createdAt, sweep.nowMs, sweep.retentionMs)) return null;\n const recordGone =\n removedJobIds.has(indexEntry.jobId) ||\n !candidateJobResultPaths(indexEntry.jobId).some((p) => existsSync(p));\n if (!recordGone) return null;\n if (!sweep.dryRun) unlinkSync(path);\n return 'deletedKeys';\n}\n\n/**\n * Strictly older than `windowMs`. An unparseable timestamp yields NaN, and a\n * NaN comparison is false — an age that cannot be read is never \"old enough\".\n */\nfunction isOlderThan(isoTimestamp: string, nowMs: number, windowMs: number): boolean {\n return nowMs - Date.parse(isoTimestamp) > windowMs;\n}\n\n/**\n * The `failed` rewrite of an abandoned `pending` record. Every field of the\n * original survives (`createdAt`, `signalAccepted`, the tool); the original\n * producer's version moves into the message because `producerVersion` names\n * the writer that settled the record, and that is now the sweep.\n */\nfunction abandonedRecord(record: JobResult, nowMs: number): JobResult {\n const producer = record.producerVersion ?? 'unrecorded';\n return {\n ...record,\n status: 'failed',\n completedAt: new Date(nowMs).toISOString(),\n error:\n `abandoned: pending since ${record.createdAt} under producer ${producer}; ` +\n 'no process settled it within the runaway guard, and the retention sweep ' +\n 'marked it failed rather than deleting the evidence',\n errorKind: 'abandoned',\n producerVersion: VERSION,\n };\n}\n\n/**\n * Epoch ms of the last sweep this process ran, per jobs directory. Keyed by\n * directory rather than a single timestamp because `NEXUS_DATA_DIR` routes\n * per-repo state (#2872), so one process can serve more than one jobs\n * directory and each deserves its own hourly sweep. Bounded by the number of\n * distinct data dirs a process touches.\n */\nconst lastSweepAtMsByDir = new Map<string, number>();\n\n/**\n * Run {@link pruneJobRecords} with the production window if at least\n * {@link JOB_PRUNE_SWEEP_INTERVAL_MS} has passed since this process last swept\n * the current jobs directory (#6224). Called by `runAsJob` before every\n * pending write.\n *\n * A sweep that throws is logged and swallowed: retention must never block a\n * dispatch. The timestamp is taken BEFORE the sweep so a directory that keeps\n * failing is retried once an hour, not on every call.\n *\n * @returns The counts when a sweep ran, `null` when one was not due or failed.\n */\nexport function pruneJobRecordsIfDue(nowMs: number): JobPruneCounts | null {\n const dir = nexusDataPath('jobs');\n const lastSweepAtMs = lastSweepAtMsByDir.get(dir);\n if (lastSweepAtMs !== undefined && nowMs - lastSweepAtMs < JOB_PRUNE_SWEEP_INTERVAL_MS) {\n return null;\n }\n lastSweepAtMsByDir.set(dir, nowMs);\n try {\n return pruneJobRecords({ nowMs, retentionMs: JOB_RECORD_RETENTION_MS });\n } catch (err) {\n logger.warn('Job record sweep failed', {\n error: err instanceof Error ? err.message : String(err),\n });\n return null;\n }\n}\n","/**\n * Idempotency-key resolution for async-mode MCP tool dispatch (#3042 Stage 1c,\n * epic #2631). Lets a caller pass `idempotencyKey: \"<string>\"` and re-invoke\n * the same logical operation safely across sessions / process restarts.\n *\n * ## Contract\n *\n * - Key + matching inputs → returns the existing job's record (whatever\n * state — pending / complete / failed / cancelled). Caller polls\n * `get_job_result(jobId)` exactly as if it had dispatched fresh.\n * - Key + DIFFERENT inputs → fails closed with `idempotency_key_collision`.\n * Reusing a key with different inputs is almost certainly a caller bug;\n * silent merge would either hide a typo or leak the first call's result\n * into a second logical operation.\n * - No key → caller falls back to a fresh `randomUUID()` jobId (existing\n * behavior; this module is a no-op).\n *\n * ## Storage shape\n *\n * One file per (tool, key) tuple at:\n * `<NEXUS_DATA_DIR>/jobs/key-<sha256(tool + ':' + key)>.json`\n *\n * Record: `{ v: 1, tool, key, inputsHash, jobId, createdAt }`.\n *\n * Sharded by `(tool, key)` so two different tools using the same human key\n * don't collide. The filename is the hash so an attacker who reads the\n * directory listing can't recover the user-supplied key.\n *\n * @module mcp/jobs/job-idempotency\n */\n\nimport { createHash, randomUUID } from 'node:crypto';\nimport { existsSync, readFileSync, writeFileSync } from 'node:fs';\n\nimport { z } from 'zod';\n\nimport { createLogger } from '../../core/index.js';\nimport { nexusDataPath, nexusDataPathEnsure } from '../../config/nexus-data-dir.js';\n\nconst logger = createLogger({ component: 'job-idempotency' });\n\n/** Index-file record persisted per (tool, key). */\nexport const IdempotencyIndexEntrySchema = z.object({\n v: z.literal(1),\n /** MCP tool name (e.g. `orchestrate`, `run_workflow`, `consensus_vote`). */\n tool: z.string().min(1),\n /** Caller-supplied idempotency key. */\n key: z.string().min(1),\n /** sha256 of the canonical input JSON. */\n inputsHash: z.string().length(64),\n /** Existing jobId for this (tool, key, inputs) tuple. */\n jobId: z.string().min(1),\n /** ISO timestamp of first dispatch. */\n createdAt: z.iso.datetime(),\n});\nexport type IdempotencyIndexEntry = z.infer<typeof IdempotencyIndexEntrySchema>;\n\n/** Outcome of `resolveIdempotency` — discriminated by `kind`. */\nexport type IdempotencyResolution =\n | { readonly kind: 'fresh'; readonly jobId: string }\n | { readonly kind: 'replay'; readonly jobId: string; readonly entry: IdempotencyIndexEntry }\n | {\n readonly kind: 'collision';\n readonly existingInputsHash: string;\n readonly incomingInputsHash: string;\n readonly existingJobId: string;\n };\n\n/** sha256 hex of a string. */\nfunction sha256Hex(input: string): string {\n return createHash('sha256').update(input).digest('hex');\n}\n\n/**\n * Canonical JSON serialization for input hashing. Sorts object keys\n * recursively so `{a:1,b:2}` and `{b:2,a:1}` produce identical hashes.\n *\n * `undefined` values are dropped (JSON semantics); function values throw\n * — schema validation should have caught those upstream.\n */\nfunction canonicalJsonStringify(value: unknown): string {\n if (value === null || typeof value !== 'object') return JSON.stringify(value);\n if (Array.isArray(value)) return `[${value.map(canonicalJsonStringify).join(',')}]`;\n const entries = Object.entries(value as Record<string, unknown>)\n .filter(([, v]) => v !== undefined)\n .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0));\n return `{${entries.map(([k, v]) => `${JSON.stringify(k)}:${canonicalJsonStringify(v)}`).join(',')}}`;\n}\n\n/** Compute the inputs hash used to detect (tool, key) collisions. */\nexport function computeInputsHash(inputs: unknown): string {\n return sha256Hex(canonicalJsonStringify(inputs));\n}\n\n/** Compute the on-disk index path for a (tool, key) tuple. */\nfunction indexFilePath(tool: string, key: string): string {\n // Filename is hashed so a directory listing doesn't leak user keys.\n const filename = `key-${sha256Hex(`${tool}:${key}`)}.json`;\n return nexusDataPathEnsure('jobs', filename);\n}\n\n/** Read-only counterpart that doesn't create the parent directory. */\nfunction indexFilePathReadOnly(tool: string, key: string): string {\n const filename = `key-${sha256Hex(`${tool}:${key}`)}.json`;\n return nexusDataPath('jobs', filename);\n}\n\n/**\n * Resolve a dispatch request to one of three outcomes:\n *\n * - `fresh`: no prior index entry — caller dispatches a new job using the\n * returned `jobId`, then calls `registerIdempotentJob` to record the\n * index entry. The `jobId` is derived deterministically from\n * `(tool, key, inputsHash)` so concurrent dispatches with the same key\n * converge on the same id and don't double-dispatch.\n * - `replay`: an existing entry has the SAME `inputsHash` — caller skips\n * dispatch and returns the existing job's record (via `readJobResult`).\n * - `collision`: an existing entry has a DIFFERENT `inputsHash` — caller\n * fails closed. Reusing a key with different inputs is a programmer\n * error; silent merge would hide bugs.\n *\n * Callers should NOT call `registerIdempotentJob` when this returns\n * `replay` or `collision` — only on `fresh`.\n */\nexport function resolveIdempotency(\n tool: string,\n idempotencyKey: string | undefined,\n inputs: unknown,\n randomFallback: () => string = randomUUID\n): IdempotencyResolution {\n if (idempotencyKey === undefined || idempotencyKey === '') {\n return { kind: 'fresh', jobId: randomFallback() };\n }\n const incomingInputsHash = computeInputsHash(inputs);\n const path = indexFilePathReadOnly(tool, idempotencyKey);\n if (existsSync(path)) {\n const entry = readIndexEntry(path);\n if (entry !== null) {\n if (entry.inputsHash === incomingInputsHash) {\n return { kind: 'replay', jobId: entry.jobId, entry };\n }\n return {\n kind: 'collision',\n existingInputsHash: entry.inputsHash,\n incomingInputsHash,\n existingJobId: entry.jobId,\n };\n }\n // Index file present but unreadable — treat as fresh, log the breach.\n logger.warn('Idempotency index file unreadable; treating as fresh dispatch', { tool, path });\n }\n // Derive jobId deterministically so two concurrent requests with the\n // same (tool, key, inputs) converge on a single id even if both miss\n // the index lookup race.\n const jobId = `job-${tool}-${sha256Hex(`${tool}:${idempotencyKey}:${incomingInputsHash}`).slice(0, 16)}`;\n return { kind: 'fresh', jobId };\n}\n\n/**\n * Persist the index entry after a `fresh` dispatch. Idempotent — if the\n * file already exists (e.g. a concurrent dispatch raced ahead), the\n * existing entry stays in place. Safe to call without checking\n * `existsSync` first.\n */\nexport function registerIdempotentJob(params: {\n tool: string;\n idempotencyKey: string;\n inputs: unknown;\n jobId: string;\n}): void {\n const path = indexFilePath(params.tool, params.idempotencyKey);\n if (existsSync(path)) {\n logger.debug('Idempotency index entry already present; skipping write', {\n tool: params.tool,\n jobId: params.jobId,\n });\n return;\n }\n const entry: IdempotencyIndexEntry = {\n v: 1,\n tool: params.tool,\n key: params.idempotencyKey,\n inputsHash: computeInputsHash(params.inputs),\n jobId: params.jobId,\n createdAt: new Date().toISOString(),\n };\n writeFileSync(path, JSON.stringify(entry, null, 2));\n logger.debug('Wrote idempotency index entry', { tool: params.tool, jobId: params.jobId });\n}\n\n/**\n * Discriminated outcome of `shortCircuitOrFreshJobId` — `continue` means\n * the caller proceeds with dispatch on `jobId`; `shortCircuit` means the\n * caller returns the envelope `value` immediately and skips dispatch.\n */\nexport type ShortCircuitOutcome<TEnvelope> =\n | { readonly kind: 'continue'; readonly jobId: string }\n | { readonly kind: 'shortCircuit'; readonly value: TEnvelope };\n\n/**\n * One-call wrapper around `resolveIdempotency` that lets each dispatch\n * helper stay under the 50-line cap while keeping the shape of the\n * resulting envelope (toolSuccess / toolStructuredError / errorResponse)\n * tool-specific.\n *\n * Caller supplies:\n * - `replayEnvelope(jobId)` — wraps the per-tool \"replay\" envelope. Most\n * tools return a `{ status: 'replay', jobId, pollTool, note }` JSON\n * string via `toolSuccess`.\n * - `collisionEnvelope(existingJobId)` — wraps the error envelope when\n * the same key was reused with different inputs.\n *\n * On `continue`, the caller MUST call `registerIdempotentJob` after\n * writing the pending record so subsequent replays converge.\n */\nexport function shortCircuitOrFreshJobId<TEnvelope>(params: {\n tool: string;\n idempotencyKey: string | undefined;\n inputs: unknown;\n freshJobId: () => string;\n replayEnvelope: (jobId: string) => TEnvelope;\n collisionEnvelope: (existingJobId: string) => TEnvelope;\n}): ShortCircuitOutcome<TEnvelope> {\n const r = resolveIdempotency(\n params.tool,\n params.idempotencyKey,\n params.inputs,\n params.freshJobId\n );\n if (r.kind === 'collision') {\n return { kind: 'shortCircuit', value: params.collisionEnvelope(r.existingJobId) };\n }\n if (r.kind === 'replay') {\n return { kind: 'shortCircuit', value: params.replayEnvelope(r.jobId) };\n }\n return { kind: 'continue', jobId: r.jobId };\n}\n\n/**\n * Read + schema-validate an index file. Returns `null` on miss / corruption.\n * Exported for the retention sweep in `job-result-store.ts` (#6224), which\n * must read an entry to learn which job it points at before dropping it.\n */\nexport function readIndexEntry(path: string): IdempotencyIndexEntry | null {\n try {\n const raw = JSON.parse(readFileSync(path, 'utf-8')) as unknown;\n const parsed = IdempotencyIndexEntrySchema.safeParse(raw);\n if (!parsed.success) {\n logger.warn('Idempotency index file failed schema check', { path });\n return null;\n }\n return parsed.data;\n } catch (err) {\n logger.warn('Idempotency index file read failed', {\n path,\n error: err instanceof Error ? err.message : String(err),\n });\n return null;\n }\n}\n","/**\n * Candidate job-result resolution across data directories (#5472).\n *\n * When an MCP server starts, `activeWorkspaceRoot` is initially unset until\n * the client completes its `roots/list` handshake. Jobs dispatched during\n * this window land in `~/.nexus-agents/jobs/` (`nexusSharedPath`), while jobs\n * settled after root discovery land in `<repo>/.nexus-agents/jobs/` (`nexusDataPath`).\n *\n * This module resolves candidate paths, ranks records so terminal status\n * outranks stale pending records, and propagates updates across directories.\n *\n * @module mcp/jobs/job-result-candidates\n */\n\nimport { existsSync, readFileSync } from 'node:fs';\nimport { join } from 'node:path';\n\nimport { nexusDataPath, nexusSharedPath } from '../../config/nexus-data-dir.js';\nimport { findRepoRoot } from '../../config/repo-root-detection.js';\nimport type { ILogger } from '../../core/index.js';\nimport { JobResultSchema, type JobResult } from './job-result-store.js';\n\ntype CandidatePathsResolver = (jobId: string) => readonly string[] | undefined;\nlet candidatePathsResolverForTests: CandidatePathsResolver | undefined;\n\n/** Test helper — override candidate paths resolution for tests. */\nexport function _setCandidatePathsResolverForTests(\n resolver: CandidatePathsResolver | undefined\n): void {\n candidatePathsResolverForTests = resolver;\n}\n\nfunction getExplicitDataDir(): string | undefined {\n const env = process.env['NEXUS_DATA_DIR']?.trim();\n return env !== undefined && env.length > 0 ? env : undefined;\n}\n\nfunction appendUniquePath(paths: string[], candidate: string | null): void {\n if (candidate !== null && !paths.includes(candidate)) {\n paths.push(candidate);\n }\n}\n\n/**\n * Resolves all candidate paths where a job-result sidecar might reside (#5472).\n *\n * Returns all possible candidate paths for a given `jobId`:\n * 1. Primary path (`nexusDataPath('jobs', ...)`)\n * 2. Shared path (`nexusSharedPath('jobs', ...)`)\n * 3. Cwd-discovered repo path (if different and known)\n */\nexport function candidateJobResultPaths(\n jobId: string,\n resolvePrimary: (subdir: string, ...segments: string[]) => string = nexusDataPath,\n resolveShared: (subdir: string, ...segments: string[]) => string = nexusSharedPath,\n repoRootFinder: (start: string) => string | null = findRepoRoot\n): readonly string[] {\n if (candidatePathsResolverForTests !== undefined) {\n const overridden = candidatePathsResolverForTests(jobId);\n if (overridden !== undefined) return overridden;\n }\n const filename = `result-${jobId}.json`;\n const primary = resolvePrimary('jobs', filename);\n if (getExplicitDataDir() !== undefined) {\n return [primary];\n }\n\n const paths: string[] = [primary];\n appendUniquePath(paths, resolveShared('jobs', filename));\n\n const cwdRepo = repoRootFinder(process.cwd());\n const cwdRepoPath = cwdRepo !== null ? join(cwdRepo, '.nexus-agents', 'jobs', filename) : null;\n appendUniquePath(paths, cwdRepoPath);\n\n return paths;\n}\n\nfunction compareTerminalRecords(a: JobResult, b: JobResult): number {\n if (a.status === 'cancelled' && b.status !== 'cancelled') return -1;\n if (b.status === 'cancelled' && a.status !== 'cancelled') return 1;\n\n const aSettled = Date.parse(a.completedAt ?? a.createdAt);\n const bSettled = Date.parse(b.completedAt ?? b.createdAt);\n if (Number.isFinite(aSettled) && Number.isFinite(bSettled) && aSettled !== bSettled) {\n return bSettled - aSettled;\n }\n return 0;\n}\n\nfunction comparePendingRecords(a: JobResult, b: JobResult): number {\n const aActivity = Date.parse(a.lastProgressAt ?? a.createdAt);\n const bActivity = Date.parse(b.lastProgressAt ?? b.createdAt);\n if (Number.isFinite(aActivity) && Number.isFinite(bActivity) && aActivity !== bActivity) {\n return bActivity - aActivity;\n }\n return 0;\n}\n\n/**\n * Compares two job records to determine which is more authoritative (#5472).\n *\n * Ranking rules:\n * 1. Terminal status (`complete`, `failed`, `cancelled`) outranks `pending`.\n * 2. Cancellation preservation (#4017): `cancelled` outranks `complete` and `failed`.\n * 3. If both are terminal (or neither is `cancelled`), later `completedAt ?? createdAt` wins.\n * 4. If both are `pending`, later `lastProgressAt ?? createdAt` wins.\n * 5. Stable tie-break (returns 0).\n */\nexport function compareJobRecords(a: JobResult, b: JobResult): number {\n const aTerminal = a.status !== 'pending';\n const bTerminal = b.status !== 'pending';\n\n if (aTerminal && !bTerminal) return -1;\n if (!aTerminal && bTerminal) return 1;\n\n return aTerminal ? compareTerminalRecords(a, b) : comparePendingRecords(a, b);\n}\n\n/**\n * Selects the winning job record among multiple candidate records (#5472),\n * carrying forward any recorded heartbeat (`lastProgressAt`) if the winner\n * lacks one.\n */\nexport function selectAuthoritativeJobRecord(records: readonly JobResult[]): JobResult {\n const sorted = [...records].sort(compareJobRecords);\n const winner = sorted[0];\n if (winner === undefined) {\n throw new Error('selectAuthoritativeJobRecord called with empty records');\n }\n\n if (winner.lastProgressAt !== undefined) {\n return winner;\n }\n\n for (const r of records) {\n if (r.lastProgressAt !== undefined) {\n return { ...winner, lastProgressAt: r.lastProgressAt };\n }\n }\n\n return winner;\n}\n\n/**\n * Read and validate a job-result file from disk. Returns null on parse/schema failure.\n */\nexport function readJobResultFile(path: string, jobId: string, logger: ILogger): JobResult | null {\n try {\n const raw = JSON.parse(readFileSync(path, 'utf-8')) as unknown;\n const parsed = JobResultSchema.safeParse(raw);\n if (!parsed.success) {\n logger.warn('Job result file failed schema check', { jobId, path });\n return null;\n }\n return parsed.data;\n } catch (err) {\n logger.warn('Job result file unreadable', {\n jobId,\n path,\n error: err instanceof Error ? err.message : String(err),\n });\n return null;\n }\n}\n\n/**\n * Read a job-result record across candidate data directories (#5472).\n */\nexport function readJobResultAcrossCandidates(jobId: string, logger: ILogger): JobResult | null {\n const candidates = candidateJobResultPaths(jobId);\n const records: JobResult[] = [];\n for (const path of candidates) {\n if (!existsSync(path)) continue;\n const record = readJobResultFile(path, jobId, logger);\n if (record !== null) {\n records.push(record);\n }\n }\n const first = records[0];\n if (first === undefined) return null;\n if (records.length === 1) return first;\n return selectAuthoritativeJobRecord(records);\n}\n\n/**\n * Syncs a settled or updated job record to any existing alternate candidate\n * paths (#5472) so readers looking at either repo or shared directories\n * immediately observe the current status.\n */\nexport function syncAlternateCandidates(\n jobId: string,\n primaryPath: string,\n record: JobResult,\n logger: ILogger,\n persistFn: (path: string, record: JobResult) => void\n): void {\n const candidates = candidateJobResultPaths(jobId);\n for (const candidatePath of candidates) {\n if (candidatePath === primaryPath) continue;\n if (!existsSync(candidatePath)) continue;\n try {\n persistFn(candidatePath, record);\n logger.debug('Synced job record to alternate candidate path', {\n jobId,\n path: candidatePath,\n status: record.status,\n });\n } catch (err) {\n logger.warn('Failed to sync job record to alternate candidate path', {\n jobId,\n path: candidatePath,\n error: err instanceof Error ? err.message : String(err),\n });\n }\n }\n}\n","/**\n * Structured adapter/transport failure detail in job records (#4375).\n *\n * Persisted on `failed` job records so readers of `get_job_result` can\n * programmatically distinguish adapter outages or capacity exhaustion\n * from application errors without parsing prose.\n *\n * @module mcp/jobs/job-failure-detail\n */\n\nimport { z } from 'zod';\nimport { sanitizeErrorDetails } from '../../security/output-sanitizer.js';\nimport { ERROR_ENVELOPE_META_KEY } from '../error-envelope.js';\n\n/**\n * Structured failure detail for adapter / transport failures (#4375).\n */\nexport const JobFailureDetailSchema = z.object({\n /** Identifier of the failing adapter (e.g. 'claude', 'codex', 'api:anthropic'). */\n adapter: z.string().min(1),\n /** Transport mechanism where the failure occurred (e.g. 'subprocess', 'mcp', 'stdio'). */\n transport: z.string().min(1),\n /** Normalized failure category (e.g. 'rate_limited', 'timeout', 'capacity_exhausted'). */\n category: z.string().min(1),\n});\nexport type JobFailureDetail = z.infer<typeof JobFailureDetailSchema>;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n\nfunction getNonEmptyString(value: unknown): string | undefined {\n return typeof value === 'string' && value.trim() !== '' ? value.trim() : undefined;\n}\n\n/**\n * Normalizes a raw category or code string into a snake_case failure category.\n */\nfunction normalizeFailureCategory(raw: string): string {\n return raw.trim().toLowerCase();\n}\n\n/**\n * Extracts category from a candidate object, falling back to message text for capacity_exhausted (#4373).\n */\nfunction extractCategory(candidate: Record<string, unknown>): string | undefined {\n const direct = getNonEmptyString(candidate.category) ?? getNonEmptyString(candidate.code);\n if (direct !== undefined) {\n return normalizeFailureCategory(direct);\n }\n const msg = getNonEmptyString(candidate.message);\n if (msg?.toLowerCase().includes('capacity_exhausted') === true) {\n return 'capacity_exhausted';\n }\n return undefined;\n}\n\n/**\n * Inspects an explicit failureDetail property if present.\n */\nfunction inspectExplicitFailureDetail(\n candidate: Record<string, unknown>\n): JobFailureDetail | undefined {\n if (!isRecord(candidate.failureDetail)) return undefined;\n const fd = candidate.failureDetail;\n const adapter = getNonEmptyString(fd.adapter);\n const transport = getNonEmptyString(fd.transport);\n const category = getNonEmptyString(fd.category);\n if (adapter !== undefined && transport !== undefined && category !== undefined) {\n return {\n adapter,\n transport,\n category: normalizeFailureCategory(category),\n };\n }\n return undefined;\n}\n\n/**\n * Inspects a single candidate record for adapter failure fields.\n */\nfunction inspectCandidateForDetail(\n candidate: Record<string, unknown>\n): JobFailureDetail | undefined {\n const explicit = inspectExplicitFailureDetail(candidate);\n if (explicit !== undefined) return explicit;\n\n const adapter = getNonEmptyString(candidate.adapter) ?? getNonEmptyString(candidate.cli);\n if (adapter === undefined) return undefined;\n\n const transport = getNonEmptyString(candidate.transport) ?? 'subprocess';\n const category = extractCategory(candidate);\n if (category === undefined) return undefined;\n\n return { adapter, transport, category };\n}\n\n/**\n * Inspects MCP error envelope or _meta metadata for failure details.\n */\nfunction inspectMetaForDetail(meta: unknown): JobFailureDetail | undefined {\n if (!isRecord(meta)) return undefined;\n const direct = inspectCandidateForDetail(meta);\n if (direct !== undefined) return direct;\n\n const env = meta[ERROR_ENVELOPE_META_KEY];\n if (isRecord(env) && isRecord(env.detail)) {\n return inspectCandidateForDetail(env.detail);\n }\n return undefined;\n}\n\n/**\n * Extracts structured adapter/transport failure detail from a caught error\n * or failure-shaped result (#4375).\n *\n * Inspects:\n * 1. An explicit `failureDetail` property\n * 2. CLI error structures (`cli`, `code`, `transport`)\n * 3. Generic adapter error shapes (`adapter`, `transport`, `category`)\n * 4. Nested `_meta` or MCP error envelope structures\n * 5. Nested `.error` or `.cause` properties\n *\n * Strips all excess properties (e.g. response bodies, prompt text, stack traces)\n * returning strictly `{ adapter, transport, category }`.\n *\n * @param source - Caught exception or failure-shaped job result\n * @returns Structured failure detail, or `undefined` if not an adapter/transport failure\n */\nexport function extractFailureDetail(source: unknown): JobFailureDetail | undefined {\n if (!isRecord(source)) return undefined;\n\n return (\n inspectCandidateForDetail(source) ??\n inspectMetaForDetail(source._meta) ??\n (isRecord(source.error) ? inspectCandidateForDetail(source.error) : undefined) ??\n (isRecord(source.cause) ? inspectCandidateForDetail(source.cause) : undefined)\n );\n}\n\n/**\n * Sanitizes all string fields in a failure detail and validates against the schema (#4375).\n * Returns undefined if detail is undefined.\n */\nexport function validateAndSanitizeFailureDetail(\n detail?: JobFailureDetail\n): JobFailureDetail | undefined {\n if (detail === undefined) return undefined;\n return JobFailureDetailSchema.parse({\n adapter: sanitizeErrorDetails(detail.adapter),\n transport: sanitizeErrorDetails(detail.transport),\n category: sanitizeErrorDetails(detail.category),\n });\n}\n","/**\n * nexus-agents/mcp/jobs — per-job AbortController registry (#4086).\n *\n * `runAsJob` dispatches detached background work; `cancel_job` previously only\n * wrote a durable `cancelled` record but could not actually STOP the in-flight\n * work (run-as-job had no abort wiring, #4017). This registry closes that gap: a\n * dispatched job registers an `AbortController` keyed by `jobId`, the job body\n * receives `controller.signal`, and `cancel_job` calls {@link abortJob} to abort\n * it — so a tool that threads the signal into its awaited work is interrupted in\n * the same process. (Tools that ignore the signal still run to completion, but the\n * record is preserved as `cancelled` by the terminal-writer guards, #4022.)\n *\n * Process-local and same-process only (no IPC): a worker in another process must\n * still poll the durable record.\n *\n * @module mcp/jobs/job-abort-registry\n */\n\nconst controllers = new Map<string, AbortController>();\n\n/**\n * Register a fresh `AbortController` for `jobId` and return it. The dispatcher\n * passes its `signal` to the job body and must call {@link unregisterJobAbort}\n * when the job settles (whether it completed, failed, or was aborted).\n */\nexport function registerJobAbort(jobId: string): AbortController {\n const controller = new AbortController();\n controllers.set(jobId, controller);\n return controller;\n}\n\n/**\n * Abort the in-flight job's signal, if it is still registered. Returns true when a\n * live controller was found and aborted, false when the job is unknown / already\n * settled (in which case there is nothing in-flight to stop — the durable record\n * is the source of truth). The entry is removed so a late settle doesn't double-fire.\n */\nexport function abortJob(jobId: string, reason?: string): boolean {\n const controller = controllers.get(jobId);\n if (controller === undefined) return false;\n controllers.delete(jobId);\n controller.abort(reason ?? 'cancelled via cancel_job');\n return true;\n}\n\n/** Remove the controller for a settled job. Idempotent. */\nexport function unregisterJobAbort(jobId: string): void {\n controllers.delete(jobId);\n}\n\n/** Number of in-flight controllers (test/observability). @internal */\nexport function jobAbortRegistrySize(): number {\n return controllers.size;\n}\n","/**\n * Structured task state — JSONL append-only log (#2033).\n *\n * Writes a per-task log at `~/.nexus-agents/tasks/state-{taskId}.jsonl`\n * (overridable via `customDir` for tests). Replay reduces the log\n * forward to a current `StructuredTaskState` snapshot — suitable for\n * resume-after-restart and STATE.md-style inspection.\n * Security and error-handling characteristics:\n * - Directory mode 0o700, file mode 0o600\n * - Path-traversal validation on taskId\n * - `Result<T, Error>` returns, no exceptions for expected failures\n *\n * @module context/structured-task-state\n */\n\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { AsyncLocalStorage } from 'node:async_hooks';\nimport { nexusDataPath } from '../config/nexus-data-dir.js';\nimport type { Result } from '../core/result.js';\nimport { ok, err } from '../core/result.js';\nimport { createLogger } from '../core/logger.js';\nimport {\n StructuredTaskLogEntrySchema,\n TASK_RESULT_MAX_BYTES,\n type ProgressLedgerEntry,\n type ReflectAction,\n type StructuredTaskLogEntry,\n type StructuredTaskState,\n type TaskBlocker,\n type TaskCancellation,\n type TaskDecision,\n type TaskLedger,\n type TaskPosition,\n type TaskStage,\n} from './structured-task-state-types.js';\n\nconst logger = createLogger({ component: 'structured-task-state' });\n\n/** Subdirectory name under the resolved nexus data dir for task-state logs. */\nconst TASKS_SUBDIR = 'tasks';\n\nconst FILE_MODE = 0o600;\nconst DIR_MODE = 0o700;\n\nconst asyncTaskStateJob = new AsyncLocalStorage<string>();\n\n/** Run work whose task-state initialization must record async dispatch. @internal */\nexport function withAsyncTaskStateDispatch<T>(jobId: string, operation: () => T): T {\n return asyncTaskStateJob.run(jobId, operation);\n}\n\n/**\n * The jobId of the async dispatch the current async context belongs to, or\n * `undefined` outside any (#6162). The heartbeat bridge in `mcp/jobs` uses it\n * to attribute a pipeline-bus event to the job whose body emitted it.\n * @internal\n */\nexport function currentAsyncDispatchJobId(): string | undefined {\n return asyncTaskStateJob.getStore();\n}\n\nfunction getTasksDir(customDir?: string): string {\n if (customDir !== undefined) return path.resolve(customDir);\n return nexusDataPath(TASKS_SUBDIR);\n}\n\nfunction getLogPath(taskId: string, customDir?: string): string {\n return path.join(getTasksDir(customDir), `state-${taskId}.jsonl`);\n}\n\n/**\n * Enumerate the task ids that have a state log on disk (#3693). Walks the tasks\n * dir for `state-<taskId>.jsonl` files; returns `[]` when the dir is absent or\n * unreadable (best-effort, never throws). `customDir` steers the lookup for tests.\n */\nexport function listTaskStateIds(customDir?: string): string[] {\n const dir = getTasksDir(customDir);\n if (!fs.existsSync(dir)) return [];\n let entries: string[];\n try {\n entries = fs.readdirSync(dir);\n } catch (cause) {\n logger.warn('tasks directory unreadable', {\n dir,\n error: cause instanceof Error ? cause.message : String(cause),\n });\n return [];\n }\n const ids: string[] = [];\n for (const entry of entries) {\n const match = /^state-(.+)\\.jsonl$/.exec(entry);\n if (match?.[1] !== undefined) ids.push(match[1]);\n }\n return ids;\n}\n\nfunction validateTaskId(taskId: string): Result<string, Error> {\n if (taskId.includes('..') || taskId.includes('/') || taskId.includes('\\\\')) {\n return err(new Error('Invalid task ID: contains path traversal characters'));\n }\n if (taskId.length === 0 || taskId.length > 128) {\n return err(new Error('Invalid task ID: must be 1-128 characters'));\n }\n return ok(taskId);\n}\n\nfunction ensureTasksDir(customDir?: string): Result<string, Error> {\n const dirPath = getTasksDir(customDir);\n try {\n fs.mkdirSync(dirPath, { recursive: true, mode: DIR_MODE });\n return ok(dirPath);\n } catch (cause) {\n const e = cause instanceof Error ? cause : new Error(String(cause));\n return err(new Error(`Failed to create tasks directory at ${dirPath}: ${e.message}`));\n }\n}\n\n/** Append a log entry (no state computation). Pure I/O. */\nfunction appendLogEntry(\n taskId: string,\n entry: StructuredTaskLogEntry,\n customDir?: string\n): Result<void, Error> {\n const idCheck = validateTaskId(taskId);\n if (!idCheck.ok) return err(idCheck.error);\n const dirResult = ensureTasksDir(customDir);\n if (!dirResult.ok) return err(dirResult.error);\n\n const filePath = getLogPath(taskId, customDir);\n const line = JSON.stringify(entry) + '\\n';\n try {\n fs.appendFileSync(filePath, line, { mode: FILE_MODE });\n return ok(undefined);\n } catch (cause) {\n const e = cause instanceof Error ? cause : new Error(String(cause));\n return err(new Error(`Failed to write task state entry: ${e.message}`));\n }\n}\n\n/**\n * Initialize structured state for a new task. Writes the full initial\n * state as an `init` log entry. Safe to call once per taskId.\n */\nexport function initTaskState(state: StructuredTaskState, customDir?: string): Result<void, Error> {\n const isAsyncJob = asyncTaskStateJob.getStore() === state.taskId;\n const persistedState = isAsyncJob ? { ...state, dispatch: 'async' as const } : state;\n return appendLogEntry(\n state.taskId,\n { event: 'init', ts: state.updatedAt, state: persistedState },\n customDir\n );\n}\n\nexport function appendDecision(\n taskId: string,\n decision: TaskDecision,\n customDir?: string\n): Result<void, Error> {\n return appendLogEntry(taskId, { event: 'decision', ts: decision.ts, decision }, customDir);\n}\n\nexport function appendBlocker(\n taskId: string,\n blocker: TaskBlocker,\n customDir?: string\n): Result<void, Error> {\n return appendLogEntry(taskId, { event: 'blocker', ts: blocker.ts, blocker }, customDir);\n}\n\nexport function resolveBlocker(\n taskId: string,\n blockerIndex: number,\n resolvedAt: string,\n customDir?: string\n): Result<void, Error> {\n return appendLogEntry(\n taskId,\n { event: 'blocker_resolved', ts: resolvedAt, blockerIndex, resolvedAt },\n customDir\n );\n}\n\nexport function updateStage(\n taskId: string,\n stage: TaskStage,\n ts: string,\n customDir?: string\n): Result<void, Error> {\n return appendLogEntry(taskId, { event: 'stage', ts, stage }, customDir);\n}\n\nexport function updatePosition(\n taskId: string,\n position: TaskPosition,\n ts: string,\n customDir?: string\n): Result<void, Error> {\n return appendLogEntry(taskId, { event: 'position', ts, position }, customDir);\n}\n\n/**\n * Replace the Magentic-One Task Ledger atomically (#2278). The outer loop calls\n * this when it replans — facts/guesses/openQuestions are revised together so\n * downstream reflections are reading a consistent set.\n */\nexport function updateTaskLedger(\n taskId: string,\n ledger: TaskLedger,\n customDir?: string\n): Result<void, Error> {\n return appendLogEntry(taskId, { event: 'task_ledger', ts: ledger.updatedAt, ledger }, customDir);\n}\n\n/**\n * Append a Magentic-One Progress Ledger entry (#2278). Inner-loop reflection\n * after a step: was the plan still valid, are we stuck, what to do next.\n */\nexport function appendProgressLedgerEntry(\n taskId: string,\n entry: ProgressLedgerEntry,\n customDir?: string\n): Result<void, Error> {\n return appendLogEntry(taskId, { event: 'progress_ledger', ts: entry.ts, entry }, customDir);\n}\n\n/**\n * Append a tool-result payload (#3043 / epic #2631 Stage 2). Carries the\n * same shape the synchronous mode would have returned inline. Writers\n * should `updateStage(taskId, 'complete', ...)` immediately before so a\n * polling reader observes the terminal stage transition + result together.\n *\n * The payload is JSON-serialized to measure size; over-cap writes\n * (> `TASK_RESULT_MAX_BYTES`) get replaced with a typed truncation\n * marker. The cap is observable by the caller (the reducer surfaces\n * `state.result` as the truncation marker rather than the original) so\n * silent data loss is impossible.\n */\nexport function appendResult(\n taskId: string,\n result: unknown,\n ts: string,\n customDir?: string\n): Result<void, Error> {\n let payload: unknown = result;\n let serialized: string;\n try {\n serialized = JSON.stringify(result ?? null);\n } catch (cause) {\n const e = cause instanceof Error ? cause : new Error(String(cause));\n return err(new Error(`Failed to serialize result for task ${taskId}: ${e.message}`));\n }\n // Note: `Buffer.byteLength` is the right unit — JSON.stringify length is\n // UTF-16 code units, not the bytes that hit disk. For ASCII the two\n // coincide; for non-ASCII / emoji results the byte-count is what bounds\n // the actual storage cost.\n const bytes = Buffer.byteLength(serialized, 'utf-8');\n if (bytes > TASK_RESULT_MAX_BYTES) {\n payload = {\n truncated: true,\n originalBytes: bytes,\n maxBytes: TASK_RESULT_MAX_BYTES,\n note: 'Result exceeded TASK_RESULT_MAX_BYTES — original dropped at write time.',\n };\n logger.warn('Task result truncated at write', {\n taskId,\n bytes,\n max: TASK_RESULT_MAX_BYTES,\n });\n }\n return appendLogEntry(taskId, { event: 'result', ts, result: payload }, customDir);\n}\n\n/**\n * Append a cancellation marker (#3043 / epic #2631 Stage 2). Called by\n * `cancel_job`. The reducer is append-only: if a cancellation already\n * exists in the log, subsequent cancellation events are kept on disk\n * (for audit) but DON'T overwrite the original `requestedAt` — so a\n * malicious or buggy double-cancel can't rewrite history.\n */\nexport function appendCancellation(\n taskId: string,\n cancellation: TaskCancellation,\n customDir?: string\n): Result<void, Error> {\n return appendLogEntry(\n taskId,\n { event: 'cancellation', ts: cancellation.requestedAt, cancellation },\n customDir\n );\n}\n\n/**\n * Read the most recent ProgressLedger entry's suggested action — what\n * `Orchestrator.reflect()` returns. Returns `'continue'` when no progress-ledger\n * entries exist yet (default to \"no reflection has flagged a problem\"), and an\n * error if the task log itself can't be read.\n */\nexport function reflect(taskId: string, customDir?: string): Result<ReflectAction, Error> {\n const stateResult = readTaskState(taskId, customDir);\n if (!stateResult.ok) return err(stateResult.error);\n const ledger = stateResult.value.progressLedger;\n if (ledger === undefined || ledger.length === 0) return ok('continue');\n const last = ledger[ledger.length - 1];\n if (last === undefined) return ok('continue');\n return ok(last.suggestedAction);\n}\n\n/**\n * Read the log file and reduce it to the current state snapshot.\n *\n * Returns `err` when the file doesn't exist or no `init` entry is\n * present. Malformed lines are skipped with a warning (log, don't\n * fail).\n */\nexport function readTaskState(\n taskId: string,\n customDir?: string\n): Result<StructuredTaskState, Error> {\n const idCheck = validateTaskId(taskId);\n if (!idCheck.ok) return err(idCheck.error);\n\n const filePath = getLogPath(taskId, customDir);\n if (!fs.existsSync(filePath)) {\n return err(new Error(`No state log for task: ${taskId}`));\n }\n\n let content: string;\n try {\n content = fs.readFileSync(filePath, 'utf-8');\n } catch (cause) {\n const e = cause instanceof Error ? cause : new Error(String(cause));\n return err(new Error(`Failed to read state log: ${e.message}`));\n }\n\n const lines = content.split('\\n').filter((l) => l.length > 0);\n const entries: StructuredTaskLogEntry[] = [];\n for (const line of lines) {\n try {\n const parsed: unknown = JSON.parse(line);\n const validated = StructuredTaskLogEntrySchema.safeParse(parsed);\n if (validated.success) {\n entries.push(validated.data);\n } else {\n logger.warn('Skipping malformed task-state log entry', {\n taskId,\n error: validated.error.message,\n });\n }\n } catch (cause) {\n const msg = cause instanceof Error ? cause.message : String(cause);\n logger.warn('Skipping unparseable task-state log entry', { taskId, error: msg });\n }\n }\n\n return reduceLogEntries(taskId, entries);\n}\n\n/**\n * Fold a sequence of log entries into the final state. Exported so\n * tests can exercise the reducer without touching the filesystem.\n */\nexport function reduceLogEntries(\n taskId: string,\n entries: readonly StructuredTaskLogEntry[]\n): Result<StructuredTaskState, Error> {\n const init = entries.find((e) => e.event === 'init');\n if (init === undefined) {\n return err(new Error(`No init entry found for task: ${taskId}`));\n }\n const initState = init.state;\n if (initState.taskId !== taskId) {\n return err(\n new Error(`Task ID mismatch: log contains state for ${initState.taskId}, expected ${taskId}`)\n );\n }\n\n // #3043: monotonic version. Pre-Stage-2 logs lack the field; default\n // to 0 and start counting from there. Each non-init event bumps by 1.\n let state: StructuredTaskState = {\n ...initState,\n decisions: [...initState.decisions],\n blockers: initState.blockers.map((b) => ({ ...b })),\n version: initState.version ?? 0,\n // #3090: createdAt is fixed at the init entry's ts and never advances\n // (unlike updatedAt). Prefer an explicit createdAt on the init state,\n // else fall back to the init entry's ts.\n createdAt: initState.createdAt ?? init.ts,\n };\n\n for (const entry of entries) {\n if (entry === init) continue;\n state = applyLogEntry(state, entry);\n }\n return ok(state);\n}\n\n/** Apply a blockers-related event (#2033). */\nfunction applyBlockerEvent(\n state: StructuredTaskState,\n entry: Extract<StructuredTaskLogEntry, { event: 'blocker' | 'blocker_resolved' }>,\n nextVersion: number\n): StructuredTaskState {\n if (entry.event === 'blocker') {\n return {\n ...state,\n blockers: [...state.blockers, entry.blocker],\n updatedAt: entry.ts,\n version: nextVersion,\n };\n }\n return {\n ...state,\n blockers: state.blockers.map((b, i) =>\n i === entry.blockerIndex ? { ...b, resolved: entry.resolvedAt } : b\n ),\n updatedAt: entry.ts,\n version: nextVersion,\n };\n}\n\n/** Apply a simple scalar/ledger replacement event (no array merge). */\nfunction applyReplacementEvent(\n state: StructuredTaskState,\n entry: Extract<\n StructuredTaskLogEntry,\n { event: 'stage' | 'position' | 'task_ledger' | 'decision' | 'progress_ledger' }\n >,\n nextVersion: number\n): StructuredTaskState {\n switch (entry.event) {\n case 'decision':\n return {\n ...state,\n decisions: [...state.decisions, entry.decision],\n updatedAt: entry.ts,\n version: nextVersion,\n };\n case 'stage':\n return { ...state, stage: entry.stage, updatedAt: entry.ts, version: nextVersion };\n case 'position':\n return { ...state, position: entry.position, updatedAt: entry.ts, version: nextVersion };\n case 'task_ledger':\n return { ...state, taskLedger: entry.ledger, updatedAt: entry.ts, version: nextVersion };\n case 'progress_ledger':\n return {\n ...state,\n progressLedger: [...(state.progressLedger ?? []), entry.entry],\n updatedAt: entry.ts,\n version: nextVersion,\n };\n }\n}\n\n/**\n * Apply a result or cancellation event (#3043 / epic #2631 Stage 2). Result\n * always assigns; cancellation is append-only (in-memory keeps the FIRST\n * requestedAt across duplicate events).\n */\nfunction applyTerminalEvent(\n state: StructuredTaskState,\n entry: Extract<StructuredTaskLogEntry, { event: 'result' | 'cancellation' }>,\n nextVersion: number\n): StructuredTaskState {\n if (entry.event === 'result') {\n return { ...state, result: entry.result, updatedAt: entry.ts, version: nextVersion };\n }\n return {\n ...state,\n cancellation: state.cancellation ?? entry.cancellation,\n updatedAt: entry.ts,\n version: nextVersion,\n };\n}\n\n/**\n * Map each event tag to the apply-helper that owns it. Lets `applyLogEntry`\n * dispatch in one table lookup rather than a 10-case switch — the latter\n * trips the per-function complexity cap as the event set grows (#3043).\n */\nconst EVENT_CATEGORY: Record<\n StructuredTaskLogEntry['event'],\n 'init' | 'blocker' | 'replace' | 'terminal'\n> = {\n init: 'init',\n blocker: 'blocker',\n blocker_resolved: 'blocker',\n decision: 'replace',\n stage: 'replace',\n position: 'replace',\n task_ledger: 'replace',\n progress_ledger: 'replace',\n result: 'terminal',\n cancellation: 'terminal',\n};\n\nfunction applyLogEntry(\n state: StructuredTaskState,\n entry: StructuredTaskLogEntry\n): StructuredTaskState {\n const category = EVENT_CATEGORY[entry.event];\n if (category === 'init') return state;\n // #3043: every non-init event bumps the monotonic version. Calculated\n // here (not in each branch) so a new event type can't accidentally\n // forget to bump.\n const nextVersion = (state.version ?? 0) + 1;\n if (category === 'blocker') {\n return applyBlockerEvent(\n state,\n entry as Extract<StructuredTaskLogEntry, { event: 'blocker' | 'blocker_resolved' }>,\n nextVersion\n );\n }\n if (category === 'terminal') {\n return applyTerminalEvent(\n state,\n entry as Extract<StructuredTaskLogEntry, { event: 'result' | 'cancellation' }>,\n nextVersion\n );\n }\n return applyReplacementEvent(\n state,\n entry as Extract<\n StructuredTaskLogEntry,\n { event: 'decision' | 'stage' | 'position' | 'task_ledger' | 'progress_ledger' }\n >,\n nextVersion\n );\n}\n","/**\n * Structured task state — type definitions (#2033).\n *\n * Per-task state (decisions, blockers, stage, position) that a\n * long-running orchestration task mutates as it progresses. Designed\n * for the STATE.md-equivalent pattern from GSD — replacing ad-hoc\n * `memory_write` calls with a typed append-only log keyed by taskId.\n *\n * Serialized one-entry-per-JSONL-line so a later `query_trace` can\n * replay the full evolution, and resume-after-timeout reads the latest\n * state without replaying everything.\n *\n * @module context/structured-task-state-types\n */\n\nimport { z } from 'zod';\n\n/** Task execution lifecycle stages. */\nexport const TaskStageSchema = z.enum([\n 'planning',\n 'executing',\n 'verifying',\n 'complete',\n 'blocked',\n // #3091 / epic #2631: terminal failure stage. Distinct from `blocked`\n // (recoverable, still in-flight) — `failed` is terminal and maps to the\n // job-result `failed` status. Added so async-mode writers can record a\n // failed run in StructuredTaskState instead of the Stage-1 sidecar.\n 'failed',\n]);\nexport type TaskStage = z.infer<typeof TaskStageSchema>;\n\n/** A single recorded decision in the task evolution. */\nconst TaskDecisionSchema = z.object({\n ts: z.iso.datetime(),\n decision: z.string().min(1),\n rationale: z.string().min(1),\n});\nexport type TaskDecision = z.infer<typeof TaskDecisionSchema>;\n\n/** A blocker that stopped forward progress (optionally later resolved). */\nconst TaskBlockerSchema = z.object({\n ts: z.iso.datetime(),\n blocker: z.string().min(1),\n resolved: z.iso.datetime().optional(),\n});\nexport type TaskBlocker = z.infer<typeof TaskBlockerSchema>;\n\n/** Where the task currently is in its execution. */\nconst TaskPositionSchema = z.object({\n currentStep: z.string().min(1),\n nextStep: z.string().optional(),\n});\nexport type TaskPosition = z.infer<typeof TaskPositionSchema>;\n\n/**\n * Magentic-One Task Ledger — outer-loop \"facts and guesses\" about the task (#2278).\n *\n * Mirrors AutoGen's `magentic-one` Orchestrator pattern: the outer loop maintains\n * a ledger of verifiable facts, working assumptions (guesses), and open questions\n * the orchestrator still needs to resolve. The inner loop's `ProgressLedger`\n * decides whether to continue, replan (which triggers a TaskLedger refresh), or\n * escalate.\n *\n * Reference: microsoft.github.io/autogen — Magentic-One Task Ledger / Progress\n * Ledger pattern.\n */\nconst TaskLedgerSchema = z.object({\n /** Verifiable observations: what we have observed/measured/confirmed. */\n facts: z.array(z.string()),\n /** Working assumptions: useful guesses we proceed under, marked separately. */\n guesses: z.array(z.string()),\n /** Things we still need to figure out before the plan is sound. */\n openQuestions: z.array(z.string()),\n updatedAt: z.iso.datetime(),\n});\nexport type TaskLedger = z.infer<typeof TaskLedgerSchema>;\n\n/**\n * Magentic-One Progress Ledger — the inner-loop self-reflection at each step (#2278).\n *\n * After each step, the orchestrator (or whoever is driving) emits one\n * `ProgressLedgerEntry` summarizing whether the outer plan is still valid,\n * whether we are stuck, and what to do next. Append-only; the most recent entry's\n * `suggestedAction` is what `Orchestrator.reflect()` returns.\n */\nconst ReflectActionSchema = z.enum(['continue', 'revise_plan', 'escalate_to_human', 'abort']);\nexport type ReflectAction = z.infer<typeof ReflectActionSchema>;\n\nconst ProgressLedgerEntrySchema = z.object({\n ts: z.iso.datetime(),\n /** What just happened (the step we are reflecting on). */\n step: z.string().min(1),\n /** Is the outer Task Ledger plan still right after this step? */\n planStillValid: z.boolean(),\n /** Are we making progress, or have we stalled? */\n stuck: z.boolean(),\n /** What the orchestrator should do next based on this reflection. */\n suggestedAction: ReflectActionSchema,\n /** Why this action was chosen — required so future readers can audit the call. */\n rationale: z.string().min(1),\n});\nexport type ProgressLedgerEntry = z.infer<typeof ProgressLedgerEntrySchema>;\n\n/**\n * Cancellation marker for async-mode tools (#3043 / epic #2631 Stage 2).\n *\n * Append-only — once present, the cancellation timestamp can't be\n * cleared. `cancel_job` writes this; the task's run loop checks it at\n * safe-point boundaries to abort cleanly.\n */\nconst TaskCancellationSchema = z.object({\n requestedAt: z.iso.datetime(),\n /** Optional human-readable note carried back to the caller. */\n reason: z.string().max(1000).optional(),\n});\nexport type TaskCancellation = z.infer<typeof TaskCancellationSchema>;\n\n/**\n * Maximum serialized size of a `result` payload, in bytes\n * (#3043 / epic #2631 Stage 2). Caps result-retention DoS — a\n * misbehaving tool that wrote a 100 MiB result into the state log\n * would block reads of every other tool's state on the same data\n * dir while the reducer parses it. 1 MiB is generous for structured\n * payloads but bounds the worst case. `appendResult` truncates\n * over-cap writes to `{ truncated: true, originalBytes }` rather\n * than dropping them silently — so the caller can tell whether a\n * missing result was never written vs. dropped at write time.\n */\nexport const TASK_RESULT_MAX_BYTES = 1_048_576;\n\n/**\n * Structured state for a single long-running task.\n *\n * All arrays are append-only during the task's lifetime; a blocker can\n * be resolved by updating its `resolved` timestamp, but we do not\n * retroactively rewrite earlier entries.\n */\nexport const StructuredTaskStateSchema = z.object({\n taskId: z.string().min(1),\n /**\n * Marks state created by the shared async-job dispatcher (#5622).\n * Optional for backward compatibility; absence does not prove async dispatch.\n */\n dispatch: z.literal('async').optional(),\n stage: TaskStageSchema,\n decisions: z.array(TaskDecisionSchema),\n blockers: z.array(TaskBlockerSchema),\n position: TaskPositionSchema,\n /**\n * Magentic-One Task Ledger (#2278). Mutable single-object outer-loop state:\n * facts/guesses/openQuestions revised together when the plan is replanned.\n * Optional so the field can be added later without breaking existing logs.\n */\n taskLedger: TaskLedgerSchema.optional(),\n /**\n * Magentic-One Progress Ledger (#2278). Append-only inner-loop reflections.\n * Most recent entry's `suggestedAction` is what `reflect()` returns. Optional\n * for the same backward-compat reason as `taskLedger`.\n */\n progressLedger: z.array(ProgressLedgerEntrySchema).optional(),\n /**\n * Monotonic version counter (#3043 / epic #2631 Stage 2). Increments by\n * 1 on every write; polling clients use this to detect \"I missed a\n * transition\" and resync rather than silently observe a stale snapshot.\n *\n * Optional + defaulting-to-0 in the reducer for backward-compat — old\n * state logs (pre-Stage-2) don't carry it; the reducer treats their\n * baseline as v0 and starts counting from there.\n */\n version: z.number().int().nonnegative().optional(),\n /**\n * Tool result payload (#3043 / epic #2631 Stage 2). Set atomically\n * via the `result` log event when `stage === 'complete'`. Carries the\n * same shape the synchronous mode would have returned inline.\n *\n * Capped at `TASK_RESULT_MAX_BYTES` at write time; over-cap payloads\n * are replaced with `{ truncated: true, originalBytes }` so the\n * cap is observable rather than silent.\n *\n * Once Stage 2 (this) ships, Stage 3+ (#3044 / #3045) migrate the\n * orchestrate / run_workflow / consensus_vote async-mode writers\n * from the Stage-1 sidecar (`mcp/jobs/job-result-store.ts`) to this\n * field, then the sidecar files become legacy that the next cleanup\n * sweep can remove.\n */\n result: z.unknown().optional(),\n /**\n * Cancellation marker (#3043 / epic #2631 Stage 2). Set by `cancel_job`\n * — the running tool checks for this at safe-point boundaries (between\n * steps, between waves) and aborts via the AbortSignal plumbing from\n * #3035 / #3038. Append-only by construction (the reducer ignores a\n * second cancellation event).\n */\n cancellation: TaskCancellationSchema.optional(),\n /**\n * Creation timestamp (#3090 / epic #2631). Set by the reducer to the\n * `init` entry's `ts` and never mutated thereafter — `updatedAt` advances\n * with each write, but `createdAt` is fixed. Job-result readers need the\n * original creation time; `updatedAt` alone can't supply it once any\n * transition has been recorded. Optional for backward-compat with\n * pre-#3090 logs (the reducer backfills it from the init entry).\n */\n createdAt: z.iso.datetime().optional(),\n updatedAt: z.iso.datetime(),\n});\nexport type StructuredTaskState = z.infer<typeof StructuredTaskStateSchema>;\n\n/** Log entry types for the append-only journal. */\nexport const StructuredTaskLogEntrySchema = z.discriminatedUnion('event', [\n z.object({\n event: z.literal('init'),\n ts: z.iso.datetime(),\n state: StructuredTaskStateSchema,\n }),\n z.object({\n event: z.literal('decision'),\n ts: z.iso.datetime(),\n decision: TaskDecisionSchema,\n }),\n z.object({\n event: z.literal('blocker'),\n ts: z.iso.datetime(),\n blocker: TaskBlockerSchema,\n }),\n z.object({\n event: z.literal('blocker_resolved'),\n ts: z.iso.datetime(),\n /** Index of the blocker in the state's blockers[] array. */\n blockerIndex: z.number().int().nonnegative(),\n resolvedAt: z.iso.datetime(),\n }),\n z.object({\n event: z.literal('stage'),\n ts: z.iso.datetime(),\n stage: TaskStageSchema,\n }),\n z.object({\n event: z.literal('position'),\n ts: z.iso.datetime(),\n position: TaskPositionSchema,\n }),\n // Magentic-One Task Ledger replacement event — the outer loop revises the\n // entire ledger atomically when replanning. Always replaces, never partial.\n z.object({\n event: z.literal('task_ledger'),\n ts: z.iso.datetime(),\n ledger: TaskLedgerSchema,\n }),\n // Magentic-One Progress Ledger append event — one self-reflection per step.\n z.object({\n event: z.literal('progress_ledger'),\n ts: z.iso.datetime(),\n entry: ProgressLedgerEntrySchema,\n }),\n // #3043 / epic #2631 Stage 2 — tool result payload set when stage flips\n // to 'complete'. Written by appendResult; replayed into state.result.\n // The payload itself is `unknown` because each tool's result shape is\n // its own; readers cast after a status check.\n z.object({\n event: z.literal('result'),\n ts: z.iso.datetime(),\n result: z.unknown(),\n }),\n // #3043 / epic #2631 Stage 2 — cancellation marker. Append-only: the\n // reducer ignores a second cancellation event so a malicious or buggy\n // double-cancel can't rewrite the requestedAt timestamp.\n z.object({\n event: z.literal('cancellation'),\n ts: z.iso.datetime(),\n cancellation: TaskCancellationSchema,\n }),\n]);\nexport type StructuredTaskLogEntry = z.infer<typeof StructuredTaskLogEntrySchema>;\n","/**\n * Pipeline-bus → job heartbeat bridge (#6162).\n *\n * Pipeline bodies (`run_pipeline`, `run_dev_pipeline`, `run`, `orchestrate`)\n * already emit `stage.*` / `model.called` / `pipeline.*` events on the global\n * pipeline event bus as they progress. Rather than threading `progress()` into\n * every stage registry, `runAsJob` subscribes ONCE per job and treats any bus\n * event emitted from inside that job's async context as its heartbeat.\n *\n * Attribution is the load-bearing part. The bus is process-wide, so a naive\n * subscription would let a concurrent pipeline keep a wedged job alive — the\n * exact misreport the heartbeat exists to prevent. `runJobInBackground` runs\n * the body under `withAsyncTaskStateDispatch(jobId)`, an `AsyncLocalStorage`\n * scope that every await, timer and subprocess callback inside the body\n * inherits, and the bus invokes handlers synchronously inside `emit`; so the\n * store read in the handler names the job whose body emitted the event.\n *\n * Empty case: a body that emits nothing on either bus and never calls\n * `progress()` gets no heartbeat from this bridge — under a long guard it is\n * wedged by definition, which is the point.\n *\n * @module mcp/jobs/job-heartbeat-bridge\n */\n\nimport { currentAsyncDispatchJobId } from '../../context/structured-task-state.js';\nimport { stepBus } from '../../core/step-bus.js';\nimport { getPipelineEventBus } from '../../pipeline/event-bus.js';\nimport type { Unsubscribe } from '../../pipeline/event-types.js';\n\n/**\n * Subscribe `progress` to every pipeline-bus event AND every `stepBus` step\n * event emitted from inside `jobId`'s async context. The step bus carries\n * `withStep` activity — agent model calls, expert executions — which is how\n * `orchestrate`'s main phase (the Orchestrator agent's sequential model calls,\n * #6428) proves it is moving; `agents/heartbeat-monitor.ts` reads the same\n * signal for its session-health report. Returns the unsubscribe;\n * `runJobInBackground` calls it in its `finally` so a settled job stops\n * listening.\n */\nexport function bridgePipelineEventsToHeartbeat(jobId: string, progress: () => void): Unsubscribe {\n const onOwnEvent = (): void => {\n if (currentAsyncDispatchJobId() === jobId) progress();\n };\n const unsubscribePipeline = getPipelineEventBus().subscribe({}, onOwnEvent);\n stepBus.on('step', onOwnEvent);\n return () => {\n unsubscribePipeline();\n stepBus.off('step', onOwnEvent);\n };\n}\n","/**\n * Per-tool async-job concurrency cap (#3044 / epic #2631 Stage 3).\n *\n * Tracks in-flight async-mode dispatches in-process so a noisy caller\n * can't queue 1,000 long-running `run_workflow` invocations behind a\n * slow CLI and exhaust adapter slots. The cap is per-tool (each\n * registered tool gets its own slot count) and per-process — restarting\n * the MCP server resets the count, which is fine because the orphan\n * background promises die with it.\n *\n * Configuration order, lowest priority first:\n * 1. The per-tool default in `DEFAULT_JOB_CAPS` below.\n * 2. Environment override `NEXUS_JOB_MAX_CONCURRENT_<TOOL_UPPER>` —\n * tool name is uppercased + `_` for the env-var match. A value of\n * `0` disables async-mode for that tool entirely (`tryAcquire`\n * always returns busy).\n *\n * The Contrarian-vote flag from #3041 specifically asked for the cap\n * to land BEFORE async-mode expands past `orchestrate` (which has a\n * natural ceiling because it's depth-guarded). This module is the\n * primitive that satisfies that ask for `run_workflow` and later tools.\n *\n * @module mcp/jobs/job-concurrency\n */\n\nimport { createLogger } from '../../core/index.js';\n\nconst logger = createLogger({ component: 'job-concurrency' });\n\n/**\n * Default concurrent-job caps per tool. Numbers are starting points\n * informed by typical workload shape, NOT measured ceilings — re-tune\n * after observing actual job duration distributions in #2703 telemetry.\n *\n * `0` would disable async-mode for that tool; absence means \"no cap\"\n * (currently no tool falls into this category).\n */\nexport const DEFAULT_JOB_CAPS: Readonly<Record<string, number>> = {\n orchestrate: 3,\n run_workflow: 3,\n consensus_vote: 2,\n execute_expert: 4,\n // #3726: run_dev_pipeline is a heavy multi-agent pipeline (plan→vote→\n // decompose→implement→qa→security, each a live LLM call). Cap low — 2\n // concurrent real runs already saturate adapter slots on most hosts.\n run_dev_pipeline: 2,\n // #3730: run_pipeline is a multi-stage adaptive orchestrator with per-stage\n // experts (live LLM calls). Same shape as run_dev_pipeline — cap low at 2.\n run_pipeline: 2,\n // #3731: pr_review fans out to 5 live LLM voters in parallel. Same heavy\n // multi-llm-panel shape as consensus_vote — cap low at 2.\n pr_review: 2,\n // #3731: supply_chain_tradeoff_panel fans out to up to 7 live LLM voters in\n // parallel. Same heavy multi-llm-panel shape as consensus_vote — cap low at 2.\n supply_chain_tradeoff_panel: 2,\n // #3732: execute_spec runs a full spec DAG pipeline (parse→decompose→compile\n // →execute→validate→analyze, live multi-agent execution). Heavy — cap low at 2.\n execute_spec: 2,\n // #3732: run_graph_workflow runs up to ~100 expert nodes with checkpoints.\n // Heavy multi-node pipeline — cap low at 2.\n run_graph_workflow: 2,\n // #3732: run (execute:true) dispatches the heaviest engines (dev-pipeline/\n // pipeline) via the MetaDispatcher. Same heavy-pipeline shape — cap low at 2.\n run: 2,\n};\n\n/**\n * Default total cross-tool cap (defensive backstop, #3046 Stage 5).\n * Per-tool caps prevent a noisy single tool; the global cap prevents\n * 5 tools × 3 jobs each from saturating the host's adapter slots.\n *\n * Env override: `NEXUS_JOB_MAX_CONCURRENT_TOTAL`. Defaults to 10 —\n * comfortably above the sum of per-tool defaults (3+3+2+4=12 is also\n * fine because no realistic workload fills every tool simultaneously)\n * but stops runaway parallel fan-outs.\n */\nexport const DEFAULT_GLOBAL_JOB_CAP = 10;\n\n/** In-flight count per tool. Reset on process restart. */\nconst inFlight = new Map<string, number>();\n\n/** Returns the configured per-tool cap — env override beats default. */\nexport function getJobCap(toolName: string): number {\n const envKey = `NEXUS_JOB_MAX_CONCURRENT_${toolName.toUpperCase()}`;\n const envValue = process.env[envKey];\n if (envValue !== undefined && envValue !== '') {\n const parsed = Number(envValue);\n if (Number.isInteger(parsed) && parsed >= 0) {\n return parsed;\n }\n logger.warn('Invalid env override for job cap — ignoring', {\n tool: toolName,\n envKey,\n envValue,\n });\n }\n return DEFAULT_JOB_CAPS[toolName] ?? DEFAULT_GLOBAL_JOB_CAP;\n}\n\n/**\n * Returns the global cross-tool cap (#3046 Stage 5). Env override:\n * `NEXUS_JOB_MAX_CONCURRENT_TOTAL`. A value of `0` disables async-mode\n * across ALL tools simultaneously.\n */\nexport function getGlobalJobCap(): number {\n const envValue = process.env['NEXUS_JOB_MAX_CONCURRENT_TOTAL'];\n if (envValue !== undefined && envValue !== '') {\n const parsed = Number(envValue);\n if (Number.isInteger(parsed) && parsed >= 0) {\n return parsed;\n }\n logger.warn('Invalid env override for global job cap — ignoring', {\n envKey: 'NEXUS_JOB_MAX_CONCURRENT_TOTAL',\n envValue,\n });\n }\n return DEFAULT_GLOBAL_JOB_CAP;\n}\n\n/** Sum of in-flight counts across all tools (Stage 5 observability). */\nexport function getTotalInFlight(): number {\n let total = 0;\n for (const count of inFlight.values()) total += count;\n return total;\n}\n\n/** Current in-flight count for a tool (testing + observability helper). */\nexport function getInFlight(toolName: string): number {\n return inFlight.get(toolName) ?? 0;\n}\n\n/**\n * Attempt to acquire one slot. Returns `true` on success (caller MUST\n * `release()` exactly once when the job finishes / fails). Returns\n * `false` when EITHER cap is full — per-tool cap OR cross-tool global\n * cap (#3046 Stage 5). Caller responds synchronously with the busy\n * envelope (`{ status: 'busy', retryAfterMs }`).\n *\n * Atomicity note: Node.js is single-threaded between awaits, so this\n * read-then-write pattern is safe as long as no `await` interleaves\n * — and it doesn't here.\n */\nexport function tryAcquire(toolName: string): boolean {\n const cap = getJobCap(toolName);\n // Cap of 0 disables async-mode for the tool.\n if (cap === 0) return false;\n const current = inFlight.get(toolName) ?? 0;\n if (current >= cap) return false;\n // #3046 Stage 5: global cap check. Prevents 5 tools × 3 jobs each\n // saturating adapter slots even when each per-tool cap is satisfied.\n const globalCap = getGlobalJobCap();\n if (globalCap === 0) return false;\n if (getTotalInFlight() >= globalCap) return false;\n inFlight.set(toolName, current + 1);\n return true;\n}\n\n/**\n * Release one slot. Idempotent only in the trivial sense (calling twice\n * is a bug — the counter would underflow). Callers should pair every\n * `tryAcquire` returning `true` with exactly one `release` in a\n * `finally` block to be safe on both success and rejection paths.\n */\nexport function release(toolName: string): void {\n const current = inFlight.get(toolName) ?? 0;\n if (current === 0) {\n logger.warn('release() called with no in-flight count — caller bug', { tool: toolName });\n return;\n }\n inFlight.set(toolName, current - 1);\n}\n\n/**\n * Suggested retry interval for a busy response. Linear in current\n * load — at full cap, suggest 30s; halved as load shrinks. Pure\n * convenience for clients implementing exponential backoff.\n */\nexport function suggestRetryAfterMs(toolName: string): number {\n const cap = getJobCap(toolName);\n if (cap === 0) return 0; // never retry — async-mode is disabled\n const current = inFlight.get(toolName) ?? 0;\n // 30s base, scaled by fullness (clamped to [5s, 60s]).\n const base = 30_000 * (current / Math.max(1, cap));\n return Math.min(60_000, Math.max(5_000, base));\n}\n\n/** Reset all counters. Test-only — do not call from production code. */\nexport function _resetForTests(): void {\n inFlight.clear();\n}\n","/**\n * Shared async-job dispatcher — `runAsJob` (#3729 / epic #2631).\n *\n * Three tools (orchestrate, run_workflow, consensus_vote) implemented the\n * async-mode dispatcher VERBATIM: resolve idempotency → tryAcquire (busy\n * envelope on cap) → writeJobPending → registerIdempotentJob → fire a\n * detached background `run` that writes complete/failed + releases the slot\n * in a `finally` → return a synchronous `{ status: 'pending', jobId }`\n * envelope. This module extracts that sequence once so new long-running\n * tools (run_dev_pipeline, run_pipeline, …) opt into async with a few lines.\n *\n * The dispatcher sequence is FIXED here; the only per-tool variation is the\n * envelope shape (some tools use `ToolResult` via toolSuccess/\n * toolStructuredError, run_workflow uses its structurally-identical\n * `ToolResponse`). Callers that need a non-default envelope supply\n * `toEnvelope`; the default builders reproduce the orchestrate/consensus_vote\n * `ToolResult` envelopes byte-for-byte so faithful migration is a drop-in.\n *\n * @module mcp/jobs/run-as-job\n */\n\nimport { getTimeProvider, type ILogger } from '../../core/index.js';\nimport { toolSuccess, toolStructuredError, type ToolResult } from '../tools/tool-result.js';\nimport {\n pruneJobRecordsIfDue,\n writeJobComplete,\n writeJobFailed,\n writeJobPending,\n heartbeatJob,\n readLastProgressMs,\n} from './job-result-store.js';\nimport { extractFailureDetail } from './job-failure-detail.js';\nexport { extractFailureDetail } from './job-failure-detail.js';\nimport { registerJobAbort, unregisterJobAbort } from './job-abort-registry.js';\nimport { bridgePipelineEventsToHeartbeat } from './job-heartbeat-bridge.js';\nimport { registerIdempotentJob, shortCircuitOrFreshJobId } from './job-idempotency.js';\nimport { release, suggestRetryAfterMs, tryAcquire } from './job-concurrency.js';\nimport { MCP_TIMEOUTS, resolveClassGuardMs } from '../../config/timeouts.js';\nimport { withAsyncTaskStateDispatch } from '../../context/structured-task-state.js';\n\n/**\n * Async-job-body runaway-guard (#3734). A backgrounded job body has NO MCP\n * request timeout (that is the point of async mode), so without a ceiling a\n * wedged `run` would hold its concurrency slot and pending record forever.\n * The `async-job-body` operation class (3600s by default) bounds it.\n *\n * Because the body has no MCP request, it is the one class NOT ceilinged by\n * `MCP_TIMEOUTS.maxMs` (#5995, panel option 1). `NEXUS_TIMEOUT_MULTIPLIER` and\n * `NEXUS_TIMEOUT_CLASS_ASYNC_JOB_BODY_MS` raise it up to the class override\n * ceiling (7200000ms); a value past that is clamped and reported at startup by\n * `findIneffectiveVars`. The default is unchanged — the extra hour is opt-in,\n * and it costs something: a job holds its concurrency slot for as long as it\n * runs. Past the standard ceiling that cost is bounded by liveness (#6162): the\n * body must heartbeat via `progress()` or be failed as wedged at\n * {@link ASYNC_JOB_BODY_WEDGED_MISSED_HEARTBEATS} missed intervals. The guard a\n * job actually runs under is logged once at job start so real job durations\n * can be judged against it.\n *\n * On expiry the job is recorded as failed with `runaway guard exceeded` and the\n * slot is released by the existing `finally`. This is a runaway-guard, not an\n * 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\n/**\n * Liveness for a body allowed past the standard MCP ceiling (#6162 item 1).\n *\n * #6159 let an operator raise the guard from `MCP_TIMEOUTS.maxMs` (3.6M) to the\n * 7.2M class ceiling, and the only signals over the extra hour were the start\n * log and the 0.5 WARN — both say time passed, neither says the body is alive.\n * So a guard ABOVE the standard ceiling requires the body to prove progress:\n * `runAsJob` hands it a `progress()` heartbeat, and a watchdog fails the job as\n * wedged exactly one silence budget after its last heartbeat — releasing its\n * concurrency slot and recording `failed`, well before the guard would. The\n * watchdog is lazy: a timer armed for one budget that, on firing, measures the\n * silence from the record and re-arms for the exact remainder, so the verdict\n * lands at `lastHeartbeat + budget` wherever the heartbeat fell (#6428: a\n * poller ticking per interval held the slot for up to four intervals when the\n * heartbeat landed just after a tick). A guard at or under the standard\n * ceiling is not watched: those bodies never opted into anything and keep\n * their pre-#6162 behaviour.\n *\n * Interval = guard / {@link ASYNC_JOB_BODY_HEARTBEAT_INTERVAL_DIVISOR}; wedged\n * after {@link ASYNC_JOB_BODY_WEDGED_MISSED_HEARTBEATS} intervals of silence,\n * i.e. 3/8 of the guard — under the 0.5 near-timeout WARN fraction, so a silent\n * body is released before the WARN that used to be its only signal. On the\n * smallest watched guard (just over 3.6M) that is ~22.5 min of silence; on the\n * 7.2M ceiling, 45 min. Both exceed the `multi-llm-panel` class guard (15 min),\n * the longest single unit a body composes, so a body that heartbeats between\n * units is never wedged by one slow-but-alive unit; only a unit hung past its\n * own guard is. Module-private constants, not env vars: nothing reads a knob,\n * and the tests pin the numbers.\n *\n * A body that never calls `progress()` under a watched guard is wedged BY\n * DEFINITION — that is the point: opting into a longer guard is not opting into\n * a longer hang. The empty case (no heartbeat ever recorded) is measured from\n * job start, so such a body fails at exactly N intervals after dispatch.\n *\n * Not the same instrument as `agents/heartbeat-monitor.ts`: that monitor is\n * in-memory and reporting-only — it classifies an agent SESSION as healthy /\n * stalled / unmeasured for logs and the dashboard, and acts on nothing. This\n * watchdog is per JOB, durable through the job record, and its verdict frees a\n * concurrency slot and settles a record a poller reads. Both consume the same\n * `stepBus` progress signal; they answer different questions.\n */\nconst ASYNC_JOB_BODY_HEARTBEAT_INTERVAL_DIVISOR = 8;\n\n/** Missed heartbeat intervals after which a watched body is failed as wedged. */\nconst ASYNC_JOB_BODY_WEDGED_MISSED_HEARTBEATS = 3;\n\n/** Heartbeat handle for one job body: the callback plus its watch's teardown. */\ninterface LivenessWatch {\n /** The body's heartbeat — stamps the record and re-arms the watchdog. */\n readonly progress: () => void;\n /** Disarms the watchdog (no-op when the guard was not watched). */\n readonly clear: () => void;\n}\n\n/**\n * Build the heartbeat for one body and, when `guardMs` exceeds the standard\n * MCP ceiling, the watchdog that enforces it. The stamp is written under every\n * guard — a poller wants slow-vs-stuck regardless — only the watchdog is\n * gated. `onWedged` receives the failure the job is recorded with.\n *\n * Every heartbeat — the callback, `heartbeatJob(jobId)`, a bridged bus event —\n * goes through `heartbeatJob`, which stamps the record; nothing else is kept in\n * memory. When the timer fires it measures the silence from the record (empty\n * case: from job start): under budget, it re-arms for exactly the remainder;\n * otherwise the verdict quotes what `get_job_result` shows. So a body that\n * keeps heartbeating costs one file read per silence budget, and a body that\n * stops is failed at `lastHeartbeat + budget`, not at the next poll tick.\n */\nfunction makeLivenessWatch(\n jobId: string,\n guardMs: number,\n onWedged: (err: Error) => void\n): LivenessWatch {\n const startedAtMs = getTimeProvider().now();\n const progress = (): void => {\n heartbeatJob(jobId);\n };\n if (guardMs <= MCP_TIMEOUTS.maxMs) return { progress, clear: () => {} };\n\n const intervalMs = Math.floor(guardMs / ASYNC_JOB_BODY_HEARTBEAT_INTERVAL_DIVISOR);\n const silenceBudgetMs = intervalMs * ASYNC_JOB_BODY_WEDGED_MISSED_HEARTBEATS;\n let timer: ReturnType<typeof setTimeout> | undefined;\n const arm = (ms: number): void => {\n timer = setTimeout(onFire, ms);\n // Like the guard timers: never keep the event loop alive for the watchdog.\n timer.unref();\n };\n const onFire = (): void => {\n const silentMs = getTimeProvider().now() - (readLastProgressMs(jobId) ?? startedAtMs);\n if (silentMs < silenceBudgetMs) {\n arm(silenceBudgetMs - silentMs);\n return;\n }\n onWedged(new Error(`wedged (no progress for ${String(silentMs)} ms)`));\n };\n arm(silenceBudgetMs);\n return {\n progress,\n clear: () => {\n clearTimeout(timer);\n },\n };\n}\n\ninterface GuardHandles {\n /**\n * Rejects when the guard window elapses, or — under a guard past the\n * standard MCP ceiling — when the body goes\n * {@link ASYNC_JOB_BODY_WEDGED_MISSED_HEARTBEATS} intervals without a\n * heartbeat (#6162). Never settles on clear.\n */\n readonly expired: Promise<never>;\n /** The body's heartbeat (#6162). */\n readonly progress: () => void;\n /** Cancels the guard, near-timeout and liveness timers. */\n readonly clear: () => void;\n}\n\n/**\n * Builds a guard that rejects with the runaway sentinel after `guardMs`, emits\n * a one-shot near-timeout WARN at {@link ASYNC_JOB_BODY_NEAR_TIMEOUT_THRESHOLD},\n * and — past the standard MCP ceiling — rejects earlier with the wedged\n * failure when the body stops heartbeating ({@link makeLivenessWatch}).\n */\nfunction makeAsyncBodyGuard(\n jobId: string,\n toolName: string,\n guardMs: number,\n logger: ILogger | undefined\n): GuardHandles {\n // The executor runs synchronously, so `reject` is the promise's own by the\n // time any timer below can fire.\n let reject: (err: Error) => void = () => {};\n const expired = new Promise<never>((_resolve, rej) => {\n reject = rej;\n });\n const warnTimer = setTimeout(\n () => {\n logger?.warn(`Async ${toolName} job approaching runaway guard`, {\n jobId,\n guardMs,\n thresholdFraction: ASYNC_JOB_BODY_NEAR_TIMEOUT_THRESHOLD,\n });\n },\n Math.floor(guardMs * ASYNC_JOB_BODY_NEAR_TIMEOUT_THRESHOLD)\n );\n const guardTimer = setTimeout(() => {\n reject(new 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 const liveness = makeLivenessWatch(jobId, guardMs, (err) => {\n reject(err);\n });\n return {\n expired,\n progress: liveness.progress,\n clear: () => {\n clearTimeout(guardTimer);\n clearTimeout(warnTimer);\n liveness.clear();\n },\n };\n}\n\n/**\n * Per-tool envelope builders. Every async dispatcher returns the same five\n * logical outcomes; only their wire shape differs. Supplying this lets a tool\n * that uses a different success/error factory (e.g. run_workflow's\n * `successResponse`/`errorResponse`) reuse the dispatcher unchanged.\n *\n * @template E - The tool's MCP envelope type (defaults to {@link ToolResult}).\n */\nexport interface JobEnvelopeBuilders<E> {\n /** `{ status: 'pending', jobId, pollTool, note }` — returned synchronously after dispatch. */\n readonly pending: (jobId: string) => E;\n /** `{ status: 'busy', retryAfterMs, note }` — concurrency cap reached. */\n readonly busy: (retryAfterMs: number, toolName: string) => E;\n /** `{ status: 'replay', jobId, pollTool, note }` — idempotency key matched a prior dispatch. */\n readonly replay: (jobId: string) => E;\n /** Error envelope — idempotency key reused with different inputs. */\n readonly collision: (existingJobId: string) => E;\n}\n\n/** Default pending envelope (orchestrate/consensus_vote shape). */\nexport function defaultPendingEnvelope(jobId: string): ToolResult {\n return toolSuccess(\n JSON.stringify({\n status: 'pending',\n jobId,\n pollTool: 'get_job_result',\n note: 'Poll via get_job_result({ jobId }) until status !== \"pending\".',\n })\n );\n}\n\n/** Default busy envelope (orchestrate/consensus_vote shape). */\nexport function defaultBusyEnvelope(retryAfterMs: number, toolName: string): ToolResult {\n return toolSuccess(\n JSON.stringify({\n status: 'busy',\n retryAfterMs,\n note: `Async-mode concurrency cap reached for ${toolName}. Retry later or use dispatch: \"sync\".`,\n })\n );\n}\n\n/** Default replay envelope (orchestrate/consensus_vote shape). */\nexport function defaultReplayEnvelope(jobId: string): ToolResult {\n return toolSuccess(\n JSON.stringify({\n status: 'replay',\n jobId,\n pollTool: 'get_job_result',\n note: 'Idempotency key matched a prior dispatch — poll get_job_result for current status.',\n })\n );\n}\n\n/** Default collision envelope (orchestrate/consensus_vote shape). */\nexport function defaultCollisionEnvelope(existingJobId: string): ToolResult {\n return toolStructuredError({\n errorCategory: 'validation',\n message: `Idempotency key already used with different inputs. Existing jobId: ${existingJobId}. Use a fresh key or omit it.`,\n });\n}\n\n/** The full default ({@link ToolResult}) envelope set. */\nexport const DEFAULT_JOB_ENVELOPES: JobEnvelopeBuilders<ToolResult> = {\n pending: defaultPendingEnvelope,\n busy: defaultBusyEnvelope,\n replay: defaultReplayEnvelope,\n collision: defaultCollisionEnvelope,\n};\n\n/**\n * Parameters for {@link runAsJob}.\n *\n * @template I - The tool's validated input type (hashed for idempotency,\n * passed to `run`).\n * @template R - The structured result `run` resolves to; recorded verbatim\n * via `writeJobComplete` and returned by a later `get_job_result(jobId)`.\n * @template E - The tool's envelope type (defaults to {@link ToolResult}).\n */\nexport interface RunAsJobParams<I, R, E = ToolResult> {\n /** MCP tool name — the idempotency / concurrency / job-store key. */\n readonly toolName: string;\n /** Validated tool input. Hashed for idempotency + passed to `run`. */\n readonly input: I;\n /** Caller-supplied idempotency key (optional). */\n readonly idempotencyKey?: string | undefined;\n /** Mints a fresh jobId when no idempotency short-circuit applies. */\n readonly freshJobId: () => string;\n /**\n * The detached background work. Receives the resolved `jobId` (so the\n * runner can thread it into a task-state log), the `input`, and an\n * `AbortSignal` (#4086) that fires when `cancel_job` cancels this job —\n * thread it into awaited operations to make cancellation actually stop the\n * work. The fourth argument is the body's heartbeat (#6162): call\n * `progress()` after each unit of work (a seat, a stage, a fetch) to stamp\n * `lastProgressAt` on the pending record. Under a guard past the standard\n * MCP ceiling (`MCP_TIMEOUTS.maxMs`) the heartbeat is REQUIRED — a body that\n * goes {@link ASYNC_JOB_BODY_WEDGED_MISSED_HEARTBEATS} intervals without one\n * is failed as wedged and its slot released; a body that never calls it is\n * wedged by definition. Each call is a synchronous sidecar write, so call it\n * per unit of work, not per token. Existing 2- and 3-arg callbacks remain\n * valid (trailing params are ignored). Its resolved value is recorded as the\n * job's `complete` result; a rejection is recorded as `failed`.\n */\n readonly run: (jobId: string, input: I, signal: AbortSignal, progress: () => void) => Promise<R>;\n /** Per-tool envelope builders. Defaults to the {@link ToolResult} set. */\n readonly toEnvelope?: JobEnvelopeBuilders<E>;\n /** Optional logger for the background failure path. */\n readonly logger?: ILogger | undefined;\n /**\n * Opt out of the fail-closed result check (#4363), stating why.\n *\n * By default a `run` callback that RESOLVES a failure-shaped payload records\n * the job `failed` rather than `complete`. A handful of tools legitimately\n * resolve such a payload as their real answer — `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. `pruneJobRecordsIfDue` (#6224), then `writeJobPending` +\n * `registerIdempotentJob` (when a key was supplied).\n * 4. Fire-and-forget `run(jobId, input)`: on resolve `writeJobComplete`,\n * on reject `writeJobFailed`, `release` in a `finally`.\n * 5. Return the `pending` envelope (`{ status: 'pending', jobId, … }`).\n *\n * The background promise is intentionally not awaited — async mode exists\n * precisely because awaiting it would defeat the contract. Its rejection is\n * caught + recorded; nothing escapes unhandled.\n *\n * @returns The synchronous envelope: `pending` on dispatch, `busy` on cap,\n * `replay`/`collision` on an idempotency match.\n */\nexport function runAsJob<I, R, E = ToolResult>(params: RunAsJobParams<I, R, E>): E {\n const env = params.toEnvelope ?? (DEFAULT_JOB_ENVELOPES as unknown as JobEnvelopeBuilders<E>);\n\n // Step 1: idempotency resolves BEFORE the slot acquire.\n const idempotency = shortCircuitOrFreshJobId<E>({\n tool: params.toolName,\n idempotencyKey: params.idempotencyKey,\n inputs: params.input,\n freshJobId: params.freshJobId,\n replayEnvelope: env.replay,\n collisionEnvelope: env.collision,\n });\n if (idempotency.kind === 'shortCircuit') return idempotency.value;\n\n // Step 2: per-tool concurrency cap. Over-cap returns busy synchronously.\n if (!tryAcquire(params.toolName)) {\n return env.busy(suggestRetryAfterMs(params.toolName), params.toolName);\n }\n\n const jobId = idempotency.jobId;\n // Step 3: retention sweep, then pending record + idempotency index entry.\n // #6224: the store had no reaper (#4976 gap 2), so every dispatch left a\n // record forever. Bounded to one sweep per process per hour inside the\n // store; a failed sweep is logged there and never blocks the dispatch.\n pruneJobRecordsIfDue(getTimeProvider().now());\n // #4972: record whether this tool can even receive a cancel. `run.length`\n // is the callback's declared arity, so >= 3 means it takes the `signal`\n // parameter. Structural, not behavioural — see `signalAccepted`'s doc.\n writeJobPending(jobId, params.toolName, params.run.length >= 3, params.producerVersion);\n if (params.idempotencyKey !== undefined && params.idempotencyKey !== '') {\n registerIdempotentJob({\n tool: params.toolName,\n idempotencyKey: params.idempotencyKey,\n inputs: params.input,\n jobId,\n });\n }\n\n // Step 4: detached background run with terminal recording + slot release.\n void runJobInBackground(jobId, params);\n\n // Step 5: synchronous pending envelope.\n return env.pending(jobId);\n}\n\n/**\n * Fire-and-forget background runner. Exported (awaitable) so integration\n * tests can drive the dispatch deterministically instead of racing the\n * detached promise.\n * @internal\n */\nfunction settleJobResult<I, R, E>(\n jobId: string,\n params: RunAsJobParams<I, R, E>,\n result: unknown\n): void {\n const failure = detectFailureShapedResult(result);\n if (failure !== null && params.allowFailureShapedResult === undefined) {\n writeJobFailed(\n jobId,\n params.toolName,\n describeFailureShape(failure),\n params.producerVersion,\n extractFailureDetail(result)\n );\n return;\n }\n if (failure !== null) {\n params.logger?.warn(\n `Recorded a failure-shaped ${params.toolName} result as complete (opted out)`,\n { jobId, key: failure.key, reason: params.allowFailureShapedResult }\n );\n }\n writeJobComplete(jobId, params.toolName, result, params.producerVersion);\n}\n\n/**\n * Detached executor for `runAsJob`. Exported for tests so a test can drive\n * the background run deterministically without racing the dispatch envelope.\n *\n * @internal\n */\nexport async function runJobInBackground<I, R, E>(\n jobId: string,\n params: RunAsJobParams<I, R, E>\n): Promise<void> {\n const guardMs = resolveClassGuardMs(ASYNC_JOB_BODY_GUARD_CLASS);\n // Once per job, at info: the guard is operator-tunable (#5995), so the value\n // a job actually ran under is the record, not the config that produced it.\n params.logger?.info(`Async ${params.toolName} job started under runaway guard`, {\n jobId,\n guardMs,\n guardClass: ASYNC_JOB_BODY_GUARD_CLASS,\n });\n const guard = makeAsyncBodyGuard(jobId, params.toolName, guardMs, params.logger);\n // #4086: register an AbortController so cancel_job can stop this job's work. Its\n // signal is threaded into params.run; abort → run rejects → writeJobFailed, which\n // no-ops against the already-written `cancelled` record (#4022), preserving it.\n const controller = registerJobAbort(jobId);\n // #6162: pipeline bodies heartbeat through the stage events they already\n // emit; attributed to this job by the async context the body runs under.\n const unbridge = bridgePipelineEventsToHeartbeat(jobId, guard.progress);\n try {\n // Race the body against the runaway-guard. On guard expiry the guard\n // rejects with 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, guard.progress)\n );\n const result = await Promise.race([body, guard.expired]);\n // #4363: `writeJobComplete` used to fire on ANY resolved value, so a\n // callback resolving a failure-shaped payload recorded `complete` and a\n // caller polling `get_job_result` read it as a success. Fail closed by\n // default — an opt-in predicate was rejected because \"caller forgot to\n // normalize\" would just become \"caller forgot to pass the predicate\".\n settleJobResult(jobId, params, result);\n } catch (err: unknown) {\n const errObj = err instanceof Error ? err : new Error(String(err));\n params.logger?.error(`Async ${params.toolName} dispatch failed`, errObj, { jobId });\n writeJobFailed(\n jobId,\n params.toolName,\n errObj.message,\n params.producerVersion,\n extractFailureDetail(err)\n );\n } finally {\n unbridge();\n guard.clear();\n unregisterJobAbort(jobId);\n release(params.toolName);\n }\n}\n"],"mappings":"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","names":["z","logger","logger","crypto","z","z","z","z","z","logger","logger","z","z","logger","resolve","logger","logger","z","z","path","logger","z","z","z","z","z","logger","err","logger","logger","logger","logger","logger","z","logger","z","z","logger","appendFileSync","existsSync","mkdirSync","readFileSync","dirname","isAbsolute","resolve","join","resolve","resolve","join","path","logger","existsSync","resolve","isAbsolute","resolved","mkdirSync","dirname","appendFileSync","readFileSync","parsed","mkdirSync","dirname","readFileSync","statSync","randomBytes","path","delay","appendFileSync","readFileSync","existsSync","logger","existsSync","readFileSync","appendFileSync","logger","path","mkdirSync","dirname","defaultLogger","logger","defaultLogger","logger","logger","existsSync","unlinkSync","writeFileSync","mkdirSync","dirname","z","createHash","existsSync","readFileSync","writeFileSync","z","logger","z","createHash","path","existsSync","writeFileSync","readFileSync","err","existsSync","readFileSync","join","join","path","logger","readFileSync","err","existsSync","z","z","logger","z","mkdirSync","dirname","path","writeFileSync","existsSync","existsSync","err","logger","path","unlinkSync","fs","z","logger","FILE_MODE","DIR_MODE","logger","logger","logger","logger","logger","err","randomUUID","logger","z"]}
|