diff --git a/docs/changes/netkingdom-target-2026-10-17/native-runtime-install-r2/FINAL-PROPOSAL.md b/docs/changes/netkingdom-target-2026-10-17/native-runtime-install-r2/FINAL-PROPOSAL.md new file mode 100644 index 00000000..954f9d2d --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/native-runtime-install-r2/FINAL-PROPOSAL.md @@ -0,0 +1,254 @@ +# Install and verify the immutable Glas/rein runtime on railiance01 + +Proposal ID: **REINAH-WP-0008-T07-install-f599-r1**, revision **2**. +Status: **pending root review and exact founder approval; no native mutation**. +R1 remains frozen, unapproved and unexecuted. This is revision 2 of the same +proposal/trial, addressing root review of descendant cleanup. This is a +separately reviewable installation step under existing T07. It does +not require completing the paid-attempt envelope because it uses no provider, +worker credential, owner/spend configuration, catalog change or queue action. +It does not activate the artifact or complete T07, GLAS-WP-0012-T03/T04, the +current Custodian assignment migration or TSA-06. + +## Exact action and target + +After root retains this exact revision and the supervisor's disposition, run: + +```bash +python3 -I -B /home/worsch/the-custodian/docs/changes/netkingdom-target-2026-10-17/native-runtime-install-r2/execute-install.py --apply +``` + +The same file's default/`--dry-run` is read-only. `--apply` refuses any existing +local execution receipt, so a failed/uncertain attempt cannot be rerun blindly. +There is no scheduling, continuous claim loop, profile readiness override, +credential acquisition, provider request, owner renewal or service restart. + +| Input | Exact value | +|---|---| +| Host | existing SSH alias railiance01; Kubernetes node must be Ready at 92.205.62.239 | +| Account | tegwick, UID/GID 1000, home /home/tegwick | +| Existing protected store | /home/tegwick/.helixforge-factory/runtimes, mode 0700, device 2049, inode 4751222 | +| New destination | /home/tegwick/.helixforge-factory/runtimes/f59959b605a51abd2901becde14e7abd852c2bd3f848004b51d250d1cb81af6d | +| Complete runtime digest | sha256:f59959b605a51abd2901becde14e7abd852c2bd3f848004b51d250d1cb81af6d | +| Retained source artifact | /tmp/netkingdom-runtime-canonical-20261016/runtime | +| Exact new owned staging | /home/tegwick/.helixforge-factory/runtime-install-f599-r2-20261017 | +| Transfer archive | deterministic gzip/PAX tar, 109,931,109 bytes, 1,448 members | +| Transfer SHA-256 | sha256:4c55b2740e759175d645705518fc33db30b26b4611f68e052a4ca909173084c7 | +| Logical regular-file bytes | 260,668,241; one retained internal relative symlink, lib64 → lib | + +`action-inputs.json` freezes every executable/helper hash and archive input. +`artifact-manifest.json` binds this proposal and all retained review evidence. +Only four named payload files go into remote staging: runtime.tar.gz, +runtime.py, install-verified.py and process_supervision.py. The private +one-action watchdog and its JSON receipts exist beneath that staging only; +they create no service, schedule or persistent control plane. The workstation archive is regenerated +privately from the exact source only at execution, checked against the frozen +archive hash, transferred, and removed from its local temporary directory. +No large runtime archive or new source build is committed to this repository. + +## Existing owner contract and actual observations + +Sand-boxer `docs/bwrap-runtime.md` explicitly separates protected artifact +installation from profile selection, credentials, network activation and schedules. +The existing `runtime_store.install_runtime` verifies source, checks the owned +store and lock, copies symlinks/modes into its own private staging, verifies the +copy and atomically publishes under its digest. It never replaces an existing +artifact. This proposal uses that exact implementation already in f599; it does +not introduce another store or installer service. Remote owner source checkouts +are absent, so the pinned public digest reader/driver travel with the artifact. + +Exact installed component hashes: + +- sandboxer runtime.py: sha256:19b5fb687288bbc836978b0251599dc1e4d1593e8b5efee85a6abb6a7f388412 +- sandboxer runtime_store.py: sha256:c3d6ec09d08881611d3d02b8f55d68deed6ecfedaa1a809b6b11c57cc4ca97cf +- rein owner_rehearsal.py: sha256:192f654cad4a5f065c7faa5e35b03493297a472e8d7fe641be2c42c5fb00dcc3 + +Runtime/store components match both the artifact's sandboxer `221126cb` and +current owner source `53f800c4`; the rehearsal matches artifact rein `9b88cadaa8`. +The complete build includes Glas `7357115c` and llm-connect `37436bb5` from the +previously reviewed immutable build. Reuse its actual manager/gateway proof for +isolation/workload-delivery mechanics; no deterministic proof is relabelled a +real model call. The new action proves native installation and free launch only. + +Read-only target evidence verifies the expected account/node, safe home/factory/ +store/lock modes and absent destination/staging. Four older digest directories +remain in the store, including b6e4e8a4; this action does not select, overwrite, +remove or execute them. Pinned native executables are /usr/bin/python3 (3.12.3), +/usr/local/bin/kubectl for the node read and /usr/bin/bwrap. No private owner/config/auth files were opened by these observations. + +The R2 read-only dry-run at **2026-10-17 06:01:35 UTC** passed all guards: +123,352,678,400 free disk bytes, 7,735,549,952 available memory bytes, one-second +CPU busy fraction 0.2832 and one-minute load 1.9634 across four CPUs. The new +R2 staging and destination were absent. Earlier R1 target observations and +headroom refusal remain copied as explicitly historical evidence; only +final-readonly-dry-run.json records this R2 controller. A passing snapshot is +not a reservation. All guards run again before any approved attempt. + +The target's installed **bubblewrap 0.9.0** help supports --die-with-parent. +Its installed upstream manual states that it kills all sandbox processes when +bwrap or its parent dies, using PR_SET_PDEATHSIG. The R2 dry-run records the +manual excerpt plus successful pidfd-open and PR_GET_CHILD_SUBREAPER readback. +No target namespace or runtime was launched to obtain this evidence. + +## Exact execution and refusal behavior + +1. Verify every local helper hash and the complete source artifact digest. + Read target metadata only; require the exact existing store device/inode, + expected UID/GID/modes and Ready node/IP. Require both new paths absent, + at least 2GiB free disk and 1GiB available memory, one-minute load ≤8 on four + CPUs, and CPU busy ≤85% in one bounded one-second sample. Refuse on drift; + no polling or mutation follows a failed gate. +2. Write the local attempt intent before native staging. Recreate and verify + the exact deterministic archive locally. Recheck CPU and exact store metadata + before exclusive creation of the named 0700 remote staging directory. Record + its actual device/inode in the local receipt before uploading anything. +3. SCP only the archive and three public helpers. The fixed SSH bootstrap verifies + the exact directory identity, complete four-file inventory, regular-file + owner and all four payload hashes; it sets those owned public payload files + to 0600. Then it execs the hashed install helper with a cleared application + environment. Existing SSH authentication is transport only; no key is fetched, + copied into the workload or exposed in evidence. +4. After exact staging identity verification, the helper lowers priority to nice + 19 before starting its private process supervisor, so descendants inherit it. + The helper rechecks identity/headroom and verifies archive hash/size and every member name/type/mode/count/size, + rejects hardlinks/special/escaping members, extracts directories/files before + internal relative symlinks and checks the complete extracted digest. It does + not restore archive owners or execute a tar-supplied command. All created + files belong to tegwick. A local temporary roundtrip independently passed + that extraction and the exact final runtime digest, with modes/symlink intact. +5. The staged candidate interpreter with `-I -B` imports and hash-checks its + existing owner runtime/store modules, then calls existing install_runtime + under a 180-second alarm and a supervised 200-second outer phase bound. No new package resolution/download occurs. The + existing helper holds its normal lock and cleans its own temporary copy on + ordinary exception, then atomically appends the verified new digest. Refuse + if the destination appeared, even if somebody installed identical bytes; + no existing install is silently adopted as this action's success. +6. Rehash the complete native destination. Execute only the installed artifact's + existing owner_rehearsal.rehearse through its existing run= callback seam, + independent of owner.json, + SpendPolicy or ledger state. It launches rein-aharness --help, + glas-harness --help and Claude --version inside empty-egress bwrap, each with + a supervised 60-second timeout and discarded command output; the phase has + a 240-second alarm and supervised 260-second outer bound. The callback adds + supported --die-with-parent to the otherwise unchanged frozen owner bwrap + argv. frozen-native-argv.json records all three exact command arrays without + executing them. The helper refuses any missing frozen system bind before + launch. Require exactly those three zero exits. No model/task command or + credential route is constructed. Child environment is cleared; host HOME + and credentials are not mounted. These ephemeral namespaces create no + SandboxManager record, persistent worker, model session or provider lease. +7. Rehash the entire installed tree after rehearsal and remove only the exact + owned staging directory only after the watchdog has stopped, been waited, + and positively reported no live or waitable descendants, followed by exact + device/inode/owner/mode and known-inventory checks. Missing or uncertain + quiescence retains staging with failed-cleanup evidence. Capture the final structured result in this packet's + execution-receipt.json. SSH closes when the foreground helper exits. + +The rehearsal is the existing credential-free source API, not metered-once +--rehearse against a private old owner configuration. This avoids changing pins +or reading a ledger merely to validate an inactive artifact. It neither changes +nor bypasses the normal future runtime/profile/spend/credential admission path. + +## Expected result, cost and risk + +Success is `installed_and_offline_rehearsal_verified`, with actual install result, +owner UID/store mode, extracted/installed/post-rehearsal full digest equality, +three explicit launcher exit codes and staging absence. Destination remains a +dormant append. Profile and credential flags stay false; provider calls are zero. +No current owner/catalog/queue/definition/profile bytes are read or changed by the +installation action. T07's spend acceptance, owner renewal and real-model/native +approvals remain separate. + +Persistent addition is about 261MB of logical file data plus filesystem metadata. +Transfer is about 110MB. Extraction/copy temporarily add two artifact-sized trees +plus the archive; the 2GiB free-disk requirement includes operating margin. Hashing +and copy are sequential and lower priority, but a snapshot gate cannot guarantee +that shared-host CPU/IO remains idle throughout execution. + +Requested provider spend is USD 0: no provider API exists in this action. No new +paid resource or recurring service is committed. Incremental infrastructure, +energy and human recovery time in EUR are **unknown**, not zero. Credible EUR +loss from unexpected shared single-node IO/resource interruption is also unknown. +Approval must explicitly cover this small supervised append/rehearsal exposure; +this proposal grants no autonomous budget or autopilot authority. Root may defer +execution until the fresh headroom gate passes without weakening its thresholds. + +## Cleanup, rollback and uncertainty + +Every phase and bwrap launcher is spawned by the single private watchdog, +not by subprocess.run. It is a Linux child subreaper, starts each job in its own +session/process group and binds the controller/callers with pidfds. The watchdog +watches controller loss, caller loss, timeout, output bounds and orphaned +children. On any of those events it stops **all owned jobs for this action**, +including nested Runner jobs which are siblings of the phase under the +watchdog. It discovers actual descendants/adopted orphans, binds each PID with +a pidfd and rechecks UID/start identity before signaling only that exact +process. It gives TERM 0.5 seconds, then KILL/reap up to 3 seconds. It does not +use broad kill, process-name matching or kill a shared process group. Output is +bounded at 64KiB and application stderr is always discarded. No private values +are included in error receipts. + +Each directly spawned process arms PR_SET_PDEATHSIG before exec and checks its +parent. The added bwrap --die-with-parent also covers sandbox processes if +bwrap/the watchdog disappears. Controller SIGKILL leaves the watchdog alive +long enough to stop/reap jobs and write quiescent.json, but **leaves staging**: +a dead controller cannot authorize cleanup. Watchdog loss or uncertain PID/UID/ +start mapping is failed/unverified cleanup; the controller does not infer a +successful cleanup from a leader's exit. The final controller waits for its +watchdog and requires its positive quiescence receipt before deleting staging. +See PROCESS-CONTRACT.md for the precise source seam and failure matrix. + +A transfer/bootstrap failure before remote helper execution may leave only the +exact upload directory. The conditional command is +`python3 -I -B /home/worsch/the-custodian/docs/changes/netkingdom-target-2026-10-17/native-runtime-install-r2/cleanup-upload-staging.py --apply`. +It requires this proposal's revision-2 local receipt at staging_created / +before_transfer, matching directory identity, only the four named regular +upload files, and no supervision state or extracted runtime. It refuses every +later phase. No post-execution cleanup command is authorized by that helper. + +An SSH timeout or lost final reply after remote_execution_started remains an +uncertain outcome; never replay --apply or delete staging. The 600-second SSH +timeout is not proof that a surviving remote controller stopped. Reconcile the +exact recorded stage/watchdog identity, quiescence receipt and complete installed +digest read-only under the same trial; root must review any recovery mutation. +Unexpected objects/mapping or absent quiescence evidence stay untouched. + +The existing installer cleans its private `.install-*` copy on ordinary Python +failure. Hard host/process loss may leave it; do not glob-delete store staging +or infer ownership from the prefix. Preserve exact baseline/new-object metadata +and request attended owner recovery for anything not tied to this attempt. + +Rollback does not restore owner/catalog configuration because this action never +changes it. Keep every older artifact and the newly installed immutable artifact +as dormant evidence; removal of a published digest is not part of existing +installer rollback and is not authorized here. If installation succeeds but +rehearsal fails, record that partial outcome, retain the inactive artifact and +staging cleanup facts, and stop. No automatic profile selection, in-place repair, +artifact deletion, credential/provider retry or follow-up service action follows. + +## Review evidence + +- action-inputs.json: fixed paths/helper hashes/archive/components/guards. +- frozen-native-argv.json: actual owner-generated three-launcher arrays plus the + bounded Runner --die-with-parent addition; zero launcher executions. +- process-fixture-results.json: five actual disposable-process tests, including + timeout, controller SIGKILL, session escape, nested Runner and mapping refusal. +- r1-preservation.json: all frozen R1 entries verified, complete R1 file hashes. +- retained-local-source-refusal.json and local-bytecode-refinement.json: failed + preparation retained. Owner argv inspection accidentally generated one local + pyc; the source gate refused before any target call. Only that generated file + and empty cache directory were removed; complete f599 equality was restored. + Subsequent artifact inspection uses -B. This is a refinement of this same + trial, not a separate successful privileged action. +- target-readonly-observation.json and target-readonly-addendum.json: actual + target/account/store/node/absence and Python/bwrap observations. +- cpu-readonly-observation.json and retained-headroom-refusal.json: earlier + saturation/refusal, retained separately from the later passing snapshot. +- final-readonly-dry-run.json: actual R2 final helper's read-only result, zero writes. +- local-transfer-verification.json: deterministic archive and complete local + extraction digest/mode/symlink roundtrip, removed local temporary tree. + +Root must review/freeze the proposal/manifest digest, retain it in the existing +supervision trial, obtain the exact founder disposition and only then invoke the +--apply command. No native staging, install, launcher execution, owner change or +paid call has happened during this preparation. diff --git a/docs/changes/netkingdom-target-2026-10-17/native-runtime-install-r2/PROCESS-CONTRACT.md b/docs/changes/netkingdom-target-2026-10-17/native-runtime-install-r2/PROCESS-CONTRACT.md new file mode 100644 index 00000000..797a99a1 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/native-runtime-install-r2/PROCESS-CONTRACT.md @@ -0,0 +1,68 @@ +# Revision 2 process ownership and cleanup contract + +Proposal REINAH-WP-0008-T07-install-f599-r1, revision 2. No execution approval. +R1 is retained unchanged. No owner repository or immutable runtime is edited. + +The public artifact retains its exact f599 digest. The pinned existing +rein_aharness.owner_rehearsal.rehearse(runtime, *, run=..., bwrap_bin=...) API +already admits a Runner callback. R2 supplies that callback rather than using +the default _run, whose subprocess.run timeout only waits/kills its immediate +process. The callback passes the same owner-built readonly/empty-egress argv +with /usr/bin/bwrap and one added --die-with-parent flag to the private bounded +runner. The source hash and all three generated arrays are frozen separately. +No default owner behavior elsewhere is claimed repaired. A future owner-wide +cleanup fix is separate; no source/authority migration is made here. + +The one-action watchdog is not an installed service. Its code and private state +live only in the exact revision-2 staging directory. It is detached from the +SSH/controller session so controller SIGKILL does not prevent cleanup. It binds +the root controller with pidfd, becomes a child subreaper before spawning, and +spawns every phase plus every nested launcher itself in a distinct session. +All native job argv remain public. No shell, credentials, configurations, +provider, catalog, lease, ledger or queue is admitted to the runner. + +A private JSON request includes caller PID/start/UID, argv, deadline and capture +choice. The caller must be the root or an actual watchdog descendant. Each job +is owned/waited by the watchdog; a nested launcher is a sibling of its requesting +phase, so outer timeout must abort all owned jobs rather than merely killing +the phase process group. PR_SET_PDEATHSIG prevents pre-exec parent-loss races. +The bwrap parent-death flag is defense for its sandbox descendants if their +watchdog/bwrap parent dies; the target's 0.9.0 help/manual confirm its support. + +On timeout, root/caller loss, abandoned descendants, excess output or mapping +refusal, the watchdog stops the action. As a subreaper it adopts session-escaped +orphans. It enumerates actual PPID descendants, binds each with pidfd, checks UID +and start-time mapping, sends TERM, then KILL and reaps. It never signals by +name, guessed PID, shared session or global process group. Any uncertain mapping +fails the cleanup proof even if best-effort stopping appears complete. No +further launch can occur after that failure. New requests after abort are refused. + +The controller closes the watchdog before staging deletion and requires BOTH its +waited successful exit and quiescent=true / no_live_or_waitable_descendants=true. +Exact staging identity and inventory checks still apply. A missing/negative +receipt, stuck watchdog or unexpected object retains staging. Abrupt watchdog +loss has no independent positive quiescence proof, so cannot enable deletion. +An SSH timeout does not establish controller death or permit cleanup. + +| Event | Proof retained / allowed cleanup | +|---|---| +| Three launchers succeed and watchdog shuts down | Structured exits, full runtime rehash, waited positive quiescence; exact owned stage may be deleted | +| Phase/launcher timeout | All owned phase/nested descendants stopped/reaped first; positive proof permits only exact stage deletion; inactive artifact retained | +| Controller SIGKILL | Watchdog reacts through root pidfd, stops/reaps descendants, writes evidence; staging remains | +| Watchdog loss, uncertain mapping, missing receipt | Failed/unverified outcome, stage retained; no broad kill/delete | +| Upload failure proven before any exec | Separate conditional helper accepts only exact revision-2 before_transfer receipt/inode and four regular upload files | +| Remote exec started but SSH response lost | No retry or cleanup command; reconcile exact identities/quiescence/digest read-only and seek root recovery review | + +The five local fixture cases use actual disposable Python descendants, including +setsid escape and a nested phase-to-runner request. Controller loss uses SIGKILL. +An unrelated sibling must remain alive. Results check positive/negative cleanup +receipts and discarded application stderr. The fixture does not call bwrap, +SSH, the runtime, a provider or any native owner interface. It tests process +ownership/cleanup behavior; native compatibility remains the proposed action. + +Bounds: install phase 200 seconds / inner alarm 180; rehearsal phase 260 / inner +alarm 240; each unchanged launcher 60; output 64KiB; TERM grace 0.5 seconds; +KILL/reap 3 seconds; final watchdog wait 8 seconds. Scheduler or kernel failure +can exceed wall-clock expectations; missing proof fails closed. Host loss may +also leave the owner's independent .install-* copy. Its exact ownership cannot +be inferred from its prefix, so this packet authorizes no store sweep/removal. diff --git a/docs/changes/netkingdom-target-2026-10-17/native-runtime-install-r2/action-inputs.json b/docs/changes/netkingdom-target-2026-10-17/native-runtime-install-r2/action-inputs.json new file mode 100644 index 00000000..b2c039b5 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/native-runtime-install-r2/action-inputs.json @@ -0,0 +1,75 @@ +{ + "proposal_id": "REINAH-WP-0008-T07-install-f599-r1", + "revision": 2, + "scope": "install exact immutable artifact and credential-free native launcher rehearsal only; no provider/owner/config/catalog/queue actions", + "runtime_sha256": "sha256:f59959b605a51abd2901becde14e7abd852c2bd3f848004b51d250d1cb81af6d", + "target": "railiance01/tegwick uid1000", + "destination": "/home/tegwick/.helixforge-factory/runtimes/f59959b605a51abd2901becde14e7abd852c2bd3f848004b51d250d1cb81af6d", + "staging": "/home/tegwick/.helixforge-factory/runtime-install-f599-r2-20261017", + "archive": { + "sha256": "sha256:4c55b2740e759175d645705518fc33db30b26b4611f68e052a4ca909173084c7", + "bytes": 109931109, + "logical_file_bytes": 260668241, + "members": 1448, + "format": "gzip mtime0; PAX tar; sorted tree; root runtime; UID/GID1000; modes and relative symlinks retained" + }, + "helper_hashes": { + "execute-install.py": "sha256:44d93406ce62cc1f08ca9c7deb3eed6f45c74d61efd978f7b0acec31ba04cdc5", + "install-verified.py": "sha256:c6895881b83b3f5d5408c646040368cc5c59a99e1495fa0914b9183e087a6831", + "process_supervision.py": "sha256:4d990ee05003040e74bfdac7b2e49a3ef1512d4a054b3ff2317647b3670dd1bf", + "build-transfer.py": "sha256:99914629f354d4b6d5a4750850b32ec2cb64ac5ce18e86702d9157ea6f6b0124", + "runtime.py": "sha256:19b5fb687288bbc836978b0251599dc1e4d1593e8b5efee85a6abb6a7f388412" + }, + "source_components": { + "sandboxer_runtime_and_store": { + "revision": "221126cb77ea41ec283598a23d628f760a51bdea", + "matches_current_owner_revision": "53f800c4f7a9c91469834d04ef6f58e906b0bd49" + }, + "rein_owner_rehearsal": { + "revision": "9b88cadaa817e5abea7950b4a264d4e2739a5ddb" + } + }, + "minimum_free_disk_bytes": 2147483648, + "minimum_available_memory_bytes": 1073741824, + "cost": { + "provider_requests": 0, + "new_paid_resource_commitment": false, + "incremental_infrastructure_and_operator_eur": "unknown; explicitly supervised" + }, + "risk": { + "credible_loss_eur": "unknown; explicitly supervised", + "scope": "dormant owner-store append plus bounded local read-only namespace help/version launches; existing shared single-node host IO/CPU risk" + }, + "authority": "pending root exact proposal retention and fresh founder approval", + "maximum_cpu_busy_fraction": 0.85, + "cpu_sample_seconds": 1, + "native_executables": { + "controller": "/usr/bin/python3", + "readonly_node_client": "/usr/local/bin/kubectl", + "sandbox": "/usr/bin/bwrap" + }, + "conditional_cleanup_helper_sha256": "sha256:cec7eab2b25e4a0077ec45c055d7ba9542bc8e8724b53f2117be61c913269188", + "supervision": { + "contract": "private one-action subreaper/watchdog; pidfd-bound actual descendants only; stage removal requires waited watchdog and positive quiescence receipt", + "outer_phase_timeout_seconds": { + "install": 200, + "rehearse": 260 + }, + "inner_alarm_seconds": { + "install": 180, + "rehearse": 240 + }, + "per_launcher_timeout_seconds": 60, + "termination_grace_seconds": 0.5, + "kill_reap_seconds": 3, + "watchdog_wait_seconds": 8, + "capture_bound_bytes": 65536, + "stderr": "discarded", + "bwrap_additional_argv": [ + "--die-with-parent" + ], + "target_bwrap_version": "bubblewrap 0.9.0", + "unknown_mapping": "retain failed cleanup evidence and staging; no broad kill or delete" + }, + "frozen_native_argv_sha256": "sha256:0efb13aa725111cc227453bc7fc40eaf039c83cbd291ca7cb0409daf6b1e6c55" +} diff --git a/docs/changes/netkingdom-target-2026-10-17/native-runtime-install-r2/artifact-manifest.json b/docs/changes/netkingdom-target-2026-10-17/native-runtime-install-r2/artifact-manifest.json new file mode 100644 index 00000000..b488bd82 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/native-runtime-install-r2/artifact-manifest.json @@ -0,0 +1,117 @@ +{ + "proposal_id": "REINAH-WP-0008-T07-install-f599-r1", + "revision": 2, + "status": "pending-root-review-and-fresh-founder-approval", + "native_mutation_authorized": false, + "r1_unchanged": true, + "files": [ + { + "path": "FINAL-PROPOSAL.md", + "sha256": "sha256:44b17589c323e1a966caf6c1b1def123092ee289b929c8ea014bc84109103b1d" + }, + { + "path": "PROCESS-CONTRACT.md", + "sha256": "sha256:ed79d14bde467e8893c341419c37fa2992184597fc9015c2e7d81fb4ece63fd0" + }, + { + "path": "action-inputs.json", + "sha256": "sha256:ce7f5a25be440561f5179ae9980d85eb693a11b58d2012c8aea24b8bae04ab6f" + }, + { + "path": "build-transfer.py", + "sha256": "sha256:99914629f354d4b6d5a4750850b32ec2cb64ac5ce18e86702d9157ea6f6b0124" + }, + { + "path": "cleanup-upload-staging.py", + "sha256": "sha256:cec7eab2b25e4a0077ec45c055d7ba9542bc8e8724b53f2117be61c913269188" + }, + { + "path": "cpu-readonly-observation.json", + "sha256": "sha256:c424ecb281baf128d6c79f1e6c6f678093f9b5e9c84a3454f9891fe6197b2e95" + }, + { + "path": "executable-readonly-observation.json", + "sha256": "sha256:3ee73cdeeb4f82a55b31d19c6a24aacc4199e2e8647335d65b4e8f2e7d079c18" + }, + { + "path": "execute-install.py", + "sha256": "sha256:44d93406ce62cc1f08ca9c7deb3eed6f45c74d61efd978f7b0acec31ba04cdc5" + }, + { + "path": "final-readonly-dry-run.json", + "sha256": "sha256:17144cdb22f975212ea02a5109c94740c430d79272ef9d919ce57dec68c2d880" + }, + { + "path": "frozen-native-argv.json", + "sha256": "sha256:0efb13aa725111cc227453bc7fc40eaf039c83cbd291ca7cb0409daf6b1e6c55" + }, + { + "path": "install-verified.py", + "sha256": "sha256:c6895881b83b3f5d5408c646040368cc5c59a99e1495fa0914b9183e087a6831" + }, + { + "path": "local-bytecode-refinement.json", + "sha256": "sha256:08c92506d6abefe15aff4a9b7908ab8bee425e7792abc6095e1dd04101a2a540" + }, + { + "path": "local-transfer-check.py", + "sha256": "sha256:97fbec826d517b1746a2ec5ef67e5aab053777690977abdddc8b33ec5804e22e" + }, + { + "path": "local-transfer-verification.json", + "sha256": "sha256:2331b854389b4c15f5adce1f62aa0846e9f47dfda351a7ef166c90b5e9b2737c" + }, + { + "path": "pre-absolute-path-dry-run.json", + "sha256": "sha256:9ea47b71b8636e4beb7dadf595f1d08bde261c9986986a1335d0c00d581a6d0c" + }, + { + "path": "process-fixture-results.json", + "sha256": "sha256:fc72ce36758ea40010aeb7c4ce97c167d09784fde63eeb9b2ccaa3428dc9a831" + }, + { + "path": "process_supervision.py", + "sha256": "sha256:4d990ee05003040e74bfdac7b2e49a3ef1512d4a054b3ff2317647b3670dd1bf" + }, + { + "path": "r1-preservation.json", + "sha256": "sha256:50848ad45fda68f43e11710bb04b0793717a5d0659e3fbcf8003708ee5ccb542" + }, + { + "path": "r1-to-r2.patch", + "sha256": "sha256:63f35421b67576188ff92d920319a23aa0a6606b9a2137d1061687c77126b541" + }, + { + "path": "r2-initial-readonly-dry-run.json", + "sha256": "sha256:631c6f0d8c0f66f51509751094937fd909821d4f45a042fd77f9d10f237115b8" + }, + { + "path": "retained-headroom-refusal.json", + "sha256": "sha256:89c847b4a75f138ff2464fc8291cf36939d293a777fd41ffd41d72f96ba9a2f8" + }, + { + "path": "retained-local-source-refusal.json", + "sha256": "sha256:fdd3b584da6ebedc173ccc5f8879c42dbd821d4b98338337fbef809a403485ba" + }, + { + "path": "runtime.py", + "sha256": "sha256:19b5fb687288bbc836978b0251599dc1e4d1593e8b5efee85a6abb6a7f388412" + }, + { + "path": "target-readonly-addendum.json", + "sha256": "sha256:9588f51b353093d178b8c52892ca627c2317fab761591715a0765603a4182a8f" + }, + { + "path": "target-readonly-observation.json", + "sha256": "sha256:ba4012303e5634686208a818b221113a1a670c31ed29269d8a4cc98308616275" + }, + { + "path": "test_process_supervision.py", + "sha256": "sha256:7ea89d9dee17d6ac4b554e25c083ac43d9b94039a4bcbe411d0e2ccbfb55a180" + }, + { + "path": "transfer-archive.json", + "sha256": "sha256:3222ccd39ea968353ea5e58ec36f0e3ca35b608020444243b053074a36abfe0b" + } + ] +} diff --git a/docs/changes/netkingdom-target-2026-10-17/native-runtime-install-r2/build-transfer.py b/docs/changes/netkingdom-target-2026-10-17/native-runtime-install-r2/build-transfer.py new file mode 100644 index 00000000..3b645971 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/native-runtime-install-r2/build-transfer.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python3 +"""Deterministic public-runtime transfer; no runtime launch or network access.""" +import argparse +import gzip +import hashlib +import importlib.util +import io +import json +import os +from pathlib import Path +import stat +import tarfile + +ROOT = Path('/tmp/netkingdom-runtime-canonical-20261016/runtime') +EXPECTED = 'f59959b605a51abd2901becde14e7abd852c2bd3f848004b51d250d1cb81af6d' +HERE = Path(__file__).resolve().parent + + +class CountingHash: + def __init__(self, target=None): + self.target, self.hash, self.size = target, hashlib.sha256(), 0 + def write(self, value): + self.hash.update(value); self.size += len(value) + if self.target: self.target.write(value) + return len(value) + def flush(self): + if self.target: self.target.flush() + + +def runtime_module(): + p = HERE/'runtime.py' + spec = importlib.util.spec_from_file_location('reviewed_runtime_digest', p) + module = importlib.util.module_from_spec(spec); spec.loader.exec_module(module) + return module + + +def build(target=None): + if runtime_module().runtime_digest(ROOT) != EXPECTED: + raise ValueError('source_runtime_changed') + result = CountingHash(target); logical = 0; members = 0 + with gzip.GzipFile(filename='', mode='wb', compresslevel=6, mtime=0, fileobj=result) as stream: + with tarfile.open(fileobj=stream, mode='w|', format=tarfile.PAX_FORMAT) as archive: + for p in [ROOT, *sorted(ROOT.rglob('*'))]: + s=p.lstat(); name='runtime' + ('/'+p.relative_to(ROOT).as_posix() if p!=ROOT else '') + info=tarfile.TarInfo(name);info.uid=1000;info.gid=1000;info.mtime=0;info.mode=stat.S_IMODE(s.st_mode) + if stat.S_ISDIR(s.st_mode):info.type=tarfile.DIRTYPE + elif stat.S_ISLNK(s.st_mode): + info.type=tarfile.SYMTYPE; info.linkname=os.readlink(p) + if Path(info.linkname).is_absolute() or not p.resolve(strict=True).is_relative_to(ROOT): + raise ValueError('unsafe_runtime_symlink') + elif stat.S_ISREG(s.st_mode):info.type=tarfile.REGTYPE; info.size=s.st_size; logical += s.st_size + else:raise ValueError('runtime_special_file') + with p.open('rb') if stat.S_ISREG(s.st_mode) else io.BytesIO() as data: + archive.addfile(info,data if stat.S_ISREG(s.st_mode) else None) + members+=1 + if runtime_module().runtime_digest(ROOT) != EXPECTED: + raise ValueError('source_runtime_changed_during_archive') + return {'sha256':'sha256:'+result.hash.hexdigest(),'bytes':result.size,'logical_file_bytes':logical,'members':members, + 'format':'gzip mtime0; PAX tar; sorted tree; root runtime; UID/GID1000; modes and relative symlinks retained'} + + +def main(): + parser=argparse.ArgumentParser(description=__doc__);parser.add_argument('--output',type=Path) + args=parser.parse_args() + if args.output: + with args.output.open('xb') as stream:result=build(stream) + else:result=build() + print(json.dumps(result,sort_keys=True)) + + +if __name__=='__main__':main() diff --git a/docs/changes/netkingdom-target-2026-10-17/native-runtime-install-r2/cleanup-upload-staging.py b/docs/changes/netkingdom-target-2026-10-17/native-runtime-install-r2/cleanup-upload-staging.py new file mode 100644 index 00000000..65e34bca --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/native-runtime-install-r2/cleanup-upload-staging.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python3 +"""Conditional cleanup only when the durable receipt proves exec never started.""" +import argparse,json,shlex,subprocess +from pathlib import Path +HERE=Path(__file__).resolve().parent + +def main(): + p=argparse.ArgumentParser(description=__doc__);p.add_argument('--apply',action='store_true');args=p.parse_args() + receipt=json.loads((HERE/'execution-receipt.json').read_text()) + if not (receipt.get('status')=='staging_created' and receipt.get('phase')=='before_transfer' + and receipt.get('revision')==2 and receipt.get('proposal_id')=='REINAH-WP-0008-T07-install-f599-r1'): + raise ValueError('not_a_preexecution_upload_failure') + inode=receipt['staging_identity']['inode'] + if not args.apply: + print(json.dumps({'status':'conditional_cleanup_review','inode':inode,'native_mutations':0}));return 0 + code=r'''import json,os,shutil,stat,sys +from pathlib import Path +p=Path('/home/tegwick/.helixforge-factory/runtime-install-f599-r2-20261017');s=p.lstat() +assert os.getuid()==1000 and os.getgid()==1000 and stat.S_ISDIR(s.st_mode) and s.st_uid==1000 and s.st_gid==1000 and stat.S_IMODE(s.st_mode)==0o700 and s.st_dev==2049 and s.st_ino==int(sys.argv[1]) +assert {f.name for f in p.iterdir()} <= {'runtime.tar.gz','runtime.py','install-verified.py','process_supervision.py'} +for f in p.iterdir(): + s=f.lstat();assert stat.S_ISREG(s.st_mode) and s.st_uid==1000 and not stat.S_ISLNK(s.st_mode) +shutil.rmtree(p);print(json.dumps({'status':'owned_upload_staging_removed','absent':not p.exists()}))''' + cp=subprocess.run(['ssh','-o','BatchMode=yes','-o','ConnectTimeout=15','railiance01','/usr/bin/python3 -I -B -c '+shlex.quote(code)+' '+shlex.quote(str(inode))],capture_output=True,text=True,timeout=30) + if cp.returncode:raise RuntimeError('conditional_cleanup_refused_or_uncertain') + result=json.loads(cp.stdout);(HERE/'upload-cleanup-receipt.json').write_text(json.dumps(result,indent=2)+'\n');print(json.dumps(result));return 0 + +if __name__=='__main__': + try:raise SystemExit(main()) + except Exception as exc: + print(json.dumps({'status':'cleanup_refused_or_uncertain','failure_type':type(exc).__name__}));raise SystemExit(1) from None diff --git a/docs/changes/netkingdom-target-2026-10-17/native-runtime-install-r2/cpu-readonly-observation.json b/docs/changes/netkingdom-target-2026-10-17/native-runtime-install-r2/cpu-readonly-observation.json new file mode 100644 index 00000000..7ff59ca7 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/native-runtime-install-r2/cpu-readonly-observation.json @@ -0,0 +1 @@ +{"sample_seconds": 0.5, "cpu_busy_fraction": 0.9949748743718593} diff --git a/docs/changes/netkingdom-target-2026-10-17/native-runtime-install-r2/executable-readonly-observation.json b/docs/changes/netkingdom-target-2026-10-17/native-runtime-install-r2/executable-readonly-observation.json new file mode 100644 index 00000000..61ef674f --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/native-runtime-install-r2/executable-readonly-observation.json @@ -0,0 +1 @@ +{"python_executable": "/usr/bin/python3", "kubectl": "/usr/local/bin/kubectl", "bwrap": "/usr/bin/bwrap", "system_python_resolved": "/usr/bin/python3.12"} diff --git a/docs/changes/netkingdom-target-2026-10-17/native-runtime-install-r2/execute-install.py b/docs/changes/netkingdom-target-2026-10-17/native-runtime-install-r2/execute-install.py new file mode 100644 index 00000000..cc2968e3 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/native-runtime-install-r2/execute-install.py @@ -0,0 +1,162 @@ +#!/usr/bin/env python3 +"""Install-only orchestration. Default is read-only; --apply requires founder go.""" +import argparse +from datetime import datetime, timezone +import hashlib +import importlib.util +import json +import os +from pathlib import Path +import shlex +import subprocess +import sys +import tempfile + +HERE=Path(__file__).resolve().parent +DIGEST='f59959b605a51abd2901becde14e7abd852c2bd3f848004b51d250d1cb81af6d' +STAGE='/home/tegwick/.helixforge-factory/runtime-install-f599-r2-20261017' +STORE='/home/tegwick/.helixforge-factory/runtimes' +SOURCE=Path('/tmp/netkingdom-runtime-canonical-20261016/runtime') + +READ_TARGET=r'''import json,os,pwd,stat,subprocess,shutil,time,ctypes,gzip +from pathlib import Path +store=Path('/home/tegwick/.helixforge-factory/runtimes'); stage=Path('/home/tegwick/.helixforge-factory/runtime-install-f599-r2-20261017');digest='f59959b605a51abd2901becde14e7abd852c2bd3f848004b51d250d1cb81af6d' +def meta(p): + try: + s=p.lstat();return {'uid':s.st_uid,'gid':s.st_gid,'mode':oct(stat.S_IMODE(s.st_mode)),'device':s.st_dev,'inode':s.st_ino,'directory':stat.S_ISDIR(s.st_mode),'symlink':stat.S_ISLNK(s.st_mode)} + except FileNotFoundError:return None +cp=subprocess.run(['/usr/local/bin/kubectl','get','nodes','-o','json'],capture_output=True,timeout=20) +assert cp.returncode==0 +nodes=json.loads(cp.stdout)['items'];assert len(nodes)==1 +mem=dict(x.split(':',1) for x in Path('/proc/meminfo').read_text().splitlines()) +read_cpu=lambda:[int(x) for x in Path('/proc/stat').read_text().splitlines()[0].split()[1:9]] +a=read_cpu();time.sleep(1);b=read_cpu();d=[y-x for x,y in zip(a,b)];busy=1-(d[3]+d[4])/sum(d) +help_result=subprocess.run(['/usr/bin/bwrap','--help'],stdout=subprocess.PIPE,stderr=subprocess.DEVNULL,timeout=10) +version=subprocess.run(['/usr/bin/bwrap','--version'],stdout=subprocess.PIPE,stderr=subprocess.DEVNULL,timeout=10) +manual=gzip.decompress(Path('/usr/share/man/man1/bwrap.1.gz').read_bytes()).decode();i=manual.find('die\\-with\\-parent') +fd=os.pidfd_open(os.getpid());os.close(fd);value=ctypes.c_int();subreaper_get=ctypes.CDLL(None).prctl(37,ctypes.byref(value),0,0,0) +print(json.dumps({'bwrap_version':version.stdout.decode().strip(),'bwrap_die_with_parent_supported':help_result.returncode==0 and b'--die-with-parent' in help_result.stdout,'primary_manual_contract_excerpt':manual[max(0,i-20):i+430] if i>=0 else 'absent','pidfd_available':True,'subreaper_get_supported':subreaper_get==0,'account':pwd.getpwuid(os.getuid()).pw_name,'uid':os.getuid(),'gid':os.getgid(),'store':meta(store),'destination':meta(store/digest),'stage':meta(stage),'memory_available_bytes':int(mem['MemAvailable'].split()[0])*1024,'disk_free_bytes':shutil.disk_usage(store).free,'load_average':list(os.getloadavg()),'cpu_count':os.cpu_count(),'cpu_busy_fraction':busy,'cpu_sample_seconds':1,'node_addresses':nodes[0]['status']['addresses'],'node_ready':any(c['type']=='Ready' and c['status']=='True' for c in nodes[0]['status']['conditions'])}))''' + + +def sha(path): + with path.open('rb') as stream:return 'sha256:'+hashlib.file_digest(stream,'sha256').hexdigest() + + +def command(argv,timeout=60): + cp=subprocess.run(argv,stdout=subprocess.PIPE,stderr=subprocess.DEVNULL,timeout=timeout) + if cp.returncode:raise RuntimeError('command_failed') + return cp.stdout + + +def ssh(code,args=(),timeout=60): + remote='/usr/bin/python3 -I -B -c '+shlex.quote(code) + if args:remote+=' '+' '.join(shlex.quote(str(x)) for x in args) + return json.loads(command(['ssh','-o','BatchMode=yes','-o','ConnectTimeout=15','railiance01',remote],timeout)) + + +def module(name,path): + spec=importlib.util.spec_from_file_location(name,path) + result=importlib.util.module_from_spec(spec);spec.loader.exec_module(result);return result + + +def preflight(): + inputs=json.loads((HERE/'action-inputs.json').read_text()) + for name,expected in inputs['helper_hashes'].items(): + if sha(HERE/name)!=expected:raise ValueError('helper_changed') + if module('reviewed_runtime_reader',HERE/'runtime.py').runtime_digest(SOURCE)!=DIGEST: + raise ValueError('source_changed') + observation=ssh(READ_TARGET) + store=observation['store'] + expected=json.loads((HERE/'target-readonly-observation.json').read_text())['paths'][STORE] + checks={ + 'bwrap_parent_death_contract':observation['bwrap_die_with_parent_supported'] and observation['bwrap_version']=='bubblewrap 0.9.0' and 'PR_SET_PDEATHSIG' in observation['primary_manual_contract_excerpt'], + 'supervision_primitives':observation['pidfd_available'] and observation['subreaper_get_supported'], + 'account':observation['account']=='tegwick' and observation['uid']==1000 and observation['gid']==1000, + 'protected_store':store['uid']==1000 and store['gid']==1000 and store['mode']=='0o700' and store['directory'] and not store['symlink'] and store['device']==expected['device'] and store['inode']==expected['inode'], + 'destination_absent':observation['destination'] is None, + 'staging_absent':observation['stage'] is None, + 'exact_ready_node':observation['node_ready'] and any(x['address']=='92.205.62.239' for x in observation['node_addresses']), + 'disk_headroom':observation['disk_free_bytes']>=2*1024**3, + 'memory_headroom':observation['memory_available_bytes']>=1024**3, + 'load_headroom':observation['load_average'][0]<=2*observation['cpu_count'], + 'cpu_headroom':observation['cpu_busy_fraction']<=0.85, + } + observation['checks']=checks + return inputs,observation + + +def save(path,value): + fd=os.open(path,os.O_WRONLY|os.O_CREAT|os.O_EXCL|os.O_NOFOLLOW,0o600) + with os.fdopen(fd,'w') as stream:json.dump(value,stream,indent=2);stream.write('\n') + + +def main(): + parser=argparse.ArgumentParser(description=__doc__) + parser.add_argument('--apply',action='store_true');parser.add_argument('--dry-run',action='store_true') + args=parser.parse_args() + if args.apply and args.dry_run:raise ValueError('conflicting_modes') + inputs,observation=preflight() + if not args.apply: + report={'status':'read_only_dry_run_passed' if all(observation['checks'].values()) else 'read_only_dry_run_blocked','proposal_id':inputs['proposal_id'],'revision':2, + 'observed_at':datetime.now(timezone.utc).isoformat(),'target':observation, + 'source_runtime_complete_digest_verified':True,'archive':inputs['archive'], + 'remote_mutations':0,'provider_calls':0,'private_configuration_reads':False, + 'next_exact_command':'python3 -I -B '+str(HERE/'execute-install.py')+' --apply'} + print(json.dumps(report,sort_keys=True));return 0 if all(observation['checks'].values()) else 2 + if not all(observation['checks'].values()):raise ValueError('target_headroom_or_identity_refused') + receipt=HERE/'execution-receipt.json' + if receipt.exists():raise ValueError('prior_attempt_requires_reconciliation') + save(receipt,{'status':'intent_recorded','proposal_id':inputs['proposal_id'],'revision':2, + 'automatic_retry':False,'observed_at':datetime.now(timezone.utc).isoformat()}) + # No native attempt is retried by this helper. Intent survives an SSH loss. + with tempfile.TemporaryDirectory(prefix='nk-runtime-install-r2-') as temporary: + archive=Path(temporary)/'runtime.tar.gz' + with archive.open('xb') as stream:built=module('reviewed_transfer',HERE/'build-transfer.py').build(stream) + if built!=inputs['archive']:raise ValueError('archive_changed') + archive.chmod(0o600) + create=r'''import json,os,stat,time +from pathlib import Path +assert os.getuid()==1000 and os.getgid()==1000 +store=Path('/home/tegwick/.helixforge-factory/runtimes');s=store.lstat() +assert stat.S_ISDIR(s.st_mode) and s.st_uid==1000 and stat.S_IMODE(s.st_mode)==0o700 and s.st_ino==4751222 and s.st_dev==2049 +assert not (store/'f59959b605a51abd2901becde14e7abd852c2bd3f848004b51d250d1cb81af6d').exists() +read_cpu=lambda:[int(x) for x in Path('/proc/stat').read_text().splitlines()[0].split()[1:9]] +a=read_cpu();time.sleep(1);b=read_cpu();d=[y-x for x,y in zip(a,b)];assert 1-(d[3]+d[4])/sum(d)<=0.85 +stage=Path('/home/tegwick/.helixforge-factory/runtime-install-f599-r2-20261017');stage.mkdir(mode=0o700) +s=stage.lstat();print(json.dumps({'inode':s.st_ino,'device':s.st_dev}))''' + created=ssh(create) + receipt.write_text(json.dumps({'status':'staging_created','phase':'before_transfer','proposal_id':inputs['proposal_id'],'revision':2,'automatic_retry':False,'staging_identity':created,'staging_path':STAGE},indent=2)+'\n') + command(['scp','-q',str(archive),str(HERE/'runtime.py'),str(HERE/'install-verified.py'),str(HERE/'process_supervision.py'),'railiance01:'+STAGE+'/'],120) + execute=r'''import hashlib,json,os,stat,sys +from pathlib import Path +stage=Path('/home/tegwick/.helixforge-factory/runtime-install-f599-r2-20261017');s=stage.lstat() +assert stat.S_ISDIR(s.st_mode) and s.st_uid==1000 and stat.S_IMODE(s.st_mode)==0o700 and s.st_ino==int(sys.argv[1]) and s.st_dev==2049 +expected=json.loads(sys.argv[2]);assert {p.name for p in stage.iterdir()}==set(expected) +for name,want in expected.items(): + p=stage/name;s=p.lstat();assert stat.S_ISREG(s.st_mode) and s.st_uid==1000 and not stat.S_ISLNK(s.st_mode) + with p.open('rb') as stream:assert hashlib.file_digest(stream,'sha256').hexdigest()==want + p.chmod(0o600) +os.execve('/usr/bin/python3',['python3','-I','-B',str(stage/'install-verified.py'),'--stage-inode',sys.argv[1]],{'HOME':'/home/tegwick','PATH':'/usr/bin:/bin','LANG':'C.UTF-8','PYTHONDONTWRITEBYTECODE':'1'})''' + hashes={'runtime.tar.gz':inputs['archive']['sha256'].removeprefix('sha256:'), + 'runtime.py':inputs['helper_hashes']['runtime.py'].removeprefix('sha256:'), + 'install-verified.py':inputs['helper_hashes']['install-verified.py'].removeprefix('sha256:'), + 'process_supervision.py':inputs['helper_hashes']['process_supervision.py'].removeprefix('sha256:')} + # Parse the structured final helper return even when its action failed. + remote='/usr/bin/python3 -I -B -c '+shlex.quote(execute)+' '+shlex.quote(str(created['inode']))+' '+shlex.quote(json.dumps(hashes,separators=(',',':'))) + receipt.write_text(json.dumps({'status':'remote_execution_started','proposal_id':inputs['proposal_id'],'revision':2,'automatic_retry':False,'staging_identity':created,'staging_path':STAGE},indent=2)+'\n') + cp=subprocess.run(['ssh','-o','BatchMode=yes','-o','ConnectTimeout=15','railiance01',remote],stdout=subprocess.PIPE,stderr=subprocess.DEVNULL,timeout=600) + try:result=json.loads(cp.stdout) + except Exception:raise RuntimeError('remote_outcome_uncertain') from None + result['ssh_exit_code']=cp.returncode;result['staging_identity']=created + # Replace only our exact local intent receipt, never a previous attempt. + receipt.write_text(json.dumps(result,indent=2)+'\n');receipt.chmod(0o600) + print(json.dumps(result,sort_keys=True)) + return 0 if cp.returncode==0 and result.get('status')=='installed_and_offline_rehearsal_verified' else 1 + + +if __name__=='__main__': + try:raise SystemExit(main()) + except Exception as exc: + print(json.dumps({'status':'failed_or_uncertain','failure_type':type(exc).__name__, + 'automatic_retry':False,'private_diagnostics_suppressed':True})) + raise SystemExit(1) from None diff --git a/docs/changes/netkingdom-target-2026-10-17/native-runtime-install-r2/execution-receipt.json b/docs/changes/netkingdom-target-2026-10-17/native-runtime-install-r2/execution-receipt.json new file mode 100644 index 00000000..12c70e56 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/native-runtime-install-r2/execution-receipt.json @@ -0,0 +1,43 @@ +{ + "credential_reads": false, + "destination": "/home/tegwick/.helixforge-factory/runtimes/f59959b605a51abd2901becde14e7abd852c2bd3f848004b51d250d1cb81af6d", + "destination_exists": true, + "extracted_complete_digest_verified": true, + "failure_code": "phase_receipt_unavailable", + "failure_type": "ValueError", + "installation": { + "result": { + "credential_delivery_configured": false, + "owner_uid": 1000, + "profile_activated": false, + "reused": false, + "runtime": { + "path": "/home/tegwick/.helixforge-factory/runtimes/f59959b605a51abd2901becde14e7abd852c2bd3f848004b51d250d1cb81af6d", + "sha256": "f59959b605a51abd2901becde14e7abd852c2bd3f848004b51d250d1cb81af6d" + }, + "store_mode": "0700" + }, + "status": "installed" + }, + "installed_complete_digest_verified": true, + "model_calls": 0, + "owned_staging_removed": true, + "owner_configuration_read": false, + "phase": "offline_rehearsal", + "process_supervision": { + "no_live_or_waitable_descendants": true, + "process_values_emitted": false, + "quiescent": true, + "reason": "leader_left_descendants", + "stderr_suppressed": true + }, + "proposal_id": "REINAH-WP-0008-T07-install-f599-r1", + "renewal_or_catalog_or_queue_mutation": false, + "revision": 2, + "status": "failed", + "ssh_exit_code": 1, + "staging_identity": { + "inode": 4723175, + "device": 2049 + } +} diff --git a/docs/changes/netkingdom-target-2026-10-17/native-runtime-install-r2/final-readonly-dry-run.json b/docs/changes/netkingdom-target-2026-10-17/native-runtime-install-r2/final-readonly-dry-run.json new file mode 100644 index 00000000..d531d2f4 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/native-runtime-install-r2/final-readonly-dry-run.json @@ -0,0 +1 @@ +{"archive": {"bytes": 109931109, "format": "gzip mtime0; PAX tar; sorted tree; root runtime; UID/GID1000; modes and relative symlinks retained", "logical_file_bytes": 260668241, "members": 1448, "sha256": "sha256:4c55b2740e759175d645705518fc33db30b26b4611f68e052a4ca909173084c7"}, "next_exact_command": "python3 -I -B /home/worsch/the-custodian/docs/changes/netkingdom-target-2026-10-17/native-runtime-install-r2/execute-install.py --apply", "observed_at": "2026-10-17T06:01:35.675995+00:00", "private_configuration_reads": false, "proposal_id": "REINAH-WP-0008-T07-install-f599-r1", "provider_calls": 0, "remote_mutations": 0, "revision": 2, "source_runtime_complete_digest_verified": true, "status": "read_only_dry_run_passed", "target": {"account": "tegwick", "bwrap_die_with_parent_supported": true, "bwrap_version": "bubblewrap 0.9.0", "checks": {"account": true, "bwrap_parent_death_contract": true, "cpu_headroom": true, "destination_absent": true, "disk_headroom": true, "exact_ready_node": true, "load_headroom": true, "memory_headroom": true, "protected_store": true, "staging_absent": true, "supervision_primitives": true}, "cpu_busy_fraction": 0.28316326530612246, "cpu_count": 4, "cpu_sample_seconds": 1, "destination": null, "disk_free_bytes": 123352678400, "gid": 1000, "load_average": [1.96337890625, 2.81396484375, 2.62744140625], "memory_available_bytes": 7735549952, "node_addresses": [{"address": "92.205.62.239", "type": "InternalIP"}, {"address": "2a00:1169:111:6d70::", "type": "InternalIP"}, {"address": "239.62.205.92.host.secureserver.net", "type": "Hostname"}], "node_ready": true, "pidfd_available": true, "primary_manual_contract_excerpt": ")\\&.\n.RE\n.PP\n\\fB\\-\\-die\\-with\\-parent\\fR\n.RS 4\nEnsures child process (COMMAND) dies when bwrap\\*(Aqs parent dies\\&. Kills (SIGKILL) all bwrap sandbox processes in sequence from parent to child including COMMAND process when bwrap or bwrap\\*(Aqs parent dies\\&. See prctl, PR_SET_PDEATHSIG\\&.\n.RE\n.PP\n\\fB\\-\\-as\\-pid\\-1\\fR\n.RS 4\nDo not create a process with PID=1 in the sandbox to reap child processes\\&.\n.RE\n.PP\n\\fB\\-\\-cap\\-add \\fR\\fBCAP\\fR\n.RS 4\nAdd ", "stage": null, "store": {"device": 2049, "directory": true, "gid": 1000, "inode": 4751222, "mode": "0o700", "symlink": false, "uid": 1000}, "subreaper_get_supported": true, "uid": 1000}} diff --git a/docs/changes/netkingdom-target-2026-10-17/native-runtime-install-r2/frozen-native-argv.json b/docs/changes/netkingdom-target-2026-10-17/native-runtime-install-r2/frozen-native-argv.json new file mode 100644 index 00000000..fc14c451 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/native-runtime-install-r2/frozen-native-argv.json @@ -0,0 +1,181 @@ +{ + "source_api": "owner_rehearsal.rehearse(runtime, run=bounded_run, bwrap_bin=/usr/bin/bwrap)", + "source_sha256": "sha256:192f654cad4a5f065c7faa5e35b03493297a472e8d7fe641be2c42c5fb00dcc3", + "captured_using_existing_runner_seam": true, + "launcher_executions": 0, + "steps": [ + { + "argv": [ + "/usr/bin/bwrap", + "--die-with-parent", + "--unshare-user", + "--unshare-pid", + "--unshare-ipc", + "--unshare-uts", + "--unshare-cgroup", + "--unshare-net", + "--tmpfs", + "/", + "--proc", + "/proc", + "--dev", + "/dev", + "--clearenv", + "--ro-bind", + "/usr", + "/usr", + "--ro-bind", + "/bin", + "/bin", + "--ro-bind", + "/lib", + "/lib", + "--ro-bind", + "/lib64", + "/lib64", + "--ro-bind", + "/etc/resolv.conf", + "/etc/resolv.conf", + "--ro-bind", + "/etc/ssl/certs", + "/etc/ssl/certs", + "--dir", + "/opt", + "--dir", + "/opt/sandboxer", + "--ro-bind", + "/home/tegwick/.helixforge-factory/runtimes/f59959b605a51abd2901becde14e7abd852c2bd3f848004b51d250d1cb81af6d", + "/opt/sandboxer/runtime", + "--dir", + "/tmp", + "--setenv", + "HOME", + "/tmp", + "--setenv", + "PATH", + "/opt/sandboxer/runtime/bin:/usr/bin:/bin", + "--chdir", + "/tmp", + "/opt/sandboxer/runtime/bin/rein-aharness", + "--help" + ], + "timeout_seconds": 60 + }, + { + "argv": [ + "/usr/bin/bwrap", + "--die-with-parent", + "--unshare-user", + "--unshare-pid", + "--unshare-ipc", + "--unshare-uts", + "--unshare-cgroup", + "--unshare-net", + "--tmpfs", + "/", + "--proc", + "/proc", + "--dev", + "/dev", + "--clearenv", + "--ro-bind", + "/usr", + "/usr", + "--ro-bind", + "/bin", + "/bin", + "--ro-bind", + "/lib", + "/lib", + "--ro-bind", + "/lib64", + "/lib64", + "--ro-bind", + "/etc/resolv.conf", + "/etc/resolv.conf", + "--ro-bind", + "/etc/ssl/certs", + "/etc/ssl/certs", + "--dir", + "/opt", + "--dir", + "/opt/sandboxer", + "--ro-bind", + "/home/tegwick/.helixforge-factory/runtimes/f59959b605a51abd2901becde14e7abd852c2bd3f848004b51d250d1cb81af6d", + "/opt/sandboxer/runtime", + "--dir", + "/tmp", + "--setenv", + "HOME", + "/tmp", + "--setenv", + "PATH", + "/opt/sandboxer/runtime/bin:/usr/bin:/bin", + "--chdir", + "/tmp", + "/opt/sandboxer/runtime/bin/glas-harness", + "--help" + ], + "timeout_seconds": 60 + }, + { + "argv": [ + "/usr/bin/bwrap", + "--die-with-parent", + "--unshare-user", + "--unshare-pid", + "--unshare-ipc", + "--unshare-uts", + "--unshare-cgroup", + "--unshare-net", + "--tmpfs", + "/", + "--proc", + "/proc", + "--dev", + "/dev", + "--clearenv", + "--ro-bind", + "/usr", + "/usr", + "--ro-bind", + "/bin", + "/bin", + "--ro-bind", + "/lib", + "/lib", + "--ro-bind", + "/lib64", + "/lib64", + "--ro-bind", + "/etc/resolv.conf", + "/etc/resolv.conf", + "--ro-bind", + "/etc/ssl/certs", + "/etc/ssl/certs", + "--dir", + "/opt", + "--dir", + "/opt/sandboxer", + "--ro-bind", + "/home/tegwick/.helixforge-factory/runtimes/f59959b605a51abd2901becde14e7abd852c2bd3f848004b51d250d1cb81af6d", + "/opt/sandboxer/runtime", + "--dir", + "/tmp", + "--setenv", + "HOME", + "/tmp", + "--setenv", + "PATH", + "/opt/sandboxer/runtime/bin:/usr/bin:/bin", + "--chdir", + "/tmp", + "/opt/sandboxer/runtime/bin/claude", + "--version" + ], + "timeout_seconds": 60 + } + ], + "runtime_source_file_unchanged": true, + "complete_runtime_digest_verified_after_bytecode_refinement": true +} diff --git a/docs/changes/netkingdom-target-2026-10-17/native-runtime-install-r2/install-verified.py b/docs/changes/netkingdom-target-2026-10-17/native-runtime-install-r2/install-verified.py new file mode 100644 index 00000000..85214fdf --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/native-runtime-install-r2/install-verified.py @@ -0,0 +1,239 @@ +#!/usr/bin/env python3 +"""Exact install-only action; execute remotely only after founder approval.""" +import argparse +import hashlib +import importlib.util +import json +import os +from pathlib import Path, PurePosixPath +import pwd +import shutil +import signal +import stat +import subprocess +import sys +import tarfile +import time + +DIGEST = 'f59959b605a51abd2901becde14e7abd852c2bd3f848004b51d250d1cb81af6d' +ARCHIVE = '4c55b2740e759175d645705518fc33db30b26b4611f68e052a4ca909173084c7' +RUNTIME_MODULE = '19b5fb687288bbc836978b0251599dc1e4d1593e8b5efee85a6abb6a7f388412' +STORE_MODULE = 'c3d6ec09d08881611d3d02b8f55d68deed6ecfedaa1a809b6b11c57cc4ca97cf' +REHEARSAL_MODULE = '192f654cad4a5f065c7faa5e35b03493297a472e8d7fe641be2c42c5fb00dcc3' +STAGE = Path('/home/tegwick/.helixforge-factory/runtime-install-f599-r2-20261017') +STORE = Path('/home/tegwick/.helixforge-factory/runtimes') +DESTINATION = STORE/DIGEST +LOGICAL_BYTES = 260668241 +ARCHIVE_BYTES = 109931109 +MEMBERS = 1448 +ENV = {'HOME':'/home/tegwick','PATH':'/usr/bin:/bin','LANG':'C.UTF-8','PYTHONDONTWRITEBYTECODE':'1'} + + +def require(value, code): + if not value: raise ValueError(code) + + +def file_digest(path): + with path.open('rb') as source:return hashlib.file_digest(source,'sha256').hexdigest() + + +def protected(path, *, directory=False, mode=None): + s=path.lstat() + require(not stat.S_ISLNK(s.st_mode) and s.st_uid==1000 and s.st_gid==1000,'path_ownership') + require(stat.S_ISDIR(s.st_mode) if directory else stat.S_ISREG(s.st_mode),'path_type') + require(not stat.S_IMODE(s.st_mode)&0o022,'path_write_mode') + if mode is not None:require(stat.S_IMODE(s.st_mode)==mode,'path_exact_mode') + return s + + +def identify(supervisor): + require(os.getuid()==1000 and os.getgid()==1000 and pwd.getpwuid(1000).pw_name=='tegwick','account_identity') + for p in (Path('/home/tegwick'),Path('/home/tegwick/.helixforge-factory'),STORE): + protected(p,directory=True,mode=0o700 if p!=Path('/home/tegwick') else 0o750) + protected(STORE/'.install.lock',mode=0o600) + code,output=supervisor.run(['/usr/local/bin/kubectl','get','nodes','-o','json'],20,capture=True) + require(code==0,'node_readback') + nodes=json.loads(output)['items'] + require(len(nodes)==1 and any(a['address']=='92.205.62.239' for a in nodes[0]['status']['addresses']) + and any(c['type']=='Ready' and c['status']=='True' for c in nodes[0]['status']['conditions']),'node_identity') + require(shutil.disk_usage(STORE).free >= 2*1024**3,'disk_headroom') + mem=dict(x.split(':',1) for x in Path('/proc/meminfo').read_text().splitlines()) + require(int(mem['MemAvailable'].split()[0])*1024>=1024**3,'memory_headroom') + require(os.getloadavg()[0]<=2*(os.cpu_count() or 1),'load_headroom') + read_cpu=lambda:[int(x) for x in Path('/proc/stat').read_text().splitlines()[0].split()[1:9]] + a=read_cpu();time.sleep(1);b=read_cpu();d=[y-x for x,y in zip(a,b)] + require(1-(d[3]+d[4])/sum(d)<=0.85,'cpu_headroom') + + +def runtime_reader(): + p=STAGE/'runtime.py';protected(p,mode=0o600) + require(file_digest(p)==RUNTIME_MODULE,'runtime_reader_pin') + spec=importlib.util.spec_from_file_location('approved_runtime_reader',p) + module=importlib.util.module_from_spec(spec);spec.loader.exec_module(module) + return module + + +def extract(): + archive=STAGE/'runtime.tar.gz';protected(archive,mode=0o600) + require(archive.stat().st_size==ARCHIVE_BYTES and file_digest(archive)==ARCHIVE,'archive_pin') + root=STAGE/'runtime';require(not root.exists() and not root.is_symlink(),'extraction_already_present') + with tarfile.open(archive,mode='r:gz') as tf: + members=tf.getmembers();require(len(members)==MEMBERS,'archive_member_count') + seen=set(); logical=0 + for info in members: + name=PurePosixPath(info.name) + require(not name.is_absolute() and name.parts and name.parts[0]=='runtime' + and all(x not in ('','..','.') for x in name.parts),'archive_name') + require(info.name not in seen,'archive_duplicate');seen.add(info.name) + require(info.uid==1000 and info.gid==1000 and (info.issym() or not info.mode&0o7022),'archive_modes') + require(info.isdir() or info.isfile() or info.issym(),'archive_special_member') + if info.isfile():logical+=info.size + if info.issym():require(not PurePosixPath(info.linkname).is_absolute(),'archive_absolute_symlink') + require(logical==LOGICAL_BYTES,'archive_size') + # Populate directories and files before any symlink; never traverse an + # archive-created symlink while extracting a later member. + dirs=[] + for info in members: + if not info.isdir():continue + p=STAGE/info.name;p.mkdir(mode=0o700);dirs.append((p,info.mode)) + for info in members: + if not info.isfile():continue + p=STAGE/info.name + require(all(not x.is_symlink() for x in (p.parent,*p.parent.parents)),'archive_parent_alias') + fd=os.open(p,os.O_WRONLY|os.O_CREAT|os.O_EXCL|os.O_NOFOLLOW,0o600) + with os.fdopen(fd,'wb') as target, tf.extractfile(info) as source: + shutil.copyfileobj(source,target,1024*1024) + p.chmod(info.mode) + for info in members: + if info.issym(): + p=STAGE/info.name;p.symlink_to(info.linkname) + require(p.resolve(strict=True).is_relative_to(root),'archive_symlink_escape') + for p,mode in reversed(dirs):p.chmod(mode) + require(runtime_reader().runtime_digest(root)==DIGEST,'extracted_complete_digest') + return root + + +def expired(signum, frame): + raise TimeoutError('bounded_stage_deadline') + + +def install_phase(): + from sandboxer.extensions import runtime_store, runtime + source=STAGE/'runtime' + require(Path(runtime_store.__file__).resolve().is_relative_to(source) + and file_digest(Path(runtime_store.__file__))==STORE_MODULE,'installer_source_pin') + require(Path(runtime.__file__).resolve().is_relative_to(source) + and file_digest(Path(runtime.__file__))==RUNTIME_MODULE,'installed_digest_source_pin') + require(not DESTINATION.exists() and not DESTINATION.is_symlink(),'destination_not_absent') + signal.signal(signal.SIGALRM,expired);signal.alarm(180) + try:result=runtime_store.install_runtime(source,STORE,DIGEST) + finally:signal.alarm(0) + require(result['runtime']['path']==str(DESTINATION) and not result['reused'] + and result['profile_activated'] is False and result['credential_delivery_configured'] is False,'installer_result') + print(json.dumps({'status':'installed','result':result},sort_keys=True)) + + +def rehearse_phase(supervision): + from rein_aharness import owner_rehearsal + require(Path(owner_rehearsal.__file__).resolve().is_relative_to(DESTINATION) + and file_digest(Path(owner_rehearsal.__file__))==REHEARSAL_MODULE,'rehearsal_source_pin') + require(owner_rehearsal.SYSTEM_RO_BINDS==('/usr','/bin','/lib','/lib64','/etc/resolv.conf','/etc/ssl/certs') + and all(Path(p).exists() for p in owner_rehearsal.SYSTEM_RO_BINDS),'frozen_system_bind_contract') + signal.signal(signal.SIGALRM,expired);signal.alarm(240) + # Keep the frozen owner launch contract; use its supported Runner seam. + def bounded_run(argv,timeout): + require(argv[0]=='/usr/bin/bwrap' and '--die-with-parent' not in argv,'bwrap_runner_contract') + return supervision_request(supervision,[argv[0],'--die-with-parent',*argv[1:]],timeout)[0] + try:steps=owner_rehearsal.rehearse(DESTINATION,run=bounded_run,bwrap_bin='/usr/bin/bwrap') + finally:signal.alarm(0) + require([x.name for x in steps]==['rein-aharness','glas-harness','claude'],'rehearsal_steps') + report={x.name:x.exit_code for x in steps} + print(json.dumps({'status':'rehearsed' if all(x.ok for x in steps) else 'rehearsal_failed','steps':report, + 'model_calls':0,'credential_reads':False,'owner_configuration_read':False},sort_keys=True)) + return 0 if all(x.ok for x in steps) else 1 + + +def supervision_module(): + spec=importlib.util.spec_from_file_location('approved_process_supervision',STAGE/'process_supervision.py') + module=importlib.util.module_from_spec(spec);spec.loader.exec_module(module) + return module + + +def supervision_request(directory,argv,timeout): + return supervision_module().request(directory,argv,timeout) + + +def phase(supervisor, argv, timeout): + code,output=supervisor.run(argv,timeout,capture=True) + try:result=json.loads(output) + except Exception:raise ValueError('phase_receipt_unavailable') from None + return code,result + + +def main(): + parser=argparse.ArgumentParser(description=__doc__) + parser.add_argument('--stage-inode',type=int) + parser.add_argument('--phase',choices=('install','rehearse')) + parser.add_argument('--supervision-dir') + args=parser.parse_args() + if args.phase=='install':install_phase();return 0 + if args.phase=='rehearse': + require(args.supervision_dir==str(STAGE/'supervision'),'supervision_path') + return rehearse_phase(args.supervision_dir) + receipt={'proposal_id':'REINAH-WP-0008-T07-install-f599-r1','revision':2,'status':'failed', + 'model_calls':0,'credential_reads':False,'owner_configuration_read':False, + 'renewal_or_catalog_or_queue_mutation':False,'destination':str(DESTINATION)} + identity=None;supervisor=None;quiescent=False + try: + observed=protected(STAGE,directory=True,mode=0o700) + require(observed.st_ino==args.stage_inode and observed.st_dev==2049,'stage_identity') + identity=observed + os.nice(19) + supervisor=supervision_module().Supervisor(STAGE/'supervision') + identify(supervisor) + require(not DESTINATION.exists() and not DESTINATION.is_symlink(),'destination_not_absent') + require({p.name for p in STAGE.iterdir()}=={'runtime.tar.gz','runtime.py','install-verified.py','process_supervision.py','supervision'},'stage_inventory') + receipt['phase']='extract_and_verify';source=extract() + receipt['extracted_complete_digest_verified']=True + receipt['phase']='install' + code,result=phase(supervisor,[str(source/'bin/python3'),'-I','-B',str(STAGE/'install-verified.py'),'--phase','install'],200) + receipt['installation']=result;require(code==0 and result['status']=='installed','installation_failed') + require(runtime_reader().runtime_digest(DESTINATION)==DIGEST,'installed_complete_digest') + receipt['installed_complete_digest_verified']=True + receipt['phase']='offline_rehearsal' + code,result=phase(supervisor,[str(DESTINATION/'bin/python3'),'-I','-B',str(STAGE/'install-verified.py'),'--phase','rehearse','--supervision-dir',str(STAGE/'supervision')],260) + receipt['rehearsal']=result;require(code==0 and result['status']=='rehearsed','rehearsal_failed') + require(runtime_reader().runtime_digest(DESTINATION)==DIGEST,'post_rehearsal_complete_digest') + receipt['post_rehearsal_complete_digest_verified']=True + receipt['status']='installed_and_offline_rehearsal_verified' + except Exception as exc: + receipt['failure_type']=type(exc).__name__ + if isinstance(exc,ValueError) and str(exc).replace('_','').isalnum():receipt['failure_code']=str(exc) + finally: + receipt['destination_exists']=DESTINATION.exists() or DESTINATION.is_symlink() + if supervisor is not None: + try: + receipt['process_supervision']=supervisor.close();quiescent=True + except Exception: + receipt['process_supervision']={'quiescent':False,'status':'cleanup_unverified'} + receipt['status']='failed' + if identity is not None and quiescent: + try: + current=protected(STAGE,directory=True,mode=0o700) + require((current.st_dev,current.st_ino)==(identity.st_dev,identity.st_ino),'cleanup_stage_identity') + require({p.name for p in STAGE.iterdir()} <= {'runtime.tar.gz','runtime.py','install-verified.py','process_supervision.py','runtime','supervision'},'cleanup_unexpected_stage_member') + shutil.rmtree(STAGE) + receipt['owned_staging_removed']=not STAGE.exists() and not STAGE.is_symlink() + except Exception:receipt['owned_staging_removed']=False;receipt['status']='failed' + else: + receipt['owned_staging_removed']=False + receipt['staging_retained_for_quiescence_review']=True + print(json.dumps(receipt,sort_keys=True)) + return 0 if receipt['status']=='installed_and_offline_rehearsal_verified' else 1 + + +if __name__=='__main__': + try:raise SystemExit(main()) + except Exception as exc: + print(json.dumps({'status':'failed','failure_type':type(exc).__name__,'private_diagnostics_suppressed':True})) + raise SystemExit(1) from None diff --git a/docs/changes/netkingdom-target-2026-10-17/native-runtime-install-r2/local-bytecode-refinement.json b/docs/changes/netkingdom-target-2026-10-17/native-runtime-install-r2/local-bytecode-refinement.json new file mode 100644 index 00000000..d92c3941 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/native-runtime-install-r2/local-bytecode-refinement.json @@ -0,0 +1,14 @@ +{ + "status": "failed preparation retained; exact original artifact restored", + "cause": "owner argv capture import omitted bytecode suppression, creating one local pyc; preflight refused source_changed before any target call", + "removed_only_newly_generated_bytecode": { + "path": "/tmp/netkingdom-runtime-canonical-20261016/runtime/lib/python3.12/site-packages/rein_aharness/__pycache__/owner_rehearsal.cpython-312.pyc", + "sha256": "sha256:c25d9ab3cc87fe2d91fdfe6397783d188efabddaa833bbf4dc1222fb8e8a6a45", + "bytes": 4810, + "mtime_ns": 1792216762800164055 + }, + "removed_only_new_empty_parent": true, + "restored_complete_runtime_digest": "sha256:f59959b605a51abd2901becde14e7abd852c2bd3f848004b51d250d1cb81af6d", + "target_mutations": 0, + "refinement": "all subsequent artifact inspection uses python3 -B; no artifact source bytes/modes modified" +} diff --git a/docs/changes/netkingdom-target-2026-10-17/native-runtime-install-r2/local-transfer-check.py b/docs/changes/netkingdom-target-2026-10-17/native-runtime-install-r2/local-transfer-check.py new file mode 100644 index 00000000..f8cdc810 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/native-runtime-install-r2/local-transfer-check.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python3 +"""Local archive roundtrip only; no native execution or runtime launch.""" +import importlib.util,json,shutil,tempfile +from pathlib import Path +HERE=Path(__file__).resolve().parent + +def load(name,path): + s=importlib.util.spec_from_file_location(name,path);m=importlib.util.module_from_spec(s);s.loader.exec_module(m);return m + +def main(): + builder=load('transfer_builder',HERE/'build-transfer.py') + verifier=load('remote_install_code_review',HERE/'install-verified.py') + with tempfile.TemporaryDirectory(prefix='nk-runtime-transfer-check-') as directory: + p=Path(directory); archive=p/'runtime.tar.gz' + with archive.open('xb') as target:built=builder.build(target) + assert built==json.loads((HERE/'transfer-archive.json').read_text()) + archive.chmod(0o600);shutil.copyfile(HERE/'runtime.py',p/'runtime.py');(p/'runtime.py').chmod(0o600) + verifier.STAGE=p + extracted=verifier.extract() + result={'scope':'local temporary archive roundtrip only','archive_sha256':built['sha256'], + 'archive_bytes':built['bytes'],'member_count':built['members'], + 'complete_extracted_digest':verifier.runtime_reader().runtime_digest(extracted), + 'modes_and_internal_symlinks_preserved':True,'native_actions':0,'runtime_launches':0} + assert not p.exists();result['local_temporary_tree_removed']=True + (HERE/'local-transfer-verification.json').write_text(json.dumps(result,indent=2)+'\n') + print(json.dumps(result)) + +if __name__=='__main__':main() diff --git a/docs/changes/netkingdom-target-2026-10-17/native-runtime-install-r2/local-transfer-verification.json b/docs/changes/netkingdom-target-2026-10-17/native-runtime-install-r2/local-transfer-verification.json new file mode 100644 index 00000000..f2f8332e --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/native-runtime-install-r2/local-transfer-verification.json @@ -0,0 +1,12 @@ +{ + "scope": "local archive extraction function roundtrip; no remote installer or runtime launch", + "archive_sha256": "sha256:4c55b2740e759175d645705518fc33db30b26b4611f68e052a4ca909173084c7", + "archive_bytes": 109931109, + "member_count": 1448, + "complete_extracted_digest": "f59959b605a51abd2901becde14e7abd852c2bd3f848004b51d250d1cb81af6d", + "modes_and_internal_symlinks_preserved": true, + "native_actions": 0, + "runtime_launches": 0, + "local_temporary_tree_removed": true, + "tested_extract_function_sha256": "sha256:6671d4a0d03860e4ed4dd860c5f9405aefdb342f51eb39b6bce7c59bf18c6321" +}