Appendix — Design Decision Records

The decisions in this spec were reached through structured Socratic debates with multiple AI agent perspectives, then cross-validated to consensus. This appendix preserves the rationale.

Cards: Template with Meta vs Keyword

Decision: No card keyword. Cards are templates with kind: "card" meta. Confidence: 88%.

Cards and templates are structurally identical — both have ports and meta. Adding a keyword is irreversible. If we later discover we need one, we can add card as syntactic sugar that desugars to a template (non-breaking). Removing a keyword is breaking.

Ring Member Syntax

Decision: Both explicit and implicit forms accepted. Emitter always emits explicit. Confidence: 82%.

Explicit form (member Console.OptoCore_A) is stable — if someone later adds a TWINLANe port to the Console template, the explicit form still resolves correctly. Implicit form (member Console) would break in that scenario.

Slot/Card Compatibility

Decision: Inverted model. Cards declare fits. Slots declare bay shape only. Confidence: 87%.

If each slot listed compatible cards, every new card type would require editing every template that has that slot type. The inverted model: adding a new card never requires editing existing templates.

ID Separator

Decision: Double-colon :: separator. Confidence: 85%.

Underscore (_) is ambiguous because identifiers contain underscores. :: cannot appear in PatchLang identifiers, making parsing unambiguous.

Reserved Keywords

Decision: Reserve ring and member only. Un-reserve card. Confidence: 92%.

Reserve a keyword only when a concrete syntax design exists, the keyword name is confirmed, and an implementation plan is committed.

Project Structure: Page Tree vs Flat Bundle

Decision: One DB row per canvas level (ProjectPage model). Confidence: high.

The frontend loads one level at a time. Per-page rows match the loading pattern (one query per level), save pattern (one row per save), and enable row-level concurrency (two users editing different rooms don’t conflict).

project.json: Full Manifest vs Inferred

Decision: Thin manifest. Sub-levels inferred from use graph. Libraries and dependencies declared explicitly. Confidence: high.

Listing sub-levels duplicates the use graph and creates sync drift. The compiler discovers sub-levels by walking use statements. Only things that can’t be inferred (project-local libraries, external dependencies) are declared.

Multi-File Compilation: File Map

Decision: compile_project(files: HashMap, entry: &str). No concatenation, no incremental compilation. Confidence: high.

Concatenation loses file provenance (error messages can’t report which file). Incremental compilation is YAGNI at this scale (under 1 MB total). The file map gives the compiler everything it needs to resolve use statements and report errors with file + line info.

Flat Namespace

Decision: All templates share a single namespace. Duplicate names are compile errors. Confidence: high.

Simple and sufficient. If two files define Splitter, the compiler reports the conflict. Users use unique names (FOH_Splitter, Broadcast_Splitter). Scoped namespaces can be added later if needed.

Snapshot Strategy

Decision: Per-page version rows, not monolithic JSON blobs. Confidence: high.

Monolithic JSON blobs are the problem PatchLang was created to solve. Snapshots use a PageVersion table — each page’s content in its own row. Diffing compares rows. Restoring updates pages individually.