@adhd/backlog 1.0.4 → 1.0.6

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 (59) hide show
  1. package/CHANGELOG.md +69 -0
  2. package/README.md +194 -39
  3. package/api.d.ts +87 -0
  4. package/api.ir.json +1 -1
  5. package/citation.d.ts +176 -0
  6. package/envelope.d.ts +36 -2
  7. package/index.d.ts +23 -3
  8. package/index.js +105 -57
  9. package/index.mjs +11450 -6758
  10. package/ir-artifact.d.ts +7 -3
  11. package/lifecycle.d.ts +49 -0
  12. package/package.json +5 -5
  13. package/query/canonical.d.ts +16 -0
  14. package/query/card.d.ts +116 -4
  15. package/query/get.d.ts +8 -1
  16. package/query/index.d.ts +1 -0
  17. package/query/query.d.ts +32 -22
  18. package/query/redirect.d.ts +30 -0
  19. package/query/resolve.d.ts +75 -0
  20. package/query/similar-clusters.d.ts +8 -0
  21. package/query/similarity-signals.d.ts +47 -0
  22. package/query/spec-staleness.d.ts +21 -0
  23. package/query/types.d.ts +249 -34
  24. package/query/verdict-core.d.ts +21 -0
  25. package/query/verdict.d.ts +22 -0
  26. package/query/views/catalog.d.ts +47 -0
  27. package/query/views/registry.d.ts +27 -7
  28. package/query/views/report.d.ts +49 -0
  29. package/query/views/semantic.d.ts +28 -5
  30. package/query/views/stats.d.ts +38 -2
  31. package/readiness.d.ts +29 -0
  32. package/retry-policy.d.ts +44 -0
  33. package/serve.d.ts +1 -1
  34. package/server.d.ts +71 -3
  35. package/service-config.d.ts +109 -0
  36. package/service-errors.d.ts +51 -0
  37. package/skill/SKILL.md +688 -81
  38. package/store/catalog-invariant-guard.d.ts +13 -7
  39. package/vocabulary.d.ts +48 -0
  40. package/write/anchor-check.d.ts +139 -0
  41. package/write/attestation.d.ts +64 -0
  42. package/write/catalog-merge.d.ts +15 -8
  43. package/write/catalog.d.ts +72 -2
  44. package/write/citation-path.d.ts +31 -0
  45. package/write/citation.d.ts +157 -0
  46. package/write/create-issue.d.ts +143 -29
  47. package/write/errors.d.ts +196 -1
  48. package/write/gate.d.ts +67 -0
  49. package/write/merge-project.d.ts +54 -0
  50. package/write/obligation.d.ts +133 -0
  51. package/write/relate.d.ts +1 -1
  52. package/write/revision.d.ts +27 -0
  53. package/write/similarity-scan.d.ts +84 -0
  54. package/write/spec-revision.d.ts +131 -0
  55. package/write/spec-revision.reconcile.d.ts +48 -0
  56. package/write/transition.d.ts +13 -2
  57. package/write/tx.d.ts +44 -2
  58. package/write/uid-prefix.d.ts +78 -0
  59. package/write/update.d.ts +23 -1
package/citation.d.ts ADDED
@@ -0,0 +1,176 @@
1
+ /**
2
+ * citation.ts — the ONE citation contract (leaf module, zero imports).
3
+ *
4
+ * ## Why this module exists
5
+ *
6
+ * A citation used to be described by TWO independent, drifting shapes:
7
+ *
8
+ * - the **persisted** encoding `create-issue.ts`/`transition.ts` wrote into a
9
+ * `citation` node's `meta` — `{ target, target_type, sha, line, at }` (plus
10
+ * the unconsumed `symbol`/`blastRadius`); and
11
+ * - the **transport** input `ICitationInput` a caller supplied —
12
+ * `{ file, lines?, context?, symbol?, blastRadius? }`,
13
+ *
14
+ * with `query/card.ts` hand-inverting one into the other at read time. There
15
+ * was no single definition of "a citation": a field added to one side silently
16
+ * failed to round-trip, and the read projection lived in the query layer while
17
+ * the write encoding lived in the write layer. `DATA_MODEL.md` §4 documented
18
+ * the persisted set, `SPEC.md` §6.3.2 documented the transport set, and neither
19
+ * was the source of truth for the other.
20
+ *
21
+ * This module is that one source. `ICitation` is THE typed contract; the
22
+ * persisted encoding is an implementation detail produced by exactly one
23
+ * function ({@link citationNodeMetadata}) and read back by exactly one function
24
+ * ({@link citationFromNode}). Nothing else in the package may hand-roll either
25
+ * direction.
26
+ *
27
+ * It is a LEAF with zero imports on purpose: it is imported by the write
28
+ * verbs, by the query read projection (`query/card.ts`), and by the pure type
29
+ * barrel (`query/types.ts`), so it must never drag the write or query graph
30
+ * into a consumer that only needs the shape.
31
+ *
32
+ * ## The `revision` field — citing against a git revision, not just the tree
33
+ *
34
+ * A citation whose file exists only on an unmerged branch could not be filed
35
+ * at all: the working-tree sha gate (`citation-path.ts` + `computeCitationSha`)
36
+ * read the file from the checked-out tree, found nothing, and refused. The
37
+ * optional {@link ICitation.revision} names a git revision (branch/tag/sha) the
38
+ * target is resolved against instead — `git show <revision>:<path>` — so
39
+ * branch-only evidence is citable. The revision is persisted verbatim on the
40
+ * citation node (`meta.revision`) and surfaced on read, so a reader can tell a
41
+ * working-tree citation from a revision-pinned one.
42
+ */
43
+ /**
44
+ * The ONE citation contract — a caller-facing citation, and the shape every
45
+ * read projection extends. This is what `SPEC.md` §6.3.2's `Citation` and
46
+ * `DATA_MODEL.md` §4's `citation` node both mean.
47
+ *
48
+ * Field vocabulary (the reconciliation): the persisted node stores
49
+ * `file` as `meta.target` and `lines` as `meta.line` (the graph-native names
50
+ * `DATA_MODEL.md` §4 fixes), but the CONTRACT a consumer passes and receives is
51
+ * always `file`/`lines` — never `target`/`line`. The two are bridged ONLY by
52
+ * {@link citationNodeMetadata}/{@link citationFromNode}, never at a call site.
53
+ */
54
+ export interface ICitation {
55
+ /** The cited target — a repo-relative or absolute filesystem path (the persisted `meta.target`). REQUIRED and non-blank. */
56
+ file: string;
57
+ /**
58
+ * The line or line-range WITHIN `file` (the persisted `meta.line`). OPTIONAL —
59
+ * a whole-file citation omits it. Kept a free `string` (e.g. `"120-140"`) so
60
+ * a caller is not forced to narrow to a single integer.
61
+ *
62
+ * `lines` (pl.) is the CONTRACT name; `line` is the persisted one end. Both
63
+ * spellings intentionally diverge from the persisted key — see this
64
+ * interface's own doc comment.
65
+ */
66
+ lines?: string;
67
+ /**
68
+ * Free-text prose for THIS citation. Persisted as the citation node's
69
+ * `content` column (never its `meta`), which is what {@link citationFromNode}
70
+ * reads back into this field. NOT the item-level disclosure-contract git
71
+ * context — that lives on the issue (`gitContext`) and is rendered once at
72
+ * the head of its `Citations:` block, never per-citation.
73
+ */
74
+ context?: string;
75
+ /** The named symbol (`function`/`class`/`method`) this citation points at, when narrower than a whole file. */
76
+ symbol?: string;
77
+ /**
78
+ * Best-effort enrichment payload carried through verbatim. Not re-specified
79
+ * here (SPEC.md §6.3.2 declares it `CitationBlastRadius`, a type that exists
80
+ * nowhere in the package): the write layer has always stored whatever
81
+ * JSON-serializable value a caller passed and `similarity-scan.ts` reads it
82
+ * only when it is a string. Typed `unknown` to match that existing behavior
83
+ * exactly rather than introducing a third, narrower shape.
84
+ */
85
+ blastRadius?: unknown;
86
+ /**
87
+ * A git revision (branch/tag/sha) the `file` is resolved against, instead of
88
+ * the working tree. Present only for revision-pinned citations — see this
89
+ * module's header. Persisted as `meta.revision`.
90
+ */
91
+ revision?: string;
92
+ }
93
+ /**
94
+ * The pre-unification name of the transport contract, kept as an alias so an
95
+ * existing importer (`write/transition.ts`) compiles unchanged. New code
96
+ * should use `ICitation`; this name means the SAME declaration, never a second
97
+ * shape.
98
+ */
99
+ export type ICitationInput = ICitation;
100
+ /**
101
+ * A citation as PROJECTED FOR READ — the contract plus the server-computed
102
+ * identity (`uid`), content-address (`sha`), and filing instant (`at`), and the
103
+ * persisted `target_type` (today always `'path'`). `query/types.ts`'s
104
+ * `IIssueCitation` extends this, so the read surface and the write surface can
105
+ * never drift.
106
+ */
107
+ export interface ICitationRecord extends ICitation {
108
+ /** The citation node's own uid — the identity `removeCitation` addresses (never a `(target,line)` composite). */
109
+ uid: string;
110
+ /** `sha256` of the cited content at filing time, or the fixed sentinel `"unverified"` (§8.5). */
111
+ sha: string;
112
+ /** The filing instant (the node's own `meta.at`, falling back to `t_created` for a legacy row). */
113
+ at: string;
114
+ /** The persisted target discriminator (`'path'` today). Optional so a legacy row without one still projects. */
115
+ targetType?: string;
116
+ }
117
+ /**
118
+ * The minimal node view {@link citationFromNode} needs — a structural subset of
119
+ * `@adhd/sox-graph-store`'s `NodeRecord` (and of the write layer's
120
+ * `ITxNodeRow`), so neither type has to be imported here.
121
+ */
122
+ export interface ICitationNodeView {
123
+ uid: string;
124
+ /** `string | null` from the write layer's `ITxNodeRow`, `string | undefined` from the query layer's `NodeRecord` — both accepted. */
125
+ name: string | null | undefined;
126
+ content: string;
127
+ metadata: Record<string, unknown> | undefined;
128
+ tCreated: string;
129
+ }
130
+ /**
131
+ * Encode a citation into the `citation` node's `meta` blob — the ONE writer of
132
+ * the persisted citation encoding. `sha` is computed by the caller (the write
133
+ * layer's sha gate) and `at` is the write's single logical timestamp, so both
134
+ * are passed in rather than recomputed here.
135
+ *
136
+ * `file` is stored as `target`, `lines` as `line` (the graph-native keys
137
+ * `DATA_MODEL.md` §4 fixes). `revision` is always present (`null` when absent),
138
+ * so a stored citation node's shape does not vary by presence of the field.
139
+ */
140
+ export declare function citationNodeMetadata(citation: ICitation, sha: string, at: string): Record<string, unknown>;
141
+ /**
142
+ * Decode a `citation` node back into the contract + the server fields — the ONE
143
+ * reader of the persisted citation encoding. Every field the write side
144
+ * persists round-trips: `file`↔`target`, `lines`↔`line`, `context`↔`content`,
145
+ * `symbol`, `blastRadius`, `revision`.
146
+ *
147
+ * Defensive on a malformed/legacy row (mirrors the mapping `query/card.ts`
148
+ * previously hand-rolled, verbatim): a missing `sha` degrades to the
149
+ * `"unverified"` sentinel (never a fabricated hash), and a missing `at` to the
150
+ * node's `t_created`. A malformed `meta` never throws — the caller gets a
151
+ * best-effort projection, never a crash.
152
+ */
153
+ export declare function citationFromNode(node: ICitationNodeView): ICitationRecord;
154
+ /**
155
+ * The identity used to DIFF a desired citation set against the live one
156
+ * (`update`'s citations diff): `file`, `lines`, AND `revision`. Deliberately
157
+ * excludes `sha`/`context`/`symbol`/`blastRadius` — the diff is add-or-remove
158
+ * on the citation's TARGET, never an in-place descriptive edit (a citation is
159
+ * content-addressed evidence; changing its prose is a new citation, so the old
160
+ * one is removed and the new one added).
161
+ *
162
+ * `revision` IS part of the identity, unlike those descriptive fields: two
163
+ * citations of the same `(file, lines)` resolved against DIFFERENT revisions
164
+ * are different evidence, so a desired set that changes only a citation's
165
+ * revision is a genuine remove+add, never a silent no-op.
166
+ *
167
+ * A `\u0000` separator makes the key unambiguous (`"a.ts" + "1"` can never
168
+ * collide with `"a.ts1" + ""`).
169
+ */
170
+ export declare function citationKey(citation: Pick<ICitation, 'file' | 'lines' | 'revision'>): string;
171
+ /**
172
+ * {@link citationKey} for a persisted metadata blob (a live citation node),
173
+ * reading the same `target`/`line`/`revision` ends
174
+ * {@link citationNodeMetadata} wrote.
175
+ */
176
+ export declare function citationKeyFromMetadata(metadata: Record<string, unknown> | undefined): string;
package/envelope.d.ts CHANGED
@@ -26,7 +26,7 @@
26
26
  * Each member names the error class(es) that produce it, so the derivation
