Skip to content

docs: propose and exercise the v0 semantic architecture - #27

Draft
0xwonj wants to merge 18 commits into
mainfrom
docs/semantic-redesign
Draft

docs: propose and exercise the v0 semantic architecture#27
0xwonj wants to merge 18 commits into
mainfrom
docs/semantic-redesign

Conversation

@0xwonj

@0xwonj 0xwonj commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

This draft presents the research-stage v0 semantic redesign, its durable target documents, and the executable witnesses and falsifiers used to pressure-test the model. The existing docs/ authority map remains controlling; nothing in docs-next/ changes current product semantics, support, or release status.

Research review contract

The primary review surface is:

  • the architectural synthesis under docs-next/project/;
  • the target semantic contracts under docs-next/pir/, relations/, analysis/, and compiler/;
  • the domain boundaries under foundation/, oir/, realization/, and evidence/; and
  • the corresponding executable evidence under evaluation/, plus the bounded composed-protocol projection change and its lit test.

docs-next/notes/ is an optional, non-authoritative research appendix. It preserves source research, rejected alternatives, pressure tests, failed snapshots, and decision history. Reviewers are not expected to read it sequentially or exhaustively. Consult it when a durable decision lacks clear rationale, an alternative appears omitted, a claim needs its source or falsification trail, or a durable page may have failed to absorb an important qualification.

A note does not repair a missing definition in a durable document. Findings should be stated against the durable owner, implementation, or executable evidence; notes may be cited as supporting context. Review the current HEAD as the selected snapshot rather than treating intermediate commits as current design states.

Merge gate

This PR is intentionally a draft and is not merge-ready. Before squash merge, all still-needed conclusions and rationale must be absorbed into their durable owners, docs-next/notes/ and its remaining references must be removed, the manifest and navigation must be reconciled, and the final checks must be rerun.

Verification

  • cmake --build --preset ci --target check-zkc: 171/171 lit tests and all 50 C++ unit cases passed (8 encoding, 11 registry, 13 relation, 18 soundness).
  • evaluation/r2-protocol-model: 39/39 tests and the source-bound report runner passed.
  • evaluation/r2-p01-schnorr: 69/69 tests and the exact public report replay passed.
  • The commitment, LogUp, value-bridge, and guard-cost probes passed 33/33, 29/29, 18/18, and 22/22 tests respectively.
  • Ruff, Python bytecode compilation, and whitespace checks passed.
  • A full local Markdown audit covered 128 changed pages, 1,326 relative links, 65 document anchors, and 97 GitHub line fragments without a missing target.

Decisions

  • Keep semantic meaning independent of any one carrier while retaining MLIR as the rich authoring and transformation workbench and selecting one canonical PIR carrier.
  • Separate Core, challenge interpretation, Protocol, Interface, Plan, Relations, Analysis, Compiler decision, OIR, realization, and evidence authority instead of allowing one artifact or checker to stand for them all.
  • Keep identities, validation bases, evidence records, owner-local authority, and theorem applicability in distinct lanes with explicit non-promotion rules.
  • Retain temporary notes during collaborative research, but treat absorption and note removal as a hard pre-merge condition.

0xwonj and others added 18 commits August 23, 2026 21:42
The coverage tool measured whether a witness reaches the boundaries an
invariant claims, and reported closure on that alone. Reaching a boundary is
mechanical; deciding that reaching it discharges a stated requirement is a
judgment, and the tool had nowhere to record that judgment or check it.

F-06 asks for a semantically inert permutation or field to be removed or
justified. It was filed as closed on `logup:derived-anchors`, whose test
asserts that an authored anchor may not diverge from derived material. That is
a derived-stays-derived property, so the boundary now sits under X-02, where it
belongs, and F-06 is open: no witness permutes an identity-bearing collection.

Quoting each invariant's required pressure next to the boundaries claimed to
deliver it made two more mismatches readable. F-01 asks for two independent
implementations and gets one, on a finite-field algebra profile rather than a
rotated regime. F-05 asks for stored bytes, peak structure, memory, and work;
the guards witness measures node count and work. Both now state the shortfall
and are held to partial.

Verification: witnesses 160 tests OK; FRI and Schnorr --check reproduce their
frozen identities; ruff clean; public tree guard clean. Coverage moves from
19 closed / 0 partial / 1 open to 16 closed / 3 partial / 2 open of 21 tracked.
The guards witness claimed to answer whether a canonical guard is cheap by
measuring "real/adversarial node and work measurements". It measured nodes.

`robdd_size` recursed over every assignment and memoised each node on the
function it denotes. That yields the correct reduced node count, but it visits
2^|order| leaves whatever the diagram looks like, so both orders cost the same
to build: 65536 predicate evaluations and ~0.085s each at eight pairs, for
diagrams of 18 and 512 nodes. A cost model whose cost does not vary with the
representation says nothing about the representation, and the figure this
witness has been cited for — 2n+2 against 2^n — is two node counts.

