| uid | contributing.project-board |
|---|---|
| title | Surgewave Project Board |
The roadmap, in-flight work, and bug triage all live on the Surgewave Project board. This page explains the fields and views — it doesn't replace ROADMAP.md, which still carries the narrative description of each track.
| Field | Values | Used for |
|---|---|---|
| Status | Backlog · Next up · In progress · In review · Done |
Kanban swim-lane |
| Milestone (built-in) | the repo's open work sections M<n> — <theme> (M1 … M6) |
The ordered section the ticket belongs to — see Milestones and releases. Every ticket has one; a ticket outside a section's themes goes to the next section. Unset is rendered as "Later" in ROADMAP.md. |
| Area | broker · clustering · protocol · storage · security · streams · connect · schema · ai · cli · control · observability · plugin-sdk · docs · site · multi |
Component filter |
| Track | kafka-compat · performance · ai-pipelines · cluster-correctness · transport · plugin-distribution |
Multi-phase initiatives that span releases |
| Project Effort | Low · Medium · High |
Sizing |
| Effort, Priority | (fields exist but carry no options) | Unused today. sync-project.mjs still tries to set Priority, which is where its !! Missing option Priority=P1 warnings come from — either add the options or drop them from the script. |
| Type (native issue field, not a board field) | Bug · Task · Feature |
What it is. Set on the issue itself (org-level GitHub issue types), searchable as type:Bug. Replaced the former kind:* label family and the board's Kind field — do not re-create either. |
| Where | What | Values |
|---|---|---|
| Type (built-in issue type) | What the ticket is | Bug · Feature · Task — every issue carries exactly one; the former kind:* labels are retired |
| Priority (org issue field, on the issue) | The order within a section | Urgent (now — blocks or burns) · High (this section) · Medium (the next section) · Low (someday) |
| Effort (org issue field) | Planned size | Low (a day or less) · Medium (days) · High (a week or more — split it) |
| Effort (actual) (board field) | What it turned out to be, set at Done | the same scale — plan next to actual, per issue (Bowire's design) |
| Milestone (built-in) | The ordered work section | M<n> — <themes>; a sibling repo mirrors the product's sections as its own milestones |
| Release (board field, where the board has one) | The version a ticket shipped in | vX.Y, stamped at the cut; empty while planned |
| Area (board field) | The component | per product (terrain, workbench, broker, …); the area:* label says the same for issue search |
| Status (board field) | Where the work sits in the flow | Backlog · Next up · In progress · In review · Done |
| Assignee | Who holds it | never empty — unassigned means nobody decided |
| Parent issue (built-in sub-issues) | Belongs to / depends on | an epic's slices are its sub-issues; "follow-up of #N" in the text is not a link |
Order inside a section is the Priority field, read by the roadmap generator; manual sorting on a board is the order of one view and nothing else — not on the ticket, not in the API, gone when the view is regrouped. Use it for the last fine ordering within a priority, never instead of one.
Since 2026-09-19 (the convention was rolled out from Bowire) milestones and release versions are decoupled:
- A milestone is an ordered work section —
M1 — Hygiene: CI, dependencies, licences,M2 — Multi-tenancy & data mesh, … Its description is one short statement of the themes it contains and ends with the scope rule: "Scope fixed on : a ticket belongs here if it falls under one of these themes — otherwise into the next section. The section gets its version number only at the release cut." A section does not grow: a ticket outside its themes goes to the next section, or a new section is opened behind the last. Every ticket gets a milestone when it is created. - A release gets its version number when it is cut, by content (SemVer). A finished section is the release as a rule; a second section that finished at the same time may ride along. The tag names the sections it ships in its message —
git tag -a v0.6.0 -m "Surgewave v0.6.0 — M1 — Hygiene …"— andscripts/resolve-milestone.mjsreads them for the release title and the drafted notes (falling back to av<base> — …milestone for old tags, then to the frontmost complete section). After the cut the milestone is closed with "Shipped in v0.6.0". - Release due = the frontmost open milestone has no open ticket, CI is green, no pull request is open.
node scripts/resolve-milestone.mjs v<next>says which section that is.
The board ships with the default All items view. The four views below mirror how Akka.NET's v1.6 project is structured — they need ~30 seconds each to configure in the UI (clone the default view, change layout + grouping):
- Layout: Roadmap
- Group by:
Milestone - Filter:
Status≠Done - Use for: "What is targeted for v1.6?" — the public-facing release plan
- Layout: Board
- Group by:
Status - Filter:
Milestone= current (the frontmost open section) - Use for: Operational kanban — what's currently moving
- Layout: Board
- Group by:
Area - Filter:
Status≠Done - Use for: Drill-down per component ("show me everything
security")
- Layout: Table
- Filter:
type:Bug - Sort by:
Priority↑ thenStatus↑ - Use for: Triage backlog, regardless of milestone
- One field per concept:
Milestoneis the which section (and thereby the when),Trackis the grouped initiative across releases,Areais the component. They overlap deliberately — Milestone is enforced (the bar for shipping), Track is editorial (Auth Phase A / B / C). area:*/track:*labels duplicate board fields on purpose: GitHub issue search needs labels (is:open label:area:security). Project filters need fields. Those two families are kept in sync so an issue is findable from either side. This does not extend to the nature of the work — that is the native issue Type (type:Bug), which exists exactly once and must not be mirrored back into a label.roadmaplabel flags items that are tracked on the board. Throwaway bug reports don't need it.community-votelabel marks feature requests where reactions on the issue are read as priority signal. Don't comment "+1" — react with 👍.- PRs close issues via
Closes #Nso Status flips toDoneautomatically and the item drops off the active views.
- New issue created via Convert from Markdown (in the issue editor) or Create issue — the board adds it as
Backlogby default. - Status transitions:
Backlog→Next up→In progress→In review→Done. The last two are driven by PR state where possible. - Milestones are managed in Settings → Issues → Milestones. When a milestone closes, its issues move out of the
Roadmapview automatically.
Every milestone's title carries the release headline directly: vX.Y[.Z] — <theme>. The theme is the same one that lands on the GitHub Release once the milestone tags, and it shows in the Project board's Roadmap view as the group heading (since Projects v2 reads the milestone title verbatim).
Format examples that work well:
v1.7 — new protocol pluginsv1.8 — AI workbenchv1.9 — AI for securityv1.10 — gRPC Connect
One concept per release. Themes are 2-5 words, concrete enough that a reader knows what the cycle is about (gRPC Connect beats protocol expansion). Avoid +-joined dual themes — if a cycle is gathering two big buckets, split them into two milestones instead of bundling. Splitting forces a decision about which bucket is the actual focus; bundling defers it.
Why pre-commit a theme at planning time: the headline defines what the cycle is about — what we'd be embarrassed to ship without. It anchors the milestone discussion ("does this issue serve the theme?"), avoids the retrospective scramble of summarising whatever happened to land, and gives the team a one-line elevator pitch through the cycle. Mid-cycle pivots are fine — rename the milestone (GitHub keeps the audit trail).
Mechanical consequences:
release.ymlparses the matching milestone's title when creating the GitHub Release and uses the<theme>tail asvX.Y.Z — <theme>. No hand-editing of the release title required.scripts/generate-roadmap.mjsrenders the full title as the section heading inROADMAP.mdso the offline view matches the Project board.- The milestone description stays free-form for slip context, stakeholder hints, &c. — no machinery parses it.
- If the milestone title is bare (
v2.0with no— <theme>tail), the release falls back to a barevX.Y.Ztitle and the roadmap section shows no theme — so missing themes are visible by their absence rather than crashing the pipeline.
CLI ergonomics caveat: gh issue list --milestone v2.0 no longer matches when the milestone is renamed to v2.0 — <theme> — gh matches the full title verbatim. Either use the full title, or look up by milestone number (--milestone <N>).
The roadmap is wired to maintain itself once an issue lands with label:roadmap:
| Event | What happens |
|---|---|
New issue with roadmap label |
.github/workflows/add-to-project.yml attaches it to the Project (Status defaults to Backlog) |
| Issue closed | roadmap-sync.yml regenerates ROADMAP.md from the Project + commits |
| Issue title / label / milestone change | same — roadmap-sync.yml re-renders |
PR merged that uses Closes #N |
Status flips to Done via Project workflow (UI-side, see below) |
| Daily 05:23 UTC | Safety-net roadmap-sync.yml cron |
add-to-project.yml and Surgewave.Bootcamp/notify-surgewave.yml share one organization secret BOWIRE_DISPATCH_TOKEN. The default GITHUB_TOKEN can't write to org-level Projects nor dispatch into sibling repos, so a PAT is required either way — but only one.
- Create a fine-grained PAT — Settings → Developer settings → Personal access tokens → Fine-grained.
- Resource owner:
Kuestenlogik - Repository access:
Kuestenlogik/Surgewave+ all sibling Surgewave.* repos (Bootcamp, Templates, VulnDb, Protocol., Sdk.) - Repository permissions:
Contents: R/W,Issues: Read,Pull requests: Read - Organization permissions:
Projects: Read and write
- Resource owner:
- Save as organization secret
BOWIRE_DISPATCH_TOKENinKuestenlogikorg settings → Secrets → Actions → New organization secret. Repository access: "Selected repositories" → tick every Surgewave.* repo. - Both workflows pick it up automatically; nothing per-repo to configure.
Configure once in the Project UI — these aren't exposed via API yet, so they live alongside the GitHub Action workflow files.
- Open https://github.com/orgs/Kuestenlogik/projects/4 → ⚙ Settings → Workflows
- Item closed → enable → Set status to
Done. - Pull request merged → enable → Set status to
Done. - Auto-add to project → leave disabled for
Kuestenlogik/Surgewave(the GitHub Action above handles that with the label filter). For sibling Surgewave.* repos that don't carry the workflow file, enable Auto-add with filterrepo:Kuestenlogik/<RepoName> label:roadmap is:issue,pr.
Sibling-repo wiring options (Project-side auto-add vs Action-side label-filter vs back-fill) are picked per-repo; the Project-side default works for most cases.
The pilot batch lives on the board now (6 items from In progress + Next up). ROADMAP.md is unchanged for the moment. Once the board's daily feel is validated, the plan is:
- Migrate the rest of
ROADMAP.mdto issues, one per###heading. - Trim
ROADMAP.mdto a ~30-line index that points at the board and the In progress + Next up highlights, regenerated periodically from the board. - The marketing site's
roadmap.htmlpulls from the Project's GraphQL API (cached assite/_data/roadmap.ymlvia a GitHub Action) so visitors see live data without the page making a network call.
Rollback plan: closing the issues and deleting the project + milestones restores the previous "ROADMAP.md is the only source" state. The labels stay — they're useful regardless.