Projection, Not Duplication
Every view of an artifact is derived from it by a declared, recomputable function.
- Standing
- WITNESSED CHECKABLE RUNNABLE EXECUTED STAGED PUBLISHED REPRODUCED
- Last checked
- 2026-09-11 15:26:17 UTC
- Source
graphonomous/v2/test/projection_v1.test.mjs@61adec2d5484· bytes957b52a20a403381…- Limit
- States that derived views may not become rival authorities. Nothing here checks that any view in the tree is derived rather than maintained; the WRL world for this chapter is sealed, and a sealed topology is not an authority audit.
- Next rung
live_local— a check on this page that walks a projection back to its source and refuses one that has drifted. The WRL world for this chapter seals, and a sealed topology is not an authority audit.
Why this page says WITNESSED — the derivation, not the word
- ✓ a witness is named
- ✓ its evidence kind is one the ledger already uses (constructive_witness)
- ✓ the witness path resolves in this tree
- ✓ its rung is in_tree or above (in_tree)
- ✓ a run is recorded for these exact bytes
- ✓ no claim is cited that could be REFUTED
- ✓ a counterexample is shipped (required once WITNESSED)
- ✗ not staged on this site, so it cannot run from the page
WITNESSED requires every line above to hold. The label is computed from them by build.mjs and cannot be typed into the registry — the build refuses a record that carries it.
Intent
A view is a projection, not a second copy that pretends to be authoritative. Two viewers agree because each derived the view from the artifact, not because they trusted each other. A copy that was edited since it was taken is a replica, and a receiver that cannot derive it refuses it.
Technical register
WRL §D8.18/§D8.19: deriveRuntimeProjection makes the V1→V2 downgrade in-band, and the projection on the wire carries only claims a receiver recomputes. Graphonomous projection-v1: eleven acceptance laws over schema_closure_id + projection_contract_id, so a projection's certificate closes over the schemas it actually used rather than every schema in the checkout — growing the vocabulary no longer re-mints frozen projections (the v0 defect D-068 fixed). 15 tests, five golden vectors.
Problem
v0 hashed every schema file in the checkout into every projection's identity. Adding a schema re-minted the certificates of frozen projections whose records had not moved. Identity that closes over the wrong set is duplication wearing a hash.
Solution
Declare the projection function and its contract. Derive the schema closure from what the projection actually consumed. Put the closure id and contract id in the certificate. Have every consumer recompute the projection from the artifact and refuse anything it cannot derive.
Real-world analogy
Two accountants each recompute the quarter from the ledger. A third brings last month's spreadsheet with edits. The first two agree; the third is not a view of anything.
Structure — on the surface
An illustration on a compute surface: loci above, carriers below. Press Play or Step; the takeaways collect as you go. Nothing here is evidence — the witness section is.
The chapter in WRL — and the chain so far
Chapter 11 of 32 — the fragment _patterns/wrl/chain/projection-not-duplication.wrl, sealed alone by wrl.js
; PROJECTION, NOT DUPLICATION — pj_view_a and pj_view_b are both derived from pj_artifact through
; SocketControl; neither is a copy. pj_in is the entry, fed by the grant router.
[relay:pj_in]{sig_in, sig_out}
[spinner:pj_artifact](w=16, n=8, rotor=quarter_turn_z){sig_in, socket}
[orb:pj_view_a]{pose}
[orb:pj_view_b]{pose}
[pj_in] --sig--> [pj_artifact]
[pj_artifact] --socket--> {[pj_view_a], [pj_view_b]}Its test bench _patterns/wrl/chain/projection-not-duplication.bench.wrl — drives the entry for this chapter's own film; never part of the chain
; TEST BENCH — drives this chapter's entry alone; the chain replaces it with a wire from an earlier chapter
[pulser:pj_bench](every 1){sig_out}
[pj_bench] --sig--> [pj_in]module + bench seal to → sem-7e9b02088e689d96680477ca165ad6e8f6ae575d47913b7fbf1f7c189a58648b
Reduced by the reference reducer (pure Python); parity with the other reducer not run for this world.
The Film, epoch by epoch (4)
epoch 1 · sha256:fb2c4975b7bdcba090926926df7373ad28b422f6646764bb3abc8a99431e238a
FILM v0.7 t=1 spinner:pj_artifact:policy=forge_motor_widemac_tz_sat_v1,quat4,w=16,n=8,rotor=00b5,0000,0000,00b5,socket=pj_view_a,config=fixed orb:pj_view_a:policy=forge_motor_widemac_tz_sat_v1,quat4,w=16,n=8,pose=0100,0000,0000,0000,controller=pj_artifact,fault=0 orb:pj_view_b:policy=forge_motor_widemac_tz_sat_v1,quat4,w=16,n=8,pose=0100,0000,0000,0000,controller=pj_artifact,fault=0 pulser:pj_bench:mode=periodic,p=1,phase=0,armed=0,done=0,nf=1 relay:pj_in:cur_out=0,next_out=1 wire:w__pj_bench__pj_in:cur=1,nxt=1 wire:w__pj_in__pj_artifact:cur=0,nxt=0 admit:policy=admit_candidate_min_firstreceipt_v1,fact_capacity_fault=0,receipt_capacity_fault=0,capacity_fault=0
epoch 2 · sha256:4d885cf88f3378fffe3454d8d9b1be3cfb4e4d773a58a927c5e7bf5d0e257750
FILM v0.7 t=2 spinner:pj_artifact:policy=forge_motor_widemac_tz_sat_v1,quat4,w=16,n=8,rotor=00b5,0000,0000,00b5,socket=pj_view_a,config=fixed orb:pj_view_a:policy=forge_motor_widemac_tz_sat_v1,quat4,w=16,n=8,pose=0100,0000,0000,0000,controller=pj_artifact,fault=0 orb:pj_view_b:policy=forge_motor_widemac_tz_sat_v1,quat4,w=16,n=8,pose=0100,0000,0000,0000,controller=pj_artifact,fault=0 pulser:pj_bench:mode=periodic,p=1,phase=0,armed=0,done=0,nf=1 relay:pj_in:cur_out=1,next_out=1 wire:w__pj_bench__pj_in:cur=1,nxt=1 wire:w__pj_in__pj_artifact:cur=0,nxt=1 admit:policy=admit_candidate_min_firstreceipt_v1,fact_capacity_fault=0,receipt_capacity_fault=0,capacity_fault=0
epoch 3 · sha256:e37c4d4b30741d10519a387c22f571c197c0a8c2c903535f44d15cfb5243b4e2
FILM v0.7 t=3 spinner:pj_artifact:policy=forge_motor_widemac_tz_sat_v1,quat4,w=16,n=8,rotor=00b5,0000,0000,00b5,socket=pj_view_a,config=fixed orb:pj_view_a:policy=forge_motor_widemac_tz_sat_v1,quat4,w=16,n=8,pose=00b5,0000,0000,00b5,controller=pj_artifact,fault=0 orb:pj_view_b:policy=forge_motor_widemac_tz_sat_v1,quat4,w=16,n=8,pose=00b5,0000,0000,00b5,controller=pj_artifact,fault=0 pulser:pj_bench:mode=periodic,p=1,phase=0,armed=0,done=0,nf=1 relay:pj_in:cur_out=1,next_out=1 wire:w__pj_bench__pj_in:cur=1,nxt=1 wire:w__pj_in__pj_artifact:cur=1,nxt=1 admit:policy=admit_candidate_min_firstreceipt_v1,fact_capacity_fault=0,receipt_capacity_fault=0,capacity_fault=0
epoch 4 · sha256:ce88a51cbe43b6b1500a2ab79acdc0c2ddba06d2957fc45abb2e07eaf04b077a
FILM v0.7 t=4 spinner:pj_artifact:policy=forge_motor_widemac_tz_sat_v1,quat4,w=16,n=8,rotor=00b5,0000,0000,00b5,socket=pj_view_a,config=fixed orb:pj_view_a:policy=forge_motor_widemac_tz_sat_v1,quat4,w=16,n=8,pose=0000,0000,0000,00ff,controller=pj_artifact,fault=0 orb:pj_view_b:policy=forge_motor_widemac_tz_sat_v1,quat4,w=16,n=8,pose=0000,0000,0000,00ff,controller=pj_artifact,fault=0 pulser:pj_bench:mode=periodic,p=1,phase=0,armed=0,done=0,nf=1 relay:pj_in:cur_out=1,next_out=1 wire:w__pj_bench__pj_in:cur=1,nxt=1 wire:w__pj_in__pj_artifact:cur=1,nxt=1 admit:policy=admit_candidate_min_firstreceipt_v1,fact_capacity_fault=0,receipt_capacity_fault=0,capacity_fault=0
Composes with the 10 chapters before it
The chain through this chapter — every earlier fragment, this one, and the links — seals to sem-42597d2b8f062a222caf638d66eb8745b939bed8ce14afebf4276dec55d3c9fb: 34 objects, 33 edges (was 30 / 29; every earlier object and edge is still present — checked, or the build refuses).
Links only the chain carries
[cc_grant] --sig--> [pj_in]
How to read this board
Five kinds of object, two kinds of wire, and one band per Part of the book. Signal flows left to right: it starts at a clock, travels through relays, and ends at a door — or turns a spinner, which drives an orb. Nothing below is the book's own vocabulary; each line is quoted from where the definition lives.
| shape | is | and so |
|---|---|---|
| a clock; the only source of signal | Every signal on the board starts at one of these. Nothing else can make one. | |
| a pass-through, so signal can travel | One arrives, any number leave — a relay that fans out is the board's router. | |
| a sink; signal arrives and stops | It latches what reached it and passes nothing on. A door is where a path ends. | |
| rotation: takes signal, drives a pose | The only object on the board that holds a value a claim can rewrite — and only if its config says configurable. | |
| the thing that gets moved | It is driven, never driving: an orb is what you watch to see whether anything happened. | |
| not a WRL role — the book's own drawing of the receipts in the epoch's Film | It counts what the run admitted, and turns red on a Rejected outcome. | |
| SignalWire | signal: a sig_out to a sig_in | Legal from a Pulser or Relay, into a Relay, Door or Spinner. This is how the board moves. |
| SocketControl | control: a socket to a pose | Legal only from a Spinner into an Orb. At most one may land on any input port — fan-in is a typed refusal. |
Hover any object for what it is, which chapter put it there, and every field of its line in that epoch's Film — split into what it is doing now and how it was built. Click to pin the readout, then click a wired name to follow the signal. The field definitions come from TRVM/forge/film.py (the emitter), TRVM/forge/forge_state.py (nf, derived from the decoded counter and never from t), TRVM/forge/lower_e2a.py (the commit/react law), TRVM/FORGE_SEMANTIC_IR_v1_MEASURE.md §1.3; the shapes from WRL/learn.html and WRL/docs/spec/README.md. The build refuses if a Film emits a field this key does not explain.
The board so far: one band per Part, signal flowing left to right; relays that fan out are routers, doors are switches, pulsers are clock domains. Hover an object — or click the board and walk it with the arrow keys — for its role, its Part and what it is wired to. This board is the chain’s sealed shape; no Film drives it, so it has no state to report, and the whole board in the conclusion is where every object’s state is read epoch by epoch. Wheel zooms · drag pans · double-click fits.
Syntax — quoted from the tree at build time
Why v1 exists — the test file's own header graphonomous/v2/test/projection_v1.test.mjs:3
* The subject is one coordinate. v0's `schema_set_id` hashes EVERY schema file in the checkout, keyed on basename, so * growing the v1 vocabulary re-minted the certificates of frozen v0 projections whose records had not moved. v1 * replaces it with `schema_closure_id` + `projection_contract_id`: the REQUIRED closure the verifier derives from the * projection's own adapter_run records through a trusted local contract (lib/closure.mjs, contracts/projection.v1.json).
The projection on the wire (WRL relation-v2.js) WRL/relation-v2.js:2363
export async function deriveRuntimeProjection(artifact,
claimedSemanticId = null) {
const v2 = artifact && typeof artifact === "object" &&
Object.prototype.hasOwnProperty.call(
V2_RELATION_SOURCE_FAMILIES, artifact.ir_version);
Forces
Derivation costs recomputation on every read, which is exactly the cost a replica avoids — and the reason replicas drift. The closure a projection's identity depends on must be neither too wide (every schema) nor too narrow (none); it is derived from the adapter runs that produced it, through a trusted contract.
Applicability
Read models, dashboards, exports, search indexes, semantic graphs over a corpus — anything that presents an artifact from another angle.
Transformations
- adding a projection
- re-deriving after the artifact changes
- downgrading a projection in-band so the receiver sees the downgrade as a claim
- a copy presented as the artifact (Replica Theater)
- an identity that closes over inputs the projection did not use
- a flag that says 'this is current' instead of a recomputation
A refusing transformation is not one that is discouraged: it is one that, applied, makes the invariant above false. The word is the tree's, and it is the same word the join uses.
Consequences
Views can multiply without becoming sources of truth. The methodological consequence is law 4 of projection-v1, measured in both of its readings, with the second found not to hold — the test says so, and D-072 records it.
Failure mode it answers
Replica Theater — Calling independent mutable copies 'the same thing'. Paid for at: CLAUDE.md: the served box-and-box copy is a MANUAL COPY and nothing syncs it
Witness
Source identity: graphonomous/v2/test/projection_v1.test.mjs · shape side-effect · evidence kind constructive_witness · rung in_tree (graphonomous/v2/handoff/STATUS.md:113 — TESTED, 15 tests over eleven laws)
Execution identity: 2026-09-11T15:26:17.256Z on PX13 · bytes 957b52a20a403381… · repo HEAD 61adec2d5484
Not staged on this site: the page cannot run this witness. It runs from the command line: node test/projection_v1.test.mjs in graphonomous/v2.
Counterexample
graphonomous/v2/test/projection_v1.test.mjs — marker does not hold
, expected REFUSED.
A marker, not a resolved law. The build checked that this string is present in the file. A string being present proves the file mentions it, not that the file refuses anything — this record cites no law id that could be resolved against a suite index. It is the weaker of the two forms this catalog uses.
What to take away
- from the animationTwo views agreed by derivation; the replica was refused because nothing could derive it.
- from the syntaxA projection's identity closes over the schemas it consumed — schema_closure_id — not the checkout.
- from the literatureCQRS read models and materialized views are the ancestry; the contribution is the closure id in the certificate.
- from the witness15 tests over eleven laws ran today with a receipt; law 4's second reading fails and the test says so.
Prior art — and what is not claimed
| work | relation | what it shares | where it differs |
|---|---|---|---|
| CQRS read models; materialized views | antecedent | many views derived from one authority | CQRS permits a read model to drift and reconcile; this pattern refuses a second authority outright |
| Unison's hash-addressed definitions | close analogue | derivations cannot disagree about what they derive from | Unison gets it from naming; this gets it from a projection rule |
Novelty not claimed. Derived views are ubiquitous. The narrow claim is about authority, not about caching.
Realizations in the tree
- WRL/HANDOFF_D8_PATH_B.md §D8.18-D8.19
- graphonomous/v2/contracts/projection.v1.json
Relations with other patterns
Refusable Divergence WITNESSED · Shared Observable WITNESSED