P04-01: 同時発生の更新規約
This commit is contained in:
@@ -17,7 +17,7 @@ MANIFEST_SHA256 = 'a15f29fa12537f6d8aaf7cabea390922a9f16e3eb9c10981e5742aafc8c4c
|
|||||||
MANIFEST_BYTES = 1244135
|
MANIFEST_BYTES = 1244135
|
||||||
PRODUCT = '5f6bc11d6bb6e92d22d787989b219fef3a435bc1'
|
PRODUCT = '5f6bc11d6bb6e92d22d787989b219fef3a435bc1'
|
||||||
RUNS = {'s1': 'p04-s1-native-r02', 's2a': 'p04-s2a-native-r03',
|
RUNS = {'s1': 'p04-s1-native-r02', 's2a': 'p04-s2a-native-r03',
|
||||||
's2b': 'p04-s2b-native-r02', 's3': 'p04-s3-native-r01', 's4': 'p04-s4-native-r24'}
|
's2b': 'p04-s2b-native-r02', 's3': 'p04-s3-native-r01', 's4': 'p04-s4-native-r26'}
|
||||||
# Native descriptors pinned from literal files, never ROOT result passed fields.
|
# Native descriptors pinned from literal files, never ROOT result passed fields.
|
||||||
NATIVE_PINS = {
|
NATIVE_PINS = {
|
||||||
's1': ('1e26d9585396da9415747d87d77b70f23425a3ee0714e4fca114748f9479fd4e', '01372beb0ffec181c892d3b4e88bce32001e08fb2007938d7bf19135511a7acc', '0b6d11eb34d8af64b22cb806caeb06eed4ec521fa9ee24d1204ea185345e655c'),
|
's1': ('1e26d9585396da9415747d87d77b70f23425a3ee0714e4fca114748f9479fd4e', '01372beb0ffec181c892d3b4e88bce32001e08fb2007938d7bf19135511a7acc', '0b6d11eb34d8af64b22cb806caeb06eed4ec521fa9ee24d1204ea185345e655c'),
|
||||||
@@ -1023,11 +1023,29 @@ class S4Series(Series):
|
|||||||
require(path.is_relative_to(self.build), 'S4 material outside own B')
|
require(path.is_relative_to(self.build), 'S4 material outside own B')
|
||||||
self.read_build(path.relative_to(self.build).as_posix(), pin)
|
self.read_build(path.relative_to(self.build).as_posix(), pin)
|
||||||
verify_s4_engine(inputs['engine'], execution['engine_identity'])
|
verify_s4_engine(inputs['engine'], execution['engine_identity'])
|
||||||
require(inputs['engine_identity'] == execution['engine_identity'], 'S4 input/execution engine identity')
|
initial = inputs['engine_identity_initial']
|
||||||
|
require(inputs['engine_identity_before'] == inputs['engine'] == initial['before'] ==
|
||||||
|
execution['engine_identity']['before'], 'S4 immutable initial engine descriptor')
|
||||||
|
require(set(initial) == {'before', 'during', 'after'} and initial['after'] is None and
|
||||||
|
isinstance(initial['during'], list) and
|
||||||
|
initial['during'] == execution['engine_identity']['during'][:len(initial['during'])],
|
||||||
|
'S4 initial observations are an immutable prefix')
|
||||||
observations = execution['engine_observations']
|
observations = execution['engine_observations']
|
||||||
require(any(row['stage'] == 'after-cleanup' for row in observations) and
|
stages = [row['stage'] for row in observations]
|
||||||
all(row.get('descriptor') == inputs['engine'] for row in observations),
|
required = ['before-import', 'before-parse', 'before-writer', 'before-reader',
|
||||||
'S4 runtime engine observations')
|
'after-collection', 'after-cleanup', 'after-output-collection']
|
||||||
|
require(all(stages.count(stage) == 1 for stage in required) and
|
||||||
|
[stages.index(stage) for stage in required] == sorted(stages.index(stage) for stage in required) and
|
||||||
|
all(row.get('descriptor') == inputs['engine'] and 'error' not in row for row in observations),
|
||||||
|
'S4 ordered runtime engine observations')
|
||||||
|
for phase in ('import', 'parse', 'writer', 'reader'):
|
||||||
|
index = stages.index('before-' + phase)
|
||||||
|
require(loads(self.read('engine-identity-before-' + phase + '.json')) ==
|
||||||
|
dict(observations[index], observation_index=index), 'S4 immutable per-phase engine receipt')
|
||||||
|
require(loads(self.read('engine-identity.json')) ==
|
||||||
|
dict(observations=observations, identity=execution['engine_identity']), 'S4 final engine receipt')
|
||||||
|
require(observations[stages.index('after-cleanup')]['descriptor'] == inputs['engine'],
|
||||||
|
'S4 exact after-cleanup engine descriptor')
|
||||||
require(execution['error'] is None and execution['guard_errors'] == [] and execution['cleanup_errors'] == [] and
|
require(execution['error'] is None and execution['guard_errors'] == [] and execution['cleanup_errors'] == [] and
|
||||||
[p['phase'] for p in execution['phases']] == ['import', 'parse', 'writer', 'reader'], 'S4 native phase/guard failure')
|
[p['phase'] for p in execution['phases']] == ['import', 'parse', 'writer', 'reader'], 'S4 native phase/guard failure')
|
||||||
for phase in execution['phases']:
|
for phase in execution['phases']:
|
||||||
|
|||||||
@@ -14,20 +14,24 @@ provenance only. Never open their original production locations.
|
|||||||
export B=/Users/korizatou114/Projects/TheTree-managed-worktrees/p04-01/.runtime/P04-01/build
|
export B=/Users/korizatou114/Projects/TheTree-managed-worktrees/p04-01/.runtime/P04-01/build
|
||||||
export E=docs/plans/original-completion-2026-10-02/execution/p04-01
|
export E=docs/plans/original-completion-2026-10-02/execution/p04-01
|
||||||
export PYTHONDONTWRITEBYTECODE=1
|
export PYTHONDONTWRITEBYTECODE=1
|
||||||
mkdir "$B/audit-support/p04-s4-source-r24"
|
python3 "$E/s4/engine_identity_negative_fixtures.py"
|
||||||
cp "$E/s4/run_s4_native.py" "$E/s4/p04_s4_power_probe.gd" "$E/s4/S4_ROOT_RUN.md" "$B/audit-support/p04-s4-source-r24/"
|
python3 "$E/s4/receipt_lifecycle_fixtures.py"
|
||||||
python3 "$B/audit-support/p04-s4-source-r24/run_s4_native.py" \
|
mkdir "$B/audit-support/p04-s4-source-r26"
|
||||||
|
cp "$E/s4/run_s4_native.py" "$E/s4/p04_s4_power_probe.gd" "$E/s4/S4_ROOT_RUN.md" "$B/audit-support/p04-s4-source-r26/"
|
||||||
|
python3 "$B/audit-support/p04-s4-source-r26/run_s4_native.py" \
|
||||||
--project-root "$B/audit-support/p04-r17-full-inputs-r01/product" \
|
--project-root "$B/audit-support/p04-r17-full-inputs-r01/product" \
|
||||||
--output "$B/p04-s4-native-r24" --plan "$B/p04-s4-plan-r24.json" \
|
--output "$B/p04-s4-native-r26" --plan "$B/p04-s4-plan-r26.json" \
|
||||||
--godot /Applications/Godot.app/Contents/MacOS/Godot --check-only
|
--godot /Applications/Godot.app/Contents/MacOS/Godot --check-only
|
||||||
python3 "$B/audit-support/p04-s4-source-r24/run_s4_native.py" \
|
python3 "$B/audit-support/p04-s4-source-r26/run_s4_native.py" \
|
||||||
--project-root "$B/audit-support/p04-r17-full-inputs-r01/product" \
|
--project-root "$B/audit-support/p04-r17-full-inputs-r01/product" \
|
||||||
--output "$B/p04-s4-native-r24" --plan "$B/p04-s4-plan-r24.json" \
|
--output "$B/p04-s4-native-r26" --plan "$B/p04-s4-plan-r26.json" \
|
||||||
--godot /Applications/Godot.app/Contents/MacOS/Godot
|
--godot /Applications/Godot.app/Contents/MacOS/Godot
|
||||||
```
|
```
|
||||||
|
|
||||||
The first invocation only prepares the pinned plan: zero engine launches. The
|
Root must stop if either fixture or check-only fails; the commands are not an
|
||||||
second is one collection, exactly four sequential owned processes: import,
|
unconditional batch. Both fixtures start zero engines. The check-only invocation
|
||||||
|
only prepares the pinned plan: zero engine launches. The final invocation
|
||||||
|
is one collection, exactly four sequential owned processes: import,
|
||||||
parse, Writer, Reader. Each retains the framework's native diagnostics,
|
parse, Writer, Reader. Each retains the framework's native diagnostics,
|
||||||
ownership, exit/end checks, full stream SHA, default-player protection, private
|
ownership, exit/end checks, full stream SHA, default-player protection, private
|
||||||
profiles, source-before/after guards and cleanup. Failure stops the collection;
|
profiles, source-before/after guards and cleanup. Failure stops the collection;
|
||||||
@@ -37,7 +41,7 @@ inputs. Reader uses only the existing IO1 formal package mapping.
|
|||||||
|
|
||||||
Exact input footprints:
|
Exact input footprints:
|
||||||
|
|
||||||
- Current wrapper SHA256 is recorded in `../REPAIR24_STATUS.md`. The plan pins
|
- Historical wrapper hashes do not pin this repair. The fresh plan pins
|
||||||
its exact bytes and Stage R checks them against the current source checkout.
|
its exact bytes and Stage R checks them against the current source checkout.
|
||||||
- `B/audit-support/p04-r17-full-inputs-r01/MANIFEST.json`, SHA256
|
- `B/audit-support/p04-r17-full-inputs-r01/MANIFEST.json`, SHA256
|
||||||
`a15f29fa12537f6d8aaf7cabea390922a9f16e3eb9c10981e5742aafc8c4c8a8`.
|
`a15f29fa12537f6d8aaf7cabea390922a9f16e3eb9c10981e5742aafc8c4c8a8`.
|
||||||
@@ -48,7 +52,8 @@ Exact input footprints:
|
|||||||
- The three staged S4 files above, pinned by the plan, and the installed executable
|
- The three staged S4 files above, pinned by the plan, and the installed executable
|
||||||
`/Applications/Godot.app/Contents/MacOS/Godot`, pinned directly against the
|
`/Applications/Godot.app/Contents/MacOS/Godot`, pinned directly against the
|
||||||
constant SHA before launch, during collection, and explicitly after cleanup.
|
constant SHA before launch, during collection, and explicitly after cleanup.
|
||||||
Before/during/after descriptors are retained in runner-input and execution. The only stage override
|
Runner-input retains an immutable initial descriptor and observation prefix;
|
||||||
|
execution and engine-identity retain the final before/during/after identity. The only stage override
|
||||||
is `tests/s3/test_runtime_staff_assignment.gd` with the S4 probe. Harness and
|
is `tests/s3/test_runtime_staff_assignment.gd` with the S4 probe. Harness and
|
||||||
kitchen fixture are the unchanged product files; inherited sources are
|
kitchen fixture are the unchanged product files; inherited sources are
|
||||||
included in the full1338 map. The parse roster is all316 `.gd` inputs.
|
included in the full1338 map. The parse roster is all316 `.gd` inputs.
|
||||||
@@ -64,8 +69,8 @@ Exact input footprints:
|
|||||||
proof and remains ineligible. Its diagnostics are at
|
proof and remains ineligible. Its diagnostics are at
|
||||||
`audit-support/p04-root-d393-s4-r01/ENGINE_STAGING_DIAGNOSTICS.json`.
|
`audit-support/p04-root-d393-s4-r01/ENGINE_STAGING_DIAGNOSTICS.json`.
|
||||||
|
|
||||||
Exact output footprints are `B/p04-s4-plan-r24.json` and the fresh
|
Exact output footprints are `B/p04-s4-plan-r26.json` and the fresh
|
||||||
`B/p04-s4-native-r24/**`: private selected source stage, complete phase receipts
|
`B/p04-s4-native-r26/**`: private selected source stage, complete phase receipts
|
||||||
and logs, raw JSON/Variant points and all phase observations, full source maps,
|
and logs, raw JSON/Variant points and all phase observations, full source maps,
|
||||||
PID and cleanup receipts. `formal/{writer,reader}/S4-{boundary,held,recovered}/`
|
PID and cleanup receipts. `formal/{writer,reader}/S4-{boundary,held,recovered}/`
|
||||||
mirrors all four formal members (`journal.log`, `manifest.json`, `thumbnail.png`,
|
mirrors all four formal members (`journal.log`, `manifest.json`, `thumbnail.png`,
|
||||||
@@ -107,8 +112,115 @@ restore and is not part of Runtime snapshot equality. The derived
|
|||||||
`related_facility_operating` flag is measured separately and checked after restore.
|
`related_facility_operating` flag is measured separately and checked after restore.
|
||||||
|
|
||||||
This source-only dispatch authorizes no worker execution. Root stages the three
|
This source-only dispatch authorizes no worker execution. Root stages the three
|
||||||
files, creates the r24 plan with --check-only, then collects once to the fresh
|
files, creates the r26 plan with --check-only, then collects once to the fresh
|
||||||
r24 output. Do not rerun S1-S3, C or full178. No engine copy, signing, xattr,
|
r26 output. Do not read or write r24 outputs, cleanup, stages or plans.
|
||||||
|
Do not rerun S1-S3, C or full178. No engine copy, signing, xattr,
|
||||||
codesign call or security-setting change is part of this procedure.
|
codesign call or security-setting change is part of this procedure.
|
||||||
Native evidence, registered validation, independent review, support53cb rebind
|
Native evidence, registered validation, independent review, support53cb rebind
|
||||||
and formal acceptance remain pending. D05 remains pending.
|
and formal acceptance remain pending. D05 remains pending.
|
||||||
|
|
||||||
|
## REPAIR26 receipt lifecycle audit (static; NOT RUN)
|
||||||
|
|
||||||
|
All names below are relative to the fresh output unless marked otherwise.
|
||||||
|
`r.write` is the unchanged exclusive `open('x')` writer in
|
||||||
|
`tools/run_all_tests.py`. No retry, overwrite, replace or atomic rename is used
|
||||||
|
for a JSON proof. A write attempt may fail or leave a partial file; it is never
|
||||||
|
retried. “At most once” describes wrapper control flow, not a durability claim.
|
||||||
|
The initial input is serialized once with `engine=engine_descriptor`,
|
||||||
|
`engine_identity_before=engine_descriptor` and a deep-copied initial identity.
|
||||||
|
`repin()` itself is unchanged (it returns None); each per-phase receipt uses
|
||||||
|
the descriptor it just appended and the index of that exact observation.
|
||||||
|
|
||||||
|
| Writer / destination | Maximum attempts per run / uniqueness | Success and failure reachability |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `r.write(args.plan)` outside output | 1, check-only branch returns immediately | Native branch only reads the exact plan; existing plan rejected in check-only |
|
||||||
|
| `runner-started.json` | 1 | First write inside protected setup; exception enters cleanup |
|
||||||
|
| `source_before.json` | 1 | Setup before source copy; no fallback write |
|
||||||
|
| `selected-source-map.json` | 1 | Setup before source copy; no fallback write |
|
||||||
|
| `r.copy_source` to `stage/<source name>` | 1 per unique source-map key | Fresh stage; loop stops on setup failure; source files are not proof receipts |
|
||||||
|
| `write_bytes` to `bootstrap/<name>` | 1 per pinned bootstrap key | The reviewed map names `profile_guard.gd` and `parse_full_dependencies.gd`; setup only |
|
||||||
|
| `/bin/cp -c` to `stage/.godot/<name>` | 1 per cache inventory key | Optional eligible-cache branch only; fresh mode never accesses cache |
|
||||||
|
| `cache-reuse.json` | 0 or 1 | Only after all optional cache clones and guards |
|
||||||
|
| `parse-paths.json` | 1 | Setup after 316-script guard |
|
||||||
|
| `contracts.json` | 1 | Setup after unchanged suite-policy guard |
|
||||||
|
| `runner-input.json` | 1 | Setup; no final read/rewrite; absent if earlier setup fails |
|
||||||
|
| `engine-identity-before-<phase>.json` | 1 each for import, parse, writer, reader | Immediately after that phase's repin; failure stops loop, never resumes it |
|
||||||
|
| `write_bytes` to `writer-combined-raw.log`, `reader-combined-raw.log` | 1 each | Binary copy immediately after returned phase row, even a failed row if it has a log; later phases never reuse names |
|
||||||
|
| `<phase>-actual-phase.json` | 1 each for four unique phases | Before `require(row['passed'])`; mid-loop failure retains its row and stops later phases |
|
||||||
|
| `outer-owned-finally.json` | 1 | Single finally after setup/loop success or failure; cleanup called once; cleanup exception recorded; receipt write exception becomes guard error |
|
||||||
|
| `source_after.json` | 0 or 1 | Single post-cleanup guarded block, after fixed_guard/source_refs succeed; later guard failure does not re-enter or retry the write |
|
||||||
|
| `shutil.copyfile` to `formal/<role>/<slot>/<member>` | 1 per tuple | Only preliminary pass; two unique roles, unique slot map keys, four unique member keys, fresh target directory; exception stops collection |
|
||||||
|
| `formal-relocation.json` | 0 or 1 | Only after successful complete formal mirror |
|
||||||
|
| `raw-inventory.json` | 0 or 1 | Once after mirror branch, including setup/phase/cleanup failure; earlier output-collection exception can skip it |
|
||||||
|
| `PID-set.json` | 0 or 1 | Once after raw inventory; earlier output-collection exception can skip it |
|
||||||
|
| `engine-identity.json` | 1 | One final attempt after cleanup and both after-cleanup/after-output-collection repin attempts, including caught setup/phase/cleanup/collection failures; own write failure records guard error and makes both passed fields false |
|
||||||
|
| `execution.json` | 1 | After identity attempt, with final observations, identity and guard errors |
|
||||||
|
| `runner-ended.json` | 1 | After execution; no retry if final receipt storage itself fails |
|
||||||
|
|
||||||
|
The wrapper has no `write_text` call. The unchanged `execute_phase` dependency
|
||||||
|
also writes the following. Its shared text log is an explicit exception to
|
||||||
|
write-once naming, and is not presented as two independent phase proofs.
|
||||||
|
|
||||||
|
| Dependency destination | Writer and lifecycle |
|
||||||
|
| --- | --- |
|
||||||
|
| `<phase>-startup-profile-before.json` | Exclusive `write`, once per distinct phase before engine start |
|
||||||
|
| `<phase>-profile.json` | Guard report path for parse/writer/reader, one per phase; actual Guard checks file absence before writing |
|
||||||
|
| `starters/<phase>.gd` | `write_text`, once each for writer/reader |
|
||||||
|
| `<phase>/combined-raw.log` | `write_text`, once each for import/parse |
|
||||||
|
| `tests__s3__test_runtime_staff_assignment.gd.log` (general `out/<test>.log`) | Both writer and reader call `write_text` on this same per-test name; reader replaces the shared text. Wrapper preserves separate binary copies as `writer-combined-raw.log` and `reader-combined-raw.log`, retaining `strict_runner_log_path` and the original log hash |
|
||||||
|
| `<phase>-receipt.json` | Exclusive `write`, once per phase after its finally and guards |
|
||||||
|
| `stage/project.godot` | `write_bytes` for private startup settings and restoration in each phase finally; mutable private source, not immutable proof |
|
||||||
|
| `<phase>/**`, private profiles, raw QA outputs | Delegated owned-native capture/engine/QA outputs; not wrapper `r.write`/`write_bytes`/`write_text` calls; their existing ownership/diagnostic/formal guards remain unchanged |
|
||||||
|
|
||||||
|
Path coverage: success traverses each distinct phase once. A failed parse row is
|
||||||
|
recorded, then `require(row['passed'])` jumps to the single finally; no writer or
|
||||||
|
reader names are used. A protected setup failure also enters that finally, then
|
||||||
|
attempts post-cleanup guards and final identity/execution/end receipts. Cleanup
|
||||||
|
exceptions are caught separately, set `cleanup_errors`, and do not prevent final
|
||||||
|
receipts. A post-cleanup fixed/source guard failure is caught without retrying
|
||||||
|
`source_after`; formal/output-collection exceptions now become guard errors and
|
||||||
|
still reach the final repin and identity receipt. A final identity write failure
|
||||||
|
is caught without touching existing bytes and forces failure in execution/end.
|
||||||
|
|
||||||
|
Admission failures before the protected setup (invalid plan/product/engine,
|
||||||
|
live engine, insufficient disk, existing output, directory creation failure)
|
||||||
|
remain fail-closed and do not promise final receipts. They have no repeated
|
||||||
|
wrapper proof write. Persistent storage failure writing execution/end can still
|
||||||
|
prevent a complete terminal receipt pair; no code can guarantee receipt storage
|
||||||
|
when that storage fails. Such runs cannot provide accepted evidence.
|
||||||
|
|
||||||
|
## Fixture scope and remaining gaps
|
||||||
|
|
||||||
|
`receipt_lifecycle_fixtures.py` imports the real wrapper and standard writer.
|
||||||
|
It builds 1338 synthetic source entries including 316 scripts in resolved fresh
|
||||||
|
temporary paths; engine identity, template_guard, disk/default-player, helpers
|
||||||
|
and phase execution are mocked. Four distinct fake PIDs and complete synthetic
|
||||||
|
formal slot members exercise wrapper guards and copying without starting an
|
||||||
|
engine. The actual identity section of `S4Series.__init__` is compiled from its
|
||||||
|
AST, and actual `verify_s4_engine` checks a non-executable temporary data file
|
||||||
|
under fixture-only patched constants. Other verifier sections are not claimed
|
||||||
|
as covered by this synthetic fixture.
|
||||||
|
|
||||||
|
Cases cover success after check-only, parse failure, cleanup exception, setup
|
||||||
|
copy failure, post-cleanup collection failure and final identity write failure.
|
||||||
|
Every exclusive write attempt is counted. Input bytes are compared with their
|
||||||
|
creation bytes before negative mutation. Fresh-output refusal, each missing or
|
||||||
|
tampered phase receipt and mismatched initial-before are negative checks. The
|
||||||
|
fixture's deliberate proof mutations are confined to its disposable temporary
|
||||||
|
files. No registered plan/output/stage is read or changed.
|
||||||
|
|
||||||
|
Reasoning only about the 7af6 wrapper: import writes `engine-identity.json` via
|
||||||
|
exclusive create. Before parse, the same name raises FileExistsError, so the
|
||||||
|
four-phase success assertion cannot pass. After cleanup the old final write
|
||||||
|
tries that same name again and escapes main, preventing final execution/end.
|
||||||
|
Even if that collision alone were removed, the old runner-input final rewrite
|
||||||
|
would hit the exclusive writer, and the required initial/per-phase receipts
|
||||||
|
are absent. No 7af6 execution was performed to establish this reasoning.
|
||||||
|
|
||||||
|
Worker performed source inspection and file edits only: no fixtures, check-only,
|
||||||
|
tests, Git, engines, Runner, agents or commits. Root still must run both fixtures
|
||||||
|
and check-only before any native r26 collection, then exact-version verification
|
||||||
|
and independent review. The registered validation gate remains unchanged at
|
||||||
|
7af6, exit 2, fresh MANIFEST missing; this is the supplied gate record, not a new
|
||||||
|
worker run. Native/product proof, full formal checks, D05 and original P04-01
|
||||||
|
acceptance remain pending. This repair is submitted preparation, not completion.
|
||||||
|
|||||||
+1
-1
@@ -33,7 +33,7 @@ def run():
|
|||||||
|
|
||||||
# Same bytes/SHA cannot admit an own-B bare copy or another outside-B path.
|
# Same bytes/SHA cannot admit an own-B bare copy or another outside-B path.
|
||||||
for label, path in [
|
for label, path in [
|
||||||
("copied bare engine in B with same SHA", s4.BUILD / "audit-support/p04-s4-source-r24/Godot"),
|
("copied bare engine in B with same SHA", s4.BUILD / "audit-support/p04-s4-source-r26/Godot"),
|
||||||
("other outside-B path", Path("/Applications/OtherGodot.app/Contents/MacOS/Godot")),
|
("other outside-B path", Path("/Applications/OtherGodot.app/Contents/MacOS/Godot")),
|
||||||
]:
|
]:
|
||||||
other = dict(pin, path=str(path))
|
other = dict(pin, path=str(path))
|
||||||
|
|||||||
+255
@@ -0,0 +1,255 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Root-only synthetic receipt lifecycle fixtures. No engine/process is started.
|
||||||
|
|
||||||
|
Uses the real main, exclusive JSON writer, source_refs and inventories. The
|
||||||
|
identity section is compiled directly from S4Series.__init__, not reimplemented.
|
||||||
|
This is not native/product/ownership/formal acceptance evidence.
|
||||||
|
"""
|
||||||
|
import ast
|
||||||
|
from collections import Counter
|
||||||
|
from contextlib import ExitStack, redirect_stdout
|
||||||
|
import copy
|
||||||
|
import importlib.util
|
||||||
|
import io
|
||||||
|
import json
|
||||||
|
from pathlib import Path
|
||||||
|
import shutil
|
||||||
|
import sys
|
||||||
|
import tempfile
|
||||||
|
from types import SimpleNamespace
|
||||||
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
sys.dont_write_bytecode = True
|
||||||
|
HERE = Path(__file__).resolve().parent
|
||||||
|
ROOT = next(p for p in HERE.parents if (p / 'tools/run_all_tests.py').is_file())
|
||||||
|
|
||||||
|
|
||||||
|
def load(name, path):
|
||||||
|
spec = importlib.util.spec_from_file_location(name, path)
|
||||||
|
value = importlib.util.module_from_spec(spec)
|
||||||
|
spec.loader.exec_module(value)
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
s4 = load('receipt_s4', HERE / 'run_s4_native.py')
|
||||||
|
r = load('receipt_standard', ROOT / 'tools/run_all_tests.py')
|
||||||
|
series = load('receipt_series', HERE.parent / 'p04_native_series.py')
|
||||||
|
|
||||||
|
|
||||||
|
def identity_code():
|
||||||
|
tree = ast.parse((HERE.parent / 'p04_native_series.py').read_text())
|
||||||
|
cls = next(n for n in tree.body if isinstance(n, ast.ClassDef) and n.name == 'S4Series')
|
||||||
|
init = next(n for n in cls.body if isinstance(n, ast.FunctionDef) and n.name == '__init__')
|
||||||
|
start = next(i for i, n in enumerate(init.body) if isinstance(n, ast.Expr) and
|
||||||
|
isinstance(n.value, ast.Call) and isinstance(n.value.func, ast.Name) and
|
||||||
|
n.value.func.id == 'verify_s4_engine')
|
||||||
|
end = next(i for i in range(start + 1, len(init.body))
|
||||||
|
if "execution['error']" in ast.unparse(init.body[i]))
|
||||||
|
return compile(ast.Module(body=init.body[start:end], type_ignores=[]), '<real S4 identity section>', 'exec')
|
||||||
|
|
||||||
|
|
||||||
|
def verify_identity(out, descriptor):
|
||||||
|
# The real engine verifier reads only the synthetic ordinary file here.
|
||||||
|
# Production constants/functions on disk are never changed.
|
||||||
|
with patch.object(series, 'S4_ENGINE_PATH', descriptor['path']), \
|
||||||
|
patch.object(series, 'S4_ENGINE_SHA256', descriptor['sha256']):
|
||||||
|
namespace = dict(vars(series), inputs=r.read(out / 'runner-input.json'),
|
||||||
|
execution=r.read(out / 'execution.json'),
|
||||||
|
self=SimpleNamespace(read=lambda name: (out / name).read_bytes()))
|
||||||
|
exec(identity_code(), namespace)
|
||||||
|
|
||||||
|
|
||||||
|
def rejected(action):
|
||||||
|
try:
|
||||||
|
action()
|
||||||
|
except (ValueError, AssertionError, OSError, KeyError, TypeError):
|
||||||
|
return
|
||||||
|
raise AssertionError('negative fixture was accepted')
|
||||||
|
|
||||||
|
|
||||||
|
def case(base, failure=None):
|
||||||
|
product = base / 'product'
|
||||||
|
support = base / 'support'
|
||||||
|
staged = base / 'source'
|
||||||
|
for path in (product, support, staged):
|
||||||
|
path.mkdir(parents=True)
|
||||||
|
|
||||||
|
def put(path, data):
|
||||||
|
path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
path.write_bytes(data)
|
||||||
|
|
||||||
|
# Real 1338-entry source_refs and 316-entry script roster, synthetic bytes.
|
||||||
|
scripts = [s4.TEST, 'tests/transport/test_runtime_transport.gd',
|
||||||
|
'tests/staff/test_rescue_elevator.gd']
|
||||||
|
scripts += ['scripts/fixture_%03d.gd' % i for i in range(313)]
|
||||||
|
for name in scripts:
|
||||||
|
put(product / name, b'extends Node\n')
|
||||||
|
for name in ('project.godot', 'export_presets.cfg', 'Makefile', 'AGENTS.md'):
|
||||||
|
put(product / name, b'fixture\n')
|
||||||
|
put(product / 'tools/run_all_tests.py', (ROOT / 'tools/run_all_tests.py').read_bytes())
|
||||||
|
for i in range(1017):
|
||||||
|
put(product / ('data/fixture_%04d.txt' % i), b'fixture\n')
|
||||||
|
assert len(r.source_refs(product)) == 1338
|
||||||
|
qa = staged / 'p04_s4_power_probe.gd'
|
||||||
|
put(qa, b'extends Node\n# synthetic override\n')
|
||||||
|
put(staged / 'run_s4_native.py', (HERE / 'run_s4_native.py').read_bytes())
|
||||||
|
put(staged / 'S4_ROOT_RUN.md', b'synthetic fixture material\n')
|
||||||
|
contracts = base / 'contracts.json'
|
||||||
|
r.write(contracts, {})
|
||||||
|
material = base / 'material.json'
|
||||||
|
r.write(material, {})
|
||||||
|
r.write(support / 'suite-policy.json', {'suite_policies': {}})
|
||||||
|
r.write(support / 'bootstrap-scripts.json', {
|
||||||
|
'parse_full_dependencies.gd': {'text': 'fixture\n', 'sha256': r.sha(product / 'Makefile')}})
|
||||||
|
engine = base / 'synthetic-engine-data'
|
||||||
|
put(engine, b'not an executable; never launched\n')
|
||||||
|
st = engine.stat()
|
||||||
|
descriptor = dict(path=str(engine), resolved_path=str(engine), bytes=st.st_size,
|
||||||
|
sha256=r.sha(engine), mtime_ns=st.st_mtime_ns, mode=st.st_mode,
|
||||||
|
device=st.st_dev, inode=st.st_ino, ctime_ns=st.st_ctime_ns)
|
||||||
|
out = base / 'p04-s4-native-r26'
|
||||||
|
plan = base / 'p04-s4-plan-r26.json'
|
||||||
|
attempts, created, phases = Counter(), {}, []
|
||||||
|
cleanup_calls = []
|
||||||
|
real_write, real_inventory = r.write, r.inventory
|
||||||
|
protected = dict(path=str(base / 'default-player'), existed=False, files={}, logs_and_locks_included=True)
|
||||||
|
|
||||||
|
def write(path, value):
|
||||||
|
path = Path(path)
|
||||||
|
attempts[path] += 1
|
||||||
|
if failure == 'identity-write' and path == out / 'engine-identity.json':
|
||||||
|
raise OSError('injected final identity write error')
|
||||||
|
real_write(path, value) # unchanged open('x'), including collisions
|
||||||
|
created[path] = path.read_bytes()
|
||||||
|
|
||||||
|
def finish(owned):
|
||||||
|
cleanup_calls.append(list(owned))
|
||||||
|
if failure == 'cleanup':
|
||||||
|
raise RuntimeError('injected cleanup error')
|
||||||
|
return [dict(pid=p.pid, engine_ended=True) for p in owned], []
|
||||||
|
|
||||||
|
outer = SimpleNamespace(native=SimpleNamespace(helper={'live_engines': lambda: []}),
|
||||||
|
OWNED=[SimpleNamespace(pid=91001+i) for i in range(4)],
|
||||||
|
finish_captured=finish, run_phase=lambda *a, **k: None)
|
||||||
|
|
||||||
|
def execute(engine_arg, stage, output, phase, test, selected, expected, previous,
|
||||||
|
policy, contracts_arg, paths, public, player, root, *helpers):
|
||||||
|
phases.append(phase)
|
||||||
|
assert engine_arg == str(engine) and output == out and player == protected
|
||||||
|
assert r.source_refs(root) == selected['root_before']
|
||||||
|
assert r.inventory(stage, stage=True) == dict(expected, **previous)
|
||||||
|
pid = outer.OWNED[len(phases)-1].pid
|
||||||
|
row = dict(phase=phase, passed=not (failure == 'parse' and phase == 'parse'), actual_pid=pid)
|
||||||
|
if test:
|
||||||
|
slots = {}
|
||||||
|
for slot in s4.SLOTS:
|
||||||
|
directory = base / 'profiles' / phase / slot
|
||||||
|
for member in ('journal.log', 'manifest.json', 'thumbnail.png', 'world.bin'):
|
||||||
|
put(directory / member, (slot + '/' + member).encode())
|
||||||
|
slots[slot] = str(directory)
|
||||||
|
(out / 'raw').mkdir(exist_ok=True)
|
||||||
|
write(out / ('raw/' + phase + '.json'), dict(checks=1, failures=0, branches=['S4'],
|
||||||
|
slots=slots, pid=pid, profile=str(base / 'profiles' / phase)))
|
||||||
|
# Reproduce the runner's shared text log and let main copy its bytes.
|
||||||
|
log = test.replace('/', '__') + '.log'
|
||||||
|
(out / log).write_text(phase + '\n')
|
||||||
|
row['log'] = log
|
||||||
|
return row
|
||||||
|
|
||||||
|
def inventory(path, **kwargs):
|
||||||
|
if failure == 'output' and Path(path) == out / 'raw':
|
||||||
|
raise OSError('injected post-cleanup inventory error')
|
||||||
|
return real_inventory(path, **kwargs)
|
||||||
|
|
||||||
|
def copy_source(source, target):
|
||||||
|
if failure == 'setup':
|
||||||
|
raise OSError('injected setup copy error')
|
||||||
|
shutil.copyfile(source, target)
|
||||||
|
|
||||||
|
def modules(name, path):
|
||||||
|
if name == 's4_standard_runner':
|
||||||
|
return r
|
||||||
|
if name == 's4_owned_outer':
|
||||||
|
return outer
|
||||||
|
if name == 's4_markers':
|
||||||
|
return SimpleNamespace(load_contracts=lambda path: {})
|
||||||
|
if name in ('s4_diagnostics', 's4_owners', 's4_audio'):
|
||||||
|
return SimpleNamespace()
|
||||||
|
raise AssertionError('unexpected helper import: ' + name)
|
||||||
|
|
||||||
|
with ExitStack() as stack:
|
||||||
|
for obj, values in [(s4, dict(BUILD=base, PRODUCT=product, HERE=staged, QA=qa,
|
||||||
|
ENGINE=engine, CONTRACTS=contracts, MATERIALS=[material],
|
||||||
|
__file__=str(staged / 'run_s4_native.py'), module=modules)),
|
||||||
|
(r, dict(SUPPORT=support, write=write, execute_phase=execute,
|
||||||
|
copy_source=copy_source, inventory=inventory))]:
|
||||||
|
for key, value in values.items():
|
||||||
|
stack.enter_context(patch.object(obj, key, value))
|
||||||
|
pin_mock = stack.enter_context(patch.object(s4, 'engine_pin', return_value=descriptor))
|
||||||
|
guard_mock = stack.enter_context(patch.object(s4, 'template_guard', return_value=None))
|
||||||
|
player_mock = stack.enter_context(patch.object(r, 'default_player', return_value=protected))
|
||||||
|
disk_mock = stack.enter_context(patch.object(s4.shutil, 'disk_usage',
|
||||||
|
return_value=SimpleNamespace(free=10 * 1024**3)))
|
||||||
|
stack.enter_context(redirect_stdout(io.StringIO()))
|
||||||
|
argv = ['run_s4_native.py', '--project-root', str(product), '--output', str(out),
|
||||||
|
'--plan', str(plan), '--godot', str(engine)]
|
||||||
|
with patch.object(sys, 'argv', argv + ['--check-only']):
|
||||||
|
assert s4.main() == 0
|
||||||
|
assert not phases and not cleanup_calls and not out.exists()
|
||||||
|
with patch.object(sys, 'argv', argv):
|
||||||
|
result = s4.main()
|
||||||
|
rejected(s4.main) # same output must be rejected before any new writes
|
||||||
|
assert pin_mock.called and guard_mock.called and player_mock.called and disk_mock.called
|
||||||
|
|
||||||
|
assert result == (0 if failure is None else 1)
|
||||||
|
assert len(cleanup_calls) == 1
|
||||||
|
assert all(count == 1 for count in attempts.values()), attempts
|
||||||
|
for leaf in ('outer-owned-finally.json', 'engine-identity.json', 'execution.json', 'runner-ended.json'):
|
||||||
|
assert attempts[out / leaf] == 1
|
||||||
|
if failure != 'identity-write' or leaf != 'engine-identity.json':
|
||||||
|
assert (out / leaf).is_file()
|
||||||
|
if failure != 'setup':
|
||||||
|
assert (out / 'runner-input.json').read_bytes() == created[out / 'runner-input.json']
|
||||||
|
assert r.read(out / 'runner-input.json')['engine_identity_initial']['after'] is None
|
||||||
|
execution = r.read(out / 'execution.json')
|
||||||
|
assert execution['passed'] is (failure is None)
|
||||||
|
assert 'FileExistsError' not in json.dumps(execution)
|
||||||
|
assert phases == ([] if failure == 'setup' else ['import', 'parse'] if failure == 'parse'
|
||||||
|
else ['import', 'parse', 'writer', 'reader'])
|
||||||
|
if failure == 'cleanup':
|
||||||
|
assert execution['cleanup_errors'] == ['injected cleanup error']
|
||||||
|
if failure in ('output', 'identity-write'):
|
||||||
|
assert execution['guard_errors']
|
||||||
|
if failure is None:
|
||||||
|
assert len(list(out.glob('engine-identity*.json'))) == 5
|
||||||
|
verify_identity(out, descriptor)
|
||||||
|
assert (out / 'writer-combined-raw.log').read_bytes() == b'writer\n'
|
||||||
|
assert (out / 'reader-combined-raw.log').read_bytes() == b'reader\n'
|
||||||
|
# Mutations below affect only this disposable fixture's synthetic proofs.
|
||||||
|
for phase in ('import', 'parse', 'writer', 'reader'):
|
||||||
|
path = out / ('engine-identity-before-' + phase + '.json')
|
||||||
|
original = path.read_bytes()
|
||||||
|
path.write_text('{}')
|
||||||
|
rejected(lambda: verify_identity(out, descriptor))
|
||||||
|
path.unlink()
|
||||||
|
rejected(lambda: verify_identity(out, descriptor))
|
||||||
|
path.write_bytes(original)
|
||||||
|
path = out / 'runner-input.json'
|
||||||
|
initial = r.read(path)
|
||||||
|
changed = copy.deepcopy(initial)
|
||||||
|
changed['engine_identity_initial']['before']['inode'] += 1
|
||||||
|
path.write_text(json.dumps(changed))
|
||||||
|
rejected(lambda: verify_identity(out, descriptor))
|
||||||
|
path.write_bytes(created[path])
|
||||||
|
verify_identity(out, descriptor)
|
||||||
|
return dict(case=failure or 'success', passed=True, native_engine_launches=0)
|
||||||
|
|
||||||
|
|
||||||
|
def run():
|
||||||
|
with tempfile.TemporaryDirectory(prefix='s4-receipt-fixtures-') as temporary:
|
||||||
|
return [case(Path(temporary).resolve() / (failure or 'success'), failure)
|
||||||
|
for failure in (None, 'parse', 'cleanup', 'setup', 'output', 'identity-write')]
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
print(json.dumps(dict(results=run(), formal_acceptance=False), indent=2))
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
"""S4-only native entry. --check-only never loads ownership helpers or starts Godot."""
|
"""S4-only native entry. --check-only never loads ownership helpers or starts Godot."""
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import argparse
|
import argparse
|
||||||
|
import copy
|
||||||
import hashlib
|
import hashlib
|
||||||
import importlib.util
|
import importlib.util
|
||||||
import json
|
import json
|
||||||
@@ -98,8 +99,8 @@ def engine_pin(path, expected=None):
|
|||||||
def main():
|
def main():
|
||||||
parser = argparse.ArgumentParser(description=__doc__)
|
parser = argparse.ArgumentParser(description=__doc__)
|
||||||
parser.add_argument("--project-root", type=Path, default=PRODUCT)
|
parser.add_argument("--project-root", type=Path, default=PRODUCT)
|
||||||
parser.add_argument("--output", type=Path, default=BUILD / "p04-s4-native-r24")
|
parser.add_argument("--output", type=Path, default=BUILD / "p04-s4-native-r26")
|
||||||
parser.add_argument("--plan", type=Path, default=BUILD / "p04-s4-plan-r24.json")
|
parser.add_argument("--plan", type=Path, default=BUILD / "p04-s4-plan-r26.json")
|
||||||
parser.add_argument("--cache-run", type=Path, default=None,
|
parser.add_argument("--cache-run", type=Path, default=None,
|
||||||
help="optional passed registered cache; default is fresh, without cache access")
|
help="optional passed registered cache; default is fresh, without cache access")
|
||||||
parser.add_argument("--godot", type=Path, default=ENGINE)
|
parser.add_argument("--godot", type=Path, default=ENGINE)
|
||||||
@@ -222,9 +223,9 @@ def main():
|
|||||||
env.update(THE_TREE_S4_EVIDENCE=str(out / "raw"), THE_TREE_S4_MODE=folder.name)
|
env.update(THE_TREE_S4_EVIDENCE=str(out / "raw"), THE_TREE_S4_MODE=folder.name)
|
||||||
return original_phase(argv, folder, timeout, env, **kwargs)
|
return original_phase(argv, folder, timeout, env, **kwargs)
|
||||||
outer.run_phase = run_phase
|
outer.run_phase = run_phase
|
||||||
r.write(out / "runner-started.json", dict(started=r.now(), owner_runner_pid=os.getpid(),
|
|
||||||
plan=pin(args.plan), engines_launched=0))
|
|
||||||
try:
|
try:
|
||||||
|
r.write(out / "runner-started.json", dict(started=r.now(), owner_runner_pid=os.getpid(),
|
||||||
|
plan=pin(args.plan), engines_launched=0))
|
||||||
r.write(out / "source_before.json", source_before)
|
r.write(out / "source_before.json", source_before)
|
||||||
r.write(out / "selected-source-map.json", refs)
|
r.write(out / "selected-source-map.json", refs)
|
||||||
# Private source stage first, then literal reviewed bootstrap.
|
# Private source stage first, then literal reviewed bootstrap.
|
||||||
@@ -262,7 +263,9 @@ def main():
|
|||||||
r.require(TEST not in policy["suite_policies"], "no normal suite watchdog/policy override")
|
r.require(TEST not in policy["suite_policies"], "no normal suite watchdog/policy override")
|
||||||
r.write(out / "contracts.json", contracts)
|
r.write(out / "contracts.json", contracts)
|
||||||
r.write(out / "runner-input.json", dict(plan, owner_runner_pid=os.getpid(),
|
r.write(out / "runner-input.json", dict(plan, owner_runner_pid=os.getpid(),
|
||||||
wrapper_sha256=r.sha(__file__), QA=pin(QA), engine=engine_descriptor, engine_identity=engine_identity, runner_sha256=r.sha(root / "tools/run_all_tests.py"),
|
wrapper_sha256=r.sha(__file__), QA=pin(QA), engine=engine_descriptor,
|
||||||
|
engine_identity_before=engine_descriptor, engine_identity_initial=copy.deepcopy(engine_identity),
|
||||||
|
runner_sha256=r.sha(root / "tools/run_all_tests.py"),
|
||||||
default_player_before=protected, fixed_input_pins=fixed,
|
default_player_before=protected, fixed_input_pins=fixed,
|
||||||
functional_watchdog_seconds=1200, source_adoption=False))
|
functional_watchdog_seconds=1200, source_adoption=False))
|
||||||
diagnostics = module("s4_diagnostics", r.SUPPORT / "diagnostic_gate.py")
|
diagnostics = module("s4_diagnostics", r.SUPPORT / "diagnostic_gate.py")
|
||||||
@@ -278,12 +281,15 @@ def main():
|
|||||||
r.require(not (stage / ".godot").exists() and not (stage / ".godot").is_symlink(),
|
r.require(not (stage / ".godot").exists() and not (stage / ".godot").is_symlink(),
|
||||||
"fresh private .godot absent at actual import")
|
"fresh private .godot absent at actual import")
|
||||||
repin("before-" + phase)
|
repin("before-" + phase)
|
||||||
r.write(out / "engine-identity.json", engine_observations)
|
r.write(out / ("engine-identity-before-" + phase + ".json"),
|
||||||
|
dict(engine_observations[-1], observation_index=len(engine_observations)-1))
|
||||||
row = r.execute_phase(str(engine), stage, out, phase, test, selected, expected,
|
row = r.execute_phase(str(engine), stage, out, phase, test, selected, expected,
|
||||||
previous, policy, contracts, paths, public, protected, root,
|
previous, policy, contracts, paths, public, protected, root,
|
||||||
outer, markers, diagnostics, owners, audio)
|
outer, markers, diagnostics, owners, audio)
|
||||||
phases.append(row)
|
phases.append(row)
|
||||||
# execute_phase uses the same test log name; retain each phase's exact log too.
|
# execute_phase writer/reader share out/<test>.log via write_text.
|
||||||
|
# Keep binary per-phase copies under these existing unique names.
|
||||||
|
# The shared runner log is not write-once; see S4_ROOT_RUN.md.
|
||||||
if test and row.get("log"):
|
if test and row.get("log"):
|
||||||
(out / (phase + "-combined-raw.log")).write_bytes((out / row["log"]).read_bytes())
|
(out / (phase + "-combined-raw.log")).write_bytes((out / row["log"]).read_bytes())
|
||||||
row["strict_runner_log_path"] = row["log"]
|
row["strict_runner_log_path"] = row["log"]
|
||||||
@@ -349,36 +355,43 @@ def main():
|
|||||||
# IO1 has already copied all four members into a separate Reader profile.
|
# IO1 has already copied all four members into a separate Reader profile.
|
||||||
# Mirror those exact complete directories to own B for read-only R verification.
|
# Mirror those exact complete directories to own B for read-only R verification.
|
||||||
# Original profile paths are provenance after this step, never verifier inputs.
|
# Original profile paths are provenance after this step, never verifier inputs.
|
||||||
if passed:
|
try:
|
||||||
relocated = {}
|
if passed:
|
||||||
for role in ("writer", "reader"):
|
relocated = {}
|
||||||
receipt = r.read(out / ("raw/" + role + ".json"))
|
for role in ("writer", "reader"):
|
||||||
relocated[role] = {}
|
receipt = r.read(out / ("raw/" + role + ".json"))
|
||||||
for slot, original in receipt["slots"].items():
|
relocated[role] = {}
|
||||||
target = out / "formal" / role / slot
|
for slot, original in receipt["slots"].items():
|
||||||
target.mkdir(parents=True)
|
target = out / "formal" / role / slot
|
||||||
members = r.inventory(Path(original))
|
target.mkdir(parents=True)
|
||||||
r.require(set(members) == {"journal.log", "manifest.json", "thumbnail.png", "world.bin"}, "all formal members")
|
members = r.inventory(Path(original))
|
||||||
for member in members:
|
r.require(set(members) == {"journal.log", "manifest.json", "thumbnail.png", "world.bin"}, "all formal members")
|
||||||
shutil.copyfile(Path(original) / member, target / member)
|
for member in members:
|
||||||
r.require(r.inventory(target) == members == formal_before[slot], "whole formal mirror")
|
shutil.copyfile(Path(original) / member, target / member)
|
||||||
relocated[role][slot] = dict(provenance=original, relative=str(target.relative_to(out)), members=members)
|
r.require(r.inventory(target) == members == formal_before[slot], "whole formal mirror")
|
||||||
r.write(out / "formal-relocation.json", relocated)
|
relocated[role][slot] = dict(provenance=original, relative=str(target.relative_to(out)), members=members)
|
||||||
r.write(out / "raw-inventory.json", r.inventory(out / "raw"))
|
r.write(out / "formal-relocation.json", relocated)
|
||||||
r.write(out / "PID-set.json", dict(owner_runner_pid=os.getpid(), engine_PIDs=pids))
|
r.write(out / "raw-inventory.json", r.inventory(out / "raw"))
|
||||||
|
r.write(out / "PID-set.json", dict(owner_runner_pid=os.getpid(), engine_PIDs=pids))
|
||||||
|
except BaseException as caught:
|
||||||
|
guards.append("output collection: " + type(caught).__name__ + ": " + str(caught))
|
||||||
|
passed = False
|
||||||
|
execution["passed"] = False
|
||||||
try:
|
try:
|
||||||
repin("after-output-collection")
|
repin("after-output-collection")
|
||||||
except BaseException as caught:
|
except BaseException as caught:
|
||||||
guards.append(str(caught))
|
guards.append(str(caught))
|
||||||
passed = False
|
passed = False
|
||||||
execution["passed"] = False
|
execution["passed"] = False
|
||||||
r.write(out / "engine-identity.json", engine_observations)
|
try:
|
||||||
|
r.write(out / "engine-identity.json",
|
||||||
|
dict(observations=engine_observations, identity=engine_identity))
|
||||||
|
except BaseException as caught:
|
||||||
|
guards.append("engine identity receipt: " + type(caught).__name__ + ": " + str(caught))
|
||||||
|
passed = False
|
||||||
|
execution["passed"] = False
|
||||||
execution["engine_observations"] = engine_observations
|
execution["engine_observations"] = engine_observations
|
||||||
execution["engine_identity"] = engine_identity
|
execution["engine_identity"] = engine_identity
|
||||||
if (out / "runner-input.json").is_file():
|
|
||||||
final_inputs = r.read(out / "runner-input.json")
|
|
||||||
final_inputs["engine_identity"] = engine_identity
|
|
||||||
r.write(out / "runner-input.json", final_inputs)
|
|
||||||
r.write(out / "execution.json", execution)
|
r.write(out / "execution.json", execution)
|
||||||
r.write(out / "runner-ended.json", dict(execution, ended=r.now()))
|
r.write(out / "runner-ended.json", dict(execution, ended=r.now()))
|
||||||
print(json.dumps(dict(passed=passed, error=error, guard_errors=guards, output=str(out))))
|
print(json.dumps(dict(passed=passed, error=error, guard_errors=guards, output=str(out))))
|
||||||
|
|||||||
Reference in New Issue
Block a user