@descryy/core 0.2.0 → 0.3.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 (52) hide show
  1. package/dist/budget/index.d.ts +2 -0
  2. package/dist/budget/index.d.ts.map +1 -1
  3. package/dist/budget/index.js +1 -0
  4. package/dist/budget/index.js.map +1 -1
  5. package/dist/budget/reply.d.ts +67 -0
  6. package/dist/budget/reply.d.ts.map +1 -0
  7. package/dist/budget/reply.js +76 -0
  8. package/dist/budget/reply.js.map +1 -0
  9. package/dist/contracts/engine.d.ts.map +1 -1
  10. package/dist/contracts/engine.js +11 -1
  11. package/dist/contracts/engine.js.map +1 -1
  12. package/dist/contracts/orphans.d.ts +17 -0
  13. package/dist/contracts/orphans.d.ts.map +1 -1
  14. package/dist/contracts/orphans.js +19 -2
  15. package/dist/contracts/orphans.js.map +1 -1
  16. package/dist/graph/cross-language.d.ts +0 -7
  17. package/dist/graph/cross-language.d.ts.map +1 -1
  18. package/dist/graph/cross-language.js +36 -2
  19. package/dist/graph/cross-language.js.map +1 -1
  20. package/dist/graph/index.d.ts +2 -0
  21. package/dist/graph/index.d.ts.map +1 -1
  22. package/dist/graph/index.js +1 -0
  23. package/dist/graph/index.js.map +1 -1
  24. package/dist/graph/observed-tests.d.ts +118 -0
  25. package/dist/graph/observed-tests.d.ts.map +1 -0
  26. package/dist/graph/observed-tests.js +123 -0
  27. package/dist/graph/observed-tests.js.map +1 -0
  28. package/dist/query/index.d.ts +5 -1
  29. package/dist/query/index.d.ts.map +1 -1
  30. package/dist/query/index.js +3 -1
  31. package/dist/query/index.js.map +1 -1
  32. package/dist/query/prominence.d.ts +73 -0
  33. package/dist/query/prominence.d.ts.map +1 -0
  34. package/dist/query/prominence.js +79 -0
  35. package/dist/query/prominence.js.map +1 -0
  36. package/dist/query/test-coverage.d.ts +65 -0
  37. package/dist/query/test-coverage.d.ts.map +1 -0
  38. package/dist/query/test-coverage.js +95 -0
  39. package/dist/query/test-coverage.js.map +1 -0
  40. package/dist/query/traverse.d.ts +60 -2
  41. package/dist/query/traverse.d.ts.map +1 -1
  42. package/dist/query/traverse.js +0 -0
  43. package/dist/query/traverse.js.map +1 -1
  44. package/dist/sources/git/diff.d.ts +14 -6
  45. package/dist/sources/git/diff.d.ts.map +1 -1
  46. package/dist/sources/git/diff.js +33 -10
  47. package/dist/sources/git/diff.js.map +1 -1
  48. package/dist/store/schema.d.ts +5 -4
  49. package/dist/store/schema.d.ts.map +1 -1
  50. package/dist/store/schema.js +42 -2
  51. package/dist/store/schema.js.map +1 -1
  52. package/package.json +2 -2
