@vostride/agent-qa-knowledge-local 0.0.1 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +105 -0
- package/NOTICE.md +15 -0
- package/assets/potion-retrieval-32m/LICENSE +29 -0
- package/assets/potion-retrieval-32m/golden-vectors.json +4144 -0
- package/assets/potion-retrieval-32m/manifest.json +37 -0
- package/assets/potion-retrieval-32m/potion-retrieval-32m.i8bin +0 -0
- package/assets/potion-retrieval-32m/tokenizer.json +63241 -0
- package/dist/embedder-worker/worker-entry.cjs +1424 -0
- package/dist/embedder-worker/worker-entry.cjs.map +1 -0
- package/dist/embedder-worker/worker-entry.d.cts +18 -0
- package/dist/embedder-worker/worker-entry.d.ts +18 -0
- package/dist/embedder-worker/worker-entry.js +1426 -0
- package/dist/embedder-worker/worker-entry.js.map +1 -0
- package/dist/index.cjs +21491 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +3983 -0
- package/dist/index.d.ts +3983 -0
- package/dist/index.js +21612 -0
- package/dist/index.js.map +1 -0
- package/dist/mark-evidence-plan-BCkYN07i.d.cts +1014 -0
- package/dist/mark-evidence-plan-BCkYN07i.d.ts +1014 -0
- package/dist/reader.cjs +5829 -0
- package/dist/reader.cjs.map +1 -0
- package/dist/reader.d.cts +107 -0
- package/dist/reader.d.ts +107 -0
- package/dist/reader.js +5951 -0
- package/dist/reader.js.map +1 -0
- package/dist/worker-registration-C-9spEsf.d.cts +78 -0
- package/dist/worker-registration-C-9spEsf.d.ts +78 -0
- package/package.json +69 -3
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,3983 @@
|
|
|
1
|
+
import { KnowledgePort } from '@vostride/agent-qa-agent';
|
|
2
|
+
import { KnowledgeHintReader } from '@vostride/agent-qa-runner';
|
|
3
|
+
import * as _vostride_agent_qa_schema from '@vostride/agent-qa-schema';
|
|
4
|
+
import { CurationSnapshotChange, CurationSnapshot, EntityKind, EmbeddingProfile, EntityDescriptor, EntityResolution, VerdictClass, QuarantineOperationsPort, ArtifactRef, MaskFn, CurationAuthorship, BundleDraft, BundleDiscriminant, OriginClass, ScreenState, BundleOutcomeEvent, BundleRelation, DistilledObservation, RecordId, BundleIdentityCore, GateReceipt, MeasurementObservation, PromotionReceipt, MeasurementBaseline, RetrievalTraceLeg, RecordedRetrievalRung, Anchor, IndexEntry, TrustPriorTable, CompletedRunHandoff, PerTestOutcome, StepEvidence, QuarantineLedgerEvent, RunAnalysisArtifact, Verdict, ScopeKey, ExecutionContext, BundleKind, FactSubtype, Delta, CurationFallbackReason, CompareAndSet, BundleStatus, ResolvePromotionPosture, PromotionGateHoldReason, PromotionPath, KnowledgeAcceptInput, KnowledgeRejectInput, KnowledgeForgetInput, KnowledgeMarkInput, KnowledgeProjection, KnowledgeReviewVerb, CommitReceipt, ForgetReceiptV1, KnowledgeTargetRef, DraftReceipt, MarkReceipt, OriginStage, NoDraftableFixChecked, MarkQuarantineClass, ImprovementPlan, Mark } from '@vostride/agent-qa-schema';
|
|
5
|
+
export { testFingerprintElements } from '@vostride/agent-qa-schema';
|
|
6
|
+
import { z } from 'zod';
|
|
7
|
+
import { I as IndexReaderConnection, E as EmbedderPort, a as IndexFace, K as KnowledgeReader, V as VecCapability, Q as QuarantineAppendOutcome, b as QuarantineDetectionSighting, R as RefusedQuarantineLine, r as readRebuildRequest, c as readIndexMaintenanceState, d as RebuildRequest, o as openKnowledgeReader, L as LoadedBundle, A as AppendMarkEvidenceOutcome } from './mark-evidence-plan-BCkYN07i.js';
|
|
8
|
+
export { e as AUTHORING_BRIEF_DEFAULT_BUDGET, f as AUTHORING_DENSE_K, g as AUTHORING_EXCERPT_CHAR_BUDGET, h as AUTHORING_EXEMPLAR_CAP, i as AUTHORING_PROCEDURE_CAP, j as AUTO_QUARANTINE_CLASSES, k as AssembleAuthoringBriefInput, l as AssembledAuthoringBrief, m as AuthoringEntryCandidate, n as AuthoringExemplarRow, p as AuthoringReaderDependencies, q as AuthoringTestRef, C as CHECKPOINT_EVERY_N_BUNDLES, s as CanaryPostureFacts, t as CanonicalBundleAnchorLookup, D as DenseHit, u as DenseSearchOptions, v as DiffSinceOptions, w as EnumeratedBundleDir, x as EvaluateQuarantineDetectionInput, G as GATES_REL_PATH, y as INDEX_DB_FILE, z as INDEX_RENDERING_SCHEMA_VERSION, B as INDEX_SCHEMA_VERSION, F as IndexHealth, H as IndexWriterHandle, J as InspectRecordsOptions, M as IntegrityReport, N as KnowledgeHit, O as KnowledgeMaintenanceScanError, P as KnowledgeMaintenanceScanIssue, S as KnowledgeRecordNotFoundError, T as KnowledgeSearchOptions, U as LoadBundleOutcome, W as LowerTrustShare, X as MARK_EVIDENCE_TOKEN_PREFIX, Y as MarkEvidenceEffect, Z as MarkEvidencePlan, _ as MarkEvidenceTarget, $ as Measurements, a0 as OpenKnowledgeReaderOptions, a1 as OpenServingKnowledgeReaderConfig, a2 as PlanMarkEvidenceInput, a3 as QUARANTINE_AUTO_EXIT_PASSES, a4 as QUARANTINE_CLASS_DISPOSITIONS, a5 as QUARANTINE_DEFAULT_EXPIRY_DAYS, a6 as QUARANTINE_ESCALATE_THRESHOLD, a7 as QUARANTINE_FLAG_FLOOR, a8 as QUARANTINE_LEDGER_FILENAME, a9 as QuarantineDetectionFailure, aa as QuarantineDetectionResult, ab as QuarantineDetectionTestWindow, ac as QuarantineDisposition, ad as QuarantineLedgerRead, ae as QuarantineOrdinalOutcome, af as READER_BUSY_TIMEOUT_MS, ag as REBUILD_MARKER_FILE, ah as REQUIRED_INDEX_TABLES, ai as ReadRebuildRequestOutcome, aj as RebuildReason, ak as RequestRebuildOptions, al as ScanBundleByIdOptions, am as ScanBundlesOptions, an as ShowRecordOptions, ao as StandingReceiptDigest, ap as WRITER_BUSY_TIMEOUT_MS, aq as assembleAuthoringBrief, ar as canaryPostureFactsFor, as as classifyIndexFace, at as clearRebuildRequest, au as createAuthoringReader, av as deriveBundleTrust, aw as diffSince, ax as embeddingProfileKey, ay as enumerateBundleDirs, az as evaluateQuarantineDetection, aA as foldQuarantineLedgerState, aB as indexDbPath, aC as inspectRecords, aD as isServable, aE as loadBundle, aF as lowerTrustSharesFor, aG as markEvidenceEvent, aH as openIndexReaderConnection, aI as openIndexWriter, aJ as openKnowledgeReader, aK as planMarkEvidence, aL as probeIndexHealth, aM as projectMarkEvidenceOutcome, aN as quarantineLedgerPath, aO as readCanonicalBundleAnchors, aP as readGateReceipts, aQ as readMeasurements, aR as readQuarantineLedger, aS as requestRebuild, aT as resolveActiveProfile, aU as resolveVecCapability, aV as scanBundleById, aW as scanBundles, aX as showRecord, aY as standingReceiptDigestsFor, aZ as toInspectRecordView, a_ as vecTableName, a$ as verifyBundleIntegrity } from './mark-evidence-plan-BCkYN07i.js';
|
|
9
|
+
import { DatabaseSync } from 'node:sqlite';
|
|
10
|
+
import { Tokenizer } from '@huggingface/tokenizers';
|
|
11
|
+
import { E as EmbedderWorkerRegistration, a as EmbedderWorkerIncarnationVerdict } from './worker-registration-C-9spEsf.js';
|
|
12
|
+
export { b as EMBEDDER_WORKER_REGISTRATION_FILE, c as EMBEDDER_WORKER_REGISTRATION_SCHEMA_VERSION, d as EMBEDDER_WORKER_REQUEST_TIMEOUT_MS, e as EMBEDDER_WORKER_START_TIMEOUT_MS, f as EMBEDDER_WORKER_TERM_GRACE_MS, g as EMBEDDER_WORKER_UNVERIFIABLE_INCARNATION, h as EmbedderWorkerTimeoutError, i as EmbedderWorkerTimeoutPhase, R as ReadEmbedderWorkerRegistrationOutcome, j as embedderWorkerProcessIsAlive, k as embedderWorkerSocketPath, p as probeEmbedderWorkerSocket, r as readEmbedderWorkerRegistration, l as removeEmbedderWorkerRegistration, w as writeEmbedderWorkerRegistration } from './worker-registration-C-9spEsf.js';
|
|
13
|
+
|
|
14
|
+
interface ReadCurationEffectsOptions {
|
|
15
|
+
knowledgeRoot: string;
|
|
16
|
+
sourceRunId: string;
|
|
17
|
+
observationIds?: readonly string[];
|
|
18
|
+
}
|
|
19
|
+
/** Read only successful, surviving effects; current status is never classification authority. */
|
|
20
|
+
declare function readCurationEffects(options: ReadCurationEffectsOptions): CurationSnapshotChange[];
|
|
21
|
+
/** One affected record, strongest classification, with all historical identities retained. */
|
|
22
|
+
declare function foldCurationSnapshot(effects: readonly CurationSnapshotChange[]): CurationSnapshot;
|
|
23
|
+
|
|
24
|
+
declare const PAYLOAD_BENEFITS: readonly ["exercised-benefited", "rode-along", "exercised-harmed"];
|
|
25
|
+
declare const PAYLOAD_STATE_VALIDITIES: readonly ["valid", "stale", "unknown"];
|
|
26
|
+
declare const canaryOutcomePayloadSchema: z.ZodObject<{
|
|
27
|
+
schemaVersion: z.ZodLiteral<2>;
|
|
28
|
+
benefit: z.ZodEnum<{
|
|
29
|
+
"exercised-benefited": "exercised-benefited";
|
|
30
|
+
"rode-along": "rode-along";
|
|
31
|
+
"exercised-harmed": "exercised-harmed";
|
|
32
|
+
}>;
|
|
33
|
+
stateValidity: z.ZodEnum<{
|
|
34
|
+
unknown: "unknown";
|
|
35
|
+
valid: "valid";
|
|
36
|
+
stale: "stale";
|
|
37
|
+
}>;
|
|
38
|
+
corpusDigest: z.ZodOptional<z.ZodString>;
|
|
39
|
+
observedStateDigest: z.ZodOptional<z.ZodString>;
|
|
40
|
+
ablation: z.ZodOptional<z.ZodObject<{
|
|
41
|
+
crossCheck: z.ZodEnum<{
|
|
42
|
+
inconclusive: "inconclusive";
|
|
43
|
+
flipped: "flipped";
|
|
44
|
+
held: "held";
|
|
45
|
+
"not-run": "not-run";
|
|
46
|
+
}>;
|
|
47
|
+
k: z.ZodNumber;
|
|
48
|
+
baseSeed: z.ZodNumber;
|
|
49
|
+
seeds: z.ZodArray<z.ZodNumber>;
|
|
50
|
+
seedHonored: z.ZodBoolean;
|
|
51
|
+
spend: z.ZodObject<{
|
|
52
|
+
modelCalls: z.ZodNumber;
|
|
53
|
+
screens: z.ZodNumber;
|
|
54
|
+
promptTokens: z.ZodNumber;
|
|
55
|
+
completionTokens: z.ZodNumber;
|
|
56
|
+
}, z.core.$strict>;
|
|
57
|
+
}, z.core.$strict>>;
|
|
58
|
+
jobKind: z.ZodLiteral<"canary-outcome">;
|
|
59
|
+
candidateId: z.ZodString;
|
|
60
|
+
runId: z.ZodString;
|
|
61
|
+
testId: z.ZodString;
|
|
62
|
+
testIndex: z.ZodNumber;
|
|
63
|
+
buildOrdinal: z.ZodNumber;
|
|
64
|
+
stepIndex: z.ZodNumber;
|
|
65
|
+
outcome: z.ZodEnum<{
|
|
66
|
+
positive: "positive";
|
|
67
|
+
negative: "negative";
|
|
68
|
+
}>;
|
|
69
|
+
exercisedAnchor: z.ZodType<_vostride_agent_qa_schema.Anchor, unknown, z.core.$ZodTypeInternals<_vostride_agent_qa_schema.Anchor, unknown>>;
|
|
70
|
+
attribution: z.ZodString;
|
|
71
|
+
briefDigest: z.ZodString;
|
|
72
|
+
}, z.core.$strict>;
|
|
73
|
+
type CanaryOutcomePayload = z.infer<typeof canaryOutcomePayloadSchema>;
|
|
74
|
+
type QueuedCanaryPayloadRead = {
|
|
75
|
+
kind: 'current';
|
|
76
|
+
payload: CanaryOutcomePayload;
|
|
77
|
+
} | {
|
|
78
|
+
kind: 'refused';
|
|
79
|
+
issues: string[];
|
|
80
|
+
};
|
|
81
|
+
declare function readQueuedCanaryPayload(value: unknown): QueuedCanaryPayloadRead;
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Stamped into `PRAGMA user_version` at creation and checked on every open.
|
|
85
|
+
*
|
|
86
|
+
* Stamp and hard-fail, never migrate — the 385 D-04 convention. The milestone ships nothing
|
|
87
|
+
* between its releases, so a ledger written by another build is a development artifact, and
|
|
88
|
+
* migration machinery for it would be code with no user that everything afterwards has to
|
|
89
|
+
* keep working. Note what this does NOT license: the ROWS are permanent regardless. A version
|
|
90
|
+
* refusal tells an operator to move a stale development file aside; it never rewrites one.
|
|
91
|
+
*/
|
|
92
|
+
declare const ADDRESSING_LEDGER_USER_VERSION = 2;
|
|
93
|
+
/**
|
|
94
|
+
* Busy timeout for every connection.
|
|
95
|
+
*
|
|
96
|
+
* D-02's story is "any process mints, sqlite arbitrates", which only works if a writer
|
|
97
|
+
* waiting on the write lock retries rather than failing immediately. Matched to the job
|
|
98
|
+
* store's window because the transactions are the same shape and size: retune from observed
|
|
99
|
+
* contention, not from a guess about how many hosts there are.
|
|
100
|
+
*/
|
|
101
|
+
declare const ADDRESSING_LEDGER_BUSY_TIMEOUT_MS = 2000;
|
|
102
|
+
/** The ledger's own file name under the agent-qa root, beside `agent-jobs.db` (D-02). */
|
|
103
|
+
declare const ADDRESSING_LEDGER_DB_FILE = "entity-addresses.db";
|
|
104
|
+
/** A ledger file this build cannot read. Refused before a single schema statement runs. */
|
|
105
|
+
declare class AddressingLedgerSchemaVersionError extends Error {
|
|
106
|
+
readonly path: string;
|
|
107
|
+
readonly expected: number;
|
|
108
|
+
readonly found: number;
|
|
109
|
+
constructor(path: string, expected: number, found: number);
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* An EXPLICITLY recorded target rename (D-03).
|
|
113
|
+
*
|
|
114
|
+
* There is no heuristic rename detection in this file and there must not be. Inferring that
|
|
115
|
+
* two target slugs are "the same target" from their spelling, their order of appearance or
|
|
116
|
+
* their contents is a guess, and ENTY-01's never-guess law is not weaker inside the ledger
|
|
117
|
+
* than it is inside the resolver — a wrong link here would silently re-point a published
|
|
118
|
+
* address, which is the exact failure D-02 exists to make impossible.
|
|
119
|
+
*/
|
|
120
|
+
interface TargetRename {
|
|
121
|
+
readonly fromSlug: string;
|
|
122
|
+
readonly toSlug: string;
|
|
123
|
+
readonly recordedAt: string;
|
|
124
|
+
}
|
|
125
|
+
/** A minted address: the durable mapping plus the short-ID it renders as. */
|
|
126
|
+
interface EntityAddress {
|
|
127
|
+
readonly kind: EntityKind;
|
|
128
|
+
readonly machineId: string;
|
|
129
|
+
/** Present for ordinal-addressed kinds; absent for slug-addressed ones (D-03). */
|
|
130
|
+
readonly ordinal?: number;
|
|
131
|
+
readonly shortId: string;
|
|
132
|
+
readonly mintedAt: string;
|
|
133
|
+
}
|
|
134
|
+
interface AddressingLedger {
|
|
135
|
+
/**
|
|
136
|
+
* Assign this machine id its permanent address, or return the one it already has.
|
|
137
|
+
*
|
|
138
|
+
* Idempotent by construction rather than by a caller-side check: the unique index decides,
|
|
139
|
+
* so two processes calling this at the same instant agree, and a caller that forgot to look
|
|
140
|
+
* first cannot create a second address.
|
|
141
|
+
*/
|
|
142
|
+
mint(kind: EntityKind, machineId: string): EntityAddress;
|
|
143
|
+
/** The address for a machine id, or `undefined` when it has never been sighted. */
|
|
144
|
+
lookup(kind: EntityKind, machineId: string): EntityAddress | undefined;
|
|
145
|
+
/** The address a published short-ID names, or `undefined`. Tier (a)'s whole job. */
|
|
146
|
+
lookupByShortId(shortId: string): EntityAddress | undefined;
|
|
147
|
+
/**
|
|
148
|
+
* Every address ever minted, in a fixed order (kind, then short-ID).
|
|
149
|
+
*
|
|
150
|
+
* READ-only, and the append-only law is what makes it worth having: this list only grows, so
|
|
151
|
+
* a caller enumerating it is reading a complete history rather than a snapshot that could
|
|
152
|
+
* have lost rows. The entity index is rebuilt FROM this (D-06) — a projection can only claim
|
|
153
|
+
* to heal if the thing it is rebuilt from can be enumerated in full.
|
|
154
|
+
*/
|
|
155
|
+
listAddresses(): EntityAddress[];
|
|
156
|
+
/**
|
|
157
|
+
* Record that a config target was renamed (D-03). See {@link TargetRename} for why this is
|
|
158
|
+
* the only way a link between two slugs ever comes to exist.
|
|
159
|
+
*
|
|
160
|
+
* Both slugs are minted, so both keep their own permanent address: the predecessor keeps
|
|
161
|
+
* the one already sitting in somebody's CI log, and the successor gets its own rather than
|
|
162
|
+
* inheriting one. Recording is idempotent — a repeat is the same fact, not a second one.
|
|
163
|
+
*/
|
|
164
|
+
recordTargetRename(fromSlug: string, toSlug: string): TargetRename;
|
|
165
|
+
/** The rename recorded FOR this slug, if any. Never the reverse direction. */
|
|
166
|
+
lookupTargetRename(fromSlug: string): TargetRename | undefined;
|
|
167
|
+
close(): void;
|
|
168
|
+
}
|
|
169
|
+
interface OpenAddressingLedgerOptions {
|
|
170
|
+
/** Absolute path to the ledger file, typically `<agentQaRoot>/entity-addresses.db`. */
|
|
171
|
+
readonly path: string;
|
|
172
|
+
/** ISO-8601 stamp source. Injected so mint times are deterministic under test. */
|
|
173
|
+
readonly now?: () => string;
|
|
174
|
+
readonly timeoutMs?: number;
|
|
175
|
+
}
|
|
176
|
+
declare function openAddressingLedger(options: OpenAddressingLedgerOptions): AddressingLedger;
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* The projection's own file name, beside the knowledge index rather than inside it.
|
|
180
|
+
*
|
|
181
|
+
* Beside, because an entity is not a learned fact (D-06). Its own file, because the knowledge
|
|
182
|
+
* index's schema version, rebuild and per-profile vec bookkeeping belong to records, and
|
|
183
|
+
* sharing them would have coupled two projections whose only similarity is their shape.
|
|
184
|
+
*/
|
|
185
|
+
declare const ENTITY_INDEX_DB_FILE = "entity-index.db";
|
|
186
|
+
/**
|
|
187
|
+
* Stamped into `PRAGMA user_version` at creation and checked on every open.
|
|
188
|
+
*
|
|
189
|
+
* Stamp and hard-fail, never migrate — the 385 D-04 house style. Migration would be effort
|
|
190
|
+
* spent on a file whose contents can be regenerated in full from the ledger; a refusal that
|
|
191
|
+
* says which version it found is more useful than a migration nobody would maintain.
|
|
192
|
+
*/
|
|
193
|
+
declare const ENTITY_INDEX_USER_VERSION = 2;
|
|
194
|
+
/**
|
|
195
|
+
* How often a standing daemon re-renders the projection from its sources (D-06).
|
|
196
|
+
*
|
|
197
|
+
* PROVISIONAL 600_000 (ten minutes); retune from operational evidence without adding config,
|
|
198
|
+
* the `LEASE_HEARTBEAT_TTL_MS` house style. What it is bounding is STALENESS of a title or a
|
|
199
|
+
* status in a fuzzy-match target — never correctness of an address, which the ledger owns and
|
|
200
|
+
* no cadence can affect. Sightings already refresh an entity the moment anything touches it,
|
|
201
|
+
* so this sweep exists for the entities nothing has touched since their source data moved.
|
|
202
|
+
*
|
|
203
|
+
* Deliberately its own interval rather than the daemon's `MAINTENANCE_CADENCE_MS`. That
|
|
204
|
+
* cadence runs the lease-holding maintenance tail; this sweep must never require the writer
|
|
205
|
+
* lease (D-02/D-06) because it writes only this file, and sharing a timer with lease-gated
|
|
206
|
+
* work would have made a lease-free projection stop being maintained the moment a lease was
|
|
207
|
+
* lost — a coupling nothing in the projection's own contract asks for.
|
|
208
|
+
*/
|
|
209
|
+
declare const ENTITY_INDEX_SWEEP_INTERVAL_MS = 600000;
|
|
210
|
+
declare class EntityIndexSchemaVersionError extends Error {
|
|
211
|
+
readonly path: string;
|
|
212
|
+
readonly supportedVersion: number;
|
|
213
|
+
readonly foundVersion: number;
|
|
214
|
+
constructor(path: string, supportedVersion: number, foundVersion: number);
|
|
215
|
+
}
|
|
216
|
+
interface EntityIndexHandle {
|
|
217
|
+
/** The connection shape the retrieval legs take. `vec` is pinned `brute` — see the header. */
|
|
218
|
+
readonly connection: IndexReaderConnection;
|
|
219
|
+
readonly path: string;
|
|
220
|
+
close(): void;
|
|
221
|
+
}
|
|
222
|
+
interface OpenEntityIndexOptions {
|
|
223
|
+
/** Absolute path to the projection file, typically `entityIndexDbPath(knowledgeRoot)`. */
|
|
224
|
+
readonly path: string;
|
|
225
|
+
/**
|
|
226
|
+
* The knowledge root the path lives under. When given, the path's directory chain must stay
|
|
227
|
+
* inside it (261003-mqc): a linked `memory/` or `memory/index/` is refused before the open.
|
|
228
|
+
*/
|
|
229
|
+
readonly knowledgeRoot?: string;
|
|
230
|
+
readonly timeoutMs?: number;
|
|
231
|
+
}
|
|
232
|
+
/** The projection's path: beside the knowledge index, never inside it. */
|
|
233
|
+
declare function entityIndexDbPath(knowledgeRoot: string): string;
|
|
234
|
+
declare function openEntityIndex(options: OpenEntityIndexOptions): EntityIndexHandle;
|
|
235
|
+
/**
|
|
236
|
+
* Project one entity into the index (D-06's incremental half).
|
|
237
|
+
*
|
|
238
|
+
* Called from the resolver's sighting/mint path, so every process posture — daemon, one-shot
|
|
239
|
+
* CLI, a test harness — maintains the projection by using it. Idempotent: re-projecting an
|
|
240
|
+
* unchanged entity leaves the same row.
|
|
241
|
+
*/
|
|
242
|
+
declare function refreshEntity(handle: EntityIndexHandle, descriptor: EntityDescriptor): void;
|
|
243
|
+
/**
|
|
244
|
+
* Drop everything and re-project from the supplied descriptor set (D-06's healing half).
|
|
245
|
+
*
|
|
246
|
+
* The set comes from the ledger plus the owning stores, which is what makes this a rebuild
|
|
247
|
+
* rather than a repair: nothing in this file is consulted to produce the new contents, so a
|
|
248
|
+
* file damaged in any way at all converges to the same result as a file that never existed.
|
|
249
|
+
* Embeddings are re-derived rather than carried, because a rebuild that preserved derived
|
|
250
|
+
* bytes would preserve exactly the state a rebuild is run to be rid of.
|
|
251
|
+
*/
|
|
252
|
+
declare function rebuildEntityIndex(handle: EntityIndexHandle, descriptors: Iterable<EntityDescriptor>): number;
|
|
253
|
+
interface EntityIndexSweepReport {
|
|
254
|
+
readonly examined: number;
|
|
255
|
+
readonly refreshed: number;
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Re-project the entities whose source data moved (D-06's maintenance-cadence half).
|
|
259
|
+
*
|
|
260
|
+
* A sweep is maintenance of a disposable projection, so it writes only where a row disagrees
|
|
261
|
+
* with its source. It never touches the addressing ledger — the ledger is not a projection
|
|
262
|
+
* (D-02) — and it takes no writer lease, because everything it writes lives in this file.
|
|
263
|
+
*/
|
|
264
|
+
declare function sweepEntityIndex(handle: EntityIndexHandle, descriptors: Iterable<EntityDescriptor>): EntityIndexSweepReport;
|
|
265
|
+
/**
|
|
266
|
+
* Embed every row whose rendering has no vector yet, returning how many were embedded.
|
|
267
|
+
*
|
|
268
|
+
* Separate from `refreshEntity` on purpose. Projecting an entity is synchronous and always
|
|
269
|
+
* possible; embedding one needs a model that a floor host may not have. Splitting them is what
|
|
270
|
+
* lets the degradation ladder work by omission — an index with no vectors simply serves its
|
|
271
|
+
* lexical leg, and the resolver rides that without a posture flag anywhere.
|
|
272
|
+
*
|
|
273
|
+
* A profile change invalidates every stored vector rather than mixing two geometries in one
|
|
274
|
+
* table, which is the same disposability law the records index applies to its own.
|
|
275
|
+
*/
|
|
276
|
+
declare function embedPendingEntities(handle: EntityIndexHandle, embedder: EmbedderPort, profile?: EmbeddingProfile): Promise<number>;
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* One store's answer to "do you own an entity with exactly this machine id?".
|
|
280
|
+
*
|
|
281
|
+
* A port rather than a switch over kinds, because each kind's machine ids live behind a
|
|
282
|
+
* different store and the tracer wires only one of them. 387-03 adds sources for the
|
|
283
|
+
* remaining kinds and neither this function nor its callers change.
|
|
284
|
+
*/
|
|
285
|
+
interface EntitySightingSource {
|
|
286
|
+
readonly kind: EntityKind;
|
|
287
|
+
/** The entity with this exact machine id, or `undefined`. Never a fuzzy match. */
|
|
288
|
+
sight(machineId: string): EntitySighting | undefined;
|
|
289
|
+
/** The entity a minted address maps back to, for rendering a ledger hit. */
|
|
290
|
+
hydrate(machineId: string): EntitySighting | undefined;
|
|
291
|
+
}
|
|
292
|
+
/** What a store reports about one of its entities. Facts only — no card, no address. */
|
|
293
|
+
interface EntitySighting {
|
|
294
|
+
readonly machineId: string;
|
|
295
|
+
readonly title: string;
|
|
296
|
+
/**
|
|
297
|
+
* The status as the OWNING store reports it. Validated against the kind's closed union at
|
|
298
|
+
* the card boundary (D-12), not here: this layer reports, the producer renders, and the
|
|
299
|
+
* schema refuses. Three responsibilities, three places.
|
|
300
|
+
*/
|
|
301
|
+
readonly statusSource: string;
|
|
302
|
+
}
|
|
303
|
+
interface ResolveEntityRefDeps {
|
|
304
|
+
readonly ledger: AddressingLedger;
|
|
305
|
+
readonly sources: readonly EntitySightingSource[];
|
|
306
|
+
/**
|
|
307
|
+
* The D-06 projection, maintained by USE.
|
|
308
|
+
*
|
|
309
|
+
* Optional, and that is the degradation ladder rather than a convenience: a composition that
|
|
310
|
+
* supplies no index gets tier (a) and the honest `none` arm, which is exactly what 387-01
|
|
311
|
+
* shipped. Nothing here silently becomes a guess when the projection is absent.
|
|
312
|
+
*/
|
|
313
|
+
readonly entityIndex?: EntityIndexHandle;
|
|
314
|
+
/** Test/integration seam for tier (b)'s dense leg; omission runs the acquisition ladder. */
|
|
315
|
+
readonly embedder?: EmbedderPort;
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* Every entity the ledger has ever addressed and a source can still describe.
|
|
319
|
+
*
|
|
320
|
+
* This is the set `rebuildEntityIndex` is rebuilt FROM and the set the daemon sweep re-renders
|
|
321
|
+
* (D-06). It reads the LEDGER, never the index: a projection rebuilt from itself would
|
|
322
|
+
* preserve exactly the state a rebuild is run to be rid of.
|
|
323
|
+
*
|
|
324
|
+
* An address whose source can no longer describe it is skipped rather than projected as a
|
|
325
|
+
* husk. The address keeps resolving through tier (a) either way — D-04's permanence lives in
|
|
326
|
+
* the ledger — but a row with no title is not something fuzzy text should ever match.
|
|
327
|
+
*/
|
|
328
|
+
declare function describeAllEntities(deps: ResolveEntityRefDeps): EntityDescriptor[];
|
|
329
|
+
/**
|
|
330
|
+
* THE sighting leg (D-01): exact machine-id equality, mint, project, describe.
|
|
331
|
+
*
|
|
332
|
+
* Extracted so the resolver's own leg and the LIST VERBS' sighting site are one mechanism
|
|
333
|
+
* rather than two that mint the same way today. D-01 names four sighting sites — a resolver
|
|
334
|
+
* hit, a card render, verdict authoring, a list verb — and a second minting path written for
|
|
335
|
+
* the fourth would be a second place where "first sighting mints" could stop being true, with
|
|
336
|
+
* nothing comparing them.
|
|
337
|
+
*
|
|
338
|
+
* `undefined` means no registered source recognises the id at all.
|
|
339
|
+
*
|
|
340
|
+
* EXACT equality, always. A prefix or case-insensitive comparison here would be tier (b)
|
|
341
|
+
* smuggled in below the never-guess contract. Sources are consulted in registered order so
|
|
342
|
+
* the answer does not depend on iteration accidents.
|
|
343
|
+
*/
|
|
344
|
+
declare function sightEntity(machineId: string, deps: ResolveEntityRefDeps): EntityResolution | undefined;
|
|
345
|
+
/**
|
|
346
|
+
* Resolve a reference through the three tiers, minting on first sighting (D-01).
|
|
347
|
+
*
|
|
348
|
+
* Order matters and is fixed: URI, then short-ID, then exact machine id, then — for free text
|
|
349
|
+
* only — the hybrid tiers. Addresses are tried before machine ids because an address is
|
|
350
|
+
* unambiguous by construction, and a machine id that happened to LOOK like a short-ID would
|
|
351
|
+
* otherwise be able to shadow a published address.
|
|
352
|
+
*
|
|
353
|
+
* ASYNC because tier (b)'s dense leg is: an embedding query cannot be made synchronous, and
|
|
354
|
+
* the alternative — a second, synchronous entry that quietly answers with tier (a) only —
|
|
355
|
+
* would be a resolver that under-answers depending on which function a caller happened to
|
|
356
|
+
* import. The PORT this reaches surfaces through was already asynchronous, so no composition
|
|
357
|
+
* edge changes shape.
|
|
358
|
+
*/
|
|
359
|
+
declare function resolveEntityRef(ref: string, deps: ResolveEntityRefDeps): Promise<EntityResolution>;
|
|
360
|
+
/**
|
|
361
|
+
* `entities.get`'s read path: the descriptor for an EXACT address, or `undefined`.
|
|
362
|
+
*
|
|
363
|
+
* Deliberately narrower than `resolveEntityRef` — it neither mints nor consults the sighting
|
|
364
|
+
* leg. `get` means "I already have the address", and a `get` that could mint would make every
|
|
365
|
+
* card render a potential write.
|
|
366
|
+
*/
|
|
367
|
+
declare function getEntityDescriptor(ref: string, deps: ResolveEntityRefDeps): EntityDescriptor | undefined;
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* The two leg weights, and they are EQUAL for a reason that is not aesthetic.
|
|
371
|
+
*
|
|
372
|
+
* The degradation invariant (D-08) says a floor host may only produce MORE disambiguation,
|
|
373
|
+
* never a different answer. Floor mode is full mode minus the dense leg, so each candidate's
|
|
374
|
+
* floor score is its full score minus its own dense contribution. With equal weights the most
|
|
375
|
+
* any candidate can gain from the dense leg is one rank-1 contribution, which is what bounds
|
|
376
|
+
* how far the dense leg can reorder the lexical ranking — and that bound is what
|
|
377
|
+
* `RESOLVER_STRONG_HIT_MARGIN` is set against. Weighting the dense leg above the lexical one
|
|
378
|
+
* (as the `semantic` query-class vector does for records) would let the dense leg invert an
|
|
379
|
+
* ordering by more than the margin, and floor mode could then resolve to a different entity.
|
|
380
|
+
*
|
|
381
|
+
* The resolver therefore owns its own weights rather than importing a query-class vector: this
|
|
382
|
+
* pair is load-bearing for a safety property, and a vector tuned for record retrieval has no
|
|
383
|
+
* obligation to stay equal.
|
|
384
|
+
*/
|
|
385
|
+
declare const RESOLVER_LEG_WEIGHT_LEXICAL = 1;
|
|
386
|
+
declare const RESOLVER_LEG_WEIGHT_DENSE = 1;
|
|
387
|
+
/**
|
|
388
|
+
* The fused score of a candidate ranked first in EVERY leg — the scale's maximum.
|
|
389
|
+
*
|
|
390
|
+
* Derived rather than typed out, so a `C_RRF` change or a weight change moves the scale and
|
|
391
|
+
* the thresholds below keep meaning what they say. Dividing by it turns the fused score into
|
|
392
|
+
* agreement on [0, 1]: 1 means every leg put this candidate first, and exactly 0.5 means one
|
|
393
|
+
* leg put it first and the other did not rank it at all.
|
|
394
|
+
*
|
|
395
|
+
* This is a rescale by a constant and nothing else — it preserves the ordering `fuseWeightedRrf`
|
|
396
|
+
* produced, and no ranking decision is taken here. It exists so a card can print a number next
|
|
397
|
+
* to tier (a)'s 1.0 without inventing a second vocabulary for confidence.
|
|
398
|
+
*/
|
|
399
|
+
declare const RESOLVER_FUSED_SCORE_NORMALIZER: number;
|
|
400
|
+
/**
|
|
401
|
+
* The absolute half of the D-07 rule: a strong hit is at the head of at least one leg.
|
|
402
|
+
*
|
|
403
|
+
* 0.5 is exactly one leg's rank-1 contribution on the normalised scale, and picking it says
|
|
404
|
+
* something narrow and true: a candidate that no leg ranked first is never a strong hit, no
|
|
405
|
+
* matter how far ahead of the runner-up it ended up. That case is reachable in practice — the
|
|
406
|
+
* index is refreshed on sighting, so it can hold a row for an entity whose owning store has
|
|
407
|
+
* since forgotten it; when that row heads a leg it is dropped after fusion, and the survivor
|
|
408
|
+
* behind it must NOT be promoted into a confident answer just because the leader vanished.
|
|
409
|
+
*
|
|
410
|
+
* Honest about its limits: on an RRF scale an absolute threshold cannot do much more than
|
|
411
|
+
* this. The fused top is always at least one leg's rank-1 contribution whenever any leg head
|
|
412
|
+
* survives, so a threshold below 0.5 would never fire, and a threshold above 0.5 would forbid
|
|
413
|
+
* a floor host from ever resolving anything — including a reference that matched exactly one
|
|
414
|
+
* entity. The discrimination work is therefore done by the margin below, which is where the
|
|
415
|
+
* two-part rule's second half earns its place rather than restating the first.
|
|
416
|
+
*
|
|
417
|
+
* The corpus report confirms both halves of that claim rather than only the comfortable one:
|
|
418
|
+
* 31 of its 110 cases resolve at the floor, so the threshold is not quietly forbidding the
|
|
419
|
+
* floor rung; and the case where a leg head is dropped after fusion still refuses, so it is not
|
|
420
|
+
* quietly permitting a survivor to inherit a leader's confidence.
|
|
421
|
+
*/
|
|
422
|
+
declare const RESOLVER_STRONG_HIT_MIN_SCORE = 0.5;
|
|
423
|
+
/**
|
|
424
|
+
* The margin half of the D-07 rule, and the number that makes a safety property structural.
|
|
425
|
+
*
|
|
426
|
+
* A candidate can gain at most 0.5 on the normalised scale by being ranked first in the dense
|
|
427
|
+
* leg. For floor mode (which has no dense leg) to resolve entity E while full mode resolves a
|
|
428
|
+
* DIFFERENT entity Z, the dense leg would have to move Z past E by more than twice the margin.
|
|
429
|
+
* Any margin above 0.25 therefore makes that impossible rather than unlikely: floor mode can
|
|
430
|
+
* only ever produce the same resolved entity or refuse to resolve at all. 0.26 is the pinned
|
|
431
|
+
* value with room above the bound so an adjacent-rank rounding difference cannot reach it.
|
|
432
|
+
*
|
|
433
|
+
* Its everyday meaning is simpler: a strong hit is one the legs AGREE on more than they agree
|
|
434
|
+
* on anything else. Two near-twins ranked 1 and 2 differ by 0.016 and always disambiguate —
|
|
435
|
+
* including the equal-strength typo case, which differs by exactly zero and therefore cannot
|
|
436
|
+
* be resolved by any positive margin at all (D-07).
|
|
437
|
+
*
|
|
438
|
+
* WHERE THE BOUNDARY ACTUALLY IS, measured by the 387-05 corpus rather than argued.
|
|
439
|
+
*
|
|
440
|
+
* The 0.25 above comes from a CONTINUOUS inequality, and this scale is not continuous. A floor
|
|
441
|
+
* host's score comes from the lexical leg alone, so its top is one leg's rank-1 contribution
|
|
442
|
+
* (0.5) and its runner-up, when it has one, is rank 2 (0.4919). The largest margin a floor host
|
|
443
|
+
* can therefore ever clear against a rival is the gap between two adjacent ranks — 1/124, about
|
|
444
|
+
* 0.00806 — and above that the floor can only resolve a reference that matched exactly ONE
|
|
445
|
+
* entity, which no dense leg can reorder. So the real bound is thirty times smaller than the
|
|
446
|
+
* one the paragraph above derives, and 0.26 clears both with room to spare.
|
|
447
|
+
*
|
|
448
|
+
* That is not a licence to lower it. The corpus runs its whole population through this same
|
|
449
|
+
* rule at several margins and reports what it finds: no divergence at 0.26, none at 1.5×1/124,
|
|
450
|
+
* and a real one BELOW 1/124, where a case whose two lexical candidates sit 0.008 apart resolves
|
|
451
|
+
* the first at the floor while the dense leg promotes the second in full. That measurement is
|
|
452
|
+
* what makes the invariant's test a gate rather than an arithmetic tautology — and it is only
|
|
453
|
+
* reachable because the decision is applied through one exported function (`applyStrongHitRule`)
|
|
454
|
+
* that the corpus can hand a different margin. Nothing in production passes it one.
|
|
455
|
+
*
|
|
456
|
+
* Retune only alongside `RESOLVER_STRONG_HIT_MIN_SCORE`, and only against the corpus report
|
|
457
|
+
* named at the top of this file: dropping below 1/124 trades the degradation guarantee for
|
|
458
|
+
* recall, and dropping to 0.25 or below gives up the argument that it cannot be traded at all.
|
|
459
|
+
*/
|
|
460
|
+
declare const RESOLVER_STRONG_HIT_MARGIN = 0.26;
|
|
461
|
+
/**
|
|
462
|
+
* How many candidates each leg is asked for.
|
|
463
|
+
*
|
|
464
|
+
* Larger than the top-3 a disambiguation card shows, because fusion needs to SEE the runner-up
|
|
465
|
+
* to refuse: a leg truncated at 3 would hide the competitor that should have turned a resolve
|
|
466
|
+
* into a disambiguation. Bounded because the entity corpus is bounded by what a human can name.
|
|
467
|
+
*/
|
|
468
|
+
declare const RESOLVER_CANDIDATE_K = 32;
|
|
469
|
+
/**
|
|
470
|
+
* The lexical admission floor for the ENTITY corpus, which is not the records corpus floor.
|
|
471
|
+
*
|
|
472
|
+
* `TAU_LEX` is 6.86, calibrated from a recorded serving replay over knowledge records. Measured
|
|
473
|
+
* against entity renderings on 2026-08-02, the entire observed positive BM25 range was 0.0 to
|
|
474
|
+
* 3.24 — an entity rendering is six words where a record rendering is a paragraph, so the two
|
|
475
|
+
* corpora are not on the same scale and `TAU_LEX` rejects EVERY entity lexical candidate. The
|
|
476
|
+
* dense leg keeps its own floor, `tau_dense`, which is profile-owned and therefore correct
|
|
477
|
+
* wherever it is applied; only the lexical floor is corpus-specific, and applying a record
|
|
478
|
+
* corpus's number here would have silently deleted the lexical leg.
|
|
479
|
+
*
|
|
480
|
+
* Zero means "the FTS query matched at all", and that is deliberately permissive. Under the
|
|
481
|
+
* never-guess rule a weak extra candidate can only ADD a runner-up, and a runner-up can only
|
|
482
|
+
* turn a resolve into a disambiguation — never into a different answer, because `lexicalLeg`
|
|
483
|
+
* orders by BM25, so a genuine match always outranks a noise match. Raising this floor would
|
|
484
|
+
* make small corpora answer `none` where several entities plainly do mention the word, which
|
|
485
|
+
* is a worse lie than an honest disambiguation card.
|
|
486
|
+
*/
|
|
487
|
+
declare const RESOLVER_LEXICAL_MIN_BM25 = 0;
|
|
488
|
+
|
|
489
|
+
/** Build the MEM sighting source over a knowledge root. */
|
|
490
|
+
declare function createMemorySightingSource(resolveKnowledgeRoot: () => string): EntitySightingSource;
|
|
491
|
+
|
|
492
|
+
/**
|
|
493
|
+
* Read side of the fingerprint-keyed recurrence window (Phase 390, D-07).
|
|
494
|
+
*
|
|
495
|
+
* `run_fingerprint_windows` is written by `applyRunOutcomes`; this module is the one place that
|
|
496
|
+
* queries it. Strictly read-only: prepared SELECTs, no statement that mutates a row, ever — the
|
|
497
|
+
* writer half stays whole in `run-outcomes.ts`, exactly as `run-outcome-read.ts` does for the
|
|
498
|
+
* per-test counters it is the sibling of.
|
|
499
|
+
*
|
|
500
|
+
* KEY LAW — a window row is addressed by `(product, fingerprint)`. Stable test identity
|
|
501
|
+
* `(product, filePath, testName)` travels ON the row because a crossing has to name the test it
|
|
502
|
+
* quarantines, but it is never part of the recurrence key: one fingerprint may be exercised by
|
|
503
|
+
* several tests, and D-07's rule is about the FAILURE recurring, not the test.
|
|
504
|
+
*
|
|
505
|
+
* THE WINDOW SLIDES OVER ORDINALS, NOT RUNS (D-07). Recurrence is counted over the ordinal range
|
|
506
|
+
* `[current - QUARANTINE_WINDOW_ORDINALS + 1, current]`:
|
|
507
|
+
*
|
|
508
|
+
* - two failing runs inside ONE build ordinal count once (the numerator counts DISTINCT ordinals),
|
|
509
|
+
* - a failure at ordinals 5/7/9 still crosses at 9 even though no two runs were consecutive,
|
|
510
|
+
* - and an occurrence that has slid out of the range is FORGIVEN. That is the whole point of a
|
|
511
|
+
* window: the lifetime `flake_count` never forgives, which is exactly why D-07 demoted it to a
|
|
512
|
+
* ranking input and made this the trigger substrate instead.
|
|
513
|
+
*
|
|
514
|
+
* `windowOrdinals` is the honest denominator: how many distinct ordinals in the range this product
|
|
515
|
+
* recorded a failure in at all. A caller renders "3rd occurrence in 5 builds" from the pair, and an
|
|
516
|
+
* empty window answers typed zeros rather than an absence a renderer has to guess about.
|
|
517
|
+
*
|
|
518
|
+
* PRECONDITION — the caller supplies a connection where `ensureRunOutcomeTables` has run (every
|
|
519
|
+
* `openIndexWriter` does). A read-only connection against a store predating these tables raises
|
|
520
|
+
* sqlite's `no such table`, which the composition layer folds to typed absence the same way it
|
|
521
|
+
* already does for `readTestOutcomeHistory`.
|
|
522
|
+
*/
|
|
523
|
+
|
|
524
|
+
/**
|
|
525
|
+
* §7.3's locked detection window, verbatim: the same fingerprint recurring within the last five
|
|
526
|
+
* build ordinals. A pinned constant with no config key (386 D-15) — retune it from operational
|
|
527
|
+
* evidence, in the source, where the change is reviewable. Plan 05's rule reads the threshold
|
|
528
|
+
* against this window; D-10's auto-exit is symmetric with it by design.
|
|
529
|
+
*/
|
|
530
|
+
declare const QUARANTINE_WINDOW_ORDINALS = 5;
|
|
531
|
+
/** The recurrence key: the failure, inside one product partition. */
|
|
532
|
+
interface FingerprintWindowIdentity {
|
|
533
|
+
product: string;
|
|
534
|
+
fingerprint: string;
|
|
535
|
+
}
|
|
536
|
+
/** One window row, as the writer stored it. */
|
|
537
|
+
interface FingerprintWindowRow {
|
|
538
|
+
product: string;
|
|
539
|
+
filePath: string;
|
|
540
|
+
testName: string;
|
|
541
|
+
fingerprint: string;
|
|
542
|
+
verdictClass: VerdictClass;
|
|
543
|
+
buildOrdinal: number;
|
|
544
|
+
runId: string;
|
|
545
|
+
}
|
|
546
|
+
interface FingerprintRecurrence {
|
|
547
|
+
/** DISTINCT build ordinals inside the window carrying this fingerprint. */
|
|
548
|
+
occurrenceOrdinals: number;
|
|
549
|
+
/** DISTINCT build ordinals inside the window carrying ANY failure for this product. */
|
|
550
|
+
windowOrdinals: number;
|
|
551
|
+
}
|
|
552
|
+
/**
|
|
553
|
+
* Every stored row for one fingerprint inside the bounded read scope, ordinal-ascending.
|
|
554
|
+
*
|
|
555
|
+
* The read scope is the last {@link LAST_OUTCOMES_LIMIT} ordinals rather than the detection window,
|
|
556
|
+
* so a caller that wants to SHOW the recent history (D-10's M-consecutive-passes exit, the list
|
|
557
|
+
* verb) sees the same depth the per-test outcome window carries. An identity the projection never
|
|
558
|
+
* recorded answers `[]` — typed absence, never a stand-in row.
|
|
559
|
+
*/
|
|
560
|
+
declare function readFingerprintWindow(db: DatabaseSync, identity: FingerprintWindowIdentity, currentBuildOrdinal: number): FingerprintWindowRow[];
|
|
561
|
+
/**
|
|
562
|
+
* One fingerprint's recurrence over the sliding ordinal window (D-07) — computed LIVE on every
|
|
563
|
+
* call, never stored. Both legs count DISTINCT ordinals, which is what makes two failing runs in
|
|
564
|
+
* one build one occurrence.
|
|
565
|
+
*/
|
|
566
|
+
declare function fingerprintRecurrence(db: DatabaseSync, identity: FingerprintWindowIdentity, currentBuildOrdinal: number): FingerprintRecurrence;
|
|
567
|
+
|
|
568
|
+
declare const LEASE_FILE = ".lease";
|
|
569
|
+
declare const EPOCH_FILE = ".epoch";
|
|
570
|
+
/** Provisional writer-heartbeat TTL; retune from operational evidence without adding config. */
|
|
571
|
+
declare const LEASE_HEARTBEAT_TTL_MS = 30000;
|
|
572
|
+
/** Bounded mutation-lock takeover; retune from operational evidence without adding config. */
|
|
573
|
+
declare const MUTATION_LOCK_TAKEOVER_MS = 45000;
|
|
574
|
+
/** Authority-store filename is pinned; retune only through a data-migration plan. */
|
|
575
|
+
declare const WRITER_AUTHORITY_DB_FILE = ".writer-authority.sqlite";
|
|
576
|
+
/**
|
|
577
|
+
* Provisional SQLite contention window; retune from operational evidence without adding config.
|
|
578
|
+
*
|
|
579
|
+
* The takeover deadline remains separate: this short timeout makes each failed write attempt
|
|
580
|
+
* observable so the contender can apply the lease and verified-termination policy.
|
|
581
|
+
*/
|
|
582
|
+
declare const MUTATION_LOCK_BUSY_TIMEOUT_MS = 2000;
|
|
583
|
+
/**
|
|
584
|
+
* Transient guard serializing the beat's read-check-write with release's read-check-delete.
|
|
585
|
+
*
|
|
586
|
+
* A directory holding exactly one `owner-<token>` file, published whole by renaming a staged
|
|
587
|
+
* directory into place. It lives under `memory/queue/`, which every scaffolded knowledge
|
|
588
|
+
* `.gitignore` already ignores, so neither a guard in use nor one a crash left behind is ever a
|
|
589
|
+
* commit-visible file in a user's knowledge repository (261002-lse follow-up; the user's
|
|
590
|
+
* `.gitignore` is never rewritten, D-22).
|
|
591
|
+
*/
|
|
592
|
+
declare const LEASE_GUARD_DIR = "memory/queue/lease-guard";
|
|
593
|
+
declare const writerLeaseSchema: z.ZodObject<{
|
|
594
|
+
leaseId: z.ZodString;
|
|
595
|
+
pid: z.ZodNumber;
|
|
596
|
+
epoch: z.ZodNumber;
|
|
597
|
+
heartbeatAtMs: z.ZodNumber;
|
|
598
|
+
}, z.core.$strict>;
|
|
599
|
+
type WriterLease = z.infer<typeof writerLeaseSchema>;
|
|
600
|
+
/** What the contender could observe about the owner it gave up on; never an authority claim. */
|
|
601
|
+
interface UnreclaimableMutationLockOwner {
|
|
602
|
+
pid: number;
|
|
603
|
+
acquiredAtMs: number;
|
|
604
|
+
generationToken: string;
|
|
605
|
+
/** False when the row carries no incarnation, which is why escalation could never fire. */
|
|
606
|
+
incarnationAttributed: boolean;
|
|
607
|
+
}
|
|
608
|
+
type AcquireWriterLeaseOutcome = {
|
|
609
|
+
kind: 'held';
|
|
610
|
+
holder: WriterLease;
|
|
611
|
+
} | {
|
|
612
|
+
kind: 'acquired';
|
|
613
|
+
leaseId: string;
|
|
614
|
+
epoch: number;
|
|
615
|
+
reclaimed?: WriterLease;
|
|
616
|
+
} | {
|
|
617
|
+
kind: 'refused';
|
|
618
|
+
reason: 'corrupt-epoch-state';
|
|
619
|
+
error: CorruptEpochStateError;
|
|
620
|
+
} | {
|
|
621
|
+
/**
|
|
622
|
+
* CR-01 (round 5): the lease file's own sibling of `corrupt-epoch-state`.
|
|
623
|
+
*
|
|
624
|
+
* `code` is the raw errno so an operator sees EACCES rather than a contender that silently
|
|
625
|
+
* spun to its deadline over an authority state nobody can evaluate; `error` keeps this arm
|
|
626
|
+
* inside the union's stated contract that every refusal is rethrowable.
|
|
627
|
+
*/
|
|
628
|
+
kind: 'refused';
|
|
629
|
+
reason: 'unreadable-lease-state';
|
|
630
|
+
code: string;
|
|
631
|
+
error: UnreadableWriterLeaseStateError;
|
|
632
|
+
} | {
|
|
633
|
+
kind: 'refused';
|
|
634
|
+
reason: 'mutation-lock-unreclaimable';
|
|
635
|
+
/**
|
|
636
|
+
* Both refusal arms carry a thrown-shaped `error` ON PURPOSE.
|
|
637
|
+
*
|
|
638
|
+
* Every caller of this union already renders `refused` as `[reason]: error.message` or
|
|
639
|
+
* rethrows it, so a new arm that also carries one is surfaced by name at every entry point —
|
|
640
|
+
* including any added later — without a list of call sites to keep in step. Naming the
|
|
641
|
+
* refusal is the requirement; enumerating the callers who must name it is the failure mode
|
|
642
|
+
* this phase keeps rediscovering.
|
|
643
|
+
*/
|
|
644
|
+
error: WriterLeaseUnreclaimableError;
|
|
645
|
+
attempts: number;
|
|
646
|
+
waitedMs: number;
|
|
647
|
+
observedOwner?: UnreclaimableMutationLockOwner;
|
|
648
|
+
observedLease?: WriterLease;
|
|
649
|
+
};
|
|
650
|
+
interface LeaseOperationOptions {
|
|
651
|
+
knowledgeRoot: string;
|
|
652
|
+
leaseId: string;
|
|
653
|
+
}
|
|
654
|
+
/** Test/chaos seam on the lease-file guard taken by `heartbeatLease` and `releaseLease`. */
|
|
655
|
+
interface LeaseGuardHooks {
|
|
656
|
+
/** Fires once, when the guard is first found held by a live section other than this caller's. */
|
|
657
|
+
onLeaseGuardContended?: () => void;
|
|
658
|
+
/** Fires each time a guard has been judged residue, before this caller reclaims it. */
|
|
659
|
+
beforeLeaseGuardReclaim?: () => void;
|
|
660
|
+
/** Fires inside a reclaim, after its first step and before its last. */
|
|
661
|
+
duringLeaseGuardReclaim?: () => void;
|
|
662
|
+
}
|
|
663
|
+
type HeartbeatLeaseOutcome = {
|
|
664
|
+
kind: 'heartbeated';
|
|
665
|
+
holder: WriterLease;
|
|
666
|
+
} | {
|
|
667
|
+
kind: 'refused';
|
|
668
|
+
reason: 'lease-missing' | 'lease-malformed'
|
|
669
|
+
/** CR-01: the lease exists and could not be opened — never write over what you cannot read. */
|
|
670
|
+
| 'lease-unreadable' | 'lease-id-mismatch' | 'stale-epoch' | 'corrupt-epoch-state';
|
|
671
|
+
holder?: WriterLease;
|
|
672
|
+
observedEpoch?: number;
|
|
673
|
+
error?: CorruptEpochStateError;
|
|
674
|
+
};
|
|
675
|
+
type ReleaseLeaseOutcome = {
|
|
676
|
+
kind: 'released';
|
|
677
|
+
} | {
|
|
678
|
+
kind: 'refused';
|
|
679
|
+
reason: 'lease-missing' | 'lease-malformed' | 'lease-unreadable' | 'lease-id-mismatch';
|
|
680
|
+
holder?: WriterLease;
|
|
681
|
+
};
|
|
682
|
+
/** Exact writer identity carried by governed maintenance mutators. */
|
|
683
|
+
interface WriterLeaseAuthority extends LeaseOperationOptions {
|
|
684
|
+
epoch: number;
|
|
685
|
+
}
|
|
686
|
+
type WriterAuthorityLostReason = Extract<HeartbeatLeaseOutcome, {
|
|
687
|
+
kind: 'refused';
|
|
688
|
+
}>['reason'] | 'epoch-mismatch-before-heartbeat' | 'epoch-mismatch-after-heartbeat' | 'mutation-lock-generation-lost';
|
|
689
|
+
/** Fail-closed maintenance refusal with the holder and fresh disk epoch attached. */
|
|
690
|
+
declare class WriterAuthorityLostError extends Error {
|
|
691
|
+
readonly name = "WriterAuthorityLostError";
|
|
692
|
+
readonly authority: WriterLeaseAuthority;
|
|
693
|
+
readonly reason: WriterAuthorityLostReason;
|
|
694
|
+
readonly observedEpoch: number;
|
|
695
|
+
constructor(authority: WriterLeaseAuthority, reason: WriterAuthorityLostReason, observedEpoch: number);
|
|
696
|
+
}
|
|
697
|
+
type CorruptEpochStateReason = 'unreadable' | 'malformed' | 'overflow';
|
|
698
|
+
/** Fail-closed authority-state error; callers must never substitute epoch zero for this state. */
|
|
699
|
+
declare class CorruptEpochStateError extends Error {
|
|
700
|
+
readonly name = "CorruptEpochStateError";
|
|
701
|
+
readonly path: string;
|
|
702
|
+
readonly reason: CorruptEpochStateReason;
|
|
703
|
+
readonly rawPreview: string;
|
|
704
|
+
constructor(path: string, reason: CorruptEpochStateReason, rawPreview: string);
|
|
705
|
+
}
|
|
706
|
+
/**
|
|
707
|
+
* Fail-closed acquisition refusal after the deadline; carries why the wait could not end well.
|
|
708
|
+
*
|
|
709
|
+
* A contender that gives up is reporting a fact about the SYSTEM, not about itself, so the
|
|
710
|
+
* diagnostics travel with the error: the owner it kept losing to, whether that owner was even
|
|
711
|
+
* attributable (an unattributed row can never be escalated against, which is usually the whole
|
|
712
|
+
* story), and the lease it kept reading. `agent-qa daemon` prints this and exits non-zero where it
|
|
713
|
+
* previously hung with no output at all.
|
|
714
|
+
*/
|
|
715
|
+
declare class WriterLeaseUnreclaimableError extends Error {
|
|
716
|
+
readonly name = "WriterLeaseUnreclaimableError";
|
|
717
|
+
readonly reason: "mutation-lock-unreclaimable";
|
|
718
|
+
readonly attempts: number;
|
|
719
|
+
readonly waitedMs: number;
|
|
720
|
+
readonly observedOwner?: UnreclaimableMutationLockOwner;
|
|
721
|
+
readonly observedLease?: WriterLease;
|
|
722
|
+
constructor(attempts: number, waitedMs: number, observedOwner?: UnreclaimableMutationLockOwner, observedLease?: WriterLease);
|
|
723
|
+
}
|
|
724
|
+
/**
|
|
725
|
+
* The lease file's sibling of `CorruptEpochStateError`, for a read that produced no throwable.
|
|
726
|
+
*
|
|
727
|
+
* `readFileSync` threw, but the value that reaches a consumer is a kinded outcome rather than an
|
|
728
|
+
* exception, and `AcquireWriterLeaseOutcome`'s own contract is that EVERY refusal arm carries a
|
|
729
|
+
* thrown-shaped `error` — three call sites rethrow or render it without knowing which arm they
|
|
730
|
+
* hold (`drain.ts:842` among them). A refusal that carried only an errno string would have made
|
|
731
|
+
* that contract a list of call sites to keep in step, which is the failure mode this module keeps
|
|
732
|
+
* rediscovering. Deliberately not re-exported from the package index (IN-04): the refusal is fully
|
|
733
|
+
* legible from `reason`, `code` and `error.message`.
|
|
734
|
+
*/
|
|
735
|
+
declare class UnreadableWriterLeaseStateError extends Error {
|
|
736
|
+
readonly name = "UnreadableWriterLeaseStateError";
|
|
737
|
+
readonly path: string;
|
|
738
|
+
readonly code: string;
|
|
739
|
+
constructor(path: string, code: string);
|
|
740
|
+
}
|
|
741
|
+
/**
|
|
742
|
+
* The authority-file read verdict, and it has four values rather than three.
|
|
743
|
+
*
|
|
744
|
+
* Round-5 CR-01: `unreadable` is the sibling of the epoch read's
|
|
745
|
+
* `CorruptEpochStateError(…, 'unreadable', …)`. A file that EXISTS and could not be opened is a
|
|
746
|
+
* different fact from a file that is not there and from a file whose bytes were read and failed to
|
|
747
|
+
* parse, and the previous three arms had nowhere to put it — so EACCES, EIO, EMFILE and ENFILE all
|
|
748
|
+
* landed on `malformed`, which every consumer reads as "nobody holds authority". `code` carries
|
|
749
|
+
* the errno so the refusal that follows can name the cause to an operator.
|
|
750
|
+
*/
|
|
751
|
+
type ReadWriterLeaseOutcome = {
|
|
752
|
+
kind: 'absent';
|
|
753
|
+
} | {
|
|
754
|
+
kind: 'malformed';
|
|
755
|
+
} | {
|
|
756
|
+
kind: 'unreadable';
|
|
757
|
+
code: string;
|
|
758
|
+
} | {
|
|
759
|
+
kind: 'parsed';
|
|
760
|
+
lease: WriterLease;
|
|
761
|
+
};
|
|
762
|
+
/**
|
|
763
|
+
* Opaque process-incarnation token for one pid, anchored OUTSIDE any value this module writes.
|
|
764
|
+
*
|
|
765
|
+
* CR-04: a durable row's pid is not an identity. Once the recorded process dies, the kernel is
|
|
766
|
+
* free to hand that number to a stranger, and every later decision keyed on the number alone
|
|
767
|
+
* (above all `SIGKILL`) targets whoever holds it now. The one fact that distinguishes them is
|
|
768
|
+
* assigned by the OS and cannot be forged from inside the store: when the process at that pid
|
|
769
|
+
* started.
|
|
770
|
+
*
|
|
771
|
+
* Linux reads field 22 (`starttime`) of `/proc/<pid>/stat`, counted from the LAST `)` because the
|
|
772
|
+
* `comm` field is parenthesised and may itself contain spaces and parentheses. Other POSIX hosts
|
|
773
|
+
* read `/bin/ps -p <pid> -o lstart=` in the C locale and UTC, so every reader renders one start
|
|
774
|
+
* time as one token. Windows has no equivalent builtin, so it resolves to `undefined` and every
|
|
775
|
+
* incarnation check there fails closed.
|
|
776
|
+
*
|
|
777
|
+
* Returns `undefined` — never throws — whenever the pid cannot be attributed. `undefined` means
|
|
778
|
+
* "do not signal", never "safe to signal".
|
|
779
|
+
*
|
|
780
|
+
* WR-04: `timeoutMs` bounds the POSIX arm's `ps` fork, which is the last wait beneath the
|
|
781
|
+
* acquisition deadline that used to be able to outlive it — a wedged `ps` never returns, and this
|
|
782
|
+
* resolution sits directly on the pre-signal path. A cap that expires resolves
|
|
783
|
+
* through the SAME funnel every other failure uses (`undefined`), so a timed-out resolution is
|
|
784
|
+
* unverifiable and therefore signal-ineligible. Callers with no budget of their own omit it.
|
|
785
|
+
*
|
|
786
|
+
* 386-32 consumes this same helper for the embedder-worker signal path, so both kill paths speak
|
|
787
|
+
* one incarnation vocabulary.
|
|
788
|
+
*/
|
|
789
|
+
declare function resolveProcessIncarnation(pid: number, timeoutMs?: number, psExecutable?: string): string | undefined;
|
|
790
|
+
interface MutationLockOptions {
|
|
791
|
+
/** Test/chaos seam after the claim is committed and before the held transaction begins. */
|
|
792
|
+
afterMutationLockClaimed?: (generationToken: string) => void;
|
|
793
|
+
afterMutationLockAcquired?: () => void;
|
|
794
|
+
/** Test/chaos seam inside acquisition, after the epoch rewrite and before lease publication. */
|
|
795
|
+
afterEpochRewrite?: () => void;
|
|
796
|
+
mutationLockTakeoverMs?: number;
|
|
797
|
+
/**
|
|
798
|
+
* Test-only observation of every process-incarnation resolution the escalation path performs.
|
|
799
|
+
*
|
|
800
|
+
* Purely an observer, never a replacement: the production resolver still runs, so what a test
|
|
801
|
+
* counts is what a daemon pays. It exists because the cost being bounded (a `ps` fork per
|
|
802
|
+
* resolution, on the caller's main thread) is invisible to any assertion about outcomes.
|
|
803
|
+
*/
|
|
804
|
+
onProcessIncarnationResolved?: (pid: number) => void;
|
|
805
|
+
psExecutable?: string;
|
|
806
|
+
}
|
|
807
|
+
interface AcquireWriterLeaseOptions extends MutationLockOptions {
|
|
808
|
+
/**
|
|
809
|
+
* Test/chaos seam for the pinned acquisition deadline; production never sets it.
|
|
810
|
+
*
|
|
811
|
+
* The same shape as `mutationLockTakeoverMs` and the heartbeat supervisor's `stopTimeoutMs`: a
|
|
812
|
+
* real unreclaimable wait is 60 s, which no test can afford to sit through, and shortening the
|
|
813
|
+
* window is the only way to reach the refusal branch (D-15 — a seam, never a config key).
|
|
814
|
+
*/
|
|
815
|
+
acquireDeadlineMs?: number;
|
|
816
|
+
}
|
|
817
|
+
interface CurrentWriterAuthority {
|
|
818
|
+
leaseId: string;
|
|
819
|
+
epoch: number;
|
|
820
|
+
}
|
|
821
|
+
interface CurrentWriterAuthorityHooks extends MutationLockOptions {
|
|
822
|
+
/** Test/chaos seam after the lock-held epoch comparison and before mutation. */
|
|
823
|
+
afterFinalAuthorityCompare?: () => void;
|
|
824
|
+
}
|
|
825
|
+
/**
|
|
826
|
+
* Read and strictly validate current writer authority without acquiring or refreshing it.
|
|
827
|
+
*
|
|
828
|
+
* CR-01 (round 5): ENOENT is the only read failure that is evidence of absence, and NO read
|
|
829
|
+
* failure is evidence of corruption. This is `readEpoch`'s rule applied to the file it was not
|
|
830
|
+
* applied to — the derivation's own W-01 note says the guard belongs at the READ, so that
|
|
831
|
+
* consumers inherit it rather than each re-deriving it, and this read has three consumers that
|
|
832
|
+
* select SIGKILL, epoch minting and registration deletion from its answer.
|
|
833
|
+
*
|
|
834
|
+
* The `existsSync` fallback that used to sit here is deleted rather than kept beside the errno
|
|
835
|
+
* test: under fd exhaustion it fails for the same reason the open did, so it degraded an EMFILE
|
|
836
|
+
* read from `malformed` to `absent` — the strongest possible statement that nobody holds the
|
|
837
|
+
* lease, produced by the weakest possible evidence.
|
|
838
|
+
*/
|
|
839
|
+
declare function readWriterLease(knowledgeRoot: string): ReadWriterLeaseOutcome;
|
|
840
|
+
/** Purely classify a guarded or untrusted lease value against one explicit wall-clock instant. */
|
|
841
|
+
declare function isLeaseStale(lease: unknown, nowMs: number): boolean;
|
|
842
|
+
/**
|
|
843
|
+
* The one freshness answer, and it has three values rather than two.
|
|
844
|
+
*
|
|
845
|
+
* CR-01: the previous derivation returned a boolean, so every way of failing to READ the epoch
|
|
846
|
+
* collapsed into the same value a genuinely expired lease produces. `readEpoch` raises
|
|
847
|
+
* `CorruptEpochStateError(…, 'unreadable', …)` for EACCES, EIO, EMFILE and ENFILE, not only for
|
|
848
|
+
* corrupt bytes, and fd exhaustion produces both that failure and the daemon identity-handshake
|
|
849
|
+
* failure at once. A live, healthy holder therefore became de-registrable and SIGKILL-eligible on
|
|
850
|
+
* a transient read error.
|
|
851
|
+
*
|
|
852
|
+
* `unknown` is deliberately NOT resolved to either boolean here. Resolving it toward "fresh" makes
|
|
853
|
+
* a permanently unreadable epoch an immortal phantom holder no contender can ever reclaim;
|
|
854
|
+
* resolving it toward "reclaimable" is the kill this closes. It is returned to the consumers so
|
|
855
|
+
* each of them names what it does with it, and so a fourth consumer added later cannot inherit a
|
|
856
|
+
* default it never chose.
|
|
857
|
+
*
|
|
858
|
+
* W-01: the epoch conjunct lives HERE, in the derivation, not at the consumers. Three surfaces
|
|
859
|
+
* classify recoverability from this verdict — `leasePermitsEscalation`, the acquisition
|
|
860
|
+
* pre-check, and `classifyDaemonRegistration` in the CLI — and a fix applied consumer by consumer
|
|
861
|
+
* is a list that the next surface joins without joining the guard. A lease naming a superseded
|
|
862
|
+
* epoch is recovery input no matter how fresh its bytes are: nobody can still be inside a
|
|
863
|
+
* transaction for an epoch that has already been replaced.
|
|
864
|
+
*
|
|
865
|
+
* WR-04: a crash between the epoch rewrite and the lease rewrite leaves a lease naming the
|
|
866
|
+
* previous epoch. Reporting that lease as held manufactures a phantom holder no TTL sweep ever
|
|
867
|
+
* reclaims, so an epoch-invalid lease is recovery input rather than an answer.
|
|
868
|
+
*
|
|
869
|
+
* The inputs are the disk epoch and the lease value, and nothing else. There is no second
|
|
870
|
+
* freshness channel and no further conjunct: three conjuncts produced three defects.
|
|
871
|
+
*/
|
|
872
|
+
type WriterLeaseFreshness = {
|
|
873
|
+
kind: 'fresh';
|
|
874
|
+
} | {
|
|
875
|
+
kind: 'reclaimable';
|
|
876
|
+
} | {
|
|
877
|
+
kind: 'unknown';
|
|
878
|
+
error: CorruptEpochStateError;
|
|
879
|
+
};
|
|
880
|
+
declare function deriveWriterLeaseFreshness(knowledgeRoot: string, lease: WriterLease, nowMs: number): WriterLeaseFreshness;
|
|
881
|
+
/** Return a live holder or atomically mint a new, monotonically fenced writer identity. */
|
|
882
|
+
declare function acquireWriterLease(knowledgeRoot: string, hooks?: AcquireWriterLeaseOptions): AcquireWriterLeaseOutcome;
|
|
883
|
+
/**
|
|
884
|
+
* Compare one exact writer authority and run its mutation under the same generation lock.
|
|
885
|
+
* The generation check after the failpoint prevents an expired owner from resuming after a
|
|
886
|
+
* bounded takeover. Mutation implementations must keep irreversible work inside `mutate`.
|
|
887
|
+
*/
|
|
888
|
+
declare function withCurrentWriterAuthority<T>(knowledgeRoot: string, authority: CurrentWriterAuthority, mutate: () => T, hooks?: CurrentWriterAuthorityHooks): T;
|
|
889
|
+
/**
|
|
890
|
+
* Refresh the matching current-epoch holder without entering the mutation lock.
|
|
891
|
+
*
|
|
892
|
+
* CR-03 dissolves here rather than being worked around. The beat used to share
|
|
893
|
+
* `withMutationLock` with every governed write, and it runs in a worker THREAD, so the daemon's
|
|
894
|
+
* long synchronous mutation on the main thread held the lock while the worker blocked on it: the
|
|
895
|
+
* holder starved its own heartbeat, crossed the TTL and became a takeover target. Writing `.lease`
|
|
896
|
+
* directly means a governed mutation of any length cannot starve the beat at all, so heartbeat
|
|
897
|
+
* independence is structural instead of a fallback that has to be maintained beside the real path.
|
|
898
|
+
*
|
|
899
|
+
* What the lock used to buy was check-then-write atomicity of the identity/epoch ladder below
|
|
900
|
+
* against a concurrent reclaim, and dropping it opens exactly one race: a holder resuming from a
|
|
901
|
+
* >=TTL wedge can land its read-check-write astride a contender's reclaim and clobber the
|
|
902
|
+
* successor's lease. That is contained rather than prevented, and the containment is the epoch
|
|
903
|
+
* fence: a reclaim rewrites `.epoch` strictly BEFORE it publishes its lease, both inside the lock,
|
|
904
|
+
* so any lease clobbered afterwards names a superseded epoch. Every classifier reads it as
|
|
905
|
+
* recovery input, no store write is admitted under it (the epoch fence at the store verbs), and
|
|
906
|
+
* the successor's next authority check surfaces WriterAuthorityLostError, after which a fresh
|
|
907
|
+
* acquisition reclaims at the next epoch. The worst case is one successor bounce in a microsecond
|
|
908
|
+
* window after a 30 s wedge — a liveness hiccup, never minted authority. During the exact schedule
|
|
909
|
+
* this lock-free write exists for (the holder's own mutation in flight) no contender can be
|
|
910
|
+
* mid-reclaim at all, because a reclaim requires the very lock that mutation is holding.
|
|
911
|
+
*
|
|
912
|
+
* 2026-08-01 W-02 re-scope: `MUTATION_LOCK_TAKEOVER_MS` now governs reclaim from DEAD and
|
|
913
|
+
* whole-process-STOPPED owners, which write no beats and cross the TTL. Auto-takeover of a LIVE
|
|
914
|
+
* holder whose beat thread is still ticking is deliberately impossible; a wedged-forever live
|
|
915
|
+
* daemon surfaces at every contender as the typed `mutation-lock-unreclaimable` refusal naming its
|
|
916
|
+
* pid. That is an operator kill rather than an automated one, which is this module's own law: a
|
|
917
|
+
* wrong kill is unrecoverable, a wedged contender is not.
|
|
918
|
+
*
|
|
919
|
+
* Identity is still proven first, and every refusal below leaves `.lease` byte-identical.
|
|
920
|
+
*
|
|
921
|
+
* 2026-10-02 (quick 261002-lse, 432-19 #7): the ladder and the write run under the lease-file
|
|
922
|
+
* guard `releaseLease` also takes. Without it a beat that read before a release wrote after it,
|
|
923
|
+
* and since release deliberately keeps the epoch, the resurrected lease named the CURRENT epoch:
|
|
924
|
+
* the fence above contains a reclaim but not a release, and the next acquire answered `held`.
|
|
925
|
+
* The guard is not the mutation lock, so everything said above about CR-03 still holds.
|
|
926
|
+
*/
|
|
927
|
+
declare function heartbeatLease(opts: LeaseOperationOptions, hooks?: LeaseGuardHooks): HeartbeatLeaseOutcome;
|
|
928
|
+
/**
|
|
929
|
+
* Refresh one exact maintenance writer at a non-mutating boundary.
|
|
930
|
+
*
|
|
931
|
+
* The epoch reads deliberately bracket the heartbeat: the first rejects an already-reclaimed
|
|
932
|
+
* holder, while the second detects a reclaim race after the lease rewrite. The authority-store
|
|
933
|
+
* transaction is released before this function returns, so this is NOT a mutation fence. Any
|
|
934
|
+
* irreversible mutation must instead run inside `withCurrentWriterAuthority`.
|
|
935
|
+
*/
|
|
936
|
+
declare function refreshWriterLeaseAuthority(authority: WriterLeaseAuthority): WriterLeaseAuthority;
|
|
937
|
+
/**
|
|
938
|
+
* Remove only the matching lease file; the monotonic epoch is deliberately retained forever.
|
|
939
|
+
*
|
|
940
|
+
* The read and the deletion run under the lease-file guard, taken inside the mutation lock, so a
|
|
941
|
+
* heartbeat in flight finishes before the lease is read and any later beat finds it gone
|
|
942
|
+
* (261002-lse). The guard is always taken second, and the beat never takes the mutation lock, so
|
|
943
|
+
* the two cannot wait on each other.
|
|
944
|
+
*/
|
|
945
|
+
declare function releaseLease(opts: LeaseOperationOptions, hooks?: LeaseGuardHooks): ReleaseLeaseOutcome;
|
|
946
|
+
|
|
947
|
+
/**
|
|
948
|
+
* What a manually added window records where an auto-entry records the fingerprint that crossed.
|
|
949
|
+
*
|
|
950
|
+
* A human quarantining a known-broken test is not reporting a recurrence, so there is no window key
|
|
951
|
+
* to carry — and the `entered` event REQUIRES one (an entry with no fingerprint would fail the
|
|
952
|
+
* ledger's own shape guard). A typed literal that cannot be mistaken for a real key is the honest
|
|
953
|
+
* answer: every computed fingerprint contains `::`, this one contains none.
|
|
954
|
+
*/
|
|
955
|
+
declare const QUARANTINE_MANUAL_ENTRY_FINGERPRINT = "manual-entry";
|
|
956
|
+
/**
|
|
957
|
+
* The class a manual entry records: `unknown`, on the merits rather than for convenience.
|
|
958
|
+
*
|
|
959
|
+
* `unknown` is precisely "a failure carrying no verdict" — nothing classified this test, because a
|
|
960
|
+
* human decided to suppress it rather than a detector deciding it recurred. Recording a made-up
|
|
961
|
+
* `flake` would put an assertion nobody made into committed truth, and the detection ladder reads
|
|
962
|
+
* the class of AUTO entries only, so no rule changes behaviour on the strength of this value.
|
|
963
|
+
*/
|
|
964
|
+
declare const QUARANTINE_MANUAL_ENTRY_CLASS: VerdictClass;
|
|
965
|
+
/**
|
|
966
|
+
* The `filePath` a caller sent cannot mint the durable identity the ledger is keyed on (390-12).
|
|
967
|
+
*
|
|
968
|
+
* Same shape and same reason as the lease refusal above: the port's result unions carry no refusal
|
|
969
|
+
* arm by design (390-04), so a refusal that is not one of the named outcomes surfaces as a typed
|
|
970
|
+
* throw. Raised BEFORE the knowledge root is resolved, before the lease is acquired and before a
|
|
971
|
+
* byte is read, so a refused call costs the ledger nothing and the next writer nothing.
|
|
972
|
+
*
|
|
973
|
+
* WHAT THIS OWNS, AND WHAT THE LEDGER'S OWN WRITE GUARD OWNS (390-11). They are not two spellings
|
|
974
|
+
* of one rule and neither subsumes the other:
|
|
975
|
+
*
|
|
976
|
+
* - THIS decides what the identity IS. It is the only gate that knows the checkout root, so it is
|
|
977
|
+
* the only one that can turn `/Users/me/repo/tests/a.yaml` — a real file inside the workspace,
|
|
978
|
+
* the exact bytes an operator pastes out of a failure report — into `tests/a.yaml` and ACCEPT
|
|
979
|
+
* it. The structural guard would refuse that input; refusing it is the wrong answer, because
|
|
980
|
+
* the operator named a file the workspace genuinely contains.
|
|
981
|
+
* - The STRUCTURAL guard in `appendQuarantineEvents` decides what the FILE may carry, for every
|
|
982
|
+
* writer including one that never met a mint. It is a backstop with no host context, and it
|
|
983
|
+
* throws rather than answering data because a line the reader refuses is corruption.
|
|
984
|
+
*
|
|
985
|
+
* What cannot be canonicalized at all — a path escaping the config directory — is refused here,
|
|
986
|
+
* with the mint's own message carried so the operator learns why rather than that.
|
|
987
|
+
*/
|
|
988
|
+
declare class QuarantineIdentityRefusedError extends Error {
|
|
989
|
+
readonly filePath: string;
|
|
990
|
+
readonly reason: unknown;
|
|
991
|
+
constructor(filePath: string, reason: unknown);
|
|
992
|
+
}
|
|
993
|
+
interface QuarantineOperationsOptions {
|
|
994
|
+
/** The committed knowledge root. A FACTORY, because the CLI host resolves it asynchronously. */
|
|
995
|
+
resolveKnowledgeRoot: () => Promise<string> | string;
|
|
996
|
+
/** The ONLY way wall clock enters these verbs. Required — see the module head. */
|
|
997
|
+
now: () => string;
|
|
998
|
+
/**
|
|
999
|
+
* Mints the durable workspace-relative identity a `filePath` is stored under (390-12 / D-01).
|
|
1000
|
+
*
|
|
1001
|
+
* Production supplies core's ONE recipe, `workspaceRelativeIdentityPath`, pre-bound to the host's
|
|
1002
|
+
* own config directory. INJECTED rather than imported for two independent reasons, and either
|
|
1003
|
+
* alone would be sufficient: this package may not depend on `@vostride/agent-qa-core` (only the
|
|
1004
|
+
* surface packages may), and — the load-bearing one — the checkout root is a HOST fact these
|
|
1005
|
+
* verbs cannot discover. A verb that guessed it would mint identities against the wrong root.
|
|
1006
|
+
*
|
|
1007
|
+
* REQUIRED, with no default. A default passthrough is exactly the unvalidated pass-through that
|
|
1008
|
+
* produced the round-2 regression: the verbs answered `entered` over lines the reader is
|
|
1009
|
+
* guaranteed to refuse. An absent mint must be a compile error at the composition that forgot it,
|
|
1010
|
+
* not a runtime surprise inside a committed artifact.
|
|
1011
|
+
*
|
|
1012
|
+
* @throws whatever the mint throws for a path it cannot canonicalize; re-raised as
|
|
1013
|
+
* {@link QuarantineIdentityRefusedError}.
|
|
1014
|
+
*/
|
|
1015
|
+
mintIdentityPath: (filePath: string) => string;
|
|
1016
|
+
/**
|
|
1017
|
+
* The writer lease THIS process already holds, when it holds one (387-08 D-18 / D-5).
|
|
1018
|
+
*
|
|
1019
|
+
* Supplied by the daemon host, which acquires at startup and holds for its whole lifetime: a
|
|
1020
|
+
* holder that calls `acquireWriterLease` is answered `held` by itself and, unlike the apply path,
|
|
1021
|
+
* has nobody to delegate to. Absent on the CLI in-process host, which holds nothing and therefore
|
|
1022
|
+
* takes the lease per call.
|
|
1023
|
+
*
|
|
1024
|
+
* THE VALUE IS CONSULTED FOR FENCING (390-15 / G-390-2R), and this sentence used to say the
|
|
1025
|
+
* opposite. It is re-validated against disk on every write verb, so the question it answers is
|
|
1026
|
+
* "is this process STILL the holder?" rather than "did this process already serialize itself?".
|
|
1027
|
+
* The two are the same question only while nothing reclaims: a daemon whose heartbeat starved
|
|
1028
|
+
* and whose lease was then taken answers yes to the second one forever, and the two-OS-process
|
|
1029
|
+
* harness measured what that costs — two `entered` lines for one identity, and the verb
|
|
1030
|
+
* returning an owner committed truth does not record. See {@link underWriterLease}.
|
|
1031
|
+
*
|
|
1032
|
+
* AND WHAT THE RE-VALIDATION DOES NOT BUY (390-22 / WR-07): it is a read, not a lock. It answers
|
|
1033
|
+
* "still the holder?" as of the read, and the decide it licenses runs after it. A reclaim landing
|
|
1034
|
+
* between the two is still unfenced. `lease/under-writer-lease.ts` states the residual in full.
|
|
1035
|
+
*/
|
|
1036
|
+
resolveWriterAuthority?: () => {
|
|
1037
|
+
leaseId: string;
|
|
1038
|
+
epoch: number;
|
|
1039
|
+
} | undefined;
|
|
1040
|
+
}
|
|
1041
|
+
/**
|
|
1042
|
+
* The three verbs over one committed ledger.
|
|
1043
|
+
*
|
|
1044
|
+
* Each call is a full read-fold-decide-append cycle. Nothing is cached between calls, which is what
|
|
1045
|
+
* makes `quarantine.list` and the sentence's ladder clause two readings of ONE live computation
|
|
1046
|
+
* (SC4): an event appended between two calls is visible to both.
|
|
1047
|
+
*/
|
|
1048
|
+
declare function createQuarantineOperations(options: QuarantineOperationsOptions): QuarantineOperationsPort;
|
|
1049
|
+
|
|
1050
|
+
declare const ARTIFACT_STEP_CAP_BYTES: number;
|
|
1051
|
+
declare const ARTIFACT_RUN_CAP_BYTES: number;
|
|
1052
|
+
interface ArtifactCopyInput {
|
|
1053
|
+
ref: ArtifactRef;
|
|
1054
|
+
sourcePath: string;
|
|
1055
|
+
stepIndex: number;
|
|
1056
|
+
role?: string;
|
|
1057
|
+
originalName?: string;
|
|
1058
|
+
}
|
|
1059
|
+
interface CopiedArtifact {
|
|
1060
|
+
ref: ArtifactRef;
|
|
1061
|
+
relPath: string;
|
|
1062
|
+
bytes: number;
|
|
1063
|
+
stepIndex: number;
|
|
1064
|
+
role?: string;
|
|
1065
|
+
originalName?: string;
|
|
1066
|
+
}
|
|
1067
|
+
type ArtifactCopySkipReason = 'step-cap' | 'run-cap' | 'pruned-source' | 'sha-mismatch';
|
|
1068
|
+
interface SkippedArtifact<Reason extends string = ArtifactCopySkipReason> {
|
|
1069
|
+
ref: ArtifactRef;
|
|
1070
|
+
stepIndex: number;
|
|
1071
|
+
reason: Reason;
|
|
1072
|
+
}
|
|
1073
|
+
interface ArtifactCopyResult {
|
|
1074
|
+
copied: CopiedArtifact[];
|
|
1075
|
+
skipped: SkippedArtifact[];
|
|
1076
|
+
evidenceIncomplete: boolean;
|
|
1077
|
+
}
|
|
1078
|
+
interface ArtifactCopyOptions {
|
|
1079
|
+
/** Pre-copy refusals retained in the same inventory as copy-time refusals. */
|
|
1080
|
+
preSkipped?: readonly SkippedArtifact[];
|
|
1081
|
+
mask?: MaskFn;
|
|
1082
|
+
}
|
|
1083
|
+
declare function copyArtifacts(inputs: readonly ArtifactCopyInput[], destArtifactsDir: string, options?: ArtifactCopyOptions): ArtifactCopyResult;
|
|
1084
|
+
|
|
1085
|
+
interface RenderedBundlePart {
|
|
1086
|
+
relPath: string;
|
|
1087
|
+
label: string;
|
|
1088
|
+
text: string;
|
|
1089
|
+
}
|
|
1090
|
+
type BundleProvenanceInput = {
|
|
1091
|
+
mode: 'run-linked';
|
|
1092
|
+
runId: string;
|
|
1093
|
+
testId: string;
|
|
1094
|
+
stepIndex: number;
|
|
1095
|
+
curationJobId?: string;
|
|
1096
|
+
sourceBuildOrdinal?: number;
|
|
1097
|
+
authorship?: CurationAuthorship;
|
|
1098
|
+
needsEnrichment?: boolean;
|
|
1099
|
+
withheld?: boolean;
|
|
1100
|
+
} | {
|
|
1101
|
+
mode: 'standalone';
|
|
1102
|
+
sourceDescription: string;
|
|
1103
|
+
};
|
|
1104
|
+
interface RenderBundlePartsInput {
|
|
1105
|
+
draft: BundleDraft;
|
|
1106
|
+
discriminant: BundleDiscriminant;
|
|
1107
|
+
originClass: OriginClass;
|
|
1108
|
+
createdAtOrdinal: number;
|
|
1109
|
+
screenStates: readonly ScreenState[];
|
|
1110
|
+
initialEvents: readonly BundleOutcomeEvent[];
|
|
1111
|
+
relations: readonly BundleRelation[];
|
|
1112
|
+
provenance: BundleProvenanceInput;
|
|
1113
|
+
copiedArtifacts: ArtifactCopyResult;
|
|
1114
|
+
evidenceIncomplete: boolean;
|
|
1115
|
+
evidenceMarkdown?: string;
|
|
1116
|
+
distilledObservations?: readonly DistilledObservation[];
|
|
1117
|
+
}
|
|
1118
|
+
declare function renderBundleParts(input: RenderBundlePartsInput): {
|
|
1119
|
+
parts: RenderedBundlePart[];
|
|
1120
|
+
id: RecordId;
|
|
1121
|
+
identityHash: string;
|
|
1122
|
+
identityCore: BundleIdentityCore;
|
|
1123
|
+
};
|
|
1124
|
+
|
|
1125
|
+
interface BundleStoreConfig {
|
|
1126
|
+
/** Absolute committed-root path. Deliberately no working-directory default. */
|
|
1127
|
+
knowledgeRoot: string;
|
|
1128
|
+
productKey: string;
|
|
1129
|
+
commitArtifacts: 'none' | 'thumbnails';
|
|
1130
|
+
/** Active writer identity used to attribute crash-left staging trees. */
|
|
1131
|
+
writerLeaseId?: string;
|
|
1132
|
+
/** Fencing epoch embedded in reader-invisible staging names. */
|
|
1133
|
+
writerEpoch?: number;
|
|
1134
|
+
hooks?: {
|
|
1135
|
+
/** Test/chaos seam after all staged bytes exist but before the visibility rename. */
|
|
1136
|
+
beforePublishRename?: () => void;
|
|
1137
|
+
/** Test/chaos seam after each durable mutable-file replacement. */
|
|
1138
|
+
afterMutableReplacement?: (targetRelPath: string) => void;
|
|
1139
|
+
};
|
|
1140
|
+
}
|
|
1141
|
+
interface PublishBundleInput extends Omit<RenderBundlePartsInput, 'copiedArtifacts' | 'evidenceIncomplete'> {
|
|
1142
|
+
artifacts: readonly ArtifactCopyInput[];
|
|
1143
|
+
/** Refusals already decided by the Curator's pre-copy pass. */
|
|
1144
|
+
preSkippedArtifacts?: readonly SkippedArtifact<ArtifactCopySkipReason>[];
|
|
1145
|
+
}
|
|
1146
|
+
type PublishBundleOutcome = {
|
|
1147
|
+
kind: 'published';
|
|
1148
|
+
id: RecordId;
|
|
1149
|
+
dir: string;
|
|
1150
|
+
evidenceIncomplete: boolean;
|
|
1151
|
+
} | {
|
|
1152
|
+
kind: 'already-exists';
|
|
1153
|
+
id: RecordId;
|
|
1154
|
+
} | {
|
|
1155
|
+
kind: 'identity-collision';
|
|
1156
|
+
id: RecordId;
|
|
1157
|
+
dir: string;
|
|
1158
|
+
reason: 'identity-hash-mismatch' | 'identity-core-mismatch' | 'existing-manifest-corrupt';
|
|
1159
|
+
expectedIdentityHash: string;
|
|
1160
|
+
existingIdentityHash: string | null;
|
|
1161
|
+
};
|
|
1162
|
+
|
|
1163
|
+
/** Unfenced compatibility composition for test data setup only. */
|
|
1164
|
+
declare function publishBundle(config: BundleStoreConfig, input: PublishBundleInput): PublishBundleOutcome;
|
|
1165
|
+
|
|
1166
|
+
type AppendOutcome = {
|
|
1167
|
+
kind: 'appended';
|
|
1168
|
+
} | {
|
|
1169
|
+
kind: 'duplicate';
|
|
1170
|
+
} | {
|
|
1171
|
+
kind: 'not-found';
|
|
1172
|
+
};
|
|
1173
|
+
/** 416 D-04: receipt identity is its verified content digest, before any committed write. */
|
|
1174
|
+
declare function appendGateReceipt(config: BundleStoreConfig, id: RecordId, receipt: GateReceipt): AppendOutcome;
|
|
1175
|
+
/** 416 D-05/D-07: one promotion line per candidate/path; lifecycle bytes remain unchanged. */
|
|
1176
|
+
declare function appendPromotionReceipt(config: BundleStoreConfig, id: RecordId, lineWithoutDigest: Omit<PromotionReceipt, 'receiptDigest' | 'citedReceiptDigests'> & {
|
|
1177
|
+
citedReceiptDigests: readonly string[];
|
|
1178
|
+
}): AppendOutcome;
|
|
1179
|
+
declare const MEASUREMENTS_REL_PATH = "evidence/measurements.json";
|
|
1180
|
+
declare function appendOutcomeEvent(config: BundleStoreConfig, id: RecordId, event: BundleOutcomeEvent): AppendOutcome;
|
|
1181
|
+
/**
|
|
1182
|
+
* Persist D-03's immutable validity-window snapshot. An existing measurements
|
|
1183
|
+
* file is an idempotent refusal: baseline bytes are never rewritten.
|
|
1184
|
+
*/
|
|
1185
|
+
declare function writeMeasurementBaseline(config: BundleStoreConfig, id: RecordId, baseline: MeasurementBaseline): AppendOutcome;
|
|
1186
|
+
/**
|
|
1187
|
+
* Append one observation through the full journaled replacement path. Existing
|
|
1188
|
+
* lines remain byte-for-byte unchanged; only the new canonical line is added.
|
|
1189
|
+
*/
|
|
1190
|
+
declare function appendMeasurementObservation(config: BundleStoreConfig, id: RecordId, observation: MeasurementObservation): AppendOutcome;
|
|
1191
|
+
declare function appendRelation(config: BundleStoreConfig, id: RecordId, relation: BundleRelation): AppendOutcome;
|
|
1192
|
+
|
|
1193
|
+
type CanonicalBundleStateDigests = {
|
|
1194
|
+
kind: 'found';
|
|
1195
|
+
digests: string[];
|
|
1196
|
+
} | {
|
|
1197
|
+
kind: 'not-found';
|
|
1198
|
+
};
|
|
1199
|
+
declare function readCanonicalBundleStateDigests(input: {
|
|
1200
|
+
knowledgeRoot: string;
|
|
1201
|
+
candidateId: string;
|
|
1202
|
+
}): CanonicalBundleStateDigests;
|
|
1203
|
+
|
|
1204
|
+
/**
|
|
1205
|
+
* The leg Channel-1 run-brief assembly attributes to. See the module header: the assembly's whole
|
|
1206
|
+
* ordering signal is the scope/anchor token overlap, so this is a statement about the code that
|
|
1207
|
+
* ranks, not a default.
|
|
1208
|
+
*/
|
|
1209
|
+
declare const CHANNEL_1_SERVING_LEG: RetrievalTraceLeg;
|
|
1210
|
+
/**
|
|
1211
|
+
* The leg Channel-3 caution selection attributes to. Unambiguous here: a caution with no matching
|
|
1212
|
+
* anchor is dropped before it is ever ranked.
|
|
1213
|
+
*/
|
|
1214
|
+
declare const CHANNEL_3_CAUTION_LEG: RetrievalTraceLeg;
|
|
1215
|
+
/**
|
|
1216
|
+
* The legs a serving channel in this package can actually emit. This is the `knowledge-local` half
|
|
1217
|
+
* of the cross-package vocabulary check the trace DTO asks for: the schema declares
|
|
1218
|
+
* `RETRIEVAL_TRACE_LEGS`, the retrieval legs module declares a module-private `CandidateLeg`, and
|
|
1219
|
+
* this package is the only one that can see both. Exported so a test can assert the three sets
|
|
1220
|
+
* agree instead of a comment claiming they do.
|
|
1221
|
+
*/
|
|
1222
|
+
declare const SERVING_TRACE_LEGS: readonly RetrievalTraceLeg[];
|
|
1223
|
+
|
|
1224
|
+
type EmbedCacheLeg = 'doc' | 'query';
|
|
1225
|
+
type EmbedCacheMode = 'check-only' | 'check-and-store';
|
|
1226
|
+
interface EmbedCacheLookup {
|
|
1227
|
+
db: DatabaseSync;
|
|
1228
|
+
profile: EmbeddingProfile;
|
|
1229
|
+
leg: EmbedCacheLeg;
|
|
1230
|
+
rendering: string;
|
|
1231
|
+
}
|
|
1232
|
+
interface EmbedCachePut extends EmbedCacheLookup {
|
|
1233
|
+
vector: Float32Array;
|
|
1234
|
+
}
|
|
1235
|
+
interface EmbedCacheWrapperOptions {
|
|
1236
|
+
embedder: EmbedderPort;
|
|
1237
|
+
profile: EmbeddingProfile;
|
|
1238
|
+
db: DatabaseSync;
|
|
1239
|
+
mode: EmbedCacheMode;
|
|
1240
|
+
}
|
|
1241
|
+
/** Create the derived cache table from a writer-role connection. */
|
|
1242
|
+
declare function ensureEmbedCacheTable(db: DatabaseSync): void;
|
|
1243
|
+
/** Return a copied vector so callers cannot mutate SQLite-owned row bytes. */
|
|
1244
|
+
declare function getCachedEmbedding({ db, profile, leg, rendering, }: EmbedCacheLookup): Float32Array | undefined;
|
|
1245
|
+
/** Store an exact Float32 byte copy under the raw-rendering content hash. */
|
|
1246
|
+
declare function putCachedEmbedding({ db, profile, leg, rendering, vector, }: EmbedCachePut): void;
|
|
1247
|
+
/** Evict every cached leg/revision/dtype row owned by one model id. */
|
|
1248
|
+
declare function dropEmbedCacheForModel(db: DatabaseSync, modelId: string): void;
|
|
1249
|
+
/**
|
|
1250
|
+
* Decorate an embedder with the M2 connection-role posture.
|
|
1251
|
+
*
|
|
1252
|
+
* Reader connections use check-only: they benefit from materialized rows but never write on a
|
|
1253
|
+
* miss. Writer-role backfill, migration, and bench paths use check-and-store, which is where the
|
|
1254
|
+
* steady-state cache materializes. Callers must ensure the table once through a writer first.
|
|
1255
|
+
*/
|
|
1256
|
+
declare function wrapEmbedderWithCache({ embedder, profile, db, mode, }: EmbedCacheWrapperOptions): EmbedderPort;
|
|
1257
|
+
|
|
1258
|
+
type WorkerDiscoveryResult = {
|
|
1259
|
+
kind: 'no-worker';
|
|
1260
|
+
} | {
|
|
1261
|
+
kind: 'worker';
|
|
1262
|
+
};
|
|
1263
|
+
type EmbedderRung = 'native' | 'floor';
|
|
1264
|
+
type EmbedderWorkerPolicy = 'preferred' | 'required';
|
|
1265
|
+
type DeferReason = 'cold-artifact' | 'load-failure' | 'worker-unavailable';
|
|
1266
|
+
type AcquireEmbedderOutcome = {
|
|
1267
|
+
kind: 'ready';
|
|
1268
|
+
rung: EmbedderRung;
|
|
1269
|
+
profile: EmbeddingProfile;
|
|
1270
|
+
embedder: EmbedderPort;
|
|
1271
|
+
} | {
|
|
1272
|
+
kind: 'deferred';
|
|
1273
|
+
reason: DeferReason;
|
|
1274
|
+
} | {
|
|
1275
|
+
kind: 'lexical-only';
|
|
1276
|
+
};
|
|
1277
|
+
/**
|
|
1278
|
+
* D-12/D-17 test-only capability injection seam.
|
|
1279
|
+
*
|
|
1280
|
+
* Production callers must omit this field so rung selection reflects host truth. No probe is a
|
|
1281
|
+
* user-facing selector, configuration key, environment variable, or CLI switch.
|
|
1282
|
+
*/
|
|
1283
|
+
interface EmbedderProbes {
|
|
1284
|
+
discoverWorker?: (agentQaRoot: string) => Promise<WorkerDiscoveryResult>;
|
|
1285
|
+
createNativeEmbedder?: (options: {
|
|
1286
|
+
profile: EmbeddingProfile;
|
|
1287
|
+
allowDownload: boolean;
|
|
1288
|
+
}) => Promise<EmbedderPort>;
|
|
1289
|
+
createFloorEmbedder?: () => EmbedderPort | Promise<EmbedderPort>;
|
|
1290
|
+
}
|
|
1291
|
+
interface AcquireEmbedderOptions {
|
|
1292
|
+
preferredProfile?: EmbeddingProfile;
|
|
1293
|
+
allowDownload: boolean;
|
|
1294
|
+
/** Daemon posture requires the child; ordinary one-shot callers retain the preferred ladder. */
|
|
1295
|
+
workerPolicy?: EmbedderWorkerPolicy;
|
|
1296
|
+
/** Explicit hosted runtime root. Required policy must never infer it from ambient cwd. */
|
|
1297
|
+
agentQaRoot?: string;
|
|
1298
|
+
cache?: {
|
|
1299
|
+
db: DatabaseSync;
|
|
1300
|
+
mode: EmbedCacheMode;
|
|
1301
|
+
};
|
|
1302
|
+
/** D-12/D-17 test seam. Production callers resolve actual host capabilities. */
|
|
1303
|
+
probes?: EmbedderProbes;
|
|
1304
|
+
}
|
|
1305
|
+
interface ResolveEmbedderCapabilityOptions {
|
|
1306
|
+
preferredProfile?: EmbeddingProfile;
|
|
1307
|
+
allowDownload: boolean;
|
|
1308
|
+
/** Daemon posture requires the child; ordinary one-shot callers retain the preferred ladder. */
|
|
1309
|
+
workerPolicy?: EmbedderWorkerPolicy;
|
|
1310
|
+
/** Explicit hosted runtime root. Required policy must never infer it from ambient cwd. */
|
|
1311
|
+
agentQaRoot?: string;
|
|
1312
|
+
/** D-12/D-17 test seam. Production callers resolve actual host capabilities. */
|
|
1313
|
+
probes?: EmbedderProbes;
|
|
1314
|
+
}
|
|
1315
|
+
type CapabilityOutcome = AcquireEmbedderOutcome;
|
|
1316
|
+
/**
|
|
1317
|
+
* Invalidate process-lifetime capability resolution without touching process-local pipelines.
|
|
1318
|
+
*
|
|
1319
|
+
* A named profile clears only its memo entry. Omitting the profile clears every production and
|
|
1320
|
+
* probe-isolated entry so a long-lived host can re-probe after its worker or artifact state moves.
|
|
1321
|
+
*/
|
|
1322
|
+
declare function resetEmbedderCapability(profile?: EmbeddingProfile): void;
|
|
1323
|
+
interface DiscoverEmbedderWorkerOptions {
|
|
1324
|
+
/** Test-only shortening seam; production omits this and uses the pinned request deadline. */
|
|
1325
|
+
readonly requestTimeoutMs?: number;
|
|
1326
|
+
}
|
|
1327
|
+
/** D-09's worker arm, rooted in the hosted project rather than ambient process cwd. */
|
|
1328
|
+
declare function discoverEmbedderWorker(agentQaRoot: string, options?: DiscoverEmbedderWorkerOptions): Promise<WorkerDiscoveryResult>;
|
|
1329
|
+
/**
|
|
1330
|
+
* Resolve the automatic ladder once per profile for this process (D-17).
|
|
1331
|
+
*
|
|
1332
|
+
* Every host/runtime failure collapses to a typed capability outcome; callers cannot select a
|
|
1333
|
+
* rung. Injected test seams receive an isolated memo while production keys solely by the stable
|
|
1334
|
+
* embedding profile identity.
|
|
1335
|
+
*/
|
|
1336
|
+
declare function resolveEmbedderCapability(options: ResolveEmbedderCapabilityOptions): Promise<CapabilityOutcome>;
|
|
1337
|
+
declare function acquireEmbedder(options: AcquireEmbedderOptions): Promise<AcquireEmbedderOutcome>;
|
|
1338
|
+
|
|
1339
|
+
/**
|
|
1340
|
+
* The ONE fold from the host's two retrieval axes to the recorded rung (407 TRST-01 · D-13/D-17).
|
|
1341
|
+
*
|
|
1342
|
+
* ONE resolver, three callers: the runner's evidence recorder (407-07) stamps the value into
|
|
1343
|
+
* `StepEvidence.retrievalRung`, `doctor` (407-08) grades it live, and the run header banner
|
|
1344
|
+
* (407-10) renders the recorded copy. Three callers deriving a rung independently from the same
|
|
1345
|
+
* two axes is exactly how a banner and a doctor row come to disagree about one machine, so the
|
|
1346
|
+
* fold table lives here once and its cells are pinned by `__tests__/retrieval-rung.test.ts`.
|
|
1347
|
+
*
|
|
1348
|
+
* WHAT THE VALUE MEANS. It is the HOST's ladder at serve time — never a claim about how any
|
|
1349
|
+
* individual brief line was ranked. The run-brief serve path reads index rows directly and
|
|
1350
|
+
* attributes channels 1 and 3 to the `anchor` leg by construction; the dense leg and the
|
|
1351
|
+
* bundle-scan fallback belong to the general `retrieve()` path the curator, the entity resolver
|
|
1352
|
+
* and the authoring reader use. A surface renders "retrieval was on rung X for this run".
|
|
1353
|
+
*
|
|
1354
|
+
* This module lives in knowledge-local because it is the only package that can see either axis:
|
|
1355
|
+
* the index face is `index-reader`'s degrade ladder and the embedder outcome is
|
|
1356
|
+
* `embedder-acquire`'s capability probe. What it hands back is the schema-owned value.
|
|
1357
|
+
*/
|
|
1358
|
+
|
|
1359
|
+
/** The index half of the fold — `index-reader`'s degrade ladder, read without side effects. */
|
|
1360
|
+
type IndexAxis = IndexFace;
|
|
1361
|
+
/** The embedder half of the fold — `embedder-acquire`'s capability outcome, unchanged. */
|
|
1362
|
+
type EmbedderAxis = AcquireEmbedderOutcome;
|
|
1363
|
+
/**
|
|
1364
|
+
* Fold the two axes into the value that gets recorded (D-17).
|
|
1365
|
+
*
|
|
1366
|
+
* ORDERING IS PART OF THE CONTRACT: the index axis is consulted FIRST. No dense leg can run
|
|
1367
|
+
* against an index that will not open, whatever the embedder resolved to, so a `scan` face is
|
|
1368
|
+
* `bundle-scan` even on a host with a live native embedder. Folding the embedder first would
|
|
1369
|
+
* label a host with an unopenable index `memidex` and make the banner lie.
|
|
1370
|
+
*
|
|
1371
|
+
* `reason` is ABSENT for `memidex` — the top rung is not a degradation and has no cause to name.
|
|
1372
|
+
* Every lower rung carries one, which is what lets the banner say rung AND cause in one line.
|
|
1373
|
+
*/
|
|
1374
|
+
declare function foldRetrievalRung(index: IndexAxis, embedder: EmbedderAxis, preferredProfile?: EmbeddingProfile): RecordedRetrievalRung;
|
|
1375
|
+
interface ResolveRetrievalRungOptions {
|
|
1376
|
+
knowledgeRoot: string;
|
|
1377
|
+
/** Explicit hosted runtime root for worker discovery; defaults to the acquirer's own rule. */
|
|
1378
|
+
agentQaRoot?: string;
|
|
1379
|
+
preferredProfile?: EmbeddingProfile;
|
|
1380
|
+
/** D-12/D-17 test seam, passed through unchanged. Production callers omit it. */
|
|
1381
|
+
probes?: EmbedderProbes;
|
|
1382
|
+
}
|
|
1383
|
+
/**
|
|
1384
|
+
* Probe both axes and fold them (D-17). NEVER throws, NEVER downloads, NEVER writes.
|
|
1385
|
+
*
|
|
1386
|
+
* - `allowDownload: false` is hard-coded, not an option: this call answers "what is this host
|
|
1387
|
+
* doing today", and a probe that fetched a model would change the answer by asking it (T-407-09).
|
|
1388
|
+
* - A `scan` face short-circuits before the embedder is touched at all. The fold does not need the
|
|
1389
|
+
* embedder axis in that arm, and the probe can cost a model load.
|
|
1390
|
+
* - A rejected capability probe folds to `deferred/load-failure` rather than propagating. This
|
|
1391
|
+
* resolver's callers are a banner, a doctor row and an evidence recorder; none of them has a
|
|
1392
|
+
* sensible behaviour for "asking about the ladder threw".
|
|
1393
|
+
* - `classifyIndexFace` writes no rebuild marker, so asking is not a mutation of the knowledge root.
|
|
1394
|
+
*
|
|
1395
|
+
* The memo inside `resolveEmbedderCapability` is what makes a second call in the same process free,
|
|
1396
|
+
* which is why `doctor` and the runner can both ask without paying twice.
|
|
1397
|
+
*/
|
|
1398
|
+
declare function resolveRetrievalRung(options: ResolveRetrievalRungOptions): Promise<RecordedRetrievalRung>;
|
|
1399
|
+
|
|
1400
|
+
/**
|
|
1401
|
+
* Fixed weighted-RRF vector for each deterministic query class (D-06).
|
|
1402
|
+
*
|
|
1403
|
+
* PROVISIONAL vectors pending M3's learned per-product replacements. Plain RRF with all three
|
|
1404
|
+
* weights equal to 1 is the declared cold-start floor; learning may replace vectors, never the
|
|
1405
|
+
* classifier itself.
|
|
1406
|
+
*/
|
|
1407
|
+
declare const QUERY_CLASS_WEIGHTS: {
|
|
1408
|
+
readonly literal: {
|
|
1409
|
+
readonly wLex: 1.5;
|
|
1410
|
+
readonly wDense: 0.5;
|
|
1411
|
+
readonly wAnchor: 2;
|
|
1412
|
+
};
|
|
1413
|
+
readonly mixed: {
|
|
1414
|
+
readonly wLex: 1;
|
|
1415
|
+
readonly wDense: 1;
|
|
1416
|
+
readonly wAnchor: 1.5;
|
|
1417
|
+
};
|
|
1418
|
+
readonly semantic: {
|
|
1419
|
+
readonly wLex: 0.5;
|
|
1420
|
+
readonly wDense: 1.5;
|
|
1421
|
+
readonly wAnchor: 1;
|
|
1422
|
+
};
|
|
1423
|
+
};
|
|
1424
|
+
|
|
1425
|
+
/**
|
|
1426
|
+
* D-06's closed query-class contract. The classifier is deterministic and total; future learned
|
|
1427
|
+
* weights may replace class vectors, but they must not replace or widen these classes implicitly.
|
|
1428
|
+
*/
|
|
1429
|
+
type QueryClass = 'literal' | 'mixed' | 'semantic';
|
|
1430
|
+
|
|
1431
|
+
/**
|
|
1432
|
+
* The deterministic memory.md §5.5.8 query door (377 D-13). Every identity anchor is normalized
|
|
1433
|
+
* through the schema authority before keys or matching helpers are derived. Raw selector atoms
|
|
1434
|
+
* remain lexical-only; dense text and fallback regions are assembled from structured fields.
|
|
1435
|
+
*/
|
|
1436
|
+
|
|
1437
|
+
interface RetrievalQueryInput {
|
|
1438
|
+
screenState?: ScreenState;
|
|
1439
|
+
intent: string;
|
|
1440
|
+
anchors: readonly Anchor[];
|
|
1441
|
+
}
|
|
1442
|
+
interface FallbackRendering {
|
|
1443
|
+
anchorIndex: number;
|
|
1444
|
+
lookupKey: string;
|
|
1445
|
+
text: string;
|
|
1446
|
+
reconfirmToken: string;
|
|
1447
|
+
fallback: true;
|
|
1448
|
+
anchorExact: false;
|
|
1449
|
+
}
|
|
1450
|
+
interface RetrievalQuery {
|
|
1451
|
+
lexicalQuery: string;
|
|
1452
|
+
semanticText: string;
|
|
1453
|
+
normalizedAnchors: Anchor[];
|
|
1454
|
+
anchorLookupKeys: string[];
|
|
1455
|
+
queryClass: QueryClass;
|
|
1456
|
+
weights: (typeof QUERY_CLASS_WEIGHTS)[QueryClass];
|
|
1457
|
+
fallbackRenderings: FallbackRendering[];
|
|
1458
|
+
}
|
|
1459
|
+
/**
|
|
1460
|
+
* Build both recall inputs from structured runner state. Fallback renderings are candidates only:
|
|
1461
|
+
* callers use them after exact/normalized anchor lookup misses and may set the admission
|
|
1462
|
+
* anchorExact carve-out only after a lexical hit re-confirms reconfirmToken (T-377-23).
|
|
1463
|
+
*/
|
|
1464
|
+
declare function buildRetrievalQuery(input: RetrievalQueryInput): RetrievalQuery;
|
|
1465
|
+
|
|
1466
|
+
interface AsOfRange {
|
|
1467
|
+
lo: number;
|
|
1468
|
+
hi: number;
|
|
1469
|
+
}
|
|
1470
|
+
|
|
1471
|
+
/**
|
|
1472
|
+
* Public memory.md §5.5 retrieval composition.
|
|
1473
|
+
*
|
|
1474
|
+
* Usage telemetry (§5.5.9) is deferred by architecture: reader connections are query_only, so
|
|
1475
|
+
* counters land with Phases 378/380's writer-owned paths and are never an input to trust.
|
|
1476
|
+
*/
|
|
1477
|
+
|
|
1478
|
+
interface RetrieveOptions {
|
|
1479
|
+
n: number;
|
|
1480
|
+
product: string;
|
|
1481
|
+
testKey?: string;
|
|
1482
|
+
suiteKey?: string;
|
|
1483
|
+
asOfBuild?: number;
|
|
1484
|
+
resolveLatestOrdinal?: (product: string) => number | undefined;
|
|
1485
|
+
runtimeRoot?: string;
|
|
1486
|
+
includeSuperseded?: boolean;
|
|
1487
|
+
asOfRange?: AsOfRange;
|
|
1488
|
+
/** Host-resolved posture; a deferred daemon capability forbids in-process fallback. */
|
|
1489
|
+
embeddingCapability?: AcquireEmbedderOutcome;
|
|
1490
|
+
}
|
|
1491
|
+
type RetrieveResult = IndexEntry[];
|
|
1492
|
+
/** Retrieve a deterministic ranked headline list through the reader's current capability. */
|
|
1493
|
+
declare function retrieve(reader: KnowledgeReader, query: RetrievalQueryInput, options: RetrieveOptions): Promise<RetrieveResult>;
|
|
1494
|
+
|
|
1495
|
+
interface RebuildReport {
|
|
1496
|
+
projected: number;
|
|
1497
|
+
skippedIncomplete: number;
|
|
1498
|
+
scanIssues: string[];
|
|
1499
|
+
removed: number;
|
|
1500
|
+
backfilled: number;
|
|
1501
|
+
vec: VecCapability;
|
|
1502
|
+
pendingEmbeddings: number;
|
|
1503
|
+
maintenanceRemaining: boolean;
|
|
1504
|
+
}
|
|
1505
|
+
type RebuildMutationFamily = 'project-bundle' | 'checkpoint-passive' | 'remove-missing-bundles' | 'complete-rendering-epoch' | 'complete-trust-epoch' | 'clear-rebuild-request';
|
|
1506
|
+
interface RebuildIndexHooks {
|
|
1507
|
+
/** Test/chaos seam after synchronous DML and immediately before the final commit fence. */
|
|
1508
|
+
beforeTransactionCommit?: () => void;
|
|
1509
|
+
/** Test/chaos seam immediately before one named authority unit acquires its hold. */
|
|
1510
|
+
beforeMutationAuthority?: (family: RebuildMutationFamily) => void;
|
|
1511
|
+
/** Test/chaos seam after authority is held and before the named mutation begins. */
|
|
1512
|
+
insideMutationAuthority?: (family: RebuildMutationFamily) => void;
|
|
1513
|
+
}
|
|
1514
|
+
interface RebuildIndexOptions {
|
|
1515
|
+
knowledgeRoot: string;
|
|
1516
|
+
priors?: TrustPriorTable;
|
|
1517
|
+
embedder?: EmbedderPort;
|
|
1518
|
+
vecLoadablePath?: string;
|
|
1519
|
+
writerAuthority?: WriterLeaseAuthority;
|
|
1520
|
+
hooks?: RebuildIndexHooks;
|
|
1521
|
+
}
|
|
1522
|
+
/**
|
|
1523
|
+
* WR-01 record-scoped healing: delete the total projection set for exactly the supplied bundle
|
|
1524
|
+
* ids inside one transaction and return the number of records removed. An absent index db,
|
|
1525
|
+
* empty ids, and ids without records rows are no-ops; embed_cache is untouched (purge-only A4).
|
|
1526
|
+
*/
|
|
1527
|
+
declare function removeBundleProjectionRows(knowledgeRoot: string, bundleIds: readonly string[], writerAuthority: WriterLeaseAuthority): number;
|
|
1528
|
+
/** Hash-selected projection plus the independent D-02 backfill and D-10 reconciliation passes. */
|
|
1529
|
+
declare function rebuildIndex(opts: RebuildIndexOptions): Promise<RebuildReport>;
|
|
1530
|
+
|
|
1531
|
+
declare function readLatestBuildOrdinal(runtimeRoot: string, product: string): number | undefined;
|
|
1532
|
+
|
|
1533
|
+
/** The one table name, so the read port and every writer cannot spell it apart. */
|
|
1534
|
+
declare const SUITE_FINGERPRINTS_TABLE = "suite_fingerprints";
|
|
1535
|
+
|
|
1536
|
+
/** One test's ordered fingerprint elements, keyed by the stable identity. */
|
|
1537
|
+
interface SuiteFingerprintTestDelta {
|
|
1538
|
+
filePath: string;
|
|
1539
|
+
testName: string;
|
|
1540
|
+
/** `actionAnchorElement` bytes, in exercised order. Never empty — see `testFingerprint`. */
|
|
1541
|
+
elements: string[];
|
|
1542
|
+
}
|
|
1543
|
+
/** The row set one run contributes, plus the provenance the replacement rule compares on. */
|
|
1544
|
+
interface SuiteFingerprintsProjection {
|
|
1545
|
+
product: string;
|
|
1546
|
+
runId: string;
|
|
1547
|
+
buildOrdinal: number;
|
|
1548
|
+
tests: SuiteFingerprintTestDelta[];
|
|
1549
|
+
}
|
|
1550
|
+
interface FoldSuiteFingerprintsOptions {
|
|
1551
|
+
/**
|
|
1552
|
+
* The projection partition — `projectionPartition(handoff.scope).product`. Supplied by the
|
|
1553
|
+
* caller so this module never re-spells the partition law that `run-outcomes.ts` owns (and so
|
|
1554
|
+
* the two modules do not have to import each other).
|
|
1555
|
+
*/
|
|
1556
|
+
product: string;
|
|
1557
|
+
/**
|
|
1558
|
+
* The `excludedFromOutcomes` decision, CARRIED rather than re-read. See the exclusion note in
|
|
1559
|
+
* this module's header: a gate-run contributes no rows.
|
|
1560
|
+
*/
|
|
1561
|
+
excluded: boolean;
|
|
1562
|
+
}
|
|
1563
|
+
/**
|
|
1564
|
+
* The per-identity deltas for a member list (pure).
|
|
1565
|
+
*
|
|
1566
|
+
* Takes MEMBERS rather than a handoff because the production caller has already applied the one
|
|
1567
|
+
* exclusion gate to them — see the exclusion note in the header. A test contributing zero
|
|
1568
|
+
* elements yields no delta at all, which is what stops an evidence-less run from ERASING an
|
|
1569
|
+
* identity's accumulated coverage: the union only ever moves through evidence.
|
|
1570
|
+
*/
|
|
1571
|
+
declare function suiteFingerprintDeltas(members: readonly PerTestOutcome[]): SuiteFingerprintTestDelta[];
|
|
1572
|
+
/**
|
|
1573
|
+
* Writer against the one index connection.
|
|
1574
|
+
*
|
|
1575
|
+
* Deliberately opens NO transaction of its own. On the production path it runs inside
|
|
1576
|
+
* `applyRunOutcomes`'s `BEGIN IMMEDIATE`, so the fingerprint rows and the outcome counters commit
|
|
1577
|
+
* or roll back together and the two tables can never describe different runs; SQLite has no
|
|
1578
|
+
* nested transactions, so a second `BEGIN IMMEDIATE` here would fail exactly on that path. Called
|
|
1579
|
+
* standalone it rides autocommit, which is sound because the replacement rule is convergent.
|
|
1580
|
+
*/
|
|
1581
|
+
declare function applySuiteFingerprints(db: DatabaseSync, projection: SuiteFingerprintsProjection): number;
|
|
1582
|
+
/**
|
|
1583
|
+
* The standalone fold door: project one handoff's fingerprints and write them.
|
|
1584
|
+
*
|
|
1585
|
+
* The production path does NOT come through here — it folds both projections in one pass through
|
|
1586
|
+
* `projectRunOutcomes`/`applyRunOutcomes` so a single transaction and a single applied-runs marker
|
|
1587
|
+
* cover both tables. This entry exists for callers that hold a handoff and want only the
|
|
1588
|
+
* fingerprint half (the gate evaluator's own harness, and this module's corpus).
|
|
1589
|
+
*/
|
|
1590
|
+
declare function foldSuiteFingerprints(db: DatabaseSync, handoff: CompletedRunHandoff, opts: FoldSuiteFingerprintsOptions): SuiteFingerprintsProjection;
|
|
1591
|
+
/**
|
|
1592
|
+
* The read port gate 3 consumes through composition (D-15).
|
|
1593
|
+
*
|
|
1594
|
+
* MINIMAL BY DESIGN. Conservatism lives in the normalizer (D-14), not here: this port answers
|
|
1595
|
+
* what the table holds and nothing more, so a later retune of "near-same elements normalize
|
|
1596
|
+
* equal" moves in exactly one place. There is no similarity verb here because there is no
|
|
1597
|
+
* similarity threshold to defend — gate 3's value test is set membership, spec §6.3 verbatim.
|
|
1598
|
+
*/
|
|
1599
|
+
interface SuiteFingerprintIndex {
|
|
1600
|
+
/** The union D-14's novel-element test compares against. Empty table, empty union. */
|
|
1601
|
+
elementUnion(): Set<string>;
|
|
1602
|
+
/**
|
|
1603
|
+
* The identities that HAVE fingerprint rows, sorted. The consumer subtracts these from the
|
|
1604
|
+
* authored-test universe to derive the evidence-less set that rides D-16's text lane — which is
|
|
1605
|
+
* why this port reports coverage rather than trying to enumerate the suite, a fact it does not
|
|
1606
|
+
* own and could only guess at.
|
|
1607
|
+
*/
|
|
1608
|
+
coveredTests(): Array<{
|
|
1609
|
+
filePath: string;
|
|
1610
|
+
testName: string;
|
|
1611
|
+
}>;
|
|
1612
|
+
/** One identity's elements in exercised order; `[]` for an identity with no rows. */
|
|
1613
|
+
elementsForTest(filePath: string, testName: string): string[];
|
|
1614
|
+
}
|
|
1615
|
+
interface SuiteFingerprintIndexOptions {
|
|
1616
|
+
/**
|
|
1617
|
+
* The partition to read. REQUIRED rather than optional: an unscoped union would compare a draft
|
|
1618
|
+
* against another product's suite, and "everything in the table" is never the question gate 3 is
|
|
1619
|
+
* asking.
|
|
1620
|
+
*/
|
|
1621
|
+
product: string;
|
|
1622
|
+
}
|
|
1623
|
+
declare function createSuiteFingerprintIndex(db: DatabaseSync, opts: SuiteFingerprintIndexOptions): SuiteFingerprintIndex;
|
|
1624
|
+
|
|
1625
|
+
/**
|
|
1626
|
+
* PROVISIONAL last-N window for per-test outcome history (~10 pending ABRF-02 ranking
|
|
1627
|
+
* measurements). Entries are {buildOrdinal, passed} — ordinals only, wall-clock never.
|
|
1628
|
+
* Shared by readers and writers without pulling writer authority into the read closure.
|
|
1629
|
+
*/
|
|
1630
|
+
declare const LAST_OUTCOMES_LIMIT = 10;
|
|
1631
|
+
|
|
1632
|
+
/**
|
|
1633
|
+
* Stamped into the curation-tail receipt's projection component. Bump when the fold
|
|
1634
|
+
* semantics or table shapes change so already-receipted runs refold on the next tail.
|
|
1635
|
+
*
|
|
1636
|
+
* HOW THAT REFOLD ACTUALLY HAPPENS (393 CR-02), because the receipt alone cannot do it. The tail
|
|
1637
|
+
* stores this number in each run's receipt, so a bump invalidates every receipt and the sweep
|
|
1638
|
+
* re-runs each historical run — but the per-run fold then answers 'already-applied' off the
|
|
1639
|
+
* durable marker and writes nothing. The stamp is therefore ALSO stored in the index itself, in
|
|
1640
|
+
* `run_outcome_projection_version`, and `reconcileRunOutcomesProjection` compares the two ONCE per
|
|
1641
|
+
* curation-tail sweep, before the per-run loop: a differing or absent stamp rebuilds the whole
|
|
1642
|
+
* projection family from the runs root through `rebuildRunOutcomes`, which clears the family
|
|
1643
|
+
* (marker included) and re-reads every `handoff.json` + `analysis.json` from disk. THAT is how an
|
|
1644
|
+
* already-receipted run contributes its elements. The per-run receipts then rewrite at the new
|
|
1645
|
+
* version through the same sweep. The family is derived, so the rebuild is the whole upgrade, and
|
|
1646
|
+
* it is a mechanism that runs, not an argument that it is unnecessary.
|
|
1647
|
+
*
|
|
1648
|
+
* NOT the case argued at `cli/src/commands/run.ts:1949` (390-08 D-01), where a bump was
|
|
1649
|
+
* deliberately declined: there the rebuild would have replayed stored handoffs carrying the OLD
|
|
1650
|
+
* identities, landing in the same mixed state the bump was meant to clear. Here the new table has
|
|
1651
|
+
* no historical rows at all, and every row it will hold is derivable from evidence the stored
|
|
1652
|
+
* handoffs already carry — so the refold produces the complete answer rather than a mixed one.
|
|
1653
|
+
*/
|
|
1654
|
+
declare const RUN_OUTCOMES_PROJECTION_VERSION = 2;
|
|
1655
|
+
|
|
1656
|
+
/** Anchor extraction seam: the CLI tail passes its exercisedAnchors(step) walk. */
|
|
1657
|
+
type ExtractStepAnchors = (step: StepEvidence) => Anchor[];
|
|
1658
|
+
/**
|
|
1659
|
+
* Projection inputs contain no exclusion override. The durable handoff marker is the sole
|
|
1660
|
+
* authority for current-run folds, sibling backfill, and full rebuild alike (D-14 §6).
|
|
1661
|
+
*/
|
|
1662
|
+
interface ProjectRunOutcomesOptions {
|
|
1663
|
+
extractAnchors: ExtractStepAnchors;
|
|
1664
|
+
/**
|
|
1665
|
+
* The run's persisted analysis artifact when one exists (390 D-09, the `ProjectCanaryOutcomes
|
|
1666
|
+
* Input.artifact` precedent). DATA, not a port: `foldRunOutcomes` and `rebuildRunOutcomes` each
|
|
1667
|
+
* load it from the run's own dir through the one shared loader and hand it here, so ONE
|
|
1668
|
+
* projection function with ONE signature serves both paths — a second signature only one path
|
|
1669
|
+
* calls is exactly how L12 rebuild parity breaks in silence.
|
|
1670
|
+
*/
|
|
1671
|
+
artifact?: RunAnalysisArtifact;
|
|
1672
|
+
}
|
|
1673
|
+
/**
|
|
1674
|
+
* What a FAILED member contributes to the fingerprint-keyed recurrence window (390 D-07).
|
|
1675
|
+
*
|
|
1676
|
+
* The fingerprint is composed through the ONE exported vocabulary — `failingStepOf`/`errorTextOf`
|
|
1677
|
+
* over `exercisedAnchors`, keyed by `failureFingerprint` — so this window and the render-time
|
|
1678
|
+
* cluster presentation cannot disagree about what "the same failure" is. The verdict class is part
|
|
1679
|
+
* of the key by recipe, which is why it travels beside it rather than being re-derived downstream.
|
|
1680
|
+
*/
|
|
1681
|
+
interface RunOutcomeFailureKey {
|
|
1682
|
+
fingerprint: string;
|
|
1683
|
+
verdictClass: VerdictClass;
|
|
1684
|
+
/**
|
|
1685
|
+
* WHICH pipeline authored the class (390-16). Not part of the fingerprint and not stored on
|
|
1686
|
+
* `run_fingerprint_windows` — it travels on the in-memory delta only, because the quarantine
|
|
1687
|
+
* ladder's floor-eligibility gate needs to know whether the class is a statement about THIS
|
|
1688
|
+
* TEST (an authored `analyze-run` verdict) or about the RUN (the deterministic floor, whose
|
|
1689
|
+
* `environment` arms are one health-probe result applied to every failing member).
|
|
1690
|
+
*/
|
|
1691
|
+
producer: Verdict['producer'];
|
|
1692
|
+
}
|
|
1693
|
+
interface RunOutcomeTestDelta {
|
|
1694
|
+
filePath: string;
|
|
1695
|
+
testName: string;
|
|
1696
|
+
passed: boolean;
|
|
1697
|
+
heals: number;
|
|
1698
|
+
flake: boolean;
|
|
1699
|
+
/** canonicalJson(normalizeAnchor(...)) keys — byte-deterministic (ABRF-02 encoding edge). */
|
|
1700
|
+
anchorKeys: string[];
|
|
1701
|
+
/** Present for exactly the failed members — a pass contributes no window row (D-07). */
|
|
1702
|
+
failure?: RunOutcomeFailureKey;
|
|
1703
|
+
}
|
|
1704
|
+
interface RunOutcomesProjection {
|
|
1705
|
+
product: string;
|
|
1706
|
+
scope: ScopeKey;
|
|
1707
|
+
runId: string;
|
|
1708
|
+
buildOrdinal: number;
|
|
1709
|
+
excluded: boolean;
|
|
1710
|
+
tests: RunOutcomeTestDelta[];
|
|
1711
|
+
/**
|
|
1712
|
+
* The suite-fingerprint deltas for the SAME members (393 D-15). They travel on this projection
|
|
1713
|
+
* rather than being folded by a second pass so that one traversal of the handoff produces both
|
|
1714
|
+
* tables, one transaction commits them, and one applied-runs marker covers them — which is what
|
|
1715
|
+
* makes rebuild parity structural instead of asserted.
|
|
1716
|
+
*/
|
|
1717
|
+
fingerprints: SuiteFingerprintTestDelta[];
|
|
1718
|
+
}
|
|
1719
|
+
type ApplyRunOutcomesResult = {
|
|
1720
|
+
kind: 'applied';
|
|
1721
|
+
tests: number;
|
|
1722
|
+
} | {
|
|
1723
|
+
kind: 'already-applied';
|
|
1724
|
+
tests: 0;
|
|
1725
|
+
};
|
|
1726
|
+
interface RebuildRunOutcomesOptions {
|
|
1727
|
+
extractAnchors: ExtractStepAnchors;
|
|
1728
|
+
}
|
|
1729
|
+
/**
|
|
1730
|
+
* What one rebuild did, with its two skip causes kept APART (393 round 7, CR-01-WIDENED).
|
|
1731
|
+
*
|
|
1732
|
+
* A single conflating counter answered "how many runs did not fold" and nothing an operator could
|
|
1733
|
+
* act on: a malformed `handoff.json` and an unloadable `analysis.json` are different files, written
|
|
1734
|
+
* by different producers, and fixed differently. There is deliberately no third counter for a
|
|
1735
|
+
* projection or write failure — that class is no longer a skip at all. It propagates out of
|
|
1736
|
+
* `rebuildRunOutcomes` and the rebuild produces no report.
|
|
1737
|
+
*/
|
|
1738
|
+
interface RebuildRunOutcomesReport {
|
|
1739
|
+
folded: number;
|
|
1740
|
+
/** Runs whose `handoff.json` would not load or carries a pre-381 / structurally unsafe shape. */
|
|
1741
|
+
skippedHandoffs: number;
|
|
1742
|
+
/** Runs whose `handoff.json` loaded but whose `analysis.json` threw (the D-09 second document). */
|
|
1743
|
+
skippedArtifacts: number;
|
|
1744
|
+
}
|
|
1745
|
+
/**
|
|
1746
|
+
* What the fold needs before it may evaluate the quarantine detection ladder (390 D-08).
|
|
1747
|
+
*
|
|
1748
|
+
* Grouped and OPTIONAL on purpose: a caller that cannot supply a clock does
|
|
1749
|
+
* not get a silently empty evaluation, it gets `{kind: 'not-evaluated', reason: 'not-requested'}`
|
|
1750
|
+
* on the report. "Detection ran and found nothing" and "detection never ran" are different facts.
|
|
1751
|
+
*/
|
|
1752
|
+
interface QuarantineDetectionOptions {
|
|
1753
|
+
/**
|
|
1754
|
+
* The ISO-8601 instant the evaluation is anchored to — the drain's own wall clock, read ONCE by
|
|
1755
|
+
* the caller. The fold and the rule below it stay clock-free (390-01's purity-by-argument), which
|
|
1756
|
+
* is what lets both expiry and the ladder be pinned one step either side.
|
|
1757
|
+
*/
|
|
1758
|
+
now: string;
|
|
1759
|
+
}
|
|
1760
|
+
interface FoldRunOutcomesOptions {
|
|
1761
|
+
/** Absolute agent-qa-knowledge root hosting the derived index SQLite. */
|
|
1762
|
+
knowledgeRoot: string;
|
|
1763
|
+
handoff: CompletedRunHandoff;
|
|
1764
|
+
extractAnchors: ExtractStepAnchors;
|
|
1765
|
+
/**
|
|
1766
|
+
* The run's own directory (`.agent-qa/runs/<slug(runId)>/`). When supplied, the fold loads
|
|
1767
|
+
* `analysis.json` from it so the counters read RESOLVED verdicts (D-09). Absent — a caller that
|
|
1768
|
+
* has no run dir — folds the deterministic floor, byte-identically to pre-390.
|
|
1769
|
+
*/
|
|
1770
|
+
runDir?: string;
|
|
1771
|
+
/** Present when the caller wants the D-08 detection step; absent skips it explicitly. */
|
|
1772
|
+
quarantine?: QuarantineDetectionOptions;
|
|
1773
|
+
}
|
|
1774
|
+
/**
|
|
1775
|
+
* What the fold's detection step did, as DATA (390 Pitfall 4).
|
|
1776
|
+
*
|
|
1777
|
+
* Every arm is a fact the caller can print. A ledger that could not be read is a value, not an
|
|
1778
|
+
* exception: a failure that vanished inside a catch is exactly how an `entered` event goes missing
|
|
1779
|
+
* in silence, and a missing `entered` event is a test that keeps failing builds with nobody told
|
|
1780
|
+
* why it was supposed to stop.
|
|
1781
|
+
*/
|
|
1782
|
+
type QuarantineFoldOutcome = {
|
|
1783
|
+
kind: 'not-evaluated';
|
|
1784
|
+
reason: 'already-applied' | 'not-requested';
|
|
1785
|
+
}
|
|
1786
|
+
/** The committed ledger could not be read at all — detection refuses rather than guessing. */
|
|
1787
|
+
| {
|
|
1788
|
+
kind: 'ledger-unreadable';
|
|
1789
|
+
reason: string;
|
|
1790
|
+
} | {
|
|
1791
|
+
kind: 'evaluated';
|
|
1792
|
+
append: QuarantineAppendOutcome;
|
|
1793
|
+
events: readonly QuarantineLedgerEvent[];
|
|
1794
|
+
flagged: readonly QuarantineDetectionSighting[];
|
|
1795
|
+
escalatedNotQuarantined: readonly QuarantineDetectionSighting[];
|
|
1796
|
+
refusedLines: readonly RefusedQuarantineLine[];
|
|
1797
|
+
};
|
|
1798
|
+
type FoldRunOutcomesReport = ApplyRunOutcomesResult & {
|
|
1799
|
+
quarantine: QuarantineFoldOutcome;
|
|
1800
|
+
};
|
|
1801
|
+
/** Pure fold: identical (handoff, artifact) bytes yield identical row deltas. */
|
|
1802
|
+
declare function projectRunOutcomes(handoff: CompletedRunHandoff, opts: ProjectRunOutcomesOptions): RunOutcomesProjection;
|
|
1803
|
+
/**
|
|
1804
|
+
* Writer against the one index connection. Idempotent per product/runId: the applied-runs
|
|
1805
|
+
* marker commits in the same transaction as the counter rows, so a crash-rerun tail that
|
|
1806
|
+
* refolds an already-applied partition (receipt withheld mid-tail) changes nothing.
|
|
1807
|
+
*/
|
|
1808
|
+
declare function applyRunOutcomes(db: DatabaseSync, projection: RunOutcomesProjection): ApplyRunOutcomesResult;
|
|
1809
|
+
/**
|
|
1810
|
+
* Full rebuild: scan and read every run dir under `runsRoot`, then clear the projection tables
|
|
1811
|
+
* and refold each loadable handoff. Reproduces tables byte-identical to the incremental fold
|
|
1812
|
+
* (L12); a rebuild over zero handoff dirs yields empty tables without error (ABRF-02
|
|
1813
|
+
* empty edge). BAD-BYTES load failures and pre-381 shapes are counted skips — including a run whose
|
|
1814
|
+
* `analysis.json` will not decode, which costs that run's contribution and nothing else (393 round
|
|
1815
|
+
* 6, CR-01). One undecodable artifact must never truncate a family this function has already
|
|
1816
|
+
* read; an errno-coded HOST fault on either document, on the runs root, or on any run dir
|
|
1817
|
+
* propagates BEFORE the family is deleted, so no sweep can stamp — or empty — a family the
|
|
1818
|
+
* filesystem prevented it from reading (418-12, CR-01-EXISTS).
|
|
1819
|
+
*
|
|
1820
|
+
* Phase A: no document is destroyed before every document was read — a host fault during reads
|
|
1821
|
+
* leaves the previous family and its stamp untouched (418-12, CR-02-DESTRUCTIVE, load-before-delete).
|
|
1822
|
+
* The list holds parsed handoffs for one sweep; the runs root is bounded by host run retention.
|
|
1823
|
+
*
|
|
1824
|
+
* Phase B is DELETE-FIRST, STAMP-LAST, and that order is the crash story rather than a style choice (393
|
|
1825
|
+
* CR-02). The version row is cleared with the family it describes and re-written only after the
|
|
1826
|
+
* refold loop has run to completion, so a crash anywhere in between leaves NO stamp — which
|
|
1827
|
+
* `reconcileRunOutcomesProjection` reads as a mismatch and rebuilds again. The projection
|
|
1828
|
+
* therefore self-heals from a partial rebuild instead of stamping a half-built family as current.
|
|
1829
|
+
*/
|
|
1830
|
+
declare function rebuildRunOutcomes(db: DatabaseSync, runsRoot: string, opts: RebuildRunOutcomesOptions): RebuildRunOutcomesReport;
|
|
1831
|
+
/** What one reconcile did — a fact the caller can print, never a silent side effect. */
|
|
1832
|
+
type ReconcileRunOutcomesProjectionResult = {
|
|
1833
|
+
kind: 'current';
|
|
1834
|
+
} | {
|
|
1835
|
+
kind: 'rebuilt';
|
|
1836
|
+
report: RebuildRunOutcomesReport;
|
|
1837
|
+
} | {
|
|
1838
|
+
kind: 'skipped';
|
|
1839
|
+
reason: 'no-writer-authority';
|
|
1840
|
+
};
|
|
1841
|
+
interface ReconcileRunOutcomesProjectionOptions {
|
|
1842
|
+
/** The exact live writer lease owned by the caller; never inferred from an epoch alone. */
|
|
1843
|
+
authority?: {
|
|
1844
|
+
leaseId: string;
|
|
1845
|
+
epoch: number;
|
|
1846
|
+
};
|
|
1847
|
+
/** Absolute agent-qa-knowledge root hosting the derived index SQLite. */
|
|
1848
|
+
knowledgeRoot: string;
|
|
1849
|
+
/** `<agentQaRoot>/runs` — the scan root the rebuild refolds from. */
|
|
1850
|
+
runsRoot: string;
|
|
1851
|
+
extractAnchors: ExtractStepAnchors;
|
|
1852
|
+
}
|
|
1853
|
+
/**
|
|
1854
|
+
* THE version trigger: reconcile the stored fold semantics with the shipped ones (393 CR-02).
|
|
1855
|
+
*
|
|
1856
|
+
* `RUN_OUTCOMES_PROJECTION_VERSION`'s doc block has always promised that a bump makes
|
|
1857
|
+
* already-receipted runs refold. Nothing performed that refold: `applyRunOutcomes` short-circuits
|
|
1858
|
+
* on the `run_outcome_applied_runs` marker before it can reach the fingerprint write, and nothing
|
|
1859
|
+
* cleared the marker on a version change — so on any project that folded runs before a bump, the
|
|
1860
|
+
* new table stayed empty forever and gate 3's fingerprint lane never had data to decide on. This
|
|
1861
|
+
* function is what makes that promise true, and it composes machinery that already existed rather
|
|
1862
|
+
* than adding a parallel path: `rebuildRunOutcomes` already clears the family, already re-reads
|
|
1863
|
+
* every `handoff.json` + `analysis.json` through the one shared loader, and already reaches
|
|
1864
|
+
* `applySuiteFingerprints` for every fold.
|
|
1865
|
+
*
|
|
1866
|
+
* ABSENT MEANS MISMATCH, deliberately. Every pre-stamp index reads as absent, which is exactly the
|
|
1867
|
+
* population that needs to converge; so does an index whose file was deleted, which is exactly the
|
|
1868
|
+
* population that needs to re-heal. Treating absence as "probably fine" would have made the
|
|
1869
|
+
* upgrade path the one path this function does not serve.
|
|
1870
|
+
*
|
|
1871
|
+
* WHY A REBUILD RATHER THAN A PER-RUN VERSION COLUMN. Refolding runs in place through the
|
|
1872
|
+
* incremental path would add each run's counters a SECOND time — the fold accumulates, it does not
|
|
1873
|
+
* replace. The rebuild is the mechanism precisely because it clears before it refolds, which is
|
|
1874
|
+
* also why the derived family is safe to move this way at all (L12: every row here is reproducible
|
|
1875
|
+
* from run artifacts on disk).
|
|
1876
|
+
*
|
|
1877
|
+
* 418-12 WR-03: a destructive rebuild of a shared derived family is a leased act. A caller
|
|
1878
|
+
* without authority gets a typed skip before opening a writer; it stays stale until a leased
|
|
1879
|
+
* sweep. The version check and entire rebuild share the current-authority generation lock.
|
|
1880
|
+
*/
|
|
1881
|
+
declare function reconcileRunOutcomesProjection(opts: ReconcileRunOutcomesProjectionOptions): ReconcileRunOutcomesProjectionResult;
|
|
1882
|
+
/**
|
|
1883
|
+
* Incremental fold wrapper for the post-verdict tail: opens the one index writer, applies
|
|
1884
|
+
* the projection, and closes. The tail invokes it inside the SAME crash boundary and the
|
|
1885
|
+
* SAME (extended) receipt as candidate/canary emit — never a second marker file.
|
|
1886
|
+
*
|
|
1887
|
+
* Detection hangs off the `'applied'` arm ONLY (D-08). `applyRunOutcomes` answers
|
|
1888
|
+
* `'already-applied'` from an early return that fires before its transaction even opens, so
|
|
1889
|
+
* "a refold never double-quarantines" is true by POSITION — there is no second idempotency
|
|
1890
|
+
* condition here to keep in sync with the marker.
|
|
1891
|
+
*/
|
|
1892
|
+
declare function foldRunOutcomes(opts: FoldRunOutcomesOptions): FoldRunOutcomesReport;
|
|
1893
|
+
|
|
1894
|
+
/**
|
|
1895
|
+
* Read side of the run-outcome projection (389 ANLZ-03, RESEARCH Pitfall 2).
|
|
1896
|
+
*
|
|
1897
|
+
* `run_test_outcomes` is written by `foldRunOutcomes`/`applyRunOutcomes`; this module is
|
|
1898
|
+
* the one place that queries it. Strictly read-only: one prepared SELECT, no statement
|
|
1899
|
+
* that mutates a row, ever — the writer half stays whole in `run-outcomes.ts`.
|
|
1900
|
+
*
|
|
1901
|
+
* KEY LAW — stable test identity is `(product, filePath, testName)`, exactly the
|
|
1902
|
+
* projection's primary key and per-test-outcome.ts's identity rule. Callers joining from
|
|
1903
|
+
* a handoff use `PerTestOutcome.filePath` + `testName`, NEVER `testId` (a per-run
|
|
1904
|
+
* explicit id, not a durable identity).
|
|
1905
|
+
*/
|
|
1906
|
+
|
|
1907
|
+
/** One window entry: ordinals only, wall-clock never (mirrors the writer's OutcomeEntry). */
|
|
1908
|
+
interface TestOutcomeEntry {
|
|
1909
|
+
buildOrdinal: number;
|
|
1910
|
+
passed: boolean;
|
|
1911
|
+
}
|
|
1912
|
+
interface TestOutcomeHistory {
|
|
1913
|
+
passes: number;
|
|
1914
|
+
failures: number;
|
|
1915
|
+
heals: number;
|
|
1916
|
+
flakeCount: number;
|
|
1917
|
+
/** Ordinal-ascending, at most LAST_OUTCOMES_LIMIT entries; [] when the stored JSON is malformed. */
|
|
1918
|
+
lastOutcomes: TestOutcomeEntry[];
|
|
1919
|
+
lastBuildOrdinal: number | undefined;
|
|
1920
|
+
}
|
|
1921
|
+
/** The projection's key, spelled the way the table is keyed. */
|
|
1922
|
+
interface TestOutcomeIdentity {
|
|
1923
|
+
product: string;
|
|
1924
|
+
filePath: string;
|
|
1925
|
+
testName: string;
|
|
1926
|
+
}
|
|
1927
|
+
/**
|
|
1928
|
+
* Answer one test's failure history from `run_test_outcomes`, or `undefined` when the
|
|
1929
|
+
* projection has never counted the test — typed absence, never an empty stand-in row.
|
|
1930
|
+
*/
|
|
1931
|
+
declare function readTestOutcomeHistory(db: DatabaseSync, identity: TestOutcomeIdentity): TestOutcomeHistory | undefined;
|
|
1932
|
+
/**
|
|
1933
|
+
* Every identity the projection has counted inside ONE file, in one product (394-17 · WTST-05).
|
|
1934
|
+
*
|
|
1935
|
+
* The neighbours side of D-14's stability read: "which tests does this suite file already have run
|
|
1936
|
+
* evidence for". Keyed on the projection's own primary key, so `product` is REQUIRED for the same
|
|
1937
|
+
* reason `readTestOutcomeHistory` requires it — a query that dropped it would serve every
|
|
1938
|
+
* product's rows under one file path and report another application's tests as this target's.
|
|
1939
|
+
*
|
|
1940
|
+
* `test_name` ORDER, so a caller's message names its neighbours in a stable order across runs. An
|
|
1941
|
+
* empty array is the honest answer for a file the projection has never counted; the caller turns
|
|
1942
|
+
* that into a `no-history` posture rather than into a clean bill of health.
|
|
1943
|
+
*/
|
|
1944
|
+
declare function listTestsInFile(db: DatabaseSync, scope: {
|
|
1945
|
+
product: string;
|
|
1946
|
+
filePath: string;
|
|
1947
|
+
}): string[];
|
|
1948
|
+
/**
|
|
1949
|
+
* D-02's forced discriminator channel: did the same step pass on the previous build?
|
|
1950
|
+
* Answers the entry with the greatest buildOrdinal STRICTLY below `currentBuildOrdinal`,
|
|
1951
|
+
* or `undefined` when no prior build is in the window (empty history, a single
|
|
1952
|
+
* current-build entry, or every entry at/above current) — prior-build honestly absent,
|
|
1953
|
+
* never faked from the current entry.
|
|
1954
|
+
*/
|
|
1955
|
+
declare function priorBuildOutcome(history: TestOutcomeHistory, currentBuildOrdinal: number): TestOutcomeEntry | undefined;
|
|
1956
|
+
interface FailureRecurrence {
|
|
1957
|
+
/** Failed entries with buildOrdinal AT OR BELOW current — includes the current failure when recorded. */
|
|
1958
|
+
kth: number;
|
|
1959
|
+
/** Distinct buildOrdinals observed in lastOutcomes — honest about the ≤LAST_OUTCOMES_LIMIT window. */
|
|
1960
|
+
windowBuilds: number;
|
|
1961
|
+
}
|
|
1962
|
+
/**
|
|
1963
|
+
* Feeds "Kth failure in the last N builds", computed LIVE at render time (D-08) — counts
|
|
1964
|
+
* derived from the window on every call, never stored prose. 390 rebinds the same seam to
|
|
1965
|
+
* its fingerprint-window computation; this derivation is 389's binding, not the seam's
|
|
1966
|
+
* final owner. An empty history answers {kth: 0, windowBuilds: 0}: the renderer (plan 05)
|
|
1967
|
+
* turns zero-history into an explicit no-history clause, so absence stays typed.
|
|
1968
|
+
*/
|
|
1969
|
+
declare function failureRecurrence(history: TestOutcomeHistory, currentBuildOrdinal: number): FailureRecurrence;
|
|
1970
|
+
|
|
1971
|
+
/**
|
|
1972
|
+
* PROVISIONAL D-13 superseded-generation retention depth. M3 may calibrate the
|
|
1973
|
+
* value against gate receipts, but it remains an internal constitution value
|
|
1974
|
+
* and never a runtime config key.
|
|
1975
|
+
*/
|
|
1976
|
+
declare const GC_SUPERSEDED_RETAIN_K = 3;
|
|
1977
|
+
/**
|
|
1978
|
+
* D-13 gate seam. M2 always passes `{ kind: 'none' }`; M3 plugs real gate
|
|
1979
|
+
* receipt ordinals into the second variant with zero shape change.
|
|
1980
|
+
*/
|
|
1981
|
+
type GateHorizon = {
|
|
1982
|
+
kind: 'none';
|
|
1983
|
+
} | {
|
|
1984
|
+
kind: 'ordinal';
|
|
1985
|
+
deepestGateOrdinal: number;
|
|
1986
|
+
};
|
|
1987
|
+
interface GcSummary {
|
|
1988
|
+
trimmedRecordIds: RecordId[];
|
|
1989
|
+
skipped: {
|
|
1990
|
+
unknownRef: number;
|
|
1991
|
+
withinK: number;
|
|
1992
|
+
userOrigin: number;
|
|
1993
|
+
horizon: number;
|
|
1994
|
+
};
|
|
1995
|
+
}
|
|
1996
|
+
interface RunKnowledgeGcInput {
|
|
1997
|
+
knowledgeRoot: string;
|
|
1998
|
+
horizon: GateHorizon;
|
|
1999
|
+
retainK?: number;
|
|
2000
|
+
}
|
|
2001
|
+
interface RunKnowledgeGcHooks {
|
|
2002
|
+
/** Test/chaos seam immediately before the authority check for one planned removal. */
|
|
2003
|
+
beforeGcRemoval?(recordId: RecordId): void;
|
|
2004
|
+
}
|
|
2005
|
+
/**
|
|
2006
|
+
* Trim only whole superseded bundle directories after constructing every D-13
|
|
2007
|
+
* exclusion set. No projection SQL exists here by design: the drain tail feeds
|
|
2008
|
+
* trimmedRecordIds straight into removeBundleProjectionRows, so the disposable
|
|
2009
|
+
* index heals in the same drain (WR-01).
|
|
2010
|
+
*
|
|
2011
|
+
* RATIFICATION: this typed in-memory summary, surfaced through drain diagnostics,
|
|
2012
|
+
* is the low-cost §9.2-style operational note. GC writes no persisted note artifact.
|
|
2013
|
+
*/
|
|
2014
|
+
declare function runKnowledgeGc(input: RunKnowledgeGcInput, writerAuthority: WriterLeaseAuthority, hooks?: RunKnowledgeGcHooks): GcSummary;
|
|
2015
|
+
|
|
2016
|
+
/**
|
|
2017
|
+
* D-19 active-profile migration over the derived index.
|
|
2018
|
+
*
|
|
2019
|
+
* M2 keeps this library-only: Phase 378's drainer binds it to runtime
|
|
2020
|
+
* coordination, while Phase 382 owns any eventual CLI cutover surface. Rows
|
|
2021
|
+
* projected after the frozen snapshot take the benign lag direction: the flip
|
|
2022
|
+
* marks them pending so 375's unchanged backfill selector heals them.
|
|
2023
|
+
*/
|
|
2024
|
+
|
|
2025
|
+
type MigrationOutcome = {
|
|
2026
|
+
flipped: true;
|
|
2027
|
+
profileKey: string;
|
|
2028
|
+
} | {
|
|
2029
|
+
flipped: false;
|
|
2030
|
+
missing: string[];
|
|
2031
|
+
};
|
|
2032
|
+
interface SetActiveEmbeddingProfileOptions {
|
|
2033
|
+
db: DatabaseSync;
|
|
2034
|
+
vec: VecCapability;
|
|
2035
|
+
target: {
|
|
2036
|
+
profile: EmbeddingProfile;
|
|
2037
|
+
embedder: EmbedderPort;
|
|
2038
|
+
};
|
|
2039
|
+
}
|
|
2040
|
+
/**
|
|
2041
|
+
* Stage every frozen record for a schema-owned target profile, then atomically
|
|
2042
|
+
* flip only when the exact frozen member set is complete.
|
|
2043
|
+
*/
|
|
2044
|
+
declare function setActiveEmbeddingProfile(options: SetActiveEmbeddingProfileOptions): Promise<MigrationOutcome>;
|
|
2045
|
+
|
|
2046
|
+
type FloorAssetLoadErrorCode = 'package-root-not-found' | 'manifest-invalid' | 'asset-read-failed' | 'asset-size-mismatch' | 'digest-mismatch' | 'binary-invalid' | 'tokenizer-invalid' | 'tokenizer-runtime-unavailable';
|
|
2047
|
+
declare class FloorAssetLoadError extends Error {
|
|
2048
|
+
readonly code: FloorAssetLoadErrorCode;
|
|
2049
|
+
constructor(code: FloorAssetLoadErrorCode, message: string, options?: ErrorOptions);
|
|
2050
|
+
}
|
|
2051
|
+
type FloorEmbeddingErrorCode = 'empty-token-set' | 'token-id-out-of-range' | 'zero-vector';
|
|
2052
|
+
declare class FloorEmbeddingError extends Error {
|
|
2053
|
+
readonly code: FloorEmbeddingErrorCode;
|
|
2054
|
+
constructor(code: FloorEmbeddingErrorCode, message: string, options?: ErrorOptions);
|
|
2055
|
+
}
|
|
2056
|
+
interface FloorAssets {
|
|
2057
|
+
tokenizer: Tokenizer;
|
|
2058
|
+
vocabularySize: number;
|
|
2059
|
+
dimension: number;
|
|
2060
|
+
scales: Float32Array;
|
|
2061
|
+
weights: Int8Array;
|
|
2062
|
+
}
|
|
2063
|
+
interface FloorAssetLoadOptions {
|
|
2064
|
+
/** Test-only injection seam. Production callers resolve the committed package asset. */
|
|
2065
|
+
assetsDir?: string;
|
|
2066
|
+
/** Optional caller-owned token cap for bounded benchmark/runtime work. */
|
|
2067
|
+
maxTokens?: number;
|
|
2068
|
+
}
|
|
2069
|
+
declare function loadFloorAssets(options?: FloorAssetLoadOptions): Promise<FloorAssets>;
|
|
2070
|
+
/**
|
|
2071
|
+
* Construct the pure-TypeScript degradation-floor embedder without loading assets eagerly.
|
|
2072
|
+
*
|
|
2073
|
+
* The static floor profile has empty document and query prefixes, so both legs intentionally
|
|
2074
|
+
* share exactly the same token lookup, mean pooling, and L2-normalization implementation.
|
|
2075
|
+
*/
|
|
2076
|
+
declare function createFloorEmbedder(options?: FloorAssetLoadOptions): EmbedderPort;
|
|
2077
|
+
|
|
2078
|
+
declare class NativeEmbeddingModuleLoadError extends Error {
|
|
2079
|
+
constructor(cause: unknown);
|
|
2080
|
+
}
|
|
2081
|
+
declare class NativeEmbeddingDimensionError extends RangeError {
|
|
2082
|
+
readonly actualDim: number;
|
|
2083
|
+
readonly expectedDim: number;
|
|
2084
|
+
constructor(actualDim: number, expectedDim: number);
|
|
2085
|
+
}
|
|
2086
|
+
declare function createNativeEmbedder(options: {
|
|
2087
|
+
profile: EmbeddingProfile;
|
|
2088
|
+
allowDownload: boolean;
|
|
2089
|
+
/** Optional process-wide token budget fixed by the first acquisition for this model identity. */
|
|
2090
|
+
maxTokens?: number;
|
|
2091
|
+
}): Promise<EmbedderPort>;
|
|
2092
|
+
|
|
2093
|
+
declare const MODEL_CACHE_DIR_ENV_VAR = "AGENT_QA_MODEL_CACHE_DIR";
|
|
2094
|
+
/**
|
|
2095
|
+
* Resolve the shared model cache used by every native embedder acquisition.
|
|
2096
|
+
*
|
|
2097
|
+
* D-11: one download per machine across all projects, with artifacts identified
|
|
2098
|
+
* by (model_id, revision). An explicit agent-qa override wins, then the XDG
|
|
2099
|
+
* cache root, with the conventional home cache as the final fallback.
|
|
2100
|
+
*/
|
|
2101
|
+
declare function resolveModelCacheDir(): string;
|
|
2102
|
+
|
|
2103
|
+
/**
|
|
2104
|
+
* The embedder worker's half of the one process-identity vocabulary in this package.
|
|
2105
|
+
*
|
|
2106
|
+
* This is a separate module from `worker-registration.ts` on purpose. Registration reading and
|
|
2107
|
+
* socket probing are reachable from the read-only serving entry, and `reader-import-closure`
|
|
2108
|
+
* forbids that closure from crossing into `lease/`. The *signal decision* is a writer-side concern
|
|
2109
|
+
* that the reader never makes, so it lives here — which lets both kill paths in this package share
|
|
2110
|
+
* CR-04's single `resolveProcessIncarnation` definition instead of growing a second, subtly
|
|
2111
|
+
* different identity scheme.
|
|
2112
|
+
*/
|
|
2113
|
+
|
|
2114
|
+
/**
|
|
2115
|
+
* Compare the registration's recorded incarnation against the pid's CURRENT occupant.
|
|
2116
|
+
*
|
|
2117
|
+
* CR-05: a schema-valid registration naming a live pid whose socket has stopped answering is not
|
|
2118
|
+
* proof that the worker is still there. Once the worker died, the kernel is free to hand its pid to
|
|
2119
|
+
* a stranger, and every decision keyed on that number alone targets whoever holds it now. The one
|
|
2120
|
+
* fact that separates them is assigned by the OS and cannot be forged from inside the file: when
|
|
2121
|
+
* the process at that pid started.
|
|
2122
|
+
*
|
|
2123
|
+
* `mismatch` means the registered worker is provably gone; `unverifiable` means we cannot say, and
|
|
2124
|
+
* that is a refusal rather than a default-allow. Neither may be signalled — and neither needs to
|
|
2125
|
+
* be, because generation-specific sockets (Plan 24) let a fresh worker take a clean address without
|
|
2126
|
+
* the old pid ever being touched.
|
|
2127
|
+
*/
|
|
2128
|
+
declare function verifyEmbedderWorkerIncarnation(registration: EmbedderWorkerRegistration): EmbedderWorkerIncarnationVerdict;
|
|
2129
|
+
|
|
2130
|
+
declare const CURATION_QUEUE_SCHEMA_VERSION = 2;
|
|
2131
|
+
declare const curationArtifactRoleSchema: z.ZodEnum<{
|
|
2132
|
+
"dom-snapshot": "dom-snapshot";
|
|
2133
|
+
"ax-snapshot": "ax-snapshot";
|
|
2134
|
+
screenshot: "screenshot";
|
|
2135
|
+
"opaque-evidence": "opaque-evidence";
|
|
2136
|
+
}>;
|
|
2137
|
+
declare const curationArtifactDescriptorSchema: z.ZodObject<{
|
|
2138
|
+
ref: z.ZodType<ArtifactRef, unknown, z.core.$ZodTypeInternals<ArtifactRef, unknown>>;
|
|
2139
|
+
stepIndex: z.ZodNumber;
|
|
2140
|
+
role: z.ZodEnum<{
|
|
2141
|
+
"dom-snapshot": "dom-snapshot";
|
|
2142
|
+
"ax-snapshot": "ax-snapshot";
|
|
2143
|
+
screenshot: "screenshot";
|
|
2144
|
+
"opaque-evidence": "opaque-evidence";
|
|
2145
|
+
}>;
|
|
2146
|
+
originalName: z.ZodString;
|
|
2147
|
+
}, z.core.$strict>;
|
|
2148
|
+
declare const artifactInventoryEntrySchema: z.ZodObject<{
|
|
2149
|
+
role: z.ZodEnum<{
|
|
2150
|
+
"dom-snapshot": "dom-snapshot";
|
|
2151
|
+
"ax-snapshot": "ax-snapshot";
|
|
2152
|
+
screenshot: "screenshot";
|
|
2153
|
+
"opaque-evidence": "opaque-evidence";
|
|
2154
|
+
}>;
|
|
2155
|
+
originalName: z.ZodString;
|
|
2156
|
+
relativePath: z.ZodString;
|
|
2157
|
+
sha256: z.ZodString;
|
|
2158
|
+
bytes: z.ZodNumber;
|
|
2159
|
+
stepIndex: z.ZodNumber;
|
|
2160
|
+
}, z.core.$strict>;
|
|
2161
|
+
declare const curationCandidateProjectionSchema: z.ZodObject<{
|
|
2162
|
+
artifactDescriptors: z.ZodArray<z.ZodObject<{
|
|
2163
|
+
ref: z.ZodType<ArtifactRef, unknown, z.core.$ZodTypeInternals<ArtifactRef, unknown>>;
|
|
2164
|
+
stepIndex: z.ZodNumber;
|
|
2165
|
+
role: z.ZodEnum<{
|
|
2166
|
+
"dom-snapshot": "dom-snapshot";
|
|
2167
|
+
"ax-snapshot": "ax-snapshot";
|
|
2168
|
+
screenshot: "screenshot";
|
|
2169
|
+
"opaque-evidence": "opaque-evidence";
|
|
2170
|
+
}>;
|
|
2171
|
+
originalName: z.ZodString;
|
|
2172
|
+
}, z.core.$strict>>;
|
|
2173
|
+
emittedAt: z.ZodString;
|
|
2174
|
+
sourceRunId: z.ZodString;
|
|
2175
|
+
scope: z.ZodType<ScopeKey, unknown, z.core.$ZodTypeInternals<ScopeKey, unknown>>;
|
|
2176
|
+
buildOrdinal: z.ZodNumber;
|
|
2177
|
+
executionContext: z.ZodType<ExecutionContext, unknown, z.core.$ZodTypeInternals<ExecutionContext, unknown>>;
|
|
2178
|
+
kind: z.ZodType<BundleKind, unknown, z.core.$ZodTypeInternals<BundleKind, unknown>>;
|
|
2179
|
+
subtype: z.ZodOptional<z.ZodType<FactSubtype, unknown, z.core.$ZodTypeInternals<FactSubtype, unknown>>>;
|
|
2180
|
+
rootCauseClass: z.ZodOptional<z.ZodEnum<{
|
|
2181
|
+
environment: "environment";
|
|
2182
|
+
timeout: "timeout";
|
|
2183
|
+
flake: "flake";
|
|
2184
|
+
}>>;
|
|
2185
|
+
anchors: z.ZodArray<z.ZodType<_vostride_agent_qa_schema.Anchor, unknown, z.core.$ZodTypeInternals<_vostride_agent_qa_schema.Anchor, unknown>>>;
|
|
2186
|
+
summarySeed: z.ZodString;
|
|
2187
|
+
bodySeed: z.ZodString;
|
|
2188
|
+
distilledObservations: z.ZodArray<z.ZodObject<{
|
|
2189
|
+
schemaVersion: z.ZodNumber;
|
|
2190
|
+
step: z.ZodObject<{
|
|
2191
|
+
naturalKey: z.ZodString;
|
|
2192
|
+
ordinal: z.ZodNumber;
|
|
2193
|
+
}, z.core.$strict>;
|
|
2194
|
+
platform: z.ZodOptional<z.ZodEnum<{
|
|
2195
|
+
web: "web";
|
|
2196
|
+
mobile: "mobile";
|
|
2197
|
+
}>>;
|
|
2198
|
+
test: z.ZodOptional<z.ZodObject<{
|
|
2199
|
+
id: z.ZodString;
|
|
2200
|
+
}, z.core.$strict>>;
|
|
2201
|
+
procedure: z.ZodOptional<z.ZodObject<{
|
|
2202
|
+
id: z.ZodString;
|
|
2203
|
+
}, z.core.$strict>>;
|
|
2204
|
+
flow: z.ZodOptional<z.ZodObject<{
|
|
2205
|
+
name: z.ZodString;
|
|
2206
|
+
precedes: z.ZodOptional<z.ZodString>;
|
|
2207
|
+
}, z.core.$strict>>;
|
|
2208
|
+
surface: z.ZodOptional<z.ZodObject<{
|
|
2209
|
+
kind: z.ZodEnum<{
|
|
2210
|
+
page: "page";
|
|
2211
|
+
screen: "screen";
|
|
2212
|
+
}>;
|
|
2213
|
+
naturalKey: z.ZodString;
|
|
2214
|
+
}, z.core.$strict>>;
|
|
2215
|
+
element: z.ZodOptional<z.ZodObject<{
|
|
2216
|
+
naturalKey: z.ZodString;
|
|
2217
|
+
}, z.core.$strict>>;
|
|
2218
|
+
locator: z.ZodOptional<z.ZodObject<{
|
|
2219
|
+
selector: z.ZodString;
|
|
2220
|
+
}, z.core.$strict>>;
|
|
2221
|
+
error: z.ZodOptional<z.ZodObject<{
|
|
2222
|
+
naturalKey: z.ZodString;
|
|
2223
|
+
rootCauseClass: z.ZodOptional<z.ZodEnum<{
|
|
2224
|
+
environment: "environment";
|
|
2225
|
+
timeout: "timeout";
|
|
2226
|
+
flake: "flake";
|
|
2227
|
+
}>>;
|
|
2228
|
+
}, z.core.$strict>>;
|
|
2229
|
+
observedAtOrdinal: z.ZodNumber;
|
|
2230
|
+
}, z.core.$strict>>;
|
|
2231
|
+
evidenceToken: z.ZodString;
|
|
2232
|
+
attributingObservationId: z.ZodString;
|
|
2233
|
+
}, z.core.$strict>;
|
|
2234
|
+
declare const curationCandidateAddressFieldsSchema: z.ZodObject<{
|
|
2235
|
+
artifactInventory: z.ZodArray<z.ZodObject<{
|
|
2236
|
+
role: z.ZodEnum<{
|
|
2237
|
+
"dom-snapshot": "dom-snapshot";
|
|
2238
|
+
"ax-snapshot": "ax-snapshot";
|
|
2239
|
+
screenshot: "screenshot";
|
|
2240
|
+
"opaque-evidence": "opaque-evidence";
|
|
2241
|
+
}>;
|
|
2242
|
+
originalName: z.ZodString;
|
|
2243
|
+
relativePath: z.ZodString;
|
|
2244
|
+
sha256: z.ZodString;
|
|
2245
|
+
bytes: z.ZodNumber;
|
|
2246
|
+
stepIndex: z.ZodNumber;
|
|
2247
|
+
}, z.core.$strict>>;
|
|
2248
|
+
emittedAt: z.ZodString;
|
|
2249
|
+
sourceRunId: z.ZodString;
|
|
2250
|
+
scope: z.ZodType<ScopeKey, unknown, z.core.$ZodTypeInternals<ScopeKey, unknown>>;
|
|
2251
|
+
buildOrdinal: z.ZodNumber;
|
|
2252
|
+
executionContext: z.ZodType<ExecutionContext, unknown, z.core.$ZodTypeInternals<ExecutionContext, unknown>>;
|
|
2253
|
+
kind: z.ZodType<BundleKind, unknown, z.core.$ZodTypeInternals<BundleKind, unknown>>;
|
|
2254
|
+
subtype: z.ZodOptional<z.ZodType<FactSubtype, unknown, z.core.$ZodTypeInternals<FactSubtype, unknown>>>;
|
|
2255
|
+
rootCauseClass: z.ZodOptional<z.ZodEnum<{
|
|
2256
|
+
environment: "environment";
|
|
2257
|
+
timeout: "timeout";
|
|
2258
|
+
flake: "flake";
|
|
2259
|
+
}>>;
|
|
2260
|
+
anchors: z.ZodArray<z.ZodType<_vostride_agent_qa_schema.Anchor, unknown, z.core.$ZodTypeInternals<_vostride_agent_qa_schema.Anchor, unknown>>>;
|
|
2261
|
+
summarySeed: z.ZodString;
|
|
2262
|
+
bodySeed: z.ZodString;
|
|
2263
|
+
distilledObservations: z.ZodArray<z.ZodObject<{
|
|
2264
|
+
schemaVersion: z.ZodNumber;
|
|
2265
|
+
step: z.ZodObject<{
|
|
2266
|
+
naturalKey: z.ZodString;
|
|
2267
|
+
ordinal: z.ZodNumber;
|
|
2268
|
+
}, z.core.$strict>;
|
|
2269
|
+
platform: z.ZodOptional<z.ZodEnum<{
|
|
2270
|
+
web: "web";
|
|
2271
|
+
mobile: "mobile";
|
|
2272
|
+
}>>;
|
|
2273
|
+
test: z.ZodOptional<z.ZodObject<{
|
|
2274
|
+
id: z.ZodString;
|
|
2275
|
+
}, z.core.$strict>>;
|
|
2276
|
+
procedure: z.ZodOptional<z.ZodObject<{
|
|
2277
|
+
id: z.ZodString;
|
|
2278
|
+
}, z.core.$strict>>;
|
|
2279
|
+
flow: z.ZodOptional<z.ZodObject<{
|
|
2280
|
+
name: z.ZodString;
|
|
2281
|
+
precedes: z.ZodOptional<z.ZodString>;
|
|
2282
|
+
}, z.core.$strict>>;
|
|
2283
|
+
surface: z.ZodOptional<z.ZodObject<{
|
|
2284
|
+
kind: z.ZodEnum<{
|
|
2285
|
+
page: "page";
|
|
2286
|
+
screen: "screen";
|
|
2287
|
+
}>;
|
|
2288
|
+
naturalKey: z.ZodString;
|
|
2289
|
+
}, z.core.$strict>>;
|
|
2290
|
+
element: z.ZodOptional<z.ZodObject<{
|
|
2291
|
+
naturalKey: z.ZodString;
|
|
2292
|
+
}, z.core.$strict>>;
|
|
2293
|
+
locator: z.ZodOptional<z.ZodObject<{
|
|
2294
|
+
selector: z.ZodString;
|
|
2295
|
+
}, z.core.$strict>>;
|
|
2296
|
+
error: z.ZodOptional<z.ZodObject<{
|
|
2297
|
+
naturalKey: z.ZodString;
|
|
2298
|
+
rootCauseClass: z.ZodOptional<z.ZodEnum<{
|
|
2299
|
+
environment: "environment";
|
|
2300
|
+
timeout: "timeout";
|
|
2301
|
+
flake: "flake";
|
|
2302
|
+
}>>;
|
|
2303
|
+
}, z.core.$strict>>;
|
|
2304
|
+
observedAtOrdinal: z.ZodNumber;
|
|
2305
|
+
}, z.core.$strict>>;
|
|
2306
|
+
evidenceToken: z.ZodString;
|
|
2307
|
+
attributingObservationId: z.ZodString;
|
|
2308
|
+
schemaVersion: z.ZodLiteral<2>;
|
|
2309
|
+
}, z.core.$strict>;
|
|
2310
|
+
declare const curationCandidatePayloadSchema: z.ZodObject<{
|
|
2311
|
+
artifactInventory: z.ZodArray<z.ZodObject<{
|
|
2312
|
+
role: z.ZodEnum<{
|
|
2313
|
+
"dom-snapshot": "dom-snapshot";
|
|
2314
|
+
"ax-snapshot": "ax-snapshot";
|
|
2315
|
+
screenshot: "screenshot";
|
|
2316
|
+
"opaque-evidence": "opaque-evidence";
|
|
2317
|
+
}>;
|
|
2318
|
+
originalName: z.ZodString;
|
|
2319
|
+
relativePath: z.ZodString;
|
|
2320
|
+
sha256: z.ZodString;
|
|
2321
|
+
bytes: z.ZodNumber;
|
|
2322
|
+
stepIndex: z.ZodNumber;
|
|
2323
|
+
}, z.core.$strict>>;
|
|
2324
|
+
emittedAt: z.ZodString;
|
|
2325
|
+
sourceRunId: z.ZodString;
|
|
2326
|
+
scope: z.ZodType<ScopeKey, unknown, z.core.$ZodTypeInternals<ScopeKey, unknown>>;
|
|
2327
|
+
buildOrdinal: z.ZodNumber;
|
|
2328
|
+
executionContext: z.ZodType<ExecutionContext, unknown, z.core.$ZodTypeInternals<ExecutionContext, unknown>>;
|
|
2329
|
+
kind: z.ZodType<BundleKind, unknown, z.core.$ZodTypeInternals<BundleKind, unknown>>;
|
|
2330
|
+
subtype: z.ZodOptional<z.ZodType<FactSubtype, unknown, z.core.$ZodTypeInternals<FactSubtype, unknown>>>;
|
|
2331
|
+
rootCauseClass: z.ZodOptional<z.ZodEnum<{
|
|
2332
|
+
environment: "environment";
|
|
2333
|
+
timeout: "timeout";
|
|
2334
|
+
flake: "flake";
|
|
2335
|
+
}>>;
|
|
2336
|
+
anchors: z.ZodArray<z.ZodType<_vostride_agent_qa_schema.Anchor, unknown, z.core.$ZodTypeInternals<_vostride_agent_qa_schema.Anchor, unknown>>>;
|
|
2337
|
+
summarySeed: z.ZodString;
|
|
2338
|
+
bodySeed: z.ZodString;
|
|
2339
|
+
distilledObservations: z.ZodArray<z.ZodObject<{
|
|
2340
|
+
schemaVersion: z.ZodNumber;
|
|
2341
|
+
step: z.ZodObject<{
|
|
2342
|
+
naturalKey: z.ZodString;
|
|
2343
|
+
ordinal: z.ZodNumber;
|
|
2344
|
+
}, z.core.$strict>;
|
|
2345
|
+
platform: z.ZodOptional<z.ZodEnum<{
|
|
2346
|
+
web: "web";
|
|
2347
|
+
mobile: "mobile";
|
|
2348
|
+
}>>;
|
|
2349
|
+
test: z.ZodOptional<z.ZodObject<{
|
|
2350
|
+
id: z.ZodString;
|
|
2351
|
+
}, z.core.$strict>>;
|
|
2352
|
+
procedure: z.ZodOptional<z.ZodObject<{
|
|
2353
|
+
id: z.ZodString;
|
|
2354
|
+
}, z.core.$strict>>;
|
|
2355
|
+
flow: z.ZodOptional<z.ZodObject<{
|
|
2356
|
+
name: z.ZodString;
|
|
2357
|
+
precedes: z.ZodOptional<z.ZodString>;
|
|
2358
|
+
}, z.core.$strict>>;
|
|
2359
|
+
surface: z.ZodOptional<z.ZodObject<{
|
|
2360
|
+
kind: z.ZodEnum<{
|
|
2361
|
+
page: "page";
|
|
2362
|
+
screen: "screen";
|
|
2363
|
+
}>;
|
|
2364
|
+
naturalKey: z.ZodString;
|
|
2365
|
+
}, z.core.$strict>>;
|
|
2366
|
+
element: z.ZodOptional<z.ZodObject<{
|
|
2367
|
+
naturalKey: z.ZodString;
|
|
2368
|
+
}, z.core.$strict>>;
|
|
2369
|
+
locator: z.ZodOptional<z.ZodObject<{
|
|
2370
|
+
selector: z.ZodString;
|
|
2371
|
+
}, z.core.$strict>>;
|
|
2372
|
+
error: z.ZodOptional<z.ZodObject<{
|
|
2373
|
+
naturalKey: z.ZodString;
|
|
2374
|
+
rootCauseClass: z.ZodOptional<z.ZodEnum<{
|
|
2375
|
+
environment: "environment";
|
|
2376
|
+
timeout: "timeout";
|
|
2377
|
+
flake: "flake";
|
|
2378
|
+
}>>;
|
|
2379
|
+
}, z.core.$strict>>;
|
|
2380
|
+
observedAtOrdinal: z.ZodNumber;
|
|
2381
|
+
}, z.core.$strict>>;
|
|
2382
|
+
evidenceToken: z.ZodString;
|
|
2383
|
+
attributingObservationId: z.ZodString;
|
|
2384
|
+
schemaVersion: z.ZodLiteral<2>;
|
|
2385
|
+
candidateId: z.ZodString;
|
|
2386
|
+
}, z.core.$strict>;
|
|
2387
|
+
type CurationCandidateAddressFields = z.infer<typeof curationCandidateAddressFieldsSchema>;
|
|
2388
|
+
type CurationCandidatePayload = z.infer<typeof curationCandidatePayloadSchema>;
|
|
2389
|
+
type CurationCandidateArtifact = z.infer<typeof artifactInventoryEntrySchema>;
|
|
2390
|
+
type CurationArtifactRole = z.infer<typeof curationArtifactRoleSchema>;
|
|
2391
|
+
type CurationArtifactDescriptor = z.infer<typeof curationArtifactDescriptorSchema>;
|
|
2392
|
+
type CurationCandidateProjection = z.infer<typeof curationCandidateProjectionSchema>;
|
|
2393
|
+
type BuildCurationCandidateAddressFieldsInput = CurationCandidateAddressFields;
|
|
2394
|
+
/** Constructs strict version-2 fields with descriptor metadata for every copied artifact. */
|
|
2395
|
+
declare function buildCurationCandidateAddressFields(input: BuildCurationCandidateAddressFieldsInput): CurationCandidateAddressFields;
|
|
2396
|
+
/**
|
|
2397
|
+
* Hashes every payload field except derived candidateId and diagnostic emittedAt. Identity covers
|
|
2398
|
+
* schema/run/scope/ordinal/execution context, candidate kind/subtype, anchors and seeds, distilled
|
|
2399
|
+
* observations, evidence attribution, and the complete artifact inventory.
|
|
2400
|
+
*/
|
|
2401
|
+
declare function candidateContentAddress(fields: CurationCandidateAddressFields): string;
|
|
2402
|
+
|
|
2403
|
+
/** Gitignored durable curation transport root; provisional until M2 field evidence retunes it. */
|
|
2404
|
+
declare const QUEUE_DIR = "memory/queue";
|
|
2405
|
+
/** Pending candidates visible to a drainer. */
|
|
2406
|
+
declare const QUEUED_SUBDIR = "queued";
|
|
2407
|
+
/** Lease-partitioned candidates atomically removed from the pending set. */
|
|
2408
|
+
declare const CLAIMED_SUBDIR = "claimed";
|
|
2409
|
+
/** Durable lifecycle checkpoints keyed by candidate content address. */
|
|
2410
|
+
declare const JOBS_SUBDIR = "jobs";
|
|
2411
|
+
/** Provisional fail-closed disk-growth limit for one knowledge scope. */
|
|
2412
|
+
declare const QUEUE_MAX_JOBS_PER_SCOPE = 200;
|
|
2413
|
+
/** Provisional fail-closed candidate emission limit for one source run. */
|
|
2414
|
+
declare const QUEUE_MAX_EMITS_PER_RUN = 50;
|
|
2415
|
+
declare function queueRoot(knowledgeRoot: string): string;
|
|
2416
|
+
declare function queuedRoot(knowledgeRoot: string): string;
|
|
2417
|
+
declare function claimedRoot(knowledgeRoot: string): string;
|
|
2418
|
+
declare function jobsRoot(knowledgeRoot: string): string;
|
|
2419
|
+
declare function queueStagingRoot(knowledgeRoot: string): string;
|
|
2420
|
+
declare function queuedCandidateDir(knowledgeRoot: string, candidateId: string): string;
|
|
2421
|
+
declare function claimedLeaseDir(knowledgeRoot: string, leaseId: string): string;
|
|
2422
|
+
declare function claimedCandidateDir(knowledgeRoot: string, leaseId: string, candidateId: string): string;
|
|
2423
|
+
declare function jobStatePath(knowledgeRoot: string, candidateId: string): string;
|
|
2424
|
+
|
|
2425
|
+
interface CurationProjectionArtifactSource {
|
|
2426
|
+
/** Binds one raw projection descriptor by its ArtifactRef id. */
|
|
2427
|
+
artifactId: string;
|
|
2428
|
+
/** Absolute source outside the queue's durable projection. */
|
|
2429
|
+
sourcePath: string;
|
|
2430
|
+
}
|
|
2431
|
+
interface EnqueueCurationCandidateProjectionOptions {
|
|
2432
|
+
knowledgeRoot: string;
|
|
2433
|
+
projection: CurationCandidateProjection;
|
|
2434
|
+
artifactSources: readonly CurationProjectionArtifactSource[];
|
|
2435
|
+
mask?: MaskFn;
|
|
2436
|
+
}
|
|
2437
|
+
type CurationEnqueueRefusalReason = 'invalid-payload' | 'artifact-inventory-mismatch' | 'artifact-missing' | 'artifact-sha-mismatch' | 'artifact-byte-length-mismatch' | 'artifact-step-cap' | 'artifact-run-cap';
|
|
2438
|
+
type EnqueueCurationCandidateProjectionOutcome = {
|
|
2439
|
+
kind: 'enqueued';
|
|
2440
|
+
candidateId: string;
|
|
2441
|
+
} | {
|
|
2442
|
+
kind: 'coalesced';
|
|
2443
|
+
candidateId: string;
|
|
2444
|
+
} | {
|
|
2445
|
+
kind: 'cap-exceeded';
|
|
2446
|
+
candidateId: string;
|
|
2447
|
+
} | {
|
|
2448
|
+
kind: 'refused';
|
|
2449
|
+
reason: CurationEnqueueRefusalReason;
|
|
2450
|
+
};
|
|
2451
|
+
type ReadCurationCandidatePayloadOutcome = {
|
|
2452
|
+
kind: 'absent';
|
|
2453
|
+
present: false;
|
|
2454
|
+
} | {
|
|
2455
|
+
kind: 'parsed';
|
|
2456
|
+
present: true;
|
|
2457
|
+
payload: CurationCandidatePayload;
|
|
2458
|
+
} | {
|
|
2459
|
+
kind: 'malformed';
|
|
2460
|
+
present: true;
|
|
2461
|
+
};
|
|
2462
|
+
interface ClaimNextJobOptions {
|
|
2463
|
+
knowledgeRoot: string;
|
|
2464
|
+
leaseId: string;
|
|
2465
|
+
authority: CurrentWriterAuthority;
|
|
2466
|
+
}
|
|
2467
|
+
interface ClaimedCurationJob {
|
|
2468
|
+
kind: 'claimed';
|
|
2469
|
+
candidateId: string;
|
|
2470
|
+
leaseId: string;
|
|
2471
|
+
payload: CurationCandidatePayload;
|
|
2472
|
+
candidateDir: string;
|
|
2473
|
+
payloadPath: string;
|
|
2474
|
+
artifactsDir: string;
|
|
2475
|
+
}
|
|
2476
|
+
interface MalformedClaimedCurationJob {
|
|
2477
|
+
kind: 'malformed';
|
|
2478
|
+
candidateId: string;
|
|
2479
|
+
leaseId: string;
|
|
2480
|
+
candidateDir: string;
|
|
2481
|
+
payloadPath: string;
|
|
2482
|
+
artifactsDir: string;
|
|
2483
|
+
payloadPresent: true;
|
|
2484
|
+
}
|
|
2485
|
+
type ClaimNextJobOutcome = ClaimedCurationJob | MalformedClaimedCurationJob;
|
|
2486
|
+
interface RequeueClaimedOptions {
|
|
2487
|
+
knowledgeRoot: string;
|
|
2488
|
+
leaseId: string;
|
|
2489
|
+
authority: CurrentWriterAuthority;
|
|
2490
|
+
}
|
|
2491
|
+
interface InspectDrainableCurationWorkOptions {
|
|
2492
|
+
readonly knowledgeRoot: string;
|
|
2493
|
+
readonly currentLeaseId: string;
|
|
2494
|
+
}
|
|
2495
|
+
interface DrainableCurationWork {
|
|
2496
|
+
readonly queuedCandidateIds: readonly string[];
|
|
2497
|
+
readonly recoverableClaimedCandidateIds: readonly string[];
|
|
2498
|
+
}
|
|
2499
|
+
interface CountRemainingCurationWorkOptions {
|
|
2500
|
+
/** Diagnostic identity only. The current claim remains included in the count. */
|
|
2501
|
+
readonly currentLeaseId?: string;
|
|
2502
|
+
}
|
|
2503
|
+
interface CurationRemainingWork {
|
|
2504
|
+
readonly queued: number;
|
|
2505
|
+
readonly claimedNonterminal: number;
|
|
2506
|
+
readonly quarantined: number;
|
|
2507
|
+
}
|
|
2508
|
+
type CurationQuarantineReason = 'malformed-payload' | 'malformed-job-state' | 'malformed-authored-checkpoint';
|
|
2509
|
+
interface QuarantineClaimedOptions {
|
|
2510
|
+
readonly knowledgeRoot: string;
|
|
2511
|
+
readonly leaseId: string;
|
|
2512
|
+
readonly candidateId: string;
|
|
2513
|
+
readonly authority: CurrentWriterAuthority;
|
|
2514
|
+
readonly reason: CurationQuarantineReason;
|
|
2515
|
+
}
|
|
2516
|
+
/** Return deterministic candidate-id order and ignore non-contract directory names. */
|
|
2517
|
+
declare function listQueuedCandidates(knowledgeRoot: string): string[];
|
|
2518
|
+
/** Visibility-only count over the same durable pending layout consumed by claimNextJob. */
|
|
2519
|
+
declare function countPendingCurationJobs(knowledgeRoot: string): number;
|
|
2520
|
+
/**
|
|
2521
|
+
* Count every durable unit that prevents the queue from being complete.
|
|
2522
|
+
*
|
|
2523
|
+
* Unlike recovery visibility this includes the current writer's claim: a process can crash
|
|
2524
|
+
* after its last pending rename, so excluding that claim would produce a false zero.
|
|
2525
|
+
*/
|
|
2526
|
+
declare function countRemainingCurationWork(knowledgeRoot: string, _options?: CountRemainingCurationWorkOptions): CurationRemainingWork;
|
|
2527
|
+
/** Return deterministic active/recoverable lease directory order. */
|
|
2528
|
+
declare function listClaimedLeases(knowledgeRoot: string): string[];
|
|
2529
|
+
/**
|
|
2530
|
+
* Observe work the current writer can reach through the canonical reconciliation path.
|
|
2531
|
+
*
|
|
2532
|
+
* This deliberately performs no recovery itself. The current lease is excluded by the same
|
|
2533
|
+
* identity rule as reconcileOnDrainStart; drainQueue remains the only owner of requeue mutation.
|
|
2534
|
+
*/
|
|
2535
|
+
declare function inspectDrainableCurationWork(options: InspectDrainableCurationWorkOptions): DrainableCurationWork;
|
|
2536
|
+
declare function readCurationCandidatePayload(candidateDir: string): ReadCurationCandidatePayloadOutcome;
|
|
2537
|
+
/** Atomically claim the lexicographically first queued content address. */
|
|
2538
|
+
declare function claimNextJob(opts: ClaimNextJobOptions): ClaimNextJobOutcome | undefined;
|
|
2539
|
+
/** Reclaim one dead lease without discarding an already-authored deterministic checkpoint. */
|
|
2540
|
+
declare function requeueClaimed(opts: RequeueClaimedOptions): string[];
|
|
2541
|
+
/**
|
|
2542
|
+
* Fenced terminal disposition for a claimed job whose durable inputs cannot be interpreted.
|
|
2543
|
+
* The claimed payload, optional lifecycle bytes, and reason document move as one directory.
|
|
2544
|
+
*/
|
|
2545
|
+
declare function quarantineClaimed(opts: QuarantineClaimedOptions): string;
|
|
2546
|
+
/**
|
|
2547
|
+
* Copies the projection's artifacts through the declared mask before the candidate content
|
|
2548
|
+
* address or any queue-visible directory exists.
|
|
2549
|
+
*/
|
|
2550
|
+
declare function enqueueCurationCandidateProjection(opts: EnqueueCurationCandidateProjectionOptions): EnqueueCurationCandidateProjectionOutcome;
|
|
2551
|
+
declare const enqueueCurationCandidate: typeof enqueueCurationCandidateProjection;
|
|
2552
|
+
|
|
2553
|
+
declare const CURATION_JOB_STATE_SCHEMA_VERSION = 2;
|
|
2554
|
+
type CurationJobLifecycle = 'queued' | 'authored' | 'bundling' | 'committing' | 'done';
|
|
2555
|
+
declare const curationJobStateSchema: z.ZodObject<{
|
|
2556
|
+
schemaVersion: z.ZodLiteral<2>;
|
|
2557
|
+
candidateId: z.ZodString;
|
|
2558
|
+
lifecycle: z.ZodType<CurationJobLifecycle, unknown, z.core.$ZodTypeInternals<CurationJobLifecycle, unknown>>;
|
|
2559
|
+
embedCrashCount: z.ZodDefault<z.ZodNumber>;
|
|
2560
|
+
authored: z.ZodOptional<z.ZodUnknown>;
|
|
2561
|
+
updatedAt: z.ZodString;
|
|
2562
|
+
}, z.core.$strict>;
|
|
2563
|
+
type CurationJobState = z.infer<typeof curationJobStateSchema>;
|
|
2564
|
+
interface WriteJobStateOptions {
|
|
2565
|
+
knowledgeRoot: string;
|
|
2566
|
+
candidateId: string;
|
|
2567
|
+
lifecycle: CurationJobLifecycle;
|
|
2568
|
+
authority: CurrentWriterAuthority;
|
|
2569
|
+
embedCrashCount?: number;
|
|
2570
|
+
authored?: unknown;
|
|
2571
|
+
}
|
|
2572
|
+
type ReadJobStateOutcome = {
|
|
2573
|
+
kind: 'absent';
|
|
2574
|
+
present: false;
|
|
2575
|
+
} | {
|
|
2576
|
+
kind: 'parsed';
|
|
2577
|
+
present: true;
|
|
2578
|
+
state: CurationJobState;
|
|
2579
|
+
} | {
|
|
2580
|
+
kind: 'malformed';
|
|
2581
|
+
present: true;
|
|
2582
|
+
};
|
|
2583
|
+
interface PersistAuthoredCheckpointOptions {
|
|
2584
|
+
knowledgeRoot: string;
|
|
2585
|
+
candidateId: string;
|
|
2586
|
+
authority: CurrentWriterAuthority;
|
|
2587
|
+
authored: unknown;
|
|
2588
|
+
}
|
|
2589
|
+
type PersistAuthoredCheckpointOutcome = {
|
|
2590
|
+
kind: 'persisted';
|
|
2591
|
+
state: CurationJobState;
|
|
2592
|
+
} | {
|
|
2593
|
+
kind: 'malformed-state';
|
|
2594
|
+
present: true;
|
|
2595
|
+
};
|
|
2596
|
+
/** Read a strict lifecycle checkpoint; corrupt bytes remain a typed present signal. */
|
|
2597
|
+
declare function readJobState(knowledgeRoot: string, candidateId: string): ReadJobStateOutcome;
|
|
2598
|
+
declare function writeJobState(opts: WriteJobStateOptions): CurationJobState;
|
|
2599
|
+
/** Persist the validated-later authored value before any deterministic bundle mutation begins. */
|
|
2600
|
+
declare function persistAuthoredCheckpoint(opts: PersistAuthoredCheckpointOptions): PersistAuthoredCheckpointOutcome;
|
|
2601
|
+
|
|
2602
|
+
declare const COMMIT_INTENT_SCHEMA_VERSION = 2;
|
|
2603
|
+
declare const commitIntentSchema: z.ZodObject<{
|
|
2604
|
+
schemaVersion: z.ZodLiteral<2>;
|
|
2605
|
+
candidateId: z.ZodString;
|
|
2606
|
+
bundleId: z.ZodString;
|
|
2607
|
+
deltaKind: z.ZodEnum<{
|
|
2608
|
+
Add: "Add";
|
|
2609
|
+
Confirm: "Confirm";
|
|
2610
|
+
Supersede: "Supersede";
|
|
2611
|
+
Deprecate: "Deprecate";
|
|
2612
|
+
MintUnknown: "MintUnknown";
|
|
2613
|
+
Noop: "Noop";
|
|
2614
|
+
}>;
|
|
2615
|
+
targetRecordId: z.ZodOptional<z.ZodString>;
|
|
2616
|
+
epoch: z.ZodNumber;
|
|
2617
|
+
observation: z.ZodOptional<z.ZodObject<{
|
|
2618
|
+
effects: z.ZodArray<z.ZodObject<{
|
|
2619
|
+
recordId: z.ZodString;
|
|
2620
|
+
product: z.ZodString;
|
|
2621
|
+
change: z.ZodEnum<{
|
|
2622
|
+
confirmed: "confirmed";
|
|
2623
|
+
superseded: "superseded";
|
|
2624
|
+
deprecated: "deprecated";
|
|
2625
|
+
added: "added";
|
|
2626
|
+
}>;
|
|
2627
|
+
atOrdinal: z.ZodNumber;
|
|
2628
|
+
evidenceToken: z.ZodString;
|
|
2629
|
+
byRecordId: z.ZodOptional<z.ZodString>;
|
|
2630
|
+
}, z.core.$strict>>;
|
|
2631
|
+
sourceRunId: z.ZodString;
|
|
2632
|
+
observationId: z.ZodString;
|
|
2633
|
+
originalDeltaKind: z.ZodEnum<{
|
|
2634
|
+
Add: "Add";
|
|
2635
|
+
Confirm: "Confirm";
|
|
2636
|
+
Supersede: "Supersede";
|
|
2637
|
+
Deprecate: "Deprecate";
|
|
2638
|
+
MintUnknown: "MintUnknown";
|
|
2639
|
+
Noop: "Noop";
|
|
2640
|
+
}>;
|
|
2641
|
+
appliedDeltaKind: z.ZodEnum<{
|
|
2642
|
+
Add: "Add";
|
|
2643
|
+
Confirm: "Confirm";
|
|
2644
|
+
Supersede: "Supersede";
|
|
2645
|
+
Deprecate: "Deprecate";
|
|
2646
|
+
MintUnknown: "MintUnknown";
|
|
2647
|
+
Noop: "Noop";
|
|
2648
|
+
}>;
|
|
2649
|
+
disposition: z.ZodEnum<{
|
|
2650
|
+
apply: "apply";
|
|
2651
|
+
downgraded: "downgraded";
|
|
2652
|
+
}>;
|
|
2653
|
+
downgradeReason: z.ZodOptional<z.ZodString>;
|
|
2654
|
+
schemaVersion: z.ZodLiteral<2>;
|
|
2655
|
+
}, z.core.$strict>>;
|
|
2656
|
+
}, z.core.$strict>;
|
|
2657
|
+
type CommitIntent = z.infer<typeof commitIntentSchema>;
|
|
2658
|
+
|
|
2659
|
+
declare const AUTHORED_CHECKPOINT_SCHEMA_VERSION = 2;
|
|
2660
|
+
/** The deterministic author-facing projection of one durable queue payload. */
|
|
2661
|
+
type CurationJobView = Pick<CurationCandidatePayload, 'candidateId' | 'kind' | 'subtype' | 'rootCauseClass' | 'anchors' | 'summarySeed' | 'bodySeed' | 'distilledObservations' | 'scope' | 'buildOrdinal' | 'attributingObservationId' | 'executionContext'>;
|
|
2662
|
+
/** One retrieval hit as shown to the author through a small integer alias. */
|
|
2663
|
+
interface NeighborRecordBase {
|
|
2664
|
+
alias: number;
|
|
2665
|
+
recordId: RecordId;
|
|
2666
|
+
summary: string;
|
|
2667
|
+
anchors: Anchor[];
|
|
2668
|
+
observedStatus: string;
|
|
2669
|
+
observedOrdinal: number;
|
|
2670
|
+
}
|
|
2671
|
+
type NonFactNeighborRecord = {
|
|
2672
|
+
[Kind in Exclude<BundleKind, 'fact'>]: {
|
|
2673
|
+
kind: Kind;
|
|
2674
|
+
subtype?: never;
|
|
2675
|
+
};
|
|
2676
|
+
}[Exclude<BundleKind, 'fact'>];
|
|
2677
|
+
type NeighborRecord = NeighborRecordBase & ({
|
|
2678
|
+
kind: 'fact';
|
|
2679
|
+
subtype: FactSubtype;
|
|
2680
|
+
} | NonFactNeighborRecord);
|
|
2681
|
+
/**
|
|
2682
|
+
* One authored outcome may carry multiple deltas (D-02): a procedure-extraction job can yield
|
|
2683
|
+
* whole-flow AND sub-flow candidates from one trajectory. Fact/caution authoring produces a
|
|
2684
|
+
* one-element array. The array is never empty.
|
|
2685
|
+
*/
|
|
2686
|
+
type AuthorOutcome = {
|
|
2687
|
+
kind: 'authored';
|
|
2688
|
+
deltas: Delta[];
|
|
2689
|
+
authorship: CurationAuthorship;
|
|
2690
|
+
} | {
|
|
2691
|
+
kind: 'fallback-required';
|
|
2692
|
+
reason: CurationFallbackReason;
|
|
2693
|
+
};
|
|
2694
|
+
/** Provider-neutral author seam injected by the CLI composition root. */
|
|
2695
|
+
type CuratorAuthor = (job: CurationJobView, neighbors: NeighborRecord[]) => Promise<AuthorOutcome>;
|
|
2696
|
+
/**
|
|
2697
|
+
* Caller-owned disposition authority. Phase 379 may extend this profile with its deterministic
|
|
2698
|
+
* born-active drift-supersede carve-out without changing the author or checkpoint contracts.
|
|
2699
|
+
*/
|
|
2700
|
+
interface DispositionProfile {
|
|
2701
|
+
mode: 'drain-to-active' | 'propose-only';
|
|
2702
|
+
}
|
|
2703
|
+
/**
|
|
2704
|
+
* Resolve automatic curation authority from the run's already-captured execution context.
|
|
2705
|
+
* Local work applies directly (432 D-08); CI and cloud stay proposed for the rolling-PR flow.
|
|
2706
|
+
*/
|
|
2707
|
+
declare function resolveDispositionProfile(executionContext: ExecutionContext): DispositionProfile;
|
|
2708
|
+
type CheckpointBundleDraft = BundleDraft & {
|
|
2709
|
+
needsEnrichment?: true;
|
|
2710
|
+
};
|
|
2711
|
+
/**
|
|
2712
|
+
* The SHARED structural boundary for a checkpoint. Neighbor membership and CAS freshness are
|
|
2713
|
+
* deliberately disposition checks, so this schema validates structure without applying them.
|
|
2714
|
+
* D-02: the checkpoint carries the authored outcome's FULL delta array — one durable authoring
|
|
2715
|
+
* checkpoint per job, disposed delta-by-delta through the commit boundary.
|
|
2716
|
+
*
|
|
2717
|
+
* Deliberately origin-WIDE, and that is not an oversight — see
|
|
2718
|
+
* `AUTHORED_CHECKPOINT_ORIGIN_ADMISSION` below. `AuthoredCheckpoint`'s inferred delta type is
|
|
2719
|
+
* the type every in-process checkpoint carries, including the user-origin deltas the review
|
|
2720
|
+
* verbs commit and the system-origin deltas rollback and the canary commit. Origin admission is
|
|
2721
|
+
* a property of the DRAIN's parse boundary, not of the checkpoint shape.
|
|
2722
|
+
*/
|
|
2723
|
+
declare const authoredCheckpointSchema: z.ZodObject<{
|
|
2724
|
+
schemaVersion: z.ZodLiteral<2>;
|
|
2725
|
+
deltas: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
2726
|
+
bundle: z.ZodType<CheckpointBundleDraft, unknown, z.core.$ZodTypeInternals<CheckpointBundleDraft, unknown>>;
|
|
2727
|
+
origin: z.ZodEnum<{
|
|
2728
|
+
user: "user";
|
|
2729
|
+
import: "import";
|
|
2730
|
+
agent: "agent";
|
|
2731
|
+
system: "system";
|
|
2732
|
+
}>;
|
|
2733
|
+
scope: z.ZodType<ScopeKey, unknown, z.core.$ZodTypeInternals<ScopeKey, unknown>>;
|
|
2734
|
+
citedIds: z.ZodArray<z.ZodPipe<z.ZodString, z.ZodTransform<RecordId, string>>>;
|
|
2735
|
+
precondition: z.ZodOptional<z.ZodArray<z.ZodType<CompareAndSet, unknown, z.core.$ZodTypeInternals<CompareAndSet, unknown>>>>;
|
|
2736
|
+
authorship: z.ZodOptional<z.ZodType<CurationAuthorship, unknown, z.core.$ZodTypeInternals<CurationAuthorship, unknown>>>;
|
|
2737
|
+
kind: z.ZodLiteral<"Add">;
|
|
2738
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
2739
|
+
targetId: z.ZodPipe<z.ZodString, z.ZodTransform<RecordId, string>>;
|
|
2740
|
+
evidenceToken: z.ZodPipe<z.ZodString, z.ZodTransform<_vostride_agent_qa_schema.EvidenceToken, string>>;
|
|
2741
|
+
origin: z.ZodEnum<{
|
|
2742
|
+
user: "user";
|
|
2743
|
+
import: "import";
|
|
2744
|
+
agent: "agent";
|
|
2745
|
+
system: "system";
|
|
2746
|
+
}>;
|
|
2747
|
+
scope: z.ZodType<ScopeKey, unknown, z.core.$ZodTypeInternals<ScopeKey, unknown>>;
|
|
2748
|
+
citedIds: z.ZodArray<z.ZodPipe<z.ZodString, z.ZodTransform<RecordId, string>>>;
|
|
2749
|
+
precondition: z.ZodOptional<z.ZodArray<z.ZodType<CompareAndSet, unknown, z.core.$ZodTypeInternals<CompareAndSet, unknown>>>>;
|
|
2750
|
+
authorship: z.ZodOptional<z.ZodType<CurationAuthorship, unknown, z.core.$ZodTypeInternals<CurationAuthorship, unknown>>>;
|
|
2751
|
+
kind: z.ZodLiteral<"Confirm">;
|
|
2752
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
2753
|
+
victimId: z.ZodPipe<z.ZodString, z.ZodTransform<RecordId, string>>;
|
|
2754
|
+
newBundle: z.ZodType<CheckpointBundleDraft, unknown, z.core.$ZodTypeInternals<CheckpointBundleDraft, unknown>>;
|
|
2755
|
+
evidenceToken: z.ZodPipe<z.ZodString, z.ZodTransform<_vostride_agent_qa_schema.EvidenceToken, string>>;
|
|
2756
|
+
origin: z.ZodEnum<{
|
|
2757
|
+
user: "user";
|
|
2758
|
+
import: "import";
|
|
2759
|
+
agent: "agent";
|
|
2760
|
+
system: "system";
|
|
2761
|
+
}>;
|
|
2762
|
+
scope: z.ZodType<ScopeKey, unknown, z.core.$ZodTypeInternals<ScopeKey, unknown>>;
|
|
2763
|
+
citedIds: z.ZodArray<z.ZodPipe<z.ZodString, z.ZodTransform<RecordId, string>>>;
|
|
2764
|
+
precondition: z.ZodOptional<z.ZodArray<z.ZodType<CompareAndSet, unknown, z.core.$ZodTypeInternals<CompareAndSet, unknown>>>>;
|
|
2765
|
+
authorship: z.ZodOptional<z.ZodType<CurationAuthorship, unknown, z.core.$ZodTypeInternals<CurationAuthorship, unknown>>>;
|
|
2766
|
+
kind: z.ZodLiteral<"Supersede">;
|
|
2767
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
2768
|
+
targetId: z.ZodPipe<z.ZodString, z.ZodTransform<RecordId, string>>;
|
|
2769
|
+
reason: z.ZodString;
|
|
2770
|
+
origin: z.ZodEnum<{
|
|
2771
|
+
user: "user";
|
|
2772
|
+
import: "import";
|
|
2773
|
+
agent: "agent";
|
|
2774
|
+
system: "system";
|
|
2775
|
+
}>;
|
|
2776
|
+
scope: z.ZodType<ScopeKey, unknown, z.core.$ZodTypeInternals<ScopeKey, unknown>>;
|
|
2777
|
+
citedIds: z.ZodArray<z.ZodPipe<z.ZodString, z.ZodTransform<RecordId, string>>>;
|
|
2778
|
+
precondition: z.ZodOptional<z.ZodArray<z.ZodType<CompareAndSet, unknown, z.core.$ZodTypeInternals<CompareAndSet, unknown>>>>;
|
|
2779
|
+
authorship: z.ZodOptional<z.ZodType<CurationAuthorship, unknown, z.core.$ZodTypeInternals<CurationAuthorship, unknown>>>;
|
|
2780
|
+
kind: z.ZodLiteral<"Deprecate">;
|
|
2781
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
2782
|
+
conflict: z.ZodObject<{
|
|
2783
|
+
recordIds: z.ZodArray<z.ZodPipe<z.ZodString, z.ZodTransform<RecordId, string>>>;
|
|
2784
|
+
kind: z.ZodEnum<{
|
|
2785
|
+
contradiction: "contradiction";
|
|
2786
|
+
drift: "drift";
|
|
2787
|
+
clarification: "clarification";
|
|
2788
|
+
}>;
|
|
2789
|
+
}, z.core.$strict>;
|
|
2790
|
+
origin: z.ZodEnum<{
|
|
2791
|
+
user: "user";
|
|
2792
|
+
import: "import";
|
|
2793
|
+
agent: "agent";
|
|
2794
|
+
system: "system";
|
|
2795
|
+
}>;
|
|
2796
|
+
scope: z.ZodType<ScopeKey, unknown, z.core.$ZodTypeInternals<ScopeKey, unknown>>;
|
|
2797
|
+
citedIds: z.ZodArray<z.ZodPipe<z.ZodString, z.ZodTransform<RecordId, string>>>;
|
|
2798
|
+
precondition: z.ZodOptional<z.ZodArray<z.ZodType<CompareAndSet, unknown, z.core.$ZodTypeInternals<CompareAndSet, unknown>>>>;
|
|
2799
|
+
authorship: z.ZodOptional<z.ZodType<CurationAuthorship, unknown, z.core.$ZodTypeInternals<CurationAuthorship, unknown>>>;
|
|
2800
|
+
kind: z.ZodLiteral<"MintUnknown">;
|
|
2801
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
2802
|
+
origin: z.ZodEnum<{
|
|
2803
|
+
user: "user";
|
|
2804
|
+
import: "import";
|
|
2805
|
+
agent: "agent";
|
|
2806
|
+
system: "system";
|
|
2807
|
+
}>;
|
|
2808
|
+
scope: z.ZodType<ScopeKey, unknown, z.core.$ZodTypeInternals<ScopeKey, unknown>>;
|
|
2809
|
+
citedIds: z.ZodArray<z.ZodPipe<z.ZodString, z.ZodTransform<RecordId, string>>>;
|
|
2810
|
+
precondition: z.ZodOptional<z.ZodArray<z.ZodType<CompareAndSet, unknown, z.core.$ZodTypeInternals<CompareAndSet, unknown>>>>;
|
|
2811
|
+
authorship: z.ZodOptional<z.ZodType<CurationAuthorship, unknown, z.core.$ZodTypeInternals<CurationAuthorship, unknown>>>;
|
|
2812
|
+
kind: z.ZodLiteral<"Noop">;
|
|
2813
|
+
}, z.core.$strict>], "kind">>;
|
|
2814
|
+
neighborIds: z.ZodArray<z.ZodPipe<z.ZodString, z.ZodTransform<RecordId, string>>>;
|
|
2815
|
+
preconditions: z.ZodArray<z.ZodType<CompareAndSet, unknown, z.core.$ZodTypeInternals<CompareAndSet, unknown>>>;
|
|
2816
|
+
authorship: z.ZodType<CurationAuthorship, unknown, z.core.$ZodTypeInternals<CurationAuthorship, unknown>>;
|
|
2817
|
+
}, z.core.$strict>;
|
|
2818
|
+
type AuthoredCheckpoint = z.infer<typeof authoredCheckpointSchema>;
|
|
2819
|
+
/**
|
|
2820
|
+
* Parse authored bytes at the drain's boundary — both when wrapping fresh author output
|
|
2821
|
+
* (drain.ts:537) and when replaying crash-recovered state (drain.ts:992).
|
|
2822
|
+
*
|
|
2823
|
+
* BOTH sites, deliberately. Guarding only the recovery read would leave the injected author seam
|
|
2824
|
+
* able to put a non-agent origin into the durable slot in the first place, which is the same
|
|
2825
|
+
* defect one step upstream: a delta the store attributes to a person, authored by a model, that
|
|
2826
|
+
* the autonomy floor would then let tombstone standing knowledge.
|
|
2827
|
+
*/
|
|
2828
|
+
declare function parseAuthoredCheckpoint(value: unknown): AuthoredCheckpoint;
|
|
2829
|
+
/**
|
|
2830
|
+
* The per-delta commit unit sliced from a widened checkpoint. `commitCurationDelta` remains
|
|
2831
|
+
* the ONE serialized mutation boundary and disposes exactly one delta per call; the drain
|
|
2832
|
+
* slices the checkpoint and disposes each delta independently (D-02).
|
|
2833
|
+
*/
|
|
2834
|
+
interface AuthoredDeltaCheckpoint {
|
|
2835
|
+
schemaVersion: typeof AUTHORED_CHECKPOINT_SCHEMA_VERSION;
|
|
2836
|
+
delta: AuthoredCheckpoint['deltas'][number];
|
|
2837
|
+
neighborIds: AuthoredCheckpoint['neighborIds'];
|
|
2838
|
+
preconditions: AuthoredCheckpoint['preconditions'];
|
|
2839
|
+
authorship: AuthoredCheckpoint['authorship'];
|
|
2840
|
+
}
|
|
2841
|
+
/** Slice one widened checkpoint into its ordered per-delta commit units. */
|
|
2842
|
+
declare function sliceAuthoredCheckpoint(checkpoint: AuthoredCheckpoint): AuthoredDeltaCheckpoint[];
|
|
2843
|
+
/** Re-widen one commit unit into a parseable singleton checkpoint (job-state persistence). */
|
|
2844
|
+
declare function widenAuthoredDeltaCheckpoint(slice: AuthoredDeltaCheckpoint): AuthoredCheckpoint;
|
|
2845
|
+
|
|
2846
|
+
interface CanonicalBundleSnapshot {
|
|
2847
|
+
recordId: RecordId;
|
|
2848
|
+
kind: 'fact' | 'procedure' | 'caution' | 'unknown' | 'policy';
|
|
2849
|
+
anchors: readonly Anchor[];
|
|
2850
|
+
scope: ScopeKey;
|
|
2851
|
+
createdAtOrdinal: number;
|
|
2852
|
+
events: readonly BundleOutcomeEvent[];
|
|
2853
|
+
status: BundleStatus;
|
|
2854
|
+
curationJobId?: string;
|
|
2855
|
+
}
|
|
2856
|
+
|
|
2857
|
+
/** Provisional §7.3.1 cap. Phase 379 may retune it only through an explicit constant edit. */
|
|
2858
|
+
declare const BLAST_RADIUS_MAX_SUPERSEDES_PER_ANCHOR_PER_DRAIN = 1;
|
|
2859
|
+
|
|
2860
|
+
/**
|
|
2861
|
+
* 381-03 (PROC-01 D-02/D-03): the verified queue evidence the procedure-extraction wall
|
|
2862
|
+
* validates against. It is code-derived queue truth — distilled observations — never LLM text.
|
|
2863
|
+
*/
|
|
2864
|
+
interface ProcedureDispositionEvidence {
|
|
2865
|
+
distilledObservations: readonly DistilledObservation[];
|
|
2866
|
+
}
|
|
2867
|
+
interface DispositionCandidateContext {
|
|
2868
|
+
anchors: readonly Anchor[];
|
|
2869
|
+
scope: ScopeKey;
|
|
2870
|
+
buildOrdinal: number;
|
|
2871
|
+
/** Durable queue address used as the observation's idempotency identity. */
|
|
2872
|
+
curationJobId?: string;
|
|
2873
|
+
/** Original measurement seed value; prose authored by a model is never parsed for authority. */
|
|
2874
|
+
measurementValue?: string;
|
|
2875
|
+
/** Present only for procedure-extraction jobs; procedure deltas fail closed without it. */
|
|
2876
|
+
procedureEvidence?: ProcedureDispositionEvidence;
|
|
2877
|
+
}
|
|
2878
|
+
interface RelationIntent {
|
|
2879
|
+
type: 'proposed-supersession-of' | 'renamed-from';
|
|
2880
|
+
targetId: RecordId;
|
|
2881
|
+
}
|
|
2882
|
+
interface DispositionDrainState {
|
|
2883
|
+
supersedesSeenByAnchorKey: Map<string, number>;
|
|
2884
|
+
/** 379 Open Question 3: one canonical O(store) scan, lazily cached per drain. */
|
|
2885
|
+
canonicalBundles?: CanonicalBundleSnapshot[];
|
|
2886
|
+
/** Test-only observability seam for proving the canonical scan runs once. */
|
|
2887
|
+
onCanonicalBundleScan?: () => void;
|
|
2888
|
+
/** Prevent two jobs in one drain from arming the same not-yet-published unknown. */
|
|
2889
|
+
unknownMarkersSeen?: Set<string>;
|
|
2890
|
+
/** New anchor groups observed by earlier jobs after the once-per-drain snapshot. */
|
|
2891
|
+
firstSeenAnchorsByScope?: Map<string, Map<string, {
|
|
2892
|
+
buildOrdinal: number;
|
|
2893
|
+
recordId?: RecordId;
|
|
2894
|
+
}>>;
|
|
2895
|
+
}
|
|
2896
|
+
interface FirstSeenRegistration {
|
|
2897
|
+
scopeKey: string;
|
|
2898
|
+
supersessionKey: string;
|
|
2899
|
+
buildOrdinal: number;
|
|
2900
|
+
}
|
|
2901
|
+
interface UnknownMintIntent {
|
|
2902
|
+
kind: 'thrash' | 'scope-burst';
|
|
2903
|
+
marker: string;
|
|
2904
|
+
triggerKey: string;
|
|
2905
|
+
scope: ScopeKey;
|
|
2906
|
+
windowOpenOrdinal: number;
|
|
2907
|
+
windowCloseOrdinal: number;
|
|
2908
|
+
evidenceRecordIds: RecordId[];
|
|
2909
|
+
includeCommittedBundle: boolean;
|
|
2910
|
+
firstSeenCount?: number;
|
|
2911
|
+
}
|
|
2912
|
+
interface UnknownResolutionIntent {
|
|
2913
|
+
targetId: RecordId;
|
|
2914
|
+
reason: 'thrash-stable-window';
|
|
2915
|
+
}
|
|
2916
|
+
interface DisposeDeltaInput {
|
|
2917
|
+
delta: Delta;
|
|
2918
|
+
checkpoint: AuthoredDeltaCheckpoint;
|
|
2919
|
+
profile: DispositionProfile;
|
|
2920
|
+
knowledgeRoot: string;
|
|
2921
|
+
priors?: TrustPriorTable;
|
|
2922
|
+
/**
|
|
2923
|
+
* Verified queue evidence needed for anchor and new-ordinal checks. Optional only for the
|
|
2924
|
+
* non-mutating delta shapes; Add and Supersede fail closed when it is absent.
|
|
2925
|
+
*/
|
|
2926
|
+
candidate?: DispositionCandidateContext;
|
|
2927
|
+
drainState: DispositionDrainState;
|
|
2928
|
+
}
|
|
2929
|
+
type DispositionOutcome = {
|
|
2930
|
+
kind: 'apply';
|
|
2931
|
+
delta: Delta;
|
|
2932
|
+
relationIntents?: RelationIntent[];
|
|
2933
|
+
bornActive?: true;
|
|
2934
|
+
measurementAppend?: {
|
|
2935
|
+
victimId: RecordId;
|
|
2936
|
+
observation: MeasurementObservation;
|
|
2937
|
+
};
|
|
2938
|
+
unknownMintIntents?: UnknownMintIntent[];
|
|
2939
|
+
unknownResolutionIntents?: UnknownResolutionIntent[];
|
|
2940
|
+
firstSeenRegistration?: FirstSeenRegistration;
|
|
2941
|
+
} | {
|
|
2942
|
+
kind: 'downgraded';
|
|
2943
|
+
delta: Delta;
|
|
2944
|
+
reason: string;
|
|
2945
|
+
original: Delta;
|
|
2946
|
+
relationIntents?: RelationIntent[];
|
|
2947
|
+
measurementAppend?: {
|
|
2948
|
+
victimId: RecordId;
|
|
2949
|
+
observation: MeasurementObservation;
|
|
2950
|
+
};
|
|
2951
|
+
unknownMintIntents?: UnknownMintIntent[];
|
|
2952
|
+
unknownResolutionIntents?: UnknownResolutionIntent[];
|
|
2953
|
+
firstSeenRegistration?: FirstSeenRegistration;
|
|
2954
|
+
} | {
|
|
2955
|
+
kind: 'requeue-resynthesis';
|
|
2956
|
+
reason: string;
|
|
2957
|
+
} | {
|
|
2958
|
+
kind: 'noop';
|
|
2959
|
+
reason: string;
|
|
2960
|
+
};
|
|
2961
|
+
/**
|
|
2962
|
+
* Every way `checkCitedIdIntegrity` can decide this store cannot stand behind a cited id.
|
|
2963
|
+
*
|
|
2964
|
+
* The registry exists so the count stops being something a comment or a corpus has to keep in
|
|
2965
|
+
* step. Round 2 measured what happens when it is not one: the check's second return is a
|
|
2966
|
+
* three-way disjunction, the corpus and the doc comment both said "three conditions", and
|
|
2967
|
+
* carving `scope-mismatch` out of the refusal for every origin left 3 files / 70 tests green.
|
|
2968
|
+
* A fifth member added here is a compile error at `citedIdIntegrityFailure`'s derivation and at
|
|
2969
|
+
* the corpus's `satisfies Record<CitedIdIntegrityCondition, …>` fixture table.
|
|
2970
|
+
*/
|
|
2971
|
+
declare const CITED_ID_INTEGRITY_CONDITIONS: readonly ["not-a-persisted-neighbor", "missing-from-disk", "deprecated", "scope-mismatch"];
|
|
2972
|
+
type CitedIdIntegrityCondition = (typeof CITED_ID_INTEGRITY_CONDITIONS)[number];
|
|
2973
|
+
/**
|
|
2974
|
+
* The typed refusal a USER-authored delta receives when its cited-id integrity check fails.
|
|
2975
|
+
*
|
|
2976
|
+
* Thrown rather than returned, and out of the check funnel rather than out of the commit, so it
|
|
2977
|
+
* fires before any canonical byte moves for this delta: `disposeDelta` runs `checkCitedIdIntegrity`
|
|
2978
|
+
* first of the six §7.3.1 checks, ahead of every append, projection and promotion.
|
|
2979
|
+
* `applyReview`'s `commitAndPublish` catches it, restores the proposal to pending and rethrows,
|
|
2980
|
+
* which is how the caller gets a typed answer instead of a receipt for work nobody did.
|
|
2981
|
+
*
|
|
2982
|
+
* WHAT MAKES "NOTHING MOVED" TRUE, and it is not this sentence. The previous version of this
|
|
2983
|
+
* comment asserted whole-store neutrality as free-standing prose, naming no mechanism, and the
|
|
2984
|
+
* round-2 verifier measured that claim FALSE: the delta had already reached disposition through
|
|
2985
|
+
* `knowledge-store.ts`'s bridge, which materialized a claimed curation candidate on disk before
|
|
2986
|
+
* `commitWithProfile` ever called into the commit, and the throw left it there for the next
|
|
2987
|
+
* drain's reconcile to requeue (CR-02″). Two mechanisms now establish the claim, and each of them
|
|
2988
|
+
* reds if it is removed:
|
|
2989
|
+
*
|
|
2990
|
+
* 1. `bridgeDelta` is WRITE-FREE (`curator/knowledge-store.ts`). It computes the candidate's
|
|
2991
|
+
* address and materializes nothing, so a check that throws at any position has nothing to
|
|
2992
|
+
* leave behind. Reintroducing its two write statements reds the case in (2).
|
|
2993
|
+
* 2. `review/__tests__/apply-review.test.ts` asserts `hashTree(knowledgeRoot)` and the tree's
|
|
2994
|
+
* full entry listing — QUEUE TREE INCLUDED — are identical across a refused `accept`, with
|
|
2995
|
+
* a potency control proving the digest is falsifiable over that exact root.
|
|
2996
|
+
*
|
|
2997
|
+
* The scope of the guarantee is the knowledge root. The writer lease's own fencing state
|
|
2998
|
+
* (`.epoch`, `.writer-authority.sqlite`) advances on acquisition regardless of what the caller
|
|
2999
|
+
* then does, which is why the case above holds the lease across its measurement rather than
|
|
3000
|
+
* excusing those two names.
|
|
3001
|
+
*/
|
|
3002
|
+
declare class UserDeltaCitationIntegrityError extends Error {
|
|
3003
|
+
readonly recordId: RecordId;
|
|
3004
|
+
readonly deltaKind: Delta['kind'];
|
|
3005
|
+
readonly condition: CitedIdIntegrityCondition;
|
|
3006
|
+
constructor(recordId: RecordId, deltaKind: Delta['kind'], condition: CitedIdIntegrityCondition);
|
|
3007
|
+
}
|
|
3008
|
+
/**
|
|
3009
|
+
* Run memory.md §7.3.1's six checks in order. The function is deliberately synchronous: every
|
|
3010
|
+
* decision is made from the persisted checkpoint and canonical bundle tree, never an index row.
|
|
3011
|
+
*/
|
|
3012
|
+
declare function disposeDelta(input: DisposeDeltaInput): DispositionOutcome;
|
|
3013
|
+
|
|
3014
|
+
interface CommitCurationJob extends ClaimedCurationJob {
|
|
3015
|
+
screenStates?: readonly ScreenState[];
|
|
3016
|
+
/** Product authority resolved with the checkpoint; absent ids must be globally unique. */
|
|
3017
|
+
targetProducts?: Readonly<Record<string, string>>;
|
|
3018
|
+
}
|
|
3019
|
+
interface CommitCurationDependencies {
|
|
3020
|
+
knowledgeRoot: string;
|
|
3021
|
+
epoch: number;
|
|
3022
|
+
profile: DispositionProfile;
|
|
3023
|
+
drainState: DispositionDrainState;
|
|
3024
|
+
/** Host-resolved posture as data; absent means the v51 floor. */
|
|
3025
|
+
resolvePromotionPosture?: ResolvePromotionPosture;
|
|
3026
|
+
priors?: TrustPriorTable;
|
|
3027
|
+
/**
|
|
3028
|
+
* Multi-delta disposal (D-02): when set, terminal paths skip queue completion so the
|
|
3029
|
+
* claimed candidate directory stays available for the checkpoint's remaining deltas.
|
|
3030
|
+
* The drain leaves it unset on the final delta, which completes the job as before.
|
|
3031
|
+
*/
|
|
3032
|
+
deferCompletion?: true;
|
|
3033
|
+
hooks?: {
|
|
3034
|
+
/**
|
|
3035
|
+
* Test/chaos seam after every pre-staging write and immediately before the commit tail
|
|
3036
|
+
* enters its current-writer-authority section. Nothing durable and reader-relevant to this
|
|
3037
|
+
* candidate has been published yet when it fires.
|
|
3038
|
+
*/
|
|
3039
|
+
beforeCommitAuthorityEntry?: () => void;
|
|
3040
|
+
/** Test/chaos seam immediately after the durable intent rename. */
|
|
3041
|
+
afterIntentWritten?: () => void;
|
|
3042
|
+
/** Test/chaos seam while the complete bundle is staged but still reader-invisible. */
|
|
3043
|
+
beforePublishRename?: () => void;
|
|
3044
|
+
/** Test/chaos seam after lock-held authority comparison and before finalize. */
|
|
3045
|
+
afterFinalAuthorityCompare?: () => void;
|
|
3046
|
+
/** Test-only bounded-takeover override; production uses the pinned lock deadline. */
|
|
3047
|
+
mutationLockTakeoverMs?: number;
|
|
3048
|
+
/** Test/chaos seam after each durable mutable-file replacement. */
|
|
3049
|
+
afterMutableReplacement?: (targetRelPath: string) => void;
|
|
3050
|
+
/** Test/chaos seam after a fresh bundle publish and before its index projection. */
|
|
3051
|
+
afterBundlePublished?: (bundleId: RecordId) => void;
|
|
3052
|
+
/** Test/chaos seam after the index transaction and before intent removal. */
|
|
3053
|
+
afterIndexApplied?: (bundleId: RecordId) => void;
|
|
3054
|
+
/** Test/chaos seams around the durable observation/cleanup boundary. */
|
|
3055
|
+
afterEffectReceiptsWritten?: () => void;
|
|
3056
|
+
afterIntentCleared?: () => void;
|
|
3057
|
+
};
|
|
3058
|
+
operations?: {
|
|
3059
|
+
/** Test/chaos seam; production always uses the canonical publisher. */
|
|
3060
|
+
publishBundle?: (config: BundleStoreConfig, input: PublishBundleInput) => PublishBundleOutcome;
|
|
3061
|
+
};
|
|
3062
|
+
}
|
|
3063
|
+
interface CommittedBundleResult {
|
|
3064
|
+
bundleId: RecordId;
|
|
3065
|
+
bundleDir: string;
|
|
3066
|
+
deltaKind: Delta['kind'];
|
|
3067
|
+
/** D-16 exception-bucket observability; absent when the gate promotes or never runs. */
|
|
3068
|
+
promotionHoldReason?: PromotionGateHoldReason;
|
|
3069
|
+
promotionPath?: PromotionPath;
|
|
3070
|
+
}
|
|
3071
|
+
/**
|
|
3072
|
+
* 381-47 (F-381-45-1): WHY a delta-noop disposition had nothing to apply. `authored-noop`
|
|
3073
|
+
* = a capable-model author deliberately emitted a Noop delta; the `fallback-*` members
|
|
3074
|
+
* name WHICH author fallback defeated extraction (the §7.9 one-element procedure Noop).
|
|
3075
|
+
* Benign noop reasons (evidence-token dedup, disposition rejects) never carry a cause.
|
|
3076
|
+
*/
|
|
3077
|
+
type EmptyDeltaCause = 'authored-noop' | 'fallback-malformed' | 'fallback-no-model' | 'fallback-token-budget' | 'fallback-model-error';
|
|
3078
|
+
type CommitCurationOutcome = ({
|
|
3079
|
+
kind: 'applied';
|
|
3080
|
+
} & CommittedBundleResult) | ({
|
|
3081
|
+
kind: 'downgraded';
|
|
3082
|
+
reason: string;
|
|
3083
|
+
original: Delta;
|
|
3084
|
+
} & CommittedBundleResult) | ({
|
|
3085
|
+
kind: 'converted-confirm';
|
|
3086
|
+
} & CommittedBundleResult) | {
|
|
3087
|
+
kind: 'abandoned-stale-epoch';
|
|
3088
|
+
observedEpoch: number;
|
|
3089
|
+
} | {
|
|
3090
|
+
kind: 'failed';
|
|
3091
|
+
reason: 'identity-collision' | 'append-failed';
|
|
3092
|
+
collisionReason?: Extract<PublishBundleOutcome, {
|
|
3093
|
+
kind: 'identity-collision';
|
|
3094
|
+
}>['reason'];
|
|
3095
|
+
} | {
|
|
3096
|
+
kind: 'noop';
|
|
3097
|
+
reason: string;
|
|
3098
|
+
emptyDeltaCause?: EmptyDeltaCause;
|
|
3099
|
+
} | {
|
|
3100
|
+
kind: 'requeue-resynthesis';
|
|
3101
|
+
reason: string;
|
|
3102
|
+
};
|
|
3103
|
+
interface ApplyIndexDeltaForBundleInput {
|
|
3104
|
+
knowledgeRoot: string;
|
|
3105
|
+
priors?: TrustPriorTable;
|
|
3106
|
+
bundleId: string;
|
|
3107
|
+
product?: string;
|
|
3108
|
+
}
|
|
3109
|
+
/** Shared Plan 378-10 projection authority used by commit and journal reconciliation. */
|
|
3110
|
+
declare function applyIndexDeltaForBundle(input: ApplyIndexDeltaForBundleInput): void;
|
|
3111
|
+
/** Recovery alias deliberately delegates to the same projection unit as the live tail. */
|
|
3112
|
+
declare function deriveIndexRowFromBundle(input: ApplyIndexDeltaForBundleInput): void;
|
|
3113
|
+
/**
|
|
3114
|
+
* The one serialized mutation boundary: fresh epoch, disposition, intent, fresh epoch, publish,
|
|
3115
|
+
* append-only lifecycle, canonical index projection, intent clear, and queue completion.
|
|
3116
|
+
*/
|
|
3117
|
+
declare function commitCurationDelta(deps: CommitCurationDependencies, job: CommitCurationJob, checkpoint: AuthoredDeltaCheckpoint): CommitCurationOutcome;
|
|
3118
|
+
|
|
3119
|
+
interface ReconcileOnDrainStartHooks {
|
|
3120
|
+
/**
|
|
3121
|
+
* Fires immediately before a stale intent is renamed aside. The only seam that can reproduce
|
|
3122
|
+
* the race a second reconciler on another host creates: it removes the intent file between our
|
|
3123
|
+
* listing and our rename.
|
|
3124
|
+
*/
|
|
3125
|
+
beforeStaleQuarantine?(candidateId: string, epoch: number): void;
|
|
3126
|
+
}
|
|
3127
|
+
interface ReconcileOnDrainStartDependencies {
|
|
3128
|
+
knowledgeRoot: string;
|
|
3129
|
+
writerAuthority: CurrentWriterAuthority;
|
|
3130
|
+
hasIndexRow(bundleId: string): boolean;
|
|
3131
|
+
applyIndexDelta(intent: CommitIntent): void;
|
|
3132
|
+
deriveIndexRowFromBundle(bundleId: string): void;
|
|
3133
|
+
hooks?: ReconcileOnDrainStartHooks;
|
|
3134
|
+
}
|
|
3135
|
+
interface ReconcileReport {
|
|
3136
|
+
intentsCleared: number;
|
|
3137
|
+
intentsReplayed: number;
|
|
3138
|
+
intentsDiscarded: number;
|
|
3139
|
+
/** Intents authored before the reconciled-epoch watermark: renamed aside, never replayed. */
|
|
3140
|
+
intentsQuarantinedStale: number;
|
|
3141
|
+
jobsRequeued: number;
|
|
3142
|
+
orphansRemoved: number;
|
|
3143
|
+
/** Present on production reconciliation; optional keeps injected legacy test reports compatible. */
|
|
3144
|
+
mutationsRecovered?: number;
|
|
3145
|
+
malformed: number;
|
|
3146
|
+
}
|
|
3147
|
+
declare function reconcileOnDrainStart(deps: ReconcileOnDrainStartDependencies): ReconcileReport;
|
|
3148
|
+
|
|
3149
|
+
/**
|
|
3150
|
+
* CR-02 takeover barriers. Test-only seams naming the three points at which a canary flow is
|
|
3151
|
+
* about to make canonical state durable; production callers omit them.
|
|
3152
|
+
*
|
|
3153
|
+
* The two entry barriers fire OUTSIDE the held section, which is what lets a schedule complete a
|
|
3154
|
+
* real takeover there and then observe the resumed writer's refusal. `beforeIndexProjection` fires
|
|
3155
|
+
* INSIDE it, so its schedule observes a contender blocked behind the tail instead.
|
|
3156
|
+
*/
|
|
3157
|
+
interface CanaryAuthorityHooks {
|
|
3158
|
+
/** Immediately before the negative arm enters its held section. */
|
|
3159
|
+
beforeNegativeAppend?: () => void;
|
|
3160
|
+
/** Immediately before the positive arm enters its held promotion section. */
|
|
3161
|
+
beforePromotionAppend?: () => void;
|
|
3162
|
+
/** Inside the negative arm's held section, between its append and its projection. */
|
|
3163
|
+
beforeIndexProjection?: () => void;
|
|
3164
|
+
}
|
|
3165
|
+
interface CreateLocalKnowledgeStoreConfig {
|
|
3166
|
+
knowledgeRoot: string;
|
|
3167
|
+
executionContext: ExecutionContext;
|
|
3168
|
+
/** The holder's fresh lease epoch. Defaults to a fresh disk read for composition roots. */
|
|
3169
|
+
epoch?: number;
|
|
3170
|
+
/**
|
|
3171
|
+
* The caller's real writer-lease id, paired with `epoch`.
|
|
3172
|
+
*
|
|
3173
|
+
* CR-02: every canonical append, promotion, and index projection this store performs carries
|
|
3174
|
+
* this identity into `withCurrentWriterAuthority`, so a store constructed by someone who is not
|
|
3175
|
+
* the published holder is refused at its first canonical mutation instead of laundering a
|
|
3176
|
+
* fabricated id. It is required precisely so no code path can omit it and fall back to one.
|
|
3177
|
+
*/
|
|
3178
|
+
writerLeaseId: string;
|
|
3179
|
+
/** Port calls lack a run ordinal; callers with run context should supply it. */
|
|
3180
|
+
sourceBuildOrdinal?: number;
|
|
3181
|
+
sourceRunId?: string;
|
|
3182
|
+
/** 2026-09-07, 418 D-07: queue entry identity stamped as producedBy.jobId. */
|
|
3183
|
+
sourceJobId?: string;
|
|
3184
|
+
screenStates?: readonly ScreenState[];
|
|
3185
|
+
resolvePromotionPosture?: ResolvePromotionPosture;
|
|
3186
|
+
/** Resolved once at construction; only neutral immutable data reaches folds and projections. */
|
|
3187
|
+
resolveTrustPriors?: () => TrustPriorTable | undefined;
|
|
3188
|
+
onPromotionOutcome?: (report: PromotionOutcomeReport) => void;
|
|
3189
|
+
/** Fault-injection seam; production callers must omit it. */
|
|
3190
|
+
canaryAuthorityHooks?: CanaryAuthorityHooks;
|
|
3191
|
+
/**
|
|
3192
|
+
* Joins the caller's own terminal work to the canary tail's held section. The drain's `done`
|
|
3193
|
+
* job-state write uses this so the append, the projection, and the lifecycle transition are one
|
|
3194
|
+
* indivisible section; implementations must use within-held write forms only.
|
|
3195
|
+
*/
|
|
3196
|
+
onCanaryTailWithinCurrentAuthority?: () => void;
|
|
3197
|
+
operations?: {
|
|
3198
|
+
/** Test/chaos seam; production always uses commitCurationDelta. */
|
|
3199
|
+
commitCurationDelta?: typeof commitCurationDelta;
|
|
3200
|
+
};
|
|
3201
|
+
}
|
|
3202
|
+
interface PromotionOutcomeReport {
|
|
3203
|
+
candidateId: RecordId;
|
|
3204
|
+
promotionPath?: PromotionPath;
|
|
3205
|
+
promotionHoldReason?: PromotionGateHoldReason;
|
|
3206
|
+
}
|
|
3207
|
+
/**
|
|
3208
|
+
* @deprecated `recordCanaryOutcome` is implemented. The exported class remains only so code
|
|
3209
|
+
* compiled against the pre-380 package surface does not lose its named import.
|
|
3210
|
+
*/
|
|
3211
|
+
declare class KnowledgeStoreNotImplementedError extends Error {
|
|
3212
|
+
readonly operation: 'recordCanaryOutcome';
|
|
3213
|
+
constructor(operation: 'recordCanaryOutcome', _retiredOwnerPhase?: 380);
|
|
3214
|
+
}
|
|
3215
|
+
type KnowledgePromotionErrorReason = PromotionGateHoldReason | 'propose-only' | 'not-found';
|
|
3216
|
+
/** Typed refusal for the evidence-gated promote port; callers never receive a force path. */
|
|
3217
|
+
declare class KnowledgePromotionError extends Error {
|
|
3218
|
+
readonly candidateId: RecordId;
|
|
3219
|
+
readonly reason: KnowledgePromotionErrorReason;
|
|
3220
|
+
constructor(candidateId: RecordId, reason: KnowledgePromotionErrorReason);
|
|
3221
|
+
}
|
|
3222
|
+
declare class KnowledgeCommitError extends Error {
|
|
3223
|
+
readonly outcome: CommitCurationOutcome;
|
|
3224
|
+
constructor(outcome: CommitCurationOutcome);
|
|
3225
|
+
}
|
|
3226
|
+
/** Typed WR-02 refusal for procedure drafts that require evidence this port cannot carry. */
|
|
3227
|
+
declare class KnowledgeUnsupportedDeltaError extends Error {
|
|
3228
|
+
readonly deltaKind: Delta['kind'];
|
|
3229
|
+
readonly reason: 'procedure-evidence-unsupported';
|
|
3230
|
+
constructor(deltaKind: Delta['kind']);
|
|
3231
|
+
}
|
|
3232
|
+
/**
|
|
3233
|
+
* Realizes the agent write port over the canonical mutation path. D-08 propose-only is a
|
|
3234
|
+
* disposition profile inside commitCurationDelta, never a second mutation path. Because the port
|
|
3235
|
+
* carries bare deltas, this bridge materializes the smallest queue/checkpoint envelope and resolves
|
|
3236
|
+
* cited neighbor truth from canonical bundles before entering disposition.
|
|
3237
|
+
*/
|
|
3238
|
+
declare function createLocalKnowledgeStore(config: CreateLocalKnowledgeStoreConfig): KnowledgePort;
|
|
3239
|
+
|
|
3240
|
+
type MaintenanceSkipReason = 'lease-held' | 'budget-exhausted' | 'aborted' | 'daemon-cadence';
|
|
3241
|
+
type WriterPassReport = {
|
|
3242
|
+
kind: 'not-requested';
|
|
3243
|
+
} | {
|
|
3244
|
+
kind: 'skipped';
|
|
3245
|
+
reason: MaintenanceSkipReason;
|
|
3246
|
+
} | {
|
|
3247
|
+
kind: 'rebuilt';
|
|
3248
|
+
request?: RebuildRequest;
|
|
3249
|
+
rebuild: RebuildReport;
|
|
3250
|
+
} | {
|
|
3251
|
+
kind: 'failed';
|
|
3252
|
+
message: string;
|
|
3253
|
+
};
|
|
3254
|
+
type GcPassReport = {
|
|
3255
|
+
kind: 'not-run';
|
|
3256
|
+
} | {
|
|
3257
|
+
kind: 'skipped';
|
|
3258
|
+
reason: MaintenanceSkipReason;
|
|
3259
|
+
} | {
|
|
3260
|
+
kind: 'completed';
|
|
3261
|
+
summary: GcSummary;
|
|
3262
|
+
/** WR-01: projection rows removed by the same-tail scoped cleanup; absent on zero-trim. */
|
|
3263
|
+
projectionRowsRemoved?: number;
|
|
3264
|
+
} | {
|
|
3265
|
+
kind: 'failed';
|
|
3266
|
+
message: string;
|
|
3267
|
+
};
|
|
3268
|
+
interface MaintenanceOperations {
|
|
3269
|
+
readRebuildRequest: typeof readRebuildRequest;
|
|
3270
|
+
readIndexMaintenanceState: typeof readIndexMaintenanceState;
|
|
3271
|
+
acquireEmbedder: typeof acquireEmbedder;
|
|
3272
|
+
rebuildIndex: typeof rebuildIndex;
|
|
3273
|
+
runKnowledgeGc: typeof runKnowledgeGc;
|
|
3274
|
+
removeBundleProjectionRows: typeof removeBundleProjectionRows;
|
|
3275
|
+
beforeGcRemoval?: RunKnowledgeGcHooks['beforeGcRemoval'];
|
|
3276
|
+
}
|
|
3277
|
+
interface MaintenanceBudget {
|
|
3278
|
+
now: () => number;
|
|
3279
|
+
startedAtMs: number;
|
|
3280
|
+
limitMs: number;
|
|
3281
|
+
}
|
|
3282
|
+
interface RunMaintenanceTailOptions {
|
|
3283
|
+
knowledgeRoot: string;
|
|
3284
|
+
/** Same host-resolved data supplied to drains and review stores. */
|
|
3285
|
+
priors?: TrustPriorTable;
|
|
3286
|
+
lease: {
|
|
3287
|
+
leaseId: string;
|
|
3288
|
+
epoch: number;
|
|
3289
|
+
};
|
|
3290
|
+
/** Host-resolved posture; daemon callers pass worker-required, one-shot callers omit it. */
|
|
3291
|
+
embeddingCapability?: AcquireEmbedderOutcome;
|
|
3292
|
+
/** Omit for daemon cadence; one-shot drains provide their 60 s boundary explicitly. */
|
|
3293
|
+
budget?: MaintenanceBudget;
|
|
3294
|
+
/** Fault-injection seam; production callers must omit it. */
|
|
3295
|
+
operations?: Partial<MaintenanceOperations>;
|
|
3296
|
+
/** One-shot drains fold authority loss into their report; daemon callers surface it by default. */
|
|
3297
|
+
surfaceAuthorityLoss?: boolean;
|
|
3298
|
+
}
|
|
3299
|
+
interface MaintenanceTailFailure {
|
|
3300
|
+
stage: 'writer-pass' | 'gc';
|
|
3301
|
+
error: unknown;
|
|
3302
|
+
}
|
|
3303
|
+
interface MaintenanceTailResult {
|
|
3304
|
+
writerPass: WriterPassReport;
|
|
3305
|
+
gc: GcPassReport;
|
|
3306
|
+
failures: MaintenanceTailFailure[];
|
|
3307
|
+
}
|
|
3308
|
+
/**
|
|
3309
|
+
* Run the writer-repair and canonical-GC tail as one host-independent callable.
|
|
3310
|
+
*
|
|
3311
|
+
* Daemon callers omit budget and receive stale authority errors unchanged. The one-shot drain
|
|
3312
|
+
* supplies its existing wall-clock boundary and folds typed failures into DrainReport.
|
|
3313
|
+
*/
|
|
3314
|
+
declare function runMaintenanceTail(options: RunMaintenanceTailOptions): Promise<MaintenanceTailResult>;
|
|
3315
|
+
|
|
3316
|
+
/** Ratified M2 one-shot budget. A run's tail aborts an author request in flight at its end. */
|
|
3317
|
+
declare const DRAIN_BUDGET_MS = 60000;
|
|
3318
|
+
/** Provisional §7.4 cap over distinct search-before-create query targets. */
|
|
3319
|
+
declare const SEARCH_BEFORE_CREATE_MAX_QUERIES = 5;
|
|
3320
|
+
/** Provisional 376 D-14 per-job breaker before a vector-deferred commit is forced. */
|
|
3321
|
+
declare const EMBED_CRASH_VECTORLESS_THRESHOLD = 2;
|
|
3322
|
+
type DrainFailureStage = 'lease' | 'reconcile' | 'claim' | 'heartbeat' | 'job-state' | 'search' | 'author' | 'checkpoint' | 'commit' | 'quarantine' | 'requeue' | 'release' | 'writer-pass' | 'gc';
|
|
3323
|
+
interface DrainFailure {
|
|
3324
|
+
stage: DrainFailureStage;
|
|
3325
|
+
message: string;
|
|
3326
|
+
candidateId?: string;
|
|
3327
|
+
}
|
|
3328
|
+
/**
|
|
3329
|
+
* A commit that decided there was nothing to apply. Legitimate reasons exist (evidence-token
|
|
3330
|
+
* dedup), so a noop is never a failure — but dropping it on the floor made live procedure
|
|
3331
|
+
* extraction die silently for 13 UAT runs (G-381-1). Visibility, never a gate.
|
|
3332
|
+
*/
|
|
3333
|
+
interface DrainNoop {
|
|
3334
|
+
candidateId: string;
|
|
3335
|
+
reason: string;
|
|
3336
|
+
/**
|
|
3337
|
+
* 381-47: present only on delta-noop entries — distinguishes a defeated extraction
|
|
3338
|
+
* (`fallback-*`) from a deliberate authored Noop; benign dedup carries no cause.
|
|
3339
|
+
*/
|
|
3340
|
+
emptyDeltaCause?: EmptyDeltaCause;
|
|
3341
|
+
}
|
|
3342
|
+
interface DrainPromotionOutcome {
|
|
3343
|
+
candidateId: string;
|
|
3344
|
+
promotionPath?: PromotionPath;
|
|
3345
|
+
promotionHoldReason?: PromotionGateHoldReason;
|
|
3346
|
+
}
|
|
3347
|
+
interface DrainReportBase {
|
|
3348
|
+
/** Actual surviving effects for the requested run, also present on incomplete drains. */
|
|
3349
|
+
effects?: readonly CurationSnapshotChange[];
|
|
3350
|
+
/** Certified only after a complete drain; absent for historical missing receipts. */
|
|
3351
|
+
snapshot?: CurationSnapshot;
|
|
3352
|
+
/**
|
|
3353
|
+
* The effects committed; only the projection over them failed, so `snapshot` is absent. Never a
|
|
3354
|
+
* failure: the drain stays complete and nothing is retried or refolded.
|
|
3355
|
+
*/
|
|
3356
|
+
snapshotFoldFailed?: true;
|
|
3357
|
+
jobsProcessed: number;
|
|
3358
|
+
committed: number;
|
|
3359
|
+
evidenceCommitted?: number;
|
|
3360
|
+
/**
|
|
3361
|
+
* Committed deltas whose kind was `Deprecate` (388-02).
|
|
3362
|
+
*
|
|
3363
|
+
* OPTIONAL because the drain report is constructed by fault-injection fakes across four
|
|
3364
|
+
* packages and a required field would make every one of them a compile error over a number
|
|
3365
|
+
* they have no opinion about. The real drain always sets it, so a production report saying
|
|
3366
|
+
* `deprecated: 0` is a measurement rather than an absence — which is what the post-run
|
|
3367
|
+
* chain's notification (D-11) needs in order to tell a drain that deprecated nothing apart
|
|
3368
|
+
* from a drain that never ran at all.
|
|
3369
|
+
*/
|
|
3370
|
+
deprecated?: number;
|
|
3371
|
+
/** Optional for fault-injection fakes; the real drain always sets this measurement. */
|
|
3372
|
+
promotions?: readonly DrainPromotionOutcome[];
|
|
3373
|
+
downgraded: number;
|
|
3374
|
+
withheld: number;
|
|
3375
|
+
quarantined: number;
|
|
3376
|
+
requeued: number;
|
|
3377
|
+
failures: number;
|
|
3378
|
+
failureDetails: DrainFailure[];
|
|
3379
|
+
noops: number;
|
|
3380
|
+
noopDetails: DrainNoop[];
|
|
3381
|
+
reconcile: ReconcileReport | undefined;
|
|
3382
|
+
writerPass: WriterPassReport;
|
|
3383
|
+
gc: GcPassReport;
|
|
3384
|
+
/** Visibility only: every durable disposition that still prevents queue completion. */
|
|
3385
|
+
remaining: number;
|
|
3386
|
+
/** Durable remainder partition. The current writer's nonterminal claim is included. */
|
|
3387
|
+
remainingWork: CurationRemainingWork;
|
|
3388
|
+
}
|
|
3389
|
+
type DrainReport = DrainReportBase & ({
|
|
3390
|
+
kind: 'drained' | 'aborted';
|
|
3391
|
+
} | {
|
|
3392
|
+
kind: 'handed-off';
|
|
3393
|
+
holder: WriterLease;
|
|
3394
|
+
});
|
|
3395
|
+
type CurationDrainLifecycleEvent = {
|
|
3396
|
+
readonly kind: 'job-claimed';
|
|
3397
|
+
readonly candidateId: string;
|
|
3398
|
+
} | {
|
|
3399
|
+
readonly kind: 'job-completed';
|
|
3400
|
+
readonly candidateId: string;
|
|
3401
|
+
};
|
|
3402
|
+
/**
|
|
3403
|
+
* Internal capability table used by focused fault-injection tests. Production callers omit it;
|
|
3404
|
+
* every default delegates directly to the shipped queue, lease, retrieval, commit, and rebuild
|
|
3405
|
+
* authorities.
|
|
3406
|
+
*/
|
|
3407
|
+
interface DrainOperations extends MaintenanceOperations {
|
|
3408
|
+
acquireWriterLease: typeof acquireWriterLease;
|
|
3409
|
+
heartbeatLease: typeof heartbeatLease;
|
|
3410
|
+
releaseLease: typeof releaseLease;
|
|
3411
|
+
reconcileOnDrainStart: typeof reconcileOnDrainStart;
|
|
3412
|
+
claimNextJob: typeof claimNextJob;
|
|
3413
|
+
quarantineClaimed: typeof quarantineClaimed;
|
|
3414
|
+
requeueClaimed: typeof requeueClaimed;
|
|
3415
|
+
readJobState: typeof readJobState;
|
|
3416
|
+
writeJobState: typeof writeJobState;
|
|
3417
|
+
persistAuthoredCheckpoint: typeof persistAuthoredCheckpoint;
|
|
3418
|
+
openKnowledgeReader: typeof openKnowledgeReader;
|
|
3419
|
+
buildRetrievalQuery: typeof buildRetrievalQuery;
|
|
3420
|
+
retrieve: typeof retrieve;
|
|
3421
|
+
commitCurationDelta: typeof commitCurationDelta;
|
|
3422
|
+
/** The canonical commit already projects dense work as pending; the breaker selects this seam. */
|
|
3423
|
+
commitCurationDeltaVectorless: typeof commitCurationDelta;
|
|
3424
|
+
hasIndexRow(knowledgeRoot: string, bundleId: string): boolean;
|
|
3425
|
+
applyIndexDeltaForBundle: typeof applyIndexDeltaForBundle;
|
|
3426
|
+
deriveIndexRowFromBundle: typeof deriveIndexRowFromBundle;
|
|
3427
|
+
/** CR-02 takeover barriers for the canary branch; production omits them. */
|
|
3428
|
+
canaryAuthorityHooks?: CanaryAuthorityHooks;
|
|
3429
|
+
}
|
|
3430
|
+
interface DrainOptions {
|
|
3431
|
+
/** A per-run reader request, independent of which queued jobs this drain claims. */
|
|
3432
|
+
sourceRunId?: string;
|
|
3433
|
+
observationIds?: readonly string[];
|
|
3434
|
+
knowledgeRoot: string;
|
|
3435
|
+
/** `unbounded` is reserved for a standing host whose process lifetime is the boundary. */
|
|
3436
|
+
budgetMs?: number | 'unbounded';
|
|
3437
|
+
/** Standing writer authority owned by the caller; drainQueue never mutates its lifecycle. */
|
|
3438
|
+
lease?: {
|
|
3439
|
+
leaseId: string;
|
|
3440
|
+
epoch: number;
|
|
3441
|
+
};
|
|
3442
|
+
author: CuratorAuthor;
|
|
3443
|
+
executionContext: ExecutionContext;
|
|
3444
|
+
/** Host-resolved posture; daemon sessions pass worker-required capability here. */
|
|
3445
|
+
embeddingCapability?: AcquireEmbedderOutcome;
|
|
3446
|
+
/** Built once per drain on the host; synchronous per candidate inside the gate. */
|
|
3447
|
+
resolvePromotionPosture?: ResolvePromotionPosture;
|
|
3448
|
+
/** Already-resolved host snapshot; the host retains this data across queue retries. */
|
|
3449
|
+
priors?: TrustPriorTable;
|
|
3450
|
+
/** Default inline preserves one-shot behavior; daemon sessions skip for their own cadence. */
|
|
3451
|
+
maintenance?: 'inline' | 'skip';
|
|
3452
|
+
signal?: AbortSignal;
|
|
3453
|
+
/** Synchronous durable-boundary observer; daemon hosts append these facts before proceeding. */
|
|
3454
|
+
onJobLifecycle?: (event: CurationDrainLifecycleEvent) => void;
|
|
3455
|
+
/** D-06 test seam. Production uses the one wall clock only at drain boundaries. */
|
|
3456
|
+
now?: () => number;
|
|
3457
|
+
/** Fault-injection seam; production callers must omit it. */
|
|
3458
|
+
operations?: Partial<DrainOperations>;
|
|
3459
|
+
}
|
|
3460
|
+
/**
|
|
3461
|
+
* Lease-gated one-shot Curator drain. It owns no provider: authoring is injected, serialized, and
|
|
3462
|
+
* durably checkpointed before the deterministic commit tail. Abort and budget are checked at job
|
|
3463
|
+
* boundaries; an in-flight model request is cut off only by the host's own author signal.
|
|
3464
|
+
*/
|
|
3465
|
+
declare function drainQueue(options: DrainOptions): Promise<DrainReport>;
|
|
3466
|
+
|
|
3467
|
+
declare const PURGE_RECEIPT_SCHEMA_VERSION = 2;
|
|
3468
|
+
/**
|
|
3469
|
+
* Content-free committed audit receipt shared by the purge writer and read-only maintenance
|
|
3470
|
+
* history. Keeping the contract outside purge.ts prevents the reader graph from importing the
|
|
3471
|
+
* destructive implementation merely to validate committed receipt bytes.
|
|
3472
|
+
*/
|
|
3473
|
+
declare const PurgeReceiptSchema: z.ZodObject<{
|
|
3474
|
+
schemaVersion: z.ZodLiteral<2>;
|
|
3475
|
+
purgedRecordId: z.ZodString;
|
|
3476
|
+
purgedAtOrdinal: z.ZodNumber;
|
|
3477
|
+
initiator: z.ZodString;
|
|
3478
|
+
affectedPaths: z.ZodArray<z.ZodString>;
|
|
3479
|
+
firstCommittedOrdinal: z.ZodNumber;
|
|
3480
|
+
}, z.core.$strict>;
|
|
3481
|
+
declare const purgeReceiptSchema: z.ZodObject<{
|
|
3482
|
+
schemaVersion: z.ZodLiteral<2>;
|
|
3483
|
+
purgedRecordId: z.ZodString;
|
|
3484
|
+
purgedAtOrdinal: z.ZodNumber;
|
|
3485
|
+
initiator: z.ZodString;
|
|
3486
|
+
affectedPaths: z.ZodArray<z.ZodString>;
|
|
3487
|
+
firstCommittedOrdinal: z.ZodNumber;
|
|
3488
|
+
}, z.core.$strict>;
|
|
3489
|
+
type PurgeReceipt = z.infer<typeof PurgeReceiptSchema>;
|
|
3490
|
+
declare function guardPurgeReceipt(value: unknown): PurgeReceipt;
|
|
3491
|
+
|
|
3492
|
+
interface PurgeAffectedBundleTarget {
|
|
3493
|
+
product: string;
|
|
3494
|
+
bundleDir: string;
|
|
3495
|
+
kind: LoadedBundle['frontmatter']['kind'];
|
|
3496
|
+
affectedPaths: string[];
|
|
3497
|
+
}
|
|
3498
|
+
interface PurgeAffectedQueueTarget {
|
|
3499
|
+
candidateId: string;
|
|
3500
|
+
candidateDir: string;
|
|
3501
|
+
jobStatePath: string;
|
|
3502
|
+
}
|
|
3503
|
+
/**
|
|
3504
|
+
* Content-free, deterministic statement of every local surface one purge operation will affect.
|
|
3505
|
+
* This is the single planning shape shared by preview, the under-lease recheck, and destructive
|
|
3506
|
+
* execution.
|
|
3507
|
+
*/
|
|
3508
|
+
interface PurgeAffectedSet {
|
|
3509
|
+
recordId: string;
|
|
3510
|
+
state: 'live' | 'resume' | 'already-purged' | 'not-found';
|
|
3511
|
+
bundles: PurgeAffectedBundleTarget[];
|
|
3512
|
+
receiptAffectedPaths: string[];
|
|
3513
|
+
projectionTargets: string[];
|
|
3514
|
+
embedCacheAction: 'clear-all';
|
|
3515
|
+
queueTargets: PurgeAffectedQueueTarget[];
|
|
3516
|
+
intentPath: string;
|
|
3517
|
+
receiptPath: string;
|
|
3518
|
+
}
|
|
3519
|
+
interface PurgeRecordInput {
|
|
3520
|
+
knowledgeRoot: string;
|
|
3521
|
+
recordId: RecordId;
|
|
3522
|
+
/** Caller-owned sovereign identity; Phase 382 supplies the confirmed user identity. */
|
|
3523
|
+
initiator: string;
|
|
3524
|
+
/** Runtime-counter reservation used for a fresh destruction receipt; resumes reuse intent. */
|
|
3525
|
+
purgedAtOrdinal?: number;
|
|
3526
|
+
/** Governed maintenance callers fence this exact lease at every mutation boundary. */
|
|
3527
|
+
writerAuthority?: WriterLeaseAuthority;
|
|
3528
|
+
/** Fingerprint of the caller's preview; drift must fail before any mutation. */
|
|
3529
|
+
expectedAffectedSetFingerprint?: string;
|
|
3530
|
+
/** Test/chaos seam between purge phases; production callers omit it (commit.ts precedent). */
|
|
3531
|
+
hooks?: {
|
|
3532
|
+
/** Immediately after the durable intent publication. */
|
|
3533
|
+
afterIntentWritten?: () => void;
|
|
3534
|
+
/** After the transactional projection purge. */
|
|
3535
|
+
afterProjectionPurge?: () => void;
|
|
3536
|
+
/** After every committed bundle tree removal. */
|
|
3537
|
+
afterBundleRemoval?: () => void;
|
|
3538
|
+
/** After the queue payload sweep. */
|
|
3539
|
+
afterQueueSweep?: () => void;
|
|
3540
|
+
/** Immediately before the completion receipt publication. */
|
|
3541
|
+
beforeReceiptPublish?: () => void;
|
|
3542
|
+
};
|
|
3543
|
+
}
|
|
3544
|
+
type PurgeRecordOutcome = {
|
|
3545
|
+
kind: 'purged';
|
|
3546
|
+
receipt: PurgeReceipt;
|
|
3547
|
+
} | {
|
|
3548
|
+
kind: 'already-purged';
|
|
3549
|
+
receipt: PurgeReceipt;
|
|
3550
|
+
} | {
|
|
3551
|
+
kind: 'not-found';
|
|
3552
|
+
};
|
|
3553
|
+
declare class PurgeTargetChangedError extends Error {
|
|
3554
|
+
readonly expectedFingerprint: string;
|
|
3555
|
+
readonly actualFingerprint: string;
|
|
3556
|
+
readonly code = "purge-target-changed";
|
|
3557
|
+
constructor(expectedFingerprint: string, actualFingerprint: string);
|
|
3558
|
+
}
|
|
3559
|
+
declare class PurgeTargetIntegrityError extends Error {
|
|
3560
|
+
readonly targetPath: string;
|
|
3561
|
+
readonly reason: string;
|
|
3562
|
+
readonly code = "purge-target-integrity";
|
|
3563
|
+
constructor(targetPath: string, reason: string);
|
|
3564
|
+
}
|
|
3565
|
+
declare class PurgeQueueIdentityError extends Error {
|
|
3566
|
+
readonly targetPath: string;
|
|
3567
|
+
readonly reason: string;
|
|
3568
|
+
readonly code = "purge-queue-identity";
|
|
3569
|
+
constructor(targetPath: string, reason: string);
|
|
3570
|
+
}
|
|
3571
|
+
declare class PurgeCompletionVerificationError extends Error {
|
|
3572
|
+
readonly survivingSurface: string;
|
|
3573
|
+
readonly code = "purge-completion-verification";
|
|
3574
|
+
constructor(survivingSurface: string);
|
|
3575
|
+
}
|
|
3576
|
+
declare class PurgeChronologyRequiredError extends Error {
|
|
3577
|
+
readonly code = "purge-chronology-required";
|
|
3578
|
+
constructor();
|
|
3579
|
+
}
|
|
3580
|
+
declare function resolvePurgeAffectedSet(input: {
|
|
3581
|
+
knowledgeRoot: string;
|
|
3582
|
+
recordId: RecordId;
|
|
3583
|
+
}): PurgeAffectedSet;
|
|
3584
|
+
declare function purgeAffectedSetFingerprint(affectedSet: PurgeAffectedSet): string;
|
|
3585
|
+
/**
|
|
3586
|
+
* Hard-remove one confirmed-sensitive record from every recoverable local-store surface.
|
|
3587
|
+
*
|
|
3588
|
+
* Recovery invariant (CR-04): nothing irreversible ever precedes a durable intent, so a retry
|
|
3589
|
+
* either re-resolves intact state (crash before the intent) or replays the intent's persisted
|
|
3590
|
+
* identities to the identical completion receipt (crash at any later boundary).
|
|
3591
|
+
*
|
|
3592
|
+
* Revival ratification (SC-4/DCAY-05, option a): bundle ids are deterministic content addresses,
|
|
3593
|
+
* so purged-then-re-learned content re-mints the SAME record id. Receipt-exists-but-live-surfaces
|
|
3594
|
+
* therefore runs a FRESH destruction cycle publishing the next append-only versioned receipt in
|
|
3595
|
+
* the series; original audit receipts are never rewritten, and already-purged is attested only
|
|
3596
|
+
* over verified-dead surfaces (live resolution always precedes any receipt-based attestation).
|
|
3597
|
+
*/
|
|
3598
|
+
declare function purgeRecord(input: PurgeRecordInput): PurgeRecordOutcome;
|
|
3599
|
+
|
|
3600
|
+
/**
|
|
3601
|
+
* The §7.7 projections a forget in THIS store actually scrubs, enumerated honestly.
|
|
3602
|
+
*
|
|
3603
|
+
* `KNOWLEDGE_PROJECTIONS` declares four — `fts`, `vec`, `graph`, `exemplar` — and a receipt
|
|
3604
|
+
* claiming all four would be a receipt nobody can trust. `scrubDeadRecallRows` (index-rebuild.ts)
|
|
3605
|
+
* deletes the FTS row, deletes the record from every materialised vec table, and deletes the
|
|
3606
|
+
* record's graph edges plus the nodes those edges orphaned. It does NOT touch the exemplar
|
|
3607
|
+
* ranking, and it should not: an exemplar in this system is a TEST reference drawn from the
|
|
3608
|
+
* run-outcome projection (`serving/get-authoring-brief.ts`), not a knowledge record, so a
|
|
3609
|
+
* forgotten record has no exemplar row to scrub. Listing `exemplar` anyway would be the receipt
|
|
3610
|
+
* asserting work nobody did — which is worse than a receipt that says less, because a shorter
|
|
3611
|
+
* true list can be lengthened and a false one cannot be believed.
|
|
3612
|
+
*
|
|
3613
|
+
* When the exemplar ranking gains knowledge-record rows, this constant is the one place that
|
|
3614
|
+
* fact is recorded, and the receipt widens with it.
|
|
3615
|
+
*/
|
|
3616
|
+
declare const FORGET_SCRUBBED_PROJECTIONS: readonly KnowledgeProjection[];
|
|
3617
|
+
/** Resolves a `MEM-` short-ID to the machine id it addresses, or `undefined` (D-01/D-04). */
|
|
3618
|
+
type ResolveBundleShortId = (shortId: string) => string | undefined;
|
|
3619
|
+
/** A validated mark, accept, reject or forget, in the shape the review verbs take. */
|
|
3620
|
+
interface ReviewChangeRequest {
|
|
3621
|
+
readonly verb: 'accept' | 'reject' | 'forget' | 'mark';
|
|
3622
|
+
readonly input: KnowledgeAcceptInput | KnowledgeRejectInput | KnowledgeForgetInput | KnowledgeMarkInput;
|
|
3623
|
+
}
|
|
3624
|
+
declare class MarkPlanIntegrityError extends Error {
|
|
3625
|
+
readonly recordId: string;
|
|
3626
|
+
constructor(recordId: string);
|
|
3627
|
+
}
|
|
3628
|
+
|
|
3629
|
+
/**
|
|
3630
|
+
* How long a delegating process waits for the leaseholder to finish an apply (D-18).
|
|
3631
|
+
*
|
|
3632
|
+
* PINNED, not configured, on the `LEASE_HEARTBEAT_TTL_MS` idiom. 30s is chosen as "longer than any
|
|
3633
|
+
* commit this store performs, shorter than a person's patience": a commit is a handful of file
|
|
3634
|
+
* appends plus one bundle re-projection, all local. RETUNE from an observed apply that legitimately
|
|
3635
|
+
* exceeded it — never from a flaky test, which is a symptom of a wedged holder rather than a slow
|
|
3636
|
+
* one, and the wedged holder is exactly what this bound exists to refuse rather than wait out.
|
|
3637
|
+
*/
|
|
3638
|
+
declare const APPLY_DELEGATE_TIMEOUT_MS = 30000;
|
|
3639
|
+
/** The typed refusal a bounded wait produces. Never a generic timeout, never a takeover. */
|
|
3640
|
+
declare class ApplyDelegateTimeoutError extends Error {
|
|
3641
|
+
readonly changeId: string;
|
|
3642
|
+
readonly timeoutMs: number;
|
|
3643
|
+
constructor(changeId: string, timeoutMs: number);
|
|
3644
|
+
}
|
|
3645
|
+
/** The typed refusal when a live holder exists and this host was given no way to reach it. */
|
|
3646
|
+
declare class ApplyDelegateUnavailableError extends Error {
|
|
3647
|
+
readonly changeId: string;
|
|
3648
|
+
readonly holder: WriterLease;
|
|
3649
|
+
constructor(changeId: string, holder: WriterLease);
|
|
3650
|
+
}
|
|
3651
|
+
/** The record a change addresses left the store between resolution and commit. */
|
|
3652
|
+
declare class ReviewTargetVanishedError extends Error {
|
|
3653
|
+
readonly changeId: string;
|
|
3654
|
+
constructor(changeId: string);
|
|
3655
|
+
}
|
|
3656
|
+
interface WriterAuthority {
|
|
3657
|
+
readonly leaseId: string;
|
|
3658
|
+
readonly epoch: number;
|
|
3659
|
+
}
|
|
3660
|
+
/** A validated mark, accept, reject or forget, in the shape the review verbs already take. */
|
|
3661
|
+
type ExplicitReviewRequest = ReviewChangeRequest;
|
|
3662
|
+
/** What the writer-lease holder is handed: the same request and the same stable identity. */
|
|
3663
|
+
interface ExplicitReviewDelegation {
|
|
3664
|
+
readonly request: ExplicitReviewRequest;
|
|
3665
|
+
readonly operationId: string;
|
|
3666
|
+
}
|
|
3667
|
+
/**
|
|
3668
|
+
* Hand the direct request to the leaseholder and wait bounded for its answer (D-18). Injected as
|
|
3669
|
+
* an optional operation rather than built here: `knowledge-local` neither knows nor may know that a
|
|
3670
|
+
* unix socket exists. A host supplies its transport; the leaseholder's own composition supplies
|
|
3671
|
+
* nothing, which makes delegation recursion impossible by construction.
|
|
3672
|
+
*/
|
|
3673
|
+
type ExplicitReviewDelegate = (delegation: ExplicitReviewDelegation) => Promise<ExplicitReviewResult>;
|
|
3674
|
+
interface ApplyExplicitReviewInput {
|
|
3675
|
+
readonly agentQaRoot: string;
|
|
3676
|
+
readonly knowledgeRoot: string;
|
|
3677
|
+
readonly request: ExplicitReviewRequest;
|
|
3678
|
+
/**
|
|
3679
|
+
* The caller's stable identity for this change, such as a mark intent's UUID. A retry with the
|
|
3680
|
+
* same identity is the same change: its evidence tokens, receipts and record ids repeat.
|
|
3681
|
+
*/
|
|
3682
|
+
readonly operationId: string;
|
|
3683
|
+
/** The op making the change, stamped on Gate-3 receipts as `producedBy.opId`. */
|
|
3684
|
+
readonly opId: string;
|
|
3685
|
+
/** The caller's actual context. Recorded as-is; explicit authority never rewrites it. */
|
|
3686
|
+
readonly executionContext: ExecutionContext;
|
|
3687
|
+
readonly resolveBundleShortId?: ResolveBundleShortId;
|
|
3688
|
+
readonly delegate?: ExplicitReviewDelegate;
|
|
3689
|
+
readonly writerAuthority?: WriterAuthority;
|
|
3690
|
+
readonly resolvePromotionPosture?: ResolvePromotionPosture;
|
|
3691
|
+
readonly resolveTrustPriors?: () => TrustPriorTable | undefined;
|
|
3692
|
+
readonly now?: () => number;
|
|
3693
|
+
readonly delegateTimeoutMs?: number;
|
|
3694
|
+
}
|
|
3695
|
+
type ExplicitReviewResult = {
|
|
3696
|
+
readonly outcome: 'applied';
|
|
3697
|
+
readonly verb: KnowledgeReviewVerb;
|
|
3698
|
+
readonly changeId: string;
|
|
3699
|
+
/** The records the change added, confirmed or tombstoned, read back after the write. */
|
|
3700
|
+
readonly recordIds: readonly string[];
|
|
3701
|
+
readonly commitReceipt?: CommitReceipt;
|
|
3702
|
+
readonly forgetReceipt?: ForgetReceiptV1;
|
|
3703
|
+
} | {
|
|
3704
|
+
readonly outcome: 'target-not-found';
|
|
3705
|
+
readonly verb: KnowledgeReviewVerb;
|
|
3706
|
+
readonly changeId: string;
|
|
3707
|
+
readonly target: KnowledgeTargetRef;
|
|
3708
|
+
} | {
|
|
3709
|
+
readonly outcome: 'policy-materialize-refused';
|
|
3710
|
+
readonly verb: KnowledgeReviewVerb;
|
|
3711
|
+
readonly changeId: string;
|
|
3712
|
+
};
|
|
3713
|
+
/**
|
|
3714
|
+
* Apply an explicit knowledge change in the call (432-06, D-04/D-05/D-09/D-11).
|
|
3715
|
+
*
|
|
3716
|
+
* No envelope is written, claimed or reloaded. A holder commits with its own authority, a free lease is acquired and released, and a live holder is
|
|
3717
|
+
* handed the same validated request and identity, bounded, and is never stolen from. Retrying
|
|
3718
|
+
* the same `operationId` lands nothing twice and answers the same record ids.
|
|
3719
|
+
*/
|
|
3720
|
+
declare function applyExplicitReview(input: ApplyExplicitReviewInput): Promise<ExplicitReviewResult>;
|
|
3721
|
+
|
|
3722
|
+
/** The one directory name receipts live under, beneath the agent-qa runtime root. */
|
|
3723
|
+
declare const DRAFT_RECEIPTS_DIR_NAME = "draft-receipts";
|
|
3724
|
+
/** Thrown when a content digest could not be safely turned into a filename. */
|
|
3725
|
+
declare class DraftReceiptDigestError extends Error {
|
|
3726
|
+
readonly contentDigest: string;
|
|
3727
|
+
constructor(contentDigest: string);
|
|
3728
|
+
}
|
|
3729
|
+
/** Thrown when a persisted receipt was written under a different schema version. */
|
|
3730
|
+
declare class DraftReceiptSchemaVersionError extends Error {
|
|
3731
|
+
readonly path: string;
|
|
3732
|
+
readonly foundVersion: unknown;
|
|
3733
|
+
constructor(path: string, foundVersion: unknown);
|
|
3734
|
+
}
|
|
3735
|
+
interface DraftReceiptsStoreOptions {
|
|
3736
|
+
/**
|
|
3737
|
+
* Where receipts are durable — `<configDir>/.agent-qa`. A FACTORY on the `createProposalsInbox`
|
|
3738
|
+
* precedent: the CLI resolves its root asynchronously and per call, so closing over one resolved
|
|
3739
|
+
* value would cache a fact this module does not own.
|
|
3740
|
+
*/
|
|
3741
|
+
readonly resolveAgentQaRoot: () => Promise<string> | string;
|
|
3742
|
+
}
|
|
3743
|
+
interface DraftReceiptsStore {
|
|
3744
|
+
/** Persist a receipt under its own `draftRef.contentDigest`. Create-on-first-write. */
|
|
3745
|
+
put(receipt: DraftReceipt): Promise<void>;
|
|
3746
|
+
/** The receipt for these draft bytes, or `undefined` if none was ever written. */
|
|
3747
|
+
get(contentDigest: string): Promise<DraftReceipt | undefined>;
|
|
3748
|
+
/** Every stored receipt, ordered by digest so two calls render the same table. */
|
|
3749
|
+
list(): Promise<DraftReceipt[]>;
|
|
3750
|
+
}
|
|
3751
|
+
declare function draftReceiptsDir(agentQaRoot: string): string;
|
|
3752
|
+
/**
|
|
3753
|
+
* Bind the three receipt verbs over one agent-qa runtime root.
|
|
3754
|
+
*
|
|
3755
|
+
* Nothing opens here and nothing is created until the first write, which is what lets a
|
|
3756
|
+
* composition root bind this unconditionally without deciding whether a project has ever
|
|
3757
|
+
* evaluated a draft — an absent directory and an empty store are the same answer.
|
|
3758
|
+
*/
|
|
3759
|
+
declare function createDraftReceiptsStore(options: DraftReceiptsStoreOptions): DraftReceiptsStore;
|
|
3760
|
+
|
|
3761
|
+
type RollbackKind = 'job' | 'campaign';
|
|
3762
|
+
interface RollbackCounterEvent {
|
|
3763
|
+
recordId: RecordId;
|
|
3764
|
+
evidenceToken: string;
|
|
3765
|
+
curationJobId: string;
|
|
3766
|
+
type: 'confirmed' | 'deprecated' | 'superseded' | 'promoted';
|
|
3767
|
+
}
|
|
3768
|
+
type RollbackPlannedEffect = {
|
|
3769
|
+
kind: 'deprecate-bundle';
|
|
3770
|
+
product: string;
|
|
3771
|
+
recordId: RecordId;
|
|
3772
|
+
} | {
|
|
3773
|
+
kind: 'retract-counter' | 'retract-window-close' | 'retract-promotion';
|
|
3774
|
+
product: string;
|
|
3775
|
+
recordId: RecordId;
|
|
3776
|
+
eventKey: string;
|
|
3777
|
+
evidenceToken: string;
|
|
3778
|
+
curationJobId: string;
|
|
3779
|
+
};
|
|
3780
|
+
interface RollbackBundleTarget {
|
|
3781
|
+
product: string;
|
|
3782
|
+
recordId: RecordId;
|
|
3783
|
+
}
|
|
3784
|
+
interface RollbackAffectedSet {
|
|
3785
|
+
operationId: string;
|
|
3786
|
+
/** Compatibility summary; plannedEffects is the product-qualified mutation authority. */
|
|
3787
|
+
mintedBundleIds: RecordId[];
|
|
3788
|
+
counterEvents: RollbackCounterEvent[];
|
|
3789
|
+
plannedEffects: RollbackPlannedEffect[];
|
|
3790
|
+
/** Projection healing targets; these never require a new rollback ordinal on their own. */
|
|
3791
|
+
projectionTargets: RollbackBundleTarget[];
|
|
3792
|
+
products: string[];
|
|
3793
|
+
}
|
|
3794
|
+
interface RollbackReport {
|
|
3795
|
+
receiptId: string;
|
|
3796
|
+
inverseCount: number;
|
|
3797
|
+
restoredVictims: RecordId[];
|
|
3798
|
+
deprecatedBundles: RecordId[];
|
|
3799
|
+
/** Bundles whose surviving promoted events were cascade-retracted after support loss. */
|
|
3800
|
+
retractedPromotions: RecordId[];
|
|
3801
|
+
/** Auditable exact resolution that drove inverse construction. */
|
|
3802
|
+
affected: RollbackAffectedSet;
|
|
3803
|
+
}
|
|
3804
|
+
type RollbackMutationKind = 'append' | 'projection';
|
|
3805
|
+
interface RollbackHooks {
|
|
3806
|
+
/** Test/chaos seam after canonical resolution and causal preflight, before the first write. */
|
|
3807
|
+
afterResolution?: () => void;
|
|
3808
|
+
/** Test/chaos seam after one actual append or projection mutation completes. */
|
|
3809
|
+
afterMutation?: (kind: RollbackMutationKind, recordId: RecordId) => void;
|
|
3810
|
+
}
|
|
3811
|
+
interface RollbackBaseInput {
|
|
3812
|
+
knowledgeRoot: string;
|
|
3813
|
+
resolvedAtOrdinal: number;
|
|
3814
|
+
/** Governed maintenance callers fence this exact lease at every mutation boundary. */
|
|
3815
|
+
writerAuthority?: WriterLeaseAuthority;
|
|
3816
|
+
/** Preview fingerprint revalidated by the mutator immediately before its first write. */
|
|
3817
|
+
expectedAffectedSetFingerprint?: string;
|
|
3818
|
+
hooks?: RollbackHooks;
|
|
3819
|
+
}
|
|
3820
|
+
interface RollbackCurationJobInput extends RollbackBaseInput {
|
|
3821
|
+
curationJobId: string;
|
|
3822
|
+
}
|
|
3823
|
+
interface RollbackCampaignInput extends RollbackBaseInput {
|
|
3824
|
+
fromOrdinal?: number;
|
|
3825
|
+
toOrdinal?: number;
|
|
3826
|
+
anchorClusterKey?: string;
|
|
3827
|
+
originClass?: OriginClass;
|
|
3828
|
+
}
|
|
3829
|
+
type ResolveRollbackAffectedSetInput = RollbackCurationJobInput | RollbackCampaignInput;
|
|
3830
|
+
/**
|
|
3831
|
+
* CR-02: a rollback must never attest success at a resolution ordinal that is powerless to
|
|
3832
|
+
* change lifecycle status. At equal buildOrdinal the trust fold's fixed STATUS_PRECEDENCE keeps
|
|
3833
|
+
* active above deprecated, and an older event can never replace a newer status, so a
|
|
3834
|
+
* non-strictly-later resolvedAtOrdinal cannot causally invert a minted bundle.
|
|
3835
|
+
*/
|
|
3836
|
+
declare class RollbackCausalityError extends Error {
|
|
3837
|
+
readonly offendingRecordIds: RecordId[];
|
|
3838
|
+
readonly minimumRequiredOrdinal: number;
|
|
3839
|
+
constructor(offendingRecordIds: RecordId[], minimumRequiredOrdinal: number);
|
|
3840
|
+
}
|
|
3841
|
+
declare class RollbackPlanChangedError extends Error {
|
|
3842
|
+
readonly name = "RollbackPlanChangedError";
|
|
3843
|
+
readonly expectedFingerprint: string;
|
|
3844
|
+
readonly actualFingerprint: string;
|
|
3845
|
+
constructor(expectedFingerprint: string, actualFingerprint: string);
|
|
3846
|
+
}
|
|
3847
|
+
/** Stable identity for one selector and its product-qualified source-effect universe. */
|
|
3848
|
+
declare function rollbackReceiptId(kind: RollbackKind, keys: Readonly<Record<string, unknown>>, effectKeys?: readonly string[]): string;
|
|
3849
|
+
declare function rollbackAffectedSetFingerprint(affected: RollbackAffectedSet): string;
|
|
3850
|
+
/** Resolve the canonical rollback preview without appending inverse events or touching indexes. */
|
|
3851
|
+
declare function resolveRollbackAffectedSet(input: ResolveRollbackAffectedSetInput): RollbackAffectedSet;
|
|
3852
|
+
/** Resolve and append the ratified inverse map for one curation job. */
|
|
3853
|
+
declare function rollbackCurationJob(input: RollbackCurationJobInput): RollbackReport;
|
|
3854
|
+
/** Resolve and append the inverse map for an AND-composed provenance campaign. */
|
|
3855
|
+
declare function rollbackCampaign(input: RollbackCampaignInput): RollbackReport;
|
|
3856
|
+
|
|
3857
|
+
/**
|
|
3858
|
+
* 378-17 canonical mutable-target order, additively extended by 379 D-03:
|
|
3859
|
+
* record, provenance, outcomes, measurements, relations, then manifest.
|
|
3860
|
+
*/
|
|
3861
|
+
declare const MUTABLE_BUNDLE_TARGETS: readonly ["record.md", "provenance.json", "evidence/outcomes.jsonl", "evidence/measurements.json", "evidence/gates.jsonl", "relations.json", "manifest.json"];
|
|
3862
|
+
|
|
3863
|
+
type MarkTriage = {
|
|
3864
|
+
kind: 'quarantined';
|
|
3865
|
+
class: MarkQuarantineClass;
|
|
3866
|
+
producer: string;
|
|
3867
|
+
} | {
|
|
3868
|
+
kind: 'learnable';
|
|
3869
|
+
rootCause?: {
|
|
3870
|
+
class: VerdictClass;
|
|
3871
|
+
producer: string;
|
|
3872
|
+
};
|
|
3873
|
+
};
|
|
3874
|
+
declare function triageMark(member: PerTestOutcome): MarkTriage;
|
|
3875
|
+
declare function servedIdsOn(step: StepEvidence): string[];
|
|
3876
|
+
declare function procedureReadOn(member: PerTestOutcome, stepIndex: number): string | undefined;
|
|
3877
|
+
declare function assertionDrift(member: PerTestOutcome, step: StepEvidence): boolean;
|
|
3878
|
+
interface ServedRecordFacts {
|
|
3879
|
+
recordId: string;
|
|
3880
|
+
kind: BundleKind;
|
|
3881
|
+
subtype?: FactSubtype;
|
|
3882
|
+
anchors: Anchor[];
|
|
3883
|
+
scope: ScopeKey;
|
|
3884
|
+
summary: string;
|
|
3885
|
+
distilledEvidenceRef: ArtifactRef;
|
|
3886
|
+
originStage: OriginStage;
|
|
3887
|
+
}
|
|
3888
|
+
type FixSelection = {
|
|
3889
|
+
fix: 'fact' | 'caution';
|
|
3890
|
+
target: ServedRecordFacts;
|
|
3891
|
+
} | {
|
|
3892
|
+
fix: 'procedure-hint';
|
|
3893
|
+
target: ServedRecordFacts;
|
|
3894
|
+
} | {
|
|
3895
|
+
fix: 'test-edit';
|
|
3896
|
+
} | {
|
|
3897
|
+
fix: 'none';
|
|
3898
|
+
checked: NoDraftableFixChecked;
|
|
3899
|
+
};
|
|
3900
|
+
declare function selectFixKind(input: {
|
|
3901
|
+
kind: Mark;
|
|
3902
|
+
member: PerTestOutcome;
|
|
3903
|
+
step: StepEvidence;
|
|
3904
|
+
stepIndex: number;
|
|
3905
|
+
served: ServedRecordFacts[];
|
|
3906
|
+
procedure?: ServedRecordFacts;
|
|
3907
|
+
}): FixSelection;
|
|
3908
|
+
interface ApplyFeedbackInput {
|
|
3909
|
+
mark: Pick<MarkReceipt, 'markId' | 'runId' | 'runSlug' | 'testIndex' | 'testId' | 'stepIndex' | 'kind' | 'note'>;
|
|
3910
|
+
handoff: CompletedRunHandoff;
|
|
3911
|
+
resolvedStepIndex: number;
|
|
3912
|
+
served: ServedRecordFacts[];
|
|
3913
|
+
procedure?: ServedRecordFacts;
|
|
3914
|
+
testRef?: string;
|
|
3915
|
+
}
|
|
3916
|
+
declare function applyFeedback(input: ApplyFeedbackInput): ImprovementPlan;
|
|
3917
|
+
|
|
3918
|
+
interface FloorProseInput {
|
|
3919
|
+
kind: Mark;
|
|
3920
|
+
fix: 'fact' | 'caution' | 'procedure-hint';
|
|
3921
|
+
stepText: string;
|
|
3922
|
+
verifierReasoning: string;
|
|
3923
|
+
servedSummary?: string;
|
|
3924
|
+
note?: string;
|
|
3925
|
+
}
|
|
3926
|
+
declare function floorProse(input: FloorProseInput): {
|
|
3927
|
+
summary: string;
|
|
3928
|
+
body: string;
|
|
3929
|
+
};
|
|
3930
|
+
|
|
3931
|
+
interface AppendMarkEvidenceInput {
|
|
3932
|
+
knowledgeRoot: string;
|
|
3933
|
+
executionContext: ExecutionContext;
|
|
3934
|
+
lease: {
|
|
3935
|
+
leaseId: string;
|
|
3936
|
+
epoch: number;
|
|
3937
|
+
};
|
|
3938
|
+
mark: Pick<MarkReceipt, 'markId' | 'runId' | 'kind'>;
|
|
3939
|
+
servedRecordIds: readonly string[];
|
|
3940
|
+
/** Historical observation hashes require the original member/step coordinates. */
|
|
3941
|
+
handoff?: CompletedRunHandoff;
|
|
3942
|
+
/** Host-derived chainJobIdsForRun(runId, idSource).curateMemory; never guessed here. */
|
|
3943
|
+
curationJobIds?: readonly string[];
|
|
3944
|
+
/** Resuming one mark reports its complete logical effect, including already durable events. */
|
|
3945
|
+
includeAlreadyAppended?: boolean;
|
|
3946
|
+
}
|
|
3947
|
+
declare function appendMarkEvidence(input: AppendMarkEvidenceInput): Promise<AppendMarkEvidenceOutcome>;
|
|
3948
|
+
|
|
3949
|
+
declare class PolicyTextRefusedError extends Error {
|
|
3950
|
+
constructor();
|
|
3951
|
+
}
|
|
3952
|
+
declare function policySectionMarkers(recordId: string): {
|
|
3953
|
+
open: string;
|
|
3954
|
+
close: string;
|
|
3955
|
+
};
|
|
3956
|
+
declare function policyShelfPath(knowledgeRoot: string, scope: string): string;
|
|
3957
|
+
interface MaterializePolicyInput {
|
|
3958
|
+
writerAuthority: CurrentWriterAuthority;
|
|
3959
|
+
knowledgeRoot: string;
|
|
3960
|
+
recordId: string;
|
|
3961
|
+
scope: string;
|
|
3962
|
+
ruleText: string;
|
|
3963
|
+
title?: string;
|
|
3964
|
+
/** Recovery validates a previously authored section and must never recreate a missing one. */
|
|
3965
|
+
existingOnly?: boolean;
|
|
3966
|
+
}
|
|
3967
|
+
type MaterializeOutcome = {
|
|
3968
|
+
kind: 'written' | 'unchanged';
|
|
3969
|
+
relPath: string;
|
|
3970
|
+
sectionBytes: number;
|
|
3971
|
+
};
|
|
3972
|
+
/**
|
|
3973
|
+
* The authored shelf is append-only under the caller's writer lease. An existing section ID
|
|
3974
|
+
* always wins, including when its human-edited body differs. Never rewrite that body.
|
|
3975
|
+
* commitArtifacts governs binary bundle artifacts, not policy text or git commits.
|
|
3976
|
+
* The authored text is written as given; no detector scans it (Phase 441, D-15).
|
|
3977
|
+
*/
|
|
3978
|
+
declare function materializePolicy(input: MaterializePolicyInput): MaterializeOutcome;
|
|
3979
|
+
|
|
3980
|
+
type LocalKnowledgeStore = KnowledgePort;
|
|
3981
|
+
type LocalKnowledgeReader = KnowledgeHintReader;
|
|
3982
|
+
|
|
3983
|
+
export { ADDRESSING_LEDGER_BUSY_TIMEOUT_MS, ADDRESSING_LEDGER_DB_FILE, ADDRESSING_LEDGER_USER_VERSION, APPLY_DELEGATE_TIMEOUT_MS, ARTIFACT_RUN_CAP_BYTES, ARTIFACT_STEP_CAP_BYTES, AUTHORED_CHECKPOINT_SCHEMA_VERSION, type AcquireEmbedderOptions, type AcquireEmbedderOutcome, type AcquireWriterLeaseOptions, type AcquireWriterLeaseOutcome, type AddressingLedger, AddressingLedgerSchemaVersionError, type AppendMarkEvidenceInput, AppendMarkEvidenceOutcome, type AppendOutcome, ApplyDelegateTimeoutError, ApplyDelegateUnavailableError, type ApplyExplicitReviewInput, type ApplyFeedbackInput, type ApplyIndexDeltaForBundleInput, type ApplyRunOutcomesResult, type ArtifactCopyInput, type ArtifactCopyResult, type AuthorOutcome, type AuthoredCheckpoint, type AuthoredDeltaCheckpoint, BLAST_RADIUS_MAX_SUPERSEDES_PER_ANCHOR_PER_DRAIN, type BuildCurationCandidateAddressFieldsInput, type BundleProvenanceInput, type BundleStoreConfig, CHANNEL_1_SERVING_LEG, CHANNEL_3_CAUTION_LEG, CITED_ID_INTEGRITY_CONDITIONS, CLAIMED_SUBDIR, COMMIT_INTENT_SCHEMA_VERSION, CURATION_JOB_STATE_SCHEMA_VERSION, CURATION_QUEUE_SCHEMA_VERSION, type CanonicalBundleStateDigests, type CitedIdIntegrityCondition, type ClaimNextJobOptions, type ClaimNextJobOutcome, type ClaimedCurationJob, type CommitCurationDependencies, type CommitCurationJob, type CommitCurationOutcome, type CopiedArtifact, CorruptEpochStateError, type CorruptEpochStateReason, type CountRemainingCurationWorkOptions, type CreateLocalKnowledgeStoreConfig, type CurationArtifactDescriptor, type CurationArtifactRole, type CurationCandidateAddressFields, type CurationCandidateArtifact, type CurationCandidatePayload, type CurationCandidateProjection, type CurationDrainLifecycleEvent, type CurationEnqueueRefusalReason, type CurationJobLifecycle, type CurationJobState, type CurationJobView, type CurationProjectionArtifactSource, type CurationQuarantineReason, type CurationRemainingWork, type CuratorAuthor, type CurrentWriterAuthority, type CurrentWriterAuthorityHooks, DRAFT_RECEIPTS_DIR_NAME, DRAIN_BUDGET_MS, type DeferReason, type DiscoverEmbedderWorkerOptions, type DisposeDeltaInput, type DispositionCandidateContext, type DispositionDrainState, type DispositionOutcome, type DispositionProfile, DraftReceiptDigestError, DraftReceiptSchemaVersionError, type DraftReceiptsStore, type DraftReceiptsStoreOptions, type DrainFailure, type DrainFailureStage, type DrainNoop, type DrainOptions, type DrainPromotionOutcome, type DrainReport, type DrainableCurationWork, EMBED_CRASH_VECTORLESS_THRESHOLD, ENTITY_INDEX_DB_FILE, ENTITY_INDEX_SWEEP_INTERVAL_MS, ENTITY_INDEX_USER_VERSION, EPOCH_FILE, type EmbedCacheLeg, type EmbedCacheLookup, type EmbedCacheMode, type EmbedCachePut, type EmbedCacheWrapperOptions, type EmbedderAxis, EmbedderPort, type EmbedderProbes, type EmbedderRung, EmbedderWorkerIncarnationVerdict, type EmbedderWorkerPolicy, EmbedderWorkerRegistration, type EmptyDeltaCause, type EnqueueCurationCandidateProjectionOptions, type EnqueueCurationCandidateProjectionOutcome, type EntityAddress, type EntityIndexHandle, EntityIndexSchemaVersionError, type EntityIndexSweepReport, type EntitySighting, type EntitySightingSource, type ExplicitReviewDelegate, type ExplicitReviewDelegation, type ExplicitReviewRequest, type ExplicitReviewResult, type ExtractStepAnchors, FORGET_SCRUBBED_PROJECTIONS, type FailureRecurrence, type FingerprintRecurrence, type FingerprintWindowIdentity, type FingerprintWindowRow, type FixSelection, FloorAssetLoadError, type FloorAssetLoadErrorCode, type FloorAssetLoadOptions, type FloorAssets, FloorEmbeddingError, type FloorEmbeddingErrorCode, type FloorProseInput, type FoldRunOutcomesOptions, type FoldRunOutcomesReport, type FoldSuiteFingerprintsOptions, GC_SUPERSEDED_RETAIN_K, type GateHorizon, type GcPassReport, type GcSummary, type HeartbeatLeaseOutcome, type IndexAxis, IndexFace, IndexReaderConnection, type InspectDrainableCurationWorkOptions, JOBS_SUBDIR, KnowledgeCommitError, KnowledgePromotionError, type KnowledgePromotionErrorReason, KnowledgeReader, KnowledgeStoreNotImplementedError, KnowledgeUnsupportedDeltaError, LAST_OUTCOMES_LIMIT, LEASE_FILE, LEASE_GUARD_DIR, LEASE_HEARTBEAT_TTL_MS, type LeaseOperationOptions, LoadedBundle, type LocalKnowledgeReader, type LocalKnowledgeStore, MEASUREMENTS_REL_PATH, MODEL_CACHE_DIR_ENV_VAR, MUTABLE_BUNDLE_TARGETS, MUTATION_LOCK_BUSY_TIMEOUT_MS, MUTATION_LOCK_TAKEOVER_MS, type MaintenanceBudget, type MaintenanceOperations, type MaintenanceSkipReason, type MaintenanceTailFailure, type MaintenanceTailResult, type MalformedClaimedCurationJob, MarkPlanIntegrityError, type MarkTriage, type MaterializeOutcome, type MaterializePolicyInput, type MigrationOutcome, NativeEmbeddingDimensionError, NativeEmbeddingModuleLoadError, type NeighborRecord, type OpenAddressingLedgerOptions, type OpenEntityIndexOptions, PAYLOAD_BENEFITS, PAYLOAD_STATE_VALIDITIES, PURGE_RECEIPT_SCHEMA_VERSION, type PersistAuthoredCheckpointOptions, type PersistAuthoredCheckpointOutcome, PolicyTextRefusedError, type ProcedureDispositionEvidence, type ProjectRunOutcomesOptions, type PromotionOutcomeReport, type PublishBundleInput, type PublishBundleOutcome, type PurgeAffectedSet, PurgeChronologyRequiredError, PurgeCompletionVerificationError, PurgeQueueIdentityError, type PurgeReceipt, PurgeReceiptSchema, type PurgeRecordInput, type PurgeRecordOutcome, PurgeTargetChangedError, PurgeTargetIntegrityError, QUARANTINE_MANUAL_ENTRY_CLASS, QUARANTINE_MANUAL_ENTRY_FINGERPRINT, QUARANTINE_WINDOW_ORDINALS, QUEUED_SUBDIR, QUEUE_DIR, QUEUE_MAX_EMITS_PER_RUN, QUEUE_MAX_JOBS_PER_SCOPE, QuarantineAppendOutcome, type QuarantineClaimedOptions, type QuarantineDetectionOptions, QuarantineDetectionSighting, type QuarantineFoldOutcome, QuarantineIdentityRefusedError, type QuarantineOperationsOptions, type QueuedCanaryPayloadRead, RESOLVER_CANDIDATE_K, RESOLVER_FUSED_SCORE_NORMALIZER, RESOLVER_LEG_WEIGHT_DENSE, RESOLVER_LEG_WEIGHT_LEXICAL, RESOLVER_LEXICAL_MIN_BM25, RESOLVER_STRONG_HIT_MARGIN, RESOLVER_STRONG_HIT_MIN_SCORE, RUN_OUTCOMES_PROJECTION_VERSION, type ReadCurationCandidatePayloadOutcome, type ReadCurationEffectsOptions, type ReadJobStateOutcome, type ReadWriterLeaseOutcome, type RebuildIndexHooks, type RebuildIndexOptions, type RebuildMutationFamily, type RebuildReport, RebuildRequest, type RebuildRunOutcomesOptions, type RebuildRunOutcomesReport, type ReconcileRunOutcomesProjectionOptions, type ReconcileRunOutcomesProjectionResult, RefusedQuarantineLine, type RelationIntent, type ReleaseLeaseOutcome, type RenderBundlePartsInput, type RenderedBundlePart, type RequeueClaimedOptions, type ResolveBundleShortId, type ResolveEmbedderCapabilityOptions, type ResolveEntityRefDeps, type ResolveRetrievalRungOptions, type ResolveRollbackAffectedSetInput, type RetrievalQuery, type RetrievalQueryInput, type RetrieveOptions, type RetrieveResult, type ReviewChangeRequest, ReviewTargetVanishedError, type RollbackAffectedSet, type RollbackCampaignInput, RollbackCausalityError, type RollbackCounterEvent, type RollbackCurationJobInput, type RollbackKind, RollbackPlanChangedError, type RollbackPlannedEffect, type RollbackReport, type RunKnowledgeGcHooks, type RunKnowledgeGcInput, type RunMaintenanceTailOptions, type RunOutcomeFailureKey, type RunOutcomeTestDelta, type RunOutcomesProjection, SEARCH_BEFORE_CREATE_MAX_QUERIES, SERVING_TRACE_LEGS, SUITE_FINGERPRINTS_TABLE, type ServedRecordFacts, type SetActiveEmbeddingProfileOptions, type SkippedArtifact, type SuiteFingerprintIndex, type SuiteFingerprintIndexOptions, type SuiteFingerprintTestDelta, type SuiteFingerprintsProjection, type TargetRename, type TestOutcomeEntry, type TestOutcomeHistory, type TestOutcomeIdentity, type UnreclaimableMutationLockOwner, UserDeltaCitationIntegrityError, VecCapability, WRITER_AUTHORITY_DB_FILE, type WorkerDiscoveryResult, type WriteJobStateOptions, WriterAuthorityLostError, type WriterAuthorityLostReason, type WriterLease, type WriterLeaseAuthority, type WriterLeaseFreshness, type WriterPassReport, acquireEmbedder, acquireWriterLease, appendGateReceipt, appendMarkEvidence, appendMeasurementObservation, appendOutcomeEvent, appendPromotionReceipt, appendRelation, applyExplicitReview, applyFeedback, applyIndexDeltaForBundle, applyRunOutcomes, applySuiteFingerprints, assertionDrift, authoredCheckpointSchema, buildCurationCandidateAddressFields, buildRetrievalQuery, candidateContentAddress, claimNextJob, claimedCandidateDir, claimedLeaseDir, claimedRoot, commitCurationDelta, copyArtifacts, countPendingCurationJobs, countRemainingCurationWork, createDraftReceiptsStore, createFloorEmbedder, createLocalKnowledgeStore, createMemorySightingSource, createNativeEmbedder, createQuarantineOperations, createSuiteFingerprintIndex, curationArtifactDescriptorSchema, curationArtifactRoleSchema, curationCandidatePayloadSchema, curationCandidateProjectionSchema, curationJobStateSchema, deriveIndexRowFromBundle, deriveWriterLeaseFreshness, describeAllEntities, discoverEmbedderWorker, disposeDelta, draftReceiptsDir, drainQueue, dropEmbedCacheForModel, embedPendingEntities, enqueueCurationCandidate, enqueueCurationCandidateProjection, ensureEmbedCacheTable, entityIndexDbPath, failureRecurrence, fingerprintRecurrence, floorProse, foldCurationSnapshot, foldRetrievalRung, foldRunOutcomes, foldSuiteFingerprints, getCachedEmbedding, getEntityDescriptor, guardPurgeReceipt, heartbeatLease, inspectDrainableCurationWork, isLeaseStale, jobStatePath, jobsRoot, listClaimedLeases, listQueuedCandidates, listTestsInFile, loadFloorAssets, materializePolicy, openAddressingLedger, openEntityIndex, parseAuthoredCheckpoint, persistAuthoredCheckpoint, policySectionMarkers, policyShelfPath, priorBuildOutcome, procedureReadOn, projectRunOutcomes, publishBundle as publishBundleForTest, purgeAffectedSetFingerprint, purgeReceiptSchema, purgeRecord, putCachedEmbedding, quarantineClaimed, queueRoot, queueStagingRoot, queuedCandidateDir, queuedRoot, readCanonicalBundleStateDigests, readCurationCandidatePayload, readCurationEffects, readFingerprintWindow, readJobState, readLatestBuildOrdinal, readQueuedCanaryPayload, readRebuildRequest, readTestOutcomeHistory, readWriterLease, rebuildEntityIndex, rebuildIndex, rebuildRunOutcomes, reconcileRunOutcomesProjection, refreshEntity, refreshWriterLeaseAuthority, releaseLease, renderBundleParts, requeueClaimed, resetEmbedderCapability, resolveDispositionProfile, resolveEmbedderCapability, resolveEntityRef, resolveModelCacheDir, resolveProcessIncarnation, resolvePurgeAffectedSet, resolveRetrievalRung, resolveRollbackAffectedSet, retrieve, rollbackAffectedSetFingerprint, rollbackCampaign, rollbackCurationJob, rollbackReceiptId, runKnowledgeGc, runMaintenanceTail, selectFixKind, servedIdsOn, setActiveEmbeddingProfile, sightEntity, sliceAuthoredCheckpoint, suiteFingerprintDeltas, sweepEntityIndex, triageMark, verifyEmbedderWorkerIncarnation, widenAuthoredDeltaCheckpoint, withCurrentWriterAuthority, wrapEmbedderWithCache, writeJobState, writeMeasurementBaseline };
|