Skip to content

release(40.0.1): six durability fixes from the v40.0.0 review (#763) - #804

Merged
emooreatx merged 2 commits into
mainfrom
release-40.0.1
Oct 4, 2026
Merged

emooreatx merged 2 commits into
mainfrom
release-40.0.1

Conversation

@emooreatx

Copy link
Copy Markdown
Contributor

Release PR for v40.0.1 (PATCH from v40.0.0; same pins: persist v53.0.1, verify v19.0.0; no API change).

Fixes the six defects Codex found in #802's #763 self/family durability code:

  1. Outsider claims counted with no scope table. Self/family holdings are now decided by persist's cohort audience before the table's arming check, and withheld with no directory (CC 5.2). The v18 'no table means open' pin now covers only the tiers the table governs; its two tests are updated to say so.
  2. Unread audience fell through to eviction. The converger target is CohortTarget { Full, Tuple, Unknown }, and Unknown keeps the content.
  3. Full-holding repair loop. It counts each signed holder once plus the local copy, not The converger evicts on raw unverified holding claims — a signed lie makes honest nodes delete real copies; HoldingClaimVerification exists and is never called #582's weighted equivalents.
  4. Withdrawn cohort content kept or repaired. Revoked skips the full-holding branch, so EjectHardDelete stays its retry path.
  5. Sweep blocked the puller. It now runs as its own task, one at a time, aborted on exit.
  6. Rooms past 4096 files never fully swept. A rolling room and page cursor.

Witnesses (each fails with its fix reverted): a_cohort_claim_is_refused_from_an_outsider_without_a_scope_table_802, a_fully_held_cohort_content_is_kept_not_repaired_802, a_revoked_cohort_content_is_not_kept_by_the_full_holding_branch_802, the_durability_pass_rolls_past_its_file_budget_802. (2) has no direct witness, since no failing-directory double exists.

Local gates: fmt; clippy -D warnings on both feature sets; lib suite 1869 (two halves); integration family_files_wire_736, delivery_receipts_738, blob_federation_e2e, self_dag_field_path_717, owned_devices_route_682, chat_message_federates; evidence and hash tests on the release commit.

🤖 Generated with Claude Code

https://claude.ai/code/session_011ksniaWCvWoUwFQHRG3HQL

emooreatx and others added 2 commits October 3, 2026 23:28
)

- A self/family holding claim is decided by persist's cohort audience
  before the scope table's arming check: on a runtime with no table, the
  unarmed Announce admitted an outsider's claim into rarity and repair. With
  no directory, the holding is withheld (CC 5.2), never announced to an
  unknown peer. The v18 'no table means open' pin now covers only the tiers
  the table governs.
- The converger's holding target is a CohortTarget { Full(n), Tuple,
  Unknown }: an unreadable audience keeps the content this tick, rather than
  falling through to the tuple's eviction.
- Full holding counts each signed holder once, plus the local copy, not the
  #582 weighted equivalents (those guard deletes), so a fully held content is
  kept, not repaired forever.
- A Revoked cohort content skips the full-holding branch, so EjectHardDelete
  stays its retry path.
- The durability sweep runs as its own task (one at a time, aborted on
  exit), so the puller keeps receiving rows, retries and key wakes.
- The bounded sweep rolls: it saves its room and page cursor and resumes
  there, so a room past MAX_FILES is eventually visited in full.

Witnesses (each fails with its fix reverted):
a_cohort_claim_is_refused_from_an_outsider_without_a_scope_table_802,
a_fully_held_cohort_content_is_kept_not_repaired_802,
a_revoked_cohort_content_is_not_kept_by_the_full_holding_branch_802,
the_durability_pass_rolls_past_its_file_budget_802.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011ksniaWCvWoUwFQHRG3HQL
PATCH, same pins (persist v53.0.1, verify v19.0.0), no API change. Evidence
TSV at ciris-edge@v40.0.1. Notes: docs/RELEASE_NOTES.md § v40.0.1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011ksniaWCvWoUwFQHRG3HQL

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 70e38d86c0

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/swarm/runtime.rs
Comment on lines +1491 to +1492
let claimed = u32::try_from(all_claims.len()).unwrap_or(u32::MAX);
let holders = claimed.saturating_add(u32::from(local_holds));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Revalidate claimants against the current audience

When cohort membership changes within the 600-second claim TTL, all_claims can still contain a signed claim from a node that has left while full_holding_audience returns only the new audience's size. For example, replacing member B with C leaves A/B's two claims satisfying an audience size of two, so this branch emits Keep even though new member C has no copy. Preserve the resolved audience node set and count only claims whose peer remains in it before deciding that full holding is satisfied.

Useful? React with 👍 / 👎.

Comment thread src/swarm/runtime.rs
Comment on lines +1487 to +1488
let local_holds = local_by_content.contains_key(&content_id)
&& !all_claims.iter().any(|c| c.peer_id == local_peer_id);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Verify the local copy is whole before counting it

HeldFountainContent represents the symbol IDs currently retained and can therefore describe a partial or damaged fountain copy, but this test counts any map entry as a full holder. In a two-node full-holding audience, one remote claim plus a local entry containing only a subset of the required symbols produces holders == audience and emits Keep, suppressing the repair that should restore the local whole copy. Count the local node only after verifying that its retained symbols constitute a complete copy.

Useful? React with 👍 / 👎.

@emooreatx
emooreatx merged commit 2eb1893 into main Oct 4, 2026
26 checks passed
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.

1 participant