@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
|
@@ -63,8 +63,26 @@
|
|
|
63
63
|
* means reusing `nextState`, which is a larger change than a measurement
|
|
64
64
|
* correction and would itself need re-measuring.
|
|
65
65
|
*
|
|
66
|
+
* · THE RETRY-CONDITIONED RE-REFUSAL SHARE, which every bullet above is
|
|
67
|
+
* silent about because until 2026-09-30 nothing produced it. It does NOT
|
|
68
|
+
* come from the corpus: it is read from the gate's own shadow records under
|
|
69
|
+
* `agents/runtime/state/turn-end-gate/*.shadow.json`, written live on an
|
|
70
|
+
* allow path by the instrument `turn-end-detector-demotion.md` registers as
|
|
71
|
+
* instrument 1. Reported per LAYER and then per detector, never pooled, and
|
|
72
|
+
* never as `0.0%` where it has no denominator — see `renderQ1`.
|
|
73
|
+
* · It does NOT print that contract's **Q1**, and the distinction is in the
|
|
74
|
+
* report's own header rather than only here. Q1 conditions BOTH its halves
|
|
75
|
+
* on the detector; the shadow record cannot, because it never stores which
|
|
76
|
+
* refusal produced a retry. The two disagree in direction and neither
|
|
77
|
+
* bounds the other, so no number this prints may be read against a bar.
|
|
78
|
+
* · It does not report promissory, completion or untested at all. Those three
|
|
79
|
+
* are skipped by the gate when a dispatch is open and the shadow record
|
|
80
|
+
* carries no dispatch flag, so their denominators would absorb silences
|
|
81
|
+
* nobody observed. The contract's attribution clause already forbids it.
|
|
82
|
+
*
|
|
66
83
|
* Usage:
|
|
67
84
|
* ./scripts-run src/scripts/measure_turn_end_gate --store <dir> [--limit N] [--show-fires]
|
|
85
|
+
* ./scripts-run src/scripts/measure_turn_end_gate --q1 [--workspace <dir>]
|
|
68
86
|
*/
|
|
69
87
|
import * as fs from 'node:fs';
|
|
70
88
|
import * as path from 'node:path';
|
|
@@ -82,6 +100,14 @@ import {
|
|
|
82
100
|
extractToolCalls,
|
|
83
101
|
type ToolCall,
|
|
84
102
|
} from './hooks/turn_end_gate_hook.js';
|
|
103
|
+
import {
|
|
104
|
+
DETECTOR_IDS,
|
|
105
|
+
DISPATCH_CENSORED_DETECTORS,
|
|
106
|
+
SHADOW_LAYERS,
|
|
107
|
+
collectShadowStats,
|
|
108
|
+
retryConditionedShare,
|
|
109
|
+
type ShadowStats,
|
|
110
|
+
} from './_lib/turn_end_refusals.js';
|
|
85
111
|
|
|
86
112
|
interface Counts {
|
|
87
113
|
/**
|
|
@@ -495,16 +521,169 @@ export function render(c: Counts): string {
|
|
|
495
521
|
].join('\n');
|
|
496
522
|
}
|
|
497
523
|
|
|
524
|
+
/** `n` with a unit that agrees with it. One place, so no line has to remember. */
|
|
525
|
+
function plural(n: number, one: string, many = `${one}s`): string {
|
|
526
|
+
return `${String(n)} ${n === 1 ? one : many}`;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
/**
|
|
530
|
+
* The retry-conditioned re-refusal share, read from the shadow records rather
|
|
531
|
+
* than from a transcript. `road-to-a-stop-that-holds` step 2.2; the producer is
|
|
532
|
+
* step 2.1.
|
|
533
|
+
*
|
|
534
|
+
* ```
|
|
535
|
+
* THIS IS NOT THE Q1 `turn-end-detector-demotion.md` REGISTERS BARS AGAINST,
|
|
536
|
+
* AND THE REPORT SAYS SO IN ITS OWN HEADER.
|
|
537
|
+
* ```
|
|
538
|
+
*
|
|
539
|
+
* The first version of this renderer called the number Q1 outright. An
|
|
540
|
+
* independent review (2026-10-01) showed the two are different quantities that
|
|
541
|
+
* disagree in direction, not one quantity with a looser denominator — see
|
|
542
|
+
* `retryConditionedShare` for the worked ten-retry example. The rename and this
|
|
543
|
+
* header are that finding, acted on rather than noted.
|
|
544
|
+
*
|
|
545
|
+
* A DIFFERENT SOURCE FROM EVERY OTHER NUMBER THIS SCRIPT PRINTS, which is why
|
|
546
|
+
* it is a separate renderer rather than another line in `render`. The fire
|
|
547
|
+
* rates above are replayed out of a transcript corpus; this comes out of
|
|
548
|
+
* `agents/runtime/state/turn-end-gate/*.shadow.json`, written live by the gate
|
|
549
|
+
* on an allow path. The two cannot be joined — a shadow record carries no
|
|
550
|
+
* transcript and a transcript carries no shadow record — so printing them from
|
|
551
|
+
* one `Counts` object would invite exactly the cross-instrument arithmetic R2
|
|
552
|
+
* finding 7 removed from the language totals.
|
|
553
|
+
*
|
|
554
|
+
* NULL IS PRINTED AS `—`, NEVER AS `0.0%`. The two mean opposite things and
|
|
555
|
+
* `retryConditionedShare` keeps them apart for that reason; collapsing them at
|
|
556
|
+
* the render layer would undo the distinction one line before a human reads it.
|
|
557
|
+
*
|
|
558
|
+
* THE RESOLVED WORKSPACE IS PRINTED, because the one failure mode here is quiet:
|
|
559
|
+
* `--workspace` takes any path, a worktree carries no `agents/runtime/`, and the
|
|
560
|
+
* report for a wrong directory is a confident "no shadow record". A reading
|
|
561
|
+
* pasted into an evidence file must carry the directory that produced it.
|
|
562
|
+
*/
|
|
563
|
+
export function renderQ1(stats: ShadowStats, today: string, workspace?: string): string {
|
|
564
|
+
const lines: string[] = [
|
|
565
|
+
`measure-turn-end-gate · retry-conditioned re-refusal share · ${plural(stats.files, 'shadow record')} · read ${today}`,
|
|
566
|
+
' NOT the Q1 `turn-end-detector-demotion.md` registers bars against — see',
|
|
567
|
+
' the note below the table before comparing any number here to a bar.',
|
|
568
|
+
];
|
|
569
|
+
if (workspace !== undefined) {
|
|
570
|
+
lines.push(` workspace: ${path.resolve(workspace)}`);
|
|
571
|
+
}
|
|
572
|
+
lines.push('');
|
|
573
|
+
if (stats.files === 0) {
|
|
574
|
+
lines.push(
|
|
575
|
+
' No readable shadow record under this workspace. The share has no',
|
|
576
|
+
' denominator and is not reported as zero — a gate that has never been',
|
|
577
|
+
' retried is not a gate whose retries all came back clean.',
|
|
578
|
+
);
|
|
579
|
+
if (stats.unreadable > 0) {
|
|
580
|
+
lines.push(
|
|
581
|
+
'',
|
|
582
|
+
` ${plural(stats.unreadable, 'shadow file')} present but UNREADABLE, so "none" above`,
|
|
583
|
+
' means none could be parsed rather than none exists. That is a defect to',
|
|
584
|
+
' investigate, not an empty sample.',
|
|
585
|
+
);
|
|
586
|
+
}
|
|
587
|
+
return lines.join('\n');
|
|
588
|
+
}
|
|
589
|
+
for (const layer of SHADOW_LAYERS) {
|
|
590
|
+
const bucket = stats.byLayer.find((b) => b.layer === layer);
|
|
591
|
+
if (bucket === undefined) continue;
|
|
592
|
+
lines.push(
|
|
593
|
+
` layer ${layer} — ${plural(bucket.retries, 'retry', 'retries')} observed, ${plural(bucket.rows, 'shadow row')}`,
|
|
594
|
+
);
|
|
595
|
+
if (bucket.retries === 0) {
|
|
596
|
+
lines.push(' (no retry on this layer; every share below would have no denominator)');
|
|
597
|
+
}
|
|
598
|
+
for (const id of DETECTOR_IDS) {
|
|
599
|
+
if (DISPATCH_CENSORED_DETECTORS.has(id)) {
|
|
600
|
+
lines.push(` ${id.padEnd(17)} censored (dispatch-suppressed retries are indistinguishable)`);
|
|
601
|
+
continue;
|
|
602
|
+
}
|
|
603
|
+
const share = retryConditionedShare(stats, layer, id);
|
|
604
|
+
// A dash denies a measurement; a count beside it reads like one. The
|
|
605
|
+
// `(0 / 0)` the first version printed there was the denial and the
|
|
606
|
+
// measurement on the same line.
|
|
607
|
+
if (share === null) {
|
|
608
|
+
lines.push(` ${id.padEnd(17)} —`);
|
|
609
|
+
continue;
|
|
610
|
+
}
|
|
611
|
+
const shown = `${(100 * share).toFixed(1)}%`.padStart(6);
|
|
612
|
+
lines.push(` ${id.padEnd(17)} ${shown} (${String(bucket.byDetector[id])} / ${String(bucket.retries)})`);
|
|
613
|
+
}
|
|
614
|
+
lines.push('');
|
|
615
|
+
}
|
|
616
|
+
lines.push(
|
|
617
|
+
' WHAT THIS IS, precisely, because the contract defines a DIFFERENT number',
|
|
618
|
+
' under a similar name. Printed here: of the retries observed on a layer,',
|
|
619
|
+
" the share a detector would have refused. The contract's Q1: of a",
|
|
620
|
+
" DETECTOR'S OWN initial refusals, the share whose retry that same detector",
|
|
621
|
+
' refuses again. Both halves of the contract definition are conditioned on',
|
|
622
|
+
' the detector; neither half here is, because `ShadowRecord` does not record',
|
|
623
|
+
' which refusal produced a retry. The two disagree in direction and neither',
|
|
624
|
+
' bounds the other, so no number above may be read against a bar in',
|
|
625
|
+
" `turn-end-detector-demotion.md` § The bars. Closing that needs the",
|
|
626
|
+
' PRODUCER to record the originating detector.',
|
|
627
|
+
'',
|
|
628
|
+
' THREE DETECTORS ARE CENSORED, and the contract requires it rather than',
|
|
629
|
+
' this renderer choosing it. `runDetectors` skips promissory, completion and',
|
|
630
|
+
" untested when a dispatch is open, and the shadow record carries no dispatch",
|
|
631
|
+
' flag — so those retries would enter their denominators as observations of',
|
|
632
|
+
' silence that nobody made. The attribution clause already forbids reporting',
|
|
633
|
+
' a detector a rollup cannot separate that way.',
|
|
634
|
+
'',
|
|
635
|
+
' GROUPED BY LAYER FIRST, and the grouping is load-bearing rather than',
|
|
636
|
+
' cosmetic. A `stop_hook_active` retry follows ANY stop concern\'s block, not',
|
|
637
|
+
' only this gate\'s, so a pooled share divides another concern\'s retries into',
|
|
638
|
+
' this gate\'s refusals. `retries_observed` is keyed by layer so the',
|
|
639
|
+
' denominator splits with the numerator.',
|
|
640
|
+
'',
|
|
641
|
+
' TWO FURTHER BOUNDS ON EVERY NUMBER ABOVE, both properties of the instrument:',
|
|
642
|
+
' 1. A retry whose transcript is absent, oversized or textless records',
|
|
643
|
+
' NOTHING — no row and no retry. Numerator and denominator shrink',
|
|
644
|
+
' together, so each share is an UPPER bound, never a point estimate.',
|
|
645
|
+
' 2. On a host that sends no `session_id` every session shares one record.',
|
|
646
|
+
' The record count above is FILES; it equals sessions only where the',
|
|
647
|
+
' host sends an id.',
|
|
648
|
+
'',
|
|
649
|
+
' A share above may be well-formed and still unreadable as a rate if the',
|
|
650
|
+
' record count is small. The count is printed first for that reason.',
|
|
651
|
+
);
|
|
652
|
+
if (stats.dropped > 0) {
|
|
653
|
+
lines.push(
|
|
654
|
+
'',
|
|
655
|
+
` ${plural(stats.dropped, 'row')} dropped to the per-session cap: every numerator above is a FLOOR.`,
|
|
656
|
+
);
|
|
657
|
+
}
|
|
658
|
+
if (stats.unreadable > 0) {
|
|
659
|
+
lines.push(
|
|
660
|
+
'',
|
|
661
|
+
` ${plural(stats.unreadable, 'shadow file')} present but unreadable — same reading, same direction.`,
|
|
662
|
+
);
|
|
663
|
+
}
|
|
664
|
+
if (stats.earliest !== null && stats.latest !== null) {
|
|
665
|
+
lines.push('', ` Window observed: ${stats.earliest} … ${stats.latest}`);
|
|
666
|
+
}
|
|
667
|
+
return lines.join('\n');
|
|
668
|
+
}
|
|
669
|
+
|
|
498
670
|
export function main(argv: string[] = process.argv.slice(2)): number {
|
|
499
671
|
let store = '';
|
|
500
672
|
let limit = 30;
|
|
501
673
|
let showFires = false;
|
|
674
|
+
let q1Only = false;
|
|
675
|
+
let workspace = process.cwd();
|
|
502
676
|
for (let i = 0; i < argv.length; i += 1) {
|
|
503
677
|
if (argv[i] === '--store' && argv[i + 1] !== undefined) {
|
|
504
678
|
store = argv[i + 1]!;
|
|
505
679
|
i += 1;
|
|
506
680
|
} else if (argv[i] === '--show-fires') {
|
|
507
681
|
showFires = true;
|
|
682
|
+
} else if (argv[i] === '--q1') {
|
|
683
|
+
q1Only = true;
|
|
684
|
+
} else if (argv[i] === '--workspace' && argv[i + 1] !== undefined) {
|
|
685
|
+
workspace = argv[i + 1]!;
|
|
686
|
+
i += 1;
|
|
508
687
|
} else if (argv[i] === '--limit' && argv[i + 1] !== undefined) {
|
|
509
688
|
// R2 finding 15: an unvalidated parseInt made `--limit abc` yield
|
|
510
689
|
// NaN, `slice(0, NaN)` return nothing, and the script exit 2 with
|
|
@@ -521,6 +700,16 @@ export function main(argv: string[] = process.argv.slice(2)): number {
|
|
|
521
700
|
i += 1;
|
|
522
701
|
}
|
|
523
702
|
}
|
|
703
|
+
const today = new Date().toISOString().slice(0, 10);
|
|
704
|
+
// `--q1` needs no transcript corpus: the shadow records are the source, and
|
|
705
|
+
// requiring a `--store` for them would make the one reading this roadmap
|
|
706
|
+
// asks for contingent on an unrelated input. Deliberately NOT a silent
|
|
707
|
+
// default of the store path — a reading over the wrong workspace is the
|
|
708
|
+
// failure mode here, and it is quiet.
|
|
709
|
+
if (q1Only) {
|
|
710
|
+
process.stdout.write(`${renderQ1(collectShadowStats(workspace), today, workspace)}\n`);
|
|
711
|
+
return 0;
|
|
712
|
+
}
|
|
524
713
|
if (!store) {
|
|
525
714
|
process.stderr.write('measure-turn-end-gate: --store <transcript dir> is required\n');
|
|
526
715
|
return 2;
|
|
@@ -533,6 +722,10 @@ export function main(argv: string[] = process.argv.slice(2)): number {
|
|
|
533
722
|
return 2;
|
|
534
723
|
}
|
|
535
724
|
process.stdout.write(`${render(counts)}\n`);
|
|
725
|
+
// Q1 rides on the default report because step 2.2 asks that
|
|
726
|
+
// `measure_turn_end_gate` PRINT it, not that it offer to. A reader who
|
|
727
|
+
// never learns the flag exists still sees the number.
|
|
728
|
+
process.stdout.write(`\n${renderQ1(collectShadowStats(workspace), today, workspace)}\n`);
|
|
536
729
|
if (showFires) {
|
|
537
730
|
process.stdout.write(`\n detector F fired here — read these turns before\n calling any of them a false positive:\n${renderFires(counts)}\n`);
|
|
538
731
|
process.stdout.write(`\n detector E fired here — same reading, same reason:\n${renderDroppedFires(counts)}\n`);
|
|
@@ -35,7 +35,7 @@ import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
|
35
35
|
import { createRequire } from 'node:module';
|
|
36
36
|
import YAML, { parseDocument } from 'yaml';
|
|
37
37
|
|
|
38
|
-
import { sanitize_entry } from './_lib/retrieval_sanitize.js';
|
|
38
|
+
import { sanitize_entry } from './_lib/retrieval_sanitize.js'; // read-surface: ingested-corpus
|
|
39
39
|
import { LexicalIndex, tokenize as _lexTokenize } from './_lib/lexical_index.js';
|
|
40
40
|
import {
|
|
41
41
|
ensureIndex as _ftsEnsureIndex,
|
|
@@ -48,6 +48,13 @@ function titleOf(slug: string): string {
|
|
|
48
48
|
return slug.replace(/-/g, ' ');
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
+
// The two heading markers the release-holds block emits, interpolated rather
|
|
52
|
+
// than written literally: `lint_code_comments` strips indentation before
|
|
53
|
+
// matching, so a template-literal line beginning `## ` reads to it as a
|
|
54
|
+
// markdown heading left in source. The emitted text is unchanged.
|
|
55
|
+
const H2 = '#'.repeat(2) + ' ';
|
|
56
|
+
const H3 = '#'.repeat(3) + ' ';
|
|
57
|
+
|
|
51
58
|
export function skeleton(slug: string, complexity: 'lightweight' | 'structural', date: string): string {
|
|
52
59
|
return `---
|
|
53
60
|
complexity: ${complexity}
|
|
@@ -73,6 +80,36 @@ could tell whether it happened.
|
|
|
73
80
|
verify: the check that proves it — a command, a test, an observable
|
|
74
81
|
state. Never "looks right".
|
|
75
82
|
|
|
83
|
+
<!-- Release holds — emitted commented out, because the default is that there is
|
|
84
|
+
not one. Uncomment ONLY if an intermediate tree state of this roadmap must
|
|
85
|
+
not be published. Template rule 28 is the contract; the authoring order is
|
|
86
|
+
re-sequence -> guard -> hold, and a hold is the last resort, never the
|
|
87
|
+
first tool.
|
|
88
|
+
|
|
89
|
+
Record the outcome either way. A roadmap that considered a hold and reached
|
|
90
|
+
rung 1 or 2 instead writes the one-line \`resequenced:\` / \`guarded:\` note
|
|
91
|
+
below and deletes the entry; that note is a counted outcome, not a comment.
|
|
92
|
+
|
|
93
|
+
resequenced: <one line — the broken intermediate state, and the phase cut
|
|
94
|
+
that removed it, so no window was ever needed.>
|
|
95
|
+
|
|
96
|
+
${H2}Release holds
|
|
97
|
+
|
|
98
|
+
${H3}hold: <kebab-id>
|
|
99
|
+
- **Channel:** all (all | latest; omitted parses to all)
|
|
100
|
+
- **Opened by:** <phase.step> (the checkbox whose [x] opens the window)
|
|
101
|
+
- **Cleared by:** <phase.step> (the checkbox whose [x] closes it)
|
|
102
|
+
- **State:** <one sentence naming what is broken in the tree while open.>
|
|
103
|
+
- **Why not a guard:** <why the guard rung failed, concretely. Mandatory —
|
|
104
|
+
an entry without it is malformed and reddens CI.>
|
|
105
|
+
|
|
106
|
+
Both named steps carry an inline HTML-comment marker on the checkbox line
|
|
107
|
+
itself — \`opens-hold: <kebab-id>\` on the opener, \`clears-hold: <kebab-id>\`
|
|
108
|
+
on the clearer — so the binding is readable from the checkbox and not only
|
|
109
|
+
from this section. The clearing step MUST carry a \`verify:\` field: a hold
|
|
110
|
+
cleared by an unverified flip is a hold cleared by assertion.
|
|
111
|
+
-->
|
|
112
|
+
|
|
76
113
|
## Risk Register
|
|
77
114
|
<!-- risk-review: v1 | reviewed: ${date} | reviewer: claude/host -->
|
|
78
115
|
|
|
@@ -18,7 +18,6 @@
|
|
|
18
18
|
* [--rules-carried 32] [--rules-used 5] \
|
|
19
19
|
* [--work-tokens 41000] [--floor-provenance measured|estimated] \
|
|
20
20
|
* [--capsule-emitted true|false] [--capsule-entries 9] \
|
|
21
|
-
* [--watermark-step 8] [--saturation-step 4] [--trigger-arm-earlier watermark|saturation|tie] \
|
|
22
21
|
* [--dir <audit-dir>] [--dry-run]
|
|
23
22
|
*
|
|
24
23
|
* Read by `src/scripts/orchestration_savings_report.ts`.
|
|
@@ -42,7 +41,6 @@ import {
|
|
|
42
41
|
type LineOutcome,
|
|
43
42
|
type RecordInput,
|
|
44
43
|
type RouteTaken,
|
|
45
|
-
type TriggerArm,
|
|
46
44
|
} from './_lib/orchestration_record.js';
|
|
47
45
|
|
|
48
46
|
// Exported so other writers of the same audit-log-v1 orchestration line
|
|
@@ -174,9 +172,6 @@ export function main(argv: string[] = process.argv.slice(2)): number {
|
|
|
174
172
|
floor_provenance: str(flags, 'floor-provenance') as Provenance | undefined,
|
|
175
173
|
capsule_emitted: bool(flags, 'capsule-emitted'),
|
|
176
174
|
capsule_entries: int(flags, 'capsule-entries'),
|
|
177
|
-
watermark_step: int(flags, 'watermark-step'),
|
|
178
|
-
saturation_step: int(flags, 'saturation-step'),
|
|
179
|
-
trigger_arm_earlier: str(flags, 'trigger-arm-earlier') as TriggerArm | undefined,
|
|
180
175
|
phase: str(flags, 'phase') as LinePhase | undefined,
|
|
181
176
|
outcome: str(flags, 'outcome') as LineOutcome | undefined,
|
|
182
177
|
confidence_band: str(flags, 'confidence-band') as Band | undefined,
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
* Skip with PREPACK_SKIP_BUILD_CHECK=1 only for local `npm pack` dry-runs
|
|
24
24
|
* that intentionally test the failure mode.
|
|
25
25
|
*/
|
|
26
|
+
import { createHash } from 'node:crypto';
|
|
26
27
|
import { readFileSync, statSync } from 'node:fs';
|
|
27
28
|
import { resolve } from 'node:path';
|
|
28
29
|
import { argv, env, exit } from 'node:process';
|
|
@@ -66,6 +67,58 @@ if (head !== SHEBANG) {
|
|
|
66
67
|
|
|
67
68
|
process.stderr.write(`prepack-check: ${BIN} OK\n`);
|
|
68
69
|
|
|
70
|
+
// ---------------------------------------------------------------------------
|
|
71
|
+
// Bundle-digest sidecar: `dist/hooks/dispatch.js` must ship with the
|
|
72
|
+
// `dist/hooks/dispatch.sha256` its build wrote, and the digest must still
|
|
73
|
+
// describe the bundle beside it.
|
|
74
|
+
//
|
|
75
|
+
// Risk 3 of road-to-a-kernel-that-guards-its-plumbing: the runtime integrity
|
|
76
|
+
// check treats a MISSING sidecar as `unverifiable` and allows, deliberately,
|
|
77
|
+
// so that a consumer install predating the sidecar is not wedged. That safety
|
|
78
|
+
// property has a cost — a bundle shipped without its sidecar silently disables
|
|
79
|
+
// the check for every consumer who installs it, and nothing at runtime can
|
|
80
|
+
// tell that apart from the legitimate old-package case. The place to catch it
|
|
81
|
+
// is here, in the one step that knows a bundle is being packaged NOW and
|
|
82
|
+
// therefore had no excuse for the sidecar's absence.
|
|
83
|
+
//
|
|
84
|
+
// A stale digest is treated exactly like a missing one: both mean the two
|
|
85
|
+
// files were not produced by the same `npm run build:hooks`.
|
|
86
|
+
const HOOK_BUNDLE = resolve('dist/hooks/dispatch.js');
|
|
87
|
+
const HOOK_SIDECAR = resolve('dist/hooks/dispatch.sha256');
|
|
88
|
+
let hookBundleBytes = null;
|
|
89
|
+
try {
|
|
90
|
+
hookBundleBytes = readFileSync(HOOK_BUNDLE);
|
|
91
|
+
} catch {
|
|
92
|
+
// No hook bundle in this tree at all — `npm run build` builds it, and gate
|
|
93
|
+
// 1 above has already failed if the build did not run. Nothing to check.
|
|
94
|
+
}
|
|
95
|
+
if (hookBundleBytes !== null) {
|
|
96
|
+
let sidecarText;
|
|
97
|
+
try {
|
|
98
|
+
sidecarText = readFileSync(HOOK_SIDECAR, 'utf8');
|
|
99
|
+
} catch {
|
|
100
|
+
die(
|
|
101
|
+
`dist/hooks/dispatch.js ships without dist/hooks/dispatch.sha256. The runtime ` +
|
|
102
|
+
`integrity check reads a missing sidecar as "unverifiable" and ALLOWS, so ` +
|
|
103
|
+
`publishing this tarball would silently disable it for every consumer. Run ` +
|
|
104
|
+
`\`npm run build:hooks\`, which writes both.`,
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
const claimed = /^([0-9a-f]{64})\s/u.exec(sidecarText.trim())?.[1] ?? null;
|
|
108
|
+
if (claimed === null) {
|
|
109
|
+
die(`dist/hooks/dispatch.sha256 is malformed — expected "<64 hex> dispatch.js".`);
|
|
110
|
+
}
|
|
111
|
+
const actual = createHash('sha256').update(hookBundleBytes).digest('hex');
|
|
112
|
+
if (actual !== claimed) {
|
|
113
|
+
die(
|
|
114
|
+
`dist/hooks/dispatch.sha256 does not describe dist/hooks/dispatch.js ` +
|
|
115
|
+
`(sidecar ${claimed.slice(0, 12)}…, bundle ${actual.slice(0, 12)}…). The two were ` +
|
|
116
|
+
`not produced by the same build. Run \`npm run build:hooks\`.`,
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
process.stderr.write(`prepack-check: dist/hooks/dispatch.sha256 OK (${actual.slice(0, 12)}…)\n`);
|
|
120
|
+
}
|
|
121
|
+
|
|
69
122
|
// ---------------------------------------------------------------------------
|
|
70
123
|
// Import-completeness guard: every relative import reachable from the
|
|
71
124
|
// SHIPPED src/ trees must itself resolve to a shipped file. Catches the
|
package/src/scripts/release.ts
CHANGED
|
@@ -122,9 +122,7 @@ import {
|
|
|
122
122
|
import {
|
|
123
123
|
HEAD_LABELS,
|
|
124
124
|
type MixObligation,
|
|
125
|
-
|
|
126
|
-
derive_category_hits,
|
|
127
|
-
render_derived_head_values,
|
|
125
|
+
derive_head_prefill,
|
|
128
126
|
} from './_lib/release_highlights.js';
|
|
129
127
|
import { canPrompt, promptLine } from './_lib/tty_prompt.js';
|
|
130
128
|
import { preflightPosition } from './_lib/release_position.js';
|
|
@@ -137,6 +135,11 @@ import {
|
|
|
137
135
|
release_notes_from_section,
|
|
138
136
|
render_mix_response,
|
|
139
137
|
} from './_lib/release_material.js';
|
|
138
|
+
import {
|
|
139
|
+
assert_major_migration_section,
|
|
140
|
+
assert_scheduled_deprecations_clear,
|
|
141
|
+
} from './_lib/release_migration_gate.js';
|
|
142
|
+
import { releaseHoldPreflight } from './_lib/release_holds.js';
|
|
140
143
|
|
|
141
144
|
// `__doc__.splitlines()[0]` in `_parse_args` — the argparse description. Kept
|
|
142
145
|
// as a referenceable constant so the first docstring line is preserved exactly.
|
|
@@ -144,7 +147,6 @@ const MODULE_DOC_FIRST_LINE = 'End-to-end release automation for `event4u/agent-
|
|
|
144
147
|
|
|
145
148
|
const _HERE = fileURLToPath(import.meta.url);
|
|
146
149
|
|
|
147
|
-
|
|
148
150
|
import {
|
|
149
151
|
ArgparseExit,
|
|
150
152
|
AUGMENT_MARKETPLACE_JSON,
|
|
@@ -169,7 +171,6 @@ import {
|
|
|
169
171
|
_rstrip,
|
|
170
172
|
_splitlines,
|
|
171
173
|
} from './release_env.js';
|
|
172
|
-
import type { RunResult } from './release_publication.js';
|
|
173
174
|
// Re-export surface for the names tests import from `release.js` and that moved
|
|
174
175
|
// into the publication unit — eleven since the test-count-trend unit followed. `export ... from` rather than a bare import,
|
|
175
176
|
// because these are not USED here — an unused import would be dropped and the
|
|
@@ -226,7 +227,6 @@ import {
|
|
|
226
227
|
// existing block resolve. This is the whole of step 1.1's "re-export shape that
|
|
227
228
|
// keeps callers unaffected": no caller and no test import path changes.
|
|
228
229
|
|
|
229
|
-
|
|
230
230
|
// ---------------------------------------------------------------------------
|
|
231
231
|
// Parity helpers — code-point length, comma grouping, regex escape, JSON
|
|
232
232
|
// ---------------------------------------------------------------------------
|
|
@@ -304,8 +304,7 @@ export { RELEASE_HEAD_CAP_LINES } from './_lib/release_material.js';
|
|
|
304
304
|
*/
|
|
305
305
|
function _derive_head_prefill(prev: string | null): Record<string, string> {
|
|
306
306
|
try {
|
|
307
|
-
|
|
308
|
-
return render_derived_head_values(derive_category_hits(span));
|
|
307
|
+
return derive_head_prefill(prev, 'HEAD', REPO_ROOT);
|
|
309
308
|
} catch (err) {
|
|
310
309
|
process.stderr.write(
|
|
311
310
|
`warning: could not derive release-head highlights (${(err as Error).message}); ` +
|
|
@@ -698,93 +697,6 @@ function set_template_pin(p: string, version: string): void {
|
|
|
698
697
|
fs.writeFileSync(p, lines.join('\n'), 'utf-8');
|
|
699
698
|
}
|
|
700
699
|
|
|
701
|
-
/**
|
|
702
|
-
* Refuse a MAJOR cut that carries a scheduled deprecation due at or before it.
|
|
703
|
-
*
|
|
704
|
-
* **The trigger is the shape of the TARGET, not a comparison with the current
|
|
705
|
-
* version.** A major target is `X.0.0` — and that one predicate covers every
|
|
706
|
-
* path to a major: the `--as major` flag, an explicit `--version 13.0.0`,
|
|
707
|
-
* auto-detection from a `feat!:` commit, AND `--resume`, where
|
|
708
|
-
* `_detect_in_flight_target()` returns the already-bumped `package.json`
|
|
709
|
-
* version so `target === current` and any current-vs-target comparison
|
|
710
|
-
* silently returns. Resume was the fourth path an earlier version of this
|
|
711
|
-
* guard missed while its own comment claimed three paths converged.
|
|
712
|
-
*
|
|
713
|
-
* Refusing a resumed release can strand a partially-completed one, and that is
|
|
714
|
-
* the deliberate trade: a stranded release is recoverable by fixing the table
|
|
715
|
-
* and resuming again, whereas a major shipped over a missed commitment is the
|
|
716
|
-
* failure this whole surface exists to prevent.
|
|
717
|
-
*
|
|
718
|
-
* The target version is PASSED to the gate. Without it the gate falls back to
|
|
719
|
-
* `package.json`, which at the cut to N still reads N-1 — so a row committed
|
|
720
|
-
* to N reads as one major early and passes, and only rows already a major late
|
|
721
|
-
* could ever be refused. That is the lateness being prevented, so measuring
|
|
722
|
-
* against the shipped version would have made the refusal fire exactly one
|
|
723
|
-
* major too late, forever.
|
|
724
|
-
*
|
|
725
|
-
* Runs under `--dry-run` too, unlike the rest of preflight: this check is one
|
|
726
|
-
* subprocess reading two files, so the "keep a preview fast" rationale that
|
|
727
|
-
* excludes the ~15s test-trend collection does not apply — and a preview that
|
|
728
|
-
* reports green for the single condition that will refuse the real run is the
|
|
729
|
-
* case an operator runs a preview to discover. It REPORTS there rather than
|
|
730
|
-
* dying: `--dry-run` exiting 0 before `execute()` and before `preflight()` is a
|
|
731
|
-
* contract this file's own tests assert, and an earlier revision of this guard
|
|
732
|
-
* broke it by sitting above the dry-run branch with no preview mode.
|
|
733
|
-
*
|
|
734
|
-
* @param runner Seam for the gate invocation. Production passes nothing and
|
|
735
|
-
* gets the real `run`; tests inject a stub, because the alternative — reaching
|
|
736
|
-
* this branch only by mutating `docs/MIGRATION.md` — would make the refusal
|
|
737
|
-
* path testable exclusively through a tracked-file edit.
|
|
738
|
-
*/
|
|
739
|
-
export function assert_scheduled_deprecations_clear(
|
|
740
|
-
target: string,
|
|
741
|
-
runner: (args: readonly string[]) => RunResult = (args) => run(args, { check: false, capture: true }),
|
|
742
|
-
opts: { previewOnly?: boolean } = {},
|
|
743
|
-
): void {
|
|
744
|
-
const [, minor, patch] = parse_version(target);
|
|
745
|
-
if (minor !== 0 || patch !== 0) {
|
|
746
|
-
return;
|
|
747
|
-
}
|
|
748
|
-
const res = runner([
|
|
749
|
-
'./scripts-run',
|
|
750
|
-
'src/scripts/lint_scheduled_deprecations',
|
|
751
|
-
'--cutting',
|
|
752
|
-
target,
|
|
753
|
-
]);
|
|
754
|
-
if (res.returncode === 0) {
|
|
755
|
-
return;
|
|
756
|
-
}
|
|
757
|
-
process.stderr.write(res.stdout);
|
|
758
|
-
process.stderr.write(res.stderr);
|
|
759
|
-
if (res.returncode !== 1) {
|
|
760
|
-
// The gate reserves 1 for a finding and 2 for a usage/environment
|
|
761
|
-
// failure. Diagnosing the latter as "the table has an overdue row"
|
|
762
|
-
// sends the releaser to edit a file that is not the problem.
|
|
763
|
-
die(
|
|
764
|
-
`refusing the ${target} cut: the scheduled-deprecations check could not run ` +
|
|
765
|
-
`(exit ${String(res.returncode)}). That is an environment or usage failure, not a ` +
|
|
766
|
-
'finding in docs/MIGRATION.md — fix the invocation or the checkout, then re-run.',
|
|
767
|
-
);
|
|
768
|
-
}
|
|
769
|
-
if (opts.previewOnly === true) {
|
|
770
|
-
// The preview's job is to SHOW what the real run will refuse. Dying
|
|
771
|
-
// here would break the `--dry-run exits 0` contract asserted elsewhere
|
|
772
|
-
// in this file's tests — trading a documented exit code for a message
|
|
773
|
-
// that has already been printed above.
|
|
774
|
-
process.stderr.write(
|
|
775
|
-
`\n(dry-run) the ${target} cut WOULD BE REFUSED for the reason above. ` +
|
|
776
|
-
'Previewing only; exit code unchanged.\n',
|
|
777
|
-
);
|
|
778
|
-
return;
|
|
779
|
-
}
|
|
780
|
-
die(
|
|
781
|
-
`refusing the ${target} cut: the scheduled-deprecations table in docs/MIGRATION.md ` +
|
|
782
|
-
'has a row due at or before this major, or one that cannot be resolved. Act on ' +
|
|
783
|
-
"it — perform the removal in its own change, or revise the row's commitment and " +
|
|
784
|
-
'record why the surface stays — then re-run.',
|
|
785
|
-
);
|
|
786
|
-
}
|
|
787
|
-
|
|
788
700
|
// ─── preflight ────────────────────────────────────────────────────────────────
|
|
789
701
|
|
|
790
702
|
/**
|
|
@@ -878,6 +790,7 @@ function preflight(target: string, opts: { resume?: boolean; ci?: boolean } = {}
|
|
|
878
790
|
die(`tag '${target}' already exists; nothing to release`);
|
|
879
791
|
}
|
|
880
792
|
}
|
|
793
|
+
releaseHoldPreflight(REPO_ROOT, die);
|
|
881
794
|
}
|
|
882
795
|
|
|
883
796
|
// ─── plan ─────────────────────────────────────────────────────────────────────
|
|
@@ -1109,9 +1022,9 @@ function execute(
|
|
|
1109
1022
|
if (pr_merged) {
|
|
1110
1023
|
_step(4, total, 'PR already merged — skip push');
|
|
1111
1024
|
} else {
|
|
1112
|
-
//
|
|
1113
|
-
//
|
|
1114
|
-
//
|
|
1025
|
+
// push_release_branch reads the remote FIRST — it skips the push when
|
|
1026
|
+
// the remote is already at head (a no-op push still runs the pre-push
|
|
1027
|
+
// hook, which then refuses over pending CI) and merges one that moved.
|
|
1115
1028
|
// Not a `_step`: a second `[4/11]` makes the cited evidence anchors ambiguous.
|
|
1116
1029
|
process.stdout.write(' · verifying release gates locally (`task release:verify -- --cheap`)\n');
|
|
1117
1030
|
run(local_release_gate_argv());
|
|
@@ -1673,6 +1586,7 @@ function main(argv: readonly string[] | null = null): number {
|
|
|
1673
1586
|
head: _derive_head_prefill(prev),
|
|
1674
1587
|
mix: measure_mix_obligation(target, prev),
|
|
1675
1588
|
});
|
|
1589
|
+
assert_major_migration_section(target, full, { previewOnly: args.dry_run });
|
|
1676
1590
|
|
|
1677
1591
|
// Era-split planning — gate on the POST-release view (2026-07-07 fix).
|
|
1678
1592
|
// The drift test measures the era AFTER this release's section is
|
|
@@ -1777,6 +1691,8 @@ export {
|
|
|
1777
1691
|
bump_version,
|
|
1778
1692
|
commits_since,
|
|
1779
1693
|
infer_bump,
|
|
1694
|
+
assert_major_migration_section,
|
|
1695
|
+
assert_scheduled_deprecations_clear,
|
|
1780
1696
|
render_changelog_entry,
|
|
1781
1697
|
_changelog_line,
|
|
1782
1698
|
_cap_body,
|