@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
@@ -4,877 +4,976 @@ import { tmpdir } from "node:os";
4
4
  import { dirname, relative, resolve } from "node:path";
5
5
  import { fileURLToPath } from "node:url";
6
6
  import { performance } from "node:perf_hooks";
7
- import { approximateTokens, averagePercent as average, defaultJsonRunReportPath, escapeMarkdownTableCell as escapeTable, formatPercent, latencySummary, medianPercent as median, normalizeIterations, parseBenchmarkCliArgs, reductionPercent, writeBenchmarkReportPair, } from "./benchmark-harness.js";
7
+ import {
8
+ approximateTokens,
9
+ averagePercent as average,
10
+ defaultJsonRunReportPath,
11
+ escapeMarkdownTableCell as escapeTable,
12
+ formatPercent,
13
+ latencySummary,
14
+ medianPercent as median,
15
+ normalizeIterations,
16
+ parseBenchmarkCliArgs,
17
+ reductionPercent,
18
+ writeBenchmarkReportPair,
19
+ } from "./benchmark-harness.js";
8
20
  import { freeflowSearch } from "../tools/search.js";
9
21
  import { createVault, storeCommandOutput } from "../vault/vault.js";
10
22
  const DEFAULT_ITERATIONS = 3;
11
23
  const DEFAULT_CONTEXT_LINES = 2;
12
- const LEGACY_SKIP_DIRS = new Set([".git", "node_modules", "dist", "build", "out", ".next", ".nuxt", "coverage", "target"]);
24
+ const LEGACY_SKIP_DIRS = new Set([
25
+ ".git",
26
+ "node_modules",
27
+ "dist",
28
+ "build",
29
+ "out",
30
+ ".next",
31
+ ".nuxt",
32
+ "coverage",
33
+ "target",
34
+ ]);
13
35
  const GENERATED_DIRS = new Set([
14
- ".git",
15
- "node_modules",
16
- "dist",
17
- "build",
18
- "out",
19
- ".next",
20
- ".nuxt",
21
- "coverage",
22
- "target",
23
- "graphify-out",
24
- ".cache",
25
- ".tmp",
26
- "tmp",
27
- "temp",
28
- "logs",
36
+ ".git",
37
+ "node_modules",
38
+ "dist",
39
+ "build",
40
+ "out",
41
+ ".next",
42
+ ".nuxt",
43
+ "coverage",
44
+ "target",
45
+ "graphify-out",
46
+ ".cache",
47
+ ".tmp",
48
+ "tmp",
49
+ "temp",
50
+ "logs",
29
51
  ]);
30
52
  const EXTERNAL_TOOL_SKIPS = [
31
- { name: "Graphify", reason: "Optional external comparator is not required for CI-friendly router benchmarks." },
32
- { name: "Claude Context", reason: "Optional semantic/hybrid search comparator is skipped unless configured separately." },
33
- { name: "RTK", reason: "Command-output comparator belongs to the later command benchmark track." },
34
- { name: "Squeez", reason: "Session-efficiency comparator belongs to the later command/session benchmark track." },
53
+ { name: "Graphify", reason: "Optional external comparator is not required for CI-friendly router benchmarks." },
54
+ {
55
+ name: "Claude Context",
56
+ reason: "Optional semantic/hybrid search comparator is skipped unless configured separately.",
57
+ },
58
+ { name: "RTK", reason: "Command-output comparator belongs to the later command benchmark track." },
59
+ { name: "Squeez", reason: "Session-efficiency comparator belongs to the later command/session benchmark track." },
35
60
  ];
