Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions .github/workflows/vitrine-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,16 +44,21 @@ jobs:
with:
python-version: '3.12'
- name: Install light CPU test deps
# Covers the hermetic object-arc suite: numpy (object_crops), requests +
# trimesh (trellis2_client), opencv-headless (object_crops, cv2-gated).
# No torch / sam3 / gsplat — those tests defer or stub GPU deps.
run: pip install pytest pillow numpy requests trimesh opencv-python-headless
# Covers the hermetic object-arc + R&D suite: numpy (object_crops),
# requests + trimesh (generator clients), opencv-headless (object_crops,
# cv2-gated), flask (native service test). No torch/sam3/gsplat — those
# tests defer or stub GPU deps.
run: pip install pytest pillow numpy requests trimesh opencv-python-headless flask
- name: Hermetic pipeline unit tests (no GPU/container)
run: |
pytest -q \
tests/python/test_image_decoder.py \
tests/python/test_object_placement.py \
tests/python/test_object_candidate_score.py \
tests/python/test_object_orientation.py \
tests/python/test_trellis2_native_service.py \
tests/python/test_pixal3d_client.py \
tests/python/test_image_edit_view.py \
tests/python/test_config_hull.py \
tests/python/test_object_crops.py \
tests/python/test_trellis2_client.py \
Expand Down
49 changes: 49 additions & 0 deletions docs/engineering-log.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,55 @@

Development history for Vitrine (a standalone project that vendors LichtFeld Studio as a pinned tool; formerly a fork — see ADR-021).

## 2026-07-10 — R&D frontier: 4 Fable teammates, branch `feat/object-rd-frontier`

Ran a 4-agent Fable R&D fan-out on the open object-arc frontier; each teammate
owned distinct new files and returned integration diffs, consolidated serially
onto the branch. All integrations compile, the container pipeline suite is
**209 passed** (+47), and both new geometry paths are live-verified in the USD
assembler.

- **Native TRELLIS.2 service (R5)** — `scripts/trellis2_native_service.py`
fleshed out: `/health` (liveness) vs `/ready` (pipeline loaded), a full error
taxonomy (400/413/503/500, all JSON), param hardening (unparseable→default,
out-of-range→clamp, `face_count_low ≤ high`), thread-safe lazy load, 64 MB
upload cap, complete lineage. This is the durable answer to the ComfyUI drtk
fragility (the native pipeline uses nvdiffrast, not the ABI-brittle drtk
path). 15 hermetic tests. VERIFY-ON-ENV-BUILD kept on the two upstream-API
wrappers (the ComfyUI-ported tree lacks the `pipelines/` module).
- **R10 orientation solve** — `src/pipeline/object_orientation.py`: the mesh's
canonical front (+Z) corresponds to the observing crop camera's ray, so an
upright-object **yaw** is solved from the COLMAP camera pose (frame math
verified against `colmap_parser` + the assembler; COLMAP world→cam vs USD
Y/Z-flip handled). Wired through `object_placement.build_placements` →
`usd/placements.json` → the assembler's `AddOrientOp` (TRS order). Live USD
check: yaw-90 → `xformOp:orient=(0.7071,0,0.7071,0)`. Roll/pitch stay pinned
upright (single-view can't observe them); near-vertical views flagged
`degenerate`→unsolved. 17 solver tests + 2 integration tests.
- **R7 rung (b) image-edit view** — `src/pipeline/image_edit_view.py` +
`qwen_image_edit_view.json`: for objects whose best seed scores below
`escalation_threshold`, synthesize ONE "show the back" alternate view
(Qwen-Image-Edit-2509, Apache-2.0) and add it as another single-image
best-of-N candidate (NOT panel-stitching). Self-gates via
`probe_edit_model()` (the edit UNET isn't staged), flattens input alpha
(avoids the LoadImage premultiplied-ghost trap), re-mattes the output. A
winning edit-view rewrites the asset's `surface` to `image-edit-inferred`.
18 tests.
- **R8 Pixal3D** — `src/pipeline/pixal3d_client.py` mirrors the single-image
contract as a drop-in generator (opt-in, default-off, eval-gated), + the
`research/2026-07-pixal3d-eval.md` head-to-head plan. Pixal3D is **MIT** (the
ADR-025 correction), so its licence gate passes; weights are NOT staged, so
the client is a contract-validated scaffold (VERIFY-ON-ENV-BUILD), never
live-run. `eval/objects/run_eval.py --generator pixal3d` added. 13 tests.

Integration hygiene: config.py gained `Pixal3DConfig` + `ImageEditConfig` +
Trellis2Config escalation fields; stages `_generate_object_from_crop` gained a
Pixal3D primary tier + the image-edit rung (best-of-N tuple widened, backward
compatible — the default single-shot path is byte-identical). CI now runs all
four new hermetic suites (+flask dep). One correction applied during
integration: the orientation camera-pose reads from `provenance` (the crops
manifest), not `crop_entry`, which the teammate's diff had assumed.

## 2026-07-10 — R7 best-of-N quality ladder + drtk self-heal hardened

### R7 — best-of-N seed re-rolls with a silhouette-consistency scorer
Expand Down
10 changes: 9 additions & 1 deletion eval/objects/run_eval.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,13 @@ def run_generation(crops_dir: Path, out_dir: Path, generator: str, seed: int) ->
client = Trellis2Client.from_config(cfg.trellis2)
res = client.reconstruct_from_image(crop, seed=seed, label=name)
glb = res.glb_data
elif generator == "pixal3d":
# R8 head-to-head: constructs the client directly, so the eval
# never needs the pipeline flag flipped (cfg.pixal3d.enabled).
from pipeline.pixal3d_client import Pixal3DClient
client = Pixal3DClient.from_config(cfg.pixal3d)
res = client.reconstruct_from_image(crop, seed=seed, label=name)
glb = res.glb_data
else:
from pipeline.hunyuan3d_client import Hunyuan3DClient
client = Hunyuan3DClient.from_config(cfg.hunyuan3d)
Expand Down Expand Up @@ -171,7 +178,8 @@ def main() -> int:
ap = argparse.ArgumentParser(description=__doc__.splitlines()[0])
ap.add_argument("--crops", type=Path, help="Directory of object crops (RGBA PNGs)")
ap.add_argument("--out", type=Path, help="Output directory for GLBs + metrics")
ap.add_argument("--generator", choices=["trellis2", "hy3d21"], default="trellis2")
ap.add_argument("--generator", choices=["trellis2", "hy3d21", "pixal3d"],
default="trellis2")
ap.add_argument("--seed", type=int, default=42)
ap.add_argument("--stats-only", type=Path, metavar="GLB",
help="Grade one existing GLB and exit (no generation)")
Expand Down
Loading
Loading