From c52ca7f405416d437951844c0640b86e677c3523 Mon Sep 17 00:00:00 2001 From: tegwick Date: Sat, 17 Oct 2026 04:15:30 +0200 Subject: [PATCH] fix(recovery): require one original client and refine native owner gates Assistant: codex Assistant-Model: gpt-6.1-sol Assistant-Session: 01a1468b-63fa-7710-85dc-8f2e16b3ebfa --- ...lated-keycape-native-fixture-manifest.json | 6 +- tests/test_isolated_keycape_recovery.py | 28 +++ tools/bootstrap-recovery/isolated-keycape.py | 27 ++- workplans/NK-WP-0048-security-case-types.md | 177 ++++++++++++++++-- ...-bootstrap-secret-free-recovery-handoff.md | 58 +++++- 5 files changed, 270 insertions(+), 26 deletions(-) diff --git a/tests/isolated-keycape-native-fixture-manifest.json b/tests/isolated-keycape-native-fixture-manifest.json index a925454..53d6b54 100644 --- a/tests/isolated-keycape-native-fixture-manifest.json +++ b/tests/isolated-keycape-native-fixture-manifest.json @@ -7,7 +7,7 @@ "tests/run_isolated_keycape_native_fixture.py": "sha256:ecbadecc475622eaaf20a726110aebef5f4fe7af141110a98aca1640179b4a03", "tests/test_identity_bundle.py": "sha256:be5ce74097594cc7f7e77dbccd6cb53aa72f263cd1bb442ce5464038aed1116c", "tests/test_isolated_keycape_fixture_plan.py": "sha256:5945619f4c5957187763276cc900870a9f08f9475b63c240694688e0c2eca7dd", - "tests/test_isolated_keycape_recovery.py": "sha256:247e9a87f5be2ee9f20f7edbb4a9f612ab7cb0cd940392c3caeca8b046605f55", + "tests/test_isolated_keycape_recovery.py": "sha256:5f729e077db51dd6b17d00dc3eb71c0e652849f55fe68505a07befa663c91dea", "tests/test_isolated_keycape_session.py": "sha256:cbdf51efde26eff337e9303a2c431f80b333b8846d763eb62853f81eb3f13e2c", "tools/bootstrap-recovery/capture-identity.py": "sha256:47dca7c4dc96fa7eb9fb02c81fca9ca8dc5281aac918979eb7367148168ba705", "tools/bootstrap-recovery/check-privacyidea-database.py": "sha256:90f454c87998d7f5d625e3c6656c3418f8f56275dc1879a9d19ed605431b94a4", @@ -25,7 +25,7 @@ "tools/bootstrap-recovery/inventory-scaleway.py": "sha256:a219df205708fa4ed44b763a418585d63c820c25434bc0fd14e805eb5c2f79d3", "tools/bootstrap-recovery/inventory-storage-share.py": "sha256:673f9b17fb2f3fef6fcdb5c50a2bcca69e3df3157a9e5582a2d995c6b87640b5", "tools/bootstrap-recovery/isolated-keycape-session.py": "sha256:8fa38efe28167b59a6307f342b2ac8fcda78ecda60e6228f22017424d2343c22", - "tools/bootstrap-recovery/isolated-keycape.py": "sha256:f67627b7d1647d75187dd899874efe22383bc91de5d97dabb9801076668ab3c2", + "tools/bootstrap-recovery/isolated-keycape.py": "sha256:86f37add7221e4c73e3f9d878c09a3cc81061627cbf024ed6887d973d929b718", "tools/bootstrap-recovery/isolated-lldap.py": "sha256:35bfa8411186ad936a199bd450c7e18c2ad51059301a6db9650e6bd055ab1b81", "tools/bootstrap-recovery/isolated-privacyidea.py": "sha256:4df7196678aac1ad594f32abf45c68dc21a9d2760d9e8a536a215a4a3c5d277f", "tools/bootstrap-recovery/prepare-identity-coverage.py": "sha256:cd5f3067d28b4c7cc93ed08b8cf3869218bdecf7c54b5dffed22d697de71dbb1", @@ -81,7 +81,7 @@ "synthetic_source_root": "private /dev/shm/nk49-keycape-fixture-", "safe_result": "private /tmp/nk49-keycape-native-fixture-review-/result.json" }, - "scope": "candidate itself on complete synthetic format/integrity archive fixture; no native PI/LLDAP/Authelia proof, real custody, real factor or real client credential; successor binds sealed-descriptor custody preparation sources; synthetic fixture itself overrides custody with generated fixture key as before", + "scope": "candidate itself on complete synthetic format/integrity archive fixture; no native PI/LLDAP/Authelia proof, real custody, real factor or real client credential; successor binds sealed-descriptor custody preparation sources; synthetic fixture itself overrides custody with generated fixture key as before; unexecuted exact-one-selector adapter successor: no new native outcome inferred from earlier fixtures", "mutations": [ "conditional creation of exact fresh local containers and local-driver tmpfs volumes", "private synthetic file import to those volumes", diff --git a/tests/test_isolated_keycape_recovery.py b/tests/test_isolated_keycape_recovery.py index cf780ae..b2a4455 100644 --- a/tests/test_isolated_keycape_recovery.py +++ b/tests/test_isolated_keycape_recovery.py @@ -54,6 +54,34 @@ class ArchiveTests(unittest.TestCase): if row['path'].endswith('/deployment/keycape.json'):row.update(bytes=len(raw),sha256=hashlib.sha256(raw).hexdigest()) with self.assertRaises(a.Refused):self.payload() + +class OriginalSelectorTests(unittest.TestCase): + """Already-restored public fixture config; no archive/key/native action.""" + def assert_refused_before_further_inputs(self,clients): + import yaml + cfg={'issuer':'https://issuer.example','clients':clients} + payload={'files':{'/etc/keycape/config.yaml':base64.b64encode(yaml.safe_dump(cfg).encode()).decode(), + '/etc/keycape/key.pem':'deliberately-not-base64'}} + admission={'issuer':'https://issuer.example','consumer':{'client_id':'existing','secret_env':'KEYCAPE_ORIGINAL_SECRET'}} + # Empty session/no env and an undecodable key also expose early private access. + from contextlib import ExitStack + with ExitStack() as stack: + blocked=[stack.enter_context(patch.object(a,name,side_effect=AssertionError('later input or native call'))) + for name in ('container_file','runtime_file','runtime_files','command','check_jwks','process')] + with self.assertRaises(a.Refused):a.run_verifier({},admission,payload) + for call in blocked:call.assert_not_called() + def client(self): + return {'clientId':'existing','clientType':'confidential','secretRef':'env:KEYCAPE_ORIGINAL_SECRET', + 'grantTypes':['client_credentials']} + def test_absent_original_selector_refused_before_further_inputs(self): + self.assert_refused_before_further_inputs([dict(self.client(),clientId='unrelated')]) + def test_identical_duplicate_selector_refused_before_further_inputs(self): + self.assert_refused_before_further_inputs([self.client(),self.client()]) + def test_conflicting_duplicate_selector_refused_before_further_inputs(self): + self.assert_refused_before_further_inputs([self.client(),dict(self.client(),secretRef='env:OTHER')]) + def test_empty_registry_refused_before_further_inputs(self): + self.assert_refused_before_further_inputs([]) + class NativeTests(unittest.TestCase): def setUp(self): from cryptography.hazmat.primitives import serialization diff --git a/tools/bootstrap-recovery/isolated-keycape.py b/tools/bootstrap-recovery/isolated-keycape.py index 4cc40e6..44a3a11 100644 --- a/tools/bootstrap-recovery/isolated-keycape.py +++ b/tools/bootstrap-recovery/isolated-keycape.py @@ -322,6 +322,23 @@ def runtime_file(session,path): def run_verifier(session, admission, payload): + # Select from the already-restored config before further private/runtime reads. + # This is not public preflight before archive decryption or its key prompt. + import yaml + cfg = yaml.safe_load(base64.b64decode(payload['files']['/etc/keycape/config.yaml'],validate=True)) + if not isinstance(cfg,dict) or cfg.get('issuer') != admission['issuer']: + raise Refused() + consumer = admission['consumer'] + clients = cfg.get('clients') + if not isinstance(clients,list) or any(not isinstance(client,dict) for client in clients): + raise Refused() + matches = [client for client in clients if client.get('clientId') == consumer['client_id']] + if len(matches) != 1: + raise Refused() + client = matches[0] + if (client.get('secretRef') != 'env:'+consumer['secret_env'] or client.get('clientType') != 'confidential' + or 'client_credentials' not in client.get('grantTypes',[])): + raise Refused() issuer = session['issuer'] if {v['target'] for v in session.get('volumes',{}).values()}!={'/etc/keycape','/var/lib/keycape-policy','/etc/keycape-factor','/recovery-tls'}:raise Refused() from urllib.parse import urlsplit @@ -352,15 +369,7 @@ def run_verifier(session, admission, payload): if durable!={k:v for k,v in files.items() if k.startswith('/var/lib/keycape-policy/')}: raise Refused() equal() - # Reading YAML is data parsing only; no archived executable is evaluated. - import yaml - cfg = yaml.safe_load(files['/etc/keycape/config.yaml']) - if cfg['issuer'] != admission['issuer']: - raise Refused() - consumer = admission['consumer'] - client = next(x for x in cfg['clients'] if x['clientId']==consumer['client_id']) - if (client['secretRef']!='env:'+consumer['secret_env'] or client['clientType']!='confidential' - or 'client_credentials' not in client['grantTypes'] or not env.get(consumer['secret_env'])): + if not env.get(consumer['secret_env']): raise Refused() from cryptography.hazmat.primitives import serialization key=serialization.load_pem_private_key(files['/etc/keycape/key.pem'],password=None) diff --git a/workplans/NK-WP-0048-security-case-types.md b/workplans/NK-WP-0048-security-case-types.md index c3dc3b2..359c925 100644 --- a/workplans/NK-WP-0048-security-case-types.md +++ b/workplans/NK-WP-0048-security-case-types.md @@ -708,6 +708,34 @@ receipts confer no new grant. The default production endpoint remains disabled without the trusted integration. SQLite remains local/disposable only; any production exception requires explicit scoped governance under ADR-0015. +2026-10-17 owner-integration refinement: T23 records the completed source/package +placement review, distinct from T21's source/disposable-SQL proof. Its dedicated +`rapp-identity-provisioner` recommendation is draft and unbound, not an accepted +package or existing repository. The full six-consumer rapp-postgres renderer +accepts the inert candidate on platform-pg-2 as its third of four declared +consumers; first-cell placement is refused as a fifth. Neither the estimated +four-consumer ceiling nor source requests establish native headroom or backup. + +Next independent owner contracts: NetKingdom/package/substrate owners accept +exact deployment/rollback fate; rapp-postgres admits the dedicated consumer, +roles, five-connection budget and actual backup/restore; Platform admits exact +renewable runtime/migration delivery and TLS/CA/SAN; network owners scope SQL, +broker and checkpoint paths without assuming a narrow policy subtracts additive +same-namespace access. Protected caller owners must provide authoritative +GroupJournalBinding construction and current authorization; an independent +existing holder must authenticate and atomically advance the exact content +checkpoint, not a counter or ordinary Audit receipt. Directory/runtime owners +must select and prove either an exclusive all-writer maintenance barrier or +provider-supported CAS/generation, including established sessions, lifecycle +cascades and remove/readd ABA. No source review establishes those owner facts. + +The default PostgreSQL activation and destructive native rollback remain refused. +Storage/lease acceptance can be proposed separately from LDAP mutation only after +exact owner source/target/custody/verification/recovery and cost/risk review; +State Hub guard approval grants none of it. Source-only integration review and +native acceptance matrix: Custodian native-storage-r1/OWNER-REVIEW.md. T14's +existing status, UUID, dependencies and native completion gate are retained. + 2026-10-17 refinement: T20 retains the historical durable SQLite source and actual disposable LLDAP proof. T21 extracts the completed PostgreSQL source and bounded real disposable SQL compatibility proof. T14 remains `progress` for @@ -738,14 +766,33 @@ state_hub_task_id: "1b825705-4848-5edc-832f-b1622cd9bdb7" ``` Owner: NetKingdom for registration state, with Warden owning kernel evidence -admission. Next action: select the exact existing owner evidence holder/readback -contract and define authenticated lookup for the original creation attempt. -Completion requires restart/lost-receipt fixtures that bind case/source/principal, -original created-only provenance and current native revision before any undo; -uncertain outcomes remain non-replayable. The T13 adapter deliberately refuses -post-restart rollback and installs no reconciliation callback. A new broker or -unverified JSON receipt is not a recovery contract. Actual evidence-holder -acceptance and attended recovery remain separately authorized native work. +admission. T22 records the completed source review and exact existing-seam gaps; +T15 retains implementation and authenticated restart/lost-receipt acceptance. +Next action: identify the actual owner publisher/authenticator and bounded +original-attempt readback contract, and obtain Warden's reviewed original-intent +lookup/context interface through existing WARDEN-WP-0044-T03. The current Journal +retains attempt identity in historical rows but only hashes evidence references; +load drops that context and reconcile passes a fresh attempt to the callback. +The adapter's original payload and creation record remain process-local. Neither +that journal nor a current matching registry entry reconstructs creation authority. + +The owner contract must bind the original Invocation, case/type/descriptor/catalog/ +acceptance pins, source, principal and admitted tenant/realm provenance, separately +from the new reconciliation attempt and its independently revoked parent session. +Use an existing authenticated holder/readback; Audit Core's custody API is a +candidate only until its actual registration source/class, load-bearing emission +contract and separate scoped reader are admitted. No new broker or receipt trust +root is proposed. A missing original record, ambiguous publication, NO_CHANGE, +changed native revision or lost readback stays uncertain; no add replay or undo. + +Completion requires restart/lost-receipt fixtures against the selected actual owner +contract: independently authenticated original created-only provenance, original +exact client entry and unchanged current postcreation UID/resourceVersion before +any undo, with wrong attempt/case/source/principal and unavailable-holder refusals. +The T13 adapter deliberately refuses post-restart rollback and installs no +reconciliation callback. Existing source review, JSON receipts and synthetic +trust do not satisfy native holder acceptance or authorize attended recovery. +Exact remaining owner facts: Custodian native-registration-r1/original-attempt-review.json. ## T16 — Select and review the actual machine descriptor composition @@ -757,11 +804,28 @@ state_hub_task_id: "200bf500-5084-5ae7-be26-3033fe1f296e" ``` Owner: NetKingdom for descriptor/type source and exact checker artifact; Warden -independently owns global provenance/admission. Next action: obtain review of the -exact checker source/artifact proposed by T17 and identify native owner evidence/ -session callback contracts, then assemble the complete step descriptor set and -a proposed explicit type version selection. T13's historical descriptor retains -its synthetic checker; T17 supplies an artifact-bound proposal, not admission. +independently owns global provenance/admission. T22 records the completed seven-step +source1.2 inventory and regenerated register-client descriptor using the delivered +checker and current sealed-snapshot source; T16 retains exact owner review, +complete descriptor composition and admission. Next action: bind actual native +publisher/authenticator, original/current session verification and revocation, +executable storage/custody and config pins, then obtain the six missing fixed +owner descriptors/adapters for ensure-groups, mint-secret, deliver-secret, +bind-env, deliver-consumer-secret and hand-over. The inventory identifies each +existing owner seam, exact missing contract and created-only rollback requirement; +it is not an executable bundle. T14 and T15 remain independent prerequisites. + +Review the dedicated consumer source1.2 composition only through the existing +explicit version-root selection. Keep canonical1.1/default and its accepted case +unchanged, and the source-only acknowledged1.2 reference case proposed without +acceptance fields. New descriptor bytes require a reviewed exact successor +revision/version under canon section6; they do not inherit historical source +acknowledgment. Changed authentication/materialization/trust needs the prescribed +informed-decision acknowledgment. Do not insert a partial descriptor map or use +--allow-unimplemented preparation as ordinary case/native admission. The registry +helper reports restart_required; separately review quiet-window restart/readiness +and actual consumer verification rather than infer activation from registry CAS. +Exact composition: Custodian native-registration-r1/descriptor-composition.json. Completion requires separate owner source review of exact machine descriptors, artifact/source/config pins, normal type/version admission and independent evidence-verification boundaries. Warden d97652a refreshes producer validator @@ -1064,3 +1128,90 @@ exact source/pre/postimages and retained predecessors; native R5 manifest storage/HA/backup/lease/TLS/capacity/restore admission, authoritative protected callbacks, real LDAP writer fencing/CAS/ABA exclusion, owner assent or production endpoint activation is claimed. Those remain live T14 work. + + +## T22 — Establish registration recovery source gaps and complete descriptor review inventory + +```task +id: NK-WP-0048-T22 +status: done +priority: high +state_hub_task_id: "ea50d93b-0d04-55d2-98c4-9b6c3fe925b1" +``` + +Completed 2026-10-17: source-only owner-contract review and complete review +inventory. Inspected the actual registration adapter, Warden Journal/Executor, +NetKingdom evidence compatibility checker and Audit Core custody/read surfaces. +No existing admitted holder/readback supplies authenticated original-attempt +recovery: payload/creation are process-local, persisted evidence references are +hashed, and reconcile receives a new attempt without original context. The exact +four-owner contract requirements and non-replayable missing/ambiguous cases are +recorded; no recovery callback, publisher, credential grant or native trust root +was installed. T15 retains implementation and actual acceptance. + +The complete source1.2 inventory maps all seven follow-through steps to their +existing owners, missing exact contracts and created-only rollback requirements. +The actual maintained adapter regenerated the sole existing register-client +machine descriptor against the delivered 13,633,409-byte checker and current +sealed-memfd snapshot source. The checker rehash and Warden Descriptor.decode +round-trip passed; six owner descriptors remain absent. Actual source commands +render canonical1.1 and explicitly selected1.2 with execution.permitted false; +ordinary1.2 case admission still refuses its acknowledged/unimplemented type. +Canonical type/case/acknowledgment bytes were hash-checked unchanged. No tests were +added or rerun, no native configuration or effect occurred, and no owner assent +or complete machine bundle is claimed. T16 retains native executable custody, +complete exact descriptors, independent source review and normal version/type +admission. This extracted outcome supplies no native gate completion credit. + +Evidence in the-custodian: +`docs/changes/netkingdom-target-2026-10-17/native-registration-r1/`, especially +original-attempt-review.json, descriptor-composition.json, source-verification.json, +source-manifest.json and manifest.json. The prior sixteen-gate audit remains +immutable. Publication, normal task UUID allocation and projection are separate +coordinator follow-through; no Hub UUID is assigned by this source record. + + +## T23 — Review native journal package assignment and storage integration boundaries + +```task +id: NK-WP-0048-T23 +status: done +priority: high +state_hub_task_id: "6e7cd483-c7af-53a2-9d0a-3d76b6fb49ee" +``` + +Completed 2026-10-17: source/package placement and protected integration review +only, separate from T21's completed PostgreSQL source and disposable-SQL proof. +The owner review recommends a dedicated independently rolled-back +`rapp-identity-provisioner`, owned by NetKingdom on rail-kubernetes, with a +schema-valid draft declaration and no reef binding. No repository, registry +entry, native package assignment or owner assent was created. Existing +rapp-user-engine ownership/token delivery does not assign it the provisioner. + +The complete current rapp-postgres catalog has six declared consumers: four on +platform-pg and two on platform-pg-2. The inert renderer-valid provisioner +candidate fits platform-pg-2 at three of four, requesting one migration plus +four runtime connections; placing it on the first cell is refused as a fifth. +Normative package schema and full-catalog capacity/render checks passed. The +four-consumer ceiling is estimated, not measured native headroom, and no current +SQL session, backup or restore acceptance is claimed. + +The exact review identifies remaining package/substrate, SQL role/lease/TLS, +network and backup/recovery contracts; independently authenticated protected +scope callbacks; an external content-bound checkpoint holder with atomic +advance/loss handling; and all-LDAP-writer exclusion or provider CAS/generation, +including lifecycle cascades and remove/readd ABA. Generic Audit custody is not +that checkpoint service. A database-only fence, final reread or one replica +cannot exclude foreign directory writers. The native acceptance/recovery matrix +keeps storage/lease admission separate from separately approved directory +mutation; the production activation remains disabled pending trusted integration. + +Evidence in the-custodian: +`docs/changes/netkingdom-target-2026-10-17/native-storage-r1/OWNER-REVIEW.md`, +source-validation.json and hash-bound source-references.json, plus the inert +proposed declaration/consumer and renderer outputs. No native resource, lease, +credential, deployment, destructive effect, independent holder or native owner +acceptance was delivered. T14 retains these live gates with its original UUID +and progress status. This completed review adds no duplicate T21 acceptance +credit; publication, task UUID allocation and projection remain coordinator +follow-through and no UUID is hand-assigned here. diff --git a/workplans/NK-WP-0049-bootstrap-secret-free-recovery-handoff.md b/workplans/NK-WP-0049-bootstrap-secret-free-recovery-handoff.md index 1a3eaf3..2078d62 100644 --- a/workplans/NK-WP-0049-bootstrap-secret-free-recovery-handoff.md +++ b/workplans/NK-WP-0049-bootstrap-secret-free-recovery-handoff.md @@ -1130,6 +1130,16 @@ Evidence: Custodian October17 `secrets-engine-projection.json` and October16 `recovery-owner-handoffs-r1` source review; independent ID/UUID/status/remote readback is recorded separately when performed. +2026-10-17 source checkpoint refinement: the completed exact-one original +selector guard and its bounded refusal/unique-selector proof are extracted into +T38. T36 retains exact archive-to-selector binding, current actual service-owner +recovery assent and outage-compatible private admission/consumer preparation. +The current eight-field source-selector correspondence is evidenced separately; +it does not complete those remaining obligations or any T18/T19 native gate. +T33 continues to require the complete reviewed TLS/custody/admission packet. +This extraction records one source outcome rather than counting it again as +original registration validation or consumer continuity. + ## Verify actual SOPS compatibility and sealed-descriptor read/write custody ```task @@ -1170,6 +1180,52 @@ T33 attempt readiness, T18 actual recovery/consumer acceptance, T19 retained MFA T35 TLS/trust disposition and T36 original registration/private admission remain open under their existing owner boundaries. +## Deliver exact-one original selector guard and bounded source refusal proof + +```task +id: NK-WP-0049-T38 +status: done +priority: high +assignee: codex +depends_on: [NK-WP-0049-T34] +state_hub_task_id: "76dde6b9-5ee8-50d3-bf15-461d6d5f29b8" +``` + +Completed 2026-10-17 as source preparation, independently reviewed by the +coordinating Custodian agent. The adapter now requires exactly one selected +registration in the already-restored archive configuration before further runtime +environment reads, signer-key parsing or native checker invocation. Absent, +empty, identical-duplicate and conflicting-duplicate selectors refuse before +those later inputs; the existing unique-selector mocked native path still passes. +Current KeyCape Go configuration also rejects duplicate IDs; this makes the +adapter's own boundary explicit and establishes no native duplicate exploit. +The guard cannot run before archive decryption or the original key prompt. + +The 39 adapter checks passed, including four added early-refusal regressions. +Running those four cases against the retained original adapter failed the new +refusal contract as expected. The broader 77-check source run retained 76 passes +and one stale fixture-proposal source-hash refusal. Only the two affected hashes +and scope of that unexecuted/unapproved successor proposal were then refreshed; +all four affected fixture-plan checks passed. The original manifest preimage and +failure receipt remain retained, and frozen actual R6 runtime receipts were not +changed or claimed as proof of this successor. No broader native rerun occurred. + +Evidence: Custodian +`docs/changes/netkingdom-target-2026-10-17/native-identity-r1/`: +`owner-source.patch`, `verification.json`, `manifest.json`, retained preimages, +`original-behavior-regression.txt` and `focused-regressions.stderr.txt`. +The later task extraction and exact workplan successor bytes are in +`refinement-r2/`; the original source-proof packet remains immutable. +Canonical owner publication, allocator-assigned Hub UUID and projection must be +recorded separately through the normal owner process; none is claimed here. + +This completes only the source guard/refusal deliverable extracted from T36. +T35 original TLS public provenance/private custody or accepted reissue, T36 exact +archive binding/current owner assent/consumer custody preparation, T33 complete +attempt readiness, T18 actual recovery/consumer acceptance and T19 retained-factor +MFA remain open. No actual archive, private key, Secret object, token exchange, +OpenBao login, rotation, production action or owner assent was exercised. + ## Accept remaining recovery and caller evidence and close the G08 handoff ```task @@ -1189,7 +1245,7 @@ Owner boundary: NetKingdom, Platform and affected service owners, with Custodian G08 receiving the final evidence. The completed archive/job milestones remain accepted independently of this final gate. -**Done when:** T02 and T15–T37 have their stated completed or explicitly accepted +**Done when:** T02 and T15–T38 have their stated completed or explicitly accepted handoff outcomes; service authentication/token/audit proof and current/legacy caller dispositions are accepted; the source workplan and projected tasks agree; and G08 has an exact evidence/handoff record. Record actionable residuals as live