36
61
  export async function runRouterBenchmarks(options = {}) {
37
- const iterations = normalizeIterations(options.iterations, DEFAULT_ITERATIONS);
38
- const fixtures = await createBenchmarkFixtures();
39
- try {
40
- const fixtureResults = [];
41
- for (const fixture of fixtures) {
42
- const results = [];
43
- for (const mode of benchmarkModes()) {
44
- results.push(await runFixtureMode(fixture, mode, iterations));
45
- }
46
- fixtureResults.push({
47
- id: fixture.id,
48
- title: fixture.title,
49
- kind: fixture.kind,
50
- expected: fixture.expected,
51
- results,
52
- });
53
- }
54
- return {
55
- generatedAt: options.generatedAt ?? new Date().toISOString(),
56
- iterations,
57
- summary: summarizeReport(fixtureResults),
58
- fixtures: fixtureResults,
59
- skippedExternalTools: EXTERNAL_TOOL_SKIPS,
60
- };
61
- }
62
- finally {
63
- await Promise.all(fixtures.map((fixture) => fixture.cleanup()));
62
+ const iterations = normalizeIterations(options.iterations, DEFAULT_ITERATIONS);
63
+ const fixtures = await createBenchmarkFixtures();
64
+ try {
65
+ const fixtureResults = [];
66
+ for (const fixture of fixtures) {
67
+ const results = [];
68
+ for (const mode of benchmarkModes()) {
69
+ results.push(await runFixtureMode(fixture, mode, iterations));
70
+ }
71
+ fixtureResults.push({
72
+ id: fixture.id,
73
+ title: fixture.title,
74
+ kind: fixture.kind,
75
+ expected: fixture.expected,
76
+ results,
77
+ });
64
78
  }
79
+ return {
80
+ generatedAt: options.generatedAt ?? new Date().toISOString(),
81
+ iterations,
82
+ summary: summarizeReport(fixtureResults),
83
+ fixtures: fixtureResults,
84
+ skippedExternalTools: EXTERNAL_TOOL_SKIPS,
85
+ };
86
+ } finally {
87
+ await Promise.all(fixtures.map((fixture) => fixture.cleanup()));
88
+ }
65
89
  }
66
90
  export function renderRouterBenchmarkReport(report) {
67
- const date = report.generatedAt.slice(0, 10);
68
- const lines = [
69
- "# Output Router Benchmark Report - Iteration 1",
70
- "",
71
- `Date: ${date}`,
72
- "",
73
- "## Scope",
74
- "",
75
- "Deterministic, CI-friendly tool benchmark for Freeflow Router retrieval behavior. The runner compares a native text-search proxy, a pre-hardening Freeflow-style proxy, and the improved Freeflow Router implementation. Optional external comparators are recorded as skipped rather than failed.",
76
- "",
77
- "Reduction percentages compare routed/context bytes and approximate tokens against the raw source or direct output for that mode. Negative reduction means structured routing overhead is larger than the tiny raw output; native exact-search proxies can still be smaller than the router for simple lookups.",
78
- "",
79
- "## Baseline Caveat",
80
- "",
81
- "The pre-hardening Freeflow mode is a deterministic proxy for the old line-scoring behavior, not a checkout of an older runtime. It is useful for stable regression pressure, not historical performance archaeology.",
82
- "",
83
- "## Command",
84
- "",
85
- "```sh",
86
- "npm run bench:router",
87
- "```",
88
- "",
89
- "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.",
90
- "",
91
- "## Summary",
92
- "",
93
- `- Iterations per mode: ${report.iterations}`,
94
- `- Fixtures: ${report.summary.fixtures}`,
95
- `- Improved Freeflow Router gated pass: ${report.summary.improved.passed}/${report.summary.fixtures}`,
96
- `- Native baseline proxy pass: ${report.summary.nativeBaseline.passed}/${report.summary.fixtures}`,
97
- `- Pre-hardening Freeflow proxy pass: ${report.summary.freeflowBaseline.passed}/${report.summary.fixtures}`,
98
- `- Generated false positives observed: ${report.summary.generatedFalsePositiveCount}/${report.summary.modeResults} mode results`,
99
- `- Improved generated false positives: ${report.summary.improved.generatedFalsePositiveCount}/${report.summary.fixtures}`,
100
- `- Improved weighted byte/token reduction: ${formatPercent(report.summary.improved.weightedByteReductionPercent)} / ${formatPercent(report.summary.improved.weightedTokenReductionPercent)} (${report.summary.improved.totalRawBytes}/${report.summary.improved.totalRawTokensApprox} raw to ${report.summary.improved.totalRoutedBytes}/${report.summary.improved.totalRoutedTokensApprox} routed)`,
101
- `- Improved average byte/token reduction: ${formatPercent(report.summary.improved.averageByteReductionPercent)} / ${formatPercent(report.summary.improved.averageTokenReductionPercent)}`,
102
- `- Improved median byte/token reduction: ${formatPercent(report.summary.improved.medianByteReductionPercent)} / ${formatPercent(report.summary.improved.medianTokenReductionPercent)}`,
103
- `- Improved path/span/excerpt checks: ${report.summary.improved.pathCorrect}/${report.summary.fixtures} path, ${report.summary.improved.spanCorrect}/${report.summary.fixtures} span, ${report.summary.improved.excerptComplete}/${report.summary.fixtures} excerpt`,
104
- `- Sandbox failure fixed: ${report.summary.sandboxFailureFixed ? "yes" : "no"}`,
105
- "",
106
- "## Results",
107
- "",
108
- "| fixture | mode | correctness | checks | path | lines | raw bytes/tokens | routed bytes/tokens | byte/token reduction | latency p50/p95 ms | recovery | notes |",
109
- "| --- | --- | --- | --- | --- | --- | ---: | ---: | ---: | ---: | --- | --- |",
110
- ];
111
- for (const fixture of report.fixtures) {
112
- for (const result of fixture.results) {
113
- const correctness = result.skipped ? "skipped" : result.correctness.passed ? "pass" : "fail";
114
- const recovery = result.recovery.status;
115
- const notes = result.notes.length ? result.notes.join("; ") : result.skipReason ?? "";
116
- const checks = formatCorrectnessChecks(result.correctness);
117
- lines.push(`| ${escapeTable(fixture.id)} | ${escapeTable(result.mode)} | ${correctness} | ${escapeTable(checks)} | ${escapeTable(result.actualPath ?? "-")} | ${escapeTable(result.actualLines ?? "-")} | ${result.rawBytes}/${result.rawTokensApprox} | ${result.routedBytes}/${result.routedTokensApprox} | ${formatPercent(result.byteReductionPercent)}/${formatPercent(result.tokenReductionPercent)} | ${result.latencyMs.p50.toFixed(2)}/${result.latencyMs.p95.toFixed(2)} | ${escapeTable(recovery)} | ${escapeTable(notes)} |`);
118
- }
119
- }
120
- lines.push("", "## Not Yet Measured", "", "- recall@3 / alternate candidates: not measured in this first deterministic runner.", "- explanation quality: not measured beyond route reason capture.", "- command-output parser benchmarks: deferred to the command benchmark track.", "", "## Skipped External Comparators", "");
121
- for (const tool of report.skippedExternalTools) {
122
- lines.push(`- ${tool.name}: ${tool.reason}`);
123
- }
124
- lines.push("", "## Regression Status", "", report.summary.improved.failed === 0
125
- ? "Improved Freeflow Router passed all gated benchmark fixtures."
126
- : `Improved Freeflow Router failed ${report.summary.improved.failed} gated benchmark fixture(s).`, "", "The generated-artifact decoy benchmark preserves the original Sandbox Permissions false-positive shape and records it as fixed when the improved router selects the docs target instead of `graphify-out/graph.html`.", "");
127
- return `${lines.join("\n")}`;
91
+ const date = report.generatedAt.slice(0, 10);
92
+ const lines = [
93
+ "# Output Router Benchmark Report - Iteration 1",
94
+ "",
95
+ `Date: ${date}`,
96
+ "",
97
+ "## Scope",
98
+ "",
99
+ "Deterministic, CI-friendly tool benchmark for Freeflow Router retrieval behavior. The runner compares a native text-search proxy, a pre-hardening Freeflow-style proxy, and the improved Freeflow Router implementation. Optional external comparators are recorded as skipped rather than failed.",
100
+ "",
101
+ "Reduction percentages compare routed/context bytes and approximate tokens against the raw source or direct output for that mode. Negative reduction means structured routing overhead is larger than the tiny raw output; native exact-search proxies can still be smaller than the router for simple lookups.",
102
+ "",
103
+ "## Baseline Caveat",
104
+ "",
105
+ "The pre-hardening Freeflow mode is a deterministic proxy for the old line-scoring behavior, not a checkout of an older runtime. It is useful for stable regression pressure, not historical performance archaeology.",
106
+ "",
107
+ "## Command",
108
+ "",
109
+ "```sh",
110
+ "npm run bench:router",
111
+ "```",
112
+ "",
113
+ "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.",
114
+ "",
115
+ "## Summary",
116
+ "",
117
+ `- Iterations per mode: ${report.iterations}`,
118
+ `- Fixtures: ${report.summary.fixtures}`,
119
+ `- Improved Freeflow Router gated pass: ${report.summary.improved.passed}/${report.summary.fixtures}`,
120
+ `- Native baseline proxy pass: ${report.summary.nativeBaseline.passed}/${report.summary.fixtures}`,
121
+ `- Pre-hardening Freeflow proxy pass: ${report.summary.freeflowBaseline.passed}/${report.summary.fixtures}`,
122
+ `- Generated false positives observed: ${report.summary.generatedFalsePositiveCount}/${report.summary.modeResults} mode results`,
123
+ `- Improved generated false positives: ${report.summary.improved.generatedFalsePositiveCount}/${report.summary.fixtures}`,
124
+ `- Improved weighted byte/token reduction: ${formatPercent(report.summary.improved.weightedByteReductionPercent)} / ${formatPercent(report.summary.improved.weightedTokenReductionPercent)} (${report.summary.improved.totalRawBytes}/${report.summary.improved.totalRawTokensApprox} raw to ${report.summary.improved.totalRoutedBytes}/${report.summary.improved.totalRoutedTokensApprox} routed)`,
125
+ `- Improved average byte/token reduction: ${formatPercent(report.summary.improved.averageByteReductionPercent)} / ${formatPercent(report.summary.improved.averageTokenReductionPercent)}`,
126
+ `- Improved median byte/token reduction: ${formatPercent(report.summary.improved.medianByteReductionPercent)} / ${formatPercent(report.summary.improved.medianTokenReductionPercent)}`,
127
+ `- Improved path/span/excerpt checks: ${report.summary.improved.pathCorrect}/${report.summary.fixtures} path, ${report.summary.improved.spanCorrect}/${report.summary.fixtures} span, ${report.summary.improved.excerptComplete}/${report.summary.fixtures} excerpt`,
128
+ `- Sandbox failure fixed: ${report.summary.sandboxFailureFixed ? "yes" : "no"}`,
129
+ "",
130
+ "## Results",
131
+ "",
132
+ "| fixture | mode | correctness | checks | path | lines | raw bytes/tokens | routed bytes/tokens | byte/token reduction | latency p50/p95 ms | recovery | notes |",
133
+ "| --- | --- | --- | --- | --- | --- | ---: | ---: | ---: | ---: | --- | --- |",
134
+ ];
135
+ for (const fixture of report.fixtures) {
136
+ for (const result of fixture.results) {
137
+ const correctness = result.skipped ? "skipped" : result.correctness.passed ? "pass" : "fail";
138
+ const recovery = result.recovery.status;
139
+ const notes = result.notes.length ? result.notes.join("; ") : (result.skipReason ?? "");
140
+ const checks = formatCorrectnessChecks(result.correctness);
141
+ lines.push(
142
+ `| ${escapeTable(fixture.id)} | ${escapeTable(result.mode)} | ${correctness} | ${escapeTable(checks)} | ${escapeTable(result.actualPath ?? "-")} | ${escapeTable(result.actualLines ?? "-")} | ${result.rawBytes}/${result.rawTokensApprox} | ${result.routedBytes}/${result.routedTokensApprox} | ${formatPercent(result.byteReductionPercent)}/${formatPercent(result.tokenReductionPercent)} | ${result.latencyMs.p50.toFixed(2)}/${result.latencyMs.p95.toFixed(2)} | ${escapeTable(recovery)} | ${escapeTable(notes)} |`,
143
+ );
144
+ }
145
+ }
146
+ lines.push(
147
+ "",
148
+ "## Not Yet Measured",
149
+ "",
150
+ "- recall@3 / alternate candidates: not measured in this first deterministic runner.",
151
+ "- explanation quality: not measured beyond route reason capture.",
152
+ "- command-output parser benchmarks: deferred to the command benchmark track.",
153
+ "",
154
+ "## Skipped External Comparators",
155
+ "",
156
+ );
157
+ for (const tool of report.skippedExternalTools) {
158
+ lines.push(`- ${tool.name}: ${tool.reason}`);
159
+ }
160
+ lines.push(
161
+ "",
162
+ "## Regression Status",
163
+ "",
164
+ report.summary.improved.failed === 0
165
+ ? "Improved Freeflow Router passed all gated benchmark fixtures."
166
+ : `Improved Freeflow Router failed ${report.summary.improved.failed} gated benchmark fixture(s).`,
167
+ "",
168
+ "The generated-artifact decoy benchmark preserves the original Sandbox Permissions false-positive shape and records it as fixed when the improved router selects the docs target instead of `graphify-out/graph.html`.",
169
+ "",
170
+ );
171
+ return `${lines.join("\n")}`;
128
172
  }
129
173
  export async function writeRouterBenchmarkReport(report, reportPath) {
130
- await mkdir(dirname(reportPath), { recursive: true });
131
- await writeFile(reportPath, renderRouterBenchmarkReport(report), "utf8");
174
+ await mkdir(dirname(reportPath), { recursive: true });
175
+ await writeFile(reportPath, renderRouterBenchmarkReport(report), "utf8");
132
176
  }
133
177
  export async function writeRouterBenchmarkJsonReport(report, reportPath) {
134
- await mkdir(dirname(reportPath), { recursive: true });
135
- await writeFile(reportPath, `${JSON.stringify(report, null, 2)}\n`, "utf8");
178
+ await mkdir(dirname(reportPath), { recursive: true });
179
+ await writeFile(reportPath, `${JSON.stringify(report, null, 2)}\n`, "utf8");
136
180
  }
137
181
  export async function writeRouterBenchmarkReports(report, markdownReportPath, options = {}) {
138
- return writeBenchmarkReportPair({
139
- report,
140
- markdownReportPath,
141
- jsonReportPath: options.jsonReportPath,
142
- renderMarkdown: renderRouterBenchmarkReport,
143
- });
182
+ return writeBenchmarkReportPair({
183
+ report,
184
+ markdownReportPath,
185
+ jsonReportPath: options.jsonReportPath,
186
+ renderMarkdown: renderRouterBenchmarkReport,
187
+ });
144
188
  }
145
189
  async function runFixtureMode(fixture, mode, iterations) {
146
- const latencies = [];
147
- let observation = null;
148
- for (let index = 0; index < iterations; index += 1) {
149
- const startedAt = performance.now();
150
- observation = await fixture.modes[mode]();
151
- latencies.push(performance.now() - startedAt);
152
- }
153
- if (!observation) {
154
- observation = skippedObservation("benchmark runner", "No observation was produced.");
155
- }
156
- const correctness = scoreCorrectness(fixture.expected, observation);
157
- const rawTokensApprox = approximateTokens(observation.rawBytes);
158
- const routedTokensApprox = approximateTokens(observation.routedBytes);
159
- return {
160
- mode,
161
- toolPathUsed: observation.toolPathUsed,
162
- skipped: observation.skipped ?? false,
163
- ...(observation.skipReason ? { skipReason: observation.skipReason } : {}),
164
- rawBytes: observation.rawBytes,
165
- rawTokensApprox,
166
- routedBytes: observation.routedBytes,
167
- routedTokensApprox,
168
- byteReductionPercent: reductionPercent(observation.rawBytes, observation.routedBytes),
169
- tokenReductionPercent: reductionPercent(rawTokensApprox, routedTokensApprox),
170
- latencyMs: latencySummary(latencies),
171
- ...(observation.actualPath ? { actualPath: observation.actualPath } : {}),
172
- ...(observation.actualLines ? { actualLines: observation.actualLines } : {}),
173
- correctness,
174
- recovery: observation.recovery,
175
- notes: observation.notes ?? [],
176
- };
190
+ const latencies = [];
191
+ let observation = null;
192
+ for (let index = 0; index < iterations; index += 1) {
193
+ const startedAt = performance.now();
194
+ observation = await fixture.modes[mode]();
195
+ latencies.push(performance.now() - startedAt);
196
+ }
197
+ if (!observation) {
198
+ observation = skippedObservation("benchmark runner", "No observation was produced.");
199
+ }
200
+ const correctness = scoreCorrectness(fixture.expected, observation);
201
+ const rawTokensApprox = approximateTokens(observation.rawBytes);
202
+ const routedTokensApprox = approximateTokens(observation.routedBytes);
203
+ return {
204
+ mode,
205
+ toolPathUsed: observation.toolPathUsed,
206
+ skipped: observation.skipped ?? false,
207
+ ...(observation.skipReason ? { skipReason: observation.skipReason } : {}),
208
+ rawBytes: observation.rawBytes,
209
+ rawTokensApprox,
210
+ routedBytes: observation.routedBytes,
211
+ routedTokensApprox,
212
+ byteReductionPercent: reductionPercent(observation.rawBytes, observation.routedBytes),
213
+ tokenReductionPercent: reductionPercent(rawTokensApprox, routedTokensApprox),
214
+ latencyMs: latencySummary(latencies),
215
+ ...(observation.actualPath ? { actualPath: observation.actualPath } : {}),
216
+ ...(observation.actualLines ? { actualLines: observation.actualLines } : {}),
217
+ correctness,
218
+ recovery: observation.recovery,
219
+ notes: observation.notes ?? [],
220
+ };
177
221
  }
178
222
  function summarizeReport(fixtures) {
179
- const nativeBaseline = summarizeMode(fixtures, "native-baseline-proxy");
180
- const freeflowBaseline = summarizeMode(fixtures, "pre-hardening-freeflow-proxy");
181
- const improved = summarizeMode(fixtures, "improved-freeflow-router");
182
- const generatedFalsePositiveCount = fixtures
183
- .flatMap((fixture) => fixture.results)
184
- .filter((result) => result.correctness.generatedFalsePositive).length;
185
- const sandboxFixture = fixtures.find((fixture) => fixture.id === "generated-artifact-decoy");
186
- const sandboxImproved = sandboxFixture?.results.find((result) => result.mode === "improved-freeflow-router");
187
- return {
188
- fixtures: fixtures.length,
189
- modeResults: fixtures.reduce((count, fixture) => count + fixture.results.length, 0),
190
- improved,
191
- nativeBaseline,
192
- freeflowBaseline,
193
- generatedFalsePositiveCount,
194
- sandboxFailureFixed: Boolean(sandboxImproved?.correctness.passed && !sandboxImproved.correctness.generatedFalsePositive),
195
- };
223
+ const nativeBaseline = summarizeMode(fixtures, "native-baseline-proxy");
224
+ const freeflowBaseline = summarizeMode(fixtures, "pre-hardening-freeflow-proxy");
225
+ const improved = summarizeMode(fixtures, "improved-freeflow-router");
226
+ const generatedFalsePositiveCount = fixtures
227
+ .flatMap((fixture) => fixture.results)
228
+ .filter((result) => result.correctness.generatedFalsePositive).length;
229
+ const sandboxFixture = fixtures.find((fixture) => fixture.id === "generated-artifact-decoy");
230
+ const sandboxImproved = sandboxFixture?.results.find((result) => result.mode === "improved-freeflow-router");
231
+ return {
232
+ fixtures: fixtures.length,
233
+ modeResults: fixtures.reduce((count, fixture) => count + fixture.results.length, 0),
234
+ improved,
235
+ nativeBaseline,
236
+ freeflowBaseline,
237
+ generatedFalsePositiveCount,
238
+ sandboxFailureFixed: Boolean(
239
+ sandboxImproved?.correctness.passed && !sandboxImproved.correctness.generatedFalsePositive,
240
+ ),
241
+ };
196
242
  }
197
243
  function summarizeMode(fixtures, mode) {
198
- const modeResults = fixtures
199
- .map((fixture) => fixture.results.find((candidate) => candidate.mode === mode))
200
- .filter((result) => Boolean(result));
201
- const measuredResults = modeResults.filter((result) => !result.skipped);
202
- const totalRawBytes = measuredResults.reduce((sum, result) => sum + result.rawBytes, 0);
203
- const totalRoutedBytes = measuredResults.reduce((sum, result) => sum + result.routedBytes, 0);
204
- const totalRawTokensApprox = measuredResults.reduce((sum, result) => sum + result.rawTokensApprox, 0);
205
- const totalRoutedTokensApprox = measuredResults.reduce((sum, result) => sum + result.routedTokensApprox, 0);
206
- return modeResults.reduce((summary, result) => {
207
- if (result.skipped) {
208
- summary.skipped += 1;
209
- }
210
- else if (isGatedPass(result, mode)) {
211
- summary.passed += 1;
212
- }
213
- else {
214
- summary.failed += 1;
215
- }
216
- if (result.correctness.pathCorrect) {
217
- summary.pathCorrect += 1;
218
- }
219
- if (result.correctness.spanCorrect) {
220
- summary.spanCorrect += 1;
221
- }
222
- if (result.correctness.excerptComplete) {
223
- summary.excerptComplete += 1;
224
- }
225
- if (result.correctness.generatedFalsePositive) {
226
- summary.generatedFalsePositiveCount += 1;
227
- }
228
- return summary;
229
- }, {
230
- passed: 0,
231
- failed: 0,
232
- skipped: 0,
233
- pathCorrect: 0,
234
- spanCorrect: 0,
235
- excerptComplete: 0,
236
- generatedFalsePositiveCount: 0,
237
- totalRawBytes,
238
- totalRoutedBytes,
239
- totalRawTokensApprox,
240
- totalRoutedTokensApprox,
241
- weightedByteReductionPercent: reductionPercent(totalRawBytes, totalRoutedBytes),
242
- weightedTokenReductionPercent: reductionPercent(totalRawTokensApprox, totalRoutedTokensApprox),
243
- averageByteReductionPercent: average(measuredResults.map((result) => result.byteReductionPercent)),
244
- medianByteReductionPercent: median(measuredResults.map((result) => result.byteReductionPercent)),
245
- averageTokenReductionPercent: average(measuredResults.map((result) => result.tokenReductionPercent)),
246
- medianTokenReductionPercent: median(measuredResults.map((result) => result.tokenReductionPercent)),
247
- });
244
+ const modeResults = fixtures
245
+ .map((fixture) => fixture.results.find((candidate) => candidate.mode === mode))
246
+ .filter((result) => Boolean(result));
247
+ const measuredResults = modeResults.filter((result) => !result.skipped);
248
+ const totalRawBytes = measuredResults.reduce((sum, result) => sum + result.rawBytes, 0);
249
+ const totalRoutedBytes = measuredResults.reduce((sum, result) => sum + result.routedBytes, 0);
250
+ const totalRawTokensApprox = measuredResults.reduce((sum, result) => sum + result.rawTokensApprox, 0);
251
+ const totalRoutedTokensApprox = measuredResults.reduce((sum, result) => sum + result.routedTokensApprox, 0);
252
+ return modeResults.reduce(
253
+ (summary, result) => {
254
+ if (result.skipped) {
255
+ summary.skipped += 1;
256
+ } else if (isGatedPass(result, mode)) {
257
+ summary.passed += 1;
258
+ } else {
259
+ summary.failed += 1;
260
+ }
261
+ if (result.correctness.pathCorrect) {
262
+ summary.pathCorrect += 1;
263
+ }
264
+ if (result.correctness.spanCorrect) {
265
+ summary.spanCorrect += 1;
266
+ }
267
+ if (result.correctness.excerptComplete) {
268
+ summary.excerptComplete += 1;
269
+ }
270
+ if (result.correctness.generatedFalsePositive) {
271
+ summary.generatedFalsePositiveCount += 1;
272
+ }
273
+ return summary;
274
+ },
275
+ {
276
+ passed: 0,
277
+ failed: 0,
278
+ skipped: 0,
279
+ pathCorrect: 0,
280
+ spanCorrect: 0,
281
+ excerptComplete: 0,
282
+ generatedFalsePositiveCount: 0,
283
+ totalRawBytes,
284
+ totalRoutedBytes,
285
+ totalRawTokensApprox,
286
+ totalRoutedTokensApprox,
287
+ weightedByteReductionPercent: reductionPercent(totalRawBytes, totalRoutedBytes),
288
+ weightedTokenReductionPercent: reductionPercent(totalRawTokensApprox, totalRoutedTokensApprox),
289
+ averageByteReductionPercent: average(measuredResults.map((result) => result.byteReductionPercent)),
290
+ medianByteReductionPercent: median(measuredResults.map((result) => result.byteReductionPercent)),
291
+ averageTokenReductionPercent: average(measuredResults.map((result) => result.tokenReductionPercent)),
292
+ medianTokenReductionPercent: median(measuredResults.map((result) => result.tokenReductionPercent)),
293
+ },
294
+ );
248
295
  }
249
296
  function isGatedPass(result, mode) {
250
- if (!result.correctness.passed) {
251
- return false;
252
- }
253
- if (mode !== "improved-freeflow-router") {
254
- return true;
255
- }
256
- return result.recovery.status === "passed" || result.recovery.status === "not-applicable";
297
+ if (!result.correctness.passed) {
298
+ return false;
299
+ }
300
+ if (mode !== "improved-freeflow-router") {
301
+ return true;
302
+ }
303
+ return result.recovery.status === "passed" || result.recovery.status === "not-applicable";
257
304
  }
258
305
  async function createBenchmarkFixtures() {
259
- const fixtures = await Promise.all([
260
- createExactCopiedTextFixture(),
261
- createMarkdownSectionFixture(),
262
- createGeneratedArtifactDecoyFixture(),
263
- createHugeSingleLineDecoyFixture(),
264
- createAmbiguousMultiFileFixture(),
265
- createVaultedOutputFixture(),
266
- createExpansionFixture(),
267
- ]);
268
- return fixtures;
306
+ const fixtures = await Promise.all([
307
+ createExactCopiedTextFixture(),
308
+ createMarkdownSectionFixture(),
309
+ createGeneratedArtifactDecoyFixture(),
310
+ createHugeSingleLineDecoyFixture(),
311
+ createAmbiguousMultiFileFixture(),
312
+ createVaultedOutputFixture(),
313
+ createExpansionFixture(),
314
+ ]);
315
+ return fixtures;
269
316
  }
270
317
  async function createExactCopiedTextFixture() {
271
- const repo = await createTempRepo({
272
- "target.md": [
273
- "# Target",
274
- "",
275
- "The output router vault preserves exact failure evidence for review.",
276
- ].join("\n"),
277
- "notes.md": "vault evidence evidence evidence without the exact sentence",
278
- });
279
- return repoQueryFixture(repo, {
280
- id: "exact-copied-text-block",
281
- title: "Exact copied text block",
282
- query: "output router vault preserves exact failure evidence",
283
- expected: {
284
- path: "target.md",
285
- lines: "3-3",
286
- requiredExcerpt: ["output router vault preserves exact failure evidence"],
287
- },
288
- });
318
+ const repo = await createTempRepo({
319
+ "target.md": ["# Target", "", "The output router vault preserves exact failure evidence for review."].join("\n"),
320
+ "notes.md": "vault evidence evidence evidence without the exact sentence",
321
+ });
322
+ return repoQueryFixture(repo, {
323
+ id: "exact-copied-text-block",
324
+ title: "Exact copied text block",
325
+ query: "output router vault preserves exact failure evidence",
326
+ expected: {
327
+ path: "target.md",
328
+ lines: "3-3",
329
+ requiredExcerpt: ["output router vault preserves exact failure evidence"],
330
+ },
331
+ });
289
332
  }
290
333
  async function createMarkdownSectionFixture() {
291
- const repo = await createTempRepo({
292
- "target.md": [
293
- "# Target",
294
- "",
295
- "## Adaptive Compression",
296
- "",
297
- "Vault recovery remains exact for raw output.",
298
- "Parser confidence labels routed diagnostics.",
299
- ].join("\n"),
300
- "decoy.md": "adaptive adaptive adaptive adaptive adaptive",
301
- });
302
- return repoQueryFixture(repo, {
303
- id: "markdown-heading-nearby-body",
304
- title: "Markdown heading plus nearby body text",
305
- query: "adaptive compression vault recovery parser confidence",
306
- expected: {
307
- path: "target.md",
308
- lines: "3-6",
309
- requiredExcerpt: ["Adaptive Compression", "Vault recovery", "Parser confidence"],
310
- },
311
- });
334
+ const repo = await createTempRepo({
335
+ "target.md": [
336
+ "# Target",
337
+ "",
338
+ "## Adaptive Compression",
339
+ "",
340
+ "Vault recovery remains exact for raw output.",
341
+ "Parser confidence labels routed diagnostics.",
342
+ ].join("\n"),
343
+ "decoy.md": "adaptive adaptive adaptive adaptive adaptive",
344
+ });
345
+ return repoQueryFixture(repo, {
346
+ id: "markdown-heading-nearby-body",
347
+ title: "Markdown heading plus nearby body text",
348
+ query: "adaptive compression vault recovery parser confidence",
349
+ expected: {
350
+ path: "target.md",
351
+ lines: "3-6",
352
+ requiredExcerpt: ["Adaptive Compression", "Vault recovery", "Parser confidence"],
353
+ },
354
+ });
312
355
  }
313
356
  async function createGeneratedArtifactDecoyFixture() {
314
- const repo = await createTempRepo({
315
- "docs/codex-cli-agent-harness/2026-06-12-pass-3-sandboxing-and-permissions.md": [
316
- "# Pass 3",
317
- "",
318
- "### Sandbox Permissions",
319
- "",
320
- "`SandboxPermissions` is a per-command request shape.",
321
- "",
322
- "Plain-language meaning:",
323
- "",
324
- "UseDefault: run with the turn's normal sandbox.",
325
- ].join("\n"),
326
- "graphify-out/graph.html": [
327
- "<html><body>",
328
- `${"Sandbox Permissions SandboxPermissions Plain-language meaning ".repeat(5000)}GENERATED_GRAPH_DECOY_SENTINEL`,
329
- "</body></html>",
330
- ].join("\n"),
331
- });
332
- return repoQueryFixture(repo, {
333
- id: "generated-artifact-decoy",
334
- title: "Generated-artifact decoy",
335
- query: "Sandbox Permissions SandboxPermissions Plain-language meaning",
336
- expected: {
337
- path: "docs/codex-cli-agent-harness/2026-06-12-pass-3-sandboxing-and-permissions.md",
338
- lines: "3-7",
339
- requiredExcerpt: ["SandboxPermissions", "Plain-language meaning"],
340
- },
341
- });
357
+ const repo = await createTempRepo({
358
+ "router/evals/fixtures/output-router-corpus/sandbox-permissions.md": [
359
+ "# Pass 3",
360
+ "",
361
+ "### Sandbox Permissions",
362
+ "",
363
+ "`SandboxPermissions` is a per-command request shape.",
364
+ "",
365
+ "Plain-language meaning:",
366
+ "",
367
+ "UseDefault: run with the turn's normal sandbox.",
368
+ ].join("\n"),
369
+ "graphify-out/graph.html": [
370
+ "<html><body>",
371
+ `${"Sandbox Permissions SandboxPermissions Plain-language meaning ".repeat(5000)}GENERATED_GRAPH_DECOY_SENTINEL`,
372
+ "</body></html>",
373
+ ].join("\n"),
374
+ });
375
+ return repoQueryFixture(repo, {
376
+ id: "generated-artifact-decoy",
377
+ title: "Generated-artifact decoy",
378
+ query: "Sandbox Permissions SandboxPermissions Plain-language meaning",
379
+ expected: {
380
+ path: "router/evals/fixtures/output-router-corpus/sandbox-permissions.md",
381
+ lines: "3-7",
382
+ requiredExcerpt: ["SandboxPermissions", "Plain-language meaning"],
383
+ },
384
+ });
342
385
  }
343
386
  async function createHugeSingleLineDecoyFixture() {
344
- const repo = await createTempRepo({
345
- "docs/router.md": [
346
- "# Router",
347
- "",
348
- "HUGE_MARKER belongs in bounded target evidence, not generated logs.",
349
- ].join("\n"),
350
- "debug.log": `${"HUGE_MARKER generated log noise ".repeat(6000)}HUGE_LOG_TAIL`,
351
- });
352
- return repoQueryFixture(repo, {
353
- id: "huge-single-line-decoy",
354
- title: "Huge single-line generated/log decoy",
355
- query: "HUGE_MARKER bounded target evidence",
356
- expected: {
357
- path: "docs/router.md",
358
- lines: "3-3",
359
- requiredExcerpt: ["HUGE_MARKER belongs in bounded target evidence"],
360
- },
361
- });
387
+ const repo = await createTempRepo({
388
+ "docs/router.md": ["# Router", "", "HUGE_MARKER belongs in bounded target evidence, not generated logs."].join(
389
+ "\n",
390
+ ),
391
+ "debug.log": `${"HUGE_MARKER generated log noise ".repeat(6000)}HUGE_LOG_TAIL`,
392
+ });
393
+ return repoQueryFixture(repo, {
394
+ id: "huge-single-line-decoy",
395
+ title: "Huge single-line generated/log decoy",
396
+ query: "HUGE_MARKER bounded target evidence",
397
+ expected: {
398
+ path: "docs/router.md",
399
+ lines: "3-3",
400
+ requiredExcerpt: ["HUGE_MARKER belongs in bounded target evidence"],
401
+ },
402
+ });
362
403
  }
363
404
  async function createAmbiguousMultiFileFixture() {
364
- const repo = await createTempRepo({
365
- "target.md": [
366
- "# Target",
367
- "",
368
- "Adaptive compression keeps vault recovery exact while parser confidence labels routed diagnostics.",
369
- ].join("\n"),
370
- "decoy.md": "adaptive ".repeat(900),
371
- "near-miss.md": "compression vault recovery without parser confidence",
372
- });
373
- return repoQueryFixture(repo, {
374
- id: "ambiguous-multi-file-query",
375
- title: "Ambiguous multi-file query",
376
- query: "adaptive compression vault recovery parser confidence",
377
- expected: {
378
- path: "target.md",
379
- lines: "3-3",
380
- requiredExcerpt: ["Adaptive compression", "vault recovery", "parser confidence"],
381
- },
382
- });
405
+ const repo = await createTempRepo({
406
+ "target.md": [
407
+ "# Target",
408
+ "",
409
+ "Adaptive compression keeps vault recovery exact while parser confidence labels routed diagnostics.",
410
+ ].join("\n"),
411
+ "decoy.md": "adaptive ".repeat(900),
412
+ "near-miss.md": "compression vault recovery without parser confidence",
413
+ });
414
+ return repoQueryFixture(repo, {
415
+ id: "ambiguous-multi-file-query",
416
+ title: "Ambiguous multi-file query",
417
+ query: "adaptive compression vault recovery parser confidence",
418
+ expected: {
419
+ path: "target.md",
420
+ lines: "3-3",
421
+ requiredExcerpt: ["Adaptive compression", "vault recovery", "parser confidence"],
422
+ },
423
+ });
383
424
  }
384
425
  async function createVaultedOutputFixture() {
385
- const vaultRoot = await createTempDir("freeflow-router-benchmark-vault-");
386
- const vault = createVault({ root: vaultRoot.path });
387
- const sessionId = "benchmark-vault-session";
388
- const stderr = [
389
- "setup ok",
390
- "ASSERTION_FAILED payments badge missing accessible label",
391
- "stack: renderSettingsBadge at settings.test.ts:42",
392
- ].join("\n");
393
- const record = await storeCommandOutput(vault, {
394
- sessionId,
395
- command: "npm test -- settings",
396
- stdout: "",
397
- stderr,
398
- executionStatus: "failed",
399
- exitCode: 1,
400
- createdAt: "2026-06-16T00:00:00.000Z",
401
- });
402
- const expected = {
403
- pathIncludes: `${record.outputId}:stderr`,
404
- lines: "2-2",
405
- requiredExcerpt: ["ASSERTION_FAILED", "payments badge"],
406
- };
407
- return {
408
- id: "vaulted-output-query",
409
- title: "Vaulted output query",
410
- kind: "vault-query",
411
- expected,
412
- modes: {
413
- "native-baseline-proxy": async () => directTextSearchObservation({
414
- toolPathUsed: "native-baseline-proxy: direct command output text search",
415
- text: stderr,
416
- path: `${record.outputId}:stderr`,
417
- query: "ASSERTION_FAILED payments badge",
418
- recovery: { status: "not-applicable", detail: "Native direct output has no Freeflow vault recovery contract." },
419
- }),
420
- "pre-hardening-freeflow-proxy": async () => directTextSearchObservation({
421
- toolPathUsed: "pre-hardening-freeflow-proxy: simple vaulted line scanner",
422
- text: stderr,
423
- path: `${record.outputId}:stderr`,
424
- query: "ASSERTION_FAILED payments badge",
425
- recovery: { status: "failed", detail: "Baseline proxy does not expose structured recovery metadata." },
426
- }),
427
- "improved-freeflow-router": async () => improvedRetrieveObservation(await freeflowSearch({
428
- action: "query",
429
- source: { kind: "vault", root: vaultRoot.path, sessionId, outputId: record.outputId, stream: "stderr" },
430
- query: "ASSERTION_FAILED payments badge",
431
- preserve: "important",
432
- }), "improved-freeflow-router: freeflow_search vault query", stderr, (result) => verifyVaultEvidenceRecovery(vaultRoot.path, sessionId, result)),
433
- },
434
- cleanup: vaultRoot.cleanup,
435
- };
426
+ const vaultRoot = await createTempDir("freeflow-router-benchmark-vault-");
427
+ const vault = createVault({ root: vaultRoot.path });
428
+ const sessionId = "benchmark-vault-session";
429
+ const stderr = [
430
+ "setup ok",
431
+ "ASSERTION_FAILED payments badge missing accessible label",
432
+ "stack: renderSettingsBadge at settings.test.ts:42",
433
+ ].join("\n");
434
+ const record = await storeCommandOutput(vault, {
435
+ sessionId,
436
+ command: "npm test -- settings",
437
+ stdout: "",
438
+ stderr,
439
+ executionStatus: "failed",
440
+ exitCode: 1,
441
+ createdAt: "2026-06-16T00:00:00.000Z",
442
+ });
443
+ const expected = {
444
+ pathIncludes: `${record.outputId}:stderr`,
445
+ lines: "2-2",
446
+ requiredExcerpt: ["ASSERTION_FAILED", "payments badge"],
447
+ };
448
+ return {
449
+ id: "vaulted-output-query",
450
+ title: "Vaulted output query",
451
+ kind: "vault-query",
452
+ expected,
453
+ modes: {
454
+ "native-baseline-proxy": async () =>
455
+ directTextSearchObservation({
456
+ toolPathUsed: "native-baseline-proxy: direct command output text search",
457
+ text: stderr,
458
+ path: `${record.outputId}:stderr`,
459
+ query: "ASSERTION_FAILED payments badge",
460
+ recovery: {
461
+ status: "not-applicable",
462
+ detail: "Native direct output has no Freeflow vault recovery contract.",
463
+ },
464
+ }),
465
+ "pre-hardening-freeflow-proxy": async () =>
466
+ directTextSearchObservation({
467
+ toolPathUsed: "pre-hardening-freeflow-proxy: simple vaulted line scanner",
468
+ text: stderr,
469
+ path: `${record.outputId}:stderr`,
470
+ query: "ASSERTION_FAILED payments badge",
471
+ recovery: { status: "failed", detail: "Baseline proxy does not expose structured recovery metadata." },
472
+ }),
473
+ "improved-freeflow-router": async () =>
474
+ improvedRetrieveObservation(
475
+ await freeflowSearch({
476
+ action: "query",
477
+ source: { kind: "vault", root: vaultRoot.path, sessionId, outputId: record.outputId, stream: "stderr" },
478
+ query: "ASSERTION_FAILED payments badge",
479
+ preserve: "important",
480
+ }),
481
+ "improved-freeflow-router: freeflow_search vault query",
482
+ stderr,
483
+ (result) => verifyVaultEvidenceRecovery(vaultRoot.path, sessionId, result),
484
+ ),
485
+ },
486
+ cleanup: vaultRoot.cleanup,
487
+ };
436
488
  }
437
489
  async function createExpansionFixture() {
438
- const body = [
439
- "# Expansion Target",
440
- "",
441
- "EXPANSION_START router evidence begins here.",
442
- ...Array.from({ length: 20 }, (_, index) => `expansion context line ${index + 1}`),
443
- "EXPANSION_END router evidence is complete here.",
444
- ];
445
- const repo = await createTempRepo({
446
- "target.md": body.join("\n"),
447
- "decoy.md": "EXPANSION_START ".repeat(200),
448
- });
449
- const query = "EXPANSION_START router evidence";
450
- const expected = {
451
- path: "target.md",
452
- lines: "1-24",
453
- requiredExcerpt: ["EXPANSION_START", "EXPANSION_END"],
454
- };
455
- return {
456
- id: "expand-narrow-evidence",
457
- title: "Expansion from narrow evidence to complete block",
458
- kind: "repo-expand",
459
- expected,
460
- modes: {
461
- "native-baseline-proxy": async () => directFileObservation(repo.path, "target.md", {
462
- toolPathUsed: "native-baseline-proxy: direct whole-file read",
463
- recovery: { status: "not-applicable", detail: "Native read is exact direct output, not routed recovery." },
464
- }),
465
- "pre-hardening-freeflow-proxy": async () => repoBaselineObservation(repo.path, query, {
466
- toolPathUsed: "pre-hardening-freeflow-proxy: narrow lexical line window without expansion",
467
- skipDirs: LEGACY_SKIP_DIRS,
468
- recovery: { status: "failed", detail: "Baseline proxy does not expose structured expansion recovery." },
469
- }),
470
- "improved-freeflow-router": async () => {
471
- const queryResult = await freeflowSearch({
472
- action: "query",
473
- source: { kind: "repo", root: repo.path },
474
- query,
475
- preserve: "important",
476
- });
477
- const evidence = queryResult.evidence?.[0];
478
- if (!evidence) {
479
- return improvedRetrieveObservation(queryResult, "improved-freeflow-router: freeflow_search query before expand", body.join("\n"), (result) => verifyRepoEvidenceRecovery(repo.path, result));
480
- }
481
- return improvedRetrieveObservation(await freeflowSearch({
482
- action: "expand",
483
- source: { kind: "repo", root: repo.path },
484
- evidence,
485
- expansion: "lines_30",
486
- preserve: "important",
487
- }), "improved-freeflow-router: freeflow_search expand lines_30", body.join("\n"), (result) => verifyRepoEvidenceRecovery(repo.path, result));
488
- },
489
- },
490
- cleanup: repo.cleanup,
491
- };
490
+ const body = [
491
+ "# Expansion Target",
492
+ "",
493
+ "EXPANSION_START router evidence begins here.",
494
+ ...Array.from({ length: 20 }, (_, index) => `expansion context line ${index + 1}`),
495
+ "EXPANSION_END router evidence is complete here.",
496
+ ];
497
+ const repo = await createTempRepo({
498
+ "target.md": body.join("\n"),
499
+ "decoy.md": "EXPANSION_START ".repeat(200),
500
+ });
501
+ const query = "EXPANSION_START router evidence";
502
+ const expected = {
503
+ path: "target.md",
504
+ lines: "1-24",
505
+ requiredExcerpt: ["EXPANSION_START", "EXPANSION_END"],
506
+ };
507
+ return {
508
+ id: "expand-narrow-evidence",
509
+ title: "Expansion from narrow evidence to complete block",
510
+ kind: "repo-expand",
511
+ expected,
512
+ modes: {
513
+ "native-baseline-proxy": async () =>
514
+ directFileObservation(repo.path, "target.md", {
515
+ toolPathUsed: "native-baseline-proxy: direct whole-file read",
516
+ recovery: { status: "not-applicable", detail: "Native read is exact direct output, not routed recovery." },
517
+ }),
518
+ "pre-hardening-freeflow-proxy": async () =>
519
+ repoBaselineObservation(repo.path, query, {
520
+ toolPathUsed: "pre-hardening-freeflow-proxy: narrow lexical line window without expansion",
521
+ skipDirs: LEGACY_SKIP_DIRS,
522
+ recovery: { status: "failed", detail: "Baseline proxy does not expose structured expansion recovery." },
523
+ }),
524
+ "improved-freeflow-router": async () => {
525
+ const queryResult = await freeflowSearch({
526
+ action: "query",
527
+ source: { kind: "repo", root: repo.path },
528
+ query,
529
+ preserve: "important",
530
+ });
531
+ const evidence = queryResult.evidence?.[0];
532
+ if (!evidence) {
533
+ return improvedRetrieveObservation(
534
+ queryResult,
535
+ "improved-freeflow-router: freeflow_search query before expand",
536
+ body.join("\n"),
537
+ (result) => verifyRepoEvidenceRecovery(repo.path, result),
538
+ );
539
+ }
540
+ return improvedRetrieveObservation(
541
+ await freeflowSearch({
542
+ action: "expand",
543
+ source: { kind: "repo", root: repo.path },
544
+ evidence,
545
+ expansion: "lines_30",
546
+ preserve: "important",
547
+ }),
548
+ "improved-freeflow-router: freeflow_search expand lines_30",
549
+ body.join("\n"),
550
+ (result) => verifyRepoEvidenceRecovery(repo.path, result),
551
+ );
552
+ },
553
+ },
554
+ cleanup: repo.cleanup,
555
+ };
492
556
  }
493
557
  function repoQueryFixture(repo, options) {
494
- return {
495
- id: options.id,
496
- title: options.title,
497
- kind: "repo-query",
498
- expected: options.expected,
499
- modes: {
500
- "native-baseline-proxy": async () => repoBaselineObservation(repo.path, options.query, {
501
- toolPathUsed: "native-baseline-proxy: recursive text scan (rg/read proxy)",
502
- skipDirs: new Set(),
503
- recovery: { status: "not-applicable", detail: "Native proxy returns direct text without Freeflow recovery metadata." },
504
- }),
505
- "pre-hardening-freeflow-proxy": async () => repoBaselineObservation(repo.path, options.query, {
506
- toolPathUsed: "pre-hardening-freeflow-proxy: legacy line scorer",
507
- skipDirs: LEGACY_SKIP_DIRS,
508
- recovery: { status: "failed", detail: "Baseline proxy does not expose structured recovery metadata." },
509
- }),
510
- "improved-freeflow-router": async () => improvedRetrieveObservation(await freeflowSearch({
511
- action: "query",
512
- source: { kind: "repo", root: repo.path },
513
- query: options.query,
514
- preserve: "important",
515
- }), "improved-freeflow-router: freeflow_search query", await readRepoBytes(repo.path), (result) => verifyRepoEvidenceRecovery(repo.path, result)),
516
- },
517
- cleanup: repo.cleanup,
518
- };
558
+ return {
559
+ id: options.id,
560
+ title: options.title,
561
+ kind: "repo-query",
562
+ expected: options.expected,
563
+ modes: {
564
+ "native-baseline-proxy": async () =>
565
+ repoBaselineObservation(repo.path, options.query, {
566
+ toolPathUsed: "native-baseline-proxy: recursive text scan (rg/read proxy)",
567
+ skipDirs: new Set(),
568
+ recovery: {
569
+ status: "not-applicable",
570
+ detail: "Native proxy returns direct text without Freeflow recovery metadata.",
571
+ },
572
+ }),
573
+ "pre-hardening-freeflow-proxy": async () =>
574
+ repoBaselineObservation(repo.path, options.query, {
575
+ toolPathUsed: "pre-hardening-freeflow-proxy: legacy line scorer",
576
+ skipDirs: LEGACY_SKIP_DIRS,
577
+ recovery: { status: "failed", detail: "Baseline proxy does not expose structured recovery metadata." },
578
+ }),
579
+ "improved-freeflow-router": async () =>
580
+ improvedRetrieveObservation(
581
+ await freeflowSearch({
582
+ action: "query",
583
+ source: { kind: "repo", root: repo.path },
584
+ query: options.query,
585
+ preserve: "important",
586
+ }),
587
+ "improved-freeflow-router: freeflow_search query",
588
+ await readRepoBytes(repo.path),
589
+ (result) => verifyRepoEvidenceRecovery(repo.path, result),
590
+ ),
591
+ },
592
+ cleanup: repo.cleanup,
593
+ };
519
594
  }
520
595
  async function repoBaselineObservation(root, query, options) {
521
- const files = await collectTextFiles(root, options.skipDirs);
522
- const hit = findBestLineHit(files, query);
523
- const rawBytes = byteLength(files.map((file) => file.text).join("\n"));
524
- if (!hit) {
525
- return {
526
- toolPathUsed: options.toolPathUsed,
527
- rawBytes,
528
- routedBytes: 0,
529
- excerpt: "",
530
- recovery: options.recovery,
531
- notes: ["no lexical hit"],
532
- };
533
- }
534
- const range = contextRange(hit.file.lines, hit.lineIndex);
535
- const excerpt = hit.file.lines.slice(range.start - 1, range.end).join("\n");
596
+ const files = await collectTextFiles(root, options.skipDirs);
597
+ const hit = findBestLineHit(files, query);
598
+ const rawBytes = byteLength(files.map((file) => file.text).join("\n"));
599
+ if (!hit) {
536
600
  return {
537
- toolPathUsed: options.toolPathUsed,
538
- rawBytes,
539
- routedBytes: byteLength(excerpt),
540
- actualPath: hit.file.path,
541
- actualLines: `${range.start}-${range.end}`,
542
- excerpt,
543
- recovery: options.recovery,
544
- notes: [`score=${hit.score.toFixed(2)}`],
601
+ toolPathUsed: options.toolPathUsed,
602
+ rawBytes,
603
+ routedBytes: 0,
604
+ excerpt: "",
605
+ recovery: options.recovery,
606
+ notes: ["no lexical hit"],
545
607
  };
608
+ }
609
+ const range = contextRange(hit.file.lines, hit.lineIndex);
610
+ const excerpt = hit.file.lines.slice(range.start - 1, range.end).join("\n");
611
+ return {
612
+ toolPathUsed: options.toolPathUsed,
613
+ rawBytes,
614
+ routedBytes: byteLength(excerpt),
615
+ actualPath: hit.file.path,
616
+ actualLines: `${range.start}-${range.end}`,
617
+ excerpt,
618
+ recovery: options.recovery,
619
+ notes: [`score=${hit.score.toFixed(2)}`],
620
+ };
546
621
  }
547
622
  async function directFileObservation(root, path, options) {
548
- const text = await readFile(resolve(root, path), "utf8");
549
- const lines = splitLines(text);
550
- return {
551
- toolPathUsed: options.toolPathUsed,
552
- rawBytes: byteLength(text),
553
- routedBytes: byteLength(text),
554
- actualPath: path,
555
- actualLines: `1-${lines.length}`,
556
- excerpt: text,
557
- recovery: options.recovery,
558
- };
623
+ const text = await readFile(resolve(root, path), "utf8");
624
+ const lines = splitLines(text);
625
+ return {
626
+ toolPathUsed: options.toolPathUsed,
627
+ rawBytes: byteLength(text),
628
+ routedBytes: byteLength(text),
629
+ actualPath: path,
630
+ actualLines: `1-${lines.length}`,
631
+ excerpt: text,
632
+ recovery: options.recovery,
633
+ };
559
634
  }
560
635
  async function directTextSearchObservation(options) {
561
- const file = { path: options.path, text: options.text, lines: splitLines(options.text) };
562
- const hit = findBestLineHit([file], options.query);
563
- if (!hit) {
564
- return {
565
- toolPathUsed: options.toolPathUsed,
566
- rawBytes: byteLength(options.text),
567
- routedBytes: 0,
568
- excerpt: "",
569
- recovery: options.recovery,
570
- notes: ["no lexical hit"],
571
- };
572
- }
573
- const range = contextRange(file.lines, hit.lineIndex);
574
- const excerpt = file.lines.slice(range.start - 1, range.end).join("\n");
636
+ const file = { path: options.path, text: options.text, lines: splitLines(options.text) };
637
+ const hit = findBestLineHit([file], options.query);
638
+ if (!hit) {
575
639
  return {
576
- toolPathUsed: options.toolPathUsed,
577
- rawBytes: byteLength(options.text),
578
- routedBytes: byteLength(excerpt),
579
- actualPath: options.path,
580
- actualLines: `${range.start}-${range.end}`,
581
- excerpt,
582
- recovery: options.recovery,
583
- notes: [`score=${hit.score.toFixed(2)}`],
640
+ toolPathUsed: options.toolPathUsed,
641
+ rawBytes: byteLength(options.text),
642
+ routedBytes: 0,
643
+ excerpt: "",
644
+ recovery: options.recovery,
645
+ notes: ["no lexical hit"],
584
646
  };
647
+ }
648
+ const range = contextRange(file.lines, hit.lineIndex);
649
+ const excerpt = file.lines.slice(range.start - 1, range.end).join("\n");
650
+ return {
651
+ toolPathUsed: options.toolPathUsed,
652
+ rawBytes: byteLength(options.text),
653
+ routedBytes: byteLength(excerpt),
654
+ actualPath: options.path,
655
+ actualLines: `${range.start}-${range.end}`,
656
+ excerpt,
657
+ recovery: options.recovery,
658
+ notes: [`score=${hit.score.toFixed(2)}`],
659
+ };
585
660
  }
586
661
  async function improvedRetrieveObservation(result, toolPathUsed, rawSource, verifyRecovery) {
587
- const evidence = result.evidence?.[0];
588
- const excerpt = result.evidence?.map((packet) => packet.excerpt).join("\n") ?? "";
589
- const recoveryGuidancePresent = Boolean(result.recovery?.how && (result.recovery.outputId || result.recovery.evidenceId || result.evidence?.some((packet) => packet.expandable)));
590
- const notes = [result.routing.reason];
591
- if (result.evidence && result.evidence.length > 1) {
592
- notes.push(`evidencePackets=${result.evidence.length}`);
593
- }
594
- let recovery = recoveryGuidancePresent
595
- ? { status: "passed", detail: result.recovery?.how ?? "Routed result exposes recovery guidance." }
596
- : { status: "failed", detail: "Routed result did not expose recovery guidance." };
597
- if (recoveryGuidancePresent && verifyRecovery) {
598
- recovery = await verifyRecovery(result);
599
- notes.push(`recovery=${recovery.status}: ${recovery.detail}`);
600
- }
601
- return {
602
- toolPathUsed,
603
- rawBytes: byteLength(rawSource),
604
- routedBytes: byteLength(JSON.stringify(result)),
605
- ...(evidence?.path ? { actualPath: evidence.path } : {}),
606
- ...(evidence?.lines ? { actualLines: evidence.lines } : {}),
607
- excerpt,
608
- recovery,
609
- notes,
610
- };
662
+ const evidence = result.evidence?.[0];
663
+ const excerpt = result.evidence?.map((packet) => packet.excerpt).join("\n") ?? "";
664
+ const recoveryGuidancePresent = Boolean(
665
+ result.recovery?.how &&
666
+ (result.recovery.outputId || result.recovery.evidenceId || result.evidence?.some((packet) => packet.expandable)),
667
+ );
668
+ const notes = [result.routing.reason];
669
+ if (result.evidence && result.evidence.length > 1) {
670
+ notes.push(`evidencePackets=${result.evidence.length}`);
671
+ }
672
+ let recovery = recoveryGuidancePresent
673
+ ? { status: "passed", detail: result.recovery?.how ?? "Routed result exposes recovery guidance." }
674
+ : { status: "failed", detail: "Routed result did not expose recovery guidance." };
675
+ if (recoveryGuidancePresent && verifyRecovery) {
676
+ recovery = await verifyRecovery(result);
677
+ notes.push(`recovery=${recovery.status}: ${recovery.detail}`);
678
+ }
679
+ return {
680
+ toolPathUsed,
681
+ rawBytes: byteLength(rawSource),
682
+ routedBytes: byteLength(JSON.stringify(result)),
683
+ ...(evidence?.path ? { actualPath: evidence.path } : {}),
684
+ ...(evidence?.lines ? { actualLines: evidence.lines } : {}),
685
+ excerpt,
686
+ recovery,
687
+ notes,
688
+ };
611
689
  }
612
690
  async function verifyRepoEvidenceRecovery(root, result) {
613
- const evidence = result.evidence?.[0];
614
- if (!evidence?.path || !evidence.lines) {
615
- return { status: "failed", detail: "No repo evidence path/lines available for recovery verification." };
616
- }
617
- const range = parseRange(evidence.lines);
618
- if (!range) {
619
- return { status: "failed", detail: `Unsupported repo evidence range ${evidence.lines}.` };
620
- }
621
- const recovered = await freeflowSearch({
622
- action: "retrieve",
623
- source: { kind: "repo", root, path: evidence.path },
624
- lineRange: range,
625
- preserve: "full",
626
- });
627
- return verifyRecoveredEvidence(recovered, evidence, `Verified repo retrieve ${evidence.path}:${evidence.lines}.`);
691
+ const evidence = result.evidence?.[0];
692
+ if (!evidence?.path || !evidence.lines) {
693
+ return { status: "failed", detail: "No repo evidence path/lines available for recovery verification." };
694
+ }
695
+ const range = parseRange(evidence.lines);
696
+ if (!range) {
697
+ return { status: "failed", detail: `Unsupported repo evidence range ${evidence.lines}.` };
698
+ }
699
+ const recovered = await freeflowSearch({
700
+ action: "retrieve",
701
+ source: { kind: "repo", root, path: evidence.path },
702
+ lineRange: range,
703
+ preserve: "full",
704
+ });
705
+ return verifyRecoveredEvidence(recovered, evidence, `Verified repo retrieve ${evidence.path}:${evidence.lines}.`);
628
706
  }
629
707
  async function verifyVaultEvidenceRecovery(vaultRoot, sessionId, result) {
630
- const evidence = result.evidence?.[0];
631
- if (!evidence?.lines || evidence.source.kind !== "vault") {
632
- return { status: "failed", detail: "No vault evidence outputId/lines available for recovery verification." };
633
- }
634
- const range = parseRange(evidence.lines);
635
- if (!range) {
636
- return { status: "failed", detail: `Unsupported vault evidence range ${evidence.lines}.` };
637
- }
638
- const recovered = await freeflowSearch({
639
- action: "retrieve",
640
- source: {
641
- kind: "vault",
642
- root: vaultRoot,
643
- sessionId,
644
- outputId: evidence.source.outputId,
645
- stream: evidence.source.stream ?? "combined",
646
- },
647
- lineRange: range,
648
- preserve: "full",
649
- });
650
- return verifyRecoveredEvidence(recovered, evidence, `Verified vault retrieve ${evidence.source.outputId}:${evidence.source.stream ?? "combined"}:${evidence.lines}.`);
708
+ const evidence = result.evidence?.[0];
709
+ if (!evidence?.lines || evidence.source.kind !== "vault") {
710
+ return { status: "failed", detail: "No vault evidence outputId/lines available for recovery verification." };
711
+ }
712
+ const range = parseRange(evidence.lines);
713
+ if (!range) {
714
+ return { status: "failed", detail: `Unsupported vault evidence range ${evidence.lines}.` };
715
+ }
716
+ const recovered = await freeflowSearch({
717
+ action: "retrieve",
718
+ source: {
719
+ kind: "vault",
720
+ root: vaultRoot,
721
+ sessionId,
722
+ outputId: evidence.source.outputId,
723
+ stream: evidence.source.stream ?? "combined",
724
+ },
725
+ lineRange: range,
726
+ preserve: "full",
727
+ });
728
+ return verifyRecoveredEvidence(
729
+ recovered,
730
+ evidence,
731
+ `Verified vault retrieve ${evidence.source.outputId}:${evidence.source.stream ?? "combined"}:${evidence.lines}.`,
732
+ );
651
733
  }
652
734
  function verifyRecoveredEvidence(recovered, originalEvidence, successDetail) {
653
- const recoveredExcerpt = recovered.evidence?.map((packet) => packet.excerpt).join("\n") ?? "";
654
- const anchor = firstRecoveryAnchor(originalEvidence.excerpt);
655
- if (recovered.toolStatus !== "ok" || recovered.evidence?.length !== 1) {
656
- return { status: "failed", detail: "Recovery retrieve did not return one ok evidence packet." };
657
- }
658
- if (anchor && !recoveredExcerpt.includes(anchor)) {
659
- return { status: "failed", detail: "Recovery retrieve did not include the original evidence anchor." };
660
- }
661
- return { status: "passed", detail: successDetail };
735
+ const recoveredExcerpt = recovered.evidence?.map((packet) => packet.excerpt).join("\n") ?? "";
736
+ const anchor = firstRecoveryAnchor(originalEvidence.excerpt);
737
+ if (recovered.toolStatus !== "ok" || recovered.evidence?.length !== 1) {
738
+ return { status: "failed", detail: "Recovery retrieve did not return one ok evidence packet." };
739
+ }
740
+ if (anchor && !recoveredExcerpt.includes(anchor)) {
741
+ return { status: "failed", detail: "Recovery retrieve did not include the original evidence anchor." };
742
+ }
743
+ return { status: "passed", detail: successDetail };
662
744
  }
663
745
  function firstRecoveryAnchor(excerpt) {
664
- return splitLines(excerpt)
665
- .map((line) => line.trim())
666
- .find((line) => line.length > 0)
667
- ?.slice(0, 80) ?? "";
746
+ return (
747
+ splitLines(excerpt)
748
+ .map((line) => line.trim())
749
+ .find((line) => line.length > 0)
750
+ ?.slice(0, 80) ?? ""
751
+ );
668
752
  }
669
753
  function scoreCorrectness(expected, observation) {
670
- if (observation.skipped) {
671
- return {
672
- passed: false,
673
- pathCorrect: false,
674
- spanCorrect: false,
675
- excerptComplete: false,
676
- generatedFalsePositive: false,
677
- };
678
- }
679
- const pathCorrect = expected.path
680
- ? observation.actualPath === expected.path
681
- : expected.pathIncludes
682
- ? Boolean(observation.actualPath?.includes(expected.pathIncludes))
683
- : true;
684
- const spanCorrect = expected.lines
685
- ? Boolean(observation.actualLines && rangesOverlap(expected.lines, observation.actualLines))
686
- : true;
687
- const excerptComplete = (expected.requiredExcerpt ?? []).every((snippet) => observation.excerpt.toLowerCase().includes(snippet.toLowerCase()));
688
- const generatedFalsePositive = observation.actualPath ? isGeneratedBenchmarkPath(observation.actualPath) : false;
689
- const passed = pathCorrect && spanCorrect && excerptComplete && !generatedFalsePositive;
754
+ if (observation.skipped) {
690
755
  return {
691
- passed,
692
- pathCorrect,
693
- spanCorrect,
694
- excerptComplete,
695
- generatedFalsePositive,
756
+ passed: false,
757
+ pathCorrect: false,
758
+ spanCorrect: false,
759
+ excerptComplete: false,
760
+ generatedFalsePositive: false,
696
761
  };
762
+ }
763
+ const pathCorrect = expected.path
764
+ ? observation.actualPath === expected.path
765
+ : expected.pathIncludes
766
+ ? Boolean(observation.actualPath?.includes(expected.pathIncludes))
767
+ : true;
768
+ const spanCorrect = expected.lines
769
+ ? Boolean(observation.actualLines && rangesOverlap(expected.lines, observation.actualLines))
770
+ : true;
771
+ const excerptComplete = (expected.requiredExcerpt ?? []).every((snippet) =>
772
+ observation.excerpt.toLowerCase().includes(snippet.toLowerCase()),
773
+ );
774
+ const generatedFalsePositive = observation.actualPath ? isGeneratedBenchmarkPath(observation.actualPath) : false;
775
+ const passed = pathCorrect && spanCorrect && excerptComplete && !generatedFalsePositive;
776
+ return {
777
+ passed,
778
+ pathCorrect,
779
+ spanCorrect,
780
+ excerptComplete,
781
+ generatedFalsePositive,
782
+ };
697
783
  }
698
784
  async function createTempRepo(files) {
699
- const root = await createTempDir("freeflow-router-benchmark-repo-");
700
- for (const [path, text] of Object.entries(files)) {
701
- const absolutePath = resolve(root.path, path);
702
- await mkdir(dirname(absolutePath), { recursive: true });
703
- await writeFile(absolutePath, text, "utf8");
704
- }
705
- return root;
785
+ const root = await createTempDir("freeflow-router-benchmark-repo-");
786
+ for (const [path, text] of Object.entries(files)) {
787
+ const absolutePath = resolve(root.path, path);
788
+ await mkdir(dirname(absolutePath), { recursive: true });
789
+ await writeFile(absolutePath, text, "utf8");
790
+ }
791
+ return root;
706
792
  }
707
793
  async function createTempDir(prefix) {
708
- const path = await mkdtemp(resolve(tmpdir(), prefix));
709
- return {
710
- path,
711
- cleanup: async () => {
712
- await rm(path, { recursive: true, force: true });
713
- },
714
- };
794
+ const path = await mkdtemp(resolve(tmpdir(), prefix));
795
+ return {
796
+ path,
797
+ cleanup: async () => {
798
+ await rm(path, { recursive: true, force: true });
799
+ },
800
+ };
715
801
  }
716
802
  async function collectTextFiles(root, skipDirs) {
717
- const files = [];
718
- await collectTextFilesInto(resolve(root), resolve(root), skipDirs, files);
719
- return files.sort((a, b) => a.path.localeCompare(b.path));
803
+ const files = [];
804
+ await collectTextFilesInto(resolve(root), resolve(root), skipDirs, files);
805
+ return files.sort((a, b) => a.path.localeCompare(b.path));
720
806
  }
721
807
  async function collectTextFilesInto(root, currentPath, skipDirs, files) {
722
- const currentStat = await stat(currentPath);
723
- const name = currentPath.split(/[\\/]+/).at(-1) ?? currentPath;
724
- if (currentStat.isDirectory()) {
725
- if (currentPath !== root && skipDirs.has(name)) {
726
- return;
727
- }
728
- const entries = await readdir(currentPath, { withFileTypes: true });
729
- for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
730
- await collectTextFilesInto(root, resolve(currentPath, entry.name), skipDirs, files);
731
- }
732
- return;
733
- }
734
- if (!currentStat.isFile()) {
735
- return;
736
- }
737
- const text = await readFile(currentPath, "utf8");
738
- if (text.includes("\0")) {
739
- return;
740
- }
741
- files.push({
742
- path: normalizeRelativePath(relative(root, currentPath)),
743
- text,
744
- lines: splitLines(text),
745
- });
808
+ const currentStat = await stat(currentPath);
809
+ const name = currentPath.split(/[\\/]+/).at(-1) ?? currentPath;
810
+ if (currentStat.isDirectory()) {
811
+ if (currentPath !== root && skipDirs.has(name)) {
812
+ return;
813
+ }
814
+ const entries = await readdir(currentPath, { withFileTypes: true });
815
+ for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
816
+ await collectTextFilesInto(root, resolve(currentPath, entry.name), skipDirs, files);
817
+ }
818
+ return;
819
+ }
820
+ if (!currentStat.isFile()) {
821
+ return;
822
+ }
823
+ const text = await readFile(currentPath, "utf8");
824
+ if (text.includes("\0")) {
825
+ return;
826
+ }
827
+ files.push({
828
+ path: normalizeRelativePath(relative(root, currentPath)),
829
+ text,
830
+ lines: splitLines(text),
831
+ });
746
832
  }
