clay-borg/specs/ArchitectureBlueprint.md
tegwick fed422a3a3 T01: audit every InnerLoop rule, and make the checkable ones executable
41 rules classified executable / checkable / decorative, each tagged with
the failure class it catches. Counts: 11 executable, 22 checkable, 4
decorative (one of them dead policy).
Audit: history/260731-inner-loop-rule-audit.md

New tools/loop-lint.py makes 7 rules executable (tier declared, chaos
roll recorded, tier-L review trail, unmeasured-in-evidence, whole-file
loadability, reporting tools expose --self-test). It found three real
violations on its first run, none previously visible:

  - specs/ArchitectureBlueprint.md was 543 lines against a ~400 limit
    the loop has stated since v0.2 and never measured. Split at its own
    section boundaries into Blueprint (1-8) + Runtime (9-15).
  - tools/dep-weight.py and tools/rule-coverage.py had positive-control
    logic and no --self-test, so nothing verified the control worked.

Adding rule-coverage's self-test exposed a latent instance of the exact
class this workplan is about: if the spec regex stopped matching, rules
was empty, missing was empty, and the tool exited 0 reporting "0/0" --
a silent pass, in the tool that reports our headline AM-1 number. Both
tools now assert they found something before reporting.

Two demotions applied in the spec rather than left implicit: "structured
over prose" is marked guidance (nothing can check it), and the 8k/10k
token budget is struck through and marked DEAD POLICY pointing at T05.

The audit's uncomfortable finding: rule 13 (re-derive inherited numbers)
has no mechanical form, is deliberately left decorative, and caught the
LARGEST error in CB-WP-0002. That is a counter-example to this
workplan's own hypothesis. "A rule that cannot be executed is not a
rule" is wrong as stated; the defensible version is that such a rule
cannot be relied on to fire, so it must not be the only defence for a
class that matters.

Class coverage: harness-does-nothing has five executable rules;
trusted-arithmetic has ZERO and produced the largest single error.

make loop-lint and make self-tests wired into `make all` and CI.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-31 09:16:00 +02:00

11 KiB

Clay-Borg Architecture Blueprint

Reference architecture for the Clay-Borg framework. This document describes the stable structural decisions: layers, component planes, capability ports, data flows, and repository layout. For motivation and product intent see ../INTENT.md; for the full originating exploration see ../history/260730-InitialExploration.md.

Status: draft — this blueprint is normative for new work but still malleable (Clay). Changes go through a decision record in decisions/.


1. Layered architecture

