Compare commits

..
Author SHA1 Message Date
sorokin.oleg.edu 3d067041d1 Verify compact source editing in the native application 2026-09-13 06:24:05 -07:00
8 changed files with 368 additions and 64 deletions
+1
View File
@@ -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
@@ -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.
@@ -0,0 +1,14 @@
{
"evidence.zip": {
"bytes": 5251658,
"sha256": "0eb6f2a566deff1275b19b8c5718ebb56f9afde0518ac65c09d885a1d6e84d68"
},
"README.md": {
"bytes": 4964,
"sha256": "713c7ccddcffba87c38327ee39e4a82cdff42fe8adb9ce91d3affa26a01d75e4"
},
"verify.py": {
"bytes": 13770,
"sha256": "4ea03bbd274e731f4e3856a5965be29a93011c31dc26c62ae09784e7f7b75b27"
}
}
@@ -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.")
@@ -1,64 +0,0 @@
# Issue 28: iterative transitions and computed overview links
2026-09-13. This bounded assessment addresses C1 and C4 of the user's [research attachment](http://217.177.34.108:3000/attachments/3126660e-188e-4194-8a0d-42a4365e9da7). Implementation references below are to **94383107153cccb32f3fdcbd8111b6381f3e15aa**, not an uninspected future integration. It complements the [published C3/C5 assessment](http://217.177.34.108:3000/sorokin.oleg.edu/ARCADIA-Studio/src/commit/edd6a603edb3914a1dc58c8048ba9ebcdd27c017/harness/issue28-scenario-assessment-ytr83r.md). This is a source/specification assessment with explicit proposed experiments; no new build, native workflow, interchange or performance result is claimed.
## Primary-source check
The report's C1 description is supported by Capella's [pinned iterative transition guide](https://github.com/eclipse-capella/capella/blob/5537297b071fff809285bc63989f5067d675bc52/doc/plugins/org.polarsys.capella.transitions.doc/html/11.%20Iterative%20Transitions/11.1.%20Concepts.mediawiki). Trace links support repeated transformation and a candidate merge view. Its examples retain a target after source deletion, but can move a target or recreate a deleted target on rerun; rules may differ by transformation. Thus “conservative” is not a universal promise to leave every target edit untouched. Studio needs explicit policies and refusal/review behavior, not just that adjective.
For C4, Capella's [functional-analysis rationale](https://mbse-capella.org/arcadia_capella_sysml_tool.html) describes non-leaf functions as grouping constructs and displaying detailed dependencies at higher levels. This page compares historical SysML v1; it cannot establish a limitation of SysML v2. The official [computed-links description](https://mbse-capella.org/features.html) independently confirms that simplified diagrams derive higher-level links from lower-level exchanges. These sources support a modeling workflow benefit, not a measured productivity claim or a requirement to materialize additional flows.
## C1: iterative transition assessment
**Existing capability.** The [ordinary transition planner](../crates/oa-core/src/transitions.rs#L693) reuses a single traced counterpart, reports multiple-counterpart ambiguity, supports explicit existing/new-target choices, and reviews name/description changes against separate baselines. Its [public contract](../docs/v2-interface.md) deliberately preserves existing typed bodies. That does not imply structural review is absent: the newer [typed semantic interface](../docs/language.rst#L1488) includes Parent/Child facets, explicit correspondence, Keep/Take/candidate decisions, agreement checks and review of induced cleanup. Both apply paths reject stale plans and preserve planned generated IDs. Existing `workflows`, `review_regressions` and `r3_semantic` tests exercise these distinctions; `child_membership_and_parent_resolutions_agree_by_actual_child_slot` specifically checks compatible structural changes and rejects conflicting parent choices.
**Deletion needs precise language.** [Reference cleanup](../crates/oa-core/src/references.rs#L351) removes a trace when either endpoint is deleted; it does not traverse that trace to delete the other endpoint. `workflows::deleting_source_cascades_owned_records_but_keeps_other_layer_counterpart` checks retained counterpart existence and exact Undo. Thus source deletion preserves downstream existence but removes the pair's trace and review baseline. This differs from a deleted historical member ID retained inside a *surviving* trace, which the typed contract explicitly permits. The existing deletion test is not an exact comparison of a richly populated retained counterpart.
**Static retry consequence.** After target deletion, a fresh implicit plan can create another target because the original trace is gone. An explicit mapping to the deleted target conflicts, and an old plan is stale. After source deletion and recreation under a new UUID, an old retained target has no automatic correspondence to that new source. An implicit plan can create a second target; explicit mapping can relink the retained one. Name matching must not replace identity. Whether to retain deleted-endpoint provenance is an open lifecycle/UX decision, not evidence that the current engine deletes downstream design work.
**Next acceptance cases.** These are proposed evaluations, not newly executed results:
1. Create an isolated traced Activity/Function pair with target children, ports, relations, placement and artifact. Delete the source and compare the entire retained target subgraph, with source-owned removals and trace removal stated explicitly. Undo restores the complete original project/source. Repeat in the reverse direction.
2. In a separate branch of that fixture, delete the target and replan implicitly: create one new counterpart, then replan unchanged without duplicating it. Check old-plan rejection, an explicit mapping to the deleted target, exact save/reopen and API retry preconditions. An intentional explicit request for another new counterpart is a separate valid operation.
3. Delete and recreate the source under a new identity; compare implicit creation with explicit reuse of the retained target. Observe whether an engineer can understand trace loss, discover the retained target and relink it. Establish this workflow before selecting tombstones or any automatic matching rule.
4. Change upstream ownership and edit target content. Verify that prose review preserves structure, while explicit typed Parent/Child review presents the agreed change, respects Keep and refuses contradictory proposals. Reuse the existing structural oracles; a realistic GUI task must separately establish usability.
The inspected suites contain useful component tests but do not establish the whole endpoint-deletion→retransition workflow above. The report's later logical/physical levels remain future layers by the user's explicit release scope; OA↔SA conservation and understandable review are current requirements. C1 supports improving these lifecycle checks and explanations, not replacing a transition engine that already exists or blindly importing Capella's target-relocation rules.
## C4: existing preservation and the remaining overview boundary
**Existing contract.** [Language section 8](../docs/language.rst) distinguishes functional reparenting, performer allocation and moving a diagram placement. Reparenting must not silently change the performer. The allocation rule forbids treating a computed parent summary as another semantic allocation. Section 5 permits collapsed links to end at an ancestor without creating a new port or exchange. These distinctions already address an important part of C4; they should be preserved through later extensions.
**Existing implementation.** `projection.rs::parents` derives visual nesting from containment or allocation, while `ProjectedEdge.id` remains the original relation ID. `project_diagram_impl` promotes a placed but folded endpoint through its visible ancestor chain; `edges.push` retains that relation ID. The desktop diagram's selection-context path passes the same edge ID to object actions. A projected link therefore has an existing semantic identity to inspect. This is source evidence of that connection, not native proof that every crowded edge can be selected conveniently.
**Existing reusable tests.** `release_diagrams::port_identity_collapse_and_group_movement_do_not_invent_semantic_edges` checks collapsed endpoint promotion, absent invented ports and unchanged semantic relations. `unplaced_work_parent_cannot_detach_a_leaf_from_its_visible_performer` checks allocation summary placement. `language::nesting_tests::checked_in_example_supports_cross_file_reparent_without_changing_allocations` checks exact relation preservation, declaration/comment movement and untouched bundle files. All three are named PASS in the already published [full-core evidence](text-default-omission-followup-verified-20260913.md), whose relevant production code is unchanged here. They do not exercise the parent-only overview case below.
**Source-level limitation.** At `projection.rs:355`, endpoint anchoring begins with `placed.get(&owner)`. If the leaf owner has no placement, traversal never starts, even if its semantic ancestor is shown. This differs from hiding a placed leaf by collapsing its parent. A parent-only diagram therefore does not obtain descendant exchange links through this mechanism. `edge_availability` can report `EndpointNotShown`; it does not derive a replacement summary. This is a precise boundary in the inspected code, not a runtime observation or a claim that all computed links are absent.
The current `ProjectedEdge` represents one original relation, not a multi-relation summary. Several promoted exchanges can remain distinct. Lack of a contributor-set type alone does not prove a defect: a bundle is only needed if the chosen interaction combines those exchanges into one displayed object. The required invariant is that every displayed summary can identify all contributing original exchanges without introducing additional communication or control semantics.
## C4 acceptance experiment and candidate choice
Use stable semantic identities `G1`, `G2`, `G3`, leaf functions `A`, `B`, typed input/output ports `AI/AO` and `BI/BO`, and exchange `E` directed from AO to BI. Fix performers `P` (System) and `Q` (SystemActor), with allocation relations `PA=(P,A)` and `PB=(Q,B)`. Initially `A.parent=G1` and `B.parent=G2`; the grouping parents are not directly allocated. Create a functional-dataflow diagram containing placements only for G1/G2/G3. This small fixture isolates the behavior before scaling to the report's 200-function workflow.
1. In an explicitly selected computed-overview mode, the G1→G2 displayed link identifies E and its real ports. No placements for A/B and no additional semantic relations are required merely to obtain the overview.
2. Reparent A into G3. A, its ports, E, PA and PB keep their identities and meanings. The overview becomes G3→G2. Source/JSON/REST round trips preserve the complete model; Undo restores the original parent and view result together.
3. Using the initial hierarchy as a control, place A/B and collapse G1/G2. Existing folded-link behavior remains unchanged. In both ordinary and computed-overview modes, adding E to `hidden_edges` suppresses E; removing that explicit exclusion restores it. Its explanation differs from missing placements or internal folded connections.
4. Add E2 directed from BO to AI, plus new leaves C/D in G1 with typed ports connected by E3. The contributing directions are exactly A→B and B→A; after reparenting, their displayed directions are G3→G2 and G2→G3. Preserve them as separate direction groups or explicitly show both directions, never silently replace them with an undirected flow. If links are visually bundled, selecting the bundle exposes exactly its eligible contributors; E3 is represented as internal detail, not invented as an external flow. Selection filters and categories must not silently lose provenance. An ordinary detailed view may continue displaying separate edges.
5. Repeat the corresponding ownership/interaction case in OA. Observe the actual GUI and exported SVG, including selection, drill-down, undo/reopen and dense labels. Then use 200 leaf functions to assess editing burden and responsiveness. This document contains no execution result for these proposed cases.
| Candidate | Benefit and cost | Assessment |
| --- | --- | --- |
| Pre-place all leaves, then collapse | Reuses existing projection; requires view membership and placement work proportional to hidden detail | Retain as the existing workflow and control, not proof of parent-only overview support |
| Explicit semantic overview projection | Resolves original endpoints to selected visible ancestors without creating semantic exchanges; needs clear membership/filter/selection rules | Preferred experiment for reducing view maintenance while preserving the existing model |
| Materialize extra parent-to-parent exchanges | Easy to draw but adds relationships that can be counted, exported or maintained inconsistently | Reject as the default representation of computed links |
The preference is a scoped engineering proposal for the shared team, not an adopted schema change or ownership of the canvas implementation. Evaluate it with the fixture before adding a new persistent option, cache or abstraction. Preserve ordinary view behavior and coordinate any persisted option with graphical/textual/API parity.
**Open interaction decision:** existing “Hide from this diagram” removes a placement (`model_menu.rs`); the proposed mode deliberately includes exchanges of unplaced leaves. It must distinguish absent placement from an explicitly excluded semantic branch. Preserve ordinary Hide behavior and evaluate an understandable branch-exclusion workflow before selecting any new exclusion schema. Missing placement alone cannot encode both meanings. This is a prerequisite of the proposed experiment, not a reason to change all current diagrams implicitly.
## Decision boundary
C1/C4 should become concrete regression and workflow criteria. The identified C4 extension primarily concerns projection and interaction; these two cases do not establish that a complete metamodel replacement is necessary. They also cannot settle the report's other SysML v2 proposals. Definitions/usages, invariant bindings, quantities, constraints, libraries, temporal concepts and broader interchange require their own mappings and acceptance decisions. Old scope-document omissions cannot narrow the user's full OA/SA goal.
Live ownership and prioritization remain in Gitea issues 28, 3 and 27. This assessment neither closes those issues nor substitutes for #11's pending native checks. Linux remains user-paused.
@@ -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
@@ -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 <extracted>/native/saved-before/project.arcadia --json
arcadia check <extracted>/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.