747
833
  function findBestLineHit(files, query) {
748
- const tokens = tokenize(query);
749
- let best = null;
750
- for (const file of files) {
751
- const pathScore = scoreText(file.path, tokens);
752
- file.lines.forEach((line, lineIndex) => {
753
- const lineScore = scoreText(line, tokens);
754
- const headingBonus = line.trimStart().startsWith("#") ? 2 : 0;
755
- const score = lineScore * 4 + pathScore + headingBonus;
756
- if (score <= 0) {
757
- return;
758
- }
759
- if (!best || score > best.score) {
760
- best = { file, lineIndex, score };
761
- }
762
- });
763
- }
764
- return best;
834
+ const tokens = tokenize(query);
835
+ let best = null;
836
+ for (const file of files) {
837
+ const pathScore = scoreText(file.path, tokens);
838
+ file.lines.forEach((line, lineIndex) => {
839
+ const lineScore = scoreText(line, tokens);
840
+ const headingBonus = line.trimStart().startsWith("#") ? 2 : 0;
841
+ const score = lineScore * 4 + pathScore + headingBonus;
842
+ if (score <= 0) {
843
+ return;
844
+ }
845
+ if (!best || score > best.score) {
846
+ best = { file, lineIndex, score };
847
+ }
848
+ });
849
+ }
850
+ return best;
765
851
  }
