@hassangameryt/freeflow 0.3.0 → 0.5.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 (692) hide show
  1. package/.claude-plugin/marketplace.json +4 -4
  2. package/.claude-plugin/plugin.json +6 -2
  3. package/.codex-plugin/plugin.json +9 -9
  4. package/README.md +190 -127
  5. package/assets/feedback-loop.png +0 -0
  6. package/assets/freeflow_workflow_map.png +0 -0
  7. package/assets/workflow.png +0 -0
  8. package/{skills → capabilities}/output-router/SKILL.md +21 -17
  9. package/{skills → capabilities}/output-router/references/safety-policy.md +1 -1
  10. package/capabilities/output-router/references/setup.md +110 -0
  11. package/command-surface.json +62 -7
  12. package/hooks/freeflow-runtime-context.mjs +572 -154
  13. package/hooks/hooks.json +26 -1
  14. package/hooks/tests/check-runtime-context-hook.sh +375 -0
  15. package/package.json +24 -24
  16. package/pi-extension/dist/index.js +264 -80
  17. package/pi-extension/dist/integrations/mcp-config.js +29 -0
  18. package/pi-extension/dist/output-router/host-producer-identification.js +232 -0
  19. package/pi-extension/dist/output-router/native-safety-net.js +216 -0
  20. package/pi-extension/dist/output-router/observed-tool-routing.js +122 -0
  21. package/pi-extension/dist/output-router/renderers.js +1023 -0
  22. package/pi-extension/dist/output-router/router-tools.js +554 -0
  23. package/pi-extension/dist/output-router/schemas.js +383 -0
  24. package/pi-extension/dist/output-router/status.js +744 -0
  25. package/pi-extension/dist/output-router/utils.js +502 -0
  26. package/pi-extension/dist/runtime/runtime-context.js +798 -0
  27. package/pi-extension/dist/settings/settings-tui.js +314 -0
  28. package/pi-extension/dist/settings/settings-ui.js +1487 -0
  29. package/pi-extension/freeflow/index.js +1 -0
  30. package/pi-extension/src/index.ts +230 -56
  31. package/pi-extension/src/{host-producer-identification.ts → output-router/host-producer-identification.ts} +37 -7
  32. package/pi-extension/src/{native-safety-net.ts → output-router/native-safety-net.ts} +8 -12
  33. package/pi-extension/src/{observed-tool-routing.ts → output-router/observed-tool-routing.ts} +19 -11
  34. package/pi-extension/src/{renderers.ts → output-router/renderers.ts} +246 -55
  35. package/pi-extension/src/{router-tools.ts → output-router/router-tools.ts} +130 -29
  36. package/pi-extension/src/{schemas.ts → output-router/schemas.ts} +171 -43
  37. package/pi-extension/src/output-router/status.ts +791 -0
  38. package/pi-extension/src/{utils.ts → output-router/utils.ts} +80 -18
  39. package/pi-extension/src/runtime/runtime-context.ts +895 -0
  40. package/pi-extension/src/settings/settings-tui.ts +408 -0
  41. package/pi-extension/src/settings/settings-ui.ts +1730 -0
  42. package/pi-extension/tests/integration/pi-extension.test.js +4020 -0
  43. package/pi-extension/tests/output-router/observed-producers.test.js +132 -0
  44. package/pi-extension/tests/output-router/search.test.js +722 -0
  45. package/pi-extension/tests/settings/settings-tui.test.js +243 -0
  46. package/router/dist/benchmarks/benchmark-harness.d.ts +16 -13
  47. package/router/dist/benchmarks/benchmark-harness.js +62 -62
  48. package/router/dist/benchmarks/benchmarks.d.ts +80 -73
  49. package/router/dist/benchmarks/benchmarks.js +860 -761
  50. package/router/dist/benchmarks/codex-qa-benchmarks.d.ts +71 -67
  51. package/router/dist/benchmarks/codex-qa-benchmarks.js +429 -390
  52. package/router/dist/benchmarks/command-benchmarks.d.ts +107 -92
  53. package/router/dist/benchmarks/command-benchmarks.js +616 -571
  54. package/router/dist/benchmarks/context-mode-normalized-benchmarks.d.ts +64 -56
  55. package/router/dist/benchmarks/context-mode-normalized-benchmarks.js +679 -613
  56. package/router/dist/benchmarks/context-mode-real-deep-benchmark.d.ts +103 -95
  57. package/router/dist/benchmarks/context-mode-real-deep-benchmark.js +1188 -1103
  58. package/router/dist/benchmarks/context-saving-baseline.d.ts +47 -41
  59. package/router/dist/benchmarks/context-saving-baseline.js +405 -374
  60. package/router/dist/benchmarks/index-benchmarks.d.ts +74 -69
  61. package/router/dist/benchmarks/index-benchmarks.js +761 -661
  62. package/router/dist/benchmarks/storage-policy-benchmarks.d.ts +80 -69
  63. package/router/dist/benchmarks/storage-policy-benchmarks.js +549 -469
  64. package/router/dist/benchmarks/vault-index-benchmarks.d.ts +43 -34
  65. package/router/dist/benchmarks/vault-index-benchmarks.js +294 -229
  66. package/router/dist/config/config.d.ts +62 -55
  67. package/router/dist/config/config.js +552 -373
  68. package/router/dist/config/router-contract.d.ts +2 -2
  69. package/router/dist/config/router-contract.js +38 -38
  70. package/router/dist/config/schema.d.ts +19 -10
  71. package/router/dist/config/schema.js +586 -538
  72. package/router/dist/config/types.d.ts +413 -361
  73. package/router/dist/config/types.js +19 -8
  74. package/router/dist/evidence/bounded-evidence.d.ts +26 -26
  75. package/router/dist/evidence/bounded-evidence.js +265 -252
  76. package/router/dist/evidence/evidence-range-selector.d.ts +16 -14
  77. package/router/dist/evidence/evidence-range-selector.js +192 -191
  78. package/router/dist/evidence/evidence-search.d.ts +18 -16
  79. package/router/dist/evidence/evidence-search.js +401 -377
  80. package/router/dist/evidence/evidence.d.ts +17 -17
  81. package/router/dist/evidence/evidence.js +163 -159
  82. package/router/dist/evidence/failure-contracts.d.ts +25 -15
  83. package/router/dist/evidence/failure-contracts.js +132 -126
  84. package/router/dist/evidence/line-ranges.d.ts +17 -15
  85. package/router/dist/evidence/line-ranges.js +18 -18
  86. package/router/dist/experiments/local-index.d.ts +47 -41
  87. package/router/dist/experiments/local-index.js +477 -458
  88. package/router/dist/local/local-traversal.d.ts +18 -0
  89. package/router/dist/local/local-traversal.js +334 -0
  90. package/router/dist/processing/engine.d.ts +94 -70
  91. package/router/dist/processing/engine.js +462 -364
  92. package/router/dist/processing/reducers.d.ts +208 -194
  93. package/router/dist/processing/reducers.js +1434 -1256
  94. package/router/dist/processing/renderers.d.ts +24 -18
  95. package/router/dist/processing/renderers.js +161 -152
  96. package/router/dist/processing/scripts.d.ts +80 -67
  97. package/router/dist/processing/scripts.js +343 -290
  98. package/router/dist/repo/repo-traversal.d.ts +9 -9
  99. package/router/dist/repo/repo-traversal.js +205 -202
  100. package/router/dist/routing/observed-reducers.d.ts +25 -19
  101. package/router/dist/routing/observed-reducers.js +559 -545
  102. package/router/dist/routing/observed-routing.d.ts +23 -14
  103. package/router/dist/routing/observed-routing.js +319 -318
  104. package/router/dist/routing/parsers.d.ts +10 -10
  105. package/router/dist/routing/parsers.js +454 -406
  106. package/router/dist/routing/run-filters.d.ts +45 -41
  107. package/router/dist/routing/run-filters.js +215 -207
  108. package/router/dist/routing/run-reducers.d.ts +45 -26
  109. package/router/dist/routing/run-reducers.js +102 -90
  110. package/router/dist/sandbox/adapter-roots.d.ts +34 -26
  111. package/router/dist/sandbox/adapter-roots.js +43 -41
  112. package/router/dist/sandbox/eryx-python-adapter.d.ts +9 -5
  113. package/router/dist/sandbox/eryx-python-adapter.js +659 -588
  114. package/router/dist/sandbox/jq-wasm-adapter.d.ts +3 -3
  115. package/router/dist/sandbox/jq-wasm-adapter.js +319 -311
  116. package/router/dist/sandbox/quickjs-wasi-adapter.d.ts +9 -5
  117. package/router/dist/sandbox/quickjs-wasi-adapter.js +336 -333
  118. package/router/dist/sandbox/script-sandbox.d.ts +105 -84
  119. package/router/dist/sandbox/script-sandbox.js +294 -260
  120. package/router/dist/setup/script-transform-adapters.d.ts +23 -19
  121. package/router/dist/setup/script-transform-adapters.js +223 -204
  122. package/router/dist/tools/batch.d.ts +27 -16
  123. package/router/dist/tools/batch.js +493 -416
  124. package/router/dist/tools/run.d.ts +47 -35
  125. package/router/dist/tools/run.js +1172 -1087
  126. package/router/dist/tools/search.d.ts +53 -31
  127. package/router/dist/tools/search.js +1224 -1065
  128. package/router/dist/transform/engine.d.ts +121 -96
  129. package/router/dist/transform/engine.js +1853 -1736
  130. package/router/dist/vault/vault-index.d.ts +97 -78
  131. package/router/dist/vault/vault-index.js +347 -342
  132. package/router/dist/vault/vault.d.ts +109 -74
  133. package/router/dist/vault/vault.js +528 -533
  134. package/runtime/interaction-contract.md +16 -0
  135. package/skills/bypass/SKILL.md +52 -38
  136. package/skills/commit-work/SKILL.md +54 -46
  137. package/skills/commit-work/references/staging-decisions.md +46 -24
  138. package/skills/decision-gate/SKILL.md +48 -0
  139. package/skills/design-for-depth/SKILL.md +75 -59
  140. package/skills/design-for-depth/references/design-pressure-signals.md +56 -7
  141. package/skills/design-for-depth/references/interface-design-loop.md +156 -0
  142. package/skills/design-for-depth/references/software-design-philosophy.md +32 -3
  143. package/skills/diagnose-failure/SKILL.md +65 -60
  144. package/skills/diagnose-failure/references/diagnostic-loop-catalog.md +36 -0
  145. package/skills/diagnose-failure/references/flaky-and-performance.md +30 -18
  146. package/skills/discuss/SKILL.md +121 -0
  147. package/skills/discuss/references/checkpoints.md +66 -0
  148. package/skills/evaluate-skill/SKILL.md +62 -53
  149. package/skills/evaluate-skill/references/definition-schema.md +345 -0
  150. package/skills/evaluate-skill/references/evaluation-design.md +86 -0
  151. package/skills/evaluate-skill/references/execution-and-evidence.md +85 -0
  152. package/skills/evaluate-skill/references/review-and-revision.md +51 -0
  153. package/skills/evaluate-skill/scripts/lib/definitions.mjs +296 -0
  154. package/skills/evaluate-skill/scripts/lib/evidence.mjs +46 -0
  155. package/skills/evaluate-skill/scripts/lib/grade-comparison.mjs +60 -0
  156. package/skills/evaluate-skill/scripts/lib/grade-interaction.mjs +148 -0
  157. package/skills/evaluate-skill/scripts/lib/grade-support.mjs +126 -0
  158. package/skills/evaluate-skill/scripts/lib/grade-workspace.mjs +192 -0
  159. package/skills/evaluate-skill/scripts/lib/grade.mjs +56 -0
  160. package/skills/evaluate-skill/scripts/lib/pi.mjs +489 -0
  161. package/skills/evaluate-skill/scripts/lib/process.mjs +79 -0
  162. package/skills/evaluate-skill/scripts/lib/rpc.mjs +444 -0
  163. package/skills/evaluate-skill/scripts/lib/runner.mjs +346 -0
  164. package/skills/evaluate-skill/scripts/lib/sandbox.mjs +409 -0
  165. package/skills/evaluate-skill/scripts/lib/view.mjs +337 -0
  166. package/skills/evaluate-skill/scripts/pi-guard.mjs +164 -0
  167. package/skills/evaluate-skill/scripts/skill-eval.mjs +101 -0
  168. package/skills/execute-work/SKILL.md +99 -0
  169. package/skills/execute-work/references/code-practices.md +78 -0
  170. package/skills/execute-work/references/execution-loop.md +77 -0
  171. package/skills/finish-branch/SKILL.md +117 -0
  172. package/skills/finish-branch/references/integration-options.md +80 -0
  173. package/skills/handoff/SKILL.md +65 -39
  174. package/skills/handoff/references/templates.md +104 -27
  175. package/skills/launch-work/SKILL.md +116 -0
  176. package/skills/launch-work/references/launch-readiness.md +85 -0
  177. package/skills/migration-work/SKILL.md +115 -0
  178. package/skills/migration-work/references/migration-lifecycle.md +82 -0
  179. package/skills/mode-contract/SKILL.md +72 -52
  180. package/skills/release-work/SKILL.md +118 -0
  181. package/skills/release-work/references/release-evidence.md +78 -0
  182. package/skills/review-artifact/SKILL.md +77 -69
  183. package/skills/review-artifact/references/reviewer-prompt.md +133 -42
  184. package/skills/review-work/SKILL.md +82 -57
  185. package/skills/review-work/references/reviewer-prompt.md +97 -60
  186. package/skills/review-work/references/security-risk-lens.md +67 -0
  187. package/skills/setup-freeflow/SKILL.md +54 -68
  188. package/skills/setup-freeflow/references/activation-contract.md +84 -69
  189. package/skills/setup-freeflow/references/host-setup.md +50 -17
  190. package/skills/simplify-code/SKILL.md +80 -0
  191. package/skills/simplify-code/references/simplification-patterns.md +70 -0
  192. package/skills/tdd/SKILL.md +96 -0
  193. package/skills/tdd/references/test-design.md +96 -0
  194. package/skills/track-work/SKILL.md +84 -0
  195. package/skills/track-work/references/working-record-schema.md +378 -0
  196. package/skills/verify-work/SKILL.md +59 -38
  197. package/skills/verify-work/references/browser-runtime-evidence.md +55 -0
  198. package/skills/verify-work/references/integration-evidence.md +51 -0
  199. package/skills/verify-work/references/performance-evidence.md +57 -0
  200. package/skills/workflow/SKILL.md +53 -59
  201. package/skills/workflow/references/domain-skill-composition.md +57 -0
  202. package/skills/workflow/references/workflow-loop.md +92 -0
  203. package/skills/write-plan/SKILL.md +85 -58
  204. package/skills/write-plan/references/plan-shapes.md +132 -46
  205. package/skills/write-skill/SKILL.md +82 -51
  206. package/skills/write-skill/references/activation-boundaries.md +62 -0
  207. package/skills/write-skill/references/agent-first-instructions.md +87 -0
  208. package/skills/write-skill/references/progressive-disclosure.md +63 -0
  209. package/skills/write-skill/scripts/lib/skill-author.mjs +653 -0
  210. package/skills/write-skill/scripts/skill-author.mjs +104 -0
  211. package/skills/write-spec/SKILL.md +65 -54
  212. package/skills/write-spec/references/artifact-standards.md +60 -41
  213. package/skills/write-spec/references/decision-records.md +77 -0
  214. package/skills/write-spec/references/spec-shapes.md +119 -60
  215. package/evals/README.md +0 -32
  216. package/evals/fixtures/copy-conventions.md +0 -31
  217. package/evals/fixtures/output-router/README.md +0 -12
  218. package/evals/fixtures/output-router/failed-command-output.txt +0 -9
  219. package/evals/fixtures/output-router/large-router-manual.md +0 -63
  220. package/evals/fixtures/output-router/native-large-output.txt +0 -40
  221. package/evals/fixtures/output-router/noisy-test-output.txt +0 -30
  222. package/evals/fixtures/output-router/verification-output.txt +0 -8
  223. package/evals/fixtures/tiny-artifact-review-app/README.md +0 -5
  224. package/evals/fixtures/tiny-artifact-review-app/docs/billing-policy.md +0 -10
  225. package/evals/fixtures/tiny-artifact-review-app/docs/specs/billing-webhook-api-draft.md +0 -21
  226. package/evals/fixtures/tiny-artifact-review-app/docs/specs/failed-payment-grace-period.md +0 -24
  227. package/evals/fixtures/tiny-artifact-review-app/docs/specs/immediate-downgrade.md +0 -17
  228. package/evals/fixtures/tiny-artifact-review-app/tests/billing.test.md +0 -8
  229. package/evals/fixtures/tiny-commit-ambiguous-app/.freeflow-eval-setup.sh +0 -15
  230. package/evals/fixtures/tiny-commit-ambiguous-app/README.md +0 -3
  231. package/evals/fixtures/tiny-commit-ambiguous-app/src/billing.ts +0 -5
  232. package/evals/fixtures/tiny-commit-ambiguous-app/src/settings-page.ts +0 -1
  233. package/evals/fixtures/tiny-commit-ambiguous-app/tests/settings.test.md +0 -5
  234. package/evals/fixtures/tiny-commit-app/.freeflow-eval-setup.sh +0 -14
  235. package/evals/fixtures/tiny-commit-app/README.md +0 -3
  236. package/evals/fixtures/tiny-commit-app/docs/specs/settings-title.md +0 -5
  237. package/evals/fixtures/tiny-commit-app/src/billing.ts +0 -5
  238. package/evals/fixtures/tiny-commit-app/src/settings-page.ts +0 -1
  239. package/evals/fixtures/tiny-commit-app/tests/settings.test.md +0 -5
  240. package/evals/fixtures/tiny-commit-everything-app/.freeflow-eval-setup.sh +0 -15
  241. package/evals/fixtures/tiny-commit-everything-app/README.md +0 -3
  242. package/evals/fixtures/tiny-commit-everything-app/docs/specs/settings-title.md +0 -5
  243. package/evals/fixtures/tiny-commit-everything-app/src/billing.ts +0 -5
  244. package/evals/fixtures/tiny-commit-everything-app/src/settings-page.ts +0 -1
  245. package/evals/fixtures/tiny-commit-everything-app/tests/settings.test.md +0 -5
  246. package/evals/fixtures/tiny-commit-staged-app/.freeflow-eval-setup.sh +0 -15
  247. package/evals/fixtures/tiny-commit-staged-app/README.md +0 -3
  248. package/evals/fixtures/tiny-commit-staged-app/docs/specs/settings-title.md +0 -5
  249. package/evals/fixtures/tiny-commit-staged-app/src/billing.ts +0 -5
  250. package/evals/fixtures/tiny-commit-staged-app/src/settings-page.ts +0 -1
  251. package/evals/fixtures/tiny-commit-staged-app/tests/settings.test.md +0 -5
  252. package/evals/fixtures/tiny-commit-staged-mixed-app/.freeflow-eval-setup.sh +0 -15
  253. package/evals/fixtures/tiny-commit-staged-mixed-app/README.md +0 -3
  254. package/evals/fixtures/tiny-commit-staged-mixed-app/docs/billing-policy.md +0 -3
  255. package/evals/fixtures/tiny-commit-staged-mixed-app/docs/release-notes.md +0 -3
  256. package/evals/fixtures/tiny-commit-staged-mixed-app/src/billing.ts +0 -5
  257. package/evals/fixtures/tiny-dashboard-stale-app/README.md +0 -11
  258. package/evals/fixtures/tiny-dashboard-stale-app/src/api-client.ts +0 -13
  259. package/evals/fixtures/tiny-dashboard-stale-app/src/dashboard-data.ts +0 -19
  260. package/evals/fixtures/tiny-dashboard-stale-app/tests/dashboard-data.test.md +0 -9
  261. package/evals/fixtures/tiny-decision-destination-app/README.md +0 -6
  262. package/evals/fixtures/tiny-decision-destination-app/src/risk.ts +0 -8
  263. package/evals/fixtures/tiny-decision-destination-app/tests/risk.test.md +0 -4
  264. package/evals/fixtures/tiny-design-depth-app/README.md +0 -15
  265. package/evals/fixtures/tiny-design-depth-app/src/routes.ts +0 -25
  266. package/evals/fixtures/tiny-design-depth-app/src/sendEmail.ts +0 -3
  267. package/evals/fixtures/tiny-design-depth-app/src/sendSms.ts +0 -3
  268. package/evals/fixtures/tiny-design-depth-app/src/telemetry.ts +0 -3
  269. package/evals/fixtures/tiny-design-depth-app/tests/routes.test.md +0 -12
  270. package/evals/fixtures/tiny-eval-method-app/README.md +0 -8
  271. package/evals/fixtures/tiny-eval-method-app/evals/reports/review-pr-eval-result.md +0 -5
  272. package/evals/fixtures/tiny-eval-method-app/evals/reports/triage-question-failure.md +0 -17
  273. package/evals/fixtures/tiny-eval-method-app/evals/runs/review-pr-with-skill-output.diff +0 -11
  274. package/evals/fixtures/tiny-eval-method-app/evals/runs/review-pr-with-skill-output.md +0 -3
  275. package/evals/fixtures/tiny-eval-method-app/skills/review-pr/SKILL.md +0 -10
  276. package/evals/fixtures/tiny-eval-method-app/skills/triage-question/SKILL.md +0 -10
  277. package/evals/fixtures/tiny-execute-plan-app/README.md +0 -5
  278. package/evals/fixtures/tiny-execute-plan-app/checks/settings-and-billing-check.sh +0 -5
  279. package/evals/fixtures/tiny-execute-plan-app/docs/billing-policy.md +0 -10
  280. package/evals/fixtures/tiny-execute-plan-app/docs/plans/immediate-downgrade-plan.md +0 -11
  281. package/evals/fixtures/tiny-execute-plan-app/docs/plans/settings-title-plan.md +0 -12
  282. package/evals/fixtures/tiny-execute-plan-app/docs/plans/settings-title-with-bad-check.md +0 -15
  283. package/evals/fixtures/tiny-execute-plan-app/docs/plans/unverified-billing-plan.md +0 -9
  284. package/evals/fixtures/tiny-execute-plan-app/docs/specs/failed-payment-grace-period.md +0 -9
  285. package/evals/fixtures/tiny-execute-plan-app/docs/specs/settings-title.md +0 -9
  286. package/evals/fixtures/tiny-execute-plan-app/src/billing.ts +0 -7
  287. package/evals/fixtures/tiny-execute-plan-app/src/settings-page.ts +0 -1
  288. package/evals/fixtures/tiny-execute-plan-app/tests/billing.test.md +0 -7
  289. package/evals/fixtures/tiny-execute-plan-app/tests/settings.test.md +0 -5
  290. package/evals/fixtures/tiny-execute-review-loop-app/README.md +0 -5
  291. package/evals/fixtures/tiny-execute-review-loop-app/docs/billing-policy.md +0 -9
  292. package/evals/fixtures/tiny-execute-review-loop-app/docs/plans/settings-title-plan.md +0 -12
  293. package/evals/fixtures/tiny-execute-review-loop-app/docs/review/previous-agent-summary.md +0 -15
  294. package/evals/fixtures/tiny-execute-review-loop-app/docs/review/review-pass-1-non-pass.md +0 -11
  295. package/evals/fixtures/tiny-execute-review-loop-app/docs/specs/settings-title.md +0 -9
  296. package/evals/fixtures/tiny-execute-review-loop-app/src/billing.ts +0 -7
  297. package/evals/fixtures/tiny-execute-review-loop-app/src/settings-page.ts +0 -1
  298. package/evals/fixtures/tiny-execute-review-loop-app/tests/billing.test.md +0 -7
  299. package/evals/fixtures/tiny-execute-review-loop-app/tests/settings.test.md +0 -5
  300. package/evals/fixtures/tiny-flaky-session-app/README.md +0 -10
  301. package/evals/fixtures/tiny-flaky-session-app/src/session-timeout.ts +0 -13
  302. package/evals/fixtures/tiny-flaky-session-app/tests/session-timeout.test.md +0 -8
  303. package/evals/fixtures/tiny-handoff-app/README.md +0 -5
  304. package/evals/fixtures/tiny-handoff-app/docs/billing-policy.md +0 -10
  305. package/evals/fixtures/tiny-handoff-app/docs/handoffs/old-agent-handoff.md +0 -8
  306. package/evals/fixtures/tiny-handoff-app/docs/plans/billing-retry-plan.md +0 -11
  307. package/evals/fixtures/tiny-handoff-app/src/billing.ts +0 -7
  308. package/evals/fixtures/tiny-handoff-report-app/README.md +0 -3
  309. package/evals/fixtures/tiny-handoff-report-app/evals/runs/handoff-3/hof-003/with-skill-output.diff +0 -1
  310. package/evals/fixtures/tiny-handoff-report-app/evals/runs/handoff-3/hof-003/with-skill-output.md +0 -1
  311. package/evals/fixtures/tiny-handoff-report-app/evals/scores/hof-003-score.txt +0 -4
  312. package/evals/fixtures/tiny-plan-app/README.md +0 -5
  313. package/evals/fixtures/tiny-plan-app/docs/billing-policy.md +0 -10
  314. package/evals/fixtures/tiny-plan-app/docs/specs/failed-payment-grace-period.md +0 -25
  315. package/evals/fixtures/tiny-plan-app/src/billing.ts +0 -17
  316. package/evals/fixtures/tiny-plan-app/src/settings-page.ts +0 -1
  317. package/evals/fixtures/tiny-plan-app/tests/billing.test.md +0 -8
  318. package/evals/fixtures/tiny-plan-app/tests/settings.test.md +0 -5
  319. package/evals/fixtures/tiny-plan-strict-api-app/README.md +0 -3
  320. package/evals/fixtures/tiny-plan-strict-api-app/docs/billing-policy.md +0 -5
  321. package/evals/fixtures/tiny-plan-strict-api-app/docs/specs/billing-webhook-api.md +0 -25
  322. package/evals/fixtures/tiny-plan-strict-api-app/src/billing.ts +0 -5
  323. package/evals/fixtures/tiny-plan-strict-api-app/src/webhooks.ts +0 -3
  324. package/evals/fixtures/tiny-plan-strict-api-app/tests/billing-webhook.test.md +0 -8
  325. package/evals/fixtures/tiny-post-setup-invalid-config-app/.freeflow/config.json +0 -3
  326. package/evals/fixtures/tiny-post-setup-invalid-config-app/AGENTS.md +0 -15
  327. package/evals/fixtures/tiny-post-setup-invalid-config-app/README.md +0 -16
  328. package/evals/fixtures/tiny-post-setup-invalid-config-app/docs/auth-review.md +0 -15
  329. package/evals/fixtures/tiny-post-setup-invalid-config-app/docs/billing-policy.md +0 -10
  330. package/evals/fixtures/tiny-post-setup-invalid-config-app/docs/copy-conventions.md +0 -15
  331. package/evals/fixtures/tiny-post-setup-invalid-config-app/src/auth-middleware.ts +0 -12
  332. package/evals/fixtures/tiny-post-setup-invalid-config-app/src/billing.ts +0 -20
  333. package/evals/fixtures/tiny-post-setup-invalid-config-app/src/login-copy.ts +0 -1
  334. package/evals/fixtures/tiny-post-setup-invalid-config-app/src/settings-page.ts +0 -1
  335. package/evals/fixtures/tiny-post-setup-invalid-config-app/tests/auth-middleware.test.md +0 -8
  336. package/evals/fixtures/tiny-post-setup-invalid-config-app/tests/billing.test.md +0 -8
  337. package/evals/fixtures/tiny-post-setup-invalid-config-app/tests/copy.test.md +0 -7
  338. package/evals/fixtures/tiny-post-setup-missing-config-app/AGENTS.md +0 -15
  339. package/evals/fixtures/tiny-post-setup-missing-config-app/README.md +0 -16
  340. package/evals/fixtures/tiny-post-setup-missing-config-app/docs/auth-review.md +0 -15
  341. package/evals/fixtures/tiny-post-setup-missing-config-app/docs/billing-policy.md +0 -10
  342. package/evals/fixtures/tiny-post-setup-missing-config-app/docs/copy-conventions.md +0 -15
  343. package/evals/fixtures/tiny-post-setup-missing-config-app/src/auth-middleware.ts +0 -12
  344. package/evals/fixtures/tiny-post-setup-missing-config-app/src/billing.ts +0 -20
  345. package/evals/fixtures/tiny-post-setup-missing-config-app/src/login-copy.ts +0 -1
  346. package/evals/fixtures/tiny-post-setup-missing-config-app/src/settings-page.ts +0 -1
  347. package/evals/fixtures/tiny-post-setup-missing-config-app/tests/auth-middleware.test.md +0 -8
  348. package/evals/fixtures/tiny-post-setup-missing-config-app/tests/billing.test.md +0 -8
  349. package/evals/fixtures/tiny-post-setup-missing-config-app/tests/copy.test.md +0 -7
  350. package/evals/fixtures/tiny-post-setup-source-conflict-app/.freeflow/config.json +0 -3
  351. package/evals/fixtures/tiny-post-setup-source-conflict-app/AGENTS.md +0 -15
  352. package/evals/fixtures/tiny-post-setup-source-conflict-app/README.md +0 -16
  353. package/evals/fixtures/tiny-post-setup-source-conflict-app/docs/auth-review.md +0 -15
  354. package/evals/fixtures/tiny-post-setup-source-conflict-app/docs/billing-policy.md +0 -10
  355. package/evals/fixtures/tiny-post-setup-source-conflict-app/docs/copy-conventions.md +0 -15
  356. package/evals/fixtures/tiny-post-setup-source-conflict-app/src/auth-middleware.ts +0 -12
  357. package/evals/fixtures/tiny-post-setup-source-conflict-app/src/billing.ts +0 -20
  358. package/evals/fixtures/tiny-post-setup-source-conflict-app/src/login-copy.ts +0 -1
  359. package/evals/fixtures/tiny-post-setup-source-conflict-app/src/settings-page.ts +0 -1
  360. package/evals/fixtures/tiny-post-setup-source-conflict-app/tests/auth-middleware.test.md +0 -8
  361. package/evals/fixtures/tiny-post-setup-source-conflict-app/tests/billing.test.md +0 -8
  362. package/evals/fixtures/tiny-post-setup-source-conflict-app/tests/copy.test.md +0 -7
  363. package/evals/fixtures/tiny-report-performance-app/README.md +0 -11
  364. package/evals/fixtures/tiny-report-performance-app/docs/performance.md +0 -10
  365. package/evals/fixtures/tiny-report-performance-app/src/report-summary.ts +0 -29
  366. package/evals/fixtures/tiny-report-performance-app/tests/report-performance.test.md +0 -8
  367. package/evals/fixtures/tiny-review-request-app/README.md +0 -3
  368. package/evals/fixtures/tiny-review-request-app/docs/billing-policy.md +0 -5
  369. package/evals/fixtures/tiny-review-request-app/docs/plans/billing-webhook-api.md +0 -19
  370. package/evals/fixtures/tiny-review-request-app/docs/review/previous-agent-summary.md +0 -20
  371. package/evals/fixtures/tiny-review-request-app/docs/specs/billing-webhook-api.md +0 -25
  372. package/evals/fixtures/tiny-review-request-app/src/billing.ts +0 -11
  373. package/evals/fixtures/tiny-review-request-app/src/webhooks.ts +0 -19
  374. package/evals/fixtures/tiny-review-request-app/tests/billing-webhook.test.md +0 -8
  375. package/evals/fixtures/tiny-review-work-app/README.md +0 -5
  376. package/evals/fixtures/tiny-review-work-app/docs/billing-policy.md +0 -9
  377. package/evals/fixtures/tiny-review-work-app/docs/plans/settings-title-plan.md +0 -12
  378. package/evals/fixtures/tiny-review-work-app/docs/review/previous-agent-summary.md +0 -15
  379. package/evals/fixtures/tiny-review-work-app/docs/specs/settings-title.md +0 -9
  380. package/evals/fixtures/tiny-review-work-app/src/billing.ts +0 -7
  381. package/evals/fixtures/tiny-review-work-app/src/settings-page.ts +0 -1
  382. package/evals/fixtures/tiny-review-work-app/tests/billing.test.md +0 -7
  383. package/evals/fixtures/tiny-review-work-app/tests/settings.test.md +0 -5
  384. package/evals/fixtures/tiny-saas-app/README.md +0 -16
  385. package/evals/fixtures/tiny-saas-app/docs/auth-review.md +0 -15
  386. package/evals/fixtures/tiny-saas-app/docs/billing-policy.md +0 -10
  387. package/evals/fixtures/tiny-saas-app/docs/copy-conventions.md +0 -15
  388. package/evals/fixtures/tiny-saas-app/docs/specs/settings-title.md +0 -13
  389. package/evals/fixtures/tiny-saas-app/src/auth-middleware.ts +0 -12
  390. package/evals/fixtures/tiny-saas-app/src/billing.ts +0 -20
  391. package/evals/fixtures/tiny-saas-app/src/login-copy.ts +0 -1
  392. package/evals/fixtures/tiny-saas-app/src/settings-page.ts +0 -1
  393. package/evals/fixtures/tiny-saas-app/tests/auth-middleware.test.md +0 -8
  394. package/evals/fixtures/tiny-saas-app/tests/billing.test.md +0 -8
  395. package/evals/fixtures/tiny-saas-app/tests/copy.test.md +0 -7
  396. package/evals/fixtures/tiny-setup-agents-app/AGENTS.md +0 -6
  397. package/evals/fixtures/tiny-setup-both-app/AGENTS.md +0 -5
  398. package/evals/fixtures/tiny-setup-both-app/CLAUDE.md +0 -5
  399. package/evals/fixtures/tiny-setup-claude-app/CLAUDE.md +0 -6
  400. package/evals/fixtures/tiny-setup-codex-rules-app/.codex/rules/shell.rules +0 -5
  401. package/evals/fixtures/tiny-setup-codex-rules-app/AGENTS.md +0 -6
  402. package/evals/fixtures/tiny-setup-conflict-app/AGENTS.md +0 -6
  403. package/evals/fixtures/tiny-setup-existing-block-app/AGENTS.md +0 -14
  404. package/evals/fixtures/tiny-setup-four-rules-app/CLAUDE.md +0 -6
  405. package/evals/fixtures/tiny-skill-dev-app/README.md +0 -10
  406. package/evals/fixtures/tiny-skill-dev-app/evals/prompts/review-pr-001.txt +0 -8
  407. package/evals/fixtures/tiny-skill-dev-app/evals/reports/review-pr-failure.md +0 -17
  408. package/evals/fixtures/tiny-skill-dev-app/skills/review-pr/SKILL.md +0 -13
  409. package/evals/fixtures/tiny-team-app/README.md +0 -5
  410. package/evals/fixtures/tiny-team-app/docs/product.md +0 -6
  411. package/evals/fixtures/tiny-team-app/src/teams.ts +0 -9
  412. package/evals/fixtures/tiny-team-app/src/users.ts +0 -5
  413. package/evals/fixtures/tiny-team-app/tests/teams.test.md +0 -7
  414. package/evals/fixtures/tiny-verify-app/README.md +0 -5
  415. package/evals/fixtures/tiny-verify-app/src/settings-nav.ts +0 -1
  416. package/evals/fixtures/tiny-verify-app/src/settings-page.ts +0 -1
  417. package/evals/fixtures/tiny-verify-app/tests/settings.test.md +0 -7
  418. package/evals/prompts/aon-001.txt +0 -2
  419. package/evals/prompts/byp-001.txt +0 -2
  420. package/evals/prompts/byp-002.txt +0 -2
  421. package/evals/prompts/cap-001.txt +0 -3
  422. package/evals/prompts/cap-002.txt +0 -3
  423. package/evals/prompts/cmd-001.txt +0 -3
  424. package/evals/prompts/cmd-002.txt +0 -3
  425. package/evals/prompts/cmd-003.txt +0 -6
  426. package/evals/prompts/cmd-004.txt +0 -5
  427. package/evals/prompts/cmd-005.txt +0 -5
  428. package/evals/prompts/cmd-006.txt +0 -5
  429. package/evals/prompts/cmd-007.txt +0 -5
  430. package/evals/prompts/cmd-008.txt +0 -5
  431. package/evals/prompts/cmd-009.txt +0 -8
  432. package/evals/prompts/cmd-010.txt +0 -5
  433. package/evals/prompts/cmd-011.txt +0 -5
  434. package/evals/prompts/cmd-012.txt +0 -5
  435. package/evals/prompts/cmd-013.txt +0 -5
  436. package/evals/prompts/cmd-014.txt +0 -7
  437. package/evals/prompts/cmd-015.txt +0 -7
  438. package/evals/prompts/cmd-016.txt +0 -5
  439. package/evals/prompts/cmt-001.txt +0 -1
  440. package/evals/prompts/cmt-002.txt +0 -1
  441. package/evals/prompts/cmt-003.txt +0 -1
  442. package/evals/prompts/cmt-004.txt +0 -1
  443. package/evals/prompts/cmt-005.txt +0 -1
  444. package/evals/prompts/dfd-001.txt +0 -3
  445. package/evals/prompts/dia-001.txt +0 -3
  446. package/evals/prompts/dia-002.txt +0 -3
  447. package/evals/prompts/dia-003.txt +0 -3
  448. package/evals/prompts/dis-001.txt +0 -5
  449. package/evals/prompts/dis-002.txt +0 -5
  450. package/evals/prompts/esk-001.txt +0 -5
  451. package/evals/prompts/esk-002.txt +0 -5
  452. package/evals/prompts/esk-003.txt +0 -5
  453. package/evals/prompts/grc-001.txt +0 -3
  454. package/evals/prompts/hof-001.txt +0 -3
  455. package/evals/prompts/hof-002.txt +0 -1
  456. package/evals/prompts/hof-003.txt +0 -1
  457. package/evals/prompts/hof-004.txt +0 -1
  458. package/evals/prompts/hof-005.txt +0 -1
  459. package/evals/prompts/ivg-001.txt +0 -1
  460. package/evals/prompts/ivg-002.txt +0 -11
  461. package/evals/prompts/ivg-003.txt +0 -1
  462. package/evals/prompts/ivg-004.txt +0 -1
  463. package/evals/prompts/mode-001.txt +0 -3
  464. package/evals/prompts/mode-002.txt +0 -1
  465. package/evals/prompts/mode-003.txt +0 -3
  466. package/evals/prompts/mode-004.txt +0 -3
  467. package/evals/prompts/mode-005.txt +0 -3
  468. package/evals/prompts/mode-006.txt +0 -3
  469. package/evals/prompts/mode-007.txt +0 -3
  470. package/evals/prompts/otr-001.txt +0 -3
  471. package/evals/prompts/otr-002.txt +0 -3
  472. package/evals/prompts/rar-001.txt +0 -5
  473. package/evals/prompts/rar-002.txt +0 -3
  474. package/evals/prompts/rar-003.txt +0 -6
  475. package/evals/prompts/rar-004.txt +0 -15
  476. package/evals/prompts/rar-005.txt +0 -10
  477. package/evals/prompts/rbr-001.txt +0 -3
  478. package/evals/prompts/rbr-002.txt +0 -3
  479. package/evals/prompts/rbr-003.txt +0 -7
  480. package/evals/prompts/rev-001.txt +0 -3
  481. package/evals/prompts/rev-002.txt +0 -5
  482. package/evals/prompts/rev-003.txt +0 -6
  483. package/evals/prompts/rev-004.txt +0 -1
  484. package/evals/prompts/rev-005.txt +0 -15
  485. package/evals/prompts/rev-006.txt +0 -5
  486. package/evals/prompts/stp-001.txt +0 -1
  487. package/evals/prompts/stp-002.txt +0 -1
  488. package/evals/prompts/stp-003.txt +0 -1
  489. package/evals/prompts/stp-004.txt +0 -1
  490. package/evals/prompts/stp-005.txt +0 -1
  491. package/evals/prompts/stp-006.txt +0 -1
  492. package/evals/prompts/stp-007.txt +0 -1
  493. package/evals/prompts/stp-008.txt +0 -1
  494. package/evals/prompts/stp-009.txt +0 -1
  495. package/evals/prompts/stp-010.txt +0 -1
  496. package/evals/prompts/stp-011.txt +0 -1
  497. package/evals/prompts/vfy-003.txt +0 -1
  498. package/evals/prompts/wpl-001.txt +0 -3
  499. package/evals/prompts/wpl-002.txt +0 -5
  500. package/evals/prompts/wpl-003.txt +0 -3
  501. package/evals/prompts/wpl-004.txt +0 -5
  502. package/evals/prompts/wpl-005.txt +0 -1
  503. package/evals/prompts/wrc-001.txt +0 -10
  504. package/evals/prompts/wrc-002.txt +0 -3
  505. package/evals/prompts/wsk-001.txt +0 -6
  506. package/evals/prompts/wsp-001.txt +0 -5
  507. package/evals/prompts/wsp-002.txt +0 -15
  508. package/evals/prompts/wsp-003.txt +0 -3
  509. package/evals/prompts/wsp-004.txt +0 -15
  510. package/evals/prompts/wsp-005.txt +0 -5
  511. package/evals/prompts/wsp-006.txt +0 -12
  512. package/evals/prompts/wsp-007.txt +0 -9
  513. package/evals/prompts/wsp-008.txt +0 -13
  514. package/evals/prompts/xpl-001.txt +0 -1
  515. package/evals/prompts/xpl-002.txt +0 -3
  516. package/evals/prompts/xpl-003.txt +0 -3
  517. package/evals/prompts/xpl-004.txt +0 -3
  518. package/evals/prompts/xpl-005.txt +0 -5
  519. package/evals/prompts/xpl-006.txt +0 -3
  520. package/evals/registries/adversarial-evals.json +0 -39
  521. package/evals/registries/fixture-evals.json +0 -2513
  522. package/evals/registries/handoff-evals.json +0 -74
  523. package/evals/registries/legacy-evals.json +0 -147
  524. package/evals/registries/skill-evidence.json +0 -193
  525. package/evals/registries/verify-work-evals.json +0 -46
  526. package/evals/reports/acceptance/v0.1-acceptance-report.md +0 -130
  527. package/evals/reports/by-command-surface/command-surface-1-report.md +0 -45
  528. package/evals/reports/by-command-surface/command-surface-10-report.md +0 -76
  529. package/evals/reports/by-command-surface/command-surface-11-report.md +0 -77
  530. package/evals/reports/by-command-surface/command-surface-12-report.md +0 -91
  531. package/evals/reports/by-command-surface/command-surface-13-report.md +0 -64
  532. package/evals/reports/by-command-surface/command-surface-14-report.md +0 -66
  533. package/evals/reports/by-command-surface/command-surface-15-report.md +0 -124
  534. package/evals/reports/by-command-surface/command-surface-16-report.md +0 -39
  535. package/evals/reports/by-command-surface/command-surface-2-report.md +0 -80
  536. package/evals/reports/by-command-surface/command-surface-3-report.md +0 -86
  537. package/evals/reports/by-command-surface/command-surface-4-report.md +0 -76
  538. package/evals/reports/by-command-surface/command-surface-5-report.md +0 -80
  539. package/evals/reports/by-command-surface/command-surface-6-report.md +0 -74
  540. package/evals/reports/by-command-surface/command-surface-7-report.md +0 -84
  541. package/evals/reports/by-command-surface/command-surface-8-report.md +0 -79
  542. package/evals/reports/by-command-surface/command-surface-9-report.md +0 -79
  543. package/evals/reports/by-command-surface/command-surface-matrix.md +0 -91
  544. package/evals/reports/by-skill/bypass-1-report.md +0 -124
  545. package/evals/reports/by-skill/capture-decisions-1-report.md +0 -99
  546. package/evals/reports/by-skill/capture-decisions-2-report.md +0 -102
  547. package/evals/reports/by-skill/commit-work-1-report.md +0 -165
  548. package/evals/reports/by-skill/commit-work-2-report.md +0 -109
  549. package/evals/reports/by-skill/design-for-depth-1-report.md +0 -95
  550. package/evals/reports/by-skill/diagnose-failure-1-report.md +0 -91
  551. package/evals/reports/by-skill/diagnose-failure-2-report.md +0 -94
  552. package/evals/reports/by-skill/discover-1-report.md +0 -118
  553. package/evals/reports/by-skill/evaluate-skill-2-report.md +0 -71
  554. package/evals/reports/by-skill/execute-plan-1-report.md +0 -103
  555. package/evals/reports/by-skill/execute-plan-2-report.md +0 -112
  556. package/evals/reports/by-skill/execute-plan-3-report.md +0 -87
  557. package/evals/reports/by-skill/grill-context-1-report.md +0 -103
  558. package/evals/reports/by-skill/handoff-1-report.md +0 -123
  559. package/evals/reports/by-skill/handoff-2-report.md +0 -105
  560. package/evals/reports/by-skill/handoff-3-report.md +0 -100
  561. package/evals/reports/by-skill/handoff-7-report.md +0 -77
  562. package/evals/reports/by-skill/interview-gate-1-report.md +0 -63
  563. package/evals/reports/by-skill/interview-gate-2-report.md +0 -105
  564. package/evals/reports/by-skill/mode-contract-1-report.md +0 -74
  565. package/evals/reports/by-skill/mode-contract-2-report.md +0 -87
  566. package/evals/reports/by-skill/mode-contract-3-report.md +0 -65
  567. package/evals/reports/by-skill/mode-contract-4-report.md +0 -71
  568. package/evals/reports/by-skill/mode-contract-5-report.md +0 -70
  569. package/evals/reports/by-skill/output-router-1-report.md +0 -76
  570. package/evals/reports/by-skill/output-router-2-report.md +0 -65
  571. package/evals/reports/by-skill/research-1-report.md +0 -144
  572. package/evals/reports/by-skill/research-brief-1-report.md +0 -94
  573. package/evals/reports/by-skill/research-brief-2-report.md +0 -75
  574. package/evals/reports/by-skill/review-artifact-1-report.md +0 -91
  575. package/evals/reports/by-skill/review-artifact-2-report.md +0 -79
  576. package/evals/reports/by-skill/review-artifact-3-report.md +0 -120
  577. package/evals/reports/by-skill/review-artifact-4-report.md +0 -89
  578. package/evals/reports/by-skill/review-artifact-5-report.md +0 -66
  579. package/evals/reports/by-skill/review-work-1-report.md +0 -85
  580. package/evals/reports/by-skill/review-work-2-report.md +0 -87
  581. package/evals/reports/by-skill/review-work-3-report.md +0 -104
  582. package/evals/reports/by-skill/review-work-4-report.md +0 -108
  583. package/evals/reports/by-skill/review-work-5-report.md +0 -73
  584. package/evals/reports/by-skill/review-work-6-report.md +0 -66
  585. package/evals/reports/by-skill/setup-freeflow-1-report.md +0 -199
  586. package/evals/reports/by-skill/setup-freeflow-2-report.md +0 -105
  587. package/evals/reports/by-skill/setup-freeflow-3-report.md +0 -105
  588. package/evals/reports/by-skill/setup-freeflow-4-report.md +0 -88
  589. package/evals/reports/by-skill/setup-freeflow-5-report.md +0 -115
  590. package/evals/reports/by-skill/skill-authoring-1-report.md +0 -81
  591. package/evals/reports/by-skill/verify-work-1-report.md +0 -111
  592. package/evals/reports/by-skill/verify-work-2-report.md +0 -120
  593. package/evals/reports/by-skill/workflow-1-report.md +0 -65
  594. package/evals/reports/by-skill/write-plan-1-report.md +0 -123
  595. package/evals/reports/by-skill/write-plan-2-report.md +0 -98
  596. package/evals/reports/by-skill/write-plan-3-report.md +0 -110
  597. package/evals/reports/by-skill/write-spec-1-report.md +0 -88
  598. package/evals/reports/by-skill/write-spec-2-report.md +0 -89
  599. package/evals/reports/by-skill/write-spec-3-report.md +0 -90
  600. package/evals/reports/by-skill/write-spec-4-report.md +0 -167
  601. package/evals/reports/harness/claude-harness-1-report.md +0 -103
  602. package/evals/reports/harness/eval-harness-1-report.md +0 -91
  603. package/evals/reports/iterations/iteration-1-report.md +0 -71
  604. package/evals/reports/iterations/iteration-2-report.md +0 -78
  605. package/evals/reports/iterations/iteration-3-report.md +0 -118
  606. package/evals/reports/iterations/iteration-4-report.md +0 -131
  607. package/evals/reports/iterations/iteration-5-report.md +0 -149
  608. package/evals/reports/iterations/iteration-6-report.md +0 -136
  609. package/evals/reports/runtime/always-on-runtime-1-report.md +0 -107
  610. package/evals/reports/runtime/context-mode-normalized-benchmark-1-report.md +0 -52
  611. package/evals/reports/runtime/context-mode-real-deep-baseline-1-report.md +0 -410
  612. package/evals/reports/runtime/context-mode-real-deep-final-slice-11-report.md +0 -203
  613. package/evals/reports/runtime/context-mode-real-deep-final-slice-11-review.md +0 -51
  614. package/evals/reports/runtime/context-saving-native-tools-baseline-1-report.md +0 -99
  615. package/evals/reports/runtime/eryx-python-compatibility-reprobe-1-report.md +0 -166
  616. package/evals/reports/runtime/eryx-python-proof-spike-1-report.md +0 -96
  617. package/evals/reports/runtime/eryx-python-proof-spike-2-report.md +0 -151
  618. package/evals/reports/runtime/eryx-python-script-derive-execution-1-report.md +0 -233
  619. package/evals/reports/runtime/jq-script-derive-execution-1-report.md +0 -215
  620. package/evals/reports/runtime/jq-wasm-proof-spike-1-report.md +0 -67
  621. package/evals/reports/runtime/output-router-benchmark-1-report.md +0 -81
  622. package/evals/reports/runtime/output-router-capture-derive-provider-eval-1-report.md +0 -35
  623. package/evals/reports/runtime/output-router-codex-large-index-sqlite-adhoc-report.md +0 -150
  624. package/evals/reports/runtime/output-router-codex-qa-benchmark-1-report.md +0 -46
  625. package/evals/reports/runtime/output-router-command-benchmark-1-report.md +0 -62
  626. package/evals/reports/runtime/output-router-index-benchmark-1-report.md +0 -64
  627. package/evals/reports/runtime/output-router-regression-1-report.md +0 -81
  628. package/evals/reports/runtime/output-router-transform-eval-1-report.md +0 -28
  629. package/evals/reports/runtime/pi-observed-routing-eval-1-report.md +0 -44
  630. package/evals/reports/runtime/quickjs-script-derive-execution-1-report.md +0 -159
  631. package/evals/reports/runtime/quickjs-wasi-proof-spike-1-report.md +0 -55
  632. package/evals/reports/runtime/render-format-row-protocol-1-report.md +0 -58
  633. package/evals/reports/runtime/script-sandbox-adapter-selection-review-1-report.md +0 -84
  634. package/evals/reports/runtime/script-sandbox-probe-resource-hardening-1-report.md +0 -51
  635. package/evals/reports/runtime/storage-policy-benchmark-1-report.md +0 -176
  636. package/evals/reports/runtime/vault-index-storage-spike-1-report.md +0 -39
  637. package/evals/reports/runtime/workflow-context-hook-1-report.md +0 -82
  638. package/evals/runbooks/adversarial-eval-runbook.md +0 -28
  639. package/evals/runbooks/fixture-eval-runbook.md +0 -137
  640. package/evals/runbooks/handoff-eval-runbook.md +0 -22
  641. package/evals/runbooks/verify-work-eval-runbook.md +0 -27
  642. package/evals/scripts/audit-command-surface.sh +0 -160
  643. package/evals/scripts/check-activation-contract.sh +0 -121
  644. package/evals/scripts/check-runtime-context-hook.sh +0 -183
  645. package/evals/scripts/grade-fixture-eval.sh +0 -446
  646. package/evals/scripts/run-claude-fixture-eval.sh +0 -26
  647. package/evals/scripts/run-codex-fixture-eval.sh +0 -26
  648. package/evals/scripts/run-eryx-python-proof-spike.js +0 -559
  649. package/evals/scripts/run-fixture-eval-by-id.sh +0 -23
  650. package/evals/scripts/run-fixture-eval.sh +0 -464
  651. package/evals/scripts/run-jq-wasm-proof-spike.js +0 -299
  652. package/evals/scripts/run-output-router-transform-eval.js +0 -115
  653. package/evals/scripts/run-pi-observed-routing-eval.js +0 -478
  654. package/evals/scripts/run-quickjs-wasi-proof-spike.js +0 -339
  655. package/evals/scripts/skill-evidence.sh +0 -316
  656. package/evals/scripts/validate-release-metadata.sh +0 -486
  657. package/evals/suites/v0.1-acceptance-suite.md +0 -131
  658. package/pi-extension/dist/host-producer-identification.js +0 -186
  659. package/pi-extension/dist/mcp-config.js +0 -30
  660. package/pi-extension/dist/native-safety-net.js +0 -209
  661. package/pi-extension/dist/observed-tool-routing.js +0 -114
  662. package/pi-extension/dist/renderers.js +0 -835
  663. package/pi-extension/dist/router-tools.js +0 -438
  664. package/pi-extension/dist/runtime-context.js +0 -288
  665. package/pi-extension/dist/schemas.js +0 -254
  666. package/pi-extension/dist/status.js +0 -449
  667. package/pi-extension/dist/utils.js +0 -467
  668. package/pi-extension/src/runtime-context.ts +0 -347
  669. package/pi-extension/src/status.ts +0 -505
  670. package/plugin-docs/README.md +0 -40
  671. package/plugin-docs/adr/0001-three-modes.md +0 -27
  672. package/plugin-docs/adr/0002-evals-before-hooks.md +0 -17
  673. package/plugin-docs/adr/0003-release-boundary.md +0 -21
  674. package/plugin-docs/adr/0004-discover-replaces-shallow-discovery-skills.md +0 -26
  675. package/plugin-docs/adr/README.md +0 -10
  676. package/plugin-docs/architecture.md +0 -89
  677. package/plugin-docs/output-router.md +0 -396
  678. package/plugin-docs/release-evidence.md +0 -77
  679. package/plugin-docs/skills.md +0 -44
  680. package/plugin-docs/workflow.md +0 -57
  681. package/skills/diagnose-failure/references/feedback-loop-catalog.md +0 -25
  682. package/skills/discover/ARTIFACT-DESTINATIONS.md +0 -58
  683. package/skills/discover/CHECKPOINTS.md +0 -74
  684. package/skills/discover/SKILL.md +0 -173
  685. package/skills/evaluate-skill/references/eval-patterns.md +0 -41
  686. package/skills/evaluate-skill/references/grading-priority.md +0 -33
  687. package/skills/execute-plan/SKILL.md +0 -133
  688. package/skills/execute-plan/references/execution-map.md +0 -122
  689. package/skills/interview-gate/SKILL.md +0 -90
  690. package/skills/setup-freeflow/references/output-router-setup.md +0 -102
  691. package/skills/workflow/references/workflow-map.md +0 -104
  692. /package/pi-extension/src/{mcp-config.ts → integrations/mcp-config.ts} +0 -0
