SIGNOFF: claim-verifier chronology lower bounds (reject pre-emission / negative-time / contradictory-lifecycle false-accepts) - #10
Draft
AnubisQuantumCipher wants to merge 3 commits into
Conversation
added 3 commits
August 18, 2026 13:38
deep_validate_node accepted claim bundles verified BEFORE emission (verification_time < emitted_at, including negative verification time) and with contradictory lifecycles (expires_at < emitted_at). Only the upper bounds (vtime > expires, vtime - emitted > max_age) were enforced, so future-issued and lifecycle-impossible bundles falsely verified. Add both-sided chronology enforcement in deep_validate_node, ordered so domain violations refuse as freshness-schema, a valid-but-too-early check refuses as the new freshness-premature class, and the existing upper bounds run last (keeping vtime - emitted non-negative): - t < 0 -> freshness-schema - expires_at < 0 -> freshness-schema - expires_at < emitted_at -> freshness-schema - t < emitted_at -> freshness-premature (new REASON_CLASS) - t > expires_at (existing) -> freshness-expired - t - emitted > max_age -> freshness-stale enforce_policy documents the node-level >= invariant it now relies on. Harden the hermes adapter (tool_jackal_verify_bundle) to reject a malformed / negative / non-integer verification_time_unix at the caller boundary (plugin-args-schema) before spawning the verifier. TRUST-SURFACE (verifier accept-condition) change: DO NOT MERGE without architect sign-off on the exact semantics above. This is a release blocker for any later release claiming freshness/age checking.
Add hostile chronology rows to family_freshness proving the fix closes
the false-accepts (RED on pre-fix bytes, GREEN after): F-premature-
future-emit, F-negative-vtime, F-expires-before-emit, F-expires-negative,
F-aba-b, plus equality-boundary and A->B->A controls
(F-emit-eq-vtime-ok, F-expiry-eq-emit-eq-vtime-ok, F-aba-a1/a2).
Correct two fixtures that themselves encoded the bug and only "passed"
via the one-sided check:
- F-expired: set emitted=VTIME-1000 so expires=VTIME-10 no longer
precedes emission (the old fixture was expires < emitted).
- release/evidence/ci_claim_fixture_v160/pins.json: bump
verification_time_unix 1786752000 -> 1786924800, which was ~1.95 days
BEFORE the fixture's emitted_at_unix=1786920569 (a live instance of
the bug in release evidence). verification_time_unix is a caller-side
pin, not part of bundle_sha256 and not referenced by any manifest, so
the bundle bytes are unchanged.
Regenerate release/evidence/claim_hostile_matrix_v160.json:
CLAIM_HOSTILE_PASS rows=117 failures=0; ci_claim_admission still
CI_CLAIM_ADMISSION_PASS checks=3.
SPEC.md sec 3: enumerate the both-sided chronology bounds the verifier now enforces and their exact refusal classes. SPEC.md sec 10: state that freshness timestamps are SELF-DECLARED by the producer -- the verifier enforces internal lifecycle consistency, NOT timestamp authenticity or temporal provenance (no trusted time source), and one-time replay prevention remains an explicit residual non-claim.
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This changes what the claim-kernel verifier accepts. It is a security fix for a reproduced false-accept, but activating a new accept condition is a trust-surface decision. Merge/tag/release only after the architect approves the exact diff.
Defect (reproduced on live bytes)
tools/claim_bundle_verify.pyenforced only upper chronology bounds (vtime > expires,vtime - emitted > max_age). It accepted bundles that are chronologically impossible:emitted=1000, max_age=0, verify atvtime=-1emitted=1000, max_age=0, verify atvtime=999emitted=1000, expires=900(expiry precedes emission), verify at899/900Reproduced against the installed plugin and against this repo's verifier (
tests/claim_hostile_test.pyhelpers). This is a software-semantic false-accept distinct from the (correct) formal mathematics; it affects freshness/age/expiry and any "age-checked" rendering.Root cause
deep_validate_nodefreshness block (pre-fixtools/claim_bundle_verify.py:2167-2173): novtime >= emitted, novtime >= 0, noexpires >= emitted.--verification-time-unixistype=int(accepts negatives).enforce_policypolicy-max-age used the same one-sided subtraction.Proposed semantics (exact, ordered)
For each node, against caller time
t:t < 0→ refusefreshness-schema(non-negative Unix time).expires_at < 0orexpires_at < emitted_at→ refusefreshness-schema(lifecycle consistency).t < emitted_at→ refusefreshness-premature(new class; the dual offreshness-expired).t > expires_at(when set) → refusefreshness-expired(unchanged).t - emitted_at > max_age_seconds(when set) → refusefreshness-stale(unchanged).Equality boundaries verify (
emitted == t,t == expires).freshness-prematureis added toREASON_CLASSES(locked bytests/claim_receipt_context_unsupported_v172_test.py::test_no_undeclared_reason_classes, incl.python -O). Negative/contradictory cases reusefreshness-schemato match the existingemitted<0 → freshness-schemaconvention.Sibling paths covered (not just one)
tools/claim_bundle_verify.py—deep_validate_node(authoritative trust boundary) +enforce_policyinvariant.plugin/hermes/server.py::tool_jackal_verify_bundle— rejects malformed/negative/non-integerverification_time_unixat the caller boundary (plugin-args-schema).plugins/jackel/mcp/server.py— no direct verify handler (proxies to the shared verifier; covered by the core fix).Evidence (all commands re-runnable;
JACKAL_BIN= sealed v1.7.0 runtimejackal-native)tests/claim_hostile_test.py::family_freshness): 5 rows fail pre-fix (F-premature-future-emit,F-negative-vtime,F-expires-before-emit,F-expires-negative,F-aba-b) → 0 fail post-fix; controls (F-emit-eq-vtime-ok,F-expiry-eq-emit-eq-vtime-ok,F-aba-a1/a2) pass both.CLAIM_HOSTILE_PASS rows=117 failures=0.python3 release/tools/ci_claim_admission.py→CI_CLAIM_ADMISSION_PASS checks=3.tests/claim_receipt_context_unsupported_v172_test.py→ 9/9 OK.refused reason=freshness-prematurein both normal and-O.-1→freshness-schema,999→freshness-premature,1000→verified,1001→freshness-stale; contradictory899/900/901→freshness-schema.Fixtures corrected (with justification, not masking)
tests/claim_hostile_test.pyF-expired: old fixture setexpires=VTIME-10with defaultemitted=VTIME— itselfexpires<emitted(contradictory), only "passing" via the one-sided check. Corrected to a genuine expired bundle (emitted=VTIME-1000, expires=VTIME-10).release/evidence/ci_claim_fixture_v160/pins.json:verification_time_unixwas1786752000, before the fixture'semitted_at_unix=1786920569(~1.95 days before emission — a live instance of the bug in release evidence). Bumped to1786924800(after emission).verification_time_unixis a caller-side pin, not part ofbundle_sha256, and is not referenced by any manifest/SHA256SUMS, so no hash cascade; the bundle bytes are unchanged.release/evidence/claim_hostile_matrix_v160.json: regenerated deterministic evidence (adds the new rows).Not in this PR (recommended follow-ups)
tools/claim_kernel.py::freshness_blockstill constructsexpires<emittedbundles; the verifier now rejects them (verifier is the trust boundary), but refusing at compile is a cheap defense-in-depth follow-up.master; that is the sign-off action, deliberately not taken here.Required at landing (before/at merge; not in this proposal)
tools/claim_bundle_verify.pychanges its sha256 (e0fcb954…→90d6480e…), pinned atrelease/MANIFEST.sha256:38(claim_verifier) and recorded inrelease/evidence/claim_aba_v160.json+claim_dogfood_v160.json. Runlake -C proofs/lean buildthenrelease/tools/repin_v172.pyto re-pin the manifest, regenerate the aba/dogfood evidence, and refresh the hermes plugin bundle/identity hashes. Hosted CI on this PR does not check that pin (gaussian-proof-gateruns the verifier without hashing it;jackal-codex-pluginverifiesplugins/jackel/PLUGIN_IDENTITY.sha256, not the hermes pin), so CI is green as-is; the re-pin is required for the hermes plugin's runtime self-check and the full localrun_gates_v172aggregate at release.Independent review (two read-only reviewers)
expires<emitted, negative expires, multi-node non-root evasion, parse/ordering edges) closed with correct stable classes; legitimate bundles still verify; instrument-validated against the pre-fix tree (identical inputs verify pre-fix, refuse post-fix);-Odoes not downgrade. No BLOCKING/IMPORTANT soundness defect.emitted<0clause).Non-claims (unchanged posture)
Timestamps remain self-declared by the producer. These checks enforce internal lifecycle consistency, not timestamp authenticity, temporal provenance, or replay prevention (still an explicit residual non-claim; requires an external nonce store). Documented in
release/claim/SPEC.md§3, §10.Release-blocker
Per the chronology mission, this is a release blocker for any later JACKAL release (e.g. v1.8) that claims freshness/age checking. Do not ship such a release around it.