The open authoring profile: GPT-6's freedom on the infra's evidence, materials and gate - #48
Conversation
… its surfaces
The `base` profile stops at shell materials and wall fixtures, and that is what
makes a finished render read as a MODEL of a room rather than a room: every
surface is right and the room is empty. An unoccupied desk is the loudest
statement a scene can make that nobody was ever there. Separately, a room whose
objects do not say what holds them up cannot be simulated no matter how good it
looks — geometry cannot distinguish a mug resting on a desk from a mug floating
a millimetre above one.
`--author-profile simulation` asks for both, in four gated jobs:
1 shell structure + materials, floor -> walls -> ceiling
2 LIGHT — the real luminaires from the photographs, geometry AND a Blender
light, matched on colour temperature, intensity and the direction the
photo's shadows imply. Before the props, because every material judgement
after it is made under that light.
3 the fixtures the scan missed
4 the small objects, surface by surface, from the raw frames rather than the
stitches — which flatten exactly the things this job is about. With an
explicit instruction not to tidy: axis-alignment is the giveaway of a
generated room, and not to invent a prop it cannot point at in a photo.
Simulation readiness is enforced rather than encouraged. `group_fixture` now
takes `rests_on=` / `attached_to=`, stores them on the handle, and `_register`
carries them out into `room_layout.json` where a simulator reads them. The brief
requires one or the other on every added object, and requires the claim to be
TRUE — the underside on the surface, read from the geometry rather than placed
by eye, because a prop that floats falls on the first simulated frame and one
that intersects gets fired across the room.
The authoring profile, step budget and turn cap had no CLI spelling at all; they
do now (`--author-profile`, `--author-steps`, `--author-turns`).
Verified against Office_room with gpt-6-astra: 143 objects, 132 support
declarations (the other 11 are the floor, ceiling and nine walls, which
correctly have none), all 47 `rests_on` claims seated within 2 cm — none
floating, none sunk — and an FCL mesh check over 131 bodies finding 2 genuine
clashes, both a continuous skirting/trunking run drawn through a door opening.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Sip8HKWXRgZhZpzsBnk5Uf
One `codex exec --json` event is one line, and an event carries the entire output of the command it reports — a `cat Room.py` on an authored room is over 100 KB, a stitch listing more. asyncio's StreamReader caps a line at 64 KiB and raises `ValueError: Separator is found, but chunk is longer than limit`, which killed the session a couple of tool calls in AND reported success, so the run looked like a model that had simply stopped early. The cap has to clear the largest event a session can emit, not the typical one. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Sip8HKWXRgZhZpzsBnk5Uf
… PBR Two defaults that were quietly costing every room. `--profile` defaulted to `base`, which stops after shell, materials and wall fixtures. That is why rooms came back with three empty tables and no light datablocks: the brief never asked for the props or the luminaires. `simulation` is the brief that produces a room worth judging — lights that actually emit, objects on the surfaces, and every added object grouped with `rests_on` / `attached_to` so a physics engine can read it. Make it the default; `base` is still there for a surfaces-only pass. `fetch_material` was described accurately and then ignored. The prompt listed the procedural `make(...)` helper as a peer alternative, and the agent read that as permission to write flat RGB and move on — a room whose surfaces are all flat colours is the single biggest remaining gap between the render and the photo. The tool now reads as an instruction: every surface with visible texture gets a fetched PBR set, only genuinely flat modern paint may stay a plain colour, and that has to be justifiable from the photograph. Procedural `make(...)` is demoted to what it is good at — procedural weave and grain.
`mesh_qc.chair_repair` is the only thing in the pipeline that looks at what TRELLIS produced rather than at what it was asked for: it flags fused floor slabs, squat blobs and floating fragments, then repairs a bad cluster by regenerating its reference image and re-running TRELLIS. The reconstruct stage has always forwarded `--chair-qc` to `scene_init.flow`, and `flow` has always honoured it — but nothing on the CLI side ever put `chair_qc` into the options dict, so the flag was unreachable and every chair went into every room ungated. It is ON by default. The checks are local geometry and cost nothing; only a cluster that FAILS pays for a regeneration. `--no-chair-qc` opts out, and then a bad chair ships as-is.
A one-shot GPT-6 run given nothing but the raw scan and a page of intent got the desk at 0.75 m, the shelves at 1.42 and 1.84 m and the meeting chairs where the photos put them — by probing the depth maps, slicing the point cloud by height and triangulating pixels across frames, all in a numpy script of its own. Our authoring pass hands the model head-on stitches and RoomPlan boxes and no way to ask the scan a number; it has to guess dimensions the capture already knows. The kit is those helpers as FILES, not tools: `read_scan` (frames, poses, intrinsics, depth in metres, confidence, the cloud, all in Blender Z-up), `measure` (probe_depth, triangulate, height_profile, pcd_slice), `rectify` (a screen or board lifted out of a photo as a texture), `contact_sheets` (every photograph, upright, before anything is built) and `arkit_cameras` (the capture cameras inside Blender). A tool answers one question the way its author framed it; a function the model can combine in a script is the freedom the measured run actually used. `evidence_pack.build()` lays it out beside the room — `evidence/` with the scan and stitches linked, the helpers COPIED so a run stays self-describing, contact sheets prebuilt, and one README stating the data formats and the Y-up→Z-up convention once. Beside, not inside: the room dir is copied wholesale downstream and a stray file in it is a trap. Checked against Office_room: the cloud's floor comes out within 3 cm of RoomPlan's (LiDAR scatters returns 30 cm under the real floor, so the floor is the strongest low band, not the lowest point), and with RoomPlan's floor the height profiles read desk 0.75 m and meeting table 0.75 m — the numbers the one-shot run measured by hand. Triangulation round-trips a projected point to 1e-3 m.
…eometry `rests_on` and `attached_to` made simulation readiness a statement the author makes; nothing checked whether the statement was true. The one-shot run that outperformed our pass on layout rebuilt itself until its own audit passed — floor contact within 1 mm, no pairwise intersections, no open boundary edges. This is that audit as part of the harness. `pipeline/room_qc/validate.py` reads the build (room_layout.json, Room.glb, manifest.json) and reports: every `rests_on` claim measured from the support's top (+1 cm floating / -2 cm sunk, and over its footprint), floor-standing furniture against the floor, objects that declare neither support, the real-mesh contact report from check_collisions when python-fcl is present, and whether every articulated asset in the manifest still reaches the build as a handle with its moving/fixed parts. Open-edge counts are reported, not failed — a reconstructed mesh that is not closed is a decomposition problem. Axis-aligned overlaps are a review list, never a verdict: a chair tucked under a table overlaps its box legitimately (77 such pairs in Office_room, 0 mesh clashes). Exit 0 pass / 2 fail / 1 could-not-run, and `validation.json` beside the layout so the stage summary, the trace and the model itself read the same verdict. Lives in pipeline/room_qc because it needs both room_ops and the collision code under agent/, and room_ops must not import agent.
Measured on Office_room: GPT-6 alone, given the raw scan and a page of intent,
came back in 37 minutes with a room closer to the photographs on layout and
fixtures than our scripted authoring pass — heater with fins and dials, AC
louvres, sockets at the measured spacing, the coat on its hooks — while our
pass kept the clearly better materials (fetch_material's photo-matched PBR),
the real glazing, the reconstructed and articulated assets and the sim export.
The scripted profiles prescribe an order, a cadence and what not to touch
because a step-budgeted model on Claude Code banked cheap calls and edited at
the end; that is a harness problem answered here with gates on the result
instead of rules on the process.
`--author-profile open`:
* the brief states what a finished room has and how it is judged, not how
to work — "HOW YOU WORK IS YOURS", with two conditions (Room.py compiles
after every save; save as you go);
* the evidence pack is built beside the room and put in the prompt and the
harness's readable roots: contact sheets to review first, stitches, the
raw capture, and the measurement helpers to import in the model's own
scripts; furniture boxes MAY be corrected when a measurement says so;
* the validation gate is the finish line: the brief tells the model to run
it, and the author stage builds the room (if the session did not) and
runs it again afterwards, recording the verdict as an artifact and a
warning;
* budgets the brief needs rather than the scripted pass's — 300 steps /
400 turns (the one-shot took 69 calls; our pass was cut at 56) — and the
codex/gpt-6 harness by default, unless a provider is set.
Two trace fixes the same measurement exposed: the session record now carries
the model that actually ran (the Office_room gpt-6 session was filed under
claude-opus-5, the role's name) and the harness name; and on Codex the raw
rollout is copied beside the trace, because it is the only place that says
which images the model was really shown — 28, against 84 filename mentions
the normalised trace had counted.
Smoke-tested end to end on Office_room with a 6-call Claude session: pack
built, README read first, trace fields present, build + gate PASS on the
seed room.
scene.json's capture link is the pipeline's input dir, which for Office_room holds one .usdz; input/rgbd/ is the pipeline's own split layout. The kit reads the raw frame_NNNNN.* capture, which lives under scene.json's roots.scans. Resolve it there (or LITEREALITY_SCAN, or the settings scans dir), and refuse to build a pack with no frames — the first gpt-6 run of the open profile was handed a pack with a usdz and the stitches and said so within four calls.
Result: the
|
Why
We ran GPT-6 (Codex,
gpt-6-astra) on Office_room two ways and rendered both from the same 59 capture cameras with the same Cycles setup:room.usdz) and a one-page brief, no LiteReality tooling. 37 min, 69 tool calls.simulationauthoring profile over the pipeline's assets.Our side won clearly on materials (
fetch_material's photo-matched PBR: carpet pile, wood grain, acoustic tile, the blind's fabric — GPT-6 alone had permission to fetch and still chose flat procedural colour), on real glazing, on reconstructed/articulated assets and on sim export. GPT-6 alone won on layout and fixtures: it measured desk and shelf heights from the depth maps, triangulated chair positions from silhouettes, built the heater with fins and dials, the AC louvres, sockets at the measured spacing, the coat on its hooks — and rebuilt until its own contact/intersection audit passed. Our scripted profile tells the model what to read, in what order, and what not to touch; none of that measuring was possible with what it was given.This PR keeps what the infra does well and gives the model what the one-shot run had.
What
--author-profile open— a brief, not a script. It states what a finished room has and how it is judged; "how you work is yours", with two conditions (Room.pycompiles after every save; save as you go). Furniture boxes may be corrected when a measurement says so; articulated and reconstructed assets must survive. Defaults to the Codex/gpt-6 harness and to budgets the brief needs (300 steps / 400 turns — the one-shot took 69 calls; our last pass was cut at 56).Evidence kit + pack (
evidence_kit/,agent/evidence_pack.py) — plain-python helpers the model imports in its own scripts, laid out beside the room asevidence/: contact sheets of every photograph, the stitches, the raw capture, andmeasure.probe_depth / triangulate / height_profile / pcd_slice,rectify.rectify_region,arkit_cameras. One README states the data formats and the Y-up→Z-up convention once. Verified on Office_room: the cloud's floor within 3 cm of RoomPlan's; desk and meeting table both read 0.75 m — the numbers GPT-6 measured by hand.Validation gate (
pipeline/room_qc/validate.py) — everyrests_onclaim measured against its support's top (+1 cm / −2 cm, over its footprint), floor-standing furniture against the floor, undeclared supports, the real-mesh contact report (python-fcl), and whether each articulated asset still reaches the build as a handle with its parts. Box overlaps are advisory (a chair tucked under a table overlaps its box legitimately).validation.jsonbeside the layout; exit 0/2. The brief tells the model to run it; the author stage builds the room if the session didn't and runs it again, recording the verdict. Current Office_room build: PASS — 0 clashes, 131 declared supports all seated.Trace fixes the same measurement exposed: the session record carries the model that actually ran (the Office_room gpt-6 session was filed under
claude-opus-5, the role's name) and the harness; on Codex the raw rollout is copied beside the trace — the only place that says which images the model was actually shown (28, against 84 filename mentions the trace had counted).Ported from
zhening/gpt-6(never landed on main): thesimulationprofile withrests_on/attached_toand the--author-profile/--author-turnsflags, the Codex whole-output fix, and the chair-QC gate in reconstruct.Verification
test_stdio_bridge_matches_the_registry— the venv lacks the installed package;test_reconstruct_resolves_python_from_canonical_repo_root— a realscans_uploaded/Office_roomshadows the test's path).open-profile run on Office_room with gpt-6 is queued for when the Codex quota window reopens; the three-way render comparison (GPT-6 alone / current profile / open) will be posted here.