Repository navigation
Description
Writer-set spec §9 item 2 (doc/2026-10-30T13-15-00Z_design_id_writer_set_view_projection/). Slice 1 shipped as #3854 (pkgs/id/src/idset.rs: WriterSet, Entry in all three shapes, Excludes, Rescind, canonical body encode/decode, sign/decode round-trip). This slice adds the expansion both later slices stand on.
Goal
expand(set_version) -> BTreeSet<AuthorKey>
expand_retro(set_version) -> BTreeSet<AuthorKey> // same expansion, narrowed to entries carrying include_history
Spec §3.1 and §4.1: retro is per entry, so one flagged friend must never import another's backlog — expand_retro(v) ⊆ expand(v) is an invariant, not an approximation.
What already exists (verified at main 0467ae0f9, 2026-11-03)
pkgs/id/src/idset.rs— the types and their canonical encoding;Entrycarriesinclude_historyon every shape (§D3). Its module doc still ends: "This module is types and encoding only. Expansion, projection, and counting are later slices of the spec's routing (§9 items 2–4) and are deliberately absent here."pkgs/id/crates/id-core/src/membership/layer.rs:442—Membership::access_at_position(after, group, who), the frontier-aware membership check;:424—is_member_at(author, group, &after).pkgs/id/src/groups/delegation.rs:312— a caller ofaccess_at_position;pkgs/id/src/event_store/resolve.rs:397— a caller ofis_member_at.pkgs/id/src/groups/fold.rs— the fold the two above read.
What to build
- Expansion must go through
is_member_at/access_at_position, notmembers(group)(§4.5): the answer is pinned to the set version's frontier, and a live roster is not that. - One-level flattening of group entries (§D3/D4) — a group entry expands to its members at the frontier; a nested group reference is not followed.
role_minfiltering (§D3): include a member whose role is at least the entry'srole_minat that frontier.- Exclusions win (§D6): an exclusion entry removes its target from the expansion regardless of which entry admitted them.
- Cache, if any, keyed
(group, frontier, R)(§4.5) — and the fork-invalidation test below is what proves the key is right.
Tests (spec §9 item 2, verbatim requirements)
- Expansion is order-independent — the same set with entries permuted yields the same set of authors.
- Expansion is frontier-pinned — a membership change after the set version does not change
expand(v). - Expansion is unchanged by a later group-membership event — the reproducibility guarantee, as a test with the event written after the pin.
expand_retro(v) ⊆ expand(v), and a set with noinclude_historyentries hasexpand_retroempty whileexpandis not.- Fork proof that invalidates a group grant changes the expansion, and the cache does not serve the stale one (§4.5) — the test finding 23 added.
role_minfilters at the frontier: a member who holds the role later is not admitted by an earlier version.- An exclusion removes an admitted writer, and an exclusion of someone never admitted is a no-op rather than an error.
Out of scope
AuthorEvents/retrieval (slice 3), Projection/counted/uncounted/validity_now (slice 4), public/sentinel views (Q1 on #2031), abuse budgets (#2032), app/UI rendering.
Acceptance
cargo test -p id green with tests 1–7 above present and named; no counting path enabled (expand* returns authors only); pkgs/id/src/idset.rs's module doc updated to say expansion now lives beside the types.
Parent: #3789 · spec §9 item 2 · slice 1: #3854
Acceptance criteria
expand(set_version)andexpand_retro(set_version)exist in the id writer-set module, expanding throughis_member_at/access_at_positionpinned to the set version's frontier — never a livemembers(group)roster.- Group entries flatten exactly one level (§D3/D4);
expand_retro(v) ⊆ expand(v)holds and is test-pinned, including the case where one entry'sinclude_historymust not import another entry's backlog. - The idset module doc no longer states that expansion is absent; slice 3/4 consumers can call both functions without further expansion work.
Activity
developing-today commentedon Nov 3, 2026
agent-note:v1
state: reviewed (coverage loop-back)
Coverage pass 2026-11-03, loop-back review: this issue was re-reviewed (drift / overlap / already-handled / stale / blockers / ordering) so every open issue in the four repos is reviewed and in the system. Verdict: still live; in the system as task 8240 (small_fix, queued, priority 40) in repo-health-code-pilot. Labels audited and synced. If it is already handled at current main, its triage closes it with evidence; if oversized, the triage files the split; blockers belong on this issue.
Found via: coverage loop-back 2026-11-03
dezren39 commentedon Nov 3, 2026
Intake review
Fleet monitor intake (Duty 2), 2026-11-03. (Posted on a delayed retry: the original comment attempts were rejected by a GitHub secondary rate limit; the label/body enrichment itself landed during the run.)
pkgs/id/src/idset.rsis still types-and-encoding only; expansion is deliberately absent pending this slice.Membership::access_at_positionas the body directs; property-test the retro subset invariant.dezren39 commentedon Nov 3, 2026
agent-note:v1
state: handed_off
task: task 8240 (small_fix, repo-health-code-pilot, lane code-l)
worker: repo-worker-code
issue: #4998
Execution lane assigned: opencode. Handed off to the laptop claimant, which launches the bound session to drive task 8240 (writer-set expansion, spec slice 2 of #3789) to its terminal state.
34 remaining items
dezren39 commentedon Nov 4, 2026
🤖 Agent note · handed off
dezren39 commentedon Nov 5, 2026
🤖 Agent note · handed off