Skip to content

Navigation Menu

Sign in
Sign up

fix(aebs): correct forward-situation visualization geometry - #180

Merged
de4sdv merged 10 commits into
main from
fix/aebs-forward-situation-geometry
Sep 6, 2026
Merged

fix(aebs): correct forward-situation visualization geometry #180
de4sdv merged 10 commits into
main from
fix/aebs-forward-situation-geometry

Conversation

@de4sdv

@de4sdv de4sdv commented Sep 1, 2026
edited
Loading

Copy link
×ばつ its fixture footprint (plus a lateral ×ばつ stretch) while the filtered obstacle cloud used the true scene scale. During INTERVENTION the cyan cluster visually touched the ego although the fixture geometry never brings them into contact — a viewer could reasonably read this as a collision. 2. **Glow pre-contact.** The cyan point glow (11 px halo) extended apparent contact beyond the projected point positions. 3. **Fringed EGO label.** The `EGO` text sat on the silhouette boundary; at ×ばつ600 anti-aliasing blended the glyphs into the vehicle edge. ## Changes (presentation-only) ### 1. One scene scale (isotropic) - `sceneGeometry()` now derives a single metre-per-pixel factor (`MAX_RANGE_M / usableHeight`) used by **both** axes; the lateral projection divides by the same factor as the footprint conversion. Ego footprint, obstacle points, and range ticks all share it, so on-screen separation now equals real fixture separation. - The ego silhouette is drawn at the **true fixture footprint** (front 3.74 m, rear 1.03 m, width 1.83 m), taken from the pure render model (`SituationRenderModel.EGO_*_M`). No presentation multiplier exists anymore. At ×ばつ600 the fixture-true silhouette is ~14 px wide (~7.4 px per metre); the circular emphasis halo of the earlier generation is **removed** (see the repair round below) and the silhouette renders as a crisp bright core only. The represented physical dimensions are never enlarged. ### 2. Point glow is decoration only - Glow 11 px → **6 px**, core 5 px → **3.5 px** (`POINT_GLOW_PX`/`POINT_CORE_PX`). Radii are constants, documented as visual decoration that does not represent physical extent; point-rendering size is never usable as object extent. ### 3. EGO label below the silhouette - Label is drawn **below** the silhouette with a fixed **5 px clearance** (`EGO_LABEL_CLEARANCE_PX`) between the boundary and the glyphs; light-on-dark for contrast against both the vehicle edge and the background. The footprint is not enlarged to fit the label. ### 4. Engineering-status panel: displayed obstacle range - New rows: `Displayed obstacle range 13.4 m` (closest projected point of the filtered obstacle cloud = `target_range`, display-derived, `%.1f m`) with the smaller clarification `filtered point cloud`. - The row is **diagnostic only**: it is not a native Autoware AEB decision distance, is never compared against `rss_distance`, is never shown beside a braking/RSS threshold, and never feeds state or reducer logic. It clears fail-closed on stale/invalid/unavailable together with the scene geometry. - The former `AEB decision distances not visualized` boundary row is removed (the HMI shows only available engineering information). Native AEB decision metrics remain intentionally not shown. - No reducer, bridge, Gateway, protobuf, SysML, or AEB-behavior changes. The read-only System 2 boundary is unchanged; the renderer still contains no collision detection or decision semantics. ### 5. Documentation - `VISUALIZATION-CONTRACT.md` §13 (new): presentation-scale and diagnostic-range contract — one consistent metre-per-pixel scale, no ego enlargement, decorative glow, label clearance, displayed-range semantics and its explicit non-claims, unchanged prohibited list. §10 table corrected to match code (the "visually emphasized 2.5x" row no longer exists). ### 6. Tests - `tests/test_aebs_visualization_hmi_presentation_contract.py`: extended/added guards for no ego metric-scale exaggeration, fixture-footprint correspondence, approved obstacle-range wording, absence of the native-metrics row and of any target-range/RSS comparison, no renderer dependency from obstacle geometry to AEBS state, fail-closed clearing of the displayed range, EGO-label clearance, and (repair round) no circular ego halo. Source-level guards pin policy text; the numeric geometry behavior is pinned on the JVM (below), not by screenshots. - `SituationRenderModelTest` (JVM): fixture-dimension and scale guards. - `SituationSceneGeometryTest` (JVM, repair round): behavioral scene geometry — isotropic projection, fixture-true front/rear/width bounds, decoration containment at the fixture minimum separation, label clearance with actual glyph ascent. Reviewed local commit: `4cd3f1d` (campaign head); evidence and hygiene-pin commits follow (`5e836e8`, `98655d5`) ## Repair round (post-#188 merge, head `d47ee556`) `origin/main` (with merged #188) was merged into this branch (merge commit `49d1bfe`, no conflicts) and two remaining renderer defects were repaired: 1. **Rear footprint shortened.** `bottom = originY + rear * 0.4f` contradicted the claimed fixture-true footprint. The presentation multiplier is removed: the rear bound is the full fixture rear (1.03 m) via the new `SituationSceneGeometry.egoFootprintRectPx()`. The renderer no longer owns any footprint math. 2. **Circular halo beyond the footprint.** The ego emphasis halo was bounded by the longitudinal span only — nothing constrained it to the vehicle width, so it always extended past the projected footprint boundary (width ~6 px at ×ばつ600). An inscribed circle would still be footprint-sized at this viewport, so the halo is **removed**; the ego renders as a crisp core only. Containment is no longer argued from constants: the JVM tests pin projected bounds numerically. Supporting changes: scene projection and footprint bounds are extracted to the Android-free `SituationSceneGeometry` (same JVM-testable pattern as the render model; added to the `de4sdv_aebs_visualization_render_model` java_library), and two branch-local tests written against pre-#188 lifecycle semantics were repaired (the absence-arc test now records the arc, asserts no WARNING and a RELEASED end; the footprint guard no longer contradicts the constants it asserts). ## Validation Local (Jetson, head `d47ee556`): - `python scripts/check_repo.py` → passed - `python scripts/smoke_test.py` → passed - `git diff --check` → clean - JVM suites (`SituationSceneGeometryTest` + `SituationRenderModelTest` + `VisualizationStateReducerTest`) → **OK (37 tests)** - Focused presentation/view pytest → **16 passed** - Remaining suite failures (4, semantic-MCP/ingestion) reproduce identically on clean `origin/main` — missing local tool-managed deps, not introduced here. Independent review trail: - Round 1 (snapshot `d47ee556`): **FAILED** — one confirmed logic error: `drawEgo()` invoked the new geometry methods on the view's private `float[] sceneGeometry()` helper, so `SituationSceneGeometry` was never instantiated and the app tree would not compile (invisible to the JVM harness, which compiles only the Android-free classes). Snapshot identity and all test suites verified by the reviewer. - Round 2 (head `f99fbc3`): **PASSED** — round-1 fix verified, android-stub view compile exit 0, JVM OK (37 tests), focused pytest 16 passed, geometry math and guards verified; non-blocking notes adopted in the docs commit. - Round 3 (head `4cd3f1d`, docs/comment-only delta): **PASSED** — delta scope clean, contract wording consistent, JVM OK (37 tests), pytest 16 passed. The retained past-tense "2.5x" mention in the §13 preamble is historical root-cause narrative documenting the defect, not current behavior. - CI: `checks` green at `4cd3f1d` (run 34041425127). The evidence commit (`5e836e8`) then failed CI on the media-manifest count pin (18 == 22) — the full-suite hygiene guard the focused run does not execute; the pin was consciously bumped to 22 with the new entries named (`98655d5`), full suite green locally (906 passed; the 4 pre-existing mcp/.sysand failures excluded as on clean main), and CI is green at the final head `98655d5` (run 34046507952). A post-review correction (`f97fda8`) replaced an unsupported 'clearance ≥ 120 px' claim in the evidence disposition with the bounded visual observation plus renderer-arithmetic support, and repointed the per-instant .jpg references to their maintainer-archive location (registered in `external-media.yaml`). PR stays draft pending Orkun's review; merging requires explicit approval. Historical (pre-merge head `0ae1f41`): vmA AOSP build `De4sdvAebsVisualizationApp` + `De4sdvAebsVisualizationReducerTest` (`sdv_core_cf-trunk_staging-userdebug`) BUILD_SUCCEEDED; JVM tests on that build output OK (26 tests). Superseded as current evidence by this head. ## Runtime evidence status — final combined campaign EXECUTED (head `4cd3f1d`) The final combined acceptance campaign ran on the single-VM bench with the exact repaired head staged from `git archive` (provenance chain in `EXACT_HEAD_PROVENANCE.txt`) and **verified build identity**: - built APK sha256 = installed APK sha256 = `66ec6609a81f80d545fd0fc4e5f99ab63ee373c418a6ceb8e551b91f90a96303` (`APK_IDENTITY_MATCH`); dex probe confirms the new geometry class is present and no halo residue exists. The #188 campaign validated the image-bundled app; this campaign validates THIS APK. - JVM gate on the build output: OK (37 tests), including `SituationSceneGeometryTest`. - 009D profile verified on the live node: `use_object_velocity_calculation = False`. Acceptance items (×ばつ600), all **pass** — evidence in `evidence/010/forward-ui/final-hmi-v22-geometry/`: | Item | Verdict | Evidence | | --- | --- | --- | | Correct scale and footprint | pass | one isotropic scale; 20.6 m read at the 20 m tick; fixture-true ego incl. full rear; no halo | | No misleading contact | pass | bounded visual observation: no touch/overlap incl. 6 px decorative glow at 20.6 → 15.7 → 10.7 m closest approach (renderer arithmetic: ~51.5 px metric gap at 10.7 m, glow edge ~45 px short); halo removed | | Clean presentation | pass | EGO label + range row readable, no clipping | | Fail-closed behavior | pass | ingress stop → STALE gray, scene cleared, range em-dash; restore → LIVE (p180-fc-*.png) | | Lifecycle regression | pass | pixel-verified MONITORING → WARNING → INTERVENTION → RELEASED (B→O→R→G); 1318 app frames, 0 seq gaps | | Observer warning-lead | pass | warning_lead_s = 1.034 ≥ 0.8 (single regression run; no regression exposed, so the #188 three-run protocol was not repeated) | Non-claims preserved: the observer evaluator outcome remains `fail_scenario` on the documented footprint-collection issue (pre-existing from #188, not an HMI defect) — `pass_observed_chain` is NOT claimed; scenario safety outcome remains `deferred_not_proven`; read-only visualization issues no vehicle commands. Segment disposition: `observed_bounded`. Video bytes are registered in `external-media.yaml` (maintainer archive per the evidence-management policy); PNG stills, text evidence, and `SHA256SUMS` are in-tree. ## Scope boundaries (unchanged by this PR) Autoware AEB behavior, scenario behavior, reducer/state semantics, ROS bridge engineering semantics, Gateway transport, the read-only System 2 boundary, and vehicle control behavior are all untouched. No radar sweep, RSS reference geometry, braking-threshold visualization, target-range/RSS comparison, renderer-side thresholds, invented classification, lane/FOV geometry, or collision semantics are reintroduced. " data-view-component="true"> Copy Markdown
Owner

