@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.
Files changed (94) hide show
  1. package/LICENSE +21 -0
  2. package/dist/capabilities.d.ts +83 -0
  3. package/dist/capabilities.d.ts.map +1 -0
  4. package/dist/capabilities.js +91 -0
  5. package/dist/capabilities.js.map +1 -0
  6. package/dist/conformance/bind.d.ts +82 -0
  7. package/dist/conformance/bind.d.ts.map +1 -0
  8. package/dist/conformance/bind.js +157 -0
  9. package/dist/conformance/bind.js.map +1 -0
  10. package/dist/conformance/cli.d.ts +25 -0
  11. package/dist/conformance/cli.d.ts.map +1 -0
  12. package/dist/conformance/cli.js +137 -0
  13. package/dist/conformance/cli.js.map +1 -0
  14. package/dist/conformance/compare.d.ts +74 -0
  15. package/dist/conformance/compare.d.ts.map +1 -0
  16. package/dist/conformance/compare.js +140 -0
  17. package/dist/conformance/compare.js.map +1 -0
  18. package/dist/conformance/compose.d.ts +79 -0
  19. package/dist/conformance/compose.d.ts.map +1 -0
  20. package/dist/conformance/compose.js +167 -0
  21. package/dist/conformance/compose.js.map +1 -0
  22. package/dist/conformance/golden.d.ts +110 -0
  23. package/dist/conformance/golden.d.ts.map +1 -0
  24. package/dist/conformance/golden.js +252 -0
  25. package/dist/conformance/golden.js.map +1 -0
  26. package/dist/conformance/index.d.ts +26 -0
  27. package/dist/conformance/index.d.ts.map +1 -0
  28. package/dist/conformance/index.js +18 -0
  29. package/dist/conformance/index.js.map +1 -0
  30. package/dist/conformance/manifest-check.d.ts +78 -0
  31. package/dist/conformance/manifest-check.d.ts.map +1 -0
  32. package/dist/conformance/manifest-check.js +149 -0
  33. package/dist/conformance/manifest-check.js.map +1 -0
  34. package/dist/conformance/manifest.d.ts +83 -0
  35. package/dist/conformance/manifest.d.ts.map +1 -0
  36. package/dist/conformance/manifest.js +158 -0
  37. package/dist/conformance/manifest.js.map +1 -0
  38. package/dist/conformance/report.d.ts +14 -0
  39. package/dist/conformance/report.d.ts.map +1 -0
  40. package/dist/conformance/report.js +87 -0
  41. package/dist/conformance/report.js.map +1 -0
  42. package/dist/conformance/run.d.ts +172 -0
  43. package/dist/conformance/run.d.ts.map +1 -0
  44. package/dist/conformance/run.js +626 -0
  45. package/dist/conformance/run.js.map +1 -0
  46. package/dist/contracts.d.ts +198 -0
  47. package/dist/contracts.d.ts.map +1 -0
  48. package/dist/contracts.js +10 -0
  49. package/dist/contracts.js.map +1 -0
  50. package/dist/contradiction.d.ts +112 -0
  51. package/dist/contradiction.d.ts.map +1 -0
  52. package/dist/contradiction.js +97 -0
  53. package/dist/contradiction.js.map +1 -0
  54. package/dist/finding.d.ts +567 -0
  55. package/dist/finding.d.ts.map +1 -0
  56. package/dist/finding.js +491 -0
  57. package/dist/finding.js.map +1 -0
  58. package/dist/hypothesis.d.ts +130 -0
  59. package/dist/hypothesis.d.ts.map +1 -0
  60. package/dist/hypothesis.js +116 -0
  61. package/dist/hypothesis.js.map +1 -0
  62. package/dist/identity.d.ts +295 -0
  63. package/dist/identity.d.ts.map +1 -0
  64. package/dist/identity.js +404 -0
  65. package/dist/identity.js.map +1 -0
  66. package/dist/index.d.ts +34 -0
  67. package/dist/index.d.ts.map +1 -0
  68. package/dist/index.js +21 -0
  69. package/dist/index.js.map +1 -0
  70. package/dist/ir.d.ts +360 -0
  71. package/dist/ir.d.ts.map +1 -0
  72. package/dist/ir.js +76 -0
  73. package/dist/ir.js.map +1 -0
  74. package/dist/model-tables.d.ts +111 -0
  75. package/dist/model-tables.d.ts.map +1 -0
  76. package/dist/model-tables.js +103 -0
  77. package/dist/model-tables.js.map +1 -0
  78. package/dist/normalise.d.ts +114 -0
  79. package/dist/normalise.d.ts.map +1 -0
  80. package/dist/normalise.js +603 -0
  81. package/dist/normalise.js.map +1 -0
  82. package/dist/reliability.d.ts +89 -0
  83. package/dist/reliability.d.ts.map +1 -0
  84. package/dist/reliability.js +181 -0
  85. package/dist/reliability.js.map +1 -0
  86. package/dist/tool-surface.d.ts +131 -0
  87. package/dist/tool-surface.d.ts.map +1 -0
  88. package/dist/tool-surface.js +133 -0
  89. package/dist/tool-surface.js.map +1 -0
  90. package/dist/vocabulary.d.ts +73 -0
  91. package/dist/vocabulary.d.ts.map +1 -0
  92. package/dist/vocabulary.js +150 -0
  93. package/dist/vocabulary.js.map +1 -0
  94. package/package.json +27 -0
