openspec/changes/archive/2026-09-10-add-cartridge-model/reviews/2026-09-10-advise.md
Advise: add-cartridge-model
ADVISE: send-back READER: agt-fable-5-1-arch-review SPAWN: /Users/dukejones/work/ClientProjects/AllSystemsGo/AICamera/.spawns/aicam-cart.1-1789064442-97604-b2bee6d1
Rigor: architecture. Density: lean. Reader family: Claude (Fable 5.1). Author family: grok.
Read order: packet Why → change spec specs/cartridge-runtime/spec.md → proposal.md → steer.md → ~/work/Family/web3d-space/docs/all-systems-go/MODELS.md, MODES.md → docs/3090-SIM.md → openspec/changes/add-sim-box-mix/specs/hardware-kit/spec.md → openspec/specs/hardware-kit/spec.md → src/lib/bay/t4000.ts → .grok/skills/3090-loadout/SKILL.md.
Blind take written before design.md / tasks.md were opened. No living cartridge-runtime spec exists.
Blind take (written before design.md)
- Pin. Cost record splits VRAM and host RAM. That is a 3090 shape. Thor is 64 GB unified; the
t4000column must sum both against one pool, or carry a singleunifiedfield. Otherwise a 3090-measured cost (3 GB VRAM + 2 GB host) is seated against the wrong two ceilings on t4000. - Pin. “Null means unmeasured, not free” needs a packer consequence in the spec: a null cost on the target envelope SHALL NOT seat; it may gauge or list. Without that scenario, null becomes free by default in the first packer that sums a column.
- Pin. No throughput cost. 3090-SIM says the live stack is a 273 GB/s and 70 W problem, and the 3090 “makes the nets look cheap and the memory envelope look expensive.” A knapsack on VRAM/RAM/W/NVENC alone will seat 9B + klein + SAM2 in 64 GB and miss that 30 fps does not survive. Either the record carries a latency class (LIVE/NEAR from MODELS.md) and the pack counts LIVE slots against a budget, or the spec states plainly that the pack is memory-only and 30 fps is a separate gauge.
- Pin.
never-on-thoris a shelf value, but it is derivable from the cost record (not4000cost, or at4000cost over envelope). Two fields that say the same thing drift. Either drop the shelf value and let the per-envelope record decide, or define shelf as an override that wins and say why. - Pin.
sam2-maxine-4kis conditional (steer: “SAM2↔Maxine at 4K”). A flat exclusive tag cannot express the condition. MODES.md mode 5 Talent tracking runs SAM2 + Maxine together. A flat tag refuses that preset. Either the tag carries a resolution predicate, or it is dropped this pass and left to measured costs. - Pin. On
3090co-residency is physically impossible (16 GB host, stages unload, sim-box-mix saysswap). The spec must define what “seated” means on a swap envelope: sum of peaks (refuses everything the 3090 actually runs) or max of peaks (what the harness does today). Otherwise the live brick refuses its own working loadout. - Pin. Id namespace. Scenario ids are
klein-4b,qwen-27b: model ids. MODELS.md names jobs (“On-set snap”, “AD heavy”, “Shot-calling”) and the spec says job names come from there and shall not fork. A cart needs both: the job it fills (from MODELS.md) and the model that fills it. Without ajobfield the catalog invents a second namespace, which is the fork the spec forbids. - Refuse. A third copy of costs. 3090 FACT numbers live in
docs/3090-SIM.mdMeasured, and derates already live twice (doc +t4000.ts, flagged on stage-bay). A hand-typedcosts.3090in JSON is copy three. The catalog must cite the doc row (date + stage) per cost, or the doc table must be generated from the catalog. One home. - Refuse. Always-on encode without a counted NVENC cost. T4000 HQ is 2× 4Kp30; mode 11 multicam can exceed. If the always-on cart’s NVENC sessions are not in the record and summed, “a pack SHALL NOT drop encode” is unenforceable and record can silently fail while AI stays seated.
- Tradeoff. JSON catalog vs TS module. TS gives types and
/bayimports it directly, but the packer’s first host is the Python harness on fractal1. Take JSON with atypes.tsmirror and a schema check in CI. Cost: one more file to keep in step. Benefit: Python and Svelte read the same bytes.
Compare against design.md, tasks.md
Shape matches the take. Catalog record is id / kind / shelf / exclusive / costs-per-envelope,
JSON, with MODELS.md and MODES.md as the name source and docs/3090-SIM.md as the 3090 FACT home.
Tradeoff 10 is decided the way I would decide it. Steer records presets, knapsack plus physics
tags, and live-brick envelope as user decisions; I do not contest any of them.
Pin 6 is a contradiction with add-sim-box-mix, and it is on the live brick. Design: “the
packer refuses a seat when the live-brick envelope is exceeded.” Sim-box-mix, ACTIVE in the same
wave: the 3090 “SHALL emulate that pipeline by loading one slot at a time and unloading it” and
residency on 3090 is swap. Sum-of-peaks refuses klein + SAM2 + CLIP, which is exactly the
loadout the harness runs today by swapping. The design’s own example (klein 16 GB VRAM + 8 GB
host) plus SAM2 already breaks 16 GB host. The spec must say what a pack means on a swap envelope. One sentence, but it has to be written before the actor sums a column.
Pin 5 is a contradiction with the tasks’ own preset list. Tasks seed talent-tracking as a
preset and sam2-maxine-4k as an exclusive tag. MODES.md mode 5 is SAM2 plus Maxine. Under the
spec’s flat rule (“cartridges that share an exclusive tag SHALL NOT be co-resident”) the seed
catalog refuses its own preset. Steelman: the author may intend the tag to sit on sam2-*-4k / maxine-*-4k variants as distinct cart ids, with 720p variants untagged. That is a legitimate
way to keep tags flat. It must be written, because the spec as read forbids the mode.
Pin 2 sharpens against always-on. cuVSLAM is Isaac ROS; nothing on fractal1 runs it, so its 3090 cost is null. Always-on plus “null is not free” plus “pack SHALL NOT drop always-on” means
every pack on the live brick either seats a null (null became free) or refuses (no pack ever
seats). The three rules are individually right and jointly undefined. Needs one scenario:
null on the target envelope for an always-on cart is absent, not unseatable, and is logged;
null on a slottable cart cannot seat.
Pin 8 is demonstrated by the design’s example. "vram_gb": 16.0 for klein-4b on 3090 is the
disk weight size (loadout: text enc 8.05 + transformer 7.75 + VAE 0.17). The measured run used cpu_offload; VRAM peak under offload is not 16 GB, and 3090-SIM does not record a VRAM peak for
klein at all. The first hand-typed number is already a guess dressed as FACT. Each cost needs a src (doc anchor plus date) or fact: false, and the doc row stays the home.
Pin 1 unaddressed. t4000 record carries vram_gb and host_ram_gb as two nulls. 3090-SIM:
“Do not treat 16 GB host RAM as a T4000 limit — Thor unified 64 GB eats the host half.” The
record shape is a 3090 shape applied to a unified box. Local fix: unified_gb on t4000, or a
stated rule that the packer sums the two columns against one ceiling on unified envelopes.
Pin 3 unaddressed, and sim-box-mix already has the answer. Sim-box-mix names SMALL and LARGE
packs and a resident-30fps target. This catalog carries neither a latency class nor a SMALL/LARGE
marker. The two changes describe the same carts with disjoint vocabularies. Not a redesign: add latency (LIVE / NEAR / MIN, from MODELS.md) or pack (SMALL / LARGE) to the record, or state
in the spec that this pack is memory-and-power only and 30 fps is sim-box-mix’s gauge.
Pin 4 downgraded to a note. Design keeps never-on-thor. MODES.md “Do not put on the body”
is a declared list, and it covers policy (H3 territorial weights) that no measured cost expresses.
Shelf as an override that wins is right. Say so in the spec; today it reads as a third fact.
Pin 9 partly answered, and it exposes a gap. nvenc is a field. Good. But no envelope
ceilings exist anywhere: VRAM 24 / 64 / 96, host 16, watts 350 / 70, NVENC sessions 1 / 2 HQ.
Sim-box-mix names the four boxes; neither change records what they hold. The Why says the
catalog is what lets a packer refuse. Costs without ceilings cannot refuse. The home is hardware-kit (sim-box-mix) or an envelopes block beside the catalog; either is fine, but one
of the two ACTIVE changes has to own it and today neither does.
Pin 7 stands as a task. Ids are model ids; MODELS.md rows are jobs. One job string per cart
pointing at the MODELS.md row keeps the “do not fork” promise honest and makes klein↔27B
legible as “same slot, both do not fit” rather than a hand-coded tag.
tasks.md has no acceptance step. The cheapest test this change can carry: every seeded preset seats on its home envelope under the spec’s own rules. That single check catches pins 2, 5, and 6 before any packer exists. Added below.
Steelman for the author. This is a lean contract for a packer that does not exist yet, on a
one-person lab brick, steered in one sitting. Every pin above is a sentence or a field, not a
redesign, and the author could reasonably say “the packer change answers those.” I agree on
1, 3, 4, 7, 8, 9: they are task pins. I do not agree on 2, 5, 6: those are the spec refusing
its own live brick and its own preset, and spec.md is not on this reader’s write path.
Why send-back, not accept
The catalog shape is right and steered. Send-back is narrow: three edits to specs/cartridge-runtime/spec.md before act.
- Define a pack on a
swapenvelope (3090): max-of-peaks across the swap set, or name the rule. Cite sim-box-mix. - Resolve
sam2-maxine-4kagainst the talent-tracking preset: resolution-variant cart ids, or drop the tag this pass. - Add the null scenario: always-on with null cost on the target envelope is
absentand logged; slottable with null cost cannot seat.
With those three in the spec, the rest are tasks and act can proceed. Re-advise is not required; a fresh reader can confirm the three lines in the next act verify.