fix(forms): reset replacement sessions and preserve visible scroll
This commit is contained in:
@@ -425,6 +425,25 @@ fn review_reference_facets_groups_and_attachment_hosts_browse_without_replanning
|
||||
};
|
||||
let mut app = App::with_project(p.clone());
|
||||
let _ = app.update(Message::StartSemanticReview(Id::from_u128(100)));
|
||||
if mode == 2 {
|
||||
// A paired attachment is a real catalog facet only after explicit
|
||||
// correspondence; selecting an unstaged synthetic pair is rejected.
|
||||
for (id, oa) in [(103, true), (104, false)] {
|
||||
let choice = crate::app::Choice {
|
||||
id: Id::from_u128(id),
|
||||
label: format!("Record · @object_{id}"),
|
||||
};
|
||||
send_review(
|
||||
&mut app,
|
||||
if oa {
|
||||
RowEvent::ReferenceOa(choice)
|
||||
} else {
|
||||
RowEvent::ReferenceSa(choice)
|
||||
},
|
||||
);
|
||||
}
|
||||
send_review(&mut app, RowEvent::AddReference);
|
||||
}
|
||||
send_review(&mut app, RowEvent::Select(facet.clone()));
|
||||
send_review(
|
||||
&mut app,
|
||||
@@ -436,7 +455,19 @@ fn review_reference_facets_groups_and_attachment_hosts_browse_without_replanning
|
||||
} else {
|
||||
Id::from_u128(101)
|
||||
};
|
||||
assert_eq!(app.reference_draft(&host, path).unwrap().original, record);
|
||||
assert_eq!(
|
||||
app.reference_draft(&host, path)
|
||||
.unwrap_or_else(|| {
|
||||
panic!(
|
||||
"Reference fixture mode={mode}, facet={facet:?}, selected={:?}, decisions={:?}, error={:?}",
|
||||
review(&app).selected,
|
||||
review(&app).decisions,
|
||||
review(&app).error
|
||||
)
|
||||
})
|
||||
.original,
|
||||
record
|
||||
);
|
||||
let before = review(&app).recovery_snapshot().unwrap();
|
||||
let plan = serde_json::to_value(&review(&app).plan).unwrap();
|
||||
let proposed = review(&app).proposed.clone();
|
||||
|
||||
@@ -760,22 +760,34 @@ async fn mounted_reverse_review_required_rationale_remains_editable_beside_candi
|
||||
let sa = p
|
||||
.elements
|
||||
.values()
|
||||
.find(|element| {
|
||||
element.layer() == Layer::Sa
|
||||
&& matches!(
|
||||
element.shared(),
|
||||
Some(SharedBody::Occurrence {
|
||||
body: OccurrenceBody::Exchange {
|
||||
operation: Some(_),
|
||||
message_kind: MessageKind::Call | MessageKind::Asynchronous,
|
||||
..
|
||||
},
|
||||
..
|
||||
})
|
||||
)
|
||||
})
|
||||
.find(|element| element.alias == "operation_probe_43")
|
||||
.unwrap()
|
||||
.id;
|
||||
let allocation = p
|
||||
.relations
|
||||
.values()
|
||||
.find(|relation| relation.alias == "operation_probe_30")
|
||||
.unwrap()
|
||||
.id;
|
||||
// The boundary fixture deliberately has no selected operation. Author one
|
||||
// through the validated command path before testing reverse omission.
|
||||
let mut message = p.elements[&sa].clone();
|
||||
let Some(SharedBody::Occurrence {
|
||||
body: OccurrenceBody::Exchange { operation, .. },
|
||||
..
|
||||
}) = message.shared_mut()
|
||||
else {
|
||||
panic!("The operation fixture must contain an Exchange call")
|
||||
};
|
||||
*operation = Some(OperationUse {
|
||||
allocation: Some(allocation),
|
||||
});
|
||||
p = execute_batch(&p, &[Command::EditElement(sa, message)]).unwrap();
|
||||
assert!(matches!(
|
||||
oa_core::operations::resolve(&p, sa).unwrap(),
|
||||
oa_core::operations::OperationResolution::Selected(value)
|
||||
if value.allocation == allocation
|
||||
));
|
||||
let inspector_id = Id::new_v4();
|
||||
element(
|
||||
&mut p,
|
||||
@@ -836,7 +848,14 @@ async fn mounted_reverse_review_required_rationale_remains_editable_beside_candi
|
||||
let candidate = serde_json::to_value(
|
||||
review(&app)
|
||||
.reference_form(app.project())
|
||||
.unwrap()
|
||||
.unwrap_or_else(|| {
|
||||
panic!(
|
||||
"Reverse review candidate: selected={:?}, decisions={:?}, error={:?}",
|
||||
review(&app).selected,
|
||||
review(&app).decisions,
|
||||
review(&app).error
|
||||
)
|
||||
})
|
||||
.recovery_snapshot(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
@@ -17,6 +17,7 @@ use std::collections::BTreeMap;
|
||||
#[cfg(test)]
|
||||
mod contextual_source_tests;
|
||||
pub(crate) mod creation;
|
||||
mod form_session;
|
||||
pub(crate) mod scenario;
|
||||
// Projection acceptance precedes the coordinated scenario renderer integration.
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -0,0 +1,148 @@
|
||||
//! Keep behavior field state within one editing session and reset it on replacement.
|
||||
use iced::advanced::widget::{Operation, Tree, tree};
|
||||
use iced::advanced::{Clipboard, Layout, Shell, Widget, layout, overlay, renderer};
|
||||
use iced::{Element, Event, Length, Rectangle, Size, Theme, Vector, mouse};
|
||||
use oa_core::Id;
|
||||
|
||||
struct Identity(Id);
|
||||
|
||||
struct Session<'a, Message, R: renderer::Renderer> {
|
||||
identity: Id,
|
||||
content: Element<'a, Message, Theme, R>,
|
||||
}
|
||||
|
||||
pub(super) fn reset_on_change<'a, Message: 'a, R: renderer::Renderer + 'a>(
|
||||
identity: Id,
|
||||
content: impl Into<Element<'a, Message, Theme, R>>,
|
||||
) -> Element<'a, Message, Theme, R> {
|
||||
Element::new(Session {
|
||||
identity,
|
||||
content: content.into(),
|
||||
})
|
||||
}
|
||||
|
||||
impl<Message, R: renderer::Renderer> Widget<Message, Theme, R> for Session<'_, Message, R> {
|
||||
fn tag(&self) -> tree::Tag {
|
||||
tree::Tag::of::<Identity>()
|
||||
}
|
||||
|
||||
fn state(&self) -> tree::State {
|
||||
tree::State::new(Identity(self.identity))
|
||||
}
|
||||
|
||||
fn children(&self) -> Vec<Tree> {
|
||||
vec![Tree::new(self.content.as_widget())]
|
||||
}
|
||||
|
||||
fn diff(&self, tree: &mut Tree) {
|
||||
let retained = tree.state.downcast_mut::<Identity>();
|
||||
if retained.0 != self.identity {
|
||||
retained.0 = self.identity;
|
||||
// Iced's keyed column preserves same-length child replacements.
|
||||
// An editing-session replacement must instead get fresh field state.
|
||||
tree.children = self.children();
|
||||
} else {
|
||||
tree.diff_children(std::slice::from_ref(&self.content));
|
||||
}
|
||||
}
|
||||
|
||||
fn size(&self) -> Size<Length> {
|
||||
self.content.as_widget().size()
|
||||
}
|
||||
|
||||
fn layout(&mut self, tree: &mut Tree, renderer: &R, limits: &layout::Limits) -> layout::Node {
|
||||
self.content
|
||||
.as_widget_mut()
|
||||
.layout(&mut tree.children[0], renderer, limits)
|
||||
}
|
||||
|
||||
fn operate(
|
||||
&mut self,
|
||||
tree: &mut Tree,
|
||||
layout: Layout<'_>,
|
||||
renderer: &R,
|
||||
operation: &mut dyn Operation,
|
||||
) {
|
||||
self.content
|
||||
.as_widget_mut()
|
||||
.operate(&mut tree.children[0], layout, renderer, operation);
|
||||
}
|
||||
|
||||
fn update(
|
||||
&mut self,
|
||||
tree: &mut Tree,
|
||||
event: &Event,
|
||||
layout: Layout<'_>,
|
||||
cursor: mouse::Cursor,
|
||||
renderer: &R,
|
||||
clipboard: &mut dyn Clipboard,
|
||||
shell: &mut Shell<'_, Message>,
|
||||
viewport: &Rectangle,
|
||||
) {
|
||||
self.content.as_widget_mut().update(
|
||||
&mut tree.children[0],
|
||||
event,
|
||||
layout,
|
||||
cursor,
|
||||
renderer,
|
||||
clipboard,
|
||||
shell,
|
||||
viewport,
|
||||
);
|
||||
}
|
||||
|
||||
fn draw(
|
||||
&self,
|
||||
tree: &Tree,
|
||||
renderer: &mut R,
|
||||
theme: &Theme,
|
||||
style: &renderer::Style,
|
||||
layout: Layout<'_>,
|
||||
cursor: mouse::Cursor,
|
||||
viewport: &Rectangle,
|
||||
) {
|
||||
self.content.as_widget().draw(
|
||||
&tree.children[0],
|
||||
renderer,
|
||||
theme,
|
||||
style,
|
||||
layout,
|
||||
cursor,
|
||||
viewport,
|
||||
);
|
||||
}
|
||||
|
||||
fn mouse_interaction(
|
||||
&self,
|
||||
tree: &Tree,
|
||||
layout: Layout<'_>,
|
||||
cursor: mouse::Cursor,
|
||||
viewport: &Rectangle,
|
||||
renderer: &R,
|
||||
) -> mouse::Interaction {
|
||||
self.content.as_widget().mouse_interaction(
|
||||
&tree.children[0],
|
||||
layout,
|
||||
cursor,
|
||||
viewport,
|
||||
renderer,
|
||||
)
|
||||
}
|
||||
|
||||
fn overlay<'b>(
|
||||
&'b mut self,
|
||||
tree: &'b mut Tree,
|
||||
layout: Layout<'b>,
|
||||
renderer: &R,
|
||||
viewport: &Rectangle,
|
||||
translation: Vector,
|
||||
) -> Option<overlay::Element<'b, Message, Theme, R>> {
|
||||
self.content.as_widget_mut().overlay(
|
||||
&mut tree.children[0],
|
||||
layout,
|
||||
renderer,
|
||||
viewport,
|
||||
translation,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -232,25 +232,31 @@ impl Operation for Collect {
|
||||
};
|
||||
let mut shifts = BTreeMap::new();
|
||||
for ancestor in ancestors.iter().rev() {
|
||||
let dx = reveal(
|
||||
bounds.x,
|
||||
bounds.width,
|
||||
ancestor.bounds.x,
|
||||
ancestor.bounds.width,
|
||||
);
|
||||
let dy = reveal(
|
||||
bounds.y,
|
||||
bounds.height,
|
||||
ancestor.bounds.y,
|
||||
ancestor.bounds.height,
|
||||
);
|
||||
// Drawing offsets are rounded; an already-visible axis must not
|
||||
// acquire a scroll delta from a fractional capacity alone.
|
||||
let delta = Vector::new(
|
||||
(ancestor.offset.x
|
||||
+ reveal(
|
||||
bounds.x,
|
||||
bounds.width,
|
||||
ancestor.bounds.x,
|
||||
ancestor.bounds.width,
|
||||
))
|
||||
.clamp(0., ancestor.capacity.x)
|
||||
- ancestor.offset.x,
|
||||
(ancestor.offset.y
|
||||
+ reveal(
|
||||
bounds.y,
|
||||
bounds.height,
|
||||
ancestor.bounds.y,
|
||||
ancestor.bounds.height,
|
||||
))
|
||||
.clamp(0., ancestor.capacity.y)
|
||||
- ancestor.offset.y,
|
||||
if dx == 0. {
|
||||
0.
|
||||
} else {
|
||||
(ancestor.offset.x + dx).clamp(0., ancestor.capacity.x) - ancestor.offset.x
|
||||
},
|
||||
if dy == 0. {
|
||||
0.
|
||||
} else {
|
||||
(ancestor.offset.y + dy).clamp(0., ancestor.capacity.y) - ancestor.offset.y
|
||||
},
|
||||
);
|
||||
if delta != Vector::ZERO {
|
||||
shifts.insert(ancestor.index, delta);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//! Scenario presentation. Layout/camera controls never construct model commands.
|
||||
use super::super::scenario_scroll;
|
||||
use super::super::{form_session, scenario_scroll};
|
||||
use super::*;
|
||||
use iced::widget::{Space, column, keyed_column, sensor};
|
||||
use iced::widget::{Space, column, sensor};
|
||||
|
||||
pub(crate) const NAME_INPUT: &str = "scenario-form-name";
|
||||
|
||||
@@ -754,16 +754,13 @@ fn editor_panel<'a, R: iced::advanced::text::Renderer + 'a>(
|
||||
container(
|
||||
column![
|
||||
container(actions).id("scenario-actions").width(Fill),
|
||||
keyed_column([(
|
||||
form_session::reset_on_change(
|
||||
session,
|
||||
scrollable(fields)
|
||||
.id("scenario-form")
|
||||
.width(Fill)
|
||||
.height(Fill)
|
||||
.into(),
|
||||
)])
|
||||
.width(Fill)
|
||||
.height(Fill),
|
||||
.height(Fill),
|
||||
),
|
||||
]
|
||||
.spacing(6),
|
||||
)
|
||||
|
||||
@@ -183,9 +183,19 @@ impl Operation for Collect {
|
||||
ancestor.bounds.y,
|
||||
ancestor.bounds.height,
|
||||
);
|
||||
// Iced reports rounded drawing offsets, while capacity can be
|
||||
// fractional. Clamping an already-visible axis can move it a pixel.
|
||||
let delta = Vector::new(
|
||||
(ancestor.offset.x + dx).clamp(0., ancestor.capacity.x) - ancestor.offset.x,
|
||||
(ancestor.offset.y + dy).clamp(0., ancestor.capacity.y) - ancestor.offset.y,
|
||||
if dx == 0. {
|
||||
0.
|
||||
} else {
|
||||
(ancestor.offset.x + dx).clamp(0., ancestor.capacity.x) - ancestor.offset.x
|
||||
},
|
||||
if dy == 0. {
|
||||
0.
|
||||
} else {
|
||||
(ancestor.offset.y + dy).clamp(0., ancestor.capacity.y) - ancestor.offset.y
|
||||
},
|
||||
);
|
||||
if delta != Vector::ZERO {
|
||||
shifts.insert(ancestor.index, delta);
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
# Chooser and editing-session corrections — Windows gate
|
||||
|
||||
Codex-956atf `/root`, 2026-09-11. The corrected source passes **chooser14/14** and
|
||||
**scenario-workspace18/18**, including all four previously failing cases and all
|
||||
five parent-focus I1/I2 regressions. No failed or ignored tests. The full720 rerun
|
||||
is active; its terminal result remains a separate gate.
|
||||
|
||||
The [first full run](release-scenario-focus-gate-20260911.md#subsequent-full-suite-failure-and-corrective-work)
|
||||
finished716 passed/4 failed. Its evidence is preserved. The
|
||||
[chooser diagnosis](release-chooser-full-gate-diagnosis-20260911.md) records why
|
||||
an already-visible anchor drifted by1px and why the rationale/attachment fixtures
|
||||
stopped before their intended interaction. Exact assertions were retained.
|
||||
|
||||
Root replaced the one-child keyed-column assumption with a small generic
|
||||
`behavior/form_session.rs` widget. It forwards layout/input/drawing/operations,
|
||||
retains child state for the same editing identity, and creates a fresh child tree
|
||||
when a different session replaces it without an intervening closed render. The
|
||||
existing test now verifies zero new-form scroll while preserving the canvas's
|
||||
actual137×850 offset, same-session700px scroll, raw recovery and source/history.
|
||||
The helper is shared with the future isolated process-editor union.
|
||||
|
||||
The chooser and parent focus collectors now preserve zero requested reveal on
|
||||
each axis. Rounded drawing offsets no longer create a spurious delta from a
|
||||
fractional scroll capacity. The exact pointer-versus-keyboard anchor assertion
|
||||
now passes. The corrected operation fixture explicitly selects and resolves its
|
||||
actual interface operation; the paired-attachment fixture establishes real child
|
||||
correspondence through public events before selecting its facet. Neither change
|
||||
relaxes production ownership/write guards.
|
||||
|
||||
## Actual commands and evidence
|
||||
|
||||
Root used Rust/Cargo1.98.1 Windows GNU/LLVM, one Cargo job and ordinary test-stack
|
||||
settings. Standalone scoped rustfmt and `git diff --check` pass.
|
||||
|
||||
| Command | Result |
|
||||
| --- | --- |
|
||||
| `cargo test --locked -p oa-desktop --bin arcadia-studio app::reference_authoring::tests:: -- --test-threads=1` | Exit0; warning-free compile2m01s;14 passed,706 filtered;64.11s. |
|
||||
| Same prefix with `behavior::scenario::workspace::tests::` | Exit0;18 passed,702 filtered;4.89s. |
|
||||
|
||||
Immutable `.local/chooser-correction-gate-20260911/` contains the corrected
|
||||
executable, verified runtime DLL and exact focused logs. Its512-input manifest
|
||||
includes Rust/Cargo inputs plus shared Windows build resources, docs, examples
|
||||
and harness fixtures. The earlier275-input manifest remains a narrower preserved
|
||||
source inventory for the earlier executable, not this corrected gate.
|
||||
|
||||
| Artifact | SHA256 |
|
||||
| --- | --- |
|
||||
| 135,405,568-byte corrected test executable | `05811E18E4FF3495EECFD585947234906F27F7709B7E583F0362477EF1A943C3` |
|
||||
| 190,464-byte libunwind.dll | `AA282FA47BB2C4E210CEA5E470CDBDCA58568F0BE0BC73E404D86AB9CD95EF6A` |
|
||||
| Chooser14 log | `EFA48AE5C66C8D839635F61DE2F9C798DF809FA686B3F173FE112B28558AAAF4` |
|
||||
| Scenario18 log | `10B7EF829A7AF0D741571701EC257D88B71A0D5EF7BB53A2022AE000B5FF1CEE` |
|
||||
| Working-input/artifact manifest | `985C06A3B9926C9096F97D59DDE57CE3494F2FE06008BB9F46FBD5578126B4BB` |
|
||||
|
||||
Independent follow-up review of root's session wrapper and parent reveal
|
||||
correction is active. Full720/current desktop Clippy and matching native Windows
|
||||
GUI focus/visual acceptance remain open. The isolated shared canvas and schema8
|
||||
codec changes are outside this build. Further Linux builds/checks are deferred
|
||||
by the user's15:28 UTC instruction until the user reports networking resolved.
|
||||
@@ -0,0 +1,53 @@
|
||||
# Chooser full-gate diagnosis — 2026-09-11
|
||||
|
||||
Codex-956atf `/root/chooser_gate_debug`. Initial read-only source diagnosis, followed by root's narrow three-file correction lease after the suite reached terminal failure. No compiler, saved-executable, native, WSL, network/VPN, or Git actions. Root remains sole execution/integration owner. Read AGENTS.md, current issue 1 comments through 346, empty open PR inventory, ScenarioFocus20260911 Wiki and prior chooser production review. This report supersedes no historical result.
|
||||
|
||||
## Actual evidence
|
||||
|
||||
Root identifies source `8895dd2e0f87c0f16085bf4b478b8c0fbed38685` and immutable `.local/scenario-focus-gate-20260911/arcadia_studio-e358a5ed59b1de41.exe`, SHA256 `C9C4210EA36854F20C0DC9F38137CEFE5C3BC9CD19E10E1AD41DCB410CC92D04`. Reviewer independently read the terminal `.local/logs/scenario-focus-full720-20260911.log`: **716 passed, 4 failed, 0 ignored**, 377.91 seconds. Root records log SHA256 `4A765FFAD4B08EC0B9D6B8399CF841E3C776051EA07B4433BB47C8E6BDC4C67F`. Reviewer did not execute it. Three assigned failures are below; scenario fresh-session scroll reset is root-owned and outside this diagnosis.
|
||||
|
||||
Paths below are relative to `crates/oa-desktop/src` unless otherwise specified.
|
||||
|
||||
## Rationale fixture stops before any widget interaction
|
||||
|
||||
Actual failure: `app/reference_authoring/tests/mounted.rs:777`, Option unwrap while finding an SA Exchange occurrence whose operation is `Some`. No rationale field is mounted, clicked, or typed before this failure.
|
||||
|
||||
The loaded `harness/fixtures/interface-operation-probe/output/boundary-only.json:188–228` has calls `operation_probe_43` and `operation_probe_44` with no authored operation field. The fixture represents an unselected operation. Existing `semantic_review/source7_tests.rs:285–301` shows the established explicit setup: select call 43, set `OperationUse { allocation: Some(operation_probe_30) }`, then validate via `execute_batch`.
|
||||
|
||||
Minimal correction suggestion: prepare an explicitly operation-bearing call using that established setup before the search/reverse-review construction, and assert successful actual operation resolution. Do not merely broaden the search to accept `None`: that would no longer establish the operation-omission premise. Preserve every per-key addressed rationale event, final `Engineering reason`, retained focus, candidate recovery, Inspector raw, SourceBundle and Undo assertion.
|
||||
|
||||
Production path to verify after setup: `reference_authoring.rs::reference_overlay` selects modal form ownership; `forms/reference_chooser/widget.rs:282–284` calls `trigger::own_input`; `trigger/focus.rs::exclusive` uses the whole `reference-owning-review-modal` boundary; `semantic_review/row.rs:182` receives `OperationRationale`. The current source boundary preserves sibling inputs; this failing execution neither proves nor disproves that behavior.
|
||||
|
||||
## Keyboard return moves an already-visible anchor by one pixel
|
||||
|
||||
Actual failure: `app/reference_authoring/tests/mounted.rs:463`, after pointer Open and Escape return, keyboard Open anchor is `Rectangle { x: 0.0, y: 124.79999, width: 300.0, height: 16.0 }`; original expected is identical except `y: 123.79999`. The preparatory actual-scroll assertion, pointer message assertion and first exact pointer anchor equality already passed.
|
||||
|
||||
Concrete source defect: `forms/reference_chooser/trigger/focus.rs:185–188` computes `(ancestor.offset + reveal_delta).clamp(0, capacity) - ancestor.offset` even when reveal_delta is zero. The installed Iced 0.14.2 `scrollable.rs:549–559` passes the rounded drawing translation to the operation; `scrollable.rs:1876–1901` rounds each axis. Capacity derives from fractional content minus viewport size. A rounded END offset can exceed that fractional capacity; clamping then creates a negative delta for an already-visible field. Iced `State::scroll` adds that delta to the unrounded underlying absolute offset (`scrollable.rs:1790–1802`), potentially crossing the adjacent pixel boundary. This predicts precisely the observed +1px anchor.
|
||||
|
||||
Minimal correction suggestion: zero requested reveal on an axis must produce exactly zero applied delta on that axis; only bound an axis that actually needs revealing. Preserve the exact rectangle equality; adding a tolerance would hide an unintended scroll. Keep existing fresh entry, nested reveal, return-after-scrolling-away and ownership tests.
|
||||
|
||||
Needed falsifier: root narrow reproduction logging field bounds, ancestor rounded offset, fractional capacity, dx/dy and applied delta immediately before return. Expected defect signature is dx=dy=0 with a negative nonzero clamp delta at END. After correction, return should leave the scroll unchanged and both pointer/keyboard anchors equal. No runtime instrumentation has yet been applied.
|
||||
|
||||
## Paired attachment facet may not be legitimately staged
|
||||
|
||||
Actual failure: `app/reference_authoring/tests.rs:439`, first `reference_draft(host,path).unwrap()` in the loop over scalar, constructor group and child attachment. The log lacks the loop mode, active selected facet and errors. No chooser Open occurs in the failing iteration.
|
||||
|
||||
Strong source hypothesis: mode 2 constructs `Child { oa: 103, sa: 104 }` and sends Select without staging this pair or establishing 103→104 correspondence. `oa-core/src/semantic/catalog.rs:690–703` derives child pairs from the reference map. Without that mapping, the current catalog has separate unpaired child selectors. Batch Select still invokes refresh (`semantic_review/batch.rs:395–400,584–586`); `semantic_review/row.rs:863–875` replaces selection if its selector is absent from current facts. Later Decide stores the explicit Candidate facet and attachment draft, but does not select it. `row.rs:529–545` correctly rejects a host facet that is not actively selected.
|
||||
|
||||
The scalar banked-row reference test passed in the same executable, and `Document::from_project` explicitly proves model equality after source roundtrip, so source normalization loss is unsupported here. The paired-attachment diagnosis still requires actual mode/selection evidence.
|
||||
|
||||
Needed falsifier: enrich the failing assertion with mode, requested facet, current selected facet, decisions, state error, candidate roots and candidate draft availability. If mode2/selection mismatch is confirmed, prepare its pair through the actual Attachment Pick/Stage workflow before Select (or establish explicit correspondence through its real workflow), retaining the old-facet rejection and source/history comparisons. Do not relax the production active-facet guard to accept a banked/unselected draft. If another mode fails, re-localize against its actual gate before changing source.
|
||||
|
||||
## Handoff
|
||||
|
||||
Root granted the narrow lease after reviewing the actual failure evidence. Three files were edited and standalone rustfmt completed exit 0 with edition2024 and skip_children=true:
|
||||
|
||||
| File | Frozen correction SHA256 |
|
||||
| --- | --- |
|
||||
| `forms/reference_chooser/trigger/focus.rs` | `F1E79F4B03B2F9FD1CDC335054D4AE177DC9E759B6EA3D334B2BCCA39B57191B` |
|
||||
| `app/reference_authoring/tests/mounted.rs` | `3A43E32BD028D4DF699F905BDBFAA7B99A56D5ADB5EB190AB6E47E14F6D7520C` |
|
||||
| `app/reference_authoring/tests.rs` | `AAE2D95305DBCA6120DCFBFBF292F138C39015F136F3C85784CA46B0669729B8` |
|
||||
|
||||
The production correction guards each zero reveal axis before the capacity clamp. The rationale fixture follows the existing validated EditElement operation-selection setup and additionally proves actual Selected resolution. Mode2 uses the real public ReferenceOa, ReferenceSa and AddReference events to establish103→104 correspondence before selecting its paired Child catalog facet; semantic-review visibility and write guards are unchanged. Candidate fixture failures now include mode/facet/selected/decisions/error diagnostics. Exact anchor, key counts, final rationale, stale-facet rejection, candidate staging, SourceBundle and history expectations were retained.
|
||||
|
||||
These are prepared source corrections, not passing execution evidence. Root owns targeted chooser and full-suite reruns and integration with its separate session-scroll correction. Existing scenario parent-focus5/5 and independent canvas/schema8 work remain separate.
|
||||
@@ -41,6 +41,11 @@ manifest of actual source/build files, including the new untracked focus module.
|
||||
The manifest explicitly identifies working-source provenance rather than claiming
|
||||
all inputs were identical to base HEAD.
|
||||
|
||||
The correction is now committed as
|
||||
`8895dd2e0f87c0f16085bf4b478b8c0fbed38685`, pushed and exact readback verified.
|
||||
Root independently compared all275 manifest inputs with that commit's Git archive;
|
||||
there were zero mismatches. `commit-readback.json` preserves the comparison.
|
||||
|
||||
| Artifact | SHA256 |
|
||||
| --- | --- |
|
||||
| 135,520,256-byte test executable | `C9C4210EA36854F20C0DC9F38137CEFE5C3BC9CD19E10E1AD41DCB410CC92D04` |
|
||||
@@ -54,3 +59,26 @@ focus timing/visual behavior and Linux desktop acceptance remain separate gates.
|
||||
The isolated shared canvas candidate is not part of this binary; its future union
|
||||
must preserve the exact parent marker, session/mount split, Name identity, sensor
|
||||
and all five regressions. Prior676-suite/native80cf197 evidence remains historical.
|
||||
|
||||
## Subsequent full-suite failure and corrective work
|
||||
|
||||
Root ran the preserved executable with `--test-threads=1` and captured the complete
|
||||
720-test run: exit101,716 passed/4 failed, no ignored tests,377.91s. All five parent
|
||||
focus tests pass within this run. The saved full log SHA256 is
|
||||
`4A765FFAD4B08EC0B9D6B8399CF841E3C776051EA07B4433BB47C8E6BDC4C67F`.
|
||||
|
||||
Three failures concern chooser fixtures/scrolling; the separately
|
||||
[recorded diagnosis](release-chooser-full-gate-diagnosis-20260911.md) preserves
|
||||
exact panic lines and values. The fourth is the existing
|
||||
`new_scenario_form_resets_only_its_scroll_and_recovery_gets_a_fresh_session`:
|
||||
after Cancel→Start without a closed render, the new form retained700px instead
|
||||
of zero. Installed Iced0.14.2 keyed-column diff does not replace same-length child
|
||||
state merely because its key changed. Root introduced a small explicit editing
|
||||
session wrapper which replaces only its child tree on identity change and retains
|
||||
same-session field state. The original complete canvas/source/history assertions
|
||||
are unchanged. The wrapper is reusable for the isolated process editor's invocation.
|
||||
|
||||
Root also applies the chooser's zero-reveal-axis correction to the parent focus
|
||||
collector's identical fractional-capacity calculation. Corrected source is not
|
||||
yet covered by this saved binary; a new focused/full gate is required. No fixture
|
||||
tolerance, disabled test, stack override or renderer skip was introduced.
|
||||
|
||||
Reference in New Issue
Block a user