From cb05c02ed38bcbb1f061bb0adb4c10da56865d72 Mon Sep 17 00:00:00 2001 From: Jose Celano Date: Wed, 22 Jul 2026 09:43:55 +0100 Subject: [PATCH 01/19] docs(issues): add project dictionary formatter specification --- .../EPIC.md | 12 +- ...automatically-format-project-dictionary.md | 154 ++++++++++++++++++ 2 files changed, 164 insertions(+), 2 deletions(-) create mode 100644 docs/issues/open/2019-automatically-format-project-dictionary.md diff --git a/docs/issues/open/2003-overhaul-guardrails-and-automation/EPIC.md b/docs/issues/open/2003-overhaul-guardrails-and-automation/EPIC.md index d668a7360..a13f73279 100644 --- a/docs/issues/open/2003-overhaul-guardrails-and-automation/EPIC.md +++ b/docs/issues/open/2003-overhaul-guardrails-and-automation/EPIC.md @@ -5,7 +5,7 @@ status: planned github-issue: 2003 spec-path: docs/issues/open/2003-overhaul-guardrails-and-automation/EPIC.md epic-owner: josecelano -last-updated-utc: 2026-07-20 00:00 +last-updated-utc: 2026-07-22 00:00 semantic-links: skill-links: - create-issue @@ -161,6 +161,11 @@ build actions needed by its checks. - Add a required deterministic check that verifies `project-words.txt` uses one documented ordering rule and contains no duplicate entries. Decide its package and execution tier through the EPIC design rather than coupling it to the tracker library. +- Permit the narrowly scoped interim formatter described by + [`automatically-format-project-dictionary.md`](../../drafts/automatically-format-project-dictionary.md). + It supplies immediate developer feedback but does not select the EPIC's long-term architecture, + execution tier, or check/action contract, and may be replaced or refactored after the design + decision. - Re-evaluate #1843, #1774, and #1768 against the resulting evidence and recommend whether each should proceed unchanged, be re-scoped, be split, or be superseded. - Present the evidence and options for maintainer review before selecting a full design. @@ -174,7 +179,8 @@ build actions needed by its checks. ### Out of Scope - Implementing, migrating, or consolidating automation tools or checks before the design decision - and implementation subissues are approved. + and implementation subissues are approved, except for the explicitly approved interim project + dictionary formatter linked in Scope. - Prescribing a `workspace-tools` crate, a single Rust binary, Bash scripts, a task runner, or any other tool shape before alternatives are compared and reviewed. - Prototyping architecture tests before the research identifies a question that requires a @@ -317,6 +323,8 @@ For each completed subissue in this EPIC, the default completion policy is: - 2026-07-20 00:00 UTC - josecelano - Approved the draft EPIC and its supporting artifacts - 2026-07-20 00:00 UTC - GitHub Operator - Created EPIC #2003 and moved the approved local specification to `docs/issues/open/2003-overhaul-guardrails-and-automation/` +- 2026-07-22 00:00 UTC - josecelano - Approved a narrowly scoped interim project dictionary + formatter; it may be replaced or refactored after the EPIC design decision ## Acceptance Criteria diff --git a/docs/issues/open/2019-automatically-format-project-dictionary.md b/docs/issues/open/2019-automatically-format-project-dictionary.md new file mode 100644 index 000000000..dd7150fcf --- /dev/null +++ b/docs/issues/open/2019-automatically-format-project-dictionary.md @@ -0,0 +1,154 @@ +--- +doc-type: issue +issue-type: enhancement +status: open +priority: p2 +github-issue: 2019 +spec-path: docs/issues/open/2019-automatically-format-project-dictionary.md +branch: "2019-automatically-format-project-dictionary" +related-pr: null +last-updated-utc: 2026-07-22 00:00 +semantic-links: + skill-links: + - create-issue + related-artifacts: + - .github/skills/dev/planning/create-issue/SKILL.md + - contrib/dev-tools/git/format-project-words.sh + - contrib/dev-tools/git/hooks/pre-commit.sh + - docs/issues/open/2003-overhaul-guardrails-and-automation/EPIC.md + - project-words.txt +--- + + + +# Issue #2019 - Automatically format the project dictionary + +## Goal + +Make `project-words.txt` consistently sorted and free of exact duplicate entries without requiring contributors or AI agents to edit its ordering manually. + +## Background + +`project-words.txt` is the custom cspell dictionary. Its intended alphabetical ordering is documented but not enforced by `linter all` or the pre-commit hook, so pull-request reviews repeatedly identify unsorted entries. This issue delivers a small, immediately useful interim formatter while EPIC #2003 evaluates the long-term automation and guardrail architecture. It must not constrain that future design: the EPIC may replace or refactor this implementation after its design decision. + +## Scope + +### In Scope + +- Add `contrib/dev-tools/git/format-project-words.sh`, an independently runnable formatter that applies `LC_ALL=C sort --unique` to `project-words.txt`. +- Invoke the formatter from the pre-commit hook. +- Detect when formatting changes the dictionary and abort the commit with clear restaging instructions. +- Document the automatic behavior and manual formatting command in the relevant pre-commit workflow guidance. +- Ensure the committed dictionary is formatted by the new command. + +### Out of Scope + +- Changing the cspell configuration or its accepted dictionaries. +- Case-insensitive de-duplication or normalization of dictionary entries. +- Reordering unrelated project files. +- Selecting the long-term repository automation or guardrail architecture; that decision belongs to EPIC #2003. +- Treating this interim script as a constraint on EPIC #2003's future implementation. + +## Implementation Plan + +Status values: `TODO`, `IN_PROGRESS`, `BLOCKED`, `DONE`. + +| ID | Status | Task | Notes / Expected Output | +| --- | ------ | ------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| T1 | TODO | Add an independently runnable dictionary formatter | `contrib/dev-tools/git/format-project-words.sh` applies `LC_ALL=C sort --unique` to `project-words.txt` and reports whether it changed the file. | +| T2 | TODO | Invoke the formatter from the pre-commit hook | The hook calls the formatter before verification steps and retains its role as orchestration scaffolding. | +| T3 | TODO | Abort when the formatter changes the dictionary | The commit stops and tells the contributor to stage `project-words.txt` and retry, preventing a stale index from being committed. | +| T4 | TODO | Update workflow documentation | The documentation describes automatic formatting, the helper command, and the interim relationship to EPIC #2003; it no longer requires manual alphabetical-order review. | +| T5 | TODO | Add or update automated tests for formatter and hook behavior | Tests cover an already formatted dictionary and a dictionary changed by formatting. | +| T6 | TODO | Format and verify the dictionary | The checked-in file is sorted by the chosen command and all required checks pass. | + +## Progress Tracking + +### Workflow Checkpoints + +- [x] Spec drafted in `docs/issues/drafts/` +- [x] Spec reviewed and approved by user/maintainer +- [x] GitHub issue created and issue number added to this spec +- [ ] (Optional, recommended for complex issues) Spec-only PR merged into `develop` before implementation +- [ ] Implementation completed +- [ ] Automatic verification completed (`linter all`, relevant tests, and any pre-push checks) +- [ ] Manual verification scenarios executed and recorded (status + evidence) +- [ ] Acceptance criteria reviewed after implementation and updated with evidence +- [ ] Reviewer validated acceptance criteria and updated checkboxes +- [ ] Committer verified spec progress is up to date before commit +- [ ] Issue closed and spec moved from `docs/issues/open/` to `docs/issues/closed/` + +### Progress Log + +Append one line per meaningful update. + +- 2026-07-22 00:00 UTC - GitHub Copilot - Created draft specification for review - `docs/issues/drafts/automatically-format-project-dictionary.md` +- 2026-07-22 00:00 UTC - josecelano - Approved an interim standalone formatter and hook integration while EPIC #2003 determines the long-term automation design - draft updated +- 2026-07-22 00:00 UTC - GitHub Operator - Created issue #2019 - https://github.com/torrust/torrust-tracker/issues/2019 + +## Acceptance Criteria + +- [ ] AC1: `contrib/dev-tools/git/format-project-words.sh` applies `LC_ALL=C sort --unique` to `project-words.txt`, preserving distinct entries that differ only by case. +- [ ] AC2: If formatting modifies `project-words.txt`, the pre-commit hook exits non-zero and clearly instructs the contributor to stage the modified file and retry the commit. +- [ ] AC3: If formatting does not modify `project-words.txt`, the pre-commit hook continues with its existing verification steps. +- [ ] AC4: Automated coverage verifies both unchanged and changed formatter and hook behavior. +- [ ] AC5: The workflow documentation describes the automatic behavior and standalone formatter command. +- [ ] AC6: The implementation is documented as an interim measure related to EPIC #2003 and can be replaced or refactored by its future design. +- [ ] `linter all` exits with code `0`. +- [ ] Relevant tests pass. +- [ ] Manual verification scenarios are executed and documented (status + evidence). +- [ ] Acceptance criteria are re-reviewed after implementation and reflect actual behavior. +- [ ] Documentation is updated when behavior/workflow changes. + +## Verification Plan + +Define verification before implementation starts and execute it before closing the issue. + +### Automatic Checks + +- `linter all` +- Focused tests for the pre-commit hook behavior +- `./contrib/dev-tools/git/format-project-words.sh` +- `TORRUST_GIT_HOOKS_LOG_DIR=.tmp ./contrib/dev-tools/git/hooks/pre-commit.sh` +- Pre-push checks when applicable + +### Manual Verification Scenarios + +Status values: `TODO`, `IN_PROGRESS`, `DONE`, `FAILED`, `BLOCKED`. + +| ID | Scenario | Command/Steps | Expected Result | Status | Evidence | +| --- | ----------------------------- | --------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- | ------ | ----------------------- | +| M1 | Dictionary needs formatting | Temporarily add unsorted and duplicate exact entries in an isolated Git checkout, then run the pre-commit hook. | The hook rewrites `project-words.txt`, exits non-zero, and instructs the user to stage the file and retry. | TODO | Pending implementation. | +| M2 | Dictionary already formatted | Run the pre-commit hook with the formatted tracked dictionary. | The formatter leaves the file unchanged and the hook continues to its existing checks. | TODO | Pending implementation. | +| M3 | Case variants remain distinct | Run the standalone formatter against a disposable dictionary containing otherwise identical case variants. | Both variants remain; only exact duplicate lines are removed. | TODO | Pending implementation. | + +Notes: + +- Manual verification is mandatory even when automated tests pass. +- If a scenario fails, record the failure and diagnosis in the progress log before proceeding. + +### Acceptance Verification + +| AC ID | Status (`TODO`/`DONE`) | Evidence | +| ----- | ---------------------- | ----------------------- | +| AC1 | TODO | Pending implementation. | +| AC2 | TODO | Pending implementation. | +| AC3 | TODO | Pending implementation. | +| AC4 | TODO | Pending implementation. | +| AC5 | TODO | Pending implementation. | +| AC6 | TODO | Pending implementation. | + +## Risks and Trade-offs + +- A hook that changes a working-tree file after Git has prepared the index could otherwise allow the unsorted staged version to be committed. The hook must abort after a formatting change so the corrected file can be staged deliberately. +- Locale-sensitive sorting would yield inconsistent output across machines. Setting `LC_ALL=C` makes the ordering deterministic. +- Case-insensitive de-duplication could delete meaningful proper-name or acronym variants. Exact duplicate removal only avoids that data loss. + +## References + +- `project-words.txt` +- `cspell.json` +- `contrib/dev-tools/git/format-project-words.sh` +- `contrib/dev-tools/git/hooks/pre-commit.sh` +- `docs/issues/open/2003-overhaul-guardrails-and-automation/EPIC.md` +- `.github/skills/dev/git-workflow/run-pre-commit-checks/SKILL.md` From 319ef20789556f1b3ce926a7196092470ac8fe6b Mon Sep 17 00:00:00 2001 From: Jose Celano Date: Wed, 22 Jul 2026 09:53:02 +0100 Subject: [PATCH 02/19] feat(git): format project dictionary before commits --- .../dev/git-workflow/commit-changes/SKILL.md | 6 +- .../dev/git-workflow/run-linters/SKILL.md | 5 +- .../run-linters/references/linters.md | 4 +- .../run-pre-commit-checks/SKILL.md | 21 +++- contrib/dev-tools/git/format-project-words.sh | 35 ++++++ contrib/dev-tools/git/hooks/pre-commit.sh | 7 ++ .../git/tests/test-format-project-words.sh | 119 ++++++++++++++++++ .../EPIC.md | 2 +- ...automatically-format-project-dictionary.md | 31 ++--- 9 files changed, 206 insertions(+), 24 deletions(-) create mode 100755 contrib/dev-tools/git/format-project-words.sh create mode 100755 contrib/dev-tools/git/tests/test-format-project-words.sh diff --git a/.github/skills/dev/git-workflow/commit-changes/SKILL.md b/.github/skills/dev/git-workflow/commit-changes/SKILL.md index e76609e30..34e1164ba 100644 --- a/.github/skills/dev/git-workflow/commit-changes/SKILL.md +++ b/.github/skills/dev/git-workflow/commit-changes/SKILL.md @@ -128,8 +128,10 @@ Verify these by hand before committing: `docs/` pages reflect the change - **`AGENTS.md` updated**: if architecture, package structure, or key workflows changed, the relevant `AGENTS.md` file is updated -- **New technical terms added to `project-words.txt`**: any new jargon or identifiers that - cspell does not know about are added alphabetically +- **New technical terms added to `project-words.txt`**: run + `./contrib/dev-tools/git/format-project-words.sh` after adding jargon or identifiers that cspell + does not know. The pre-commit hook does this automatically, aborting for deliberate restaging if + it changes the dictionary. ### Debugging a Failing Run diff --git a/.github/skills/dev/git-workflow/run-linters/SKILL.md b/.github/skills/dev/git-workflow/run-linters/SKILL.md index 5b94b6f0d..0f817c55c 100644 --- a/.github/skills/dev/git-workflow/run-linters/SKILL.md +++ b/.github/skills/dev/git-workflow/run-linters/SKILL.md @@ -125,8 +125,9 @@ taplo fmt **/*.toml # Auto-fix TOML formatting ### Spell Check Errors (cspell) -For legitimate technical terms not in dictionaries, add them to `project-words.txt` -(alphabetical order, one per line). +For legitimate technical terms not in dictionaries, add them to `project-words.txt` (one per line) +and run `./contrib/dev-tools/git/format-project-words.sh`. The pre-commit hook runs the formatter +automatically and requests restaging if it changes the dictionary. ### Shell Script Errors (shellcheck) diff --git a/.github/skills/dev/git-workflow/run-linters/references/linters.md b/.github/skills/dev/git-workflow/run-linters/references/linters.md index 40b3ee5fb..c3a724e81 100644 --- a/.github/skills/dev/git-workflow/run-linters/references/linters.md +++ b/.github/skills/dev/git-workflow/run-linters/references/linters.md @@ -56,7 +56,9 @@ Key formatting settings: **Dictionary**: `project-words.txt` **Run**: `linter cspell` -Add technical terms to `project-words.txt` (alphabetical order, one per line). +Add technical terms to `project-words.txt` (one per line), then run +`./contrib/dev-tools/git/format-project-words.sh`. The formatter uses `LC_ALL=C sort --unique`; +the pre-commit hook runs it automatically and requests restaging if it changes the dictionary. ## Configuration Linters diff --git a/.github/skills/dev/git-workflow/run-pre-commit-checks/SKILL.md b/.github/skills/dev/git-workflow/run-pre-commit-checks/SKILL.md index b53f4df93..9f9348836 100644 --- a/.github/skills/dev/git-workflow/run-pre-commit-checks/SKILL.md +++ b/.github/skills/dev/git-workflow/run-pre-commit-checks/SKILL.md @@ -47,9 +47,21 @@ TORRUST_GIT_HOOKS_LOG_DIR=.tmp ./contrib/dev-tools/git/hooks/pre-commit.sh The script runs these steps in order: -1. `cargo machete` - unused dependency check -2. `linter all` - all linters (markdown, YAML, TOML, clippy, rustfmt, shellcheck, cspell) -3. `cargo test --doc --workspace` - documentation tests +1. `./contrib/dev-tools/git/format-project-words.sh` - formats `project-words.txt` with + `LC_ALL=C sort --unique` +2. `cargo machete` - unused dependency check +3. `linter all` - all linters (markdown, YAML, TOML, clippy, rustfmt, shellcheck, cspell) +4. `cargo test --doc --workspace` - documentation tests + +If the formatter changes the dictionary, the hook exits non-zero before the verification steps. +Stage `project-words.txt` and retry the commit. Run the formatter independently with: + +```bash +./contrib/dev-tools/git/format-project-words.sh +``` + +This is an interim action related to EPIC #2003 and may be replaced or refactored after its +automation design decision. ## Output Modes @@ -117,7 +129,8 @@ Verify these by hand before committing: - **Self-review the diff**: read through `git diff --staged` for debug artifacts or unintended changes - **Documentation updated**: if public API or behaviour changed, doc comments and `docs/` pages reflect it - **`AGENTS.md` updated**: if architecture or key workflows changed, the relevant `AGENTS.md` is updated -- **New technical terms in `project-words.txt`**: new jargon added alphabetically +- **New technical terms in `project-words.txt`**: run the formatter after adding new jargon; the + hook will also format it automatically and request restaging when needed - **Branch name validation**: if the branch uses an issue-number prefix (e.g. `42-some-description`), verify that `docs/issues/open/` contains a matching spec file or directory. This prevents committing under a non-existent, closed, or wrong issue number. diff --git a/contrib/dev-tools/git/format-project-words.sh b/contrib/dev-tools/git/format-project-words.sh new file mode 100755 index 000000000..1d8493010 --- /dev/null +++ b/contrib/dev-tools/git/format-project-words.sh @@ -0,0 +1,35 @@ +#!/usr/bin/env bash +# Format the repository cspell dictionary with deterministic ordering and exact de-duplication. + +set -uo pipefail + +SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd) +PROJECT_ROOT=$(cd -- "${SCRIPT_DIR}/../../.." && pwd) +DICTIONARY_PATH="${PROJECT_ROOT}/project-words.txt" + +if [[ ! -f "${DICTIONARY_PATH}" ]]; then + printf 'Error: project dictionary not found: %s\n' "${DICTIONARY_PATH}" >&2 + exit 2 +fi + +temporary_dictionary=$(mktemp) +trap 'rm -f "${temporary_dictionary}"' EXIT + +if ! LC_ALL=C sort --unique "${DICTIONARY_PATH}" >"${temporary_dictionary}"; then + printf 'Error: failed to format project dictionary: %s\n' "${DICTIONARY_PATH}" >&2 + exit 2 +fi + +if cmp --silent "${DICTIONARY_PATH}" "${temporary_dictionary}"; then + printf 'project-words.txt is already formatted.\n' + exit 0 +fi + +if ! cat "${temporary_dictionary}" >"${DICTIONARY_PATH}"; then + printf 'Error: failed to update project dictionary: %s\n' "${DICTIONARY_PATH}" >&2 + exit 2 +fi + +printf 'Formatted project-words.txt with LC_ALL=C sort --unique.\n' +printf "Stage 'project-words.txt' and retry the commit.\n" +exit 1 \ No newline at end of file diff --git a/contrib/dev-tools/git/hooks/pre-commit.sh b/contrib/dev-tools/git/hooks/pre-commit.sh index 477c46c19..784aa3899 100755 --- a/contrib/dev-tools/git/hooks/pre-commit.sh +++ b/contrib/dev-tools/git/hooks/pre-commit.sh @@ -9,6 +9,9 @@ # AI agents: set a per-command timeout of at least 3 minutes before invoking this script. # # All steps must pass (exit 0) before committing. +# The formatter is an intentionally small interim action while EPIC #2003 determines +# the repository's long-term automation architecture. It exits 1 after rewriting the +# dictionary so this hook aborts and the contributor can deliberately stage the change. # # TODO: Implement branch-name validation in the Rust git-hooks binary (#1843). # When the branch uses an issue-number prefix (e.g. "42-some-description"), verify that @@ -24,6 +27,7 @@ set -uo pipefail # Each step: "description|command" declare -a STEPS=( + "Formatting project dictionary|./contrib/dev-tools/git/format-project-words.sh" "Checking for unused dependencies (cargo machete --with-metadata)|cargo machete --with-metadata" "Checking workspace layer boundary bans (cargo deny check bans)|cargo deny check bans" "Running all linters|linter all" @@ -364,6 +368,9 @@ fi echo echo "==========================================" echo "FAILED: Pre-commit checks failed!" +if [[ "${failed_step_name}" == "Formatting project dictionary" ]]; then + echo "The formatter changed project-words.txt. Stage 'project-words.txt' and retry the commit." +fi echo "Fix the errors above before committing." echo "==========================================" exit 1 diff --git a/contrib/dev-tools/git/tests/test-format-project-words.sh b/contrib/dev-tools/git/tests/test-format-project-words.sh new file mode 100755 index 000000000..aff9361fe --- /dev/null +++ b/contrib/dev-tools/git/tests/test-format-project-words.sh @@ -0,0 +1,119 @@ +#!/usr/bin/env bash +# Integration tests for the project dictionary formatter and pre-commit orchestration. + +set -uo pipefail + +PROJECT_ROOT=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/../../../.." && pwd) +TEST_DIRECTORY=$(mktemp -d) +trap 'rm -rf "${TEST_DIRECTORY}"' EXIT + +create_fixture() { + local fixture_name=$1 + local fixture_root="${TEST_DIRECTORY}/${fixture_name}" + + mkdir -p "${fixture_root}/contrib/dev-tools/git/hooks" "${fixture_root}/bin" "${fixture_root}/logs" + cp "${PROJECT_ROOT}/contrib/dev-tools/git/format-project-words.sh" "${fixture_root}/contrib/dev-tools/git/" + cp "${PROJECT_ROOT}/contrib/dev-tools/git/hooks/pre-commit.sh" "${fixture_root}/contrib/dev-tools/git/hooks/" + chmod +x \ + "${fixture_root}/contrib/dev-tools/git/format-project-words.sh" \ + "${fixture_root}/contrib/dev-tools/git/hooks/pre-commit.sh" + + printf '%s\n' "${fixture_root}" +} + +create_successful_command_stubs() { + local fixture_root=$1 + + cat >"${fixture_root}/bin/cargo" <<'EOF' +#!/usr/bin/env bash +printf 'cargo %s\n' "$*" >>"${TEST_COMMAND_LOG}" +EOF + cat >"${fixture_root}/bin/linter" <<'EOF' +#!/usr/bin/env bash +printf 'linter %s\n' "$*" >>"${TEST_COMMAND_LOG}" +EOF + chmod +x "${fixture_root}/bin/cargo" "${fixture_root}/bin/linter" +} + +it_should_sort_and_remove_exact_duplicates_when_dictionary_requires_formatting() { + # Arrange + local fixture_root + fixture_root=$(create_fixture "formatter-changed") + printf 'zebra\nAlpha\nalpha\nAlpha\n' >"${fixture_root}/project-words.txt" + + # Act + if "${fixture_root}/contrib/dev-tools/git/format-project-words.sh" >"${fixture_root}/formatter-output.txt" 2>&1; then + printf 'Expected formatter to report a changed dictionary.\n' >&2 + return 1 + fi + + # Assert + diff --unified "${fixture_root}/project-words.txt" <(printf 'Alpha\nalpha\nzebra\n') + grep --fixed-strings --quiet 'Formatted project-words.txt with LC_ALL=C sort --unique.' "${fixture_root}/formatter-output.txt" +} + +it_should_report_success_when_dictionary_is_already_formatted() { + # Arrange + local fixture_root + fixture_root=$(create_fixture "formatter-unchanged") + printf 'Alpha\nalpha\nzebra\n' >"${fixture_root}/project-words.txt" + + # Act + "${fixture_root}/contrib/dev-tools/git/format-project-words.sh" >"${fixture_root}/formatter-output.txt" + + # Assert + grep --fixed-strings --quiet 'project-words.txt is already formatted.' "${fixture_root}/formatter-output.txt" +} + +it_should_abort_pre_commit_and_request_restaging_when_dictionary_is_formatted() { + # Arrange + local fixture_root + fixture_root=$(create_fixture "hook-changed") + printf 'zebra\nAlpha\nAlpha\n' >"${fixture_root}/project-words.txt" + create_successful_command_stubs "${fixture_root}" + + # Act + if ( + cd "${fixture_root}" || exit + PATH="${fixture_root}/bin:${PATH}" \ + TEST_COMMAND_LOG="${fixture_root}/commands.log" \ + TORRUST_GIT_HOOKS_LOG_DIR="${fixture_root}/logs" \ + ./contrib/dev-tools/git/hooks/pre-commit.sh >"${fixture_root}/hook-output.txt" 2>&1 + ); then + printf 'Expected pre-commit hook to abort after formatting the dictionary.\n' >&2 + return 1 + fi + + # Assert + diff --unified "${fixture_root}/project-words.txt" <(printf 'Alpha\nzebra\n') + grep --fixed-strings --quiet "stage 'project-words.txt' and retry the commit" "${fixture_root}/hook-output.txt" + [[ ! -e "${fixture_root}/commands.log" ]] +} + +it_should_continue_pre_commit_checks_when_dictionary_is_already_formatted() { + # Arrange + local fixture_root + fixture_root=$(create_fixture "hook-unchanged") + printf 'Alpha\nzebra\n' >"${fixture_root}/project-words.txt" + create_successful_command_stubs "${fixture_root}" + + # Act + ( + cd "${fixture_root}" || exit + PATH="${fixture_root}/bin:${PATH}" \ + TEST_COMMAND_LOG="${fixture_root}/commands.log" \ + TORRUST_GIT_HOOKS_LOG_DIR="${fixture_root}/logs" \ + ./contrib/dev-tools/git/hooks/pre-commit.sh >"${fixture_root}/hook-output.txt" + ) + + # Assert + [[ $(wc -l <"${fixture_root}/commands.log") -eq 4 ]] + grep --fixed-strings --quiet 'SUCCESS: All pre-commit checks passed!' "${fixture_root}/hook-output.txt" +} + +it_should_sort_and_remove_exact_duplicates_when_dictionary_requires_formatting +it_should_report_success_when_dictionary_is_already_formatted +it_should_abort_pre_commit_and_request_restaging_when_dictionary_is_formatted +it_should_continue_pre_commit_checks_when_dictionary_is_already_formatted + +printf 'All formatter and pre-commit hook tests passed.\n' \ No newline at end of file diff --git a/docs/issues/open/2003-overhaul-guardrails-and-automation/EPIC.md b/docs/issues/open/2003-overhaul-guardrails-and-automation/EPIC.md index a13f73279..6cca5d79b 100644 --- a/docs/issues/open/2003-overhaul-guardrails-and-automation/EPIC.md +++ b/docs/issues/open/2003-overhaul-guardrails-and-automation/EPIC.md @@ -162,7 +162,7 @@ build actions needed by its checks. ordering rule and contains no duplicate entries. Decide its package and execution tier through the EPIC design rather than coupling it to the tracker library. - Permit the narrowly scoped interim formatter described by - [`automatically-format-project-dictionary.md`](../../drafts/automatically-format-project-dictionary.md). + [`2019-automatically-format-project-dictionary.md`](../2019-automatically-format-project-dictionary.md). It supplies immediate developer feedback but does not select the EPIC's long-term architecture, execution tier, or check/action contract, and may be replaced or refactored after the design decision. diff --git a/docs/issues/open/2019-automatically-format-project-dictionary.md b/docs/issues/open/2019-automatically-format-project-dictionary.md index dd7150fcf..e1d1ad9a6 100644 --- a/docs/issues/open/2019-automatically-format-project-dictionary.md +++ b/docs/issues/open/2019-automatically-format-project-dictionary.md @@ -55,12 +55,12 @@ Status values: `TODO`, `IN_PROGRESS`, `BLOCKED`, `DONE`. | ID | Status | Task | Notes / Expected Output | | --- | ------ | ------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| T1 | TODO | Add an independently runnable dictionary formatter | `contrib/dev-tools/git/format-project-words.sh` applies `LC_ALL=C sort --unique` to `project-words.txt` and reports whether it changed the file. | -| T2 | TODO | Invoke the formatter from the pre-commit hook | The hook calls the formatter before verification steps and retains its role as orchestration scaffolding. | -| T3 | TODO | Abort when the formatter changes the dictionary | The commit stops and tells the contributor to stage `project-words.txt` and retry, preventing a stale index from being committed. | -| T4 | TODO | Update workflow documentation | The documentation describes automatic formatting, the helper command, and the interim relationship to EPIC #2003; it no longer requires manual alphabetical-order review. | -| T5 | TODO | Add or update automated tests for formatter and hook behavior | Tests cover an already formatted dictionary and a dictionary changed by formatting. | -| T6 | TODO | Format and verify the dictionary | The checked-in file is sorted by the chosen command and all required checks pass. | +| T1 | DONE | Add an independently runnable dictionary formatter | `contrib/dev-tools/git/format-project-words.sh` applies `LC_ALL=C sort --unique` to `project-words.txt` and reports whether it changed the file. | +| T2 | DONE | Invoke the formatter from the pre-commit hook | The hook calls the formatter before verification steps and retains its role as orchestration scaffolding. | +| T3 | DONE | Abort when the formatter changes the dictionary | The commit stops and tells the contributor to stage `project-words.txt` and retry, preventing a stale index from being committed. | +| T4 | DONE | Update workflow documentation | The documentation describes automatic formatting, the helper command, and the interim relationship to EPIC #2003; it no longer requires manual alphabetical-order review. | +| T5 | DONE | Add or update automated tests for formatter and hook behavior | `contrib/dev-tools/git/tests/test-format-project-words.sh` covers formatter and hook behavior for changed and unchanged dictionaries. | +| T6 | DONE | Format and verify the dictionary | The checked-in file is formatted; focused tests and the required pre-commit validation gate pass. | ## Progress Tracking @@ -70,9 +70,9 @@ Status values: `TODO`, `IN_PROGRESS`, `BLOCKED`, `DONE`. - [x] Spec reviewed and approved by user/maintainer - [x] GitHub issue created and issue number added to this spec - [ ] (Optional, recommended for complex issues) Spec-only PR merged into `develop` before implementation -- [ ] Implementation completed -- [ ] Automatic verification completed (`linter all`, relevant tests, and any pre-push checks) -- [ ] Manual verification scenarios executed and recorded (status + evidence) +- [x] Implementation completed +- [x] Automatic verification completed (`linter all`, relevant tests, and any pre-push checks) +- [x] Manual verification scenarios executed and recorded (status + evidence) - [ ] Acceptance criteria reviewed after implementation and updated with evidence - [ ] Reviewer validated acceptance criteria and updated checkboxes - [ ] Committer verified spec progress is up to date before commit @@ -85,6 +85,9 @@ Append one line per meaningful update. - 2026-07-22 00:00 UTC - GitHub Copilot - Created draft specification for review - `docs/issues/drafts/automatically-format-project-dictionary.md` - 2026-07-22 00:00 UTC - josecelano - Approved an interim standalone formatter and hook integration while EPIC #2003 determines the long-term automation design - draft updated - 2026-07-22 00:00 UTC - GitHub Operator - Created issue #2019 - https://github.com/torrust/torrust-tracker/issues/2019 +- 2026-07-22 00:00 UTC - GitHub Copilot - Implemented the standalone formatter, pre-commit orchestration, focused shell tests, and synchronized workflow guidance; reviewed the linked `create-issue` skill with no process change required +- 2026-07-22 00:00 UTC - GitHub Copilot - Verified focused formatter and hook tests, the standalone formatter, and `TORRUST_GIT_HOOKS_LOG_DIR=.tmp ./contrib/dev-tools/git/hooks/pre-commit.sh --format=json`; all passed +- 2026-07-22 00:00 UTC - GitHub Copilot - Verified `TORRUST_GIT_HOOKS_LOG_DIR=.tmp ./contrib/dev-tools/git/hooks/pre-push.sh --format=json`; all nightly checks, documentation build, and stable workspace tests passed ## Acceptance Criteria @@ -116,11 +119,11 @@ Define verification before implementation starts and execute it before closing t Status values: `TODO`, `IN_PROGRESS`, `DONE`, `FAILED`, `BLOCKED`. -| ID | Scenario | Command/Steps | Expected Result | Status | Evidence | -| --- | ----------------------------- | --------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- | ------ | ----------------------- | -| M1 | Dictionary needs formatting | Temporarily add unsorted and duplicate exact entries in an isolated Git checkout, then run the pre-commit hook. | The hook rewrites `project-words.txt`, exits non-zero, and instructs the user to stage the file and retry. | TODO | Pending implementation. | -| M2 | Dictionary already formatted | Run the pre-commit hook with the formatted tracked dictionary. | The formatter leaves the file unchanged and the hook continues to its existing checks. | TODO | Pending implementation. | -| M3 | Case variants remain distinct | Run the standalone formatter against a disposable dictionary containing otherwise identical case variants. | Both variants remain; only exact duplicate lines are removed. | TODO | Pending implementation. | +| ID | Scenario | Command/Steps | Expected Result | Status | Evidence | +| --- | ----------------------------- | --------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------ | +| M1 | Dictionary needs formatting | Temporarily add unsorted and duplicate exact entries in an isolated Git checkout, then run the pre-commit hook. | The hook rewrites `project-words.txt`, exits non-zero, and instructs the user to stage the file and retry. | DONE | `test-format-project-words.sh`: `it_should_abort_pre_commit_and_request_restaging_when_dictionary_is_formatted`. | +| M2 | Dictionary already formatted | Run the pre-commit hook with the formatted tracked dictionary. | The formatter leaves the file unchanged and the hook continues to its existing checks. | DONE | `TORRUST_GIT_HOOKS_LOG_DIR=.tmp ./contrib/dev-tools/git/hooks/pre-commit.sh --format=json` passed its formatter and all four verification steps. | +| M3 | Case variants remain distinct | Run the standalone formatter against a disposable dictionary containing otherwise identical case variants. | Both variants remain; only exact duplicate lines are removed. | DONE | `test-format-project-words.sh`: `it_should_sort_and_remove_exact_duplicates_when_dictionary_requires_formatting`. | Notes: From aa2f856975ddea3ea9bc697cbae4c958ecad9ce7 Mon Sep 17 00:00:00 2001 From: Jose Celano Date: Wed, 22 Jul 2026 10:05:05 +0100 Subject: [PATCH 03/19] fix(git): address dictionary formatter review feedback --- .../run-pre-commit-checks/SKILL.md | 7 ++-- contrib/dev-tools/git/format-project-words.sh | 4 +- contrib/dev-tools/git/hooks/pre-commit.sh | 6 ++- .../git/tests/test-format-project-words.sh | 2 +- ...automatically-format-project-dictionary.md | 41 ++++++++++--------- 5 files changed, 33 insertions(+), 27 deletions(-) diff --git a/.github/skills/dev/git-workflow/run-pre-commit-checks/SKILL.md b/.github/skills/dev/git-workflow/run-pre-commit-checks/SKILL.md index 9f9348836..18893c8f0 100644 --- a/.github/skills/dev/git-workflow/run-pre-commit-checks/SKILL.md +++ b/.github/skills/dev/git-workflow/run-pre-commit-checks/SKILL.md @@ -49,9 +49,10 @@ The script runs these steps in order: 1. `./contrib/dev-tools/git/format-project-words.sh` - formats `project-words.txt` with `LC_ALL=C sort --unique` -2. `cargo machete` - unused dependency check -3. `linter all` - all linters (markdown, YAML, TOML, clippy, rustfmt, shellcheck, cspell) -4. `cargo test --doc --workspace` - documentation tests +2. `cargo machete --with-metadata` - unused dependency check +3. `cargo deny check bans` - workspace layer-boundary dependency check +4. `linter all` - all linters (markdown, YAML, TOML, clippy, rustfmt, shellcheck, cspell) +5. `cargo test --doc --workspace` - documentation tests If the formatter changes the dictionary, the hook exits non-zero before the verification steps. Stage `project-words.txt` and retry the commit. Run the formatter independently with: diff --git a/contrib/dev-tools/git/format-project-words.sh b/contrib/dev-tools/git/format-project-words.sh index 1d8493010..900319189 100755 --- a/contrib/dev-tools/git/format-project-words.sh +++ b/contrib/dev-tools/git/format-project-words.sh @@ -12,7 +12,7 @@ if [[ ! -f "${DICTIONARY_PATH}" ]]; then exit 2 fi -temporary_dictionary=$(mktemp) +temporary_dictionary=$(mktemp "${DICTIONARY_PATH}.XXXXXX") trap 'rm -f "${temporary_dictionary}"' EXIT if ! LC_ALL=C sort --unique "${DICTIONARY_PATH}" >"${temporary_dictionary}"; then @@ -25,7 +25,7 @@ if cmp --silent "${DICTIONARY_PATH}" "${temporary_dictionary}"; then exit 0 fi -if ! cat "${temporary_dictionary}" >"${DICTIONARY_PATH}"; then +if ! chmod --reference="${DICTIONARY_PATH}" "${temporary_dictionary}" || ! mv -- "${temporary_dictionary}" "${DICTIONARY_PATH}"; then printf 'Error: failed to update project dictionary: %s\n' "${DICTIONARY_PATH}" >&2 exit 2 fi diff --git a/contrib/dev-tools/git/hooks/pre-commit.sh b/contrib/dev-tools/git/hooks/pre-commit.sh index 784aa3899..c9ca6efcf 100755 --- a/contrib/dev-tools/git/hooks/pre-commit.sh +++ b/contrib/dev-tools/git/hooks/pre-commit.sh @@ -42,6 +42,7 @@ LOG_DIR="${TORRUST_GIT_HOOKS_LOG_DIR:-/tmp}" declare -a STEP_NAMES=() declare -a STEP_COMMANDS=() declare -a STEP_STATUSES=() +declare -a STEP_EXIT_CODES=() declare -a STEP_ELAPSED_SECONDS=() declare -a STEP_LOG_PATHS=() @@ -191,6 +192,7 @@ run_step() { STEP_NAMES+=("${description}") STEP_COMMANDS+=("${command}") + STEP_EXIT_CODES+=("${command_exit_code}") STEP_ELAPSED_SECONDS+=("${step_elapsed}") STEP_LOG_PATHS+=("${log_path}") @@ -333,6 +335,7 @@ TOTAL_STEPS=${#STEPS[@]} overall_status="pass" exit_code=0 failed_step_name="" +failed_step_exit_code=0 if [[ "${FORMAT}" == "text" ]]; then echo "Running pre-commit checks..." @@ -345,6 +348,7 @@ for i in "${!STEPS[@]}"; do overall_status="fail" exit_code=1 failed_step_name="${description}" + failed_step_exit_code=${STEP_EXIT_CODES[$(( ${#STEP_EXIT_CODES[@]} - 1 ))]} break fi done @@ -368,7 +372,7 @@ fi echo echo "==========================================" echo "FAILED: Pre-commit checks failed!" -if [[ "${failed_step_name}" == "Formatting project dictionary" ]]; then +if [[ "${failed_step_name}" == "Formatting project dictionary" && "${failed_step_exit_code}" -eq 1 ]]; then echo "The formatter changed project-words.txt. Stage 'project-words.txt' and retry the commit." fi echo "Fix the errors above before committing." diff --git a/contrib/dev-tools/git/tests/test-format-project-words.sh b/contrib/dev-tools/git/tests/test-format-project-words.sh index aff9361fe..0aa6475c2 100755 --- a/contrib/dev-tools/git/tests/test-format-project-words.sh +++ b/contrib/dev-tools/git/tests/test-format-project-words.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash # Integration tests for the project dictionary formatter and pre-commit orchestration. -set -uo pipefail +set -euo pipefail PROJECT_ROOT=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/../../../.." && pwd) TEST_DIRECTORY=$(mktemp -d) diff --git a/docs/issues/open/2019-automatically-format-project-dictionary.md b/docs/issues/open/2019-automatically-format-project-dictionary.md index e1d1ad9a6..257989596 100644 --- a/docs/issues/open/2019-automatically-format-project-dictionary.md +++ b/docs/issues/open/2019-automatically-format-project-dictionary.md @@ -73,7 +73,7 @@ Status values: `TODO`, `IN_PROGRESS`, `BLOCKED`, `DONE`. - [x] Implementation completed - [x] Automatic verification completed (`linter all`, relevant tests, and any pre-push checks) - [x] Manual verification scenarios executed and recorded (status + evidence) -- [ ] Acceptance criteria reviewed after implementation and updated with evidence +- [x] Acceptance criteria reviewed after implementation and updated with evidence - [ ] Reviewer validated acceptance criteria and updated checkboxes - [ ] Committer verified spec progress is up to date before commit - [ ] Issue closed and spec moved from `docs/issues/open/` to `docs/issues/closed/` @@ -88,20 +88,21 @@ Append one line per meaningful update. - 2026-07-22 00:00 UTC - GitHub Copilot - Implemented the standalone formatter, pre-commit orchestration, focused shell tests, and synchronized workflow guidance; reviewed the linked `create-issue` skill with no process change required - 2026-07-22 00:00 UTC - GitHub Copilot - Verified focused formatter and hook tests, the standalone formatter, and `TORRUST_GIT_HOOKS_LOG_DIR=.tmp ./contrib/dev-tools/git/hooks/pre-commit.sh --format=json`; all passed - 2026-07-22 00:00 UTC - GitHub Copilot - Verified `TORRUST_GIT_HOOKS_LOG_DIR=.tmp ./contrib/dev-tools/git/hooks/pre-push.sh --format=json`; all nightly checks, documentation build, and stable workspace tests passed +- 2026-07-22 00:00 UTC - GitHub Copilot - Re-reviewed the acceptance criteria against the implementation and recorded the existing verification evidence ## Acceptance Criteria -- [ ] AC1: `contrib/dev-tools/git/format-project-words.sh` applies `LC_ALL=C sort --unique` to `project-words.txt`, preserving distinct entries that differ only by case. -- [ ] AC2: If formatting modifies `project-words.txt`, the pre-commit hook exits non-zero and clearly instructs the contributor to stage the modified file and retry the commit. -- [ ] AC3: If formatting does not modify `project-words.txt`, the pre-commit hook continues with its existing verification steps. -- [ ] AC4: Automated coverage verifies both unchanged and changed formatter and hook behavior. -- [ ] AC5: The workflow documentation describes the automatic behavior and standalone formatter command. -- [ ] AC6: The implementation is documented as an interim measure related to EPIC #2003 and can be replaced or refactored by its future design. -- [ ] `linter all` exits with code `0`. -- [ ] Relevant tests pass. -- [ ] Manual verification scenarios are executed and documented (status + evidence). -- [ ] Acceptance criteria are re-reviewed after implementation and reflect actual behavior. -- [ ] Documentation is updated when behavior/workflow changes. +- [x] AC1: `contrib/dev-tools/git/format-project-words.sh` applies `LC_ALL=C sort --unique` to `project-words.txt`, preserving distinct entries that differ only by case. +- [x] AC2: If formatting modifies `project-words.txt`, the pre-commit hook exits non-zero and clearly instructs the contributor to stage the modified file and retry the commit. +- [x] AC3: If formatting does not modify `project-words.txt`, the pre-commit hook continues with its existing verification steps. +- [x] AC4: Automated coverage verifies both unchanged and changed formatter and hook behavior. +- [x] AC5: The workflow documentation describes the automatic behavior and standalone formatter command. +- [x] AC6: The implementation is documented as an interim measure related to EPIC #2003 and can be replaced or refactored by its future design. +- [x] `linter all` exits with code `0`. +- [x] Relevant tests pass. +- [x] Manual verification scenarios are executed and documented (status + evidence). +- [x] Acceptance criteria are re-reviewed after implementation and reflect actual behavior. +- [x] Documentation is updated when behavior/workflow changes. ## Verification Plan @@ -132,14 +133,14 @@ Notes: ### Acceptance Verification -| AC ID | Status (`TODO`/`DONE`) | Evidence | -| ----- | ---------------------- | ----------------------- | -| AC1 | TODO | Pending implementation. | -| AC2 | TODO | Pending implementation. | -| AC3 | TODO | Pending implementation. | -| AC4 | TODO | Pending implementation. | -| AC5 | TODO | Pending implementation. | -| AC6 | TODO | Pending implementation. | +| AC ID | Status (`TODO`/`DONE`) | Evidence | +| ----- | ---------------------- | ---------------------------------------------------------------------------------------- | +| AC1 | DONE | Formatter uses `LC_ALL=C sort --unique`; M3 verifies case variants remain distinct. | +| AC2 | DONE | M1 and focused hook test verify the non-zero exit and restaging instruction. | +| AC3 | DONE | M2 and focused hook test verify the existing checks continue. | +| AC4 | DONE | `test-format-project-words.sh` covers changed and unchanged formatter and hook behavior. | +| AC5 | DONE | `run-pre-commit-checks` documents the automatic behavior and standalone command. | +| AC6 | DONE | The formatter, hook, and workflow guidance identify this as interim work for EPIC #2003. | ## Risks and Trade-offs From 2cc5583fd58e6a841ac2ee3f46e4b073aac0ac74 Mon Sep 17 00:00:00 2001 From: Jose Celano Date: Wed, 22 Jul 2026 10:10:11 +0100 Subject: [PATCH 04/19] docs(review): track PR #2020 Copilot suggestions --- .../pr-reviews/pr-2020-copilot-suggestions.md | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 docs/pr-reviews/pr-2020-copilot-suggestions.md diff --git a/docs/pr-reviews/pr-2020-copilot-suggestions.md b/docs/pr-reviews/pr-2020-copilot-suggestions.md new file mode 100644 index 000000000..8ff76eec0 --- /dev/null +++ b/docs/pr-reviews/pr-2020-copilot-suggestions.md @@ -0,0 +1,48 @@ +--- +semantic-links: + skill-links: + - process-copilot-suggestions + related-artifacts: + - .github/skills/dev/pr-reviews/process-copilot-suggestions/SKILL.md +--- + + + + + +# PR #2020 Copilot Suggestions Tracking + +Source: Copilot PR review threads for https://github.com/torrust/torrust-tracker/pull/2020 + +Status legend: + +- `action`: code/docs change applied +- `no-action`: suggestion reviewed; no code change needed +- `resolved`: thread resolved in PR + +## Workflow + +1. Download all review threads (including resolved/outdated state and thread IDs). +2. Add one row per thread in the Suggestions table. +3. Process suggestions one by one: decide, implement and validate action items, reply on the PR thread, then resolve the thread. +4. Set `Thread State` to `resolved` once resolved in PR. + +## Processing Log + +- 2026-07-22: Started processing six Copilot suggestions. +- 2026-07-22: Applied the accepted fixes in signed commit `b917355c` and replied to and resolved all six original threads. + +## Suggestions + +| # | Thread ID | Path | URL | Suggestion Summary | Decision | Reply URL | Status | Thread State | +| --- | --------------------- | ------------------------------------------------------------------ | --------------------------------------------------------------------------- | ------------------------------------------------------------ | ---------------------------------------------------------------------- | --------------------------------------------------------------------------- | ------ | ------------ | +| 1 | PRRT_kwDOGp2yqc6S2_XP | `contrib/dev-tools/git/tests/test-format-project-words.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628911184 | Ensure assertions fail the test script. | action: enabled fail-fast shell execution. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628954196 | DONE | RESOLVED | +| 2 | PRRT_kwDOGp2yqc6S2_Xn | `contrib/dev-tools/git/format-project-words.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628911225 | Replace the dictionary atomically. | action: used a same-directory temporary file and `mv`. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628955657 | DONE | RESOLVED | +| 3 | PRRT_kwDOGp2yqc6S2_X4 | `contrib/dev-tools/git/hooks/pre-commit.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628911249 | Do not mislabel formatter operational errors as changes. | action: show restaging guidance only for formatter exit code 1. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628957067 | DONE | RESOLVED | +| 4 | PRRT_kwDOGp2yqc6S2_YS | `.github/skills/dev/git-workflow/run-pre-commit-checks/SKILL.md` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628911279 | Synchronize documented hook steps. | action: added `cargo deny check bans` and the current machete command. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628958264 | DONE | RESOLVED | +| 5 | PRRT_kwDOGp2yqc6S2_Yt | `docs/issues/open/2019-automatically-format-project-dictionary.md` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628911319 | Keep completed acceptance criteria consistent with evidence. | action: marked verified criteria complete. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628959344 | DONE | RESOLVED | +| 6 | PRRT_kwDOGp2yqc6S2_ZL | `docs/issues/open/2019-automatically-format-project-dictionary.md` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628911359 | Replace stale pending acceptance-verification entries. | action: recorded completion evidence. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628960975 | DONE | RESOLVED | + +## Notes + +- The linked `process-copilot-suggestions` skill was reviewed while updating this tracker; its workflow requires no change. From 4c8becdaefb664d324970544b37319fa3f99b90e Mon Sep 17 00:00:00 2001 From: Jose Celano Date: Wed, 22 Jul 2026 10:13:49 +0100 Subject: [PATCH 05/19] fix(git): report dictionary temp file failures --- contrib/dev-tools/git/format-project-words.sh | 6 ++++- .../git/tests/test-format-project-words.sh | 24 ++++++++++++++++++- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/contrib/dev-tools/git/format-project-words.sh b/contrib/dev-tools/git/format-project-words.sh index 900319189..0bd4fc233 100755 --- a/contrib/dev-tools/git/format-project-words.sh +++ b/contrib/dev-tools/git/format-project-words.sh @@ -12,7 +12,11 @@ if [[ ! -f "${DICTIONARY_PATH}" ]]; then exit 2 fi -temporary_dictionary=$(mktemp "${DICTIONARY_PATH}.XXXXXX") +if ! temporary_dictionary=$(mktemp "${DICTIONARY_PATH}.XXXXXX"); then + printf 'Error: failed to create a temporary project dictionary: %s\n' "${DICTIONARY_PATH}" >&2 + exit 2 +fi + trap 'rm -f "${temporary_dictionary}"' EXIT if ! LC_ALL=C sort --unique "${DICTIONARY_PATH}" >"${temporary_dictionary}"; then diff --git a/contrib/dev-tools/git/tests/test-format-project-words.sh b/contrib/dev-tools/git/tests/test-format-project-words.sh index 0aa6475c2..44736aab5 100755 --- a/contrib/dev-tools/git/tests/test-format-project-words.sh +++ b/contrib/dev-tools/git/tests/test-format-project-words.sh @@ -65,6 +65,27 @@ it_should_report_success_when_dictionary_is_already_formatted() { grep --fixed-strings --quiet 'project-words.txt is already formatted.' "${fixture_root}/formatter-output.txt" } +it_should_report_a_temp_file_creation_failure() { + # Arrange + local fixture_root + fixture_root=$(create_fixture "formatter-mktemp-failure") + printf 'Alpha\nzebra\n' >"${fixture_root}/project-words.txt" + cat >"${fixture_root}/bin/mktemp" <<'EOF' +#!/usr/bin/env bash +exit 1 +EOF + chmod +x "${fixture_root}/bin/mktemp" + + # Act + if PATH="${fixture_root}/bin:${PATH}" "${fixture_root}/contrib/dev-tools/git/format-project-words.sh" >"${fixture_root}/formatter-output.txt" 2>&1; then + printf 'Expected formatter to fail when it cannot create its temporary dictionary.\n' >&2 + return 1 + fi + + # Assert + grep --fixed-strings --quiet 'Error: failed to create a temporary project dictionary:' "${fixture_root}/formatter-output.txt" +} + it_should_abort_pre_commit_and_request_restaging_when_dictionary_is_formatted() { # Arrange local fixture_root @@ -86,7 +107,7 @@ it_should_abort_pre_commit_and_request_restaging_when_dictionary_is_formatted() # Assert diff --unified "${fixture_root}/project-words.txt" <(printf 'Alpha\nzebra\n') - grep --fixed-strings --quiet "stage 'project-words.txt' and retry the commit" "${fixture_root}/hook-output.txt" + grep --fixed-strings --quiet "Stage 'project-words.txt' and retry the commit" "${fixture_root}/hook-output.txt" [[ ! -e "${fixture_root}/commands.log" ]] } @@ -113,6 +134,7 @@ it_should_continue_pre_commit_checks_when_dictionary_is_already_formatted() { it_should_sort_and_remove_exact_duplicates_when_dictionary_requires_formatting it_should_report_success_when_dictionary_is_already_formatted +it_should_report_a_temp_file_creation_failure it_should_abort_pre_commit_and_request_restaging_when_dictionary_is_formatted it_should_continue_pre_commit_checks_when_dictionary_is_already_formatted From 14ef83c87e81c9c7069b34a04e24fc2e1f6237ab Mon Sep 17 00:00:00 2001 From: Jose Celano Date: Wed, 22 Jul 2026 10:17:14 +0100 Subject: [PATCH 06/19] docs(issues): align #2019 spec layout --- .../EPIC.md | 2 +- .../ISSUE.md | 159 ++++++++++++++++++ 2 files changed, 160 insertions(+), 1 deletion(-) create mode 100644 docs/issues/open/2019-automatically-format-project-dictionary/ISSUE.md diff --git a/docs/issues/open/2003-overhaul-guardrails-and-automation/EPIC.md b/docs/issues/open/2003-overhaul-guardrails-and-automation/EPIC.md index 6cca5d79b..4db9d4f69 100644 --- a/docs/issues/open/2003-overhaul-guardrails-and-automation/EPIC.md +++ b/docs/issues/open/2003-overhaul-guardrails-and-automation/EPIC.md @@ -162,7 +162,7 @@ build actions needed by its checks. ordering rule and contains no duplicate entries. Decide its package and execution tier through the EPIC design rather than coupling it to the tracker library. - Permit the narrowly scoped interim formatter described by - [`2019-automatically-format-project-dictionary.md`](../2019-automatically-format-project-dictionary.md). + [`2019-automatically-format-project-dictionary/ISSUE.md`](../2019-automatically-format-project-dictionary/ISSUE.md). It supplies immediate developer feedback but does not select the EPIC's long-term architecture, execution tier, or check/action contract, and may be replaced or refactored after the design decision. diff --git a/docs/issues/open/2019-automatically-format-project-dictionary/ISSUE.md b/docs/issues/open/2019-automatically-format-project-dictionary/ISSUE.md new file mode 100644 index 000000000..235bf1ce7 --- /dev/null +++ b/docs/issues/open/2019-automatically-format-project-dictionary/ISSUE.md @@ -0,0 +1,159 @@ +--- +doc-type: issue +issue-type: enhancement +status: open +priority: p2 +github-issue: 2019 +spec-path: docs/issues/open/2019-automatically-format-project-dictionary/ISSUE.md +branch: "2019-automatically-format-project-dictionary" +related-pr: null +last-updated-utc: 2026-07-22 00:00 +semantic-links: + skill-links: + - create-issue + related-artifacts: + - .github/skills/dev/planning/create-issue/SKILL.md + - contrib/dev-tools/git/format-project-words.sh + - contrib/dev-tools/git/hooks/pre-commit.sh + - docs/issues/open/2003-overhaul-guardrails-and-automation/EPIC.md + - project-words.txt +--- + + + +# Issue #2019 - Automatically format the project dictionary + +## Goal + +Make `project-words.txt` consistently sorted and free of exact duplicate entries without requiring contributors or AI agents to edit its ordering manually. + +## Background + +`project-words.txt` is the custom cspell dictionary. Its intended alphabetical ordering is documented but not enforced by `linter all` or the pre-commit hook, so pull-request reviews repeatedly identify unsorted entries. This issue delivers a small, immediately useful interim formatter while EPIC #2003 evaluates the long-term automation and guardrail architecture. It must not constrain that future design: the EPIC may replace or refactor this implementation after its design decision. + +## Scope + +### In Scope + +- Add `contrib/dev-tools/git/format-project-words.sh`, an independently runnable formatter that applies `LC_ALL=C sort --unique` to `project-words.txt`. +- Invoke the formatter from the pre-commit hook. +- Detect when formatting changes the dictionary and abort the commit with clear restaging instructions. +- Document the automatic behavior and manual formatting command in the relevant pre-commit workflow guidance. +- Ensure the committed dictionary is formatted by the new command. + +### Out of Scope + +- Changing the cspell configuration or its accepted dictionaries. +- Case-insensitive de-duplication or normalization of dictionary entries. +- Reordering unrelated project files. +- Selecting the long-term repository automation or guardrail architecture; that decision belongs to EPIC #2003. +- Treating this interim script as a constraint on EPIC #2003's future implementation. + +## Implementation Plan + +Status values: `TODO`, `IN_PROGRESS`, `BLOCKED`, `DONE`. + +| ID | Status | Task | Notes / Expected Output | +| --- | ------ | ------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| T1 | DONE | Add an independently runnable dictionary formatter | `contrib/dev-tools/git/format-project-words.sh` applies `LC_ALL=C sort --unique` to `project-words.txt` and reports whether it changed the file. | +| T2 | DONE | Invoke the formatter from the pre-commit hook | The hook calls the formatter before verification steps and retains its role as orchestration scaffolding. | +| T3 | DONE | Abort when the formatter changes the dictionary | The commit stops and tells the contributor to stage `project-words.txt` and retry, preventing a stale index from being committed. | +| T4 | DONE | Update workflow documentation | The documentation describes automatic formatting, the helper command, and the interim relationship to EPIC #2003; it no longer requires manual alphabetical-order review. | +| T5 | DONE | Add or update automated tests for formatter and hook behavior | `contrib/dev-tools/git/tests/test-format-project-words.sh` covers formatter and hook behavior for changed and unchanged dictionaries. | +| T6 | DONE | Format and verify the dictionary | The checked-in file is formatted; focused tests and the required pre-commit validation gate pass. | + +## Progress Tracking + +### Workflow Checkpoints + +- [x] Spec drafted in `docs/issues/drafts/` +- [x] Spec reviewed and approved by user/maintainer +- [x] GitHub issue created and issue number added to this spec +- [ ] (Optional, recommended for complex issues) Spec-only PR merged into `develop` before implementation +- [x] Implementation completed +- [x] Automatic verification completed (`linter all`, relevant tests, and any pre-push checks) +- [x] Manual verification scenarios executed and recorded (status + evidence) +- [x] Acceptance criteria reviewed after implementation and updated with evidence +- [ ] Reviewer validated acceptance criteria and updated checkboxes +- [ ] Committer verified spec progress is up to date before commit +- [ ] Issue closed and spec moved from `docs/issues/open/` to `docs/issues/closed/` + +### Progress Log + +Append one line per meaningful update. + +- 2026-07-22 00:00 UTC - GitHub Copilot - Created draft specification for review - `docs/issues/drafts/automatically-format-project-dictionary.md` +- 2026-07-22 00:00 UTC - josecelano - Approved an interim standalone formatter and hook integration while EPIC #2003 determines the long-term automation design - draft updated +- 2026-07-22 00:00 UTC - GitHub Operator - Created issue #2019 - https://github.com/torrust/torrust-tracker/issues/2019 +- 2026-07-22 00:00 UTC - GitHub Copilot - Implemented the standalone formatter, pre-commit orchestration, focused shell tests, and synchronized workflow guidance; reviewed the linked `create-issue` skill with no process change required +- 2026-07-22 00:00 UTC - GitHub Copilot - Verified focused formatter and hook tests, the standalone formatter, and `TORRUST_GIT_HOOKS_LOG_DIR=.tmp ./contrib/dev-tools/git/hooks/pre-commit.sh --format=json`; all passed +- 2026-07-22 00:00 UTC - GitHub Copilot - Verified `TORRUST_GIT_HOOKS_LOG_DIR=.tmp ./contrib/dev-tools/git/hooks/pre-push.sh --format=json`; all nightly checks, documentation build, and stable workspace tests passed +- 2026-07-22 00:00 UTC - GitHub Copilot - Re-reviewed the acceptance criteria against the implementation and recorded the existing verification evidence +- 2026-07-22 00:00 UTC - GitHub Copilot - Moved the specification into the documented issue-folder layout after review feedback + +## Acceptance Criteria + +- [x] AC1: `contrib/dev-tools/git/format-project-words.sh` applies `LC_ALL=C sort --unique` to `project-words.txt`, preserving distinct entries that differ only by case. +- [x] AC2: If formatting modifies `project-words.txt`, the pre-commit hook exits non-zero and clearly instructs the contributor to stage the modified file and retry the commit. +- [x] AC3: If formatting does not modify `project-words.txt`, the pre-commit hook continues with its existing verification steps. +- [x] AC4: Automated coverage verifies both unchanged and changed formatter and hook behavior. +- [x] AC5: The workflow documentation describes the automatic behavior and standalone formatter command. +- [x] AC6: The implementation is documented as an interim measure related to EPIC #2003 and can be replaced or refactored by its future design. +- [x] `linter all` exits with code `0`. +- [x] Relevant tests pass. +- [x] Manual verification scenarios are executed and documented (status + evidence). +- [x] Acceptance criteria are re-reviewed after implementation and reflect actual behavior. +- [x] Documentation is updated when behavior/workflow changes. + +## Verification Plan + +Define verification before implementation starts and execute it before closing the issue. + +### Automatic Checks + +- `linter all` +- Focused tests for the pre-commit hook behavior +- `./contrib/dev-tools/git/format-project-words.sh` +- `TORRUST_GIT_HOOKS_LOG_DIR=.tmp ./contrib/dev-tools/git/hooks/pre-commit.sh` +- Pre-push checks when applicable + +### Manual Verification Scenarios + +Status values: `TODO`, `IN_PROGRESS`, `DONE`, `FAILED`, `BLOCKED`. + +| ID | Scenario | Command/Steps | Expected Result | Status | Evidence | +| --- | ----------------------------- | --------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------ | +| M1 | Dictionary needs formatting | Temporarily add unsorted and duplicate exact entries in an isolated Git checkout, then run the pre-commit hook. | The hook rewrites `project-words.txt`, exits non-zero, and instructs the user to stage the file and retry. | DONE | `test-format-project-words.sh`: `it_should_abort_pre_commit_and_request_restaging_when_dictionary_is_formatted`. | +| M2 | Dictionary already formatted | Run the pre-commit hook with the formatted tracked dictionary. | The formatter leaves the file unchanged and the hook continues to its existing checks. | DONE | `TORRUST_GIT_HOOKS_LOG_DIR=.tmp ./contrib/dev-tools/git/hooks/pre-commit.sh --format=json` passed its formatter and all four verification steps. | +| M3 | Case variants remain distinct | Run the standalone formatter against a disposable dictionary containing otherwise identical case variants. | Both variants remain; only exact duplicate lines are removed. | DONE | `test-format-project-words.sh`: `it_should_sort_and_remove_exact_duplicates_when_dictionary_requires_formatting`. | + +Notes: + +- Manual verification is mandatory even when automated tests pass. +- If a scenario fails, record the failure and diagnosis in the progress log before proceeding. + +### Acceptance Verification + +| AC ID | Status (`TODO`/`DONE`) | Evidence | +| ----- | ---------------------- | ---------------------------------------------------------------------------------------- | +| AC1 | DONE | Formatter uses `LC_ALL=C sort --unique`; M3 verifies case variants remain distinct. | +| AC2 | DONE | M1 and focused hook test verify the non-zero exit and restaging instruction. | +| AC3 | DONE | M2 and focused hook test verify the existing checks continue. | +| AC4 | DONE | `test-format-project-words.sh` covers changed and unchanged formatter and hook behavior. | +| AC5 | DONE | `run-pre-commit-checks` documents the automatic behavior and standalone command. | +| AC6 | DONE | The formatter, hook, and workflow guidance identify this as interim work for EPIC #2003. | + +## Risks and Trade-offs + +- A hook that changes a working-tree file after Git has prepared the index could otherwise allow the unsorted staged version to be committed. The hook must abort after a formatting change so the corrected file can be staged deliberately. +- Locale-sensitive sorting would yield inconsistent output across machines. Setting `LC_ALL=C` makes the ordering deterministic. +- Case-insensitive de-duplication could delete meaningful proper-name or acronym variants. Exact duplicate removal only avoids that data loss. + +## References + +- `project-words.txt` +- `cspell.json` +- `contrib/dev-tools/git/format-project-words.sh` +- `contrib/dev-tools/git/hooks/pre-commit.sh` +- `docs/issues/open/2003-overhaul-guardrails-and-automation/EPIC.md` +- `.github/skills/dev/git-workflow/run-pre-commit-checks/SKILL.md` From e83ae97c985c266f25dc0dafb75b15d1077329dd Mon Sep 17 00:00:00 2001 From: Jose Celano Date: Wed, 22 Jul 2026 10:22:06 +0100 Subject: [PATCH 07/19] docs(issues): remove legacy #2019 spec --- ...automatically-format-project-dictionary.md | 158 ------------------ 1 file changed, 158 deletions(-) delete mode 100644 docs/issues/open/2019-automatically-format-project-dictionary.md diff --git a/docs/issues/open/2019-automatically-format-project-dictionary.md b/docs/issues/open/2019-automatically-format-project-dictionary.md deleted file mode 100644 index 257989596..000000000 --- a/docs/issues/open/2019-automatically-format-project-dictionary.md +++ /dev/null @@ -1,158 +0,0 @@ ---- -doc-type: issue -issue-type: enhancement -status: open -priority: p2 -github-issue: 2019 -spec-path: docs/issues/open/2019-automatically-format-project-dictionary.md -branch: "2019-automatically-format-project-dictionary" -related-pr: null -last-updated-utc: 2026-07-22 00:00 -semantic-links: - skill-links: - - create-issue - related-artifacts: - - .github/skills/dev/planning/create-issue/SKILL.md - - contrib/dev-tools/git/format-project-words.sh - - contrib/dev-tools/git/hooks/pre-commit.sh - - docs/issues/open/2003-overhaul-guardrails-and-automation/EPIC.md - - project-words.txt ---- - - - -# Issue #2019 - Automatically format the project dictionary - -## Goal - -Make `project-words.txt` consistently sorted and free of exact duplicate entries without requiring contributors or AI agents to edit its ordering manually. - -## Background - -`project-words.txt` is the custom cspell dictionary. Its intended alphabetical ordering is documented but not enforced by `linter all` or the pre-commit hook, so pull-request reviews repeatedly identify unsorted entries. This issue delivers a small, immediately useful interim formatter while EPIC #2003 evaluates the long-term automation and guardrail architecture. It must not constrain that future design: the EPIC may replace or refactor this implementation after its design decision. - -## Scope - -### In Scope - -- Add `contrib/dev-tools/git/format-project-words.sh`, an independently runnable formatter that applies `LC_ALL=C sort --unique` to `project-words.txt`. -- Invoke the formatter from the pre-commit hook. -- Detect when formatting changes the dictionary and abort the commit with clear restaging instructions. -- Document the automatic behavior and manual formatting command in the relevant pre-commit workflow guidance. -- Ensure the committed dictionary is formatted by the new command. - -### Out of Scope - -- Changing the cspell configuration or its accepted dictionaries. -- Case-insensitive de-duplication or normalization of dictionary entries. -- Reordering unrelated project files. -- Selecting the long-term repository automation or guardrail architecture; that decision belongs to EPIC #2003. -- Treating this interim script as a constraint on EPIC #2003's future implementation. - -## Implementation Plan - -Status values: `TODO`, `IN_PROGRESS`, `BLOCKED`, `DONE`. - -| ID | Status | Task | Notes / Expected Output | -| --- | ------ | ------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| T1 | DONE | Add an independently runnable dictionary formatter | `contrib/dev-tools/git/format-project-words.sh` applies `LC_ALL=C sort --unique` to `project-words.txt` and reports whether it changed the file. | -| T2 | DONE | Invoke the formatter from the pre-commit hook | The hook calls the formatter before verification steps and retains its role as orchestration scaffolding. | -| T3 | DONE | Abort when the formatter changes the dictionary | The commit stops and tells the contributor to stage `project-words.txt` and retry, preventing a stale index from being committed. | -| T4 | DONE | Update workflow documentation | The documentation describes automatic formatting, the helper command, and the interim relationship to EPIC #2003; it no longer requires manual alphabetical-order review. | -| T5 | DONE | Add or update automated tests for formatter and hook behavior | `contrib/dev-tools/git/tests/test-format-project-words.sh` covers formatter and hook behavior for changed and unchanged dictionaries. | -| T6 | DONE | Format and verify the dictionary | The checked-in file is formatted; focused tests and the required pre-commit validation gate pass. | - -## Progress Tracking - -### Workflow Checkpoints - -- [x] Spec drafted in `docs/issues/drafts/` -- [x] Spec reviewed and approved by user/maintainer -- [x] GitHub issue created and issue number added to this spec -- [ ] (Optional, recommended for complex issues) Spec-only PR merged into `develop` before implementation -- [x] Implementation completed -- [x] Automatic verification completed (`linter all`, relevant tests, and any pre-push checks) -- [x] Manual verification scenarios executed and recorded (status + evidence) -- [x] Acceptance criteria reviewed after implementation and updated with evidence -- [ ] Reviewer validated acceptance criteria and updated checkboxes -- [ ] Committer verified spec progress is up to date before commit -- [ ] Issue closed and spec moved from `docs/issues/open/` to `docs/issues/closed/` - -### Progress Log - -Append one line per meaningful update. - -- 2026-07-22 00:00 UTC - GitHub Copilot - Created draft specification for review - `docs/issues/drafts/automatically-format-project-dictionary.md` -- 2026-07-22 00:00 UTC - josecelano - Approved an interim standalone formatter and hook integration while EPIC #2003 determines the long-term automation design - draft updated -- 2026-07-22 00:00 UTC - GitHub Operator - Created issue #2019 - https://github.com/torrust/torrust-tracker/issues/2019 -- 2026-07-22 00:00 UTC - GitHub Copilot - Implemented the standalone formatter, pre-commit orchestration, focused shell tests, and synchronized workflow guidance; reviewed the linked `create-issue` skill with no process change required -- 2026-07-22 00:00 UTC - GitHub Copilot - Verified focused formatter and hook tests, the standalone formatter, and `TORRUST_GIT_HOOKS_LOG_DIR=.tmp ./contrib/dev-tools/git/hooks/pre-commit.sh --format=json`; all passed -- 2026-07-22 00:00 UTC - GitHub Copilot - Verified `TORRUST_GIT_HOOKS_LOG_DIR=.tmp ./contrib/dev-tools/git/hooks/pre-push.sh --format=json`; all nightly checks, documentation build, and stable workspace tests passed -- 2026-07-22 00:00 UTC - GitHub Copilot - Re-reviewed the acceptance criteria against the implementation and recorded the existing verification evidence - -## Acceptance Criteria - -- [x] AC1: `contrib/dev-tools/git/format-project-words.sh` applies `LC_ALL=C sort --unique` to `project-words.txt`, preserving distinct entries that differ only by case. -- [x] AC2: If formatting modifies `project-words.txt`, the pre-commit hook exits non-zero and clearly instructs the contributor to stage the modified file and retry the commit. -- [x] AC3: If formatting does not modify `project-words.txt`, the pre-commit hook continues with its existing verification steps. -- [x] AC4: Automated coverage verifies both unchanged and changed formatter and hook behavior. -- [x] AC5: The workflow documentation describes the automatic behavior and standalone formatter command. -- [x] AC6: The implementation is documented as an interim measure related to EPIC #2003 and can be replaced or refactored by its future design. -- [x] `linter all` exits with code `0`. -- [x] Relevant tests pass. -- [x] Manual verification scenarios are executed and documented (status + evidence). -- [x] Acceptance criteria are re-reviewed after implementation and reflect actual behavior. -- [x] Documentation is updated when behavior/workflow changes. - -## Verification Plan - -Define verification before implementation starts and execute it before closing the issue. - -### Automatic Checks - -- `linter all` -- Focused tests for the pre-commit hook behavior -- `./contrib/dev-tools/git/format-project-words.sh` -- `TORRUST_GIT_HOOKS_LOG_DIR=.tmp ./contrib/dev-tools/git/hooks/pre-commit.sh` -- Pre-push checks when applicable - -### Manual Verification Scenarios - -Status values: `TODO`, `IN_PROGRESS`, `DONE`, `FAILED`, `BLOCKED`. - -| ID | Scenario | Command/Steps | Expected Result | Status | Evidence | -| --- | ----------------------------- | --------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------ | -| M1 | Dictionary needs formatting | Temporarily add unsorted and duplicate exact entries in an isolated Git checkout, then run the pre-commit hook. | The hook rewrites `project-words.txt`, exits non-zero, and instructs the user to stage the file and retry. | DONE | `test-format-project-words.sh`: `it_should_abort_pre_commit_and_request_restaging_when_dictionary_is_formatted`. | -| M2 | Dictionary already formatted | Run the pre-commit hook with the formatted tracked dictionary. | The formatter leaves the file unchanged and the hook continues to its existing checks. | DONE | `TORRUST_GIT_HOOKS_LOG_DIR=.tmp ./contrib/dev-tools/git/hooks/pre-commit.sh --format=json` passed its formatter and all four verification steps. | -| M3 | Case variants remain distinct | Run the standalone formatter against a disposable dictionary containing otherwise identical case variants. | Both variants remain; only exact duplicate lines are removed. | DONE | `test-format-project-words.sh`: `it_should_sort_and_remove_exact_duplicates_when_dictionary_requires_formatting`. | - -Notes: - -- Manual verification is mandatory even when automated tests pass. -- If a scenario fails, record the failure and diagnosis in the progress log before proceeding. - -### Acceptance Verification - -| AC ID | Status (`TODO`/`DONE`) | Evidence | -| ----- | ---------------------- | ---------------------------------------------------------------------------------------- | -| AC1 | DONE | Formatter uses `LC_ALL=C sort --unique`; M3 verifies case variants remain distinct. | -| AC2 | DONE | M1 and focused hook test verify the non-zero exit and restaging instruction. | -| AC3 | DONE | M2 and focused hook test verify the existing checks continue. | -| AC4 | DONE | `test-format-project-words.sh` covers changed and unchanged formatter and hook behavior. | -| AC5 | DONE | `run-pre-commit-checks` documents the automatic behavior and standalone command. | -| AC6 | DONE | The formatter, hook, and workflow guidance identify this as interim work for EPIC #2003. | - -## Risks and Trade-offs - -- A hook that changes a working-tree file after Git has prepared the index could otherwise allow the unsorted staged version to be committed. The hook must abort after a formatting change so the corrected file can be staged deliberately. -- Locale-sensitive sorting would yield inconsistent output across machines. Setting `LC_ALL=C` makes the ordering deterministic. -- Case-insensitive de-duplication could delete meaningful proper-name or acronym variants. Exact duplicate removal only avoids that data loss. - -## References - -- `project-words.txt` -- `cspell.json` -- `contrib/dev-tools/git/format-project-words.sh` -- `contrib/dev-tools/git/hooks/pre-commit.sh` -- `docs/issues/open/2003-overhaul-guardrails-and-automation/EPIC.md` -- `.github/skills/dev/git-workflow/run-pre-commit-checks/SKILL.md` From 895117e6fd36170489929b0ee3bfa22739195aa5 Mon Sep 17 00:00:00 2001 From: Jose Celano Date: Wed, 22 Jul 2026 10:29:16 +0100 Subject: [PATCH 08/19] fix(git): retain pre-commit step exit codes --- contrib/dev-tools/git/hooks/pre-commit.sh | 9 ++--- .../git/tests/test-format-project-words.sh | 33 +++++++++++++++++++ 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/contrib/dev-tools/git/hooks/pre-commit.sh b/contrib/dev-tools/git/hooks/pre-commit.sh index c9ca6efcf..ccf663e97 100755 --- a/contrib/dev-tools/git/hooks/pre-commit.sh +++ b/contrib/dev-tools/git/hooks/pre-commit.sh @@ -42,7 +42,6 @@ LOG_DIR="${TORRUST_GIT_HOOKS_LOG_DIR:-/tmp}" declare -a STEP_NAMES=() declare -a STEP_COMMANDS=() declare -a STEP_STATUSES=() -declare -a STEP_EXIT_CODES=() declare -a STEP_ELAPSED_SECONDS=() declare -a STEP_LOG_PATHS=() @@ -192,7 +191,6 @@ run_step() { STEP_NAMES+=("${description}") STEP_COMMANDS+=("${command}") - STEP_EXIT_CODES+=("${command_exit_code}") STEP_ELAPSED_SECONDS+=("${step_elapsed}") STEP_LOG_PATHS+=("${log_path}") @@ -344,11 +342,14 @@ fi for i in "${!STEPS[@]}"; do IFS='|' read -r description command <<< "${STEPS[$i]}" - if ! run_step $((i + 1)) "${TOTAL_STEPS}" "${description}" "${command}"; then + if run_step $((i + 1)) "${TOTAL_STEPS}" "${description}" "${command}"; then + step_exit_code=0 + else + step_exit_code=$? overall_status="fail" exit_code=1 failed_step_name="${description}" - failed_step_exit_code=${STEP_EXIT_CODES[$(( ${#STEP_EXIT_CODES[@]} - 1 ))]} + failed_step_exit_code=${step_exit_code} break fi done diff --git a/contrib/dev-tools/git/tests/test-format-project-words.sh b/contrib/dev-tools/git/tests/test-format-project-words.sh index 44736aab5..1f8d87b96 100755 --- a/contrib/dev-tools/git/tests/test-format-project-words.sh +++ b/contrib/dev-tools/git/tests/test-format-project-words.sh @@ -111,6 +111,38 @@ it_should_abort_pre_commit_and_request_restaging_when_dictionary_is_formatted() [[ ! -e "${fixture_root}/commands.log" ]] } +it_should_not_mislabel_log_creation_failures_as_dictionary_changes() { + # Arrange + local fixture_root + fixture_root=$(create_fixture "hook-log-mktemp-failure") + printf 'Alpha\nzebra\n' >"${fixture_root}/project-words.txt" + create_successful_command_stubs "${fixture_root}" + cat >"${fixture_root}/bin/mktemp" <<'EOF' +#!/usr/bin/env bash +if [[ "$1" == *pre-commit-* ]]; then + exit 1 +fi +exec /usr/bin/mktemp "$@" +EOF + chmod +x "${fixture_root}/bin/mktemp" + + # Act + if ( + cd "${fixture_root}" || exit + PATH="${fixture_root}/bin:${PATH}" \ + TEST_COMMAND_LOG="${fixture_root}/commands.log" \ + TORRUST_GIT_HOOKS_LOG_DIR="${fixture_root}/logs" \ + ./contrib/dev-tools/git/hooks/pre-commit.sh >"${fixture_root}/hook-output.txt" 2>&1 + ); then + printf 'Expected pre-commit hook to fail when it cannot create a step log.\n' >&2 + return 1 + fi + + # Assert + grep --fixed-strings --quiet "Error: failed to create a temporary log file in '${fixture_root}/logs'." "${fixture_root}/hook-output.txt" + ! grep --fixed-strings --quiet "The formatter changed project-words.txt." "${fixture_root}/hook-output.txt" +} + it_should_continue_pre_commit_checks_when_dictionary_is_already_formatted() { # Arrange local fixture_root @@ -136,6 +168,7 @@ it_should_sort_and_remove_exact_duplicates_when_dictionary_requires_formatting it_should_report_success_when_dictionary_is_already_formatted it_should_report_a_temp_file_creation_failure it_should_abort_pre_commit_and_request_restaging_when_dictionary_is_formatted +it_should_not_mislabel_log_creation_failures_as_dictionary_changes it_should_continue_pre_commit_checks_when_dictionary_is_already_formatted printf 'All formatter and pre-commit hook tests passed.\n' \ No newline at end of file From 641c06f4ab78ae97529078c9222ac96cd0d86e4a Mon Sep 17 00:00:00 2001 From: Jose Celano Date: Wed, 22 Jul 2026 10:45:16 +0100 Subject: [PATCH 09/19] fix(git): support portable dictionary formatting --- .../dev/git-workflow/run-pre-commit-checks/SKILL.md | 2 +- contrib/dev-tools/git/format-project-words.sh | 13 +++++++++---- .../git/tests/test-format-project-words.sh | 2 +- .../ISSUE.md | 8 ++++---- 4 files changed, 15 insertions(+), 10 deletions(-) diff --git a/.github/skills/dev/git-workflow/run-pre-commit-checks/SKILL.md b/.github/skills/dev/git-workflow/run-pre-commit-checks/SKILL.md index 18893c8f0..07a807514 100644 --- a/.github/skills/dev/git-workflow/run-pre-commit-checks/SKILL.md +++ b/.github/skills/dev/git-workflow/run-pre-commit-checks/SKILL.md @@ -48,7 +48,7 @@ TORRUST_GIT_HOOKS_LOG_DIR=.tmp ./contrib/dev-tools/git/hooks/pre-commit.sh The script runs these steps in order: 1. `./contrib/dev-tools/git/format-project-words.sh` - formats `project-words.txt` with - `LC_ALL=C sort --unique` + `LC_ALL=C sort -u` 2. `cargo machete --with-metadata` - unused dependency check 3. `cargo deny check bans` - workspace layer-boundary dependency check 4. `linter all` - all linters (markdown, YAML, TOML, clippy, rustfmt, shellcheck, cspell) diff --git a/contrib/dev-tools/git/format-project-words.sh b/contrib/dev-tools/git/format-project-words.sh index 0bd4fc233..9634c70cf 100755 --- a/contrib/dev-tools/git/format-project-words.sh +++ b/contrib/dev-tools/git/format-project-words.sh @@ -19,21 +19,26 @@ fi trap 'rm -f "${temporary_dictionary}"' EXIT -if ! LC_ALL=C sort --unique "${DICTIONARY_PATH}" >"${temporary_dictionary}"; then +if ! cp -p "${DICTIONARY_PATH}" "${temporary_dictionary}"; then + printf 'Error: failed to preserve project dictionary metadata: %s\n' "${DICTIONARY_PATH}" >&2 + exit 2 +fi + +if ! LC_ALL=C sort -u "${DICTIONARY_PATH}" >"${temporary_dictionary}"; then printf 'Error: failed to format project dictionary: %s\n' "${DICTIONARY_PATH}" >&2 exit 2 fi -if cmp --silent "${DICTIONARY_PATH}" "${temporary_dictionary}"; then +if cmp -s "${DICTIONARY_PATH}" "${temporary_dictionary}"; then printf 'project-words.txt is already formatted.\n' exit 0 fi -if ! chmod --reference="${DICTIONARY_PATH}" "${temporary_dictionary}" || ! mv -- "${temporary_dictionary}" "${DICTIONARY_PATH}"; then +if ! mv "${temporary_dictionary}" "${DICTIONARY_PATH}"; then printf 'Error: failed to update project dictionary: %s\n' "${DICTIONARY_PATH}" >&2 exit 2 fi -printf 'Formatted project-words.txt with LC_ALL=C sort --unique.\n' +printf 'Formatted project-words.txt with LC_ALL=C sort -u.\n' printf "Stage 'project-words.txt' and retry the commit.\n" exit 1 \ No newline at end of file diff --git a/contrib/dev-tools/git/tests/test-format-project-words.sh b/contrib/dev-tools/git/tests/test-format-project-words.sh index 1f8d87b96..a32b132d8 100755 --- a/contrib/dev-tools/git/tests/test-format-project-words.sh +++ b/contrib/dev-tools/git/tests/test-format-project-words.sh @@ -49,7 +49,7 @@ it_should_sort_and_remove_exact_duplicates_when_dictionary_requires_formatting() # Assert diff --unified "${fixture_root}/project-words.txt" <(printf 'Alpha\nalpha\nzebra\n') - grep --fixed-strings --quiet 'Formatted project-words.txt with LC_ALL=C sort --unique.' "${fixture_root}/formatter-output.txt" + grep --fixed-strings --quiet 'Formatted project-words.txt with LC_ALL=C sort -u.' "${fixture_root}/formatter-output.txt" } it_should_report_success_when_dictionary_is_already_formatted() { diff --git a/docs/issues/open/2019-automatically-format-project-dictionary/ISSUE.md b/docs/issues/open/2019-automatically-format-project-dictionary/ISSUE.md index 235bf1ce7..cb91120da 100644 --- a/docs/issues/open/2019-automatically-format-project-dictionary/ISSUE.md +++ b/docs/issues/open/2019-automatically-format-project-dictionary/ISSUE.md @@ -35,7 +35,7 @@ Make `project-words.txt` consistently sorted and free of exact duplicate entries ### In Scope -- Add `contrib/dev-tools/git/format-project-words.sh`, an independently runnable formatter that applies `LC_ALL=C sort --unique` to `project-words.txt`. +- Add `contrib/dev-tools/git/format-project-words.sh`, an independently runnable formatter that applies `LC_ALL=C sort -u` to `project-words.txt`. - Invoke the formatter from the pre-commit hook. - Detect when formatting changes the dictionary and abort the commit with clear restaging instructions. - Document the automatic behavior and manual formatting command in the relevant pre-commit workflow guidance. @@ -55,7 +55,7 @@ Status values: `TODO`, `IN_PROGRESS`, `BLOCKED`, `DONE`. | ID | Status | Task | Notes / Expected Output | | --- | ------ | ------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| T1 | DONE | Add an independently runnable dictionary formatter | `contrib/dev-tools/git/format-project-words.sh` applies `LC_ALL=C sort --unique` to `project-words.txt` and reports whether it changed the file. | +| T1 | DONE | Add an independently runnable dictionary formatter | `contrib/dev-tools/git/format-project-words.sh` applies `LC_ALL=C sort -u` to `project-words.txt` and reports whether it changed the file. | | T2 | DONE | Invoke the formatter from the pre-commit hook | The hook calls the formatter before verification steps and retains its role as orchestration scaffolding. | | T3 | DONE | Abort when the formatter changes the dictionary | The commit stops and tells the contributor to stage `project-words.txt` and retry, preventing a stale index from being committed. | | T4 | DONE | Update workflow documentation | The documentation describes automatic formatting, the helper command, and the interim relationship to EPIC #2003; it no longer requires manual alphabetical-order review. | @@ -93,7 +93,7 @@ Append one line per meaningful update. ## Acceptance Criteria -- [x] AC1: `contrib/dev-tools/git/format-project-words.sh` applies `LC_ALL=C sort --unique` to `project-words.txt`, preserving distinct entries that differ only by case. +- [x] AC1: `contrib/dev-tools/git/format-project-words.sh` applies `LC_ALL=C sort -u` to `project-words.txt`, preserving distinct entries that differ only by case. - [x] AC2: If formatting modifies `project-words.txt`, the pre-commit hook exits non-zero and clearly instructs the contributor to stage the modified file and retry the commit. - [x] AC3: If formatting does not modify `project-words.txt`, the pre-commit hook continues with its existing verification steps. - [x] AC4: Automated coverage verifies both unchanged and changed formatter and hook behavior. @@ -136,7 +136,7 @@ Notes: | AC ID | Status (`TODO`/`DONE`) | Evidence | | ----- | ---------------------- | ---------------------------------------------------------------------------------------- | -| AC1 | DONE | Formatter uses `LC_ALL=C sort --unique`; M3 verifies case variants remain distinct. | +| AC1 | DONE | Formatter uses `LC_ALL=C sort -u`; M3 verifies case variants remain distinct. | | AC2 | DONE | M1 and focused hook test verify the non-zero exit and restaging instruction. | | AC3 | DONE | M2 and focused hook test verify the existing checks continue. | | AC4 | DONE | `test-format-project-words.sh` covers changed and unchanged formatter and hook behavior. | From 03aa7d51f229ea04531d113628cd7b5fd1013f82 Mon Sep 17 00:00:00 2001 From: Jose Celano Date: Wed, 22 Jul 2026 10:54:04 +0100 Subject: [PATCH 10/19] docs(review): complete PR #2020 suggestions audit --- docs/pr-reviews/pr-2020-copilot-suggestions.md | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/docs/pr-reviews/pr-2020-copilot-suggestions.md b/docs/pr-reviews/pr-2020-copilot-suggestions.md index 8ff76eec0..8935f0d29 100644 --- a/docs/pr-reviews/pr-2020-copilot-suggestions.md +++ b/docs/pr-reviews/pr-2020-copilot-suggestions.md @@ -14,11 +14,11 @@ semantic-links: Source: Copilot PR review threads for https://github.com/torrust/torrust-tracker/pull/2020 -Status legend: +Column legend: -- `action`: code/docs change applied -- `no-action`: suggestion reviewed; no code change needed -- `resolved`: thread resolved in PR +- **Decision**: `action` means a code or documentation change was applied; `no-action` means the suggestion was reviewed and declined with a documented rationale. +- **Status**: `OPEN` while a thread is being processed; `DONE` after it has been handled. +- **Thread State**: `OPEN` until the thread is resolved in the PR; `RESOLVED` after resolution. ## Workflow @@ -42,6 +42,11 @@ Status legend: | 4 | PRRT_kwDOGp2yqc6S2_YS | `.github/skills/dev/git-workflow/run-pre-commit-checks/SKILL.md` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628911279 | Synchronize documented hook steps. | action: added `cargo deny check bans` and the current machete command. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628958264 | DONE | RESOLVED | | 5 | PRRT_kwDOGp2yqc6S2_Yt | `docs/issues/open/2019-automatically-format-project-dictionary.md` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628911319 | Keep completed acceptance criteria consistent with evidence. | action: marked verified criteria complete. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628959344 | DONE | RESOLVED | | 6 | PRRT_kwDOGp2yqc6S2_ZL | `docs/issues/open/2019-automatically-format-project-dictionary.md` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628911359 | Replace stale pending acceptance-verification entries. | action: recorded completion evidence. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628960975 | DONE | RESOLVED | +| 7 | PRRT_kwDOGp2yqc6S3Lr0 | `contrib/dev-tools/git/format-project-words.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628981491 | Report temporary-file creation failures explicitly. | action: added the diagnostic and focused test coverage. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629010458 | DONE | RESOLVED | +| 8 | PRRT_kwDOGp2yqc6S3LsT | `docs/issues/open/2019-automatically-format-project-dictionary.md` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628981533 | Align the issue specification with the documented layout. | action: moved the spec to its documented `ISSUE.md` folder layout. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629239329 | DONE | RESOLVED | +| 9 | PRRT_kwDOGp2yqc6S3T8_ | `contrib/dev-tools/git/hooks/pre-commit.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629029141 | Retain the exact failed step exit code. | action: captured the `run_step` exit code directly. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629242405 | DONE | RESOLVED | +| 10 | PRRT_kwDOGp2yqc6S3dJZ | `contrib/dev-tools/git/format-project-words.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629081831 | Support non-GNU local toolchains. | action: replaced GNU-only options with portable equivalents. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629243737 | DONE | RESOLVED | +| 11 | PRRT_kwDOGp2yqc6S3k60 | `docs/pr-reviews/pr-2020-copilot-suggestions.md` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629126625 | Make tracker column meanings unambiguous. | action: replaced the ambiguous legend with column-specific definitions. | Pending | OPEN | OPEN | ## Notes From b2db6a57b4eba98f31b75d9dccdf149134d4ac0c Mon Sep 17 00:00:00 2001 From: Jose Celano Date: Wed, 22 Jul 2026 10:56:11 +0100 Subject: [PATCH 11/19] fix(git): keep formatter tests portable --- .../run-linters/references/linters.md | 2 +- .../git/tests/test-format-project-words.sh | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/skills/dev/git-workflow/run-linters/references/linters.md b/.github/skills/dev/git-workflow/run-linters/references/linters.md index c3a724e81..bd82190f1 100644 --- a/.github/skills/dev/git-workflow/run-linters/references/linters.md +++ b/.github/skills/dev/git-workflow/run-linters/references/linters.md @@ -57,7 +57,7 @@ Key formatting settings: **Run**: `linter cspell` Add technical terms to `project-words.txt` (one per line), then run -`./contrib/dev-tools/git/format-project-words.sh`. The formatter uses `LC_ALL=C sort --unique`; +`./contrib/dev-tools/git/format-project-words.sh`. The formatter uses `LC_ALL=C sort -u`; the pre-commit hook runs it automatically and requests restaging if it changes the dictionary. ## Configuration Linters diff --git a/contrib/dev-tools/git/tests/test-format-project-words.sh b/contrib/dev-tools/git/tests/test-format-project-words.sh index a32b132d8..1cfe20f98 100755 --- a/contrib/dev-tools/git/tests/test-format-project-words.sh +++ b/contrib/dev-tools/git/tests/test-format-project-words.sh @@ -48,8 +48,8 @@ it_should_sort_and_remove_exact_duplicates_when_dictionary_requires_formatting() fi # Assert - diff --unified "${fixture_root}/project-words.txt" <(printf 'Alpha\nalpha\nzebra\n') - grep --fixed-strings --quiet 'Formatted project-words.txt with LC_ALL=C sort -u.' "${fixture_root}/formatter-output.txt" + diff -u "${fixture_root}/project-words.txt" <(printf 'Alpha\nalpha\nzebra\n') + grep -F -q 'Formatted project-words.txt with LC_ALL=C sort -u.' "${fixture_root}/formatter-output.txt" } it_should_report_success_when_dictionary_is_already_formatted() { @@ -62,7 +62,7 @@ it_should_report_success_when_dictionary_is_already_formatted() { "${fixture_root}/contrib/dev-tools/git/format-project-words.sh" >"${fixture_root}/formatter-output.txt" # Assert - grep --fixed-strings --quiet 'project-words.txt is already formatted.' "${fixture_root}/formatter-output.txt" + grep -F -q 'project-words.txt is already formatted.' "${fixture_root}/formatter-output.txt" } it_should_report_a_temp_file_creation_failure() { @@ -83,7 +83,7 @@ EOF fi # Assert - grep --fixed-strings --quiet 'Error: failed to create a temporary project dictionary:' "${fixture_root}/formatter-output.txt" + grep -F -q 'Error: failed to create a temporary project dictionary:' "${fixture_root}/formatter-output.txt" } it_should_abort_pre_commit_and_request_restaging_when_dictionary_is_formatted() { @@ -106,8 +106,8 @@ it_should_abort_pre_commit_and_request_restaging_when_dictionary_is_formatted() fi # Assert - diff --unified "${fixture_root}/project-words.txt" <(printf 'Alpha\nzebra\n') - grep --fixed-strings --quiet "Stage 'project-words.txt' and retry the commit" "${fixture_root}/hook-output.txt" + diff -u "${fixture_root}/project-words.txt" <(printf 'Alpha\nzebra\n') + grep -F -q "Stage 'project-words.txt' and retry the commit" "${fixture_root}/hook-output.txt" [[ ! -e "${fixture_root}/commands.log" ]] } @@ -139,8 +139,8 @@ EOF fi # Assert - grep --fixed-strings --quiet "Error: failed to create a temporary log file in '${fixture_root}/logs'." "${fixture_root}/hook-output.txt" - ! grep --fixed-strings --quiet "The formatter changed project-words.txt." "${fixture_root}/hook-output.txt" + grep -F -q "Error: failed to create a temporary log file in '${fixture_root}/logs'." "${fixture_root}/hook-output.txt" + ! grep -F -q "The formatter changed project-words.txt." "${fixture_root}/hook-output.txt" } it_should_continue_pre_commit_checks_when_dictionary_is_already_formatted() { @@ -161,7 +161,7 @@ it_should_continue_pre_commit_checks_when_dictionary_is_already_formatted() { # Assert [[ $(wc -l <"${fixture_root}/commands.log") -eq 4 ]] - grep --fixed-strings --quiet 'SUCCESS: All pre-commit checks passed!' "${fixture_root}/hook-output.txt" + grep -F -q 'SUCCESS: All pre-commit checks passed!' "${fixture_root}/hook-output.txt" } it_should_sort_and_remove_exact_duplicates_when_dictionary_requires_formatting From 8c8b09780dc8a119bfa91653e4461dee92d74bd7 Mon Sep 17 00:00:00 2001 From: Jose Celano Date: Wed, 22 Jul 2026 11:02:47 +0100 Subject: [PATCH 12/19] docs(review): record PR #2020 follow-up responses --- docs/pr-reviews/pr-2020-copilot-suggestions.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/docs/pr-reviews/pr-2020-copilot-suggestions.md b/docs/pr-reviews/pr-2020-copilot-suggestions.md index 8935f0d29..c3b48ce0b 100644 --- a/docs/pr-reviews/pr-2020-copilot-suggestions.md +++ b/docs/pr-reviews/pr-2020-copilot-suggestions.md @@ -31,6 +31,7 @@ Column legend: - 2026-07-22: Started processing six Copilot suggestions. - 2026-07-22: Applied the accepted fixes in signed commit `b917355c` and replied to and resolved all six original threads. +- 2026-07-22: Processed all follow-up Copilot threads opened after subsequent pushes; every accepted change was committed, validated, replied to, and resolved. ## Suggestions @@ -46,7 +47,14 @@ Column legend: | 8 | PRRT_kwDOGp2yqc6S3LsT | `docs/issues/open/2019-automatically-format-project-dictionary.md` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628981533 | Align the issue specification with the documented layout. | action: moved the spec to its documented `ISSUE.md` folder layout. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629239329 | DONE | RESOLVED | | 9 | PRRT_kwDOGp2yqc6S3T8_ | `contrib/dev-tools/git/hooks/pre-commit.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629029141 | Retain the exact failed step exit code. | action: captured the `run_step` exit code directly. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629242405 | DONE | RESOLVED | | 10 | PRRT_kwDOGp2yqc6S3dJZ | `contrib/dev-tools/git/format-project-words.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629081831 | Support non-GNU local toolchains. | action: replaced GNU-only options with portable equivalents. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629243737 | DONE | RESOLVED | -| 11 | PRRT_kwDOGp2yqc6S3k60 | `docs/pr-reviews/pr-2020-copilot-suggestions.md` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629126625 | Make tracker column meanings unambiguous. | action: replaced the ambiguous legend with column-specific definitions. | Pending | OPEN | OPEN | +| 11 | PRRT_kwDOGp2yqc6S3k60 | `docs/pr-reviews/pr-2020-copilot-suggestions.md` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629126625 | Make tracker column meanings unambiguous. | action: replaced the ambiguous legend with column-specific definitions. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629280599 | DONE | RESOLVED | +| 12 | PRRT_kwDOGp2yqc6S32cm | `.github/skills/dev/git-workflow/run-linters/references/linters.md` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629225537 | Synchronize the documented portable formatter command. | action: documented `LC_ALL=C sort -u`. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629282267 | DONE | RESOLVED | +| 13 | PRRT_kwDOGp2yqc6S32dU | `contrib/dev-tools/git/tests/test-format-project-words.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629225593 | Use portable test assertion options. | action: replaced GNU-only `diff` and `grep` options. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629283760 | DONE | RESOLVED | +| 14 | PRRT_kwDOGp2yqc6S32dt | `contrib/dev-tools/git/tests/test-format-project-words.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629225631 | Use portable `grep` options. | action: replaced GNU-only `grep` options. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629285275 | DONE | RESOLVED | +| 15 | PRRT_kwDOGp2yqc6S32eH | `contrib/dev-tools/git/tests/test-format-project-words.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629225665 | Use portable `grep` options. | action: replaced GNU-only `grep` options. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629287113 | DONE | RESOLVED | +| 16 | PRRT_kwDOGp2yqc6S32ec | `contrib/dev-tools/git/tests/test-format-project-words.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629225692 | Use portable test assertion options. | action: replaced GNU-only `diff` and `grep` options. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629290234 | DONE | RESOLVED | +| 17 | PRRT_kwDOGp2yqc6S32eo | `contrib/dev-tools/git/tests/test-format-project-words.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629225706 | Use portable `grep` options. | action: replaced GNU-only `grep` options. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629305692 | DONE | RESOLVED | +| 18 | PRRT_kwDOGp2yqc6S32e3 | `contrib/dev-tools/git/tests/test-format-project-words.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629225730 | Use portable `grep` options. | action: replaced GNU-only `grep` options. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629307405 | DONE | RESOLVED | ## Notes From 577c3337574b4a84f2107139a3315f7ffc683a22 Mon Sep 17 00:00:00 2001 From: Jose Celano Date: Wed, 22 Jul 2026 11:09:04 +0100 Subject: [PATCH 13/19] fix(git): retain hook infrastructure exit codes --- contrib/dev-tools/git/hooks/pre-commit.sh | 2 +- .../git/tests/test-format-project-words.sh | 34 ++++++++++++++++++- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/contrib/dev-tools/git/hooks/pre-commit.sh b/contrib/dev-tools/git/hooks/pre-commit.sh index ccf663e97..9fc4c4509 100755 --- a/contrib/dev-tools/git/hooks/pre-commit.sh +++ b/contrib/dev-tools/git/hooks/pre-commit.sh @@ -347,7 +347,7 @@ for i in "${!STEPS[@]}"; do else step_exit_code=$? overall_status="fail" - exit_code=1 + exit_code=${step_exit_code} failed_step_name="${description}" failed_step_exit_code=${step_exit_code} break diff --git a/contrib/dev-tools/git/tests/test-format-project-words.sh b/contrib/dev-tools/git/tests/test-format-project-words.sh index 1cfe20f98..62eeb8498 100755 --- a/contrib/dev-tools/git/tests/test-format-project-words.sh +++ b/contrib/dev-tools/git/tests/test-format-project-words.sh @@ -4,7 +4,7 @@ set -euo pipefail PROJECT_ROOT=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/../../../.." && pwd) -TEST_DIRECTORY=$(mktemp -d) +TEST_DIRECTORY=$(mktemp -d "${TMPDIR:-/tmp}/test-format-project-words.XXXXXX") trap 'rm -rf "${TEST_DIRECTORY}"' EXIT create_fixture() { @@ -143,6 +143,37 @@ EOF ! grep -F -q "The formatter changed project-words.txt." "${fixture_root}/hook-output.txt" } +it_should_report_infrastructure_failures_with_their_exit_code_in_json() { + # Arrange + local fixture_root + fixture_root=$(create_fixture "hook-log-mktemp-failure-json") + printf 'Alpha\nzebra\n' >"${fixture_root}/project-words.txt" + create_successful_command_stubs "${fixture_root}" + cat >"${fixture_root}/bin/mktemp" <<'EOF' +#!/usr/bin/env bash +if [[ "$1" == *pre-commit-* ]]; then + exit 2 +fi +exec /usr/bin/mktemp "$@" +EOF + chmod +x "${fixture_root}/bin/mktemp" + + # Act + if ( + cd "${fixture_root}" || exit + PATH="${fixture_root}/bin:${PATH}" \ + TEST_COMMAND_LOG="${fixture_root}/commands.log" \ + TORRUST_GIT_HOOKS_LOG_DIR="${fixture_root}/logs" \ + ./contrib/dev-tools/git/hooks/pre-commit.sh --format=json >"${fixture_root}/hook-output.txt" 2>&1 + ); then + printf 'Expected pre-commit hook to fail when it cannot create a step log.\n' >&2 + return 1 + fi + + # Assert + grep -F -q '"exit_code": 2' "${fixture_root}/hook-output.txt" +} + it_should_continue_pre_commit_checks_when_dictionary_is_already_formatted() { # Arrange local fixture_root @@ -169,6 +200,7 @@ it_should_report_success_when_dictionary_is_already_formatted it_should_report_a_temp_file_creation_failure it_should_abort_pre_commit_and_request_restaging_when_dictionary_is_formatted it_should_not_mislabel_log_creation_failures_as_dictionary_changes +it_should_report_infrastructure_failures_with_their_exit_code_in_json it_should_continue_pre_commit_checks_when_dictionary_is_already_formatted printf 'All formatter and pre-commit hook tests passed.\n' \ No newline at end of file From 441f1bd1b467fa3654a6a50dad885de42ffd3872 Mon Sep 17 00:00:00 2001 From: Jose Celano Date: Wed, 22 Jul 2026 11:11:30 +0100 Subject: [PATCH 14/19] docs(review): finalize PR #2020 suggestions audit --- docs/pr-reviews/pr-2020-copilot-suggestions.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/pr-reviews/pr-2020-copilot-suggestions.md b/docs/pr-reviews/pr-2020-copilot-suggestions.md index c3b48ce0b..19874d2f8 100644 --- a/docs/pr-reviews/pr-2020-copilot-suggestions.md +++ b/docs/pr-reviews/pr-2020-copilot-suggestions.md @@ -32,6 +32,7 @@ Column legend: - 2026-07-22: Started processing six Copilot suggestions. - 2026-07-22: Applied the accepted fixes in signed commit `b917355c` and replied to and resolved all six original threads. - 2026-07-22: Processed all follow-up Copilot threads opened after subsequent pushes; every accepted change was committed, validated, replied to, and resolved. +- 2026-07-22: Processed the final hook JSON and BSD `mktemp` portability suggestions in signed commit `53c0a6e6`. ## Suggestions @@ -55,6 +56,8 @@ Column legend: | 16 | PRRT_kwDOGp2yqc6S32ec | `contrib/dev-tools/git/tests/test-format-project-words.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629225692 | Use portable test assertion options. | action: replaced GNU-only `diff` and `grep` options. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629290234 | DONE | RESOLVED | | 17 | PRRT_kwDOGp2yqc6S32eo | `contrib/dev-tools/git/tests/test-format-project-words.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629225706 | Use portable `grep` options. | action: replaced GNU-only `grep` options. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629305692 | DONE | RESOLVED | | 18 | PRRT_kwDOGp2yqc6S32e3 | `contrib/dev-tools/git/tests/test-format-project-words.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629225730 | Use portable `grep` options. | action: replaced GNU-only `grep` options. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629307405 | DONE | RESOLVED | +| 19 | PRRT_kwDOGp2yqc6S4CoL | `contrib/dev-tools/git/hooks/pre-commit.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629295494 | Preserve infrastructure errors in JSON results. | action: propagated the actual failed-step exit code. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629362577 | DONE | RESOLVED | +| 20 | PRRT_kwDOGp2yqc6S4Coq | `contrib/dev-tools/git/tests/test-format-project-words.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629295532 | Use a portable test directory `mktemp` template. | action: supplied an explicit BSD-compatible template. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629365111 | DONE | RESOLVED | ## Notes From 55def235d8c99dcce5315e1dead9a1a1fa9bcef1 Mon Sep 17 00:00:00 2001 From: Jose Celano Date: Wed, 22 Jul 2026 11:14:48 +0100 Subject: [PATCH 15/19] docs(issues): link #2019 to PR #2020 --- .../open/2019-automatically-format-project-dictionary/ISSUE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/issues/open/2019-automatically-format-project-dictionary/ISSUE.md b/docs/issues/open/2019-automatically-format-project-dictionary/ISSUE.md index cb91120da..7c204e527 100644 --- a/docs/issues/open/2019-automatically-format-project-dictionary/ISSUE.md +++ b/docs/issues/open/2019-automatically-format-project-dictionary/ISSUE.md @@ -6,7 +6,7 @@ priority: p2 github-issue: 2019 spec-path: docs/issues/open/2019-automatically-format-project-dictionary/ISSUE.md branch: "2019-automatically-format-project-dictionary" -related-pr: null +related-pr: 2020 last-updated-utc: 2026-07-22 00:00 semantic-links: skill-links: From 458be87bea4d44f5c97f36645e06f1625860cd16 Mon Sep 17 00:00:00 2001 From: Jose Celano Date: Wed, 22 Jul 2026 11:17:05 +0100 Subject: [PATCH 16/19] docs(review): record final PR #2020 responses --- .../pr-reviews/pr-2020-copilot-suggestions.md | 47 ++++++++++--------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/docs/pr-reviews/pr-2020-copilot-suggestions.md b/docs/pr-reviews/pr-2020-copilot-suggestions.md index 19874d2f8..0fb0b4cf8 100644 --- a/docs/pr-reviews/pr-2020-copilot-suggestions.md +++ b/docs/pr-reviews/pr-2020-copilot-suggestions.md @@ -33,31 +33,34 @@ Column legend: - 2026-07-22: Applied the accepted fixes in signed commit `b917355c` and replied to and resolved all six original threads. - 2026-07-22: Processed all follow-up Copilot threads opened after subsequent pushes; every accepted change was committed, validated, replied to, and resolved. - 2026-07-22: Processed the final hook JSON and BSD `mktemp` portability suggestions in signed commit `53c0a6e6`. +- 2026-07-22: Processed the issue metadata and dictionary typo suggestions in signed commit `57ed3b05`. ## Suggestions -| # | Thread ID | Path | URL | Suggestion Summary | Decision | Reply URL | Status | Thread State | -| --- | --------------------- | ------------------------------------------------------------------ | --------------------------------------------------------------------------- | ------------------------------------------------------------ | ---------------------------------------------------------------------- | --------------------------------------------------------------------------- | ------ | ------------ | -| 1 | PRRT_kwDOGp2yqc6S2_XP | `contrib/dev-tools/git/tests/test-format-project-words.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628911184 | Ensure assertions fail the test script. | action: enabled fail-fast shell execution. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628954196 | DONE | RESOLVED | -| 2 | PRRT_kwDOGp2yqc6S2_Xn | `contrib/dev-tools/git/format-project-words.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628911225 | Replace the dictionary atomically. | action: used a same-directory temporary file and `mv`. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628955657 | DONE | RESOLVED | -| 3 | PRRT_kwDOGp2yqc6S2_X4 | `contrib/dev-tools/git/hooks/pre-commit.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628911249 | Do not mislabel formatter operational errors as changes. | action: show restaging guidance only for formatter exit code 1. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628957067 | DONE | RESOLVED | -| 4 | PRRT_kwDOGp2yqc6S2_YS | `.github/skills/dev/git-workflow/run-pre-commit-checks/SKILL.md` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628911279 | Synchronize documented hook steps. | action: added `cargo deny check bans` and the current machete command. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628958264 | DONE | RESOLVED | -| 5 | PRRT_kwDOGp2yqc6S2_Yt | `docs/issues/open/2019-automatically-format-project-dictionary.md` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628911319 | Keep completed acceptance criteria consistent with evidence. | action: marked verified criteria complete. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628959344 | DONE | RESOLVED | -| 6 | PRRT_kwDOGp2yqc6S2_ZL | `docs/issues/open/2019-automatically-format-project-dictionary.md` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628911359 | Replace stale pending acceptance-verification entries. | action: recorded completion evidence. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628960975 | DONE | RESOLVED | -| 7 | PRRT_kwDOGp2yqc6S3Lr0 | `contrib/dev-tools/git/format-project-words.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628981491 | Report temporary-file creation failures explicitly. | action: added the diagnostic and focused test coverage. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629010458 | DONE | RESOLVED | -| 8 | PRRT_kwDOGp2yqc6S3LsT | `docs/issues/open/2019-automatically-format-project-dictionary.md` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628981533 | Align the issue specification with the documented layout. | action: moved the spec to its documented `ISSUE.md` folder layout. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629239329 | DONE | RESOLVED | -| 9 | PRRT_kwDOGp2yqc6S3T8_ | `contrib/dev-tools/git/hooks/pre-commit.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629029141 | Retain the exact failed step exit code. | action: captured the `run_step` exit code directly. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629242405 | DONE | RESOLVED | -| 10 | PRRT_kwDOGp2yqc6S3dJZ | `contrib/dev-tools/git/format-project-words.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629081831 | Support non-GNU local toolchains. | action: replaced GNU-only options with portable equivalents. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629243737 | DONE | RESOLVED | -| 11 | PRRT_kwDOGp2yqc6S3k60 | `docs/pr-reviews/pr-2020-copilot-suggestions.md` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629126625 | Make tracker column meanings unambiguous. | action: replaced the ambiguous legend with column-specific definitions. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629280599 | DONE | RESOLVED | -| 12 | PRRT_kwDOGp2yqc6S32cm | `.github/skills/dev/git-workflow/run-linters/references/linters.md` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629225537 | Synchronize the documented portable formatter command. | action: documented `LC_ALL=C sort -u`. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629282267 | DONE | RESOLVED | -| 13 | PRRT_kwDOGp2yqc6S32dU | `contrib/dev-tools/git/tests/test-format-project-words.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629225593 | Use portable test assertion options. | action: replaced GNU-only `diff` and `grep` options. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629283760 | DONE | RESOLVED | -| 14 | PRRT_kwDOGp2yqc6S32dt | `contrib/dev-tools/git/tests/test-format-project-words.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629225631 | Use portable `grep` options. | action: replaced GNU-only `grep` options. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629285275 | DONE | RESOLVED | -| 15 | PRRT_kwDOGp2yqc6S32eH | `contrib/dev-tools/git/tests/test-format-project-words.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629225665 | Use portable `grep` options. | action: replaced GNU-only `grep` options. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629287113 | DONE | RESOLVED | -| 16 | PRRT_kwDOGp2yqc6S32ec | `contrib/dev-tools/git/tests/test-format-project-words.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629225692 | Use portable test assertion options. | action: replaced GNU-only `diff` and `grep` options. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629290234 | DONE | RESOLVED | -| 17 | PRRT_kwDOGp2yqc6S32eo | `contrib/dev-tools/git/tests/test-format-project-words.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629225706 | Use portable `grep` options. | action: replaced GNU-only `grep` options. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629305692 | DONE | RESOLVED | -| 18 | PRRT_kwDOGp2yqc6S32e3 | `contrib/dev-tools/git/tests/test-format-project-words.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629225730 | Use portable `grep` options. | action: replaced GNU-only `grep` options. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629307405 | DONE | RESOLVED | -| 19 | PRRT_kwDOGp2yqc6S4CoL | `contrib/dev-tools/git/hooks/pre-commit.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629295494 | Preserve infrastructure errors in JSON results. | action: propagated the actual failed-step exit code. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629362577 | DONE | RESOLVED | -| 20 | PRRT_kwDOGp2yqc6S4Coq | `contrib/dev-tools/git/tests/test-format-project-words.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629295532 | Use a portable test directory `mktemp` template. | action: supplied an explicit BSD-compatible template. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629365111 | DONE | RESOLVED | +| # | Thread ID | Path | URL | Suggestion Summary | Decision | Reply URL | Status | Thread State | +| --- | --------------------- | ------------------------------------------------------------------- | --------------------------------------------------------------------------- | ------------------------------------------------------------ | ----------------------------------------------------------------------- | --------------------------------------------------------------------------- | ------ | ------------ | +| 1 | PRRT_kwDOGp2yqc6S2_XP | `contrib/dev-tools/git/tests/test-format-project-words.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628911184 | Ensure assertions fail the test script. | action: enabled fail-fast shell execution. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628954196 | DONE | RESOLVED | +| 2 | PRRT_kwDOGp2yqc6S2_Xn | `contrib/dev-tools/git/format-project-words.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628911225 | Replace the dictionary atomically. | action: used a same-directory temporary file and `mv`. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628955657 | DONE | RESOLVED | +| 3 | PRRT_kwDOGp2yqc6S2_X4 | `contrib/dev-tools/git/hooks/pre-commit.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628911249 | Do not mislabel formatter operational errors as changes. | action: show restaging guidance only for formatter exit code 1. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628957067 | DONE | RESOLVED | +| 4 | PRRT_kwDOGp2yqc6S2_YS | `.github/skills/dev/git-workflow/run-pre-commit-checks/SKILL.md` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628911279 | Synchronize documented hook steps. | action: added `cargo deny check bans` and the current machete command. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628958264 | DONE | RESOLVED | +| 5 | PRRT_kwDOGp2yqc6S2_Yt | `docs/issues/open/2019-automatically-format-project-dictionary.md` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628911319 | Keep completed acceptance criteria consistent with evidence. | action: marked verified criteria complete. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628959344 | DONE | RESOLVED | +| 6 | PRRT_kwDOGp2yqc6S2_ZL | `docs/issues/open/2019-automatically-format-project-dictionary.md` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628911359 | Replace stale pending acceptance-verification entries. | action: recorded completion evidence. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628960975 | DONE | RESOLVED | +| 7 | PRRT_kwDOGp2yqc6S3Lr0 | `contrib/dev-tools/git/format-project-words.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628981491 | Report temporary-file creation failures explicitly. | action: added the diagnostic and focused test coverage. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629010458 | DONE | RESOLVED | +| 8 | PRRT_kwDOGp2yqc6S3LsT | `docs/issues/open/2019-automatically-format-project-dictionary.md` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628981533 | Align the issue specification with the documented layout. | action: moved the spec to its documented `ISSUE.md` folder layout. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629239329 | DONE | RESOLVED | +| 9 | PRRT*kwDOGp2yqc6S3T8* | `contrib/dev-tools/git/hooks/pre-commit.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629029141 | Retain the exact failed step exit code. | action: captured the `run_step` exit code directly. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629242405 | DONE | RESOLVED | +| 10 | PRRT_kwDOGp2yqc6S3dJZ | `contrib/dev-tools/git/format-project-words.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629081831 | Support non-GNU local toolchains. | action: replaced GNU-only options with portable equivalents. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629243737 | DONE | RESOLVED | +| 11 | PRRT_kwDOGp2yqc6S3k60 | `docs/pr-reviews/pr-2020-copilot-suggestions.md` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629126625 | Make tracker column meanings unambiguous. | action: replaced the ambiguous legend with column-specific definitions. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629280599 | DONE | RESOLVED | +| 12 | PRRT_kwDOGp2yqc6S32cm | `.github/skills/dev/git-workflow/run-linters/references/linters.md` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629225537 | Synchronize the documented portable formatter command. | action: documented `LC_ALL=C sort -u`. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629282267 | DONE | RESOLVED | +| 13 | PRRT_kwDOGp2yqc6S32dU | `contrib/dev-tools/git/tests/test-format-project-words.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629225593 | Use portable test assertion options. | action: replaced GNU-only `diff` and `grep` options. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629283760 | DONE | RESOLVED | +| 14 | PRRT_kwDOGp2yqc6S32dt | `contrib/dev-tools/git/tests/test-format-project-words.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629225631 | Use portable `grep` options. | action: replaced GNU-only `grep` options. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629285275 | DONE | RESOLVED | +| 15 | PRRT_kwDOGp2yqc6S32eH | `contrib/dev-tools/git/tests/test-format-project-words.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629225665 | Use portable `grep` options. | action: replaced GNU-only `grep` options. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629287113 | DONE | RESOLVED | +| 16 | PRRT_kwDOGp2yqc6S32ec | `contrib/dev-tools/git/tests/test-format-project-words.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629225692 | Use portable test assertion options. | action: replaced GNU-only `diff` and `grep` options. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629290234 | DONE | RESOLVED | +| 17 | PRRT_kwDOGp2yqc6S32eo | `contrib/dev-tools/git/tests/test-format-project-words.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629225706 | Use portable `grep` options. | action: replaced GNU-only `grep` options. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629305692 | DONE | RESOLVED | +| 18 | PRRT_kwDOGp2yqc6S32e3 | `contrib/dev-tools/git/tests/test-format-project-words.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629225730 | Use portable `grep` options. | action: replaced GNU-only `grep` options. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629307405 | DONE | RESOLVED | +| 19 | PRRT_kwDOGp2yqc6S4CoL | `contrib/dev-tools/git/hooks/pre-commit.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629295494 | Preserve infrastructure errors in JSON results. | action: propagated the actual failed-step exit code. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629362577 | DONE | RESOLVED | +| 20 | PRRT_kwDOGp2yqc6S4Coq | `contrib/dev-tools/git/tests/test-format-project-words.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629295532 | Use a portable test directory `mktemp` template. | action: supplied an explicit BSD-compatible template. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629365111 | DONE | RESOLVED | +| 21 | PRRT_kwDOGp2yqc6S4JkJ | `docs/issues/open/2019-automatically-format-project-dictionary/ISSUE.md` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629334908 | Link the issue specification to its implementation PR. | action: set `related-pr: 2020`. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629396136 | DONE | RESOLVED | +| 22 | PRRT_kwDOGp2yqc6S4Jkr | `project-words.txt` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629334953 | Remove the unreferenced dictionary typo. | action: removed `Unamed`. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629397148 | DONE | RESOLVED | ## Notes From e5b2f9543bfc5f54ed2ce51928396d3cae5a8b63 Mon Sep 17 00:00:00 2001 From: Jose Celano Date: Wed, 22 Jul 2026 11:44:16 +0100 Subject: [PATCH 17/19] docs(review): correct tracker thread ID --- .../pr-reviews/pr-2020-copilot-suggestions.md | 50 ++++++++++--------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/docs/pr-reviews/pr-2020-copilot-suggestions.md b/docs/pr-reviews/pr-2020-copilot-suggestions.md index 0fb0b4cf8..b5452d089 100644 --- a/docs/pr-reviews/pr-2020-copilot-suggestions.md +++ b/docs/pr-reviews/pr-2020-copilot-suggestions.md @@ -34,33 +34,35 @@ Column legend: - 2026-07-22: Processed all follow-up Copilot threads opened after subsequent pushes; every accepted change was committed, validated, replied to, and resolved. - 2026-07-22: Processed the final hook JSON and BSD `mktemp` portability suggestions in signed commit `53c0a6e6`. - 2026-07-22: Processed the issue metadata and dictionary typo suggestions in signed commit `57ed3b05`. +- 2026-07-22: Started processing the tracker thread-ID formatting suggestion. ## Suggestions -| # | Thread ID | Path | URL | Suggestion Summary | Decision | Reply URL | Status | Thread State | -| --- | --------------------- | ------------------------------------------------------------------- | --------------------------------------------------------------------------- | ------------------------------------------------------------ | ----------------------------------------------------------------------- | --------------------------------------------------------------------------- | ------ | ------------ | -| 1 | PRRT_kwDOGp2yqc6S2_XP | `contrib/dev-tools/git/tests/test-format-project-words.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628911184 | Ensure assertions fail the test script. | action: enabled fail-fast shell execution. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628954196 | DONE | RESOLVED | -| 2 | PRRT_kwDOGp2yqc6S2_Xn | `contrib/dev-tools/git/format-project-words.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628911225 | Replace the dictionary atomically. | action: used a same-directory temporary file and `mv`. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628955657 | DONE | RESOLVED | -| 3 | PRRT_kwDOGp2yqc6S2_X4 | `contrib/dev-tools/git/hooks/pre-commit.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628911249 | Do not mislabel formatter operational errors as changes. | action: show restaging guidance only for formatter exit code 1. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628957067 | DONE | RESOLVED | -| 4 | PRRT_kwDOGp2yqc6S2_YS | `.github/skills/dev/git-workflow/run-pre-commit-checks/SKILL.md` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628911279 | Synchronize documented hook steps. | action: added `cargo deny check bans` and the current machete command. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628958264 | DONE | RESOLVED | -| 5 | PRRT_kwDOGp2yqc6S2_Yt | `docs/issues/open/2019-automatically-format-project-dictionary.md` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628911319 | Keep completed acceptance criteria consistent with evidence. | action: marked verified criteria complete. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628959344 | DONE | RESOLVED | -| 6 | PRRT_kwDOGp2yqc6S2_ZL | `docs/issues/open/2019-automatically-format-project-dictionary.md` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628911359 | Replace stale pending acceptance-verification entries. | action: recorded completion evidence. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628960975 | DONE | RESOLVED | -| 7 | PRRT_kwDOGp2yqc6S3Lr0 | `contrib/dev-tools/git/format-project-words.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628981491 | Report temporary-file creation failures explicitly. | action: added the diagnostic and focused test coverage. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629010458 | DONE | RESOLVED | -| 8 | PRRT_kwDOGp2yqc6S3LsT | `docs/issues/open/2019-automatically-format-project-dictionary.md` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628981533 | Align the issue specification with the documented layout. | action: moved the spec to its documented `ISSUE.md` folder layout. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629239329 | DONE | RESOLVED | -| 9 | PRRT*kwDOGp2yqc6S3T8* | `contrib/dev-tools/git/hooks/pre-commit.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629029141 | Retain the exact failed step exit code. | action: captured the `run_step` exit code directly. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629242405 | DONE | RESOLVED | -| 10 | PRRT_kwDOGp2yqc6S3dJZ | `contrib/dev-tools/git/format-project-words.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629081831 | Support non-GNU local toolchains. | action: replaced GNU-only options with portable equivalents. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629243737 | DONE | RESOLVED | -| 11 | PRRT_kwDOGp2yqc6S3k60 | `docs/pr-reviews/pr-2020-copilot-suggestions.md` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629126625 | Make tracker column meanings unambiguous. | action: replaced the ambiguous legend with column-specific definitions. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629280599 | DONE | RESOLVED | -| 12 | PRRT_kwDOGp2yqc6S32cm | `.github/skills/dev/git-workflow/run-linters/references/linters.md` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629225537 | Synchronize the documented portable formatter command. | action: documented `LC_ALL=C sort -u`. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629282267 | DONE | RESOLVED | -| 13 | PRRT_kwDOGp2yqc6S32dU | `contrib/dev-tools/git/tests/test-format-project-words.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629225593 | Use portable test assertion options. | action: replaced GNU-only `diff` and `grep` options. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629283760 | DONE | RESOLVED | -| 14 | PRRT_kwDOGp2yqc6S32dt | `contrib/dev-tools/git/tests/test-format-project-words.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629225631 | Use portable `grep` options. | action: replaced GNU-only `grep` options. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629285275 | DONE | RESOLVED | -| 15 | PRRT_kwDOGp2yqc6S32eH | `contrib/dev-tools/git/tests/test-format-project-words.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629225665 | Use portable `grep` options. | action: replaced GNU-only `grep` options. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629287113 | DONE | RESOLVED | -| 16 | PRRT_kwDOGp2yqc6S32ec | `contrib/dev-tools/git/tests/test-format-project-words.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629225692 | Use portable test assertion options. | action: replaced GNU-only `diff` and `grep` options. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629290234 | DONE | RESOLVED | -| 17 | PRRT_kwDOGp2yqc6S32eo | `contrib/dev-tools/git/tests/test-format-project-words.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629225706 | Use portable `grep` options. | action: replaced GNU-only `grep` options. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629305692 | DONE | RESOLVED | -| 18 | PRRT_kwDOGp2yqc6S32e3 | `contrib/dev-tools/git/tests/test-format-project-words.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629225730 | Use portable `grep` options. | action: replaced GNU-only `grep` options. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629307405 | DONE | RESOLVED | -| 19 | PRRT_kwDOGp2yqc6S4CoL | `contrib/dev-tools/git/hooks/pre-commit.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629295494 | Preserve infrastructure errors in JSON results. | action: propagated the actual failed-step exit code. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629362577 | DONE | RESOLVED | -| 20 | PRRT_kwDOGp2yqc6S4Coq | `contrib/dev-tools/git/tests/test-format-project-words.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629295532 | Use a portable test directory `mktemp` template. | action: supplied an explicit BSD-compatible template. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629365111 | DONE | RESOLVED | -| 21 | PRRT_kwDOGp2yqc6S4JkJ | `docs/issues/open/2019-automatically-format-project-dictionary/ISSUE.md` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629334908 | Link the issue specification to its implementation PR. | action: set `related-pr: 2020`. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629396136 | DONE | RESOLVED | -| 22 | PRRT_kwDOGp2yqc6S4Jkr | `project-words.txt` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629334953 | Remove the unreferenced dictionary typo. | action: removed `Unamed`. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629397148 | DONE | RESOLVED | +| # | Thread ID | Path | URL | Suggestion Summary | Decision | Reply URL | Status | Thread State | +| --- | --------------------- | ------------------------------------------------------------------------ | --------------------------------------------------------------------------- | ------------------------------------------------------------ | ----------------------------------------------------------------------- | --------------------------------------------------------------------------- | ------ | ------------ | +| 1 | PRRT_kwDOGp2yqc6S2_XP | `contrib/dev-tools/git/tests/test-format-project-words.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628911184 | Ensure assertions fail the test script. | action: enabled fail-fast shell execution. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628954196 | DONE | RESOLVED | +| 2 | PRRT_kwDOGp2yqc6S2_Xn | `contrib/dev-tools/git/format-project-words.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628911225 | Replace the dictionary atomically. | action: used a same-directory temporary file and `mv`. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628955657 | DONE | RESOLVED | +| 3 | PRRT_kwDOGp2yqc6S2_X4 | `contrib/dev-tools/git/hooks/pre-commit.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628911249 | Do not mislabel formatter operational errors as changes. | action: show restaging guidance only for formatter exit code 1. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628957067 | DONE | RESOLVED | +| 4 | PRRT_kwDOGp2yqc6S2_YS | `.github/skills/dev/git-workflow/run-pre-commit-checks/SKILL.md` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628911279 | Synchronize documented hook steps. | action: added `cargo deny check bans` and the current machete command. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628958264 | DONE | RESOLVED | +| 5 | PRRT_kwDOGp2yqc6S2_Yt | `docs/issues/open/2019-automatically-format-project-dictionary.md` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628911319 | Keep completed acceptance criteria consistent with evidence. | action: marked verified criteria complete. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628959344 | DONE | RESOLVED | +| 6 | PRRT_kwDOGp2yqc6S2_ZL | `docs/issues/open/2019-automatically-format-project-dictionary.md` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628911359 | Replace stale pending acceptance-verification entries. | action: recorded completion evidence. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628960975 | DONE | RESOLVED | +| 7 | PRRT_kwDOGp2yqc6S3Lr0 | `contrib/dev-tools/git/format-project-words.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628981491 | Report temporary-file creation failures explicitly. | action: added the diagnostic and focused test coverage. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629010458 | DONE | RESOLVED | +| 8 | PRRT_kwDOGp2yqc6S3LsT | `docs/issues/open/2019-automatically-format-project-dictionary.md` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3628981533 | Align the issue specification with the documented layout. | action: moved the spec to its documented `ISSUE.md` folder layout. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629239329 | DONE | RESOLVED | +| 9 | PRRT_kwDOGp2yqc6S3T8 | `contrib/dev-tools/git/hooks/pre-commit.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629029141 | Retain the exact failed step exit code. | action: captured the `run_step` exit code directly. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629242405 | DONE | RESOLVED | +| 10 | PRRT_kwDOGp2yqc6S3dJZ | `contrib/dev-tools/git/format-project-words.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629081831 | Support non-GNU local toolchains. | action: replaced GNU-only options with portable equivalents. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629243737 | DONE | RESOLVED | +| 11 | PRRT_kwDOGp2yqc6S3k60 | `docs/pr-reviews/pr-2020-copilot-suggestions.md` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629126625 | Make tracker column meanings unambiguous. | action: replaced the ambiguous legend with column-specific definitions. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629280599 | DONE | RESOLVED | +| 12 | PRRT_kwDOGp2yqc6S32cm | `.github/skills/dev/git-workflow/run-linters/references/linters.md` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629225537 | Synchronize the documented portable formatter command. | action: documented `LC_ALL=C sort -u`. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629282267 | DONE | RESOLVED | +| 13 | PRRT_kwDOGp2yqc6S32dU | `contrib/dev-tools/git/tests/test-format-project-words.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629225593 | Use portable test assertion options. | action: replaced GNU-only `diff` and `grep` options. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629283760 | DONE | RESOLVED | +| 14 | PRRT_kwDOGp2yqc6S32dt | `contrib/dev-tools/git/tests/test-format-project-words.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629225631 | Use portable `grep` options. | action: replaced GNU-only `grep` options. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629285275 | DONE | RESOLVED | +| 15 | PRRT_kwDOGp2yqc6S32eH | `contrib/dev-tools/git/tests/test-format-project-words.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629225665 | Use portable `grep` options. | action: replaced GNU-only `grep` options. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629287113 | DONE | RESOLVED | +| 16 | PRRT_kwDOGp2yqc6S32ec | `contrib/dev-tools/git/tests/test-format-project-words.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629225692 | Use portable test assertion options. | action: replaced GNU-only `diff` and `grep` options. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629290234 | DONE | RESOLVED | +| 17 | PRRT_kwDOGp2yqc6S32eo | `contrib/dev-tools/git/tests/test-format-project-words.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629225706 | Use portable `grep` options. | action: replaced GNU-only `grep` options. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629305692 | DONE | RESOLVED | +| 18 | PRRT_kwDOGp2yqc6S32e3 | `contrib/dev-tools/git/tests/test-format-project-words.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629225730 | Use portable `grep` options. | action: replaced GNU-only `grep` options. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629307405 | DONE | RESOLVED | +| 19 | PRRT_kwDOGp2yqc6S4CoL | `contrib/dev-tools/git/hooks/pre-commit.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629295494 | Preserve infrastructure errors in JSON results. | action: propagated the actual failed-step exit code. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629362577 | DONE | RESOLVED | +| 20 | PRRT_kwDOGp2yqc6S4Coq | `contrib/dev-tools/git/tests/test-format-project-words.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629295532 | Use a portable test directory `mktemp` template. | action: supplied an explicit BSD-compatible template. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629365111 | DONE | RESOLVED | +| 21 | PRRT_kwDOGp2yqc6S4JkJ | `docs/issues/open/2019-automatically-format-project-dictionary/ISSUE.md` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629334908 | Link the issue specification to its implementation PR. | action: set `related-pr: 2020`. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629396136 | DONE | RESOLVED | +| 22 | PRRT_kwDOGp2yqc6S4Jkr | `project-words.txt` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629334953 | Remove the unreferenced dictionary typo. | action: removed `Unamed`. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629397148 | DONE | RESOLVED | +| 23 | PRRT_kwDOGp2yqc6S4Z4w | `docs/pr-reviews/pr-2020-copilot-suggestions.md` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629428258 | Remove Markdown asterisks from row 9's thread ID. | action: corrected the thread ID to its exact value. | — | OPEN | OPEN | ## Notes From 72108e8268b6e59f20f64726f61926656fa132b6 Mon Sep 17 00:00:00 2001 From: Jose Celano Date: Wed, 22 Jul 2026 11:52:45 +0100 Subject: [PATCH 18/19] docs(review): record PR #2020 thread resolution --- docs/pr-reviews/pr-2020-copilot-suggestions.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/pr-reviews/pr-2020-copilot-suggestions.md b/docs/pr-reviews/pr-2020-copilot-suggestions.md index b5452d089..4de142596 100644 --- a/docs/pr-reviews/pr-2020-copilot-suggestions.md +++ b/docs/pr-reviews/pr-2020-copilot-suggestions.md @@ -35,6 +35,7 @@ Column legend: - 2026-07-22: Processed the final hook JSON and BSD `mktemp` portability suggestions in signed commit `53c0a6e6`. - 2026-07-22: Processed the issue metadata and dictionary typo suggestions in signed commit `57ed3b05`. - 2026-07-22: Started processing the tracker thread-ID formatting suggestion. +- 2026-07-22: Corrected the tracker thread ID in signed commit `53909678`, replied to, and resolved the formatting suggestion. ## Suggestions @@ -62,7 +63,7 @@ Column legend: | 20 | PRRT_kwDOGp2yqc6S4Coq | `contrib/dev-tools/git/tests/test-format-project-words.sh` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629295532 | Use a portable test directory `mktemp` template. | action: supplied an explicit BSD-compatible template. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629365111 | DONE | RESOLVED | | 21 | PRRT_kwDOGp2yqc6S4JkJ | `docs/issues/open/2019-automatically-format-project-dictionary/ISSUE.md` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629334908 | Link the issue specification to its implementation PR. | action: set `related-pr: 2020`. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629396136 | DONE | RESOLVED | | 22 | PRRT_kwDOGp2yqc6S4Jkr | `project-words.txt` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629334953 | Remove the unreferenced dictionary typo. | action: removed `Unamed`. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629397148 | DONE | RESOLVED | -| 23 | PRRT_kwDOGp2yqc6S4Z4w | `docs/pr-reviews/pr-2020-copilot-suggestions.md` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629428258 | Remove Markdown asterisks from row 9's thread ID. | action: corrected the thread ID to its exact value. | — | OPEN | OPEN | +| 23 | PRRT_kwDOGp2yqc6S4Z4w | `docs/pr-reviews/pr-2020-copilot-suggestions.md` | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629428258 | Remove Markdown asterisks from row 9's thread ID. | action: corrected the thread ID to its exact value. | https://github.com/torrust/torrust-tracker/pull/2020#discussion_r3629575867 | DONE | RESOLVED | ## Notes From 35cc02a352b2ffc558708a23afbba22e2878945f Mon Sep 17 00:00:00 2001 From: Jose Celano Date: Wed, 22 Jul 2026 12:41:32 +0100 Subject: [PATCH 19/19] chore(cspell): canonicalize project dictionary ordering --- project-words.txt | 220 +++++++++++++++++++++++----------------------- 1 file changed, 110 insertions(+), 110 deletions(-) diff --git a/project-words.txt b/project-words.txt index 64b0ae2fb..a9ad9aa3c 100644 --- a/project-words.txt +++ b/project-words.txt @@ -1,12 +1,118 @@ +ASMS +AUTOINCREMENT +Addrs +Agentic +Aideq +Arvid +Avicora +Azureus +Beránek +Biriukov +Bitflu +Bragilevsky +BuildKit +Buildx +CALLSITE +Celano +Cinstrument +Condvar +Containerfile +Cyberneering +DGRAM +DNSSEC +Deque +Dihc +Dijke +Dmqcd +EADDRINUSE +EINVAL +Eray +Freebox +Frostegård +Garnham +Gibibytes +Glrg +Graphviz +Grcov +HDRINCL +Hydranode +IPPROTO +IPV6 +Icelake +Intermodal +Irwe +Jakub +Joakim +JobManager +JoinSet +Karatay +Kibibytes +LOGNAME +LVJDMDAwMDAwMDAwMDAwMDAwMDE +Laravel +LoadTest +Lphant +MSRV +Mbps +Mebibytes +Naim +Norberg +PGID +PRRT +PUID +Pando +Publishability +QJSF +QUIC +Quickstart +RAII +REUSEPORT +RPIT +RUSTDOCFLAGS +RUSTFLAGS +Radeon +Rakshasa +Rasterbar +Registar +Rustls +Ryzen +SHLVL +Seedable +Shareaza +Signedness +Subissues +Swatinem +Swiftbit +TSIG +Tebibytes +Tera +Torrentstorm +Trackon +Trixie +UNCONN +Unamed +Unparker +Unsendable +VARCHAR +Vagaa +Vitaly +Vuze +WEBUI +Weidendorfer +Werror +Winsock +XBTT +Xacrimon +Xdebug +Xeon +Xtorrent +Xunlei acgnxtracker actix -Addrs adduser adminadmin adrs -Agentic agentskills -Aideq alekitto alives alloca @@ -17,17 +123,12 @@ aquasec aquasecurity argjson artefacts -Arvid asdh -ASMS asyn autoclean -AUTOINCREMENT autolinks automock autoremove -Avicora -Azureus backlinks bdecode behaviour @@ -36,35 +137,26 @@ bencode bencoded bencoding beps -Beránek bidirectionality binascii bindv6only binstall -Biriukov bitcode -Bitflu bools bottlenecked -Bragilevsky bufs buildid -BuildKit -Buildx byteorder callgrind -CALLSITE callsites camino canonicalize canonicalized categorisation cdylib -Celano certbot chihaya chrono -Cinstrument ciphertext clippy cloneable @@ -75,15 +167,12 @@ colours commiter completei composecheck -Condvar connectionless -Containerfile conv creds curr cvar cves -Cyberneering cyclomatic dashmap datagram @@ -94,16 +183,10 @@ dbname debuginfo defence depgraph -Deque dfsg -DGRAM -Dihc -Dijke distroless distros dler -Dmqcd -DNSSEC dockerhub doctest downloadedi @@ -111,8 +194,6 @@ dpkg dport dtolnay dylib -EADDRINUSE -EINVAL elif endgroup endianness @@ -120,7 +201,6 @@ envcontainer epoll eprint eprintln -Eray esac eventfd exploitability @@ -142,21 +222,13 @@ formatjson fput fputwc fract -Freebox frontmatter -Frostegård fscanf -Garnham gecos getaddrinfo gethostbyname ghac -Gibibytes -Glrg -Graphviz -Grcov hasher -HDRINCL healthcheck heaptrack hexdigit @@ -168,10 +240,8 @@ hotfixes hotspot hotspots httpclientpeerid -Hydranode hyperium hyperthread -Icelake iiiiiiiiiiiiiiiiiiiid iiiiiiiiiiiiiiiipp iiiiiiiiiiiiiiiippe @@ -185,29 +255,18 @@ infohash infohashes infoschema initialisation -Intermodal intervali io_uring -IPPROTO -IPV6 -Irwe isready iterationsadd -Jakub jdbe -Joakim -JobManager -JoinSet josecelano kallsyms -Karatay kcachegrind kexec keyout -Kibibytes kptr ksys -Laravel lcov leafification leecher @@ -221,14 +280,8 @@ libsqlite libtorrent libz llist -LoadTest -LOGNAME -Lphant lscr -LVJDMDAwMDAwMDAwMDAwMDAwMDE matchmakes -Mbps -Mebibytes metainfo microbenchmark microbenchmarks @@ -244,13 +297,10 @@ mmdb mockall monomorphisation mprotect -MSRV multimap myacicontext mysqladmin mysqld -ñaca -Naim nanos newkey newtrackon @@ -264,7 +314,6 @@ nocapture nologin nonblocking nonroot -Norberg notnull nping nquery @@ -284,7 +333,6 @@ organisation organised ostr overengineered -Pando parallelisable parallelise parallelised @@ -294,7 +342,6 @@ peerlist peersld penalise pessimize -PGID pipefail pkey pkill @@ -305,19 +352,9 @@ prioritise programatik proot proto -PRRT -Publishability -PUID qbittorrent -QJSF -QUIC quickcheck -Quickstart -Radeon -RAII -Rakshasa randomised -Rasterbar readelf realpath reannounce @@ -327,7 +364,6 @@ recompiles recvfrom recvspace referer -Registar reorganisation reorganising repomix @@ -337,7 +373,6 @@ reqwest rerequests rescope reuseaddr -REUSEPORT ringbuf ringsize rlib @@ -345,33 +380,24 @@ rmem rngs rosegment routable -RPIT rsplit rstest rusqlite rustc rustdoc -RUSTDOCFLAGS -RUSTFLAGS rustfmt -Rustls rustup -Ryzen sarif savepath scanf sccache -Seedable sendto serde serialisation setgroups setsockopt -Shareaza sharktorrent shellcheck -SHLVL -Signedness skiplist slowloris socat @@ -384,23 +410,18 @@ srcset sscanf stabilised subissue -Subissues subkey subsec substeps summarising supertrait -Swatinem -Swiftbit syscall sysmalloc sysret taiki taplo tdyne -Tebibytes tempfile -Tera testcontainer testcontainers thirdparty @@ -410,38 +431,30 @@ tlnp tlsv toki toplevel -Torrentstorm torru torrust torrustracker trackerid -Trackon triaging trivy trivy-action trivy-results -Trixie trunc tryhackx -TSIG tslconfig ttwu typenum udpv ulnp -Unamed unconfigured -UNCONN underflows ungetwc uninit unittests unparked -Unparker unrecognised unrepresentable unreviewed -Unsendable unsync untuple unvalidated @@ -451,31 +464,18 @@ ureq urlencode uroot usize -Vagaa valgrind -VARCHAR -Vitaly vmlinux vtable vulns -Vuze wakelist wakeup walkdir webtorrent -WEBUI -Weidendorfer -Werror whitespaces -Winsock -Xacrimon -XBTT -Xdebug -Xeon -Xtorrent -Xunlei xxxxxxxxxxxxxxxxxxxxd yyyyyyyyyyyyyyyyyyyyd zerocopy zeroize zstd +ñaca