@@ -0,0 +1,123 @@
1
+ /**
2
+ * `observed_tests` — the EARNED record of which tests actually ran.
3
+ *
4
+ * This is the coverage axis, and coverage is deliberately not confidence: AI
5
+ * layer §20 separates *"what I actually verified"* from *"how sure am I"*, and
6
+ * the five report categories say nothing about the first. This module is the
7
+ * carrier for that separation, ruled in
8
+ * `documents/decisions-inbox/DEC-NEXT-test-run-coverage-has-no-carrier.md`.
9
+ *
10
+ * ## Why this is a table and not an R4 edge promotion
11
+ *
12
+ * The obvious-looking design is to run the suite and promote each `TESTS` edge
13
+ * it exercised to R4, reusing {@link applyRuntimeObservations}. That is not
14
+ * available, and the reason is the same one `observe-runtime.ts`'s header
15
+ * already gives for refusing to derive edges from correlated evidence.
16
+ *
17
+ * An edge needs **two endpoints and a witnessed relationship between them**. A
18
+ * test-runner's evidence carries no stack — every item it emits has
19
+ * `stackTrace: null` — so an observed test names exactly one node, its own
20
+ * `TEST_CASE`. Nothing in the run witnesses which function that test reached.
21
+ * Pairing the test with a function that merely co-occurred in the same run
22
+ * would mint an edge from temporal coincidence, which is precisely the
23
+ * wrong-direction failure rule 2 exists to prevent, arriving through the one
24
+ * mechanism built to make the graph *more* trustworthy.
25
+ *
26
+ * So the honest fact a test run establishes is a fact about **one node**: this
27
+ * test case executed, and this is what happened. That is not an edge and R4 in
28
+ * this store is a property of an edge, so it needs a carrier of its own.
29
+ *
30
+ * ## Why EARNED
31
+ *
32
+ * Same argument as `observed_edges`, one step over. Nothing in the source says
33
+ * which tests ran — the source says which tests *exist*. A rebuild that dropped
34
+ * this table would silently turn "what I actually verified" back into "what
35
+ * might be affected", which is the exact collapse the coverage axis exists to
36
+ * prevent.
37
+ *
38
+ * ## What this module refuses to do
39
+ *
40
+ * - **Invent a node.** An observation naming a node this graph does not hold is
41
+ * refused with its reason, never created — rule 2, and the same posture
42
+ * {@link applyRuntimeObservations} takes for an edge endpoint.
43
+ * - **Accept a category error.** A test outcome against a node that is not a
44
+ * `TEST_CASE` is refused rather than written. The graph holds the id, so this
45
+ * is not a missing-node refusal; it is a claim that would make every later
46
+ * coverage read meaningless, and it is far more likely to be a resolver bug
47
+ * than a real observation.
48
+ * - **Judge anything.** No finding, no hypothesis, no report category. It
49
+ * records what ran; whether that is *enough* is a judgement for a layer above
50
+ * this one.
51
+ *
52
+ * @see `packages/core/src/graph/runtime-confirmation.ts` — the edge half.
53
+ */
54
+ const SYSTEM_CLOCK = { now: () => Date.now() };
55
+ function nodeTypeOf(driver, id) {
56
+ const row = driver.prepare("SELECT type FROM nodes WHERE id = ?").get(id);
57
+ return row?.type;
58
+ }
59
+ /**
60
+ * Record a run's test observations.
61
+ *
62
+ * Total over its input: every observation lands in exactly one of
63
+ * {@link ObservedTestsResult.recorded} or {@link ObservedTestsResult.refused},
64
+ * so a caller can account for all of them without inspecting the store. Never
65
+ * throws for an observation it cannot act on — that is a refusal, per the
66
+ * five-result-states rule the tool contract applies one layer up.
67
+ */
68
+ export function applyObservedTests(driver, input, clock = SYSTEM_CLOCK) {
69
+ const recorded = [];
70
+ const refused = [];
71
+ const now = clock.now();
72
+ driver.transaction(() => {
73
+ for (const observation of input.observations) {
74
+ const type = nodeTypeOf(driver, observation.nodeId);
75
+ if (type === undefined) {
76
+ refused.push({
77
+ nodeId: observation.nodeId,
78
+ qualifiedName: observation.qualifiedName,
79
+ reason: `${observation.nodeId} is not in this graph, so the observed test cannot be recorded against it. ` +
80
+ "The graph is not extended from a runtime name.",
81
+ });
82
+ continue;
83
+ }
84
+ if (type !== "TEST_CASE") {
85
+ refused.push({
86
+ nodeId: observation.nodeId,
87
+ qualifiedName: observation.qualifiedName,
88
+ reason: `${observation.nodeId} is a ${type}, not a TEST_CASE — a test outcome recorded against it would ` +
89
+ "make every later coverage read meaningless. Refused rather than written.",
90
+ });
91
+ continue;
92
+ }
93
+ driver
94
+ .prepare("INSERT INTO observed_tests (node_id, run_id, qualified_name, outcome, duration_ms, commit_sha, observed_at)" +
95
+ " VALUES (?, ?, ?, ?, ?, ?, ?)" +
96
+ " ON CONFLICT(node_id, run_id) DO UPDATE SET qualified_name = excluded.qualified_name," +
97
+ " outcome = excluded.outcome, duration_ms = excluded.duration_ms, observed_at = excluded.observed_at")
98
+ .run(observation.nodeId, input.runId, observation.qualifiedName, observation.outcome, observation.durationMs, input.commitSha, now);
99
+ recorded.push(observation.nodeId);
100
+ }
101
+ });
102
+ return { recorded, refused };
103
+ }
104
+ /** Read the EARNED ledger, newest observation first, optionally for one run. */
105
+ export function observedTests(driver, options = {}) {
106
+ const where = options.runId === undefined ? "" : " WHERE run_id = ?";
107
+ const sql = "SELECT node_id, run_id, qualified_name, outcome, duration_ms, commit_sha, observed_at" +
108
+ ` FROM observed_tests${where} ORDER BY observed_at DESC, node_id ASC`;
109
+ const args = options.runId === undefined ? [] : [options.runId];
110
+ return driver
111
+ .prepare(sql)
112
+ .all(...args)
113
+ .map((row) => ({
114
+ nodeId: row.node_id,
115
+ runId: row.run_id,
116
+ qualifiedName: row.qualified_name,
117
+ outcome: row.outcome,
118
+ durationMs: row.duration_ms,
119
+ commitSha: row.commit_sha,
120
+ observedAt: row.observed_at,
121
+ }));
122
+ }
123
+ //# sourceMappingURL=observed-tests.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"observed-tests.js","sourceRoot":"","sources":["../../src/graph/observed-tests.ts"],"names":[],"mappings":"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"}
@@ -3,7 +3,7 @@ export type { AdjacencyProvider, AdjacencyOptions, GraphStamp, QueryResult, } fr
3
3
  export { createMemoryProvider } from "./memory.ts";
4
4
  export type { MemoryGraph } from "./memory.ts";
5
5
  export { createStoreProvider, commitSpread } from "./sqlite.ts";
6
- export { bfs, weightedBfs, findPath, API_JOIN_EDGE_TYPES } from "./traverse.ts";
6
+ export { bfs, weightedBfs, findPath, defaultTraversalWeight, API_JOIN_EDGE_TYPES } from "./traverse.ts";
7
7
  export type { Direction, Reached, TraversalOptions, TraversalOutcome, WeightedOptions } from "./traverse.ts";
8
8
  export { impactOf, rootCauseSearch, testsCovering, dataFlowFrom, DATA_FLOW_EDGE_TYPES, traceApi, changeRisk, changesWith, } from "./queries.ts";
9
9
  export type { ImpactOptions, RootCauseMatch, ChangeRisk, CoChange } from "./queries.ts";
@@ -18,6 +18,10 @@ export type { RefusalSite, RefusalQuestion, RefusalDropCounts, GroupingResult, }
18
18
  export { summariseRefusals, fetchRefusalPage } from "./refusal-fetch.ts";
19
19
  export type { RefusalSummary, RefusalPage, RefusalPageOk, RefusalPageRefused } from "./refusal-fetch.ts";
20
20
  export { computeVerificationStatus, resolutionOfExercised } from "./verification-status.ts";
21
+ export { observedTestCoverage } from "./test-coverage.ts";
22
+ export type { ObservedTestFor, TestCoverageForRef } from "./test-coverage.ts";
23
+ export { prominenceOf, withProminence, prominenceCounts, PROMINENCE_CUTOFFS } from "./prominence.ts";
24
+ export type { Prominence, Ranked } from "./prominence.ts";
21
25
  export type { CoverageCheck, ScopeItem } from "./verification-status.ts";
22
26
  export { applyDeclaredValues, DECLARED_VALUE_RELIABILITY } from "./declared-value-closure.ts";
