diff --git a/.gitattributes b/.gitattributes
index 3658687c..6d7e360b 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -71,3 +71,6 @@ harness/history/2026-09-11-state-before-gitea-migration/** -text whitespace=cr-a
harness/experiments/contextual-prerelease-20260911/native/**/*.arcadia whitespace=-blank-at-eol,-blank-at-eof,cr-at-eol
harness/experiments/contextual-prerelease-20260911/producer/package*.log whitespace=-blank-at-eof,cr-at-eol
harness/experiments/contextual-prerelease-20260911/producer/source-push.log -whitespace
+harness/experiments/source-alias-rename-native-20260912/** -text whitespace=cr-at-eol
+harness/experiments/source-alias-rename-completed-20260912/** -text whitespace=cr-at-eol
+harness/experiments/source-alias-rename-refresh-20260912/** -text whitespace=cr-at-eol
diff --git a/crates/oa-desktop/src/app.rs b/crates/oa-desktop/src/app.rs
index 11030066..b9d14f11 100644
--- a/crates/oa-desktop/src/app.rs
+++ b/crates/oa-desktop/src/app.rs
@@ -7,6 +7,7 @@ mod diagram_selection_tests;
mod hosted;
#[cfg(test)]
mod review_navigation_tests;
+pub(crate) mod source_rename;
mod source_symbols;
#[cfg(test)]
mod transition_context_tests;
@@ -422,6 +423,8 @@ pub enum Message {
crate::source_navigation::SymbolEvent,
),
SourceSymbolsReady(crate::source_navigation::Completion),
+ SourceRename(source_rename::Event),
+ SourceRenameReady(source_rename::Completion),
SourceForSelection,
SourceNavigation(crate::source_navigation::Event),
SourceFindClose(crate::source_navigation::SymbolContext, Id),
@@ -500,6 +503,7 @@ pub struct App {
pub source_navigation: crate::source_navigation::State,
source_find_instance: Id,
pub source_symbols: crate::source_navigation::SymbolState,
+ pub source_rename: source_rename::State,
pub model_issues: Vec
Rename alias (F2 while the source editor has focus) changes the alias +under the caret or its exact selection. It requires a unique authored identity +in the complete accepted source bundle, with no pending source, property or +behavior drafts and no extra loaded detached files. Accepted but unsaved source +is eligible. The operation MUST NOT implicitly apply a draft or allocate an ID. +The engineering name and UUID remain unchanged.
+The Source alias field does not trim or normalize the entered alias. Pasting +line breaks, tabs or other control characters is explicitly rejected as a whole: +the field and its selection remain unchanged, and any previous preview approval +is invalidated. Preview +prepares a typed alias change and displays every changed file and source line; +comments, strings, engineering data, file membership and declaration ownership +remain unchanged. Enter in the field requests Preview, never confirmation. +The preview is for this operation against accepted source, so a later Save may +also contain earlier accepted edits. A changing rename requires enough model +history capacity to retain its immediate Undo. An invalid, identical, stale or +oversized candidate cannot enable confirmation.
+The preview MUST provide access to all admitted files, hunks, lines and long-line +segments. Refuse a candidate whose complete preview exceeds the editor's bounds: +256 changed files, 50,000 changed lines or 8 MiB of displayed source bytes +(both versions of changed/context lines and file paths). Index metadata is +separately bounded to seven retained line records per changed line. These +limits do not restrict the language itself. A changed-line count is not a count +of semantic references. Cancel, Preview and Rename alias remain reachable +outside the independently scrolling source preview.
+Explicit Rename alias confirms the current preview once, as one accepted +model/source transaction. A source, document, recovery or replacement change +invalidates its approval even if later bytes match the old preview. Closing the +form cancels approval; a late worker result MUST NOT reopen it. Rejected, +canceled and unchanged operations preserve accepted bytes, drafts, save state, +revisions, selection and both histories. Successful rename selects the new alias +at the original occurrence rather than the first matching spelling in the file. +Editing the replacement permits a new Preview in the same form. After a source +context change, close the form and invoke Rename again on the current alias.
+Undo rename is guarded against intervening edits and uses model history; +the persistent Undo model and Redo model controls restore the complete +accepted snapshots. Text Ctrl+Z remains Undo text. Save is separate and +uses the ordinary guarded source-save contract. An unconfirmed preview and Undo +history are not persisted on reopening.
Changing a graphical UUID must atomically update map keys and every reference. Alias changes preserve UUID identity. Deletion must account for owned elements, incident relationships, ordered occurrences, and diagram placements without diff --git a/docs/language.rst b/docs/language.rst index 9ea3a7f6..c1ca9106 100644 --- a/docs/language.rst +++ b/docs/language.rst @@ -2073,6 +2073,50 @@ Navigation MUST preserve the accepted model and every source draft, and select locations in the original UTF-8 bytes. Displayed locations use one-based lines and UTF-8 byte columns. +**Rename alias** (``F2`` while the source editor has focus) changes the alias +under the caret or its exact selection. It requires a unique authored identity +in the complete accepted source bundle, with no pending source, property or +behavior drafts and no extra loaded detached files. Accepted but unsaved source +is eligible. The operation MUST NOT implicitly apply a draft or allocate an ID. +The engineering name and UUID remain unchanged. + +The **Source alias** field does not trim or normalize the entered alias. Pasting +line breaks, tabs or other control characters is explicitly rejected as a whole: +the field and its selection remain unchanged, and any previous preview approval +is invalidated. **Preview** +prepares a typed alias change and displays every changed file and source line; +comments, strings, engineering data, file membership and declaration ownership +remain unchanged. Enter in the field requests Preview, never confirmation. +The preview is for this operation against accepted source, so a later Save may +also contain earlier accepted edits. A changing rename requires enough model +history capacity to retain its immediate Undo. An invalid, identical, stale or +oversized candidate cannot enable confirmation. + +The preview MUST provide access to all admitted files, hunks, lines and long-line +segments. Refuse a candidate whose complete preview exceeds the editor's bounds: +256 changed files, 50,000 changed lines or 8 MiB of displayed source bytes +(both versions of changed/context lines and file paths). Index metadata is +separately bounded to seven retained line records per changed line. These +limits do not restrict the language itself. A changed-line count is not a count +of semantic references. Cancel, Preview and Rename alias remain reachable +outside the independently scrolling source preview. + +Explicit **Rename alias** confirms the current preview once, as one accepted +model/source transaction. A source, document, recovery or replacement change +invalidates its approval even if later bytes match the old preview. Closing the +form cancels approval; a late worker result MUST NOT reopen it. Rejected, +canceled and unchanged operations preserve accepted bytes, drafts, save state, +revisions, selection and both histories. Successful rename selects the new alias +at the original occurrence rather than the first matching spelling in the file. +Editing the replacement permits a new Preview in the same form. After a source +context change, close the form and invoke Rename again on the current alias. + +**Undo rename** is guarded against intervening edits and uses model history; +the persistent **Undo model** and **Redo model** controls restore the complete +accepted snapshots. Text ``Ctrl+Z`` remains **Undo text**. Save is separate and +uses the ordinary guarded source-save contract. An unconfirmed preview and Undo +history are not persisted on reopening. + Changing a graphical UUID must atomically update map keys and every reference. Alias changes preserve UUID identity. Deletion must account for owned elements, incident relationships, ordered occurrences, and diagram placements without diff --git a/harness/experiments/source-alias-rename-completed-20260912/archive-result.json b/harness/experiments/source-alias-rename-completed-20260912/archive-result.json new file mode 100644 index 00000000..27d03ac1 --- /dev/null +++ b/harness/experiments/source-alias-rename-completed-20260912/archive-result.json @@ -0,0 +1,19 @@ +{ + "archive": "source-rename-completed-evidence-20260912.zip", + "sha256": "2282e4e755bb03ab3ecb079391909f3978297ad307e76306ef7eb5a87a9437cf", + "bytes": 10755689, + "members": 77, + "payloadBytes": 12361849, + "completedRuns": [ + "attempt-6", + "clipping-negative-1", + "clipping-positive-diagnostic-1", + "nested-sync-diagnostic-1", + "editor-patch-check-1" + ], + "commandReceipts": 8, + "inputArchivesVerified": 5, + "sourceReadbacks": 73, + "allMemberBytesAndCrcVerified": true, + "scope": "Completed source gates and bounded experiments only; not candidate acceptance or native paint." +} \ No newline at end of file diff --git a/harness/experiments/source-alias-rename-completed-20260912/build_archive.py b/harness/experiments/source-alias-rename-completed-20260912/build_archive.py new file mode 100644 index 00000000..08e3f45d --- /dev/null +++ b/harness/experiments/source-alias-rename-completed-20260912/build_archive.py @@ -0,0 +1,145 @@ +"""Archive only explicitly selected completed receipts; execute no project code.""" +import hashlib +import io +import json +from pathlib import Path +import zipfile + +ROOT = Path(__file__).resolve().parents[2] +OUT = Path(__file__).resolve().parent +PREFIX = "source-rename-completed-evidence/" +RUNS = ["attempt-6", "clipping-negative-1", "clipping-positive-diagnostic-1", + "nested-sync-diagnostic-1", "editor-patch-check-1"] +payload = {} +originals = {} +checks = [] + +def sha(data): + return hashlib.sha256(data).hexdigest() + +def encoded(value): + return (json.dumps(value, ensure_ascii=True, indent=2) + "\n").encode() + +def add(source, target): + path = ROOT / source + data = path.read_bytes() + assert target not in payload + assert path.suffix.lower() not in {".exe", ".dll", ".pyc"} + payload[target] = data + originals[str(path)] = data + +for run in RUNS: + directory = ROOT / ".local/source-rename-integration-20260912" / run + names = ["inputs.zip", "inputs.json", "environment.json"] + phases = ["clippy", "tests", "timing", "gui"] if run == "attempt-6" else [""] + if run == "attempt-6": + names.append("complete.json") + complete = json.loads((directory / "complete.json").read_bytes()) + assert complete["inputsUnchanged"] and complete["gates"] == phases + for phase in phases: + receipt_name = phase + "-result.json" if phase else "result.json" + receipt = json.loads((directory / receipt_name).read_bytes()) + assert receipt["finished"] and receipt["inputsUnchanged"] + assert receipt["exitCode"] == (101 if run == "clipping-negative-1" else 0) + names.append(receipt_name) + for stream in ["stdout", "stderr"]: + log = (phase + "-" if phase else "") + stream + ".log" + assert sha((directory / log).read_bytes()) == receipt[stream + "Sha256"] + names.append(log) + checks.append({"run": run, "phase": phase or "command", "exitCode": receipt["exitCode"], + "finished": receipt["finished"], "command": receipt["command"]}) + manifest = json.loads((directory / "inputs.json").read_bytes()) + raw = (directory / "inputs.zip").read_bytes() + assert sha(raw) == manifest["archiveSha256"] + with zipfile.ZipFile(io.BytesIO(raw)) as inner: + expected = {entry["path"]: entry for entry in manifest["files"]} + assert len(inner.namelist()) == len(set(inner.namelist())) == len(expected) + assert set(inner.namelist()) == set(expected) and inner.testzip() is None + for name, entry in expected.items(): + assert not Path(name).is_absolute() and ".." not in Path(name).parts + assert Path(name).suffix.lower() not in {".exe", ".dll", ".pyc"} + data = inner.read(name) + assert len(data) == entry["bytes"] and sha(data) == entry["sha256"] + checks.append({"run": run, "inputArchiveSha256": sha(raw), "inputMembers": len(expected), + "allInputBytesAndCrcVerified": True}) + for name in names: + add(directory.relative_to(ROOT) / name, "runs/" + run + "/" + name) + +diagnosis = ".local/source-rename-latency-diagnosis-20260912/" +notes = ["notes.md", "read-bindings.json", "nested-summary.json", "summarize.py", + "editor-initialization-candidates.md", "editor-initialization-bindings.json", + "same-line-patch-assessment.md", "editor-patch-independent-review.md", + "editor-patch-review-bindings.json", "prepare-instrumentation.ps1", + "candidate/editor_patch.rs", "candidate/README.md"] +for name in notes: + add(diagnosis + name, "diagnosis/" + name) +for path in sorted((ROOT / diagnosis / "instrumentation").rglob("*")): + if path.is_file(): + add(path.relative_to(ROOT), "diagnosis/instrumentation/" + path.relative_to(ROOT / diagnosis / "instrumentation").as_posix()) +for name in ["README.md", "source_rename.rs", "controller-tests.rs", "preview_glyph_tests.rs", "base-hashes.json", "staged-hashes.json"]: + add(".local/source-rename-preview-clipping-20260912/" + name, "clipping-stage/" + name) +for name in ["native-preview-clipping-review.md", "native-preview-clipping-bindings.json", "staged-clipping-review.md", "staged-clipping-review-bindings.json"]: + add(".local/source-rename-controller-independent-review-20260912/" + name, "reviews/" + name) +for name in ["gate.py", "focused.py"]: + add(".local/source-rename-integration-20260912/" + name, "helpers-current-readback/" + name) +assert sha(payload["diagnosis/candidate/editor_patch.rs"]) == "f301b8a043916b69dccb176da527a50ee85124b7e8b1da18921e4a0374a5153b" + +# Bind the corrected helper from the completed check snapshot, never moving live source. +with zipfile.ZipFile(io.BytesIO(payload["runs/editor-patch-check-1/inputs.zip"])) as inner: + corrected = inner.read("crates/oa-desktop/src/app/source_rename/editor_patch.rs") +assert sha(corrected) == "049c9774c1ca28cda01f9a8e024604bef282366aa52c53c17c1918dbd09c3441" +negative = payload["runs/clipping-negative-1/stderr.log"].decode() +assert "source glyph under scrollbar" in negative and "cluster=92..93" in negative + +native_path = "harness/experiments/source-alias-rename-native-20260912/source-rename-native-attempt-6-20260912.zip" +native = (ROOT / native_path).read_bytes() +assert sha(native) == "77adda5a33eb1def6dab23352ca0ab172300ea65fc21d2c215d545d7fcce0d08" +gui = json.loads(payload["runs/attempt-6/gui-result.json"])["binary"] +summary = {"scope": "Completed source gates and bounded experiments only; not candidate acceptance or native paint.", + "checks": checks, "externalBindings": [{"path": native_path, "sha256": sha(native), "bytes": len(native), "included": False}, + {"path": ".local/source-rename-integration-20260912/attempt-6/arcadia-studio.exe", "sha256": gui["sha256"], "bytes": gui["bytes"], "included": False}], + "correctedHelperFromCheckInputSha256": sha(corrected), + "excluded": ["editor-patch-tests-1", "next-layout evaluator", "executable/DLL bytes", "private profiles", "caches", "duplicate native trial archive"]} +payload["SUMMARY.json"] = encoded(summary) +payload["INDEX.md"] = b"""# Completed alias source gates and bounded experiments + +This private archive preserves five completed runs only. It is not a release or acceptance of an editor-reuse candidate. Native trial evidence is separately versioned and SHA-bound in SUMMARY.json, without duplicate payload. + +| Run | Meaning | +| --- | --- | +| attempt-6 | Four successful Windows source gates: Clippy, tests, existing full Confirm timing, GUI executable build. The GUI JSON records the external binary; building it is not native acceptance. | +| clipping-negative-1 | Expected test failure (101): original layout allows actual shaped declaration glyph cluster92..93 beneath the scrollbar. | +| clipping-positive-diagnostic-1 | Successful focused rename tests with corrected preview layout and temporary timing instrumentation in source. This is an experimental capture, not clean production acceptance. | +| nested-sync-diagnostic-1 | Successful ignored real-Confirm timing experiment with nested instrumentation. Inclusive phase levels must not be added together; no GPU, first-paint or native responsiveness claim. | +| editor-patch-check-1 | Successful cargo check of corrected reuse helper integration only. It does not execute helper behavior, later layout timing or native rendering. | + +Every run has its exact inputs.zip, complete membership/hash manifest, environment, commands/receipts and raw logs. All eight command receipt log hashes and all five nested ZIP memberships/member bytes/CRCs were independently checked during construction. Inputs manifests bind historical uncommitted snapshots; baseCommit alone is not their source identity. + +diagnosis/instrumentation preserves removed diagnostic baseline/modified files, exact patch, bindings and generator. Historical notes retain their original time-scoped claims; later receipts qualify earlier hypotheses. diagnosis/candidate/editor_patch.rs is frozen f301b8a0 and has the known after-only LFCR counterexample documented in editor-patch-independent-review.md. Its original README's broad fallback claim is superseded by that review. Corrected helper049c9774 is preserved inside editor-patch-check-1/inputs.zip. The review is static, not proof of executed correctness. + +clipping-stage and reviews preserve the earlier proposed repair/evaluator and source review; the exact executed evaluator is in each run's inputs.zip. helpers-current-readback are archive-time helper source snapshots, not independently proven historical executed versions. Historical absolute paths are evidence, not portable execution instructions. Reproduce with the recorded Windows compiler/dependencies and exact source snapshot; do not run relocated helpers blindly. + +No current editor-patch-tests-1 or subsequent layout evaluation is included. No executables, DLLs, caches or private profiles are included, and no native trial payload is duplicated. PAYLOAD-MANIFEST.json covers all members except itself; external archive-result.json binds the entire archive. +""" +add(Path(__file__).relative_to(ROOT), "archive-tools/build_archive.py") +payload["READBACK-SOURCES.json"] = encoded([{"path": str(Path(path).relative_to(ROOT)), "sha256": sha(data), "bytes": len(data)} for path, data in originals.items()]) +payload["PAYLOAD-MANIFEST.json"] = encoded({"selfExcluded": "PAYLOAD-MANIFEST.json", "members": [{"path": name, "bytes": len(data), "sha256": sha(data)} for name, data in sorted(payload.items())]}) +archive = OUT / "source-rename-completed-evidence-20260912.zip" +with zipfile.ZipFile(archive, "x", compression=zipfile.ZIP_DEFLATED, compresslevel=9) as zipped: + for name, data in sorted(payload.items()): + info = zipfile.ZipInfo(PREFIX + name, date_time=(2026, 9, 12, 0, 0, 0)) + info.compress_type = zipfile.ZIP_DEFLATED + zipped.writestr(info, data) +with zipfile.ZipFile(archive) as zipped: + assert zipped.testzip() is None and set(zipped.namelist()) == {PREFIX + n for n in payload} + for name, data in payload.items(): + assert zipped.read(PREFIX + name) == data +for path, data in originals.items(): + assert Path(path).read_bytes() == data, "Source changed during archive: " + path +receipt = {"archive": archive.name, "sha256": sha(archive.read_bytes()), "bytes": archive.stat().st_size, + "members": len(payload), "payloadBytes": sum(map(len, payload.values())), "completedRuns": RUNS, + "commandReceipts": 8, "inputArchivesVerified": 5, "sourceReadbacks": len(originals), + "allMemberBytesAndCrcVerified": True, "scope": summary["scope"]} +with (OUT / "archive-result.json").open("x", encoding="utf-8") as stream: + json.dump(receipt, stream, indent=2) +print(json.dumps(receipt)) diff --git a/harness/experiments/source-alias-rename-completed-20260912/independent-review.md b/harness/experiments/source-alias-rename-completed-20260912/independent-review.md new file mode 100644 index 00000000..0b3d4bd0 --- /dev/null +++ b/harness/experiments/source-alias-rename-completed-20260912/independent-review.md @@ -0,0 +1,11 @@ +# Independent archive verification — PASS + +2026-09-12, `/root/publication_review`. No discrepancies found. Read-only verification of archive/original bytes; no archived helper, project code, Cargo or native application was executed. See `independent-verification.json` and the separate `independent_verify.py` evaluator. + +- Whole ZIP matches `archive-result.json`: SHA256 `2282e4e755bb03ab3ecb079391909f3978297ad307e76306ef7eb5a87a9437cf`, 10,755,689 bytes, 77 members, 12,361,849 uncompressed payload bytes. +- Complete outer manifest membership, every payload hash/length and all CRCs pass. All five nested input ZIPs pass exact membership, every input hash/length and CRC: 513/514/514/514/515 members respectively. No duplicate or unsafe paths, executable/DLL/cache/profile payloads, or nested native archive duplicates were found. +- All eight completed command receipts agree with their raw log hashes and summary entries. All 73 original-source readbacks are byte-identical, including the archive builder. External native ZIP `77adda5a…` and preserved executable `d1ec6305…` match their complete SHA256 and byte bindings. +- Raw outcomes match the stated historical scope: attempt6 has 796 tests passed, zero failed, two ignored, plus successful strict Clippy, separate ignored timing and executable build. The clipping negative control fails with the recorded glyph cluster92..93 beneath the scrollbar. The corrected-layout diagnostic run passes 33 focused tests; nested timing passes its one experiment. Editor-patch-check-1 is a successful **check**, not executed behavior. +- The original candidate `f301b8a0…`, its documented LFCR finding, and corrected helper `049c9774…` inside the completed check snapshot are correctly distinguished. Staged clipping hashes and nested timing summary-to-log binding pass. + +Limitations are accurately stated in INDEX.md: this is historical evidence, not acceptance of the current reuse candidate, subsequent evaluator runs, corrected native layout, or release. Native trial payload remains separately bound. Helper sources labeled archive-time readbacks are not asserted to be the exact historical executed versions. Historical uncommitted input snapshots, rather than baseCommit alone, identify each tested source. No new native painting or latency claim follows from this verification. diff --git a/harness/experiments/source-alias-rename-completed-20260912/independent-verification.json b/harness/experiments/source-alias-rename-completed-20260912/independent-verification.json new file mode 100644 index 00000000..4ec1ff3b --- /dev/null +++ b/harness/experiments/source-alias-rename-completed-20260912/independent-verification.json @@ -0,0 +1,133 @@ +{ + "status": "PASS", + "checks": 2945, + "archiveSha256": "2282e4e755bb03ab3ecb079391909f3978297ad307e76306ef7eb5a87a9437cf", + "bytes": 10755689, + "members": 77, + "payloadBytes": 12361849, + "nestedInputs": { + "attempt-6": { + "members": 513, + "sha256": "03b5a9e3f4e9e220421320c09f1ecf46f811edf2e3c6c45dcd9522c6d78b8255", + "topLevelCounts": { + "Cargo.lock": 1, + "Cargo.toml": 1, + "build": 3, + "crates": 275, + "docs": 18, + "examples": 51, + "harness": 164 + } + }, + "clipping-negative-1": { + "members": 514, + "sha256": "1a59b58373d615a534244881a931f4423f590f04e0e632c986bf2a93af7d287d", + "topLevelCounts": { + "Cargo.lock": 1, + "Cargo.toml": 1, + "build": 3, + "crates": 276, + "docs": 18, + "examples": 51, + "harness": 164 + } + }, + "clipping-positive-diagnostic-1": { + "members": 514, + "sha256": "fc899e533e04317d0ba27dfa9f1bdfbfca77d3dede8478c45480f0edb19931a0", + "topLevelCounts": { + "Cargo.lock": 1, + "Cargo.toml": 1, + "build": 3, + "crates": 276, + "docs": 18, + "examples": 51, + "harness": 164 + } + }, + "nested-sync-diagnostic-1": { + "members": 514, + "sha256": "5bbd5145f6eea69fabe5cbfa3da14f059cf4446de49072f8714a5dc709d35cfa", + "topLevelCounts": { + "Cargo.lock": 1, + "Cargo.toml": 1, + "build": 3, + "crates": 276, + "docs": 18, + "examples": 51, + "harness": 164 + } + }, + "editor-patch-check-1": { + "members": 515, + "sha256": "1b18763ba3f74cbff0e842ff51b58879a6d7f82daac4ce65086b8c579ae0b272", + "topLevelCounts": { + "Cargo.lock": 1, + "Cargo.toml": 1, + "build": 3, + "crates": 277, + "docs": 18, + "examples": 51, + "harness": 164 + } + } + }, + "commandReceipts": [ + { + "run": "attempt-6", + "phase": "clippy", + "exitCode": 0 + }, + { + "run": "attempt-6", + "phase": "tests", + "exitCode": 0 + }, + { + "run": "attempt-6", + "phase": "timing", + "exitCode": 0 + }, + { + "run": "attempt-6", + "phase": "gui", + "exitCode": 0 + }, + { + "run": "clipping-negative-1", + "phase": "command", + "exitCode": 101 + }, + { + "run": "clipping-positive-diagnostic-1", + "phase": "command", + "exitCode": 0 + }, + { + "run": "nested-sync-diagnostic-1", + "phase": "command", + "exitCode": 0 + }, + { + "run": "editor-patch-check-1", + "phase": "command", + "exitCode": 0 + } + ], + "originalReadbacks": 73, + "originalDeltas": [], + "externalBindings": [ + { + "path": "harness/experiments/source-alias-rename-native-20260912/source-rename-native-attempt-6-20260912.zip", + "sha256": "77adda5a33eb1def6dab23352ca0ab172300ea65fc21d2c215d545d7fcce0d08", + "bytes": 3221627 + }, + { + "path": ".local/source-rename-integration-20260912/attempt-6/arcadia-studio.exe", + "sha256": "d1ec63050e95513064155e9d04f443d95667b1e468dcdbb3b810dad379504814", + "bytes": 113854464 + } + ], + "failures": [], + "scope": "Independent byte/CRC/membership and receipt verification only; no archived or production code executed." +} \ No newline at end of file diff --git a/harness/experiments/source-alias-rename-completed-20260912/independent_verify.py b/harness/experiments/source-alias-rename-completed-20260912/independent_verify.py new file mode 100644 index 00000000..157a6283 --- /dev/null +++ b/harness/experiments/source-alias-rename-completed-20260912/independent_verify.py @@ -0,0 +1,140 @@ +"""Read archive/original bytes only; never import or execute archived helpers.""" +from pathlib import Path, PurePosixPath, PureWindowsPath +from collections import Counter +import hashlib +import io +import json +import zipfile + +root = Path(__file__).resolve().parents[2] +folder = Path(__file__).resolve().parent +receipt = json.loads((folder / 'archive-result.json').read_bytes()) +raw = (folder / receipt['archive']).read_bytes() +sha = lambda b: hashlib.sha256(b).hexdigest() +failures = [] +checks = 0 +def check(ok, message): + global checks + checks += 1 + if not ok: + failures.append(message) +def safe(name): + pos = PurePosixPath(name) + win = PureWindowsPath(name) + return not pos.is_absolute() and not win.is_absolute() and not win.drive and '..' not in pos.parts and '\\' not in name +def verify_zip(z, label): + names = z.namelist() + check(len(names) == len(set(names)), label + ': duplicate member') + check(z.testzip() is None, label + ': CRC') + check(all(safe(n) for n in names), label + ': unsafe member path') + check(all(not n.endswith('/') for n in names), label + ': unexpected directory member') + check(all(PurePosixPath(n).suffix.lower() not in {'.exe', '.dll', '.pyc'} for n in names), label + ': executable/cache member') + check(all(not ({'node_modules', 'target', '.git', '__pycache__', 'profile', 'profiles', 'cache', 'caches'} & set(PurePosixPath(n).parts)) for n in names), label + ': out-of-scope directory') + return names + +check(sha(raw) == receipt['sha256'], 'whole archive SHA') +check(len(raw) == receipt['bytes'], 'whole archive bytes') +prefix = 'source-rename-completed-evidence/' +z = zipfile.ZipFile(io.BytesIO(raw)) +names = verify_zip(z, 'outer') +check(len(names) == receipt['members'] == 77, 'outer member count') +check(all(n.startswith(prefix) for n in names), 'outer prefix') +payload = {n[len(prefix):]: z.read(n) for n in names} +check(sum(map(len, payload.values())) == receipt['payloadBytes'], 'outer payload bytes') +manifest = json.loads(payload['PAYLOAD-MANIFEST.json']) +entries = manifest['members'] +check(manifest['selfExcluded'] == 'PAYLOAD-MANIFEST.json', 'manifest self exclusion') +check(len(entries) == len({e['path'] for e in entries}), 'manifest duplicate entry') +check(set(e['path'] for e in entries) == set(payload) - {'PAYLOAD-MANIFEST.json'}, 'manifest complete membership') +for entry in entries: + data = payload[entry['path']] + check(len(data) == entry['bytes'] and sha(data) == entry['sha256'], 'manifest member: ' + entry['path']) + +source_maps = [ + ('.local/source-rename-latency-diagnosis-20260912/', 'diagnosis/'), + ('.local/source-rename-preview-clipping-20260912/', 'clipping-stage/'), + ('.local/source-rename-controller-independent-review-20260912/', 'reviews/'), +] +source_entries = json.loads(payload['READBACK-SOURCES.json']) +check(len(source_entries) == receipt['sourceReadbacks'] == 73, 'readback count') +original_deltas = [] +for entry in source_entries: + source = entry['path'].replace('\\', '/') + check(safe(source), 'unsafe original path: ' + source) + if source.endswith('/build_archive.py'): + member = 'archive-tools/build_archive.py' + elif source in {'.local/source-rename-integration-20260912/gate.py', '.local/source-rename-integration-20260912/focused.py'}: + member = 'helpers-current-readback/' + source.rsplit('/', 1)[1] + elif source.startswith('.local/source-rename-integration-20260912/'): + member = 'runs/' + source.removeprefix('.local/source-rename-integration-20260912/') + else: + mapped = [target + source.removeprefix(base) for base, target in source_maps if source.startswith(base)] + check(len(mapped) == 1, 'original target mapping: ' + source) + if not mapped: + continue + member = mapped[0] + archived = payload[member] + check(len(archived) == entry['bytes'] and sha(archived) == entry['sha256'], 'readback archive binding: ' + member) + actual = (root / source).read_bytes() + if actual != archived: + original_deltas.append({'path': source, 'currentSha256': sha(actual), 'archiveSha256': sha(archived)}) +check(not original_deltas, 'original source byte differences') + +summary = json.loads(payload['SUMMARY.json']) +runs = receipt['completedRuns'] +check(runs == ['attempt-6', 'clipping-negative-1', 'clipping-positive-diagnostic-1', 'nested-sync-diagnostic-1', 'editor-patch-check-1'], 'completed run scope') +check({PurePosixPath(n).parts[1] for n in payload if n.startswith('runs/')} == set(runs), 'actual run membership') +nested = {} +commands = [] +for run in runs: + start = f'runs/{run}/' + manifest = json.loads(payload[start + 'inputs.json']) + data = payload[start + 'inputs.zip'] + check(sha(data) == manifest['archiveSha256'], run + ': input ZIP binding') + inner = zipfile.ZipFile(io.BytesIO(data)) + inner_names = verify_zip(inner, run) + expected = manifest['files'] + check(len(expected) == len({e['path'] for e in expected}), run + ': duplicate input manifest entry') + check(set(inner_names) == {e['path'] for e in expected}, run + ': input membership') + for entry in expected: + item = inner.read(entry['path']) + check(len(item) == entry['bytes'] and sha(item) == entry['sha256'], run + ': ' + entry['path']) + nested[run] = {'members': len(inner_names), 'sha256': sha(data), 'topLevelCounts': dict(Counter(PurePosixPath(n).parts[0] for n in inner_names))} + recorded = [r for r in summary['checks'] if r['run'] == run and 'inputArchiveSha256' in r] + check(len(recorded) == 1 and recorded[0]['inputArchiveSha256'] == sha(data) and recorded[0]['inputMembers'] == len(inner_names), run + ': summary input binding') + phases = ['clippy', 'tests', 'timing', 'gui'] if run == 'attempt-6' else [''] + for phase in phases: + stem = phase + '-' if phase else '' + result = json.loads(payload[start + stem + 'result.json']) + check(bool(result['finished']) and result['inputsUnchanged'] and result['started'] < result['finished'], run + ': completion ' + phase) + check(result['exitCode'] == (101 if run == 'clipping-negative-1' else 0), run + ': exit ' + phase) + for stream in ['stdout', 'stderr']: + check(sha(payload[start + stem + stream + '.log']) == result[stream + 'Sha256'], run + ': log ' + phase + stream) + recorded = [r for r in summary['checks'] if r['run'] == run and r.get('phase') == (phase or 'command')] + check(len(recorded) == 1 and all(recorded[0][key] == result[key] for key in ['command', 'finished', 'exitCode']), run + ': command summary ' + phase) + commands.append({'run': run, 'phase': phase or 'command', 'exitCode': result['exitCode']}) + if run == 'editor-patch-check-1': + corrected = inner.read('crates/oa-desktop/src/app/source_rename/editor_patch.rs') + check(sha(corrected) == summary['correctedHelperFromCheckInputSha256'] == '049c9774c1ca28cda01f9a8e024604bef282366aa52c53c17c1918dbd09c3441', 'corrected helper binding') +check(len(commands) == receipt['commandReceipts'] == 8, 'command count') +check(len(nested) == receipt['inputArchivesVerified'] == 5, 'input archive count') +complete = json.loads(payload['runs/attempt-6/complete.json']) +check(complete['inputsUnchanged'] and complete['gates'] == ['clippy', 'tests', 'timing', 'gui'], 'gate6 closure') +check(sha(payload['diagnosis/candidate/editor_patch.rs']) == 'f301b8a043916b69dccb176da527a50ee85124b7e8b1da18921e4a0374a5153b', 'original candidate binding') +check('source glyph under scrollbar' in payload['runs/clipping-negative-1/stderr.log'].decode() and 'cluster=92..93' in payload['runs/clipping-negative-1/stderr.log'].decode(), 'negative glyph failure receipt') +check(json.loads(payload['diagnosis/nested-summary.json'])['logSha256'] == sha(payload['runs/nested-sync-diagnostic-1/stdout.log']), 'nested timing summary log binding') +for entry in json.loads(payload['clipping-stage/staged-hashes.json']): + member = 'clipping-stage/' + PureWindowsPath(entry['Path']).name + check(sha(payload[member]) == entry['Hash'].lower(), 'staged layout source binding: ' + member) +external = [] +for entry in summary['externalBindings']: + data = (root / entry['path']).read_bytes() + check(not entry['included'], 'external mistakenly marked included') + check(len(data) == entry['bytes'] and sha(data) == entry['sha256'], 'external binding: ' + entry['path']) + external.append({'path': entry['path'], 'sha256': sha(data), 'bytes': len(data)}) +binary = json.loads(payload['runs/attempt-6/gui-result.json'])['binary'] +check(external[1]['sha256'] == binary['sha256'] and external[1]['bytes'] == binary['bytes'], 'external binary gate receipt') + +result = {'status': 'PASS' if not failures else 'FAIL', 'checks': checks, 'archiveSha256': sha(raw), 'bytes': len(raw), 'members': len(names), 'payloadBytes': sum(map(len, payload.values())), 'nestedInputs': nested, 'commandReceipts': commands, 'originalReadbacks': len(source_entries), 'originalDeltas': original_deltas, 'externalBindings': external, 'failures': failures, 'scope': 'Independent byte/CRC/membership and receipt verification only; no archived or production code executed.'} +(folder / 'independent-verification.json').write_text(json.dumps(result, indent=2), encoding='utf-8') +print(json.dumps(result, indent=2)) diff --git a/harness/experiments/source-alias-rename-completed-20260912/source-rename-completed-evidence-20260912.zip b/harness/experiments/source-alias-rename-completed-20260912/source-rename-completed-evidence-20260912.zip new file mode 100644 index 00000000..7ce2c7d5 Binary files /dev/null and b/harness/experiments/source-alias-rename-completed-20260912/source-rename-completed-evidence-20260912.zip differ diff --git a/harness/experiments/source-alias-rename-native-20260912/archive-result.json b/harness/experiments/source-alias-rename-native-20260912/archive-result.json new file mode 100644 index 00000000..07e7d533 --- /dev/null +++ b/harness/experiments/source-alias-rename-native-20260912/archive-result.json @@ -0,0 +1,59 @@ +{ + "archive": "C:\\Users\\User\\Documents\\Git\\ARCADIA-Studio\\.local\\source-rename-native-evidence-20260912\\source-rename-native-attempt-6-20260912.zip", + "sha256": "77adda5a33eb1def6dab23352ca0ab172300ea65fc21d2c215d545d7fcce0d08", + "bytes": 3221627, + "members": 284, + "payloadBytes": 5375259, + "screenshots": { + "metadataFiles": 47, + "originalJpegFiles": 59 + }, + "verifiedUnchangedReadbacks": 285, + "exactFixtureReadbacks": [ + { + "case": "simple", + "variant": "baseline", + "matchesManifest": "original_files", + "files": 4, + "bytes": 772 + }, + { + "case": "simple", + "variant": "expected", + "matchesManifest": "expected_files", + "files": 4, + "bytes": 786 + }, + { + "case": "simple", + "variant": "work", + "matchesManifest": "expected_files", + "files": 4, + "bytes": 786 + }, + { + "case": "representative", + "variant": "baseline", + "matchesManifest": "original_files", + "files": 37, + "bytes": 294617 + }, + { + "case": "representative", + "variant": "expected", + "matchesManifest": "expected_files", + "files": 37, + "bytes": 294641 + }, + { + "case": "representative", + "variant": "work", + "matchesManifest": "original_files", + "files": 37, + "bytes": 294617 + } + ], + "zipCrcAndAllMemberBytesVerified": true, + "scope": "Completed attempt-6 native trial only; partial native outcome, not acceptance or release.", + "binarySha256": "d1ec63050e95513064155e9d04f443d95667b1e468dcdbb3b810dad379504814" +} \ No newline at end of file diff --git a/harness/experiments/source-alias-rename-native-20260912/review.md b/harness/experiments/source-alias-rename-native-20260912/review.md new file mode 100644 index 00000000..dc7ec986 --- /dev/null +++ b/harness/experiments/source-alias-rename-native-20260912/review.md @@ -0,0 +1,20 @@ +# Independent archive review + +Reviewer: Codex-9e8r6t /root/native_archive. Reviewed 2026-09-12. PASS for archival integrity and claim scope; this is not native acceptance. + +Reviewed archive: source-rename-native-attempt-6-20260912.zip + +- SHA256: 77adda5a33eb1def6dab23352ca0ab172300ea65fc21d2c215d545d7fcce0d08 +- ZIP size: 3,221,627 bytes; 284 unique members. +- ZIP CRC check passed. Exact manifest membership and all 283 payload byte lengths/SHA256 values passed; PAYLOAD-MANIFEST.json correctly excludes itself. +- All 59 original JPEGs and 47 metadata files match the original trial directory byte-for-byte, with exact membership. +- All six physical fixture trees match the preauthored fixture manifest: simple baseline/expected/work contain four files each; representative baseline/expected/work contain 37 each. Simple work matches expected; representative work remains baseline. Physical support files are retained. +- All five saved-disk verification receipts report exit 0, no failure, exact physical-byte match and unchanged-by-oracle. Their expected variants, four-file maps, pinned oracle/DLL/binary hashes, and stdout/stderr hashes agree with the archived evidence. Their logs report exact model/identity/four reachable sources and four exact disk files. +- Closure receipt binds PID 9108, exit 0, unchanged binary/runtime and SHA256 values of both empty raw logs. +- Historical launcher SHA256 cf65065d18c110a029ec4dc6bbf712cfedc0b9970992b42cb158e676a289b343 verified. Comparison to the current launcher shows only the later profile/Desktop mkdir-list entry; the archive accurately describes the historical helper as a hash-proved reconstruction. + +INDEX.md and SUMMARY.json explicitly identify the minimum-size preview clipping failure and partial native outcome. They do not claim representative native rename, immediate Undo Rename acceptance, unsaved-memory inspection by disk oracles, or acceptance of a later repair. The saved Undo/Redo evidence concerns model Undo/Redo with subsequent saved-disk checks. + +No executable, DLL, private-profile directory or cache payload is included. External binary/source-build bindings remain separate; archived relocated helpers are not represented as portable launch instructions. + +This review used read-only archive/hash/CRC comparisons, receipt inspection and comparison with original files. No Cargo, compiler, native application, oracle, GUI, network or production edit was executed. This note records that completed review without rerunning it. diff --git a/harness/experiments/source-alias-rename-native-20260912/source-rename-native-attempt-6-20260912.zip b/harness/experiments/source-alias-rename-native-20260912/source-rename-native-attempt-6-20260912.zip new file mode 100644 index 00000000..5155a9c6 Binary files /dev/null and b/harness/experiments/source-alias-rename-native-20260912/source-rename-native-attempt-6-20260912.zip differ diff --git a/harness/experiments/source-alias-rename-refresh-20260912/archive-result.json b/harness/experiments/source-alias-rename-refresh-20260912/archive-result.json new file mode 100644 index 00000000..c79d46a2 --- /dev/null +++ b/harness/experiments/source-alias-rename-refresh-20260912/archive-result.json @@ -0,0 +1,20 @@ +{ + "archive": "source-rename-refresh-evidence-20260912.zip", + "sha256": "d46aacbba1dfccec64b195482e2857c97ceefecad6b0176c62c73c50964e18ba", + "bytes": 6411947, + "members": 37, + "payloadBytes": 7201600, + "completedRuns": [ + "editor-patch-tests-2", + "editor-patch-timing-1", + "attempt-7" + ], + "commandReceipts": 6, + "inputArchivesVerified": 3, + "inputMembersEach": 516, + "exactThreeWayInputMembershipAndBytes": true, + "originalReadbacks": 34, + "allMemberBytesAndCrcVerified": true, + "externalBinarySha256": "2486eecc00d8de9160ecd930f69394e00b1a1ce102d76fb776b978db33414ed3", + "scope": "Windows debug source gates and bounded timing only; corrected native trial not yet accepted." +} diff --git a/harness/experiments/source-alias-rename-refresh-20260912/independent-review-receipt.json b/harness/experiments/source-alias-rename-refresh-20260912/independent-review-receipt.json new file mode 100644 index 00000000..fc2d6968 --- /dev/null +++ b/harness/experiments/source-alias-rename-refresh-20260912/independent-review-receipt.json @@ -0,0 +1,52 @@ +{ + "scope": "Independent archive byte/CRC/provenance review only; no execution of builders, project code, native app or gate tools. No corrected native acceptance.", + "archiveSha256": "d46aacbba1dfccec64b195482e2857c97ceefecad6b0176c62c73c50964e18ba", + "archiveBytes": 6411947, + "members": 37, + "manifestPayloadsVerified": 36, + "originalReadbacks": 34, + "nestedInputArchives": 3, + "nestedInputMembersEach": 516, + "exactThreeWayInputMembershipAndBytes": true, + "allCrcsAndMemberHashesPassed": true, + "completedCommands": [ + { + "run": "editor-patch-tests-2", + "phase": "", + "finished": "2026-09-12T13:51:44.023824+00:00" + }, + { + "run": "editor-patch-timing-1", + "phase": "", + "finished": "2026-09-12T13:54:04.503303+00:00" + }, + { + "run": "attempt-7", + "phase": "clippy", + "finished": "2026-09-12T14:00:02.795856+00:00" + }, + { + "run": "attempt-7", + "phase": "tests", + "finished": "2026-09-12T14:09:16.517298+00:00" + }, + { + "run": "attempt-7", + "phase": "timing", + "finished": "2026-09-12T14:10:05.679440+00:00" + }, + { + "run": "attempt-7", + "phase": "gui", + "finished": "2026-09-12T14:15:41.805763+00:00" + } + ], + "externalBinary": { + "path": ".local/source-rename-integration-20260912/attempt-7/arcadia-studio.exe", + "sha256": "2486eecc00d8de9160ecd930f69394e00b1a1ce102d76fb776b978db33414ed3", + "bytes": 113879552, + "included": false + }, + "producerReceiptSha256": "ec91311ea6850745960072571d088415df4d3f3210e58c0dad1bd4f0ee7135ad", + "builderSha256": "6fbfca25bf38c459e723f30b9333786372a5207c937e34b6204d6f8161baca11" +} \ No newline at end of file diff --git a/harness/experiments/source-alias-rename-refresh-20260912/independent-review.md b/harness/experiments/source-alias-rename-refresh-20260912/independent-review.md new file mode 100644 index 00000000..19111077 --- /dev/null +++ b/harness/experiments/source-alias-rename-refresh-20260912/independent-review.md @@ -0,0 +1,15 @@ +# Independent refresh archive review + +2026-09-12; Codex-9e8r6t /root/native_archive. PASS for archive integrity, original bindings and stated scope. No builder/project code, Cargo, native application or gate tool was executed. The active native trial was not touched or evaluated. + +Archive SHA256 d46aacbba1dfccec64b195482e2857c97ceefecad6b0176c62c73c50964e18ba; 6,411,947 bytes;37 unique members. This agrees with archive-result.json (the earlier dispatch typo is not authoritative). + +ZIP CRC and all36 manifest payload byte lengths/SHA256 values passed, with exact membership and correct self-exclusion. All34 ORIGINAL-SOURCES bindings match both archived member bytes and current preserved originals; adjacent INDEX.md/PAYLOAD-MANIFEST.json match their archived versions. All three nested input ZIP hashes, CRCs and516-member manifests passed. Exact member sets and bytes are equal across tests-2, timing-1 and attempt-7 despite distinct whole ZIP hashes. + +All six command receipts have terminal timestamps, exit0 and inputsUnchanged=true; raw stdout/stderr hashes agree. Attempt-7 complete.json lists the four completed Clippy/tests/timing/GUI gates. Its full test log reports802 passed,0 failed,3 ignored. GUI completion is14:15:41.805763UTC. Static App-review source bindings match the exact archived inputs; the earlier execution review's receipt/log/input bindings also match. Its then-running attempt-7 language is correctly identified as historical in the index. + +The external preserved binary independently matches2486eecc00d8de9160ecd930f69394e00b1a1ce102d76fb776b978db33414ed3 and113,879,552 bytes. Binary bytes are excluded. No executable/DLL/cache/profile payload was found, including nested input archives. + +Builder inspected as source only: explicit completed-run whitelist, exclusive outputs, exact input/log/source checks, original readbacks and no project execution. The index honestly limits conclusions to completed Windows debug source gates and bounded timing. It distinguishes ordinary sync from optimized Confirm, fixed-fixture timing from native/GPU/first-paint results, and static reviews from executable assertions. It makes no corrected-native acceptance or later-source claim. The new native trial remains separate. + +Detailed bindings/check outcomes: independent-review-receipt.json. Original archive, builder and producer receipt are unchanged. diff --git a/harness/experiments/source-alias-rename-refresh-20260912/source-rename-refresh-evidence-20260912.zip b/harness/experiments/source-alias-rename-refresh-20260912/source-rename-refresh-evidence-20260912.zip new file mode 100644 index 00000000..1d4a7067 Binary files /dev/null and b/harness/experiments/source-alias-rename-refresh-20260912/source-rename-refresh-evidence-20260912.zip differ diff --git a/harness/release-source-alias-rename-design-20260911.md b/harness/release-source-alias-rename-design-20260911.md index 1da6695a..962a6f5b 100644 --- a/harness/release-source-alias-rename-design-20260911.md +++ b/harness/release-source-alias-rename-design-20260911.md @@ -39,11 +39,11 @@ Resolve only an alias token or live `@` use under the exact caret/selection, usi 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. 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. +**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. Proposed display admission is 256 changed files, 50,000 changed lines and 8 MiB of retained diff display data; exceeding a bound explains that no rename was applied. Page complete admitted hunks; never approve a truncated candidate. These are proposed 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. +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. diff --git a/harness/release-source-alias-rename-validation-20260912.md b/harness/release-source-alias-rename-validation-20260912.md new file mode 100644 index 00000000..dd206e47 --- /dev/null +++ b/harness/release-source-alias-rename-validation-20260912.md @@ -0,0 +1,350 @@ +# Text alias rename — branch validation + +Codex-9e8r6t `/root`, Windows, 2026-09-12. This records **uncommitted branch work** +over `be7a8cd8d7d63aa18e0196bbd36f9e646764c761`; it is not an integrated release +or native acceptance claim. [Issue 9](http://217.177.34.108:3000/sorokin.oleg.edu/ARCADIA-Studio/issues/9) +owns the current task. The [design](release-source-alias-rename-design-20260911.md) +and [transaction critique](release-source-alias-rename-transaction-critique-20260911.md) +define the intended behavior and evaluators. Linux/WSL remains user-paused. + +## Verification method + +Root coordinates one Windows compiler job. The local toolchain environment is +`.local/toolchain/env.ps1`; `CARGO_BUILD_JOBS=1`. Commands use `--locked --offline` +and the Windows GNU LLVM development profile. The attempt helper +`.local/source-rename-integration-20260912/gate.py` preserves each attempt in an +exclusive directory, including raw input ZIP, complete scoped file membership, +per-file hashes, compiler/environment records, raw logs and stage receipts. +It verifies the same file membership and bytes before and after each command. +Its scopes include the workspace manifests, crates, build support, Cargo config, +documentation, examples and harness fixtures. These private evidence directories +are not yet published artifacts; preserve them until final evidence packaging. + +The serial gates are strict Clippy for all desktop targets, the complete desktop +binary test suite, an explicit ignored representative timing experiment and +the matching desktop build. Attempts 1–5 ran tests before Clippy; attempt 6 +moves Clippy first to catch lint failures before the longer suite. A failed +stage stops the attempt. Native checks +use a separately identified executable only after these gates pass. + +## Earlier findings and verified results + +The isolated Document/query trial initially omitted `build/windows_manifest.rs` +from its reconstruction and failed before tests. Its corrected `v2` capture +passed 8 alias-transaction, 13 existing Document and 20 query tests, finishing +at 11:20:55 UTC. This establishes those isolated seams only. The combined +`cargo check --locked --offline -p oa-desktop --tests` subsequently passed; +unused preview range accessors were removed after its warning. + +Attempt 1 failed compilation on two mounted-test calls that attempted mutable +widget operations through `as_widget()`. Correcting those test calls to +`as_widget_mut()` allowed execution. Attempt 2 passed 791 tests, failed one and +ignored two. Its sole failure used an invalid property-field key, `name` instead +of `/name`, so it had never created the intended dirty draft. The fixture was +corrected and strengthened to assert retention of the exact `/name` draft value. +Neither finding justified a production behavior change. + +Attempt 3 passed **792 tests, zero failed, two ignored**, finishing at +11:49:39.273922 UTC (165.53 seconds of test execution). Its captured inputs +remained unchanged. Raw stdout SHA-256: +`392379b23ca446ad1d617da25c640f2911a9ab643fd61d6b8fc15a72d346f92b`; +stderr: `f5b640295276418cb45226fe82f3dfdfe5f7ee018c1777516784f80d562620a3`. +The subsequent strict Clippy stage stopped on five diagnostics: a collapsible +search conditional, two constant platform/profile assertions in the timing +experiment, a test-case type-complexity diagnostic and field reassignment after +`Default` in a query test. The correction uses a let-chain, scopes the manual +timing module to Windows debug tests, names the case type and initializes the +query limit directly. The platform-specific experiment does not prevent other +platforms or release profiles from compiling their applicable tests. + +No timing or desktop-build stage ran in attempts 1–3. Passing attempt 3 does not +cover the subsequent paste guard described below. + +Attempt 4 passed 792 tests, failed the newly added normal-paste assertion and +ignored two, finishing at 12:03:16.113761 UTC (167.39 seconds of test execution). +The rejection cases reached their expected outcomes before the normal-paste +case failed. The attempt's captured inputs remained unchanged; no subsequent +gate ran. Its stdout SHA-256 is +`62cc9471678fabe08fc32db0e46665f1b9babd1d70f814371995c96a6b5de430`. +Root and the implementation owner independently traced the failure to the test +fixture: Iced calls the test operation's selection callback before its focus +callback, and `focus()` moves the cursor to the end. Thus the fixture erased its +own selection before pasting. The correction must focus and select separately, +assert a real nonempty selection and retain the exact replacement oracle. This +is an evaluator defect, not a reason to change valid-paste production behavior. + +## Clipboard finding and correction + +Root inspected the actual dependency source, Iced `iced_widget` 0.14.2 +`src/text_input.rs`, whose paste path filters `char::is_control` before invoking +either input callback. Consequently, a pasted `foo\nbar` could silently become +the valid alias `foobar`. Merely validating the callback value or adding an +`on_paste` callback would miss the original input. This contradicted the +design's prohibition on silent replacement normalization. + +The alias field now has a narrow widget adapter that checks the actual paste +shortcut before the child input handles it. It rejects the whole paste if it +contains control characters, retaining field text and selection, displaying +feedback and invalidating the previous preview approval and pending intent. +An occupied worker remains occupied until its matching completion. Permitted +first-paste input uses one captured clipboard value passed to the child; normal +Iced editing, focus and key-repeat behavior remain with the child widget. +No dependency, vendor or cached Iced source was changed. + +Mounted evaluator cases cover newline, tab, CRLF and NUL refusal; unchanged +selection through feedback/rebuild; normal valid paste; exactly one actual +clipboard read; and refusal of an old confirmation. Independent review checks +the wrapper against the cached Iced implementation, with particular attention +to stored modifiers, focus, pending workers and repeated paste. + +That review found another production counterexample: the wrapper initially +reset its modifier state on `KeyPressed.key == Escape`, whereas the child uses +its effective dispatch, including `modified_key` and earlier shortcut returns. +For `key=Escape, modified_key=Home`, the wrapper could clear Command while the +child retained it, allowing a following paste to bypass rejection. The +correction observes the child's actual focused-to-unfocused transition after +forwarding a key press instead of guessing its dispatch. Mounted tests must +exercise mismatched key fields, pending worker retention and the relevant +focus/enabled/modifier conditions. Held-key paste may reuse the child's earlier +admitted cache; the single-read claim applies to fresh clipboard reads. + +The final bounded static review found no remaining concrete paste defect and +bound the corrected adapter, wrapper tests and controller tests to exact hashes +in `.local/source-rename-controller-independent-review-20260912/paste-resolution-bindings.json`. +The focused `source_rename::` run then passed **32 tests, zero failed, one +ignored**, finishing at 12:08:16.497392 UTC (3.20 seconds of test execution). +This includes the actual-selection correction, valid paste, the 20-condition +focus/enabled/modifier matrix, divergent key fields, held-key cache release and +pending-worker rejection. Raw logs and the command receipt are retained under +`.local/source-rename-integration-20260912/focused-paste-v2`. + +## Remaining acceptance + +Attempt 5 passed the full desktop suite: **796 passed, zero failed, two +ignored**, finishing at 12:11:20.769886 UTC (147.44 seconds of execution). +Inputs remained unchanged. Stdout SHA-256: +`38e9413b678de73fdc1e277be5313193002c81326f32e29bafdd4e45701fe322`; +stderr: `43c2d65557dd4392177fcb91e097ca375acfc796928e92a51b129c69892fb66d`. +Its Clippy stage subsequently found a preview helper used only by tests and an +obsolete `expect(dead_code)` on the now-used authored identity accessor. The +helper is now test-only and the obsolete expectation removed. Attempt 5 stopped +at 12:12:23.924779 UTC without timing/build execution; its Clippy stderr SHA-256 +is `87a4858cf1d4116b1938268db07095c17b301e64a1e115f42a4020da633ea58f`. +Before attempt 6 the edited guide and generated HTML were aligned to the +repository's LF policy; no frozen evidence or fixture bytes were normalized. +Attempt 6 captures these final inputs, with lint first. The native launch +helper checks this same required gate order; its behavior otherwise remains +the independently reviewed launch protocol. + +Attempt 6 passed strict all-target Clippy at 12:14:39.585030 UTC, then the +full suite (**796 passed, zero failed, two ignored**) at 12:18:12.718483 UTC +(172.07 seconds of test execution). The explicit timing experiment also passed +its complete-model/source/identity/history assertions at 12:18:36.171758 UTC. +All three stages verified unchanged captured inputs. The desktop build also +passed at 12:21:39.274814 UTC. Its preserved executable is 113,854,464 bytes, +SHA-256 `d1ec63050e95513064155e9d04f443d95667b1e468dcdbb3b810dad379504814`. +The 513-file raw input ZIP SHA-256 is +`03b5a9e3f4e9e220421320c09f1ecf46f811edf2e3c6c45dcd9522c6d78b8255`. +All four gates verified unchanged captured membership and bytes. + +For the 30-file, 78,414-byte, 258-identity walkthrough, five measured Windows +debug trials after one warmup reported these median/range values in milliseconds: + +| Phase | Median | Min–max | +| --- | ---: | ---: | +| Mint Document request | 0.092 | 0.052–0.170 | +| Worker Document preparation | 282.259 | 165.302–298.259 | +| Worker preview and origin | 13.429 | 10.763–23.969 | +| Guarded Document commit | 0.0109 | 0.0082–0.0229 | +| Application synchronization | 495.499 | 472.030–610.017 | +| Actual Confirm update | 571.893 | 433.909–1122.241 | + +The phases and full Confirm use separate fresh fixtures with alternating trial +order; their values must not be added or subtracted as simultaneous timings. +Task polling, layout, GPU work and first paint are excluded. Fast snapshot +adoption does **not** establish a responsive UI: application refresh still takes +roughly half a second in these samples. Native assessment and a discriminating +refresh-phase diagnosis are needed before making a responsiveness claim. The +timing log SHA-256 is +`a063b67755b972e7f0b6a42c4af7fb9e1a41ecbda9775e1f40b031b8dd0c9a5c`. + +Native fixtures in `.local/source-rename-native-20260912` preserve +independent baseline/work/expected trees for a four-source project and the +30-source engineering walkthrough. Their expected edits were authored by +literal role-specific replacements, preserving every physical supporting file. +Preparation-only oracle passes do not establish future GUI correctness. + +Native acceptance must inspect complete preview access, focus and bounded +layout, cancellation, confirmation, model Undo/Redo, Save and reopen, comparing +the full saved Project, identities and source bytes against the authored oracle. +The reviewed launch helper preserves the identified executable and runtime, +uses a private profile and retains the child process handle until exit to record +the actual exit code and final logs. + +## First native transaction trial and blocking findings + +The identified attempt-6 executable ran in a private profile as PID 9108 from +12:22:14 UTC, with actual process exit zero recorded at 12:45:42.336483 UTC. +Both logs were empty; the executable and runtime DLL remained unchanged. +The private profile initially lacked a Desktop directory, causing a file-picker +notice. Creating that private directory resolved the harness setup issue. + +The four-source Unicode-path project exercised F2 on the typed reference, +invalid alias feedback, Enter to preview, Enter again without confirmation, +both changed-file previews, minimum 1100×700 client layout, Escape cancellation, +explicit confirmation, Save, persistent model Undo/Save, Redo/Save and reopen. +The new alias was selected at the original typed reference after confirmation; +the same spelling in prose remained unchanged. Reopen showed the expected +`assess_damage` alias. Five independent saved-disk oracle runs passed: cancelled +baseline, renamed save, undone save, redone save and reopened result. Each +compared the complete Project, identities and all four exact physical files. +The representative 30-source native workflow and immediate Undo Rename button +were not exercised in this trial. + +Native preview acceptance **failed**: screenshot +`trial-attempt-6/screenshots/032-simple-preview-minimum-bottom-0.jpg` shows the +final brace of the longer After declaration occluded by the vertical scrollbar. +Independent image/source review confirmed default Shrink width and a floating +scrollbar, plus inadequate wrapping for unbroken fragments. Byte-complete +preview indexes and rectangle-only layout checks did not catch this defect. +The correction must reserve scrollbar space, wrap unbroken fragments, and add +actual shaped-glyph/paint visibility checks before a new native trial. + +Publication also needs byte-reproducible source. The provenance review verified +all 513 captured files but identified 13 Git-clean baseline files whose live +CRLF bytes differ from the LF bytes in HEAD. These are strict newline-only +differences, distinct from intentional alias changes. After closing the native +trial, root verified each current hash, Git-clean status and strict newline-only +equivalence, then aligned exactly those 13 ordinary files with their HEAD LF +bytes. The receipt is `aligned-reviewed-lf.json` in the integration evidence +directory. New checks/builds use new captures; attempt-6 and all earlier raw +archives remain unchanged and bound to their original bytes. + +The new real-paragraph visibility evaluator compiled against the **old** layout +and failed as intended at 12:57:38.285740 UTC. It identified the exact native +declaration's final brace (UTF-8 cluster 92–93) at x591.398 with width6.598, +crossing the actual scrollbar boundary x587.996. Captured inputs remained +unchanged. This is a demonstrated regression falsifier, not a passing gate. +Receipt/logs: `clipping-negative-1` in the integration evidence directory; +stderr SHA-256 `2ac214f31252edeef4f33b64a46b11fb42dbf0c04848d38bb8730978d9d5ce10`. +The reviewed correction fills the preview width, reserves the scrollbar's +actual width plus spacing, and uses glyph-fallback wrapping. It leaves source +indexing and the transaction unchanged. A positive check is separate. + +The corrected layout then passed all **33 focused rename tests**, zero failed, +one ignored, at 13:05:52.950223 UTC (11.89 seconds of test execution). +That capture included disabled-by-default temporary timing instrumentation; +the geometry and transaction tests did not enable it. Inputs remained unchanged. +Stdout SHA-256 `307bd915536983fc19102fcff39535df950cee06841d968f5be2092c091ccc76`. + +The independently reviewed nested diagnostic subsequently passed the existing +full Project/source/identity/history/origin assertions in all warmup and measured +trials, finishing at 13:07:20.854282 UTC. It measured the same real Confirm +message path, with fixed-capacity timestamps enabled only around direct sync +or Confirm. In the whole-Confirm arm, five measured samples gave these medians: +actual update **1039.0 ms**, source Content assignment **996.7 ms** (814.4–1182.2), +validation **26.4 ms**, property refresh **6.3 ms**, and Workspace acceptance +**0.28 ms**. Each nested phase belongs to that same arm; earlier runs have +different absolute timings and are not a paired performance comparison. +Source Content assignment includes construction and destruction of the previous +editor. Layout, highlighting during draw and native paint remain excluded. +The raw log SHA-256 is +`a98877362ca52a024942803e0ab698a1fd84703d4512fcf7137c147a28817039`. +The temporary instrumentation was removed afterwards, restoring both exact +production baselines before implementing any candidate. + +This evidence justifies a bounded display-refresh experiment: retain the laid-out +editor and apply complete, preflighted same-line changes only after the existing +Document commit succeeds. Every ordinary synchronization step remains shared; +incompatible line endings, stale display bytes or a failed exact final readback +fall back to reconstruction from accepted source. A review found that deleting +an entire line body could introduce a greedy LFCR boundary; both before and after +preflight now refuse that representation. The candidate resets highlighting from +line zero without changing text, and restores the same approved origin. It passed +`cargo check --locked --offline -p oa-desktop --tests` at 13:25:02.235871 UTC, +with unchanged captured inputs. Execution, first subsequent layout/highlighting +cost, native behavior and final gates remain separate acceptance requirements. + +The user's new [Text UX issue 13](http://217.177.34.108:3000/sorokin.oleg.edu/ARCADIA-Studio/issues/13) +also rules out adding permanent command clutter. The new separate Undo Rename +row has been removed; the existing model Undo control uses the guarded rename +action while it remains available. Broader compact-editor work is owned in that +issue and is not claimed complete by this local adjustment. + +The completed native trial is preserved in the +[attempt-6 evidence archive](experiments/source-alias-rename-native-20260912/source-rename-native-attempt-6-20260912.zip), +with [archive receipt](experiments/source-alias-rename-native-20260912/archive-result.json) +and [independent verification](experiments/source-alias-rename-native-20260912/review.md). +Its 284 members occupy 3,221,627 compressed bytes; SHA-256 +`77adda5a33eb1def6dab23352ca0ab172300ea65fc21d2c215d545d7fcce0d08`. +The archive retains all original captures, complete fixture trees, five saved +verification receipts, helper sources and clean-exit logs; executable/DLL bytes +are externally hash-bound. The gate inputs and provenance evidence are preserved +separately below. This archive describes the first trial only; later corrections +and execution do not turn its clipping failure into a passing native result. + +## Corrected editor refresh execution + +The next-layout evaluator initially failed to compile because its new focus call +lacked Iced's `Focusable` trait import. The failed `editor-patch-tests-1` capture +is preserved unchanged; no runtime result is claimed for it. After adding that +test-only import, `editor-patch-tests-2` passed **38 focused tests**, zero failed, +two ignored, at 13:51:44.023824 UTC. This includes exact editor text and line +endings, the LFCR refusal, retained-tree highlighter reset, real Confirm/history +checks and normal synchronization fallback. All captured inputs stayed unchanged. +Stdout SHA-256: `a25dd49c669c09936d1da7ddeba4f7d3d6b6a918b72cd39dde4df6f75d201344`. + +On the same source, `editor-patch-timing-1` passed both ignored experiments at +13:54:04.503303 UTC. The real App Confirm update had median **46.0 ms** +(23.0–206.1 ms, five measured samples); ordinary `app_sync` deliberately retains +the reconstruction path and is not the same operation. The paired editor trial +used one warmup and five alternating fresh trials per arm, the 29,506-byte +traceability source, a retained widget tree, a 640×350 viewport, 14px monospace +font and 16px padding. Replacement plus next layout plus draw/highlighting had +median **35.5 ms** with reuse (13.6–73.4), versus **2782.7 ms** with reconstruction +(2697.7–3994.6). Exact source/line-ending/cursor checks and accepted alias +attributes, shaped glyph colors and visible glyph bounds passed after every arm. +This measures real text layout and highlighting, but excludes GPU/native paint +and is not an end-to-end production latency guarantee. Source inputs stayed +unchanged; stdout SHA-256: +`ae8d57e0d65084d71d92815c093607c7cd4d9d9166c562cec33a061b2fcba74c`. + +Independent static review of the App seam found no actionable defect: commit +authority, ordinary synchronization order, fallback, metadata, histories and +guarded reveal remain intact. Native focus/reveal, the next text edit, corrected +preview rendering and full gates still require their own evidence. + +The earlier completed gates and experiments are preserved separately in the +[historical evidence archive](experiments/source-alias-rename-completed-20260912/source-rename-completed-evidence-20260912.zip) +with its [independent review](experiments/source-alias-rename-completed-20260912/independent-review.md). +All 77 members, five nested source archives, eight receipt/log pairs and 73 +original readbacks passed verification. ZIP SHA-256: +`2282e4e755bb03ab3ecb079391909f3978297ad307e76306ef7eb5a87a9437cf`. +That archive intentionally ends at the earlier check-only candidate; the newer +focused execution and timing captures are separate. + +## Full corrected Windows gates + +Attempt 7 completed unchanged at **14:15:41.805763 UTC**: strict desktop Clippy +with all targets and `-D warnings`, **802 desktop tests passed** (zero failed, +three ignored), the required isolated Confirm experiment passed, and the GUI +build passed. The repeated Confirm median was 71.9 ms (43.2–101.8); the separate +paired layout experiment above remains the rendering-cost evidence. Formatting +of all changed/new Rust files passed with `rustfmt --edition 2024 --check +--config skip_children=true`; `git diff --check` also passed. + +The identified GUI is 113,879,552 bytes, SHA-256 +`2486eecc00d8de9160ecd930f69394e00b1a1ce102d76fb776b978db33414ed3`, +built with the Windows GNU LLVM development profile, no optimization/debuginfo, +and debug assertions enabled. All 516 captured input files match the preceding +focused test and paired timing inputs byte for byte. + +[Corrected refresh evidence](experiments/source-alias-rename-refresh-20260912/source-rename-refresh-evidence-20260912.zip) +preserves those three complete captures, receipts, raw logs and independent App +and execution reviews. Its [independent archive review](experiments/source-alias-rename-refresh-20260912/independent-review.md) +verified all 37 members, three nested source snapshots, six command receipts +and original bindings. ZIP SHA-256: +`d46aacbba1dfccec64b195482e2857c97ceefecad6b0176c62c73c50964e18ba`. +This is a source-verification checkpoint, not a released or fully native-accepted +milestone. The corrected native trial is separate and must retain its actual +workflow coverage and limitations.