Skip to content
← Documentation

docs/projection-coherence-matrix.md


The Projection Coherence Matrix

Measurement only. The generated organization is the canonical truth. Every projection is evaluated independently against it, not pairwise against another projection.

Invariant under test:

No projection should reconstruct semantics that another projection receives explicitly. Where one derives meaning from presentation and another from structured data, coherence is accidental.


1. The projection inventory

Five projections — but only two derivation roots, which is the finding that matters.

# Projection Derives from
1 deriveAnswers → panel text the World
2 WorldScene → 3D scene graph the World
3 /api/world → JSON the World
4 verifyWorld → constitutional verdict the World
5 CityMap → SVG city lib/hq/state.ts — a parallel derivation

Projections 1–4 share a source, so their agreement is structural. Projection 5 does not.


2. The matrix — "Which agent is busiest?"

Canonical answer computed directly from the facts, independent of any projection: weight = priority × (blocked ? 2 : 1).

Projection Answer Agrees with canonical
canonical (from facts) i > m > z
World.load i > m > z yes
panel (deriveAnswers) names i yes
3D department height i > m > z yes
CityMap pod height not measured — needs HqState unknown

Agreement among 1–4 is guaranteed by construction: all read World.load. The matrix confirms it rather than discovering it.


3. Findings — meaning reconstructed rather than received

A systematic audit for the invariant found five instances, one fixed and four open.

3.1 FIXED — an answer derived from prose

answers.ts matched label.includes("quiet"). Relabelling an identical incident flipped the organizational answer while the render still showed the problem. Repaired by carrying IncidentFact.condition (core's ratified stalled). Committed with a regression witness and a mutation.

3.2 OPEN — a constitutional verdict derived from prose

constitution.ts:191:

const silentFallback = world.buildings.filter(
  (b) => b.height <= 0 && !b.evidence.includes("UNKNOWN"),
);

Article VI enforcement — "an unbacked dimension must say so rather than sit at a default" — decides compliance by grepping a human-readable evidence string for a magic word, which the composer writes at build.ts:348.

The composer already knows this structurally. build.ts:324 computes:

const unmeasured =
  b.heightRule.kind === "measure" &&
  index.measure.get(`${b.id}::${b.heightRule.metric}`) == null;

It has the fact, writes it into prose, and the verifier parses the prose back out. Whether the world is judged constitutionally compliant depends on wording. Rewording that evidence string would silently change a constitutional verdict.

This is the same defect as 3.1 in the highest-consequence location, and it is the sharpest instance of the invariant being violated: meaning received explicitly, reconstructed from presentation.

Recorded, not repaired — a fix was drafted and declined.

3.3 OPEN — operational status classified twice

types.ts states status is "classified ONCE here", citing a past defect where "the same agent could read as active in one and indistinguishable from steady in the other."

Measured — it is classified twice:

Site Rule
build.ts:440 unstaffed → unstaffed, blocked>0 → active, queueDepth>0 → steady, else idle
state.ts:452 reserved → reserved, blocked>0 → active, queue.length>0 → steady, else idle

The three shared branches are identical, so the projections currently agree — but nothing enforces that. They agree because the same ternary was written twice. The fourth branch already diverges in vocabulary: unstaffed versus reserved, from different sources (placement.kind versus agent.kind).

This is textbook accidental coherence. The comment asserting single classification is false as measured.

3.4 OPEN — workload derived twice

Site Formula
build.ts:177 weight += priority × (blocked ? 2 : 1)
state.ts:462 workload = min(1, weight / peak)

CityMap pod height reads the second; WorldScene, the panel and the API read the first. Two independent derivations of how busy is this agent, feeding different renderers. Whether they rank agents identically is unverifiedCityMap could not be measured here because it consumes HqState, which needs telemetry.

3.5 OPEN — structure reconstructed from identifier shape

Site Reconstruction Explicit field that already exists
answers.ts:35 homeBuildingId.startsWith("dept-") Building.kind === "department"
build.ts:300 b.id.startsWith("dept-") ? b.id.slice(5) structure.agentHomes (inverted)
build.ts:320 same same

Three projections recover an entity's kind by parsing its id string, while the kind is carried explicitly on the object. Renaming an id prefix would silently change organizational answers.


4. Where meaning should move

The instruction is to move meaning earlier, not to teach a projection more heuristics. For each open finding, the earlier location already exists:

Finding Meaning currently recovered from Already available at
3.2 evidence prose build.ts:324unmeasured, a computed boolean
3.3 duplicated ternary World.agents[].status — already classified
3.4 parallel formula World.agents[].load — already derived
3.5 id string shape Building.kind, structure.agentHomes

Not one of these requires a new concept. In every case the structured fact exists upstream and the projection declines to read it. That is why the invariant is the right diagnostic: it names a class of defect where the information is already present and the consumer chooses prose or string shape instead.


5. Status

  • Questions audited: 1 of 7 in full matrix form; the invariant audit is repository-wide.
  • Coherence defects found: 5 — 1 fixed, 4 open.
  • Highest consequence open: 3.2, a constitutional verdict that depends on wording.
  • Projections sharing a derivation root: 4 of 5. CityMap is the exception and is the only projection whose agreement is unverified.