@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
|
@@ -32,17 +32,47 @@
|
|
|
32
32
|
* German would be a heuristic in a file called a schema check: it would pass a
|
|
33
33
|
* German-looking English sentence and fail a short German one, and its
|
|
34
34
|
* failures would be unactionable. So German is declared — `"language": "de"`
|
|
35
|
-
* on the case — and declaration is checked. Forward-only, because
|
|
36
|
-
*
|
|
37
|
-
*
|
|
35
|
+
* on the case — and declaration is checked. Forward-only, because the field
|
|
36
|
+
* postdates almost every corpus: 25 of the 100 files in the shipped tree carry
|
|
37
|
+
* it today, so requiring it everywhere would red 75 files for a field that did
|
|
38
|
+
* not exist when they were written. (Both numbers move as corpora land; they
|
|
39
|
+
* are stated as of 2026-08-30 and are illustration, not a threshold — nothing
|
|
40
|
+
* reads them.)
|
|
38
41
|
*
|
|
39
|
-
* ## Forward-only, in
|
|
42
|
+
* ## Forward-only, in three senses now
|
|
40
43
|
*
|
|
41
44
|
* The COUNT discipline (>=3 positives, >=2 near-misses) applies to every file
|
|
42
45
|
* today: exactly two files fail it, and both are listed as grandfathered by
|
|
43
46
|
* name rather than by a numeric baseline, so a third failure cannot hide inside
|
|
44
47
|
* a count. The LANGUAGE discipline applies only to files the diff adds or
|
|
45
|
-
* changes.
|
|
48
|
+
* changes. So, since 2026-08-30, does the CASE-CLASS discipline.
|
|
49
|
+
*
|
|
50
|
+
* ## The case class — three semantic classes, declared, never inferred
|
|
51
|
+
*
|
|
52
|
+
* `road-to-governed-harness-evolution` step 2.3 asked for a four-class corpus
|
|
53
|
+
* where this gate had two: the boolean. AI council 2026-08-30, anthropic +
|
|
54
|
+
* openai, 2/2 convergent, re-scoped it to THREE semantic classes on this
|
|
55
|
+
* surface and moved the fourth elsewhere:
|
|
56
|
+
*
|
|
57
|
+
* - `exemplar` — a success case; requires `trigger: true`.
|
|
58
|
+
* - `near-miss` — vocabulary genuinely overlaps a neighbour, and the
|
|
59
|
+
* answer is still no; requires `trigger: false`.
|
|
60
|
+
* - `counterexample` — unrelated, guarding over-triggering rather than a
|
|
61
|
+
* neighbour; requires `trigger: false`.
|
|
62
|
+
*
|
|
63
|
+
* The fourth class the step named — `failure`, a case the routing gets wrong
|
|
64
|
+
* TODAY — is deliberately NOT here. Both seats reached the same reason
|
|
65
|
+
* independently: it is an ORTHOGONAL axis. `exemplar` / `near-miss` /
|
|
66
|
+
* `counterexample` describe intended routing; `failure` describes observed
|
|
67
|
+
* behaviour, and one case can be both. A corpus file is a regression LOCK, so
|
|
68
|
+
* a known-wrong case placed in it is red by construction, and a rule requiring
|
|
69
|
+
* one per file would reward deliberately broken routing.
|
|
70
|
+
*
|
|
71
|
+
* This does not contradict `:20-26` above. That paragraph says the near-miss /
|
|
72
|
+
* unrelated-negative distinction is not machine-DECIDABLE, and it still is not:
|
|
73
|
+
* nothing here detects it. The class is DECLARED by the author and the
|
|
74
|
+
* declaration is validated — precisely the mechanism the German requirement
|
|
75
|
+
* already uses two paragraphs up, for the same reason.
|
|
46
76
|
*
|
|
47
77
|
* Exit codes: 0 = clean · 1 = a discipline violation · 2 = dead scope.
|
|
48
78
|
*/
|
|
@@ -54,12 +84,33 @@ import { fileURLToPath } from 'node:url';
|
|
|
54
84
|
|
|
55
85
|
import { GateLedger } from './_lib/gate_ledger.js';
|
|
56
86
|
import { type SelfTestCase, runGateCli, runSelfTest } from './_lib/gate_self_test.js';
|
|
87
|
+
import { resolveBaseRef } from './_lib/ratchet_base_ref.js';
|
|
57
88
|
import { DeadScopeError, reportScanned } from './_lib/scan_scope.js';
|
|
58
89
|
|
|
59
90
|
const HERE = fileURLToPath(import.meta.url);
|
|
60
91
|
const REAL_REPO_ROOT = path.resolve(path.dirname(HERE), '..', '..');
|
|
61
92
|
const REPO_ROOT = process.env['LINT_SKILL_TRIGGER_CORPUS_ROOT'] ?? REAL_REPO_ROOT;
|
|
62
93
|
|
|
94
|
+
/**
|
|
95
|
+
* Treat every scanned unit as diff-touched, so the forward-only disciplines
|
|
96
|
+
* apply to all of them.
|
|
97
|
+
*
|
|
98
|
+
* This can only ever WIDEN the checked set — there is no direction in which it
|
|
99
|
+
* suppresses a finding — which is what makes it safe to honour from the
|
|
100
|
+
* environment. `--self-test` needs it because its fixtures live in a temporary
|
|
101
|
+
* directory that is not a git repository, so `changedUnits` finds nothing
|
|
102
|
+
* there and the class rules would be silently unreachable: a self-test that
|
|
103
|
+
* cannot reach the rule it claims to prove is the exact no-op this harness
|
|
104
|
+
* exists to catch.
|
|
105
|
+
*/
|
|
106
|
+
function forwardAll(): boolean {
|
|
107
|
+
// Read per CALL, not at module load. `selfTest` spawns a subprocess so a
|
|
108
|
+
// module-level const worked there by accident; an in-process caller — a
|
|
109
|
+
// unit test, or any future embedder — could not reach the flag at all,
|
|
110
|
+
// which made the widening path itself untestable without a spawn.
|
|
111
|
+
return process.env['LINT_SKILL_TRIGGER_CORPUS_FORWARD_ALL'] === '1';
|
|
112
|
+
}
|
|
113
|
+
|
|
63
114
|
export const MIN_POSITIVES = 3;
|
|
64
115
|
export const MIN_NEAR_MISSES = 2;
|
|
65
116
|
|
|
@@ -71,6 +122,22 @@ export const MIN_NEAR_MISSES = 2;
|
|
|
71
122
|
*/
|
|
72
123
|
export const GRANDFATHERED = new Set(['brand-asset-generation', 'estimate-ticket']);
|
|
73
124
|
|
|
125
|
+
/**
|
|
126
|
+
* The closed case-class vocabulary, and the polarity each class requires.
|
|
127
|
+
*
|
|
128
|
+
* Polarity is part of the vocabulary rather than a separate convention: a
|
|
129
|
+
* `near-miss` carrying `trigger: true` is not a near miss, it is a positive
|
|
130
|
+
* that was mislabelled, and a class system that cannot say so buys nothing
|
|
131
|
+
* over a free-text tag.
|
|
132
|
+
*/
|
|
133
|
+
export const CASE_CLASS_POLARITY: Readonly<Record<string, boolean>> = {
|
|
134
|
+
exemplar: true,
|
|
135
|
+
'near-miss': false,
|
|
136
|
+
counterexample: false,
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
export const CASE_CLASSES: readonly string[] = Object.keys(CASE_CLASS_POLARITY);
|
|
140
|
+
|
|
74
141
|
export interface CorpusStats {
|
|
75
142
|
unit: string;
|
|
76
143
|
positives: number;
|
|
@@ -78,11 +145,33 @@ export interface CorpusStats {
|
|
|
78
145
|
germanPositives: number;
|
|
79
146
|
/** True when at least one case declares a language at all. */
|
|
80
147
|
declaresLanguage: boolean;
|
|
148
|
+
/** Cases in the `queries` shape that declare no `class` at all. */
|
|
149
|
+
unclassified: number;
|
|
150
|
+
/** Declared class values outside the closed vocabulary, as written. */
|
|
151
|
+
badClassValues: string[];
|
|
152
|
+
/** Cases whose declared class contradicts their `trigger` boolean. */
|
|
153
|
+
classPolarityErrors: string[];
|
|
154
|
+
/** Which vocabulary members appear at least once. */
|
|
155
|
+
classesPresent: string[];
|
|
156
|
+
/**
|
|
157
|
+
* True when the file uses the legacy `should_trigger` / `should_not_trigger`
|
|
158
|
+
* arrays, whose entries are bare strings and cannot carry a class.
|
|
159
|
+
*/
|
|
160
|
+
legacyShape: boolean;
|
|
81
161
|
}
|
|
82
162
|
|
|
83
163
|
export interface Violation {
|
|
84
164
|
unit: string;
|
|
85
|
-
rule:
|
|
165
|
+
rule:
|
|
166
|
+
| 'positives'
|
|
167
|
+
| 'near-misses'
|
|
168
|
+
| 'german'
|
|
169
|
+
| 'malformed'
|
|
170
|
+
| 'class-missing'
|
|
171
|
+
| 'class-vocab'
|
|
172
|
+
| 'class-polarity'
|
|
173
|
+
| 'class-coverage'
|
|
174
|
+
| 'class-shape';
|
|
86
175
|
message: string;
|
|
87
176
|
}
|
|
88
177
|
|
|
@@ -90,6 +179,7 @@ interface RawCase {
|
|
|
90
179
|
q?: string;
|
|
91
180
|
trigger?: boolean;
|
|
92
181
|
language?: string;
|
|
182
|
+
class?: unknown;
|
|
93
183
|
}
|
|
94
184
|
|
|
95
185
|
/** Read one corpus file into counts, across both shapes that exist. */
|
|
@@ -104,16 +194,50 @@ export function statsFor(unit: string, file: string): CorpusStats {
|
|
|
104
194
|
let nearMisses = queries.filter((q) => q.trigger === false).length;
|
|
105
195
|
positives += (doc.should_trigger ?? []).length;
|
|
106
196
|
nearMisses += (doc.should_not_trigger ?? []).length;
|
|
197
|
+
|
|
198
|
+
const badClassValues: string[] = [];
|
|
199
|
+
const classPolarityErrors: string[] = [];
|
|
200
|
+
const present = new Set<string>();
|
|
201
|
+
let unclassified = 0;
|
|
202
|
+
for (const q of queries) {
|
|
203
|
+
const raw = q.class;
|
|
204
|
+
if (raw === undefined || raw === null || raw === '') {
|
|
205
|
+
unclassified += 1;
|
|
206
|
+
continue;
|
|
207
|
+
}
|
|
208
|
+
if (typeof raw !== 'string' || !(raw in CASE_CLASS_POLARITY)) {
|
|
209
|
+
badClassValues.push(String(raw));
|
|
210
|
+
continue;
|
|
211
|
+
}
|
|
212
|
+
present.add(raw);
|
|
213
|
+
if (q.trigger !== CASE_CLASS_POLARITY[raw]) {
|
|
214
|
+
classPolarityErrors.push(`${raw} on \`trigger: ${String(q.trigger)}\``);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
107
218
|
return {
|
|
108
219
|
unit,
|
|
109
220
|
positives,
|
|
110
221
|
nearMisses,
|
|
111
222
|
germanPositives: queries.filter((q) => q.trigger === true && q.language === 'de').length,
|
|
112
223
|
declaresLanguage: queries.some((q) => typeof q.language === 'string'),
|
|
224
|
+
unclassified,
|
|
225
|
+
badClassValues,
|
|
226
|
+
classPolarityErrors,
|
|
227
|
+
classesPresent: [...present].sort(),
|
|
228
|
+
legacyShape:
|
|
229
|
+
(doc.should_trigger ?? []).length > 0 || (doc.should_not_trigger ?? []).length > 0,
|
|
113
230
|
};
|
|
114
231
|
}
|
|
115
232
|
|
|
116
|
-
|
|
233
|
+
/**
|
|
234
|
+
* `forward` is the diff-touched flag: true when this corpus file was added or
|
|
235
|
+
* changed against the base ref. The COUNT discipline ignores it; the LANGUAGE
|
|
236
|
+
* and CASE-CLASS disciplines are gated on it, so an untouched file authored
|
|
237
|
+
* before either existed is not red for a field that did not exist when it was
|
|
238
|
+
* written. Migration is by touch: the file that changes migrates.
|
|
239
|
+
*/
|
|
240
|
+
export function judge(s: CorpusStats, forward: boolean): Violation[] {
|
|
117
241
|
const out: Violation[] = [];
|
|
118
242
|
if (GRANDFATHERED.has(s.unit)) return out;
|
|
119
243
|
if (s.positives < MIN_POSITIVES) {
|
|
@@ -130,7 +254,7 @@ export function judge(s: CorpusStats, requireLanguage: boolean): Violation[] {
|
|
|
130
254
|
message: `${String(s.nearMisses)} near-miss(es), the discipline asks for ${String(MIN_NEAR_MISSES)}`,
|
|
131
255
|
});
|
|
132
256
|
}
|
|
133
|
-
if (
|
|
257
|
+
if (forward && s.germanPositives < 1) {
|
|
134
258
|
out.push({
|
|
135
259
|
unit: s.unit,
|
|
136
260
|
rule: 'german',
|
|
@@ -139,31 +263,136 @@ export function judge(s: CorpusStats, requireLanguage: boolean): Violation[] {
|
|
|
139
263
|
'a detector would pass German-looking English and fail short German',
|
|
140
264
|
});
|
|
141
265
|
}
|
|
266
|
+
if (forward) out.push(...judgeClasses(s));
|
|
267
|
+
return out;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* The case-class rules, all forward-only. Split out so the findings read as one
|
|
272
|
+
* discipline rather than as unrelated additions to `judge`.
|
|
273
|
+
*
|
|
274
|
+
* **`class-shape` cannot fire on the tree as it stands, and that is stated
|
|
275
|
+
* rather than left to be discovered** (completion review, 2026-08-30). It fires
|
|
276
|
+
* on a legacy-shaped corpus; the only two legacy-shaped files in the tree are
|
|
277
|
+
* exactly the two `GRANDFATHERED` units, and `judge` returns before reaching
|
|
278
|
+
* here for those. So it is a FORWARD guard — it catches a legacy-shaped file
|
|
279
|
+
* added from now on, or a grandfathered one promoted — not a rule with live
|
|
280
|
+
* coverage. It is exercised by synthetic fixtures in `--self-test`, so it is
|
|
281
|
+
* tested; what it is not is currently reachable from real data. Counting it
|
|
282
|
+
* among the rules this gate enforces TODAY would inflate the coverage claim,
|
|
283
|
+
* which is the failure this whole file exists to prevent one level down.
|
|
284
|
+
*/
|
|
285
|
+
function judgeClasses(s: CorpusStats): Violation[] {
|
|
286
|
+
const out: Violation[] = [];
|
|
287
|
+
const vocab = CASE_CLASSES.join(' | ');
|
|
288
|
+
if (s.legacyShape) {
|
|
289
|
+
out.push({
|
|
290
|
+
unit: s.unit,
|
|
291
|
+
rule: 'class-shape',
|
|
292
|
+
message:
|
|
293
|
+
'the `should_trigger` / `should_not_trigger` arrays hold bare strings and ' +
|
|
294
|
+
'cannot carry a case class — migrate this file to the `queries` shape',
|
|
295
|
+
});
|
|
296
|
+
return out;
|
|
297
|
+
}
|
|
298
|
+
if (s.unclassified > 0) {
|
|
299
|
+
out.push({
|
|
300
|
+
unit: s.unit,
|
|
301
|
+
rule: 'class-missing',
|
|
302
|
+
message:
|
|
303
|
+
`${String(s.unclassified)} case(s) declare no \`class\` (${vocab}). ` +
|
|
304
|
+
'Declared, never inferred — the near-miss / counterexample split is not ' +
|
|
305
|
+
'machine-decidable, so the author states it and the gate checks the statement',
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
if (s.badClassValues.length > 0) {
|
|
309
|
+
out.push({
|
|
310
|
+
unit: s.unit,
|
|
311
|
+
rule: 'class-vocab',
|
|
312
|
+
message: `class outside the closed vocabulary (${vocab}): ${s.badClassValues.sort().join(', ')}`,
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
if (s.classPolarityErrors.length > 0) {
|
|
316
|
+
out.push({
|
|
317
|
+
unit: s.unit,
|
|
318
|
+
rule: 'class-polarity',
|
|
319
|
+
message:
|
|
320
|
+
'class contradicts its own `trigger` boolean: ' +
|
|
321
|
+
`${s.classPolarityErrors.sort().join(', ')}. \`exemplar\` is a positive; ` +
|
|
322
|
+
'`near-miss` and `counterexample` are negatives',
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
const missing = CASE_CLASSES.filter((c) => !s.classesPresent.includes(c));
|
|
326
|
+
if (missing.length > 0) {
|
|
327
|
+
out.push({
|
|
328
|
+
unit: s.unit,
|
|
329
|
+
rule: 'class-coverage',
|
|
330
|
+
message:
|
|
331
|
+
`no case carries ${missing.join(' or ')}. A corpus of positives and ` +
|
|
332
|
+
'near-misses alone cannot show whether the skill over-triggers on ' +
|
|
333
|
+
'unrelated input, which is what a counterexample is for',
|
|
334
|
+
});
|
|
335
|
+
}
|
|
142
336
|
return out;
|
|
143
337
|
}
|
|
144
338
|
|
|
339
|
+
/**
|
|
340
|
+
* What the diff scope actually is — three states, deliberately not collapsed.
|
|
341
|
+
*
|
|
342
|
+
* The previous shape returned a bare `Set` and an empty one meant BOTH "the
|
|
343
|
+
* diff touched no corpus file" and "git could not answer". Those are opposite
|
|
344
|
+
* facts: the first is a clean tree, the second is a gate that cannot know what
|
|
345
|
+
* changed. Collapsing them made every forward-only rule a silent no-op wherever
|
|
346
|
+
* the base ref does not resolve — a shallow clone, a fork remote, a tarball, a
|
|
347
|
+
* worktree that never fetched — while `main()` still printed its success line
|
|
348
|
+
* asserting the discipline had run. A gate that reports green on a scope it
|
|
349
|
+
* could not read is the exact failure `DeadScopeError` exists for, applied one
|
|
350
|
+
* level up from the population to the DIFF.
|
|
351
|
+
*/
|
|
352
|
+
export type ChangedScope =
|
|
353
|
+
| { kind: 'diff'; units: Set<string> }
|
|
354
|
+
| { kind: 'no-repo' }
|
|
355
|
+
| { kind: 'base-unresolvable'; base: string };
|
|
356
|
+
|
|
357
|
+
function gitOk(root: string, args: readonly string[]): boolean {
|
|
358
|
+
try {
|
|
359
|
+
execFileSync('git', [...args], {
|
|
360
|
+
cwd: root,
|
|
361
|
+
encoding: 'utf-8',
|
|
362
|
+
// Silenced deliberately: outside a repo git prints its whole usage
|
|
363
|
+
// text to stderr, and a gate that dumps a manual page on a path it
|
|
364
|
+
// already handles is noise a reader has to learn to ignore.
|
|
365
|
+
stdio: ['ignore', 'ignore', 'ignore'],
|
|
366
|
+
});
|
|
367
|
+
return true;
|
|
368
|
+
} catch {
|
|
369
|
+
return false;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
145
373
|
/** Corpus files the diff added or modified, relative to a base ref. */
|
|
146
|
-
export function changedUnits(root: string, base: string):
|
|
374
|
+
export function changedUnits(root: string, base: string): ChangedScope {
|
|
375
|
+
if (!gitOk(root, ['rev-parse', '--git-dir'])) return { kind: 'no-repo' };
|
|
376
|
+
if (!gitOk(root, ['rev-parse', '--verify', '--quiet', base])) {
|
|
377
|
+
return { kind: 'base-unresolvable', base };
|
|
378
|
+
}
|
|
147
379
|
let out = '';
|
|
148
380
|
try {
|
|
149
381
|
out = execFileSync('git', ['diff', '--name-only', `${base}...HEAD`], {
|
|
150
382
|
cwd: root,
|
|
151
383
|
encoding: 'utf-8',
|
|
152
|
-
// Silenced deliberately: outside a repo (a self-test fixture, a
|
|
153
|
-
// tarball install) git prints its whole usage text to stderr, and
|
|
154
|
-
// a gate that dumps a manual page on a path it already handles is
|
|
155
|
-
// noise a reader has to learn to ignore.
|
|
156
384
|
stdio: ['ignore', 'pipe', 'ignore'],
|
|
157
385
|
});
|
|
158
386
|
} catch {
|
|
159
|
-
|
|
387
|
+
// The ref resolved a line ago, so a failure here is not "no diff".
|
|
388
|
+
return { kind: 'base-unresolvable', base };
|
|
160
389
|
}
|
|
161
390
|
const units = new Set<string>();
|
|
162
391
|
for (const line of out.split('\n')) {
|
|
163
392
|
const m = /^src\/skills\/([^/]+)\/evals\/triggers\.json$/.exec(line.trim());
|
|
164
393
|
if (m?.[1] !== undefined) units.add(m[1]);
|
|
165
394
|
}
|
|
166
|
-
return units;
|
|
395
|
+
return { kind: 'diff', units };
|
|
167
396
|
}
|
|
168
397
|
|
|
169
398
|
export interface Result {
|
|
@@ -172,7 +401,7 @@ export interface Result {
|
|
|
172
401
|
ledger: GateLedger;
|
|
173
402
|
}
|
|
174
403
|
|
|
175
|
-
export function evaluate(root = REPO_ROOT, base
|
|
404
|
+
export function evaluate(root = REPO_ROOT, base?: string): Result {
|
|
176
405
|
const dir = path.join(root, 'src', 'skills');
|
|
177
406
|
let entries: fs.Dirent[];
|
|
178
407
|
try {
|
|
@@ -183,7 +412,37 @@ export function evaluate(root = REPO_ROOT, base = 'origin/main'): Result {
|
|
|
183
412
|
'src/skills is unreadable — a corpus gate with no corpus passes every tree.',
|
|
184
413
|
);
|
|
185
414
|
}
|
|
186
|
-
|
|
415
|
+
// `origin/main` is exactly the ref that is NOT available where this matters:
|
|
416
|
+
// actions/checkout does a shallow PR-merge fetch, so a PR build has no
|
|
417
|
+
// remote-tracking main at all. Hardcoding it made the first version of this
|
|
418
|
+
// guard a hard CI failure on every run — the opposite of the silent no-op it
|
|
419
|
+
// replaced, and no better. `resolveBaseRef` is this repository's existing
|
|
420
|
+
// answer to the same problem (RATCHET_BASE_REF, then GITHUB_BASE_REF, then
|
|
421
|
+
// the merge commit's first parent on Actions, then origin/main), so the gate
|
|
422
|
+
// uses it rather than inventing a second ladder. An explicit `base` still
|
|
423
|
+
// wins, which is what the tests pass.
|
|
424
|
+
const resolved = base ?? resolveBaseRef(root);
|
|
425
|
+
const scope: ChangedScope =
|
|
426
|
+
resolved === null ? { kind: 'base-unresolvable', base: '(none resolved)' } : changedUnits(root, resolved);
|
|
427
|
+
// FORWARD_ALL widens to every unit, so it needs no diff and is checked
|
|
428
|
+
// first — that is what keeps `--self-test`, which runs in a temporary
|
|
429
|
+
// non-repo directory, reachable.
|
|
430
|
+
const wideMode = forwardAll();
|
|
431
|
+
if (!wideMode && scope.kind !== 'diff') {
|
|
432
|
+
throw new DeadScopeError(
|
|
433
|
+
'lint_skill_trigger_corpus',
|
|
434
|
+
scope.kind === 'no-repo'
|
|
435
|
+
? 'not a git repository, so the diff scope cannot be read and every ' +
|
|
436
|
+
'forward-only rule would be unreachable while this gate printed green. ' +
|
|
437
|
+
'Run it inside the repo, or set LINT_SKILL_TRIGGER_CORPUS_FORWARD_ALL=1 ' +
|
|
438
|
+
'to check every unit instead.'
|
|
439
|
+
: `base ref ${scope.base} does not resolve, so the diff scope cannot be ` +
|
|
440
|
+
'read and every forward-only rule would be unreachable while this gate ' +
|
|
441
|
+
'printed green. Fetch it (`git fetch origin main`) or pass a base that ' +
|
|
442
|
+
'exists; LINT_SKILL_TRIGGER_CORPUS_FORWARD_ALL=1 checks every unit instead.',
|
|
443
|
+
);
|
|
444
|
+
}
|
|
445
|
+
const changed = scope.kind === 'diff' ? scope.units : new Set<string>();
|
|
187
446
|
const ledger = new GateLedger('lint_skill_trigger_corpus');
|
|
188
447
|
const violations: Violation[] = [];
|
|
189
448
|
let scanned = 0;
|
|
@@ -195,7 +454,7 @@ export function evaluate(root = REPO_ROOT, base = 'origin/main'): Result {
|
|
|
195
454
|
ledger.plan(e.name);
|
|
196
455
|
let own: Violation[];
|
|
197
456
|
try {
|
|
198
|
-
own = judge(statsFor(e.name, file), changed.has(e.name));
|
|
457
|
+
own = judge(statsFor(e.name, file), wideMode || changed.has(e.name));
|
|
199
458
|
} catch {
|
|
200
459
|
own = [{ unit: e.name, rule: 'malformed', message: 'is not parseable JSON' }];
|
|
201
460
|
}
|
|
@@ -206,7 +465,7 @@ export function evaluate(root = REPO_ROOT, base = 'origin/main'): Result {
|
|
|
206
465
|
if (scanned === 0) {
|
|
207
466
|
throw new DeadScopeError(
|
|
208
467
|
'lint_skill_trigger_corpus',
|
|
209
|
-
'zero corpus files found under src/skills/*/evals/triggers.json —
|
|
468
|
+
'zero corpus files found under src/skills/*/evals/triggers.json — 100 exist ' +
|
|
210
469
|
'in the shipped tree, so an empty scan is a moved root, not a clean one.',
|
|
211
470
|
);
|
|
212
471
|
}
|
|
@@ -221,14 +480,43 @@ export function selfTest(): number {
|
|
|
221
480
|
const d = path.join(root, 'src', 'skills', unit, 'evals');
|
|
222
481
|
fs.mkdirSync(d, { recursive: true });
|
|
223
482
|
fs.writeFileSync(path.join(d, 'triggers.json'), JSON.stringify(body));
|
|
483
|
+
// A REAL repo with a resolvable `origin/main`, not a bare directory.
|
|
484
|
+
//
|
|
485
|
+
// The non-forward arms below assert that a corpus is accepted when it
|
|
486
|
+
// is NOT diff-touched, and they used to get that for free: outside a
|
|
487
|
+
// repo `changedUnits` returned an empty set, which the gate could not
|
|
488
|
+
// distinguish from a clean diff. That conflation was the finding this
|
|
489
|
+
// branch fixed — an unreadable diff now REFUSES — so the fixtures have
|
|
490
|
+
// to supply the condition they were only ever simulating. Committing
|
|
491
|
+
// the file and pointing `origin/main` at that same commit makes the
|
|
492
|
+
// diff genuinely empty, which is what those arms mean.
|
|
493
|
+
const git = (...args: string[]): void => {
|
|
494
|
+
execFileSync('git', args, {
|
|
495
|
+
cwd: root,
|
|
496
|
+
stdio: ['ignore', 'ignore', 'ignore'],
|
|
497
|
+
env: {
|
|
498
|
+
...process.env,
|
|
499
|
+
GIT_AUTHOR_NAME: 'selftest',
|
|
500
|
+
GIT_AUTHOR_EMAIL: 'selftest@invalid',
|
|
501
|
+
GIT_COMMITTER_NAME: 'selftest',
|
|
502
|
+
GIT_COMMITTER_EMAIL: 'selftest@invalid',
|
|
503
|
+
},
|
|
504
|
+
});
|
|
505
|
+
};
|
|
506
|
+
git('init', '-q');
|
|
507
|
+
git('add', '-A');
|
|
508
|
+
git('commit', '-q', '-m', 'fixture');
|
|
509
|
+
git('update-ref', 'refs/remotes/origin/main', 'HEAD');
|
|
224
510
|
return root;
|
|
225
511
|
};
|
|
226
|
-
const run = (root: string): number => {
|
|
512
|
+
const run = (root: string, forwardAll = false): number => {
|
|
227
513
|
process.env['LINT_SKILL_TRIGGER_CORPUS_ROOT'] = root;
|
|
514
|
+
if (forwardAll) process.env['LINT_SKILL_TRIGGER_CORPUS_FORWARD_ALL'] = '1';
|
|
228
515
|
try {
|
|
229
516
|
return runGateCli(REAL_REPO_ROOT, 'src/scripts/lint_skill_trigger_corpus.ts', [], root);
|
|
230
517
|
} finally {
|
|
231
518
|
delete process.env['LINT_SKILL_TRIGGER_CORPUS_ROOT'];
|
|
519
|
+
delete process.env['LINT_SKILL_TRIGGER_CORPUS_FORWARD_ALL'];
|
|
232
520
|
}
|
|
233
521
|
};
|
|
234
522
|
const good = {
|
|
@@ -240,6 +528,19 @@ export function selfTest(): number {
|
|
|
240
528
|
{ q: 'e', trigger: false },
|
|
241
529
|
],
|
|
242
530
|
};
|
|
531
|
+
/** The same corpus, fully classified and German-declared — forward-clean. */
|
|
532
|
+
const classified = {
|
|
533
|
+
queries: [
|
|
534
|
+
{ q: 'a', trigger: true, class: 'exemplar' },
|
|
535
|
+
{ q: 'b', trigger: true, class: 'exemplar' },
|
|
536
|
+
{ q: 'c', trigger: true, class: 'exemplar', language: 'de' },
|
|
537
|
+
{ q: 'd', trigger: false, class: 'near-miss' },
|
|
538
|
+
{ q: 'e', trigger: false, class: 'counterexample' },
|
|
539
|
+
],
|
|
540
|
+
};
|
|
541
|
+
const mutate = (fn: (qs: Record<string, unknown>[]) => Record<string, unknown>[]) => ({
|
|
542
|
+
queries: fn(JSON.parse(JSON.stringify(classified.queries)) as Record<string, unknown>[]),
|
|
543
|
+
});
|
|
243
544
|
const cases: SelfTestCase[] = [
|
|
244
545
|
{
|
|
245
546
|
name: 'a compliant corpus is accepted',
|
|
@@ -293,13 +594,114 @@ export function selfTest(): number {
|
|
|
293
594
|
return run(root);
|
|
294
595
|
},
|
|
295
596
|
},
|
|
597
|
+
// --- case-class discipline, forward-only. Every case below runs with
|
|
598
|
+
// the forward flag forced on; the pair at the end proves the flag is
|
|
599
|
+
// what turns the rule on, so a rule that fired unconditionally would
|
|
600
|
+
// be caught here rather than by a reviewer.
|
|
601
|
+
{
|
|
602
|
+
name: 'a fully classified corpus is accepted under the class discipline',
|
|
603
|
+
expect: 'accept',
|
|
604
|
+
run: () => run(mkRoot('probe', classified), true),
|
|
605
|
+
},
|
|
606
|
+
{
|
|
607
|
+
name: 'an unclassified case is rejected',
|
|
608
|
+
expect: 'reject',
|
|
609
|
+
run: () =>
|
|
610
|
+
run(
|
|
611
|
+
mkRoot(
|
|
612
|
+
'probe',
|
|
613
|
+
mutate((qs) => {
|
|
614
|
+
delete qs[0]?.['class'];
|
|
615
|
+
return qs;
|
|
616
|
+
}),
|
|
617
|
+
),
|
|
618
|
+
true,
|
|
619
|
+
),
|
|
620
|
+
},
|
|
621
|
+
{
|
|
622
|
+
name: 'a class outside the closed vocabulary is rejected',
|
|
623
|
+
expect: 'reject',
|
|
624
|
+
run: () =>
|
|
625
|
+
run(
|
|
626
|
+
mkRoot(
|
|
627
|
+
'probe',
|
|
628
|
+
mutate((qs) => {
|
|
629
|
+
if (qs[0]) qs[0]['class'] = 'positive';
|
|
630
|
+
return qs;
|
|
631
|
+
}),
|
|
632
|
+
),
|
|
633
|
+
true,
|
|
634
|
+
),
|
|
635
|
+
},
|
|
636
|
+
{
|
|
637
|
+
name: 'a near-miss on trigger:true is rejected — polarity is part of the vocabulary',
|
|
638
|
+
expect: 'reject',
|
|
639
|
+
run: () =>
|
|
640
|
+
run(
|
|
641
|
+
mkRoot(
|
|
642
|
+
'probe',
|
|
643
|
+
mutate((qs) => {
|
|
644
|
+
if (qs[0]) qs[0]['class'] = 'near-miss';
|
|
645
|
+
return qs;
|
|
646
|
+
}),
|
|
647
|
+
),
|
|
648
|
+
true,
|
|
649
|
+
),
|
|
650
|
+
},
|
|
651
|
+
{
|
|
652
|
+
name: 'an exemplar on trigger:false is rejected — the other polarity direction',
|
|
653
|
+
expect: 'reject',
|
|
654
|
+
run: () =>
|
|
655
|
+
run(
|
|
656
|
+
mkRoot(
|
|
657
|
+
'probe',
|
|
658
|
+
mutate((qs) => {
|
|
659
|
+
if (qs[4]) qs[4]['class'] = 'exemplar';
|
|
660
|
+
return qs;
|
|
661
|
+
}),
|
|
662
|
+
),
|
|
663
|
+
true,
|
|
664
|
+
),
|
|
665
|
+
},
|
|
666
|
+
{
|
|
667
|
+
name: 'a corpus with no counterexample at all is rejected',
|
|
668
|
+
expect: 'reject',
|
|
669
|
+
run: () =>
|
|
670
|
+
run(
|
|
671
|
+
mkRoot(
|
|
672
|
+
'probe',
|
|
673
|
+
mutate((qs) => {
|
|
674
|
+
if (qs[4]) qs[4]['class'] = 'near-miss';
|
|
675
|
+
return qs;
|
|
676
|
+
}),
|
|
677
|
+
),
|
|
678
|
+
true,
|
|
679
|
+
),
|
|
680
|
+
},
|
|
681
|
+
{
|
|
682
|
+
name: 'the legacy string-array shape is rejected under the class discipline',
|
|
683
|
+
expect: 'reject',
|
|
684
|
+
run: () =>
|
|
685
|
+
run(
|
|
686
|
+
mkRoot('probe', {
|
|
687
|
+
should_trigger: ['a', 'b', 'c'],
|
|
688
|
+
should_not_trigger: ['d', 'e'],
|
|
689
|
+
}),
|
|
690
|
+
true,
|
|
691
|
+
),
|
|
692
|
+
},
|
|
693
|
+
{
|
|
694
|
+
name: 'the SAME unclassified corpus is accepted when NOT diff-touched',
|
|
695
|
+
expect: 'accept',
|
|
696
|
+
run: () => run(mkRoot('probe', good), false),
|
|
697
|
+
},
|
|
296
698
|
];
|
|
297
699
|
try {
|
|
298
700
|
return runSelfTest({
|
|
299
701
|
gate: 'lint_skill_trigger_corpus',
|
|
300
702
|
cases,
|
|
301
|
-
minCases:
|
|
302
|
-
minRejectCases:
|
|
703
|
+
minCases: 15,
|
|
704
|
+
minRejectCases: 10,
|
|
303
705
|
});
|
|
304
706
|
} finally {
|
|
305
707
|
fs.rmSync(tmp, { recursive: true, force: true });
|
|
@@ -330,7 +732,8 @@ export function main(argv: string[] = process.argv.slice(2), root = REPO_ROOT):
|
|
|
330
732
|
process.stdout.write(
|
|
331
733
|
`lint_skill_trigger_corpus: ${String(r.scanned)} corpus file(s) hold the discipline ` +
|
|
332
734
|
`(>=${String(MIN_POSITIVES)} positives, >=${String(MIN_NEAR_MISSES)} near-misses; ` +
|
|
333
|
-
`${String(GRANDFATHERED.size)} grandfathered by name)
|
|
735
|
+
`${String(GRANDFATHERED.size)} grandfathered by name). Diff-touched files also ` +
|
|
736
|
+
`carry a declared case class per query (${CASE_CLASSES.join(' | ')}).\n`,
|
|
334
737
|
);
|
|
335
738
|
return 0;
|
|
336
739
|
}
|
|
@@ -609,6 +609,22 @@ function _cycle(graph: Map<string, string[]>): string[] | null {
|
|
|
609
609
|
// iterdir / glob helpers (pathlib-faithful sort)
|
|
610
610
|
// ---------------------------------------------------------------------------
|
|
611
611
|
|
|
612
|
+
/**
|
|
613
|
+
* Directories under `agents/tickets/` that are NOT ticket bundles.
|
|
614
|
+
*
|
|
615
|
+
* `archive` was the original member and was tested inline. `symptoms` joins it
|
|
616
|
+
* because it is a different artefact class that happens to live under the same
|
|
617
|
+
* root: one markdown file per operator symptom report, plus a README and a
|
|
618
|
+
* template, established so a production symptom had somewhere in the tree to
|
|
619
|
+
* land. It has no tickets, no dependency graph and no Definition-of-Ready, so
|
|
620
|
+
* every check below is meaningless there — and demanding a `manifest.yml` from
|
|
621
|
+
* it is the gate asserting a contract that directory never claimed.
|
|
622
|
+
*
|
|
623
|
+
* A named set rather than a second `||`: the next non-bundle directory should
|
|
624
|
+
* cost one line here instead of another inline special case.
|
|
625
|
+
*/
|
|
626
|
+
const NON_BUNDLE_DIRS: ReadonlySet<string> = new Set(['archive', 'symptoms']);
|
|
627
|
+
|
|
612
628
|
/** sorted(TICKETS_ROOT.iterdir()) — all entries (files + dirs), name-sorted. */
|
|
613
629
|
function _iterdirSorted(root: string): string[] {
|
|
614
630
|
let names: string[];
|
|
@@ -707,7 +723,7 @@ function lint(): number {
|
|
|
707
723
|
const bundle_ids = new Set<string>();
|
|
708
724
|
|
|
709
725
|
for (const bundle of _iterdirSorted(TICKETS_ROOT)) {
|
|
710
|
-
if (!_isDir(bundle) || path.basename(bundle)
|
|
726
|
+
if (!_isDir(bundle) || NON_BUNDLE_DIRS.has(path.basename(bundle))) {
|
|
711
727
|
continue;
|
|
712
728
|
}
|
|
713
729
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schema_version": 1,
|
|
3
|
-
"description": "Source-of-truth catalog of consumer-relevant MCP tools. Read by the stdio server (scripts/mcp_server/) and packed into the Cloud Worker bundle (internal/workers/mcp/). The 'implemented_on' field lists transports where the real handler is wired. Entries marked '[stub — implemented on demand]' are DOCUMENTATION of the on-demand backlog: per ADR-132 they are NOT registered on the stdio tools/list (the wire carries implemented tools only); the 'not_implemented' envelope contract (docs/contracts/mcp-tool-stub-envelope.md) remains for Worker parity. Generated by `
|
|
3
|
+
"description": "Source-of-truth catalog of consumer-relevant MCP tools. Read by the stdio server (scripts/mcp_server/) and packed into the Cloud Worker bundle (internal/workers/mcp/). The 'implemented_on' field lists transports where the real handler is wired. Entries marked '[stub — implemented on demand]' are DOCUMENTATION of the on-demand backlog: per ADR-132 they are NOT registered on the stdio tools/list (the wire carries implemented tools only); the 'not_implemented' envelope contract (docs/contracts/mcp-tool-stub-envelope.md) remains for Worker parity. Generated by `build_mcp_catalog` — never hand-edit this file.",
|
|
4
4
|
"install_hint_stdio": "npx -y @event4u/agent-config mcp-server",
|
|
5
5
|
"tools": [
|
|
6
6
|
{
|
|
@@ -33,7 +33,7 @@ export const CATALOG_DESCRIPTION =
|
|
|
33
33
|
'backlog: per ADR-132 they are NOT registered on the stdio tools/list ' +
|
|
34
34
|
"(the wire carries implemented tools only); the 'not_implemented' " +
|
|
35
35
|
'envelope contract (docs/contracts/mcp-tool-stub-envelope.md) remains ' +
|
|
36
|
-
'for Worker parity. Generated by `
|
|
36
|
+
'for Worker parity. Generated by `build_mcp_catalog` — ' +
|
|
37
37
|
'never hand-edit this file.';
|
|
38
38
|
|
|
39
39
|
export interface StubToolSource {
|