Files
ARCADIA-Studio/harness/release-contextual-source-creation-review-20260911.md

393 lines
31 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Contextual source creation: independent preimplementation review
Codex-9e8r6t /root/behavior_audit, 2026-09-11. Reviewed the proposed
`release-contextual-source-creation-plan-20260911.md` against committed
`4bb4aaf3dc47b9738625b4d3f23ef8c74f286395` desktop contracts and current unchanged
core. Read AGENTS, revised PROJECT_GOAL, Gitea issue1 through #138, empty open PR
inventory and LocalBehaviorCreation20260911 Wiki. No evolving implementation was
read; no production edits, Cargo, direct rustc or native input. These are
source-derived integration traps and exact acceptance expectations, not findings
against the new implementation. Urgent items were sent directly to its author.
The proposed staged-source transaction is coherent for Lifeline, process Work
and new machine owner. Keep qualified Action allocation, new ScenarioUse targets
and the external chooser implementation outside this slice. The following
existing contracts require explicit handling; a generic wrapper is insufficient.
## Ranked material traps
1. **P1 — New first-action routes can implicitly commit another editor.**
In committed `app.rs:2326`, non-creation `starts_form()` invokes `self.apply()`.
A new first-lifeline/contribution button routed to the existing Start event,
arriving while a valid raw property draft exists, commits that property
before opening its form. The explicit Canvas Choose guard does not protect
this route. Reject source/property/pending conflicts in the actual new App
event path before generic Apply; a disabled button alone cannot guard stale
dispatch. Assert accepted snapshot/history and all raw strings unchanged.
2. **P1 — Stale scenario owners can panic before transaction validation.**
`scenario.rs`'s `parents()` always includes the supplied owner ID, even if that
element is absent. A recovered Lifeline draft therefore passes the first
destination check in `Draft::command`, then `sources()` at line 941 indexes
`p.elements[&d.owner]`. A removed owner can panic before `execute_batch` gets
a chance to reject it. Validate owner existence/kind/layer/viewpoint before
candidate rendering and parent planning. Show repair/cancel with both raw
drafts retained. Do not interpret a same UUID with changed kind or viewpoint
as the unchanged invocation merely because a new source still exists.
3. **P2 — Nesting the old process batch loses consumer selection.**
`topology/direct.rs:209` scans only immediate Batch children for a newly
created contribution. `Batch[CreateSource, Batch(parent_commands)]` therefore
returns no contribution selection. Core `session.rs:386` uses the last
selected operation and `SetSteps` at line 703 selects the process owner.
Flatten with preserved command order, or carry the exact prepared command's
consumer target through success. Test the actual App selection, including
rejection of changed/trailing commands borrowing that target.
4. **P2 — Stable source identity does not make the combined plan stable.**
`scenario.rs:1274` still creates a fresh Lifeline via `make_element` each
prepare; `topology.rs:476–508` creates fresh occurrence and link UUIDs.
Reserve/cache the complete created identity set, including repaired links.
With a blank consumer label, source and consumer share a display name: the
source already owns its alias in the private preview, so the consumer alias
includes its UUID suffix. Replacing only the temporary consumer ID leaves an
alias derived from a discarded UUID. All aliases, endpoints, SetSteps,
parent references and optional machine/view IDs must use the reserved set.
Require full prepared-Command equality across preview/retry/recovery, not
merely equality of the source UUID or final object count.
5. **P2 — A fresh Work source cannot satisfy every captured insertion.**
`topology.rs:438–449` requires a Work target next to an Exchange contribution
to equal that exchange's exact source/target UUID. A newly created Function
cannot equal an existing endpoint. The plan's successful “between two
contributions” case should use Action→Action. An Exchange-adjacent case must
refuse and retain both names and the exact slot; it must not retarget the
shared exchange, change a reusable definition, choose a different source or
silently append. Keep the existing full compatibility check on the preview.
## Semantic constraints that the new source form must expose accurately
`validation.rs:92` separates source containment from its use. Activity may be
root-owned or owned by Activity; Function by Function; OA Entity/Actor/Role may
be roots or children of Entity. Current SA System and SystemActor admit no
semantic parent, so a new SA owner is a root even when its machine is nested
under it. Neither process, scenario nor lifeline owns new work. A new Lifeline
belongs directly to its scenario, never an operand, and does not enter its
ordered steps (`session.rs:336` attaches Occurrences only).
`viewpoint_represents` at validation.rs:1262 admits Activity, Function,
Entity/Actor/Role, and System/SystemActor for the four explicit viewpoints
respectively. Role is valid for an OA participant lifeline but **not** a machine
owner: `Kind::is_performer` at model.rs:153 excludes Role. SA System uniqueness
is a hard project-wide error at validation.rs:238. A second System must refuse,
even if named differently; an Actor requires a separate explicit choice.
Do not turn completeness warnings into new blockers. Unallocated leaf work and
a missing SA System are warnings. Adding a lifeline to an already reused callee
can also be accepted while existing uses gain `missing_lifeline_binding`
warnings (`validation.rs:2112`); keep all caller bindings unchanged. By contrast,
an explicitly incompatible binding is an error. Compatibility uses represented
identities or explicit RoleRealization/RoleAssignment, never equal names
(`validation.rs:1283`, `:2073`). A new same-named Role does not impersonate an
existing referenced role, and staging it creates no realization or allocation.
Persist authored state and reserve identities, but separate it from runtime
canvas generations. Existing behavior recovery deliberately drops viewport and
revision tokens (`behavior.rs:789`); App reset gives a fresh `canvas_document`.
A recovered valid draft must be rebound to that runtime document without
reusing stale event invocations. A child invocation token must still reject
late Use/Name/Back events after that child was cancelled/reopened. Passive
scroll/viewport epoch changes must neither discard input nor count as a semantic
context change. New optional recovery fields must preserve older pending forms.
## Compact exact acceptance matrix
Use separate fixed symbols for source `S`, consumer `C`, child invocation `I`,
new link `L`, and optional machine/view/placement `M/V/N`. Only a new cancelled-
then-reopened invocation may reserve a new set. Every accepted row compares the
complete Project and SourceBundle against the explicit delta; every refused or
cancelled row requires exact accepted baseline and raw-draft preservation.
| Case | Exact expected result |
| --- | --- |
| OA activity lifeline | OperationalActivity scenario; source **Assess distress**, consumer **Assessment role**. Exactly Activity `S` at selected valid work parent/root and Lifeline `C` under the original scenario with `represented=S`. Names remain separate, description/body defaults empty, scenario steps unchanged. No allocation, capability involvement, actor, view or placement. Blank consumer label uses the source name; explicit label follows the existing consumer trimming policy, while raw text remains exact during staging. |
| SA function lifeline | Functional scenario, no existing Function/System. Exactly Function `S` at root or selected Function parent plus Lifeline `C`, with fixed represented identity. Missing allocation/System warnings do not cause fallback or automatic participant creation. Wrong-viewpoint source kind refuses. |
| OA Role and reuse mapping | ParticipantInteraction scenario can create Role `S` plus Lifeline `C`; no relationship is inferred. An existing local Actor maps to an existing referenced Role only through its explicit realization. A new same-named Role without that relationship cannot satisfy the old binding. While editing a reused callee, adding `C` leaves both existing caller-use records byte-for-byte unchanged; missing-binding warnings are expected, not auto-binding or rejection. |
| SA boundary and new owner kinds | BoundaryInterface permits explicit System/SystemActor, not Function/Role. Empty SA permits one new System; existing System makes another System refuse unchanged. Explicit SystemActor remains valid. Role cannot own a machine. Illegal source-parent choices refuse; source-parent change must not become machine-parent change. |
| Work at exact Action→Action link | For captured `A —(R, guard g)→ B`, source `S`, contribution `C`: add root/valid-parent work `S`; `C` is `Action { action:S, lifeline:None }` owned by that process. Preserve `R`'s ID/name/alias/guard and change only its target to `C`; add `L: C→B` with empty guard; insert `C` in the captured order. All sibling paths and referenced definitions unchanged. Select `C`. Repeat preparation/recovery with exactly the same new IDs/aliases. |
| Work next to Exchange / stale slot | A new UUID cannot equal the captured existing exchange endpoint; refuse without changing it. Also remove/change the captured link or presentation-before ID between staging and Apply: retain both drafts and require an explicit position repair. Never fall back to current selection or append. |
| Machine before participant | Name machine **Rescue modes**, opt into first view, stage explicit valid participant **Rescue team**. Commit exactly participant `S` + machine `M` with `parent=S`; optional view `V` named **Rescue modes · states**, StateMachine projection, one placement `N`, no regions/states/routes. Select/open `M/V`. Child Back restores prior owner; parent Cancel creates nothing. Re-selecting an existing owner commits no abandoned staged source. |
| Invocation, recovery and Escape | Parent label, source raw name, search, original reference, viewpoint, slot and IDs survive child opening/Back/recovery. Old invocation `I` cannot affect a reopened child `I2`, even with identical names and owner IDs. Restored valid drafts survive the fresh runtime canvas ID; missing owner refuses without panic. Overlay Escape closes the overlay first, then child Back, then parent Cancel. The focused captured-Escape path must follow the same ordering. |
| Semantic first action and history | With no semantic contributions, first-work action is directly visible; with no lifelines/occurrences, first-lifeline action is visible. An unresolved lifeline (`represented=None`), offscreen content, ScenarioUse or fragment prevents a false “empty” claim. A lifeline-only scenario gets applicable guidance without inventing an exchange/action allocation. CTA appearance/resize and rejected stale Start leave model/source/history/raw properties unchanged. |
For committed names with leading/trailing whitespace, pin source and consumer
policies explicitly: current scenario/topology planners trim an explicit
consumer label; they do not overwrite it with the selected source's label. Do
not claim all committed names remain byte-exact by inspecting only raw recovery.
One Undo must restore the prior Project and reachable SourceBundle, while disk
Save may retain newly detached source files. Use the corrected oracle's explicit
history origin: disk equals the first committed checkpoint's file map overlaid
with expected reachable files; unknown/changed retained bytes fail. Redo/reopen
uses original committed role IDs, not newly borrowed replacement UUIDs.
This matrix deliberately excludes qualified Action allocation and new reuse
definitions. Those require further explicit semantic intent; they are not
required to validate this staged-source slice. The external chooser remains
owned separately. Implementation review and native evidence follow only after
the author freezes the new source.
## Independent implementation review, 2026-09-11
Codex-9e8r6t `/root/behavior_audit`. Resumed after the author froze the first
production candidate. Read issue #1 through #151 and traced the actual App,
behavior dispatch, nested draft, recovery, view, and command-selection paths.
The author made explicitly identified corrections between the first and second
compile windows. This reviewer edited only this report and ran no Cargo, rustc,
native input, or implementation tests. The author's first compilation exposed
missing Clone derives; no passing runtime result is inferred from that compile.
Five independently derived counterexamples were sent directly to the author
and root. All five have corresponding corrections in the second frozen source
inspected here. The following is source verification, pending the author's
19-case focused gate and root's native acceptance.
| Priority / finding in first candidate | Concrete counterexample and consequence | Correction inspected in second frozen source |
| --- | --- | --- |
| P1: missing pending owner can panic while rendering another owner | Recover source draft for scenario A after A is absent, with another same-layer scenario B present. `behavior::selected_owner` returns pending A, while `behavior::view` falls back to B. B's workspace calls `scenario_context().expect(...)`, but the context still resolves absent A and is None. Process fallback has the same mismatch. With no other owner, the pending form is hidden behind New instead. Safe `sources()` and `prepare_pending()` do not protect this render path. | `behavior::view` now checks the pending owner's presence/kind/layer before choosing a fallback. It shows the retained consumer name plus current child form or explicit parent Cancel. The child Back remains reachable; it never silently opens B as the pending consumer. New orphan-view tests construct both no-choice and remaining-B cases. |
| P1: staged recovery completeness was assumed by presentation | Recover selected staged source with `source.staged.kind = null`, a valid value for its serialized `Option<Kind>`. Deserialization accepts it; `State::label` then calls `unwrap()` and panics in parent view/selection before command validation can return its existing missing-kind error. | `source_draft::State::label` is now total and displays a missing-kind label. Planning still refuses; raw recovery remains intact. A malformed-kind regression exercises both planning and the label. |
| P2: owner-first machine creation cannot leave its valid child | New → Machine, leave machine name blank, Create new owner, choose valid kind/name, Use. The source is valid, but the parent handler calls `next.command(p)` and refuses the blank machine name. Parent edits are locked while the child is open; Back drops the entered owner before the machine can be named. | Machine Use stages the valid prerequisite and checks the actual eligible-owner predicate on its private preview. It does not require an already complete machine. Final Submit still validates the complete batch. The owner-first regression keeps the same source/name while the machine is subsequently named. |
| P2: footer Back disagrees with Escape on retained stale/dirty recovery | After recovering unrelated dirty source/property text, App rejects every source event, including Back. After deleting/changing the owner, scenario/topology validate the origin before dispatching Back; the helper also compares scope first. The visible Back button refuses although global Escape succeeds through `source_back()`. | Token-only `source.dismiss` runs before semantic context checks. App exempts only `Source(Edit::Back)` from other-editor admission. Wrong/old tokens still refuse; Open and Use keep their guards. Added dirty-editor and deleted-owner Back regressions preserve parent/property state. |
| P2: new empty actions accept a previous owner's event | Capture A's new first-action message, navigate to clean B or another layer, then deliver A's bare `Start(owner, tool)`. That route checks dirtiness and owner existence but carries no context. It can open A; `selected_owner` prioritizes the resulting pending owner. | Scenario CTAs now use `CanvasEvent::First(Context, Tool)` through the existing context and dirty guards, with a fresh semantic emptiness check. Process first Work uses its existing context-bound Begin with the explicit default insertion. A new owner/layer-stale CTA regression rejects old context and admits the current one. |
The source changes address the reported mechanisms. Their tests are authored
regressions, not independently executed evidence in this review. In particular,
constructing an orphan view prevents the identified `expect` panic but does not
by itself prove its footer can be clicked at the minimum native window size.
The unchanged core contracts are used correctly in the inspected paths:
- App form start/source admission checks raw source and property dirtiness
without calling generic Apply. Source/parent submission retains the existing
dirty guard. Model-menu and modal Escape precedence is resolved before child
Back, then parent cancellation. Raw edits and form rendering create no
accepted model/history operation.
- Source commands keep source name, semantic parent, kind, layer, document, and
exact captured consumer/parent identity distinct from the consumer. Existing
validation admits Role only where appropriate, enforces System uniqueness,
and preserves allowed completeness warnings. No allocation, role realization,
reuse binding, or shared exchange retargeting is inferred.
- For an actively selected staged source, the helper previews the source,
prepares the original consumer, remaps every new element/relation identity
and typed reference plus SetSteps to the reserved set, then forms one flat
validated batch. Recomputed aliases use the reserved IDs rather than an
abandoned temporary UUID. Machine/view/placement identities remain reserved
by the existing creation planner. This review does not claim that the older
non-staged planners reserve their IDs across separate preparations.
- App compares the complete prepared staged command before assigning its
consumer selection, and assigns it only after `Document::execute` succeeds.
Parent acknowledgement follows success. Choosing an existing reference makes
the staged source inactive: preview/combine omit it, so it is not published.
Parent Cancel drops the entire pending state.
- Captured process link identity/endpoints and presentation-before slot remain
validated. Work insertion preserves the existing guarded link and adds the
new successor link; a fresh source next to an existing Exchange still cannot
impersonate the required endpoint and refuses with raw input retained.
- New empty guidance counts semantic Lifeline/Occurrence/contribution records,
rather than rendered positions. An unresolved lifeline is still a lifeline;
ScenarioUse, fragment, and offscreen content do not become empty merely
because of presentation. Existing scenario canvas/scroll slots remain in the
surrounding workspace tree while the explicit child form occupies its form
pane.
The author deliberately made explicit staged-consumer names exact, including
leading/trailing whitespace; source names are also exact, and a blank consumer
continues to default to its chosen source name. This supersedes the earlier
matrix's inherited trimming expectation **for active staged-source consumers**.
The older existing-reference consumer path still has its pre-existing trim
policy. Native/oracle expectations must distinguish those paths and must not
borrow an observed output name to define the expected model.
Second frozen source fingerprints captured at approximately 11:39 UTC:
| File | SHA-256 |
| --- | --- |
| `crates/oa-desktop/src/app.rs` | `81E0AA21A93126D716E628B3EBD440201AB19D6B578E2585F5E500072244D58B` |
| `crates/oa-desktop/src/behavior.rs` | `A0E595F17F254002F1FBD7984EEB679320DAB042CA310C38D8916F0055713780` |
| `crates/oa-desktop/src/behavior/source_draft.rs` | `32057E30C0526FA674D463F47C4EAC7C0F391B1F4C5060757981A3CBED16C6AE` |
| `crates/oa-desktop/src/behavior/scenario.rs` | `759805631BE9E8526DACFB959D91C76CA1A2A40F47F8645BCEB0E0C15B77E326` |
| `crates/oa-desktop/src/behavior/topology.rs` | `8E1C65AFE4C7C097F683B33A6DF237219F48AFD1E81F81329B07612F4D6994CC` |
| `crates/oa-desktop/src/behavior/creation.rs` | `BE75840293E84FCAE90DC6D17CCD6630A586B389FB189ADF73D1E9B046CE3DE2` |
| `crates/oa-desktop/src/behavior/contextual_source_tests.rs` | `242B68E0DFF14E57E1F510EA3DEA95ED1B2ADCDABFD24C9F493FC871CB50F049` |
No additional implementation blocker was found in this bounded review. Required
evidence still includes terminal focused checks and native minimum/wide form
authoring, plus independent complete model/source comparison for actual
source/consumer creation and Undo/Redo/reopen. The earlier explicit detached-file
retention rule remains unchanged. No native result, full-suite result, or release
completion is claimed here.
## Final staged-source delta review, 2026-09-11
Codex-9e8r6t `/root/behavior_audit`. Reviewed only the changes after the recorded
second freeze: compact consumer captions, explicit creation summaries, recovered
typed-scope validation, nested semantic-parent and callee/caller regressions,
guide correction, and App Undo/Redo result handling. Read the final author gate
and current Gitea decisions through #178. No production edits, Cargo, rustc or
native input; root retains the immutable full-suite run and native acceptance.
The source inspected in this pass matched all ten corresponding entries in
`.local/contextual-source-20260911/focused4-inputs.json`: App, behavior, source
draft, scenario, scenario workspace, topology, topology view, creation,
contextual-source tests and guide. This identifies the precise compiled source
without presenting the earlier second-freeze fingerprints as current.
### Concrete corrections identified at the final boundary
1. **P2 — The State machine guide still directs the user out of the new flow.**
At `guide.rs:547`, the first step says to cancel and create a missing owner in
Architecture; the immediately following new step describes Create new owner
with the retained machine draft. The old sentence would unnecessarily lose
the user's pending setup and hides the new supported route. Sent directly to
the author/root; the author removed it after the Clippy source freeze and
this reviewer confirmed the source readback. The guide's previously rejected
`explain` argument count is already corrected in the passing focused4 source.
2. **P2 — The source origin must survive inactive dependency planning.**
The author identified this additional case before review closure, and this
reviewer independently confirmed its actual code path. Start a Lifeline or
Work form with a valid existing target, open Create new source, then Back.
`source.engaged` remains true, but there is no editing/active staged source.
`check_scope` and `preview` therefore pass without a source-side document
check. Parent `Draft::command` at scenario.rs:1350/topology.rs:582 then reaches
its ordinary consumer planner against a different `Project.id` with the same
owner and target UUIDs. The captured `source_origin` is checked only while
handling Source events. Use followed by reselecting an existing source has
the same inactive-dependency mechanism. This is a concrete preparation-boundary
failure; no claim is made that ordinary file navigation preserves the form
through its existing App reset.
The narrow proposed correction checks captured document plus exact owner at
final command preparation whenever source creation has been engaged, keeping
token-only Back and cancellation available. Regression must begin with a
valid existing target, prove baseline preparation succeeds, then refuse the
other document while retaining all raw fields. A compatibility edge was sent
separately: old recovered forms legitimately have `source_origin=None` and
unengaged default source state. Their first successful source Open should bind
the current origin; an already engaged missing/mismatched origin must never
be silently rebound. The author implemented these document/legacy controls
after the source freeze, with a valid-target Scenario/Work × Back/inactive ×
ordinary/legacy regression matrix. That later source is not covered by
focused4 and no new execution is claimed here.
**One final owner-binding detail remains at this handoff.** The initial new
guard compares the captured owner with `p.elements.get(&owner.id)`. A recovered
origin can contain another valid, unchanged same-layer owner B while the
parent draft still targets A. That lookup validates B against itself; the
otherwise valid consumer planner still operates on A. Compare the captured
owner record with `p.elements.get(&self.owner)` in final planning and
`p.elements.get(&d.owner)` in Source-event admission, or explicitly require
the two IDs to agree. The simplest negative control replaces only the
serialized origin's owner record with B, leaving the valid target/slot and
actual draft owner A unchanged. This avoids a false rejection caused by an
unrelated invalid Scenario parent slot. This reviewer sent that independently
derived detail to author/root; final strengthened source readback is pending.
### Confirmed scope of the other deltas
- New outer consumer captions call `views::short` with 60 characters, or 80 in
the orphan card. That helper collapses whitespace and truncates presentation;
it does not rewrite raw draft names. The source fields still have their own
remaining-height scroller and a separate Back/Use footer. Active-source
summaries describe the actual source+lifeline/work/machine transaction, with
the first machine view explicitly conditional. No view call adopts a model
command. Native minimum-window readability is not inferred from this trace.
- `source.check_scope` is called before preview in all three parent planners.
A selected staged source or current child with the wrong typed consumer scope
is rejected; an inactive staged source remains excluded. The malformed-kind
regression now also falsifies a Machine scope inside a Lifeline draft.
- The nested-parent test uses a real OA Activity parent, refuses an Entity as
work ownership, stages exactly one child Activity, then changes the captured
parent's kind and proves private preview refuses without changing the raw
source state. The implementation validates both the exact parent snapshot
and current `can_parent` predicate. This is not a test of every parent family.
- The callee regression has one existing ScenarioUse with an empty binding list.
Adding a new Activity-backed callee lifeline preserves every original
element, relation and diagram and produces the expected
`missing_lifeline_binding` warning on that use. Its shared history helper
checks model/source Undo, Redo and fresh source reconstruction. This is useful
evidence for allowing an incomplete caller; it is not a claim of independently
testing multiple callers with nonempty Role mappings.
- App Undo/Redo now uses the actual boolean returned by `Document`, calls sync
only for a history step, and reports Nothing to undo/redo when appropriate.
Its test exercises both an empty history and a real rename through the public
`Message::Command` path. Existing `apply()` guards for pending behavior/source
remain in front; the existing property-Apply behavior is unchanged. No claim
that all Undo/Redo requests are inherently free of property application is
introduced.
### CLI documentation cross-check
`docs/source-cli.md` and README's explicit `cargo run --locked -p oa-cli --bin
arcadia -- check examples/text-first/project.arcadia` example match the final
CLI adapter. The example's execution was already verified by root and was not
repeated here. The page correctly separates aliases from display names, previews
from explicit per-invocation writes, changed-file reports from unchanged captured
dependencies, pending recovery from automatic recovery, and source3–7 migration
from canonical formatting or detached-file deletion. Root accepted and applied
two precision additions during this review: Unicode scalar columns, and
`written:false` not implying guaranteed rollback. Readback confirmed both. No
new CLI implementation issue or saved-plan/digest requirement was raised.
### Evidence status
Read the author's terminal `focused4.log`/status: **22 passed, 0 failed, 653
filtered**, 2.04 seconds test execution, exit 0 at 11:59:25 UTC. The matched
immutable test executable is SHA-256
`6E677F58458B6122EA1886AAC98882640CD9CF260651FE3ECE62BDDA4BE38CC0`, inventory 675.
The full suite was running under root at review time; it is not reported passed
here. Guide/source-origin corrections above are later deltas and require their
own coherent source/test evidence, including the final owner-binding detail.
Current source-input manifest, focused logs,
and author's revised implementation report remain the build evidence authority;
this reviewer executed no desktop tests or native workflow.
### Final source readback closure
The author froze the strengthened source and root requested a short final
readback. **No remaining material source finding in this bounded delta review.**
This closes the pending owner-binding detail above; it does not assert that the
new source has completed its later compiled/native gates.
All four guards now compare the captured owner record against the actual parent
draft's `d.owner`/`self.owner`, in addition to the document identity. The 23rd
regression includes ordinary/legacy × Back/inactive-existing variants for both
Scenario and Work. Each has a valid existing-target control, wrong-document and
null-origin refusal, and a borrowed full record from another valid same-layer
owner. The latter must fail both final preparation and Source Open while the
entire raw recovery snapshot remains unchanged. This is the exact falsifier
requested in the preceding handoff, not an unrelated invalid-parent failure.
For an old unengaged draft, first Source Open creates its missing origin only in
a private clone; the clone replaces the parent only after source admission
succeeds. It cannot rebind an already engaged missing/mismatched origin. Back is
still dismissed by its token before those semantic guards, and parent Cancel
remains available. The old guide sentence is absent and the retained-owner
creation instruction is present.
Readback hashes match the author's final freeze:
| File | SHA-256 |
| --- | --- |
| `behavior/scenario.rs` | `D12A4B1CAA61C08F69C4D2A64BD15568C4B7158DEA91AAC5A52A58A35ADB863C` |
| `behavior/topology.rs` | `D06B2F0FC39B4814E94200297E148F1D4D97E04CB167766030AC9DF18689E3B0` |
| `behavior/contextual_source_tests.rs` | `5F05318A6533503B9D6FEBF1EC4DD7256F192394BC1B952A7904C8175BD8DDAE` |
| `guide.rs` | `47EEB3CC0A48D5712720096015A08387CD354FB91559B0BD6FA106B5CAC6292C` |
Paths in this last table are under `crates/oa-desktop/src/`. Root subsequently
reported the earlier immutable 675-test artifact passed 675/675 in 448.33 seconds
(Gitea #185). That artifact predates these final corrections. The author's
focused5, matching GUI/lint and root's native/source oracle remain the appropriate
next evidence; no Cargo, rustc, native input or production change was performed
by this reviewer during closure.