Mesh Segmentation
Recognize the parts, generate one immutable fragment map, then finish exactly
one part at a time through direct visual decisions. Before rev-000, inspect a
small registered mask probe and choose either the deterministic eight-view mask
initializer or direct signed fragment selection. After rev-000, both routes
use the same fragment review and the agent is responsible for every refinement
decision.
This is a clean workflow. Do not inherit strategies from an older segmentation skill. Reuse the existing scripts only as general-purpose rendering, fragment, picking, editing, audit, and export infrastructure.
Guardrails
- A provider retry can re-enter the same run directory with a fresh agent
thread. Inspect existing state before creating anything. If a part has a
locked
part_completion.json, never regenerate its initializer decision, initializer validation,rev-000, or earlier evidence. Resume from the newest numbered state. Every accepted lock is face-immutable in every run mode; continue only from unlocked, provisional, or residual faces. - Do not inspect golden, benchmark, or previously accepted segment labels during a run.
- Do not use annulus fitting, PCA, flood filling, category-specific predicates, remembered face IDs, fixed coordinates, or asset-specific scripts.
- Image-generation masks are optional, fallible initialization proposals. Use
the
image-generationskill for every generated mask. It selects an explicitly configured World Understanding backend or defaults to the coding agent's companion image-generation capability. If the selected mode is unavailable, record and report a warning and continue with direct agentic selection; never select another provider implicitly or fabricate mask evidence. When masks are available, a part-specific three-view probe must show that they survive erosion and project cleanly to fragments before the mask route is allowed. - Record and validate
PART/initializer_decision.jsonbefore creatingrev-000. Part size or category alone never determines the route. - If the mask route is chosen, do not vote over mask pixels, fragments, or views. Erode by exactly 2 px, select closest-visible fragments independently, and take the exact eight-view set union without visual alteration.
- If the direct route is chosen, discard mask-derived fragment IDs. Build
rev-000only from focused neutral/ID evidence and visually confirmed signed fragment picks. - Do not edit individual triangles. A pick resolves the closest visible face, but the include or exclude operation applies to its entire frozen fragment.
- Do not treat a script result as semantic validation. Only visual inspection determines whether a fragment belongs to a part.
- Batch obvious decisions. Do not serialize clicks that can be made from the same evidence.
- Treat a validated lock as immutable. Never extend, reassign, or otherwise change any of its faces in any run mode. Continue only from unlocked, provisional, or residual faces.
- Finish a part cleanly when practical. When a retry is unlikely to change the evidence, follow the recovery policy below instead of getting stuck.
- Treat every
rev-000as provisional regardless of initializer route. Never let acceptance of an image-mask probe substitute for post-seed falsification. - Before locking, collect signed positive target evidence and signed negative
confuser evidence, then mechanically verify both against the exact candidate
labels. A prose
passedassertion is not validation. - Challenge boundaries rather than sampling only easy interiors. For every expected instance, positive evidence must cover its interior, visible extent, and an opposing or occluded surface from at least two views, with a close signed pair straddling a visible target/confuser boundary. Every held-out view must contribute both polarities.
- Before acceptance, render the exact active segment by itself from every held-out view. Use selected-only evidence for both error directions: find embedded caps, internal plates, and floaters, but also reject truncated shells, discontinuous contours, implausible openings, and unexplained jagged cuts caused by missing faces. Compare repeated instances against one another so neither extra nor missing geometry can hide behind residual geometry.
- Connected-component count proves instance presence, not completeness. Before locking, review every expected instance from at least two selected-only views, including one opposing or occlusion-revealing view. Classify every visible selection boundary as an intended semantic boundary or a silhouette/occlusion; any unexplained boundary rejects the candidate.
- Expand any explicit count or repeated collection into separate stable
expected_instancesIDs before review (for example,wing-1throughwing-4, not one entry namedfour wings). The number ofinstance_completeness_reviewsentries must match that explicit count. If an instance is missing or unresolved, inspect and record the disposition of the selected components'nearby_similar_scale_component_ids; those hints are candidates to falsify, not semantic proof. An instance-count mismatch cannot pass: revise the candidate when evidence localizes the missing instance, or defer it when ambiguity remains. - For each selected-only completeness view with a nonempty deterministic frontier, inspect at least one actual adjacent unselected fragment in the matching flat-label and ID evidence. A candidate cannot pass until every checked frontier fragment is confirmed non-target; include any confirmed target fragment and rerender. If the audit frontier is empty, record the complete-disconnected-component not-applicable decision instead.
- If one fragment visibly crosses a semantic boundary, do not split it with triangle edits. Before any part is locked, regenerate a finer fragment map. After locking begins, report the representational limit rather than silently changing the map.
Prerequisites
The input is a USD stage containing one static triangulated fused mesh. Record the target mesh prim path. Work in a fresh run directory; never overwrite a revision. Use the workflow-owned usd-cli session and a fresh host Codex session, not Docker.
Locate the canonical tool directory:
if test -d agentic/.agents/skills/content-workflow-mesh-segmentation/scripts; then
MESH_TOOL_DIR=agentic/.agents/skills/content-workflow-mesh-segmentation/scripts
elif test -d .agents/skills/content-workflow-mesh-segmentation/scripts; then
MESH_TOOL_DIR=.agents/skills/content-workflow-mesh-segmentation/scripts
else
echo "mesh segmentation tools not found" >&2
exit 1
fi
Use only the scripts named below. The canonical directory contains both the general-purpose fragment tools and the evidence tools.
The launcher records the image-generation mode in request.json and requires
the image-generation skill. With an explicit World Understanding backend it
also records the model, optional base URL, and API-key environment-variable
name. Without a backend, the shared skill defaults to the coding agent's
companion image-generation capability and treats any model as a preference,
not an implicit provider. Read those values from the frozen request. Never
persist or print a key value.
Use Observation Memory
Read runtime.agent_memory from the frozen request. When enabled, use
content-agent-memory with exactly its run_id and pass its broker_url via
--broker-url; do not open the wrapper-owned root, object store, locks, or
SQLite index directly. Memory is required-capture for that run.
When disabled, continue normally and report that durable recall is unavailable.
Current-run memory is empty before the first plan and before a part's first attempt, so do not query it then. Search only when resuming or deliberately revisiting the active part:
content-agent-memory --run-id RUN_ID --broker-url MEMORY_BROKER_URL search \
--workflow mesh-segmentation --target "PART" --limit 4
Search a named confuser separately only when it is relevant. Do not load global context or unrelated part cards. Inspect explicit observation IDs and artifact roles only when their summaries affect the current decision.
Memory is a checkpoint, not a second decision-maker. Do not search memory before every revision or lock, and do not reload unchanged observations. Memory capture is post-decision bookkeeping: first create and review the same candidate you would create with memory disabled. The launcher records an evidence-only checkpoint as soon as that exact revision has selected-only and frontier evidence; do not duplicate it or wait until the end. The checkpoint deliberately does not claim a semantic result and cannot satisfy your required-capture duty. The broker marks agent records separately from launcher checkpoints for terminal audit. Final export is forbidden while any requested part lacks selected-only evidence, a frontier audit, or its launcher checkpoint; finish the missing review first. Record a materially changed diagnosis or correction, a deferral, or a validated lock yourself; do not record routine successful commands or repeat an unchanged backend warning.
A memory summary is not semantic evidence. Never select, reject, transfer, or preserve geometry merely to agree with a previous observation. On revisit, use memory to recover the prior candidate and unresolved question, then let current signed and visual evidence decide whether to keep or change it.
Use absolute artifact paths. Put the exact semantic part in
interaction.target_object_ids and tags; interaction has no semantic_part
field. Chain changed decisions with parent_observation_id.
Use this minimal record shape; do not rediscover the schema during a run:
{
"workflow": "mesh-segmentation",
"phase": "revision_review",
"interaction": {
"operation": "review_candidate",
"target_object_ids": ["PART"],
"target_prim_paths": ["/World/FusedMesh"]
},
"outcome": {"classification": "ambiguous", "summary": "EVIDENCE SUMMARY"},
"expectation": {
"expected_changes": ["COMPLETE TARGET SHELL"],
"forbidden_changes": ["EXCLUDE NAMED CONFUSERS"]
},
"artifacts": [{
"path": "/ABSOLUTE/RUN/PART/rev-NNN/face_labels.u32le",
"role": "candidate_labels",
"media_type": "application/octet-stream"
}],
"importance": "high",
"tags": ["mesh-segmentation", "PART"]
}
Classify an initializer or unvalidated revision as not_checked, ambiguous,
or contradicted; never call it matched merely because routing or edit
validation passed. Use matched and pinning only after both false-positive and
false-negative validation passes. Preserve expected completeness as strongly
as forbidden leakage.
Memory must not reduce cameras, renders, signed evidence, revisions, or visual inspection. It is advisory; dense labels and validations remain authoritative. If immediate required capture fails, retry the capture once. If it still fails, continue producing the best workflow artifacts, report the missing capture, and do not claim that the run satisfied its memory contract.
Recover, Defer, and Finish
Use ordinary operator judgment; do not turn recovery into another state machine.
- Retry while a changed camera, evidence source, or edit still produces measurable progress: it covers a previously uncovered required positive, removes at least one signed mismatch, resolves an unexplained boundary, or adds a registered view that can decide a named ambiguity. Never repeat an attempt unchanged. Defer only after distinct changed attempts repeat the same defect without any of those gains.
- Make revisions evidence-monotonic. Replace the current best candidate only when new signed, registered, selected-only, or component-context evidence identifies a specific false positive or false negative and the proposed edit addresses it. An ambiguous reinterpretation is not new evidence: keep the earlier candidate unchanged, gather a genuinely discriminating view, or defer. Never swap one plausible semantic guess for another merely to try something different.
- Do not defer an unstarted part. For every requested part with inspectable
evidence, create and visually review at least one real
rev-000covering every inspectable expected instance and visible extent. A token seed does not count. Complexity, remaining time, or strict validation cost alone is not a deferral reason. A part proven invisible in all available views may remain residual with that limitation recorded. - Treat every requested target as a positive assertion that the part should be found. Before calling one absent or uninspectable, audit every still-unlocked topology component, not only the components whose thumbnail or shape looks likely. Tiny assembled-view crops and semantic shape guesses cannot rule a component out. For each hidden, occluded, or too-small component that remains unclassified, render its isolated geometry from at least two fitted opposing views and compare those views with its registered source-context locator. Record every component's disposition. Deferral is allowed only when this exhaustive residual audit leaves no component or coherent component assembly consistent with the requested target.
- Only validated locks reserve faces. A deferred or provisional candidate must not consume geometry from later parts; preserve it separately and rebuild or reconcile it from the latest locked parent when revisited.
- A validated lock freezes both its evidence history and assigned faces in every run mode. If later evidence suggests that it is wrong, preserve the lock, record the conflict or unresolved boundary, and continue without changing its faces. This workflow does not advertise lock correction until a launcher-owned transactional validator can bind every affected revision to the final state.
- When the same problem remains, or the evidence says another retry is unlikely to help, preserve the best valid full-face labels, record the exact unresolved issue in memory, defer the part and continue with another part. A deferred candidate is provisional; do not promote it as a validated lock.
- Revisit deferred parts once, each after every other non-deferred requested part has been attempted. The remaining geometry and accumulated observations often make the boundary clearer. If one is still unresolved, keep the best provisional assignment and report the uncertainty.
- A zero unselected frontier is legitimate when the selected target is already a complete disconnected component. Record the frontier check as not applicable. Do not invent adjacent geometry or borrow faces merely to satisfy a checklist.
- Never rewrite the frozen fragment artifacts during semantic work. If their integrity changes, stop label edits and reproduce the deterministic fragment map from the source once. Stop the run only when a clean retry cannot restore face provenance, label count, fragment atomicity, or the source mesh.
- Always export the best complete face partition, even when some semantic parts remain deferred. Preserve one label per source face, use the documented residual for genuinely unresolved faces, and produce the final USD, labels, manifest, renders, and report. Do not call a deferred part validated or locked.
1. Identify the Parts
Prepare a neutral copy and render the source and frozen fragments from all eight cube-corner cameras. The script defaults to these eight views; do not reduce the set when memory is enabled. Reuse the saved cameras for registered ID evidence:
python "$MESH_TOOL_DIR/prepare_mesh.py" \
--source-usd INPUT.usd \
--target /World/FusedMesh \
--output-dir RUN/prepare
python "$MESH_TOOL_DIR/render_mesh_evidence.py" \
--scene INPUT.usd \
--focus /World/FusedMesh \
--camera-json CAMERA_A.json \
--camera-json CAMERA_B.json \
--output-dir RUN/part-identification
Inspect the source references and neutral renders. Write RUN/part_plan.json
with:
- a stable segment ID and semantic name for each visible logical/material part;
- separate stable IDs for repeated instances expected to share that label; if
the description gives an explicit count, write exactly that many entries and
never collapse the collection into one phrase such as
four wings; - nearby parts likely to be confused with it;
- a short visual description that can be checked in renders.
When request.json provides non-empty inputs.target_semantic_parts, treat
that list as the complete user vocabulary and skip open-ended part
identification. Use exactly those strings as semantic_name values; do not
add, rename, split, or merge non-residual categories. Inspect the object only
to record expected instances, confusers, visual descriptions, and a safe
processing order with broad provided body categories last. Use other only as
the final residual for genuinely unassigned faces.
For targeted runs, create each part directory directly under RUN using the
exact case-sensitive vocabulary string, for example RUN/Base and
RUN/Fan Blades. Do not lowercase, slug, number, or nest these directories.
Vocabulary strings may contain spaces. Set PART to the exact string and quote
every shell path containing it, for example
--clicks "RUN/$PART/rev-NNN/clicks.json". Record the same string in every
semantic_part field.
Do not segment yet. The inventory may be corrected when new views reveal an
unstarted part, but do not redefine a completed part to hide an error. Reserve
broad residual categories such as body or other until the more specific
parts are complete.
2. Generate and Freeze Fragments
Generate deterministic Python/SciPy over-segmentation once:
python "$MESH_TOOL_DIR/oversegment_mesh.py" \
--source-usd INPUT.usd \
--target /World/FusedMesh \
--output-dir RUN/fragments
Render RUN/fragments/fragments.usdc from the same cameras as the neutral
source. Check that the fragment coloring is registered to the source and that
fragments are small enough to represent visible semantic boundaries. More
fragments are acceptable; premature merging is not.
Freeze these artifacts for the full run:
fragment_ids.u32lefragment_adjacency.npyfragments.usdcfragment_manifest.json
Create RUN/state/labels-000.u32le with one background segment ID (0) for
each source face. This is the parent state for the first part. Every later state
must preserve one label per source face and keep each fragment atomic.
State history is append-only. Once a state/labels-NNN.u32le file exists, never
rewrite it, especially after an initializer gate has sealed it. For any later
correction, use the newest state as the revision parent, write the result to a
new rev-NNN, then promote it to a new monotonically numbered state file. Do
not rebuild or reapply unchanged later parts. A cross-label transfer is two
explicit append-only revisions: exclude from the source part, then include in
the destination from the resulting newest state.
Treat state/final_labels.u32le as the terminal promotion marker, not a rolling
working alias. During construction, use the newest numbered state. Never create,
replace, rename, or write final_labels.u32le. After every requested part has a
complete validated lock and the bounded uncertainty pass is complete, end the
turn. The launcher validates the exact lock-bound state and promotes it. A
continuation reads raw/final_labels_promotion.json and uses its lock-bound
source_labels numbered state for final export work; it must not access or
change the launcher-owned terminal marker.
The launcher prompt binds every executable helper to an absolute checked-in
path outside the writable run. Use those exact paths. Never execute a helper
copy under RUN/scripts/ or RUN/.agents/; those copies are child-writable and
are not trusted execution inputs.
Render zero-label face-ID buffers for all eight saved neutral cameras in one
render_face_id_buffers.py call, then build the reusable component evidence:
The neutral render manifest, ID buffers, and component builder must all bind to
the exact immutable INPUT.usd, not prepare/neutral.usdc. The prepared stage
is useful diagnostic output, but its file digest is intentionally different.
Select camera JSON paths from .renders[].camera in the render manifest; do
not glob every JSON file in the render directory because response JSON files
are not cameras.
python "$MESH_TOOL_DIR/build_topology_component_evidence.py" \
--source-usd INPUT.usd \
--target /World/FusedMesh \
--fragment-labels RUN/fragments/fragment_ids.u32le \
--id-buffer-manifest RUN/topology-id-buffers/manifest.json \
--neutral-render-manifest RUN/part-identification/render_manifest.json \
--appearance-dir RUN/inputs/references \
--output-dir RUN/topology-components
Visible cards preserve registered source appearance in a close crop, a wider local crop, and a readable full-view locator. Each card also lists similarly scaled components whose 3D bounds nearly touch; treat that list only as a prompt to inspect possible assembly peers, never as proof that they share a semantic label. Components hidden in every assembled OVRTX view get an isolated-geometry card with a diagnostic-only local preview and global-position locator. Never use that PIL preview to make a semantic or inspectability decision. Obtain a focused shared OVRTX render before declaring an expected part uninspectable. Use this corpus only for the active part: inspect likely registered cards and its named confusers. Do not assign the rest of the asset speculatively. In particular, do not make a global component-to-semantics assignment before part work; that turns an early visual guess into a sticky taxonomy and makes memory a second decision-maker.
If the likely-card pass does not locate a requested target, switch from likely triage to an exhaustive residual audit before deferring it. Inspect every still-unlocked component and classify it in a target-specific audit artifact. An assembled-view thumbnail can be too small or occluded to reveal an interior part, so render isolated geometry from at least two fitted opposing views for each unresolved component and compare it with the registered source-context locator. Do not let an early semantic guess about a component's shape stand in for this evidence.
Before starting the first semantic revision, use the component corpus to challenge the plan's assembly granularity. Topology is a clue, not semantic proof. Prefer the coarsest logical-assembly partition consistent with the request and registered evidence; a semantic part is not every surface that can be named. If the request supplies target names but no annotated boundary or explicit part description, do not infer a fine cut inside a welded component from the name alone. Surface orientation, a narrow visible band, and even a local seam are supporting clues, not sufficient evidence. Split the component only when registered multi-view evidence establishes a repeatable closed boundary around a coherent 3D subassembly, or the user explicitly defines that boundary. Otherwise revise the still-unstarted plan at the logical-assembly level and keep the component together.
3. Segment One Part
Choose one unfinished part from part_plan.json. Give it its recorded nonzero
segment ID. Already completed segment IDs in the parent labels are locked.
Choose the initializer and create rev-000
Read initializer-routing.md completely before initializing the active part.
Resolve image generation through the image-generation skill as specified by
the routing reference. When it is available, create the three-view image-mask
probe, preserve each agentic-image-generation-result.v1 manifest, and inspect
the registered masks, 2 px-eroded pixels, and resulting whole-fragment
projections. When it is unavailable, record the required warning and use the
direct route without fabricating a probe. Then write and validate:
RUN/PART/initializer_decision.jsonRUN/PART/initializer_decision_validation.json
Create the validation artifact by running
the launcher-provided absolute validate_initializer_decision.py path against
the decision before recording
initializer memory or creating rev-000. The launcher-owned
RUN/PART/initializer_runtime_gate.json is watchdog state: it never substitutes
for the decision validation and must not be cited as if it did.
After validation passes, treat the decision and every cited evidence artifact as
immutable. If any of them is rewritten, delete the now-stale validation, rerun
the validator, and wait for the runtime gate to accept the refreshed corpus
before continuing. Do not start or review rev-000 against a stale digest.
Choose exactly one route:
image_mask_seed: reuse the accepted probe views, generate the remaining five fixed cube-corner views, and apply the exact deterministic eight-view fragment union unchanged asrev-000.direct_agentic_selection: discard every mask-derived fragment ID, add focused views, batch closest-hit positive and negative fragment picks, inspect each whole fragment, and apply only confirmed direct selections asrev-000.
Do not blend routes within one rev-000. Both routes must preserve the same
immutable parent labels and frozen fragment map.
Observe
Read falsification-and-locking.md
completely before reviewing rev-000. Write the falsification plan before
looking for reasons to accept the initializer. Predeclare expected instances,
nearby confusers, observable falsifiers, construction views, and held-out
review views.
Render a small set of informative views of:
- the neutral source;
- the frozen fragment colors;
- a flat, unlit binary label view, with the active part highlighted and every unselected visible face neutral;
- the closest-visible face and fragment ID buffers.
- a selected-only export of the exact candidate, with every other segment hidden.
Use matching saved cameras so evidence can be compared directly. Add closer, opposing, top, bottom, or occlusion-revealing views whenever the existing views leave uncertainty. Normal and depth renders may clarify geometry, but they do not decide semantics. Lit renders provide semantic context only; never infer label membership from lighting or shadow.
Generate all registered ID and label channels from the same saved camera:
python "$MESH_TOOL_DIR/render_face_id_buffers.py" \
--source-usd INPUT.usd \
--target /World/FusedMesh \
--fragment-labels RUN/fragments/fragment_ids.u32le \
--face-labels "RUN/$PART/rev-NNN/face_labels.u32le" \
--active-segment-id PART_ID \
--camera-json RUN/cameras/right.json \
--output-dir "RUN/$PART/rev-NNN/id-buffers"
Batch-pick and decide
Create a click batch against the rendered evidence:
{
"events": [
{
"camera": "RUN/cameras/right.json",
"view_id": "right",
"instance_id": "target-part",
"pixel": [320, 240],
"polarity": "positive",
"note": "interior of a fragment visibly belonging to the target"
}
]
}
Pick several unmistakable fragment interiors in one call:
python "$MESH_TOOL_DIR/pick_face_evidence.py" \
--source-usd INPUT.usd \
--target /World/FusedMesh \
--fragment-labels RUN/fragments/fragment_ids.u32le \
--clicks "RUN/$PART/rev-NNN/clicks.json" \
--output "RUN/$PART/rev-NNN/picks.json"
Use the closest visible hit only. Avoid silhouettes and fragment boundaries. Deduplicate returned fragment IDs.
For a broad or thin visible mistake, mark a batch polygon or scribble over the same-camera ID buffer instead of issuing thousands of point rays:
python "$MESH_TOOL_DIR/regions_to_fragment_evidence.py" \
--id-buffer-manifest "RUN/$PART/rev-NNN/id-buffers/manifest.json" \
--regions "RUN/$PART/rev-NNN/regions.json" \
--output "RUN/$PART/rev-NNN/region-fragments.json"
The mapping is deterministic and returns the unique closest-visible fragment IDs under each marked region. Region evidence is still a proposal: inspect each whole fragment before applying it.
Classify each picked fragment by direct inspection:
- include when the whole visible fragment belongs to the target part;
- exclude when a selected fragment belongs to another part;
- undecided when current evidence is insufficient.
Never guess an undecided fragment. Render another view of it. Write one batch of supported decisions:
{
"edits": [
{
"operation": "include",
"fragment_ids": [12, 34],
"reason": "visible target-part surfaces in two views",
"evidence_render_ids": ["right", "upper-right"]
},
{
"operation": "exclude",
"fragment_ids": [56],
"reason": "visible neighboring part",
"evidence_render_ids": ["front-close"]
}
]
}
Apply the batch as a new immutable revision:
python "$MESH_TOOL_DIR/apply_fragment_edits.py" \
--source-usd INPUT.usd \
--target /World/FusedMesh \
--fragment-labels RUN/fragments/fragment_ids.u32le \
--parent-labels "RUN/$PART/rev-NNN/parent_labels.u32le" \
--edits "RUN/$PART/rev-NNN/edits.json" \
--active-segment-id PART_ID \
--output-dir "RUN/$PART/rev-NEXT"
For rev-000, pass RUN/PART/rev-000 as the actual script output directory so
the generated face_labels.u32le, diagnostic.usdc, and edit_manifest.json
all live there. Put the edit request outside that output directory when needed.
Do not create RUN/PART/rev-000 first: apply_fragment_edits.py owns that
directory and refuses to overwrite or populate a pre-existing revision.
Never output to rev-000-applied and copy selected files afterward.
Inspect and repeat
Render the new diagnostic USD with the same cameras. Conduct two explicit, separate searches in every review.
False-positive search
- Find highlighted pixels that the neutral or reference evidence shows belong to a neighboring part.
- Map the region through the same-camera ID buffer and inspect the returned whole fragments.
- Exclude only confirmed non-target fragments.
False-negative search
- Find target pixels that remain neutral in the flat label view.
- Map the region through the same-camera ID buffer and inspect the returned whole fragments.
- Include only confirmed target fragments.
Also inspect missing repeated instances, leaks at contact boundaries, isolated selected fragments, and hidden-side mistakes. If a decision is unclear, change the view before changing labels.
Repeat:
render current state
-> batch-pick visible mistakes or missing fragments
-> include / exclude / retain undecided
-> create a new revision
-> render again
Do not replace this loop with a geometry hypothesis or automatic semantic expansion. Large batches are fine when every decision is visually grounded; small batches are fine near difficult boundaries.
Before declaring the current revision clean, export its full partition, then isolate the active segment:
Write the candidate's segment metadata from the segment IDs actually present
in that revision's face_labels.u32le. Do not pass future labels or residual
label 0 after it has no faces: export_segmented_usd.py rejects every
configured segment with zero faces. Keep this revision-local segment JSON next
to the selected-only evidence at
RUN/$PART/rev-NNN/selected-only/segments.json.
python "$MESH_TOOL_DIR/export_segmented_usd.py" \
--source-usd INPUT.usd \
--target /World/FusedMesh \
--fragment-labels RUN/fragments/fragment_ids.u32le \
--face-labels "RUN/$PART/rev-NNN/face_labels.u32le" \
--segments "RUN/$PART/rev-NNN/selected-only/segments.json" \
--output-usd "RUN/$PART/rev-NNN/selected-only/segmented.usdc" \
--manifest "RUN/$PART/rev-NNN/selected-only/export_manifest.json"
python "$MESH_TOOL_DIR/build_selected_only_stage.py" \
--source-usd "RUN/$PART/rev-NNN/selected-only/segmented.usdc" \
--target-prim /World/SegmentedAsset/Segments/PART \
--output-usd "RUN/$PART/rev-NNN/selected-only/part-only.usdc" \
--manifest "RUN/$PART/rev-NNN/selected-only/stage_manifest.json"
Render that revision-bound part-only.usdc from every held-out camera into
RUN/$PART/rev-NNN/selected-only/renders. Keep the renders beside the revision
they validate: the render manifest must cite the exact part-only.usdc in that
same rev-NNN/selected-only directory so the launcher can checkpoint the
reviewed candidate without overwriting an earlier lock's evidence.
For repeated instances,
compare silhouettes, shells, holes/openings, and visible internal surfaces.
Inspect the isolated part as an object that must look semantically complete by
itself. Any truncated wall, discontinuous contour, unexplained jagged opening,
one-sided structure, or subset-only structure rejects the candidate. Inspect
the corresponding selected and adjacent unselected frontier fragments in the
matching flat-label and ID views, then include or exclude only confirmed whole
fragments.
For the current candidate, maintain one signed falsification evidence set:
- positive clicks covering
target_interior,target_extent, andopposing_or_occluded_surfacefor every expected instance from at least two views; - negative clicks tagged with every visible named confuser;
- one close positive/negative boundary pair per expected instance, tagged with
the same
boundary_pair_id.
Resolve these clicks independently of image-generation masks. Run
compare_face_labels.py against the immutable state from before the active
part. A selected negative face or omitted positive face rejects the candidate
even when the rendered result looks broadly plausible. Repair it and rerun the
comparison.
Apply the recovery policy after a failed review: use changed evidence or method while it produces measurable progress; otherwise defer the part and continue. Preserve every rejected revision. If the review is merely ambiguous and does not localize a false positive or false negative, keep the earlier candidate unchanged instead of editing from a new semantic guess.
4. Review, Lock, and Move On
When memory is enabled, let the launcher checkpoint the exact candidate as soon as its deterministic selected-only and frontier evidence exists. This checkpoint makes no semantic claim. If the part is revisited, search this checkpoint before gathering the new discriminating evidence. Record a changed semantic diagnosis or correction after deciding it. This is the point of memory: resume the prior decision without redoing it, while the new evidence—not the summary—still decides the correction.
When an inspection pass finds no issue, perform a separate falsification and completion review:
- inspect all sides and any relevant underside or occluded region;
- inspect close views of every visible semantic boundary;
- compare neutral, flat binary label, fragment-color, face-ID, and fragment-ID evidence from matching cameras;
- inspect the selected-only candidate from every held-out view and compare all repeated instances for both inconsistent extra geometry and incomplete shells, discontinuous contours, or unexplained openings;
- record one structured
instance_completeness_reviewsentry for every expected instance, with at least two visible selected-only views spanningprimary_surfaceandopposing_or_occluded_surface; - reject a collective phrase used as one
instance_id; an explicit expected count must have the same number of separate completeness entries; - for every missing or unresolved instance, inspect each selected component's
nearby_similar_scale_component_idsand record why every hinted component is target or non-target before accepting, revising, or deferring; - for every completeness view, classify the visible selected-only boundaries,
require
coherent_semantic_shell,outer_contour_continuous, andsemantic_openings_plausible, and record zerounexplained_boundaries; - when the exact frontier audit contains unselected fragments, check at least
one of them per completeness view and record
confirmed_non_target; when the audit is empty because the target is a complete disconnected component, record an empty checked-fragment list andnot_applicable_complete_disconnected_componentinstead; - explicitly record that both the false-positive and false-negative searches found no actionable issue;
- check every expected repeated instance;
- include at least one useful view that was not used to make the last edit;
- verify every predeclared falsifier and named confuser;
- verify that every held-out view contributed accepted positive and negative evidence and that boundary pairs challenge the candidate locally rather than merely sampling distant interiors;
- rerun signed evidence against the exact latest candidate labels;
- run the deterministic frontier audit:
python "$MESH_TOOL_DIR/audit_selection_frontier.py" \
--source-usd INPUT.usd \
--target /World/FusedMesh \
--fragment-labels RUN/fragments/fragment_ids.u32le \
--face-labels "RUN/$PART/rev-FINAL/face_labels.u32le" \
--active-segment-id PART_ID \
--output-dir "RUN/$PART/review"
The audit locates boundaries; it does not approve them. If review or signed evidence exposes one coherent mistake, write a diagnosis and return to the same render-and-pick loop. Continue with changed evidence while coverage or leakage still improves. If distinct changed attempts repeat the same defect without progress, defer the part rather than blocking the rest of the asset. Preserve the rejected revision.
Lock the part only after one complete review following the last edit produces
no further edit and the launcher-provided absolute
validate_falsification_review.py path passes. Preserve:
RUN/PART/falsification_plan.json;RUN/PART/falsification_evidence.json;RUN/PART/falsification_review.json;RUN/PART/falsification_validation.json.RUN/PART/rev-FINAL/revision_consistency_regions.json;RUN/PART/rev-FINAL/revision-consistency/manifest.jsonand every generated crop, comparison sheet, and context sheet;RUN/PART/rev-FINAL/revision_consistency_review.json.
Never hand-write falsification_validation.json, copy one from another part,
or edit falsification_review.json after validation. The validator binds the
review digest and exact evidence digests. If the review or any bound artifact
changes, delete the stale validation and run the validator again. Immediately
after it passes, write part_completion.json, record the validated-lock memory
observation when memory is enabled, and only then promote the part labels to the
next numbered state. Record every requested part's validated lock, finish the
bounded uncertainty pass, and end the turn. The launcher validates the complete
lock corpus and owns creation of state/final_labels.u32le; its first promotion
closes the timely-memory window.
Record RUN/PART/part_completion.json with the same final revision, both
falsification artifact paths, the validation digest, views inspected, expected
instances checked, remaining blind spots, and the agent's confidence rationale.
The record must list the ID-buffer manifests and state
false_positive_review: passed and false_negative_review: passed. These
strings are summaries; they have no authority without the passing validation
artifact. Promote its face labels to the parent state for the next part. Locked
assignments remain face-immutable in every run mode.
After a validated lock, begin the next part. If validation cannot pass after the recovery policy, preserve the candidate as prov
…(truncated)