@nanobpm/urban 0.57.0 → 0.59.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1,66 @@
1
- export {};
1
+ /** Whether the corpus expects a validator to accept or reject an input. */
2
+ export type ConformanceExpectation = "accept" | "reject";
3
+ /** A single corpus entry: an input and the outcome every conformant validator must produce. */
4
+ export interface ConformanceCase {
5
+ /** Unique, stable, human-readable case name. */
6
+ readonly name: string;
7
+ /** The required outcome. */
8
+ readonly expect: ConformanceExpectation;
9
+ /** The (untrusted) value fed to the validator. */
10
+ readonly input: unknown;
11
+ /** Why this case exists / what rule it exercises. */
12
+ readonly note: string;
13
+ }
14
+ /**
15
+ * The minimal validator contract the corpus tests. A conformant validator maps
16
+ * an untrusted value to an accept/reject decision via `{ ok }`.
17
+ * `validateMemoryRecord` (result form) adapts to this shape via
18
+ * {@link fromResultValidator}; the boolean `isMemoryRecord` conforms by wrapping
19
+ * its result — `(input) => ({ ok: isMemoryRecord(input) })`.
20
+ */
21
+ export type ConformanceValidator = (input: unknown) => {
22
+ readonly ok: boolean;
23
+ };
24
+ /** The outcome of running one case through a validator. */
25
+ export interface ConformanceCaseResult {
26
+ readonly case: ConformanceCase;
27
+ readonly expected: ConformanceExpectation;
28
+ readonly actual: ConformanceExpectation;
29
+ readonly passed: boolean;
30
+ }
31
+ /** The aggregate report from {@link runConformance}. */
32
+ export interface ConformanceReport {
33
+ readonly total: number;
34
+ readonly passed: number;
35
+ readonly failed: number;
36
+ readonly results: readonly ConformanceCaseResult[];
37
+ readonly failures: readonly ConformanceCaseResult[];
38
+ }
39
+ /**
40
+ * The full conformance corpus: exhaustive scope × valid/invalid triples, plus
41
+ * structural and vocabulary-drift cases. Deterministic and stable — treat it as
42
+ * the versioned contract fixture both producer and consumer are held to.
43
+ */
44
+ export declare const corpus: readonly ConformanceCase[];
45
+ /** The subset of the corpus that must be accepted. */
46
+ export declare const validFixtures: readonly ConformanceCase[];
47
+ /** The subset of the corpus that must be rejected. */
48
+ export declare const invalidFixtures: readonly ConformanceCase[];
49
+ /**
50
+ * Adapt a `{ ok } | { ... }`-returning validator (like `validateMemoryRecord`)
51
+ * to the {@link ConformanceValidator} shape. Any function returning an object
52
+ * with a boolean `ok` already conforms; this is a typed identity helper.
53
+ */
54
+ export declare function fromResultValidator(validate: (input: unknown) => {
55
+ readonly ok: boolean;
56
+ }): ConformanceValidator;
57
+ /**
58
+ * Run `validate` against the corpus (or a supplied subset) and return a
59
+ * structured report. Pure: does not throw and does not depend on a test runner.
60
+ */
61
+ export declare function runConformance(validate: ConformanceValidator, cases?: readonly ConformanceCase[]): ConformanceReport;
62
+ /**
63
+ * Assert full conformance: throws with a readable summary if any case fails.
64
+ * Consumers can call this in their own test suite to be held to the contract.
65
+ */
66
+ export declare function assertConformance(validate: ConformanceValidator, cases?: readonly ConformanceCase[]): void;
@@ -1 +1,215 @@
1
- export {};
1
+ // Slice S2 (conformance) — the shared conformance corpus + a reusable runner.
2
+ //
3
+ // Published as `@nanobpm/urban/context/conformance`. This subpath IS the
4
+ // contract: BOTH the producer (this repo) and the consumer
5
+ // (`nanobpm/nano-workforce#291`) are held to the SAME corpus, and the
6
+ // adversarial slice (S7) imports the corpus + runner from here directly. It is
7
+ // intentionally self-contained — it does NOT re-export the schema module, so a
8
+ // consumer can import it without pulling the whole schema surface, and the top
9
+ // barrel never sees a duplicate symbol.
10
+ //
11
+ // The runner is a PURE function over a validator callback (no test framework),
12
+ // so any party can point it at their own validator and get a structured report.
13
+ // The `.conformance.ts` sibling wires it into `node:test` for `test:conformance`.
14
+ import { MEMORY_RECORD_SCHEMA_VERSION, SCOPE_LADDER } from "../schema/index.js";
15
+ /**
16
+ * Every (provenance, mode, authority) triple that is VALID by the schema
17
+ * invariants. Instantiated across all scopes below, this covers every
18
+ * scope × provenance × mode combination that a well-formed record can take.
19
+ */
20
+ const VALID_TRIPLES = [
21
+ { provenance: "human", mode: "normative", authority: "hypothesis" },
22
+ { provenance: "human", mode: "normative", authority: "authoritative" },
23
+ { provenance: "human", mode: "empirical", authority: "hypothesis" },
24
+ { provenance: "human", mode: "empirical", authority: "authoritative" },
25
+ { provenance: "agent-retro", mode: "normative", authority: "hypothesis" },
26
+ { provenance: "agent-retro", mode: "empirical", authority: "hypothesis" },
27
+ { provenance: "measured", mode: "empirical", authority: "authoritative" },
28
+ { provenance: "instance", mode: "empirical", authority: "authoritative" },
29
+ ];
30
+ /**
31
+ * Every (provenance, mode, authority) triple that MUST be rejected by the
32
+ * invariants, with the rule it violates. The first two are the headline
33
+ * hypothesis-never-fix invariant (agent-retro can never be authoritative).
34
+ */
35
+ const INVALID_TRIPLES = [
36
+ { provenance: "agent-retro", mode: "normative", authority: "authoritative", why: "hypothesis-never-fix: agent-retro can never be authoritative" },
37
+ { provenance: "agent-retro", mode: "empirical", authority: "authoritative", why: "hypothesis-never-fix: agent-retro can never be authoritative" },
38
+ { provenance: "measured", mode: "empirical", authority: "hypothesis", why: "measured must be authoritative" },
39
+ { provenance: "measured", mode: "normative", authority: "authoritative", why: "measured must be empirical, not normative" },
40
+ { provenance: "instance", mode: "empirical", authority: "hypothesis", why: "instance must be authoritative" },
41
+ { provenance: "instance", mode: "normative", authority: "authoritative", why: "instance must be empirical, not normative" },
42
+ ];
43
+ function baseRecord(scope, triple) {
44
+ return {
45
+ schemaVersion: MEMORY_RECORD_SCHEMA_VERSION,
46
+ id: `rec-${scope}-${triple.provenance}-${triple.mode}-${triple.authority}`,
47
+ scope,
48
+ mode: triple.mode,
49
+ provenance: triple.provenance,
50
+ authority: triple.authority,
51
+ statement: `example ${triple.mode} ${triple.provenance} record at ${scope} scope`,
52
+ createdAt: "2026-01-01T00:00:00.000Z",
53
+ };
54
+ }
55
+ function buildCombinationalCases() {
56
+ const cases = [];
57
+ for (const scope of SCOPE_LADDER) {
58
+ for (const triple of VALID_TRIPLES) {
59
+ cases.push({
60
+ name: `accept ${scope}/${triple.mode}/${triple.provenance}/${triple.authority}`,
61
+ expect: "accept",
62
+ input: baseRecord(scope, triple),
63
+ note: "well-formed record; valid vocabulary + consistent invariants",
64
+ });
65
+ }
66
+ for (const triple of INVALID_TRIPLES) {
67
+ cases.push({
68
+ name: `reject ${scope}/${triple.mode}/${triple.provenance}/${triple.authority}`,
69
+ expect: "reject",
70
+ input: baseRecord(scope, triple),
71
+ note: triple.why,
72
+ });
73
+ }
74
+ }
75
+ return cases;
76
+ }
77
+ /** Structural / vocabulary-drift rejects that are independent of scope. */
78
+ const STRUCTURAL_CASES = [
79
+ { name: "reject non-object (number)", expect: "reject", input: 42, note: "record must be an object" },
80
+ { name: "reject non-object (null)", expect: "reject", input: null, note: "record must be an object" },
81
+ { name: "reject non-object (array)", expect: "reject", input: [], note: "record must be a plain object, not an array" },
82
+ {
83
+ name: "reject unsupported schemaVersion",
84
+ expect: "reject",
85
+ input: { schemaVersion: 2, id: "x", scope: "repo", mode: "empirical", provenance: "human", authority: "authoritative", statement: "s", createdAt: "2026-01-01T00:00:00.000Z" },
86
+ note: "schemaVersion must be exactly 1",
87
+ },
88
+ {
89
+ name: "reject missing schemaVersion",
90
+ expect: "reject",
91
+ input: { id: "x", scope: "repo", mode: "empirical", provenance: "human", authority: "authoritative", statement: "s", createdAt: "2026-01-01T00:00:00.000Z" },
92
+ note: "schemaVersion is required",
93
+ },
94
+ {
95
+ name: "reject missing id",
96
+ expect: "reject",
97
+ input: { schemaVersion: MEMORY_RECORD_SCHEMA_VERSION, scope: "repo", mode: "empirical", provenance: "human", authority: "authoritative", statement: "s", createdAt: "2026-01-01T00:00:00.000Z" },
98
+ note: "id is required",
99
+ },
100
+ {
101
+ name: "reject empty statement",
102
+ expect: "reject",
103
+ input: { schemaVersion: MEMORY_RECORD_SCHEMA_VERSION, id: "x", scope: "repo", mode: "empirical", provenance: "human", authority: "authoritative", statement: "", createdAt: "2026-01-01T00:00:00.000Z" },
104
+ note: "statement must be non-empty",
105
+ },
106
+ {
107
+ name: "reject drifted scope vocabulary",
108
+ expect: "reject",
109
+ input: { schemaVersion: MEMORY_RECORD_SCHEMA_VERSION, id: "x", scope: "galaxy", mode: "empirical", provenance: "human", authority: "authoritative", statement: "s", createdAt: "2026-01-01T00:00:00.000Z" },
110
+ note: "scope must be in the ladder vocabulary",
111
+ },
112
+ {
113
+ name: "reject drifted mode vocabulary",
114
+ expect: "reject",
115
+ input: { schemaVersion: MEMORY_RECORD_SCHEMA_VERSION, id: "x", scope: "repo", mode: "prescriptive", provenance: "human", authority: "authoritative", statement: "s", createdAt: "2026-01-01T00:00:00.000Z" },
116
+ note: "mode must be normative|empirical",
117
+ },
118
+ {
119
+ name: "reject drifted provenance vocabulary",
120
+ expect: "reject",
121
+ input: { schemaVersion: MEMORY_RECORD_SCHEMA_VERSION, id: "x", scope: "repo", mode: "empirical", provenance: "robot", authority: "authoritative", statement: "s", createdAt: "2026-01-01T00:00:00.000Z" },
122
+ note: "provenance must be in the vocabulary",
123
+ },
124
+ {
125
+ name: "reject drifted authority vocabulary",
126
+ expect: "reject",
127
+ input: { schemaVersion: MEMORY_RECORD_SCHEMA_VERSION, id: "x", scope: "repo", mode: "empirical", provenance: "human", authority: "supreme", statement: "s", createdAt: "2026-01-01T00:00:00.000Z" },
128
+ note: "authority must be hypothesis|authoritative",
129
+ },
130
+ {
131
+ name: "reject non-ISO timestamp",
132
+ expect: "reject",
133
+ input: { schemaVersion: MEMORY_RECORD_SCHEMA_VERSION, id: "x", scope: "repo", mode: "empirical", provenance: "human", authority: "authoritative", statement: "s", createdAt: "yesterday" },
134
+ note: "createdAt must be ISO-8601",
135
+ },
136
+ {
137
+ name: "reject wrong-typed id",
138
+ expect: "reject",
139
+ input: { schemaVersion: MEMORY_RECORD_SCHEMA_VERSION, id: 123, scope: "repo", mode: "empirical", provenance: "human", authority: "authoritative", statement: "s", createdAt: "2026-01-01T00:00:00.000Z" },
140
+ note: "id must be a string",
141
+ },
142
+ {
143
+ name: "reject wrong-typed evidence",
144
+ expect: "reject",
145
+ input: { schemaVersion: MEMORY_RECORD_SCHEMA_VERSION, id: "x", scope: "repo", mode: "empirical", provenance: "measured", authority: "authoritative", statement: "s", createdAt: "2026-01-01T00:00:00.000Z", evidence: "not-an-array" },
146
+ note: "evidence, if present, must be a string array",
147
+ },
148
+ {
149
+ name: "accept well-formed measured record with evidence + optionals",
150
+ expect: "accept",
151
+ input: { schemaVersion: MEMORY_RECORD_SCHEMA_VERSION, id: "x", scope: "instance", scopeRef: "elem-7", subject: "latency", mode: "empirical", provenance: "measured", authority: "authoritative", statement: "p99 improved", createdAt: "2026-01-01T00:00:00.000Z", evidence: ["run-1", "run-2"], supersedes: "rec-old" },
152
+ note: "optional fields accepted when well-typed",
153
+ },
154
+ ];
155
+ /**
156
+ * The full conformance corpus: exhaustive scope × valid/invalid triples, plus
157
+ * structural and vocabulary-drift cases. Deterministic and stable — treat it as
158
+ * the versioned contract fixture both producer and consumer are held to.
159
+ */
160
+ export const corpus = [...buildCombinationalCases(), ...STRUCTURAL_CASES];
161
+ /** The subset of the corpus that must be accepted. */
162
+ export const validFixtures = corpus.filter((c) => c.expect === "accept");
163
+ /** The subset of the corpus that must be rejected. */
164
+ export const invalidFixtures = corpus.filter((c) => c.expect === "reject");
165
+ // ---------------------------------------------------------------------------
166
+ // The runner
167
+ // ---------------------------------------------------------------------------
168
+ /**
169
+ * Adapt a `{ ok } | { ... }`-returning validator (like `validateMemoryRecord`)
170
+ * to the {@link ConformanceValidator} shape. Any function returning an object
171
+ * with a boolean `ok` already conforms; this is a typed identity helper.
172
+ */
173
+ export function fromResultValidator(validate) {
174
+ return (input) => ({ ok: validate(input).ok });
175
+ }
176
+ /**
177
+ * Run `validate` against the corpus (or a supplied subset) and return a
178
+ * structured report. Pure: does not throw and does not depend on a test runner.
179
+ */
180
+ export function runConformance(validate, cases = corpus) {
181
+ const results = cases.map((c) => {
182
+ // A validator that throws (even accidentally) must not crash the run: treat
183
+ // a throw as a rejection so the runner stays pure and the doc above holds.
184
+ let ok;
185
+ try {
186
+ ok = validate(c.input).ok;
187
+ }
188
+ catch {
189
+ ok = false;
190
+ }
191
+ const actual = ok ? "accept" : "reject";
192
+ return { case: c, expected: c.expect, actual, passed: actual === c.expect };
193
+ });
194
+ const failures = results.filter((r) => !r.passed);
195
+ return {
196
+ total: results.length,
197
+ passed: results.length - failures.length,
198
+ failed: failures.length,
199
+ results,
200
+ failures,
201
+ };
202
+ }
203
+ /**
204
+ * Assert full conformance: throws with a readable summary if any case fails.
205
+ * Consumers can call this in their own test suite to be held to the contract.
206
+ */
207
+ export function assertConformance(validate, cases = corpus) {
208
+ const report = runConformance(validate, cases);
209
+ if (report.failed > 0) {
210
+ const detail = report.failures
211
+ .map((f) => ` - ${f.case.name}: expected ${f.expected}, got ${f.actual} (${f.case.note})`)
212
+ .join("\n");
213
+ throw new Error(`conformance failed: ${report.failed}/${report.total} case(s):\n${detail}`);
214
+ }
215
+ }
@@ -0,0 +1,52 @@
1
+ // Runnable conformance suite — matched by the pre-declared `test:conformance`
2
+ // glob (src/context/conformance/**/*.conformance.ts). It holds THIS repo's
3
+ // producer validator (`validateMemoryRecord`) to the shared corpus. The consumer
4
+ // (nano-workforce#291) imports the same `corpus` + `runConformance`/
5
+ // `assertConformance` and runs it against its own validator, so both sides prove
6
+ // they agree on the exact same fixtures.
7
+ import { test } from "node:test";
8
+ import assert from "node:assert/strict";
9
+ import { validateMemoryRecord } from "../schema/index.js";
10
+ import { corpus, runConformance, assertConformance, fromResultValidator, validFixtures, invalidFixtures, } from "./index.js";
11
+ const validator = fromResultValidator(validateMemoryRecord);
12
+ test("corpus is non-trivial and partitioned", () => {
13
+ assert.ok(corpus.length >= 50, `expected a substantial corpus, got ${corpus.length}`);
14
+ assert.ok(validFixtures.length > 0);
15
+ assert.ok(invalidFixtures.length > 0);
16
+ assert.equal(validFixtures.length + invalidFixtures.length, corpus.length);
17
+ // Case names must be unique so failures are unambiguous.
18
+ assert.equal(new Set(corpus.map((c) => c.name)).size, corpus.length);
19
+ });
20
+ test("producer validator satisfies the full conformance corpus", () => {
21
+ const report = runConformance(validator);
22
+ assert.equal(report.failed, 0, `failures:\n${report.failures.map((f) => `${f.case.name}: expected ${f.expected}, got ${f.actual}`).join("\n")}`);
23
+ assert.equal(report.passed, report.total);
24
+ });
25
+ test("assertConformance does not throw for the producer validator", () => {
26
+ assert.doesNotThrow(() => assertConformance(validator));
27
+ });
28
+ test("runConformance treats a throwing validator as a rejection instead of crashing", () => {
29
+ const throwing = () => {
30
+ throw new Error("boom");
31
+ };
32
+ // The runner must stay pure: no throw escapes, and every case is scored `reject`.
33
+ let report;
34
+ assert.doesNotThrow(() => {
35
+ report = runConformance(throwing);
36
+ });
37
+ assert.ok(report);
38
+ if (report) {
39
+ assert.equal(report.total, corpus.length);
40
+ // Every case scores `reject`; only the corpus's reject-cases can pass.
41
+ const rejectCount = corpus.filter((c) => c.expect === "reject").length;
42
+ assert.equal(report.passed, rejectCount);
43
+ assert.equal(report.results.every((r) => r.actual === "reject"), true);
44
+ }
45
+ });
46
+ // Per-case granularity: one sub-test per fixture so a regression names the exact case.
47
+ for (const c of corpus) {
48
+ test(`case: ${c.name}`, () => {
49
+ const actual = validator(c.input).ok ? "accept" : "reject";
50
+ assert.equal(actual, c.expect, `${c.name} — ${c.note}`);
51
+ });
52
+ }
@@ -1 +1,135 @@
1
- export {};
1
+ /**
2
+ * The only schema version this module accepts. Records must carry it explicitly
3
+ * so a future producer can bump the shape while old consumers reject-with-reason
4
+ * instead of silently mis-reading a newer record.
5
+ */
6
+ export declare const MEMORY_RECORD_SCHEMA_VERSION: 1;
7
+ export type MemoryRecordSchemaVersion = typeof MEMORY_RECORD_SCHEMA_VERSION;
8
+ /**
9
+ * The scope ladder — the granularity a record is attached to, from the most
10
+ * specific (a single ladder `element`) up to the whole `corpus`. The array
11
+ * order IS the ladder order (specific → general) and is exported so callers can
12
+ * reason about containment without re-deriving it.
13
+ */
14
+ export declare const SCOPE_LADDER: readonly ["element", "instance", "epic", "repo", "corpus"];
15
+ export type MemoryScope = (typeof SCOPE_LADDER)[number];
16
+ /**
17
+ * Whether the record asserts a norm (`normative` — "this is how it should be")
18
+ * or an observation (`empirical` — "this is what was measured/seen").
19
+ */
20
+ export declare const MEMORY_MODES: readonly ["normative", "empirical"];
21
+ export type MemoryMode = (typeof MEMORY_MODES)[number];
22
+ /**
23
+ * Where the record came from:
24
+ * - `human` — authored by a person.
25
+ * - `agent-retro` — a retrospective prior PROPOSED by an agent. Always a
26
+ * hypothesis until ratified by governance (S3: merge of a bot
27
+ * PR). By construction it can never be authoritative here.
28
+ * - `measured` — produced by an empirical measurement. Authoritative fact.
29
+ * - `instance` — observed directly from a concrete instance run. Fact.
30
+ */
31
+ export declare const PROVENANCES: readonly ["human", "agent-retro", "measured", "instance"];
32
+ export type MemoryProvenance = (typeof PROVENANCES)[number];
33
+ /**
34
+ * The authority tier — the forgery target. `hypothesis` is a not-yet-ratified
35
+ * claim; `authoritative` is a ratified fact/fix. The invariants below make it
36
+ * impossible for an `agent-retro` (or otherwise unratified) record to carry the
37
+ * `authoritative` tier. Governance (S3) is the ONLY thing that legitimately
38
+ * mints `authoritative` records, via the ratification transition it owns.
39
+ */
40
+ export declare const AUTHORITIES: readonly ["hypothesis", "authoritative"];
41
+ export type MemoryAuthority = (typeof AUTHORITIES)[number];
42
+ /**
43
+ * A memory record. The required fields form the stable published contract; the
44
+ * optional fields are additive and safe for consumers to ignore.
45
+ */
46
+ export interface MemoryRecord {
47
+ /** Discriminates the schema version (see MEMORY_RECORD_SCHEMA_VERSION). */
48
+ readonly schemaVersion: MemoryRecordSchemaVersion;
49
+ /** Stable, non-empty identifier for the record. */
50
+ readonly id: string;
51
+ /** The ladder level this record is attached to. */
52
+ readonly scope: MemoryScope;
53
+ /** Normative vs empirical. */
54
+ readonly mode: MemoryMode;
55
+ /** Where the record came from. */
56
+ readonly provenance: MemoryProvenance;
57
+ /** Hypothesis vs authoritative — constrained by provenance (see invariants). */
58
+ readonly authority: MemoryAuthority;
59
+ /** The claim/observation the record carries. Non-empty. */
60
+ readonly statement: string;
61
+ /** ISO-8601 timestamp of when the record was created. */
62
+ readonly createdAt: string;
63
+ /** Optional: the specific target within `scope` (e.g. an element id). */
64
+ readonly scopeRef?: string;
65
+ /** Optional: free-form subject/topic the record is about. */
66
+ readonly subject?: string;
67
+ /** Optional: references (ids/urls) backing an empirical/measured claim. */
68
+ readonly evidence?: readonly string[];
69
+ /** Optional: id of a record this one supersedes. */
70
+ readonly supersedes?: string;
71
+ }
72
+ /** A machine-readable validation failure code. */
73
+ export type ValidationCode = "not-an-object" | "unsupported-schema-version" | "missing-field" | "wrong-type" | "empty-string" | "invalid-vocabulary" | "invalid-timestamp" | "invariant-violation";
74
+ /** A single, human- and machine-readable validation error. */
75
+ export interface ValidationError {
76
+ /** Dotted path to the offending field (empty for whole-record errors). */
77
+ readonly path: string;
78
+ /** Stable machine code. */
79
+ readonly code: ValidationCode;
80
+ /** Human-readable explanation. */
81
+ readonly message: string;
82
+ }
83
+ /** The result of validating an untrusted value. */
84
+ export type ValidationResult = {
85
+ readonly ok: true;
86
+ readonly record: MemoryRecord;
87
+ } | {
88
+ readonly ok: false;
89
+ readonly errors: readonly ValidationError[];
90
+ };
91
+ /** The three vocabulary fields the cross-field invariants constrain. */
92
+ export interface InvariantContext {
93
+ readonly mode: MemoryMode;
94
+ readonly provenance: MemoryProvenance;
95
+ readonly authority: MemoryAuthority;
96
+ }
97
+ /**
98
+ * Enumerates every invariant violation in `ctx`. An empty array means the
99
+ * (mode, provenance, authority) triple is internally consistent.
100
+ *
101
+ * The rules, together, guarantee the hypothesis-never-fix invariant:
102
+ * R1 agent-retro ⇒ hypothesis (a proposed prior is never a fact)
103
+ * R2 measured ⇒ authoritative (a measurement is a fact, not a guess)
104
+ * R3 measured ⇒ empirical (you cannot "measure" a norm)
105
+ * R4 instance ⇒ authoritative (a real observation is a fact)
106
+ * R5 instance ⇒ empirical (an observation is not a norm)
107
+ * R6 normative ⇒ human | agent-retro (only people/agents author norms)
108
+ *
109
+ * A consequence worth stating explicitly (and tested by S7): the ONLY way to
110
+ * reach `authoritative` is provenance ∈ {human, measured, instance}; agent-retro
111
+ * is structurally excluded, so an unratified prior can never be laundered into a
112
+ * fact by any field permutation.
113
+ */
114
+ export declare function checkInvariants(ctx: InvariantContext): readonly ValidationError[];
115
+ /** Convenience predicate: is this a ratified, authoritative fact/fix? */
116
+ export declare function isAuthoritative(record: MemoryRecord): boolean;
117
+ /**
118
+ * Validate an untrusted value as a MemoryRecord. On success returns the record
119
+ * narrowed to `MemoryRecord`; on failure returns EVERY error found (not just the
120
+ * first) so callers can surface all problems at once. Never throws.
121
+ */
122
+ export declare function validateMemoryRecord(input: unknown): ValidationResult;
123
+ /** Type guard form of {@link validateMemoryRecord}. */
124
+ export declare function isMemoryRecord(input: unknown): input is MemoryRecord;
125
+ /** Error thrown by {@link assertMemoryRecord}. Carries the structured errors. */
126
+ export declare class MemoryRecordValidationError extends Error {
127
+ readonly errors: readonly ValidationError[];
128
+ constructor(errors: readonly ValidationError[]);
129
+ }
130
+ /**
131
+ * Throwing form: returns the validated record or throws
132
+ * {@link MemoryRecordValidationError}. Handy for governance/write paths that
133
+ * treat an invalid record as a hard failure.
134
+ */
135
+ export declare function assertMemoryRecord(input: unknown): MemoryRecord;