@event4u/agent-config 16.2.0 → 16.3.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 +89 -237
- package/README.md +14 -12
- package/dist/agent-src/commands/analyze/inbox.md +1 -1
- package/dist/agent-src/commands/analyze/roadmap-repos.md +1 -1
- package/dist/agent-src/commands/bug/fix.md +17 -2
- package/dist/agent-src/commands/feature/plan.md +1 -1
- package/dist/agent-src/commands/feature/roadmap.md +1 -1
- package/dist/agent-src/commands/fix/ci.md +1 -1
- package/dist/agent-src/commands/implement-ticket.md +1 -1
- package/dist/agent-src/commands/jira-ticket.md +1 -1
- package/dist/agent-src/commands/roadmap/create.md +1 -1
- package/dist/agent-src/commands/roadmap/materialize.md +1 -1
- package/dist/agent-src/commands/roadmap/process-full.md +4 -4
- package/dist/agent-src/commands/roadmap/resolve-blockers.md +361 -0
- package/dist/agent-src/commands/roadmap/triage-parked.md +325 -0
- package/dist/agent-src/commands/roadmap.md +18 -4
- package/dist/agent-src/commands/tests/create.md +17 -3
- package/dist/agent-src/commands/tests/execute.md +22 -5
- package/dist/agent-src/contexts/authority/decision-revisit-gate-enforcement.md +43 -0
- package/dist/agent-src/contexts/communication/rules-auto/design-fidelity-enforcement.md +24 -0
- package/dist/agent-src/contexts/execution/auto-dispatch-classification.md +6 -6
- package/dist/agent-src/contexts/execution/roadmap-process-loop.md +32 -2
- package/dist/agent-src/contexts/execution/session-canary-enforcement-history.md +67 -0
- package/dist/agent-src/contexts/execution/toolchain-resolver.md +101 -7
- package/dist/agent-src/rules/active-remediation.md +1 -1
- package/dist/agent-src/rules/autonomous-execution.md +1 -0
- package/dist/agent-src/rules/broken-access-control.md +1 -0
- package/dist/agent-src/rules/command-suggestion-policy.md +1 -0
- package/dist/agent-src/rules/context-hygiene.md +1 -1
- package/dist/agent-src/rules/decision-revisit-gate.md +16 -33
- package/dist/agent-src/rules/design-fidelity.md +13 -16
- package/dist/agent-src/rules/doc-screenshot-hygiene.md +1 -0
- package/dist/agent-src/rules/domain-safety-disclaimer.md +1 -0
- package/dist/agent-src/rules/domain-safety-pii.md +1 -0
- package/dist/agent-src/rules/domain-safety-retention.md +1 -0
- package/dist/agent-src/rules/engineering-safety-floor.md +1 -0
- package/dist/agent-src/rules/evaluator-independence.md +3 -2
- package/dist/agent-src/rules/fast-path-marker-visibility.md +1 -0
- package/dist/agent-src/rules/finance-safety-floor.md +1 -0
- package/dist/agent-src/rules/git-history-discipline.md +1 -0
- package/dist/agent-src/rules/image-likeness-and-rights.md +1 -0
- package/dist/agent-src/rules/legal-safety-floor.md +3 -2
- package/dist/agent-src/rules/lethal-trifecta-guard.md +1 -0
- package/dist/agent-src/rules/low-impact-corpus-privacy-floor.md +1 -0
- package/dist/agent-src/rules/media-governance-routing.md +14 -17
- package/dist/agent-src/rules/persona-governance.md +2 -2
- package/dist/agent-src/rules/provider-lifecycle-discipline.md +1 -1
- package/dist/agent-src/rules/question-not-instruction.md +1 -0
- package/dist/agent-src/rules/roadmap-progress-sync.md +1 -1
- package/dist/agent-src/rules/runtime-safety.md +1 -0
- package/dist/agent-src/rules/secret-vcs-guard.md +1 -0
- package/dist/agent-src/rules/security-sensitive-stop.md +3 -2
- package/dist/agent-src/rules/session-canary.md +8 -62
- package/dist/agent-src/rules/settings-ask-protocol.md +1 -0
- package/dist/agent-src/rules/source-confidentiality.md +1 -0
- package/dist/agent-src/rules/strategy-safety-floor.md +1 -0
- package/dist/agent-src/rules/tool-safety.md +1 -0
- package/dist/agent-src/rules/untrusted-input-defense.md +1 -0
- package/dist/agent-src/rules/user-interrupt-priority.md +1 -0
- package/dist/agent-src/scripts/archive_completed_roadmaps.ts +115 -20
- package/dist/agent-src/scripts/deferral_carry.ts +339 -0
- package/dist/agent-src/scripts/update_roadmap_progress.ts +4 -1
- package/dist/agent-src/skills/api-design/data/manifest.json +2 -2
- package/dist/agent-src/skills/api-testing/SKILL.md +17 -0
- package/dist/agent-src/skills/code-intelligence/SKILL.md +14 -2
- package/dist/agent-src/skills/design-system-capture/references/import-procedure.md +1 -1
- package/dist/agent-src/skills/existing-ui-audit/SKILL.md +2 -2
- package/dist/agent-src/skills/fe-design/SKILL.md +1 -1
- package/dist/agent-src/skills/iconography/SKILL.md +1 -1
- package/dist/agent-src/skills/js-library-packaging/SKILL.md +2 -2
- package/dist/agent-src/skills/monorepo-workspace/SKILL.md +1 -1
- package/dist/agent-src/skills/quality-tools/SKILL.md +11 -1
- package/dist/agent-src/skills/quality-tools/references/go-tools.md +76 -0
- package/dist/agent-src/skills/quality-tools/references/python-tools.md +104 -0
- package/dist/agent-src/skills/review-routing/SKILL.md +2 -2
- package/dist/agent-src/skills/skill-improvement-pipeline/SKILL.md +1 -1
- package/dist/agent-src/skills/storybook-workshop/SKILL.md +3 -3
- package/dist/agent-src/skills/tailwind-engineer/SKILL.md +1 -1
- package/dist/agent-src/skills/test-case-discovery/SKILL.md +7 -0
- package/dist/agent-src/skills/test-driven-development/SKILL.md +17 -0
- package/dist/agent-src/skills/test-performance/SKILL.md +19 -1
- package/dist/agent-src/skills/ui-component-architect/SKILL.md +2 -2
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +48 -6
- package/dist/agent-src/templates/scripts/work_engine/stack/runner.ts +774 -109
- package/dist/cli/registry.js +1 -1
- package/dist/cli-delegate/archive_completed_roadmaps.js +92 -12
- package/dist/cli-delegate/check_update_banner.js +12 -1
- package/dist/cli-delegate/chunk-523HCFYO.js +90 -0
- package/dist/cli-delegate/{chunk-M2DPGFZ4.js → chunk-6V6TA25H.js} +22 -152
- package/dist/cli-delegate/chunk-7IQE3D5S.js +191 -0
- package/dist/cli-delegate/{chunk-6KFEC3G7.js → chunk-CQWX336L.js} +1 -1
- package/dist/cli-delegate/chunk-DEIV7XP7.js +108 -0
- package/dist/cli-delegate/chunk-EEHDXSYD.js +2040 -0
- package/dist/cli-delegate/{chunk-P6ZHP5W2.js → chunk-GKE7ZVFA.js} +4 -4
- package/dist/cli-delegate/chunk-JQOM7TTM.js +1201 -0
- package/dist/cli-delegate/{chunk-IGD6ERX6.js → chunk-JQVYKIZA.js} +10 -0
- package/dist/cli-delegate/{chunk-FC75PGJE.js → chunk-JY2I2DXV.js} +12 -1
- package/dist/cli-delegate/chunk-KB5FZ655.js +208 -0
- package/dist/cli-delegate/{chunk-7RQP4UDH.js → chunk-KR6EM23A.js} +235 -1455
- package/dist/cli-delegate/{chunk-LTYVIY76.js → chunk-LIYTLH6O.js} +1 -1
- package/dist/cli-delegate/{chunk-YJ72UIAK.js → chunk-NQ7WT43P.js} +1186 -244
- package/dist/cli-delegate/chunk-NXEILF2K.js +2160 -0
- package/dist/cli-delegate/{chunk-5R7HOLAF.js → chunk-NYX3L2PZ.js} +1 -1
- package/dist/cli-delegate/{chunk-4E2W63DA.js → chunk-OKJUIAPS.js} +62 -1
- package/dist/cli-delegate/{chunk-QAJS5YWY.js → chunk-PHD7OOLE.js} +2 -1
- package/dist/cli-delegate/{chunk-RGNIWTEA.js → chunk-QLDHIPWR.js} +1 -1
- package/dist/cli-delegate/{chunk-7XGBX6ZH.js → chunk-RQNNW7IF.js} +1314 -560
- package/dist/cli-delegate/{chunk-4XFP2Y3E.js → chunk-S4UMZNES.js} +1 -1
- package/dist/cli-delegate/{chunk-6KM6ORRY.js → chunk-S4YWNRKO.js} +24 -8
- package/dist/cli-delegate/{chunk-FP36SWJD.js → chunk-TRI6DQZ6.js} +2781 -340
- package/dist/cli-delegate/chunk-ULQRUR23.js +208 -0
- package/dist/cli-delegate/{chunk-NUHLI2RX.js → chunk-YCU3TIXH.js} +2 -0
- package/dist/cli-delegate/chunk-ZBZV2G5R.js +210 -0
- package/dist/cli-delegate/{chunk-WGXTVKCQ.js → chunk-ZUZKZYCN.js} +5 -3
- 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 +1167 -234
- package/dist/cli-delegate/cmd_doctor.js +13 -6
- package/dist/cli-delegate/cmd_doctor_neighbours.js +23 -0
- package/dist/cli-delegate/cmd_explain.js +5 -5
- package/dist/cli-delegate/cmd_export.js +11 -8
- package/dist/cli-delegate/cmd_fleet.js +3 -3
- package/dist/cli-delegate/cmd_handoff.js +10 -7
- package/dist/cli-delegate/cmd_mcp_available.js +1 -1
- package/dist/cli-delegate/cmd_memory_get.js +3 -1
- package/dist/cli-delegate/cmd_migrate.js +2 -2
- package/dist/cli-delegate/cmd_packs_active.js +3 -3
- package/dist/cli-delegate/cmd_preflight.js +6 -6
- package/dist/cli-delegate/cmd_prune.js +11 -8
- package/dist/cli-delegate/cmd_refresh.js +2 -1
- package/dist/cli-delegate/cmd_route_audit.js +8 -6
- package/dist/cli-delegate/cmd_route_explain.js +4 -4
- package/dist/cli-delegate/cmd_session_recycle.js +4 -3
- package/dist/cli-delegate/cmd_settings_get.js +1 -1
- package/dist/cli-delegate/cmd_settings_migrate.js +11 -8
- package/dist/cli-delegate/cmd_settings_set.js +4 -4
- package/dist/cli-delegate/cmd_sync.js +11 -8
- package/dist/cli-delegate/cmd_uninstall.js +11 -8
- package/dist/cli-delegate/cmd_update.js +1 -1
- package/dist/cli-delegate/cmd_upgrade.js +3 -2
- package/dist/cli-delegate/cmd_validate.js +11 -8
- package/dist/cli-delegate/cmd_versions.js +1 -1
- package/dist/cli-delegate/deferral_carry.js +16 -0
- package/dist/cli-delegate/gate_execute.js +2 -2
- package/dist/cli-delegate/roadmap_gates.js +5 -5
- package/dist/cli-delegate/update_roadmap_progress.js +1 -1
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +127 -75
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +3 -3
- package/dist/discovery/dormancy-report.md +1 -1
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +7 -5
- package/dist/discovery/trust-report.md +2 -2
- package/dist/discovery/workspaces.json +6 -4
- package/dist/hooks/dispatch.js +5357 -6656
- package/dist/hooks/dispatch.sha256 +1 -1
- package/dist/install/claudePathsPlan.js +47 -6
- package/dist/install/claudeRuleRewrite.js +7 -0
- package/dist/install/emit_host_rules_cli.js +39 -36
- package/dist/install/globalRuleScope.js +87 -0
- package/dist/install/host_rule_ownership.js +160 -0
- package/dist/install/install.mjs +2080 -1024
- package/dist/install/installThinLayer.js +261 -0
- package/dist/install/installedRuleLinks.js +176 -0
- package/dist/install/wizard-plan.js +24 -0
- package/dist/mcp/registry-manifest.json +3 -3
- package/dist/mcp/server.json +2 -2
- package/dist/mcp/server.mjs +31965 -27154
- package/dist/scripts/_lib/agent_settings.js +11 -0
- package/dist/scripts/_lib/claude_settings_hooks.js +10 -8
- package/dist/scripts/_lib/installed_layer.js +378 -0
- package/dist/scripts/_lib/lean_projection_mode.js +218 -15
- package/dist/scripts/_lib/rule_consequence_class.js +45 -0
- package/dist/scripts/_lib/rule_injection.js +67 -10
- package/dist/scripts/_lib/rule_law_section.js +122 -0
- package/dist/scripts/_lib/thin_rules.js +458 -0
- package/dist/scripts/_lib/windsurf_render.js +60 -0
- package/dist/scripts/condense.js +14 -26
- package/dist/scripts/project_thin_rules.js +14 -294
- package/dist/server/schemas/settings.js +6 -0
- package/dist/shared/skillRanking.js +74 -13
- package/docs/contracts/settings-classes.md +7 -5
- package/package.json +1 -1
- package/src/agent-src/scripts/archive_completed_roadmaps.ts +115 -20
- package/src/agent-src/scripts/deferral_carry.ts +339 -0
- package/src/agent-src/scripts/update_roadmap_progress.ts +4 -1
- package/src/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +48 -6
- package/src/agent-src/templates/scripts/work_engine/stack/runner.ts +774 -109
- package/src/config/agent-settings.template.yml +62 -22
- package/src/config/continuity-surface.json +7 -0
- package/src/config/evaluator-budgets.json +4 -4
- package/src/config/gate-coverage.yml +96 -3
- package/src/config/gate-violation-baselines.json +17 -9
- package/src/config/hook-bundle-budget.json +25 -0
- package/src/config/hook-token-budget.json +6 -1
- package/src/config/host-instruction-limits.json +33 -0
- package/src/config/routing-coverage-seed.json +24 -3
- package/src/config/rule-activation-census.json +7 -3
- package/src/config/rule-consequence-class.json +161 -0
- package/src/config/rule-law-ceilings.json +99 -0
- package/src/install/claudePathsPlan.ts +46 -4
- package/src/install/claudeRuleRewrite.ts +10 -1
- package/src/install/emit_host_rules_cli.ts +43 -34
- package/src/install/globalRuleScope.ts +109 -0
- package/src/install/host_rule_ownership.ts +170 -0
- package/src/install/installThinLayer.ts +312 -0
- package/src/install/installedRuleLinks.ts +220 -0
- package/src/install/wizard-plan.ts +24 -0
- package/src/scripts/_cli/cmd_doctor.ts +23 -71
- package/src/scripts/_cli/cmd_doctor_neighbours.ts +293 -0
- package/src/scripts/_dispatch.bash +16 -2
- package/src/scripts/_lib/agent_settings.ts +11 -0
- package/src/scripts/_lib/claude_settings_hooks.ts +10 -8
- package/src/scripts/_lib/estate_offsets.ts +241 -0
- package/src/scripts/_lib/exemption_shape.ts +143 -0
- package/src/scripts/_lib/fnv.ts +23 -0
- package/src/scripts/_lib/foreign_scan.ts +106 -0
- package/src/scripts/_lib/gitignore_block.ts +314 -0
- package/src/scripts/_lib/global_deploy_inventory.ts +32 -0
- package/src/scripts/_lib/graph_feeder_record.ts +214 -0
- package/src/scripts/_lib/hook_settings.ts +73 -0
- package/src/scripts/_lib/host_capability.ts +40 -19
- package/src/scripts/_lib/host_hook_merge.ts +165 -0
- package/src/scripts/_lib/installed_layer.ts +538 -0
- package/src/scripts/_lib/json_merge.ts +82 -0
- package/src/scripts/_lib/json_pointers.ts +93 -11
- package/src/scripts/_lib/lean_projection_mode.ts +275 -15
- package/src/scripts/_lib/machine_wake.ts +16 -3
- package/src/scripts/_lib/neighbour_census.ts +760 -0
- package/src/scripts/_lib/neighbour_scan.ts +122 -0
- package/src/scripts/_lib/neighbour_tool_use.ts +189 -0
- package/src/scripts/_lib/prompt_shape.ts +46 -0
- package/src/scripts/_lib/release_migration_gate.ts +19 -3
- package/src/scripts/_lib/reserved_name_sweep.ts +73 -0
- package/src/scripts/_lib/review_coverage.ts +134 -0
- package/src/scripts/_lib/rule_consequence_class.ts +71 -0
- package/src/scripts/_lib/rule_injection.ts +130 -10
- package/src/scripts/_lib/rule_law_section.ts +147 -0
- package/src/scripts/_lib/rule_layer_overlap.ts +58 -0
- package/src/scripts/_lib/skill_origin.ts +254 -0
- package/src/scripts/_lib/structured_ask.ts +64 -21
- package/src/scripts/_lib/thin_rules.ts +540 -0
- package/src/scripts/_lib/touched_file_quality.ts +434 -0
- package/src/scripts/_lib/turn_end_refusals.ts +77 -2
- package/src/scripts/_lib/windsurf_render.ts +63 -0
- package/src/scripts/ai_council/cli_call_budget.ts +13 -5
- package/src/scripts/ai_council/clients.ts +26 -57
- package/src/scripts/ai_council/config.ts +1 -1
- package/src/scripts/ai_council/vendor_defaults.ts +45 -0
- package/src/scripts/audit_skill_overlap.ts +261 -0
- package/src/scripts/before_complete_hook.ts +243 -12
- package/src/scripts/bench_touched_file_quality.ts +238 -0
- package/src/scripts/check_enforcement_matrix.ts +377 -20
- package/src/scripts/check_estate_count.ts +130 -153
- package/src/scripts/check_finding_dispositions.ts +116 -4
- package/src/scripts/check_hook_bundle_composition.ts +370 -0
- package/src/scripts/check_kernel_edit_ratified.ts +49 -11
- package/src/scripts/check_memory.ts +7 -1
- package/src/scripts/check_release_highlights.ts +10 -0
- package/src/scripts/check_release_pr_shape.ts +38 -15
- package/src/scripts/check_standing_rule_delivery.ts +33 -13
- package/src/scripts/check_verify_expectation_delta.ts +521 -0
- package/src/scripts/code_graph/detect.ts +127 -7
- package/src/scripts/code_graph/foreign.ts +194 -0
- package/src/scripts/code_graph/query.ts +217 -4
- package/src/scripts/code_graph/types.ts +26 -2
- package/src/scripts/code_graph/validate.ts +3 -1
- package/src/scripts/code_graph/verbs.ts +103 -0
- package/src/scripts/compile_hook_manifest.ts +33 -1
- package/src/scripts/condense.ts +14 -27
- package/src/scripts/estate_exemption_shape.ts +202 -0
- package/src/scripts/generate_host_cost_table.ts +1 -1
- package/src/scripts/hook_manifest.json +1 -1
- package/src/scripts/hook_manifest.yaml +150 -9
- package/src/scripts/hooks/block_config_weakening.ts +67 -2
- package/src/scripts/hooks/block_plumbing_writes.ts +29 -1
- package/src/scripts/hooks/code_graph_context_hook.ts +252 -23
- package/src/scripts/hooks/concern_failure_policy.ts +280 -0
- package/src/scripts/hooks/dispatch_hook.ts +52 -52
- package/src/scripts/hooks/exit_codes.ts +2 -1
- package/src/scripts/hooks/host_lowering.json +1 -1
- package/src/scripts/hooks/host_lowering.ts +19 -1
- package/src/scripts/hooks/one_question_per_ask_hook.ts +41 -25
- package/src/scripts/hooks/payload_stub.ts +10 -1
- package/src/scripts/hooks/rule_inject_hook.ts +757 -63
- package/src/scripts/hooks/table_fingerprint.ts +21 -0
- package/src/scripts/hooks/telemetry_usage_hook.ts +64 -8
- package/src/scripts/hooks/turn_end_gate_hook.ts +84 -0
- package/src/scripts/hooks_status.ts +112 -0
- package/src/scripts/injection_scan_hook.ts +7 -0
- package/src/scripts/install.ts +72 -185
- package/src/scripts/installed_layer_report.ts +103 -0
- package/src/scripts/language_mirror_hook.ts +15 -6
- package/src/scripts/learning_sidecar.ts +119 -8
- package/src/scripts/lint_hook_manifest.ts +53 -0
- package/src/scripts/lint_major_migration_sections.ts +156 -26
- package/src/scripts/lint_pack_boundaries.ts +63 -5
- package/src/scripts/lint_rule_law_section.ts +517 -0
- package/src/scripts/lint_workflow_security.ts +161 -5
- package/src/scripts/mcp_server/consumer_tool_catalog.json +53 -0
- package/src/scripts/mcp_server/graph_tools.ts +72 -3
- package/src/scripts/measure_routing_signal.ts +54 -16
- package/src/scripts/measure_skill_ranker_baseline.ts +216 -8
- package/src/scripts/memory_learn_hook.ts +91 -6
- package/src/scripts/model_rule_injection.ts +52 -5
- package/src/scripts/project_thin_rules.ts +34 -327
- package/src/scripts/report_evidence_temperature.ts +657 -0
- package/src/scripts/report_installed_rule_links.ts +157 -0
- package/src/scripts/report_label_agreement.ts +233 -0
- package/src/scripts/report_obligation_mechanism.ts +230 -0
- package/src/scripts/report_single_token_triggers.ts +277 -0
- package/src/scripts/report_skill_ranker_confusion.ts +442 -0
- package/src/scripts/report_standing_payload_by_host.ts +188 -15
- package/src/scripts/report_verification_record_coverage.ts +306 -0
- package/src/scripts/rule_activation_census.ts +5 -2
- package/src/scripts/rule_trigger_eval.ts +9 -9
- package/src/scripts/schemas/review-findings.schema.json +3 -2
- package/src/scripts/schemas/rule.schema.json +5 -0
- package/src/scripts/self_review_gate.ts +62 -7
- package/src/scripts/skill_tools/score_skill_relevance.ts +290 -25
- package/src/scripts/sweep_skill_ranker_signals.ts +129 -0
- package/src/scripts/sync_gitignore.ts +29 -235
- package/src/scripts/trigger_eval_grandfather.json +0 -5
- package/src/server/schemas/settings.ts +10 -0
- package/src/shared/skillRanking.ts +117 -11
- package/dist/cli-delegate/chunk-JNMVLWLR.js +0 -4457
- package/dist/cli-delegate/chunk-YDPILCOL.js +0 -152
|
@@ -77,6 +77,19 @@ export const LOWERING_REL = path.join('src', 'scripts', 'hooks', 'host_lowering.
|
|
|
77
77
|
export const BEGIN_MARKER = '<!-- BEGIN GENERATED: enforcement-configured-by-slot -->';
|
|
78
78
|
export const END_MARKER = '<!-- END GENERATED: enforcement-configured-by-slot -->';
|
|
79
79
|
|
|
80
|
+
/**
|
|
81
|
+
* The second generated region: every `blocking` concern, with the enforcement
|
|
82
|
+
* the host it is bound on can actually carry.
|
|
83
|
+
*
|
|
84
|
+
* road-to-blocking-severities 1.2. Its own marker pair rather than an extra
|
|
85
|
+
* column in the first region, because the two tables have different units — the
|
|
86
|
+
* first is one row per host-SLOT, this is one row per host-slot-CONCERN — and
|
|
87
|
+
* merging them would make every host-slot row repeat once per concern bound to
|
|
88
|
+
* it.
|
|
89
|
+
*/
|
|
90
|
+
export const SEVERITY_BEGIN_MARKER = '<!-- BEGIN GENERATED: blocking-severity-by-binding -->';
|
|
91
|
+
export const SEVERITY_END_MARKER = '<!-- END GENERATED: blocking-severity-by-binding -->';
|
|
92
|
+
|
|
80
93
|
/** The command a drift failure tells the reader to run. Printed, never guessed at. */
|
|
81
94
|
export const REGEN_COMMAND = `./scripts-run src/scripts/${GATE} --write`;
|
|
82
95
|
|
|
@@ -335,31 +348,200 @@ export function renderRegion(lowering: HostLowering): string {
|
|
|
335
348
|
return out.join('\n');
|
|
336
349
|
}
|
|
337
350
|
|
|
338
|
-
/**
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
351
|
+
/**
|
|
352
|
+
* How each {@link VerifiedEnforcement} is worded in the published table.
|
|
353
|
+
*
|
|
354
|
+
* `unverified` and `warning-only` are worded so a reader cannot slide between
|
|
355
|
+
* them. Only `warning-only` says "cannot"; `unverified` says what is missing.
|
|
356
|
+
*/
|
|
357
|
+
export const ENFORCEMENT_TEXT: Readonly<Record<VerifiedEnforcement, string>> = {
|
|
358
|
+
refusal: 'the slot denies — the concern does what it declares',
|
|
359
|
+
'proof-expired': 'the slot can deny; this package’s `verified` citation has lapsed',
|
|
360
|
+
'warning-only': 'the slot is bound and `block_exit` is null — it runs and warns, it cannot refuse',
|
|
361
|
+
unverified: 'no lowering row for this slot — nothing is bound natively, and nothing is established',
|
|
362
|
+
};
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* The 1.2 region body: one row per `blocking` binding, two independent columns.
|
|
366
|
+
*
|
|
367
|
+
* Grouped by host and ordered as `concernSlotAudit` sorted it, so a
|
|
368
|
+
* regeneration is a no-op whenever nothing moved.
|
|
369
|
+
*/
|
|
370
|
+
export function renderSeverityRegion(audit: readonly HostConcernAudit[]): string {
|
|
371
|
+
const all = audit.flatMap((h) => h.blocking.map((b) => b));
|
|
372
|
+
const out: string[] = [];
|
|
373
|
+
out.push(
|
|
374
|
+
`Projected from \`${MANIFEST_REL}\` (declared severity) and \`${LOWERING_REL}\` ` +
|
|
375
|
+
'(verified enforcement). **Two independent facts, never folded into one.**',
|
|
376
|
+
);
|
|
377
|
+
out.push('');
|
|
378
|
+
out.push(
|
|
379
|
+
'The manifest declares what a concern is *meant* to do; the lowering table records ' +
|
|
380
|
+
'what the host slot it is bound on *can* do. A `blocking` concern on a slot that ' +
|
|
381
|
+
'cannot refuse still runs and still warns — it is not silent, and it is not a ' +
|
|
382
|
+
'refusal either. These columns say which.',
|
|
383
|
+
);
|
|
384
|
+
out.push('');
|
|
385
|
+
const byEnforcement = (e: VerifiedEnforcement): number =>
|
|
386
|
+
all.filter((b) => b.enforcement === e).length;
|
|
387
|
+
out.push(
|
|
388
|
+
`**${String(all.length)} binding(s) declare \`blocking\`: ` +
|
|
389
|
+
`${String(byEnforcement('refusal'))} refuse, ` +
|
|
390
|
+
`${String(byEnforcement('warning-only'))} run and warn on a slot verified unable to ` +
|
|
391
|
+
`refuse, ${String(byEnforcement('unverified'))} sit on a slot with no lowering row, ` +
|
|
392
|
+
`${String(byEnforcement('proof-expired'))} sit on a slot whose proof has lapsed.**`,
|
|
393
|
+
);
|
|
394
|
+
out.push('');
|
|
395
|
+
out.push('| Host | Slot | Concern | Declared severity | Verified enforcement | What that means |');
|
|
396
|
+
out.push('|---|---|---|---|---|---|');
|
|
397
|
+
for (const b of all) {
|
|
398
|
+
out.push(
|
|
399
|
+
`| \`${b.host}\` | \`${b.slot}\` | \`${b.concern}\` | \`${b.declared}\` | ` +
|
|
400
|
+
`\`${b.enforcement}\` | ${ENFORCEMENT_TEXT[b.enforcement]} |`,
|
|
401
|
+
);
|
|
402
|
+
}
|
|
403
|
+
if (all.length === 0) {
|
|
404
|
+
out.push('');
|
|
405
|
+
out.push('No concern in the manifest declares `blocking`.');
|
|
406
|
+
}
|
|
407
|
+
return out.join('\n');
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/** Replace the block between one marker pair. Idempotent by construction. */
|
|
411
|
+
function _splice(text: string, region: string, begin: string, end: string): string {
|
|
412
|
+
const b = text.indexOf(begin);
|
|
413
|
+
const e = text.indexOf(end);
|
|
342
414
|
if (b === -1 || e === -1 || e < b) {
|
|
343
415
|
throw new Error(
|
|
344
416
|
`${GATE}: ${DOC_REL} is missing the generated-region markers ` +
|
|
345
|
-
`(${
|
|
417
|
+
`(${begin} … ${end}). Restore them rather than hand-writing the ` +
|
|
346
418
|
'table — the markers are what makes the region regenerable.',
|
|
347
419
|
);
|
|
348
420
|
}
|
|
349
|
-
return `${text.slice(0, b +
|
|
421
|
+
return `${text.slice(0, b + begin.length)}\n${region}\n${text.slice(e)}`;
|
|
350
422
|
}
|
|
351
423
|
|
|
352
|
-
/**
|
|
353
|
-
export function
|
|
354
|
-
|
|
355
|
-
|
|
424
|
+
/** Replace the block between the markers. Idempotent by construction. */
|
|
425
|
+
export function spliceDoc(text: string, region: string): string {
|
|
426
|
+
return _splice(text, region, BEGIN_MARKER, END_MARKER);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
/** Replace the blocking-severity region. Same contract as {@link spliceDoc}. */
|
|
430
|
+
export function spliceSeverityDoc(text: string, region: string): string {
|
|
431
|
+
return _splice(text, region, SEVERITY_BEGIN_MARKER, SEVERITY_END_MARKER);
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
function _extract(text: string, begin: string, end: string): string | null {
|
|
435
|
+
const b = text.indexOf(begin);
|
|
436
|
+
const e = text.indexOf(end);
|
|
356
437
|
if (b === -1 || e === -1 || e < b) return null;
|
|
357
438
|
return text
|
|
358
|
-
.slice(b +
|
|
439
|
+
.slice(b + begin.length, e)
|
|
359
440
|
.replace(/^\n/, '')
|
|
360
441
|
.replace(/\n$/, '');
|
|
361
442
|
}
|
|
362
443
|
|
|
444
|
+
/** The region body a committed document carries, or null when the markers are gone. */
|
|
445
|
+
export function extractRegion(text: string): string | null {
|
|
446
|
+
return _extract(text, BEGIN_MARKER, END_MARKER);
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
/** The blocking-severity region a committed document carries, or null. */
|
|
450
|
+
export function extractSeverityRegion(text: string): string | null {
|
|
451
|
+
return _extract(text, SEVERITY_BEGIN_MARKER, SEVERITY_END_MARKER);
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
/** One published blocking-severity row, read off the committed region. */
|
|
455
|
+
export interface CommittedSeverityCell {
|
|
456
|
+
readonly host: string;
|
|
457
|
+
readonly slot: string;
|
|
458
|
+
readonly concern: string;
|
|
459
|
+
readonly declared: string;
|
|
460
|
+
readonly enforcement: string;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
/** Blocking-severity rows a committed region carries, in document order. */
|
|
464
|
+
export function committedSeverityCells(region: string): CommittedSeverityCell[] {
|
|
465
|
+
const out: CommittedSeverityCell[] = [];
|
|
466
|
+
for (const line of region.split('\n')) {
|
|
467
|
+
if (!line.trim().startsWith('|')) continue;
|
|
468
|
+
const cells = splitMarkdownRow(line);
|
|
469
|
+
if (cells.length < 5) continue;
|
|
470
|
+
if (cells[0] === 'Host' || /^-+$/.test((cells[0] ?? '').trim())) continue;
|
|
471
|
+
const strip = (s: string): string => s.trim().replace(/^`|`$/g, '');
|
|
472
|
+
out.push({
|
|
473
|
+
host: strip(cells[0] ?? ''),
|
|
474
|
+
slot: strip(cells[1] ?? ''),
|
|
475
|
+
concern: strip(cells[2] ?? ''),
|
|
476
|
+
declared: strip(cells[3] ?? ''),
|
|
477
|
+
enforcement: strip(cells[4] ?? ''),
|
|
478
|
+
});
|
|
479
|
+
}
|
|
480
|
+
return out;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
/**
|
|
484
|
+
* The 1.2 HARD gate: published enforcement claims the configuration refutes.
|
|
485
|
+
*
|
|
486
|
+
* This is the half the council asked to fail rather than report, and the
|
|
487
|
+
* distinction from the audit above is the reason it may. `concernSlotAudit`
|
|
488
|
+
* counts BINDINGS, a population with a legacy backlog this package did not
|
|
489
|
+
* create in one diff — failing on it would red the tree on history. These
|
|
490
|
+
* findings compare a GENERATED DOCUMENT against the configuration it is
|
|
491
|
+
* generated from, which has no backlog by construction: every row was written
|
|
492
|
+
* by the generator one command ago, so a disagreement is a hand edit or a
|
|
493
|
+
* generator bug and neither should ship.
|
|
494
|
+
*
|
|
495
|
+
* Both seats named the same two dishonesty classes, and both directions are
|
|
496
|
+
* checked because they fail in opposite ways:
|
|
497
|
+
*
|
|
498
|
+
* - A row claiming `refusal` where the slot's `block_exit` is null, or where
|
|
499
|
+
* there is no row at all, OVERSTATES the guarantee. A reader takes it as a
|
|
500
|
+
* deterministic block and gets a warning.
|
|
501
|
+
* - A row claiming `warning-only` where the lowering table has NO row for the
|
|
502
|
+
* slot UNDERSTATES what is known: it asserts the host cannot refuse, which
|
|
503
|
+
* is a host fact this package has not established and which
|
|
504
|
+
* `host_lowering.yaml` explicitly disclaims. `unverified` is the honest
|
|
505
|
+
* value there, and collapsing the two is how an absence of measurement
|
|
506
|
+
* becomes a measurement.
|
|
507
|
+
*
|
|
508
|
+
* A value outside {@link VERIFIED_ENFORCEMENTS} is its own finding, for the
|
|
509
|
+
* same reason `unbackedOutcomes` rejects one: an invented category in a
|
|
510
|
+
* generated table looks exactly as authoritative as a real one.
|
|
511
|
+
*/
|
|
512
|
+
export function severityFindings(region: string, lowering: HostLowering): string[] {
|
|
513
|
+
const findings: string[] = [];
|
|
514
|
+
for (const cell of committedSeverityCells(region)) {
|
|
515
|
+
const label = `${cell.host}/${cell.slot}/${cell.concern}`;
|
|
516
|
+
if (!(VERIFIED_ENFORCEMENTS as readonly string[]).includes(cell.enforcement)) {
|
|
517
|
+
findings.push(
|
|
518
|
+
`${label}: \`${cell.enforcement}\` is not in the closed enforcement vocabulary ` +
|
|
519
|
+
`(${VERIFIED_ENFORCEMENTS.map((e) => `\`${e}\``).join(' · ')}).`,
|
|
520
|
+
);
|
|
521
|
+
continue;
|
|
522
|
+
}
|
|
523
|
+
const row = readSlots(lowering, cell.host).slots.find(
|
|
524
|
+
(s: SlotReading) => s.slot === cell.slot,
|
|
525
|
+
);
|
|
526
|
+
if (cell.enforcement === 'refusal' && (row === undefined || row.literal === null)) {
|
|
527
|
+
findings.push(
|
|
528
|
+
`${label}: published \`refusal\`, but ${LOWERING_REL} carries ` +
|
|
529
|
+
`${row === undefined ? 'no row for this slot' : '`block_exit: null`'} — a ` +
|
|
530
|
+
'refusal has nowhere to go, so the published row overstates the guarantee.',
|
|
531
|
+
);
|
|
532
|
+
continue;
|
|
533
|
+
}
|
|
534
|
+
if (cell.enforcement === 'warning-only' && row === undefined) {
|
|
535
|
+
findings.push(
|
|
536
|
+
`${label}: published \`warning-only\`, which asserts this slot CANNOT refuse, ` +
|
|
537
|
+
`but ${LOWERING_REL} carries no row for it at all. An absent row is ` +
|
|
538
|
+
'`unverified`, never a host fact — the table says so in its own header.',
|
|
539
|
+
);
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
return findings;
|
|
543
|
+
}
|
|
544
|
+
|
|
363
545
|
/** Outcome cells a committed region carries, with their row label. */
|
|
364
546
|
export function committedCells(region: string): { label: string; value: string }[] {
|
|
365
547
|
const out: { label: string; value: string }[] = [];
|
|
@@ -472,6 +654,18 @@ export interface HostConcernAudit {
|
|
|
472
654
|
* has nowhere to go.
|
|
473
655
|
*/
|
|
474
656
|
readonly noDeny: readonly NullBlockBinding[];
|
|
657
|
+
/**
|
|
658
|
+
* EVERY binding on this host whose declared severity is `blocking`, with
|
|
659
|
+
* the enforcement its slot carries — including the ones that CAN refuse,
|
|
660
|
+
* which `noDeny` by construction never holds.
|
|
661
|
+
*
|
|
662
|
+
* Separate from `noDeny` rather than a filter over it, because the
|
|
663
|
+
* published table needs the complete picture: a reader who sees only the
|
|
664
|
+
* gaps cannot tell a host that refuses nowhere from a host with no blocking
|
|
665
|
+
* concerns at all, and those are the two readings the 1.2 table exists to
|
|
666
|
+
* keep apart.
|
|
667
|
+
*/
|
|
668
|
+
readonly blocking: readonly BlockingBinding[];
|
|
475
669
|
}
|
|
476
670
|
|
|
477
671
|
/** Slots that carry a dispatcher verdict. `ask` is a UI affordance, not one. */
|
|
@@ -534,6 +728,7 @@ export function concernSlotAudit(root: string, lowering: HostLowering): HostConc
|
|
|
534
728
|
const denySlots = reading.slots.filter((s: SlotReading) => s.literal !== null).length;
|
|
535
729
|
|
|
536
730
|
const noDeny: NullBlockBinding[] = [];
|
|
731
|
+
const blocking: BlockingBinding[] = [];
|
|
537
732
|
let boundSlots = 0;
|
|
538
733
|
if (blockRaw !== null && typeof blockRaw === 'object') {
|
|
539
734
|
for (const [slot, value] of Object.entries(blockRaw as Record<string, unknown>)) {
|
|
@@ -553,6 +748,21 @@ export function concernSlotAudit(root: string, lowering: HostLowering): HostConc
|
|
|
553
748
|
: row.effective === null
|
|
554
749
|
? 'stale-proof'
|
|
555
750
|
: null;
|
|
751
|
+
// The 1.2 roster runs BEFORE the `reason === null` return, so a
|
|
752
|
+
// binding on a slot that CAN refuse is recorded here and
|
|
753
|
+
// nowhere else.
|
|
754
|
+
for (const concern of value) {
|
|
755
|
+
if (typeof concern !== 'string') continue;
|
|
756
|
+
const declared = severities.get(concern) ?? '(unknown concern)';
|
|
757
|
+
if (declared !== 'blocking') continue;
|
|
758
|
+
blocking.push({
|
|
759
|
+
host,
|
|
760
|
+
slot,
|
|
761
|
+
concern,
|
|
762
|
+
declared,
|
|
763
|
+
enforcement: enforcementFor(reason),
|
|
764
|
+
});
|
|
765
|
+
}
|
|
556
766
|
if (reason === null) continue;
|
|
557
767
|
for (const concern of value) {
|
|
558
768
|
if (typeof concern !== 'string') continue;
|
|
@@ -566,6 +776,9 @@ export function concernSlotAudit(root: string, lowering: HostLowering): HostConc
|
|
|
566
776
|
}
|
|
567
777
|
}
|
|
568
778
|
}
|
|
779
|
+
blocking.sort(
|
|
780
|
+
(a, b) => a.slot.localeCompare(b.slot) || a.concern.localeCompare(b.concern),
|
|
781
|
+
);
|
|
569
782
|
const reasonRank = (r: NoDenyReason): number =>
|
|
570
783
|
r === 'unlowerable' ? 0 : r === 'null-block' ? 1 : 2;
|
|
571
784
|
const sevRank = (s: string): number => (s === 'blocking' ? 0 : s === 'advisory' ? 2 : 1);
|
|
@@ -582,11 +795,77 @@ export function concernSlotAudit(root: string, lowering: HostLowering): HostConc
|
|
|
582
795
|
lowerableSlots: reading.slots.length,
|
|
583
796
|
boundSlots,
|
|
584
797
|
noDeny,
|
|
798
|
+
blocking,
|
|
585
799
|
});
|
|
586
800
|
}
|
|
587
801
|
return out;
|
|
588
802
|
}
|
|
589
803
|
|
|
804
|
+
/**
|
|
805
|
+
* What a binding's host slot can actually carry, as a closed vocabulary.
|
|
806
|
+
*
|
|
807
|
+
* road-to-blocking-severities 1.2, option (a) as the council revised it on
|
|
808
|
+
* 2026-10-01 (2/2, both seats). The revision is in the NAMES and it is the
|
|
809
|
+
* whole point: the first draft called this the "effective severity", and the
|
|
810
|
+
* second seat refused that term — severity has not changed, enforcement
|
|
811
|
+
* strength has, and a generated document that silently redefines the
|
|
812
|
+
* manifest's own word is worse than one that says nothing. So a binding
|
|
813
|
+
* carries two independent facts, published side by side and never folded into
|
|
814
|
+
* one: the DECLARED severity, which is the concern's policy intent and belongs
|
|
815
|
+
* to `hook_manifest.yaml`, and the VERIFIED ENFORCEMENT below, which is the
|
|
816
|
+
* host slot's measured capability and belongs to `host_lowering.yaml`.
|
|
817
|
+
*
|
|
818
|
+
* - `refusal` — the slot's `block_exit` can deny and its `verified`
|
|
819
|
+
* proof is current. A `blocking` concern here does what
|
|
820
|
+
* it says.
|
|
821
|
+
* - `warning-only` — a lowering row exists and its `block_exit` is null. The
|
|
822
|
+
* slot is wired, the concern runs, and its verdict cannot
|
|
823
|
+
* become a refusal. This is the only value that asserts
|
|
824
|
+
* the host CANNOT refuse, and it is backed by a row.
|
|
825
|
+
* - `unverified` — no lowering row for this slot on this host. Nothing is
|
|
826
|
+
* bound natively and nothing has been established.
|
|
827
|
+
* Deliberately NOT `warning-only`: `host_lowering.yaml`
|
|
828
|
+
* says in its own header that an absence "does NOT mean
|
|
829
|
+
* the host cannot enforce", and both council seats named
|
|
830
|
+
* collapsing the two the defect to avoid. The gate below
|
|
831
|
+
* fails a published row that collapses them.
|
|
832
|
+
* - `proof-expired` — the literal `block_exit` can deny but this package's
|
|
833
|
+
* `verified` citation has lapsed. A statement about our
|
|
834
|
+
* provenance, never about the host.
|
|
835
|
+
*
|
|
836
|
+
* Order is strongest-first, matching {@link CONFIGURED_OUTCOMES}'s convention.
|
|
837
|
+
*/
|
|
838
|
+
export const VERIFIED_ENFORCEMENTS = [
|
|
839
|
+
'refusal',
|
|
840
|
+
'proof-expired',
|
|
841
|
+
'warning-only',
|
|
842
|
+
'unverified',
|
|
843
|
+
] as const;
|
|
844
|
+
|
|
845
|
+
export type VerifiedEnforcement = (typeof VERIFIED_ENFORCEMENTS)[number];
|
|
846
|
+
|
|
847
|
+
/**
|
|
848
|
+
* The enforcement a {@link NoDenyReason} corresponds to; `null` means the slot
|
|
849
|
+
* can deny, which is the one case `concernSlotAudit` does not record a reason
|
|
850
|
+
* for.
|
|
851
|
+
*/
|
|
852
|
+
export function enforcementFor(reason: NoDenyReason | null): VerifiedEnforcement {
|
|
853
|
+
if (reason === null) return 'refusal';
|
|
854
|
+
if (reason === 'unlowerable') return 'unverified';
|
|
855
|
+
if (reason === 'null-block') return 'warning-only';
|
|
856
|
+
return 'proof-expired';
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
/** One concern declared `blocking`, with the enforcement its host slot carries. */
|
|
860
|
+
export interface BlockingBinding {
|
|
861
|
+
readonly host: string;
|
|
862
|
+
readonly slot: string;
|
|
863
|
+
readonly concern: string;
|
|
864
|
+
/** Always `blocking` here — kept explicit so the published row carries both facts. */
|
|
865
|
+
readonly declared: string;
|
|
866
|
+
readonly enforcement: VerifiedEnforcement;
|
|
867
|
+
}
|
|
868
|
+
|
|
590
869
|
/** How each {@link NoDenyReason} is worded. `stale-proof` never says "cannot". */
|
|
591
870
|
const REASON_TEXT: Readonly<Record<NoDenyReason, string>> = {
|
|
592
871
|
unlowerable: 'no lowering row for this slot — nothing is bound natively at all',
|
|
@@ -672,19 +951,27 @@ export function main(argv?: readonly string[]): number {
|
|
|
672
951
|
const ledger = new GateLedger(GATE);
|
|
673
952
|
ledger.plan(built.rows.map((r) => `${r.host}/${r.slot}`));
|
|
674
953
|
const region = renderRegion(lowering);
|
|
954
|
+
const audit = concernSlotAudit(root, lowering);
|
|
955
|
+
const severityRegion = renderSeverityRegion(audit);
|
|
675
956
|
|
|
676
957
|
if (write) {
|
|
677
958
|
let next: string;
|
|
678
959
|
try {
|
|
679
|
-
next = spliceDoc(docText, region);
|
|
960
|
+
next = spliceSeverityDoc(spliceDoc(docText, region), severityRegion);
|
|
680
961
|
} catch (exc) {
|
|
681
962
|
process.stderr.write(`❌ ${String(exc)}\n`);
|
|
682
963
|
return 2;
|
|
683
964
|
}
|
|
684
965
|
// The backing check runs BEFORE the write, so a generator bug cannot
|
|
685
966
|
// put a phantom value into the document and then be caught by the
|
|
686
|
-
// check that same generator's output feeds.
|
|
687
|
-
|
|
967
|
+
// check that same generator's output feeds. The 1.2 severity check
|
|
968
|
+
// rides in the same position and for the same reason: a generator that
|
|
969
|
+
// could write `refusal` onto a null `block_exit` must be stopped at the
|
|
970
|
+
// write, not discovered by the next read-only run.
|
|
971
|
+
const phantom = [
|
|
972
|
+
...unbackedOutcomes(region, backedOutcomes(lowering)),
|
|
973
|
+
...severityFindings(severityRegion, lowering),
|
|
974
|
+
];
|
|
688
975
|
if (phantom.length > 0) {
|
|
689
976
|
for (const f of phantom) process.stderr.write(`❌ ${GATE}: ${f}\n`);
|
|
690
977
|
process.stderr.write(
|
|
@@ -718,14 +1005,31 @@ export function main(argv?: readonly string[]): number {
|
|
|
718
1005
|
return 2;
|
|
719
1006
|
}
|
|
720
1007
|
|
|
1008
|
+
const committedSeverity = extractSeverityRegion(docText);
|
|
1009
|
+
if (committedSeverity === null) {
|
|
1010
|
+
process.stderr.write(
|
|
1011
|
+
`❌ ${GATE}: ${DOC_REL} has no blocking-severity region. The markers ` +
|
|
1012
|
+
`${SEVERITY_BEGIN_MARKER} … ${SEVERITY_END_MARKER} are what make that table ` +
|
|
1013
|
+
`regenerable; restore them and run \`${REGEN_COMMAND}\`.\n`,
|
|
1014
|
+
);
|
|
1015
|
+
return 2;
|
|
1016
|
+
}
|
|
1017
|
+
|
|
721
1018
|
const findings: string[] = [];
|
|
722
1019
|
findings.push(...unbackedOutcomes(committed, backedOutcomes(lowering)));
|
|
723
1020
|
findings.push(...built.contradictions);
|
|
1021
|
+
findings.push(...severityFindings(committedSeverity, lowering));
|
|
724
1022
|
if (committed !== region) {
|
|
725
1023
|
findings.push(
|
|
726
1024
|
`${DOC_REL} § the generated region differs from what \`${LOWERING_REL}\` produces.`,
|
|
727
1025
|
);
|
|
728
1026
|
}
|
|
1027
|
+
if (committedSeverity !== severityRegion) {
|
|
1028
|
+
findings.push(
|
|
1029
|
+
`${DOC_REL} § the blocking-severity region differs from what \`${MANIFEST_REL}\` ` +
|
|
1030
|
+
`and \`${LOWERING_REL}\` produce.`,
|
|
1031
|
+
);
|
|
1032
|
+
}
|
|
729
1033
|
|
|
730
1034
|
// A pair is `fail`ed when the committed cell for it is absent or carries a
|
|
731
1035
|
// different outcome, and `complete`d otherwise. The denominator is the
|
|
@@ -755,7 +1059,7 @@ export function main(argv?: readonly string[]): number {
|
|
|
755
1059
|
// The concern-vs-slot audit prints on every read-only run, before the
|
|
756
1060
|
// verdict, so it is visible whether the row comparison passed or failed.
|
|
757
1061
|
// It never changes the exit code — see `concernSlotAudit`.
|
|
758
|
-
for (const line of renderConcernAudit(
|
|
1062
|
+
for (const line of renderConcernAudit(audit)) {
|
|
759
1063
|
process.stdout.write(`${line}\n`);
|
|
760
1064
|
}
|
|
761
1065
|
|
|
@@ -788,15 +1092,33 @@ export function main(argv?: readonly string[]): number {
|
|
|
788
1092
|
function selfTest(): number {
|
|
789
1093
|
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'enforcement-matrix-'));
|
|
790
1094
|
const lowering = _read(ROOT, LOWERING_REL) ?? '';
|
|
791
|
-
const
|
|
1095
|
+
const manifest = _read(ROOT, MANIFEST_REL) ?? '';
|
|
1096
|
+
/**
|
|
1097
|
+
* Plant a fixture tree carrying BOTH generated regions.
|
|
1098
|
+
*
|
|
1099
|
+
* The manifest is copied in alongside the lowering table because the
|
|
1100
|
+
* severity region is derived from the two together — without it
|
|
1101
|
+
* `concernSlotAudit` reads nothing and every severity case would exercise
|
|
1102
|
+
* an empty table, which is a fixture that cannot fail.
|
|
1103
|
+
*/
|
|
1104
|
+
const plant = (
|
|
1105
|
+
name: string,
|
|
1106
|
+
mutate: (region: string) => string,
|
|
1107
|
+
mutateSeverity: (region: string) => string = (r) => r,
|
|
1108
|
+
): string => {
|
|
792
1109
|
const dir = path.join(tmp, name);
|
|
793
1110
|
fs.mkdirSync(path.join(dir, path.dirname(LOWERING_REL)), { recursive: true });
|
|
1111
|
+
fs.mkdirSync(path.join(dir, path.dirname(MANIFEST_REL)), { recursive: true });
|
|
794
1112
|
fs.mkdirSync(path.join(dir, path.dirname(DOC_REL)), { recursive: true });
|
|
795
1113
|
fs.writeFileSync(path.join(dir, LOWERING_REL), lowering, 'utf-8');
|
|
796
|
-
|
|
1114
|
+
fs.writeFileSync(path.join(dir, MANIFEST_REL), manifest, 'utf-8');
|
|
1115
|
+
const table = parseHostLowering(lowering);
|
|
1116
|
+
const region = renderRegion(table);
|
|
1117
|
+
const severity = renderSeverityRegion(concernSlotAudit(dir, table));
|
|
797
1118
|
fs.writeFileSync(
|
|
798
1119
|
path.join(dir, DOC_REL),
|
|
799
|
-
`# fixture\n\n${BEGIN_MARKER}\n${mutate(region)}\n${END_MARKER}\n
|
|
1120
|
+
`# fixture\n\n${BEGIN_MARKER}\n${mutate(region)}\n${END_MARKER}\n\n` +
|
|
1121
|
+
`${SEVERITY_BEGIN_MARKER}\n${mutateSeverity(severity)}\n${SEVERITY_END_MARKER}\n`,
|
|
800
1122
|
'utf-8',
|
|
801
1123
|
);
|
|
802
1124
|
return dir;
|
|
@@ -807,9 +1129,44 @@ function selfTest(): number {
|
|
|
807
1129
|
try {
|
|
808
1130
|
return runSelfTest({
|
|
809
1131
|
gate: GATE,
|
|
810
|
-
minCases:
|
|
811
|
-
minRejectCases:
|
|
1132
|
+
minCases: 8,
|
|
1133
|
+
minRejectCases: 7,
|
|
812
1134
|
cases: [
|
|
1135
|
+
// road-to-blocking-severities 1.2 — the two dishonesty classes
|
|
1136
|
+
// the council asked to FAIL rather than report. Both are planted
|
|
1137
|
+
// by hand, because a generator that could emit either is the bug
|
|
1138
|
+
// these cases exist to catch, so a generated fixture could not
|
|
1139
|
+
// demonstrate one.
|
|
1140
|
+
{
|
|
1141
|
+
name: 'a published `refusal` on a slot whose block_exit is null is rejected',
|
|
1142
|
+
expect: 'reject',
|
|
1143
|
+
run: () =>
|
|
1144
|
+
run(
|
|
1145
|
+
plant('overstate', (r) => r, (s) =>
|
|
1146
|
+
s.replace('| `warning-only` |', '| `refusal` |'),
|
|
1147
|
+
),
|
|
1148
|
+
),
|
|
1149
|
+
},
|
|
1150
|
+
{
|
|
1151
|
+
name: 'a published `warning-only` on a slot with no lowering row is rejected',
|
|
1152
|
+
expect: 'reject',
|
|
1153
|
+
run: () =>
|
|
1154
|
+
run(
|
|
1155
|
+
plant('understate', (r) => r, (s) =>
|
|
1156
|
+
s.replace('| `unverified` |', '| `warning-only` |'),
|
|
1157
|
+
),
|
|
1158
|
+
),
|
|
1159
|
+
},
|
|
1160
|
+
{
|
|
1161
|
+
name: 'an enforcement value outside the closed vocabulary is rejected',
|
|
1162
|
+
expect: 'reject',
|
|
1163
|
+
run: () =>
|
|
1164
|
+
run(
|
|
1165
|
+
plant('enf-vocab', (r) => r, (s) =>
|
|
1166
|
+
s.replace('| `unverified` |', '| `advisory` |'),
|
|
1167
|
+
),
|
|
1168
|
+
),
|
|
1169
|
+
},
|
|
813
1170
|
{
|
|
814
1171
|
name: 'a cell claiming `halt-by-state`, which nothing emits, is rejected',
|
|
815
1172
|
expect: 'reject',
|