Verify compact Process removal workflow and record failure boundary

This commit is contained in:
2026-09-24 21:10:39 -07:00
parent 7323a80e94
commit afcea12cd9
10 changed files with 2690 additions and 4 deletions
+5 -2
View File
@@ -112,8 +112,11 @@ and explicit coverage limits; default-branch integration remains separate.
The [Process removal policy](process-group-removal-policy-20260925.md) defines
local occurrence/link admission, cascade normalization, implicit-order and
caller consequences, and captured one-step removal. It is a development policy;
its existence does not establish App, native or integration acceptance.
caller consequences, and captured one-step removal. Its
[Windows App/native evidence](process-group-removal-app-20260925.md) and
[compact review follow-up](process-removal-compact-20260925.md) identify the
tested source and bounded acceptance. Default-branch integration remains open;
the policy alone does not establish implementation or runtime acceptance.
## Acceptance and dependencies
@@ -1,6 +1,6 @@
# Process aggregate removal — App implementation and verification, 2026-09-25 UTC
Local-only contribution for issue 29. Source `572e96ba03522cfb822b13fe4abb50e857a5de48` builds and runs on Windows. Process/FunctionalChain aggregate removal has source review, filtered regression checks and a native OA model/source/history/reopen receipt. Compact-window acceptance remains open. No integration, release or remote publication is claimed.
Local-only contribution for issue 29. Source `572e96ba03522cfb822b13fe4abb50e857a5de48` builds and runs on Windows. Process/FunctionalChain aggregate removal has source review, filtered regression checks and a native OA model/source/history/reopen receipt. The [compact follow-up](process-removal-compact-20260925.md) additionally verifies the bounded removal review at 1102x732. No integration, release or remote publication is claimed.
## Behavior and reviewed corrections
@@ -86,6 +86,6 @@ python -B harness/process-group-removal-evidence-20260925/native/verify.py harne
## Remaining scope and publication
This native receipt covers OA derived layout and the bounded fixture. SA/qualified paths, cascades, stale input races and command-failure preservation have separate filtered-test evidence. Actual Process source-budget failure, native Shift-click, compact layout, comprehensive accessibility, full-suite and Linux acceptance are unclaimed. Preserve these limits when integrating; no issue closure is justified by this branch alone.
This original native receipt covers OA derived layout and the bounded fixture. SA/qualified paths, cascades, stale input races and command-failure preservation have separate filtered-test evidence. The [follow-up](process-removal-compact-20260925.md) closes the compact review gap for this fixture. Actual Process source-budget failure, native Shift-click, comprehensive accessibility, full-suite and Linux acceptance remain unclaimed. Static investigation found no valid source-growth case for the admitted Process removal; see the [evaluator boundary](process-group-removal-evidence-20260925/source-failure-investigation.md). This is not a formal monotonicity proof or actual Process source-write-failure coverage. Preserve these limits when integrating; no issue closure is justified by this branch alone.
Fresh guarded push was rejected with `remote unpack failed: unable to create temporary object directory`; a Gitea MCP issue-comment write also failed. Read operations work, main AGENTS remains blob e76647f49913b314e1543c4464f6199533909bae, and the remote contribution branch remains 43340b94. WSL DNS still timed out after ten seconds; Linux builds remain explicitly user-paused. These are observed failed attempts, not a newly verified disk-full root cause. Pending Scenario follow-up and this Process contribution remain local-only. Reconcile and publish the buffered issue-29 handoff when writes recover; do not overwrite remote history. Historical local paths inside copied reviews identify their original context, not peer-accessible deliverables.
@@ -0,0 +1,44 @@
# Compact Process native follow-up, 2026-09-25 UTC
Run 3 uses the unchanged Windows Studio executable built from source
572e96ba03522cfb822b13fe4abb50e857a5de48. PID 6252; normal Alt+F4 close,
exit 0, empty logs and unchanged immutable inputs. Parent Computer Use actions
below are observations, not an instrumented input log.
- Captures 01–16: prepare a fully visible 1102x732 window. Initial window was
partly off-screen. Title-bar movement and edge dragging were unreliable;
one edge attempt scrolled the Home view. Native System menu > Size, Right,
pointer placement at x1100 set width; Size, Down, placement at y730 set height.
Failed eval-based helper loading was rejected before execution; capture
function was then defined directly. These are automation/setup limitations.
- 17–26: native Open picker for this run's working.arcadia. UIA set_value failed
(property absent from CacheRequest), then fresh observation, file-name click
and literal typing entered the path. UIA Open click did not close the picker;
reobservation plus Return loaded the correct model. The accessibility focus
field said Search Box while the visible caret/text were in File name. No
model data was typed into another editor or external destination.
- 27–34: select Assessment, Behavior, Fit (59%), then select Action @a and use
context Add on Control @c and SequenceLink @approved. Count 3, link primary.
Native Shift-click is not claimed. Canvas palette uses narrow abbreviations;
full canvas/palette accessibility and compact authoring are outside this test.
- 35: header review at 1102x732, title, 3 removed/1 updated, 10 effects, search,
paging, fixed Cancel and explicit Remove all visible.
- 36: scroll page 1 to the explicit-before / implicit-after order rows; footer
remains visible. 37: page 2 displays @e1 then @e2 and full direct @caller and
transitive @outer names/aliases, without clipping the confirmation controls.
- 38–40: search @outer finds one caller; append -missing gives zero results
with recovery guidance. The review remains open and footer stays reachable.
- 41–42: Cancel preserves count 3 and @approved primary; Save all, exact
compact-cancelled snapshot equals all 2609 baseline bytes.
- 43–45: fresh header review resets search; explicit Remove succeeds, group
clears, owner selected, two exchange cards connected implicitly. Save all;
compact-removed snapshot equals all 2258 independent v2 oracle bytes.
- 46–47: one Ctrl+Z restores all four cards/authored link. Save all;
compact-undo snapshot equals all 2609 baseline bytes. Then Alt+F4; supervisor
confirms normal closure. No additional Redo/reopen claim from this run;
original runs 1–2 retain that evidence separately.
Scope: OA derived Process and this fixture's compact removal review. This is
not SA native acceptance, full keyboard-only navigation, native Shift-click,
comprehensive accessibility, a full-suite rerun or a release. No production
source changed and no Linux build/check ran.
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,300 @@
"""Offline archive/source/receipt checks. Never executes archived helpers or native binaries."""
from pathlib import Path, PurePosixPath, PureWindowsPath
import argparse
import datetime
import hashlib
import json
import re
import zipfile
KIND = 'process-aggregate-removal-native-evidence'
PHASES = {'baseline': 'baseline.arcadia', 'removed': 'expected-removed.arcadia'}
V2 = 'process-removal-v2-preserved-trivia'
def pin(data):
return {'bytes': len(data), 'sha256': hashlib.sha256(data).hexdigest()}
def safe_name(name):
p = PurePosixPath(name)
assert name and not p.is_absolute() and str(p) == name, 'Unsafe member: ' + name
assert '\\' not in name and ':' not in name and not any(x in ('.', '..', '') for x in name.split('/')), 'Unsafe member: ' + name
def check_oracles(files, fixture, prefix='fixtures/'):
revision = fixture['fixture_revision']
assert revision in ('process-removal-v1-literal', V2)
assert fixture['selection'] == fixture['removed'] == ['a', 'c', 'approved']
assert fixture['changed'] == ['assessment']
assert fixture['caller_definitions'] == ['caller', 'outer']
assert fixture['remaining_implicit_order'] == ['e1', 'e2']
assert set(fixture['files']) == set(PHASES.values()), 'Wrong fixture inventory'
for name, expected in fixture['files'].items():
assert pin(files[prefix + name]) == expected, 'Fixture pin mismatch: ' + name
baseline = files[prefix + 'baseline.arcadia']
assert pin(baseline) == {'bytes': 2609, 'sha256': '9965f4024584d64ac81442724aeb77b018b0cfae94e50bd412c5dcbbac49f6bf'}
actual = files[prefix + 'expected-removed.arcadia']
if revision != V2:
# Preserve the original incorrect oracle as history, never acceptance.
assert pin(actual) == {'bytes': 2186, 'sha256': '117b550f0c10753f53febb3ca6beb2c8088688ffa707f21eac654573e4a3d29c'}
return
text = baseline.decode('utf-8')
assert '\r' not in text
pattern = r'(?m)^ (?:oa_occurrence (?:a|c) |sequence_link approved )[^\n]*'
# Independent fixture-specific lexical rules; never execute archived code.
def trivia(line):
return re.sub(r'\S', '', re.sub(r'"(?:\\.|[^"\\])*"', '', line))
rows = re.findall(pattern, text)
assert [trivia(row) for row in rows] == [' ' * 22, ' ' * 20, ' ' * 16]
expected = re.sub(pattern, lambda m: '\n\n' + trivia(m.group()) + '\n\n', text)
assert expected.count('steps [@a,@e1,@c,@e2]') == 1
expected = expected.replace('steps [@a,@e1,@c,@e2]', 'steps [@e1,@e2]')
assert actual == expected.encode('utf-8'), 'V2 differs from independently specified delta'
assert pin(actual) == {'bytes': 2258, 'sha256': 'b4a2b07ad4c796f555c61945ca42b1c221b454b35488c60fefc86f96f7aa71ba'}
def check_source(files, actual, phase, prefix='fixtures/'):
assert phase in PHASES, 'Unknown source phase'
assert actual == files[prefix + PHASES[phase]], 'Exact full source differs from ' + phase
def verify(root):
manifest = json.loads((root / 'manifest.json').read_text(encoding='utf-8'))
assert manifest['kind'] == KIND, 'Wrong package kind'
assert pin((root / 'native-evidence.zip').read_bytes()) == manifest['archive'], 'Archive pin mismatch'
with zipfile.ZipFile(root / 'native-evidence.zip') as archive:
names = archive.namelist()
assert len(names) == len(set(names)) and set(names) == set(manifest['members']), 'Archive member inventory mismatch'
for name in names:
safe_name(name)
assert ((archive.getinfo(name).external_attr >> 16) & 0o170000) != 0o120000, 'Symlink member'
files = {name: archive.read(name) for name in names}
for name, data in files.items():
assert pin(data) == manifest['members'][name], 'Member pin mismatch: ' + name
assert PurePosixPath(name).suffix.lower() not in ('.exe', '.dll'), 'Unexpected archived binary'
for name in manifest['excluded_binary_bytes']:
safe_name(name)
assert name not in files and PurePosixPath(name).suffix.lower() in ('.exe', '.dll'), 'Invalid omitted binary entry'
assert (root / 'verify.py').read_bytes() == files['helpers/native-evidence-verify.py'], 'External verifier differs from pinned helper'
def js(name):
return json.loads(files[name].decode('utf-8-sig'))
def present_pin(name):
return pin(files[name]) if name in files else manifest['excluded_binary_bytes'].get(name)
def build_binding(prefix, source):
receipt = js(prefix + 'result.json')
proof = js(prefix + 'source-proof.json')
inputs = js(prefix + 'inputs.json')
assert receipt['exitCode'] == 0 and receipt['inputsUnchanged'] is True, 'Build not successful/unchanged'
assert proof['status'].startswith('PASS') and proof['result'] == pin(files[prefix + 'result.json']), 'Build proof result binding'
assert proof['inputMap'] == receipt['inputs'] == pin(files[prefix + 'inputs.json']), 'Build input-map binding'
assert proof['inputCount'] == receipt['inputCount'] == len(inputs), 'Build input count'
assert proof['commit'] == receipt['head'] == source and re.fullmatch('[0-9a-f]{40}', source), 'Build source identity'
return receipt
fixture = js('fixtures/fixture-manifest.json')
check_oracles(files, fixture)
for name in files:
if name.startswith('oracle-revisions/') and name.endswith('/fixture-manifest.json'):
check_oracles(files, js(name), name.removesuffix('fixture-manifest.json'))
derivation = 'oracle-revisions/oracle-v2/derive-source-oracle-v2.ps1'
assert pin(files[derivation]) == js('oracle-revisions/oracle-v2/fixture-manifest.json')['derivation']
config = js('review-config.json')
final_source = config['final_source']
assert re.fullmatch('[0-9a-f]{40}', final_source)
assert config['runs'] == manifest['runs'] and config['preflights'] == manifest['preflights']
for entries, prefix, pattern in [(config['runs'], 'runs', r'run-[0-9]+'), (config['preflights'], 'preflight', r'fixture-preflight-[0-9]+')]:
assert entries and len({x['name'] for x in entries}) == len(entries)
assert all(re.fullmatch(pattern, x['name']) and type(x['accepted']) is bool for x in entries)
assert {name.split('/')[1] for name in files if name.startswith(prefix + '/')} == {x['name'] for x in entries}, 'Undeclared archived attempts'
gates = config['gates']
assert len(gates) == len(set(gates)) and {'process-removal-tests-1', 'process-removal-tests-2'} <= set(gates)
assert all(re.fullmatch(r'process-removal-(?:tests|format|clippy|build)-[0-9]+', g) for g in gates)
assert {n.split('/')[1] for n in files if n.startswith('gates/')} == set(gates)
gate_reports = []
for gate in gates:
prefix = 'gates/' + gate + '/'
result, proof, inputs = (js(prefix + f) for f in ('result.json', 'source-proof.json', 'inputs.json'))
assert result['inputsUnchanged'] is True and 'finish' in result
assert proof['status'].startswith('PASS') and proof['result'] == pin(files[prefix + 'result.json'])
assert proof['inputMap'] == result['inputs'] == pin(files[prefix + 'inputs.json'])
assert proof['inputCount'] == result['inputCount'] == len(inputs)
assert proof['commit'] == result['head'] and re.fullmatch('[0-9a-f]{40}', result['head'])
for stream in ('stdout', 'stderr'):
assert result[stream] == pin(files[prefix + stream + '.log'])
gate_reports.append({'gate': gate, 'source': result['head'], 'exitCode': result['exitCode']})
# The original failed gates must remain failed historical facts.
for gate, source in [('process-removal-tests-1', 'fe637dcd277b17653139ffa234e601b29775c565'),
('process-removal-tests-2', 'f20497b29bf637619bc35ffe41274fc0f66c387b')]:
receipt = js('gates/' + gate + '/result.json')
assert receipt['head'] == source and receipt['exitCode'] == 101
reports, preflights = [], []
accepted_cli_bindings = set()
for entry in config['preflights']:
prefix = 'preflight/' + entry['name'] + '/'
problems = []
try:
current = js(prefix + 'result.json')
started = js(prefix + 'started.json')
fixture_name = prefix + 'evidence/fixture-manifest.json'
current_fixture = js(fixture_name)
check_oracles(files, current_fixture, prefix + 'fixtures/')
revision = current_fixture.get('fixture_revision', 'removal-v1-source-derived')
if 'fixture_revision' in current:
assert current['fixture_revision'] == revision and current['fixture_manifest'] == pin(files[fixture_name]), 'Preflight fixture revision binding'
assert current['fixture_comparator'] == pin(files[prefix + 'evidence/verify-captured.py']), 'Preflight comparator pin'
assert started['checks'] == [] and all(current[key] == started[key] for key in started if key != 'checks'), 'Preflight started/result changed identity'
assert current['status'].startswith('PASS') and current['cliUnchanged'] is True, 'Preflight not passed'
receipt = build_binding(prefix + 'evidence/', current['source'])
assert current['receipt'] == pin(files[prefix + 'evidence/result.json']) and current['proof'] == pin(files[prefix + 'evidence/source-proof.json']), 'Preflight proof pins'
cli = [a for a in receipt['artifacts'] if a['cargo']['target']['name'] == 'arcadia' and not a['cargo']['profile']['test']]
assert len(cli) == 1 and cli[0]['readback'] == current['cli'] == present_pin(prefix + 'bin/arcadia.exe'), 'CLI artifact binding'
assert len(current['checks']) == len(PHASES) and {x['fixture'] for x in current['checks']} == set(PHASES.values()), 'Incomplete fixture preflight'
for check in current['checks']:
name = check['fixture']
assert check['exitCode'] == 0 and check['json_report'] is True and check['fixtureUnchanged'] is True, 'Fixture check failed: ' + name
assert check['stdout'] == pin(files[prefix + name + '.stdout.json']) and check['stderr'] == pin(files[prefix + name + '.stderr.log']), 'CLI output pins'
assert pin(files[prefix + 'fixtures/' + name]) == current_fixture['files'][name], 'Preflight fixture differs'
raw = js(prefix + name + '.stdout.json')
assert raw['operation'] == 'check' and raw['exit_code'] == 0 and raw['written'] is False and not any(x['severity'] == 'error' for x in raw['diagnostics']), 'Raw CLI report rejects fixture'
for runtime in current['runtime']:
assert present_pin(prefix + 'bin/' + PureWindowsPath(runtime['source']).name) == {k: runtime[k] for k in ('bytes', 'sha256')}, 'CLI runtime pin'
except (AssertionError, KeyError, ValueError, TypeError) as error:
problems.append(str(error))
preflights.append({'preflight': entry['name'], 'reviewer_accepted': entry['accepted'], 'checks_pass': not problems, 'problems': problems})
if entry['accepted']:
assert current_fixture['fixture_revision'] == V2, 'Historical v1 cannot be accepted'
assert current['source'] == final_source, 'Accepted preflight source differs'
assert not problems, json.dumps(preflights[-1])
accepted_cli_bindings.add((current['source'], pin(files[fixture_name])['sha256']))
for entry in config['runs']:
prefix = 'runs/' + entry['name'] + '/'
problems, captures, sources = [], 0, []
# Report the actual discovered count even when an earlier historical
# source failure prevents the remaining per-run checks from passing.
for name in files:
if name.startswith(prefix) and name.endswith('.json'):
try:
record = js(name)
captures += int(isinstance(record, dict) and 'images' in record)
except (ValueError, UnicodeError):
pass
try:
prepared, started, finished = (js(prefix + name + '.json') for name in ('prepared', 'started', 'finished'))
fixture_name = prefix + 'evidence/fixture-manifest.json'
run_fixture = js(fixture_name)
check_oracles(files, run_fixture, prefix + 'evidence/')
revision = run_fixture.get('fixture_revision', 'removal-v1-source-derived')
if 'fixture_revision' in prepared:
assert prepared['fixture_revision'] == revision and prepared['fixture_manifest'] == pin(files[fixture_name]), 'Run fixture revision binding'
assert started['prepared'] == pin(files[prefix + 'prepared.json']), 'Started/prepared binding'
for rel, expected in prepared['immutable'].items():
safe_name(rel)
assert present_pin(prefix + rel) == expected, 'Immutable pin: ' + rel
assert prepared['helper'] == pin(files[prefix + 'evidence/native-harness.py']), 'Native helper binding'
for helper in ('capture.js', 'verify-captured.py'):
rel = 'evidence/' + helper
assert prepared['immutable'].get(rel) == pin(files[prefix + rel]), 'Captured observation/source helper is not immutable: ' + helper
for name in [*run_fixture['files'], 'fixture-manifest.json']:
assert prepared['immutable'].get('evidence/' + name) == pin(files[prefix + 'evidence/' + name]), 'Run oracle is not immutable: ' + name
receipt = build_binding(prefix + 'evidence/', prepared['source'])
gui = [a for a in receipt['artifacts'] if a['cargo']['target']['name'] == 'arcadia-studio' and not a['cargo']['profile']['test']]
assert len(gui) == 1 and gui[0]['readback'] == prepared['artifact'] == present_pin(prefix + 'bin/arcadia-studio.exe'), 'GUI artifact binding'
for runtime in prepared['runtime_sources']:
assert present_pin(prefix + 'bin/' + PureWindowsPath(runtime['path']).name) == {k: runtime[k] for k in ('bytes', 'sha256')}, 'GUI runtime pin'
assert started['command'] == prepared['command'] and started['cwd'] == prepared['cwd'], 'Launch command/cwd changed'
identity = started['identity']
assert identity['pid'] == started['pid'] and identity['created_filetime'] > 0 and identity['running'] is True, 'Missing initial live process identity'
assert PureWindowsPath(identity['image']) == PureWindowsPath(prepared['command'][0]), 'Wrong process image'
assert finished['exitCode'] == 0 and finished['immutableUnchanged'] is True, 'Normal exit/immutability not established'
for stream in ('stdout', 'stderr'):
assert finished[stream] == pin(files[prefix + 'app.' + stream + '.log']), 'Final log binding'
assert finished['working'] == pin(files[prefix + 'working.arcadia']), 'Final source binding'
assert prepared.get('initial_pin', started['workingBefore']) == started['workingBefore'], 'Initial source pin changed'
origin = entry.get('reopen_from')
if prefix + 'reopen-origin.json' in files:
old = js(prefix + 'reopen-origin.json')
declared = {'run': old['from_run'], 'file': old['from_file']}
assert origin is None or origin == declared, 'Contradictory reopen origins'
origin = declared
assert old['from_pin'] == old['copied_pin'] == started['workingBefore'], 'Reopen-origin pins disagree'
if origin:
assert origin['run'] != entry['name'] and origin['run'] in {x['name'] for x in config['runs']}, 'Unknown/self reopen origin'
safe_name(origin['file'])
assert pin(files['runs/' + origin['run'] + '/' + origin['file']]) == started['workingBefore'], 'Reopen source is not the exact captured copy'
else:
assert started['workingBefore'] == run_fixture['files']['baseline.arcadia'], 'Nonbaseline start needs explicit reopen_from'
phases = entry.get('source_phases', {})
actual_sources = [name for name in files if name.startswith(prefix) and name.endswith('.arcadia') and '/evidence/' not in name and name != prefix + 'baseline.arcadia']
assert set(phases) <= {name[len(prefix):] for name in actual_sources}, 'Phase config references missing source'
for name in actual_sources:
rel = name[len(prefix):]
sidecar = name[:-8] + '.json'
phase = phases.get(rel)
if sidecar in files and 'phase' in js(sidecar):
saved = js(sidecar)
assert phase is None or phase == saved['phase'], 'Contradictory snapshot phase'
phase = saved['phase']
assert saved['pin'] == pin(files[name]) and saved['exitCode'] == 0, 'Snapshot check/pin failed'
evaluated = js(name[:-8] + '.evaluator.stdout.json')
assert evaluated['status'] == 'PASS' and evaluated['phase'] == phase and evaluated['sha256'] == pin(files[name])['sha256'], 'Raw source evaluator report mismatch'
assert not files[name[:-8] + '.evaluator.stderr.log'], 'Source evaluator stderr is nonempty'
check_source(files, files[name], phase, prefix + 'evidence/')
sources.append({'file': rel, 'phase': phase})
start_time = datetime.datetime.fromisoformat(started['started'])
finish_time = datetime.datetime.fromisoformat(finished['finished'])
assert start_time <= finish_time, 'Reversed process lifetime'
for name in files:
if not name.startswith(prefix) or not name.endswith('.json'):
continue
record = js(name)
if not isinstance(record, dict) or 'images' not in record:
continue
assert record['images'], 'Empty capture record'
assert record['window']['app'].casefold() == ('process:' + identity['image']).casefold(), 'Capture uses a different executable surface'
observed = datetime.datetime.fromisoformat(record['time'])
assert start_time <= observed <= finish_time, 'Capture is outside process lifetime'
for image in record['images']:
safe_name(image['file'])
assert prefix + image['file'] in files and image['width'] > 0 and image['height'] > 0, 'Missing/invalid capture image'
assert captures > 0, 'No captured native observations'
if entry['accepted']:
assert run_fixture['fixture_revision'] == V2, 'Historical v1 cannot be accepted'
assert prepared['source'] == final_source, 'Accepted native source differs'
assert (prepared['source'], pin(files[fixture_name])['sha256']) in accepted_cli_bindings, 'No accepted current-source/current-oracle CLI fixture preflight'
except (AssertionError, KeyError, ValueError, TypeError) as error:
problems.append(str(error))
reports.append({'run': entry['name'], 'reviewer_accepted': entry['accepted'], 'checks_pass': not problems, 'problems': problems, 'capture_records': captures, 'source_checks': sources})
if entry['accepted']:
assert not problems, json.dumps(reports[-1], indent=2)
return {
'status': 'PASS offline archive, exact source and receipt consistency checks',
'gates': gate_reports,
'runs': reports,
'preflights': preflights,
'accepted_run_count': sum(entry['accepted'] for entry in config['runs']),
'limitations': [
'Human visual, keyboard, selection and interaction claims are not inferred from screenshots.',
'Omitted executable/DLL bytes cannot be rehashed offline.',
'Build proof/input map consistency checked; Git blobs are not independently available offline.',
'accepted=false failures are retained and reported, never silently promoted.',
'No native history-depth introspection, usability acceptance, release or publication assertion.',
],
}
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('directory', type=Path)
args = parser.parse_args()
print(json.dumps(verify(args.directory.resolve()), indent=2))
if __name__ == '__main__':
main()
@@ -0,0 +1,235 @@
{
"status": "PASS",
"audited_at": "2026-09-25T04:10:10.690609+00:00",
"scope": "Independent exhaustive byte-level original/member mapping, recursive run/preflight/gate inventories, omitted local executable/DLL pins, historical preservation and report review; no GUI/Cargo/Git/Gitea/source mutation",
"archive": {
"bytes": 9190152,
"sha256": "02ef32920cb76e12da8b2e41cdecd0d5eea5526371df6425462195c30b564250"
},
"manifest": {
"bytes": 77836,
"sha256": "e4b02304f6f7d4113e4799b6c96d6a5a6d663cde0b32a472d7b31d8a19ca8a75"
},
"members": 461,
"mapped_original_files": 460,
"normalized_config": 1,
"member_groups": {
"fixtures": 3,
"gates": 70,
"helpers": 13,
"oracle-revisions": 5,
"preflight": 15,
"preparation": 7,
"review-config.json": 1,
"review-notes": 8,
"runs": 339
},
"attempts": {
"run-1": {
"archived_files": 156,
"excluded_binaries": 2,
"capture_records": 43
},
"run-2": {
"archived_files": 52,
"excluded_binaries": 2,
"capture_records": 10
},
"run-3": {
"archived_files": 131,
"excluded_binaries": 2,
"capture_records": 46
},
"fixture-preflight-1": {
"archived_files": 15,
"excluded_binaries": 2,
"capture_records": 0
}
},
"omitted_binaries_rehashed": 8,
"historical_preservation": {
"old_archive_pin_matches_prior_audit": true,
"old_members": 327,
"identical_members": 326,
"changed_members": [
"review-config.json"
],
"missing_members": [],
"explanation": "Only normalized top-level review-config.json extends accepted runs with run-3; original per-run config, bytes, old package and failures are retained."
},
"errors": [],
"standalone_verifier": {
"command": [
"C:\\Users\\User\\.cache\\codex-runtimes\\codex-primary-runtime\\dependencies\\python\\python.exe",
"-B",
"C:\\ar-scenario-9e8r6t\\harness\\process-group-removal-evidence-20260925\\compact-native\\verify.py",
"C:\\ar-scenario-9e8r6t\\harness\\process-group-removal-evidence-20260925\\compact-native"
],
"exit_code": 0,
"stderr": "",
"result": {
"status": "PASS offline archive, exact source and receipt consistency checks",
"gates": [
{
"gate": "process-removal-tests-1",
"source": "fe637dcd277b17653139ffa234e601b29775c565",
"exitCode": 101
},
{
"gate": "process-removal-tests-2",
"source": "f20497b29bf637619bc35ffe41274fc0f66c387b",
"exitCode": 101
},
{
"gate": "process-removal-tests-3",
"source": "d93c0a801249f361d95721fb0fc239a95159af5c",
"exitCode": 0
},
{
"gate": "process-removal-tests-4",
"source": "572e96ba03522cfb822b13fe4abb50e857a5de48",
"exitCode": 0
},
{
"gate": "process-removal-format-1",
"source": "fe637dcd277b17653139ffa234e601b29775c565",
"exitCode": 0
},
{
"gate": "process-removal-format-2",
"source": "f20497b29bf637619bc35ffe41274fc0f66c387b",
"exitCode": 0
},
{
"gate": "process-removal-format-3",
"source": "572e96ba03522cfb822b13fe4abb50e857a5de48",
"exitCode": 0
},
{
"gate": "process-removal-clippy-1",
"source": "d93c0a801249f361d95721fb0fc239a95159af5c",
"exitCode": 101
},
{
"gate": "process-removal-clippy-2",
"source": "572e96ba03522cfb822b13fe4abb50e857a5de48",
"exitCode": 0
},
{
"gate": "process-removal-build-1",
"source": "572e96ba03522cfb822b13fe4abb50e857a5de48",
"exitCode": 0
}
],
"runs": [
{
"run": "run-1",
"reviewer_accepted": true,
"checks_pass": true,
"problems": [],
"capture_records": 43,
"source_checks": [
{
"file": "snapshots/cancelled-baseline.arcadia",
"phase": "baseline"
},
{
"file": "snapshots/redo.arcadia",
"phase": "removed"
},
{
"file": "snapshots/removed.arcadia",
"phase": "removed"
},
{
"file": "snapshots/undo.arcadia",
"phase": "baseline"
},
{
"file": "working.arcadia",
"phase": "removed"
}
]
},
{
"run": "run-2",
"reviewer_accepted": true,
"checks_pass": true,
"problems": [],
"capture_records": 10,
"source_checks": [
{
"file": "snapshots/reopened.arcadia",
"phase": "removed"
},
{
"file": "working.arcadia",
"phase": "removed"
}
]
},
{
"run": "run-3",
"reviewer_accepted": true,
"checks_pass": true,
"problems": [],
"capture_records": 46,
"source_checks": [
{
"file": "snapshots/compact-cancelled.arcadia",
"phase": "baseline"
},
{
"file": "snapshots/compact-removed.arcadia",
"phase": "removed"
},
{
"file": "snapshots/compact-undo.arcadia",
"phase": "baseline"
},
{
"file": "working.arcadia",
"phase": "baseline"
}
]
}
],
"preflights": [
{
"preflight": "fixture-preflight-1",
"reviewer_accepted": true,
"checks_pass": true,
"problems": []
}
],
"accepted_run_count": 3,
"limitations": [
"Human visual, keyboard, selection and interaction claims are not inferred from screenshots.",
"Omitted executable/DLL bytes cannot be rehashed offline.",
"Build proof/input map consistency checked; Git blobs are not independently available offline.",
"accepted=false failures are retained and reported, never silently promoted.",
"No native history-depth introspection, usability acceptance, release or publication assertion."
]
}
},
"report_review": {
"file": "harness/process-removal-compact-20260925.md",
"material_overclaims": [],
"limits_preserved": [
"One OA derived fixture at 1102x732; compact removal review only",
"Parent action account distinct from capture/source receipts",
"Context Add rather than untested native Shift-click",
"General canvas clipping/small labels/abbreviated palette remain",
"No keyboard-only/full accessibility/SA-native/full-suite/Linux acceptance",
"Redo/reopen evidence comes from original runs1/2",
"Static source-budget investigation found no candidate; no actual Process source-write-failure claim",
"Local-only, no integration/issue-closure/release claim"
],
"review_basis": "Direct image review and source/lifecycle checks in compact-review.md; report compared to that review, compact-actions.md and separate static investigation. No new native execution or formal byte-monotonicity proof."
},
"limits": [
"Offline verifier cannot resolve Git blobs or rehash omitted binaries; this audit additionally rehashed locally available omitted binaries.",
"Archive consistency does not establish new gesture/usability claims.",
"Gate source capsules inputs.zip are intentionally omitted here; receipt pins and original checks package preserve their separate provenance."
]
}
@@ -0,0 +1,80 @@
# Independent compact Process review — 2026-09-25 UTC
Reviewer: `compact_process_review`, bounded evidence review only. No GUI, Cargo,
Git, Gitea or production-source mutation. Parent action account is
`compact-actions.md`; capture JSON records states, not an instrumented input log.
**Finding:** no correctness or usability blocker identified for this fixture's
OA derived Process aggregate-removal review at 1102×732. This is acceptance of
the bounded compact review evidence, not general compact authoring/accessibility.
## Direct visual inspection
Viewed actual images 16, 28, 29 and every image 34–47 with `view_image`.
- 16 establishes the visible compact window. 34 shows 3 selected, both same-name
Review gate cards outlined and the authored link selected; the inspector
distinguishes primary `@approved`. Selection gestures come from the parent's
report, not filenames or screenshot inference.
- 35 shows a contained dialog with readable title, 3 removed / 1 updated,
separate affected-definition counts, search, page controls and fixed Cancel /
explicit Remove controls. The explanation distinguishes local contributions
from preserved referenced definitions and warns that complete caller graphs
are not computed. Same-name selected cards are distinguished by `@a` / `@c`.
- 36 shows the first page scrolled to the explicit-before / implicit-after
summaries while both action buttons remain fully visible. The partial line at
the scroll viewport's upper edge is normal scrolling, not inaccessible content.
- 37 shows page 2 with full `@e1` then `@e2` order entries and both `@caller` and
transitive `@outer` names/aliases. Previous is enabled and Next visibly disabled.
Search and action buttons remain in place, with no review-specific clipping.
- 38 shows the search caret. 39 shows `@outer`, one match and its full affected
caller entry. 40 shows `@outer-missing`, zero matches and recovery guidance;
the three-selection title/counts remain, clearly separating filtering from the
pending operation. Confirmation still represents the entire selected group.
- 41 shows cancellation feedback, original graph, selection count 3 and retained
primary alias; 42 shows saved status. 43 is a fresh unfiltered review. 44–45
show removal feedback, cleared selection, Process owner in the inspector and
surviving exchange cards joined by implicit order, then saved status. 46–47
show the restored four-card/authored-link graph, Undo feedback then saved state.
Undo does not restore the earlier selection; no such guarantee is asserted.
## Source and lifecycle checks
Independently compared complete byte arrays: `compact-cancelled.arcadia`,
`compact-undo.arcadia`, and final `working.arcadia` all equal pinned oracle-v2
`baseline.arcadia` (2609 bytes, SHA256
`9965f4024584d64ac81442724aeb77b018b0cfae94e50bd412c5dcbbac49f6bf`).
`compact-removed.arcadia` equals oracle-v2 `expected-removed.arcadia` (2258 bytes,
SHA256 `b4a2b07ad4c796f555c61945ca42b1c221b454b35488c60fefc86f96f7aa71ba`).
All three snapshot sidecars record evaluator exit 0. The source delta removes
`@a`, `@c`, `@approved`, updates Assessment steps to `[@e1,@e2]`, and preserves
referenced OA work/exchanges, caller references, SA sentinels and remaining bytes.
Rehashed all 12 prepared immutable entries, including the local executable,
DLL, source-proof/input-map/build receipts, exact oracle and comparator copies:
all byte lengths and SHA256 pins match. The executable's pin matches its build
receipt for `572e96ba03522cfb822b13fe4abb50e857a5de48`; the captured source-proof
receipt reports exact source/input agreement. This review did not rerun Git blob
verification. The started receipt correctly pins prepared.json and identifies
PID 6252 and the isolated executable. All 46 capture timestamps lie between
03:58:20.104404 and 04:05:21.991314 UTC; snapshot timestamps also lie within that
interval. Finished receipt reports exit 0, unchanged immutable inputs and final
baseline pin. Actual stdout/stderr files are empty. Parent reports normal Alt+F4.
## Limits and non-blocking observations
At 100% the compact canvas crops the graph (28); Fit exposes it at 59% (29), with
small labels. The narrow palette uses abbreviations, and the inspector/explorer
require scrolling for more content. These are general compact UI observations,
not modal clipping or blockers for the demonstrated removal sequence. Broader
compact authoring remains unevaluated.
Evidence covers this OA derived-layout fixture, mouse/context-add selection,
header review, scrolling/paging/search/empty result, Cancel, explicit Remove,
Save and one parent-reported Ctrl+Z. No native Shift-click, keyboard-only modal
navigation, screen-reader usability, full accessibility, SA native workflows,
source-budget failure or arbitrary smaller windows are accepted here. Captured
native accessibility exposes only the top-level window/title-bar tree. This run
does not add Redo or fresh-process reopen evidence; original runs 1–2 remain
separate and unchanged. Screenshots cannot establish exact keystrokes, timing or
all intermediate states. No new full-suite, Linux, integration or release claim.
@@ -0,0 +1,27 @@
# Process aggregate removal source-budget investigation
Scope: local branch `codex/scenario-multiselect-9e8r6t-20260924`, parent-provided baseline `7323a80e`. Static investigation only; no Cargo, GUI, Gitea, commit, or runtime experiment performed. No production or test source edited.
## Finding
No legitimate source-growth case was found for an admitted Process / Functional Chain aggregate removal. Do not transplant the Scenario lifeline budget fixture by giving Process contributions invalid references, alter a prepared command to perform unrelated growing changes, or reduce private Document limits after loading. Those would test a different operation or an invalid model.
The existing Process regression (`crates/oa-desktop/src/app/process_removal/tests.rs:205`) replaces the admitted plan with Delete(existing) + Delete(nonexistent). It evaluates atomic engine failure and App recovery, **not an actual source update failure**. Keep that evidence boundary explicit.
## Evidence and excluded candidates
- `behavior/topology/group_removal.rs:176` admits only listed local contributions or locally maintained SequenceLink / ContextualLink. `behavior/topology.rs:395` restricts contributions to Action, Exchange, Control and SequenceReference occurrences. Removing a reused contribution does not remove its referenced definition or the referenced work/exchange.
- `oa-core/src/references.rs:325` cascades ownership, incident relations, contextual references, diagram nodes, traces and artifact links. A contextual link referencing a removed occurrence is deleted, not rewritten to a longer reference. No new identities are introduced by the removal plan (`group_removal.rs:263`).
- `references.rs:459` removes records and prunes surviving steps, constraint lists, view options, routes and Scenario layout references. Process occurrence and maintained-link identities cannot be valid targets of the optional work, sequence, scenario, lifeline, supertype, operation-allocation or exchange fields that become `none` when their targets disappear.
- The plausible remaining optional occurrence reference, `reply_to`, cannot reference an admitted Process contribution: `validation.rs:1626` rejects Call/reply semantics outside Scenario; `validation.rs:1688` requires the target Call to belong to the same Scenario. State trigger fallback text likewise requires Event or work targets (`validation.rs:2619`), not occurrence or maintained-link targets.
- `view_options.rs:96` retains explicit empty selection variants and only filters their identity lists; no longer enum is substituted.
- `source_project.rs:1516` uses identity keys for surviving reference list entries, preserving surviving syntax/trivia and stripping deleted tokens. `item_key` at approximately 1695 keys references, routes and semantic rows. `trivia` at 1127 filters input tokens without adding bytes. Structural deletion in `source_project/source_structure.rs` retains trivia of deleted declarations and does not create/move surviving records for this cascade. There was no credible canonical-format expansion candidate in the paths inspected.
These are reviewed code-path observations, not a formal proof that every possible accepted source spelling is byte-monotone. No claim of an exhaustive runtime search is made. OA and SA share these admission and cascade rules; saved views add record/list pruning, not a discovered growth mechanism.
## Better evaluator
1. Retain the existing Process injected engine-failure test with its precise scope. It already checks snapshot identity, exact model/bundle, editor/workspace, selection targets/primary, camera and usable redo. Future strengthening may add revision/clean state, selection generation and navigation, but cannot turn that test into source-write-failure evidence.
2. Use `app/scenario_removal/tests.rs:199` as the genuine source-budget failure evaluator: valid lifeline removals rewrite many short `@a` / `@b` references in surviving messages to `none`, prove unrestricted exact-model success and net source growth, and fail through public `Document::from_bundle` limits. That test covers the shared Document transactional source-write boundary plus Scenario App recovery.
3. If explicit Process source-write failure branch coverage is required, introduce a narrowly scoped test fault at the Document source writer, and label it an injected source-writer failure. That is more honest than a semantically invalid growth fixture, but adds a test seam and is outside the delegated tests-only scope. A meaningful non-fault alternative is a public input-sized-budget **successful** Process removal test over the literal native fixture; it checks that deletion remains possible at the admitted source budget, not failure atomicity.
4. Revisit if Process semantics gain surviving optional references to contributions or if source editing changes to insert replacement syntax during removal.
@@ -0,0 +1,71 @@
# Process removal compact review follow-up
The unchanged Windows build from `572e96ba03522cfb822b13fe4abb50e857a5de48`
supports the bounded OA derived Process removal workflow at **1102x732**.
This closes the compact review gap in the [original report](process-group-removal-app-20260925.md).
The contribution remains local-only pending recovery of Gitea writes; no
integration, issue closure or release is claimed.
## Observed behavior
Run 3 opened an isolated copy of the original fixture. Fit made its four cards
and authored link visible. Context Add formed the exact group Action @a,
Control @c and SequenceLink @approved, with the link primary. The review's
title, aggregate counts, search, paging and fixed Cancel/Remove buttons fit
within the window. Scrolling page 1 exposes the explicit-before/implicit-after
order changes without losing the footer. Page 2 shows both remaining exchange
positions and full direct/transitive caller names and aliases. Search finds
@outer; a nonmatching query displays recovery guidance.
Cancel preserves all three selected members and the link primary. Save gives
the complete 2609-byte baseline. A fresh review resets search; explicit Remove
leaves two exchange cards with their implicit connection and clears selection.
Save equals the independently specified 2258-byte v2 result. One Ctrl+Z and
Save restores every original byte. The normal close exits 0, with empty logs
and all twelve immutable file pins unchanged. Redo and fresh reopen retain
their original runs 1–2 evidence; they were not rerun here.
- Baseline SHA256: `9965f4024584d64ac81442724aeb77b018b0cfae94e50bd412c5dcbbac49f6bf`.
- Removed SHA256: `b4a2b07ad4c796f555c61945ca42b1c221b454b35488c60fefc86f96f7aa71ba`.
See the [parent action record](process-group-removal-evidence-20260925/compact-actions.md)
and [independent review](process-group-removal-evidence-20260925/compact-review.md).
Actions reported by the parent are distinguished from screenshots and source
receipts. The setup record preserves ineffective edge drags, the unsupported
UIA value operation and picker-focus reporting inconsistency. None is counted
as successful application interaction.
## Evidence and limitations
The new [native evidence snapshot](process-group-removal-evidence-20260925/compact-native/native-evidence.zip)
includes all three closed runs and the original failed gate history. It does
not overwrite the earlier two-run package. Its [manifest](process-group-removal-evidence-20260925/compact-native/manifest.json)
pins every included member and identifies omitted executable/DLL bytes.
The standalone verifier passes: 461 members, eight omitted binary payloads,
three accepted closed native runs, and the retained preflight/gate history.
ZIP size is 9,190,152 bytes; SHA256
`02ef32920cb76e12da8b2e41cdecd0d5eea5526371df6425462195c30b564250`.
The [independent archive audit](process-group-removal-evidence-20260925/compact-package-audit.json)
compares all members with original records, rehashes omitted local binaries,
confirms preservation of the original two runs, and separately runs the verifier.
Recheck with Python 3.11+:
```text
python -B harness/process-group-removal-evidence-20260925/compact-native/verify.py harness/process-group-removal-evidence-20260925/compact-native
```
This is compact **removal review** acceptance for one OA derived fixture, not
complete compact authoring or accessibility acceptance. At 100% zoom the narrow
canvas crops the graph; Fit reduces label size. The narrow tool palette uses
abbreviated labels. Native Shift-click, keyboard-only navigation, equivalent SA
native acceptance, full-suite and Linux checks remain unclaimed. No production
source changed and no new Cargo build was needed for this native trial.
A [separate static investigation](process-group-removal-evidence-20260925/source-failure-investigation.md)
found no legitimate growing-source Process removal for a genuine size-budget
failure. Valid removals prune admitted contributions, links and references;
Scenario's optional-reference expansion fixture does not transfer to Process.
The existing Process test exercises an injected engine failure. The genuine
Scenario test covers the shared Document source-budget boundary. Neither is
relabeled as actual Process source-write-failure coverage, and no artificial
fixture or production fault seam was introduced.