@gobing-ai/spur 0.3.20 → 0.3.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/config/rules/typescript/prefer-accessible-role-for-button-queries.yaml +31 -0
- package/config/templates/docs/00_ADR.md +25 -15
- package/config/templates/docs/01_PRD.md +12 -7
- package/config/templates/docs/02_ROADMAP.md +16 -8
- package/config/templates/docs/03_ARCHITECTURE.md +12 -5
- package/config/templates/docs/04_DESIGN.md +26 -8
- package/config/templates/docs/05_FEATURES.md +18 -7
- package/config/templates/docs/99_PROJECT_CONSTITUTION.md +427 -33
- package/config/workflows/task-pipeline.yaml +6 -2
- package/config/workflows/wrapup-pipeline.yaml +4 -7
- package/package.json +1 -1
- package/schemas/spur-config.schema.json +13 -0
- package/spur.js +7816 -6774
- package/web/_astro/BoardApp.LygxZgOy.js +1 -0
- package/web/_astro/{BoardApp.DfUXxULJ.js → BoardApp.b8HvN_Uy.js} +82 -82
- package/web/_astro/{TaskDetail.CWHJA-V_.js → TaskDetail.BRr8ebLd.js} +1 -1
- package/web/_astro/{arc.B64JH2Yw.js → arc.D9I3ghf3.js} +1 -1
- package/web/_astro/{architectureDiagram-3BPJPVTR.CNsf8RqK.js → architectureDiagram-3BPJPVTR.B60VjZ82.js} +1 -1
- package/web/_astro/{blockDiagram-GPEHLZMM.B5L6Sdtp.js → blockDiagram-GPEHLZMM.B8xiXsGb.js} +1 -1
- package/web/_astro/{c4Diagram-AAUBKEIU.D2LUWzto.js → c4Diagram-AAUBKEIU.D8Q9jRJZ.js} +1 -1
- package/web/_astro/channel.BToTp7Lu.js +1 -0
- package/web/_astro/{chunk-2J33WTMH.BDCK4a2A.js → chunk-2J33WTMH.BVcogAuP.js} +1 -1
- package/web/_astro/{chunk-4BX2VUAB.DRG-P5ln.js → chunk-4BX2VUAB.pDodeppW.js} +1 -1
- package/web/_astro/{chunk-55IACEB6.BF6dAaDw.js → chunk-55IACEB6.5dYLJxJn.js} +1 -1
- package/web/_astro/{chunk-727SXJPM.GT8NEsK6.js → chunk-727SXJPM.C6GTI_n6.js} +1 -1
- package/web/_astro/{chunk-AQP2D5EJ.C6g9Ixyp.js → chunk-AQP2D5EJ.kgDX41bQ.js} +1 -1
- package/web/_astro/{chunk-FMBD7UC4.37t3ZahP.js → chunk-FMBD7UC4.CSnAi74r.js} +1 -1
- package/web/_astro/{chunk-ND2GUHAM.CIMe94Tp.js → chunk-ND2GUHAM.qQ8ldUUT.js} +1 -1
- package/web/_astro/{chunk-QZHKN3VN.BDk4vBSo.js → chunk-QZHKN3VN.PzPFlVri.js} +1 -1
- package/web/_astro/{classDiagram-4FO5ZUOK.BkZHAH5J.js → classDiagram-4FO5ZUOK.C7RulRYW.js} +1 -1
- package/web/_astro/{classDiagram-v2-Q7XG4LA2.BkZHAH5J.js → classDiagram-v2-Q7XG4LA2.C7RulRYW.js} +1 -1
- package/web/_astro/{cose-bilkent-S5V4N54A.-vmutMeo.js → cose-bilkent-S5V4N54A.Dw4HZHnT.js} +1 -1
- package/web/_astro/{dagre-BM42HDAG.YTN__ph-.js → dagre-BM42HDAG.MmGbZWM_.js} +1 -1
- package/web/_astro/{diagram-2AECGRRQ.CpwYXr6h.js → diagram-2AECGRRQ.DugWYvZC.js} +1 -1
- package/web/_astro/{diagram-5GNKFQAL.BLW_nNiA.js → diagram-5GNKFQAL.BL7D0BMi.js} +1 -1
- package/web/_astro/{diagram-KO2AKTUF.BTFC9CYM.js → diagram-KO2AKTUF.B9GQMjwM.js} +1 -1
- package/web/_astro/{diagram-LMA3HP47.CWXHZTYF.js → diagram-LMA3HP47.CbHPvhbu.js} +1 -1
- package/web/_astro/{diagram-OG6HWLK6.4DO1knJK.js → diagram-OG6HWLK6.Bx6GcKpw.js} +1 -1
- package/web/_astro/{erDiagram-TEJ5UH35.eWFFCa1s.js → erDiagram-TEJ5UH35._sHJgXD7.js} +1 -1
- package/web/_astro/{flowDiagram-I6XJVG4X.Qnt78_UD.js → flowDiagram-I6XJVG4X.D305L8m4.js} +1 -1
- package/web/_astro/{ganttDiagram-6RSMTGT7.CMqioE2G.js → ganttDiagram-6RSMTGT7.qjJ4kX00.js} +1 -1
- package/web/_astro/{gitGraphDiagram-PVQCEYII.DIHrO_gc.js → gitGraphDiagram-PVQCEYII.D-t4MzVO.js} +1 -1
- package/web/_astro/index.CmVh0AUD.css +1 -0
- package/web/_astro/{infoDiagram-5YYISTIA.DbzNXZsX.js → infoDiagram-5YYISTIA.WwSNIljZ.js} +1 -1
- package/web/_astro/{ishikawaDiagram-YF4QCWOH.C34rBvEh.js → ishikawaDiagram-YF4QCWOH.EWsUYdpd.js} +1 -1
- package/web/_astro/{journeyDiagram-JHISSGLW.B4Y56hm8.js → journeyDiagram-JHISSGLW.CqKE9hNP.js} +1 -1
- package/web/_astro/{kanban-definition-UN3LZRKU.CbkLbGD-.js → kanban-definition-UN3LZRKU.BDCCufoa.js} +1 -1
- package/web/_astro/{linear.CJu-zQ8Y.js → linear.CyHEakPy.js} +1 -1
- package/web/_astro/{mermaid.core.Cg8FpcnS.js → mermaid.core.B-9P_KDH.js} +4 -4
- package/web/_astro/{mindmap-definition-RKZ34NQL.CUS8uIx4.js → mindmap-definition-RKZ34NQL.bCxpjW2r.js} +1 -1
- package/web/_astro/{pieDiagram-4H26LBE5.DLoKfxBO.js → pieDiagram-4H26LBE5.x_CRiGMu.js} +1 -1
- package/web/_astro/{quadrantDiagram-W4KKPZXB.C4gJNQom.js → quadrantDiagram-W4KKPZXB.CnbQkwo7.js} +1 -1
- package/web/_astro/{requirementDiagram-4Y6WPE33.BsiW5Ob5.js → requirementDiagram-4Y6WPE33.CfeJKVEP.js} +1 -1
- package/web/_astro/{sankeyDiagram-5OEKKPKP.k6qljwMr.js → sankeyDiagram-5OEKKPKP.COYpTQlG.js} +1 -1
- package/web/_astro/{sequenceDiagram-3UESZ5HK.Bx0G-FfT.js → sequenceDiagram-3UESZ5HK.DVzoeimO.js} +1 -1
- package/web/_astro/{stateDiagram-AJRCARHV.CRbr10-B.js → stateDiagram-AJRCARHV.BVL5te9q.js} +1 -1
- package/web/_astro/{stateDiagram-v2-BHNVJYJU.iDwcqAkR.js → stateDiagram-v2-BHNVJYJU.C_x1GbV0.js} +1 -1
- package/web/_astro/{timeline-definition-PNZ67QCA.p4S9tDNI.js → timeline-definition-PNZ67QCA.DtZPbOJL.js} +1 -1
- package/web/_astro/{vennDiagram-CIIHVFJN.DgzRFt8Y.js → vennDiagram-CIIHVFJN.pexoUOut.js} +1 -1
- package/web/_astro/{wardley-L42UT6IY.DUFfR4J1.js → wardley-L42UT6IY.DLG5pKRN.js} +1 -1
- package/web/_astro/{wardleyDiagram-YWT4CUSO.BgE4haqE.js → wardleyDiagram-YWT4CUSO.CnYrM4tH.js} +1 -1
- package/web/_astro/{xychartDiagram-2RQKCTM6.BnitKCz8.js → xychartDiagram-2RQKCTM6.kBrlce_Y.js} +1 -1
- package/web/index.html +2 -2
- package/web/_astro/BoardApp.Bwxdbc0J.js +0 -1
- package/web/_astro/channel.DTWaHQwD.js +0 -1
- package/web/_astro/index.Bg28MlvM.css +0 -1
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
$schema: "@gobing-ai/spur/schemas/rule-file.schema.json"
|
|
2
|
+
# Forbid getByLabelText queries on button accessible names in web component tests.
|
|
3
|
+
#
|
|
4
|
+
# WHY: HTML `<button>` elements are non-labellable per WHATWG HTML spec. In DOM Testing
|
|
5
|
+
# Library, `getByLabelText` queries elements associated with `<label>` tags. When used to
|
|
6
|
+
# query a `<button>` with an `aria-label` attribute, it works when happy-dom DOM state is
|
|
7
|
+
# fresh, but throws `TestingLibraryElementError: element associated with this label is non-labellable`
|
|
8
|
+
# when running in full multi-file test suites on CI (e.g. Linux runners).
|
|
9
|
+
# Real incident: CI-only failure in apps/web/tests/modules/task-kanban/components.test.tsx on 2026-07-24.
|
|
10
|
+
#
|
|
11
|
+
# FIX: Use `getByRole('button', { name: '...' })` or `getByRole('button', { name: /.../ })`,
|
|
12
|
+
# which queries the W3C accessible name provided by `aria-label`.
|
|
13
|
+
include:
|
|
14
|
+
- "apps/web/tests/**/*.test.ts"
|
|
15
|
+
- "apps/web/tests/**/*.test.tsx"
|
|
16
|
+
exclude:
|
|
17
|
+
- "**/node_modules/**"
|
|
18
|
+
- "**/dist/**"
|
|
19
|
+
|
|
20
|
+
rules:
|
|
21
|
+
- id: prefer-accessible-role-for-button-queries
|
|
22
|
+
description: >
|
|
23
|
+
Do not query button accessible names with `getByLabelText` in web React tests.
|
|
24
|
+
`<button>` elements are non-labellable per WHATWG spec, causing timing-dependent
|
|
25
|
+
CI failures when tests run sequentially in a single process.
|
|
26
|
+
Use `getByRole('button', { name: ... })` instead.
|
|
27
|
+
severity: warning
|
|
28
|
+
evaluator:
|
|
29
|
+
type: rg
|
|
30
|
+
config:
|
|
31
|
+
pattern: "getByLabelText\\(['\"]Sort "
|
|
@@ -4,29 +4,39 @@ doc: 00_ADR
|
|
|
4
4
|
owns: WHY — which cross-cutting decision was made, and the one-line reason
|
|
5
5
|
authority: authoritative
|
|
6
6
|
version: 1.0.0
|
|
7
|
-
|
|
8
|
-
updated_at:
|
|
7
|
+
owner: _(project owner)_
|
|
8
|
+
updated_at: {{init-date}}
|
|
9
|
+
read_before: any structural change
|
|
10
|
+
edit_rules: 99 §6.1
|
|
11
|
+
sync: [T1, T2]
|
|
9
12
|
---
|
|
10
13
|
|
|
11
14
|
# Architecture Decision Records
|
|
12
15
|
|
|
13
|
-
|
|
14
|
-
> Each entry is append-only; supersession is by a new dated entry, never by editing an old one.
|
|
15
|
-
> Only real cross-cutting decisions belong here — not implementation notes, not feature status, not
|
|
16
|
-
> how-to guidance. Entries that grow past decision + reason are carrying mechanism that belongs in
|
|
17
|
-
> `03`/`04`; link it instead of inlining it.
|
|
16
|
+
## ADR-001 — Adopt this doc structure
|
|
18
17
|
|
|
19
|
-
|
|
18
|
+
**Status:** Accepted · **Date:** {{init-date}}
|
|
20
19
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
20
|
+
**Decision.** Adopt the Spur doc structure (`00`–`05` + `99` constitution).
|
|
21
|
+
|
|
22
|
+
**Why.** Separates WHY (`00`) from WHAT (`01`) from HOW (`03`/`04`) — one fact, one home.
|
|
23
|
+
|
|
24
|
+
**Detail:** `docs/99_PROJECT_CONSTITUTION.md` §4.1.
|
|
26
25
|
|
|
27
26
|
<!--
|
|
28
|
-
Add new ADRs here.
|
|
27
|
+
Add new ADRs here. Entry shape (per 99 §6.1):
|
|
28
|
+
|
|
29
|
+
## ADR-NNN: <Decision title, outcome-shaped>
|
|
30
|
+
|
|
31
|
+
**Status:** Accepted | Accepted (design) | Superseded by ADR-MMM | Skipped · **Date:** YYYY-MM-DD
|
|
32
|
+
|
|
33
|
+
**Decision.** <What was decided — the smallest complete statement of the choice.>
|
|
34
|
+
|
|
35
|
+
**Why.** <One line. The single strongest reason.>
|
|
36
|
+
|
|
37
|
+
**Detail:** <pointer into 03/04/plans — depth never lives here.>
|
|
38
|
+
|
|
29
39
|
A decision that reverses a prior ADR adds a new entry that says "supersedes ADR-NNN".
|
|
30
40
|
An Amendment records the decision delta + one-line reason — not the mechanism. Implementation
|
|
31
41
|
paths, detailed semantics, and multi-paragraph rationale belong in 03/04, not in the amendment.
|
|
32
|
-
-->
|
|
42
|
+
-->
|
|
@@ -4,14 +4,15 @@ doc: 01_PRD
|
|
|
4
4
|
owns: WHAT — product vision, users, scope (in / out / deferred)
|
|
5
5
|
authority: authoritative-on-scope
|
|
6
6
|
version: 1.0.0
|
|
7
|
-
|
|
8
|
-
updated_at:
|
|
7
|
+
owner: _(project owner)_
|
|
8
|
+
updated_at: {{init-date}}
|
|
9
|
+
read_before: adding a command or feature
|
|
10
|
+
edit_rules: 99 §6.2
|
|
11
|
+
sync: [T1, T4, T6]
|
|
9
12
|
---
|
|
10
13
|
|
|
11
14
|
# Product Requirements Document
|
|
12
15
|
|
|
13
|
-
> Authoritative on **scope**. In-scope vs out-of-scope vs deferred lives here and nowhere else.
|
|
14
|
-
|
|
15
16
|
## 1. Vision
|
|
16
17
|
|
|
17
18
|
_(One sentence: what this product is and who it is for.)_
|
|
@@ -28,10 +29,14 @@ _(One sentence: what this product is and who it is for.)_
|
|
|
28
29
|
|
|
29
30
|
- _(capability the product delivers)_
|
|
30
31
|
|
|
31
|
-
###
|
|
32
|
+
### Supporting
|
|
32
33
|
|
|
33
|
-
- _(
|
|
34
|
+
- _(capability that enables an in-scope item but is not user-facing)_
|
|
34
35
|
|
|
35
36
|
### Deferred
|
|
36
37
|
|
|
37
|
-
- _(capability intentionally postponed — not a commitment)_
|
|
38
|
+
- _(capability intentionally postponed — not a commitment; carry the condition that would reactivate it)_
|
|
39
|
+
|
|
40
|
+
### Out of scope
|
|
41
|
+
|
|
42
|
+
- _(explicitly excluded capability — prevents scope creep)_
|
|
@@ -4,19 +4,27 @@ doc: 02_ROADMAP
|
|
|
4
4
|
owns: WHEN — phases, current vs deferred, sequencing
|
|
5
5
|
authority: derived
|
|
6
6
|
version: 1.0.0
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
derived_from: [00_ADR, 01_PRD]
|
|
8
|
+
owner: _(project owner)_
|
|
9
|
+
updated_at: {{init-date}}
|
|
10
|
+
read_before: placing work in a phase
|
|
11
|
+
edit_rules: 99 §6.3
|
|
12
|
+
sync: [T5]
|
|
9
13
|
---
|
|
10
14
|
|
|
11
15
|
# Roadmap
|
|
12
16
|
|
|
13
|
-
> Derived from `01_PRD` (scope) and `00_ADR` (decisions). Edit when phase status changes.
|
|
14
|
-
|
|
15
17
|
## Phases
|
|
16
18
|
|
|
17
|
-
| Phase | Status | Items |
|
|
18
|
-
|
|
19
|
-
| Phase 0 — Foundation | ✅ done | _(list the real, shipped deliverable names)_ |
|
|
20
|
-
| Phase 1 — _(name)_ | ⏳ planned | _(items)_ |
|
|
19
|
+
| Phase | Status | Items | Exit criterion |
|
|
20
|
+
|-------|--------|-------|----------------|
|
|
21
|
+
| Phase 0 — Foundation | ✅ done | _(list the real, shipped deliverable names)_ | _(what must be true to exit)_ |
|
|
22
|
+
| Phase 1 — _(name)_ | ⏳ planned | _(items)_ | _(what must be true to exit)_ |
|
|
21
23
|
|
|
22
24
|
**Status legend:** ✅ done · 🔶 partial · ⏳ planned · 💤 deferred
|
|
25
|
+
|
|
26
|
+
<!--
|
|
27
|
+
Markers: [x] done · [~] partial · [ ] pending. [x]/[~] carry a one-line evidence note.
|
|
28
|
+
When a deliverable lands under a different name than planned, rewrite the bullet to the real name.
|
|
29
|
+
Insert sub-phases (1.5) rather than renumbering existing ones.
|
|
30
|
+
-->
|
|
@@ -4,14 +4,16 @@ doc: 03_ARCHITECTURE
|
|
|
4
4
|
owns: HOW — module boundaries, data flow, runtime model, invariants
|
|
5
5
|
authority: derived
|
|
6
6
|
version: 1.0.0
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
derived_from: [00_ADR, 01_PRD]
|
|
8
|
+
owner: _(project owner)_
|
|
9
|
+
updated_at: {{init-date}}
|
|
10
|
+
read_before: cross-module, seam, or schema work
|
|
11
|
+
edit_rules: 99 §6.4
|
|
12
|
+
sync: [T1]
|
|
9
13
|
---
|
|
10
14
|
|
|
11
15
|
# Architecture
|
|
12
16
|
|
|
13
|
-
> Derived (ADR wins). Read before cross-module/seam/schema work; edit when boundaries or mechanisms change.
|
|
14
|
-
|
|
15
17
|
## 1. Module map
|
|
16
18
|
|
|
17
19
|
```
|
|
@@ -24,4 +26,9 @@ _(Describe the primary data path: input → processing → output. Name the seam
|
|
|
24
26
|
|
|
25
27
|
## 3. Invariants
|
|
26
28
|
|
|
27
|
-
- _(state or property that always holds —
|
|
29
|
+
- _(state or property that always holds — phrased so a constraint rule or reviewer can check it mechanically)_
|
|
30
|
+
|
|
31
|
+
<!--
|
|
32
|
+
Describes the CURRENT architecture only. Future/accepted designs go in sections explicitly
|
|
33
|
+
titled "(accepted design — ADR-NNN; not yet built)". On conflict with 00, the ADR wins; fix here.
|
|
34
|
+
-->
|
|
@@ -1,17 +1,29 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: Design
|
|
3
3
|
doc: 04_DESIGN
|
|
4
|
-
owns: SURFACE — concrete shapes: every CLI command, flag, config key, env var, table, DTO
|
|
4
|
+
owns: SURFACE — concrete shapes: every CLI command, flag, config key, env var, table, DTO; index over docs/design/
|
|
5
5
|
authority: derived
|
|
6
6
|
version: 1.0.0
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
derived_from: [00_ADR, 01_PRD]
|
|
8
|
+
owner: _(project owner)_
|
|
9
|
+
updated_at: {{init-date}}
|
|
10
|
+
read_before: changing a command, flag, env var, or schema
|
|
11
|
+
edit_rules: 99 §6.5
|
|
12
|
+
sync: [T3, T9]
|
|
9
13
|
---
|
|
10
14
|
|
|
11
15
|
# Design
|
|
12
16
|
|
|
13
|
-
>
|
|
14
|
-
>
|
|
17
|
+
> **Index page** over `docs/design/` satellites (99 §4.5). Each surface area gets a
|
|
18
|
+
> `docs/design/<slug>.md` satellite; this index carries the surface map + pointers.
|
|
19
|
+
> Edit order: satellite first, then index row — same change (T9).
|
|
20
|
+
|
|
21
|
+
## UI/UX boundary
|
|
22
|
+
|
|
23
|
+
Repository-root `DESIGN.md` owns all UI/UX design, including visual language, design tokens,
|
|
24
|
+
components, layout, interaction, accessibility, and responsive behavior. Read and update it for UI
|
|
25
|
+
work; keep this document focused on non-UI surface design. If `DESIGN.md` is absent, follow the
|
|
26
|
+
project's established UI conventions rather than adding UI guidance here.
|
|
15
27
|
|
|
16
28
|
## 1. CLI commands
|
|
17
29
|
|
|
@@ -19,12 +31,18 @@ updated_at: 1970-01-01T00:00:00.000Z
|
|
|
19
31
|
_(command) <positional> [--flag <value>] [--json]
|
|
20
32
|
```
|
|
21
33
|
|
|
22
|
-
| Command | Description |
|
|
23
|
-
|
|
24
|
-
| _(command)_ | _(one-line description)_ |
|
|
34
|
+
| Command | Description | Design doc |
|
|
35
|
+
|---------|-------------|------------|
|
|
36
|
+
| _(command)_ | _(one-line description)_ | `docs/design/_(slug)_.md` |
|
|
25
37
|
|
|
26
38
|
## 2. Configuration keys
|
|
27
39
|
|
|
28
40
|
| Key | Type | Default | Description |
|
|
29
41
|
|-----|------|---------|-------------|
|
|
30
42
|
| _(key)_ | _(type)_ | _(default)_ | _(description)_ |
|
|
43
|
+
|
|
44
|
+
<!--
|
|
45
|
+
Shapes only — rationale lives in 00/03. Behavioral notes are shapes ("resolving zero rules exits 1"
|
|
46
|
+
— keep); justifications are not ("...because a silent gate is the worst failure mode" — cut).
|
|
47
|
+
Transcribe command signatures from the code registrations, never from memory.
|
|
48
|
+
-->
|
|
@@ -1,16 +1,22 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: Features
|
|
3
3
|
doc: 05_FEATURES
|
|
4
|
-
owns: STATUS — feature decomposition + state
|
|
4
|
+
owns: STATUS — feature decomposition + state; index over docs/features/
|
|
5
5
|
authority: derived
|
|
6
6
|
version: 1.0.0
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
derived_from: [00_ADR, 01_PRD]
|
|
8
|
+
owner: _(project owner)_
|
|
9
|
+
updated_at: {{init-date}}
|
|
10
|
+
read_before: finding a feature's state
|
|
11
|
+
edit_rules: 99 §6.6
|
|
12
|
+
sync: [T4, T9]
|
|
9
13
|
---
|
|
10
14
|
|
|
11
15
|
# Features
|
|
12
16
|
|
|
13
|
-
>
|
|
17
|
+
> **Index page** over `docs/features/` satellites (99 §4.5). Both the satellites and this index's
|
|
18
|
+
> generated region are **tool-owned** (e.g. `spur feature`/`ftree`); edit through the tool, never
|
|
19
|
+
> with raw file writes. Edit order: satellite first, then refresh index (T9).
|
|
14
20
|
|
|
15
21
|
## Status legend
|
|
16
22
|
|
|
@@ -18,6 +24,11 @@ updated_at: 1970-01-01T00:00:00.000Z
|
|
|
18
24
|
|
|
19
25
|
## Feature tree
|
|
20
26
|
|
|
21
|
-
| ID | Feature | Status | Parent | Notes |
|
|
22
|
-
|
|
23
|
-
| F1 | _(root feature)_ | ⏳ planned | — | _(one-line scope)_ |
|
|
27
|
+
| ID | Feature | Status | Parent | Notes | Satellite |
|
|
28
|
+
|----|---------|--------|--------|-------|-----------|
|
|
29
|
+
| F1 | _(root feature)_ | ⏳ planned | — | _(one-line scope)_ | `docs/features/F1__(slug)_.md` |
|
|
30
|
+
|
|
31
|
+
<!--
|
|
32
|
+
Never trust a row you have not verified — check status against code before citing or building on it.
|
|
33
|
+
One item per satellite; <feature-id> is the stable grep anchor. Renaming is a tool operation.
|
|
34
|
+
-->
|