Spaces:
Running on Zero
Running on Zero
kwabs22 Claude Opus 5.5 commited on
Commit Β·
b546563
1
Parent(s): 447d1d2
Archive QA feedback under feedback/
Browse filesKeeps the 2026-10-30 QA report in the repo for later reference.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
feedback/vli-qa-feedback-2026-10-30.md
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# VisualLearningIdea β QA feedback for the coding agent
|
| 2 |
+
|
| 3 |
+
**Session date:** 2026-10-30 Β· **Method:** full contract re-verification of the MCP tools via live calls, plus a read of repo HEAD (`app.py`, `SPEC.md`, `vli/grammar.py`, `vli/lexicon.py`, `vli/assets.py`, `vli/scene.py`, `vli/pipeline.py`, `vli/html.py`, `vli/simplify.py`).
|
| 4 |
+
|
| 5 |
+
**TL;DR:** The `refine_scene` contract is now **fully verified** β including the last open cell (reject on an Objaverse-tier item drops cleanly to a primitive). Everything previously tested still behaves as documented. The feedback below is 4 priority items, 3 robustness/polish items, and one build-parity question. The single most impactful fix is #1 (reroll determinism); the cheapest high-value fix is #2 (q0 labels, one line).
|
| 6 |
+
|
| 7 |
+
---
|
| 8 |
+
|
| 9 |
+
## 1. Verified contract (complete as of today)
|
| 10 |
+
|
| 11 |
+
| Change | Status | Evidence |
|
| 12 |
+
|---|---|---|
|
| 13 |
+
| `freeze: true/false` | β
| prior session; ledger round-trips `frozen` flag |
|
| 14 |
+
| `use: n` (0-indexed, swap) | β
| prior session |
|
| 15 |
+
| `reroll` swaps with the pool | β
| reproduced today: seed 0 β chosen β `alternatives[6]`, `4459b90dβ¦ β b86b2f4dβ¦`, pool unchanged |
|
| 16 |
+
| `reject` (simready β objaverse β primitive) | β
| prior session |
|
| 17 |
+
| **reject on Objaverse item β primitive** | β
**new** | today: `rejected_tiers: ["objaverse"]`, chosen = box, height re-derived to 0.3 m (`source: default`), renders clean |
|
| 18 |
+
| `shape` (primitive) | β
| prior session |
|
| 19 |
+
| `height_m` | β
| prior session; reject correctly resets only non-user heights |
|
| 20 |
+
| seed re-chooses configuration | β
| seed 0 and seed 1 re-verified today; placement details in item 6 |
|
| 21 |
+
| reject on primitive-tier β generation | β οΈ reachable dead end | today: readable error, no fallback (item 3) |
|
| 22 |
+
|
| 23 |
+
Seed-0 baseline reproduced bit-identically from the first session: uid `4459b90d0e87486b96739feb2a40e0ee` (4893 faces, license `by`), yaw β82.87678304500669Β°, sun 26.638940957447787Β°/β145.04170934144128Β°, sky `#b8aaa5`, cat z-offset 0.013124391962400764.
|
| 24 |
+
|
| 25 |
+
---
|
| 26 |
+
|
| 27 |
+
## 2. Priority items
|
| 28 |
+
|
| 29 |
+
### P1-1 Β· Reroll at a fixed seed is a toggle, not a sampler
|
| 30 |
+
|
| 31 |
+
- **Evidence:** two sessions days apart, reroll at seed 0 always swaps chosen with `alternatives[6]` (`4459b90d β b86b2f4d`, same z-offset 0.0215100129063485 both times). Seed 1 always picks slot 3 (`7c3383a2β¦`). Same input β same pick, forever.
|
| 32 |
+
- **Cause:** `pipeline.apply_changes` builds `rng = np.random.default_rng(seed)` fresh on every call, so a fixed seed always draws the same `k = rng.integers(len(alternatives))`.
|
| 33 |
+
- **Consequence:** to see a *different* asset the caller must change the seed β but the seed also re-rolls placement and sun (verified: seed 1 moved the cat to yaw 162.17Β° and the sun to 30.77Β°/134.59Β°, sky `#adacb3`). Asset exploration and configuration exploration are coupled through one number, which the docstring presents as one knob.
|
| 34 |
+
- **Suggested fix (pick one):**
|
| 35 |
+
1. derive the pick from item state so it walks the pool: `k = int(chosen["uid"][:8], 16) % len(alternatives)` β deterministic per state, changes as swaps change state;
|
| 36 |
+
2. carry a counter in the ledger (e.g. `ledger["revision"] += 1` inside `apply_changes`; seed the changes-rng from `(seed, revision)`);
|
| 37 |
+
3. at minimum, document the toggle behaviour in the `refine_scene` docstring so MCP callers know to vary the seed (and that this also moves the scene).
|
| 38 |
+
|
| 39 |
+
### P1-2 Β· `q0` "which cat?" is unanswerable β 8 identical labels
|
| 40 |
+
|
| 41 |
+
- **Evidence:** `q0.alternatives = ["cat", "cat", β¦ Γ8]` on every ledger; unchanged after rerolls; `default_chosen: "cat"`.
|
| 42 |
+
- **Cause:** `pipeline.settle_all` fills question labels via `candidate_label()`, which returns `cand.get("category")` for Objaverse candidates; the uid (present in every candidate dict) is never surfaced.
|
| 43 |
+
- **Impact:** SPEC says determiners open a "which?" question for the discussion to arbitrate; as shipped the question carries zero information β arbitration is only possible by reading `n1.decision.chosen.uid`.
|
| 44 |
+
- **Suggested fix (one line in `settle_all`):** for `unresolved` alternatives only, disambiguate, e.g. `f"{label} [{uid[:6]}]"` β `cat [4459b9]`, `cat [b86b2f]`β¦ Keep `use` positional β labels are display-only. Optionally append loaded face count later. (Bonus: `check_words`' `maps_to` already helps availability; consider adding the uid there too.)
|
| 45 |
+
|
| 46 |
+
### P1-3 Β· Generation tier is a user-reachable dead end
|
| 47 |
+
|
| 48 |
+
- **Evidence (today, end-to-end):** `refine_scene` with `[{"id":"n1","reject":true}]` on a primitive-tier item β `Error: no usable generation asset for 'cat' (generation tier is not wired up yet)`.
|
| 49 |
+
- **Good:** this is a readable `gr.Error` (via `assets.load_generation` β `UnusableAsset` β `assets.settle` β `app._fail`), *not* a raw `NotImplementedError` traceback; `app.generate_mesh` (the ZeroGPU stub) is never called, as documented.
|
| 50 |
+
- **Bad:** the `refine_scene` docstring advertises `reject` β generation, so a user/model can hit this dead end, and the mutated ledger is discarded with the error (the caller must resend their previous ledger to recover).
|
| 51 |
+
- **Suggested fix:** pre-empt in `apply_changes`/`next_tier` β when the *next* tier would be `generation`, raise a clean `ValueError` **before mutating** the decision, e.g. `"'cat' has no tier left after primitive; generation is not wired up β use shape/height instead"`. Keep the stub itself as is.
|
| 52 |
+
|
| 53 |
+
### P1-4 Β· The canonical example sentence errors as-is
|
| 54 |
+
|
| 55 |
+
- **Evidence:** `translate_to_scene("the cat sat and the sun shone")` β `Not available (no asset): sun β¦ map each to a primitive`. It only works with `primitives_json={"sun":"sphere"}`. This sentence is the example in the `check_words` *and* `translate_to_scene` docstrings and the UI placeholder, so a first-time MCP caller (e.g. HuggingChat) hits an error on the advertised happy path.
|
| 56 |
+
- **Cause:** intended, not a regression β the `simready_phrases` sun-visor guard correctly stopped indexing a lone "sun", and LVIS provides no usable sun category. The code is right; the docs lag.
|
| 57 |
+
- **Suggested fix:** swap the canonical example to a sentence that needs no primitives. Verified today: **"the cat sat and the lamp glowed"** β `ok: true` (lamp: 1 SimReady + 79 Objaverse, `maps_to: "desk_lamp"`), and a desk lamp as the light source reads nicely. Alternatively keep the cat/sun sentence but append `β¦ pass primitives_json={"sun":"sphere"}` wherever it appears.
|
| 58 |
+
|
| 59 |
+
---
|
| 60 |
+
|
| 61 |
+
## 3. Robustness / polish
|
| 62 |
+
|
| 63 |
+
### P2-5 Β· Build parity: scene-page face budget is not in effect
|
| 64 |
+
|
| 65 |
+
- **Evidence:** today's scene page for the 4893-face cat inlined **4893 faces** in its `mesh` blob. Repo `vli/html.py` sets `SCENE_FACE_BUDGET = 400` and `_geometry()` unconditionally decimates above budget (`simplify.decimate` β `simplify_quadric_decimation`); with repo HEAD, 4893 inline is impossible. Meanwhile `b86b2f4d` shipped exactly 400 β consistent with its native count (no decimation path running).
|
| 66 |
+
- **Ask:** confirm the running build matches repo HEAD (rebuild/restart if stale). If it *does* match, debug the `_geometry` budget path. Untested related path: `ladder_page`'s `LADDER_MAX_FACES = 1000` skip.
|
| 67 |
+
|
| 68 |
+
### P2-6 Β· Placement couples to asset bounds β document it
|
| 69 |
+
|
| 70 |
+
- **Evidence:** same seed 0, same yaw/sun/sky, but the cat's z-offset differs per asset: 0.0131 (`4459b90d`), 0.0215 (`b86b2f4d`), 0.0205 (box). Cause: `scene.configure` draws the same uniforms for the same seed, but multiplies the row z-jitter by the mesh's half-width, and the sun position scales with reach computed from widths. So "same seed = same scene" only holds while assets don't change (exactly what confused the previous session's "seed restored, but not bit-identically").
|
| 71 |
+
- **Ask:** either make the row z-jitter fixed in metres (so small objects don't wiggle proportionally to their own width), or add one docstring line: *placement/sun are seeded but scale with each asset's bounds; swapping an asset shifts offsets*.
|
| 72 |
+
|
| 73 |
+
### P2-7 Β· Vocabulary can drift silently between rebuilds
|
| 74 |
+
|
| 75 |
+
- `lexicon._simready_packages()` calls the unauthenticated GitHub tree API (60 req/h, shared Space IP) and silently falls back to `SIMREADY_FALLBACK` (only `nvidia/simready-assets`) on failure; `_cached_json` is per-container. The word list β the product's core promise ("the UI offers only available words") β can change without a code change.
|
| 76 |
+
- **Ask:** make drift visible and/or impossible: commit the built package index (or serve it from a pinned dataset revision), and/or expose dictionary stats in `check_words` (e.g. total words, simready package count) so callers can detect a reduced dictionary.
|
| 77 |
+
|
| 78 |
+
### P3-8 Β· Candidate pool capped at 9 of 87
|
| 79 |
+
|
| 80 |
+
- `_object_decision` and `next_tier` take `cands[1:9]` β chosen + 8 alternatives, while "cat" has 87 Objaverse candidates (lamp: 79). `use`/`reroll` can never reach the rest, and a random 9 includes junk (one of the nine was a 400-face lump that reads as a rock; another, `7c3383a2`, is excellent β the pool has both).
|
| 81 |
+
- **Ask:** raise the cap for large categories, or accept `{"id":"n1","use_uid":"β¦"}` / an offset parameter; at minimum document the cap. (Fixing #2's labels makes the 9 visible; wider access makes them matter.)
|
| 82 |
+
|
| 83 |
+
### P3-9 Β· Small DX nits
|
| 84 |
+
|
| 85 |
+
- `use` with an out-of-range index (or on empty alternatives) raises a raw `IndexError` β unhelpful message. Wrap: `"n1 has no alternative at index k (N alternatives)"`.
|
| 86 |
+
- Fallback primitives render neutral grey (`base_color` default `#b4b4b4`): the rejected cat-box is colourless in an otherwise tinted scene. Optional: tint primitives deterministically per word (hash β hue) so primitive-tier scenes read better.
|
| 87 |
+
|
| 88 |
+
---
|
| 89 |
+
|
| 90 |
+
## 4. Session probe log (exact)
|
| 91 |
+
|
| 92 |
+
1. `translate "the cat sat and the sun shone", {"sun":"sphere"}, seed 0` β n1 = `4459b90dβ¦` (4893 faces, license `by`), yaw β82.8768Β°, sun 26.6389Β°/β145.0417Β°, sky `#b8aaa5`, z 0.01312 β matches the original session bit-for-bit β
|
| 93 |
+
2. `reroll`, seed 0 β n1 = `b86b2f4dβ¦` (400 faces, pale olive), z 0.02151, slot-6 swap β identical to previous session β
|
| 94 |
+
3. `reject n1` β primitive box, `rejected_tiers: ["objaverse"]`, height 0.3 (default), q0 β `default_chosen: "box"`, `alternatives: []` β
*(closes the last untested cell)*
|
| 95 |
+
4. `reroll`, seed 1 β n1 = `7c3383a2β¦` (399 faces, reads clearly as a cat), yaw 162.1669Β°, sun 30.7664Β°/134.5948Β°, sky `#adacb3` β
*(also demonstrates placement/asset seed coupling)*
|
| 96 |
+
5. `reject n1` (primitive tier) β `Error: no usable generation asset for 'cat' (generation tier is not wired up yet)` β οΈ *(documented gap, now confirmed end-to-end)*
|
| 97 |
+
6. `check_words "the cat sat and the lamp glowed"` β `ok: true`, lamp `available_in {simready: 1, objaverse: 79}`, `maps_to: "desk_lamp"` β
|
| 98 |
+
|
| 99 |
+
**Suggested follow-ups for the agent's own QA:** `simplify_item` end-to-end (ladder rungs + `LADDER_MAX_FACES` skip), NC/ND license skip recording with a live `decision.skipped` entry, `use` back-swap idempotence after a skip shifted indices, and `check_words` on a low-memory/fallback build to observe dictionary drift.
|