kenaz 0.3.21 → 0.3.23

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 (481) hide show
  1. package/core/.claude/commands/Ansuz.md +2 -0
  2. package/core/.claude/hooks/__tests__/peer-session-fill.test.js +37 -0
  3. package/core/.claude/hooks/_ansuz-conversation.js +32 -1
  4. package/core/.claude/hooks/_user-scope.js +1 -1
  5. package/core/.claude/hooks/core-resolve.js +1 -1
  6. package/core/.claude/hooks/peer-optin.test.js +74 -0
  7. package/core/.claude/hooks/peer-session-fill.js +38 -0
  8. package/core/.claude/hooks/turn-context.js +5 -4
  9. package/core/.claude/hooks/worktree-create.js +6 -6
  10. package/core/.claude/hooks/worktree-remove.js +4 -4
  11. package/core/.claude/settings.json +9 -0
  12. package/core/.collaboration/core/reconcile.js +16 -1
  13. package/core/.collaboration/core/task-2467-lifecycle.test.js +63 -0
  14. package/core/.collaboration/core/task-api.js +37 -7
  15. package/core/.formation/bifrost/launch.js +1 -1
  16. package/core/.formation/bifrost/openai/codex-hook-shim.js +21 -4
  17. package/core/.formation/bifrost/openai/codex-peer-pull.test.js +42 -0
  18. package/core/.formation/bifrost/provider-launch.js +2 -1
  19. package/core/.formation/tools/kenaz-stats.js +1 -1
  20. package/core/.formation/tools/post-complete/git-merge.js +1 -1
  21. package/core/.formation/tools/prompt.js +1 -1
  22. package/core/.kenaz/specialist/ansuz_rules.yaml +7 -51
  23. package/core/.kenaz/specialist/ansuz_session_handoff.schema.json +2 -6
  24. package/core/.rule/general/project-self-containment.yaml +2 -2
  25. package/core/.specialist/Amelia/README.md +1 -1
  26. package/core/.specialist/Amelia/rule.yaml +1 -1
  27. package/core/.specialist/Ansuz/RULES.md +1 -1
  28. package/core/.specialist/Ansuz/concepts/commitment_layer.yaml +1 -1
  29. package/core/.specialist/Ansuz/concepts/evolvable_guardrails.yaml +1 -1
  30. package/core/.specialist/Ansuz/knowledge.yaml +1 -3
  31. package/core/.specialist/tools/__tests__/task-2409-lessons.test.js +10 -0
  32. package/core/.specialist/tools/__tests__/task-2427-harvest.test.js +25 -0
  33. package/core/.specialist/tools/ansuz-boot-fast.js +1 -1
  34. package/core/.specialist/tools/failure-detector.js +4 -4
  35. package/core/.specialist/tools/handoff-doc.js +1 -1
  36. package/core/.specialist/tools/lessons.js +2 -2
  37. package/core/CLAUDE.md +5 -5
  38. package/core/KENAZ_CORE_VERSION +1 -1
  39. package/core/dashboard/scripts/install-kenaz-cli.js +471 -0
  40. package/core/dev/scripts/check-file-size.js +1 -1
  41. package/core/dev/scripts/ci-feedback.js +1 -1
  42. package/core/dev/scripts/gc-agent-worktrees.js +11 -11
  43. package/core/dev/scripts/kenaz-session.js +3 -3
  44. package/core/dev/scripts/peer-identity-e2e.js +3 -3
  45. package/core/dev/scripts/run-rust-tests.js +2 -2
  46. package/core/dev/scripts/skill-routing-replay.js +3 -3
  47. package/core/dev/scripts/task1961/selftest.js +2 -2
  48. package/core/dev/scripts/windows-hide-guard.test.js +97 -0
  49. package/core/plugins/kenaz/commands/Ansuz.md +2 -0
  50. package/core/plugins/kenaz/guidance.md +2 -0
  51. package/core/plugins/kenaz/hooks/core-resolve.js +1 -1
  52. package/core/plugins/kenaz/hooks/hooks.json +9 -0
  53. package/core/plugins/kenaz/hooks/kenaz-hook.js +53 -4
  54. package/core/plugins/kenaz/scripts/kenaz.test.js +72 -5
  55. package/core/plugins/kenaz/scripts/ygg.js +40 -4
  56. package/core/plugins/kenaz/scripts/ygg.test.js +63 -3
  57. package/core/plugins/kenaz-peer/hooks/register.test.ts +59 -2
  58. package/core/plugins/kenaz-peer/hooks/register.ts +24 -1
  59. package/lib/cli.js +9 -5
  60. package/package.json +6 -6
  61. package/vendor/install-kenaz-cli.js +21 -6
  62. package/core/.kenaz/designs/METAPLASTICITY_CONFIDENCE_DESIGN.md +0 -537
  63. package/core/.kenaz/designs/REFLEX_INITIATOR_DESIGN.md +0 -501
  64. package/core/.kenaz/designs/TASK_1385_handoff_mcp_design.md +0 -426
  65. package/core/.kenaz/designs/TASK_932_hippocampus_consolidation.md +0 -103
  66. package/core/.kenaz/designs/TASK_934_efe_signal_engine.md +0 -97
  67. package/core/.kenaz/designs/TASK_935_self_evolution_framework.md +0 -154
  68. package/core/.kenaz/designs/VISION_cognitive_architecture_roadmap.md +0 -159
  69. package/core/.kenaz/designs/metaplasticity_simulation_results.json +0 -696
  70. package/core/.kenaz/main-memory/README.md +0 -230
  71. package/core/.kenaz/main-memory/kenaz/cortex/001_cortex_overview.md +0 -168
  72. package/core/.kenaz/main-memory/kenaz/cortex/001_rag_engine_overview.md +0 -30
  73. package/core/.kenaz/main-memory/kenaz/memory-system/001_three_tier_architecture.md +0 -361
  74. package/core/.kenaz/main-memory/kenaz/pipeline/001_task_execution_flow.md +0 -117
  75. package/core/.kenaz/main-memory/kenaz/pipeline/001_task_granularity.md +0 -154
  76. package/core/.kenaz/main-memory/kenaz/pipeline/002_team_priority.md +0 -51
  77. package/core/.kenaz/main-memory/kenaz/pipeline/003_feature_id_system.md +0 -46
  78. package/core/.kenaz/main-memory/kenaz/rules/001_gen_007_self_containment.md +0 -108
  79. package/core/.kenaz/main-memory/kenaz/rules/001_rule_priority_system.md +0 -121
  80. package/core/.kenaz/main-memory/kenaz/rules/002_agt_006_pre_check.md +0 -0
  81. package/core/.kenaz/main-memory/kenaz/rules/003_ppl_002_task_archival.md +0 -48
  82. package/core/.kenaz/main-memory/kenaz/system/001_dual_track_task_system.md +0 -197
  83. package/core/.kenaz/main-memory/knowledge/patterns/001_json_bom_issue.md +0 -78
  84. package/core/.kenaz/main-memory/knowledge/patterns/001_leader_worker_pattern.md +0 -0
  85. package/core/.kenaz/main-memory/knowledge/patterns/002_scope_path_conflict.md +0 -115
  86. package/core/.kenaz/main-memory/knowledge/patterns/002_task_dependency_resolution.md +0 -223
  87. package/core/.kenaz/main-memory/knowledge/patterns/003_question_protocol.md +0 -242
  88. package/core/.kenaz/main-memory/knowledge/patterns/004_user_insight_value.md +0 -111
  89. package/core/.kenaz/main-memory/knowledge/patterns/005_file_lock_pattern.md +0 -274
  90. package/core/.kenaz/main-memory/knowledge/references/001_ppl_rules.md +0 -28
  91. package/core/.kenaz/main-memory/knowledge/solutions/001_json_bom_issue.md +0 -137
  92. package/core/.kenaz/main-memory/knowledge/solutions/001_team_invocation.md +0 -0
  93. package/core/.kenaz/main-memory/knowledge/solutions/002_passive_monitoring.md +0 -0
  94. package/core/.kenaz/main-memory/knowledge/solutions/003_windows_file_race_condition.md +0 -239
  95. package/core/.kenaz/main-memory/registry.json +0 -326
  96. package/core/.kenaz/main-memory/version.yaml +0 -58
  97. package/core/.kenaz/specialist/memory_guard_fired.json +0 -1
  98. package/core/.kenaz/specialist/memory_guard_trigger_cache.json +0 -1
  99. package/core/.kenaz/specialist/memory_source_priority.yaml +0 -260
  100. package/core/.kenaz/specialist/prompt_1775.txt +0 -317
  101. package/core/.kenaz/specialist/prompt_1776.txt +0 -326
  102. package/core/.kenaz/specialist/prompt_1791.txt +0 -320
  103. package/core/.kenaz/specialist/prompt_1792.txt +0 -320
  104. package/core/.kenaz/specialist/prompt_1795.txt +0 -281
  105. package/core/.kenaz/specialist/prompt_1813.txt +0 -332
  106. package/core/.kenaz/specialist/prompt_1814.txt +0 -401
  107. package/core/.kenaz/specialist/prompt_1815.txt +0 -394
  108. package/core/.kenaz/specialist/prompt_1816.txt +0 -437
  109. package/core/.kenaz/specialist/prompt_1818.txt +0 -361
  110. package/core/.kenaz/specialist/prompt_1819.txt +0 -421
  111. package/core/.kenaz/specialist/prompt_1821.txt +0 -345
  112. package/core/.kenaz/specialist/prompt_1822.txt +0 -313
  113. package/core/.kenaz/specialist/prompt_1824.txt +0 -348
  114. package/core/.kenaz/specialist/prompt_1826.txt +0 -388
  115. package/core/.kenaz/specialist/rune_efe_salience_gap.md +0 -21
  116. package/core/.kenaz/specialist/task1825_update.json +0 -43
  117. package/core/.kenaz/specialist/taskgen/consolidation_i.json +0 -38
  118. package/core/.kenaz/specialist/taskgen/csharp_a.json +0 -44
  119. package/core/.kenaz/specialist/taskgen/csharp_b.json +0 -40
  120. package/core/.kenaz/specialist/taskgen/embedding_e.json +0 -34
  121. package/core/.kenaz/specialist/taskgen/hygiene_fg.json +0 -39
  122. package/core/.kenaz/specialist/taskgen/pathology_h.json +0 -36
  123. package/core/.kenaz/specialist/taskgen/unity_noise_d.json +0 -38
  124. package/core/.kenaz/specialist/taskgen/visibility_c.json +0 -38
  125. package/core/.specialist/Ansuz/decisions/ADR-requirement-graph-layer.md +0 -390
  126. package/core/.specialist/Ansuz/self_model_seed.backup.json +0 -100
  127. package/core/.specialist/ansuz_session_handoff.json +0 -96
  128. package/core/dev/ALAYA_FIELD_FEEDBACK_DESIGN.md +0 -126
  129. package/core/dev/ANSUZ_SCAFFOLD_DIET_2026-09-20.md +0 -231
  130. package/core/dev/ANSUZ_STARTUP_INJECTION_REVIEW.md +0 -355
  131. package/core/dev/ANSUZ_WORKFLOW_MODERNIZATION.md +0 -143
  132. package/core/dev/CORTEX_META_GRAPH_ASSESSMENT.md +0 -99
  133. package/core/dev/FREYA_DOWNSTREAM_BUGS_2026-09-19.md +0 -44
  134. package/core/dev/GLOBAL_MEMORY_IDENTITY_CONSOLIDATION.md +0 -263
  135. package/core/dev/GUARD_EFFECTIVENESS_DESIGN.md +0 -180
  136. package/core/dev/HEALTH_GATE_VARIANCE_ASSESSMENT.md +0 -271
  137. package/core/dev/HOOK_DIET_2026-09-21.md +0 -126
  138. package/core/dev/JEV_INTEGRATION_PLAN.md +0 -189
  139. package/core/dev/KENAZ_AGENT_CONNECT_v1_SPEC.md +0 -139
  140. package/core/dev/MOBILE_DESIGN_SPEC.md +0 -569
  141. package/core/dev/MULTI_ANSUZ_SPEC.md +0 -136
  142. package/core/dev/MUNINN_RETIREMENT.md +0 -115
  143. package/core/dev/PHASE3_ATTRIBUTION_POPULATION_DIAGNOSIS.md +0 -211
  144. package/core/dev/PHASE3_P3-2B_TASKLEVEL_PROBE.md +0 -83
  145. package/core/dev/PHASE3_P3-2_POPULATION_DISJOINTNESS.md +0 -83
  146. package/core/dev/PHASE3_P3-2_REMEASURE_REPORT.md +0 -231
  147. package/core/dev/PREDICTION_GROUNDING_DESIGN.md +0 -376
  148. package/core/dev/PRODUCT_SPEC.md +0 -317
  149. package/core/dev/PROJECT_REGISTRY_DUPLICATE_ASSESSMENT.md +0 -86
  150. package/core/dev/STARTUP_TIMELINE_TASK_1995.md +0 -181
  151. package/core/dev/SYNAPSE_WORKER_PER_PROJECT.md +0 -881
  152. package/core/dev/TASK_1680_P3-3_DISPATCH_SPEC.md +0 -96
  153. package/core/dev/TASK_1684_CALIBRATION_IMPACT_ANALYSIS.md +0 -170
  154. package/core/dev/TASK_1684_FORK_A_GOODHART_DESIGN.md +0 -171
  155. package/core/dev/TASK_1684_P3_2_REMEASURE_VALIDATION.md +0 -262
  156. package/core/dev/TASK_1903_SIGNAL_AUC_MEASUREMENT.md +0 -207
  157. package/core/dev/TASK_1904_BRANCH_INTEGRITY_AUDIT.md +0 -146
  158. package/core/dev/ansuz-eval/README.md +0 -38
  159. package/core/dev/ansuz-eval/build-fixtures.js +0 -87
  160. package/core/dev/ansuz-eval/grade.js +0 -96
  161. package/core/dev/ansuz-eval/grader.test.js +0 -117
  162. package/core/dev/ansuz-eval/tasks.md +0 -32
  163. package/core/dev/archive/ansuz/BOOT_FULL.md +0 -141
  164. package/core/dev/archive/ansuz/agents/ansuz-boot.md +0 -176
  165. package/core/dev/archive/ansuz/designs/alaya-passive-surfacing.md +0 -84
  166. package/core/dev/archive/ansuz/designs/cc_memory_indexing.md +0 -307
  167. package/core/dev/archive/ansuz/designs/check_guard.md +0 -322
  168. package/core/dev/archive/ansuz/designs/consequence_loop.md +0 -227
  169. package/core/dev/archive/ansuz/designs/mcp_kuzudb_lock_architecture.md +0 -312
  170. package/core/dev/archive/ansuz/designs/phase0_git_enrichment.md +0 -278
  171. package/core/dev/archive/ansuz/designs/refactor_mcp_tools_synapse.md +0 -490
  172. package/core/dev/archive/ansuz/designs/semantic_markdown_extraction.md +0 -167
  173. package/core/dev/archive/ansuz/designs/task_1372_prompt_injects_into.md +0 -193
  174. package/core/dev/archive/ansuz/designs/thought_stack.md +0 -286
  175. package/core/dev/archive/ansuz/investigations/reachability_unified_api_2026-04-11.md +0 -330
  176. package/core/dev/archive/ansuz/investigations/synapse_orphans_indexing_bug_2026-04-11.md +0 -352
  177. package/core/dev/archive/ansuz/investigations/synapse_orphans_reindex_verification_2026-04-11.md +0 -48
  178. package/core/dev/archive/ansuz/investigations/synapse_orphans_verification_2026-04-11.md +0 -170
  179. package/core/dev/archive/ansuz/legacy/kernel.yaml +0 -399
  180. package/core/dev/archive/ansuz/legacy/phases/phase_0.yaml +0 -418
  181. package/core/dev/archive/ansuz/legacy/phases/phase_1.yaml +0 -376
  182. package/core/dev/archive/ansuz/legacy/phases/phase_10.yaml +0 -35
  183. package/core/dev/archive/ansuz/legacy/phases/phase_11.yaml +0 -582
  184. package/core/dev/archive/ansuz/legacy/phases/phase_2.yaml +0 -94
  185. package/core/dev/archive/ansuz/legacy/phases/phase_3.yaml +0 -274
  186. package/core/dev/archive/ansuz/legacy/phases/phase_4.yaml +0 -67
  187. package/core/dev/archive/ansuz/legacy/phases/phase_5.yaml +0 -32
  188. package/core/dev/archive/ansuz/legacy/phases/phase_6.yaml +0 -91
  189. package/core/dev/archive/ansuz/legacy/phases/phase_7.yaml +0 -58
  190. package/core/dev/archive/ansuz/legacy/phases/phase_8.yaml +0 -146
  191. package/core/dev/archive/ansuz/legacy/phases/phase_9.yaml +0 -424
  192. package/core/dev/archive/ansuz/specs/INDEX_bifrost_hook_parity.yaml +0 -92
  193. package/core/dev/archive/ansuz/specs/active-inference-formation.yaml +0 -453
  194. package/core/dev/archive/ansuz/specs/brief_TASK_1228_userpromptsubmit.yaml +0 -191
  195. package/core/dev/archive/ansuz/specs/brief_TASK_1229_pretooluse_posttooluse.yaml +0 -250
  196. package/core/dev/archive/ansuz/specs/brief_TASK_1230_sessionstart_stop.yaml +0 -301
  197. package/core/dev/archive/ansuz/specs/brief_TASK_1231_verification.yaml +0 -272
  198. package/core/dev/archive/skills/feature_agent/SKILL.md +0 -289
  199. package/core/dev/design/PHASE4_DESIGN.md +0 -559
  200. package/core/dev/design/dashboard_docs_integration_PLAN.md +0 -388
  201. package/core/dev/design/matrix_format_ABBREVIATIONS.md +0 -655
  202. package/core/dev/design/matrix_format_DESIGN_SPEC.md +0 -601
  203. package/core/dev/design/matrix_format_DISCUSSION_SUMMARY.md +0 -484
  204. package/core/dev/design/matrix_format_EXAMPLE_memory.matrix +0 -13
  205. package/core/dev/design/matrix_format_EXAMPLE_project_status.matrix +0 -9
  206. package/core/dev/design/matrix_format_EXAMPLE_tasks.matrix +0 -14
  207. package/core/dev/design/matrix_format_SYNTAX_BNF.md +0 -754
  208. package/core/dev/design/matrix_format_TOKEN_COMPARISON.md +0 -484
  209. package/core/dev/design/matrix_v2_COGNITIVE_DESIGN.md +0 -503
  210. package/core/dev/design/matrix_v2_DISCUSSION_SUMMARY.md +0 -414
  211. package/core/dev/design/matrix_v2_EXAMPLE.matrix +0 -67
  212. package/core/dev/designs/EXPANDABLE_CARD_DESIGN_SPEC.md +0 -509
  213. package/core/dev/jev-eval/ACTIVE_CORRECTION.md +0 -52
  214. package/core/dev/jev-eval/ANNOTATION_GUIDE.md +0 -68
  215. package/core/dev/jev-eval/BASELINE_COMPARISON.md +0 -45
  216. package/core/dev/jev-eval/CONTEXT_REVIEW.md +0 -31
  217. package/core/dev/jev-eval/EVALUATION_STATUS.md +0 -39
  218. package/core/dev/jev-eval/HISTORICAL_CORPUS.md +0 -33
  219. package/core/dev/jev-eval/PACKAGING_VERIFICATION.md +0 -42
  220. package/core/dev/jev-eval/README.md +0 -101
  221. package/core/dev/jev-eval/THALAMUS_RANKING.md +0 -58
  222. package/core/dev/jev-eval/VALIDATION_PROGRESS.md +0 -54
  223. package/core/dev/jev-eval/cli.mjs +0 -50
  224. package/core/dev/jev-eval/context.mjs +0 -183
  225. package/core/dev/jev-eval/corpus.mjs +0 -186
  226. package/core/dev/jev-eval/fixtures/conversation-review.seed.jsonl +0 -6
  227. package/core/dev/jev-eval/fixtures/synthetic.jsonl +0 -11
  228. package/core/dev/jev-eval/metrics.mjs +0 -67
  229. package/core/dev/jev-eval/muninn-baseline.mjs +0 -119
  230. package/core/dev/jev-eval/providers.mjs +0 -95
  231. package/core/dev/jev-eval/reports/annotation-pilot-2026-09-20.json +0 -32
  232. package/core/dev/jev-eval/reports/context-review-2026-09-20.json +0 -48
  233. package/core/dev/jev-eval/reports/conversation-review.pending.json +0 -151
  234. package/core/dev/jev-eval/reports/history-corpus-2026-09-20.json +0 -52
  235. package/core/dev/jev-eval/reports/length-probe-2026-09-20.json +0 -133
  236. package/core/dev/jev-eval/reports/live-smoke-2026-09-20.json +0 -616
  237. package/core/dev/jev-eval/reports/muninn-baseline-2026-09-20.json +0 -52
  238. package/core/dev/jev-eval/reports/resilience-2026-09-20.json +0 -520
  239. package/core/dev/jev-eval/reports/rules-baseline.json +0 -197
  240. package/core/dev/jev-eval/reports/synthetic-review.pending.json +0 -357
  241. package/core/dev/jev-eval/resilience.mjs +0 -71
  242. package/core/dev/jev-eval/review.mjs +0 -78
  243. package/core/dev/jev-eval/schema.mjs +0 -87
  244. package/core/dev/jev-eval/test/context.test.mjs +0 -95
  245. package/core/dev/jev-eval/test/corpus.test.mjs +0 -102
  246. package/core/dev/jev-eval/test/eval.test.mjs +0 -146
  247. package/core/dev/jev-eval/test/muninn-baseline.test.mjs +0 -71
  248. package/core/dev/jev-eval/test/resilience.test.mjs +0 -72
  249. package/core/dev/jev-eval/test/review.test.mjs +0 -61
  250. package/core/dev/pipeline/PHASE3_PLANNING_SUMMARY.md +0 -338
  251. package/core/dev/pipeline/PROGRESS.md +0 -113
  252. package/core/dev/pipeline/PROGRESS_template.md +0 -860
  253. package/core/dev/pipeline/QA_REPORT_F008.md +0 -431
  254. package/core/dev/pipeline/QA_REPORT_LOCAL_CLAUDE_DIAGNOSIS.md +0 -583
  255. package/core/dev/pipeline/README.md +0 -210
  256. package/core/dev/pipeline/WORKFLOW_GUIDE.md +0 -824
  257. package/core/dev/pipeline/archived/TASK_015_tauri_init.yaml +0 -53
  258. package/core/dev/pipeline/archived/TASK_016_tauri_commands.yaml +0 -54
  259. package/core/dev/pipeline/archived/TASK_017_rust_pty.yaml +0 -54
  260. package/core/dev/pipeline/archived/TASK_018_tauri_bundle.yaml +0 -53
  261. package/core/dev/pipeline/archived/TASK_019_release_workflow.yaml +0 -56
  262. package/core/dev/pipeline/archived/TASK_020_update_ui.yaml +0 -54
  263. package/core/dev/pipeline/archived/TASK_021_update_notification_ui.yaml +0 -55
  264. package/core/dev/pipeline/archived/TASK_022_remove_node_pty.yaml +0 -65
  265. package/core/dev/pipeline/archived/TASK_023_api_routes_migration.yaml +0 -86
  266. package/core/dev/pipeline/archived/TASK_024_feature_id_system.yaml +0 -51
  267. package/core/dev/pipeline/archived/TASK_025_executable_acceptance.yaml +0 -66
  268. package/core/dev/pipeline/archived/TASK_026_spec_versioning.yaml +0 -56
  269. package/core/dev/pipeline/archived/TASK_027_drift_detection.yaml +0 -60
  270. package/core/dev/pipeline/archived/TASK_028_tauri_pty_manager.yaml +0 -60
  271. package/core/dev/pipeline/archived/TASK_029_tauri_pty_commands.yaml +0 -62
  272. package/core/dev/pipeline/archived/TASK_030_frontend_session_adapter.yaml +0 -54
  273. package/core/dev/pipeline/archived/TASK_031_terminal_tauri_events.yaml +0 -56
  274. package/core/dev/pipeline/archived/TASK_041_scheduler_data_models.yaml +0 -54
  275. package/core/dev/pipeline/archived/TASK_042_path_lock_manager.yaml +0 -53
  276. package/core/dev/pipeline/archived/TASK_043_process_manager.yaml +0 -57
  277. package/core/dev/pipeline/archived/TASK_044_git_integration.yaml +0 -85
  278. package/core/dev/pipeline/archived/TASK_045_task_queue_manager.yaml +0 -54
  279. package/core/dev/pipeline/archived/TASK_046_scheduler_dispatcher.yaml +0 -60
  280. package/core/dev/pipeline/archived/TASK_047_tauri_scheduler_commands.yaml +0 -55
  281. package/core/dev/pipeline/archived/TASK_048_realtime_status_push.yaml +0 -92
  282. package/core/dev/pipeline/archived/TASK_049_frontend_scheduler_integration.yaml +0 -58
  283. package/core/dev/pipeline/archived/TASK_050_error_recovery.yaml +0 -56
  284. package/core/dev/pipeline/archived/TASK_051_optimization_proposals_backend.yaml +0 -53
  285. package/core/dev/pipeline/archived/TASK_052_optimization_proposals_ui.yaml +0 -58
  286. package/core/dev/pipeline/archived/TASK_053_optimization_proposals_diff_view.yaml +0 -54
  287. package/core/dev/pipeline/archived/TASK_054_multi_project_scheduler_state.yaml +0 -76
  288. package/core/dev/pipeline/archived/TASK_055_scheduler_api_project_scope.yaml +0 -64
  289. package/core/dev/pipeline/archived/TASK_056_frontend_scheduler_project_scope.yaml +0 -62
  290. package/core/dev/pipeline/archived/TASK_057_scheduler_module_structure.yaml +0 -54
  291. package/core/dev/pipeline/archived/TASK_058_scheduler_models_extract.yaml +0 -51
  292. package/core/dev/pipeline/archived/TASK_059_scheduler_core_extract.yaml +0 -51
  293. package/core/dev/pipeline/archived/TASK_060_scheduler_commands_extract.yaml +0 -51
  294. package/core/dev/pipeline/archived/TASK_061_scheduler_specialized_commands.yaml +0 -53
  295. package/core/dev/pipeline/archived/TASK_062_process_manager_module_structure.yaml +0 -56
  296. package/core/dev/pipeline/archived/TASK_063_process_manager_core_extract.yaml +0 -56
  297. package/core/dev/pipeline/archived/TASK_064_recovery_module_structure.yaml +0 -57
  298. package/core/dev/pipeline/archived/TASK_065_recovery_core_extract.yaml +0 -56
  299. package/core/dev/pipeline/archived/TASK_066_self_enhancement_scheduler_models.yaml +0 -60
  300. package/core/dev/pipeline/archived/TASK_067_agents_section_quick_actions.yaml +0 -53
  301. package/core/dev/pipeline/archived/TASK_067_self_enhancement_scheduler_core.yaml +0 -65
  302. package/core/dev/pipeline/archived/TASK_068_agent_workflow_rule_enhancement.yaml +0 -46
  303. package/core/dev/pipeline/archived/TASK_068_self_enhancement_tauri_commands.yaml +0 -61
  304. package/core/dev/pipeline/archived/TASK_069_agent_wizard_responsive.yaml +0 -46
  305. package/core/dev/pipeline/archived/TASK_069_self_enhancement_ui.yaml +0 -62
  306. package/core/dev/pipeline/archived/TASK_070_preview_panel_redesign.yaml +0 -62
  307. package/core/dev/pipeline/archived/TASK_070_self_enhancement_integration.yaml +0 -57
  308. package/core/dev/pipeline/archived/TASK_071_preview_panel_qa.yaml +0 -98
  309. package/core/dev/pipeline/archived/TASK_071_single_agent_config.yaml +0 -57
  310. package/core/dev/pipeline/archived/TASK_072_preview_modal_esc_fix.yaml +0 -71
  311. package/core/dev/pipeline/archived/TASK_072_product_review_module.yaml +0 -57
  312. package/core/dev/pipeline/archived/TASK_073_agents_page_component_refactor.yaml +0 -68
  313. package/core/dev/pipeline/archived/TASK_073_rename_single_agent.yaml +0 -64
  314. package/core/dev/pipeline/archived/TASK_074_preview_mode_ui_diagnosis.yaml +0 -71
  315. package/core/dev/pipeline/archived/TASK_074_single_agent_ui_toggle.yaml +0 -56
  316. package/core/dev/pipeline/archived/TASK_075_agents_page_component_refactor.yaml +0 -69
  317. package/core/dev/pipeline/archived/TASK_075_single_agent_integration_test.yaml +0 -75
  318. package/core/dev/pipeline/archived/TASK_076_preview_mode_ui_diagnosis.yaml +0 -70
  319. package/core/dev/pipeline/archived/TASK_076_single_agent_continuous_mode.yaml +0 -65
  320. package/core/dev/pipeline/archived/TASK_077_failure_directory_structure.yaml +0 -51
  321. package/core/dev/pipeline/archived/TASK_077_single_agent_typescript_types.yaml +0 -59
  322. package/core/dev/pipeline/archived/TASK_078_fail_001_agent_no_output.yaml +0 -53
  323. package/core/dev/pipeline/archived/TASK_078_single_agent_ui_simplify.yaml +0 -74
  324. package/core/dev/pipeline/archived/TASK_079_dashboard_rwd_responsive.yaml +0 -63
  325. package/core/dev/pipeline/archived/TASK_079_fail_002_json_bom.yaml +0 -56
  326. package/core/dev/pipeline/archived/TASK_080_fail_003_queue_pollution.yaml +0 -56
  327. package/core/dev/pipeline/archived/TASK_080_http_server_module.yaml +0 -55
  328. package/core/dev/pipeline/archived/TASK_081_failure_logging_tools.yaml +0 -57
  329. package/core/dev/pipeline/archived/TASK_081_http_api_routes.yaml +0 -62
  330. package/core/dev/pipeline/archived/TASK_082_frontend_api_adapter.yaml +0 -51
  331. package/core/dev/pipeline/archived/TASK_082_integrate_failure_to_workflow.yaml +0 -60
  332. package/core/dev/pipeline/archived/TASK_083_cleanup_nextjs_api.yaml +0 -48
  333. package/core/dev/pipeline/archived/TASK_083_task_queue_cleanup.yaml +0 -67
  334. package/core/dev/pipeline/archived/TASK_084_rust_dead_code_cleanup.yaml +0 -66
  335. package/core/dev/pipeline/archived/TASK_084_scheduler_sync_logic_fix.yaml +0 -68
  336. package/core/dev/pipeline/archived/TASK_085_http_api_web_mode_fixes.yaml +0 -46
  337. package/core/dev/pipeline/archived/TASK_085_memory_consolidation_0204_0205.yaml +0 -98
  338. package/core/dev/pipeline/archived/TASK_086_collapsible_preview_panel.yaml +0 -161
  339. package/core/dev/pipeline/archived/TASK_086_web_mode_feature_parity.yaml +0 -62
  340. package/core/dev/pipeline/archived/TASK_087_manual_memory_archival.yaml +0 -163
  341. package/core/dev/pipeline/archived/TASK_087_mobile_http_control.yaml +0 -68
  342. package/core/dev/pipeline/archived/TASK_088_fail_003_to_ppl_002_rule.yaml +0 -63
  343. package/core/dev/pipeline/archived/TASK_088_mobile_http_qa.yaml +0 -121
  344. package/core/dev/pipeline/archived/TASK_089_agent_collaboration_topic.yaml +0 -60
  345. package/core/dev/pipeline/archived/TASK_089_web_mode_monitor_fix.yaml +0 -58
  346. package/core/dev/pipeline/archived/TASK_090_cli_detection_fix.yaml +0 -61
  347. package/core/dev/pipeline/archived/TASK_090_ui_ux_lessons_topic.yaml +0 -63
  348. package/core/dev/pipeline/archived/TASK_091_expandable_card_design.yaml +0 -56
  349. package/core/dev/pipeline/archived/TASK_091_move_agent_section_components.yaml +0 -65
  350. package/core/dev/pipeline/archived/TASK_092_expandable_card_component.yaml +0 -60
  351. package/core/dev/pipeline/archived/TASK_092_refactor_agent_create_wizard.yaml +0 -84
  352. package/core/dev/pipeline/archived/TASK_093_taskcard_detail_integration.yaml +0 -57
  353. package/core/dev/pipeline/archived/TASK_093_update_barrel_exports_test.yaml +0 -84
  354. package/core/dev/pipeline/archived/TASK_094_ai_agent_generation_enhancement.yaml +0 -115
  355. package/core/dev/pipeline/archived/TASK_094_proposalcard_detail_integration.yaml +0 -55
  356. package/core/dev/pipeline/archived/TASK_095_preview_fixes.yaml +0 -129
  357. package/core/dev/pipeline/archived/TASK_095_single_agent_task_selector.yaml +0 -60
  358. package/core/dev/pipeline/archived/TASK_096_agents_page_ux_improvements.yaml +0 -163
  359. package/core/dev/pipeline/archived/TASK_096_single_agent_status_sync.yaml +0 -60
  360. package/core/dev/pipeline/archived/TASK_097_local_claude_error_logging.yaml +0 -59
  361. package/core/dev/pipeline/archived/TASK_097_single_agent_monitor_events.yaml +0 -59
  362. package/core/dev/pipeline/archived/TASK_098_product_manager_team_phase2.yaml +0 -60
  363. package/core/dev/pipeline/archived/TASK_098_single_agent_refactor_test.yaml +0 -58
  364. package/core/dev/pipeline/archived/TASK_099_backend_team_creation.yaml +0 -258
  365. package/core/dev/pipeline/archived/TASK_100_frontend_team_creation.yaml +0 -61
  366. package/core/dev/pipeline/archived/TASK_101_orchestrator_system.yaml +0 -403
  367. package/core/dev/pipeline/archived/TASK_102_designer_sre_teams.yaml +0 -90
  368. package/core/dev/pipeline/archived/TASK_103_integration_testing.yaml +0 -86
  369. package/core/dev/pipeline/archived/TASK_128_integration_testing.yaml +0 -83
  370. package/core/dev/pipeline/archived/TASK_134_cortex_v2_phase3_file_watcher.yaml +0 -65
  371. package/core/dev/pipeline/archived/TASK_134_team_http_api.yaml +0 -96
  372. package/core/dev/pipeline/archived/TASK_135_cortex_v2_phase3_git_monitor.yaml +0 -63
  373. package/core/dev/pipeline/archived/TASK_136_cortex_v2_phase3_change_analyzer.yaml +0 -69
  374. package/core/dev/pipeline/archived/TASK_137_cortex_v2_phase3_cache_invalidator.yaml +0 -67
  375. package/core/dev/pipeline/archived/TASK_137_team_orchestrator_integration.yaml +0 -93
  376. package/core/dev/pipeline/archived/TASK_138_cortex_v2_phase3_distributed_cache.yaml +0 -68
  377. package/core/dev/pipeline/archived/TASK_138_matrix_folder_structure.yaml +0 -61
  378. package/core/dev/pipeline/archived/TASK_139_cortex_v2_phase3_cache_prewarming.yaml +0 -65
  379. package/core/dev/pipeline/archived/TASK_146_unified_documentation.yaml +0 -141
  380. package/core/dev/pipeline/archived/TASK_147_pipeline_execution_rules.yaml +0 -76
  381. package/core/dev/pipeline/archived/TASK_148_update_claude_md.yaml +0 -77
  382. package/core/dev/pipeline/archived/TASK_149_fix_nextjs_mdx_serialization.yaml +0 -63
  383. package/core/dev/pipeline/archived/TASK_149_update_team_docs.yaml +0 -77
  384. package/core/dev/pipeline/archived/TASK_150_pipeline_workflow_guide.yaml +0 -82
  385. package/core/dev/pipeline/archived/TASK_164_fix_smart_context_switch.yaml +0 -49
  386. package/core/dev/pipeline/archived/TASK_165_ctags_symbol_index.yaml +0 -53
  387. package/core/dev/pipeline/archived/TASK_166_symbol_search_mcp_tool.yaml +0 -48
  388. package/core/dev/pipeline/archived/TASK_167_llm_module_summary.yaml +0 -55
  389. package/core/dev/pipeline/archived/TASK_168_map_reduce_context.yaml +0 -51
  390. package/core/dev/pipeline/archived/TASK_169_v2_integration_testing.yaml +0 -52
  391. package/core/dev/pipeline/backups/archive_2026-02-04T22-07-22/TASK_QUEUE_backup.json +0 -95
  392. package/core/dev/pipeline/docs/multi-agent-coordination.md +0 -446
  393. package/core/dev/pipeline/docs/overview.md +0 -406
  394. package/core/dev/pipeline/docs/task-management.md +0 -412
  395. package/core/dev/pipeline/docs/workflows.md +0 -32
  396. package/core/dev/pipeline/orchestrator/schemas/task_queue_schema.json +0 -58
  397. package/core/dev/pipeline/orchestrator/schemas/task_schema.json +0 -139
  398. package/core/dev/pipeline/plans/PLAN_task_cli_refactor.md +0 -281
  399. package/core/dev/pipeline/test_results/TASK_TEST_PARALLEL_002_result.txt +0 -27
  400. package/core/dev/plans/ANSUZ_SLIM_PLAN.md +0 -68
  401. package/core/dev/plans/CLI_FIRST_INSTALL_FLOW.md +0 -120
  402. package/core/dev/plans/FORMATION_RETIREMENT_PLAN.md +0 -313
  403. package/core/dev/plans/KUZU_REPLACEMENT_PLAN.md +0 -126
  404. package/core/dev/scripts/CRASH_DIAGNOSIS.md +0 -47
  405. package/core/dev/scripts/README.md +0 -142
  406. package/core/dev/scripts/RUN_ONCE.bat +0 -40
  407. package/core/dev/scripts/START_DEV_AGENT.bat +0 -63
  408. package/core/dev/scripts/START_MULTI_AGENT.bat +0 -80
  409. package/core/dev/scripts/dev_agent_scheduler.ps1 +0 -536
  410. package/core/dev/scripts/init_git.ps1 +0 -396
  411. package/core/dev/scripts/init_git.sh +0 -337
  412. package/core/dev/scripts/init_project.ps1 +0 -851
  413. package/core/dev/scripts/init_project.sh +0 -477
  414. package/core/dev/scripts/multi_agent_scheduler.ps1 +0 -2021
  415. package/core/dev/scripts/multi_agent_scheduler.sh +0 -1344
  416. package/core/dev/scripts/run_once.sh +0 -47
  417. package/core/dev/scripts/setup_rag.ps1 +0 -304
  418. package/core/dev/scripts/setup_rag.sh +0 -230
  419. package/core/dev/scripts/start_dev_agent.sh +0 -137
  420. package/core/dev/scripts/start_multi_agent.sh +0 -41
  421. package/core/dev/scripts/sync_task_queue.ps1 +0 -505
  422. package/core/dev/scripts/sync_task_queue.sh +0 -392
  423. package/core/dev/specs/agent-connect/PROTOCOL.md +0 -177
  424. package/core/dev/specs/agent-connect/SDK_GUIDE.md +0 -915
  425. package/core/dev/specs/agent-connect/examples/minimal-site/README.md +0 -137
  426. package/core/dev/specs/agent-connect/examples/minimal-site/package.json +0 -12
  427. package/core/dev/specs/agent-connect/examples/minimal-site/public/index.html +0 -116
  428. package/core/dev/specs/agent-connect/examples/minimal-site/public/install-redirect.js +0 -73
  429. package/core/dev/specs/agent-connect/examples/minimal-site/server.js +0 -516
  430. package/core/dev/specs/agent-connect/examples/minimal-site/test/smoke.test.mjs +0 -263
  431. package/core/dev/specs/agent-connect/history/DEFECT_REPORT_kenaz-agent-hub_2026-09-09_v0.4-empty-prompt-no-first-turn.md +0 -77
  432. package/core/dev/specs/agent-connect/history/DEFECT_REPORT_kenaz-agent-hub_2026-09-09_v0.4-prompt-mojibake.md +0 -90
  433. package/core/dev/specs/agent-connect/history/FEATURE_REQUEST_kenaz-agent-hub_2026-09-07.md +0 -61
  434. package/core/dev/specs/agent-connect/history/FEATURE_REQUEST_kenaz-agent-hub_2026-09-08_relay-v1-conformance.md +0 -76
  435. package/core/dev/specs/agent-connect/history/FEATURE_REQUEST_kenaz-agent-hub_2026-09-09_v0.4-session-channel.md +0 -87
  436. package/core/dev/specs/agent-connect/history/FLOWPIX_REPLY_agent-hub_2026-09-08_relay-v1-answers.md +0 -68
  437. package/core/dev/specs/agent-connect/history/FLOWPIX_bridge_CONTRACT.md +0 -642
  438. package/core/dev/specs/agent-connect/history/FLOWPIX_spikes_relay_spike_relay.mjs +0 -244
  439. package/core/dev/specs/agent-connect/history/KENAZ_RESPONSE_agent-hub_2026-09-07.md +0 -77
  440. package/core/dev/specs/agent-connect/history/KENAZ_RESPONSE_agent-hub_2026-09-08_direction-change-v0.3.md +0 -44
  441. package/core/dev/specs/agent-connect/history/KENAZ_RESPONSE_agent-hub_2026-09-08_relay-v1-answers-ack.md +0 -37
  442. package/core/dev/specs/agent-connect/history/KENAZ_RESPONSE_agent-hub_2026-09-08_relay-v1-conformance.md +0 -56
  443. package/core/dev/specs/agent-connect/history/KENAZ_RESPONSE_agent-hub_2026-09-09_annotations-install-coldstart.md +0 -44
  444. package/core/dev/specs/agent-connect/history/KENAZ_RESPONSE_agent-hub_2026-09-09_empty-prompt-first-turn.md +0 -56
  445. package/core/dev/specs/agent-connect/history/KENAZ_RESPONSE_agent-hub_2026-09-09_prompt-mojibake-fixed.md +0 -48
  446. package/core/dev/specs/agent-connect/history/KENAZ_RESPONSE_agent-hub_2026-09-09_session-channel.md +0 -57
  447. package/core/dev/specs/agent-connect/history/PROTOCOL_v0.3_snapshot.md +0 -379
  448. package/core/dev/specs/agent-connect/history/README.md +0 -47
  449. package/core/dev/specs/peer/CODEX_INTERACTIVE_PUSH.md +0 -65
  450. package/core/dev/specs/peer/CODEX_MANAGED_DAEMON.md +0 -54
  451. package/core/dev/specs/peer/CODEX_PEER_PULL_SPIKE.md +0 -54
  452. package/core/dev/specs/peer/MODS_SPIKE.md +0 -133
  453. package/core/dev/specs/peer/PER_PROJECT_ADDRESSING.md +0 -143
  454. package/core/dev/specs/peer/SWARM_PROTOCOLS.md +0 -256
  455. package/core/dev/specs/peer/codex-hook-shim-peer.test.js +0 -113
  456. package/core/dev/specs/peer/codex-push-launcher.test.js +0 -142
  457. package/core/dev/specs/peer/setup-codex-hooks.test.js +0 -60
  458. package/core/dev/specs/peer-ansuz/DELIVERY_SPIKE.md +0 -397
  459. package/core/dev/specs/peer-ansuz/DESIGN.md +0 -109
  460. package/core/dev/specs/peer-ansuz/spike/claude_poke.js +0 -129
  461. package/core/dev/specs/peer-ansuz/spike/claude_session_start_hook.js +0 -37
  462. package/core/dev/specs/peer-ansuz/spike/claude_settings_hook.json +0 -14
  463. package/core/dev/specs/peer-ansuz/spike/codex_appserver_client.js +0 -105
  464. package/core/dev/specs/peer-ansuz/spike/codex_appserver_query.js +0 -29
  465. package/core/dev/specs/peer-ansuz/spike/extract_timeline.js +0 -26
  466. package/core/dev/specs/synapse/SYMBOL_IDENTITY.md +0 -305
  467. package/core/dev/spikes/A4-cypher-varlen.md +0 -176
  468. package/core/dev/spikes/bloat-rounds.sh +0 -25
  469. package/core/dev/spikes/mods/clean-claude.js +0 -9
  470. package/core/dev/spikes/mods/drive-probe.js +0 -29
  471. package/core/dev/spikes/mods/e2e-peer.js +0 -71
  472. package/core/dev/spikes/mods/evidence/e2e-peer-control.json +0 -17
  473. package/core/dev/spikes/mods/evidence/e2e-peer-mod.json +0 -17
  474. package/core/dev/spikes/mods/evidence/probe-006a6e65-d807-4bc1-b648-fd7d1edfe0b4.jsonl +0 -4
  475. package/core/dev/spikes/mods/evidence/probe-cebdf1f7-f9c4-47a8-83cd-7c0786177404.jsonl +0 -12
  476. package/core/dev/spikes/mods/evidence/probe-eb21147d-10ce-4c32-93ed-37ca37d88d5a.jsonl +0 -11
  477. package/core/dev/spikes/mods/evidence/stream-cebdf1f7.jsonl +0 -18
  478. package/core/dev/spikes/mods/kenaz-mod-probe/.claude-plugin/plugin.json +0 -1
  479. package/core/dev/spikes/mods/kenaz-mod-probe/hooks/hooks.json +0 -1
  480. package/core/dev/spikes/mods/kenaz-mod-probe/hooks/register.ts +0 -65
  481. package/core/dev/spikes/mods/kenaz-mod-probe/tsconfig.json +0 -3
