@claude-flow/cli 3.38.12 → 3.38.13

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 (140) hide show
  1. package/.claude/.proven-config-version +1 -0
  2. package/.claude/helpers/.helpers-version +1 -1
  3. package/.claude/helpers/helpers.manifest.json +2 -2
  4. package/.claude/helpers/statusline.cjs +0 -0
  5. package/.claude/proven-config.json +42 -0
  6. package/catalog-manifest.json +4 -4
  7. package/dist/src/mcp-tools/hooks-tools.js +6 -1
  8. package/dist/src/ruvector/lattice-wasm.d.ts +14 -0
  9. package/dist/src/ruvector/lattice-wasm.js +144 -0
  10. package/dist/src/services/flywheel-receipt.d.ts +10 -0
  11. package/dist/src/services/flywheel-receipt.js +82 -7
  12. package/dist/src/services/flywheel-transaction.js +10 -1
  13. package/node_modules/@claude-flow/codex/dist/cli.js +0 -0
  14. package/node_modules/@claude-flow/plugin-agent-federation/dist/bin.js +0 -0
  15. package/node_modules/@claude-flow/security/dist/input-validator.d.ts +6 -6
  16. package/package.json +1 -1
  17. package/plugins/ruflo-metaharness/.claude-flow/daemon-state.json +178 -0
  18. package/plugins/ruflo-metaharness/.claude-flow/daemon.pid +1 -0
  19. package/plugins/ruflo-metaharness/.claude-flow/data/pending-insights.jsonl +5 -0
  20. package/plugins/ruflo-metaharness/.claude-flow/logs/daemon.log +269 -0
  21. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/audit_1783604774864_ozbujc_prompt.log +19 -0
  22. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/audit_1783604774864_ozbujc_result.log +108 -0
  23. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/audit_1783605513587_ulvmpb_prompt.log +19 -0
  24. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/audit_1783605513587_ulvmpb_result.log +209 -0
  25. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/audit_1783606368867_ahysui_prompt.log +19 -0
  26. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/audit_1783606368867_ahysui_result.log +192 -0
  27. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/audit_1783607120257_lh05rb_prompt.log +19 -0
  28. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/audit_1783607120257_lh05rb_result.log +13 -0
  29. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/audit_1783608020362_j3096j_prompt.log +19 -0
  30. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/audit_1783608020362_j3096j_result.log +120 -0
  31. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/audit_1783608776347_261b61_prompt.log +19 -0
  32. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/audit_1783608776347_261b61_result.log +85 -0
  33. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/audit_1783609621359_s5i6ye_prompt.log +19 -0
  34. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/audit_1783609621359_s5i6ye_result.log +13 -0
  35. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/audit_1783610087998_qihv9v_prompt.log +19 -0
  36. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/audit_1783610087998_qihv9v_result.log +17 -0
  37. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/audit_1783610773920_qlzmxo_prompt.log +19 -0
  38. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/audit_1783610773920_qlzmxo_result.log +17 -0
  39. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/audit_1783611376090_xpqf1z_prompt.log +19 -0
  40. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/audit_1783611376090_xpqf1z_result.log +16 -0
  41. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/audit_1783612097184_9rqfor_prompt.log +19 -0
  42. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/audit_1783612097184_9rqfor_result.log +138 -0
  43. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/audit_1783612811574_4u602j_prompt.log +19 -0
  44. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/audit_1783612811574_4u602j_result.log +16 -0
  45. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/audit_1783613750487_a46ttn_prompt.log +19 -0
  46. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/audit_1783613750487_a46ttn_result.log +107 -0
  47. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/audit_1783614289360_figwc0_prompt.log +19 -0
  48. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/audit_1783614289360_figwc0_result.log +200 -0
  49. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/audit_1783615067640_l7tm6a_prompt.log +19 -0
  50. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/audit_1783615067640_l7tm6a_result.log +54 -0
  51. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/audit_1783615825308_44nor5_prompt.log +19 -0
  52. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/audit_1783615825308_44nor5_result.log +85 -0
  53. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/audit_1783616524771_ut1ftw_prompt.log +19 -0
  54. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/audit_1783616524771_ut1ftw_result.log +266 -0
  55. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/audit_1783617323039_fs3x5a_prompt.log +19 -0
  56. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/audit_1783617323039_fs3x5a_result.log +56 -0
  57. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/audit_1783618049184_1f4yah_prompt.log +19 -0
  58. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/audit_1783618049184_1f4yah_result.log +96 -0
  59. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/audit_1783618793925_4ee7tf_prompt.log +19 -0
  60. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/audit_1783618793925_4ee7tf_result.log +481 -0
  61. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/audit_1783619642574_yjr4mm_prompt.log +19 -0
  62. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/audit_1783619642574_yjr4mm_result.log +104 -0
  63. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/audit_1783620392771_oduto0_prompt.log +19 -0
  64. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/audit_1783620392771_oduto0_result.log +148 -0
  65. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/audit_1783621183670_gd0p1x_prompt.log +19 -0
  66. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/audit_1783621183670_gd0p1x_result.log +111 -0
  67. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/audit_1783621738388_z4k48b_prompt.log +19 -0
  68. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/audit_1783621738388_z4k48b_result.log +89 -0
  69. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/audit_1783622493677_zwc35w_prompt.log +19 -0
  70. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/audit_1783622493677_zwc35w_result.log +207 -0
  71. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/optimize_1783604894861_v6n3ut_prompt.log +14 -0
  72. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/optimize_1783604894861_v6n3ut_result.log +66 -0
  73. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/optimize_1783605934532_9h8ikb_prompt.log +14 -0
  74. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/optimize_1783605934532_9h8ikb_result.log +68 -0
  75. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/optimize_1783607181736_t12f4y_prompt.log +14 -0
  76. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/optimize_1783607181736_t12f4y_result.log +78 -0
  77. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/optimize_1783608341266_zhk0fl_prompt.log +14 -0
  78. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/optimize_1783608341266_zhk0fl_result.log +68 -0
  79. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/optimize_1783609420180_7xw817_prompt.log +14 -0
  80. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/optimize_1783609420180_7xw817_result.log +72 -0
  81. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/optimize_1783610535307_2pxofp_prompt.log +14 -0
  82. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/optimize_1783610535307_2pxofp_result.log +17 -0
  83. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/optimize_1783611437445_ofwnpb_prompt.log +14 -0
  84. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/optimize_1783611437445_ofwnpb_result.log +60 -0
  85. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/optimize_1783612556827_1cb112_prompt.log +14 -0
  86. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/optimize_1783612556827_1cb112_result.log +56 -0
  87. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/optimize_1783613579531_18xiax_prompt.log +14 -0
  88. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/optimize_1783613579531_18xiax_result.log +74 -0
  89. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/optimize_1783614650481_2zdz7w_prompt.log +14 -0
  90. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/optimize_1783614650481_2zdz7w_result.log +68 -0
  91. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/optimize_1783615742328_rjj69d_prompt.log +14 -0
  92. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/optimize_1783615742328_rjj69d_result.log +65 -0
  93. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/optimize_1783616767230_1iad99_prompt.log +14 -0
  94. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/optimize_1783616767230_1iad99_result.log +68 -0
  95. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/optimize_1783617783537_rqagku_prompt.log +14 -0
  96. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/optimize_1783617783537_rqagku_result.log +56 -0
  97. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/optimize_1783618817343_r1lbhr_prompt.log +14 -0
  98. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/optimize_1783618817343_r1lbhr_result.log +65 -0
  99. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/optimize_1783619907773_8msfw3_prompt.log +14 -0
  100. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/optimize_1783619907773_8msfw3_result.log +77 -0
  101. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/optimize_1783621009302_hybdum_prompt.log +14 -0
  102. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/optimize_1783621009302_hybdum_result.log +64 -0
  103. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/optimize_1783622083681_nznpnx_prompt.log +14 -0
  104. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/optimize_1783622083681_nznpnx_result.log +56 -0
  105. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/optimize_1783623208340_olsbaw_prompt.log +14 -0
  106. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/testgaps_1783605134860_9jssz9_prompt.log +14 -0
  107. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/testgaps_1783605134860_9jssz9_result.log +69 -0
  108. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/testgaps_1783606516743_zftbaa_prompt.log +14 -0
  109. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/testgaps_1783606516743_zftbaa_result.log +92 -0
  110. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/testgaps_1783608038317_jrd66e_prompt.log +14 -0
  111. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/testgaps_1783608038317_jrd66e_result.log +92 -0
  112. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/testgaps_1783609388416_mc3zoe_prompt.log +14 -0
  113. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/testgaps_1783609388416_mc3zoe_result.log +82 -0
  114. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/testgaps_1783610821384_tzqvlb_prompt.log +14 -0
  115. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/testgaps_1783610821384_tzqvlb_result.log +17 -0
  116. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/testgaps_1783612023285_buygpo_prompt.log +14 -0
  117. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/testgaps_1783612023285_buygpo_result.log +57 -0
  118. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/testgaps_1783613599301_6f78cw_prompt.log +14 -0
  119. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/testgaps_1783613599301_6f78cw_result.log +60 -0
  120. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/testgaps_1783615000844_v95ues_prompt.log +14 -0
  121. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/testgaps_1783615000844_v95ues_result.log +69 -0
  122. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/testgaps_1783616341693_bl5d9o_prompt.log +14 -0
  123. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/testgaps_1783616341693_bl5d9o_result.log +64 -0
  124. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/testgaps_1783617832831_ha6s8d_prompt.log +14 -0
  125. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/testgaps_1783617832831_ha6s8d_result.log +42 -0
  126. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/testgaps_1783619384959_s5iiwf_prompt.log +14 -0
  127. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/testgaps_1783619384959_s5iiwf_result.log +47 -0
  128. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/testgaps_1783620946263_d7ovai_prompt.log +14 -0
  129. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/testgaps_1783620946263_d7ovai_result.log +52 -0
  130. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/testgaps_1783622473846_t839e5_prompt.log +14 -0
  131. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/testgaps_1783622473846_t839e5_result.log +96 -0
  132. package/plugins/ruflo-metaharness/.claude-flow/metrics/backup.json +7 -0
  133. package/plugins/ruflo-metaharness/.claude-flow/metrics/codebase-map.json +11 -0
  134. package/plugins/ruflo-metaharness/.claude-flow/metrics/consolidation.json +16 -0
  135. package/plugins/ruflo-metaharness/.claude-flow/metrics/harness-loop.json +83 -0
  136. package/plugins/ruflo-metaharness/.claude-flow/metrics/performance.json +55 -0
  137. package/plugins/ruflo-metaharness/.claude-flow/metrics/security-audit.json +206 -0
  138. package/plugins/ruflo-metaharness/.claude-flow/metrics/test-gaps.json +95 -0
  139. package/plugins/ruflo-metaharness/.claude-flow/neural/stats.json +6 -0
  140. package/plugins/ruflo-metaharness/skills/harness-gepa/SKILL.md +1 -1
@@ -0,0 +1,95 @@
1
+ {
2
+ "timestamp": "2026-07-09T18:43:49.365Z",
3
+ "mode": "headless",
4
+ "workerType": "testgaps",
5
+ "model": "sonnet",
6
+ "durationMs": 155519,
7
+ "executionId": "testgaps_1783622473846_t839e5",
8
+ "success": true,
9
+ "findings": {
10
+ "sections": [
11
+ {
12
+ "title": "Test Coverage Analysis — `plugins/ruflo-metaharness`",
13
+ "content": "\n**Testing model:** no framework (no Jest/Vitest/Mocha, no `package.json` in this directory) — coverage is via hand-rolled `scripts/test-*.mjs` node scripts that assert and exit non-zero on failure. 34 `.mjs` files (~6,900 lines): 6 shared library modules (`_*.mjs`), 22 CLI wrappers, 6 test scripts.\n\n",
14
+ "level": 2
15
+ },
16
+ {
17
+ "title": "What's actually covered today",
18
+ "content": "\n| Test file | Covers |\n|---|---|\n| `test-similarity.mjs` | `_similarity.mjs` pure functions (`projectToVec`, `cosine`, `categoricalAgreement`, `jaccard`, `similarity`) + `_harness.mjs`'s `SEVERITY_RANK`/`rankSeverity`/`parseMcpScanText` |\n| `test-graceful-degradation.mjs` | **Degraded-path only** (network blocked) for `score`, `genome`, `mcp-scan`, `threat-model`, `oia-audit`, `audit-list`, `audit-trend`, `mint` — asserts exit 0 + `\"degraded\":true` |\n| `test-mcp-tools.mjs` | MCP tool registry handler contract (callable, returns `{success,data,degraded,exitCode}`, never throws) |\n| `test-pipeline-roundtrip.mjs` | E2E `oia-audit` → `audit-trend` chain against the real repo |\n| `test-parallel-pipeline.mjs` | `recordPair`/`recordPairOutcome` (TS, elsewhere) → `.jsonl` → `router-parallel-analyze.mjs` composition |\n| `test-with-openrouter.mjs` | Costed E2E: scaffold via `mint` + `doctor`/`validate`/`score`/`genome` lifecycle |\n\nEvery one of these is an **integration/degraded-path/contract** test. None of them is a true unit test of a CLI wrapper's own logic (arg parsing, safety checks, output shaping) on its **success path** with a **fake/mocked upstream**.\n\n---\n\n",
19
+ "level": 3
20
+ },
21
+ {
22
+ "title": "Gap 1 — `_invoke.mjs`: zero direct unit tests (highest priority)",
23
+ "content": "\nThis is the shared plumbing layer imported by ~15 scripts (`classifyDegraded`, `injectJson`, `parseTrailingJson`, `satisfiesTildeRange`, `findLocalPackageDir`, `ensureCachedInstall`, `importOptionalLibrary`, `makeDegradedEmitter`). It's pure/near-pure and currently only exercised transitively through e2e degraded-path runs — no test asserts its behavior directly.\n\n**Untested edge cases:**\n- `classifyDegraded`: `exitCode === null` → `-timeout` reason vs `DEGRADED_RX` match → `-not-available` vs neither → `{degraded:false}`. The regex itself (`could not determine executable|404|not installed|MODULE_NOT_FOUND|ENOTFOUND|getaddrinfo|ECONNREFUSED|ETIMEDOUT|npm ERR`) has no per-token test.\n- `parseTrailingJson`: multiple `{...}` blocks (must pick **last** parseable one, not first — this was called out in the file header as a fixed bug), nested objects that break the lazy regex (falls back to greedy whole-span match), no JSON present → `null`.\n- `injectJson`: `args` already contains `--json` → no duplicate; `wantJson=false` → untouched copy (not mutated).\n- `satisfiesTildeRange`: same major.minor + patch ≥ pin → true; different minor → false; malformed version strings → false (no throw).\n- `findLocalPackageDir`: `RUFLO_METAHARNESS_SKIP_LOCAL=1` short-circuits; pin-version filtering skips a stale ancestor install.\n\n```javascript\n// scripts/test-invoke.mjs — unit tests for _invoke.mjs (skeleton)\nimport {\n classifyDegraded, injectJson, parseTrailingJson, satisfiesTildeRange,\n} from './_invoke.mjs';\n\nlet failures = 0;\nfunction assertEq(actual, expected, label) {\n const ok = JSON.stringify(actual) === JSON.stringify(expected);\n if (!ok) { failures++; console.error(`FAIL ${label}: got ${JSON.stringify(actual)}, want ${JSON.stringify(expected)}`); }\n}\n\n// classifyDegraded\nassertEq(classifyDegraded('', null, 'x'), { degraded: true, reason: 'x-timeout' }, 'timeout');\nassertEq(classifyDegraded('npm ERR! 404', 1, 'x'), { degraded: true, reason: 'x-not-available' }, 'npm-404');\nassertEq(classifyDegraded('normal output', 0, 'x'), { degraded: false }, 'healthy');\n\n// injectJson\nassertEq(injectJson(['a'], true), ['a', '--json'], 'inject-json');\nassertEq(injectJson(['a', '--json'], true), ['a', '--json'], 'no-dup');\nassertEq(injectJson(['a'], false), ['a'], 'opt-out');\n\n// parseTrailingJson — LAST block wins (regression guard for the documented bug)\nassertEq(parseTrailingJson('progress {\"partial\":1}\\nfinal: {\"result\":\"ok\"}'), { result: 'ok' }, 'last-block');\nassertEq(parseTrailingJson('no json here'), null, 'no-json');\n\n// satisfiesTildeRange\nassertEq(satisfiesTildeRange('0.3.2', '~0.3.0'), true, 'patch-ok');\nassertEq(satisfiesTildeRange('0.4.0', '~0.3.0'), false, 'minor-mismatch');\nassertEq(satisfiesTildeRange('garbage', '~0.3.0'), false, 'malformed');\n\nconsole.log(failures === 0 ? 'PASS' : `${failures} FAILED`);\nprocess.exit(failures === 0 ? 0 : 1);\n```\n\n",
24
+ "level": 3
25
+ },
26
+ {
27
+ "title": "Gap 2 — `_darwin.mjs`: zero coverage (not even degraded-path)",
28
+ "content": "\n`test-graceful-degradation.mjs` explicitly lists 8 covered skills; **none of `evolve`, `bench`, `security-bench`, `gepa` (all `_darwin.mjs` consumers) are in that list.** So the entire darwin invocation path — sync (`runDarwin`) and async streaming (`runDarwinAsync`, `onProgress` callback, `signal` abort, timeout kill) — has no test at all, degraded or otherwise.\n\n```javascript\n// scripts/test-darwin-degraded.mjs (skeleton) — extend test-graceful-degradation.mjs's\n// pattern (unresolvable registry) to cover the darwin-backed skills.\nimport { spawnSync } from 'node:child_process';\n\nconst DARWIN_SKILLS = [\n { name: 'bench', args: ['scripts/bench.mjs', '--op', 'verify', '--suite', '/tmp/nonexistent.json'] },\n { name: 'evolve', args: ['scripts/evolve.mjs', '--repo', '.', '--confirm'] },\n { name: 'security-bench', args: ['scripts/security-bench.mjs'] },\n { name: 'gepa', args: ['scripts/gepa.mjs', '--op', 'genome'] },\n];\n\nlet failures = 0;\nfor (const skill of DARWIN_SKILLS) {\n const r = spawnSync('node', skill.args, {\n encoding: 'utf-8',\n env: { ...process.env, npm_config_registry: 'http://127.0.0.1:1' },\n });\n const ok = r.status === 0 && /\"degraded\"\\s*:\\s*true/.test(r.stdout || '');\n if (!ok) { failures++; console.error(`FAIL ${skill.name}: exit=${r.status}`); }\n}\nprocess.exit(failures === 0 ? 0 : 1);\n```\n\n",
29
+ "level": 3
30
+ },
31
+ {
32
+ "title": "Gap 3 — `evolve.mjs`: safety-critical logic, zero tests",
33
+ "content": "\nThis is the only script that mutates a target repo and has a documented safety model (ADR-153). Its **pure logic is fully unit-testable without spawning darwin** but isn't tested:\n- `safetyChecks()`: `--generations` 0/51 rejected, `--children` 0/21 rejected, `--concurrency` 0/9 rejected, invalid `--sandbox`/`--selection`/`--mutator` rejected, nonexistent `--repo` → exit 2.\n- `defaultTimeoutMs()`: arithmetic for `mock` vs `real` sandbox, `Math.ceil(variants/parallelism)` bucketing.\n- `--confirm` omitted → dry-run plan printed, exit 0, **no subprocess spawned** (this is the load-bearing safety guarantee and has no regression test).\n- Exit code 99 propagation (`safetyDisqualified`) — never exercised.\n- `looksLikeGepaTranscript` / `extractGepaTranscripts` / `summarizeTraces` — pure functions handling malformed/absent `.metaharness/runs/*.json`, never tested with synthetic fixtures.\n\n```javascript\n// scripts/test-evolve-safety.mjs (skeleton)\nimport { spawnSync } from 'node:child_process';\n\nlet failures = 0;\nfunction expectExit(args, wantCode, label) {\n const r = spawnSync('node', ['scripts/evolve.mjs', ...args], { encoding: 'utf-8' });\n if (r.status !== wantCode) { failures++; console.error(`FAIL ${label}: exit ${r.status}, want ${wantCode}`); }\n return r;\n}\n\nexpectExit(['--repo', '.', '--generations', '0'], 2, 'generations-too-low');\nexpectExit(['--repo', '.', '--generations', '51'], 2, 'generations-too-high');\nexpectExit(['--repo', '.', '--children', '21'], 2, 'children-cap');\nexpectExit(['--repo', '.', '--sandbox', 'bogus'], 2, 'bad-sandbox');\nexpectExit(['--repo', '/nonexistent/path'], 2, 'bad-repo');\n\n// dry-run: no --confirm → must never spawn darwin, must exit 0 with a plan\nconst dry = expectExit(['--repo', '.'], 0, 'dry-run-plan');\nif (!/\"dryRun\"\\s*:\\s*true/.test(dry.stdout)) { failures++; console.error('FAIL dry-run-plan: missing dryRun:true'); }\n\nprocess.exit(failures === 0 ? 0 : 1);\n```\n\n",
34
+ "level": 3
35
+ },
36
+ {
37
+ "title": "Gap 4 — `mint.mjs`: path-traversal safety check untested",
38
+ "content": "\n`safetyChecks()` refuses to write to the project root or inside the calling repo — this is a directory-traversal guard with no negative test:\n\n```javascript\n// scripts/test-mint-safety.mjs (skeleton)\nimport { spawnSync } from 'node:child_process';\n\nlet failures = 0;\nfunction expectRejected(target, label) {\n const r = spawnSync('node', ['scripts/mint.mjs', '--name', 'x', '--template', 'minimal', '--target', target], { encoding: 'utf-8' });\n if (r.status !== 2) { failures++; console.error(`FAIL ${label}: expected exit 2, got ${r.status}`); }\n}\n\nexpectRejected(process.cwd(), 'refuses-repo-root');\nexpectRejected(process.cwd() + '/subdir', 'refuses-inside-repo');\n\n// missing --name / --template\nfor (const args of [['--template', 'minimal'], ['--name', 'x']]) {\n const r = spawnSync('node', ['scripts/mint.mjs', ...args], { encoding: 'utf-8' });\n if (r.status !== 2) { failures++; console.error(`FAIL missing-required-arg ${args}`); }\n}\nprocess.exit(failures === 0 ? 0 : 1);\n```\n\n",
39
+ "level": 3
40
+ },
41
+ {
42
+ "title": "Gap 5 — `drift-from-history.mjs`: composed pipeline, zero tests",
43
+ "content": "\n404-line orchestrator (3-way fast-path selection: slow / `--baseline-key` / `--baseline-file`) with no test at any level. Highest-value untested branches:\n- `--baseline-file` path skips memory entirely (`skippedAuditList=true, usedBaselineFile=true`) — the `timing.path === 'file'` label is asserted nowhere.\n- Empty `audit-list` result (no history) → exit 2, distinguished from `metaharness` absence → exit 3 (uses `auditResult.json?.degraded` from the *other* parallel branch — subtle coupling, easy to regress).\n- `--alert-on-new-severity` orthogonal gate: fires independent of `--threshold`, and the two reasons must both appear in `alert.reasons` when both trigger.\n- `runScriptJsonAsync` error path (`spawn` failure → `exitCode:127`, `stderr:'spawn-failed'`) — never simulated.\n\n```javascript\n// scripts/test-drift-from-history.mjs (skeleton, fixture-driven)\nimport { spawnSync } from 'node:child_process';\nimport { writeFileSync, mkdtempSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { tmpdir } from 'node:os';\n\nlet failures = 0;\nconst dir = mkdtempSync(join(tmpdir(), 'drift-test-'));\n\n// Fixture: two near-identical oia-audit-shaped records with fingerprints.\nconst baseline = { startedAt: '2026-01-01T00:00:00Z', composite: { worst: 'clean' },\n fingerprint: { score: { dims: [1,1,1] }, genome: { tags: ['a'] } } };\nwriteFileSync(join(dir, 'baseline.json'), JSON.stringify(baseline));\n\n// --baseline-file path: assert timing.path === 'file' and no audit-list call\nconst r = spawnSync('node', [\n 'scripts/drift-from-history.mjs',\n '--baseline-file', join(dir, 'baseline.json'),\n '--format', 'json',\n], { encoding: 'utf-8' });\nconst json = JSON.parse((r.stdout.match(/\\{[\\s\\S]*\\}/) || ['{}'])[0]);\nif (json.timing?.path !== 'file') { failures++; console.error('FAIL baseline-file: wrong fast-path label'); }\n\nprocess.exit(failures === 0 ? 0 : 1);\n```\n\n",
44
+ "level": 3
45
+ },
46
+ {
47
+ "title": "Gap 6 — Untested error/malformed-input handling across CLI wrappers",
48
+ "content": "\nNone of the following are exercised anywhere:\n- `audit-trend.mjs` / `similarity.mjs`: malformed JSON file for `--baseline`/`--a`/`--b` (both have a try/catch around `JSON.parse` → exit 2, but no test); missing `composite` key in a supplied record (`audit-trend.mjs:104-107`); memory-namespace key-not-found path (`memRetrieve` returns `null`).\n- `mcp-scan.mjs`: invalid `--fail-on` value → exit 2 (untested); `rankSeverity` applied to an unknown/undefined severity in `findings` (regression the code comment explicitly calls out as a past bug — iter 63 — but has no test guarding it).\n- `redblue.mjs`: unknown subcommand → exit 2; `attack` without a valid family → exit 2; `report` without `--in` → exit 2; unknown `--flag` passthrough forwarding (`_passthrough` accumulation logic, including the \"peek next token, only consume if not another flag\" branch) — no test.\n- `gepa.mjs`: invalid `--op` → exit 2; `--transcript` pointing at a non-array JSON → exit 2; `readJsonFile` on missing file → exit 2.\n- `learn.mjs`: `CHECKOUT_RX` detection path (`requires a metaharness repo checkout` in combined stdout/stderr) → `{status:'checkout-required'}` — this is a load-bearing distinct-from-`degraded` state with no test.\n\n```javascript\n// scripts/test-cli-arg-validation.mjs (skeleton — one file to batch cheap negative-path checks)\nimport { spawnSync } from 'node:child_process';\n\nconst CASES = [\n { args: ['scripts/mcp-scan.mjs', '--fail-on', 'bogus'], code: 2, label: 'mcp-scan bad --fail-on' },\n { args: ['scripts/redblue.mjs', 'nonsense'], code: 2, label: 'redblue unknown subcommand' },\n { args: ['scripts/redblue.mjs', 'attack', 'bogus-family'], code: 2, label: 'redblue bad attack family' },\n { args: ['scripts/redblue.mjs', 'report'], code: 2, label: 'redblue report missing --in' },\n { args: ['scripts/gepa.mjs', '--op', 'bogus'], code: 2, label: 'gepa bad --op' },\n { args: ['scripts/bench.mjs', '--op', 'bogus'], code: 2, label: 'bench bad --op' },\n { args: ['scripts/bench.mjs', '--op', 'verify'], code: 2, label: 'bench verify missing --suite' },\n];\n\nlet failures = 0;\nfor (const c of CASES) {\n const r = spawnSync('node', c.args, { encoding: 'utf-8' });\n if (r.status !== c.code) { failures++; console.error(`FAIL ${c.label}: exit ${r.status}, want ${c.code}`); }\n}\nprocess.exit(failures === 0 ? 0 : 1);\n```\n\n",
49
+ "level": 3
50
+ },
51
+ {
52
+ "title": "Gap 7 — `router-parallel-analyze.mjs`: promotion-criteria math untested in isolation",
53
+ "content": "\nCovered only via `test-parallel-pipeline.mjs`'s full e2e (recorder → jsonl → analyzer). The three-criteria AND-gate arithmetic (`median`, `pctile`, `mean`, the >2%/<1%/<5% thresholds) has no direct unit test with a synthetic `.jsonl` fixture that pins one criterion failing while the other two pass — the case most likely to regress silently (OR-vs-AND was literally the bug this file's header warns about).\n\n```javascript\n// scripts/test-router-parallel-analyze.mjs (skeleton)\nimport { writeFileSync, mkdtempSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { tmpdir } from 'node:os';\nimport { spawnSync } from 'node:child_process';\n\nconst dir = mkdtempSync(join(tmpdir(), 'rpa-test-'));\nconst file = join(dir, 'router-parallel.jsonl');\n\n// Fixture: quality +5% (passes >2%), cost +2% (FAILS <1%), latency +1% (passes <5%)\n// → overall must NOT be promotable even though 2/3 criteria pass (AND, not OR).\nconst rows = Array.from({ length: 20 }, (_, i) => JSON.stringify({\n ts: new Date(0).toISOString(),\n bandit: { pick: 'a', predictedQuality: 0.80, predictedCostUsd: 0.0100 },\n ser: { pick: 'b', predictedQuality: 0.84, predictedCostUsd: 0.0102 },\n outcome: { actualModel: 'b', actualQuality: 0.84, actualUsd: 0.0102, actualLatencyMs: 1010 },\n}));\nwriteFileSync(file, rows.join('\\n'));\n\nconst r = spawnSync('node', ['scripts/router-parallel-analyze.mjs', '--input', file, '--strict', '--format', 'json'], { encoding: 'utf-8' });\nlet failures = 0;\nif (r.status !== 1) { failures++; console.error('FAIL: cost regression should block promotion under --strict (AND-gate)'); }\nprocess.exit(failures === 0 ? 0 : 1);\n```\n\n---\n\n",
54
+ "level": 3
55
+ },
56
+ {
57
+ "title": "Summary table",
58
+ "content": "| File | Lines | Existing coverage | Gap severity |\n|---|---:|---|---|\n| `_invoke.mjs` | 232 | none (transitive only) | **High** — shared by ~15 files |\n| `_darwin.mjs` | 211 | none | **High** — powers evolve/bench/security-bench/gepa |\n| `evolve.mjs` | 405 | none | **High** — mutates repos, safety-critical |\n| `drift-from-history.mjs` | 364 | none | **High** — 3-way fast-path branching |\n| `gepa.mjs` | 154 | none | Medium |\n| `learn.mjs` | 128 | none | Medium |\n| `security-bench.mjs` | 175 | none (incl. markdown parser `parseSecurityBenchMarkdown`) | Medium |\n| `bench.mjs` | 96 | none | Medium |\n| `redblue.mjs` / `_redblue.mjs` | 286 / 144 | none | Medium |\n| `mint.mjs` | 127 | degraded-path only | Medium — success + safety-check paths untested |\n| `similarity.mjs` (CLI) | 159 | `_similarity.mjs` internals tested; CLI wrapper (arg parsing, mem lookup, `--alert-below`) not | Low-Medium |\n| `audit-trend.mjs` | 273 | degraded-path + e2e roundtrip only | Low-Medium — malformed-record/missing-key branches untested |\n| `mcp-scan.mjs` | 111 | `parseMcpScanText` tested via `_harness.mjs`; CLI arg validation + severity-filter edge cases not | Low |\n| `router-parallel-analyze.mjs` | 250 | e2e only | Low — pure math untested in isolation |\n\n**Recommendation:** prioritize `test-invoke.mjs` (Gap 1) — it's pure, fast, and de-risks every other script that imports it — then `test-evolve-safety.mjs` and `test-mint-safety.mjs` (Gaps 3–4) since those guard destructive/safety-critical behavior with zero regression protection today.",
59
+ "level": 3
60
+ }
61
+ ],
62
+ "codeBlocks": [
63
+ {
64
+ "language": "javascript",
65
+ "code": "// scripts/test-invoke.mjs — unit tests for _invoke.mjs (skeleton)\nimport {\n classifyDegraded, injectJson, parseTrailingJson, satisfiesTildeRange,\n} from './_invoke.mjs';\n\nlet failures = 0;\nfunction assertEq(actual, expected, label) {\n const ok = JSON.stringify(actual) === JSON.stringify(expected);\n if (!ok) { failures++; console.error(`FAIL ${label}: got ${JSON.stringify(actual)}, want ${JSON.stringify(expected)}`); }\n}\n\n// classifyDegraded\nassertEq(classifyDegraded('', null, 'x'), { degraded: true, reason: 'x-timeout' }, 'timeout');\nassertEq(classifyDegraded('npm ERR! 404', 1, 'x'), { degraded: true, reason: 'x-not-available' }, 'npm-404');\nassertEq(classifyDegraded('normal output', 0, 'x'), { degraded: false }, 'healthy');\n\n// injectJson\nassertEq(injectJson(['a'], true), ['a', '--json'], 'inject-json');\nassertEq(injectJson(['a', '--json'], true), ['a', '--json'], 'no-dup');\nassertEq(injectJson(['a'], false), ['a'], 'opt-out');\n\n// parseTrailingJson — LAST block wins (regression guard for the documented bug)\nassertEq(parseTrailingJson('progress {\"partial\":1}\\nfinal: {\"result\":\"ok\"}'), { result: 'ok' }, 'last-block');\nassertEq(parseTrailingJson('no json here'), null, 'no-json');\n\n// satisfiesTildeRange\nassertEq(satisfiesTildeRange('0.3.2', '~0.3.0'), true, 'patch-ok');\nassertEq(satisfiesTildeRange('0.4.0', '~0.3.0'), false, 'minor-mismatch');\nassertEq(satisfiesTildeRange('garbage', '~0.3.0'), false, 'malformed');\n\nconsole.log(failures === 0 ? 'PASS' : `${failures} FAILED`);\nprocess.exit(failures === 0 ? 0 : 1);"
66
+ },
67
+ {
68
+ "language": "javascript",
69
+ "code": "// scripts/test-darwin-degraded.mjs (skeleton) — extend test-graceful-degradation.mjs's\n// pattern (unresolvable registry) to cover the darwin-backed skills.\nimport { spawnSync } from 'node:child_process';\n\nconst DARWIN_SKILLS = [\n { name: 'bench', args: ['scripts/bench.mjs', '--op', 'verify', '--suite', '/tmp/nonexistent.json'] },\n { name: 'evolve', args: ['scripts/evolve.mjs', '--repo', '.', '--confirm'] },\n { name: 'security-bench', args: ['scripts/security-bench.mjs'] },\n { name: 'gepa', args: ['scripts/gepa.mjs', '--op', 'genome'] },\n];\n\nlet failures = 0;\nfor (const skill of DARWIN_SKILLS) {\n const r = spawnSync('node', skill.args, {\n encoding: 'utf-8',\n env: { ...process.env, npm_config_registry: 'http://127.0.0.1:1' },\n });\n const ok = r.status === 0 && /\"degraded\"\\s*:\\s*true/.test(r.stdout || '');\n if (!ok) { failures++; console.error(`FAIL ${skill.name}: exit=${r.status}`); }\n}\nprocess.exit(failures === 0 ? 0 : 1);"
70
+ },
71
+ {
72
+ "language": "javascript",
73
+ "code": "// scripts/test-evolve-safety.mjs (skeleton)\nimport { spawnSync } from 'node:child_process';\n\nlet failures = 0;\nfunction expectExit(args, wantCode, label) {\n const r = spawnSync('node', ['scripts/evolve.mjs', ...args], { encoding: 'utf-8' });\n if (r.status !== wantCode) { failures++; console.error(`FAIL ${label}: exit ${r.status}, want ${wantCode}`); }\n return r;\n}\n\nexpectExit(['--repo', '.', '--generations', '0'], 2, 'generations-too-low');\nexpectExit(['--repo', '.', '--generations', '51'], 2, 'generations-too-high');\nexpectExit(['--repo', '.', '--children', '21'], 2, 'children-cap');\nexpectExit(['--repo', '.', '--sandbox', 'bogus'], 2, 'bad-sandbox');\nexpectExit(['--repo', '/nonexistent/path'], 2, 'bad-repo');\n\n// dry-run: no --confirm → must never spawn darwin, must exit 0 with a plan\nconst dry = expectExit(['--repo', '.'], 0, 'dry-run-plan');\nif (!/\"dryRun\"\\s*:\\s*true/.test(dry.stdout)) { failures++; console.error('FAIL dry-run-plan: missing dryRun:true'); }\n\nprocess.exit(failures === 0 ? 0 : 1);"
74
+ },
75
+ {
76
+ "language": "javascript",
77
+ "code": "// scripts/test-mint-safety.mjs (skeleton)\nimport { spawnSync } from 'node:child_process';\n\nlet failures = 0;\nfunction expectRejected(target, label) {\n const r = spawnSync('node', ['scripts/mint.mjs', '--name', 'x', '--template', 'minimal', '--target', target], { encoding: 'utf-8' });\n if (r.status !== 2) { failures++; console.error(`FAIL ${label}: expected exit 2, got ${r.status}`); }\n}\n\nexpectRejected(process.cwd(), 'refuses-repo-root');\nexpectRejected(process.cwd() + '/subdir', 'refuses-inside-repo');\n\n// missing --name / --template\nfor (const args of [['--template', 'minimal'], ['--name', 'x']]) {\n const r = spawnSync('node', ['scripts/mint.mjs', ...args], { encoding: 'utf-8' });\n if (r.status !== 2) { failures++; console.error(`FAIL missing-required-arg ${args}`); }\n}\nprocess.exit(failures === 0 ? 0 : 1);"
78
+ },
79
+ {
80
+ "language": "javascript",
81
+ "code": "// scripts/test-drift-from-history.mjs (skeleton, fixture-driven)\nimport { spawnSync } from 'node:child_process';\nimport { writeFileSync, mkdtempSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { tmpdir } from 'node:os';\n\nlet failures = 0;\nconst dir = mkdtempSync(join(tmpdir(), 'drift-test-'));\n\n// Fixture: two near-identical oia-audit-shaped records with fingerprints.\nconst baseline = { startedAt: '2026-01-01T00:00:00Z', composite: { worst: 'clean' },\n fingerprint: { score: { dims: [1,1,1] }, genome: { tags: ['a'] } } };\nwriteFileSync(join(dir, 'baseline.json'), JSON.stringify(baseline));\n\n// --baseline-file path: assert timing.path === 'file' and no audit-list call\nconst r = spawnSync('node', [\n 'scripts/drift-from-history.mjs',\n '--baseline-file', join(dir, 'baseline.json'),\n '--format', 'json',\n], { encoding: 'utf-8' });\nconst json = JSON.parse((r.stdout.match(/\\{[\\s\\S]*\\}/) || ['{}'])[0]);\nif (json.timing?.path !== 'file') { failures++; console.error('FAIL baseline-file: wrong fast-path label'); }\n\nprocess.exit(failures === 0 ? 0 : 1);"
82
+ },
83
+ {
84
+ "language": "javascript",
85
+ "code": "// scripts/test-cli-arg-validation.mjs (skeleton — one file to batch cheap negative-path checks)\nimport { spawnSync } from 'node:child_process';\n\nconst CASES = [\n { args: ['scripts/mcp-scan.mjs', '--fail-on', 'bogus'], code: 2, label: 'mcp-scan bad --fail-on' },\n { args: ['scripts/redblue.mjs', 'nonsense'], code: 2, label: 'redblue unknown subcommand' },\n { args: ['scripts/redblue.mjs', 'attack', 'bogus-family'], code: 2, label: 'redblue bad attack family' },\n { args: ['scripts/redblue.mjs', 'report'], code: 2, label: 'redblue report missing --in' },\n { args: ['scripts/gepa.mjs', '--op', 'bogus'], code: 2, label: 'gepa bad --op' },\n { args: ['scripts/bench.mjs', '--op', 'bogus'], code: 2, label: 'bench bad --op' },\n { args: ['scripts/bench.mjs', '--op', 'verify'], code: 2, label: 'bench verify missing --suite' },\n];\n\nlet failures = 0;\nfor (const c of CASES) {\n const r = spawnSync('node', c.args, { encoding: 'utf-8' });\n if (r.status !== c.code) { failures++; console.error(`FAIL ${c.label}: exit ${r.status}, want ${c.code}`); }\n}\nprocess.exit(failures === 0 ? 0 : 1);"
86
+ },
87
+ {
88
+ "language": "javascript",
89
+ "code": "// scripts/test-router-parallel-analyze.mjs (skeleton)\nimport { writeFileSync, mkdtempSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { tmpdir } from 'node:os';\nimport { spawnSync } from 'node:child_process';\n\nconst dir = mkdtempSync(join(tmpdir(), 'rpa-test-'));\nconst file = join(dir, 'router-parallel.jsonl');\n\n// Fixture: quality +5% (passes >2%), cost +2% (FAILS <1%), latency +1% (passes <5%)\n// → overall must NOT be promotable even though 2/3 criteria pass (AND, not OR).\nconst rows = Array.from({ length: 20 }, (_, i) => JSON.stringify({\n ts: new Date(0).toISOString(),\n bandit: { pick: 'a', predictedQuality: 0.80, predictedCostUsd: 0.0100 },\n ser: { pick: 'b', predictedQuality: 0.84, predictedCostUsd: 0.0102 },\n outcome: { actualModel: 'b', actualQuality: 0.84, actualUsd: 0.0102, actualLatencyMs: 1010 },\n}));\nwriteFileSync(file, rows.join('\\n'));\n\nconst r = spawnSync('node', ['scripts/router-parallel-analyze.mjs', '--input', file, '--strict', '--format', 'json'], { encoding: 'utf-8' });\nlet failures = 0;\nif (r.status !== 1) { failures++; console.error('FAIL: cost regression should block promotion under --strict (AND-gate)'); }\nprocess.exit(failures === 0 ? 0 : 1);"
90
+ }
91
+ ]
92
+ },
93
+ "rawOutputPreview": "## Test Coverage Analysis — `plugins/ruflo-metaharness`\n\n**Testing model:** no framework (no Jest/Vitest/Mocha, no `package.json` in this directory) — coverage is via hand-rolled `scripts/test-*.mjs` node scripts that assert and exit non-zero on failure. 34 `.mjs` files (~6,900 lines): 6 shared library modules (`_*.mjs`), 22 CLI wrappers, 6 test scripts.\n\n### What's actually covered today\n\n| Test file | Covers |\n|---|---|\n| `test-similarity.mjs` | `_similarity.mjs` pure functions (`projectToVec`, `cosine`, `categoricalAgreement`, `jaccard`, `similarity`) + `_harness.mjs`'s `SEVERITY_RANK`/`rankSeverity`/`parseMcpScanText` |\n| `test-graceful-degradation.mjs` | **Degraded-path only** (network blocked) for `score`, `genome`, `mcp-scan`, `threat-model`, `oia-audit`, `audit-list`, `audit-trend`, `mint` — asserts exit 0 + `\"degraded\":true` |\n| `test-mcp-tools.mjs` | MCP tool registry handler contract (callable, returns `{success,data,degraded,exitCode}`, never throws) |\n| `test-pipeline-roundtrip.mjs` | E2E `oia-audit` → `audit-trend` chain against the real repo |\n| `test-parallel-pipeline.mjs` | `recordPair`/`recordPairOutcome` (TS, elsewhere) → `.jsonl` → `router-parallel-analyze.mjs` composition |\n| `test-with-openrouter.mjs` | Costed E2E: scaffold via `mint` + `doctor`/`validate`/`score`/`genome` lifecycle |\n\nEvery one of these is an **integration/degraded-path/contract** test. None of them is a true unit test of a CLI wrapper's own logic (arg parsing, safety checks, output shaping) on its **success path** with a **fake/mocked upstream**.\n\n---\n\n### Gap 1 — `_invoke.mjs`: zero direct unit tests (highest priority)\n\nThis is the shared plumbing layer imported by ~15 scripts (`classifyDegraded`, `injectJson`, `parseTrailingJson`, `satisfiesTildeRange`, `findLocalPackageDir`, `ensureCachedInstall`, `importOptionalLibrary`, `makeDegradedEmitter`). It's pure/near-pure and currently only exercised transitively through e2e degraded-path runs — no test asserts its behavior direc",
94
+ "rawOutputLength": 16613
95
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "trajectoriesRecorded": 654,
3
+ "patternsLearned": 654,
4
+ "signalsProcessed": 0,
5
+ "lastAdaptation": 1783622549806
6
+ }
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: harness-gepa
3
- description: Inspect and audit GEPA genomes via the `@metaharness/darwin/gepa` library entry (darwin 0.8.0) — load/validate a genome (default: the shipped cand-6 promotion), render the system prompt a genome compiles to, or classify failure modes in a run transcript. The `gepaOptimize` loop itself is library-only (bring your own evaluator) and not surfaced here — use `harness-evolve` for sandbox-scored evolution. Degrades gracefully when @metaharness/darwin is absent.
3
+ description: "Inspect and audit GEPA genomes via the `@metaharness/darwin/gepa` library entry (darwin 0.8.0) — load/validate a genome (default is the shipped cand-6 promotion), render the system prompt a genome compiles to, or classify failure modes in a run transcript. The `gepaOptimize` loop itself is library-only (bring your own evaluator) and not surfaced here — use `harness-evolve` for sandbox-scored evolution. Degrades gracefully when @metaharness/darwin is absent."
4
4
  argument-hint: "--op genome|validate|render|analyze [--path <genome.json>] [--transcript <t.json>] [--alert-on-invalid]"
5
5
  allowed-tools: Bash
6
6
  ---