@@ -5,758 +5,858 @@ import { tmpdir } from "node:os";
5
5
  import { dirname, relative, resolve } from "node:path";
6
6
  import { fileURLToPath } from "node:url";
7
7
  import { performance } from "node:perf_hooks";
8
- import { defaultJsonRunReportPath, escapeMarkdownTableCell as escapeTable, formatPercent, latencySummary, normalizeIterations, parseBenchmarkCliArgs, reductionPercent, writeBenchmarkReportPair, } from "./benchmark-harness.js";
8
+ import {
9
+ defaultJsonRunReportPath,
10
+ escapeMarkdownTableCell as escapeTable,
11
+ formatPercent,
12
+ latencySummary,
13
+ normalizeIterations,
14
+ parseBenchmarkCliArgs,
15
+ reductionPercent,
16
+ writeBenchmarkReportPair,
17
+ } from "./benchmark-harness.js";
9
18
  import { freeflowSearch } from "../tools/search.js";
10
- import { buildOrLoadExperimentalRepoIndex, queryExperimentalRepoIndex, } from "../experiments/local-index.js";
19
+ import { buildOrLoadExperimentalRepoIndex, queryExperimentalRepoIndex } from "../experiments/local-index.js";
11
20
  const DEFAULT_ITERATIONS = 3;