766
852
  function contextRange(lines, lineIndex) {
767
- return {
768
- start: Math.max(1, lineIndex + 1 - DEFAULT_CONTEXT_LINES),
769
- end: Math.min(lines.length, lineIndex + 1 + DEFAULT_CONTEXT_LINES),
770
- };
853
+ return {
854
+ start: Math.max(1, lineIndex + 1 - DEFAULT_CONTEXT_LINES),
855
+ end: Math.min(lines.length, lineIndex + 1 + DEFAULT_CONTEXT_LINES),
856
+ };
771
857
  }
772
858
  async function readRepoBytes(root) {
773
- const files = await collectTextFiles(root, new Set());
774
- return files.map((file) => file.text).join("\n");
859
+ const files = await collectTextFiles(root, new Set());
860
+ return files.map((file) => file.text).join("\n");
775
861
  }
776
862
  function rangesOverlap(left, right) {
777
- const leftRange = parseRange(left);
778
- const rightRange = parseRange(right);
779
- if (!leftRange || !rightRange) {
780
- return false;
781
- }
782
- return leftRange.start <= rightRange.end && rightRange.start <= leftRange.end;
863
+ const leftRange = parseRange(left);
864
+ const rightRange = parseRange(right);
865
+ if (!leftRange || !rightRange) {
866
+ return false;
867
+ }
868
+ return leftRange.start <= rightRange.end && rightRange.start <= leftRange.end;
783
869
  }
