Repository navigation
fix(webvh): enforce the did:webvh future-skew bound on versionTime (#131) - #148
Conversation
…kew bound (#131) did:webvh v1.0 Read step 4: an entry whose versionTime is more than the tolerance (SHOULD <= 5 minutes) ahead of the resolver's current time MUST fail resolution. 22 cases; 12 fail on assertions against the pre-fix resolver, which never compares versionTime to a clock. The 10 passing cases are accept-side boundaries and controls. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…bound (#131) did:webvh v1.0 Read step 4 requires every entry's versionTime to be no more than a small tolerance (SHOULD <= 5 minutes) ahead of the resolver's current time, and entries beyond it MUST fail resolution. NetDid only enforced adjacent monotonicity, so arbitrarily future-dated logs resolved. LogChainValidator now checks every validated entry (genesis included) against an explicit "now" at the same choke point as the per-entry SCID check, before hash and proof work. DidWebVhMethod observes its Clock once per operation: Resolve shares one observation between the requested-prefix pass and the deactivation-tail pass; Update and Deactivate validate the supplied log against it. Failures map to invalidDidLog (resolution) or LogChainValidationException (Update/Deactivate). Historical resolution of a valid prefix still succeeds below a future-dated tail (spec Read steps 10-11.2), without asserting a deactivation it cannot verify. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PRD timestamp rules and Resolve step 5, README did:webvh section, CHANGELOG [Unreleased] Fixed entry, and the regenerated DIF vector divergence report (negative-versiontime-future now rejected by the skew rule itself). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Correct the Update/Deactivate exception-split wording (a head up to ~1 s ahead succeeds after the whole-second wait; exactly 5 min ahead still gets ArgumentException). - Document that writer clocks must be synchronized too, and how to recover a log published by a fast writer clock. - Make the PRD caching statement precise (historical successes are cached with ordinary TTL staleness). - Plan file review record and lessons. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
moisesja
left a comment
There was a problem hiding this comment.
Looks good to merge at a072ba7. No actionable correctness, security, or scalability defect found after reviewing the full diff and an independent adversarial pass. Genesis and later entries enforce the inclusive five-minute bound; historical prefix/tail validation shares one clock observation and cannot assert a future-invalid deactivation. The exception change is documented. Commit messages are clear, and the large line count is mostly tests/docs; production changes stay within two files.
Independently verified: Release build with 0 warnings/errors; 1,845 tests passed, including WebVh 545/545 and W3C 233/233; 7 opt-in EVM tests skipped; all five samples passed. The unchanged did:key sample needed an unsandboxed rerun because Apple cryptography failed inside the sandbox. CI is also green.
Fixes #131
Problem
did:webvh v1.0, Read step 4: "The
versionTimeof every entry MUST NOT be more than a small, implementation-defined tolerance in the future relative to the resolver's current time. Resolvers SHOULD use a tolerance of no more than 5 minutes. Entries that exceed this tolerance MUST cause resolution to fail."NetDid only checked that entries were in increasing order, so a log dated days or years in the future resolved even though conforming resolvers must reject it.
Change
LogChainValidator: every validated entry, genesis included, must satisfyversionTime - now <= 5 min. The check sits next to the per-entry SCID check and runs before hash and proof work.LogChainValidationException.DidWebVhMethod: the time comes from the existingClockseam and is read once per operation. A resolution uses the same reading for the pass up to the requested version and for the pass that checks later entries for a deactivation. Update and Deactivate validate the supplied log against the same rule.versionTime.Behavior
invalidDidLogif any entry is more than 5 min ahead of the resolver clock.versionId/versionTimeresolution: returns an earlier valid entry even when later entries are future-dated, as spec Read step 11.2 requires. A deactivation found only in those future-dated entries is not reported.LogChainValidationException; before, it threwArgumentException.ArgumentException.Evidence
Issue131_*tests. Fail-first: 12 failed on assertions against the pre-fix code; the other 10 are accept-side and control cases. All 9 code mutations I tried were caught (boundary operator, 4/6-min tolerance, removing either check, tail pass on the system clock or reading the clock twice, Update/Deactivate on the system clock).main.negative-versiontime-futureis now rejected by this rule; before, it was rejected only because the vector's entries are also out of order. Counts are unchanged.tasks/todo20261027-issue131.md.No
NetDidVersionbump; CHANGELOG updated under[Unreleased].🤖 Generated with Claude Code