Skip to content

Commit b079886

Browse files
alex-poorclaude
andcommitted
Let a carrier be told what to carry
The peer had no way to be given a subject. It carried its own, whatever it had been paired with, and whatever a bucket-topic announcement told it about — and that announcement has to arrive over an overlay whose membership is sampled, so sometimes it simply does not. Twenty minutes of `carrying 1 · holding 0 · heard 0` while the data sat in its own store. `--carry <subject-hex>`, repeatable. `carry_share` already carried follows unconditionally every pass; this puts named subjects on the same footing. Somebody running a carrier for their own family already knows whose records they mean, and should not have to wait to be told. Measured: first pass after the restart, `carrying 4 (+4) · holding 1798`. Discovery is out of the path for the subjects the machine exists to hold. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent f3d47d3 commit b079886

5 files changed

Lines changed: 29 additions & 3 deletions

File tree

‎crates/diaswarm-android/src/lib.rs‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2485,6 +2485,8 @@ pub extern "system" fn Java_nz_diaswarm_jni_SwarmNative_keysCarryAll<'a>(
24852485
&store,
24862486
&own,
24872487
max_adopt.max(0) as usize,
2488+
// A phone is told whom to carry by pairing, not by a flag.
2489+
&[],
24882490
)) {
24892491
Ok(share) => share.carrying as jlong,
24902492
Err(_) => -4,

‎crates/diaswarm-net/src/share.rs‎

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use std::path::Path;
1919
use anyhow::Result;
2020

2121
use crate::replicate::KeysReplicator;
22-
use crate::swarm::Swarm;
22+
use crate::swarm::{is_subject, Swarm};
2323

2424
/// What one pass over the pool did.
2525
///
@@ -78,6 +78,7 @@ pub async fn carry_share(
7878
store: &Path,
7979
own_subject: &str,
8080
max_adopt: usize,
81+
also: &[String],
8182
) -> Result<Share> {
8283
// `.max(2)` because a pool of one has no depth to speak of and the first
8384
// pass usually runs before anybody has been heard from.
@@ -86,6 +87,14 @@ pub async fn carry_share(
8687

8788
let mut wanted: Vec<String> = vec![own_subject.to_string()];
8889

90+
// **SUBJECTS THIS PEER WAS TOLD TO CARRY, WHICH NEED NO GOSSIP AT ALL.**
91+
// Everything else here waits to be told: follows come from a pairing, and
92+
// strangers from a `HoldingKeys` announcement that has to arrive over an
93+
// overlay whose membership is sampled. A carrier somebody runs for their
94+
// own family should not be at the mercy of that — they already know whose
95+
// data they mean. Named subjects are carried every pass, unconditionally.
96+
wanted.extend(also.iter().filter(|s| is_subject(s)).cloned());
97+
8998
// Everyone we follow, by the keys identity their invite carried. A follow
9099
// with no keys identity is skipped rather than failed: it is somebody
91100
// paired before the field existed, or a subject with no keys vault.

‎crates/diaswarm-net/src/swarm.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -904,7 +904,7 @@ fn topic(bytes: [u8; 32]) -> Topic {
904904
Hash::from_bytes(bytes).into()
905905
}
906906

907-
fn is_subject(s: &str) -> bool {
907+
pub(crate) fn is_subject(s: &str) -> bool {
908908
s.len() == 64 && s.bytes().all(|b| b.is_ascii_hexdigit())
909909
}
910910

‎crates/diaswarm-net/tests/keys_pool.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ async fn a_stranger_carries_a_keys_subject_it_was_never_introduced_to() {
129129
&carrier_dir,
130130
&carrier_own,
131131
4,
132+
&[],
132133
)
133134
.await
134135
{

‎crates/diaswarm-peer/src/main.rs‎

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,19 @@ struct Args {
7272
#[arg(long, value_name = "NAME")]
7373
network: Option<String>,
7474

75+
/// Carry this subject, whatever gossip does or does not say. Repeatable.
76+
///
77+
/// **THE ONE WAY TO BE SURE.** Everything else this peer carries it has to
78+
/// be *told about*: a follow comes from a pairing, a stranger from an
79+
/// announcement that has to reach it over an overlay whose membership is
80+
/// sampled and can simply not include the peer holding the data. A carrier
81+
/// somebody runs for their own family already knows whose records it means;
82+
/// naming them here removes discovery from the path entirely.
83+
///
84+
/// Take the value from the phone's log line `swarm: keys subject <hex>`.
85+
#[arg(long = "carry", value_name = "SUBJECT-HEX")]
86+
carry: Vec<String>,
87+
7588
/// Do one pass and exit.
7689
#[arg(long)]
7790
once: bool,
@@ -231,7 +244,8 @@ async fn main() -> Result<()> {
231244
loop {
232245
let tick = swarm.tick().await;
233246
let share =
234-
diaswarm_net::share::carry_share(&swarm, &replicator, &dir, &own, args.adopt).await;
247+
diaswarm_net::share::carry_share(&swarm, &replicator, &dir, &own, args.adopt, &args.carry)
248+
.await;
235249
let bytes = disk_bytes(&dir);
236250
let stored = held(&store, &replicator.carried()).await;
237251
// **HOW MANY SUBJECTS IT HAS HEARD OF BUT IS NOT YET CARRYING.**

0 commit comments

Comments
 (0)