diff --git a/.github/workflows/back-merge.yml b/.github/workflows/back-merge.yml index f4f24fd4..4a0ff6a7 100644 --- a/.github/workflows/back-merge.yml +++ b/.github/workflows/back-merge.yml @@ -74,6 +74,5 @@ jobs: gh issue create \ --repo "${{ github.repository }}" \ --title "Back-merge main into next failed (run ${{ github.run_id }})" \ - --label "back-merge-failed" \ --body "The automated back-merge of \`main\` into \`next\` failed, so \`next\` is drifting from the latest release. Resync manually by opening a PR from \`main\` into \`next\`. Run: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" \ || echo "issue creation failed; check the run logs" diff --git a/ROADMAP.md b/ROADMAP.md index c27c8a52..c979ef24 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -1,6 +1,6 @@ # Roadmap -The live roadmap - **Now / Next / Later** with per-item status across the framework and CLI - is the [AIDD Roadmap board](https://github.com/orgs/ai-driven-dev/projects/8). That board is the single source of truth; this file deliberately does not duplicate it. Shipped reality lives in [`CHANGELOG.md`](./CHANGELOG.md). +The live roadmap is the [AIDD Roadmap board](https://github.com/orgs/ai-driven-dev/projects/8): a milestone is a theme, due on a Friday, and everything without one is the backlog, ordered by priority. That board is the single source of truth; this file deliberately does not duplicate it. Shipped reality lives in [`CHANGELOG.md`](./CHANGELOG.md). ## How to influence diff --git a/aidd_docs/memory/vcs.md b/aidd_docs/memory/vcs.md index 06725d7a..633907f4 100644 --- a/aidd_docs/memory/vcs.md +++ b/aidd_docs/memory/vcs.md @@ -18,19 +18,19 @@ type/ticket-short-description ### Types The single source of truth: find your row, read left to right β€” it tells you the -branch to create, the label that applies, and where the PR goes. The branch -**prefix** alone decides the target (not a label, not a board field); the +branch to create, the issue type that applies, and where the PR goes. The branch +**prefix** alone decides the target (not a type, not a board field); the `aidd-vcs:02-pull-request` skill reads this table to set the base automatically. -| I want to… | Issue template | Branch | Commit | Label (auto) | PR targets | -| ---------- | -------------- | ------ | ------ | ------------ | ---------- | -| ship a feature | ✨ Feature | `feat/…` | `feat:` | `enhancement` | `next` | -| fix a bug | πŸ› Bug | `fix/…` | `fix:` | `bug` | `next` | -| change docs only | ✨ Feature | `docs/…` | `docs:` | `documentation` | `next` | -| refactor (no behaviour change) | β€” | `refactor/…` | `refactor:` | β€” | `next` | -| build / config / deps | β€” | `chore/…` | `chore:` | `dependencies` | `next` | -| add or update tests | β€” | `test/…` | `test:` | β€” | `next` | -| 🚨 urgent production fix | πŸ› Bug | `hotfix/…` | `fix:` | `bug` | **`main`** | +| I want to… | Issue template | Branch | Commit | Issue type | PR targets | +| ---------- | -------------- | ------ | ------ | ---------- | ---------- | +| ship a feature | ✨ Feature | `feat/…` | `feat:` | `Feature` | `next` | +| fix a bug | πŸ› Bug | `fix/…` | `fix:` | `Bug` | `next` | +| change docs only | πŸ—ΊοΈ Roadmap | `docs/…` | `docs:` | `Task` | `next` | +| refactor (no behaviour change) | πŸ—ΊοΈ Roadmap | `refactor/…` | `refactor:` | `Task` | `next` | +| build / config / deps | πŸ—ΊοΈ Roadmap | `chore/…` | `chore:` | `Task` | `next` | +| add or update tests | πŸ—ΊοΈ Roadmap | `test/…` | `test:` | `Task` | `next` | +| 🚨 urgent production fix | πŸ› Bug | `hotfix/…` | `fix:` | `Bug` | **`main`** | #### Routing rule (strict) @@ -38,11 +38,12 @@ branch to create, the label that applies, and where the PR goes. The branch - **Only `hotfix/*` targets `main`** β€” an urgent production fix, out of cycle. Once the PR is open, the board advances on its own: -`Todo β†’ In review` (PR opened) `β†’ Ready` (review approved) `β†’ Done` (merged). +`Todo β†’ In review` (PR opened) `β†’ Done` (merged). -Labels are **triage only**: they categorize, they never route. `security` is -cross-cutting β€” add it to any kind when the change is security-sensitive. The -"Commit" column shows the conventional type; the authoritative type list is the +The **issue type** categorizes; it never routes. The form stamps it, so you +never set it by hand. Labels categorize nothing here: one exists only when a bot +or a human reads it (`.github/labels.yml`). The "Commit" column shows the +conventional type; the authoritative type list is the [Commit Convention](#commit-convention) below (mirrors `commitlint.config.cjs`). ### Examples diff --git a/docs/MAINTAINERS.md b/docs/MAINTAINERS.md index 3bfff5a9..ffbde964 100644 --- a/docs/MAINTAINERS.md +++ b/docs/MAINTAINERS.md @@ -18,42 +18,47 @@ How to operate this repository day to day. This file is the **HabilitΓ©** (maint ## πŸ“… Daily -- **Triage issues.** New issues auto-add to board #8. Set `Status` / `Area` / `Priority`; link under an epic (native sub-issues) if relevant. **Type** is the issue/PR label, not a board field (see [Project board layout](#-project-board-project-8)). +- **Triage issues.** New issues auto-add to board #8. The form already stamped the type. You give the issue a **milestone** or a **priority**, never both. - **Roadmap.** Priority = the community vote (mechanism in `GOVERNANCE.md`). Accepted items live on board #8 β€” keep `ROADMAP.md` a pointer, don't maintain a second list. - **Review PRs.** Approve as CODEOWNERS, then squash-merge (merge policy β†’ [`GOVERNANCE.md`](../GOVERNANCE.md#-code-decisions-merging)). -## πŸ“‹ Project board (Project 8) +## πŸ“‹ Four axes, one board -The board is a **view** of the taxonomy the docs define, never its own. Each property answers one question: **Type** = the label Β· **Priority** = urgency Β· **Status** = flow position Β· **When** = Timeline. Routing (`next`/`main`) is *not* a board property β€” it derives from the branch prefix ([routing table](../aidd_docs/memory/vcs.md#types)). +Each axis answers one question, and only `Status` lives on the board. Routing (`next`/`main`) is not an axis β€” it derives from the branch prefix ([routing table](../aidd_docs/memory/vcs.md#types)). -One-time layout (org-admin / board-write; get field IDs via `gh project field-list 8 --owner ai-driven-dev`): +| Axis | Lives in | Answers | Values | +| --- | --- | --- | --- | +| **Type** | issue type, stamped by the form | what kind of work | `Bug` Β· `Feature` Β· `Task` | +| **Milestone** | repo milestone | *when* it ships | one theme, due a Friday | +| **Priority** | org issue field | *in what order*, among what has no *when* | `Urgent` Β· `High` Β· `Medium` Β· `Low` | +| **Status** | board field | where the work stands | `Ideation` Β· `Todo` Β· `In Progress` Β· `In review` Β· `Done` | -- **Drop** `Work type` (duplicates Type) and `Phases` (duplicates Status) β€” `gh project field-delete --id `. -- **Keep** `Priority` (P0 Β· P1 Β· P2) and `Area`. -- **`Status`** options, in order: `Todo Β· In progress Β· In review Β· Ready Β· Done` (built-in field β€” edit its values in the UI). -- **Timeline view** β€” new view, date = Milestone/target; use it as the roadmap horizon. +Two rules keep the axes orthogonal: -Status automation (Project β†’ β‹― β†’ Workflows); `In progress` is the one manual move: +- **A milestone or a priority, never both.** The milestone decided when; the order no longer matters. +- **The scope lives in the title**, conventional and queryable: `feat(aidd-pm): …`. No `Area` field, no scope label. Find work with `gh issue list --search 'aidd-pm in:title'`. + +Status automation (Project β†’ β‹― β†’ Workflows); `In Progress` is the one manual move: | Trigger (built-in) | Status | | --- | --- | | Item added | `Todo` | | PR linked / ready for review | `In review` | -| Code review approved | `Ready` | | PR merged Β· item closed | `Done` | +The roadmap layout cannot read a milestone as a date, so the milestone view is a **Table view grouped by `Milestone`**. Its `No milestone` group is the backlog, ordered by `Priority`. + ## 🏷️ Labels -[`.github/labels.yml`](../.github/labels.yml) is the canonical set (triage only β€” routing is by branch prefix). The sync loop **creates/updates** from the file; it does **not** delete. So when you remove a label from the file, also delete it on GitHub: +Labels categorize nothing: the **issue type** does. A label in [`.github/labels.yml`](../.github/labels.yml) exists only when a bot or a human reads it β€” `good first issue`, `dependencies` (dependabot), `autorelease: *` (release-please). + +Nothing syncs the file to GitHub. Create and delete by hand, then check they agree: ```bash -gh label delete "help wanted" --yes -gh label delete npm --yes -gh label delete "github-actions" --yes +diff <(gh label list --repo ai-driven-dev/framework | cut -f1 | sort) \ + <(yq e '.[].name' .github/labels.yml | sort) ``` -Dependabot labels its PRs `dependencies` only (ecosystem sub-labels were dropped); confirm `.github/dependabot.yml` does not re-add a deleted label before deleting it. - ## πŸš€ Releases release-please opens/updates a `chore: release main` PR on each push to `main`. @@ -101,7 +106,7 @@ The App: ID in secret `AIDD_BOT_APP_ID`, key in `AIDD_BOT_PRIVATE_KEY`. If the A Head branches are **not** auto-deleted on merge (`delete_branch_on_merge: false`): - The promote PR merges `next` into `main` without deleting `next`, so the back-merge that realigns `next` never hits a missing branch. **Do not re-enable** the setting. -- The back-merge runs unattended (bot App `always` bypass on the `next` ruleset). If it can't push, it opens an issue labelled `back-merge-failed` β€” resync with a `main` β†’ `next` PR. +- The back-merge runs unattended (bot App `always` bypass on the `next` ruleset). If it can't push, it opens a tracking issue β€” resync with a `main` β†’ `next` PR. - If `next` is ever missing, recreate it: `git push origin main:next`. To change protection, edit `.github/rulesets/main.json` (or `next.json`), then apply it live: