@adhd/backlog 0.1.8 → 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.
Files changed (61) hide show
  1. package/CHANGELOG.md +93 -44
  2. package/README.md +332 -81
  3. package/api.d.ts +146 -0
  4. package/cli.d.ts +45 -18
  5. package/env.d.ts +23 -3
  6. package/envelope.d.ts +163 -0
  7. package/index.d.ts +11 -10
  8. package/index.js +531 -173
  9. package/index.mjs +29814 -15647
  10. package/install-skill.d.ts +23 -0
  11. package/package.json +50 -15
  12. package/query/card.d.ts +31 -0
  13. package/query/get.d.ts +11 -0
  14. package/query/index.d.ts +67 -0
  15. package/query/markdown.d.ts +11 -0
  16. package/query/query.d.ts +131 -0
  17. package/query/resolve.d.ts +123 -0
  18. package/query/types.d.ts +450 -0
  19. package/query/views/registry.d.ts +43 -0
  20. package/query/views/semantic.d.ts +101 -0
  21. package/query/views/stats.d.ts +109 -0
  22. package/search-shortcut.d.ts +79 -0
  23. package/serve.d.ts +18 -0
  24. package/server.d.ts +139 -4
  25. package/skill/SKILL.md +619 -138
  26. package/store/graph-backlog-store.d.ts +80 -17
  27. package/store/immediate-retry.d.ts +24 -13
  28. package/store/type-policy.d.ts +4 -0
  29. package/store/vocabulary-guard.d.ts +52 -0
  30. package/version-info.d.ts +15 -0
  31. package/write/audit.d.ts +36 -0
  32. package/write/bootstrap.d.ts +123 -0
  33. package/write/catalog.d.ts +351 -0
  34. package/write/claim-lease.d.ts +21 -0
  35. package/write/claim.d.ts +80 -0
  36. package/write/create-issue.d.ts +250 -0
  37. package/write/delete.d.ts +39 -0
  38. package/write/embed-drain.d.ts +68 -0
  39. package/write/embedding-observer.d.ts +80 -0
  40. package/write/errors.d.ts +303 -0
  41. package/write/issue-status.d.ts +10 -0
  42. package/write/move.d.ts +70 -0
  43. package/write/relate.d.ts +52 -0
  44. package/write/transition.d.ts +60 -0
  45. package/write/tx.d.ts +344 -0
  46. package/write/update.d.ts +81 -0
  47. package/client.d.ts +0 -169
  48. package/markdown.d.ts +0 -75
  49. package/migration-admin.d.ts +0 -26
  50. package/model.d.ts +0 -437
  51. package/store/audit-log.d.ts +0 -16
  52. package/store/claim.d.ts +0 -24
  53. package/store/crud.d.ts +0 -62
  54. package/store/ids.d.ts +0 -24
  55. package/store/lifecycle.d.ts +0 -36
  56. package/store/mapping.d.ts +0 -101
  57. package/store/mutate-metadata.d.ts +0 -8
  58. package/store/query.d.ts +0 -68
  59. package/store/repo-migration.d.ts +0 -51
  60. package/store/serve-lock.d.ts +0 -42
  61. package/store/structure.d.ts +0 -66
