@event4u/agent-config 16.0.0 → 16.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.augment-plugin/marketplace.json +3 -3
- package/.augment-plugin/plugin.json +1 -1
- package/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +289 -140
- package/CONTRIBUTING.md +9 -0
- package/README.md +2 -2
- package/dist/agent-src/commands/analyze/inbox.md +26 -0
- package/dist/agent-src/commands/analyze/roadmap-repos.md +27 -0
- package/dist/agent-src/commands/challenge-me/closure.md +178 -0
- package/dist/agent-src/commands/challenge-me.md +9 -2
- package/dist/agent-src/commands/council/default.md +25 -5
- package/dist/agent-src/commands/feature/plan.md +28 -1
- package/dist/agent-src/commands/feature/roadmap.md +28 -1
- package/dist/agent-src/commands/implement-ticket.md +27 -0
- package/dist/agent-src/commands/jira-ticket.md +27 -0
- package/dist/agent-src/commands/pr/create.md +29 -0
- package/dist/agent-src/commands/pr/merge.md +60 -9
- package/dist/agent-src/commands/roadmap/ai-council.md +7 -1
- package/dist/agent-src/commands/roadmap/create.md +74 -27
- package/dist/agent-src/commands/roadmap/materialize.md +27 -0
- package/dist/agent-src/commands/roadmap/process-full.md +123 -18
- package/dist/agent-src/commands/team.md +22 -0
- package/dist/agent-src/commands/work.md +4 -0
- package/dist/agent-src/contexts/authority/scope-growth-ownership.md +80 -0
- package/dist/agent-src/contexts/communication/rules-auto/user-interaction-mechanics.md +47 -0
- package/dist/agent-src/contexts/execution/auto-orchestration-activation.md +44 -3
- package/dist/agent-src/contexts/execution/autonomy-mechanics.md +19 -23
- package/dist/agent-src/contexts/execution/decision-closure-execution.md +93 -0
- package/dist/agent-src/contexts/execution/fix-loop-ladder.md +108 -0
- package/dist/agent-src/contexts/execution/plan-confidence-gate.md +4 -2
- package/dist/agent-src/contexts/execution/roadmap-process-loop.md +75 -6
- package/dist/agent-src/guidelines/agent-infra/active-remediation-mechanics.md +57 -0
- package/dist/agent-src/guidelines/agent-infra/evaluator-independence-mechanics.md +102 -0
- package/dist/agent-src/guidelines/design-fidelity-routing.md +29 -0
- package/dist/agent-src/rules/autonomous-execution.md +15 -8
- package/dist/agent-src/rules/delegation-policy.md +23 -45
- package/dist/agent-src/rules/design-fidelity.md +32 -37
- package/dist/agent-src/rules/evaluator-independence.md +43 -49
- package/dist/agent-src/rules/test-first.md +41 -0
- package/dist/agent-src/rules/ui-audit-gate.md +1 -2
- package/dist/agent-src/skills/accessibility-auditor/data/aria-patterns.csv +1 -1
- package/dist/agent-src/skills/accessibility-auditor/data/manifest.json +3 -3
- package/dist/agent-src/skills/ai-council/SKILL.md +11 -3
- package/dist/agent-src/skills/api-design/data/manifest.json +3 -3
- package/dist/agent-src/skills/database/data/manifest.json +4 -4
- package/dist/agent-src/skills/database/data/query-tuning.csv +3 -3
- package/dist/agent-src/skills/design-review/SKILL.md +80 -4
- package/dist/agent-src/skills/design-review/references/verification-automation.md +32 -0
- package/dist/agent-src/skills/existing-ui-audit/SKILL.md +30 -5
- package/dist/agent-src/skills/existing-ui-audit/references/component-taxonomy-detection.md +56 -0
- package/dist/agent-src/skills/experiment-loop/SKILL.md +31 -1
- package/dist/agent-src/skills/markitdown/SKILL.md +4 -0
- package/dist/agent-src/skills/playwright-testing/SKILL.md +30 -6
- package/dist/agent-src/skills/roadmap-writing/SKILL.md +1 -1
- package/dist/agent-src/skills/storybook-workshop/SKILL.md +42 -3
- package/dist/agent-src/skills/threat-modeling/SKILL.md +9 -4
- package/dist/agent-src/skills/threat-modeling/data/manifest.json +4 -4
- package/dist/agent-src/skills/ui-component-architect/SKILL.md +23 -0
- package/dist/agent-src/skills/verify-repair-loop/SKILL.md +37 -3
- package/dist/agent-src/templates/agent-settings.md +1 -1
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/agent-src/templates/roadmaps.md +218 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/backend/_self_fix.ts +62 -2
- package/dist/agent-src/templates/scripts/work_engine/directives/backend/test.ts +1 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/backend/verify.ts +1 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/app_spec.ts +10 -4
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +260 -21
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/audit.ts +22 -3
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/scaffold.ts +6 -1
- package/dist/agent-src/templates/scripts/work_engine/state.ts +57 -7
- package/dist/agent-src/templates/scripts/work_engine/taxonomy/detect.ts +500 -0
- package/dist/agent-src/templates/scripts/work_engine/taxonomy/place.ts +183 -0
- package/dist/cli/python/knowledge_ingest.js +1 -1
- package/dist/cli/python/workspace_drive.js +1 -1
- package/dist/cli-delegate/check_update_banner.js +40 -2
- package/dist/cli-delegate/chunk-4E2W63DA.js +335 -0
- package/dist/cli-delegate/{chunk-S3VFXMTM.js → chunk-4XFP2Y3E.js} +1 -1
- package/dist/cli-delegate/chunk-5R7HOLAF.js +99 -0
- package/dist/cli-delegate/{chunk-IVBPRCQO.js → chunk-6KFEC3G7.js} +1 -1
- package/dist/cli-delegate/{chunk-2TAQ2K4V.js → chunk-6KM6ORRY.js} +55 -386
- package/dist/cli-delegate/{chunk-AK6HODNQ.js → chunk-7XGBX6ZH.js} +973 -555
- package/dist/cli-delegate/{chunk-2XY7ILBT.js → chunk-FC75PGJE.js} +42 -2
- package/dist/cli-delegate/{chunk-55ACLDUE.js → chunk-FP36SWJD.js} +587 -141
- package/dist/cli-delegate/{chunk-3FKR64R5.js → chunk-IGD6ERX6.js} +62 -7
- package/dist/cli-delegate/{chunk-GYC3VRYN.js → chunk-JNMVLWLR.js} +99 -14
- package/dist/cli-delegate/{chunk-H32DGUJH.js → chunk-P6ZHP5W2.js} +1 -1
- package/dist/cli-delegate/{chunk-57PN4GYJ.js → chunk-RGNIWTEA.js} +1 -1
- package/dist/cli-delegate/chunk-ROYYTEZU.js +39 -0
- package/dist/cli-delegate/{chunk-2DK2VJWG.js → chunk-WGXTVKCQ.js} +20 -6
- package/dist/cli-delegate/chunk-YDPILCOL.js +152 -0
- package/dist/cli-delegate/{chunk-QJWAUMJW.js → chunk-YJ72UIAK.js} +730 -15
- package/dist/cli-delegate/cmd_analyze_session.js +1 -1
- package/dist/cli-delegate/cmd_brand_status.js +1 -1
- package/dist/cli-delegate/cmd_conformance.js +985 -831
- package/dist/cli-delegate/cmd_doctor.js +7 -5
- package/dist/cli-delegate/cmd_explain.js +2 -2
- package/dist/cli-delegate/cmd_export.js +9 -7
- package/dist/cli-delegate/cmd_fleet.js +4 -2
- package/dist/cli-delegate/cmd_handoff.js +7 -7
- package/dist/cli-delegate/cmd_mcp_available.js +1 -1
- package/dist/cli-delegate/cmd_memory_get.js +1 -1
- package/dist/cli-delegate/cmd_migrate.js +2 -2
- package/dist/cli-delegate/cmd_packs_active.js +2 -2
- package/dist/cli-delegate/cmd_preflight.js +4 -2
- package/dist/cli-delegate/cmd_prune.js +10 -8
- package/dist/cli-delegate/cmd_route_audit.js +3 -3
- package/dist/cli-delegate/cmd_route_explain.js +1 -1
- package/dist/cli-delegate/cmd_session_recycle.js +4 -4
- package/dist/cli-delegate/cmd_settings_get.js +28 -2
- package/dist/cli-delegate/cmd_settings_migrate.js +9 -7
- package/dist/cli-delegate/cmd_settings_set.js +1 -1
- package/dist/cli-delegate/cmd_sync.js +10 -8
- package/dist/cli-delegate/cmd_uninstall.js +16 -13
- package/dist/cli-delegate/cmd_update.js +1 -1
- package/dist/cli-delegate/cmd_upgrade.js +1 -1
- package/dist/cli-delegate/cmd_validate.js +12 -10
- package/dist/cli-delegate/cmd_versions.js +1 -1
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +90 -43
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +4 -4
- package/dist/discovery/dormancy-report.md +1 -1
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +10 -8
- package/dist/discovery/trust-report.md +3 -3
- package/dist/discovery/workspaces.json +8 -6
- package/dist/hooks/dispatch.js +7682 -2772
- package/dist/hooks/dispatch.sha256 +1 -0
- package/dist/install/claudeRuleRewrite.js +14 -3
- package/dist/install/conflict.js +60 -10
- package/dist/install/conflictTracker.js +218 -0
- package/dist/install/fsPrimitives.js +54 -0
- package/dist/install/install.mjs +2200 -1559
- package/dist/install/manifestFiles.js +259 -0
- package/dist/install/preflight.js +14 -2
- package/dist/install/preserve.js +157 -0
- package/dist/install/recordedOwnership.js +132 -0
- package/dist/install/txlog.js +11 -2
- package/dist/mcp/registry-manifest.json +3 -3
- package/dist/mcp/server.json +2 -2
- package/dist/mcp/server.mjs +3066 -1470
- package/dist/router.json +1 -1
- package/dist/scripts/_lib/agent_settings.js +3 -2
- package/dist/scripts/_lib/fs_atomic.js +167 -0
- package/dist/scripts/_lib/installed_tools.js +460 -0
- package/dist/scripts/_lib/lean_projection_mode.js +3 -2
- package/dist/scripts/_lib/settings_renamed_keys.js +78 -0
- package/dist/server/routes/install.js +8 -0
- package/dist/server/routes/wizard.js +9 -3
- package/dist/server/schemas/settings.js +40 -5
- package/dist/shared/missionExecution.js +97 -0
- package/dist/ui/assets/index-Cwq4d0hX.js +23 -0
- package/dist/ui/assets/index-Cyjy8bWO.css +1 -0
- package/dist/ui/index.html +2 -2
- package/docs/MIGRATION.md +103 -0
- package/docs/contracts/settings-classes.md +28 -7
- package/docs/guidelines/agent-infra/active-remediation-mechanics.md +57 -0
- package/docs/guidelines/agent-infra/evaluator-independence-mechanics.md +102 -0
- package/docs/guidelines/design-fidelity-routing.md +29 -0
- package/package.json +4 -4
- package/src/agent-src/templates/scripts/work_engine/directives/backend/_self_fix.ts +62 -2
- package/src/agent-src/templates/scripts/work_engine/directives/backend/test.ts +1 -0
- package/src/agent-src/templates/scripts/work_engine/directives/backend/verify.ts +1 -0
- package/src/agent-src/templates/scripts/work_engine/directives/ui/app_spec.ts +10 -4
- package/src/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +260 -21
- package/src/agent-src/templates/scripts/work_engine/directives/ui/audit.ts +22 -3
- package/src/agent-src/templates/scripts/work_engine/directives/ui/scaffold.ts +6 -1
- package/src/agent-src/templates/scripts/work_engine/state.ts +57 -7
- package/src/agent-src/templates/scripts/work_engine/taxonomy/detect.ts +500 -0
- package/src/agent-src/templates/scripts/work_engine/taxonomy/place.ts +183 -0
- package/src/config/agent-settings.template.yml +168 -27
- package/src/config/auto-rule-budget.json +16 -0
- package/src/config/ci-local-parity.yml +36 -5
- package/src/config/continuity-surface.json +23 -2
- package/src/config/gate-coverage.yml +377 -13
- package/src/config/gate-violation-baselines.json +10 -6
- package/src/config/hook-latency-budget.json +21 -0
- package/src/config/hook-token-budget.json +4 -2
- package/src/config/loop-surfaces.yaml +215 -0
- package/src/config/metric-registry.yml +114 -0
- package/src/config/placeholder-drift-budget.json +10 -0
- package/src/config/platform-anchor.json +3 -2
- package/src/config/release-gate-locality.yml +11 -0
- package/src/config/routing-coverage-seed.json +33 -5
- package/src/config/rule-enforcement-baseline.json +0 -1
- package/src/install/claudeRuleRewrite.ts +16 -2
- package/src/install/conflict.ts +65 -9
- package/src/install/conflictTracker.ts +299 -0
- package/src/install/fsPrimitives.ts +54 -0
- package/src/install/manifestFiles.ts +312 -0
- package/src/install/preflight.ts +16 -2
- package/src/install/preserve.ts +205 -0
- package/src/install/recordedOwnership.ts +149 -0
- package/src/install/txlog.ts +11 -2
- package/src/install/types.ts +19 -4
- package/src/scripts/_cli/cmd_conformance.ts +88 -15
- package/src/scripts/_cli/cmd_doctor.ts +7 -20
- package/src/scripts/_cli/cmd_route_explain.ts +9 -2
- package/src/scripts/_cli/cmd_settings_get.ts +44 -0
- package/src/scripts/_cli/doctor_execution.ts +173 -0
- package/src/scripts/_cli/doctor_network_posture.ts +226 -0
- package/src/scripts/_lib/activation_payload.ts +247 -0
- package/src/scripts/_lib/agent_settings.ts +4 -2
- package/src/scripts/_lib/authority_path.ts +102 -0
- package/src/scripts/_lib/body_portable.ts +102 -0
- package/src/scripts/_lib/cascade_base.ts +94 -0
- package/src/scripts/_lib/cc_transcript.ts +132 -1
- package/src/scripts/_lib/changelog_eras.ts +7 -2
- package/src/scripts/_lib/concern_sla_window.ts +200 -0
- package/src/scripts/_lib/continuation_ladder.ts +149 -2
- package/src/scripts/_lib/council_transport.ts +129 -0
- package/src/scripts/_lib/delivery_ready.ts +112 -0
- package/src/scripts/_lib/forge_protection.ts +381 -0
- package/src/scripts/_lib/forge_reader.ts +558 -0
- package/src/scripts/_lib/hook_platform_keys.ts +27 -0
- package/src/scripts/_lib/host_env_write.ts +111 -0
- package/src/scripts/_lib/json_python_parity.ts +127 -0
- package/src/scripts/_lib/lean_projection_mode.ts +14 -3
- package/src/scripts/_lib/llm_proposer_transport.ts +14 -4
- package/src/scripts/_lib/loop_surfaces.ts +382 -0
- package/src/scripts/_lib/mission_record.ts +190 -0
- package/src/scripts/_lib/obligation_frequency.ts +217 -0
- package/src/scripts/_lib/obligations.ts +513 -0
- package/src/scripts/_lib/orchestration_record.ts +11 -20
- package/src/scripts/_lib/probe_inputs.ts +271 -0
- package/src/scripts/_lib/read_surface_scan.ts +322 -0
- package/src/scripts/_lib/release_highlights.ts +201 -11
- package/src/scripts/_lib/release_holds.ts +493 -0
- package/src/scripts/_lib/release_migration_gate.ts +184 -0
- package/src/scripts/_lib/retrieval_sanitize.ts +77 -16
- package/src/scripts/_lib/rides_along.ts +102 -0
- package/src/scripts/_lib/settings_renamed_keys.ts +82 -0
- package/src/scripts/_lib/shell_write_shapes.ts +108 -0
- package/src/scripts/_lib/structural_hiding.ts +622 -0
- package/src/scripts/_lib/test_delta.ts +166 -0
- package/src/scripts/_lib/test_provenance.ts +171 -0
- package/src/scripts/_lib/turn_end_refusals.ts +525 -4
- package/src/scripts/_lib/turn_end_transcript.ts +216 -0
- package/src/scripts/_lib/typed_op_grant.ts +246 -0
- package/src/scripts/_lib/typed_op_watch.ts +185 -0
- package/src/scripts/_lib/verification_command.ts +324 -0
- package/src/scripts/_lib/verification_evidence.ts +647 -0
- package/src/scripts/_lib/verify_clause.ts +280 -0
- package/src/scripts/ai_council/config.ts +8 -11
- package/src/scripts/ai_council/fallback_config.ts +5 -3
- package/src/scripts/ai_council/ownership_classes.ts +118 -0
- package/src/scripts/ai_team/team_dispatch.ts +4 -0
- package/src/scripts/ask_block_census.ts +285 -15
- package/src/scripts/before_complete_hook.ts +340 -23
- package/src/scripts/bench_hook_latency.ts +412 -5
- package/src/scripts/cache_realization_report.ts +61 -1
- package/src/scripts/check_argument_hint.ts +287 -0
- package/src/scripts/check_claims.ts +125 -1
- package/src/scripts/check_enforcement_coverage.ts +38 -9
- package/src/scripts/check_enforcement_matrix.ts +866 -0
- package/src/scripts/check_finding_dispositions.ts +22 -3
- package/src/scripts/check_gate_reachability.ts +173 -10
- package/src/scripts/check_generator_sync.ts +1025 -0
- package/src/scripts/check_host_docs_digest.ts +786 -0
- package/src/scripts/check_host_format_column.ts +559 -0
- package/src/scripts/check_input_references.ts +228 -0
- package/src/scripts/check_inputs_parity.ts +235 -0
- package/src/scripts/check_kernel_edit_ratified.ts +47 -5
- package/src/scripts/check_kill_switch_table.ts +294 -0
- package/src/scripts/check_placeholder_drift.ts +221 -0
- package/src/scripts/check_preamble_payload_budget.ts +75 -2
- package/src/scripts/check_read_surface_coverage.ts +515 -0
- package/src/scripts/check_release_highlights.ts +33 -1
- package/src/scripts/check_release_holds.ts +568 -0
- package/src/scripts/check_routing_coverage.ts +378 -11
- package/src/scripts/check_rule_projection_integrity.ts +22 -12
- package/src/scripts/check_static_parity.ts +17 -0
- package/src/scripts/check_test_delta.ts +294 -0
- package/src/scripts/check_test_weakening.ts +299 -0
- package/src/scripts/ci_settle.ts +145 -19
- package/src/scripts/closure_scan.ts +447 -0
- package/src/scripts/compile_hook_manifest.ts +102 -18
- package/src/scripts/council_record_shape.ts +209 -0
- package/src/scripts/external_sources_denylist.json +29 -4
- package/src/scripts/hook_manifest.json +1 -1
- package/src/scripts/hook_manifest.yaml +127 -11
- package/src/scripts/hooks/block_config_weakening.ts +229 -4
- package/src/scripts/hooks/block_kernel_rule_writes.ts +9 -78
- package/src/scripts/hooks/block_plumbing_writes.ts +314 -0
- package/src/scripts/hooks/bundle_integrity.ts +291 -0
- package/src/scripts/hooks/chain_nudge_hook.ts +1 -2
- package/src/scripts/hooks/code_graph_context_hook.ts +1 -2
- package/src/scripts/hooks/comment_discipline_hook.ts +1 -3
- package/src/scripts/hooks/concern_registry.ts +6 -0
- package/src/scripts/hooks/concern_timings.ts +94 -0
- package/src/scripts/hooks/delegation_nudge_hook.ts +1 -2
- package/src/scripts/hooks/design_pass_hook.ts +221 -5
- package/src/scripts/hooks/design_slop_hook.ts +1 -2
- package/src/scripts/hooks/dispatch_hook.ts +25 -19
- package/src/scripts/hooks/edit_shape_hook.ts +1 -2
- package/src/scripts/hooks/end_review_nudge_hook.ts +1 -1
- package/src/scripts/hooks/evidence_independence.ts +97 -2
- package/src/scripts/hooks/exit_codes.ts +128 -0
- package/src/scripts/hooks/host_lowering.json +1 -0
- package/src/scripts/hooks/host_lowering.ts +128 -3
- package/src/scripts/hooks/host_lowering.yaml +262 -46
- package/src/scripts/hooks/host_semantics.ts +30 -2
- package/src/scripts/hooks/injection_budget.ts +9 -2
- package/src/scripts/hooks/interruption_ledger_hook.ts +1 -2
- package/src/scripts/hooks/journal_record_hook.ts +1 -2
- package/src/scripts/hooks/memory_recall_hook.ts +539 -0
- package/src/scripts/hooks/obligation_settle_hook.ts +328 -0
- package/src/scripts/hooks/one_question_per_ask_hook.ts +25 -4
- package/src/scripts/hooks/orchestration_record_hook.ts +1 -2
- package/src/scripts/hooks/permission_gate.ts +1 -2
- package/src/scripts/hooks/push_settle_hook.ts +1 -3
- package/src/scripts/hooks/replay_hook.ts +2 -1
- package/src/scripts/hooks/reread_guard_hook.ts +1 -2
- package/src/scripts/hooks/review_baseline_hook.ts +1 -2
- package/src/scripts/hooks/rtk_wrap_hook.ts +1 -2
- package/src/scripts/hooks/rule_inject_hook.ts +55 -4
- package/src/scripts/hooks/run_continuation_hook.ts +30 -35
- package/src/scripts/hooks/skill_route_hook.ts +1 -2
- package/src/scripts/hooks/source_first_gate_hook.ts +1 -2
- package/src/scripts/hooks/spawn_guard_shadow_hook.ts +1 -2
- package/src/scripts/hooks/subagent_ledger_hook.ts +1 -2
- package/src/scripts/hooks/suggestion_capture_hook.ts +1 -1
- package/src/scripts/hooks/table_fingerprint.ts +49 -0
- package/src/scripts/hooks/telemetry_flush_hook.ts +1 -2
- package/src/scripts/hooks/telemetry_usage_hook.ts +1 -2
- package/src/scripts/hooks/tool_result_bytes_hook.ts +93 -9
- package/src/scripts/hooks/turn_end_gate_hook.ts +337 -324
- package/src/scripts/hooks/ui_route_nudge_hook.ts +1 -2
- package/src/scripts/hooks_doctor.ts +85 -0
- package/src/scripts/hooks_status.ts +19 -0
- package/src/scripts/install.ts +109 -210
- package/src/scripts/janitor.ts +7 -0
- package/src/scripts/lint_decision_classes.ts +464 -0
- package/src/scripts/lint_deny_text.ts +419 -0
- package/src/scripts/lint_exit_codes.ts +262 -0
- package/src/scripts/lint_hook_manifest.ts +66 -0
- package/src/scripts/lint_major_migration_sections.ts +450 -0
- package/src/scripts/lint_plan_risk_register.ts +47 -3
- package/src/scripts/lint_roadmap_blockers.ts +139 -12
- package/src/scripts/lint_roadmap_producers.ts +202 -0
- package/src/scripts/lint_skill_descriptions.ts +1 -1
- package/src/scripts/lint_skill_scripts_readonly.ts +1 -1
- package/src/scripts/mcp_server/prompts.ts +142 -1
- package/src/scripts/measure_rule_budget.ts +101 -5
- package/src/scripts/measure_skill_ranker_baseline.ts +305 -51
- package/src/scripts/measure_turn_end_gate.ts +193 -0
- package/src/scripts/memory_lookup.ts +1 -1
- package/src/scripts/new_roadmap.ts +37 -0
- package/src/scripts/orchestration_record.ts +0 -5
- package/src/scripts/prepack-check.mjs +53 -0
- package/src/scripts/release.ts +14 -98
- package/src/scripts/release_drill.ts +267 -1
- package/src/scripts/release_publication.ts +64 -1
- package/src/scripts/report_enforcement_drift.ts +566 -0
- package/src/scripts/report_host_injection_effect.ts +3 -11
- package/src/scripts/report_invocation_surface.ts +383 -0
- package/src/scripts/report_obligation_carriers.ts +699 -0
- package/src/scripts/report_obligation_writer_split.ts +236 -0
- package/src/scripts/report_skill_menu_census.ts +208 -0
- package/src/scripts/report_standing_payload_by_host.ts +26 -152
- package/src/scripts/roadmap_verify_share.ts +213 -0
- package/src/scripts/schemas/agent-settings.schema.json +23 -0
- package/src/scripts/schemas/command.schema.json +48 -0
- package/src/scripts/schemas/review-findings.schema.json +4 -0
- package/src/scripts/schemas/skill.schema.json +44 -0
- package/src/scripts/scope_growth.ts +219 -0
- package/src/scripts/self_review_gate.ts +359 -10
- package/src/scripts/semantic_parity_census.ts +314 -0
- package/src/scripts/session_eol_report.ts +54 -1
- package/src/scripts/sweep_dead_scan_roots.ts +1 -1
- package/src/scripts/trigger_eval_grandfather.json +0 -3
- package/src/scripts/trigger_eval_rotation.ts +122 -27
- package/src/scripts/ui_conformance_probe.ts +774 -0
- package/src/scripts/update_prices.ts +85 -3
- package/src/scripts/write_bundle_digest.mjs +74 -0
- package/src/server/schemas/settings.ts +62 -7
- package/src/shared/missionExecution.ts +126 -0
- package/src/templates/consumer-settings/ONBOARDING.md +1 -0
- package/dist/cli-delegate/chunk-523HCFYO.js +0 -90
- package/dist/ui/assets/index-D0jaCRPM.js +0 -29
- package/dist/ui/assets/index-jSfMW8_t.css +0 -1
- /package/dist/cli-delegate/{chunk-YUM5KURG.js → chunk-7RQP4UDH.js} +0 -0
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `execution` block of `agent-config doctor --json`.
|
|
3
|
+
*
|
|
4
|
+
* `road-to-adversarial-verification-and-long-runs` Phase 0.3. Its own module
|
|
5
|
+
* rather than a function inside `cmd_doctor.ts` for the reason
|
|
6
|
+
* `_lib/continuation_ladder.ts` states for itself: `check_source_size_budget` is
|
|
7
|
+
* a shrink-only ratchet and `cmd_doctor.ts` sits far past the 1,500-line cap, so
|
|
8
|
+
* every line added there is an added violation. A phase pays for its additions by
|
|
9
|
+
* putting new code in a file under the cap rather than by raising a baseline.
|
|
10
|
+
*
|
|
11
|
+
* `owner_owned_check` appears here as the ladder's last RUNG rather than as a
|
|
12
|
+
* separate field, because it is not a separate switch: it is the rung that
|
|
13
|
+
* decides whether the residue is owner-owned at all, and lifting it out would
|
|
14
|
+
* suggest it can be toggled independently of the order it sits in.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import {
|
|
18
|
+
executionPostureFromOverrides,
|
|
19
|
+
resolveExecutionPosture,
|
|
20
|
+
} from '../../shared/missionExecution.js';
|
|
21
|
+
import {
|
|
22
|
+
forgeProtectionRows,
|
|
23
|
+
protectionActions,
|
|
24
|
+
type ForgeReading,
|
|
25
|
+
} from '../_lib/forge_protection.js';
|
|
26
|
+
import {
|
|
27
|
+
FORGE_TOTAL_BUDGET_MS,
|
|
28
|
+
budgetOf,
|
|
29
|
+
forgeReadingFor,
|
|
30
|
+
liveForgeApi,
|
|
31
|
+
originUrl,
|
|
32
|
+
resolveForgeRepo,
|
|
33
|
+
type Runner,
|
|
34
|
+
} from '../_lib/forge_reader.js';
|
|
35
|
+
|
|
36
|
+
type Dict = Record<string, unknown>;
|
|
37
|
+
|
|
38
|
+
/** A settings-override stream, in the shape `iter_setting_overrides` yields. */
|
|
39
|
+
export type OverrideStream = Iterable<readonly [string, unknown, string]>;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Build the payload block from a settings-override stream.
|
|
43
|
+
*
|
|
44
|
+
* A stream that throws yields the defaults rather than propagating — a
|
|
45
|
+
* diagnostic that cannot report because its own input is malformed is the one
|
|
46
|
+
* shape `doctor` must never take.
|
|
47
|
+
*/
|
|
48
|
+
export function executionJson(overrides: () => OverrideStream): Dict {
|
|
49
|
+
let posture;
|
|
50
|
+
try {
|
|
51
|
+
posture = executionPostureFromOverrides(overrides());
|
|
52
|
+
} catch {
|
|
53
|
+
posture = resolveExecutionPosture({});
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
fix_loop_max: posture.fix_loop_max,
|
|
57
|
+
escalation: [...posture.escalation],
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* The `forge_protection` block of `doctor --json` — Phase 3.2.
|
|
63
|
+
*
|
|
64
|
+
* **THIS function does not reach the network; `doctor` now does.** The mapper
|
|
65
|
+
* stays pure and takes an INJECTED reading — a caller that queried the forge
|
|
66
|
+
* passes it, one that did not passes the all-null reading, which produces five
|
|
67
|
+
* `unread` rows that still name the call each value would come from. What
|
|
68
|
+
* changed is the caller: `forgeProtectionJsonFor` below acquires that reading,
|
|
69
|
+
* so `doctor --json` does make `gh` calls. Phase 3.2's "`doctor` does not reach
|
|
70
|
+
* the network" is SUPERSEDED, and this header said otherwise for three review
|
|
71
|
+
* rounds while the function forty lines down called it a reversal — the third
|
|
72
|
+
* copy of a refuted argument in this diff, each found by a different round.
|
|
73
|
+
* Corrected here for the reason the others were: a header is where a dead
|
|
74
|
+
* argument gets reused.
|
|
75
|
+
*
|
|
76
|
+
* That is the honest shape for *read, never guessed*: the block is always
|
|
77
|
+
* present, a value appears only when a named call produced it, and `unread` is a
|
|
78
|
+
* third state rather than a quiet `false`. A row that was never looked at and a
|
|
79
|
+
* row that was looked at and failed are different repairs.
|
|
80
|
+
*
|
|
81
|
+
* `actions` carries the human ACTION lines — the step's own words are that a
|
|
82
|
+
* missing row is a blocker entry and NOT a halt, so this reports and returns.
|
|
83
|
+
*/
|
|
84
|
+
export function forgeProtectionJson(reading: ForgeReading, repo: string | null = null): Dict {
|
|
85
|
+
const rows = forgeProtectionRows(reading);
|
|
86
|
+
const readFromForge = rows.some((r) => r.state !== 'unread');
|
|
87
|
+
// **The slug is reported only when something was actually read, and that
|
|
88
|
+
// invariant is structural rather than a caller's promise.** The first
|
|
89
|
+
// version reported whatever the git remote resolved to, which is a LOCAL
|
|
90
|
+
// read that succeeds with no network — so an ordinary offline run (GitHub
|
|
91
|
+
// remote present, no connectivity, no opt-out) emitted a named repository
|
|
92
|
+
// and substituted sources while every row was `unread`. That made the
|
|
93
|
+
// claim this change rests on — offline output is what Phase 3.2 shipped —
|
|
94
|
+
// false on exactly the failed-live path the council condition names. The
|
|
95
|
+
// earlier verification only ever exercised the opt-out switch and read it
|
|
96
|
+
// as offline; the two are not the same path.
|
|
97
|
+
const anonymous = repo === null || !readFromForge;
|
|
98
|
+
const name = (s: string): string =>
|
|
99
|
+
anonymous ? s : s.replace(/\{owner\}\/\{repo\}/g, () => repo);
|
|
100
|
+
return {
|
|
101
|
+
repository: readFromForge ? repo : null,
|
|
102
|
+
rows: rows.map((r) => ({
|
|
103
|
+
id: r.id,
|
|
104
|
+
state: r.state,
|
|
105
|
+
source: name(r.source),
|
|
106
|
+
detail: r.detail,
|
|
107
|
+
})),
|
|
108
|
+
actions: protectionActions(rows).map(name),
|
|
109
|
+
read_from_forge: readFromForge,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* The block as `doctor` itself builds it — AC-5.
|
|
115
|
+
*
|
|
116
|
+
* Phase 3.2 left `forgeProtectionJson` with no production caller, so the
|
|
117
|
+
* command the criterion names reported five `unread` rows while the forge
|
|
118
|
+
* satisfied all five, and the rows were only ever established by a human
|
|
119
|
+
* running `gh api` and reading the mapper in a test. This is the wiring that
|
|
120
|
+
* makes the named command answer for itself.
|
|
121
|
+
*
|
|
122
|
+
* **This IS a reversal of Phase 3.2's module boundary, and the roadmap records
|
|
123
|
+
* the supersession.** An earlier draft of this comment argued the opposite —
|
|
124
|
+
* "an addition rather than a reversal" — which a 2/2 convergent council pass
|
|
125
|
+
* refuted: that note recorded two boundaries, `doctor` does not reach the
|
|
126
|
+
* network AND the reading is injected, and this reverses both. The refuted
|
|
127
|
+
* argument is corrected here rather than left standing, because a comment is
|
|
128
|
+
* what the next reader of this module finds first and is where a refuted
|
|
129
|
+
* reasoning would get reused.
|
|
130
|
+
*
|
|
131
|
+
* What survives is the AVAILABILITY property, which is narrower than the
|
|
132
|
+
* earlier claim and is the one the supersession rests on: every failure path in
|
|
133
|
+
* `forgeReadingFor` — opt-out switch, no GitHub remote, no `gh`, no
|
|
134
|
+
* credentials, timeout, unparseable payload, a throw — returns the same
|
|
135
|
+
* `UNREAD_FORGE` reading, so offline the ROWS, their `source` templates and the
|
|
136
|
+
* action lines are what Phase 3.2 printed. Not the whole document: the block
|
|
137
|
+
* gained a top-level `repository` key, which is `null` on every such path. A
|
|
138
|
+
* consumer validating `forge_protection` against a closed schema sees that one
|
|
139
|
+
* added key; "prints exactly what it printed before" was too strong and is not
|
|
140
|
+
* claimed.
|
|
141
|
+
*
|
|
142
|
+
* `process.env` and the git remote are read HERE rather than inside the reader,
|
|
143
|
+
* so the reader stays injectable and every branch above is reachable from a
|
|
144
|
+
* test without spawning anything.
|
|
145
|
+
*/
|
|
146
|
+
export interface ForgeDeps {
|
|
147
|
+
readonly env?: Readonly<Record<string, string | undefined>>;
|
|
148
|
+
/** The subprocess runner for both `git` and `gh`. */
|
|
149
|
+
readonly run?: Runner;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export function forgeProtectionJsonFor(root: string, deps: ForgeDeps = {}): Dict {
|
|
153
|
+
// The composition root — budget, thunk, host and cwd wired together — had
|
|
154
|
+
// no seam and therefore no test, so the opt-out-before-spawn and host
|
|
155
|
+
// binding were asserted one layer down against fakes while a regression in
|
|
156
|
+
// the real wiring stayed invisible. `deps` is that seam; production passes
|
|
157
|
+
// nothing and gets `process.env` plus the real spawn.
|
|
158
|
+
const env = deps.env ?? process.env;
|
|
159
|
+
const run = deps.run;
|
|
160
|
+
const remaining = budgetOf(FORGE_TOTAL_BUDGET_MS);
|
|
161
|
+
const read = forgeReadingFor({
|
|
162
|
+
env,
|
|
163
|
+
// A thunk, so the opt-out short-circuits before `git` spawns.
|
|
164
|
+
resolveRepo: () => resolveForgeRepo(originUrl(root, run)),
|
|
165
|
+
// Built from the RESOLVED target, so `gh` is addressed at the host and
|
|
166
|
+
// directory the slug came from. The per-call ceiling is whatever is
|
|
167
|
+
// left of the whole-read budget, so a call admitted near the deadline
|
|
168
|
+
// cannot run past it.
|
|
169
|
+
apiFor: (t) => liveForgeApi(remaining, run, { host: t.host, cwd: root }),
|
|
170
|
+
remaining,
|
|
171
|
+
});
|
|
172
|
+
return forgeProtectionJson(read.reading, read.repo);
|
|
173
|
+
}
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What this install does on the network — the two `doctor` surfaces that
|
|
3
|
+
* answer that question, in one module under the source-size cap.
|
|
4
|
+
*
|
|
5
|
+
* `road-to-host-traffic-knobs-that-ship` Phases 2.1 and 2.2. Its own module
|
|
6
|
+
* rather than a function inside `cmd_doctor.ts` for the reason
|
|
7
|
+
* `_lib/doctor_runtime_checks.ts` states for itself: that file is ~3,600 lines
|
|
8
|
+
* and `check_source_size_budget` counts every line above 1,500, so a change
|
|
9
|
+
* that adds lines there pays for them by taking lines away. Wiring the traffic
|
|
10
|
+
* section in costs two lines; `checkOfflineReadiness` moving here returns more
|
|
11
|
+
* than that, and lands beside a cohesive sibling rather than in an arbitrary
|
|
12
|
+
* bin — "can this install work with no registry" and "which host traffic is
|
|
13
|
+
* switched off" are the same question asked from two ends.
|
|
14
|
+
*
|
|
15
|
+
* `checkOfflineReadiness` is a PURE MOVE: same id, same statuses, same message
|
|
16
|
+
* and remedy strings. Its `pathExists` is `fs.statSync` in a try, matching the
|
|
17
|
+
* helper it used in `cmd_doctor.ts` — `existsSync` would differ on a path whose
|
|
18
|
+
* parent denies traversal, and this is a move, not a repair.
|
|
19
|
+
*
|
|
20
|
+
* Why the traffic section reports rather than decides: the variables below belong to the HOST, not to this package. Writing one into
|
|
21
|
+
* a consumer environment changes behaviour the consumer never asked to change,
|
|
22
|
+
* and — per the mapping measured in `docs/setup/host-traffic-environment.md` —
|
|
23
|
+
* could stop their background security updates as a side effect of a telemetry
|
|
24
|
+
* preference. So this module reads `env` and returns; it writes nothing, opens
|
|
25
|
+
* no socket, and touches no settings file. Two consecutive calls return equal
|
|
26
|
+
* payloads and leave the tree byte-identical.
|
|
27
|
+
*
|
|
28
|
+
* Why an inapplicable row is PRESENT and says so: the obvious implementation lists only the variables that resolve on the
|
|
29
|
+
* current host, which produces a short, clean section on a host that documents
|
|
30
|
+
* none of them. An operator reading that concludes their traffic is governed,
|
|
31
|
+
* when in fact the package simply had nothing to say. An omission that reads as
|
|
32
|
+
* a clean bill of health is the precise failure this surface exists to prevent,
|
|
33
|
+
* so a row that does not apply is emitted with the literal state
|
|
34
|
+
* {@link NOT_APPLICABLE} instead of being dropped.
|
|
35
|
+
*
|
|
36
|
+
* A variable that is SET on a host that does not document it still reports its
|
|
37
|
+
* value beside that state. The state says "this host is not known to read it";
|
|
38
|
+
* dropping the value as well would hide a fact the reader has.
|
|
39
|
+
*/
|
|
40
|
+
import * as fs from 'node:fs';
|
|
41
|
+
import * as path from 'node:path';
|
|
42
|
+
|
|
43
|
+
/** The doctor's structured check row. Mirrors `cmd_doctor`'s internal `Dict`. */
|
|
44
|
+
export interface NetworkCheck {
|
|
45
|
+
id: string;
|
|
46
|
+
status: 'ok' | 'warn' | 'fail' | 'skipped';
|
|
47
|
+
message: string;
|
|
48
|
+
remedy: string;
|
|
49
|
+
/** Structural compatibility with `cmd_doctor`'s `Dict` row type. */
|
|
50
|
+
[k: string]: string;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** The literal a row carries where the host has no documented meaning for it. */
|
|
54
|
+
export const NOT_APPLICABLE = 'not applicable on this host';
|
|
55
|
+
|
|
56
|
+
/** The documentation surface every row points at. One copy of the mapping. */
|
|
57
|
+
export const TRAFFIC_DOC = 'docs/setup/host-traffic-environment.md';
|
|
58
|
+
|
|
59
|
+
/** Host id used when nothing in the environment identifies the host. */
|
|
60
|
+
export const UNKNOWN_HOST = 'unknown';
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* One documented host traffic variable.
|
|
64
|
+
*
|
|
65
|
+
* `hosts` lists the host ids whose shipped build was actually READ for this
|
|
66
|
+
* variable — never a host somebody expects to behave the same way. A host
|
|
67
|
+
* absent from the list gets {@link NOT_APPLICABLE}, which is the honest answer
|
|
68
|
+
* and also the safe one.
|
|
69
|
+
*/
|
|
70
|
+
export interface TrafficVariable {
|
|
71
|
+
readonly variable: string;
|
|
72
|
+
readonly hosts: readonly string[];
|
|
73
|
+
/** Host build and date the row was read from, e.g. `claude-code 2.1.284 · 2026-09-29`. */
|
|
74
|
+
readonly checked_against: string;
|
|
75
|
+
/**
|
|
76
|
+
* May THIS PACKAGE write the variable into the host env block?
|
|
77
|
+
*
|
|
78
|
+
* `false` on both traffic variables and it is not a policy setting — it is a
|
|
79
|
+
* structural fact: `install.ts`'s `WRITABLE_HOST_ENV` is a two-row allow
|
|
80
|
+
* table and the settings schema admits only those two keys, so neither
|
|
81
|
+
* traffic variable is expressible anywhere in the write path. Reported
|
|
82
|
+
* because a consumer reading `set` on a row deserves to know whether this
|
|
83
|
+
* package could have been the one that set it.
|
|
84
|
+
*/
|
|
85
|
+
readonly writable_by_this_package: boolean;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** The host build every row below was read from. One place to bump on a re-check. */
|
|
89
|
+
const CHECKED = 'claude-code 2.1.284 · 2026-09-29';
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* The documented set, in the order `docs/setup/host-traffic-environment.md`
|
|
93
|
+
* lists it. What each one governs — and does not — lives in that page and is
|
|
94
|
+
* deliberately not duplicated here: a second copy is a second thing to keep
|
|
95
|
+
* true, and this one would be the copy nobody re-reads.
|
|
96
|
+
*/
|
|
97
|
+
export const TRAFFIC_VARIABLES: readonly TrafficVariable[] = [
|
|
98
|
+
// Both traffic variables reach the host's update-disabled resolver, the
|
|
99
|
+
// blanket one as its third rung, so neither is writable by this package —
|
|
100
|
+
// owner-decided 2026-09-30.
|
|
101
|
+
{ variable: 'CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC', hosts: ['claude-code'], checked_against: CHECKED, writable_by_this_package: false },
|
|
102
|
+
{ variable: 'DISABLE_AUTOUPDATER', hosts: ['claude-code'], checked_against: CHECKED, writable_by_this_package: false },
|
|
103
|
+
// Size caps. Neither reaches the updater resolver, and neither suppresses a
|
|
104
|
+
// call, an update check or a download.
|
|
105
|
+
{ variable: 'BASH_MAX_OUTPUT_LENGTH', hosts: ['claude-code'], checked_against: CHECKED, writable_by_this_package: true },
|
|
106
|
+
{ variable: 'MAX_MCP_OUTPUT_TOKENS', hosts: ['claude-code'], checked_against: CHECKED, writable_by_this_package: true },
|
|
107
|
+
];
|
|
108
|
+
|
|
109
|
+
/** An environment map, in the shape `process.env` has. */
|
|
110
|
+
export type EnvMap = Readonly<Record<string, string | undefined>>;
|
|
111
|
+
|
|
112
|
+
/** Which host this process is running under, and whether that was observed. */
|
|
113
|
+
export interface TrafficHost {
|
|
114
|
+
host: string;
|
|
115
|
+
observed: boolean;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Resolve the host from the environment it exported.
|
|
120
|
+
*
|
|
121
|
+
* `observed` carries the same distinction `routing:doctor` draws for its own
|
|
122
|
+
* platform field: a host that identified itself is a fact, and the absence of
|
|
123
|
+
* any marker is NOT evidence of a different host — only evidence that nobody
|
|
124
|
+
* said. An unidentified host resolves to {@link UNKNOWN_HOST}, which documents
|
|
125
|
+
* no variable, so every row reads {@link NOT_APPLICABLE} rather than reporting
|
|
126
|
+
* against a host this code guessed at.
|
|
127
|
+
*/
|
|
128
|
+
export function resolveTrafficHost(env: EnvMap): TrafficHost {
|
|
129
|
+
const claude =
|
|
130
|
+
(env['CLAUDECODE'] ?? '').trim() !== '' || (env['CLAUDE_CODE_SESSION_ID'] ?? '').trim() !== '';
|
|
131
|
+
if (claude) return { host: 'claude-code', observed: true };
|
|
132
|
+
return { host: UNKNOWN_HOST, observed: false };
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/** One emitted row: the variable, its state on this host, and its value if set. */
|
|
136
|
+
export interface TrafficRow {
|
|
137
|
+
variable: string;
|
|
138
|
+
state: string;
|
|
139
|
+
value: string | null;
|
|
140
|
+
checked_against: string;
|
|
141
|
+
writable_by_this_package: boolean;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Build one row. A variable the host does not document reports
|
|
146
|
+
* {@link NOT_APPLICABLE} whether or not it happens to be exported.
|
|
147
|
+
*/
|
|
148
|
+
function trafficRow(spec: TrafficVariable, env: EnvMap, host: string): TrafficRow {
|
|
149
|
+
const raw = env[spec.variable];
|
|
150
|
+
const present = raw !== undefined && raw !== '';
|
|
151
|
+
const applicable = spec.hosts.includes(host);
|
|
152
|
+
return {
|
|
153
|
+
variable: spec.variable,
|
|
154
|
+
state: applicable ? (present ? 'set' : 'unset') : NOT_APPLICABLE,
|
|
155
|
+
value: present ? String(raw) : null,
|
|
156
|
+
checked_against: spec.checked_against,
|
|
157
|
+
writable_by_this_package: spec.writable_by_this_package,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* The `traffic_environment` block of `agent-config doctor --json`.
|
|
163
|
+
*
|
|
164
|
+
* Read-only by construction: the only input is the injected `env` map, and the
|
|
165
|
+
* only output is a fresh object. `hostOverride` is the test seam Phase 2.2's
|
|
166
|
+
* non-Claude fixture needs, and is never passed by the production call site.
|
|
167
|
+
*
|
|
168
|
+
* `reporting_read_only` replaced a flat `read_only: true` on 2026-09-30, and the
|
|
169
|
+
* rename is the point rather than cosmetics: this REPORT is still read-only, but
|
|
170
|
+
* the PACKAGE is no longer, so the old key had become a true statement about the
|
|
171
|
+
* wrong subject. Two of the four rows are now writable by the installer when the
|
|
172
|
+
* consumer sets a cap, and `writable_by_this_package` says which — a consumer
|
|
173
|
+
* reading `set` deserves to know whether we could have been the one who set it.
|
|
174
|
+
*/
|
|
175
|
+
export function trafficEnvironmentJson(
|
|
176
|
+
env: EnvMap,
|
|
177
|
+
hostOverride?: TrafficHost,
|
|
178
|
+
): Record<string, unknown> {
|
|
179
|
+
const resolved = hostOverride ?? resolveTrafficHost(env);
|
|
180
|
+
return {
|
|
181
|
+
host: resolved.host,
|
|
182
|
+
host_observed: resolved.observed,
|
|
183
|
+
doc: TRAFFIC_DOC,
|
|
184
|
+
reporting_read_only: true,
|
|
185
|
+
writable_by_this_package: TRAFFIC_VARIABLES.filter((v) => v.writable_by_this_package).map(
|
|
186
|
+
(v) => v.variable,
|
|
187
|
+
),
|
|
188
|
+
rows: TRAFFIC_VARIABLES.map((spec) => trafficRow(spec, env, resolved.host)),
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/** `fs.statSync` in a try — the `cmd_doctor.ts` helper this move preserves. */
|
|
193
|
+
function pathExists(p: string): boolean {
|
|
194
|
+
try {
|
|
195
|
+
fs.statSync(p);
|
|
196
|
+
return true;
|
|
197
|
+
} catch {
|
|
198
|
+
return false;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* The `offline-readiness` check — a pure move out of `cmd_doctor.ts`.
|
|
204
|
+
*
|
|
205
|
+
* `packageRoot` is passed IN rather than resolved here for the reason
|
|
206
|
+
* `doctor_runtime_checks.ts` gives for its `which` parameter: `_package_root`
|
|
207
|
+
* lives in `cmd_doctor.ts` and importing it back would make the two modules
|
|
208
|
+
* circular.
|
|
209
|
+
*/
|
|
210
|
+
export function checkOfflineReadiness(packageRoot: string): NetworkCheck {
|
|
211
|
+
const script = path.join(packageRoot, 'src', 'scripts', 'hermetic-install.sh');
|
|
212
|
+
if (!pathExists(script)) {
|
|
213
|
+
return {
|
|
214
|
+
id: 'offline-readiness',
|
|
215
|
+
status: 'warn',
|
|
216
|
+
message: 'src/scripts/hermetic-install.sh not found in package',
|
|
217
|
+
remedy: 'reinstall @event4u/agent-config or pull missing files',
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
return {
|
|
221
|
+
id: 'offline-readiness',
|
|
222
|
+
status: 'ok',
|
|
223
|
+
message: 'verified-offline install entrypoint present',
|
|
224
|
+
remedy: '',
|
|
225
|
+
};
|
|
226
|
+
}
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The runtime activation payload — what a trigger match charges per fire.
|
|
3
|
+
*
|
|
4
|
+
* The third of the three numbers `road-to-the-delivery-flip-that-tells-the-truth`
|
|
5
|
+
* Phase 3 separates. The other two already have names and a record: ADR-270
|
|
6
|
+
* calls them `source_corpus` (what the source tree could deliver) and
|
|
7
|
+
* `host_payload` (what one host actually receives at rest), and requires them to
|
|
8
|
+
* be structurally separate fields because "until the two are named apart, every
|
|
9
|
+
* ceiling discussion risks comparing unlike quantities". After a per-host
|
|
10
|
+
* projection flip a third quantity diverges from both: the bytes a delivery
|
|
11
|
+
* concern injects when a rule's trigger fires. A standing reduction published
|
|
12
|
+
* without it is a saving published without its cost.
|
|
13
|
+
*
|
|
14
|
+
* MEASURED THROUGH THE CONCERN'S OWN SELECTION, never a second model of it.
|
|
15
|
+
* `matchTierRules` + `selectForInjection` are the functions the runtime concern
|
|
16
|
+
* calls; an offline figure computed by a different matcher would price a set the
|
|
17
|
+
* concern does not deliver. That is the same single-definition rule
|
|
18
|
+
* `_lib/rule_injection.ts` was written for, applied one layer out.
|
|
19
|
+
*
|
|
20
|
+
* THE CAP IS A PARAMETER, not an import. The value lives on the concern
|
|
21
|
+
* (`hooks/rule_inject_hook.ts::CAP_BYTES`) and every caller passes it, so this
|
|
22
|
+
* module stays free of the hook's import closure and can be read from a gate, a
|
|
23
|
+
* report, or a bundled path without dragging a hook into it.
|
|
24
|
+
*
|
|
25
|
+
* Moved here from `report_standing_payload_by_host.ts`, which had the only
|
|
26
|
+
* implementation and is still its largest caller — same move, and for the same
|
|
27
|
+
* reason, as `censusRuleDir` into `_lib/carrier_divergence.ts`: a second reader
|
|
28
|
+
* needed it and a second copy is how two numbers start disagreeing.
|
|
29
|
+
*/
|
|
30
|
+
import * as fs from 'node:fs';
|
|
31
|
+
import * as path from 'node:path';
|
|
32
|
+
|
|
33
|
+
import { loadRouter, matchTierRules, selectForInjection } from './rule_injection.js';
|
|
34
|
+
|
|
35
|
+
/** The frozen corpus every fire figure in this module is sampled from. */
|
|
36
|
+
export const ROUTING_MATRIX_REL = path.join('tests', 'eval', 'routing-matrix');
|
|
37
|
+
|
|
38
|
+
/** One positive prompt of the frozen corpus, with the open files it declares. */
|
|
39
|
+
export interface CorpusPrompt {
|
|
40
|
+
prompt: string;
|
|
41
|
+
openFiles: string[] | null;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Every YAML shape inside `positives:` this hand parser cannot read.
|
|
46
|
+
*
|
|
47
|
+
* `readCorpusPositives` accepts only `- prompt: "…"` with a double-quoted
|
|
48
|
+
* same-line scalar and an inline `open_files: [...]`. Any other legal shape —
|
|
49
|
+
* single quotes, an unquoted scalar, a folded block, a block sequence for
|
|
50
|
+
* `open_files` — is SILENTLY SKIPPED, which drops fires out of the distribution
|
|
51
|
+
* a budget row is derived from. A measurement that governs a budget must fail
|
|
52
|
+
* loudly on a shape it cannot read rather than under-count, so callers refuse on
|
|
53
|
+
* a non-empty result here.
|
|
54
|
+
*
|
|
55
|
+
* Reported as a shape problem rather than fixed by widening the parser: this
|
|
56
|
+
* module must not grow a second YAML implementation, and the corpus is frozen,
|
|
57
|
+
* so the honest answer to an unreadable shape is to say which file carries it.
|
|
58
|
+
*/
|
|
59
|
+
export function corpusShapeProblems(root: string): string[] {
|
|
60
|
+
const dir = path.join(root, ROUTING_MATRIX_REL);
|
|
61
|
+
const problems: string[] = [];
|
|
62
|
+
if (!fs.existsSync(dir)) return problems;
|
|
63
|
+
for (const f of fs.readdirSync(dir).filter((n) => n.endsWith('.yaml')).sort()) {
|
|
64
|
+
let inPositives = false;
|
|
65
|
+
let lineNo = 0;
|
|
66
|
+
for (const raw of fs.readFileSync(path.join(dir, f), 'utf-8').split('\n')) {
|
|
67
|
+
lineNo += 1;
|
|
68
|
+
if (/^positives:/u.test(raw)) { inPositives = true; continue; }
|
|
69
|
+
if (/^near_misses:/u.test(raw)) { inPositives = false; continue; }
|
|
70
|
+
if (!inPositives) continue;
|
|
71
|
+
if (/^\s*-\s*prompt:/u.test(raw) && !/^\s*-\s*prompt:\s*"(.*)"\s*$/u.test(raw)) {
|
|
72
|
+
problems.push(
|
|
73
|
+
`${f}:${String(lineNo)}: a \`- prompt:\` this parser cannot read — only a ` +
|
|
74
|
+
`double-quoted same-line scalar is accepted: ${JSON.stringify(raw.trim())}`,
|
|
75
|
+
);
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
if (/^\s*-\s*/u.test(raw) && !/^\s*-\s*(prompt|command|open_files):/u.test(raw)
|
|
79
|
+
&& raw.trim() !== '-' && raw.trim() !== '') {
|
|
80
|
+
// A bare sequence item under `positives:` is a shape with no
|
|
81
|
+
// `prompt:` key on its first line — folded or nested.
|
|
82
|
+
if (!/^\s{4,}/u.test(raw)) {
|
|
83
|
+
problems.push(
|
|
84
|
+
`${f}:${String(lineNo)}: a positives entry whose first line carries no ` +
|
|
85
|
+
`\`prompt:\` key: ${JSON.stringify(raw.trim())}`,
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
if (/^\s*open_files:\s*$/u.test(raw)) {
|
|
90
|
+
problems.push(
|
|
91
|
+
`${f}:${String(lineNo)}: a BLOCK-sequence \`open_files:\` — only the inline ` +
|
|
92
|
+
'`[...]` form is read, so this entry\'s files would be dropped',
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return problems;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** Every positive prompt in the frozen routing-matrix corpus. Near-misses are not fires. */
|
|
101
|
+
export function readCorpusPositives(root: string): CorpusPrompt[] {
|
|
102
|
+
const dir = path.join(root, ROUTING_MATRIX_REL);
|
|
103
|
+
const out: CorpusPrompt[] = [];
|
|
104
|
+
if (!fs.existsSync(dir)) return out;
|
|
105
|
+
for (const f of fs.readdirSync(dir).filter((n) => n.endsWith('.yaml')).sort()) {
|
|
106
|
+
let inPositives = false;
|
|
107
|
+
let cur: CorpusPrompt | null = null;
|
|
108
|
+
for (const raw of fs.readFileSync(path.join(dir, f), 'utf-8').split('\n')) {
|
|
109
|
+
if (/^positives:/u.test(raw)) { inPositives = true; continue; }
|
|
110
|
+
if (/^near_misses:/u.test(raw)) { inPositives = false; continue; }
|
|
111
|
+
if (!inPositives) continue;
|
|
112
|
+
const p = /^\s*-\s*prompt:\s*"(.*)"\s*$/u.exec(raw);
|
|
113
|
+
if (p !== null) {
|
|
114
|
+
cur = { prompt: p[1] as string, openFiles: null };
|
|
115
|
+
out.push(cur);
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
const of = /^\s*open_files:\s*\[(.*)\]\s*$/u.exec(raw);
|
|
119
|
+
if (of !== null && cur !== null) {
|
|
120
|
+
cur.openFiles = (of[1] as string)
|
|
121
|
+
.split(',')
|
|
122
|
+
.map((x) => x.trim().replace(/^["']|["']$/gu, ''))
|
|
123
|
+
.filter((x) => x !== '');
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return out;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/** Nearest-rank percentile over an unsorted sample. Empty sample → 0. */
|
|
131
|
+
export function percentile(xs: readonly number[], q: number): number {
|
|
132
|
+
if (xs.length === 0) return 0;
|
|
133
|
+
const s = [...xs].sort((a, b) => a - b);
|
|
134
|
+
return s[Math.min(s.length - 1, Math.floor(q * (s.length - 1)))] as number;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export interface SlotFireSizes {
|
|
138
|
+
readonly slot: string;
|
|
139
|
+
readonly fires: number;
|
|
140
|
+
readonly p50: number;
|
|
141
|
+
readonly p90: number;
|
|
142
|
+
readonly max: number;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Gate-open per-fire emission sizes for the delivery concern, per slot.
|
|
147
|
+
*
|
|
148
|
+
* `pre_compact` is 0 by construction rather than by measurement: that branch of
|
|
149
|
+
* `rule_inject_hook` clears the seen-set and returns allow without writing to
|
|
150
|
+
* stdout, so there is no emission to sample.
|
|
151
|
+
*/
|
|
152
|
+
export function slotFireSizes(root: string, capBytes: number): SlotFireSizes[] {
|
|
153
|
+
const router = loadRouter(root);
|
|
154
|
+
const prompts = readCorpusPositives(root);
|
|
155
|
+
const sample = (mode: 'prompt' | 'file'): number[] => {
|
|
156
|
+
const out: number[] = [];
|
|
157
|
+
for (const r of prompts) {
|
|
158
|
+
if (mode === 'file' && (r.openFiles === null || r.openFiles.length === 0)) continue;
|
|
159
|
+
const matches =
|
|
160
|
+
mode === 'prompt'
|
|
161
|
+
? matchTierRules(router, r.prompt, null, null)
|
|
162
|
+
: matchTierRules(router, '', r.openFiles, null);
|
|
163
|
+
if (matches.length === 0) continue;
|
|
164
|
+
const sel = selectForInjection(root, matches, capBytes);
|
|
165
|
+
if (sel.selected.length > 0) out.push(sel.bytes);
|
|
166
|
+
}
|
|
167
|
+
return out;
|
|
168
|
+
};
|
|
169
|
+
const row = (slot: string, xs: number[]): SlotFireSizes => ({
|
|
170
|
+
slot,
|
|
171
|
+
fires: xs.length,
|
|
172
|
+
p50: percentile(xs, 0.5),
|
|
173
|
+
p90: percentile(xs, 0.9),
|
|
174
|
+
max: xs.length === 0 ? 0 : Math.max(...xs),
|
|
175
|
+
});
|
|
176
|
+
return [
|
|
177
|
+
row('user_prompt_submit', sample('prompt')),
|
|
178
|
+
row('pre_tool_use', sample('file')),
|
|
179
|
+
row('pre_compact', []),
|
|
180
|
+
];
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/** The third labelled number, or the reason it could not be taken on this tree. */
|
|
184
|
+
export interface ActivationPayload {
|
|
185
|
+
/** Always the literal `activation-payload` — the label a reader and a caller key on. */
|
|
186
|
+
readonly scope: 'activation-payload';
|
|
187
|
+
/** `false` when the corpus or the router is absent; every figure is then 0. */
|
|
188
|
+
readonly measured: boolean;
|
|
189
|
+
/** Why it is unmeasured, or `null`. Never an estimate in place of a number. */
|
|
190
|
+
readonly unmeasured_reason: string | null;
|
|
191
|
+
/** The cap the sampled selection was taken at — the concern's `CAP_BYTES`. */
|
|
192
|
+
readonly cap_bytes: number;
|
|
193
|
+
readonly corpus: string;
|
|
194
|
+
readonly slots: readonly SlotFireSizes[];
|
|
195
|
+
readonly basis: string;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* The runtime activation payload, or an honestly unmeasured reading.
|
|
200
|
+
*
|
|
201
|
+
* Never throws and never estimates: a missing corpus or router yields
|
|
202
|
+
* `measured: false` with the reason named, because a fabricated distribution
|
|
203
|
+
* published beside a standing saving is the exact defect this number exists to
|
|
204
|
+
* prevent.
|
|
205
|
+
*/
|
|
206
|
+
export function measureActivationPayload(root: string, capBytes: number): ActivationPayload {
|
|
207
|
+
const basis =
|
|
208
|
+
'Gate-open per-fire emission of the `rule-inject` concern over the frozen ' +
|
|
209
|
+
'`tests/eval/routing-matrix` positives, measured through the same ' +
|
|
210
|
+
'`matchTierRules` + `selectForInjection` the runtime concern calls, at the ' +
|
|
211
|
+
'concern\'s own CAP_BYTES. Bytes per fire, never tokens — the unit ' +
|
|
212
|
+
'`hook-token-budget.json` enforces.';
|
|
213
|
+
const empty = (reason: string): ActivationPayload => ({
|
|
214
|
+
scope: 'activation-payload',
|
|
215
|
+
measured: false,
|
|
216
|
+
unmeasured_reason: reason,
|
|
217
|
+
cap_bytes: capBytes,
|
|
218
|
+
corpus: ROUTING_MATRIX_REL,
|
|
219
|
+
slots: [],
|
|
220
|
+
basis,
|
|
221
|
+
});
|
|
222
|
+
if (!fs.existsSync(path.join(root, ROUTING_MATRIX_REL))) {
|
|
223
|
+
return empty(`the frozen corpus ${ROUTING_MATRIX_REL} is absent under ${root}`);
|
|
224
|
+
}
|
|
225
|
+
const shape = corpusShapeProblems(root);
|
|
226
|
+
if (shape.length > 0) {
|
|
227
|
+
return empty(
|
|
228
|
+
`${String(shape.length)} corpus entry/entries are in a shape the reader cannot parse, ` +
|
|
229
|
+
`so the distribution would be under-counted — first: ${shape[0] as string}`,
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
let slots: SlotFireSizes[];
|
|
233
|
+
try {
|
|
234
|
+
slots = slotFireSizes(root, capBytes);
|
|
235
|
+
} catch (err) {
|
|
236
|
+
return empty(`the fire sample could not be taken: ${(err as Error).message}`);
|
|
237
|
+
}
|
|
238
|
+
return {
|
|
239
|
+
scope: 'activation-payload',
|
|
240
|
+
measured: true,
|
|
241
|
+
unmeasured_reason: null,
|
|
242
|
+
cap_bytes: capBytes,
|
|
243
|
+
corpus: ROUTING_MATRIX_REL,
|
|
244
|
+
slots,
|
|
245
|
+
basis,
|
|
246
|
+
};
|
|
247
|
+
}
|
|
@@ -53,6 +53,7 @@ import { fileURLToPath } from 'node:url';
|
|
|
53
53
|
|
|
54
54
|
import * as user_global_paths from './user_global_paths.js';
|
|
55
55
|
import { carveOutKeys } from '../../shared/settingsCarveOut.js';
|
|
56
|
+
import { applyRenamedKeys } from './settings_renamed_keys.js';
|
|
56
57
|
import type * as YamlModule from 'yaml';
|
|
57
58
|
|
|
58
59
|
// ESM has no `require`; `createRequire(import.meta.url)` restores it so the
|
|
@@ -956,9 +957,9 @@ export function load_agent_settings(
|
|
|
956
957
|
// precedence here is the inverse of the server family's, so the order of
|
|
957
958
|
// these three statements is the whole contract.
|
|
958
959
|
const merged: SettingsDict = template_defaults(template_path ?? undefined);
|
|
959
|
-
_deep_merge(merged, user_global_filtered);
|
|
960
|
+
_deep_merge(merged, applyRenamedKeys(user_global_filtered));
|
|
960
961
|
for (const p of cascade) {
|
|
961
|
-
const layer = _read_yaml(p) ?? {};
|
|
962
|
+
const layer = applyRenamedKeys(_read_yaml(p) ?? {});
|
|
962
963
|
if (Object.keys(layer).length > 0) {
|
|
963
964
|
_deep_merge(merged, layer);
|
|
964
965
|
}
|
|
@@ -967,6 +968,7 @@ export function load_agent_settings(
|
|
|
967
968
|
return merged;
|
|
968
969
|
}
|
|
969
970
|
|
|
971
|
+
|
|
970
972
|
/**
|
|
971
973
|
* Settings keys this package has DELETED. A leftover value from an older
|
|
972
974
|
* install is ignored — never applied by any reader — and surfaced with ONE
|