The diagram is now built the way an implementation builds one: from guard
syntax, by `apply` over a unique table with memoisation on operand node pairs.
Work then tracks structure. The interleaved order costs exactly n^2 expansions
and the separated order more than doubles at every step, so the two separate in
work as well as in size, and the gap widens with scale instead of holding at a
constant factor.

Two further defects the rewrite exposed. The declared default bound never bound
anything: MAX_GUARD_NODES was 512, the separated diagram at eight pairs is
exactly 512, and the comparison is `>`, so every refusal the witness
demonstrated came from an ad-hoc narrower profile invented in the test. The
default is now 256 and is shown refusing the adversarial case. And the corpus
admits two atom kinds while only `BooleanAtom` was exercised; `FiniteValueEquals`
is modelled, because it is the kind whose encoding makes the variable count
depend on declared domain size.

Work is bounded separately from size, at its own boundary, because a bound on
one does not bound the other.

Verification: 22 guard tests, up from 7, including exhaustive checks that the
diagram denotes its formula under both orders; all six witnesses OK; FRI and
Schnorr --check reproduce their frozen identities; ruff and tree guard clean.
The guards probe moves from 1 negative to 3. F-05 stays partial: stored bytes
and memory are still unmeasured, and the guards are still the textbook
separating family rather than a corpus of real ones.
`check_relation_honest_prover_correspondence` pairs an admitted relation with
an admitted Core and the honest prover contract over it. It carries five named
codes and a real affirmative, and it had zero callers anywhere in the
repository — no test, no self-check, no report case. Unreached source reads as
coverage from the outside while establishing nothing.

It is the only place in this witness where a relation and a Core are held
against each other, so its absence is what made the relation half of the
Relation/Protocol pair the only half that executed.

Six tests now drive it, including one that keeps the two judgments apart by
disagreement rather than by assertion: the canonical pair corresponds while a
perturbed witness assignment fails satisfaction. Every field of the
correspondence is shown load-bearing by perturbing each in turn.

The report layer omitted this law for the same reason it had no callers, so the
frozen oracle gains four cases and rotates. The outcome, boundary, and code of
each were predicted from reading the law and then confirmed against the run;
the digests are machine-derived, as they must be. All twelve pre-existing cases
are asserted unchanged, so the rotation is growth rather than a changed
judgment.

R-07 gains the exact-law boundary and states what it still does not reach:
Protocol acceptance, soundness direction, completeness direction, and full
equivalence are not exercised, so it is partial rather than closed.

Verification: 40 Schnorr tests, up from 34; all six witnesses OK; FRI and
Schnorr --check pass; ruff and tree guard clean. Coverage moves to
15 closed / 4 partial / 2 open of 21 tracked.
A witness declares boundaries and codes in source. Whether any input drives them
is a separate question, and nobody had asked it. Two judgments in the Schnorr
witness were found today carrying five named codes and a real affirmative with
no caller anywhere in the repository — coverage from outside, establishing
nothing.

This answers the question by running rather than reading. It wraps the result
type each witness builds its judgments through, runs that witness's own suite
and its report layer where it has one, and compares the codes that were actually
carried by a constructed result against the codes its sources declare.

The first measurement:

    witness              declared  fired  unreachable
    r2-p01-schnorr            270     77          193
    r2-p02-commitment          27     11           16
    r2-p03-logup               24     16            8
    r2-p04-bridges             16     15            1
    r2-p05-guards               4      4            0
    r2-protocol-model         225     79          146
                              566    202          364   (36% reached)

Unreachable codes cluster rather than scatter, so the count is grouped by the
module declaring them: `execution.py` accounts for 150 of the 364 across the two
largest witnesses, and it is also where three of the five known dead judgments
live. The small recent witnesses reach nearly everything they declare; the large
early ones reach about a third.

An unreachable code is not automatically a defect — a witness may declare a
refusal for an input its fixtures cannot yet build. Not knowing which ones those
are is the defect.

Two measurement bugs were found while building it and are recorded in the source:
requiring a letter after the code prefix reported three witnesses as declaring no
codes while they were plainly firing them, and counting only the test suite would
have reported report-only judgments as unreachable.
…es suggest

Every mapping in the tool was re-read against the invariant's quoted pressure,
one auditor and one adversary per entry. Of eighteen, two were sound.

R-06 joins F-06 as filed against the wrong property. It asks that PIR distinguish
relation Witness occurrences from confidential Context, ProtocolValue, and
internal obligation outputs. Its claimed boundaries refuse an operand that names
a foreign parent — referential binding between admission layers. No witness
models the Witness/Context/ProtocolValue vocabulary at all, so the boundaries are
cleared and the invariant is open.