fix(aebs): correct forward-situation visualization geometry

Follow-up to merged PR #164. PR #164 remains the accepted integration/evidence
baseline; its evidence history is untouched and is not rewritten by this PR.

Problem (post-merge presentation defects)

After the #164 recording was reviewed, three presentation defects were
confirmed in the final HMI generation:

  1. False visual ego/obstacle contact. ForwardSituationView drew the ego
    silhouette at ×ばつ its fixture footprint (plus a lateral ×ばつ stretch) while
    the filtered obstacle cloud used the true scene scale. During INTERVENTION
    the cyan cluster visually touched the ego although the fixture geometry
    never brings them into contact — a viewer could reasonably read this as a
    collision.
  2. Glow pre-contact. The cyan point glow (11 px halo) extended apparent
    contact beyond the projected point positions.
  3. Fringed EGO label. The EGO text sat on the silhouette boundary; at
    ×ばつ600 anti-aliasing blended the glyphs into the vehicle edge.

Changes (presentation-only)

1. One scene scale (isotropic)

  • sceneGeometry() now derives a single metre-per-pixel factor
    (MAX_RANGE_M / usableHeight) used by both axes; the lateral projection
    divides by the same factor as the footprint conversion. Ego footprint,
    obstacle points, and range ticks all share it, so on-screen separation now
    equals real fixture separation.
  • The ego silhouette is drawn at the true fixture footprint (front 3.74 m,
    rear 1.03 m, width 1.83 m), taken from the pure render model
    (SituationRenderModel.EGO_*_M). No presentation multiplier exists anymore.
    At ×ばつ600 the fixture-true silhouette is ~14 px wide (~7.4 px per metre);
    the circular emphasis halo of the earlier generation is removed (see the
    repair round below) and the silhouette renders as a crisp bright core only.
    The represented physical dimensions are never enlarged.

2. Point glow is decoration only

  • Glow 11 px → 6 px, core 5 px → 3.5 px (POINT_GLOW_PX/POINT_CORE_PX).
    Radii are constants, documented as visual decoration that does not represent
    physical extent; point-rendering size is never usable as object extent.

3. EGO label below the silhouette

  • Label is drawn below the silhouette with a fixed 5 px clearance
    (EGO_LABEL_CLEARANCE_PX) between the boundary and the glyphs; light-on-dark
    for contrast against both the vehicle edge and the background. The footprint
    is not enlarged to fit the label.

4. Engineering-status panel: displayed obstacle range

  • New rows: Displayed obstacle range 13.4 m (closest projected point of the
    filtered obstacle cloud = target_range, display-derived, %.1f m) with the
    smaller clarification filtered point cloud.
  • The row is diagnostic only: it is not a native Autoware AEB decision
    distance, is never compared against rss_distance, is never shown beside a
    braking/RSS threshold, and never feeds state or reducer logic. It clears
    fail-closed on stale/invalid/unavailable together with the scene geometry.
  • The former AEB decision distances not visualized boundary row is removed
    (the HMI shows only available engineering information). Native AEB decision
    metrics remain intentionally not shown.
  • No reducer, bridge, Gateway, protobuf, SysML, or AEB-behavior changes. The
    read-only System 2 boundary is unchanged; the renderer still contains no
    collision detection or decision semantics.

5. Documentation

  • VISUALIZATION-CONTRACT.md §13 (new): presentation-scale and
    diagnostic-range contract — one consistent metre-per-pixel scale, no ego
    enlargement, decorative glow, label clearance, displayed-range semantics and
    its explicit non-claims, unchanged prohibited list. §10 table corrected to
    match code (the "visually emphasized 2.5x" row no longer exists).

6. Tests

  • tests/test_aebs_visualization_hmi_presentation_contract.py: extended/added
    guards for no ego metric-scale exaggeration, fixture-footprint correspondence,
    approved obstacle-range wording, absence of the native-metrics row and of any
    target-range/RSS comparison, no renderer dependency from obstacle geometry to
    AEBS state, fail-closed clearing of the displayed range, EGO-label clearance,
    and (repair round) no circular ego halo. Source-level guards pin policy text;
    the numeric geometry behavior is pinned on the JVM (below), not by screenshots.
  • SituationRenderModelTest (JVM): fixture-dimension and scale guards.
  • SituationSceneGeometryTest (JVM, repair round): behavioral scene geometry —
    isotropic projection, fixture-true front/rear/width bounds, decoration
    containment at the fixture minimum separation, label clearance with actual
    glyph ascent.

Reviewed local commit: 4cd3f1d (campaign head); evidence and hygiene-pin commits follow (5e836e8, 98655d5)

Repair round (post-#188 merge, head d47ee556)

origin/main (with merged #188) was merged into this branch (merge commit
49d1bfe, no conflicts) and two remaining renderer defects were repaired:

  1. Rear footprint shortened. bottom = originY + rear * 0.4f contradicted
    the claimed fixture-true footprint. The presentation multiplier is removed:
    the rear bound is the full fixture rear (1.03 m) via the new
    SituationSceneGeometry.egoFootprintRectPx(). The renderer no longer owns
    any footprint math.
  2. Circular halo beyond the footprint. The ego emphasis halo was bounded by
    the longitudinal span only — nothing constrained it to the vehicle width, so
    it always extended past the projected footprint boundary (width ~6 px at
    ×ばつ600). An inscribed circle would still be footprint-sized at this
    viewport, so the halo is removed; the ego renders as a crisp core only.
    Containment is no longer argued from constants: the JVM tests pin projected
    bounds numerically.

Supporting changes: scene projection and footprint bounds are extracted to the
Android-free SituationSceneGeometry (same JVM-testable pattern as the render
model; added to the de4sdv_aebs_visualization_render_model java_library), and
two branch-local tests written against pre-#188 lifecycle semantics were
repaired (the absence-arc test now records the arc, asserts no WARNING and a
RELEASED end; the footprint guard no longer contradicts the constants it
asserts).

Validation

Local (Jetson, head d47ee556):

  • python scripts/check_repo.py → passed
  • python scripts/smoke_test.py → passed
  • git diff --check → clean
  • JVM suites (SituationSceneGeometryTest + SituationRenderModelTest +
    VisualizationStateReducerTest) → OK (37 tests)
  • Focused presentation/view pytest → 16 passed
  • Remaining suite failures (4, semantic-MCP/ingestion) reproduce identically on
    clean origin/main — missing local tool-managed deps, not introduced here.

Independent review trail:

  • Round 1 (snapshot d47ee556): FAILED — one confirmed logic error:
    drawEgo() invoked the new geometry methods on the view's private
    float[] sceneGeometry() helper, so SituationSceneGeometry was never
    instantiated and the app tree would not compile (invisible to the JVM
    harness, which compiles only the Android-free classes). Snapshot identity
    and all test suites verified by the reviewer.
  • Round 2 (head f99fbc3): PASSED — round-1 fix verified, android-stub
    view compile exit 0, JVM OK (37 tests), focused pytest 16 passed, geometry
    math and guards verified; non-blocking notes adopted in the docs commit.
  • Round 3 (head 4cd3f1d, docs/comment-only delta): PASSED — delta scope
    clean, contract wording consistent, JVM OK (37 tests), pytest 16 passed.
    The retained past-tense "2.5x" mention in the §13 preamble is historical
    root-cause narrative documenting the defect, not current behavior.
  • CI: checks green at 4cd3f1d (run 34041425127). The evidence commit
    (5e836e8) then failed CI on the media-manifest count pin
    (18 == 22) — the full-suite hygiene guard the focused run does not
    execute; the pin was consciously bumped to 22 with the new entries named
    (98655d5), full suite green locally (906 passed; the 4 pre-existing
    mcp/.sysand failures excluded as on clean main), and CI is green at the
    final head 98655d5 (run 34046507952). A post-review correction
    (f97fda8) replaced an unsupported 'clearance ≥ 120 px' claim in the
    evidence disposition with the bounded visual observation plus
    renderer-arithmetic support, and repointed the per-instant .jpg
    references to their maintainer-archive location (registered in
    external-media.yaml).
    PR stays draft pending Orkun's review; merging requires explicit approval.

Historical (pre-merge head 0ae1f41): vmA AOSP build
De4sdvAebsVisualizationApp + De4sdvAebsVisualizationReducerTest
(sdv_core_cf-trunk_staging-userdebug) BUILD_SUCCEEDED; JVM tests on that
build output OK (26 tests). Superseded as current evidence by this head.

Runtime evidence status — final combined campaign EXECUTED (head 4cd3f1d)

The final combined acceptance campaign ran on the single-VM bench with the
exact repaired head staged from git archive (provenance chain in
EXACT_HEAD_PROVENANCE.txt) and verified build identity:

  • built APK sha256 = installed APK sha256 =
    66ec6609a81f80d545fd0fc4e5f99ab63ee373c418a6ceb8e551b91f90a96303
    (APK_IDENTITY_MATCH); dex probe confirms the new geometry class is
    present and no halo residue exists. The fix(aebs): deterministic warning-lead for 009D coordinator chain #188 campaign validated the
    image-bundled app; this campaign validates THIS APK.
  • JVM gate on the build output: OK (37 tests), including
    SituationSceneGeometryTest.
  • 009D profile verified on the live node: use_object_velocity_calculation = False.

Acceptance items (×ばつ600), all pass — evidence in
evidence/010/forward-ui/final-hmi-v22-geometry/:

Item Verdict Evidence
Correct scale and footprint pass one isotropic scale; 20.6 m read at the 20 m tick; fixture-true ego incl. full rear; no halo
No misleading contact pass bounded visual observation: no touch/overlap incl. 6 px decorative glow at 20.6 → 15.7 → 10.7 m closest approach (renderer arithmetic: ~51.5 px metric gap at 10.7 m, glow edge ~45 px short); halo removed
Clean presentation pass EGO label + range row readable, no clipping
Fail-closed behavior pass ingress stop → STALE gray, scene cleared, range em-dash; restore → LIVE (p180-fc-*.png)
Lifecycle regression pass pixel-verified MONITORING → WARNING → INTERVENTION → RELEASED (B→O→R→G); 1318 app frames, 0 seq gaps
Observer warning-lead pass warning_lead_s = 1.034 ≥ 0.8 (single regression run; no regression exposed, so the #188 three-run protocol was not repeated)

Non-claims preserved: the observer evaluator outcome remains fail_scenario
on the documented footprint-collection issue (pre-existing from #188, not an
HMI defect) — pass_observed_chain is NOT claimed; scenario safety outcome
remains deferred_not_proven; read-only visualization issues no vehicle
commands. Segment disposition: observed_bounded. Video bytes are registered
in external-media.yaml (maintainer archive per the evidence-management
policy); PNG stills, text evidence, and SHA256SUMS are in-tree.

Scope boundaries (unchanged by this PR)

Autoware AEB behavior, scenario behavior, reducer/state semantics, ROS bridge
engineering semantics, Gateway transport, the read-only System 2 boundary, and
vehicle control behavior are all untouched. No radar sweep, RSS reference
geometry, braking-threshold visualization, target-range/RSS comparison,
renderer-side thresholds, invented classification, lane/FOV geometry, or
collision semantics are reintroduced.

Follow-up to merged PR #164 (accepted integration/evidence baseline;
its evidence history is untouched and remains the historical record).
Presentation defects after the merge: the ego silhouette was drawn at
2.5x (plus lateral 1.4x) its fixture footprint while obstacle points
used the true scene scale, so during INTERVENTION the cyan cluster
visually touched the ego although the fixture geometry never brings
them into contact; point glow extended apparent contact beyond the
projected points; and the EGO label blended into the silhouette edge
at 1080x600.
- ForwardSituationView: one isotropic metre-per-pixel scale for ego
 footprint, filtered obstacle points, and ticks; ego drawn at the TRUE
 fixture footprint (3.74/1.03/1.83 m) from the pure render model with
 a presentation-only halo that never extends the represented
 dimensions; point glow reduced 11/5 px -> 6/3.5 px; EGO label moved
 below the silhouette with fixed 5 px clearance. No renderer-side
 collision detection, no new decision semantics.
- MainActivity + layout + strings: engineering-status panel shows
 'Displayed obstacle range' (diagnostic, closest projected point of
 the filtered cloud, %.1f m) with 'filtered point cloud'
 clarification; removed the 'AEB decision distances not visualized'
 row; displayed range clears fail-closed on stale/invalid/unavailable
 with the scene geometry; never compared with rss_distance.
- SituationRenderModel: owns the public fixture footprint constants.
- SituationRenderModelTest: fixture-dimension and scale guards.
- tests/test_aebs_010_hmi_presentation_contract.py: presentation-scale,
 diagnostic-range wording, label-clearance, and fail-closed guards.
- VISUALIZATION-CONTRACT.md: new section 13 (presentation-scale and
 diagnostic-range contract); sections 10 table and section 8 checks
 updated to match code.
Review feedback: no age-in-ms visualization anywhere on the HMI.
- Health chip shows health state + rate only ('くろまる LIVE · 10 Hz');
 the '· age N ms' suffix is gone.
- 'Frame age' metric row removed from layout, strings, and render path.
- Staleness logic is UNCHANGED: frameAgeMs remains the internal input to
 the STALE health label and the reducer/watchdog fail-closed behavior;
 only rendering was removed.
- Test updated: reflection sweep asserts no String getter exposes an
 age value; geometry-independence assertion retained.
- VISUALIZATION-CONTRACT.md §6/§7 updated to record the no-age-display
 boundary.
... WARNING
Pins the v22 campaign shape: when upstream never supplies warning=true,
the HMI disposition sequence is exactly MONITORING -> INTERVENTION ->
RELEASED with no WARNING ever rendered (honest read-only representation).
Complements warningPrecedesIntervention which covers the warning-first path.
de4sdv pushed a commit that referenced this pull request Sep 6, 2026
Three independent runtime campaigns staged from exact head 108bfa9
(archive sha256 fed9458c...56e905), executed 2026年09月06日 on the bench VM:
lifecycle_gate warning_lead_s 1.1103 / 1.1123 / 0.9238, all >= 0.8 s
minimum, live use_object_velocity_calculation=False verified per run,
WARNING frames precede first braking frame with zero sequence gaps in
the app-frame log, full lifecycle recorded on camera (stills retained).
footprint_outcome remains a documented bounded non-pass (footprint
collection stops before the gate command); pass_observed_chain is not
claimed. App is image-bundled pre-#180 generation: HMI geometry claims
stay separated until a combined-head run.
Videos are maintainer-archive only; identities added to
external-media.yaml (15 -> 18 entries). Restores the media-hygiene
guards the 009B repair had clobbered in tests/test_evidence_repository_hygiene.py
(video bytes untracked, no empty placeholders, manifest identity) and
updates the manifest count assertion to 18.
de4sdv added a commit that referenced this pull request Sep 6, 2026
* fix(aebs): deterministic warning-lead for 009D coordinator chain
Root cause (2026年09月02日 v22 campaign): the HMI correctly rendered
MONITORING -> INTERVENTION because no warning_request=true ever existed
at the source (0/900 samples). Two stacked upstream defects:
1. Nondeterministic native AEB intervention: the pinned upstream object
 velocity estimator (calcObjectSpeedFromHistory) derives object speed
 from collision-point displacement between AEB cycles. In v22 it
 produced a constant wrong estimate (object_speed_mps=-4.17 against a
 target receding at +1.0 m/s), inflating rss_distance_m to 23.45 at a
 20.0 m bumper gap and firing native intervention at first sight. The
 estimator output depends on the ego spawn location's surrounding
 pointcloud (v21: +2.45 m/s, rss 13.7; v22: -4.17, rss 23.45), so the
 warning-lead contract was not reproducible. Fix: pin
 use_object_velocity_calculation=false in the bench AEB parameter
 calibration so RSS depends only on ego kinematics. The moving-target
 claim then rests on coordinator geometry, the ego-speed trajectory,
 and the deterministic RSS schedule. Prototype fixture setting, not a
 product requirement (scenario non_claims).
2. Coordinator latch race: a native intervention diagnostic arriving
 between two publish ticks transitioned the latch to braking_latched
 before the warning condition was evaluated, permanently erasing a
 warning that already held from observed geometry (arm-only latch
 rule). Fix: evaluate the warning condition against the
 PRE-diagnostic latch state at diagnostic arrival via the new pure
 function warning_on_intervention_diagnostic(); semantics preserved —
 the warning still requires real geometry + real RSS + the margin, and
 is never fabricated when geometry inputs are absent.
Hard evidence gates: the observer result document now carries a
lifecycle_gate block with warning_lead_min_s, first_warning_timestamp_s,
first_intervention_timestamp_s, warning_lead_s, and a pass/fail gate
value, so campaign eligibility for the full lifecycle claim is
determined from authoritative source timestamps, not video.
Tests: test_warning_lead_determinism.py covers the race case with
geometry present (warning latches pre-transition), the no-geometry case
(no fabrication), the absent-condition case (no creation), the pinned
parameter, and the 0.8 s contract; evaluator-level tests pin the valid
lifecycle pass, the v22-shaped intervention-before-warning failure
(fails at native_risk_assessment, no fabricated lead), and that
warning_lead_s is recorded from accepted-event timestamps.
* fix(aebs): isolate 009D AEB calibration + freshness-bound race evaluation
Review tightening for the deterministic warning-lead fix (three points):
1. Freshness-bounded race evaluation: warning_on_intervention_diagnostic()
 now takes explicit input ages; both RSS and point-distance must carry
 non-negative ages within geometry_max_age_s (new coordinator parameter,
 default 0.2 s — the override/odometry max-age class, one AEB cycle of
 slack at the 10 Hz diagnostic cadence). The coordinator records source +
 receipt nanosecond timing for both inputs at receipt and combines the
 source-stamp lag with the receipt-to-diagnostic lag at evaluation time.
 Stale, future-stamped, or missing inputs behave like unavailable inputs
 and never create/latch a warning: the run stays honestly
 MONITORING -> INTERVENTION when the race loses real geometry. Fail-closed
 on future/invalid timing.
2. 009D AEB calibration isolated: the shared aebs-009b.param.yaml is
 REVERTED to the pinned authority (use_object_velocity_calculation: true,
 unchanged 009B behavior). The 009D override now lives in
 config/aebs-009d.param.yaml (static-surrogate velocity model, full
 derivation comment). The launch file takes aeb_param_file (default:
 aebs-009b.param.yaml); scripts/launch.sh passes
 aeb_param_file:=aebs-009d.param.yaml only in 009D mode. setup.py ships
 the 009D file; execution_identity binds both calibrations.
3. Moving-target limitation explicit: two new 009D scenario non_claims
 record that disabling native object-velocity calculation does not
 validate Autoware moving-object relative-velocity estimation or
 moving-target braking performance, and that the target still moves at
 1.0 m/s (not stationary) — REQUIRED_009D_NON_CLAIMS extended so the
 closed claim-boundary set enforces it.
The lifecycle_gate block (first_warning_timestamp_s,
first_intervention_timestamp_s, warning_lead_s, warning_lead_min_s,
pass/fail) is unchanged and remains the sole full-lifecycle-claim authority.
Tests extended: fresh/missing/stale-RSS/stale-point/both-stale/future
freshness matrix, exact-boundary age, 009B authority revert, launch wiring.
17 tests in test_warning_lead_determinism.py pass; full bench suite green
except pre-existing host-environment artifacts (missing map/run script,
verified identical on origin/main).
* docs(aebs): correct AEB-cycle timing comment (0.2 s = two 10 Hz periods)
* fix(aebs): freshness-bounded warning race + isolated 009D calibration
Completes the warning-lead determinism repair (INC-AEBS-009D):
- warning_on_intervention_diagnostic takes explicit input freshness ages
 (rss_age_s, point_distance_age_s, geometry_max_age_s) and fails closed on
 stale, future-stamped, missing, or non-finite geometry; an existing warning
 is retained without recreating history.
- Coordinator records receipt times for RSS and point-cloud caches,
 invalidates caches on invalid/empty samples, bounds the race path AND the
 periodic 20 Hz publish path with the same freshness window, and no longer
 evaluates warnings from stale cached geometry.
- Scenario-specific 009D calibration config/aebs-009d.param.yaml
 (use_object_velocity_calculation: false) with honest non-claims; 009B
 calibration unchanged. Launch takes aeb_param_file (default 009B); launch.sh
 passes the 009D file only in 009D mode; setup.py ships it; execution
 identity binds it.
- Moving-target non-claims added to the closed 009D scenario set (estimator
 disabled; target still moves; static model applies to fixture RSS only).
- Test contract updated to the shared evidence pipeline: retired
 run_override_profile.sh references replaced by launch.sh + contract-009d.yaml
 assertions; stale expected error strings corrected to the actual
 'independent replay' messages.
- Restored the five 009B run artifacts deleted by #68 while the canonical
 scenario-evidence.json still hash-binds them (the cause of the pre-existing
 clean-checkout map-runtime test failure); SHA-256s match the manifest.
- New repair guards pin race freshness, periodic freshness, calibration
 isolation/shipping, and contract-test currency.
Validation: bench suite 126 passed (was 13 failed / 4 passed at 560dcc6);
check_repo, smoke_test, git diff --check pass; repo suite 899 passed with the
two test_sysml_full_ingestion failures reproduced identically on pristine
origin/main (pre-existing, unrelated). Exact-head CI and the privileged
validation run, plus the 009D runtime campaign, remain required before merge.
* fix(evidence): track hash-bound 009B run artifacts, drop empty log per policy
The previous commit restored four deleted run artifacts (launch.log,
map-runtime.json, observer-raw.json, run-metadata.json) that the canonical
scenario-evidence.json hash-binds, but a plain git add silently skipped them:
.gitignore excludes implementation/*/evidence/**/runs/. Track them with
git add -f, byte-identical to b20834d where they were first committed, so
clean checkouts and CI replay the canonical evidence again.
The zero-byte observer.log is deliberately NOT restored: per
docs/evidence-management.md a zero-byte file is not evidence. Its retained
manifest reference carries the well-known empty-string SHA as documented
sentinel semantics, asserted by the new hygiene guard along with the
hash-binding of the four restored artifacts and the ignore-rule context.
* evidence(aebs): exact-head 009D warning-lead campaign for PR #188
Three independent runtime campaigns staged from exact head 108bfa9
(archive sha256 fed9458c...56e905), executed 2026年09月06日 on the bench VM:
lifecycle_gate warning_lead_s 1.1103 / 1.1123 / 0.9238, all >= 0.8 s
minimum, live use_object_velocity_calculation=False verified per run,
WARNING frames precede first braking frame with zero sequence gaps in
the app-frame log, full lifecycle recorded on camera (stills retained).
footprint_outcome remains a documented bounded non-pass (footprint
collection stops before the gate command); pass_observed_chain is not
claimed. App is image-bundled pre-#180 generation: HMI geometry claims
stay separated until a combined-head run.
Videos are maintainer-archive only; identities added to
external-media.yaml (15 -> 18 entries). Restores the media-hygiene
guards the 009B repair had clobbered in tests/test_evidence_repository_hygiene.py
(video bytes untracked, no empty placeholders, manifest identity) and
updates the manifest count assertion to 18.
---------
Co-authored-by: de4sdv <de4sdv@users.noreply.github.com>
Co-authored-by: Orkun Yilmaz <orkun.y92@googlemail.com>
...JVM-tested scene geometry
Merge origin/main (post-#188) into fix/aebs-forward-situation-geometry.
- Ego rear bound is the full fixture rear (1.03 m): the presentation
 multiplier (rear * 0.4f) that shortened the rendered footprint is gone.
- The circular ego emphasis halo is removed: a circle cannot stay inside
 the projected fixture-true footprint (width ~6 px at 1080x600), so any
 glow beyond the footprint boundary read as false visual contact
 (VISUALIZATION-CONTRACT.md 13.1).
- Scene projection and footprint bounds are extracted to the Android-free
 SituationSceneGeometry (same JVM-testable pattern as the render model)
 and pinned by SituationSceneGeometryTest: isotropic projection, front/
 rear/width bounds, decoration containment at the fixture minimum
 separation, and EGO label clearance using actual font bounds
 (getTextBounds ascent).
- Android.bp: render-model java_library carries the geometry class; the
 java_test module picks the new test up via app/tests/**.
- Presentation-contract pytest guards re-pointed from view-internal
 formulas to the geometry class; new guard asserts no circular ego halo.
- Two branch-local tests written against pre-#188 semantics repaired:
 the absence-arc test now records the arc and asserts no WARNING with a
 RELEASED end (matching its own documented intent), and the footprint
 guard no longer contradicts the fixture constants it asserts.
JVM suites: 37/37 green locally (JUnit 4). Presentation/view pytest:
16 passed. check_repo/smoke/diff-check pass. Remaining suite failures
reproduce identically on clean origin/main (missing local mcp/.sysand
deps) and are not introduced here.
Independent review finding (confirmed): drawEgo called egoFootprintRectPx/
egoLabelBaselinePx on sceneGeometry() — the view's private float[] helper —
so the pure geometry class was never instantiated and the app tree would
not compile. Both call sites now construct the class at the reference
viewport dimensions. Local android-stub harness (View/Paint/Canvas/
Color/Rect/RectF) now compiles ForwardSituationView, closing the blind
spot that let this through the first round (the JVM test harness compiles
only the Android-free classes). JVM 37/37, focused pytest 16, check_repo
and diff --check green at this commit.
...halo removal
Round-2 review non-blocking findings, adopted:
- The fixture width projects to ~14 px at 1080x600 (7.4 px/m), not the
 stale ~5-6 px estimates; view comment and pytest comment corrected.
- VISUALIZATION-CONTRACT 13.1 now records the halo REMOVAL instead of the
 superseded 'radius never exceeds the footprint span' rule, and the 10
 table row no longer claims 'visually emphasized 2.5x' rendering.
- Dead-wiring recurrence guard: the presentation contract now asserts the
 view instantiates SituationSceneGeometry (round-1 review suggestion).
Comment/doc-only; no behavior change. JVM 37/37, view stub-compile, 16
pytest, check_repo, diff --check green at this commit.
Single-VM campaign on the exact repaired head (staged from git archive,
provenance chain in EXACT_HEAD_PROVENANCE.txt; APK sha chain
66ec6609a81f80d545fd0fc4e5f99ab63ee373c418a6ceb8e551b91f90a96303 with
APK_IDENTITY_MATCH and dex probe: geometry class present, no halo residue).
The #188 campaign validated the image-bundled app; this campaign validates
THIS APK build.
Acceptance items (all pass, at 1080x600):
- scale/footprint: one isotropic scale, fixture-true ego incl. full rear
- no misleading contact: no touch/overlap at 20.6/15.7/10.7 m closest
 approach incl. 6 px decorative glow; halo removed (still-verified)
- clean presentation: EGO label and range row readable, no clipping
- fail-closed: STALE gray + scene cleared + range em-dash on ingress stop;
 LIVE restored after restart (p180-fc-*.png)
- lifecycle: pixel-verified MONITORING -> WARNING -> INTERVENTION ->
 RELEASED (B->O->R->G at 2 fps scan), 1318 app frames, 0 seq gaps
- observer warning-lead regression retained: warning_lead_s = 1.034 >= 0.8
 (single run; no regression exposed, #188 three-run protocol not repeated)
Non-claims preserved: observer evaluator outcome remains fail_scenario on
the documented footprint-collection issue (pre-existing from #188, not an
HMI defect); scenario_safety_outcome deferred_not_proven.
Video bytes registered in external-media.yaml (maintainer archive per
docs/evidence-management.md); PNG stills + text evidence + SHA256SUMS
retained in-tree.
The full-suite hygiene guard pins the external-media manifest count; the
final-hmi-v22-geometry campaign added four entries (raw take + three
inspection frames) with complete identity (sha256, bytes, disposition,
availability, absence in-tree). Found by CI at 5e836e8; local fix verified
against the full hygiene suite (6 passed).
...ervation
Review correction: segment.yaml claimed 'clearance >= 120 px at closest
approach' from the retained 1080x600 still. That number is unsupported -
the still supports no-overlap, not a numerical pixel clearance (a naive
color-segmentation attempt fails on scene-scale landmarks like tick labels
and the bottom dock, so no defensible pixel measurement exists from the
compressed capture). Replaced with the bounded visual observation plus
renderer-arithmetic support: 10.7 m displayed range vs 3.74 m fixture
front = 6.96 m metric gap, ~51.5 px at ~7.4 px/m scene scale, glow leading
edge ~45 px short of the ego front bumper - consistent with the
projection-based containment pinned by SituationSceneGeometryTest.
Also resolves the three cited per-instant .jpg evidence references: they
are NOT in the committed bundle; they are held in the maintainer archive
and registered with sha256 in external-media.yaml. The evidence pointers
now name the retained stills and state the archive location explicitly.
de4sdv marked this pull request as ready for review September 6, 2026 18:12
de4sdv merged commit 489b865 into main Sep 6, 2026
1 check passed
de4sdv deleted the fix/aebs-forward-situation-geometry branch September 6, 2026 18:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

No reviews

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

1 participant

AltStyle によって変換されたページ (->オリジナル) /