flowchart TB
    TR["TargetRevenue Control Plane
    phases • workload • revenue • licensing • trust"]

    AF["Agentic Development Forge
    specifications • work packets • generators
    tests • scenarios • benchmarks • evidence"]

    GP["Game Packages
    GROUND • fixture games • future products"]

    TT["Tabletop Framework
    cards • decks • tokens • zones • hands
    seats • hidden information • manipulation"]

    GR["Game Runtime
    commands • validation • rules • events
    phases • simultaneous actions • replay"]

    WS["World and Simulation
    entities • components • transforms • time
    scheduling • spatial queries • snapshots"]

    PORTS["Canonical Capability Ports
    render • physics • network • assets
    UI • audio • persistence • scripting"]

    LIBS["Assimilated Libraries
    wgpu • Rapier • Bevy ECS • Wasmtime
    Quinn • egui • Serde • tracing"]

    PLATFORM["Platform Substrate
    native • browser/WASM • server • CI"]

    TR --> AF
    AF --> GP
    GP --> TT
    TT --> GR
    GR --> WS
    WS --> PORTS
    PORTS --> LIBS
    LIBS --> PLATFORM

    AF -.tests and measures.-> GR
    AF -.tests and measures.-> WS
    AF -.tests and measures.-> PORTS
    TR -.governs releases.-> GP
    TR -.governs releases.-> PORTS

The four state kinds

Every subsystem must respect the separation between:

State kind Definition Owner
Authoritative semantic state What is legally happening in the game Game runtime
World state Where representations currently are World layer
Physical state How objects are moving Physics port
Presentation state What a particular player is allowed to see Projection layer

A game must remain playable in a headless process with no rendering and no rigid-body simulation. The 3D tabletop is a projection and interaction surface, never the definition of the game.


2. Clay Canon

The stable conceptual foundation shared by engines, games, tools, and agents.

Component Responsibility
Capability model Names and describes each engine capability and its implementations
Canonical identifiers Stable IDs for entities, players, assets, games, commands, events, sessions, packages
Schema system Machine-readable definitions for game packages, assets, scenarios, engine configuration
Contract system Interfaces and invariants every implementation must satisfy
Versioning model Compatibility rules for APIs, schemas, save games, event logs
Capability registry What exists, where it lives, maturity, dependencies, evidence, release phase
Assimilation manifests Why a library was adopted, what boundary contains it, how it can be replaced

Assimilation manifest (required per external dependency)

capability = "physics.rigid-body.3d"
implementation = "rapier3d"
boundary_crate = "cb-physics-rapier"
canonical_interface = "cb-physics-api"

determinism = "authoritative-server"
replaceability = "high"
exposed_upstream_types = false

required_tests = [
  "physics-conformance",
  "snapshot-restore",
  "card-stack-stability",
  "drag-release-behavior",
]

required_benchmarks = [
  "1000-resting-cards",
  "deck-shuffle-and-deal",
  "multi-object-picking",
]

Hard rule: no external library type leaks across a canonical interface. A card must not contain a RapierRigidBodyHandle, a wgpu::Texture, or an engine-specific entity id.


3. Runtime substrate

The lowest layer Clay-Borg owns itself:

  • Platform abstraction, application lifecycle
  • Time and fixed simulation ticks
  • Task scheduling and job execution
  • Memory and resource ownership conventions
  • Deterministic random-number streams
  • Configuration and feature flags
  • Diagnostics and structured tracing (tracing)
  • Capability discovery
  • Error taxonomy
  • Shutdown, recovery, headless execution

Port/implementation pattern

Every important capability ships a null, a reference, and (when financed) an optimized implementation:

cb-time-api
├── cb-time-realtime
└── cb-time-controlled

cb-render-api
├── cb-render-null
└── cb-render-wgpu

cb-network-api
├── cb-network-loopback
└── cb-network-quic

cb-physics-api
├── cb-physics-null
├── cb-physics-reference
└── cb-physics-rapier

Null and reference implementations keep tests fast, expose semantic assumptions, and let agents work without a GPU or a multiplayer environment.


4. Simulation kernel

Small and largely independent of game-specific concepts.

Entity and component model

  • ECS (bevy_ecs, assimilated standalone — not full Bevy) for world composition, spatial representation, runtime scheduling.
  • Explicit typed aggregates for game rules and authoritative state. Canonical game state is never reduced to arbitrary ECS components.

Mutation pipeline

Every meaningful state change follows:

Intent
  → Command
  → Validation
  → Domain Events
  → State Reducer
  → New Authoritative State
  → World/Presentation Projection

This yields replay, undo/branching, multiplayer sync, bot/agent access, auditing, save-game migration, rule debugging, and scenario testing.

Snapshots and event logs

  • Periodic full snapshots; append-only event streams
  • Stable event serialization (Serde behind versioned Clay-Borg schemas)
  • State hashes, replay seeds, branching from earlier state
  • Snapshot migration; expected-vs-actual state comparison
  • Every failed test produces a replay bundle an agent can execute locally.

5. Physics subsystem

Physics is a service of the world, not a source of game truth. Rapier is the optimized implementation; the server owns authoritative physical outcomes while clients interpolate and predict interaction feedback. Do not depend on independently simulated client physics remaining identical across platforms.

Tabletop physics scope (initial, deliberately narrow): pick up / move / flip / place a card, stack and unstack, move relation markers, snap tokens to tracks, animate reveal and resolution, prevent accidental scattering. Dice, complex joints, bags, arbitrary models, and unrestricted throwing come later.


6. World-building layer

Binds semantic objects to spatial representations.

Concept Meaning
World An independently simulated environment
Scene A loadable arrangement of objects
Object A spatially represented entity
Prototype Reusable object definition
Instance Runtime occurrence of a prototype
Transform Position, orientation, scale
Zone A spatial area with semantic meaning
Surface Table, board, tray, or similar placement area
Seat A participant position and viewpoint
View Player-specific projection of world state
Binding Connection between domain state and world objects

The world system supports multiple simultaneous projections: authoritative server world, player-visible worlds, spectator, debug, replay, and agent-observation worlds. This is what makes hidden hands and simultaneous decisions tractable.


7. Tabletop domain framework

Canonical tabletop object set (no game reinvents these):

Table  Board  Card  Deck  Stack  Token  Counter  Marker  Die  Bag
Zone  Hand  Seat  PlayerPointer  Note  Rulebook  ScoreTrack
SequenceTrack  Timer

Each object carries: physical representation, semantic identity, ownership, visibility policy, interaction permissions, allowed operations, snap behavior, serialization, behavior hooks, presentation variants.

Game-operation modes

Mode Rule
Sandbox Players manipulate objects freely; physics is primary, rules are social
Governed Only legal commands alter authoritative state; objects merely visualize
Hybrid Physical gestures propose commands; zones, ownership, and rules decide acceptance

GROUND uses hybrid mode: dragging a card toward another player only becomes an attack or support action when the rules engine validates target, relationship capacity, timing, and card availability.


8. Game runtime and packages

A game package describes five things separately:

  1. Content — cards, tokens, text, symbols, assets
  2. Setup — session initialization
  3. Rules — legal commands and their effects
  4. Flow — phases, simultaneous windows, end conditions
  5. Presentation bindings — how semantic state appears on the table
games/ground/
├── GAME.toml
├── INTENT.md
├── rules/          # ground.wit, phases.yaml, actions.yaml, resolution.yaml
├── content/        # cards.yaml, tokens.yaml, symbols.yaml
├── scenes/         # table.scene.yaml, tutorial.scene.yaml
├── assets/
├── scenarios/
├── bots/
├── tests/
└── migrations/

Extension boundary

Early GROUND rules live in native Rust crates. The stable extension boundary is later expressed through WebAssembly Interface Types loaded via Wasmtime. A game component receives explicit capabilities from the host (read public state, propose commands, spawn canonical objects) — never direct filesystem, network, clock, or GPU access.

Simultaneous action primitive

Open decision window
→ privately choose action and target
→ commit
→ wait for all players or timeout
→ reveal
→ order or group interactions
→ resolve
→ emit consequences

Networked play uses commit/reveal semantics so early submissions cannot be inspected and exploited. The interaction-group resolver (mutual attacks, support opposing an attack, capacity conflicts, simultaneous end conditions) is expected to become one of the first genuinely reusable Clay-Borg capabilities.



Continued in ArchitectureRuntime.md — §9 rendering/input/creation tools, §10 networking and sessions, §11 the agentic inner loop, §12 TargetRevenue integration, §13 repository structure, §14 milestones, §15 governing design decisions.

(Split 2026-07-31: this file was 543 lines against the loop's ~400-line whole-file loadability rule. The rule had been stated since v0.2 and nothing measured it until tools/loop-lint.py — see history/260731-inner-loop-rule-audit.md.)