@@ -0,0 +1,198 @@
1
+ /**
2
+ * Contracts every producer of IR must satisfy.
3
+ *
4
+ * `IRSource` is the narrow surface: one way in, and it goes through the
5
+ * Normaliser. The git-history reader is an `IRSource` but not a `LanguageAdapter`
6
+ * — without this split it would need a second write path, and a second write path
7
+ * is a way for un-provenanced rows to reach storage.
8
+ */
9
+ import type { FrameworkCapability } from "./capabilities.ts";
10
+ import type { IRBatch, IREdge, IRNode, ResolutionLevel } from "./ir.ts";
11
+ import type { EdgeType, NodeType } from "./vocabulary.ts";
12
+ export interface RepoRoot {
13
+ /** Stable repo identifier — the identity scope for every source artefact. */
14
+ readonly repo: string;
15
+ /**
16
+ * The contract boundary: the set of repositories that talk to each other.
17
+ *
18
+ * Workspace-scoped node types (`API_ENDPOINT`, `DATABASE_TABLE`,
19
+ * `DATABASE_COLUMN`, `INCIDENT`, `FIX_PATTERN`) are keyed by this instead of by
20
+ * `repo`, which is what lets a caller in one repository and a route in another
21
+ * reach the same node. See DEC-054.
22
+ *
23
+ * Absent means "this repository alone", so local mode works unconfigured. When
24
+ * present it must be **byte-identical** in every repository of the workspace —
25
+ * a mismatch produces a graph that joins nothing and says nothing.
26
+ */
27
+ readonly workspace?: string | undefined;
28
+ /** Absolute path to the root on disk. Never stored in the graph. */
29
+ readonly absolutePath: string;
30
+ readonly commitSha: string;
31
+ }
32
+ export interface FileRef {
33
+ /** Repo-relative. Absolute paths are rejected by the Normaliser — they make
34
+ * graphs non-portable and give the same code different IDs per machine. */
35
+ readonly path: string;
36
+ readonly contentHash: string;
37
+ }
38
+ export interface AnalysisContext {
39
+ readonly root: RepoRoot;
40
+ /** Wall-clock budget for `prepare()`. On expiry the adapter returns the level
41
+ * it actually reached; it never blocks the run and never silently downgrades. */
42
+ readonly prepareTimeoutMs: number;
43
+ readonly signal: AbortSignal;
44
+ }
45
+ export interface DetectionResult {
46
+ readonly detected: boolean;
47
+ /** Repo-relative roots this adapter claims. Empty when `detected` is false. */
48
+ readonly roots: readonly string[];
49
+ /** Why it matched — surfaced in the report, not just logged. */
50
+ readonly evidence: readonly string[];
51
+ }
52
+ /**
53
+ * What an adapter can and cannot do.
54
+ *
55
+ * Machine-read, not documentation: governance uses it to decide whether a check
56
+ * is attemptable for this repo at all, and the report uses it to name what was
57
+ * skipped rather than reporting a thin result as a clean one.
58
+ */
59
+ export interface CapabilityMatrix {
60
+ /** The best this adapter can reach on a fully resolvable project. */
61
+ readonly maxResolution: ResolutionLevel;
62
+ readonly nodeTypes: readonly NodeType[];
63
+ readonly edgeTypes: readonly EdgeType[];
64
+ /** LSP method support is not uniform — `callHierarchy` and `typeHierarchy` are
65
+ * far from universal. Adapters declare rather than assume. */
66
+ readonly hasCallHierarchy: boolean;
67
+ readonly hasTypeHierarchy: boolean;
68
+ /** Framework extractors bound to this adapter, by their own names. Empty means
69
+ * Layers 4–6 are unavailable, and patterns needing them are skipped rather
70
+ * than failed. Nothing above the adapter reads these names. */
71
+ readonly frameworkExtractors: readonly string[];
72
+ /**
73
+ * What those extractors supply, from the closed set in `capabilities.ts`.
74
+ *
75
+ * Required whenever `frameworkExtractors` is non-empty: the names above are
76
+ * `"spring"` and `"rails"`, which the harness must never interpret, so an
77
+ * adapter that binds an extractor and does not say what it supplies has told
78
+ * the harness nothing it can act on. **Absent with extractors bound is an
79
+ * adapter failure**, not a default — a default in either direction is a gate
80
+ * silently changing what it checks.
81
+ *
82
+ * Declare what the extractor actually produces, not what the framework could:
83
+ * `adapter-ruby` binds Rails and reads only its routes, so it supplies
84
+ * `route-extractor` and not `orm-extractor`, and the ORM patterns skip
85
+ * honestly rather than failing on ActiveRecord it never reads.
86
+ */
87
+ readonly frameworkCapabilities?: readonly FrameworkCapability[];
88
+ /**
89
+ * Directories this adapter's ecosystem installs dependencies or build output
90
+ * into — `node_modules` for npm, `vendor` for Composer and Go, `target` for
91
+ * Cargo and Maven.
92
+ *
93
+ * **DEC-110's end state, and the reason it is here rather than in the engine.**
94
+ * A vendored tree carries its own `.env.example` files, and a dependency's
95
+ * sample configuration is not this repository's declaration of anything —
96
+ * including one puts another project's variable names into the denominator of
97
+ * the coverage guard. But *which* directories those are is a fact about an
98
+ * ecosystem, and engine code that knows one ecosystem's build cache by name is
99
+ * engine code that will be missing the next one's. So the adapter declares and
100
+ * the walk consumes.
101
+ *
102
+ * Names only, never paths or globs: the walk matches a single directory
103
+ * component, so `node_modules` is right and a recursive glob spelling of it is
104
+ * not.
105
+ *
106
+ * **Absent is not a failure**, unlike `frameworkCapabilities`. Undeclared, the
107
+ * walk descends into whatever is there and reports the empty set it used, so
108
+ * the degradation is visible rather than silent (rule 7). An adapter for a
109
+ * language with no vendoring convention correctly declares nothing.
110
+ */
111
+ readonly noiseDirectories?: readonly string[];
112
+ /**
113
+ * Set when this language has no qualified symbol path independent of file
114
+ * location, so node identity falls back to path. Required by DEC-004: the
115
+ * fallback must be declared, not assumed, because it makes the rename
116
+ * guarantee partial for this adapter.
117
+ */
118
+ readonly nodeIdentityFallback?: {
119
+ readonly appliesTo: readonly NodeType[];
120
+ readonly reason: string;
121
+ };
122
+ /**
123
+ * Opt-in to cross-language identity resolution — DEC-161.
124
+ *
125
+ * `id` is an opaque string; the engine never inspects what it means, only
126
+ * compares it for equality. `peers` are the `id`s this adapter expects to
127
+ * share a namespace with. **Declaration must be mutual**: the resolver joins
128
+ * two adapters only when each names the other, so one adapter declaring a
129
+ * peer that does not declare it back resolves nothing — a one-sided
130
+ * declaration is a silent no-op, not a partial join. This is what stops an
131
+ * accidental string collision between two unrelated adapters from minting a
132
+ * cross-language edge neither intended: a collision with no peer declaration
133
+ * on both sides is refused, not resolved.
134
+ *
135
+ * `adapter-java` and `adapter-kotlin` are the only adapters expected to
136
+ * declare one, both naming the same `id`. Declaring this for a language pair
137
+ * that does not share a name-resolution model — `qualifiedName` collisions
138
+ * across unrelated languages are not the same claim — is the adapter's own
139
+ * mistake to avoid; nothing here checks that the pairing makes sense,
140
+ * because nothing above the IR is allowed to know what a language is.
141
+ */
142
+ readonly crossLanguageNamespace?: {
143
+ readonly id: string;
144
+ readonly peers: readonly string[];
145
+ };
146
+ }
147
+ export interface ParsedUnit {
148
+ readonly file: FileRef;
149
+ /** Adapter-private parse output. Opaque above the boundary. */
150
+ readonly tree: unknown;
151
+ }
152
+ /**
153
+ * The one way IR reaches the graph.
154
+ *
155
+ * Everything — language adapters, the git-history reader, schema readers —
156
+ * implements this, and everything it returns passes through the Normaliser.
157
+ */
158
+ export interface IRSource {
159
+ readonly id: string;
160
+ readonly version: string;
161
+ emit(ctx: AnalysisContext): Promise<IRBatch>;
162
+ }
163
+ /**
164
+ * A language- or format-specific adapter.
165
+ *
166
+ * Three requirements that are cheap now and expensive to retrofit:
167
+ *
168
+ * 1. `parseFiles` must never fail because dependencies are missing. R0 is always
169
+ * achievable; degradation belongs in `prepare()`.
170
+ * 2. `capabilities()` is consumed by governance, not by a reader.
171
+ * 3. `dispose()` is mandatory — language servers are long-lived child processes
172
+ * and a leak here is hundreds of megabytes per repo.
173
+ */
174
+ export interface LanguageAdapter extends IRSource {
175
+ detect(root: RepoRoot): Promise<DetectionResult>;
176
+ capabilities(): CapabilityMatrix;
177
+ /**
178
+ * Does this adapter own the given repository-relative path, on its own
179
+ * criteria — extension, config, whatever it uses internally? Optional
180
+ * because it answers a narrower question than `detect` (one path, not the
181
+ * whole repository) that not every caller needs: `verification_status`
182
+ * (`@descryy/mcp`) is the one that does, to attach real capabilities to
183
+ * a file the graph never reached, without a caller above this boundary
184
+ * ever naming or comparing a language itself (architecture principle 7).
185
+ * Absent, or `false`, means only "this adapter does not claim it" — never
186
+ * "no adapter anywhere would."
187
+ */
188
+ ownsPath?(path: string): boolean;
189
+ /** Dependency resolution, LSP warm-up or index load. Returns the level actually
190
+ * reached — which may be lower than `capabilities().maxResolution`. */
191
+ prepare(ctx: AnalysisContext): Promise<ResolutionLevel>;
192
+ /** Structure only. Must succeed at R0 with no dependencies present. */
193
+ parseFiles(files: readonly FileRef[]): Promise<readonly ParsedUnit[]>;
194
+ extractNodes(units: readonly ParsedUnit[]): readonly IRNode[];
195
+ extractEdges(units: readonly ParsedUnit[]): readonly IREdge[];
196
+ dispose(): Promise<void>;
197
+ }
198
+ //# sourceMappingURL=contracts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contracts.d.ts","sourceRoot":"","sources":["../src/contracts.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Contracts every producer of IR must satisfy.
3
+ *
4
+ * `IRSource` is the narrow surface: one way in, and it goes through the
5
+ * Normaliser. The git-history reader is an `IRSource` but not a `LanguageAdapter`
6
+ * — without this split it would need a second write path, and a second write path
7
+ * is a way for un-provenanced rows to reach storage.
8
+ */
9
+ export {};
10
+ //# sourceMappingURL=contracts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contracts.js","sourceRoot":"","sources":["../src/contracts.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG"}
@@ -0,0 +1,112 @@
1
+ /**
2
+ * Graph-vs-runtime contradiction — `documents/plans/ai-layer-plan.md` §10, P21
3
+ * of §11 (Phase 5).
4
+ *
5
+ * *"Graph says X is called; runtime proves it is not. The ordering is
6
+ * settled: R4 outranks R3. Runtime wins."* This module answers the two things
7
+ * §10 leaves open once that ordering fires:
8
+ *
9
+ * 1. **Disclosure** — the finding must state the graph was wrong here (§41.6).
10
+ * {@link detectGraphRuntimeContradiction} produces that sentence.
11
+ * 2. **Defect recording** — *"the valuable half."* A runtime contradiction is
12
+ * the only edge-precision ground truth that is not another instrument —
13
+ * this project's history (Rust grader, Swift control, Java/C# adjudicators,
14
+ * TypeScript workspace gap) is repeatedly the measuring tool being the
15
+ * defect, not the adapter. {@link toGraphDefectRecord} shapes the
16
+ * contradiction into that independent check.
17
+ *
18
+ * Same posture as G1–G4 and the hypothesis state machine
19
+ * (`./finding.ts`, `./hypothesis.ts`): a pure function over caller-supplied
20
+ * facts, never a prompt instruction, never storage. `hypothesis.ts`'s own
21
+ * module doc names this file as the source of the `contradicted` input it
22
+ * does not compute — wiring that input from here is future work; this module
23
+ * builds the detection, not the caller.
24
+ *
25
+ * **Persistence is a disclosed gap, same shape as P9–P20's.** A
26
+ * {@link GraphDefectRecord} is a value, not a write — nothing here touches a
27
+ * store. `packages/core/src/recording/` is the nearest existing precedent for
28
+ * what a `graph_defects` table would look like, and building it is whoever
29
+ * wires stage 12/13 to this module, not this session.
30
+ *
31
+ * ## Why R4-vs-R4 is out of scope here
32
+ *
33
+ * {@link detectGraphRuntimeContradiction} requires `hop.resolution < 4`. A
34
+ * graph hop already at R4 was itself minted from a prior runtime observation
35
+ * — a fresh observation disagreeing with it is not "graph vs runtime," it is
36
+ * two runtime observations disagreeing across time, which is a staleness
37
+ * question with no settled answer yet
38
+ * (`documents/decisions-inbox/DEC-NEXT-r4-expiry-interval.md`,
39
+ * `documents/process/open-register.md` §3). Silently treating it as an
40
+ * ordinary contradiction would launder that open question through a function
41
+ * that looks decided.
42
+ */
43
+ import type { EdgeType } from "./vocabulary.ts";
44
+ import type { GraphPathHop } from "./finding.ts";
45
+ import type { ResolutionLevel } from "./ir.ts";
46
+ /**
47
+ * One runtime observation that names a specific graph edge and states
48
+ * whether it held. Deliberately narrower than {@link "./finding.ts".RuntimeEvidence} —
49
+ * that type records *what was observed*; this one records *what edge it
50
+ * confirms or denies*, which only some observations do. A caller producing
51
+ * this from a `RuntimeEvidence` record decides that mapping; it is not
52
+ * inferred here from `nodeId`/`directMechanism` co-occurrence, because
53
+ * co-occurrence is exactly the ambiguity `directMechanismEvidence` already
54
+ * requires an explicit flag to avoid, and a contradiction claim deserves the
55
+ * same discipline.
56
+ */
57
+ export interface RuntimeEdgeObservation {
58
+ /** Source node id, matched against {@link GraphPathHop.from}. */
59
+ readonly from: string;
60
+ /** Target node id, matched against {@link GraphPathHop.to}. */
61
+ readonly to: string;
62
+ readonly edgeType: EdgeType;
63
+ /** `false` — runtime observed this edge did not hold. `true` — confirmed it did. */
64
+ readonly held: boolean;
65
+ /** What was observed, in the collector's own words. Never summarised here. */
66
+ readonly detail: string;
67
+ }
68
+ /** One detected disagreement between a graph hop and a runtime observation of the same edge. */
69
+ export interface GraphRuntimeContradiction {
70
+ readonly hop: GraphPathHop;
71
+ readonly observation: RuntimeEdgeObservation;
72
+ /**
73
+ * Ready to append to a `Finding.evidence` entry verbatim — §10 item 1's
74
+ * "does the finding state the graph was wrong here? Yes."
75
+ */
76
+ readonly disclosure: string;
77
+ }
78
+ /**
79
+ * The independent-instrument shape — a defect against the graph itself,
80
+ * divorced from any one finding. `claimedResolution` is what the graph got
81
+ * wrong *at*, which is what an edge-precision recomputation needs to weigh
82
+ * this against everything else drawn at that resolution.
83
+ */
84
+ export interface GraphDefectRecord {
85
+ readonly from: string;
86
+ readonly to: string;
87
+ readonly edgeType: EdgeType;
88
+ readonly claimedResolution: ResolutionLevel;
89
+ readonly detail: string;
90
+ }
91
+ /**
92
+ * Detect whether `observation` contradicts `hop` — same edge (`from`, `to`,
93
+ * `edgeType`), `observation.held === false`, and `hop.resolution < 4` (see
94
+ * the module doc for why R4-vs-R4 is excluded). Returns `null` on no match,
95
+ * a confirming observation, or an R4 hop — never throws, matching G1–G4's
96
+ * "check, not execution" posture.
97
+ */
98
+ export declare function detectGraphRuntimeContradiction(hop: GraphPathHop, observation: RuntimeEdgeObservation): GraphRuntimeContradiction | null;
99
+ /**
100
+ * Scan every hop in `path` against every observation for a contradiction,
101
+ * via {@link detectGraphRuntimeContradiction}. Order follows `path`, then
102
+ * `observations`, for a stable, reproducible result — required for
103
+ * `ai-layer-plan.md` §12's replay guarantee.
104
+ */
105
+ export declare function findGraphRuntimeContradictions(path: readonly GraphPathHop[], observations: readonly RuntimeEdgeObservation[]): readonly GraphRuntimeContradiction[];
106
+ /**
107
+ * Shape a detected contradiction into the independent edge-precision check
108
+ * §10 item 2 calls "the valuable half." A pure reshaping — no write, no
109
+ * side effect; see the module doc for what persisting this still requires.
110
+ */
111
+ export declare function toGraphDefectRecord(contradiction: GraphRuntimeContradiction): GraphDefectRecord;
112
+ //# sourceMappingURL=contradiction.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contradiction.d.ts","sourceRoot":"","sources":["../src/contradiction.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE/C;;;;;;;;;;GAUG;AACH,MAAM,WAAW,sBAAsB;IACrC,iEAAiE;IACjE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,+DAA+D;IAC/D,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,oFAAoF;IACpF,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,8EAA8E;IAC9E,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,gGAAgG;AAChG,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,GAAG,EAAE,YAAY,CAAC;IAC3B,QAAQ,CAAC,WAAW,EAAE,sBAAsB,CAAC;IAC7C;;;OAGG;IACH,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAED;;;;;GAKG;AACH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,QAAQ,CAAC,iBAAiB,EAAE,eAAe,CAAC;IAC5C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;GAMG;AACH,wBAAgB,+BAA+B,CAC7C,GAAG,EAAE,YAAY,EACjB,WAAW,EAAE,sBAAsB,GAClC,yBAAyB,GAAG,IAAI,CAelC;AAED;;;;;GAKG;AACH,wBAAgB,8BAA8B,CAC5C,IAAI,EAAE,SAAS,YAAY,EAAE,EAC7B,YAAY,EAAE,SAAS,sBAAsB,EAAE,GAC9C,SAAS,yBAAyB,EAAE,CAStC;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,aAAa,EAAE,yBAAyB,GAAG,iBAAiB,CAQ/F"}
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Graph-vs-runtime contradiction — `documents/plans/ai-layer-plan.md` §10, P21
3
+ * of §11 (Phase 5).
4
+ *
5
+ * *"Graph says X is called; runtime proves it is not. The ordering is
6
+ * settled: R4 outranks R3. Runtime wins."* This module answers the two things
7
+ * §10 leaves open once that ordering fires:
8
+ *
9
+ * 1. **Disclosure** — the finding must state the graph was wrong here (§41.6).
10
+ * {@link detectGraphRuntimeContradiction} produces that sentence.
11
+ * 2. **Defect recording** — *"the valuable half."* A runtime contradiction is
12
+ * the only edge-precision ground truth that is not another instrument —
13
+ * this project's history (Rust grader, Swift control, Java/C# adjudicators,
14
+ * TypeScript workspace gap) is repeatedly the measuring tool being the
15
+ * defect, not the adapter. {@link toGraphDefectRecord} shapes the
16
+ * contradiction into that independent check.
17
+ *
18
+ * Same posture as G1–G4 and the hypothesis state machine
19
+ * (`./finding.ts`, `./hypothesis.ts`): a pure function over caller-supplied
20
+ * facts, never a prompt instruction, never storage. `hypothesis.ts`'s own
21
+ * module doc names this file as the source of the `contradicted` input it
22
+ * does not compute — wiring that input from here is future work; this module
23
+ * builds the detection, not the caller.
24
+ *
25
+ * **Persistence is a disclosed gap, same shape as P9–P20's.** A
26
+ * {@link GraphDefectRecord} is a value, not a write — nothing here touches a
27
+ * store. `packages/core/src/recording/` is the nearest existing precedent for
28
+ * what a `graph_defects` table would look like, and building it is whoever
29
+ * wires stage 12/13 to this module, not this session.
30
+ *
31
+ * ## Why R4-vs-R4 is out of scope here
32
+ *
33
+ * {@link detectGraphRuntimeContradiction} requires `hop.resolution < 4`. A
34
+ * graph hop already at R4 was itself minted from a prior runtime observation
35
+ * — a fresh observation disagreeing with it is not "graph vs runtime," it is
36
+ * two runtime observations disagreeing across time, which is a staleness
37
+ * question with no settled answer yet
38
+ * (`documents/decisions-inbox/DEC-NEXT-r4-expiry-interval.md`,
39
+ * `documents/process/open-register.md` §3). Silently treating it as an
40
+ * ordinary contradiction would launder that open question through a function
41
+ * that looks decided.
42
+ */
43
+ /**
44
+ * Detect whether `observation` contradicts `hop` — same edge (`from`, `to`,
45
+ * `edgeType`), `observation.held === false`, and `hop.resolution < 4` (see
46
+ * the module doc for why R4-vs-R4 is excluded). Returns `null` on no match,
47
+ * a confirming observation, or an R4 hop — never throws, matching G1–G4's
48
+ * "check, not execution" posture.
49
+ */
50
+ export function detectGraphRuntimeContradiction(hop, observation) {
51
+ if (hop.resolution >= 4)
52
+ return null;
53
+ if (hop.from !== observation.from || hop.to !== observation.to || hop.edgeType !== observation.edgeType) {
54
+ return null;
55
+ }
56
+ if (observation.held)
57
+ return null;
58
+ return {
59
+ hop,
60
+ observation,
61
+ disclosure: `The graph reports a ${hop.edgeType} edge from ${hop.from} to ${hop.to} at resolution ` +
62
+ `R${hop.resolution}, but this was not observed at runtime (R4): ${observation.detail} ` +
63
+ "Runtime evidence takes precedence over the graph here.",
64
+ };
65
+ }
66
+ /**
67
+ * Scan every hop in `path` against every observation for a contradiction,
68
+ * via {@link detectGraphRuntimeContradiction}. Order follows `path`, then
69
+ * `observations`, for a stable, reproducible result — required for
70
+ * `ai-layer-plan.md` §12's replay guarantee.
71
+ */
72
+ export function findGraphRuntimeContradictions(path, observations) {
73
+ const found = [];
74
+ for (const hop of path) {
75
+ for (const observation of observations) {
76
+ const contradiction = detectGraphRuntimeContradiction(hop, observation);
77
+ if (contradiction)
78
+ found.push(contradiction);
79
+ }
80
+ }
81
+ return found;
82
+ }
83
+ /**
84
+ * Shape a detected contradiction into the independent edge-precision check
85
+ * §10 item 2 calls "the valuable half." A pure reshaping — no write, no
86
+ * side effect; see the module doc for what persisting this still requires.
87
+ */
88
+ export function toGraphDefectRecord(contradiction) {
89
+ return {
90
+ from: contradiction.hop.from,
91
+ to: contradiction.hop.to,
92
+ edgeType: contradiction.hop.edgeType,
93
+ claimedResolution: contradiction.hop.resolution,
94
+ detail: contradiction.observation.detail,
95
+ };
96
+ }
97
+ //# sourceMappingURL=contradiction.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contradiction.js","sourceRoot":"","sources":["../src/contradiction.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AAsDH;;;;;;GAMG;AACH,MAAM,UAAU,+BAA+B,CAC7C,GAAiB,EACjB,WAAmC;IAEnC,IAAI,GAAG,CAAC,UAAU,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IACrC,IAAI,GAAG,CAAC,IAAI,KAAK,WAAW,CAAC,IAAI,IAAI,GAAG,CAAC,EAAE,KAAK,WAAW,CAAC,EAAE,IAAI,GAAG,CAAC,QAAQ,KAAK,WAAW,CAAC,QAAQ,EAAE,CAAC;QACxG,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,WAAW,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IAElC,OAAO;QACL,GAAG;QACH,WAAW;QACX,UAAU,EACR,uBAAuB,GAAG,CAAC,QAAQ,cAAc,GAAG,CAAC,IAAI,OAAO,GAAG,CAAC,EAAE,iBAAiB;YACvF,IAAI,GAAG,CAAC,UAAU,gDAAgD,WAAW,CAAC,MAAM,GAAG;YACvF,wDAAwD;KAC3D,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,8BAA8B,CAC5C,IAA6B,EAC7B,YAA+C;IAE/C,MAAM,KAAK,GAAgC,EAAE,CAAC;IAC9C,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,KAAK,MAAM,WAAW,IAAI,YAAY,EAAE,CAAC;YACvC,MAAM,aAAa,GAAG,+BAA+B,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;YACxE,IAAI,aAAa;gBAAE,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QAC/C,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAC,aAAwC;IAC1E,OAAO;QACL,IAAI,EAAE,aAAa,CAAC,GAAG,CAAC,IAAI;QAC5B,EAAE,EAAE,aAAa,CAAC,GAAG,CAAC,EAAE;QACxB,QAAQ,EAAE,aAAa,CAAC,GAAG,CAAC,QAAQ;QACpC,iBAAiB,EAAE,aAAa,CAAC,GAAG,CAAC,UAAU;QAC/C,MAAM,EAAE,aAAa,CAAC,WAAW,CAAC,MAAM;KACzC,CAAC;AACJ,CAAC"}