Skip to content

docs(issues): add specification for #2190 - #2193

Open
da2ce7 wants to merge 12 commits into
torrust:developfrom
da2ce7:2190-maintenance-frictions-cleanup-spec
Open

docs(issues): add specification for #2190#2193
da2ce7 wants to merge 12 commits into
torrust:developfrom
da2ce7:2190-maintenance-frictions-cleanup-spec

Conversation

@da2ce7

@da2ce7 da2ce7 commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

Related to #2190

Summary

This pull request adds the reviewed specification for issue #2190 and contains no implementation, so it does not resolve the issue.

The specification proposes clearing a verified batch of eight small, independent maintenance frictions in one review pass, and recording the two items that are not code changes so a maintainer can act on them deliberately. Every entry was re-verified against develop at revision f6b73e29 on 2026-09-09, and the evidence column records what was observed rather than what was reported; two candidates that had been proposed for the batch did not reproduce and are written up as dropped so the same ground is not re-covered.

The eight in-scope frictions are: a dictionary-formatter test suite that has been red on develop since it was moved beside its sensor, for two independent reasons; three developer-tool test suites that no orchestrator runs at all; a container-workflow push trigger still matching releases/**/*, so every package release push starts a job that immediately refuses itself at the semver guard; five live references that still place e2e_tests_runner, profiling, and qbittorrent_e2e_runner under src/bin/ after they moved into packages/e2e-tools; sixteen specification directories under docs/issues/open/ whose issues GitHub reports as closed; an explicit character-type generic in the workspace-coupling tool that cannot be quoted in a review discussion without arriving as text that would not compile; a script note that becomes untrue in the same pull request that makes it so; and a dictionary entry for a file that a recorded decision says will never exist.

The frictions are deliberately grouped rather than filed separately. They share a review context — small, low-risk, mechanical — and splitting them into a dozen issues would cost more maintainer attention than the defects themselves. They do not share an implementation: the plan is one commit per friction, with the sixteen archival moves isolated in their own commit, so a reviewer can accept or reject each row of the inventory without unpicking the rest.

Boundaries the specification draws

Five neighbouring pieces of work are named as out of scope with the issue that owns each: archival automation is #1774, external-link triage is #2185, the Docker E2E job repair is #2179, the folder-style specification migration is #2159, and the long-term check-harness and sensor architecture is EPIC #2003. The specification also records a stop condition: if placing the developer-tool suites in CI turns into a real question about where such tests belong rather than a one-step addition, the implementer raises it against #2003 instead of settling it inside a clean-up pull request.

Two maintainer-owned items are recorded rather than attempted from a pull request. The first is that the repository's allowed-actions allowlist pins taiki-e/install-action to an exact patch version, so no Dependabot bump of it can run and the resulting workflow terminations present as startup_failure — invisible in the ordinary check view, which lists only passing and skipped rows. The second is two Dependabot pull requests stalled since August behind the Docker E2E failure that #2179 fixes. One behavioural defect found while verifying the batch is recorded as related but separate, with a recommendation that it gets its own issue rather than being folded into a clean-up.

Files touched

Only docs/issues/. The branch adds docs/issues/open/2190-maintenance-frictions-cleanup/ISSUE.md and removes the draft it was renamed from, and no other file changes, so no source, test, workflow, or manifest is touched here.

Validation performed

linter all passes with exit code 0 at the branch tip in 19.0 s, covering markdown, local Markdown links and fragments via lychee, YAML, TOML, cspell, clippy, rustfmt, and shellcheck.

The full pre-commit gate ./contrib/dev-tools/git/hooks/pre-commit.sh passes with exit code 0 in 35.2 s, all six steps green: dictionary formatting, unused dependencies via cargo machete --with-metadata, workspace layer boundary bans via cargo deny check bans, all linters, the Containerfile hadolint check, and the workspace documentation tests.

The moved document contains no relative file links, only intra-document anchors and one absolute issue URL; every anchor was resolved against the document's own headings and every repository path named in inline code was checked to exist. The folder moved from docs/issues/drafts/<name>/ to docs/issues/open/<name>/, the same directory depth, and lychee confirms the result independently.

Copilot AI lite review requested due to automatic review settings September 10, 2026 08:08
@josecelano
josecelano self-requested a review September 10, 2026 08:18
@josecelano josecelano self-assigned this Sep 10, 2026

