do-better 1.0.0
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/LICENSE +21 -0
- package/README.md +265 -0
- package/bin/cli.js +262 -0
- package/do-better/SKILL.md +417 -0
- package/do-better/references/refute-charter.md +170 -0
- package/do-better/references/scoring.md +98 -0
- package/do-better/references/taxonomy.md +136 -0
- package/do-better/references/templates/charter-template.md +71 -0
- package/do-better/references/templates/finding-template.md +56 -0
- package/do-better/references/templates/rail-template.md +74 -0
- package/do-better/references/templates/roadmap-template.md +67 -0
- package/do-better/references/templates/ticket-template.md +78 -0
- package/do-better/references/verification.md +129 -0
- package/package.json +20 -0
- package/src/adlc.js +331 -0
- package/src/artifacts.js +580 -0
- package/src/charter.js +657 -0
- package/src/comprehend.js +553 -0
- package/src/identify.js +1119 -0
- package/src/llm.js +530 -0
- package/src/rail.js +533 -0
- package/src/refresh.js +256 -0
- package/src/roadmap.js +630 -0
- package/src/scan.js +313 -0
- package/src/state.js +260 -0
- package/src/utils.js +449 -0
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# Roadmap Scoring & Sequencing — D3 Rubric
|
|
2
|
+
|
|
3
|
+
The frontier model **proposes** per-finding attributes; deterministic code
|
|
4
|
+
**computes** scores and order. Judgment supplies inputs; arithmetic is never
|
|
5
|
+
delegated to a model.
|
|
6
|
+
|
|
7
|
+
## Per-finding attributes (frontier proposes)
|
|
8
|
+
|
|
9
|
+
For every verified finding, the model assigns:
|
|
10
|
+
|
|
11
|
+
| Attribute | Values | Meaning |
|
|
12
|
+
|---|---|---|
|
|
13
|
+
| `impact` | S / M / L / XL | how much better the system gets if addressed |
|
|
14
|
+
| `effort` | S / M / L / XL | cost to address, including verification |
|
|
15
|
+
| `confidence` | 0..1 | how sure we are the fix delivers the impact |
|
|
16
|
+
| `dependsOn` | finding ids | what must land first |
|
|
17
|
+
| `railsNeeded` | true/false | whether characterization rails must exist before touching it |
|
|
18
|
+
| `declineReason` | string (optional) | why this should NOT be done (conflicts with charter intent/constraints) |
|
|
19
|
+
|
|
20
|
+
Reconciliation is **by id**: findings the model omits get conservative defaults
|
|
21
|
+
`impact: M, effort: M, confidence: 0.5` — never dropped. Nothing silently
|
|
22
|
+
disappears between findings and roadmap.
|
|
23
|
+
|
|
24
|
+
## T-shirt tables
|
|
25
|
+
|
|
26
|
+
| Size | Impact value | Effort value |
|
|
27
|
+
|---|---|---|
|
|
28
|
+
| S | 1 | 1 |
|
|
29
|
+
| M | 2 | 2 |
|
|
30
|
+
| L | 3 | 3 |
|
|
31
|
+
| XL | 5 | 5 |
|
|
32
|
+
|
|
33
|
+
## The score
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
score = impact × confidence ÷ effort
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
then weighted by the approved charter (D0):
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
weighted = score × (charterWeight[dimension] / 3)
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
A weight of 3 is neutral; the floor guarantees every dimension has weight ≥ 1,
|
|
46
|
+
so no dimension can be zeroed out of the roadmap — only de-emphasized.
|
|
47
|
+
|
|
48
|
+
Worked example: a `high` security finding, impact L (3), confidence 0.8,
|
|
49
|
+
effort M (2), security charter weight 5:
|
|
50
|
+
`3 × 0.8 ÷ 2 = 1.2`, weighted `1.2 × (5/3) = 2.0`.
|
|
51
|
+
|
|
52
|
+
## Thresholds (deterministic)
|
|
53
|
+
|
|
54
|
+
| Rule | Threshold |
|
|
55
|
+
|---|---|
|
|
56
|
+
| Quick win (front-loaded into Now) | weighted score ≥ 1.5 AND effort = S |
|
|
57
|
+
| Declined (listed, never silently dropped) | weighted score < 0.3, or explicit `declineReason` |
|
|
58
|
+
| Phase bands | Now / Next / Later by descending score, subject to dependency feasibility |
|
|
59
|
+
|
|
60
|
+
## Sequencing rules (deterministic)
|
|
61
|
+
|
|
62
|
+
1. **Topological order** on `dependsOn` — an item never appears before its
|
|
63
|
+
prerequisites.
|
|
64
|
+
2. **Rails-first Phase 0**: environment-fix items (preflight red → "make it
|
|
65
|
+
runnable") and rail-prerequisite items (`railsNeeded` ancestors) come before
|
|
66
|
+
everything. You don't refactor what you can't run, and you don't change what
|
|
67
|
+
you can't pin.
|
|
68
|
+
3. **Quick wins forward**: qualifying items lead the Now phase — early visible
|
|
69
|
+
value buys trust for the long items.
|
|
70
|
+
4. **Score bands** fill Now → Next → Later, demoting items whose dependencies
|
|
71
|
+
sit in a later band.
|
|
72
|
+
5. **Cycles**: break the lowest-weighted-score edge in the cycle and warn. A
|
|
73
|
+
cycle is a planning bug, not a reason to halt.
|
|
74
|
+
|
|
75
|
+
## Declined items (D6)
|
|
76
|
+
|
|
77
|
+
Every finding that does not become a roadmap item appears in the roadmap's
|
|
78
|
+
`## Declined` section with its reason **and a risk-of-inaction line**. A
|
|
79
|
+
stakeholder must be able to see what was consciously not done and what that
|
|
80
|
+
choice costs. Silent omission is the failure mode this section exists to kill.
|
|
81
|
+
|
|
82
|
+
## Ticket derivation
|
|
83
|
+
|
|
84
|
+
Each Now and Next item becomes one ADLC-P2-shaped ticket
|
|
85
|
+
([templates/ticket-template.md](./templates/ticket-template.md)): self-contained
|
|
86
|
+
body, motivation linking back to `findings/F-*.md`, machine-verifiable
|
|
87
|
+
acceptance criteria each naming its verification method, scope globs, rails
|
|
88
|
+
paths, dependency edges with contract files. Tickets are **cold-start tested**
|
|
89
|
+
(D6 gate): a fresh agent with only the ticket must be able to execute it. Gaps
|
|
90
|
+
are repaired up to 2 rounds; a ticket still gapped is demoted to Later — and if
|
|
91
|
+
any Now/Next ticket remains gapped, the roadmap gate fails (exit 2).
|
|
92
|
+
|
|
93
|
+
## What scoring refuses to optimize
|
|
94
|
+
|
|
95
|
+
Findings count, roadmap length, and artifact volume are vanity metrics (D11).
|
|
96
|
+
The score exists to maximize **ticket survival rate** — items accepted into
|
|
97
|
+
execution without rework — and to keep retained functionality intact. A shorter
|
|
98
|
+
roadmap with higher ticket survival beats a longer one every time.
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# The Fixed Taxonomy Floor (D5)
|
|
2
|
+
|
|
3
|
+
Eight dimensions of "better," in canonical order. This is the **floor**, not a
|
|
4
|
+
menu: every engagement charter MUST carry a weight (1–5) for every dimension
|
|
5
|
+
below. The charter interview (D0) may *weight* dimensions and *add*
|
|
6
|
+
engagement-specific ones, but it may never drop one — the floor exists to
|
|
7
|
+
prevent charter blind spots ("nobody asked about security, so nobody looked").
|
|
8
|
+
A synthesized charter missing a dimension is corrected to weight 1 with a
|
|
9
|
+
`(floor)` note, never dropped.
|
|
10
|
+
|
|
11
|
+
Weight also governs **D2 finder-pool width**: with `--n` as the ceiling, a
|
|
12
|
+
weight 4–5 dimension fans the full `--n` distinct-lens finders per pass, weight
|
|
13
|
+
2–3 fans `max(1, floor(--n / 2))`, and weight 1 runs a single finder (no
|
|
14
|
+
pooling). So a heavily-weighted dimension is searched both first (descending
|
|
15
|
+
weight order) and wider. See the flag tables in `SKILL.md` / `README.md`.
|
|
16
|
+
|
|
17
|
+
Each section below is the **finder charter** for that dimension: what a
|
|
18
|
+
D2 finder chartered on this dimension hunts for, and what counts as concrete
|
|
19
|
+
evidence. Finders operate under the refutation doctrine in
|
|
20
|
+
[refute-charter.md](./refute-charter.md) — they are told to *disprove* the
|
|
21
|
+
claim that the codebase is acceptable on the dimension, with file:line
|
|
22
|
+
citations for every claim.
|
|
23
|
+
|
|
24
|
+
Canonical ids (used in charter weights, finding ids, and ticket categories):
|
|
25
|
+
`correctness`, `security`, `maintainability`, `performance`, `operability`,
|
|
26
|
+
`test-quality`, `dependency-health`, `dx`.
|
|
27
|
+
|
|
28
|
+
## Correctness risk
|
|
29
|
+
|
|
30
|
+
`id: correctness`
|
|
31
|
+
|
|
32
|
+
Hunt for code that can silently produce wrong results: unhandled error paths,
|
|
33
|
+
swallowed exceptions, race conditions and unsynchronized shared state, off-by-one
|
|
34
|
+
and boundary errors, implicit type coercions at trust boundaries, null/undefined
|
|
35
|
+
dereferences on optional data, time-zone and floating-point hazards, partial
|
|
36
|
+
writes without transactions or rollback, retry logic that double-applies effects,
|
|
37
|
+
and logic that contradicts the documented or evident intent (comments, names,
|
|
38
|
+
tests asserting one thing while code does another). Evidence is the exact
|
|
39
|
+
file:line where the wrong result can be produced, plus the input or sequence that
|
|
40
|
+
triggers it. The strongest correctness findings come with a runnable
|
|
41
|
+
reproduction; propose one whenever the claim is mechanically checkable.
|
|
42
|
+
|
|
43
|
+
## Security
|
|
44
|
+
|
|
45
|
+
`id: security`
|
|
46
|
+
|
|
47
|
+
Hunt for ways an attacker — external or internal — gains capability they should
|
|
48
|
+
not have: injection (SQL, shell, template, path traversal), missing or bypassable
|
|
49
|
+
authentication/authorization checks, secrets in source or config committed to the
|
|
50
|
+
repo, unvalidated input crossing a trust boundary, unsafe deserialization,
|
|
51
|
+
`eval`/dynamic-require on tainted data, child processes built from string
|
|
52
|
+
concatenation, permissive CORS, missing rate limits on state-changing endpoints,
|
|
53
|
+
sensitive data in logs or error messages, and outdated crypto or homegrown
|
|
54
|
+
crypto. Cite the exact sink and the path tainted data takes to reach it. Severity
|
|
55
|
+
tracks exploitability × blast radius, not theoretical purity.
|
|
56
|
+
|
|
57
|
+
## Maintainability / debt
|
|
58
|
+
|
|
59
|
+
`id: maintainability`
|
|
60
|
+
|
|
61
|
+
Hunt for structures that make every future change slower or riskier: god files
|
|
62
|
+
and god functions, copy-paste clones that must be changed in lockstep, cyclic
|
|
63
|
+
dependencies, dead code that still has to be read, abstraction layers that leak
|
|
64
|
+
or that exist for exactly one caller, configuration scattered across hardcoded
|
|
65
|
+
literals, naming that lies, TODO/FIXME/HACK clusters that mark known unfinished
|
|
66
|
+
surgery, and modules whose churn history shows repeated bug-fix commits (hot,
|
|
67
|
+
fragile code). Evidence is structural and locational — name the files, the line
|
|
68
|
+
ranges, and where possible the churn or clone counterpart that proves the cost
|
|
69
|
+
recurs.
|
|
70
|
+
|
|
71
|
+
## Performance
|
|
72
|
+
|
|
73
|
+
`id: performance`
|
|
74
|
+
|
|
75
|
+
Hunt for work the system does that it does not need to do, at the moments it can
|
|
76
|
+
least afford it: N+1 query patterns, unbounded result sets, synchronous I/O on
|
|
77
|
+
hot paths, O(n²) loops over data that grows, missing indexes implied by query
|
|
78
|
+
shapes, per-request recomputation of invariants, oversized payloads, chatty
|
|
79
|
+
service calls inside loops, memory retained beyond its useful life, and absent
|
|
80
|
+
caching where reads dwarf writes (or caching with no invalidation where writes
|
|
81
|
+
matter). Claims must name the code path and the scaling variable that makes it
|
|
82
|
+
hurt; "this could be slow" without a growth factor is not a finding.
|
|
83
|
+
|
|
84
|
+
## Operability
|
|
85
|
+
|
|
86
|
+
`id: operability`
|
|
87
|
+
|
|
88
|
+
Hunt for everything that makes the system hard to run, observe, and recover:
|
|
89
|
+
missing or useless logging at failure points, no health/readiness signals,
|
|
90
|
+
swallowed errors that turn outages into mysteries, absent timeouts and circuit
|
|
91
|
+
breakers on outbound calls, no graceful shutdown, configuration that only works
|
|
92
|
+
on one machine, deploy and migration steps that exist only in someone's head,
|
|
93
|
+
unbounded queues and retries that amplify incidents, and startup that fails
|
|
94
|
+
late instead of failing fast on missing prerequisites. Evidence cites where the
|
|
95
|
+
signal is missing (the catch block that drops the error, the fetch with no
|
|
96
|
+
timeout) — absence is locational too.
|
|
97
|
+
|
|
98
|
+
## Test quality
|
|
99
|
+
|
|
100
|
+
`id: test-quality`
|
|
101
|
+
|
|
102
|
+
Hunt for the gap between what the test suite appears to guarantee and what it
|
|
103
|
+
actually guarantees: load-bearing behaviors with no test at all (cross-check the
|
|
104
|
+
behavior inventory and rails map), tests with no assertions or assertions that
|
|
105
|
+
cannot fail, tests that mock the very thing under test, snapshot tests nobody
|
|
106
|
+
reads, flaky patterns (sleeps, ordering dependence, shared mutable fixtures),
|
|
107
|
+
test code that swallows errors, and suites that pass with the implementation
|
|
108
|
+
deleted (hollowness). Evidence cites the test file and line, and names the
|
|
109
|
+
production behavior left unguarded. Coverage percentage alone is never evidence.
|
|
110
|
+
|
|
111
|
+
## Dependency health
|
|
112
|
+
|
|
113
|
+
`id: dependency-health`
|
|
114
|
+
|
|
115
|
+
Hunt for risk imported through the dependency graph: dependencies past
|
|
116
|
+
end-of-life or unmaintained, known-vulnerable version ranges, lockfile drift or
|
|
117
|
+
absence, duplicate dependencies solving the same problem, deep coupling to a
|
|
118
|
+
dependency's internals (imports from `dist/` or private paths), licenses
|
|
119
|
+
incompatible with the engagement's constraints, and single points of failure
|
|
120
|
+
(one maintainer, one registry). Flag what can be verified from manifests and
|
|
121
|
+
lockfiles deterministically; mark CVE/EOL claims that require network
|
|
122
|
+
verification as "needs verification" rather than asserting them — see
|
|
123
|
+
[verification.md](./verification.md).
|
|
124
|
+
|
|
125
|
+
## Developer experience
|
|
126
|
+
|
|
127
|
+
`id: dx`
|
|
128
|
+
|
|
129
|
+
Hunt for friction that taxes every contributor on every change: setup that takes
|
|
130
|
+
hours or requires tribal knowledge, build/test cycles measured in tens of
|
|
131
|
+
minutes, incantations that exist only in CI config or shell history, missing or
|
|
132
|
+
lying README instructions, inconsistent formatting with no enforcement, error
|
|
133
|
+
messages that don't say what to do, slow or noisy CI that trains people to
|
|
134
|
+
ignore it, and onboarding gaps the glossary and codemap expose. Evidence is the
|
|
135
|
+
concrete command, file, or absence — "DX is bad" is vibes; "`npm test` takes 14
|
|
136
|
+
minutes because X (file:line)" is a finding.
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# Charter Template — `.dobetter/charter.md` (D0 output)
|
|
2
|
+
|
|
3
|
+
Fill every placeholder. The frontmatter keys and shapes below are a contract:
|
|
4
|
+
`parseCharter` validates them, and the taxonomy floor (D5) requires **all 8
|
|
5
|
+
dimension ids present with weight 1–5** — a dimension the interview didn't
|
|
6
|
+
prioritize gets weight 1 with a `(floor)` note in the rationale, never removed.
|
|
7
|
+
|
|
8
|
+
Frontmatter uses the zero-dependency subset: flat scalars, inline arrays of
|
|
9
|
+
scalars, one level of nesting. Each `extraDimensions` entry is a single
|
|
10
|
+
pipe-delimited scalar string `id|Label|weight` (e.g. `ci-reliability|CI
|
|
11
|
+
reliability|4`); the list is empty when the engagement adds none.
|
|
12
|
+
|
|
13
|
+
```markdown
|
|
14
|
+
---
|
|
15
|
+
approved: false
|
|
16
|
+
headSha: <40-hex sha the interview facts were drawn from>
|
|
17
|
+
generatedAt: <ISO 8601 timestamp>
|
|
18
|
+
intent: <stabilize | scale | extend | handoff>
|
|
19
|
+
weights:
|
|
20
|
+
correctness: <1-5>
|
|
21
|
+
security: <1-5>
|
|
22
|
+
maintainability: <1-5>
|
|
23
|
+
performance: <1-5>
|
|
24
|
+
operability: <1-5>
|
|
25
|
+
test-quality: <1-5>
|
|
26
|
+
dependency-health: <1-5>
|
|
27
|
+
dx: <1-5>
|
|
28
|
+
extraDimensions: [<id|Label|weight>, ...]
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
# Engagement Charter — <repo name>
|
|
32
|
+
|
|
33
|
+
## Pain
|
|
34
|
+
|
|
35
|
+
<What hurts today, in the stakeholder's words. One bullet per pain point, each
|
|
36
|
+
tied where possible to a scan fact that evidences it
|
|
37
|
+
(`path/to/file.js:123@a1b2c3d`).>
|
|
38
|
+
|
|
39
|
+
## Intent
|
|
40
|
+
|
|
41
|
+
<The 12-month intent — stabilize, scale, extend, or hand off — and what that
|
|
42
|
+
implies for prioritization. One short paragraph.>
|
|
43
|
+
|
|
44
|
+
## Constraints
|
|
45
|
+
|
|
46
|
+
<Hard constraints the roadmap must respect: freeze windows, compliance,
|
|
47
|
+
budgets, no-touch areas, team capacity. One bullet each. "None stated" is a
|
|
48
|
+
valid entry — absence must be explicit.>
|
|
49
|
+
|
|
50
|
+
## Dimension weights
|
|
51
|
+
|
|
52
|
+
<One bullet per taxonomy dimension, in canonical order: the weight, and one
|
|
53
|
+
sentence of rationale citing the interview answer or scan fact that justifies
|
|
54
|
+
it. Floor-corrected dimensions read: "1 (floor) — not prioritized by
|
|
55
|
+
stakeholder; retained per taxonomy floor.">
|
|
56
|
+
|
|
57
|
+
## Established from the codebase
|
|
58
|
+
|
|
59
|
+
<Questions answered deterministically from D-1 scan facts instead of asked —
|
|
60
|
+
each as "Q → answer, evidence: <citation or scan fact>". Empty section allowed
|
|
61
|
+
but must be present.>
|
|
62
|
+
|
|
63
|
+
## Engagement dimensions
|
|
64
|
+
|
|
65
|
+
<One bullet per extra dimension: id, label, weight, and why this engagement
|
|
66
|
+
needs it beyond the fixed taxonomy. "None" if extraDimensions is empty.>
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Approval: a human reviews and edits this file, then approves (interactively at
|
|
70
|
+
the end of the interview, or later via `do-better charter --approve`). Approval
|
|
71
|
+
hashes the file; the hash is the anchor every downstream phase trusts.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Finding Template — `.dobetter/findings/F-<DIM>-NNNN.md` (D2 output)
|
|
2
|
+
|
|
3
|
+
One file per **verified** finding. Unverified candidates are killed, never
|
|
4
|
+
written — if a file exists in `findings/`, it survived reproduce-or-kill
|
|
5
|
+
([../verification.md](../verification.md)). The id embeds the dimension
|
|
6
|
+
(first 4 letters, uppercase) and a zero-padded sequence: `F-SEC-0003`,
|
|
7
|
+
`F-CORR-0012`.
|
|
8
|
+
|
|
9
|
+
Frontmatter shapes are a contract (`readFindings` parses them). `evidence` is
|
|
10
|
+
an inline array of canonical citation strings `path:line@sha`; `reproduction`
|
|
11
|
+
is one level of nesting; `stale` is written `false` here and only ever flipped
|
|
12
|
+
by `refresh`, never by identify.
|
|
13
|
+
|
|
14
|
+
```markdown
|
|
15
|
+
---
|
|
16
|
+
id: F-<DIM>-NNNN
|
|
17
|
+
dimension: <correctness|security|maintainability|performance|operability|test-quality|dependency-health|dx|<extra-dimension-id>>
|
|
18
|
+
title: <short imperative summary>
|
|
19
|
+
severity: <critical|high|medium|low>
|
|
20
|
+
confidence: <0..1>
|
|
21
|
+
evidence: [<path/to/file.js:123@a1b2c3d>, ...]
|
|
22
|
+
reproduction:
|
|
23
|
+
method: <command|reread|static>
|
|
24
|
+
record: <command + captured output, or blind-reread verdict rationale; single line, escaped>
|
|
25
|
+
exitCode: <integer or null>
|
|
26
|
+
status: verified
|
|
27
|
+
foundAt: <ISO 8601 timestamp>
|
|
28
|
+
headSha: <40-hex repo HEAD at verification time>
|
|
29
|
+
stale: false
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
# <title>
|
|
33
|
+
|
|
34
|
+
## Claim
|
|
35
|
+
|
|
36
|
+
<One paragraph: what is wrong, why it matters on this dimension, what triggers
|
|
37
|
+
it. Plain language a stakeholder can read.>
|
|
38
|
+
|
|
39
|
+
## Evidence
|
|
40
|
+
|
|
41
|
+
<One bullet per citation: the citation (`path/to/file.js:123@a1b2c3d`) plus a
|
|
42
|
+
one-line quote or description of what that location shows. Every bullet's
|
|
43
|
+
citation must verify deterministically — file exists, line in range.>
|
|
44
|
+
|
|
45
|
+
## Reproduction record
|
|
46
|
+
|
|
47
|
+
<The full reproduction: for `command`, the exact command, its stdout/stderr,
|
|
48
|
+
and exit code; for `reread`, the blind verifier's CONFIRM rationale; for
|
|
49
|
+
`static`, the deterministic check and its result. This record is what refresh
|
|
50
|
+
re-runs to decide resolved-vs-still-present.>
|
|
51
|
+
|
|
52
|
+
## Impact
|
|
53
|
+
|
|
54
|
+
<What happens if nothing is done — the risk-of-inaction in concrete terms.
|
|
55
|
+
Feeds the roadmap's risk-of-inaction line.>
|
|
56
|
+
```
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Rail Template — Characterization-Test Authoring (D4)
|
|
2
|
+
|
|
3
|
+
A **rail** is a characterization test that pins a behavior exactly as it is
|
|
4
|
+
today, so execution work can prove it broke nothing. Rails are authored in a
|
|
5
|
+
**fresh context** that sees ONLY: the behavior-inventory entry, the boundary
|
|
6
|
+
I/O shape, and this template — never implementation internals (P3
|
|
7
|
+
separate-context doctrine). A rail written by someone who read the
|
|
8
|
+
implementation tests the implementation's opinion of itself.
|
|
9
|
+
|
|
10
|
+
## Where rails live
|
|
11
|
+
|
|
12
|
+
- File: `<repo>/test/dobetter-rails/<behaviorId>.rail.test.js` (or the repo's
|
|
13
|
+
idiomatic test directory if one is detected — rails run under the repo's own
|
|
14
|
+
runner or `node --test`).
|
|
15
|
+
- Pointers only in `.dobetter/rails/manifest.md`; the tests live in the repo's
|
|
16
|
+
test tree and ship with it.
|
|
17
|
+
|
|
18
|
+
## Authoring rules
|
|
19
|
+
|
|
20
|
+
1. **Boundary-level golden-master style.** Capture the behavior at its
|
|
21
|
+
observable surface, by kind:
|
|
22
|
+
- `route` — start the app locally, hit it with builtin `fetch`, assert
|
|
23
|
+
status + headers that matter + body (normalized for timestamps/ids).
|
|
24
|
+
- `cli` — spawn the command (`spawnSync`, no shell), assert exit code,
|
|
25
|
+
stdout, stderr.
|
|
26
|
+
- `job`/`event` — invoke the entry, assert emitted effects.
|
|
27
|
+
- `db-write` — snapshot relevant rows before, run, assert the after-state
|
|
28
|
+
delta.
|
|
29
|
+
2. **Bug-compatible pinning.** Assert the *current actual* output, even when it
|
|
30
|
+
is odd or known-wrong. Annotate, don't fix:
|
|
31
|
+
|
|
32
|
+
```js
|
|
33
|
+
// pinned current behavior, possibly a bug: see F-CORR-0007
|
|
34
|
+
assert.equal(res.status, 200); // (spec says 404; current code returns 200)
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Rails preserve behavior; the roadmap changes it. A rail that asserts the
|
|
38
|
+
*desired* behavior is red on arrival and useless as a rail.
|
|
39
|
+
3. **Deterministic.** Normalize or freeze time, ids, ordering, and environment.
|
|
40
|
+
A flaky rail is worse than no rail — it trains people to ignore red.
|
|
41
|
+
4. **One behavior per rail file.** Named by behavior id (`B-014.rail.test.js`),
|
|
42
|
+
header comment citing the inventory entry and its citation
|
|
43
|
+
(`path:line@sha`).
|
|
44
|
+
5. **Self-contained setup.** The rail starts/seeds what it needs and tears it
|
|
45
|
+
down; it must pass on a fresh clone where preflight is green.
|
|
46
|
+
|
|
47
|
+
## Quality gates the rail must survive
|
|
48
|
+
|
|
49
|
+
- **Green on current code** — any rail red after 2 fix rounds is deleted and
|
|
50
|
+
the behavior recorded as `gap: could not pin`. Never ship a red rail.
|
|
51
|
+
- **Hollow-test audit** — mutants in the rail's assertions must be killed. A
|
|
52
|
+
rail that passes with its assertions mutated is fog, not glass; survivors get
|
|
53
|
+
one fix round, then the rail is deleted and the gap recorded. When
|
|
54
|
+
hollow-test is unavailable: deletion spot-check (comment out the behavior's
|
|
55
|
+
entry line; the rail must go red).
|
|
56
|
+
- **Frozen** — once green and audited, the rail path is appended to every
|
|
57
|
+
backlog ticket's `rails` array so ADLC rails-guard freezes it mechanically.
|
|
58
|
+
Execution agents may not edit rails; a rail change is a human decision.
|
|
59
|
+
|
|
60
|
+
## Manifest row shape — `.dobetter/rails/manifest.md`
|
|
61
|
+
|
|
62
|
+
One table row per authored rail:
|
|
63
|
+
|
|
64
|
+
```markdown
|
|
65
|
+
| behavior | rail file | style | pinned-at SHA | audit | frozen |
|
|
66
|
+
|---|---|---|---|---|---|
|
|
67
|
+
| B-014 | test/dobetter-rails/B-014.rail.test.js | http golden-master | a1b2c3d | hollow: killed 4/4 | yes |
|
|
68
|
+
| B-021 | test/dobetter-rails/B-021.rail.test.js | cli golden-master | a1b2c3d | spot-check | yes |
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
`audit` values: `hollow: killed n/n` · `spot-check` · `unaudited (hollow-test
|
|
72
|
+
absent)`. Below the table, a `## Gaps` section lists every targeted behavior
|
|
73
|
+
without a green rail and why (`could not pin`, `env not runnable`, `vacuous —
|
|
74
|
+
deleted`). A gap declared is a known risk; a gap omitted is a lie.
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Roadmap Template — `.dobetter/ROADMAP.md` (D3 output)
|
|
2
|
+
|
|
3
|
+
The executive deliverable. Dual artifact, one source of truth: every item here
|
|
4
|
+
maps to verified findings (`findings/F-*.md`) and Now/Next items map to backlog
|
|
5
|
+
tickets. It is a **living document** — idempotent re-runs reconcile prior state
|
|
6
|
+
and move items into Done / Regressed rather than regenerating from scratch.
|
|
7
|
+
|
|
8
|
+
```markdown
|
|
9
|
+
---
|
|
10
|
+
generatedAt: <ISO 8601 timestamp>
|
|
11
|
+
headSha: <40-hex repo HEAD this roadmap was generated against>
|
|
12
|
+
basedOnFindings: <count of verified findings consumed>
|
|
13
|
+
approved: false
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
# Technical Roadmap — <repo name>
|
|
17
|
+
|
|
18
|
+
## Executive summary
|
|
19
|
+
|
|
20
|
+
<3–6 sentences: the state of the codebase against the charter, the top risks,
|
|
21
|
+
what Now buys, and what was consciously declined. No item lists here —
|
|
22
|
+
judgment, written for a stakeholder who reads nothing else.>
|
|
23
|
+
|
|
24
|
+
## Phase 0 — Rails & runnability
|
|
25
|
+
|
|
26
|
+
<Items that must precede all change: environment fixes (preflight red →
|
|
27
|
+
"Make the environment runnable"), and characterization-rail prerequisites.
|
|
28
|
+
Empty phase must say "None required — environment runnable, rails in place.">
|
|
29
|
+
|
|
30
|
+
<!-- Item shape, used in every phase section: -->
|
|
31
|
+
- **<title>** (T<id> · score <weighted score> · <severity>)
|
|
32
|
+
- Evidence: <links to findings files, e.g. [F-SEC-0003](findings/F-SEC-0003.md)>
|
|
33
|
+
- Risk of inaction: <one concrete sentence>
|
|
34
|
+
|
|
35
|
+
## Now
|
|
36
|
+
|
|
37
|
+
<Quick wins first (score ≥ 1.5, effort S), then highest-scored
|
|
38
|
+
dependency-feasible items. Each item: title, finding links, score,
|
|
39
|
+
risk-of-inaction.>
|
|
40
|
+
|
|
41
|
+
## Next
|
|
42
|
+
|
|
43
|
+
<Same item shape. Items here have tickets too; items demoted by coldstart
|
|
44
|
+
failures land in Later, flagged.>
|
|
45
|
+
|
|
46
|
+
## Later
|
|
47
|
+
|
|
48
|
+
<Same item shape, lighter detail allowed. Includes coldstart-demoted tickets,
|
|
49
|
+
flagged `coldstart: failed`.>
|
|
50
|
+
|
|
51
|
+
## Done / Regressed
|
|
52
|
+
|
|
53
|
+
<Living-document ledger. `✅ done — <title> (resolved @ <sha>)` for items whose
|
|
54
|
+
findings no longer reproduce; `⚠ regressed — <title> (re-verified @ <sha>)` for
|
|
55
|
+
previously-done items whose finding came back, and for retained behaviors that
|
|
56
|
+
changed with no roadmap item claiming the change. Empty on first run.>
|
|
57
|
+
|
|
58
|
+
## Declined
|
|
59
|
+
|
|
60
|
+
<Every finding that did not become a roadmap item: title, finding link, reason
|
|
61
|
+
(explicit declineReason or score < 0.3), and a risk-of-inaction line. Nothing
|
|
62
|
+
is silently dropped — an empty section must state "Nothing declined.">
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Approval: human gate 2. Review this file and `backlog/`, edit freely (edits are
|
|
66
|
+
re-hashed, not rejected), then `do-better roadmap --approve`. Approval requires
|
|
67
|
+
the coldstart gate clean.
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Ticket Template — `.dobetter/backlog/<id>.md` (D3 output)
|
|
2
|
+
|
|
3
|
+
One markdown file per Now/Next roadmap item, **plus** the machine mirror
|
|
4
|
+
`backlog/tickets.json` in the exact ADLC `.adlc/tickets.json` schema
|
|
5
|
+
(`{ "tickets": [ { id, title, body, scope, rails, edges, duration, category,
|
|
6
|
+
budget? } ] }`). The JSON is the source of truth consumed by `coldstart
|
|
7
|
+
--tickets .dobetter/backlog/tickets.json` and ADLC P3/P4 intake; the markdown
|
|
8
|
+
is the human-review surface. The two are written together and must agree.
|
|
9
|
+
|
|
10
|
+
A ticket must be **self-contained**: a fresh agent with only this ticket (and
|
|
11
|
+
the repo) can execute it. That is what the coldstart gate tests. Embed data
|
|
12
|
+
shapes, contracts, and file paths — never reference "the discussion" or "as
|
|
13
|
+
mentioned above."
|
|
14
|
+
|
|
15
|
+
```markdown
|
|
16
|
+
---
|
|
17
|
+
id: T<n>
|
|
18
|
+
title: <short imperative title>
|
|
19
|
+
category: <dimension id of the driving finding>
|
|
20
|
+
duration: <relative build-time estimate, positive number>
|
|
21
|
+
scope: [<glob>, ...]
|
|
22
|
+
rails: [<path>, ...]
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
# T<n> — <title>
|
|
26
|
+
|
|
27
|
+
## Motivation
|
|
28
|
+
|
|
29
|
+
<Why this work exists, linking every driving finding:
|
|
30
|
+
[F-SEC-0003](../findings/F-SEC-0003.md). Quote the risk-of-inaction. A ticket
|
|
31
|
+
whose motivation cites no finding is not a do-better ticket.>
|
|
32
|
+
|
|
33
|
+
## Acceptance criteria
|
|
34
|
+
|
|
35
|
+
<Each criterion is machine-verifiable and NAMES its verification method (F1
|
|
36
|
+
defense). One bullet per criterion, exactly one method each:>
|
|
37
|
+
- <criterion> — verified by: <a test to be written at `<path>`>
|
|
38
|
+
- <criterion> — verified by: <a command whose output is asserted: `<command>` → <expected>>
|
|
39
|
+
- <criterion> — verified by: <a behavior demonstrated: <observable before/after>>
|
|
40
|
+
|
|
41
|
+
## Scope
|
|
42
|
+
|
|
43
|
+
<The declared file globs this ticket may touch, one per line, matching the
|
|
44
|
+
frontmatter `scope` array. Work outside scope is escalation, not improvisation.>
|
|
45
|
+
|
|
46
|
+
## Rails
|
|
47
|
+
|
|
48
|
+
<The characterization rails that must stay green while executing this ticket
|
|
49
|
+
(paths matching the frontmatter `rails` array — frozen, hollow-audited; see
|
|
50
|
+
rails/manifest.md). D4 appends authored rail paths here mechanically.>
|
|
51
|
+
|
|
52
|
+
## Dependencies
|
|
53
|
+
|
|
54
|
+
<One line per edge: `T<m> — contract: <path/to/contract/file>` meaning this
|
|
55
|
+
ticket must complete before T<m>, with the named file as the interface between
|
|
56
|
+
them. "None" if independent. Mirrors `edges` in tickets.json.>
|
|
57
|
+
|
|
58
|
+
## Partition hints
|
|
59
|
+
|
|
60
|
+
<How to split execution contexts if the ticket is run by parallel agents: which
|
|
61
|
+
files group together, what must be sequential. Optional but recommended.>
|
|
62
|
+
|
|
63
|
+
## Suppression allowances
|
|
64
|
+
|
|
65
|
+
<Optional `allow-suppression: <marker>` lines, one per allowed lint/test
|
|
66
|
+
suppression marker this ticket may legitimately introduce. Omit the section if
|
|
67
|
+
none — absence means zero suppressions allowed.>
|
|
68
|
+
|
|
69
|
+
## Coldstart
|
|
70
|
+
|
|
71
|
+
<Gate record: `clean` (round N) or `failed — demoted to Later`, with the gap
|
|
72
|
+
list from the coldstart run. Written by the tool, kept current on re-runs.>
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Validation (mirrors aidlc `validateTicket`, applied before writing): string
|
|
76
|
+
`id` and `title` required; `scope`/`rails` arrays; every `edges[].to` a string
|
|
77
|
+
naming a known ticket id; `duration` a positive number. An invalid ticket gets
|
|
78
|
+
one repair round, then is demoted to Later with a warning.
|