23
27
  export type { ClosureState, DeclaredValueClosure, DeclaredValueApplication, } from "./declared-value-closure.ts";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/query/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AACjE,YAAY,EACV,iBAAiB,EACjB,gBAAgB,EAChB,UAAU,EACV,WAAW,GACZ,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACnD,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,OAAO,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhE,OAAO,EAAE,GAAG,EAAE,WAAW,EAAE,QAAQ,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAChF,YAAY,EAAE,SAAS,EAAE,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAE7G,OAAO,EACL,QAAQ,EACR,eAAe,EACf,aAAa,EACb,YAAY,EACZ,oBAAoB,EACpB,QAAQ,EACR,UAAU,EACV,WAAW,GACZ,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAExF,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AACrG,YAAY,EACV,mBAAmB,EACnB,oBAAoB,EACpB,sBAAsB,EACtB,qBAAqB,EACrB,yBAAyB,GAC1B,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC9E,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAE3F,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC3D,YAAY,EAAE,wBAAwB,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAEzF,OAAO,EAAE,0BAA0B,EAAE,wBAAwB,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAC7G,YAAY,EACV,WAAW,EACX,eAAe,EACf,iBAAiB,EACjB,cAAc,GACf,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACzE,YAAY,EAAE,cAAc,EAAE,WAAW,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAEzG,OAAO,EAAE,yBAAyB,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAC5F,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAEzE,OAAO,EAAE,mBAAmB,EAAE,0BAA0B,EAAE,MAAM,6BAA6B,CAAC;AAC9F,YAAY,EACV,YAAY,EACZ,oBAAoB,EACpB,wBAAwB,GACzB,MAAM,6BAA6B,CAAC;AAErC,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,YAAY,EACV,gBAAgB,EAChB,aAAa,EACb,iBAAiB,EACjB,qBAAqB,GACtB,MAAM,0BAA0B,CAAC;AAElC,OAAO,EAAE,aAAa,EAAE,0BAA0B,EAAE,2BAA2B,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AACpI,YAAY,EACV,gBAAgB,EAChB,gBAAgB,EAChB,wBAAwB,EACxB,gBAAgB,EAChB,sBAAsB,GACvB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,YAAY,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/query/index.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  export { rankEdges, applyAdjacencyOptions } from "./provider.js";
2
2
  export { createMemoryProvider } from "./memory.js";
3
3
  export { createStoreProvider, commitSpread } from "./sqlite.js";
4
- export { bfs, weightedBfs, findPath, API_JOIN_EDGE_TYPES } from "./traverse.js";
4
+ export { bfs, weightedBfs, findPath, defaultTraversalWeight, API_JOIN_EDGE_TYPES } from "./traverse.js";
5
5
  export { impactOf, rootCauseSearch, testsCovering, dataFlowFrom, DATA_FLOW_EDGE_TYPES, traceApi, changeRisk, changesWith, } from "./queries.js";
6
6
  export { similarIncidents, tokenSetSimilarity, fileOverlapSimilarity } from "./similar-incidents.js";
7
7
  export { classifyRefusal, classifyRefusals, readRate } from "./unresolved.js";
@@ -9,6 +9,8 @@ export { applyConfirmedFacts } from "./confirmed-facts.js";
9
9
  export { groupRefusalsIntoQuestions, groupRefusalsAcrossRepos, askableHandle } from "./refusal-questions.js";
10
10
  export { summariseRefusals, fetchRefusalPage } from "./refusal-fetch.js";
11
11
  export { computeVerificationStatus, resolutionOfExercised } from "./verification-status.js";
12
+ export { observedTestCoverage } from "./test-coverage.js";
13
+ export { prominenceOf, withProminence, prominenceCounts, PROMINENCE_CUTOFFS } from "./prominence.js";
12
14
  export { applyDeclaredValues, DECLARED_VALUE_RELIABILITY } from "./declared-value-closure.js";
13
15
  export { describeRowClosures } from "./row-closure-picture.js";
