ADRs
ADR 0087 — Component Model integration (Property/State/Behaviour/Proof + tokens)
  • Status: Accepted (design). Execution phased Ф0–Ф7.
  • Date: 2026-08-20
  • Supersedes / relates to: builds on @arno/origine Verifier (proof substrate); relates to ADR 0053 (token tiers), ADR 0059 (naming chord), the Studio-tools doc pattern (ADR 0058), and ADR 0022 (branch strategy).
  • Spec: docs/component-model/model.md — the Arno Component Model with Part B — Binding Amendments (v2), which is normative.

Context

@arno/origine already ships a mature proof half of a component contract model: a fold-based Verifier (20/21 behaviours proven), hand-authored + DOM-sampled Witnesses, a framework-neutral observation adapter (DOM/React), an obligation store, and a human waiver. What it lacks is the authoring half: capabilities, dimensional states, a structured WHEN/THEN behaviour model, property semantics, temporal operators, and — above all — an Induction Engine that turns demonstrated behaviour into candidate obligations.

A new model document (model.md) formalises the whole: a component = Properties + States + Behaviours + Proof, plus Capabilities and derived Observables, with an Induction→Proof split and a human confirmation membrane. Review of that document surfaced seven under-specifications that, if left vague, would let an implementer invent semantics during development (the god-schema failure mode). Those are closed in Part B of the spec and are binding.

The user need this serves: create a component → make it interactive with a set of rules and interactions → verifiable at the Arno level, per every principle in the spec.

Decision

  1. Adopt the Component Model with its Part B binding amendments as the source of truth (docs/component-model/model.md).
  2. Do not rebuild origine's proof half. Treat origine's Verifier, Witness, obligation store and waiver as consumers. Build only the missing authoring half, as producer modules (each only emits; consumers already exist in the flow).
  3. Integrate via existing seams (Punta, WorkflowView, ObligationList, the token catalog, Component Builder), not new surfaces where an old one fits.
  4. Make /build model-aware (analyst classifies P/S/B/Capabilities and emits obligations; QA treats scenarios as Witnesses and writes safety-first, verify-beyond-example tests; reviewers enforce the 15 rules + the three-part contract + the trust-boundary law). This discipline is Arno-only scoped (role files are global; gate behind "building an Arno Foundation/Studio component").
  5. Execute design-first, in phases Ф0–Ф7, each a shippable /build run.

Overarching law (root of every amendment)

No implicit derivation crosses the trust boundary. Everything the machine derives stays a candidate until a human confirms it. No proof → no truth. Enforced as a /build review gate.

The seven binding amendments (full text: Part B of the spec)

  1. Induction — Witness → candidate-gen → ranking (fixed prior) → human confirm → obligation. May rank, never create without confirmation.
  2. State ownership + Property/State discriminator — one membrane. Statehood granted by confirmed behavioural participation; non-sticky; statehood {confirmedBy, sourceBehaviour}.
  3. TimingTemporalConstraint {duration, bound, clock}; Core = finite bounds only; witness-time deterministic replay; witness-time ≠ temporal bound.
  4. Enforcement layered — Authoring → Verifier → Projector.
  5. Observables declared, not guessed — Semantic map → observation contract → platform adapter; derivation proposes relationships as candidates.
  6. Multi-projector conformance — golden-case Conformance Harness before a second Core projector; the two projectors are Arno's DESIGN render and the customer's CODE render.
  7. Status system — non-mixing axes (below).

Status system (four non-mixing concerns)

  • Obligationverdict {VERIFIED|VIOLATED|UNOBSERVABLE} × lifecycle {ACTIVE|INVALIDATED|ARCHIVED} (+ PENDING for unresolved targets) × waiver {none|active{waivedBy,reason,expiry}}.
  • ProjectorCONFORMANT | NON_CONFORMANT.
  • Contract completenessCOMPLETE | INCOMPLETE{unresolved:[(node,slot,state)]}.
  • Component trustTRUSTED | DEGRADED | BROKEN.
  • Fold: active obligations → verdict → severity → waiver overlay → trust, capped by conformance and completeness. UNOBSERVABLE (state unreached) ≠ INVALIDATED (state gone) ≠ NON_CONFORMANT (projector blind) ≠ INCOMPLETE (contract hole).

Tokens ↔ state (the colour binding)

  • Tokens are state-indexed under a role (interactive.primary.hovered). Bind to the role, resolve the state-child (role[state] ?? role.default).
  • Token editor: Role {Priority|Meaning|State}; a new Type dropdown appears only under Role=State, options = capability-licensed states (authoring enforcement at the token layer; kills free-text drift).
  • appliedToken(node, slot) is a Core observable and a vector over the whole component tree — one state change moves background + icon + text at any depth; obligations are per (state, node, slot). State owned at root, consumed by presentational descendants.
  • Token-editor arrows = colour-relationship layer (no WHEN). WHEN is assigned at component assembly. They compose at verify time.
  • Completeness + guided repair: a missing state-colour is INCOMPLETE, not a silent fallback — the node is flagged red on canvas, and the token editor scaffolds a red placeholder card (relationship + settings pre-wired, colour value left to the human).