package/markdown.d.ts DELETED
@@ -1,75 +0,0 @@
1
- import { BacklogFilter, BacklogItem, BacklogStatus, MalformedHeaderInfo, Priority } from './model.js';
2
-
3
- declare const LEGACY_TERMINAL_DONE: string[];
4
- declare const LEGACY_TERMINAL_WORKAROUND: string[];
5
- declare const LEGACY_TERMINAL_DISMISSED: string[];
6
- declare const LEGACY_TERMINAL: Set<string>;
7
- export declare function normalizeLegacyStatus(rawLabel: string): BacklogStatus;
8
- /**
9
- * Classify a free-form status string into a {label, open} pair — ported
10
- * verbatim from tools/util/backlog.mjs:56-82 (`classifyStatus`). Backlog
11
- * Status lines are prose, so an open signal must win over a closed word when
12
- * both are present.
13
- */
14
- export declare function classifyStatus(raw: string | undefined): {
15
- label: string;
16
- open: boolean;
17
- } | null;
18
- /** Ported verbatim from tools/util/backlog.mjs:84-96 (`detectStatus`). */
19
- export declare function detectStatus(headerLine: string, body: string): {
20
- label: string;
21
- open: boolean;
22
- };
23
- /** Ported verbatim from tools/util/backlog.mjs:98-104 (`detectPriority`). */
24
- export declare function detectPriority(headerLine: string, body: string): string;
25
- export interface ParsedMarkdownItem {
26
- id: string;
27
- kind: string;
28
- family: string;
29
- title: string;
30
- level: number;
31
- line: number;
32
- headerLine: string;
33
- status: string;
34
- open: boolean;
35
- terminal: boolean;
36
- priority: string;
37
- body: string;
38
- }
39
- export interface ParseWithDiagnosticsResult {
40
- items: ParsedMarkdownItem[];
41
- malformedHeaders: MalformedHeaderInfo[];
42
- }
43
- /** Ported (structure preserved) from tools/util/backlog.mjs:106-155 (`parse`). */
44
- export declare function parseBacklogMarkdown(text: string): ParsedMarkdownItem[];
45
- /**
46
- * Same parse as {@link parseBacklogMarkdown}, plus `malformedHeaders` — every
47
- * `##`/`###` line that looks like a corrupted/typo'd id header and was
48
- * dropped instead of parsed into an item (DEBT-BACKLOG-IMPORT-SILENT-DROP-001).
49
- * `importFromMarkdown` (client.ts) uses this to populate `ImportResult.malformedHeaders`.
50
- */
51
- export declare function parseBacklogMarkdownWithDiagnostics(text: string): ParseWithDiagnosticsResult;
52
- /**
53
- * SPEC.md §5.6 `renderToMarkdown` — one `###` block per item. Archived-item
54
- * exclusion (SPEC.md §5.4 `archiveResolved`'s "renderToMarkdown's default
55
- * view excludes them") happens one layer up, in `client.ts`'s
56
- * `renderToMarkdown`, which has access to the raw node `metadata.archivedAt`
57
- * flag — `BacklogItem` (SPEC.md §4.1) deliberately carries no `archivedAt`
58
- * field of its own, so this function (pure, no store access) cannot filter
59
- * on it and takes an already-filtered `items` array.
60
- */
61
- export declare function renderItemsToMarkdown(items: BacklogItem[]): string;
62
- /** Ported from tools/util/backlog.mjs:351-361 (`buildChangelogSection`). */
63
- export declare function buildChangelogSection(items: BacklogItem[], date: string): string;
64
- /** Applies the SAME filters `applyFilters`/`BacklogFilter` describes, used only for markdown-side symmetry checks in tests. */
65
- export declare function matchesFilter(item: ParsedMarkdownItem, filter: BacklogFilter): boolean;
66
- export interface ParsedImportItem {
67
- humanId: string;
68
- title: string;
69
- body: string;
70
- status: BacklogStatus;
71
- priority?: Priority;
72
- }
73
- /** Bridges the legacy parser's raw shape into the canonical vocabulary (SPEC.md §5.6 `importFromMarkdown`). */
74
- export declare function toImportItems(parsed: ParsedMarkdownItem[]): ParsedImportItem[];
75
- export { LEGACY_TERMINAL, LEGACY_TERMINAL_DONE, LEGACY_TERMINAL_DISMISSED, LEGACY_TERMINAL_WORKAROUND };
@@ -1,26 +0,0 @@
1
- import { MigrationPhase } from './model.js';
2
- import { BacklogConfig } from './env.js';
3
- import { Environment } from '@adhd/environment';
4
-
5
- /**
6
- * Mirrors `@adhd/environment-builder`'s own internal `roots.ts` global-root
7
- * formula (`~/.<orgNamespace>/<project>/<namespace>/config.yaml`) using ONLY
8
- * the public fields the `@adhd/environment` `Environment` instance exposes
9
- * (`orgNamespace`/`project`/`namespace`) — `@adhd/backlog` does not depend on
10
- * the internal `environment-builder` package directly, so this is a
11
- * deliberate, narrow re-derivation, not an import of a private module.
12
- * `adhdRootOverride` mirrors `EnvironmentOptions.adhdRoot`'s own test-isolation
13
- * escape hatch (see `BuildBacklogEnvOptions`) for tests that must never touch
14
- * the real machine-global `~/.adhd`.
15
- */
16
- export declare function globalConfigPath(env: Environment<BacklogConfig>, adhdRootOverride?: string): string;
17
- /**
18
- * Reads the existing global `config.yaml` (if any), deep-merges in
19
- * `migration.phase`, and writes it back — preserving every OTHER key already
20
- * in the file (e.g. a previously-set `db.busyTimeoutMs` override) rather than
21
- * clobbering the whole file. A missing or malformed existing file is treated
22
- * as empty (never fatal for a write), mirroring
23
- * `@adhd/environment-builder`'s own `readLayerFile` tolerance for a corrupt
24
- * layer. Returns the absolute path written, for caller confirmation.
25
- */
26
- export declare function writeMigrationPhase(env: Environment<BacklogConfig>, phase: MigrationPhase, adhdRootOverride?: string): string;
package/model.d.ts DELETED
@@ -1,437 +0,0 @@
1
- /**
2
- * model.ts — the `BacklogItem` domain shape and every operation-surface input
3
- * / output type. Ported verbatim from `SPEC.md` §4/§5. Pure types + a handful
4
- * of tiny, dependency-free classification helpers — no store/env imports.
5
- */
6
- export type BacklogStatus = 'OPEN' | 'IN_PROGRESS' | 'PARTIAL' | 'OUTSTANDING' | 'DEFERRED' | 'BLOCKED' | 'MIXED' | 'UNKNOWN' | 'FIXED' | 'RESOLVED' | 'DONE' | 'SHIPPED' | 'VERIFIED' | 'REMOVED' | 'MITIGATED' | 'SUPERSEDED' | 'INVALID' | 'DUPLICATE' | 'WONTFIX';
7
- /** §4.2 rule 3 — terminal-done + terminal-workaround: require ≥1 citation. */
8
- export declare const TERMINAL_DONE_STATUSES: ReadonlySet<BacklogStatus>;
9
- export declare const TERMINAL_WORKAROUND_STATUSES: ReadonlySet<BacklogStatus>;
10
- /** §4.2 rule 3 — terminal-dismissed: require a reason (citation optional). */
11
- export declare const TERMINAL_DISMISSED_STATUSES: ReadonlySet<BacklogStatus>;
12
- export declare const TERMINAL_STATUSES: ReadonlySet<BacklogStatus>;
13
- export declare function isTerminalStatus(status: BacklogStatus): boolean;
14
- /** §4.2 rule 3 — "a transition INTO any terminal status requires evidence." */
15
- export declare function requiresCitation(status: BacklogStatus): boolean;
16
- export declare function requiresReason(status: BacklogStatus): boolean;
17
- export type Priority = 'CRITICAL' | 'HIGH' | 'MEDIUM' | 'LOW';
18
- export interface Citation {
19
- /** Repo-relative path, matching the global CLAUDE.md citation format. */
20
- file: string;
21
- /** e.g. "42-58"; omit for a whole-file citation. */
22
- lines?: string;
23
- /** Free text — active git context / agent name / model, per the citation format. */
24
- context?: string;
25
- }
26
- export interface Note {
27
- by: string;
28
- at: string;
29
- text: string;
30
- }
31
- export interface BacklogItem {
32
- /** The graph node id (see DESIGN.md §2). Never exposed to markdown; internal only. */
33
- nodeId: number;
34
- /** Human-facing id, e.g. "BUG-APIGEN-014". Unique within (repo, family). */
35
- humanId: string;
36
- /** First hyphen segment of humanId, e.g. "BUG". Open vocabulary — not an enum. */
37
- kind: string;
38
- /** humanId with the trailing "-NNN" stripped, e.g. "BUG-APIGEN". */
39
- family: string;
40
- title: string;
41
- /** Markdown body — the full entry text minus the header line. */
42
- body: string;
43
- status: BacklogStatus;
44
- priority?: Priority;
45
- /** Stable repo slug — see SPEC.md §3 "Repo identity". */
46
- repo: string;
47
- /** Package-relative path within the repo, e.g. "packages/apigen/apigen-core-client". Optional — repo-level items omit it. */
48
- projectPath?: string;
49
- /** Plan slug this item is attached to, if any — e.g. "agent-registry-schema". */
50
- plan?: string;
51
- /** Source markdown path this item was imported from, if any (DEBT-BACKLOG-IMPORT-PLAN-PROVENANCE-001). */
52
- importedFrom?: string;
53
- /** Durable ownership — who this item is assigned to (may differ from the active claimant). */
54
- assignee?: string;
55
- /** Ephemeral claim lease — see SPEC.md §5. */
56
- claimedBy?: string;
57
- claimedAt?: string;
58
- citations: Citation[];
59
- notes: Note[];
60
- tags: string[];
61
- createdAt: string;
62
- updatedAt: string;
63
- }
64
- /**
65
- * BUG-BACKLOG-REPO-LOOKUP-UX-001: a `(repo, humanId)` miss is frequently NOT
66
- * "this item doesn't exist" but "this item exists under a DIFFERENT `repo`
67
- * string" (e.g. `"adhd"` vs `"PseudoSky/adhd"` both live in the same store
68
- * for what is logically one project). `foundInRepos` — populated by
69
- * `store/query.ts`'s `buildNotFoundError` helper, which every throw site now
70
- * calls instead of constructing this directly — carries the OTHER repo
71
- * value(s) the humanId actually lives under, so the thrown message names the
72
- * fix instead of leaving the caller to guess.
73
- */
74
- export declare class BacklogItemNotFoundError extends Error {
75
- readonly foundInRepos: string[];
76
- constructor(repo: string, humanId: string, foundInRepos?: string[]);
77
- }
78
- export declare class CitationRequiredError extends Error {
79
- constructor(status: BacklogStatus);
80
- }
81
- export declare class ReasonRequiredError extends Error {
82
- constructor(status: BacklogStatus);
83
- }
84
- export declare class ClaimHeldError extends Error {
85
- readonly heldBy: string;
86
- readonly heldSince: string;
87
- constructor(heldBy: string, heldSince: string);
88
- }
89
- export declare class DependencyCycleError extends Error {
90
- readonly cycle: string[];
91
- constructor(cycle: string[]);
92
- }
93
- /**
94
- * BUG-BACKLOG-HUMANID-COLLISION-001 (fix #1 — write-time guard):
95
- * `createItemNode` rejects a `family` that is missing/empty/whitespace-only
96
- * UNLESS `idOverride` is also given (SPEC.md §5.1's `CreateItemInput.family`
97
- * contract: "required unless idOverride given"). Thrown BEFORE
98
- * `allocateHumanIdAndInsert`/`computeNextHumanId` ever run, so a caller that
99
- * omits `family` (previously silently coerced to the literal string
100
- * `"undefined"` by `computeNextHumanId`'s template literal, producing
101
- * `humanId: "undefined-001"` and colliding with every other item that hit
102
- * the same bug) now fails loudly instead of minting a collision. This is
103
- * defense in depth: it must hold regardless of whether an upstream caller's
104
- * own input-schema validation (e.g. apigen-core-client's extracted
105
- * `CreateItemInput` schema, BUG-APIGEN-CORE-CLIENT-001) enforces `family` as
106
- * required — the store's own write path must never trust the caller alone.
107
- */
108
- export declare class InvalidArgumentError extends Error {
109
- readonly argument: string;
110
- constructor(argument: string, message: string);
111
- }
112
- /**
113
- * BUG-BACKLOG-HUMANID-COLLISION-001 (fix #2 — read-time guard): every
114
- * `(repo, humanId)`-keyed lookup used to silently resolve to "whichever
115
- * live node is found first" when more than one live node shared the same
116
- * key (the exact shape of the pre-existing `"undefined-001"` collisions,
117
- * and the root cause of a real mis-transition this session — see the
118
- * backlog item's body). Any lookup that finds >1 live match now throws this
119
- * instead of guessing, listing every colliding `nodeId` so a caller can
120
- * disambiguate (there is no tool-level nodeId-addressed path yet — the
121
- * caller must go through the store's own repair primitives, e.g.
122
- * `renameHumanId`, to resolve the collision).
123
- */
124
- export declare class AmbiguousHumanIdError extends Error {
125
- readonly nodeIds: number[];
126
- constructor(repo: string, humanId: string, nodeIds: number[]);
127
- }
128
- export interface DedupeScanInput {
129
- symbol?: string;
130
- path?: string;
131
- errorText?: string;
132
- }
133
- export interface CreateItemInput {
134
- family: string;
135
- idOverride?: string;
136
- title: string;
137
- body: string;
138
- repo: string;
139
- projectPath?: string;
140
- priority?: Priority;
141
- tags?: string[];
142
- plan?: string;
143
- /** Source markdown path this item is being imported from, if any (DEBT-BACKLOG-IMPORT-PLAN-PROVENANCE-001). */
144
- importedFrom?: string;
145
- dedupeScan?: DedupeScanInput;
146
- /** Skip the dedupe gate and file anyway (planner override after reviewing candidates). */
147
- force?: boolean;
148
- /**
149
- * Citations to attach at creation time (BUG-BACKLOG-CREATE-ITEM-DROPS-CITATIONS-001).
150
- * Previously absent from this interface entirely — a caller passing
151
- * `citations` on create got a success response with the item created and
152
- * the citations silently discarded (no such field existed to carry them
153
- * through). Validated the same way as every other citation write path
154
- * (`Citation.file` non-empty — see `lifecycle.ts`'s `assertValidCitation`)
155
- * and rejected as a whole (no partial write) before allocation runs.
156
- */
157
- citations?: Citation[];
158
- }
159
- export interface CreateItemResult {
160
- item: BacklogItem;
161
- created: boolean;
162
- duplicateCandidates: BacklogItem[];
163
- /**
164
- * BUG-BACKLOG-REPO-LOOKUP-UX-001: set (soft warning, never blocks the
165
- * write) when `input.repo` doesn't match any repo value already known to
166
- * this store — a likely typo/inconsistent-repo-string drift (e.g. filing
167
- * under `"adhd"` when every existing item uses `"PseudoSky/adhd"`) rather
168
- * than a genuine first-time-use of a new repo, which is always allowed.
169
- */
170
- repoWarning?: string;
171
- }
172
- export interface UpdateItemInput {
173
- title?: string;
174
- body?: string;
175
- tags?: string[];
176
- projectPath?: string;
177
- /**
178
- * Provenance owner of this item (the source-file path that authored it).
179
- * Only ever set to BACKFILL a legacy row whose `importedFrom` was never
180
- * stamped (created before the provenance field existed) — see
181
- * `importFromMarkdown`'s owning-import branch. An already-stamped owner is
182
- * immutable and must never be reassigned via this patch.
183
- */
184
- importedFrom?: string;
185
- }
186
- export interface BacklogFilter {
187
- repo?: string;
188
- projectPath?: string;
189
- status?: BacklogStatus | 'open' | 'closed';
190
- kind?: string;
191
- family?: string;
192
- priority?: Priority;
193
- plan?: string;
194
- assignee?: string;
195
- claimedBy?: string;
196
- tags?: string[];
197
- grep?: string;
198
- /**
199
- * Exact-match on `BacklogItem.importedFrom` — the sourcePath that OWNS an
200
- * item's canonical content (DEBT-BACKLOG-IMPORT-SCOPE-CROSSFILE-001).
201
- * Needed for a root-level `BACKLOG.md` projection: filtering by bare
202
- * `{repo}` alone would also surface every item cross-referenced FROM root
203
- * by a plan/package file (which correctly carries a `plan`/`projectPath`
204
- * of its own once ownership-gating lands) — `importedFrom` is the only
205
- * field that reliably answers "does THIS file own this item's content",
206
- * independent of which OTHER files also cite the same id.
207
- */
208
- importedFrom?: string;
209
- /**
210
- * Repo-level projection selector (MIGRATION.md §2.2 "root BACKLOG.md =
211
- * repo-only, no projectPath/plan"). When true, returns only items that carry
212
- * NEITHER a `projectPath` NOR a `plan` — i.e. items owned by the repo root
213
- * rather than a package or plan projection. Unlike the `importedFrom`
214
- * workaround it does not depend on provenance, so a freshly tool-created
215
- * repo-level item (which has no `importedFrom`) still appears in the root
216
- * projection — the Phase-3 DoD ("a fresh create-item appears in the
217
- * regenerated BACKLOG.md") requires this. Cross-referenced items that carry a
218
- * `plan`/`projectPath` render in that plan/package projection instead, never
219
- * duplicated into root.
220
- */
221
- rootLevel?: boolean;
222
- /**
223
- * Drops items with `metadata.archivedAt` set (BACKLOG-adoption's
224
- * `archiveResolved` — SPEC.md §5.4). `renderToMarkdown` always applies
225
- * this internally (a markdown projection never shows archived rows), but
226
- * `listItems`/`queryItemNodes` do NOT default to it — auditing/reporting
227
- * consumers legitimately need to see archived items too. A caller that
228
- * needs to reproduce `renderToMarkdown`'s exact item set through
229
- * `listItems` (e.g. `render-projections.mjs`/`parity-check.mjs` verifying
230
- * a rendered projection against the graph's own view of the same filter —
231
- * BUG-BACKLOG-RENDER-VERIFY-ARCHIVED-MISMATCH-001) must set this
232
- * explicitly; otherwise the two queries diverge on every archived row.
233
- */
234
- excludeArchived?: boolean;
235
- limit?: number;
236
- offset?: number;
237
- }
238
- export interface StatsScope {
239
- repo?: string;
240
- projectPath?: string;
241
- }
242
- export interface BacklogStats {
243
- total: number;
244
- open: number;
245
- closed: number;
246
- byStatus: Record<string, number>;
247
- byKind: Record<string, number>;
248
- byFamily: Record<string, number>;
249
- byPriority: Record<string, number>;
250
- byRepo: Record<string, number>;
251
- }
252
- export interface DependencyGraph {
253
- nodes: Array<{
254
- humanId: string;
255
- title: string;
256
- status: BacklogStatus;
257
- }>;
258
- edges: Array<{
259
- from: string;
260
- to: string;
261
- rel: 'DEPENDS_ON' | 'RELATES_TO' | 'PART_OF';
262
- }>;
263
- }
264
- export type TopoOrderResult = {
265
- ok: true;
266
- order: string[];
267
- } | {
268
- ok: false;
269
- cycle: string[];
270
- };
271
- export interface ClaimOpts {
272
- /** Minutes after which an unrenewed claim is considered abandoned. Default: 30 (DESIGN.md §4.2). */
273
- staleAfterMin?: number;
274
- /** Explicitly override a claim that is NOT stale (human-confirmed abandonment). */
275
- force?: boolean;
276
- }
277
- export type ClaimStatus = 'claimed' | 'renewed' | 'reclaimed-stale' | 'held';
278
- export interface ClaimResult {
279
- status: ClaimStatus;
280
- claimedBy: string;
281
- claimedAt: string;
282
- /** Only present when status === 'held'. */
283
- heldBy?: string;
284
- heldSince?: string;
285
- /** Only present when status === 'reclaimed-stale' — the abandoned claimant, for audit. */
286
- previousClaimant?: string;
287
- }
288
- export interface ReleaseResult {
289
- status: 'released' | 'release-noop';
290
- wasClaimedBy?: string;
291
- }
292
- export interface TransitionOpts {
293
- by: string;
294
- note?: string;
295
- citations?: Citation[];
296
- reason?: string;
297
- }
298
- export interface ArchiveOpts {
299
- /** Exclude specific humanIds from the sweep even though they're terminal (mirrors tools/util/backlog.mjs's --exclude). */
300
- exclude?: string[];
301
- }
302
- export interface ArchiveResult {
303
- archivedCount: number;
304
- changelogMarkdown: string;
305
- }
306
- export interface ImportMarkdownInput {
307
- path: string;
308
- repo: string;
309
- projectPath?: string;
310
- /** Plan slug to attach every imported item to (DEBT-BACKLOG-IMPORT-PLAN-PROVENANCE-001) — replaces the post-import attachToPlan-per-id workaround. */
311
- plan?: string;
312
- /**
313
- * Provenance path recorded on each imported node's `importedFrom` field
314
- * (DEBT-BACKLOG-IMPORT-PLAN-PROVENANCE-001). Defaults to `path` when
315
- * omitted — the file actually read IS the source, so a caller only needs
316
- * to set this explicitly when it differs (e.g. importing from a scratch
317
- * copy but wanting the ORIGINAL path recorded).
318
- */
319
- sourcePath?: string;
320
- dryRun?: boolean;
321
- }
322
- /** A `##`/`###` header line that failed the strict `HEADER_RE` id pattern but looks like an attempted id (DEBT-BACKLOG-IMPORT-SILENT-DROP-001). */
323
- export interface MalformedHeaderInfo {
324
- /** 1-based line number in the source file. */
325
- line: number;
326
- headerLine: string;
327
- }
328
- export interface ImportResult {
329
- parsed: number;
330
- created: number;
331
- skippedDuplicates: number;
332
- /**
333
- * Of `skippedDuplicates` (an already-existing humanId), how many had a
334
- * title/body/priority/status that DIFFERED from the graph's current copy
335
- * and were refreshed to match the re-imported source
336
- * (BUG-BACKLOG-IMPORT-INSERT-ONLY-NO-UPDATE-001 — re-importing used to be
337
- * pure insert-only: a status/content change made directly in a
338
- * `BACKLOG.md` file after the first import was silently never reflected
339
- * in the graph on a later re-import). An unchanged existing item is a
340
- * true no-op — never counted here.
341
- */
342
- updated: number;
343
- errors: Array<{
344
- humanId: string;
345
- message: string;
346
- }>;
347
- /** Headers that look like a corrupted/typo'd id and were dropped instead of parsed — never silent (DEBT-BACKLOG-IMPORT-SILENT-DROP-001). */
348
- malformedHeaders: MalformedHeaderInfo[];
349
- /** See `CreateItemResult.repoWarning` (BUG-BACKLOG-REPO-LOOKUP-UX-001) — computed once for `input.repo`, not per item. */
350
- repoWarning?: string;
351
- }
352
- export interface AuditTrailEntry {
353
- at: string;
354
- kind: 'created' | 'transition' | 'claim' | 'note' | 'citation' | 'supersession';
355
- detail: Record<string, unknown>;
356
- }
357
- export interface AuditTrailResult {
358
- humanId: string;
359
- history: AuditTrailEntry[];
360
- supersessionChain?: {
361
- supersedes?: string;
362
- supersededBy?: string;
363
- };
364
- }
365
- export type MigrationPhase = 'not-started' | 'phase-1' | 'phase-2' | 'phase-3' | 'phase-4' | 'phase-5' | 'complete';
366
- export interface MigrationStatusResult {
367
- phase: MigrationPhase;
368
- /** One-line human-readable meaning of `phase`, e.g. "phase-2: BACKLOG.md is still authoritative; the tool is shadow-running in parity-check mode." */
369
- description: string;
370
- /** True once the graph (not hand-edited markdown) is authoritative — phase-3 and later. */
371
- toolIsAuthoritative: boolean;
372
- }
373
- /** `setMigrationPhase`'s result — `MigrationStatusResult` plus the absolute
374
- * path of the GLOBAL `config.yaml` the new phase was persisted to (so a
375
- * caller can confirm this was a durable, cross-process write, not merely an
376
- * in-memory value). */
377
- export interface SetMigrationPhaseResult extends MigrationStatusResult {
378
- configPath: string;
379
- }
380
- /** One item's move within a `RepoMigrationPlan` — always dry-runnable, never mutates on its own. */
381
- export interface RepoMigrationPlanItem {
382
- nodeId: number;
383
- /** The humanId this item currently carries in `fromRepo`. */
384
- humanId: string;
385
- /**
386
- * The humanId this item will carry in `toRepo` — identical to `humanId`
387
- * unless `renamed` is true. Deterministic: preserves the item's `family`
388
- * prefix and picks the next free number in that family within `toRepo`
389
- * (mirrors `computeNextHumanId`'s own `max + 1` allocation rule), scanning
390
- * BOTH `toRepo`'s pre-existing items AND every earlier item in this same
391
- * plan already assigned a number in that family — so two colliding items
392
- * sharing a family (e.g. two different `BUG-001`s) never collide with each
393
- * other's rename target either.
394
- */
395
- targetHumanId: string;
396
- /** True iff `humanId` already exists as a LIVE item in `toRepo` and had to be renamed to avoid an id collision. */
397
- renamed: boolean;
398
- title: string;
399
- status: BacklogStatus;
400
- }
401
- /**
402
- * The full, deterministic plan for moving every live item out of `fromRepo`
403
- * into `toRepo` — computed by a pure read-only scan (`planRepoMigration`),
404
- * safe to call repeatedly and to inspect before ever mutating anything.
405
- */
406
- export interface RepoMigrationPlan {
407
- fromRepo: string;
408
- toRepo: string;
409
- items: RepoMigrationPlanItem[];
410
- /** Count of `items` where `renamed === true` — the collision count. */
411
- collisionCount: number;
412
- }
413
- /** Per-item outcome of actually executing a `RepoMigrationPlan`. Every planned item gets exactly one of these — nothing is ever silently dropped. */
414
- export interface RepoMigrationItemResult {
415
- nodeId: number;
416
- fromHumanId: string;
417
- toHumanId: string;
418
- renamed: boolean;
419
- ok: boolean;
420
- /** Present iff `ok === false` — the item was left untouched in `fromRepo`, never partially moved. */
421
- error?: string;
422
- }
423
- /**
424
- * `migrateRepo`'s result. When `dryRun` is true (the default — a caller must
425
- * pass `dryRun:false` explicitly to mutate anything), `results` is absent and
426
- * NOTHING was written; `plan` alone previews exactly what would happen.
427
- */
428
- export interface RepoMigrationResult {
429
- fromRepo: string;
430
- toRepo: string;
431
- dryRun: boolean;
432
- plan: RepoMigrationPlan;
433
- /** Present only when `dryRun === false`. One entry per `plan.items` entry, same order. */
434
- results?: RepoMigrationItemResult[];
435
- succeeded?: number;
436
- failed?: number;
437
- }
@@ -1,16 +0,0 @@
1
- import { GraphBacklogStore } from './graph-backlog-store.js';
2
- import { AuditTrailEntry } from '../model.js';
3
-
4
- export declare const BACKLOG_AUDIT_EVENT_TAG = "backlog-audit-event";
5
- /**
6
- * Records one `transition`/`claim` event for the item at `itemNodeId`.
7
- * `content` is a uniqueness-marker string (mirrors `buildNodeContent()`'s
8
- * own reasoning, `mapping.ts`) — `@adhd/sox-graph-store`'s global
9
- * content-hash dedup would otherwise be free to collapse two
10
- * byte-identical events (e.g. two items independently transitioning
11
- * `OPEN`→`IN_PROGRESS` with no `by`/`reason` at all) into ONE node.
12
- */
13
- export declare function writeAuditEvent(store: GraphBacklogStore, itemNodeId: number, repo: string, humanId: string, kind: AuditTrailEntry['kind'], detail: Record<string, unknown>): Promise<void>;
14
- /** Every persisted event for `itemNodeId`, oldest first — ready to merge
15
- * straight into `auditTrail()`'s `history` array. */
16
- export declare function queryAuditEvents(store: GraphBacklogStore, itemNodeId: number): Promise<AuditTrailEntry[]>;
package/store/claim.d.ts DELETED
@@ -1,24 +0,0 @@
1
- import { GraphBacklogStore } from './graph-backlog-store.js';
2
- import { ClaimOpts, ClaimResult, ReleaseResult } from '../model.js';
3
-
4
- /** DESIGN.md §4.2 — matches STALE_CLAIM_S = 30*60 at state-transition.js:601. */
5
- export declare const DEFAULT_STALE_AFTER_MIN = 30;
6
- export declare class ClaimContentionError extends Error {
7
- readonly heldBy: string;
8
- constructor(heldBy: string, by: string);
9
- }
10
- /**
11
- * DESIGN.md §4.2 — the exact branch table:
12
- * unclaimed -> claimed
13
- * by === claimedBy -> renewed (no contention check, ever)
14
- * by !== claimedBy, age <= staleAfterMin -> held (refuse, no write)
15
- * by !== claimedBy, age > staleAfterMin -> reclaimed-stale
16
- * by !== claimedBy, opts.force -> proceeds anyway (reclaimed-stale-shaped)
17
- */
18
- export declare function claimItemNode(store: GraphBacklogStore, nodeId: number, by: string, opts?: ClaimOpts): Promise<ClaimResult>;
19
- /** SPEC.md §5.3 — "always succeeds (bumps claimedAt), no contention check, ever." */
20
- export declare function renewClaimNode(store: GraphBacklogStore, nodeId: number, by: string): Promise<ClaimResult>;
21
- /** DESIGN.md §4.2 — releasing an already-unclaimed item is a no-op, never an error. */
22
- export declare function releaseClaimNode(store: GraphBacklogStore, nodeId: number, by: string, opts?: {
23
- force?: boolean;
24
- }): Promise<ReleaseResult>;
package/store/crud.d.ts DELETED
@@ -1,62 +0,0 @@
1
- import { GraphBacklogStore } from './graph-backlog-store.js';
2
- import { BacklogItem, CreateItemInput, CreateItemResult, UpdateItemInput } from '../model.js';
3
-
4
- /**
5
- * Minimum fraction of the NEW item's meaningful title tokens that must also
6
- * appear in a CANDIDATE's title for the candidate to count as a duplicate
7
- * (BUG-BACKLOG-DEDUPE-FTS-WEAK-MATCH-001). Exported so callers/tests can
8
- * tune it without touching this file's internals.
9
- *
10
- * Why title-to-title overlap instead of the FTS hit's bm25 `score`:
11
- * `store.graph.searchNodes()` (`@adhd/sox-graph-store`) DOES return a
12
- * per-hit `score` (`-fts_node.rank`, i.e. a positive, higher-is-better bm25
13
- * score) — but bm25 is corpus- and document-length-relative, not an absolute
14
- * similarity measure, and empirically it does NOT discriminate this bug's
15
- * failure mode: a live probe reproducing the exact reported case (a short
16
- * generic new title vs. a long, verbose, unrelated document that happens to
17
- * repeat a couple of the new title's common words many times) scored
18
- * `~0.0000109`, while a genuine short-title-vs-short-title near-duplicate
19
- * scored `~0.0000113` — the SAME order of magnitude, with no clean
20
- * separating threshold between them. A long document's sheer token count
21
- * inflates its bm25 term-frequency component enough to rival a real
22
- * duplicate's score. Title-to-title token overlap has no such document-
23
- * length confound: a new item's title can only ever match against a
24
- * candidate's (typically similarly short) title, so incidental repetition
25
- * buried in a long candidate BODY can no longer count toward "looks like a
26
- * duplicate" at all.
27
- *
28
- * 0.5 (at least half the new title's meaningful tokens must recur in the
29
- * candidate's title) was chosen because DESIGN.md §2.4's own worked example
30
- * ("same bug, different words") is a near-total title rewrite that still
31
- * shares most of its content words ("database connection pool leaks under
32
- * load" -> "the database connection pool leaks under load" is 6/6); dropping
33
- * to a small minority match (e.g. 1-2 shared generic words out of 5) is
34
- * exactly the false-positive shape this bug reports and must NOT pass.
35
- */
36
- export declare const TITLE_OVERLAP_MIN_FRACTION = 0.5;
37
- declare function dedupeScan(store: GraphBacklogStore, repo: string, input: CreateItemInput): Promise<BacklogItem[]>;
38
- export declare function createItemNode(store: GraphBacklogStore, input: CreateItemInput): Promise<CreateItemResult>;
39
- export declare function getItemNode(store: GraphBacklogStore, repo: string, humanId: string): Promise<BacklogItem | null>;
40
- /**
41
- * DEVIATION (mitigated — DEBT-BACKLOG-CONTENT-IMMUTABLE-001): `@adhd/sox-graph-store`
42
- * exposes no PUBLIC primitive to update a node's `content` column after
43
- * creation (`touch()`'s `Partial<NodeMeta>` covers
44
- * name/summary/topic/tags/importance/confidence/tExpires/metadata — never
45
- * `content`; verified against the real source). `title` updates the `summary`
46
- * column (source of truth for the API) AND `metadata.title`; `body` updates
47
- * `metadata.body` (source of truth for the API). Below, a title/body change
48
- * ALSO re-synchronizes the FTS-indexed `content`/`content_hash` columns
49
- * directly via `adapter.executeRun` on the store-owned `adapter` handle —
50
- * the same DESIGN.md §14-sanctioned escape hatch `structure.ts`'s
51
- * `removeDependencyNode` already uses for the one other gap (`edge`
52
- * deletion) the `GraphBackend` API lacks, now routed through the store-
53
- * adapter's query surface (F-01/F-02: the raw `store.db` handle is gone).
54
- * This is safe specifically because `fts_node_au` (the real schema's `AFTER
55
- * UPDATE ON node` trigger — `~/dev/ai/sox-ecosystem/libs/data/graph/graph-store/
56
- * src/index.ts`'s `FTS_TRIGGERS`) re-indexes `fts_node` automatically on
57
- * ANY write to `node.content`/`name`/`summary`, so no separate FTS statement
58
- * is needed here.
59
- */
60
- export declare function updateItemNode(store: GraphBacklogStore, repo: string, humanId: string, patch: UpdateItemInput): Promise<BacklogItem>;
61
- export declare function softDeleteItemNode(store: GraphBacklogStore, repo: string, humanId: string, reason: string): Promise<void>;
62
- export { dedupeScan };
package/store/ids.d.ts DELETED
@@ -1,24 +0,0 @@
1
- import { GraphBacklogStore } from './graph-backlog-store.js';
2
- import { NodeRecord } from '@adhd/sox-graph-store';
3
-
4
- /**
5
- * Resolves the humanId to insert under (either `idOverride`, re-verified for
6
- * an already-live node, or the next auto-allocated `family-NNN`) and invokes
7
- * `insert(humanId, existing)` — ALL inside one retried `.immediate()`
8
- * transaction, so no other concurrent `.immediate()`-wrapped write can
9
- * interleave between "the id was resolved" and "a node claiming it landed".
10
- * `existing` is the already-live node under `idOverride` (re-checked HERE,
11
- * not just by an earlier, racy caller-side check) — `insert` is expected to
12
- * short-circuit on a non-null `existing` exactly like `createItemNode`'s
13
- * documented idempotent-reimport behavior, but now race-free.
14
- */
15
- export declare function allocateHumanIdAndInsert<T>(store: GraphBacklogStore, repo: string, family: string, idOverride: string | undefined, insert: (humanId: string, existing: NodeRecord | null) => T): Promise<T>;
16
- /**
17
- * @deprecated kept ONLY as a standalone id-generator for any caller that does
18
- * not need an atomic insert alongside it. `createItemNode`/
19
- * `supersedeItemNode` no longer use this (see `allocateHumanIdAndInsert`'s
20
- * doc comment for why splitting allocate-then-insert-later is unsafe under
21
- * concurrency). Still correct in isolation — just NOT TOCTOU-safe when the
22
- * caller's own insert happens in a separate, later transaction.
23
- */
24
- export declare function allocateHumanId(store: GraphBacklogStore, repo: string, family: string): Promise<string>;