12
21
  const BENCHMARK_TOP_K = 3;
13
22
  const FTS_CONTEXT_LINES = 2;
14
23
  const require = createRequire(import.meta.url);
15
24
  let cachedFtsCandidateStatus;
16
25
  export async function runIndexBenchmarks(options = {}) {
17
- const iterations = normalizeIterations(options.iterations, DEFAULT_ITERATIONS);
18
- const fixtures = indexFixtureDefinitions();
19
- const fixtureResults = [];
20
- for (const fixture of fixtures) {
21
- const results = [];
22
- for (const mode of indexBenchmarkModes()) {
23
- results.push(await runIndexFixtureMode(fixture, mode, iterations));
24
- }
25
- fixtureResults.push({ id: fixture.id, title: fixture.title, expected: fixtureExpectedForMode(fixture, "index-warm"), results });
26
- }
27
- return {
28
- generatedAt: options.generatedAt ?? new Date().toISOString(),
29
- iterations,
30
- summary: summarizeIndexReport(fixtureResults),
31
- fixtures: fixtureResults,
32
- };
26
+ const iterations = normalizeIterations(options.iterations, DEFAULT_ITERATIONS);
27
+ const fixtures = indexFixtureDefinitions();
28
+ const fixtureResults = [];
29
+ for (const fixture of fixtures) {
30
+ const results = [];
31
+ for (const mode of indexBenchmarkModes()) {
32
+ results.push(await runIndexFixtureMode(fixture, mode, iterations));
33
+ }
34
+ fixtureResults.push({
35
+ id: fixture.id,
36
+ title: fixture.title,
37
+ expected: fixtureExpectedForMode(fixture, "index-warm"),
38
+ results,
39
+ });
40
+ }
41
+ return {
42
+ generatedAt: options.generatedAt ?? new Date().toISOString(),
43
+ iterations,
44
+ summary: summarizeIndexReport(fixtureResults),
45
+ fixtures: fixtureResults,
46
+ };
33
47
  }