14
16
  export { rankRootCause, DEFAULT_ROOT_CAUSE_WEIGHTS, ROOT_CAUSE_TRACE_EDGE_TYPES, INCIDENT_SATURATION } from "./root-cause-score.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/query/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAQjE,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAGnD,OAAO,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhE,OAAO,EAAE,GAAG,EAAE,WAAW,EAAE,QAAQ,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAGhF,OAAO,EACL,QAAQ,EACR,eAAe,EACf,aAAa,EACb,YAAY,EACZ,oBAAoB,EACpB,QAAQ,EACR,UAAU,EACV,WAAW,GACZ,MAAM,cAAc,CAAC;AAGtB,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AASrG,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAG9E,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAG3D,OAAO,EAAE,0BAA0B,EAAE,wBAAwB,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAQ7G,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAGzE,OAAO,EAAE,yBAAyB,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAG5F,OAAO,EAAE,mBAAmB,EAAE,0BAA0B,EAAE,MAAM,6BAA6B,CAAC;AAO9F,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAQ/D,OAAO,EAAE,aAAa,EAAE,0BAA0B,EAAE,2BAA2B,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AASpI,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/query/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAQjE,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAGnD,OAAO,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhE,OAAO,EAAE,GAAG,EAAE,WAAW,EAAE,QAAQ,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAGxG,OAAO,EACL,QAAQ,EACR,eAAe,EACf,aAAa,EACb,YAAY,EACZ,oBAAoB,EACpB,QAAQ,EACR,UAAU,EACV,WAAW,GACZ,MAAM,cAAc,CAAC;AAGtB,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AASrG,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAG9E,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAG3D,OAAO,EAAE,0BAA0B,EAAE,wBAAwB,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAQ7G,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAGzE,OAAO,EAAE,yBAAyB,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAC5F,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAE1D,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAIrG,OAAO,EAAE,mBAAmB,EAAE,0BAA0B,EAAE,MAAM,6BAA6B,CAAC;AAO9F,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAQ/D,OAAO,EAAE,aAAa,EAAE,0BAA0B,EAAE,2BAA2B,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AASpI,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC"}
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Prominence — "show me the top few, not a flat list", without borrowing a
3
+ * calibration that does not apply.
4
+ *
5
+ * ## Why this is not `tierFor`
6
+ *
7
+ * `scoping/tiers.ts` already bands a score into §12.7's tiers 1-4 on **absolute
8
+ * thresholds** (0.7 and 0.3). Reusing it here was the obvious move and it is
9
+ * the wrong one, for a reason that is invisible from the type: the two scores
10
+ * are different quantities that happen to share the range (0, 1].
11
+ *
12
+ * - `scope` scores through `scoping/`: designed per-edge weights, then
13
+ * `finalScore` applies co-change and incident boosts. `weights.ts` says in
14
+ * its own comment that these must "stay on the same scale as an absolute tier
15
+ * threshold" — the thresholds were calibrated against *this* pipeline.
16
+ * - `impact` and `pr_analysis` score through `weightedBfs`, whose default
17
+ * `weightFor` is `edge.confidence` and nothing else. No designed weights, no
18
+ * boosts. `pr_analysis` passes only a budget, so it takes that default.
19
+ *
20
+ * Feeding the second into thresholds calibrated for the first would produce
21
+ * bands that look like §12.7's and mean something else — a calibrated label on
22
+ * an uncalibrated number, which is worse than no band at all because it reads
23
+ * as more precise than it is.
24
+ *
25
+ * ## So this bands on rank, and rank is a fact about the answer
26
+ *
27
+ * "This was the highest-scoring item in this reply" is true whatever produced
28
+ * the score, and it is exactly what "show me the top few" asks for. It claims
29
+ * nothing about magnitude, nothing about a threshold, and nothing that a change
30
+ * of scoring pipeline could silently falsify.
31
+ *
32
+ * The cut-offs are reading-surface sizes rather than measurements — the same
33
+ * footing `NODE_BUDGETS`'s own comment puts its figures on. Tune from data.
34
+ */
35
+ /** Where an item falls in its answer's own ordering. */
36
+ export type Prominence = "top" | "notable" | "rest";
37
+ /**
38
+ * Rank cut-offs, inclusive upper bounds.
39
+ *
40
+ * `top` is three because that is what a developer reads before acting; the
41
+ * same figure `FINDING_CAPS["pre-push"]` reaches independently, from the same
42
+ * reasoning about a blocked developer's attention. It is **not** imported from
43
+ * there: that cap governs findings through the governance funnel, this governs
44
+ * presentation ordering, and coupling them would make a change to either mean
45
+ * a change to both.
46
+ */
47
+ export declare const PROMINENCE_CUTOFFS: {
48
+ readonly top: 3;
49
+ readonly notable: 10;
50
+ };
51
+ /** `rank` is 1-based: the highest-scoring item in an answer is rank 1. */
52
+ export declare function prominenceOf(rank: number): Prominence;
53
+ export interface Ranked {
54
+ /** 1-based position in this answer, highest score first. */
55
+ readonly rank: number;
56
+ readonly prominence: Prominence;
57
+ }
58
+ /**
59
+ * Attach `rank` and `prominence` to items already ordered highest-first.
60
+ *
61
+ * Deliberately does **not** sort. Every caller here already orders its own
62
+ * list, and re-sorting would either be a no-op or silently disagree with the
63
+ * order the caller reported elsewhere in the same reply. Ranking a list that
64
+ * is not in score order is a caller bug this function cannot detect, which is
65
+ * why it says so here rather than pretending to be total over any input.
66
+ */
67
+ export declare function withProminence<T>(ordered: readonly T[]): readonly (T & Ranked)[];
68
+ /**
69
+ * How many of each band a list holds — the counts a reply shows so a reader
70
+ * knows what the shown items were selected from.
71
+ */
72
+ export declare function prominenceCounts(total: number): Readonly<Record<Prominence, number>>;
73
+ //# sourceMappingURL=prominence.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prominence.d.ts","sourceRoot":"","sources":["../../src/query/prominence.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,wDAAwD;AACxD,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG,SAAS,GAAG,MAAM,CAAC;AAEpD;;;;;;;;;GASG;AACH,eAAO,MAAM,kBAAkB;;;CAAmC,CAAC;AAEnE,0EAA0E;AAC1E,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAIrD;AAED,MAAM,WAAW,MAAM;IACrB,4DAA4D;IAC5D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;CACjC;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,OAAO,EAAE,SAAS,CAAC,EAAE,GAAG,SAAS,CAAC,CAAC,GAAG,MAAM,CAAC,EAAE,CAMhF;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,CAIpF"}
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Prominence — "show me the top few, not a flat list", without borrowing a
3
+ * calibration that does not apply.
4
+ *
5
+ * ## Why this is not `tierFor`
6
+ *
7
+ * `scoping/tiers.ts` already bands a score into §12.7's tiers 1-4 on **absolute
8
+ * thresholds** (0.7 and 0.3). Reusing it here was the obvious move and it is
9
+ * the wrong one, for a reason that is invisible from the type: the two scores
10
+ * are different quantities that happen to share the range (0, 1].
11
+ *
12
+ * - `scope` scores through `scoping/`: designed per-edge weights, then
13
+ * `finalScore` applies co-change and incident boosts. `weights.ts` says in
14
+ * its own comment that these must "stay on the same scale as an absolute tier
15
+ * threshold" — the thresholds were calibrated against *this* pipeline.
16
+ * - `impact` and `pr_analysis` score through `weightedBfs`, whose default
17
+ * `weightFor` is `edge.confidence` and nothing else. No designed weights, no
18
+ * boosts. `pr_analysis` passes only a budget, so it takes that default.
19
+ *
20
+ * Feeding the second into thresholds calibrated for the first would produce
21
+ * bands that look like §12.7's and mean something else — a calibrated label on
22
+ * an uncalibrated number, which is worse than no band at all because it reads
23
+ * as more precise than it is.
24
+ *
25
+ * ## So this bands on rank, and rank is a fact about the answer
26
+ *
27
+ * "This was the highest-scoring item in this reply" is true whatever produced
28
+ * the score, and it is exactly what "show me the top few" asks for. It claims
29
+ * nothing about magnitude, nothing about a threshold, and nothing that a change
30
+ * of scoring pipeline could silently falsify.
31
+ *
32
+ * The cut-offs are reading-surface sizes rather than measurements — the same
33
+ * footing `NODE_BUDGETS`'s own comment puts its figures on. Tune from data.
34
+ */
35
+ /**
36
+ * Rank cut-offs, inclusive upper bounds.
37
+ *
38
+ * `top` is three because that is what a developer reads before acting; the
39
+ * same figure `FINDING_CAPS["pre-push"]` reaches independently, from the same
40
+ * reasoning about a blocked developer's attention. It is **not** imported from
41
+ * there: that cap governs findings through the governance funnel, this governs
42
+ * presentation ordering, and coupling them would make a change to either mean
43
+ * a change to both.
44
+ */
45
+ export const PROMINENCE_CUTOFFS = { top: 3, notable: 10 };
46
+ /** `rank` is 1-based: the highest-scoring item in an answer is rank 1. */
47
+ export function prominenceOf(rank) {
48
+ if (rank <= PROMINENCE_CUTOFFS.top)
49
+ return "top";
50
+ if (rank <= PROMINENCE_CUTOFFS.notable)
51
+ return "notable";
52
+ return "rest";
53
+ }
54
+ /**
55
+ * Attach `rank` and `prominence` to items already ordered highest-first.
56
+ *
57
+ * Deliberately does **not** sort. Every caller here already orders its own
58
+ * list, and re-sorting would either be a no-op or silently disagree with the
59
+ * order the caller reported elsewhere in the same reply. Ranking a list that
60
+ * is not in score order is a caller bug this function cannot detect, which is
61
+ * why it says so here rather than pretending to be total over any input.
62
+ */
63
+ export function withProminence(ordered) {
64
+ return ordered.map((item, index) => ({
65
+ ...item,
66
+ rank: index + 1,
67
+ prominence: prominenceOf(index + 1),
68
+ }));
69
+ }
70
+ /**
71
+ * How many of each band a list holds — the counts a reply shows so a reader
72
+ * knows what the shown items were selected from.
73
+ */
74
+ export function prominenceCounts(total) {
75
+ const top = Math.min(total, PROMINENCE_CUTOFFS.top);
76
+ const notable = Math.max(0, Math.min(total, PROMINENCE_CUTOFFS.notable) - top);
77
+ return { top, notable, rest: Math.max(0, total - top - notable) };
78
+ }
79
+ //# sourceMappingURL=prominence.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prominence.js","sourceRoot":"","sources":["../../src/query/prominence.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAKH;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,EAAE,GAAG,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,EAAW,CAAC;AAEnE,0EAA0E;AAC1E,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,IAAI,IAAI,IAAI,kBAAkB,CAAC,GAAG;QAAE,OAAO,KAAK,CAAC;IACjD,IAAI,IAAI,IAAI,kBAAkB,CAAC,OAAO;QAAE,OAAO,SAAS,CAAC;IACzD,OAAO,MAAM,CAAC;AAChB,CAAC;AAQD;;;;;;;;GAQG;AACH,MAAM,UAAU,cAAc,CAAI,OAAqB;IACrD,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;QACnC,GAAG,IAAI;QACP,IAAI,EAAE,KAAK,GAAG,CAAC;QACf,UAAU,EAAE,YAAY,CAAC,KAAK,GAAG,CAAC,CAAC;KACpC,CAAC,CAAC,CAAC;AACN,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAa;IAC5C,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,kBAAkB,CAAC,GAAG,CAAC,CAAC;IACpD,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,kBAAkB,CAAC,OAAO,CAAC,GAAG,GAAG,CAAC,CAAC;IAC/E,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,GAAG,GAAG,GAAG,OAAO,CAAC,EAAE,CAAC;AACpE,CAAC"}
@@ -0,0 +1,65 @@
1
+ /**
2
+ * The join from `observed_tests` to the code a caller actually asked about.
3
+ *
4
+ * `observed_tests` records facts about `TEST_CASE` nodes: this test ran, and
5
+ * this is how it finished. Almost nobody asks about a test case. They ask about
6
+ * a function, a file, a scope from an earlier `impact` call, and getting from
7
+ * one to the other crosses a `TESTS` edge.
8
+ *
9
+ * ## What the crossing costs, and why it is disclosed rather than hidden
10
+ *
11
+ * The `TESTS` edge is **static**. An adapter inferred it, at whatever
12
+ * resolution that adapter reached, and nothing in a test run witnesses it: the
13
+ * run witnessed that a test executed, not which functions it touched. So the
14
+ * honest claim this query supports is *"a test that claims to cover this ran,
15
+ * and here is how it finished"* and **not** *"this function executed"*. The two
16
+ * are close enough in English to be conflated by a reader in a hurry, and far
17
+ * enough apart that conflating them turns an inference into a fabricated
18
+ * observation. {@link ObservedTestFor} carries `direct` for exactly this
19
+ * reason: `true` means the caller asked about the test case itself and the
20
+ * answer is witnessed end to end; `false` means the answer leans on an edge no
21
+ * run confirmed.
22
+ *
23
+ * That is also why this lives here rather than inside
24
+ * `computeVerificationStatus`. That module's contract is the *static* half, it
25
+ * says so in its own header, and it stays that way. Composing the static half
26
+ * with this earned one is the tool layer's job, the same place `observe_runtime`
27
+ * composes rather than absorbs.
28
+ *
29
+ * ## Absent, not empty
30
+ *
31
+ * A node no observed test reaches is missing from the returned map rather than
32
+ * present with an empty list. Inventing a key would let a caller iterate the
33
+ * map and believe it had asked about everything.
34
+ */
35
+ import type { ObservedTestOutcome } from "../graph/observed-tests.ts";
36
+ import type { SqlDriver } from "../store/driver/driver.ts";
37
+ export interface ObservedTestFor {
38
+ /** The `TEST_CASE` node that ran. */
39
+ readonly nodeId: string;
40
+ /** The name the run itself printed. */
41
+ readonly qualifiedName: string;
42
+ readonly outcome: ObservedTestOutcome;
43
+ readonly runId: string;
44
+ readonly observedAt: number;
45
+ /**
46
+ * `true` when the caller asked about this very test case, witnessed end to
47
+ * end. `false` when the answer was reached across a static `TESTS` edge,
48
+ * which no run confirmed. See the module header.
49
+ */
50
+ readonly direct: boolean;
51
+ }
52
+ export interface TestCoverageForRef {
53
+ readonly ref: string;
54
+ readonly tests: readonly ObservedTestFor[];
55
+ }
56
+ /**
57
+ * For each requested node id, the observed tests that bear on it.
58
+ *
59
+ * One test contributes at most one entry per ref: a test re-run across several
60
+ * runs is still one test, and the **most recent** observation is what the code
61
+ * stands verified against now. Reporting every historical run instead would
62
+ * make a flaky test look like broad coverage.
63
+ */
64
+ export declare function observedTestCoverage(driver: SqlDriver, refs: readonly string[]): ReadonlyMap<string, TestCoverageForRef>;
65
+ //# sourceMappingURL=test-coverage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-coverage.d.ts","sourceRoot":"","sources":["../../src/query/test-coverage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACtE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAE3D,MAAM,WAAW,eAAe;IAC9B,qCAAqC;IACrC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,uCAAuC;IACvC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,OAAO,EAAE,mBAAmB,CAAC;IACtC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B;;;;OAIG;IACH,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,KAAK,EAAE,SAAS,eAAe,EAAE,CAAC;CAC5C;AAaD;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,SAAS,EACjB,IAAI,EAAE,SAAS,MAAM,EAAE,GACtB,WAAW,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAwDzC"}
@@ -0,0 +1,95 @@
1
+ /**
2
+ * The join from `observed_tests` to the code a caller actually asked about.
3
+ *
4
+ * `observed_tests` records facts about `TEST_CASE` nodes: this test ran, and
5
+ * this is how it finished. Almost nobody asks about a test case. They ask about
6
+ * a function, a file, a scope from an earlier `impact` call, and getting from
7
+ * one to the other crosses a `TESTS` edge.
8
+ *
9
+ * ## What the crossing costs, and why it is disclosed rather than hidden
10
+ *
11
+ * The `TESTS` edge is **static**. An adapter inferred it, at whatever
12
+ * resolution that adapter reached, and nothing in a test run witnesses it: the
13
+ * run witnessed that a test executed, not which functions it touched. So the
14
+ * honest claim this query supports is *"a test that claims to cover this ran,
15
+ * and here is how it finished"* and **not** *"this function executed"*. The two
16
+ * are close enough in English to be conflated by a reader in a hurry, and far
17
+ * enough apart that conflating them turns an inference into a fabricated
18
+ * observation. {@link ObservedTestFor} carries `direct` for exactly this
19
+ * reason: `true` means the caller asked about the test case itself and the
20
+ * answer is witnessed end to end; `false` means the answer leans on an edge no
21
+ * run confirmed.
22
+ *
23
+ * That is also why this lives here rather than inside
24
+ * `computeVerificationStatus`. That module's contract is the *static* half, it
25
+ * says so in its own header, and it stays that way. Composing the static half
26
+ * with this earned one is the tool layer's job, the same place `observe_runtime`
27
+ * composes rather than absorbs.
28
+ *
29
+ * ## Absent, not empty
30
+ *
31
+ * A node no observed test reaches is missing from the returned map rather than
32
+ * present with an empty list. Inventing a key would let a caller iterate the
33
+ * map and believe it had asked about everything.
34
+ */
35
+ /**
36
+ * For each requested node id, the observed tests that bear on it.
37
+ *
38
+ * One test contributes at most one entry per ref: a test re-run across several
39
+ * runs is still one test, and the **most recent** observation is what the code
40
+ * stands verified against now. Reporting every historical run instead would
41
+ * make a flaky test look like broad coverage.
42
+ */
43
+ export function observedTestCoverage(driver, refs) {
44
+ const out = new Map();
45
+ if (refs.length === 0)
46
+ return out;
47
+ const placeholders = refs.map(() => "?").join(", ");
48
+ // Two arms, unioned rather than fetched separately so the de-duplication
49
+ // below sees both at once: a test case that both ran itself and is joined to
50
+ // by a TESTS edge must not be counted twice for one subject.
51
+ const sql = "SELECT e.target AS subject, o.node_id, o.qualified_name, o.outcome, o.run_id, o.observed_at," +
52
+ " 0 AS direct, o.rowid AS seq" +
53
+ " FROM observed_tests o" +
54
+ " JOIN edges e ON e.source = o.node_id AND e.type = 'TESTS'" +
55
+ ` WHERE e.target IN (${placeholders})` +
56
+ " UNION ALL " +
57
+ "SELECT o.node_id AS subject, o.node_id, o.qualified_name, o.outcome, o.run_id, o.observed_at," +
58
+ " 1 AS direct, o.rowid AS seq" +
59
+ " FROM observed_tests o" +
60
+ ` WHERE o.node_id IN (${placeholders})` +
61
+ // `seq` breaks the tie, and the tie is real rather than theoretical: two
62
+ // runs of one suite land in the same millisecond easily, and `observed_at`
63
+ // alone then leaves SQLite free to return the older run first. That made
64
+ // this query answer "verified against a failing run" when a later run had
65
+ // passed. rowid is monotonic for an ordinary (non-WITHOUT ROWID) table, so
66
+ // ordering by it is exactly "whichever row was written last" -- which is
67
+ // the semantics the timestamp was reaching for and could not express at
68
+ // millisecond resolution.
69
+ " ORDER BY observed_at DESC, seq DESC, node_id ASC";
70
+ const rows = driver.prepare(sql).all(...refs, ...refs);
71
+ // Rows arrive newest first, so the first sighting of a (subject, test) pair
72
+ // is the observation that stands. Later ones are older runs of the same test.
73
+ const seen = new Set();
74
+ for (const row of rows) {
75
+ const key = `${row.subject} ${row.node_id}`;
76
+ if (seen.has(key))
77
+ continue;
78
+ seen.add(key);
79
+ const entry = {
80
+ nodeId: row.node_id,
81
+ qualifiedName: row.qualified_name,
82
+ outcome: row.outcome,
83
+ runId: row.run_id,
84
+ observedAt: row.observed_at,
85
+ direct: row.direct === 1,
86
+ };
87
+ const existing = out.get(row.subject);
88
+ out.set(row.subject, {
89
+ ref: row.subject,
90
+ tests: existing === undefined ? [entry] : [...existing.tests, entry],
91
+ });
92
+ }
93
+ return out;
94
+ }
95
+ //# sourceMappingURL=test-coverage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-coverage.js","sourceRoot":"","sources":["../../src/query/test-coverage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAqCH;;;;;;;GAOG;AACH,MAAM,UAAU,oBAAoB,CAClC,MAAiB,EACjB,IAAuB;IAEvB,MAAM,GAAG,GAAG,IAAI,GAAG,EAA8B,CAAC;IAClD,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,GAAG,CAAC;IAElC,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACpD,yEAAyE;IACzE,6EAA6E;IAC7E,6DAA6D;IAC7D,MAAM,GAAG,GACP,8FAA8F;QAC9F,8BAA8B;QAC9B,wBAAwB;QACxB,4DAA4D;QAC5D,uBAAuB,YAAY,GAAG;QACtC,aAAa;QACb,+FAA+F;QAC/F,8BAA8B;QAC9B,wBAAwB;QACxB,wBAAwB,YAAY,GAAG;QACvC,yEAAyE;QACzE,2EAA2E;QAC3E,yEAAyE;QACzE,0EAA0E;QAC1E,2EAA2E;QAC3E,yEAAyE;QACzE,wEAAwE;QACxE,0BAA0B;QAC1B,mDAAmD,CAAC;IAEtD,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAc,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,IAAI,EAAE,GAAG,IAAI,CAAC,CAAC;IAEpE,4EAA4E;IAC5E,8EAA8E;IAC9E,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,GAAG,GAAG,GAAG,GAAG,CAAC,OAAO,IAAI,GAAG,CAAC,OAAO,EAAE,CAAC;QAC5C,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,SAAS;QAC5B,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAEd,MAAM,KAAK,GAAoB;YAC7B,MAAM,EAAE,GAAG,CAAC,OAAO;YACnB,aAAa,EAAE,GAAG,CAAC,cAAc;YACjC,OAAO,EAAE,GAAG,CAAC,OAA8B;YAC3C,KAAK,EAAE,GAAG,CAAC,MAAM;YACjB,UAAU,EAAE,GAAG,CAAC,WAAW;YAC3B,MAAM,EAAE,GAAG,CAAC,MAAM,KAAK,CAAC;SACzB,CAAC;QAEF,MAAM,QAAQ,GAAG,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACtC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,EAAE;YACnB,GAAG,EAAE,GAAG,CAAC,OAAO;YAChB,KAAK,EAAE,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;SACrE,CAAC,CAAC;IACL,CAAC;IAED,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -24,6 +24,43 @@
24
24
  * improvement (relaxation), and any hop whose combined factor reaches 1.0 is
