diff --git a/.gitattributes b/.gitattributes index bb009874..20c9811f 100644 --- a/.gitattributes +++ b/.gitattributes @@ -105,3 +105,4 @@ harness/experiments/default-fidelity-20260913/**/*.log -whitespace harness/experiments/default-production-20260913/** -text whitespace=cr-at-eol harness/experiments/default-followup-20260913/** -text whitespace=cr-at-eol harness/experiments/default-consumers-20260913/** -text whitespace=cr-at-eol +harness/experiments/default-native-20260913/** -text whitespace=cr-at-eol diff --git a/harness/experiments/default-native-20260913/README.md b/harness/experiments/default-native-20260913/README.md new file mode 100644 index 00000000..3996fd7a --- /dev/null +++ b/harness/experiments/default-native-20260913/README.md @@ -0,0 +1,86 @@ +# Compact source native workflow evidence + +This package preserves two completed Windows native runs of the default-omission +followup, including the original screenshots, window/accessibility metadata, +process receipts, producers, input fixture, and both saved source bundles. +Run the read-only archive check from any checkout with Python 3: + +```text +python harness/experiments/default-native-20260913/verify.py +``` + +The verifier reads ZIP members in memory. It does not extract files, run the +archived programs, build code, or modify the checkout. `files.json` pins the other +three outer files; `capture-files.json` pins every original payload inside the ZIP. +These hashes establish internal consistency, not cryptographic attestation. + +## Source and executable provenance + +Both native runs record the same 115,056,640-byte `arcadia-studio.exe`, SHA-256 +`4070927256414a770c5fbcedfaab922810cea33d9f07610b81e9ab8c0465da44`. +Their build receipt and the original build stdout/stderr, producer, and complete +613-file executed-input snapshot are included under `build/`. These are copied +unchanged from the +[published consumer package](../default-consumers-20260913/README.md) at commit +`94383107153cccb32f3fdcbd8111b6381f3e15aa`. +The actual build recorded HEAD `df2e1cd65ca5e56f47669e04a9d4bcb426900fcd` +plus the HTTP test subsequently published in `9438310`; the captured source bytes, +rather than HEAD alone, identify the tested input. Production code is unchanged +from `7bb366f66a8c6f8b6f66fc9b04c9e3b39f84b78e`. +No executable is distributed in this evidence package. + +Both native process receipts close with exit code zero and empty stdout/stderr. +Trial 2 additionally pins its producer at launch and its immutable baseline ZIP. +Trial 1's runner and the screenshot helper are preserved as original local +producers but were not contemporaneously hashed by that trial's receipt. +Do not mistake a packaging-time hash for stronger historical provenance. +The helper initially selects `trial-1`; the interactive session changed its +output directory to `trial-2` for the continuation. Original producer bytes are +preserved, including their historical machine-specific paths. + +## Workflow and evidence boundaries + +Trial 1 opened the minimal source fixture, created one activity through Model +Explorer, inspected its compact source, and saved the resulting two-file bundle. +The important frames are `13-created-activity`, `17-compact-new-activity`, and +`27-cleanup-save-submitted`. Intermediate dialog focus and retry captures remain +in the archive; the trial was closed before the cleanup interruption. + +Trial 2 reopened that baseline and dragged Work. Its Text view showed x=190, +model Undo showed x=120, and model Redo showed x=190 again. It then used Save As, +cleared the current model, reopened the saved result, and inspected both source +files. Review these frames with their adjacent JSON metadata: + +- `03-baseline-loaded`, `04-drag-work`, `05-text-after-move`. +- `06-model-actions`, `07-undo-model`, `08-redo-menu`, `09-redo-model`. +- `17-save-complete`, `19-clear-current-model`, `22-reopened-root`, + `25-reopened-compact-activity`. + +Screenshot interpretation and the intermediate undo/redo observations require +human review. The archive verifier checks their inventory, metadata, timing and +byte hashes; it does not infer visible behavior from frame names or run OCR. +The machine-checkable before/after oracle independently requires exact bundle +membership and bytes: one compact new activity with stable UUID +`1e1da408-da79-42ab-a990-9d00b7dc2631`, one root include, and the sole subsequent +change `position { x 120.0; y 80.0; };` to +`position { x 190.0; y 80.0; };`. The explicit +`port_anchors [] ; // Keep explicit automatic placement.` survives exactly. + +`native/bundle-checks/` preserves both closed CLI checks and their original +`native/check-saved-bundles.py` producer. Both full bundles parsed and validated, +with four expected draft warnings (each activity is unallocated and lacks behavior +context), no errors, no IDs requiring stabilization, and no source changes. These +checks do not compare the entire parsed model. After explicit extraction to a +chosen directory, a rebuilt CLI can check `native/saved-before/project.arcadia` +and `native/saved-after/project.arcadia`; the verification script itself never +extracts or executes them. + +On reopen the diagram fits/recenters, so screen coordinates cannot prove the +persisted x value; the reopened Text frame supplies that observation. Save dialog +frames 14–16 retain a filename-selection automation quirk: text first appended, +then was visibly corrected before submission. No incorrect path was submitted. + +This is evidence for one ordinary source/graphical workflow on Windows. It is +not an exhaustive usability assessment, Linux result, performance experiment, +packaged application verification, or full release acceptance. See the linked +consumer and core evidence for broader automated coverage. diff --git a/harness/experiments/default-native-20260913/evidence.zip b/harness/experiments/default-native-20260913/evidence.zip new file mode 100644 index 00000000..cd8803e0 Binary files /dev/null and b/harness/experiments/default-native-20260913/evidence.zip differ diff --git a/harness/experiments/default-native-20260913/files.json b/harness/experiments/default-native-20260913/files.json new file mode 100644 index 00000000..d9e5ab3b --- /dev/null +++ b/harness/experiments/default-native-20260913/files.json @@ -0,0 +1,14 @@ +{ + "evidence.zip": { + "bytes": 5251658, + "sha256": "0eb6f2a566deff1275b19b8c5718ebb56f9afde0518ac65c09d885a1d6e84d68" + }, + "README.md": { + "bytes": 4964, + "sha256": "713c7ccddcffba87c38327ee39e4a82cdff42fe8adb9ce91d3affa26a01d75e4" + }, + "verify.py": { + "bytes": 13770, + "sha256": "4ea03bbd274e731f4e3856a5965be29a93011c31dc26c62ae09784e7f7b75b27" + } +} diff --git a/harness/experiments/default-native-20260913/verify.py b/harness/experiments/default-native-20260913/verify.py new file mode 100644 index 00000000..31df8217 --- /dev/null +++ b/harness/experiments/default-native-20260913/verify.py @@ -0,0 +1,172 @@ +"""Read-only verification of frozen native receipts and exact saved source bytes.""" +from pathlib import Path, PurePosixPath +from datetime import datetime +import hashlib +import io +import json +import zipfile + +ROOT = Path(__file__).resolve().parent +HEAD = "df2e1cd65ca5e56f47669e04a9d4bcb426900fcd" +GUI = {"bytes": 115056640, "sha256": "4070927256414a770c5fbcedfaab922810cea33d9f07610b81e9ab8c0465da44"} +CLI = {"bytes": 20608512, "sha256": "d89aba9f10b598926dfdc5c644474ae891b753e8583a184860e941a359ed0eea"} +BUILD = {"bytes": 5538, "sha256": "25c7878f56395ed1e8e6b3532fd9135e0b313fd2b781a4c982f9f2b01a4ec64b"} +INPUTS = {"bytes": 102567, "sha256": "6bf74c1f68431a034681b754617c39d387783f71354c9106649aec9480e4f29f"} +SOURCES = {"bytes": 2483742, "sha256": "e20f33dc363850a9289103a7be28ad613c3fffb2039061957a0186cac72d541b"} +ACTIVITY_PATH = "oa/activities/activity_new_activity.arcadia" +ACTIVITY = b'\noa_activity new_activity "New activity" id "1e1da408-da79-42ab-a990-9d00b7dc2631" {\n}\n\n\n' +FIXTURE = b'''arcadia 7; +project p "Compact source workflow" id "00000000-0000-4000-8000-000000000001" { + oa_activity work "Work" id "00000000-0000-4000-8000-000000000002" {} + diagram view "Overview" id "00000000-0000-4000-8000-000000000003" {} + node placement id "00000000-0000-4000-8000-000000000004" { + diagram @view; element @work; + position { x 120.0; y 80.0; }; + port_anchors [] ; // Keep explicit automatic placement. + } +} +''' +LABELS = { + "trial-1": "01-home 02-open-dialog 03-open-file-field 05-open-after-uia-error 06-open-focused 07-open-path-typed 08-project-opened 09-project-settled 10-open-keyboard-ready 11-open-submitted 12-model-explorer 13-created-activity 14-generated-source 15-source-folder 16-activity-source-row 17-compact-new-activity 18-save-before-request 19-save-before-dialog 20-cleanup-save-dialog 21-cleanup-filename-focus 22-cleanup-filename-caret 23-cleanup-save-path 24-cleanup-save-path-settled 25-cleanup-filename-refocus 26-cleanup-save-path-retry 27-cleanup-save-submitted".split(), + "trial-2": "01-home 02-open-baseline 03-baseline-loaded 04-drag-work 05-text-after-move 06-model-actions 07-undo-model 08-redo-menu 09-redo-model 10-save-as-request 11-save-dialog 12-save-filename-focus 13-select-filename 14-enter-save-path 15-correct-path-selection 16-save-path-corrected 17-save-complete 18-home-reopen 19-clear-current-model 20-empty-home 21-reopen-request 22-reopened-root 23-open-source-folder 24-activity-source-list 25-reopened-compact-activity".split(), +} + + +def require(condition, message): + if not condition: + raise SystemExit(message) + + +def digest(data): + return {"bytes": len(data), "sha256": hashlib.sha256(data).hexdigest()} + + +def membership(archive, expected, label): + names = archive.namelist() + require(len(names) == len(set(names)) and set(names) == set(expected), label + ": ZIP membership mismatch") + require(all(not PurePosixPath(n).is_absolute() and ".." not in PurePosixPath(n).parts and "\\" not in n and ":" not in n for n in names), label + ": unsafe ZIP member") + + +def time(value): + parsed = datetime.fromisoformat(value.replace("Z", "+00:00")) + require(parsed.tzinfo is not None, "Timestamp missing timezone") + return parsed + + +outer = json.loads((ROOT / "files.json").read_text(encoding="utf-8")) +require(set(outer) == {"README.md", "verify.py", "evidence.zip"}, "Outer manifest membership mismatch") +require({p.name for p in ROOT.iterdir()} == set(outer) | {"files.json"}, "Outer directory membership mismatch") +for name, pin in outer.items(): + require(digest((ROOT / name).read_bytes()) == pin, "Outer hash mismatch: " + name) + +with zipfile.ZipFile(ROOT / "evidence.zip") as z: + def read(name): + return z.read(name) + + def obj(name): + return json.loads(read(name)) + + pins = obj("capture-files.json") + membership(z, set(pins) | {"capture-files.json"}, "Evidence") + for name, pin in pins.items(): + require(digest(read(name)) == pin, "Payload hash mismatch: " + name) + + build = obj("build/result.json") + require(digest(read("build/result.json")) == BUILD, "Original build receipt mismatch") + require(build["head"] == HEAD and build["exitCode"] == 0 and build["inputsUnchanged"] is True, "Build closure mismatch") + require(build["inputs"] == INPUTS and build["archive"] == SOURCES, "Build source identity mismatch") + require(all(build.get(k) == v for k, v in obj("build/started.json").items()), "Build start/result mismatch") + require(time(build["start"]) <= time(build["finish"]), "Build chronology mismatch") + require(build["command"] == ["cargo", "build", "--locked", "--offline", "--workspace", "--bins", "--message-format=json"], "Build command mismatch") + for key, name in [("inputs", "inputs.json"), ("archive", "inputs.zip"), ("helper", "gate-policy.py"), ("stdout", "stdout.log"), ("stderr", "stderr.log")]: + require(digest(read("build/" + name)) == build[key], "Build payload mismatch: " + name) + source_pins = obj("build/inputs.json") + require(len(source_pins) == build["inputCount"] == 613, "Source count mismatch") + with zipfile.ZipFile(io.BytesIO(read("build/inputs.zip"))) as sources: + membership(sources, source_pins, "Source") + for name, pin in source_pins.items(): + require(digest(sources.read(name)) == pin, "Source blob mismatch: " + name) + build_events = [json.loads(line) for line in read("build/stdout.log").decode().splitlines() if line.startswith("{")] + require([e.get("success") for e in build_events if e.get("reason") == "build-finished"] == [True], "Build success event mismatch") + require([e for e in build_events if e.get("reason") == "compiler-artifact" and e.get("executable")] == [a["cargo"] for a in build["artifacts"]], "Build artifact log mismatch") + binaries = {a["cargo"]["target"]["name"]: a for a in build["artifacts"]} + require(binaries["arcadia-studio"]["readback"] == GUI and binaries["arcadia"]["readback"] == CLI, "Native binary build identity mismatch") + + expected = {"build/" + n for n in ["result.json", "started.json", "stdout.log", "stderr.log", "inputs.json", "inputs.zip", "gate-policy.py"]} + expected |= {"native/" + n for n in ["run-native.py", "run-native-followup.py", "capture-snippet.js", "check-fixture.py", "verify-creation-checkpoint.py", "fixture-check.result.json", "fixture-check.stdout.json", "fixture-check.stderr.log", "input/project.arcadia"]} + before = FIXTURE[:-2] + b'\n include "oa/activities/activity_new_activity.arcadia";\n}\n' + after = before.replace(b"position { x 120.0; y 80.0; };", b"position { x 190.0; y 80.0; };") + require(read("native/input/project.arcadia") == FIXTURE, "Input fixture bytes mismatch") + for label, root in [("saved-before", before), ("saved-after", after)]: + expected |= {f"native/{label}/project.arcadia", f"native/{label}/{ACTIVITY_PATH}"} + require(read(f"native/{label}/project.arcadia") == root and read(f"native/{label}/{ACTIVITY_PATH}") == ACTIVITY, label + ": exact source construction mismatch") + + previous_finish = time(build["finish"]) + for trial, labels in LABELS.items(): + prefix = "native/" + trial + "/" + expected |= {prefix + n for n in ["started.json", "result.json", "process.json", "stdout.log", "stderr.log"]} + result, started, process = (obj(prefix + n + ".json") for n in ["result", "started", "process"]) + require(all(result.get(k) == v for k, v in started.items()), trial + ": start/result mismatch") + require(result["exitCode"] == 0 and result["binary"] == result["binaryAfter"] == GUI, trial + ": process/binary closure mismatch") + require(result["buildReceipt"] == BUILD and result["buildHead"] == HEAD and result["buildInputs"] == INPUTS, trial + ": build provenance mismatch") + require(result["command"] == [binaries["arcadia-studio"]["cargo"]["executable"]], trial + ": launch command mismatch") + require(previous_finish <= time(result["start"]) <= time(process["observed"]) <= time(result["finish"]), trial + ": chronology mismatch") + require(isinstance(process["pid"], int) and process["pid"] > 0, trial + ": PID mismatch") + for stream in ["stdout", "stderr"]: + require(result[stream] == digest(read(prefix + stream + ".log")) == digest(b""), trial + ": unexpected process output") + previous_capture = time(result["start"]) + for label in labels: + expected.add(prefix + label + ".json") + frame = obj(prefix + label + ".json") + require(previous_capture <= time(frame["time"]) <= time(result["finish"]), trial + ": capture chronology mismatch") + previous_capture = time(frame["time"]) + require(frame["window"]["id"] and (isinstance(frame["accessibility"], dict) or (trial, label, frame["accessibility"]) == ("trial-1", "08-project-opened", None)), trial + ": capture metadata mismatch") + require(len(frame["images"]) in [1, 2], trial + ": image inventory mismatch") + for i, image in enumerate(frame["images"]): + name = f"{label}-{i}.jpg" + require(image["file"] == name and image["width"] > 0 and image["height"] > 0, trial + ": image metadata mismatch") + require(read(prefix + name).startswith(b"\xff\xd8"), trial + ": JPEG bytes mismatch") + expected.add(prefix + name) + previous_finish = time(result["finish"]) + if trial == "trial-2": + expected.add(prefix + "baseline.zip") + require(result["helper"] == digest(read("native/run-native-followup.py")), "Trial 2 producer pin mismatch") + require(result["baselineUnchanged"] is True and result["baselineArchive"] == digest(read(prefix + "baseline.zip")), "Baseline receipt mismatch") + require(result["baseline"] == {"project.arcadia": digest(before), ACTIVITY_PATH: digest(ACTIVITY)}, "Baseline source pins mismatch") + with zipfile.ZipFile(io.BytesIO(read(prefix + "baseline.zip"))) as baseline: + membership(baseline, result["baseline"], "Baseline") + require(baseline.read("project.arcadia") == before and baseline.read(ACTIVITY_PATH) == ACTIVITY, "Launch baseline bytes mismatch") + + fixture = obj("native/fixture-check.result.json") + require(fixture["exitCode"] == 0 and fixture["binary"] == CLI, "Fixture CLI receipt mismatch") + require(fixture["fixtureBefore"] == fixture["fixtureAfter"] == digest(FIXTURE), "Fixture CLI source mismatch") + for key, suffix in [("stdout", "stdout.json"), ("stderr", "stderr.log")]: + require(fixture[key] == digest(read("native/fixture-check." + suffix)), "Fixture CLI stream mismatch") + require(read("native/fixture-check.stderr.log") == b"", "Fixture CLI stderr was not empty") + expected.add("native/check-saved-bundles.py") + expected.add("native/bundle-checks/summary.json") + producer = digest(read("native/check-saved-bundles.py")) + require(producer == {"bytes": 4238, "sha256": "b1116c3c5227fad2d99d0d4ab421e0840a09120b1aedfa1fd4364b25787450cc"}, "Saved-bundle producer pin mismatch") + summary = obj("native/bundle-checks/summary.json") + require(summary["status"] == "PASS" and summary["runs"] == ["saved-before", "saved-after"] and summary["producer"] == producer, "Bundle summary mismatch") + diagnostics = [{"severity": "warning", "code": code, "object_id": identity} + for code in ["unallocated_leaf", "work_without_behavior_context"] + for identity in ["00000000-0000-4000-8000-000000000002", "1e1da408-da79-42ab-a990-9d00b7dc2631"]] + for label, source in [("saved-before", before), ("saved-after", after)]: + prefix = "native/bundle-checks/" + label + expected |= {prefix + suffix for suffix in [".result.json", ".stdout.json", ".stderr.log"]} + result, report = obj(prefix + ".result.json"), obj(prefix + ".stdout.json") + entry = "C:\\ar-default-9e8r6t\\.local\\default-omission-native\\" + label + "\\project.arcadia" + require(result["command"] == [binaries["arcadia"]["cargo"]["executable"], "check", entry, "--json"], label + ": CLI command mismatch") + require(result["exitCode"] == 0 and result["binary"] == CLI and result["buildReceipt"] == BUILD and result["producer"] == producer, label + ": CLI provenance mismatch") + require(result["filesUnchanged"] is True and result["files"] == {"project.arcadia": digest(source), ACTIVITY_PATH: digest(ACTIVITY)}, label + ": CLI input mismatch") + require(previous_finish <= time(result["start"]) <= time(result["finish"]), label + ": CLI chronology mismatch") + previous_finish = time(result["finish"]) + require(result["stdout"] == digest(read(prefix + ".stdout.json")) and result["stderr"] == digest(read(prefix + ".stderr.log")) == digest(b""), label + ": CLI streams mismatch") + require(report["entry"] == entry and report["operation"] == "check" and report["status"] == "checked" and report["exit_code"] == 0, label + ": CLI status mismatch") + require(report["written"] is False and report["changes"] == [] and report["identities_to_stabilize"] == 0, label + ": CLI changed source or identities") + require(result["diagnostics"] == [{k: d[k] for k in ["severity", "code", "object_id"]} for d in report["diagnostics"]] == diagnostics, label + ": expected draft diagnostics mismatch") + require(set(pins) == expected, "Exact payload inventory mismatch") + +print("Verified closed native trials, unchanged verified GUI, original captures, 613 build inputs, and exact saved-bundle bytes.") +print("Intermediate GUI behavior requires screenshot review; no Linux, performance, packaging, or full-release acceptance claim.") diff --git a/harness/text-default-omission-consumers-20260913.md b/harness/text-default-omission-consumers-20260913.md index acedfc43..e901d026 100644 --- a/harness/text-default-omission-consumers-20260913.md +++ b/harness/text-default-omission-consumers-20260913.md @@ -1,5 +1,8 @@ # Ordinary default omission: public consumer verification +Follow-up: the [completed native workflow evidence](text-default-omission-native-20260913.md) +supersedes the native-workflow gap recorded at this earlier checkpoint. + The ordinary source changes at `7bb366f66a8c6f8b6f66fc9b04c9e3b39f84b78e` now pass the CLI, HTTP and desktop automated consumer gates, strict workspace Clippy, and a matching Windows build. A new HTTP regression test verifies the distinction between preserving authored source and producing compact canonical export. Native workflow acceptance and integration remain incomplete. ## Executed candidate and results diff --git a/harness/text-default-omission-native-20260913.md b/harness/text-default-omission-native-20260913.md new file mode 100644 index 00000000..594c6d88 --- /dev/null +++ b/harness/text-default-omission-native-20260913.md @@ -0,0 +1,92 @@ +# Ordinary default omission: native editing verification + +The matching Windows application completed graphical creation, drag, model Undo/Redo, +Save As and reopening for a compact two-file source project. The saved files match the +explicit byte oracle: creation adds one include and one compact activity declaration; +moving the existing activity changes only its x coordinate from `120.0` to `190.0`. +The authored `port_anchors [] ;` field, spacing and rationale comment survive unchanged. + +This is branch-specific ordinary-source acceptance evidence. Integration with source8 +and the complete OA/SA release remain separate work in Gitea issues 7, 11 and 27. + +## Candidate and observable checks + +Production code is `7bb366f66a8c6f8b6f66fc9b04c9e3b39f84b78e`. The GUI and CLI were built +by the [published consumer gate](text-default-omission-consumers-20260913.md), whose 613 +captured inputs are published at `94383107153cccb32f3fdcbd8111b6381f3e15aa`. The build +captured HEAD `df2e1cd` plus the subsequently published HTTP witness, not HEAD alone. +No production edits or new build occurred during the native trials. + +| Observation | Evidence and result | +| --- | --- | +| Trial 1, 12:13:57–12:28:17 UTC | Opened compact source, created an activity through Model Explorer, inspected its compact declaration, saved the two-file baseline, closed normally. | +| Trial 2, 13:10:06–13:15:23 UTC | Opened that baseline, dragged Work, observed x `190.0`, chose **Undo model change** and observed x `120.0` plus saved state, then **Redo model change** and observed x `190.0` plus unsaved state. | +| Save As and reopen | Saved to a separate folder, selected New to clear the current model, then opened the saved result from Recent models. Source again showed x `190.0`, the original explicit empty field/comment, and the compact included activity. | +| Exact saved-source comparison | Both bundles contain exactly the expected two files. The included activity is byte-identical before/after; the root changes only the expected position token. Original baseline remains unchanged. | +| CLI checks on both saved bundles | Both exit 0 with empty stderr, no proposed changes and no identities awaiting stabilization. Each reports four expected draft warnings. | +| GUI closure | Both trials exit 0, preserve the verified executable hash, and have empty stdout/stderr. | + +The four draft warnings are `unallocated_leaf` and `work_without_behavior_context` +for Work and New activity. These are expected for this deliberately minimal fixture; +there are no parse or model errors. The created activity retains UUID +`1e1da408-da79-42ab-a990-9d00b7dc2631` through both saves and reopening. + +The GUI SHA-256 is `4070927256414a770c5fbcedfaab922810cea33d9f07610b81e9ab8c0465da44` +(115,056,640 bytes). The CLI SHA-256 is +`d89aba9f10b598926dfdc5c644474ae891b753e8583a184860e941a359ed0eea` (20,608,512 bytes). +The baseline root SHA-256 is `dad153f45038ed9ae79ea7263364e6cdedc40737fe7f63fdad7fb198ee7f65c8`; +the edited root is `c93bd35eaaf3a19bc07b5c6a4ee5839ab565e9fd90a2605261b7618fc8a7ecef`. +The unchanged included file is `42efe80410d56ae9dd919bad6b0633129028339b8271f500f35d9148a058f50a`. + +## Interpretation and limits + +Native Undo/Redo is an observed UI check. The byte oracle checks persisted bundles; +it does not expose or compare the complete in-memory model at the intermediate Undo +step. CLI checks parse and validate both full bundles, without comparing their complete +decoded models. The separately published HTTP and automated desktop tests cover their +documented model equality and exact Undo invariants; those results should not be described +as additional native observations. + +The diagram recenters on reopening, so comparing screen coordinates across the reopen +would be misleading. Persisted x is verified in Text and the saved-byte oracle. +Save-dialog accessibility reported Search Box while the filename field visibly held +focus. In trial 2 an initial selection attempt did not take effect and typing appended +to the filename. Observation caught this before saving; a confirmed selection and +replacement produced the intended full path. Original captures retain the correction. +This is an automation focus limitation, not evidence of source corruption. + +Trial 2 pins its runner and baseline archive contemporaneously. Trial 1's original +runner and the capture snippet are retained, but the trial 1 receipt does not hash those +producer files. Do not infer stronger contemporaneous provenance from later archive pins. +These short trials do not establish performance, accessibility completeness, large-model +usability, cross-platform acceptance or complete release readiness. Linux remains paused +by the user. + +## Reproduction and portable evidence + +The [portable package](experiments/default-native-20260913/README.md) contains the actual +inputs, saved bundles, original captures and process/CLI receipts. Its read-only verifier +checks archive integrity and the scoped machine oracles; screenshots still require human +inspection against the workflow above. + +Independent review inspected the 14 key original frames covering creation, movement, +Undo/Redo, Save As correction, clearing the model and reopening both source files. +It independently checked the saved-byte oracle and process/CLI receipts, ran the portable +verifier, and compared all 160 archived original payloads against the raw local evidence. +No actionable finding remained. Parent also ran the verifier. The ZIP SHA-256 is +`0eb6f2a566deff1275b19b8c5718ebb56f9afde0518ac65c09d885a1d6e84d68` (5,251,658 bytes). + +```text +python harness/experiments/default-native-20260913/verify.py +arcadia check /native/saved-before/project.arcadia --json +arcadia check /native/saved-after/project.arcadia --json +``` + +To repeat the native task, build the identified candidate using the documented Windows +GNU LLVM environment, open the archived input, create an activity through Model Explorer, +inspect its generated file, save a baseline, drag Work, use model Undo/Redo in Text Actions, +save to a separate folder, create a new blank model and reopen the saved result. A new +activity receives a new UUID; check that it remains stable within the new trial rather +than expecting this run's literal UUID. + +No issue closure, integration, tag or release is claimed by this report.