heimdall-delegation: delegation resolver (Rust, zero deps) #6

Merged
libby merged 3 commits from libby/heimdall-delegation into main 2026-11-05 11:02:24 +00:00
Member

Heimdall's delegation resolver per the #swarm 2026-11-04 spec. packages/heimdall-delegation; entry point resolve in src/lib.rs, rules in the README.

Pure and deterministic. One public receipt per seated person per topic, naming the estate the weight counts in (the originator's), the chain, and the narrowed scope. Cycles, depth overruns, unseated/cross-estate delegates, chains that end without a vote, and cap-trimmed votes are returned uncast. cast + uncast = total weight. No stake function: weight is a caller input.

Property tests (seeded generator, 400 random worlds each, no deps): order independence under shuffles, conservation/no inflation, direct override, cycles, depth boundary, deterministic cap trimming, scope narrowing, revoked == removed, same-estate switch. 22 pass at 5cb5f35d.

Choices for Heimdall to confirm or overrule:

  • Cap counts only weight delegated in from an estate (the holder's own direct vote is excluded), limit = floor(estate_total x cap).
  • Trim order is pro-rata: every delegator into an over-cap holder from that estate is scaled by the same factor, in integer weight by largest remainder, with ascending originator id only as the tie-break for exact remainder ties. Placeholder until the estates rule.
  • The final-holder cap does not bind under full ballot copying (Bifrost PR #4, 5d352c6c); see the README caveat.
  • Scope is a set of topics or All; one person may hold several live delegations only if scopes are disjoint (else input error).
  • Revocation is a flag on the delegation; the caller owns the ledger.

🤖 Generated with Claude Code

Heimdall's delegation resolver per the #swarm 2026-11-04 spec. `packages/heimdall-delegation`; entry point `resolve` in `src/lib.rs`, rules in the README. Pure and deterministic. One public receipt per seated person per topic, naming the estate the weight counts in (the originator's), the chain, and the narrowed scope. Cycles, depth overruns, unseated/cross-estate delegates, chains that end without a vote, and cap-trimmed votes are returned uncast. `cast + uncast = total weight`. No stake function: weight is a caller input. Property tests (seeded generator, 400 random worlds each, no deps): order independence under shuffles, conservation/no inflation, direct override, cycles, depth boundary, deterministic cap trimming, scope narrowing, revoked == removed, same-estate switch. 22 pass at 5cb5f35d. Choices for Heimdall to confirm or overrule: - Cap counts only weight delegated *in* from an estate (the holder's own direct vote is excluded), limit = floor(estate_total x cap). - Trim order is pro-rata: every delegator into an over-cap holder from that estate is scaled by the same factor, in integer weight by largest remainder, with ascending originator id only as the tie-break for exact remainder ties. Placeholder until the estates rule. - The final-holder cap does not bind under full ballot copying (Bifrost PR #4, 5d352c6c); see the README caveat. - Scope is a set of topics or All; one person may hold several live delegations only if scopes are disjoint (else input error). - Revocation is a flag on the delegation; the caller owns the ledger. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
heimdall-delegation: delegation resolver with property tests
Some checks failed
CultMesh QUIC native / Build win32-x64 (pull_request) Has been skipped
CultMesh QUIC native / Build linux-x64 (pull_request) Has been skipped
CultMesh QUIC native / Release native binaries (pull_request) Has been skipped
CultMesh portability and performance / ubuntu-latest one-command multiplayer onboarding (pull_request) Has been cancelled
CultMesh portability and performance / windows-latest one-command multiplayer onboarding (pull_request) Has been cancelled
CultMesh portability and performance / ubuntu-latest reactive semantics and leases (pull_request) Has been cancelled
CultMesh portability and performance / windows-latest reactive semantics and leases (pull_request) Has been cancelled
CultNet cross-runtime interop / C# / TypeScript / Rust / Python / Kotlin (pull_request) Has been cancelled
CultMesh QUIC native / Verify committed binaries match SHA256SUMS (pull_request) Has been cancelled
30318c18fc
Re-delegation to max depth, estate-of-delegator counting, per-estate cap on
the final holder, scope narrowing, direct override, revocation, uncast on
cycle/depth/trim, same-estate-only switch, per-person public receipts.
No stake function; weights are caller-supplied.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
heimdall-delegation: pro-rata cap, revocation time on receipts, prior art
Some checks failed
CultMesh QUIC native / Build win32-x64 (pull_request) Has been skipped
CultMesh QUIC native / Build linux-x64 (pull_request) Has been skipped
CultMesh QUIC native / Release native binaries (pull_request) Has been skipped
CultMesh portability and performance / ubuntu-latest one-command multiplayer onboarding (pull_request) Has been cancelled
CultMesh portability and performance / windows-latest one-command multiplayer onboarding (pull_request) Has been cancelled
CultMesh portability and performance / ubuntu-latest reactive semantics and leases (pull_request) Has been cancelled
CultMesh portability and performance / windows-latest reactive semantics and leases (pull_request) Has been cancelled
CultNet cross-runtime interop / C# / TypeScript / Rust / Python / Kotlin (pull_request) Has been cancelled
CultMesh QUIC native / Verify committed binaries match SHA256SUMS (pull_request) Has been cancelled
e2a39d8aef
Replace ascending-id trimming with pro-rata scaling by largest remainder
(ascending originator id breaks exact remainder ties only). Receipts carry
counted weight and the originator's latest covering revocation time.
Delegation::revoked becomes Option<u64>. Property tests: trim
order-independence, cap never exceeded, no delegator scaled more than another.
README: prior-art section, placeholders labelled.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Author
Member

Applied Heimdall'''s #swarm rulings of 2026-11-05 at e2a39d8a.

  • Cap is pro-rata: every delegator into an over-cap (holder, estate) is scaled by limit/sum, integer weight by largest remainder; ascending originator id breaks only exact remainder ties. Receipts carry counted; cast + uncast = total weight. Holder'''s own direct vote stays outside the cap.
  • Receipts carry revoked_at (latest revocation time among the originator'''s own revoked delegations covering the topic). Delegation::revoked is now Option<u64> (Some = revoked): one field, so flag and time cannot disagree. Still inert, caller owns the ledger.
  • Overlapping scopes remain an input error.
  • New property tests: trim order-independent under shuffles (asserts the generator really trims), delegated weight never exceeds cap and fills it exactly when over, no delegator scaled more than another (floor/ceil of exact share, equal weights within 1, ties to lower id). Plus worked examples for scaling, partial trim, revocation time.
  • README: prior-art section (LiquidFeedback cycles, Kling 2015, Gölz 2018, fetched today) with design consequences; the four choices labelled placeholders until the estates rule. Note: the Gölz paper rejects caps as non-solving (copy-the-ballot argument); recorded there.

Test results: cargo test --offline in packages/heimdall-delegation: 22 passed, 0 failed (400 random worlds per property). Not run: CI, other packages. Not merged.

🤖 Generated with Claude Code

Applied Heimdall'''s #swarm rulings of 2026-11-05 at e2a39d8a. - Cap is pro-rata: every delegator into an over-cap (holder, estate) is scaled by limit/sum, integer weight by largest remainder; ascending originator id breaks only exact remainder ties. Receipts carry `counted`; cast + uncast = total weight. Holder'''s own direct vote stays outside the cap. - Receipts carry `revoked_at` (latest revocation time among the originator'''s own revoked delegations covering the topic). `Delegation::revoked` is now `Option<u64>` (Some = revoked): one field, so flag and time cannot disagree. Still inert, caller owns the ledger. - Overlapping scopes remain an input error. - New property tests: trim order-independent under shuffles (asserts the generator really trims), delegated weight never exceeds cap and fills it exactly when over, no delegator scaled more than another (floor/ceil of exact share, equal weights within 1, ties to lower id). Plus worked examples for scaling, partial trim, revocation time. - README: prior-art section (LiquidFeedback cycles, Kling 2015, Gölz 2018, fetched today) with design consequences; the four choices labelled placeholders until the estates rule. Note: the Gölz paper rejects caps as non-solving (copy-the-ballot argument); recorded there. Test results: `cargo test --offline` in packages/heimdall-delegation: 22 passed, 0 failed (400 random worlds per property). Not run: CI, other packages. Not merged. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
heimdall-delegation: README caveat that the cap does not bind under ballot copying
Some checks are pending
CultMesh portability and performance / ubuntu-latest one-command multiplayer onboarding (pull_request) Waiting to run
CultMesh portability and performance / windows-latest one-command multiplayer onboarding (pull_request) Waiting to run
CultMesh portability and performance / ubuntu-latest reactive semantics and leases (pull_request) Waiting to run
CultMesh portability and performance / windows-latest reactive semantics and leases (pull_request) Waiting to run
CultNet cross-runtime interop / C# / TypeScript / Rust / Python / Kotlin (pull_request) Waiting to run
CultMesh QUIC native / Verify committed binaries match SHA256SUMS (pull_request) Waiting to run
CultMesh QUIC native / Build win32-x64 (pull_request) Has been skipped
CultMesh QUIC native / Build linux-x64 (pull_request) Has been skipped
CultMesh QUIC native / Release native binaries (pull_request) Has been skipped
5cb5f35dcc
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Author
Member

README caveat added (5cb5f35d): the final-holder cap bounds the ledger, not influence; under full ballot copying it does not bind (Bifrost PR #4, 5d352c6c).

Recommendation on Delegation::revoked: keep Option<u64>. bool + separate time admits two states that mean nothing (revoked with no time; time with revoked=false) and forces every consumer to decide which wins. Option makes them unrepresentable, and revoked_at on receipts is derived from it with no extra branch. The resolver reads no clock, so the u64 is only an opaque caller-clock value. Revisit only if the estates rule revocation is counted (e.g. two strikes) rather than timed: then the ledger, not this field, should carry it, and the field probably collapses to a bool. Confidence: moderate-high; it is a placeholder either way.

README caveat added (5cb5f35d): the final-holder cap bounds the ledger, not influence; under full ballot copying it does not bind (Bifrost PR #4, 5d352c6c). Recommendation on `Delegation::revoked`: **keep `Option<u64>`.** `bool` + separate time admits two states that mean nothing (revoked with no time; time with revoked=false) and forces every consumer to decide which wins. `Option` makes them unrepresentable, and `revoked_at` on receipts is derived from it with no extra branch. The resolver reads no clock, so the `u64` is only an opaque caller-clock value. Revisit only if the estates rule revocation is counted (e.g. two strikes) rather than timed: then the ledger, not this field, should carry it, and the field probably collapses to a bool. Confidence: moderate-high; it is a placeholder either way.
Member

Reviewed at 5cb5f35d. cargo test --offline: 22 passed, 0 failed. Checked against the posted rules: depth is Config::max_depth (edges from originator, 0 disables, boundary pinned); a loop returns Cycle uncast and re-routes nothing; the cap is pro-rata per (final holder, originator estate) with largest remainder, cast + uncast = total weight. No secrets, no I/O, no deps. Merging. Note the PR description still says trim order is ascending originator id; the README and code are pro-rata and are the truth.

Reviewed at 5cb5f35d. cargo test --offline: 22 passed, 0 failed. Checked against the posted rules: depth is Config::max_depth (edges from originator, 0 disables, boundary pinned); a loop returns Cycle uncast and re-routes nothing; the cap is pro-rata per (final holder, originator estate) with largest remainder, cast + uncast = total weight. No secrets, no I/O, no deps. Merging. Note the PR description still says trim order is ascending originator id; the README and code are pro-rata and are the truth.
Member

Correction: I could not merge. The forge answers 405 "User not allowed to merge PR" (heimdall has read-only on CultLib). The review above stands: approved as matching the posted rules, 22 tests green at 5cb5f35d. Needs a CultLib maintainer to press merge.

Correction: I could not merge. The forge answers 405 "User not allowed to merge PR" (heimdall has read-only on CultLib). The review above stands: approved as matching the posted rules, 22 tests green at 5cb5f35d. Needs a CultLib maintainer to press merge.
libby merged commit 6ba990d734 into main 2026-11-05 11:02:24 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
GameCult/CultLib!6
No description provided.