kenaz 0.3.22 → 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 (465) hide show
  1. package/core/.claude/hooks/_user-scope.js +1 -1
  2. package/core/.claude/hooks/core-resolve.js +1 -1
  3. package/core/.claude/hooks/worktree-create.js +6 -6
  4. package/core/.claude/hooks/worktree-remove.js +4 -4
  5. package/core/.collaboration/core/reconcile.js +16 -1
  6. package/core/.collaboration/core/task-2467-lifecycle.test.js +63 -0
  7. package/core/.collaboration/core/task-api.js +37 -7
  8. package/core/.formation/bifrost/launch.js +1 -1
  9. package/core/.formation/tools/kenaz-stats.js +1 -1
  10. package/core/.formation/tools/post-complete/git-merge.js +1 -1
  11. package/core/.formation/tools/prompt.js +1 -1
  12. package/core/.kenaz/specialist/ansuz_rules.yaml +7 -51
  13. package/core/.kenaz/specialist/ansuz_session_handoff.schema.json +2 -6
  14. package/core/.rule/general/project-self-containment.yaml +2 -2
  15. package/core/.specialist/Amelia/README.md +1 -1
  16. package/core/.specialist/Amelia/rule.yaml +1 -1
  17. package/core/.specialist/Ansuz/RULES.md +1 -1
  18. package/core/.specialist/Ansuz/concepts/commitment_layer.yaml +1 -1
  19. package/core/.specialist/Ansuz/concepts/evolvable_guardrails.yaml +1 -1
  20. package/core/.specialist/Ansuz/knowledge.yaml +1 -3
  21. package/core/.specialist/tools/__tests__/task-2409-lessons.test.js +10 -0
  22. package/core/.specialist/tools/__tests__/task-2427-harvest.test.js +25 -0
  23. package/core/.specialist/tools/ansuz-boot-fast.js +1 -1
  24. package/core/.specialist/tools/failure-detector.js +4 -4
  25. package/core/.specialist/tools/handoff-doc.js +1 -1
  26. package/core/.specialist/tools/lessons.js +2 -2
  27. package/core/CLAUDE.md +5 -5
  28. package/core/KENAZ_CORE_VERSION +1 -1
  29. package/core/dashboard/scripts/install-kenaz-cli.js +21 -6
  30. package/core/dev/scripts/check-file-size.js +1 -1
  31. package/core/dev/scripts/ci-feedback.js +1 -1
  32. package/core/dev/scripts/gc-agent-worktrees.js +11 -11
  33. package/core/dev/scripts/kenaz-session.js +3 -3
  34. package/core/dev/scripts/peer-identity-e2e.js +3 -3
  35. package/core/dev/scripts/run-rust-tests.js +2 -2
  36. package/core/dev/scripts/skill-routing-replay.js +3 -3
  37. package/core/dev/scripts/task1961/selftest.js +2 -2
  38. package/core/dev/scripts/windows-hide-guard.test.js +97 -0
  39. package/core/plugins/kenaz/guidance.md +1 -0
  40. package/core/plugins/kenaz/hooks/core-resolve.js +1 -1
  41. package/core/plugins/kenaz/hooks/kenaz-hook.js +52 -4
  42. package/core/plugins/kenaz/scripts/kenaz.test.js +72 -5
  43. package/lib/cli.js +9 -5
  44. package/package.json +6 -6
  45. package/vendor/install-kenaz-cli.js +21 -6
  46. package/core/.kenaz/designs/METAPLASTICITY_CONFIDENCE_DESIGN.md +0 -537
  47. package/core/.kenaz/designs/REFLEX_INITIATOR_DESIGN.md +0 -501
  48. package/core/.kenaz/designs/TASK_1385_handoff_mcp_design.md +0 -426
  49. package/core/.kenaz/designs/TASK_932_hippocampus_consolidation.md +0 -103
  50. package/core/.kenaz/designs/TASK_934_efe_signal_engine.md +0 -97
  51. package/core/.kenaz/designs/TASK_935_self_evolution_framework.md +0 -154
  52. package/core/.kenaz/designs/VISION_cognitive_architecture_roadmap.md +0 -159
  53. package/core/.kenaz/designs/metaplasticity_simulation_results.json +0 -696
  54. package/core/.kenaz/main-memory/README.md +0 -230
  55. package/core/.kenaz/main-memory/kenaz/cortex/001_cortex_overview.md +0 -168
  56. package/core/.kenaz/main-memory/kenaz/cortex/001_rag_engine_overview.md +0 -30
  57. package/core/.kenaz/main-memory/kenaz/memory-system/001_three_tier_architecture.md +0 -361
  58. package/core/.kenaz/main-memory/kenaz/pipeline/001_task_execution_flow.md +0 -117
  59. package/core/.kenaz/main-memory/kenaz/pipeline/001_task_granularity.md +0 -154
  60. package/core/.kenaz/main-memory/kenaz/pipeline/002_team_priority.md +0 -51
  61. package/core/.kenaz/main-memory/kenaz/pipeline/003_feature_id_system.md +0 -46
  62. package/core/.kenaz/main-memory/kenaz/rules/001_gen_007_self_containment.md +0 -108
  63. package/core/.kenaz/main-memory/kenaz/rules/001_rule_priority_system.md +0 -121
  64. package/core/.kenaz/main-memory/kenaz/rules/002_agt_006_pre_check.md +0 -0
  65. package/core/.kenaz/main-memory/kenaz/rules/003_ppl_002_task_archival.md +0 -48
  66. package/core/.kenaz/main-memory/kenaz/system/001_dual_track_task_system.md +0 -197
  67. package/core/.kenaz/main-memory/knowledge/patterns/001_json_bom_issue.md +0 -78
  68. package/core/.kenaz/main-memory/knowledge/patterns/001_leader_worker_pattern.md +0 -0
  69. package/core/.kenaz/main-memory/knowledge/patterns/002_scope_path_conflict.md +0 -115
  70. package/core/.kenaz/main-memory/knowledge/patterns/002_task_dependency_resolution.md +0 -223
  71. package/core/.kenaz/main-memory/knowledge/patterns/003_question_protocol.md +0 -242
  72. package/core/.kenaz/main-memory/knowledge/patterns/004_user_insight_value.md +0 -111
  73. package/core/.kenaz/main-memory/knowledge/patterns/005_file_lock_pattern.md +0 -274
  74. package/core/.kenaz/main-memory/knowledge/references/001_ppl_rules.md +0 -28
  75. package/core/.kenaz/main-memory/knowledge/solutions/001_json_bom_issue.md +0 -137
  76. package/core/.kenaz/main-memory/knowledge/solutions/001_team_invocation.md +0 -0
  77. package/core/.kenaz/main-memory/knowledge/solutions/002_passive_monitoring.md +0 -0
  78. package/core/.kenaz/main-memory/knowledge/solutions/003_windows_file_race_condition.md +0 -239
  79. package/core/.kenaz/main-memory/registry.json +0 -326
  80. package/core/.kenaz/main-memory/version.yaml +0 -58
  81. package/core/.kenaz/specialist/memory_guard_fired.json +0 -1
  82. package/core/.kenaz/specialist/memory_guard_trigger_cache.json +0 -1
  83. package/core/.kenaz/specialist/memory_source_priority.yaml +0 -260
  84. package/core/.kenaz/specialist/prompt_1775.txt +0 -317
  85. package/core/.kenaz/specialist/prompt_1776.txt +0 -326
  86. package/core/.kenaz/specialist/prompt_1791.txt +0 -320
  87. package/core/.kenaz/specialist/prompt_1792.txt +0 -320
  88. package/core/.kenaz/specialist/prompt_1795.txt +0 -281
  89. package/core/.kenaz/specialist/prompt_1813.txt +0 -332
  90. package/core/.kenaz/specialist/prompt_1814.txt +0 -401
  91. package/core/.kenaz/specialist/prompt_1815.txt +0 -394
  92. package/core/.kenaz/specialist/prompt_1816.txt +0 -437
  93. package/core/.kenaz/specialist/prompt_1818.txt +0 -361
  94. package/core/.kenaz/specialist/prompt_1819.txt +0 -421
  95. package/core/.kenaz/specialist/prompt_1821.txt +0 -345
  96. package/core/.kenaz/specialist/prompt_1822.txt +0 -313
  97. package/core/.kenaz/specialist/prompt_1824.txt +0 -348
  98. package/core/.kenaz/specialist/prompt_1826.txt +0 -388
  99. package/core/.kenaz/specialist/rune_efe_salience_gap.md +0 -21
  100. package/core/.kenaz/specialist/task1825_update.json +0 -43
  101. package/core/.kenaz/specialist/taskgen/consolidation_i.json +0 -38
  102. package/core/.kenaz/specialist/taskgen/csharp_a.json +0 -44
  103. package/core/.kenaz/specialist/taskgen/csharp_b.json +0 -40
  104. package/core/.kenaz/specialist/taskgen/embedding_e.json +0 -34
  105. package/core/.kenaz/specialist/taskgen/hygiene_fg.json +0 -39
  106. package/core/.kenaz/specialist/taskgen/pathology_h.json +0 -36
  107. package/core/.kenaz/specialist/taskgen/unity_noise_d.json +0 -38
  108. package/core/.kenaz/specialist/taskgen/visibility_c.json +0 -38
  109. package/core/.specialist/Ansuz/decisions/ADR-requirement-graph-layer.md +0 -390
  110. package/core/.specialist/Ansuz/self_model_seed.backup.json +0 -100
  111. package/core/.specialist/ansuz_session_handoff.json +0 -96
  112. package/core/dev/ALAYA_FIELD_FEEDBACK_DESIGN.md +0 -126
  113. package/core/dev/ANSUZ_SCAFFOLD_DIET_2026-09-20.md +0 -231
  114. package/core/dev/ANSUZ_STARTUP_INJECTION_REVIEW.md +0 -355
  115. package/core/dev/ANSUZ_WORKFLOW_MODERNIZATION.md +0 -143
  116. package/core/dev/CORTEX_META_GRAPH_ASSESSMENT.md +0 -99
  117. package/core/dev/FREYA_DOWNSTREAM_BUGS_2026-09-19.md +0 -44
  118. package/core/dev/GLOBAL_MEMORY_IDENTITY_CONSOLIDATION.md +0 -263
  119. package/core/dev/GUARD_EFFECTIVENESS_DESIGN.md +0 -180
  120. package/core/dev/HEALTH_GATE_VARIANCE_ASSESSMENT.md +0 -271
  121. package/core/dev/HOOK_DIET_2026-09-21.md +0 -126
  122. package/core/dev/JEV_INTEGRATION_PLAN.md +0 -189
  123. package/core/dev/KENAZ_AGENT_CONNECT_v1_SPEC.md +0 -139
  124. package/core/dev/MOBILE_DESIGN_SPEC.md +0 -569
  125. package/core/dev/MULTI_ANSUZ_SPEC.md +0 -136
  126. package/core/dev/MUNINN_RETIREMENT.md +0 -115
  127. package/core/dev/PHASE3_ATTRIBUTION_POPULATION_DIAGNOSIS.md +0 -211
  128. package/core/dev/PHASE3_P3-2B_TASKLEVEL_PROBE.md +0 -83
  129. package/core/dev/PHASE3_P3-2_POPULATION_DISJOINTNESS.md +0 -83
  130. package/core/dev/PHASE3_P3-2_REMEASURE_REPORT.md +0 -231
  131. package/core/dev/PREDICTION_GROUNDING_DESIGN.md +0 -376
  132. package/core/dev/PRODUCT_SPEC.md +0 -317
  133. package/core/dev/PROJECT_REGISTRY_DUPLICATE_ASSESSMENT.md +0 -86
  134. package/core/dev/STARTUP_TIMELINE_TASK_1995.md +0 -181
  135. package/core/dev/SYNAPSE_WORKER_PER_PROJECT.md +0 -881
  136. package/core/dev/TASK_1680_P3-3_DISPATCH_SPEC.md +0 -96
  137. package/core/dev/TASK_1684_CALIBRATION_IMPACT_ANALYSIS.md +0 -170
  138. package/core/dev/TASK_1684_FORK_A_GOODHART_DESIGN.md +0 -171
  139. package/core/dev/TASK_1684_P3_2_REMEASURE_VALIDATION.md +0 -262
  140. package/core/dev/TASK_1903_SIGNAL_AUC_MEASUREMENT.md +0 -207
  141. package/core/dev/TASK_1904_BRANCH_INTEGRITY_AUDIT.md +0 -146
  142. package/core/dev/ansuz-eval/README.md +0 -38
  143. package/core/dev/ansuz-eval/build-fixtures.js +0 -87
  144. package/core/dev/ansuz-eval/grade.js +0 -96
  145. package/core/dev/ansuz-eval/grader.test.js +0 -117
  146. package/core/dev/ansuz-eval/tasks.md +0 -32
  147. package/core/dev/archive/ansuz/BOOT_FULL.md +0 -141
  148. package/core/dev/archive/ansuz/agents/ansuz-boot.md +0 -176
  149. package/core/dev/archive/ansuz/designs/alaya-passive-surfacing.md +0 -84
  150. package/core/dev/archive/ansuz/designs/cc_memory_indexing.md +0 -307
  151. package/core/dev/archive/ansuz/designs/check_guard.md +0 -322
  152. package/core/dev/archive/ansuz/designs/consequence_loop.md +0 -227
  153. package/core/dev/archive/ansuz/designs/mcp_kuzudb_lock_architecture.md +0 -312
  154. package/core/dev/archive/ansuz/designs/phase0_git_enrichment.md +0 -278
  155. package/core/dev/archive/ansuz/designs/refactor_mcp_tools_synapse.md +0 -490
  156. package/core/dev/archive/ansuz/designs/semantic_markdown_extraction.md +0 -167
  157. package/core/dev/archive/ansuz/designs/task_1372_prompt_injects_into.md +0 -193
  158. package/core/dev/archive/ansuz/designs/thought_stack.md +0 -286
  159. package/core/dev/archive/ansuz/investigations/reachability_unified_api_2026-04-11.md +0 -330
  160. package/core/dev/archive/ansuz/investigations/synapse_orphans_indexing_bug_2026-04-11.md +0 -352
  161. package/core/dev/archive/ansuz/investigations/synapse_orphans_reindex_verification_2026-04-11.md +0 -48
  162. package/core/dev/archive/ansuz/investigations/synapse_orphans_verification_2026-04-11.md +0 -170
  163. package/core/dev/archive/ansuz/legacy/kernel.yaml +0 -399
  164. package/core/dev/archive/ansuz/legacy/phases/phase_0.yaml +0 -418
  165. package/core/dev/archive/ansuz/legacy/phases/phase_1.yaml +0 -376
  166. package/core/dev/archive/ansuz/legacy/phases/phase_10.yaml +0 -35
  167. package/core/dev/archive/ansuz/legacy/phases/phase_11.yaml +0 -582
  168. package/core/dev/archive/ansuz/legacy/phases/phase_2.yaml +0 -94
  169. package/core/dev/archive/ansuz/legacy/phases/phase_3.yaml +0 -274
  170. package/core/dev/archive/ansuz/legacy/phases/phase_4.yaml +0 -67
  171. package/core/dev/archive/ansuz/legacy/phases/phase_5.yaml +0 -32
  172. package/core/dev/archive/ansuz/legacy/phases/phase_6.yaml +0 -91
  173. package/core/dev/archive/ansuz/legacy/phases/phase_7.yaml +0 -58
  174. package/core/dev/archive/ansuz/legacy/phases/phase_8.yaml +0 -146
  175. package/core/dev/archive/ansuz/legacy/phases/phase_9.yaml +0 -424
  176. package/core/dev/archive/ansuz/specs/INDEX_bifrost_hook_parity.yaml +0 -92
  177. package/core/dev/archive/ansuz/specs/active-inference-formation.yaml +0 -453
  178. package/core/dev/archive/ansuz/specs/brief_TASK_1228_userpromptsubmit.yaml +0 -191
  179. package/core/dev/archive/ansuz/specs/brief_TASK_1229_pretooluse_posttooluse.yaml +0 -250
  180. package/core/dev/archive/ansuz/specs/brief_TASK_1230_sessionstart_stop.yaml +0 -301
  181. package/core/dev/archive/ansuz/specs/brief_TASK_1231_verification.yaml +0 -272
  182. package/core/dev/archive/skills/feature_agent/SKILL.md +0 -289
  183. package/core/dev/design/PHASE4_DESIGN.md +0 -559
  184. package/core/dev/design/dashboard_docs_integration_PLAN.md +0 -388
  185. package/core/dev/design/matrix_format_ABBREVIATIONS.md +0 -655
  186. package/core/dev/design/matrix_format_DESIGN_SPEC.md +0 -601
  187. package/core/dev/design/matrix_format_DISCUSSION_SUMMARY.md +0 -484
  188. package/core/dev/design/matrix_format_EXAMPLE_memory.matrix +0 -13
  189. package/core/dev/design/matrix_format_EXAMPLE_project_status.matrix +0 -9
  190. package/core/dev/design/matrix_format_EXAMPLE_tasks.matrix +0 -14
  191. package/core/dev/design/matrix_format_SYNTAX_BNF.md +0 -754
  192. package/core/dev/design/matrix_format_TOKEN_COMPARISON.md +0 -484
  193. package/core/dev/design/matrix_v2_COGNITIVE_DESIGN.md +0 -503
  194. package/core/dev/design/matrix_v2_DISCUSSION_SUMMARY.md +0 -414
  195. package/core/dev/design/matrix_v2_EXAMPLE.matrix +0 -67
  196. package/core/dev/designs/EXPANDABLE_CARD_DESIGN_SPEC.md +0 -509
  197. package/core/dev/jev-eval/ACTIVE_CORRECTION.md +0 -52
  198. package/core/dev/jev-eval/ANNOTATION_GUIDE.md +0 -68
  199. package/core/dev/jev-eval/BASELINE_COMPARISON.md +0 -45
  200. package/core/dev/jev-eval/CONTEXT_REVIEW.md +0 -31
  201. package/core/dev/jev-eval/EVALUATION_STATUS.md +0 -39
  202. package/core/dev/jev-eval/HISTORICAL_CORPUS.md +0 -33
  203. package/core/dev/jev-eval/PACKAGING_VERIFICATION.md +0 -42
  204. package/core/dev/jev-eval/README.md +0 -101
  205. package/core/dev/jev-eval/THALAMUS_RANKING.md +0 -58
  206. package/core/dev/jev-eval/VALIDATION_PROGRESS.md +0 -54
  207. package/core/dev/jev-eval/cli.mjs +0 -50
  208. package/core/dev/jev-eval/context.mjs +0 -183
  209. package/core/dev/jev-eval/corpus.mjs +0 -186
  210. package/core/dev/jev-eval/fixtures/conversation-review.seed.jsonl +0 -6
  211. package/core/dev/jev-eval/fixtures/synthetic.jsonl +0 -11
  212. package/core/dev/jev-eval/metrics.mjs +0 -67
  213. package/core/dev/jev-eval/muninn-baseline.mjs +0 -119
  214. package/core/dev/jev-eval/providers.mjs +0 -95
  215. package/core/dev/jev-eval/reports/annotation-pilot-2026-09-20.json +0 -32
  216. package/core/dev/jev-eval/reports/context-review-2026-09-20.json +0 -48
  217. package/core/dev/jev-eval/reports/conversation-review.pending.json +0 -151
  218. package/core/dev/jev-eval/reports/history-corpus-2026-09-20.json +0 -52
  219. package/core/dev/jev-eval/reports/length-probe-2026-09-20.json +0 -133
  220. package/core/dev/jev-eval/reports/live-smoke-2026-09-20.json +0 -616
  221. package/core/dev/jev-eval/reports/muninn-baseline-2026-09-20.json +0 -52
  222. package/core/dev/jev-eval/reports/resilience-2026-09-20.json +0 -520
  223. package/core/dev/jev-eval/reports/rules-baseline.json +0 -197
  224. package/core/dev/jev-eval/reports/synthetic-review.pending.json +0 -357
  225. package/core/dev/jev-eval/resilience.mjs +0 -71
  226. package/core/dev/jev-eval/review.mjs +0 -78
  227. package/core/dev/jev-eval/schema.mjs +0 -87
  228. package/core/dev/jev-eval/test/context.test.mjs +0 -95
  229. package/core/dev/jev-eval/test/corpus.test.mjs +0 -102
  230. package/core/dev/jev-eval/test/eval.test.mjs +0 -146
  231. package/core/dev/jev-eval/test/muninn-baseline.test.mjs +0 -71
  232. package/core/dev/jev-eval/test/resilience.test.mjs +0 -72
  233. package/core/dev/jev-eval/test/review.test.mjs +0 -61
  234. package/core/dev/pipeline/PHASE3_PLANNING_SUMMARY.md +0 -338
  235. package/core/dev/pipeline/PROGRESS.md +0 -113
  236. package/core/dev/pipeline/PROGRESS_template.md +0 -860
  237. package/core/dev/pipeline/QA_REPORT_F008.md +0 -431
  238. package/core/dev/pipeline/QA_REPORT_LOCAL_CLAUDE_DIAGNOSIS.md +0 -583
  239. package/core/dev/pipeline/README.md +0 -210
  240. package/core/dev/pipeline/WORKFLOW_GUIDE.md +0 -824
  241. package/core/dev/pipeline/archived/TASK_015_tauri_init.yaml +0 -53
  242. package/core/dev/pipeline/archived/TASK_016_tauri_commands.yaml +0 -54
  243. package/core/dev/pipeline/archived/TASK_017_rust_pty.yaml +0 -54
  244. package/core/dev/pipeline/archived/TASK_018_tauri_bundle.yaml +0 -53
  245. package/core/dev/pipeline/archived/TASK_019_release_workflow.yaml +0 -56
  246. package/core/dev/pipeline/archived/TASK_020_update_ui.yaml +0 -54
  247. package/core/dev/pipeline/archived/TASK_021_update_notification_ui.yaml +0 -55
  248. package/core/dev/pipeline/archived/TASK_022_remove_node_pty.yaml +0 -65
  249. package/core/dev/pipeline/archived/TASK_023_api_routes_migration.yaml +0 -86
  250. package/core/dev/pipeline/archived/TASK_024_feature_id_system.yaml +0 -51
  251. package/core/dev/pipeline/archived/TASK_025_executable_acceptance.yaml +0 -66
  252. package/core/dev/pipeline/archived/TASK_026_spec_versioning.yaml +0 -56
  253. package/core/dev/pipeline/archived/TASK_027_drift_detection.yaml +0 -60
  254. package/core/dev/pipeline/archived/TASK_028_tauri_pty_manager.yaml +0 -60
  255. package/core/dev/pipeline/archived/TASK_029_tauri_pty_commands.yaml +0 -62
  256. package/core/dev/pipeline/archived/TASK_030_frontend_session_adapter.yaml +0 -54
  257. package/core/dev/pipeline/archived/TASK_031_terminal_tauri_events.yaml +0 -56
  258. package/core/dev/pipeline/archived/TASK_041_scheduler_data_models.yaml +0 -54
  259. package/core/dev/pipeline/archived/TASK_042_path_lock_manager.yaml +0 -53
  260. package/core/dev/pipeline/archived/TASK_043_process_manager.yaml +0 -57
  261. package/core/dev/pipeline/archived/TASK_044_git_integration.yaml +0 -85
  262. package/core/dev/pipeline/archived/TASK_045_task_queue_manager.yaml +0 -54
  263. package/core/dev/pipeline/archived/TASK_046_scheduler_dispatcher.yaml +0 -60
  264. package/core/dev/pipeline/archived/TASK_047_tauri_scheduler_commands.yaml +0 -55
  265. package/core/dev/pipeline/archived/TASK_048_realtime_status_push.yaml +0 -92
  266. package/core/dev/pipeline/archived/TASK_049_frontend_scheduler_integration.yaml +0 -58
  267. package/core/dev/pipeline/archived/TASK_050_error_recovery.yaml +0 -56
  268. package/core/dev/pipeline/archived/TASK_051_optimization_proposals_backend.yaml +0 -53
  269. package/core/dev/pipeline/archived/TASK_052_optimization_proposals_ui.yaml +0 -58
  270. package/core/dev/pipeline/archived/TASK_053_optimization_proposals_diff_view.yaml +0 -54
  271. package/core/dev/pipeline/archived/TASK_054_multi_project_scheduler_state.yaml +0 -76
  272. package/core/dev/pipeline/archived/TASK_055_scheduler_api_project_scope.yaml +0 -64
  273. package/core/dev/pipeline/archived/TASK_056_frontend_scheduler_project_scope.yaml +0 -62
  274. package/core/dev/pipeline/archived/TASK_057_scheduler_module_structure.yaml +0 -54
  275. package/core/dev/pipeline/archived/TASK_058_scheduler_models_extract.yaml +0 -51
  276. package/core/dev/pipeline/archived/TASK_059_scheduler_core_extract.yaml +0 -51
  277. package/core/dev/pipeline/archived/TASK_060_scheduler_commands_extract.yaml +0 -51
  278. package/core/dev/pipeline/archived/TASK_061_scheduler_specialized_commands.yaml +0 -53
  279. package/core/dev/pipeline/archived/TASK_062_process_manager_module_structure.yaml +0 -56
  280. package/core/dev/pipeline/archived/TASK_063_process_manager_core_extract.yaml +0 -56
  281. package/core/dev/pipeline/archived/TASK_064_recovery_module_structure.yaml +0 -57
  282. package/core/dev/pipeline/archived/TASK_065_recovery_core_extract.yaml +0 -56
  283. package/core/dev/pipeline/archived/TASK_066_self_enhancement_scheduler_models.yaml +0 -60
  284. package/core/dev/pipeline/archived/TASK_067_agents_section_quick_actions.yaml +0 -53
  285. package/core/dev/pipeline/archived/TASK_067_self_enhancement_scheduler_core.yaml +0 -65
  286. package/core/dev/pipeline/archived/TASK_068_agent_workflow_rule_enhancement.yaml +0 -46
  287. package/core/dev/pipeline/archived/TASK_068_self_enhancement_tauri_commands.yaml +0 -61
  288. package/core/dev/pipeline/archived/TASK_069_agent_wizard_responsive.yaml +0 -46
  289. package/core/dev/pipeline/archived/TASK_069_self_enhancement_ui.yaml +0 -62
  290. package/core/dev/pipeline/archived/TASK_070_preview_panel_redesign.yaml +0 -62
  291. package/core/dev/pipeline/archived/TASK_070_self_enhancement_integration.yaml +0 -57
  292. package/core/dev/pipeline/archived/TASK_071_preview_panel_qa.yaml +0 -98
  293. package/core/dev/pipeline/archived/TASK_071_single_agent_config.yaml +0 -57
  294. package/core/dev/pipeline/archived/TASK_072_preview_modal_esc_fix.yaml +0 -71
  295. package/core/dev/pipeline/archived/TASK_072_product_review_module.yaml +0 -57
  296. package/core/dev/pipeline/archived/TASK_073_agents_page_component_refactor.yaml +0 -68
  297. package/core/dev/pipeline/archived/TASK_073_rename_single_agent.yaml +0 -64
  298. package/core/dev/pipeline/archived/TASK_074_preview_mode_ui_diagnosis.yaml +0 -71
  299. package/core/dev/pipeline/archived/TASK_074_single_agent_ui_toggle.yaml +0 -56
  300. package/core/dev/pipeline/archived/TASK_075_agents_page_component_refactor.yaml +0 -69
  301. package/core/dev/pipeline/archived/TASK_075_single_agent_integration_test.yaml +0 -75
  302. package/core/dev/pipeline/archived/TASK_076_preview_mode_ui_diagnosis.yaml +0 -70
  303. package/core/dev/pipeline/archived/TASK_076_single_agent_continuous_mode.yaml +0 -65
  304. package/core/dev/pipeline/archived/TASK_077_failure_directory_structure.yaml +0 -51
  305. package/core/dev/pipeline/archived/TASK_077_single_agent_typescript_types.yaml +0 -59
  306. package/core/dev/pipeline/archived/TASK_078_fail_001_agent_no_output.yaml +0 -53
  307. package/core/dev/pipeline/archived/TASK_078_single_agent_ui_simplify.yaml +0 -74
  308. package/core/dev/pipeline/archived/TASK_079_dashboard_rwd_responsive.yaml +0 -63
  309. package/core/dev/pipeline/archived/TASK_079_fail_002_json_bom.yaml +0 -56
  310. package/core/dev/pipeline/archived/TASK_080_fail_003_queue_pollution.yaml +0 -56
  311. package/core/dev/pipeline/archived/TASK_080_http_server_module.yaml +0 -55
  312. package/core/dev/pipeline/archived/TASK_081_failure_logging_tools.yaml +0 -57
  313. package/core/dev/pipeline/archived/TASK_081_http_api_routes.yaml +0 -62
  314. package/core/dev/pipeline/archived/TASK_082_frontend_api_adapter.yaml +0 -51
  315. package/core/dev/pipeline/archived/TASK_082_integrate_failure_to_workflow.yaml +0 -60
  316. package/core/dev/pipeline/archived/TASK_083_cleanup_nextjs_api.yaml +0 -48
  317. package/core/dev/pipeline/archived/TASK_083_task_queue_cleanup.yaml +0 -67
  318. package/core/dev/pipeline/archived/TASK_084_rust_dead_code_cleanup.yaml +0 -66
  319. package/core/dev/pipeline/archived/TASK_084_scheduler_sync_logic_fix.yaml +0 -68
  320. package/core/dev/pipeline/archived/TASK_085_http_api_web_mode_fixes.yaml +0 -46
  321. package/core/dev/pipeline/archived/TASK_085_memory_consolidation_0204_0205.yaml +0 -98
  322. package/core/dev/pipeline/archived/TASK_086_collapsible_preview_panel.yaml +0 -161
  323. package/core/dev/pipeline/archived/TASK_086_web_mode_feature_parity.yaml +0 -62
  324. package/core/dev/pipeline/archived/TASK_087_manual_memory_archival.yaml +0 -163
  325. package/core/dev/pipeline/archived/TASK_087_mobile_http_control.yaml +0 -68
  326. package/core/dev/pipeline/archived/TASK_088_fail_003_to_ppl_002_rule.yaml +0 -63
  327. package/core/dev/pipeline/archived/TASK_088_mobile_http_qa.yaml +0 -121
  328. package/core/dev/pipeline/archived/TASK_089_agent_collaboration_topic.yaml +0 -60
  329. package/core/dev/pipeline/archived/TASK_089_web_mode_monitor_fix.yaml +0 -58
  330. package/core/dev/pipeline/archived/TASK_090_cli_detection_fix.yaml +0 -61
  331. package/core/dev/pipeline/archived/TASK_090_ui_ux_lessons_topic.yaml +0 -63
  332. package/core/dev/pipeline/archived/TASK_091_expandable_card_design.yaml +0 -56
  333. package/core/dev/pipeline/archived/TASK_091_move_agent_section_components.yaml +0 -65
  334. package/core/dev/pipeline/archived/TASK_092_expandable_card_component.yaml +0 -60
  335. package/core/dev/pipeline/archived/TASK_092_refactor_agent_create_wizard.yaml +0 -84
  336. package/core/dev/pipeline/archived/TASK_093_taskcard_detail_integration.yaml +0 -57
  337. package/core/dev/pipeline/archived/TASK_093_update_barrel_exports_test.yaml +0 -84
  338. package/core/dev/pipeline/archived/TASK_094_ai_agent_generation_enhancement.yaml +0 -115
  339. package/core/dev/pipeline/archived/TASK_094_proposalcard_detail_integration.yaml +0 -55
  340. package/core/dev/pipeline/archived/TASK_095_preview_fixes.yaml +0 -129
  341. package/core/dev/pipeline/archived/TASK_095_single_agent_task_selector.yaml +0 -60
  342. package/core/dev/pipeline/archived/TASK_096_agents_page_ux_improvements.yaml +0 -163
  343. package/core/dev/pipeline/archived/TASK_096_single_agent_status_sync.yaml +0 -60
  344. package/core/dev/pipeline/archived/TASK_097_local_claude_error_logging.yaml +0 -59
  345. package/core/dev/pipeline/archived/TASK_097_single_agent_monitor_events.yaml +0 -59
  346. package/core/dev/pipeline/archived/TASK_098_product_manager_team_phase2.yaml +0 -60
  347. package/core/dev/pipeline/archived/TASK_098_single_agent_refactor_test.yaml +0 -58
  348. package/core/dev/pipeline/archived/TASK_099_backend_team_creation.yaml +0 -258
  349. package/core/dev/pipeline/archived/TASK_100_frontend_team_creation.yaml +0 -61
  350. package/core/dev/pipeline/archived/TASK_101_orchestrator_system.yaml +0 -403
  351. package/core/dev/pipeline/archived/TASK_102_designer_sre_teams.yaml +0 -90
  352. package/core/dev/pipeline/archived/TASK_103_integration_testing.yaml +0 -86
  353. package/core/dev/pipeline/archived/TASK_128_integration_testing.yaml +0 -83
  354. package/core/dev/pipeline/archived/TASK_134_cortex_v2_phase3_file_watcher.yaml +0 -65
  355. package/core/dev/pipeline/archived/TASK_134_team_http_api.yaml +0 -96
  356. package/core/dev/pipeline/archived/TASK_135_cortex_v2_phase3_git_monitor.yaml +0 -63
  357. package/core/dev/pipeline/archived/TASK_136_cortex_v2_phase3_change_analyzer.yaml +0 -69
  358. package/core/dev/pipeline/archived/TASK_137_cortex_v2_phase3_cache_invalidator.yaml +0 -67
  359. package/core/dev/pipeline/archived/TASK_137_team_orchestrator_integration.yaml +0 -93
  360. package/core/dev/pipeline/archived/TASK_138_cortex_v2_phase3_distributed_cache.yaml +0 -68
  361. package/core/dev/pipeline/archived/TASK_138_matrix_folder_structure.yaml +0 -61
  362. package/core/dev/pipeline/archived/TASK_139_cortex_v2_phase3_cache_prewarming.yaml +0 -65
  363. package/core/dev/pipeline/archived/TASK_146_unified_documentation.yaml +0 -141
  364. package/core/dev/pipeline/archived/TASK_147_pipeline_execution_rules.yaml +0 -76
  365. package/core/dev/pipeline/archived/TASK_148_update_claude_md.yaml +0 -77
  366. package/core/dev/pipeline/archived/TASK_149_fix_nextjs_mdx_serialization.yaml +0 -63
  367. package/core/dev/pipeline/archived/TASK_149_update_team_docs.yaml +0 -77
  368. package/core/dev/pipeline/archived/TASK_150_pipeline_workflow_guide.yaml +0 -82
  369. package/core/dev/pipeline/archived/TASK_164_fix_smart_context_switch.yaml +0 -49
  370. package/core/dev/pipeline/archived/TASK_165_ctags_symbol_index.yaml +0 -53
  371. package/core/dev/pipeline/archived/TASK_166_symbol_search_mcp_tool.yaml +0 -48
  372. package/core/dev/pipeline/archived/TASK_167_llm_module_summary.yaml +0 -55
  373. package/core/dev/pipeline/archived/TASK_168_map_reduce_context.yaml +0 -51
  374. package/core/dev/pipeline/archived/TASK_169_v2_integration_testing.yaml +0 -52
  375. package/core/dev/pipeline/backups/archive_2026-02-04T22-07-22/TASK_QUEUE_backup.json +0 -95
  376. package/core/dev/pipeline/docs/multi-agent-coordination.md +0 -446
  377. package/core/dev/pipeline/docs/overview.md +0 -406
  378. package/core/dev/pipeline/docs/task-management.md +0 -412
  379. package/core/dev/pipeline/docs/workflows.md +0 -32
  380. package/core/dev/pipeline/orchestrator/schemas/task_queue_schema.json +0 -58
  381. package/core/dev/pipeline/orchestrator/schemas/task_schema.json +0 -139
  382. package/core/dev/pipeline/plans/PLAN_task_cli_refactor.md +0 -281
  383. package/core/dev/pipeline/test_results/TASK_TEST_PARALLEL_002_result.txt +0 -27
  384. package/core/dev/plans/ANSUZ_SLIM_PLAN.md +0 -68
  385. package/core/dev/plans/CLI_FIRST_INSTALL_FLOW.md +0 -120
  386. package/core/dev/plans/FORMATION_RETIREMENT_PLAN.md +0 -313
  387. package/core/dev/plans/KUZU_REPLACEMENT_PLAN.md +0 -126
  388. package/core/dev/scripts/CRASH_DIAGNOSIS.md +0 -47
  389. package/core/dev/scripts/README.md +0 -142
  390. package/core/dev/scripts/RUN_ONCE.bat +0 -40
  391. package/core/dev/scripts/START_DEV_AGENT.bat +0 -63
  392. package/core/dev/scripts/START_MULTI_AGENT.bat +0 -80
  393. package/core/dev/scripts/dev_agent_scheduler.ps1 +0 -536
  394. package/core/dev/scripts/init_git.ps1 +0 -396
  395. package/core/dev/scripts/init_git.sh +0 -337
  396. package/core/dev/scripts/init_project.ps1 +0 -851
  397. package/core/dev/scripts/init_project.sh +0 -477
  398. package/core/dev/scripts/multi_agent_scheduler.ps1 +0 -2021
  399. package/core/dev/scripts/multi_agent_scheduler.sh +0 -1344
  400. package/core/dev/scripts/run_once.sh +0 -47
  401. package/core/dev/scripts/setup_rag.ps1 +0 -304
  402. package/core/dev/scripts/setup_rag.sh +0 -230
  403. package/core/dev/scripts/start_dev_agent.sh +0 -137
  404. package/core/dev/scripts/start_multi_agent.sh +0 -41
  405. package/core/dev/scripts/sync_task_queue.ps1 +0 -505
  406. package/core/dev/scripts/sync_task_queue.sh +0 -392
  407. package/core/dev/specs/agent-connect/PROTOCOL.md +0 -177
  408. package/core/dev/specs/agent-connect/SDK_GUIDE.md +0 -915
  409. package/core/dev/specs/agent-connect/examples/minimal-site/README.md +0 -137
  410. package/core/dev/specs/agent-connect/examples/minimal-site/package.json +0 -12
  411. package/core/dev/specs/agent-connect/examples/minimal-site/public/index.html +0 -116
  412. package/core/dev/specs/agent-connect/examples/minimal-site/public/install-redirect.js +0 -73
  413. package/core/dev/specs/agent-connect/examples/minimal-site/server.js +0 -516
  414. package/core/dev/specs/agent-connect/examples/minimal-site/test/smoke.test.mjs +0 -263
  415. 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
  416. package/core/dev/specs/agent-connect/history/DEFECT_REPORT_kenaz-agent-hub_2026-09-09_v0.4-prompt-mojibake.md +0 -90
  417. package/core/dev/specs/agent-connect/history/FEATURE_REQUEST_kenaz-agent-hub_2026-09-07.md +0 -61
  418. package/core/dev/specs/agent-connect/history/FEATURE_REQUEST_kenaz-agent-hub_2026-09-08_relay-v1-conformance.md +0 -76
  419. package/core/dev/specs/agent-connect/history/FEATURE_REQUEST_kenaz-agent-hub_2026-09-09_v0.4-session-channel.md +0 -87
  420. package/core/dev/specs/agent-connect/history/FLOWPIX_REPLY_agent-hub_2026-09-08_relay-v1-answers.md +0 -68
  421. package/core/dev/specs/agent-connect/history/FLOWPIX_bridge_CONTRACT.md +0 -642
  422. package/core/dev/specs/agent-connect/history/FLOWPIX_spikes_relay_spike_relay.mjs +0 -244
  423. package/core/dev/specs/agent-connect/history/KENAZ_RESPONSE_agent-hub_2026-09-07.md +0 -77
  424. package/core/dev/specs/agent-connect/history/KENAZ_RESPONSE_agent-hub_2026-09-08_direction-change-v0.3.md +0 -44
  425. package/core/dev/specs/agent-connect/history/KENAZ_RESPONSE_agent-hub_2026-09-08_relay-v1-answers-ack.md +0 -37
  426. package/core/dev/specs/agent-connect/history/KENAZ_RESPONSE_agent-hub_2026-09-08_relay-v1-conformance.md +0 -56
  427. package/core/dev/specs/agent-connect/history/KENAZ_RESPONSE_agent-hub_2026-09-09_annotations-install-coldstart.md +0 -44
  428. package/core/dev/specs/agent-connect/history/KENAZ_RESPONSE_agent-hub_2026-09-09_empty-prompt-first-turn.md +0 -56
  429. package/core/dev/specs/agent-connect/history/KENAZ_RESPONSE_agent-hub_2026-09-09_prompt-mojibake-fixed.md +0 -48
  430. package/core/dev/specs/agent-connect/history/KENAZ_RESPONSE_agent-hub_2026-09-09_session-channel.md +0 -57
  431. package/core/dev/specs/agent-connect/history/PROTOCOL_v0.3_snapshot.md +0 -379
  432. package/core/dev/specs/agent-connect/history/README.md +0 -47
  433. package/core/dev/specs/peer/CODEX_INTERACTIVE_PUSH.md +0 -65
  434. package/core/dev/specs/peer/CODEX_MANAGED_DAEMON.md +0 -54
  435. package/core/dev/specs/peer/CODEX_PEER_PULL_SPIKE.md +0 -54
  436. package/core/dev/specs/peer/MODS_SPIKE.md +0 -133
  437. package/core/dev/specs/peer/PER_PROJECT_ADDRESSING.md +0 -143
  438. package/core/dev/specs/peer/SWARM_PROTOCOLS.md +0 -256
  439. package/core/dev/specs/peer/codex-hook-shim-peer.test.js +0 -113
  440. package/core/dev/specs/peer/codex-push-launcher.test.js +0 -142
  441. package/core/dev/specs/peer/setup-codex-hooks.test.js +0 -60
  442. package/core/dev/specs/peer-ansuz/DELIVERY_SPIKE.md +0 -397
  443. package/core/dev/specs/peer-ansuz/DESIGN.md +0 -109
  444. package/core/dev/specs/peer-ansuz/spike/claude_poke.js +0 -129
  445. package/core/dev/specs/peer-ansuz/spike/claude_session_start_hook.js +0 -37
  446. package/core/dev/specs/peer-ansuz/spike/claude_settings_hook.json +0 -14
  447. package/core/dev/specs/peer-ansuz/spike/codex_appserver_client.js +0 -105
  448. package/core/dev/specs/peer-ansuz/spike/codex_appserver_query.js +0 -29
  449. package/core/dev/specs/peer-ansuz/spike/extract_timeline.js +0 -26
  450. package/core/dev/specs/synapse/SYMBOL_IDENTITY.md +0 -305
  451. package/core/dev/spikes/A4-cypher-varlen.md +0 -176
  452. package/core/dev/spikes/bloat-rounds.sh +0 -25
  453. package/core/dev/spikes/mods/clean-claude.js +0 -9
  454. package/core/dev/spikes/mods/drive-probe.js +0 -29
  455. package/core/dev/spikes/mods/e2e-peer.js +0 -71
  456. package/core/dev/spikes/mods/evidence/e2e-peer-control.json +0 -17
  457. package/core/dev/spikes/mods/evidence/e2e-peer-mod.json +0 -17
  458. package/core/dev/spikes/mods/evidence/probe-006a6e65-d807-4bc1-b648-fd7d1edfe0b4.jsonl +0 -4
  459. package/core/dev/spikes/mods/evidence/probe-cebdf1f7-f9c4-47a8-83cd-7c0786177404.jsonl +0 -12
  460. package/core/dev/spikes/mods/evidence/probe-eb21147d-10ce-4c32-93ed-37ca37d88d5a.jsonl +0 -11
  461. package/core/dev/spikes/mods/evidence/stream-cebdf1f7.jsonl +0 -18
  462. package/core/dev/spikes/mods/kenaz-mod-probe/.claude-plugin/plugin.json +0 -1
  463. package/core/dev/spikes/mods/kenaz-mod-probe/hooks/hooks.json +0 -1
  464. package/core/dev/spikes/mods/kenaz-mod-probe/hooks/register.ts +0 -65
  465. 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
- });