784
870
  function parseRange(range) {
785
- const match = /^(\d+)-(\d+)$/.exec(range);
786
- if (!match) {
787
- return null;
788
- }
789
- const start = Number(match[1]);
790
- const end = Number(match[2]);
791
- return Number.isInteger(start) && Number.isInteger(end) ? { start, end } : null;
871
+ const match = /^(\d+)-(\d+)$/.exec(range);
872
+ if (!match) {
873
+ return null;
874
+ }
875
+ const start = Number(match[1]);
876
+ const end = Number(match[2]);
877
+ return Number.isInteger(start) && Number.isInteger(end) ? { start, end } : null;
792
878
  }
793
879
  function isGeneratedBenchmarkPath(path) {
794
- const segments = path.split(/[\\/]+/);
795
- if (segments.some((segment) => GENERATED_DIRS.has(segment))) {
796
- return true;
797
- }
798
- const name = segments.at(-1)?.toLowerCase() ?? path.toLowerCase();
799
- return name.endsWith(".log") || name.endsWith(".map") || name.endsWith(".min.js") || name.endsWith(".min.css") || name.includes(".bundle.");
880
+ const segments = path.split(/[\\/]+/);
881
+ if (segments.some((segment) => GENERATED_DIRS.has(segment))) {
882
+ return true;
883
+ }
884
+ const name = segments.at(-1)?.toLowerCase() ?? path.toLowerCase();
885
+ return (
886
+ name.endsWith(".log") ||
887
+ name.endsWith(".map") ||
888
+ name.endsWith(".min.js") ||
889
+ name.endsWith(".min.css") ||
890
+ name.includes(".bundle.")
891
+ );
800
892
  }
