Example

Keep one reading of a source and render from it

Validate a hand-written semantic record against its source, watch three direct renderings drift apart, and walk every element back to the words it came from.

If a source can be rendered many ways, each rendering re-reads it. The chapter’s proposal is to keep one structured reading and draw the renderings from that, so that what the reader sees cannot drift apart silently. The program below takes a constructed payments policy, three constructed direct renderings, and one hand-written record, and shows what each approach costs.

No model is called. The record is written by hand, and the three direct renderings are built by hand to make the drift visible; they are not model output.

Run it

git clone https://github.com/ernanhughes/project-language.git
cd project-language
git checkout 329660f679a5a87831f91fe1430c20ac9360dda8
npm ci
npm run example:ch07

Node 22.19 or later; the project was developed on Node 25.8. The record module itself imports nothing, so core/record/src/index.ts can be read on its own.

Expected outcome

Three renderings written straight from the prose carry between one and two of the policy’s three exceptions. The renderings drawn from the record carry all three — by construction, because they are the same reading:

...
  Monday: diagram        carries 2 of 3 exceptions; missing: final
  Wednesday: timeline    carries 1 of 3 exceptions; missing: partition, idempotent
  Friday: table          carries 1 of 3 exceptions; missing: partition, final

Each is plausible alone. Together they describe three slightly different systems: 3 of 3 exceptions are carried by some and not by others.

The traceability check reports no problems for the hand-written record, and every element can be located in the source by character offset:

...
9 claims, 3 relations with direction, 0 qualifiers; each cites the source verbatim.
traceability problems: []
...
  partition  chars 143-245 "If the failure is a network partition, the payment is not retried and is sent to the dead-letter queue"
  x3         chars 330-368 "unless the partition exception applies"
  final      chars 305-368 "The third retry is final unless the partition exception applies"

And the record is not the source of truth. The source asserts a causal link and cites nothing for it; the record keeps the claim and records that nothing backs it, rather than correcting it:

...
source asserts: "Retries cause queue backlogs during outages."
record keeps:   standing=stated, evidence=none_cited

The check that makes it a record

The traceability check is the whole mechanism. It holds for any record, not only the fixture, and it is the reason a record is a reading rather than a paraphrase. This is the check, in full:

export function validateRecord(source: Source, record: DocumentRecord): { problem: RecordProblem; id: string }[] {
	const out: { problem: RecordProblem; id: string }[] = [];
	const ids = new Set<string>();
	const claimIds = new Set(record.claims.map((c) => c.id));
	const targetIds = new Set([...claimIds, ...record.relations.map((r) => r.id)]);
	const add = (problem: RecordProblem, id: string) => out.push({ problem, id });
	if (record.source_id !== source.id) add("SOURCE_MISMATCH", record.source_id);

	const kinds: [string, readonly { id: string; passage: string }[], ReadonlySet<string>][] = [
		["claim", record.claims, ALLOWED_FIELDS.claim],
		["relation", record.relations, ALLOWED_FIELDS.relation],
		["qualifier", record.qualifiers, ALLOWED_FIELDS.qualifier],
	];
	for (const [, entries, allowed] of kinds) {
		for (const entry of entries) {
			if (ids.has(entry.id)) add("DUPLICATE_ID", entry.id);
			ids.add(entry.id);
			if (typeof entry.passage !== "string" || entry.passage.trim() === "") add("EMPTY_PASSAGE", entry.id);
			else if (!source.text.includes(entry.passage)) add("PASSAGE_NOT_IN_SOURCE", entry.id);
			for (const key of Object.keys(entry)) if (!allowed.has(key)) add("UNKNOWN_FIELD", entry.id + "." + key);
		}
	}
	for (const r of record.relations) {
		if (!claimIds.has(r.from) || !claimIds.has(r.to)) add("UNKNOWN_CLAIM", r.id);
		if (r.from === r.to) add("SELF_RELATION", r.id);
	}
	for (const q of record.qualifiers) {
		if (!targetIds.has(q.applies_to)) add("UNKNOWN_CLAIM", q.id);
		const passage = q.passage.toLowerCase();
		if (!passage.includes(q.condition.toLowerCase())) add("CONDITION_NOT_IN_PASSAGE", q.id);
		if (q.status === "unknown" && (!q.gap || !passage.includes(q.gap.toLowerCase()))) add("GAP_WITHOUT_PASSAGE", q.id);
	}
	for (const c of record.claims) if (c.kind === "conclusion" && c.standing === "disputed" && !c.holder) add("DISPUTE_WITHOUT_HOLDER", c.id);
	return out;
}

The same module answers “where did this come from,” which is what makes a rendering traceable rather than merely tidy:

export function locate(record: DocumentRecord, source: Source, id: string): Located | undefined {
	const entry = [...record.claims, ...record.relations, ...record.qualifiers].find((e) => e.id === id);
	if (!entry) return undefined;
	const start = source.text.indexOf(entry.passage);
	return start < 0 ? undefined : { id, passage: entry.passage, start, end: start + entry.passage.length };
}

Mechanism and limitations

Documented: the record’s shape — claims, directed relations, qualifiers, each citing a passage — and the rule that a reading can be wrong, are in the module’s own header comment and in core/record/src/index.ts. The rule that the record stores what the source said rather than a corrected fact is the standing and evidenceStatus pair.

Observed: the run above. validateRecord returned [] for the hand-written record; the three direct renderings carried 2, 1 and 1 of the 3 exceptions; the record-drawn renderings carried 3, 3 and 3; and the record kept evidence=none_cited for the causal claim the source does not support.

Not shown. The chapter’s bet is that renderings made through a record agree more, contradict less and trace back further than renderings made directly. The “direct” renderings here are constructed, and the agreement check is phrase presence, so agreement is true by construction. The bet is untested by this program. Whether a model can build a record that passes the traceability check is also untested: this one is written by hand. Nothing here measures a reader, and the record’s own costs — a wrong record, omitted information, over-specified vague prose, false authority — are not exercised.

The traceback is a repeated quotation resolving to its first occurrence, nothing checks that a label means what its passage means, and there is no concepts field, extraction or revision log.

Canonical source and the record module .

Understand this example

Copy this prompt into your AI tool. No code runs here.

Apply this example

Copy this prompt into your AI tool. No code runs here.