34
48
  export function renderIndexBenchmarkReport(report) {
35
- const date = report.generatedAt.slice(0, 10);
36
- const lines = [
37
- "# Output Router Index Benchmark Report - Iteration 1",
38
- "",
39
- `Date: ${date}`,
40
- "",
41
- "## Scope",
42
- "",
43
- "Repo Search Backend Benchmark for `freeflow_search`. The scanner remains the product default; this benchmark compares scanner-only retrieval, the no-dependency local lexical index, a conservative hybrid scanner+index path, and records whether an FTS5/BM25/trigram candidate is available.",
44
- "",
45
- "The index cache is keyed by repo root and stores outside the repo by default. No external service, vector DB, or native dependency is required for the local lexical index.",
46
- "",
47
- "## Command",
48
- "",
49
- "```sh",
50
- "npm run bench:router:index",
51
- "```",
52
- "",
53
- "The CLI writes machine-readable JSON under `evals/runs/output-router/` by default. That JSON is generated run data; this Markdown file is the durable runtime report.",
54
- "",
55
- "## Summary",
56
- "",
57
- `- Fixtures: ${report.summary.fixtures}`,
58
- `- Scanner remains default: ${report.summary.scannerDefault ? "yes" : "no"}`,
59
- `- Index adopted by default: ${report.summary.indexAdopted ? "yes" : "no"}`,
60
- `- Scanner pass: ${report.summary.scanner.passed}/${report.summary.fixtures} (recall@${BENCHMARK_TOP_K}: ${report.summary.scanner.recallAtK}/${report.summary.fixtures})`,
61
- `- Index warm pass: ${report.summary.index.passed}/${report.summary.fixtures} (recall@${BENCHMARK_TOP_K}: ${report.summary.index.recallAtK}/${report.summary.fixtures})`,
62
- `- FTS5/BM25/trigram pass: ${report.summary.fts.passed}/${report.summary.fixtures} (skipped: ${report.summary.fts.skipped}; recall@${BENCHMARK_TOP_K}: ${report.summary.fts.recallAtK}/${report.summary.fixtures})`,
63
- `- Hybrid warm pass: ${report.summary.hybrid.passed}/${report.summary.fixtures} (recall@${BENCHMARK_TOP_K}: ${report.summary.hybrid.recallAtK}/${report.summary.fixtures})`,
64
- `- FTS5/BM25/trigram candidate: ${report.summary.ftsCandidate.available ? "available" : "unavailable"} — ${report.summary.ftsCandidate.reason}`,
65
- `- Generated false positives: ${report.summary.generatedFalsePositiveCount}/${report.summary.modeResults}`,
66
- `- Cold build p50/p95: ${report.summary.coldBuildMs.p50.toFixed(2)}/${report.summary.coldBuildMs.p95.toFixed(2)} ms`,
67
- `- Warm query p50/p95: ${report.summary.warmQueryMs.p50.toFixed(2)}/${report.summary.warmQueryMs.p95.toFixed(2)} ms`,
68
- `- Stale refresh p50/p95: ${report.summary.staleRefreshMs.p50.toFixed(2)}/${report.summary.staleRefreshMs.p95.toFixed(2)} ms`,
69
- `- Index warm context reduction: ${formatPercent(report.summary.index.weightedContextReductionPercent)} (${report.summary.index.totalRawBytes} raw bytes to ${report.summary.index.totalContextBytes} context bytes)`,
70
- "",
71
- "## Results",
72
- "",
73
- "| fixture | mode | correctness | checks | path | lines | candidates | raw/context bytes | context reduction | latency p50/p95 ms | build/query ms | index mode | notes |",
74
- "| --- | --- | --- | --- | --- | --- | --- | ---: | ---: | ---: | ---: | --- | --- |",
75
- ];
76
- for (const fixture of report.fixtures) {
77
- for (const result of fixture.results) {
78
- const correctness = result.skipped ? "skipped" : result.correctness.passed ? "pass" : "fail";
79
- const checks = formatCorrectnessChecks(result.correctness);
80
- const buildQuery = `${(result.buildMs ?? 0).toFixed(2)}/${(result.queryMs ?? 0).toFixed(2)}`;
81
- const notes = result.notes.length ? result.notes.join("; ") : "";
82
- lines.push(`| ${escapeTable(fixture.id)} | ${escapeTable(result.mode)} | ${correctness} | ${escapeTable(checks)} | ${escapeTable(result.actualPath ?? "-")} | ${escapeTable(result.actualLines ?? "-")} | ${escapeTable(result.candidatePaths.join(", ") || "-")} | ${result.rawBytes}/${result.contextBytes} | ${formatPercent(result.contextReductionPercent)} | ${result.latencyMs.p50.toFixed(2)}/${result.latencyMs.p95.toFixed(2)} | ${buildQuery} | ${escapeTable(result.indexMode ?? "-")} | ${escapeTable(notes)} |`);
83
- }
84
- }
85
- lines.push("", "## Adoption Decision", "", "Index adopted by default: no. This slice only records benchmark evidence; scanner behavior remains the default until a later adoption checkpoint explicitly approves otherwise.", "", "## Regression Status", "", report.summary.index.failed === 0 && report.summary.fts.failed === 0 && report.summary.hybrid.failed === 0
86
- ? "Warm experimental index, FTS5/BM25/trigram, and hybrid modes passed all gated fixtures without generated-artifact false positives."
87
- : `Failures: warm index ${report.summary.index.failed}, FTS5/BM25/trigram ${report.summary.fts.failed}, hybrid ${report.summary.hybrid.failed}.`, "");
88
- return lines.join("\n");
49
+ const date = report.generatedAt.slice(0, 10);
50
+ const lines = [
51
+ "# Output Router Index Benchmark Report - Iteration 1",
52
+ "",
53
+ `Date: ${date}`,
54
+ "",
55
+ "## Scope",
56
+ "",
57
+ "Repo Search Backend Benchmark for `freeflow_search`. The scanner remains the product default; this benchmark compares scanner-only retrieval, the no-dependency local lexical index, a conservative hybrid scanner+index path, and records whether an FTS5/BM25/trigram candidate is available.",
58
+ "",
59
+ "The index cache is keyed by repo root and stores outside the repo by default. No external service, vector DB, or native dependency is required for the local lexical index.",
60
+ "",
61
+ "## Command",
62
+ "",
63
+ "```sh",
64
+ "npm run bench:router:index",
65
+ "```",
66
+ "",
67
+ "The CLI writes machine-readable JSON under `router/evals/runs/` by default. That JSON is generated run data; this Markdown file is the durable runtime report.",
68
+ "",
69
+ "## Summary",
70
+ "",
71
+ `- Fixtures: ${report.summary.fixtures}`,
72
+ `- Scanner remains default: ${report.summary.scannerDefault ? "yes" : "no"}`,
73
+ `- Index adopted by default: ${report.summary.indexAdopted ? "yes" : "no"}`,
74
+ `- Scanner pass: ${report.summary.scanner.passed}/${report.summary.fixtures} (recall@${BENCHMARK_TOP_K}: ${report.summary.scanner.recallAtK}/${report.summary.fixtures})`,
75
+ `- Index warm pass: ${report.summary.index.passed}/${report.summary.fixtures} (recall@${BENCHMARK_TOP_K}: ${report.summary.index.recallAtK}/${report.summary.fixtures})`,
76
+ `- FTS5/BM25/trigram pass: ${report.summary.fts.passed}/${report.summary.fixtures} (skipped: ${report.summary.fts.skipped}; recall@${BENCHMARK_TOP_K}: ${report.summary.fts.recallAtK}/${report.summary.fixtures})`,
77
+ `- Hybrid warm pass: ${report.summary.hybrid.passed}/${report.summary.fixtures} (recall@${BENCHMARK_TOP_K}: ${report.summary.hybrid.recallAtK}/${report.summary.fixtures})`,
78
+ `- FTS5/BM25/trigram candidate: ${report.summary.ftsCandidate.available ? "available" : "unavailable"} — ${report.summary.ftsCandidate.reason}`,
79
+ `- Generated false positives: ${report.summary.generatedFalsePositiveCount}/${report.summary.modeResults}`,
80
+ `- Cold build p50/p95: ${report.summary.coldBuildMs.p50.toFixed(2)}/${report.summary.coldBuildMs.p95.toFixed(2)} ms`,
81
+ `- Warm query p50/p95: ${report.summary.warmQueryMs.p50.toFixed(2)}/${report.summary.warmQueryMs.p95.toFixed(2)} ms`,
82
+ `- Stale refresh p50/p95: ${report.summary.staleRefreshMs.p50.toFixed(2)}/${report.summary.staleRefreshMs.p95.toFixed(2)} ms`,
83
+ `- Index warm context reduction: ${formatPercent(report.summary.index.weightedContextReductionPercent)} (${report.summary.index.totalRawBytes} raw bytes to ${report.summary.index.totalContextBytes} context bytes)`,
84
+ "",
85
+ "## Results",
86
+ "",
87
+ "| fixture | mode | correctness | checks | path | lines | candidates | raw/context bytes | context reduction | latency p50/p95 ms | build/query ms | index mode | notes |",
88
+ "| --- | --- | --- | --- | --- | --- | --- | ---: | ---: | ---: | ---: | --- | --- |",
89
+ ];
90
+ for (const fixture of report.fixtures) {
91
+ for (const result of fixture.results) {
92
+ const correctness = result.skipped ? "skipped" : result.correctness.passed ? "pass" : "fail";
93
+ const checks = formatCorrectnessChecks(result.correctness);
94
+ const buildQuery = `${(result.buildMs ?? 0).toFixed(2)}/${(result.queryMs ?? 0).toFixed(2)}`;
95
+ const notes = result.notes.length ? result.notes.join("; ") : "";
96
+ lines.push(
97
+ `| ${escapeTable(fixture.id)} | ${escapeTable(result.mode)} | ${correctness} | ${escapeTable(checks)} | ${escapeTable(result.actualPath ?? "-")} | ${escapeTable(result.actualLines ?? "-")} | ${escapeTable(result.candidatePaths.join(", ") || "-")} | ${result.rawBytes}/${result.contextBytes} | ${formatPercent(result.contextReductionPercent)} | ${result.latencyMs.p50.toFixed(2)}/${result.latencyMs.p95.toFixed(2)} | ${buildQuery} | ${escapeTable(result.indexMode ?? "-")} | ${escapeTable(notes)} |`,
98
+ );
99
+ }
100
+ }
101
+ lines.push(
102
+ "",
103
+ "## Adoption Decision",
104
+ "",
105
+ "Index adopted by default: no. This slice only records benchmark evidence; scanner behavior remains the default until a later adoption checkpoint explicitly approves otherwise.",
106
+ "",
107
+ "## Regression Status",
108
+ "",
109
+ report.summary.index.failed === 0 && report.summary.fts.failed === 0 && report.summary.hybrid.failed === 0
110
+ ? "Warm experimental index, FTS5/BM25/trigram, and hybrid modes passed all gated fixtures without generated-artifact false positives."
111
+ : `Failures: warm index ${report.summary.index.failed}, FTS5/BM25/trigram ${report.summary.fts.failed}, hybrid ${report.summary.hybrid.failed}.`,
112
+ "",
113
+ );
114
+ return lines.join("\n");
89
115
  }
