@open-tomato/rafa 0.44.0 → 0.46.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.
Files changed (142) hide show
  1. package/README.md +280 -42
  2. package/dist/PROMPT.md +18 -1
  3. package/dist/adapters/logger/settings.d.ts +132 -0
  4. package/dist/bugs/closest.d.ts +19 -0
  5. package/dist/bugs/fenced.d.ts +8 -0
  6. package/dist/bugs/places.d.ts +20 -0
  7. package/dist/bugs/record.d.ts +145 -0
  8. package/dist/bugs/title.d.ts +83 -0
  9. package/dist/bundled/agents/doc-updater.md +17 -3
  10. package/dist/bundled/agents/loop-implementer.md +14 -2
  11. package/dist/bundled/operators/skills/rafa-stretch-pit-stop/SKILL.md +10 -3
  12. package/dist/bundled/operators/skills/rafa-stretch-sweep/SKILL.md +5 -0
  13. package/dist/bundled/skills/dev-planner/SKILL.md +120 -24
  14. package/dist/bundled/skills/documentation/SKILL.md +2 -12
  15. package/dist/cli.js +72387 -59411
  16. package/dist/config/entry.d.ts +119 -0
  17. package/dist/config/index.d.ts +36 -0
  18. package/dist/config/index.js +51 -0
  19. package/dist/config/shape.d.ts +232 -0
  20. package/dist/config-registry.d.ts +127 -0
  21. package/dist/config-schema-board-project.d.ts +157 -0
  22. package/dist/config-schema-bugs.d.ts +71 -0
  23. package/dist/config-schema-errors.d.ts +54 -0
  24. package/dist/config-schema-features.d.ts +64 -0
  25. package/dist/config-schema-hub.d.ts +150 -0
  26. package/dist/config-schema-issues.d.ts +95 -0
  27. package/dist/config-schema-logger.d.ts +91 -0
  28. package/dist/config-schema-loop-continue.d.ts +122 -0
  29. package/dist/config-schema-loop-retries.d.ts +94 -0
  30. package/dist/config-schema-release.d.ts +307 -0
  31. package/dist/config-schema-tests.d.ts +170 -0
  32. package/dist/config-schema-triage.d.ts +142 -0
  33. package/dist/config-schema-wrap-up.d.ts +96 -0
  34. package/dist/core/command/command.d.ts +228 -0
  35. package/dist/core/command/confirm.d.ts +67 -0
  36. package/dist/core/command/index.d.ts +112 -0
  37. package/dist/core/command/lazy.d.ts +54 -0
  38. package/dist/core/command/registry-types.d.ts +96 -0
  39. package/dist/core/command/running.d.ts +96 -0
  40. package/dist/core/command/spends.d.ts +39 -0
  41. package/dist/core/command/types.d.ts +92 -0
  42. package/dist/core/command/version.d.ts +4 -0
  43. package/dist/core/config/branch-template.d.ts +20 -0
  44. package/dist/core/config/config-items.d.ts +86 -0
  45. package/dist/core/config/config-load.d.ts +47 -0
  46. package/dist/core/config/config-origins.d.ts +57 -0
  47. package/dist/core/config/config-readers.d.ts +167 -0
  48. package/dist/core/config/config-schema.d.ts +207 -0
  49. package/dist/core/config/config-sections.d.ts +493 -0
  50. package/dist/core/config/config.d.ts +320 -0
  51. package/dist/core/config/core-section.d.ts +39 -0
  52. package/dist/core/config/dangerous.d.ts +58 -0
  53. package/dist/core/config/default-routing.d.ts +16 -0
  54. package/dist/core/config/index.d.ts +141 -0
  55. package/dist/core/config/scope.d.ts +42 -0
  56. package/dist/core/config/section.d.ts +206 -0
  57. package/dist/core/config/sections.d.ts +45 -0
  58. package/dist/core/config/standard-schema.d.ts +27 -0
  59. package/dist/core/git/commit.d.ts +232 -0
  60. package/dist/core/git/gh-runner.d.ts +24 -0
  61. package/dist/core/git/git.d.ts +22 -0
  62. package/dist/core/git/index.d.ts +85 -0
  63. package/dist/core/loop/claude.d.ts +388 -0
  64. package/dist/core/loop/hop-record.d.ts +52 -0
  65. package/dist/core/loop/index.d.ts +179 -0
  66. package/dist/core/loop/session-env.d.ts +20 -0
  67. package/dist/core/loop/session-record-parse.d.ts +63 -0
  68. package/dist/core/loop/sessions.d.ts +408 -0
  69. package/dist/core/loop/suite-failure.d.ts +25 -0
  70. package/dist/core/output/active.d.ts +100 -0
  71. package/dist/core/output/stream.d.ts +20 -0
  72. package/dist/core/output/text.d.ts +55 -0
  73. package/dist/core/plan/block-reader.d.ts +46 -0
  74. package/dist/core/plan/blocks.d.ts +139 -0
  75. package/dist/core/plan/declaration.d.ts +366 -0
  76. package/dist/core/plan/plan-stamp.d.ts +75 -0
  77. package/dist/core/runtime/identity.d.ts +21 -0
  78. package/dist/core/runtime/index.d.ts +46 -0
  79. package/dist/effort/store/bring-forward.d.ts +131 -0
  80. package/dist/effort/store/check-rows.d.ts +31 -0
  81. package/dist/effort/store/commit-stats.d.ts +42 -0
  82. package/dist/effort/store/copy.d.ts +35 -0
  83. package/dist/effort/store/development-build.d.ts +105 -0
  84. package/dist/effort/store/effort-levels.d.ts +13 -0
  85. package/dist/effort/store/findings.d.ts +214 -0
  86. package/dist/effort/store/fix-schema.d.ts +184 -0
  87. package/dist/effort/store/index.js +10 -7
  88. package/dist/effort/store/location.d.ts +44 -0
  89. package/dist/effort/store/merge-commit-gaps.d.ts +68 -0
  90. package/dist/effort/store/merge-conflicts.d.ts +91 -0
  91. package/dist/effort/store/merge-rules.d.ts +82 -0
  92. package/dist/effort/store/merge-store.d.ts +211 -0
  93. package/dist/effort/store/merge-union.d.ts +92 -0
  94. package/dist/effort/store/migrate.d.ts +146 -0
  95. package/dist/effort/store/migrations.d.ts +92 -0
  96. package/dist/effort/store/ndjson-files.d.ts +114 -0
  97. package/dist/effort/store/origins.d.ts +116 -0
  98. package/dist/effort/store/plan-stubs.d.ts +79 -0
  99. package/dist/effort/store/rebuild-aside.d.ts +172 -0
  100. package/dist/effort/store/schema-plan.d.ts +102 -0
  101. package/dist/effort/store/session-row-types.d.ts +64 -0
  102. package/dist/effort/store/settings.d.ts +13 -0
  103. package/dist/effort/store/sqlite.d.ts +340 -0
  104. package/dist/effort/store/store-generation.d.ts +17 -0
  105. package/dist/effort/store/store-identity.d.ts +220 -0
  106. package/dist/effort/store/store-meta.d.ts +305 -0
  107. package/dist/effort/store/store-replaced.d.ts +72 -0
  108. package/dist/effort/store/types.d.ts +223 -0
  109. package/dist/errors/codes.d.ts +56 -0
  110. package/dist/errors/rafa-codes.d.ts +36 -0
  111. package/dist/index-2a7nb3an.js +125 -0
  112. package/dist/{index-57mmzkcn.js → index-39kbcw68.js} +516 -217
  113. package/dist/{index-nv34ptht.js → index-77ajfffn.js} +14 -9
  114. package/dist/index-cy98y87p.js +2597 -0
  115. package/dist/index-gqz4jn6j.js +13447 -0
  116. package/dist/index-gvek4r8m.js +710 -0
  117. package/dist/index-j4k2vdz3.js +1125 -0
  118. package/dist/index-jh1r4kcn.js +1067 -0
  119. package/dist/index-ykggr043.js +540 -0
  120. package/dist/index-z1w83f81.js +4 -0
  121. package/dist/index.js +16091 -22798
  122. package/dist/learning/index.js +5 -6
  123. package/dist/plan/index.js +12 -11
  124. package/dist/plan-prompt.md +11 -2
  125. package/dist/ports/index.d.ts +732 -0
  126. package/dist/ports/learning.d.ts +101 -0
  127. package/dist/ports/log-level.d.ts +13 -0
  128. package/dist/ports/spec-review.d.ts +66 -0
  129. package/dist/pr/checks.d.ts +133 -0
  130. package/dist/pr/types.d.ts +422 -0
  131. package/dist/ready-4f8edezt.js +2016 -0
  132. package/dist/release-templates/release-bot-fragment.yml +153 -0
  133. package/dist/release-templates/release-publish.yml +110 -0
  134. package/dist/release-templates/release-settle.yml +122 -0
  135. package/dist/release-templates/release-tag.yml +102 -0
  136. package/dist/report/parse.d.ts +415 -0
  137. package/dist/schema/project-id.d.ts +79 -0
  138. package/dist/schema/tiers.d.ts +107 -0
  139. package/package.json +42 -4
  140. package/dist/index-6q30dtgm.js +0 -6342
  141. package/dist/index-cknayrpc.js +0 -2414
  142. package/dist/index-hf2k497d.js +0 -16
