Files
stack/docs/design/framework-constitution/debate/rebuttal-architect.md
Jason Woltje c70b217a5c
Some checks failed
ci/woodpecker/push/ci Pipeline failed
docs(design): mosaic framework constitution — expert conference output
Conference of 7 experts (architect/moonshot/contrarian/coder/aiml/devex/steward)
debated layering, sanitization, upgrade-safety, cross-harness robustness.
Artifacts: BRIEF, 7 positions, 7 rebuttals, synthesis-v1, 3 red-team passes,
canonical DESIGN.md, OPEN-QUESTIONS.md, MISSION.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 23:47:49 -05:00

18 KiB
Raw Blame History

Rebuttal — The Framework Architect

Lens: Clean layering, single-source-of-truth, separation of concerns, long-term maintainability.

Author role: Framework Architect Responding to: position-coder, position-contrarian, position-devex, position-aiml, position-steward, position-moonshot (and defending/extending position-architect).

One-line stance: The six other papers converge on the shape I proposed — split law from persona from operator, make the seam physical, enforce it in CI. That convergence is the real signal of the conference. Where they diverge is on how much machinery the seam needs, and that is where the architecture is won or lost. My job here is to keep the seam physical and boundary-checked while killing two proposals that would re-introduce the exact coupling we are trying to remove — and to settle the one disagreement that actually determines whether this design is maintainable: is enforcement a property of the launcher, or a property of the artifact?


1. Strongest ideas from other personas worth keeping

1.1 Contrarian's "subtraction before structure" is the correct precondition for my own layering

The Contrarian's central claim — "the framework's biggest defect is not under-layering, it is over-volume and internal contradiction" (position-contrarian §TL;DR) — is the most important corrective to my own paper, and I am adopting it as a hard precondition. I argued for five layers; the Contrarian and Coder argued for four. On reflection the Contrarian is right that adding a fifth document called "Constitution" on top of four existing restatements yields five disagreeing law files, not one. The architecture only pays off if the new CONSTITUTION.md is created by extraction and deletion, never by addition.

I verified the contradiction he cites is live, not hypothetical: 12 template files under templates/ still emit ~/.config/mosaic/rails/git/... while the canonical contract uses tools/git/... (defaults/AGENTS.md:30), and install.sh:192-194 actively deletes a stale rails symlink on migration. So the framework already knows rails/ is dead and ships 12 templates that point an agent at a path the installer removes. That is a single-source-of-truth violation producing a runnable-command failure — exactly the class of bug my lens exists to eliminate. Keep: law stated once, everything else references it, CI greps for known-dead path tokens. This is non-negotiable and I will not let an elegant five-layer diagram obscure it.

1.2 DevEx's "ownership + mutability is the layer axis" sharpens my owner×cadence basis

position-devex §DQ1 draws the layer lines by "who owns the file and what happens to it on upgrade — not by subject matter," and position-aiml §DQ1 adds the token-lifecycle axis (residency). Both are refinements of the basis I proposed (owner × change-cadence). The synthesis is clean and I endorse it: a layer boundary is legitimate iff the two sides differ in owner, upgrade-fate, OR residency. That test does real work — it is precisely why defaults/AGENTS.md:37's "(Policy: Jason, 2026-06-11.)" merge-authority clause cannot live in the constitution: it has a different owner (operator) and a different upgrade-fate (preserved, not clobbered) than the gate mechanism around it. Three independent papers reach the same seam from three different axes; that is the convergence worth banking.

1.3 Steward's license + credentials findings are the genuinely new, blocking facts

position-steward is the only paper that surfaces two issues outside the DQ frame that are nonetheless release blockers and that my own paper missed: (1) there is no LICENSE file anywhere — "Public does not mean licensed" (§Cross-Cutting) — so the package is legally all-rights-reserved; and (2) tools/_lib/credentials.sh:19 hardcodes $HOME/src/jarvis-brain/credentials.json as a credential default. From a maintainability lens these are layer-5 (deployment) contamination of the worst kind: a security-relevant default baked into shared tooling. Keep: both go in the alpha definition-of-done, and the credentials default becomes ${MOSAIC_CREDENTIALS_FILE:?...} (fast-fail), consistent with the existing STANDARDS.md:35 ban on ${VAR:-default} for required values. The framework already has this rule for downstream apps; it is violating it in its own tooling.


