@event4u/agent-config 16.1.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 +98 -257
- 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 +5 -5
- 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/commands/work.md +4 -0
- 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/autonomy-mechanics.md +4 -8
- 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/ui-audit-gate.md +1 -2
- 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/accessibility-auditor/data/aria-patterns.csv +1 -1
- package/dist/agent-src/skills/accessibility-auditor/data/manifest.json +2 -2
- 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-review/SKILL.md +30 -4
- package/dist/agent-src/skills/design-review/references/verification-automation.md +32 -0
- package/dist/agent-src/skills/design-system-capture/references/import-procedure.md +1 -1
- package/dist/agent-src/skills/existing-ui-audit/SKILL.md +18 -3
- package/dist/agent-src/skills/existing-ui-audit/references/component-taxonomy-detection.md +56 -0
- 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/markitdown/SKILL.md +4 -0
- package/dist/agent-src/skills/monorepo-workspace/SKILL.md +1 -1
- package/dist/agent-src/skills/playwright-testing/SKILL.md +30 -6
- 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 +25 -2
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/agent-src/templates/roadmaps.md +30 -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 +302 -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/stack/runner.ts +774 -109
- 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/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-UNCRJBT3.js → chunk-JQVYKIZA.js} +41 -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-YUM5KURG.js → chunk-KR6EM23A.js} +235 -1455
- package/dist/cli-delegate/{chunk-LTYVIY76.js → chunk-LIYTLH6O.js} +1 -1
- package/dist/cli-delegate/chunk-NQ7WT43P.js +2729 -0
- 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-HDVVGPQW.js → chunk-RQNNW7IF.js} +1405 -567
- package/dist/cli-delegate/{chunk-S3VFXMTM.js → chunk-S4UMZNES.js} +1 -1
- package/dist/cli-delegate/{chunk-6KM6ORRY.js → chunk-S4YWNRKO.js} +24 -8
- package/dist/cli-delegate/{chunk-GJCBB2UG.js → chunk-TRI6DQZ6.js} +3054 -325
- 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 +1862 -809
- 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 +132 -80
- 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 +7972 -5186
- package/dist/hooks/dispatch.sha256 +1 -0
- 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 +2226 -1055
- 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 +40913 -34865
- 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 +29 -0
- package/dist/shared/skillRanking.js +74 -13
- 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/contracts/settings-classes.md +10 -6
- package/package.json +4 -4
- 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/app_spec.ts +10 -4
- package/src/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +302 -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/stack/runner.ts +774 -109
- 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 +91 -22
- package/src/config/ci-local-parity.yml +18 -0
- package/src/config/continuity-surface.json +9 -2
- package/src/config/evaluator-budgets.json +4 -4
- package/src/config/gate-coverage.yml +327 -3
- package/src/config/gate-violation-baselines.json +21 -9
- package/src/config/hook-bundle-budget.json +25 -0
- package/src/config/hook-latency-budget.json +21 -0
- package/src/config/hook-token-budget.json +8 -3
- package/src/config/host-instruction-limits.json +33 -0
- package/src/config/metric-registry.yml +114 -0
- package/src/config/placeholder-drift-budget.json +10 -0
- package/src/config/routing-coverage-seed.json +38 -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 +28 -90
- package/src/scripts/_cli/cmd_doctor_neighbours.ts +293 -0
- package/src/scripts/_cli/doctor_execution.ts +100 -17
- package/src/scripts/_cli/doctor_network_posture.ts +226 -0
- package/src/scripts/_dispatch.bash +16 -2
- package/src/scripts/_lib/agent_settings.ts +11 -0
- package/src/scripts/_lib/body_portable.ts +102 -0
- package/src/scripts/_lib/cc_transcript.ts +132 -1
- package/src/scripts/_lib/claude_settings_hooks.ts +10 -8
- package/src/scripts/_lib/concern_sla_window.ts +200 -0
- 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/forge_protection.ts +114 -0
- package/src/scripts/_lib/forge_reader.ts +558 -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_env_write.ts +111 -0
- 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/llm_proposer_transport.ts +14 -4
- 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/obligations.ts +119 -8
- package/src/scripts/_lib/probe_inputs.ts +271 -0
- package/src/scripts/_lib/prompt_shape.ts +46 -0
- package/src/scripts/_lib/read_surface_scan.ts +322 -0
- package/src/scripts/_lib/release_highlights.ts +2 -1
- package/src/scripts/_lib/release_migration_gate.ts +19 -3
- package/src/scripts/_lib/reserved_name_sweep.ts +73 -0
- package/src/scripts/_lib/retrieval_sanitize.ts +77 -16
- 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/shell_write_shapes.ts +108 -0
- package/src/scripts/_lib/skill_origin.ts +254 -0
- package/src/scripts/_lib/structural_hiding.ts +622 -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 +600 -4
- package/src/scripts/_lib/turn_end_transcript.ts +216 -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/_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/ai_team/team_dispatch.ts +4 -0
- package/src/scripts/audit_skill_overlap.ts +261 -0
- package/src/scripts/before_complete_hook.ts +573 -25
- package/src/scripts/bench_hook_latency.ts +412 -5
- package/src/scripts/bench_touched_file_quality.ts +238 -0
- 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 +621 -22
- package/src/scripts/check_estate_count.ts +130 -153
- package/src/scripts/check_finding_dispositions.ts +138 -7
- package/src/scripts/check_generator_sync.ts +71 -0
- package/src/scripts/check_hook_bundle_composition.ts +370 -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 +89 -9
- package/src/scripts/check_kill_switch_table.ts +294 -0
- package/src/scripts/check_memory.ts +7 -1
- package/src/scripts/check_placeholder_drift.ts +221 -0
- package/src/scripts/check_read_surface_coverage.ts +515 -0
- package/src/scripts/check_release_highlights.ts +10 -0
- package/src/scripts/check_release_holds.ts +2 -1
- package/src/scripts/check_release_pr_shape.ts +38 -15
- package/src/scripts/check_routing_coverage.ts +378 -11
- package/src/scripts/check_standing_rule_delivery.ts +33 -13
- package/src/scripts/check_static_parity.ts +17 -0
- package/src/scripts/check_verify_expectation_delta.ts +521 -0
- package/src/scripts/ci_settle.ts +145 -19
- package/src/scripts/closure_scan.ts +115 -1
- 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 +90 -14
- package/src/scripts/condense.ts +14 -27
- package/src/scripts/estate_exemption_shape.ts +202 -0
- package/src/scripts/external_sources_denylist.json +29 -4
- package/src/scripts/generate_host_cost_table.ts +1 -1
- package/src/scripts/hook_manifest.json +1 -1
- package/src/scripts/hook_manifest.yaml +192 -14
- package/src/scripts/hooks/block_config_weakening.ts +294 -4
- package/src/scripts/hooks/block_kernel_rule_writes.ts +9 -78
- package/src/scripts/hooks/block_plumbing_writes.ts +342 -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 +253 -25
- package/src/scripts/hooks/comment_discipline_hook.ts +1 -3
- package/src/scripts/hooks/concern_failure_policy.ts +280 -0
- package/src/scripts/hooks/concern_registry.ts +2 -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 +100 -9
- package/src/scripts/hooks/design_slop_hook.ts +1 -2
- package/src/scripts/hooks/dispatch_hook.ts +77 -71
- 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 +1 -2
- package/src/scripts/hooks/exit_codes.ts +129 -0
- package/src/scripts/hooks/host_lowering.json +1 -0
- package/src/scripts/hooks/host_lowering.ts +146 -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 +1 -2
- package/src/scripts/hooks/obligation_settle_hook.ts +151 -5
- package/src/scripts/hooks/one_question_per_ask_hook.ts +43 -6
- package/src/scripts/hooks/orchestration_record_hook.ts +1 -2
- package/src/scripts/hooks/payload_stub.ts +10 -1
- 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 +765 -68
- package/src/scripts/hooks/run_continuation_hook.ts +13 -15
- 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 +70 -0
- package/src/scripts/hooks/telemetry_flush_hook.ts +1 -2
- package/src/scripts/hooks/telemetry_usage_hook.ts +65 -10
- package/src/scripts/hooks/tool_result_bytes_hook.ts +93 -9
- package/src/scripts/hooks/turn_end_gate_hook.ts +421 -324
- package/src/scripts/hooks/ui_route_nudge_hook.ts +1 -2
- package/src/scripts/hooks_status.ts +112 -0
- package/src/scripts/injection_scan_hook.ts +7 -0
- package/src/scripts/install.ts +75 -189
- 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_deny_text.ts +419 -0
- package/src/scripts/lint_exit_codes.ts +262 -0
- package/src/scripts/lint_hook_manifest.ts +108 -0
- package/src/scripts/lint_major_migration_sections.ts +156 -26
- package/src/scripts/lint_pack_boundaries.ts +63 -5
- package/src/scripts/lint_roadmap_blockers.ts +78 -12
- package/src/scripts/lint_rule_law_section.ts +517 -0
- package/src/scripts/lint_skill_descriptions.ts +1 -1
- package/src/scripts/lint_skill_scripts_readonly.ts +1 -1
- 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/mcp_server/prompts.ts +142 -1
- package/src/scripts/measure_routing_signal.ts +54 -16
- package/src/scripts/measure_skill_ranker_baseline.ts +515 -53
- package/src/scripts/measure_turn_end_gate.ts +193 -0
- package/src/scripts/memory_learn_hook.ts +91 -6
- package/src/scripts/memory_lookup.ts +1 -1
- package/src/scripts/model_rule_injection.ts +52 -5
- package/src/scripts/prepack-check.mjs +53 -0
- package/src/scripts/project_thin_rules.ts +34 -327
- package/src/scripts/release_publication.ts +13 -1
- package/src/scripts/report_evidence_temperature.ts +657 -0
- package/src/scripts/report_installed_rule_links.ts +157 -0
- package/src/scripts/report_invocation_surface.ts +383 -0
- package/src/scripts/report_label_agreement.ts +233 -0
- package/src/scripts/report_obligation_carriers.ts +699 -0
- package/src/scripts/report_obligation_mechanism.ts +230 -0
- package/src/scripts/report_obligation_writer_split.ts +236 -0
- package/src/scripts/report_single_token_triggers.ts +277 -0
- package/src/scripts/report_skill_menu_census.ts +208 -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/roadmap_verify_share.ts +213 -0
- package/src/scripts/rule_activation_census.ts +5 -2
- package/src/scripts/rule_trigger_eval.ts +9 -9
- package/src/scripts/schemas/command.schema.json +44 -0
- package/src/scripts/schemas/review-findings.schema.json +7 -2
- package/src/scripts/schemas/rule.schema.json +5 -0
- package/src/scripts/schemas/skill.schema.json +44 -0
- package/src/scripts/self_review_gate.ts +421 -17
- package/src/scripts/semantic_parity_census.ts +314 -0
- package/src/scripts/session_eol_report.ts +54 -1
- package/src/scripts/skill_tools/score_skill_relevance.ts +290 -25
- package/src/scripts/sweep_dead_scan_roots.ts +1 -1
- 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 -7
- package/src/scripts/trigger_eval_rotation.ts +122 -27
- package/src/scripts/ui_conformance_probe.ts +156 -4
- package/src/scripts/update_prices.ts +85 -3
- package/src/scripts/write_bundle_digest.mjs +74 -0
- package/src/server/schemas/settings.ts +41 -0
- package/src/shared/skillRanking.ts +117 -11
- package/src/templates/consumer-settings/ONBOARDING.md +1 -0
- package/dist/cli-delegate/chunk-FXYUYU4N.js +0 -4416
- package/dist/cli-delegate/chunk-QJWAUMJW.js +0 -1072
- package/dist/cli-delegate/chunk-YDPILCOL.js +0 -152
- package/dist/ui/assets/index-DH1xc62v.js +0 -29
- package/dist/ui/assets/index-jSfMW8_t.css +0 -1
|
@@ -154,6 +154,8 @@ import { resolveBaseRef } from './_lib/ratchet_base_ref.js';
|
|
|
154
154
|
import { materialiseSubtree } from './_lib/base_tree.js';
|
|
155
155
|
import { SKILLS_POSIX, measureSkillEstate } from './_lib/skill_estate.js';
|
|
156
156
|
import { CONCERN_MANIFEST_POSIX, countConcerns } from './_lib/concern_estate.js';
|
|
157
|
+
import { exemptionFindings, type ExemptionFinding } from './_lib/exemption_shape.js';
|
|
158
|
+
import { classifyDiff, growthClaims, type GrowthClaim, type OffsetLedger } from './_lib/estate_offsets.js';
|
|
157
159
|
import { runGateCli, runSelfTest, type SelfTestCase } from './_lib/gate_self_test.js';
|
|
158
160
|
|
|
159
161
|
const GATE = 'check_estate_count';
|
|
@@ -301,32 +303,7 @@ export interface GrowthFinding {
|
|
|
301
303
|
allowance: number;
|
|
302
304
|
}
|
|
303
305
|
|
|
304
|
-
/** How a change touched the active roadmap tree, as git reports it. */
|
|
305
|
-
export interface OffsetLedger {
|
|
306
|
-
/** Files that entered the active top level: new files, and un-parked ones. */
|
|
307
|
-
added: string[];
|
|
308
|
-
/** Files that left it: deleted, archived, parked or merged away. */
|
|
309
|
-
offsets: string[];
|
|
310
|
-
/** Added files carrying an `estate_offset_exempt:` reason, with the reason. */
|
|
311
|
-
exempt: Array<{ file: string; reason: string }>;
|
|
312
|
-
/**
|
|
313
|
-
* The subset of `offsets` that went to `later/`.
|
|
314
|
-
*
|
|
315
|
-
* Tracked separately because parking is the one offset that RAISES another
|
|
316
|
-
* gated count: active falls by one and later rises by one, which under an
|
|
317
|
-
* exact floor is growth in `later_roadmaps` unless this allowance exists.
|
|
318
|
-
* Kept out of a general "any offset raises any allowance" rule on purpose —
|
|
319
|
-
* an archived roadmap must not buy a new `later/` file.
|
|
320
|
-
*/
|
|
321
|
-
parked: string[];
|
|
322
|
-
}
|
|
323
306
|
|
|
324
|
-
/** An `estate_growth_exempt:` reason ADDED to a roadmap in this change. */
|
|
325
|
-
export interface GrowthClaim {
|
|
326
|
-
/** The roadmap the claim was added to, as git reports the path. */
|
|
327
|
-
file: string;
|
|
328
|
-
reason: string;
|
|
329
|
-
}
|
|
330
307
|
|
|
331
308
|
export interface EstateVerdict {
|
|
332
309
|
counts: EstateCounts;
|
|
@@ -362,6 +339,23 @@ export interface EstateVerdict {
|
|
|
362
339
|
offsets: OffsetLedger | null;
|
|
363
340
|
offsetSkipReason: string | null;
|
|
364
341
|
unpaid: number;
|
|
342
|
+
/**
|
|
343
|
+
* Added exemptions whose reason names no rejected alternative, or repeats
|
|
344
|
+
* another added file's. Empty on every change that adds no exemption.
|
|
345
|
+
*/
|
|
346
|
+
exemptionFindings: ExemptionFinding[];
|
|
347
|
+
/**
|
|
348
|
+
* Roadmaps carrying an unscheduled status — REPORTED, never gated.
|
|
349
|
+
*
|
|
350
|
+
* `collect()` excludes them by design, so a draft is invisible to every
|
|
351
|
+
* count above and adding one costs no slot. That is the right policy: a
|
|
352
|
+
* draft is not active work, and charging for one would make every parked
|
|
353
|
+
* idea cost a slot. What was wrong was that the number was invisible too, so
|
|
354
|
+
* a reader of `active_roadmaps 26` could not tell an estate of 26 from an
|
|
355
|
+
* estate of 26 with 14 drafts behind it. It contributes nothing to
|
|
356
|
+
* `withinBudget` — there is no floor for it and no claim path to it.
|
|
357
|
+
*/
|
|
358
|
+
draftRoadmaps: number;
|
|
365
359
|
/**
|
|
366
360
|
* The provisional-promotion path's state, reported and never acted on.
|
|
367
361
|
*
|
|
@@ -513,143 +507,51 @@ export function countEstate(repoRoot: string): EstateCounts {
|
|
|
513
507
|
};
|
|
514
508
|
}
|
|
515
509
|
|
|
516
|
-
/** Did the tokeniser resolve under `root`? A ratchet must not mix the two modes. */
|
|
517
|
-
export function skillTokensExact(root: string): boolean {
|
|
518
|
-
return measureSkillEstate(root).skill_description_tokens !== null;
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
/** `agents/roadmaps/<name>.md` — the active top level. code-comment-allow provenance-comment -- operand, not provenance */
|
|
522
|
-
function isActiveTopLevel(rel: string): boolean {
|
|
523
|
-
const norm = rel.split(path.sep).join('/');
|
|
524
|
-
if (!norm.startsWith('agents/roadmaps/') || !norm.endsWith('.md')) {
|
|
525
|
-
return false;
|
|
526
|
-
}
|
|
527
|
-
const tail = norm.slice('agents/roadmaps/'.length);
|
|
528
|
-
return !tail.includes('/') && isRoadmapCandidate(norm);
|
|
529
|
-
}
|
|
530
|
-
|
|
531
510
|
/**
|
|
532
|
-
*
|
|
511
|
+
* Top-level roadmaps `collect()` drops for an unscheduled status.
|
|
533
512
|
*
|
|
534
|
-
*
|
|
535
|
-
*
|
|
536
|
-
*
|
|
537
|
-
*
|
|
538
|
-
*
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
const norm = rel.split(path.sep).join('/');
|
|
542
|
-
return /^agents\/roadmaps\/(archive|later|skipped|stubs)\//.test(norm);
|
|
543
|
-
}
|
|
544
|
-
|
|
545
|
-
/** A roadmap parked for later — the one disposition that grows another count. */
|
|
546
|
-
function isParked(rel: string): boolean {
|
|
547
|
-
return rel.split(path.sep).join('/').startsWith('agents/roadmaps/later/');
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
/**
|
|
551
|
-
* Read the exemption reason a newly added roadmap declares, if any.
|
|
513
|
+
* Reported beside the count, never added to it. The exclusion in `collect()` is
|
|
514
|
+
* deliberate and stays: a draft is not active work, and counting one would make
|
|
515
|
+
* every parked idea cost a slot under one-in-one-out. What the exclusion also
|
|
516
|
+
* did, silently, was make the drafts unreadable — the estate report showed
|
|
517
|
+
* `active_roadmaps 26` whether 0 or 14 drafts sat beside them. This closes the
|
|
518
|
+
* reporting half and nothing else, so it has no floor, no allowance and no
|
|
519
|
+
* claim path: it cannot fail.
|
|
552
520
|
*
|
|
553
|
-
*
|
|
554
|
-
*
|
|
555
|
-
*
|
|
556
|
-
* it, and a reviewer sees it without being told to look.
|
|
521
|
+
* `isUnscheduled` is the same predicate `collect()` filters on, so this count
|
|
522
|
+
* and that exclusion cannot disagree — a second status list here is how a
|
|
523
|
+
* reported number starts describing a different set from the one it explains.
|
|
557
524
|
*/
|
|
558
|
-
export function
|
|
559
|
-
const
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
525
|
+
export function countDrafts(repoRoot: string): number {
|
|
526
|
+
const dir = path.join(repoRoot, ROADMAPS_REL);
|
|
527
|
+
let names: string[];
|
|
528
|
+
try {
|
|
529
|
+
names = fs.readdirSync(dir);
|
|
530
|
+
} catch {
|
|
531
|
+
return 0;
|
|
563
532
|
}
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
* `later/road-to-x.md` → `road-to-x.md` is an un-parking and counts as an
|
|
574
|
-
* addition. A top-level-to-top-level rename is neither.
|
|
575
|
-
*/
|
|
576
|
-
export function classifyDiff(
|
|
577
|
-
nameStatus: string,
|
|
578
|
-
readFile: (rel: string) => string | null,
|
|
579
|
-
): OffsetLedger {
|
|
580
|
-
const added: string[] = [];
|
|
581
|
-
const offsets: string[] = [];
|
|
582
|
-
const exempt: Array<{ file: string; reason: string }> = [];
|
|
583
|
-
const parked: string[] = [];
|
|
584
|
-
for (const line of nameStatus.split('\n')) {
|
|
585
|
-
if (line.trim() === '') continue;
|
|
586
|
-
const cols = line.split('\t');
|
|
587
|
-
const status = (cols[0] ?? '').trim();
|
|
588
|
-
if (status.startsWith('R') || status.startsWith('C')) {
|
|
589
|
-
const from = cols[1] ?? '';
|
|
590
|
-
const to = cols[2] ?? '';
|
|
591
|
-
if (isActiveTopLevel(from) && isDisposed(to)) {
|
|
592
|
-
offsets.push(from);
|
|
593
|
-
if (isParked(to)) parked.push(to);
|
|
594
|
-
} else if (isDisposed(from) && isActiveTopLevel(to)) {
|
|
595
|
-
added.push(to);
|
|
596
|
-
}
|
|
533
|
+
let n = 0;
|
|
534
|
+
for (const name of names) {
|
|
535
|
+
if (!name.endsWith('.md') || !isRoadmapCandidate(name)) continue;
|
|
536
|
+
const abs = path.join(dir, name);
|
|
537
|
+
let text: string;
|
|
538
|
+
try {
|
|
539
|
+
if (!fs.statSync(abs).isFile()) continue;
|
|
540
|
+
text = fs.readFileSync(abs, 'utf-8');
|
|
541
|
+
} catch {
|
|
597
542
|
continue;
|
|
598
543
|
}
|
|
599
|
-
|
|
600
|
-
if (!isActiveTopLevel(file)) continue;
|
|
601
|
-
if (status === 'A') {
|
|
602
|
-
added.push(file);
|
|
603
|
-
} else if (status === 'D') {
|
|
604
|
-
offsets.push(file);
|
|
605
|
-
}
|
|
606
|
-
}
|
|
607
|
-
for (const file of added) {
|
|
608
|
-
const text = readFile(file);
|
|
609
|
-
if (text === null) continue;
|
|
610
|
-
const reason = exemptionReason(text);
|
|
611
|
-
if (reason !== null) {
|
|
612
|
-
exempt.push({ file, reason });
|
|
613
|
-
}
|
|
544
|
+
if (isUnscheduled(parseFrontmatter(text))) n += 1;
|
|
614
545
|
}
|
|
615
|
-
return
|
|
546
|
+
return n;
|
|
616
547
|
}
|
|
617
548
|
|
|
618
|
-
/**
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
* Read from the diff rather than from the file, and that is the point: a claim
|
|
622
|
-
* sitting in a roadmap authorises nothing on a later change, so an exemption
|
|
623
|
-
* cannot be banked the way surplus in a stored baseline could. It also means a
|
|
624
|
-
* newly added roadmap and an edited one need no separate handling — in a
|
|
625
|
-
* `base...HEAD` patch both arrive as `+` lines.
|
|
626
|
-
*
|
|
627
|
-
* `--unified=0` keeps context lines out, so a claim that merely sits NEAR an
|
|
628
|
-
* edited line is not read as added. Deliberately tolerant of leading whitespace
|
|
629
|
-
* and of quoted values, matching `exemptionReason`; deliberately NOT tolerant of
|
|
630
|
-
* an empty reason, because an exemption whose reason is blank is the silent
|
|
631
|
-
* exception the key exists to replace.
|
|
632
|
-
*/
|
|
633
|
-
export function growthClaims(patch: string): GrowthClaim[] {
|
|
634
|
-
const out: GrowthClaim[] = [];
|
|
635
|
-
let file = '';
|
|
636
|
-
for (const line of patch.split('\n')) {
|
|
637
|
-
// `+++ b/<path>` names the file the following `+` lines belong to. The
|
|
638
|
-
// `/dev/null` form is a deletion, which cannot carry a claim.
|
|
639
|
-
const head = /^\+\+\+ b\/(.+)$/.exec(line);
|
|
640
|
-
if (head !== null) {
|
|
641
|
-
file = (head[1] ?? '').trim();
|
|
642
|
-
continue;
|
|
643
|
-
}
|
|
644
|
-
if (!line.startsWith('+') || line.startsWith('+++')) continue;
|
|
645
|
-
const m = /^\+\s*estate_growth_exempt:\s*(.+?)\s*$/.exec(line);
|
|
646
|
-
if (m === null) continue;
|
|
647
|
-
const reason = (m[1] ?? '').trim().replace(/^["']|["']$/g, '').trim();
|
|
648
|
-
if (reason !== '') out.push({ file, reason });
|
|
649
|
-
}
|
|
650
|
-
return out;
|
|
549
|
+
/** Did the tokeniser resolve under `root`? A ratchet must not mix the two modes. */
|
|
550
|
+
export function skillTokensExact(root: string): boolean {
|
|
551
|
+
return measureSkillEstate(root).skill_description_tokens !== null;
|
|
651
552
|
}
|
|
652
553
|
|
|
554
|
+
|
|
653
555
|
export function evaluate(
|
|
654
556
|
repoRoot: string,
|
|
655
557
|
opts: { baseRef?: string | undefined } = {},
|
|
@@ -816,6 +718,13 @@ export function evaluate(
|
|
|
816
718
|
unpaid = Math.max(0, chargeable.length - offsets.offsets.length);
|
|
817
719
|
}
|
|
818
720
|
|
|
721
|
+
// The SHAPE half, and it is deliberately not gated on `lintApplies`. The
|
|
722
|
+
// threshold decides whether an unoffset addition is charged; it says nothing
|
|
723
|
+
// about whether a claim an author chose to write has to mean something. An
|
|
724
|
+
// exemption below the threshold buys nothing anyway, so a shapeless one
|
|
725
|
+
// below it is a line that will be read as a reason later and is not one.
|
|
726
|
+
const findings = offsets === null ? [] : exemptionFindings(offsets.exempt);
|
|
727
|
+
|
|
819
728
|
// The allowances, one metric at a time and never a blanket rule. An exempt
|
|
820
729
|
// addition and a parked roadmap are the two increases the existing policy
|
|
821
730
|
// already sanctions, and under an exact floor each needs its own headroom or
|
|
@@ -883,13 +792,15 @@ export function evaluate(
|
|
|
883
792
|
offsets,
|
|
884
793
|
offsetSkipReason,
|
|
885
794
|
unpaid,
|
|
795
|
+
exemptionFindings: findings,
|
|
796
|
+
draftRoadmaps: countDrafts(repoRoot),
|
|
886
797
|
provisionalPromotion,
|
|
887
798
|
// No floor is a FAILURE, not a skip, and it is the one place this gate
|
|
888
799
|
// convicts on a missing input. The other halves can report "unproven" and
|
|
889
800
|
// still leave a meaningful verdict behind; the count half IS the verdict,
|
|
890
801
|
// so with no floor a green here would assert something nothing measured.
|
|
891
802
|
// A shrink-only gate whose floor is absent passes every possible tree.
|
|
892
|
-
withinBudget: floorSkipReason === null && growth.length === 0 && unpaid === 0,
|
|
803
|
+
withinBudget: floorSkipReason === null && growth.length === 0 && unpaid === 0 && findings.length === 0,
|
|
893
804
|
};
|
|
894
805
|
}
|
|
895
806
|
|
|
@@ -1104,10 +1015,44 @@ function selfTest(): number {
|
|
|
1104
1015
|
write(
|
|
1105
1016
|
dir,
|
|
1106
1017
|
'agents/roadmaps/road-to-new.md',
|
|
1107
|
-
'---\nestate_offset_exempt: fixture —
|
|
1018
|
+
'---\nestate_offset_exempt: fixture — archiving road-to-0 was rejected, it is mid-flight\n---\n\n' +
|
|
1019
|
+
roadmap('N'),
|
|
1108
1020
|
),
|
|
1109
1021
|
}),
|
|
1110
1022
|
},
|
|
1023
|
+
{
|
|
1024
|
+
// The shape half. The old reason here was "the addition that cannot
|
|
1025
|
+
// be offset", which names no alternative and is exactly what this
|
|
1026
|
+
// case now refuses — so the pair above and below are the same
|
|
1027
|
+
// addition differing only in what its reason says.
|
|
1028
|
+
name: 'exemption naming no rejected alternative → reject',
|
|
1029
|
+
expect: 'reject',
|
|
1030
|
+
run: () =>
|
|
1031
|
+
fixture({
|
|
1032
|
+
roadmaps: 3,
|
|
1033
|
+
base: 'main',
|
|
1034
|
+
after: (dir) =>
|
|
1035
|
+
write(
|
|
1036
|
+
dir,
|
|
1037
|
+
'agents/roadmaps/road-to-new.md',
|
|
1038
|
+
'---\nestate_offset_exempt: fixture — lane 5 of road-to-parent\n---\n\n' + roadmap('N'),
|
|
1039
|
+
),
|
|
1040
|
+
}),
|
|
1041
|
+
},
|
|
1042
|
+
{
|
|
1043
|
+
name: 'one exemption reason pasted into two added files → reject',
|
|
1044
|
+
expect: 'reject',
|
|
1045
|
+
run: () =>
|
|
1046
|
+
fixture({
|
|
1047
|
+
roadmaps: 3,
|
|
1048
|
+
base: 'main',
|
|
1049
|
+
after: (dir) => {
|
|
1050
|
+
const fm = '---\nestate_offset_exempt: fixture — archiving road-to-0 was rejected, it is mid-flight\n---\n\n';
|
|
1051
|
+
write(dir, 'agents/roadmaps/road-to-n1.md', fm + roadmap('N1'));
|
|
1052
|
+
write(dir, 'agents/roadmaps/road-to-n2.md', fm + roadmap('N2'));
|
|
1053
|
+
},
|
|
1054
|
+
}),
|
|
1055
|
+
},
|
|
1111
1056
|
{
|
|
1112
1057
|
name: 'addition paid for by an archive move → accept',
|
|
1113
1058
|
expect: 'accept',
|
|
@@ -1319,7 +1264,7 @@ export function main(argv: string[] = process.argv.slice(2)): number {
|
|
|
1319
1264
|
}
|
|
1320
1265
|
|
|
1321
1266
|
const ledger = new GateLedger(GATE);
|
|
1322
|
-
ledger.plan([...METRICS, 'floor', 'one_in_one_out']);
|
|
1267
|
+
ledger.plan([...METRICS, 'floor', 'one_in_one_out', 'exemption_shape']);
|
|
1323
1268
|
for (const metric of METRICS) {
|
|
1324
1269
|
// Round 2 finding 3, kept: a metric is recorded ONCE here, for whichever
|
|
1325
1270
|
// way it actually failed, so the ledger cannot show a green completeness
|
|
@@ -1335,6 +1280,10 @@ export function main(argv: string[] = process.argv.slice(2)): number {
|
|
|
1335
1280
|
if (verdict.offsets === null) ledger.skip('one_in_one_out', 'precondition_unmet');
|
|
1336
1281
|
else if (verdict.unpaid > 0) ledger.fail('one_in_one_out', `${String(verdict.unpaid)} unpaid addition(s)`);
|
|
1337
1282
|
else ledger.complete('one_in_one_out');
|
|
1283
|
+
if (verdict.offsets === null) ledger.skip('exemption_shape', 'precondition_unmet');
|
|
1284
|
+
else if (verdict.exemptionFindings.length > 0)
|
|
1285
|
+
ledger.fail('exemption_shape', `${String(verdict.exemptionFindings.length)} unshaped exemption(s)`);
|
|
1286
|
+
else ledger.complete('exemption_shape');
|
|
1338
1287
|
|
|
1339
1288
|
if (json) {
|
|
1340
1289
|
// The ledger goes to stderr here so stdout stays parseable after the
|
|
@@ -1358,6 +1307,12 @@ export function main(argv: string[] = process.argv.slice(2)): number {
|
|
|
1358
1307
|
` ${metric.padEnd(18)} ${String(live).padStart(5)} (floor ${String(base)} at ${verdict.floorRef ?? '?'}, ${sign}${String(delta)})\n`,
|
|
1359
1308
|
);
|
|
1360
1309
|
}
|
|
1310
|
+
// Beside the gated counts, never among them: no floor line, no delta, and
|
|
1311
|
+
// the label says what it is. A reader comparing two runs can see the drafts
|
|
1312
|
+
// move without reading this as a ratchet that moved.
|
|
1313
|
+
process.stdout.write(
|
|
1314
|
+
` ${'draft_roadmaps'.padEnd(18)} ${String(verdict.draftRoadmaps).padStart(5)} (reported, not gated — excluded from active_roadmaps)\n`,
|
|
1315
|
+
);
|
|
1361
1316
|
if (verdict.offsets !== null) {
|
|
1362
1317
|
const o = verdict.offsets;
|
|
1363
1318
|
process.stdout.write(
|
|
@@ -1435,6 +1390,28 @@ export function main(argv: string[] = process.argv.slice(2)): number {
|
|
|
1435
1390
|
' that costs one reviewable line instead of a silent exception.\n',
|
|
1436
1391
|
);
|
|
1437
1392
|
}
|
|
1393
|
+
|
|
1394
|
+
for (const f of verdict.exemptionFindings) {
|
|
1395
|
+
if (f.kind === 'shapeless') {
|
|
1396
|
+
process.stderr.write(
|
|
1397
|
+
`❌ ${f.file}: estate_offset_exempt names no rejected alternative.\n` +
|
|
1398
|
+
` reason: ${f.reason.slice(0, 160)}\n` +
|
|
1399
|
+
' The exemption is the escape hatch from one-in-one-out, so its reason has to\n' +
|
|
1400
|
+
' say what you considered INSTEAD of adding a file — archiving something,\n' +
|
|
1401
|
+
' parking it in `later/`, merging into an existing roadmap — and why that was\n' +
|
|
1402
|
+
' not available. Name the disposition you rejected. Measured over the existing\n' +
|
|
1403
|
+
' 221 exemptions, 43 name none; this check applies to ADDED files only, so\n' +
|
|
1404
|
+
' nothing already in the tree is re-read.\n',
|
|
1405
|
+
);
|
|
1406
|
+
} else {
|
|
1407
|
+
process.stderr.write(
|
|
1408
|
+
`❌ ${f.file}: estate_offset_exempt repeats ${f.twin ?? '(another added file)'} verbatim.\n` +
|
|
1409
|
+
` reason: ${f.reason.slice(0, 160)}\n` +
|
|
1410
|
+
' One sentence pasted into every file a round adds is one claim, not N. Write\n' +
|
|
1411
|
+
' the reason this FILE could not be offset, or offset the ones that could.\n',
|
|
1412
|
+
);
|
|
1413
|
+
}
|
|
1414
|
+
}
|
|
1438
1415
|
ledger.report();
|
|
1439
1416
|
if (verdict.withinBudget) {
|
|
1440
1417
|
process.stdout.write(`✅ ${GATE}: estate within its ratchet.\n`);
|
|
@@ -75,6 +75,7 @@ import * as path from 'node:path';
|
|
|
75
75
|
import process from 'node:process';
|
|
76
76
|
import { fileURLToPath } from 'node:url';
|
|
77
77
|
|
|
78
|
+
import { coverageLabel } from './_lib/review_coverage.js';
|
|
78
79
|
import { DeadScopeError, reportScanned } from './_lib/scan_scope.js';
|
|
79
80
|
|
|
80
81
|
const _HERE = fileURLToPath(import.meta.url);
|
|
@@ -84,6 +85,27 @@ export const LEDGER_DIR = 'agents/evidence/release-findings';
|
|
|
84
85
|
export const DISPOSITION_STATUSES = ['fixed', 'false_positive', 'accepted_risk'] as const;
|
|
85
86
|
export type DispositionStatus = (typeof DISPOSITION_STATUSES)[number];
|
|
86
87
|
|
|
88
|
+
/**
|
|
89
|
+
* Every status that means a human re-read the finding and decided.
|
|
90
|
+
*
|
|
91
|
+
* `still_open` is the fourth, and it exists so that "give every row a terminal
|
|
92
|
+
* status" does not read as "close every finding". A row re-checked against the
|
|
93
|
+
* merged head and found to be a real, unfixed issue is adjudicated; writing
|
|
94
|
+
* `accepted_risk` over it to make a count reach zero would be the cheapest way
|
|
95
|
+
* to satisfy the requirement and the one that destroys it.
|
|
96
|
+
*
|
|
97
|
+
* It is deliberately NOT in {@link DISPOSITION_STATUSES}: a BLOCKING row may
|
|
98
|
+
* never pass on it. `missing_dispositions` reads only the three, so a blocking
|
|
99
|
+
* finding marked `still_open` reports as an unknown status and the gate stays
|
|
100
|
+
* red — which is the behaviour a blocking finding that is still open should
|
|
101
|
+
* have.
|
|
102
|
+
*
|
|
103
|
+
* `open` from the schema is absent on purpose. The schema documents it as the
|
|
104
|
+
* INITIAL state, so counting it would make the tally reachable without anyone
|
|
105
|
+
* re-reading a finding.
|
|
106
|
+
*/
|
|
107
|
+
export const TERMINAL_STATUSES = [...DISPOSITION_STATUSES, 'still_open'] as const;
|
|
108
|
+
|
|
87
109
|
export interface LedgerFinding {
|
|
88
110
|
finding_id: string;
|
|
89
111
|
severity: 'critical' | 'high' | 'medium' | 'low';
|
|
@@ -95,6 +117,12 @@ export interface LedgerFinding {
|
|
|
95
117
|
rationale?: string;
|
|
96
118
|
verified_by?: string;
|
|
97
119
|
date?: string;
|
|
120
|
+
/**
|
|
121
|
+
* The tree's mechanical disproof of the finding's premise, written by
|
|
122
|
+
* `self_review_gate.annotateContradicted`. A finding carrying one is not
|
|
123
|
+
* blocking — see `isBlocking`.
|
|
124
|
+
*/
|
|
125
|
+
contradicted?: string;
|
|
98
126
|
}
|
|
99
127
|
|
|
100
128
|
export interface Ledger {
|
|
@@ -114,6 +142,12 @@ export interface Ledger {
|
|
|
114
142
|
assurance?: string;
|
|
115
143
|
reviewers?: string[];
|
|
116
144
|
coverage?: unknown;
|
|
145
|
+
/**
|
|
146
|
+
* Per-run count of findings quoting a supplied fact, written by
|
|
147
|
+
* `self_review_gate` under `--findings-out`. Declared here because ingest
|
|
148
|
+
* now carries it; see {@link INTEGRITY_FIELDS}.
|
|
149
|
+
*/
|
|
150
|
+
fact_claims?: unknown;
|
|
117
151
|
}
|
|
118
152
|
|
|
119
153
|
/**
|
|
@@ -133,7 +167,7 @@ export interface Ledger {
|
|
|
133
167
|
* consumer inferring it from the findings would be inventing the integrity
|
|
134
168
|
* claim the fields exist to record.
|
|
135
169
|
*/
|
|
136
|
-
|
|
170
|
+
const SCHEMA_INTEGRITY_FIELDS = [
|
|
137
171
|
'review_independence',
|
|
138
172
|
'context_relation',
|
|
139
173
|
'acceptance_status',
|
|
@@ -142,6 +176,24 @@ export const INTEGRITY_FIELDS = [
|
|
|
142
176
|
'coverage',
|
|
143
177
|
] as const;
|
|
144
178
|
|
|
179
|
+
/**
|
|
180
|
+
* The carried set: the six above plus `fact_claims`.
|
|
181
|
+
*
|
|
182
|
+
* `fact_claims` is written by `self_review_gate.ts` at `--findings-out` time and
|
|
183
|
+
* was dropped by every ingest, because this list predates it. The field is the
|
|
184
|
+
* falsifier for the supplied-facts change — a count over the next cut — and a
|
|
185
|
+
* falsifier that never reaches the record is not one. It is carried rather than
|
|
186
|
+
* recomputed for the same reason the other six are: only the producing run knows
|
|
187
|
+
* what it quoted.
|
|
188
|
+
*
|
|
189
|
+
* It is NOT in {@link SCHEMA_INTEGRITY_FIELDS}, which is the set the ingest
|
|
190
|
+
* warning names. That warning tells a writer that `check_review_schema` derives
|
|
191
|
+
* `acceptance_status` and `assurance` from `review_independence` and will red on
|
|
192
|
+
* a ledger declaring neither — a sentence that is simply untrue of `fact_claims`,
|
|
193
|
+
* and naming it there would make the warning wrong to buy one shorter list.
|
|
194
|
+
*/
|
|
195
|
+
export const INTEGRITY_FIELDS = [...SCHEMA_INTEGRITY_FIELDS, 'fact_claims'] as const;
|
|
196
|
+
|
|
145
197
|
/**
|
|
146
198
|
* Merge a self-review artifact into a ledger: new findings by id, the integrity
|
|
147
199
|
* fields on first write, and — when the review found nothing — the reason that
|
|
@@ -220,8 +272,21 @@ function _clean_review_reason(artifact: Record<string, unknown>): string {
|
|
|
220
272
|
);
|
|
221
273
|
}
|
|
222
274
|
|
|
223
|
-
/**
|
|
224
|
-
|
|
275
|
+
/**
|
|
276
|
+
* Mirrors self_review_gate.classifyBlocking — security/claim × critical/high,
|
|
277
|
+
* MINUS anything the tree disproved.
|
|
278
|
+
*
|
|
279
|
+
* The `contradicted` clause is not a second policy; it is the same one, and
|
|
280
|
+
* the mirror has to carry it or the two gates disagree: the review would stop
|
|
281
|
+
* counting a disproved deletion claim as blocking while the release kept
|
|
282
|
+
* demanding a disposition for it. A `contradicted` value is written only by
|
|
283
|
+
* `annotateContradicted`, which checks the claim against
|
|
284
|
+
* `git diff --name-status base...HEAD` AND the working tree.
|
|
285
|
+
*/
|
|
286
|
+
export function isBlocking(f: Pick<LedgerFinding, 'kind' | 'severity' | 'contradicted'>): boolean {
|
|
287
|
+
if ((f.contradicted ?? '').trim() !== '') {
|
|
288
|
+
return false;
|
|
289
|
+
}
|
|
225
290
|
return (
|
|
226
291
|
(f.kind === 'security' || f.kind === 'claim') &&
|
|
227
292
|
(f.severity === 'critical' || f.severity === 'high')
|
|
@@ -263,6 +328,66 @@ export function missing_dispositions(findings: readonly LedgerFinding[]): string
|
|
|
263
328
|
return problems;
|
|
264
329
|
}
|
|
265
330
|
|
|
331
|
+
/** What the success line reports, counted over the two populations apart. */
|
|
332
|
+
export interface DispositionTally {
|
|
333
|
+
/** Rows `isBlocking` admits. */
|
|
334
|
+
readonly blockingTotal: number;
|
|
335
|
+
/** Of those, the ones `missing_dispositions` finds nothing wrong with. */
|
|
336
|
+
readonly blockingDispositioned: number;
|
|
337
|
+
/** Every other row. The gate cannot fail on these; it can still count them. */
|
|
338
|
+
readonly nonBlockingTotal: number;
|
|
339
|
+
/** Of those, the ones carrying a {@link TERMINAL_STATUSES} value. */
|
|
340
|
+
readonly nonBlockingTerminal: number;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
* Count what the gate checked, split by what it can actually require.
|
|
345
|
+
*
|
|
346
|
+
* The recorded failure this exists for: `--release 16.2.0` printed "all 20
|
|
347
|
+
* recorded finding(s) for 16.2.0 dispositioned (blocking ones completely)" over
|
|
348
|
+
* a ledger carrying a `status` on 2 of 20 rows. Both halves of that sentence are
|
|
349
|
+
* individually defensible — the gate did require the blocking ones, and it did
|
|
350
|
+
* complete — and together they say the opposite of the truth, because nobody
|
|
351
|
+
* reads a parenthetical as a retraction of the word in front of it. Eighteen
|
|
352
|
+
* findings had never been adjudicated and the record said they had.
|
|
353
|
+
*
|
|
354
|
+
* The fix is a count, not a new refusal. Exit semantics are untouched: a
|
|
355
|
+
* non-blocking row still cannot fail the gate. What changes is that the line
|
|
356
|
+
* stops claiming the rows it never looked at.
|
|
357
|
+
*
|
|
358
|
+
* An unrecognised status counts as NOT terminal, which is the conservative
|
|
359
|
+
* direction: a typo surfaces as a row the line says is unadjudicated, rather
|
|
360
|
+
* than disappearing into a count that reads as finished.
|
|
361
|
+
*/
|
|
362
|
+
export function disposition_tally(findings: readonly LedgerFinding[]): DispositionTally {
|
|
363
|
+
let blockingTotal = 0;
|
|
364
|
+
let blockingDispositioned = 0;
|
|
365
|
+
let nonBlockingTotal = 0;
|
|
366
|
+
let nonBlockingTerminal = 0;
|
|
367
|
+
for (const f of findings) {
|
|
368
|
+
if (isBlocking(f)) {
|
|
369
|
+
blockingTotal++;
|
|
370
|
+
if (missing_dispositions([f]).length === 0) {
|
|
371
|
+
blockingDispositioned++;
|
|
372
|
+
}
|
|
373
|
+
continue;
|
|
374
|
+
}
|
|
375
|
+
nonBlockingTotal++;
|
|
376
|
+
if ((TERMINAL_STATUSES as readonly string[]).includes((f.status ?? '').trim())) {
|
|
377
|
+
nonBlockingTerminal++;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
return { blockingTotal, blockingDispositioned, nonBlockingTotal, nonBlockingTerminal };
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
/** The tally as the success line renders it. Never the word "all". */
|
|
384
|
+
export function disposition_summary(t: DispositionTally): string {
|
|
385
|
+
return (
|
|
386
|
+
`blocking ${String(t.blockingDispositioned)}/${String(t.blockingTotal)} dispositioned · ` +
|
|
387
|
+
`non-blocking ${String(t.nonBlockingTerminal)}/${String(t.nonBlockingTotal)} carry a terminal status`
|
|
388
|
+
);
|
|
389
|
+
}
|
|
390
|
+
|
|
266
391
|
/**
|
|
267
392
|
* An empty finding set must say why it is empty.
|
|
268
393
|
*
|
|
@@ -413,7 +538,7 @@ export function resolve_release_status(release: string): ReleaseStatus {
|
|
|
413
538
|
|
|
414
539
|
/** Findings the gate comment reported but the ledger never ingested. */
|
|
415
540
|
export function unrecorded_findings(
|
|
416
|
-
reported: ReadonlyArray<Pick<LedgerFinding, 'finding_id' | 'severity' | 'kind' | 'title'>>,
|
|
541
|
+
reported: ReadonlyArray<Pick<LedgerFinding, 'finding_id' | 'severity' | 'kind' | 'title' | 'contradicted'>>,
|
|
417
542
|
ledger: readonly LedgerFinding[],
|
|
418
543
|
): string[] {
|
|
419
544
|
const known = new Set(ledger.map((f) => f.finding_id));
|
|
@@ -558,7 +683,7 @@ function main(argv: readonly string[]): number {
|
|
|
558
683
|
'ledger is a result rather than an absence\n',
|
|
559
684
|
);
|
|
560
685
|
}
|
|
561
|
-
const absent =
|
|
686
|
+
const absent = SCHEMA_INTEGRITY_FIELDS.filter((k) => ledger[k] === undefined);
|
|
562
687
|
if (absent.length > 0) {
|
|
563
688
|
process.stdout.write(
|
|
564
689
|
`⚠️ artifact carried no ${absent.join(', ')} — ` +
|
|
@@ -656,10 +781,16 @@ function main(argv: readonly string[]): number {
|
|
|
656
781
|
|
|
657
782
|
if (problems.length === 0) {
|
|
658
783
|
const n = ledger.findings.length;
|
|
784
|
+
// The label is appended to BOTH lines, including the zero-findings one:
|
|
785
|
+
// a review that read 65 of 678 files and reported nothing is the case
|
|
786
|
+
// where "no findings" is least informative on its own.
|
|
787
|
+
const partial = coverageLabel(ledger.coverage);
|
|
788
|
+
const suffix = partial === null ? '' : ` — ${partial}`;
|
|
659
789
|
process.stdout.write(
|
|
660
790
|
n === 0
|
|
661
|
-
? `✅ no recorded findings for ${release} (ledger ${fs.existsSync(ledgerPath) ? 'empty' : 'absent'})\n`
|
|
662
|
-
: `✅
|
|
791
|
+
? `✅ no recorded findings for ${release} (ledger ${fs.existsSync(ledgerPath) ? 'empty' : 'absent'})${suffix}\n`
|
|
792
|
+
: `✅ ${String(n)} recorded finding(s) for ${release} — ` +
|
|
793
|
+
`${disposition_summary(disposition_tally(ledger.findings))}${suffix}\n`,
|
|
663
794
|
);
|
|
664
795
|
return 0;
|
|
665
796
|
}
|