25
25
  * rejected with an error naming the edge. Step 12 supplies the weights; this is
26
26
  * the layer that refuses to run with weights that cannot terminate.
27
+ *
28
+ * ## Confidence is not the traversal weight
29
+ *
30
+ * This module's default `weightFor` used to be `edge.confidence` and nothing
31
+ * else, which made two shipped modules contradict each other. `runtime-
32
+ * confirmation.ts` writes `confidence = 1.0` on every edge it promotes or mints
33
+ * at R4 — correctly, because rule 3 makes R4 unconditionally class A and a
34
+ * witnessed edge is not 99% believed. The old default then handed that same 1.0
35
+ * to the guard above as a *weight*, so the strongest edge in the graph was the
36
+ * one edge `impact` refused to walk. Any graph that had ever had a runtime
37
+ * observation applied threw.
38
+ *
39
+ * The two quantities were never the same thing, and `weights.ts` has said so
40
+ * all along: `validateScopingConfig` asserts
41
+ * `0 < edgeWeight x maxFanOutMultiplier x maxConfidence < 1` and notes in its
42
+ * own comment that *"maxConfidence is 1.0 by definition"*. Termination is the
43
+ * **edge weight's** job; confidence is evidence strength and is entitled to
44
+ * reach 1.0. The old default was the degenerate weight table with every edge
45
+ * type at 1.0 — precisely the configuration `validateScopingConfig` refuses to
46
+ * load. The in-process path was running a config the config loader would
47
+ * reject, while the worker path passed a real table and did not.
48
+ *
49
+ * So the default is now {@link defaultTraversalWeight}: the per-edge-type decay
50
+ * of `DEFAULT_EDGE_WEIGHTS` times the edge's confidence — the same product
51
+ * `weightFromTable` builds for the worker. Termination survives on three
52
+ * independent legs, none of which is a stored confidence value:
53
+ *
54
+ * 1. every weight in `DEFAULT_EDGE_WEIGHTS` is <= 0.95, and confidence is
55
+ * capped at 1.0 by the IR, so the per-hop factor is <= 0.95 < 1 by
56
+ * construction rather than by data;
57
+ * 2. `validateScopingConfig` refuses, at config load, any table that would
58
+ * break leg 1;
59
+ * 3. the per-hop `RangeError` below is unchanged and still refuses any weight
60
+ * outside (0, 1), which is what holds a caller-supplied `weightFor` to the
61
+ * same rule.
62
+ *
63
+ * Ruled in `DEC-386`.
27
64
  */