801
893
  function scoreText(text, tokens) {
802
- const lower = text.toLowerCase();
803
- return tokens.reduce((score, token) => score + countOccurrences(lower, token), 0);
894
+ const lower = text.toLowerCase();
895
+ return tokens.reduce((score, token) => score + countOccurrences(lower, token), 0);
804
896
  }
805
897
  function countOccurrences(text, token) {
806
- let count = 0;
807
- let index = text.indexOf(token);
808
- while (index !== -1) {
809
- count += 1;
810
- index = text.indexOf(token, index + token.length);
811
- }
812
- return count;
898
+ let count = 0;
899
+ let index = text.indexOf(token);
900
+ while (index !== -1) {
901
+ count += 1;
902
+ index = text.indexOf(token, index + token.length);
903
+ }
904
+ return count;
813
905
  }
814
906
  function tokenize(query) {
815
- return query
816
- .toLowerCase()
817
- .split(/[^a-z0-9_./-]+/)
818
- .map((token) => token.trim())
819
- .filter((token) => token.length >= 2);
907
+ return query
908
+ .toLowerCase()
909
+ .split(/[^a-z0-9_./-]+/)
910
+ .map((token) => token.trim())
911
+ .filter((token) => token.length >= 2);
820
912
  }
821
913
  function splitLines(text) {
822
- if (text.length === 0) {
823
- return [];
824
- }
825
- return text.replace(/\r\n/g, "\n").replace(/\r/g, "\n").split("\n");
914
+ if (text.length === 0) {
915
+ return [];
916
+ }
917
+ return text.replace(/\r\n/g, "\n").replace(/\r/g, "\n").split("\n");
826
918
  }