@@ -0,0 +1,145 @@
1
+ /**
2
+ * The bug record (#951): the fields every bug is filed with, the check
3
+ * that refuses a record missing one, the body the fields are written as,
4
+ * and the parser that reads a body back.
5
+ *
6
+ * ## Three axes
7
+ *
8
+ * - The title, for a person reading a list: `summary`, rendered through
9
+ * the project's template (`./title.ts`) with the boundary fields.
10
+ * - The boundary, for knowing where two pieces of work overlap:
11
+ * `project`, `module`, `action`.
12
+ * - The context, for knowing what the error looked like and where:
13
+ * `environment`, `versions`, `errorLine`, `artifact`, and the cause
14
+ * (`cause`, `proposed`, `suspected`).
15
+ *
16
+ * `reproduce` and `rerun` stand beside them: the steps, or the condition
17
+ * that revealed the bug, and the one command that shows it again.
18
+ *
19
+ * ## The body
20
+ *
21
+ * One `## <Heading>` section per field that holds a value, in the order
22
+ * of {@link BUG_FIELDS}. Two headings are triage's own: the description
23
+ * is `What` and the error output is `Artifact`, both in the fence
24
+ * `fenced` writes (`./fenced.ts`). So triage's similarity
25
+ * step (`issueTextOf`, `../triage/similarity.ts`) reads a record as it
26
+ * reads a body the loop filed, and a body the loop filed parses as a
27
+ * record with the other fields missing.
28
+ *
29
+ * A value is written plain only when the check holds it to a token:
30
+ * the cause codes, the module, the action and the place. Every free text
31
+ * is fenced, so an `@name` or a `#12` inside it never pings or links on
32
+ * the tracker. The summary has no section: the title holds it.
33
+ *
34
+ * {@link parseBugRecord} reads `##` and `###` headings, a value in a
35
+ * fence or as text, and a heading inside a fence as text. A fence is
36
+ * three or more backticks or tildes, indented by three spaces at most,
37
+ * closed by a line of the same mark at least as long. `###` and
38
+ * `_No response_` are what a GitHub issue form writes
39
+ * (`.github/ISSUE_TEMPLATE/bug.yml`).
40
+ *
41
+ * Nothing a filer wrote is dropped without a word. The text ahead of the
42
+ * first heading is the description when no `What` section holds one, and
43
+ * {@link otherSections} answers the rest for the caller to file after
44
+ * the record's own sections: that text beside a `What` section, a
45
+ * section that is no field, and the second section under one heading.
46
+ *
47
+ * ## The check
48
+ *
49
+ * {@link bugProblems} answers every problem at once, each sentence
50
+ * opening with the field it names, so a filer fixes the line in one go.
51
+ * `module`, `action` and `environment` may be the word `unknown`;
52
+ * `reproduce` never is; `cause` is a code of the list, or
53
+ * `<family>:new-context` with the leaf the filer would have used kept as
54
+ * `proposed` (`context/error-codes.md`).
55
+ *
56
+ * Nothing here redacts: a caller takes local paths and secrets out of
57
+ * the values before it builds the record.
58
+ */
59
+ import type { ErrorCodeEntry } from '@open-tomato/rafa/errors/codes';
60
+ /** A bug's fields, each null until something fills it. */
61
+ export interface BugRecord {
62
+ /** One line saying what is wrong; the title's last part. */
63
+ readonly summary: string | null;
64
+ /** The description. The `What` section. */
65
+ readonly what: string | null;
66
+ /** The steps, or the condition that revealed the bug. Never `unknown`. */
67
+ readonly reproduce: string | null;
68
+ /** One command that shows the bug again. */
69
+ readonly rerun: string | null;
70
+ /** The first line of the error output, with what changes between runs taken out. */
71
+ readonly errorLine: string | null;
72
+ /** The error output and its stack. The `Artifact` section. */
73
+ readonly artifact: string | null;
74
+ /** The cause code: one of the list, or `<family>:new-context`. */
75
+ readonly cause: string | null;
76
+ /** The leaf the filer would have used, beside a `new-context` cause. */
77
+ readonly proposed: string | null;
78
+ /** What the filer thinks went wrong, in words. */
79
+ readonly suspected: string | null;
80
+ /** The module the bug is in, or `unknown`. */
81
+ readonly module: string | null;
82
+ /** What was running: a command, a step, a test; or `unknown`. */
83
+ readonly action: string | null;
84
+ /** The project, where one tracker holds several. */
85
+ readonly project: string | null;
86
+ /** The place it was seen: `local`, `ci`, `prod`, one the project adds, or `unknown`. */
87
+ readonly environment: string | null;
88
+ /** The rafa version, the commit and the package, one `name: value` line each. */
89
+ readonly versions: string | null;
90
+ }
91
+ /** A record nothing has filled. */
92
+ export declare const EMPTY_BUG_RECORD: BugRecord;
93
+ /** How a field's value is written in a body; `unwritten` for one the body never holds. */
94
+ export type BugFieldShape = 'fenced' | 'plain' | 'unwritten';
95
+ /** One field: its key, the heading of its section, and how its value is written. */
96
+ export interface BugFieldSpec {
97
+ readonly key: keyof BugRecord;
98
+ readonly heading: string;
99
+ readonly shape: BugFieldShape;
100
+ }
101
+ /** Every field, in the order a body writes them; see the module note. */
102
+ export declare const BUG_FIELDS: readonly BugFieldSpec[];
103
+ /** What a record is checked against: the project's template, caps, names and codes. */
104
+ export interface BugRules {
105
+ /** The template the title is rendered with. */
106
+ readonly template: string;
107
+ /** The most characters a summary holds. */
108
+ readonly summaryMax: number;
109
+ /** The places a bug may name, without `unknown`, which is always one. */
110
+ readonly environments: readonly string[];
111
+ /** The module names accepted; empty for any name of the shape. */
112
+ readonly modules: readonly string[];
113
+ /** The actions accepted; empty for any of the shape. */
114
+ readonly actions: readonly string[];
115
+ /** The cause codes a bug may carry. */
116
+ readonly codes: readonly ErrorCodeEntry[];
117
+ }
118
+ /** True when `body` holds a section of the record. */
119
+ export declare function hasBugSections(body: string): boolean;
120
+ /**
121
+ * The record `body` holds: each field from the first section under its
122
+ * heading. The text ahead of the first heading is the description when
123
+ * no `What` section holds one, so a paragraph written above the sections
124
+ * is never dropped. See the module note.
125
+ */
126
+ export declare function parseBugRecord(body: string): BugRecord;
127
+ /**
128
+ * What `body` holds that {@link parseBugRecord} does not read, as
129
+ * written and in order; `''` for nothing. That is the text ahead of the
130
+ * first heading when a `What` section took its place as the description,
131
+ * every section whose heading names no field, and a section under a
132
+ * field's heading used a second time.
133
+ */
134
+ export declare function otherSections(body: string): string;
135
+ /** The body a record is filed with; `''` for a record holding nothing. See the module note. */
136
+ export declare function renderBugBody(record: BugRecord): string;
137
+ /** The title a record is filed under, rendered through the project's template. */
138
+ export declare function bugTitle(record: BugRecord, rules: Pick<BugRules, 'template'>): string;
139
+ /**
140
+ * Every problem of `record` under `rules`, in the order of
141
+ * {@link BUG_FIELDS}, or none. The last, that the title does not read
142
+ * back, is weighed only once the fields the title prints raised nothing.
143
+ * See the module note.
144
+ */
145
+ export declare function bugProblems(record: BugRecord, rules: BugRules): readonly string[];
@@ -0,0 +1,83 @@
1
+ /**
2
+ * The title template (#951): one string that renders an issue's title
3
+ * from its fields and reads a title back into them.
4
+ *
5
+ * ## The syntax
6
+ *
7
+ * - `${name}` prints a variable, one of {@link TITLE_VARIABLES}.
8
+ * - `?( … )` is an optional group. It prints only when every variable
9
+ * DIRECTLY inside it is printable ({@link isPrintable}): a group
10
+ * nested in it decides for itself. A separator goes inside its group,
11
+ * so a missing value takes its separator with it.
12
+ * - Anything else is text. A `)` outside every group is text too.
13
+ *
14
+ * `null`, `undefined`, a blank string, the word `unknown` and anything
15
+ * that is no string are not printable. The issue's id is no variable: a
16
+ * tracker assigns it after the title is written, and a listing prints it
17
+ * as a column of its own.
18
+ *
19
+ * ## Reading back
20
+ *
21
+ * {@link parseTitle} turns the same template into a pattern: text is
22
+ * matched as written, a group is optional, and each variable is a named
23
+ * capture. `module` and `action` are read with the shape their values
24
+ * are held to ({@link MODULE_SHAPE}, {@link ACTION_SHAPE}), and the last
25
+ * variable reads the rest, so a `: ` inside the summary never splits it.
26
+ *
27
+ * One limit stays. Under the default template a summary shaped
28
+ * `<word>: …`, filed with no module, reads back with that word as its
29
+ * module. {@link titleRoundTrips} reports it, and the record check
30
+ * (`./record.ts`) refuses such a bug, naming the title.
31
+ *
32
+ * {@link templateProblem} is what a config reader calls: it refuses a
33
+ * template that cannot be parsed, one whose summary is not the last
34
+ * variable outside every group, and one whose own titles do not read
35
+ * back, tried over every way of leaving its other variables out.
36
+ */
37
+ /** Every variable a template may name. */
38
+ export declare const TITLE_VARIABLES: readonly ["type", "project", "projectType", "module", "action", "summary"];
39
+ /** One variable's name. */
40
+ export type TitleVariable = (typeof TITLE_VARIABLES)[number];
41
+ /** The values a title is rendered from, and the ones read back from it. */
42
+ export type TitleValues = {
43
+ readonly [K in TitleVariable]?: string | null;
44
+ };
45
+ /** One part of a parsed template. */
46
+ export type TitleNode = {
47
+ readonly kind: 'text';
48
+ readonly text: string;
49
+ } | {
50
+ readonly kind: 'variable';
51
+ readonly name: TitleVariable;
52
+ } | {
53
+ readonly kind: 'group';
54
+ readonly nodes: readonly TitleNode[];
55
+ };
56
+ /** The word a filer writes for a field it cannot tell. Never printed in a title. */
57
+ export declare const UNKNOWN_VALUE = "unknown";
58
+ /** The template a bug's title is rendered with when the config names none. */
59
+ export declare const DEFAULT_BUG_TITLE = "?(${module}?( - ${action}): )${summary}";
60
+ /** What a module name looks like, as a pattern source with no anchors. */
61
+ export declare const MODULE_SHAPE = "[a-z0-9][a-z0-9._-]*";
62
+ /** What an action looks like: a module's shape, spaces allowed. */
63
+ export declare const ACTION_SHAPE = "[a-z0-9][a-z0-9._ -]*";
64
+ /** A template that cannot be parsed; its message says why. */
65
+ export declare class TitleTemplateError extends Error {
66
+ constructor(message: string);
67
+ }
68
+ /** True for a value a title prints: a string that is not blank and not `unknown`. */
69
+ export declare function isPrintable(value: unknown): value is string;
70
+ /** A template's nodes. Throws a {@link TitleTemplateError} for one that cannot be read. */
71
+ export declare function parseTitleTemplate(template: string): readonly TitleNode[];
72
+ /** The title `template` renders from `values`. Throws for a template that cannot be read. */
73
+ export declare function renderTitle(template: string, values: TitleValues): string;
74
+ /**
75
+ * The values `title` holds under `template`, or null when it does not
76
+ * fit. Throws for a template that cannot be read, or that names a
77
+ * variable twice. See the module note.
78
+ */
79
+ export declare function parseTitle(template: string, title: string): TitleValues | null;
80
+ /** True when the title rendered from `values` reads back as the values it printed. */
81
+ export declare function titleRoundTrips(template: string, values: TitleValues): boolean;
82
+ /** Why `template` cannot be used, or null when it can. See the module note. */
83
+ export declare function templateProblem(template: string): string | null;
@@ -96,9 +96,23 @@ file's wrapped lines before searching.
96
96
 