@@ -1,78 +0,0 @@
1
- import { createHash, randomUUID } from 'node:crypto';
2
- import { readFile, stat, writeFile, link, unlink } from 'node:fs/promises';
3
- import { resolve } from 'node:path';
4
- import { fileURLToPath } from 'node:url';
5
- import { check, keys, identity, stateHash, readJsonl, validateDataset, MAX_FILE_BYTES } from './schema.mjs';
6
-
7
- export const REVIEW_VERSION = 'jev-review-v1';
8
- const canonical = value => JSON.stringify(value, function (key, item) {
9
- return item && typeof item === 'object' && !Array.isArray(item) ? Object.fromEntries(Object.keys(item).sort().map(k => [k, item[k]])) : item;
10
- });
11
- export const datasetHash = rows => createHash('sha256').update(canonical(rows)).digest('hex');
12
- export function exportReview(rows) {
13
- validateDataset(rows);
14
- return { schema_version: 1, review_version: REVIEW_VERSION, dataset_hash: datasetHash(rows), items: rows.map(row => ({
15
- ...identity(row), state_hash: stateHash(row), purpose: row.purpose, language: row.language, context: structuredClone(row.state),
16
- ...(row.purpose === 'relevance' ? { candidates: row.candidates.map(({ id, text }) => ({ id, text })) } : {}),
17
- decision: row.purpose === 'correction' ? { correction: null } : { grades: row.candidates.map(c => ({ id: c.id, grade: null })) },
18
- reviewed: false, reviewer: null, reviewed_at: null,
19
- })) };
20
- }
21
- function validTime(value) {
22
- if (typeof value !== 'string' || !/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{3})?Z$/.test(value)) return false;
23
- const time = Date.parse(value);
24
- return Number.isFinite(time) && new Date(time).toISOString() === value.replace(/(?<!\.\d{3})Z$/, '.000Z');
25
- }
26
- export function applyReview(rows, review) {
27
- const expected = exportReview(rows);
28
- keys(review, ['schema_version', 'review_version', 'dataset_hash', 'items']);
29
- check(review.schema_version === 1 && review.review_version === REVIEW_VERSION, 'invalid_review_version');
30
- check(review.dataset_hash === expected.dataset_hash, 'stale_dataset');
31
- check(Array.isArray(review.items) && review.items.length === rows.length, 'incomplete_review');
32
- const byId = new Map();
33
- for (const item of review.items) { check(item && !byId.has(item.id), 'duplicate_review'); byId.set(item.id, item); }
34
- const result = rows.map((row, index) => {
35
- const item = byId.get(row.id), base = expected.items[index]; keys(item, Object.keys(base));
36
- for (const key of Object.keys(base).filter(k => !['decision', 'reviewed', 'reviewer', 'reviewed_at'].includes(k))) check(canonical(item[key]) === canonical(base[key]), 'review_identity_mismatch');
37
- check(item.reviewed === true, 'unreviewed_item');
38
- check(typeof item.reviewer === 'string' && item.reviewer.trim().length > 0 && item.reviewer.length <= 160, 'invalid_reviewer');
39
- check(validTime(item.reviewed_at), 'invalid_review_date');
40
- const out = structuredClone(row);
41
- if (row.purpose === 'correction') { keys(item.decision, ['correction']); check(typeof item.decision.correction === 'boolean', 'invalid_review_decision'); out.labels.correction = item.decision.correction; }
42
- else {
43
- keys(item.decision, ['grades']);
44
- check(Array.isArray(item.decision.grades) && item.decision.grades.length === row.candidates.length, 'incomplete_grades');
45
- const grades = new Map();
46
- for (const c of item.decision.grades) { keys(c, ['id', 'grade']); check(!grades.has(c.id) && row.candidates.some(x => x.id === c.id) && Number.isInteger(c.grade) && c.grade >= 0 && c.grade <= 3, 'invalid_review_grade'); grades.set(c.id, c.grade); }
47
- for (const c of out.candidates) c.grade = grades.get(c.id);
48
- }
49
- out.provenance = { ...out.provenance, annotation: 'human_verified', reviewer: item.reviewer, reviewed_at: item.reviewed_at };
50
- return out;
51
- });
52
- return validateDataset(result);
53
- }
54
- export async function main(args = process.argv.slice(2)) {
55
- const [command, ...rest] = args; check(['export', 'apply'].includes(command), 'invalid_command');
56
- const options = {};
57
- for (let i = 0; i < rest.length; i += 2) { check(['--dataset', '--out', ...(command === 'apply' ? ['--reviews'] : [])].includes(rest[i]) && typeof rest[i + 1] === 'string' && !rest[i + 1].startsWith('--') && !Object.hasOwn(options, rest[i]), 'invalid_arguments'); options[rest[i]] = rest[i + 1]; }
58
- check(options['--dataset'] && options['--out'] && (command !== 'apply' || options['--reviews']), 'missing_argument');
59
- check(resolve(options['--dataset']).toLowerCase() !== resolve(options['--out']).toLowerCase() && (!options['--reviews'] || resolve(options['--reviews']).toLowerCase() !== resolve(options['--out']).toLowerCase()), 'overwrite_forbidden');
60
- const rows = validateDataset(await readJsonl(options['--dataset']));
61
- let output;
62
- if (command === 'export') output = JSON.stringify(exportReview(rows), null, 2) + '\n';
63
- else {
64
- check((await stat(options['--reviews'])).size <= MAX_FILE_BYTES, 'file_budget_exceeded');
65
- const text = await readFile(options['--reviews'], 'utf8'); check(Buffer.byteLength(text) <= MAX_FILE_BYTES, 'file_budget_exceeded');
66
- let review; try { review = JSON.parse(text.replace(/^\uFEFF/, '')); } catch { throw new Error('invalid_review_json'); }
67
- output = applyReview(rows, review).map(r => JSON.stringify(r)).join('\n') + '\n';
68
- }
69
- check(Buffer.byteLength(output) <= MAX_FILE_BYTES, 'file_budget_exceeded');
70
- // A same-directory hard link publishes only the complete file, and fails if out exists.
71
- const temporary = `${options['--out']}.${randomUUID()}.tmp`;
72
- try { await writeFile(temporary, output, { flag: 'wx', encoding: 'utf8' }); await link(temporary, options['--out']); }
73
- finally { await unlink(temporary).catch(() => {}); }
74
- return { schema_version: 1, operation: command, count: rows.length, promotion_eligible: false, human_review_is_attestation_not_proof: true };
75
- }
76
- if (process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.url)) main().then(r => console.log(JSON.stringify(r, null, 2))).catch(error => {
77
- console.error(JSON.stringify({ error: /^[a-z_]{1,80}$/.test(error.message) ? error.message : error.code === 'EEXIST' ? 'output_exists' : 'operation_failed' })); process.exitCode = 1;
78
- });
@@ -1,87 +0,0 @@
1
- import { readFile, stat } from 'node:fs/promises';
2
- import { createHash } from 'node:crypto';
3
-
4
- export const MAX_FILE_BYTES = 8 * 1024 * 1024;
5
- export const MAX_RECORD_BYTES = 64 * 1024;
6
- export const SPLITS = ['development', 'calibration', 'held_out'];
7
- export function check(condition, code = 'invalid_data') { if (!condition) throw new Error(code); }
8
- export const object = x => x !== null && typeof x === 'object' && !Array.isArray(x);
9
- export const number = (x, min, max) => typeof x === 'number' && Number.isFinite(x) && x >= min && x <= max;
10
- const string = x => typeof x === 'string' && x.trim().length > 0 && x.length <= 16384;
11
- const identifier = x => typeof x === 'string' && /^[\w.:/-]{1,160}$/.test(x);
12
- export function keys(x, names) {
13
- check(object(x) && Object.keys(x).length === names.length && names.every(k => Object.hasOwn(x, k)), 'invalid_fields');
14
- }
15
- export async function readJsonl(path) {
16
- check((await stat(path)).size <= MAX_FILE_BYTES, 'file_budget_exceeded');
17
- const text = await readFile(path, 'utf8');
18
- check(Buffer.byteLength(text) <= MAX_FILE_BYTES, 'file_budget_exceeded');
19
- try { return text.replace(/^\uFEFF/, '').split(/\r?\n/).filter(x => x.trim()).map(x => {
20
- check(Buffer.byteLength(x) <= MAX_RECORD_BYTES, 'record_budget_exceeded');
21
- return JSON.parse(x);
22
- }); } catch { throw new Error('invalid_jsonl'); }
23
- }
24
- export function inputState(row) {
25
- return { purpose: row.purpose, ...row.state, ...(row.purpose === 'relevance' ? { candidates: row.candidates.map(({ id, text }) => ({ id, text })) } : {}) };
26
- }
27
- export const stateHash = row => createHash('sha256').update(JSON.stringify(inputState(row))).digest('hex');
28
- export function identity(row) {
29
- return Object.fromEntries(['id', 'project_id', 'session_id', 'task_id', 'event_id', 'event_seq', 'task_revision'].map(k => [k, row[k]]));
30
- }
31
- export function validateDataset(rows) {
32
- check(Array.isArray(rows) && rows.length > 0 && rows.length <= 10000, 'invalid_dataset_size');
33
- const ids = new Set(), events = new Set(), splits = new Map(), texts = new Map();
34
- for (const row of rows) {
35
- check(Buffer.byteLength(JSON.stringify(row)) <= MAX_RECORD_BYTES, 'record_budget_exceeded');
36
- keys(row, ['schema_version', 'id', 'project_id', 'session_id', 'group_id', 'task_id', 'event_id', 'event_seq', 'task_revision', 'purpose', 'language', 'split', 'provenance', 'state', row.purpose === 'correction' ? 'labels' : 'candidates']);
37
- check(row.schema_version === 1, 'invalid_schema_version');
38
- for (const k of ['id', 'project_id', 'session_id', 'group_id', 'task_id', 'event_id']) check(identifier(row[k]), 'invalid_identifier');
39
- for (const k of ['event_seq', 'task_revision']) check(Number.isSafeInteger(row[k]) && row[k] >= 0, 'invalid_revision');
40
- check(['correction', 'relevance'].includes(row.purpose) && ['en', 'zh', 'mixed'].includes(row.language) && SPLITS.includes(row.split), 'invalid_enum');
41
- keys(row.provenance, ['source', 'annotation', 'reviewer', 'reviewed_at']);
42
- check(['synthetic', 'real'].includes(row.provenance.source) && ['agent_proposed', 'human_verified'].includes(row.provenance.annotation), 'invalid_provenance');
43
- check(row.provenance.annotation === 'human_verified' ? string(row.provenance.reviewer) : row.provenance.reviewer === null, 'invalid_reviewer');
44
- check(row.provenance.annotation === 'human_verified' ? typeof row.provenance.reviewed_at === 'string' && /^\d{4}-\d{2}-\d{2}T/.test(row.provenance.reviewed_at) && Number.isFinite(Date.parse(row.provenance.reviewed_at)) : row.provenance.reviewed_at === null, 'invalid_review_date');
45
- keys(row.state, ['goal', 'assumptions', 'message']);
46
- check(string(row.state.goal) && string(row.state.message) && Array.isArray(row.state.assumptions) && row.state.assumptions.length <= 20 && row.state.assumptions.every(string), 'invalid_state');
47
- if (row.purpose === 'correction') { keys(row.labels, ['correction']); check(typeof row.labels.correction === 'boolean', 'invalid_label'); }
48
- else {
49
- check(Array.isArray(row.candidates) && row.candidates.length >= 2 && row.candidates.length <= 12, 'invalid_candidates');
50
- const candidateIds = new Set();
51
- for (const c of row.candidates) { keys(c, ['id', 'text', 'grade']); check(identifier(c.id) && string(c.text) && Number.isInteger(c.grade) && number(c.grade, 0, 3) && !candidateIds.has(c.id), 'invalid_candidate'); candidateIds.add(c.id); }
52
- }
53
- check(!ids.has(row.id), 'duplicate_id'); ids.add(row.id);
54
- const event = JSON.stringify([row.project_id, row.session_id, row.event_id, row.purpose]);
55
- check(!events.has(event), 'duplicate_event'); events.add(event);
56
- for (const group of [`session:${row.project_id}:${row.session_id}`, `group:${row.group_id}`]) {
57
- check(!splits.has(group) || splits.get(group) === row.split, 'split_leakage'); splits.set(group, row.split);
58
- }
59
- const hash = stateHash(row);
60
- check(!texts.has(hash) || texts.get(hash) === row.split, 'content_split_leakage'); texts.set(hash, row.split);
61
- }
62
- return rows;
63
- }
64
- export function validatePrediction(row, prediction) {
65
- keys(prediction, [...Object.keys(identity(row)), 'state_hash', 'model', 'question_set_version', 'status', 'failure_reason', 'http_status', 'usage', 'latency_ms', row.purpose === 'correction' ? 'correction_probability' : 'scores']);
66
- for (const [k, v] of Object.entries(identity(row))) check(prediction[k] === v, 'prediction_identity_mismatch');
67
- check(prediction.state_hash === stateHash(row), 'stale_prediction');
68
- check(['jev-1.13.0', 'rules-v1'].includes(prediction.model) && prediction.question_set_version === 'jev-eval-v1', 'invalid_prediction_version');
69
- check(['ok', 'abstain', 'timeout', 'unavailable', 'invalid'].includes(prediction.status), 'invalid_status');
70
- check(number(prediction.latency_ms, 0, 3600000), 'invalid_latency');
71
- check(prediction.http_status === null || Number.isInteger(prediction.http_status) && number(prediction.http_status, 100, 599), 'invalid_http_status');
72
- check(prediction.status === 'ok' ? prediction.failure_reason === null : ['timeout', 'http_failure', 'transport_failure', 'invalid_response', 'abstain'].includes(prediction.failure_reason), 'invalid_failure_reason');
73
- if (prediction.usage !== null) { keys(prediction.usage, ['input_tokens', 'output_tokens']); for (const n of Object.values(prediction.usage)) check(Number.isSafeInteger(n) && n >= 0, 'invalid_usage'); }
74
- if (row.purpose === 'correction') {
75
- check(prediction.status === 'ok' ? number(prediction.correction_probability, 0, 1) : prediction.correction_probability === null, 'invalid_probability');
76
- } else {
77
- check(Array.isArray(prediction.scores) && prediction.scores.length === row.candidates.length, 'invalid_scores');
78
- const expected = new Set(row.candidates.map(c => c.id));
79
- for (const item of prediction.scores) {
80
- keys(item, ['id', 'score']); check(expected.delete(item.id), 'invalid_score_id');
81
- check(item.score === null || number(item.score, 0, 3), 'invalid_score');
82
- if (prediction.status !== 'ok') check(item.score === null, 'failure_with_score');
83
- }
84
- if (prediction.status === 'ok') check(prediction.scores.some(s => s.score !== null), 'empty_ok_prediction');
85
- }
86
- return prediction;
87
- }
@@ -1,95 +0,0 @@
1
- import test from 'node:test';
2
- import assert from 'node:assert/strict';
3
- import { mkdtemp, writeFile, symlink, readdir, unlink, rmdir, lstat } from 'node:fs/promises';
4
- import { createHash } from 'node:crypto';
5
- import { tmpdir } from 'node:os';
6
- import { join } from 'node:path';
7
- import { enrich, resolveSource, renderHtml } from '../context.mjs';
8
- import { normalizeMessage, redactHomePaths, credentialBearing } from '../corpus.mjs';
9
-
10
- const hash = text => createHash('sha256').update(text).digest('hex'), cwd = 'C:/Users/test/Documents/GitHub/KenazAI';
11
- const c = (uuid, parentUuid, role, text, extra = {}) => ({ uuid, parentUuid, sessionId: 's1', cwd, type: role, message: { role, content: [{ type: 'text', text }] }, ...extra });
12
- async function fixture(t, kind, records, targetLine, overrides = {}) {
13
- const dir = await mkdtemp(join(tmpdir(), 'jev-context-test-'));
14
- t.after(async () => { for (const name of await readdir(dir)) { const p = join(dir, name), s = await lstat(p); if (s.isSymbolicLink() && process.platform === 'win32') await rmdir(p); else await unlink(p); } await rmdir(dir); });
15
- const path = join(dir, 'source.jsonl'), bytes = records.map(r => JSON.stringify(r) + '\n').join(''); await writeFile(path, bytes);
16
- const source = { kind, relative_path: 'source.jsonl', source_id: hash(`${kind}:source.jsonl`) };
17
- const target = records[targetLine - 1], message = normalizeMessage(redactHomePaths(kind === 'claude' ? target.message.content[0].text : target.payload.message));
18
- const row = { kind: 'pending_historical_review', id: hash(`${source.source_id}:${targetLine}:${hash(message.toLowerCase())}`), source_id: source.source_id, session_id: hash(`${kind}:s1`), group_id: 'group', message, review_status: 'pending', provenance: { source: 'real', annotation: 'unreviewed' }, ...overrides };
19
- return { dir, path, bytes, row, source, manifest: { schema_version: 1, sources: [source], items: [{ id: row.id, source_id: source.source_id, line: targetLine }] }, options: { sourceRoots: { claude: dir, codex: dir }, cwdRoots: [cwd] } };
20
- }
21
- test('Claude ancestry follows parent UUID rather than neighboring branch, skips thinking/tools/future', async t => {
22
- const records = [c('u1', null, 'user', 'Start'), c('a1', 'u1', 'assistant', 'Correct branch'), c('wrong', 'u1', 'assistant', 'Other branch'), c('tool', 'a1', 'user', '', { message: { role: 'user', content: [{ type: 'tool_result', content: 'secret tool output' }] } }), c('thinking', 'tool', 'assistant', '', { message: { role: 'assistant', content: [{ type: 'thinking', thinking: 'hidden reasoning' }] } }), c('target', 'thinking', 'user', 'Please revise'), c('future', 'target', 'assistant', 'Future answer')];
23
- const f = await fixture(t, 'claude', records, 6), before = JSON.stringify(f.row), result = await enrich([f.row], f.manifest, f.options), row = result.rows[0];
24
- assert.equal(row.status, 'restored'); assert.deepEqual(row.observed_context.map(c => c.text), ['Start', 'Correct branch']);
25
- assert.ok(row.observed_context.every(c => c.source_line < row.target_line)); assert.equal(JSON.stringify(row).includes('hidden reasoning'), false); assert.equal(JSON.stringify(row).includes('Other branch'), false);
26
- assert.equal(row.source_prefix_sha256, hash(records.slice(0, 6).map(r => JSON.stringify(r) + '\n').join(''))); assert.equal(JSON.stringify(f.row), before); assert.equal(row.decision.correction, null);
27
- });
28
- test('stale targets and wrong session rejected without dropping IDs', async t => {
29
- const f = await fixture(t, 'claude', [c('a', null, 'assistant', 'Context'), c('u', 'a', 'user', 'Target')], 2);
30
- for (const change of [r => r.message = 'Changed', r => r.session_id = hash('other'), r => r.review_status = 'human_verified']) {
31
- const row = structuredClone(f.row); change(row); const result = await enrich([row], f.manifest, f.options); assert.equal(result.rows[0].id, row.id); assert.equal(result.rows[0].status, 'rejected'); assert.equal(result.rows[0].observed_context, undefined);
32
- }
33
- });
34
- test('source paths reject traversal absolute paths hash mismatch and symlink escape', async t => {
35
- const f = await fixture(t, 'claude', [c('u', null, 'user', 'Target')], 1);
36
- for (const relative_path of ['../outside', '/absolute', 'C:\\absolute', 'nested/../../outside']) await assert.rejects(resolveSource({ kind: 'claude', relative_path, source_id: hash(`claude:${relative_path}`) }, f.options.sourceRoots), /unsafe_source_path/);
37
- await assert.rejects(resolveSource({ ...f.source, source_id: 'wrong' }, f.options.sourceRoots), /source_id_mismatch/);
38
- const outside = await fixture(t, 'claude', [c('u', null, 'user', 'Other')], 1), link = join(f.dir, 'escape');
39
- await symlink(outside.dir, link, process.platform === 'win32' ? 'junction' : 'dir');
40
- await assert.rejects(resolveSource({ kind: 'claude', relative_path: 'escape/source.jsonl', source_id: hash('claude:escape/source.jsonl') }, f.options.sourceRoots), /source_path_escape/);
41
- });
42
- test('credential context dropped as whole message and gaps remain explicit', async t => {
43
- const f = await fixture(t, 'claude', [c('a1', null, 'assistant', 'Safe context'), c('a2', 'a1', 'assistant', 'Use apikey_abcdefgh12345 now'), c('u', 'a2', 'user', 'Continue')], 3);
44
- const row = (await enrich([f.row], f.manifest, f.options)).rows[0]; assert.equal(row.status, 'partial'); assert.deepEqual(row.observed_context.map(c => c.text), ['Safe context']); assert.ok(row.context_gaps.includes('credential_context')); assert.equal(JSON.stringify(row).includes('apikey_'), false);
45
- });
46
- test('normalization and JSON quote escaping cannot hide credential context', async t => {
47
- const escaped = 'API_KEY="abcd1234"'; assert.equal(credentialBearing(escaped), true); assert.equal(credentialBearing(JSON.stringify(escaped)), false);
48
- for (const text of [escaped, 'The config is {"API_KEY":"abc12345"}', 'Use API_KEY=abc12345 locally', 'APIKEY_abcdefgh12345']) {
49
- assert.equal(credentialBearing(normalizeMessage(text)), true);
50
- const f = await fixture(t, 'claude', [c('safe', null, 'assistant', 'Safe earlier text'), c('secret', 'safe', 'assistant', text), c('target', 'secret', 'user', 'Continue')], 3);
51
- const row = (await enrich([f.row], f.manifest, f.options)).rows[0];
52
- assert.deepEqual(row.observed_context.map(c => c.text), ['Safe earlier text']);
53
- assert.ok(row.context_gaps.includes('credential_context')); assert.ok(row.observed_context.every(c => !credentialBearing(c.text)));
54
- }
55
- const target = await fixture(t, 'claude', [c('user', null, 'user', 'API_KEY=abc12345')], 1);
56
- assert.equal((await enrich([target.row], target.manifest, target.options)).rows[0].status, 'rejected');
57
- });
58
- const meta = { type: 'session_meta', payload: { id: 's1', cwd, source: 'cli' } };
59
- const assistant = text => ({ type: 'response_item', payload: { type: 'message', role: 'assistant', phase: 'final_answer', content: [{ type: 'output_text', text }] } });
60
- const user = text => ({ type: 'event_msg', payload: { type: 'user_message', message: text } });
61
- test('Codex compaction/scope resets context and event assistant duplicates are ignored', async t => {
62
- const list = [meta, assistant('Before reset'), { type: 'compacted', payload: {} }, assistant('After reset'), { type: 'event_msg', payload: { type: 'agent_message', message: 'Event duplicate' } }, user('Target'), assistant('Future')];
63
- const f = await fixture(t, 'codex', list, 6), row = (await enrich([f.row], f.manifest, f.options)).rows[0];
64
- assert.deepEqual(row.observed_context.map(c => c.text), ['After reset']); assert.ok(row.context_gaps.includes('compaction_or_rollback'));
65
- const scoped = await fixture(t, 'codex', [meta, assistant('Original cwd'), { type: 'turn_context', payload: { cwd: 'C:/Other' } }, assistant('Foreign'), { type: 'turn_context', payload: { cwd } }, user('Return')], 6);
66
- assert.equal((await enrich([scoped.row], scoped.manifest, scoped.options)).rows[0].status, 'missing');
67
- });
68
- test('bounded context marks truncation, missing ancestry never uses nearest neighbor', async t => {
69
- const long = await fixture(t, 'claude', [c('a', null, 'assistant', 'Long visible text '.repeat(500)), c('u', 'a', 'user', 'Target')], 2);
70
- const row = (await enrich([long.row], long.manifest, long.options)).rows[0]; assert.equal(row.status, 'partial'); assert.equal(row.observed_context[0].text.length, 3000); assert.equal(row.observed_context[0].truncated, true);
71
- const missing = await fixture(t, 'claude', [c('a', null, 'assistant', 'Not ancestor'), c('u', 'unknown', 'user', 'Target')], 2);
72
- const m = (await enrich([missing.row], missing.manifest, missing.options)).rows[0]; assert.equal(m.status, 'missing'); assert.ok(m.context_gaps.includes('missing_ancestor'));
73
- });
74
- test('static HTML escapes raw content and has no scripts or external resources', () => {
75
- const html = renderHtml([{ id: 'case', status: 'restored', message: '<script>fetch("https://evil")</script>', observed_context: [{ role: 'assistant', source_line: 1, text: '<img src=x onerror=alert(1)>' }] }]);
76
- assert.equal(html.includes('<script>'), false); assert.equal(html.includes('<img'), false); assert.ok(html.includes('&lt;script&gt;')); assert.ok(html.includes("default-src 'none'"));
77
- });
78
- test('metadata-only duplicate UUID tolerated; conflicting text identity rejected', async t => {
79
- const first = c('a', null, 'assistant', 'Actual context');
80
- const attachment = { uuid: 'attachment', type: 'attachment', parentUuid: 'a', sessionId: 's1', cwd, arbitraryMetadata: 1 };
81
- const f = await fixture(t, 'claude', [first, attachment, { ...attachment, arbitraryMetadata: 2 }, c('u', 'a', 'user', 'Target')], 4);
82
- assert.equal((await enrich([f.row], f.manifest, f.options)).rows[0].status, 'restored');
83
- const bad = await fixture(t, 'claude', [first, c('a', null, 'assistant', 'Conflicting context'), c('u', 'a', 'user', 'Target')], 3);
84
- assert.equal((await enrich([bad.row], bad.manifest, bad.options)).rows[0].status, 'rejected');
85
- });
86
- test('ancestry walk and Codex history window are bounded with explicit gaps', async t => {
87
- const list = [c('a', null, 'assistant', 'Ancient context')];
88
- for (let i = 0; i < 6; i++) list.push({ uuid: `tool${i}`, parentUuid: i ? `tool${i - 1}` : 'a', sessionId: 's1', cwd, type: 'user', message: { role: 'user', content: [{ type: 'tool_result', content: 'omitted' }] } });
89
- list.push(c('u', 'tool5', 'user', 'Target'));
90
- const f = await fixture(t, 'claude', list, list.length); f.options.limits = { maxAncestorSteps: 3 };
91
- const row = (await enrich([f.row], f.manifest, f.options)).rows[0]; assert.ok(row.context_gaps.includes('ancestry_budget')); assert.equal(row.status, 'missing');
92
- const history = [meta, ...Array.from({ length: 25 }, (_, i) => assistant(`Turn ${i}`)), user('Target')];
93
- const g = await fixture(t, 'codex', history, history.length), restored = (await enrich([g.row], g.manifest, g.options)).rows[0];
94
- assert.equal(restored.observed_context.length, 6); assert.ok(restored.context_gaps.includes('history_window')); assert.ok(renderHtml([restored]).includes('history_window'));
95
- });
@@ -1,102 +0,0 @@
1
- import test from 'node:test';
2
- import assert from 'node:assert/strict';
3
- import { mkdtemp, mkdir, writeFile, readdir, unlink, rmdir } from 'node:fs/promises';
4
- import { tmpdir } from 'node:os';
5
- import { join } from 'node:path';
6
- import { credentialBearing, generatedMessage, automationSeed, redactHomePaths, userText, withinRoots, extractFile, sampleCandidates, records, discover, inventory, main } from '../corpus.mjs';
7
-
8
- async function temp(t) {
9
- const dir = await mkdtemp(join(tmpdir(), 'jev-corpus-test-'));
10
- async function cleanup(path) { for (const entry of await readdir(path, { withFileTypes: true })) { const child = join(path, entry.name); if (entry.isDirectory()) await cleanup(child); else await unlink(child); } await rmdir(path); }
11
- t.after(() => cleanup(dir)); return dir;
12
- }
13
- const roots = ['C:/Users/test/Documents/GitHub/KenazAI'];
14
- const claude = (text, extra = {}) => ({ type: 'user', sessionId: 's1', cwd: roots[0], message: { role: 'user', content: text }, ...extra });
15
- const meta = (extra = {}) => ({ type: 'session_meta', payload: { id: 's1', cwd: roots[0], source: 'cli', ...extra } });
16
- const event = text => ({ type: 'event_msg', payload: { type: 'user_message', message: text } });
17
- const response = text => ({ type: 'response_item', payload: { type: 'message', role: 'user', content: [{ type: 'input_text', text }] } });
18
- async function extract(t, items, kind = 'claude', limits = {}) {
19
- const dir = await temp(t), path = join(dir, 's.jsonl'); await writeFile(path, items.map(r => JSON.stringify(r)).join('\n'));
20
- const stats = {}, candidates = await extractFile({ path, kind, relative_path: 's.jsonl' }, roots, stats, limits); return { candidates, stats };
21
- }
22
- test('credential detection quarantines whole message and home paths are removed', () => {
23
- for (const text of ['apikey_abcdefgh123456', 'sk-abcdefgh-123456', 'Authorization: Bearer abcdefgh123', '$env:TYPESAFE_API_KEY="abc123456"', 'export API_KEY=abc12345', 'password: hunter22', 'https://user:secret@site.test', '-----BEGIN PRIVATE KEY-----', 'github_pat_abcde12345678']) assert.equal(credentialBearing(text), true);
24
- assert.equal(credentialBearing('Please configure the API key locally.'), false);
25
- const clean = redactHomePaths('C:\\Users\\someone\\repo /home/someone/repo /Users/someone/file'); assert.equal(clean.includes('someone'), false);
26
- });
27
- test('generated and non-user records are excluded without fabricated labels', async t => {
28
- for (const text of ['# AGENTS.md instructions for repo', '<environment_context>cwd</environment_context>', '[CANARY:v2]', '<system-reminder>generated</system-reminder>', '<subagent_notification>done</subagent_notification>']) assert.equal(generatedMessage(text), true);
29
- assert.equal(userText(claude([{ type: 'tool_result', content: 'not user' }]), 'claude'), null);
30
- const { candidates } = await extract(t, [claude('Real request'), claude('internal', { isMeta: true }), claude('render-only', { isVisibleInTranscriptOnly: true }), { type: 'assistant', message: { role: 'assistant', content: 'not user' } }, claude('<environment_context>private</environment_context>'), claude('Another request')]);
31
- assert.equal(candidates.length, 2);
32
- for (const { row } of candidates) { for (const field of ['labels', 'goal', 'assumptions', 'grade']) assert.equal(Object.hasOwn(row, field), false); assert.equal(row.review_status, 'pending'); assert.equal(row.incomplete_context_for_correction, true); }
33
- });
34
- test('secret message cannot survive as later preceding context', async t => {
35
- const { candidates, stats } = await extract(t, [claude('First'), claude('Use apikey_abcdefgh1234 now'), claude('Next request')]);
36
- assert.equal(candidates.length, 2); assert.equal(stats.credential_message, 1); assert.equal(candidates[1].row.context_missing, true);
37
- assert.equal(JSON.stringify(candidates).includes('apikey_'), false);
38
- });
39
- test('Codex exact cwd boundaries and subagent metadata fail closed', async t => {
40
- assert.equal(withinRoots(roots[0] + '/dashboard', roots), true); assert.equal(withinRoots(roots[0] + 'Else', roots), false); assert.equal(withinRoots(roots[0] + '/../Other', roots), false);
41
- for (const metadata of [meta({ cwd: 'C:/Other' }), meta({ source: { subagent: { parent_thread_id: 'parent' } } })]) assert.equal((await extract(t, [metadata, event('Request')], 'codex')).candidates.length, 0);
42
- assert.equal((await extract(t, [event('No metadata')], 'codex')).candidates.length, 0);
43
- const proper = await extract(t, [meta(), response('Replayed old text'), event('Actual text'), response('Actual text')], 'codex');
44
- assert.equal(proper.candidates.length, 1); assert.equal(proper.candidates[0].row.message, 'Actual text'); assert.equal(proper.candidates[0].row.context_missing, true);
45
- const fallback = await extract(t, [meta(), response('Fallback text')], 'codex'); assert.equal(fallback.candidates.length, 1); assert.equal(fallback.stats.response_fallback_candidates, 1);
46
- });
47
- test('whole Claude sidechain file rejected even after first candidate', async t => {
48
- const { candidates } = await extract(t, [claude('Earlier request'), claude('Subagent request', { isSidechain: true })]); assert.equal(candidates.length, 0);
49
- });
50
- test('automation seeds exclude entire session while genuine TASK references remain', async t => {
51
- const seeds = ['- ## Automated Dispatch Context\nThis prompt was machine-assembled by the Kenaz orchestration system.', 'This prompt was machine-assembled by the Kenaz orchestration system.', '- Extract key technical insights from this conversation chunk. Output in English only. Be concise, 1-3 sentences.', '[HEADLESS MODE] 你已被 Formation Lead 指派任務', 'You have access to MCP tools from kenaz-dashboard. Call the synapse_status tool now.'];
52
- for (const seed of seeds) {
53
- assert.equal(automationSeed(seed), true);
54
- const result = await extract(t, [claude('Prior automated followup'), claude(seed), claude('Continue automatically')]);
55
- assert.equal(result.candidates.length, 0); assert.equal(result.stats.automation_seed, 1);
56
- }
57
- assert.equal(automationSeed('Please investigate TASK_35 and explain the Automated Dispatch Context header.'), false);
58
- const genuine = await extract(t, [claude('Please investigate TASK_35'), claude('[Request interrupted by user for tool use]'), claude('<turn_aborted>The user interrupted the previous turn</turn_aborted>'), claude('Continue my investigation')]);
59
- assert.equal(genuine.candidates.length, 2);
60
- const smoke = await extract(t, [meta(), event(seeds.at(-1)), event('Continue')], 'codex'); assert.equal(smoke.candidates.length, 0);
61
- });
62
- test('automation discovered in one source excludes same session in another source', async t => {
63
- const dir = await temp(t), claudeRoot = join(dir, 'claude'), codexRoot = join(dir, 'codex'), project = join(claudeRoot, 'C-KenazAI');
64
- await mkdir(project, { recursive: true }); await mkdir(codexRoot);
65
- await writeFile(join(project, 'a.jsonl'), JSON.stringify(claude('Earlier inherited automated turn')));
66
- await writeFile(join(project, 'b.jsonl'), JSON.stringify(claude('[HEADLESS MODE] 你已被 Formation Lead 指派任務')));
67
- const result = await inventory({ claudeRoot, codexRoot, roots }); assert.equal(result.rows.length, 0); assert.equal(result.summary.exclusions.cross_file_automation_candidates, 1);
68
- });
69
- test('Claude foreign/missing cwd excluded; changing session identity rejects entire file', async t => {
70
- const foreign = await extract(t, [claude('Allowed first'), claude('Foreign', { cwd: 'C:/Other' }), claude('Allowed return'), claude('Missing', { cwd: undefined })]);
71
- assert.equal(foreign.candidates.length, 2); assert.equal(foreign.candidates[1].row.context_missing, true);
72
- const mixed = await extract(t, [claude('First'), claude('Other session', { sessionId: 's2' })]); assert.equal(mixed.candidates.length, 0); assert.equal(mixed.stats.session_identity_change, 1);
73
- const reentry = await extract(t, [meta(), event('First'), { type: 'turn_context', payload: { cwd: 'C:/Other' } }, { type: 'turn_context', payload: { cwd: roots[0] } }, event('Return')], 'codex');
74
- assert.equal(reentry.candidates[1].row.context_missing, true);
75
- });
76
- test('dedup and balanced sampling deterministic; generic duplicates do not merge families', async t => {
77
- const { candidates: a } = await extract(t, [claude('Continue'), claude('Unique A1'), claude('Unique A2')]);
78
- const { candidates: b } = await extract(t, [claude(' continue ', { sessionId: 's2' }), claude('Unique B1', { sessionId: 's2' }), claude('Unique B2', { sessionId: 's2' })]);
79
- const input = [...a, ...b], sample = sampleCandidates(input, 4);
80
- assert.equal(sample.unique_count, 5); assert.equal(sample.duplicate_count, 1); assert.equal(sample.group_count, 2);
81
- assert.deepEqual(sampleCandidates([...input].reverse(), 4), sample); assert.equal(new Set(sample.selected.map(c => c.row.session_id)).size, 2);
82
- const lengthy = 'Copied historical context '.repeat(10);
83
- const c = await extract(t, [claude(lengthy)]), d = await extract(t, [claude(lengthy, { sessionId: 's2' })]);
84
- assert.equal(sampleCandidates([...c.candidates, ...d.candidates]).group_count, 1);
85
- });
86
- test('stream bounds discard oversized lines then recover next JSON record', async t => {
87
- const dir = await temp(t), path = join(dir, 'big.jsonl'); await writeFile(path, 'x'.repeat(200000) + '\n' + JSON.stringify({ ok: true }) + '\n');
88
- const stats = {}, output = []; for await (const item of records(path, stats, { maxLineBytes: 100 })) output.push(item);
89
- assert.equal(stats.oversize_line, 1); assert.deepEqual(output, [{ value: { ok: true }, line: 2 }]);
90
- });
91
- test('discovery excludes non-Kenaz Claude and nested subagents; summary only dry output', async t => {
92
- const dir = await temp(t), claudeRoot = join(dir, 'claude'), codexRoot = join(dir, 'codex');
93
- for (const path of [join(claudeRoot, 'C-KenazAI'), join(claudeRoot, 'C-Other'), join(claudeRoot, 'C-KenazAI', 'subagents'), codexRoot]) await mkdir(path, { recursive: true });
94
- await writeFile(join(claudeRoot, 'C-KenazAI', 's.jsonl'), JSON.stringify(claude('Kept real user text')));
95
- await writeFile(join(claudeRoot, 'C-KenazAI', 'agent-1.jsonl'), JSON.stringify(claude('Agent')));
96
- await writeFile(join(claudeRoot, 'C-Other', 's.jsonl'), JSON.stringify(claude('Other')));
97
- await writeFile(join(claudeRoot, 'C-KenazAI', 'subagents', 'a.jsonl'), JSON.stringify(claude('Nested')));
98
- assert.equal((await discover({ claudeRoot, codexRoot })).length, 1);
99
- const result = await inventory({ claudeRoot, codexRoot, roots, target: 500 }); assert.equal(result.summary.shortfall, 499);
100
- const report = await main(['--claude-root', claudeRoot, '--codex-root', codexRoot]); assert.equal(report.written, false); assert.equal(JSON.stringify(report).includes('Kept real'), false);
101
- await assert.rejects(main(['--target', 'NaN']), /invalid_target/);
102
- });
@@ -1,146 +0,0 @@
1
- import test from 'node:test';
2
- import assert from 'node:assert/strict';
3
- import { createServer } from 'node:http';
4
- import { once } from 'node:events';
5
- import { spawnSync } from 'node:child_process';
6
- import { template, main } from '../cli.mjs';
7
- import { readJsonl, validateDataset, validatePrediction, stateHash, inputState } from '../schema.mjs';
8
- import { MODEL, RUBRIC, prediction, rules, replayProvider, liveProvider, buildRequest, parseAnswers } from '../providers.mjs';
9
- import { report } from '../metrics.mjs';
10
-
11
- const fixture = new URL('../fixtures/synthetic.jsonl', import.meta.url);
12
- const rows = validateDataset(await readJsonl(fixture));
13
- const clone = x => structuredClone(x);
14
- const row = () => template();
15
- function correctionResponse(noul = 0.9) { return { model: MODEL, answers: { correction: { type: 'noul', noul } }, usage: { input_tokens: 30, output_tokens: 2 } }; }
16
- async function server(t, handler) {
17
- const http = createServer(handler); http.listen(0, '127.0.0.1'); await once(http, 'listening');
18
- t.after(() => { http.closeAllConnections(); http.close(); });
19
- return `http://127.0.0.1:${http.address().port}/v1/systemone`;
20
- }
21
- const live = (endpoint, extra = {}) => liveProvider({ apiKey: 'test-only-secret', endpoint, allowLoopbackForTests: true, timeoutMs: 2000, ...extra });
22
-
23
- test('varied synthetic fixtures are strict, immutable and never promotion eligible', async () => {
24
- const before = JSON.stringify(rows);
25
- assert.equal(rows.length, 11);
26
- const result = report(rows, rows.map(rules), { provider: 'rules' });
27
- assert.equal(result.promotion_eligible, false);
28
- assert.equal(result.provenance.annotation.agent_proposed, rows.length);
29
- assert.equal(result.metrics.relevance.zero_relevance_queries_excluded, 1);
30
- assert.equal(JSON.stringify(rows), before);
31
- assert.equal(JSON.stringify(result).includes(rows[0].state.message), false);
32
- assert.equal((await main(['validate', '--dataset', fixture.pathname.replace(/^\/([A-Z]:)/i, '$1')])).valid, true);
33
- });
34
- test('schema rejects unknown fields, invalid labels, duplicates and dishonest review metadata', () => {
35
- for (const mutate of [r => r.extra = true, r => r.labels.correction = 1, r => r.provenance.annotation = 'human_verified', r => r.state.message = '', r => r.event_seq = -1]) {
36
- const r = row(); mutate(r); assert.throws(() => validateDataset([r]));
37
- }
38
- const valid = row(); valid.provenance = { source: 'real', annotation: 'human_verified', reviewer: 'reviewer-a', reviewed_at: '2026-09-20T00:00:00Z' };
39
- assert.doesNotThrow(() => validateDataset([valid]));
40
- assert.throws(() => validateDataset([row(), row()]));
41
- });
42
- test('group, session and exact-content split leakage rejected', () => {
43
- for (const kind of ['group', 'session', 'content']) {
44
- const a = row(), b = row(); b.id = 'other'; b.event_id = 'other'; b.split = 'held_out';
45
- if (kind !== 'session') b.session_id = 'other';
46
- if (kind !== 'group') b.group_id = 'other';
47
- if (kind !== 'content') b.state.message = 'Different message';
48
- assert.throws(() => validateDataset([a, b]), /leakage/);
49
- }
50
- });
51
- test('model input and hash exclude ground truth and provenance', () => {
52
- const r = clone(rows.find(r => r.purpose === 'relevance')), hash = stateHash(r);
53
- r.candidates[0].grade = 0; r.provenance.reviewer = 'changed'; r.split = 'held_out';
54
- assert.equal(stateHash(r), hash);
55
- const input = JSON.stringify(inputState(r));
56
- for (const forbidden of ['grade', 'provenance', 'reviewer', 'split', 'labels']) assert.equal(input.includes(`"${forbidden}"`), false);
57
- r.state.message += ' revised'; assert.notEqual(stateHash(r), hash);
58
- });
59
- test('replay rejects wrong project/session/task, stale revision/hash, unknown IDs and aliases', () => {
60
- const r = row(), p = prediction(r, 'ok', 0.8);
61
- for (const field of ['project_id', 'session_id', 'task_id', 'event_id', 'task_revision', 'state_hash', 'model', 'question_set_version']) {
62
- const bad = clone(p); bad[field] = 'wrong'; assert.throws(() => replayProvider([r], [bad]));
63
- }
64
- assert.throws(() => replayProvider([r], []));
65
- assert.throws(() => replayProvider([r], [p, p]));
66
- assert.equal(replayProvider([r], [p])(r), p);
67
- });
68
- test('correction metrics include failed positives, preserve unanswered Brier denominator', () => {
69
- const data = [true, true, false, false].map((label, i) => ({ ...row(), id: `m${i}`, labels: { correction: label } }));
70
- const preds = [prediction(data[0], 'ok', 0.8), prediction(data[1], 'timeout'), prediction(data[2], 'ok', 0.6), prediction(data[3], 'ok', 0.1)];
71
- const result = report(data, preds, { provider: 'replay' }), m = result.metrics.correction;
72
- assert.deepEqual(m.confusion, { tp: 1, fp: 1, tn: 1, fn: 0 });
73
- assert.equal(m.coverage, 0.75); assert.equal(m.recall_including_abstentions, 0.5); assert.equal(m.recall_answered_only, 1);
74
- assert.equal(m.precision, 0.5); assert.equal(m.accuracy_including_abstentions, 0.5);
75
- assert.ok(Math.abs(m.brier_answered_only - 0.41 / 3) < 1e-12); assert.equal(m.brier_count, 3);
76
- const empty = report([data[1]], [prediction(data[1], 'abstain')], { provider: 'replay' }).metrics.correction;
77
- assert.equal(empty.precision, null); assert.equal(empty.brier_answered_only, null); assert.equal(empty.recall_including_abstentions, 0);
78
- });
79
- test('ranking uses full ideal, tracks partial scores and handles zero relevance', () => {
80
- const r = clone(rows.find(r => r.purpose === 'relevance'));
81
- const partial = prediction(r, 'ok', { [r.candidates[1].id]: 3 });
82
- const m = report([r], [partial], { provider: 'replay', k: 1 }).metrics.relevance;
83
- assert.equal(m.ndcg_at_k, 1 / 7); assert.equal(m.recall_at_k, 0.5); assert.equal(m.query_coverage, 0); assert.equal(m.candidate_coverage, 0.25); assert.equal(m.ndcg_complete_queries_only, null);
84
- const failed = report([r], [prediction(r, 'timeout')], { provider: 'replay' }).metrics.relevance;
85
- assert.equal(failed.ndcg_at_k, 0); assert.equal(failed.recall_at_k, 0);
86
- const zero = rows.at(-1), z = report([zero], [rules(zero)], { provider: 'rules' }).metrics.relevance;
87
- assert.equal(z.ndcg_at_k, null); assert.equal(z.zero_relevance_queries_excluded, 1);
88
- partial.scores[0].id = 'wrong'; assert.throws(() => validatePrediction(r, partial));
89
- });
90
- test('missing/blank key and unsafe URL rejected before any network', () => {
91
- let calls = 0; const fetchImpl = () => { calls++; throw new Error('unexpected'); };
92
- for (const apiKey of ['', ' ', '\r\n']) assert.throws(() => liveProvider({ apiKey, fetchImpl }), /api_key/);
93
- for (const endpoint of ['http://evil.example', 'https://api.typesafe.ai.evil.example/v1/systemone', 'https://api.typesafe.ai/v1/systemone?key=x', 'http://localhost:1234']) assert.throws(() => liveProvider({ apiKey: 'fake', endpoint, fetchImpl }), /unsafe_endpoint/);
94
- assert.equal(calls, 0);
95
- const child = spawnSync(process.execPath, ['dev/jev-eval/cli.mjs', 'evaluate', '--dataset', 'dev/jev-eval/fixtures/synthetic.jsonl', '--provider', 'live'], { env: { ...process.env, TYPESAFE_API_KEY: '' }, encoding: 'utf8' });
96
- assert.equal(child.status, 1); assert.deepEqual(JSON.parse(child.stderr), { error: 'missing_or_invalid_api_key' });
97
- });
98
- test('successful HTTP batches by row and tracks usage without gold leakage', async t => {
99
- const endpoint = await server(t, async (req, res) => {
100
- const parts = []; for await (const chunk of req) parts.push(chunk);
101
- const request = JSON.parse(Buffer.concat(parts));
102
- assert.equal(request.model, MODEL); assert.equal(request.state.labels, undefined); assert.equal(req.headers.authorization, 'Bearer test-only-secret');
103
- res.setHeader('Content-Type', 'application/json'); res.end(JSON.stringify(correctionResponse()));
104
- });
105
- const p = await live(endpoint)(row()); assert.equal(p.status, 'ok'); assert.equal(p.correction_probability, 0.9); assert.equal(p.usage.input_tokens, 30); validatePrediction(row(), p);
106
- });
107
- test('HTTP error statuses abstain without leaking raw provider errors', async t => {
108
- for (const status of [401, 422, 429, 529]) {
109
- const endpoint = await server(t, (req, res) => { res.writeHead(status); res.end('secret-body test-only-secret'); });
110
- const p = await live(endpoint)(row()); assert.equal(p.status, 'unavailable'); assert.equal(p.http_status, status); assert.equal(p.correction_probability, null); assert.equal(JSON.stringify(p).includes('secret'), false);
111
- }
112
- });
113
- test('redirect rejected without contacting target', async t => {
114
- let targetCalls = 0;
115
- const target = await server(t, (req, res) => { targetCalls++; res.end('{}'); });
116
- const endpoint = await server(t, (req, res) => { res.writeHead(302, { Location: target }); res.end(); });
117
- const p = await live(endpoint)(row()); assert.equal(p.status, 'unavailable'); assert.equal(targetCalls, 0);
118
- });
119
- test('timeout remains active across response body and also covers stalled transport', async t => {
120
- const endpoint = await server(t, (req, res) => { res.writeHead(200, { 'Content-Type': 'application/json' }); res.flushHeaders(); res.write('{'); });
121
- const start = Date.now(), p = await live(endpoint, { timeoutMs: 80 })(row());
122
- assert.equal(p.status, 'timeout'); assert.ok(Date.now() - start < 3000);
123
- const stalled = await liveProvider({ apiKey: 'fake', timeoutMs: 20, fetchImpl: () => new Promise(() => {}) })(row());
124
- assert.equal(stalled.status, 'timeout');
125
- });
126
- test('invalid JSON, oversized response and malformed answers fail closed', async t => {
127
- const invalids = ['{', 'x'.repeat(65537), JSON.stringify(correctionResponse(1.1)), JSON.stringify({ ...correctionResponse(), answers: { wrong: { type: 'noul', noul: 0.9 } } }), JSON.stringify({ ...correctionResponse(), usage: null })];
128
- for (const body of invalids) {
129
- const endpoint = await server(t, (req, res) => res.end(body));
130
- const p = await live(endpoint)(row()); assert.equal(p.status, 'invalid'); assert.equal(p.correction_probability, null);
131
- }
132
- });
133
- test('score answers enforce distributions, legends, bounds, confidence and exact IDs', () => {
134
- const r = rows.find(r => r.purpose === 'relevance'), request = buildRequest(r);
135
- const answer = { type: 'score', score: 2, legend: Object.fromEntries(RUBRIC.map((v, i) => [i, v])), probabilities: { 0: 0, 1: 0, 2: 1, 3: 0 }, confidence: 1 };
136
- const body = { model: MODEL, answers: Object.fromEntries(Object.keys(request.questions).map(k => [k, clone(answer)])), usage: { input_tokens: 100, output_tokens: 8 } };
137
- assert.equal(Object.keys(parseAnswers(r, body, request)).length, r.candidates.length);
138
- for (const mutate of [a => a.score = NaN, a => a.probabilities[2] = 0.3, a => a.legend[0] = 'wrong', a => a.confidence = 2, a => a.probabilities[4] = 0, a => a.type = 'noul']) {
139
- const bad = clone(body); mutate(bad.answers.candidate_0); assert.throws(() => parseAnswers(r, bad, request));
140
- }
141
- });
142
- test('CLI defaults offline, rejects ambiguous options, and preflight prints no key', async () => {
143
- assert.equal((await main(['preflight'])).network_attempted, false);
144
- assert.equal((await main(['template'])).schema_version, 1);
145
- for (const args of [['evaluate', '--endpoint', 'http://evil'], ['evaluate', '--dataset', 'a', '--dataset', 'b'], ['preflight', '--provider', 'live']]) await assert.rejects(main(args));
146
- });
@@ -1,71 +0,0 @@
1
- import test from 'node:test';
2
- import assert from 'node:assert/strict';
3
- import { readFile } from 'node:fs/promises';
4
- import { createHash } from 'node:crypto';
5
- import { resolve } from 'node:path';
6
- import { readJsonl } from '../schema.mjs';
7
- import { runBaseline, strictAnswers, safeInvocation, nativeTransport, main } from '../muninn-baseline.mjs';
8
-
9
- const source = await readFile(new URL('../../../.formation/tools/muninn.js', import.meta.url), 'utf8');
10
- const rows = await readJsonl(new URL('../fixtures/synthetic.jsonl', import.meta.url));
11
- const corrections = rows.filter(r => r.purpose === 'correction');
12
- const answers = () => corrections.map((r, idx) => ({ idx, translated: `Synthetic translation ${idx}`, labels: r.labels.correction ? ['correction'] : [] }));
13
- const response = items => ({ status: 0, stdout: JSON.stringify({ result: JSON.stringify(items), modelUsage: { 'claude-haiku-test': { inputTokens: 20 } } }) });
14
-
15
- test('offline default captures actual source prompt/parser without model quality claim', async () => {
16
- const result = await main([]);
17
- assert.equal(result.live, false); assert.equal(result.promotion_eligible, false); assert.equal(result.status, 'ok');
18
- assert.equal(result.batch_count, 8); assert.equal(result.translation_present, 8); assert.equal(result.correction_confusion, null);
19
- assert.equal(result.source_sha256, createHash('sha256').update(source).digest('hex'));
20
- assert.equal(result.source_requested_permission_bypass, true); assert.equal(result.actual_permission_bypass, false);
21
- });
22
- test('isolated source passes exact indexed messages, single transport and stable confusion', () => {
23
- let calls = 0; const before = JSON.stringify(rows);
24
- const result = runBaseline(rows, { source, live: true, transport: input => {
25
- calls++; assert.ok(input.startsWith('For each numbered message, output a JSON array'));
26
- assert.ok(input.includes('length_too_short')); assert.ok(!input.includes('Development startup also fails'));
27
- corrections.forEach((r, idx) => assert.ok(input.includes(`[${idx}] ${r.state.message.replace(/\r?\n/g, ' ')}`)));
28
- return response(answers());
29
- } });
30
- assert.equal(calls, 1); assert.equal(result.status, 'ok'); assert.equal(JSON.stringify(rows), before);
31
- assert.deepEqual(result.correction_confusion, { tp: 4, fp: 0, tn: 4, fn: 0, precision: 1, recall: 1 });
32
- assert.deepEqual(result.observed_model_metadata, ['claude-haiku-test']);
33
- assert.equal(JSON.stringify(result).includes(corrections[0].state.message), false);
34
- });
35
- test('strict raw checking rejects identities and labels before permissive source filters them', () => {
36
- const changes = [a => a.pop(), a => a[1].idx = a[0].idx, a => a.reverse(), a => a[0].idx = 0.5, a => a[0].translated = ' ', a => a[0].labels = ['invented'], a => a[0].labels = ['correction', 'correction'], a => a[0].extra = true];
37
- for (const change of changes) {
38
- const items = answers(); change(items); assert.throws(() => strictAnswers(JSON.stringify(items), corrections.length));
39
- const result = runBaseline(rows, { source, live: true, transport: () => response(items) });
40
- assert.notEqual(result.status, 'ok'); assert.equal(result.correction_confusion, null); assert.equal(result.translation_present, 0);
41
- }
42
- });
43
- test('failures timeouts malformed envelopes and oversize output remain sanitized failures', () => {
44
- for (const transport of [() => ({ status: 1, stdout: 'private-error' }), () => ({ status: null, error: { code: 'ETIMEDOUT' } }), () => ({ status: 0, stdout: '{' }), () => ({ status: 0, stdout: 'x'.repeat(1048577) }), () => { throw 'private-error'; }, () => ({ status: 0, stdout: JSON.stringify({ is_error: true, result: 'private-error' }) })]) {
45
- const result = runBaseline(rows, { source, live: true, transport });
46
- assert.notEqual(result.status, 'ok'); assert.equal(result.correction_confusion, null); assert.equal(JSON.stringify(result).includes('private-error'), false);
47
- }
48
- });
49
- test('real data rejected before transport including irrelevant purpose rows', () => {
50
- let calls = 0; const real = structuredClone(rows); real.at(-1).provenance.source = 'real';
51
- assert.throws(() => runBaseline(real, { source, live: true, transport: () => { calls++; } }), /synthetic_only/); assert.equal(calls, 0);
52
- });
53
- test('VM denies filesystem/network and unrelated module calls; empty environment', () => {
54
- for (const expression of ["require('fs').readFileSync('x')", "require('http').request('x')", "require('os').homedir()", "require('net')", "require('./log-reader').findTaskLog()"])
55
- assert.throws(() => runBaseline(rows, { source: source + '\n' + expression }), /blocked_vm/);
56
- const checked = source + '\nif (Object.keys(process.env).length || require.main === module) throw new Error("unexpected_environment");';
57
- assert.equal(runBaseline(rows, { source: checked }).status, 'ok');
58
- });
59
- test('safe subprocess uses explicit executable argv no shell and bounded output/time', () => {
60
- const exe = resolve('test-claude.exe'), invocation = safeInvocation(exe);
61
- for (const flag of ['--safe-mode', '--tools', '--disable-slash-commands', '--no-session-persistence']) assert.ok(invocation.args.includes(flag));
62
- assert.equal(invocation.args[invocation.args.indexOf('--tools') + 1], '');
63
- assert.equal(invocation.args.includes('--dangerously-skip-permissions'), false);
64
- let calls = 0;
65
- nativeTransport(exe, '/isolated', (command, args, options) => {
66
- calls++; assert.equal(command, exe); assert.deepEqual(args, invocation.args); assert.equal(options.shell, false);
67
- assert.equal(options.timeout, 30000); assert.equal(options.maxBuffer, 1048576); assert.equal(options.windowsHide, true);
68
- assert.equal(Object.hasOwn(options.env, 'TYPESAFE_API_KEY'), false); return { status: 0, stdout: '{}' };
69
- })('synthetic prompt'); assert.equal(calls, 1);
70
- for (const bad of ['claude', resolve('claude.cmd'), resolve('claude.bat')]) assert.throws(() => safeInvocation(bad), /invalid_claude_cli/);
71
- });