Radish alpha
h
rad:z3gqcJUoA1n9HaHKufZs5FCSGazv5
Radicle Heartwood Protocol & Stack
Radicle
Git
Revert elipses checks
Open fintohaps opened 13 days ago

These checks never worked in the first place.

When trying to check using a regex, too many valid cases of git ranges and CLI test substitutions showed up.

36 files changed +74 -57 6ce2d00b 48d382cd
deleted .codespell-dictionary.txt
@@ -1 +0,0 @@
-
...->…
modified .codespellrc
@@ -2,4 +2,3 @@
skip = .git*,*.lock,.codespellrc,target,.jj,.direnv
check-hidden = true
ignore-words-list = ser,set,noes
-
dictionary = .codespell-dictionary.txt,-

\ No newline at end of file
modified .typos.toml
@@ -11,9 +11,6 @@ extend-ignore-re = [
[default.extend-identifiers]
"typ" = "typ" # We may write "typ" instead of "type". The latter is a Rust keyword.

-
[default.extend-words]
-
"..." = "…"
-

[type.codespell]
check-file = false
extend-glob = [".codespellrc"]
modified CHANGELOG.md
@@ -133,7 +133,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
  The `Service` has now learned to return results when an error occurs which
  will be reported back to the user.
- Parsing addresses involving an IPv6 host failed if they were enclosed in
-
  square brackets, e.g. in `rad node connect z6Mk...@[::1]:8776`.
+
  square brackets, e.g. in `rad node connect z6Mk…@[::1]:8776`.
  Also, ambiguous addresses would parse, e.g. `::1:8776` would be
  indistinguishable from `[::1]:8776`. Since a port number is always required
  along a host when providing an address, IPv6 addresses now always require
modified CONTRIBUTING.md
@@ -122,7 +122,7 @@ are separated from private modules with a blank line:
    use std::time;
    use std::process;

-
    ...
+

Imports are organized in groups, from least specific to more specific:

@@ -143,13 +143,13 @@ Use short 1-letter names when the variable scope is only a few lines, or the con
obvious, eg.

    if let Some(e) = result.err() {
-
        ...
+
    }

Use 1-word names for function parameters or variables that have larger scopes:

    pub fn commit(repo: &Repository, sig: &Signature) -> Result<Commit, Error> {
-
        ...
+
    }

Use the most descriptive names for globals:
@@ -192,7 +192,7 @@ for the reader:
    // all of it. It can happen that inventory is not properly tracked if for eg. the
    // user creates a new repository while the node is stopped.
    for rid in self.storage.inventory()? {
-
        ...
+

### Referring to radicle.xyz in Code

modified crates/radicle-cli/examples/rad-auth.md
@@ -6,7 +6,7 @@ $ rad auth --alias "alice"

Initializing your Radicle 👾 identity

-
✓ Creating your Ed25519 keypair...
+
✓ Creating your Ed25519 keypair…
✓ Your Radicle DID is did:key:z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi. This identifies your device. Run `rad self` to show it at all times.
✓ You're all set.

modified crates/radicle-cli/examples/rad-id-private.md
@@ -6,7 +6,7 @@ Here we will add Bob and Eve's DIDs to the `allow`list:

```
$ rad id update --title "Allow Bob & Eve" --allow did:key:z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk --allow did:key:z6Mkux1aUQD2voWWukVb5nNUR7thrHveQG4pDQua8nVhib7Z -q
-
...
+
[...]
$ rad inspect --identity
{
  "payload": {
@@ -34,7 +34,7 @@ To remove a peer's DID, we can use the `--disallow` option. Let's remove both of

```
$ rad id update --title "Remove allow list" --disallow did:key:z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk --disallow did:key:z6Mkux1aUQD2voWWukVb5nNUR7thrHveQG4pDQua8nVhib7Z
-
...
+
[...]
$ rad inspect --identity
{
  "payload": {
@@ -67,7 +67,7 @@ the document is already up to date:

```
$ rad id update --title "Allow Bob" --allow did:key:z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk -q
-
...
+
[...]
```
```
$ rad id update --title "Allow Bob" --allow did:key:z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk
@@ -87,7 +87,7 @@ Let's change the repository to `public`:

```
$ rad id update --title "IPO" --visibility public -q
-
...
+
[...]
```

Now, if we attempt to change the `allow` list we also get an error with a
modified crates/radicle-cli/examples/rad-id.md
@@ -58,7 +58,7 @@ the delegates and threshold:
    +   "did:key:z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi",
    +   "did:key:z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk"
      ],
-
    ...
+
    -  "threshold": 1
    +  "threshold": 2

modified crates/radicle-cli/examples/rad-inbox.md
@@ -6,7 +6,7 @@ Your inbox is empty.

``` ~bob
$ cd heartwood
-
$ rad issue open --title "No license file" --description "..." -q
+
$ rad issue open --title "No license file" --description "…" -q
✓ Synced with 1 seed(s)
$ git commit -m "Change copyright" --allow-empty -q
$ git push rad HEAD:bob/copy
@@ -80,7 +80,7 @@ $ rad inbox show 1
│ Author  bob z6Mkt67…v4N1tRk                      │
│ Status  open                                     │
│                                                  │
-
│ ...                                              │
+
│ [...]                                            │
╰──────────────────────────────────────────────────╯
```

modified crates/radicle-cli/examples/rad-init-existing-bare.md
@@ -22,7 +22,7 @@ And initialize this working copy as that existing repository:
```
$ rad init --setup-signing --existing rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji

-
Configuring Radicle signing key SHA256:UIedaL6Cxm6OUErh9GQUzzglSk7VpQlVTI1TAFB/HWA...
+
Configuring Radicle signing key SHA256:UIedaL6Cxm6OUErh9GQUzzglSk7VpQlVTI1TAFB/HWA…

✓ Signing configured in [..]/heartwood/config
! Not writing .gitsigners file.
modified crates/radicle-cli/examples/rad-init-existing.md
@@ -22,7 +22,7 @@ And initialize this working copy as that existing repository:
```
$ rad init --setup-signing --existing rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji

-
Configuring Radicle signing key SHA256:UIedaL6Cxm6OUErh9GQUzzglSk7VpQlVTI1TAFB/HWA...
+
Configuring Radicle signing key SHA256:UIedaL6Cxm6OUErh9GQUzzglSk7VpQlVTI1TAFB/HWA…

✓ Signing configured in [..]/heartwood/.git/config
✓ Created .gitsigners file
modified crates/radicle-cli/examples/rad-init-private-clone-seed.md
@@ -4,7 +4,7 @@ is able to fetch it by specifying Alice as a seed.

``` ~alice
$ rad id update --title "Allow Bob" --description "" --allow did:key:z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk -q
-
...
+
[...]
$ rad inspect --identity
{
  "payload": {
modified crates/radicle-cli/examples/rad-init-private-clone.md
@@ -19,7 +19,7 @@ the refs.

``` ~alice
$ rad id update --title "Allow Bob" --description "" --allow did:key:z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk -q
-
...
+
[...]
$ rad sync --announce --timeout 3s
✓ Synced with 1 seed(s)
```
modified crates/radicle-cli/examples/rad-init-with-existing-remote.md
@@ -12,7 +12,7 @@ Then we add it as a remote.
```
$ git remote add origin file://$PWD/remote
$ git push -u origin master:master
-
...
+
[...]
$ git branch -vv
* master f2de534 [origin/master] Second commit
```
modified crates/radicle-cli/examples/rad-node.md
@@ -84,7 +84,7 @@ Running the command again gives us an error:

```
$ rad node stop
-
✗ Stopping node... error: node is not running
+
✗ Stopping node… error: node is not running
```

Note that if we unseed a repository, it is no longer part of our inventory:
@@ -126,7 +126,7 @@ $ rad sync status
```
``` (fail)
$ rad node connect z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk@radicle.xyz:8776
-
✗ Connecting to z6Mkt67…v4N1tRk@radicle.xyz:8776... <canceled>
+
✗ Connecting to z6Mkt67…v4N1tRk@radicle.xyz:8776… <canceled>
✗ Error: failed to open node control socket "[..]/.radicle/node/control.sock" (entity not found)
✗ Hint: to start your node, run `rad node start`.
```
modified crates/radicle-cli/examples/rad-patch-checkout-force.md
@@ -80,7 +80,7 @@ ensure that they are looking at the latest changes:

``` ~bob (fail)
$ rad patch checkout aa45913 --name alice-init
-
✗ Performing checkout... <canceled>
+
✗ Performing checkout… <canceled>
✗ Error: branch 'alice-init' already exists (use `--force` to overwrite)
```

modified crates/radicle-cli/src/commands/auth.rs
@@ -55,7 +55,7 @@ pub fn init(args: Args) -> anyhow::Result<()> {
        term::passphrase_confirm("Enter a passphrase:", env::RAD_PASSPHRASE)?
    };
    let passphrase = passphrase.filter(|passphrase| !passphrase.trim().is_empty());
-
    let spinner = term::spinner("Creating your Ed25519 keypair...");
+
    let spinner = term::spinner("Creating your Ed25519 keypair…");
    let profile = Profile::init(home, alias, passphrase.clone(), env::seed())?;
    let mut agent = true;
    spinner.finish();
@@ -63,7 +63,7 @@ pub fn init(args: Args) -> anyhow::Result<()> {
    if let Some(passphrase) = passphrase {
        match ssh::agent::Agent::connect() {
            Ok(mut agent) => {
-
                let mut spinner = term::spinner("Adding your Radicle key to ssh-agent...");
+
                let mut spinner = term::spinner("Adding your Radicle key to ssh-agent…");
                if register(&mut agent, &profile, passphrase).is_ok() {
                    spinner.finish();
                } else {
modified crates/radicle-cli/src/commands/checkout.rs
@@ -38,7 +38,7 @@ fn execute(args: Args, profile: &Profile) -> anyhow::Result<PathBuf> {
        anyhow::bail!("the local path {:?} already exists", path.as_path());
    }

-
    let mut spinner = term::spinner("Performing checkout...");
+
    let mut spinner = term::spinner("Performing checkout…");
    let repo = match radicle::rad::checkout(args.repo, &remote, path.clone(), &storage, false) {
        Ok(repo) => repo,
        Err(err) => {
modified crates/radicle-cli/src/commands/init.rs
@@ -134,7 +134,7 @@ pub fn init(repo: git::Repository, args: Args, profile: &profile::Profile) -> an

    let signer = term::signer(profile)?;
    let mut node = radicle::Node::new(profile.socket_from_env());
-
    let mut spinner = term::spinner("Initializing...");
+
    let mut spinner = term::spinner("Initializing…");
    let mut push_cmd = String::from("git push");

    match radicle::rad::init(
@@ -497,7 +497,7 @@ pub fn setup_signing(
    let key = ssh::fmt::fingerprint(node_id);
    let yes = if !git::is_signing_configured(path)? {
        term::headline(format!(
-
            "Configuring Radicle signing key {}...",
+
            "Configuring Radicle signing key {}…",
            term::format::tertiary(key)
        ));
        true
modified crates/radicle-cli/src/commands/node/control.rs
@@ -120,7 +120,7 @@ pub fn start(
}

pub fn stop(node: Node, profile: &Profile) {
-
    let mut spinner = term::spinner("Stopping node...");
+
    let mut spinner = term::spinner("Stopping node…");
    if node.shutdown().is_err() {
        spinner.error("node is not running");
    } else {
@@ -198,7 +198,7 @@ pub fn connect(
    timeout: time::Duration,
) -> anyhow::Result<()> {
    let spinner = term::spinner(format!(
-
        "Connecting to {}@{addr}...",
+
        "Connecting to {}@{addr}…",
        term::format::node_id_human_compact(&nid)
    ));
    match node.connect(
@@ -222,11 +222,11 @@ pub fn connect_many(
    addrs: Vec<Address>,
    timeout: time::Duration,
) -> anyhow::Result<()> {
-
    let mut spinner = term::spinner("Connecting...");
+
    let mut spinner = term::spinner("Connecting…");
    let mut errors = HashMap::new();
    for addr in addrs {
        spinner.message(format!(
-
            "Connecting to {}@{addr}...",
+
            "Connecting to {}@{addr}…",
            term::format::node_id_human_compact(&nid)
        ));
        match node.connect(
modified crates/radicle-cli/src/commands/patch/checkout.rs
@@ -54,7 +54,7 @@ pub fn run(
        None => patch.latest(),
    };

-
    let mut spinner = term::spinner("Performing checkout...");
+
    let mut spinner = term::spinner("Performing checkout…");
    let patch_branch = opts.branch(patch_id)?;

    let commit = match working.find_branch(patch_branch.as_str(), git::raw::BranchType::Local) {
modified crates/radicle-cli/src/terminal/io.rs
@@ -64,7 +64,7 @@ pub fn signer(profile: &Profile) -> anyhow::Result<BoxedDevice> {
            )
        }
    };
-
    let spinner = spinner("Unsealing key...");
+
    let spinner = spinner("Unsealing key…");
    let signer = MemorySigner::load(&profile.keystore, Some(passphrase))?;

    spinner.finish();
modified crates/radicle-node/src/main.rs
@@ -18,7 +18,7 @@ use radicle_signals as signals;
const HELP_MSG: &str = r#"
Usage

-
   radicle-node [<option>...]
+
   radicle-node [<option>…]

   If you're running a public seed node, make sure to use `--listen` to bind a listening socket to
   eg. `0.0.0.0:8776`, and add your external addresses in your configuration.
modified crates/radicle-node/src/reactor.rs
@@ -310,7 +310,7 @@ impl Reactor {
        let poll = Poll::new()?;
        let controller = Controller::new(sender, Arc::new(Waker::new(poll.registry(), WAKER)?));

-
        log::debug!(target: "reactor-controller", "Initializing reactor thread...");
+
        log::debug!(target: "reactor-controller", "Initializing reactor thread…");
        let thread = builder.spawn(move || {
            let runtime = Runtime {
                service,
modified crates/radicle-node/src/reactor/controller.rs
@@ -46,7 +46,7 @@ impl Controller {
    }

    pub fn shutdown(self) -> Result<(), Self> {
-
        log::info!(target: "reactor::controller", "Initiating reactor shutdown...");
+
        log::info!(target: "reactor::controller", "Initiating reactor shutdown…");
        let res1 = self.sender.send(ControlMessage::Shutdown);
        let res2 = self.wake();
        res1.or(res2).map_err(|_| self)
modified crates/radicle-node/src/tests.rs
@@ -1224,7 +1224,7 @@ fn test_persistent_peer_reconnect_attempt() {
    assert!(ips.contains(&bob.id()));
    assert!(ips.contains(&eve.id()));

-
    // ... Negotiated ...
+
    // … Negotiated …
    //
    // Now let's disconnect a peer.

@@ -1519,7 +1519,7 @@ fn test_queued_fetch_max_capacity() {

    // Now the 1st fetch is done, the 2nd fetch is dequeued.
    assert_eq!(alice.fetches().next(), Some((rid2, bob.id)));
-
    // ... but not the third.
+
    // … but not the third.
    assert_matches!(alice.fetches().next(), None);

    // Finish the 2nd fetch.
@@ -1651,7 +1651,7 @@ fn test_queued_fetch_from_command_same_rid() {
    assert_eq!(rid, rid1);
    assert!(peers.remove(&nid));

-
    // ... but not the third.
+
    // … but not the third.
    assert_matches!(alice.fetches().next(), None);

    // Finish the 2nd fetch.
modified crates/radicle-protocol/src/bounded.rs
@@ -126,7 +126,7 @@ impl<T, const N: usize> BoundedVec<T, N> {
    /// vec.push(3).expect("within limit");
    /// assert_eq!(vec, vec![1, 2, 3].try_into().unwrap());
    ///
-
    /// // ...but this will exceed its limit, returning an error.
+
    /// // …but this will exceed its limit, returning an error.
    /// vec.push(4).expect_err("limit exceeded");
    /// assert_eq!(vec.len(), 3);
    /// ```
modified crates/radicle-protocol/src/service.rs
@@ -749,7 +749,7 @@ where
        );

        if now - self.last_idle >= IDLE_INTERVAL {
-
            trace!(target: "service", "Running 'idle' task...");
+
            trace!(target: "service", "Running 'idle' task…");

            self.keep_alive(&now);
            self.disconnect_unresponsive_peers(&now);
@@ -760,7 +760,7 @@ where
            self.last_idle = now;
        }
        if now - self.last_gossip >= GOSSIP_INTERVAL {
-
            trace!(target: "service", "Running 'gossip' task...");
+
            trace!(target: "service", "Running 'gossip' task…");

            if let Err(e) = self.relay_announcements() {
                warn!(target: "service", "Failed to relay stored announcements: {e}");
@@ -769,7 +769,7 @@ where
            self.last_gossip = now;
        }
        if now - self.last_sync >= SYNC_INTERVAL {
-
            trace!(target: "service", "Running 'sync' task...");
+
            trace!(target: "service", "Running 'sync' task…");

            if let Err(e) = self.fetch_missing_repositories() {
                warn!(target: "service", "Failed to fetch missing inventory: {e}");
@@ -778,14 +778,14 @@ where
            self.last_sync = now;
        }
        if now - self.last_announce >= ANNOUNCE_INTERVAL {
-
            trace!(target: "service", "Running 'announce' task...");
+
            trace!(target: "service", "Running 'announce' task…");

            self.announce_inventory();
            self.outbox.wakeup(ANNOUNCE_INTERVAL);
            self.last_announce = now;
        }
        if now - self.last_prune >= PRUNE_INTERVAL {
-
            trace!(target: "service", "Running 'prune' task...");
+
            trace!(target: "service", "Running 'prune' task…");

            if let Err(err) = self.prune_routing_entries(&now) {
                warn!(target: "service", "Failed to prune routing entries: {err}");
@@ -2635,7 +2635,7 @@ where

        for (nid, addr, attempts) in reconnect {
            if self.reconnect(nid, addr) {
-
                debug!(target: "service", "Reconnecting to {nid} (attempts={attempts})...");
+
                debug!(target: "service", "Reconnecting to {nid} (attempts={attempts})…");
            }
        }
    }
modified crates/radicle-protocol/src/wire/frame.rs
@@ -191,7 +191,7 @@ impl From<StreamType> for u8 {
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// |                     Stream ID                           |TTT|I| Stream ID with Stream [T]ype and [I]nitiator bits
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-
/// |                     Data                                   ...| Data (variable size)
+
/// |                     Data                                     …| Data (variable size)
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// ```
#[derive(Debug, PartialEq, Eq)]
modified crates/radicle-term/src/io.rs
@@ -209,7 +209,7 @@ pub fn indented(msg: impl fmt::Display) {
}

pub fn subcommand(msg: impl fmt::Display) {
-
    println!("{}", style(format!("Running `{msg}`...")).dim());
+
    println!("{}", style(format!("Running `{msg}`…")).dim());
}

pub fn warning(warning: impl fmt::Display) {
modified crates/radicle/src/canonical/formatter.rs
@@ -238,7 +238,7 @@ impl Formatter for CanonicalFormatter {

    // This is for serde_json's `raw_value` feature, which provides a RawValue type
    // that is passed through as-is. That's not good enough for canonical JSON,
-
    // so we parse it and immediately write it back out... as canonical JSON.
+
    // so we parse it and immediately write it back out… as canonical JSON.
    fn write_raw_fragment<W: Write + ?Sized>(
        &mut self,
        writer: &mut W,
modified crates/radicle/src/identity/doc.rs
@@ -940,7 +940,7 @@ impl Doc {
            &crate::cob::identity::TYPENAME,
            &cob.id,
        );
-
        // Set `.../refs/rad/id` -> `.../refs/cobs/xyz.radicle.id/<id>`
+
        // Set `…/refs/rad/id` -> `…/refs/cobs/xyz.radicle.id/<id>`
        repo.backend.reference_symbolic(
            id_ref.as_str(),
            cob_ref.as_str(),
modified crates/radicle/src/profile.rs
@@ -3,7 +3,7 @@
//!   $RAD_HOME/                                 # Radicle home
//!     storage/                                 # Storage root
//!       zEQNunJUqkNahQ8VvQYuWZZV7EJB/          # Project git repository
-
//!       ...                                    # More projects...
+
//!       …                                      # More projects…
//!     keys/
//!       radicle                                # Secret key (PKCS 8)
//!       radicle.pub                            # Public key (PKCS 8)
modified justfile
@@ -61,10 +61,15 @@ check-docs:
[group('pre-push')]
[group('check')]
[parallel]
-
check-typos: (verify-tool "typos" "typos-cli")
+
check-typos: (verify-tool "typos" "typos-cli") check-ellipses
    @echo "{{CHECK}}Checking for spelling typos...{{NORMAL}}"
    @typos

+
[group('check')]
+
check-ellipses:
+
    @echo "{{CHECK}} Checking for ellipses...{{NORMAL}}"
+
    scripts/just/check-ellipses.sh
+

# Run codespell
[group('pre-commit')]
[group('pre-push')]
added scripts/just/check-ellipses.sh
@@ -0,0 +1,17 @@
+
#! /usr/bin/env bash
+
set -euo pipefail
+

+
# Replace '...' with '…' (U+2026) in markdown and Rust files, but ignore:
+
# - Git ranges, such as 20aa5dd...f2de534, feature/1...rad/patches/f2de534
+
# - Wildcards for CLI example tests, i.e. [...]
+
patterns=('*.md' '*.rs')
+

+
git ls-files -z "${patterns[@]}" | xargs -0 sed --follow-symlinks --in-place --regexp-extended \
+
    --expression '/[a-zA-Z0-9_\/.]\.\.\.[a-zA-Z0-9_\/.]/! { /\[\s*\.\.\.\s*\]/! s/\.\.\./…/g }'
+

+
if ! git diff --quiet -- "${patterns[@]}"; then
+
    echo "error: Replaced '...' with '…' (U+2026) in the following files:"
+
    git diff --name-only -- "${patterns[@]}"
+
    echo "Please commit these changes."
+
    exit 1
+
fi
modified simulation/README.md
@@ -69,7 +69,7 @@ This will give us the following workflow for constructing test scenarios:
- [ ] Flexibility to define network topologies.
- [ ] Easy to construct and run new simulations.
- [ ] Reproducible starting state.
-
- [ ] Adverse network emulation e.g. dropped packets, network delays...
+
- [ ] Adverse network emulation e.g. dropped packets, network delays…

## Plan