97
97
  ## Boundaries
98
98
 
99
- - A sentence your own change falsified is yours to repair in the same
100
- commit. A stale sentence your change did not touch is reported, not
101
- repaired.
99
+ - A doc line your own change falsified is repaired in the same commit.
100
+ Any other stale doc line you find goes into the report's `stale_docs`
101
+ field, with `where` and `what`, and never into `out_of_scope_bugs`.
102
+ - The doc task has two outputs beyond its own repairs. A row it could not
103
+ settle goes into its own `stale_docs` field. A row it finds to be about
104
+ code, not prose, goes into `out_of_scope_bugs`, which takes the kind the
105
+ rule below gives it.
106
+ - **Kind of each out-of-scope entry.** Every entry of `out_of_scope_bugs`
107
+ carries a `kind`: `bug`, `own-fallout`, `own-gap`, `convention`, `docs`
108
+ or `machine`. `bug` is for code that does the wrong thing and that this
109
+ plan did not cause. What an earlier task of this plan broke or left
110
+ stale is `own-fallout`; what this plan built and left unfinished is
111
+ `own-gap`. A file too long or a name off the pattern is `convention`,
112
+ and this machine's fault is `machine`. A stale doc line goes into
113
+ `stale_docs`; `docs` is the fallback for one written in the wrong field.
114
+ The loop checks every `own-` claim, so a guess between `bug` and
115
+ `own-fallout` is written as `bug`.
102
116
  - Never commit, never push, never open a pull request, never merge. The
103
117
  loop owns all four, and `src/PROMPT.md` states what it does once this
104
118
  session exits cleanly. Leave your work in the tree in a state the
@@ -21,8 +21,10 @@ with no `packages/` directory and no workspace boundaries to navigate.
21
21
  Where a reading could be a false negative, pair it with a control that
22
22
  proves the check could have failed.
23
23
  - **Same-commit doc law.** A change that falsifies a sentence in a tracked
24
- document fixes that sentence in the same commit. An invariant's register
25
- row moves with the artifact that enforces it.
24
+ document fixes that sentence in the same commit. Any other stale doc line
25
+ you find goes into the report's `stale_docs` field, with `where` and
26
+ `what`, and never into `out_of_scope_bugs`. An invariant's register row
27
+ moves with the artifact that enforces it.
26
28
  - **Style is enforced by ESLint and is not obvious.** Single quotes with no
27
29
  `avoidEscape`, three-line ternaries, `import type` first in its own
28
30
  block, parent and sibling as separate import groups. Write it, run
@@ -31,6 +33,16 @@ with no `packages/` directory and no workspace boundaries to navigate.
31
33
  past the width cap.
32
34
  - **Never widen scope.** The task is the deliverable. A real problem found
33
35
  outside it is reported, not fixed.
36
+ - **Kind of each out-of-scope entry.** Every entry of `out_of_scope_bugs`
37
+ carries a `kind`: `bug`, `own-fallout`, `own-gap`, `convention`, `docs`
38
+ or `machine`. `bug` is for code that does the wrong thing and that this
39
+ plan did not cause. What an earlier task of this plan broke or left
40
+ stale is `own-fallout`; what this plan built and left unfinished is
41
+ `own-gap`. A file too long or a name off the pattern is `convention`,
42
+ and this machine's fault is `machine`. A stale doc line goes into
43
+ `stale_docs`; `docs` is the fallback for one written in the wrong field.
44
+ The loop checks every `own-` claim, so a guess between `bug` and
45
+ `own-fallout` is written as `bug`.
34
46
 
35
47
  ## Verification
36
48
 
@@ -28,7 +28,7 @@ of course, and never a reason to chase one issue down a rabbit hole.
28
28
  | Check | Line | What is wrong |
29
29
  |---|---|---|
30
30
  | Effort | `rafa effort dashboard` | cost per task drifting up against the baseline, not explained by the item's size |
31
- | Bugs | `rafa issue list --type=bug --limit=200` | the open count rising, or bugs filed during this loop that repeat an open one |
31
+ | Bugs | the `Bugs:` and `Filed since` lines of the item's closing output | the open count rising, or a bug filed during this loop that repeats an open one |
32
32
  | Delivery | `rafa loop status`, `rafa pr list` | the run is done with no pull request, or its pull request did not merge |
33
33
  | Conflicts | `rafa pr show <pr>` | the pull request conflicts with the integration branch |
34
34
  | CI | `rafa ci status --branch=stretch/<n>` | the run failed (use `gh run view <id> --log-failed` to see why), or is still running |
@@ -37,6 +37,12 @@ A CI failure already red in the local runs is inherited and noted in the pit-sto
37
37
  A new failure is filed as one bug after a search for an existing one. A run still in progress
38
38
  is read at the next pit stop.
39
39
 
40
+ The bugs come from the closing output of `rafa stretch item`: `Bugs: <n> open.`,
41
+ then `Filed since <time>: <n>.` with one indented line per bug filed after the
42
+ last item, open or closed since, as `#<n> <title>: <first line>`. `none` is a
43
+ reading, not a failure. A line that says `not read` names its reason; read the
44
+ bugs with `rafa issue list --type=bug --limit=200` when a reading is not read.
45
+
40
46
  A conflict goes to the resolve plans first:
41
47
 
42
48
  ```bash
@@ -58,8 +64,9 @@ only after reading the run's last `rafa·` lines.
58
64
  happens twice, when the hook rule fires, or when the fix would touch
59
65
  anything outside the integration branch.
60
66
 
61
- Anything else you find is filed, not fixed: one issue, after a search for
62
- an existing one, and the stretch goes on.
67
+ A stale doc line you find is added to the release's stale-docs issue as one
68
+ line, and no issue is filed for it. Every other finding is filed, not fixed:
69
+ one issue, after a search for an existing one, and the stretch goes on.
63
70
 
64
71
  ## The entry
65
72
 
@@ -27,11 +27,16 @@ person's approval.
27
27
  ## Read the board
28
28
 
29
29
  ```bash
30
+ rafa bug recheck --all
30
31
  rafa roadmap --full
31
32
  rafa issue list --type=bug --limit=200
32
33
  rafa effort report --trend
33
34
  ```
34
35
 
36
+ `rafa bug recheck --all` reruns each open bug's test and prints one
37
+ verdict per bug. A `gone` bug is closed by the sweep as fixed; a `flaky`
38
+ one is grouped as a bug of its own, never read as fixed.
39
+
35
40
  Read the roadmap's "now" epics first: their members are where the
36
41
  project already said the work is.
37
42
 
@@ -257,6 +257,18 @@ out_of_scope_bugs:
257
257
  - what: "bun:sqlite connection pooling"
258
258
  artifact: "SQLITE_MISUSE"
259
259
  security: false
260
+ kind: bug
261
+ module: "store"
262
+ action: "appending to an open store"
263
+ reproduce: "run the store tests against a shared connection"
264
+ cause: "the handle is shared across calls"
265
+ changes:
266
+ - level: minor
267
+ area: "store"
268
+ summary: "the store reads and writes through one interface"
269
+ stale_docs:
270
+ - where: "context/effort-store.md:41"
271
+ what: "says the store has one backend"
260
272
  ```
261
273
  ````
262
274
 
@@ -269,8 +281,9 @@ Report fields:
269
281
  | `findings` | list of objects | Findings discovered during the task (see below) |
270
282
  | `skills_used` | list of strings | Names of skills referenced or applied |
271
283
  | `blockers` | list of objects | What blocked the task. Any entry marks the task `[BLOCKED]` whatever `status` says, so write `[]` when nothing did |
272
- | `out_of_scope_bugs` | list of objects | Bugs found that are outside this task's scope |
284
+ | `out_of_scope_bugs` | list of objects | Bugs and other leftovers found outside this task's scope, each with a `kind` (see below) |
273
285
  | `changes` | list of objects | Release notes for this task's own diff (contributing to the release fragment), one entry per user-visible change (see below). An absent list is empty with no issue; a task whose diff a user would notice nothing of writes one entry at level `none`. The wrap-up collects these from all tasks and writes them to the fragment that `rafa release settle` processes after the branch merges. |
286
+ | `stale_docs` | list of objects | Documentation lines the task saw that no longer match the code and that its own change did not falsify (see below). An absent list is empty with no issue |
274
287
 
275
288
  Finding entry fields:
276
289
 
@@ -293,13 +306,43 @@ Change note entry fields:
293
306
  | `area` | string | no | The changelog section the line groups under (e.g., `cli`, `store`) |
294
307
  | `summary` | string | yes | One line a user of the project would understand, quoted |
295
308
 
296
- Blocker/bug entry fields:
309
+ Stale doc entry fields:
297
310
 
298
311
  | Field | Type | Required | Description |
299
312
  | --- | --- | --- | --- |
300
- | `what` | string | yes | Description of the blocker or bug |
313
+ | `where` | string | no | The file, with the line when known, as one string (e.g., `context/triage.md:12`). An entry without one is kept |
314
+ | `what` | string | yes | What no longer matches. An entry without one is reported as an issue and dropped |
315
+
316
+ Blocker entry fields:
317
+
318
+ | Field | Type | Required | Description |
319
+ | --- | --- | --- | --- |
320
+ | `what` | string | yes | Description of the blocker |
301
321
  | `artifact` | string | no | Error message or diagnostic output |
302
- | `security` | boolean | yes (bugs only) | Whether this is a security issue; never defaulted when missing |
322
+
323
+ Out-of-scope bug entry fields:
324
+
325
+ | Field | Type | Required | Default | Description |
326
+ | --- | --- | --- | --- | --- |
327
+ | `what` | string | yes | none | Description of the bug |
328
+ | `artifact` | string | no | none | Error message or diagnostic output |
329
+ | `security` | boolean | yes | none | Whether this is a security issue; never defaulted when missing |
330
+ | `kind` | string | no | `bug` | What sort of leftover the entry is, one of the six below. An absent key reads as `bug` with no issue; a value outside the list is reported as an issue and read as `bug`. A different field from a finding's `kind`, with its own list |
331
+ | `module` | string | no | `unknown` | The module the bug is in. Checked against the project's `issues.vocabulary.modules` when that is set, and read as any name of the shape when it is empty. A name outside the set is filed as `unknown`, with the word kept in the bug's record as `Reported module`; triage never refuses a bug over it |
332
+ | `action` | string | no | `unknown` | What was running: a command, a step, a test. Checked against `issues.vocabulary.actions` the same way, the word kept as `Reported action` |
333
+ | `reproduce` | string | no | "seen while running task <task line> of plan <stub>", or "seen while running `<command>`" for a dispatch with no plan stub | The steps, or the condition that revealed it. Double-quote it. A blank value or `unknown` takes the default: the bug record never holds `unknown` here |
334
+ | `cause` | string | no | `unknown:new-context` | A cause code from `rafa bug codes`, or the cause in words. Double-quote it. A code the list lacks is filed as `<family>:new-context`, with the code kept as proposed, or as `unknown:new-context` when its family is unlisted; words that are no code are filed as `unknown:new-context`, with the words kept as the suspected cause |
335
+
336
+ Out-of-scope entry kinds:
337
+
338
+ | Kind | When it applies |
339
+ | --- | --- |
340
+ | `bug` | The code does the wrong thing, and this plan did not cause it |
341
+ | `own-fallout` | Something an earlier task of this plan broke or left stale |
342
+ | `own-gap` | Something this plan built and left unfinished |
343
+ | `convention` | A file too long, a name off the pattern |
344
+ | `docs` | A stale doc line |
345
+ | `machine` | This machine's fault |
303
346
 
304
347
  ---
305
348
 
@@ -311,7 +354,7 @@ The block strip rule means:
311
354
  - A block in a stage description does not appear in the operator log line
312
355
  - A block anywhere in the plan does not appear in a commit subject or commit body
313
356
 
314
- The strip happens where the loop reads the next task, `findNextTask` in `src/utils/tracker.ts`, and it follows fences the way a renderer shows them (`src/plan/blocks.ts`):
357
+ The strip happens where the loop reads the next task, `findNextTask` in `src/utils/tracker.ts`, and it follows fences the way a renderer shows them (`packages/rafa/src/core/plan/blocks.ts`):
315
358
 
316
359
  - Only a closed, top-level `rafa:*` block hides its lines. Every other fence is transparent, so a `- [ ] ` line at column 0 inside a `markdown` or `text` illustration, or inside a `rafa:` fence nested in one, is dispatched as a task. A plan that illustrates the format indents its example lines.
317
360
  - A `rafa:` fence that is never closed hides nothing, because taking the rest of the document as its body would end the plan with its tasks unrun. `parsePlan` reports it as `unclosed-block`, and each open task line after it as `task-in-block`.
@@ -335,11 +378,12 @@ The strip happens where the loop reads the next task, `findNextTask` in `src/uti
335
378
  holding no nested braces and at least one recognised key, and it is
336
379
  never the whole task text. Two spaces separate it from the text.
337
380
  Anything failing one of those rules stays task text — a task ending on
338
- a code span carrying `{ "a": 1 }` is not a declaration. The one thing
339
- that may follow the block is the loop's own: on a blocked task's
340
- tracker line it writes `<!-- blocked: <text> -->` after the block, and
341
- takes that comment off before the block is read. The plan itself never
342
- holds one.
381
+ a code span carrying `{ "a": 1 }` is not a declaration. What may
382
+ follow the block is the loop's own: on a blocked task's tracker line
383
+ it writes `<!-- blocked: <text> -->` after the block, and on a repair
384
+ task's line `<!-- repairs: <text> -->` before that, naming the plan
385
+ task repaired. It takes both comments off before the block is read.
386
+ The plan itself never holds either.
343
387
  * Its tokens are space-separated `key=value` pairs, of the recognised keys
344
388
  in the table below; an unrecognised key is kept for telemetry and maps
345
389
  to no flag.
@@ -353,6 +397,7 @@ The strip happens where the loop reads the next task, `findNextTask` in `src/uti
353
397
  | `tools` | tool names, comma-separated with no spaces | `--tools` | never passed: the definition names its tool set |
354
398
  | `skills` | skill names, comma-separated with no spaces | nothing: no flag carries a skill | kept on the record beside the agent |
355
399
  | `tests` | `affected`, `module` or `full`; `affected` when absent | nothing: the loop's runner reads it | kept on the record beside the agent |
400
+ | `docs` | `repair`, its one value; any other is recorded as an issue and read as absent | nothing: the loop reads it | kept on the record beside the agent |
356
401
 
357
402
  * `agent=<name>` outranks `model` and `tools`, and `effort` only when its
358
403
  definition declares one, as the last column says. The outranked keys
@@ -377,11 +422,11 @@ The strip happens where the loop reads the next task, `findNextTask` in `src/uti
377
422
 
378
423
  There is no default agent. A task with no declaration passes no routing flag and runs at the loop's defaults, as does one whose every value failed to parse.
379
424
 
380
- The recognised keys are the `DECLARATION_KEYS` of `src/utils/declaration.ts`, whose `MODEL_ALIASES`, `EFFORT_LEVELS` and `TEST_SCOPES` hold the aliases, levels and test scopes in the table, whose `parseBudgetUsd` reads a budget, whose `parseSkillList` reads a skill list and whose `readTestScope` reads a test scope; that module is the authority for this section, so change the two together.
425
+ The recognised keys are the `DECLARATION_KEYS` of `packages/rafa/src/core/plan/declaration.ts`, whose `MODEL_ALIASES`, `EFFORT_LEVELS` and `TEST_SCOPES` hold the aliases, levels and test scopes in the table, whose `parseBudgetUsd` reads a budget, whose `parseSkillList` reads a skill list, whose `readTestScope` reads a test scope and whose `DOCS_ROLES` and `readDocsRole` hold and read the one `docs` value; that module is the authority for this section, so change the two together.
381
426
 
382
427
  ### `skills=` declaration
383
428
 
384
- When a task needs help from a skill, name those skills with `skills=`. Skill names must come from the skill index provided in this prompt; naming a skill no tier holds is recorded as an issue. Names are comma-separated with no spaces.
429
+ When a task needs help from a skill, name those skills with `skills=`. Skill names must come from the skill index provided in this prompt. Naming a skill no tier holds is refused, not recorded: `rafa plan validate` exits 1 on the line that names it, and `rafa loop start`'s preflight refuses to start the plan, so nothing is dispatched. Names are comma-separated with no spaces.
385
430
 
386
431
  `skills` is a recognised key that maps to no flag: there is no CLI flag for a skill, so the names are parsed, kept on the dispatch record and stripped from the task text with the rest of the block. It stands on its own — `{skills=bun-testing}` is a declaration with no other key beside it — and a value that is not a comma-separated list of skill names is recorded as an issue rather than passed on.
387
432
 
@@ -411,6 +456,8 @@ The second example above has no `skills=` and is still a valid task declaration.
411
456
  - [ ] Move the test preload into `bunfig.toml` {tests=full}
412
457
  ```
413
458
 
459
+ A task's text never asks its session for a whole-suite run, or for any command that can outlast one Bash call, since the Bash tool stops a command at 10 minutes. The runner runs the suite through `tests=full` on the task. A task that needs a long run's output reads a file that a `[start]` prerequisite or the runner wrote, such as the `.output.txt` beside a suite run's JUnit file.
460
+
414
461
  ---
415
462
 
416
463
  ## Task sizing (session economics)
@@ -428,6 +475,10 @@ The second example above has no `skills=` and is still a valid task declaration.
428
475
  `src/start.ts`" task grows it enough for its own diff to flag, and phase
429
476
  0's six took `src/start.ts` from 798 lines to 960 with no task owning the
430
477
  split; only a whole-change-set review caught it.
478
+ * When the project's entry test lists command modules, a task that adds
479
+ a command module or an import to one updates that list in the same
480
+ task and names the file in its Description: in rafa, `COMMAND_MODULES`
481
+ in `src/index.test.ts`.
431
482
  * Keep as SEPARATE tasks: cross-cutting verification (fan-out gates,
432
483
  invariant sweeps), live-seam runs, migrations, and close-out — these
433
484
  preserve resumability where a halt is most likely.
