Skip to content

id(boards): Rules revision numbers are not unique per board — two different revision-1 rule texts coexist in one graph #3964

Open

Description

@dezren39

Bug

Nothing in BoardGraph keeps a board's Rules revision numbers unique. Two different Rules objects for the same board can both claim revision: 1 (different text, different hashes) and both are accepted into the graph, leaving the board with two competing "revision 1" rule texts and no graph-level way to say which one is the board's rules at that revision.

Evidence (verified this run, main @ e860d3a)

  • pkgs/id/src/boards.rs:82-92 — Rules { board, revision, text }, with revision documented as "One-based revision number within this board."
  • pkgs/id/src/boards.rs:326-329 — validate_shape checks only revision > 0.
  • pkgs/id/src/boards.rs:482-484 — the BoardObject::Rules arm of validate_links checks only moderator authority (require_moderator); no uniqueness or monotonicity check against existing rules for the board.
  • Laptop probe ~/git/fleet/probe-2026-11-01-laneB-boards/ (verbatim boards.rs, sha256 bcc08b3e… matching the repo file @ e860d3a): inserting owner-signed Rules revision 1 "Be kind" and then a second, different owner-signed Rules revision 1 "Be kind, and no spam" for the same board → both accepted (graph len 3: board + 2 rules). A moderator holding a grant can likewise shadow the owner's revision text with their own same-revision object.

Why it matters

Threads pin rules by object hash (Thread.rules_ref), so pinned references stay exact — but any "current rules" or "rules at revision N" projection (the board-view layer, #2813) has no deterministic answer when two objects claim the same revision: the result depends on which object the projection happens to pick, i.e. on arrival/iteration order. That is exactly the arrival-order nondeterminism this module already rejects for role acceptance (see the has_role design note in boards.rs): peers holding the same signed set must reach the same verdict. Duplicate revisions break that property for the board's most-read object.

Acceptance criteria

  • One of the following is implemented and documented in the module:
    • (a) BoardGraph::insert rejects a Rules object whose (board, revision) is already claimed by a different object in the graph; or
    • (b) duplicate revisions are explicitly documented as legal, together with the deterministic rule projections must use to resolve them (and the resolution does not depend on arrival order).
  • A regression test pins the chosen behavior: a second distinct revision-1 Rules object for the same board is rejected (option a) or resolves deterministically regardless of insertion order (option b).
  • All existing boards tests still pass.

Activity

  1. added
    kind/bugSomething isn't working (prefixed form of the classic bug label)
    task/triageQueue packet kind: verify, reproduce, and route this item
    source/creatorFiled by the new-issue-creator job
    priority/normalOrdinary priority (the default)
    queue/queuedHas a queued task in the Supabase agent queue
    app/idPackage/app: id (pkgs/ or apps/ in this repo)
    effort/sSmall: expected under 2 hours of work
    on Nov 1, 2026
  2. dezren39 commented on Nov 1, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · filed

    • Agent: new-issue-creator-code-b
    • Session / ID: cron job new-issue-creator-code-b, run 2026-11-01 14:20 CST
    • Found via: filed this run
    • Task: Make a board's Rules revision numbers unambiguous in BoardGraph — either reject a second distinct Rules object claiming an already-used (board, revision), or document duplicate revisions with a deterministic, arrival-order-independent projection rule — and pin the chosen behavior with a regression test.
    • Expectation: effort/s — done when the acceptance criteria on this issue pass.
    • Links: evidence in the issue body; laptop probe at ~/git/fleet/probe-2026-11-01-laneB-boards/ (verbatim boards.rs, sha256-matched @e860d3a9; two different revision-1 rules texts both accepted for one board).
  3. dezren39 commented on Nov 2, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · adopted as Phase 2 of design #4113 — open ruling decided

  4. 45 remaining items

  5. dezren39 commented on Nov 4, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · handed off

  6. added
    queue/queuedHas a queued task in the Supabase agent queue
    and removed
    queue/claimedQueue worker lifecycle state
    work/assignedQueue worker lifecycle state
    on Nov 4, 2026
  7. dezren39 commented on Nov 4, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · handed off

    • Agent: fleet monitor (repo-fleet-monitor)
    • Session / ID: task 8831
    • Found via: monitor reconciliation
    • Task: claim-evaporated repair — the queue claim on task 8831 ended without complete/park/block, its lease expired, and the task returned to queued unclaimed while this issue still carried claimed labels. Labels reset to the truth: queue/queued + status/needs-triage. Checkpoint stage at evaporation: handed_off.
    • Expectation: the next lane to claim task 8831 posts a fresh pickup note.
  8. added
    work/assignedQueue worker lifecycle state
    queue/claimedQueue worker lifecycle state
    and removed
    queue/queuedHas a queued task in the Supabase agent queue
    on Nov 4, 2026
  9. dezren39 commented on Nov 4, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · handed off

  10. dezren39 commented on Nov 4, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · handed off

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

Metadata

Metadata

Assignees

Labels

app/idPackage/app: id (pkgs/ or apps/ in this repo)effort/sSmall: expected under 2 hours of workkind/bugSomething isn't working (prefixed form of the classic bug label)priority/normalOrdinary priority (the default)queue/claimedQueue worker lifecycle statesource/creatorFiled by the new-issue-creator jobsource/design-architectFiled by the repo design architect jobstatus/in-progressQueue worker lifecycle statetask/small-fixQueue packet kind: bounded fix with reproduction and targeted testswork/assignedQueue worker lifecycle state

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions