@event4u/agent-config 9.9.0 → 9.10.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/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +153 -194
- package/README.md +1 -1
- package/dist/agent-src/commands/agent-status.md +12 -11
- package/dist/agent-src/commands/agents/user/accept.md +115 -30
- package/dist/agent-src/commands/agents/user/delete.md +147 -0
- package/dist/agent-src/commands/agents/user/review.md +65 -28
- package/dist/agent-src/commands/agents/user/show.md +82 -29
- package/dist/agent-src/commands/agents/user/update.md +2 -2
- package/dist/agent-src/commands/agents/user.md +16 -3
- package/dist/agent-src/commands/check-current-md.md +0 -10
- package/dist/agent-src/commands/condense.md +28 -97
- package/dist/agent-src/commands/cost/report.md +7 -0
- package/dist/agent-src/commands/fix/portability.md +0 -8
- package/dist/agent-src/commands/fix/refs.md +0 -8
- package/dist/agent-src/commands/humanize.md +2 -2
- package/dist/agent-src/commands/jira-ticket.md +1 -1
- package/dist/agent-src/commands/memory/load.md +11 -0
- package/dist/agent-src/commands/optimize/skills.md +1 -1
- package/dist/agent-src/commands/pr/create.md +4 -4
- package/dist/agent-src/commands/profile/show.md +3 -3
- package/dist/agent-src/commands/rule-compliance-audit.md +5 -4
- package/dist/agent-src/commands/security-audit-config.md +1 -1
- package/dist/agent-src/commands/sync/gitignore/fix.md +1 -1
- package/dist/agent-src/commands/tdd.md +21 -0
- package/dist/agent-src/commands/team/delegate.md +2 -2
- package/dist/agent-src/commands/team-knowledge/bootstrap.md +9 -8
- package/dist/agent-src/commands/team-knowledge/consolidate.md +8 -7
- package/dist/agent-src/commands/team.md +4 -1
- package/dist/agent-src/commands/upstream-contribute.md +0 -1
- package/dist/agent-src/contexts/authority/commit-mechanics.md +7 -0
- package/dist/agent-src/contexts/authority/destructive-mechanics.md +16 -0
- package/dist/agent-src/contexts/authority/scope-mechanics.md +61 -0
- package/dist/agent-src/contexts/communication/rules-auto/reply-close-mechanics.md +20 -18
- package/dist/agent-src/contexts/communication/rules-auto/skill-quality-mechanics.md +1 -1
- package/dist/agent-src/contexts/communication/rules-auto/slash-command-routing-policy-mechanics.md +1 -1
- package/dist/agent-src/contexts/communication/rules-auto/source-of-truth-mechanics.md +9 -10
- package/dist/agent-src/contexts/communication/rules-auto/think-before-action-mechanics.md +1 -1
- package/dist/agent-src/contexts/communication/rules-auto/user-interaction-mechanics.md +11 -0
- package/dist/agent-src/contexts/contracts/artifact-engagement-flow.md +26 -15
- package/dist/agent-src/contexts/contracts/command-suggestion-flow.md +3 -0
- package/dist/agent-src/contexts/execution/auto-dispatch-classification.md +67 -37
- package/dist/agent-src/contexts/execution/auto-orchestration-activation.md +1 -1
- package/dist/agent-src/contexts/execution/autonomy-examples.md +1 -1
- package/dist/agent-src/contexts/execution/autonomy-mechanics.md +7 -6
- package/dist/agent-src/contexts/execution/evidence-discipline.md +92 -77
- package/dist/agent-src/contexts/execution/orchestration-benchmark-gate.md +22 -21
- package/dist/agent-src/contexts/execution/orchestration-telemetry.md +24 -0
- package/dist/agent-src/contexts/execution/project-intelligence.md +122 -103
- package/dist/agent-src/contexts/execution/roadmap-execution-contract.md +23 -21
- package/dist/agent-src/contexts/execution/subagent-response-contract.md +5 -5
- package/dist/agent-src/contexts/execution/subagent-routing.md +11 -0
- package/dist/agent-src/contexts/execution/subagent-spawn-contract.md +13 -13
- package/dist/agent-src/contexts/execution/subagent-steering.md +36 -34
- package/dist/agent-src/contexts/execution/toolchain-resolver.md +1 -1
- package/dist/agent-src/contexts/execution/user-memory-channels.md +189 -0
- package/dist/agent-src/contexts/execution/verification-mechanics.md +9 -0
- package/dist/agent-src/contexts/model-recommendations.md +3 -2
- package/dist/agent-src/contexts/subagent-configuration.md +3 -3
- package/dist/agent-src/ghostwriter/README.md +2 -2
- package/dist/agent-src/packs/README.md +1 -1
- package/dist/agent-src/personas/README.md +5 -5
- package/dist/agent-src/personas/_template-specialist/persona.md +3 -3
- package/dist/agent-src/personas/backend-architect.md +24 -23
- package/dist/agent-src/personas/eloquent-tamer.md +30 -30
- package/dist/agent-src/personas/frontend-engineer.md +30 -30
- package/dist/agent-src/personas/product-owner.md +41 -38
- package/dist/agent-src/personas/qa.md +13 -13
- package/dist/agent-src/personas/security-engineer.md +22 -22
- package/dist/agent-src/presets/README.md +3 -3
- package/dist/agent-src/profiles/README.md +3 -3
- package/dist/agent-src/rules/active-remediation.md +2 -2
- package/dist/agent-src/rules/artifact-engagement-recording.md +4 -4
- package/dist/agent-src/rules/ask-when-uncertain.md +0 -4
- package/dist/agent-src/rules/augment-edit-discipline.md +1 -1
- package/dist/agent-src/rules/broken-access-control.md +4 -4
- package/dist/agent-src/rules/code-comment-discipline.md +1 -1
- package/dist/agent-src/rules/code-provenance.md +2 -2
- package/dist/agent-src/rules/commit-policy.md +4 -9
- package/dist/agent-src/rules/communication-through-line.md +5 -5
- package/dist/agent-src/rules/decision-revisit-gate.md +1 -1
- package/dist/agent-src/rules/doc-screenshot-hygiene.md +1 -1
- package/dist/agent-src/rules/domain-adoption-policy.md +1 -1
- package/dist/agent-src/rules/domain-safety-pii.md +1 -1
- package/dist/agent-src/rules/external-code-graph-interop.md +1 -1
- package/dist/agent-src/rules/fast-path-marker-visibility.md +43 -7
- package/dist/agent-src/rules/finance-safety-floor.md +1 -1
- package/dist/agent-src/rules/framework-neutrality-in-generic-skills.md +3 -3
- package/dist/agent-src/rules/history-discipline.md +1 -1
- package/dist/agent-src/rules/legal-safety-floor.md +1 -1
- package/dist/agent-src/rules/lethal-trifecta-guard.md +5 -5
- package/dist/agent-src/rules/low-impact-corpus-privacy-floor.md +10 -8
- package/dist/agent-src/rules/media-governance-routing.md +13 -13
- package/dist/agent-src/rules/media-sync-ground-truth.md +29 -11
- package/dist/agent-src/rules/no-cheap-questions.md +7 -7
- package/dist/agent-src/rules/no-decorative-emojis-in-git-surfaces.md +29 -18
- package/dist/agent-src/rules/non-destructive-by-default.md +5 -23
- package/dist/agent-src/rules/onboarding-gate.md +14 -4
- package/dist/agent-src/rules/persona-governance.md +2 -2
- package/dist/agent-src/rules/prefer-enums-over-literals.md +9 -9
- package/dist/agent-src/rules/preservation-guard.md +10 -2
- package/dist/agent-src/rules/question-not-instruction.md +1 -1
- package/dist/agent-src/rules/roadmap-progress-sync.md +6 -6
- package/dist/agent-src/rules/rule-type-governance.md +1 -1
- package/dist/agent-src/rules/scale-discipline.md +1 -1
- package/dist/agent-src/rules/scope-control.md +1 -1
- package/dist/agent-src/rules/secret-vcs-guard.md +1 -1
- package/dist/agent-src/rules/security-sensitive-stop.md +17 -11
- package/dist/agent-src/rules/senior-engineering-discipline.md +17 -17
- package/dist/agent-src/rules/session-canary.md +1 -1
- package/dist/agent-src/rules/skill-quality.md +1 -1
- package/dist/agent-src/rules/source-confidentiality.md +21 -19
- package/dist/agent-src/rules/source-of-truth.md +6 -5
- package/dist/agent-src/rules/spreadsheet-source-quality.md +2 -2
- package/dist/agent-src/rules/strategy-safety-floor.md +1 -1
- package/dist/agent-src/rules/think-before-action.md +5 -5
- package/dist/agent-src/rules/token-budget-discipline.md +5 -3
- package/dist/agent-src/rules/token-efficiency.md +2 -2
- package/dist/agent-src/rules/untrusted-input-defense.md +4 -4
- package/dist/agent-src/rules/user-interaction.md +12 -0
- package/dist/agent-src/rules/verify-before-complete.md +4 -24
- package/dist/agent-src/skills/adversarial-review/SKILL.md +2 -2
- package/dist/agent-src/skills/agent-security-review/SKILL.md +52 -45
- package/dist/agent-src/skills/agents-md-thin-root/SKILL.md +2 -2
- package/dist/agent-src/skills/ai-code-blindspots/SKILL.md +20 -20
- package/dist/agent-src/skills/ai-council/SKILL.md +185 -128
- package/dist/agent-src/skills/analysis-skill-router/SKILL.md +3 -3
- package/dist/agent-src/skills/api-endpoint/SKILL.md +2 -2
- package/dist/agent-src/skills/artisan-commands/SKILL.md +2 -2
- package/dist/agent-src/skills/async-python-patterns/SKILL.md +8 -7
- package/dist/agent-src/skills/authz-review/SKILL.md +16 -15
- package/dist/agent-src/skills/aws-infrastructure/SKILL.md +5 -5
- package/dist/agent-src/skills/blade-ui/SKILL.md +1 -1
- package/dist/agent-src/skills/bug-analyzer/SKILL.md +30 -12
- package/dist/agent-src/skills/code-intelligence/SKILL.md +0 -1
- package/dist/agent-src/skills/code-intelligence/evals/triggers.json +52 -0
- package/dist/agent-src/skills/code-review/SKILL.md +6 -6
- package/dist/agent-src/skills/command-routing/SKILL.md +5 -4
- package/dist/agent-src/skills/composer-packages/SKILL.md +2 -2
- package/dist/agent-src/skills/condense-memory/SKILL.md +43 -41
- package/dist/agent-src/skills/context-document/SKILL.md +23 -21
- package/dist/agent-src/skills/copilot-config/SKILL.md +6 -1
- package/dist/agent-src/skills/decision-record/SKILL.md +20 -18
- package/dist/agent-src/skills/design-intelligence/SKILL.md +4 -4
- package/dist/agent-src/skills/design-review/SKILL.md +15 -14
- package/dist/agent-src/skills/design-system-capture/reference/design-system-json.md +28 -25
- package/dist/agent-src/skills/devcontainer/SKILL.md +2 -2
- package/dist/agent-src/skills/docker/SKILL.md +1 -1
- package/dist/agent-src/skills/docx-authoring/evals/triggers.json +52 -0
- package/dist/agent-src/skills/emit-tickets/SKILL.md +2 -2
- package/dist/agent-src/skills/error-handling-patterns/SKILL.md +1 -1
- package/dist/agent-src/skills/estimate-ticket/SKILL.md +2 -2
- package/dist/agent-src/skills/evaluate-llm-feature/SKILL.md +0 -1
- package/dist/agent-src/skills/evaluate-llm-feature/evals/triggers.json +52 -0
- package/dist/agent-src/skills/existing-ui-audit/SKILL.md +6 -5
- package/dist/agent-src/skills/feature-planning/SKILL.md +2 -2
- package/dist/agent-src/skills/finishing-a-development-branch/SKILL.md +3 -3
- package/dist/agent-src/skills/flux/SKILL.md +1 -1
- package/dist/agent-src/skills/frontend-render-security/SKILL.md +13 -13
- package/dist/agent-src/skills/git-workflow/SKILL.md +33 -33
- package/dist/agent-src/skills/grafana/SKILL.md +5 -0
- package/dist/agent-src/skills/humanizer/SKILL.md +83 -66
- package/dist/agent-src/skills/humanizer/data/patterns.md +14 -14
- package/dist/agent-src/skills/humanizer/references/anti-aiisms.md +4 -4
- package/dist/agent-src/skills/judge-artifact-completeness/SKILL.md +82 -37
- package/dist/agent-src/skills/judge-bug-hunter/SKILL.md +17 -5
- package/dist/agent-src/skills/judge-injection-defense/SKILL.md +63 -25
- package/dist/agent-src/skills/judge-security-auditor/SKILL.md +2 -0
- package/dist/agent-src/skills/judge-synthesis/SKILL.md +72 -28
- package/dist/agent-src/skills/laravel-horizon/SKILL.md +5 -0
- package/dist/agent-src/skills/laravel-mail/SKILL.md +5 -4
- package/dist/agent-src/skills/laravel-middleware/SKILL.md +5 -4
- package/dist/agent-src/skills/laravel-notifications/SKILL.md +10 -9
- package/dist/agent-src/skills/laravel-pennant/SKILL.md +1 -1
- package/dist/agent-src/skills/laravel-pulse/SKILL.md +9 -8
- package/dist/agent-src/skills/laravel-reverb/SKILL.md +6 -5
- package/dist/agent-src/skills/laravel-scheduling/SKILL.md +6 -1
- package/dist/agent-src/skills/laravel-validation/SKILL.md +12 -0
- package/dist/agent-src/skills/launch-readiness/SKILL.md +1 -1
- package/dist/agent-src/skills/learning-to-rule-or-skill/SKILL.md +7 -7
- package/dist/agent-src/skills/learning-tutor/SKILL.md +44 -43
- package/dist/agent-src/skills/learning-tutor/evals/triggers.json +52 -0
- package/dist/agent-src/skills/license-compliance-audit/SKILL.md +7 -7
- package/dist/agent-src/skills/license-compliance-borrow-check/SKILL.md +3 -3
- package/dist/agent-src/skills/license-compliance-credits/SKILL.md +4 -4
- package/dist/agent-src/skills/llm-provider-knowledge/SKILL.md +0 -1
- package/dist/agent-src/skills/memory-consolidation/SKILL.md +69 -64
- package/dist/agent-src/skills/motion-choreographer/SKILL.md +6 -6
- package/dist/agent-src/skills/pdf-tools/evals/triggers.json +52 -0
- package/dist/agent-src/skills/performance-analysis/SKILL.md +7 -3
- package/dist/agent-src/skills/persona-improvement/SKILL.md +0 -2
- package/dist/agent-src/skills/persona-improvement/evals/triggers.json +52 -0
- package/dist/agent-src/skills/php-coder/SKILL.md +10 -0
- package/dist/agent-src/skills/prediction-pool-optimizer/SKILL.md +129 -120
- package/dist/agent-src/skills/prediction-pool-optimizer/reference/ev-fixtures.md +36 -35
- package/dist/agent-src/skills/prediction-pool-optimizer/reference/odds-and-bonus.md +45 -41
- package/dist/agent-src/skills/project-analysis-core/SKILL.md +4 -4
- package/dist/agent-src/skills/project-analysis-hypothesis-driven/SKILL.md +3 -3
- package/dist/agent-src/skills/project-analysis-react/SKILL.md +1 -1
- package/dist/agent-src/skills/project-analysis-symfony/SKILL.md +1 -1
- package/dist/agent-src/skills/project-analysis-zend-laminas/SKILL.md +2 -2
- package/dist/agent-src/skills/prompt-engineering-patterns/SKILL.md +1 -1
- package/dist/agent-src/skills/prompt-validator/SKILL.md +39 -39
- package/dist/agent-src/skills/quality-tools/SKILL.md +15 -15
- package/dist/agent-src/skills/react-shadcn-ui/SKILL.md +55 -19
- package/dist/agent-src/skills/react-shadcn-ui/reference/registry.md +29 -27
- package/dist/agent-src/skills/readme-writing-package/SKILL.md +2 -2
- package/dist/agent-src/skills/reasoning-orchestrator/SKILL.md +25 -25
- package/dist/agent-src/skills/recursive-verification/SKILL.md +6 -5
- package/dist/agent-src/skills/refine-prompt/SKILL.md +1 -1
- package/dist/agent-src/skills/refine-ticket/SKILL.md +20 -2
- package/dist/agent-src/skills/repomix-packer/SKILL.md +1 -1
- package/dist/agent-src/skills/requesting-code-review/SKILL.md +2 -2
- package/dist/agent-src/skills/roadmap-management/SKILL.md +80 -66
- package/dist/agent-src/skills/roadmap-writing/SKILL.md +84 -77
- package/dist/agent-src/skills/rule-refactor/SKILL.md +1 -1
- package/dist/agent-src/skills/screenshot-hygiene/evals/triggers.json +52 -0
- package/dist/agent-src/skills/security-audit/SKILL.md +26 -9
- package/dist/agent-src/skills/security-maturity-assessment/SKILL.md +38 -16
- package/dist/agent-src/skills/skill-improvement-pipeline/SKILL.md +14 -11
- package/dist/agent-src/skills/skill-writing/SKILL.md +9 -8
- package/dist/agent-src/skills/song-to-script/SKILL.md +93 -85
- package/dist/agent-src/skills/sql-writing/SKILL.md +2 -2
- package/dist/agent-src/skills/stakeholder-tradeoff/SKILL.md +4 -3
- package/dist/agent-src/skills/standards-from-config/SKILL.md +61 -43
- package/dist/agent-src/skills/subagent-orchestration/SKILL.md +22 -8
- package/dist/agent-src/skills/subagent-orchestration/prompts/README.md +28 -2
- package/dist/agent-src/skills/supply-chain-intake/SKILL.md +13 -13
- package/dist/agent-src/skills/systematic-debugging/SKILL.md +22 -21
- package/dist/agent-src/skills/tailwind-engineer/SKILL.md +1 -1
- package/dist/agent-src/skills/technical-specification/SKILL.md +5 -0
- package/dist/agent-src/skills/terraform/SKILL.md +2 -2
- package/dist/agent-src/skills/terragrunt/SKILL.md +8 -8
- package/dist/agent-src/skills/testing-anti-patterns/process-anti-patterns.md +1 -1
- package/dist/agent-src/skills/threat-modeling/SKILL.md +19 -13
- package/dist/agent-src/skills/universal-project-analysis/SKILL.md +1 -1
- package/dist/agent-src/skills/upstream-contribute/SKILL.md +0 -1
- package/dist/agent-src/skills/using-git-worktrees/SKILL.md +9 -9
- package/dist/agent-src/skills/validate-feature-fit/SKILL.md +3 -1
- package/dist/agent-src/skills/verify-completion-evidence/SKILL.md +4 -6
- package/dist/agent-src/skills/verify-repair-loop/SKILL.md +67 -61
- package/dist/agent-src/skills/video-director/SKILL.md +7 -7
- package/dist/agent-src/skills/worktree-lifecycle/SKILL.md +3 -3
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/agent-src/templates/contexts/knowledge-pages.md +47 -45
- package/dist/agent-src/templates/contexts/lesson-card.md +2 -2
- package/dist/agent-src/templates/contexts/tenant-boundaries.md +2 -2
- package/dist/agent-src/templates/contexts.md +1 -1
- package/dist/agent-src/templates/features.md +1 -1
- package/dist/agent-src/templates/roadmaps.md +125 -116
- package/dist/agent-src/templates/rule.md +2 -1
- package/dist/agent-src/templates/scripts/pr_risk_review.ts +0 -0
- package/dist/agent-src/templates/scripts/telemetry/aggregator.ts +0 -0
- package/dist/agent-src/templates/scripts/tier_usage_report.ts +2 -2
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/polish.ts +2 -2
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/review.ts +1 -1
- package/dist/agent-src/user-types/README.md +8 -8
- package/dist/agent-src/user-types/galabau-field-crew.md +34 -33
- package/dist/agent-src/user-types/metalworking-shop.md +35 -34
- package/dist/agent-src/user-types/truck-driver.md +22 -20
- package/dist/cli/python/workspace_roles.js +2 -2
- package/dist/cli/python/workspace_roles.js.map +1 -1
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +88 -62
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +3 -3
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +6 -5
- package/dist/discovery/trust-report.md +2 -2
- package/dist/discovery/workspaces.json +5 -4
- package/dist/hooks/dispatch.js +186 -12
- package/dist/install/install.mjs +8 -0
- package/dist/mcp/registry-manifest.json +3 -3
- package/dist/mcp/server.json +2 -2
- package/dist/mcp/server.mjs +1199 -857
- package/dist/router.json +1 -1
- package/dist/scripts/_lib/compile_time_toggles.js +48 -0
- package/dist/scripts/_lib/compile_time_toggles.js.map +1 -0
- package/dist/scripts/condense.js +234 -217
- package/dist/scripts/condense.js.map +1 -1
- package/dist/server/schemas/settings.js +4 -0
- package/dist/server/schemas/settings.js.map +1 -1
- package/dist/shared/userMd/utils.js +30 -0
- package/dist/shared/userMd/utils.js.map +1 -1
- package/dist/ui/assets/index-BpSQt5vm.js.map +1 -1
- package/docs/guidelines/agent-infra/api-cost-levers.md +56 -5
- package/docs/guidelines/agent-infra/simplicity-and-goal-demos.md +93 -33
- package/package.json +1 -1
- package/src/agent-src/templates/scripts/pr_risk_review.ts +0 -0
- package/src/agent-src/templates/scripts/telemetry/aggregator.ts +0 -0
- package/src/agent-src/templates/scripts/tier_usage_report.ts +2 -2
- package/src/agent-src/templates/scripts/work_engine/directives/ui/polish.ts +2 -2
- package/src/agent-src/templates/scripts/work_engine/directives/ui/review.ts +1 -1
- package/src/config/agent-settings.template.yml +32 -2
- package/src/config/ci-local-parity.yml +142 -0
- package/src/config/gate-coverage.yml +127 -0
- package/src/config/preamble-payload-budget.json +44 -0
- package/src/scripts/_cli/cmd_doctor.ts +78 -2
- package/src/scripts/_lib/agent_user_profile.ts +381 -0
- package/src/scripts/_lib/agents_overlay.ts +9 -0
- package/src/scripts/_lib/anchor_eval.ts +311 -0
- package/src/scripts/_lib/cc_transcript.ts +316 -0
- package/src/scripts/_lib/compile_time_toggles.ts +79 -0
- package/src/scripts/_lib/confusables.ts +101 -0
- package/src/scripts/_lib/duplicate_scope_census.ts +77 -0
- package/src/scripts/_lib/managed_agents_folder.ts +181 -0
- package/src/scripts/_lib/payload_hash_drift.ts +126 -0
- package/src/scripts/_lib/preservation_migration.ts +291 -0
- package/src/scripts/_lib/retrieval_sanitize.ts +166 -2
- package/src/scripts/_lib/scan_scope.ts +115 -0
- package/src/scripts/_lib/user_global_memory_audit.ts +187 -0
- package/src/scripts/_lib/user_global_observations.ts +830 -0
- package/src/scripts/_lib/user_global_revocations.ts +110 -0
- package/src/scripts/_lib/user_memory_gate_counters.ts +291 -0
- package/src/scripts/ai_council/blind_review.ts +0 -0
- package/src/scripts/ai_council/budget_guard.ts +90 -11
- package/src/scripts/ai_council/bundler.ts +2 -2
- package/src/scripts/ai_council/clients.ts +59 -3
- package/src/scripts/ai_council/config.ts +38 -0
- package/src/scripts/ai_council/orchestrator.ts +54 -9
- package/src/scripts/ai_team/team_dispatch.ts +17 -6
- package/src/scripts/anchor_eval_falsify.ts +198 -0
- package/src/scripts/anchor_scoring_run.ts +239 -0
- package/src/scripts/annotate_discovery.ts +1 -65
- package/src/scripts/bench_quality_run.ts +168 -4
- package/src/scripts/cache_realization_report.ts +782 -0
- package/src/scripts/check_artefact_count_messaging.ts +5 -1
- package/src/scripts/check_augment_description_cap.ts +15 -4
- package/src/scripts/check_ci_local_parity.ts +317 -0
- package/src/scripts/check_condensation.ts +96 -191
- package/src/scripts/check_context_paths.ts +38 -9
- package/src/scripts/check_gate_coverage.ts +299 -0
- package/src/scripts/check_iron_law_prominence.ts +22 -1
- package/src/scripts/check_kernel_prefix_stability.ts +0 -0
- package/src/scripts/check_no_new_legacy_path.ts +16 -6
- package/src/scripts/check_no_roadmap_refs.ts +22 -9
- package/src/scripts/check_originality_freshness.ts +167 -0
- package/src/scripts/check_preamble_payload_budget.ts +130 -0
- package/src/scripts/check_proposal.ts +0 -0
- package/src/scripts/check_references.ts +0 -1
- package/src/scripts/check_safety_floor_untouched.ts +171 -24
- package/src/scripts/check_site_links.ts +62 -3
- package/src/scripts/ci_status.ts +0 -0
- package/src/scripts/cluster_near_miss_patterns.ts +0 -0
- package/src/scripts/code_graph/build.ts +0 -0
- package/src/scripts/command_suggester/types.ts +0 -0
- package/src/scripts/compile_router.ts +10 -14
- package/src/scripts/condense.sh +3 -4
- package/src/scripts/condense.ts +247 -228
- package/src/scripts/cost/track.mjs +168 -33
- package/src/scripts/cost_summary.ts +33 -1
- package/src/scripts/council_cli.ts +45 -3
- package/src/scripts/discovery_graph.ts +0 -0
- package/src/scripts/encoding_corpus.ts +500 -0
- package/src/scripts/encoding_corpus_report.ts +216 -0
- package/src/scripts/generate_index.ts +19 -2
- package/src/scripts/install-hooks.sh +2 -2
- package/src/scripts/learning_sidecar.ts +0 -0
- package/src/scripts/lint_confusables.ts +10 -72
- package/src/scripts/lint_featured_skills.ts +0 -0
- package/src/scripts/lint_hidden_unicode.ts +208 -0
- package/src/scripts/lint_load_context.ts +17 -5
- package/src/scripts/lint_new_skill_gate.ts +9 -3
- package/src/scripts/lint_no_python_twin_rationale.ts +17 -2
- package/src/scripts/lint_originality.ts +1 -1
- package/src/scripts/lint_skill_originality.ts +1 -1
- package/src/scripts/lint_ticket_buildable.ts +1 -1
- package/src/scripts/mcp_server/tools.ts +4 -4
- package/src/scripts/measure_scope_dedup.ts +224 -0
- package/src/scripts/memory_lookup.ts +0 -0
- package/src/scripts/mine_session.ts +98 -0
- package/src/scripts/orchestration_payload_hash_drift.ts +145 -0
- package/src/scripts/preamble_byte_census.ts +574 -0
- package/src/scripts/probe_skill_registration.ts +2 -2
- package/src/scripts/redact_hook_capture.ts +13 -0
- package/src/scripts/release.ts +65 -10
- package/src/scripts/router_telemetry.ts +1 -1
- package/src/scripts/second_brain_retrieval.ts +14 -4
- package/src/scripts/skill_linter.ts +5 -0
- package/src/scripts/surface-tiers.yml +2 -0
- package/src/scripts/validate_pack_yaml.ts +0 -0
- package/src/server/schemas/settings.ts +8 -0
- package/src/shared/userMd/utils.ts +31 -0
- package/dist/agent-src/rules/telegraph-speak.md +0 -87
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
/**
|
|
3
|
+
* Anchor-scoring runner — constrained anchor evaluation with frozen verdicts
|
|
4
|
+
* (ADR-202, amended; attempt 2).
|
|
5
|
+
*
|
|
6
|
+
* Two phases, deliberately separate commands, because the freeze is the thing
|
|
7
|
+
* that makes the run reproducible:
|
|
8
|
+
*
|
|
9
|
+
* --generate DIR answer both arms once, freeze transcripts.json
|
|
10
|
+
* --score DIR evaluate every anchor with both evaluators, freeze
|
|
11
|
+
* verdicts.json, then score — κ, δ, thresholds, verdict
|
|
12
|
+
*
|
|
13
|
+
* Re-scoring a frozen directory is repeatable by construction: the scorer is a
|
|
14
|
+
* pure function over the frozen verdicts. Re-GENERATING is a new experiment with
|
|
15
|
+
* its own directory and its own δ, never a re-run of this one.
|
|
16
|
+
*
|
|
17
|
+
* Exit codes: 0 ok · 1 usage/IO error · 2 verdict FAIL or instrument FAIL.
|
|
18
|
+
*/
|
|
19
|
+
import { createRequire } from 'node:module';
|
|
20
|
+
import * as fs from 'node:fs';
|
|
21
|
+
import * as path from 'node:path';
|
|
22
|
+
import process from 'node:process';
|
|
23
|
+
import { fileURLToPath } from 'node:url';
|
|
24
|
+
|
|
25
|
+
import yaml from 'js-yaml';
|
|
26
|
+
|
|
27
|
+
import { build_thin, RULES_SOURCE } from './project_thin_rules.js';
|
|
28
|
+
import { cohensKappa } from './check_quality_regression.js';
|
|
29
|
+
import {
|
|
30
|
+
delta_from_spread,
|
|
31
|
+
eval_prompt,
|
|
32
|
+
eval_with_retry,
|
|
33
|
+
key,
|
|
34
|
+
resolve,
|
|
35
|
+
verdict,
|
|
36
|
+
type Arm,
|
|
37
|
+
type TaskAnchors,
|
|
38
|
+
} from './_lib/anchor_eval.js';
|
|
39
|
+
|
|
40
|
+
const _HERE = fileURLToPath(import.meta.url);
|
|
41
|
+
const REPO_ROOT = path.resolve(path.dirname(_HERE), '..', '..');
|
|
42
|
+
const CORPUS = path.join(REPO_ROOT, 'internal/bench/corpora/token-quality-golden.yaml');
|
|
43
|
+
const REPORT = path.join(REPO_ROOT, 'internal/bench/reports/quality-run.json');
|
|
44
|
+
|
|
45
|
+
const ANSWER_MODEL = 'claude-sonnet-4-5';
|
|
46
|
+
const EVAL_ANTHROPIC = 'claude-sonnet-4-5';
|
|
47
|
+
const EVAL_OPENAI = process.env['ANCHOR_EVAL_OPENAI_MODEL'] ?? 'gpt-5';
|
|
48
|
+
const ANSWER_SYSTEM =
|
|
49
|
+
'You are an AI coding agent governed by the following always-loaded package rules. '
|
|
50
|
+
+ 'Answer the user request as that agent would, honouring these rules:\n\n';
|
|
51
|
+
const EVAL_SYSTEM = 'You are a strict checklist grader. You output only the requested JSON.';
|
|
52
|
+
|
|
53
|
+
interface RawTask {
|
|
54
|
+
id: string;
|
|
55
|
+
rules: string[];
|
|
56
|
+
prompt: string;
|
|
57
|
+
expected: { must_include?: string[]; must_not?: string[] };
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function load_tasks(limit: number | null): Array<RawTask & TaskAnchors> {
|
|
61
|
+
const doc = yaml.load(fs.readFileSync(CORPUS, 'utf-8')) as { tasks: RawTask[] };
|
|
62
|
+
const all = doc.tasks.map((t) => ({
|
|
63
|
+
...t,
|
|
64
|
+
must_include: t.expected.must_include ?? [],
|
|
65
|
+
must_not: t.expected.must_not ?? [],
|
|
66
|
+
}));
|
|
67
|
+
return limit === null ? all : all.slice(0, limit);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function contexts(): Record<Arm, string> {
|
|
71
|
+
// Mirror `project_thin_rules.measure()` exactly — same file set, same join —
|
|
72
|
+
// so the arms this run bills for are the arms the token measurement reports.
|
|
73
|
+
// `build_thin`'s first parameter is the rules DIRECTORY, not a scope; passing
|
|
74
|
+
// a scope string there silently yields an empty map and a rule-free "thin"
|
|
75
|
+
// arm, which would measure nothing.
|
|
76
|
+
const names = fs.readdirSync(RULES_SOURCE).filter((f) => f.endsWith('.md')).sort();
|
|
77
|
+
const eager = names.map((f) => fs.readFileSync(path.join(RULES_SOURCE, f), 'utf-8')).join('');
|
|
78
|
+
const thin = [...build_thin(RULES_SOURCE, null).values()].join('');
|
|
79
|
+
if (thin.length === 0) throw new Error('thin projection is empty — refusing to run a rule-free arm');
|
|
80
|
+
return { eager, thin };
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function anthropic(model: string): (s: string, u: string) => string {
|
|
84
|
+
const require = createRequire(import.meta.url);
|
|
85
|
+
const c = require('./ai_council/clients.js') as {
|
|
86
|
+
AnthropicClient: new (o: { model: string; api_key: string }) => { ask(s: string, u: string): { text: string } };
|
|
87
|
+
load_anthropic_key: () => string;
|
|
88
|
+
};
|
|
89
|
+
const cl = new c.AnthropicClient({ model, api_key: c.load_anthropic_key() });
|
|
90
|
+
return (s, u) => cl.ask(s, u).text;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function openai(model: string): (s: string, u: string) => string {
|
|
94
|
+
const require = createRequire(import.meta.url);
|
|
95
|
+
const c = require('./ai_council/clients.js') as {
|
|
96
|
+
OpenAIClient: new (o: { model: string; api_key: string }) => { ask(s: string, u: string): { text: string } };
|
|
97
|
+
load_openai_key: () => string;
|
|
98
|
+
};
|
|
99
|
+
const cl = new c.OpenAIClient({ model, api_key: c.load_openai_key() });
|
|
100
|
+
return (s, u) => cl.ask(s, u).text;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// ── generate ────────────────────────────────────────────────────────────────
|
|
104
|
+
function generate(dir: string, limit: number | null): number {
|
|
105
|
+
const tasks = load_tasks(limit);
|
|
106
|
+
const ctx = contexts();
|
|
107
|
+
const ask = anthropic(ANSWER_MODEL);
|
|
108
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
109
|
+
const out: Record<string, Record<Arm, string>> = {};
|
|
110
|
+
let i = 0;
|
|
111
|
+
for (const t of tasks) {
|
|
112
|
+
i += 1;
|
|
113
|
+
process.stdout.write(` [${i}/${tasks.length}] ${t.id}\n`);
|
|
114
|
+
out[t.id] = {
|
|
115
|
+
thin: ask(ANSWER_SYSTEM + ctx.thin, t.prompt),
|
|
116
|
+
eager: ask(ANSWER_SYSTEM + ctx.eager, t.prompt),
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
fs.writeFileSync(
|
|
120
|
+
path.join(dir, 'transcripts.json'),
|
|
121
|
+
JSON.stringify({ answer_model: ANSWER_MODEL, task_count: tasks.length, limit, transcripts: out }, null, 2) + '\n',
|
|
122
|
+
);
|
|
123
|
+
process.stdout.write(`\n❄️ frozen: ${path.relative(REPO_ROOT, dir)}/transcripts.json (${tasks.length} tasks × 2 arms)\n`);
|
|
124
|
+
return 0;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// ── score ───────────────────────────────────────────────────────────────────
|
|
128
|
+
function score(dir: string): number {
|
|
129
|
+
const frozen = JSON.parse(fs.readFileSync(path.join(dir, 'transcripts.json'), 'utf-8')) as {
|
|
130
|
+
answer_model: string;
|
|
131
|
+
transcripts: Record<string, Record<Arm, string>>;
|
|
132
|
+
};
|
|
133
|
+
const ids = new Set(Object.keys(frozen.transcripts));
|
|
134
|
+
const tasks = load_tasks(null).filter((t) => ids.has(t.id));
|
|
135
|
+
const evalA = anthropic(EVAL_ANTHROPIC);
|
|
136
|
+
const evalB = openai(EVAL_OPENAI);
|
|
137
|
+
|
|
138
|
+
const labelsA: string[] = [];
|
|
139
|
+
const labelsB: string[] = [];
|
|
140
|
+
const resolved = new Map<string, boolean>();
|
|
141
|
+
const disagreements: Array<{ task_id: string; arm: Arm; kind: string; anchor: string; a: string; b: string; resolved_to: boolean }> = [];
|
|
142
|
+
let retries = 0;
|
|
143
|
+
let n = 0;
|
|
144
|
+
|
|
145
|
+
for (const t of tasks) {
|
|
146
|
+
for (const arm of ['thin', 'eager'] as const) {
|
|
147
|
+
n += 1;
|
|
148
|
+
process.stdout.write(` [${n}/${tasks.length * 2}] ${t.id} · ${arm}\n`);
|
|
149
|
+
const p = eval_prompt(t.prompt, frozen.transcripts[t.id]![arm], t.must_include, t.must_not);
|
|
150
|
+
const ra = eval_with_retry((u) => evalA(EVAL_SYSTEM, u), p, t.must_include.length, t.must_not.length);
|
|
151
|
+
const rb = eval_with_retry((u) => evalB(EVAL_SYSTEM, u), p, t.must_include.length, t.must_not.length);
|
|
152
|
+
if (ra.retried) retries += 1;
|
|
153
|
+
if (rb.retried) retries += 1;
|
|
154
|
+
|
|
155
|
+
const record = (kind: 'must_include' | 'must_not', idx: number, anchor: string, a: boolean | null, b: boolean | null): void => {
|
|
156
|
+
labelsA.push(String(a));
|
|
157
|
+
labelsB.push(String(b));
|
|
158
|
+
const r = resolve(kind, a, b);
|
|
159
|
+
resolved.set(key(t.id, arm, kind, idx), r);
|
|
160
|
+
if (a !== b) {
|
|
161
|
+
disagreements.push({ task_id: t.id, arm, kind, anchor, a: String(a), b: String(b), resolved_to: r });
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
t.must_include.forEach((anchor, idx) => record('must_include', idx, anchor, ra.include[idx]!, rb.include[idx]!));
|
|
165
|
+
t.must_not.forEach((anchor, idx) => record('must_not', idx, anchor, ra.not[idx]!, rb.not[idx]!));
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const kappa = cohensKappa(labelsA, labelsB);
|
|
170
|
+
const input = { tasks, resolved };
|
|
171
|
+
const v = verdict(input, { kappa });
|
|
172
|
+
const delta = delta_from_spread(input);
|
|
173
|
+
|
|
174
|
+
fs.writeFileSync(
|
|
175
|
+
path.join(dir, 'verdicts.json'),
|
|
176
|
+
JSON.stringify({ evaluators: [EVAL_ANTHROPIC, EVAL_OPENAI], retries, labelsA, labelsB, disagreements }, null, 2) + '\n',
|
|
177
|
+
);
|
|
178
|
+
|
|
179
|
+
// quality-run.json — the schema check_quality_regression reads. Per-pair
|
|
180
|
+
// winners are emitted for compatibility; the DECISION is the two-leg
|
|
181
|
+
// aggregate below, and saying so here is the split ADR-202 required be explicit.
|
|
182
|
+
const results = tasks.map((t) => {
|
|
183
|
+
let thin = 0;
|
|
184
|
+
let eager = 0;
|
|
185
|
+
t.must_include.forEach((_, i) => {
|
|
186
|
+
if (resolved.get(key(t.id, 'thin', 'must_include', i)) === true) thin += 1;
|
|
187
|
+
if (resolved.get(key(t.id, 'eager', 'must_include', i)) === true) eager += 1;
|
|
188
|
+
});
|
|
189
|
+
return {
|
|
190
|
+
id: t.id,
|
|
191
|
+
winner: thin > eager ? 'thin' : eager > thin ? 'eager' : 'tie',
|
|
192
|
+
length_delta: 0,
|
|
193
|
+
winner_is_longer: null,
|
|
194
|
+
};
|
|
195
|
+
});
|
|
196
|
+
fs.mkdirSync(path.dirname(REPORT), { recursive: true });
|
|
197
|
+
fs.writeFileSync(
|
|
198
|
+
REPORT,
|
|
199
|
+
JSON.stringify(
|
|
200
|
+
{
|
|
201
|
+
threshold: 0.48,
|
|
202
|
+
judge_model: `anchor-scoring:${EVAL_ANTHROPIC}+${EVAL_OPENAI}`,
|
|
203
|
+
note: 'Per-pair winners are schema compatibility only. The decision is the two-leg aggregate in `anchor_verdict`.',
|
|
204
|
+
anchor_verdict: { ...v, delta_from_spread_pp: delta, retries, disagreement_count: disagreements.length },
|
|
205
|
+
results,
|
|
206
|
+
},
|
|
207
|
+
null,
|
|
208
|
+
2,
|
|
209
|
+
) + '\n',
|
|
210
|
+
);
|
|
211
|
+
|
|
212
|
+
const line = (ok: boolean, s: string): void => {
|
|
213
|
+
process.stdout.write(` ${ok ? '✅' : '❌'} ${s}\n`);
|
|
214
|
+
};
|
|
215
|
+
process.stdout.write('\n── verdict ──\n');
|
|
216
|
+
line(v.instrument_ok, `κ = ${kappa.toFixed(3)} (floor ${v.kappa_floor})`);
|
|
217
|
+
line(v.delta_registered, `δ = ${delta.toFixed(2)} pp (ceiling ${v.delta_ceiling_pp} pp)`);
|
|
218
|
+
line(v.must_not_ok, `must_not: ${v.thin.must_not_violations.length} thin / ${v.eager.must_not_violations.length} eager violations`);
|
|
219
|
+
line(v.non_inferiority_ok, `must_include: thin ${(v.thin.rate * 100).toFixed(1)}% vs eager ${(v.eager.rate * 100).toFixed(1)}% (gap ${v.rate_gap_pp.toFixed(2)} pp)`);
|
|
220
|
+
line(v.per_rule_floor_ok, `per-rule floor: ${v.per_rule_floor_breaches.length} breach(es)`);
|
|
221
|
+
process.stdout.write(`\n ${v.pass ? '✅ PASS' : '❌ FAIL'} · disagreements ${disagreements.length} · retries ${retries}\n`);
|
|
222
|
+
return v.pass ? 0 : 2;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function main(argv: string[]): number {
|
|
226
|
+
const gi = argv.indexOf('--generate');
|
|
227
|
+
const si = argv.indexOf('--score');
|
|
228
|
+
const li = argv.indexOf('--limit');
|
|
229
|
+
const limit = li >= 0 ? Number(argv[li + 1]) : null;
|
|
230
|
+
if (gi >= 0) return generate(path.resolve(argv[gi + 1] ?? ''), limit);
|
|
231
|
+
if (si >= 0) return score(path.resolve(argv[si + 1] ?? ''));
|
|
232
|
+
process.stderr.write('usage: anchor_scoring_run --generate DIR [--limit N] | --score DIR\n');
|
|
233
|
+
return 1;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
if (process.argv[1] !== undefined && process.argv[1].endsWith('anchor_scoring_run.ts')) {
|
|
237
|
+
process.exit(main(process.argv.slice(2)));
|
|
238
|
+
}
|
|
239
|
+
export { generate, score };
|
|
@@ -6,23 +6,19 @@
|
|
|
6
6
|
* Python→TS migration, Phase 8 / Wave 8g). Mirrors the Python CLI contract
|
|
7
7
|
* EXACTLY — the `--pack` choice flag + positional `paths`, exit code (0),
|
|
8
8
|
* the stdout/stderr split, byte-identical messages, and byte-identical
|
|
9
|
-
* frontmatter rewrites of the source
|
|
10
|
-
* condensation-hash file.
|
|
9
|
+
* frontmatter rewrites of the source and the dist/agent-src mirror.
|
|
11
10
|
*
|
|
12
11
|
* Walks a list of artefacts in `.agent-src.uncondensed/` and:
|
|
13
12
|
* 1. Inserts the 5 ADR-013 frontmatter keys (workspaces, packs, lifecycle,
|
|
14
13
|
* trust, install) before the closing `---`, deterministically.
|
|
15
14
|
* 2. Mirrors the new keys into the matching `dist/agent-src/` counterpart so
|
|
16
15
|
* the condensed projection stays consistent (body preserved).
|
|
17
|
-
* 3. Refreshes `internal/.condensation-hashes.json` for each touched source
|
|
18
|
-
* path so `task check-condensation` stays green.
|
|
19
16
|
*
|
|
20
17
|
* Idempotent: re-runs leave already-annotated files untouched.
|
|
21
18
|
*
|
|
22
19
|
* Mapping table (`PACK_DEFAULTS`) is the council-locked authority. No
|
|
23
20
|
* behaviour changes — historical quirks preserved (consumers pin the exact behaviour).
|
|
24
21
|
*/
|
|
25
|
-
import * as crypto from 'node:crypto';
|
|
26
22
|
import * as fs from 'node:fs';
|
|
27
23
|
import * as path from 'node:path';
|
|
28
24
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
@@ -32,7 +28,6 @@ const _HERE = fileURLToPath(import.meta.url);
|
|
|
32
28
|
export const ROOT = path.resolve(path.dirname(_HERE), '..', '..');
|
|
33
29
|
export const SRC = path.join(ROOT, '.agent-src.uncondensed');
|
|
34
30
|
export const DST = path.join(ROOT, 'dist/agent-src');
|
|
35
|
-
export const HASH_FILE = path.join(ROOT, 'internal', '.condensation-hashes.json');
|
|
36
31
|
|
|
37
32
|
// Pack → [workspace_id, trust_level, default_install, removable, lifecycle].
|
|
38
33
|
export const PACK_DEFAULTS: Record<string, [string, string, boolean, boolean, string]> = {
|
|
@@ -131,13 +126,6 @@ function _mirrorToCondensed(rel: string, pack: string): void {
|
|
|
131
126
|
fs.writeFileSync(dst, newText, 'utf-8');
|
|
132
127
|
}
|
|
133
128
|
|
|
134
|
-
function _refreshHash(rel: string, hashes: Record<string, string>): void {
|
|
135
|
-
const src = path.join(SRC, rel);
|
|
136
|
-
// rel.as_posix() — POSIX separators for the JSON key, regardless of OS.
|
|
137
|
-
const key = rel.split(path.sep).join('/');
|
|
138
|
-
hashes[key] = crypto.createHash('sha256').update(fs.readFileSync(src)).digest('hex');
|
|
139
|
-
}
|
|
140
|
-
|
|
141
129
|
function _isFile(p: string): boolean {
|
|
142
130
|
try {
|
|
143
131
|
return fs.statSync(p).isFile();
|
|
@@ -202,9 +190,6 @@ export function parseArgs(argv: string[]): Args {
|
|
|
202
190
|
export function main(argv: string[] | null = null): number {
|
|
203
191
|
const args = parseArgs(argv ?? process.argv.slice(2));
|
|
204
192
|
|
|
205
|
-
const hashes: Record<string, string> = _isFile(HASH_FILE)
|
|
206
|
-
? (JSON.parse(fs.readFileSync(HASH_FILE, 'utf-8')) as Record<string, string>)
|
|
207
|
-
: {};
|
|
208
193
|
let changed = 0;
|
|
209
194
|
for (const raw of args.paths) {
|
|
210
195
|
let rel = raw;
|
|
@@ -226,60 +211,11 @@ export function main(argv: string[] | null = null): number {
|
|
|
226
211
|
changed += 1;
|
|
227
212
|
}
|
|
228
213
|
_mirrorToCondensed(inner, args.pack);
|
|
229
|
-
_refreshHash(inner, hashes);
|
|
230
214
|
}
|
|
231
|
-
// json.dumps(hashes, indent=2, sort_keys=True) + "\n"
|
|
232
|
-
fs.mkdirSync(path.dirname(HASH_FILE), { recursive: true });
|
|
233
|
-
fs.writeFileSync(HASH_FILE, _dumpsSorted(hashes) + '\n', 'utf-8');
|
|
234
215
|
process.stdout.write(`annotated ${changed} files with pack=${args.pack}\n`);
|
|
235
216
|
return 0;
|
|
236
217
|
}
|
|
237
218
|
|
|
238
|
-
// --- json.dumps(indent=2, sort_keys=True) for a flat string→string map -------
|
|
239
|
-
|
|
240
|
-
function _pyJsonStr(s: string): string {
|
|
241
|
-
let out = '"';
|
|
242
|
-
for (const ch of s) {
|
|
243
|
-
const code = ch.codePointAt(0) as number;
|
|
244
|
-
if (ch === '"') {
|
|
245
|
-
out += '\\"';
|
|
246
|
-
} else if (ch === '\\') {
|
|
247
|
-
out += '\\\\';
|
|
248
|
-
} else if (ch === '\n') {
|
|
249
|
-
out += '\\n';
|
|
250
|
-
} else if (ch === '\r') {
|
|
251
|
-
out += '\\r';
|
|
252
|
-
} else if (ch === '\t') {
|
|
253
|
-
out += '\\t';
|
|
254
|
-
} else if (ch === '\b') {
|
|
255
|
-
out += '\\b';
|
|
256
|
-
} else if (ch === '\f') {
|
|
257
|
-
out += '\\f';
|
|
258
|
-
} else if (code < 0x20) {
|
|
259
|
-
out += `\\u${code.toString(16).padStart(4, '0')}`;
|
|
260
|
-
} else if (code < 0x7f) {
|
|
261
|
-
out += ch;
|
|
262
|
-
} else if (code <= 0xffff) {
|
|
263
|
-
out += `\\u${code.toString(16).padStart(4, '0')}`;
|
|
264
|
-
} else {
|
|
265
|
-
const c = code - 0x10000;
|
|
266
|
-
const hi = 0xd800 + (c >> 10);
|
|
267
|
-
const lo = 0xdc00 + (c & 0x3ff);
|
|
268
|
-
out += `\\u${hi.toString(16).padStart(4, '0')}\\u${lo.toString(16).padStart(4, '0')}`;
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
return out + '"';
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
function _dumpsSorted(obj: Record<string, string>): string {
|
|
275
|
-
const keys = Object.keys(obj).sort();
|
|
276
|
-
if (keys.length === 0) {
|
|
277
|
-
return '{}';
|
|
278
|
-
}
|
|
279
|
-
const parts = keys.map((k) => ` ${_pyJsonStr(k)}: ${_pyJsonStr(obj[k] as string)}`);
|
|
280
|
-
return `{\n${parts.join(',\n')}\n}`;
|
|
281
|
-
}
|
|
282
|
-
|
|
283
219
|
function _isCliEntry(): boolean {
|
|
284
220
|
if (process.argv[1] === undefined) {
|
|
285
221
|
return false;
|
|
@@ -126,6 +126,116 @@ export function run_golden_judge(
|
|
|
126
126
|
});
|
|
127
127
|
}
|
|
128
128
|
|
|
129
|
+
// ── Export mode (--dump-answers): blinded pairs for an external instrument ──
|
|
130
|
+
//
|
|
131
|
+
// Needed because LLM-paired judging on thin-vs-eager is closed-by-diagnosis
|
|
132
|
+
// (`docs/benchmark.md` § Length-neutral judge RERUN). Any admissible re-open
|
|
133
|
+
// needs the raw answer pairs, whether the instrument is deterministic
|
|
134
|
+
// anchor-scoring against `must_include`/`must_not` or a human judge. Export mode
|
|
135
|
+
// makes NO judge calls, so it costs ~half a full judged run (2 arms, 0 judges).
|
|
136
|
+
|
|
137
|
+
/** Deterministic per-task coin flip — FNV-1a over `seed:taskId`, low bit.
|
|
138
|
+
* Reproducible blinding without Math.random, so re-running the export yields
|
|
139
|
+
* the same A/B assignment and a partially-filled verdicts.csv stays valid. */
|
|
140
|
+
export function blind_flip(taskId: string, seed: number): boolean {
|
|
141
|
+
const s = `${seed}:${taskId}`;
|
|
142
|
+
let h = 0x811c9dc5;
|
|
143
|
+
for (let i = 0; i < s.length; i += 1) {
|
|
144
|
+
h ^= s.charCodeAt(i);
|
|
145
|
+
h = Math.imul(h, 0x01000193) >>> 0;
|
|
146
|
+
}
|
|
147
|
+
return (h & 1) === 1;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export interface BlindPair {
|
|
151
|
+
id: string;
|
|
152
|
+
/** Which arm was presented as ANSWER A. Belongs in _mapping.json ONLY. */
|
|
153
|
+
a_arm: 'thin' | 'eager';
|
|
154
|
+
answer_a: string;
|
|
155
|
+
answer_b: string;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export function build_blind_pair(
|
|
159
|
+
task: GoldenTask,
|
|
160
|
+
thinAnswer: string,
|
|
161
|
+
eagerAnswer: string,
|
|
162
|
+
seed: number,
|
|
163
|
+
): BlindPair {
|
|
164
|
+
const thinIsA = blind_flip(task.id, seed);
|
|
165
|
+
return {
|
|
166
|
+
id: task.id,
|
|
167
|
+
a_arm: thinIsA ? 'thin' : 'eager',
|
|
168
|
+
answer_a: thinIsA ? thinAnswer : eagerAnswer,
|
|
169
|
+
answer_b: thinIsA ? eagerAnswer : thinAnswer,
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/** Render the operator-facing pair file. MUST NOT leak the arm mapping —
|
|
174
|
+
* `tests/scripts/bench_quality_run.test.ts` asserts the blinding invariant. */
|
|
175
|
+
export function render_pair_file(task: GoldenTask, pair: BlindPair): string {
|
|
176
|
+
const lines: string[] = [`# ${task.id}`, '', '## Request', '', task.prompt, '', '## Rubric', '', task.rubric, ''];
|
|
177
|
+
if (task.must_include.length) lines.push('## Must satisfy', '', ...task.must_include.map((s) => `- ${s}`), '');
|
|
178
|
+
if (task.must_not.length) lines.push('## Must avoid', '', ...task.must_not.map((s) => `- ${s}`), '');
|
|
179
|
+
lines.push(
|
|
180
|
+
'## Judging rules',
|
|
181
|
+
'',
|
|
182
|
+
'- Judge ONLY which answer better satisfies the rubric above.',
|
|
183
|
+
'- IGNORE length and verbosity. A longer answer is NOT a better answer.',
|
|
184
|
+
'- `tie` is a valid verdict — do not force a winner.',
|
|
185
|
+
'- Do NOT open `_mapping.json` until every verdict is recorded.',
|
|
186
|
+
'',
|
|
187
|
+
'## ANSWER A',
|
|
188
|
+
'',
|
|
189
|
+
pair.answer_a,
|
|
190
|
+
'',
|
|
191
|
+
'## ANSWER B',
|
|
192
|
+
'',
|
|
193
|
+
pair.answer_b,
|
|
194
|
+
'',
|
|
195
|
+
'## Verdict',
|
|
196
|
+
'',
|
|
197
|
+
`Append to verdicts.csv — one of: \`${task.id},A\` · \`${task.id},B\` · \`${task.id},tie\``,
|
|
198
|
+
'',
|
|
199
|
+
);
|
|
200
|
+
return lines.join('\n');
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/** Write the blinded export: one file per task + the withheld mapping + a CSV stub. */
|
|
204
|
+
export function write_export(
|
|
205
|
+
dir: string,
|
|
206
|
+
tasks: GoldenTask[],
|
|
207
|
+
pairs: BlindPair[],
|
|
208
|
+
meta: { seed: number; model: string; dry_run: boolean },
|
|
209
|
+
): void {
|
|
210
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
211
|
+
const byId = new Map(tasks.map((t) => [t.id, t]));
|
|
212
|
+
for (const pair of pairs) {
|
|
213
|
+
const task = byId.get(pair.id);
|
|
214
|
+
if (task === undefined) continue;
|
|
215
|
+
fs.writeFileSync(path.join(dir, `${pair.id}.md`), render_pair_file(task, pair));
|
|
216
|
+
}
|
|
217
|
+
fs.writeFileSync(
|
|
218
|
+
path.join(dir, '_mapping.json'),
|
|
219
|
+
JSON.stringify(
|
|
220
|
+
{
|
|
221
|
+
generated_by: 'bench_quality_run --dump-answers',
|
|
222
|
+
warning: 'DO NOT READ until every verdict is recorded in verdicts.csv.',
|
|
223
|
+
seed: meta.seed,
|
|
224
|
+
answer_model: meta.model,
|
|
225
|
+
dry_run: meta.dry_run,
|
|
226
|
+
threshold: DEFAULT_THRESHOLD,
|
|
227
|
+
mapping: pairs.map((p) => ({ id: p.id, a_arm: p.a_arm })),
|
|
228
|
+
},
|
|
229
|
+
null,
|
|
230
|
+
2,
|
|
231
|
+
) + '\n',
|
|
232
|
+
);
|
|
233
|
+
const csv = path.join(dir, 'verdicts.csv');
|
|
234
|
+
if (!fs.existsSync(csv)) {
|
|
235
|
+
fs.writeFileSync(csv, `task_id,verdict\n${pairs.map((p) => `${p.id},`).join('\n')}\n`);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
129
239
|
// ── Mock model (--dry-run): deterministic, no API ───────────────────────────
|
|
130
240
|
function mock_answer(_ctx: string, task: GoldenTask): string {
|
|
131
241
|
return `Answer to ${task.id}: ${(task.must_include[0] ?? 'addresses the request')}.`;
|
|
@@ -137,16 +247,41 @@ interface Args {
|
|
|
137
247
|
model: string;
|
|
138
248
|
limit: number | null;
|
|
139
249
|
output: string;
|
|
250
|
+
dumpAnswers: string | null;
|
|
251
|
+
seed: number;
|
|
140
252
|
}
|
|
141
253
|
|
|
254
|
+
const DEFAULT_SEED = 20260729;
|
|
255
|
+
|
|
142
256
|
function parse_args(argv: string[]): Args | number {
|
|
143
|
-
const a: Args = {
|
|
257
|
+
const a: Args = {
|
|
258
|
+
dryRun: false,
|
|
259
|
+
model: 'claude-sonnet-4-5',
|
|
260
|
+
limit: null,
|
|
261
|
+
output: OUT,
|
|
262
|
+
dumpAnswers: null,
|
|
263
|
+
seed: DEFAULT_SEED,
|
|
264
|
+
};
|
|
144
265
|
for (let i = 0; i < argv.length; i += 1) {
|
|
145
266
|
const arg = argv[i];
|
|
146
267
|
if (arg === '--dry-run') a.dryRun = true;
|
|
147
268
|
else if (arg === '--model') a.model = String(argv[(i += 1)] ?? a.model);
|
|
148
269
|
else if (arg === '--output') a.output = String(argv[(i += 1)] ?? a.output);
|
|
149
|
-
else if (arg === '--
|
|
270
|
+
else if (arg === '--dump-answers') {
|
|
271
|
+
const v = argv[(i += 1)];
|
|
272
|
+
if (v === undefined || v.startsWith('--')) {
|
|
273
|
+
process.stderr.write('error: --dump-answers requires a directory path\n');
|
|
274
|
+
return 1;
|
|
275
|
+
}
|
|
276
|
+
a.dumpAnswers = v;
|
|
277
|
+
} else if (arg === '--seed') {
|
|
278
|
+
const v = Number(argv[(i += 1)]);
|
|
279
|
+
if (!Number.isInteger(v)) {
|
|
280
|
+
process.stderr.write('error: --seed must be an integer\n');
|
|
281
|
+
return 1;
|
|
282
|
+
}
|
|
283
|
+
a.seed = v;
|
|
284
|
+
} else if (arg === '--limit') {
|
|
150
285
|
const v = Number(argv[(i += 1)]);
|
|
151
286
|
if (!Number.isInteger(v) || v < 1) {
|
|
152
287
|
process.stderr.write('error: --limit must be a positive integer\n');
|
|
@@ -154,7 +289,13 @@ function parse_args(argv: string[]): Args | number {
|
|
|
154
289
|
}
|
|
155
290
|
a.limit = v;
|
|
156
291
|
} else if (arg === '-h' || arg === '--help') {
|
|
157
|
-
process.stdout.write(
|
|
292
|
+
process.stdout.write(
|
|
293
|
+
'usage: bench_quality_run [--dry-run] [--model M] [--limit N] [--output PATH]\n' +
|
|
294
|
+
' [--dump-answers DIR] [--seed N]\n\n' +
|
|
295
|
+
' --dump-answers DIR export blinded pairs for an external instrument; makes NO\n' +
|
|
296
|
+
' judge calls (~half the cost of a judged run)\n' +
|
|
297
|
+
` --seed N deterministic A/B blinding seed (default ${String(DEFAULT_SEED)})\n`,
|
|
298
|
+
);
|
|
158
299
|
return 0;
|
|
159
300
|
} else {
|
|
160
301
|
process.stderr.write(`error: unknown argument: ${arg}\n`);
|
|
@@ -214,8 +355,31 @@ function main(argv: string[]): number {
|
|
|
214
355
|
);
|
|
215
356
|
modelLabel = args.model;
|
|
216
357
|
process.stdout.write(
|
|
217
|
-
|
|
358
|
+
args.dumpAnswers === null
|
|
359
|
+
? `Live run: ${tasks.length} tasks × 2 arms + 2 judge calls each via ${args.model}. This costs API $.\n`
|
|
360
|
+
: `Live export: ${tasks.length} tasks × 2 arms via ${args.model}, NO judge calls. This costs API $.\n`,
|
|
361
|
+
);
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
// Export mode: generate both arms, blind them, write the pairs, judge nothing.
|
|
365
|
+
if (args.dumpAnswers !== null) {
|
|
366
|
+
let pairs: BlindPair[];
|
|
367
|
+
try {
|
|
368
|
+
pairs = tasks.map((task) =>
|
|
369
|
+
build_blind_pair(task, answer(contexts.thin, task), answer(contexts.eager, task), args.seed),
|
|
370
|
+
);
|
|
371
|
+
} catch (e) {
|
|
372
|
+
process.stderr.write(`error: answer generation failed: ${(e as Error).message}\n`);
|
|
373
|
+
return 1;
|
|
374
|
+
}
|
|
375
|
+
const dir = path.resolve(args.dumpAnswers);
|
|
376
|
+
write_export(dir, tasks, pairs, { seed: args.seed, model: modelLabel, dry_run: args.dryRun });
|
|
377
|
+
process.stdout.write(
|
|
378
|
+
`→ wrote ${pairs.length} blinded pairs to ${dir}\n` +
|
|
379
|
+
` Arm mapping withheld in _mapping.json — do not open it until verdicts.csv is complete.\n` +
|
|
380
|
+
` Judged nothing: LLM-paired judging is closed-by-diagnosis for this question.\n`,
|
|
218
381
|
);
|
|
382
|
+
return 0;
|
|
219
383
|
}
|
|
220
384
|
|
|
221
385
|
let results: PairResult[];
|