@event4u/agent-config 14.12.0 → 14.14.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 +118 -155
- 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 +145 -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-comment-discipline.md +6 -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 +252 -8
- package/dist/agent-src/scripts/guarded_baseline.ts +343 -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 +516 -0
- package/dist/agent-src/scripts/ticket_bundles.ts +84 -0
- package/dist/agent-src/scripts/update_roadmap_progress.ts +16 -12
- 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 +80 -11
- 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 +58 -58
- 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 +2900 -1049
- 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 +4895 -2627
- 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/code-clarity.md +18 -0
- 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 +252 -8
- package/src/agent-src/scripts/guarded_baseline.ts +343 -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 +516 -0
- package/src/agent-src/scripts/ticket_bundles.ts +84 -0
- package/src/agent-src/scripts/update_roadmap_progress.ts +16 -12
- 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 +57 -36
- package/src/config/evaluator-budgets.json +14 -14
- package/src/config/gate-coverage.yml +729 -63
- package/src/config/gate-reachability-exemptions.json +21 -0
- package/src/config/gate-violation-baselines.json +42 -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 +12 -4
- 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 +133 -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 +23 -0
- package/src/scripts/_lib/activation_ladder.ts +255 -0
- package/src/scripts/_lib/activation_receipt_producer.ts +341 -0
- package/src/scripts/_lib/activation_states.ts +88 -0
- package/src/scripts/_lib/adherence_detectors.ts +143 -0
- package/src/scripts/_lib/adr_frontmatter.ts +26 -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_pair_delta.ts +349 -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/carrier_status.ts +118 -0
- package/src/scripts/_lib/cascade_stage_enumeration.ts +92 -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/corpus_manifest.ts +726 -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 +282 -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/estate_carrier_cases.ts +72 -0
- package/src/scripts/_lib/eval_publication.ts +354 -0
- package/src/scripts/_lib/evaluation_cascade.ts +452 -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/evolution_roi.ts +562 -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 +239 -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/lexical_shortlist.ts +215 -0
- package/src/scripts/_lib/llm_candidate_proposer.ts +461 -0
- package/src/scripts/_lib/llm_proposer_transport.ts +153 -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/pathology_archive.ts +393 -0
- package/src/scripts/_lib/prefix_stable_surfaces.ts +123 -0
- package/src/scripts/_lib/privacy_class.ts +47 -0
- package/src/scripts/_lib/promotion_capability.ts +315 -0
- package/src/scripts/_lib/promotion_evidence.ts +414 -0
- package/src/scripts/_lib/promotion_review.ts +294 -0
- package/src/scripts/_lib/prompt_shape.ts +92 -0
- package/src/scripts/_lib/regression_neighbourhood.ts +259 -0
- package/src/scripts/_lib/release_highlights.ts +70 -1
- package/src/scripts/_lib/release_material.ts +125 -2
- 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/routing_corpus.ts +307 -0
- package/src/scripts/_lib/routing_index_input.ts +104 -0
- package/src/scripts/_lib/rule_injection.ts +22 -1
- package/src/scripts/_lib/runtime_journal.ts +1499 -0
- package/src/scripts/_lib/runtime_wiring_checks.ts +430 -0
- package/src/scripts/_lib/semantic_noop.ts +167 -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/activation_receipt.ts +258 -0
- 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/cross_exam.ts +128 -0
- package/src/scripts/ai_council/disagreement_signal.ts +338 -0
- package/src/scripts/ai_council/explain_route.ts +157 -0
- package/src/scripts/ai_council/information_gain.ts +293 -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/leakage_corpus.ts +385 -0
- package/src/scripts/ai_council/leakage_patterns.ts +453 -0
- package/src/scripts/ai_council/minority_retention.ts +171 -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/recouncil_savings.ts +299 -0
- package/src/scripts/ai_council/replay_route.ts +223 -0
- package/src/scripts/ai_council/response_record.ts +50 -0
- package/src/scripts/ai_council/reviewer_assignment.ts +279 -0
- package/src/scripts/ai_council/routing_training_row.ts +197 -0
- package/src/scripts/ai_council/synthesis_strategy.ts +159 -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 +131 -10
- 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 +347 -25
- 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_release_highlights.ts +96 -13
- package/src/scripts/check_roadmap_trackable.ts +17 -2
- 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/corpus_manifest.ts +235 -0
- 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 +1153 -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 +125 -16
- 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/comment_discipline_hook.ts +146 -0
- package/src/scripts/hooks/concern_registry.ts +6 -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/hooks/turn_end_gate_hook.ts +9 -1
- 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/language_mirror_hook.ts +14 -2
- package/src/scripts/lint_adr_sweep_routing.ts +12 -0
- package/src/scripts/lint_canonical_terms.ts +604 -0
- package/src/scripts/lint_carrier_integrity.ts +820 -0
- package/src/scripts/lint_code_comments.ts +643 -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_plan_risk_register.ts +39 -19
- package/src/scripts/lint_promotion_paths.ts +779 -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/llm_propose.ts +256 -0
- 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_delivery_sets.ts +361 -0
- package/src/scripts/measure_docs_dead_links.ts +348 -0
- package/src/scripts/measure_host_capture.ts +461 -0
- package/src/scripts/measure_routing_signal.ts +307 -0
- package/src/scripts/migration_status.ts +3 -3
- package/src/scripts/model_rule_injection.ts +76 -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_council_retention.ts +495 -0
- package/src/scripts/probe_turnaround.ts +384 -0
- package/src/scripts/probe_unblocked_ask.ts +279 -0
- package/src/scripts/release.ts +21 -37
- package/src/scripts/release_drill.ts +143 -0
- package/src/scripts/release_env.ts +35 -0
- package/src/scripts/release_publication.ts +84 -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,294 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The lifecycle AFTER promotion — `road-to-harness-promotion-bridge` steps 7.6
|
|
3
|
+
* and 7.7.
|
|
4
|
+
*
|
|
5
|
+
* ## 7.6 — a promoted artefact is not immortal
|
|
6
|
+
*
|
|
7
|
+
* > *post-promotion re-evaluation with `KEEP / REVISE / MERGE / SPLIT / RETIRE`.
|
|
8
|
+
* > The master's promotion phase ends at the evidence package plus a cooldown,
|
|
9
|
+
* > so nothing reopens a promoted artefact and the lifecycle is manual-only at
|
|
10
|
+
* > exactly the point where growth accumulates.*
|
|
11
|
+
* > verify: **a promoted artefact reaching its review trigger produces one of
|
|
12
|
+
* > the five verdicts, and at least one `RETIRE` path is exercised in a
|
|
13
|
+
* > fixture.**
|
|
14
|
+
*
|
|
15
|
+
* Two halves were already in the tree and one was missing. Four of the five
|
|
16
|
+
* verdicts are E6 curator ops (`_lib/curator_ops.ts`) — `REVISE` is not — and
|
|
17
|
+
* `promoted -> retired` is already the one legal retirement edge
|
|
18
|
+
* (`_lib/candidate_record.ts:210-219`). What did not exist was the REVIEW
|
|
19
|
+
* TRIGGER: nothing decided that a promoted artefact was due, and nothing turned
|
|
20
|
+
* that into a verdict. {@link reviewPromoted} is that.
|
|
21
|
+
*
|
|
22
|
+
* **The verdict set is NOT a subset of `CURATOR_OPS`, and finding that out is
|
|
23
|
+
* part of what this step buys.** E6 argued for seven curator ops on the ground
|
|
24
|
+
* that 7.6 specifies five verdicts a four-op curator could not execute — and the
|
|
25
|
+
* shipped seven still cannot execute one of them, because `REVISE` is not among
|
|
26
|
+
* them. The relationship is pinned by a test in both directions rather than
|
|
27
|
+
* papered over with a mapping nobody chose; see {@link POST_PROMOTION_VERDICTS}.
|
|
28
|
+
*
|
|
29
|
+
* ## 7.7 — best-known-state reference on regression
|
|
30
|
+
*
|
|
31
|
+
* > *Roll back to the recorded best-known state; lineage, not endless append.*
|
|
32
|
+
* > verify: **an injected regression triggers the rollback path in a fixture.**
|
|
33
|
+
*
|
|
34
|
+
* {@link BestKnownState} is the record, {@link planRollback} is the decision.
|
|
35
|
+
* "Lineage, not endless append" is carried in the type: a rollback names the
|
|
36
|
+
* state it returns to and the state it leaves, so the history is a chain rather
|
|
37
|
+
* than a pile of snapshots nobody can order.
|
|
38
|
+
*
|
|
39
|
+
* ## This module promotes nothing
|
|
40
|
+
*
|
|
41
|
+
* It reads promoted artefacts and it can RETIRE one — the only transition it
|
|
42
|
+
* expresses is `promoted -> retired`, which `assertTransition` accepts without
|
|
43
|
+
* an approver because retirement is the direction that shrinks the estate.
|
|
44
|
+
* There is no path here that moves anything INTO `promoted`; that stays behind
|
|
45
|
+
* `_lib/promotion_capability.ts`, and `lint_promotion_paths.ts` is what proves
|
|
46
|
+
* this file did not grow one.
|
|
47
|
+
*/
|
|
48
|
+
import { ACCEPTED_STATE, type LifecycleState, assertTransition } from './candidate_record.js';
|
|
49
|
+
import { CURATOR_OPS, type CuratorOp } from './curator_ops.js';
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* The five verdicts step 7.6 names, verbatim.
|
|
53
|
+
*
|
|
54
|
+
* **Four of the five are E6 curator ops. `REVISE` is not, and that is a finding
|
|
55
|
+
* rather than a detail.** `_lib/curator_ops.ts:48-56` is `KEEP · ADD · MERGE ·
|
|
56
|
+
* REPLACE · SPLIT · RETIRE · SKIP`, and its own header argues for seven ops on
|
|
57
|
+
* the ground that *"step 7.6 of the same roadmap already specifies the verdict
|
|
58
|
+
* set KEEP / REVISE / MERGE / SPLIT / RETIRE, so a four-op curator would emit
|
|
59
|
+
* verdicts it cannot execute"*. Measured against the shipped set: `REVISE` is
|
|
60
|
+
* still a verdict the curator cannot execute — `REPLACE` is the nearest op and
|
|
61
|
+
* it is not the same thing, since `REPLACE` is 1→1 with a new artefact while
|
|
62
|
+
* `REVISE` edits the one in place and keeps its identity.
|
|
63
|
+
*
|
|
64
|
+
* The list is therefore written out rather than derived, because deriving it
|
|
65
|
+
* would require inventing the mapping the two sets do not have. What IS pinned,
|
|
66
|
+
* by `tests/scripts/promotion_review.test.ts`, is the relationship in both
|
|
67
|
+
* directions: the four shared verdicts really are curator ops, and `REVISE`
|
|
68
|
+
* really is not — so a later change that adds `REVISE` to `CURATOR_OPS`, or
|
|
69
|
+
* drops one of the four, fails a test instead of drifting.
|
|
70
|
+
*/
|
|
71
|
+
export const POST_PROMOTION_VERDICTS = ['KEEP', 'REVISE', 'MERGE', 'SPLIT', 'RETIRE'] as const;
|
|
72
|
+
|
|
73
|
+
/** The four verdicts the curator can actually execute today. */
|
|
74
|
+
export const VERDICTS_EXECUTABLE_BY_CURATOR: readonly CuratorOp[] = CURATOR_OPS.filter(
|
|
75
|
+
(op) => (POST_PROMOTION_VERDICTS as readonly string[]).includes(op),
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
export type PostPromotionVerdict = (typeof POST_PROMOTION_VERDICTS)[number];
|
|
79
|
+
|
|
80
|
+
/** Why a promoted artefact came up for review. Absent means it is not due. */
|
|
81
|
+
export const REVIEW_TRIGGERS = [
|
|
82
|
+
'regression',
|
|
83
|
+
'usage-floor',
|
|
84
|
+
'duplicate-detected',
|
|
85
|
+
'scope-overgrown',
|
|
86
|
+
'age',
|
|
87
|
+
] as const;
|
|
88
|
+
export type ReviewTrigger = (typeof REVIEW_TRIGGERS)[number];
|
|
89
|
+
|
|
90
|
+
/** What a review reads. Every field is an observation, not a judgement. */
|
|
91
|
+
export interface PromotedArtefactState {
|
|
92
|
+
readonly id: string;
|
|
93
|
+
readonly lifecycle: LifecycleState;
|
|
94
|
+
/** Measured effect now, in the same units as the promotion evidence's delta. */
|
|
95
|
+
readonly currentDeltaPercent: number;
|
|
96
|
+
/** The delta recorded at promotion. The regression test is `current < promoted`. */
|
|
97
|
+
readonly promotedDeltaPercent: number;
|
|
98
|
+
/** How many times the artefact was actually reached since promotion. */
|
|
99
|
+
readonly invocations: number;
|
|
100
|
+
/** Ids of promoted artefacts whose text this one now duplicates. */
|
|
101
|
+
readonly duplicates: readonly string[];
|
|
102
|
+
/** Distinct responsibilities the artefact has accumulated. */
|
|
103
|
+
readonly responsibilities: number;
|
|
104
|
+
readonly daysSincePromotion: number;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export class NotPromotedError extends Error {
|
|
108
|
+
constructor(id: string, lifecycle: LifecycleState) {
|
|
109
|
+
super(
|
|
110
|
+
`'${id}' is '${lifecycle}', not '${ACCEPTED_STATE}' — post-promotion review acts on a ` +
|
|
111
|
+
'PROMOTED artefact. A candidate that never landed is rejected, not retired, and ' +
|
|
112
|
+
'reviewing one here would report a lifecycle event that did not happen.',
|
|
113
|
+
);
|
|
114
|
+
this.name = 'NotPromotedError';
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export interface ReviewOutcome {
|
|
119
|
+
readonly id: string;
|
|
120
|
+
readonly trigger: ReviewTrigger;
|
|
121
|
+
readonly verdict: PostPromotionVerdict;
|
|
122
|
+
readonly reason: string;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/** The floors the review reads. Stated defaults; each carries its own revisit-if. */
|
|
126
|
+
export const REVIEW_THRESHOLDS = {
|
|
127
|
+
/** Below this many invocations the artefact is not earning its place. `revisit-if` a
|
|
128
|
+
* legitimately rare artefact is retired for being rare. */
|
|
129
|
+
usageFloor: 1,
|
|
130
|
+
/** Distinct responsibilities above which the artefact should be SPLIT. `revisit-if` a
|
|
131
|
+
* cohesive artefact with several facets is split for having them. */
|
|
132
|
+
responsibilityCeiling: 2,
|
|
133
|
+
/** Days after which an unreviewed artefact is due. `revisit-if` the cadence is noise. */
|
|
134
|
+
ageDays: 180,
|
|
135
|
+
} as const;
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Is this artefact due for review, and why? `null` means not due.
|
|
139
|
+
*
|
|
140
|
+
* Order is precedence: a regression outranks a usage question, which outranks a
|
|
141
|
+
* duplicate, which outranks overgrowth, which outranks mere age. Without a fixed
|
|
142
|
+
* order two triggers firing at once would make the verdict depend on evaluation
|
|
143
|
+
* order, which is how a review becomes irreproducible.
|
|
144
|
+
*/
|
|
145
|
+
export function reviewTriggerFor(state: PromotedArtefactState): ReviewTrigger | null {
|
|
146
|
+
if (state.currentDeltaPercent < state.promotedDeltaPercent) return 'regression';
|
|
147
|
+
if (state.invocations < REVIEW_THRESHOLDS.usageFloor) return 'usage-floor';
|
|
148
|
+
if (state.duplicates.length > 0) return 'duplicate-detected';
|
|
149
|
+
if (state.responsibilities > REVIEW_THRESHOLDS.responsibilityCeiling) return 'scope-overgrown';
|
|
150
|
+
if (state.daysSincePromotion >= REVIEW_THRESHOLDS.ageDays) return 'age';
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Produce exactly ONE of the five verdicts for a promoted artefact that reached
|
|
156
|
+
* its review trigger.
|
|
157
|
+
*
|
|
158
|
+
* @throws {NotPromotedError} when the artefact is not promoted.
|
|
159
|
+
*/
|
|
160
|
+
export function reviewPromoted(state: PromotedArtefactState, trigger: ReviewTrigger): ReviewOutcome {
|
|
161
|
+
if (state.lifecycle !== ACCEPTED_STATE) {
|
|
162
|
+
throw new NotPromotedError(state.id, state.lifecycle);
|
|
163
|
+
}
|
|
164
|
+
const outcome = (verdict: PostPromotionVerdict, reason: string): ReviewOutcome => ({
|
|
165
|
+
id: state.id,
|
|
166
|
+
trigger,
|
|
167
|
+
verdict,
|
|
168
|
+
reason,
|
|
169
|
+
});
|
|
170
|
+
switch (trigger) {
|
|
171
|
+
case 'regression':
|
|
172
|
+
// A measured effect that fell BELOW zero is not worth revising; it is
|
|
173
|
+
// now costing what it was promoted to save.
|
|
174
|
+
return state.currentDeltaPercent <= 0
|
|
175
|
+
? outcome('RETIRE', `effect fell to ${String(state.currentDeltaPercent)} pp — it no longer earns its place`)
|
|
176
|
+
: outcome(
|
|
177
|
+
'REVISE',
|
|
178
|
+
`effect fell ${String(state.promotedDeltaPercent)} -> ${String(state.currentDeltaPercent)} pp ` +
|
|
179
|
+
'but is still positive',
|
|
180
|
+
);
|
|
181
|
+
case 'usage-floor':
|
|
182
|
+
return outcome('RETIRE', `reached ${String(state.invocations)} time(s) since promotion`);
|
|
183
|
+
case 'duplicate-detected':
|
|
184
|
+
return outcome('MERGE', `now duplicates ${state.duplicates.join(', ')}`);
|
|
185
|
+
case 'scope-overgrown':
|
|
186
|
+
return outcome('SPLIT', `carries ${String(state.responsibilities)} distinct responsibilities`);
|
|
187
|
+
case 'age':
|
|
188
|
+
return outcome('KEEP', `${String(state.daysSincePromotion)} days since promotion, effect held`);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Execute the RETIRE verdict.
|
|
194
|
+
*
|
|
195
|
+
* Routes through `assertTransition`, so the ONE legal retirement edge is the one
|
|
196
|
+
* this takes and a caller cannot retire something that never landed. Returns the
|
|
197
|
+
* next lifecycle state rather than writing anything — nothing in this module
|
|
198
|
+
* touches the filesystem.
|
|
199
|
+
*
|
|
200
|
+
* @throws {LifecycleTransitionError} from `assertTransition`.
|
|
201
|
+
*/
|
|
202
|
+
export function retirePromoted(state: PromotedArtefactState): LifecycleState {
|
|
203
|
+
assertTransition(state.lifecycle, 'retired');
|
|
204
|
+
return 'retired';
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// --- 7.7 — best-known state and rollback ------------------------------------
|
|
208
|
+
|
|
209
|
+
/** A recorded good state, and the state it came from. Lineage, not endless append. */
|
|
210
|
+
export interface BestKnownState {
|
|
211
|
+
readonly artefactId: string;
|
|
212
|
+
/** The revision or bundle identifier this state is recoverable from. */
|
|
213
|
+
readonly reference: string;
|
|
214
|
+
readonly deltaPercent: number;
|
|
215
|
+
/** The best-known state this one replaced. `null` only for the first. */
|
|
216
|
+
readonly supersedes: string | null;
|
|
217
|
+
readonly recordedAt: string;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
export interface RollbackPlan {
|
|
221
|
+
readonly artefactId: string;
|
|
222
|
+
readonly from: string;
|
|
223
|
+
readonly to: string;
|
|
224
|
+
readonly reason: string;
|
|
225
|
+
/** Oldest first. The chain that makes this a lineage rather than a pile. */
|
|
226
|
+
readonly lineage: readonly string[];
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
export class NoBestKnownStateError extends Error {
|
|
230
|
+
constructor(artefactId: string) {
|
|
231
|
+
super(
|
|
232
|
+
`'${artefactId}' regressed and has no recorded best-known state to return to. A rollback ` +
|
|
233
|
+
'target is recorded at promotion time, not reconstructed after the regression — by ' +
|
|
234
|
+
'then the state that worked is exactly what is missing.',
|
|
235
|
+
);
|
|
236
|
+
this.name = 'NoBestKnownStateError';
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Walk the `supersedes` chain, oldest first.
|
|
242
|
+
*
|
|
243
|
+
* Cycle-guarded: a chain that points at itself is a corrupted lineage, and
|
|
244
|
+
* following it forever would hang the caller rather than report the corruption.
|
|
245
|
+
*/
|
|
246
|
+
export function lineageOf(head: BestKnownState, all: readonly BestKnownState[]): string[] {
|
|
247
|
+
const byRef = new Map(all.map((s) => [s.reference, s]));
|
|
248
|
+
const chain: string[] = [];
|
|
249
|
+
const seen = new Set<string>();
|
|
250
|
+
let cursor: BestKnownState | undefined = head;
|
|
251
|
+
while (cursor !== undefined && !seen.has(cursor.reference)) {
|
|
252
|
+
seen.add(cursor.reference);
|
|
253
|
+
chain.push(cursor.reference);
|
|
254
|
+
cursor = cursor.supersedes === null ? undefined : byRef.get(cursor.supersedes);
|
|
255
|
+
}
|
|
256
|
+
return chain.reverse();
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Plan a rollback when the current state regressed against the best known one.
|
|
261
|
+
*
|
|
262
|
+
* `null` when there is no regression — the caller does not have to know the
|
|
263
|
+
* comparison, and a rollback that fires on an improvement is worse than none.
|
|
264
|
+
*
|
|
265
|
+
* @throws {NoBestKnownStateError} when a regression has nowhere to return to.
|
|
266
|
+
*/
|
|
267
|
+
export function planRollback(
|
|
268
|
+
artefactId: string,
|
|
269
|
+
currentReference: string,
|
|
270
|
+
currentDeltaPercent: number,
|
|
271
|
+
history: readonly BestKnownState[],
|
|
272
|
+
): RollbackPlan | null {
|
|
273
|
+
const mine = history.filter((s) => s.artefactId === artefactId);
|
|
274
|
+
const best = mine.reduce<BestKnownState | null>(
|
|
275
|
+
(acc, s) => (acc === null || s.deltaPercent > acc.deltaPercent ? s : acc),
|
|
276
|
+
null,
|
|
277
|
+
);
|
|
278
|
+
if (best === null) {
|
|
279
|
+
if (currentDeltaPercent < 0) throw new NoBestKnownStateError(artefactId);
|
|
280
|
+
return null;
|
|
281
|
+
}
|
|
282
|
+
if (currentDeltaPercent >= best.deltaPercent) {
|
|
283
|
+
return null;
|
|
284
|
+
}
|
|
285
|
+
return {
|
|
286
|
+
artefactId,
|
|
287
|
+
from: currentReference,
|
|
288
|
+
to: best.reference,
|
|
289
|
+
reason:
|
|
290
|
+
`regressed ${String(best.deltaPercent)} -> ${String(currentDeltaPercent)} pp against the ` +
|
|
291
|
+
`best-known state '${best.reference}'`,
|
|
292
|
+
lineage: lineageOf(best, mine),
|
|
293
|
+
};
|
|
294
|
+
}
|
|
@@ -86,3 +86,95 @@ export function humanAuthoredLead(text: string): string {
|
|
|
86
86
|
}
|
|
87
87
|
return kept.join("\n");
|
|
88
88
|
}
|
|
89
|
+
|
|
90
|
+
/** A line that is nothing but an opening tag, with the tag name captured. */
|
|
91
|
+
const REGION_OPEN = /^\s*<([A-Za-z][\w-]*)>\s*$/;
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* The host's own framing of an injected region — the sentence it writes ABOUT
|
|
95
|
+
* the block, not a sentence the user typed.
|
|
96
|
+
*
|
|
97
|
+
* Named literally, for the same reason `isSyntheticPrompt` names wrapper tags:
|
|
98
|
+
* this is host furniture, and furniture is identified by what it says about
|
|
99
|
+
* itself. It is deliberately NOT a language rule — the clauses describe the
|
|
100
|
+
* region's provenance and its data status, and a user who types one is quoting
|
|
101
|
+
* the host, which is exactly the case that should be dropped too.
|
|
102
|
+
*/
|
|
103
|
+
const REGION_NOTE =
|
|
104
|
+
/\b(content (above|below) is from|treat (it|this|that|the (content|text|above|following)) as data)\b/i;
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Remove host-injected wrapper regions — `<launch-selected-element>` and
|
|
108
|
+
* friends — leaving the text the human actually typed around them.
|
|
109
|
+
*
|
|
110
|
+
* MEASURED, from a 14.13.0 field report (2026-09-01) reproduced against this
|
|
111
|
+
* source. `DOCUMENT_HEAD` matches a bare `<tag>` line, and Claude Code PREPENDS
|
|
112
|
+
* exactly that when the user picks a DOM element in the browser pane. So
|
|
113
|
+
* `humanAuthoredLead` broke at line zero and returned `""` for every such
|
|
114
|
+
* prompt — the lead-first isolation was not degraded, it was OFF — and the
|
|
115
|
+
* whole-text fallback then scored ~4 KB of class-heavy markup plus the host's
|
|
116
|
+
* own advisory line. Four consecutive German turns pinned English, and the
|
|
117
|
+
* turn-end gate refused each one.
|
|
118
|
+
*
|
|
119
|
+
* Two things had to move, and both are visible in the reproduction:
|
|
120
|
+
*
|
|
121
|
+
* 1. A bare `<tag>` line that HAS a matching close is the START of a region
|
|
122
|
+
* to skip, never the end of the human lead. That is this function.
|
|
123
|
+
* 2. It runs BEFORE `instructionText`. The block's indented lines arm that
|
|
124
|
+
* filter's paste-state machine, and where no blank line separates the
|
|
125
|
+
* block from the user's sentence, the sentence itself was deleted — the
|
|
126
|
+
* German markers did not merely lose the count, they reached zero.
|
|
127
|
+
*
|
|
128
|
+
* Conservative by construction, in three ways. An UNBALANCED bare tag is left
|
|
129
|
+
* in place, so a pasted document opening with one still terminates the lead
|
|
130
|
+
* exactly as before. A prompt with no balanced region is returned untouched,
|
|
131
|
+
* so nothing outside this shape reclassifies. And the framing sentence is
|
|
132
|
+
* dropped LINE BY LINE against `REGION_NOTE` rather than as a paragraph: in the
|
|
133
|
+
* reported shape the advisory and the user's sentence share one unbroken run,
|
|
134
|
+
* so dropping the run would have taken the sentence with it.
|
|
135
|
+
*
|
|
136
|
+
* Not `isSyntheticPrompt`: that answers "is this whole turn machine-written",
|
|
137
|
+
* and these turns are not — a human sentence follows the block. The wrapper is
|
|
138
|
+
* removed; the turn is kept.
|
|
139
|
+
*
|
|
140
|
+
* Nested same-name regions resolve to the FIRST matching close tag. Host
|
|
141
|
+
* wrappers do not nest by name, and stopping early keeps more human text than
|
|
142
|
+
* scanning past the wrong close would.
|
|
143
|
+
*/
|
|
144
|
+
export function stripInjectedRegions(text: string): string {
|
|
145
|
+
const lines = text.split("\n");
|
|
146
|
+
const kept: string[] = [];
|
|
147
|
+
for (let i = 0; i < lines.length; i++) {
|
|
148
|
+
const line = lines[i] ?? "";
|
|
149
|
+
const open = REGION_OPEN.exec(line);
|
|
150
|
+
if (open === null) {
|
|
151
|
+
kept.push(line);
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
// The tag name comes from `[A-Za-z][\w-]*`, so it carries no regex
|
|
155
|
+
// metacharacter and needs no escaping.
|
|
156
|
+
const close = new RegExp(`^\\s*</${open[1] ?? ""}>\\s*$`);
|
|
157
|
+
let end = -1;
|
|
158
|
+
for (let j = i + 1; j < lines.length; j++) {
|
|
159
|
+
if (close.test(lines[j] ?? "")) {
|
|
160
|
+
end = j;
|
|
161
|
+
break;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
if (end === -1) {
|
|
165
|
+
kept.push(line);
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
if (kept.length > 0 && REGION_NOTE.test(kept[kept.length - 1] ?? "")) {
|
|
169
|
+
kept.pop();
|
|
170
|
+
}
|
|
171
|
+
i = end;
|
|
172
|
+
while (i + 1 < lines.length && (lines[i + 1] ?? "").trim() !== "") {
|
|
173
|
+
if (!REGION_NOTE.test(lines[i + 1] ?? "")) {
|
|
174
|
+
break;
|
|
175
|
+
}
|
|
176
|
+
i++;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return kept.join("\n");
|
|
180
|
+
}
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Regression selection from the affected neighbourhood.
|
|
3
|
+
*
|
|
4
|
+
* `road-to-governed-harness-evolution` Phase 4, step 4.6.
|
|
5
|
+
*
|
|
6
|
+
* > *Use the code graph to choose which regressions to run for a given
|
|
7
|
+
* > candidate. The master adopted the attack "local improvement, global
|
|
8
|
+
* > regression" as a risk with no mechanism behind it. This is distinct from
|
|
9
|
+
* > the killed curriculum generator — it selects existing regressions, it does
|
|
10
|
+
* > not author tasks.*
|
|
11
|
+
* > verify: **a candidate touching one surface runs the regressions its
|
|
12
|
+
* > neighbourhood names, and a fixture proves a neighbour regression is
|
|
13
|
+
* > caught.**
|
|
14
|
+
*
|
|
15
|
+
* ## Which graph, and why it is not the one the step names
|
|
16
|
+
*
|
|
17
|
+
* The step says "the code graph". This tree has two graph surfaces and only one
|
|
18
|
+
* of them resolves here, so the substitution is STATED rather than hidden.
|
|
19
|
+
*
|
|
20
|
+
* · `agent-config code-graph` — the native code-graph engine (ADR-124). It
|
|
21
|
+
* ships `hooks.code_graph.enabled: false`
|
|
22
|
+
* (`src/config/agent-settings.template.yml:1373-1374`), and
|
|
23
|
+
* `agent-config code-graph detect` in this checkout answers
|
|
24
|
+
* `no code-graph source detected`. There is no index to select against.
|
|
25
|
+
* · `src/scripts/discovery_graph.ts` — this suite's OWN artefact relation
|
|
26
|
+
* graph, five typed edges extracted from the discovery manifest's
|
|
27
|
+
* structured fields, with an `affected` BFS already implemented and
|
|
28
|
+
* answering. That is the surface this module builds on.
|
|
29
|
+
*
|
|
30
|
+
* The substitution changes what a "neighbourhood" means, and the difference is
|
|
31
|
+
* worth naming: the native engine would neighbour a candidate by SYMBOL
|
|
32
|
+
* relations, while `discovery_graph` neighbours it by ARTEFACT relations
|
|
33
|
+
* (`supersedes`, `routes_to`, `references_adr`, pack and workspace membership).
|
|
34
|
+
* For this roadmap's candidates — rules, skills, guidelines — the artefact
|
|
35
|
+
* graph is the one that carries the coupling a rewrite can break. For a
|
|
36
|
+
* candidate that edits a `.ts` symbol, it is the weaker surface, and this
|
|
37
|
+
* module says so through {@link selectionVerdict}: a touched surface absent
|
|
38
|
+
* from the graph is REFUSED, never silently neighboured with the empty set.
|
|
39
|
+
*
|
|
40
|
+
* ## Why an unresolved surface refuses instead of selecting nothing
|
|
41
|
+
*
|
|
42
|
+
* A selector whose neighbourhood lookup fails and then runs zero regressions
|
|
43
|
+
* reports a clean sheet, which is indistinguishable from a candidate that
|
|
44
|
+
* genuinely touches nothing coupled. That is exactly the "local improvement,
|
|
45
|
+
* global regression" hole the step exists to close, arriving through the
|
|
46
|
+
* selector rather than around it. So an unresolved touched surface is a
|
|
47
|
+
* refusal reason, and there is no option flag that relaxes it.
|
|
48
|
+
*
|
|
49
|
+
* ## Selects, never authors — carried by object identity (K9)
|
|
50
|
+
*
|
|
51
|
+
* K9 killed the curriculum generator. This module has no code path that
|
|
52
|
+
* constructs a {@link RegressionSpec}: every selected entry is an element of
|
|
53
|
+
* the registry the caller supplied, returned by reference, so
|
|
54
|
+
* `registry.includes(selected.spec)` holds by identity for every selection.
|
|
55
|
+
* A test asserts that identity rather than an id match, because an id match
|
|
56
|
+
* would also be satisfied by a synthesized spec carrying a copied id.
|
|
57
|
+
*/
|
|
58
|
+
import { affected, isSyntheticNode, type Graph } from '../discovery_graph.js';
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* An EXISTING regression, as the registry holds it. `guards` names the artefact
|
|
62
|
+
* ids whose breakage this regression would detect.
|
|
63
|
+
*
|
|
64
|
+
* Nothing in this module builds one of these. It is the caller's registry entry,
|
|
65
|
+
* passed through by reference.
|
|
66
|
+
*/
|
|
67
|
+
export interface RegressionSpec {
|
|
68
|
+
id: string;
|
|
69
|
+
guards: readonly string[];
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** A candidate under evaluation, reduced to the surfaces it touches. */
|
|
73
|
+
export interface Candidate {
|
|
74
|
+
id: string;
|
|
75
|
+
/** Artefact ids the candidate's diff touches. */
|
|
76
|
+
touches: readonly string[];
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** Why a node is in the neighbourhood: the candidate touched it, or a relation reached it. */
|
|
80
|
+
export type NeighbourReason = 'touched' | 'neighbour';
|
|
81
|
+
|
|
82
|
+
export interface NeighbourhoodNode {
|
|
83
|
+
node: string;
|
|
84
|
+
reason: NeighbourReason;
|
|
85
|
+
/** Hop distance from the nearest touched surface. `0` for a touched surface. */
|
|
86
|
+
depth: number;
|
|
87
|
+
/** The relation that reached it, or `''` for a touched surface. */
|
|
88
|
+
via: string;
|
|
89
|
+
/** True for `pack:` / `workspace:` container nodes the graph invents. */
|
|
90
|
+
synthetic: boolean;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export interface Selection {
|
|
94
|
+
spec: RegressionSpec;
|
|
95
|
+
/** The neighbourhood nodes this regression guards, sorted. */
|
|
96
|
+
matched: readonly string[];
|
|
97
|
+
/** `touched` when it guards a surface the candidate edited, else `neighbour`. */
|
|
98
|
+
reason: NeighbourReason;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export interface NeighbourhoodReport {
|
|
102
|
+
candidate_id: string;
|
|
103
|
+
neighbourhood: readonly NeighbourhoodNode[];
|
|
104
|
+
/** Touched surfaces that are not nodes in the graph. A refusal reason, not a warning. */
|
|
105
|
+
unresolved: readonly string[];
|
|
106
|
+
selected: readonly Selection[];
|
|
107
|
+
/** Registry entries whose guards intersect nothing in the neighbourhood. */
|
|
108
|
+
skipped: readonly string[];
|
|
109
|
+
/**
|
|
110
|
+
* Literal 0. This module selects from a registry; a non-zero value here
|
|
111
|
+
* would mean it authored a task, which is K9.
|
|
112
|
+
*/
|
|
113
|
+
authored: 0;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Hops walked out from each touched surface.
|
|
118
|
+
*
|
|
119
|
+
* A STATED default, not a measured optimum. Two is the smallest depth that
|
|
120
|
+
* reaches a `routes_to` target AND that target's own container membership, so a
|
|
121
|
+
* rule edit neighbours the skill it routes to and the pack that skill sits in.
|
|
122
|
+
* `revisit-if` a run selects a regression nobody can explain from the diff, or
|
|
123
|
+
* a real breakage lands outside the two-hop set.
|
|
124
|
+
*/
|
|
125
|
+
export const DEFAULT_NEIGHBOURHOOD_DEPTH = 2;
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* The neighbourhood of a candidate: every touched surface, plus everything the
|
|
129
|
+
* relation graph reaches from it within `depth` hops.
|
|
130
|
+
*
|
|
131
|
+
* Deterministic — nodes are emitted at their shallowest depth and sorted by
|
|
132
|
+
* `(depth, node)`, so two runs over the same graph produce byte-identical
|
|
133
|
+
* reports.
|
|
134
|
+
*/
|
|
135
|
+
export function neighbourhood(
|
|
136
|
+
graph: Graph,
|
|
137
|
+
candidate: Candidate,
|
|
138
|
+
depth: number = DEFAULT_NEIGHBOURHOOD_DEPTH,
|
|
139
|
+
): NeighbourhoodNode[] {
|
|
140
|
+
const best = new Map<string, NeighbourhoodNode>();
|
|
141
|
+
for (const t of candidate.touches) {
|
|
142
|
+
best.set(t, { node: t, reason: 'touched', depth: 0, via: '', synthetic: isSyntheticNode(t) });
|
|
143
|
+
}
|
|
144
|
+
for (const t of candidate.touches) {
|
|
145
|
+
for (const hit of affected(graph, t, depth)) {
|
|
146
|
+
const prior = best.get(hit.node);
|
|
147
|
+
if (prior !== undefined && prior.depth <= hit.depth) continue;
|
|
148
|
+
best.set(hit.node, {
|
|
149
|
+
node: hit.node,
|
|
150
|
+
reason: 'neighbour',
|
|
151
|
+
depth: hit.depth,
|
|
152
|
+
via: hit.via,
|
|
153
|
+
synthetic: isSyntheticNode(hit.node),
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return [...best.values()].sort((a, b) => a.depth - b.depth || a.node.localeCompare(b.node));
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/** Touched surfaces the graph does not know about. */
|
|
161
|
+
export function unresolvedSurfaces(graph: Graph, candidate: Candidate): string[] {
|
|
162
|
+
const known = new Set(graph.nodes);
|
|
163
|
+
return candidate.touches.filter((t) => !known.has(t)).sort((a, b) => a.localeCompare(b));
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Select the registry entries whose guards intersect the candidate's
|
|
168
|
+
* neighbourhood.
|
|
169
|
+
*
|
|
170
|
+
* The returned `spec` values are the caller's registry objects, by reference.
|
|
171
|
+
*/
|
|
172
|
+
export function selectRegressions(
|
|
173
|
+
graph: Graph,
|
|
174
|
+
candidate: Candidate,
|
|
175
|
+
registry: readonly RegressionSpec[],
|
|
176
|
+
depth: number = DEFAULT_NEIGHBOURHOOD_DEPTH,
|
|
177
|
+
): NeighbourhoodReport {
|
|
178
|
+
const hood = neighbourhood(graph, candidate, depth);
|
|
179
|
+
const reasonOf = new Map<string, NeighbourReason>(hood.map((n) => [n.node, n.reason]));
|
|
180
|
+
const selected: Selection[] = [];
|
|
181
|
+
const skipped: string[] = [];
|
|
182
|
+
for (const spec of registry) {
|
|
183
|
+
const matched = spec.guards.filter((g) => reasonOf.has(g)).sort((a, b) => a.localeCompare(b));
|
|
184
|
+
if (matched.length === 0) {
|
|
185
|
+
skipped.push(spec.id);
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
const reason: NeighbourReason = matched.some((m) => reasonOf.get(m) === 'touched')
|
|
189
|
+
? 'touched'
|
|
190
|
+
: 'neighbour';
|
|
191
|
+
selected.push({ spec, matched, reason });
|
|
192
|
+
}
|
|
193
|
+
return {
|
|
194
|
+
candidate_id: candidate.id,
|
|
195
|
+
neighbourhood: hood,
|
|
196
|
+
unresolved: unresolvedSurfaces(graph, candidate),
|
|
197
|
+
selected: selected.sort((a, b) => a.spec.id.localeCompare(b.spec.id)),
|
|
198
|
+
skipped: skipped.sort((a, b) => a.localeCompare(b)),
|
|
199
|
+
authored: 0,
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* `null` when the selection may be trusted, otherwise every reason it may not.
|
|
205
|
+
*
|
|
206
|
+
* Fail-closed by construction: no option object relaxes a reason, so a caller
|
|
207
|
+
* who wants to proceed on an unresolved surface has to delete this call — which
|
|
208
|
+
* is visible in a diff — rather than pass a flag, which is not.
|
|
209
|
+
*/
|
|
210
|
+
export function selectionVerdict(report: NeighbourhoodReport): readonly string[] | null {
|
|
211
|
+
const reasons: string[] = [];
|
|
212
|
+
if (report.unresolved.length > 0) {
|
|
213
|
+
reasons.push(
|
|
214
|
+
`touched surfaces absent from the relation graph: ${report.unresolved.join(', ')} — ` +
|
|
215
|
+
'their neighbourhood is unknown, and an unknown neighbourhood is not an empty one',
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
if (report.neighbourhood.length === 0) {
|
|
219
|
+
reasons.push('empty neighbourhood — the candidate touches nothing the graph knows');
|
|
220
|
+
}
|
|
221
|
+
return reasons.length === 0 ? null : reasons;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/** One regression's observed result on a candidate. */
|
|
225
|
+
export interface RegressionOutcome {
|
|
226
|
+
regression_id: string;
|
|
227
|
+
passed: boolean;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
export interface CatchReport {
|
|
231
|
+
/** Selected regressions that FAILED — the breakages this selection caught. */
|
|
232
|
+
caught: readonly string[];
|
|
233
|
+
/**
|
|
234
|
+
* Regressions that failed but were never selected, so their failure was
|
|
235
|
+
* never observed. Present so a miss is countable rather than invisible.
|
|
236
|
+
*/
|
|
237
|
+
missed: readonly string[];
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Split observed regression outcomes by whether the selection actually ran them.
|
|
242
|
+
*
|
|
243
|
+
* `outcomes` is the full registry's result — what WOULD have been observed had
|
|
244
|
+
* everything run. `caught` is the part the neighbourhood selection reached;
|
|
245
|
+
* `missed` is the part it did not. A selector that narrows too far shows up
|
|
246
|
+
* here as a non-empty `missed`, which is what makes the fixture in
|
|
247
|
+
* `tests/scripts/regression_neighbourhood.test.ts` falsifiable.
|
|
248
|
+
*/
|
|
249
|
+
export function catchReport(
|
|
250
|
+
report: NeighbourhoodReport,
|
|
251
|
+
outcomes: readonly RegressionOutcome[],
|
|
252
|
+
): CatchReport {
|
|
253
|
+
const ran = new Set(report.selected.map((s) => s.spec.id));
|
|
254
|
+
const failed = outcomes.filter((o) => !o.passed).map((o) => o.regression_id);
|
|
255
|
+
return {
|
|
256
|
+
caught: failed.filter((id) => ran.has(id)).sort((a, b) => a.localeCompare(b)),
|
|
257
|
+
missed: failed.filter((id) => !ran.has(id)).sort((a, b) => a.localeCompare(b)),
|
|
258
|
+
};
|
|
259
|
+
}
|