Twelve more were overstated: the right property, with conjuncts of the pressure
clause undelivered. The pattern repeats — a single boundary claimed for a clause
demanding several distinct mutations. F-03 claims algorithm closure on two name
checks that a sampler is cited and supported; nothing encodes a value or steps a
sampler, so no round-trip runs. R-04 claims lossless bridge laws on a boundary
that checks which obligations each lane declares; no bridge carries an executable
map, so neither round trip is driven. R-03 has no position mutation and its
evaluation-order rule cannot be made to fire. R-08's two boundaries both refuse
inside admit_core, so neither operand was ever admitted, which is the layered
case the pressure actually names.

Two were understated, and F-05 gains the boundaries it had earned.

Each entry now carries the shortfall as prose next to the quoted requirement, so
the judgment is where a reader can check it rather than implied by a boundary
name. The tool still cannot mechanize that pairing and still says so.

Verification: all six witnesses OK; FRI and Schnorr --check reproduce their
frozen identities; ruff and tree guard clean. Coverage moves from
16 closed / 3 partial / 2 open to 3 closed / 15 partial / 3 open of 21 tracked.
The number fell because it stopped counting boundary names as evidence.
No composed protocol had ever been projected. The reason was structural rather
than deliberate: composition leaves its operands in the module beside the
composite, this fixture's producer only exports a claim, and pir-project walks
every seal in the module — so projecting a composite refused at zkc-E234 for an
empty verifier face on a protocol nobody asked to project.

The pass gains a `protocol` option naming which seal to project. It is a
development adapter over the projection boundary, and selecting one protocol out
of a module holding several is what the link workflow creates a need for.

With that, the composition-context question becomes answerable by running
something. When a composite's consumer derives a challenge, does the producer's
material influence it? The three answers — carry the whole lineage, carry a
smaller domain identifier, exclude provenance — differ in whether a proof for one
composite replays inside another.

The answer is not in the domain string. Link renames the coins
`left.producer.challenge` and `right.consumer.challenge`, and those prefixes are
positional: they would read the same whichever producer had been linked. The
answer is in the sponge, and the new test follows it by SSA value across the
segment seam. The producer's squeeze result is absorbed into the state the
consumer's own values extend, and the consumer's squeeze consumes exactly that
state. Nothing resets at the boundary.

It is written as a falsifier and it fails in a reachable world: a link that
opened the consumer's segment from a fresh sponge, which is what excluding
provenance looks like once implemented, would absorb into an initial state
instead. Verified by breaking exactly that capture, which fails this test and no
other.

Verification: check-zkc 171 tests, up from 170, all passing; unit tests clean;
public tree guard clean.
The ledger asked whether a selection had an executable inhabitant. Read
literally that admits one inhabitant, which all fifteen registered rows already
have, so it filtered nothing. The stronger unwritten reading — build every
alternative and compare — was tested against this repository and failed in both
directions.

Not sufficient: composition context has all three alternatives inhabited by
running code and stays incomparable, because nothing carries a composition
context at the moment a challenge is derived, so the dimension never varies.
Not necessary: four alternatives are unrepresentable because a shipped refusal
makes them so, and inhabiting those means deleting a guarantee to measure the
hole, where the refusing code is already the argument.

Meanwhile the failure that actually occurred, four times in one day, was a real
artifact sitting adjacent to a claimed property and counted as it. An invariant
filed closed on a boundary testing something else. A guard witness reporting
diagram size as build work, both orders costing 65536 predicate evaluations for
diagrams differing 28-fold. A witness-surface invariant closed by an
identity-equality check. Building more alternatives produces more of these.

So each row now names what would show the selection wrong, and whether that has
been run. A falsifier that cannot fail is worse than none because it reports
success, so every row states the wrong result and why a reachable state produces
it. Rows are tiered: uncontested closes on the falsifier plus a costed rejection
with no rival built; contested owes the rival and a shared substrate where one
input drives both and the outcome can differ.

Section 7 grows from fifteen rows to thirty-four. The nineteen additions were
already load-bearing selections carrying no row — nine of them in
pir/protocol-model.md alone, and two in analysis/, where the ledger had
registered nothing at all. Registering them did not create the work; it made
work already being relied upon visible.

Seventeen of the nineteen drafted falsifiers failed adversarial attack before
landing: nine could not reach their failing outcome, three were vacuous, three
restated the decision, two named a task instead of an observation. That rate is
the reason the attack step is part of writing a row rather than a review of one.

Statement scope's clause is read as a conjunction. A single Sigma protocol fixes
its statement up front and cannot exhibit a later introduction at all, so only
sequential composition exercises what that row is about.

Verification: check-zkc 171 tests passing; ruff clean; public tree guard clean;
no absolute paths, private references, or internal shorthand in the tracked text.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant