@event4u/agent-config 14.12.0 → 14.13.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 +234 -0
- package/CONTRIBUTING.md +38 -0
- package/CREDITS.md +135 -0
- package/NOTICE +13 -0
- package/README.md +8 -6
- package/dist/agent-src/commands/analyze/inbox.md +109 -2
- package/dist/agent-src/commands/feature/dev.md +7 -2
- package/dist/agent-src/commands/ghostwriter/write.md +5 -1
- package/dist/agent-src/commands/implement-ticket.md +1 -1
- package/dist/agent-src/commands/mission/upgrade.md +1 -1
- package/dist/agent-src/commands/orchestrate.md +2 -2
- package/dist/agent-src/commands/post-as/me.md +5 -1
- package/dist/agent-src/commands/pr/merge.md +19 -6
- package/dist/agent-src/commands/roadmap/process-full.md +19 -5
- package/dist/agent-src/commands/tdd/red.md +12 -2
- package/dist/agent-src/commands/work.md +1 -1
- package/dist/agent-src/contexts/communication/rules-auto/token-efficiency-mechanics.md +40 -0
- package/dist/agent-src/contexts/execution/auto-dispatch-classification.md +5 -2
- package/dist/agent-src/contexts/execution/autonomy-mechanics.md +21 -0
- package/dist/agent-src/contexts/execution/orchestration-telemetry.md +1 -0
- package/dist/agent-src/contexts/execution/subagent-response-contract.md +40 -0
- package/dist/agent-src/contexts/execution/subagent-steering.md +13 -1
- package/dist/agent-src/contexts/execution/terminal-states.md +96 -0
- package/dist/agent-src/rules/artifact-drafting-protocol.md +1 -1
- package/dist/agent-src/rules/broken-access-control.md +4 -0
- package/dist/agent-src/rules/code-provenance.md +4 -0
- package/dist/agent-src/rules/design-fidelity.md +1 -1
- package/dist/agent-src/rules/domain-safety-pii.md +4 -0
- package/dist/agent-src/rules/domain-safety-retention.md +4 -0
- package/dist/agent-src/rules/engineering-safety-floor.md +2 -0
- package/dist/agent-src/rules/external-code-graph-interop.md +14 -12
- package/dist/agent-src/rules/improve-before-implement.md +6 -8
- package/dist/agent-src/rules/laravel-routing.md +1 -1
- package/dist/agent-src/rules/lethal-trifecta-guard.md +4 -0
- package/dist/agent-src/rules/secret-vcs-guard.md +2 -0
- package/dist/agent-src/rules/security-sensitive-stop.md +2 -0
- package/dist/agent-src/rules/source-confidentiality.md +12 -34
- package/dist/agent-src/rules/symfony-routing.md +1 -1
- package/dist/agent-src/rules/token-efficiency.md +14 -0
- package/dist/agent-src/rules/tool-safety.md +4 -0
- package/dist/agent-src/rules/untrusted-input-defense.md +4 -0
- package/dist/agent-src/scripts/archive_completed_roadmaps.ts +247 -3
- package/dist/agent-src/scripts/guarded_baseline.ts +328 -0
- package/dist/agent-src/scripts/roadmap_set_step.ts +253 -0
- package/dist/agent-src/scripts/stub_queue.ts +82 -0
- package/dist/agent-src/scripts/stubs_due.ts +400 -0
- package/dist/agent-src/scripts/ticket_bundles.ts +84 -0
- package/dist/agent-src/scripts/update_roadmap_progress.ts +8 -4
- package/dist/agent-src/skills/brand-asset-generation/SKILL.md +17 -4
- package/dist/agent-src/skills/brand-audit/SKILL.md +33 -0
- package/dist/agent-src/skills/code-intelligence/SKILL.md +57 -0
- package/dist/agent-src/skills/database/SKILL.md +8 -0
- package/dist/agent-src/skills/dependency-upgrade/SKILL.md +27 -0
- package/dist/agent-src/skills/design-review/SKILL.md +1 -1
- package/dist/agent-src/skills/doc-coauthoring/SKILL.md +1 -1
- package/dist/agent-src/skills/existing-ui-audit/SKILL.md +17 -1
- package/dist/agent-src/skills/feature-planning/SKILL.md +9 -2
- package/dist/agent-src/skills/frontend-render-security/SKILL.md +44 -0
- package/dist/agent-src/skills/git-workflow/SKILL.md +1 -1
- package/dist/agent-src/skills/js-library-packaging/scripts/check_package_surface.ts +38 -4
- package/dist/agent-src/skills/judge-artifact-completeness/rubrics/ticket-quality-score.json +2 -2
- package/dist/agent-src/skills/laravel/SKILL.md +35 -0
- package/dist/agent-src/skills/laravel-migration/SKILL.md +57 -3
- package/dist/agent-src/skills/monorepo-workspace/SKILL.md +26 -0
- package/dist/agent-src/skills/playbook-authoring/SKILL.md +28 -1
- package/dist/agent-src/skills/react-shadcn-ui/SKILL.md +1 -1
- package/dist/agent-src/skills/skill-writing/references/procedure.md +5 -5
- package/dist/agent-src/skills/sql-writing/SKILL.md +7 -1
- package/dist/agent-src/skills/standards-from-config/SKILL.md +27 -4
- package/dist/agent-src/skills/supply-chain-intake/SKILL.md +11 -4
- package/dist/agent-src/skills/symfony-workflow/SKILL.md +35 -0
- package/dist/agent-src/skills/test-case-discovery/SKILL.md +85 -0
- package/dist/agent-src/skills/test-driven-development/SKILL.md +33 -9
- package/dist/agent-src/skills/testing-anti-patterns/SKILL.md +1 -1
- package/dist/agent-src/skills/testing-anti-patterns/process-anti-patterns.md +37 -0
- package/dist/agent-src/skills/ui-component-architect/SKILL.md +45 -2
- package/dist/agent-src/skills/upstream-contribute/SKILL.md +38 -1
- package/dist/agent-src/skills/verify-repair-loop/SKILL.md +9 -4
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/agent-src/templates/roadmaps.md +97 -3
- package/dist/agent-src/templates/scripts/check_memory.ts +258 -17
- package/dist/agent-src/templates/scripts/check_memory_proposal.ts +9 -3
- package/dist/agent-src/templates/scripts/memory_lookup.ts +86 -0
- package/dist/agent-src/templates/scripts/memory_signal.ts +44 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/backend/implement.ts +90 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/backend/index.ts +11 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/backend/test.ts +23 -1
- package/dist/agent-src/templates/scripts/work_engine/directives/backend/verify.ts +10 -1
- package/dist/agent-src/templates/scripts/work_engine/directives/mixed/stitch.ts +5 -1
- package/dist/agent-src/templates/scripts/work_engine/stack/runner.ts +102 -14
- package/dist/cli/commands/uiAudit.js +124 -5
- package/dist/cli/registry.js +2 -0
- package/dist/cli-delegate/{chunk-HYWSRNUX.js → chunk-2DK2VJWG.js} +3 -3
- package/dist/cli-delegate/{chunk-JCW7ZLHK.js → chunk-4FS4WRXP.js} +5 -0
- package/dist/cli-delegate/{chunk-OMIVVCG2.js → chunk-A4QJ6ENT.js} +24 -0
- package/dist/cli-delegate/{chunk-JJA2QEWA.js → chunk-AKJGUQNO.js} +466 -285
- package/dist/cli-delegate/{chunk-E46KPN6K.js → chunk-BTWUYDGN.js} +424 -363
- package/dist/cli-delegate/{chunk-K4FFODTS.js → chunk-ILMUPLGW.js} +1227 -316
- package/dist/cli-delegate/{chunk-FF7WAFMR.js → chunk-KPBWFOPZ.js} +5 -1
- package/dist/cli-delegate/cmd_adr_effective.js +102 -0
- package/dist/cli-delegate/cmd_conformance.js +42 -10
- package/dist/cli-delegate/cmd_doctor.js +3 -3
- package/dist/cli-delegate/cmd_export.js +3 -2
- package/dist/cli-delegate/cmd_fleet.js +2 -2
- package/dist/cli-delegate/cmd_handoff.js +1 -1
- package/dist/cli-delegate/cmd_preflight.js +2 -2
- package/dist/cli-delegate/cmd_prune.js +3 -2
- package/dist/cli-delegate/cmd_settings_get.js +1 -1
- package/dist/cli-delegate/cmd_settings_migrate.js +3 -2
- package/dist/cli-delegate/cmd_settings_set.js +2 -2
- package/dist/cli-delegate/cmd_sync.js +3 -2
- package/dist/cli-delegate/cmd_uninstall.js +3 -2
- package/dist/cli-delegate/cmd_validate.js +3 -2
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +57 -57
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +1 -1
- package/dist/discovery/dormancy-report.md +1 -1
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +2 -2
- package/dist/discovery/trust-report.md +1 -1
- package/dist/discovery/workspaces.json +2 -2
- package/dist/hooks/dispatch.js +1836 -712
- package/dist/install/claudeRuleRewrite.js +254 -0
- package/dist/install/detect.js +29 -16
- package/dist/install/detect_php_shape.js +159 -0
- package/dist/install/install.mjs +634 -428
- package/dist/mcp/awesome-mcp-servers.row.md +1 -1
- package/dist/mcp/mcp-cloudflare-catalogue.json +1 -1
- package/dist/mcp/registry-manifest.json +3 -3
- package/dist/mcp/server.json +3 -3
- package/dist/mcp/server.mjs +4818 -2645
- package/dist/server/schemas/settings.js +3 -0
- package/dist/ui/assets/index-D0jaCRPM.js +29 -0
- package/dist/ui/index.html +1 -1
- package/docs/MIGRATION.md +1 -1
- package/docs/THIRD-PARTY-NOTICES.md +25 -0
- package/docs/contracts/provider-lifecycle.md +1 -1
- package/docs/contracts/settings-classes.md +10 -4
- package/docs/guidelines/agent-infra/5w2h-analysis.md +3 -3
- package/docs/guidelines/agent-infra/agent-interaction-and-decision-quality.md +1 -0
- package/docs/guidelines/agent-infra/artifact-drafting-protocol-mechanics.md +58 -3
- package/docs/guidelines/agent-infra/ask-when-uncertain-demos.md +2 -2
- package/docs/guidelines/agent-infra/asking-and-brevity-examples.md +3 -3
- package/docs/guidelines/agent-infra/break-glass-usage.md +7 -7
- package/docs/guidelines/agent-infra/carve-out-predicates.md +3 -3
- package/docs/guidelines/agent-infra/comparison-matrix.md +1 -1
- package/docs/guidelines/agent-infra/critical-thinking.md +4 -4
- package/docs/guidelines/agent-infra/direct-answers-demos.md +2 -2
- package/docs/guidelines/agent-infra/domain-eval-anti-pattern.md +1 -1
- package/docs/guidelines/agent-infra/engineering-memory-data-format.md +3 -3
- package/docs/guidelines/agent-infra/existence-question-verdicts.md +80 -0
- package/docs/guidelines/agent-infra/first-principles.md +2 -2
- package/docs/guidelines/agent-infra/framework-neutrality-patterns.md +2 -2
- package/docs/guidelines/agent-infra/guarded-baseline.md +39 -0
- package/docs/guidelines/agent-infra/inversion-thinking.md +5 -5
- package/docs/guidelines/agent-infra/language-and-tone-examples.md +1 -1
- package/docs/guidelines/agent-infra/layered-settings.md +10 -10
- package/docs/guidelines/agent-infra/memory-access.md +1 -1
- package/docs/guidelines/agent-infra/mental-models.md +3 -3
- package/docs/guidelines/agent-infra/reuse-verdict-mechanics.md +71 -0
- package/docs/guidelines/agent-infra/review-routing-data-format.md +7 -7
- package/docs/guidelines/agent-infra/roadmap-progress-mechanics.md +13 -7
- package/docs/guidelines/agent-infra/role-contracts.md +2 -2
- package/docs/guidelines/agent-infra/role-mode-router.md +3 -3
- package/docs/guidelines/agent-infra/rule-type-governance.md +2 -2
- package/docs/guidelines/agent-infra/scqa-framework.md +5 -5
- package/docs/guidelines/agent-infra/self-improvement-pipeline.md +6 -6
- package/docs/guidelines/agent-infra/simplicity-and-goal-demos.md +2 -2
- package/docs/guidelines/agent-infra/six-hats.md +3 -3
- package/docs/guidelines/agent-infra/skill-quality-checklist.md +6 -6
- package/docs/guidelines/agent-infra/source-confidentiality-mechanics.md +109 -0
- package/docs/guidelines/agent-infra/systems-thinking.md +1 -1
- package/docs/guidelines/agent-infra/verify-before-complete-demos.md +2 -2
- package/docs/guidelines/augment-portability-patterns.md +6 -4
- package/docs/guidelines/component-oriented-and-oop-development.md +3 -2
- package/docs/guidelines/cross-role-handoff.md +2 -2
- package/docs/guidelines/design-fidelity-mechanics.md +1 -1
- package/docs/guidelines/docs/readme-size-and-splitting.md +3 -3
- package/docs/guidelines/php/database.md +90 -7
- package/docs/guidelines/prompt-templates.md +7 -7
- package/llms.txt +2 -2
- package/package.json +5 -2
- package/src/agent-src/scripts/archive_completed_roadmaps.ts +247 -3
- package/src/agent-src/scripts/guarded_baseline.ts +328 -0
- package/src/agent-src/scripts/roadmap_set_step.ts +253 -0
- package/src/agent-src/scripts/stub_queue.ts +82 -0
- package/src/agent-src/scripts/stubs_due.ts +400 -0
- package/src/agent-src/scripts/ticket_bundles.ts +84 -0
- package/src/agent-src/scripts/update_roadmap_progress.ts +8 -4
- package/src/agent-src/templates/scripts/check_memory.ts +258 -17
- package/src/agent-src/templates/scripts/check_memory_proposal.ts +9 -3
- package/src/agent-src/templates/scripts/memory_lookup.ts +86 -0
- package/src/agent-src/templates/scripts/memory_signal.ts +44 -0
- package/src/agent-src/templates/scripts/work_engine/directives/backend/implement.ts +90 -0
- package/src/agent-src/templates/scripts/work_engine/directives/backend/index.ts +11 -0
- package/src/agent-src/templates/scripts/work_engine/directives/backend/test.ts +23 -1
- package/src/agent-src/templates/scripts/work_engine/directives/backend/verify.ts +10 -1
- package/src/agent-src/templates/scripts/work_engine/directives/mixed/stitch.ts +5 -1
- package/src/agent-src/templates/scripts/work_engine/stack/runner.ts +102 -14
- package/src/config/agent-settings.template.yml +32 -3
- package/src/config/assurance-capability-registry.json +21 -9
- package/src/config/canonical-terms.yml +119 -0
- package/src/config/capability-native-outcome-bars.json +81 -0
- package/src/config/ci-local-parity.yml +80 -0
- package/src/config/drafting-channels.yml +43 -0
- package/src/config/estate-count-budget.json +38 -36
- package/src/config/evaluator-budgets.json +14 -14
- package/src/config/gate-coverage.yml +579 -63
- package/src/config/gate-reachability-exemptions.json +21 -0
- package/src/config/gate-violation-baselines.json +37 -19
- package/src/config/harness-evolution-budget.json +25 -0
- package/src/config/lapsed-beta-baseline.json +96 -0
- package/src/config/memory-twin-verdicts.yml +129 -0
- package/src/config/metric-registry.yml +124 -0
- package/src/config/pack-size-budget.json +16 -15
- package/src/config/preamble-payload-budget.json +8 -8
- package/src/config/profiles/balanced.ini +27 -0
- package/src/config/profiles/full.ini +27 -0
- package/src/config/profiles/minimal.ini +27 -0
- package/src/config/publish-surface.json +9 -2
- package/src/config/routing-coverage-seed.json +16 -2
- package/src/config/rule-stub-ceilings.json +126 -112
- package/src/config/turnaround-budget.json +66 -0
- package/src/install/claudeRuleRewrite.ts +288 -0
- package/src/install/detect.ts +60 -17
- package/src/install/detect_php_shape.ts +191 -0
- package/src/scripts/_cli/cmd_doctor.ts +27 -112
- package/src/scripts/_dispatch.bash +27 -0
- package/src/scripts/_lib/activation_ladder.ts +211 -0
- package/src/scripts/_lib/activation_states.ts +88 -0
- package/src/scripts/_lib/adherence_detectors.ts +143 -0
- package/src/scripts/_lib/arith_claims.ts +181 -0
- package/src/scripts/_lib/arm_ranking.ts +62 -0
- package/src/scripts/_lib/asset_delivery_ledger.ts +303 -0
- package/src/scripts/_lib/audit_field_provenance.ts +54 -0
- package/src/scripts/_lib/auto_dispatch.ts +32 -3
- package/src/scripts/_lib/bench_ab_size_claim.ts +98 -4
- package/src/scripts/_lib/benchmark_cache_fields.ts +158 -0
- package/src/scripts/_lib/candidate_proposer.ts +402 -0
- package/src/scripts/_lib/candidate_record.ts +601 -0
- package/src/scripts/_lib/capture_rate.ts +319 -0
- package/src/scripts/_lib/collector_denominator.ts +771 -0
- package/src/scripts/_lib/collector_record.ts +340 -0
- package/src/scripts/_lib/collector_store.ts +664 -0
- package/src/scripts/_lib/collector_supervision.ts +827 -0
- package/src/scripts/_lib/concern_estate.ts +77 -0
- package/src/scripts/_lib/config_chain.ts +477 -0
- package/src/scripts/_lib/config_cost.ts +209 -0
- package/src/scripts/_lib/council_settings_block.ts +6 -0
- package/src/scripts/_lib/curator_ops.ts +172 -0
- package/src/scripts/_lib/delivery_arm_experiment.ts +266 -0
- package/src/scripts/_lib/delivery_criticality.ts +126 -0
- package/src/scripts/_lib/doctor_runtime_checks.ts +70 -0
- package/src/scripts/_lib/empty_cycles.ts +88 -0
- package/src/scripts/_lib/eval_publication.ts +354 -0
- package/src/scripts/_lib/evaluation_vector.ts +283 -0
- package/src/scripts/_lib/evaluator_promotion.ts +225 -0
- package/src/scripts/_lib/evidence_basis.ts +118 -0
- package/src/scripts/_lib/exec_evidence.ts +8 -0
- package/src/scripts/_lib/experience_card.ts +272 -0
- package/src/scripts/_lib/experience_report.ts +151 -0
- package/src/scripts/_lib/experiment_freeze.ts +112 -0
- package/src/scripts/_lib/generated_by.ts +66 -0
- package/src/scripts/_lib/harness_evolution_guards.ts +229 -0
- package/src/scripts/_lib/hook_effect_probe.ts +141 -0
- package/src/scripts/_lib/host_denominator.ts +687 -0
- package/src/scripts/_lib/host_projection_reach.ts +157 -0
- package/src/scripts/_lib/ignored_blocker.ts +148 -0
- package/src/scripts/_lib/install_reach_checks.ts +495 -0
- package/src/scripts/_lib/json_duplicate_keys.ts +150 -0
- package/src/scripts/_lib/judge_hygiene.ts +228 -0
- package/src/scripts/_lib/legacy_boundary_map.ts +228 -0
- package/src/scripts/_lib/loop_guards.ts +299 -0
- package/src/scripts/_lib/loss_class.ts +129 -0
- package/src/scripts/_lib/machine_wake.ts +51 -0
- package/src/scripts/_lib/md_prose_lines.ts +177 -0
- package/src/scripts/_lib/minimality_tiebreak.ts +168 -0
- package/src/scripts/_lib/one_resolver_invariant.ts +449 -0
- package/src/scripts/_lib/orchestration_record.ts +253 -5
- package/src/scripts/_lib/outcome_envelope.ts +227 -0
- package/src/scripts/_lib/outcome_vocabularies.ts +125 -0
- package/src/scripts/_lib/paired_stats.ts +245 -0
- package/src/scripts/_lib/paired_verdict.ts +226 -0
- package/src/scripts/_lib/prefix_stable_surfaces.ts +123 -0
- package/src/scripts/_lib/privacy_class.ts +47 -0
- package/src/scripts/_lib/regression_neighbourhood.ts +259 -0
- package/src/scripts/_lib/repeated_failure.ts +105 -0
- package/src/scripts/_lib/repo_root.ts +111 -0
- package/src/scripts/_lib/review_skipped_record.ts +37 -0
- package/src/scripts/_lib/role_split.ts +338 -0
- package/src/scripts/_lib/runtime_journal.ts +1499 -0
- package/src/scripts/_lib/runtime_wiring_checks.ts +430 -0
- package/src/scripts/_lib/skill_catalogue.ts +11 -1
- package/src/scripts/_lib/source_digest.ts +200 -0
- package/src/scripts/_lib/source_redact.ts +260 -0
- package/src/scripts/_lib/source_shape.ts +502 -0
- package/src/scripts/_lib/source_snapshot_dedup.ts +199 -0
- package/src/scripts/_lib/strip_comments.d.mts +8 -0
- package/src/scripts/_lib/strip_comments.mjs +65 -0
- package/src/scripts/_lib/test_red_state.ts +154 -0
- package/src/scripts/_lib/trigger_shift.ts +144 -0
- package/src/scripts/_lib/untrusted_content.ts +82 -7
- package/src/scripts/adoption_report.ts +1 -1
- package/src/scripts/adr/evidence_census.ts +1 -1
- package/src/scripts/adr/regenerate_index.ts +26 -2
- package/src/scripts/adr_cite_check.ts +164 -1
- package/src/scripts/ai_council/blind_review.ts +11 -1
- package/src/scripts/ai_council/clients.ts +4 -0
- package/src/scripts/ai_council/config.ts +3 -0
- package/src/scripts/ai_council/consensus.ts +28 -8
- package/src/scripts/ai_council/consensus_round.ts +226 -0
- package/src/scripts/ai_council/disagreement_signal.ts +338 -0
- package/src/scripts/ai_council/inline_findings.ts +340 -0
- package/src/scripts/ai_council/judge_position_bias.ts +197 -0
- package/src/scripts/ai_council/orchestrator.ts +16 -203
- package/src/scripts/ai_council/orchestrator_results.ts +23 -3
- package/src/scripts/ai_council/pricing.ts +106 -0
- package/src/scripts/ai_council/prompts.ts +74 -7
- package/src/scripts/ai_council/provider_leakage_bench.ts +327 -0
- package/src/scripts/ai_council/py_format.ts +14 -3
- package/src/scripts/ai_council/recouncil_guard.ts +293 -0
- package/src/scripts/ai_council/response_record.ts +50 -0
- package/src/scripts/ai_council/topology_bench_manifest.ts +860 -0
- package/src/scripts/ai_council/topology_vocabulary.ts +175 -0
- package/src/scripts/asset_delivery_ledger.ts +157 -0
- package/src/scripts/attest_artifact.ts +193 -0
- package/src/scripts/audit_auto_rules.ts +2 -1
- package/src/scripts/audit_command_surface.ts +1 -1
- package/src/scripts/audit_mcp_tools.ts +2 -2
- package/src/scripts/audit_skill_overlap_allowlist.json +6 -1
- package/src/scripts/audit_user_type_axis.ts +2 -1
- package/src/scripts/bench_ab_clone.ts +215 -10
- package/src/scripts/bench_ab_integrity.ts +119 -5
- package/src/scripts/bench_ab_v2_stats.ts +40 -213
- package/src/scripts/build_archive_index.ts +1 -1
- package/src/scripts/build_linear_digest.ts +1 -1
- package/src/scripts/build_proof.ts +11 -4
- package/src/scripts/build_rule_trigger_matrix.ts +1 -1
- package/src/scripts/build_source_digests.ts +157 -0
- package/src/scripts/cache_realization_report.ts +103 -0
- package/src/scripts/check_adr_frontmatter.ts +126 -0
- package/src/scripts/check_benchmark_report_fields.ts +207 -0
- package/src/scripts/check_beta_review_markers.ts +235 -6
- package/src/scripts/check_bundle_path_leakage.ts +34 -1
- package/src/scripts/check_claims.ts +576 -6
- package/src/scripts/check_composite_arming.ts +35 -0
- package/src/scripts/check_concern_admissions.ts +365 -0
- package/src/scripts/check_enforcement_coverage.ts +28 -0
- package/src/scripts/check_estate_count.ts +142 -1
- package/src/scripts/check_gate_reachability.ts +383 -0
- package/src/scripts/check_host_loadability.ts +104 -0
- package/src/scripts/check_loss_class_declared.ts +308 -0
- package/src/scripts/check_md_language.ts +15 -98
- package/src/scripts/check_memory_proposal.ts +18 -11
- package/src/scripts/check_no_currency_in_cost_surfaces.ts +225 -0
- package/src/scripts/check_no_external_sources.ts +281 -6
- package/src/scripts/check_pack_conformance_fixture.ts +11 -1
- package/src/scripts/check_pack_size.ts +59 -2
- package/src/scripts/check_preamble_payload_budget.ts +114 -3
- package/src/scripts/check_prefix_stable_mutation.ts +372 -0
- package/src/scripts/check_publish_surface.ts +10 -1
- package/src/scripts/check_references.ts +24 -1
- package/src/scripts/check_rule_evidence_declaration.ts +316 -0
- package/src/scripts/check_rule_projection_integrity.ts +14 -4
- package/src/scripts/check_score_contract.ts +26 -3
- package/src/scripts/check_static_parity.ts +285 -0
- package/src/scripts/check_supervision_claim_atomicity.ts +498 -0
- package/src/scripts/check_suppression_hygiene.ts +15 -0
- package/src/scripts/ci_settle.ts +39 -2
- package/src/scripts/code_graph/build.ts +60 -3
- package/src/scripts/code_graph/extract.ts +44 -0
- package/src/scripts/code_graph/types.ts +24 -0
- package/src/scripts/collector_daemon.ts +714 -0
- package/src/scripts/config_cost_report.ts +302 -0
- package/src/scripts/consumer_matrix.ts +74 -1
- package/src/scripts/cost/budget.mjs +10 -3
- package/src/scripts/cost/track.mjs +10 -3
- package/src/scripts/council_cli.ts +37 -54
- package/src/scripts/dispatch_r2_reviewer.ts +46 -5
- package/src/scripts/evolution_lab.ts +980 -0
- package/src/scripts/external_sources_denylist.json +5 -18
- package/src/scripts/extract_audit_patterns.ts +21 -0
- package/src/scripts/fold_intake.ts +12 -1
- package/src/scripts/gen_discovery_baseline.ts +1 -1
- package/src/scripts/generate_capabilities_index.ts +12 -5
- package/src/scripts/generate_capability_matrix.ts +3 -3
- package/src/scripts/generate_command_flows.ts +2 -2
- package/src/scripts/generate_cookbook.ts +2 -2
- package/src/scripts/generate_index.ts +8 -1
- package/src/scripts/generate_knowledge_index.ts +2 -1
- package/src/scripts/generate_ownership_matrix.ts +2 -1
- package/src/scripts/generate_pack_manifests.ts +10 -2
- package/src/scripts/generate_role_experiences_catalog.ts +2 -2
- package/src/scripts/generate_settings_reference.ts +1 -1
- package/src/scripts/git_authorization_hook.ts +22 -1
- package/src/scripts/grade_target_readiness.ts +48 -5
- package/src/scripts/hook_effect_doctor.ts +261 -0
- package/src/scripts/hook_manifest.json +1 -1
- package/src/scripts/hook_manifest.yaml +98 -11
- package/src/scripts/hooks/block_speaking_inbox_dir.ts +271 -0
- package/src/scripts/hooks/block_unauthorized_git.ts +18 -0
- package/src/scripts/hooks/concern_registry.ts +4 -0
- package/src/scripts/hooks/dispatch_hook.ts +32 -0
- package/src/scripts/hooks/journal_record_hook.ts +345 -0
- package/src/scripts/hooks/prepush_metadata_sources.sh +110 -0
- package/src/scripts/hooks/run_continuation_hook.ts +44 -9
- package/src/scripts/hooks/shims/install.sh +61 -0
- package/src/scripts/hooks/shims/php +101 -0
- package/src/scripts/hooks/suggestion_capture_hook.ts +10 -0
- package/src/scripts/hot_context_hook.ts +16 -0
- package/src/scripts/install-hooks.sh +20 -5
- package/src/scripts/install.ts +17 -35
- package/src/scripts/inventory_frontmatter.ts +2 -1
- package/src/scripts/lint_adr_sweep_routing.ts +12 -0
- package/src/scripts/lint_canonical_terms.ts +604 -0
- package/src/scripts/lint_composition_review.ts +619 -0
- package/src/scripts/lint_consolidation_lineage.ts +666 -0
- package/src/scripts/lint_eval_specs.ts +593 -0
- package/src/scripts/lint_hook_manifest.ts +19 -0
- package/src/scripts/lint_host_portability.ts +373 -0
- package/src/scripts/lint_judge_prompt_expectation.ts +27 -1
- package/src/scripts/lint_memory_twin_parity.ts +335 -0
- package/src/scripts/lint_metric_consumers.ts +355 -0
- package/src/scripts/lint_skill_descriptions.ts +18 -1
- package/src/scripts/lint_skill_frontmatter_safety.ts +58 -0
- package/src/scripts/lint_skill_link_reach.ts +252 -0
- package/src/scripts/lint_skill_trigger_corpus.ts +426 -23
- package/src/scripts/lint_ticket_buildable.ts +17 -1
- package/src/scripts/mcp_server/consumer_tool_catalog.json +1 -1
- package/src/scripts/mcp_server/tool_catalog_source.ts +1 -1
- package/src/scripts/measure_docs_dead_links.ts +348 -0
- package/src/scripts/measure_host_capture.ts +461 -0
- package/src/scripts/migration_status.ts +3 -3
- package/src/scripts/model_rule_injection.ts +60 -0
- package/src/scripts/orchestration_record.ts +14 -0
- package/src/scripts/preamble_byte_census.ts +139 -10
- package/src/scripts/prepack-check.mjs +4 -1
- package/src/scripts/probe_turnaround.ts +384 -0
- package/src/scripts/probe_unblocked_ask.ts +279 -0
- package/src/scripts/render_benchmark_md.ts +1 -1
- package/src/scripts/rule_activation_census.ts +70 -9
- package/src/scripts/rule_backlinks.ts +1 -1
- package/src/scripts/run_lifecycle_suite.ts +208 -0
- package/src/scripts/run_skill_evals.ts +40 -0
- package/src/scripts/schemas/delivery-manifest.schema.json +43 -0
- package/src/scripts/schemas/drafting-channels.schema.json +43 -0
- package/src/scripts/schemas/evals.schema.json +24 -1
- package/src/scripts/schemas/rule.schema.json +52 -1
- package/src/scripts/schemas/skill.schema.json +17 -2
- package/src/scripts/skill_overlap.ts +7 -1
- package/src/scripts/skill_tools/run_block_d_eval.ts +8 -1
- package/src/scripts/skill_tools/score_skill_relevance.ts +84 -3
- package/src/scripts/skill_tools/suggest_skill_for_task.ts +8 -1
- package/src/scripts/skill_usage_report.ts +2 -1
- package/src/scripts/stubs_due.ts +211 -0
- package/src/scripts/sweep_source_surfaces.ts +678 -0
- package/src/scripts/sync_pr_branch.ts +3 -3
- package/src/scripts/trigger_eval_grandfather.json +202 -222
- package/src/scripts/utilization_report.ts +22 -2
- package/src/server/schemas/settings.ts +5 -0
- package/src/templates/marketing-copy.yml +1 -1
- package/dist/ui/assets/index-Cxgy63kz.js +0 -26
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `guarded-baseline` — the third machine-readable step state, and its evidence
|
|
3
|
+
* contract (AI council 2026-08-31, 2/2 convergent: anthropic/claude-sonnet-4-5 +
|
|
4
|
+
* openai/codex-default, option C).
|
|
5
|
+
*
|
|
6
|
+
* A roadmap step whose `verify:` asserts a property of a mechanism that DOES NOT
|
|
7
|
+
* YET EXIST may not close `[x]` — that overstates the evidence. It keeps the
|
|
8
|
+
* canonical unchecked box, carries an annotation, and carries a structured
|
|
9
|
+
* evidence record next to it:
|
|
10
|
+
*
|
|
11
|
+
* - [ ] <!-- roadmap-status: guarded-baseline -->
|
|
12
|
+
* **7.3** …step text…
|
|
13
|
+
* ```yaml
|
|
14
|
+
* guarded_baseline:
|
|
15
|
+
* category: future-mechanism
|
|
16
|
+
* scope: src/scripts/ai_council/**
|
|
17
|
+
* command: npx vitest run tests/scripts/x.test.ts
|
|
18
|
+
* red_proof: sabotage run 2026-08-31 — 2 failed
|
|
19
|
+
* sabotage_model: added a `--topology` flag to the option table
|
|
20
|
+
* recheck_when: src/scripts/ai_council/topology_selector.ts
|
|
21
|
+
* discharged_ac: the baseline is pinned and RED-proven
|
|
22
|
+
* pending_ac: the constraint under real topology selection
|
|
23
|
+
* ```
|
|
24
|
+
*
|
|
25
|
+
* BOTH SEATS MADE THE TOOLING A CONDITION OF THE VERDICT — "C is acceptable only
|
|
26
|
+
* if its tooling lands atomically; otherwise use ordinary `[ ]` with structured
|
|
27
|
+
* evidence" — so the annotation is worth nothing without the five semantics
|
|
28
|
+
* below, and they live here rather than duplicated in the two consumers:
|
|
29
|
+
*
|
|
30
|
+
* 1. reported separately and NEVER counted as done — the canonical box stays
|
|
31
|
+
* `[ ]`, so `count_checkboxes` already excludes it; `reportGuardedBaselines`
|
|
32
|
+
* is the separate surface that makes the state visible rather than silent;
|
|
33
|
+
* 2. `archive_completed_roadmaps` treats it as incomplete and refuses archival;
|
|
34
|
+
* 3. a `recheck_when` trigger that now RESOLVES in the tree marks the evidence
|
|
35
|
+
* STALE — the guard was written against an absence that has since ended;
|
|
36
|
+
* 4. only verification against the real mechanism permits `[x]`;
|
|
37
|
+
* 5. a baseline that has not demonstrably gone RED is an ordinary open item —
|
|
38
|
+
* hence `red_proof` is mandatory and its absence REJECTS the annotation.
|
|
39
|
+
*
|
|
40
|
+
* The two legal categories are the council's own split. An `absence-assertion`
|
|
41
|
+
* step asserts something directly observable today and MAY close `[x]` once
|
|
42
|
+
* sabotage-verified; a `future-mechanism` step is what this state exists for. No
|
|
43
|
+
* third value is accepted and absence is not defaulted: defaulting would silently
|
|
44
|
+
* promote the strict case into the lax one, which is the overstatement the whole
|
|
45
|
+
* verdict is against.
|
|
46
|
+
*/
|
|
47
|
+
|
|
48
|
+
import * as fs from 'node:fs';
|
|
49
|
+
import * as path from 'node:path';
|
|
50
|
+
|
|
51
|
+
/** The annotation itself. Tolerant of internal spacing, nothing else. */
|
|
52
|
+
export const GUARDED_BASELINE_RE = /<!--[ \t]*roadmap-status:[ \t]*guarded-baseline[ \t]*-->/;
|
|
53
|
+
|
|
54
|
+
/** The only two legal `category:` values — see the header on why absence is not a default. */
|
|
55
|
+
export const GUARDED_CATEGORIES: readonly string[] = ['future-mechanism', 'absence-assertion'];
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* `- [<glyph>] …` at any indent, with `-` or `*`.
|
|
59
|
+
*
|
|
60
|
+
* Deliberately neither of the two checkbox patterns already in this directory:
|
|
61
|
+
* the dashboard's `CHECKBOX_RE` is `g`-sticky and requires trailing whitespace,
|
|
62
|
+
* and the sweep's `DEFERRED_STEP_RE` pins `[~]`. This one has to CAPTURE the
|
|
63
|
+
* glyph an annotation sits on — including `[x]` — because refusing that case is
|
|
64
|
+
* the whole point of the validator below.
|
|
65
|
+
*/
|
|
66
|
+
const ANY_CHECKBOX_RE = /^[ \t]*[-*][ \t]+\[([ xX~-])\]/;
|
|
67
|
+
|
|
68
|
+
/** A following step or any heading ends the annotated step's span. */
|
|
69
|
+
const SPAN_END_RE = /^[ \t]*[-*][ \t]+\[[ xX~-]\]|^#{1,6}[ \t]/;
|
|
70
|
+
|
|
71
|
+
const BLOCK_START_RE = /^[ \t]*guarded_baseline:[ \t]*$/;
|
|
72
|
+
const FIELD_RE = /^[ \t]*([a-z_]+):[ \t]*(.*)$/;
|
|
73
|
+
const FENCE_RE = /^[ \t]*(?:```|~~~)/;
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* A record annotates a STEP, so it is only recognised on a list item.
|
|
77
|
+
*
|
|
78
|
+
* Measured, not defensive: without this the very roadmap that SPECIFIES this
|
|
79
|
+
* state reddened its own dashboard, because its verdict paragraph names the
|
|
80
|
+
* annotation in prose. Same discipline `parse_blockers` already applies with
|
|
81
|
+
* `_stripFencedCode` — a documentation example of a shape is not an instance of
|
|
82
|
+
* it — extended to the two prose forms that actually occur, an inline code span
|
|
83
|
+
* and a fenced example.
|
|
84
|
+
*/
|
|
85
|
+
const LIST_ITEM_RE = /^[ \t]*[-*][ \t]+/;
|
|
86
|
+
const INLINE_CODE_RE = /`[^`]*`/g;
|
|
87
|
+
|
|
88
|
+
/** One annotated step, as both consumers need it. */
|
|
89
|
+
export interface GuardedBaselineItem {
|
|
90
|
+
/** 1-based line of the annotated line, for the messages. */
|
|
91
|
+
line: number;
|
|
92
|
+
/** Step text, from the annotated line or its first continuation line. */
|
|
93
|
+
label: string;
|
|
94
|
+
/**
|
|
95
|
+
* The checkbox glyph the annotation actually sits on, or `null` when the
|
|
96
|
+
* annotation is not on a checkbox line at all. Both non-`' '` and `null` are
|
|
97
|
+
* rejections — recorded rather than normalised, so the message can say which.
|
|
98
|
+
*/
|
|
99
|
+
glyph: string | null;
|
|
100
|
+
/** Did the span carry a `guarded_baseline:` block at all? */
|
|
101
|
+
hasBlock: boolean;
|
|
102
|
+
fields: Readonly<Record<string, string>>;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function _label(annotatedLine: string, lines: readonly string[], i: number): string {
|
|
106
|
+
const own = annotatedLine
|
|
107
|
+
.replace(ANY_CHECKBOX_RE, '')
|
|
108
|
+
.replace(GUARDED_BASELINE_RE, '')
|
|
109
|
+
.replace(/\*\*/g, '')
|
|
110
|
+
.trim();
|
|
111
|
+
if (own !== '') {
|
|
112
|
+
return own;
|
|
113
|
+
}
|
|
114
|
+
// The council's mechanical form puts the step text on the NEXT line.
|
|
115
|
+
for (let j = i + 1; j < lines.length; j++) {
|
|
116
|
+
const next = (lines[j] as string).trim();
|
|
117
|
+
if (next === '') {
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
if (SPAN_END_RE.test(lines[j] as string)) {
|
|
121
|
+
break;
|
|
122
|
+
}
|
|
123
|
+
return next.replace(/\*\*/g, '').trim();
|
|
124
|
+
}
|
|
125
|
+
return '(unlabelled)';
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/** Every `guarded-baseline`-annotated step in one roadmap, with its evidence block. */
|
|
129
|
+
export function parseGuardedBaselines(text: string): GuardedBaselineItem[] {
|
|
130
|
+
const lines = text.split('\n');
|
|
131
|
+
const out: GuardedBaselineItem[] = [];
|
|
132
|
+
let inFence = false;
|
|
133
|
+
for (let i = 0; i < lines.length; i++) {
|
|
134
|
+
const raw = lines[i] as string;
|
|
135
|
+
if (FENCE_RE.test(raw)) {
|
|
136
|
+
inFence = !inFence;
|
|
137
|
+
}
|
|
138
|
+
// Inside a fence it is an example; inside backticks it is prose; off a
|
|
139
|
+
// list item it is not a step at all. See LIST_ITEM_RE for the measurement.
|
|
140
|
+
if (inFence || !LIST_ITEM_RE.test(raw)) {
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
if (!GUARDED_BASELINE_RE.test(raw.replace(INLINE_CODE_RE, ''))) {
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
const box = ANY_CHECKBOX_RE.exec(raw);
|
|
147
|
+
const fields: Record<string, string> = {};
|
|
148
|
+
let hasBlock = false;
|
|
149
|
+
for (let j = i + 1; j < lines.length; j++) {
|
|
150
|
+
const line = lines[j] as string;
|
|
151
|
+
if (SPAN_END_RE.test(line)) {
|
|
152
|
+
break; // the next step — this one's span is over
|
|
153
|
+
}
|
|
154
|
+
if (FENCE_RE.test(line)) {
|
|
155
|
+
continue; // a ```yaml wrapper is optional, and not the data
|
|
156
|
+
}
|
|
157
|
+
if (!hasBlock) {
|
|
158
|
+
hasBlock = BLOCK_START_RE.test(line);
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
const f = FIELD_RE.exec(line);
|
|
162
|
+
if (f) {
|
|
163
|
+
fields[f[1] as string] = (f[2] as string).trim();
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
out.push({
|
|
167
|
+
line: i + 1,
|
|
168
|
+
label: _label(raw, lines, i),
|
|
169
|
+
glyph: box ? (box[1] as string) : null,
|
|
170
|
+
hasBlock,
|
|
171
|
+
fields,
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
return out;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Every reason this annotation is REJECTED. Empty means the record is well
|
|
179
|
+
* formed — never that the acceptance criterion is discharged.
|
|
180
|
+
*/
|
|
181
|
+
export function guardedBaselineProblems(items: readonly GuardedBaselineItem[]): string[] {
|
|
182
|
+
const problems: string[] = [];
|
|
183
|
+
for (const it of items) {
|
|
184
|
+
const at = `line ${it.line} (${it.label})`;
|
|
185
|
+
if (it.glyph === null) {
|
|
186
|
+
problems.push(
|
|
187
|
+
`${at}: the guarded-baseline annotation is not on a checkbox step — ` +
|
|
188
|
+
'it is only legal on an unchecked `- [ ]` line',
|
|
189
|
+
);
|
|
190
|
+
} else if (it.glyph !== ' ') {
|
|
191
|
+
problems.push(
|
|
192
|
+
`${at}: the guarded-baseline annotation sits on \`[${it.glyph}]\` — ` +
|
|
193
|
+
'the canonical checkbox stays UNCHECKED; only verification against ' +
|
|
194
|
+
'the real mechanism permits `[x]`',
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
if (!it.hasBlock) {
|
|
198
|
+
problems.push(`${at}: carries no adjacent \`guarded_baseline:\` evidence block`);
|
|
199
|
+
}
|
|
200
|
+
if ((it.fields['red_proof'] ?? '') === '') {
|
|
201
|
+
problems.push(
|
|
202
|
+
`${at}: records no \`red_proof\` — a baseline that has not demonstrably ` +
|
|
203
|
+
'gone RED is an ordinary open item, not a guarded one',
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
const category = it.fields['category'] ?? '';
|
|
207
|
+
if (category === '') {
|
|
208
|
+
problems.push(
|
|
209
|
+
`${at}: records no \`category\` — one of ${GUARDED_CATEGORIES.join(', ')} ` +
|
|
210
|
+
'is required, and absence is not defaulted',
|
|
211
|
+
);
|
|
212
|
+
} else if (!GUARDED_CATEGORIES.includes(category)) {
|
|
213
|
+
problems.push(
|
|
214
|
+
`${at}: records category \`${category}\`, which is not one of ` +
|
|
215
|
+
GUARDED_CATEGORIES.join(', '),
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
return problems;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Which records are STALE, i.e. whose `recheck_when` trigger now resolves in the
|
|
224
|
+
* tree — the mechanism the baseline was written against has arrived, so the
|
|
225
|
+
* evidence describes a world that no longer exists.
|
|
226
|
+
*
|
|
227
|
+
* HONEST SCOPE. Only a PATH trigger is machine-checkable: a token containing `/`
|
|
228
|
+
* is resolved against the repo root and stale iff it exists. A bare symbol name
|
|
229
|
+
* cannot be decided from a path, so it is returned as `unverifiable` rather than
|
|
230
|
+
* silently reading as "not stale" — an unchecked trigger that looks checked is
|
|
231
|
+
* the failure this whole state exists to avoid.
|
|
232
|
+
*/
|
|
233
|
+
export function guardedBaselineStaleness(
|
|
234
|
+
items: readonly GuardedBaselineItem[],
|
|
235
|
+
repo_root: string,
|
|
236
|
+
): { stale: string[]; unverifiable: string[] } {
|
|
237
|
+
const stale: string[] = [];
|
|
238
|
+
const unverifiable: string[] = [];
|
|
239
|
+
for (const it of items) {
|
|
240
|
+
const trigger = it.fields['recheck_when'] ?? '';
|
|
241
|
+
if (trigger === '') {
|
|
242
|
+
continue;
|
|
243
|
+
}
|
|
244
|
+
for (const token of trigger.split(/[\s,]+/).filter((t) => t !== '')) {
|
|
245
|
+
if (!token.includes('/')) {
|
|
246
|
+
unverifiable.push(`line ${it.line} (${it.label}): recheck_when \`${token}\``);
|
|
247
|
+
} else if (fs.existsSync(path.join(repo_root, token))) {
|
|
248
|
+
stale.push(
|
|
249
|
+
`line ${it.line} (${it.label}): recheck_when \`${token}\` now exists — ` +
|
|
250
|
+
're-verify against the real mechanism',
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
return { stale, unverifiable };
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/** One roadmap, as the report needs it — structural, so `RoadmapStats` fits as-is. */
|
|
259
|
+
export interface GuardedBaselineHost {
|
|
260
|
+
readonly rel: string;
|
|
261
|
+
readonly path: string;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
export interface GuardedBaselineReport {
|
|
265
|
+
/** Dashboard section, appended to the rendered markdown. `''` when nothing is annotated. */
|
|
266
|
+
section: string;
|
|
267
|
+
/** Rejections across every roadmap — `--check` must fail on these. */
|
|
268
|
+
problems: number;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Report every guarded baseline in the estate: a dashboard section, and the
|
|
273
|
+
* rejections + staleness on stderr. Side-effecting on purpose, and named for it
|
|
274
|
+
* — the sibling `_warn_merge_gated` does the same, and it keeps the caller at
|
|
275
|
+
* one line in a file that sits at its size cap.
|
|
276
|
+
*/
|
|
277
|
+
export function reportGuardedBaselines(
|
|
278
|
+
roadmaps: readonly GuardedBaselineHost[],
|
|
279
|
+
repo_root: string,
|
|
280
|
+
write: (s: string) => void = (s) => process.stderr.write(s),
|
|
281
|
+
): GuardedBaselineReport {
|
|
282
|
+
const rows: string[] = [];
|
|
283
|
+
let problems = 0;
|
|
284
|
+
for (const r of roadmaps) {
|
|
285
|
+
let items: GuardedBaselineItem[];
|
|
286
|
+
try {
|
|
287
|
+
items = parseGuardedBaselines(fs.readFileSync(r.path, { encoding: 'utf-8' }));
|
|
288
|
+
} catch {
|
|
289
|
+
continue;
|
|
290
|
+
}
|
|
291
|
+
if (items.length === 0) {
|
|
292
|
+
continue;
|
|
293
|
+
}
|
|
294
|
+
const bad = guardedBaselineProblems(items);
|
|
295
|
+
const { stale, unverifiable } = guardedBaselineStaleness(items, repo_root);
|
|
296
|
+
problems += bad.length;
|
|
297
|
+
rows.push(
|
|
298
|
+
`| [${r.rel}](roadmaps/${r.rel}) | ${items.length} | ${stale.length} | ${bad.length} |`,
|
|
299
|
+
);
|
|
300
|
+
write(
|
|
301
|
+
`🛡️ ${r.rel}: ${items.length} guarded-baseline step(s) — RED-proven, ` +
|
|
302
|
+
'NOT complete, and blocking archival:\n',
|
|
303
|
+
);
|
|
304
|
+
for (const it of items) {
|
|
305
|
+
write(` - ${it.label} (category ${it.fields['category'] ?? '—'})\n`);
|
|
306
|
+
}
|
|
307
|
+
for (const p of bad) write(` ❌ ${p}\n`);
|
|
308
|
+
for (const s of stale) write(` ⚠️ ${s}\n`);
|
|
309
|
+
for (const u of unverifiable) write(` · not machine-checkable: ${u}\n`);
|
|
310
|
+
}
|
|
311
|
+
if (rows.length === 0) {
|
|
312
|
+
return { section: '', problems };
|
|
313
|
+
}
|
|
314
|
+
return {
|
|
315
|
+
section:
|
|
316
|
+
'\n## 🛡️ Guarded baselines — RED-proven, not complete\n\n' +
|
|
317
|
+
'These steps carry `<!-- roadmap-status: guarded-baseline -->`: an ' +
|
|
318
|
+
'executable guard exists and has been shown to go RED under a named ' +
|
|
319
|
+
'sabotage, but the acceptance criterion names a mechanism that does not ' +
|
|
320
|
+
'exist yet. They are **not** done, they are **not** counted as done, and ' +
|
|
321
|
+
'they **block archival** until the real mechanism is verified (council ' +
|
|
322
|
+
'2026-08-31, 2/2 convergent).\n\n' +
|
|
323
|
+
'| Roadmap | Guarded | Stale | Rejected |\n|---|---:|---:|---:|\n' +
|
|
324
|
+
rows.join('\n') +
|
|
325
|
+
'\n',
|
|
326
|
+
problems,
|
|
327
|
+
};
|
|
328
|
+
}
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
/**
|
|
3
|
+
* The single sanctioned writer of a roadmap checkbox glyph.
|
|
4
|
+
*
|
|
5
|
+
* `road-to-skill-ecosystem-runtime-enforcement` Phase 6. Every mechanism here
|
|
6
|
+
* exists because of a recorded way a concurrent writer destroys work, and each
|
|
7
|
+
* one is listed with the failure it closes rather than as a good practice:
|
|
8
|
+
*
|
|
9
|
+
* 1. **Advisory lock + atomic rename.** Two writers read, edit and write the
|
|
10
|
+
* same file; the second write lands last and the first writer's step is
|
|
11
|
+
* gone, with no error to either. A torn write is worse still: a
|
|
12
|
+
* half-rewritten plan parses as a plan with fewer steps.
|
|
13
|
+
* 2. **Anchor on the step's OWN LINE.** A greedy multi-line pattern across a
|
|
14
|
+
* multi-entry file is the recorded mechanism by which one substitution
|
|
15
|
+
* overwrites later entries — the regex matches from the first step to the
|
|
16
|
+
* last and replaces everything between.
|
|
17
|
+
* 3. **Structural invariant against the LIVE pre-write file.** Asserting the
|
|
18
|
+
* step count against an in-memory snapshot confirms what you INTENDED to
|
|
19
|
+
* write while destroying what a parallel writer wrote in between. The
|
|
20
|
+
* re-read is the whole point: the file is checked at the moment of writing.
|
|
21
|
+
* 4. **Post-write survival check.** In a concurrent overwrite the loser gets
|
|
22
|
+
* no error, so a successful write is not evidence the write survived.
|
|
23
|
+
* Grep for the mutated step afterwards and confirm exactly one occurrence.
|
|
24
|
+
* 5. **Fail closed on ambiguity.** Two roadmaps in scope — one in the working
|
|
25
|
+
* directory, one nested — resolve NEITHER and name both. Silently choosing
|
|
26
|
+
* is how a step gets flipped in the wrong plan.
|
|
27
|
+
*
|
|
28
|
+
* Exit codes: 0 written · 1 refused (ambiguity, invariant, survival) · 2 usage.
|
|
29
|
+
*/
|
|
30
|
+
import * as fs from 'node:fs';
|
|
31
|
+
import * as path from 'node:path';
|
|
32
|
+
import process from 'node:process';
|
|
33
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
34
|
+
|
|
35
|
+
const _HERE = fileURLToPath(import.meta.url);
|
|
36
|
+
|
|
37
|
+
/** The four glyphs a roadmap step may carry. */
|
|
38
|
+
export const GLYPHS = ['x', ' ', '~', '-'] as const;
|
|
39
|
+
export type Glyph = (typeof GLYPHS)[number];
|
|
40
|
+
|
|
41
|
+
/** A lock older than this is treated as abandoned. A crashed writer must not wedge the file. */
|
|
42
|
+
export const LOCK_STALE_MS = 60_000;
|
|
43
|
+
|
|
44
|
+
export class RoadmapWriteError extends Error {}
|
|
45
|
+
|
|
46
|
+
/** Every checkbox line in the file, as `[lineIndex, glyph, text]`. */
|
|
47
|
+
export function scanSteps(content: string): { line: number; glyph: string; text: string }[] {
|
|
48
|
+
const out: { line: number; glyph: string; text: string }[] = [];
|
|
49
|
+
const lines = content.split('\n');
|
|
50
|
+
for (let i = 0; i < lines.length; i += 1) {
|
|
51
|
+
const m = /^(\s*-\s\[)([ x~-])(\]\s?)(.*)$/.exec(lines[i] as string);
|
|
52
|
+
if (m !== null) out.push({ line: i, glyph: m[2] as string, text: m[4] as string });
|
|
53
|
+
}
|
|
54
|
+
return out;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Locate the ONE step whose text starts with `stepId`.
|
|
59
|
+
*
|
|
60
|
+
* Refuses on zero and on more than one. A prefix that matches two steps is an
|
|
61
|
+
* ambiguous address, and picking the first is the same silent-choice failure as
|
|
62
|
+
* resolving an ambiguous plan.
|
|
63
|
+
*/
|
|
64
|
+
export function findStep(content: string, stepId: string): { line: number; glyph: string; text: string } {
|
|
65
|
+
const needle = stepId.trim();
|
|
66
|
+
if (needle === '') throw new RoadmapWriteError('step id is empty');
|
|
67
|
+
// Match against the raw text AND its bold-stripped form, so `**1.2` and `1.2`
|
|
68
|
+
// both address the same step. Stripping only ONE side is the bug this shape
|
|
69
|
+
// replaces: a needle carrying `**` then matched nothing at all.
|
|
70
|
+
const strip = (t: string): string => t.replace(/^\*\*/, '');
|
|
71
|
+
const hits = scanSteps(content).filter(
|
|
72
|
+
(s) => s.text.startsWith(needle) || strip(s.text).startsWith(strip(needle)),
|
|
73
|
+
);
|
|
74
|
+
if (hits.length === 0) {
|
|
75
|
+
throw new RoadmapWriteError(`no step whose text starts with "${needle}"`);
|
|
76
|
+
}
|
|
77
|
+
if (hits.length > 1) {
|
|
78
|
+
throw new RoadmapWriteError(
|
|
79
|
+
`"${needle}" matches ${String(hits.length)} steps (lines ${hits.map((h) => h.line + 1).join(', ')}) — ` +
|
|
80
|
+
'refusing rather than picking the first. Give a longer prefix.',
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
return hits[0]!;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Rewrite ONE line's glyph. Line-anchored by construction: the function is given
|
|
88
|
+
* a line index and touches only `lines[index]`, so there is no pattern that can
|
|
89
|
+
* span entries even in principle.
|
|
90
|
+
*/
|
|
91
|
+
export function setGlyphOnLine(content: string, lineIndex: number, glyph: Glyph): string {
|
|
92
|
+
const lines = content.split('\n');
|
|
93
|
+
const line = lines[lineIndex];
|
|
94
|
+
if (line === undefined) throw new RoadmapWriteError(`line ${String(lineIndex)} is out of range`);
|
|
95
|
+
const m = /^(\s*-\s\[)([ x~-])(\].*)$/.exec(line);
|
|
96
|
+
if (m === null) throw new RoadmapWriteError(`line ${String(lineIndex + 1)} is not a checkbox line`);
|
|
97
|
+
lines[lineIndex] = `${m[1]}${glyph}${m[3]}`;
|
|
98
|
+
return lines.join('\n');
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** Acquire an advisory lock, or throw. `O_EXCL` is the exclusion; the mtime is the staleness clock. */
|
|
102
|
+
export function acquireLock(file: string, nowMs = Date.now()): string {
|
|
103
|
+
const lock = `${file}.lock`;
|
|
104
|
+
try {
|
|
105
|
+
fs.writeFileSync(lock, `${String(process.pid)}\n`, { flag: 'wx' });
|
|
106
|
+
return lock;
|
|
107
|
+
} catch {
|
|
108
|
+
let age = 0;
|
|
109
|
+
try {
|
|
110
|
+
age = nowMs - fs.statSync(lock).mtimeMs;
|
|
111
|
+
} catch {
|
|
112
|
+
// The holder released it between our failed create and this stat —
|
|
113
|
+
// retry once rather than reporting a lock that no longer exists.
|
|
114
|
+
fs.writeFileSync(lock, `${String(process.pid)}\n`, { flag: 'wx' });
|
|
115
|
+
return lock;
|
|
116
|
+
}
|
|
117
|
+
if (age > LOCK_STALE_MS) {
|
|
118
|
+
// A crashed writer must not wedge the file forever. Breaking a stale
|
|
119
|
+
// lock is safe precisely because every write below re-validates the
|
|
120
|
+
// live file — the lock reduces collisions, it does not carry
|
|
121
|
+
// correctness on its own.
|
|
122
|
+
fs.rmSync(lock, { force: true });
|
|
123
|
+
fs.writeFileSync(lock, `${String(process.pid)}\n`, { flag: 'wx' });
|
|
124
|
+
return lock;
|
|
125
|
+
}
|
|
126
|
+
throw new RoadmapWriteError(
|
|
127
|
+
`${path.basename(file)} is locked by another writer (${String(Math.round(age / 1000))}s old) — refusing`,
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export interface SetStepResult {
|
|
133
|
+
file: string;
|
|
134
|
+
line: number;
|
|
135
|
+
from: string;
|
|
136
|
+
to: Glyph;
|
|
137
|
+
stepsBefore: number;
|
|
138
|
+
stepsAfter: number;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Flip one step's glyph, safely.
|
|
143
|
+
*
|
|
144
|
+
* The ordering is the contract: lock → RE-READ → locate → invariant → write →
|
|
145
|
+
* survival check → unlock. The re-read after the lock is what makes the
|
|
146
|
+
* invariant meaningful; checking a snapshot taken before the lock would confirm
|
|
147
|
+
* an intention rather than a fact.
|
|
148
|
+
*/
|
|
149
|
+
export function setStep(file: string, stepId: string, glyph: Glyph, nowMs = Date.now()): SetStepResult {
|
|
150
|
+
const lock = acquireLock(file, nowMs);
|
|
151
|
+
try {
|
|
152
|
+
// LIVE read, inside the lock. Any snapshot taken earlier is stale by
|
|
153
|
+
// definition — a parallel writer may have landed between then and now.
|
|
154
|
+
const before = fs.readFileSync(file, 'utf8');
|
|
155
|
+
const stepsBefore = scanSteps(before).length;
|
|
156
|
+
const target = findStep(before, stepId);
|
|
157
|
+
const after = setGlyphOnLine(before, target.line, glyph);
|
|
158
|
+
|
|
159
|
+
const stepsAfter = scanSteps(after).length;
|
|
160
|
+
if (stepsAfter !== stepsBefore) {
|
|
161
|
+
throw new RoadmapWriteError(
|
|
162
|
+
`structural invariant failed: ${String(stepsBefore)} step(s) before, ${String(stepsAfter)} after. ` +
|
|
163
|
+
'A glyph flip may not change the step count — this is the signature of a pattern ' +
|
|
164
|
+
'that spanned entries.',
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const tmp = `${file}.${String(process.pid)}.tmp`;
|
|
169
|
+
fs.writeFileSync(tmp, after, 'utf8');
|
|
170
|
+
fs.renameSync(tmp, file);
|
|
171
|
+
|
|
172
|
+
// SURVIVAL, not success. In a concurrent overwrite the loser receives no
|
|
173
|
+
// error, so the write returning is not evidence the write is on disk.
|
|
174
|
+
const verify = fs.readFileSync(file, 'utf8');
|
|
175
|
+
const survivors = scanSteps(verify).filter(
|
|
176
|
+
(s) => s.line === target.line && s.glyph === glyph && s.text === target.text,
|
|
177
|
+
);
|
|
178
|
+
if (survivors.length !== 1) {
|
|
179
|
+
throw new RoadmapWriteError(
|
|
180
|
+
`write did not survive: expected exactly 1 occurrence of the mutated step, found ` +
|
|
181
|
+
`${String(survivors.length)}. A parallel writer very likely landed after ours.`,
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
return { file, line: target.line + 1, from: target.glyph, to: glyph, stepsBefore, stepsAfter };
|
|
185
|
+
} finally {
|
|
186
|
+
fs.rmSync(lock, { force: true });
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Resolve the roadmap to write, FAILING CLOSED on ambiguity.
|
|
192
|
+
*
|
|
193
|
+
* When the working directory carries an active roadmap and a nested directory
|
|
194
|
+
* carries its own, neither is resolved and both are named. Choosing silently is
|
|
195
|
+
* how a step gets flipped in the wrong plan — and the wrong plan's author gets
|
|
196
|
+
* no signal at all.
|
|
197
|
+
*/
|
|
198
|
+
export function resolvePlan(roots: readonly string[]): string {
|
|
199
|
+
const found: string[] = [];
|
|
200
|
+
for (const root of roots) {
|
|
201
|
+
const dir = path.join(root, 'agents', 'roadmaps');
|
|
202
|
+
if (!fs.existsSync(dir)) continue;
|
|
203
|
+
for (const name of fs.readdirSync(dir)) {
|
|
204
|
+
if (name.endsWith('.md') && name !== 'README.md') found.push(path.join(dir, name));
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
if (found.length === 0) throw new RoadmapWriteError('no active roadmap found under any candidate root');
|
|
208
|
+
if (found.length > 1) {
|
|
209
|
+
throw new RoadmapWriteError(
|
|
210
|
+
`ambiguous plan — ${String(found.length)} active roadmaps in scope:\n ${found.join('\n ')}\n` +
|
|
211
|
+
'Refusing to choose. Name the file explicitly with --file.',
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
return found[0]!;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
export function main(argv: string[] = process.argv.slice(2)): number {
|
|
218
|
+
const usage =
|
|
219
|
+
'usage: roadmap_set_step --file <roadmap.md> --step <id-prefix> --glyph <x| |~|->\n' +
|
|
220
|
+
' Refuses on: an ambiguous step prefix, a changed step count, a write that did not survive.\n';
|
|
221
|
+
if (argv.includes('-h') || argv.includes('--help')) {
|
|
222
|
+
process.stdout.write(usage);
|
|
223
|
+
return 0;
|
|
224
|
+
}
|
|
225
|
+
const val = (flag: string): string | null => {
|
|
226
|
+
const i = argv.indexOf(flag);
|
|
227
|
+
return i !== -1 && i + 1 < argv.length ? (argv[i + 1] as string) : null;
|
|
228
|
+
};
|
|
229
|
+
const file = val('--file');
|
|
230
|
+
const step = val('--step');
|
|
231
|
+
const glyph = val('--glyph');
|
|
232
|
+
if (file === null || step === null || glyph === null || !(GLYPHS as readonly string[]).includes(glyph)) {
|
|
233
|
+
process.stderr.write(`roadmap_set_step: error: --file, --step and a valid --glyph are required\n${usage}`);
|
|
234
|
+
return 2;
|
|
235
|
+
}
|
|
236
|
+
try {
|
|
237
|
+
const r = setStep(path.resolve(file), step, glyph as Glyph);
|
|
238
|
+
process.stdout.write(
|
|
239
|
+
`✅ ${path.basename(r.file)}:${String(r.line)} [${r.from}] → [${r.to}] · ` +
|
|
240
|
+
`${String(r.stepsAfter)} step(s) intact\n`,
|
|
241
|
+
);
|
|
242
|
+
return 0;
|
|
243
|
+
} catch (e) {
|
|
244
|
+
process.stderr.write(`❌ ${e instanceof Error ? e.message : String(e)}\n`);
|
|
245
|
+
return e instanceof RoadmapWriteError ? 1 : 2;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/* c8 ignore start */
|
|
250
|
+
if (process.argv[1] !== undefined && pathToFileURL(path.resolve(process.argv[1])).href === pathToFileURL(_HERE).href) {
|
|
251
|
+
process.exit(main());
|
|
252
|
+
}
|
|
253
|
+
/* c8 ignore stop */
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The parked estate's two integers, for the dashboard header.
|
|
3
|
+
*
|
|
4
|
+
* `road-to-inbox-harvest-2026-08-f-owner-decision-queue` Phase 2.3. Split out of
|
|
5
|
+
* `update_roadmap_progress.ts` rather than left inline, and the reason is
|
|
6
|
+
* mechanical: that file is past the 1500-line ceiling
|
|
7
|
+
* `check_source_size_budget` charges, so lines added to it are paid back by
|
|
8
|
+
* extraction rather than by a baseline bump.
|
|
9
|
+
*
|
|
10
|
+
* **Two integers are not an inventory.** No row, no link, nothing to conflict
|
|
11
|
+
* on — which is exactly the distinction that keeps this clear of the 2026-08-21
|
|
12
|
+
* council verdict that deleted the hand-maintained index in `stubs/README.md`,
|
|
13
|
+
* and of `check_no_stub_inventory_table`, which refuses its return.
|
|
14
|
+
*
|
|
15
|
+
* The dashboard excludes `stubs/` on purpose and that does not change. What was
|
|
16
|
+
* missing is that a maintainer had no way to learn a stub had gone unread
|
|
17
|
+
* without listing the directory.
|
|
18
|
+
*/
|
|
19
|
+
import * as fs from 'node:fs';
|
|
20
|
+
import * as path from 'node:path';
|
|
21
|
+
|
|
22
|
+
/** Frontmatter block, matching the parent script's own pattern. */
|
|
23
|
+
const FRONTMATTER_RE = /^---\n([\s\S]*?)\n---[ \t\n\r\f\v]*\n/;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Phrases that mean "a person has to decide this".
|
|
27
|
+
*
|
|
28
|
+
* A literal list, never a heuristic: a general "looks like a decision" match
|
|
29
|
+
* would count every stub that mentions the word, and a count that over-reports
|
|
30
|
+
* is a count nobody trusts twice. Kept in sync with `stubs_due.ts` by the test
|
|
31
|
+
* that asserts both readers agree on the same corpus.
|
|
32
|
+
*/
|
|
33
|
+
const OWNER_ROUTING = [
|
|
34
|
+
'owner-reserved',
|
|
35
|
+
'owner reserved',
|
|
36
|
+
'owner: maintainer',
|
|
37
|
+
'reserved to the owner',
|
|
38
|
+
'requires owner',
|
|
39
|
+
'maintainer decision',
|
|
40
|
+
'owner decision',
|
|
41
|
+
'owner sign-off',
|
|
42
|
+
'awaiting the owner',
|
|
43
|
+
];
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Count overdue stubs and stubs routing a decision to a person.
|
|
47
|
+
*
|
|
48
|
+
* Returns `null` on any failure — a dashboard is not the place to surface a
|
|
49
|
+
* parse error, and an absent `stubs/` directory in a consumer install is normal
|
|
50
|
+
* rather than a fault. `today` is a parameter so the count is testable.
|
|
51
|
+
*/
|
|
52
|
+
export function stub_queue_counts(
|
|
53
|
+
roadmap_root: string,
|
|
54
|
+
today: string = new Date().toISOString().slice(0, 10),
|
|
55
|
+
): { overdue: number; owner: number } | null {
|
|
56
|
+
const dir = path.join(roadmap_root, 'stubs');
|
|
57
|
+
let names: string[];
|
|
58
|
+
try {
|
|
59
|
+
names = fs.readdirSync(dir).filter((n) => n.endsWith('.md') && n !== 'README.md');
|
|
60
|
+
} catch {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
if (names.length === 0) return null;
|
|
64
|
+
let overdue = 0;
|
|
65
|
+
let owner = 0;
|
|
66
|
+
for (const n of names) {
|
|
67
|
+
let source: string;
|
|
68
|
+
try {
|
|
69
|
+
source = fs.readFileSync(path.join(dir, n), 'utf-8');
|
|
70
|
+
} catch {
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
const fm = FRONTMATTER_RE.exec(source);
|
|
74
|
+
const due = /^review_by:\s*(\d{4}-\d{2}-\d{2})\s*$/m.exec(fm?.[1] ?? '');
|
|
75
|
+
// An ABSENT date counts as overdue: the contract requires it, so missing
|
|
76
|
+
// means nobody scheduled a read — the state the count exists to surface.
|
|
77
|
+
if (due === null || (due[1] as string) <= today) overdue += 1;
|
|
78
|
+
const lower = source.toLowerCase();
|
|
79
|
+
if (OWNER_ROUTING.some((phrase) => lower.includes(phrase))) owner += 1;
|
|
80
|
+
}
|
|
81
|
+
return { overdue, owner };
|
|
82
|
+
}
|