sneakoscope 7.3.0 → 7.6.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 (283) hide show
  1. package/README.md +129 -10
  2. package/crates/sks-core/Cargo.lock +1 -1
  3. package/crates/sks-core/Cargo.toml +1 -1
  4. package/dist/cli/codex-app-command.js +1 -1
  5. package/dist/cli/command-manifest-lite.js +4 -1
  6. package/dist/cli/command-registry.js +2 -0
  7. package/dist/cli/install-helpers-codex-lb-chain.js +42 -0
  8. package/dist/cli/install-helpers-codex-lb-config.js +114 -9
  9. package/dist/cli/install-helpers-install-support.js +6 -16
  10. package/dist/cli/install-helpers.js +788 -600
  11. package/dist/cli/router.js +30 -2
  12. package/dist/commands/codex-app.js +37 -1
  13. package/dist/commands/codex-lb.js +491 -300
  14. package/dist/config/skills-manifest.json +57 -71
  15. package/dist/core/align/align-route.js +127 -0
  16. package/dist/core/codex-app/codex-app-fast-ui-repair.js +8 -4
  17. package/dist/core/codex-app/codex-app-restart.js +83 -0
  18. package/dist/core/codex-app/codex-app-ui-state-snapshot.js +8 -4
  19. package/dist/core/codex-app/desktop-routing-snapshot.js +1 -1
  20. package/dist/core/codex-app/menubar/constants.js +5 -0
  21. package/dist/core/codex-app/menubar/generation-transaction-journal.js +1 -3
  22. package/dist/core/codex-app/menubar/installer.js +18 -0
  23. package/dist/core/codex-app/multi-provider-router.js +22 -10
  24. package/dist/core/codex-app/openrouter-activate.js +26 -1
  25. package/dist/core/codex-app.js +118 -26
  26. package/dist/core/codex-control/codex-app-server-runtime-env.js +86 -0
  27. package/dist/core/codex-control/codex-app-server-v2-client.js +78 -8
  28. package/dist/core/codex-control/codex-task-runner.js +2 -2
  29. package/dist/core/codex-lb/capability-runner.js +204 -0
  30. package/dist/core/codex-lb/capability-types.js +1 -0
  31. package/dist/core/codex-lb/codex-lb-env.js +9 -13
  32. package/dist/core/codex-lb/codex-lb-setup.js +45 -8
  33. package/dist/core/codex-lb/codex-lb-tool-catalog.js +52 -74
  34. package/dist/core/codex-lb/codex-lb-tool-output-recovery.js +1 -1
  35. package/dist/core/codex-lb/desktop-auth-invariant.js +185 -0
  36. package/dist/core/codex-lb/desktop-bridge/client.js +34 -0
  37. package/dist/core/codex-lb/desktop-bridge/header-policy.js +106 -0
  38. package/dist/core/codex-lb/desktop-bridge/http-forward.js +101 -0
  39. package/dist/core/codex-lb/desktop-bridge/index.js +10 -0
  40. package/dist/core/codex-lb/desktop-bridge/launchd.js +81 -0
  41. package/dist/core/codex-lb/desktop-bridge/location-rewrite.js +27 -0
  42. package/dist/core/codex-lb/desktop-bridge/security.js +274 -0
  43. package/dist/core/codex-lb/desktop-bridge/server.js +179 -0
  44. package/dist/core/codex-lb/desktop-bridge/state.js +119 -0
  45. package/dist/core/codex-lb/desktop-bridge/types.js +16 -0
  46. package/dist/core/codex-lb/desktop-bridge/websocket-forward.js +151 -0
  47. package/dist/core/codex-lb/desktop-center-credentials.js +189 -0
  48. package/dist/core/codex-lb/desktop-controller.js +1410 -0
  49. package/dist/core/codex-lb/desktop-mode.js +32 -0
  50. package/dist/core/codex-lb/desktop-real-evidence.js +168 -0
  51. package/dist/core/codex-lb/desktop-service.js +613 -0
  52. package/dist/core/codex-lb/legacy-migration.js +575 -0
  53. package/dist/core/codex-lb/migration-receipt.js +246 -0
  54. package/dist/core/codex-lb/probes/auxiliary-surfaces-probe.js +60 -0
  55. package/dist/core/codex-lb/probes/bridge-probe.js +75 -0
  56. package/dist/core/codex-lb/probes/catalog-probe.js +128 -0
  57. package/dist/core/codex-lb/probes/computer-use-probe.js +50 -0
  58. package/dist/core/codex-lb/probes/image-generation-probe.js +47 -0
  59. package/dist/core/codex-lb/probes/probe-evidence.js +39 -0
  60. package/dist/core/codex-lb/probes/voice-realtime-probe.js +44 -0
  61. package/dist/core/codex-lb/trusted-deep-evidence.js +403 -0
  62. package/dist/core/codex-native/core-skill-manifest.js +22 -6
  63. package/dist/core/codex-runtime/codex-desktop-config-policy.js +2 -1
  64. package/dist/core/commands/align-command.js +220 -0
  65. package/dist/core/commands/image-ux-review-command.js +280 -68
  66. package/dist/core/commands/naruto-command.js +257 -8
  67. package/dist/core/commands/ppt-command.js +2 -2
  68. package/dist/core/commands/telegram-command.js +402 -34
  69. package/dist/core/commands/triwiki-command.js +11 -1
  70. package/dist/core/commands/triwiki-graph-command.js +160 -0
  71. package/dist/core/commands/wiki-command.js +100 -20
  72. package/dist/core/doctor/skill-legacy-surface.js +1 -3
  73. package/dist/core/errors/message.js +3 -0
  74. package/dist/core/evidence/evidence-freshness.js +14 -0
  75. package/dist/core/feature-fixtures.js +9 -1
  76. package/dist/core/feature-registry.js +5 -3
  77. package/dist/core/fsx.js +7 -3
  78. package/dist/core/hooks-runtime/codex-commit-hooks-selftest.js +82 -0
  79. package/dist/core/hooks-runtime/context-graph-freshness-preflight.js +113 -0
  80. package/dist/core/hooks-runtime/hook-context.js +15 -2
  81. package/dist/core/hooks-runtime/managed-skill-generation-heal.js +46 -0
  82. package/dist/core/hooks-runtime/naruto-terminal-finalization.js +1 -0
  83. package/dist/core/hooks-runtime/official-subagent-lifecycle.js +1 -1
  84. package/dist/core/hooks-runtime/tool-output-quarantine.js +1 -1
  85. package/dist/core/hooks-runtime.js +33 -89
  86. package/dist/core/image-ux-review/callout-extraction.js +6 -0
  87. package/dist/core/image-ux-review/imagegen-adapter.js +64 -23
  88. package/dist/core/image-ux-review/real-callout-extractor.js +1 -0
  89. package/dist/core/image-ux-review.js +230 -12
  90. package/dist/core/imagegen/codex-lb-imagegen-target.js +21 -7
  91. package/dist/core/imagegen/imagegen-capability.js +10 -4
  92. package/dist/core/imagegen/require-imagegen.js +29 -5
  93. package/dist/core/init/skills.js +25 -13
  94. package/dist/core/init.js +1 -1
  95. package/dist/core/install/installed-package-smoke.js +157 -4
  96. package/dist/core/managed-assets/managed-assets-manifest.js +2 -1
  97. package/dist/core/managed-path-safety.js +8 -10
  98. package/dist/core/mcp-config/backup.js +2 -4
  99. package/dist/core/mcp-config/config-reader.js +2 -4
  100. package/dist/core/mcp-config/scope.js +3 -5
  101. package/dist/core/naruto/context-graph-advisor-scope.js +242 -0
  102. package/dist/core/naruto/context-graph-advisor.js +0 -0
  103. package/dist/core/perf/release-latency-slo.js +12 -6
  104. package/dist/core/pipeline-internals/runtime-core.js +78 -0
  105. package/dist/core/pipeline-internals/runtime-gates.js +5 -2
  106. package/dist/core/policy/latest-version-guidance.js +113 -0
  107. package/dist/core/ppt.js +8 -8
  108. package/dist/core/preflight/parallel-preflight-engine.js +1 -1
  109. package/dist/core/proof/auto-finalize.js +98 -6
  110. package/dist/core/proof/route-proof-gate.js +12 -1
  111. package/dist/core/proof/route-proof-policy.js +8 -8
  112. package/dist/core/release/gate-manifest.js +32 -1
  113. package/dist/core/release/npm-stage-contract.js +21 -0
  114. package/dist/core/release/package-size-budget.js +2 -2
  115. package/dist/core/release/release-gate-contract.js +5 -0
  116. package/dist/core/release/release-proof-io.js +1 -3
  117. package/dist/core/release/release-real-contract.js +5 -4
  118. package/dist/core/release/release-stamp-proof.js +1 -3
  119. package/dist/core/release/stage-publish.js +27 -0
  120. package/dist/core/remote/audit-idempotency.js +50 -18
  121. package/dist/core/remote/codex-public-activity.js +283 -0
  122. package/dist/core/remote/index.js +1 -0
  123. package/dist/core/remote/ssh-worker-client.js +4 -1
  124. package/dist/core/remote/worker.js +206 -27
  125. package/dist/core/research/research-adversarial-review.js +1 -3
  126. package/dist/core/research/research-claim-synthesizer.js +1 -3
  127. package/dist/core/research/research-falsification-runner.js +1 -3
  128. package/dist/core/research/research-source-evidence.js +1 -3
  129. package/dist/core/responses-stream.js +65 -19
  130. package/dist/core/routes/constants.js +1 -1
  131. package/dist/core/routes/design-policy.js +7 -2
  132. package/dist/core/routes/dollar-manifest-lite.js +2 -4
  133. package/dist/core/routes/evidence.js +1 -1
  134. package/dist/core/routes.js +30 -10
  135. package/dist/core/safety/command-contract/contracts.js +2 -0
  136. package/dist/core/safety/command-contract/types.js +1 -1
  137. package/dist/core/search/context-graph-seeds.js +205 -0
  138. package/dist/core/search/context.js +0 -0
  139. package/dist/core/search/provider.js +2 -2
  140. package/dist/core/secret-redaction.js +6 -0
  141. package/dist/core/subagents/naruto-help-contract.js +2 -1
  142. package/dist/core/subagents/naruto-host-credentials.js +161 -0
  143. package/dist/core/subagents/official-subagent-preparation.js +4 -1
  144. package/dist/core/subagents/official-subagent-prompt.js +44 -2
  145. package/dist/core/subagents/official-subagent-runner.js +26 -8
  146. package/dist/core/subagents/triwiki-attention.js +135 -123
  147. package/dist/core/telegram/bot-api.js +85 -10
  148. package/dist/core/telegram/center-snapshot.js +718 -0
  149. package/dist/core/telegram/config.js +158 -31
  150. package/dist/core/telegram/hub.js +288 -33
  151. package/dist/core/telegram/index.js +2 -0
  152. package/dist/core/telegram/ingress-spool.js +419 -0
  153. package/dist/core/telegram/ledgers.js +188 -29
  154. package/dist/core/telegram/messages.js +26 -6
  155. package/dist/core/telegram/owner-lock.js +10 -7
  156. package/dist/core/telegram/runtime-projection.js +38 -3
  157. package/dist/core/telegram/runtime.js +298 -63
  158. package/dist/core/telegram/service.js +137 -8
  159. package/dist/core/telegram/setup.js +291 -73
  160. package/dist/core/text/strings.js +3 -0
  161. package/dist/core/triwiki/code-pack.js +12 -120
  162. package/dist/core/triwiki/context-graph/compiler/cache-key.js +277 -0
  163. package/dist/core/triwiki/context-graph/compiler/extract.js +104 -0
  164. package/dist/core/triwiki/context-graph/compiler/freshness.js +108 -0
  165. package/dist/core/triwiki/context-graph/compiler/index.js +237 -0
  166. package/dist/core/triwiki/context-graph/compiler/merge.js +0 -0
  167. package/dist/core/triwiki/context-graph/compiler/serialize.js +115 -0
  168. package/dist/core/triwiki/context-graph/contracts.js +236 -0
  169. package/dist/core/triwiki/context-graph/extractors/code/builders.js +150 -0
  170. package/dist/core/triwiki/context-graph/extractors/code/declarations.js +161 -0
  171. package/dist/core/triwiki/context-graph/extractors/code/index.js +265 -0
  172. package/dist/core/triwiki/context-graph/extractors/code/inventory.js +237 -0
  173. package/dist/core/triwiki/context-graph/extractors/code/module-graph.js +252 -0
  174. package/dist/core/triwiki/context-graph/extractors/code/modules.js +79 -0
  175. package/dist/core/triwiki/context-graph/extractors/code/references.js +184 -0
  176. package/dist/core/triwiki/context-graph/extractors/code/selection.js +100 -0
  177. package/dist/core/triwiki/context-graph/extractors/code/ts-config.js +161 -0
  178. package/dist/core/triwiki/context-graph/extractors/code/types.js +18 -0
  179. package/dist/core/triwiki/context-graph/extractors/evidence/claims.js +289 -0
  180. package/dist/core/triwiki/context-graph/extractors/evidence/index.js +54 -0
  181. package/dist/core/triwiki/context-graph/extractors/evidence/proof-index.js +213 -0
  182. package/dist/core/triwiki/context-graph/extractors/evidence/proofs.js +266 -0
  183. package/dist/core/triwiki/context-graph/extractors/evidence/redaction.js +177 -0
  184. package/dist/core/triwiki/context-graph/extractors/evidence/shared.js +0 -0
  185. package/dist/core/triwiki/context-graph/extractors/evidence/sources.js +154 -0
  186. package/dist/core/triwiki/context-graph/extractors/index.js +7 -0
  187. package/dist/core/triwiki/context-graph/extractors/topology/commands.js +207 -0
  188. package/dist/core/triwiki/context-graph/extractors/topology/gate-edges.js +201 -0
  189. package/dist/core/triwiki/context-graph/extractors/topology/gates.js +182 -0
  190. package/dist/core/triwiki/context-graph/extractors/topology/globs.js +124 -0
  191. package/dist/core/triwiki/context-graph/extractors/topology/index.js +92 -0
  192. package/dist/core/triwiki/context-graph/extractors/topology/routes.js +135 -0
  193. package/dist/core/triwiki/context-graph/extractors/topology/shared.js +215 -0
  194. package/dist/core/triwiki/context-graph/graph-index.js +143 -0
  195. package/dist/core/triwiki/context-graph/ids.js +0 -0
  196. package/dist/core/triwiki/context-graph/lint/index.js +0 -0
  197. package/dist/core/triwiki/context-graph/lint/rules.js +232 -0
  198. package/dist/core/triwiki/context-graph/lint/warnings.js +93 -0
  199. package/dist/core/triwiki/context-graph/paths.js +116 -0
  200. package/dist/core/triwiki/context-graph/profiles.js +78 -0
  201. package/dist/core/triwiki/context-graph/projections/anchors.js +91 -0
  202. package/dist/core/triwiki/context-graph/projections/attention.js +58 -0
  203. package/dist/core/triwiki/context-graph/projections/code-pack-workspace.js +62 -0
  204. package/dist/core/triwiki/context-graph/projections/code-pack.js +144 -0
  205. package/dist/core/triwiki/context-graph/projections/index.js +7 -0
  206. package/dist/core/triwiki/context-graph/projections/module-view.js +140 -0
  207. package/dist/core/triwiki/context-graph/projections/node-summary.js +118 -0
  208. package/dist/core/triwiki/context-graph/projections/pack-contract.js +6 -0
  209. package/dist/core/triwiki/context-graph/query/explain.js +0 -0
  210. package/dist/core/triwiki/context-graph/query/index.js +178 -0
  211. package/dist/core/triwiki/context-graph/query/load.js +116 -0
  212. package/dist/core/triwiki/context-graph/query/pack.js +117 -0
  213. package/dist/core/triwiki/context-graph/query/rank.js +142 -0
  214. package/dist/core/triwiki/context-graph/query/ranking-config.js +64 -0
  215. package/dist/core/triwiki/context-graph/query/seeds.js +241 -0
  216. package/dist/core/triwiki/context-graph/query/snapshot-cache.js +72 -0
  217. package/dist/core/triwiki/context-graph/query/traverse.js +154 -0
  218. package/dist/core/triwiki/context-graph/query-types.js +29 -0
  219. package/dist/core/triwiki/context-graph/store/compile-lock.js +21 -0
  220. package/dist/core/triwiki/context-graph/store/event-log.js +48 -0
  221. package/dist/core/triwiki/context-graph/store/fragment-cache.js +85 -0
  222. package/dist/core/triwiki/context-graph/store/graph-status.js +85 -0
  223. package/dist/core/triwiki/context-graph/store/snapshot-store.js +155 -0
  224. package/dist/core/triwiki/triwiki-proof-bank-index-repair.js +115 -0
  225. package/dist/core/triwiki/triwiki-proof-bank-index-store.js +290 -0
  226. package/dist/core/triwiki/triwiki-proof-bank-index.js +126 -0
  227. package/dist/core/triwiki/triwiki-proof-bank.js +7 -1
  228. package/dist/core/verification/context-graph-affected.js +271 -0
  229. package/dist/core/version.js +1 -1
  230. package/dist/native/sks-menubar/Sources/AlertFactory.swift +11 -3
  231. package/dist/native/sks-menubar/Sources/AppDelegate.swift +9 -0
  232. package/dist/native/sks-menubar/Sources/ControlCenterWindowController.swift +25 -3
  233. package/dist/native/sks-menubar/Sources/ControlKit.swift +19 -8
  234. package/dist/native/sks-menubar/Sources/DiagnosticsViewController.swift +1 -2
  235. package/dist/native/sks-menubar/Sources/MCPServersViewController.swift +45 -17
  236. package/dist/native/sks-menubar/Sources/OverviewSummary.swift +162 -0
  237. package/dist/native/sks-menubar/Sources/OverviewViewController.swift +136 -190
  238. package/dist/native/sks-menubar/Sources/ProcessClient.swift +107 -11
  239. package/dist/native/sks-menubar/Sources/ProvidersMultiProvider.swift +5 -1
  240. package/dist/native/sks-menubar/Sources/ProvidersOpenRouter.swift +16 -4
  241. package/dist/native/sks-menubar/Sources/ProvidersRoleModels.swift +4 -1
  242. package/dist/native/sks-menubar/Sources/ProvidersRoutingTruth.swift +131 -0
  243. package/dist/native/sks-menubar/Sources/ProvidersViewController.swift +288 -341
  244. package/dist/native/sks-menubar/Sources/RemoteTelegramCenterState.swift +447 -0
  245. package/dist/native/sks-menubar/Sources/RemoteTelegramRendering.swift +484 -0
  246. package/dist/native/sks-menubar/Sources/RemoteTelegramViewController.swift +364 -115
  247. package/dist/native/sks-menubar/Sources/SettingsViewController.swift +73 -12
  248. package/dist/native/sks-menubar/Sources/SidebarItem.swift +3 -3
  249. package/dist/native/sks-menubar/Sources/StatusItemController.swift +13 -13
  250. package/dist/native/sks-menubar/Sources/TelegramHubSupervisor.swift +469 -0
  251. package/dist/native/sks-menubar/Sources/UpdatesViewController.swift +1 -6
  252. package/dist/native/sks-menubar/Tests/AppRuntimeTestSupport.swift +12 -0
  253. package/dist/native/sks-menubar/Tests/NativeTelegramRegressionRunner.swift +55 -0
  254. package/dist/native/sks-menubar/Tests/ProcessClientTests.swift +33 -0
  255. package/dist/native/sks-menubar/Tests/ProvidersViewControllerTests.swift +142 -0
  256. package/dist/native/sks-menubar/Tests/RemoteTelegramCenterStateTests.swift +56 -0
  257. package/dist/native/sks-menubar/Tests/TelegramHubSupervisorTests.swift +55 -0
  258. package/dist/scripts/codex-lb-catalog-passthrough-check.js +120 -0
  259. package/dist/scripts/codex-lb-desktop-auth-invariant-check.js +169 -0
  260. package/dist/scripts/codex-lb-desktop-bridge-check.js +394 -0
  261. package/dist/scripts/codex-lb-desktop-bridge-latency-check.js +196 -0
  262. package/dist/scripts/codex-lb-desktop-capabilities-check.js +287 -0
  263. package/dist/scripts/codex-lb-desktop-real-evidence-check.js +123 -0
  264. package/dist/scripts/codex-lb-fast-mode-truth-check.js +10 -3
  265. package/dist/scripts/codex-lb-fast-ui-preservation-check.js +81 -40
  266. package/dist/scripts/codex-lb-gpt56-fast-profile-check.js +99 -37
  267. package/dist/scripts/context-graph-check.js +191 -0
  268. package/dist/scripts/doctor-fixes-codex-app-fast-ui-check.js +1 -1
  269. package/dist/scripts/gate-policy-audit-check.js +1 -1
  270. package/dist/scripts/helper-dedup-check.js +0 -2
  271. package/dist/scripts/installed-package-smoke-check.js +4 -1
  272. package/dist/scripts/latest-version-guidance-check.js +74 -0
  273. package/dist/scripts/release-metadata-check.js +21 -4
  274. package/dist/scripts/release-real-check.js +7 -0
  275. package/dist/scripts/ux-review-imagegen-blackbox-check.js +25 -1
  276. package/dist/scripts/ux-review-run-wires-imagegen-check.js +9 -1
  277. package/package.json +8 -3
  278. package/release-gates.v2.json +176 -1
  279. package/runtime-required-scripts.json +30 -0
  280. package/schemas/triwiki/context-graph.schema.json +119 -0
  281. package/dist/cli/install-helpers-codex-lb-selftest-chain.js +0 -112
  282. package/dist/cli/install-helpers-codex-lb-selftest.js +0 -481
  283. package/dist/core/triwiki/code-index-scanner.js +0 -309
