@weftlet/toolkit 0.7.2 → 0.7.3

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/README.md CHANGED
@@ -14,7 +14,7 @@ Proposed future capabilities are recorded in the [Weftlet 2.0 product plan](docs
14
14
  ## Set up a project
15
15
 
16
16
  <!-- weftlet:release:start -->
17
- Package versions in this checkout/archive: `@weftlet/toolkit@0.7.2` and `@weftlet/core@0.7.2`.
17
+ Package versions in this checkout/archive: `@weftlet/toolkit@0.7.3` and `@weftlet/core@0.7.3`.
18
18
  <!-- weftlet:release:end -->
19
19
 
20
20
  Weftlet uses `@weftlet/toolkit`; its neutral `@weftlet/core` dependency is installed
@@ -486,10 +486,11 @@ pending re-extraction. Queries compare captured file digests with current workin
486
486
  report subsequent edits separately from captured and excluded changes. Older overlays without
487
487
  capture metadata have unknown freshness. Historical or draft evidence cannot validate a current diff.
488
488
 
489
- Impact queries [rank nearby consumers and varied evidence sources](docs/ADR-041-bounded-relationship-retrieval.md)
489
+ Impact queries [give near and indirect relationships bounded turns](docs/ADR-042-indirect-local-relationships.md)
490
490
  ahead of repeated detail and shared-import context. Ranking changes ordering, not saved facts or
491
- the reachable scope. Saved local calls, their exact references and consumer relationships precede dense local-variable
492
- detail within each source; unindexed symbol hubs receive a penalty unless explicitly queried.
491
+ the reachable scope. Calls, cross-file references (including those without call proof) and file
492
+ consumers share turns across distance groups, with source diversity within each group. Local
493
+ detail has its own turns; unindexed symbol hubs follow local evidence unless explicitly queried.
493
494
  These are ordering signals, not new assertions or proof of execution. All evidence remains in
494
495
  the reachable set. Responses identify the ranking version; after a ranking upgrade, restart
495
496
  scans whose old continuation tokens are rejected. No snapshot refresh is needed for new ordering.
@@ -0,0 +1,18 @@
1
+ import type { GraphFact } from '@weftlet/core';
2
+ export interface ImpactOrderRow {
3
+ readonly fact: GraphFact;
4
+ readonly proximity: number;
5
+ readonly relationshipOrder: number;
6
+ readonly contextOnly: boolean;
7
+ readonly focus: number;
8
+ readonly tie: string;
9
+ }
10
+ /** Ordering waves preserve evidence-lane balancing in the query facade. Near
11
+ * and indirect relationships each get turns (two slots for calls, references
12
+ * and consumers, one for other relations); local detail also gets one slot
13
+ * per wave. Unindexed/shared-import context follows local evidence unless it
14
+ * was explicitly queried. No assertion, citation or authority is rewritten. */
15
+ export declare function orderImpactRows(rows: ImpactOrderRow[]): {
16
+ fact: GraphFact;
17
+ score: number;
18
+ }[];
@@ -0,0 +1,77 @@
1
+ /** Fixed distance bands prevent thousands of first-hop sources from exhausting
2
+ * every page before any second-hop evidence gets a turn. They do not bound scope. */
3
+ function distanceBand(distance) {
4
+ return distance < 4 ? distance : distance < 8 ? 4 : 5;
5
+ }
6
+ function family(fact) {
7
+ if (fact.predicate === 'calls' || fact.predicate === 'references' || fact.predicate === 'consumes')
8
+ return fact.predicate;
9
+ return 'other';
10
+ }
11
+ const lexical = (a, b) => a < b ? -1 : a > b ? 1 : 0;
12
+ const compare = (a, b) => b.focus - a.focus ||
13
+ a.proximity - b.proximity || lexical(a.tie, b.tie) || lexical(a.fact.id, b.fact.id);
14
+ /** One source per turn within a distance/family bucket, without adding an
15
+ * unbounded source ordinal to graph distance. Every input row is retained. */
16
+ function sourceQueue(rows) {
17
+ const sources = new Map();
18
+ for (const row of rows.sort(compare)) {
19
+ const group = sources.get(row.fact.provenance.path) ?? [];
20
+ group.push(row);
21
+ sources.set(row.fact.provenance.path, group);
22
+ }
23
+ let active = [...sources.values()].map(rows => ({ rows, offset: 0 }));
24
+ let cursor = 0;
25
+ return () => {
26
+ if (!active.length)
27
+ return undefined;
28
+ if (cursor === active.length) {
29
+ active = active.filter(source => source.offset < source.rows.length);
30
+ cursor = 0;
31
+ }
32
+ const source = active[cursor++];
33
+ return source?.rows[source.offset++];
34
+ };
35
+ }
36
+ /** Ordering waves preserve evidence-lane balancing in the query facade. Near
37
+ * and indirect relationships each get turns (two slots for calls, references
38
+ * and consumers, one for other relations); local detail also gets one slot
39
+ * per wave. Unindexed/shared-import context follows local evidence unless it
40
+ * was explicitly queried. No assertion, citation or authority is rewritten. */
41
+ export function orderImpactRows(rows) {
42
+ const result = [];
43
+ let wave = 0;
44
+ for (const contextOnly of [false, true]) {
45
+ const selected = rows.filter(row => row.contextOnly === contextOnly);
46
+ const buckets = new Map();
47
+ const details = [];
48
+ for (const row of selected) {
49
+ if (row.relationshipOrder > 0) {
50
+ details.push(row);
51
+ continue;
52
+ }
53
+ const key = `${distanceBand(row.proximity)}:${family(row.fact)}`;
54
+ const bucket = buckets.get(key) ?? [];
55
+ bucket.push(row);
56
+ buckets.set(key, bucket);
57
+ }
58
+ const queues = [...buckets].sort(([a], [b]) => lexical(a, b))
59
+ .map(([key, group]) => ({ next: sourceQueue(group), slots: key.endsWith(':other') ? 1 : 2 }));
60
+ if (details.length)
61
+ queues.push({ next: sourceQueue(details), slots: 1 });
62
+ let remaining = selected.length;
63
+ while (remaining > 0) {
64
+ for (const { next, slots } of queues) {
65
+ for (let slot = 0; slot < slots; slot++) {
66
+ const row = next();
67
+ if (row) {
68
+ result.push({ fact: row.fact, score: wave });
69
+ remaining--;
70
+ }
71
+ }
72
+ }
73
+ wave++;
74
+ }
75
+ }
76
+ return result;
77
+ }
@@ -3,5 +3,6 @@ import type { GraphFact, GraphNode } from '@weftlet/core';
3
3
  export declare function impactRankingSignals(facts: readonly GraphFact[], anchorTerms: readonly string[]): {
4
4
  penalty: (fact: GraphFact) => 0 | 8;
5
5
  seedNodes: (fact: GraphFact) => GraphNode[];
6
- relationshipOrder: (fact: GraphFact) => 0 | 2 | 1;
6
+ relationshipOrder: (fact: GraphFact) => 0 | 2;
7
+ contextOnly: (fact: GraphFact) => boolean;
7
8
  };
@@ -2,7 +2,6 @@
2
2
  export function impactRankingSignals(facts, anchorTerms) {
3
3
  const definitions = new Map();
4
4
  const callsiteReferences = new Set();
5
- const callableNativeSymbols = new Set();
6
5
  const localCall = (fact) => fact.predicate === 'calls' && fact.codeCall !== undefined &&
7
6
  fact.codeCall.target !== 'external' && fact.codeCall.targetDefinitions.length > 0;
8
7
  for (const fact of facts) {
@@ -14,8 +13,6 @@ export function impactRankingSignals(facts, anchorTerms) {
14
13
  if (localCall(fact)) {
15
14
  for (const proof of fact.codeCall.targetOccurrences)
16
15
  callsiteReferences.add(proof.factId);
17
- if (fact.object.codeSymbol)
18
- callableNativeSymbols.add(fact.object.codeSymbol.nativeSymbol);
19
16
  }
20
17
  }
21
18
  const explicit = (node) => anchorTerms.some(term => `${node.id} ${node.label} ${node.codeSymbol?.nativeSymbol ?? ''}`.toLowerCase().includes(term));
@@ -36,19 +33,22 @@ export function impactRankingSignals(facts, anchorTerms) {
36
33
  const relationshipOrder = (fact) => {
37
34
  if (localCall(fact) || callsiteReferences.has(fact.id))
38
35
  return 0;
39
- if (fact.predicate === 'consumes' && fact.object.id.startsWith('symbol:scip:') &&
40
- callableNativeSymbols.has(fact.object.label))
41
- return 0;
42
36
  if (fact.codeOccurrence?.role === 'reference') {
43
37
  if (explicit(fact.object))
44
38
  return 0;
45
39
  const targetPaths = definitions.get(fact.object.id);
40
+ // A saved reference across repository files is useful without a native
41
+ // call proof. This only changes its query order, never its predicate.
46
42
  if (targetPaths && [...targetPaths].some(path => path !== fact.provenance.path))
47
- return 1;
43
+ return 0;
48
44
  }
49
45
  if (fact.codeOccurrence || fact.codeCall)
50
46
  return 2;
47
+ if (fact.predicate === 'contains' && (fact.subject.kind === 'Project' ||
48
+ fact.object.kind === 'CodeSymbol' || fact.object.id.startsWith('symbol:scip:')))
49
+ return 2;
51
50
  return 0; // Keep intent, queue/data contracts, validation and legacy adapter relations available.
52
51
  };
53
- return { penalty, seedNodes, relationshipOrder };
52
+ const contextOnly = (fact) => [fact.subject, fact.object].some(node => hub(node) || (node.id.startsWith('contract:module:') && !explicit(node)));
53
+ return { penalty, seedNodes, relationshipOrder, contextOnly };
54
54
  }
@@ -203,7 +203,7 @@ export class SnapshotImpactQueryService {
203
203
  tier.push(fact);
204
204
  tiers.set(score, tier);
205
205
  }
206
- // Balance evidence lanes among similarly ranked facts, not across unrelated distance tiers.
206
+ // Balance evidence lanes within each ordering wave; retain the scorer's wave boundaries.
207
207
  const allBalanced = [...tiers.values()].flatMap((tier) => [
208
208
  ...selectBalancedFacts(tier, tier.length),
209
209
  ...tier.filter((fact) => contextPackLaneForFact(fact) === undefined),
@@ -1,6 +1,6 @@
1
1
  import type { GraphFact } from '@weftlet/core';
2
2
  /** Binds continuation offsets to the ordering policy; changing this requires restarting a scan. */
3
- export declare const IMPACT_RANKING_VERSION = "local-relationships-diversity-v2";
3
+ export declare const IMPACT_RANKING_VERSION = "local-relationship-waves-v3";
4
4
  export declare function factSearchText(fact: GraphFact): string;
5
5
  export interface RankedImpactFact {
6
6
  readonly fact: GraphFact;
@@ -1,7 +1,8 @@
1
1
  import { stableJson } from '../infrastructure/util.js';
2
2
  import { impactRankingSignals } from './impact-signals.js';
3
+ import { orderImpactRows } from './impact-order.js';
3
4
  /** Binds continuation offsets to the ordering policy; changing this requires restarting a scan. */
4
- export const IMPACT_RANKING_VERSION = 'local-relationships-diversity-v2';
5
+ export const IMPACT_RANKING_VERSION = 'local-relationship-waves-v3';
5
6
  export function factSearchText(fact) {
6
7
  return [fact.subject.id, fact.subject.label, fact.predicate, fact.object.id,
7
8
  fact.object.label, fact.provenance.path].join(' ').toLowerCase();
@@ -69,25 +70,10 @@ export function rankImpactFacts(facts, direct, anchorTerms, focus) {
69
70
  fact,
70
71
  proximity: costs.get(fact) + (directIds.has(fact.id) ? 0 : Math.min((distance.get(fact.subject.id) ?? Infinity) + cost(fact, true), (distance.get(fact.object.id) ?? Infinity) + cost(fact, false))),
71
72
  relationshipOrder: signals.relationshipOrder(fact),
73
+ contextOnly: signals.contextOnly(fact),
72
74
  focus: focus.filter((term) => text.includes(term)).length,
73
75
  tie: stableTie(fact),
74
76
  };
75
77
  });
76
- const lexical = (a, b) => a < b ? -1 : a > b ? 1 : 0;
77
- const compare = (a, b) => a.relationshipOrder - b.relationshipOrder || b.focus - a.focus || lexical(a.tie, b.tie) || lexical(a.fact.id, b.fact.id);
78
- // Allocate each source's early slots to relationships before local occurrence
79
- // detail. Otherwise hundreds of nearer variable references consume a file's
80
- // diversity allowance before its file-to-symbol consumer can be considered.
81
- // Final ordering below still charges distance and shared-library penalties.
82
- rows.sort((a, b) => costs.get(a.fact) - costs.get(b.fact) ||
83
- a.relationshipOrder - b.relationshipOrder || a.proximity - b.proximity || compare(a, b));
84
- const counts = new Map();
85
- const diverse = rows.map((row) => {
86
- const seen = counts.get(row.fact.provenance.path) ?? 0;
87
- counts.set(row.fact.provenance.path, seen + 1);
88
- // Each additional fact from one source costs one ordinary edge. Details stay on later pages.
89
- return { ...row, score: row.proximity + seen };
90
- });
91
- return diverse.sort((a, b) => a.score - b.score || compare(a, b))
92
- .map(({ fact, score }) => ({ fact, score }));
78
+ return orderImpactRows(rows);
93
79
  }
@@ -3,7 +3,7 @@ import { graphPredicates } from '@weftlet/core';
3
3
  import { parseGraphPathsRequest } from '../graph/path-request.js';
4
4
  export const graphPathsTool = {
5
5
  name: 'graph.paths',
6
- description: 'Explore simple cited paths between exact node IDs in an explicit saved snapshot. Depth-first assertion order, not shortest/causal paths. Follow continuation with identical selectors; inspect depth/work limits and unexplored frontier. No hydration or model calls.',
6
+ description: 'Explore simple cited paths between exact node IDs in an explicit saved snapshot. Shortest-first traversal, prioritizing edges to the exact target; static paths are not proof of causality. Follow continuation with identical selectors; inspect depth/work limits and unexplored frontier. No hydration or model calls.',
7
7
  inputSchema: {
8
8
  type: 'object', additionalProperties: false, required: ['snapshotId', 'fromNodeId', 'toNodeId'],
9
9
  properties: {
@@ -28,6 +28,15 @@ known direct paths and specific worker `references`/`consumes` assertions were d
28
28
  fixed retrieval budgets. [ADR 041](ADR-041-bounded-relationship-retrieval.md) tracks the bounded
29
29
  query-order patch and its public regression; no extraction refresh is needed for that patch.
30
30
 
31
+ 0.7.2 private replay: **direct-path acceptance is closed**; exact stored single-edge references
32
+ and calls surface at the original budget. Keep **one indirect-ranking ticket open**: retrieve
33
+ second-hop local references and legacy consumers without a saved call proof despite broad local
34
+ competition. Library share and file discovery improved, but neither private target reached the
35
+ first three 60-fact pages. Preserve extraction, authority, reachable totals and immutable evidence;
36
+ record public and private denominators separately. See the latest [validation record](VALIDATION.md).
37
+ The [ADR 042 patch](ADR-042-indirect-local-relationships.md) retrieves both exact public targets
38
+ on the first page with the same saved evidence; private acceptance still requires the original replay.
39
+
31
40
  All three public 554,516-fact strict SHACL passes succeeded but took about 35–37 minutes each
32
41
  in this cloud. This is a capacity result, not a 30-minute hydration qualification. B6b must record
33
42
  full hydration and agent-query latency on the consumer workload as well as correctness.
@@ -1,6 +1,7 @@
1
1
  # ADR 041: useful relationships within bounded retrieval
2
2
 
3
3
  Status: query-only patch; validation and publication status are recorded in VALIDATION.md.
4
+ Impact ordering is superseded by [ADR 042](ADR-042-indirect-local-relationships.md); path ordering remains in effect.
4
5
 
5
6
  ## Evidence and scope
6
7
 
@@ -0,0 +1,59 @@
1
+ # ADR 042: indirect local relationships under broad anchors
2
+
3
+ Status: query-only patch. Qualification and consumer status are recorded in VALIDATION.md.
4
+ Supersedes ADR 041's impact ordering; its shortest-first path search is unchanged.
5
+
6
+ ## Evidence
7
+
8
+ The 0.7.2 private replay closes the direct-path report and confirms improved file discovery
9
+ and library share. It does **not** close relationship recall: two exact second-hop assertions
10
+ remain outside the original 180-fact budget despite zero hub penalty. One is a symbol reference
11
+ without a saved call proof; the other is a legacy file consumer. No extraction loss is reported.
12
+
13
+ The frozen [public regression](../evaluations/indirect-retrieval/protocol.md) independently
14
+ reproduces this shape with actual extraction, broad catalog anchors and 192 competing local
15
+ setup files. Both assertions exist and are reachable in round two. The baseline returns
16
+ 178 provenance files but misses both assertions. Per-source diversity alone is insufficient.
17
+
18
+ ## Decision
19
+
20
+ Use `local-relationship-waves-v3` ordering over the **unchanged reachable set**:
21
+
22
+ - Retain weighted graph distance and explicit-anchor exceptions from ADR 041. A saved cross-file
23
+ reference with an indexed definition receives the relationship category even without native
24
+ call proof. Do not change its predicate, confidence, authority or citations.
25
+ - Separate relationships by weighted distance (0, 1, 2, 3, 4–7, 8+) and predicate family
26
+ (`calls`, `references`, `consumes`, other). Each wave takes two assertions from each populated
27
+ code-relationship bucket and one from each other-relationship bucket. Distances 0–3 each get
28
+ turns so broad near-anchor competition cannot consume every turn before indirect evidence.
29
+ - Round-robin provenance sources **within** each bucket. Order each source by focus match,
30
+ distance and stable semantic tie key. Remove the unbounded per-source ordinal added to graph
31
+ distance in v2. All saved facts remain eligible, including repeated-source assertions.
32
+ - Local symbol occurrence/definition and project/file membership detail get a separate single
33
+ slot per wave. Unindexed-symbol and generic module-import context follow local evidence unless
34
+ explicitly queried. These are retrieval signals, not proof that an unindexed symbol is external.
35
+ - Give every assertion in a wave the same ordering score, then retain the query facade's existing
36
+ evidence-lane balancing. The score is now a wave number, not a distance-plus-diversity value.
37
+ Version continuation tokens and reject prior policies with instructions to restart the scan.
38
+
39
+ There are no consumer names, target IDs or corpus-specific file selectors in the scorer.
40
+ The fixed bucket proportions are a retrieval heuristic, not a universal relevance guarantee.
41
+ Larger or equally competitive buckets can still displace relevant assertions. Intent, contracts
42
+ and validation retain their evidence lanes; the returned page is not complete product coverage.
43
+
44
+ ## Tradeoffs and boundaries
45
+
46
+ The same 9,038-fact saved public graph now returns the exact reference at position 17 and consumer
47
+ at 15. All 180 output slots remain in the denominator. Source diversity falls from 178 to 71 files;
48
+ that is an explicit tradeoff for relationship recall, not lost reachable evidence. Both facts
49
+ remain as originally stored, including omitted authority fields on the legacy consumer. The
50
+ reference still has no saved call proof; do not describe it as proven invocation or execution.
51
+
52
+ The existing 36-target call-backed regression and direct-path acceptance remain separate checks.
53
+ The private two-target ranking ticket stays open until the original queries are replayed at their
54
+ original budgets. Public success cannot establish the private result positions.
55
+
56
+ No extractor, assembly, semantic-cache, snapshot, persistence, RDF or strict-validation identity
57
+ changes. Existing snapshots can be queried immediately without hydration or model calls. The
58
+ 0.7.1 capacity fix remains intact. The MCP path description is corrected to shortest-first with
59
+ exact-target priority, retaining its static-path/non-causality warning.
package/docs/RELEASING.md CHANGED
@@ -202,14 +202,14 @@ Verify the matching public version in a fresh disposable project after publicati
202
202
 
203
203
  ```sh
204
204
  npm init -y
205
- npx --yes @weftlet/toolkit@0.7.2 init --yes
206
- npx --yes @weftlet/toolkit@0.7.2 config validate
205
+ npx --yes @weftlet/toolkit@0.7.3 init --yes
206
+ npx --yes @weftlet/toolkit@0.7.3 config validate
207
207
  ```
208
208
 
209
209
  For local installation, use both prepared archives from the same reviewed release:
210
210
 
211
211
  ```sh
212
- npm install --save-dev "/path/to/weftlet/.release/weftlet-core-0.7.2.tgz" "/path/to/weftlet/.release/weftlet-toolkit-0.7.2.tgz"
212
+ npm install --save-dev "/path/to/weftlet/.release/weftlet-core-0.7.3.tgz" "/path/to/weftlet/.release/weftlet-toolkit-0.7.3.tgz"
213
213
  ```
214
214
  <!-- weftlet:release:end -->
215
215
 
@@ -1,5 +1,49 @@
1
1
  # Validation evidence
2
2
 
3
+ ## Indirect-ranking patch: public comparison, 2026-11-03
4
+
5
+ [ADR 042](ADR-042-indirect-local-relationships.md) and the
6
+ [frozen comparison](../evaluations/indirect-retrieval/README.md) cover the remaining query-only
7
+ ranking change. Actual TypeScript extraction produces both second-hop assertions without a
8
+ saved call proof for the reference. At unchanged depth three / 3 × 60 facts, their ranks move
9
+ from 3,704 / 1,760 to **17 / 15**. The 9,038 stored/reachable assertions and 150 direct matches
10
+ are unchanged. All 180 results remain in the denominator; source diversity changes from 178
11
+ to 71 files. The four saved evidence files retain exact bytes during the comparison. No private
12
+ source, semantic/model calls, new extraction or larger query budgets enter that comparison.
13
+
14
+ The prior 36-target call-backed regression and direct-path/exhaustive-oracle/viewer parity tests
15
+ pass locally. The MCP path description now reflects shortest-first traversal with exact-target
16
+ priority and retains the warning that static paths are not causality. Full release qualification
17
+ is recorded separately on the change PR. **Private two-target ranking acceptance stays open.**
18
+ Existing snapshots and caches need no refresh; impact continuation must restart after upgrading.
19
+
20
+ ## 0.7.2 private replay: paths closed, indirect ranking open, 2026-11-03
21
+
22
+ The maintainer reports that the same saved endpoints now return two exact stored single-edge
23
+ paths (`references` and `calls`) on page one at outgoing depth three / 1,000 steps. The CLI and
24
+ fresh stdio MCP agree, and truncation/continuation remains truthful. **Close the direct-path
25
+ consumer report.** This establishes cited static paths, not exhaustive discovery or runtime causality.
26
+
27
+ The remaining ranking ticket concerns second-hop local `references` and legacy file `consumes`
28
+ assertions without a saved call whose target-occurrence proof cites the reference. Both still
29
+ exist and are reachable in expansion round two. Neither receives the unindexed-symbol penalty.
30
+ Do not invent a `calls` fact or change extraction to address this query-order finding.
31
+
32
+ On unchanged private inputs and budgets, 0.7.1 → 0.7.2 improves page-one file suggestion/source
33
+ citation from 11/12 to 12/12 and library assertions from 378/540 to 0/540. The two target
34
+ assertions remain absent from the first 180 PM results. Their calculated ranks improve from
35
+ 24,801 / 69,207 to 23,052 / 3,447; v2 scores are 34 / 9, relationship-order values 1 / 0, and
36
+ 22,791 / 3,295 assertions have strictly lower scores. The first 180 cover 158 provenance files.
37
+ These measurements implicate the interaction of distance, relationship category and source
38
+ diversity under broad local competition; they do not identify one scoring term as the sole cause.
39
+
40
+ The consumer reproduced all 180 CLI fact IDs in order, with 360 direct matches and 420,837
41
+ reachable assertions. All three queries retain their prior reachable counts. All 20 stored-file
42
+ fingerprints match; no rehydration, model calls or extra pages were used. This private two-target
43
+ case is distinct from the earlier public 36-relationship denominator, which remains valid for its
44
+ call-backed fixture. A new public regression must include broad anchors, many local competitor
45
+ files, and both exact second-hop assertions without call proof at depth three / 3 × 60 facts.
46
+
3
47
  ## 0.7.1 consumer follow-up and bounded retrieval patch, 2026-11-03
4
48
 
5
49
  **Maintainer-reported consumer pass:** the published 0.7.1 toolkit hydrates, strictly validates,
@@ -108,7 +108,7 @@
108
108
  "destinationPath": "package.json",
109
109
  "sourceSha256": "a575dbb2fed8c554b95e8e9b3e03a0c21cab1be7249860bbebc18e046b2ff78d",
110
110
  "modified": true,
111
- "destinationSha256": "5ca2ea1f62e6b8393e731f761a1732a8ccf464948a905ab9fe246ae5d941dda8"
111
+ "destinationSha256": "f331a6f0f0f0183466e5a9bb97a856d66522417f3c357d2ff825f348ac0410c1"
112
112
  },
113
113
  {
114
114
  "sourcePath": "tools/context-graph/packages/core/LICENSE",
@@ -129,7 +129,7 @@
129
129
  "destinationPath": "packages/core/README.md",
130
130
  "sourceSha256": "6044bf7b9a3dc793f41e2ff048546ed11938957d10a5b143eb1739ac4cd7477c",
131
131
  "modified": true,
132
- "destinationSha256": "1c0c80c8a85f9240ace5a2f01d102646fa293ef246a5f056eb94c7efa0f6e401"
132
+ "destinationSha256": "b49357185e5c1cd44e76a77ba4134e70002eeb3399983a7d9e4dd737a9dad9d8"
133
133
  },
134
134
  {
135
135
  "sourcePath": "tools/context-graph/packages/core/THIRD_PARTY_NOTICES.md",
@@ -143,7 +143,7 @@
143
143
  "destinationPath": "packages/core/package.json",
144
144
  "sourceSha256": "2a29066eb8452f22fafcb06bb035a84dda93c5705dba32aba600a1b7e5aaf19c",
145
145
  "modified": true,
146
- "destinationSha256": "4a17cd04c7ec5a3a96ec0767d3883d588dfe6724822f254ed91f452b30b939bc"
146
+ "destinationSha256": "afd324effa694d0f753d99be367434d1d3355eacfc68cc27813a5279267dbf94"
147
147
  },
148
148
  {
149
149
  "sourcePath": "tools/context-graph/packages/core/src/core.ts",
@@ -388,14 +388,14 @@
388
388
  "destinationPath": "src/graph/query.test.ts",
389
389
  "sourceSha256": "ba07c52566da979fcbb451b0c0c99b466521993cb49415ff8b35df2b01d4ecaf",
390
390
  "modified": true,
391
- "destinationSha256": "20f0766299e66d4b5e7bc4577b6b0937c5bf87f2f1858f7b0205172231f0bb4c"
391
+ "destinationSha256": "4a87d3be19769dee26ffafc1b876d877f39dec921ffa89dcd011c7a3cfb9667e"
392
392
  },
393
393
  {
394
394
  "sourcePath": "tools/context-graph/src/query.ts",
395
395
  "destinationPath": "src/graph/query.ts",
396
396
  "sourceSha256": "4d67f87ca660cefe9686fb5b775f86a997a25d539819ea81d321c8bd1e0aaa39",
397
397
  "modified": true,
398
- "destinationSha256": "b689b2285cc22fdcc89d5dd64ee91d0395a1751004c7970bf62f9edebd7162ce"
398
+ "destinationSha256": "8c13b32499f0b830cd02bfc281c37c32fd6387aa3b98a325e6a60d3706b64528"
399
399
  },
400
400
  {
401
401
  "sourcePath": "tools/context-graph/src/request.test.ts",
@@ -635,6 +635,7 @@
635
635
  "docs/ADR-039-mapping-proposals.md",
636
636
  "docs/ADR-040-bounded-graph-io.md",
637
637
  "docs/ADR-041-bounded-relationship-retrieval.md",
638
+ "docs/ADR-042-indirect-local-relationships.md",
638
639
  "docs/CLOUD-ENVIRONMENT.md",
639
640
  "docs/CONSUMER-TRIAL.md",
640
641
  "docs/ENVIRONMENT-VALIDATION.md",
@@ -748,6 +749,10 @@
748
749
  "evaluations/dispatch/routing-baseline.json",
749
750
  "evaluations/dispatch/routing-protocol.md",
750
751
  "evaluations/dispatch/routing.config.json",
752
+ "evaluations/indirect-retrieval/README.md",
753
+ "evaluations/indirect-retrieval/baseline.json",
754
+ "evaluations/indirect-retrieval/candidate.json",
755
+ "evaluations/indirect-retrieval/protocol.md",
751
756
  "evaluations/mapping-gaps/README.md",
752
757
  "evaluations/mapping-gaps/inputs.lock.json",
753
758
  "evaluations/mapping-gaps/project/.gitattributes",
@@ -872,6 +877,8 @@
872
877
  "scripts/evaluation/score.ts",
873
878
  "scripts/git-content.d.mts",
874
879
  "scripts/git-content.mjs",
880
+ "scripts/indirect-retrieval-study/measure.ts",
881
+ "scripts/indirect-retrieval-study/run.ts",
875
882
  "scripts/inventory.test.ts",
876
883
  "scripts/large-graph/lifecycle.ts",
877
884
  "scripts/large-graph/run.ts",
@@ -1019,6 +1026,8 @@
1019
1026
  "src/graph/evidence-description.ts",
1020
1027
  "src/graph/identity-preflight.test.ts",
1021
1028
  "src/graph/identity-preflight.ts",
1029
+ "src/graph/impact-order.test.ts",
1030
+ "src/graph/impact-order.ts",
1022
1031
  "src/graph/impact-signals.ts",
1023
1032
  "src/graph/neighborhood-renderer.ts",
1024
1033
  "src/graph/neighborhood-request.ts",
@@ -1098,6 +1107,7 @@
1098
1107
  "tests/fixtures/code-evidence-project.ts",
1099
1108
  "tests/fixtures/compatibility-cases.ts",
1100
1109
  "tests/fixtures/compatibility-project.ts",
1110
+ "tests/fixtures/indirect-retrieval-project.ts",
1101
1111
  "tests/fixtures/large-typescript-project.ts",
1102
1112
  "tests/fixtures/mapping-project.ts",
1103
1113
  "tests/fixtures/monorepo-project.ts",
@@ -1112,6 +1122,7 @@
1112
1122
  "tests/hydration-plan.test.ts",
1113
1123
  "tests/identity-preflight.test.ts",
1114
1124
  "tests/implementation-coverage.test.ts",
1125
+ "tests/indirect-retrieval.test.ts",
1115
1126
  "tests/large-graph-lifecycle.test.ts",
1116
1127
  "tests/mapping-proposals.test.ts",
1117
1128
  "tests/module-boundaries.test.ts",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@weftlet/toolkit",
3
- "version": "0.7.2",
3
+ "version": "0.7.3",
4
4
  "description": "Evidence-backed context graphs for AI development agents: product intent, contracts, code, tests and runtime behavior",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -66,7 +66,7 @@
66
66
  "rdf-validate-shacl": "0.6.5",
67
67
  "sparqljs": "3.7.4",
68
68
  "typescript": "5.5.4",
69
- "@weftlet/core": "^0.7.2"
69
+ "@weftlet/core": "^0.7.3"
70
70
  },
71
71
  "devDependencies": {
72
72
  "@changesets/cli": "3.0.3",
@@ -131,6 +131,7 @@
131
131
  "benchmark:validation": "node scripts/validation-benchmark/run.mjs",
132
132
  "evaluate:mappings": "tsx scripts/mapping-study/run.ts",
133
133
  "evaluate:calls": "tsx scripts/call-study/run.ts",
134
- "evaluate:proposals": "tsx scripts/mapping-proposal-study/run.ts"
134
+ "evaluate:proposals": "tsx scripts/mapping-proposal-study/run.ts",
135
+ "evaluate:indirect": "tsx scripts/indirect-retrieval-study/run.ts"
135
136
  }
136
137
  }