90
116
  export async function writeIndexBenchmarkReport(report, reportPath) {
91
- await mkdir(dirname(reportPath), { recursive: true });
92
- await writeFile(reportPath, renderIndexBenchmarkReport(report), "utf8");
117
+ await mkdir(dirname(reportPath), { recursive: true });
118
+ await writeFile(reportPath, renderIndexBenchmarkReport(report), "utf8");
93
119
  }
94
120
  export async function writeIndexBenchmarkJsonReport(report, reportPath) {
95
- await mkdir(dirname(reportPath), { recursive: true });
96
- await writeFile(reportPath, `${JSON.stringify(report, null, 2)}\n`, "utf8");
121
+ await mkdir(dirname(reportPath), { recursive: true });
122
+ await writeFile(reportPath, `${JSON.stringify(report, null, 2)}\n`, "utf8");
97
123
  }
98
124
  export async function writeIndexBenchmarkReports(report, markdownReportPath, options = {}) {
99
- return writeBenchmarkReportPair({
100
- report,
101
- markdownReportPath,
102
- jsonReportPath: options.jsonReportPath,
103
- renderMarkdown: renderIndexBenchmarkReport,
104
- });
125
+ return writeBenchmarkReportPair({
126
+ report,
127
+ markdownReportPath,
128
+ jsonReportPath: options.jsonReportPath,
129
+ renderMarkdown: renderIndexBenchmarkReport,
130
+ });
105
131
  }