2. Weakest / riskiest proposals — concrete failure modes

2.1 Moonshot's YAML front-matter + content-hash "launcher refuses to start" is layer inversion

position-moonshot §DQ1 proposes putting mosaic-layer: 0 / mosaic-owner: framework / mosaic-override: forbidden front-matter in each deployed file, and having "the launcher read these headers and refuse to start if a layer-0 file has been structurally overridden (content-hash check)." position-steward §DQ3 proposes the same mechanism by another name: mosaic doctor --check-constitution comparing SHA-256 against a shipped .checksums file.

This is architecturally backwards and I will die on this hill. It makes the layer model a property of runtime metadata and a hashing tool, when the entire point of the re-architecture is to make the layer model a property of directory structure. Failure modes:

  1. It re-couples what we just decoupled. If "this file is immutable law" is encoded in YAML front-matter inside the file, then the immutability claim and the content it governs share a file — the same co-mingling (defaults/SOUL.md mixing persona + law + accommodation) we are eliminating. A user (or an agent) who edits the body can edit the header. The guarantee is self-referential.
  2. The checksum manifest is a fourth source of truth that will drift. .checksums / schema.json / front-matter mosaic-layer all encode "what is framework-owned." So does the directory split. So does install.sh's preserve/overwrite logic. That is four encodings of one fact. position-aiml §physics-#3 names exactly why this fails: contradiction is silently lossy. The first time a maintainer adds a constitution file and forgets to regenerate the checksum, mosaic doctor either false-positives (blocks every start) or the check is disabled — and a disabled integrity check is worse than none.
  3. "Launcher refuses to start" is a denial-of-service against the operator's own work. A content-hash mismatch can be a benign line-ending normalization, an rsync mtime quirk, or a legitimate hotfix the user applied while waiting for an upstream PR. Hard-failing the launcher on byte-inequality turns a maintainability nicety into an availability outage.

The architecturally correct version is what I already proposed and the directory split gives for free: framework-owned content lives under ~/.config/mosaic/constitution/ and is rsync --delete'd wholesale on every upgrade (position-coder §DQ3 FRAMEWORK_DIRS, position-architect §DQ3). The user cannot persist an edit to a clobbered directory across upgrade — that is the enforcement, and it requires zero hashes, zero front-matter, zero launcher gate. Immutability is enforced by the file being overwritten, not by a tool checking whether it was. Drift-detection-by-checksum is solving a problem that overwrite-by-directory deletes. If you want a doctor check, check structure ("is there a stray flat AGENTS.md shadowing constitution/?"), not content bytes.

2.2 Moonshot/DevEx's .local.md + 3-way-merge reconciliation engine is over-engineering the wrong layer

position-moonshot §DQ3 and position-devex §DQ3 both propose a per-file template-version marker plus a 3-way merge (base = old template, theirs = user file, ours = new template) that surfaces SOUL.md.mosaic-merge conflicts "exactly like git," plus copy-vs-symlink policy inversion in mosaic-link-runtime-assets. position-coder §DQ3 proposes the lighter E2E-DELIVERY.local.md overlay variant.