@josecelano josecelano left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Think this is a kind of global review of the repo and it addresses many different things I would propose to convert it into an EPIC and treat each sub-tasks as a sub-issue of the main EPIC. While doing the refactor consider if some of the tasks can naturally belong to other existing EPICs or even new ECPIs. So we should cluster the subtasks. Organizing the job by domain is better from the human point of view and also for AI agetns. In the agetns case you can keep the context for an ECPI and make the agent work in the subissues.

In the scope the issue says:

The eight code, configuration, and documentation frictions listed in [Friction Inventory](https://github.com/torrust/torrust-tracker/issues/2190#friction-inventory), each fixed or explicitly deferred with a linked issue.

It's fine to have an issue to make this inventory and process all the issues, but the output should be other ECPIs, issues, or subissues, removing from the scope to directly fix the problems in this issue implementations. This converts this issue in planing-only issue.

Another secondary advantage is not having big PRs, that are harder to review and fix even for AI.

Copilot stopped reviewing on behalf of da2ce7 due to an error September 10, 2026 08:28

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note

Copilot was unable to run its full agentic suite in this review.

Pull request overview

Adds a new folder-style issue specification for #2190 to track and execute a batch clean-up of small repository maintenance frictions (tooling/CI triggers/docs drift/issue archival), including scoped fixes, maintainer actions, and verification criteria.

Changes:

  • Introduces a structured issue spec describing eight in-scope “friction” fixes (F1–F8) with evidence and proposed resolutions.
  • Documents two maintainer-owned actions (A1–A2) and one related-but-separate behavioral defect to be filed independently.
  • Defines an implementation plan, commit breakdown, verification plan, and acceptance criteria for the batch.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread docs/issues/open/2190-maintenance-frictions-cleanup/ISSUE.md Outdated
@da2ce7

da2ce7 commented Sep 10, 2026

Copy link
Copy Markdown
Contributor Author

Agreed, and done. #2190 is now a planning-only EPIC: it produces the subissues and implements nothing itself. The specification is renamed to EPIC.md, the "fix the eight frictions in this pull request" scope is replaced by "produce the clustered subissues", and the verified inventory, maintainer actions, and dropped candidates stay as the evidence the subissues are written from.

The eleven items are clustered into eight clusters. Two clusters move to an existing EPIC, six stay under #2190, and one is a standalone issue.

Cluster Items Domain Parent Draft
C1 F5 Developer-tool checks: repairing an existing check EPIC #2003 2003-repair-project-dictionary-formatter-test-suite
C2 F1, F7 Developer-tool checks: invoking existing checks from CI EPIC #2003 2003-run-developer-tool-test-suites-in-ci
C3 F3 Workflow trigger correctness EPIC #2190 2190-narrow-container-workflow-release-branch-trigger
C4 F4, F8 Stale references left by completed moves and decisions EPIC #2190 2190-correct-stale-documentation-references
C5 F2 Issue-backlog archival EPIC #2190 2190-archive-closed-issue-specifications
C6 F6 Source hygiene for quotable artifacts EPIC #2190 2190-remove-unquotable-character-type-generic
C7 A1, A2 Repository administration; no repository change EPIC #2190 2190-widen-workflow-actions-allowlist-entry, 2190-resolve-stalled-dependency-update-pull-requests
C8 R1 Configuration error reporting None; standalone configuration-schema-version-error-ordering

All nine drafts are in this pull request under docs/issues/drafts/, each sized for one focused pull request and each naming its parent below its title.

Why C1 and C2 go to EPIC #2003. Its In Scope undertakes to "Evaluate check placement across pre-commit, pre-push, CI, and any future repository-policy or architecture-check category", and it explicitly permits the interim project dictionary formatter from #2019. F5 repairs that formatter's own test suite; C2 wires that suite and its two siblings into CI. Both also fit #2003's stated exception for additive, independently verifiable work that may proceed before the architecture decision, because neither selects a runner, cache, or enforcement platform. F7 rides with C2 because the dead note it removes is the one at lint-containerfile.sh:4 that names #2003 — it only becomes untrue once C2 lands.

Two candidates I considered for an existing EPIC and rejected. F3 (container workflow trigger) is not EPIC #1840: that EPIC's goal is pull request wait time, and the spurious run happens on package release branches, which are not on the pull request critical path. F4 (stale src/bin/ paths) is not EPIC #1669: its documentation audit covers docs/packages.md, packages/AGENTS.md, the extracted-packages tables, and the dependency diagram, and none of the five stale references is one of those. The reasoning for every cluster is written out in the EPIC's "Why Each Parent" section, so the assignments can be argued with rather than taken on trust.

What happens next, once the clustering looks right to you: the GitHub subissues are created from the approved drafts and linked under their parent EPIC, each draft moves from docs/issues/drafts/ to docs/issues/open/ under its assigned number, and #2003's subissue table gains the two rows it adopted. Nothing is filed yet — I would rather agree the clustering first than open nine issues and rearrange them afterwards.

Two things worth your call:

  1. Should the subissues be opened now, or after this specification pull request merges?
  2. Overhaul: Automation Tools and AI Agent Guardrails #2003's subissue table needs two new rows. I have kept them out of this pull request so it stays scoped to EPIC: Repository maintenance frictions clean-up #2190; say the word if you would rather they land here.

@da2ce7
da2ce7 requested a review from josecelano September 10, 2026 08:47
@da2ce7

da2ce7 commented Sep 10, 2026

Copy link
Copy Markdown
Contributor Author

Reshaped to follow your own EPICs: EPIC.md now carries the spine of #1840 and #1347 — Goal, Why This Is Needed, Scope, Subissues, Delivery Strategy, Progress Tracking, Acceptance Criteria, Risks and Trade-offs, References — plus one domain section, a compact Friction Inventory in the shape of #2003's Known Existing Issues, sitting where #1347 keeps Package Coverage Tracking.

The eight extra sections are gone and nothing with them: each item's evidence stays in the subissue draft that owns it, the per-parent argument is one line per row in the Subissues Notes column plus a paragraph of Delivery Strategy, the two candidates that did not reproduce are Out of Scope entries, and the ADR pointer moved to References. The frontmatter is now #1840's key set, with epic-owner: null since no maintainer has taken the EPIC yet, and the spec is 195 lines.

Head is 76dcf0a3.

Re-verify each reported friction against develop at f6b73e2 and record the
evidence inline: eight in-scope code, configuration, and documentation items;
two maintainer-owned actions that no pull request can perform; one behavioural
defect recommended for its own issue; and two candidates that no longer
reproduce.

Pre-commit checks run on the build server rather than this host, so the local
hook is skipped here; linter all and the pre-commit script are executed against
this commit as a separate gate.
Move the reviewed maintenance-frictions clean-up specification out of drafts
and into the open backlog under its assigned issue number, so the batch of
eight verified frictions, the two maintainer-owned actions, and the one
related-but-separate behavioural defect are tracked where implementation work
looks for them.

The specification records evidence per item against develop at f6b73e2 and
keeps one commit per friction, so a reviewer can accept or reject each row
independently.
… EPIC

The specification proposed fixing eight unrelated maintenance frictions in
one pull request. That shape makes review expensive and hides items that
already fall inside an existing EPIC's scope.

Rename the primary document to EPIC.md, restate the scope as planning only,
and add a Clusters section that assigns every inventory item to a domain
cluster and argues its parent from that parent's own stated scope. The
verified inventory, maintainer actions, related-but-separate defect, and
dropped candidates are preserved as the evidence behind the subissues.
Add one folder-style draft specification per cluster item: two adopted by
EPIC torrust#2003, six owned by EPIC torrust#2190, and one standalone issue for the
behavioural defect found while verifying the inventory.

Each draft is sized for a single focused pull request, names its parent
below its title, and carries its own scope, acceptance criteria, and
verification plan.
EPIC torrust#1840 and EPIC torrust#1347 establish the shape an EPIC in this repository
takes: Goal, Why This Is Needed, Scope, Subissues, Delivery Strategy,
Progress Tracking, Acceptance Criteria, Risks and Trade-offs, References,
plus at most a domain section where the EPIC genuinely needs one — a
package inventory in torrust#1669, Known Existing Issues in torrust#2003. EPIC torrust#2190
carried eight sections beyond that spine, and its inventory duplicated
evidence the subissue drafts already hold.

Collapse the friction, maintainer-action, related-but-separate, cluster,
per-parent-argument, and handoff sections into one compact Friction
Inventory, shaped like torrust#2003's Known Existing Issues: one row per item,
naming the draft that holds its evidence and the EPIC that owns it. The
per-parent argument moves into the Subissues table's Notes column and one
paragraph of Delivery Strategy; the two candidates that did not reproduce
become Out of Scope entries, the form torrust#2003 uses for work it excludes; the
ADR pointer moves to References, where every model EPIC keeps one. No EPIC
in the repository, and not the EPIC template, carries an Architectural
Decisions section — that section belongs to child specs.

Reduce the frontmatter to the key set torrust#1840, torrust#1347 and the template share.
epic-owner stays null: the template's default is written for an EPIC no
maintainer has adopted, and naming one would assert what is not yet true.

Add the sentence torrust#2003 uses to keep proposed subissues from becoming
GitHub issues before a maintainer approves them, and record the alignment
in the progress log. The drafts' progress logs lose the cluster
identifiers, which no longer exist, and name their inventory items
instead. Every fact survives; only the shape changes.
…that made them

The restructuring entry in EPIC torrust#2190's progress log, and the drafting
entry in each of the nine subissue drafts, carried 09:30 UTC. The commit
that made both, `d8a2058e`, is dated 08:43 UTC, and the entry recording
this alignment is later still, so the log read out of order.

Date each entry from the commit that produced it, so git remains the
provenance of the record and the log reads in the order the work happened.
…anning guides

The EPIC was reshaped to the spine the maintainers' EPICs use, which left
four requirements of the written guides unmet.

The create-issue skill's spec-only-PR step requires the specification
frontmatter `branch:` to name the `-spec` branch, so it is restored. No
maintainer EPIC carries the key, but the example is silent where the skill
is explicit, and AGENTS.md fixes the same branch name independently.

The same skill requires an `Architectural Decisions` section in a drafted
specification and carves out only `Commit Points` for EPICs, so the section
is added; the paragraph that had carried its content inside Delivery
Strategy moves into it rather than being duplicated.

Phase 2 now names the GitHub sub-issues API as the linking mechanism, which
the link-subissue-to-parent-issue skill defines, and records that a source
artifact gains its `issue: #<number>` marker when the subissue number
exists. A draft-path marker added earlier would have to be rewritten
immediately, which is what the semantic-link convention warns against.

The Acceptance Verification table covered seven of the nine acceptance
criteria; the two missing rows are added so every criterion has an ID and
an evidence slot. The first three workflow checkpoints take the EPIC
template's wording.
…he two handed drafts

The create-issue skill sets `epic:` only for an explicitly established
subissue and forbids inferring a parent from related issues or topic
overlap. These two drafts name EPIC torrust#2003 as parent on an argument from
that EPIC's own stated scope, which is stronger than overlap but is not yet
accepted by its maintainer, and EPIC torrust#2190 still carries the unticked
checkpoint for that review.

The parent line now says so, so a reader of the draft alone sees the
assignment as proposed rather than settled. The other seven drafts are
unaffected: six name the EPIC that produced them, and the parentless draft
already states it has no parent and why.
Record the audit against the planning guides in the progress log and move
`last-updated-utc` to the time of the change.
…rly candidates

EPIC torrust#2190's inventory found a developer-tool test suite that has been red
on `develop` since it was moved, and three such suites that no orchestrator
runs. Both sit inside this EPIC's stated scope for check placement across
pre-commit, pre-push, and CI, and both meet its exception for low-risk,
additive, independently verifiable work that selects no shared runner,
cache, or enforcement platform, so they are recorded here rather than in the
EPIC that found them.

The rows carry `#[To be assigned]` and their draft paths, the shape EPIC
numbers when the issues are created. EPIC torrust#2190's checkpoints are split to
match: the rows exist now, the numbers arrive in its Phase 2.

The table is re-aligned because the adopted titles are wider than every
existing entry.
@da2ce7
da2ce7 force-pushed the 2190-maintenance-frictions-cleanup-spec branch from 76dcf0a to c622139 Compare September 10, 2026 09:56
@da2ce7

da2ce7 commented Sep 10, 2026

Copy link
Copy Markdown
Contributor Author

Audited the EPIC, the nine subissue drafts, and the GitHub-side procedure against the repository's guides — the create-issue, write-markdown-docs, and link-subissue-to-parent-issue skills, docs/issues/README.md and the drafts//open/ READMEs, docs/templates/EPIC.md and ISSUE.md, and docs/skills/semantic-skill-link-convention.md. Where a guide and the maintainers' example EPICs disagreed, the guide won; the two places that happened are noted below.

Head is c6221390, rebased onto develop at 89d45145.

What the guides required, and what changed

branch: is back in the EPIC frontmatter. The create-issue skill's spec-only-PR step is explicit at SKILL.md:249-251: name the branch {issue-number}-{short-description}-spec and "Set the issue specification frontmatter branch: value to this same -spec branch name". It was dropped because no maintainer EPIC carries the key — but the examples are silent where the skill is explicit, and AGENTS.md:312-313 fixes the same branch name independently. docs/skills/semantic-skill-link-convention.md:134-143 omits branch: from the required-EPIC-field list, which makes it not-required rather than not-allowed; the skill's instruction is the specific one and it wins.

An Architectural Decisions section was added. create-issue/SKILL.md:106-121 lists the sections a draft must initialize before review, and carves EPICs out of exactly one of them — Commit Points, because "EPICs track delivery through Subissues". Architectural Decisions has no such carve-out. docs/templates/EPIC.md has no such section and neither does any maintainer EPIC, so this is the second guide-versus-example conflict; the skill wins, and the paragraph that had been carrying the content inside Delivery Strategy moved into the new section rather than being duplicated.

Phase 2 now names the mechanism: children are attached with the GitHub sub-issues API per the link-subissue-to-parent-issue skill, which is how both #1840's and #2003's existing children are in fact attached. It also records that a source artifact gains its issue: #<number> marker once the number exists — write-markdown-docs/SKILL.md:75-79 asks for the marker, and semantic-skill-link-convention.md:42-50 says not to retain a draft path after the issue is created, so adding an issue-spec: path marker now would only have to be rewritten days later.

The Acceptance Verification table covered seven of the nine acceptance criteria; the two missing rows were added so every criterion has an ID and an evidence slot, matching EPIC #1347. The first three workflow checkpoints took the EPIC template's wording.

The two drafts handed to EPIC #2003 now say the adoption is proposed and pending that EPIC's maintainer review, because create-issue/SKILL.md:170-171 sets epic: only for an "explicitly established" subissue and forbids inferring a parent from topic overlap. The argument from #2003's own stated scope is stronger than overlap, but it is not yet accepted, and a reader of the draft alone should see that.

EPIC #2003's approved-early-candidates table now carries the two adopted rows, as rows 8 and 9, with #[To be assigned] and their draft paths — the shape #1840 uses for a child whose issue does not exist yet. That table is the right home: its preamble already covers "low-risk, additive, independently verifiable work" that "may be created and implemented now", which is the exception both items were argued under.

Three design calls, answered from the guides

Subissues that change no repository file (the allowlist entry, the stalled dependency PRs). The guides neither require nor forbid it. What they do require is a commit policy, and docs/templates/ISSUE.md:91 supplies the shape directly: "Record a justified no-change decision in the task's evidence without creating an empty commit." Both drafts already state the no-change outcome and record it that way, so they are well-formed issues rather than table rows. Keeping them as issues gives each an owner, an acceptance criterion, and a visible state, which a bullet in an EPIC body does not.

The parentless draft. docs/issues/drafts/README.md:20-25 is direct: "Use an unnumbered descriptive folder for a draft... Do not infer a parent EPIC from related work; leave epic: null and use an unnumbered name until the relationship is established." configuration-schema-version-error-ordering does exactly that — unnumbered folder, epic: null, and a line under its title saying it has no parent and why. No change needed.

Two fixes in one draft (the stale paths and the retired dictionary entry). The guides set no rule by count. docs/templates/ISSUE.md:82-84 sets it by coherence: a commit point "completes one independently reviewable behavior, refactor, or evidence increment; do not group unrelated changes merely to reduce commit count." Both items are documentation drift left by a decision that has already been taken, they are verified by the same three linters, and they are reverted together or not at all. They stay in one draft, with a commit point each.

Verification

linter all passes and git diff --check is clean on the branch. Every relative link and every docs/ path named in the changed files resolves, checked by script over all 258 references. Two exceptions are deliberate: the progress-log line and the Copilot-review table both name .../2190-maintenance-frictions-cleanup/ISSUE.md, the path before the rename to EPIC.md, which create-issue/SKILL.md:320-322 preserves — "Retain paths in immutable historical records only when they accurately describe the path at that time."

The branch is rebased onto develop at 89d45145, so it applies cleanly and its merge base is that commit. The only conflict was docs/issues/open/2003-overhaul-guardrails-and-automation/EPIC.md, where develop had meanwhile added a row for #2185 and reformatted the EPIC tables. It was resolved by taking develop's file whole and re-applying the two adopted rows against the current table, so they are numbered 8 and 9 after the existing seven, and the table is re-aligned to fit the wider titles. Every develop change is kept.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants