@event4u/agent-config 14.9.0 → 14.11.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 +384 -0
- package/README.md +1 -1
- package/dist/agent-src/commands/design.md +88 -0
- package/dist/agent-src/commands/project/analyze.md +47 -0
- package/dist/agent-src/commands/review/changes.md +67 -6
- package/dist/agent-src/commands/roadmap/create.md +49 -0
- package/dist/agent-src/commands/roadmap/next.md +27 -11
- package/dist/agent-src/commands/roadmap/process-full.md +14 -0
- package/dist/agent-src/commands/video/from-script.md +60 -3
- package/dist/agent-src/commands/video/stitch.md +14 -0
- package/dist/agent-src/contexts/communication/rules-auto/guidelines-mechanics.md +1 -0
- package/dist/agent-src/contexts/execution/roadmap-process-loop.md +154 -2
- package/dist/agent-src/rules/active-remediation.md +3 -3
- package/dist/agent-src/rules/code-provenance.md +2 -2
- package/dist/agent-src/rules/context-hygiene.md +13 -33
- package/dist/agent-src/rules/council-availability.md +2 -2
- package/dist/agent-src/rules/decision-revisit-gate.md +3 -1
- package/dist/agent-src/rules/design-fidelity.md +18 -0
- package/dist/agent-src/rules/design-review-after-ui-write.md +2 -2
- package/dist/agent-src/rules/evaluator-independence.md +56 -44
- package/dist/agent-src/rules/fix-what-you-see.md +9 -1
- package/dist/agent-src/rules/framework-neutrality-in-generic-skills.md +1 -1
- package/dist/agent-src/rules/minimal-safe-diff.md +14 -20
- package/dist/agent-src/rules/missing-skill-recovery.md +13 -1
- package/dist/agent-src/rules/playbook-precedence.md +105 -0
- package/dist/agent-src/rules/recurring-criticism.md +3 -1
- package/dist/agent-src/rules/roadmap-progress-sync.md +14 -13
- package/dist/agent-src/rules/scale-discipline.md +24 -0
- package/dist/agent-src/rules/security-sensitive-stop.md +2 -2
- package/dist/agent-src/rules/settings-ask-protocol.md +2 -2
- package/dist/agent-src/rules/ui-audit-gate.md +27 -15
- package/dist/agent-src/rules/untrusted-input-defense.md +2 -2
- package/dist/agent-src/skills/accessibility-auditor/SKILL.md +19 -0
- package/dist/agent-src/skills/adr-create/SKILL.md +7 -0
- package/dist/agent-src/skills/agents-md-thin-root/SKILL.md +33 -0
- package/dist/agent-src/skills/ai-council/references/advanced-modes.md +17 -3
- package/dist/agent-src/skills/ai-council/references/output-and-synthesis.md +31 -0
- package/dist/agent-src/skills/ai-council/references/procedure.md +19 -0
- package/dist/agent-src/skills/alerting-doctrine/SKILL.md +225 -0
- package/dist/agent-src/skills/alerting-doctrine/evals/triggers.json +17 -0
- package/dist/agent-src/skills/async-python-patterns/SKILL.md +1 -1
- package/dist/agent-src/skills/authz-review/SKILL.md +0 -1
- package/dist/agent-src/skills/blast-radius-analyzer/SKILL.md +32 -0
- package/dist/agent-src/skills/brand/SKILL.md +3 -0
- package/dist/agent-src/skills/brand-asset-generation/SKILL.md +3 -0
- package/dist/agent-src/skills/brand-audit/SKILL.md +3 -0
- package/dist/agent-src/skills/brand-identity/SKILL.md +3 -0
- package/dist/agent-src/skills/brand-strategy/SKILL.md +3 -0
- package/dist/agent-src/skills/brand-to-tokens/SKILL.md +3 -0
- package/dist/agent-src/skills/check-refs/SKILL.md +3 -0
- package/dist/agent-src/skills/code-refactoring/SKILL.md +1 -1
- package/dist/agent-src/skills/code-review/SKILL.md +11 -0
- package/dist/agent-src/skills/command-routing/SKILL.md +6 -0
- package/dist/agent-src/skills/condense-memory/SKILL.md +4 -1
- package/dist/agent-src/skills/context-authoring/SKILL.md +1 -1
- package/dist/agent-src/skills/conventional-commits-writing/SKILL.md +4 -1
- package/dist/agent-src/skills/copilot-agents-optimization/SKILL.md +10 -0
- package/dist/agent-src/skills/corpus-grounding/SKILL.md +3 -0
- package/dist/agent-src/skills/design-intelligence/SKILL.md +3 -0
- package/dist/agent-src/skills/design-intelligence/data/landing.csv +36 -35
- package/dist/agent-src/skills/design-intelligence/data/stacks/threejs.csv +1 -0
- package/dist/agent-src/skills/design-review/SKILL.md +80 -2
- package/dist/agent-src/skills/design-review/references/verification-automation.md +41 -0
- package/dist/agent-src/skills/design-system-capture/SKILL.md +35 -40
- package/dist/agent-src/skills/design-system-capture/references/import-procedure.md +50 -0
- package/dist/agent-src/skills/design-tokens/SKILL.md +3 -0
- package/dist/agent-src/skills/design-variations/SKILL.md +3 -0
- package/dist/agent-src/skills/developer-like-execution/SKILL.md +3 -0
- package/dist/agent-src/skills/discovery-interview/SKILL.md +1 -1
- package/dist/agent-src/skills/doc-coauthoring/SKILL.md +1 -1
- package/dist/agent-src/skills/docx-authoring/SKILL.md +1 -1
- package/dist/agent-src/skills/editorial-calendar/SKILL.md +1 -1
- package/dist/agent-src/skills/estimate-ticket/SKILL.md +3 -0
- package/dist/agent-src/skills/existing-ui-audit/SKILL.md +20 -3
- package/dist/agent-src/skills/fe-design/SKILL.md +74 -41
- package/dist/agent-src/skills/fe-design/evals/triggers.json +65 -53
- package/dist/agent-src/skills/fe-design/references/craft-floor.md +52 -0
- package/dist/agent-src/skills/fe-design/references/source-led-port.md +36 -0
- package/dist/agent-src/skills/file-editor/SKILL.md +5 -0
- package/dist/agent-src/skills/finishing-a-development-branch/SKILL.md +2 -2
- package/dist/agent-src/skills/git-workflow/SKILL.md +3 -0
- package/dist/agent-src/skills/github-ci/SKILL.md +1 -1
- package/dist/agent-src/skills/html-deck/SKILL.md +3 -0
- package/dist/agent-src/skills/iconography/SKILL.md +3 -0
- package/dist/agent-src/skills/image-editing/SKILL.md +3 -0
- package/dist/agent-src/skills/image-generation/SKILL.md +3 -0
- package/dist/agent-src/skills/image-provider-routing/SKILL.md +3 -0
- package/dist/agent-src/skills/incident-commander/SKILL.md +10 -0
- package/dist/agent-src/skills/js-library-packaging/SKILL.md +173 -0
- package/dist/agent-src/skills/js-library-packaging/evals/triggers.json +17 -0
- package/dist/agent-src/skills/js-library-packaging/scripts/check_package_surface.ts +270 -0
- package/dist/agent-src/skills/judge-artifact-completeness/SKILL.md +1 -1
- package/dist/agent-src/skills/judge-injection-defense/SKILL.md +1 -1
- package/dist/agent-src/skills/laravel-migration/SKILL.md +3 -0
- package/dist/agent-src/skills/laravel-validation/SKILL.md +1 -1
- package/dist/agent-src/skills/learning-to-rule-or-skill/SKILL.md +3 -0
- package/dist/agent-src/skills/legal-intake-triage/SKILL.md +1 -1
- package/dist/agent-src/skills/legal-practice-profile/SKILL.md +1 -1
- package/dist/agent-src/skills/lint-skills/SKILL.md +3 -0
- package/dist/agent-src/skills/llm-provider-knowledge/SKILL.md +3 -0
- package/dist/agent-src/skills/logging-monitoring/SKILL.md +234 -51
- package/dist/agent-src/skills/logo-generation/SKILL.md +3 -0
- package/dist/agent-src/skills/md-language-check/SKILL.md +3 -0
- package/dist/agent-src/skills/messaging-architecture/SKILL.md +1 -1
- package/dist/agent-src/skills/migration-architect/SKILL.md +1 -1
- package/dist/agent-src/skills/module-detect-on-the-fly/SKILL.md +1 -1
- package/dist/agent-src/skills/module-management/SKILL.md +1 -1
- package/dist/agent-src/skills/monorepo-workspace/SKILL.md +149 -0
- package/dist/agent-src/skills/monorepo-workspace/evals/triggers.json +17 -0
- package/dist/agent-src/skills/motion-choreographer/SKILL.md +7 -1
- package/dist/agent-src/skills/multi-tenancy/SKILL.md +4 -0
- package/dist/agent-src/skills/onboarding-program/SKILL.md +1 -1
- package/dist/agent-src/skills/operational-readiness/SKILL.md +184 -0
- package/dist/agent-src/skills/operational-readiness/evals/triggers.json +17 -0
- package/dist/agent-src/skills/override-management/SKILL.md +3 -0
- package/dist/agent-src/skills/perf-feedback-craft/SKILL.md +1 -1
- package/dist/agent-src/skills/persona-improvement/SKILL.md +3 -0
- package/dist/agent-src/skills/pest-testing/SKILL.md +3 -0
- package/dist/agent-src/skills/playbook-authoring/SKILL.md +162 -0
- package/dist/agent-src/skills/playwright-testing/SKILL.md +3 -0
- package/dist/agent-src/skills/privacy-review/SKILL.md +3 -0
- package/dist/agent-src/skills/prompt-engineering-image/SKILL.md +3 -0
- package/dist/agent-src/skills/prompt-optimizer/SKILL.md +1 -1
- package/dist/agent-src/skills/quality-tools/SKILL.md +5 -0
- package/dist/agent-src/skills/react-shadcn-ui/SKILL.md +52 -21
- package/dist/agent-src/skills/readme-reviewer/SKILL.md +3 -0
- package/dist/agent-src/skills/readme-writing/SKILL.md +3 -0
- package/dist/agent-src/skills/readme-writing-package/SKILL.md +3 -0
- package/dist/agent-src/skills/receiving-code-review/SKILL.md +3 -3
- package/dist/agent-src/skills/refine-prompt/SKILL.md +3 -0
- package/dist/agent-src/skills/refine-ticket/SKILL.md +3 -0
- package/dist/agent-src/skills/requesting-code-review/SKILL.md +2 -2
- package/dist/agent-src/skills/review-routing/SKILL.md +2 -2
- package/dist/agent-src/skills/roadmap-writing/SKILL.md +23 -41
- package/dist/agent-src/skills/roadmap-writing/references/follow-up-roadmap-shape.md +47 -0
- package/dist/agent-src/skills/rtk-output-filtering/SKILL.md +22 -6
- package/dist/agent-src/skills/runway-cognition/SKILL.md +3 -0
- package/dist/agent-src/skills/scene-expander/SKILL.md +1 -1
- package/dist/agent-src/skills/scene-expander/scene-blueprint.schema.yaml +26 -0
- package/dist/agent-src/skills/secrets-management/SKILL.md +5 -1
- package/dist/agent-src/skills/server-hardening/SKILL.md +159 -0
- package/dist/agent-src/skills/server-hardening/evals/triggers.json +17 -0
- package/dist/agent-src/skills/skill-improvement-pipeline/SKILL.md +3 -0
- package/dist/agent-src/skills/skill-management/SKILL.md +3 -0
- package/dist/agent-src/skills/skill-reviewer/SKILL.md +3 -0
- package/dist/agent-src/skills/skill-writing/SKILL.md +6 -0
- package/dist/agent-src/skills/spreadsheet-authoring/SKILL.md +3 -0
- package/dist/agent-src/skills/storybook-workshop/SKILL.md +194 -0
- package/dist/agent-src/skills/storybook-workshop/evals/triggers.json +17 -0
- package/dist/agent-src/skills/storybook-workshop/scripts/story_contrast_floor.ts +134 -0
- package/dist/agent-src/skills/subagent-orchestration/SKILL.md +1 -1
- package/dist/agent-src/skills/subagent-orchestration/prompts/README.md +25 -0
- package/dist/agent-src/skills/supply-chain-intake/SKILL.md +12 -0
- package/dist/agent-src/skills/systematic-debugging/SKILL.md +1 -1
- package/dist/agent-src/skills/terraform/SKILL.md +3 -0
- package/dist/agent-src/skills/test-driven-development/SKILL.md +1 -1
- package/dist/agent-src/skills/threat-modeling/SKILL.md +0 -3
- package/dist/agent-src/skills/token-optimizer/SKILL.md +3 -0
- package/dist/agent-src/skills/typography-system/SKILL.md +3 -0
- package/dist/agent-src/skills/ui-component-architect/SKILL.md +9 -1
- package/dist/agent-src/skills/upstream-contribute/SKILL.md +3 -0
- package/dist/agent-src/skills/using-git-worktrees/SKILL.md +1 -1
- package/dist/agent-src/skills/validate-feature-fit/SKILL.md +3 -0
- package/dist/agent-src/skills/verify-completion-evidence/SKILL.md +2 -2
- package/dist/agent-src/skills/wireframe/SKILL.md +3 -0
- package/dist/agent-src/skills/wireframe/references/story-beat-ledger.schema.json +115 -0
- package/dist/agent-src/skills/workspace-link/SKILL.md +131 -0
- package/dist/agent-src/skills/workspace-link/evals/triggers.json +17 -0
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/agent-src/templates/playbook.md +75 -0
- package/dist/agent-src/templates/roadmaps.md +37 -0
- package/dist/agent-src/templates/scripts/check_playbook_invokes.ts +231 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +24 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/polish.ts +2 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/review.ts +216 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/scaffold.ts +159 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/stack_bundles.ts +73 -4
- package/dist/agent-src/templates/scripts/work_engine/stack/detect.ts +325 -40
- package/dist/cli/commands/uiAudit.js +221 -0
- package/dist/cli/commands/uiAudit.js.map +1 -0
- package/dist/cli/commands/uiRender.js +206 -0
- package/dist/cli/commands/uiRender.js.map +1 -0
- package/dist/cli/main.js +22 -1
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/mcp/content.js +64 -1
- package/dist/cli/mcp/content.js.map +1 -1
- package/dist/cli/mcp/dispatch.js +175 -10
- package/dist/cli/mcp/dispatch.js.map +1 -1
- package/dist/cli/registry.js +3 -0
- package/dist/cli/registry.js.map +1 -1
- package/dist/cli-delegate/{chunk-H4VIVD4C.js → chunk-236PNQZK.js} +413 -391
- package/dist/cli-delegate/{chunk-G23AT6GD.js → chunk-DMSZHXZS.js} +57 -1
- package/dist/cli-delegate/{chunk-77GR3VD4.js → chunk-FF7WAFMR.js} +58 -3
- package/dist/cli-delegate/{chunk-PLSG6UL5.js → chunk-K4FFODTS.js} +341 -204
- package/dist/cli-delegate/{chunk-YM4GZDJG.js → chunk-L43NCYPB.js} +5 -0
- package/dist/cli-delegate/{chunk-B2ERU2VA.js → chunk-WOKWX5PL.js} +1 -1
- package/dist/cli-delegate/cmd_brand_status.js +8 -6
- package/dist/cli-delegate/cmd_conformance.js +3 -3
- package/dist/cli-delegate/cmd_doctor.js +3 -3
- package/dist/cli-delegate/cmd_export.js +4 -4
- 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 +4 -4
- package/dist/cli-delegate/cmd_session_recycle.js +70 -9
- package/dist/cli-delegate/cmd_settings_migrate.js +4 -4
- package/dist/cli-delegate/cmd_settings_set.js +1 -1
- package/dist/cli-delegate/cmd_sync.js +4 -4
- package/dist/cli-delegate/cmd_uninstall.js +4 -4
- package/dist/cli-delegate/cmd_validate.js +4 -4
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +380 -145
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +4 -4
- package/dist/discovery/dormancy-report.md +1 -1
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +18 -8
- package/dist/discovery/trust-report.md +3 -3
- package/dist/discovery/workspaces.json +16 -6
- package/dist/hooks/dispatch.js +2337 -1436
- package/dist/install/install.mjs +795 -708
- package/dist/mcp/registry-manifest.json +3 -3
- package/dist/mcp/server.json +2 -2
- package/dist/mcp/server.mjs +1685 -1250
- package/dist/router.json +1 -1
- package/dist/scripts/_lib/lean_projection_mode.js +40 -0
- package/dist/scripts/_lib/lean_projection_mode.js.map +1 -0
- package/dist/scripts/_lib/scoped_projection.js +84 -0
- package/dist/scripts/_lib/scoped_projection.js.map +1 -1
- package/dist/scripts/_lib/ui_surface.js +89 -0
- package/dist/scripts/_lib/ui_surface.js.map +1 -0
- package/dist/scripts/condense.js +6 -10
- package/dist/scripts/condense.js.map +1 -1
- package/dist/scripts/project_thin_rules.js +40 -2
- package/dist/scripts/project_thin_rules.js.map +1 -1
- package/dist/server/schemas/settings.js +3 -0
- package/dist/server/schemas/settings.js.map +1 -1
- package/dist/shared/skillRanking.js +159 -0
- package/dist/shared/skillRanking.js.map +1 -0
- package/docs/contracts/provider-lifecycle.md +47 -18
- package/docs/contracts/settings-classes.md +14 -4
- package/docs/guidelines/agent-infra/context-hygiene-mechanics.md +49 -0
- package/docs/guidelines/agent-infra/evaluator-independence-mechanics.md +92 -0
- package/docs/guidelines/agent-infra/minimal-safe-diff-mechanics.md +45 -1
- package/docs/guidelines/agent-infra/roadmap-deferred-resolution-provenance.md +54 -0
- package/docs/guidelines/design-antipatterns.md +4 -2
- package/docs/guidelines/design-asset-discipline.md +38 -0
- package/docs/guidelines/design-fidelity-mechanics.md +45 -29
- package/docs/guidelines/design-handover-extraction.md +35 -5
- package/docs/guidelines/design-modes.md +41 -1
- package/docs/guidelines/monorepo-antipatterns.md +141 -0
- package/llms.txt +50 -39
- package/package.json +1 -1
- package/src/agent-src/templates/scripts/check_playbook_invokes.ts +231 -0
- package/src/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +24 -0
- package/src/agent-src/templates/scripts/work_engine/directives/ui/polish.ts +2 -0
- package/src/agent-src/templates/scripts/work_engine/directives/ui/review.ts +216 -0
- package/src/agent-src/templates/scripts/work_engine/directives/ui/scaffold.ts +159 -0
- package/src/agent-src/templates/scripts/work_engine/directives/ui/stack_bundles.ts +73 -4
- package/src/agent-src/templates/scripts/work_engine/stack/detect.ts +325 -40
- package/src/config/agent-settings.template.yml +28 -0
- package/src/config/assurance-capability-registry.json +223 -0
- package/src/config/assurance-threshold-budget.json +65 -0
- package/src/config/ci-local-parity.yml +14 -0
- package/src/config/discovery/unassigned-artefacts.yml +2 -0
- package/src/config/dispatch-economy-metrics.json +4 -2
- package/src/config/evaluator-budgets.json +14 -14
- package/src/config/gate-coverage.yml +227 -8
- package/src/config/gate-violation-baselines.json +76 -72
- package/src/config/hook-latency-budget.json +1 -0
- package/src/config/hook-token-budget.json +137 -125
- package/src/config/pack-size-budget.json +4 -2
- package/src/config/preamble-payload-budget.json +71 -67
- package/src/config/quorum-attendance-budget.json +12 -4
- package/src/config/rule-activation-census.json +7 -3
- package/src/config/rule-enforcement-baseline.json +0 -1
- package/src/config/rule-stub-ceilings.json +112 -91
- package/src/scripts/_cli/cmd_doctor.ts +15 -16
- package/src/scripts/_cli/doctor_install_mode.ts +49 -0
- package/src/scripts/_cli/doctor_overrides.ts +154 -0
- package/src/scripts/_dispatch.bash +17 -0
- package/src/scripts/_lib/as_of.ts +412 -0
- package/src/scripts/_lib/exec_evidence.ts +7 -0
- package/src/scripts/_lib/hook_settings.ts +33 -0
- package/src/scripts/_lib/host_listing_model.ts +192 -0
- package/src/scripts/_lib/lean_projection_mode.ts +44 -0
- package/src/scripts/_lib/mcp_bridge.ts +199 -0
- package/src/scripts/_lib/review_independence.ts +62 -10
- package/src/scripts/_lib/rule_injection.ts +239 -0
- package/src/scripts/_lib/run_checkpoint.ts +54 -1
- package/src/scripts/_lib/scoped_projection.ts +96 -0
- package/src/scripts/_lib/session_register.ts +44 -2
- package/src/scripts/_lib/skill_catalogue.ts +38 -2
- package/src/scripts/_lib/transcript_reads.ts +207 -0
- package/src/scripts/_lib/ui_authority.test.ts +251 -0
- package/src/scripts/_lib/ui_authority.ts +343 -0
- package/src/scripts/ai-video/adapters/fal.sh +8 -3
- package/src/scripts/ai-video/adapters/gemini-veo.sh +10 -0
- package/src/scripts/ai-video/adapters/higgsfield.sh +10 -2
- package/src/scripts/ai-video/adapters/kling.sh +10 -0
- package/src/scripts/ai-video/adapters/sora.sh +10 -0
- package/src/scripts/ai-video/lib/calibrate-cost.sh +145 -0
- package/src/scripts/ai-video/lib/model-capabilities/README.md +53 -7
- package/src/scripts/ai-video/lib/model-capabilities/comfyui.json +15 -3
- package/src/scripts/ai-video/lib/model-capabilities/fal.json +36 -6
- package/src/scripts/ai-video/lib/model-capabilities/gemini-veo.json +23 -0
- package/src/scripts/ai-video/lib/model-capabilities/higgsfield.json +23 -0
- package/src/scripts/ai-video/lib/model-capabilities/kling.json +23 -0
- package/src/scripts/ai-video/lib/model-capabilities/musetalk.json +8 -2
- package/src/scripts/ai-video/lib/model-capabilities/replicate.json +36 -6
- package/src/scripts/ai-video/lib/model-capabilities/sora.json +45 -0
- package/src/scripts/ai-video/lib/model-capabilities/syncso.json +8 -2
- package/src/scripts/ai-video/lib/parse-blueprint.sh +52 -5
- package/src/scripts/ai-video/lib/resume-scan.sh +92 -3
- package/src/scripts/ai-video/lib/seam-plan.sh +212 -0
- package/src/scripts/ai-video/smoke-trace.sh +450 -2
- package/src/scripts/ai-video/stitch.sh +191 -10
- package/src/scripts/ai-video/test-pipeline.sh +84 -6
- package/src/scripts/ai_council/cli_agency_bounds.ts +139 -0
- package/src/scripts/ai_council/cli_least_agency_canary.ts +347 -0
- package/src/scripts/ai_council/clients.ts +3 -2
- package/src/scripts/ai_council/consensus.ts +63 -6
- package/src/scripts/ai_council/events_log.ts +46 -1
- package/src/scripts/ai_council/orchestrator.ts +103 -108
- package/src/scripts/ai_council/orchestrator_results.ts +166 -0
- package/src/scripts/ai_council/prompts.ts +12 -5
- package/src/scripts/ai_council/quorum.ts +82 -1
- package/src/scripts/ai_council/quorum_wiring.ts +82 -5
- package/src/scripts/ai_council/seating.ts +211 -0
- package/src/scripts/ai_council/stance_tally.ts +22 -0
- package/src/scripts/bench_hook_latency.ts +62 -0
- package/src/scripts/build_proof.ts +12 -1
- package/src/scripts/capture_skill_catalogue.ts +21 -0
- package/src/scripts/check_always_budget.ts +2 -1
- package/src/scripts/check_augmentignore.ts +2 -1
- package/src/scripts/check_beta_review_markers.ts +2 -1
- package/src/scripts/check_composite_arming.ts +364 -0
- package/src/scripts/check_corpus_staleness.ts +2 -1
- package/src/scripts/check_council_pin_staleness.ts +3 -1
- package/src/scripts/check_enforcement_coverage.ts +116 -3
- package/src/scripts/check_enforcement_denominator.ts +365 -0
- package/src/scripts/check_gate_coverage.ts +2 -1
- package/src/scripts/check_hook_bundle_freshness.ts +13 -1
- package/src/scripts/check_knowledge_cards.ts +2 -1
- package/src/scripts/check_knowledge_pages.ts +3 -2
- package/src/scripts/check_memory.ts +2 -1
- package/src/scripts/check_no_automerge_key.ts +287 -0
- package/src/scripts/check_pack_conformance_fixture.ts +565 -0
- package/src/scripts/check_pack_passport_reconciliation.ts +274 -0
- package/src/scripts/check_proposal.ts +2 -1
- package/src/scripts/check_reach_staleness.ts +2 -1
- package/src/scripts/check_release_adjacent_health.ts +2 -1
- package/src/scripts/check_release_pr_shape.ts +5 -0
- package/src/scripts/check_review_schema.ts +34 -1
- package/src/scripts/check_roadmap_trackable.ts +48 -3
- package/src/scripts/check_source_size_budget.ts +2 -1
- package/src/scripts/check_standing_payload_delta.ts +505 -0
- package/src/scripts/check_trigger_evals.ts +2 -1
- package/src/scripts/classify_change_risk.ts +281 -0
- package/src/scripts/compute_skill_tiers.ts +186 -0
- package/src/scripts/condense.ts +8 -13
- package/src/scripts/council_attendance_metrics.ts +183 -0
- package/src/scripts/council_cli.ts +10 -8
- package/src/scripts/council_parse_rate.ts +116 -0
- package/src/scripts/derive_playbooks.ts +406 -0
- package/src/scripts/design_slop_rules.test.ts +7 -0
- package/src/scripts/design_slop_rules.ts +56 -2
- package/src/scripts/dispatch_r2_reviewer.ts +16 -0
- package/src/scripts/frontend_corpus_hash.ts +116 -0
- package/src/scripts/generate_pack_manifests.ts +78 -0
- package/src/scripts/grade_target_readiness.ts +478 -0
- package/src/scripts/hook_manifest.json +1 -1
- package/src/scripts/hook_manifest.yaml +97 -16
- package/src/scripts/hooks/concern_registry.ts +4 -0
- package/src/scripts/hooks/design_pass_hook.ts +356 -0
- package/src/scripts/hooks/rtk_wrap_hook.ts +30 -7
- package/src/scripts/hooks/rule_inject_hook.ts +318 -0
- package/src/scripts/hot_context_hook.ts +74 -7
- package/src/scripts/install.ts +40 -89
- package/src/scripts/lint_adapter_tier.ts +663 -0
- package/src/scripts/lint_archived_skills.ts +93 -0
- package/src/scripts/lint_budget_ownership.ts +2 -1
- package/src/scripts/lint_deterministic_time.ts +470 -0
- package/src/scripts/lint_framework_leakage.ts +5 -0
- package/src/scripts/lint_handoffs.ts +525 -1
- package/src/scripts/lint_judge_prompt_expectation.ts +155 -0
- package/src/scripts/lint_marketplace.ts +88 -0
- package/src/scripts/lint_media_policy_linkage.ts +140 -1
- package/src/scripts/lint_one_off_age.ts +6 -1
- package/src/scripts/lint_override_kernel_guard.ts +87 -5
- package/src/scripts/lint_roadmap_complexity.ts +56 -0
- package/src/scripts/lint_rule_enforcement_declaration.ts +24 -7
- package/src/scripts/lint_rule_norm_pin.ts +321 -0
- package/src/scripts/lint_spawn_payload.ts +42 -5
- package/src/scripts/lint_symptom_intake.ts +2 -1
- package/src/scripts/mcp_parity_smoke.ts +30 -4
- package/src/scripts/mcp_render.ts +66 -1
- package/src/scripts/mcp_tool_fingerprint.ts +241 -0
- package/src/scripts/measure_risk_class_drift.ts +140 -0
- package/src/scripts/measure_skill_ranker_baseline.ts +212 -0
- package/src/scripts/media/lib/adapter-common.sh +211 -1
- package/src/scripts/media/lib/adapter-contract.md +74 -6
- package/src/scripts/model_rule_injection.ts +907 -0
- package/src/scripts/project_thin_rules.ts +45 -2
- package/src/scripts/release.ts +66 -860
- package/src/scripts/release_drill.ts +59 -3
- package/src/scripts/release_env.ts +298 -0
- package/src/scripts/release_publication.ts +720 -0
- package/src/scripts/roadmap_context.ts +778 -0
- package/src/scripts/schemas/fidelity-measurement-sheet.schema.json +169 -0
- package/src/scripts/schemas/pack.schema.json +62 -4
- package/src/scripts/schemas/rule.schema.json +24 -2
- package/src/scripts/schemas/skill.schema.json +41 -2
- package/src/scripts/schemas/ui-authority.schema.json +114 -0
- package/src/scripts/session_register_hook.ts +29 -3
- package/src/scripts/sessions_cli.ts +67 -3
- package/src/scripts/skill_tools/score_skill_relevance.ts +36 -53
- package/src/scripts/tighten_skill_descriptions.ts +264 -0
- package/src/scripts/token_sink_report.ts +239 -0
- package/src/scripts/trigger_coverage.ts +122 -3
- package/src/scripts/update_counts.ts +7 -3
- package/src/scripts/validate_frontmatter.ts +66 -0
- package/src/server/schemas/settings.ts +5 -0
- package/src/shared/skillRanking.ts +183 -0
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
/**
|
|
3
|
+
* Replay the four registered council attendance metrics over an events log.
|
|
4
|
+
*
|
|
5
|
+
* Step 3.2 of `road-to-council-evidence-integrity`. The metrics were registered
|
|
6
|
+
* in `src/config/quorum-attendance-budget.json` on 2026-08-10 and nothing in the
|
|
7
|
+
* tree ever computed them, so "the four registered metrics reproduce unchanged
|
|
8
|
+
* across the schema bump" was a claim with no instrument. This is the instrument.
|
|
9
|
+
*
|
|
10
|
+
* ## The exclusion rule, which is the whole point of the schema version
|
|
11
|
+
*
|
|
12
|
+
* `stance_agreement` arrived at schema v5. A line written at v4 or earlier does
|
|
13
|
+
* not carry the field and NO honest value can be inferred for it — a v4 pass may
|
|
14
|
+
* have had a stance tally whose verdict was never recorded, or none at all, and
|
|
15
|
+
* the line cannot tell you which. So the agreement rate's denominator is
|
|
16
|
+
* v5-and-later lines ONLY, and this reports the excluded count next to the rate
|
|
17
|
+
* rather than folding it in. Defaulting the missing field to `not_tallied` would
|
|
18
|
+
* manufacture a measurement out of an absence, which is the defect class this
|
|
19
|
+
* whole roadmap exists to close.
|
|
20
|
+
*
|
|
21
|
+
* The four pre-existing metrics are computed over their own documented
|
|
22
|
+
* populations, unchanged by the bump: they read fields that exist at every
|
|
23
|
+
* version they were registered against.
|
|
24
|
+
*
|
|
25
|
+
* ## Scope, stated rather than discovered later
|
|
26
|
+
*
|
|
27
|
+
* `agents/runtime/council/events.log` is gitignored and machine-local, so every
|
|
28
|
+
* reading is one machine's traffic and no rate from it generalises. A rate
|
|
29
|
+
* printed here describes the log it was given and nothing else.
|
|
30
|
+
*/
|
|
31
|
+
import * as fs from 'node:fs';
|
|
32
|
+
import * as path from 'node:path';
|
|
33
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
34
|
+
|
|
35
|
+
/** The version at which `stance_agreement` began to be written. */
|
|
36
|
+
export const STANCE_AGREEMENT_SINCE = 5;
|
|
37
|
+
|
|
38
|
+
type Line = Record<string, unknown>;
|
|
39
|
+
|
|
40
|
+
export interface AttendanceMetrics {
|
|
41
|
+
/** post_run, command=run lines — the population every rate below is scoped to. */
|
|
42
|
+
readonly passes: number;
|
|
43
|
+
/** present / total, summed over passes. `null` when there are none. */
|
|
44
|
+
readonly attendance_rate: number | null;
|
|
45
|
+
/** share of passes with total < configured_total. */
|
|
46
|
+
readonly roster_shortfall_rate: number | null;
|
|
47
|
+
/** share of passes with `solo: true`. */
|
|
48
|
+
readonly solo_conclusion_rate: number | null;
|
|
49
|
+
/** share of passes with `floor_would_hold: true`. */
|
|
50
|
+
readonly shadow_floor_fire_rate: number | null;
|
|
51
|
+
/** count per `absent[].reason`. */
|
|
52
|
+
readonly absent_reason_distribution: Record<string, number>;
|
|
53
|
+
/**
|
|
54
|
+
* Share of AGREEMENT-ELIGIBLE passes that reached consensus. The denominator
|
|
55
|
+
* is `agreement_eligible`, never `passes` — see the module header.
|
|
56
|
+
*/
|
|
57
|
+
readonly consensus_rate: number | null;
|
|
58
|
+
/** Passes at schema >= STANCE_AGREEMENT_SINCE. The agreement denominator. */
|
|
59
|
+
readonly agreement_eligible: number;
|
|
60
|
+
/** Passes excluded from the agreement rate because their schema predates the field. */
|
|
61
|
+
readonly agreement_excluded: number;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function parseLog(text: string): Line[] {
|
|
65
|
+
const out: Line[] = [];
|
|
66
|
+
for (const raw of text.split('\n')) {
|
|
67
|
+
const line = raw.trim();
|
|
68
|
+
if (line === '') continue;
|
|
69
|
+
try {
|
|
70
|
+
const rec = JSON.parse(line) as unknown;
|
|
71
|
+
if (rec !== null && typeof rec === 'object' && !Array.isArray(rec)) {
|
|
72
|
+
out.push(rec as Line);
|
|
73
|
+
}
|
|
74
|
+
} catch {
|
|
75
|
+
// A malformed line is skipped, never guessed at. It is counted
|
|
76
|
+
// nowhere, which is the honest treatment: it is not a pass that
|
|
77
|
+
// happened one way, it is a line nobody can read.
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return out;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function computeMetrics(lines: readonly Line[]): AttendanceMetrics {
|
|
84
|
+
// The documented population: post_run proves providers were actually
|
|
85
|
+
// called; `command: run` excludes the spend-free estimate preview.
|
|
86
|
+
const passes = lines.filter(
|
|
87
|
+
(l) => l['action'] === 'quorum_result' && l['phase'] === 'post_run' && l['command'] === 'run',
|
|
88
|
+
);
|
|
89
|
+
const n = passes.length;
|
|
90
|
+
const num = (v: unknown): number => (typeof v === 'number' && Number.isFinite(v) ? v : 0);
|
|
91
|
+
const share = (pred: (l: Line) => boolean): number | null =>
|
|
92
|
+
n === 0 ? null : passes.filter(pred).length / n;
|
|
93
|
+
|
|
94
|
+
const attendance_rate =
|
|
95
|
+
n === 0
|
|
96
|
+
? null
|
|
97
|
+
: passes.reduce((acc, l) => {
|
|
98
|
+
const total = num(l['total']);
|
|
99
|
+
return acc + (total === 0 ? 0 : num(l['present']) / total);
|
|
100
|
+
}, 0) / n;
|
|
101
|
+
|
|
102
|
+
const absent_reason_distribution: Record<string, number> = {};
|
|
103
|
+
for (const l of passes) {
|
|
104
|
+
const absent = l['absent'];
|
|
105
|
+
if (!Array.isArray(absent)) continue;
|
|
106
|
+
for (const a of absent) {
|
|
107
|
+
if (a === null || typeof a !== 'object') continue;
|
|
108
|
+
const reason = String((a as Line)['reason'] ?? 'unavailable');
|
|
109
|
+
absent_reason_distribution[reason] = (absent_reason_distribution[reason] ?? 0) + 1;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// The exclusion, applied on the SCHEMA VERSION rather than on the presence
|
|
114
|
+
// of the key. A v5 line whose field is somehow absent is a defect worth
|
|
115
|
+
// seeing; keying on presence would silently reclassify it as old data.
|
|
116
|
+
const eligible = passes.filter((l) => num(l['schema_version']) >= STANCE_AGREEMENT_SINCE);
|
|
117
|
+
const consensus_rate =
|
|
118
|
+
eligible.length === 0 ? null : eligible.filter((l) => l['stance_agreement'] === 'consensus').length / eligible.length;
|
|
119
|
+
|
|
120
|
+
return {
|
|
121
|
+
passes: n,
|
|
122
|
+
attendance_rate,
|
|
123
|
+
roster_shortfall_rate: share((l) => num(l['total']) < num(l['configured_total'])),
|
|
124
|
+
solo_conclusion_rate: share((l) => l['solo'] === true),
|
|
125
|
+
shadow_floor_fire_rate: share((l) => l['floor_would_hold'] === true),
|
|
126
|
+
absent_reason_distribution,
|
|
127
|
+
consensus_rate,
|
|
128
|
+
agreement_eligible: eligible.length,
|
|
129
|
+
agreement_excluded: n - eligible.length,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function repoRoot(): string {
|
|
134
|
+
return path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..');
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export function main(argv: string[]): number {
|
|
138
|
+
const asJson = argv.includes('--json');
|
|
139
|
+
const pathArg = argv.find((a) => !a.startsWith('--'));
|
|
140
|
+
const logPath = pathArg ?? path.join(repoRoot(), 'agents/runtime/council/events.log');
|
|
141
|
+
if (!fs.existsSync(logPath)) {
|
|
142
|
+
process.stderr.write(
|
|
143
|
+
`council_attendance_metrics: no log at ${logPath}\n` +
|
|
144
|
+
' This is an honest null, not a failure: the log is gitignored and\n' +
|
|
145
|
+
' machine-local, so a fresh checkout legitimately has none.\n',
|
|
146
|
+
);
|
|
147
|
+
return 0;
|
|
148
|
+
}
|
|
149
|
+
const m = computeMetrics(parseLog(fs.readFileSync(logPath, 'utf8')));
|
|
150
|
+
if (asJson) {
|
|
151
|
+
process.stdout.write(`${JSON.stringify(m, null, 2)}\n`);
|
|
152
|
+
return 0;
|
|
153
|
+
}
|
|
154
|
+
const pct = (v: number | null): string => (v === null ? 'n/a (no passes)' : `${(v * 100).toFixed(1)}%`);
|
|
155
|
+
process.stdout.write(`council attendance metrics · ${logPath}\n`);
|
|
156
|
+
process.stdout.write(` (machine-local log — this describes THIS log, and generalises to nothing)\n\n`);
|
|
157
|
+
process.stdout.write(` post_run/command=run passes ${String(m.passes)}\n`);
|
|
158
|
+
process.stdout.write(` attendance_rate ${pct(m.attendance_rate)}\n`);
|
|
159
|
+
process.stdout.write(` roster_shortfall_rate ${pct(m.roster_shortfall_rate)}\n`);
|
|
160
|
+
process.stdout.write(` solo_conclusion_rate ${pct(m.solo_conclusion_rate)}\n`);
|
|
161
|
+
process.stdout.write(` shadow_floor_fire_rate ${pct(m.shadow_floor_fire_rate)}\n`);
|
|
162
|
+
process.stdout.write(
|
|
163
|
+
` consensus_rate ${pct(m.consensus_rate)} (denominator ${String(m.agreement_eligible)} v${String(STANCE_AGREEMENT_SINCE)}+ lines; ${String(m.agreement_excluded)} older lines EXCLUDED, not defaulted)\n`,
|
|
164
|
+
);
|
|
165
|
+
const dist = Object.entries(m.absent_reason_distribution).sort(([a], [b]) => a.localeCompare(b));
|
|
166
|
+
process.stdout.write(` absent_reason_distribution ${dist.length === 0 ? '(none)' : dist.map(([k, v]) => `${k}=${String(v)}`).join(' · ')}\n`);
|
|
167
|
+
return 0;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (process.argv[1] !== undefined) {
|
|
171
|
+
try {
|
|
172
|
+
const here = fs.realpathSync(fileURLToPath(import.meta.url));
|
|
173
|
+
const argv1 = fs.realpathSync(path.resolve(process.argv[1]));
|
|
174
|
+
if (here === argv1) {
|
|
175
|
+
process.exitCode = main(process.argv.slice(2));
|
|
176
|
+
}
|
|
177
|
+
} catch {
|
|
178
|
+
const argvUrl = pathToFileURL(path.resolve(process.argv[1])).href;
|
|
179
|
+
if (import.meta.url === argvUrl) {
|
|
180
|
+
process.exitCode = main(process.argv.slice(2));
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
@@ -82,8 +82,10 @@ import { classifyCliFailure, type AbsentReason } from './ai_council/transport_re
|
|
|
82
82
|
import { evaluateQuorum, type QuorumResult } from './ai_council/quorum.js';
|
|
83
83
|
import {
|
|
84
84
|
_emitQuorumEvent,
|
|
85
|
+
annotateRenderedQuorum,
|
|
85
86
|
_format_quorum_line,
|
|
86
87
|
_postRunQuorum,
|
|
88
|
+
stanceAgreementOf,
|
|
87
89
|
_quorum_min_present_from,
|
|
88
90
|
_quorum_setting_from,
|
|
89
91
|
} from './ai_council/quorum_wiring.js';
|
|
@@ -165,7 +167,7 @@ import {
|
|
|
165
167
|
render_deanonymization_block,
|
|
166
168
|
with_chairman_fields,
|
|
167
169
|
} from './ai_council/blind_review.js';
|
|
168
|
-
import {
|
|
170
|
+
import { tallyFromResponses } from './ai_council/stance_tally.js';
|
|
169
171
|
import { buildHandoffFromStanceTally, type HandoffEnvelope } from './ai_council/handoff.js';
|
|
170
172
|
|
|
171
173
|
// ── argparse-style exit plumbing ────────────────────────────────────
|
|
@@ -2657,6 +2659,9 @@ function cmd_run(
|
|
|
2657
2659
|
// with 3 configured members where 2 fail to construct and 1 answers emits
|
|
2658
2660
|
// `{total: 1, present: 1}` and reads as full attendance.
|
|
2659
2661
|
const configured_total = quorum_out.result?.total ?? null;
|
|
2662
|
+
// Hoisted above the post-run emit so agreement rides the same line as attendance.
|
|
2663
|
+
const stance_tally_result = tallyFromResponses(responses, stance_tally_on);
|
|
2664
|
+
const stance_agreement = stanceAgreementOf(stance_tally_result);
|
|
2660
2665
|
const post_run = _postRunQuorum(members, responses, ai_cfg);
|
|
2661
2666
|
quorum_out.result = post_run.quorum;
|
|
2662
2667
|
skipped.push(...post_run.absent);
|
|
@@ -2667,6 +2672,7 @@ function cmd_run(
|
|
|
2667
2672
|
// skips already went out under `phase: 'pre_run'` from `build_members`,
|
|
2668
2673
|
// and merging them here would double-count a member absent in both.
|
|
2669
2674
|
_emitQuorumEvent('post_run', post_run.quorum, post_run.absent, {
|
|
2675
|
+
...(stance_agreement === undefined ? {} : { stanceAgreement: stance_agreement }),
|
|
2670
2676
|
command: 'run',
|
|
2671
2677
|
// Whether the roster actually shrank — see `dispatch_shape`. Without
|
|
2672
2678
|
// this the line is byte-identical to a configured one-member council,
|
|
@@ -2698,13 +2704,7 @@ function cmd_run(
|
|
|
2698
2704
|
// the payload in the first place). `buildHandoffFromStanceTally` returns
|
|
2699
2705
|
// the honest all-null envelope when stance tally never ran or split, so
|
|
2700
2706
|
// this is always additive, never a fabricated decision.
|
|
2701
|
-
const handoff: HandoffEnvelope = buildHandoffFromStanceTally(
|
|
2702
|
-
stance_tally_on
|
|
2703
|
-
? tally_stances(
|
|
2704
|
-
responses.filter((r) => !r.error).map((r) => ({ member: `${r.provider}:${r.model}`, text: r.text })),
|
|
2705
|
-
)
|
|
2706
|
-
: null,
|
|
2707
|
-
);
|
|
2707
|
+
const handoff: HandoffEnvelope = buildHandoffFromStanceTally(stance_tally_result);
|
|
2708
2708
|
const persona_labels = build_persona_labels(advisor_plans, billable);
|
|
2709
2709
|
const peer_review = _maybe_run_peer_review(
|
|
2710
2710
|
ai_cfg,
|
|
@@ -2718,6 +2718,8 @@ function cmd_run(
|
|
|
2718
2718
|
{ persona_labels },
|
|
2719
2719
|
);
|
|
2720
2720
|
const consensus = _maybe_run_consensus(ai_cfg, question, members, responses, budget, table, project, args);
|
|
2721
|
+
// Rendered attendance, re-derived after the parser. The event does not move.
|
|
2722
|
+
quorum_out.result = annotateRenderedQuorum(quorum_out.result, consensus?.parse_outcomes);
|
|
2721
2723
|
const chairman = _maybe_run_chairman(
|
|
2722
2724
|
ai_cfg,
|
|
2723
2725
|
question,
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
/**
|
|
3
|
+
* Findings-parse outcome rates over the recorded fixture corpus.
|
|
4
|
+
*
|
|
5
|
+
* Step 2.4 of `road-to-council-evidence-integrity`. Phase 2 made the three
|
|
6
|
+
* outcomes distinguishable (`parsed` / `empty` / `parse_failed`); this makes the
|
|
7
|
+
* distinction *measurable*, over a population a reader can open.
|
|
8
|
+
*
|
|
9
|
+
* ## What the denominator is, and what it is not
|
|
10
|
+
*
|
|
11
|
+
* The denominator is `tests/fixtures/council-parse-corpus/` — recorded verbatim
|
|
12
|
+
* member answers, one per file. It is **not live traffic**, and no number this
|
|
13
|
+
* script prints may be quoted as if it were. The corpus was assembled to cover
|
|
14
|
+
* the distinct failure SHAPES, so it over-represents them by construction: two
|
|
15
|
+
* of seven answers are unparseable here because there are two unparseable
|
|
16
|
+
* shapes, not because two in seven real answers fail.
|
|
17
|
+
*
|
|
18
|
+
* Saying that in the same breath as the number is the whole point. A
|
|
19
|
+
* `parse_empty_rate` with an unstated denominator is exactly the "looks more
|
|
20
|
+
* settled than the run was" defect this roadmap exists to close, one layer up.
|
|
21
|
+
*
|
|
22
|
+
* ## Why it also acts as a gate
|
|
23
|
+
*
|
|
24
|
+
* `expected.json` pins the outcome per fixture, so a change to the extractor
|
|
25
|
+
* that silently reclassifies a recorded answer fails here rather than being
|
|
26
|
+
* discovered by a paid re-ask in production. Exit 1 on any drift.
|
|
27
|
+
*/
|
|
28
|
+
import * as fs from 'node:fs';
|
|
29
|
+
import * as path from 'node:path';
|
|
30
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
31
|
+
|
|
32
|
+
import { parse_findings_outcome, type FindingsParseOutcome } from './ai_council/consensus.js';
|
|
33
|
+
|
|
34
|
+
const CORPUS_REL = 'tests/fixtures/council-parse-corpus';
|
|
35
|
+
|
|
36
|
+
function repoRoot(): string {
|
|
37
|
+
return path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
interface Row {
|
|
41
|
+
readonly file: string;
|
|
42
|
+
readonly outcome: FindingsParseOutcome;
|
|
43
|
+
readonly findings: number;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function scoreCorpus(dir: string): Row[] {
|
|
47
|
+
const files = fs
|
|
48
|
+
.readdirSync(dir)
|
|
49
|
+
.filter((f) => f.endsWith('.txt'))
|
|
50
|
+
.sort();
|
|
51
|
+
return files.map((f) => {
|
|
52
|
+
const text = fs.readFileSync(path.join(dir, f), 'utf8');
|
|
53
|
+
const ex = parse_findings_outcome(text, { source: `fixture:${f}` });
|
|
54
|
+
return { file: f, outcome: ex.outcome, findings: ex.findings.length };
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function main(argv: string[]): number {
|
|
59
|
+
const asJson = argv.includes('--json');
|
|
60
|
+
const dir = path.join(repoRoot(), CORPUS_REL);
|
|
61
|
+
if (!fs.existsSync(dir)) {
|
|
62
|
+
process.stderr.write(`council_parse_rate: corpus not found at ${CORPUS_REL}\n`);
|
|
63
|
+
return 1;
|
|
64
|
+
}
|
|
65
|
+
const rows = scoreCorpus(dir);
|
|
66
|
+
const total = rows.length;
|
|
67
|
+
const count = (o: FindingsParseOutcome): number => rows.filter((r) => r.outcome === o).length;
|
|
68
|
+
const failed = count('parse_failed');
|
|
69
|
+
const empty = count('empty');
|
|
70
|
+
const parsed = count('parsed');
|
|
71
|
+
|
|
72
|
+
const expectedPath = path.join(dir, 'expected.json');
|
|
73
|
+
let drift: string[] = [];
|
|
74
|
+
if (fs.existsSync(expectedPath)) {
|
|
75
|
+
const expected = JSON.parse(fs.readFileSync(expectedPath, 'utf8')) as Record<string, string>;
|
|
76
|
+
drift = rows
|
|
77
|
+
.filter((r) => expected[r.file] !== undefined && expected[r.file] !== r.outcome)
|
|
78
|
+
.map((r) => `${r.file}: expected ${String(expected[r.file])}, got ${r.outcome}`);
|
|
79
|
+
const missing = rows.filter((r) => expected[r.file] === undefined).map((r) => `${r.file}: not pinned in expected.json`);
|
|
80
|
+
drift = [...drift, ...missing];
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (asJson) {
|
|
84
|
+
process.stdout.write(
|
|
85
|
+
`${JSON.stringify({ denominator: CORPUS_REL, total, parsed, empty, parse_failed: failed, rows, drift }, null, 2)}\n`,
|
|
86
|
+
);
|
|
87
|
+
} else {
|
|
88
|
+
process.stdout.write(`council parse outcomes · denominator: ${CORPUS_REL} (${String(total)} recorded answers, NOT live traffic)\n\n`);
|
|
89
|
+
for (const r of rows) {
|
|
90
|
+
process.stdout.write(` ${r.outcome.padEnd(13)} ${r.file} (${String(r.findings)} finding(s))\n`);
|
|
91
|
+
}
|
|
92
|
+
const pct = (n: number): string => (total === 0 ? 'n/a' : `${((n / total) * 100).toFixed(1)}%`);
|
|
93
|
+
process.stdout.write(`\n parse_failed_rate ${String(failed)}/${String(total)} ${pct(failed)}\n`);
|
|
94
|
+
process.stdout.write(` parse_empty_rate ${String(empty)}/${String(total)} ${pct(empty)}\n`);
|
|
95
|
+
process.stdout.write(` parsed_rate ${String(parsed)}/${String(total)} ${pct(parsed)}\n`);
|
|
96
|
+
for (const d of drift) {
|
|
97
|
+
process.stderr.write(` DRIFT ${d}\n`);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return drift.length > 0 ? 1 : 0;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (process.argv[1] !== undefined) {
|
|
104
|
+
try {
|
|
105
|
+
const here = fs.realpathSync(fileURLToPath(import.meta.url));
|
|
106
|
+
const argv1 = fs.realpathSync(path.resolve(process.argv[1]));
|
|
107
|
+
if (here === argv1) {
|
|
108
|
+
process.exitCode = main(process.argv.slice(2));
|
|
109
|
+
}
|
|
110
|
+
} catch {
|
|
111
|
+
const argvUrl = pathToFileURL(path.resolve(process.argv[1])).href;
|
|
112
|
+
if (import.meta.url === argvUrl) {
|
|
113
|
+
process.exitCode = main(process.argv.slice(2));
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|