From dca293a446fa86767fb4bed6fe734f09b6cfafde Mon Sep 17 00:00:00 2001 From: morluto <76467478+morluto@users.noreply.github.com> Date: Tue, 29 Sep 2026 10:53:17 +0800 Subject: [PATCH] refactor(evidence): remove session ledger quotas --- docs/user-visible-errors.csv | 1 - src/application/BinarySessionPort.ts | 7 +- src/application/BinarySessionRecords.ts | 13 +-- src/application/EvidenceBundleCommands.ts | 5 +- .../EvidenceLedger.residualUnknown.test.ts | 22 ++--- src/application/EvidenceLedger.test.ts | 78 +++++++-------- src/application/EvidenceLedger.ts | 97 ++----------------- src/domain/analysisErrorPresentation.ts | 5 - src/domain/analysisErrorProjection.ts | 4 - src/domain/errors.ts | 13 --- src/server/sessionEvidence.ts | 5 +- 11 files changed, 61 insertions(+), 189 deletions(-) diff --git a/docs/user-visible-errors.csv b/docs/user-visible-errors.csv index f1ada69cf..9d1a248f0 100644 --- a/docs/user-visible-errors.csv +++ b/docs/user-visible-errors.csv @@ -17,7 +17,6 @@ harm_rank,location,trigger,current_copy,user_risk,proposed_replacement,implement 16,src/domain/errors.ts:AnalysisTimeoutError,Analysis deadline expires,"Analysis operation timed out after {timeoutMs}ms: {operation}",Exposes internal deadline and operation; weak recovery,"Analysis took too long. Try a smaller request, then run `rea doctor` if it continues.",implemented,focused assertions passed; full `npm run check` passed 17,src/domain/errors.ts:HopperTimeoutError,Provider deadline expires,"Hopper did not respond within {timeoutMs}ms",Exposes provider and internal deadline,"Analysis took too long. Try a smaller request, then run `rea doctor` if it continues.",implemented,focused assertions passed; full `npm run check` passed 18,src/domain/errors.ts:ProviderSelectionError,Deep-provider selection fails,"Analysis provider selection failed ({reason}) for {requestedProviderId}; candidates: {candidateIds}",Retains non-secret local selection context that needs a safe structured projection,Reason-specific guidance with stable candidate IDs and actionable rejection diagnostics,implemented,focused registry/CLI/MCP assertions passed; full `npm run check` passed -19,src/domain/errors.ts:EvidenceLimitError,Evidence ledger limit reached,"Evidence ledger {limit} limit exceeded ({maximum})",Exposes internal storage model,"Evidence is too large for this session. Reduce the evidence set and try again.",implemented,focused assertions passed; full `npm run check` passed 20,src/domain/errors.ts:AnalysisInputError,Parsed analysis input invalid,"Invalid analysis input for {operation}",Exposes operation identifier and lacks correction,"Analysis input is invalid. Check the arguments and try again.",implemented,focused assertions passed; full `npm run check` passed 21,src/domain/errors.ts:AnalysisCancelledError,Caller cancels analysis,"Analysis operation was cancelled: {operation}",Exposes operation identifier,"Analysis was cancelled. Start it again when ready.",implemented,focused assertions passed; full `npm run check` passed 22,src/domain/errors.ts:HopperCancelledError,Caller cancels provider request,Hopper operation was cancelled,Exposes provider name,"Analysis was cancelled. Start it again when ready.",implemented,focused assertions passed; full `npm run check` passed diff --git a/src/application/BinarySessionPort.ts b/src/application/BinarySessionPort.ts index f333516af..3352f8be0 100644 --- a/src/application/BinarySessionPort.ts +++ b/src/application/BinarySessionPort.ts @@ -8,7 +8,6 @@ import type { AnalysisProviderSelector } from "../contracts/providerSelection.js import type { AnalysisError, EvidenceIntegrityError, - EvidenceLimitError, UnknownRegistryError, } from "../domain/errors.js"; import type { Result } from "../domain/result.js"; @@ -45,13 +44,11 @@ export interface BinarySessionPort extends AnalysisOperationPort { activeTarget(): BinaryTarget | undefined; recordEvidence( evidence: Evidence, - ): Result<"added" | "duplicate", EvidenceIntegrityError | EvidenceLimitError>; + ): Result<"added" | "duplicate", EvidenceIntegrityError>; hasEvidence(evidenceId: string): boolean; evidenceById(evidenceId: string): Evidence | undefined; exportEvidenceBundle(): EvidenceBundle; - importEvidenceBundle( - bundle: unknown, - ): Result; + importEvidenceBundle(bundle: unknown): Result; exportAnalysisSnapshot(): Result; importAnalysisSnapshot( snapshot: AnalysisSnapshot, diff --git a/src/application/BinarySessionRecords.ts b/src/application/BinarySessionRecords.ts index 007e6ede9..aa483b5fd 100644 --- a/src/application/BinarySessionRecords.ts +++ b/src/application/BinarySessionRecords.ts @@ -6,7 +6,6 @@ import type { EvidenceBundle } from "../domain/evidenceBundle.js"; import { evidenceBundleForTarget } from "../domain/evidenceBundle.js"; import { EvidenceIntegrityError, - EvidenceLimitError, type AnalysisError, type UnknownRegistryError, } from "../domain/errors.js"; @@ -36,10 +35,7 @@ export interface ActiveAnalysisBinding { /** Owns session evidence, snapshots, and residual unknowns. */ export abstract class BinarySessionRecords { - readonly #evidence = new EvidenceLedger({ - maxRecords: 10_000, - maxBytes: 64 * 1024 * 1024, - }); + readonly #evidence = new EvidenceLedger(); readonly #snapshot = new AnalysisSnapshotCache(); #snapshotInvalidated = false; readonly #snapshotListeners = new Set<() => void | Promise>(); @@ -52,10 +48,7 @@ export abstract class BinarySessionRecords { recordEvidence( evidence: Evidence, - ): Result< - "added" | "duplicate", - EvidenceIntegrityError | EvidenceLimitError - > { + ): Result<"added" | "duplicate", EvidenceIntegrityError> { const recorded = this.#evidence.record(evidence); if (recorded.ok && recorded.value === "added") this.#emitSnapshotChanged(); return recorded; @@ -75,7 +68,7 @@ export abstract class BinarySessionRecords { importEvidenceBundle( bundle: unknown, - ): Result { + ): Result { const imported = this.#evidence.import(bundle); if (!imported.ok) return imported; if (imported.value.changed) this.#emitSnapshotChanged(); diff --git a/src/application/EvidenceBundleCommands.ts b/src/application/EvidenceBundleCommands.ts index d780e5135..4c1939222 100644 --- a/src/application/EvidenceBundleCommands.ts +++ b/src/application/EvidenceBundleCommands.ts @@ -16,7 +16,7 @@ import { writeEvidenceBundle, } from "./EvidenceBundleFiles.js"; -/** Validate and merge one bundle using the same bounded ledger as MCP. */ +/** Validate and merge one bundle using the session Evidence ledger. */ export const importEvidenceBundleCommand = async ( path: string, policy: EvidenceFilePolicy, @@ -72,8 +72,7 @@ export const compareEvidenceBundlesCommand = async (input: { } }; -const createLedger = (): EvidenceLedger => - new EvidenceLedger({ maxRecords: 10_000, maxBytes: 64 * 1024 * 1024 }); +const createLedger = (): EvidenceLedger => new EvidenceLedger(); const projectWrite = ( bundle: EvidenceBundle, diff --git a/src/application/EvidenceLedger.residualUnknown.test.ts b/src/application/EvidenceLedger.residualUnknown.test.ts index 3392454b6..6568adff0 100644 --- a/src/application/EvidenceLedger.residualUnknown.test.ts +++ b/src/application/EvidenceLedger.residualUnknown.test.ts @@ -16,8 +16,7 @@ import { } from "../domain/residualUnknown.js"; const provider = { id: "fixture", name: "Fixture", version: "1" }; -const ledger = (): EvidenceLedger => - new EvidenceLedger({ maxRecords: 1_000, maxBytes: 4 * 1024 * 1024 }); +const ledger = (): EvidenceLedger => new EvidenceLedger(); const evidence = ( label: string, confidence: "observed" | "derived" | "inferred" = "derived", @@ -110,13 +109,10 @@ describe("residual unknown registry reads and identity", () => { ).toMatchObject({ ok: true, value: { valid: false } }); }); - it("requires approval, derives stable IDs, filters heads, and rejects duplicate creation", () => { - expect(() => - recordUnknownInputSchema.parse({ - ...input("Is branch live?"), - approved: false, - }), - ).toThrow(); + it("derives stable IDs, filters heads, and rejects duplicate creation", () => { + expect(recordUnknownInputSchema.parse(input("Is branch live?"))).toEqual( + input("Is branch live?"), + ); const store = ledger(); const first = store.recordUnknown( input(" Is branch live? "), @@ -311,10 +307,10 @@ describe("residual unknown registry resolution and history", () => { expect(base.import(branch.export()).ok).toBe(false); expect(serializeEvidenceBundle(base.export())).toBe(before); - const bounded = new EvidenceLedger({ maxRecords: 1, maxBytes: 1_000_000 }); + const unbounded = new EvidenceLedger(); expect( - bounded.recordUnknown(input("Too many?"), mutation("bounded")).ok, - ).toBe(false); - expect(bounded.export()).toMatchObject({ records: [], unknowns: [] }); + unbounded.recordUnknown(input("No quota"), mutation("unbounded")).ok, + ).toBe(true); + expect(unbounded.export().unknowns).toHaveLength(1); }); }); diff --git a/src/application/EvidenceLedger.test.ts b/src/application/EvidenceLedger.test.ts index 36e5c94e3..bb50301b6 100644 --- a/src/application/EvidenceLedger.test.ts +++ b/src/application/EvidenceLedger.test.ts @@ -17,13 +17,13 @@ const TARGET: BinaryTarget = { const PROVIDER = { id: "fixture", name: "Fixture provider", version: "1" }; describe("evidence ledger recording", () => { - it("deduplicates and atomically imports bounded bundles", () => { + it("deduplicates and atomically imports bundles", () => { const evidence = createEvidence(TARGET, PROVIDER, { operation: "health", parameters: {}, result: true, }); - const ledger = new EvidenceLedger({ maxRecords: 1, maxBytes: 1_000_000 }); + const ledger = new EvidenceLedger(); expect(ledger.record(evidence)).toEqual({ ok: true, value: "added" }); expect(ledger.record(evidence)).toEqual({ ok: true, value: "duplicate" }); const relocated = createEvidence( @@ -56,7 +56,7 @@ describe("evidence ledger recording", () => { parameters: { beta: 2, alpha: 1 }, normalized_result: { beta: 2, alpha: 1 }, }); - const ledger = new EvidenceLedger({ maxRecords: 1, maxBytes: 1_000_000 }); + const ledger = new EvidenceLedger(); expect(ledger.record(evidence)).toEqual({ ok: true, value: "added" }); expect(ledger.record(reordered)).toEqual({ ok: true, @@ -64,41 +64,32 @@ describe("evidence ledger recording", () => { }); }); - it("returns typed record and byte limit failures without eviction", () => { - const first = createEvidence(TARGET, PROVIDER, { - operation: "health", - parameters: {}, - result: true, - }); - const second = createEvidence(TARGET, PROVIDER, { - operation: "health", - parameters: { changed: true }, - result: true, - }); - const recordBound = new EvidenceLedger({ - maxRecords: 1, - maxBytes: 1_000_000, - }); - expect(recordBound.record(first).ok).toBe(true); - expect(recordBound.record(second)).toMatchObject({ - ok: false, - error: { _tag: "EvidenceLimitError", limit: "records", maximum: 1 }, - }); - expect(recordBound.export().records).toEqual([first]); - - const byteBound = new EvidenceLedger({ maxRecords: 10, maxBytes: 1 }); - expect(byteBound.record(first)).toMatchObject({ - ok: false, - error: { _tag: "EvidenceLimitError", limit: "bytes", maximum: 1 }, - }); - expect(byteBound.export().records).toEqual([]); + it("retains more than ten thousand inline evidence records", () => { + const ledger = new EvidenceLedger(); + for (let index = 0; index < 10_001; index += 1) { + const record = createEvidence(TARGET, PROVIDER, { + operation: "health", + parameters: { index }, + result: true, + }); + expect(ledger.record(record)).toEqual({ ok: true, value: "added" }); + } + expect(ledger.export().records).toHaveLength(10_001); }); - it("counts unknown revisions when enforcing direct record limits", () => { - const ledger = new EvidenceLedger({ - maxRecords: 2, - maxBytes: 1_000_000, + it("retains inline evidence larger than the former session byte quota", () => { + const ledger = new EvidenceLedger(); + const record = createEvidence(TARGET, PROVIDER, { + operation: "health", + parameters: {}, + result: "x".repeat(64 * 1024 * 1024 + 1), }); + expect(ledger.record(record)).toEqual({ ok: true, value: "added" }); + expect(ledger.get(record.evidence_id)).toEqual(record); + }); + + it("retains Evidence alongside unknown revisions without a record quota", () => { + const ledger = new EvidenceLedger(); const mutation = createEvidence(undefined, PROVIDER, { predicateType: "rea.residual-unknown-mutation/v1", operation: "record_unknown", @@ -125,12 +116,9 @@ describe("evidence ledger recording", () => { parameters: {}, result: true, }); - expect(ledger.record(direct)).toMatchObject({ - ok: false, - error: { _tag: "EvidenceLimitError", limit: "records", maximum: 2 }, - }); + expect(ledger.record(direct)).toEqual({ ok: true, value: "added" }); expect(ledger.export()).toMatchObject({ - records: [mutation], + records: expect.arrayContaining([mutation, direct]), unknowns: [expect.objectContaining({ domain: "record-limit-test" })], }); }); @@ -138,7 +126,7 @@ describe("evidence ledger recording", () => { describe("evidence bundle imports", () => { it("rejects conflicting duplicate IDs without mutating the ledger", () => { - const ledger = new EvidenceLedger({ maxRecords: 2, maxBytes: 1_000_000 }); + const ledger = new EvidenceLedger(); const first = createEvidence(TARGET, PROVIDER, { operation: "health", parameters: {}, @@ -159,8 +147,8 @@ describe("evidence bundle imports", () => { expect(ledger.export().records).toEqual([first]); }); - it("atomically rejects Evidence plus unknown when the batch exceeds limits", () => { - const ledger = new EvidenceLedger({ maxRecords: 2, maxBytes: 1_000_000 }); + it("atomically rejects Evidence plus an invalid unknown", () => { + const ledger = new EvidenceLedger(); const output = createEvidence(undefined, PROVIDER, { operation: "derived", parameters: {}, @@ -177,7 +165,7 @@ describe("evidence bundle imports", () => { question: "What remains unresolved?", severity: "high", domain: "atomic-test", - supporting_evidence_ids: [], + supporting_evidence_ids: [`ev_${"f".repeat(64)}`], contradicting_evidence_ids: [], required_authority: "shipped-artifact", required_confidence: "observed", @@ -187,7 +175,7 @@ describe("evidence bundle imports", () => { }); expect(ledger.recordWithUnknown(output, unknown, mutation)).toMatchObject({ ok: false, - error: { _tag: "EvidenceLimitError" }, + error: { _tag: "UnknownRegistryError" }, }); expect(ledger.export()).toMatchObject({ records: [], unknowns: [] }); }); diff --git a/src/application/EvidenceLedger.ts b/src/application/EvidenceLedger.ts index ca0a4774d..aa5555c2b 100644 --- a/src/application/EvidenceLedger.ts +++ b/src/application/EvidenceLedger.ts @@ -8,7 +8,6 @@ import { } from "../domain/evidenceBundle.js"; import { EvidenceIntegrityError, - EvidenceLimitError, UnknownRegistryError, } from "../domain/errors.js"; import { parseEvidence, type Evidence } from "../domain/evidence.js"; @@ -22,12 +21,7 @@ import { } from "../domain/residualUnknown.js"; import { err, ok, type Result } from "../domain/result.js"; -export interface EvidenceLedgerLimits { - readonly maxRecords: number; - readonly maxBytes: number; -} - -type EvidenceLedgerFailure = EvidenceIntegrityError | EvidenceLimitError; +type EvidenceLedgerFailure = EvidenceIntegrityError; type RecordResult = Result<"added" | "duplicate", EvidenceLedgerFailure>; /** Describes the state changes made by one atomic bundle import. */ @@ -39,20 +33,11 @@ export interface EvidenceImportDelta { type ImportResult = Result; -/** Bounded, session-owned set of immutable evidence records. */ +/** Session-owned set of immutable evidence records. */ export class EvidenceLedger { readonly #records = new Map(); readonly #unknownRevisions = new Map(); readonly #unknownHeads = new Map(); - #bytes = 0; - - constructor(private readonly limits: EvidenceLedgerLimits) { - if (!Number.isSafeInteger(limits.maxRecords) || limits.maxRecords < 1) - throw new RangeError("maxRecords must be a positive safe integer"); - if (!Number.isSafeInteger(limits.maxBytes) || limits.maxBytes < 1) - throw new RangeError("maxBytes must be a positive safe integer"); - } - /** Record evidence idempotently; conflicting content is rejected. */ record(input: Evidence): RecordResult { let evidence: Evidence; @@ -71,18 +56,7 @@ export class EvidenceLedger { ? ok("duplicate") : err(new EvidenceIntegrityError("Conflicting evidence record")); } - if ( - this.#exceedsRecordLimit( - this.#records.size + 1, - this.#unknownRevisions.size, - ) - ) - return err(new EvidenceLimitError("records", this.limits.maxRecords)); - const bytes = serializedBytes(evidence); - if (this.#bytes + bytes > this.limits.maxBytes) - return err(new EvidenceLimitError("bytes", this.limits.maxBytes)); this.#records.set(evidence.evidence_id, evidence); - this.#bytes += bytes; return ok("added"); } @@ -132,7 +106,7 @@ export class EvidenceLedger { return err(checked.error); } const added = pending.size - this.#records.size; - this.#commit(pending, pendingUnknowns, checked.value); + this.#commit(pending, pendingUnknowns); return ok({ recordsAdded: added, unknownsAdded, @@ -165,10 +139,7 @@ export class EvidenceLedger { recordUnknown( input: RecordUnknownInput, mutationEvidence: Evidence, - ): Result< - ResidualUnknown, - EvidenceIntegrityError | EvidenceLimitError | UnknownRegistryError - > { + ): Result { let parsedMutation: Evidence; try { parsedMutation = parseEvidence(mutationEvidence); @@ -201,7 +172,7 @@ export class EvidenceLedger { mutationInput: Evidence, ): Result< ResidualUnknown | null, - EvidenceIntegrityError | EvidenceLimitError | UnknownRegistryError + EvidenceIntegrityError | UnknownRegistryError > { let evidence: Evidence; let mutation: Evidence; @@ -251,10 +222,7 @@ export class EvidenceLedger { updateUnknown( input: UpdateUnknownInput, mutationEvidence: Evidence, - ): Result< - ResidualUnknown, - EvidenceIntegrityError | EvidenceLimitError | UnknownRegistryError - > { + ): Result { const current = this.#unknownHeads.get(input.unknown_id); if (current === undefined) return err(new UnknownRegistryError("not-found")); @@ -317,16 +285,12 @@ export class EvidenceLedger { this.#records.clear(); this.#unknownRevisions.clear(); this.#unknownHeads.clear(); - this.#bytes = 0; } #appendUnknown( unknown: ResidualUnknown, mutationEvidenceInput: Evidence, - ): Result< - ResidualUnknown, - EvidenceIntegrityError | EvidenceLimitError | UnknownRegistryError - > { + ): Result { let mutationEvidence: Evidence; try { mutationEvidence = parseEvidence(mutationEvidenceInput); @@ -345,12 +309,8 @@ export class EvidenceLedger { #appendIncremental( records: readonly Evidence[], unknown?: ResidualUnknown, - ): Result< - void, - EvidenceIntegrityError | EvidenceLimitError | UnknownRegistryError - > { + ): Result { const additions = new Map(); - let addedBytes = 0; for (const evidence of records) { const existing = additions.get(evidence.evidence_id) ?? @@ -361,22 +321,11 @@ export class EvidenceLedger { continue; } additions.set(evidence.evidence_id, evidence); - addedBytes += serializedBytes(evidence); } const unknownKey = unknown === undefined ? undefined : unknownRevisionKey(unknown); if (unknownKey !== undefined && this.#unknownRevisions.has(unknownKey)) return err(new UnknownRegistryError("integrity")); - const unknownBytes = unknown === undefined ? 0 : serializedBytes(unknown); - if ( - this.#exceedsRecordLimit( - this.#records.size + additions.size, - this.#unknownRevisions.size + (unknown === undefined ? 0 : 1), - ) - ) - return err(new EvidenceLimitError("records", this.limits.maxRecords)); - if (this.#bytes + addedBytes + unknownBytes > this.limits.maxBytes) - return err(new EvidenceLimitError("bytes", this.limits.maxBytes)); if (unknown !== undefined) try { validateResidualUnknownAddition( @@ -395,30 +344,13 @@ export class EvidenceLedger { this.#unknownRevisions.set(unknownKey, unknown); this.#unknownHeads.set(unknown.unknown_id, unknown); } - this.#bytes += addedBytes + unknownBytes; return ok(undefined); } #validateCandidate( records: ReadonlyMap, unknowns: ReadonlyMap, - ): Result< - number, - EvidenceIntegrityError | EvidenceLimitError | UnknownRegistryError - > { - if (this.#exceedsRecordLimit(records.size, unknowns.size)) - return err(new EvidenceLimitError("records", this.limits.maxRecords)); - const bytes = - [...records.values()].reduce( - (total, evidence) => total + serializedBytes(evidence), - 0, - ) + - [...unknowns.values()].reduce( - (total, unknown) => total + serializedBytes(unknown), - 0, - ); - if (bytes > this.limits.maxBytes) - return err(new EvidenceLimitError("bytes", this.limits.maxBytes)); + ): Result { try { parseEvidenceBundle( createEvidenceBundle([...records.values()], [...unknowns.values()]), @@ -426,17 +358,12 @@ export class EvidenceLedger { } catch (cause: unknown) { return err(new UnknownRegistryError("integrity", { cause })); } - return ok(bytes); - } - - #exceedsRecordLimit(recordCount: number, unknownCount: number): boolean { - return recordCount + unknownCount > this.limits.maxRecords; + return ok(undefined); } #commit( records: ReadonlyMap, unknowns: ReadonlyMap, - bytes: number, ): void { this.#records.clear(); for (const [id, evidence] of records) this.#records.set(id, evidence); @@ -448,13 +375,9 @@ export class EvidenceLedger { if (head === undefined || head.revision < unknown.revision) this.#unknownHeads.set(unknown.unknown_id, unknown); } - this.#bytes = bytes; } } -const serializedBytes = (value: Evidence | ResidualUnknown): number => - Buffer.byteLength(JSON.stringify(value), "utf8"); - const unknownRevisionKey = (unknown: ResidualUnknown): string => `${unknown.unknown_id}:${String(unknown.revision)}`; diff --git a/src/domain/analysisErrorPresentation.ts b/src/domain/analysisErrorPresentation.ts index 954e3972b..331c62c9c 100644 --- a/src/domain/analysisErrorPresentation.ts +++ b/src/domain/analysisErrorPresentation.ts @@ -6,7 +6,6 @@ import { ConfigurationError, EvidenceFileError, EvidenceIntegrityError, - EvidenceLimitError, HopperRemoteError, HopperProcessError, HopperStartError, @@ -133,7 +132,6 @@ const STATIC_ERROR_CATEGORIES: Readonly< AnalysisCapabilityUnavailableError: "unsupported_provider", ProviderSelectionError: "unsupported_provider", EvidenceIntegrityError: "integrity_mismatch", - EvidenceLimitError: "truncated", AnalysisCancelledError: "cancelled", HopperCancelledError: "cancelled", AnalysisTimeoutError: "timeout", @@ -158,8 +156,6 @@ export const analysisErrorUserMessage = (error: AnalysisError): string => { return artifactMessage(error.reason); if (error instanceof EvidenceIntegrityError) return "Evidence is invalid or has changed. Recreate or re-import it, then try again."; - if (error instanceof EvidenceLimitError) - return "Evidence is too large for this session. Reduce the evidence set and try again."; if (error instanceof EvidenceFileError) return evidenceFileMessage(error.reason); if (error instanceof WorkspaceStorageError) @@ -307,7 +303,6 @@ const KNOWN_ERROR_TAGS = { ArtifactOperationError: true, ProcessCaptureError: true, EvidenceIntegrityError: true, - EvidenceLimitError: true, EvidenceFileError: true, WorkspaceStorageError: true, UnknownRegistryError: true, diff --git a/src/domain/analysisErrorProjection.ts b/src/domain/analysisErrorProjection.ts index 307ddc64e..70206d78d 100644 --- a/src/domain/analysisErrorProjection.ts +++ b/src/domain/analysisErrorProjection.ts @@ -12,7 +12,6 @@ import { BinaryTargetError, BrowserObservationError, EvidenceFileError, - EvidenceLimitError, EvidenceReferenceError, HopperCancelledError, HopperProcessError, @@ -175,7 +174,6 @@ const STATIC_ERROR_CODES = { NoBinaryOpenError: "target_unavailable", BinaryTargetError: "target_unavailable", EvidenceIntegrityError: "evidence_integrity_mismatch", - EvidenceLimitError: "truncated", ProviderAdapterError: "execution_failure", HopperRemoteError: "execution_failure", } as const satisfies Readonly< @@ -266,8 +264,6 @@ const artifactStateErrorDetails = ( reason: error.reason, ...(error.reason === "limit" ? { truncated: true } : {}), }; - if (error instanceof EvidenceLimitError) - return { limit: error.limit, maximum: error.maximum, truncated: true }; if (error instanceof WorkspaceStorageError) return { operation: error.operation, reason: error.reason }; if (error instanceof UnknownRegistryError) return { reason: error.reason }; diff --git a/src/domain/errors.ts b/src/domain/errors.ts index e06c96c27..ae47b2a74 100644 --- a/src/domain/errors.ts +++ b/src/domain/errors.ts @@ -38,7 +38,6 @@ const ANALYSIS_ERROR_TAGS = [ "ArtifactOperationError", "ProcessCaptureError", "EvidenceIntegrityError", - "EvidenceLimitError", "EvidenceFileError", "WorkspaceStorageError", "UnknownRegistryError", @@ -319,18 +318,6 @@ export class EvidenceReferenceError extends EvidenceIntegrityError { } } -/** A bounded evidence ledger cannot accept more records or serialized bytes. */ -export class EvidenceLimitError extends AnalysisError { - readonly _tag = "EvidenceLimitError"; - - constructor( - readonly limit: "records" | "bytes", - readonly maximum: number, - ) { - super(`Evidence ledger ${limit} limit exceeded (${String(maximum)})`); - } -} - /** Evidence bundle filesystem access failed within the configured policy. */ export class EvidenceFileError extends AnalysisError { readonly _tag = "EvidenceFileError"; diff --git a/src/server/sessionEvidence.ts b/src/server/sessionEvidence.ts index 51cd455f4..70615999d 100644 --- a/src/server/sessionEvidence.ts +++ b/src/server/sessionEvidence.ts @@ -2,14 +2,13 @@ import type { BinarySessionPort } from "../application/BinarySession.js"; import { EvidenceIntegrityError, EvidenceReferenceError, - type EvidenceLimitError, } from "../domain/errors.js"; import type { Evidence } from "../domain/evidence.js"; import { err, ok, type Result } from "../domain/result.js"; type EvidenceAuthorityResult = Result; -/** Resolve bounded IDs to authoritative records with exact semantic identity. */ +/** Resolve session IDs to authoritative records with exact semantic identity. */ export const resolveSessionEvidenceIds = ( session: BinarySessionPort, evidenceIds: readonly string[], @@ -61,7 +60,7 @@ export const resolveSessionEvidenceIds = ( export const recordSessionEvidenceSources = ( recordEvidence: BinarySessionPort["recordEvidence"] | undefined, sources: readonly Evidence[], -): Result => { +): Result => { for (const source of sources) { const recorded = recordEvidence?.(source); if (recorded !== undefined && !recorded.ok) return recorded;