CCI report: 1751cb06-88fd-4687-9ae4-bfcf151ca3b0

Request message

{
  "request": "trigger",
  "version": 1,
  "event_type": "patch",
  "repository": {
    "id": "rad:z3gqcJUoA1n9HaHKufZs5FCSGazv5",
    "name": "heartwood",
    "description": "Radicle Heartwood Protocol & Stack",
    "private": false,
    "default_branch": "master",
    "delegates": [
      "did:key:z6MksFqXN3Yhqk8pTJdUGLwATkRfQvwZXPqR2qMEhbS9wzpT",
      "did:key:z6MktaNvN1KVFMkSRAiN4qK5yvX1zuEEaseeX5sffhzPZRZW",
      "did:key:z6MkireRatUThvd3qzfKht1S44wpm4FEWSSa4PRMTSQZ3voM",
      "did:key:z6MkgFq6z5fkF2hioLLSNu1zP2qEL1aHXHZzGH1FLFGAnBGz",
      "did:key:z6MkkPvBfjP4bQmco5Dm7UGsX2ruDBieEHi8n9DVJWX5sTEz"
    ]
  },
  "action": "Created",
  "patch": {
    "id": "8e0570288d0435eedbcf6d9e06e2916bc69e0b5e",
    "author": {
      "id": "did:key:z6Mko5mivMvNtheBHB67cSJeMG6BbCn7Xk6MKY9VegkAbgMH",
      "alias": "Derick"
    },
    "title": "signals: Use `signals_receipts` crate instead",
    "state": {
      "status": "merged",
      "conflicts": []
    },
    "before": "e130b4dc06ca02a035519e1ea86ffeafc788866f",
    "after": "b73a881cdbff3355c66657e9f25e4fccafa2a548",
    "commits": [
      "b73a881cdbff3355c66657e9f25e4fccafa2a548"
    ],
    "target": "6cfed884bf37cba1e0d8e97fa8b0e94df4a04b1f",
    "labels": [],
    "assignees": [],
    "revisions": [
      {
        "id": "8e0570288d0435eedbcf6d9e06e2916bc69e0b5e",
        "author": {
          "id": "did:key:z6Mko5mivMvNtheBHB67cSJeMG6BbCn7Xk6MKY9VegkAbgMH",
          "alias": "Derick"
        },
        "description": "This fixes the following issues:\n- 111cf90 (`handler` is not async-signal-safe)\n- c8e0300 (`libc::signal` should not be used)\n- b91c6c3 (Mutex can cause signals to be missed)\n\nThe changes are all only internal to `radicle-signals`, and the API of\n`radicle-signals` is the same as before, and uses of it don't need to be\nand aren't changed.\n\nSee the commit's message that describes its changes.\nSee the comments in the new code.\nSee the below:\n\nAll those issues are fixed by a different internal approach that:\n- Uses only atomic counters and a semaphore from within the signal\n  handlers, ensuring async-signal-safety portably.\n- Uses `libc::sigaction` instead.  With `SA_RESTART`, which preserves\n  the same behavior as the prior use of `libc::signal` on all the OSs\n  that https://radicle.xyz/ provides prebuilt binaries for, and which\n  now ensures consistent behavior across all further OSs.\n- Does not access the mutex from within the signal handlers, and\n  separates the management of the mutex'ed global state from the\n  processing of signals receipts that sends the notifications over a\n  channel.\n- Has an additional internal thread that blocks on the semaphore, and,\n  upon wakes, takes the counters' latest values, and, for those signals\n  that have newly been delivered, sends notifications over the\n  user-provided channel.\n\nAll of this approach is provided via a new external dependency, the\n`signals_receipts` crate, written by myself, that provides and manages\nit all in a very easy-to-use way.  The justification for having a new\nexternal dependency is:\n\nIt was found that all the parts for this approach are better provided as\nlibraries (crates), because: that significantly shortens and simplifies\n`radicle-signals`; they are entirely reusable for other various\nprojects; their internal workings need to be encapsulated; and they're\nnot something that the Radicle team should be expected to take on the\nmaintenance of.  I, as the maintainer, expect the maintenance burden to\nbe minimal and rare and my understanding to not fade too much, and I\nexpect that any team member could reasonably familiarize with it all if\nneeded, due to the medium-small size, limited, and already-complete\nnature of these crates and due to the extensive comments in them.\n\nIt was also found that no lesser approach could be truly robust and\nportable while still preserving the preexisting API and use cases of\n`radicle-signals`.  The approach I settled on does achieve that and does\npreserve those.\n\nFurther information about the approach can be found in the crates'\nREADMEs and documentation:\nhttps://crates.io/crates/signals_receipts\nhttps://crates.io/crates/sem_safe\n\nTo my knowledge, the only alternative for comparable robustness and\nportability would be the `signal_hook` crate which has more use in the\nRust ecosystem.  After evaluating it, I decided against it because:\n1. It can't fully uninstall the signal handlers at the OS-process level\n   (it can only emulate that (without perfect fidelity, IIUC)), and not\n   being able to do so would've been a more disruptive change to the\n   preexisting, and perhaps future, uses of `radicle-signals` that have\n   been doing, and might want to do, full uninstalling.  Whereas,\n   `signals_receipts` does fully uninstall.\n2. It doesn't provide the ability to send over channels.  Achieving that\n   would've required an additional internal thread to do such, but\n   having an ad-hoc approach to managing that, *with the uninstalling\n   and re-installing*, would've been error-prone.  Whereas,\n   `signals_receipts` does provide the ability to send over channels,\n   and it automatically manages its internal thread robustly.\n3. It has other substantial features that aren't needed by\n   `radicle-signals`, but those would've had to be carried in the object\n   code just to use its iterator that builds on them.  Whereas,\n   `signals_receipts` carries only what's needed.\n4. It uses the \"self-pipe trick\" which is a hack (albeit a reliable\n   one).  Whereas, `signals_receipts` uses semaphores which are more\n   modern and are intended for signal handling.\n\nI've confirmed this patch builds cleanly for all the currently supported\nplatforms:\n`x86_64-unknown-linux-musl`\n`aarch64-unknown-linux-musl`\n`x86_64-apple-darwin`\n`aarch64-apple-darwin`\nAs well as for:\n`x86_64-unknown-linux-gnu`\n\nI have tested this patch in these ways:\n- The dependency crates, `signals_receipts` & `sem_safe`, that provide\n  the new approach, have thorough tests and have been confirmed by me to\n  work correctly on numerous POSIX OSs (see their READMEs).  (Their\n  portability is broader than Radicle's current support, and so will\n  assist in broadening its support.)  I've also done thorough debugger\n  stepping of their code paths.\n- I've conducted functional testing of the direct uses of\n  `radicle-signals`, using the new approach of this patch, on Linux and\n  macOS, x86-64.\n- I've done thorough debugger stepping of the code paths of the direct\n  uses of `radicle-signals`, including of the various possibilities due\n  to differences in thread-scheduling races.\n- I've spent considerable time reasoning about the dependency crates and\n  the preexisting uses of `radicle-signals`.\n\nThe uses of `radicle-signals` that I tested are:\n- `radicle-node`: Simple use in `main.rs` & `runtime.rs` that only\n  installs once with a bounded channel and never uninstalls.\n- `radicle-term`: Uses in `spinner.rs` & `pager.rs` that uninstall after\n  installing with unbounded channels and that could be invoked multiple\n  times within the same process and thus could do re-installing.\n- `rad-cli-demo`: Uses `radicle-term` spinner & pager.\n\nThe indirect uses of `radicle-signals` that I haven't tested yet are:\n- `radicle-cli`: Uses `radicle-term` spinner & pager in numerous places\n  that seemed equivalent enough to what I have tested.\n\nThe uses should be tested on AArch64 for at least the OSs that Radicle\nsupports (Linux & macOS), which I haven't done yet.  There's no reason\nto expect any issues with that, since OSs provide the same APIs and\nsemantics for the relevant aspects of signal handling regardless of CPU\narchitecture.  I'd need to find access to such machines.\n\nI can test the remaining uses, if there's interest in accepting this\ncontribution.  Or, it might be good for someone from the team to test\nthose as part of reviewing this.\n\nIf you have any questions, I'm happy to respond to them.",
        "base": "e130b4dc06ca02a035519e1ea86ffeafc788866f",
        "oid": "08844cf18464bb36690472da7c4d56563d164aa0",
        "timestamp": 1726354530
      },
      {
        "id": "53c799a7721bbcc706a742f3c16776ad40a40f2c",
        "author": {
          "id": "did:key:z6Mko5mivMvNtheBHB67cSJeMG6BbCn7Xk6MKY9VegkAbgMH",
          "alias": "Derick"
        },
        "description": "",
        "base": "e130b4dc06ca02a035519e1ea86ffeafc788866f",
        "oid": "b73a881cdbff3355c66657e9f25e4fccafa2a548",
        "timestamp": 1726354858
      },
      {
        "id": "0c5e9f122da3a08688d6ff999b0e9959dd8a5c86",
        "author": {
          "id": "did:key:z6Mko5mivMvNtheBHB67cSJeMG6BbCn7Xk6MKY9VegkAbgMH",
          "alias": "Derick"
        },
        "description": "Rebase.",
        "base": "c05434ebd5a2335f432db9ac1820f3e4ba181e68",
        "oid": "9bfef8f6ff22cb41343042778de2494e2d4a672c",
        "timestamp": 1744826854
      },
      {
        "id": "5d469e83186a6cc296d4d96af44c76074e10950c",
        "author": {
          "id": "did:key:z6Mko5mivMvNtheBHB67cSJeMG6BbCn7Xk6MKY9VegkAbgMH",
          "alias": "Derick"
        },
        "description": "Rebase and sign.",
        "base": "c05434ebd5a2335f432db9ac1820f3e4ba181e68",
        "oid": "47c785b9160c31ab360e15c7b2f849e5225ecc66",
        "timestamp": 1744827129
      }
    ]
  }
}

Send response

{
  "response": "triggered",
  "run_id": {
    "id": "1751cb06-88fd-4687-9ae4-bfcf151ca3b0"
  },
  "info_url": "https://cci.rad.levitte.org//1751cb06-88fd-4687-9ae4-bfcf151ca3b0.html"
}

Checkout the source (in /opt/radcis/ci.rad.levitte.org/cci/state/1751cb06-88fd-4687-9ae4-bfcf151ca3b0/w)

Started at: 2025-10-21 19:32:26.411326+02:00

Commands:

Read the repo configuration (.radicle/native.yaml in /opt/radcis/ci.rad.levitte.org/cci/state/1751cb06-88fd-4687-9ae4-bfcf151ca3b0/w)

shell: 'cargo --version

  rustc --version


  cargo fmt --check

  cargo clippy --all-targets --workspace -- --deny clippy::all

  cargo build --all-targets --workspace

  cargo doc --workspace

  cargo test --workspace --no-fail-fast

  '

Run the script

Commands:

Send result

{
  "response": "finished",
  "result": "failure"
}