@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,94 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* concern_timings — the per-concern latency sink the bench reads.
|
|
5
|
+
*
|
|
6
|
+
* Step 3.2 of `road-to-a-kernel-that-guards-its-plumbing`. The dispatcher has
|
|
7
|
+
* always timed each concern — `_run_concern` returns a duration and the
|
|
8
|
+
* feedback record carries it — but nothing could READ that distribution: the
|
|
9
|
+
* feedback dir keeps one file per concern and every dispatch OVERWRITES it, so
|
|
10
|
+
* the only survivor is the last run. A p95 needs every sample, and the bench
|
|
11
|
+
* harness that produces the samples runs with `AGENT_CONFIG_REPLAY=1`, where
|
|
12
|
+
* the feedback write returns before writing anything at all.
|
|
13
|
+
*
|
|
14
|
+
* So this sink is separate from the feedback dir on purpose, and deliberately
|
|
15
|
+
* not derived from it:
|
|
16
|
+
*
|
|
17
|
+
* - it APPENDS, so N runs leave N samples rather than one;
|
|
18
|
+
* - it is written in replay mode, because the measurement harness is the
|
|
19
|
+
* caller that needs it;
|
|
20
|
+
* - it is off unless the variable is set, so the cost on a real dispatch is
|
|
21
|
+
* one `process.env` lookup.
|
|
22
|
+
*
|
|
23
|
+
* It carries a concern name, an integer, an event and a platform. There is no
|
|
24
|
+
* field that can hold a payload, a path or a prompt — the same shape-level
|
|
25
|
+
* privacy floor `payload_stubs` keeps one row up.
|
|
26
|
+
*
|
|
27
|
+
* It lives in its own file rather than inside `dispatch_hook.ts` because that
|
|
28
|
+
* file sits against the 1,500-line source budget, and `check_source_size_budget`
|
|
29
|
+
* refused the inline version.
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
/** Environment variable naming the JSONL sink. Registered in the kill-switch table. */
|
|
33
|
+
export const TIMINGS_SINK_ENV = "AGENT_CONFIG_HOOK_TIMINGS";
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* One measurement.
|
|
37
|
+
*
|
|
38
|
+
* MICROseconds, not milliseconds. The dispatcher's `duration_ms` is floored,
|
|
39
|
+
* and since the in-process fast path landed every registry concern finishes in
|
|
40
|
+
* well under a millisecond — so the floored field reads exactly `0` for all of
|
|
41
|
+
* them. That was invisible while nothing consumed the number and stops being
|
|
42
|
+
* invisible the moment a p95 is reported and a timeout derived from it.
|
|
43
|
+
*/
|
|
44
|
+
export interface ConcernTimingSample {
|
|
45
|
+
concern: string;
|
|
46
|
+
duration_us: number;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Append one JSONL row per concern, when the sink is armed.
|
|
51
|
+
*
|
|
52
|
+
* Never throws and never blocks the dispatch: a measurement sink that can fail
|
|
53
|
+
* a hook would be a new way for the plumbing to refuse, which is the opposite
|
|
54
|
+
* of what this roadmap is for.
|
|
55
|
+
*/
|
|
56
|
+
export function writeConcernTimings(
|
|
57
|
+
event: string,
|
|
58
|
+
platform: string,
|
|
59
|
+
samples: readonly ConcernTimingSample[],
|
|
60
|
+
sinkPath: string | undefined = process.env[TIMINGS_SINK_ENV],
|
|
61
|
+
): void {
|
|
62
|
+
if (!sinkPath) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
try {
|
|
66
|
+
const lines: string[] = [];
|
|
67
|
+
for (const sample of samples) {
|
|
68
|
+
// A concern the dispatcher never timed is OMITTED rather than recorded
|
|
69
|
+
// as 0. A zero here would read as "instantaneous" and would be
|
|
70
|
+
// indistinguishable from a real sub-millisecond run — the exact
|
|
71
|
+
// substitution the report's `not_measured` requirement forbids one layer
|
|
72
|
+
// up, reintroduced at the source instead of at the report.
|
|
73
|
+
if (!Number.isFinite(sample.duration_us)) {
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
lines.push(
|
|
77
|
+
JSON.stringify({
|
|
78
|
+
concern: sample.concern,
|
|
79
|
+
// Rounded HERE rather than at the call site: the caller holds a
|
|
80
|
+
// float millisecond reading and the sink is the one place that has
|
|
81
|
+
// to decide the recorded unit.
|
|
82
|
+
duration_us: Math.round(sample.duration_us),
|
|
83
|
+
event,
|
|
84
|
+
platform,
|
|
85
|
+
}),
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
if (lines.length > 0) {
|
|
89
|
+
fs.appendFileSync(sinkPath, lines.join("\n") + "\n", "utf-8");
|
|
90
|
+
}
|
|
91
|
+
} catch {
|
|
92
|
+
// Non-fatal by construction — see the header.
|
|
93
|
+
}
|
|
94
|
+
}
|
|
@@ -102,15 +102,14 @@ import { classifyLadder, type LadderRung } from "../_lib/judgment_ladder.js";
|
|
|
102
102
|
import { resolveSessionRole } from "../_lib/session_role.js";
|
|
103
103
|
import { resolveSubagentRouting, type Tier } from "../_lib/subagent_routing.js";
|
|
104
104
|
import { isSyntheticPrompt } from "../_lib/prompt_shape.js";
|
|
105
|
+
import { EXIT_ALLOW, EXIT_WARN } from './exit_codes.js';
|
|
105
106
|
|
|
106
|
-
const EXIT_ALLOW = 0;
|
|
107
107
|
// Severity is taken from the EXIT CODE, not from the `decision` field in the
|
|
108
108
|
// stdout payload — mirrors `language_mirror_hook.ts`'s own note (found the
|
|
109
109
|
// same way: by tracing delivery, not by re-reading the unit tests). A warn
|
|
110
110
|
// verdict is reported at exit 2 so `host_semantics.emitFor` reduces it to
|
|
111
111
|
// severity `"warn"` and forwards `additional_context`; see the file header
|
|
112
112
|
// for why this exit code never actually blocks the turn.
|
|
113
|
-
const EXIT_WARN = 2;
|
|
114
113
|
|
|
115
114
|
type JsonValue = string | number | boolean | null | JsonValue[] | { [k: string]: JsonValue };
|
|
116
115
|
type JsonObject = { [k: string]: JsonValue };
|
|
@@ -56,15 +56,18 @@ import fs from 'node:fs';
|
|
|
56
56
|
import path from 'node:path';
|
|
57
57
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
58
58
|
|
|
59
|
+
import { appendDischarge, stamp } from '../_lib/obligations.js';
|
|
60
|
+
import { compareInputs } from '../_lib/probe_inputs.js';
|
|
61
|
+
import { trigger_matches, type Trigger } from '../_lib/router_match.js';
|
|
59
62
|
import { isUiPath, isUiTreePath } from '../_lib/ui_surface.js';
|
|
60
63
|
import { loadDesignContext, scanFile } from '../lint_design_slop.js';
|
|
61
64
|
import { readHookStdin } from './hook_stdin.js';
|
|
65
|
+
import { EXIT_ALLOW, EXIT_WARN } from './exit_codes.js';
|
|
62
66
|
|
|
63
|
-
const EXIT_ALLOW = 0;
|
|
64
|
-
const EXIT_WARN = 2;
|
|
65
67
|
const SETTINGS_FILE = '.agent-settings.yml';
|
|
66
68
|
const STATE_REL = path.join('agents', 'runtime', 'state', 'design-pass-hook.json');
|
|
67
69
|
const AUDIT_REL = path.join('agents', 'runtime', 'state', 'ui-audit.json');
|
|
70
|
+
const CONFORMANCE_REL = path.join('agents', 'runtime', 'state', 'ui-conformance.json');
|
|
68
71
|
|
|
69
72
|
/**
|
|
70
73
|
* The P0 set — objective floors only, and the list is closed on purpose.
|
|
@@ -128,6 +131,167 @@ export function enabled(root: string, key = 'design_pass'): boolean {
|
|
|
128
131
|
|
|
129
132
|
export const isUiSurface = (p: string): boolean => isUiPath(p) || isUiTreePath(p);
|
|
130
133
|
|
|
134
|
+
/**
|
|
135
|
+
* The shadow read of `ui-conformance.json` — Phase 5 of
|
|
136
|
+
* `road-to-behaviour-evidence-over-pixels`.
|
|
137
|
+
*
|
|
138
|
+
* SHADOW MEANS SHADOW. This produces a line in the reported verdict and
|
|
139
|
+
* touches nothing else: it is not consulted by `decide`, never reaches
|
|
140
|
+
* `blocked`, and cannot change an exit code. The roadmap adds evidence, not
|
|
141
|
+
* enforcement, and the block path is deliberately untouched by this change.
|
|
142
|
+
*
|
|
143
|
+
* An ABSENT artefact is reported as absent, never as clean — the same rule the
|
|
144
|
+
* probe applies to its own dimensions. A malformed one is reported as
|
|
145
|
+
* unreadable for the same reason.
|
|
146
|
+
*/
|
|
147
|
+
export interface ConformanceVerdict {
|
|
148
|
+
/**
|
|
149
|
+
* Whether this verdict is worth surfacing on its own. An ABSENT artefact is
|
|
150
|
+
* not: most repositories never run the probe, and a line on every clean UI
|
|
151
|
+
* write is the noise that gets a carrier switched off — Risk 1 of the parent
|
|
152
|
+
* roadmap. Absent is still reported honestly whenever the pass speaks for
|
|
153
|
+
* another reason.
|
|
154
|
+
*
|
|
155
|
+
* The ONE exception is a turn that actually touched a provided design
|
|
156
|
+
* handover. There, the probe is the evidence the turn was supposed to
|
|
157
|
+
* produce, and its absence is the noteworthy kind.
|
|
158
|
+
*/
|
|
159
|
+
noteworthy: boolean;
|
|
160
|
+
line: string;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export interface ConformanceOptions {
|
|
164
|
+
/**
|
|
165
|
+
* Whether a provided design handover was among the files this turn wrote.
|
|
166
|
+
* Decided by `handoverTouched` from the shipped routing triggers, never by a
|
|
167
|
+
* matcher invented here.
|
|
168
|
+
*/
|
|
169
|
+
handoverDetected?: boolean;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* The file-based half of `src/rules/design-fidelity.md`'s `triggers:` set — the
|
|
174
|
+
* shipped answer to "is this file a provided design handover?".
|
|
175
|
+
*
|
|
176
|
+
* COPIED AS A CONSTANT, MATCHED BY THE SHIPPED MATCHER. Reading and parsing the
|
|
177
|
+
* rule's frontmatter here would put a YAML load on `post_tool_use`, the hottest
|
|
178
|
+
* slot this concern binds, and would depend on a rule path that differs between
|
|
179
|
+
* this repository and an installed consumer. The drift that a constant invites
|
|
180
|
+
* is closed by a test instead: `design_pass.test.ts` asserts this list equals the
|
|
181
|
+
* rule's file-based triggers in BOTH directions, so a trigger added to the rule
|
|
182
|
+
* and not here fails CI.
|
|
183
|
+
*
|
|
184
|
+
* THE HONEST REACH. Only the two HTML patterns are reachable through this
|
|
185
|
+
* carrier. `.claude/design-system/` names JSON and token files, which
|
|
186
|
+
* `isUiSurface` does not admit, so `main` returns before the verdict is
|
|
187
|
+
* computed. Widening `isUiSurface` to admit them would change the UI-turn
|
|
188
|
+
* denominator that the consultation-rate measurement is defined against, which
|
|
189
|
+
* is a different decision than this one. The prefix stays for parity with the
|
|
190
|
+
* rule and is stated as unreachable rather than quietly dropped.
|
|
191
|
+
*/
|
|
192
|
+
export const HANDOVER_TRIGGERS: readonly Trigger[] = [
|
|
193
|
+
{ file_pattern: '*design.html' },
|
|
194
|
+
{ file_pattern: '*.dc.html' },
|
|
195
|
+
{ path_prefix: '.claude/design-system/' },
|
|
196
|
+
];
|
|
197
|
+
|
|
198
|
+
/** True when any of the paths this turn wrote is a provided design handover. */
|
|
199
|
+
export function handoverTouched(paths: readonly string[]): boolean {
|
|
200
|
+
if (!paths.length) return false;
|
|
201
|
+
return HANDOVER_TRIGGERS.some((t) => trigger_matches(t, '', paths, null));
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
export function conformanceVerdict(root: string, opts: ConformanceOptions = {}): ConformanceVerdict {
|
|
205
|
+
let raw: string;
|
|
206
|
+
try {
|
|
207
|
+
raw = fs.readFileSync(path.join(root, CONFORMANCE_REL), 'utf-8');
|
|
208
|
+
} catch {
|
|
209
|
+
const base =
|
|
210
|
+
'ui-conformance: absent — no probe artefact for this change (run `ui_conformance_probe --target <file> --reference <file>`). Absent is not clean.';
|
|
211
|
+
return opts.handoverDetected
|
|
212
|
+
? {
|
|
213
|
+
noteworthy: true,
|
|
214
|
+
line: `${base} A provided design handover was touched this turn, so this is the absence worth naming.`,
|
|
215
|
+
}
|
|
216
|
+
: { noteworthy: false, line: base };
|
|
217
|
+
}
|
|
218
|
+
try {
|
|
219
|
+
const a = JSON.parse(raw) as {
|
|
220
|
+
structure_gate?: string;
|
|
221
|
+
inputs?: unknown;
|
|
222
|
+
dimensions?: { dimension: string; status: string; findings: number | null; reason?: string }[];
|
|
223
|
+
findings?: { dimension?: string; probe_id?: string; expected?: string; observed?: string }[];
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
// Before anything is counted. A finding count measured against inputs
|
|
227
|
+
// that have since moved is the misleading half of a stale artefact, so
|
|
228
|
+
// the count is withheld rather than printed beside a warning.
|
|
229
|
+
const inputs = compareInputs(a.inputs, (p) => (path.isAbsolute(p) ? p : path.join(root, p)));
|
|
230
|
+
if (inputs.verdict === 'moved') {
|
|
231
|
+
return {
|
|
232
|
+
noteworthy: true,
|
|
233
|
+
line: [
|
|
234
|
+
`ui-conformance: stale — ${inputs.moved.join(', ')} changed since the probe ran, so its findings ` +
|
|
235
|
+
'describe inputs that no longer exist. The count is withheld rather than reported against ' +
|
|
236
|
+
'them; re-run `ui_conformance_probe --target <file> --reference <file>`.',
|
|
237
|
+
' (shadow verdict: reported, never enforced — this pass does not block on it)',
|
|
238
|
+
].join('\n'),
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
const rows = a.dimensions ?? [];
|
|
243
|
+
const exercised = rows.filter((r) => r.status === 'exercised');
|
|
244
|
+
const notApplicable = rows.filter((r) => r.status !== 'exercised');
|
|
245
|
+
const counts = exercised.map((r) => `${r.dimension}=${r.findings}`).join(' ');
|
|
246
|
+
const parts = [
|
|
247
|
+
`ui-conformance: ${(a.findings ?? []).length} behavioural finding(s) — ${counts || 'no dimension exercised'}`,
|
|
248
|
+
];
|
|
249
|
+
if (notApplicable.length) {
|
|
250
|
+
parts.push(
|
|
251
|
+
` · not applicable: ${notApplicable
|
|
252
|
+
.map((r) => `${r.dimension} (${r.reason ?? 'no reason given'})`)
|
|
253
|
+
.join('; ')}`,
|
|
254
|
+
);
|
|
255
|
+
}
|
|
256
|
+
if (a.structure_gate === 'stopped') {
|
|
257
|
+
parts.push(' · structure gate stopped on at least one node — style comparison was skipped for it');
|
|
258
|
+
}
|
|
259
|
+
// The added-element half. This line already said "Absent is not clean"
|
|
260
|
+
// about a missing artefact; the probe's structure dimension could only
|
|
261
|
+
// ever show the omit half of "never omit or add an element", so this is
|
|
262
|
+
// the one number the verdict could not print. Derived from the findings
|
|
263
|
+
// the probe already writes — no new artefact field is read.
|
|
264
|
+
const addedElements = (a.findings ?? []).filter(
|
|
265
|
+
(f) => f.dimension === 'structure' && f.expected === 'absent' && f.observed === 'present',
|
|
266
|
+
);
|
|
267
|
+
if (addedElements.length) {
|
|
268
|
+
parts.push(
|
|
269
|
+
` · ${addedElements.length} element(s) present in the target and absent from the reference: ` +
|
|
270
|
+
`${addedElements.map((f) => f.probe_id ?? '?').join(', ')} — added, not ported`,
|
|
271
|
+
);
|
|
272
|
+
}
|
|
273
|
+
parts.push(
|
|
274
|
+
inputs.verdict === 'unchanged'
|
|
275
|
+
? ' · inputs: unchanged since the probe ran'
|
|
276
|
+
: // Unknown is a version skew, not evidence of movement — and
|
|
277
|
+
// equally not evidence of freshness. Saying so is the whole
|
|
278
|
+
// point: an artefact from before the digests existed must read
|
|
279
|
+
// neither stale nor fresh.
|
|
280
|
+
` · inputs: unknown — ${inputs.reason}`,
|
|
281
|
+
);
|
|
282
|
+
parts.push(' (shadow verdict: reported, never enforced — this pass does not block on it)');
|
|
283
|
+
return {
|
|
284
|
+
noteworthy: (a.findings ?? []).length > 0 || a.structure_gate === 'stopped' || notApplicable.length > 0,
|
|
285
|
+
line: parts.join('\n'),
|
|
286
|
+
};
|
|
287
|
+
} catch {
|
|
288
|
+
return {
|
|
289
|
+
noteworthy: true,
|
|
290
|
+
line: 'ui-conformance: unreadable — the artefact exists but did not parse. Reported rather than ignored.',
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
131
295
|
/**
|
|
132
296
|
* E2.2 — is the audit artefact newer than the target?
|
|
133
297
|
*
|
|
@@ -135,6 +299,43 @@ export const isUiSurface = (p: string): boolean => isUiPath(p) || isUiTreePath(p
|
|
|
135
299
|
* because it looks like evidence. An artefact older than the file it is
|
|
136
300
|
* supposed to describe has not seen the change.
|
|
137
301
|
*/
|
|
302
|
+
/**
|
|
303
|
+
* Record that the UI-audit obligation was discharged, when it was.
|
|
304
|
+
*
|
|
305
|
+
* This concern is the only thing in the tree that knows. It already decides
|
|
306
|
+
* audit freshness for its own advisory line; until now that decision was spent
|
|
307
|
+
* on one message and thrown away, so a turn-end reader asking "was the audit
|
|
308
|
+
* done?" had to re-derive a verdict it does not own. The decision existed —
|
|
309
|
+
* only the write was missing.
|
|
310
|
+
*
|
|
311
|
+
* Discharged means: at least one target was touched AND every one of them has
|
|
312
|
+
* a fresh audit. A partial pass records nothing, because `ui-audit-gate`'s
|
|
313
|
+
* obligation is about the surfaces this turn wrote, not about a quorum of them.
|
|
314
|
+
*
|
|
315
|
+
* NO PER-WRITE VALIDATOR IS ADDED. The write is one small append behind the
|
|
316
|
+
* same lock the ledger already uses, on a path that has an mtime comparison in
|
|
317
|
+
* front of it — deliberately, because this concern sits on `post_tool_use`,
|
|
318
|
+
* the hottest slot it binds, and a validation pass per write is exactly the
|
|
319
|
+
* cost the phase forbids.
|
|
320
|
+
*/
|
|
321
|
+
export function recordAuditDischarge(
|
|
322
|
+
root: string,
|
|
323
|
+
targets: readonly string[],
|
|
324
|
+
auditMissing: readonly string[],
|
|
325
|
+
): void {
|
|
326
|
+
if (targets.length === 0 || auditMissing.length > 0) return;
|
|
327
|
+
const session = (process.env["CLAUDE_CODE_SESSION_ID"] ?? "").trim();
|
|
328
|
+
if (session === "") return;
|
|
329
|
+
try {
|
|
330
|
+
appendDischarge(root, session, [
|
|
331
|
+
{ rule: "ui-audit-gate", by: "design-pass", at: stamp() },
|
|
332
|
+
]);
|
|
333
|
+
} catch {
|
|
334
|
+
// A discharge that cannot be recorded is a missing reading, never a
|
|
335
|
+
// reason to fail the write that prompted it.
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
138
339
|
export function auditIsFresh(root: string, target: string): boolean {
|
|
139
340
|
try {
|
|
140
341
|
const a = fs.statSync(path.join(root, AUDIT_REL)).mtimeMs;
|
|
@@ -252,7 +453,7 @@ export function targetPath(payload: unknown): string | null {
|
|
|
252
453
|
return null;
|
|
253
454
|
}
|
|
254
455
|
|
|
255
|
-
export function render(result: PassResult): string {
|
|
456
|
+
export function render(result: PassResult, conformance?: string): string {
|
|
256
457
|
const lines: string[] = [];
|
|
257
458
|
if (result.blocked.length) {
|
|
258
459
|
lines.push(
|
|
@@ -272,6 +473,9 @@ export function render(result: PassResult): string {
|
|
|
272
473
|
lines.push(` · no ui-audit.json newer than ${m} — run \`agent-config ui:audit <path>\``);
|
|
273
474
|
lines.push(`verification: ${result.verification}`);
|
|
274
475
|
if (result.degradation_reason) lines.push(`degradation_reason: ${result.degradation_reason}`);
|
|
476
|
+
// Appended last and never consulted above: the conformance verdict is a
|
|
477
|
+
// report, not an input to any decision this pass makes.
|
|
478
|
+
if (conformance) lines.push(conformance);
|
|
275
479
|
return lines.join('\n');
|
|
276
480
|
}
|
|
277
481
|
|
|
@@ -329,6 +533,7 @@ function main(): number {
|
|
|
329
533
|
}
|
|
330
534
|
|
|
331
535
|
const auditMissing = targets.filter((t) => !auditIsFresh(root, t));
|
|
536
|
+
recordAuditDischarge(root, targets, auditMissing);
|
|
332
537
|
let result = decide(slot, findings, auditMissing, new Set(state.surfaced), renderAvailable(root));
|
|
333
538
|
if (scanFailed) {
|
|
334
539
|
result = { ...result, verification: 'unverified', degradation_reason: `detector unavailable: ${scanFailed}` };
|
|
@@ -338,11 +543,22 @@ function main(): number {
|
|
|
338
543
|
if (slot === 'stop') state.touched = [];
|
|
339
544
|
writeState(root, state);
|
|
340
545
|
|
|
341
|
-
|
|
546
|
+
// Shadow mount. The verdict can make the pass SPEAK when it would otherwise
|
|
547
|
+
// be silent — a behavioural finding is exactly the thing no static scan can
|
|
548
|
+
// see — but it cannot make it refuse. `result.blocked` above is computed
|
|
549
|
+
// without it and the exit code below is unchanged.
|
|
550
|
+
const conformance = conformanceVerdict(root, { handoverDetected: handoverTouched(targets) });
|
|
551
|
+
|
|
552
|
+
if (
|
|
553
|
+
!result.findings.length &&
|
|
554
|
+
!result.audit_missing.length &&
|
|
555
|
+
result.verification === 'verified' &&
|
|
556
|
+
!conformance.noteworthy
|
|
557
|
+
) {
|
|
342
558
|
return EXIT_ALLOW;
|
|
343
559
|
}
|
|
344
560
|
|
|
345
|
-
process.stdout.write(`${JSON.stringify({ reason: render(result) })}\n`);
|
|
561
|
+
process.stdout.write(`${JSON.stringify({ reason: render(result, conformance.line) })}\n`);
|
|
346
562
|
// Deliberately EXIT_WARN even with a P0 verdict. EXIT_BLOCK is unreachable
|
|
347
563
|
// for an advisory concern (the dispatcher downgrades it), so returning it
|
|
348
564
|
// would claim a refusal the transport discards.
|
|
@@ -26,10 +26,9 @@ import { type DesignContext } from "../design_slop_rules.js";
|
|
|
26
26
|
import { UI_EXT } from "../_lib/ui_surface.js";
|
|
27
27
|
import { loadDesignContext, scanFile } from "../lint_design_slop.js";
|
|
28
28
|
import { readHookStdin } from "./hook_stdin.js";
|
|
29
|
+
import { EXIT_ALLOW, EXIT_WARN } from './exit_codes.js';
|
|
29
30
|
|
|
30
31
|
const SETTINGS_FILE = ".agent-settings.yml";
|
|
31
|
-
const EXIT_ALLOW = 0;
|
|
32
|
-
const EXIT_WARN = 2;
|
|
33
32
|
const DEGRADE_AFTER = 3; // surfaces of the same file::rule signature before going silent
|
|
34
33
|
|
|
35
34
|
type JsonValue = string | number | boolean | null | JsonValue[] | { [k: string]: JsonValue };
|
|
@@ -34,6 +34,10 @@ import * as tty from "node:tty";
|
|
|
34
34
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
35
35
|
import { parse as parseYaml } from "yaml";
|
|
36
36
|
|
|
37
|
+
import { runBundleIntegrityGate } from "./bundle_integrity.js";
|
|
38
|
+
import { writeConcernTimings, type ConcernTimingSample } from "./concern_timings.js";
|
|
39
|
+
import { tableFingerprint } from "./table_fingerprint.js";
|
|
40
|
+
|
|
37
41
|
import { hardenedSpawnEnv } from "../_lib/spawn_env.js";
|
|
38
42
|
import {
|
|
39
43
|
atomic_write_json,
|
|
@@ -59,6 +63,8 @@ import { _py_json_dumps } from './py_json_dumps.js';
|
|
|
59
63
|
import { _fallback_yaml } from './fallback_yaml.js';
|
|
60
64
|
import { detectSurface } from '../_lib/surface.js';
|
|
61
65
|
import { recordCapture, recordOpportunity } from "../_lib/collector_denominator.js";
|
|
66
|
+
import { EXIT_ALLOW, EXIT_BLOCK, EXIT_WARN, EXIT_USAGE } from './exit_codes.js';
|
|
67
|
+
export { EXIT_ALLOW, EXIT_BLOCK, EXIT_WARN };
|
|
62
68
|
export { _fallback_yaml } from './fallback_yaml.js';
|
|
63
69
|
|
|
64
70
|
// Free-form JSON values flow through every helper here; a documented
|
|
@@ -84,10 +90,6 @@ const REPO_ROOT = path.resolve(
|
|
|
84
90
|
);
|
|
85
91
|
const MANIFEST_PATH = path.join(REPO_ROOT, "src", "scripts", "hook_manifest.yaml");
|
|
86
92
|
|
|
87
|
-
export const EXIT_ALLOW = 0;
|
|
88
|
-
export const EXIT_BLOCK = 1;
|
|
89
|
-
export const EXIT_WARN = 2;
|
|
90
|
-
|
|
91
93
|
// Per Council Round 2 (Q3): `agent_error` covers agent-level crashes
|
|
92
94
|
// that are not concern-triggered, so chat-history can checkpoint
|
|
93
95
|
// partial sessions on abnormal exit.
|
|
@@ -206,12 +208,7 @@ export function _parse_concern_stdout(stdout_text: string): JsonObject {
|
|
|
206
208
|
* correctness.
|
|
207
209
|
*/
|
|
208
210
|
export function _manifest_fingerprint(text: string): string {
|
|
209
|
-
|
|
210
|
-
for (let i = 0; i < text.length; i += 1) {
|
|
211
|
-
h ^= text.charCodeAt(i);
|
|
212
|
-
h = Math.imul(h, 0x01000193) >>> 0;
|
|
213
|
-
}
|
|
214
|
-
return `${h.toString(16)}:${String(text.length)}`;
|
|
211
|
+
return tableFingerprint(text);
|
|
215
212
|
}
|
|
216
213
|
|
|
217
214
|
export function _load_yaml(p: string): JsonObject {
|
|
@@ -251,12 +248,10 @@ export function _load_yaml(p: string): JsonObject {
|
|
|
251
248
|
return _isObject(data) ? data : {};
|
|
252
249
|
}
|
|
253
250
|
|
|
254
|
-
|
|
255
251
|
interface ConcernDef extends JsonObject {
|
|
256
252
|
name: string;
|
|
257
253
|
}
|
|
258
254
|
|
|
259
|
-
|
|
260
255
|
/**
|
|
261
256
|
* Per-concern tool filter — the `tools:` key.
|
|
262
257
|
*
|
|
@@ -424,7 +419,6 @@ export function _resolve_concerns(
|
|
|
424
419
|
return out;
|
|
425
420
|
}
|
|
426
421
|
|
|
427
|
-
|
|
428
422
|
/**
|
|
429
423
|
* Write the raw stdin payload to a capture directory when
|
|
430
424
|
* `AGENT_HOOK_CAPTURE_DIR` is set. Fail-silent: any IO / JSON error must
|
|
@@ -506,6 +500,7 @@ interface RunResult {
|
|
|
506
500
|
rc: number;
|
|
507
501
|
stderr: string;
|
|
508
502
|
stdout: string;
|
|
503
|
+
/** Elapsed ms, NOT floored — floored where STORED. See `concern_timings.ts`. */
|
|
509
504
|
duration_ms: number;
|
|
510
505
|
}
|
|
511
506
|
|
|
@@ -680,8 +675,7 @@ function _run_concern_inproc(
|
|
|
680
675
|
}
|
|
681
676
|
clearHookStdinOverride();
|
|
682
677
|
}
|
|
683
|
-
|
|
684
|
-
return { rc, stderr: err, stdout: out, duration_ms: elapsed };
|
|
678
|
+
return { rc, stderr: err, stdout: out, duration_ms: performance.now() - started };
|
|
685
679
|
}
|
|
686
680
|
|
|
687
681
|
function _run_concern(concern: ConcernDef, envelope: JsonObject): RunResult {
|
|
@@ -736,7 +730,7 @@ function _run_concern(concern: ConcernDef, envelope: JsonObject): RunResult {
|
|
|
736
730
|
env: concern_env,
|
|
737
731
|
timeout: 30000,
|
|
738
732
|
});
|
|
739
|
-
const elapsed =
|
|
733
|
+
const elapsed = performance.now() - started;
|
|
740
734
|
if (proc.error) {
|
|
741
735
|
// OSError / timeout equivalent — log execution-failed so the
|
|
742
736
|
// never-block contract keeps a trace.
|
|
@@ -796,6 +790,7 @@ interface FeedbackEntry extends JsonObject {
|
|
|
796
790
|
concern: string;
|
|
797
791
|
}
|
|
798
792
|
|
|
793
|
+
|
|
799
794
|
/**
|
|
800
795
|
* Write per-concern feedback files + summary rollup.
|
|
801
796
|
*
|
|
@@ -1064,7 +1059,7 @@ function _parse_args(argv: string[]): Args {
|
|
|
1064
1059
|
process.stderr.write(
|
|
1065
1060
|
`dispatch_hook: the following arguments are required: ${missing.join(", ")}\n`,
|
|
1066
1061
|
);
|
|
1067
|
-
process.exit(
|
|
1062
|
+
process.exit(EXIT_USAGE);
|
|
1068
1063
|
}
|
|
1069
1064
|
return args;
|
|
1070
1065
|
}
|
|
@@ -1251,6 +1246,15 @@ export function main(argv?: string[]): number {
|
|
|
1251
1246
|
}
|
|
1252
1247
|
}
|
|
1253
1248
|
|
|
1249
|
+
// Step 3.1 — the bundle we execute must be the bundle the build produced.
|
|
1250
|
+
// Beside `denyOnStdinFailure` for its reason: the verdict needs the resolved
|
|
1251
|
+
// concern list. Rules: `bundle_integrity.ts`.
|
|
1252
|
+
if (_IN_BUNDLE) {
|
|
1253
|
+
const stop = runBundleIntegrityGate(fileURLToPath(import.meta.url), args.platform,
|
|
1254
|
+
args.event, concerns.some((c) => !_is_advisory(c)));
|
|
1255
|
+
if (stop !== null) return stop;
|
|
1256
|
+
}
|
|
1257
|
+
|
|
1254
1258
|
const envelope = _build_envelope(args, payload_text);
|
|
1255
1259
|
const session_id = _resolve_session_id(envelope);
|
|
1256
1260
|
const started_at = _now_iso();
|
|
@@ -1286,6 +1290,7 @@ export function main(argv?: string[]): number {
|
|
|
1286
1290
|
// classes are present, which any concern loses, the single measurement pass,
|
|
1287
1291
|
// and the at-most-four envelope shapes — so the loop below reads a shape
|
|
1288
1292
|
// rather than re-deriving one. Rationale and cost model: payload_stub.ts.
|
|
1293
|
+
const timing_samples: ConcernTimingSample[] = [];
|
|
1289
1294
|
const keep_by_concern = concerns.map(
|
|
1290
1295
|
(c) => [c, _concern_body_classes(c)] as const,
|
|
1291
1296
|
);
|
|
@@ -1308,6 +1313,7 @@ export function main(argv?: string[]): number {
|
|
|
1308
1313
|
const concern_started = _now_iso();
|
|
1309
1314
|
const { rc: rawRcResult, stderr: stderr_text, stdout: stdout_text, duration_ms } =
|
|
1310
1315
|
_run_concern(concern, concern_envelope);
|
|
1316
|
+
timing_samples.push({ concern: String(concern["name"]), duration_us: duration_ms * 1000 });
|
|
1311
1317
|
let rc = rawRcResult;
|
|
1312
1318
|
const raw_rc = rc;
|
|
1313
1319
|
if (rc >= 3) {
|
|
@@ -1376,7 +1382,7 @@ export function main(argv?: string[]): number {
|
|
|
1376
1382
|
severity: _severity_for(rc),
|
|
1377
1383
|
decision: (reply["decision"] || _severity_for(rc)) as JsonValue,
|
|
1378
1384
|
reason: (reply["reason"] ?? null) as JsonValue,
|
|
1379
|
-
duration_ms,
|
|
1385
|
+
duration_ms: Math.floor(duration_ms),
|
|
1380
1386
|
started_at: concern_started,
|
|
1381
1387
|
completed_at: _now_iso(),
|
|
1382
1388
|
fail_closed: Boolean(concern["fail_closed"]),
|
|
@@ -1392,6 +1398,7 @@ export function main(argv?: string[]): number {
|
|
|
1392
1398
|
});
|
|
1393
1399
|
}
|
|
1394
1400
|
const final_rc = _reduce(rcs);
|
|
1401
|
+
writeConcernTimings(String(envelope["event"] ?? ""), String(envelope["platform"] ?? ""), timing_samples);
|
|
1395
1402
|
_write_feedback(envelope, session_id, feedback_entries, final_rc, started_at);
|
|
1396
1403
|
_record_rule_trips(envelope, feedback_entries);
|
|
1397
1404
|
if (context_blocks.length > 0 && final_rc === EXIT_ALLOW) {
|
|
@@ -1459,7 +1466,6 @@ function _sortedRepr(s: ReadonlySet<string>): string {
|
|
|
1459
1466
|
*/
|
|
1460
1467
|
let _stdin_read_failed: string | null = null;
|
|
1461
1468
|
|
|
1462
|
-
|
|
1463
1469
|
// Bundle-safety: never auto-run when inlined into an esbuild bundle, where
|
|
1464
1470
|
// every module shares the bundle's `import.meta.url` (declare at top of file).
|
|
1465
1471
|
function _isCliEntry(): boolean {
|
|
@@ -86,11 +86,10 @@ import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
|
86
86
|
import { unwrap, type JsonObject, type JsonValue } from './envelope.js';
|
|
87
87
|
import { readHookStdin } from './hook_stdin.js';
|
|
88
88
|
import { atomic_write_json } from './state_io.js';
|
|
89
|
+
import { EXIT_ALLOW, EXIT_WARN } from './exit_codes.js';
|
|
89
90
|
|
|
90
|
-
const EXIT_ALLOW = 0;
|
|
91
91
|
// Severity is taken from the EXIT CODE, not from the `decision` field in the
|
|
92
92
|
// stdout payload — see the file header for why this never blocks on `claude`.
|
|
93
|
-
const EXIT_WARN = 2;
|
|
94
93
|
|
|
95
94
|
/** Committed threshold (roadmap 5.1): minimum current line count of the
|
|
96
95
|
* replaced file before this concern has anything to say. */
|
|
@@ -253,6 +253,7 @@ import {
|
|
|
253
253
|
import { unwrap, type JsonObject, type JsonValue } from './envelope.js';
|
|
254
254
|
import { readHookStdin } from './hook_stdin.js';
|
|
255
255
|
import { atomic_write_json, is_replay_mode } from './state_io.js';
|
|
256
|
+
import { EXIT_WARN } from './exit_codes.js';
|
|
256
257
|
|
|
257
258
|
/** Default fire threshold — the council's high-risk shape (roadmap 5.1). */
|
|
258
259
|
export const MUTATION_LINE_THRESHOLD = 50;
|
|
@@ -319,7 +320,6 @@ export function isSafeTranscriptPath(
|
|
|
319
320
|
// reported at exit 2 so `host_semantics.emitFor` reduces it to severity
|
|
320
321
|
// `"warn"` and forwards `additional_context`; see the file header for why
|
|
321
322
|
// this exit code never actually blocks the turn on `claude`.
|
|
322
|
-
const EXIT_WARN = 2;
|
|
323
323
|
|
|
324
324
|
/** One `git diff --numstat` row: added/deleted line counts + the path. */
|
|
325
325
|
export interface NumstatRow {
|