NO-TOOLS scoped follow-up on one remaining blocking defect. Enterprise Assertion Provenance 0.1.0 is a bounded trusted-host reviewable draft. Previous compact closure audit: Claude BLOCK on metadata revision receipts laundering an old review; Grok ACCEPT WITH LIMITS. Both raw responses remain preserved; no vote averaging. We adopted the exact genesis-receipt fix and five regression tests. Current code now computes review_at=prior[(a['id'],1)]['recordedAt'] and compares BOTH previous-assessment receipt and explicit basis receipts to that identity-genesis receipt. Corrections of the same Activity cannot change it. Different review ID, current-active full dependency closure and available/non-mismatched captures remain required for non-insufficient genesis or label/basis/activity changes. Host authentication/current root/config/clock/concurrency and generic write-only receipts/errors remain external. This proves registration order, NOT real-world execution or evidence relevance. Review only this fix and regressions against the preceding findings; return ACCEPT WITH LIMITS or BLOCK with concrete residuals. No tools, execution, web or publication permission. Full current provenance.py, exact contract paragraph, original blocking report, fixture helpers and the five appended tests are supplied. The other 76 tests were supplied fully in the preceding compact pass to both reviewers and are unchanged; this prompt does not repeat them or the schema/harness. Reported local result now 81 tests and three native Dimensions passed. Do not claim your own execution or whole-package conformance. Confirm final sentinel and any truncation. PRECEDING CLAUDE FINDING (untrusted review evidence) # Scoped closure audit: EAP 0.1.0 genesis/basis-swap and fresh-review fixes **Verdict: BLOCK on this exact candidate.** The fix is narrow and cheap. Everything else in scope looks acceptable with the stated limits. ## Input integrity - **Truncation:** none observed. Both files end with their `END FILE` markers. - **Test count:** I counted 76 test methods in `Tests`, numbered 1 `test_three_profiles` through 76 `test_canonical_encoding_control_and_unicode_vector`, plus the fixture helpers. - **Contract excerpts:** received through `END EXCERPTS`. - **Final sentinel:** `AP-CLOSURE-76-FULL-TESTS` received. - **Not verified:** I executed nothing. I could not check the stated SHA-256 values or the reported 76 passes and native results. - **Omitted context:** the schema, native harness and full contract were not re-read. This verdict does not ratify them. ## Blocking finding: fresh-review timing uses the revision receipt, so metadata revisions restore the bypass In `semantic`, the two new timing guards compare against `a['recordedAt']`. That is the receipt of the pinned Activity *revision*, not of the review event: ```python require(old is None or old['recordedAt']1] return {'profileVersion':VERSION,'claim':copy.deepcopy(claim),'knownAt':knownAt,'inputSliceDigest':digest({**ledger,'records':known}),'configurationDigest':digest(config), 'status':'context-available' if any(r['state']=='active' and r['epistemicKind']!='unverified' for r in accounts) else 'insufficient-context', 'accounts':copy.deepcopy(accounts),'links':copy.deepcopy(links),'assessments':copy.deepcopy(assessments),'impacts':impacts, 'independence':{'status':'known-shared-origin' if shared else 'unknown','shared':shared}, 'truth':'not-evaluated','permissions':'not-inferred'} def import_snapshot(snapshot,config,*,now): config_check(config,now);validate_ledger(snapshot,config,now);return copy.deepcopy(snapshot) def migrate(snapshot,config,targetVersion,*,now): require(targetVersion==VERSION,'Unsupported or lossy migration requires explicit mapping') return import_snapshot(snapshot,config,now=now) def validate_snapshot(fact,config,previous=None,*,now): """Check companion snapshot pins; use V3 separately for the full envelope.""" require(isinstance(fact,dict) and fact.get('recordType')=='fact' and fact.get('path')=='provenance.register.snapshot','Wrong snapshot envelope') require(isinstance(fact.get('factId'),str) and bool(fact['factId']),'Missing snapshot identity') config_check(config,now);ledger=fact.get('value');validate_ledger(ledger,config,now) require(fact.get('subjectId')==ledger['dimension']+':provenance-register','Wrong aggregate subject') provenance=fact.get('provenance',{}) require(isinstance(provenance,dict) and provenance.get('snapshotDigest')==digest(ledger),'Wrong snapshot digest') if previous is None: require(provenance.get('previousSnapshotDigest') is None and fact.get('supersedes')==[],'Missing trusted previous snapshot') else: require(isinstance(previous,dict) and previous.get('recordType')=='fact' and previous.get('subjectId')==fact['subjectId'] and previous.get('path')==fact['path'],'Snapshot lineage mismatch') require(previous.get('factId')!=fact['factId'],'Snapshot identity reused') previous_ledger=previous.get('value');validate_extension(previous_ledger,ledger,config,now) previous_provenance=previous.get('provenance') require(isinstance(previous.get('factId'),str) and isinstance(previous_provenance,dict) and previous_provenance.get('snapshotDigest')==digest(previous_ledger),'Wrong previous snapshot digest') require(provenance.get('previousSnapshotDigest')==digest(previous_ledger) and fact.get('supersedes')==[previous.get('factId')],'Wrong snapshot predecessor') return True END CODE EXACT FIXTURE HELPERS """Synthetic behavior tests and fixtures for the original reference contract.""" import copy,json,unittest from unittest.mock import patch from datetime import datetime,timedelta from pathlib import Path import provenance as p HERE=Path(__file__).resolve().parent U='urn:synthetic:' CLAIM={'id':U+'claim:capacity','revision':1,'digest':'sha256:'+'a'*64} METHOD={'id':U+'method:inspection','revision':1,'digest':'sha256:'+'b'*64} NOW='2026-09-21T12:00:00Z' def config():return {'id':U+'configuration','dimension':U+'dimension','validFrom':'2026-01-01T00:00:00Z','validUntil':'2030-01-01T00:00:00Z','writers':[{'kind':k,'scope':U+'scope','actors':[U+'writer']} for k in p.ANCHORS],'readers':[U+'reader'],'purposes':['research']} def empty():return {'format':'vercy-assertion-provenance','version':'0.1.0','dimension':U+'dimension','records':[]} def stamp(i):return (datetime(2026,9,21,10,0,0)+timedelta(seconds=i)).strftime('%Y-%m-%dT%H:%M:%SZ') def row(kind,n,**kw): return {'id':U+n,'kind':kind,'scope':U+'scope','revision':1,'previousDigest':None,'recordedAt':stamp(1),'writer':U+'writer','state':'active','change':'create','reason':'Synthetic evidence-backed entry','notes':[],**kw} def capture(n='capture',**kw):return row('Capture',n,**({'sourceRef':U+'source:document','sourceVersion':'v1','sourceAuthor':U+'document-author','aboutRef':U+'system','obtainedAt':'2026-09-21T09:00:00Z','mode':'file','availability':'captured','representationDigest':'sha256:'+'c'*64,'originRef':U+'declared-origin','integrity':'not-tested'}|kw)) def activity(c,n='acquisition',**kw):return row('Activity',n,**({'actor':U+'observer','mode':'file-acquisition','startedAt':'2026-09-21T08:00:00Z','endedAt':'2026-09-21T09:30:00Z','inputs':[p.pin(c)],'observedTarget':None,'method':METHOD}|kw)) def account(a,n='account',**kw):return row('ProvenanceRecord',n,**({'claim':CLAIM,'aboutRef':U+'system','asserter':U+'asserter','epistemicKind':'source-asserted','activity':p.pin(a) if a else None,'limitations':['Source statement; no live-system verification.']}|kw)) def link(c,n='evidence',**kw):return row('EvidenceLink',n,**({'claim':CLAIM,'evidence':p.pin(c),'attributedTo':U+'relation-author','relation':'cites','selector':'whole captured representation','rationale':'Reference context without automatic support'}|kw)) def add(ledger,r,cfg=None): r=copy.deepcopy(r);r['recordedAt']=stamp(len(ledger['records'])+1) return p.admit(ledger,r,cfg or config(),r['writer'],r['recordedAt']),r def revision(r,**kw):return {**copy.deepcopy(r),'revision':r['revision']+1,'previousDigest':p.digest(r),'change':'correct',**kw} def fixture(name='startup'): g=empty();g,c=add(g,capture());g,a=add(g,activity(c));g,pr=add(g,account(a));g,l=add(g,link(c)) if name=='group': g,c2=add(g,capture('copy',sourceRef=U+'source:second-report')) g,a2=add(g,activity(c2,'second-acquisition'));g,pr2=add(g,account(a2,'second-account')) g,l2=add(g,link(c2,'counterevidence',relation='refutes',rationale='Second writer explicitly disputes the same pinned claim')) if name=='ai-team': g,s=add(g,activity(c,'synthesis',actor=U+'ai-agent',mode='synthesis',inputs=[p.pin(pr)])) g,inferred=add(g,account(s,'inference',epistemicKind='inferred',asserter=U+'ai-agent')) g,review=add(g,activity(c,'review',actor=U+'human-reviewer',mode='review',inputs=[p.pin(inferred)])) g,assessment=add(g,row('ConfidenceAssessment','assessment',account=p.pin(inferred),assessor=review['actor'],activity=p.pin(review),method=METHOD,scheme=p.SCHEME,purpose='Plan a separate live check',label='limited',basis=[p.pin(c)],limitations=['File analysis is not live observation.'])) return g def view(g,**kw):return p.view(g,config(),U+'reader','research',CLAIM,NOW,NOW,**kw) END HELPERS FIVE APPENDED TESTS def test_old_alternate_review_metadata_cannot_refresh_execution(self): g=fixture('ai-team');assessment=g['records'][-1];g['records']=g['records'][:-1] review=copy.deepcopy(g['records'][-1]);review['id']=U+'earlier-alternate-review';g,r=add(g,review);g,assessment=add(g,assessment) g,corrected=add(g,revision(r,notes=['Metadata correction after assessment'])) with self.assertRaisesRegex(p.Invalid,'first registered after'):add(g,revision(assessment,label='supported',activity=p.pin(corrected))) def test_insufficient_roundtrip_cannot_reuse_old_execution(self): g=fixture('ai-team');a=g['records'][-1];r1=g['records'][-2];r2=copy.deepcopy(r1);r2['id']=U+'second-review';g,r2=add(g,r2) g,a=add(g,revision(a,label='insufficient',activity=p.pin(r2)));g,r1=add(g,revision(r1,notes=['Later notes'])) with self.assertRaisesRegex(p.Invalid,'first registered after'):add(g,revision(a,label='limited',activity=p.pin(r1))) def test_review_metadata_cannot_move_registration_after_basis(self): g=fixture('ai-team');a=copy.deepcopy(g['records'][-1]);a['id']=U+'new-assessment';review=g['records'][-2] g,c=add(g,capture('late-basis'));g,r=add(g,revision(review,notes=['Later metadata']));a.update(activity=p.pin(r),basis=[p.pin(c)]) with self.assertRaisesRegex(p.Invalid,'first registered before'):add(g,a) def test_genuinely_later_registered_review_can_be_metadata_corrected(self): g=fixture('ai-team');a=g['records'][-1];review=copy.deepcopy(g['records'][-2]);review['id']=U+'new-review';g,r=add(g,review) g,r=add(g,revision(r,notes=['Metadata maintenance']));g,_=add(g,revision(a,label='supported',activity=p.pin(r))) self.assertEqual(view(g)['assessments'][0]['label'],'supported') def test_current_mismatched_capture_guard_isolated(self): g=fixture('ai-team');a=copy.deepcopy(g['records'][-1]);a['id']=U+'different-assessment';review=copy.deepcopy(g['records'][-2]);review['id']=U+'new-review' g,c=add(g,capture('bad-current-capture',integrity='mismatched'));g,r=add(g,review);a.update(activity=p.pin(r),basis=[p.pin(c)]) with self.assertRaisesRegex(p.Invalid,'unavailable or mismatched capture'):add(g,a) END TESTS EXACT CONTRACT PARAGRAPH A correction follows the immediate previous revision and digest, retains all prior rows and immutable anchors, and remains active. Unchanged historical dependencies may be retained when correcting notes, limitations, selectors, rationale or reducing an assessment label to insufficient. Every new assessment with a non-insufficient label, and every change to a non-insufficient assessment's label, basis or activity, requires every immediate and transitive dependency to be a current active revision; Capture dependencies must be available without declared integrity mismatch. On such a correction the review Activity must have a different ID and be first registered (revision 1 receipt) after the previous assessment. Every such review must be first registered (revision 1 receipt) no earlier than its explicit basis revisions. This check does not certify the new judgement or truth. Keeping label, basis and activity unchanged permits metadata maintenance, with changed-dependency warnings intact. Reduction to insufficient remains available when dependencies have changed; reduction from supported to limited uses the same current-basis rule as other non-insufficient reassessment. A pin moved to a different field is a new reference, even if its bytes were already present elsewhere in the record. Newly introduced/replaced immediate pins must be current and active. Correcting a judgement about an older account does not retarget it to the latest account; a fresh review needs a new review Activity and assessment. Withdrawal is terminal and changes only revision, previousDigest, receipt, writer, state, change and reason. It cannot rewrite the withdrawn content. Resurrecting, deleting or truncating records is unsupported. Retracting a capture/account/link or correcting its basis does not automatically negate an external claim or alter downstream epistemic kinds; a view reports the affected dependency pins for reassessment. END CONTRACT FINAL SENTINEL AP-FIRST-REGISTRATION-81