Project automation - AnnabiGihed/RaidManager GitHub Wiki
Generated from
docs/reference/project-automation.md. Edit that file in the repository: changes made in the wiki are overwritten.
The Raid Manager Project applies the Work Management and Delivery Specification (ADR-0026). This page documents how the Project is configured and what automation enforces; the specification is the authority for the rules themselves. Automation runs without a personal token or repository secret (specification §22).
Every item sits in one chain of native sub-issues, Epic → Feature → User Story, Improvement, Bug or Spike → Task, with
exactly one type: label (specification §2, §3, §15). The issue forms set the label and ask for the parent; add the
new issue as a sub-issue of that parent at once.
| Field | Type | Values | Specification |
|---|---|---|---|
| Status | Single select | Backlog, Ready, In Progress, In Review, Blocked, Done, Canceled | §11, §15 (A3) |
| Delivery Stage | Single select | Business Analysis, Functional Analysis, Architecture Analysis, Development, Testing, Deployment; on every task, and on stories, improvements, bugs and spikes as their current focus (the stage of their earliest open task) | §11 (owner decision, #394) |
| Sprint | Iteration | Two weeks from Sprint 5 (2026-10-03); Sprints 1 to 4 were one-day history sprints (#339) | §7, §22 |
| Story Points | Number | 1, 2, 3, 5, 8 or 13, on stories, improvements, bugs and spikes, never on tasks (#346) | §9 |
| Priority | Single select | P0 Critical, P1 High, P2 Normal, P3 Later, ordered highest first | §15 |
| Risk | Single select | Low, Medium, High, on open stories, improvements, bugs and spikes, the reason in a comment on the item | §10, §14 (owner decision, #394) |
| Start date, Target date | Date | Planned, then actual. Until work starts, the planned window: a selected item's window follows its sprint's dependency order, an unselected item takes its release's sprint window (#394). When work starts, Start date becomes that day, and a parent starts with its first child; when the item closes, Target date becomes the closing day (Europe/Brussels) (#397) | §14 (owner decisions, #394, #397) |
| Assignees | Issue assignees | The author, @AnnabiGihed, on every item from the day work on it starts (#397) |
§4, §14 |
| Area | Single select | Product areas, kept from before the specification | not in the specification |
| Milestone | Repository milestone | One per release, its due date the target date, its description linking the release record | §6, §15 |
Every item's Status value was kept when the field changed on 2026-10-02: the former Todo was renamed Backlog with the same
option, and the new values were added beside it. Change single-select options only with their option ids
(work-board-configuration-and-validation), or every item loses its value.
| View | Layout | Filter | Purpose (specification §17) |
|---|---|---|---|
| Product backlog | Table | is:issue is:open -status:Done -status:Canceled |
All outstanding work by priority and hierarchy. |
| Release backlog | Table | outstanding items with milestone:"v1.0"
|
Outstanding items in the release, grouped under their parents. |
| Release progress | Table | is:issue milestone:"v1.0" |
All release items, cancellations separate from completed delivery. |
| Sprint planning | Table | is:issue is:open status:Ready,Backlog |
Candidates with estimates, stages and prerequisites. |
| Sprint backlog | Board | is:issue sprint:@current |
The selected sprint's items, completed ones included, by Status. |
| Current sprint | Table | is:issue sprint:@current |
Active sprint execution progress. |
| Future sprints | Table | is:issue sprint:>@current |
Prepared upcoming sprint backlogs. |
| Delivery stages | Board | outstanding items | Items by Delivery Stage, showing Status. |
| Stabilization | Table | is:issue sprint:"v1.0 stabilization" |
The release's final sprint quality work. |
| Blocked work | Table | is:issue is:open status:Blocked |
Blocking reasons and prerequisites. |
| Scheduling violations | Table | is:issue label:"scheduling-violation" |
Items the board report flags. |
| Deployed to dev | Table | is:issue label:"deployed:dev" |
What runs in dev (§22, A9). |
| Deployed to test | Table | is:issue label:"deployed:test" |
What runs in test (§22, A9). |
| Deployed to production | Table | is:issue label:"deployed:production" |
What runs in production (§22, A9). |
| Failed deployments | Table | is:issue label:"deploy-failed:dev","deploy-failed:test","deploy-failed:production" |
Items a failed deployment didn't deliver (§22, A9). |
| Roadmap | Roadmap | epics and features | Feature and epic progress and forecasts. |
| Release plan | Roadmap | stories, improvements, bugs and spikes | Every release on one timeline, like an Azure DevOps delivery plan. |
| Releases | Table | stories, improvements, bugs and spikes | Each release's items with their count and Story Points. |
| Sprints | Table | stories, improvements, bugs and spikes with a sprint | Each sprint's outcome items with their count and Story Points, like sprint backlogs. |
- Release plan, Releases and Sprints were added on 2026-10-02 at the owner's request (#343) so releases and sprints can
be read at a glance:
- Release plan groups by milestone and draws each item between its sprint's start and end, at Quarter zoom, with a marker for every sprint start and every release's due date. Items not yet selected into a sprint are listed in their release without a bar.
- Releases groups by milestone and Sprints by sprint, each group showing its item count and its Story Points sum.
- The Stabilization view expects the release's last sprint to be titled
v1.0 stabilization; change the filter if the release record names it otherwise. - Capacity assumptions aren't a Project field: they are in the sprint record (
docs/planning/sprints/). - The
scheduling-violationlabel is set and cleared by the agent's board report (specification §17, §22). An ordinary filter can't evaluate dates and cross-item rules.
- Parent: every open issue has exactly one type label, every item except an epic has a parent of the allowed type, and an epic has none (specification §2).
- Milestones (specification §15, A2): a task shares its parent's milestone. Stories, improvements, bugs and spikes choose their release independently of their feature. A feature or epic has a milestone only when all its children are in that release; one that spans releases has none. A milestone change is checked at once on the changed issue, and on its parent by the next audit.
-
Contract (specification §4): an open item created since the specification's adoption answers every heading its
type requires, or
Unknown: needs clarification. The issue forms ask exactly those headings. Older open items are completed by the migration (A7). - Dependencies (specification §10): no dependency cycle, and no open item waiting on a prerequisite closed without being completed.
-
Releases (specification §6, §13): a release milestone closes only after its record,
docs/planning/releases/<milestone>.md, shows the state Released and an actual delivery date. - Completion: an epic, feature, story, improvement, bug or spike may be closed as completed only when at least one child of the level below is closed as completed and every child is closed. A story, improvement, bug or spike therefore never closes without a completed task.
-
Pull requests: a pull request closes tasks only (
Closes #N), and each one must reach an epic through a story, improvement, bug or spike and a feature. Reference other items withRefs #N. - A child closed as not planned or duplicate counts as closed but not as completed. An item closed that way is abandoned, so the completion and parent rules don't apply to it.
Every deployment marks what it delivered, so the Project shows what runs in each environment (#392, specification
§22, A9). The deployment workflow's record job runs scripts/record_deployment.py after the deployment, whether
it succeeded or failed, with the built-in token.
A merge deploys dev only when it changes a file that can affect the deployment (#491, A10): anything under src/
except the WoW addon in src/Addon/, which players install in the game, and the desktop companion's two projects,
published as a CI artifact for players' computers (#600), anything under deploy/, the build files
(Directory.Build.props, Directory.Packages.props, nuget.config, global.json, dotnet-tools.json,
RaidManager.sln) or deploy-dev.yml. The changes job of deploy-dev runs scripts/deploy_changes.py, which
compares main with the commit of the last successful dev deployment, so a change from a failed or skipped run is
deployed by the next one. After a merge, review runs the same script and starts deploy-dev only when it would
deploy; when nothing deployed changed, no run starts, and the merged items get deployed:dev from the next deployment,
which records everything in the history of its commit (A11, owner decisions on #579). A run started by hand from the
Actions tab always deploys. The
labels follow these rules:
| Label | Color | Meaning |
|---|---|---|
deployed:dev |
Light green | Delivered by a successful dev deployment. |
deployed:test |
Light blue | Delivered by a successful test deployment. |
deployed:production |
Green | Delivered by a successful production deployment. |
deploy-failed:<environment> |
Red | A deployment that would have delivered it failed; the next success removes it. |
- Items: a completed item is delivered when every merged pull request that closed it is in the history of the deployed commit; one closed without a pull request counts once it is closed. A completed parent is delivered when all its completed children are; canceled children don't count. A reopened item loses its label.
-
Releases: a release milestone whose issues are all closed and delivered gets a line in its description,
Deployed to <environment>: <date>, <run>, <commit>, betweendeploymentsmarkers; the line goes away if that stops being true. Released still needs the release record and the owner's approval (specification §6, §13). - Comments: each newly labeled item gets a comment linking the run, except during the first run in an environment, which labels everything delivered before it without comments.
- The labels are only ever set by the workflow, never by hand. Each environment's labels are independent, so a card shows every environment its item runs in. The test and production workflows (#427, #433) run the same job.
Dependabot proposes the new releases of the GitHub Actions the workflows use every Monday, all in one grouped pull
request that keeps commit-id pins and their version comment (.github/dependabot.yml, #460), so the owner reviews
once a week. Every pull request closes a task, so scripts/dependency_task.py runs with the built-in token: the
review workflow runs it when Dependabot opens or reopens its pull request, and the dependency-task workflow when a
pull request closes without a merge (#586):
-
Opened or reopened: it creates a task under the standing improvement #461, with its contract, the improvement's
milestone and the owner as assignee, and writes
Closes #<task>and the five required sections into the pull request. The self-review checklist is left for the owner to tick. - Closed without merging, usually because a newer release replaced it: it closes the task as not planned with a comment. A rerun creates nothing twice.
The rest follows the usual rules, with two differences recorded on #460. The owner is the operator of a Dependabot
pull request: they tick its checklist while reviewing, which re-runs description, post their review comment and mark
it ready, and a peer approves (verify_review.py, review). The built-in token can't write Project fields, so the
board report lists the open pull request until the agent selects #461 and the task into the active sprint, with the
owner's standing approval. Dependabot's branches, dependabot/github_actions/..., are the one exception to the
branch names in CONTRIBUTING.md. Its runs see only Dependabot secrets, so the package feed credentials the
build-test job needs are also stored there.
Every item that changes what users see carries the ui label and links or shows its Penpot mockup
(ADR-0017, how to design a screen). A
mockup is docs/mockups/<screen>.svg, rendered from its .penpot file, shown as an image or link, or a Penpot
share link (ADR-0018). A named SVG counts only once it
exists on main; until then the item keeps needs-mockup, and its comment names the missing file. The issue forms
ask User interface, and answering yes adds the ui label. The hierarchy workflow labels a ui item without a
mockup needs-mockup, with one comment, and removes the label once the mockup is linked. A pull request that changes
user-interface files must show its mockup, or state No visual change: with a reason.
The hierarchy workflow
runs with the built-in GITHUB_TOKEN:
- When an issue is opened, closed or reopened, it checks that issue and its three ancestors, and every issue changed in the last 30 minutes. A task reopened under a completed story therefore reopens the story, its feature and its epic. One action starts one run: label, milestone and text changes start none, because GitHub sends one event for each and creating an issue started up to four runs (#582). Issue runs go one at a time, so two never reopen the same parent twice.
- It audits every issue on a 15-minute schedule, in its own queue so an issue run never replaces it: the safety net
for a later label, milestone or text change, and for sub-issue changes, which start no workflow. GitHub runs that
schedule on a best-effort basis, only every few hours here, so
python scripts/work_gate.py report, which the agent runs at each session start and after each merge, also starts one audit run (#588). - It reopens an invalid parent with a comment that names the missing or open children.
- It labels a misplaced item, or one without a type label,
needs-parentwith one comment that says where it belongs; an item missing part of its contractneeds-contract; an item in a dependency cycle or waiting on a canceled prerequisitedependency-problem(audit only); and auiitem without a mockupneeds-mockup. It removes each label once the item is fixed. A new issue gets 10 minutes before it is flagged. - When a milestone is closed, and in every audit, it reopens a release milestone whose record doesn't show the delivery yet.
- Rules that need Project fields, such as the active-sprint gate, Status against the close reason, estimates and Delivery Stage, run in the agent preflight and board report instead, because the token can't read a user-owned Project (specification §22).
Every workflow runs on the owner's self-hosted runners (ADR-0034), so each run it doesn't need costs the owner's computer. Each trigger below is there for a reason; a run whose result nothing reads isn't started (#579).
| Workflow | Triggers | Why |
|---|---|---|
checks |
Pull request (opened, new commit, reopened); dispatch by hand | Job changes lists the pull request's files once (scripts/check_scope.py); then docs (documentation, skills, scripts, wiki and site), build-test (format, build, tests, coverage) and companion (the Windows executable) each run only when their files changed, and sonar on every pull request. docs, build-test and sonar are required; a skipped check counts as passed, so one is skipped only when nothing it reads can have changed. A run started by hand runs every check. It doesn't run after a merge: main must be up to date to merge, so the pull request's run tested the merged code. A newer commit cancels the run of the older commit. |
addon |
Pull request or push to main that changes src/Addon, test/Addon, test/Fixtures/Addon, .luacheckrc, .stylua.toml or the workflow; dispatch |
The addon's Lua checks, only where they can change; lua isn't required, so a pull request without those files doesn't wait for it. GitHub compares the whole pull request with main, so one that changes the addon runs it on each push. A newer commit cancels the run of the older commit. |
review |
pull_request_target (opened, new commit, reopened, ready, description edited); a review or review comment; checks completed on a pull request's branch |
Runs main's copy of the description checks (the description, the work items it closes, the mockup rule) and posts the required description status, on a commit and on an edit of the description; creates Dependabot's task; sets review-gate, hands new commits back to the operator, acts on the sign-off, and merges once every required check passed, so it runs again when checks finishes. A commit starts checks, this run and one run after checks; a description edit only this run. The completion of a canceled check is skipped. |
deploy-dev |
Dispatch by review after a merge that changed a deployed file since the last dev deployment, or by hand |
Deploys main to dev and labels the items (#491, A11). |
docs-publish |
Dispatch by review after a merge that changed docs/, mkdocs.yml, the wiki builder or the workflow, or by hand |
Publishes GitHub Pages and the Wiki from main. |
project-hierarchy |
An issue opened, closed or reopened; a closed milestone; a 15-minute schedule (every few hours in practice); dispatch, also by work_gate.py report
|
The hierarchy, contract, mockup and completion rules; one run per action; the audit, in its own queue, catches later label, milestone and text changes and sub-issue changes, which start no run. |
dependency-task |
pull_request_target closed |
Cancels the task of a Dependabot pull request closed without a merge; skipped for other pull requests, as GitHub can't filter the trigger by author. A merge by review starts no run. |
docs-links |
Weekly, and dispatch | External links change without any commit, so they are checked weekly rather than on every pull request. |
A merge through review uses the workflow token, which starts no push workflow; review dispatches docs-publish
and deploy-dev itself, each only when needed. The required checks are description, docs, build-test, sonar
and review-gate: checks runs three of them, and review posts description and review-gate.
scripts/work_gate.py reads the Project
with the owner's local gh login. Agents run it before every execution and at the start of every session, as the
scheduled check the workflow token can't do (specification §18, §22):
-
python scripts/work_gate.py preflight <task>checks the seven conditions of the active-sprint gate (specification §8): hierarchy and contract, an active sprint (Europe/Brussels midnight, end exclusive, not canceled in its record), the same sprint and release as the parent, assignee and Delivery Stage, completed prerequisites, and an open item. It prints PASS or FAIL with the correction for each, and exits 1 on any failure. -
python scripts/work_gate.py reportlists, by category:- scheduling violations: work in progress without any sprint, a task in another sprint than its parent, or an open pull request for a task without an active sprint;
- Status and closure mismatches;
- sprint and release mismatches: an item whose release (milestone) differs from its sprint's release, as listed in the Sprint sequence of the release records (owner rule, #346);
- unestimated selected stories;
- contract gaps on Ready or selected items;
- unavailable prerequisites;
- Blocked items without a recorded reason;
- open items with contract gaps, which are allowed in Backlog.
It exits 1 when any category other than the last has findings. With
--apply-labels, it keeps thescheduling-violationlabel on exactly the items it flags, which the Scheduling violations view shows.
The description check runs the pull-request rules on every pull request, so a task without a full chain, or a
user-interface change without its mockup, can't merge. After you fix a parent link, re-run that check from the pull
request's Checks tab. The review workflow closes only tasks when it merges.
The Project's built-in workflows run on GitHub's side and need no token. Closing and reopening never set Status by themselves (specification §13, A4):
| Built-in workflow | Setting | Role |
|---|---|---|
| Item closed | Off | It marked every closed item Done, canceled ones included (specification §15). |
| Item reopened | Off | It marked every reopened item In Progress, whatever its real state. |
| Auto-close issue | On | Setting Status to Done closes the issue as completed, so the guard checks it. |
| Item added to project | On | A new item starts in Backlog. |
| Auto-add sub-issues to project | On | A new child of a Project item joins the Project. |
| Pull request linked to issue, Pull request merged | On, unchanged | Must not set an issue to Done; checked in step 1 of the setup. |
Whoever closes or reopens an item sets its Status (work-task-execution-and-completion):
- completed:
Done; - not planned:
Canceled, with the reason; - reopened: the status that matches the remaining work.
The board report flags a mismatch between an item's close reason and its Status.
As of 2026-10-03, at the owner's request. Fully automated means neither the owner nor the agent does anything; not automated means one of them does it. Each gap the owner wants automated has a work item.
| Area | Behavior | Done by |
|---|---|---|
| Pull requests | Check formatting, build, run every test |
checks (build-test job) |
| Pull requests | Measure coverage, comment it, fail under 80% of changed lines or 60% in total |
checks (build-test job) |
| Pull requests | Fail on any SonarCloud finding |
checks (sonar job), SonarCloud |
| Pull requests | Check the description, the linked task's hierarchy and the mockup of user-interface changes |
review (description status) |
| Pull requests | Check spelling, prose, Markdown, links, the OpenAPI contract, the site and wiki build, and identical skill trees |
checks (docs job) |
| Review | Return a ready pull request to draft on new commits | review |
| Review | Check the operator's comment when the pull request is marked ready, then request the peer | review |
| Review | Keep the review-gate status current |
review |
| Review | Merge once every check and both reviews pass, delete the branch, close the linked tasks, run the checks on main
|
review |
| Documentation | Publish GitHub Pages and the wiki after each merge | docs-publish |
| Dependencies | Propose the week's new releases of GitHub Actions as one grouped pull request; give it a task under #461 and its description; cancel the task of an update closed without merging | Dependabot, dependency-task
|
| Documentation | Check external links every Monday | docs-links |
| Board | Check type, parent, contract, dependencies and mockup; keep the rule labels current | project-hierarchy |
| Board | Reopen a parent closed too early, and a release milestone closed before its record shows the delivery | project-hierarchy |
| Board | Start a new item in Backlog, add a new sub-issue to the Project | Project workflows |
| Board | Set a task In Progress when a pull request links it, and close an issue set to Done | Project workflows |
| Deployment | Deploy main to dev after a merge that changes a deployed file, smoke-test it, put the previous version back on a failure |
deploy-dev |
| Deployment | Label the delivered items, their parents and releases deployed:dev, or deploy-failed:dev on a failure |
deploy-dev (record job) |
| Server | Install security updates daily | unattended-upgrades |
| Server | Obtain and renew the six RaidManager certificates | shared Caddy |
| Server | Back up the server daily | OVH Automated Backup |
| Area | Behavior | Who | Work item to automate it |
|---|---|---|---|
| Work items | Create, classify, link and write contracts; run the active-sprint gate; set Status, dates, assignee, sprint, estimates, Risk, stage and priority | Agent | none (judgment) |
| Work items | After a merge, confirm it and delete the local branch | Agent | none |
| Work items | Write the evidence comment, set Done and the Target date on the merged task | Agent | #424, #425 |
| Work items | Validate and close parents against their criteria | Agent | #426 |
| Work items | Run the board report and keep scheduling-violation current |
Agent | #424 |
| Work items | Plan sprints and releases and write their records | Agent | none (decisions) |
| Changes | Branch, implement, check locally, open the draft pull request, fix findings, draft both review comments | Agent | none |
| Review | Post the operator's review comment and mark the pull request ready | Owner | none (by design) |
| Review | Approve the pull request | Peer | none (by design) |
| Deployment | Deliver the secrets to the server | Owner | #153, #386 |
| Deployment | Configure each environment | Agent and owner | #375, #388 |
| Deployment | Deploy each release to dev and test | Agent and owner | #427 |
| Deployment | Confirm a release and deploy it to production | Owner | #432, #433 |
| Deployment | Apply database migrations safely, with rollback | Agent | #434 |
| Deployment | Record test and production deployments on the items (the record job in their workflows) |
Agent | #427, #433 |
| Releases | Tag, publish the GitHub release and update the release record | Agent | #435 |
| Server | Provision the server, install the deploy key | Owner | none (done once, #374; key with #386) |
| Dependencies | Select each update's task, and #461, into the active sprint; set a canceled update's Status | Agent | none (§22: no token for Project fields) |
| Dependencies | Review an update as its operator and tick its checklist | Owner | none (by design) |
| Dependencies | Update NuGet packages and container images | Agent | none yet |
| Other | Fix a broken external link after the weekly report | Agent | none |
The API can create fields and views, but it can't switch a workflow off or set a view's grouping, so the owner does these steps once in the browser:
-
Workflows: open the Project menu, select Workflows, and switch off Item closed and Item reopened. Open Pull request linked to issue and Pull request merged: if either sets an issue's Status to
Done, switch it off too, because only verified completion setsDone(specification §13). -
Views: in each view, open the view menu and set:
View Setting Product backlog Sort by Priority; show hierarchy. Release backlog Group by Parent issue, so each item shows its parent without the parent joining the release (A2). Release progress Group by Status, so Done and Canceled stay apart. Sprint planning Group by Status; sort by Priority. Sprint backlog Column by Status. Current sprint Group by Status. Future sprints Group by Sprint. Delivery stages Column by Delivery Stage. Stabilization Group by Status. Roadmap Dates: Sprint (or Start date and Target date). Release plan Group by Milestone; Dates: Sprint; Markers: Milestone and Sprint; Zoom level: Quarter. Releases Group by Milestone; Field sum: Count and Story Points. Sprints Group by Sprint; Field sum: Count and Story Points.
- Create a test issue labeled
type:storywith no children, and add it to the Project. It starts inBacklog. - Set its Project status to
Done. The issue closes as completed. - Within a few minutes, the guard reopens it with a completion comment. Its Status stays
Doneuntil someone sets it, and the board report flags the reopened item markedDone. - After 10 minutes, the next audit labels it
needs-parent, because it has no feature. - Close the test issue as not planned and set its Status to
Canceled. It stays closed, and the next audit removes the label.
After any change to a workflow's triggers, take one task's documentation-only pull request through every step and
count the runs each step starts (#584). List them with
gh api "repos/AnnabiGihed/RaidManager/actions/runs?created=>=<UTC time of the step>"; the runs review starts
from workflow_run show main as their branch.
| Step | Runs it starts | Updates |
|---|---|---|
| Create the task | One project-hierarchy
|
None |
| Open the draft pull request, or push a commit | One checks (changes, then docs, build-test and companion as their files need, and sonar), one review, then one review after checks; addon only for addon files |
review posts description; review-gate pending |
| Edit the description | One review
|
description posted again |
| The operator's review, then Ready | One review for each |
The peer is requested |
| The peer's approval | One review, which merges |
The task closes with "Completed by #n", and the branch is deleted |
| After the merge |
docs-publish when published content changed, deploy-dev when a deployed file changed; no checks, no review
|
The task gets deployed:dev from the deployment, or from the next one when nothing deployed changed (A11) |
work_gate.py report, and the schedule (every few hours in practice) |
One project-hierarchy audit each, in its own queue |
None |
A run started twice for one event, or an update missing, is a bug to fix before other work.