10 KiB
B4 lifecycle Scene rendering — 2026-09-11
Author: Codex-ytr83r /root/server_audit, reassigned from the completed REST review to B4 rendering under root's Gitea issue #1 comment #155. Ownership announced in #157. Scope: behavior.rs lifecycle bridge, pure module declaration, dedicated rendering and Scene tests. No core semantics, schema/source/REST, staged-source creation, chooser or CLI changes; no Cargo or Git mutations. Root integrates, builds and controls native QA. Codex-ytr83r /root/integration_audit independently reviews the frozen source and owns the separate native fixture/oracle.
Implementation and decisions
Root execution update: the first completed current-host desktop compile on
cb611a7 failed101 at14:43:51.917UTC after2391.367seconds. It reported16 occurrences
of ambiguous Size in the added clip geometry tests and one production
LineDash.offset type mismatch. Raw log/status are preserved in
experiments/lifecycle-native-ytr83r-20260911/desktop-resume2-compile-failed*.
This is a real compile failure, distinct from the two reboot interruptions.
Root corrected the test import to explicit iced::Size and the zero dash offset
from floating-point to usize. No geometry, lifetime/source/model or assertion
changed. Scoped rustfmt and whitespace check pass; cached compiled rerun and
native acceptance remain pending. Earlier source freezes below retain their
original attribution.
The frozen pure scenario_lifecycle traversal is now used in production. Its conservative local-tree rules remain unchanged: exact receiver IDs; no inferred receiver from an exchange; independent ALT/Optional/Loop/Parallel operands; uncertain continuation after a lifecycle-bearing fragment; opaque ScenarioUse; no Reply invention, model commands or serialization writes.
behavior/scenario_lifecycle/render.rs contains a separate Rendering record. Neutral dotted guides and stronger scoped Alive spines are distinct from message Lines. The complete rendering lane map includes unassigned lifelines; existing Scene.lanes remains the represented-lane authoring eligibility map. Neutral top headers say Lane · name. A small footer explains guide, lifetime and ? uncertainty marks; unanswered call cues keep their existing ellipsis, avoiding two meanings for the same glyph.
The bridge gives root lifetime the actual visible span 85..scene.height−20, leaving insertion/slot bounds unchanged. Empty operands also need a nonzero visible lifetime allowance: their unchanged insertion bounds are (top,top), while existing open activation geometry reserves 26 px inside the 42 px body allowance. The dedicated lifetime scope gives those operands top..top+26. This preserves the independently alive empty sibling in the required ALT regression without changing insertion meaning.
Create capsules are 140×28, centered on the exact receiver lane and recorded occurrence row. The arrow ends on the sender-facing capsule edge. Delete X is centered on that lane/row. Both carry the original occurrence ID. Exact capsule/X shape hits precede named boxes and exact message-label rectangles; one shared nearest-distance arbitration across marker shapes and message strokes follows, using the existing 8-screen-pixel bound and persistent UUID tie breaking. Activation/guide hits remain the fallback. Neutral headers/guides retain the lifeline ID. Incomplete receiver-without-exchange records retain their explicit marker; receiver=None never borrows the global exchange endpoint.
Self lifecycle arrows end at the marker's recorded row, using a local elbow 24 px above it and 112 px to the right. Their row receives 16 px additional clearance before slot and row positions are recorded. This addresses the independent critic's Action/State/reference box overlap: the self caption at row−52 clears the previous box, whose bottom is previous-row+50. Ordinary Create captions are moved to row−40, above the capsule's top at row−14. No independent hidden coordinate is used for selection/reorder.
Activation geometry is intersected with Alive intervals for the exact receiver and structural scope. A local Delete ends that path's visible activation with an unresolved-call cue; each sibling is still visited independently. Post-fragment Absent/Unresolved intervals contain no definite activation rectangles or Reply caps. The call/reply records and correlation are unchanged. Root explicitly selected this scoped clipping over simply clipping at a Delete while leaving a solid bar in uncertain continuation.
Independent criticism addressed before execution
The critic found a concrete minimum-Fit selection defect in the first rendering draft: at scale 0.05, adjacent Create/Delete rows 92 world pixels apart are only 4.6 screen pixels apart; the later Delete's expanded 8-pixel hit tolerance stole an exact birth-capsule center. The initial correction fixed exact centers/header hits but still let an earlier message's expanded stroke tolerance steal a practical off-X click. Root selected shared nearest-distance arbitration over merely moving marker halos ahead of all strokes. Final code compares both kinds under one bound and protects exact visible shapes and labels. Regression cases cover adjacent incomplete-receiver centers/header at 0.05/0.1/0.5/1/2, ±15/±25-world-pixel death offsets at minimum Fit, and an ordinary message genuinely nearer than a lifecycle halo. The independent reviewer read back this second revision and reported both counterexamples closed with no further confirmed material finding in the bounded source review. These were draft source-derived defects, not executed/native failures; the regressions have not yet run.
Verification status
Executed: direct rustfmt over the four owned Rust files, --edition 2024 --config skip_children=true, exit 0; tracked git diff --check, exit 0. No Cargo, compiled test, real application rendering, screenshot or native acceptance is claimed by this worker. All new fixture helpers require ordinary validate_candidate and accepted Document::from_bundle before asserting Scene behavior; tests may not weaken admission to obtain desired drawings.
Ten new tests under behavior::scenario_lifecycle::render::tests exercise actual Scene construction:
- Empty and Create-only root visible extents, unchanged insertion scopes, sender lifetime, and no lane masquerading as a message Line, OA/SA.
- Create→Action→Delete intervals, capsule/X endpoint alignment, caption clearance, marker/header/guide ID selection at 0.5×/1×/2×, OA/SA.
- Call→ALT(left Delete, right empty): left bar stops at death, right retains its own open bar/lifetime, post-fragment unresolved continuation has no definite bar, unanswered-call cues remain, no Reply is created, OA/SA.
- Warning-admitted unassigned lifeline with explicit incomplete Create receiver remains rendered/selectable while retaining authoring eligibility; missing receiver is not inferred, OA/SA.
- Adjacent Create/Delete capsule/X centers and neutral header keep original IDs at minimum Fit and four larger scales; off-X death offsets beat the earlier message tolerance, using an incomplete receiver.
- A genuinely nearer ordinary-message stroke wins over lifecycle marker halos at 0.05/0.1 scale.
- Explicit self Create/Delete endpoint/marker alignment with unresolved exchange, OA/SA. Admission remains a gate; no unsupported semantics may be forced if a fixture fails.
- Self Delete caption clears the immediately preceding action box and its slot still follows the recorded row.
- Actual ALT/Optional/Loop/Parallel geometry keeps lifecycle-bearing continuation unresolved and leaves unrelated sender lifetime definite.
- A meaningful Create→Asynchronous type edit changes lifetime geometry and source; one Document Undo and Redo restores exact accepted Project, complete authored CRLF/Unicode SourceBundle, marker/lifetime geometry and history availability, OA/SA.
Every ordinary Scene fixture also checks repeatable rendering, finite message coordinates, exact accepted Project/source snapshot preservation, no dirty/history/revision change. Existing ten pure projection tests retain their original scope; these Scene tests specifically address the three frozen independent integration findings.
Handoff and remaining gates
Changed Rust paths: crates/oa-desktop/src/behavior.rs, crates/oa-desktop/src/behavior/scenario_lifecycle.rs, new crates/oa-desktop/src/behavior/scenario_lifecycle/render.rs and render_tests.rs. This report is the only new owned evidence path. The previous server audit report was separately corrected to classify its ff615d0 schema-label finding as already resolved by incoming c6 integration.
Root's first focused filters: scenario_lifecycle, then all direct_canvas_tests to cover existing message selection, slots, presses/releases, reorder, scrolling cancellation and activation regressions. Follow with relevant core scenario tests, complete desktop tests and strict Clippy. Independent source review and exact-binary native QA are required before accepting B4: minimum/wide layouts, long Unicode captions, both arrow directions, incomplete lanes, self arrows, marker/guide distinctions, nested operands, history/reopen and zoom/scroll input. The separate native fixture/oracle preserves exact complete source and explicit retained-file origin policy. No release acceptance follows from this implementation report.
Separate built-in guide follow-up
Root subsequently assigned guide content only; Gitea ownership #189. Read the current Scenarios article and its existing creation, alternatives, interface operation and definition/use instructions before editing. Added two short explanation cards to crates/oa-desktop/src/guide.rs: reading lane headers/guides, solid lifetimes and Create/Delete capsule/X selection; distinguishing ? path-dependent lifetime from unanswered-call … and inspecting lifecycle inside a referenced definition without inferring caller creation/deletion. Added lifecycle/birth/death/capsule search keywords. Existing sections and both branches' authoring/navigation instructions are unchanged. No renderer internals or new model-error claim is exposed.
Guide source freeze SHA256: 8D66EBF46BB088C24B03532593429EDC3DE34239F63D7D0D1D027DBE2C211926. Scoped diff is 9 inserted lines and 1 replaced keyword line. Direct rustfmt of guide.rs only and git diff --check pass. No Cargo, tests, native validation, renderer/core/source change, language-spec change or global-setting mutation was performed in this follow-up. Root owns integration and actual guide/layout acceptance.