@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,168 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimality tie-break — the FOUR criteria of decision E5, in its committed order.
|
|
3
|
+
*
|
|
4
|
+
* `road-to-governed-harness-evolution` Phase 4, step 4.5.
|
|
5
|
+
*
|
|
6
|
+
* > *Order per E5: the FOUR criteria `tokens → artifacts → scope →
|
|
7
|
+
* > precedence`. The fifth criterion the skipped parent added — simpler
|
|
8
|
+
* > mechanism — is OUT.*
|
|
9
|
+
* > verify: **two candidates with identical vectors resolve deterministically
|
|
10
|
+
* > under the committed order.**
|
|
11
|
+
*
|
|
12
|
+
* ## Why four and not five
|
|
13
|
+
*
|
|
14
|
+
* E5 (decided 2026-08-30, AI council, anthropic + openai, 2/2) rejected
|
|
15
|
+
* "simpler mechanism" on a timing argument rather than a taste one: by the time
|
|
16
|
+
* this function runs, both candidates have survived selection evaluation and
|
|
17
|
+
* every hygiene check, so there is **no outcome signal left to measure
|
|
18
|
+
* simplicity against**. Admitting it converts a mechanical decision into a
|
|
19
|
+
* reviewer's vote. The four that survive are all countable off candidate
|
|
20
|
+
* metadata — token count, artifact count, a scope enum, a precedence rank —
|
|
21
|
+
* which is what makes the result reproducible rather than argued.
|
|
22
|
+
*
|
|
23
|
+
* This module therefore has no place to put a fifth criterion:
|
|
24
|
+
* {@link MINIMALITY_ORDER} is the whole list, {@link breakTie} walks exactly it,
|
|
25
|
+
* and `tests/scripts/minimality_tiebreak.test.ts` pins both the order and its
|
|
26
|
+
* arity. A future fifth criterion has to move E5 first.
|
|
27
|
+
*
|
|
28
|
+
* ## The order is load-bearing, which is why inverting it is tested
|
|
29
|
+
*
|
|
30
|
+
* The two source proposals ordered these criteria in opposite directions, so
|
|
31
|
+
* the same pair of candidates resolves to different winners depending on the
|
|
32
|
+
* choice. The test asserts a fixture whose winner FLIPS under the inverted
|
|
33
|
+
* order — a tie-break whose order did not matter would not need a council
|
|
34
|
+
* decision behind it.
|
|
35
|
+
*
|
|
36
|
+
* ## Identity is a stabiliser, not a criterion
|
|
37
|
+
*
|
|
38
|
+
* {@link breakTie} returns `winner: null` when all four criteria tie: that is
|
|
39
|
+
* the honest answer, and it is deterministic. {@link orderByMinimality} needs a
|
|
40
|
+
* TOTAL order to sort with, so it falls back to the candidate id — an arbitrary
|
|
41
|
+
* but stable stabiliser that expresses no preference about the candidates and
|
|
42
|
+
* is deliberately NOT a fifth criterion. A caller that needs to know whether a
|
|
43
|
+
* decision was made reads {@link breakTie}, never the sort position.
|
|
44
|
+
*/
|
|
45
|
+
|
|
46
|
+
/** The committed order. E5, option A. Walked left to right; first difference decides. */
|
|
47
|
+
export const MINIMALITY_ORDER = ['tokens', 'artifacts', 'scope', 'precedence'] as const;
|
|
48
|
+
|
|
49
|
+
export type MinimalityCriterion = (typeof MINIMALITY_ORDER)[number];
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Blast-radius scope, narrowest first. Lower rank wins — a candidate that
|
|
53
|
+
* touches one artifact is more minimal than one that touches a whole pack.
|
|
54
|
+
*/
|
|
55
|
+
export const SCOPE_ORDER = ['single-artifact', 'module', 'pack', 'repo'] as const;
|
|
56
|
+
export type CandidateScope = (typeof SCOPE_ORDER)[number];
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Precedence rank, least binding first. Lower rank wins — a candidate that
|
|
60
|
+
* lands as advisory guidance is more minimal than one that lands in the kernel,
|
|
61
|
+
* because the kernel binds every session whether or not the change helps it.
|
|
62
|
+
*/
|
|
63
|
+
export const PRECEDENCE_ORDER = ['advisory', 'auto', 'always', 'kernel'] as const;
|
|
64
|
+
export type CandidatePrecedence = (typeof PRECEDENCE_ORDER)[number];
|
|
65
|
+
|
|
66
|
+
/** Everything the tie-break reads. All four fields are counted, none is judged. */
|
|
67
|
+
export interface MinimalityMetadata {
|
|
68
|
+
candidate_id: string;
|
|
69
|
+
/** Tokens the candidate adds to the surface it lands on. */
|
|
70
|
+
tokens: number;
|
|
71
|
+
/** Artifacts the candidate creates or edits. */
|
|
72
|
+
artifacts: number;
|
|
73
|
+
scope: CandidateScope;
|
|
74
|
+
precedence: CandidatePrecedence;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export interface TieBreakResult {
|
|
78
|
+
/** The winning candidate id, or `null` when all four criteria tie. */
|
|
79
|
+
winner: string | null;
|
|
80
|
+
/** Which criterion decided, or `null` when none did. */
|
|
81
|
+
decided_by: MinimalityCriterion | null;
|
|
82
|
+
/** One sentence a report can print verbatim. */
|
|
83
|
+
reason: string;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export class MinimalityMetadataError extends Error {
|
|
87
|
+
constructor(message: string) {
|
|
88
|
+
super(message);
|
|
89
|
+
this.name = 'MinimalityMetadataError';
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function rankOf<T extends string>(order: readonly T[], value: T, field: string): number {
|
|
94
|
+
const i = order.indexOf(value);
|
|
95
|
+
if (i < 0) {
|
|
96
|
+
throw new MinimalityMetadataError(`unknown ${field}: '${String(value)}'`);
|
|
97
|
+
}
|
|
98
|
+
return i;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** The four criterion values as comparable integers, lower being more minimal. */
|
|
102
|
+
function costs(m: MinimalityMetadata): Record<MinimalityCriterion, number> {
|
|
103
|
+
if (!Number.isFinite(m.tokens) || !Number.isFinite(m.artifacts)) {
|
|
104
|
+
throw new MinimalityMetadataError(`${m.candidate_id}: tokens and artifacts must be finite`);
|
|
105
|
+
}
|
|
106
|
+
return {
|
|
107
|
+
tokens: m.tokens,
|
|
108
|
+
artifacts: m.artifacts,
|
|
109
|
+
scope: rankOf(SCOPE_ORDER, m.scope, 'scope'),
|
|
110
|
+
precedence: rankOf(PRECEDENCE_ORDER, m.precedence, 'precedence'),
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Walk {@link MINIMALITY_ORDER} and return at the first criterion that differs.
|
|
116
|
+
*
|
|
117
|
+
* `order` exists for the test that proves the order is load-bearing; production
|
|
118
|
+
* callers pass nothing and get E5's committed order.
|
|
119
|
+
*/
|
|
120
|
+
export function breakTie(
|
|
121
|
+
a: MinimalityMetadata,
|
|
122
|
+
b: MinimalityMetadata,
|
|
123
|
+
order: readonly MinimalityCriterion[] = MINIMALITY_ORDER,
|
|
124
|
+
): TieBreakResult {
|
|
125
|
+
const ca = costs(a);
|
|
126
|
+
const cb = costs(b);
|
|
127
|
+
for (const criterion of order) {
|
|
128
|
+
if (ca[criterion] === cb[criterion]) continue;
|
|
129
|
+
const winner = ca[criterion] < cb[criterion] ? a : b;
|
|
130
|
+
return {
|
|
131
|
+
winner: winner.candidate_id,
|
|
132
|
+
decided_by: criterion,
|
|
133
|
+
reason:
|
|
134
|
+
`${winner.candidate_id} wins on ${criterion} ` +
|
|
135
|
+
`(${String(ca[criterion])} vs ${String(cb[criterion])}); ` +
|
|
136
|
+
`criteria before it tied under the committed order ${order.join(' -> ')}`,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
return {
|
|
140
|
+
winner: null,
|
|
141
|
+
decided_by: null,
|
|
142
|
+
reason:
|
|
143
|
+
`${a.candidate_id} and ${b.candidate_id} tie on all ${String(order.length)} criteria ` +
|
|
144
|
+
`(${order.join(' -> ')}); E5 admits no further criterion, so this escalates rather than resolving`,
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* A deterministic TOTAL order over candidates.
|
|
150
|
+
*
|
|
151
|
+
* Ties on all four criteria fall back to the candidate id — see the header:
|
|
152
|
+
* that is a sort stabiliser, not a fifth criterion, and it never appears in a
|
|
153
|
+
* {@link TieBreakResult}.
|
|
154
|
+
*/
|
|
155
|
+
export function orderByMinimality(
|
|
156
|
+
candidates: readonly MinimalityMetadata[],
|
|
157
|
+
): readonly MinimalityMetadata[] {
|
|
158
|
+
return [...candidates].sort((a, b) => {
|
|
159
|
+
const ca = costs(a);
|
|
160
|
+
const cb = costs(b);
|
|
161
|
+
for (const criterion of MINIMALITY_ORDER) {
|
|
162
|
+
if (ca[criterion] !== cb[criterion]) {
|
|
163
|
+
return ca[criterion] - cb[criterion];
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return a.candidate_id < b.candidate_id ? -1 : a.candidate_id > b.candidate_id ? 1 : 0;
|
|
167
|
+
});
|
|
168
|
+
}
|
|
@@ -0,0 +1,449 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one-resolver invariant, made checkable.
|
|
3
|
+
*
|
|
4
|
+
* `judgment_ladder.ts` is the ONE task-side resolver that decides which
|
|
5
|
+
* dispatch rung a task takes, council included. Its own module docstring says
|
|
6
|
+
* so, and says two further things that were equally unenforced: that no fourth
|
|
7
|
+
* parallel classifier may be "bolted on beside it", and that it is
|
|
8
|
+
* "deliberately independent of `ai_council/necessity.ts`", the council's OWN
|
|
9
|
+
* council-internal necessity gate.
|
|
10
|
+
*
|
|
11
|
+
* All three were prose. A docstring cannot fail, so a second task-side council
|
|
12
|
+
* router could land beside the ladder and every gate in this tree would stay
|
|
13
|
+
* green — which is what
|
|
14
|
+
* `road-to-inbox-harvest-2026-08-e-council-topology-evidence` step 0.5 asks to
|
|
15
|
+
* be closed: "lock the one-resolver invariant in documentation AND in a test".
|
|
16
|
+
*
|
|
17
|
+
* ## This file PARSES. It does not lex. That is the whole point.
|
|
18
|
+
*
|
|
19
|
+
* Three successive R2 review rounds killed three successive text-scanning
|
|
20
|
+
* implementations, each defect introduced by the repair for the last:
|
|
21
|
+
*
|
|
22
|
+
* | Round | Approach | What a fresh reviewer measured |
|
|
23
|
+
* |---|---|---|
|
|
24
|
+
* | 1 | no comment/string handling | false POSITIVE: a router name in a comment or string counted as a declaration |
|
|
25
|
+
* | 2 | ordered regexes, block comments first | false NEGATIVE: a line comment containing a glob opened a spurious block comment. 12 files under `src/` lost top-level exports |
|
|
26
|
+
* | 3 | hand-written character scanner | false NEGATIVE, worse: a backtick inside a REGEX LITERAL read as a template opener, and templates do not end at a newline. **54 files, 231 exports lost** |
|
|
27
|
+
*
|
|
28
|
+
* Round 3's trigger was ordinary, not exotic: `check_portability.ts:741`
|
|
29
|
+
* contains a regex with a backtick in it.
|
|
30
|
+
*
|
|
31
|
+
* The AI council was asked for guidance at the N=3 budget and **split** —
|
|
32
|
+
* one seat for withdrawing the guard, one for parsing properly. Both seats
|
|
33
|
+
* classified withdrawal and narrowing as OWNER-RESERVED and both refused
|
|
34
|
+
* another hand-lexing round, so parsing is the only option a council may
|
|
35
|
+
* execute. Both recorded the same principle:
|
|
36
|
+
*
|
|
37
|
+
* > A gate must not implement a partial lexer or parser for a language when an
|
|
38
|
+
* > authoritative parser for it is already a dependency.
|
|
39
|
+
*
|
|
40
|
+
* and a second, which is the one that explains three rounds of near-misses:
|
|
41
|
+
*
|
|
42
|
+
* > A repair is tested against the violated PROPERTY and representative
|
|
43
|
+
* > mutations, never against the reproducer's literal spelling.
|
|
44
|
+
*
|
|
45
|
+
* `typescript` is already a dependency. Comments, strings, template literals
|
|
46
|
+
* and regex literals are therefore the parser's problem, which is where they
|
|
47
|
+
* belong.
|
|
48
|
+
*
|
|
49
|
+
* **That sentence used to end "and the entire defect class above is gone rather
|
|
50
|
+
* than relocated", and round 5 showed it was false by one line.** Round 4
|
|
51
|
+
* widened WHICH files are read to include `.tsx` without widening HOW they are
|
|
52
|
+
* parsed — every file was handed over as non-JSX TypeScript — so a `.tsx`
|
|
53
|
+
* module's JSX text tokenized as ordinary TS and rounds 2 and 3's defect
|
|
54
|
+
* classes were both live again inside the repair that added the extension. The
|
|
55
|
+
* script kind is now derived from the extension. For that class the claim is
|
|
56
|
+
* true; the limits below are what remains, and they are limits rather than
|
|
57
|
+
* defects.
|
|
58
|
+
*
|
|
59
|
+
* ## The frozen claim — what this guard does and does not assert
|
|
60
|
+
*
|
|
61
|
+
* **Asserts, syntactically:** no module outside the sanctioned resolver
|
|
62
|
+
* EXPORTS A BINDING WHOSE NAME matches a router pattern, in any export form the
|
|
63
|
+
* TypeScript parser recognises; the sanctioned resolver itself exports one; and
|
|
64
|
+
* the sanctioned resolver names no council-internal module in any import,
|
|
65
|
+
* re-export, dynamic import or `require` specifier.
|
|
66
|
+
*
|
|
67
|
+
* **Does NOT assert, and no reading of it should:** anything requiring symbol
|
|
68
|
+
* resolution or a module graph. A router exported under an unrelated name, or
|
|
69
|
+
* reached through an alias chain this file cannot follow, is outside the claim.
|
|
70
|
+
*
|
|
71
|
+
* **Known limits, recorded by R2 round 5 and deliberately NOT repaired**, because
|
|
72
|
+
* each repair moved the review scope and forced another round; the loop was
|
|
73
|
+
* terminated on the one blocking finding. All are measured, none is a hole a
|
|
74
|
+
* second resolver reaches by accident:
|
|
75
|
+
*
|
|
76
|
+
* 1. A **dotted** namespace (`namespace A.B { … }`) nests a `ModuleDeclaration`
|
|
77
|
+
* where the block form nests a `ModuleBlock`, so its body is unwalked while
|
|
78
|
+
* the block form is covered.
|
|
79
|
+
* 2. {@link exportsRouterFunction} never received the namespace walk
|
|
80
|
+
* {@link exportedNames} got, so the two disagree on a router declared inside
|
|
81
|
+
* a namespace in the sanctioned file.
|
|
82
|
+
* 3. `export declare function classifyLadder(…)` — an AMBIENT declaration with
|
|
83
|
+
* no body — is accepted as a callable resolver.
|
|
84
|
+
* 4. A namespace the module does not export has its members counted as module
|
|
85
|
+
* exports, so a non-exported `namespace Internal { export class … }` reports
|
|
86
|
+
* `second-resolver`. A false positive.
|
|
87
|
+
* 5. A **symlinked directory** is invisible (`isDirectory()` is false for a
|
|
88
|
+
* symlink), and a UTF-16 file is counted in `scanned` while being read as
|
|
89
|
+
* mojibake. Both are silent-green.
|
|
90
|
+
*
|
|
91
|
+
* Limits 1-4 are syntactic and repairable; 5 is discovery. They are written
|
|
92
|
+
* here rather than in a helper's docstring because a buried caveat is not a
|
|
93
|
+
* disclosure. */
|
|
94
|
+
import fs from 'node:fs';
|
|
95
|
+
import path from 'node:path';
|
|
96
|
+
import ts from 'typescript';
|
|
97
|
+
|
|
98
|
+
/** The single sanctioned task-side resolver, repo-relative. */
|
|
99
|
+
export const SANCTIONED_RESOLVER = path.join('src', 'scripts', '_lib', 'judgment_ladder.ts');
|
|
100
|
+
|
|
101
|
+
/** The council's own internal surface. The resolver does not import from it. */
|
|
102
|
+
export const COUNCIL_INTERNAL_DIR = path.join('src', 'scripts', 'ai_council');
|
|
103
|
+
|
|
104
|
+
/** Root walked by {@link checkOneResolver}, repo-relative. */
|
|
105
|
+
export const SCAN_ROOT = 'src';
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Module file extensions walked. R2 round-4 finding: `.ts` alone left the
|
|
109
|
+
* tree's 28 `.tsx` modules invisible, and the gap was MASKED — `src/ui/`
|
|
110
|
+
* contributes `.ts` paths to `scanned`, so the directory looked covered while
|
|
111
|
+
* two thirds of its modules were never read. The anti-vacuity discriminator
|
|
112
|
+
* cannot see a per-extension gap, which is the third time in four rounds that
|
|
113
|
+
* a blind spot hid behind a non-empty `scanned`.
|
|
114
|
+
*/
|
|
115
|
+
const SCANNED_EXTS = ['.ts', '.tsx', '.mts', '.cts'] as const;
|
|
116
|
+
const TEST_SUFFIXES = ['.test.ts', '.test.tsx', '.test.mts', '.test.cts'] as const;
|
|
117
|
+
|
|
118
|
+
/** Directory names never walked. */
|
|
119
|
+
const SKIP_DIRS = new Set(['node_modules', '__tests__', 'dist', '.git']);
|
|
120
|
+
|
|
121
|
+
/** Names that mark an exported binding as a task-side council/dispatch ROUTER. */
|
|
122
|
+
export const ROUTER_NAMES: readonly RegExp[] = [
|
|
123
|
+
/^\w*Council\w*Router$/,
|
|
124
|
+
/^classifyLadder$/,
|
|
125
|
+
/^\w*resolveCouncilRoute\w*$/,
|
|
126
|
+
];
|
|
127
|
+
|
|
128
|
+
export interface Violation {
|
|
129
|
+
readonly file: string;
|
|
130
|
+
readonly kind:
|
|
131
|
+
| 'second-resolver'
|
|
132
|
+
| 'council-import-in-resolver'
|
|
133
|
+
| 'resolver-missing'
|
|
134
|
+
| 'resolver-is-not-a-resolver';
|
|
135
|
+
readonly detail: string;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export interface ScanResult {
|
|
139
|
+
readonly violations: readonly Violation[];
|
|
140
|
+
/** Every file actually read, repo-relative. Empty means the scan found nothing to look at. */
|
|
141
|
+
readonly scanned: readonly string[];
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Parse one module.
|
|
146
|
+
*
|
|
147
|
+
* `fileName` is not cosmetic. R2 round-5 finding, and it is the sharpest of the
|
|
148
|
+
* five rounds: the previous version hard-coded `'probe.ts'` and
|
|
149
|
+
* `ts.ScriptKind.TS` for EVERY file, while round 4 had just widened
|
|
150
|
+
* {@link SCANNED_EXTS} to admit `.tsx`. A `.tsx` module was therefore parsed as
|
|
151
|
+
* non-JSX TypeScript, so JSX text tokenized as ordinary TS — resurrecting the
|
|
152
|
+
* two defect classes that killed rounds 2 and 3, inside the repair that
|
|
153
|
+
* introduced the extension. The script kind is now derived from the extension,
|
|
154
|
+
* so the parser is told what it is reading.
|
|
155
|
+
*/
|
|
156
|
+
function parse(text: string, fileName = 'probe.ts'): ts.SourceFile {
|
|
157
|
+
const kind = fileName.endsWith('.tsx') ? ts.ScriptKind.TSX : ts.ScriptKind.TS;
|
|
158
|
+
return ts.createSourceFile(fileName, text, ts.ScriptTarget.Latest, true, kind);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function hasExportModifier(node: ts.Node): boolean {
|
|
162
|
+
const mods = (node as { modifiers?: readonly ts.ModifierLike[] }).modifiers;
|
|
163
|
+
return (mods ?? []).some((m) => m.kind === ts.SyntaxKind.ExportKeyword);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/** Every name a binding pattern introduces, so `export const { X } = mod` is seen. */
|
|
167
|
+
function bindingNames(name: ts.BindingName, out: string[]): void {
|
|
168
|
+
if (ts.isIdentifier(name)) {
|
|
169
|
+
out.push(name.text);
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
for (const el of name.elements) {
|
|
173
|
+
if (ts.isBindingElement(el)) bindingNames(el.name, out);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Every identifier this module exports, by any syntax the parser recognises:
|
|
179
|
+
* declarations with an `export` modifier, `export default`, named exports,
|
|
180
|
+
* aliased exports, re-exports, type-only exports, and `export * as NS from`.
|
|
181
|
+
*/
|
|
182
|
+
export function exportedNames(text: string, fileName?: string): string[] {
|
|
183
|
+
const names: string[] = [];
|
|
184
|
+
collect(parse(text, fileName).statements, names);
|
|
185
|
+
return names;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function collect(statements: readonly ts.Statement[], names: string[]): void {
|
|
189
|
+
for (const st of statements) {
|
|
190
|
+
if (ts.isVariableStatement(st) && hasExportModifier(st)) {
|
|
191
|
+
for (const d of st.declarationList.declarations) bindingNames(d.name, names);
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
if (
|
|
195
|
+
(ts.isClassDeclaration(st) ||
|
|
196
|
+
ts.isInterfaceDeclaration(st) ||
|
|
197
|
+
ts.isTypeAliasDeclaration(st) ||
|
|
198
|
+
ts.isEnumDeclaration(st) ||
|
|
199
|
+
ts.isFunctionDeclaration(st) ||
|
|
200
|
+
ts.isModuleDeclaration(st)) &&
|
|
201
|
+
hasExportModifier(st)
|
|
202
|
+
) {
|
|
203
|
+
if (st.name && ts.isIdentifier(st.name)) names.push(st.name.text);
|
|
204
|
+
}
|
|
205
|
+
// R2 round-4 finding: a namespace's own name was read and its BODY was
|
|
206
|
+
// not, so `export namespace Dispatch { export class CouncilTopologyRouter {} }`
|
|
207
|
+
// was invisible while the enclosing form was caught. The visitor listed
|
|
208
|
+
// `isModuleDeclaration` and only half-honoured it, which is worse than
|
|
209
|
+
// omitting it — a reader sees the kind in the list and assumes cover.
|
|
210
|
+
if (ts.isModuleDeclaration(st) && st.body && ts.isModuleBlock(st.body)) {
|
|
211
|
+
collect(st.body.statements, names);
|
|
212
|
+
continue;
|
|
213
|
+
}
|
|
214
|
+
if (ts.isModuleDeclaration(st)) continue;
|
|
215
|
+
if (ts.isExportAssignment(st)) {
|
|
216
|
+
if (ts.isIdentifier(st.expression)) names.push(st.expression.text);
|
|
217
|
+
if (ts.isClassExpression(st.expression) && st.expression.name) names.push(st.expression.name.text);
|
|
218
|
+
continue;
|
|
219
|
+
}
|
|
220
|
+
if (ts.isExportDeclaration(st)) {
|
|
221
|
+
const clause = st.exportClause;
|
|
222
|
+
if (clause === undefined) continue;
|
|
223
|
+
if (ts.isNamespaceExport(clause)) {
|
|
224
|
+
names.push(clause.name.text);
|
|
225
|
+
continue;
|
|
226
|
+
}
|
|
227
|
+
for (const el of clause.elements) names.push(el.name.text);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Does this file export a router-named binding that is actually CALLABLE?
|
|
234
|
+
*
|
|
235
|
+
* R2 round-3 finding: the previous resolver check tested for the identifier
|
|
236
|
+
* `classifyLadder` in an export position, so `export const classifyLadder =
|
|
237
|
+
* "moved"` scanned green while round 2's own reproducer `export const NOTE =
|
|
238
|
+
* "moved"` was caught — the two differ only in whether the stub kept the name.
|
|
239
|
+
* That is repairing to the reproducer rather than to the property, which is one
|
|
240
|
+
* of the two principles the council asked to be recorded.
|
|
241
|
+
*
|
|
242
|
+
* The property is "this file still holds a resolver", so the declaration KIND
|
|
243
|
+
* is what is checked: a function, a class, or a binding initialised to one. A
|
|
244
|
+
* string, a number or an object literal is a stub whatever it is called.
|
|
245
|
+
*
|
|
246
|
+
* Still syntactic, and deliberately so — a function that merely `return`s a
|
|
247
|
+
* constant satisfies this. Closing THAT needs semantic analysis and is outside
|
|
248
|
+
* the frozen claim.
|
|
249
|
+
*/
|
|
250
|
+
export function exportsRouterFunction(text: string, fileName?: string): boolean {
|
|
251
|
+
const sf = parse(text, fileName);
|
|
252
|
+
const named = (n: string): boolean => ROUTER_NAMES.some((re) => re.test(n));
|
|
253
|
+
|
|
254
|
+
/** Peel `(x)`, `x as T`, `x satisfies T`, `x!` — none of them changes the value. */
|
|
255
|
+
const unwrap = (e: ts.Expression): ts.Expression => {
|
|
256
|
+
let cur = e;
|
|
257
|
+
for (;;) {
|
|
258
|
+
if (ts.isParenthesizedExpression(cur) || ts.isAsExpression(cur) || ts.isNonNullExpression(cur)) {
|
|
259
|
+
cur = cur.expression;
|
|
260
|
+
} else if (ts.isSatisfiesExpression(cur)) {
|
|
261
|
+
cur = cur.expression;
|
|
262
|
+
} else {
|
|
263
|
+
return cur;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
};
|
|
267
|
+
const callableExpr = (e: ts.Expression | undefined): boolean => {
|
|
268
|
+
if (e === undefined) return false;
|
|
269
|
+
const inner = unwrap(e);
|
|
270
|
+
return ts.isArrowFunction(inner) || ts.isFunctionExpression(inner) || ts.isClassExpression(inner);
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
// Local declarations, so an export STATEMENT can be resolved to what it
|
|
274
|
+
// actually exports. R2 round-4 finding: the previous version recognised a
|
|
275
|
+
// router only when declared INLINE, so `function classifyLadder() {}` +
|
|
276
|
+
// `export { classifyLadder }` — and `export default classifyLadder`, and an
|
|
277
|
+
// `as`- or `satisfies`-wrapped arrow — were all reported as
|
|
278
|
+
// `resolver-is-not-a-resolver` on the sanctioned file, with a diagnostic
|
|
279
|
+
// asserting the resolver had "gone somewhere this guard does not look"
|
|
280
|
+
// while the function sat two lines above. `exportedNames` already accepted
|
|
281
|
+
// those exact forms, so one syntax counted as "declares a router" for every
|
|
282
|
+
// other file and as "is not a resolver" for this one.
|
|
283
|
+
const localCallable = new Map<string, boolean>();
|
|
284
|
+
for (const st of sf.statements) {
|
|
285
|
+
if (ts.isFunctionDeclaration(st) && st.name) localCallable.set(st.name.text, true);
|
|
286
|
+
else if (ts.isClassDeclaration(st) && st.name) localCallable.set(st.name.text, true);
|
|
287
|
+
else if (ts.isVariableStatement(st)) {
|
|
288
|
+
for (const d of st.declarationList.declarations) {
|
|
289
|
+
if (ts.isIdentifier(d.name)) localCallable.set(d.name.text, callableExpr(d.initializer));
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
const resolves = (local: string): boolean => localCallable.get(local) === true;
|
|
294
|
+
|
|
295
|
+
for (const st of sf.statements) {
|
|
296
|
+
// Inline: `export function X`, `export class X`, `export const X = () => …`
|
|
297
|
+
if (ts.isFunctionDeclaration(st) && hasExportModifier(st) && st.name && named(st.name.text)) return true;
|
|
298
|
+
if (ts.isClassDeclaration(st) && hasExportModifier(st) && st.name && named(st.name.text)) return true;
|
|
299
|
+
if (ts.isVariableStatement(st) && hasExportModifier(st)) {
|
|
300
|
+
for (const d of st.declarationList.declarations) {
|
|
301
|
+
if (ts.isIdentifier(d.name) && named(d.name.text) && callableExpr(d.initializer)) return true;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
// `export default X` / `export default function X() {}`
|
|
305
|
+
if (ts.isExportAssignment(st) && !st.isExportEquals) {
|
|
306
|
+
const e = unwrap(st.expression);
|
|
307
|
+
if (ts.isIdentifier(e) && named(e.text) && resolves(e.text)) return true;
|
|
308
|
+
if (ts.isFunctionExpression(e) && e.name && named(e.name.text)) return true;
|
|
309
|
+
if (ts.isClassExpression(e) && e.name && named(e.name.text)) return true;
|
|
310
|
+
}
|
|
311
|
+
// `export { X }` / `export { local as X }` — LOCAL only. A re-export
|
|
312
|
+
// carrying a module specifier resolves to another file and is still
|
|
313
|
+
// refused, which is what R2 round 3 asked for.
|
|
314
|
+
if (ts.isExportDeclaration(st) && st.moduleSpecifier === undefined) {
|
|
315
|
+
const clause = st.exportClause;
|
|
316
|
+
if (clause !== undefined && ts.isNamedExports(clause)) {
|
|
317
|
+
for (const el of clause.elements) {
|
|
318
|
+
if (!named(el.name.text)) continue;
|
|
319
|
+
if (resolves((el.propertyName ?? el.name).text)) return true;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
return false;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/** Does this file declare a task-side council/dispatch router? */
|
|
328
|
+
export function declaresRouter(text: string, fileName?: string): boolean {
|
|
329
|
+
return exportedNames(text, fileName).some((n) => ROUTER_NAMES.some((re) => re.test(n)));
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Every module specifier this file names — static import (side-effect included),
|
|
334
|
+
* re-export, dynamic `import()`, and `require()`. String and
|
|
335
|
+
* no-substitution-template specifiers both count; a specifier built by
|
|
336
|
+
* interpolation is outside the frozen claim and is not guessed at.
|
|
337
|
+
*/
|
|
338
|
+
export function moduleSpecifiers(text: string, fileName?: string): string[] {
|
|
339
|
+
const sf = parse(text, fileName);
|
|
340
|
+
const out: string[] = [];
|
|
341
|
+
const literal = (n: ts.Node | undefined): void => {
|
|
342
|
+
if (n === undefined) return;
|
|
343
|
+
if (ts.isStringLiteralLike(n)) out.push(n.text);
|
|
344
|
+
};
|
|
345
|
+
const visit = (n: ts.Node): void => {
|
|
346
|
+
if (ts.isImportDeclaration(n) || ts.isExportDeclaration(n)) literal(n.moduleSpecifier);
|
|
347
|
+
else if (ts.isImportEqualsDeclaration(n) && ts.isExternalModuleReference(n.moduleReference)) {
|
|
348
|
+
literal(n.moduleReference.expression);
|
|
349
|
+
} else if (ts.isCallExpression(n)) {
|
|
350
|
+
const isDynamic = n.expression.kind === ts.SyntaxKind.ImportKeyword;
|
|
351
|
+
const isRequire = ts.isIdentifier(n.expression) && n.expression.text === 'require';
|
|
352
|
+
if (isDynamic || isRequire) literal(n.arguments[0]);
|
|
353
|
+
}
|
|
354
|
+
ts.forEachChild(n, visit);
|
|
355
|
+
};
|
|
356
|
+
visit(sf);
|
|
357
|
+
return out;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/** Does this file import from the council's internal directory? */
|
|
361
|
+
export function importsCouncilInternal(text: string, fileName?: string): boolean {
|
|
362
|
+
return moduleSpecifiers(text, fileName).some((spec) => /(?:^|\/)ai_council(?:\/|$)/.test(spec));
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/** Walk `.ts` files under a directory, skipping tests and build output. */
|
|
366
|
+
function walk(dir: string, out: string[] = []): string[] {
|
|
367
|
+
if (!fs.existsSync(dir)) return out;
|
|
368
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
369
|
+
const p = path.join(dir, entry.name);
|
|
370
|
+
if (entry.isDirectory()) {
|
|
371
|
+
if (SKIP_DIRS.has(entry.name)) continue;
|
|
372
|
+
walk(p, out);
|
|
373
|
+
} else if (SCANNED_EXTS.some((e) => entry.name.endsWith(e)) && !TEST_SUFFIXES.some((t) => entry.name.endsWith(t))) {
|
|
374
|
+
out.push(p);
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
return out;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* Check the invariant over a tree.
|
|
382
|
+
*
|
|
383
|
+
* @param root repository root to scan
|
|
384
|
+
* @returns the violations AND the files actually read. A caller that only
|
|
385
|
+
* checks `violations.length === 0` cannot tell a clean tree from an
|
|
386
|
+
* unscanned one — which is finding 1, and why `scanned` is returned
|
|
387
|
+
* rather than logged.
|
|
388
|
+
*/
|
|
389
|
+
export function checkOneResolver(root: string): ScanResult {
|
|
390
|
+
const violations: Violation[] = [];
|
|
391
|
+
const scanned: string[] = [];
|
|
392
|
+
|
|
393
|
+
// Finding 4: the POSITIVE half. Without this the invariant is satisfied by
|
|
394
|
+
// deleting the resolver, which is not "one resolver" — it is none.
|
|
395
|
+
const resolverAbs = path.join(root, SANCTIONED_RESOLVER);
|
|
396
|
+
if (!fs.existsSync(resolverAbs)) {
|
|
397
|
+
violations.push({
|
|
398
|
+
file: SANCTIONED_RESOLVER,
|
|
399
|
+
kind: 'resolver-missing',
|
|
400
|
+
detail:
|
|
401
|
+
'the sanctioned task-side resolver does not exist. "Exactly one" is ' +
|
|
402
|
+
'violated by zero as well as by two; a tree with no resolver must not scan green.',
|
|
403
|
+
});
|
|
404
|
+
} else if (!exportsRouterFunction(fs.readFileSync(resolverAbs, 'utf-8'), SANCTIONED_RESOLVER)) {
|
|
405
|
+
// R2 round-2 finding: existence is not identity. A `judgment_ladder.ts`
|
|
406
|
+
// gutted to `export const NOTE = "moved"` passed the existence check,
|
|
407
|
+
// so `rm` was caught and hollowing-out was not.
|
|
408
|
+
violations.push({
|
|
409
|
+
file: SANCTIONED_RESOLVER,
|
|
410
|
+
kind: 'resolver-is-not-a-resolver',
|
|
411
|
+
detail:
|
|
412
|
+
'the sanctioned path exists but exports no CALLABLE binding whose name ' +
|
|
413
|
+
'matches a router pattern. Presence is not identity and neither is the name: ' +
|
|
414
|
+
'a stub such as `export const classifyLadder = \"moved\"` keeps both. If the ' +
|
|
415
|
+
'resolver was RENAMED rather than gutted, update ROUTER_NAMES in the same ' +
|
|
416
|
+
'change — this check reports the name it can see, not a conclusion about ' +
|
|
417
|
+
'where the resolver went.',
|
|
418
|
+
});
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
for (const abs of walk(path.join(root, SCAN_ROOT))) {
|
|
422
|
+
const rel = path.relative(root, abs);
|
|
423
|
+
// The council's own internals are not task-side and are out of scope.
|
|
424
|
+
if (rel.startsWith(COUNCIL_INTERNAL_DIR + path.sep)) continue;
|
|
425
|
+
scanned.push(rel);
|
|
426
|
+
const text = fs.readFileSync(abs, 'utf-8');
|
|
427
|
+
if (rel !== SANCTIONED_RESOLVER && declaresRouter(text, rel)) {
|
|
428
|
+
violations.push({
|
|
429
|
+
file: rel,
|
|
430
|
+
kind: 'second-resolver',
|
|
431
|
+
detail:
|
|
432
|
+
`declares a task-side council/dispatch router beside ` +
|
|
433
|
+
`${SANCTIONED_RESOLVER}. There is exactly one task-side resolver; ` +
|
|
434
|
+
`a second one makes routing depend on which classifier ran first.`,
|
|
435
|
+
});
|
|
436
|
+
}
|
|
437
|
+
if (rel === SANCTIONED_RESOLVER && importsCouncilInternal(text, rel)) {
|
|
438
|
+
violations.push({
|
|
439
|
+
file: rel,
|
|
440
|
+
kind: 'council-import-in-resolver',
|
|
441
|
+
detail:
|
|
442
|
+
`imports from ${COUNCIL_INTERNAL_DIR}/. The resolver is deliberately ` +
|
|
443
|
+
`independent of the council's own necessity gate; an import merges the ` +
|
|
444
|
+
`task-side and council-internal surfaces the ladder's docstring keeps apart.`,
|
|
445
|
+
});
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
return { violations, scanned };
|
|
449
|
+
}
|