Files
ARCADIA-Studio/harness/release-source-alias-rename-design-20260911.md
T

75 lines
20 KiB
Markdown
Raw 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.
# Text-caret alias rename — measured design, 2026-09-11
Codex-9e8r6t `/root`, with independent design and review; [issue 9](http://217.177.34.108:3000/sorokin.oleg.edu/ARCADIA-Studio/issues/9). The original source-derived design inspected `36db9356`; the transaction choice below now incorporates an exact `eeeaa126`-era experiment and a second critique. This is an implementation direction, not implemented Text rename or native acceptance. Finish the #6 repair correction and navigation milestone before adding this slice. No source8, calculation, library, core or CLI change is proposed here.
**Recommendation:** an editor-local **Rename alias · F2** action opens a compact modal, prepares a complete source preview against the current accepted document, then explicitly adopts that exact candidate as one model/source change. Refuse pending drafts and uncertain target/source membership. Keep Save separate.
## Existing authority and concrete traps
- `Command::SetAlias` edits the header by UUID; `prepare_command` validates the complete candidate and returns identity provenance ([session.rs](../crates/oa-core/src/session.rs), lines 170–198, 607–609, 816–870). It supports the project, elements, relations, diagrams, node placements, artifacts and traces. `Project::identities` covers those same families; alias rules are ASCII letter/underscore followed by ASCII alphanumeric/underscore, case-sensitive global uniqueness and the existing reserved set ([model.rs](../crates/oa-core/src/model.rs), lines 1667–1744). Do not substitute engineering-name matching, lowercase/trim the input, or reject every lexer keyword: some highlighted words remain legal aliases.
- The updater rechecks the current compiled index/model/bytes, changes typed syntax and recompiles to exact candidate-model equality. Reference edits preserve the separate `@`, intervening comments and unrelated trivia ([source_project.rs](../crates/oa-core/src/source_project.rs), lines 780–800, 852–1027, 1133–1225). Existing exact tests include comment-separated references and CRLF/escaped text ([source_project tests](../crates/oa-core/tests/source_project.rs), lines 843–897). These support the implementation choice; they do not prove a future desktop flow.
- `Document::execute` already prepares and commits model/source together. Public `CompiledSourceProject` fields are **not** a validated capability: `apply_compiled` recompiles and compares bundle, model and index before private `commit` ([document.rs](../crates/oa-desktop/src/document.rs), lines 301–397). Keep that check; do not expose `commit` or install a worker's public DTO unchecked.
- `Message::Command` calls `App::apply()`, which can accept a dirty property form; `sync()` refreshes the property draft and accepted source ([app.rs](../crates/oa-desktop/src/app.rs), lines 709–739, 785–855, 2601–2625). A clean Text buffer is insufficient: a property/behavior draft may still exist. Rename must use its own guarded adoption route, with no implicit Apply.
- History is bounded by 100 entries and **32 MiB of estimated source plus serialized model**, not the 64 MiB source admission. `commit` may evict even the immediately preceding snapshot; the existing large-current test explicitly expects no Undo ([document.rs](../crates/oa-desktop/src/document.rs), lines 24–32, 388–394, 796–820). An unconditional one-Undo promise is false without capacity admission.
- `Workspace::accept` resets accepted files' text-history stacks; ordinary Text Ctrl+Z routes to **Undo text**, not model history ([source_workspace.rs](../crates/oa-desktop/src/source_workspace.rs), lines 334–361; [app.rs](../crates/oa-desktop/src/app.rs), lines 2640–2674). Preview/failure/no-op must not call `sync`. Successful rename uses model Undo/Redo, and the UI must say so.
## Alternatives and selected boundaries
| Alternative | Decision and reason |
| --- | --- |
| Edit the selected alias inline and replace #6 reference rows in draft buffers | Reject. Its lexical list can be partial/truncated; it is not a typed replacement plan. Per-file text history cannot establish one accepted multi-file transaction. |
| Reuse Properties, immediately apply SetAlias | Existing semantic capability, but it leaves Text context and lacks complete change review. Generic command dispatch can also accept an unrelated property draft. |
| Compact modal with explicit Preview, exact candidate, guarded Document adoption | Select. It separates identity/name, keeps a visible change boundary and prevents background actions from retargeting an open form. A persistent side inspector would further narrow the editor; repeated inline expandable diffs would displace it. |
Select **Document-minted alias request → worker preparation → opaque guarded commit**. The [accepted-snapshot experiment](experiments/source-alias-rename-preparation-20260911/in-process/README.md) measured actual copied `Document::execute(SetAlias)` at 426.7–581.5 ms in three debug samples on the 30-source engineering model. That makes synchronous recomputation on the UI thread a poor default for the shipped development profile. It does not measure a GUI stall, an optimized build or the new prepared commit. A worker followed by public `apply_compiled` would still recompile on the caller; replacing the live Document with a worker clone could overwrite newer save/history state. The narrow alias-only result avoids both problems while retaining public DTO validation.
Document privately captures its owner nonce, accepted `Arc`, engineering revision, limits and exact target UUID/old/new alias. Only existing typed `prepare_command(SetAlias)` and `update_bundle_with_identity_map` construct the result. The worker also computes the complete bounded diff and history estimate. App's Clone messages may transport an immutable `Arc`-backed opaque result, but approval is consumed in current controller state before adoption. Candidate bytes, private estimates and intent are not caller-mutable or deserializable authority. Install the candidate `Arc` into the live Document through its shared history algorithm; do not deep-clone the candidate on Confirm or expose generic unchecked compiled adoption. Never execute then Undo to obtain a preview.
Use Document's exact history estimator before Preview becomes confirmable and recheck private sizes before adoption. Refuse a changing rename if saturating `estimated(before) + estimated(candidate) > HISTORY_BYTES` (32 MiB); a no-op requires no reservation. Otherwise Confirm could evict its own immediate Undo. Older history may still be trimmed normally. Do not duplicate the estimator in App or introduce a general compiled-accept method.
The [first critique](release-source-alias-rename-critique-20260911.md) rejected public compiled DTOs as exact rename authority and led to the simpler recompute-on-confirm proposal. The measured cost now warrants the private result, as refined by the [transaction critique](release-source-alias-rename-transaction-critique-20260911.md). Keep owner + accepted-Arc + revision guards, and refuse request/commit at exhausted `u64::MAX` revision: current saturating revisions otherwise admit edit→Undo replay to the same retained Arc. App workspace/session/invocation/draft guards remain necessary when invalid Open retains the accepted Document while changing destination.
Commit preserves the live saved baseline (including unknown `None`) and recovered flag. It uses the live histories under normal insertion, eviction and Redo rules rather than installing worker histories. A legitimate Save completion during preparation remains authoritative; an earlier Undo may mean the new candidate already equals saved bytes, so a changing rename need not finish dirty. No-op/cancel/refusal must not call `sync` or reset either history/cursor. Measure actual guarded commit plus App refresh before claiming responsiveness: source comparisons, history destruction, editor rebuilding and preview rendering still consume UI time. This bounded implementation will determine whether further changes are justified.
## Exact contract
**Admission and target.** Begin requires Text context with no busy file operation, model workflow, architecture draft, pending property/behavior draft or competing modal. Require `Workspace.applied`, no buffer edits, exact entry plus loaded path/text equality with `Document.bundle`, and the bounded #6 snapshot's complete/validated included scope. For the first slice, any extra loaded detached buffer refuses; explicitly close a clean detached buffer, or reattach/revert a dirty one through existing actions. Physical orphan files not loaded are outside the rename and remain unchanged. This conservative policy prevents silent omission; it does not delete or auto-close a file.
Resolve only an alias token or live `@` use under the exact caret/selection, using the existing bounded hit/query seam. Require exactly one complete definition, included/validated evidence, unique authored UUID, and agreement with the accepted project's alias and declaration path. Check the alias role lies within the accepted declaration location; do not require the outline's whole declaration extent to equal the compiler's project-header extent. Names, comments, strings, historical UUIDs, blank space, ambiguous definitions, missing IDs, partial includes or an exhausted query budget cannot authorize rename. A truncated reference list is neither needed nor consulted; all changes come from the typed updater. Never compile a raw unapplied workspace just to enable the action: compilation can allocate missing UUIDs or migrate source (source_project.rs, lines 286–300).
Accepted-but-unsaved documents are eligible. Preview compares against the **accepted source**, not the last disk baseline. Stabilization/migration already accepted by ordinary Open/Apply retains its fixed IDs; this rename must add no new ID, migration, default, file or include change. Save may later include earlier unsaved accepted edits as well as this rename; the modal says that it only previews this operation.
**Form and preview.** Capture invocation ID, document snapshot `Arc`, document revision, workspace session/revision, active path and exact origin cursor/alias span/UUID. Keep the replacement string raw; do not silently normalize pasted text. The single-line field explicitly rejects a whole paste containing control characters, retaining its text and selection while invalidating approval and pending intent. Invalid syntax, reserved/colliding aliases and same-alias input produce useful inline feedback; same alias is “No change” with Confirm unavailable and no history/reset. Duplicate engineering names are valid and never disambiguate identity.
Explicit Preview starts at most one worker. It prepares `SetAlias(target_uuid, replacement)` against the pinned accepted snapshot with the desktop limits. Require full candidate Project equality to an independently formed alias-only expectation, identity-map identity for every surviving record, identical file membership/entry and ownership, and unchanged non-alias fields. Preserve old/new source via the two snapshots, not duplicated whole-file strings in every row. Updater errors leave accepted data and all drafts intact.
Preview rows are derived from every changed file in the complete candidate. Because alias replacement cannot add/remove newlines, pair source lines by ordinal, collect every changed line and group nearby context into hunks; unexpected line-ending/line-count changes refuse rather than falling back to a lossy preview. The changed-line count is not presented as a count of semantic references. Display admission is 256 changed files, 50,000 changed lines and 8 MiB of exact displayed source bytes (both versions of changed/context lines plus each path once); exceeding a bound explains that no rename was applied. Source stays in the immutable snapshots. Index metadata has a separate bound of seven retained line records per changed line (350,000 maximum), rather than being included in that 8 MiB source-byte count. This distinction was clarified during implementation review on September 12: sparse tiny-line changes can use more index memory than displayed source bytes. Page complete admitted hunks, lines and UTF-8-safe fragments of unusually long lines; never approve a truncated candidate. These are editor limits, not new grammar limits. Do not use unbounded quadratic line diff or copy the CLI's single potentially huge middle hunk into one widget.
**Stale and confirmation.** Every dialog event carries its invocation ID; Preview/Confirm also identify the exact replacement generation and preview ID. Reject old widget events before canceling or changing the current form. Worker completion must match the wanted job, invocation, replacement generation, original document snapshot/revision and exact workspace readback. Close hides the form immediately but retains the occupied worker slot until its completion; late results do not reopen it. A source edit, file/membership switch, reset, recovery, model transaction, Undo/Redo or replacement edit invalidates approval, even if later bytes happen to match again. The input field survives same-form invalidation for correction. Reopen/new-session IDs cannot reuse an old approval.
After the target is pinned, typing in the rename field, scrolling the preview and focusing its buttons must remain usable: do not compare all dialog input to #6's original raw-input clock, which those legitimate interactions advance. Keep source/workspace/document freshness separate from form input generation. Passive lint/viewport receipts do not approve or cancel a current preview.
Confirm rechecks all admission predicates, exact old/new alias, target UUID, controller generation and the opaque result's Document authority, then adopts that exact prepared alias candidate once. Consume the live approval before dispatch to make repeated Confirm harmless. It neither reruns name resolution from the current caret nor calls generic `Message::Command`, `App::apply`, `apply_source`, Save or migration. If preparation, freshness or history admission fails, show the error and retain the replacement; no accepted bytes, save baseline, revisions, selection or histories change. Successful adoption follows normal accepted-source synchronization, stays in Text, and selects the new alias at the **same origin occurrence**, using an exact before/after line/token position map. No whole-buffer search for the first new alias. Apply the existing guarded reveal mechanism so a stale focus task cannot steal focus.
**Undo, Save and reopening.** Success supplies a context-bound “Undo rename” action and identifies “Undo model” as the persistent control; Text Ctrl+Z remains Undo text. The immediate Undo action must refuse pending source/property/behavior drafts and a newer accepted revision rather than applying them or undoing some later operation. Undo restores the entire preceding Project and exact accepted SourceBundle; Redo restores the exact candidate, each as one model-history transition. A successful new rename clears the previous redo branch normally; cancel, invalid, stale and no-op paths preserve it. Successful sync has the existing accepted-buffer history behavior; do not promise older per-file draft Undo stacks survive it.
Ordinary Save uses existing observed-dependency/journal checks and retains the accepted rename on a save failure. No cross-process CAS or atomic multi-file disk visibility is claimed. Pure rename creates/deletes no file, so Save/Undo/Save must preserve the same physical file set and pre-existing orphan bytes. Reopen verifies exact saved model/IDs/source; Undo history and an unconfirmed preview are not persisted. Recovery must never serialize an executable approved rename plan; a recovered accepted document requires a fresh invocation/preview.
## Interaction at minimum width
Add F2 only while the source editor is focused, plus a visible “Rename alias” Text action. It opens on the selected declaration/use without navigating away. The modal is at most 760 px wide and bounded by available window height/width, with a compact target caption (kind, engineering name, full source path available), **Source alias** input first, then summary and one unified diff pane. Explain “Engineering name stays unchanged.” Node placements use “Placement of …” context because they have no independent engineering name. Long names/paths/aliases must not push the input or footer out of view; offer full selectable details without an unbounded header.
Keep Cancel, Preview and Rename alias outside the independently scrolling diff. Use file search/selection plus Previous/Next changed file and hunk paging, rather than mounting a long homogeneous list. All admitted files/hunks are reachable; there are no per-file checkboxes because the operation is atomic. Show `+`/`−`, line numbers and before/after labels, not color alone. Enter in the alias field requests Preview, never commits implicitly; Tab/Shift+Tab reaches controls and an explicitly focused Confirm button activates normally. Captured Escape closes the rename form once, preserving source selection/drafts; it must not fall through to a different editor. Tests/native review must verify this composition at 1100×700 and a narrow dialog host, including long Unicode engineering names and paths.
## Bounded evaluator and real workflows
Prepare expected Project and exact source bytes **before** exercising the implementation; change only the chosen family's alias field and the literal role-proven declaration/typed-reference tokens. Pin all authored UUIDs. Compare complete Project, SourceBundle, declaration file ownership, saved baseline and history transitions, not only changed-file snippets or a successful reparse.
1. **OA activity across modules:** from a comment-separated `@assess` in a process, rename to `assess_damage`; keep the Unicode engineering name, CRLF, repeated uses, prose `@assess`, escaped strings, diagram geometry and trace history unchanged. Preview, Cancel, repeat Confirm, Model Undo/Redo, Save/reopen.
2. **Non-element source identity:** rename a relation alias used by view routes/traces, then a placement alias; ensure the relation/placement UUIDs, endpoints, engineering names and routed geometry do not change. Include project, diagram, artifact and trace targets in the parameterized headless family matrix rather than assuming element coverage transfers.
3. **Repair without loss:** invoke from an invalid or unapplied include draft with another dirty property form; no preview mutation or hidden Apply. After explicit repair/Apply or cancellation outside this flow, invoke afresh and complete the rename. Include a detached duplicate and a missing include; closing/reattaching remains a separate user action.
Required falsifiers: two same-name objects; legal keyword-classified alias; invalid/reserved/colliding/identical alias; target deleted/reidentified or source moved; old Confirm after same-ID reset; source edit then Undo to identical bytes; changed replacement then back to identical text; dirty property form while Text remains in sync; corrupted public candidate/index and a self-consistent unrelated compiled replacement delivered as counterfeit preview data; admitted model exceeding immediate-Undo capacity; more than 200 real uses; diff-bound overflow; long names/paths; same-line repeated uses and a caret on the final occurrence. Assert unchanged raw drafts, model/source, save baseline, revision, both undo/redo branches and cursor on every rejected/canceled/no-op path. Use real App messages for modal/captured Escape and stale queues, not only disabled-button tests. Mounted layout tests must use real paragraph metrics and actual bounded scroll/footer geometry.
Native acceptance belongs to a new identified build after #6: inspect complete preview at minimum/wide windows, keyboard focus and Escape, change the alias from a reference, Undo/Redo, Save/reopen and compare the pre-authored whole-project/source oracle. Test preparation/confirmation timing separately on a representative accepted model; the draft-only 100-module #6 query trial is not evidence for this transaction or its UI.