The instinct (don't make users edit framework files) is right and is the same one I argued. But a 3-way-merge engine over Markdown prose is a maintainability liability that fails its own goal:

  1. Markdown has no merge semantics. git merge-file resolves by line, not by meaning. A reflowed paragraph in the new template (one logical edit) produces a wall of phantom conflicts against a user's reflowed copy. The user is now hand-resolving <<<<<<< markers in their persona file on every upgrade — the precise "clobbered on upgrade" pain the BRIEF set out to kill, re-introduced as "conflict-resolution toil on upgrade."
  2. It is aimed at the layer that least needs it. SOUL/USER are small, user-owned, rarely re-templated. The thing that genuinely evolves is the framework law (layer 12), and that is solved by overwrite, not merge. Building a merge engine for the stable layer while the volatile layer needs none is effort spent against the gradient.
  3. The simpler, strictly-better primitive already exists in this very ecosystem. Additive override files — policy/standards-overrides.md (my §DQ3), Contrarian's <!-- mosaic:include STANDARDS.local.md -->, AIML's .local.md loaded-last-within-layer — give upgrade-safe customization with zero merge conflicts, because the framework file is never edited and the user delta is a separate, append-only file the composer concatenates. This is the config-layering pattern (base + drop-in) that settings.json / settings.local.json already use (runtime/claude/RUNTIME.md:47). Adopt the drop-in; reject the merge engine.

Verdict: keep template-versioning as a doctor signal ("your SOUL was generated from template v2; v4 ships — review examples/ for new sections"), but the resolution mechanism is an additive overlay, not a 3-way merge. Reserve any merge at all for the single genuinely-hand-tuned generated file (TOOLS.md), and even there surface conflicts in doctor rather than auto-resolving.

2.3 Moonshot's "Pi is the reference harness" inverts the single-source-of-truth dependency

position-moonshot §DQ4: "Pi is the Mosaic reference harness. When designing a new Constitution gate, first define it as a Pi extension behavior, then define the equivalent approximation for other harnesses." position-devex's capability-manifest idea is the better-engineered cousin of this, and I keep that — but the "Pi-first" framing is a layering error.

If the constitution is the single source of truth (every paper agrees it must be), then gates must be authored as harness-agnostic capability requirements, and each adapter — Pi included — resolves them to mechanism. Making one harness the reference means the abstract law is defined in terms of one concrete implementation's affordances; the day Pi's extension model changes, the constitution needs editing. That is the tail wagging the dog. position-devex §DQ4 already states the correct rule: the constitution speaks in capability verbs ("use structured reasoning for multi-step planning"), and adapters/<h>.capabilities.json binds the verb to mcp:sequential-thinking (gate: true) on Claude or native-thinking (gate: false) on Pi. Keep the capability manifest; drop the "Pi is canonical" framing. No harness is canonical; the capability vocabulary is canonical, and it lives in layer 1, owned by no runtime.


3. The key disagreement, sharpened — and how to resolve it

Strip away the agreements and exactly one fault line determines whether this architecture is maintainable long-term:

Is the constitution enforced because the launcher injects it, or because the artifact is self-bootstrapping and the directory layout makes it un-clobberable?

The two camps:

  • Launcher-trust camp (implicit in position-moonshot, parts of position-steward §DQ4): the launcher injects CONSTITUTION.md as system-prompt text, and we add metadata/hash checks so the launcher can refuse to run if law was tampered with. Enforcement is an active runtime behavior.
  • Artifact-trust camp (position-coder §"Single Strongest Recommendation", position-devex §"Biggest risk", position-aiml §DQ4): on 3 of 4 harnesses the "constitution" arrives only as a user-editable pointer file that says "go read this," which a busy model can skip and a user can edit away (defaults/AGENTS.md:11 even asserts the contract is "ALREADY in your context... Do not re-read it" — which position-devex §0 and position-contrarian §DQ4 both show is false for a direct claude launch). So the law must be (a) a file the agent is unconditionally told to read, and (b) backed by a mechanical hook where the harness has one (runtime/claude/RUNTIME.md:30-32: "the rule alone proved insufficient — the hook is the hard gate").

My resolution — and I think it is the load-bearing decision of the whole conference: enforcement is a property of the artifact and the directory, not the launcher. Three rules, in priority order:

  1. Immutability via directory, not metadata. Framework law lives in constitution/, rsync --delete'd every upgrade. There is nothing to tamper-check because tampering does not survive an upgrade and the upgrade is the enforcement. This deletes the entire front-matter/checksum/launcher-refusal apparatus from §2.1.
  2. Residency via self-bootstrapping read, not launcher trust. The thin AGENTS.md must say "if constitution/CONSTITUTION.md is not already in context, READ IT NOW" — never "it is already loaded" (fix defaults/AGENTS.md:11). This makes the law harness-agnostic by construction (position-coder's single strongest rec) and removes the dependency on every launcher getting injection order right. The launcher injecting by value is an optimization on strong harnesses, not the guarantee.
  3. Hard gates that are checkable become hooks/CI, not prose. position-contrarian §DQ5, position-devex §DQ4, and position-aiml §DQ4 all converge here and they are right: no-force-merge, green-CI-before-done, no-hardcoded-secrets, no-PII-in-shipped-files, and no-dead-path-tokens are all mechanically checkable. Each becomes a hook (PreToolUse) or a CI grep. Prose law is the spec; the hook/CI is the enforcement. This is the only thing that kept memory-write discipline honest (the hook, not the rule), and it is the only thing that will keep the 29-file contamination from re-accreting.

Why this resolution and not launcher-trust: launcher-trust adds runtime machinery (metadata, hashes, refusal logic) to compensate for a structural weakness; artifact-trust removes the structural weakness so no machinery is needed. A maintainable framework prefers the design where the invariant holds because of how the files are laid out, not because a tool remembered to check. Every checksum manifest is a liability that drifts; every directory that is unconditionally overwritten is a guarantee that cannot.

Concrete reconciliation for the alpha (what I'd put to a vote):

  • Adopt four ownership layers (Constitution / Persona / Operator / Project), defined by the owner×upgrade-fate×residency test (§1.2), with a typed two-axis precedence: safety → framework supreme; taste → user supreme (position-contrarian §DQ1). Drop my fifth layer into a policy/ directory under operator, not a new top-level layer.
  • Physical seam: constitution/ (clobbered) vs root user files (preserved). No PRESERVE_PATHS entry for any framework file. This is the whole upgrade-safety story.
  • Customization = additive overlays (policy/*.md, *.local.md loaded-last-within-layer), not 3-way merge.
  • Enforcement = self-bootstrapping read + hooks/CI, not front-matter/checksum/launcher refusal.
  • CI gates in the alpha DoD: verify-sanitized.sh (no PII/home-paths/dead rails/ tokens outside examples/), verify-no-duplicate-gates.sh (one normative MUST per file), verify-constitution-budget.sh (resident line ceiling — position-aiml/coder/devex all demand this), and a LICENSE/credentials-default check (position-steward).

If we get the directory seam and the CI gates, every other proposal in these seven papers is either mechanical or optional polish. If we get a beautiful five-layer precedence diagram without them, we ship the 29-file contamination with prettier filenames.


Top contentions (summary)

  1. Agree with the convergence, on one condition: introduce the Constitution layer by extraction and deletion, never addition — verified live drift (12 templates emit dead rails/git/ paths the installer deletes at install.sh:193) proves a fifth restatement yields five disagreeing law files, not one.
  2. Reject metadata/checksum/launcher-refusal enforcement (moonshot front-matter, steward --check-constitution): it re-couples the immutability claim to the file it governs and adds a 4th drifting source of truth. Enforce immutability by rsync --delete of constitution/ — overwrite is the guarantee; nothing to tamper-check.
  3. Reject the 3-way-merge reconciliation engine (devex/moonshot): Markdown has no merge semantics, so it re-creates upgrade-time toil on the stable layer. Use additive overlays (policy/*.md, *.local.md) — zero conflicts, framework file never edited.
  4. Reject "Pi is the reference harness" (moonshot): it defines abstract law in terms of one runtime's affordances. Keep devex's capability-manifest — the constitution speaks capability verbs; each adapter binds them; no harness is canonical.
  5. Resolve the core fault line toward artifact-trust: the law is enforced because it is self-bootstrapped (AGENTS.md says "READ IT NOW", never "already loaded" — fix AGENTS.md:11) and un-clobberable by directory, plus hooks/CI for every checkable gate — not because the launcher injects it and a tool checks a hash.
  6. Keep, and put in the alpha DoD: the four CI gates (sanitization, no-duplicate-gates, resident-budget) plus steward's two new blockers (MIT LICENSE, credentials default → ${VAR:?} fast-fail) — the only durable controls against regression.