827
919
  function byteLength(value) {
828
- return Buffer.byteLength(value, "utf8");
920
+ return Buffer.byteLength(value, "utf8");
829
921
  }
830
922
  function formatCorrectnessChecks(correctness) {
831
- return [
832
- `path ${correctness.pathCorrect ? "✓" : "✗"}`,
833
- `span ${correctness.spanCorrect ? "✓" : "✗"}`,
834
- `excerpt ${correctness.excerptComplete ? "✓" : "✗"}`,
835
- `gen-fp ${correctness.generatedFalsePositive ? "✗" : "✓"}`,
836
- ].join(" ");
923
+ return [
924
+ `path ${correctness.pathCorrect ? "✓" : "✗"}`,
925
+ `span ${correctness.spanCorrect ? "✓" : "✗"}`,
926
+ `excerpt ${correctness.excerptComplete ? "✓" : "✗"}`,
927
+ `gen-fp ${correctness.generatedFalsePositive ? "✗" : "✓"}`,
928
+ ].join(" ");
837
929
  }
838
930
  function benchmarkModes() {
839
- return ["native-baseline-proxy", "pre-hardening-freeflow-proxy", "improved-freeflow-router"];
931
+ return ["native-baseline-proxy", "pre-hardening-freeflow-proxy", "improved-freeflow-router"];
840
932
  }
