@adhd/backlog 0.1.9 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +80 -47
- package/README.md +332 -81
- package/api.d.ts +146 -0
- package/cli.d.ts +45 -18
- package/env.d.ts +23 -3
- package/envelope.d.ts +163 -0
- package/index.d.ts +11 -10
- package/index.js +531 -173
- package/index.mjs +30039 -15879
- package/install-skill.d.ts +23 -0
- package/package.json +50 -15
- package/query/card.d.ts +31 -0
- package/query/get.d.ts +11 -0
- package/query/index.d.ts +67 -0
- package/query/markdown.d.ts +11 -0
- package/query/query.d.ts +131 -0
- package/query/resolve.d.ts +123 -0
- package/query/types.d.ts +450 -0
- package/query/views/registry.d.ts +43 -0
- package/query/views/semantic.d.ts +101 -0
- package/query/views/stats.d.ts +109 -0
- package/search-shortcut.d.ts +79 -0
- package/serve.d.ts +18 -0
- package/server.d.ts +139 -4
- package/skill/SKILL.md +619 -138
- package/store/graph-backlog-store.d.ts +80 -17
- package/store/immediate-retry.d.ts +24 -13
- package/store/type-policy.d.ts +4 -0
- package/store/vocabulary-guard.d.ts +52 -0
- package/write/audit.d.ts +36 -0
- package/write/bootstrap.d.ts +123 -0
- package/write/catalog.d.ts +351 -0
- package/write/claim-lease.d.ts +21 -0
- package/write/claim.d.ts +80 -0
- package/write/create-issue.d.ts +250 -0
- package/write/delete.d.ts +39 -0
- package/write/embed-drain.d.ts +68 -0
- package/write/embedding-observer.d.ts +80 -0
- package/write/errors.d.ts +303 -0
- package/write/issue-status.d.ts +10 -0
- package/write/move.d.ts +70 -0
- package/write/relate.d.ts +52 -0
- package/write/transition.d.ts +60 -0
- package/write/tx.d.ts +344 -0
- package/write/update.d.ts +81 -0
- package/client.d.ts +0 -174
- package/markdown.d.ts +0 -75
- package/migration-admin.d.ts +0 -26
- package/model.d.ts +0 -437
- package/store/audit-log.d.ts +0 -16
- package/store/claim.d.ts +0 -24
- package/store/crud.d.ts +0 -62
- package/store/ids.d.ts +0 -24
- package/store/lifecycle.d.ts +0 -36
- package/store/mapping.d.ts +0 -101
- package/store/mutate-metadata.d.ts +0 -8
- package/store/query.d.ts +0 -68
- package/store/repo-migration.d.ts +0 -51
- package/store/serve-lock.d.ts +0 -42
- package/store/structure.d.ts +0 -66
package/write/tx.d.ts
ADDED
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
import { BacklogWriteError } from './errors.js';
|
|
2
|
+
import { TypePolicy } from '@adhd/sox-graph-store';
|
|
3
|
+
import { AdapterTransaction, StoreAdapter } from '@adhd/sox-store-adapter';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* The on-write embedding substrate (§4b, FEAT-021) — the narrow slice of
|
|
7
|
+
* `semanticBackend`/`SemanticBackend` (`store/semantic-search.ts`,
|
|
8
|
+
* reference-only) this write layer actually needs. Deliberately NOT the
|
|
9
|
+
* spec's own `createEmbeddingObserver(semanticBackend)` shape: that observer
|
|
10
|
+
* is constructed from a `GraphWriteObserver` and registered with
|
|
11
|
+
* `createGraphBackend`'s `observers` option, so it only ever fires from
|
|
12
|
+
* INSIDE the library's own `writeNode`/`writeNodeInTx` (`GraphWriteObserver.
|
|
13
|
+
* onNodeWritten`, verified against the published `@adhd/sox-graph-store`
|
|
14
|
+
* dist) — a hook this file's entire premise is that the write layer
|
|
15
|
+
* structurally never reaches, because every write here goes through the
|
|
16
|
+
* hand-composed, tx-scoped primitives below instead of the library's own
|
|
17
|
+
* autocommitting methods (this file's own opening doc comment). So §4b's
|
|
18
|
+
* "AFTER the write layer's `immediate` transaction has committed" contract is
|
|
19
|
+
* satisfied here by explicit, write-verb-owned invocation (see
|
|
20
|
+
* `embedding-observer.ts`'s `scheduleIssueEmbedding`) rather than an
|
|
21
|
+
* observer callback — the write verb itself IS the thing that knows the
|
|
22
|
+
* subject transaction just committed, so it is the thing that calls this
|
|
23
|
+
* interface's methods, once, right after `executeWriteTransaction` resolves.
|
|
24
|
+
*
|
|
25
|
+
* `embedDocument`/`upsertVector`/`deleteVector` only — no query-side method
|
|
26
|
+
* (`knn`/`embedQuery`/`iterVectors`) belongs here: those are `query/**`'s
|
|
27
|
+
* concern (`IQueryStoreHandle.search`, `query/views/semantic.ts`), out of
|
|
28
|
+
* this slice's scope to touch.
|
|
29
|
+
*/
|
|
30
|
+
export interface IEmbeddingBackend {
|
|
31
|
+
/** The embedding model identifier stamped alongside every vector this backend writes/deletes — passed straight through to `upsertVector`/`deleteVector`'s own `modelId` so a caller wiring multiple models never mixes spaces. */
|
|
32
|
+
readonly modelId: string;
|
|
33
|
+
/** Embeds `content` (the issue's `${title}\n${body}` text — see `embedding-observer.ts`'s own doc comment on why this MUST be composed identically to `create-issue.ts`'s `scanForDuplicates`). Rejects on a provider failure — never swallowed here; the caller (`scheduleIssueEmbedding`) is what degrades a rejection to a logged `embedding_failed` audit row (§4b). */
|
|
34
|
+
embedDocument(content: string): Promise<Float32Array>;
|
|
35
|
+
/** Upserts `vector` for graph node `nodeRowid` (the SAME numeric value `writeNodeTx`/`writeAudit` already track as `.rowid` — never `uid`, per `@adhd/sox-vector-store`'s own `id`-is-rowid convention, confirmed against `query/views/semantic.spec.ts`'s `indexIssue` helper). */
|
|
36
|
+
upsertVector(nodeRowid: number, vector: Float32Array): Promise<void>;
|
|
37
|
+
/** Deletes any vector stored for `nodeRowid` under `this.modelId`. A no-op (never throws) when no vector was ever stored for that rowid — mirrors `AsyncVectorBackend.delete`'s own idempotent contract (`@adhd/sox-vector-store`). */
|
|
38
|
+
deleteVector(nodeRowid: number): Promise<void>;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* The dependencies a write verb needs to open its own `immediate` transaction
|
|
42
|
+
* and validate the edges it writes. Constructed once at store-open time (out
|
|
43
|
+
* of scope for this slice — see the store-bootstrap file that wires
|
|
44
|
+
* `createGraphBackend`'s own `typePolicy` option, DATA_MODEL.md §0 point 5)
|
|
45
|
+
* and threaded through every write verb.
|
|
46
|
+
*/
|
|
47
|
+
export interface IWriteStoreHandle {
|
|
48
|
+
/** The `StoreAdapter` the backlog store exposes — never `GraphBackend.transaction`, which cannot request `immediate` mode (§4c). */
|
|
49
|
+
readonly adapter: StoreAdapter;
|
|
50
|
+
/**
|
|
51
|
+
* The SAME injected `TypePolicy` instance the store's `GraphBackend` was
|
|
52
|
+
* constructed with (or `DEFAULT_TYPE_POLICY` — though the spec requires an
|
|
53
|
+
* open-schema policy be injected, DATA_MODEL.md §0 point 5). `writeEdgeTx`
|
|
54
|
+
* calls this directly, in-process, never through `writeEdge` (§2).
|
|
55
|
+
*/
|
|
56
|
+
readonly typePolicy: TypePolicy;
|
|
57
|
+
/**
|
|
58
|
+
* §4b's on-write embedding substrate — OPTIONAL, mirroring
|
|
59
|
+
* `IDuplicateScanHandle.search`'s own "never silently go dark, but also
|
|
60
|
+
* never hard-fail when unwired" posture (`create-issue.ts`). Absent →
|
|
61
|
+
* `scheduleIssueEmbedding` (`embedding-observer.ts`) is a true no-op: no
|
|
62
|
+
* embed attempt, no `embedding_*` audit row, nothing logged — filing/
|
|
63
|
+
* updating an issue must never depend on RAG being configured in a given
|
|
64
|
+
* environment. Present → every genuine create and every body-changing
|
|
65
|
+
* update schedules a post-commit embed/audit round-trip (see
|
|
66
|
+
* `embedding-observer.ts`'s own doc comment for the exact verb-by-verb
|
|
67
|
+
* wiring and the touch-vs-supersede scope decision).
|
|
68
|
+
*/
|
|
69
|
+
readonly embedding?: IEmbeddingBackend;
|
|
70
|
+
}
|
|
71
|
+
/** A node row as read back inside a transaction, mapped onto the fields the write layer needs. */
|
|
72
|
+
export interface ITxNodeRow {
|
|
73
|
+
rowid: number;
|
|
74
|
+
uid: string;
|
|
75
|
+
kind: string;
|
|
76
|
+
name: string | null;
|
|
77
|
+
content: string;
|
|
78
|
+
metadata: Record<string, unknown> | undefined;
|
|
79
|
+
tInvalid: string | null;
|
|
80
|
+
isSuperseded: boolean;
|
|
81
|
+
}
|
|
82
|
+
/** Current UTC timestamp in the same ISO-8601 shape `@adhd/sox-graph-store` stamps every row with. */
|
|
83
|
+
export declare function nowISO(): string;
|
|
84
|
+
/** `sha256` hex digest of arbitrary string/Buffer content — used for citation and audit content-addressing (§4a/§8.5), never for the library's own dedupe hash (that stays trim+lowercase, see {@link writeNodeTx}). */
|
|
85
|
+
export declare function sha256Hex(input: string | Buffer): string;
|
|
86
|
+
/**
|
|
87
|
+
* Deterministic JSON serialization with keys sorted at every level — the
|
|
88
|
+
* "canonical JSON serialization... with stable (sorted) key order" DATA_MODEL.md
|
|
89
|
+
* §10 point 2 defines for `transition.sha` and states is "the same convention
|
|
90
|
+
* SPEC.md §4a already states for the audit `sha`, applied identically."
|
|
91
|
+
* `undefined` values are omitted (never serialized as `null` silently — a
|
|
92
|
+
* caller that means "explicitly null" must pass `null`, not omit the key).
|
|
93
|
+
*/
|
|
94
|
+
export declare function canonicalJSONStringify(value: Record<string, unknown>): string;
|
|
95
|
+
/**
|
|
96
|
+
* uid → node, inside a tx. Mirrors `getNodeByUid`'s own SELECT
|
|
97
|
+
* (`SELECT * FROM node WHERE uid = ?`, `@adhd/sox-graph-store` dist/index.js:1573-1576)
|
|
98
|
+
* issued against `tx` instead of the bare adapter — never a `getNodeByUid`
|
|
99
|
+
* call itself, which always runs against `this.adapter` (§4c).
|
|
100
|
+
*/
|
|
101
|
+
export declare function getNodeByUidTx(tx: AdapterTransaction, uid: string): Promise<ITxNodeRow | null>;
|
|
102
|
+
/**
|
|
103
|
+
* Resolves `uid` to the CURRENT, live `issue` row, or throws.
|
|
104
|
+
*
|
|
105
|
+
* Every issue verb needs exactly this, and the check is in two parts that are
|
|
106
|
+
* easy to half-implement:
|
|
107
|
+
*
|
|
108
|
+
* - `tInvalid !== null` — the issue was soft-deleted (`delete.ts`).
|
|
109
|
+
* - `isSuperseded` — the issue's body was edited, so `update.ts` minted a
|
|
110
|
+
* NEW node with a new uid and flipped this row's `is_superseded` flag.
|
|
111
|
+
* **The supersede CAS sets `is_superseded` ONLY; it never touches
|
|
112
|
+
* `t_invalid`** (update.ts's `UPDATE node SET is_superseded = 1 WHERE
|
|
113
|
+
* rowid = ? AND is_superseded = 0`). So a superseded row is still
|
|
114
|
+
* `t_invalid IS NULL`, and a `tInvalid`-only guard lets a stale uid
|
|
115
|
+
* straight through.
|
|
116
|
+
*
|
|
117
|
+
* That second half was missing from `claim`, `relate`, `move` and `delete`
|
|
118
|
+
* while `update` and `transition` each had their own hand-written copy of it.
|
|
119
|
+
* The consequences were silent, not loud — this repo is parallel-process
|
|
120
|
+
* enabled, so a caller holding a uid from before a concurrent body edit is a
|
|
121
|
+
* real scenario, and it could `claim` a superseded node (two agents each
|
|
122
|
+
* believing they hold the lease on the same issue), `relate` an edge onto it
|
|
123
|
+
* (permanently invisible against the issue's real uid, since `card.ts` never
|
|
124
|
+
* walks SUPERSEDES chains), or `delete` it and be told `invalidated: true`
|
|
125
|
+
* while the live issue was untouched.
|
|
126
|
+
*
|
|
127
|
+
* It exists as ONE function, rather than as a documented convention, because
|
|
128
|
+
* the convention is exactly what failed: six verbs hand-duplicated the fetch
|
|
129
|
+
* and four dropped half the guard. A new verb that calls this cannot
|
|
130
|
+
* reproduce the gap; a new verb that hand-rolls `getNodeByUidTx` can, so
|
|
131
|
+
* prefer this everywhere an issue uid arrives from a caller.
|
|
132
|
+
*
|
|
133
|
+
* @throws IssueNotFoundError when no row carries `uid`, it is not an `issue`,
|
|
134
|
+
* or it has been soft-deleted.
|
|
135
|
+
* @throws StaleSupersedeError when `uid` names a superseded node — the uid was
|
|
136
|
+
* valid once and names a real row, so this is deliberately NOT reported as
|
|
137
|
+
* "not found": the caller's reference is stale, not wrong.
|
|
138
|
+
*/
|
|
139
|
+
export declare function resolveLiveIssueTx(tx: AdapterTransaction, uid: string): Promise<ITxNodeRow>;
|
|
140
|
+
/** rowid → node, inside a tx (used to resolve an edge endpoint's kind without a redundant round trip when the caller doesn't already know it). */
|
|
141
|
+
export declare function getNodeByRowidTx(tx: AdapterTransaction, rowid: number): Promise<ITxNodeRow | null>;
|
|
142
|
+
export interface IWriteNodeTxInput {
|
|
143
|
+
/** The entity-type discriminator — `project`/`component`/`location`/`issue`/`kind`/`edge_kind`/`status`/`priority`/`agent`/`note`/`citation`/`transition`/`audit` (§3). NEVER validated against a closed vocabulary here — the schema is open by design (§0 anti-antipattern 3); the write layer is the only composer of these literals. */
|
|
144
|
+
kind: string;
|
|
145
|
+
/** The business name (`issue.title`, a catalog row's name, …). Omit for a node with no name (none currently exist in §3's table, but the column is nullable). */
|
|
146
|
+
name?: string;
|
|
147
|
+
/** The content column. Defaults to `name` when omitted (mirrors `findOrCreateNode`'s own `opts?.content ?? name` convention, `@adhd/sox-graph-store` dist/index.js:1446). */
|
|
148
|
+
content?: string;
|
|
149
|
+
metadata?: Record<string, unknown>;
|
|
150
|
+
/**
|
|
151
|
+
* The ISO-8601 timestamp stamped onto this row's `t_occurred`/`t_created`/
|
|
152
|
+
* `t_valid` columns. Optional; defaults to a fresh {@link nowISO}() call
|
|
153
|
+
* when omitted, so an existing single-row call site compiles and behaves
|
|
154
|
+
* unchanged.
|
|
155
|
+
*
|
|
156
|
+
* A caller composing ONE logical write out of several rows (e.g.
|
|
157
|
+
* `createIssue`'s issue node + N citation nodes + the `writeAudit` audit
|
|
158
|
+
* node, all inside the SAME `executeWriteTransaction` callback) MUST
|
|
159
|
+
* capture a single `const now = nowISO()` up front and pass it as `at` to
|
|
160
|
+
* EVERY {@link writeNodeTx} (and {@link writeEdgeTx}) call in that closure.
|
|
161
|
+
* Without this, each call computes its own fresh, microseconds-later
|
|
162
|
+
* `nowISO()`, so the issue node's persisted `t_created`, the citations'
|
|
163
|
+
* `t_created`, and the audit row's recorded `at` all drift apart within
|
|
164
|
+
* what is supposed to be one atomic, single-instant write — breaking the
|
|
165
|
+
* guarantee (§4a) that the audit's `at` describes exactly when the subject
|
|
166
|
+
* it records was created.
|
|
167
|
+
*/
|
|
168
|
+
at?: string;
|
|
169
|
+
/**
|
|
170
|
+
* NOT a real input — {@link writeNodeTx} unconditionally never dedupes (see
|
|
171
|
+
* its own doc comment below) and never reads a dedupe flag off `input` at
|
|
172
|
+
* all. Declared here ONLY as `never` so that a future call site which
|
|
173
|
+
* writes `{ ..., skipDedupe: true }` (or `false`) — believing, from having
|
|
174
|
+
* read the library's own `writeNodeInTx` signature, that this is a real
|
|
175
|
+
* per-call toggle — fails to COMPILE (excess-property check on an object
|
|
176
|
+
* literal) instead of silently having the property ignored. SPEC.md §1/§4
|
|
177
|
+
* state "All entity writes pass `skipDedupe: true`" with NO kind-scoped
|
|
178
|
+
* exception anywhere in the spec — every kind this write layer ever
|
|
179
|
+
* composes (`project`/`component`/`location`/`issue`/`kind`/`edge_kind`/
|
|
180
|
+
* `status`/`priority`/`agent`/`note`/`citation`/`transition`/`audit`,
|
|
181
|
+
* SPEC.md §3) skips dedupe unconditionally, so there is no legitimate
|
|
182
|
+
* call-site variance to gate: the safest surface for "always true" is a
|
|
183
|
+
* surface that cannot express anything else.
|
|
184
|
+
*/
|
|
185
|
+
skipDedupe?: never;
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Hand-composed node INSERT, issued against `tx`. Mirrors `writeNodeInTx`'s
|
|
189
|
+
* own INSERT column list and defaults EXACTLY (`@adhd/sox-graph-store`
|
|
190
|
+
* dist/index.js:1410-1421) with `skipDedupe: true` UNCONDITIONALLY in every
|
|
191
|
+
* normal run — the spec §1 requires this on every entity write ("two
|
|
192
|
+
* identical-body issues are two rows, never one collapsed row") — so this
|
|
193
|
+
* function skips the content-hash SELECT `writeNodeInTx` runs when
|
|
194
|
+
* `skipDedupe` is falsy, and always inserts a fresh row. `uid` is
|
|
195
|
+
* `crypto.randomUUID()` — the SAME generator the library uses
|
|
196
|
+
* (`generateUid()`, dist/index.js:646-648) — so a write-layer-written row is
|
|
197
|
+
* byte-for-byte indistinguishable in shape from one the library itself would
|
|
198
|
+
* have written, just composed by hand to stay inside the caller's own
|
|
199
|
+
* transaction.
|
|
200
|
+
*
|
|
201
|
+
* **`skipDedupe` is uncontrollable from any call site, by construction, not
|
|
202
|
+
* by per-call convention.** {@link IWriteNodeTxInput} has no way to ask this
|
|
203
|
+
* function to dedupe (its `skipDedupe` field is typed `never` specifically
|
|
204
|
+
* so no call site can even compile one in). This is deliberate: seven more
|
|
205
|
+
* write verbs (`update`/`transition`/`claim`/`relate`/`move`/`delete`/
|
|
206
|
+
* `supersede`) are built on top of this file by separate agents, and
|
|
207
|
+
* SPEC.md §1/§4 ("All entity writes pass `skipDedupe: true`") name NO kind
|
|
208
|
+
* that is exempt — the catalog kinds (`kind`/`status`/`priority`/`agent`/
|
|
209
|
+
* `edge_kind`), the resolved-only kinds (`project`/`component`), and every
|
|
210
|
+
* subject kind (`issue`/`note`/`citation`/`transition`/`audit`/`location`)
|
|
211
|
+
* all go through this SAME unconditional INSERT. A future call site cannot
|
|
212
|
+
* "forget" to pass `skipDedupe: true` because there is no longer any code
|
|
213
|
+
* path — in this function OR in its input type — where forgetting it would
|
|
214
|
+
* change behavior. The ONLY door back to the library's own dedupe behavior
|
|
215
|
+
* is {@link resolveDedupeMode}'s env switch, checked below — negative-control
|
|
216
|
+
* test use only, never a per-call toggle.
|
|
217
|
+
*/
|
|
218
|
+
export declare function writeNodeTx(tx: AdapterTransaction, input: IWriteNodeTxInput): Promise<{
|
|
219
|
+
rowid: number;
|
|
220
|
+
uid: string;
|
|
221
|
+
}>;
|
|
222
|
+
/**
|
|
223
|
+
* The declared `(rel, source_kind, target_kind, multiplicity)` table the spec
|
|
224
|
+
* §3 fixes once — the same "typed rels, each name unique with ONE
|
|
225
|
+
* (source_kind → target_kind)" table, `audits` carrying the one declared
|
|
226
|
+
* `source_kind: '*'` sentinel (§2). This is DATA the write layer already
|
|
227
|
+
* knows at compile time; catalog.ts's `resolveEdgeKindTx` reconciles it with
|
|
228
|
+
* the `edge_kind` catalog ROW (seeded once, never caller-mintable, §1) rather
|
|
229
|
+
* than re-deriving it from this table on every call.
|
|
230
|
+
*/
|
|
231
|
+
export type EdgeMultiplicity = 'n:1' | '1:n' | 'n:m';
|
|
232
|
+
export interface IEdgeKindRule {
|
|
233
|
+
rel: string;
|
|
234
|
+
/** `'*'` is the one declared sentinel (`audits`, §2) — skip the source-kind match for this rule only. */
|
|
235
|
+
sourceKind: string;
|
|
236
|
+
targetKind: string;
|
|
237
|
+
multiplicity: EdgeMultiplicity;
|
|
238
|
+
}
|
|
239
|
+
export interface IWriteEdgeTxInput {
|
|
240
|
+
srcRowid: number;
|
|
241
|
+
srcUid: string;
|
|
242
|
+
srcKind: string;
|
|
243
|
+
dstRowid: number;
|
|
244
|
+
dstUid: string;
|
|
245
|
+
dstKind: string;
|
|
246
|
+
rel: string;
|
|
247
|
+
metadata?: Record<string, unknown>;
|
|
248
|
+
weight?: number;
|
|
249
|
+
/** The resolved `edge_kind` rule this rel must satisfy (catalog.ts's `resolveEdgeKindTx`). */
|
|
250
|
+
rule: IEdgeKindRule;
|
|
251
|
+
typePolicy: TypePolicy;
|
|
252
|
+
/**
|
|
253
|
+
* The ISO-8601 timestamp stamped onto this edge's `t_created`/`t_valid`
|
|
254
|
+
* columns. Optional; defaults to a fresh {@link nowISO}() call when
|
|
255
|
+
* omitted. Same one-logical-write-one-timestamp rule as
|
|
256
|
+
* {@link IWriteNodeTxInput.at} — a caller writing several edges (or an
|
|
257
|
+
* edge alongside node writes) inside one `executeWriteTransaction`
|
|
258
|
+
* callback should pass the SAME captured `now` to every one of them.
|
|
259
|
+
*/
|
|
260
|
+
at?: string;
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Edge write, inside a tx (upsert, re-livening included). Mirrors
|
|
264
|
+
* `writeEdgeInternal`'s own INSERT EXACTLY (`@adhd/sox-graph-store`
|
|
265
|
+
* dist/index.js:1894-1898) — same `ON CONFLICT(src, dst, rel) DO UPDATE`,
|
|
266
|
+
* same `t_invalid = NULL` re-livening — issued against `tx` instead of the
|
|
267
|
+
* bare adapter, never a `writeEdge` call itself (§4c).
|
|
268
|
+
*
|
|
269
|
+
* Endpoint-kind validation (§2: resolve `edge_kind`, check `source_kind`/
|
|
270
|
+
* `target_kind`, THEN call the injected `TypePolicy` directly in-process,
|
|
271
|
+
* never through `writeEdge`) and multiplicity enforcement both run BEFORE the
|
|
272
|
+
* INSERT, against the SAME `tx` handle.
|
|
273
|
+
*/
|
|
274
|
+
export declare function writeEdgeTx(tx: AdapterTransaction, input: IWriteEdgeTxInput): Promise<void>;
|
|
275
|
+
/**
|
|
276
|
+
* Internal — a resolved `edge_kind` rule's declared endpoint kind does not
|
|
277
|
+
* match the actual endpoint being written. This is a write-layer composition
|
|
278
|
+
* defect (the caller passed the wrong node as an endpoint), never a
|
|
279
|
+
* caller-facing input-validation case with its own named class in the spec's
|
|
280
|
+
* taxonomy — every write-layer call site passes endpoint kinds it just resolved or
|
|
281
|
+
* wrote itself in the SAME transaction, so this should be unreachable in
|
|
282
|
+
* practice; it exists to fail loudly rather than silently write a
|
|
283
|
+
* mismatched edge if that invariant is ever broken by a future verb.
|
|
284
|
+
*/
|
|
285
|
+
export declare class BacklogEdgeKindMismatchError extends BacklogWriteError {
|
|
286
|
+
readonly code: "E_VALIDATION";
|
|
287
|
+
readonly retryable = false;
|
|
288
|
+
constructor(rel: string, side: 'source' | 'target', expectedKind: string, actualKind: string);
|
|
289
|
+
}
|
|
290
|
+
export interface IInvalidateEdgeTxInput {
|
|
291
|
+
srcRowid: number;
|
|
292
|
+
dstRowid: number;
|
|
293
|
+
rel: string;
|
|
294
|
+
reason?: string;
|
|
295
|
+
/**
|
|
296
|
+
* The ISO-8601 timestamp stamped onto `t_invalid`/`meta.invalidatedAt`.
|
|
297
|
+
* Optional; defaults to a fresh {@link nowISO}() call when omitted. Same
|
|
298
|
+
* one-logical-write-one-timestamp rule as {@link IWriteNodeTxInput.at}.
|
|
299
|
+
*/
|
|
300
|
+
at?: string;
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* Edge invalidate, inside a tx. Mirrors `invalidateEdge` EXACTLY
|
|
304
|
+
* (`@adhd/sox-graph-store` dist/index.js:1846-1855) — same idempotent
|
|
305
|
+
* "already invalidated or absent → no-op" behavior — issued against `tx`
|
|
306
|
+
* instead of the bare adapter.
|
|
307
|
+
*/
|
|
308
|
+
export declare function invalidateEdgeTx(tx: AdapterTransaction, input: IInvalidateEdgeTxInput): Promise<void>;
|
|
309
|
+
/**
|
|
310
|
+
* The one transaction wrapper every write verb calls — `store.adapter.transaction(fn,
|
|
311
|
+
* {mode: resolveTransactionMode()})`, which is `'immediate'` (§4c: `BEGIN
|
|
312
|
+
* IMMEDIATE`, the RESERVED-lock-at-BEGIN "compare-and-swap primitive" every
|
|
313
|
+
* check-then-act verb in §4's table depends on) in every normal run and only
|
|
314
|
+
* ever `'deferred'` when a test has explicitly set
|
|
315
|
+
* `ADHD_BACKLOG_UNSAFE_TX_MODE=deferred` to prove a negative control (see
|
|
316
|
+
* {@link resolveTransactionMode}'s own doc comment) — with the §4c retry
|
|
317
|
+
* contract layered on top:
|
|
318
|
+
*
|
|
319
|
+
* - A {@link BacklogWriteError} thrown from `fn` (an app-level validation
|
|
320
|
+
* failure, or the `supersede` CAS's {@link StaleSupersedeError}) is
|
|
321
|
+
* ALREADY a decided, terminal, transport-facing error — rethrown
|
|
322
|
+
* immediately, untouched, never reclassified or retried.
|
|
323
|
+
* - A raw driver-level error is classified via {@link classifyDriverError}.
|
|
324
|
+
* `E_CONTENTION` retries up to 3 total attempts (linear backoff 250ms then
|
|
325
|
+
* 500ms) before surfacing {@link WriteContentionError}. `E_IO`
|
|
326
|
+
* (`isDatabaseError(err)` true — a recognized-but-otherwise-unclassified
|
|
327
|
+
* database/driver error) surfaces {@link WriteIOError} on the FIRST
|
|
328
|
+
* occurrence, never retried — §4c's uniform reason across every write
|
|
329
|
+
* class: `writeAudit` (§4a) rides inside literally every write-layer
|
|
330
|
+
* transaction as an unguarded, keyless-content INSERT, so a retry whose
|
|
331
|
+
* earlier attempt actually committed would silently double the audit
|
|
332
|
+
* trail even where the SUBJECT write is safe to retry on its own merits.
|
|
333
|
+
* An `E_IO` classification whose `err` is NOT database-shaped at all
|
|
334
|
+
* (`isDatabaseError(err)` false — a genuine app-level bug, never a driver
|
|
335
|
+
* fault) is rethrown UNTOUCHED instead — never wrapped in
|
|
336
|
+
* {@link WriteIOError}, which always asserts `retryable: true`.
|
|
337
|
+
* - An `E_CONSTRAINT` this function did not already expect as
|
|
338
|
+
* {@link StaleSupersedeError} (i.e. a raw, unclassified constraint
|
|
339
|
+
* violation — structurally unreachable under the hand-composed
|
|
340
|
+
* find-then-create + `immediate`-mode discipline every verb follows, §1)
|
|
341
|
+
* is rethrown UNTOUCHED — never swallowed, never coerced into a
|
|
342
|
+
* not-actually-specified wrapper class.
|
|
343
|
+
*/
|
|
344
|
+
export declare function executeWriteTransaction<T>(handle: IWriteStoreHandle, fn: (tx: AdapterTransaction) => Promise<T>): Promise<T>;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { IWriteStoreHandle } from './tx.js';
|
|
2
|
+
|
|
3
|
+
export interface IUpdateIssueInput {
|
|
4
|
+
/** The `issue` uid to update (§6.3, an "Issue verb"). */
|
|
5
|
+
uid: string;
|
|
6
|
+
/** The acting identity — an agent or a person (§6.3's opening rule). REQUIRED. */
|
|
7
|
+
by: string;
|
|
8
|
+
/** → `touch` (metadata/name only). */
|
|
9
|
+
title?: string;
|
|
10
|
+
/** → `supersede` (§3/§4: "body change → supersede... never touch a body"). Mints a fresh `uid` — see {@link IUpdateIssueOutcome.uid}. */
|
|
11
|
+
body?: string;
|
|
12
|
+
/** catalog name or uid; → `touch` + `has_kind` edge rewrite (hand-composed invalidate-old + upsert-new, same tx, §4c). An unresolved NAME mints; a uid-shaped ref that does not resolve throws `CatalogNotFoundError('kind', ref)` (§6.1 — minting never applies to a uid). */
|
|
13
|
+
kind?: string;
|
|
14
|
+
/** catalog name or uid; → `touch` + `has_priority` edge rewrite. An unresolved NAME mints (rank = one past the current max); a uid-shaped ref that does not resolve throws `CatalogNotFoundError('priority', ref)`. */
|
|
15
|
+
priority?: string;
|
|
16
|
+
/** Plain metadata scalar (§6.2) — no edge. */
|
|
17
|
+
assignee?: string;
|
|
18
|
+
/** catalog agent name/uid; → `touch` + `authored_by` edge rewrite. An unresolved NAME mints; a uid-shaped ref that does not resolve throws `CatalogNotFoundError('agent', ref)`. */
|
|
19
|
+
author?: string;
|
|
20
|
+
/**
|
|
21
|
+
* §4b/§6.2 — waits for the fire-and-forget on-write embedding round-trip
|
|
22
|
+
* before `update` returns, when `true` and `handle.embedding` is
|
|
23
|
+
* configured. Only meaningful on a BODY-changing call (the `supersede`
|
|
24
|
+
* path) — a pure touch (title/kind/priority/assignee/author only) never
|
|
25
|
+
* schedules a re-embed at all, so `awaitEmbed:true` on a touch-only patch
|
|
26
|
+
* is a harmless no-op (see `embedding-observer.ts`'s own doc comment for
|
|
27
|
+
* why touch is deliberately excluded). On a body change, TWO round-trips
|
|
28
|
+
* are scheduled (delete the old node's vector, upsert the new node's) —
|
|
29
|
+
* `awaitEmbed:true` awaits BOTH before returning.
|
|
30
|
+
*/
|
|
31
|
+
awaitEmbed?: boolean;
|
|
32
|
+
}
|
|
33
|
+
export type IUpdateIssueChangedField = 'title' | 'body' | 'kind' | 'priority' | 'assignee' | 'author';
|
|
34
|
+
export interface IUpdateIssueOutcome {
|
|
35
|
+
/**
|
|
36
|
+
* The resulting CURRENT issue's uid — the SAME `input.uid` when `body` was
|
|
37
|
+
* not given (a pure touch/edge-rewrite on the existing node), or the FRESH
|
|
38
|
+
* uid the supersede minted when it was (§6.3.2's `create+supersedes`
|
|
39
|
+
* composition reads exactly this field as "the NEW node the supersede
|
|
40
|
+
* primitive minted" — `IUpdateIssueOutcome` carries no separate
|
|
41
|
+
* `supersededUid`, so `input.uid` is that composition's own record of what
|
|
42
|
+
* was superseded).
|
|
43
|
+
*/
|
|
44
|
+
uid: string;
|
|
45
|
+
/**
|
|
46
|
+
* Every key present in the input with a defined value, and ONLY those keys
|
|
47
|
+
* (`assertNoSilentlyDiscardedPatchKeys`, carried forward per §6.3.3 as a
|
|
48
|
+
* general correctness rule, not machinery scoped to any particular patch
|
|
49
|
+
* shape). Empty is unreachable here — a zero-field patch throws
|
|
50
|
+
* `InvalidArgumentError` before this outcome is ever constructed.
|
|
51
|
+
*/
|
|
52
|
+
changed: IUpdateIssueChangedField[];
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Update an issue (§4, §6.3.3). One `immediate` transaction.
|
|
56
|
+
*
|
|
57
|
+
* Errors: `InvalidArgumentError` (`uid`/`by` missing/blank; blank `title`/
|
|
58
|
+
* `body` when given; no fields at all in the patch — a zero-field call is a
|
|
59
|
+
* client error, not a silent no-op success, since the caller almost
|
|
60
|
+
* certainly meant a different verb), `BacklogValidationError('status', ...)`
|
|
61
|
+
* (an untyped caller sent a `status` field — §8 AC-14, this is the ONE
|
|
62
|
+
* runtime rejection this whole file exists to guarantee, and it names
|
|
63
|
+
* `transition` in its message), `IssueNotFoundError` (no live `issue` node
|
|
64
|
+
* carries `uid`, including an already-superseded one — this file's own doc
|
|
65
|
+
* comment on why that is a deliberate divergence, reusing
|
|
66
|
+
* `StaleSupersedeError` rather than `IssueNotFoundError` for that specific
|
|
67
|
+
* case since the identity itself still exists, just not at THIS uid
|
|
68
|
+
* anymore), `CatalogNotFoundError('kind'|'priority'|'agent', ref)`
|
|
69
|
+
* (uid-shaped ref only — an unresolved NAME instead auto-mints, §6.1),
|
|
70
|
+
* `InvalidArgumentError('kind', ...)` (§2 `project_kind` — a resolved
|
|
71
|
+
* `kind` name outside this project's non-empty `allowedKinds` set) / a
|
|
72
|
+
* project-declared `requiredFields` entry left blank by this call (§2 —
|
|
73
|
+
* see this file's own doc comment on the composition gap this resolves),
|
|
74
|
+
* `StaleSupersedeError(uid)` (body-change path only — the supersede CAS
|
|
75
|
+
* lost a race to a concurrent edit of the same `uid`, OR `uid` was already
|
|
76
|
+
* superseded before this call ever started; the patch was not applied,
|
|
77
|
+
* re-`get` and retry, never a silent partial apply),
|
|
78
|
+
* `WriteContentionError`/`WriteIOError` (§4c — an exhausted driver-level
|
|
79
|
+
* retry on the underlying `immediate` transaction).
|
|
80
|
+
*/
|
|
81
|
+
export declare function update(handle: IWriteStoreHandle, input: IUpdateIssueInput): Promise<IUpdateIssueOutcome>;
|
package/client.d.ts
DELETED
|
@@ -1,174 +0,0 @@
|
|
|
1
|
-
import { GraphBacklogStore } from './store/graph-backlog-store.js';
|
|
2
|
-
import { BacklogConfig } from './env.js';
|
|
3
|
-
import { ArchiveOpts, ArchiveResult, AuditTrailResult, BacklogFilter, BacklogItem, BacklogStats, BacklogStatus, ClaimOpts, ClaimResult, Citation, CreateItemInput, CreateItemResult, DependencyGraph, ImportMarkdownInput, ImportResult, MigrationPhase, MigrationStatusResult, Priority, ReleaseResult, RepoMigrationResult, SetMigrationPhaseResult, StatsScope, TopoOrderResult, TransitionOpts, UpdateItemInput } from './model.js';
|
|
4
|
-
import { Environment } from '@adhd/environment';
|
|
5
|
-
|
|
6
|
-
/** The one type apigen special-cases via the `ctx-name-only` invariant. */
|
|
7
|
-
export interface BacklogCtx {
|
|
8
|
-
store: GraphBacklogStore;
|
|
9
|
-
env: Environment<BacklogConfig>;
|
|
10
|
-
/**
|
|
11
|
-
* Test-isolation escape hatch ONLY — mirrors `BuildBacklogEnvOptions.adhdRoot`
|
|
12
|
-
* (the same value passed to `buildBacklogEnv({ adhdRoot })` when constructing
|
|
13
|
-
* `env`). NEVER set this in production code (`server.ts`/`cli.ts` never do).
|
|
14
|
-
* `setMigrationPhase` threads it through to `writeMigrationPhase` so a
|
|
15
|
-
* temp-rooted test `ctx` can never write to the real machine-global
|
|
16
|
-
* `~/.adhd` — omitting this on a real ctx write is exactly the bug
|
|
17
|
-
* `migration-admin.spec.ts`'s negative control caught (a test run wrote
|
|
18
|
-
* `phase-4` to the real `~/.adhd/backlog/production/config.yaml` before
|
|
19
|
-
* this field existed; reverted, see CHANGELOG).
|
|
20
|
-
*/
|
|
21
|
-
adhdRoot?: string;
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* Dedupe-scans (FTS + symbol/path/errorText metadata match) before writing.
|
|
25
|
-
* Allocates humanId as family + next number within (repo, family) unless
|
|
26
|
-
* idOverride is given.
|
|
27
|
-
*/
|
|
28
|
-
export declare function createItem(ctx: BacklogCtx, input: CreateItemInput): Promise<CreateItemResult>;
|
|
29
|
-
/**
|
|
30
|
-
* repo is required — humanId alone is not globally unique. A genuine miss
|
|
31
|
-
* (humanId doesn't exist under ANY repo) still returns `null` — unchanged,
|
|
32
|
-
* every existing caller relying on nullable-not-throwing keeps working.
|
|
33
|
-
*
|
|
34
|
-
* BUG-BACKLOG-REPO-LOOKUP-UX-001: previously a repo/humanId MISMATCH (the
|
|
35
|
-
* item is live, just filed under a different `repo` string) was
|
|
36
|
-
* indistinguishable from a genuine miss — both silently returned `null`,
|
|
37
|
-
* which is worse than `appendNote`'s bare-but-at-least-thrown
|
|
38
|
-
* `BacklogItemNotFoundError` (and, before this fix, could surface through
|
|
39
|
-
* apigen's MCP layer as the unrelated broken int64/null encoding,
|
|
40
|
-
* BUG-APIGEN-LOGICAL-NULL-OBJECT-RESULT-INT64-001 — out of scope here, but
|
|
41
|
-
* this fix removes the only path that made this lookup look like that bug).
|
|
42
|
-
* Now: a real cross-repo match THROWS the same informative
|
|
43
|
-
* `BacklogItemNotFoundError` (with `foundInRepos` naming the actual repo) the
|
|
44
|
-
* mutating lookups already throw, instead of masquerading as "not found".
|
|
45
|
-
*/
|
|
46
|
-
export declare function getItem(ctx: BacklogCtx, repo: string, humanId: string): Promise<BacklogItem | null>;
|
|
47
|
-
export declare function updateItem(ctx: BacklogCtx, repo: string, humanId: string, patch: UpdateItemInput): Promise<BacklogItem>;
|
|
48
|
-
export declare function listItems(ctx: BacklogCtx, filter?: BacklogFilter): Promise<BacklogItem[]>;
|
|
49
|
-
/** Invalidates the node (bi-temporal — never a hard delete). */
|
|
50
|
-
export declare function softDeleteItem(ctx: BacklogCtx, repo: string, humanId: string, reason: string): Promise<void>;
|
|
51
|
-
export declare function stats(ctx: BacklogCtx, scope?: StatsScope): Promise<BacklogStats>;
|
|
52
|
-
/** Open + prioritized, most-severe first. */
|
|
53
|
-
export declare function spotlight(ctx: BacklogCtx, scope?: StatsScope, limit?: number): Promise<BacklogItem[]>;
|
|
54
|
-
/** Open items whose every DEPENDS_ON target is a terminal status AND which are not currently claimed. */
|
|
55
|
-
export declare function readyItems(ctx: BacklogCtx, scope?: StatsScope): Promise<BacklogItem[]>;
|
|
56
|
-
/** The DEPENDS_ON set of `humanId` that is NOT yet terminal. */
|
|
57
|
-
export declare function blockers(ctx: BacklogCtx, repo: string, humanId: string): Promise<BacklogItem[]>;
|
|
58
|
-
export declare function dependencyGraph(ctx: BacklogCtx, scope?: StatsScope): Promise<DependencyGraph>;
|
|
59
|
-
export declare function topoOrder(ctx: BacklogCtx, scope?: StatsScope): Promise<TopoOrderResult>;
|
|
60
|
-
/** Items whose claim lease is older than maxAgeMin with no renewal — candidates for --force reclaim. */
|
|
61
|
-
export declare function staleClaims(ctx: BacklogCtx, maxAgeMin: number, scope?: StatsScope): Promise<BacklogItem[]>;
|
|
62
|
-
export declare function claimItem(ctx: BacklogCtx, repo: string, humanId: string, by: string, opts?: ClaimOpts): Promise<ClaimResult>;
|
|
63
|
-
/** Same-claimant renewal — always succeeds (bumps claimedAt), no contention check. */
|
|
64
|
-
export declare function renewClaim(ctx: BacklogCtx, repo: string, humanId: string, by: string): Promise<ClaimResult>;
|
|
65
|
-
export declare function releaseClaim(ctx: BacklogCtx, repo: string, humanId: string, by: string, opts?: {
|
|
66
|
-
force?: boolean;
|
|
67
|
-
}): Promise<ReleaseResult>;
|
|
68
|
-
/** Durable ownership (planner decision) — distinct from the ephemeral claim lease. */
|
|
69
|
-
export declare function assignItem(ctx: BacklogCtx, repo: string, humanId: string, to: string, by: string): Promise<BacklogItem>;
|
|
70
|
-
/** transitionStatus(id, 'IN_PROGRESS', ...) + an implicit claimItem(id, by) — a no-op claim-wise if already held by `by`. */
|
|
71
|
-
export declare function startWork(ctx: BacklogCtx, repo: string, humanId: string, by: string): Promise<BacklogItem>;
|
|
72
|
-
export declare function transitionStatus(ctx: BacklogCtx, repo: string, humanId: string, status: BacklogStatus, opts: TransitionOpts): Promise<BacklogItem>;
|
|
73
|
-
export declare function addCitation(ctx: BacklogCtx, repo: string, humanId: string, citation: Citation): Promise<BacklogItem>;
|
|
74
|
-
export declare function appendNote(ctx: BacklogCtx, repo: string, humanId: string, by: string, text: string): Promise<BacklogItem>;
|
|
75
|
-
/** Sugar for transitionStatus into any terminal status. */
|
|
76
|
-
export declare function resolveItem(ctx: BacklogCtx, repo: string, humanId: string, status: BacklogStatus, opts: TransitionOpts): Promise<BacklogItem>;
|
|
77
|
-
/**
|
|
78
|
-
* Renders terminal items to CHANGELOG.md-formatted markdown and marks them
|
|
79
|
-
* archived (metadata.archivedAt set) so renderToMarkdown's default view
|
|
80
|
-
* excludes them — the graph node itself is NEVER deleted.
|
|
81
|
-
*/
|
|
82
|
-
export declare function archiveResolved(ctx: BacklogCtx, scope: StatsScope, opts?: ArchiveOpts): Promise<ArchiveResult>;
|
|
83
|
-
export declare function addDependency(ctx: BacklogCtx, repo: string, humanId: string, dependsOnHumanId: string): Promise<void>;
|
|
84
|
-
export declare function removeDependency(ctx: BacklogCtx, repo: string, humanId: string, dependsOnHumanId: string): Promise<void>;
|
|
85
|
-
export declare function linkRelated(ctx: BacklogCtx, repo: string, humanIdA: string, humanIdB: string): Promise<void>;
|
|
86
|
-
/** Mints a new item, links new SUPERSEDES old, invalidates old with reason. */
|
|
87
|
-
export declare function supersedeItem(ctx: BacklogCtx, repo: string, oldHumanId: string, newInput: CreateItemInput, reason: string): Promise<BacklogItem>;
|
|
88
|
-
/** Creates N children linked child PART_OF parent. Parent is left open. */
|
|
89
|
-
export declare function splitItem(ctx: BacklogCtx, repo: string, parentHumanId: string, children: CreateItemInput[]): Promise<BacklogItem[]>;
|
|
90
|
-
/** SAME_AS(drop -> keep), invalidates drop with an auto-generated reason. */
|
|
91
|
-
export declare function mergeItems(ctx: BacklogCtx, repo: string, keepHumanId: string, dropHumanId: string, reason: string): Promise<BacklogItem>;
|
|
92
|
-
export declare function setPriority(ctx: BacklogCtx, repo: string, humanId: string, priority: Priority): Promise<BacklogItem>;
|
|
93
|
-
/** MEMBER_OF edge to a plan node (auto-created if the plan slug hasn't been seen before). */
|
|
94
|
-
export declare function attachToPlan(ctx: BacklogCtx, repo: string, humanId: string, planSlug: string): Promise<void>;
|
|
95
|
-
/**
|
|
96
|
-
* BUG-BACKLOG-REPO-SPLIT-001 / DEBT-BACKLOG-REPO-MOVE-001 — the dedicated
|
|
97
|
-
* primitive to move every live item out of `fromRepo` into `toRepo` (a
|
|
98
|
-
* repo-key correction, e.g. a legacy `"adhd"` string onto the canonical
|
|
99
|
-
* `"PseudoSky/adhd"`). `dryRun` defaults to `true`: a caller must pass
|
|
100
|
-
* `dryRun:false` explicitly to write anything — the default call is always
|
|
101
|
-
* safe to make speculatively and returns the full plan (including which
|
|
102
|
-
* items would be renamed, and to what) with zero mutation.
|
|
103
|
-
*
|
|
104
|
-
* Collisions (a humanId already live in `toRepo`) are never silently
|
|
105
|
-
* dropped, overwritten, or left ambiguous — each is deterministically
|
|
106
|
-
* renamed to the next free number in its own family within `toRepo`
|
|
107
|
-
* (`store/repo-migration.ts`'s `planRepoMigration`), and an audit note
|
|
108
|
-
* recording the original `(fromRepo, humanId)` is attached to the moved
|
|
109
|
-
* item so the rename is traceable. Cross-item links (DEPENDS_ON,
|
|
110
|
-
* RELATES_TO, PART_OF, SUPERSEDES, SAME_AS, MEMBER_OF, ASSIGNED_TO) are
|
|
111
|
-
* preserved automatically — a move never changes a node's id, only its
|
|
112
|
-
* `namespace`/`repo`/`humanId`/`name`/`content`.
|
|
113
|
-
*
|
|
114
|
-
* Every planned item gets exactly one reported outcome
|
|
115
|
-
* (`results[i].ok`/`error`) when `dryRun:false` — a per-item failure never
|
|
116
|
-
* aborts the rest of the batch and never goes unreported.
|
|
117
|
-
*/
|
|
118
|
-
export declare function migrateRepo(ctx: BacklogCtx, fromRepo: string, toRepo: string, by: string, dryRun?: boolean): Promise<RepoMigrationResult>;
|
|
119
|
-
export declare function importFromMarkdown(ctx: BacklogCtx, input: ImportMarkdownInput): Promise<ImportResult>;
|
|
120
|
-
/**
|
|
121
|
-
* Excludes archived items (SPEC.md §5.4 archiveResolved) — see markdown.ts's
|
|
122
|
-
* renderItemsToMarkdown doc comment. Archival exclusion goes through
|
|
123
|
-
* `BacklogFilter.excludeArchived` (query.ts's `applyExcludeArchivedFilter`)
|
|
124
|
-
* rather than a private scan here, so a caller comparing this output
|
|
125
|
-
* against `listItems`/`queryItemNodes` for the SAME filter (e.g.
|
|
126
|
-
* `render-projections.mjs`'s round-trip verify) can reproduce this exact
|
|
127
|
-
* item set by passing `{ ...filter, excludeArchived: true }` themselves —
|
|
128
|
-
* see BUG-BACKLOG-RENDER-VERIFY-ARCHIVED-MISMATCH-001.
|
|
129
|
-
*/
|
|
130
|
-
export declare function renderToMarkdown(ctx: BacklogCtx, filter?: BacklogFilter): Promise<string>;
|
|
131
|
-
export declare function exportJson(ctx: BacklogCtx, filter?: BacklogFilter): Promise<BacklogItem[]>;
|
|
132
|
-
/** Bi-temporal history + supersession chain. */
|
|
133
|
-
export declare function auditTrail(ctx: BacklogCtx, repo: string, humanId: string): Promise<AuditTrailResult>;
|
|
134
|
-
/**
|
|
135
|
-
* MIGRATION.md §4.4 — a QUERIED signal, never hardcoded prose: reports the
|
|
136
|
-
* live `migration.phase` config value (`env.ts`, env-overridable via
|
|
137
|
-
* `ADHD_BACKLOG_MIGRATION_PHASE`) plus a human-readable meaning, so an agent
|
|
138
|
-
* (or the `backlog-usage` skill) always asks the tool which of BACKLOG.md or
|
|
139
|
-
* the tool is authoritative right now, instead of trusting a stale doc
|
|
140
|
-
* sentence. NOT yet per-repo-keyed (MIGRATION.md §9 open decision 6) — one
|
|
141
|
-
* global value for the whole machine.
|
|
142
|
-
*/
|
|
143
|
-
export declare function migrationStatus(ctx: BacklogCtx): Promise<MigrationStatusResult>;
|
|
144
|
-
/**
|
|
145
|
-
* MIGRATION.md §4.4's "admin CLI call" half: writes `migration.phase`
|
|
146
|
-
* THROUGH to the GLOBAL layer's `config.yaml` (`migration-admin.ts`) so the
|
|
147
|
-
* new value is a durable, cross-process, cross-repo signal — not merely an
|
|
148
|
-
* env var scoped to whoever's shell happened to export it. Whoever executes
|
|
149
|
-
* a phase's Definition of Done calls this exactly once, after verifying the
|
|
150
|
-
* DoD, never speculatively.
|
|
151
|
-
*/
|
|
152
|
-
export declare function setMigrationPhase(ctx: BacklogCtx, phase: MigrationPhase): Promise<SetMigrationPhaseResult>;
|
|
153
|
-
export interface BacklogVersionInfo {
|
|
154
|
-
/** This package's real `package.json` name, e.g. `"@adhd/backlog"`. */
|
|
155
|
-
name: string;
|
|
156
|
-
/** This package's real `package.json` version — never hardcoded. */
|
|
157
|
-
version: string;
|
|
158
|
-
}
|
|
159
|
-
/**
|
|
160
|
-
* Reports this running package's own real `name`/`version`, read fresh from
|
|
161
|
-
* `package.json` on every call (never a compiled-in constant, so a
|
|
162
|
-
* republished build can never drift from what this reports). `ctx` is
|
|
163
|
-
* unused — kept for signature consistency with every other `client.ts`
|
|
164
|
-
* export (the `ctx-name-only` invariant every extraction/mount/CLI-dispatch
|
|
165
|
-
* path in this package assumes, per this file's own top-of-file doc
|
|
166
|
-
* comment) rather than special-casing a bare, ctx-less export whose
|
|
167
|
-
* extraction/dispatch behavior has not been verified.
|
|
168
|
-
*
|
|
169
|
-
* The reading itself lives in `version-info.ts`'s `readBacklogVersionInfo()`
|
|
170
|
-
* (store-free) so `cli.ts` can short-circuit `backlog version` without
|
|
171
|
-
* opening the store (DEBT-BACKLOG-CLI-EAGER-STORE-OPEN-001) — this function
|
|
172
|
-
* and that short-circuit share the exact same reading path.
|
|
173
|
-
*/
|
|
174
|
-
export declare function version(ctx: BacklogCtx): Promise<BacklogVersionInfo>;
|