@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.
- package/CHANGELOG.md +69 -0
- package/README.md +194 -39
- package/api.d.ts +87 -0
- package/api.ir.json +1 -1
- package/citation.d.ts +176 -0
- package/envelope.d.ts +36 -2
- package/index.d.ts +23 -3
- package/index.js +105 -57
- package/index.mjs +11450 -6758
- package/ir-artifact.d.ts +7 -3
- package/lifecycle.d.ts +49 -0
- package/package.json +5 -5
- package/query/canonical.d.ts +16 -0
- package/query/card.d.ts +116 -4
- package/query/get.d.ts +8 -1
- package/query/index.d.ts +1 -0
- package/query/query.d.ts +32 -22
- package/query/redirect.d.ts +30 -0
- package/query/resolve.d.ts +75 -0
- package/query/similar-clusters.d.ts +8 -0
- package/query/similarity-signals.d.ts +47 -0
- package/query/spec-staleness.d.ts +21 -0
- package/query/types.d.ts +249 -34
- package/query/verdict-core.d.ts +21 -0
- package/query/verdict.d.ts +22 -0
- package/query/views/catalog.d.ts +47 -0
- package/query/views/registry.d.ts +27 -7
- package/query/views/report.d.ts +49 -0
- package/query/views/semantic.d.ts +28 -5
- package/query/views/stats.d.ts +38 -2
- package/readiness.d.ts +29 -0
- package/retry-policy.d.ts +44 -0
- package/serve.d.ts +1 -1
- package/server.d.ts +71 -3
- package/service-config.d.ts +109 -0
- package/service-errors.d.ts +51 -0
- package/skill/SKILL.md +688 -81
- package/store/catalog-invariant-guard.d.ts +13 -7
- package/vocabulary.d.ts +48 -0
- package/write/anchor-check.d.ts +139 -0
- package/write/attestation.d.ts +64 -0
- package/write/catalog-merge.d.ts +15 -8
- package/write/catalog.d.ts +72 -2
- package/write/citation-path.d.ts +31 -0
- package/write/citation.d.ts +157 -0
- package/write/create-issue.d.ts +143 -29
- package/write/errors.d.ts +196 -1
- package/write/gate.d.ts +67 -0
- package/write/merge-project.d.ts +54 -0
- package/write/obligation.d.ts +133 -0
- package/write/relate.d.ts +1 -1
- package/write/revision.d.ts +27 -0
- package/write/similarity-scan.d.ts +84 -0
- package/write/spec-revision.d.ts +131 -0
- package/write/spec-revision.reconcile.d.ts +48 -0
- package/write/transition.d.ts +13 -2
- package/write/tx.d.ts +44 -2
- package/write/uid-prefix.d.ts +78 -0
- package/write/update.d.ts +23 -1
|
@@ -26,7 +26,7 @@ export type CatalogInvariantViolation = {
|
|
|
26
26
|
*/
|
|
27
27
|
export declare function renderCatalogInvariantViolations(violations: ReadonlyArray<CatalogInvariantViolation>): string;
|
|
28
28
|
/**
|
|
29
|
-
* The status/priority catalog violates an invariant this build's read layer
|
|
29
|
+
* The status/priority/kind catalog violates an invariant this build's read layer
|
|
30
30
|
* depends on. Carries the offending rows as structured fields so a caller can
|
|
31
31
|
* render them; the message itself names every row AND the repair.
|
|
32
32
|
*/
|
|
@@ -35,7 +35,7 @@ export declare class CatalogInvariantError extends Error {
|
|
|
35
35
|
constructor(violations: ReadonlyArray<CatalogInvariantViolation>);
|
|
36
36
|
}
|
|
37
37
|
/**
|
|
38
|
-
* Read every live status/priority row and return the invariant violations.
|
|
38
|
+
* Read every live status/priority/kind row and return the invariant violations.
|
|
39
39
|
* A pure read — it never writes, so it is safe against any store, including
|
|
40
40
|
* the live one.
|
|
41
41
|
*
|
|
@@ -46,17 +46,23 @@ export declare class CatalogInvariantError extends Error {
|
|
|
46
46
|
*/
|
|
47
47
|
export declare function inspectCatalogInvariants(adapter: StoreAdapter): Promise<CatalogInvariantViolation[]>;
|
|
48
48
|
/**
|
|
49
|
-
* Assert the store's status/priority catalog satisfies both invariants.
|
|
49
|
+
* Assert the store's status/priority/kind catalog satisfies both invariants.
|
|
50
50
|
*
|
|
51
51
|
* Passes (no throw) on an empty store, and on a catalog whose reserved
|
|
52
52
|
* terminal statuses are flagged and whose same-kind names are fold-unique.
|
|
53
53
|
* Throws {@link CatalogInvariantError}, naming every offending row and the
|
|
54
54
|
* repair that resolves it, otherwise.
|
|
55
55
|
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
56
|
+
* WHERE IT RUNS: the `store-check` CLI verb — a NAMED, non-zero check an
|
|
57
|
+
* operator runs deliberately — plus any caller that asserts deliberately via
|
|
58
|
+
* `IQueryStoreHandle.assertCatalogInvariants`. It is deliberately NOT run on
|
|
59
|
+
* the ordinary read path (`queryIssuesWithMeta`), on the write path (`api.ts`'s
|
|
60
|
+
* `writeHandle`), or at store open (`openGraphBacklogStore`): a violation must
|
|
61
|
+
* be detected loudly and REPORTED, never allowed to turn every read — or every
|
|
62
|
+
* unrelated write — into an outage.
|
|
63
|
+
*
|
|
64
|
+
* BOUNDED BY CONSTRUCTION: it must not scan the issue graph per call. It reads
|
|
65
|
+
* only the (small) status/priority/kind catalog — see
|
|
60
66
|
* {@link inspectCatalogInvariants}.
|
|
61
67
|
*/
|
|
62
68
|
export declare function assertCatalogInvariants(adapter: StoreAdapter): Promise<void>;
|
package/vocabulary.d.ts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vocabulary.ts — the ONE pinned list of the data verbs this package mounts
|
|
3
|
+
* (SPEC.md §6.7), plus nothing else.
|
|
4
|
+
*
|
|
5
|
+
* ## Why this is its own leaf module
|
|
6
|
+
*
|
|
7
|
+
* `BACKLOG_VERBS` is read by two callers that must never drift apart:
|
|
8
|
+
*
|
|
9
|
+
* - `server.ts` — the mount-time carve-out check and the four-transport
|
|
10
|
+
* surface projection; and
|
|
11
|
+
* - `query/views/catalog.ts` — the generated `verb` catalog, which must
|
|
12
|
+
* enumerate the SAME advertised surface a consumer reads.
|
|
13
|
+
*
|
|
14
|
+
* If `catalog.ts` imported `server.ts` for the list, the whole query layer
|
|
15
|
+
* would transitively load the server's fastify/MCP plugin graph (a runtime
|
|
16
|
+
* cycle `server → api → query → catalog → server`), which is both a startup
|
|
17
|
+
* cost and a needless coupling. Declaring the constant in a module with zero
|
|
18
|
+
* imports keeps `catalog.ts` on the leaf and lets `server.ts` re-export the
|
|
19
|
+
* identical binding, so there is still exactly ONE list.
|
|
20
|
+
*
|
|
21
|
+
* The comment body below is reproduced verbatim from `server.ts` (its former
|
|
22
|
+
* home) so the "why this list is pinned" rationale stays attached to the
|
|
23
|
+
* value rather than the file it happens to live in.
|
|
24
|
+
*/
|
|
25
|
+
/**
|
|
26
|
+
* SPEC.md §6.7 — the data verbs the whole surface consolidates onto:
|
|
27
|
+
* the nine issue verbs plus `lookup`, §3a's registry CRUD verbs, and the
|
|
28
|
+
* three §5 stats/rollup reads (`priority-matrix`/`part-of-rollup`/
|
|
29
|
+
* `open-curve`), mounted as `backlog_<verb>`. Pinned here, next to the
|
|
30
|
+
* carve-out it is the complement of, because it is the ONE list four separate
|
|
31
|
+
* surfaces are checked against: the three apigen mounts derive their names
|
|
32
|
+
* from the operation descriptors via `describeMountedSurface`, and `cli.ts`'s
|
|
33
|
+
* argv parser — which is deliberately NOT an apigen mount, because apigen's
|
|
34
|
+
* `parseArgs` cannot express the §2.1b positional form, projects `string[]`
|
|
35
|
+
* as a JSON-valued flag where §7.3 wants comma-separated, and only sets
|
|
36
|
+
* `process.exitCode` on a thrown `ApiError` (so an `ok:false` envelope would
|
|
37
|
+
* exit 0, contradicting `BACKLOG_EXIT_CODE`) — has to be checked against this
|
|
38
|
+
* list rather than derived from the mount.
|
|
39
|
+
*
|
|
40
|
+
* That asymmetry is exactly how a split brain starts, and this repo already
|
|
41
|
+
* has one open as BUG-BACKLOG-MCP-CLI-SPLIT-BRAIN-001. `server.verbs.spec.ts`
|
|
42
|
+
* asserts BOTH sides against this constant so a verb added to one surface and
|
|
43
|
+
* forgotten on the other fails a test instead of shipping.
|
|
44
|
+
*
|
|
45
|
+
* Order is the SPEC.md §4/§6 declaration order, not alphabetical; compare as
|
|
46
|
+
* sets.
|
|
47
|
+
*/
|
|
48
|
+
export declare const BACKLOG_VERBS: readonly string[];
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* anchor-check.ts — the cheap-first mechanical anchor ladder (C3, DESIGN §2
|
|
3
|
+
* Primitive 2).
|
|
4
|
+
*
|
|
5
|
+
* An attestation's `anchor` is a `locator + digest`. This module parses the
|
|
6
|
+
* closed locator grammar and resolves a `path:` anchor against the subject
|
|
7
|
+
* project's git work tree, in the cheapest useful order:
|
|
8
|
+
*
|
|
9
|
+
* 1. `existsAtHead` — `git cat-file -e HEAD:<relpath>` (exit 0 =
|
|
10
|
+
* present). No file read, no network, no agent.
|
|
11
|
+
* 2. `changedSinceFiling`— `git log --since=<t> -- <relpath>` non-empty.
|
|
12
|
+
* 3. full re-resolve — ONLY when `opts.full` is set (`recheck`, and the
|
|
13
|
+
* verdict's own rung 5): hash the HEAD blob and compare to the anchor's
|
|
14
|
+
* `digest`.
|
|
15
|
+
*
|
|
16
|
+
* Every outcome carries the rung that produced it (`method`), so `verified` /
|
|
17
|
+
* `stale` / `unknown` / `unverified` are EXPLICIT states with a `reason` —
|
|
18
|
+
* never an absent field, never a silent success.
|
|
19
|
+
*
|
|
20
|
+
* The whole module is pure with respect to the store (no writes); it shells to
|
|
21
|
+
* the local `git` CLI the repo already uses. A missing `git`, a non-repo root,
|
|
22
|
+
* or an unresolvable path degrades to `unknown`, never a thrown exception —
|
|
23
|
+
* `unknown` is a first-class value here (Wikidata deprecate-with-reason, C2PA
|
|
24
|
+
* claim-vs-assertion). `refuted` is deliberately absent: a mechanical anchor
|
|
25
|
+
* proves present/matching/stale/absent only, never "the claim is contradicted".
|
|
26
|
+
*/
|
|
27
|
+
/** The closed set of mechanical-check states. `refuted` is deliberately absent (see module header). */
|
|
28
|
+
export type AttestationCheckState = 'unverified' | 'verified' | 'stale' | 'unknown';
|
|
29
|
+
/**
|
|
30
|
+
* One rung-result of the anchor ladder. `method` names which rung actually ran
|
|
31
|
+
* (`'exists_at_head'` | `'changed_since'` | `'full_resolve'` | `'none'`), so a
|
|
32
|
+
* cheap pre-filter can be proven cheap (AC7) and a full re-resolve is visible.
|
|
33
|
+
*/
|
|
34
|
+
export interface IAttestCheck {
|
|
35
|
+
state: AttestationCheckState;
|
|
36
|
+
method: string;
|
|
37
|
+
checked_at: string;
|
|
38
|
+
checked_by: string;
|
|
39
|
+
reason?: string;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* An anchor is `locator + digest`. The locator grammar is closed:
|
|
43
|
+
* `path:<file>[:<line>]` | `url:<url>` | `query:<cql>` | `registry:<ref>` |
|
|
44
|
+
* `commit:<sha>` (C5: ancestry of the default branch).
|
|
45
|
+
* A bare hand-maintained `path:line` is INSUFFICIENT without a `digest` — the
|
|
46
|
+
* digest is the whole point of content-addressing the claim.
|
|
47
|
+
*/
|
|
48
|
+
export interface IAttestationAnchor {
|
|
49
|
+
locator: string;
|
|
50
|
+
digest: string;
|
|
51
|
+
}
|
|
52
|
+
/** The parsed form of a locator (one arm per grammar production). */
|
|
53
|
+
export type IParsedAnchor = {
|
|
54
|
+
scheme: 'path';
|
|
55
|
+
target: string;
|
|
56
|
+
line?: number;
|
|
57
|
+
} | {
|
|
58
|
+
scheme: 'url';
|
|
59
|
+
target: string;
|
|
60
|
+
} | {
|
|
61
|
+
scheme: 'query';
|
|
62
|
+
target: string;
|
|
63
|
+
} | {
|
|
64
|
+
scheme: 'registry';
|
|
65
|
+
target: string;
|
|
66
|
+
} | {
|
|
67
|
+
scheme: 'commit';
|
|
68
|
+
target: string;
|
|
69
|
+
} | {
|
|
70
|
+
scheme: 'revision';
|
|
71
|
+
target: string;
|
|
72
|
+
};
|
|
73
|
+
/**
|
|
74
|
+
* The closed set of locator SCHEMES the grammar names (C3 added
|
|
75
|
+
* `path|url|query|registry`; C5 adds `commit:<sha>`; C10 adds `revision:<uid>`).
|
|
76
|
+
* Kept as an exported alias so a consumer (the C5 gate) can branch on the
|
|
77
|
+
* scheme without re-listing it.
|
|
78
|
+
*/
|
|
79
|
+
export type AnchorLocatorKind = 'path' | 'url' | 'query' | 'registry' | 'commit' | 'revision';
|
|
80
|
+
/** Options for {@link checkAnchor}. */
|
|
81
|
+
export interface ICheckAnchorOptions {
|
|
82
|
+
/** The subject project's root (git work tree) — absent means `unknown`. */
|
|
83
|
+
root?: string;
|
|
84
|
+
/** ISO filing time for the changed-since rung. Absent skips rung 2. */
|
|
85
|
+
sinceISO?: string;
|
|
86
|
+
/** Run the full re-resolve (rung 3: hash HEAD content and compare to `digest`). */
|
|
87
|
+
full?: boolean;
|
|
88
|
+
now: string;
|
|
89
|
+
by: string;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Parse `locator` against the closed grammar, throwing
|
|
93
|
+
* {@link AnchorLocatorInvalidError} for anything outside it (a blank locator,
|
|
94
|
+
* an unknown scheme, an empty body). `path:` accepts an optional trailing
|
|
95
|
+
* `:<digits>` line number; every other scheme carries its body verbatim.
|
|
96
|
+
*/
|
|
97
|
+
export declare function parseAnchor(locator: string): IParsedAnchor;
|
|
98
|
+
/** Whether `root` is (inside) a git work tree — the precondition for rungs 1–3. */
|
|
99
|
+
export declare function isGitWorkTree(root: string): boolean;
|
|
100
|
+
/**
|
|
101
|
+
* Rung 1 — is `relpath` present at `HEAD`? Exit 0 = present; any other exit
|
|
102
|
+
* (missing object, not a repo) = not present. Cheap: no content is read.
|
|
103
|
+
*/
|
|
104
|
+
export declare function existsAtHead(root: string, relpath: string): boolean;
|
|
105
|
+
/**
|
|
106
|
+
* Rung 2 — did any commit touch `relpath` at/after `sinceISO`? `git log
|
|
107
|
+
* --since` compares against committer date, so this is a genuine "has the
|
|
108
|
+
* tracked file moved since we filed" probe with no content read.
|
|
109
|
+
*/
|
|
110
|
+
export declare function changedSinceFiling(root: string, relpath: string, sinceISO: string): boolean;
|
|
111
|
+
/** The mechanical check a `commit:` anchor names — the one string every refusal carries as `performed_check`. */
|
|
112
|
+
export declare const DEFAULT_BRANCH_ANCESTOR_CHECK: "default_branch_ancestor";
|
|
113
|
+
/** The result of the default-branch check: whether `sha` is an ancestor of the resolved default branch, and the named check that produced it. */
|
|
114
|
+
export interface IDefaultBranchCheck {
|
|
115
|
+
onDefaultBranch: boolean;
|
|
116
|
+
performed: string;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Is `<sha>` an ancestor of the repo's default branch? Shells
|
|
120
|
+
* `git merge-base --is-ancestor <sha> <default>`, exactly as C3's anchor ladder
|
|
121
|
+
* shells `git cat-file`/`git log`. Returns `{onDefaultBranch:false,
|
|
122
|
+
* performed:'default_branch_ancestor'}` when the repo or the branch cannot be
|
|
123
|
+
* resolved (fail-closed, never a silent pass) — the `performed` field is
|
|
124
|
+
* present in every outcome so the caller can name the mechanical check.
|
|
125
|
+
*/
|
|
126
|
+
export declare function isShaOnDefaultBranch(repoRoot: string, sha: string, defaultBranch?: string): Promise<IDefaultBranchCheck>;
|
|
127
|
+
/**
|
|
128
|
+
* Run the cheap-first ladder against `anchor` and return the rung-result.
|
|
129
|
+
*
|
|
130
|
+
* A non-`path` locator (`url:`/`query:`/`registry:`) has no mechanical checker
|
|
131
|
+
* wired, so it is explicitly `unverified` — never an absent field. A `path:`
|
|
132
|
+
* anchor with no resolvable root, or a root that is not a git work tree, is
|
|
133
|
+
* `unknown` (a genuine "could not determine", distinct from "gone").
|
|
134
|
+
*
|
|
135
|
+
* Throws {@link AnchorLocatorInvalidError} (a caller-input mistake) when the
|
|
136
|
+
* locator is outside the closed grammar; every other failure is a reported
|
|
137
|
+
* state, not a throw.
|
|
138
|
+
*/
|
|
139
|
+
export declare function checkAnchor(anchor: IAttestationAnchor, opts: ICheckAnchorOptions): IAttestCheck;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { IWriteStoreHandle } from './tx.js';
|
|
2
|
+
import { AttestationCheckState, IAttestCheck, IAttestationAnchor } from './anchor-check.js';
|
|
3
|
+
|
|
4
|
+
export type { AttestationCheckState, IAttestCheck, IAttestationAnchor };
|
|
5
|
+
/**
|
|
6
|
+
* An issue revision reference: the numeric monotonic counter, or — for C10's
|
|
7
|
+
* `SPEC`-node annotations — an opaque `sha256:<hex>` token. Additive only: an
|
|
8
|
+
* `issue` subject with a numeric revision is byte-for-byte unchanged.
|
|
9
|
+
*/
|
|
10
|
+
export type AttestRevisionRef = number | string;
|
|
11
|
+
/** The claim an attestation asserts. `kind` is open vocabulary (e.g. `'published-artifact'`, `'live-system'`); `body` is free text. */
|
|
12
|
+
export interface IAttestClaim {
|
|
13
|
+
kind: string;
|
|
14
|
+
body?: string;
|
|
15
|
+
}
|
|
16
|
+
export interface IAttestInput {
|
|
17
|
+
/** The LOGICAL subject: chain-head `uid` + the content `revision` observed. */
|
|
18
|
+
subject: {
|
|
19
|
+
id: string;
|
|
20
|
+
revision: AttestRevisionRef;
|
|
21
|
+
};
|
|
22
|
+
claim: IAttestClaim;
|
|
23
|
+
anchor: IAttestationAnchor;
|
|
24
|
+
by: string;
|
|
25
|
+
}
|
|
26
|
+
export interface IAttestOutcome {
|
|
27
|
+
attestationUid: string;
|
|
28
|
+
subject: {
|
|
29
|
+
id: string;
|
|
30
|
+
revision: AttestRevisionRef;
|
|
31
|
+
};
|
|
32
|
+
check: IAttestCheck;
|
|
33
|
+
}
|
|
34
|
+
export interface IRecheckInput {
|
|
35
|
+
attestationUid: string;
|
|
36
|
+
by: string;
|
|
37
|
+
}
|
|
38
|
+
export interface IRecheckOutcome {
|
|
39
|
+
attestationUid: string;
|
|
40
|
+
checks: IAttestCheck[];
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Create an attestation — a new `attestation` node + `attests` edge against
|
|
44
|
+
* the LIVE subject issue, plus one `audit` row. The subject node is NEVER
|
|
45
|
+
* mutated (no `UPDATE node … WHERE rowid = subject`).
|
|
46
|
+
*
|
|
47
|
+
* Errors: `InvalidArgumentError` (blank `subject.id`/`claim.kind`/`by`, an
|
|
48
|
+
* absent `subject.revision`), `AnchorLocatorInvalidError` (a locator outside
|
|
49
|
+
* the closed grammar, or a blank `anchor.digest`),
|
|
50
|
+
* `StaleSupersedeError`/`IssueNotFoundError` (the subject uid is superseded or
|
|
51
|
+
* unknown), `WriteContentionError`/`WriteIOError` (an exhausted driver-level
|
|
52
|
+
* retry on the underlying `immediate` transaction).
|
|
53
|
+
*/
|
|
54
|
+
export declare function attest(handle: IWriteStoreHandle, input: IAttestInput): Promise<IAttestOutcome>;
|
|
55
|
+
/**
|
|
56
|
+
* Re-run the anchor ladder against an existing attestation and APPEND the new
|
|
57
|
+
* check to `checks[]` (earlier entries copied forward verbatim — never a
|
|
58
|
+
* truncated history). Replaces the echoed `check` with the newest entry and
|
|
59
|
+
* writes one `audit` row on the attestation node.
|
|
60
|
+
*
|
|
61
|
+
* Errors: `InvalidArgumentError` (blank `by`), `AttestationNotFoundError` (no
|
|
62
|
+
* live `attestation` node carries the uid).
|
|
63
|
+
*/
|
|
64
|
+
export declare function recheck(handle: IWriteStoreHandle, input: IRecheckInput): Promise<IRecheckOutcome>;
|
package/write/catalog-merge.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { IWriteStoreHandle } from './tx.js';
|
|
2
2
|
import { NodeRecord } from '@adhd/sox-graph-store';
|
|
3
3
|
|
|
4
|
-
/** The
|
|
5
|
-
export type CatalogKind = 'status' | 'priority';
|
|
4
|
+
/** The catalog kinds this repair collapses (D3's scope, widened to `kind` by C8). */
|
|
5
|
+
export type CatalogKind = 'status' | 'priority' | 'kind';
|
|
6
6
|
/**
|
|
7
7
|
* A status fold group that CANNOT be safely collapsed: two or more LIVE rows
|
|
8
8
|
* share a fold, yet none carries the write path's lowercase spelling. Merging
|
|
@@ -75,16 +75,23 @@ export interface IMergeJournal {
|
|
|
75
75
|
*
|
|
76
76
|
* Grouping is by {@link catalogNameFold} alone. Within a fold group the
|
|
77
77
|
* canonical is the member already carrying the write path's spelling for that
|
|
78
|
-
* kind — lowercase for `status`, uppercase for `priority
|
|
78
|
+
* kind — lowercase for `status`, uppercase for `priority`, lowercase for the
|
|
79
|
+
* OPEN `kind` vocabulary (its canonical rule).
|
|
79
80
|
*
|
|
80
81
|
* A `priority` group with no upper-spelled member falls back to its
|
|
81
82
|
* lowest-rowid member (deterministically renamed to uppercase at apply, as
|
|
82
|
-
* before). A `status` group with no lower-spelled member is NOT
|
|
83
|
-
* any canonical would carry a spelling the write path
|
|
84
|
-
* would regenerate the fragment on the
|
|
85
|
-
* in `unmergeable` instead.
|
|
83
|
+
* before). A `status` OR `kind` group with no lower-spelled member is NOT
|
|
84
|
+
* planned at all: any canonical would carry a spelling the write path / fold
|
|
85
|
+
* lookup would not re-find, so merging would regenerate the fragment on the
|
|
86
|
+
* next ordinary `create`. It is surfaced in `unmergeable` instead.
|
|
87
|
+
*
|
|
88
|
+
* `liveKinds` is OPTIONAL and ADDITIVE (C8): existing two-argument callers
|
|
89
|
+
* keep their exact behavior, and a caller that wants the `kind` repair passes
|
|
90
|
+
* the live `kind` rows. (A kind cannot be planned without its rows entering
|
|
91
|
+
* somewhere; the spec's "unchanged signature" is honoured as "unchanged for
|
|
92
|
+
* every existing caller".)
|
|
86
93
|
*/
|
|
87
|
-
export declare function planCaseFragmentMerge(liveStatuses: readonly NodeRecord[], livePriorities: readonly NodeRecord[]): IMergePlan;
|
|
94
|
+
export declare function planCaseFragmentMerge(liveStatuses: readonly NodeRecord[], livePriorities: readonly NodeRecord[], liveKinds?: readonly NodeRecord[]): IMergePlan;
|
|
88
95
|
/**
|
|
89
96
|
* Apply the plan in ONE `executeWriteTransaction` (`BEGIN IMMEDIATE` + bounded
|
|
90
97
|
* busy-only retry, §4c) — every group in the plan commits together or not at
|
package/write/catalog.d.ts
CHANGED
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
import { IComponentSummary, ILocationSummary, ILocationType, IProjectSummary } from '../query/types.js';
|
|
2
2
|
import { IEdgeKindRule, IWriteStoreHandle } from './tx.js';
|
|
3
|
+
import { isUidShaped } from './uid-prefix.js';
|
|
3
4
|
import { AdapterTransaction } from '@adhd/sox-store-adapter';
|
|
4
5
|
|
|
5
|
-
/**
|
|
6
|
-
|
|
6
|
+
/**
|
|
7
|
+
* Disambiguation by SHAPE, not a second field (§6.1): a 36-character
|
|
8
|
+
* version-4-UUID-formatted string is a `uid`; anything else is a `name`. The
|
|
9
|
+
* single definition lives in `write/uid-prefix.ts` (which also owns prefix
|
|
10
|
+
* classification); re-exported here so every existing `isUidShaped` importer
|
|
11
|
+
* keeps its path unchanged.
|
|
12
|
+
*/
|
|
13
|
+
export { isUidShaped };
|
|
7
14
|
export interface IResolvedCatalogRow {
|
|
8
15
|
rowid: number;
|
|
9
16
|
uid: string;
|
|
@@ -55,6 +62,16 @@ export interface IMintOrResolveInput {
|
|
|
55
62
|
* of any one issue's logical write, so they keep their own clock.
|
|
56
63
|
*/
|
|
57
64
|
at?: string;
|
|
65
|
+
/**
|
|
66
|
+
* A DEPRECATED catalog name
|
|
67
|
+
* (`meta.lifecycle === 'deprecated'`, or a `kind` in the frozen
|
|
68
|
+
* {@link DEPRECATED_KIND_NAMES} set) is REFUSED on mint/resolve unless this
|
|
69
|
+
* is `true` — a typed caller decision, never an env var. Refusal throws
|
|
70
|
+
* `InvalidArgumentError('kind', …)` naming `meta.replacedBy` (or the in-code
|
|
71
|
+
* {@link DEPRECATED_KIND_REPLACEMENTS} fallback), so the caller is told the
|
|
72
|
+
* term to use instead. Only `kind` currently has a deprecated vocabulary.
|
|
73
|
+
*/
|
|
74
|
+
allowDeprecated?: boolean;
|
|
58
75
|
}
|
|
59
76
|
/**
|
|
60
77
|
* The reserved TERMINAL status vocabulary — the ONE in-code definition
|
|
@@ -87,6 +104,29 @@ export interface IMintOrResolveInput {
|
|
|
87
104
|
export declare const RESERVED_TERMINAL_STATUS_NAMES: ReadonlySet<string>;
|
|
88
105
|
/** Whether `name` is one of {@link RESERVED_TERMINAL_STATUS_NAMES} under the case fold — so any spelling of the reserved terminal vocabulary (`closed`/`Closed`/`CLOSED`, `fixed`/`FIXED`) counts. */
|
|
89
106
|
export declare function isReservedTerminalStatusName(name: string): boolean;
|
|
107
|
+
/**
|
|
108
|
+
* The RETIRED `kind` vocabulary — the borrowed terms the C8 spec retires with
|
|
109
|
+
* a replacement, modelled on {@link RESERVED_TERMINAL_STATUS_NAMES}: a frozen
|
|
110
|
+
* in-code set, so a retired term is refused on mint even before (or without) a
|
|
111
|
+
* row-level `meta.lifecycle:'deprecated'` data change. Membership is decided on
|
|
112
|
+
* the FOLDED name ({@link catalogNameFold}), so `EPIC`/`epic` are one term.
|
|
113
|
+
*
|
|
114
|
+
* `EPIC` is the one entry: it is a borrowed Jira primitive re-expressed by the
|
|
115
|
+
* existing `FEAT` kind (DESIGN §2 Invariant 6 / §6 "re-express in place, never
|
|
116
|
+
* re-key"). The replacement lives in {@link DEPRECATED_KIND_REPLACEMENTS}.
|
|
117
|
+
*/
|
|
118
|
+
export declare const DEPRECATED_KIND_NAMES: ReadonlySet<string>;
|
|
119
|
+
/**
|
|
120
|
+
* The term to use instead of each {@link DEPRECATED_KIND_NAMES} entry. Kept
|
|
121
|
+
* separate from the name set so a row's live `meta.replacedBy` (a reviewed
|
|
122
|
+
* repair's own decision) is preferred when present, with this map as the
|
|
123
|
+
* in-code fallback the error and the generated catalog both name.
|
|
124
|
+
*/
|
|
125
|
+
export declare const DEPRECATED_KIND_REPLACEMENTS: ReadonlyMap<string, string>;
|
|
126
|
+
/** Whether `name` is a RETIRED `kind` term under the case fold — `EPIC`/`epic` both count. */
|
|
127
|
+
export declare function isDeprecatedKindName(name: string): boolean;
|
|
128
|
+
/** The in-code replacement for a deprecated `kind` name, or `undefined` when it is not one. */
|
|
129
|
+
export declare function deprecatedKindReplacement(name: string): string | undefined;
|
|
90
130
|
/**
|
|
91
131
|
* The flat-catalog find-then-create (§1, §4c, §6.1): `kind`/`status`/
|
|
92
132
|
* `priority`/`agent` are mintable on an unresolved NAME; a uid-shaped `ref`
|
|
@@ -219,7 +259,30 @@ export interface IProjectPolicy {
|
|
|
219
259
|
readonly allowedKinds: readonly string[];
|
|
220
260
|
/** `project_field_requirement` — field names required on every mutating write for this project (§2). */
|
|
221
261
|
readonly requiredFields: readonly string[];
|
|
262
|
+
/**
|
|
263
|
+
* C9 — how wide the CREATE-TIME advisory similarity scan looks. `'same-project'`
|
|
264
|
+
* (the default) is byte-for-byte today's behaviour (AC1); `'multi-project'`
|
|
265
|
+
* adds sibling projects reachable via a shared `repoUrl`/`component.meta.path`;
|
|
266
|
+
* `'store-wide'` drops the id restriction entirely. This NEVER widens the
|
|
267
|
+
* WRITE path — the scan is advisory and writes nothing (AC3) — it only widens
|
|
268
|
+
* which existing items may be surfaced as similar candidates.
|
|
269
|
+
*/
|
|
270
|
+
readonly similarityScope: ISimilarityScope;
|
|
271
|
+
/**
|
|
272
|
+
* C9 — cosine threshold for CROSS-project candidates. Deliberately a DISTINCT
|
|
273
|
+
* value from `dedupeThreshold` (which stays calibrated for same-project
|
|
274
|
+
* byte-identical refiles): sharing one number either re-suppresses legitimate
|
|
275
|
+
* cross-repo filings or admits boilerplate (AC7/AC8). Enforced distinct by
|
|
276
|
+
* test, not by a runtime assertion.
|
|
277
|
+
*/
|
|
278
|
+
readonly similarityCrossProjectThreshold: number;
|
|
279
|
+
/** C9 — minimum top-vs-next cosine gap for a cross-project candidate (margin guard). A candidate that is not meaningfully more similar than the runner-up is ambiguous and is not surfaced. */
|
|
280
|
+
readonly similarityCrossProjectMargin: number;
|
|
281
|
+
/** C9 — minimum title-token Jaccard overlap required as the second independent signal for a cross-project candidate (AC7). Cosine alone is never sufficient cross-project. */
|
|
282
|
+
readonly similarityCrossProjectTokenOverlap: number;
|
|
222
283
|
}
|
|
284
|
+
/** C9 — the typed scan breadth for the create-time advisory similarity scan. */
|
|
285
|
+
export type ISimilarityScope = 'same-project' | 'multi-project' | 'store-wide';
|
|
223
286
|
export declare function resolveProjectPolicy(project: IResolvedProjectRow): IProjectPolicy;
|
|
224
287
|
/**
|
|
225
288
|
* Whether a resolved project has a known filesystem `path` (§8.4/§8.5) — the
|
|
@@ -349,6 +412,13 @@ export declare function upsertComponent(handle: IWriteStoreHandle, input: IUpser
|
|
|
349
412
|
* runs before opening its transaction.
|
|
350
413
|
*/
|
|
351
414
|
export declare function upsertComponentTx(tx: AdapterTransaction, handle: Pick<IWriteStoreHandle, 'typePolicy'>, input: IUpsertComponentInput): Promise<IUpsertComponentOutcome>;
|
|
415
|
+
/**
|
|
416
|
+
* The closed `location_type` vocabulary (§3, §3a). The ONE in-code definition:
|
|
417
|
+
* `upsertLocation` validates against it, and `query/views/catalog.ts`'s
|
|
418
|
+
* generated `location_type` catalog projects from it. Exported (rather than a
|
|
419
|
+
* private const) so the catalog cannot become a second, hand-maintained copy.
|
|
420
|
+
*/
|
|
421
|
+
export declare const VALID_LOCATION_TYPES: readonly ILocationType[];
|
|
352
422
|
export interface IUpsertLocationInput {
|
|
353
423
|
/**
|
|
354
424
|
* `component` reference — `uid` or `name` (§6.1's disambiguation-by-shape
|
package/write/citation-path.d.ts
CHANGED
|
@@ -131,3 +131,34 @@ export interface IResolvedCitationTarget {
|
|
|
131
131
|
* candidate).
|
|
132
132
|
*/
|
|
133
133
|
export declare function resolveCitationTarget(projectRoot: string, file: string, allowedRoots: readonly string[]): Promise<IResolvedCitationTarget>;
|
|
134
|
+
/**
|
|
135
|
+
* The TOOL's OWN installed evidence roots — where this package installs its
|
|
136
|
+
* skill (`install-skill.ts`'s host table: `.claude/skills/backlog`,
|
|
137
|
+
* `$CODEX_HOME/skills/backlog`, `~/.config/opencode/skills/backlog`).
|
|
138
|
+
*
|
|
139
|
+
* These are citable by DEFAULT, and deliberately NARROWER than the
|
|
140
|
+
* machine-global `~/.adhd/backlog` store home this module's header rejects:
|
|
141
|
+
* they grant only the tool's own installed docs (a stable, versioned,
|
|
142
|
+
* human-authored evidence tree), never the store. Typed and always-on, so a
|
|
143
|
+
* project does not have to allowlist the tool it is using in order to cite
|
|
144
|
+
* the tool's own documentation.
|
|
145
|
+
*
|
|
146
|
+
* `home` is injectable for tests; it defaults to the real home directory.
|
|
147
|
+
*/
|
|
148
|
+
export declare function toolOwnedCitationRoots(home?: string): string[];
|
|
149
|
+
/** The minimal read-only executor {@link resolveSiblingProjectRootsTx} needs — satisfied structurally by `AdapterTransaction` and the bare `StoreAdapter`. */
|
|
150
|
+
export interface ISiblingRootExecutor {
|
|
151
|
+
executeAll<T = Record<string, unknown>>(sql: string, args?: unknown[]): Promise<{
|
|
152
|
+
rows: T[];
|
|
153
|
+
}>;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* The `metadata.path` of every LIVE `project` row EXCEPT `excludeProjectUid`.
|
|
157
|
+
*
|
|
158
|
+
* A citation into a *sibling registered project* must be probed against that
|
|
159
|
+
* project's OWN root, not the citing item's — otherwise a legitimate
|
|
160
|
+
* cross-repo citation falsely resolves to `unverified` and the write is
|
|
161
|
+
* refused (AC4). Path-less sibling projects contribute nothing (there is no
|
|
162
|
+
* root to check against).
|
|
163
|
+
*/
|
|
164
|
+
export declare function resolveSiblingProjectRootsTx(exec: ISiblingRootExecutor, excludeProjectUid: string): Promise<string[]>;
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { IWriteStoreHandle } from './tx.js';
|
|
2
|
+
import { IProjectPolicy, IResolvedProjectRow } from './catalog.js';
|
|
3
|
+
import { ICitation, ICitationRecord } from '../citation.js';
|
|
4
|
+
import { AdapterTransaction } from '@adhd/sox-store-adapter';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* §8.5's two-branch citation-sha rule, in ONE place (the generalization of the
|
|
8
|
+
* copy `create-issue.ts`/`transition.ts` each used to carry).
|
|
9
|
+
*
|
|
10
|
+
* Branch 1: a PATH-LESS project cannot content-address anything, so every
|
|
11
|
+
* citation degrades to the `'unverified'` sentinel up front.
|
|
12
|
+
*
|
|
13
|
+
* Branch 2a (revision-pinned): when `revision` is given, the target is resolved
|
|
14
|
+
* against the git revision (`git show <revision>:<relpath>`) rather than the
|
|
15
|
+
* working tree — so a file that exists only on an unmerged branch is citable.
|
|
16
|
+
* The read is confined to the project's own git object database (git refuses a
|
|
17
|
+
* `..` path), so no filesystem containment check is needed for it.
|
|
18
|
+
*
|
|
19
|
+
* Branch 2b (working tree): the target must resolve (canonically) within the
|
|
20
|
+
* project root OR within one of `allowedExternalRoots` —
|
|
21
|
+
* `citation-path.ts`'s {@link resolveCitationTarget}. The only filesystem read
|
|
22
|
+
* happens after acceptance.
|
|
23
|
+
*
|
|
24
|
+
* §4c's error taxonomy is preserved exactly: ENOENT/ENOTDIR → `'unverified'`
|
|
25
|
+
* (the file genuinely is not there); EISDIR → `CitationTargetIsDirectoryError`;
|
|
26
|
+
* any other errno → `WriteIOError` (`citationReadError`).
|
|
27
|
+
*/
|
|
28
|
+
export declare function computeCitationSha(project: IResolvedProjectRow, file: string, revision: string | undefined, allowedExternalRoots: readonly string[], siblingRoots?: readonly string[]): Promise<string>;
|
|
29
|
+
/**
|
|
30
|
+
* Compute the sha for every citation in `citations`, in caller order — NO
|
|
31
|
+
* policy gate (see {@link assertCitationShasVerifiable}). This is the
|
|
32
|
+
* filesystem/git half of the citation-sha pre-resolve, callable on its own by a
|
|
33
|
+
* caller (`update`'s diff-emitter) that must defer the gate until it knows
|
|
34
|
+
* which citations are actually being ADDED.
|
|
35
|
+
*/
|
|
36
|
+
export declare function computeCitationShas(project: IResolvedProjectRow, citations: readonly ICitation[], allowedExternalRoots: readonly string[], siblingRoots?: readonly string[]): Promise<string[]>;
|
|
37
|
+
/**
|
|
38
|
+
* Enforce `project_policy.citationRequiresSha` over an already-computed sha
|
|
39
|
+
* list, paired index-for-index with `citations`. Only where verification is
|
|
40
|
+
* POSSIBLE (the project has a known `path`) is a `"unverified"` sha a hard
|
|
41
|
+
* `CitationUnverifiableError` naming the allowed roots; a path-less project
|
|
42
|
+
* records `sha:"unverified"` verbatim, with the deliberate waiver logged (DEBT
|
|
43
|
+
* a934e089) rather than silently applied. `verb` names the caller in that log.
|
|
44
|
+
*
|
|
45
|
+
* Split from {@link computeCitationShas} so `update`'s diff-emitter can compute
|
|
46
|
+
* shas for its whole desired set but gate ONLY the citations it actually adds —
|
|
47
|
+
* so an issue holding a citation whose file has since vanished can still be
|
|
48
|
+
* updated (that already-live citation is neither re-added nor re-gated; only a
|
|
49
|
+
* genuinely new, unverifiable citation is refused).
|
|
50
|
+
*/
|
|
51
|
+
export declare function assertCitationShasVerifiable(project: IResolvedProjectRow, policy: IProjectPolicy, citations: readonly ICitation[], shas: readonly string[], verb: string): void;
|
|
52
|
+
/**
|
|
53
|
+
* Compute AND policy-gate the sha for every citation in `citations`, in caller
|
|
54
|
+
* order — the ONE implementation `createIssue`/`transition`'s pre-transaction
|
|
55
|
+
* citation loop and `addCitation`'s single-citation resolve share. Composes
|
|
56
|
+
* {@link computeCitationShas} + {@link assertCitationShasVerifiable}.
|
|
57
|
+
*/
|
|
58
|
+
export declare function resolveCitationShas(project: IResolvedProjectRow, policy: IProjectPolicy, citations: readonly ICitation[], siblingRoots: readonly string[], verb: string): Promise<string[]>;
|
|
59
|
+
/** Mint ONE `citation` node + its `has_citation` edge against the issue, inside the caller's open `tx`. NEVER writes an audit row — the calling verb owns the ONE audit its §4a contract requires. */
|
|
60
|
+
export declare function appendCitationTx(tx: AdapterTransaction, handle: IWriteStoreHandle, params: {
|
|
61
|
+
issueRowid: number;
|
|
62
|
+
issueUid: string;
|
|
63
|
+
citation: ICitation;
|
|
64
|
+
sha: string;
|
|
65
|
+
at: string;
|
|
66
|
+
}): Promise<{
|
|
67
|
+
rowid: number;
|
|
68
|
+
uid: string;
|
|
69
|
+
}>;
|
|
70
|
+
/** A live citation attached to an issue — just the identity + diff key the diff-emitter needs. */
|
|
71
|
+
export interface ILiveCitationRow {
|
|
72
|
+
rowid: number;
|
|
73
|
+
uid: string;
|
|
74
|
+
/** {@link citationKey}-shaped (`file` + `lines`), read off the persisted `target`/`line`. */
|
|
75
|
+
key: string;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* The LIVE citations currently attached to `issueRowid`, in edge order — the
|
|
79
|
+
* "live set" `update`'s diff-emitter compares a desired set against. A live
|
|
80
|
+
* `has_citation` edge whose target node is missing or invalidated is skipped
|
|
81
|
+
* defensively (the invariant is that the two are invalidated together, so this
|
|
82
|
+
* should never fire).
|
|
83
|
+
*/
|
|
84
|
+
export declare function readLiveCitationsTx(tx: AdapterTransaction, issueRowid: number): Promise<ILiveCitationRow[]>;
|
|
85
|
+
/**
|
|
86
|
+
* Bi-temporally invalidate ONE citation: its node (`t_invalid` + a merged
|
|
87
|
+
* `meta.invalidatedReason`/`invalidatedAt`, never a wholesale replace — the
|
|
88
|
+
* `rmLocation`/`delete` shape) AND its owning `has_citation` edge. Hand-
|
|
89
|
+
* composed against `tx`.
|
|
90
|
+
*
|
|
91
|
+
* Never writes an audit row — the calling verb owns it (so `update` emits its
|
|
92
|
+
* single `'updated'` audit for a whole diff rather than one per citation).
|
|
93
|
+
*/
|
|
94
|
+
export declare function removeCitationTx(tx: AdapterTransaction, params: {
|
|
95
|
+
citationRowid: number;
|
|
96
|
+
citationUid: string;
|
|
97
|
+
at: string;
|
|
98
|
+
reason?: string;
|
|
99
|
+
}): Promise<void>;
|
|
100
|
+
export interface IAddCitationInput {
|
|
101
|
+
/** The `issue` uid the citation is attached to. */
|
|
102
|
+
uid: string;
|
|
103
|
+
/** The citation to add — the SAME {@link ICitation} contract `create`/`transition` accept, including the optional `revision`. */
|
|
104
|
+
citation: ICitation;
|
|
105
|
+
/** The acting identity (§6.3's opening rule). REQUIRED. */
|
|
106
|
+
by: string;
|
|
107
|
+
}
|
|
108
|
+
export interface IAddCitationOutcome {
|
|
109
|
+
/** The minted `citation` node's own uid — the identity `removeCitation` addresses. */
|
|
110
|
+
uid: string;
|
|
111
|
+
/** The issue the citation was attached to (unchanged). */
|
|
112
|
+
issueUid: string;
|
|
113
|
+
/** The minted citation, projected (the read shape). */
|
|
114
|
+
citation: ICitationRecord;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Add ONE citation to an existing issue (§6.3, §4). One `immediate`
|
|
118
|
+
* transaction: resolve `uid` → live `issue` → mint the `citation` node + its
|
|
119
|
+
* `has_citation` edge → `writeAudit`, all against the SAME `tx` (never the
|
|
120
|
+
* bare-adapter `writeNode`/`writeEdge`, §4c). The cited file's sha is computed
|
|
121
|
+
* BEFORE the transaction opens, exactly as `create`/`transition` do, so the
|
|
122
|
+
* write lock is never held across a filesystem/git read.
|
|
123
|
+
*
|
|
124
|
+
* Errors: `InvalidArgumentError` (blank `uid`/`by`/`citation.file`),
|
|
125
|
+
* `IssueNotFoundError` (no live `issue` carries `uid`), `StaleSupersedeError`
|
|
126
|
+
* (`uid` names a superseded issue), `CitationUnverifiableError` (the target did
|
|
127
|
+
* not resolve to a real sha and the owning project requires one — including a
|
|
128
|
+
* `revision` that does not resolve), `WriteContentionError`/`WriteIOError`
|
|
129
|
+
* (§4c).
|
|
130
|
+
*/
|
|
131
|
+
export declare function addCitation(handle: IWriteStoreHandle, input: IAddCitationInput): Promise<IAddCitationOutcome>;
|
|
132
|
+
export interface IRemoveCitationInput {
|
|
133
|
+
/** The `citation` uid to soft-remove — the citation's OWN uid, never a `(target,line)` re-specification. */
|
|
134
|
+
uid: string;
|
|
135
|
+
/** The acting identity (§6.3's opening rule). REQUIRED. */
|
|
136
|
+
by: string;
|
|
137
|
+
/** Optional explanation recorded on the invalidation and the audit row (mirrors `rmLocation`'s `reason`). */
|
|
138
|
+
reason?: string;
|
|
139
|
+
}
|
|
140
|
+
export interface IRemoveCitationOutcome {
|
|
141
|
+
uid: string;
|
|
142
|
+
invalidated: true;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Soft-remove ONE citation by its own `uid` (§6.3, §4). One `immediate`
|
|
146
|
+
* transaction: resolve `uid` → LIVE `citation` node (`resolveCitationNodeTx`,
|
|
147
|
+
* never a bare `getNodeByUid`) → bi-temporally invalidate the node AND its
|
|
148
|
+
* `has_citation` edge ({@link removeCitationTx}) → `writeAudit`, all against the
|
|
149
|
+
* SAME `tx`. The citation's ISSUE is untouched: its uid is preserved and no
|
|
150
|
+
* node is superseded.
|
|
151
|
+
*
|
|
152
|
+
* Errors: `InvalidArgumentError` (blank `uid`/`by`), `CitationNotFoundError`
|
|
153
|
+
* (no LIVE `citation` node carries `uid` — including an already-removed uid, or
|
|
154
|
+
* a uid that names a node of a different kind, the "foreign citation" refusal),
|
|
155
|
+
* `WriteContentionError`/`WriteIOError` (§4c).
|
|
156
|
+
*/
|
|
157
|
+
export declare function removeCitation(handle: IWriteStoreHandle, input: IRemoveCitationInput): Promise<IRemoveCitationOutcome>;
|