28
65
  import type { EdgeType, IREdge, ResolutionLevel } from "@descryy/ir";
29
66
  import type { AdjacencyProvider } from "./provider.ts";
@@ -79,11 +116,32 @@ export interface TraversalOutcome {
79
116
  * here precisely because there is no score to improve on a second visit.
80
117
  */
81
118
  export declare function bfs(provider: AdjacencyProvider, seeds: readonly string[], options?: TraversalOptions): TraversalOutcome;
119
+ /**
120
+ * The default per-hop decay: §12.4's `EdgeWeight` for the edge's *type*, times
121
+ * the edge's own confidence.
122
+ *
123
+ * Both terms are §12.4's, and neither one alone is the weight. Confidence
124
+ * carries how much the producer believes the edge; the type weight carries how
125
+ * far a change actually travels along that kind of edge — an `IMPORTS` hop at
126
+ * 0.4 is a weak signal even when it is certain, and a witnessed `CALLS` hop at
127
+ * 0.95 x 1.0 is strong precisely because it was witnessed.
128
+ *
129
+ * Exported so a caller can compose with it rather than reconstruct it, and so
130
+ * the in-process and worker paths are demonstrably the same function — see the
131
+ * parity test in `worker.test.ts`. It is the callback form of
132
+ * `weightFromTable({ weights: DEFAULT_EDGE_WEIGHTS, fallback: ... })`.
133
+ */
134
+ export declare function defaultTraversalWeight(edge: {
135
+ readonly type: EdgeType;
136
+ readonly confidence: number;
137
+ }): number;
82
138
  export interface WeightedOptions extends TraversalOptions {
83
139
  /**
84
140
  * The per-hop decay factor for an edge. Must be strictly less than 1.0 —
85
- * see the note at the top of this file. Defaults to the edge's own confidence,
86
- * which §12.4 makes one term of the real formula.
141
+ * see the note at the top of this file. Defaults to
142
+ * {@link defaultTraversalWeight}: the edge type's §12.4 weight times the
143
+ * edge's confidence. **Not confidence alone** — that conflated evidence
144
+ * strength with decay and made a witnessed R4 edge untraversable.
87
145
  */
88
146
  readonly weightFor?: (edge: IREdge) => number;
89
147
  /** Stop expanding below this score. The main reason traversal ends before the budget. */
@@ -1 +1 @@
1
- {"version":3,"file":"traverse.d.ts","sourceRoot":"","sources":["../../src/query/traverse.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAIrE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAEvD,MAAM,MAAM,SAAS,GAAG,KAAK,GAAG,IAAI,GAAG,MAAM,CAAC;AAE9C;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,EAAE,SAAS,QAAQ,EAA+B,CAAC;AAEnF,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,QAAQ,EAAE,CAAC;IACrC,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,CAAC;IAC/B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,kFAAkF;IAClF,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,qFAAqF;IACrF,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,gBAAgB,CAAC,EAAE,OAAO,CAAC;CACrC;AAED,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,8EAA8E;IAC9E,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,+EAA+E;IAC/E,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,OAAO,EAAE,SAAS,OAAO,EAAE,CAAC;IACrC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,sFAAsF;IACtF,QAAQ,CAAC,eAAe,EAAE,eAAe,CAAC;CAC3C;AA2CD;;;;;GAKG;AACH,wBAAgB,GAAG,CACjB,QAAQ,EAAE,iBAAiB,EAC3B,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,OAAO,GAAE,gBAAqB,GAC7B,gBAAgB,CAqClB;AAED,MAAM,WAAW,eAAgB,SAAQ,gBAAgB;IACvD;;;;OAIG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IAC9C,yFAAyF;IACzF,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CACzB,QAAQ,EAAE,iBAAiB,EAC3B,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,OAAO,GAAE,eAAoB,GAC5B,gBAAgB,CAyDlB;AAED;;;;;;GAMG;AACH,wBAAgB,QAAQ,CACtB,QAAQ,EAAE,iBAAiB,EAC3B,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,EACV,OAAO,GAAE,gBAAqB,GAC7B,SAAS,MAAM,EAAE,CA8BnB"}
1
+ {"version":3,"file":"traverse.d.ts","sourceRoot":"","sources":["../../src/query/traverse.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+DG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAMrE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAEvD,MAAM,MAAM,SAAS,GAAG,KAAK,GAAG,IAAI,GAAG,MAAM,CAAC;AAE9C;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,EAAE,SAAS,QAAQ,EAA+B,CAAC;AAEnF,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,QAAQ,EAAE,CAAC;IACrC,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,CAAC;IAC/B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,kFAAkF;IAClF,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,qFAAqF;IACrF,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,gBAAgB,CAAC,EAAE,OAAO,CAAC;CACrC;AAED,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,8EAA8E;IAC9E,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,+EAA+E;IAC/E,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,OAAO,EAAE,SAAS,OAAO,EAAE,CAAC;IACrC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,sFAAsF;IACtF,QAAQ,CAAC,eAAe,EAAE,eAAe,CAAC;CAC3C;AA2CD;;;;;GAKG;AACH,wBAAgB,GAAG,CACjB,QAAQ,EAAE,iBAAiB,EAC3B,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,OAAO,GAAE,gBAAqB,GAC7B,gBAAgB,CAqClB;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAE7G;AAED,MAAM,WAAW,eAAgB,SAAQ,gBAAgB;IACvD;;;;;;OAMG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IAC9C,yFAAyF;IACzF,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CACzB,QAAQ,EAAE,iBAAiB,EAC3B,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,OAAO,GAAE,eAAoB,GAC5B,gBAAgB,CAyDlB;AAED;;;;;;GAMG;AACH,wBAAgB,QAAQ,CACtB,QAAQ,EAAE,iBAAiB,EAC3B,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,EACV,OAAO,GAAE,gBAAqB,GAC7B,SAAS,MAAM,EAAE,CA8BnB"}
Binary file