@descryy/ir 0.1.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/LICENSE +21 -0
- package/dist/capabilities.d.ts +83 -0
- package/dist/capabilities.d.ts.map +1 -0
- package/dist/capabilities.js +91 -0
- package/dist/capabilities.js.map +1 -0
- package/dist/conformance/bind.d.ts +82 -0
- package/dist/conformance/bind.d.ts.map +1 -0
- package/dist/conformance/bind.js +157 -0
- package/dist/conformance/bind.js.map +1 -0
- package/dist/conformance/cli.d.ts +25 -0
- package/dist/conformance/cli.d.ts.map +1 -0
- package/dist/conformance/cli.js +137 -0
- package/dist/conformance/cli.js.map +1 -0
- package/dist/conformance/compare.d.ts +74 -0
- package/dist/conformance/compare.d.ts.map +1 -0
- package/dist/conformance/compare.js +140 -0
- package/dist/conformance/compare.js.map +1 -0
- package/dist/conformance/compose.d.ts +79 -0
- package/dist/conformance/compose.d.ts.map +1 -0
- package/dist/conformance/compose.js +167 -0
- package/dist/conformance/compose.js.map +1 -0
- package/dist/conformance/golden.d.ts +110 -0
- package/dist/conformance/golden.d.ts.map +1 -0
- package/dist/conformance/golden.js +252 -0
- package/dist/conformance/golden.js.map +1 -0
- package/dist/conformance/index.d.ts +26 -0
- package/dist/conformance/index.d.ts.map +1 -0
- package/dist/conformance/index.js +18 -0
- package/dist/conformance/index.js.map +1 -0
- package/dist/conformance/manifest-check.d.ts +78 -0
- package/dist/conformance/manifest-check.d.ts.map +1 -0
- package/dist/conformance/manifest-check.js +149 -0
- package/dist/conformance/manifest-check.js.map +1 -0
- package/dist/conformance/manifest.d.ts +83 -0
- package/dist/conformance/manifest.d.ts.map +1 -0
- package/dist/conformance/manifest.js +158 -0
- package/dist/conformance/manifest.js.map +1 -0
- package/dist/conformance/report.d.ts +14 -0
- package/dist/conformance/report.d.ts.map +1 -0
- package/dist/conformance/report.js +87 -0
- package/dist/conformance/report.js.map +1 -0
- package/dist/conformance/run.d.ts +172 -0
- package/dist/conformance/run.d.ts.map +1 -0
- package/dist/conformance/run.js +626 -0
- package/dist/conformance/run.js.map +1 -0
- package/dist/contracts.d.ts +198 -0
- package/dist/contracts.d.ts.map +1 -0
- package/dist/contracts.js +10 -0
- package/dist/contracts.js.map +1 -0
- package/dist/contradiction.d.ts +112 -0
- package/dist/contradiction.d.ts.map +1 -0
- package/dist/contradiction.js +97 -0
- package/dist/contradiction.js.map +1 -0
- package/dist/finding.d.ts +567 -0
- package/dist/finding.d.ts.map +1 -0
- package/dist/finding.js +491 -0
- package/dist/finding.js.map +1 -0
- package/dist/hypothesis.d.ts +130 -0
- package/dist/hypothesis.d.ts.map +1 -0
- package/dist/hypothesis.js +116 -0
- package/dist/hypothesis.js.map +1 -0
- package/dist/identity.d.ts +295 -0
- package/dist/identity.d.ts.map +1 -0
- package/dist/identity.js +404 -0
- package/dist/identity.js.map +1 -0
- package/dist/index.d.ts +34 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/ir.d.ts +360 -0
- package/dist/ir.d.ts.map +1 -0
- package/dist/ir.js +76 -0
- package/dist/ir.js.map +1 -0
- package/dist/model-tables.d.ts +111 -0
- package/dist/model-tables.d.ts.map +1 -0
- package/dist/model-tables.js +103 -0
- package/dist/model-tables.js.map +1 -0
- package/dist/normalise.d.ts +114 -0
- package/dist/normalise.d.ts.map +1 -0
- package/dist/normalise.js +603 -0
- package/dist/normalise.js.map +1 -0
- package/dist/reliability.d.ts +89 -0
- package/dist/reliability.d.ts.map +1 -0
- package/dist/reliability.js +181 -0
- package/dist/reliability.js.map +1 -0
- package/dist/tool-surface.d.ts +131 -0
- package/dist/tool-surface.d.ts.map +1 -0
- package/dist/tool-surface.js +133 -0
- package/dist/tool-surface.js.map +1 -0
- package/dist/vocabulary.d.ts +73 -0
- package/dist/vocabulary.d.ts.map +1 -0
- package/dist/vocabulary.js +150 -0
- package/dist/vocabulary.js.map +1 -0
- package/package.json +27 -0
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The hypothesis state machine — `descry-ai-layer.md` §12, P19 of
|
|
3
|
+
* `ai-layer-plan.md` §11 (Phase 4).
|
|
4
|
+
*
|
|
5
|
+
* Six states, four transitions, all evaluated outside the model: *"Every
|
|
6
|
+
* transition is a deterministic rule evaluated outside the model. The model
|
|
7
|
+
* proposes; a rule disposes."* (`ai-layer-plan.md` §6). Same posture as
|
|
8
|
+
* G1–G4 (`../governance/*.ts`, `./finding.ts`) — a pure function over
|
|
9
|
+
* caller-supplied facts, never a prompt instruction.
|
|
10
|
+
*
|
|
11
|
+
* ## This is not a report category
|
|
12
|
+
*
|
|
13
|
+
* §12's own ruling, 2026-08-24 (Option B, `ai-governance-spec.md` §9): these
|
|
14
|
+
* six are *machine states*. `supported`/`confirmed` are not §19's
|
|
15
|
+
* `strongly supported`/`confirmed` report categories — only G4
|
|
16
|
+
* ({@link "./finding.ts".reportCategory}) assigns those, and it reads
|
|
17
|
+
* different inputs (resolution, name-level-ness, humanAsserted) that this
|
|
18
|
+
* module does not see at all. Do not compare a `HypothesisState` against a
|
|
19
|
+
* `ReportCategory` anywhere upstream of G4.
|
|
20
|
+
*
|
|
21
|
+
* ## What this module does not compute
|
|
22
|
+
*
|
|
23
|
+
* Three of the five inputs below are facts only the caller (the investigation
|
|
24
|
+
* loop, stage 12, P20) can supply, and are deliberately *not* derived here:
|
|
25
|
+
*
|
|
26
|
+
* - **`contradicted`** — whether evidence directly contradicts the
|
|
27
|
+
* hypothesis. Detecting a contradiction is §10's own machinery (graph vs.
|
|
28
|
+
* runtime disagreement, P21) — a larger, separate mechanism this module
|
|
29
|
+
* does not reimplement.
|
|
30
|
+
* - **`roundLimitReached`** — whether this hypothesis has exhausted its
|
|
31
|
+
* per-hypothesis tool-call budget. That accounting is `../governance/budget.ts`
|
|
32
|
+
* (P18)'s job; this module only reacts to the boolean it produces.
|
|
33
|
+
* - **`toolCallsIssued`** — the raw count of tool calls issued so far.
|
|
34
|
+
* `candidate → investigating` fires the instant the first call is issued,
|
|
35
|
+
* before any result — even an empty or refused one — comes back, so this
|
|
36
|
+
* cannot be derived from the evidence array's shape.
|
|
37
|
+
*/
|
|
38
|
+
import { directMechanismEvidence } from "./finding.js";
|
|
39
|
+
/** §12's six states, in the order the architecture lists them. */
|
|
40
|
+
export const HYPOTHESIS_STATES = [
|
|
41
|
+
"candidate",
|
|
42
|
+
"investigating",
|
|
43
|
+
"supported",
|
|
44
|
+
"confirmed",
|
|
45
|
+
"rejected",
|
|
46
|
+
"unconfirmed",
|
|
47
|
+
];
|
|
48
|
+
/** States §12 marks terminal outright — the loop stops touching this hypothesis. */
|
|
49
|
+
export const TERMINAL_HYPOTHESIS_STATES = ["confirmed", "rejected", "unconfirmed"];
|
|
50
|
+
export function isTerminalHypothesisState(state) {
|
|
51
|
+
return TERMINAL_HYPOTHESIS_STATES.includes(state);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Why an `unconfirmed` result was reached. `ai-layer-plan.md` §6 point 4 names
|
|
55
|
+
* three: `round-limit` is the one transition §12 actually defines
|
|
56
|
+
* (`any state → unconfirmed`, the round limit reached before `confirmed` or
|
|
57
|
+
* `rejected`); `superseded` and `unreachable` are named by the plan as
|
|
58
|
+
* additional reasons but have no defined trigger here — **disclosed, not
|
|
59
|
+
* modeled**, same as every other gap this project leaves rather than guesses
|
|
60
|
+
* a rule for.
|
|
61
|
+
*/
|
|
62
|
+
export const UNCONFIRMED_REASONS = ["round-limit"];
|
|
63
|
+
/**
|
|
64
|
+
* How many independent evidence sources name this hypothesis — a graph fact
|
|
65
|
+
* counts as one, and each of the six {@link RuntimeSignalType} channels
|
|
66
|
+
* counts once however many records carry it (the same dedup-by-channel
|
|
67
|
+
* discipline `independentSignalTypes` uses for G4's `E`, applied to a wider
|
|
68
|
+
* source set).
|
|
69
|
+
*
|
|
70
|
+
* **Not `E`.** G4's `E` is a closed count over exactly the six runtime
|
|
71
|
+
* channels (`ai-governance-spec.md` §5.2) and a graph fact is not one of
|
|
72
|
+
* them by design — conflating the two is exactly the "machine state leaking
|
|
73
|
+
* into report vocabulary" failure §12's own ruling exists to prevent. This
|
|
74
|
+
* function answers a different question — *how many independent sources
|
|
75
|
+
* back this hypothesis, for the state machine's own `supported` transition*
|
|
76
|
+
* — and must never be passed anywhere G4 reads.
|
|
77
|
+
*/
|
|
78
|
+
export function independentEvidenceSources(runtimeEvidence, hasGraphFact) {
|
|
79
|
+
const channels = new Set(runtimeEvidence
|
|
80
|
+
.map((item) => item.signal)
|
|
81
|
+
.filter((signal) => signal !== null));
|
|
82
|
+
return channels.size + (hasGraphFact ? 1 : 0);
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Derive this hypothesis's current state from its accumulated evidence.
|
|
86
|
+
* Never throws — this is a check, not an execution of the thing it is
|
|
87
|
+
* checking.
|
|
88
|
+
*
|
|
89
|
+
* Precedence, most decisive first: a caller-flagged contradiction always
|
|
90
|
+
* rejects, ahead of mechanism evidence — a sane caller never sets both, but
|
|
91
|
+
* rejection winning is the conservative reading. Direct mechanism evidence
|
|
92
|
+
* confirms next, regardless of round limit — §12's `confirmed` transition
|
|
93
|
+
* names no round bound. Only after both are checked does the round limit
|
|
94
|
+
* force `unconfirmed`. Below that, two or more independent sources reach
|
|
95
|
+
* `supported`; otherwise the hypothesis is still `investigating` once at
|
|
96
|
+
* least one call has been issued, or `candidate` before the first.
|
|
97
|
+
*/
|
|
98
|
+
export function deriveHypothesisState(input) {
|
|
99
|
+
if (input.toolCallsIssued === 0) {
|
|
100
|
+
return { state: "candidate" };
|
|
101
|
+
}
|
|
102
|
+
if (input.contradicted) {
|
|
103
|
+
return { state: "rejected" };
|
|
104
|
+
}
|
|
105
|
+
if (directMechanismEvidence(input.runtimeEvidence, input.failurePoint)) {
|
|
106
|
+
return { state: "confirmed" };
|
|
107
|
+
}
|
|
108
|
+
if (input.roundLimitReached) {
|
|
109
|
+
return { state: "unconfirmed", unconfirmedReason: "round-limit" };
|
|
110
|
+
}
|
|
111
|
+
if (independentEvidenceSources(input.runtimeEvidence, input.hasGraphFact) >= 2) {
|
|
112
|
+
return { state: "supported" };
|
|
113
|
+
}
|
|
114
|
+
return { state: "investigating" };
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=hypothesis.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hypothesis.js","sourceRoot":"","sources":["../src/hypothesis.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAGH,OAAO,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AAEvD,kEAAkE;AAClE,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,WAAW;IACX,eAAe;IACf,WAAW;IACX,WAAW;IACX,UAAU;IACV,aAAa;CACL,CAAC;AAIX,oFAAoF;AACpF,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC,WAAW,EAAE,UAAU,EAAE,aAAa,CAAU,CAAC;AAE5F,MAAM,UAAU,yBAAyB,CAAC,KAAsB;IAC9D,OAAQ,0BAAyD,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AACpF,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,aAAa,CAAU,CAAC;AAgD5D;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,0BAA0B,CACxC,eAA2C,EAC3C,YAAqB;IAErB,MAAM,QAAQ,GAAG,IAAI,GAAG,CACtB,eAAe;SACZ,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC;SAC1B,MAAM,CAAC,CAAC,MAAM,EAA+B,EAAE,CAAC,MAAM,KAAK,IAAI,CAAC,CACpE,CAAC;IACF,OAAO,QAAQ,CAAC,IAAI,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAChD,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,qBAAqB,CAAC,KAA2B;IAC/D,IAAI,KAAK,CAAC,eAAe,KAAK,CAAC,EAAE,CAAC;QAChC,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC;IAChC,CAAC;IAED,IAAI,KAAK,CAAC,YAAY,EAAE,CAAC;QACvB,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC;IAC/B,CAAC;IAED,IAAI,uBAAuB,CAAC,KAAK,CAAC,eAAe,EAAE,KAAK,CAAC,YAAY,CAAC,EAAE,CAAC;QACvE,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC;IAChC,CAAC;IAED,IAAI,KAAK,CAAC,iBAAiB,EAAE,CAAC;QAC5B,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,iBAAiB,EAAE,aAAa,EAAE,CAAC;IACpE,CAAC;IAED,IAAI,0BAA0B,CAAC,KAAK,CAAC,eAAe,EAAE,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC;QAC/E,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC;IAChC,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,eAAe,EAAE,CAAC;AACpC,CAAC"}
|
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Node and edge identity.
|
|
3
|
+
*
|
|
4
|
+
* The single most consequential property here is that a node ID survives a file
|
|
5
|
+
* move or rename. Incident links, `CHANGES_WITH` weights and every compounding
|
|
6
|
+
* asset in the product are keyed to node identity — path-derived IDs churn on
|
|
7
|
+
* rename and reset all of it silently, with nothing in the output to reveal that
|
|
8
|
+
* it happened.
|
|
9
|
+
*
|
|
10
|
+
* A node ID is `hash(scopeOf(kind), language, kind, qualifiedSymbolPath)`.
|
|
11
|
+
*
|
|
12
|
+
* Neither of the first two fields is decoration. **Scope** is per node type, so a
|
|
13
|
+
* caller in one repository and a route in another land on one `API_ENDPOINT`
|
|
14
|
+
* instead of two that never meet. **Language** keeps `models.Order` in two
|
|
15
|
+
* languages apart, which module-qualified paths alone do not — that is the
|
|
16
|
+
* ordinary layout of a polyglot monorepo, and a collision there merges two
|
|
17
|
+
* unrelated symbols and pools their edges without a word in the output.
|
|
18
|
+
*
|
|
19
|
+
* See DEC-054 (scope and language), DEC-004 (exclude file path) and DEC-011 (the
|
|
20
|
+
* per-type qualified symbol path table, and the schema tag).
|
|
21
|
+
*/
|
|
22
|
+
import { type NodeType } from "./vocabulary.ts";
|
|
23
|
+
/**
|
|
24
|
+
* Schema tag on every node ID. Costs three bytes and gives IR schema migration
|
|
25
|
+
* (§32 item 14 / DEC-017) a handle: a stored graph whose IDs carry a different
|
|
26
|
+
* tag is recognisably from a different identity scheme rather than silently
|
|
27
|
+
* mismatching.
|
|
28
|
+
*
|
|
29
|
+
* `n1:`/`e1:` were `hash(repo, kind, qsp)`. DEC-054 moved them to `n2:`/`e2:`,
|
|
30
|
+
* and that bump is the first real exercise of the mechanism — performed while
|
|
31
|
+
* there are zero stored graphs, because the alternative is discovering its bugs
|
|
32
|
+
* against half a million nodes and earned data that cannot be rebuilt.
|
|
33
|
+
*/
|
|
34
|
+
export declare const NODE_ID_PREFIX = "n2:";
|
|
35
|
+
export declare const EDGE_ID_PREFIX = "e2:";
|
|
36
|
+
/**
|
|
37
|
+
* Where a node's identity lives.
|
|
38
|
+
*
|
|
39
|
+
* `workspace` is the set of repositories that talk to each other — the contract
|
|
40
|
+
* boundary. It is **not** a GitHub organisation: an organisation is an ownership
|
|
41
|
+
* boundary, and the two overlap by accident and diverge by design. A workspace is
|
|
42
|
+
* always a deliberate configuration.
|
|
43
|
+
*
|
|
44
|
+
* It defaults to `repo`, so a single-repo user never learns the concept exists
|
|
45
|
+
* and local mode needs no configuration at all.
|
|
46
|
+
*/
|
|
47
|
+
export interface IdentityScope {
|
|
48
|
+
readonly repo: string;
|
|
49
|
+
readonly workspace?: string | undefined;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* The DEC-054 scope table.
|
|
53
|
+
*
|
|
54
|
+
* The rule it encodes, which should be derivable from the table without reading
|
|
55
|
+
* the decision: **a source artefact belongs to a repository, a contract belongs
|
|
56
|
+
* to a system, and earned knowledge belongs to whoever earned it.**
|
|
57
|
+
*
|
|
58
|
+
* `API_ROUTE` is repo-scoped and `API_ENDPOINT` is workspace-scoped, and that
|
|
59
|
+
* asymmetry is the entire contract mechanism:
|
|
60
|
+
*
|
|
61
|
+
* API_ROUTE ──SERVES_API──▶ API_ENDPOINT ◀──USES_API── caller
|
|
62
|
+
* (repo) (workspace)
|
|
63
|
+
*
|
|
64
|
+
* Widening `API_ROUTE` to match would collapse two services' handlers for one
|
|
65
|
+
* path into a single node and destroy the only question worth asking — *which
|
|
66
|
+
* service serves it* — while leaving the join count unchanged, so nothing in the
|
|
67
|
+
* output would reveal the loss.
|
|
68
|
+
*
|
|
69
|
+
* `MODEL` and `DTO` stay repo-scoped deliberately. Widening them would join a
|
|
70
|
+
* `Company` in one language to a `Company` in another on the strength of a
|
|
71
|
+
* shared word; §13.2's mechanism is shape comparison at R3, not identifiers. An
|
|
72
|
+
* endpoint template is safe to key on because both sides literally transmit it.
|
|
73
|
+
*
|
|
74
|
+
* `INCIDENT` and `FIX_PATTERN` are workspace *provisionally*. Global is the
|
|
75
|
+
* attractive answer and may yet be right, but they are the two types DEC-017
|
|
76
|
+
* says must survive a rebuild — so they are the only two where widening later is
|
|
77
|
+
* lossy, because the earned facts on a merged node cannot be re-derived apart.
|
|
78
|
+
* Widening is the safe direction to defer; un-merging is not a direction.
|
|
79
|
+
*/
|
|
80
|
+
export declare const NODE_SCOPE: {
|
|
81
|
+
readonly FILE: "repo";
|
|
82
|
+
readonly FUNCTION: "repo";
|
|
83
|
+
readonly CLASS: "repo";
|
|
84
|
+
readonly MODULE: "repo";
|
|
85
|
+
readonly API_ROUTE: "repo";
|
|
86
|
+
readonly MODEL: "repo";
|
|
87
|
+
readonly DTO: "repo";
|
|
88
|
+
readonly COMPONENT: "repo";
|
|
89
|
+
readonly PAGE: "repo";
|
|
90
|
+
readonly TEST_CASE: "repo";
|
|
91
|
+
readonly API_ENDPOINT: "workspace";
|
|
92
|
+
readonly DATABASE_TABLE: "workspace";
|
|
93
|
+
readonly DATABASE_COLUMN: "workspace";
|
|
94
|
+
readonly INCIDENT: "workspace";
|
|
95
|
+
readonly FIX_PATTERN: "workspace";
|
|
96
|
+
};
|
|
97
|
+
export type ScopeKind = (typeof NODE_SCOPE)[NodeType];
|
|
98
|
+
/** Node types whose identity crosses a repository boundary. */
|
|
99
|
+
export declare const WORKSPACE_SCOPED_NODE_TYPES: readonly NodeType[];
|
|
100
|
+
/**
|
|
101
|
+
* The scope string that actually enters the hash, per DEC-054's table.
|
|
102
|
+
*
|
|
103
|
+
* The value must be **byte-identical** across every repository in a workspace.
|
|
104
|
+
* `billing-platform` in one config and `billing_platform` in another yields a
|
|
105
|
+
* graph that is structurally perfect, internally consistent, and joins nothing —
|
|
106
|
+
* zero joins, zero errors, zero warnings. That is why the workspace id is
|
|
107
|
+
* declared once and validated at the boundary rather than restated per repo.
|
|
108
|
+
*/
|
|
109
|
+
export declare function scopeOf(kind: NodeType, scope: IdentityScope): string;
|
|
110
|
+
/**
|
|
111
|
+
* Deterministic JSON: object keys sorted, arrays order-preserving.
|
|
112
|
+
*
|
|
113
|
+
* Two structurally equal values must serialise byte-identically regardless of
|
|
114
|
+
* key insertion order, or identity depends on the order an adapter happened to
|
|
115
|
+
* build its objects in.
|
|
116
|
+
*/
|
|
117
|
+
export declare function canonicalJson(value: unknown): string;
|
|
118
|
+
/**
|
|
119
|
+
* `n2:` + hash(scopeOf(kind), language, kind, qualified symbol path).
|
|
120
|
+
*
|
|
121
|
+
* Note what is absent: file path, line number, and `attrs`. A function that moves
|
|
122
|
+
* between files is the same function; a node whose attributes change is the same
|
|
123
|
+
* node.
|
|
124
|
+
*
|
|
125
|
+
* `language` is required rather than defaulted. Defaulting it to `null` would let
|
|
126
|
+
* a forgotten argument produce an id that quietly fails to match the one the
|
|
127
|
+
* adapter computes — a missing join with nothing to see. An identity change is
|
|
128
|
+
* exactly the moment every call site should have to be looked at.
|
|
129
|
+
*
|
|
130
|
+
* **`language` is now part of identity, which makes it a vocabulary rather than a
|
|
131
|
+
* free string.** Two producers describing the same artefact as `typescript` and
|
|
132
|
+
* `tsx` emit different nodes for the same symbol and never merge. Before DEC-054
|
|
133
|
+
* the field was descriptive; it is load-bearing now.
|
|
134
|
+
*/
|
|
135
|
+
export declare function nodeId(scope: IdentityScope, kind: NodeType, qualifiedSymbolPath: string, language: string | null): string;
|
|
136
|
+
/**
|
|
137
|
+
* `e2:` + hash(from, to, type). See DEC-012.
|
|
138
|
+
*
|
|
139
|
+
* Deliberately excludes `resolution`, `confidence` and `producedBy`: two adapters
|
|
140
|
+
* finding the same relationship produce the same edge, which is what makes the
|
|
141
|
+
* merge policy possible. In prior-art graphs 30% of edges were exact duplicates,
|
|
142
|
+
* so this is load-bearing rather than tidy.
|
|
143
|
+
*/
|
|
144
|
+
export declare function edgeId(from: string, to: string, type: string): string;
|
|
145
|
+
/**
|
|
146
|
+
* A stable identifier for one model-slot prompt's exact rendered text.
|
|
147
|
+
*
|
|
148
|
+
* `recording/writer.ts`'s `StartRunOptions.promptVersion` exists to carry
|
|
149
|
+
* this — `ai-layer-plan.md` §9 layer 4/layer 7's "invalidated by a prompt
|
|
150
|
+
* change" and "a golden that silently triples in cost after a prompt change
|
|
151
|
+
* is a regression" both need a real value here — and until now nothing
|
|
152
|
+
* computed one; that field's own doc reads *"No model layer exists yet, so
|
|
153
|
+
* always null today."* P25 (§11 Phase 5).
|
|
154
|
+
*
|
|
155
|
+
* Same hashing convention as {@link nodeId}/{@link edgeId} — first 128 bits
|
|
156
|
+
* of SHA-256, prefixed so a stored value is recognisably a prompt version
|
|
157
|
+
* rather than a node or edge id that happened to land in the same column.
|
|
158
|
+
* Hashes the **whole rendered prompt text**, not a caller-chosen label: a
|
|
159
|
+
* label is something a person remembers to update, a hash cannot be
|
|
160
|
+
* forgotten to change, and any difference — including whitespace — produces
|
|
161
|
+
* a different version, which is exactly the precision a looser comparison
|
|
162
|
+
* (trimmed, or blind to template placeholders) would miss.
|
|
163
|
+
*
|
|
164
|
+
* **Disclosed gap, same shape as every gate function before it in this
|
|
165
|
+
* plan:** `descry-desktop/packages/pipeline`'s model slots
|
|
166
|
+
* (`root-cause-analysis.ts`'s `NAME_LEVEL_SYSTEM_PROMPT` and its siblings)
|
|
167
|
+
* are this function's intended caller. None calls it yet — wiring it in, and
|
|
168
|
+
* republishing `@descryy/ir` so that repository can consume it, is
|
|
169
|
+
* follow-up work, not built here.
|
|
170
|
+
*/
|
|
171
|
+
export declare function promptVersion(promptText: string): string;
|
|
172
|
+
/**
|
|
173
|
+
* A stable identity for one *shape* of finding — the key a dismissal ledger
|
|
174
|
+
* stores, so dismissing a finding suppresses the same claim on a later run
|
|
175
|
+
* without suppressing a different one that merely reads similarly.
|
|
176
|
+
*
|
|
177
|
+
* Architecture §20.1's funnel has always had an `F2` filter — *"known false
|
|
178
|
+
* positives from the feedback store"* — and §21.3 calls that store *"the real
|
|
179
|
+
* learning loop, not a cosmetic feature."* Neither had an implementation, and
|
|
180
|
+
* neither could until a finding had an identity that survives a re-run. This
|
|
181
|
+
* is that identity.
|
|
182
|
+
*
|
|
183
|
+
* **What it is over, and why each part earns its place:**
|
|
184
|
+
*
|
|
185
|
+
* - `finding`, `scope` — the claim, and what was being checked.
|
|
186
|
+
* - `affectedComponents` — node ids, which are `hash(repo, kind, qualified
|
|
187
|
+
* symbol path)` and carry no file path, so a dismissal survives a rename.
|
|
188
|
+
* The identity rule doing exactly the work it exists for.
|
|
189
|
+
* - the graph path's edges — the structural route the claim rests on. Same
|
|
190
|
+
* words about the same component via a different path is a different claim.
|
|
191
|
+
* - **`resolutionLevel`, per §21.3 explicitly**: corrections are stored *"with
|
|
192
|
+
* the resolution level at which the finding was produced… A false positive
|
|
193
|
+
* generated at R1 and one generated at R3 have different causes and should
|
|
194
|
+
* not suppress each other blindly."*
|
|
195
|
+
*
|
|
196
|
+
* **Deliberately excluded:** `recommendedAction`, `evidence`,
|
|
197
|
+
* `verificationStatus` — prose and per-run detail. A model rewording its own
|
|
198
|
+
* advice must not resurrect a finding the developer already dismissed.
|
|
199
|
+
*
|
|
200
|
+
* Lives here rather than in the funnel that consumes it for the reason
|
|
201
|
+
* `DEC-NEXT-edge-id-prefix-split` was filed: an identity gets one
|
|
202
|
+
* implementation, in the module named for identity, or it drifts.
|
|
203
|
+
*/
|
|
204
|
+
export declare function findingFingerprint(finding: {
|
|
205
|
+
readonly finding: string;
|
|
206
|
+
readonly scope: string;
|
|
207
|
+
readonly affectedComponents: readonly string[];
|
|
208
|
+
readonly graphPath: readonly {
|
|
209
|
+
readonly from: string;
|
|
210
|
+
readonly to: string;
|
|
211
|
+
readonly edgeType: string;
|
|
212
|
+
}[];
|
|
213
|
+
readonly resolutionLevel: unknown;
|
|
214
|
+
}): string;
|
|
215
|
+
/**
|
|
216
|
+
* Erase every parameter segment to the literal token `{param}`.
|
|
217
|
+
*
|
|
218
|
+
* `/orders/:id`, `/orders/{order_id}`, `/orders/<int:id>` and `/orders/[id]` all
|
|
219
|
+
* normalise to `/orders/{param}`. This is what makes one `API_ENDPOINT` node out
|
|
220
|
+
* of two adapters that never share a line of code — the cross-language join.
|
|
221
|
+
*
|
|
222
|
+
* Position is preserved by path structure, so distinct routes cannot collide:
|
|
223
|
+
* `/orders/{param}/items/{param}` stays distinct from `/orders/{param}`.
|
|
224
|
+
*
|
|
225
|
+
* See DEC-013. Base paths, router mounts and gateway rewrites remain open
|
|
226
|
+
* (architecture §32 item 16) — this handles the segment shape only.
|
|
227
|
+
*
|
|
228
|
+
* ## The query string is not part of the identity, and leaving it in broke joins
|
|
229
|
+
*
|
|
230
|
+
* **Found on real code, by a lane whose own gates could not see it.** A caller
|
|
231
|
+
* writes `GET /api/invoices?company_id={param}`; the route producer writes
|
|
232
|
+
* `GET /api/invoices`, because no routing framework declares a query in its
|
|
233
|
+
* path. With the query left in, the two hash to different endpoints and the
|
|
234
|
+
* join returns **nothing** — no error, no rejection, no ledger row. Five such
|
|
235
|
+
* calls ship today across two repositories.
|
|
236
|
+
*
|
|
237
|
+
* The defect survived a 100/100 precision draw with a 0/100 control on both
|
|
238
|
+
* sides, because the adjudicator compares an edge against the source text and
|
|
239
|
+
* the source really does write `?company_id=`. Every instrument was asking *did
|
|
240
|
+
* you read this call correctly* and none was asking *can this identity ever
|
|
241
|
+
* join* — the same shape as DEC-112, one layer down: the reader and its grader
|
|
242
|
+
* shared an assumption, so no amount of grading escaped it.
|
|
243
|
+
*
|
|
244
|
+
* **A query string cannot distinguish two endpoints here**, because only
|
|
245
|
+
* consumers write one. Two callers differing only by query are reaching the
|
|
246
|
+
* same route, so collapsing them is the correct merge rather than a lossy one.
|
|
247
|
+
* The residual limit is real and disclosed rather than modelled: an API that
|
|
248
|
+
* *routes* on a query parameter — `?action=create` dispatching separately from
|
|
249
|
+
* `?action=delete` — collapses to one endpoint here. No producer in this
|
|
250
|
+
* project emits such a route, and inventing identity for one nobody declares
|
|
251
|
+
* would be the guess this rule exists to prevent.
|
|
252
|
+
*/
|
|
253
|
+
export declare function normaliseEndpointPath(path: string): string;
|
|
254
|
+
/**
|
|
255
|
+
* Qualified symbol path for an `API_ENDPOINT`: `METHOD /normalised/path`.
|
|
256
|
+
* This value IS the endpoint's identity, which is why normalisation must be
|
|
257
|
+
* applied before hashing rather than after.
|
|
258
|
+
*/
|
|
259
|
+
export declare function endpointQsp(method: string, path: string): string;
|
|
260
|
+
/** Qualified symbol path for a `DATABASE_TABLE` or `DATABASE_COLUMN`. */
|
|
261
|
+
export declare function tableQsp(schema: string, table: string, column?: string): string;
|
|
262
|
+
/**
|
|
263
|
+
* Qualified symbol path for a `TEST_CASE`: `pkg::suite::case`.
|
|
264
|
+
*
|
|
265
|
+
* **The package root is part of it, exactly as it is for a code symbol.**
|
|
266
|
+
* `symbolQsp` has carried it since DEC-047, and this did not — so a test's
|
|
267
|
+
* qualifier was its module path *relative to its own package anchor*, with the
|
|
268
|
+
* anchor thrown away. Five Strapi packages each ship
|
|
269
|
+
* `admin/src/translations/tests/plural.test.ts` with the same titles, and all
|
|
270
|
+
* five hashed to one node: 42 cross-file collisions dropping 86 test cases on
|
|
271
|
+
* one repository, and 0 on either repository this was built against.
|
|
272
|
+
*
|
|
273
|
+
* `occurrence` distinguishes two cases a runner would report identically. Two
|
|
274
|
+
* `it("…")` calls with the same title in one describe block are legal and
|
|
275
|
+
* common — 57 pairs on Rocket.Chat, 30 on Strapi — and they are two different
|
|
276
|
+
* tests. Merging them loses one; numbering them keeps both. Only the second and
|
|
277
|
+
* later carry a suffix, so the common case is unchanged.
|
|
278
|
+
*/
|
|
279
|
+
export declare function testCaseQsp(pkg: string, suite: readonly string[], caseName: string, occurrence?: number): string;
|
|
280
|
+
/**
|
|
281
|
+
* Qualified symbol path for a code symbol: `pkg::Namespace.Symbol`.
|
|
282
|
+
* `pkg` is the module/package root, not a file path.
|
|
283
|
+
*/
|
|
284
|
+
export declare function symbolQsp(pkg: string, symbolPath: readonly string[]): string;
|
|
285
|
+
/**
|
|
286
|
+
* Qualified symbol path for a `FILE`: the repo-relative path.
|
|
287
|
+
*
|
|
288
|
+
* This is the documented path-fallback in DEC-004. It is unavoidable — a file's
|
|
289
|
+
* only stable name IS its path — and it has a real consequence: `CHANGES_WITH`
|
|
290
|
+
* weights are file-to-file, so they churn on rename unless the rename-detection
|
|
291
|
+
* pass rewrites them. DEC-004's guarantee is total for symbols and partial for
|
|
292
|
+
* files, and that asymmetry is deliberate rather than overlooked.
|
|
293
|
+
*/
|
|
294
|
+
export declare function fileQsp(repoRelativePath: string): string;
|
|
295
|
+
//# sourceMappingURL=identity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../src/identity.ts"],"names":[],"mappings":"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"}
|