@@ -444,6 +495,46 @@ The second example above has no `skills=` and is still a valid task declaration.
444
495
  --write-tree origin/<base> HEAD`) and assemble the body material — the gate
445
496
  captures, the test plan, the recorded debt — into the plan's close-out
446
497
  notes for that wrap-up session to use.
498
+ * A task's text never asks its session for the whole suite, or for any
499
+ command that can outlast one Bash call. Declare `tests=full` on the task
500
+ and the runner runs the suite after the commit; a task that needs a long
501
+ run's output reads it from the file a `[start]` prerequisite or the
502
+ runner wrote.
503
+
504
+ ### The closing doc task
505
+
506
+ * A plan with one task not declared `agent=doc-updater` ends on one task
507
+ declared `agent=doc-updater docs=repair`. That task is the plan's last
508
+ task line, and it repairs the docs of what the plan changed: the loop
509
+ hands it the `stale_docs` rows the plan's tasks reported and the files
510
+ its commits touched.
511
+ * A plan whose every task is declared `agent=doc-updater` gets no closing
512
+ doc task: it is prose only, and every task in it is documentation.
513
+ * `rafa plan validate` reports a plan with a code task and no `docs=repair`
514
+ task on its last line as the warning `missing-doc-task`. The warning never
515
+ refuses a plan, so a plan written before this rule still runs.
516
+
517
+ A plan of code tasks ends on the closing task:
518
+
519
+ ````markdown
520
+ # Stage: Store
521
+
522
+ - [ ] Add the `stale_docs` table migration with its unit tests {agent=loop-implementer effort=high}
523
+ - [ ] Add the store writer for stale-doc rows with its unit tests {agent=loop-implementer effort=medium}
524
+
525
+ # Stage: Close-out
526
+
527
+ - [ ] Repair the docs of what this plan changed {agent=doc-updater docs=repair effort=medium}
528
+ ````
529
+
530
+ A prose-only plan gets none:
531
+
532
+ ````markdown
533
+ # Stage: Pages
534
+
535
+ - [ ] Rewrite the triage page for four channels {agent=doc-updater effort=medium}
536
+ - [ ] Add the doc task to the workflow page {agent=doc-updater effort=medium}
537
+ ````
447
538
 
448
539
  ---
449
540
 
@@ -472,6 +563,8 @@ The wrap-up session always receives `full` regardless of the configured mode.
472
563
  - [ ] {Tool} installed: `{tool} --version`
473
564
  - [ ] {Service name} answering on port {n}: `curl -sf http://localhost:{n}/health`
474
565
  - [ ] {VAR_NAME} set, obtained from {where}: `test -n "${VAR_NAME}"`
566
+ - [ ] [tasks] {Something only the tasks need}: `{command to verify}`
567
+ - [ ] [wrap-up] {Something only the wrap-up needs}: `{command to verify}`
475
568
 
476
569
  ## Credentials [human]
477
570
  - [ ] {Credential description}
@@ -488,6 +581,8 @@ How the file is read:
488
581
  - An item's tag is the `[auto]`, `[human]`, or `[start]` written right after its box. Without one it takes its section's tag: a heading carrying `[auto]` tags its section `auto`, one carrying `[human]` or naming `manual`, `human`, `sign-off` or `team` tags it `human`, and one carrying `[start]` tags it `start`. A heading's tag reaches the deeper headings under it and ends at the next heading of its own level or shallower. An item under no tagged heading is `human`.
489
582
  - An `auto` item's probe is the backticked span that ends it, after its final `: `. The item merges as a required prerequisite, the tier whose failure halts a run.
490
583
  - A `start` item's probe is read the same way. The item is probed on first dispatch only (skipped on resume), and failure halts a run on first dispatch.
584
+ - An item's scope is the `[tasks]` or `[wrap-up]` marker written at its opening, after its box and after its tag when it has one (`- [ ] [auto] [tasks] ...`). Without one it takes the marker of the nearest heading above it that carries one, which reaches the deeper headings under it and ends at the next heading of its own level or shallower, as a tag does; an item's own marker outranks its heading's. With no marker anywhere the scope is `both`, and the two markers written together read as `both` too. The marker is dropped from the item's text and is never read as its probe.
585
+ - The scope says which dispatches need an `auto` item: `tasks` the task sessions, `wrap-up` the wrap-up session, `both` every one. A marker on a `start` or `human` item is read and changes nothing: the `start` item is still probed on first dispatch only, and the `human` item is still a reminder.
491
586
  - A `human` item is a reminder: named to the operator, never probed, and never halting a run.
492
587
  - An `auto` or `start` item that does not end with `: ` and its command — the command first, text after it, or no span at all — is malformed: `rafa loop start` and `rafa doctor` refuse the plan, naming its line, and run nothing.
493
588
 
@@ -496,6 +591,7 @@ Rules:
496
591
  - An `[auto]` item holds exactly one backticked span, and that span is its command. The preflight runs it as written, so put no package name, path or other command in backticks anywhere in the item.
497
592
  - Tag an item `auto` only when a shell command proves it, and end the item with `: ` and that command. The command asks for no input and changes nothing.
498
593
  - Tag an item `start` only when a shell command proves it and it should only be checked on the first dispatch of a plan (not on resume). End it with `: ` and the command, one span, as for `auto`.
594
+ - Mark an `auto` item `[tasks]` when only the plan's tasks need it and `[wrap-up]` when only the wrap-up does (pushing, opening the pull request, releasing); leave it unmarked when both do or when unsure, since an unmarked item is always probed. Write the marker bare, at the item's opening or on its heading, never in backticks and never after the command: text after the span makes the item malformed.
499
595
  - Make the command complete: it exits 0 when the prerequisite holds. To prove a tool is installed, probe `<tool> --version`, `<tool> --help` or `which <tool>` — never a bare subcommand such as `uvx check-jsonschema`, which exits non-zero for want of arguments.
500
596
  - Tag every step for after the plan merges `human`, as the heading above does, so no run ever executes one as a probe.
501
597
  - Do not duplicate steps already documented in the repo's contributor docs (README, CONTRIBUTING, and the like).
@@ -506,18 +602,18 @@ Rules:
506
602
 
507
603
  ## Format validation
508
604
 
509
- The loop parses plan files through `src/plan/parse.ts`:
605
+ The loop parses plan files through `packages/rafa/src/core/plan/parse.ts`:
510
606
 
