diff --git a/docs/issues/drafts/1669-coupling-tool-resolve-lib-names-and-renames/ISSUE.md b/docs/issues/drafts/1669-coupling-tool-resolve-lib-names-and-renames/ISSUE.md new file mode 100644 index 000000000..c89a1b0bf --- /dev/null +++ b/docs/issues/drafts/1669-coupling-tool-resolve-lib-names-and-renames/ISSUE.md @@ -0,0 +1,237 @@ +--- +schema-version: 1 +doc-type: issue +issue-type: bug +status: draft +priority: p3 +epic: 1669 +github-issue: null +spec-path: docs/issues/drafts/1669-coupling-tool-resolve-lib-names-and-renames/ISSUE.md +branch: "{issue-number}-1669-coupling-tool-resolve-lib-names-and-renames" +related-pr: null +last-updated-utc: "2026-10-07 12:39" +semantic-links: + skill-links: + - create-issue + - fix-bug + related-artifacts: + - docs/issues/drafts/1669-coupling-tool-resolve-lib-names-and-renames/manual-verification-evidence.md + - contrib/dev-tools/analysis/workspace-coupling/src/main.rs + - contrib/dev-tools/analysis/workspace-coupling/tests/parse_imports.rs + - docs/issues/open/1669-overhaul-packages/workspace-coupling-report-2026-10-06.md + - docs/issues/open/1669-overhaul-packages/EPIC.md +--- + + + +# Issue #[To be assigned] - Coupling tool misses renamed dependencies and custom library names + +Subissue of EPIC [#1669](../../open/1669-overhaul-packages/EPIC.md) (Overhaul: Packages). + +## Goal + +Make `contrib/dev-tools/analysis/workspace-coupling/` find the imports of every workspace +dependency, including dependencies renamed in `Cargo.toml` and packages whose library target has +a custom name. + +## Background + +### What goes wrong + +1. For each dependency edge `A → B`, the tool builds the Rust module name to search for from + B's package name: `name.replace('-', "_")` in `src/main.rs`. +2. It then scans A's `src/`, `tests/` and `benches/` for `B_module::` paths. +3. Rust code does not use that name when the dependency is renamed in A's `Cargo.toml` + (`foo = { package = "b", ... }` makes the module `foo`) or when B's library target has a + custom name (`[lib] name = ...`). +4. The scan finds nothing and the report says "No `…::` references found in source", although + A imports B. + +This contradicts the report's own contract ("For every dependency the items actually imported +from it are listed"). Impact today: five edges show no imports, so a reader could take a used +dependency for an unused one, and thin-dependency reviews skip those edges. + +### Reproduction + +**Reproduced** on 2026-10-07 with the real tool; commands and output are in +[`manual-verification-evidence.md`](manual-verification-evidence.md) (R1). The five affected +edges: + +| Edge | Kind | Why the module name differs | +| ---------------------------------------- | ------ | ------------------------------------------------------------------------------------- | +| `client` → `client-lib` | normal | Dependency renamed to `torrust-tracker-client` in `console/tracker-client/Cargo.toml` | +| `udp-server` → `client-lib` | normal | Dependency renamed to `torrust-tracker-client` in `packages/udp-server/Cargo.toml` | +| `test-helpers` → `client-lib` | normal | Library target named `torrust_tracker_client` in `packages/tracker-client/Cargo.toml` | +| `axum-http-server` → `client-lib` | dev | Library target named `torrust_tracker_client` | +| `e2e-tools` → `torrust-tracker` | normal | Root library target named `torrust_tracker_lib` | + +The 2026-10-06 report ([finding 3](../../open/1669-overhaul-packages/workspace-coupling-report-2026-10-06.md#3-the-tool-misses-renamed-crates-and-custom-library-names), +issue #2446) now lists all five. + +`cargo metadata` already provides both facts: each dependency's `rename`, and each package's +library target name (`targets[]` with kind `lib`). + +## Scope + +### In Scope + +- Resolve the module name of each dependency edge from the dependency's `rename` when present, + otherwise from the dependency package's library target name, falling back to the package name. +- Add regression tests covering a renamed dependency and a custom library name. +- Regenerate the coupling report as a new dated file and confirm the five edges list imports. + +### Out of Scope + +- Other scan limitations (macro expansion, inactive `cfg` code) documented in the report header. +- Changing the report format. + +## Architectural Decisions + +- Related ADRs: None +- ADRs to create: None known + +## Design and Ownership Review + +Not applicable: a single pure name-resolution step changes; no processes, I/O or fixtures. + +## Bug-Fix Process + +Follows the [`fix-bug`](../../../../.github/skills/dev/debugging/fix-bug/SKILL.md) skill: + +1. Analysis and reproduction: done before review; the real tool was run and the outcome + classified as **Reproduced** in `manual-verification-evidence.md` (R1). +2. Regression tests (T1): written first and recorded red against the unfixed tool. +3. Fix (T2): resolve the module name from `rename`, then the library target name. +4. Green and recheck (T3): tests pass; the R1 command is rerun unchanged (R2) and lists no + false "no references" edge. + +## Regression Test Strategy + +- Boundary: unit tests of the module-name resolution, the single function the bug lives in, + fed with `cargo metadata`-shaped package and dependency data. No workspace is needed. +- Cases: a renamed dependency, a custom library target name, and the plain package-name + default. +- Each test is recorded failing against the unfixed code before the fix lands, per the + `write-unit-test` skill. + +## Implementation Plan + +Status values: `TODO`, `IN_PROGRESS`, `BLOCKED`, `DONE`. + +| ID | Status | Task | Notes / Expected Output | +| --- | ------ | ---------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | +| T1 | TODO | Add regression tests for a renamed dependency, a custom library name and the default | Recorded red run: the rename and library-name cases fail on the current tool | +| T2 | TODO | Resolve module names from `rename` and the library target name | The T1 tests pass | +| T3 | TODO | Green run plus like-for-like recheck: rerun the R1 command unchanged | R2 in the evidence lists no false "no references" edge | +| T4 | TODO | Regenerate the coupling report as a new dated file | The five edges list their imports | + +## Commit Points + +| Task | Coherent change set | Commit policy | +| ---- | ----------------------------------------- | -------------------------------------------------------------------------- | +| T1 | Regression tests | Commit together with T2 so every commit passes; record the red run first. | +| T2 | Name-resolution fix | One commit with T1. | +| T3 | R2 recheck evidence | One commit after the recheck. | +| T4 | New dated coupling report | One commit after R2. | + +Use a Conventional Commit message with the issue reference and sign every commit with GPG. + +## Progress Tracking + +### Workflow Checkpoints + +- [x] Spec drafted in `docs/issues/drafts/` +- [x] Bug reproduced and classified in `manual-verification-evidence.md` before review (R1) +- [ ] Spec reviewed and approved by user/maintainer +- [ ] GitHub issue created and issue number added to this spec +- [ ] Spec moved to `docs/issues/open/` with issue number prefix +- [ ] Implementation completed +- [ ] Automatic verification completed (`linter all`, relevant tests and pre-push checks) +- [ ] Manual verification scenarios executed and recorded in issue-local + `manual-verification-evidence.md` +- [ ] Acceptance criteria reviewed after implementation and updated with evidence +- [ ] Evidence-based implementation completion review recorded +- [ ] Issue closed and spec moved to `docs/issues/closed/` + +### Progress Log + +- 2026-10-06 16:01 UTC - GitHub Copilot - Drafted from finding 3 of the 2026-10-06 workspace + coupling report (#2446). +- 2026-10-07 08:52 UTC - GitHub Copilot - Reworked to follow the `fix-bug` skill, per PR #2462 + review finding F5: plain-language explanation, reproduction run and recorded as + **Reproduced** (R1; it also found a fifth affected edge, the `axum-http-server` dev + dependency), red regression-test task, and a like-for-like recheck (R2). +- 2026-10-07 09:25 UTC - GitHub Copilot - Copied the template's completion-review conditions, + per PR #2462 review finding F15. Backfilled at 12:39 UTC, per review finding F20. +- 2026-10-07 12:29 UTC - GitHub Copilot - The link to finding 3 now says it lists all five + edges, per PR #2462 review finding F21. + +## Acceptance Criteria + +- [ ] AC1: The tool resolves a dependency's module name from its `rename`, then its library + target name, then its package name. +- [ ] AC2: Regression tests cover a renamed dependency, a custom library name and the default; + the rename and library-name tests were recorded failing against the unfixed tool. +- [ ] AC3: Rerunning the R1 command unchanged (R2) lists no false "no references" edge, and the + five edges in the Background list their imports. +- [ ] AC4: `cargo test -p workspace-coupling` and `linter all` exit with code `0`. +- [ ] AC5: The reproduction (R1) and the recheck (R2) are recorded in issue-local + `manual-verification-evidence.md`. +- [ ] AC6: The acceptance criteria are re-reviewed after implementation. + +## Verification Plan + +### Automatic Checks + +- `cargo test -p workspace-coupling` +- `linter all` +- Pre-push checks + +### Manual Verification Scenarios + +Status values: `TODO`, `IN_PROGRESS`, `DONE`, `FAILED`, `BLOCKED`. + +| ID | Scenario | Human-oriented command/steps | Expected Result | Status | Evidence | +| --- | ---------------------------- | -------------------------------------------------------------------------------------------- | ----------------------------------------------------------- | ------ | -------------------------------------------- | +| R1 | Initial reproduction | `cargo run -q -p workspace-coupling -- /tmp/repro-2446.md`, then list the "no references" edges | Five used edges reported with no references (the bug) | DONE | `manual-verification-evidence.md` section R1 | +| R2 | Like-for-like recheck | Same command and listing as R1, after the fix | No false "no references" edge; the five edges list imports | TODO | `manual-verification-evidence.md` section R2 | + +Record the toolchain for each `cargo` command in the evidence file. + +### Acceptance Verification + +| AC ID | Status (`TODO`/`DONE`) | Evidence | +| ----- | ---------------------- | -------- | +| AC1 | TODO | | +| AC2 | TODO | | +| AC3 | TODO | | +| AC4 | TODO | | +| AC5 | TODO | | +| AC6 | TODO | | + +## Risks and Trade-offs + +- A dependency could be renamed differently by different dependents; resolution must be per + edge, not per package. + +## Implementation Completion Review + +After implementation, compare the result with this specification. Record +invalidated assumptions, material design changes, unexpected validation +findings, and reusable lessons. + +- Retrospective: `Not yet assessed` +- If needed, create `implementation-retrospective.md` from the repository + template at `docs/templates/IMPLEMENTATION-RETROSPECTIVE.md` in this issue + specification's directory. +- If no retrospective is needed, add a concise progress-log entry explaining + why the work had no material discovery. +- When an independent reviewer receives this folder-style specification, it + records its result in `agent-review-reports.md` using + `docs/templates/AGENT-REVIEW-REPORTS.md`. + +## References + +- EPIC: [`docs/issues/open/1669-overhaul-packages/EPIC.md`](../../open/1669-overhaul-packages/EPIC.md) +- Source finding: [2026-10-06 coupling report](../../open/1669-overhaul-packages/workspace-coupling-report-2026-10-06.md) +- Baseline issue: #2446 diff --git a/docs/issues/drafts/1669-coupling-tool-resolve-lib-names-and-renames/manual-verification-evidence.md b/docs/issues/drafts/1669-coupling-tool-resolve-lib-names-and-renames/manual-verification-evidence.md new file mode 100644 index 000000000..a38abd381 --- /dev/null +++ b/docs/issues/drafts/1669-coupling-tool-resolve-lib-names-and-renames/manual-verification-evidence.md @@ -0,0 +1,119 @@ +--- +doc-type: manual-verification-evidence +issue-spec: docs/issues/drafts/1669-coupling-tool-resolve-lib-names-and-renames/ISSUE.md +last-updated-utc: 2026-10-07 08:48 +--- + + + +# Manual Verification Evidence + +## Purpose + +Record real, human-oriented verification of the completed behavior. This is +evidence from commands or interactions actually performed against the artifact; +do not invent commands, output, logs, or results. + +## Preserving Verification Artifacts + +The commands and the relevant output are recorded inline below. The generated report under +`/tmp/` is scratch output; the excerpts that matter are copied here. + +## Environment and Prerequisites + +- Date and time (UTC): 2026-10-07 08:48 +- Artifact under test: `contrib/dev-tools/analysis/workspace-coupling/` on branch + `2446-1669-establish-baseline-analysis` (PR #2462), before any fix +- Operating system / environment: Linux; stable Rust toolchain (`rustc 1.99.0 (b940084d7 2026-09-28)`) +- Prerequisites and setup performed: none beyond a workspace checkout + +## Verification Processes + +### R1 - Initial reproduction + +- Goal: observe the tool reporting "no references" for dependency edges whose crate is used. +- Initial state: unmodified tool. +- Status: `DONE` — outcome: **Reproduced** + +#### Steps Performed + +1. Run the real tool on the workspace (stable Rust toolchain): + + ```sh + cargo run -q -p workspace-coupling -- /tmp/repro-2446.md + ``` + +2. List every edge the report marks as having no references: + + ```python + import re + txt = open("/tmp/repro-2446.md").read() + pkg = dep = None + for line in txt.splitlines(): + m = re.match(r"^### `(.+)`", line) + if m: pkg = m.group(1); continue + m = re.match(r"^#### `(.+)` \[(.+)\]", line) + if m: dep = m.group(1); continue + if "No `" in line and "references found" in line: + print(f"{pkg} -> {dep}: {line.strip()}") + ``` + +3. Show that each dependency is used in source, and how its module name differs: + + ```sh + grep -rn "^use torrust_tracker_client::" console/tracker-client/src | head -1 + grep -rn "torrust_tracker_client::" packages/udp-server/src | head -1 + grep -rn "^use torrust_tracker_client::" packages/test-helpers/src | head -1 + grep -rln "torrust_tracker_client::" packages/axum-http-server/tests | head -1 + grep -rn "torrust_tracker_lib::" packages/e2e-tools/src | head -1 + grep -n "torrust-tracker-client" console/tracker-client/Cargo.toml packages/udp-server/Cargo.toml packages/test-helpers/Cargo.toml packages/axum-http-server/Cargo.toml + grep -n -A1 "^\[lib\]" packages/tracker-client/Cargo.toml Cargo.toml + ``` + +#### Observed Result + +Step 1 exited with code 0. Step 2: + +```text +torrust-tracker-axum-http-server -> torrust-tracker-client-lib: _No `torrust_tracker_client_lib::` references found in source — may be used only in `Cargo.toml` feature flags or `build.rs`._ +torrust-tracker-client -> torrust-tracker-client-lib: _No `torrust_tracker_client_lib::` references found in source — may be used only in `Cargo.toml` feature flags or `build.rs`._ +torrust-tracker-e2e-tools -> torrust-tracker: _No `torrust_tracker::` references found in source — may be used only in `Cargo.toml` feature flags or `build.rs`._ +torrust-tracker-test-helpers -> torrust-tracker-client-lib: _No `torrust_tracker_client_lib::` references found in source — may be used only in `Cargo.toml` feature flags or `build.rs`._ +torrust-tracker-udp-server -> torrust-tracker-client-lib: _No `torrust_tracker_client_lib::` references found in source — may be used only in `Cargo.toml` feature flags or `build.rs`._ +``` + +Step 3: + +```text +console/tracker-client/src/console/clients/udp/mod.rs:5:use torrust_tracker_client::udp; +packages/udp-server/src/server/launcher.rs:16:use torrust_tracker_client::udp::client::check; +packages/test-helpers/src/http.rs:5:use torrust_tracker_client::http::client::Client; +packages/axum-http-server/tests/server/v1/contract/using_ipv6_v6only.rs +packages/e2e-tools/src/bin/e2e_tests_runner.rs:2:use torrust_tracker_lib::console::ci::e2e; +console/tracker-client/Cargo.toml:29:torrust-tracker-client = { package = "torrust-tracker-client-lib", version = "0.1.0", path = "../../packages/tracker-client" } +packages/udp-server/Cargo.toml:23:torrust-tracker-client = { package = "torrust-tracker-client-lib", version = "0.1.0", path = "../tracker-client" } +packages/test-helpers/Cargo.toml:22:torrust-tracker-client-lib = { version = "0.1.0", path = "../tracker-client" } +packages/axum-http-server/Cargo.toml:54:torrust-tracker-client-lib = { version = "0.1.0", path = "../tracker-client" } +packages/tracker-client/Cargo.toml:20:[lib] +packages/tracker-client/Cargo.toml-21-name = "torrust_tracker_client" +Cargo.toml:18:[lib] +Cargo.toml-19-name = "torrust_tracker_lib" +``` + +#### Conclusion + +**Reproduced.** Five edges are reported with no references although each dependency is used: +two through a `Cargo.toml` rename (`torrust-tracker-client`), two through the custom library +name `torrust_tracker_client`, and one through the root library name `torrust_tracker_lib`. +The tool searched for `torrust_tracker_client_lib::` and `torrust_tracker::`, which never +appear. The `axum-http-server` edge is a dev dependency, so the 2026-10-06 report's finding +(which counted only normal edges) listed four. + +### R2 - Final recheck + +- Goal: after the fix, the same command lists no false "no references" edge. +- Status: `TODO` + +## Failures and Follow-up + +None yet. diff --git a/docs/issues/drafts/1669-decouple-test-helpers-from-unpublished-crates/ISSUE.md b/docs/issues/drafts/1669-decouple-test-helpers-from-unpublished-crates/ISSUE.md new file mode 100644 index 000000000..25af18979 --- /dev/null +++ b/docs/issues/drafts/1669-decouple-test-helpers-from-unpublished-crates/ISSUE.md @@ -0,0 +1,214 @@ +--- +schema-version: 1 +doc-type: issue +issue-type: task +status: draft +priority: p2 +epic: 1669 +github-issue: null +spec-path: docs/issues/drafts/1669-decouple-test-helpers-from-unpublished-crates/ISSUE.md +branch: "{issue-number}-1669-decouple-test-helpers-from-unpublished-crates" +related-pr: null +last-updated-utc: "2026-10-07 12:39" +semantic-links: + skill-links: + - create-issue + related-artifacts: + - packages/test-helpers/Cargo.toml + - packages/test-helpers/src/http.rs + - packages/test-helpers/src/udp.rs + - tests/common/mod.rs + - docs/issues/open/1669-overhaul-packages/workspace-coupling-report-2026-10-06.md + - docs/issues/open/1669-overhaul-packages/EPIC.md +--- + + + +# Issue #[To be assigned] - Decouple published `test-helpers` from unpublished crates + +Subissue of EPIC [#1669](../../open/1669-overhaul-packages/EPIC.md) (Overhaul: Packages). + +## Goal + +Make `torrust-tracker-test-helpers` publishable again by removing its normal dependencies on +unpublished workspace crates, without losing the HTTP and UDP client helpers the root +integration tests use. + +## Background + +The 2026-10-06 workspace coupling report +([finding 1](../../open/1669-overhaul-packages/workspace-coupling-report-2026-10-06.md#1-published-test-helpers-depends-on-unpublished-crates), +issue #2446) found that `torrust-tracker-test-helpers`, published on crates.io as 3.0.0, grew from +one to five workspace dependencies. Its `http` and `udp` modules import +`torrust-tracker-client-lib`, `torrust-tracker-http-protocol` and +`torrust-tracker-udp-protocol`, none of which is published, so a new `test-helpers` release cannot +be published. + +The modules arrived with commit "fix(tracker): replace address-keyed bootstrap containers with +ordered vec" (2026-07-29). Their public functions (`http_announce`, `http_scrape`, +`udp_announce`, `udp_complete_download`, `udp_scrape` and three `send_invalid_connection_id*` +helpers) are used only by the root crate's integration tests under `tests/` (through +`tests/common/mod.rs`). The other modules (`configuration`, `logging`, `random`) are used across +the workspace and depend only on `configuration` and `primitives`, both published. + +## Scope + +### In Scope + +- Move the `http` and `udp` helpers out of `test-helpers` and record the decision in + `docs/issues/open/1669-overhaul-packages/DECISIONS.md`. Destinations to assess: + 1. The root crate's `tests/common/` (their only consumer today). + 2. A new workspace package with `publish = false`, if other packages are expected to need + them. +- Remove the then-unused dependencies from `test-helpers` and update the affected tests. +- Regenerate or annotate the coupling report and the dependency diagram for the changed edges. + +Rejected approaches, both of which leave `test-helpers` unpublishable: + +- Gating the modules behind a Cargo feature: `cargo publish` needs every dependency, optional + ones included, to come from a registry. +- Publishing `client-lib` and the protocol crates first: a release decision outside this EPIC. + +### Out of Scope + +- Publishing any crate to crates.io. +- Publishing the protocol crates or `client-lib`. +- Changing the behaviour of the helpers or of the tests that use them. + +## Architectural Decisions + +- Related ADRs: [`docs/adrs/20260629000000_adopt_independent_package_versioning.md`](../../../adrs/20260629000000_adopt_independent_package_versioning.md) +- Decision to record: the chosen destination, as the next free entry in + [`DECISIONS.md`](../../open/1669-overhaul-packages/DECISIONS.md) + +## Design and Ownership Review + +Not applicable unless the helpers move into `tests/common/`: in that case, keep each helper's +responsibilities unchanged and review the moved code against the `write-unit-test` skill's +fixture guidance. + +## Bug-Fix Process + +Not applicable: no product behaviour is wrong; the problem is a publishing constraint. + +## Regression Test Strategy + +Not applicable. The existing root integration tests that use the helpers must still pass. + +## Implementation Plan + +Status values: `TODO`, `IN_PROGRESS`, `BLOCKED`, `DONE`. + +| ID | Status | Task | Notes / Expected Output | +| --- | ------ | ----------------------------------------------------------------------- | ------------------------------------------------------------------------- | +| T1 | TODO | Choose the destination of the `http` and `udp` helpers and record it in `DECISIONS.md` | Decision entry with the chosen destination and why | +| T2 | TODO | Move the helpers and remove the unpublished dependencies from `test-helpers` | `test-helpers` has no normal dependency on an unpublished crate | +| T3 | TODO | Update the coupling report observations and the dependency diagram | Finding 1 marked resolved; diagram edges match `cargo metadata` | + +## Commit Points + +| Task | Coherent change set | Commit policy | +| ---- | ------------------------------------------------------ | ----------------------------------------------------- | +| T1 | `DECISIONS.md` entry | One commit after maintainer approval of the decision. | +| T2 | Helper move plus manifest changes | One commit after the affected tests pass. | +| T3 | Coupling report note and diagram edges | One commit after MV2. | + +Use a Conventional Commit message with the issue reference and sign every commit with GPG. + +## Progress Tracking + +### Workflow Checkpoints + +- [x] Spec drafted in `docs/issues/drafts/` +- [ ] Spec reviewed and approved by user/maintainer +- [ ] GitHub issue created and issue number added to this spec +- [ ] Spec moved to `docs/issues/open/` with issue number prefix +- [ ] Implementation completed +- [ ] Automatic verification completed (`linter all`, relevant tests and pre-push checks) +- [ ] Manual verification scenarios executed and recorded in issue-local + `manual-verification-evidence.md` +- [ ] Acceptance criteria reviewed after implementation and updated with evidence +- [ ] Evidence-based implementation completion review recorded +- [ ] Issue closed and spec moved to `docs/issues/closed/` + +### Progress Log + +- 2026-10-06 16:01 UTC - GitHub Copilot - Drafted from finding 1 of the 2026-10-06 workspace + coupling report (#2446). +- 2026-10-07 08:40 UTC - GitHub Copilot - Removed the escape clauses and the options that leave + `test-helpers` unpublishable (feature gate, publish first), per PR #2462 review finding F3. +- 2026-10-07 09:25 UTC - GitHub Copilot - Copied the template's completion-review conditions, + per PR #2462 review finding F15. Backfilled at 12:39 UTC, per review finding F20. + +## Acceptance Criteria + +- [ ] AC1: The decision is recorded in `DECISIONS.md`. +- [ ] AC2: `torrust-tracker-test-helpers` has no dependency (normal or optional) on an + unpublished workspace crate. +- [ ] AC3: The root integration tests that used the `http` and `udp` helpers still pass. +- [ ] AC4: `cargo publish --dry-run -p torrust-tracker-test-helpers` succeeds. +- [ ] AC5: `linter all` exits with code `0`. +- [ ] AC6: Manual verification scenarios are executed and documented in issue-local + `manual-verification-evidence.md`. +- [ ] AC7: The acceptance criteria are re-reviewed after implementation. + +## Verification Plan + +### Automatic Checks + +- `cargo test --test integration` (root integration tests) +- `linter all` +- Pre-push checks + +### Manual Verification Scenarios + +Status values: `TODO`, `IN_PROGRESS`, `DONE`, `FAILED`, `BLOCKED`. + +| ID | Scenario | Human-oriented command/steps | Expected Result | Status | Evidence | +| --- | ------------------------------------- | -------------------------------------------------------------------- | ------------------------------------------------- | ------ | --------------------------------------------- | +| MV1 | `test-helpers` dependencies | `cargo metadata --no-deps` and list the package's normal dependencies | No unpublished workspace crate among them | TODO | `manual-verification-evidence.md` section MV1 | +| MV2 | `test-helpers` can be packaged | `cargo publish --dry-run -p torrust-tracker-test-helpers` | Succeeds | TODO | `manual-verification-evidence.md` section MV2 | + +Create `manual-verification-evidence.md` from `docs/templates/MANUAL-VERIFICATION-EVIDENCE.md` +when executing these scenarios, and record the toolchain for each `cargo` command. + +### Acceptance Verification + +| AC ID | Status (`TODO`/`DONE`) | Evidence | +| ----- | ---------------------- | -------- | +| AC1 | TODO | | +| AC2 | TODO | | +| AC3 | TODO | | +| AC4 | TODO | | +| AC5 | TODO | | +| AC6 | TODO | | +| AC7 | TODO | | + +## Risks and Trade-offs + +- The next `test-helpers` release no longer contains the `http` and `udp` helpers. External + users of 3.0.0 are unaffected, because 3.0.0 does not contain them. +- A new `publish = false` package adds a workspace member; prefer `tests/common/` unless a + second consumer exists. + +## Implementation Completion Review + +After implementation, compare the result with this specification. Record +invalidated assumptions, material design changes, unexpected validation +findings, and reusable lessons. + +- Retrospective: `Not yet assessed` +- If needed, create `implementation-retrospective.md` from the repository + template at `docs/templates/IMPLEMENTATION-RETROSPECTIVE.md` in this issue + specification's directory. +- If no retrospective is needed, add a concise progress-log entry explaining + why the work had no material discovery. +- When an independent reviewer receives this folder-style specification, it + records its result in `agent-review-reports.md` using + `docs/templates/AGENT-REVIEW-REPORTS.md`. + +## References + +- EPIC: [`docs/issues/open/1669-overhaul-packages/EPIC.md`](../../open/1669-overhaul-packages/EPIC.md) +- Source finding: [2026-10-06 coupling report](../../open/1669-overhaul-packages/workspace-coupling-report-2026-10-06.md) +- Baseline issue: #2446 diff --git a/docs/issues/drafts/1669-gate-server-testing-modules-behind-feature/ISSUE.md b/docs/issues/drafts/1669-gate-server-testing-modules-behind-feature/ISSUE.md new file mode 100644 index 000000000..b7ef9ff3e --- /dev/null +++ b/docs/issues/drafts/1669-gate-server-testing-modules-behind-feature/ISSUE.md @@ -0,0 +1,226 @@ +--- +schema-version: 1 +doc-type: issue +issue-type: task +status: draft +priority: p3 +epic: 1669 +github-issue: null +spec-path: docs/issues/drafts/1669-gate-server-testing-modules-behind-feature/ISSUE.md +branch: "{issue-number}-1669-gate-server-testing-modules-behind-feature" +related-pr: null +last-updated-utc: "2026-10-07 12:39" +semantic-links: + skill-links: + - create-issue + related-artifacts: + - packages/axum-rest-api-server/src/testing/environment.rs + - packages/axum-http-server/src/testing/environment.rs + - packages/udp-server/src/testing/environment.rs + - docs/issues/open/1669-overhaul-packages/DECISIONS.md + - docs/issues/open/1669-overhaul-packages/workspace-coupling-report-2026-10-06.md + - docs/issues/open/1669-overhaul-packages/EPIC.md +--- + + + +# Issue #[To be assigned] - Gate server `testing` modules behind a Cargo feature + +Subissue of EPIC [#1669](../../open/1669-overhaul-packages/EPIC.md) (Overhaul: Packages). + +## Goal + +Stop the server packages' test environments from forcing runtime dependencies, by compiling +each public `src/testing/` module only when a `testing` Cargo feature is enabled. Dependencies +used only by a `testing` module become optional, enabled only by that feature; dependencies used +only by tests become dev dependencies. + +Note: `cargo metadata` still reports an optional dependency with `kind: null` (normal), marked +`optional: true`. The coupling tool and the dependency diagram currently classify edges by kind +only, so this issue also makes them show optional edges explicitly. + +## Background + +DEC-13 relocated the server test environments to public `src/testing/` modules in +`axum-rest-api-server`, `axum-http-server` and `udp-server`, and accepted that these modules +compile into release builds. The 2026-10-06 workspace coupling report +([finding 2](../../open/1669-overhaul-packages/workspace-coupling-report-2026-10-06.md#2-server-testing-modules-turn-test-only-edges-into-runtime-dependencies), +issue #2446) shows what that costs: + +- `axum-rest-api-server` → `udp-server`, `udp-core`, `http-core` and + `swarm-coordination-registry` are imported only by `src/testing/environment.rs` and + `#[cfg(test)]` code. Production code reaches UDP only through `rest-api-runtime-adapter`. +- `axum-http-server` → `swarm-coordination-registry` and `udp-server` → + `swarm-coordination-registry` are imported only by their `src/testing/` modules and tests. + +The `testing` modules are used by each package's own tests and examples +(`examples/http_only_public_tracker.rs`, `examples/udp_only_public_tracker.rs`) and by +`axum-health-check-api-server`'s tests. + +## Scope + +### In Scope + +- Add a `testing` feature to the three server packages and gate `pub mod testing` with it. +- Make the dependencies used only by the `testing` modules optional (enabled by the feature), + and move them to `[dev-dependencies]` where only tests use them. +- Enable the feature where it is needed: each package's own tests and examples + (`required-features`) and `axum-health-check-api-server`'s dev-dependencies. +- Record the change as a follow-up to DEC-13 in `DECISIONS.md`. +- Make the coupling tool label optional dependencies (for example `[normal, optional]`) and + draw optional edges distinctly (for example dashed) in the dependency diagram. +- Update the coupling report observations and the dependency diagram for the removed edges. + +### Out of Scope + +- Changing what the test environments do. +- The `test_helpers` module of `tracker-core` (not reported as a runtime-edge problem). +- Revisiting `deny.toml` layer rules beyond what the removed edges allow. + +## Architectural Decisions + +- Related decisions: DEC-13 in [`DECISIONS.md`](../../open/1669-overhaul-packages/DECISIONS.md) +- Decision to record: a DEC-13 follow-up stating that `testing` modules are feature-gated + +## Design and Ownership Review + +Not applicable: the test environments' ownership and behaviour do not change; only their +compilation condition does. + +## Bug-Fix Process + +Not applicable. + +## Regression Test Strategy + +Not applicable. All tests and examples that use the `testing` modules must still build and pass +with the feature enabled, and the packages must build without it. + +## Implementation Plan + +Status values: `TODO`, `IN_PROGRESS`, `BLOCKED`, `DONE`. + +| ID | Status | Task | Notes / Expected Output | +| --- | ------ | ------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------- | +| T1 | TODO | Record the DEC-13 follow-up in `DECISIONS.md` | Decision entry approved by the maintainer | +| T2 | TODO | Gate `axum-rest-api-server`'s `testing` module and adjust its dependencies | `udp-server`, `udp-core`, `http-core`, swarm registry optional (feature `testing`) or dev deps | +| T3 | TODO | Gate `axum-http-server`'s `testing` module and adjust its dependencies | Swarm registry optional or a dev dep, unless production code needs it | +| T4 | TODO | Gate `udp-server`'s `testing` module and adjust its dependencies | Swarm registry optional or a dev dep, unless production code needs it | +| T5 | TODO | Label optional dependencies in the coupling tool, draw them distinctly in the diagram, and update the report observations | Finding 2 marked resolved; optional edges marked in report and diagram; diagram matches `cargo metadata` including `optional` | + +## Commit Points + +| Task | Coherent change set | Commit policy | +| ---- | ----------------------------------------------------------- | ------------------------------------------------------------------- | +| T1 | `DECISIONS.md` entry | One commit after maintainer approval. | +| T2 | Feature, gate and manifest changes for `axum-rest-api-server` | One commit after its tests and the health-check tests pass. | +| T3 | Same for `axum-http-server` | One commit after its tests and examples build and pass. | +| T4 | Same for `udp-server` | One commit after its tests and examples build and pass. | +| T5 | Tool labelling, diagram edges and report note | One commit for the tool change with its tests, one for the docs after MV2. | + +Use a Conventional Commit message with the issue reference and sign every commit with GPG. + +## Progress Tracking + +### Workflow Checkpoints + +- [x] Spec drafted in `docs/issues/drafts/` +- [ ] Spec reviewed and approved by user/maintainer +- [ ] GitHub issue created and issue number added to this spec +- [ ] Spec moved to `docs/issues/open/` with issue number prefix +- [ ] Implementation completed +- [ ] Automatic verification completed (`linter all`, relevant tests and pre-push checks) +- [ ] Manual verification scenarios executed and recorded in issue-local + `manual-verification-evidence.md` +- [ ] Acceptance criteria reviewed after implementation and updated with evidence +- [ ] Evidence-based implementation completion review recorded +- [ ] Issue closed and spec moved to `docs/issues/closed/` + +### Progress Log + +- 2026-10-06 16:01 UTC - GitHub Copilot - Drafted from finding 2 of the 2026-10-06 workspace + coupling report (#2446). +- 2026-10-07 08:44 UTC - GitHub Copilot - Optional dependencies stay `kind: null` in + `cargo metadata`, so the goal, tasks, AC3 and MV2 now describe optional edges explicitly and + AC8 requires the tool and diagram to show them, per PR #2462 review finding F4. +- 2026-10-07 09:25 UTC - GitHub Copilot - Copied the template's completion-review conditions, + per PR #2462 review finding F15. Backfilled at 12:39 UTC, per review finding F20. + +## Acceptance Criteria + +- [ ] AC1: The DEC-13 follow-up is recorded in `DECISIONS.md`. +- [ ] AC2: Each of the three server packages compiles its `testing` module only with the + `testing` feature. +- [ ] AC3: Every dependency of a server package that only its `testing` module uses is + `optional: true` and enabled only by the `testing` feature; every dependency that only + tests use is a dev dependency. +- [ ] AC4: Each server package builds without the `testing` feature, and all tests and examples + that use the module build and pass with it. +- [ ] AC5: `cargo deny check bans` and `linter all` exit with code `0`. +- [ ] AC6: Manual verification scenarios are executed and documented in issue-local + `manual-verification-evidence.md`. +- [ ] AC7: The acceptance criteria are re-reviewed after implementation. +- [ ] AC8: The coupling report labels optional dependencies and the dependency diagram draws + optional edges distinctly, so feature-gated edges are not shown as plain runtime edges. + +## Verification Plan + +### Automatic Checks + +- `cargo test --workspace --all-targets --all-features` +- `cargo build` for each server package without features +- `cargo deny check bans`, `cargo machete` and `linter all` + +### Manual Verification Scenarios + +Status values: `TODO`, `IN_PROGRESS`, `DONE`, `FAILED`, `BLOCKED`. + +| ID | Scenario | Human-oriented command/steps | Expected Result | Status | Evidence | +| --- | ---------------------------------- | --------------------------------------------------------------------------------------------------- | ---------------------------------------------------- | ------ | --------------------------------------------- | +| MV1 | Release build without test code | `cargo build --release -p ` for each server, then confirm the `testing` module is excluded | Builds; no `testing` symbols in the library | TODO | `manual-verification-evidence.md` section MV1 | +| MV2 | Test-only edges are optional | List the three servers' dependencies with `kind` and `optional` from `cargo metadata --no-deps`, then regenerate the coupling report | The test-only edges show `optional: true` (or dev kind), and the report labels them optional | TODO | `manual-verification-evidence.md` section MV2 | + +Create `manual-verification-evidence.md` from `docs/templates/MANUAL-VERIFICATION-EVIDENCE.md` +when executing these scenarios, and record the toolchain for each `cargo` command. + +### Acceptance Verification + +| AC ID | Status (`TODO`/`DONE`) | Evidence | +| ----- | ---------------------- | -------- | +| AC1 | TODO | | +| AC2 | TODO | | +| AC3 | TODO | | +| AC4 | TODO | | +| AC5 | TODO | | +| AC6 | TODO | | +| AC7 | TODO | | +| AC8 | TODO | | + +## Risks and Trade-offs + +- Consumers outside each package must enable the feature explicitly; forgetting it gives a + compile error, not a silent change. +- More feature combinations to build in CI; `--all-features` covers the gated code. + +## Implementation Completion Review + +After implementation, compare the result with this specification. Record +invalidated assumptions, material design changes, unexpected validation +findings, and reusable lessons. + +- Retrospective: `Not yet assessed` +- If needed, create `implementation-retrospective.md` from the repository + template at `docs/templates/IMPLEMENTATION-RETROSPECTIVE.md` in this issue + specification's directory. +- If no retrospective is needed, add a concise progress-log entry explaining + why the work had no material discovery. +- When an independent reviewer receives this folder-style specification, it + records its result in `agent-review-reports.md` using + `docs/templates/AGENT-REVIEW-REPORTS.md`. + +## References + +- EPIC: [`docs/issues/open/1669-overhaul-packages/EPIC.md`](../../open/1669-overhaul-packages/EPIC.md) +- Source finding: [2026-10-06 coupling report](../../open/1669-overhaul-packages/workspace-coupling-report-2026-10-06.md) +- DEC-13: [`DECISIONS.md`](../../open/1669-overhaul-packages/DECISIONS.md) +- Baseline issue: #2446 diff --git a/docs/issues/open/1669-overhaul-packages/EPIC.md b/docs/issues/open/1669-overhaul-packages/EPIC.md index 37a5e7cdd..366501827 100644 --- a/docs/issues/open/1669-overhaul-packages/EPIC.md +++ b/docs/issues/open/1669-overhaul-packages/EPIC.md @@ -663,9 +663,12 @@ Status: TODO unless noted. #### 4. Other Tracked Items (Drafts and Promoted Issues) -- [ ] [#2446](https://github.com/torrust/torrust-tracker/issues/2446) SI-01: Establish baseline: dependency graph + README audit _(analysis; no blockers; informs all other subissues)_ — original tasks done May to June 2026; outputs to be refreshed for the post-#1938 workspace +- [x] [#2446](https://github.com/torrust/torrust-tracker/issues/2446) SI-01: Establish baseline: dependency graph + README audit _(analysis; no blockers; informs all other subissues)_ — **DONE** (2026-10-06 coupling report, refreshed README audit and dependency diagram; three findings drafted as subissues) - [ ] Update all package READMEs _(documentation; after completed rename work; before extractions)_ - [ ] [#2454](https://github.com/torrust/torrust-tracker/issues/2454) Mark public error enums `#[non_exhaustive]` before first publish _(Pre-publish API checklist; per crate, before its first publish)_ +- [ ] Decouple published `test-helpers` from unpublished crates _(draft; finding 1 of the 2026-10-06 coupling report)_ +- [ ] Gate server `testing` modules behind a Cargo feature _(draft; finding 2 of the 2026-10-06 coupling report; DEC-13 follow-up)_ +- [ ] Fix coupling-tool module name resolution for renamed dependencies and custom library names _(draft; finding 3 of the 2026-10-06 coupling report)_ - [x] [#1881](https://github.com/torrust/torrust-tracker/issues/1881) SI-16: Migrate `contrib/bencode` to `torrust/torrust-bittorrent` as `torrust-bencode` _(Rule E; no blockers within this EPIC)_ - [x] Extract `torrust-clock` to standalone repository — [#1879](https://github.com/torrust/torrust-tracker/issues/1879) _(Rule E; requires completed clock rename and type move work)_ - [x] Extract `torrust-located-error` to standalone repository — [#1894](https://github.com/torrust/torrust-tracker/issues/1894) _(Rule E; requires completed rename SI-10 #1823)_ — **DONE** @@ -684,7 +687,7 @@ Details: | Item | Issue | Local Spec | Status | Notes | | -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------ | --------------------------------------------------------------------------------------------------------------------------------------------- | -| Baseline analysis | [#2446](https://github.com/torrust/torrust-tracker/issues/2446) SI-01: Establish baseline: dependency graph + README audit | [docs/issues/open/2446-1669-establish-baseline-analysis/ISSUE.md](../2446-1669-establish-baseline-analysis/ISSUE.md) | TODO | T1 to T8 done May to June 2026; T9 to T13 refresh the outputs for the post-#1938 workspace | +| Baseline analysis | [#2446](https://github.com/torrust/torrust-tracker/issues/2446) SI-01: Establish baseline: dependency graph + README audit | [docs/issues/open/2446-1669-establish-baseline-analysis/ISSUE.md](../2446-1669-establish-baseline-analysis/ISSUE.md) | DONE | T1 to T8 done May to June 2026; T9 to T13 refreshed the outputs on 2026-10-06 (report, README audit, diagram, three drafts) | | Duration move | [#1790](https://github.com/torrust/torrust-tracker/issues/1790) — Move `DurationSinceUnixEpoch` from `torrust-tracker-primitives` to `torrust-tracker-clock` | [docs/issues/closed/1790-move-duration-since-unix-epoch-to-torrust-tracker-clock/ISSUE.md](../../closed/1790-move-duration-since-unix-epoch-to-torrust-tracker-clock/ISSUE.md) | DONE | Rule M; no hard blockers; prerequisite for clock extraction | | Timeout constants | [#1793](https://github.com/torrust/torrust-tracker/issues/1793) — Define per-package default timeout constants and remove `DEFAULT_TIMEOUT` from `torrust-tracker-configuration` | [docs/issues/closed/1793-1669-03-define-per-package-default-timeout-constants/ISSUE.md](../../closed/1793-1669-03-define-per-package-default-timeout-constants/ISSUE.md) | DONE | Rule M; completed | | Announce policy move | [#1795](https://github.com/torrust/torrust-tracker/issues/1795) — Move `AnnouncePolicy` from `torrust-tracker-configuration` to `torrust-tracker-primitives` | [docs/issues/closed/1795-1669-04-move-announce-policy-to-torrust-tracker-primitives/ISSUE.md](../../closed/1795-1669-04-move-announce-policy-to-torrust-tracker-primitives/ISSUE.md) | DONE | Rule M; completed | @@ -704,6 +707,9 @@ Details: | Server-lib extraction | [#1909](https://github.com/torrust/torrust-tracker/issues/1909) — Extract `torrust-server-lib` to standalone repository | [docs/issues/closed/1909-1669-si-28-extract-server-lib-to-standalone-repo/ISSUE.md](../../closed/1909-1669-si-28-extract-server-lib-to-standalone-repo/ISSUE.md) | DONE | Rule E; no workspace deps; 6 consumers migrated; crate v0.1.0 published | | InfoHash migration | [#1889](https://github.com/torrust/torrust-tracker/issues/1889) — Migrate from `bittorrent-primitives` to `torrust-info-hash` | [docs/issues/closed/1889-1669-21-migrate-from-bittorrent-primitives-to-torrust-info-hash/ISSUE.md](../../closed/1889-1669-21-migrate-from-bittorrent-primitives-to-torrust-info-hash/ISSUE.md) | DONE | SI-21; replaces `bittorrent-primitives` deps across 14 Cargo.toml files with `torrust-info-hash`; unblocks `bittorrent-primitives` archiving | | Tracker client extraction | #TBD — Extract `torrust-tracker-client` to standalone repository | [docs/issues/drafts/1669-extract-torrust-tracker-client-to-standalone-repo/ISSUE.md](../../drafts/1669-extract-torrust-tracker-client-to-standalone-repo/ISSUE.md) | TODO | Rule E; blocked by publication of `udp-protocol`, `http-protocol`, and `tracker-client` lib | +| Test-helpers decoupling | #TBD — Decouple published `test-helpers` from unpublished crates | [docs/issues/drafts/1669-decouple-test-helpers-from-unpublished-crates/ISSUE.md](../../drafts/1669-decouple-test-helpers-from-unpublished-crates/ISSUE.md) | TODO | Draft; finding 1 of the 2026-10-06 coupling report (#2446) | +| Gate server testing | #TBD — Gate server `testing` modules behind a Cargo feature | [docs/issues/drafts/1669-gate-server-testing-modules-behind-feature/ISSUE.md](../../drafts/1669-gate-server-testing-modules-behind-feature/ISSUE.md) | TODO | Draft; finding 2 of the 2026-10-06 coupling report (#2446); DEC-13 follow-up | +| Coupling tool name fix | #TBD — Coupling tool misses renamed dependencies and custom library names | [docs/issues/drafts/1669-coupling-tool-resolve-lib-names-and-renames/ISSUE.md](../../drafts/1669-coupling-tool-resolve-lib-names-and-renames/ISSUE.md) | TODO | Draft; finding 3 of the 2026-10-06 coupling report (#2446) | | UDP trait abstractions | [#1924](https://github.com/torrust/torrust-tracker/issues/1924) SI-30: Extract UDP trait abstractions for REST API (`BanningStats`, `UdpCoreStatsRepository`, `UdpServerStatsRepository`) | [docs/issues/closed/1924-1669-si-30-decouple-rest-api-core-from-udp-internals/ISSUE.md](../../closed/1924-1669-si-30-decouple-rest-api-core-from-udp-internals/ISSUE.md) | DONE | UDP-side only; REST-side wiring deferred to #1930; MAX_CONNECTION_ID_ERRORS_PER_IP → config option | | Cargo deny enforcement | [#1925](https://github.com/torrust/torrust-tracker/issues/1925) SI-31: Configure `cargo deny` for workspace layer boundary enforcement | [docs/issues/closed/1925-1669-si-31-configure-cargo-deny-for-layer-boundary-enforcement/ISSUE.md](../../closed/1925-1669-si-31-configure-cargo-deny-for-layer-boundary-enforcement/ISSUE.md) | DONE | Tooling; create deny.toml with bans for all forbidden edges; add to CI and hooks | | Versioning policy | [#1926](https://github.com/torrust/torrust-tracker/issues/1926) SI-32: Define package versioning strategy | [docs/issues/closed/1926-1669-si-32-define-package-versioning-strategy/ISSUE.md](../../closed/1926-1669-si-32-define-package-versioning-strategy/ISSUE.md) | DONE | Policy; all packages version independently; path deps make linked versions unnecessary | @@ -745,6 +751,9 @@ After SI-14, there is a proposal to evaluate a dedicated repository for protocol - [docs/issues/closed/1925-1669-si-31-configure-cargo-deny-for-layer-boundary-enforcement/ISSUE.md](../../closed/1925-1669-si-31-configure-cargo-deny-for-layer-boundary-enforcement/ISSUE.md) - [docs/issues/closed/1926-1669-si-32-define-package-versioning-strategy/ISSUE.md](../../closed/1926-1669-si-32-define-package-versioning-strategy/ISSUE.md) - [docs/issues/drafts/1669-extract-torrust-tracker-client-to-standalone-repo/ISSUE.md](../../drafts/1669-extract-torrust-tracker-client-to-standalone-repo/ISSUE.md) +- [docs/issues/drafts/1669-decouple-test-helpers-from-unpublished-crates/ISSUE.md](../../drafts/1669-decouple-test-helpers-from-unpublished-crates/ISSUE.md) +- [docs/issues/drafts/1669-gate-server-testing-modules-behind-feature/ISSUE.md](../../drafts/1669-gate-server-testing-modules-behind-feature/ISSUE.md) +- [docs/issues/drafts/1669-coupling-tool-resolve-lib-names-and-renames/ISSUE.md](../../drafts/1669-coupling-tool-resolve-lib-names-and-renames/ISSUE.md) - [docs/issues/closed/1930-1669-si-33-rest-api-contract-first-architecture/ISSUE.md](../../closed/1930-1669-si-33-rest-api-contract-first-architecture/ISSUE.md) - [docs/issues/closed/1910-1669-si-29-rename-udp-and-http-core-protocol-crates-to-remove-redundant-tracker/ISSUE.md](../../closed/1910-1669-si-29-rename-udp-and-http-core-protocol-crates-to-remove-redundant-tracker/ISSUE.md) > New subissues are created as analysis reveals the next improvement. The EPIC is never @@ -773,6 +782,9 @@ The EPIC is re-triggered (a new analysis round starts) whenever: extraction candidates identified and documented. - Exit criteria: Baseline analysis subissue merged; at least one extraction candidate has a scoped subissue ready. +- Status (2026-10-06): baseline done in #2446; the `torrust-tracker-client` extraction has a + scoped draft (blocked by crate publication). The next cycle starts from the three findings + of the [2026-10-06 coupling report](workspace-coupling-report-2026-10-06.md). ### Subsequent cycles @@ -968,6 +980,9 @@ Previously referenced tools (screenshots from CodeScene already in the issue com Delivery Strategy, because it is a decided procedure (PR #2445 review finding F7). - 2026-10-06 16:05 UTC - Copilot - Created #2454 (mark public error enums `#[non_exhaustive]` before first publish), linked as a sub-issue, to apply the Pre-publish API checklist. +- 2026-10-06 16:21 UTC - GitHub Copilot - Completed the baseline (#2446): 2026-10-06 coupling + report, refreshed README audit and dependency diagram; added three draft subissues from the + report's findings; marked AC1 done. - 2026-10-06 20:06 UTC - Copilot - Added Pre-publish API checklist item 4 (a crate whose public error enum gained `#[non_exhaustive]` is published with a semver-major bump), per the maintainer's decision on a PR #2456 review finding. @@ -979,7 +994,7 @@ Previously referenced tools (screenshots from CodeScene already in the issue com Because this EPIC is ongoing, acceptance criteria are defined per cycle, not for the entire EPIC at once. The EPIC is considered healthy (not stale) when: -- [ ] The baseline analysis is merged and the dependency graph is up to date. +- [x] The baseline analysis is merged and the dependency graph is up to date. - [ ] Every clearly independent package either has an open extraction subissue or a recorded decision explaining why extraction was deferred. - [ ] `docs/packages.md` and `AGENTS.md` Package Catalog are accurate after each change. @@ -990,7 +1005,7 @@ entire EPIC at once. The EPIC is considered healthy (not stale) when: | AC ID | Status | Evidence | | ----- | ------ | ---------------------------------------- | -| AC1 | TODO | {baseline analysis PR link} | +| AC1 | DONE | #2446: [2026-10-06 coupling report](workspace-coupling-report-2026-10-06.md), [README audit](readme-audit.md), [dependency diagram](../../../media/packages/dependencies-workspace-packages.md) | | AC2 | TODO | {per-candidate issue or decision record} | | AC3 | TODO | {PR link per structural change} | | AC4 | TODO | {per-subissue links} | diff --git a/docs/issues/open/1669-overhaul-packages/readme-audit.md b/docs/issues/open/1669-overhaul-packages/readme-audit.md index c6b8fc6dd..5d3766b92 100644 --- a/docs/issues/open/1669-overhaul-packages/readme-audit.md +++ b/docs/issues/open/1669-overhaul-packages/readme-audit.md @@ -9,8 +9,14 @@ semantic-links: # README Audit -Point-in-time audit of README quality across all workspace packages and console -tools. Generated manually on 2026-05-18 as part of SI-01 (baseline analysis). +Point-in-time audit of README quality across the tracker packages. First generated manually on +2026-05-18 as part of SI-01 (baseline analysis); refreshed on 2026-10-06 for issue +[#2446](https://github.com/torrust/torrust-tracker/issues/2446). + +The audited set is the 25 tracker packages listed in the EPIC #1669 Package Inventory: the root +`torrust-tracker` crate, `console/tracker-client` and the 23 `packages/*` members. The +`contrib/dev-tools/` workspace members are internal tools and are not audited. Line counts are +`wc -l` of each `README.md`. ## Quality scale @@ -19,64 +25,78 @@ tools. Generated manually on 2026-05-18 as part of SI-01 (baseline analysis). | **good** | Meaningful sections (purpose, usage, badges, examples); gives a reader enough to get started. | | **minimal** | Title, one-sentence description, and at most a `## Documentation` link; mostly placeholder. | | **stub** | Only heading + one-liner + a `## Documentation` link (~11 lines); essentially a template copy. | +| **missing** | The package has no `README.md`. | -## Workspace packages (`packages/`) +## Root crate -| Package directory | Crate name | Lines | Rating | Notes | -| --------------------------------- | ------------------------------------------------- | ----- | ------- | ------------------------------------------------------------ | -| `axum-health-check-api-server` | `torrust-tracker-axum-health-check-api-server` | 49 | minimal | Has purpose and port info; no usage examples | -| `axum-http-tracker-server` | `torrust-tracker-axum-http-server` | 11 | stub | Template only | -| `axum-rest-tracker-api-server` | `torrust-tracker-axum-rest-api-server` | 11 | stub | Template only | -| `axum-server` | `torrust-tracker-axum-server` | 11 | stub | Template only | -| `clock` | `torrust-tracker-clock` | 11 | stub | Template only | -| `configuration` | `torrust-tracker-configuration` | 11 | stub | Template only | -| `events` | `torrust-tracker-events` | 11 | stub | Template only | -| `http-protocol` | `bittorrent-http-tracker-protocol` | 11 | stub | Template only | -| `http-core` | `bittorrent-http-core` | 15 | minimal | Explains when to use vs. when not to; minimal depth | -| `located-error` | `torrust-tracker-located-error` | 11 | stub | Template only | -| `metrics` | `torrust-tracker-metrics` | 210 | good | Comprehensive — overview, types, usage, examples | -| `peer-id` | `bittorrent-peer-id` | 38 | minimal | Origin story + maintenance note; no usage examples | -| `primitives` | `torrust-tracker-primitives` | 11 | stub | Template only | -| `rest-tracker-api-client` | `torrust-tracker-rest-api-client` | 23 | minimal | Has license section; no usage examples | -| `rest-tracker-api-core` | `torrust-tracker-rest-api-core` | 11 | stub | **Wrong title** — says "BitTorrent UDP Tracker Core library" | -| `server-lib` | `torrust-server-lib` | 11 | stub | Template only | -| `swarm-coordination-registry` | `torrust-tracker-swarm-coordination-registry` | 22 | minimal | **Wrong title** — says "Torrust Tracker Torrent Repository" | -| `test-helpers` | `torrust-tracker-test-helpers` | 11 | stub | **Wrong title** — says "Torrust Tracker Configuration" | -| `torrent-repository-benchmarking` | `torrust-tracker-torrent-repository-benchmarking` | 32 | minimal | Has benchmarking section; no run instructions beyond basic | -| `tracker-client` | `bittorrent-tracker-client` | 25 | minimal | Has WIP disclaimer; no usage examples | -| `tracker-core` | `bittorrent-tracker-core` | 39 | minimal | Has purpose and context; no usage examples | -| `udp-protocol` | `bittorrent-udp-tracker-protocol` | 38 | minimal | Has purpose section; no usage examples | -| `udp-core` | `bittorrent-udp-core` | 15 | minimal | Explains when to use; minimal depth | -| `udp-tracker-server` | `torrust-tracker-udp-server` | 11 | stub | Template only | +| Directory | Crate name | Lines | Rating | Notes | +| ----------------- | ----------------- | ----- | ------ | --------------------------------------------------------------------- | +| (repository root) | `torrust-tracker` | 318 | good | Comprehensive: features, demo, roadmap, BEPs, architecture, getting started | -## Console tools (`console/`) +## Workspace packages (`packages/`) -| Directory | Crate name | Lines | Rating | Notes | -| ---------------- | --------------------------- | ----- | ------ | ------------------------------------------- | -| `tracker-client` | `bittorrent-tracker-client` | 204 | good | Comprehensive — purpose, commands, examples | +| Package directory | Crate name | Lines | Rating | Notes | +| --------------------------------- | ------------------------------------------------- | ----- | ------- | ----------------------------------------------------------------------------------------- | +| `axum-health-check-api-server` | `torrust-tracker-axum-health-check-api-server` | 49 | minimal | Purpose, port and example response; **wrong title** ("Torrust Axum HTTP Tracker") | +| `axum-http-server` | `torrust-tracker-axum-http-server` | 37 | minimal | One-line purpose plus testing and coverage instructions | +| `axum-rest-api-server` | `torrust-tracker-axum-rest-api-server` | 11 | stub | Template only | +| `axum-server` | `torrust-tracker-axum-server` | 29 | minimal | Purpose and design notes; notes still name the old `TslConfig` type | +| `configuration` | `torrust-tracker-configuration` | 13 | stub | Template plus a link to the v2-to-v3 migration guide | +| `e2e-tools` | `torrust-tracker-e2e-tools` | 26 | good | Purpose, binary list and usage examples | +| `events` | `torrust-tracker-events` | 11 | stub | Template only | +| `http-core` | `torrust-tracker-http-core` | 15 | minimal | Explains when to use vs. when not to; minimal depth | +| `http-protocol` | `torrust-tracker-http-protocol` | 11 | stub | Template only | +| `persistence-benchmark` | `torrust-tracker-persistence-benchmark` | 18 | good | Purpose and usage examples per database driver | +| `primitives` | `torrust-tracker-primitives` | 11 | stub | Template only | +| `rest-api-application` | `torrust-tracker-rest-api-application` | 11 | stub | Template only | +| `rest-api-client` | `torrust-tracker-rest-api-client` | 23 | minimal | Has license section; no usage examples | +| `rest-api-protocol` | `torrust-tracker-rest-api-protocol` | 11 | stub | Template only | +| `rest-api-runtime-adapter` | `torrust-tracker-rest-api-runtime-adapter` | 11 | stub | Template only | +| `swarm-coordination-registry` | `torrust-tracker-swarm-coordination-registry` | 22 | minimal | **Wrong title** ("Torrust Tracker Torrent Repository") | +| `test-helpers` | `torrust-tracker-test-helpers` | 11 | stub | **Wrong title** ("Torrust Tracker Configuration") | +| `torrent-repository-benchmarking` | `torrust-tracker-torrent-repository-benchmarking` | 32 | minimal | Has a benchmarking section; its `cargo bench -p` command names a package that no longer exists | +| `tracker-client` | `torrust-tracker-client-lib` | 25 | minimal | Has WIP disclaimer; no usage examples | +| `tracker-core` | `torrust-tracker-core` | 39 | minimal | Has purpose and context; no usage examples | +| `udp-core` | `torrust-tracker-udp-core` | 19 | minimal | Explains when to use; links benchmarking notes and ADRs | +| `udp-protocol` | `torrust-tracker-udp-protocol` | 38 | minimal | Has purpose and origin sections; no usage examples | +| `udp-server` | `torrust-tracker-udp-server` | 16 | minimal | Template plus links to the package ADRs | -## Community contributions (`contrib/`) +## Console tools (`console/`) -| Directory | Crate name | Lines | Rating | Notes | -| --------- | --------------------------------- | ----- | ------ | ----------------------------------------- | -| `bencode` | `torrust-tracker-contrib-bencode` | 5 | stub | Title + one-liner only; no usage examples | +| Directory | Crate name | Lines | Rating | Notes | +| ---------------- | ------------------------ | ----- | ------ | ------------------------------------------- | +| `tracker-client` | `torrust-tracker-client` | 204 | good | Comprehensive — purpose, commands, examples | ## Summary | Rating | Count | | ----------- | ----- | -| **good** | 2 | -| **minimal** | 9 | -| **stub** | 16 | +| **good** | 4 | +| **minimal** | 12 | +| **stub** | 9 | +| **missing** | 0 | +| **Total** | 25 | + +Since the 2026-05-18 audit: + +- Removed rows for packages no longer in the workspace: `clock`, `located-error`, `metrics`, + `server-lib` (extracted to standalone repositories), `peer-id` and `contrib/bencode` (moved to + `torrust/torrust-bittorrent`), and `rest-tracker-api-core` (removed by #1938). +- Added rows for the root crate, `e2e-tools`, `persistence-benchmark`, `rest-api-application`, + `rest-api-protocol` and `rest-api-runtime-adapter`. +- Updated folder and crate names to the SI-11 and SI-29 renames. +- Re-rated `axum-http-server`, `axum-server` and `udp-server` from stub to minimal. +- Corrected the Summary: the 2026-05-18 table (2 good, 9 minimal, 16 stub = 27) did not match its + 26 rows (2, 10, 14). -Most workspace packages have stub or minimal READMEs — they were likely cloned from a -template without being updated. The three packages with wrong titles need to be corrected: +Most tracker packages still have stub or minimal READMEs. Fourteen of them link +`docs.rs/crate/torrust-tracker/latest` (the root crate's documentation) instead of their own +crate's page. Three titles are wrong: -| Package directory | Current (wrong) title | Expected title | -| ----------------------------- | ----------------------------------- | --------------------------------------------- | -| `rest-tracker-api-core` | BitTorrent UDP Tracker Core library | Torrust REST Tracker API Core (or equivalent) | -| `swarm-coordination-registry` | Torrust Tracker Torrent Repository | Torrust Tracker Swarm Coordination Registry | -| `test-helpers` | Torrust Tracker Configuration | Torrust Tracker Test Helpers (or equivalent) | +| Package directory | Current (wrong) title | Expected title | +| ------------------------------ | ---------------------------------- | ------------------------------------------- | +| `axum-health-check-api-server` | Torrust Axum HTTP Tracker | Torrust Tracker Health Check API | +| `swarm-coordination-registry` | Torrust Tracker Torrent Repository | Torrust Tracker Swarm Coordination Registry | +| `test-helpers` | Torrust Tracker Configuration | Torrust Tracker Test Helpers | -Improving READMEs to at least **minimal** status across all workspace packages is a -low-effort, high-value documentation task that could be bundled into a dedicated subissue. +Fixing these is in scope for the "Update all package READMEs" draft under EPIC #1669. diff --git a/docs/issues/open/1669-overhaul-packages/workspace-coupling-report-2026-10-06.md b/docs/issues/open/1669-overhaul-packages/workspace-coupling-report-2026-10-06.md new file mode 100644 index 000000000..f90ddc318 --- /dev/null +++ b/docs/issues/open/1669-overhaul-packages/workspace-coupling-report-2026-10-06.md @@ -0,0 +1,1242 @@ +--- +semantic-links: + skill-links: + - create-issue + related-artifacts: + - docs/issues/open/1669-overhaul-packages/EPIC.md + - docs/issues/open/1669-overhaul-packages/DECISIONS.md + - "issue #2446" + - packages/ +--- + +# Workspace Coupling Report + +Generated: 2026-10-06 16:35 UTC + +Workspace packages: 31 + +--- + +## How to read this report + +Each section covers one workspace package that has at least one workspace-level +dependency. For every dependency the items actually imported from it are listed: + +- **Normal dep** — required for compilation of the library/binary. +- **Dev dep** — required only in tests and benchmarks. +- **Build dep** — required only in `build.rs`. + +Items are extracted by parsing the package's `src/`, `tests/`, and `benches/` +directories for `use MODULE::` statements, root aliases, and `MODULE::` fully-qualified path references. +The scan is AST-based with a targeted macro-body path scan; it may miss items generated by macro expansions +or inactive conditional code, +but it handles normal Rust `use` forms, including groups and re-exports. + +**Signal**: a dependency with only 1–3 distinct import paths may be a candidate +for elimination (move the item, break the edge). + +--- + +## Packages with no workspace dependencies + +These packages are leaves (no workspace dep) and are prime extraction candidates. + +- `agent-review-report-contract` +- `clippy-allow-reasons` +- `frontmatter-validator` +- `github-review-threads` +- `package-coverage-check` +- `torrust-tracker-events` +- `torrust-tracker-http-protocol` +- `torrust-tracker-primitives` +- `torrust-tracker-rest-api-protocol` +- `torrust-tracker-udp-protocol` +- `workspace-coupling` + +--- + +## Package coupling details + +### `torrust-tracker` + +Workspace deps: 16 + +#### `torrust-tracker-axum-health-check-api-server` [normal] + +- `torrust_tracker_axum_health_check_api_server::HEALTH_CHECK_API_LOG_TARGET` +- `torrust_tracker_axum_health_check_api_server::resources::Report` +- `torrust_tracker_axum_health_check_api_server::resources::Status` +- `torrust_tracker_axum_health_check_api_server::server` + +#### `torrust-tracker-axum-http-server` [normal] + +- `torrust_tracker_axum_http_server::HTTP_TRACKER_LOG_TARGET` +- `torrust_tracker_axum_http_server::Version` +- `torrust_tracker_axum_http_server::Version::V1` +- `torrust_tracker_axum_http_server::server::Error` +- `torrust_tracker_axum_http_server::server::HttpServer` +- `torrust_tracker_axum_http_server::server::Launcher` + +#### `torrust-tracker-axum-rest-api-server` [normal] + +- `torrust_tracker_axum_rest_api_server::Version` +- `torrust_tracker_axum_rest_api_server::Version::V1` +- `torrust_tracker_axum_rest_api_server::server::ApiServer` +- `torrust_tracker_axum_rest_api_server::server::Error` +- `torrust_tracker_axum_rest_api_server::server::Launcher` + +#### `torrust-tracker-axum-server` [normal] + +- `torrust_tracker_axum_server::signals::GracefulShutdownOutcome` +- `torrust_tracker_axum_server::tls::Error` +- `torrust_tracker_axum_server::tls::make_rust_tls` + +#### `torrust-tracker-configuration` [normal] + +- `torrust_tracker_configuration::ENV_VAR_CONFIG_TOML_PATH` +- `torrust_tracker_configuration::Error` +- `torrust_tracker_configuration::Info` +- `torrust_tracker_configuration::v3_0_0::Configuration` +- `torrust_tracker_configuration::v3_0_0::core::Core` +- `torrust_tracker_configuration::v3_0_0::database::ConnectionInfo` +- `torrust_tracker_configuration::v3_0_0::database::Database` +- `torrust_tracker_configuration::v3_0_0::health_check_api::HealthCheckApi` +- `torrust_tracker_configuration::v3_0_0::http_tracker` +- `torrust_tracker_configuration::v3_0_0::http_tracker::HttpTracker` +- `torrust_tracker_configuration::v3_0_0::logging` +- `torrust_tracker_configuration::v3_0_0::tls` +- `torrust_tracker_configuration::v3_0_0::tracker_api::AccessTokens` +- `torrust_tracker_configuration::v3_0_0::tracker_api::HttpApi` +- `torrust_tracker_configuration::v3_0_0::udp_tracker::UdpTracker` +- `torrust_tracker_configuration::v3_0_0::udp_tracker_server` +- `torrust_tracker_configuration::validator::SemanticValidationError` +- `torrust_tracker_configuration::validator::Validator` + +#### `torrust-tracker-core` [normal] + +- `torrust_tracker_core::container::Error` +- `torrust_tracker_core::container::TrackerCoreContainer` +- `torrust_tracker_core::databases::error` +- `torrust_tracker_core::statistics::event` +- `torrust_tracker_core::statistics::persisted` +- `torrust_tracker_core::torrent::manager::TorrentsManager` + +#### `torrust-tracker-events` [normal] + +- `torrust_tracker_events::shutdown::Completion` + +#### `torrust-tracker-http-core` [normal] + +- `torrust_tracker_http_core::container::HttpTrackerCoreContainer` +- `torrust_tracker_http_core::container::HttpTrackerCoreServices` +- `torrust_tracker_http_core::statistics::event` + +#### `torrust-tracker-primitives` [normal] + +- `torrust_tracker_primitives::ConfigurationInstanceId` +- `torrust_tracker_primitives::ConfigurationInstanceId::new` +- `torrust_tracker_primitives::PrivateMode` +- `torrust_tracker_primitives::RuntimeServiceMetadata` +- `torrust_tracker_primitives::RuntimeServiceMetadata::new` +- `torrust_tracker_primitives::ServiceRole` +- `torrust_tracker_primitives::ServiceRole::RestApi` +- `torrust_tracker_primitives::TrackerPolicy` +- `torrust_tracker_primitives::swarm_metadata::SwarmMetadata` + +#### `torrust-tracker-rest-api-client` [normal] + +- `torrust_tracker_rest_api_client::connection_info::ConnectionInfo` +- `torrust_tracker_rest_api_client::connection_info::Origin` +- `torrust_tracker_rest_api_client::v1::client::ApiHttpClient` + +#### `torrust-tracker-rest-api-protocol` [normal] + +- `torrust_tracker_rest_api_protocol::v1::context::torrent::resources::torrent::Torrent` + +#### `torrust-tracker-rest-api-runtime-adapter` [normal] + +- `torrust_tracker_rest_api_runtime_adapter::v1::container::TrackerHttpApiCoreContainer` + +#### `torrust-tracker-swarm-coordination-registry` [normal] + +- `torrust_tracker_swarm_coordination_registry::container::SwarmCoordinationRegistryContainer` +- `torrust_tracker_swarm_coordination_registry::statistics::activity_metrics_updater` +- `torrust_tracker_swarm_coordination_registry::statistics::event` + +#### `torrust-tracker-udp-core` [normal] + +- `torrust_tracker_udp_core::ConnectionIdValidationPolicy` +- `torrust_tracker_udp_core::UDP_TRACKER_LOG_TARGET` +- `torrust_tracker_udp_core::container::UdpTrackerCoreContainer` +- `torrust_tracker_udp_core::container::UdpTrackerCoreServices` +- `torrust_tracker_udp_core::crypto::keys` +- `torrust_tracker_udp_core::crypto::keys::Keeper` +- `torrust_tracker_udp_core::initialize_static` +- `torrust_tracker_udp_core::services::banning::BanService` +- `torrust_tracker_udp_core::statistics::event` + +#### `torrust-tracker-udp-server` [normal] + +- `torrust_tracker_udp_server::banning::event` +- `torrust_tracker_udp_server::container::UdpTrackerServerContainer` +- `torrust_tracker_udp_server::server::Server` +- `torrust_tracker_udp_server::server::UdpError` +- `torrust_tracker_udp_server::server::spawner::Spawner` +- `torrust_tracker_udp_server::statistics::event` + +#### `torrust-tracker-test-helpers` [dev] + +- `torrust_tracker_test_helpers::configuration::ephemeral_private` +- `torrust_tracker_test_helpers::configuration::ephemeral_public` +- `torrust_tracker_test_helpers::configuration::ephemeral_with_no_services` +- `torrust_tracker_test_helpers::http::http_announce` +- `torrust_tracker_test_helpers::http::http_scrape` +- `torrust_tracker_test_helpers::udp::send_invalid_connection_id_announce` +- `torrust_tracker_test_helpers::udp::send_invalid_connection_ids_across_listeners_until_banned` +- `torrust_tracker_test_helpers::udp::send_invalid_connection_ids_until_banned` +- `torrust_tracker_test_helpers::udp::udp_announce` +- `torrust_tracker_test_helpers::udp::udp_complete_download` +- `torrust_tracker_test_helpers::udp::udp_scrape` + +### `torrust-tracker-axum-health-check-api-server` + +Workspace deps: 8 + +#### `torrust-tracker-axum-server` [normal] + +- `torrust_tracker_axum_server::signals::GracefulShutdownOutcome` +- `torrust_tracker_axum_server::signals::graceful_shutdown` +- `torrust_tracker_axum_server::signals::graceful_shutdown_on_cancellation` + +#### `torrust-tracker-configuration` [normal] + +- `torrust_tracker_configuration::v3_0_0::health_check_api::HealthCheckApi` +- `torrust_tracker_configuration::v3_0_0::public_url::HttpUrl` +- `torrust_tracker_configuration::v3_0_0::tls::TlsConfig` + +#### `torrust-tracker-primitives` [normal] + +- `torrust_tracker_primitives::ConfigurationInstanceId` +- `torrust_tracker_primitives::RuntimeServiceMetadata` +- `torrust_tracker_primitives::ServiceRole` + +#### `torrust-tracker-axum-health-check-api-server` [dev] + +- `torrust_tracker_axum_health_check_api_server::environment::Started` +- `torrust_tracker_axum_health_check_api_server::resources::Report` +- `torrust_tracker_axum_health_check_api_server::resources::Status` + +#### `torrust-tracker-axum-http-server` [dev] + +- `torrust_tracker_axum_http_server::server::check_fn_with_client` +- `torrust_tracker_axum_http_server::testing::environment` + +#### `torrust-tracker-axum-rest-api-server` [dev] + +- `torrust_tracker_axum_rest_api_server::testing::environment` + +#### `torrust-tracker-test-helpers` [dev] + +- `torrust_tracker_test_helpers::configuration` +- `torrust_tracker_test_helpers::logging` + +#### `torrust-tracker-udp-server` [dev] + +- `torrust_tracker_udp_server::testing::environment` + +### `torrust-tracker-axum-http-server` + +Workspace deps: 9 + +#### `torrust-tracker-axum-server` [normal] + +- `torrust_tracker_axum_server::custom_axum_server` +- `torrust_tracker_axum_server::custom_axum_server::TimeoutAcceptor` +- `torrust_tracker_axum_server::signals::GracefulShutdownOutcome` +- `torrust_tracker_axum_server::signals::graceful_shutdown` +- `torrust_tracker_axum_server::signals::graceful_shutdown_on_cancellation` +- `torrust_tracker_axum_server::tls::make_rust_tls` + +#### `torrust-tracker-configuration` [normal] + +- `torrust_tracker_configuration::v3_0_0::Configuration` +- `torrust_tracker_configuration::v3_0_0::core::Core` +- `torrust_tracker_configuration::v3_0_0::http_tracker::HttpTracker` +- `torrust_tracker_configuration::v3_0_0::logging` + +#### `torrust-tracker-core` [normal] + +- `torrust_tracker_core::announce_handler::AnnounceHandler` +- `torrust_tracker_core::authentication` +- `torrust_tracker_core::authentication::Key` +- `torrust_tracker_core::authentication::key::repository::in_memory::InMemoryKeyRepository` +- `torrust_tracker_core::authentication::service::AuthenticationService` +- `torrust_tracker_core::container::TrackerCoreContainer` +- `torrust_tracker_core::databases::setup::initialize_database` +- `torrust_tracker_core::scrape_handler::ScrapeHandler` +- `torrust_tracker_core::statistics::persisted::downloads::DatabaseDownloadsMetricRepository` +- `torrust_tracker_core::torrent::repository::in_memory::InMemoryTorrentRepository` +- `torrust_tracker_core::whitelist::authorization::WhitelistAuthorization` +- `torrust_tracker_core::whitelist::repository::in_memory::InMemoryWhitelist` + +#### `torrust-tracker-http-core` [normal] + +- `torrust_tracker_http_core::container::HttpTrackerCoreContainer` +- `torrust_tracker_http_core::event::bus::EventBus` +- `torrust_tracker_http_core::event::sender::Broadcaster` +- `torrust_tracker_http_core::services::announce::AnnounceService` +- `torrust_tracker_http_core::services::announce::HttpAnnounceError` +- `torrust_tracker_http_core::services::scrape::HttpScrapeError` +- `torrust_tracker_http_core::services::scrape::ScrapeService` +- `torrust_tracker_http_core::statistics::event::listener::run_event_listener` +- `torrust_tracker_http_core::statistics::repository::Repository` + +#### `torrust-tracker-http-protocol` [normal] + +- `torrust_tracker_http_protocol::percent_encoding::percent_encode_byte_array` +- `torrust_tracker_http_protocol::v1::auth` +- `torrust_tracker_http_protocol::v1::query::Query` +- `torrust_tracker_http_protocol::v1::requests::announce::Announce` +- `torrust_tracker_http_protocol::v1::requests::announce::AnnounceBuilder` +- `torrust_tracker_http_protocol::v1::requests::announce::Compact` +- `torrust_tracker_http_protocol::v1::requests::announce::Event` +- `torrust_tracker_http_protocol::v1::requests::announce::NumberOfBytes` +- `torrust_tracker_http_protocol::v1::requests::announce::ParseAnnounceQueryError` +- `torrust_tracker_http_protocol::v1::requests::announce::PeerIp` +- `torrust_tracker_http_protocol::v1::requests::scrape::ParseScrapeQueryError` +- `torrust_tracker_http_protocol::v1::requests::scrape::Scrape` +- `torrust_tracker_http_protocol::v1::requests::scrape_builder::Query` +- `torrust_tracker_http_protocol::v1::requests::scrape_builder::QueryBuilder` +- `torrust_tracker_http_protocol::v1::responses` +- `torrust_tracker_http_protocol::v1::responses::announce::deserialization::CompactPeer` +- `torrust_tracker_http_protocol::v1::responses::announce::deserialization::CompactPeerList` +- `torrust_tracker_http_protocol::v1::responses::announce::deserialization::DeserializedCompact` +- `torrust_tracker_http_protocol::v1::responses::announce::deserialization::DeserializedCompactParsed` +- `torrust_tracker_http_protocol::v1::responses::announce::deserialization::DeserializedNormal` +- `torrust_tracker_http_protocol::v1::responses::announce::deserialization::DictionaryPeer` +- `torrust_tracker_http_protocol::v1::responses::error::Error` +- `torrust_tracker_http_protocol::v1::responses::scrape::deserialization` +- `torrust_tracker_http_protocol::v1::responses::scrape::deserialization::File` +- `torrust_tracker_http_protocol::v1::responses::scrape::deserialization::ResponseBuilder` +- `torrust_tracker_http_protocol::v1::services::peer_ip_resolver::ClientIpSources` + +#### `torrust-tracker-primitives` [normal] + +- `torrust_tracker_primitives::AnnounceData` +- `torrust_tracker_primitives::AnnouncePolicy` +- `torrust_tracker_primitives::ConfigurationInstanceId` +- `torrust_tracker_primitives::PeerId` +- `torrust_tracker_primitives::RuntimeServiceMetadata` +- `torrust_tracker_primitives::ScrapeData` +- `torrust_tracker_primitives::ServiceRole` +- `torrust_tracker_primitives::peer` +- `torrust_tracker_primitives::peer::fixture::PeerBuilder` +- `torrust_tracker_primitives::swarm_metadata::SwarmMetadata` + +#### `torrust-tracker-swarm-coordination-registry` [normal] + +- `torrust_tracker_swarm_coordination_registry::container::SwarmCoordinationRegistryContainer` + +#### `torrust-tracker-client-lib` [dev] + +_No `torrust_tracker_client_lib::` references found in source — may be used only in `Cargo.toml` feature flags or `build.rs`._ + +#### `torrust-tracker-test-helpers` [dev] + +- `torrust_tracker_test_helpers::configuration` +- `torrust_tracker_test_helpers::configuration::ephemeral_public` +- `torrust_tracker_test_helpers::logging` +- `torrust_tracker_test_helpers::logging::logs_contains_a_line_with` + +### `torrust-tracker-axum-rest-api-server` + +Workspace deps: 14 + +#### `torrust-tracker-axum-server` [normal] + +- `torrust_tracker_axum_server::custom_axum_server` +- `torrust_tracker_axum_server::custom_axum_server::TimeoutAcceptor` +- `torrust_tracker_axum_server::signals::GracefulShutdownOutcome` +- `torrust_tracker_axum_server::signals::graceful_shutdown` +- `torrust_tracker_axum_server::signals::graceful_shutdown_on_cancellation` +- `torrust_tracker_axum_server::tls::make_rust_tls` + +#### `torrust-tracker-configuration` [normal] + +- `torrust_tracker_configuration::v3_0_0::Configuration` +- `torrust_tracker_configuration::v3_0_0::logging` +- `torrust_tracker_configuration::v3_0_0::tracker_api::AccessTokens` + +#### `torrust-tracker-core` [normal] + +- `torrust_tracker_core::authentication::Key` +- `torrust_tracker_core::container::TrackerCoreContainer` +- `torrust_tracker_core::databases::SchemaMigrator` + +#### `torrust-tracker-http-core` [normal] + +- `torrust_tracker_http_core::container::HttpTrackerCoreContainer` + +#### `torrust-tracker-primitives` [normal] + +- `torrust_tracker_primitives::ConfigurationInstanceId` +- `torrust_tracker_primitives::RuntimeServiceMetadata` +- `torrust_tracker_primitives::ServiceRole` +- `torrust_tracker_primitives::pagination::Pagination` +- `torrust_tracker_primitives::peer` +- `torrust_tracker_primitives::peer::fixture::PeerBuilder` + +#### `torrust-tracker-rest-api-application` [normal] + +- `torrust_tracker_rest_api_application::v1::use_cases::auth_key::AuthKeyApiService` +- `torrust_tracker_rest_api_application::v1::use_cases::stats::StatsApiService` +- `torrust_tracker_rest_api_application::v1::use_cases::torrent::TorrentApiService` +- `torrust_tracker_rest_api_application::v1::use_cases::whitelist::WhitelistApiService` + +#### `torrust-tracker-rest-api-client` [normal] + +- `torrust_tracker_rest_api_client::common::http::Query` +- `torrust_tracker_rest_api_client::common::http::QueryParam` +- `torrust_tracker_rest_api_client::connection_info::ConnectionInfo` +- `torrust_tracker_rest_api_client::connection_info::Origin` +- `torrust_tracker_rest_api_client::v1::client::AUTH_BEARER_TOKEN_HEADER_PREFIX` +- `torrust_tracker_rest_api_client::v1::client::AddKeyForm` +- `torrust_tracker_rest_api_client::v1::client::ApiHttpClient` +- `torrust_tracker_rest_api_client::v1::client::TOKEN_PARAM_NAME` +- `torrust_tracker_rest_api_client::v1::client::get` +- `torrust_tracker_rest_api_client::v1::client::headers_with_auth_token` +- `torrust_tracker_rest_api_client::v1::client::headers_with_request_id` + +#### `torrust-tracker-rest-api-protocol` [normal] + +- `torrust_tracker_rest_api_protocol::v1::context` +- `torrust_tracker_rest_api_protocol::v1::context::auth_key::forms::add_key_form::AddKeyForm` +- `torrust_tracker_rest_api_protocol::v1::context::auth_key::resources::auth_key::AuthKey` +- `torrust_tracker_rest_api_protocol::v1::context::auth_key::resources::auth_key::AuthKeyError` +- `torrust_tracker_rest_api_protocol::v1::context::health_check::resources::report::Report` +- `torrust_tracker_rest_api_protocol::v1::context::health_check::resources::report::Status` +- `torrust_tracker_rest_api_protocol::v1::context::stats::resources::stats::LabeledStats` +- `torrust_tracker_rest_api_protocol::v1::context::stats::resources::stats::Stats` +- `torrust_tracker_rest_api_protocol::v1::context::torrent::resources::torrent` +- `torrust_tracker_rest_api_protocol::v1::context::torrent::resources::torrent::ListItem` +- `torrust_tracker_rest_api_protocol::v1::context::torrent::resources::torrent::Torrent` +- `torrust_tracker_rest_api_protocol::v1::context::whitelist::resources::whitelist::WhitelistError` + +#### `torrust-tracker-rest-api-runtime-adapter` [normal] + +- `torrust_tracker_rest_api_runtime_adapter::v1::adapters::auth_key::TrackerAuthKeyAdapter` +- `torrust_tracker_rest_api_runtime_adapter::v1::adapters::stats::TrackerStatsAdapter` +- `torrust_tracker_rest_api_runtime_adapter::v1::adapters::torrent::TrackerTorrentQueryAdapter` +- `torrust_tracker_rest_api_runtime_adapter::v1::adapters::whitelist::TrackerWhitelistAdapter` +- `torrust_tracker_rest_api_runtime_adapter::v1::container::TrackerHttpApiCoreContainer` +- `torrust_tracker_rest_api_runtime_adapter::v1::conversion` + +#### `torrust-tracker-swarm-coordination-registry` [normal] + +- `torrust_tracker_swarm_coordination_registry::container::SwarmCoordinationRegistryContainer` + +#### `torrust-tracker-udp-core` [normal] + +- `torrust_tracker_udp_core::container::UdpTrackerCoreContainer` +- `torrust_tracker_udp_core::initialize_static` + +#### `torrust-tracker-udp-server` [normal] + +- `torrust_tracker_udp_server::container::UdpTrackerServerContainer` + +#### `torrust-tracker-rest-api-client` [dev] + +- `torrust_tracker_rest_api_client::common::http::Query` +- `torrust_tracker_rest_api_client::common::http::QueryParam` +- `torrust_tracker_rest_api_client::connection_info::ConnectionInfo` +- `torrust_tracker_rest_api_client::connection_info::Origin` +- `torrust_tracker_rest_api_client::v1::client::AUTH_BEARER_TOKEN_HEADER_PREFIX` +- `torrust_tracker_rest_api_client::v1::client::AddKeyForm` +- `torrust_tracker_rest_api_client::v1::client::ApiHttpClient` +- `torrust_tracker_rest_api_client::v1::client::TOKEN_PARAM_NAME` +- `torrust_tracker_rest_api_client::v1::client::get` +- `torrust_tracker_rest_api_client::v1::client::headers_with_auth_token` +- `torrust_tracker_rest_api_client::v1::client::headers_with_request_id` + +#### `torrust-tracker-test-helpers` [dev] + +- `torrust_tracker_test_helpers::configuration` +- `torrust_tracker_test_helpers::configuration::ephemeral_public` +- `torrust_tracker_test_helpers::logging` +- `torrust_tracker_test_helpers::logging::logs_contains_a_line_with` + +### `torrust-tracker-axum-server` + +Workspace deps: 1 + +#### `torrust-tracker-configuration` [normal] + +- `torrust_tracker_configuration::v3_0_0::tls::TlsConfig` + +### `torrust-tracker-client` + +Workspace deps: 3 + +#### `torrust-tracker-client-lib` [normal] + +_No `torrust_tracker_client_lib::` references found in source — may be used only in `Cargo.toml` feature flags or `build.rs`._ + +#### `torrust-tracker-http-protocol` [normal] + +- `torrust_tracker_http_protocol::percent_encoding::percent_decode_info_hash` +- `torrust_tracker_http_protocol::v1::query::Query` +- `torrust_tracker_http_protocol::v1::requests::announce::AnnounceBuilder` +- `torrust_tracker_http_protocol::v1::requests::announce::Compact` +- `torrust_tracker_http_protocol::v1::requests::announce::Event` +- `torrust_tracker_http_protocol::v1::requests::scrape_builder` +- `torrust_tracker_http_protocol::v1::responses::announce::deserialization::DeserializedCompact` +- `torrust_tracker_http_protocol::v1::responses::announce::deserialization::DeserializedNormal` +- `torrust_tracker_http_protocol::v1::responses::scrape::deserialization` +- `torrust_tracker_http_protocol::v1::responses::scrape::deserialization::BencodeParseError` + +#### `torrust-tracker-udp-protocol` [normal] + +- `torrust_tracker_udp_protocol::AnnounceActionPlaceholder` +- `torrust_tracker_udp_protocol::AnnounceEvent` +- `torrust_tracker_udp_protocol::AnnounceRequest` +- `torrust_tracker_udp_protocol::AnnounceResponse` +- `torrust_tracker_udp_protocol::ConnectRequest` +- `torrust_tracker_udp_protocol::ConnectResponse` +- `torrust_tracker_udp_protocol::ConnectionId` +- `torrust_tracker_udp_protocol::ErrorResponse` +- `torrust_tracker_udp_protocol::Ipv4AddrBytes` +- `torrust_tracker_udp_protocol::Ipv6AddrBytes` +- `torrust_tracker_udp_protocol::NumberOfBytes` +- `torrust_tracker_udp_protocol::NumberOfDownloads` +- `torrust_tracker_udp_protocol::NumberOfPeers` +- `torrust_tracker_udp_protocol::PeerKey` +- `torrust_tracker_udp_protocol::Port` +- `torrust_tracker_udp_protocol::Request` +- `torrust_tracker_udp_protocol::Response` +- `torrust_tracker_udp_protocol::ScrapeRequest` +- `torrust_tracker_udp_protocol::ScrapeResponse` +- `torrust_tracker_udp_protocol::TorrentScrapeStatistics` +- `torrust_tracker_udp_protocol::TransactionId` +- `torrust_tracker_udp_protocol::common::InfoHash` + +### `torrust-tracker-client-lib` + +Workspace deps: 2 + +#### `torrust-tracker-http-protocol` [normal] + +- `torrust_tracker_http_protocol::v1::requests::announce::Announce` +- `torrust_tracker_http_protocol::v1::requests::scrape_builder` + +#### `torrust-tracker-udp-protocol` [normal] + +- `torrust_tracker_udp_protocol::ConnectRequest` +- `torrust_tracker_udp_protocol::Request` +- `torrust_tracker_udp_protocol::Response` +- `torrust_tracker_udp_protocol::TransactionId` + +### `torrust-tracker-configuration` + +Workspace deps: 1 + +#### `torrust-tracker-primitives` [normal] + +- `torrust_tracker_primitives::AnnouncePolicy` +- `torrust_tracker_primitives::Driver` +- `torrust_tracker_primitives::PrivateMode` +- `torrust_tracker_primitives::TrackerPolicy` +- `torrust_tracker_primitives::announce::AnnouncePolicy` + +### `torrust-tracker-core` + +Workspace deps: 5 + +#### `torrust-tracker-configuration` [normal] + +- `torrust_tracker_configuration::v3_0_0::Configuration` +- `torrust_tracker_configuration::v3_0_0::core::Core` +- `torrust_tracker_configuration::v3_0_0::database` +- `torrust_tracker_configuration::v3_0_0::database::ConnectionInfo` +- `torrust_tracker_configuration::v3_0_0::database::Database` + +#### `torrust-tracker-events` [normal] + +- `torrust_tracker_events::bus::SenderStatus` +- `torrust_tracker_events::receiver::Receiver` +- `torrust_tracker_events::receiver::RecvError` +- `torrust_tracker_events::shutdown::Completion` + +#### `torrust-tracker-primitives` [normal] + +- `torrust_tracker_primitives::AnnounceData` +- `torrust_tracker_primitives::AnnounceEvent` +- `torrust_tracker_primitives::AnnouncePolicy` +- `torrust_tracker_primitives::Driver` +- `torrust_tracker_primitives::NumberOfBytes` +- `torrust_tracker_primitives::NumberOfDownloads` +- `torrust_tracker_primitives::NumberOfDownloadsPerInfoHash` +- `torrust_tracker_primitives::PeerId` +- `torrust_tracker_primitives::PrivateMode` +- `torrust_tracker_primitives::ScrapeData` +- `torrust_tracker_primitives::TrackerPolicy` +- `torrust_tracker_primitives::pagination::Pagination` +- `torrust_tracker_primitives::peer` +- `torrust_tracker_primitives::peer::Peer` +- `torrust_tracker_primitives::swarm_metadata::AggregateActiveSwarmMetadata` +- `torrust_tracker_primitives::swarm_metadata::SwarmMetadata` + +#### `torrust-tracker-swarm-coordination-registry` [normal] + +- `torrust_tracker_swarm_coordination_registry::CoordinatorHandle` +- `torrust_tracker_swarm_coordination_registry::Registry` +- `torrust_tracker_swarm_coordination_registry::container::SwarmCoordinationRegistryContainer` +- `torrust_tracker_swarm_coordination_registry::event::Event` +- `torrust_tracker_swarm_coordination_registry::event::receiver::Receiver` +- `torrust_tracker_swarm_coordination_registry::statistics::event` + +#### `torrust-tracker-test-helpers` [dev] + +- `torrust_tracker_test_helpers::configuration` +- `torrust_tracker_test_helpers::configuration::ephemeral_sqlite_database` + +### `torrust-tracker-e2e-tools` + +Workspace deps: 1 + +#### `torrust-tracker` [normal] + +_No `torrust_tracker::` references found in source — may be used only in `Cargo.toml` feature flags or `build.rs`._ + +### `torrust-tracker-http-core` + +Workspace deps: 7 + +#### `torrust-tracker-configuration` [normal] + +- `torrust_tracker_configuration::v3_0_0::Configuration` +- `torrust_tracker_configuration::v3_0_0::core::Core` +- `torrust_tracker_configuration::v3_0_0::http_tracker::HttpTracker` + +#### `torrust-tracker-core` [normal] + +- `torrust_tracker_core::announce_handler::AnnounceHandler` +- `torrust_tracker_core::announce_handler::PeersWanted` +- `torrust_tracker_core::authentication` +- `torrust_tracker_core::authentication::Key` +- `torrust_tracker_core::authentication::key::repository::in_memory::InMemoryKeyRepository` +- `torrust_tracker_core::authentication::service::AuthenticationService` +- `torrust_tracker_core::container::TrackerCoreContainer` +- `torrust_tracker_core::databases::TorrentMetricsStore` +- `torrust_tracker_core::databases::setup::initialize_database` +- `torrust_tracker_core::error::AnnounceError` +- `torrust_tracker_core::error::ScrapeError` +- `torrust_tracker_core::error::TrackerCoreError` +- `torrust_tracker_core::error::WhitelistError` +- `torrust_tracker_core::scrape_handler::ScrapeHandler` +- `torrust_tracker_core::statistics::persisted::downloads::DatabaseDownloadsMetricRepository` +- `torrust_tracker_core::torrent::repository::in_memory::InMemoryTorrentRepository` +- `torrust_tracker_core::whitelist` +- `torrust_tracker_core::whitelist::authorization::WhitelistAuthorization` +- `torrust_tracker_core::whitelist::repository::in_memory::InMemoryWhitelist` + +#### `torrust-tracker-events` [normal] + +- `torrust_tracker_events::broadcaster::Broadcaster` +- `torrust_tracker_events::bus::EventBus` +- `torrust_tracker_events::bus::SenderStatus` +- `torrust_tracker_events::receiver::Receiver` +- `torrust_tracker_events::receiver::RecvError` +- `torrust_tracker_events::sender::SendError` +- `torrust_tracker_events::sender::Sender` +- `torrust_tracker_events::shutdown::Completion` + +#### `torrust-tracker-http-protocol` [normal] + +- `torrust_tracker_http_protocol::v1::requests` +- `torrust_tracker_http_protocol::v1::requests::announce::Announce` +- `torrust_tracker_http_protocol::v1::requests::announce::Event` +- `torrust_tracker_http_protocol::v1::requests::announce::NumberOfBytes` +- `torrust_tracker_http_protocol::v1::requests::announce::PeerIp` +- `torrust_tracker_http_protocol::v1::requests::scrape::Scrape` +- `torrust_tracker_http_protocol::v1::responses::error::Error` +- `torrust_tracker_http_protocol::v1::services::peer_ip_resolver::ClientIpSources` +- `torrust_tracker_http_protocol::v1::services::peer_ip_resolver::PeerIpResolutionError` +- `torrust_tracker_http_protocol::v1::services::peer_ip_resolver::RemoteClientAddr` +- `torrust_tracker_http_protocol::v1::services::peer_ip_resolver::ResolvedIp` +- `torrust_tracker_http_protocol::v1::services::peer_ip_resolver::ReverseProxyMode` +- `torrust_tracker_http_protocol::v1::services::peer_ip_resolver::resolve_remote_client_addr` + +#### `torrust-tracker-primitives` [normal] + +- `torrust_tracker_primitives::AnnounceData` +- `torrust_tracker_primitives::AnnounceEvent` +- `torrust_tracker_primitives::AnnounceEvent::Completed` +- `torrust_tracker_primitives::AnnounceEvent::None` +- `torrust_tracker_primitives::AnnounceEvent::Started` +- `torrust_tracker_primitives::AnnounceEvent::Stopped` +- `torrust_tracker_primitives::ConfigurationInstanceId` +- `torrust_tracker_primitives::NumberOfBytes` +- `torrust_tracker_primitives::PeerId` +- `torrust_tracker_primitives::ScrapeData` +- `torrust_tracker_primitives::ServiceRole` +- `torrust_tracker_primitives::peer` +- `torrust_tracker_primitives::peer::Peer` +- `torrust_tracker_primitives::peer::PeerAnnouncement` +- `torrust_tracker_primitives::swarm_metadata::SwarmMetadata` + +#### `torrust-tracker-swarm-coordination-registry` [normal] + +- `torrust_tracker_swarm_coordination_registry::container::SwarmCoordinationRegistryContainer` + +#### `torrust-tracker-test-helpers` [dev] + +- `torrust_tracker_test_helpers::configuration` + +### `torrust-tracker-persistence-benchmark` + +Workspace deps: 3 + +#### `torrust-tracker-configuration` [normal] + +- `torrust_tracker_configuration::v3_0_0::core::Core` +- `torrust_tracker_configuration::v3_0_0::database::ConnectionInfo` +- `torrust_tracker_configuration::v3_0_0::database::Database` + +#### `torrust-tracker-core` [normal] + +- `torrust_tracker_core::authentication` +- `torrust_tracker_core::databases::AuthKeyStore` +- `torrust_tracker_core::databases::SchemaMigrator` +- `torrust_tracker_core::databases::TorrentMetricsStore` +- `torrust_tracker_core::databases::WhitelistStore` +- `torrust_tracker_core::databases::setup::DatabaseStores` +- `torrust_tracker_core::databases::setup::initialize_database` + +#### `torrust-tracker-primitives` [normal] + +- `torrust_tracker_primitives::Driver` + +### `torrust-tracker-rest-api-application` + +Workspace deps: 2 + +#### `torrust-tracker-primitives` [normal] + +- `torrust_tracker_primitives::pagination::Pagination` + +#### `torrust-tracker-rest-api-protocol` [normal] + +- `torrust_tracker_rest_api_protocol::v1::context::auth_key::forms::add_key_form::AddKeyForm` +- `torrust_tracker_rest_api_protocol::v1::context::auth_key::resources::auth_key::AuthKey` +- `torrust_tracker_rest_api_protocol::v1::context::auth_key::resources::auth_key::AuthKeyError` +- `torrust_tracker_rest_api_protocol::v1::context::stats::resources::stats::LabeledStats` +- `torrust_tracker_rest_api_protocol::v1::context::stats::resources::stats::Stats` +- `torrust_tracker_rest_api_protocol::v1::context::torrent::resources::torrent::ListItem` +- `torrust_tracker_rest_api_protocol::v1::context::torrent::resources::torrent::Torrent` +- `torrust_tracker_rest_api_protocol::v1::context::whitelist::resources::whitelist::WhitelistError` + +### `torrust-tracker-rest-api-client` + +Workspace deps: 1 + +#### `torrust-tracker-rest-api-protocol` [normal] + +- `torrust_tracker_rest_api_protocol::v1::context::auth_key::forms::add_key_form::AddKeyForm` +- `torrust_tracker_rest_api_protocol::v1::context::auth_key::resources::auth_key::AuthKey` +- `torrust_tracker_rest_api_protocol::v1::context::stats::resources::stats::Stats` +- `torrust_tracker_rest_api_protocol::v1::context::torrent::resources::torrent::ListItem` +- `torrust_tracker_rest_api_protocol::v1::context::torrent::resources::torrent::Torrent` + +### `torrust-tracker-rest-api-runtime-adapter` + +Workspace deps: 9 + +#### `torrust-tracker-configuration` [normal] + +- `torrust_tracker_configuration::v3_0_0::core::Core` +- `torrust_tracker_configuration::v3_0_0::http_tracker::HttpTracker` +- `torrust_tracker_configuration::v3_0_0::tracker_api::HttpApi` +- `torrust_tracker_configuration::v3_0_0::udp_tracker::UdpTracker` +- `torrust_tracker_configuration::v3_0_0::udp_tracker_server::UdpTrackerServer` + +#### `torrust-tracker-core` [normal] + +- `torrust_tracker_core::authentication::Key` +- `torrust_tracker_core::authentication::PeerKey` +- `torrust_tracker_core::authentication::handler::AddKeyRequest` +- `torrust_tracker_core::authentication::handler::KeysHandler` +- `torrust_tracker_core::container::TrackerCoreContainer` +- `torrust_tracker_core::error::PeerKeyError` +- `torrust_tracker_core::statistics::repository` +- `torrust_tracker_core::torrent::repository::in_memory::InMemoryTorrentRepository` +- `torrust_tracker_core::torrent::services` +- `torrust_tracker_core::torrent::services::BasicInfo` +- `torrust_tracker_core::torrent::services::Info` +- `torrust_tracker_core::whitelist::manager::WhitelistManager` + +#### `torrust-tracker-http-core` [normal] + +- `torrust_tracker_http_core::container::HttpTrackerCoreContainer` +- `torrust_tracker_http_core::statistics::repository` + +#### `torrust-tracker-primitives` [normal] + +- `torrust_tracker_primitives::AnnounceEvent` +- `torrust_tracker_primitives::ConfigurationInstanceId` +- `torrust_tracker_primitives::NumberOfBytes` +- `torrust_tracker_primitives::PeerId` +- `torrust_tracker_primitives::pagination::Pagination` +- `torrust_tracker_primitives::peer` + +#### `torrust-tracker-rest-api-application` [normal] + +- `torrust_tracker_rest_api_application::v1::ports::auth_key::AuthKeyPort` +- `torrust_tracker_rest_api_application::v1::ports::stats::StatsQueryPort` +- `torrust_tracker_rest_api_application::v1::ports::torrent::TorrentQueryPort` +- `torrust_tracker_rest_api_application::v1::ports::whitelist::WhitelistCommandPort` + +#### `torrust-tracker-rest-api-protocol` [normal] + +- `torrust_tracker_rest_api_protocol::v1::context::auth_key::forms::add_key_form::AddKeyForm` +- `torrust_tracker_rest_api_protocol::v1::context::auth_key::resources::auth_key::AuthKey` +- `torrust_tracker_rest_api_protocol::v1::context::auth_key::resources::auth_key::AuthKeyError` +- `torrust_tracker_rest_api_protocol::v1::context::stats::resources::stats::LabeledStats` +- `torrust_tracker_rest_api_protocol::v1::context::stats::resources::stats::Stats` +- `torrust_tracker_rest_api_protocol::v1::context::torrent::resources::peer` +- `torrust_tracker_rest_api_protocol::v1::context::torrent::resources::torrent::ListItem` +- `torrust_tracker_rest_api_protocol::v1::context::torrent::resources::torrent::Torrent` +- `torrust_tracker_rest_api_protocol::v1::context::whitelist::resources::whitelist::WhitelistError` + +#### `torrust-tracker-swarm-coordination-registry` [normal] + +- `torrust_tracker_swarm_coordination_registry::container::SwarmCoordinationRegistryContainer` +- `torrust_tracker_swarm_coordination_registry::statistics::repository` + +#### `torrust-tracker-udp-core` [normal] + +- `torrust_tracker_udp_core::container::UdpTrackerCoreContainer` +- `torrust_tracker_udp_core::services::banning::BanService` +- `torrust_tracker_udp_core::statistics::repository` + +#### `torrust-tracker-udp-server` [normal] + +- `torrust_tracker_udp_server::container::UdpTrackerServerContainer` +- `torrust_tracker_udp_server::statistics::repository` + +### `torrust-tracker-swarm-coordination-registry` + +Workspace deps: 2 + +#### `torrust-tracker-events` [normal] + +- `torrust_tracker_events::broadcaster::Broadcaster` +- `torrust_tracker_events::bus::EventBus` +- `torrust_tracker_events::bus::SenderStatus` +- `torrust_tracker_events::receiver::Receiver` +- `torrust_tracker_events::receiver::RecvError` +- `torrust_tracker_events::sender::SendError` +- `torrust_tracker_events::sender::Sender` +- `torrust_tracker_events::shutdown::Completion` + +#### `torrust-tracker-primitives` [normal] + +- `torrust_tracker_primitives::AnnounceEvent` +- `torrust_tracker_primitives::AnnounceEvent::Completed` +- `torrust_tracker_primitives::AnnounceEvent::Started` +- `torrust_tracker_primitives::NumberOfBytes` +- `torrust_tracker_primitives::NumberOfDownloads` +- `torrust_tracker_primitives::NumberOfDownloadsPerInfoHash` +- `torrust_tracker_primitives::PeerId` +- `torrust_tracker_primitives::TrackerPolicy` +- `torrust_tracker_primitives::pagination::Pagination` +- `torrust_tracker_primitives::peer` +- `torrust_tracker_primitives::peer::Peer` +- `torrust_tracker_primitives::peer::PeerAnnouncement` +- `torrust_tracker_primitives::peer::PeerRole` +- `torrust_tracker_primitives::peer::fixture::PeerBuilder` +- `torrust_tracker_primitives::swarm_metadata::AggregateActiveSwarmMetadata` +- `torrust_tracker_primitives::swarm_metadata::SwarmMetadata` + +### `torrust-tracker-test-helpers` + +Workspace deps: 5 + +#### `torrust-tracker-client-lib` [normal] + +_No `torrust_tracker_client_lib::` references found in source — may be used only in `Cargo.toml` feature flags or `build.rs`._ + +#### `torrust-tracker-configuration` [normal] + +- `torrust_tracker_configuration::v3_0_0::Configuration` +- `torrust_tracker_configuration::v3_0_0::database::Database` +- `torrust_tracker_configuration::v3_0_0::http_tracker::HttpTracker` +- `torrust_tracker_configuration::v3_0_0::logging::Threshold` +- `torrust_tracker_configuration::v3_0_0::logging::TraceStyle` +- `torrust_tracker_configuration::v3_0_0::network::Network` +- `torrust_tracker_configuration::v3_0_0::tracker_api::HttpApi` +- `torrust_tracker_configuration::v3_0_0::udp_tracker::UdpTracker` + +#### `torrust-tracker-http-protocol` [normal] + +- `torrust_tracker_http_protocol::v1::requests::announce::Announce` +- `torrust_tracker_http_protocol::v1::requests::announce::Event` +- `torrust_tracker_http_protocol::v1::requests::announce::PeerIp` +- `torrust_tracker_http_protocol::v1::requests::scrape_builder` +- `torrust_tracker_http_protocol::v1::responses::scrape` + +#### `torrust-tracker-primitives` [normal] + +- `torrust_tracker_primitives::swarm_metadata::SwarmMetadata` + +#### `torrust-tracker-udp-protocol` [normal] + +- `torrust_tracker_udp_protocol::AnnounceActionPlaceholder` +- `torrust_tracker_udp_protocol::AnnounceEvent` +- `torrust_tracker_udp_protocol::AnnounceRequest` +- `torrust_tracker_udp_protocol::ConnectRequest` +- `torrust_tracker_udp_protocol::ConnectionId` +- `torrust_tracker_udp_protocol::NumberOfBytes` +- `torrust_tracker_udp_protocol::NumberOfPeers` +- `torrust_tracker_udp_protocol::PeerKey` +- `torrust_tracker_udp_protocol::Port` +- `torrust_tracker_udp_protocol::Response` +- `torrust_tracker_udp_protocol::ScrapeRequest` +- `torrust_tracker_udp_protocol::TransactionId` +- `torrust_tracker_udp_protocol::common::InfoHash` + +### `torrust-tracker-torrent-repository-benchmarking` + +Workspace deps: 1 + +#### `torrust-tracker-primitives` [normal] + +- `torrust_tracker_primitives::AnnounceEvent` +- `torrust_tracker_primitives::NumberOfBytes` +- `torrust_tracker_primitives::NumberOfDownloads` +- `torrust_tracker_primitives::NumberOfDownloadsPerInfoHash` +- `torrust_tracker_primitives::PeerId` +- `torrust_tracker_primitives::TrackerPolicy` +- `torrust_tracker_primitives::pagination::Pagination` +- `torrust_tracker_primitives::peer` +- `torrust_tracker_primitives::peer::Peer` +- `torrust_tracker_primitives::peer::ReadInfo` +- `torrust_tracker_primitives::peer::fixture::PeerBuilder` +- `torrust_tracker_primitives::swarm_metadata::AggregateActiveSwarmMetadata` +- `torrust_tracker_primitives::swarm_metadata::SwarmMetadata` + +### `torrust-tracker-udp-core` + +Workspace deps: 6 + +#### `torrust-tracker-configuration` [normal] + +- `torrust_tracker_configuration::v3_0_0::core::Core` +- `torrust_tracker_configuration::v3_0_0::udp_tracker::UdpTracker` + +#### `torrust-tracker-core` [normal] + +- `torrust_tracker_core::announce_handler::AnnounceHandler` +- `torrust_tracker_core::announce_handler::PeersWanted` +- `torrust_tracker_core::container::TrackerCoreContainer` +- `torrust_tracker_core::error::AnnounceError` +- `torrust_tracker_core::error::ScrapeError` +- `torrust_tracker_core::error::WhitelistError` +- `torrust_tracker_core::scrape_handler::ScrapeHandler` +- `torrust_tracker_core::torrent::repository::in_memory::InMemoryTorrentRepository` +- `torrust_tracker_core::whitelist` + +#### `torrust-tracker-events` [normal] + +- `torrust_tracker_events::broadcaster::Broadcaster` +- `torrust_tracker_events::bus::EventBus` +- `torrust_tracker_events::bus::SenderStatus` +- `torrust_tracker_events::receiver::Receiver` +- `torrust_tracker_events::receiver::RecvError` +- `torrust_tracker_events::sender::SendError` +- `torrust_tracker_events::sender::Sender` +- `torrust_tracker_events::shutdown::Completion` + +#### `torrust-tracker-primitives` [normal] + +- `torrust_tracker_primitives::AnnounceData` +- `torrust_tracker_primitives::AnnounceEvent::Completed` +- `torrust_tracker_primitives::AnnounceEvent::None` +- `torrust_tracker_primitives::AnnounceEvent::Started` +- `torrust_tracker_primitives::AnnounceEvent::Stopped` +- `torrust_tracker_primitives::ConfigurationInstanceId` +- `torrust_tracker_primitives::NumberOfBytes::new` +- `torrust_tracker_primitives::PeerId` +- `torrust_tracker_primitives::ScrapeData` +- `torrust_tracker_primitives::ServiceRole` +- `torrust_tracker_primitives::peer` +- `torrust_tracker_primitives::peer::PeerAnnouncement` +- `torrust_tracker_primitives::swarm_metadata::AggregateActiveSwarmMetadata` + +#### `torrust-tracker-swarm-coordination-registry` [normal] + +- `torrust_tracker_swarm_coordination_registry::container::SwarmCoordinationRegistryContainer` + +#### `torrust-tracker-udp-protocol` [normal] + +- `torrust_tracker_udp_protocol::AnnounceEvent::Completed` +- `torrust_tracker_udp_protocol::AnnounceEvent::None` +- `torrust_tracker_udp_protocol::AnnounceEvent::Started` +- `torrust_tracker_udp_protocol::AnnounceEvent::Stopped` +- `torrust_tracker_udp_protocol::AnnounceEvent::from` +- `torrust_tracker_udp_protocol::AnnounceRequest` +- `torrust_tracker_udp_protocol::ConnectionId` +- `torrust_tracker_udp_protocol::ScrapeRequest` +- `torrust_tracker_udp_protocol::common::InfoHash` + +### `torrust-tracker-udp-server` + +Workspace deps: 9 + +#### `torrust-tracker-client-lib` [normal] + +_No `torrust_tracker_client_lib::` references found in source — may be used only in `Cargo.toml` feature flags or `build.rs`._ + +#### `torrust-tracker-configuration` [normal] + +- `torrust_tracker_configuration::v3_0_0::Configuration` +- `torrust_tracker_configuration::v3_0_0::core::Core` +- `torrust_tracker_configuration::v3_0_0::logging` +- `torrust_tracker_configuration::v3_0_0::udp_tracker::UdpTracker` +- `torrust_tracker_configuration::v3_0_0::udp_tracker_server::ConnectionIdValidationPolicy` +- `torrust_tracker_configuration::v3_0_0::udp_tracker_server::UdpTrackerServer` + +#### `torrust-tracker-core` [normal] + +- `torrust_tracker_core::announce_handler::AnnounceHandler` +- `torrust_tracker_core::container::TrackerCoreContainer` +- `torrust_tracker_core::databases::TorrentMetricsStore` +- `torrust_tracker_core::databases::error::Error` +- `torrust_tracker_core::databases::setup::initialize_database` +- `torrust_tracker_core::error::AnnounceError` +- `torrust_tracker_core::error::ScrapeError` +- `torrust_tracker_core::error::WhitelistError` +- `torrust_tracker_core::scrape_handler::ScrapeHandler` +- `torrust_tracker_core::statistics::persisted::downloads::DatabaseDownloadsMetricRepository` +- `torrust_tracker_core::torrent::repository::in_memory::InMemoryTorrentRepository` +- `torrust_tracker_core::whitelist` +- `torrust_tracker_core::whitelist::authorization::WhitelistAuthorization` +- `torrust_tracker_core::whitelist::repository::in_memory::InMemoryWhitelist` + +#### `torrust-tracker-events` [normal] + +- `torrust_tracker_events::broadcaster::Broadcaster` +- `torrust_tracker_events::bus::EventBus` +- `torrust_tracker_events::bus::SenderStatus` +- `torrust_tracker_events::receiver::Receiver` +- `torrust_tracker_events::receiver::RecvError` +- `torrust_tracker_events::sender::SendError` +- `torrust_tracker_events::sender::Sender` +- `torrust_tracker_events::shutdown::Completion` + +#### `torrust-tracker-primitives` [normal] + +- `torrust_tracker_primitives::AnnounceData` +- `torrust_tracker_primitives::AnnounceEvent` +- `torrust_tracker_primitives::AnnouncePolicy` +- `torrust_tracker_primitives::ConfigurationInstanceId` +- `torrust_tracker_primitives::ConfigurationInstanceId::new` +- `torrust_tracker_primitives::Driver` +- `torrust_tracker_primitives::NumberOfBytes` +- `torrust_tracker_primitives::PeerId` +- `torrust_tracker_primitives::RuntimeServiceMetadata` +- `torrust_tracker_primitives::ScrapeData` +- `torrust_tracker_primitives::ServiceRole` +- `torrust_tracker_primitives::ServiceRole::UdpTracker` +- `torrust_tracker_primitives::peer` +- `torrust_tracker_primitives::peer::fixture::PeerBuilder` +- `torrust_tracker_primitives::swarm_metadata::AggregateActiveSwarmMetadata` +- `torrust_tracker_primitives::swarm_metadata::SwarmMetadata` + +#### `torrust-tracker-swarm-coordination-registry` [normal] + +- `torrust_tracker_swarm_coordination_registry::container::SwarmCoordinationRegistryContainer` + +#### `torrust-tracker-udp-core` [normal] + +- `torrust_tracker_udp_core::ConnectionIdValidationPolicy` +- `torrust_tracker_udp_core::ConnectionIdValidationPolicy::Disabled` +- `torrust_tracker_udp_core::ConnectionIdValidationPolicy::Strict` +- `torrust_tracker_udp_core::UDP_TRACKER_LOG_TARGET` +- `torrust_tracker_udp_core::connection_cookie::ConnectionCookieError` +- `torrust_tracker_udp_core::connection_cookie::check` +- `torrust_tracker_udp_core::connection_cookie::gen_remote_fingerprint` +- `torrust_tracker_udp_core::connection_cookie::make` +- `torrust_tracker_udp_core::container::UdpTrackerCoreContainer` +- `torrust_tracker_udp_core::event` +- `torrust_tracker_udp_core::event::ConnectionContext` +- `torrust_tracker_udp_core::event::Event` +- `torrust_tracker_udp_core::event::bus::EventBus` +- `torrust_tracker_udp_core::event::sender` +- `torrust_tracker_udp_core::event::sender::Broadcaster` +- `torrust_tracker_udp_core::initialize_static` +- `torrust_tracker_udp_core::services::announce` +- `torrust_tracker_udp_core::services::announce::AnnounceService` +- `torrust_tracker_udp_core::services::announce::UdpAnnounceError` +- `torrust_tracker_udp_core::services::banning::BanService` +- `torrust_tracker_udp_core::services::connect::ConnectService` +- `torrust_tracker_udp_core::services::scrape::ScrapeService` +- `torrust_tracker_udp_core::services::scrape::UdpScrapeError` +- `torrust_tracker_udp_core::statistics::event` + +#### `torrust-tracker-udp-protocol` [normal] + +- `torrust_tracker_udp_protocol::AnnounceActionPlaceholder` +- `torrust_tracker_udp_protocol::AnnounceEvent` +- `torrust_tracker_udp_protocol::AnnounceInterval` +- `torrust_tracker_udp_protocol::AnnounceRequest` +- `torrust_tracker_udp_protocol::AnnounceResponse` +- `torrust_tracker_udp_protocol::AnnounceResponseFixedData` +- `torrust_tracker_udp_protocol::ConnectRequest` +- `torrust_tracker_udp_protocol::ConnectResponse` +- `torrust_tracker_udp_protocol::ConnectionId` +- `torrust_tracker_udp_protocol::ErrorResponse` +- `torrust_tracker_udp_protocol::InfoHash` +- `torrust_tracker_udp_protocol::Ipv4AddrBytes` +- `torrust_tracker_udp_protocol::Ipv6AddrBytes` +- `torrust_tracker_udp_protocol::MAX_PACKET_SIZE` +- `torrust_tracker_udp_protocol::MAX_SCRAPE_INFO_HASHES` +- `torrust_tracker_udp_protocol::NumberOfBytes` +- `torrust_tracker_udp_protocol::NumberOfDownloads` +- `torrust_tracker_udp_protocol::NumberOfPeers` +- `torrust_tracker_udp_protocol::PeerKey` +- `torrust_tracker_udp_protocol::Port` +- `torrust_tracker_udp_protocol::Request` +- `torrust_tracker_udp_protocol::RequestParseError` +- `torrust_tracker_udp_protocol::Response` +- `torrust_tracker_udp_protocol::Response::Scrape` +- `torrust_tracker_udp_protocol::ResponsePeer` +- `torrust_tracker_udp_protocol::ScrapeRequest` +- `torrust_tracker_udp_protocol::ScrapeResponse` +- `torrust_tracker_udp_protocol::TorrentScrapeStatistics` +- `torrust_tracker_udp_protocol::TransactionId` + +#### `torrust-tracker-test-helpers` [dev] + +- `torrust_tracker_test_helpers::configuration` +- `torrust_tracker_test_helpers::configuration::ephemeral_public` +- `torrust_tracker_test_helpers::logging` +- `torrust_tracker_test_helpers::logging::logs_contains_a_line_with` + +--- + +## Observations + +Reviewed on 2026-10-06 against the +[2026-06-10 report](workspace-coupling-report-2026-06-10.md), for issue +[#2446](https://github.com/torrust/torrust-tracker/issues/2446). + +### Known thin dependencies (pre-existing) + +None remain. Previously known thin dependencies were resolved: + +- `torrust-clock` → `torrust-tracker-primitives` (SI-02, #1790) +- `torrust-tracker-configuration` → `torrust-clock` (SI-03, #1793) +- `torrust-tracker-configuration` → `torrust-tracker-primitives` for + `TrackerPolicy`/`PrivateMode`/`TORRENT_PEERS_LIMIT` (FU-1, #1859). The remaining edge imports + shared domain types (`AnnouncePolicy`, `Driver`, `PrivateMode`, `TrackerPolicy`), which is + architecturally expected. + +### Changes since the previous report (2026-06-10) + +| Metric | 2026-06-10 | 2026-10-06 | +| -------------------------------------- | ---------- | ---------- | +| Workspace members | 25 | 31 | +| Tracker packages (excluding dev-tools) | 24 | 25 | +| `contrib/dev-tools/` members | 1 | 6 | +| Leaf packages (no workspace deps) | 7 | 11 | +| Highest workspace dep count | 15 | 16 | + +The member count grew because five more developer tools became workspace members. The leaf +count grew for the same reason, plus the new `rest-api-protocol`, minus `torrust-server-lib` +(extracted) and `rest-api-client` (now depends on `rest-api-protocol`). + +**Resolved since the previous report** (its prioritization table): + +1. `axum-http-server` → `udp-protocol` (`PeerId` only) is gone. +2. `Driver` moved to `primitives` (SI-27, #1908, DEC-17). `configuration` and + `persistence-benchmark` now import `torrust_tracker_primitives::Driver`. +3. The REST layer no longer reaches UDP internals from production code: `rest-api-core` was + removed by the REST API contract-first migration (#1938, SI-5 #1943), after SI-30 (#1924) + introduced the UDP trait abstractions. Runtime wiring now lives in + `rest-api-runtime-adapter`, a runtime package that `deny.toml` allows to depend on + `udp-server`. + +**Other structural changes**: + +- REST API migration (#1938): new `rest-api-protocol` (no workspace deps), + `rest-api-application` (2 deps) and `rest-api-runtime-adapter` (9 deps); + `rest-api-client` now depends on `rest-api-protocol`; `axum-rest-api-server` went from 13 + to 14 deps (`rest-api-core` replaced by the three new packages). +- `torrust-server-lib` extracted (#1909): the edge disappeared from six packages. `axum-server` + dropped to 1 dep and `udp-server` to 9; `axum-http-server` also lost `udp-protocol` and + gained `client-lib` (10 → 9). +- `client-lib` swapped `primitives` for `http-protocol`, and the console `client` added + `http-protocol` (2 → 3 deps). +- `test-helpers` grew from 1 to 5 deps: `client-lib`, `http-protocol`, `primitives` and + `udp-protocol` were added (see finding 1). +- The root crate went from 15 to 16 deps; it is the composition root, so this follows the + package set. + +### New findings + +#### 1. Published `test-helpers` depends on unpublished crates + +`torrust-tracker-test-helpers` is published on crates.io (3.0.0), but its normal dependencies +now include `torrust-tracker-client-lib`, `torrust-tracker-http-protocol` and +`torrust-tracker-udp-protocol`, none of which is published. A new `test-helpers` release cannot +be published until those crates are, or until the protocol-specific helpers move out. Draft +subissue: +[`1669-decouple-test-helpers-from-unpublished-crates`](../../drafts/1669-decouple-test-helpers-from-unpublished-crates/ISSUE.md). + +#### 2. Server `testing` modules turn test-only edges into runtime dependencies + +DEC-13 moved the server test environments to public `src/testing/` modules and accepted that +they compile into release builds. The report now shows the cost of that trade-off: + +- `axum-rest-api-server` → `udp-server`, `udp-core`, `http-core` and + `swarm-coordination-registry` are imported only by `src/testing/environment.rs` and + `#[cfg(test)]` code. Its production code reaches UDP only through + `rest-api-runtime-adapter`. +- `axum-http-server` → `swarm-coordination-registry` and `udp-server` → + `swarm-coordination-registry` are imported only by their `src/testing/` modules and tests. + +Gating each `testing` module behind a Cargo feature would make these edges optional. Draft +subissue: +[`1669-gate-server-testing-modules-behind-feature`](../../drafts/1669-gate-server-testing-modules-behind-feature/ISSUE.md). + +#### 3. The tool misses renamed crates and custom library names + +The tool derives the import module from the package name, so it reports "no references" for +five edges that are used: + +- `client` → `client-lib` and `udp-server` → `client-lib`: the dependency is renamed to + `torrust-tracker-client` in `Cargo.toml`. +- `test-helpers` → `client-lib` and `axum-http-server` → `client-lib` (a dev dependency): the + library target is named `torrust_tracker_client`. +- `e2e-tools` → `torrust-tracker`: the root library target is named `torrust_tracker_lib` + (already noted in the previous report). + +Reading the library target name and the dependency rename from `cargo metadata` would fix +this. Draft subissue: +[`1669-coupling-tool-resolve-lib-names-and-renames`](../../drafts/1669-coupling-tool-resolve-lib-names-and-renames/ISSUE.md). + +#### Acceptable thin dependencies (not worth addressing) + +- **`axum-server` → `configuration`** (1 import: `v3_0_0::tls::TlsConfig`): kept per + [DEC-08](DECISIONS.md#dec-08--keep-tslconfig-in-tracker-configuration-and-keep-torrust-tracker-axum-server-tracker-scoped). +- **`http-core` → `swarm-coordination-registry`** and **`udp-core` → + `swarm-coordination-registry`** (1 import each: `SwarmCoordinationRegistryContainer`): + container composition; each core container holds the registry container. +- **Root crate → `events`, `rest-api-protocol`, `rest-api-runtime-adapter`** (1 import each): + the composition root wires these packages together. +- **`rest-api-application` → `primitives`** (`Pagination`), **`test-helpers` → + `primitives`** (`SwarmMetadata`), **`persistence-benchmark` → `primitives`** (`Driver`): + shared domain types, which is what `primitives` is for. +- **`udp-server` → `client-lib`**: the server uses its client for health checks, per + [DEC-11](DECISIONS.md#dec-11--accept-server--client-library-dependency-for-health-checks). +- **`http-core` → `tracker-core`**: architecturally expected, per [DEC-12](DECISIONS.md). diff --git a/docs/issues/open/2446-1669-establish-baseline-analysis/ISSUE.md b/docs/issues/open/2446-1669-establish-baseline-analysis/ISSUE.md index d841b6fdb..012749f12 100644 --- a/docs/issues/open/2446-1669-establish-baseline-analysis/ISSUE.md +++ b/docs/issues/open/2446-1669-establish-baseline-analysis/ISSUE.md @@ -2,14 +2,14 @@ schema-version: 1 doc-type: issue issue-type: task -status: planned +status: in-progress priority: p2 epic: 1669 github-issue: 2446 spec-path: docs/issues/open/2446-1669-establish-baseline-analysis/ISSUE.md branch: "2446-1669-establish-baseline-analysis-spec" related-pr: null -last-updated-utc: "2026-10-06 11:51" +last-updated-utc: "2026-10-07 12:39" semantic-links: skill-links: - create-issue @@ -197,11 +197,11 @@ Remaining work for the current workspace: | ID | Status | Task | Notes / Expected Output | | --- | ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | -| T9 | TODO | Regenerate the coupling report with `cargo run -p workspace-coupling -- ` and write its Observations section, comparing against the 2026-06-10 report | New `workspace-coupling-report-.md` covering every current workspace member; no placeholder text | -| T10 | TODO | Refresh `readme-audit.md` for the 25 audited packages (see Goal item 2): add the root crate, the three REST API packages, `e2e-tools` and `persistence-benchmark`; use current folder and crate names; remove the rows for packages no longer in the workspace (`clock`, `located-error`, `metrics`, `peer-id`, `server-lib`, `rest-tracker-api-core` and `contrib/bencode`) | Exactly one row per audited package, each rated good, minimal, stub or missing, with a Summary table that matches the rows and an updated audit date | -| T11 | TODO | Update the Mermaid diagram in `docs/media/packages/dependencies-workspace-packages.md` to the current normal dependencies | Every node and edge matches `cargo metadata --no-deps`; `rest-api-core` removed; link to the new report updated | -| T12 | TODO | Review the new report for thin-dependency or misplacement findings not covered by existing subissues | Findings recorded in the report's Observations; a draft subissue added to EPIC #1669 for each one warranting a change, or "none found" recorded | -| T13 | TODO | Mark the baseline done in EPIC #1669: quick-list entry, Details row, AC1, and the first-cycle exit criteria | EPIC updated in the same PR | +| T9 | DONE | Regenerate the coupling report with `cargo run -p workspace-coupling -- ` and write its Observations section, comparing against the 2026-06-10 report | New `workspace-coupling-report-.md` covering every current workspace member; no placeholder text | +| T10 | DONE | Refresh `readme-audit.md` for the 25 audited packages (see Goal item 2): add the root crate, the three REST API packages, `e2e-tools` and `persistence-benchmark`; use current folder and crate names; remove the rows for packages no longer in the workspace (`clock`, `located-error`, `metrics`, `peer-id`, `server-lib`, `rest-tracker-api-core` and `contrib/bencode`) | Exactly one row per audited package, each rated good, minimal, stub or missing, with a Summary table that matches the rows and an updated audit date | +| T11 | DONE | Update the Mermaid diagram in `docs/media/packages/dependencies-workspace-packages.md` to the current normal dependencies | Every node and edge matches `cargo metadata --no-deps`; `rest-api-core` removed; link to the new report updated | +| T12 | DONE | Review the new report for thin-dependency or misplacement findings not covered by existing subissues | Findings recorded in the report's Observations; a draft subissue added to EPIC #1669 for each one warranting a change, or "none found" recorded | +| T13 | DONE | Mark the baseline done in EPIC #1669: quick-list entry, Details row, AC1, and the first-cycle exit criteria | EPIC updated in the same PR | ### T8 — original research plan (historical, resolved by #1856) @@ -268,17 +268,17 @@ reviewability. - [x] Spec moved to `docs/issues/open/` with issue number prefix - [x] Coupling tool written and reviewed (T1) - [x] First coupling reports and README audit committed (T2 to T5) -- [ ] Coupling report regenerated with Observations (T9) -- [ ] README audit refreshed (T10) -- [ ] Dependency diagram updated (T11) -- [ ] New findings reviewed and recorded (T12) -- [ ] EPIC #1669 updated to `DONE` (T13) -- [ ] Spec-only PR merged into `develop` before implementation -- [ ] Automatic verification completed (`linter all` and pre-push checks) -- [ ] Manual verification scenarios executed and recorded in issue-local +- [x] Coupling report regenerated with Observations (T9) +- [x] README audit refreshed (T10) +- [x] Dependency diagram updated (T11) +- [x] New findings reviewed and recorded (T12) +- [x] EPIC #1669 updated to `DONE` (T13) +- [x] Spec-only PR merged into `develop` before implementation +- [x] Automatic verification completed (`linter all` and pre-push checks) +- [x] Manual verification scenarios executed and recorded in issue-local `manual-verification-evidence.md` -- [ ] Acceptance criteria reviewed after implementation and updated with evidence -- [ ] Evidence-based implementation completion review recorded: issue-local retrospective +- [x] Acceptance criteria reviewed after implementation and updated with evidence +- [x] Evidence-based implementation completion review recorded: issue-local retrospective created for material discoveries, or progress log states why none was needed - [ ] Reviewer validated acceptance criteria and updated checkboxes - [ ] Committer verified spec progress is up to date before commit @@ -302,6 +302,20 @@ reviewability. Points, manual-verification status and evidence, Acceptance Verification and Implementation Completion Review; defined the README audit package set; corrected the Background dating and the T2/T4 counts; mapped SI-02 and SI-03 to #1790 and #1793. +- 2026-10-06 16:25 UTC - GitHub Copilot - Implemented T9 to T13: new coupling report with + Observations, refreshed README audit, regenerated dependency diagram, three draft subissues + approved by the maintainer, and the EPIC marked done. MV1 to MV4 pass. Re-reviewed AC1 to + AC10 against the delivered artifacts: all met; AC1's "no longer mentions `rest-api-core`" + holds for the generated sections, while the Observations name it when recording its removal. + No retrospective needed: the work went as planned; the only surprise was a regular + expression that skipped one diagram edge, caught and recorded in the evidence file. +- 2026-10-07 08:36 UTC - GitHub Copilot - Clarified AC1 to state the scope it was checked + against (generated sections only), per PR #2462 review finding F8. +- 2026-10-07 08:56 UTC - GitHub Copilot - AC2 evidence row now counts five mis-resolved edges, + including the `axum-http-server` dev edge, per PR #2462 review finding F13. +- 2026-10-07 09:11 UTC - GitHub Copilot - AC5 evidence row now says "153 workspace edges" and + names the external-to-external edge drawn for context, per PR #2462 review finding F17. + This and the previous entry were backfilled at 12:39 UTC, per PR #2462 review finding F20. ## Acceptance Criteria @@ -319,23 +333,25 @@ Original criteria (T1 to T8), met by the work recorded above: Remaining criteria (T9 to T13): -- [ ] AC1: A new dated coupling report covers every current workspace member reported by - `cargo metadata --no-deps`, and no longer mentions `rest-api-core`. -- [ ] AC2: Every package with workspace-level dependencies lists at least one import path per +- [x] AC1: A new dated coupling report covers every current workspace member reported by + `cargo metadata --no-deps`, and its generated sections (everything before + `## Observations`) no longer mention `rest-api-core`. The hand-written Observations may + name it when recording its removal. (Scope clarified on 2026-10-07 after PR #2462 review.) +- [x] AC2: Every package with workspace-level dependencies lists at least one import path per dependency, or a documented reason why none was found. -- [ ] AC3: The new report's Observations section has no placeholder text, compares against the +- [x] AC3: The new report's Observations section has no placeholder text, compares against the 2026-06-10 report, and records new findings or states that none were found. -- [ ] AC4: `readme-audit.md` has exactly one row for each of the 25 audited packages (Goal +- [x] AC4: `readme-audit.md` has exactly one row for each of the 25 audited packages (Goal item 2), each rated good, minimal, stub or missing, and no row for a package outside that set. -- [ ] AC5: Every node and edge in `docs/media/packages/dependencies-workspace-packages.md` +- [x] AC5: Every node and edge in `docs/media/packages/dependencies-workspace-packages.md` matches the current normal dependencies. -- [ ] AC6: Each new finding warranting a change has a draft subissue listed in EPIC #1669. -- [ ] AC7: EPIC #1669 marks the baseline `DONE` and ticks its own AC1. -- [ ] AC8: `linter all` exits with code `0`. -- [ ] AC9: Manual verification scenarios MV1 to MV4 are executed and documented in issue-local +- [x] AC6: Each new finding warranting a change has a draft subissue listed in EPIC #1669. +- [x] AC7: EPIC #1669 marks the baseline `DONE` and ticks its own AC1. +- [x] AC8: `linter all` exits with code `0`. +- [x] AC9: Manual verification scenarios MV1 to MV4 are executed and documented in issue-local `manual-verification-evidence.md`. -- [ ] AC10: The acceptance criteria are re-reviewed after implementation and reflect the +- [x] AC10: The acceptance criteria are re-reviewed after implementation and reflect the delivered artifacts. ## Verification Plan @@ -352,10 +368,10 @@ Status values: `TODO`, `IN_PROGRESS`, `DONE`, `FAILED`, `BLOCKED`. | ID | Scenario | Human-oriented command/steps | Expected Result | Status | Evidence | | --- | -------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | ------ | --------------------------------------------- | -| MV1 | The new report covers the current workspace | Compare the report's package sections with the member names from `cargo metadata --no-deps --format-version 1` | Same set of packages; no `rest-api-core`; the three REST API packages, `e2e-tools` and `persistence-benchmark` present | TODO | `manual-verification-evidence.md` section MV1 | -| MV2 | The committed report is reproducible | On a clean checkout, run `cargo run -p workspace-coupling -- /tmp/test-report.md` and diff it with the committed new report | Only the `Generated:` timestamp, the frontmatter and the hand-written Observations section differ | TODO | `manual-verification-evidence.md` section MV2 | -| MV3 | The dependency diagram matches the manifests | Check each edge in the Mermaid diagram against the direct `torrust*` dependencies from `cargo metadata --no-deps` | No missing or extra edges | TODO | `manual-verification-evidence.md` section MV3 | -| MV4 | The README audit matches the audited package set | Check `readme-audit.md` rows against the root crate, `console/tracker-client` and the `packages/` folders | 25 rows, one per audited package; no removed package and no `contrib/dev-tools/` member | TODO | `manual-verification-evidence.md` section MV4 | +| MV1 | The new report covers the current workspace | Compare the report's package sections with the member names from `cargo metadata --no-deps --format-version 1` | Same set of packages; no `rest-api-core`; the three REST API packages, `e2e-tools` and `persistence-benchmark` present | DONE | `manual-verification-evidence.md` section MV1 | +| MV2 | The committed report is reproducible | On a clean checkout, run `cargo run -p workspace-coupling -- /tmp/test-report.md` and diff it with the committed new report | Only the `Generated:` timestamp, the frontmatter and the hand-written Observations section differ | DONE | `manual-verification-evidence.md` section MV2 | +| MV3 | The dependency diagram matches the manifests | Check each edge in the Mermaid diagram against the direct `torrust*` dependencies from `cargo metadata --no-deps` | No missing or extra edges | DONE | `manual-verification-evidence.md` section MV3 | +| MV4 | The README audit matches the audited package set | Check `readme-audit.md` rows against the root crate, `console/tracker-client` and the `packages/` folders | 25 rows, one per audited package; no removed package and no `contrib/dev-tools/` member | DONE | `manual-verification-evidence.md` section MV4 | Notes: @@ -368,25 +384,25 @@ Notes: ### Acceptance Verification -| AC ID | Status (`TODO`/`DONE`) | Evidence | -| ----- | ---------------------- | --------------------------------------------------- | -| AC1 | TODO | {new report path; MV1 evidence} | -| AC2 | TODO | {new report sections} | -| AC3 | TODO | {new report Observations section} | -| AC4 | TODO | {`readme-audit.md` commit; MV4 evidence} | -| AC5 | TODO | {diagram commit; MV3 evidence} | -| AC6 | TODO | {draft subissue paths, or the "none found" record} | -| AC7 | TODO | {EPIC commit} | -| AC8 | TODO | {pre-commit / pre-push log} | -| AC9 | TODO | {`manual-verification-evidence.md`} | -| AC10 | TODO | {progress-log entry for the re-review} | +| AC ID | Status (`TODO`/`DONE`) | Evidence | +| ----- | ---------------------- | -------- | +| AC1 | DONE | [`workspace-coupling-report-2026-10-06.md`](../1669-overhaul-packages/workspace-coupling-report-2026-10-06.md) lists the 31 members (MV1). `rest-api-core` appears only in the Observations, which record its removal; the generated sections do not mention it. | +| AC2 | DONE | Every edge lists import paths except five whose missing paths Observations finding 3 explains (tool limitation, drafted as a subissue; the fifth, a dev-dependency edge, was found by the draft's reproduction on 2026-10-07). | +| AC3 | DONE | Observations of the new report: comparison table, resolved items and three findings. | +| AC4 | DONE | [`readme-audit.md`](../1669-overhaul-packages/readme-audit.md): 25 rows (4 good, 12 minimal, 9 stub, 0 missing) (MV4). | +| AC5 | DONE | [Dependency diagram](../../../media/packages/dependencies-workspace-packages.md): its 153 workspace edges equal `cargo metadata` (MV3); it also draws one external-to-external edge (`torrust-server-lib` to `torrust-net-primitives`) for context, stated in its prose. | +| AC6 | DONE | Three drafts under `docs/issues/drafts/1669-*` linked from the report findings and listed in the EPIC quick list and Details table. | +| AC7 | DONE | Commit "docs(issues): [#2446] mark the baseline analysis done in EPIC #1669". | +| AC8 | DONE | Pre-commit (`linter all`) passed on every commit; pre-push runs on push. | +| AC9 | DONE | [`manual-verification-evidence.md`](manual-verification-evidence.md), MV1 to MV4. | +| AC10 | DONE | Progress-log entry of 2026-10-06 16:25 UTC. | ## Implementation Completion Review After implementation, compare the result with this specification. Record invalidated assumptions, material design changes, unexpected validation findings, and reusable lessons. -- Retrospective: `Not yet assessed` +- Retrospective: `Not needed` (see the 2026-10-06 16:25 UTC progress-log entry) - If needed, create `implementation-retrospective.md` from `docs/templates/IMPLEMENTATION-RETROSPECTIVE.md` in this issue folder. - If no retrospective is needed, add a concise progress-log entry explaining why the work had diff --git a/docs/issues/open/2446-1669-establish-baseline-analysis/manual-verification-evidence.md b/docs/issues/open/2446-1669-establish-baseline-analysis/manual-verification-evidence.md new file mode 100644 index 000000000..046b633c8 --- /dev/null +++ b/docs/issues/open/2446-1669-establish-baseline-analysis/manual-verification-evidence.md @@ -0,0 +1,266 @@ +--- +doc-type: manual-verification-evidence +issue-spec: docs/issues/open/2446-1669-establish-baseline-analysis/ISSUE.md +last-updated-utc: 2026-10-07 09:06 +--- + + + +# Manual Verification Evidence + +## Purpose + +Record real, human-oriented verification of the completed behavior. This is +evidence from commands or interactions actually performed against the artifact; +do not invent commands, output, logs, or results. + +## Preserving Verification Artifacts + +`.tmp/` and other git-ignored paths are not part of the repository, so a path +there is not evidence once the run ends. The commands, the helper script and the +relevant output are recorded inline below. + +## Environment and Prerequisites + +- Date and time (UTC): MV4 at 2026-10-06 16:47; MV3 at 2026-10-07 08:32; MV1 and MV2 at + 2026-10-07 09:06 (rerun to record every command that prints an observed line) +- Artifact under test: branch `2446-1669-establish-baseline-analysis` from + "docs(issues): [#2446] regenerate the coupling report after rebasing onto develop" onwards; + the later commits change no generated report section, manifest or README +- Operating system / environment: Linux 7.0.0-34-generic; stable Rust toolchain + (`rustc 1.99.0 (b940084d7 2026-09-28)`, `cargo 1.99.0 (5f94df478 2026-08-27)`) +- Prerequisites and setup performed: clean working tree (`git status --short` printed + nothing). The scenarios were first run at 12:55 and 16:17 UTC on 2026-10-06 before the + rebase, with the same results. + +## Verification Processes + +### MV1 - The new report covers the current workspace + +- Goal: the 2026-10-06 coupling report lists exactly the workspace members from `cargo metadata`. +- Initial state: `workspace-coupling-report-2026-10-06.md` committed. +- Status: `DONE` + +#### Steps Performed + +Rerun on 2026-10-07 09:06 UTC (stable Rust toolchain, `rustc 1.99.0`). Every observed line +below is printed by one of these commands, in order: + +```sh +R=docs/issues/open/1669-overhaul-packages/workspace-coupling-report-2026-10-06.md +# Workspace member names, from cargo metadata +cargo metadata --no-deps --format-version 1 \ + | python3 -c 'import json,sys;[print(p["name"]) for p in json.load(sys.stdin)["packages"]]' \ + | sort > .tmp/mv1-metadata.txt +# Packages in the report: leaf list plus detail sections +{ sed -n '/^## Packages with no workspace dependencies/,/^## Package coupling/p' $R \ + | grep -oP '^- `\K[^`]+'; grep -oP '^### `\K[^`]+' $R; } | sort > .tmp/mv1-report.txt +wc -l < .tmp/mv1-metadata.txt # line 1 +wc -l < .tmp/mv1-report.txt # line 2 +diff .tmp/mv1-metadata.txt .tmp/mv1-report.txt && echo identical # line 3 +sed -n '/^## Observations/q;p' $R | grep -c "rest-api-core" # line 4 +``` + +#### Observed Result + +```text +31 +31 +identical +0 +``` + +Both lists have 31 entries, including `torrust-tracker-rest-api-protocol`, +`torrust-tracker-rest-api-application`, `torrust-tracker-rest-api-runtime-adapter`, +`torrust-tracker-e2e-tools` and `torrust-tracker-persistence-benchmark`. + +#### Conclusion + +Met. The report covers the current workspace and its generated part does not mention +`rest-api-core`. The two mentions in the Observations section are historical (they describe +its removal by #1938). + +### MV2 - The committed report is reproducible + +- Goal: regenerating the report changes nothing but the timestamp in the generated part. +- Initial state: clean working tree. +- Status: `DONE` + +#### Steps Performed + +Rerun on 2026-10-07 09:06 UTC (stable Rust toolchain, `rustc 1.99.0`), with `R` as in MV1. +Every observed line is printed by one of these commands: + +```sh +cargo run -q -p workspace-coupling -- /tmp/test-report-2446.md > /dev/null 2>&1; echo "tool exit=$?" +diff <(sed -n '/^# Workspace Coupling Report/,/^## Observations/p' $R) \ + <(sed -n '/^# Workspace Coupling Report/,/^## Observations/p' /tmp/test-report-2446.md) +``` + +#### Observed Result + +```text +tool exit=0 +3c3 +< Generated: 2026-10-06 16:35 UTC +--- +> Generated: 2026-10-07 09:06 UTC +``` + +#### Conclusion + +Met. Only the `Generated:` line differs; the frontmatter and the hand-written Observations +section are outside the compared range by design. + +### MV3 - The dependency diagram matches the manifests + +- Goal: every edge in the Mermaid diagram is a direct normal `torrust*` dependency, and every such + dependency is drawn. +- Initial state: `docs/media/packages/dependencies-workspace-packages.md` committed. +- Status: `DONE` + +#### Steps Performed + +Rerun on 2026-10-07 08:32 UTC on the same head, after the layer-placement fix, with a single +self-contained script (stable Rust toolchain, `rustc 1.99.0`). It builds the expected edge set +from `cargo metadata --no-deps` (for each `torrust*` package, every dependency with +`kind == null` whose name starts with `torrust`, mapped to the diagram's node IDs), extracts the +diagram's edges, excluding `server-lib --> net-prim` (an edge between two external crates, drawn +for context), and compares the two sets: + +```python +import json +import re +import subprocess + +NODE = { + "torrust-tracker": "tracker", + "torrust-tracker-axum-http-server": "axum-http", + "torrust-tracker-axum-rest-api-server": "axum-rest", + "torrust-tracker-axum-health-check-api-server": "axum-health", + "torrust-tracker-udp-server": "udp-srv", + "torrust-tracker-axum-server": "axum-base", + "torrust-tracker-core": "tracker-core", + "torrust-tracker-http-core": "http-core", + "torrust-tracker-udp-core": "udp-core", + "torrust-tracker-rest-api-application": "rest-app", + "torrust-tracker-rest-api-runtime-adapter": "rest-adapter", + "torrust-tracker-http-protocol": "http-proto", + "torrust-tracker-udp-protocol": "udp-proto", + "torrust-tracker-rest-api-protocol": "rest-proto", + "torrust-tracker-swarm-coordination-registry": "swarm", + "torrust-tracker-configuration": "config", + "torrust-tracker-primitives": "primitives", + "torrust-tracker-events": "events", + "torrust-tracker-client-lib": "client-lib", + "torrust-tracker-client": "tracker-client", + "torrust-tracker-rest-api-client": "rest-client", + "torrust-tracker-test-helpers": "test-helpers", + "torrust-tracker-torrent-repository-benchmarking": "torrent-bench", + "torrust-tracker-persistence-benchmark": "persist-bench", + "torrust-tracker-e2e-tools": "e2e-tools", + "torrust-clock": "clock", + "torrust-info-hash": "info-hash", + "torrust-located-error": "located-err", + "torrust-metrics": "metrics", + "torrust-net-primitives": "net-prim", + "torrust-peer-id": "peer-id", + "torrust-bencode": "bencode", + "torrust-server-lib": "server-lib", +} + +metadata = json.loads( + subprocess.run( + ["cargo", "metadata", "--no-deps", "--format-version", "1"], + capture_output=True, check=True, text=True, + ).stdout +) +expected = { + f"{NODE[p['name']]} --> {NODE[d['name']]}" + for p in metadata["packages"] + if p["name"].startswith("torrust") + for d in p["dependencies"] + if d["kind"] is None and d["name"].startswith("torrust") +} + +diagram = open("docs/media/packages/dependencies-workspace-packages.md").read() +drawn = { + m.group(1) + for m in re.finditer(r"^ ([a-z0-9-]+ --> [a-z0-9-]+)$", diagram, re.M) + if not m.group(1).startswith("server-lib --> ") +} + +print("expected edges:", len(expected)) +print("drawn edges:", len(drawn)) +print("missing from diagram:", sorted(expected - drawn)) +print("extra in diagram:", sorted(drawn - expected)) +``` + +#### Observed Result + +```text +expected edges: 153 +drawn edges: 153 +missing from diagram: [] +extra in diagram: [] +``` + +#### Conclusion + +Met. The diagram has exactly the 153 normal `torrust*` dependency edges and no other edge +between packages. + +### MV4 - The README audit matches the audited package set + +- Goal: `readme-audit.md` has one row for each of the 25 audited packages, with the right crate + name and README line count. +- Initial state: `readme-audit.md` committed. +- Status: `DONE` + +#### Steps Performed + +1. Run this check script from the repository root: + + ```python + import re, os + A = "docs/issues/open/1669-overhaul-packages/readme-audit.md" + seen = []; section = None; bad = 0 + for line in open(A): + if line.startswith("## "): section = line.strip() + m = re.match(r"^\| (\(repository root\)|`[^`]+`) +\| `([^`]+)` +\| (\d+) +\| (\w+)", line) + if not m: continue + d, crate, n, rating = m.groups() + if d == "(repository root)": cdir = "." + elif "console" in section: cdir = "console/tracker-client" + else: cdir = "packages/" + d.strip("`") + path = cdir + "/README.md" + real = sum(1 for _ in open(path)) if os.path.exists(path) else None + name = re.search(r'^name = "([^"]+)"', open(cdir + "/Cargo.toml").read(), re.M).group(1) + if real != int(n) or name != crate: bad += 1; print("MISMATCH", d, crate, n, real, name) + seen.append(cdir) + pk = sorted("packages/" + x for x in os.listdir("packages") if os.path.isdir("packages/" + x)) + print("audited rows:", len(seen), "mismatches:", bad) + print("not audited:", [p for p in pk + ["console/tracker-client", "."] if p not in seen]) + ``` + +#### Observed Result + +```text +audited rows: 25 mismatches: 0 +not audited: [] +``` + +#### Conclusion + +Met. 25 rows, one per audited package; no removed package and no `contrib/dev-tools/` member. + +## Failures and Follow-up + +None. The first MV3 comparison used a regular expression without digits and silently skipped +the `e2e-tools --> tracker` edge on both sides (152 = 152); the corrected expression above +matches all 153 edges. + +After rebasing onto `develop` (76 new commits, none touching a manifest), the pre-rebase +report no longer reproduced exactly: a few import paths changed in six edges, with no +dependency edge added or removed. The report was regenerated ("docs(issues): [#2446] +regenerate the coupling report after rebasing onto develop") and MV1 to MV4 rerun above. diff --git a/docs/media/packages/dependencies-workspace-packages.md b/docs/media/packages/dependencies-workspace-packages.md index fcc9d85fd..5c40aaec9 100644 --- a/docs/media/packages/dependencies-workspace-packages.md +++ b/docs/media/packages/dependencies-workspace-packages.md @@ -4,11 +4,19 @@ semantic-links: - docs/packages.md - packages/AGENTS.md - docs/issues/open/1669-overhaul-packages/EPIC.md - - docs/issues/open/1669-overhaul-packages/workspace-coupling-report-2026-06-10.md + - docs/issues/open/1669-overhaul-packages/workspace-coupling-report-2026-10-06.md --- # Torrust Tracker — Workspace Package Dependencies +Direct normal (non-dev, non-build) dependencies between workspace packages and on external +`torrust-*` crates, as declared in each `Cargo.toml`. Verified against +`cargo metadata --no-deps` on 2026-10-06: 153 edges. One more edge, +`torrust-server-lib --> torrust-net-primitives`, is drawn for context: it is a dependency between +two external crates, so no workspace manifest declares it. See the +[2026-10-06 coupling report](../../issues/open/1669-overhaul-packages/workspace-coupling-report-2026-10-06.md) +for the items each edge imports. + ```mermaid flowchart TB subgraph app["Application"] @@ -25,18 +33,28 @@ flowchart TB axum-base["axum-server"] end + subgraph runtime-adapter["Runtime Adapter"] + direction TB + rest-adapter["rest-api-runtime-adapter"] + end + + subgraph rest-application["REST API Application"] + direction TB + rest-app["rest-api-application"] + end + subgraph core["Core"] direction TB tracker-core["tracker-core"] - http-core["http-tracker-core"] - udp-core["udp-tracker-core"] - rest-core["rest-api-core"] + http-core["http-core"] + udp-core["udp-core"] end subgraph protocol["Protocols"] direction TB http-proto["http-protocol"] udp-proto["udp-protocol"] + rest-proto["rest-api-protocol"] end subgraph domain["Domain / Shared"] @@ -45,7 +63,6 @@ flowchart TB config["configuration"] primitives["primitives"] events["events"] - server-lib["server-lib"] end subgraph client-tools["Client Tools"] @@ -72,117 +89,131 @@ flowchart TB net-prim["torrust-net-primitives"] peer-id["torrust-peer-id"] bencode["torrust-bencode"] + server-lib["torrust-server-lib"] end - %% App depends on servers, core, and config - tracker --> tracker-core - tracker --> http-core - tracker --> udp-core + %% App (composition root) + tracker --> clock + tracker --> server-lib + tracker --> axum-health tracker --> axum-http tracker --> axum-rest - tracker --> axum-health tracker --> axum-base - tracker --> rest-client - tracker --> rest-core - tracker --> server-lib tracker --> config + tracker --> tracker-core + tracker --> events + tracker --> http-core + tracker --> primitives + tracker --> rest-client + tracker --> rest-proto + tracker --> rest-adapter tracker --> swarm + tracker --> udp-core tracker --> udp-srv - tracker --> clock %% Server dependencies - axum-http --> axum-base + axum-http --> clock + axum-http --> info-hash + axum-http --> net-prim axum-http --> server-lib + axum-http --> axum-base axum-http --> config axum-http --> tracker-core axum-http --> http-core axum-http --> http-proto - axum-http --> swarm axum-http --> primitives - axum-http --> udp-proto - axum-http --> clock - axum-http --> info-hash - axum-http --> net-prim + axum-http --> swarm - axum-rest --> axum-base + axum-rest --> clock + axum-rest --> info-hash + axum-rest --> metrics + axum-rest --> net-prim axum-rest --> server-lib + axum-rest --> axum-base axum-rest --> config axum-rest --> tracker-core axum-rest --> http-core + axum-rest --> primitives + axum-rest --> rest-app axum-rest --> rest-client - axum-rest --> rest-core + axum-rest --> rest-proto + axum-rest --> rest-adapter axum-rest --> swarm - axum-rest --> udp-srv axum-rest --> udp-core - axum-rest --> primitives - axum-rest --> clock - axum-rest --> info-hash - axum-rest --> metrics - axum-rest --> net-prim + axum-rest --> udp-srv - axum-health --> axum-base + axum-health --> net-prim axum-health --> server-lib + axum-health --> axum-base axum-health --> config - axum-health --> net-prim + axum-health --> primitives + axum-base --> located-err axum-base --> server-lib axum-base --> config - axum-base --> located-err + udp-srv --> clock + udp-srv --> info-hash + udp-srv --> metrics + udp-srv --> net-prim + udp-srv --> peer-id udp-srv --> server-lib + udp-srv --> client-lib udp-srv --> config udp-srv --> tracker-core + udp-srv --> events + udp-srv --> primitives + udp-srv --> swarm udp-srv --> udp-core udp-srv --> udp-proto - udp-srv --> swarm - udp-srv --> primitives - udp-srv --> events - udp-srv --> client-lib - udp-srv --> clock - udp-srv --> info-hash - udp-srv --> metrics - udp-srv --> net-prim %% Core layer dependencies - tracker-core --> config - tracker-core --> swarm - tracker-core --> primitives - tracker-core --> events tracker-core --> clock tracker-core --> info-hash tracker-core --> located-err tracker-core --> metrics + tracker-core --> config + tracker-core --> events + tracker-core --> primitives + tracker-core --> swarm - http-core --> tracker-core - http-core --> http-proto - http-core --> config - http-core --> swarm - http-core --> primitives - http-core --> events http-core --> clock http-core --> info-hash http-core --> metrics http-core --> net-prim + http-core --> config + http-core --> tracker-core + http-core --> events + http-core --> http-proto + http-core --> primitives + http-core --> swarm - udp-core --> tracker-core - udp-core --> udp-proto - udp-core --> config - udp-core --> swarm - udp-core --> primitives - udp-core --> events udp-core --> clock udp-core --> info-hash udp-core --> metrics udp-core --> net-prim + udp-core --> config + udp-core --> tracker-core + udp-core --> events + udp-core --> primitives + udp-core --> swarm + udp-core --> udp-proto - rest-core --> config - rest-core --> tracker-core - rest-core --> http-core - rest-core --> swarm - rest-core --> primitives - rest-core --> udp-srv - rest-core --> udp-core - rest-core --> metrics + rest-app --> info-hash + rest-app --> primitives + rest-app --> rest-proto + + rest-adapter --> info-hash + rest-adapter --> metrics + rest-adapter --> config + rest-adapter --> tracker-core + rest-adapter --> http-core + rest-adapter --> primitives + rest-adapter --> rest-app + rest-adapter --> rest-proto + rest-adapter --> swarm + rest-adapter --> udp-core + rest-adapter --> udp-srv %% Protocol layer http-proto --> bencode @@ -193,16 +224,17 @@ flowchart TB udp-proto --> peer-id - %% Domain layer - swarm --> config - swarm --> primitives - swarm --> events + rest-proto --> metrics + + %% Domain layer (events has no torrust-* dependencies) swarm --> clock swarm --> info-hash swarm --> metrics + swarm --> events + swarm --> primitives - config --> primitives config --> located-err + config --> primitives primitives --> clock primitives --> info-hash @@ -210,37 +242,46 @@ flowchart TB primitives --> peer-id %% Client tools - client-lib --> primitives - client-lib --> udp-proto - client-lib --> info-hash client-lib --> located-err client-lib --> net-prim + client-lib --> peer-id + client-lib --> http-proto + client-lib --> udp-proto + tracker-client --> info-hash + tracker-client --> peer-id tracker-client --> client-lib + tracker-client --> http-proto tracker-client --> udp-proto - tracker-client --> info-hash - rest-client --> no-ws-deps["(no workspace deps)"] - style no-ws-deps fill:#f9f,stroke:#333,stroke-width:1px + rest-client --> rest-proto + %% External crates with torrust-* dependencies server-lib --> net-prim %% Testing / Benchmarking + test-helpers --> info-hash + test-helpers --> peer-id + test-helpers --> client-lib test-helpers --> config + test-helpers --> http-proto + test-helpers --> primitives + test-helpers --> udp-proto - torrent-bench --> primitives torrent-bench --> clock torrent-bench --> info-hash + torrent-bench --> primitives + persist-bench --> info-hash persist-bench --> config persist-bench --> tracker-core - persist-bench --> info-hash + persist-bench --> primitives e2e-tools --> tracker %% External crates styling classDef ext fill:#e1f5fe,stroke:#0288d1,stroke-dasharray: 5 5 - class clock,info-hash,located-err,metrics,net-prim,peer-id,bencode ext + class clock,info-hash,located-err,metrics,net-prim,peer-id,bencode,server-lib ext %% Layer styling classDef app fill:#fff3e0,stroke:#ff9800 @@ -250,13 +291,19 @@ flowchart TB class axum-http,axum-rest,axum-health,udp-srv,axum-base srv classDef core fill:#fce4ec,stroke:#e91e63 - class tracker-core,http-core,udp-core,rest-core core + class tracker-core,http-core,udp-core core + + classDef adapter fill:#ede7f6,stroke:#673ab7 + class rest-adapter adapter + + classDef application fill:#e3f2fd,stroke:#1976d2 + class rest-app application classDef proto fill:#f3e5f5,stroke:#9c27b0 - class http-proto,udp-proto proto + class http-proto,udp-proto,rest-proto proto classDef dom fill:#fff8e1,stroke:#ffc107 - class swarm,config,primitives,events,server-lib dom + class swarm,config,primitives,events dom classDef client fill:#e0f2f1,stroke:#009688 class client-lib,tracker-client,rest-client client diff --git a/docs/pr-reviews/pr-2462-review/PR-REVIEW.md b/docs/pr-reviews/pr-2462-review/PR-REVIEW.md new file mode 100644 index 000000000..72f64f188 --- /dev/null +++ b/docs/pr-reviews/pr-2462-review/PR-REVIEW.md @@ -0,0 +1,379 @@ +--- +semantic-links: + skill-links: + - process-pr-review + related-artifacts: + - .github/skills/dev/pr-reviews/process-pr-review/SKILL.md + - "issue #2446" +--- + + + +# PR #2462 Review Audit + +Source: pull-request reviews and inline review threads for +. + +## Ownership + +The PR author owns this tracked audit record. Reviewers, including repository review agents, +deliver findings through GitHub and have no repository-artifact obligation. + +- Post-merge workflow approval: N/A + +## Status Values + +- Relationship: `ORIGINAL`, `RE_RAISE_OF:` +- Disposition: `FIXED`, `NO_ACTION`, `SUPERSEDED`, `FOLLOW_UP` +- Thread state: `OPEN`, `RESOLVED`, `NON_RESOLVABLE`, `SUPERSEDED`. `OPEN` applies prospectively + to audits created or updated for approved follow-up work; historical audits remain valid without + bulk migration. +- Severity: `Blocker`, `Major`, `Minor`, `Nit`, `Suggestion`; append `(inferred)` when derived + from free prose. +- Author class: `Copilot`, `Human`, `Unknown` +- Category: `link-integrity`, `formatting`, `metadata`, `testing`, `correctness`, + `documentation`, `maintainability`, `security`, `other` +- An outdated thread whose concern was fixed is `FIXED`/`RESOLVED`, even when GitHub marks the + original thread outdated after the push. For in-PR feedback, use `NO_ACTION`/`SUPERSEDED` only + for a duplicate, superseded, or no-change concern. A post-merge `NO_ACTION` requires maintainer + approval to decline the follow-up work. + +## Findings + +| Finding ID | Review finding reference | Author class | Severity | Category | Relationship | Disposition | Thread state | +| ---------- | ------------------------ | ------------ | -------- | -------- | ------------ | ----------- | ------------ | +| F1 | `review-finding:pr-2462-f1` | Copilot | Minor | correctness | ORIGINAL | FIXED | RESOLVED | +| F2 | `review-finding:pr-2462-f2` | Copilot | Major | testing | ORIGINAL | FIXED | RESOLVED | +| F3 | `review-finding:pr-2462-f3` | Copilot | Major | correctness | ORIGINAL | FIXED | RESOLVED | +| F4 | `review-finding:pr-2462-f4` | Copilot | Major | correctness | ORIGINAL | FIXED | RESOLVED | +| F5 | `review-finding:pr-2462-f5` | Copilot | Major | documentation | ORIGINAL | FIXED | RESOLVED | +| F6 | `review-finding:pr-2462-f6` | Copilot | Minor | metadata | ORIGINAL | FIXED | RESOLVED | +| F7 | `review-finding:pr-2462-f7` | Copilot | Minor | documentation | ORIGINAL | FIXED | RESOLVED | +| F8 | `review-finding:pr-2462-f8` | Copilot | Minor | documentation | ORIGINAL | FIXED | RESOLVED | +| F9 | `review-finding:pr-2462-f9` | Human | Major | testing | RE_RAISE_OF:F2 | FIXED | RESOLVED | +| F10 | `review-finding:pr-2462-f10` | Human | Major | correctness | RE_RAISE_OF:F4 | FIXED | RESOLVED | +| F11 | `review-finding:pr-2462-f11` | Human | Major | correctness | RE_RAISE_OF:F3 | FIXED | RESOLVED | +| F12 | `review-finding:pr-2462-f12` | Human | Major | documentation | RE_RAISE_OF:F5 | FIXED | RESOLVED | +| F13 | `review-finding:pr-2462-f13` | Human | Minor | correctness | ORIGINAL | FIXED | RESOLVED | +| F14 | `review-finding:pr-2462-f14` | Human | Minor | documentation | RE_RAISE_OF:F7 | FIXED | RESOLVED | +| F15 | `review-finding:pr-2462-f15` | Human | Minor | documentation | ORIGINAL | FIXED | RESOLVED | +| F16 | `review-finding:pr-2462-f16` | Human | Nit | correctness | RE_RAISE_OF:F1 | FIXED | RESOLVED | +| F17 | `review-finding:pr-2462-f17` | Human | Nit | documentation | ORIGINAL | FIXED | RESOLVED | +| F18 | `review-finding:pr-2462-f18` | Human | Nit | documentation | RE_RAISE_OF:F8 | FIXED | RESOLVED | +| F19 | `review-finding:pr-2462-f19` | Human | Suggestion | metadata | RE_RAISE_OF:F6 | FIXED | RESOLVED | +| F20 | `review-finding:pr-2462-f20` | Human | Nit | metadata | ORIGINAL | FIXED | RESOLVED | +| F21 | `review-finding:pr-2462-f21` | Human | Nit | documentation | ORIGINAL | FIXED | RESOLVED | +| F22 | `review-finding:pr-2462-f22` | Human | Minor | correctness | ORIGINAL | FIXED | RESOLVED | + +## Finding Details + +### F1 - Off-by-one axum-rest-api-server dependency count + +- PR number: 2462 +- Source review ID: 5432054524 +- Reviewer finding ID: N/A +- Source URL: +- Concern: The Observations said `axum-rest-api-server` went from 12 to 13 workspace deps, while the generated sections of the June report and this report say 13 and 14. +- Solution: The Observations now say 13 to 14, using the tool's own `Workspace deps` counts rather than distinct crates. +- Current-tree verification: `Workspace deps:` lines for `torrust-tracker-axum-rest-api-server` in `docs/issues/open/1669-overhaul-packages/workspace-coupling-report-2026-10-06.md` and the June report inspected; the Observations sentence matches them. +- Resolution reference: `docs(issues): [#2446] correct the axum-rest-api-server dependency count` +- Follow-up PR URL: N/A +- Reply URL: + +### F2 - MV3 commands cannot produce the recorded comparison + +- PR number: 2462 +- Source review ID: 5432054524 +- Reviewer finding ID: N/A +- Source URL: +- Concern: MV3's commands printed only a count and the drawn edges; nothing generated the metadata edge list or ran a comparison, so the recorded `identical` result and AC5 were not reproducible. +- Solution: MV3 now records a self-contained script that maps `cargo metadata --no-deps` normal `torrust*` edges to diagram node names and compares them with the drawn edges, printing counts and both set differences. +- Current-tree verification: Extracted the MV3 script from `docs/issues/open/2446-1669-establish-baseline-analysis/manual-verification-evidence.md` and ran it after rebasing onto the latest `develop`: `expected edges: 153`, `drawn edges: 153`, `missing from diagram: []`, `extra in diagram: []`. +- Resolution reference: `docs(issues): [#2446] record a reproducible MV3 comparison` +- Follow-up PR URL: N/A +- Reply URL: + +### F3 - Test-helpers draft can close without decoupling + +- PR number: 2462 +- Source review ID: 5432054524 +- Reviewer finding ID: N/A +- Source URL: +- Concern: The draft's AC escape clauses let the issue complete without decoupling `test-helpers` or making it publishable, contradicting its own Goal and Risks. +- Solution: The draft now moves the helpers into `tests/common/` or a `publish = false` package, rejects the feature-gate and publish-first options with reasons, and AC2/AC4 have no escape clauses. +- Current-tree verification: `docs/issues/drafts/1669-decouple-test-helpers-from-unpublished-crates/ISSUE.md` Goal, options and AC2/AC4 inspected; no remaining escape clause. +- Resolution reference: `docs(issues): [#2446] require real decoupling in the test-helpers draft` +- Follow-up PR URL: N/A +- Reply URL: + +### F4 - Optional dependencies are still normal edges + +- PR number: 2462 +- Source review ID: 5432054524 +- Reviewer finding ID: N/A +- Source URL: +- Concern: Feature-gated dependencies keep `kind: null` with `optional: true` in Cargo metadata, so the draft's expected "no longer normal deps" outputs could not be met. +- Solution: The draft now says optional edges remain in `cargo metadata`, defines how the coupling tool and the diagram must label them, and adds AC8 for that labeling. +- Current-tree verification: `docs/issues/drafts/1669-gate-server-testing-modules-behind-feature/ISSUE.md` tasks, ACs and AC8 inspected against `cargo metadata --no-deps` output for an optional dependency. +- Resolution reference: `docs(issues): [#2446] represent optional edges in the testing-feature draft` +- Follow-up PR URL: N/A +- Reply URL: + +### F5 - Coupling-tool bug draft skips the fix-bug workflow + +- PR number: 2462 +- Source review ID: 5432054524 +- Reviewer finding ID: N/A +- Source URL: +- Concern: The bug draft had no issue-local reproduction evidence or classification and no like-for-like recheck, which `fix-bug/SKILL.md:106-147` requires before review. +- Solution: The draft now follows the fix-bug skill and has a new `manual-verification-evidence.md` with R1 Reproduced (five mis-resolved edges) and R2 TODO for the post-fix recheck. +- Current-tree verification: `docs/issues/drafts/1669-coupling-tool-resolve-lib-names-and-renames/ISSUE.md` and its sibling `manual-verification-evidence.md` inspected; R1 output matches the five edges in the regenerated report. +- Resolution reference: `docs(issues): [#2446] follow the fix-bug workflow in the coupling-tool draft` +- Follow-up PR URL: N/A +- Reply URL: + +### F6 - Long-lived report links the open-spec path + +- PR number: 2462 +- Source review ID: 5432054524 +- Reviewer finding ID: N/A +- Source URL: +- Concern: The report's frontmatter linked the issue spec under `docs/issues/open/`, which moves when #2446 closes; the semantic-link convention prefers the issue reference. +- Solution: The frontmatter now uses `"issue #2446"`. +- Current-tree verification: `docs/issues/open/1669-overhaul-packages/workspace-coupling-report-2026-10-06.md` frontmatter inspected; frontmatter validator passed in pre-commit. +- Resolution reference: `docs(issues): [#2446] reference issue #2446 instead of its open-spec path` +- Follow-up PR URL: N/A +- Reply URL: + +### F7 - REST API application and adapter drawn as Core + +- PR number: 2462 +- Source review ID: 5432054524 +- Reviewer finding ID: N/A +- Source URL: +- Concern: The diagram put `rest-api-application` and `rest-api-runtime-adapter` in the Core layer, while `docs/packages.md` and `packages/AGENTS.md` give them their own layers. +- Solution: The diagram now has separate `Runtime Adapter` and `REST API Application` subgraphs with their own class definitions. +- Current-tree verification: `docs/media/packages/dependencies-workspace-packages.md` subgraphs inspected; the Mermaid diagram validated; MV3 still reports 153/153 with no differences. +- Resolution reference: `docs(packages): [#2446] place REST API application and adapter in their own layers` +- Follow-up PR URL: N/A +- Reply URL: + +### F8 - AC1 checked while the report mentions rest-api-core + +- PR number: 2462 +- Source review ID: 5432054524 +- Reviewer finding ID: N/A +- Source URL: +- Concern: AC1 was checked although the hand-written Observations mention `rest-api-core`; the narrowing to generated sections lived only in the log and evidence. +- Solution: AC1 itself now limits the no-mention requirement to the generated sections (everything before `## Observations`); the hand-written Observations may name `rest-api-core` when recording its removal. +- Current-tree verification: AC1 text in `docs/issues/open/2446-1669-establish-baseline-analysis/ISSUE.md` inspected; `rest-api-core` appears only after `## Observations` in the 2026-10-06 report. +- Resolution reference: `docs(issues): [#2446] state AC1's scope in the criterion itself` +- Follow-up PR URL: N/A +- Reply URL: + +### F9 - MV evidence lines lack the commands that printed them + +- PR number: 2462 +- Source review ID: 5439725107 +- Reviewer finding ID: F1 +- Source URL: +- Concern: Re-raises F2 and extends it: MV1 and MV2 also recorded lines that no recorded command printed. +- Solution: MV3 fixed as in F2 (`docs(issues): [#2446] record a reproducible MV3 comparison`). MV1 and MV2 were rerun with commands that print every recorded line (member counts, generated-section comparison, tool exit code, timestamp-only diff), and the Environment section records each scenario's run time. +- Current-tree verification: Reran MV1/MV2 (2026-10-07 09:06 UTC) and MV3 (08:32 UTC) as recorded in `docs/issues/open/2446-1669-establish-baseline-analysis/manual-verification-evidence.md`; after rebasing onto the latest `develop`, the regenerated report's generated sections differ only in the `Generated:` stamp and MV3 still reports 153/153. +- Resolution reference: `docs(issues): [#2446] record the commands behind every MV1 and MV2 output line` +- Follow-up PR URL: N/A +- Reply URL: + +### F10 - Optional-dependency route cannot meet T2-T5, AC3 or MV2 + +- PR number: 2462 +- Source review ID: 5439725107 +- Reviewer finding ID: F2 +- Source URL: +- Concern: Re-raises F4: an optional dependency is still a normal dependency, so the draft's tasks, AC3 and MV2 could not be met as written. +- Solution: Fixed by the F4 commit. +- Current-tree verification: `docs/issues/drafts/1669-gate-server-testing-modules-behind-feature/ISSUE.md` inspected as in F4. +- Resolution reference: `docs(issues): [#2446] represent optional edges in the testing-feature draft` +- Follow-up PR URL: N/A +- Reply URL: + +### F11 - Test-helpers options and escape clauses miss the Goal + +- PR number: 2462 +- Source review ID: 5439725107 +- Reviewer finding ID: F3 +- Source URL: +- Concern: Re-raises F3: two of three options cannot meet the Goal and AC2/AC4 let the issue close without decoupling. +- Solution: Fixed by the F3 commit. +- Current-tree verification: `docs/issues/drafts/1669-decouple-test-helpers-from-unpublished-crates/ISSUE.md` inspected as in F3. +- Resolution reference: `docs(issues): [#2446] require real decoupling in the test-helpers draft` +- Follow-up PR URL: N/A +- Reply URL: + +### F12 - Bug draft has no reproduction evidence + +- PR number: 2462 +- Source review ID: 5439725107 +- Reviewer finding ID: F4 +- Source URL: +- Concern: Re-raises F5: the fix-bug rule binds the draft, which had no reproduction evidence or scenario. +- Solution: Fixed by the F5 commit. +- Current-tree verification: `docs/issues/drafts/1669-coupling-tool-resolve-lib-names-and-renames/ISSUE.md` and its evidence file inspected as in F5. +- Resolution reference: `docs(issues): [#2446] follow the fix-bug workflow in the coupling-tool draft` +- Follow-up PR URL: N/A +- Reply URL: + +### F13 - Finding 3 omits the fifth mis-resolved edge + +- PR number: 2462 +- Source review ID: 5439725107 +- Reviewer finding ID: F5 +- Source URL: +- Concern: Finding 3 said four edges are falsely reported as unreferenced; the `axum-http-server` to `client-lib` dev edge is a fifth. +- Solution: Finding 3 now lists five edges including the dev edge; the spec's AC2 evidence and the coupling-tool draft's R1 say five. +- Current-tree verification: The five "No ... references found" edges in `docs/issues/open/1669-overhaul-packages/workspace-coupling-report-2026-10-06.md` counted against Finding 3's list. +- Resolution reference: `docs(issues): [#2446] count the axum-http-server dev edge in finding 3` +- Follow-up PR URL: N/A +- Reply URL: + +### F14 - REST API application and adapter drawn in Core + +- PR number: 2462 +- Source review ID: 5439725107 +- Reviewer finding ID: F6 +- Source URL: +- Concern: Re-raises F7. +- Solution: Fixed by the F7 commit. +- Current-tree verification: `docs/media/packages/dependencies-workspace-packages.md` inspected as in F7. +- Resolution reference: `docs(packages): [#2446] place REST API application and adapter in their own layers` +- Follow-up PR URL: N/A +- Reply URL: + +### F15 - Drafts omit the completion-review conditions + +- PR number: 2462 +- Source review ID: 5439725107 +- Reviewer finding ID: F7 +- Source URL: +- Concern: The three drafts' Implementation Completion Review sections carried only `Retrospective: Not yet assessed`, without the conditions `create-issue` requires and `docs/templates/ISSUE.md` carries. +- Solution: Copied the template's retrospective, no-discovery progress-log and agent-review-report conditions into all three drafts. +- Current-tree verification: The section in `docs/issues/drafts/1669-decouple-test-helpers-from-unpublished-crates/ISSUE.md`, `docs/issues/drafts/1669-gate-server-testing-modules-behind-feature/ISSUE.md` and `docs/issues/drafts/1669-coupling-tool-resolve-lib-names-and-renames/ISSUE.md` compared with `docs/templates/ISSUE.md`. +- Resolution reference: `docs(issues): [#2446] keep the template's completion-review conditions in the drafts` +- Follow-up PR URL: N/A +- Reply URL: + +### F16 - Dependency count uses distinct crates + +- PR number: 2462 +- Source review ID: 5439725107 +- Reviewer finding ID: F8 +- Source URL: +- Concern: Re-raises F1: the count should follow the report's own `Workspace deps:` lines. +- Solution: Fixed by the F1 commit. +- Current-tree verification: `docs/issues/open/1669-overhaul-packages/workspace-coupling-report-2026-10-06.md` inspected as in F1. +- Resolution reference: `docs(issues): [#2446] correct the axum-rest-api-server dependency count` +- Follow-up PR URL: N/A +- Reply URL: + +### F17 - Diagram draws an undeclared external edge + +- PR number: 2462 +- Source review ID: 5439725107 +- Reviewer finding ID: F9 +- Source URL: +- Concern: The diagram draws 154 edges, including `server-lib --> net-prim`, which no workspace manifest declares, while its prose and AC5 describe 153 manifest edges. +- Solution: The prose now says 153 manifest edges plus one external-to-external edge drawn for context, and the AC5 evidence row says "153 workspace edges" and names the extra edge. +- Current-tree verification: `docs/media/packages/dependencies-workspace-packages.md` prose and the AC5 row in `docs/issues/open/2446-1669-establish-baseline-analysis/ISSUE.md` inspected; MV3 (which excludes `server-lib` edges) reports 153/153. +- Resolution reference: `docs(packages): [#2446] state the diagram's external-to-external edge` +- Follow-up PR URL: N/A +- Reply URL: + +### F18 - AC1 qualification only in the evidence + +- PR number: 2462 +- Source review ID: 5439725107 +- Reviewer finding ID: F10 +- Source URL: +- Concern: Re-raises F8. +- Solution: Fixed by the F8 commit. +- Current-tree verification: AC1 in `docs/issues/open/2446-1669-establish-baseline-analysis/ISSUE.md` inspected as in F8. +- Resolution reference: `docs(issues): [#2446] state AC1's scope in the criterion itself` +- Follow-up PR URL: N/A +- Reply URL: + +### F19 - Report links the open-spec path + +- PR number: 2462 +- Source review ID: 5439725107 +- Reviewer finding ID: F11 +- Source URL: +- Concern: Re-raises F6. +- Solution: Fixed by the F6 commit. +- Current-tree verification: `docs/issues/open/1669-overhaul-packages/workspace-coupling-report-2026-10-06.md` frontmatter inspected as in F6. +- Resolution reference: `docs(issues): [#2446] reference issue #2446 instead of its open-spec path` +- Follow-up PR URL: N/A +- Reply URL: + +### F20 - Stamps and logs stop before later edits + +- PR number: 2462 +- Source review ID: 5440778746 +- Reviewer finding ID: F12 +- Source URL: +- Concern: The spec's stamp and Progress Log stopped at the 08:36 UTC AC1 entry, though later commits rewrote its AC2 (08:56) and AC5 (09:11) evidence rows; the three drafts' stamps and logs predate the 09:25 completion-review edit. +- Solution: Backfilled Progress Log entries at the commits' author times in the spec and the three drafts, each saying when it was backfilled, and moved the four `last-updated-utc` stamps past them. +- Current-tree verification: Author times of the AC2, AC5 and completion-review commits read from `git log`; the Progress Logs and stamps in `docs/issues/open/2446-1669-establish-baseline-analysis/ISSUE.md` and the three drafts inspected; pre-commit passed. +- Resolution reference: `docs(issues): [#2446] log the AC2, AC5 and completion-review edits` +- Follow-up PR URL: N/A +- Reply URL: + +### F21 - Coupling-tool draft says finding 3 lists four edges + +- PR number: 2462 +- Source review ID: 5440778746 +- Reviewer finding ID: F14 +- Source URL: +- Concern: The draft said finding 3 "listed the four normal edges", but finding 3 has listed five since the dev-edge fix. +- Solution: The sentence now says finding 3 "now lists all five". The evidence file's R1 conclusion is a dated record and stays. +- Current-tree verification: Finding 3 in the 2026-10-06 report and the sentence after the edge table in `docs/issues/drafts/1669-coupling-tool-resolve-lib-names-and-renames/ISSUE.md` inspected. +- Resolution reference: `docs(issues): [#2446] say finding 3 lists all five edges in the coupling-tool draft` +- Follow-up PR URL: N/A +- Reply URL: + +### F22 - F8 Solution misstates AC1 + +- PR number: 2462 +- Source review ID: 5440778746 +- Reviewer finding ID: F15 +- Source URL: +- Concern: The F8 Solution said AC1 requires the generated sections to reproduce; AC1 only limits the no-mention requirement to the generated sections, and reproducibility is MV2's criterion. F18 inherits the cell. +- Solution: F8's Solution now says AC1 limits the no-mention requirement to the generated sections and lets the hand-written Observations name `rest-api-core`; its verification now checks that claim. +- Current-tree verification: AC1 in `docs/issues/open/2446-1669-establish-baseline-analysis/ISSUE.md` inspected; `rest-api-core` appears in the 2026-10-06 report only at lines 1163 and 1174, after `## Observations` at line 1127. +- Resolution reference: `docs(pr-reviews): [#2446] state what AC1 limits in the F8 audit row` +- Follow-up PR URL: N/A +- Reply URL: + +## Processing Log + +- 2026-10-06 17:12 UTC - Copilot review 5432054524 posted eight inline findings, F1 to F8, with its own IDs F1 to F8. +- 2026-10-07 08:36 UTC - Human review 5439725107 (da2ce7) requested changes with eleven inline findings, his F1 to F11. They collide with the Copilot IDs, so they are recorded as F9 to F19 with the original ID in "Reviewer finding ID"; eight re-raise Copilot findings. +- 2026-10-07 09:45 UTC - Fixed all findings in one commit per concern, rebased onto the latest `develop`, confirmed the report and diagram still reproduce, pushed once after the pre-push suite passed, and replied on all 19 threads before recording them here. +- 2026-10-07 10:10 UTC - Human review 5440778746 (da2ce7, round 3) requested changes: it confirmed F9 to F19 and the record, restated two Nits from a round-2 review that was never posted (his F12 and F14, recorded as F20 and F21), and raised one Minor on this record (his F15, recorded as F22). His round-2 F13 (missing audit record) had no thread and was fixed by the record itself. +- 2026-10-07 13:08 UTC - Fixed F20 to F22 in one commit each, rebased onto the latest `develop` (resolved two EPIC.md conflicts, keeping both sides), confirmed the report and diagram still reproduce, pushed once after the pre-push suite passed, and replied on the three threads before recording them here. + +## Completion Rules + +- Re-derive the reply claim against the current tree before replying or resolving a thread. +- Reply on every resolvable thread before resolving it. +- For an outdated thread whose concern was fixed, record `Disposition=FIXED` and + `Thread state=RESOLVED`, even if GitHub marks the thread outdated after the push. For a + duplicate, superseded, or no-change in-PR thread, reply exactly + `Superseded by : .`, record `Disposition=NO_ACTION` and + `Thread state=SUPERSEDED`, then resolve it. A post-merge `NO_ACTION` requires maintainer + approval to decline the follow-up work. +- A consolidated PR conversation response may cover multiple review rounds only when it names + every review ID and every finding ID with its disposition and resolution reference. Record its + durable URL in each related row. +- Cite a fix by its unique Conventional Commit subject or durable reply URL, never by a branch SHA + that can change after a rebase. +- Refresh review threads using GraphQL and confirm that no unresolved actionable thread remains.