Repository navigation
Closed
Labels
app/idPackage/app: id (pkgs/ or apps/ in this repo)Package/app: id (pkgs/ or apps/ in this repo)kind/bugSomething isn't working (prefixed form of the classic bug label)Something isn't working (prefixed form of the classic bug label)priority/lowNice to have; do when convenientNice to have; do when convenientsource/creatorFiled by the new-issue-creator jobFiled by the new-issue-creator jobtask/small-fixQueue packet kind: bounded fix with reproduction and targeted testsQueue packet kind: bounded fix with reproduction and targeted tests
Description
Bug
pkgs/id/src/tag_claims.rs — check_op for tag.clear is the only hash-set field in a chain extension whose duplicates are not refused. Every sibling set-field validated through ChainExt::validate rejects a repeated hash; a clear naming the same claim twice (or 256 times) passes both the builder and the decoder check, so any node accepts and folds it on receipt.
Evidence (verified this run, origin/main a8aa52d)
tag_claims.rs:132-141— theClearbranch ofcheck_opchecks onlyclaims.len() > MAX_CLEAR_CLAIMS(256). No duplicate check.- Sibling rules in the same validation tree:
chain.rs:219-223— a hash repeated inafterisChainError::DuplicateAfter.notes.rs:124-130— a revision naming a parent twice is aNoteError::Field("a revision names a parent twice").session_checkpoint.rs:235-242— a session naming a participant twice is aCheckpointError::Field.
- Laptop probe (worktree
probe-2026-11-02-laneB-scan6, test against the realidcrate, since removed):check_op(CLEAR_KIND, Clear{claims:[claim, claim]})=Ok(())— duplicates accepted.check_op(CLEAR_KIND, Clear{claims: vec![claim; 257]})=Err("257 claims, the most is 256")— the cap counts copies, so a clear naming ONE distinct claim 257 times is refused while one naming 256 distinct claims passes.check_op(CLEAR_KIND, 256 distinct claims)=Ok(()).
- The folds (
live_claims/compacted_claims, tag_claims.rs) treat the claims as a set, so duplicates change no outcome — the gap is purely at the admission check every other set-field enforces. Local producers never emit duplicates (LocalEvents::clear_tagbuilds its lists from distinct live claims and chunks them, id(local_events): clear_tag can never clear a name with more than 256 live claims — it builds one tag.clear over the 256-claim cap and every attempt fails #1720), so only a foreign or buggy peer's signed event exercises it — exactly the inputcheck_opexists to police on decode (ChainExt::validateis applied by bothchain::signandchain::decode).
Why it matters
- The header is the wire contract: a non-canonical clear (the same claim spelled many times) is admitted, stored, and synced to other peers instead of being refused at the choke point, mirroring the canonical-form discipline the tuple decoder and the other extension checks enforce.
- The 256-claim cap's meaning is currently "256 entries", not "256 claims": padding a clear with copies of one claim trips the cap, and a legitimate-looking count cannot be trusted when auditing a clear's size.
Acceptance criteria
check_op(CLEAR_KIND, …)refuses aClearwhoseclaimsrepeat a hash, with aTagError::Fieldin the style of the sibling messages (e.g. "a clear names a claim twice").- Regression tests alongside
test_a_clear_naming_too_many_claims_is_refused: duplicate claims refused (adjacent and non-adjacent); 256 distinct claims still pass; 257 copies of one claim refused as duplicates (either error accepted, but the duplicate case with ≤256 entries must fail specifically on duplication). - No fold behavior change:
live_claims/compacted_claimsresults for duplicate-free clears are unchanged, and existing tag_claims/chain tests stay green.
Dedup
Searched open + closed for "tag.clear duplicate claims" and "check_op clear": only #1720 (closed — clear_tag chunking over the cap, a different defect, fixed). No issue covers duplicate claim IDs inside one tag.clear.
Metadata
Metadata
Assignees
Labels
app/idPackage/app: id (pkgs/ or apps/ in this repo)Package/app: id (pkgs/ or apps/ in this repo)kind/bugSomething isn't working (prefixed form of the classic bug label)Something isn't working (prefixed form of the classic bug label)priority/lowNice to have; do when convenientNice to have; do when convenientsource/creatorFiled by the new-issue-creator jobFiled by the new-issue-creator jobtask/small-fixQueue packet kind: bounded fix with reproduction and targeted testsQueue packet kind: bounded fix with reproduction and targeted tests
Activity
dezren39 commentedon Nov 3, 2026
🤖 Agent note · filed
dezren39 commentedon Nov 3, 2026
🤖 Agent note · picked up
dezren39 commentedon Nov 3, 2026
🤖 Agent note · done
check_opClear branch in pkgs/id/src/tag_claims.rs now refuses a repeated claim hash withTagError::Field("a clear names a claim twice"), in the sibling style; regression tests for adjacent/non-adjacent duplicates and for 256 distinct claims passing, alongside the existing over-cap test