841
933
  function skippedObservation(toolPathUsed, reason) {
842
- return {
843
- toolPathUsed,
844
- rawBytes: 0,
845
- routedBytes: 0,
846
- excerpt: "",
847
- recovery: { status: "skipped", detail: reason },
848
- skipped: true,
849
- skipReason: reason,
850
- };
934
+ return {
935
+ toolPathUsed,
936
+ rawBytes: 0,
937
+ routedBytes: 0,
938
+ excerpt: "",
939
+ recovery: { status: "skipped", detail: reason },
940
+ skipped: true,
941
+ skipReason: reason,
942
+ };
851
943
  }
852
944
  function normalizeRelativePath(path) {
853
- return path.split(/[/\\]+/).filter(Boolean).join("/");
945
+ return path
946
+ .split(/[/\\]+/)
947
+ .filter(Boolean)
948
+ .join("/");
854
949
  }
855
950
  function defaultReportPath() {
856
- return resolve(process.cwd(), "evals/reports/runtime/output-router-benchmark-1-report.md");
951
+ return resolve(process.cwd(), "router/evals/reports/output-router-benchmark-1-report.md");
857
952
  }
858
953
  async function runCli() {
859
- const { iterations, reportPath, jsonReportPath } = parseBenchmarkCliArgs(process.argv.slice(2), { reportPath: defaultReportPath() });
860
- const options = {};
861
- if (iterations !== undefined) {
862
- options.iterations = iterations;
863
- }
864
- const report = await runRouterBenchmarks(options);
865
- const reports = await writeRouterBenchmarkReports(report, reportPath, {
866
- jsonReportPath: jsonReportPath === undefined ? defaultJsonRunReportPath(reportPath) : jsonReportPath,
867
- });
868
- const shortId = createHash("sha256").update(JSON.stringify(report.summary)).digest("hex").slice(0, 8);
869
- console.log(`Freeflow router benchmark ${shortId}: improved ${report.summary.improved.passed}/${report.summary.fixtures} pass`);
870
- console.log(`Markdown report: ${reports.markdown}`);
871
- if (reports.json) {
872
- console.log(`JSON run data: ${reports.json}`);
873
- }
874
- if (report.summary.improved.failed > 0) {
875
- process.exitCode = 1;
876
- }
954
+ const { iterations, reportPath, jsonReportPath } = parseBenchmarkCliArgs(process.argv.slice(2), {
955
+ reportPath: defaultReportPath(),
956
+ });
957
+ const options = {};
958
+ if (iterations !== undefined) {
959
+ options.iterations = iterations;
960
+ }
961
+ const report = await runRouterBenchmarks(options);
962
+ const reports = await writeRouterBenchmarkReports(report, reportPath, {
963
+ jsonReportPath: jsonReportPath === undefined ? defaultJsonRunReportPath(reportPath) : jsonReportPath,
964
+ });
965
+ const shortId = createHash("sha256").update(JSON.stringify(report.summary)).digest("hex").slice(0, 8);
966
+ console.log(
967
+ `Freeflow router benchmark ${shortId}: improved ${report.summary.improved.passed}/${report.summary.fixtures} pass`,
968
+ );
969
+ console.log(`Markdown report: ${reports.markdown}`);
970
+ if (reports.json) {
971
+ console.log(`JSON run data: ${reports.json}`);
972
+ }
973
+ if (report.summary.improved.failed > 0) {
974
+ process.exitCode = 1;
975
+ }
877
976
  }
878
977
  if (process.argv[1] && fileURLToPath(import.meta.url) === resolve(process.argv[1])) {
879
- await runCli();
978
+ await runCli();
880
979
  }