@event4u/agent-config 14.12.0 → 14.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.augment-plugin/marketplace.json +3 -3
- package/.augment-plugin/plugin.json +1 -1
- package/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +234 -0
- package/CONTRIBUTING.md +38 -0
- package/CREDITS.md +135 -0
- package/NOTICE +13 -0
- package/README.md +8 -6
- package/dist/agent-src/commands/analyze/inbox.md +109 -2
- package/dist/agent-src/commands/feature/dev.md +7 -2
- package/dist/agent-src/commands/ghostwriter/write.md +5 -1
- package/dist/agent-src/commands/implement-ticket.md +1 -1
- package/dist/agent-src/commands/mission/upgrade.md +1 -1
- package/dist/agent-src/commands/orchestrate.md +2 -2
- package/dist/agent-src/commands/post-as/me.md +5 -1
- package/dist/agent-src/commands/pr/merge.md +19 -6
- package/dist/agent-src/commands/roadmap/process-full.md +19 -5
- package/dist/agent-src/commands/tdd/red.md +12 -2
- package/dist/agent-src/commands/work.md +1 -1
- package/dist/agent-src/contexts/communication/rules-auto/token-efficiency-mechanics.md +40 -0
- package/dist/agent-src/contexts/execution/auto-dispatch-classification.md +5 -2
- package/dist/agent-src/contexts/execution/autonomy-mechanics.md +21 -0
- package/dist/agent-src/contexts/execution/orchestration-telemetry.md +1 -0
- package/dist/agent-src/contexts/execution/subagent-response-contract.md +40 -0
- package/dist/agent-src/contexts/execution/subagent-steering.md +13 -1
- package/dist/agent-src/contexts/execution/terminal-states.md +96 -0
- package/dist/agent-src/rules/artifact-drafting-protocol.md +1 -1
- package/dist/agent-src/rules/broken-access-control.md +4 -0
- package/dist/agent-src/rules/code-provenance.md +4 -0
- package/dist/agent-src/rules/design-fidelity.md +1 -1
- package/dist/agent-src/rules/domain-safety-pii.md +4 -0
- package/dist/agent-src/rules/domain-safety-retention.md +4 -0
- package/dist/agent-src/rules/engineering-safety-floor.md +2 -0
- package/dist/agent-src/rules/external-code-graph-interop.md +14 -12
- package/dist/agent-src/rules/improve-before-implement.md +6 -8
- package/dist/agent-src/rules/laravel-routing.md +1 -1
- package/dist/agent-src/rules/lethal-trifecta-guard.md +4 -0
- package/dist/agent-src/rules/secret-vcs-guard.md +2 -0
- package/dist/agent-src/rules/security-sensitive-stop.md +2 -0
- package/dist/agent-src/rules/source-confidentiality.md +12 -34
- package/dist/agent-src/rules/symfony-routing.md +1 -1
- package/dist/agent-src/rules/token-efficiency.md +14 -0
- package/dist/agent-src/rules/tool-safety.md +4 -0
- package/dist/agent-src/rules/untrusted-input-defense.md +4 -0
- package/dist/agent-src/scripts/archive_completed_roadmaps.ts +247 -3
- package/dist/agent-src/scripts/guarded_baseline.ts +328 -0
- package/dist/agent-src/scripts/roadmap_set_step.ts +253 -0
- package/dist/agent-src/scripts/stub_queue.ts +82 -0
- package/dist/agent-src/scripts/stubs_due.ts +400 -0
- package/dist/agent-src/scripts/ticket_bundles.ts +84 -0
- package/dist/agent-src/scripts/update_roadmap_progress.ts +8 -4
- package/dist/agent-src/skills/brand-asset-generation/SKILL.md +17 -4
- package/dist/agent-src/skills/brand-audit/SKILL.md +33 -0
- package/dist/agent-src/skills/code-intelligence/SKILL.md +57 -0
- package/dist/agent-src/skills/database/SKILL.md +8 -0
- package/dist/agent-src/skills/dependency-upgrade/SKILL.md +27 -0
- package/dist/agent-src/skills/design-review/SKILL.md +1 -1
- package/dist/agent-src/skills/doc-coauthoring/SKILL.md +1 -1
- package/dist/agent-src/skills/existing-ui-audit/SKILL.md +17 -1
- package/dist/agent-src/skills/feature-planning/SKILL.md +9 -2
- package/dist/agent-src/skills/frontend-render-security/SKILL.md +44 -0
- package/dist/agent-src/skills/git-workflow/SKILL.md +1 -1
- package/dist/agent-src/skills/js-library-packaging/scripts/check_package_surface.ts +38 -4
- package/dist/agent-src/skills/judge-artifact-completeness/rubrics/ticket-quality-score.json +2 -2
- package/dist/agent-src/skills/laravel/SKILL.md +35 -0
- package/dist/agent-src/skills/laravel-migration/SKILL.md +57 -3
- package/dist/agent-src/skills/monorepo-workspace/SKILL.md +26 -0
- package/dist/agent-src/skills/playbook-authoring/SKILL.md +28 -1
- package/dist/agent-src/skills/react-shadcn-ui/SKILL.md +1 -1
- package/dist/agent-src/skills/skill-writing/references/procedure.md +5 -5
- package/dist/agent-src/skills/sql-writing/SKILL.md +7 -1
- package/dist/agent-src/skills/standards-from-config/SKILL.md +27 -4
- package/dist/agent-src/skills/supply-chain-intake/SKILL.md +11 -4
- package/dist/agent-src/skills/symfony-workflow/SKILL.md +35 -0
- package/dist/agent-src/skills/test-case-discovery/SKILL.md +85 -0
- package/dist/agent-src/skills/test-driven-development/SKILL.md +33 -9
- package/dist/agent-src/skills/testing-anti-patterns/SKILL.md +1 -1
- package/dist/agent-src/skills/testing-anti-patterns/process-anti-patterns.md +37 -0
- package/dist/agent-src/skills/ui-component-architect/SKILL.md +45 -2
- package/dist/agent-src/skills/upstream-contribute/SKILL.md +38 -1
- package/dist/agent-src/skills/verify-repair-loop/SKILL.md +9 -4
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/agent-src/templates/roadmaps.md +97 -3
- package/dist/agent-src/templates/scripts/check_memory.ts +258 -17
- package/dist/agent-src/templates/scripts/check_memory_proposal.ts +9 -3
- package/dist/agent-src/templates/scripts/memory_lookup.ts +86 -0
- package/dist/agent-src/templates/scripts/memory_signal.ts +44 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/backend/implement.ts +90 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/backend/index.ts +11 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/backend/test.ts +23 -1
- package/dist/agent-src/templates/scripts/work_engine/directives/backend/verify.ts +10 -1
- package/dist/agent-src/templates/scripts/work_engine/directives/mixed/stitch.ts +5 -1
- package/dist/agent-src/templates/scripts/work_engine/stack/runner.ts +102 -14
- package/dist/cli/commands/uiAudit.js +124 -5
- package/dist/cli/registry.js +2 -0
- package/dist/cli-delegate/{chunk-HYWSRNUX.js → chunk-2DK2VJWG.js} +3 -3
- package/dist/cli-delegate/{chunk-JCW7ZLHK.js → chunk-4FS4WRXP.js} +5 -0
- package/dist/cli-delegate/{chunk-OMIVVCG2.js → chunk-A4QJ6ENT.js} +24 -0
- package/dist/cli-delegate/{chunk-JJA2QEWA.js → chunk-AKJGUQNO.js} +466 -285
- package/dist/cli-delegate/{chunk-E46KPN6K.js → chunk-BTWUYDGN.js} +424 -363
- package/dist/cli-delegate/{chunk-K4FFODTS.js → chunk-ILMUPLGW.js} +1227 -316
- package/dist/cli-delegate/{chunk-FF7WAFMR.js → chunk-KPBWFOPZ.js} +5 -1
- package/dist/cli-delegate/cmd_adr_effective.js +102 -0
- package/dist/cli-delegate/cmd_conformance.js +42 -10
- package/dist/cli-delegate/cmd_doctor.js +3 -3
- package/dist/cli-delegate/cmd_export.js +3 -2
- package/dist/cli-delegate/cmd_fleet.js +2 -2
- package/dist/cli-delegate/cmd_handoff.js +1 -1
- package/dist/cli-delegate/cmd_preflight.js +2 -2
- package/dist/cli-delegate/cmd_prune.js +3 -2
- package/dist/cli-delegate/cmd_settings_get.js +1 -1
- package/dist/cli-delegate/cmd_settings_migrate.js +3 -2
- package/dist/cli-delegate/cmd_settings_set.js +2 -2
- package/dist/cli-delegate/cmd_sync.js +3 -2
- package/dist/cli-delegate/cmd_uninstall.js +3 -2
- package/dist/cli-delegate/cmd_validate.js +3 -2
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +57 -57
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +1 -1
- package/dist/discovery/dormancy-report.md +1 -1
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +2 -2
- package/dist/discovery/trust-report.md +1 -1
- package/dist/discovery/workspaces.json +2 -2
- package/dist/hooks/dispatch.js +1836 -712
- package/dist/install/claudeRuleRewrite.js +254 -0
- package/dist/install/detect.js +29 -16
- package/dist/install/detect_php_shape.js +159 -0
- package/dist/install/install.mjs +634 -428
- package/dist/mcp/awesome-mcp-servers.row.md +1 -1
- package/dist/mcp/mcp-cloudflare-catalogue.json +1 -1
- package/dist/mcp/registry-manifest.json +3 -3
- package/dist/mcp/server.json +3 -3
- package/dist/mcp/server.mjs +4818 -2645
- package/dist/server/schemas/settings.js +3 -0
- package/dist/ui/assets/index-D0jaCRPM.js +29 -0
- package/dist/ui/index.html +1 -1
- package/docs/MIGRATION.md +1 -1
- package/docs/THIRD-PARTY-NOTICES.md +25 -0
- package/docs/contracts/provider-lifecycle.md +1 -1
- package/docs/contracts/settings-classes.md +10 -4
- package/docs/guidelines/agent-infra/5w2h-analysis.md +3 -3
- package/docs/guidelines/agent-infra/agent-interaction-and-decision-quality.md +1 -0
- package/docs/guidelines/agent-infra/artifact-drafting-protocol-mechanics.md +58 -3
- package/docs/guidelines/agent-infra/ask-when-uncertain-demos.md +2 -2
- package/docs/guidelines/agent-infra/asking-and-brevity-examples.md +3 -3
- package/docs/guidelines/agent-infra/break-glass-usage.md +7 -7
- package/docs/guidelines/agent-infra/carve-out-predicates.md +3 -3
- package/docs/guidelines/agent-infra/comparison-matrix.md +1 -1
- package/docs/guidelines/agent-infra/critical-thinking.md +4 -4
- package/docs/guidelines/agent-infra/direct-answers-demos.md +2 -2
- package/docs/guidelines/agent-infra/domain-eval-anti-pattern.md +1 -1
- package/docs/guidelines/agent-infra/engineering-memory-data-format.md +3 -3
- package/docs/guidelines/agent-infra/existence-question-verdicts.md +80 -0
- package/docs/guidelines/agent-infra/first-principles.md +2 -2
- package/docs/guidelines/agent-infra/framework-neutrality-patterns.md +2 -2
- package/docs/guidelines/agent-infra/guarded-baseline.md +39 -0
- package/docs/guidelines/agent-infra/inversion-thinking.md +5 -5
- package/docs/guidelines/agent-infra/language-and-tone-examples.md +1 -1
- package/docs/guidelines/agent-infra/layered-settings.md +10 -10
- package/docs/guidelines/agent-infra/memory-access.md +1 -1
- package/docs/guidelines/agent-infra/mental-models.md +3 -3
- package/docs/guidelines/agent-infra/reuse-verdict-mechanics.md +71 -0
- package/docs/guidelines/agent-infra/review-routing-data-format.md +7 -7
- package/docs/guidelines/agent-infra/roadmap-progress-mechanics.md +13 -7
- package/docs/guidelines/agent-infra/role-contracts.md +2 -2
- package/docs/guidelines/agent-infra/role-mode-router.md +3 -3
- package/docs/guidelines/agent-infra/rule-type-governance.md +2 -2
- package/docs/guidelines/agent-infra/scqa-framework.md +5 -5
- package/docs/guidelines/agent-infra/self-improvement-pipeline.md +6 -6
- package/docs/guidelines/agent-infra/simplicity-and-goal-demos.md +2 -2
- package/docs/guidelines/agent-infra/six-hats.md +3 -3
- package/docs/guidelines/agent-infra/skill-quality-checklist.md +6 -6
- package/docs/guidelines/agent-infra/source-confidentiality-mechanics.md +109 -0
- package/docs/guidelines/agent-infra/systems-thinking.md +1 -1
- package/docs/guidelines/agent-infra/verify-before-complete-demos.md +2 -2
- package/docs/guidelines/augment-portability-patterns.md +6 -4
- package/docs/guidelines/component-oriented-and-oop-development.md +3 -2
- package/docs/guidelines/cross-role-handoff.md +2 -2
- package/docs/guidelines/design-fidelity-mechanics.md +1 -1
- package/docs/guidelines/docs/readme-size-and-splitting.md +3 -3
- package/docs/guidelines/php/database.md +90 -7
- package/docs/guidelines/prompt-templates.md +7 -7
- package/llms.txt +2 -2
- package/package.json +5 -2
- package/src/agent-src/scripts/archive_completed_roadmaps.ts +247 -3
- package/src/agent-src/scripts/guarded_baseline.ts +328 -0
- package/src/agent-src/scripts/roadmap_set_step.ts +253 -0
- package/src/agent-src/scripts/stub_queue.ts +82 -0
- package/src/agent-src/scripts/stubs_due.ts +400 -0
- package/src/agent-src/scripts/ticket_bundles.ts +84 -0
- package/src/agent-src/scripts/update_roadmap_progress.ts +8 -4
- package/src/agent-src/templates/scripts/check_memory.ts +258 -17
- package/src/agent-src/templates/scripts/check_memory_proposal.ts +9 -3
- package/src/agent-src/templates/scripts/memory_lookup.ts +86 -0
- package/src/agent-src/templates/scripts/memory_signal.ts +44 -0
- package/src/agent-src/templates/scripts/work_engine/directives/backend/implement.ts +90 -0
- package/src/agent-src/templates/scripts/work_engine/directives/backend/index.ts +11 -0
- package/src/agent-src/templates/scripts/work_engine/directives/backend/test.ts +23 -1
- package/src/agent-src/templates/scripts/work_engine/directives/backend/verify.ts +10 -1
- package/src/agent-src/templates/scripts/work_engine/directives/mixed/stitch.ts +5 -1
- package/src/agent-src/templates/scripts/work_engine/stack/runner.ts +102 -14
- package/src/config/agent-settings.template.yml +32 -3
- package/src/config/assurance-capability-registry.json +21 -9
- package/src/config/canonical-terms.yml +119 -0
- package/src/config/capability-native-outcome-bars.json +81 -0
- package/src/config/ci-local-parity.yml +80 -0
- package/src/config/drafting-channels.yml +43 -0
- package/src/config/estate-count-budget.json +38 -36
- package/src/config/evaluator-budgets.json +14 -14
- package/src/config/gate-coverage.yml +579 -63
- package/src/config/gate-reachability-exemptions.json +21 -0
- package/src/config/gate-violation-baselines.json +37 -19
- package/src/config/harness-evolution-budget.json +25 -0
- package/src/config/lapsed-beta-baseline.json +96 -0
- package/src/config/memory-twin-verdicts.yml +129 -0
- package/src/config/metric-registry.yml +124 -0
- package/src/config/pack-size-budget.json +16 -15
- package/src/config/preamble-payload-budget.json +8 -8
- package/src/config/profiles/balanced.ini +27 -0
- package/src/config/profiles/full.ini +27 -0
- package/src/config/profiles/minimal.ini +27 -0
- package/src/config/publish-surface.json +9 -2
- package/src/config/routing-coverage-seed.json +16 -2
- package/src/config/rule-stub-ceilings.json +126 -112
- package/src/config/turnaround-budget.json +66 -0
- package/src/install/claudeRuleRewrite.ts +288 -0
- package/src/install/detect.ts +60 -17
- package/src/install/detect_php_shape.ts +191 -0
- package/src/scripts/_cli/cmd_doctor.ts +27 -112
- package/src/scripts/_dispatch.bash +27 -0
- package/src/scripts/_lib/activation_ladder.ts +211 -0
- package/src/scripts/_lib/activation_states.ts +88 -0
- package/src/scripts/_lib/adherence_detectors.ts +143 -0
- package/src/scripts/_lib/arith_claims.ts +181 -0
- package/src/scripts/_lib/arm_ranking.ts +62 -0
- package/src/scripts/_lib/asset_delivery_ledger.ts +303 -0
- package/src/scripts/_lib/audit_field_provenance.ts +54 -0
- package/src/scripts/_lib/auto_dispatch.ts +32 -3
- package/src/scripts/_lib/bench_ab_size_claim.ts +98 -4
- package/src/scripts/_lib/benchmark_cache_fields.ts +158 -0
- package/src/scripts/_lib/candidate_proposer.ts +402 -0
- package/src/scripts/_lib/candidate_record.ts +601 -0
- package/src/scripts/_lib/capture_rate.ts +319 -0
- package/src/scripts/_lib/collector_denominator.ts +771 -0
- package/src/scripts/_lib/collector_record.ts +340 -0
- package/src/scripts/_lib/collector_store.ts +664 -0
- package/src/scripts/_lib/collector_supervision.ts +827 -0
- package/src/scripts/_lib/concern_estate.ts +77 -0
- package/src/scripts/_lib/config_chain.ts +477 -0
- package/src/scripts/_lib/config_cost.ts +209 -0
- package/src/scripts/_lib/council_settings_block.ts +6 -0
- package/src/scripts/_lib/curator_ops.ts +172 -0
- package/src/scripts/_lib/delivery_arm_experiment.ts +266 -0
- package/src/scripts/_lib/delivery_criticality.ts +126 -0
- package/src/scripts/_lib/doctor_runtime_checks.ts +70 -0
- package/src/scripts/_lib/empty_cycles.ts +88 -0
- package/src/scripts/_lib/eval_publication.ts +354 -0
- package/src/scripts/_lib/evaluation_vector.ts +283 -0
- package/src/scripts/_lib/evaluator_promotion.ts +225 -0
- package/src/scripts/_lib/evidence_basis.ts +118 -0
- package/src/scripts/_lib/exec_evidence.ts +8 -0
- package/src/scripts/_lib/experience_card.ts +272 -0
- package/src/scripts/_lib/experience_report.ts +151 -0
- package/src/scripts/_lib/experiment_freeze.ts +112 -0
- package/src/scripts/_lib/generated_by.ts +66 -0
- package/src/scripts/_lib/harness_evolution_guards.ts +229 -0
- package/src/scripts/_lib/hook_effect_probe.ts +141 -0
- package/src/scripts/_lib/host_denominator.ts +687 -0
- package/src/scripts/_lib/host_projection_reach.ts +157 -0
- package/src/scripts/_lib/ignored_blocker.ts +148 -0
- package/src/scripts/_lib/install_reach_checks.ts +495 -0
- package/src/scripts/_lib/json_duplicate_keys.ts +150 -0
- package/src/scripts/_lib/judge_hygiene.ts +228 -0
- package/src/scripts/_lib/legacy_boundary_map.ts +228 -0
- package/src/scripts/_lib/loop_guards.ts +299 -0
- package/src/scripts/_lib/loss_class.ts +129 -0
- package/src/scripts/_lib/machine_wake.ts +51 -0
- package/src/scripts/_lib/md_prose_lines.ts +177 -0
- package/src/scripts/_lib/minimality_tiebreak.ts +168 -0
- package/src/scripts/_lib/one_resolver_invariant.ts +449 -0
- package/src/scripts/_lib/orchestration_record.ts +253 -5
- package/src/scripts/_lib/outcome_envelope.ts +227 -0
- package/src/scripts/_lib/outcome_vocabularies.ts +125 -0
- package/src/scripts/_lib/paired_stats.ts +245 -0
- package/src/scripts/_lib/paired_verdict.ts +226 -0
- package/src/scripts/_lib/prefix_stable_surfaces.ts +123 -0
- package/src/scripts/_lib/privacy_class.ts +47 -0
- package/src/scripts/_lib/regression_neighbourhood.ts +259 -0
- package/src/scripts/_lib/repeated_failure.ts +105 -0
- package/src/scripts/_lib/repo_root.ts +111 -0
- package/src/scripts/_lib/review_skipped_record.ts +37 -0
- package/src/scripts/_lib/role_split.ts +338 -0
- package/src/scripts/_lib/runtime_journal.ts +1499 -0
- package/src/scripts/_lib/runtime_wiring_checks.ts +430 -0
- package/src/scripts/_lib/skill_catalogue.ts +11 -1
- package/src/scripts/_lib/source_digest.ts +200 -0
- package/src/scripts/_lib/source_redact.ts +260 -0
- package/src/scripts/_lib/source_shape.ts +502 -0
- package/src/scripts/_lib/source_snapshot_dedup.ts +199 -0
- package/src/scripts/_lib/strip_comments.d.mts +8 -0
- package/src/scripts/_lib/strip_comments.mjs +65 -0
- package/src/scripts/_lib/test_red_state.ts +154 -0
- package/src/scripts/_lib/trigger_shift.ts +144 -0
- package/src/scripts/_lib/untrusted_content.ts +82 -7
- package/src/scripts/adoption_report.ts +1 -1
- package/src/scripts/adr/evidence_census.ts +1 -1
- package/src/scripts/adr/regenerate_index.ts +26 -2
- package/src/scripts/adr_cite_check.ts +164 -1
- package/src/scripts/ai_council/blind_review.ts +11 -1
- package/src/scripts/ai_council/clients.ts +4 -0
- package/src/scripts/ai_council/config.ts +3 -0
- package/src/scripts/ai_council/consensus.ts +28 -8
- package/src/scripts/ai_council/consensus_round.ts +226 -0
- package/src/scripts/ai_council/disagreement_signal.ts +338 -0
- package/src/scripts/ai_council/inline_findings.ts +340 -0
- package/src/scripts/ai_council/judge_position_bias.ts +197 -0
- package/src/scripts/ai_council/orchestrator.ts +16 -203
- package/src/scripts/ai_council/orchestrator_results.ts +23 -3
- package/src/scripts/ai_council/pricing.ts +106 -0
- package/src/scripts/ai_council/prompts.ts +74 -7
- package/src/scripts/ai_council/provider_leakage_bench.ts +327 -0
- package/src/scripts/ai_council/py_format.ts +14 -3
- package/src/scripts/ai_council/recouncil_guard.ts +293 -0
- package/src/scripts/ai_council/response_record.ts +50 -0
- package/src/scripts/ai_council/topology_bench_manifest.ts +860 -0
- package/src/scripts/ai_council/topology_vocabulary.ts +175 -0
- package/src/scripts/asset_delivery_ledger.ts +157 -0
- package/src/scripts/attest_artifact.ts +193 -0
- package/src/scripts/audit_auto_rules.ts +2 -1
- package/src/scripts/audit_command_surface.ts +1 -1
- package/src/scripts/audit_mcp_tools.ts +2 -2
- package/src/scripts/audit_skill_overlap_allowlist.json +6 -1
- package/src/scripts/audit_user_type_axis.ts +2 -1
- package/src/scripts/bench_ab_clone.ts +215 -10
- package/src/scripts/bench_ab_integrity.ts +119 -5
- package/src/scripts/bench_ab_v2_stats.ts +40 -213
- package/src/scripts/build_archive_index.ts +1 -1
- package/src/scripts/build_linear_digest.ts +1 -1
- package/src/scripts/build_proof.ts +11 -4
- package/src/scripts/build_rule_trigger_matrix.ts +1 -1
- package/src/scripts/build_source_digests.ts +157 -0
- package/src/scripts/cache_realization_report.ts +103 -0
- package/src/scripts/check_adr_frontmatter.ts +126 -0
- package/src/scripts/check_benchmark_report_fields.ts +207 -0
- package/src/scripts/check_beta_review_markers.ts +235 -6
- package/src/scripts/check_bundle_path_leakage.ts +34 -1
- package/src/scripts/check_claims.ts +576 -6
- package/src/scripts/check_composite_arming.ts +35 -0
- package/src/scripts/check_concern_admissions.ts +365 -0
- package/src/scripts/check_enforcement_coverage.ts +28 -0
- package/src/scripts/check_estate_count.ts +142 -1
- package/src/scripts/check_gate_reachability.ts +383 -0
- package/src/scripts/check_host_loadability.ts +104 -0
- package/src/scripts/check_loss_class_declared.ts +308 -0
- package/src/scripts/check_md_language.ts +15 -98
- package/src/scripts/check_memory_proposal.ts +18 -11
- package/src/scripts/check_no_currency_in_cost_surfaces.ts +225 -0
- package/src/scripts/check_no_external_sources.ts +281 -6
- package/src/scripts/check_pack_conformance_fixture.ts +11 -1
- package/src/scripts/check_pack_size.ts +59 -2
- package/src/scripts/check_preamble_payload_budget.ts +114 -3
- package/src/scripts/check_prefix_stable_mutation.ts +372 -0
- package/src/scripts/check_publish_surface.ts +10 -1
- package/src/scripts/check_references.ts +24 -1
- package/src/scripts/check_rule_evidence_declaration.ts +316 -0
- package/src/scripts/check_rule_projection_integrity.ts +14 -4
- package/src/scripts/check_score_contract.ts +26 -3
- package/src/scripts/check_static_parity.ts +285 -0
- package/src/scripts/check_supervision_claim_atomicity.ts +498 -0
- package/src/scripts/check_suppression_hygiene.ts +15 -0
- package/src/scripts/ci_settle.ts +39 -2
- package/src/scripts/code_graph/build.ts +60 -3
- package/src/scripts/code_graph/extract.ts +44 -0
- package/src/scripts/code_graph/types.ts +24 -0
- package/src/scripts/collector_daemon.ts +714 -0
- package/src/scripts/config_cost_report.ts +302 -0
- package/src/scripts/consumer_matrix.ts +74 -1
- package/src/scripts/cost/budget.mjs +10 -3
- package/src/scripts/cost/track.mjs +10 -3
- package/src/scripts/council_cli.ts +37 -54
- package/src/scripts/dispatch_r2_reviewer.ts +46 -5
- package/src/scripts/evolution_lab.ts +980 -0
- package/src/scripts/external_sources_denylist.json +5 -18
- package/src/scripts/extract_audit_patterns.ts +21 -0
- package/src/scripts/fold_intake.ts +12 -1
- package/src/scripts/gen_discovery_baseline.ts +1 -1
- package/src/scripts/generate_capabilities_index.ts +12 -5
- package/src/scripts/generate_capability_matrix.ts +3 -3
- package/src/scripts/generate_command_flows.ts +2 -2
- package/src/scripts/generate_cookbook.ts +2 -2
- package/src/scripts/generate_index.ts +8 -1
- package/src/scripts/generate_knowledge_index.ts +2 -1
- package/src/scripts/generate_ownership_matrix.ts +2 -1
- package/src/scripts/generate_pack_manifests.ts +10 -2
- package/src/scripts/generate_role_experiences_catalog.ts +2 -2
- package/src/scripts/generate_settings_reference.ts +1 -1
- package/src/scripts/git_authorization_hook.ts +22 -1
- package/src/scripts/grade_target_readiness.ts +48 -5
- package/src/scripts/hook_effect_doctor.ts +261 -0
- package/src/scripts/hook_manifest.json +1 -1
- package/src/scripts/hook_manifest.yaml +98 -11
- package/src/scripts/hooks/block_speaking_inbox_dir.ts +271 -0
- package/src/scripts/hooks/block_unauthorized_git.ts +18 -0
- package/src/scripts/hooks/concern_registry.ts +4 -0
- package/src/scripts/hooks/dispatch_hook.ts +32 -0
- package/src/scripts/hooks/journal_record_hook.ts +345 -0
- package/src/scripts/hooks/prepush_metadata_sources.sh +110 -0
- package/src/scripts/hooks/run_continuation_hook.ts +44 -9
- package/src/scripts/hooks/shims/install.sh +61 -0
- package/src/scripts/hooks/shims/php +101 -0
- package/src/scripts/hooks/suggestion_capture_hook.ts +10 -0
- package/src/scripts/hot_context_hook.ts +16 -0
- package/src/scripts/install-hooks.sh +20 -5
- package/src/scripts/install.ts +17 -35
- package/src/scripts/inventory_frontmatter.ts +2 -1
- package/src/scripts/lint_adr_sweep_routing.ts +12 -0
- package/src/scripts/lint_canonical_terms.ts +604 -0
- package/src/scripts/lint_composition_review.ts +619 -0
- package/src/scripts/lint_consolidation_lineage.ts +666 -0
- package/src/scripts/lint_eval_specs.ts +593 -0
- package/src/scripts/lint_hook_manifest.ts +19 -0
- package/src/scripts/lint_host_portability.ts +373 -0
- package/src/scripts/lint_judge_prompt_expectation.ts +27 -1
- package/src/scripts/lint_memory_twin_parity.ts +335 -0
- package/src/scripts/lint_metric_consumers.ts +355 -0
- package/src/scripts/lint_skill_descriptions.ts +18 -1
- package/src/scripts/lint_skill_frontmatter_safety.ts +58 -0
- package/src/scripts/lint_skill_link_reach.ts +252 -0
- package/src/scripts/lint_skill_trigger_corpus.ts +426 -23
- package/src/scripts/lint_ticket_buildable.ts +17 -1
- package/src/scripts/mcp_server/consumer_tool_catalog.json +1 -1
- package/src/scripts/mcp_server/tool_catalog_source.ts +1 -1
- package/src/scripts/measure_docs_dead_links.ts +348 -0
- package/src/scripts/measure_host_capture.ts +461 -0
- package/src/scripts/migration_status.ts +3 -3
- package/src/scripts/model_rule_injection.ts +60 -0
- package/src/scripts/orchestration_record.ts +14 -0
- package/src/scripts/preamble_byte_census.ts +139 -10
- package/src/scripts/prepack-check.mjs +4 -1
- package/src/scripts/probe_turnaround.ts +384 -0
- package/src/scripts/probe_unblocked_ask.ts +279 -0
- package/src/scripts/render_benchmark_md.ts +1 -1
- package/src/scripts/rule_activation_census.ts +70 -9
- package/src/scripts/rule_backlinks.ts +1 -1
- package/src/scripts/run_lifecycle_suite.ts +208 -0
- package/src/scripts/run_skill_evals.ts +40 -0
- package/src/scripts/schemas/delivery-manifest.schema.json +43 -0
- package/src/scripts/schemas/drafting-channels.schema.json +43 -0
- package/src/scripts/schemas/evals.schema.json +24 -1
- package/src/scripts/schemas/rule.schema.json +52 -1
- package/src/scripts/schemas/skill.schema.json +17 -2
- package/src/scripts/skill_overlap.ts +7 -1
- package/src/scripts/skill_tools/run_block_d_eval.ts +8 -1
- package/src/scripts/skill_tools/score_skill_relevance.ts +84 -3
- package/src/scripts/skill_tools/suggest_skill_for_task.ts +8 -1
- package/src/scripts/skill_usage_report.ts +2 -1
- package/src/scripts/stubs_due.ts +211 -0
- package/src/scripts/sweep_source_surfaces.ts +678 -0
- package/src/scripts/sync_pr_branch.ts +3 -3
- package/src/scripts/trigger_eval_grandfather.json +202 -222
- package/src/scripts/utilization_report.ts +22 -2
- package/src/server/schemas/settings.ts +5 -0
- package/src/templates/marketing-copy.yml +1 -1
- package/dist/ui/assets/index-Cxgy63kz.js +0 -26
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
/**
|
|
3
|
+
* The unblocked-ask rate — the class `user-interaction` measured and then had
|
|
4
|
+
* no instrument for.
|
|
5
|
+
*
|
|
6
|
+
* ## Why this one, and not one of the other 55
|
|
7
|
+
*
|
|
8
|
+
* `road-to-undeclared-obligation-disposition` Phase 2.1 ranks the
|
|
9
|
+
* `cheaply-probeable` bucket by MEASURED failure rather than by feel, and the
|
|
10
|
+
* ranking is lopsided: of 56 rules in that bucket, exactly **one** carries a
|
|
11
|
+
* cited measurement of its own failure. `user-interaction.md:75` records a
|
|
12
|
+
* 30-session conformance audit in which **every** malformed ask was a one-line
|
|
13
|
+
* parenthetical or a trailing free-text offer, and states that **no gate ships**
|
|
14
|
+
* for that class because `check_reply_consistency` inspects numbered-option
|
|
15
|
+
* blocks — "exactly the surface that did not fail".
|
|
16
|
+
*
|
|
17
|
+
* That is the whole case for building this and not a fourth probe. Phase 2.3
|
|
18
|
+
* caps the roadmap at one.
|
|
19
|
+
*
|
|
20
|
+
* ## What is counted
|
|
21
|
+
*
|
|
22
|
+
* A **hand-back** assistant turn — one immediately followed by a genuine user
|
|
23
|
+
* turn, i.e. where the agent actually stopped — that HANDS A DECISION and
|
|
24
|
+
* carries **no** numbered-options block. The rule's own § "The trigger is a
|
|
25
|
+
* decision, not a format" says the obligation fires on handing a decision in any
|
|
26
|
+
* form, so a trailing offer is an ask and owes a recommendation line.
|
|
27
|
+
*
|
|
28
|
+
* Of those, an ask is **malformed** when no recommendation line follows it.
|
|
29
|
+
*
|
|
30
|
+
* ## Honest bounds, and they are wide
|
|
31
|
+
*
|
|
32
|
+
* 1. **"Hands a decision" is a heuristic.** It matches offer shapes — *"soll ich
|
|
33
|
+
* …?"*, *"shall I …?"*, *"sag Bescheid, wenn …"*, *"willst du …?"* — anchored
|
|
34
|
+
* in the closing lines. A genuine clarifying question is deliberately NOT
|
|
35
|
+
* excluded, because `user-interaction` treats a bare yes/no as an ask too.
|
|
36
|
+
* Some rhetorical questions will be counted. The rate is therefore a
|
|
37
|
+
* CEILING for malformed asks of this class, not a point estimate.
|
|
38
|
+
* 2. **Turns WITH a numbered block are excluded**, not judged. That surface
|
|
39
|
+
* already has `check_reply_consistency`; measuring it here would double-count
|
|
40
|
+
* a covered class and hide the uncovered one.
|
|
41
|
+
* 3. **A recommendation line is matched on the label**, `Recommendation:` or
|
|
42
|
+
* `Empfehlung:` (with or without emphasis). A recommendation phrased without
|
|
43
|
+
* the label reads as malformed here. The rule requires the label — a
|
|
44
|
+
* wrong-language label is explicitly "no recommendation" — so this is the
|
|
45
|
+
* rule's own bar, but it is a bar on FORM.
|
|
46
|
+
*
|
|
47
|
+
* Both edges are printed. A reader who cannot see the bracket cannot judge the
|
|
48
|
+
* number.
|
|
49
|
+
*
|
|
50
|
+
* Usage:
|
|
51
|
+
* ./scripts-run src/scripts/probe_unblocked_ask [--limit N] [--store PATH] [--json]
|
|
52
|
+
* ./scripts-run src/scripts/probe_unblocked_ask --self-test
|
|
53
|
+
*
|
|
54
|
+
* Exit codes: 0 always — a measurement, not a gate. `--self-test` exits 1 when
|
|
55
|
+
* the detector fails to fire on its fixtures.
|
|
56
|
+
*/
|
|
57
|
+
import fs from 'node:fs';
|
|
58
|
+
import path from 'node:path';
|
|
59
|
+
import { pathToFileURL } from 'node:url';
|
|
60
|
+
|
|
61
|
+
import { defaultStore, HARNESS_TEXT, isInjectedBody } from './conformance_scan.js';
|
|
62
|
+
import { isSyntheticPrompt } from './_lib/prompt_shape.js';
|
|
63
|
+
|
|
64
|
+
/** A numbered-options block — the surface `check_reply_consistency` already reads. */
|
|
65
|
+
export const NUMBERED_BLOCK = /^\s{0,3}(\d+)[.)]\s+\S/m;
|
|
66
|
+
|
|
67
|
+
/** The recommendation line, matched on its label. Either language. */
|
|
68
|
+
export const RECOMMENDATION = /^\s{0,3}\**\s*(Recommendation|Empfehlung)\s*:?\**/im;
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Offer shapes that hand a decision without a block. Every one of these is a
|
|
72
|
+
* shape the 2026-08-06 audit found in a REAL malformed ask.
|
|
73
|
+
*/
|
|
74
|
+
export const OFFER_SHAPES: readonly RegExp[] = [
|
|
75
|
+
/\bsoll(en)? ich\b[^.!?]{0,120}\?/i,
|
|
76
|
+
/\bwillst du\b[^.!?]{0,120}\?/i,
|
|
77
|
+
/\bm(ö|oe)chtest du\b[^.!?]{0,120}\?/i,
|
|
78
|
+
/\bsag (mir )?bescheid,? (wenn|ob|falls)\b/i,
|
|
79
|
+
/\bwenn du (willst|m(ö|oe)chtest),? (dann )?(mache|kann|nehme|ziehe)\b/i,
|
|
80
|
+
/\bshall i\b[^.!?]{0,120}\?/i,
|
|
81
|
+
/\bshould i\b[^.!?]{0,120}\?/i,
|
|
82
|
+
/\bdo you want me to\b[^.!?]{0,120}\?/i,
|
|
83
|
+
/\bwould you like me to\b[^.!?]{0,120}\?/i,
|
|
84
|
+
/\blet me know (if|whether)\b/i,
|
|
85
|
+
];
|
|
86
|
+
|
|
87
|
+
interface Turn {
|
|
88
|
+
role: 'user' | 'assistant';
|
|
89
|
+
text: string;
|
|
90
|
+
at: string;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function turns(lines: string[]): Turn[] {
|
|
94
|
+
const out: Turn[] = [];
|
|
95
|
+
for (const line of lines) {
|
|
96
|
+
if (!line.trim()) continue;
|
|
97
|
+
let e: Record<string, unknown>;
|
|
98
|
+
try {
|
|
99
|
+
e = JSON.parse(line) as Record<string, unknown>;
|
|
100
|
+
} catch {
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
if (e['isSidechain'] === true) continue;
|
|
104
|
+
if (e['type'] === 'user' && e['toolUseResult'] !== undefined) continue;
|
|
105
|
+
if (e['isCompactSummary'] === true) continue;
|
|
106
|
+
const msg = e['message'] as { role?: string; content?: unknown } | undefined;
|
|
107
|
+
const role = msg?.role;
|
|
108
|
+
if (role !== 'user' && role !== 'assistant') continue;
|
|
109
|
+
const c = msg?.content;
|
|
110
|
+
const text =
|
|
111
|
+
typeof c === 'string'
|
|
112
|
+
? c
|
|
113
|
+
: Array.isArray(c)
|
|
114
|
+
? c
|
|
115
|
+
.filter((b: { type?: string }) => b?.type === 'text')
|
|
116
|
+
.map((b: { text?: string }) => b.text ?? '')
|
|
117
|
+
.join('\n')
|
|
118
|
+
: '';
|
|
119
|
+
if (!text.trim()) continue;
|
|
120
|
+
if (role === 'assistant' && HARNESS_TEXT.test(text.trim())) continue;
|
|
121
|
+
if (role === 'user' && (isSyntheticPrompt(text) || isInjectedBody(text))) continue;
|
|
122
|
+
out.push({ role, text, at: String(e['timestamp'] ?? '') });
|
|
123
|
+
}
|
|
124
|
+
return out;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export interface AskVerdict {
|
|
128
|
+
/** The turn hands a decision with no numbered block. */
|
|
129
|
+
unblockedAsk: boolean;
|
|
130
|
+
/** …and carries no recommendation label. */
|
|
131
|
+
malformed: boolean;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/** Classify one assistant hand-back's closing lines. */
|
|
135
|
+
export function classifyTail(tail: string): AskVerdict {
|
|
136
|
+
if (NUMBERED_BLOCK.test(tail)) return { unblockedAsk: false, malformed: false };
|
|
137
|
+
const offers = OFFER_SHAPES.some((re) => re.test(tail));
|
|
138
|
+
if (!offers) return { unblockedAsk: false, malformed: false };
|
|
139
|
+
return { unblockedAsk: true, malformed: !RECOMMENDATION.test(tail) };
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export interface Result {
|
|
143
|
+
handbacks: number;
|
|
144
|
+
withBlock: number;
|
|
145
|
+
unblockedAsks: number;
|
|
146
|
+
malformed: number;
|
|
147
|
+
samples: { session: string; at: string; span: string }[];
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export function measure(store: string, limit: number): Result {
|
|
151
|
+
const r: Result = { handbacks: 0, withBlock: 0, unblockedAsks: 0, malformed: 0, samples: [] };
|
|
152
|
+
let files: string[];
|
|
153
|
+
try {
|
|
154
|
+
files = fs.readdirSync(store).filter((f) => f.endsWith('.jsonl'));
|
|
155
|
+
} catch {
|
|
156
|
+
return r;
|
|
157
|
+
}
|
|
158
|
+
const ordered = files
|
|
159
|
+
.map((f) => ({ f, m: fs.statSync(path.join(store, f)).mtimeMs }))
|
|
160
|
+
.sort((a, b) => b.m - a.m)
|
|
161
|
+
.slice(0, limit)
|
|
162
|
+
.map((x) => x.f);
|
|
163
|
+
|
|
164
|
+
for (const f of ordered) {
|
|
165
|
+
const session = f.replace(/\.jsonl$/, '').slice(0, 8);
|
|
166
|
+
const ts = turns(fs.readFileSync(path.join(store, f), 'utf8').split('\n'));
|
|
167
|
+
for (let i = 0; i < ts.length; i += 1) {
|
|
168
|
+
const t = ts[i] as Turn;
|
|
169
|
+
if (t.role !== 'assistant') continue;
|
|
170
|
+
const next = ts[i + 1];
|
|
171
|
+
if (next !== undefined && next.role !== 'user') continue;
|
|
172
|
+
r.handbacks += 1;
|
|
173
|
+
// Closing lines only: an offer buried mid-reply is not the hand-back.
|
|
174
|
+
const tail = t.text.trimEnd().split('\n').slice(-8).join('\n');
|
|
175
|
+
if (NUMBERED_BLOCK.test(tail)) {
|
|
176
|
+
r.withBlock += 1;
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
const v = classifyTail(tail);
|
|
180
|
+
if (!v.unblockedAsk) continue;
|
|
181
|
+
r.unblockedAsks += 1;
|
|
182
|
+
if (v.malformed) {
|
|
183
|
+
r.malformed += 1;
|
|
184
|
+
if (r.samples.length < 5) {
|
|
185
|
+
const hit = OFFER_SHAPES.find((re) => re.test(tail));
|
|
186
|
+
r.samples.push({
|
|
187
|
+
session,
|
|
188
|
+
at: t.at,
|
|
189
|
+
span: (tail.match(hit as RegExp)?.[0] ?? '').slice(0, 110),
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return r;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Prove the detector fires, and prove it stays silent where it must.
|
|
200
|
+
*
|
|
201
|
+
* An instrument never seen fire has unknown sensitivity — and one that fires on
|
|
202
|
+
* everything measures nothing, which is why the negative cases are here too.
|
|
203
|
+
*/
|
|
204
|
+
export function selfTest(): number {
|
|
205
|
+
const cases: Array<[string, string, boolean, boolean]> = [
|
|
206
|
+
['a trailing German offer with no recommendation', 'Fertig.\n\nSag Bescheid, wenn ich die drei Zeilen mitnehmen soll.', true, true],
|
|
207
|
+
['a bare yes/no offer', 'Der Branch ist grün.\n\nSoll ich das so umsetzen?', true, true],
|
|
208
|
+
['an English trailing offer', 'Done.\n\nLet me know if you want the second half too.', true, true],
|
|
209
|
+
['an offer WITH a recommendation label', 'Soll ich das so umsetzen?\n\n**Empfehlung:** ja, es ist reversibel.', true, false],
|
|
210
|
+
['a numbered block is excluded — another gate reads it', '1. do it\n2. skip it\n\nRecommendation: 1', false, false],
|
|
211
|
+
['an ordinary statement hands nothing', 'Fixed the schema lint; force-pushed b17c4ef8.', false, false],
|
|
212
|
+
['a question about the code is not an offer to act', 'Why does this function take a callback?', false, false],
|
|
213
|
+
];
|
|
214
|
+
let failed = 0;
|
|
215
|
+
for (const [name, tail, wantAsk, wantMalformed] of cases) {
|
|
216
|
+
const v = classifyTail(tail);
|
|
217
|
+
const ok = v.unblockedAsk === wantAsk && v.malformed === wantMalformed;
|
|
218
|
+
process.stdout.write(
|
|
219
|
+
`${ok ? '✅' : '❌'} ${name} — ask=${String(v.unblockedAsk)} malformed=${String(v.malformed)}` +
|
|
220
|
+
(ok ? '\n' : ` (wanted ask=${String(wantAsk)} malformed=${String(wantMalformed)})\n`),
|
|
221
|
+
);
|
|
222
|
+
if (!ok) failed += 1;
|
|
223
|
+
}
|
|
224
|
+
const positives = cases.filter((c) => c[3]).length;
|
|
225
|
+
if (positives < 3) {
|
|
226
|
+
process.stderr.write('❌ probe_unblocked_ask --self-test: fewer than 3 positive cases — a truncated suite must fail.\n');
|
|
227
|
+
return 1;
|
|
228
|
+
}
|
|
229
|
+
process.stdout.write(
|
|
230
|
+
`\nprobe_unblocked_ask --self-test: ${String(cases.length - failed)}/${String(cases.length)} case(s) behaved ` +
|
|
231
|
+
`(${String(positives)} positive, ${String(cases.length - positives)} negative)\n`,
|
|
232
|
+
);
|
|
233
|
+
return failed > 0 ? 1 : 0;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
export function main(argv: string[]): number {
|
|
237
|
+
let limit = 60;
|
|
238
|
+
let storeArg: string | null = null;
|
|
239
|
+
let json = false;
|
|
240
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
241
|
+
const a = argv[i] as string;
|
|
242
|
+
if (a === '--limit') limit = Number(argv[++i]);
|
|
243
|
+
else if (a === '--store') storeArg = String(argv[++i]);
|
|
244
|
+
else if (a === '--json') json = true;
|
|
245
|
+
// --self-test runs BEFORE the store is resolved: the fixtures are
|
|
246
|
+
// in-process, and resolving a transcript store that may not exist here
|
|
247
|
+
// would make the sensitivity proof depend on the host having one.
|
|
248
|
+
else if (a === '--self-test') return selfTest();
|
|
249
|
+
else {
|
|
250
|
+
process.stderr.write(`probe_unblocked_ask: unrecognized argument: ${a}\n`);
|
|
251
|
+
return 0;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
const store = storeArg ?? defaultStore(process.cwd());
|
|
255
|
+
const r = measure(store, limit);
|
|
256
|
+
if (json) {
|
|
257
|
+
process.stdout.write(`${JSON.stringify(r, null, 2)}\n`);
|
|
258
|
+
return 0;
|
|
259
|
+
}
|
|
260
|
+
const pct = (n: number, d: number): string => (d === 0 ? 'n/a' : `${((100 * n) / d).toFixed(1)}%`);
|
|
261
|
+
process.stdout.write(
|
|
262
|
+
`probe_unblocked_ask · ${String(limit)} most recent session(s) under ${store}\n` +
|
|
263
|
+
` hand-back turns ${String(r.handbacks)}\n` +
|
|
264
|
+
` …with a numbered block ${String(r.withBlock)} (excluded — check_reply_consistency reads that surface)\n` +
|
|
265
|
+
` …unblocked asks ${String(r.unblockedAsks)} ${pct(r.unblockedAsks, r.handbacks)} of hand-backs\n` +
|
|
266
|
+
` …of those, malformed ${String(r.malformed)} ${pct(r.malformed, r.unblockedAsks)} of unblocked asks\n` +
|
|
267
|
+
'\n CEILING, not a point estimate: "hands a decision" is a heuristic and a\n' +
|
|
268
|
+
' rhetorical question can match it. A recommendation is matched on its LABEL,\n' +
|
|
269
|
+
' which is the rule\'s own bar but a bar on form.\n',
|
|
270
|
+
);
|
|
271
|
+
for (const s of r.samples) {
|
|
272
|
+
process.stdout.write(` · ${s.session} ${s.at}: ${s.span}\n`);
|
|
273
|
+
}
|
|
274
|
+
return 0;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
|
|
278
|
+
process.exit(main(process.argv.slice(2)));
|
|
279
|
+
}
|
|
@@ -617,7 +617,7 @@ export function render(quiet = false): number {
|
|
|
617
617
|
const parts = [
|
|
618
618
|
'# Package-Impact A/B Benchmark',
|
|
619
619
|
'',
|
|
620
|
-
'> Generated by `
|
|
620
|
+
'> Generated by `render_benchmark_md`. Do not edit. Source of truth: ' +
|
|
621
621
|
'`internal/bench/reports/ab/`. Re-render anytime with `task bench:ab:diff`.',
|
|
622
622
|
'',
|
|
623
623
|
render_headline(trackA, trackB, trackBRdp),
|
|
@@ -58,6 +58,7 @@ import * as fs from 'node:fs';
|
|
|
58
58
|
import * as path from 'node:path';
|
|
59
59
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
60
60
|
|
|
61
|
+
import { isExclusivelyPackageOnly } from '../install/partitionEligibility.js';
|
|
61
62
|
import { _claude_paths_plan, _has_non_path_trigger, _parse_frontmatter } from './condense.js';
|
|
62
63
|
|
|
63
64
|
const RULES_DIR = path.join('src', 'rules');
|
|
@@ -83,6 +84,13 @@ export interface RuleActivation {
|
|
|
83
84
|
emitted_globs: string[];
|
|
84
85
|
/** Patterns the emitter deliberately drops, with the reason it records. */
|
|
85
86
|
dropped: { pattern: string; reason: string }[];
|
|
87
|
+
/**
|
|
88
|
+
* Scoped to this package alone, so ADR-236 withholds it from every global
|
|
89
|
+
* host layer. Load-bearing for the projection comparison: a package-only
|
|
90
|
+
* rule is counted by the source verdict and is absent from a delivered
|
|
91
|
+
* tree by design, not by drift.
|
|
92
|
+
*/
|
|
93
|
+
package_only: boolean;
|
|
86
94
|
/**
|
|
87
95
|
* The emitter's verdict in one word.
|
|
88
96
|
* `scoped` — loads on a path match · `unconditional` — loads every session ·
|
|
@@ -111,7 +119,11 @@ function _declares(meta: Record<string, unknown>, keys: readonly string[]): bool
|
|
|
111
119
|
}
|
|
112
120
|
|
|
113
121
|
/** Classify one rule file through the emitter's own exported decision path. */
|
|
114
|
-
export function classify_rule(
|
|
122
|
+
export function classify_rule(
|
|
123
|
+
id: string,
|
|
124
|
+
content: string,
|
|
125
|
+
package_only = false,
|
|
126
|
+
): RuleActivation {
|
|
115
127
|
const [meta] = _parse_frontmatter(content);
|
|
116
128
|
const plan = _claude_paths_plan(meta);
|
|
117
129
|
const has_path_trigger = _declares(meta, PATH_TRIGGER_KEYS);
|
|
@@ -139,6 +151,7 @@ export function classify_rule(id: string, content: string): RuleActivation {
|
|
|
139
151
|
emitted_globs: plan.globs,
|
|
140
152
|
dropped: plan.dropped.map((d) => ({ pattern: d.pattern, reason: d.reason })),
|
|
141
153
|
verdict,
|
|
154
|
+
package_only,
|
|
142
155
|
};
|
|
143
156
|
}
|
|
144
157
|
|
|
@@ -150,7 +163,11 @@ export function census(root: string): RuleActivation[] {
|
|
|
150
163
|
.map((e) => e.name)
|
|
151
164
|
.sort();
|
|
152
165
|
return files.map((f) =>
|
|
153
|
-
classify_rule(
|
|
166
|
+
classify_rule(
|
|
167
|
+
f.replace(/\.md$/, ''),
|
|
168
|
+
fs.readFileSync(path.join(dir, f), 'utf8'),
|
|
169
|
+
isExclusivelyPackageOnly(path.join(dir, f)),
|
|
170
|
+
),
|
|
154
171
|
);
|
|
155
172
|
}
|
|
156
173
|
|
|
@@ -223,10 +240,14 @@ export function main(): number {
|
|
|
223
240
|
|
|
224
241
|
const rows = census(root);
|
|
225
242
|
const sum = summarize(rows);
|
|
243
|
+
const resolved_projection_dir =
|
|
244
|
+
projection_dir === undefined || projection_dir === null || projection_dir === ''
|
|
245
|
+
? ''
|
|
246
|
+
: path.isAbsolute(projection_dir)
|
|
247
|
+
? projection_dir
|
|
248
|
+
: path.join(root, projection_dir);
|
|
226
249
|
const projection = projection_dir
|
|
227
|
-
? projection_reading(
|
|
228
|
-
? projection_dir
|
|
229
|
-
: path.join(root, projection_dir))
|
|
250
|
+
? projection_reading(resolved_projection_dir)
|
|
230
251
|
: null;
|
|
231
252
|
|
|
232
253
|
if (as_json) {
|
|
@@ -259,11 +280,51 @@ export function main(): number {
|
|
|
259
280
|
`\n host projection at ${projection_dir} — reported SEPARATELY, not merged:\n` +
|
|
260
281
|
` files ${projection.files} · declaring paths: ${projection.with_paths}\n`,
|
|
261
282
|
);
|
|
262
|
-
|
|
283
|
+
// The source verdict counts EVERY rule in `src/rules/`. A GLOBAL host
|
|
284
|
+
// layer does not carry the package-only ones: ADR-236 partitions them to
|
|
285
|
+
// the project layer, so such a tree is expected to be short by exactly
|
|
286
|
+
// that many. Comparing the raw counts reported a divergence on every
|
|
287
|
+
// partitioned install forever — the emitter was right and the
|
|
288
|
+
// comparator was not subtracting.
|
|
289
|
+
//
|
|
290
|
+
// But the subtraction is NOT unconditional, and making it so was its own
|
|
291
|
+
// regression (completion review, 2026-08-30): a full or project-layer
|
|
292
|
+
// projection — which is also the fail-safe default `partitionEligibility`
|
|
293
|
+
// returns on a fresh checkout, an absent install record, or a version or
|
|
294
|
+
// fingerprint mismatch — DOES carry those rules, and for this repo's own
|
|
295
|
+
// project layer `source-of-truth` is the one rule delivered there and the
|
|
296
|
+
// only one declaring `paths:`. Subtracting it there inverts the line.
|
|
297
|
+
//
|
|
298
|
+
// So the partition is DETECTED from the projection rather than assumed:
|
|
299
|
+
// if a package-only rule's file is present, this is not a global layer.
|
|
300
|
+
const pkg_only_ids = rows.filter((r) => r.package_only).map((r) => r.id);
|
|
301
|
+
const partitioned = !pkg_only_ids.some((id) =>
|
|
302
|
+
fs.existsSync(path.join(resolved_projection_dir, `${id}.md`)),
|
|
303
|
+
);
|
|
304
|
+
const scoped_pkg_only = partitioned
|
|
305
|
+
? rows.filter((r) => r.verdict === 'scoped' && r.package_only)
|
|
306
|
+
: [];
|
|
307
|
+
const expected = sum.scoped - scoped_pkg_only.length;
|
|
308
|
+
if (scoped_pkg_only.length > 0) {
|
|
309
|
+
process.stdout.write(
|
|
310
|
+
` source scopes ${sum.scoped}; ${scoped_pkg_only.length} of those ` +
|
|
311
|
+
`${scoped_pkg_only.length === 1 ? 'is' : 'are'} package-only and never\n` +
|
|
312
|
+
` delivered (${scoped_pkg_only.map((r) => r.id).join(', ')}), so a ` +
|
|
313
|
+
`partitioned projection is\n expected to declare ${expected}.\n`,
|
|
314
|
+
);
|
|
315
|
+
}
|
|
316
|
+
if (projection.with_paths !== expected) {
|
|
317
|
+
process.stdout.write(
|
|
318
|
+
` ⚠️ diverges from the source verdict (${expected} expected` +
|
|
319
|
+
`${scoped_pkg_only.length > 0 ? `, ${sum.scoped} before the package-only partition` : ''}).\n` +
|
|
320
|
+
` A projection carries no record of the scope or commit it was generated\n` +
|
|
321
|
+
` at, so this is a reason to regenerate it — never a reading of the\n` +
|
|
322
|
+
` emitter.\n`,
|
|
323
|
+
);
|
|
324
|
+
} else {
|
|
263
325
|
process.stdout.write(
|
|
264
|
-
`
|
|
265
|
-
|
|
266
|
-
` is a reason to regenerate it — never a reading of the emitter.\n`,
|
|
326
|
+
` ✅ consistent with the source verdict (${expected} expected, ` +
|
|
327
|
+
`${projection.with_paths} found).\n`,
|
|
267
328
|
);
|
|
268
329
|
}
|
|
269
330
|
} else if (projection_dir) {
|
|
@@ -228,7 +228,7 @@ export function render(
|
|
|
228
228
|
validation: ValidationResult = validate_targets(byTarget),
|
|
229
229
|
): string {
|
|
230
230
|
const L: string[] = [];
|
|
231
|
-
L.push('<!-- GENERATED by
|
|
231
|
+
L.push('<!-- GENERATED by rule_backlinks — do NOT hand-edit.');
|
|
232
232
|
L.push(' Regenerate after each P4 migration batch. Report-only. -->');
|
|
233
233
|
L.push('');
|
|
234
234
|
L.push('# Rule backlinks — which rules route here');
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* run_lifecycle_suite — run the process-level lifecycle suite and write the
|
|
3
|
+
* evidence artifact `check_supervision_claim_atomicity` reads
|
|
4
|
+
* (`road-to-supervised-telemetry-collector` steps 5.1 and 5.2).
|
|
5
|
+
*
|
|
6
|
+
* ## Why a producer script and not just `vitest run`
|
|
7
|
+
*
|
|
8
|
+
* The atomicity gate refuses a present-tense supervision claim unless
|
|
9
|
+
* `internal/reports/supervision-lifecycle.json` records a suite that ran on THIS
|
|
10
|
+
* revision, exercised real processes, and was not empty or mostly skipped. That
|
|
11
|
+
* artifact has to be written by something that knows all four facts. A test file
|
|
12
|
+
* knows whether it ran; only the runner knows the revision and the counts.
|
|
13
|
+
*
|
|
14
|
+
* ## Every field here is observed, not asserted
|
|
15
|
+
*
|
|
16
|
+
* - `revision` — `git rev-parse HEAD`, read at run time. Never a constant.
|
|
17
|
+
* - `cases_run` / `cases_skipped` — parsed out of vitest's own JSON report,
|
|
18
|
+
* never counted by hand from the source.
|
|
19
|
+
* - `processes_exercised` — true only when the suite ACTUALLY spawned daemons,
|
|
20
|
+
* established by re-reading the report for the property names that can only
|
|
21
|
+
* pass against real processes. A hardcoded `true` here would defeat the entire
|
|
22
|
+
* point of the gate, which exists because a mocked suite can demonstrate all
|
|
23
|
+
* five properties and prove none of them.
|
|
24
|
+
*
|
|
25
|
+
* ## A skip is a failure
|
|
26
|
+
*
|
|
27
|
+
* AC-8: *"a suite that skips on a platform is a failure on that platform, not an
|
|
28
|
+
* absence."* So a run whose cases were skipped writes the artifact with the
|
|
29
|
+
* honest counts and exits non-zero, rather than writing nothing — a missing
|
|
30
|
+
* artifact and a skipped suite need different remediation and the gate
|
|
31
|
+
* distinguishes them.
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
import { execFileSync, spawnSync } from 'node:child_process';
|
|
35
|
+
import fs from 'node:fs';
|
|
36
|
+
import os from 'node:os';
|
|
37
|
+
import path from 'node:path';
|
|
38
|
+
import { fileURLToPath } from 'node:url';
|
|
39
|
+
|
|
40
|
+
const HERE = path.dirname(fileURLToPath(import.meta.url));
|
|
41
|
+
const REPO = path.resolve(HERE, '..', '..');
|
|
42
|
+
|
|
43
|
+
/** The suite, by path. Named once so the artifact and the runner cannot drift. */
|
|
44
|
+
export const SUITE_REL = 'tests/scripts/collector_lifecycle.test.ts';
|
|
45
|
+
export const SUITE_NAME = 'supervision-lifecycle';
|
|
46
|
+
export const EVIDENCE_REL = path.join('internal', 'reports', 'supervision-lifecycle.json');
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* The five property names the suite must have RUN for the artifact to claim
|
|
50
|
+
* real processes were exercised.
|
|
51
|
+
*
|
|
52
|
+
* Matched against the report's test names rather than counted, because a count
|
|
53
|
+
* cannot tell five properties from five repeats of one.
|
|
54
|
+
*/
|
|
55
|
+
export const REQUIRED_PROPERTIES = [
|
|
56
|
+
'PROPERTY 1',
|
|
57
|
+
'PROPERTY 2',
|
|
58
|
+
'PROPERTY 3',
|
|
59
|
+
'PROPERTY 4',
|
|
60
|
+
'PROPERTY 5',
|
|
61
|
+
] as const;
|
|
62
|
+
|
|
63
|
+
export interface SuiteCounts {
|
|
64
|
+
readonly run: number;
|
|
65
|
+
readonly skipped: number;
|
|
66
|
+
readonly passedNames: readonly string[];
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function countsFromReport(reportJson: string): SuiteCounts {
|
|
70
|
+
const raw = JSON.parse(reportJson) as {
|
|
71
|
+
testResults?: { assertionResults?: { fullName?: string; status?: string }[] }[];
|
|
72
|
+
};
|
|
73
|
+
let run = 0;
|
|
74
|
+
let skipped = 0;
|
|
75
|
+
const passedNames: string[] = [];
|
|
76
|
+
for (const suite of raw.testResults ?? []) {
|
|
77
|
+
for (const assertion of suite.assertionResults ?? []) {
|
|
78
|
+
const status = assertion.status ?? 'unknown';
|
|
79
|
+
if (status === 'pending' || status === 'skipped' || status === 'todo') {
|
|
80
|
+
skipped += 1;
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
run += 1;
|
|
84
|
+
if (status === 'passed') passedNames.push(assertion.fullName ?? '');
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return { run, skipped, passedNames };
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Did the run exercise real processes?
|
|
92
|
+
*
|
|
93
|
+
* True only when every one of the five named properties PASSED. Anything less —
|
|
94
|
+
* a skipped property, a renamed one, a suite that never collected — leaves this
|
|
95
|
+
* false, and the gate then refuses the capability claim rather than accepting a
|
|
96
|
+
* partial demonstration as a whole one.
|
|
97
|
+
*/
|
|
98
|
+
export function processesExercised(counts: SuiteCounts): boolean {
|
|
99
|
+
return REQUIRED_PROPERTIES.every((property) =>
|
|
100
|
+
counts.passedNames.some((name) => name.includes(property)),
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export function headRevision(repo: string = REPO): string {
|
|
105
|
+
try {
|
|
106
|
+
return execFileSync('git', ['-C', repo, 'rev-parse', 'HEAD'], { encoding: 'utf8' }).trim();
|
|
107
|
+
} catch {
|
|
108
|
+
return '';
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export function main(argv: readonly string[] = process.argv.slice(2)): number {
|
|
113
|
+
const dryRun = argv.includes('--dry-run');
|
|
114
|
+
const report = path.join(os.tmpdir(), `lifecycle-report-${process.pid}.json`);
|
|
115
|
+
fs.rmSync(report, { force: true });
|
|
116
|
+
|
|
117
|
+
// Clear the parity gate's alias switch, the same guard its sibling spawner
|
|
118
|
+
// takes (R2 round-5 finding 10). An ambient `AGENT_CONFIG_COLLECTOR_ABSENT`
|
|
119
|
+
// stubs the collector away for this run too, so `enableCollector` becomes a
|
|
120
|
+
// no-op and every daemon refuses with `not-enabled`. It fails loudly rather
|
|
121
|
+
// than silently — but the asymmetry between two spawners in one change is
|
|
122
|
+
// the shape the earlier finding was about.
|
|
123
|
+
const env = { ...process.env };
|
|
124
|
+
delete env.AGENT_CONFIG_COLLECTOR_ABSENT;
|
|
125
|
+
|
|
126
|
+
const result = spawnSync(
|
|
127
|
+
path.join(REPO, 'node_modules', '.bin', 'vitest'),
|
|
128
|
+
['run', SUITE_REL, '--reporter=json', `--outputFile=${report}`],
|
|
129
|
+
{ cwd: REPO, encoding: 'utf8', env, stdio: ['ignore', 'pipe', 'pipe'] },
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
if (!fs.existsSync(report)) {
|
|
133
|
+
process.stderr.write(
|
|
134
|
+
`run_lifecycle_suite: no report produced.\n${result.stdout ?? ''}\n${result.stderr ?? ''}\n`,
|
|
135
|
+
);
|
|
136
|
+
return 1;
|
|
137
|
+
}
|
|
138
|
+
const counts = countsFromReport(fs.readFileSync(report, 'utf8'));
|
|
139
|
+
fs.rmSync(report, { force: true });
|
|
140
|
+
|
|
141
|
+
const revision = headRevision();
|
|
142
|
+
const suiteGreen = result.status === 0;
|
|
143
|
+
// A red suite is a THIRD state, and the artifact used to record neither it
|
|
144
|
+
// nor anything that implied it: `processes_exercised` depends only on the
|
|
145
|
+
// five named properties, so a run where all five passed and a sixth case
|
|
146
|
+
// failed wrote `processes_exercised: true, cases_skipped: 0` and then exited
|
|
147
|
+
// 1 — a pass-shaped artifact left on disk by a failing run (R2 finding 18).
|
|
148
|
+
//
|
|
149
|
+
// Two changes close it. The flag itself is conjoined with the suite's exit
|
|
150
|
+
// status, so a red run can never claim the processes were exercised; and
|
|
151
|
+
// `suite_exit_status` is recorded outright, so the state is readable rather
|
|
152
|
+
// than inferred. The gate's own contract is unchanged — it reads
|
|
153
|
+
// `processes_exercised`, which is now false on a red run.
|
|
154
|
+
const exercised = processesExercised(counts) && suiteGreen;
|
|
155
|
+
const evidence = {
|
|
156
|
+
suite: SUITE_NAME,
|
|
157
|
+
revision,
|
|
158
|
+
processes_exercised: exercised,
|
|
159
|
+
cases_run: counts.run,
|
|
160
|
+
cases_skipped: counts.skipped,
|
|
161
|
+
suite_exit_status: result.status ?? null,
|
|
162
|
+
platform: `${process.platform}-${process.arch}`,
|
|
163
|
+
recorded_at: new Date().toISOString(),
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
process.stdout.write(
|
|
167
|
+
`run_lifecycle_suite: ${counts.run} run, ${counts.skipped} skipped, `
|
|
168
|
+
+ `suite_exit=${String(result.status ?? 'null')}, `
|
|
169
|
+
+ `processes_exercised=${String(exercised)}, revision=${revision || '(unknown)'}\n`,
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
if (dryRun) {
|
|
173
|
+
process.stdout.write(`${JSON.stringify(evidence, null, 2)}\n`);
|
|
174
|
+
return suiteGreen && exercised && counts.skipped === 0 ? 0 : 1;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const target = path.join(REPO, EVIDENCE_REL);
|
|
178
|
+
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
179
|
+
fs.writeFileSync(target, `${JSON.stringify(evidence, null, 2)}\n`);
|
|
180
|
+
process.stdout.write(`run_lifecycle_suite: wrote ${EVIDENCE_REL}\n`);
|
|
181
|
+
|
|
182
|
+
if (result.status !== 0) {
|
|
183
|
+
process.stderr.write('run_lifecycle_suite: the suite is RED\n');
|
|
184
|
+
return 1;
|
|
185
|
+
}
|
|
186
|
+
if (counts.skipped > 0) {
|
|
187
|
+
// AC-8 makes a skip a failure on that platform rather than an absence.
|
|
188
|
+
process.stderr.write(
|
|
189
|
+
`run_lifecycle_suite: ${counts.skipped} case(s) SKIPPED — on a declared platform a `
|
|
190
|
+
+ 'skip is a failure, not an absence\n',
|
|
191
|
+
);
|
|
192
|
+
return 1;
|
|
193
|
+
}
|
|
194
|
+
if (!exercised) {
|
|
195
|
+
process.stderr.write(
|
|
196
|
+
'run_lifecycle_suite: not every named property passed — the artifact records '
|
|
197
|
+
+ '`processes_exercised: false` and the capability claim stays prohibited\n',
|
|
198
|
+
);
|
|
199
|
+
return 1;
|
|
200
|
+
}
|
|
201
|
+
return 0;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const invokedDirectly =
|
|
205
|
+
process.argv[1] !== undefined && process.argv[1].includes('run_lifecycle_suite');
|
|
206
|
+
if (invokedDirectly) {
|
|
207
|
+
process.exitCode = main();
|
|
208
|
+
}
|