@@ -0,0 +1,178 @@
1
+ import { CONTEXT_GRAPH_QUERY_SCHEMA, emptyContextGraphQueryResult } from '../query-types.js';
2
+ import { CONTEXT_GRAPH_TRAVERSAL_CAPS, contextGraphQueryProfile } from '../profiles.js';
3
+ import { isWorkspaceRelativePosixPath } from '../paths.js';
4
+ import { explainContextGraphCandidates, toContextGraphSelectedNode, contextGraphProvenanceCoverage } from './explain.js';
5
+ import { loadContextGraphIndex } from './load.js';
6
+ import { packContextGraphSelection } from './pack.js';
7
+ import { isHighRiskScope, rankContextGraphCandidates } from './rank.js';
8
+ import { CONTEXT_GRAPH_RANKING_CONFIG } from './ranking-config.js';
9
+ import { resolveContextGraphSeeds } from './seeds.js';
10
+ import { traverseContextGraph } from './traverse.js';
11
+ function add(into, reason, count) {
12
+ if (count <= 0)
13
+ return;
14
+ into[reason] = (into[reason] ?? 0) + count;
15
+ }
16
+ function usableFocusPaths(request) {
17
+ const out = [];
18
+ for (const focus of request.focusPaths ?? []) {
19
+ const normalized = String(focus ?? '').replace(/^\.\//, '').replace(/\/+$/, '');
20
+ if (normalized && isWorkspaceRelativePosixPath(normalized) && !out.includes(normalized))
21
+ out.push(normalized);
22
+ }
23
+ return out;
24
+ }
25
+ export function queryContextGraphSnapshot(index, request, options = {}) {
26
+ const clock = options.clock ?? Date.now;
27
+ const startedAt = clock();
28
+ const config = options.config ?? CONTEXT_GRAPH_RANKING_CONFIG;
29
+ const profile = contextGraphQueryProfile(request.profile);
30
+ const caps = CONTEXT_GRAPH_TRAVERSAL_CAPS;
31
+ const tokenBudget = Math.max(0, request.tokenBudget ?? caps.defaultTokenBudget);
32
+ const maxSelected = Math.max(0, Math.min(request.maxSelected ?? caps.maxSelectedNodes, caps.maxSelectedNodes));
33
+ const timeoutMs = Math.max(0, request.timeoutMs ?? caps.queryTimeoutMs);
34
+ const deadline = timeoutMs > 0 ? startedAt + timeoutMs : null;
35
+ const warnings = [...(options.warnings ?? [])];
36
+ const resolution = resolveContextGraphSeeds({ index, request, config, maxSeeds: caps.maxSeeds });
37
+ if (resolution.unknownProvidedSeeds > 0) {
38
+ warnings.push(`${resolution.unknownProvidedSeeds} caller-supplied seed(s) are not present in this snapshot`);
39
+ }
40
+ if (resolution.scanBudgetExhausted) {
41
+ warnings.push('lexical seeding stopped at its scan budget; results may be incomplete');
42
+ }
43
+ if (resolution.seeds.length === 0) {
44
+ warnings.push('no graph node matched this query; nothing was selected and no text fallback was attempted');
45
+ }
46
+ const focusPaths = usableFocusPaths(request);
47
+ const highRisk = isHighRiskScope(index, resolution.seeds, request);
48
+ const maxDepth = highRisk ? profile.maxDepthHighRisk : profile.maxDepth;
49
+ const traversal = traverseContextGraph({
50
+ index,
51
+ seeds: resolution.seeds,
52
+ profile,
53
+ maxDepth,
54
+ maxVisitedNodes: caps.maxVisitedNodes,
55
+ maxVisitedEdges: caps.maxVisitedEdges,
56
+ config,
57
+ focusPaths,
58
+ deadline
59
+ });
60
+ const seedsByNode = new Map(resolution.seeds.map((seed) => [seed.nodeId, seed]));
61
+ const ranked = rankContextGraphCandidates({
62
+ index,
63
+ states: traversal.states,
64
+ seedsByNode,
65
+ request,
66
+ config,
67
+ focusActive: focusPaths.length > 0
68
+ });
69
+ if (ranked.focusExcluded > 0) {
70
+ warnings.push(`${ranked.focusExcluded} reachable node(s) were outside the requested focus paths`);
71
+ }
72
+ const explainResult = explainContextGraphCandidates({
73
+ index,
74
+ states: traversal.states,
75
+ candidates: ranked.candidates,
76
+ config
77
+ });
78
+ const packed = packContextGraphSelection({
79
+ explained: explainResult.explained,
80
+ tokenBudget,
81
+ maxSelected,
82
+ profile: profile.name,
83
+ highRisk,
84
+ config
85
+ });
86
+ warnings.push(...packed.warnings);
87
+ const omissionReasons = { ...packed.omissions };
88
+ add(omissionReasons, 'stale_node', ranked.staleExcluded);
89
+ add(omissionReasons, 'invalidated_proof', ranked.invalidatedExcluded);
90
+ add(omissionReasons, 'redundant_sibling', ranked.redundantExcluded);
91
+ add(omissionReasons, 'no_provenance', explainResult.ungrounded);
92
+ add(omissionReasons, 'depth_limit', traversal.depthLimited);
93
+ add(omissionReasons, 'visit_cap', (traversal.nodeCapHit ? 1 : 0) + resolution.droppedSeeds);
94
+ add(omissionReasons, 'edge_cap', traversal.edgeCapHit ? 1 : 0);
95
+ add(omissionReasons, 'timeout', traversal.timedOut ? 1 : 0);
96
+ const selected = packed.selected.map(toContextGraphSelectedNode);
97
+ const truncated = packed.truncated || traversal.nodeCapHit || traversal.edgeCapHit || traversal.timedOut || resolution.droppedSeeds > 0;
98
+ return {
99
+ schema: CONTEXT_GRAPH_QUERY_SCHEMA,
100
+ ok: true,
101
+ snapshotHash: index.snapshot.snapshotHash,
102
+ snapshotFreshness: options.snapshotFreshness ?? 'fresh',
103
+ profile: profile.name,
104
+ seeds: resolution.seeds,
105
+ seedCount: resolution.seeds.length,
106
+ visitedNodes: traversal.visitedNodes,
107
+ visitedEdges: traversal.visitedEdges,
108
+ selected,
109
+ selectedNodes: selected.length,
110
+ explanationPathCount: selected.filter((node) => node.explanation.length > 0).length,
111
+ provenanceCoverage: contextGraphProvenanceCoverage(selected),
112
+ staleExcluded: ranked.staleExcluded,
113
+ invalidatedExcluded: ranked.invalidatedExcluded,
114
+ tokenCost: packed.tokenCost,
115
+ tokenBudget,
116
+ truncated,
117
+ timeout: traversal.timedOut,
118
+ omissionReasons,
119
+ warnings,
120
+ errors: [],
121
+ durationMs: Math.max(0, clock() - startedAt),
122
+ processSpawns: 0
123
+ };
124
+ }
125
+ function failedResult(profile, snapshotHash, errors, warnings, tokenBudget, durationMs) {
126
+ const base = emptyContextGraphQueryResult(snapshotHash, profile, [...errors]);
127
+ return { ...base, warnings: [...warnings], tokenBudget, durationMs };
128
+ }
129
+ export async function queryContextGraph(request, options = {}) {
130
+ const clock = options.clock ?? Date.now;
131
+ const startedAt = clock();
132
+ const profileName = contextGraphQueryProfile(request.profile).name;
133
+ const tokenBudget = Math.max(0, request.tokenBudget ?? CONTEXT_GRAPH_TRAVERSAL_CAPS.defaultTokenBudget);
134
+ if (options.index) {
135
+ return queryContextGraphSnapshot(options.index, request, options);
136
+ }
137
+ const load = await loadContextGraphIndex(request.root, options);
138
+ if (!load.ok || !load.index) {
139
+ return failedResult(profileName, load.snapshotHash, load.errors, load.warnings, tokenBudget, Math.max(0, clock() - startedAt));
140
+ }
141
+ const snapshotOptions = {
142
+ ...(options.config === undefined ? {} : { config: options.config }),
143
+ ...(options.clock === undefined ? {} : { clock: options.clock }),
144
+ snapshotFreshness: load.freshness,
145
+ warnings: [...load.warnings, ...(options.warnings ?? [])]
146
+ };
147
+ return queryContextGraphSnapshot(load.index, request, snapshotOptions);
148
+ }
149
+ export function contextGraphSearchMeta(result) {
150
+ const omissionReasons = {};
151
+ for (const [reason, count] of Object.entries(result.omissionReasons)) {
152
+ if (typeof count === 'number' && count > 0)
153
+ omissionReasons[reason] = count;
154
+ }
155
+ return {
156
+ snapshotHash: result.snapshotHash,
157
+ snapshotFreshness: result.snapshotFreshness,
158
+ profile: result.profile,
159
+ seedCount: result.seedCount,
160
+ visitedNodes: result.visitedNodes,
161
+ selectedNodes: result.selectedNodes,
162
+ explanationPathCount: result.explanationPathCount,
163
+ provenanceCoverage: result.provenanceCoverage,
164
+ staleExcluded: result.staleExcluded,
165
+ invalidatedExcluded: result.invalidatedExcluded,
166
+ tokenCost: result.tokenCost,
167
+ tokenBudget: result.tokenBudget,
168
+ omissionReasons
169
+ };
170
+ }
171
+ export { CONTEXT_GRAPH_RANKING_CONFIG, CONTEXT_GRAPH_RANKING_SCHEMA, CONTEXT_GRAPH_EXACT_SEED_CONFIDENCES, isExactContextGraphSeedConfidence } from './ranking-config.js';
172
+ export { normalizeContextGraphQuery, resolveContextGraphSeeds, seedConfidenceFor } from './seeds.js';
173
+ export { traverseContextGraph, contextGraphNodePath, isUnderFocusPath } from './traverse.js';
174
+ export { rankContextGraphCandidates, contextGraphGroupKey, isInvalidatedContextGraphNode, isHighRiskScope } from './rank.js';
175
+ export { explainContextGraphCandidates, groundContextGraphNode, toContextGraphSelectedNode, contextGraphProvenanceCoverage } from './explain.js';
176
+ export { packContextGraphSelection } from './pack.js';
177
+ export { loadContextGraphIndex, contextGraphRepairHint } from './load.js';
178
+ export { CONTEXT_GRAPH_SNAPSHOT_CACHE_MAX_ENTRIES, cacheContextGraphIndex, clearContextGraphSnapshotCache, contextGraphSnapshotCacheStats, contextGraphWorkspaceKey, getCachedContextGraphIndex } from './snapshot-cache.js';
@@ -0,0 +1,116 @@
1
+ import { CONTEXT_GRAPH_CORRUPT_ERROR, CONTEXT_GRAPH_MISSING_ERROR, CONTEXT_GRAPH_REPAIR_COMMAND, CONTEXT_GRAPH_SCHEMA_REVISION, CONTEXT_GRAPH_STALE_ERROR } from '../contracts.js';
2
+ import { readSourceHashes } from '../compiler/freshness.js';
3
+ import { buildContextGraphIndex } from '../graph-index.js';
4
+ import { readContextGraphMeta, readContextGraphSnapshot } from '../store/snapshot-store.js';
5
+ import { cacheContextGraphIndex, getCachedContextGraphIndex } from './snapshot-cache.js';
6
+ const DEFAULT_MAX_VERIFIED_SOURCES = 4000;
7
+ export function contextGraphRepairHint() {
8
+ return `Run \`${CONTEXT_GRAPH_REPAIR_COMMAND}\` to rebuild the context graph.`;
9
+ }
10
+ function failure(code, detail, snapshotHash = '') {
11
+ return {
12
+ ok: false,
13
+ index: null,
14
+ snapshotHash,
15
+ errorCode: code,
16
+ errors: [code, detail, contextGraphRepairHint()],
17
+ warnings: [],
18
+ cacheHit: false,
19
+ freshness: 'stale'
20
+ };
21
+ }
22
+ function statusFailure(status) {
23
+ if (status.status === 'fresh')
24
+ return null;
25
+ const code = status.status === 'missing'
26
+ ? CONTEXT_GRAPH_MISSING_ERROR
27
+ : status.status === 'corrupt'
28
+ ? CONTEXT_GRAPH_CORRUPT_ERROR
29
+ : CONTEXT_GRAPH_STALE_ERROR;
30
+ const declared = status.reasons ?? [];
31
+ const reasons = declared.length > 0 ? ` (${declared.join(', ')})` : '';
32
+ return failure(code, `the stored context graph is ${status.status}${reasons}`, status.snapshotHash ?? '');
33
+ }
34
+ async function sourcesChanged(root, inputHashes, limit) {
35
+ const recorded = Object.keys(inputHashes).sort().slice(0, Math.max(0, limit));
36
+ if (recorded.length === 0)
37
+ return false;
38
+ const observed = await readSourceHashes(root, recorded);
39
+ for (const file of recorded) {
40
+ if (observed[file] !== inputHashes[file])
41
+ return true;
42
+ }
43
+ return false;
44
+ }
45
+ export async function loadContextGraphIndex(root, options = {}) {
46
+ const supplied = options.status;
47
+ if (supplied) {
48
+ const blocked = statusFailure(supplied);
49
+ if (blocked && !(supplied.status === 'stale' && options.allowStale === true))
50
+ return blocked;
51
+ }
52
+ const metaLoad = await readContextGraphMeta(root);
53
+ if (metaLoad.status === 'missing')
54
+ return failure(CONTEXT_GRAPH_MISSING_ERROR, 'the context graph has not been built');
55
+ if (metaLoad.status !== 'ok' || !metaLoad.meta) {
56
+ return failure(CONTEXT_GRAPH_CORRUPT_ERROR, 'the context graph metadata is unreadable');
57
+ }
58
+ const meta = metaLoad.meta;
59
+ const warnings = [];
60
+ if (options.verifySources === true) {
61
+ const changed = await sourcesChanged(root, meta.inputHashes ?? {}, options.maxVerifiedSources ?? DEFAULT_MAX_VERIFIED_SOURCES);
62
+ if (changed && options.allowStale !== true) {
63
+ return failure(CONTEXT_GRAPH_STALE_ERROR, 'a recorded source no longer hashes to its stored value', meta.snapshotHash);
64
+ }
65
+ if (changed)
66
+ warnings.push('answering over a stale context graph on request');
67
+ }
68
+ else if (!supplied) {
69
+ warnings.push(`context graph freshness was not verified by this query; ${contextGraphRepairHint()}`);
70
+ }
71
+ const useCache = options.cache !== false;
72
+ if (useCache) {
73
+ const cached = getCachedContextGraphIndex(root, meta.snapshotHash);
74
+ if (cached) {
75
+ return {
76
+ ok: true,
77
+ index: cached,
78
+ snapshotHash: meta.snapshotHash,
79
+ errorCode: null,
80
+ errors: [],
81
+ warnings,
82
+ cacheHit: true,
83
+ freshness: supplied?.status === 'stale' ? 'stale' : 'fresh'
84
+ };
85
+ }
86
+ }
87
+ const snapshotLoad = await readContextGraphSnapshot(root);
88
+ if (snapshotLoad.status === 'missing') {
89
+ return failure(CONTEXT_GRAPH_MISSING_ERROR, 'the context graph snapshot is absent while its metadata is present');
90
+ }
91
+ if (snapshotLoad.status !== 'ok' || !snapshotLoad.snapshot) {
92
+ return failure(CONTEXT_GRAPH_CORRUPT_ERROR, 'the context graph snapshot failed structural validation');
93
+ }
94
+ const snapshot = snapshotLoad.snapshot;
95
+ if (snapshot.snapshotHash !== meta.snapshotHash
96
+ || snapshot.nodeCount !== meta.nodeCount
97
+ || snapshot.edgeCount !== meta.edgeCount) {
98
+ return failure(CONTEXT_GRAPH_CORRUPT_ERROR, 'the snapshot and its metadata describe different graphs', snapshot.snapshotHash);
99
+ }
100
+ if (snapshot.schemaRevision !== CONTEXT_GRAPH_SCHEMA_REVISION) {
101
+ return failure(CONTEXT_GRAPH_STALE_ERROR, 'the snapshot was written by a different graph schema revision', snapshot.snapshotHash);
102
+ }
103
+ const index = buildContextGraphIndex(snapshot);
104
+ if (useCache)
105
+ cacheContextGraphIndex(root, snapshot.snapshotHash, index);
106
+ return {
107
+ ok: true,
108
+ index,
109
+ snapshotHash: snapshot.snapshotHash,
110
+ errorCode: null,
111
+ errors: [],
112
+ warnings,
113
+ cacheHit: false,
114
+ freshness: supplied?.status === 'stale' ? 'stale' : 'fresh'
115
+ };
116
+ }
@@ -0,0 +1,117 @@
1
+ import { compareContextGraphIds } from '../ids.js';
2
+ function bump(into, reason) {
3
+ into[reason] = (into[reason] ?? 0) + 1;
4
+ }
5
+ function isProtectedGate(entry) {
6
+ return entry.candidate.node.risk === 'protected';
7
+ }
8
+ function isImplementationEvidence(entry) {
9
+ const kind = entry.candidate.node.kind;
10
+ return kind === 'test' || kind === 'gate';
11
+ }
12
+ function byScoreThenId(left, right) {
13
+ if (left.candidate.score !== right.candidate.score)
14
+ return right.candidate.score - left.candidate.score;
15
+ return compareContextGraphIds(left.candidate.node.id, right.candidate.node.id);
16
+ }
17
+ class Packer {
18
+ budget;
19
+ limit;
20
+ chosen = new Map();
21
+ perGroup = new Map();
22
+ omissions = {};
23
+ spent = 0;
24
+ constructor(budget, limit) {
25
+ this.budget = budget;
26
+ this.limit = limit;
27
+ }
28
+ has(entry) {
29
+ return this.chosen.has(entry.candidate.node.id);
30
+ }
31
+ take(entry) {
32
+ if (this.chosen.size >= this.limit) {
33
+ bump(this.omissions, 'max_selected');
34
+ return false;
35
+ }
36
+ const cost = entry.candidate.tokenCost;
37
+ if (this.spent + cost > this.budget) {
38
+ bump(this.omissions, 'token_budget');
39
+ return false;
40
+ }
41
+ this.chosen.set(entry.candidate.node.id, entry);
42
+ this.spent += cost;
43
+ const group = entry.candidate.groupKey;
44
+ this.perGroup.set(group, (this.perGroup.get(group) ?? 0) + 1);
45
+ return true;
46
+ }
47
+ groupCount(entry) {
48
+ return this.perGroup.get(entry.candidate.groupKey) ?? 0;
49
+ }
50
+ }
51
+ export function packContextGraphSelection(input) {
52
+ const { explained, tokenBudget, maxSelected, profile, highRisk, config } = input;
53
+ const ordered = [...explained].sort(byScoreThenId);
54
+ const packer = new Packer(Math.max(0, tokenBudget), Math.max(0, maxSelected));
55
+ const warnings = [];
56
+ const exactSeeds = ordered.filter((entry) => entry.candidate.exactSeed);
57
+ const protectedGates = ordered.filter(isProtectedGate);
58
+ const implementationEvidence = ordered.filter(isImplementationEvidence);
59
+ const reserved = [];
60
+ if (highRisk) {
61
+ for (const gate of protectedGates.slice(0, config.protectedGateReserveSlots))
62
+ reserved.push(gate);
63
+ }
64
+ const firstExactSeed = exactSeeds[0];
65
+ if (firstExactSeed)
66
+ reserved.push(firstExactSeed);
67
+ if (profile === 'implementation') {
68
+ for (const evidence of implementationEvidence.slice(0, config.testOrGateReserveSlots))
69
+ reserved.push(evidence);
70
+ }
71
+ for (const entry of reserved) {
72
+ if (packer.has(entry))
73
+ continue;
74
+ packer.take(entry);
75
+ }
76
+ const slotAllowance = Math.max(config.minGroupSlots, Math.ceil(Math.max(0, maxSelected) * config.moduleShareCap));
77
+ const distinctGroups = new Set(ordered.map((entry) => entry.candidate.groupKey)).size;
78
+ const diversityApplies = distinctGroups > 1;
79
+ for (const entry of ordered) {
80
+ if (packer.has(entry))
81
+ continue;
82
+ if (diversityApplies && packer.groupCount(entry) >= slotAllowance) {
83
+ bump(packer.omissions, 'redundant_sibling');
84
+ continue;
85
+ }
86
+ packer.take(entry);
87
+ }
88
+ const selected = [...packer.chosen.values()].sort(byScoreThenId);
89
+ const selectedIds = new Set(selected.map((entry) => entry.candidate.node.id));
90
+ const protectedSelected = protectedGates.filter((entry) => selectedIds.has(entry.candidate.node.id)).length;
91
+ const guarantees = {
92
+ exactSeedSelected: selected.some((entry) => entry.candidate.exactSeed),
93
+ exactSeedAvailable: exactSeeds.length > 0,
94
+ protectedGatesReachable: protectedGates.length,
95
+ protectedGatesSelected: protectedSelected,
96
+ implementationEvidenceReachable: implementationEvidence.length > 0,
97
+ implementationEvidenceSelected: implementationEvidence.some((entry) => selectedIds.has(entry.candidate.node.id))
98
+ };
99
+ if (guarantees.exactSeedAvailable && !guarantees.exactSeedSelected) {
100
+ warnings.push('exact seed did not fit the token budget; widen tokenBudget or narrow the query');
101
+ }
102
+ if (highRisk && guarantees.protectedGatesReachable > guarantees.protectedGatesSelected) {
103
+ warnings.push('a reachable protected gate did not fit the token budget on a high-risk query');
104
+ }
105
+ if (profile === 'implementation' && guarantees.implementationEvidenceReachable && !guarantees.implementationEvidenceSelected) {
106
+ warnings.push('no reachable test or gate fit the token budget on an implementation query');
107
+ }
108
+ const truncated = (packer.omissions.token_budget ?? 0) > 0 || (packer.omissions.max_selected ?? 0) > 0;
109
+ return {
110
+ selected,
111
+ tokenCost: packer.spent,
112
+ omissions: packer.omissions,
113
+ truncated,
114
+ warnings,
115
+ guarantees
116
+ };
117
+ }
@@ -0,0 +1,142 @@
1
+ import { compareContextGraphIds, contextGraphPathFromId } from '../ids.js';
2
+ import { isExactContextGraphSeedConfidence } from './ranking-config.js';
3
+ export function contextGraphGroupKey(node) {
4
+ const nodePath = node.path ?? contextGraphPathFromId(node.id);
5
+ if (nodePath) {
6
+ const cut = nodePath.lastIndexOf('/');
7
+ return cut > 0 ? nodePath.slice(0, cut) : '.';
8
+ }
9
+ const module = node.metadata.module;
10
+ if (typeof module === 'string' && module)
11
+ return `module/${module}`;
12
+ return `kind/${node.kind}`;
13
+ }
14
+ export function isInvalidatedContextGraphNode(index, node) {
15
+ const metadata = node.metadata;
16
+ if (node.kind === 'proof') {
17
+ if (metadata.reusable === false)
18
+ return true;
19
+ if (metadata.corrupt === true)
20
+ return true;
21
+ if (metadata.expired === true)
22
+ return true;
23
+ const reasons = metadata.invalidation_reason_count;
24
+ if (typeof reasons === 'number' && reasons > 0)
25
+ return true;
26
+ }
27
+ for (const edgeId of index.outgoing.get(node.id) ?? []) {
28
+ if (index.edgesById.get(edgeId)?.type === 'invalidates')
29
+ return true;
30
+ }
31
+ return false;
32
+ }
33
+ function evidenceSourceCount(index, node, state) {
34
+ let count = 0;
35
+ if (node.path && node.contentHash)
36
+ count += 1;
37
+ if (state.parentEdgeId)
38
+ count += 1;
39
+ if ((index.outgoing.get(node.id)?.length ?? 0) > 0 || (index.incoming.get(node.id)?.length ?? 0) > 0)
40
+ count += 1;
41
+ return count;
42
+ }
43
+ export function isHighRiskScope(index, seeds, request) {
44
+ if (request.risk === 'high')
45
+ return true;
46
+ for (const seed of seeds) {
47
+ if (index.nodesById.get(seed.nodeId)?.risk === 'protected')
48
+ return true;
49
+ }
50
+ return false;
51
+ }
52
+ function baseScore(node, state, seed, input, invalidated, tokenCost, evidence) {
53
+ const config = input.config;
54
+ const exact = seed !== null && isExactContextGraphSeedConfidence(seed.confidence);
55
+ const seedBonus = seed === null ? 0 : exact ? config.exactSeedBonus : config.lexicalSeedBonus;
56
+ const riskScale = input.request.risk === 'high' ? config.highRiskRelevanceMultiplier : 1;
57
+ const evidenceBonus = Math.min(config.evidenceCoverageCap, config.evidenceCoverageBonus * evidence);
58
+ const stalePenalty = node.freshness === 'stale' ? config.stalePenalty : 0;
59
+ const invalidatedPenalty = invalidated ? config.invalidatedPenalty : 0;
60
+ const tokenPenalty = Math.min(config.tokenCostPenaltyCap, config.tokenCostPenaltyPerToken * tokenCost);
61
+ return (seedBonus
62
+ + state.weight
63
+ + config.trustBonus * node.trust
64
+ + config.freshnessBonus[node.freshness]
65
+ + config.riskRelevanceBonus[node.risk] * riskScale
66
+ + evidenceBonus
67
+ - stalePenalty
68
+ - invalidatedPenalty
69
+ - tokenPenalty);
70
+ }
71
+ function byScoreThenId(left, right) {
72
+ if (left.score !== right.score)
73
+ return right.score - left.score;
74
+ return compareContextGraphIds(left.node.id, right.node.id);
75
+ }
76
+ export function rankContextGraphCandidates(input) {
77
+ const { index, states, seedsByNode, config, focusActive } = input;
78
+ const candidates = [];
79
+ const excludedNodeIds = [];
80
+ let staleExcluded = 0;
81
+ let invalidatedExcluded = 0;
82
+ let focusExcluded = 0;
83
+ for (const state of states.values()) {
84
+ const node = index.nodesById.get(state.nodeId);
85
+ if (!node)
86
+ continue;
87
+ if (focusActive && !state.focusMatched) {
88
+ focusExcluded += 1;
89
+ continue;
90
+ }
91
+ const invalidated = isInvalidatedContextGraphNode(index, node);
92
+ if (node.freshness === 'stale') {
93
+ staleExcluded += 1;
94
+ excludedNodeIds.push(node.id);
95
+ continue;
96
+ }
97
+ if (invalidated) {
98
+ invalidatedExcluded += 1;
99
+ excludedNodeIds.push(node.id);
100
+ continue;
101
+ }
102
+ const seed = seedsByNode.get(state.nodeId) ?? null;
103
+ const tokenCost = Math.max(config.minTokenCost, node.tokenCost);
104
+ const evidence = evidenceSourceCount(index, node, state);
105
+ candidates.push({
106
+ node,
107
+ state,
108
+ seed,
109
+ exactSeed: seed !== null && isExactContextGraphSeedConfidence(seed.confidence),
110
+ groupKey: contextGraphGroupKey(node),
111
+ tokenCost,
112
+ evidenceSources: evidence,
113
+ score: baseScore(node, state, seed, input, invalidated, tokenCost, evidence),
114
+ redundancyPenalty: 0
115
+ });
116
+ }
117
+ candidates.sort(byScoreThenId);
118
+ const perGroup = new Map();
119
+ const kept = [];
120
+ let redundantExcluded = 0;
121
+ for (const candidate of candidates) {
122
+ const prior = perGroup.get(candidate.groupKey) ?? 0;
123
+ if (prior >= config.maxRedundancyGroupMembers && !candidate.exactSeed) {
124
+ redundantExcluded += 1;
125
+ continue;
126
+ }
127
+ perGroup.set(candidate.groupKey, prior + 1);
128
+ const penalty = Math.min(config.redundancyPenaltyCap, config.redundancyPenalty * prior);
129
+ candidate.redundancyPenalty = penalty;
130
+ candidate.score -= penalty;
131
+ kept.push(candidate);
132
+ }
133
+ kept.sort(byScoreThenId);
134
+ return {
135
+ candidates: kept,
136
+ staleExcluded,
137
+ invalidatedExcluded,
138
+ redundantExcluded,
139
+ focusExcluded,
140
+ excludedNodeIds: excludedNodeIds.sort(compareContextGraphIds)
141
+ };
142
+ }
@@ -0,0 +1,64 @@
1
+ export const CONTEXT_GRAPH_RANKING_SCHEMA = 'sks.context-graph-ranking.v1';
2
+ export const CONTEXT_GRAPH_EXACT_SEED_CONFIDENCES = [
3
+ 'exact_definition',
4
+ 'exact_reference',
5
+ 'manifest',
6
+ 'file_path'
7
+ ];
8
+ export const CONTEXT_GRAPH_RANKING_CONFIG = {
9
+ schema: CONTEXT_GRAPH_RANKING_SCHEMA,
10
+ seedConfidenceScore: {
11
+ exact_definition: 6,
12
+ exact_reference: 5,
13
+ manifest: 5,
14
+ syntactic_reference: 3.5,
15
+ file_path: 4,
16
+ text_candidate: 1.5
17
+ },
18
+ exactSeedBonus: 4,
19
+ lexicalSeedBonus: 0.5,
20
+ providedSeedScoreCeiling: 8,
21
+ edgeConfidenceMultiplier: {
22
+ exact: 1,
23
+ manifest: 0.95,
24
+ syntactic: 0.85,
25
+ observed: 0.7,
26
+ derived: 0.5
27
+ },
28
+ depthDecay: 0.6,
29
+ reverseEdgeMultiplier: 0.85,
30
+ trustBonus: 1.5,
31
+ freshnessBonus: { fresh: 0.75, unknown: 0, stale: -0.5 },
32
+ riskRelevanceBonus: { low: 0, medium: 0.25, high: 0.75, protected: 1.5 },
33
+ highRiskRelevanceMultiplier: 2,
34
+ evidenceCoverageBonus: 0.35,
35
+ evidenceCoverageCap: 1.05,
36
+ stalePenalty: 2.5,
37
+ invalidatedPenalty: 4,
38
+ redundancyPenalty: 0.6,
39
+ redundancyPenaltyCap: 3,
40
+ tokenCostPenaltyPerToken: 0.0015,
41
+ tokenCostPenaltyCap: 1.5,
42
+ minExactSeeds: 3,
43
+ maxLexicalSeeds: 8,
44
+ lexicalScanBudget: 50000,
45
+ lexicalMinTokenLength: 4,
46
+ lexicalMatchScore: 1.5,
47
+ maxQueryTokens: 24,
48
+ maxSeedsPerToken: 6,
49
+ timeoutCheckInterval: 512,
50
+ moduleShareCap: 0.4,
51
+ minGroupSlots: 2,
52
+ maxRedundancyGroupMembers: 12,
53
+ protectedGateReserveSlots: 8,
54
+ testOrGateReserveSlots: 1,
55
+ maxProvenancePerNode: 6,
56
+ minTokenCost: 1
57
+ };
58
+ const EXACT_SEED_CONFIDENCE_SET = new Set(CONTEXT_GRAPH_EXACT_SEED_CONFIDENCES);
59
+ export function isExactContextGraphSeedConfidence(value) {
60
+ return EXACT_SEED_CONFIDENCE_SET.has(value);
61
+ }
62
+ export function contextGraphSeedConfidenceScore(config, confidence) {
63
+ return config.seedConfidenceScore[confidence];
64
+ }