@adhd/backlog 0.1.2 → 0.1.4
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/CHANGELOG.md +17 -0
- package/cli.d.ts +80 -2
- package/client.d.ts +17 -0
- package/index.d.ts +2 -2
- package/index.js +112 -106
- package/index.mjs +15322 -14377
- package/model.d.ts +35 -0
- package/package.json +13 -12
- package/store/crud.d.ts +33 -0
- package/store/query.d.ts +14 -0
- package/store/structure.d.ts +29 -0
package/model.d.ts
CHANGED
|
@@ -90,6 +90,41 @@ export declare class DependencyCycleError extends Error {
|
|
|
90
90
|
readonly cycle: string[];
|
|
91
91
|
constructor(cycle: string[]);
|
|
92
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
|
+
}
|
|
93
128
|
export interface DedupeScanInput {
|
|
94
129
|
symbol?: string;
|
|
95
130
|
path?: string;
|
package/package.json
CHANGED
|
@@ -1,24 +1,25 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adhd/backlog",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"bin": {
|
|
5
5
|
"backlog": "index.js"
|
|
6
6
|
},
|
|
7
7
|
"dependencies": {
|
|
8
|
+
"@adhd/apigen-core-client": "^0.3.0",
|
|
9
|
+
"@adhd/apigen-engine-naming": "^0.2.2",
|
|
10
|
+
"@adhd/apigen-plugin-api-fastify": "^0.2.3",
|
|
11
|
+
"@adhd/apigen-plugin-batch": "^0.2.2",
|
|
12
|
+
"@adhd/apigen-plugin-cli-output": "^0.2.3",
|
|
13
|
+
"@adhd/apigen-plugin-ir-cache": "^0.1.0",
|
|
14
|
+
"@adhd/apigen-plugin-mcp": "^0.2.3",
|
|
15
|
+
"@adhd/apigen-plugin-openapi": "^0.2.2",
|
|
16
|
+
"@adhd/environment": "^0.1.3",
|
|
17
|
+
"@adhd/environment-base-spec": "^0.1.0",
|
|
8
18
|
"@adhd/sox-graph-store": "^0.3.0",
|
|
9
19
|
"better-sqlite3": "^12.10.0",
|
|
10
|
-
"@adhd/environment": "^0.1.2",
|
|
11
|
-
"@adhd/environment-base-spec": "^0.1.0",
|
|
12
|
-
"@adhd/apigen-core-client": "^0.2.1",
|
|
13
|
-
"@adhd/apigen-plugin-api-fastify": "^0.2.1",
|
|
14
|
-
"@adhd/apigen-plugin-openapi": "^0.2.1",
|
|
15
|
-
"@adhd/apigen-plugin-mcp": "^0.2.1",
|
|
16
|
-
"@adhd/apigen-plugin-batch": "^0.2.0",
|
|
17
|
-
"@adhd/apigen-plugin-cli-output": "^0.2.1",
|
|
18
|
-
"@adhd/apigen-engine-naming": "^0.2.1",
|
|
19
|
-
"yaml": "1.10.3",
|
|
20
20
|
"pino": "10.3.1",
|
|
21
|
-
"pino-pretty": "13.1.3"
|
|
21
|
+
"pino-pretty": "13.1.3",
|
|
22
|
+
"yaml": "1.10.3"
|
|
22
23
|
},
|
|
23
24
|
"assets": [
|
|
24
25
|
"skill"
|
package/store/crud.d.ts
CHANGED
|
@@ -1,6 +1,39 @@
|
|
|
1
1
|
import { GraphBacklogStore } from './graph-backlog-store.js';
|
|
2
2
|
import { BacklogItem, CreateItemInput, CreateItemResult, UpdateItemInput } from '../model.js';
|
|
3
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;
|
|
4
37
|
declare function dedupeScan(store: GraphBacklogStore, repo: string, input: CreateItemInput): BacklogItem[];
|
|
5
38
|
export declare function createItemNode(store: GraphBacklogStore, input: CreateItemInput): CreateItemResult;
|
|
6
39
|
export declare function getItemNode(store: GraphBacklogStore, repo: string, humanId: string): BacklogItem | null;
|
package/store/query.d.ts
CHANGED
|
@@ -6,6 +6,20 @@ import { NodeRecord } from '@adhd/sox-graph-store';
|
|
|
6
6
|
/** Raw NodeRecord query — used internally where the full node (not just the mapped BacklogItem) is needed. */
|
|
7
7
|
export declare function queryItemNodes(store: GraphBacklogStore, filter?: BacklogFilter): NodeRecord[];
|
|
8
8
|
export declare function listItems(store: GraphBacklogStore, filter?: BacklogFilter): BacklogItem[];
|
|
9
|
+
/**
|
|
10
|
+
* BUG-BACKLOG-HUMANID-COLLISION-001 fix #2: this is THE shared `(repo,
|
|
11
|
+
* humanId) -> NodeRecord` lookup every store module funnels through
|
|
12
|
+
* (`crud.ts`/`lifecycle.ts`/`structure.ts`/`client.ts`'s `requireItem*`
|
|
13
|
+
* helpers all call this, directly or via `buildNotFoundError`'s sibling
|
|
14
|
+
* miss path). It used to silently resolve to "whichever live node happens
|
|
15
|
+
* to match `name`, else whichever is first" when more than one live node
|
|
16
|
+
* shared the same `(repo, humanId)` key — the exact shape of the
|
|
17
|
+
* pre-existing `"undefined-001"` collisions, and the root cause of a real
|
|
18
|
+
* mis-transition (see the backlog item body: a `resolveItem` call intended
|
|
19
|
+
* for one node silently landed on a different, unrelated one). Any lookup
|
|
20
|
+
* that finds >1 live match now throws `AmbiguousHumanIdError` instead of
|
|
21
|
+
* guessing.
|
|
22
|
+
*/
|
|
9
23
|
export declare function findItemNode(store: GraphBacklogStore, repo: string, humanId: string): NodeRecord | null;
|
|
10
24
|
/**
|
|
11
25
|
* Finds every LIVE node carrying this `humanId`, across ALL repos (no
|
package/store/structure.d.ts
CHANGED
|
@@ -33,3 +33,32 @@ export declare function mergeItemsNode(store: GraphBacklogStore, repo: string, k
|
|
|
33
33
|
export declare function setPriorityNode(store: GraphBacklogStore, repo: string, humanId: string, priority: Priority): BacklogItem;
|
|
34
34
|
export declare function attachToPlanNode(store: GraphBacklogStore, repo: string, humanId: string, planSlug: string): void;
|
|
35
35
|
export declare function assignItemNode(store: GraphBacklogStore, repo: string, humanId: string, to: string, by: string): BacklogItem;
|
|
36
|
+
/**
|
|
37
|
+
* BUG-BACKLOG-HUMANID-COLLISION-001 fix #3 (repair primitive): re-ids a
|
|
38
|
+
* single, `nodeId`-scoped live backlog item to a new `humanId` within the
|
|
39
|
+
* same `repo`. `nodeId`-scoped (not `(repo, oldHumanId)`-keyed) so this is
|
|
40
|
+
* unambiguous EVEN under the exact collision it exists to repair — every
|
|
41
|
+
* other `(repo, humanId)`-keyed lookup in this file would throw
|
|
42
|
+
* `AmbiguousHumanIdError` on a colliding key (fix #2, `findItemNode`), so a
|
|
43
|
+
* repair tool needs a way in that doesn't go through that same lookup.
|
|
44
|
+
*
|
|
45
|
+
* There is no tool-level rename/re-id operation exposed anywhere in this
|
|
46
|
+
* store today (the backlog item's fix direction #5 explicitly calls this
|
|
47
|
+
* gap out) — this is that primitive, added as part of this fix, kept
|
|
48
|
+
* store-internal (not wired to `client.ts`/the MCP surface) since it is a
|
|
49
|
+
* narrow one-off repair tool, not a general-purpose end-user operation.
|
|
50
|
+
*
|
|
51
|
+
* Guards:
|
|
52
|
+
* - the node at `nodeId` must be live and its CURRENT `metadata.humanId`
|
|
53
|
+
* must equal `oldHumanId` (sanity check — refuses to rename the wrong
|
|
54
|
+
* node out from under a caller who mis-copied a nodeId).
|
|
55
|
+
* - `newHumanId` must not already resolve to a DIFFERENT live node in this
|
|
56
|
+
* `repo` (refuses to rename INTO a fresh collision).
|
|
57
|
+
* - re-derives `kind`/`family` from `newHumanId`, rebuilds `tags` (swapping
|
|
58
|
+
* the old kind/family tags for the new ones, preserving every other
|
|
59
|
+
* user tag) and the node `name`/`content`/`content_hash` (which both bake
|
|
60
|
+
* in `repo::humanId` — DESIGN.md §2.2, mapping.ts's `buildNodeName`/
|
|
61
|
+
* `buildNodeContent`) so the renamed node is indistinguishable from one
|
|
62
|
+
* that was always minted under `newHumanId`.
|
|
63
|
+
*/
|
|
64
|
+
export declare function renameHumanIdNode(store: GraphBacklogStore, repo: string, nodeId: number, oldHumanId: string, newHumanId: string): BacklogItem;
|