Skip to content

export PrincipalBucketHash - #1069

Open
mj-palanker wants to merge 6 commits into
mainfrom
mjp/PrincipalBucketHash
Open

export PrincipalBucketHash#1069
mj-palanker wants to merge 6 commits into
mainfrom
mjp/PrincipalBucketHash

Conversation

@mj-palanker

@mj-palanker mj-palanker commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

PrincipalBucketHash is now public as we will want to calculate this hash on the c1 side to store an index of grants by their bucket hash.

This is the bucket hash, not the content hash which is already exported.

Review hardening (cb358eb, a7ce6b8, 18e8dac):

  • Added PrincipalDigestBucket(rt, id, level) so callers get the bucket index from a signature that enforces level <= DigestBucketHashBits instead of hand-deriving it.
  • Default-behavior change: GetEntitlementGrantDigestNodes / ScanEntitlementGrantBucket now return an error for a level past the bucket-hash resolution (16 bits) instead of clamping, and ScanEntitlementGrantBucket also rejects Index >= 2^Level instead of wrapping to the low bits. Previously such calls silently returned the wrong bucket's data; buckets built via PrincipalDigestBucket are always in range.
  • Compile-time assertions couple the stored hash width, the leaf-prefix width, and the read-side bound; golden-vector test pins the hash's literal output as ABI.

Comment thread pkg/dotc1z/engine/pebble/grant_digest.go
Comment thread pkg/dotc1z/engine/pebble/grant_digest_hash_test.go
Comment thread pkg/dotc1z/engine/pebble/digest_test.go Outdated
Comment thread pkg/dotc1z/engine/pebble/grant_digest.go Outdated
@github-actions

github-actions Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

General PR Review: export PrincipalBucketHash

Blocking Issues: 0 | Suggestions: 1 | Threads Resolved: 0
Criteria: Criteria status: loaded .claude/skills/ci-review.md from trusted base 032483fbe4b1.
Review mode: incremental since a7ce6b85
View review run

Review Summary

The new commit (18e8dac) adds two compile-time assertions coupling digestLeafPrefixLen to digestMaxWidthBits, which addresses the prior finding at pkg/dotc1z/engine/pebble/digest.go:138 — the >> (16 - bits) shifts in bucketOfHash, foldedLeafBuckets, computeBucketsAtWidth and the bh[:digestLeafPrefixLen] slice in bucketOfHash are now all pinned by the build, so widening DigestBucketHashBits alone can no longer compile into a negative-shift panic at read time. The prior migration-note finding on pkg/connectorstore/connectorstore.go:206 is addressed by the PR description, which now calls the clamp→error change out explicitly as a default-behavior change. The full PR diff was scanned for security and correctness: no new blocking issues; one prior doc-drift suggestion is still open and carried forward below.

Risk triage (incremental commit): Silence no — a divergence now fails the build rather than escaping. Durability no — no stored key, leaf framing, or manifest change; digestBucketHashLen/digestLeafPrefixLen/digestMaxWidthBits all remain 16 bits. Uncontrolled dimensions no — compile-time only, no schedule, crash-timing, or version-pair dependence. Consumer distance — same package. Verdict LOW for this commit; the PR as a whole stays MEDIUM on the public clamp→error default change, which TestPrincipalBucketHashMatchesServedBuckets and the level-17 / index-out-of-range subtests already instrument through the public read APIs.

Security Issues

None found.

Correctness Issues

None found.

Suggestions

  • pkg/dotc1z/engine/pebble/digest.go:635 (carried from the previous review, still open) — computeBucketsAtWidth's doc still says "the caller clamps to the bucket-hash resolution"; the caller now rejects out-of-range levels instead.
Prompt for AI agents
Verify each finding against the current code and only fix it if needed.

## Suggestions

In `pkg/dotc1z/engine/pebble/digest.go`:
- Around line 635: The doc comment on computeBucketsAtWidth reads "bits must be in
  [1, digestMaxWidthBits]; the caller clamps to the bucket-hash resolution." The caller
  (Engine.GetEntitlementGrantDigestNodes in adapter_reader.go) no longer clamps — it now
  returns an error for level > digestMaxWidthBits. Update the sentence to say the caller
  rejects a level outside [0, digestMaxWidthBits] rather than clamping, so the precondition
  reads as "the caller guarantees this range" instead of describing removed behavior.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No blocking issues found.

@mj-palanker
mj-palanker force-pushed the mjp/PrincipalBucketHash branch from c499711 to e7c4bb5 Compare August 14, 2026 23:39
Comment thread pkg/dotc1z/engine/pebble/grant_digest.go Outdated
Review feedback on the export:

- Add PrincipalDigestBucket(rt, id, level) so callers get the bucket
  index from a signature that enforces level <= DigestBucketHashBits,
  instead of hand-deriving it from a doc-comment formula.
- GetEntitlementGrantDigestNodes / ScanEntitlementGrantBucket now error
  on a level past digestMaxWidthBits instead of clamping: a clamped
  Level paired with a caller's unclamped Index silently scanned the
  wrong bucket.
- Compile-time assertions couple digestBucketHashLen*8 to
  digestMaxWidthBits, which the exported constant's width promise
  depends on.
- Golden-vector test pins PrincipalBucketHash's literal output (ABI,
  tied to GrantDigestABIVersion); the existing tests only proved it
  consistent with the primitives it calls.
- The served-buckets test now covers the stored-leaf fold path
  (levels 1-3) as well as the index-scan fallback, and asserts the
  level-17 error on every entry point.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Comment thread pkg/dotc1z/engine/pebble/digest_test.go Outdated
Comment on lines +731 to +733
if level > digestMaxWidthBits {
return nil, false, fmt.Errorf("pebble: grant-digest level %d exceeds bucket-hash resolution %d", level, digestMaxWidthBits)
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Suggestion: this is a deliberate default-behavior break on an exported interface method — a caller that previously passed level > 16 got a clamped result set, and now gets an error (same for ScanEntitlementGrantBucket). The rationale is well argued in the doc comments, but the PR body only describes the PrincipalBucketHash export, and pkg/sdk/version.go stays at v0.24.1. Per this repo's SDK criteria, a default-behavior change should carry a 0.x minor bump and a line in the PR description so downstreams have a signal beyond reading the diff. (confidence: medium — the surface looks new enough that no external caller is likely relying on the clamp) (confidence: medium)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR description now calls out the default-behavior change (error instead of clamp past the bucket-hash resolution). Left pkg/sdk/version.go alone: version bumps in this repo land as standalone "Update SDK version to vX" release commits, not inside feature PRs — flagging that the next release should be a minor (0.25.0) rather than a patch. Leaving this thread open for a maintainer call on the bump.

Comment thread pkg/connectorstore/connectorstore.go

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No blocking issues found.

- PrincipalBucketHash's recipe now says which levels are cheap (native,
  folded leaves) and that finer levels cost an O(grants) index scan.
- connectorstore's error contract points at the native Level as the
  always-in-range bound and at pebble.DigestBucketHashBits for the full
  width, so interface-only consumers can discover the limit.
- Fix the served-buckets test comment: level 4 exceeds the native width
  (3) and takes the index-scan path, not the stored-leaf fold.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Comment thread pkg/dotc1z/engine/pebble/adapter_reader.go
Comment thread pkg/dotc1z/engine/pebble/digest_test.go
@mj-palanker

Copy link
Copy Markdown
Contributor Author

squire has apparently been impersonating me in this PR... those comments are not mine 😨

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No blocking issues found.

ScanEntitlementGrantBucket bounded Level but passed Index through, and
bucketBounds shifts an oversized index's high bits away — so
{Level: 4, Index: 20} silently scanned bucket 4. Reject
Index >= 2^Level (Level 0 keeps its Index-ignored contract), the same
treatment the Level axis got.

The served-buckets test now also runs level 16 — DigestBucketHashBits
itself, the finest permitted level, where the shifts on both sides
consume the full stored width — pinning the accept side of the bound
whose reject side the level-17 subtest pins.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Comment thread pkg/dotc1z/engine/pebble/digest.go Outdated
Comment thread pkg/connectorstore/connectorstore.go

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No blocking issues found.

The ">> (16 - bits)" shifts in bucketOfHash, foldedLeafBuckets and
computeBucketsAtWidth assume the leaf-prefix width and the resolution
bound agree; growing digestMaxWidthBits (which DigestBucketHashBits's
doc invites) without digestLeafPrefixLen would compile and then panic
on a negative shift at read time. Same assertion pattern as the
bucket-hash pair.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No blocking issues found.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants