/** * Storage layout of the published graph assessment (T12348). * * The assessment used to be ONE `_nexus_meta` JSON value holding every * retained unresolved/unmodeled reference with its full evidence — 472 MB on * this repository, 647k references against a 3.75 MB remainder. Every reader * paid to parse and validate all of it: `cleo nexus status` took ~10 s and * returned a 472 MB envelope, and every analysis re-read it before starting. * * The summary (`graph_assessment`) now carries everything except the * reference list, plus `referenceCount`; the list lives under * `graph_assessment_references` and is read only when asked for. Both are * written in the publishing transaction, so they always describe the same * generation. A historical value with inline `references` stays readable. * * The list is stored gzip-compressed (a BLOB), because every publication * rewrites it: 453 MB of JSON is 116k pages written to the WAL and 116k more * at checkpoint — measured at 0.6 ms per page write on this repository's FUSE * mount, most of a 49-minute publication. At gzip level 1 it is 28 MB, costs * ~0.6 s to compress and ~0.55 s to inflate. A historical plain-text list is * still read as stored. * * The list is written one reference per line, in gzip members of a few * thousand references (`@cleocode/nexus/reference-spool`, which the pipeline * streams into during resolution — T13656), and read back line by line * (T13326). Building it as ONE `JSON.stringify` string failed outright on a * 5 357-file repository: 846 151 references exceed V8's maximum string length * (2^29 - 24 characters), so publication died with "Invalid string length" * after every other phase had finished. The text is still one valid JSON * array, so a reader that parses it whole keeps working for lists that fit. * * Code placed in `packages/core/` per Package-Boundary Check — verified against AGENTS.md. * * @task T12348 * @module nexus/assessment-store */ import type { GraphIndexAssessment, GraphIndexReferenceReport, GraphStoredReferences } from '@cleocode/contracts'; import type { NodeSQLiteDatabase } from 'drizzle-orm/node-sqlite'; /** `_nexus_meta` key of the assessment summary. */ export declare const ASSESSMENT_KEY = "graph_assessment"; /** `_nexus_meta` key of the separately stored reference list. */ export declare const ASSESSMENT_REFERENCES_KEY = "graph_assessment_references"; /** * Encode a reference list for storage under {@link ASSESSMENT_REFERENCES_KEY}. * * The decompressed text is the JSON array `[\n,\n\n]` — one * reference per line — written as concatenated gzip members, so no string * longer than one member's text is ever built (T13326). * * @param references - The generation's retained references. * @returns gzip-compressed JSON, stored as a BLOB. */ export declare function encodeStoredReferences(references: readonly GraphIndexReferenceReport[]): Uint8Array; /** * Parse a stored reference list into its items without building one string * of the whole list (T13326). * * Reads the line-per-reference form written by {@link encodeStoredReferences}, * and the single-line form written before it — compressed or plain text — * by parsing that one line whole, as it was always read. * * @param value - The raw `_nexus_meta.value` of {@link ASSESSMENT_REFERENCES_KEY}. * @returns The stored items, not yet validated. * @throws When the value is neither text nor a compressed list, or is not a JSON array. * @example * ```ts * const references = z.array(referenceSchema).parse(parseStoredReferences(row.value)); * ``` */ export declare function parseStoredReferences(value: unknown): unknown[]; /** One stored reference, not yet validated, and the UTF-8 size of its JSON. */ export interface StoredReferenceItem { /** The parsed reference. */ item: unknown; /** UTF-8 bytes of the reference's own JSON text. */ bytes: number; } /** * Stream a stored reference list one reference at a time (T13330). * * The compressed list is inflated incrementally and split on line breaks, so * neither the decompressed text nor the parsed list is ever held whole: a * reader that keeps one page holds one page. The single-line form written * before T13326 has no line breaks to split on; it was small enough to be * written whole, so it is parsed whole, as it was always read. * * @param value - The raw `_nexus_meta.value` of {@link ASSESSMENT_REFERENCES_KEY}. * @returns The stored references in stored order. * @throws When the value is neither text nor a compressed list, or is not a JSON array. * @example * ```ts * for await (const { item } of streamStoredReferences(row.value)) count++; * ``` */ export declare function streamStoredReferences(value: unknown): AsyncGenerator; /** * Decode a stored reference list back to its JSON text. * * Accepts the compressed BLOB written since T12348 and the plain JSON text * written before it; anything else is malformed metadata. * * @param value - The raw `_nexus_meta.value` of {@link ASSESSMENT_REFERENCES_KEY}. * @returns The list's JSON text. * @throws When the value is neither text nor a compressed list. * @example * ```ts * const references = JSON.parse(decodeStoredReferences(row.value)); * ``` */ export declare function decodeStoredReferences(value: unknown): string; /** * Return the summary form of an assessment: the reference list removed and * its length recorded as `referenceCount`. * * An assessment without a `references` list is returned unchanged, so a * summary stays a summary and a historical index without references keeps * its shape. * * @param assessment - Full or summary assessment. * @returns The summary a reader of `graph_assessment` observes. * @example * ```ts * const head = assessmentSummary(stagedAssessment); * ``` */ export declare function assessmentSummary(assessment: GraphIndexAssessment): GraphIndexAssessment; /** * Write an assessment inside the caller's transaction. * * - A full assessment writes its summary and replaces the reference list. * - `stored` replaces the list with bytes already in the stored encoding * (T13656); the summary's `referenceCount` must equal `stored.count`. * - A summary that already carries `referenceCount` (for example a provenance * re-record of an unchanged generation) rewrites the summary only, keeping * the stored list of that same generation. * - An assessment with neither removes any stale list. * * Root paths are stored relative to the recorded project root (T12474); read * them back through `readKnowledgeIndexAssessment`, which resolves them * against the live project root. * * @param tx - Graph database handle or open transaction. * @param assessment - Assessment to persist, with absolute in-memory paths. * @param stored - The reference list already encoded, written verbatim. * @returns The summary written, in its in-memory (absolute-path) form. */ export declare function writeAssessment(tx: Pick, assessment: GraphIndexAssessment, stored?: GraphStoredReferences): GraphIndexAssessment; /** * Whether the stored assessment still holds absolute root paths — the form * written before T12474. Extracts only the two root fields. * * @param db - Graph database handle. * @returns `true` when a legacy absolute record should be rewritten portably. */ export declare function storedAssessmentHasAbsoluteRoots(db: Pick): boolean; //# sourceMappingURL=assessment-store.d.ts.map