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.
- package/core/.claude/hooks/_user-scope.js +1 -1
- package/core/.claude/hooks/core-resolve.js +1 -1
- package/core/.claude/hooks/worktree-create.js +6 -6
- package/core/.claude/hooks/worktree-remove.js +4 -4
- package/core/.collaboration/core/reconcile.js +16 -1
- package/core/.collaboration/core/task-2467-lifecycle.test.js +63 -0
- package/core/.collaboration/core/task-api.js +37 -7
- package/core/.formation/bifrost/launch.js +1 -1
- package/core/.formation/tools/kenaz-stats.js +1 -1
- package/core/.formation/tools/post-complete/git-merge.js +1 -1
- package/core/.formation/tools/prompt.js +1 -1
- package/core/.kenaz/specialist/ansuz_rules.yaml +7 -51
- package/core/.kenaz/specialist/ansuz_session_handoff.schema.json +2 -6
- package/core/.rule/general/project-self-containment.yaml +2 -2
- package/core/.specialist/Amelia/README.md +1 -1
- package/core/.specialist/Amelia/rule.yaml +1 -1
- package/core/.specialist/Ansuz/RULES.md +1 -1
- package/core/.specialist/Ansuz/concepts/commitment_layer.yaml +1 -1
- package/core/.specialist/Ansuz/concepts/evolvable_guardrails.yaml +1 -1
- package/core/.specialist/Ansuz/knowledge.yaml +1 -3
- package/core/.specialist/tools/__tests__/task-2409-lessons.test.js +10 -0
- package/core/.specialist/tools/__tests__/task-2427-harvest.test.js +25 -0
- package/core/.specialist/tools/ansuz-boot-fast.js +1 -1
- package/core/.specialist/tools/failure-detector.js +4 -4
- package/core/.specialist/tools/handoff-doc.js +1 -1
- package/core/.specialist/tools/lessons.js +2 -2
- package/core/CLAUDE.md +5 -5
- package/core/KENAZ_CORE_VERSION +1 -1
- package/core/dashboard/scripts/install-kenaz-cli.js +21 -6
- package/core/dev/scripts/check-file-size.js +1 -1
- package/core/dev/scripts/ci-feedback.js +1 -1
- package/core/dev/scripts/gc-agent-worktrees.js +11 -11
- package/core/dev/scripts/kenaz-session.js +3 -3
- package/core/dev/scripts/peer-identity-e2e.js +3 -3
- package/core/dev/scripts/run-rust-tests.js +2 -2
- package/core/dev/scripts/skill-routing-replay.js +3 -3
- package/core/dev/scripts/task1961/selftest.js +2 -2
- package/core/dev/scripts/windows-hide-guard.test.js +97 -0
- package/core/plugins/kenaz/guidance.md +1 -0
- package/core/plugins/kenaz/hooks/core-resolve.js +1 -1
- package/core/plugins/kenaz/hooks/kenaz-hook.js +52 -4
- package/core/plugins/kenaz/scripts/kenaz.test.js +72 -5
- package/lib/cli.js +9 -5
- package/package.json +6 -6
- package/vendor/install-kenaz-cli.js +21 -6
- package/core/.kenaz/designs/METAPLASTICITY_CONFIDENCE_DESIGN.md +0 -537
- package/core/.kenaz/designs/REFLEX_INITIATOR_DESIGN.md +0 -501
- package/core/.kenaz/designs/TASK_1385_handoff_mcp_design.md +0 -426
- package/core/.kenaz/designs/TASK_932_hippocampus_consolidation.md +0 -103
- package/core/.kenaz/designs/TASK_934_efe_signal_engine.md +0 -97
- package/core/.kenaz/designs/TASK_935_self_evolution_framework.md +0 -154
- package/core/.kenaz/designs/VISION_cognitive_architecture_roadmap.md +0 -159
- package/core/.kenaz/designs/metaplasticity_simulation_results.json +0 -696
- package/core/.kenaz/main-memory/README.md +0 -230
- package/core/.kenaz/main-memory/kenaz/cortex/001_cortex_overview.md +0 -168
- package/core/.kenaz/main-memory/kenaz/cortex/001_rag_engine_overview.md +0 -30
- package/core/.kenaz/main-memory/kenaz/memory-system/001_three_tier_architecture.md +0 -361
- package/core/.kenaz/main-memory/kenaz/pipeline/001_task_execution_flow.md +0 -117
- package/core/.kenaz/main-memory/kenaz/pipeline/001_task_granularity.md +0 -154
- package/core/.kenaz/main-memory/kenaz/pipeline/002_team_priority.md +0 -51
- package/core/.kenaz/main-memory/kenaz/pipeline/003_feature_id_system.md +0 -46
- package/core/.kenaz/main-memory/kenaz/rules/001_gen_007_self_containment.md +0 -108
- package/core/.kenaz/main-memory/kenaz/rules/001_rule_priority_system.md +0 -121
- package/core/.kenaz/main-memory/kenaz/rules/002_agt_006_pre_check.md +0 -0
- package/core/.kenaz/main-memory/kenaz/rules/003_ppl_002_task_archival.md +0 -48
- package/core/.kenaz/main-memory/kenaz/system/001_dual_track_task_system.md +0 -197
- package/core/.kenaz/main-memory/knowledge/patterns/001_json_bom_issue.md +0 -78
- package/core/.kenaz/main-memory/knowledge/patterns/001_leader_worker_pattern.md +0 -0
- package/core/.kenaz/main-memory/knowledge/patterns/002_scope_path_conflict.md +0 -115
- package/core/.kenaz/main-memory/knowledge/patterns/002_task_dependency_resolution.md +0 -223
- package/core/.kenaz/main-memory/knowledge/patterns/003_question_protocol.md +0 -242
- package/core/.kenaz/main-memory/knowledge/patterns/004_user_insight_value.md +0 -111
- package/core/.kenaz/main-memory/knowledge/patterns/005_file_lock_pattern.md +0 -274
- package/core/.kenaz/main-memory/knowledge/references/001_ppl_rules.md +0 -28
- package/core/.kenaz/main-memory/knowledge/solutions/001_json_bom_issue.md +0 -137
- package/core/.kenaz/main-memory/knowledge/solutions/001_team_invocation.md +0 -0
- package/core/.kenaz/main-memory/knowledge/solutions/002_passive_monitoring.md +0 -0
- package/core/.kenaz/main-memory/knowledge/solutions/003_windows_file_race_condition.md +0 -239
- package/core/.kenaz/main-memory/registry.json +0 -326
- package/core/.kenaz/main-memory/version.yaml +0 -58
- package/core/.kenaz/specialist/memory_guard_fired.json +0 -1
- package/core/.kenaz/specialist/memory_guard_trigger_cache.json +0 -1
- package/core/.kenaz/specialist/memory_source_priority.yaml +0 -260
- package/core/.kenaz/specialist/prompt_1775.txt +0 -317
- package/core/.kenaz/specialist/prompt_1776.txt +0 -326
- package/core/.kenaz/specialist/prompt_1791.txt +0 -320
- package/core/.kenaz/specialist/prompt_1792.txt +0 -320
- package/core/.kenaz/specialist/prompt_1795.txt +0 -281
- package/core/.kenaz/specialist/prompt_1813.txt +0 -332
- package/core/.kenaz/specialist/prompt_1814.txt +0 -401
- package/core/.kenaz/specialist/prompt_1815.txt +0 -394
- package/core/.kenaz/specialist/prompt_1816.txt +0 -437
- package/core/.kenaz/specialist/prompt_1818.txt +0 -361
- package/core/.kenaz/specialist/prompt_1819.txt +0 -421
- package/core/.kenaz/specialist/prompt_1821.txt +0 -345
- package/core/.kenaz/specialist/prompt_1822.txt +0 -313
- package/core/.kenaz/specialist/prompt_1824.txt +0 -348
- package/core/.kenaz/specialist/prompt_1826.txt +0 -388
- package/core/.kenaz/specialist/rune_efe_salience_gap.md +0 -21
- package/core/.kenaz/specialist/task1825_update.json +0 -43
- package/core/.kenaz/specialist/taskgen/consolidation_i.json +0 -38
- package/core/.kenaz/specialist/taskgen/csharp_a.json +0 -44
- package/core/.kenaz/specialist/taskgen/csharp_b.json +0 -40
- package/core/.kenaz/specialist/taskgen/embedding_e.json +0 -34
- package/core/.kenaz/specialist/taskgen/hygiene_fg.json +0 -39
- package/core/.kenaz/specialist/taskgen/pathology_h.json +0 -36
- package/core/.kenaz/specialist/taskgen/unity_noise_d.json +0 -38
- package/core/.kenaz/specialist/taskgen/visibility_c.json +0 -38
- package/core/.specialist/Ansuz/decisions/ADR-requirement-graph-layer.md +0 -390
- package/core/.specialist/Ansuz/self_model_seed.backup.json +0 -100
- package/core/.specialist/ansuz_session_handoff.json +0 -96
- package/core/dev/ALAYA_FIELD_FEEDBACK_DESIGN.md +0 -126
- package/core/dev/ANSUZ_SCAFFOLD_DIET_2026-09-20.md +0 -231
- package/core/dev/ANSUZ_STARTUP_INJECTION_REVIEW.md +0 -355
- package/core/dev/ANSUZ_WORKFLOW_MODERNIZATION.md +0 -143
- package/core/dev/CORTEX_META_GRAPH_ASSESSMENT.md +0 -99
- package/core/dev/FREYA_DOWNSTREAM_BUGS_2026-09-19.md +0 -44
- package/core/dev/GLOBAL_MEMORY_IDENTITY_CONSOLIDATION.md +0 -263
- package/core/dev/GUARD_EFFECTIVENESS_DESIGN.md +0 -180
- package/core/dev/HEALTH_GATE_VARIANCE_ASSESSMENT.md +0 -271
- package/core/dev/HOOK_DIET_2026-09-21.md +0 -126
- package/core/dev/JEV_INTEGRATION_PLAN.md +0 -189
- package/core/dev/KENAZ_AGENT_CONNECT_v1_SPEC.md +0 -139
- package/core/dev/MOBILE_DESIGN_SPEC.md +0 -569
- package/core/dev/MULTI_ANSUZ_SPEC.md +0 -136
- package/core/dev/MUNINN_RETIREMENT.md +0 -115
- package/core/dev/PHASE3_ATTRIBUTION_POPULATION_DIAGNOSIS.md +0 -211
- package/core/dev/PHASE3_P3-2B_TASKLEVEL_PROBE.md +0 -83
- package/core/dev/PHASE3_P3-2_POPULATION_DISJOINTNESS.md +0 -83
- package/core/dev/PHASE3_P3-2_REMEASURE_REPORT.md +0 -231
- package/core/dev/PREDICTION_GROUNDING_DESIGN.md +0 -376
- package/core/dev/PRODUCT_SPEC.md +0 -317
- package/core/dev/PROJECT_REGISTRY_DUPLICATE_ASSESSMENT.md +0 -86
- package/core/dev/STARTUP_TIMELINE_TASK_1995.md +0 -181
- package/core/dev/SYNAPSE_WORKER_PER_PROJECT.md +0 -881
- package/core/dev/TASK_1680_P3-3_DISPATCH_SPEC.md +0 -96
- package/core/dev/TASK_1684_CALIBRATION_IMPACT_ANALYSIS.md +0 -170
- package/core/dev/TASK_1684_FORK_A_GOODHART_DESIGN.md +0 -171
- package/core/dev/TASK_1684_P3_2_REMEASURE_VALIDATION.md +0 -262
- package/core/dev/TASK_1903_SIGNAL_AUC_MEASUREMENT.md +0 -207
- package/core/dev/TASK_1904_BRANCH_INTEGRITY_AUDIT.md +0 -146
- package/core/dev/ansuz-eval/README.md +0 -38
- package/core/dev/ansuz-eval/build-fixtures.js +0 -87
- package/core/dev/ansuz-eval/grade.js +0 -96
- package/core/dev/ansuz-eval/grader.test.js +0 -117
- package/core/dev/ansuz-eval/tasks.md +0 -32
- package/core/dev/archive/ansuz/BOOT_FULL.md +0 -141
- package/core/dev/archive/ansuz/agents/ansuz-boot.md +0 -176
- package/core/dev/archive/ansuz/designs/alaya-passive-surfacing.md +0 -84
- package/core/dev/archive/ansuz/designs/cc_memory_indexing.md +0 -307
- package/core/dev/archive/ansuz/designs/check_guard.md +0 -322
- package/core/dev/archive/ansuz/designs/consequence_loop.md +0 -227
- package/core/dev/archive/ansuz/designs/mcp_kuzudb_lock_architecture.md +0 -312
- package/core/dev/archive/ansuz/designs/phase0_git_enrichment.md +0 -278
- package/core/dev/archive/ansuz/designs/refactor_mcp_tools_synapse.md +0 -490
- package/core/dev/archive/ansuz/designs/semantic_markdown_extraction.md +0 -167
- package/core/dev/archive/ansuz/designs/task_1372_prompt_injects_into.md +0 -193
- package/core/dev/archive/ansuz/designs/thought_stack.md +0 -286
- package/core/dev/archive/ansuz/investigations/reachability_unified_api_2026-04-11.md +0 -330
- package/core/dev/archive/ansuz/investigations/synapse_orphans_indexing_bug_2026-04-11.md +0 -352
- package/core/dev/archive/ansuz/investigations/synapse_orphans_reindex_verification_2026-04-11.md +0 -48
- package/core/dev/archive/ansuz/investigations/synapse_orphans_verification_2026-04-11.md +0 -170
- package/core/dev/archive/ansuz/legacy/kernel.yaml +0 -399
- package/core/dev/archive/ansuz/legacy/phases/phase_0.yaml +0 -418
- package/core/dev/archive/ansuz/legacy/phases/phase_1.yaml +0 -376
- package/core/dev/archive/ansuz/legacy/phases/phase_10.yaml +0 -35
- package/core/dev/archive/ansuz/legacy/phases/phase_11.yaml +0 -582
- package/core/dev/archive/ansuz/legacy/phases/phase_2.yaml +0 -94
- package/core/dev/archive/ansuz/legacy/phases/phase_3.yaml +0 -274
- package/core/dev/archive/ansuz/legacy/phases/phase_4.yaml +0 -67
- package/core/dev/archive/ansuz/legacy/phases/phase_5.yaml +0 -32
- package/core/dev/archive/ansuz/legacy/phases/phase_6.yaml +0 -91
- package/core/dev/archive/ansuz/legacy/phases/phase_7.yaml +0 -58
- package/core/dev/archive/ansuz/legacy/phases/phase_8.yaml +0 -146
- package/core/dev/archive/ansuz/legacy/phases/phase_9.yaml +0 -424
- package/core/dev/archive/ansuz/specs/INDEX_bifrost_hook_parity.yaml +0 -92
- package/core/dev/archive/ansuz/specs/active-inference-formation.yaml +0 -453
- package/core/dev/archive/ansuz/specs/brief_TASK_1228_userpromptsubmit.yaml +0 -191
- package/core/dev/archive/ansuz/specs/brief_TASK_1229_pretooluse_posttooluse.yaml +0 -250
- package/core/dev/archive/ansuz/specs/brief_TASK_1230_sessionstart_stop.yaml +0 -301
- package/core/dev/archive/ansuz/specs/brief_TASK_1231_verification.yaml +0 -272
- package/core/dev/archive/skills/feature_agent/SKILL.md +0 -289
- package/core/dev/design/PHASE4_DESIGN.md +0 -559
- package/core/dev/design/dashboard_docs_integration_PLAN.md +0 -388
- package/core/dev/design/matrix_format_ABBREVIATIONS.md +0 -655
- package/core/dev/design/matrix_format_DESIGN_SPEC.md +0 -601
- package/core/dev/design/matrix_format_DISCUSSION_SUMMARY.md +0 -484
- package/core/dev/design/matrix_format_EXAMPLE_memory.matrix +0 -13
- package/core/dev/design/matrix_format_EXAMPLE_project_status.matrix +0 -9
- package/core/dev/design/matrix_format_EXAMPLE_tasks.matrix +0 -14
- package/core/dev/design/matrix_format_SYNTAX_BNF.md +0 -754
- package/core/dev/design/matrix_format_TOKEN_COMPARISON.md +0 -484
- package/core/dev/design/matrix_v2_COGNITIVE_DESIGN.md +0 -503
- package/core/dev/design/matrix_v2_DISCUSSION_SUMMARY.md +0 -414
- package/core/dev/design/matrix_v2_EXAMPLE.matrix +0 -67
- package/core/dev/designs/EXPANDABLE_CARD_DESIGN_SPEC.md +0 -509
- package/core/dev/jev-eval/ACTIVE_CORRECTION.md +0 -52
- package/core/dev/jev-eval/ANNOTATION_GUIDE.md +0 -68
- package/core/dev/jev-eval/BASELINE_COMPARISON.md +0 -45
- package/core/dev/jev-eval/CONTEXT_REVIEW.md +0 -31
- package/core/dev/jev-eval/EVALUATION_STATUS.md +0 -39
- package/core/dev/jev-eval/HISTORICAL_CORPUS.md +0 -33
- package/core/dev/jev-eval/PACKAGING_VERIFICATION.md +0 -42
- package/core/dev/jev-eval/README.md +0 -101
- package/core/dev/jev-eval/THALAMUS_RANKING.md +0 -58
- package/core/dev/jev-eval/VALIDATION_PROGRESS.md +0 -54
- package/core/dev/jev-eval/cli.mjs +0 -50
- package/core/dev/jev-eval/context.mjs +0 -183
- package/core/dev/jev-eval/corpus.mjs +0 -186
- package/core/dev/jev-eval/fixtures/conversation-review.seed.jsonl +0 -6
- package/core/dev/jev-eval/fixtures/synthetic.jsonl +0 -11
- package/core/dev/jev-eval/metrics.mjs +0 -67
- package/core/dev/jev-eval/muninn-baseline.mjs +0 -119
- package/core/dev/jev-eval/providers.mjs +0 -95
- package/core/dev/jev-eval/reports/annotation-pilot-2026-09-20.json +0 -32
- package/core/dev/jev-eval/reports/context-review-2026-09-20.json +0 -48
- package/core/dev/jev-eval/reports/conversation-review.pending.json +0 -151
- package/core/dev/jev-eval/reports/history-corpus-2026-09-20.json +0 -52
- package/core/dev/jev-eval/reports/length-probe-2026-09-20.json +0 -133
- package/core/dev/jev-eval/reports/live-smoke-2026-09-20.json +0 -616
- package/core/dev/jev-eval/reports/muninn-baseline-2026-09-20.json +0 -52
- package/core/dev/jev-eval/reports/resilience-2026-09-20.json +0 -520
- package/core/dev/jev-eval/reports/rules-baseline.json +0 -197
- package/core/dev/jev-eval/reports/synthetic-review.pending.json +0 -357
- package/core/dev/jev-eval/resilience.mjs +0 -71
- package/core/dev/jev-eval/review.mjs +0 -78
- package/core/dev/jev-eval/schema.mjs +0 -87
- package/core/dev/jev-eval/test/context.test.mjs +0 -95
- package/core/dev/jev-eval/test/corpus.test.mjs +0 -102
- package/core/dev/jev-eval/test/eval.test.mjs +0 -146
- package/core/dev/jev-eval/test/muninn-baseline.test.mjs +0 -71
- package/core/dev/jev-eval/test/resilience.test.mjs +0 -72
- package/core/dev/jev-eval/test/review.test.mjs +0 -61
- package/core/dev/pipeline/PHASE3_PLANNING_SUMMARY.md +0 -338
- package/core/dev/pipeline/PROGRESS.md +0 -113
- package/core/dev/pipeline/PROGRESS_template.md +0 -860
- package/core/dev/pipeline/QA_REPORT_F008.md +0 -431
- package/core/dev/pipeline/QA_REPORT_LOCAL_CLAUDE_DIAGNOSIS.md +0 -583
- package/core/dev/pipeline/README.md +0 -210
- package/core/dev/pipeline/WORKFLOW_GUIDE.md +0 -824
- package/core/dev/pipeline/archived/TASK_015_tauri_init.yaml +0 -53
- package/core/dev/pipeline/archived/TASK_016_tauri_commands.yaml +0 -54
- package/core/dev/pipeline/archived/TASK_017_rust_pty.yaml +0 -54
- package/core/dev/pipeline/archived/TASK_018_tauri_bundle.yaml +0 -53
- package/core/dev/pipeline/archived/TASK_019_release_workflow.yaml +0 -56
- package/core/dev/pipeline/archived/TASK_020_update_ui.yaml +0 -54
- package/core/dev/pipeline/archived/TASK_021_update_notification_ui.yaml +0 -55
- package/core/dev/pipeline/archived/TASK_022_remove_node_pty.yaml +0 -65
- package/core/dev/pipeline/archived/TASK_023_api_routes_migration.yaml +0 -86
- package/core/dev/pipeline/archived/TASK_024_feature_id_system.yaml +0 -51
- package/core/dev/pipeline/archived/TASK_025_executable_acceptance.yaml +0 -66
- package/core/dev/pipeline/archived/TASK_026_spec_versioning.yaml +0 -56
- package/core/dev/pipeline/archived/TASK_027_drift_detection.yaml +0 -60
- package/core/dev/pipeline/archived/TASK_028_tauri_pty_manager.yaml +0 -60
- package/core/dev/pipeline/archived/TASK_029_tauri_pty_commands.yaml +0 -62
- package/core/dev/pipeline/archived/TASK_030_frontend_session_adapter.yaml +0 -54
- package/core/dev/pipeline/archived/TASK_031_terminal_tauri_events.yaml +0 -56
- package/core/dev/pipeline/archived/TASK_041_scheduler_data_models.yaml +0 -54
- package/core/dev/pipeline/archived/TASK_042_path_lock_manager.yaml +0 -53
- package/core/dev/pipeline/archived/TASK_043_process_manager.yaml +0 -57
- package/core/dev/pipeline/archived/TASK_044_git_integration.yaml +0 -85
- package/core/dev/pipeline/archived/TASK_045_task_queue_manager.yaml +0 -54
- package/core/dev/pipeline/archived/TASK_046_scheduler_dispatcher.yaml +0 -60
- package/core/dev/pipeline/archived/TASK_047_tauri_scheduler_commands.yaml +0 -55
- package/core/dev/pipeline/archived/TASK_048_realtime_status_push.yaml +0 -92
- package/core/dev/pipeline/archived/TASK_049_frontend_scheduler_integration.yaml +0 -58
- package/core/dev/pipeline/archived/TASK_050_error_recovery.yaml +0 -56
- package/core/dev/pipeline/archived/TASK_051_optimization_proposals_backend.yaml +0 -53
- package/core/dev/pipeline/archived/TASK_052_optimization_proposals_ui.yaml +0 -58
- package/core/dev/pipeline/archived/TASK_053_optimization_proposals_diff_view.yaml +0 -54
- package/core/dev/pipeline/archived/TASK_054_multi_project_scheduler_state.yaml +0 -76
- package/core/dev/pipeline/archived/TASK_055_scheduler_api_project_scope.yaml +0 -64
- package/core/dev/pipeline/archived/TASK_056_frontend_scheduler_project_scope.yaml +0 -62
- package/core/dev/pipeline/archived/TASK_057_scheduler_module_structure.yaml +0 -54
- package/core/dev/pipeline/archived/TASK_058_scheduler_models_extract.yaml +0 -51
- package/core/dev/pipeline/archived/TASK_059_scheduler_core_extract.yaml +0 -51
- package/core/dev/pipeline/archived/TASK_060_scheduler_commands_extract.yaml +0 -51
- package/core/dev/pipeline/archived/TASK_061_scheduler_specialized_commands.yaml +0 -53
- package/core/dev/pipeline/archived/TASK_062_process_manager_module_structure.yaml +0 -56
- package/core/dev/pipeline/archived/TASK_063_process_manager_core_extract.yaml +0 -56
- package/core/dev/pipeline/archived/TASK_064_recovery_module_structure.yaml +0 -57
- package/core/dev/pipeline/archived/TASK_065_recovery_core_extract.yaml +0 -56
- package/core/dev/pipeline/archived/TASK_066_self_enhancement_scheduler_models.yaml +0 -60
- package/core/dev/pipeline/archived/TASK_067_agents_section_quick_actions.yaml +0 -53
- package/core/dev/pipeline/archived/TASK_067_self_enhancement_scheduler_core.yaml +0 -65
- package/core/dev/pipeline/archived/TASK_068_agent_workflow_rule_enhancement.yaml +0 -46
- package/core/dev/pipeline/archived/TASK_068_self_enhancement_tauri_commands.yaml +0 -61
- package/core/dev/pipeline/archived/TASK_069_agent_wizard_responsive.yaml +0 -46
- package/core/dev/pipeline/archived/TASK_069_self_enhancement_ui.yaml +0 -62
- package/core/dev/pipeline/archived/TASK_070_preview_panel_redesign.yaml +0 -62
- package/core/dev/pipeline/archived/TASK_070_self_enhancement_integration.yaml +0 -57
- package/core/dev/pipeline/archived/TASK_071_preview_panel_qa.yaml +0 -98
- package/core/dev/pipeline/archived/TASK_071_single_agent_config.yaml +0 -57
- package/core/dev/pipeline/archived/TASK_072_preview_modal_esc_fix.yaml +0 -71
- package/core/dev/pipeline/archived/TASK_072_product_review_module.yaml +0 -57
- package/core/dev/pipeline/archived/TASK_073_agents_page_component_refactor.yaml +0 -68
- package/core/dev/pipeline/archived/TASK_073_rename_single_agent.yaml +0 -64
- package/core/dev/pipeline/archived/TASK_074_preview_mode_ui_diagnosis.yaml +0 -71
- package/core/dev/pipeline/archived/TASK_074_single_agent_ui_toggle.yaml +0 -56
- package/core/dev/pipeline/archived/TASK_075_agents_page_component_refactor.yaml +0 -69
- package/core/dev/pipeline/archived/TASK_075_single_agent_integration_test.yaml +0 -75
- package/core/dev/pipeline/archived/TASK_076_preview_mode_ui_diagnosis.yaml +0 -70
- package/core/dev/pipeline/archived/TASK_076_single_agent_continuous_mode.yaml +0 -65
- package/core/dev/pipeline/archived/TASK_077_failure_directory_structure.yaml +0 -51
- package/core/dev/pipeline/archived/TASK_077_single_agent_typescript_types.yaml +0 -59
- package/core/dev/pipeline/archived/TASK_078_fail_001_agent_no_output.yaml +0 -53
- package/core/dev/pipeline/archived/TASK_078_single_agent_ui_simplify.yaml +0 -74
- package/core/dev/pipeline/archived/TASK_079_dashboard_rwd_responsive.yaml +0 -63
- package/core/dev/pipeline/archived/TASK_079_fail_002_json_bom.yaml +0 -56
- package/core/dev/pipeline/archived/TASK_080_fail_003_queue_pollution.yaml +0 -56
- package/core/dev/pipeline/archived/TASK_080_http_server_module.yaml +0 -55
- package/core/dev/pipeline/archived/TASK_081_failure_logging_tools.yaml +0 -57
- package/core/dev/pipeline/archived/TASK_081_http_api_routes.yaml +0 -62
- package/core/dev/pipeline/archived/TASK_082_frontend_api_adapter.yaml +0 -51
- package/core/dev/pipeline/archived/TASK_082_integrate_failure_to_workflow.yaml +0 -60
- package/core/dev/pipeline/archived/TASK_083_cleanup_nextjs_api.yaml +0 -48
- package/core/dev/pipeline/archived/TASK_083_task_queue_cleanup.yaml +0 -67
- package/core/dev/pipeline/archived/TASK_084_rust_dead_code_cleanup.yaml +0 -66
- package/core/dev/pipeline/archived/TASK_084_scheduler_sync_logic_fix.yaml +0 -68
- package/core/dev/pipeline/archived/TASK_085_http_api_web_mode_fixes.yaml +0 -46
- package/core/dev/pipeline/archived/TASK_085_memory_consolidation_0204_0205.yaml +0 -98
- package/core/dev/pipeline/archived/TASK_086_collapsible_preview_panel.yaml +0 -161
- package/core/dev/pipeline/archived/TASK_086_web_mode_feature_parity.yaml +0 -62
- package/core/dev/pipeline/archived/TASK_087_manual_memory_archival.yaml +0 -163
- package/core/dev/pipeline/archived/TASK_087_mobile_http_control.yaml +0 -68
- package/core/dev/pipeline/archived/TASK_088_fail_003_to_ppl_002_rule.yaml +0 -63
- package/core/dev/pipeline/archived/TASK_088_mobile_http_qa.yaml +0 -121
- package/core/dev/pipeline/archived/TASK_089_agent_collaboration_topic.yaml +0 -60
- package/core/dev/pipeline/archived/TASK_089_web_mode_monitor_fix.yaml +0 -58
- package/core/dev/pipeline/archived/TASK_090_cli_detection_fix.yaml +0 -61
- package/core/dev/pipeline/archived/TASK_090_ui_ux_lessons_topic.yaml +0 -63
- package/core/dev/pipeline/archived/TASK_091_expandable_card_design.yaml +0 -56
- package/core/dev/pipeline/archived/TASK_091_move_agent_section_components.yaml +0 -65
- package/core/dev/pipeline/archived/TASK_092_expandable_card_component.yaml +0 -60
- package/core/dev/pipeline/archived/TASK_092_refactor_agent_create_wizard.yaml +0 -84
- package/core/dev/pipeline/archived/TASK_093_taskcard_detail_integration.yaml +0 -57
- package/core/dev/pipeline/archived/TASK_093_update_barrel_exports_test.yaml +0 -84
- package/core/dev/pipeline/archived/TASK_094_ai_agent_generation_enhancement.yaml +0 -115
- package/core/dev/pipeline/archived/TASK_094_proposalcard_detail_integration.yaml +0 -55
- package/core/dev/pipeline/archived/TASK_095_preview_fixes.yaml +0 -129
- package/core/dev/pipeline/archived/TASK_095_single_agent_task_selector.yaml +0 -60
- package/core/dev/pipeline/archived/TASK_096_agents_page_ux_improvements.yaml +0 -163
- package/core/dev/pipeline/archived/TASK_096_single_agent_status_sync.yaml +0 -60
- package/core/dev/pipeline/archived/TASK_097_local_claude_error_logging.yaml +0 -59
- package/core/dev/pipeline/archived/TASK_097_single_agent_monitor_events.yaml +0 -59
- package/core/dev/pipeline/archived/TASK_098_product_manager_team_phase2.yaml +0 -60
- package/core/dev/pipeline/archived/TASK_098_single_agent_refactor_test.yaml +0 -58
- package/core/dev/pipeline/archived/TASK_099_backend_team_creation.yaml +0 -258
- package/core/dev/pipeline/archived/TASK_100_frontend_team_creation.yaml +0 -61
- package/core/dev/pipeline/archived/TASK_101_orchestrator_system.yaml +0 -403
- package/core/dev/pipeline/archived/TASK_102_designer_sre_teams.yaml +0 -90
- package/core/dev/pipeline/archived/TASK_103_integration_testing.yaml +0 -86
- package/core/dev/pipeline/archived/TASK_128_integration_testing.yaml +0 -83
- package/core/dev/pipeline/archived/TASK_134_cortex_v2_phase3_file_watcher.yaml +0 -65
- package/core/dev/pipeline/archived/TASK_134_team_http_api.yaml +0 -96
- package/core/dev/pipeline/archived/TASK_135_cortex_v2_phase3_git_monitor.yaml +0 -63
- package/core/dev/pipeline/archived/TASK_136_cortex_v2_phase3_change_analyzer.yaml +0 -69
- package/core/dev/pipeline/archived/TASK_137_cortex_v2_phase3_cache_invalidator.yaml +0 -67
- package/core/dev/pipeline/archived/TASK_137_team_orchestrator_integration.yaml +0 -93
- package/core/dev/pipeline/archived/TASK_138_cortex_v2_phase3_distributed_cache.yaml +0 -68
- package/core/dev/pipeline/archived/TASK_138_matrix_folder_structure.yaml +0 -61
- package/core/dev/pipeline/archived/TASK_139_cortex_v2_phase3_cache_prewarming.yaml +0 -65
- package/core/dev/pipeline/archived/TASK_146_unified_documentation.yaml +0 -141
- package/core/dev/pipeline/archived/TASK_147_pipeline_execution_rules.yaml +0 -76
- package/core/dev/pipeline/archived/TASK_148_update_claude_md.yaml +0 -77
- package/core/dev/pipeline/archived/TASK_149_fix_nextjs_mdx_serialization.yaml +0 -63
- package/core/dev/pipeline/archived/TASK_149_update_team_docs.yaml +0 -77
- package/core/dev/pipeline/archived/TASK_150_pipeline_workflow_guide.yaml +0 -82
- package/core/dev/pipeline/archived/TASK_164_fix_smart_context_switch.yaml +0 -49
- package/core/dev/pipeline/archived/TASK_165_ctags_symbol_index.yaml +0 -53
- package/core/dev/pipeline/archived/TASK_166_symbol_search_mcp_tool.yaml +0 -48
- package/core/dev/pipeline/archived/TASK_167_llm_module_summary.yaml +0 -55
- package/core/dev/pipeline/archived/TASK_168_map_reduce_context.yaml +0 -51
- package/core/dev/pipeline/archived/TASK_169_v2_integration_testing.yaml +0 -52
- package/core/dev/pipeline/backups/archive_2026-02-04T22-07-22/TASK_QUEUE_backup.json +0 -95
- package/core/dev/pipeline/docs/multi-agent-coordination.md +0 -446
- package/core/dev/pipeline/docs/overview.md +0 -406
- package/core/dev/pipeline/docs/task-management.md +0 -412
- package/core/dev/pipeline/docs/workflows.md +0 -32
- package/core/dev/pipeline/orchestrator/schemas/task_queue_schema.json +0 -58
- package/core/dev/pipeline/orchestrator/schemas/task_schema.json +0 -139
- package/core/dev/pipeline/plans/PLAN_task_cli_refactor.md +0 -281
- package/core/dev/pipeline/test_results/TASK_TEST_PARALLEL_002_result.txt +0 -27
- package/core/dev/plans/ANSUZ_SLIM_PLAN.md +0 -68
- package/core/dev/plans/CLI_FIRST_INSTALL_FLOW.md +0 -120
- package/core/dev/plans/FORMATION_RETIREMENT_PLAN.md +0 -313
- package/core/dev/plans/KUZU_REPLACEMENT_PLAN.md +0 -126
- package/core/dev/scripts/CRASH_DIAGNOSIS.md +0 -47
- package/core/dev/scripts/README.md +0 -142
- package/core/dev/scripts/RUN_ONCE.bat +0 -40
- package/core/dev/scripts/START_DEV_AGENT.bat +0 -63
- package/core/dev/scripts/START_MULTI_AGENT.bat +0 -80
- package/core/dev/scripts/dev_agent_scheduler.ps1 +0 -536
- package/core/dev/scripts/init_git.ps1 +0 -396
- package/core/dev/scripts/init_git.sh +0 -337
- package/core/dev/scripts/init_project.ps1 +0 -851
- package/core/dev/scripts/init_project.sh +0 -477
- package/core/dev/scripts/multi_agent_scheduler.ps1 +0 -2021
- package/core/dev/scripts/multi_agent_scheduler.sh +0 -1344
- package/core/dev/scripts/run_once.sh +0 -47
- package/core/dev/scripts/setup_rag.ps1 +0 -304
- package/core/dev/scripts/setup_rag.sh +0 -230
- package/core/dev/scripts/start_dev_agent.sh +0 -137
- package/core/dev/scripts/start_multi_agent.sh +0 -41
- package/core/dev/scripts/sync_task_queue.ps1 +0 -505
- package/core/dev/scripts/sync_task_queue.sh +0 -392
- package/core/dev/specs/agent-connect/PROTOCOL.md +0 -177
- package/core/dev/specs/agent-connect/SDK_GUIDE.md +0 -915
- package/core/dev/specs/agent-connect/examples/minimal-site/README.md +0 -137
- package/core/dev/specs/agent-connect/examples/minimal-site/package.json +0 -12
- package/core/dev/specs/agent-connect/examples/minimal-site/public/index.html +0 -116
- package/core/dev/specs/agent-connect/examples/minimal-site/public/install-redirect.js +0 -73
- package/core/dev/specs/agent-connect/examples/minimal-site/server.js +0 -516
- package/core/dev/specs/agent-connect/examples/minimal-site/test/smoke.test.mjs +0 -263
- 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
- package/core/dev/specs/agent-connect/history/DEFECT_REPORT_kenaz-agent-hub_2026-09-09_v0.4-prompt-mojibake.md +0 -90
- package/core/dev/specs/agent-connect/history/FEATURE_REQUEST_kenaz-agent-hub_2026-09-07.md +0 -61
- package/core/dev/specs/agent-connect/history/FEATURE_REQUEST_kenaz-agent-hub_2026-09-08_relay-v1-conformance.md +0 -76
- package/core/dev/specs/agent-connect/history/FEATURE_REQUEST_kenaz-agent-hub_2026-09-09_v0.4-session-channel.md +0 -87
- package/core/dev/specs/agent-connect/history/FLOWPIX_REPLY_agent-hub_2026-09-08_relay-v1-answers.md +0 -68
- package/core/dev/specs/agent-connect/history/FLOWPIX_bridge_CONTRACT.md +0 -642
- package/core/dev/specs/agent-connect/history/FLOWPIX_spikes_relay_spike_relay.mjs +0 -244
- package/core/dev/specs/agent-connect/history/KENAZ_RESPONSE_agent-hub_2026-09-07.md +0 -77
- package/core/dev/specs/agent-connect/history/KENAZ_RESPONSE_agent-hub_2026-09-08_direction-change-v0.3.md +0 -44
- package/core/dev/specs/agent-connect/history/KENAZ_RESPONSE_agent-hub_2026-09-08_relay-v1-answers-ack.md +0 -37
- package/core/dev/specs/agent-connect/history/KENAZ_RESPONSE_agent-hub_2026-09-08_relay-v1-conformance.md +0 -56
- package/core/dev/specs/agent-connect/history/KENAZ_RESPONSE_agent-hub_2026-09-09_annotations-install-coldstart.md +0 -44
- package/core/dev/specs/agent-connect/history/KENAZ_RESPONSE_agent-hub_2026-09-09_empty-prompt-first-turn.md +0 -56
- package/core/dev/specs/agent-connect/history/KENAZ_RESPONSE_agent-hub_2026-09-09_prompt-mojibake-fixed.md +0 -48
- package/core/dev/specs/agent-connect/history/KENAZ_RESPONSE_agent-hub_2026-09-09_session-channel.md +0 -57
- package/core/dev/specs/agent-connect/history/PROTOCOL_v0.3_snapshot.md +0 -379
- package/core/dev/specs/agent-connect/history/README.md +0 -47
- package/core/dev/specs/peer/CODEX_INTERACTIVE_PUSH.md +0 -65
- package/core/dev/specs/peer/CODEX_MANAGED_DAEMON.md +0 -54
- package/core/dev/specs/peer/CODEX_PEER_PULL_SPIKE.md +0 -54
- package/core/dev/specs/peer/MODS_SPIKE.md +0 -133
- package/core/dev/specs/peer/PER_PROJECT_ADDRESSING.md +0 -143
- package/core/dev/specs/peer/SWARM_PROTOCOLS.md +0 -256
- package/core/dev/specs/peer/codex-hook-shim-peer.test.js +0 -113
- package/core/dev/specs/peer/codex-push-launcher.test.js +0 -142
- package/core/dev/specs/peer/setup-codex-hooks.test.js +0 -60
- package/core/dev/specs/peer-ansuz/DELIVERY_SPIKE.md +0 -397
- package/core/dev/specs/peer-ansuz/DESIGN.md +0 -109
- package/core/dev/specs/peer-ansuz/spike/claude_poke.js +0 -129
- package/core/dev/specs/peer-ansuz/spike/claude_session_start_hook.js +0 -37
- package/core/dev/specs/peer-ansuz/spike/claude_settings_hook.json +0 -14
- package/core/dev/specs/peer-ansuz/spike/codex_appserver_client.js +0 -105
- package/core/dev/specs/peer-ansuz/spike/codex_appserver_query.js +0 -29
- package/core/dev/specs/peer-ansuz/spike/extract_timeline.js +0 -26
- package/core/dev/specs/synapse/SYMBOL_IDENTITY.md +0 -305
- package/core/dev/spikes/A4-cypher-varlen.md +0 -176
- package/core/dev/spikes/bloat-rounds.sh +0 -25
- package/core/dev/spikes/mods/clean-claude.js +0 -9
- package/core/dev/spikes/mods/drive-probe.js +0 -29
- package/core/dev/spikes/mods/e2e-peer.js +0 -71
- package/core/dev/spikes/mods/evidence/e2e-peer-control.json +0 -17
- package/core/dev/spikes/mods/evidence/e2e-peer-mod.json +0 -17
- package/core/dev/spikes/mods/evidence/probe-006a6e65-d807-4bc1-b648-fd7d1edfe0b4.jsonl +0 -4
- package/core/dev/spikes/mods/evidence/probe-cebdf1f7-f9c4-47a8-83cd-7c0786177404.jsonl +0 -12
- package/core/dev/spikes/mods/evidence/probe-eb21147d-10ce-4c32-93ed-37ca37d88d5a.jsonl +0 -11
- package/core/dev/spikes/mods/evidence/stream-cebdf1f7.jsonl +0 -18
- package/core/dev/spikes/mods/kenaz-mod-probe/.claude-plugin/plugin.json +0 -1
- package/core/dev/spikes/mods/kenaz-mod-probe/hooks/hooks.json +0 -1
- package/core/dev/spikes/mods/kenaz-mod-probe/hooks/register.ts +0 -65
- 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('<script>')); 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
|
-
});
|