ci: diagnose exact Pi12 Intel startup and retain final integrity

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
DottaandPaperclip committed 2026-10-01 23:17:26 -05:00
1 parent 9541eb1878
commit 07af1ef5b0
5 files changed
+123 -54

No files matched your search

+8 -8
View File
@@ -32,7 +32,7 @@ on:
type: boolean
default: false
diagnose_pi_startup:
description: "Instrument one retained W native Intel startup with unchanged deadlines (diagnostic only, no provider prompts)"
description: "Instrument one retained B9 profile12 native Intel startup with unchanged deadlines (diagnostic only, no provider prompts)"
type: boolean
default: false
diagnose_ajv_pack:
@@ -191,7 +191,7 @@ jobs:
test "$SOURCE_E2E_SUPPORT_ONLY" != true
test "$DIAGNOSE_AJV" != true
test "$IMAGE_MODE" != true
test "$EXPECTED_SOURCE_SHA" = efe019a79f50440d7bd6c3bc6c75fb8f18953093
test "$EXPECTED_SOURCE_SHA" = b9e5d6ecdb05ab7244c90976e07c950f8d09b15b
test "$EXPECTED_LOCK_SHA256" = 38338a6867358440c5ab5993eaeb85fb501bc7df65d24acf52fbd63c880ee4ba
test "$(gh api "repos/$REPOSITORY" --jq '.visibility')" = public
fi
@@ -257,7 +257,7 @@ jobs:
if-no-files-found: error
manual_pi_startup_diagnostic:
name: Retained W native Intel startup timing diagnostic (not qualification)
name: Retained B9 profile12 native Intel startup timing diagnostic (not qualification)
if: github.event_name == 'workflow_dispatch' && inputs.diagnose_pi_startup
needs: authorize_manual
runs-on: macos-15-intel
@@ -278,16 +278,16 @@ jobs:
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
gh api repos/paperclipai/paperclip/actions/artifacts/11204971146/zip \
> "$RUNNER_TEMP/pi-startup-36952019178.zip"
printf '%s %s\n' 5f9bfabcb5a3d1b3180c2eb6f0eb8ebe58770b0c63a8b7dcbd379729b6c468f9 \
"$RUNNER_TEMP/pi-startup-36952019178.zip" | shasum -a 256 --check
gh api repos/paperclipai/paperclip/actions/artifacts/11208570718/zip \
> "$RUNNER_TEMP/pi-startup-36959948724.zip"
printf '%s %s\n' b82cf6c843006781e2e6d5f0a06e0ff39497ffc457b94a511f8bdda66628aa43 \
"$RUNNER_TEMP/pi-startup-36959948724.zip" | shasum -a 256 --check
- name: Run one instrumented startup with original assertions and deadlines
timeout-minutes: 18
run: |
set -euo pipefail
python3 -B trusted-ci/scripts/ci/pi-intel/startup_diagnostic.py \
--archive "$RUNNER_TEMP/pi-startup-36952019178.zip" \
--archive "$RUNNER_TEMP/pi-startup-36959948724.zip" \
--output "$GITHUB_WORKSPACE/pi-startup-diagnostic-evidence"
- name: Admit complete diagnostic evidence within the storage bound
if: always()
@@ -1,57 +1,57 @@
{
"schema": "paperclip.native-intel-startup-diagnostic-input/v1",
"sourceRevision": "efe019a79f50440d7bd6c3bc6c75fb8f18953093",
"sourceRevision": "b9e5d6ecdb05ab7244c90976e07c950f8d09b15b",
"resolvedLockSha256": "38338a6867358440c5ab5993eaeb85fb501bc7df65d24acf52fbd63c880ee4ba",
"artifactRunId": "36952019178",
"artifactId": "11204971146",
"artifactWorkflowRevision": "31e7bc15b00ba651b9c2e321d425a7e6320a48f9",
"artifactZipBytes": 1129002006,
"artifactZipSha256": "5f9bfabcb5a3d1b3180c2eb6f0eb8ebe58770b0c63a8b7dcbd379729b6c468f9",
"artifactRunId": "36959948724",
"artifactId": "11208570718",
"artifactWorkflowRevision": "9541eb18789bac35242eeea3e569b77fa90d1818",
"artifactZipBytes": 1076365959,
"artifactZipSha256": "b82cf6c843006781e2e6d5f0a06e0ff39497ffc457b94a511f8bdda66628aa43",
"selectedFiles": {
"receipt.json": {
"bytes": 26708,
"sha256": "338d7d93ba07b09d55de9a54640eb57c498bb4b35bc7ab1ad02d8fdbb72eb44a"
"bytes": 32763,
"sha256": "47ef1f494c59c1249ac42f08308a2fb83edcb0759890960059cc367ebdf12bf0"
},
"provider-pack.tar.gz": {
"bytes": 1029188649,
"sha256": "680d5a7ed3cb7813fbce0a994d0b91b7ec4991b538da640ed9cc5175baf4b60e"
"bytes": 1029214229,
"sha256": "5a550004ca982c49a2d86b3196676f3ce1877b6655ec730d1971b4cec2ba547d"
},
"provider-pack.json": {
"bytes": 3629,
"sha256": "ffb81f911990dc66558a277ab8ec20698af03e671f44bdd8a41fda0f392e4e6a"
"sha256": "db5b1d7d825a0533a6506755c6209ccc4d45776c3abbf6c87ff845d1d47e99b2"
},
"pack-inventory.json": {
"bytes": 10633748,
"sha256": "5d2fbdb0976ae1f4431cf66ee3611c2104d23a3ce04910be8941f8a03e36d710"
"sha256": "172f0f4f2319f3716cca656cdeafd03b4f0db652def53101dfbf148850a20eaa"
},
"paperclip-runnerd": {
"bytes": 32035568,
"sha256": "a0c7ace7ad0be9ac5b5f9c58749d9c452cd3a1ef143a38d5120d8e4f2bf82d6a"
"sha256": "29d5b0fc2ae2a552b89a107e3777e2c8ee356ebdbb13a14ceab8865e1cea1d45"
},
"source.tar": {
"bytes": 141690880,
"sha256": "587c0f60a30f0ca4b43361830cb611fcaa4a83f492cb7a9fd66b7908b45f72be"
"bytes": 141742080,
"sha256": "b32d8e32639e6527804fe11bfa1aaefcefa87fca31e9155499e6b9a28f69dbd4"
},
"source-input-inventory.json": {
"bytes": 1033276,
"sha256": "1356cd9a81d4c94e477a50cf2879efc7002fd687337fdad121f0c2381689ab36"
"bytes": 1033702,
"sha256": "7c160bb1fc4d049378004d014e398d42dabf12e8a73ec9cdda7679113aaa6949"
},
"resolved-pnpm-lock.yaml": {
"bytes": 607788,
"sha256": "38338a6867358440c5ab5993eaeb85fb501bc7df65d24acf52fbd63c880ee4ba"
}
},
"originalSidecarSha256": "1f0ee222b2edaad997b898aec6580982afc179fc60e5abc87fa3e6f2386a691f",
"originalPackDigest": "sha256:ae455e79f07f189e6d5d2bb9eeb01d26040e4b19370bfcda47d288c7b1d60b24",
"daemonSha256": "a0c7ace7ad0be9ac5b5f9c58749d9c452cd3a1ef143a38d5120d8e4f2bf82d6a",
"originalSidecarSha256": "7462825f4b82bce8e2a69425eafe4ca8b2c8812df345269c82fb75aa21f3043c",
"originalPackDigest": "sha256:9cf4f88d9fcf63746f7716f773cb8d062544c19e0a78e111e60f659a3596b13f",
"daemonSha256": "29d5b0fc2ae2a552b89a107e3777e2c8ee356ebdbb13a14ceab8865e1cea1d45",
"nodeSha256": "7abcf39bd37ab251015337ff75304d7555f0d8e88c6e0fbf04bce8ce34636f49",
"testPath": "packages/paperclip-runner/test/pi-closed-startup.test.mjs",
"testSha256": "8967cf9c8cd130b68bf9d64abef8cb8d352af00646e2288b341d8c6ae758b47a",
"observerSha256": "1fcf353beb90722f90401a7792a5853bf0807d964a1065e3f55b76a63bc4b4cc",
"profileDigest": "sha256:5e276f48c8a87b3e6165369faac62d3925282c84b98934575b1b7b97ad50b309",
"closureDigest": "sha256:8c6e7802d47da9410af56e367f6cf7af572fcbf3e361627cee026e8cffc9bdd3",
"profileDigest": "sha256:47306e6d2a9b59e8f9189f725ebb7a0a7f91826044d1739e1a35ab31f228ba1f",
"closureDigest": "sha256:03351f4a250a8db0e79411a9079b43a0ff05f72a2aff41fae17f1fc2de24bd41",
"model": "openrouter/deepseek/deepseek-v4-flash-0731",
"originalFailure": "Durable session.open failed: ACPX sidecar request timed out at session.open; drain issued 30.275s after open; secondary close could not durably suspend provider;44SDK contracts passed; cleanup verified; no report.json produced",
"originalFailure": "Original 30s session.open timeout; settled35032ms; runner exit0 and owned cleanup verified;48SDK contracts passed; fresh Rust daemon and complete pack passed.",
"executionCount": 1,
"providerCalls": 0,
"timeoutChanges": false,
+49 -12
View File
@@ -58,13 +58,49 @@ def reject_sink_failure(logs):
require(stat.S_ISREG(st.st_mode) and st.st_nlink==1 and st.st_size<=1024*1024,'Diagnostic stderr is missing, linked or oversized')
require(b'PC_STARTUP_DIAGNOSTIC_SINK_FAILED' not in path.read_bytes(),'Explicit diagnostic sink failure marker')
def post_run_integrity(pack,inventory,daemon,original,test,pin):
# Every independent check runs even if another fails or timing was incomplete.
checks={};errors={}
actions={'pack':lambda:closed_tree(pack)==inventory,
'daemon':lambda:sha(daemon)==pin['daemonSha256'],
'test':lambda:sha(test)==pin['testSha256']}
for name in ['source.tar','source-input-inventory.json','resolved-pnpm-lock.yaml']:
actions[name]=lambda name=name:sha(original/name)==pin['selectedFiles'][name]['sha256']
for name,check in actions.items():
try:
require(check(),'Post-run identity mismatch: '+name);checks[name]=True
except BaseException as error:checks[name]=False;errors[name]=type(error).__name__+': '+str(error)
return {'complete':True,'passed':not errors,'checks':checks,'errors':errors}
def finalize_diagnostic(proof,active,post_check,retain,remove):
errors=[]
try:
if active is not None:
if active.child is not None:active.retire(active.child)
proof['cleanupUncertain']=active.uncertain
except BaseException as error:
proof['cleanupUncertain']=True;errors.append('owned cleanup: '+repr(error))
try:
proof['postRunIntegrity']=post_check()
if not proof['postRunIntegrity']['passed']:errors.append('post-run integrity failed')
except BaseException as error:errors.append('post-run integrity: '+repr(error))
try:retain()
except BaseException as error:errors.append('evidence retention: '+repr(error))
if not proof['cleanupUncertain']:
try:remove();proof['scratchRemoved']=True
except BaseException as error:proof['cleanupUncertain']=True;errors.append('scratch cleanup: '+repr(error))
else:errors.append('scratch retained after uncertain owned cleanup')
if errors:
proof.update(status='diagnostic_failed',finalizationErrors=errors)
raise RuntimeError('; '.join(errors))
def execute(args):
out=args.output.resolve();out.mkdir(mode=0o700,parents=True,exist_ok=False)
scratch=Path(tempfile.mkdtemp(prefix='pc-intel-diagnostic-',dir='/private/tmp'));scratch.chmod(0o700)
scratch_id=(scratch.stat().st_dev,scratch.stat().st_ino,scratch.stat().st_uid)
proof={'schema':'paperclip.native-intel-startup-diagnostic/v1','status':'preparing','sourceRevision':PIN['sourceRevision'],'runId':os.environ['GITHUB_RUN_ID'],'trustedWorkflowRevision':os.environ['GITHUB_WORKFLOW_SHA'],'originalQualificationRunId':PIN['artifactRunId'],'startedAt':datetime.datetime.now(datetime.timezone.utc).isoformat(),'isQualification':False,'providerCalls':0,'credentialsRead':False,'runtimePromptsSubmitted':0,'nativeRecompiled':False,'dependencyInstallExecuted':False,'testSourceUnmodified':True,'deadlineChanged':False,'helpers':{p.name:sha(p) for p in HERE.iterdir() if p.is_file()},'commands':[],'cleanupUncertain':False,'scratchRemoved':False,'hardwareBareMetalClaim':False,'physicalColdDiskClaim':False,'cacheNote':'Artifact integrity verification necessarily reads payload before testing; no startup warmup is performed.'}
def save():atomic_json(out/'receipt.json',proof)
active=None
active=None;pack=None;after=None;daemon=None;original=None;test=None
def cancelled(sig,_):
if active is not None:active.cancel('signal '+str(sig))
else:raise InterruptedError('Diagnostic cancelled')
@@ -104,7 +140,7 @@ def execute(args):
sidecar=pack/'dist/cli/acpx-runtime-sidecar.cjs';original_sidecar=sidecar.read_bytes();patched,patch=patch_sidecar(original_sidecar,identity)
# Preserve original file mode; this one private copy now has an explicit diagnostic identity.
sidecar.write_bytes(patched);atomic_json(out/'sidecar-patch.json',patch)
(out/'sidecar.diff').write_text(''.join(difflib.unified_diff(original_sidecar.decode().splitlines(True),patched.decode().splitlines(True),fromfile='original-W-sidecar',tofile='diagnostic-sidecar')))
(out/'sidecar.diff').write_text(''.join(difflib.unified_diff(original_sidecar.decode().splitlines(True),patched.decode().splitlines(True),fromfile='original-B9-sidecar',tofile='diagnostic-sidecar')))
command('diagnostic-sidecar-syntax',[node,'--check',sidecar])
proof['diagnosticPackVerification']=json.loads(command('diagnostic-pack-rebind',[node,HERE/'rebind-diagnostic-pack.mjs',pack,PIN['originalSidecarSha256'],PIN['sourceRevision']],180))
after_manifest=json.loads((pack/'provider-pack.json').read_text());expected=copy.deepcopy(before_manifest)
@@ -140,24 +176,25 @@ def execute(args):
reject_sink_failure([out/'closed-startup.log',*retained.rglob('runnerd.stderr.log')])
proof['timing']=validate_timing_sink(sink,identity,set(patch['phases']));shutil.copy2(sink,out/'startup-timings.jsonl')
atomic_json(out/'timing-summary.json',proof['timing'])
require(closed_tree(pack)==after and sha(daemon)==PIN['daemonSha256'],'Diagnostic test mutated pack or daemon')
proof.update(status='diagnostic_complete_original_test_passed' if result==0 else 'diagnostic_complete_original_test_failed',isQualification=False,finishedAt=datetime.datetime.now(datetime.timezone.utc).isoformat());save()
return result
except BaseException as error:
proof.update(status='diagnostic_failed',errorType=type(error).__name__,error=str(error),finishedAt=datetime.datetime.now(datetime.timezone.utc).isoformat());raise
proof.update(status='diagnostic_failed',errorType=type(error).__name__,error=str(error),finishedAt=datetime.datetime.now(datetime.timezone.utc).isoformat())
if 'timing' not in proof:proof['timing']={'completeSink':False,'error':type(error).__name__+': '+str(error),'partialEvidenceRetained':(scratch/'startup-timings.jsonl').is_file()}
raise
finally:
try:
if active is not None:
if active.child is not None:active.retire(active.child)
proof['cleanupUncertain']=active.uncertain
def post_check():
if after is None or test is None:return {'complete':False,'passed':False,'reason':'diagnostic pack/test preparation not completed'}
return post_run_integrity(pack,after,daemon,original,test,PIN)
def retain():
if (out/'retained-test-state').is_dir():proof['retainedTestStateInventory']=closed_tree(out/'retained-test-state')
if (scratch/'startup-timings.jsonl').is_file() and not (out/'startup-timings.jsonl').exists():
st=(scratch/'startup-timings.jsonl').lstat()
if stat.S_ISREG(st.st_mode) and st.st_nlink==1 and st.st_size<=32768:shutil.copyfile(scratch/'startup-timings.jsonl',out/'startup-timings.jsonl')
require(not proof['cleanupUncertain'],'Retain scratch after uncertain owned process cleanup')
def remove():
st=scratch.lstat();require((st.st_dev,st.st_ino,st.st_uid)==scratch_id and stat.S_ISDIR(st.st_mode),'Scratch identity changed')
shutil.rmtree(scratch);proof['scratchRemoved']=True
except BaseException as cleanup_error:
proof.update(cleanupUncertain=True,cleanupError=type(cleanup_error).__name__+': '+str(cleanup_error));raise
shutil.rmtree(scratch)
try:finalize_diagnostic(proof,active,post_check,retain,remove)
finally:save()
if __name__=='__main__':
+3 -2
View File
@@ -1,7 +1,7 @@
"""Sparse additive instrumentation of one pinned bundle; never edits vendor closure bytes."""
import hashlib,json
from source_guard import require
ORIGINAL_SHA='1f0ee222b2edaad997b898aec6580982afc179fc60e5abc87fa3e6f2386a691f'
ORIGINAL_SHA='7462825f4b82bce8e2a69425eafe4ca8b2c8812df345269c82fb75aa21f3043c'
PREFIX='__pcStartupDiagnostic'
def patch_sidecar(original,sink):
@@ -39,8 +39,9 @@ def patch_sidecar(original,sink):
mark('// src/drivers/acpx/pi-verified-runtime.ts','async function verifyPiRuntimeLayoutForNativeSnapshot(root, manifest, nativeManifest, expectedClosureSha256) {','pi.layout.begin',True)
mark('// src/drivers/acpx/pi-verified-runtime.ts',' return { manifestDigest };','pi.layout.end')
mark('// src/drivers/acpx/native-distribution-integrity.ts','async function createNativeAcpxDistributionSnapshot(input, entries) {','snapshot.begin',True)
mark('// src/drivers/acpx/native-distribution-integrity.ts',' for (const depth of [...parentLevels.keys()].sort((a, b) => a - b)) {','snapshot.directories.begin')
mark('// src/drivers/acpx/native-distribution-integrity.ts',' const copyEntry = async (entry) => {','snapshot.directories.end')
mark('// src/drivers/acpx/native-distribution-integrity.ts',' for (let start = 0; start < entries.length; ) {','snapshot.copy.begin')
mark('// src/drivers/acpx/native-distribution-integrity.ts',' const active = /* @__PURE__ */ new Set();','snapshot.copy.begin')
mark('// src/drivers/acpx/native-distribution-integrity.ts',' const executable = (0, import_node_path5.join)(packageRoot, ...input.executable.split("/"));','snapshot.copy.end')
mark('// src/drivers/acpx/native-distribution-integrity.ts',' await directoryBatch([...directories], (path3) => (0, import_promises6.chmod)(path3, 320));','snapshot.seal.begin')
mark('// src/drivers/acpx/native-distribution-integrity.ts',' return { commandDirectory, bootstrap, snapshot:','snapshot.seal.end')
+40 -9
View File
@@ -1,7 +1,7 @@
import copy,hashlib,json,os,subprocess,tempfile,unittest
from pathlib import Path
from startup_timing_patch import patch_sidecar,ORIGINAL_SHA
from startup_diagnostic import validate_pack_delta,validate_timing_sink,reject_sink_failure,PIN
from startup_diagnostic import validate_pack_delta,validate_timing_sink,reject_sink_failure,post_run_integrity,finalize_diagnostic,PIN
from diagnostic_lifecycle import DiagnosticChild,DiagnosticInspection
from owned_processes import process_table,command_tokens,ProcessInspectionUnavailable
from unittest.mock import patch
@@ -37,28 +37,28 @@ class DiagnosticTests(unittest.TestCase):
for change in reversed(proof['insertions']):
shift-=len(change['inserted']);at=change['offset']+shift;text=text[:at]+text[at+len(change['inserted']):]
self.assertEqual(text.encode(),self.original);self.assertEqual(hashlib.sha256(text.encode()).hexdigest(),ORIGINAL_SHA)
self.assertEqual(len(proof['phases']),46)
self.assertEqual(len(proof['phases']),47)
def test_wrong_original_rejected(self):
with self.assertRaises(RuntimeError):patch_sidecar(self.original+b' ',{'path':'unused','dev':'1','ino':'2','uid':'3'})
def test_retained_w_pack_identity_and_original_test_contract(self):
self.assertEqual(PIN['sourceRevision'],'efe019a79f50440d7bd6c3bc6c75fb8f18953093')
self.assertEqual(PIN['artifactRunId'],'36952019178')
self.assertEqual(PIN['artifactId'],'11204971146')
def test_retained_b9_pack_identity_and_original_test_contract(self):
self.assertEqual(PIN['sourceRevision'],'b9e5d6ecdb05ab7244c90976e07c950f8d09b15b')
self.assertEqual(PIN['artifactRunId'],'36959948724')
self.assertEqual(PIN['artifactId'],'11208570718')
self.assertEqual(PIN['originalSidecarSha256'],ORIGINAL_SHA)
self.assertEqual(PIN['selectedFiles']['paperclip-runnerd']['sha256'],PIN['daemonSha256'])
self.assertEqual(PIN['selectedFiles']['resolved-pnpm-lock.yaml']['sha256'],PIN['resolvedLockSha256'])
self.assertEqual(PIN['testSha256'],'8967cf9c8cd130b68bf9d64abef8cb8d352af00646e2288b341d8c6ae758b47a')
self.assertEqual((PIN['executionCount'],PIN['providerCalls'],PIN['timeoutChanges']),(1,0,False))
self.assertEqual((PIN['archiveBytesMaximum'],PIN['retentionDays']),(268435456,7))
def test_w_markers_follow_outer_layout_and_snapshot_boundaries(self):
def test_b9_markers_follow_outer_layout_and_snapshot_boundaries(self):
_,proof=patch_sidecar(self.original,{'path':'/private/tmp/pc-intel-diagnostic-fixture/startup-timings.jsonl','dev':'1','ino':'2','uid':'501'})
phases=proof['phases']
self.assertFalse(any(p.startswith('pi.hash.') for p in phases))
for begin,end in [('pi.native_manifest.begin','pi.native_manifest.end'),('pi.discovery.begin','pi.discovery.end'),('pi.layout.begin','pi.layout.end'),('snapshot.copy.begin','snapshot.copy.end'),('snapshot.seal.begin','snapshot.seal.end')]:
for begin,end in [('pi.native_manifest.begin','pi.native_manifest.end'),('pi.discovery.begin','pi.discovery.end'),('pi.layout.begin','pi.layout.end'),('snapshot.directories.begin','snapshot.directories.end'),('snapshot.copy.begin','snapshot.copy.end'),('snapshot.seal.begin','snapshot.seal.end')]:
self.assertEqual(phases.count(begin),1);self.assertEqual(phases.count(end),1)
# Discovery recursion and descriptor-copy loops must not emit one row per file.
source=self.original.decode()
for begin,end in [(' const visit = async (directory) => {',' await visit(physicalRoot);'),(' const copyEntry = async (entry) => {',' for (let start = 0; start < entries.length; ) {')]:
for begin,end in [(' const visit = async (directory) => {',' await visit(physicalRoot);'),(' const copyEntry = async (entry) => {',' const active = /* @__PURE__ */ new Set();')]:
start=source.index(begin);finish=source.index(end,start)
interior=[x for x in proof['insertions'] if start < x['offset'] < finish]
self.assertEqual(interior,[])
@@ -69,6 +69,37 @@ class DiagnosticTests(unittest.TestCase):
with self.assertRaisesRegex(RuntimeError,'terminal marks missing'):
validate_timing_sink(p,b,{'sidecar.entry','session.open.begin','snapshot.copy.begin','sidecar.exit'})
self.assertIn('snapshot.copy.begin',p.read_text())
def test_post_run_integrity_drains_checks_after_pack_failure(self):
with tempfile.TemporaryDirectory() as tmp:
root=Path(tmp);names=['daemon','test','source.tar','source-input-inventory.json','resolved-pnpm-lock.yaml']
for name in names:(root/name).write_bytes(name.encode())
digest=lambda name:hashlib.sha256(name.encode()).hexdigest()
pin={'daemonSha256':digest('daemon'),'testSha256':digest('test'),'selectedFiles':{name:{'sha256':digest(name)} for name in names[2:]}}
with patch('startup_diagnostic.closed_tree',side_effect=RuntimeError('mutation')):
result=post_run_integrity(root,[],root/'daemon',root,root/'test',pin)
self.assertFalse(result['passed']);self.assertTrue(result['complete'])
self.assertEqual(result['checks'],{'pack':False,**{name:True for name in names}})
(root/'test').write_bytes(b'drift')
with patch('startup_diagnostic.closed_tree',return_value=[]):
result=post_run_integrity(root,[],root/'daemon',root,root/'test',pin)
self.assertFalse(result['passed']);self.assertFalse(result['checks']['test']);self.assertTrue(result['checks']['resolved-pnpm-lock.yaml'])
def test_partial_sink_finally_keeps_integrity_and_cleanup(self):
proof={'status':'diagnostic_failed','timing':{'completeSink':False},'cleanupUncertain':False};calls=[]
finalize_diagnostic(proof,None,lambda:(calls.append('integrity') or {'passed':True}),lambda:calls.append('retain'),lambda:calls.append('remove'))
self.assertEqual(calls,['integrity','retain','remove']);self.assertTrue(proof['scratchRemoved']);self.assertFalse(proof['timing']['completeSink']);self.assertEqual(proof['status'],'diagnostic_failed')
def test_finalization_integrity_and_retention_errors_do_not_block_cleanup(self):
for failed_phase in ['integrity','retain']:
proof={'cleanupUncertain':False};calls=[]
def step(name):
calls.append(name)
if name==failed_phase:raise RuntimeError(name)
return {'passed':True}
with self.assertRaises(RuntimeError):finalize_diagnostic(proof,None,lambda:step('integrity'),lambda:step('retain'),lambda:step('remove'))
self.assertEqual(calls,['integrity','retain','remove']);self.assertTrue(proof['scratchRemoved']);self.assertFalse(proof['cleanupUncertain'])
def test_uncertain_cleanup_still_records_integrity_but_retains_scratch(self):
active=DiagnosticChild(FakeOwner(fail_stop=True));active.child=FakeProcess();proof={'cleanupUncertain':False};calls=[]
with self.assertRaises(RuntimeError):finalize_diagnostic(proof,active,lambda:(calls.append('integrity') or {'passed':True}),lambda:calls.append('retain'),lambda:self.fail('uncertain scratch removed'))
self.assertEqual(calls,['integrity','retain']);self.assertTrue(proof['cleanupUncertain'])
def test_numeric_inode_rejected(self):
with self.assertRaises(RuntimeError):patch_sidecar(self.original,{'path':'/private/tmp/pc-intel-diagnostic-x/startup-timings.jsonl','dev':1,'ino':2,'uid':3})
def run_prelude(self,extra='',identity_mutation=None):