@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,197 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-judge position-consistency — order-swap over sampled pairwise judgments.
|
|
3
|
+
*
|
|
4
|
+
* `road-to-inbox-harvest-2026-08-e-council-topology-evidence` Phase 3, step 3.5:
|
|
5
|
+
* "repeat sampled pairwise judgments with candidate order reversed; emit a
|
|
6
|
+
* per-judge position-consistency metric", verified by "the metric exists per
|
|
7
|
+
* judge and is reported with the verdict".
|
|
8
|
+
*
|
|
9
|
+
* ── What already existed, and why this is not a second copy of it ────────────
|
|
10
|
+
* `check_quality_regression.evaluatePair` (`:84-108`) already judges every pair
|
|
11
|
+
* in both orders and resolves a flip to `inconsistent` rather than to a winner,
|
|
12
|
+
* and `_lib/judge_hygiene.ts:5-9` records that as stronger than the step that
|
|
13
|
+
* asked for it. Two things it does not do, and both are the point here:
|
|
14
|
+
*
|
|
15
|
+
* 1. It is SINGLE-JUDGE. `aggregate` returns one run-wide `inconsistency_rate`
|
|
16
|
+
* (`:216`), so two judges of differing reliability average into one number
|
|
17
|
+
* that describes neither. The step asks for the metric PER JUDGE, which is
|
|
18
|
+
* what makes it actionable: you can drop the flipper.
|
|
19
|
+
* 2. It reports presence, not DIRECTION. A judge that flips at random and a
|
|
20
|
+
* judge that always prefers whatever it was shown first produce the same
|
|
21
|
+
* inconsistency rate and need opposite remedies — the first is noise, the
|
|
22
|
+
* second is a systematic bias that survives averaging and quietly decides
|
|
23
|
+
* verdicts. `first_position_rate` separates them.
|
|
24
|
+
*
|
|
25
|
+
* That module is the thin-vs-eager token gate and is not council code; this one
|
|
26
|
+
* is council-side and stays a pure library — no transport, no fixture path, no
|
|
27
|
+
* `main`. The judge is an injected function, so the whole surface is testable
|
|
28
|
+
* against a scripted judge and costs nothing to exercise.
|
|
29
|
+
*
|
|
30
|
+
* ── Honest scope ────────────────────────────────────────────────────────────
|
|
31
|
+
* The shipped council has NO pairwise judging stage (`grep -rn pairwise
|
|
32
|
+
* src/scripts/ai_council` returns nothing): members deliberate, peer-review and
|
|
33
|
+
* are scored on findings, never compared two at a time. So this module is the
|
|
34
|
+
* metric and its renderer, exercised by the provider-leakage bench that Phase 3
|
|
35
|
+
* builds; it does not claim a live council verdict currently carries the line,
|
|
36
|
+
* because there is currently no live council judgment for it to describe.
|
|
37
|
+
*/
|
|
38
|
+
|
|
39
|
+
import { _sha256_hex } from './blind_review.js';
|
|
40
|
+
|
|
41
|
+
/** A judge's preference between the two PRESENTED candidates — order-relative. */
|
|
42
|
+
export type PairwiseVerdict = 'first' | 'second' | 'tie';
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* The pluggable judge. `first`/`second` are the candidate bodies in PRESENTED
|
|
46
|
+
* order, so a judge implementation cannot tell which arm it is looking at
|
|
47
|
+
* unless the bodies themselves leak it.
|
|
48
|
+
*/
|
|
49
|
+
export type PairwiseJudge = (ctx: { readonly id: string }, first: string, second: string) => PairwiseVerdict;
|
|
50
|
+
|
|
51
|
+
/** How a pair resolved once both orders were seen. */
|
|
52
|
+
export type PairResolution = 'a' | 'b' | 'tie' | 'inconsistent';
|
|
53
|
+
|
|
54
|
+
export interface SwapObservation {
|
|
55
|
+
readonly id: string;
|
|
56
|
+
/** Verdict with A presented first. */
|
|
57
|
+
readonly forward: PairwiseVerdict;
|
|
58
|
+
/** Verdict with B presented first. */
|
|
59
|
+
readonly reverse: PairwiseVerdict;
|
|
60
|
+
readonly resolution: PairResolution;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Judge one (a, b) pair in BOTH orders.
|
|
65
|
+
*
|
|
66
|
+
* A verdict that does not survive the swap resolves to `inconsistent`, never to
|
|
67
|
+
* a winner — a flagged tie would still be a tie in somebody's denominator,
|
|
68
|
+
* while `inconsistent` is its own bucket with its own reported rate.
|
|
69
|
+
*/
|
|
70
|
+
export function judgeBothOrders(id: string, a: string, b: string, judge: PairwiseJudge): SwapObservation {
|
|
71
|
+
const ctx = { id };
|
|
72
|
+
const forward = judge(ctx, a, b);
|
|
73
|
+
const reverse = judge(ctx, b, a);
|
|
74
|
+
// Normalise each verdict to the CANDIDATE it names, not the position.
|
|
75
|
+
const wf: PairResolution = forward === 'first' ? 'a' : forward === 'second' ? 'b' : 'tie';
|
|
76
|
+
const wr: PairResolution = reverse === 'first' ? 'b' : reverse === 'second' ? 'a' : 'tie';
|
|
77
|
+
const resolution: PairResolution = wf === wr ? wf : 'inconsistent';
|
|
78
|
+
return { id, forward, reverse, resolution };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export interface JudgeConsistency {
|
|
82
|
+
readonly judge: string;
|
|
83
|
+
/** Pairs actually repeated in both orders. */
|
|
84
|
+
readonly sampled: number;
|
|
85
|
+
/** Both orders named the same candidate, or both said tie. */
|
|
86
|
+
readonly consistent: number;
|
|
87
|
+
/** The two orders disagreed. */
|
|
88
|
+
readonly inconsistent: number;
|
|
89
|
+
/**
|
|
90
|
+
* `consistent / sampled`. `null` at zero pairs — a rate over an empty
|
|
91
|
+
* denominator is not 1.0, and reporting it as 1.0 would make an unrun swap
|
|
92
|
+
* indistinguishable from a perfectly stable judge.
|
|
93
|
+
*/
|
|
94
|
+
readonly position_consistency: number | null;
|
|
95
|
+
/**
|
|
96
|
+
* Share of DECISIVE verdicts (`first`/`second`, both orders pooled) that
|
|
97
|
+
* named whichever candidate was shown FIRST. ~0.5 is unbiased; near 1.0 is
|
|
98
|
+
* primacy, near 0.0 recency. `null` when nothing decisive was said.
|
|
99
|
+
*
|
|
100
|
+
* This is the direction an inconsistency rate cannot show, and the reason a
|
|
101
|
+
* judge that flips at random is a different problem from one that always
|
|
102
|
+
* prefers the top of the list.
|
|
103
|
+
*/
|
|
104
|
+
readonly first_position_rate: number | null;
|
|
105
|
+
/** Decisive verdicts counted for `first_position_rate`. */
|
|
106
|
+
readonly decisive_verdicts: number;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/** Per-judge metric over that judge's own swapped observations. */
|
|
110
|
+
export function positionConsistency(judge: string, obs: readonly SwapObservation[]): JudgeConsistency {
|
|
111
|
+
let consistent = 0;
|
|
112
|
+
let inconsistent = 0;
|
|
113
|
+
let firstWins = 0;
|
|
114
|
+
let decisive = 0;
|
|
115
|
+
for (const o of obs) {
|
|
116
|
+
if (o.resolution === 'inconsistent') {
|
|
117
|
+
inconsistent += 1;
|
|
118
|
+
} else {
|
|
119
|
+
consistent += 1;
|
|
120
|
+
}
|
|
121
|
+
for (const v of [o.forward, o.reverse]) {
|
|
122
|
+
if (v === 'first') {
|
|
123
|
+
decisive += 1;
|
|
124
|
+
firstWins += 1;
|
|
125
|
+
} else if (v === 'second') {
|
|
126
|
+
decisive += 1;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
const sampled = obs.length;
|
|
131
|
+
return {
|
|
132
|
+
judge,
|
|
133
|
+
sampled,
|
|
134
|
+
consistent,
|
|
135
|
+
inconsistent,
|
|
136
|
+
position_consistency: sampled > 0 ? consistent / sampled : null,
|
|
137
|
+
first_position_rate: decisive > 0 ? firstWins / decisive : null,
|
|
138
|
+
decisive_verdicts: decisive,
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Deterministic sample of `ids` at `rate`, seeded by `seed`.
|
|
144
|
+
*
|
|
145
|
+
* The step says "SAMPLED pairwise judgments", because the swap doubles judge
|
|
146
|
+
* calls and doubling every one of them to measure the judge is a cost the
|
|
147
|
+
* measurement does not need. Deterministic so a published consistency figure is
|
|
148
|
+
* reproducible from the report's own seed — a sample nobody can re-draw is a
|
|
149
|
+
* number nobody can check.
|
|
150
|
+
*
|
|
151
|
+
* `rate <= 0` samples nothing; `rate >= 1` samples everything.
|
|
152
|
+
*/
|
|
153
|
+
export function sampleForSwap(ids: readonly string[], rate: number, seed: string): string[] {
|
|
154
|
+
if (!(rate > 0)) {
|
|
155
|
+
return [];
|
|
156
|
+
}
|
|
157
|
+
if (rate >= 1) {
|
|
158
|
+
return [...ids];
|
|
159
|
+
}
|
|
160
|
+
return ids.filter((id) => _unitHash(`${seed} ${id}`) < rate);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Stable [0,1) hash of a string.
|
|
165
|
+
*
|
|
166
|
+
* Reuses `blind_review._sha256_hex` rather than carrying a local one. That
|
|
167
|
+
* export exists for exactly this reason — `blind_review.ts:38-44` records that
|
|
168
|
+
* two hashes of one input are two answers to one question and the second is the
|
|
169
|
+
* one nobody updates. A hand-rolled FNV-1a was tried here first and its low bits
|
|
170
|
+
* were skewed enough that a rate of 0.25 sampled half the corpus; the test that
|
|
171
|
+
* caught it is kept.
|
|
172
|
+
*/
|
|
173
|
+
function _unitHash(s: string): number {
|
|
174
|
+
return parseInt(_sha256_hex(s).slice(0, 8), 16) / 4294967296;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* One report line per judge, for emission BESIDE a verdict.
|
|
179
|
+
*
|
|
180
|
+
* `n/a` rather than a number when nothing was sampled: the step's verify is
|
|
181
|
+
* that the metric is reported, and a report that silently prints nothing for an
|
|
182
|
+
* unrun swap satisfies it only by looking like it ran.
|
|
183
|
+
*/
|
|
184
|
+
export function renderPositionConsistency(rows: readonly JudgeConsistency[]): string {
|
|
185
|
+
if (rows.length === 0) {
|
|
186
|
+
return 'position consistency: no judge sampled — order-swap NOT RUN.';
|
|
187
|
+
}
|
|
188
|
+
const pct = (v: number | null): string => (v === null ? 'n/a' : `${(v * 100).toFixed(0)}%`);
|
|
189
|
+
return rows
|
|
190
|
+
.map(
|
|
191
|
+
(r) =>
|
|
192
|
+
`position consistency · ${r.judge}: ${pct(r.position_consistency)} ` +
|
|
193
|
+
`(${String(r.consistent)}/${String(r.sampled)} pairs survived the swap; ` +
|
|
194
|
+
`first-position rate ${pct(r.first_position_rate)} over ${String(r.decisive_verdicts)} decisive verdicts)`,
|
|
195
|
+
)
|
|
196
|
+
.join('\n');
|
|
197
|
+
}
|
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Corpus assembler for the provider-recognition leakage bench.
|
|
3
|
+
*
|
|
4
|
+
* `road-to-inbox-harvest-2026-08-e-council-topology-evidence`,
|
|
5
|
+
* `blocker: leakage-bench-needs-assembler-and-design-forks`, todo item 1:
|
|
6
|
+
* `collectGuesses` and `scoreRecognition` in `provider_leakage_bench.ts` both
|
|
7
|
+
* take `items: readonly LeakageItem[]` as an INJECTED parameter, and nothing in
|
|
8
|
+
* this tree ever produced those items from real council output. That gap — not
|
|
9
|
+
* quota, and not the un-committability of the corpus — is what kept the bench
|
|
10
|
+
* at NOT RUN. This module closes it and nothing else.
|
|
11
|
+
*
|
|
12
|
+
* It reads a directory of council response records — the JSON shape
|
|
13
|
+
* `{ responses: [{ provider, model, text, error, ... }] }` written per council
|
|
14
|
+
* run — and emits one `LeakageItem` per usable response body, with the response
|
|
15
|
+
* author as ground truth.
|
|
16
|
+
*
|
|
17
|
+
* ── Why the directory is a parameter, not an import ─────────────────────────
|
|
18
|
+
* `session.ts` binds `RESPONSES_DIR` at module load against the running
|
|
19
|
+
* checkout's root (`session.ts:70-73`). Importing it would couple this loader
|
|
20
|
+
* to one root and make it untestable over a fixture tree — and the same
|
|
21
|
+
* root-binding is part of the retention defect this corpus is the subject of.
|
|
22
|
+
* So the directory arrives as `opts.responsesDir` and this module imports
|
|
23
|
+
* nothing from `session.ts`.
|
|
24
|
+
*
|
|
25
|
+
* ── What this module does NOT do ────────────────────────────────────────────
|
|
26
|
+
* It does NOT anonymise. The bodies in `LeakageCorpus.items` are RAW: whatever
|
|
27
|
+
* the provider wrote, including any self-identification in the prose. An
|
|
28
|
+
* anonymisation pass is a DECLARED OPEN DESIGN FORK in the blocker above and is
|
|
29
|
+
* not settled here, so `assembleLeakageCorpus` MUST NOT be fed to a live rater
|
|
30
|
+
* until that fork is settled — a rater shown a raw body may be reading a
|
|
31
|
+
* signature rather than a style, and the recognition rate would then measure
|
|
32
|
+
* the absence of anonymisation rather than its failure.
|
|
33
|
+
*
|
|
34
|
+
* The `anonymise` seam below exists so the settled fork has somewhere to land
|
|
35
|
+
* without changing this module's shape. Its default is `IDENTITY_ANONYMISE`,
|
|
36
|
+
* which returns its input unchanged — deliberately, and tested for it, so that
|
|
37
|
+
* "the default anonymiser" can never be mistaken for anonymisation having
|
|
38
|
+
* happened.
|
|
39
|
+
*
|
|
40
|
+
* It also does NOT decide, score, prompt, or dispatch. No CLI, no `main()`, no
|
|
41
|
+
* transport, no provider calls.
|
|
42
|
+
*
|
|
43
|
+
* ── Why nothing here deletes ────────────────────────────────────────────────
|
|
44
|
+
* This module contains no write, no `unlink` and no `rm`, and must never gain
|
|
45
|
+
* one. The corpus IS the measurement subject: pruning it destroys the
|
|
46
|
+
* instrument, and the over-retention of these bodies is itself a recorded
|
|
47
|
+
* finding rather than a mess to tidy. Retention is therefore REPORTED — both
|
|
48
|
+
* partitions, counted per family in the census — and enforced by nobody here.
|
|
49
|
+
* The caller chooses which partition it is willing to measure over.
|
|
50
|
+
*/
|
|
51
|
+
import * as crypto from 'node:crypto';
|
|
52
|
+
import * as fs from 'node:fs';
|
|
53
|
+
import * as path from 'node:path';
|
|
54
|
+
|
|
55
|
+
import type { LeakageItem } from './provider_leakage_bench.js';
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* The synthetic fixture's basename. Its own body states that "a live runner
|
|
59
|
+
* must refuse this file"; that refusal is implemented here rather than
|
|
60
|
+
* documented, because a recognition rate over hand-written fixture prose
|
|
61
|
+
* describes the fixture author and not a model.
|
|
62
|
+
*/
|
|
63
|
+
export const SYNTHETIC_FIXTURE_BASENAME = 'smoke-items.json';
|
|
64
|
+
|
|
65
|
+
/** Any path segment containing this marker is the synthetic bench fixture dir. */
|
|
66
|
+
export const SYNTHETIC_PATH_MARKER = 'council-provider-leakage';
|
|
67
|
+
|
|
68
|
+
/** Mirrors the declared council retention window. Reported, never applied. */
|
|
69
|
+
export const DEFAULT_RETENTION_DAYS = 7;
|
|
70
|
+
|
|
71
|
+
const MS_PER_DAY = 86_400_000;
|
|
72
|
+
|
|
73
|
+
/** Thrown when the assembler is pointed at data that cannot measure leakage. */
|
|
74
|
+
export class SyntheticCorpusRefusal extends Error {
|
|
75
|
+
readonly source: string;
|
|
76
|
+
constructor(source: string, why: string) {
|
|
77
|
+
super(`refusing synthetic corpus data: ${source} — ${why}`);
|
|
78
|
+
this.name = 'SyntheticCorpusRefusal';
|
|
79
|
+
this.source = source;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** Machine-readable exclusion buckets. A dropped body always names one. */
|
|
84
|
+
export type ExclusionReason =
|
|
85
|
+
/** Not a `.json` file (the tree also holds `.md` notes and stray dirs). */
|
|
86
|
+
| 'not-json-file'
|
|
87
|
+
/** File exists but is not parseable JSON. */
|
|
88
|
+
| 'unparseable-json'
|
|
89
|
+
/** Parsed, but carries no top-level `responses` array. */
|
|
90
|
+
| 'no-responses-array'
|
|
91
|
+
/** A `responses` entry that is not an object. */
|
|
92
|
+
| 'not-an-object'
|
|
93
|
+
/** Entry has a non-falsy `error` — a failed call has no body to rate. */
|
|
94
|
+
| 'response-carried-error'
|
|
95
|
+
/** Entry has no non-empty `provider`, so there is no ground truth. */
|
|
96
|
+
| 'missing-provider'
|
|
97
|
+
/** Entry has no non-empty `text`, so there is nothing to show a rater. */
|
|
98
|
+
| 'empty-text';
|
|
99
|
+
|
|
100
|
+
/** One thing that did not become an item, and why. Never a silent drop. */
|
|
101
|
+
export interface ExcludedRecord {
|
|
102
|
+
/** Source path relative to `responsesDir`, POSIX-separated. */
|
|
103
|
+
readonly source: string;
|
|
104
|
+
/** Index within `responses`, or `null` for a whole-file exclusion. */
|
|
105
|
+
readonly index: number | null;
|
|
106
|
+
readonly reason: ExclusionReason;
|
|
107
|
+
/** One clause of detail, safe to print beside the reason. */
|
|
108
|
+
readonly detail: string;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* A corpus item: a `LeakageItem` plus the provenance the SCORER may see and the
|
|
113
|
+
* rater may not.
|
|
114
|
+
*/
|
|
115
|
+
export interface CorpusItem extends LeakageItem {
|
|
116
|
+
/** Source path relative to `responsesDir`, POSIX-separated. */
|
|
117
|
+
readonly source_file: string;
|
|
118
|
+
readonly response_index: number;
|
|
119
|
+
/** Source file mtime in epoch ms — the only retention input. */
|
|
120
|
+
readonly mtime_ms: number;
|
|
121
|
+
/** Whether `mtime_ms` falls inside `retention_days` of `now`. Reported only. */
|
|
122
|
+
readonly within_retention: boolean;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/** Per-family counts. Keys are whatever providers were actually present. */
|
|
126
|
+
export type FamilyCounts = Readonly<Record<string, number>>;
|
|
127
|
+
|
|
128
|
+
export interface CorpusCensus {
|
|
129
|
+
readonly files_scanned: number;
|
|
130
|
+
readonly files_excluded: number;
|
|
131
|
+
readonly responses_seen: number;
|
|
132
|
+
readonly items_kept: number;
|
|
133
|
+
readonly items_excluded: number;
|
|
134
|
+
/** Echoed so a published census is self-describing. */
|
|
135
|
+
readonly retention_days: number;
|
|
136
|
+
readonly now_ms: number;
|
|
137
|
+
/** Kept items whose source mtime is inside the TTL, counted per family. */
|
|
138
|
+
readonly within_retention: FamilyCounts;
|
|
139
|
+
/** Kept items whose source mtime is older than the TTL, per family. */
|
|
140
|
+
readonly over_retention: FamilyCounts;
|
|
141
|
+
readonly within_retention_total: number;
|
|
142
|
+
readonly over_retention_total: number;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export interface LeakageCorpus {
|
|
146
|
+
readonly items: readonly CorpusItem[];
|
|
147
|
+
/** Sorted distinct families actually present. Never a hardcoded list. */
|
|
148
|
+
readonly families: readonly string[];
|
|
149
|
+
readonly excluded: readonly ExcludedRecord[];
|
|
150
|
+
readonly census: CorpusCensus;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export interface AssembleOptions {
|
|
154
|
+
/** Directory of council response records. Walked recursively. */
|
|
155
|
+
readonly responsesDir: string;
|
|
156
|
+
/** Epoch ms treated as "now" for the retention partition. */
|
|
157
|
+
readonly now?: number;
|
|
158
|
+
readonly retentionDays?: number;
|
|
159
|
+
/**
|
|
160
|
+
* The anonymisation seam. Defaults to `IDENTITY_ANONYMISE`, i.e. NO
|
|
161
|
+
* anonymisation — see the header. Supplying one does not make this module
|
|
162
|
+
* an anonymiser; it makes the fork's decision injectable.
|
|
163
|
+
*/
|
|
164
|
+
readonly anonymise?: (text: string) => string;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/** The default `anonymise`: returns its argument unchanged. Not anonymisation. */
|
|
168
|
+
export const IDENTITY_ANONYMISE = (text: string): string => text;
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Assemble a leakage corpus from a directory of council response records.
|
|
172
|
+
*
|
|
173
|
+
* Throws `SyntheticCorpusRefusal` — never excludes-and-continues — when the
|
|
174
|
+
* directory or any file in it is synthetic bench data. The blocker's wording is
|
|
175
|
+
* that a live runner must REFUSE it, and an exclusion is not a refusal: it
|
|
176
|
+
* would let a run proceed over a silently smaller corpus.
|
|
177
|
+
*/
|
|
178
|
+
export function assembleLeakageCorpus(opts: AssembleOptions): LeakageCorpus {
|
|
179
|
+
const now = opts.now ?? Date.now();
|
|
180
|
+
const retentionDays = opts.retentionDays ?? DEFAULT_RETENTION_DAYS;
|
|
181
|
+
const anonymise = opts.anonymise ?? IDENTITY_ANONYMISE;
|
|
182
|
+
const root = opts.responsesDir;
|
|
183
|
+
|
|
184
|
+
if (_posix(path.resolve(root)).includes(SYNTHETIC_PATH_MARKER)) {
|
|
185
|
+
throw new SyntheticCorpusRefusal(
|
|
186
|
+
root,
|
|
187
|
+
`the directory path contains "${SYNTHETIC_PATH_MARKER}", the synthetic bench fixture location`,
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const excluded: ExcludedRecord[] = [];
|
|
192
|
+
const items: CorpusItem[] = [];
|
|
193
|
+
let filesScanned = 0;
|
|
194
|
+
let filesExcluded = 0;
|
|
195
|
+
let responsesSeen = 0;
|
|
196
|
+
|
|
197
|
+
// Sorted relative paths: two runs over the same tree emit byte-identical
|
|
198
|
+
// output, which a bench whose result gets published has to be able to claim.
|
|
199
|
+
for (const rel of _walkSorted(root)) {
|
|
200
|
+
const abs = path.join(root, rel);
|
|
201
|
+
const base = path.basename(rel);
|
|
202
|
+
|
|
203
|
+
if (base === SYNTHETIC_FIXTURE_BASENAME) {
|
|
204
|
+
throw new SyntheticCorpusRefusal(
|
|
205
|
+
rel,
|
|
206
|
+
`basename is the synthetic fixture "${SYNTHETIC_FIXTURE_BASENAME}", whose own body states a live runner must refuse it`,
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
if (!base.endsWith('.json')) {
|
|
210
|
+
excluded.push({ source: rel, index: null, reason: 'not-json-file', detail: 'no .json extension' });
|
|
211
|
+
filesExcluded += 1;
|
|
212
|
+
continue;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
filesScanned += 1;
|
|
216
|
+
let parsed: unknown;
|
|
217
|
+
try {
|
|
218
|
+
parsed = JSON.parse(fs.readFileSync(abs, 'utf8'));
|
|
219
|
+
} catch (err) {
|
|
220
|
+
excluded.push({
|
|
221
|
+
source: rel,
|
|
222
|
+
index: null,
|
|
223
|
+
reason: 'unparseable-json',
|
|
224
|
+
detail: err instanceof Error ? err.message : String(err),
|
|
225
|
+
});
|
|
226
|
+
filesExcluded += 1;
|
|
227
|
+
continue;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// A truthy top-level `synthetic` key is the fixture's self-declaration.
|
|
231
|
+
// Checked after the basename guard so a renamed fixture is still caught.
|
|
232
|
+
if (_isRecord(parsed) && Boolean(parsed['synthetic'])) {
|
|
233
|
+
throw new SyntheticCorpusRefusal(rel, 'the record carries a truthy top-level "synthetic" key');
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
const responses = _isRecord(parsed) ? parsed['responses'] : undefined;
|
|
237
|
+
if (!Array.isArray(responses)) {
|
|
238
|
+
excluded.push({
|
|
239
|
+
source: rel,
|
|
240
|
+
index: null,
|
|
241
|
+
reason: 'no-responses-array',
|
|
242
|
+
detail: 'no top-level `responses` array',
|
|
243
|
+
});
|
|
244
|
+
filesExcluded += 1;
|
|
245
|
+
continue;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
const mtimeMs = fs.statSync(abs).mtimeMs;
|
|
249
|
+
const withinRetention = now - mtimeMs <= retentionDays * MS_PER_DAY;
|
|
250
|
+
|
|
251
|
+
for (let i = 0; i < responses.length; i += 1) {
|
|
252
|
+
responsesSeen += 1;
|
|
253
|
+
const entry: unknown = responses[i];
|
|
254
|
+
if (!_isRecord(entry)) {
|
|
255
|
+
excluded.push({ source: rel, index: i, reason: 'not-an-object', detail: `entry is ${typeof entry}` });
|
|
256
|
+
continue;
|
|
257
|
+
}
|
|
258
|
+
const error = entry['error'];
|
|
259
|
+
if (Boolean(error)) {
|
|
260
|
+
excluded.push({
|
|
261
|
+
source: rel,
|
|
262
|
+
index: i,
|
|
263
|
+
reason: 'response-carried-error',
|
|
264
|
+
detail: typeof error === 'string' ? error.slice(0, 120) : 'non-falsy error field',
|
|
265
|
+
});
|
|
266
|
+
continue;
|
|
267
|
+
}
|
|
268
|
+
const provider = _nonEmptyString(entry['provider']);
|
|
269
|
+
if (provider === null) {
|
|
270
|
+
excluded.push({ source: rel, index: i, reason: 'missing-provider', detail: 'no non-empty provider' });
|
|
271
|
+
continue;
|
|
272
|
+
}
|
|
273
|
+
const text = _nonEmptyString(entry['text']);
|
|
274
|
+
if (text === null) {
|
|
275
|
+
excluded.push({ source: rel, index: i, reason: 'empty-text', detail: 'no non-empty text' });
|
|
276
|
+
continue;
|
|
277
|
+
}
|
|
278
|
+
items.push({
|
|
279
|
+
id: leakageItemId(rel, i),
|
|
280
|
+
text: anonymise(text),
|
|
281
|
+
true_family: provider,
|
|
282
|
+
source_file: rel,
|
|
283
|
+
response_index: i,
|
|
284
|
+
mtime_ms: mtimeMs,
|
|
285
|
+
within_retention: withinRetention,
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
const within: Record<string, number> = {};
|
|
291
|
+
const over: Record<string, number> = {};
|
|
292
|
+
for (const item of items) {
|
|
293
|
+
const bucket = item.within_retention ? within : over;
|
|
294
|
+
bucket[item.true_family] = (bucket[item.true_family] ?? 0) + 1;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
return {
|
|
298
|
+
items,
|
|
299
|
+
families: [...new Set(items.map((i) => i.true_family))].sort(),
|
|
300
|
+
excluded,
|
|
301
|
+
census: {
|
|
302
|
+
files_scanned: filesScanned,
|
|
303
|
+
files_excluded: filesExcluded,
|
|
304
|
+
responses_seen: responsesSeen,
|
|
305
|
+
items_kept: items.length,
|
|
306
|
+
items_excluded: excluded.filter((e) => e.index !== null).length,
|
|
307
|
+
retention_days: retentionDays,
|
|
308
|
+
now_ms: now,
|
|
309
|
+
within_retention: within,
|
|
310
|
+
over_retention: over,
|
|
311
|
+
within_retention_total: _sum(within),
|
|
312
|
+
over_retention_total: _sum(over),
|
|
313
|
+
},
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Stable, collision-free, OPAQUE item id.
|
|
319
|
+
*
|
|
320
|
+
* The id is a digest of the source path plus the response index — NOT the
|
|
321
|
+
* basename — and that is load-bearing rather than stylistic: real filenames
|
|
322
|
+
* under `agents/runtime/council/responses/` include
|
|
323
|
+
* `anthropic-design-skills-integration.json` and several `claude-*.json`, so a
|
|
324
|
+
* basename-derived id would hand the rater the ground truth in the item's own
|
|
325
|
+
* identifier and the bench would measure reading, not recognition. The id must
|
|
326
|
+
* never embed the provider name, or any part of a path that might.
|
|
327
|
+
*
|
|
328
|
+
* Deterministic (a digest, not a counter) so two runs over the same tree
|
|
329
|
+
* produce the same ids, and index-suffixed so two bodies in one file cannot
|
|
330
|
+
* collide.
|
|
331
|
+
*/
|
|
332
|
+
export function leakageItemId(relPath: string, index: number): string {
|
|
333
|
+
const digest = crypto.createHash('sha1').update(_posix(relPath)).digest('hex').slice(0, 12);
|
|
334
|
+
return `item-${digest}-${String(index)}`;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/** Recursive file walk, returning `root`-relative POSIX paths in sorted order. */
|
|
338
|
+
function _walkSorted(root: string): string[] {
|
|
339
|
+
const out: string[] = [];
|
|
340
|
+
const visit = (dirRel: string): void => {
|
|
341
|
+
let entries: fs.Dirent[];
|
|
342
|
+
try {
|
|
343
|
+
entries = fs.readdirSync(path.join(root, dirRel), { withFileTypes: true });
|
|
344
|
+
} catch {
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
const names = entries.map((e) => e.name).sort();
|
|
348
|
+
for (const name of names) {
|
|
349
|
+
const rel = dirRel === '' ? name : `${dirRel}/${name}`;
|
|
350
|
+
const abs = path.join(root, rel);
|
|
351
|
+
let stat: fs.Stats;
|
|
352
|
+
try {
|
|
353
|
+
stat = fs.statSync(abs);
|
|
354
|
+
} catch {
|
|
355
|
+
continue;
|
|
356
|
+
}
|
|
357
|
+
if (stat.isDirectory()) {
|
|
358
|
+
// Real records nest: `<slug>.json/` directories hold per-round
|
|
359
|
+
// files. Recursing keeps those bodies eligible; the relative
|
|
360
|
+
// path keeps their ids distinct.
|
|
361
|
+
visit(rel);
|
|
362
|
+
} else if (stat.isFile()) {
|
|
363
|
+
out.push(rel);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
};
|
|
367
|
+
visit('');
|
|
368
|
+
return out.sort();
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
function _posix(p: string): string {
|
|
372
|
+
return p.split(path.sep).join('/');
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
function _isRecord(v: unknown): v is Record<string, unknown> {
|
|
376
|
+
return typeof v === 'object' && v !== null && !Array.isArray(v);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
function _nonEmptyString(v: unknown): string | null {
|
|
380
|
+
return typeof v === 'string' && v.trim() !== '' ? v : null;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
function _sum(counts: Readonly<Record<string, number>>): number {
|
|
384
|
+
return Object.values(counts).reduce((a, b) => a + b, 0);
|
|
385
|
+
}
|