27
27
  * rule in this file's header can be checked by reading rather than inferred.
28
28
  */
29
- export declare const BACKLOG_ERROR_CODES: readonly ["not_found", "item_not_found", "invalid_argument", "validation", "store_busy", "rag_not_configured", "conflict", "precondition_failed", "internal"];
29
+ export declare const BACKLOG_ERROR_CODES: readonly ["not_found", "item_not_found", "ambiguous_reference", "invalid_argument", "validation", "store_busy", "rag_not_configured", "conflict", "precondition_failed", "internal"];
30
30
  /** The closed union of envelope error codes. See {@link BACKLOG_ERROR_CODES}. */
31
31
  export type BacklogErrorCode = (typeof BACKLOG_ERROR_CODES)[number];
32
32
  /**
@@ -72,6 +72,26 @@ export interface IOutcomeError {
72
72
  message: string;
73
73
  details?: IOutcomeErrorDetails;
74
74
  }
75
+ /**
76
+ * How exact a labelled count is. `eq` — the value is the true count; `gte` —
77
+ * the value is a LOWER BOUND (the Elasticsearch `hits.total.relation`
78
+ * pattern): more rows exist than could be counted at the cost the caller's
79
+ * request allowed. A count whose exactness is unstated is the defect this
80
+ * names (DESIGN §2 Invariant 5).
81
+ */
82
+ export type CountRelation = 'eq' | 'gte';
83
+ /**
84
+ * A count labelled for what it counts, carrying its own exactness — the
85
+ * DESIGN §2 Invariant 5 primitive ("a count named for what it counts (with an
86
+ * exactness relation, or omitted)"). Kept as its own shape rather than
87
+ * flattened into {@link IQueryEnvelopeMeta} as a bare number so a consumer can
88
+ * always tell a lower bound from an exact total.
89
+ */
90
+ export interface ILabelledCount {
91
+ value: number;
92
+ /** How exact `value` is: `eq` exact, `gte` a lower bound. */
93
+ relation: CountRelation;
94
+ }
75
95
  /**
76
96
  * Pagination truth carried beside the data. `total` is the count BEFORE
77
97
  * `limit`/`offset`; `returned` is `data.length`. A silently-truncated list is
@@ -79,7 +99,7 @@ export interface IOutcomeError {
79
99
  * there really were.
80
100
  */
