feat(illustration): derive impact geometry from the factual layout in the prompt - #25
Merged
Merged
Conversation
added 2 commits
July 30, 2026 12:16
… the prompt The AI illustration could depict a different accident from the one the data describes: the forensic-reconstruction prompt described each vehicle independently and never stated how impact participants are positioned relative to each other, so a rear-end collision could render as two cars waiting side by side. Derive the real relationship (position, orientation, contact) from the Timeline's computed poses at the impact frame, the same factual layer the schematic is drawn from, and state it in plain language in both illustration prompts. Also instruct the model to render no on-image text, and drop the now-contradictory overlay-text request; the disclosure is guaranteed by the pixel burn-in (watermark.py) instead.
Drop the over-broad bare "facing" absence check (could collide with unrelated future prose) and assert the full expected relational sentence in the duplicate-impact-entry test instead of an incidental substring count.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
A judge who reads a case and then watches the AI illustration clip will notice the illustration depicts a different accident from the one the data describes. Confirmed on a real live render (case
live-forensic-retry-0bb32eeb, providergenblaze,degraded: false): the SceneGraph described a rear-end collision (red car approaching from behind, striking the stopped blue car's rear) but the render showed the two cars side by side, as if waiting next to each other at a light.Root cause
_forensic_scene_description()insrc/claimscene/report.pydescribed each vehicle independently (colour, kind, approach, maneuver, speed, damage clock positions) and never stated how the vehicles are positioned relative to each other. A text-to-image/video model has no layout instruction and invents one.Fix
layout.py'sLayoutEnginealready computes the real geometry deterministically: a metric world frame withTimedPose(x, y, heading_deg)per vehicle, time-scheduled so impact participants are in contact atimpact_time_s. This is the same factual layer the schematic renderer draws from. This PR derives an explicit spatial-relationship sentence from those poses and adds it to both illustration prompts, so the prompt becomes a faithful rendering of the factual layer instead of an independent description the model has to invent a layout for.For each impact participant after the first, relative to the first-listed one:
layout.py), bucketed into 8 compass-style directions ("directly ahead of" / "directly behind" / "to the left/right of" / the four intermediate combinations).clock_point_world), which the LayoutEngine guarantees is near zero for real impact pairs (seetest_layout.test_impact_points_touch_at_contact_frame), so this reliably reads "in contact at the point of impact"; computed rather than assumed, with an "almost touching" / omitted fallback for anything that doesn't run through the current engine.Deterministic: pure arithmetic over the Timeline's already-rounded pose floats, no randomness. Built only from the constrained vocabulary plus the computed geometry, not from re-reading the enum text. Single-vehicle scenes, parked-only scenes, and scenes with no impacts all degrade gracefully to no relationship clause (proven by dedicated tests), never a crash.
Also added an explicit "no on-image text" instruction to both prompts: the model was inventing its own on-image captions that compete with the deterministic disclosure burned into the pixels after generation (
watermark.py, PR #24). The oldOverlay text: '{DISCLOSURE}'request inillustration_promptwas removed rather than kept, since it now directly contradicts the new no-text instruction and a live render already proved the model is free to ignore such a request anyway — the pixel burn-in is the real mechanism now.Not touched
SceneGraphschema,extra="forbid",layout.py's geometry math, the schematic renderer's output,provenance.py,tests/security/, andwatermark.py(including theDISCLOSURE/WATERMARKconstants and the burn-in logic) are all untouched.Tests
New tests in
tests/unit/test_report.py: the derived spatial phrase for rear-end / two right-angle fixtures / oblique / a synthetic head-on fixture, each asserting the exact expected relational sentence built from the realLayoutEngineoutput; determinism (independently-rebuilt Timelines yield identical wording); the no-text instruction present in both prompts; the overlay-text line's removal; graceful handling of single-vehicle, parked-only, and no-impact scenes; a scene/timeline mismatch; a vehicle struck twice (dedup); and direct coverage of the two small pure helpers' remaining branches.report.pycoverage: 98%;pipeline.py: 100%.Existing tests updated (signature only, in
tests/unit/test_report.py--illustration_prompt/illustration_still_promptnow taketimelineas well asscene):test_prompts_stay_in_the_moderation_safe_forensic_register,test_still_prompt_describes_vehicles_and_damage. One genuine wording update:test_illustration_prompt_deterministic_and_self_disclosingno longer assertsDISCLOSURE in a, since the overlay line that put it there is gone.tests/integration/test_pipeline.pyneeded zero changes -- it only inspects the sealed manifest's prompt substrings, all of which are preserved.Full suite: 425 passed, 95.44% total coverage (gate is 90%). ruff clean.
Not merging
Per instructions, this PR is left open for manual review of the derived wording and a live-render check before merge.