511
- - **Block parsing** (`src/plan/blocks.ts`): Reads fenced `rafa:*` blocks. Tolerates documents with no blocks. Retains unknown kinds.
512
- - **Plan parsing** (`src/plan/parse.ts`): Builds the plan model over blocks and the checklist grammar. Each stage captures the tasks under it and the first `rafa:stage-context` block between its heading and the next `# Stage:` heading.
513
- - **Declaration parsing** (`src/utils/declaration.ts`): Takes a trailing `{...}` block off a task line and reads its `key=value` entries. The block counts only when one of its keys is a recognized key (see Task declarations).
514
- - **Report parsing** (`src/report/parse.ts`): Reads the last `rafa:report` block from agent output and parses its YAML body. Answers an explicit absence record if no block is present.
607
+ - **Block parsing** (`packages/rafa/src/core/plan/blocks.ts`): Reads fenced `rafa:*` blocks. Tolerates documents with no blocks. Retains unknown kinds.
608
+ - **Plan parsing** (`packages/rafa/src/core/plan/parse.ts`): Builds the plan model over blocks and the checklist grammar. Each stage captures the tasks under it and the first `rafa:stage-context` block between its heading and the next `# Stage:` heading.
609
+ - **Declaration parsing** (`packages/rafa/src/core/plan/declaration.ts`): Takes a trailing `{...}` block off a task line and reads its `key=value` entries. The block counts only when one of its keys is a recognized key (see Task declarations).
610
+ - **Report parsing** (`packages/rafa/src/report/parse.ts`): Reads the last `rafa:report` block from agent output and parses its YAML body. Answers an explicit absence record if no block is present.
515
611
 
516
612
  The parser is liberal with unknown input: unknown block kinds are kept, unknown declaration keys are kept, unknown YAML keys are kept. A report yields no report only when its last `rafa:report` block is missing, never closed, not valid YAML, or not a mapping. A field that is missing, or holds a value it cannot take (a `findings` that is not a list, a `signal` other than `loud` or `silent`), is reported as an issue and the rest of the report is still read. Quote every string value in a report: an unquoted value that opens with a backtick, `@`, `%` or `[` makes the whole block unreadable, and a `#` after a space starts a comment that silently cuts the value short.
517
613
 
518
614
  Line numbers count two ways. A block's `span` (`readRafaBlocks`) and a `PlanIssue.line` count from one; `TaskInfo.lineNum` and the stage and task `lineNum` of the plan model count from zero, so compare `lineNum + 1` against either.
519
615
 
520
- The report rules in this skill restate `src/report/parse.ts`, which is the authority: change the two together.
616
+ The report rules in this skill restate `packages/rafa/src/report/parse.ts`, which is the authority: change the two together.
521
617
 
522
618
  ---
523
619
 
@@ -534,11 +630,11 @@ When the spec adds or changes anything in `.rafa/effort/`:
534
630
 
535
631
  ## Command-development rule: Claude session declaration
536
632
 
537
- When planning work on rafa commands: every command that can start a Claude
538
- Code session must declare its `spends` field on its `RafaCommand` definition.
539
- The field tells the help system, `describe` output, and the spawn guard in
540
- `src/utils/claude.ts` what Claude usage the command declares. It is optional,
541
- and takes one of four shapes:
633
+ When planning work on rafa commands: every command that can start a Claude Code
634
+ session must declare its `spends` field on its `RafaCommand` definition. The
635
+ field tells the help system, `describe` output, and the spawn guard in
636
+ `packages/rafa/src/core/loop/claude.ts` what Claude usage the command declares.
637
+ It is optional, and takes one of four shapes:
542
638
 
543
639
  - `{ when: 'always'; what: string }` — the command always starts a session
544
640
  - `{ when: 'with'; flag: string; what: string }` — starts a session only when
@@ -626,4 +722,4 @@ Both follow the same structured format. The difference is:
626
722
  - **Hand-written plans** (by a planner agent): Prose in the description, stage contexts, and task granularity reflect careful thought about the work.
627
723
  - **Generated plans** (by `rafa plan`): Produced from a spec document; structure is the same.
628
724
 
629
- A hand-written plan read by `src/plan/parse.ts` produces the same data model as a generated one. This is the property the structured format enforces.
725
+ A hand-written plan read by `packages/rafa/src/core/plan/parse.ts` produces the same data model as a generated one. This is the property the structured format enforces.
@@ -30,7 +30,7 @@ Two kinds of documentation are maintained:
30
30
  | **API (Swagger)** | `@asteasolutions/zod-to-openapi` + `swagger-ui-express` | `openapi.json` + served behind `ctx.requireAuth` at `GET /docs/` | `bun run docs:openapi` |
31
31
 
32
32
  > Both rows are INSTALLED in `@ar/service` — the OpenAPI half is no longer a
33
- > convention to adopt on some later day, and [`rules/openapi.md`](rules/openapi.md)
33
+ > convention to adopt on some later day, and this skill
34
34
  > records what is there rather than a setup to perform. The two scripts are
35
35
  > SIBLINGS sharing no output tree, which is worth stating because the pair of
36
36
  > names suggests they do: `docs:openapi` writes the gitignored `.docs/swagger/`,
@@ -46,16 +46,6 @@ Auto-generated outputs go in `.docs/` (dotfolder) and are always gitignored.
46
46
 
47
47
  ---
48
48
 
49
- ## Rules index
50
-
51
- | Rule file | When to use |
52
- | --- | --- |
53
- | [`rules/tsdoc.md`](rules/tsdoc.md) | Writing TSDoc comments on any TypeScript symbol |
54
- | [`rules/openapi.md`](rules/openapi.md) | Documenting Express routes with OpenAPI/Swagger |
55
- | [`rules/typedoc-setup.md`](rules/typedoc-setup.md) | Adding TypeDoc infra to the repo (or a project derived from it) |
56
-
57
- ---
58
-
59
49
  ## Workflow
60
50
 
61
51
  1. **Determine kind before touching**: identify whether documentation is manual or auto-generated before editing. Manual docs live in `docs/`; auto-generated outputs live in `.docs/`.
@@ -72,7 +62,7 @@ Before marking a documentation task done:
72
62
  - [ ] Every exported function, class, and interface has a TSDoc block with `@param` and `@returns`.
73
63
  - [ ] Every file has a `@packageDocumentation` comment (or is covered by a module-level JSDoc).
74
64
  - [ ] Every Express router factory is documented with `@remarks` listing its HTTP endpoints.
75
- - [ ] `typedoc.json`, `tsconfig.docs.json`, and a `docs:generate` script exist (see [`rules/typedoc-setup.md`](rules/typedoc-setup.md)).
65
+ - [ ] `typedoc.json`, `tsconfig.docs.json`, and a `docs:generate` script exist.
76
66
  - [ ] `openapi.ts` exists and every route is registered in it — `openapi-coverage.test.ts` is the gate that says so, and a route added without a binding-table entry reddens it.
77
67
  - [ ] `.docs/` is already gitignored twice over and needs no new entry: once at the repo root (`.gitignore`) and again at the package (`packages/service/.gitignore`), both files tracked. Running `git check-ignore -v` on the generated `openapi.json` names the PACKAGE rule, the nearer file winning — take the source off that output rather than predicting it.
78
68
  - [ ] `docs/` (manual ADRs) is **not** gitignored.