106
132
  async function runIndexFixtureMode(fixture, mode, iterations) {
107
- const latencies = [];
108
- let observation = null;
109
- for (let index = 0; index < iterations; index += 1) {
110
- const startedAt = performance.now();
111
- observation = await observeIndexFixture(fixture, mode);
112
- latencies.push(performance.now() - startedAt);
113
- }
114
- if (!observation) {
115
- observation = { toolPathUsed: mode, skipped: true, skipReason: "No observation was produced.", rawBytes: 0, contextBytes: 0, excerpt: "", notes: ["no observation"] };
116
- }
117
- const correctness = scoreCorrectness(fixtureExpectedForMode(fixture, mode), observation);
118
- const result = {
119
- mode,
120
- toolPathUsed: observation.toolPathUsed,
121
- skipped: observation.skipped ?? false,
122
- rawBytes: observation.rawBytes,
123
- contextBytes: observation.contextBytes,
124
- contextReductionPercent: reductionPercent(observation.rawBytes, observation.contextBytes),
125
- latencyMs: latencySummary(latencies),
126
- candidatePaths: observation.candidatePaths ?? [],
127
- excerpt: observation.excerpt,
128
- correctness,
129
- notes: observation.notes ?? [],
133
+ const latencies = [];
134
+ let observation = null;
135
+ for (let index = 0; index < iterations; index += 1) {
136
+ const startedAt = performance.now();
137
+ observation = await observeIndexFixture(fixture, mode);
138
+ latencies.push(performance.now() - startedAt);
139
+ }
140
+ if (!observation) {
141
+ observation = {
142
+ toolPathUsed: mode,
143
+ skipped: true,
144
+ skipReason: "No observation was produced.",
145
+ rawBytes: 0,
146
+ contextBytes: 0,
147
+ excerpt: "",
148
+ notes: ["no observation"],
130
149
  };
131
- if (observation.skipReason) {
132
- result.skipReason = observation.skipReason;
133
- }
134
- if (observation.buildMs !== undefined) {
135
- result.buildMs = observation.buildMs;
136
- }
137
- if (observation.queryMs !== undefined) {
138
- result.queryMs = observation.queryMs;
139
- }
140
- if (observation.indexMode !== undefined) {
141
- result.indexMode = observation.indexMode;
142
- }
143
- if (observation.actualPath !== undefined) {
144
- result.actualPath = observation.actualPath;
145
- }
146
- if (observation.actualLines !== undefined) {
147
- result.actualLines = observation.actualLines;
148
- }
149
- return result;
150
+ }
151
+ const correctness = scoreCorrectness(fixtureExpectedForMode(fixture, mode), observation);
152
+ const result = {
153
+ mode,
154
+ toolPathUsed: observation.toolPathUsed,
155
+ skipped: observation.skipped ?? false,
156
+ rawBytes: observation.rawBytes,
157
+ contextBytes: observation.contextBytes,
158
+ contextReductionPercent: reductionPercent(observation.rawBytes, observation.contextBytes),
159
+ latencyMs: latencySummary(latencies),
160
+ candidatePaths: observation.candidatePaths ?? [],
161
+ excerpt: observation.excerpt,
162
+ correctness,
163
+ notes: observation.notes ?? [],
164
+ };
165
+ if (observation.skipReason) {
166
+ result.skipReason = observation.skipReason;
167
+ }
168
+ if (observation.buildMs !== undefined) {
169
+ result.buildMs = observation.buildMs;
170
+ }
171
+ if (observation.queryMs !== undefined) {
172
+ result.queryMs = observation.queryMs;
173
+ }
174
+ if (observation.indexMode !== undefined) {
175
+ result.indexMode = observation.indexMode;
176
+ }
177
+ if (observation.actualPath !== undefined) {
178
+ result.actualPath = observation.actualPath;
179
+ }
180
+ if (observation.actualLines !== undefined) {
181
+ result.actualLines = observation.actualLines;
182
+ }
183
+ return result;
150
184
  }
151
185
  async function observeIndexFixture(fixture, mode) {
152
- const root = await createTempDir("freeflow-router-index-benchmark-repo-");
153
- const cacheRoot = await createTempDir("freeflow-router-index-benchmark-cache-");
154
- try {
155
- if (mode === "index-stale-refresh") {
156
- await writeFixtureFiles(root.path, fixture.files);
157
- await buildOrLoadExperimentalRepoIndex({ root: root.path, cacheRoot: cacheRoot.path });
158
- await writeFixtureFiles(root.path, fixture.staleFiles ?? { "stale-marker.txt": "stale refresh marker" });
159
- return await indexObservation(root.path, cacheRoot.path, fixture.staleQuery ?? fixture.query, mode);
160
- }
161
- const finalFiles = mode === "scanner-default" || mode === "index-cold" || mode === "index-warm" || mode === "fts5-bm25-trigram" || mode === "hybrid-warm"
162
- ? { ...fixture.files, ...(fixture.staleFiles && fixture.staleExpected ? fixture.staleFiles : {}) }
163
- : fixture.files;
164
- await writeFixtureFiles(root.path, finalFiles);
165
- if (mode === "scanner-default") {
166
- return await scannerObservation(root.path, fixture.staleQuery && fixture.staleExpected ? fixture.staleQuery : fixture.query);
167
- }
168
- if (mode === "fts5-bm25-trigram") {
169
- return await ftsObservation(root.path, fixture.staleQuery && fixture.staleExpected ? fixture.staleQuery : fixture.query);
170
- }
171
- if (mode === "hybrid-warm") {
172
- await buildOrLoadExperimentalRepoIndex({ root: root.path, cacheRoot: cacheRoot.path });
173
- return await hybridObservation(root.path, cacheRoot.path, fixture.staleQuery && fixture.staleExpected ? fixture.staleQuery : fixture.query);
174
- }
175
- if (mode === "index-warm") {
176
- await buildOrLoadExperimentalRepoIndex({ root: root.path, cacheRoot: cacheRoot.path });
177
- return await indexObservation(root.path, cacheRoot.path, fixture.staleQuery && fixture.staleExpected ? fixture.staleQuery : fixture.query, mode);
178
- }
179
- return await indexObservation(root.path, cacheRoot.path, fixture.staleQuery && fixture.staleExpected ? fixture.staleQuery : fixture.query, mode);
180
- }
181
- finally {
182
- await Promise.all([root.cleanup(), cacheRoot.cleanup()]);
183
- }
186
+ const root = await createTempDir("freeflow-router-index-benchmark-repo-");
187
+ const cacheRoot = await createTempDir("freeflow-router-index-benchmark-cache-");
188
+ try {
189
+ if (mode === "index-stale-refresh") {
190
+ await writeFixtureFiles(root.path, fixture.files);
191
+ await buildOrLoadExperimentalRepoIndex({ root: root.path, cacheRoot: cacheRoot.path });
192
+ await writeFixtureFiles(root.path, fixture.staleFiles ?? { "stale-marker.txt": "stale refresh marker" });
193
+ return await indexObservation(root.path, cacheRoot.path, fixture.staleQuery ?? fixture.query, mode);
194
+ }
195
+ const finalFiles =
196
+ mode === "scanner-default" ||
197
+ mode === "index-cold" ||
198
+ mode === "index-warm" ||
199
+ mode === "fts5-bm25-trigram" ||
200
+ mode === "hybrid-warm"
201
+ ? { ...fixture.files, ...(fixture.staleFiles && fixture.staleExpected ? fixture.staleFiles : {}) }
202
+ : fixture.files;
203
+ await writeFixtureFiles(root.path, finalFiles);
204
+ if (mode === "scanner-default") {
205
+ return await scannerObservation(
206
+ root.path,
207
+ fixture.staleQuery && fixture.staleExpected ? fixture.staleQuery : fixture.query,
208
+ );
209
+ }
210
+ if (mode === "fts5-bm25-trigram") {
211
+ return await ftsObservation(
212
+ root.path,
213
+ fixture.staleQuery && fixture.staleExpected ? fixture.staleQuery : fixture.query,
214
+ );
215
+ }
216
+ if (mode === "hybrid-warm") {
217
+ await buildOrLoadExperimentalRepoIndex({ root: root.path, cacheRoot: cacheRoot.path });
218
+ return await hybridObservation(
219
+ root.path,
220
+ cacheRoot.path,
221
+ fixture.staleQuery && fixture.staleExpected ? fixture.staleQuery : fixture.query,
222
+ );
223
+ }
224
+ if (mode === "index-warm") {
225
+ await buildOrLoadExperimentalRepoIndex({ root: root.path, cacheRoot: cacheRoot.path });
226
+ return await indexObservation(
227
+ root.path,
228
+ cacheRoot.path,
229
+ fixture.staleQuery && fixture.staleExpected ? fixture.staleQuery : fixture.query,
230
+ mode,
231
+ );
232
+ }
233
+ return await indexObservation(
234
+ root.path,
235
+ cacheRoot.path,
236
+ fixture.staleQuery && fixture.staleExpected ? fixture.staleQuery : fixture.query,
237
+ mode,
238
+ );
239
+ } finally {
240
+ await Promise.all([root.cleanup(), cacheRoot.cleanup()]);
241
+ }
184
242
  }
185
243
  async function scannerObservation(root, query) {
186
- const rawBytes = await repoRawBytes(root);
187
- const queryStartedAt = performance.now();
188
- const result = await freeflowSearch({ action: "query", source: { kind: "repo", root }, query, preserve: "important", topK: BENCHMARK_TOP_K });
189
- const queryMs = performance.now() - queryStartedAt;
190
- const evidence = result.evidence?.[0];
191
- const candidatePaths = uniqueCandidatePaths(result.evidence?.map((packet) => packet.path));
192
- return {
193
- toolPathUsed: "scanner-default: freeflowSearch repo scanner",
194
- rawBytes,
195
- contextBytes: byteLength(JSON.stringify(result)),
196
- ...(evidence?.path !== undefined ? { actualPath: evidence.path } : {}),
197
- ...(evidence?.lines !== undefined ? { actualLines: evidence.lines } : {}),
198
- candidatePaths,
199
- excerpt: evidence?.excerpt ?? "",
200
- queryMs,
201
- notes: [result.routing.reason],
202
- };
244
+ const rawBytes = await repoRawBytes(root);
245
+ const queryStartedAt = performance.now();
246
+ const result = await freeflowSearch({
247
+ action: "query",
248
+ source: { kind: "repo", root },
249
+ query,
250
+ preserve: "important",
251
+ topK: BENCHMARK_TOP_K,
252
+ });
253
+ const queryMs = performance.now() - queryStartedAt;
254
+ const evidence = result.evidence?.[0];
255
+ const candidatePaths = uniqueCandidatePaths(result.evidence?.map((packet) => packet.path));
256
+ return {
257
+ toolPathUsed: "scanner-default: freeflowSearch repo scanner",
258
+ rawBytes,
259
+ contextBytes: byteLength(JSON.stringify(result)),
260
+ ...(evidence?.path !== undefined ? { actualPath: evidence.path } : {}),
261
+ ...(evidence?.lines !== undefined ? { actualLines: evidence.lines } : {}),
262
+ candidatePaths,
263
+ excerpt: evidence?.excerpt ?? "",
264
+ queryMs,
265
+ notes: [result.routing.reason],
266
+ };
203
267
  }
204
268
  async function indexObservation(root, cacheRoot, query, mode) {
205
- const rawBytes = await repoRawBytes(root);
206
- const load = await buildOrLoadExperimentalRepoIndex({ root, cacheRoot });
207
- const queryStartedAt = performance.now();
208
- const candidates = queryExperimentalRepoIndex(load.index, query, { topK: BENCHMARK_TOP_K });
209
- const queryMs = performance.now() - queryStartedAt;
210
- const candidate = candidates[0];
211
- return {
212
- toolPathUsed: `${mode}: experimental local index`,
213
- rawBytes,
214
- contextBytes: byteLength(JSON.stringify(candidates)),
215
- ...(candidate?.path !== undefined ? { actualPath: candidate.path } : {}),
216
- ...(candidate?.lines !== undefined ? { actualLines: candidate.lines } : {}),
217
- candidatePaths: uniqueCandidatePaths(candidates.map((entry) => entry.path)),
218
- excerpt: candidate?.excerpt ?? "",
219
- buildMs: load.buildMs,
220
- queryMs,
221
- indexMode: load.mode,
222
- notes: candidate ? [candidate.reason, `cachePath=${load.cachePath}`, ...(load.refreshReason ? [`refresh=${load.refreshReason}`] : [])] : ["no index candidate"],
223
- };
269
+ const rawBytes = await repoRawBytes(root);
270
+ const load = await buildOrLoadExperimentalRepoIndex({ root, cacheRoot });
271
+ const queryStartedAt = performance.now();
272
+ const candidates = queryExperimentalRepoIndex(load.index, query, { topK: BENCHMARK_TOP_K });
273
+ const queryMs = performance.now() - queryStartedAt;
274
+ const candidate = candidates[0];
275
+ return {
276
+ toolPathUsed: `${mode}: experimental local index`,
277
+ rawBytes,
278
+ contextBytes: byteLength(JSON.stringify(candidates)),
279
+ ...(candidate?.path !== undefined ? { actualPath: candidate.path } : {}),
280
+ ...(candidate?.lines !== undefined ? { actualLines: candidate.lines } : {}),
281
+ candidatePaths: uniqueCandidatePaths(candidates.map((entry) => entry.path)),
282
+ excerpt: candidate?.excerpt ?? "",
283
+ buildMs: load.buildMs,
284
+ queryMs,
285
+ indexMode: load.mode,
286
+ notes: candidate
287
+ ? [
288
+ candidate.reason,
289
+ `cachePath=${load.cachePath}`,
290
+ ...(load.refreshReason ? [`refresh=${load.refreshReason}`] : []),
291
+ ]
292
+ : ["no index candidate"],
293
+ };
224
294
  }
225
295
  async function ftsObservation(root, query) {
226
- const rawBytes = await repoRawBytes(root);
227
- const ftsStatus = detectFtsCandidateStatus();
228
- if (!ftsStatus.available) {
229
- return {
230
- toolPathUsed: "fts5-bm25-trigram: unavailable optional candidate",
231
- skipped: true,
232
- skipReason: ftsStatus.reason,
233
- rawBytes,
234
- contextBytes: 0,
235
- candidatePaths: [],
236
- excerpt: "",
237
- notes: [ftsStatus.reason],
238
- };
239
- }
240
- const files = await readFtsTextFiles(root);
241
- const sqlite = loadSqliteModule();
242
- const startedAt = performance.now();
243
- const db = new sqlite.DatabaseSync(":memory:");
244
- try {
245
- db.exec("CREATE VIRTUAL TABLE docs USING fts5(path UNINDEXED, body, tokenize='trigram')");
246
- const insert = db.prepare("INSERT INTO docs(path, body) VALUES (?, ?)");
247
- for (const file of files) {
248
- insert.run(file.path, file.text);
249
- }
250
- const matchQuery = ftsMatchQuery(query);
251
- const rows = matchQuery
252
- ? db.prepare("SELECT path, bm25(docs) AS rank FROM docs WHERE docs MATCH ? ORDER BY rank LIMIT ?").all(matchQuery, BENCHMARK_TOP_K)
253
- : [];
254
- const queryMs = performance.now() - startedAt;
255
- const byPath = new Map(files.map((file) => [file.path, file]));
256
- const candidates = rows.flatMap((row) => {
257
- const file = byPath.get(row.path);
258
- if (!file) {
259
- return [];
260
- }
261
- const range = bestFtsLineRange(file, query);
262
- return [{
263
- path: file.path,
264
- lines: `${range.start}-${range.end}`,
265
- excerpt: file.lines.slice(range.start - 1, range.end).join("\n"),
266
- rank: row.rank,
267
- reason: `SQLite FTS5 trigram MATCH with bm25 rank ${row.rank.toFixed(6)}`,
268
- }];
269
- });
270
- const first = candidates[0];
271
- return {
272
- toolPathUsed: "fts5-bm25-trigram: node:sqlite FTS5 trigram virtual table",
273
- rawBytes,
274
- contextBytes: byteLength(JSON.stringify(candidates)),
275
- ...(first?.path !== undefined ? { actualPath: first.path } : {}),
276
- ...(first?.lines !== undefined ? { actualLines: first.lines } : {}),
277
- candidatePaths: uniqueCandidatePaths(candidates.map((candidate) => candidate.path)),
278
- excerpt: first?.excerpt ?? "",
279
- buildMs: queryMs,
280
- queryMs,
281
- notes: first ? [first.reason] : ["no FTS5 candidate"],
282
- };
283
- }
284
- finally {
285
- db.close();
286
- }
287
- }
288
- async function hybridObservation(root, cacheRoot, query) {
289
- const rawBytes = await repoRawBytes(root);
290
- const load = await buildOrLoadExperimentalRepoIndex({ root, cacheRoot });
291
- const indexStartedAt = performance.now();
292
- const indexCandidates = queryExperimentalRepoIndex(load.index, query, { topK: BENCHMARK_TOP_K });
293
- const indexQueryMs = performance.now() - indexStartedAt;
294
- const scannerStartedAt = performance.now();
295
- const scanner = await freeflowSearch({ action: "query", source: { kind: "repo", root }, query, preserve: "important", topK: BENCHMARK_TOP_K });
296
- const scannerQueryMs = performance.now() - scannerStartedAt;
297
- const scannerEvidence = scanner.evidence?.[0];
298
- const scannerPaths = uniqueCandidatePaths(scanner.evidence?.map((packet) => packet.path));
299
- const indexPaths = uniqueCandidatePaths(indexCandidates.map((candidate) => candidate.path));
300
- const hybridInput = { scannerPaths, indexCandidates, indexPaths };
301
- if (scannerEvidence !== undefined) {
302
- hybridInput.scannerEvidence = scannerEvidence;
303
- }
304
- const selected = chooseHybridCandidate(hybridInput);
305
- const contextPayload = {
306
- selected: selected.payload,
307
- scannerCandidateCount: scannerPaths.length,
308
- indexCandidateCount: indexPaths.length,
309
- selection: selected.selection,
296
+ const rawBytes = await repoRawBytes(root);
297
+ const ftsStatus = detectFtsCandidateStatus();
298
+ if (!ftsStatus.available) {
299
+ return {
300
+ toolPathUsed: "fts5-bm25-trigram: unavailable optional candidate",
301
+ skipped: true,
302
+ skipReason: ftsStatus.reason,
303
+ rawBytes,
304
+ contextBytes: 0,
305
+ candidatePaths: [],
306
+ excerpt: "",
307
+ notes: [ftsStatus.reason],
310
308
  };
309
+ }
310
+ const files = await readFtsTextFiles(root);
311
+ const sqlite = loadSqliteModule();
312
+ const startedAt = performance.now();
313
+ const db = new sqlite.DatabaseSync(":memory:");
314
+ try {
315
+ db.exec("CREATE VIRTUAL TABLE docs USING fts5(path UNINDEXED, body, tokenize='trigram')");
316
+ const insert = db.prepare("INSERT INTO docs(path, body) VALUES (?, ?)");
317
+ for (const file of files) {
318
+ insert.run(file.path, file.text);
319
+ }
320
+ const matchQuery = ftsMatchQuery(query);
321
+ const rows = matchQuery
322
+ ? db
323
+ .prepare("SELECT path, bm25(docs) AS rank FROM docs WHERE docs MATCH ? ORDER BY rank LIMIT ?")
324
+ .all(matchQuery, BENCHMARK_TOP_K)
325
+ : [];
326
+ const queryMs = performance.now() - startedAt;
327
+ const byPath = new Map(files.map((file) => [file.path, file]));
328
+ const candidates = rows.flatMap((row) => {
329
+ const file = byPath.get(row.path);
330
+ if (!file) {
331
+ return [];
332
+ }
333
+ const range = bestFtsLineRange(file, query);
334
+ return [
335
+ {
336
+ path: file.path,
337
+ lines: `${range.start}-${range.end}`,
338
+ excerpt: file.lines.slice(range.start - 1, range.end).join("\n"),
339
+ rank: row.rank,
340
+ reason: `SQLite FTS5 trigram MATCH with bm25 rank ${row.rank.toFixed(6)}`,
341
+ },
342
+ ];
343
+ });
344
+ const first = candidates[0];
311
345
  return {
312
- toolPathUsed: "hybrid-warm: scanner fallback with warm lexical-index candidates",
313
- rawBytes,
314
- contextBytes: byteLength(JSON.stringify(contextPayload)),
315
- ...(selected.path !== undefined ? { actualPath: selected.path } : {}),
316
- ...(selected.lines !== undefined ? { actualLines: selected.lines } : {}),
317
- candidatePaths: uniqueCandidatePaths([...scannerPaths, ...indexPaths]),
318
- excerpt: selected.excerpt,
319
- buildMs: load.buildMs,
320
- queryMs: indexQueryMs + scannerQueryMs,
321
- indexMode: load.mode,
322
- notes: [
323
- `selection=${selected.selection}`,
324
- `scannerQueryMs=${scannerQueryMs.toFixed(2)}`,
325
- `indexQueryMs=${indexQueryMs.toFixed(2)}`,
326
- ...(load.refreshReason ? [`refresh=${load.refreshReason}`] : []),
327
- ],
346
+ toolPathUsed: "fts5-bm25-trigram: node:sqlite FTS5 trigram virtual table",
347
+ rawBytes,
348
+ contextBytes: byteLength(JSON.stringify(candidates)),
349
+ ...(first?.path !== undefined ? { actualPath: first.path } : {}),
350
+ ...(first?.lines !== undefined ? { actualLines: first.lines } : {}),
351
+ candidatePaths: uniqueCandidatePaths(candidates.map((candidate) => candidate.path)),
352
+ excerpt: first?.excerpt ?? "",
353
+ buildMs: queryMs,
354
+ queryMs,
355
+ notes: first ? [first.reason] : ["no FTS5 candidate"],
328
356
  };
357
+ } finally {
358
+ db.close();
359
+ }
360
+ }
361
+ async function hybridObservation(root, cacheRoot, query) {
362
+ const rawBytes = await repoRawBytes(root);
363
+ const load = await buildOrLoadExperimentalRepoIndex({ root, cacheRoot });
364
+ const indexStartedAt = performance.now();
365
+ const indexCandidates = queryExperimentalRepoIndex(load.index, query, { topK: BENCHMARK_TOP_K });
366
+ const indexQueryMs = performance.now() - indexStartedAt;
367
+ const scannerStartedAt = performance.now();
368
+ const scanner = await freeflowSearch({
369
+ action: "query",
370
+ source: { kind: "repo", root },
371
+ query,
372
+ preserve: "important",
373
+ topK: BENCHMARK_TOP_K,
374
+ });
375
+ const scannerQueryMs = performance.now() - scannerStartedAt;
376
+ const scannerEvidence = scanner.evidence?.[0];
377
+ const scannerPaths = uniqueCandidatePaths(scanner.evidence?.map((packet) => packet.path));
378
+ const indexPaths = uniqueCandidatePaths(indexCandidates.map((candidate) => candidate.path));
379
+ const hybridInput = { scannerPaths, indexCandidates, indexPaths };
380
+ if (scannerEvidence !== undefined) {
381
+ hybridInput.scannerEvidence = scannerEvidence;
382
+ }
383
+ const selected = chooseHybridCandidate(hybridInput);
384
+ const contextPayload = {
385
+ selected: selected.payload,
386
+ scannerCandidateCount: scannerPaths.length,
387
+ indexCandidateCount: indexPaths.length,
388
+ selection: selected.selection,
389
+ };
390
+ return {
391
+ toolPathUsed: "hybrid-warm: scanner fallback with warm lexical-index candidates",
392
+ rawBytes,
393
+ contextBytes: byteLength(JSON.stringify(contextPayload)),
394
+ ...(selected.path !== undefined ? { actualPath: selected.path } : {}),
395
+ ...(selected.lines !== undefined ? { actualLines: selected.lines } : {}),
396
+ candidatePaths: uniqueCandidatePaths([...scannerPaths, ...indexPaths]),
397
+ excerpt: selected.excerpt,
398
+ buildMs: load.buildMs,
399
+ queryMs: indexQueryMs + scannerQueryMs,
400
+ indexMode: load.mode,
401
+ notes: [
402
+ `selection=${selected.selection}`,
403
+ `scannerQueryMs=${scannerQueryMs.toFixed(2)}`,
404
+ `indexQueryMs=${indexQueryMs.toFixed(2)}`,
405
+ ...(load.refreshReason ? [`refresh=${load.refreshReason}`] : []),
406
+ ],
407
+ };
329
408
  }
330
409
  function chooseHybridCandidate(options) {
331
- const scannerEvidence = options.scannerEvidence;
332
- if (scannerEvidence?.path) {
333
- const indexAgrees = options.indexPaths.includes(scannerEvidence.path);
334
- return {
335
- selection: indexAgrees ? "scanner-index-agree" : "scanner-fallback",
336
- path: scannerEvidence.path,
337
- ...(scannerEvidence.lines !== undefined ? { lines: scannerEvidence.lines } : {}),
338
- excerpt: scannerEvidence.excerpt ?? "",
339
- payload: {
340
- source: "scanner",
341
- path: scannerEvidence.path,
342
- ...(scannerEvidence.lines !== undefined ? { lines: scannerEvidence.lines } : {}),
343
- indexAgrees,
344
- },
345
- };
346
- }
347
- const indexCandidate = options.indexCandidates[0];
348
- if (indexCandidate) {
349
- return {
350
- selection: "index-only",
351
- path: indexCandidate.path,
352
- lines: indexCandidate.lines,
353
- excerpt: indexCandidate.excerpt,
354
- payload: {
355
- source: "index",
356
- path: indexCandidate.path,
357
- lines: indexCandidate.lines,
358
- score: indexCandidate.score,
359
- },
360
- };
361
- }
362
- return { selection: "none", excerpt: "", payload: { source: "none" } };
410
+ const scannerEvidence = options.scannerEvidence;
411
+ if (scannerEvidence?.path) {
412
+ const indexAgrees = options.indexPaths.includes(scannerEvidence.path);
413
+ return {
414
+ selection: indexAgrees ? "scanner-index-agree" : "scanner-fallback",
415
+ path: scannerEvidence.path,
416
+ ...(scannerEvidence.lines !== undefined ? { lines: scannerEvidence.lines } : {}),
417
+ excerpt: scannerEvidence.excerpt ?? "",
418
+ payload: {
419
+ source: "scanner",
420
+ path: scannerEvidence.path,
421
+ ...(scannerEvidence.lines !== undefined ? { lines: scannerEvidence.lines } : {}),
422
+ indexAgrees,
423
+ },
424
+ };
425
+ }
426
+ const indexCandidate = options.indexCandidates[0];
427
+ if (indexCandidate) {
428
+ return {
429
+ selection: "index-only",
430
+ path: indexCandidate.path,
431
+ lines: indexCandidate.lines,
432
+ excerpt: indexCandidate.excerpt,
433
+ payload: {
434
+ source: "index",
435
+ path: indexCandidate.path,
436
+ lines: indexCandidate.lines,
437
+ score: indexCandidate.score,
438
+ },
439
+ };
440
+ }
441
+ return { selection: "none", excerpt: "", payload: { source: "none" } };
363
442
  }
364
443
  function detectFtsCandidateStatus() {
365
- if (cachedFtsCandidateStatus !== undefined) {
366
- return cachedFtsCandidateStatus;
367
- }
368
- let db;
369
- try {
370
- const sqlite = loadSqliteModule();
371
- db = new sqlite.DatabaseSync(":memory:");
372
- db.exec("CREATE VIRTUAL TABLE docs USING fts5(path UNINDEXED, body, tokenize='trigram')");
373
- db.exec("INSERT INTO docs(path, body) VALUES ('probe', 'freeflow fts probe')");
374
- const rows = db.prepare("SELECT path, bm25(docs) AS rank FROM docs WHERE docs MATCH ?").all("freeflow AND probe");
375
- cachedFtsCandidateStatus = rows.length > 0
376
- ? {
377
- available: true,
378
- engine: "fts5-bm25-trigram",
379
- reason: "Node node:sqlite is available and supports SQLite FTS5 trigram tokenization with bm25 ranking.",
380
- }
381
- : {
382
- available: false,
383
- engine: "none",
384
- reason: "SQLite FTS5 probe returned no rows for a known trigram query.",
385
- };
386
- }
387
- catch (error) {
388
- const message = error instanceof Error ? error.message : String(error);
389
- cachedFtsCandidateStatus = {
444
+ if (cachedFtsCandidateStatus !== undefined) {
445
+ return cachedFtsCandidateStatus;
446
+ }
447
+ let db;
448
+ try {
449
+ const sqlite = loadSqliteModule();
450
+ db = new sqlite.DatabaseSync(":memory:");
451
+ db.exec("CREATE VIRTUAL TABLE docs USING fts5(path UNINDEXED, body, tokenize='trigram')");
452
+ db.exec("INSERT INTO docs(path, body) VALUES ('probe', 'freeflow fts probe')");
453
+ const rows = db.prepare("SELECT path, bm25(docs) AS rank FROM docs WHERE docs MATCH ?").all("freeflow AND probe");
454
+ cachedFtsCandidateStatus =
455
+ rows.length > 0
456
+ ? {
457
+ available: true,
458
+ engine: "fts5-bm25-trigram",
459
+ reason: "Node node:sqlite is available and supports SQLite FTS5 trigram tokenization with bm25 ranking.",
460
+ }
461
+ : {
390
462
  available: false,
391
463
  engine: "none",
392
- reason: `SQLite FTS5/BM25/trigram candidate unavailable: ${message}`,
393
- };
394
- }
395
- finally {
396
- db?.close();
397
- }
398
- return cachedFtsCandidateStatus;
464
+ reason: "SQLite FTS5 probe returned no rows for a known trigram query.",
465
+ };
466
+ } catch (error) {
467
+ const message = error instanceof Error ? error.message : String(error);
468
+ cachedFtsCandidateStatus = {
469
+ available: false,
470
+ engine: "none",
471
+ reason: `SQLite FTS5/BM25/trigram candidate unavailable: ${message}`,
472
+ };
473
+ } finally {
474
+ db?.close();
475
+ }
476
+ return cachedFtsCandidateStatus;
399
477
  }
400
478
  function loadSqliteModule() {
401
- return require("node:sqlite");
479
+ return require("node:sqlite");
402
480
  }
403
481
  async function readFtsTextFiles(root) {
404
- const files = [];
405
- await collectFtsTextFiles(root, root, files);
406
- return files.sort((a, b) => a.path.localeCompare(b.path));
482
+ const files = [];
483
+ await collectFtsTextFiles(root, root, files);
484
+ return files.sort((a, b) => a.path.localeCompare(b.path));
407
485
  }
408
486
  async function collectFtsTextFiles(root, currentPath, files) {
409
- const currentStat = await stat(currentPath);
410
- if (currentStat.isDirectory()) {
411
- const dirEntries = await readdir(currentPath, { withFileTypes: true });
412
- for (const entry of dirEntries.sort((a, b) => a.name.localeCompare(b.name))) {
413
- await collectFtsTextFiles(root, resolve(currentPath, entry.name), files);
414
- }
415
- return;
416
- }
417
- if (!currentStat.isFile()) {
418
- return;
419
- }
420
- const path = relative(root, currentPath).split(/[\\/]+/).join("/");
421
- if (isGeneratedBenchmarkPath(path)) {
422
- return;
423
- }
424
- try {
425
- const text = await readFile(currentPath, "utf8");
426
- if (!text.includes("\0")) {
427
- files.push({ path, text, lines: splitLines(text) });
428
- }
429
- }
430
- catch {
431
- // ignore non-text fixture files
432
- }
487
+ const currentStat = await stat(currentPath);
488
+ if (currentStat.isDirectory()) {
489
+ const dirEntries = await readdir(currentPath, { withFileTypes: true });
490
+ for (const entry of dirEntries.sort((a, b) => a.name.localeCompare(b.name))) {
491
+ await collectFtsTextFiles(root, resolve(currentPath, entry.name), files);
492
+ }
493
+ return;
494
+ }
495
+ if (!currentStat.isFile()) {
496
+ return;
497
+ }
498
+ const path = relative(root, currentPath)
499
+ .split(/[\\/]+/)
500
+ .join("/");
501
+ if (isGeneratedBenchmarkPath(path)) {
502
+ return;
503
+ }
504
+ try {
505
+ const text = await readFile(currentPath, "utf8");
506
+ if (!text.includes("\0")) {
507
+ files.push({ path, text, lines: splitLines(text) });
508
+ }
509
+ } catch {
510
+ // ignore non-text fixture files
511
+ }
433
512
  }
434
513
  function ftsMatchQuery(query) {
435
- return searchTokens(query).filter((token) => token.length >= 3).join(" AND ");
514
+ return searchTokens(query)
515
+ .filter((token) => token.length >= 3)
516
+ .join(" AND ");
436
517
  }
437
518
  function bestFtsLineRange(file, query) {
438
- const tokens = searchTokens(query);
439
- let bestIndex = 0;
440
- let bestScore = -1;
441
- for (let index = 0; index < file.lines.length; index += 1) {
442
- const normalizedLine = (file.lines[index] ?? "").toLowerCase();
443
- const score = tokens.reduce((sum, token) => sum + (normalizedLine.includes(token) ? 1 : 0), 0);
444
- if (score > bestScore) {
445
- bestScore = score;
446
- bestIndex = index;
447
- }
448
- }
449
- const start = Math.max(1, bestIndex + 1 - FTS_CONTEXT_LINES);
450
- const end = Math.min(file.lines.length, bestIndex + 1 + FTS_CONTEXT_LINES);
451
- return { start, end };
519
+ const tokens = searchTokens(query);
520
+ let bestIndex = 0;
521
+ let bestScore = -1;
522
+ for (let index = 0; index < file.lines.length; index += 1) {
523
+ const normalizedLine = (file.lines[index] ?? "").toLowerCase();
524
+ const score = tokens.reduce((sum, token) => sum + (normalizedLine.includes(token) ? 1 : 0), 0);
525
+ if (score > bestScore) {
526
+ bestScore = score;
527
+ bestIndex = index;
528
+ }
529
+ }
530
+ const start = Math.max(1, bestIndex + 1 - FTS_CONTEXT_LINES);
531
+ const end = Math.min(file.lines.length, bestIndex + 1 + FTS_CONTEXT_LINES);
532
+ return { start, end };
452
533
  }
453
534
  function searchTokens(value) {
454
- const seen = new Set();
455
- const tokens = [];
456
- for (const token of value.toLowerCase().match(/[a-z0-9_]+/g) ?? []) {
457
- if (!seen.has(token)) {
458
- seen.add(token);
459
- tokens.push(token);
460
- }
535
+ const seen = new Set();
536
+ const tokens = [];
537
+ for (const token of value.toLowerCase().match(/[a-z0-9_]+/g) ?? []) {
538
+ if (!seen.has(token)) {
539
+ seen.add(token);
540
+ tokens.push(token);
461
541
  }
462
- return tokens;
542
+ }
543
+ return tokens;
463
544
  }
464
545
  function summarizeIndexReport(fixtures) {
465
- const scanner = summarizeMode(fixtures, "scanner-default");
466
- const index = summarizeMode(fixtures, "index-warm");
467
- const fts = summarizeMode(fixtures, "fts5-bm25-trigram");
468
- const hybrid = summarizeMode(fixtures, "hybrid-warm");
469
- const generatedFalsePositiveCount = fixtures
470
- .flatMap((fixture) => fixture.results)
471
- .filter((result) => result.correctness.generatedFalsePositive).length;
472
- const coldBuildMs = latencyFor(fixtures, "index-cold", "buildMs");
473
- const warmQueryMs = latencyFor(fixtures, "index-warm", "queryMs");
474
- const staleRefreshMs = latencyFor(fixtures, "index-stale-refresh", "buildMs");
475
- return {
476
- fixtures: fixtures.length,
477
- modeResults: fixtures.reduce((count, fixture) => count + fixture.results.length, 0),
478
- scannerDefault: true,
479
- indexAdopted: false,
480
- ftsCandidate: detectFtsCandidateStatus(),
481
- scanner,
482
- index,
483
- fts,
484
- hybrid,
485
- generatedFalsePositiveCount,
486
- coldBuildMs,
487
- warmQueryMs,
488
- staleRefreshMs,
489
- };
546
+ const scanner = summarizeMode(fixtures, "scanner-default");
547
+ const index = summarizeMode(fixtures, "index-warm");
548
+ const fts = summarizeMode(fixtures, "fts5-bm25-trigram");
549
+ const hybrid = summarizeMode(fixtures, "hybrid-warm");
550
+ const generatedFalsePositiveCount = fixtures
551
+ .flatMap((fixture) => fixture.results)
552
+ .filter((result) => result.correctness.generatedFalsePositive).length;
553
+ const coldBuildMs = latencyFor(fixtures, "index-cold", "buildMs");
554
+ const warmQueryMs = latencyFor(fixtures, "index-warm", "queryMs");
555
+ const staleRefreshMs = latencyFor(fixtures, "index-stale-refresh", "buildMs");
556
+ return {
557
+ fixtures: fixtures.length,
558
+ modeResults: fixtures.reduce((count, fixture) => count + fixture.results.length, 0),
559
+ scannerDefault: true,
560
+ indexAdopted: false,
561
+ ftsCandidate: detectFtsCandidateStatus(),
562
+ scanner,
563
+ index,
564
+ fts,
565
+ hybrid,
566
+ generatedFalsePositiveCount,
567
+ coldBuildMs,
568
+ warmQueryMs,
569
+ staleRefreshMs,
570
+ };
490
571
  }
491
572
  function summarizeMode(fixtures, mode) {
492
- const results = fixtures
493
- .map((fixture) => fixture.results.find((result) => result.mode === mode))
494
- .filter((result) => Boolean(result));
495
- const totalRawBytes = results.reduce((sum, result) => sum + result.rawBytes, 0);
496
- const totalContextBytes = results.reduce((sum, result) => sum + result.contextBytes, 0);
497
- return results.reduce((summary, result) => {
498
- if (result.skipped) {
499
- summary.skipped += 1;
500
- }
501
- else if (result.correctness.passed) {
502
- summary.passed += 1;
503
- }
504
- else {
505
- summary.failed += 1;
506
- }
507
- if (result.correctness.pathCorrect) {
508
- summary.pathCorrect += 1;
509
- }
510
- if (result.correctness.spanCorrect) {
511
- summary.spanCorrect += 1;
512
- }
513
- if (result.correctness.excerptComplete) {
514
- summary.excerptComplete += 1;
515
- }
516
- if (result.correctness.recallAtK) {
517
- summary.recallAtK += 1;
518
- }
519
- return summary;
520
- }, {
521
- passed: 0,
522
- failed: 0,
523
- skipped: 0,
524
- pathCorrect: 0,
525
- spanCorrect: 0,
526
- excerptComplete: 0,
527
- recallAtK: 0,
528
- totalRawBytes,
529
- totalContextBytes,
530
- weightedContextReductionPercent: reductionPercent(totalRawBytes, totalContextBytes),
531
- });
573
+ const results = fixtures
574
+ .map((fixture) => fixture.results.find((result) => result.mode === mode))
575
+ .filter((result) => Boolean(result));
576
+ const totalRawBytes = results.reduce((sum, result) => sum + result.rawBytes, 0);
577
+ const totalContextBytes = results.reduce((sum, result) => sum + result.contextBytes, 0);
578
+ return results.reduce(
579
+ (summary, result) => {
580
+ if (result.skipped) {
581
+ summary.skipped += 1;
582
+ } else if (result.correctness.passed) {
583
+ summary.passed += 1;
584
+ } else {
585
+ summary.failed += 1;
586
+ }
587
+ if (result.correctness.pathCorrect) {
588
+ summary.pathCorrect += 1;
589
+ }
590
+ if (result.correctness.spanCorrect) {
591
+ summary.spanCorrect += 1;
592
+ }
593
+ if (result.correctness.excerptComplete) {
594
+ summary.excerptComplete += 1;
595
+ }
596
+ if (result.correctness.recallAtK) {
597
+ summary.recallAtK += 1;
598
+ }
599
+ return summary;
600
+ },
601
+ {
602
+ passed: 0,
603
+ failed: 0,
604
+ skipped: 0,
605
+ pathCorrect: 0,
606
+ spanCorrect: 0,
607
+ excerptComplete: 0,
608
+ recallAtK: 0,
609
+ totalRawBytes,
610
+ totalContextBytes,
611
+ weightedContextReductionPercent: reductionPercent(totalRawBytes, totalContextBytes),
612
+ },
613
+ );
532
614
  }
533
615
  function latencyFor(fixtures, mode, field) {
534
- const values = fixtures
535
- .map((fixture) => fixture.results.find((result) => result.mode === mode)?.[field])
536
- .filter((value) => typeof value === "number");
537
- return latencySummary(values);
616
+ const values = fixtures
617
+ .map((fixture) => fixture.results.find((result) => result.mode === mode)?.[field])
618
+ .filter((value) => typeof value === "number");
619
+ return latencySummary(values);
538
620
  }
539
621
  function indexFixtureDefinitions() {
540
- return [
541
- {
542
- id: "index-exact-copied-text",
543
- title: "Exact copied text block",
544
- files: {
545
- "target.md": ["# Target", "", "ExperimentalIndex exact copied text source truth."].join("\n"),
546
- "decoy.md": "ExperimentalIndex ExperimentalIndex ExperimentalIndex without copied source truth",
547
- },
548
- query: "ExperimentalIndex exact copied text source truth",
549
- expected: {
550
- path: "target.md",
551
- lines: "1-3",
552
- requiredExcerpt: ["ExperimentalIndex exact copied text source truth"],
553
- },
554
- },
555
- {
556
- id: "index-generated-artifact-decoy",
557
- title: "Generated-artifact decoy",
558
- files: {
559
- "docs/codex-cli-agent-harness/2026-06-12-pass-3-sandboxing-and-permissions.md": [
560
- "# Pass 3",
561
- "",
562
- "### Sandbox Permissions",
563
- "",
564
- "`SandboxPermissions` is a per-command request shape.",
565
- "",
566
- "Plain-language meaning:",
567
- "",
568
- "UseDefault: run with the turn's normal sandbox.",
569
- ].join("\n"),
570
- "graphify-out/graph.html": [
571
- "<html><body>",
572
- `${"Sandbox Permissions SandboxPermissions Plain-language meaning ".repeat(5000)}GENERATED_GRAPH_DECOY_SENTINEL`,
573
- "</body></html>",
574
- ].join("\n"),
575
- },
576
- query: "Sandbox Permissions SandboxPermissions Plain-language meaning",
577
- expected: {
578
- path: "docs/codex-cli-agent-harness/2026-06-12-pass-3-sandboxing-and-permissions.md",
579
- lines: "3-7",
580
- requiredExcerpt: ["SandboxPermissions", "Plain-language meaning"],
581
- },
582
- },
583
- {
584
- id: "index-stale-refresh",
585
- title: "Changed-file stale refresh",
586
- files: {
587
- "target.md": ["# Target", "", "StaleIndexNeedle original source truth."].join("\n"),
588
- },
589
- query: "StaleIndexNeedle original source truth",
590
- expected: {
591
- path: "target.md",
592
- lines: "1-3",
593
- requiredExcerpt: ["StaleIndexNeedle original"],
594
- },
595
- staleFiles: {
596
- "target.md": ["# Target", "", "StaleIndexNeedle refreshed source truth."].join("\n"),
597
- },
598
- staleQuery: "StaleIndexNeedle refreshed source truth",
599
- staleExpected: {
600
- path: "target.md",
601
- lines: "1-3",
602
- requiredExcerpt: ["StaleIndexNeedle refreshed"],
603
- },
604
- },
605
- ];
622
+ return [
623
+ {
624
+ id: "index-exact-copied-text",
625
+ title: "Exact copied text block",
626
+ files: {
627
+ "target.md": ["# Target", "", "ExperimentalIndex exact copied text source truth."].join("\n"),
628
+ "decoy.md": "ExperimentalIndex ExperimentalIndex ExperimentalIndex without copied source truth",
629
+ },
630
+ query: "ExperimentalIndex exact copied text source truth",
631
+ expected: {
632
+ path: "target.md",
633
+ lines: "1-3",
634
+ requiredExcerpt: ["ExperimentalIndex exact copied text source truth"],
635
+ },
636
+ },
637
+ {
638
+ id: "index-generated-artifact-decoy",
639
+ title: "Generated-artifact decoy",
640
+ files: {
641
+ "router/evals/fixtures/output-router-corpus/sandbox-permissions.md": [
642
+ "# Pass 3",
643
+ "",
644
+ "### Sandbox Permissions",
645
+ "",
646
+ "`SandboxPermissions` is a per-command request shape.",
647
+ "",
648
+ "Plain-language meaning:",
649
+ "",
650
+ "UseDefault: run with the turn's normal sandbox.",
651
+ ].join("\n"),
652
+ "graphify-out/graph.html": [
653
+ "<html><body>",
654
+ `${"Sandbox Permissions SandboxPermissions Plain-language meaning ".repeat(5000)}GENERATED_GRAPH_DECOY_SENTINEL`,
655
+ "</body></html>",
656
+ ].join("\n"),
657
+ },
658
+ query: "Sandbox Permissions SandboxPermissions Plain-language meaning",
659
+ expected: {
660
+ path: "router/evals/fixtures/output-router-corpus/sandbox-permissions.md",
661
+ lines: "3-7",
662
+ requiredExcerpt: ["SandboxPermissions", "Plain-language meaning"],
663
+ },
664
+ },
665
+ {
666
+ id: "index-stale-refresh",
667
+ title: "Changed-file stale refresh",
668
+ files: {
669
+ "target.md": ["# Target", "", "StaleIndexNeedle original source truth."].join("\n"),
670
+ },
671
+ query: "StaleIndexNeedle original source truth",
672
+ expected: {
673
+ path: "target.md",
674
+ lines: "1-3",
675
+ requiredExcerpt: ["StaleIndexNeedle original"],
676
+ },
677
+ staleFiles: {
678
+ "target.md": ["# Target", "", "StaleIndexNeedle refreshed source truth."].join("\n"),
679
+ },
680
+ staleQuery: "StaleIndexNeedle refreshed source truth",
681
+ staleExpected: {
682
+ path: "target.md",
683
+ lines: "1-3",
684
+ requiredExcerpt: ["StaleIndexNeedle refreshed"],
685
+ },
686
+ },
687
+ ];
606
688
  }
607
689
  function fixtureExpectedForMode(fixture, mode) {
608
- if ((mode === "index-stale-refresh" || fixture.staleQuery) && fixture.staleExpected) {
609
- return fixture.staleExpected;
610
- }
611
- return fixture.expected;
690
+ if ((mode === "index-stale-refresh" || fixture.staleQuery) && fixture.staleExpected) {
691
+ return fixture.staleExpected;
692
+ }
693
+ return fixture.expected;
612
694
  }
613
695
  function scoreCorrectness(expected, observation) {
614
- if (observation.skipped) {
615
- return {
616
- passed: false,
617
- pathCorrect: false,
618
- spanCorrect: false,
619
- excerptComplete: false,
620
- recallAtK: false,
621
- generatedFalsePositive: false,
622
- };
623
- }
624
- const pathCorrect = observation.actualPath === expected.path;
625
- const spanCorrect = expected.lines ? Boolean(observation.actualLines && rangesOverlap(expected.lines, observation.actualLines)) : true;
626
- const excerptComplete = expected.requiredExcerpt.every((snippet) => observation.excerpt.toLowerCase().includes(snippet.toLowerCase()));
627
- const candidatePaths = observation.candidatePaths ?? [];
628
- const recallAtK = candidatePaths.length === 0 ? pathCorrect : candidatePaths.includes(expected.path);
629
- const generatedFalsePositive = observation.actualPath ? isGeneratedBenchmarkPath(observation.actualPath) : false;
696
+ if (observation.skipped) {
630
697
  return {
631
- passed: pathCorrect && spanCorrect && excerptComplete && recallAtK && !generatedFalsePositive,
632
- pathCorrect,
633
- spanCorrect,
634
- excerptComplete,
635
- recallAtK,
636
- generatedFalsePositive,
698
+ passed: false,
699
+ pathCorrect: false,
700
+ spanCorrect: false,
701
+ excerptComplete: false,
702
+ recallAtK: false,
703
+ generatedFalsePositive: false,
637
704
  };
705
+ }
706
+ const pathCorrect = observation.actualPath === expected.path;
707
+ const spanCorrect = expected.lines
708
+ ? Boolean(observation.actualLines && rangesOverlap(expected.lines, observation.actualLines))
709
+ : true;
710
+ const excerptComplete = expected.requiredExcerpt.every((snippet) =>
711
+ observation.excerpt.toLowerCase().includes(snippet.toLowerCase()),
712
+ );
713
+ const candidatePaths = observation.candidatePaths ?? [];
714
+ const recallAtK = candidatePaths.length === 0 ? pathCorrect : candidatePaths.includes(expected.path);
715
+ const generatedFalsePositive = observation.actualPath ? isGeneratedBenchmarkPath(observation.actualPath) : false;
716
+ return {
717
+ passed: pathCorrect && spanCorrect && excerptComplete && recallAtK && !generatedFalsePositive,
718
+ pathCorrect,
719
+ spanCorrect,
720
+ excerptComplete,
721
+ recallAtK,
722
+ generatedFalsePositive,
723
+ };
638
724
  }
639
725
  async function writeFixtureFiles(root, files) {
640
- for (const [path, text] of Object.entries(files)) {
641
- const absolutePath = resolve(root, path);
642
- await mkdir(dirname(absolutePath), { recursive: true });
643
- await writeFile(absolutePath, text, "utf8");
644
- }
726
+ for (const [path, text] of Object.entries(files)) {
727
+ const absolutePath = resolve(root, path);
728
+ await mkdir(dirname(absolutePath), { recursive: true });
729
+ await writeFile(absolutePath, text, "utf8");
730
+ }
645
731
  }
646
732
  async function repoRawBytes(root) {
647
- const entries = [];
648
- await collectRawText(root, root, entries);
649
- return byteLength(entries.join("\n"));
733
+ const entries = [];
734
+ await collectRawText(root, root, entries);
735
+ return byteLength(entries.join("\n"));
650
736
  }
651
737
  async function collectRawText(root, currentPath, entries) {
652
- const currentStat = await stat(currentPath);
653
- if (currentStat.isDirectory()) {
654
- const dirEntries = await readdir(currentPath, { withFileTypes: true });
655
- for (const entry of dirEntries.sort((a, b) => a.name.localeCompare(b.name))) {
656
- await collectRawText(root, resolve(currentPath, entry.name), entries);
657
- }
658
- return;
659
- }
660
- if (!currentStat.isFile()) {
661
- return;
662
- }
663
- try {
664
- const text = await readFile(currentPath, "utf8");
665
- if (!text.includes("\0")) {
666
- entries.push(text);
667
- }
668
- }
669
- catch {
670
- // ignore non-text fixture files
671
- }
738
+ const currentStat = await stat(currentPath);
739
+ if (currentStat.isDirectory()) {
740
+ const dirEntries = await readdir(currentPath, { withFileTypes: true });
741
+ for (const entry of dirEntries.sort((a, b) => a.name.localeCompare(b.name))) {
742
+ await collectRawText(root, resolve(currentPath, entry.name), entries);
743
+ }
744
+ return;
745
+ }
746
+ if (!currentStat.isFile()) {
747
+ return;
748
+ }
749
+ try {
750
+ const text = await readFile(currentPath, "utf8");
751
+ if (!text.includes("\0")) {
752
+ entries.push(text);
753
+ }
754
+ } catch {
755
+ // ignore non-text fixture files
756
+ }
672
757
  }
673
758
  async function createTempDir(prefix) {
674
- const path = await mkdtemp(resolve(tmpdir(), prefix));
675
- return {
676
- path,
677
- cleanup: async () => {
678
- await rm(path, { recursive: true, force: true });
679
- },
680
- };
759
+ const path = await mkdtemp(resolve(tmpdir(), prefix));
760
+ return {
761
+ path,
762
+ cleanup: async () => {
763
+ await rm(path, { recursive: true, force: true });
764
+ },
765
+ };
681
766
  }
682
767
  function indexBenchmarkModes() {
683
- return ["scanner-default", "index-cold", "index-warm", "index-stale-refresh", "fts5-bm25-trigram", "hybrid-warm"];
768
+ return ["scanner-default", "index-cold", "index-warm", "index-stale-refresh", "fts5-bm25-trigram", "hybrid-warm"];
684
769
  }
685
770
  function rangesOverlap(left, right) {
686
- const leftRange = parseRange(left);
687
- const rightRange = parseRange(right);
688
- if (!leftRange || !rightRange) {
689
- return false;
690
- }
691
- return leftRange.start <= rightRange.end && rightRange.start <= leftRange.end;
771
+ const leftRange = parseRange(left);
772
+ const rightRange = parseRange(right);
773
+ if (!leftRange || !rightRange) {
774
+ return false;
775
+ }
776
+ return leftRange.start <= rightRange.end && rightRange.start <= leftRange.end;
692
777
  }
693
778
  function parseRange(range) {
694
- const match = /^(\d+)-(\d+)$/.exec(range);
695
- if (!match) {
696
- return null;
697
- }
698
- const start = Number(match[1]);
699
- const end = Number(match[2]);
700
- return Number.isInteger(start) && Number.isInteger(end) ? { start, end } : null;
779
+ const match = /^(\d+)-(\d+)$/.exec(range);
780
+ if (!match) {
781
+ return null;
782
+ }
783
+ const start = Number(match[1]);
784
+ const end = Number(match[2]);
785
+ return Number.isInteger(start) && Number.isInteger(end) ? { start, end } : null;
701
786
  }
702
787
  function uniqueCandidatePaths(paths) {
703
- const seen = new Set();
704
- const unique = [];
705
- for (const path of paths ?? []) {
706
- if (!path || seen.has(path)) {
707
- continue;
708
- }
709
- seen.add(path);
710
- unique.push(path);
788
+ const seen = new Set();
789
+ const unique = [];
790
+ for (const path of paths ?? []) {
791
+ if (!path || seen.has(path)) {
792
+ continue;
711
793
  }
712
- return unique;
794
+ seen.add(path);
795
+ unique.push(path);
796
+ }
797
+ return unique;
713
798
  }
714
799
  function isGeneratedBenchmarkPath(path) {
715
- const segments = path.split(/[\\/]+/);
716
- if (segments.includes("graphify-out")) {
717
- return true;
718
- }
719
- const name = segments.at(-1)?.toLowerCase() ?? path.toLowerCase();
720
- return name.endsWith(".log") || name.endsWith(".map") || name.endsWith(".min.js") || name.endsWith(".min.css") || name.includes(".bundle.");
800
+ const segments = path.split(/[\\/]+/);
801
+ if (segments.includes("graphify-out")) {
802
+ return true;
803
+ }
804
+ const name = segments.at(-1)?.toLowerCase() ?? path.toLowerCase();
805
+ return (
806
+ name.endsWith(".log") ||
807
+ name.endsWith(".map") ||
808
+ name.endsWith(".min.js") ||
809
+ name.endsWith(".min.css") ||
810
+ name.includes(".bundle.")
811
+ );
721
812
  }
722
813
  function splitLines(text) {
723
- return text.split(/\r?\n/);
814
+ return text.split(/\r?\n/);
724
815
  }
725
816
  function byteLength(value) {
726
- return Buffer.byteLength(value, "utf8");
817
+ return Buffer.byteLength(value, "utf8");
727
818
  }
728
819
  function formatCorrectnessChecks(correctness) {
729
- return [
730
- `path ${correctness.pathCorrect ? "✓" : "✗"}`,
731
- `span ${correctness.spanCorrect ? "✓" : "✗"}`,
732
- `excerpt ${correctness.excerptComplete ? "✓" : "✗"}`,
733
- `recall@${BENCHMARK_TOP_K} ${correctness.recallAtK ? "✓" : "✗"}`,
734
- `gen-fp ${correctness.generatedFalsePositive ? "✗" : "✓"}`,
735
- ].join(" ");
820
+ return [
821
+ `path ${correctness.pathCorrect ? "✓" : "✗"}`,
822
+ `span ${correctness.spanCorrect ? "✓" : "✗"}`,
823
+ `excerpt ${correctness.excerptComplete ? "✓" : "✗"}`,
824
+ `recall@${BENCHMARK_TOP_K} ${correctness.recallAtK ? "✓" : "✗"}`,
825
+ `gen-fp ${correctness.generatedFalsePositive ? "✗" : "✓"}`,
826
+ ].join(" ");
736
827
  }
737
828
  function defaultReportPath() {
738
- return resolve(process.cwd(), "evals/reports/runtime/output-router-index-benchmark-1-report.md");
829
+ return resolve(process.cwd(), "router/evals/reports/output-router-index-benchmark-1-report.md");
739
830
  }
740
831
  async function runCli() {
741
- const { iterations, reportPath, jsonReportPath } = parseBenchmarkCliArgs(process.argv.slice(2), { reportPath: defaultReportPath() });
742
- const options = {};
743
- if (iterations !== undefined) {
744
- options.iterations = iterations;
745
- }
746
- const report = await runIndexBenchmarks(options);
747
- const reports = await writeIndexBenchmarkReports(report, reportPath, {
748
- jsonReportPath: jsonReportPath === undefined ? defaultJsonRunReportPath(reportPath) : jsonReportPath,
749
- });
750
- const shortId = createHash("sha256").update(JSON.stringify(report.summary)).digest("hex").slice(0, 8);
751
- console.log(`Freeflow repo search backend benchmark ${shortId}: scanner ${report.summary.scanner.passed}/${report.summary.fixtures}, index ${report.summary.index.passed}/${report.summary.fixtures}, fts ${report.summary.fts.passed}/${report.summary.fixtures}, hybrid ${report.summary.hybrid.passed}/${report.summary.fixtures} pass`);
752
- console.log(`Markdown report: ${reports.markdown}`);
753
- if (reports.json) {
754
- console.log(`JSON run data: ${reports.json}`);
755
- }
756
- if (report.summary.scanner.failed > 0 || report.summary.index.failed > 0 || report.summary.fts.failed > 0 || report.summary.hybrid.failed > 0) {
757
- process.exitCode = 1;
758
- }
832
+ const { iterations, reportPath, jsonReportPath } = parseBenchmarkCliArgs(process.argv.slice(2), {
833
+ reportPath: defaultReportPath(),
834
+ });
835
+ const options = {};
836
+ if (iterations !== undefined) {
837
+ options.iterations = iterations;
838
+ }
839
+ const report = await runIndexBenchmarks(options);
840
+ const reports = await writeIndexBenchmarkReports(report, reportPath, {
841
+ jsonReportPath: jsonReportPath === undefined ? defaultJsonRunReportPath(reportPath) : jsonReportPath,
842
+ });
843
+ const shortId = createHash("sha256").update(JSON.stringify(report.summary)).digest("hex").slice(0, 8);
844
+ console.log(
845
+ `Freeflow repo search backend benchmark ${shortId}: scanner ${report.summary.scanner.passed}/${report.summary.fixtures}, index ${report.summary.index.passed}/${report.summary.fixtures}, fts ${report.summary.fts.passed}/${report.summary.fixtures}, hybrid ${report.summary.hybrid.passed}/${report.summary.fixtures} pass`,
846
+ );
847
+ console.log(`Markdown report: ${reports.markdown}`);
848
+ if (reports.json) {
849
+ console.log(`JSON run data: ${reports.json}`);
850
+ }
851
+ if (
852
+ report.summary.scanner.failed > 0 ||
853
+ report.summary.index.failed > 0 ||
854
+ report.summary.fts.failed > 0 ||
855
+ report.summary.hybrid.failed > 0
856
+ ) {
857
+ process.exitCode = 1;
858
+ }
759
859
  }
760
860
  if (process.argv[1] && fileURLToPath(import.meta.url) === resolve(process.argv[1])) {
761
- await runCli();
861
+ await runCli();
762
862
  }