81
101
  export interface IQueryEnvelopeMeta {
82
- /** Matching rows before limit/offset — the TRUE count. */
102
+ /** Matching rows before limit/offset. Exact unless `total_relation` says otherwise (`gte` ⇒ a lower bound). */
83
103
  total: number;
84
104
  /** Rows actually in `data`. */
85
105
  returned: number;
@@ -90,6 +110,20 @@ export interface IQueryEnvelopeMeta {
90
110
  * own `limit`. A silent cap is forbidden — if it happens, it is stated here.
91
111
  */
92
112
  truncated?: boolean;
113
+ /**
114
+ * Exactness of `total`: `eq` (or absent) — exact; `gte` — a lower bound
115
+ * (a capped scan, or a page whose true total is unknowable at list cost).
116
+ */
117
+ total_relation?: CountRelation;
118
+ /**
119
+ * True iff more rows exist beyond this page. The preferred spelling for the
120
+ * item-list views (`ready`/`stale`/`similar`) where a true pre-limit `total`
121
+ * is unknowable at bounded cost — derived by fetching `limit + 1`, never
122
+ * fabricated.
123
+ */
124
+ has_more?: boolean;
125
+ /** Opaque continuation token for cursor-paged views that are not keyset-paged today. */
126
+ next_cursor?: string;
93
127
  }
94
128
  /** The success arm. `data` is always present (never `null` as a stand-in for "missing"). */
95
129
  export interface IOutcomeSuccess<T> {
package/index.d.ts CHANGED
@@ -1,8 +1,28 @@
1
- export { get, query, priorityMatrix, partOfRollup, openCurve, embeddingStatus, lookup, create, update, transition, claim, relate, move, upsertProject, upsertComponent, upsertLocation, rmLocation, delete, } from './api.js';
1
+ export { get, query, priorityMatrix, partOfRollup, openCurve, report, embeddingStatus, lookup, create, update, addCitation, removeCitation, transition, attest, recheck, obligate, unobligate, specAppend, specCheck, claim, relate, move, upsertProject, upsertComponent, upsertLocation, rmLocation, mergeProject, rmProject, delete, } from './api.js';
2
2
  export type { BacklogCtx, IEmbeddingStatusResult } from './api.js';
3
+ export type { IAddCitationInput, IAddCitationOutcome, IRemoveCitationInput, IRemoveCitationOutcome, } from './write/citation.js';
4
+ export type { ICitation, ICitationRecord } from './citation.js';
5
+ export type { IMergeProjectInput, IMergeProjectOutcome, IRmProjectInput, } from './write/merge-project.js';
6
+ export type { IAttestInput, IAttestOutcome, IAttestClaim, IAttestCheck, IAttestationAnchor, AttestRevisionRef, AttestationCheckState, IRecheckInput, IRecheckOutcome, } from './write/attestation.js';
7
+ export { assertValidPredicate, evaluatePredicate, } from './write/obligation.js';
8
+ export type { IObligationView } from './query/types.js';
9
+ export type { IObligationSeverity, IRelationDirection, IPredicate, IObligationAppliesTo, IObligationOverride, IObligateInput, IObligateOutcome, IUnobligateInput, IUnobligateOutcome, IPredicateResolver, } from './write/obligation.js';
10
+ export type { ISpecAnchor, ISpecRevisionMeta, ISpecAppendInput, ISpecAppendOutcome, ISpecPointer, } from './write/spec-revision.js';
11
+ export type { SpecFreshness, ISpecCheckInput, ISpecCheckOutcome, } from './query/spec-staleness.js';
12
+ export { planSpecRevisionReconcile, applySpecRevisionReconcile, } from './write/spec-revision.reconcile.js';
13
+ export type { ISpecReconcileStore, ISpecReconcileStamp, ISpecReconcileHead, ISpecReconcileReport, } from './write/spec-revision.reconcile.js';
3
14
  export * from './envelope.js';
4
- export { startBacklogServer, buildBacklogApigenPackage, resolveExpectedMcpToolNames, } from './server.js';
5
- export type { StartOpts } from './server.js';
15
+ export { createBacklogServer, startBacklogServer, buildBacklogApigenPackage, resolveExpectedMcpToolNames, describeBacklogSurface, assertSurfaceIsReal, } from './server.js';
16
+ export type { StartOpts, IBacklogServerHandle } from './server.js';
17
+ export { createLifecycle } from './lifecycle.js';
18
+ export type { IServiceFailure, IServiceLifecycle, IServiceReport, IServiceState, } from './lifecycle.js';
19
+ export { probeReadiness } from './readiness.js';
20
+ export type { IReadinessHandle, IReadinessResult, IReadinessTimer, } from './readiness.js';
21
+ export { fullJitterDelay, CircuitBreaker, withResilience, } from './retry-policy.js';
22
+ export type { IResiliencePolicy, IResilienceDeps, IBreakerState, } from './retry-policy.js';
23
+ export { resolveServiceConfig, assertMcpEntryValid, assertServerArtifact, isPathResolvableBin, SERVICE_CONFIG_KEYS, } from './service-config.js';
24
+ export type { IServiceConfig, IServiceTransport, IArtifactIdentity, IMcpServerEntry, } from './service-config.js';
25
+ export { UnknownConfigKeyError, NonAbsolutePathError, UnknownMcpConfigKeyError, ArtifactDriftError, ServiceNotReadyError, } from './service-errors.js';
6
26
  export { runBacklogCli, resolveCommandPrefix, prefixCommand, stripNamespaceFlag, } from './cli.js';
7
27
  export type { RunBacklogCliOpts } from './cli.js';
8
28
  export { buildSearchArgv, SEARCH_FLAGS, SEARCH_HELP, } from './search-shortcut.js';