Producer modules (each only emits) and consumer seams

#Producer (working name → candidates)EmitsConsumer seam (existing)
P1state dimensions (stato/dimensioni)dimensional state model, authored dims; derived-state candidates via membranePunta States panel, WorkflowView, Verifier
P2capabilities (virtù/capacità/dote)capability surface = authoring-enforcement gatePunta section gate (mirror SurfaceCapabilities in ponte studio-bus), token Type dropdown
P3witness recorder (gesto/saggio)demonstrated Witness with +t timingComponentPage preview ref; executable WorkflowView transitions
P4induction (induzione/congettura)ranked candidate obligations (fixed prior)ObligationList membrane (Accept/Reject), origine store
P5temporal grammar (tempo/durata)bounded operators for predicatesverifier/evaluator.ts
P6colour-relationship (legame/nesso/arco)palette relationship graph (Type-tagged edges, no triggers)state→token resolver, Verifier; reuses @arno/rotta for drawing
completeness checker + repair scaffoldercompleteness verdict + scaffold actionscanvas node + token card

Create-entry bridge: Component Builder LayoutNode tree → ComponentContract (per-node colour bindings, not just root).

Module names require the user's pick (identity-consent) at Ф1; not needed for Ф0.

origine code deltas

  • Split Obligation.status = verified|violated|waived → three orthogonal axes (verdict / lifecycle / waiver{waivedBy,reason,expiry}); add locus.
  • Coverage.uncoveredunobservable; verify the trust-fold does not count it as verified (honesty check, Ф0).
  • Trust.verifiedtrusted; fold consumes projector conformance + completeness.
  • Witness Observation frame gains t (elapsed ms); observe()/recordVerify() stamp it.
  • Verifier fold filters lifecycle == active before computing verdicts.
  • Semantic dependency graph (behaviour → statehood → state → obligation) with cascade-invalidation; flat arrays don't capture it.
  • Declarative Foundation semantic → observable map as data.
  • New projector-conformance level + Conformance Harness.
  • button.contract.ts: remove the Property/State collapse — in source only loading and disabled are both a State and a boolean Property (selected/pressed are Properties only, correctly, since no confirmed behaviour references them).

Phase plan (each = a /build run, shippable)

  • Ф0 — unblockers (origine + punta, low risk): locus; Property/State split + discriminator (statehood-by-participation); replace Rule 1; uncovered → unobservable + verify fold honesty.
  • Ф1 — P1 authored dimensions + Punta consumer + Verifier guard-over-dimensions + migrate flat ComponentState.
  • Ф2 — P2 capabilities + Punta gate + authoring enforcement + token Type dropdown.
  • Ф3 — Witness +t + P3 demonstrator on preview + executable WorkflowView transitions.
  • Ф4 — P5 temporal + verdict set (incl. TIMEOUT) + Foundation semantic→observable map + appliedToken observable (tree-aware).
  • Ф5 — P4 induction (fixed prior) + membrane (Accept/Reject, both candidate kinds) + derived-state candidates + 3-axis obligation model + cascade-invalidation graph + P6 colour-relationship + completeness checker/repair.
  • Ф6 — Component Builder → ComponentContract bridge (per-node colour bindings).
  • Ф7 — Conformance Harness (DESIGN vs CODE golden cases); may start React-only as self-test.

Cross-cutting: from Ф1, model-aware /build reviewer gates (trust-boundary law, no Property/State collapse, 15 rules, three-part contract), Arno-only.

Alternatives considered

  • Rebuild the model as fresh code (ignore origine). Rejected — origine's proof half is mature and aligned; duplicating it wastes work and forks the source of truth.
  • Bolt the model onto /build roles globally. Rejected — the model is Arno-specific; global role edits would pollute every project's workflow. Scoped Arno-only instead.
  • Leave the seven under-specifications as future work. Rejected by the maintainer — vague Induction / State-ownership / Property-State would force the implementer to invent semantics (god-schema). Closed in Part B before any code.
  • Token vocabulary migration (rename tokens to a canonical enum). Rejected for an adapter map (§B.8) — non-breaking.

Consequences

  • The whole "configure → demonstrate → confirm → verify" loop becomes buildable, with every arrow owned by a module.
  • A component state change proves the coherence of the entire nested colour tree — the core value.
  • Cost: a real new authoring surface (demonstration, membrane), a frame-schema change (timing), and a projector-conformance harness.
  • Open: the five/six module names (Ф1), and whether production render hard-blocks on INCOMPLETE or visually falls back to base (default: fall back + flag).