@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,338 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Three roles, three prompts, three input sets — and a judge that cannot see
|
|
3
|
+
* outcome truth.
|
|
4
|
+
*
|
|
5
|
+
* `road-to-governed-harness-evolution` Phase 5, step 5.3.
|
|
6
|
+
*
|
|
7
|
+
* > *Split the roles: analyzer, curator, proposer. Do not collapse them into
|
|
8
|
+
* > one unconstrained rewrite prompt. An optional judge model grades rubric
|
|
9
|
+
* > questions only, under a frozen evaluator contract.*
|
|
10
|
+
* > verify: **the three roles are separate prompts with separate input sets,
|
|
11
|
+
* > and the judge cannot see outcome truth.**
|
|
12
|
+
*
|
|
13
|
+
* ## Separate input sets, enforced at the boundary rather than by convention
|
|
14
|
+
*
|
|
15
|
+
* {@link ROLE_INPUTS} declares which input kinds each role may receive, and
|
|
16
|
+
* {@link buildPrompt} REFUSES an input whose kind is not in that role's set.
|
|
17
|
+
* Separation therefore survives a caller who assembles one bag of everything
|
|
18
|
+
* and hands it to all three, which is precisely how three roles collapse back
|
|
19
|
+
* into one unconstrained rewrite prompt in practice: nobody decides to collapse
|
|
20
|
+
* them, the input set just widens one field at a time until the roles differ
|
|
21
|
+
* only in their preamble.
|
|
22
|
+
*
|
|
23
|
+
* The sets are deliberately not disjoint — every role sees `defect-observation`,
|
|
24
|
+
* because a curator deciding `RETIRE` without the evidence that motivated it is
|
|
25
|
+
* guessing. What no role sees is the UNION, and a test pins that: the widest
|
|
26
|
+
* role's set is a strict subset of the vocabulary.
|
|
27
|
+
*
|
|
28
|
+
* ## The judge, and why "absent" was not good enough
|
|
29
|
+
*
|
|
30
|
+
* The load-bearing half of the verify clause is that the judge cannot see
|
|
31
|
+
* outcome truth. A judge that merely is not GIVEN the outcome is one careless
|
|
32
|
+
* spread away from seeing it, and the spread reads as harmless in review. So
|
|
33
|
+
* the property is structural in two independent layers:
|
|
34
|
+
*
|
|
35
|
+
* 1. {@link JudgeInput} has no field capable of carrying an outcome. It is
|
|
36
|
+
* three fields — a contract id, rubric question ids, and the artifact text
|
|
37
|
+
* — and none of them can hold a verdict, an arm label, a metric, or a
|
|
38
|
+
* winner. `tests/scripts/role_split.test.ts` scans the declared interface
|
|
39
|
+
* for the outcome-truth field vocabulary, and proves the scanner fires on
|
|
40
|
+
* a synthetic interface before trusting it to be silent on this one.
|
|
41
|
+
* 2. {@link buildJudgePrompt} rejects any key outside {@link JUDGE_INPUT_KEYS}.
|
|
42
|
+
* Types vanish at runtime, so a caller casting a wider object through
|
|
43
|
+
* `as JudgeInput` would defeat layer 1 alone; layer 2 throws on that
|
|
44
|
+
* object rather than quietly serialising the surplus field into the prompt.
|
|
45
|
+
*
|
|
46
|
+
* The judge's own output vocabulary is closed and outcome-free
|
|
47
|
+
* ({@link JUDGE_GRADES}): it answers a rubric question, and there is no value it
|
|
48
|
+
* can return that names an arm or declares a winner.
|
|
49
|
+
*
|
|
50
|
+
* ## The frozen evaluator contract is the one that already exists
|
|
51
|
+
*
|
|
52
|
+
* The contract id travels on the prompt, and {@link promoteJudgeContract} is the
|
|
53
|
+
* only way to change it — it delegates to
|
|
54
|
+
* `evaluator_promotion.assertEvaluatorPromotable`, so a judge-contract change
|
|
55
|
+
* inherits the cross-grade and discrimination-plant requirements step 4.7
|
|
56
|
+
* already built rather than getting a second, weaker gate of its own.
|
|
57
|
+
*/
|
|
58
|
+
import { CURATOR_OPS } from './curator_ops.js';
|
|
59
|
+
import { assertEvaluatorPromotable, type EvaluatorChange } from './evaluator_promotion.js';
|
|
60
|
+
import { classifyOverfit } from './judge_hygiene.js';
|
|
61
|
+
|
|
62
|
+
/** The three roles. The judge is deliberately NOT one of them — it is optional. */
|
|
63
|
+
export const ROLES = ['analyzer', 'curator', 'proposer'] as const;
|
|
64
|
+
export type Role = (typeof ROLES)[number];
|
|
65
|
+
|
|
66
|
+
/** The closed vocabulary of input kinds a role may be given. */
|
|
67
|
+
export const INPUT_KINDS = [
|
|
68
|
+
'defect-observation',
|
|
69
|
+
'trigger-census',
|
|
70
|
+
'corpus-inventory',
|
|
71
|
+
'lifecycle-history',
|
|
72
|
+
'analyzer-finding',
|
|
73
|
+
'curator-decision',
|
|
74
|
+
'authoring-contract',
|
|
75
|
+
] as const;
|
|
76
|
+
export type InputKind = (typeof INPUT_KINDS)[number];
|
|
77
|
+
|
|
78
|
+
export interface RoleInput {
|
|
79
|
+
kind: InputKind;
|
|
80
|
+
id: string;
|
|
81
|
+
text: string;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Which input kinds each role may receive.
|
|
86
|
+
*
|
|
87
|
+
* The analyzer reads evidence and nothing about the corpus, so it cannot
|
|
88
|
+
* propose a lifecycle op. The curator reads the corpus and the analyzer's
|
|
89
|
+
* findings, so it decides WHICH artifact changes without ever seeing the
|
|
90
|
+
* authoring contract that would let it write one. The proposer reads the
|
|
91
|
+
* curator's decision and the authoring contract, so it writes text for a
|
|
92
|
+
* decision that was already made elsewhere.
|
|
93
|
+
*/
|
|
94
|
+
export const ROLE_INPUTS: Readonly<Record<Role, readonly InputKind[]>> = {
|
|
95
|
+
analyzer: ['defect-observation', 'trigger-census'],
|
|
96
|
+
curator: ['defect-observation', 'corpus-inventory', 'lifecycle-history', 'analyzer-finding'],
|
|
97
|
+
proposer: ['defect-observation', 'curator-decision', 'authoring-contract'],
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
/** What each role is asked to produce. One sentence, and they do not overlap. */
|
|
101
|
+
const ROLE_TASK: Readonly<Record<Role, string>> = {
|
|
102
|
+
analyzer:
|
|
103
|
+
'Name the defect classes the evidence supports, each with the observation ids that carry it. ' +
|
|
104
|
+
'Do not name an artifact to change and do not propose text.',
|
|
105
|
+
curator:
|
|
106
|
+
`Choose exactly one lifecycle operation from ${CURATOR_OPS.join(' / ')} per finding, with its targets. ` +
|
|
107
|
+
'Do not write the artifact body — that decision is not yours to author.',
|
|
108
|
+
proposer:
|
|
109
|
+
'Write the candidate body for the curator decision you were given, against the authoring contract. ' +
|
|
110
|
+
'Do not revisit the operation, the targets, or whether the change is warranted.',
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
export class RoleContractViolation extends Error {
|
|
114
|
+
readonly reasons: readonly string[];
|
|
115
|
+
constructor(reasons: readonly string[]) {
|
|
116
|
+
super(`role contract violated: ${reasons.join('; ')}`);
|
|
117
|
+
this.name = 'RoleContractViolation';
|
|
118
|
+
this.reasons = reasons;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export interface RolePrompt {
|
|
123
|
+
role: Role;
|
|
124
|
+
text: string;
|
|
125
|
+
/** The kinds actually supplied, sorted — the prompt's declared input set. */
|
|
126
|
+
input_kinds: readonly InputKind[];
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Build one role's prompt, refusing any input kind outside that role's set.
|
|
131
|
+
*
|
|
132
|
+
* Fail-closed by construction: there is no option object that widens a role's
|
|
133
|
+
* set, so a caller who wants to feed the curator an authoring contract has to
|
|
134
|
+
* edit {@link ROLE_INPUTS}, which is visible in a diff.
|
|
135
|
+
*/
|
|
136
|
+
export function buildPrompt(role: Role, inputs: readonly RoleInput[]): RolePrompt {
|
|
137
|
+
const allowed = new Set<InputKind>(ROLE_INPUTS[role]);
|
|
138
|
+
const rejected = inputs.filter((i) => !allowed.has(i.kind));
|
|
139
|
+
if (rejected.length > 0) {
|
|
140
|
+
throw new RoleContractViolation(
|
|
141
|
+
rejected.map(
|
|
142
|
+
(i) =>
|
|
143
|
+
`role '${role}' may not receive input kind '${i.kind}' (input '${i.id}') — ` +
|
|
144
|
+
`its set is ${[...allowed].join(', ')}`,
|
|
145
|
+
),
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
const kinds = [...new Set(inputs.map((i) => i.kind))].sort((a, b) => a.localeCompare(b));
|
|
149
|
+
const body = inputs
|
|
150
|
+
.map((i) => `[${i.kind}:${i.id}]\n${i.text}`)
|
|
151
|
+
.sort((a, b) => a.localeCompare(b))
|
|
152
|
+
.join('\n\n');
|
|
153
|
+
return {
|
|
154
|
+
role,
|
|
155
|
+
text: `## Role: ${role}\n\n${ROLE_TASK[role]}\n\n## Inputs\n\n${body}`,
|
|
156
|
+
input_kinds: kinds,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/* ─────────────────────────── the optional judge ─────────────────────────── */
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Every key a judge prompt may be built from. Frozen, and checked at runtime,
|
|
164
|
+
* because a cast defeats the type but not this list.
|
|
165
|
+
*/
|
|
166
|
+
export const JUDGE_INPUT_KEYS = ['evaluator_contract_id', 'rubric_question_ids', 'artifact_text'] as const;
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* The judge's entire view.
|
|
170
|
+
*
|
|
171
|
+
* No field here can carry an outcome: not a verdict, not an arm label, not a
|
|
172
|
+
* metric, not a winner, not a ground-truth label. That is the point, and it is
|
|
173
|
+
* asserted mechanically rather than left to review.
|
|
174
|
+
*/
|
|
175
|
+
export interface JudgeInput {
|
|
176
|
+
evaluator_contract_id: string;
|
|
177
|
+
rubric_question_ids: readonly string[];
|
|
178
|
+
artifact_text: string;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/** The judge's closed answer vocabulary. Nothing here names an arm or a winner. */
|
|
182
|
+
export const JUDGE_GRADES = ['yes', 'no', 'not-assessable'] as const;
|
|
183
|
+
export type JudgeGrade = (typeof JUDGE_GRADES)[number];
|
|
184
|
+
|
|
185
|
+
export class EvaluatorContractViolation extends Error {
|
|
186
|
+
readonly reasons: readonly string[];
|
|
187
|
+
constructor(reasons: readonly string[]) {
|
|
188
|
+
super(`evaluator contract violated: ${reasons.join('; ')}`);
|
|
189
|
+
this.name = 'EvaluatorContractViolation';
|
|
190
|
+
this.reasons = reasons;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Words that would make a rubric question an outcome question.
|
|
196
|
+
*
|
|
197
|
+
* A rubric question asks a property of ONE artifact. The moment it asks which
|
|
198
|
+
* of two did better, the judge is grading the experiment rather than the text,
|
|
199
|
+
* and its answer becomes a second verdict beside `paired_verdict` — Risk 1 on
|
|
200
|
+
* this roadmap.
|
|
201
|
+
*/
|
|
202
|
+
const OUTCOME_QUESTION_MARKERS = [
|
|
203
|
+
'which arm',
|
|
204
|
+
'which candidate',
|
|
205
|
+
'which version',
|
|
206
|
+
'treatment',
|
|
207
|
+
'control arm',
|
|
208
|
+
'baseline arm',
|
|
209
|
+
'winner',
|
|
210
|
+
'won',
|
|
211
|
+
'better than',
|
|
212
|
+
'outperform',
|
|
213
|
+
'ground truth',
|
|
214
|
+
'correct answer',
|
|
215
|
+
'passed the eval',
|
|
216
|
+
'regression',
|
|
217
|
+
];
|
|
218
|
+
|
|
219
|
+
export interface RubricQuestion {
|
|
220
|
+
id: string;
|
|
221
|
+
text: string;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
export interface RubricAudit {
|
|
225
|
+
/** Advisory shape per `judge_hygiene.classifyOverfit`. Gates nothing. */
|
|
226
|
+
shapes: readonly { id: string; shape: string; reason: string }[];
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Throw {@link EvaluatorContractViolation} on any question that asks about
|
|
231
|
+
* outcome truth, and return the advisory shape audit for the rest.
|
|
232
|
+
*/
|
|
233
|
+
export function assertRubricOnly(questions: readonly RubricQuestion[]): RubricAudit {
|
|
234
|
+
const reasons: string[] = [];
|
|
235
|
+
for (const q of questions) {
|
|
236
|
+
const lower = q.text.toLowerCase();
|
|
237
|
+
const hit = OUTCOME_QUESTION_MARKERS.find((m) => lower.includes(m));
|
|
238
|
+
if (hit !== undefined) {
|
|
239
|
+
reasons.push(`question '${q.id}' asks about outcome truth ("${hit}") — the judge grades text, not runs`);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
if (reasons.length > 0) throw new EvaluatorContractViolation(reasons);
|
|
243
|
+
return {
|
|
244
|
+
shapes: questions.map((q) => {
|
|
245
|
+
const c = classifyOverfit(q.text);
|
|
246
|
+
return { id: q.id, shape: c.shape, reason: c.reason };
|
|
247
|
+
}),
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
export interface JudgePrompt {
|
|
252
|
+
/** Deliberately not a {@link Role}: the judge is optional and outside the split. */
|
|
253
|
+
role: 'judge';
|
|
254
|
+
evaluator_contract_id: string;
|
|
255
|
+
text: string;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Build the judge prompt from the allowlist and nothing else.
|
|
260
|
+
*
|
|
261
|
+
* The surplus-key check is the layer that survives a cast. `JudgeInput` cannot
|
|
262
|
+
* DECLARE an outcome field, but `x as JudgeInput` can still carry one at
|
|
263
|
+
* runtime, and a builder that spread its input would serialise it into the
|
|
264
|
+
* prompt. This one enumerates {@link JUDGE_INPUT_KEYS} and refuses anything else.
|
|
265
|
+
*/
|
|
266
|
+
export function buildJudgePrompt(input: JudgeInput, questions: readonly RubricQuestion[]): JudgePrompt {
|
|
267
|
+
const allowed = new Set<string>(JUDGE_INPUT_KEYS);
|
|
268
|
+
const surplus = Object.keys(input as unknown as Record<string, unknown>).filter((k) => !allowed.has(k));
|
|
269
|
+
if (surplus.length > 0) {
|
|
270
|
+
throw new EvaluatorContractViolation(
|
|
271
|
+
surplus.map((k) => `judge input carries '${k}', which is outside the frozen key set`),
|
|
272
|
+
);
|
|
273
|
+
}
|
|
274
|
+
assertRubricOnly(questions);
|
|
275
|
+
const asked = questions
|
|
276
|
+
.filter((q) => input.rubric_question_ids.includes(q.id))
|
|
277
|
+
.map((q) => `- ${q.id}: ${q.text}`)
|
|
278
|
+
.join('\n');
|
|
279
|
+
return {
|
|
280
|
+
role: 'judge',
|
|
281
|
+
evaluator_contract_id: input.evaluator_contract_id,
|
|
282
|
+
text:
|
|
283
|
+
`## Role: judge (contract ${input.evaluator_contract_id})\n\n` +
|
|
284
|
+
`Answer each rubric question with exactly one of ${JUDGE_GRADES.join(' / ')}. ` +
|
|
285
|
+
'You are grading one artifact against the question. You are not told how any run went, ' +
|
|
286
|
+
'and no answer you can give names an arm or a winner.\n\n' +
|
|
287
|
+
`## Rubric\n\n${asked}\n\n## Artifact\n\n${input.artifact_text}`,
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/** Refuse a judge prompt built against a contract id other than the frozen one. */
|
|
292
|
+
export function assertJudgeContractFrozen(prompt: JudgePrompt, frozenId: string): void {
|
|
293
|
+
if (prompt.evaluator_contract_id !== frozenId) {
|
|
294
|
+
throw new EvaluatorContractViolation([
|
|
295
|
+
`judge prompt cites contract '${prompt.evaluator_contract_id}' but the frozen contract is ` +
|
|
296
|
+
`'${frozenId}' — change it through promoteJudgeContract, not by editing the prompt`,
|
|
297
|
+
]);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* The only way to move the frozen judge contract forward.
|
|
303
|
+
*
|
|
304
|
+
* Delegates to step 4.7's `assertEvaluatorPromotable`, so a judge-contract
|
|
305
|
+
* change requires the same cross-grade over a frozen candidate set and the same
|
|
306
|
+
* discrimination plants as any other evaluator change. Returns the new id only
|
|
307
|
+
* once that gate has passed.
|
|
308
|
+
*/
|
|
309
|
+
export function promoteJudgeContract(change: EvaluatorChange): string {
|
|
310
|
+
assertEvaluatorPromotable(change);
|
|
311
|
+
return change.to;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/* ───────────────────────────── the pipeline ─────────────────────────────── */
|
|
315
|
+
|
|
316
|
+
export interface SplitPipeline {
|
|
317
|
+
prompts: readonly RolePrompt[];
|
|
318
|
+
/** `null` when no judge is configured — the judge is optional, per the step. */
|
|
319
|
+
judge: JudgePrompt | null;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* Assemble the three role prompts, each from its own input set, plus the
|
|
324
|
+
* optional judge.
|
|
325
|
+
*
|
|
326
|
+
* `inputsFor` is called once per role and its result passes through
|
|
327
|
+
* {@link buildPrompt}, so a supplier that returns one undifferentiated bag is
|
|
328
|
+
* refused rather than silently accepted.
|
|
329
|
+
*/
|
|
330
|
+
export function buildSplitPipeline(
|
|
331
|
+
inputsFor: (role: Role) => readonly RoleInput[],
|
|
332
|
+
judge: { input: JudgeInput; questions: readonly RubricQuestion[] } | null = null,
|
|
333
|
+
): SplitPipeline {
|
|
334
|
+
return {
|
|
335
|
+
prompts: ROLES.map((r) => buildPrompt(r, inputsFor(r))),
|
|
336
|
+
judge: judge === null ? null : buildJudgePrompt(judge.input, judge.questions),
|
|
337
|
+
};
|
|
338
|
+
}
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The corpus and catalogue substrate for the two routing measurements of
|
|
3
|
+
* `road-to-governed-harness-evolution` — step 5.1 (description vs body) and
|
|
4
|
+
* step 6.4 (delivery sets).
|
|
5
|
+
*
|
|
6
|
+
* ONE LOADER, TWO MEASUREMENTS. Both runs need the same three things: the
|
|
7
|
+
* frozen train/holdout partition, the trigger cases, and the skill catalogue
|
|
8
|
+
* the prompts are ranked against. Two loaders over one corpus is how two
|
|
9
|
+
* measurements start disagreeing about what they measured, so there is one.
|
|
10
|
+
*
|
|
11
|
+
* THE SEAL IS ENFORCED BY REFUSAL, NOT BY FILTERING. The holdout partition
|
|
12
|
+
* frozen in `agents/evidence/analysis/trigger-corpus-holdout-2026-08-30.md`
|
|
13
|
+
* says: no analyzer authored in Phase 5 may read the sealed corpora. So
|
|
14
|
+
* `loadTrainCases` never opens a holdout `evals/triggers.json` at all — the
|
|
15
|
+
* partition is computed from the DIRECTORY NAME, before any file is read.
|
|
16
|
+
* Filtering after the read would satisfy the letter and not the seal.
|
|
17
|
+
*
|
|
18
|
+
* The seal covers the corpus files and not the catalogue: a holdout skill's
|
|
19
|
+
* `SKILL.md` is still ranked against, because removing it would measure a
|
|
20
|
+
* catalogue that does not exist. The boundary is stated in the 5.1
|
|
21
|
+
* pre-registration rather than left to be inferred here.
|
|
22
|
+
*
|
|
23
|
+
* NO SCORER OF ITS OWN. Every score comes from `src/shared/skillRanking.ts`,
|
|
24
|
+
* the module the production ranker and the MCP handler already share. A second
|
|
25
|
+
* scorer in a measurement module would measure the measurement.
|
|
26
|
+
*
|
|
27
|
+
* Pure of network and of clock; reads files and nothing else.
|
|
28
|
+
*/
|
|
29
|
+
import * as fs from 'node:fs';
|
|
30
|
+
import { createHash } from 'node:crypto';
|
|
31
|
+
import * as path from 'node:path';
|
|
32
|
+
|
|
33
|
+
import { scoreSkill, tokenize, type RankableSkill } from '../../shared/skillRanking.js';
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* The partition constant the freeze artefact fixes. Changing it re-partitions
|
|
37
|
+
* the corpus and voids every result measured under the old one, which is why
|
|
38
|
+
* it is a named export a test can pin rather than a literal.
|
|
39
|
+
*/
|
|
40
|
+
export const HOLDOUT_CEILING = 51;
|
|
41
|
+
|
|
42
|
+
export type Partition = 'holdout' | 'train';
|
|
43
|
+
|
|
44
|
+
/** `holdout iff sha256(<skill-directory-name>)[0] < 51`, from the freeze artefact. */
|
|
45
|
+
export function partitionOf(skill: string): Partition {
|
|
46
|
+
const bucket = parseInt(createHash('sha256').update(skill).digest('hex').slice(0, 2), 16);
|
|
47
|
+
return bucket < HOLDOUT_CEILING ? 'holdout' : 'train';
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** One adjudicated case: a prompt, and whether the owning skill must be delivered. */
|
|
51
|
+
export interface CorpusCase {
|
|
52
|
+
readonly skill: string;
|
|
53
|
+
readonly prompt: string;
|
|
54
|
+
/** `true` = positive (must be delivered) · `false` = negative (must not). */
|
|
55
|
+
readonly expect: boolean;
|
|
56
|
+
/** Step 2.3's vocabulary where the file declares it; 876 of 931 cases do not. */
|
|
57
|
+
readonly caseClass: 'exemplar' | 'near-miss' | 'counterexample' | null;
|
|
58
|
+
readonly language: string | null;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
interface RawQuery {
|
|
62
|
+
q?: unknown;
|
|
63
|
+
trigger?: unknown;
|
|
64
|
+
class?: unknown;
|
|
65
|
+
language?: unknown;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* The two corpus shapes this tree carries.
|
|
70
|
+
*
|
|
71
|
+
* `queries[]` is the modern one. Two train files — `brand-asset-generation` and
|
|
72
|
+
* `estimate-ticket` — are the legacy `should_trigger` / `should_not_trigger`
|
|
73
|
+
* pair that step 2.3 grandfathered, and `lint_skill_trigger_corpus` returns
|
|
74
|
+
* before its class rules for exactly those two. A reader that understood only
|
|
75
|
+
* the modern shape would drop them SILENTLY, which is worse than refusing them:
|
|
76
|
+
* the run would report 80 train corpora where the partition says 82 and nothing
|
|
77
|
+
* would say which two were missing. So both shapes are read, and
|
|
78
|
+
* `legacyShaped` records which file used which.
|
|
79
|
+
*/
|
|
80
|
+
interface RawCorpus {
|
|
81
|
+
queries?: RawQuery[];
|
|
82
|
+
should_trigger?: unknown;
|
|
83
|
+
should_not_trigger?: unknown;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function skillsDir(repoRoot: string): string {
|
|
87
|
+
return path.join(repoRoot, 'src', 'skills');
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Is this `src/skills/<name>` entry test scaffolding rather than a skill?
|
|
92
|
+
*
|
|
93
|
+
* A `__`-prefixed directory is scaffolding by convention, and a real skill can
|
|
94
|
+
* never be named one: `skill.schema.json` pins `name` to `^[a-z][a-z0-9-]*$`
|
|
95
|
+
* and requires it to match the parent directory, so a leading underscore fails
|
|
96
|
+
* `validate_frontmatter`. This predicate therefore cannot hide a shipped skill.
|
|
97
|
+
*
|
|
98
|
+
* WHY IT EXISTS, measured rather than assumed.
|
|
99
|
+
* `tests/scripts/lint_originality.test.ts:64` writes a re-skin fixture to
|
|
100
|
+
* `src/skills/__origtest_reskin_fixture/SKILL.md` in the REAL tree and removes
|
|
101
|
+
* it in `afterEach`, because the linter resolves its corpus from a
|
|
102
|
+
* module-level ROOT and takes no root argument. During that window any
|
|
103
|
+
* concurrently-running test file that counts the catalogue sees 300 where the
|
|
104
|
+
* commit holds 299 — which is what failed
|
|
105
|
+
* `tests/scripts/routing_signal_measurement.test.ts` on
|
|
106
|
+
* `Node Tests (ubuntu-latest, shard 2/4)` in runs 33418425604 and 33424783559,
|
|
107
|
+
* intermittently, while passing in isolation and passing on the next run over
|
|
108
|
+
* two markdown files nothing reads.
|
|
109
|
+
*
|
|
110
|
+
* Reproduced locally before this line was written: with the fixture present on
|
|
111
|
+
* disk the assertion fails `300` vs `299`, character for character the CI
|
|
112
|
+
* message; with this predicate active it passes.
|
|
113
|
+
*
|
|
114
|
+
* Excluding the prefix here rather than threading a root through the linter is
|
|
115
|
+
* the smaller change by an order of magnitude: ROOT is baked into ten
|
|
116
|
+
* module-level constants there, and refactoring a shipped gate to suit a test
|
|
117
|
+
* is a worse trade than a naming convention the tree already follows.
|
|
118
|
+
*/
|
|
119
|
+
export function isScaffoldingSkillDir(name: string): boolean {
|
|
120
|
+
return name.startsWith('__');
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/** Every skill directory that carries a trigger corpus, with its partition. */
|
|
124
|
+
export function corpusSkills(repoRoot: string): { skill: string; partition: Partition }[] {
|
|
125
|
+
const dir = skillsDir(repoRoot);
|
|
126
|
+
if (!fs.existsSync(dir)) return [];
|
|
127
|
+
return fs
|
|
128
|
+
.readdirSync(dir)
|
|
129
|
+
.sort()
|
|
130
|
+
.filter((skill) => !isScaffoldingSkillDir(skill))
|
|
131
|
+
.filter((skill) => fs.existsSync(path.join(dir, skill, 'evals', 'triggers.json')))
|
|
132
|
+
.map((skill) => ({ skill, partition: partitionOf(skill) }));
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* The train cases. A holdout corpus is never opened — the partition is decided
|
|
137
|
+
* from the directory name and the sealed path is skipped before any read.
|
|
138
|
+
*/
|
|
139
|
+
export function loadTrainCases(repoRoot: string): CorpusCase[] {
|
|
140
|
+
const dir = skillsDir(repoRoot);
|
|
141
|
+
const out: CorpusCase[] = [];
|
|
142
|
+
for (const { skill, partition } of corpusSkills(repoRoot)) {
|
|
143
|
+
if (partition === 'holdout') continue;
|
|
144
|
+
const raw = JSON.parse(
|
|
145
|
+
fs.readFileSync(path.join(dir, skill, 'evals', 'triggers.json'), 'utf8'),
|
|
146
|
+
) as RawCorpus;
|
|
147
|
+
if (Array.isArray(raw.queries)) {
|
|
148
|
+
for (const q of raw.queries) {
|
|
149
|
+
if (typeof q.q !== 'string' || typeof q.trigger !== 'boolean') continue;
|
|
150
|
+
const declared = typeof q.class === 'string' ? q.class : null;
|
|
151
|
+
out.push({
|
|
152
|
+
skill,
|
|
153
|
+
prompt: q.q,
|
|
154
|
+
expect: q.trigger,
|
|
155
|
+
caseClass:
|
|
156
|
+
declared === 'exemplar' ||
|
|
157
|
+
declared === 'near-miss' ||
|
|
158
|
+
declared === 'counterexample'
|
|
159
|
+
? declared
|
|
160
|
+
: null,
|
|
161
|
+
language: typeof q.language === 'string' ? q.language : null,
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
for (const [key, expect] of [
|
|
167
|
+
['should_trigger', true],
|
|
168
|
+
['should_not_trigger', false],
|
|
169
|
+
] as const) {
|
|
170
|
+
const list = raw[key];
|
|
171
|
+
if (!Array.isArray(list)) continue;
|
|
172
|
+
for (const prompt of list) {
|
|
173
|
+
if (typeof prompt !== 'string') continue;
|
|
174
|
+
out.push({ skill, prompt, expect, caseClass: null, language: null });
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return out;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/** Which train corpora use the legacy shape. Reported so the count is explainable. */
|
|
182
|
+
export function legacyShaped(repoRoot: string): string[] {
|
|
183
|
+
const dir = skillsDir(repoRoot);
|
|
184
|
+
const out: string[] = [];
|
|
185
|
+
for (const { skill, partition } of corpusSkills(repoRoot)) {
|
|
186
|
+
if (partition === 'holdout') continue;
|
|
187
|
+
const raw = JSON.parse(
|
|
188
|
+
fs.readFileSync(path.join(dir, skill, 'evals', 'triggers.json'), 'utf8'),
|
|
189
|
+
) as RawCorpus;
|
|
190
|
+
if (!Array.isArray(raw.queries)) out.push(skill);
|
|
191
|
+
}
|
|
192
|
+
return out;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/** A catalogue entry: what the ranker sees, plus the body the 5.1 arm adds. */
|
|
196
|
+
export interface CatalogueEntry extends RankableSkill {
|
|
197
|
+
readonly name: string;
|
|
198
|
+
readonly description: string;
|
|
199
|
+
readonly personas: readonly string[];
|
|
200
|
+
/** SKILL.md with its frontmatter removed. Empty when the file has none. */
|
|
201
|
+
readonly body: string;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/** Minimal frontmatter split. Returns `[block, body]`; `['', text]` when absent. */
|
|
205
|
+
export function splitFrontmatter(text: string): [string, string] {
|
|
206
|
+
if (!text.startsWith('---')) return ['', text];
|
|
207
|
+
const end = text.indexOf('\n---', 3);
|
|
208
|
+
if (end === -1) return ['', text];
|
|
209
|
+
return [text.slice(3, end), text.slice(end + 4)];
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/** `name`, `description` and `personas` out of a frontmatter block. */
|
|
213
|
+
export function readMeta(block: string): { name: string; description: string; personas: string[] } {
|
|
214
|
+
let name = '';
|
|
215
|
+
let description = '';
|
|
216
|
+
const personas: string[] = [];
|
|
217
|
+
let inPersonas = false;
|
|
218
|
+
for (const raw of block.split('\n')) {
|
|
219
|
+
const line = raw.replace(/\s+$/, '');
|
|
220
|
+
if (inPersonas && /^ {2}- /.test(line)) {
|
|
221
|
+
personas.push(line.slice(4).trim().replace(/^["']|["']$/g, ''));
|
|
222
|
+
continue;
|
|
223
|
+
}
|
|
224
|
+
inPersonas = false;
|
|
225
|
+
const m = /^([a-zA-Z_][\w-]*)[ \t]*:[ \t]*(.*)$/.exec(line);
|
|
226
|
+
if (!m) continue;
|
|
227
|
+
const key = m[1] as string;
|
|
228
|
+
const value = (m[2] as string).trim().replace(/^["']|["']$/g, '');
|
|
229
|
+
if (key === 'personas' && value === '') inPersonas = true;
|
|
230
|
+
else if (key === 'name') name = value;
|
|
231
|
+
else if (key === 'description') description = value;
|
|
232
|
+
}
|
|
233
|
+
return { name, description, personas };
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/** Every skill directory`s `SKILL.md`, name-sorted. The ranking universe. */
|
|
237
|
+
export function loadCatalogue(repoRoot: string): CatalogueEntry[] {
|
|
238
|
+
const dir = skillsDir(repoRoot);
|
|
239
|
+
if (!fs.existsSync(dir)) return [];
|
|
240
|
+
const out: CatalogueEntry[] = [];
|
|
241
|
+
for (const skill of fs.readdirSync(dir).sort()) {
|
|
242
|
+
if (isScaffoldingSkillDir(skill)) continue;
|
|
243
|
+
const file = path.join(dir, skill, 'SKILL.md');
|
|
244
|
+
if (!fs.existsSync(file)) continue;
|
|
245
|
+
const [block, body] = splitFrontmatter(fs.readFileSync(file, 'utf8'));
|
|
246
|
+
const meta = readMeta(block);
|
|
247
|
+
out.push({
|
|
248
|
+
name: meta.name || skill,
|
|
249
|
+
description: meta.description,
|
|
250
|
+
personas: meta.personas,
|
|
251
|
+
body,
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
return out;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/** The two 5.1 arms. `description` is today's production condition. */
|
|
258
|
+
export const ARMS = ['description', 'description+body'] as const;
|
|
259
|
+
export type Arm = (typeof ARMS)[number];
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* The indexed term set per arm.
|
|
263
|
+
*
|
|
264
|
+
* The `description` arm reproduces `skillTerms(skill, {})` exactly — same
|
|
265
|
+
* inputs, same tokenizer — so the control arm IS the shipped behaviour rather
|
|
266
|
+
* than a re-implementation of it.
|
|
267
|
+
*/
|
|
268
|
+
export function armTerms(entry: CatalogueEntry, arm: Arm): Set<string> {
|
|
269
|
+
const parts = [entry.name, entry.description];
|
|
270
|
+
if (arm === 'description+body') parts.push(entry.body);
|
|
271
|
+
return tokenize(parts.join(' '));
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
export interface RankedName {
|
|
275
|
+
readonly name: string;
|
|
276
|
+
readonly score: number;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Top-k by score, ties broken on name — the total order `rankSkills` already
|
|
281
|
+
* defines. Zero scores are dropped, because a skill the scorer gives 0 is not
|
|
282
|
+
* delivered by the shipped ranker either.
|
|
283
|
+
*/
|
|
284
|
+
export function topK(
|
|
285
|
+
prompt: string,
|
|
286
|
+
catalogue: readonly CatalogueEntry[],
|
|
287
|
+
terms: ReadonlyMap<string, Set<string>>,
|
|
288
|
+
k: number,
|
|
289
|
+
): RankedName[] {
|
|
290
|
+
const taskTerms = tokenize(prompt);
|
|
291
|
+
const rows: RankedName[] = [];
|
|
292
|
+
for (const entry of catalogue) {
|
|
293
|
+
const t = terms.get(entry.name);
|
|
294
|
+
if (t === undefined) continue;
|
|
295
|
+
const score = scoreSkill(taskTerms, entry, t);
|
|
296
|
+
if (score > 0) rows.push({ name: entry.name, score });
|
|
297
|
+
}
|
|
298
|
+
rows.sort((a, b) => b.score - a.score || (a.name < b.name ? -1 : a.name > b.name ? 1 : 0));
|
|
299
|
+
return rows.slice(0, k);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/** Term sets for one arm, keyed by the name `topK` ranks on. */
|
|
303
|
+
export function termIndex(catalogue: readonly CatalogueEntry[], arm: Arm): Map<string, Set<string>> {
|
|
304
|
+
const index = new Map<string, Set<string>>();
|
|
305
|
+
for (const entry of catalogue) index.set(entry.name, armTerms(entry, arm));
|
|
306
|
+
return index;
|
|
307
|
+
}
|