@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,209 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Delivered-cost primitives (`road-to-delivered-cost-truth` Phase 1).
|
|
3
|
+
*
|
|
4
|
+
* Three answers a consumer of this suite cannot currently get: what does my
|
|
5
|
+
* configuration cost per session, which assets produce that cost, and is any of
|
|
6
|
+
* it taking effect. This module owns the first; `_lib/asset_delivery_ledger.ts`
|
|
7
|
+
* owns the second.
|
|
8
|
+
*
|
|
9
|
+
* PAYLOAD AMPLIFICATION, NOT "NET NEGATIVE" — the naming is a council verdict,
|
|
10
|
+
* not a preference. AI council 2026-08-28 (2/2 convergent) resolved the
|
|
11
|
+
* `what-the-net-negative-threshold-is` blocker as option (b), a ratio against
|
|
12
|
+
* the active profile's declared payload, AND both seats refused the name the
|
|
13
|
+
* roadmap used: a ratio measures how much payload is delivered per unit the
|
|
14
|
+
* profile declared. It cannot establish that the configuration is net-negative,
|
|
15
|
+
* because it never observes what was RETURNED. A 10:1 amplification delivering
|
|
16
|
+
* critical capability is not net-negative; a 1:1 delivering nothing is. So the
|
|
17
|
+
* figure informs the question and is not allowed to answer it, and the field is
|
|
18
|
+
* named for what it measures.
|
|
19
|
+
*
|
|
20
|
+
* THE DENOMINATOR IS THE INTENDED PAYLOAD, NOT THE MEASURED ONE. A first cut
|
|
21
|
+
* declared the profile's payload as its own current measurement, which made the
|
|
22
|
+
* ratio 1.00 by construction — a number that cannot move is not a measurement.
|
|
23
|
+
* The declaration is what the profile INTENDS to deliver (its budget); the
|
|
24
|
+
* numerator is what the tree actually delivers; the ratio is the gap, which is
|
|
25
|
+
* the whole point.
|
|
26
|
+
*
|
|
27
|
+
* AND IT IS VERIFIED, NOT TRUSTED. Both council seats independently raised
|
|
28
|
+
* denominator gaming: a profile self-declaring a large payload makes any
|
|
29
|
+
* delivered cost look good. So a declaration above the measured tree's own total
|
|
30
|
+
* is refused — a profile cannot intend to deliver more than exists — and an
|
|
31
|
+
* absent, non-positive or over-ceiling declaration yields `unknown_profile`,
|
|
32
|
+
* never a ratio computed from a number nobody checked.
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
export type AmplificationVerdict = 'measured' | 'unknown_profile';
|
|
36
|
+
|
|
37
|
+
export interface ProfileDeclaration {
|
|
38
|
+
profile: string;
|
|
39
|
+
/**
|
|
40
|
+
* INTENDED standing payload per category — the profile's budget, not its
|
|
41
|
+
* current measurement. Per category so the numerator and denominator
|
|
42
|
+
* measure the same things; a single total would let a rules figure be
|
|
43
|
+
* compared against a rules-plus-skills delivery.
|
|
44
|
+
*/
|
|
45
|
+
declared: { rules_tokens: number; skill_catalogue_tokens: number };
|
|
46
|
+
/**
|
|
47
|
+
* How far ABOVE the measured tree a declaration may sit before it is
|
|
48
|
+
* refused as gamed. A profile cannot intend to deliver more than exists.
|
|
49
|
+
*/
|
|
50
|
+
sanity_headroom: number;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface AmplificationResult {
|
|
54
|
+
verdict: AmplificationVerdict;
|
|
55
|
+
/** `null` whenever `verdict` is not `measured`. Never a placeholder number. */
|
|
56
|
+
ratio: number | null;
|
|
57
|
+
delivered_tokens: number;
|
|
58
|
+
declared_tokens: number | null;
|
|
59
|
+
reason: string;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** A declaration is usable when it is present, positive, and not above the tree. */
|
|
63
|
+
export function amplification(
|
|
64
|
+
deliveredTokens: number,
|
|
65
|
+
measured: { rules_tokens: number; skill_catalogue_tokens: number },
|
|
66
|
+
declaration: ProfileDeclaration | null,
|
|
67
|
+
): AmplificationResult {
|
|
68
|
+
if (declaration === null) {
|
|
69
|
+
return {
|
|
70
|
+
verdict: 'unknown_profile',
|
|
71
|
+
ratio: null,
|
|
72
|
+
delivered_tokens: deliveredTokens,
|
|
73
|
+
declared_tokens: null,
|
|
74
|
+
reason: 'the active profile declares no intended standing payload, so there is no denominator to compare against',
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
const declaredTotal = declaration.declared.rules_tokens + declaration.declared.skill_catalogue_tokens;
|
|
78
|
+
if (!Number.isFinite(declaredTotal) || declaredTotal <= 0) {
|
|
79
|
+
return {
|
|
80
|
+
verdict: 'unknown_profile',
|
|
81
|
+
ratio: null,
|
|
82
|
+
delivered_tokens: deliveredTokens,
|
|
83
|
+
declared_tokens: null,
|
|
84
|
+
reason: `profile '${declaration.profile}' declares a non-positive payload (${String(declaredTotal)}), which cannot be a denominator`,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// The gaming direction, and the only one that matters: a declaration ABOVE
|
|
89
|
+
// what the tree can deliver drives the ratio below 1 and makes any delivery
|
|
90
|
+
// look disciplined. A declaration BELOW the delivery is not gaming — it is
|
|
91
|
+
// the finding, and it is exactly what this ratio exists to surface.
|
|
92
|
+
const measuredTotal = measured.rules_tokens + measured.skill_catalogue_tokens;
|
|
93
|
+
const ceiling = measuredTotal * (1 + declaration.sanity_headroom);
|
|
94
|
+
if (declaredTotal > ceiling) {
|
|
95
|
+
return {
|
|
96
|
+
verdict: 'unknown_profile',
|
|
97
|
+
ratio: null,
|
|
98
|
+
delivered_tokens: deliveredTokens,
|
|
99
|
+
declared_tokens: declaredTotal,
|
|
100
|
+
reason:
|
|
101
|
+
`profile '${declaration.profile}' declares ${String(declaredTotal)} tok of intended payload against a ` +
|
|
102
|
+
`measured tree of ${String(measuredTotal)} tok — a profile cannot intend to deliver more than exists, ` +
|
|
103
|
+
'so the declaration is refused rather than used as a denominator',
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return {
|
|
108
|
+
verdict: 'measured',
|
|
109
|
+
ratio: deliveredTokens / declaredTotal,
|
|
110
|
+
delivered_tokens: deliveredTokens,
|
|
111
|
+
declared_tokens: declaredTotal,
|
|
112
|
+
reason:
|
|
113
|
+
`${String(deliveredTokens)} tok delivered against ${String(declaredTotal)} tok intended by profile ` +
|
|
114
|
+
`'${declaration.profile}'`,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// ─────────────────────────────────────────────────── the billable-input split
|
|
119
|
+
|
|
120
|
+
export interface BillableSplit {
|
|
121
|
+
fresh_input_tokens: number;
|
|
122
|
+
cache_read_tokens: number;
|
|
123
|
+
cache_creation_tokens: number;
|
|
124
|
+
billable_input_tokens: number;
|
|
125
|
+
/** cache_read / billable_input. `null` when nothing was billed. */
|
|
126
|
+
cache_read_share: number | null;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export function billableSplit(fresh: number, cacheRead: number, cacheCreation: number): BillableSplit {
|
|
130
|
+
const total = fresh + cacheRead + cacheCreation;
|
|
131
|
+
return {
|
|
132
|
+
fresh_input_tokens: fresh,
|
|
133
|
+
cache_read_tokens: cacheRead,
|
|
134
|
+
cache_creation_tokens: cacheCreation,
|
|
135
|
+
billable_input_tokens: total,
|
|
136
|
+
// A share over a zero denominator is not 0 % — it is absent, and
|
|
137
|
+
// rendering 0 % would read as "the cache never helped".
|
|
138
|
+
cache_read_share: total > 0 ? cacheRead / total : null,
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// ──────────────────────────────────────────────────── re-read cost (step 1.3)
|
|
143
|
+
|
|
144
|
+
export interface RereadLeg {
|
|
145
|
+
/** Repo-relative path that was re-read. */
|
|
146
|
+
file: string;
|
|
147
|
+
/** Total reads of this file in the leg. */
|
|
148
|
+
total_reads: number;
|
|
149
|
+
/** Reads beyond the first. */
|
|
150
|
+
duplicate_reads: number;
|
|
151
|
+
/** Measured size of the file in tokens. */
|
|
152
|
+
file_tokens: number;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export interface RereadCost {
|
|
156
|
+
legs: RereadLeg[];
|
|
157
|
+
/** Tokens paid for content already in context. */
|
|
158
|
+
wasted_tokens: number;
|
|
159
|
+
/** `null` when nothing was re-read — never a zero standing in for absence. */
|
|
160
|
+
worst_file: string | null;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Price the re-reads `hot_context_hook` already counts.
|
|
165
|
+
*
|
|
166
|
+
* The hook notices a repeated read and says so; nothing turned that into a
|
|
167
|
+
* number, so a re-read was visible and unpriced. The cost is
|
|
168
|
+
* `duplicate_reads x file_tokens` — a figure DERIVED from the file's measured
|
|
169
|
+
* size, never a constant, because a constant would rank a re-read of a one-line
|
|
170
|
+
* config beside a re-read of a 3,000-token rule.
|
|
171
|
+
*/
|
|
172
|
+
export function rereadCost(legs: readonly RereadLeg[]): RereadCost {
|
|
173
|
+
const wasted = legs.reduce((n, l) => n + l.duplicate_reads * l.file_tokens, 0);
|
|
174
|
+
let worst: RereadLeg | null = null;
|
|
175
|
+
for (const l of legs) {
|
|
176
|
+
const cost = l.duplicate_reads * l.file_tokens;
|
|
177
|
+
if (cost > 0 && (worst === null || cost > worst.duplicate_reads * worst.file_tokens)) worst = l;
|
|
178
|
+
}
|
|
179
|
+
return { legs: [...legs], wasted_tokens: wasted, worst_file: worst === null ? null : worst.file };
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// ────────────────────────────────────────────── the summary line (step 2.3)
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* The one-line end-of-task figure. TOKENS ONLY.
|
|
186
|
+
*
|
|
187
|
+
* No currency, and this is a hard property rather than a style choice: the suite
|
|
188
|
+
* does not know the consumer's contract — subscription, per-token, committed
|
|
189
|
+
* spend, a reseller rate — so any monetary figure it printed would be
|
|
190
|
+
* extrapolated from a rate it invented. A fabricated cost is worse than none,
|
|
191
|
+
* because it is actionable and wrong.
|
|
192
|
+
*
|
|
193
|
+
* {@link CURRENCY_MARKERS} is what the test asserts against, so the ban is
|
|
194
|
+
* checkable rather than merely intended.
|
|
195
|
+
*/
|
|
196
|
+
export const CURRENCY_MARKERS = ['$', '€', '£', '¥', 'USD', 'EUR', 'GBP', '/1k', 'per token', 'per-token'] as const;
|
|
197
|
+
|
|
198
|
+
export function summaryLine(deliveredTokens: number, split: BillableSplit | null): string {
|
|
199
|
+
const share =
|
|
200
|
+
split === null || split.cache_read_share === null
|
|
201
|
+
? 'cache-read share unavailable'
|
|
202
|
+
: `cache-read share ${(split.cache_read_share * 100).toFixed(1)}%`;
|
|
203
|
+
return `Delivered standing payload: ${String(deliveredTokens)} tok · ${share}`;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/** True when a rendered string carries no currency figure or per-token rate. */
|
|
207
|
+
export function isCurrencyFree(text: string): boolean {
|
|
208
|
+
return !CURRENCY_MARKERS.some((m) => text.includes(m));
|
|
209
|
+
}
|
|
@@ -94,6 +94,12 @@ export function synthesizeAiCouncilBlock(cfg: CouncilConfig): Dict {
|
|
|
94
94
|
strong_threshold: cfg.consensus_scoring.strong_threshold,
|
|
95
95
|
minority_threshold: cfg.consensus_scoring.minority_threshold,
|
|
96
96
|
lenses: [...cfg.consensus_scoring.lenses],
|
|
97
|
+
// Phase 1B. Omitting it here is not a missing default — it is the key
|
|
98
|
+
// becoming UNREADABLE: `inlineFindingsActive` reads this projected
|
|
99
|
+
// dict, not the typed config, so an absent key resolves to `false` and
|
|
100
|
+
// the feature is silently off no matter what the YAML says. A live
|
|
101
|
+
// analysis run on 2026-08-30 is what found it, after the tests passed.
|
|
102
|
+
inline_findings: cfg.consensus_scoring.inline_findings,
|
|
97
103
|
},
|
|
98
104
|
cli_call_budget: {
|
|
99
105
|
max_calls_per_day: _mapToObject(cfg.cli_call_budget.max_calls_per_day),
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The curator's operation set — SEVEN ops per decision E6 — and the
|
|
3
|
+
* deterministic near-duplicate pre-stage that runs before any model judgment.
|
|
4
|
+
*
|
|
5
|
+
* `road-to-governed-harness-evolution` Phase 5, step 5.5.
|
|
6
|
+
*
|
|
7
|
+
* > *Curator operation set per E6. Candidates only, never promotions. Run
|
|
8
|
+
* > `src/scripts/_lib/shingle_similarity.ts` as a deterministic pre-stage
|
|
9
|
+
* > before any model judgment.*
|
|
10
|
+
* > verify: **a near-duplicate candidate is caught by the similarity stage with
|
|
11
|
+
* > zero model calls.**
|
|
12
|
+
*
|
|
13
|
+
* ## Seven, and why the middle answer was rejected
|
|
14
|
+
*
|
|
15
|
+
* E6 (decided 2026-08-30, AI council, anthropic + openai, 2/2) settled this on
|
|
16
|
+
* a contradiction rather than a preference: step 7.6 of the same roadmap
|
|
17
|
+
* already specifies the verdict set `KEEP / REVISE / MERGE / SPLIT / RETIRE`,
|
|
18
|
+
* so a four-op curator would emit verdicts it cannot execute. The six-op middle
|
|
19
|
+
* — deferring `SPLIT` — was rejected explicitly: it still contradicts 7.6, so
|
|
20
|
+
* it buys nothing the four-op answer does not also cost. The algebra argument
|
|
21
|
+
* is the one worth carrying: `MERGE` is n→1 and `SPLIT` is 1→n, and without
|
|
22
|
+
* `SPLIT` an overgrown rule becoming two must be written as
|
|
23
|
+
* `RETIRE + 2 x ADD`, which loses the semantic link and makes the intent
|
|
24
|
+
* unreadable in the audit log. {@link validateOp} encodes exactly that arity.
|
|
25
|
+
*
|
|
26
|
+
* ## Candidates only — carried by the type, not by a promise
|
|
27
|
+
*
|
|
28
|
+
* Every screened proposal carries `lifecycle: 'candidate'` as a LITERAL type,
|
|
29
|
+
* so there is no value a curator can construct that names any other lifecycle.
|
|
30
|
+
* Phase 7 is gated on the OPEN `merge-authority` blocker; a curator that could
|
|
31
|
+
* express a promotion would be one edit from performing one.
|
|
32
|
+
*
|
|
33
|
+
* ## Zero model calls, and how that is established rather than asserted
|
|
34
|
+
*
|
|
35
|
+
* {@link screenNearDuplicates} is synchronous, imports only
|
|
36
|
+
* `shingle_similarity`, and returns `model_calls: 0` as a literal-typed field.
|
|
37
|
+
* `tests/scripts/curator_ops.test.ts` proves the property two ways: it scans
|
|
38
|
+
* this module and its one dependency for network and model-client constructs in
|
|
39
|
+
* both polarities, and it runs the screen with `globalThis.fetch` replaced by a
|
|
40
|
+
* throwing stub, so a call would surface as a thrown error rather than as an
|
|
41
|
+
* unchecked assumption. An assertion by inspection would be worth nothing here
|
|
42
|
+
* — the whole point of a deterministic pre-stage is that it is cheaper than the
|
|
43
|
+
* judgment it precedes.
|
|
44
|
+
*/
|
|
45
|
+
import { shingleOverlap } from './shingle_similarity.js';
|
|
46
|
+
|
|
47
|
+
/** E6, option B. The exact set — arity and membership are both pinned by the test. */
|
|
48
|
+
export const CURATOR_OPS = [
|
|
49
|
+
'KEEP',
|
|
50
|
+
'ADD',
|
|
51
|
+
'MERGE',
|
|
52
|
+
'REPLACE',
|
|
53
|
+
'SPLIT',
|
|
54
|
+
'RETIRE',
|
|
55
|
+
'SKIP',
|
|
56
|
+
] as const;
|
|
57
|
+
|
|
58
|
+
export type CuratorOp = (typeof CURATOR_OPS)[number];
|
|
59
|
+
|
|
60
|
+
export interface CuratorProposal {
|
|
61
|
+
id: string;
|
|
62
|
+
op: CuratorOp;
|
|
63
|
+
/** Existing artifact ids the op reads or consumes. */
|
|
64
|
+
targets: readonly string[];
|
|
65
|
+
/** Artifact ids the op would produce. Empty for read-only ops. */
|
|
66
|
+
produces: readonly string[];
|
|
67
|
+
/** The proposed text, which is what the similarity stage compares. */
|
|
68
|
+
text: string;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Arity per op. `null` means the op places no constraint on that side. */
|
|
72
|
+
const OP_ARITY: Record<CuratorOp, { targets: [number, number | null]; produces: [number, number | null] }> = {
|
|
73
|
+
KEEP: { targets: [1, 1], produces: [0, 0] },
|
|
74
|
+
ADD: { targets: [0, 0], produces: [1, 1] },
|
|
75
|
+
MERGE: { targets: [2, null], produces: [1, 1] },
|
|
76
|
+
REPLACE: { targets: [1, 1], produces: [1, 1] },
|
|
77
|
+
SPLIT: { targets: [1, 1], produces: [2, null] },
|
|
78
|
+
RETIRE: { targets: [1, 1], produces: [0, 0] },
|
|
79
|
+
SKIP: { targets: [0, null], produces: [0, 0] },
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
function arityError(label: string, n: number, [lo, hi]: [number, number | null]): string | null {
|
|
83
|
+
if (n < lo) return `${label}: expected at least ${String(lo)}, got ${String(n)}`;
|
|
84
|
+
if (hi !== null && n > hi) return `${label}: expected at most ${String(hi)}, got ${String(n)}`;
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** `null` when the proposal's arity matches its op, otherwise the reason it does not. */
|
|
89
|
+
export function validateOp(p: CuratorProposal): string | null {
|
|
90
|
+
const spec = OP_ARITY[p.op];
|
|
91
|
+
return (
|
|
92
|
+
arityError(`${p.op} targets`, p.targets.length, spec.targets) ??
|
|
93
|
+
arityError(`${p.op} produces`, p.produces.length, spec.produces)
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Containment-overlap percent at which a proposal is a near-duplicate.
|
|
99
|
+
*
|
|
100
|
+
* A STATED default, not a measured optimum: `lint_originality`'s own gate uses
|
|
101
|
+
* shingle containment on the same primitive, and 70 % is the conservative end
|
|
102
|
+
* of the range a reskin scores there. `revisit-if` a screening run rejects a
|
|
103
|
+
* proposal a curator then has to re-add by hand, or admits one a human calls a
|
|
104
|
+
* duplicate.
|
|
105
|
+
*/
|
|
106
|
+
export const NEAR_DUPLICATE_THRESHOLD = 70;
|
|
107
|
+
|
|
108
|
+
export interface CorpusEntry {
|
|
109
|
+
id: string;
|
|
110
|
+
text: string;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export interface NearDuplicateFinding {
|
|
114
|
+
proposal_id: string;
|
|
115
|
+
/** The corpus entry it duplicates. */
|
|
116
|
+
against: string;
|
|
117
|
+
overlap_percent: number;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export interface ScreenedProposal {
|
|
121
|
+
proposal: CuratorProposal;
|
|
122
|
+
/** Literal. There is no other value this field can hold. */
|
|
123
|
+
lifecycle: 'candidate';
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export interface ScreenResult {
|
|
127
|
+
admitted: readonly ScreenedProposal[];
|
|
128
|
+
near_duplicates: readonly NearDuplicateFinding[];
|
|
129
|
+
malformed: readonly { proposal_id: string; reason: string }[];
|
|
130
|
+
/** Literal 0. The stage is deterministic; a model call here would be a defect. */
|
|
131
|
+
model_calls: 0;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* The deterministic pre-stage: reject malformed ops and near-duplicates before
|
|
136
|
+
* anything expensive runs.
|
|
137
|
+
*
|
|
138
|
+
* Synchronous on purpose — a synchronous function cannot await a network call,
|
|
139
|
+
* so the zero-model-call property is a consequence of the signature rather than
|
|
140
|
+
* a claim the body has to keep.
|
|
141
|
+
*/
|
|
142
|
+
export function screenNearDuplicates(
|
|
143
|
+
proposals: readonly CuratorProposal[],
|
|
144
|
+
corpus: readonly CorpusEntry[],
|
|
145
|
+
threshold: number = NEAR_DUPLICATE_THRESHOLD,
|
|
146
|
+
): ScreenResult {
|
|
147
|
+
const admitted: ScreenedProposal[] = [];
|
|
148
|
+
const nearDuplicates: NearDuplicateFinding[] = [];
|
|
149
|
+
const malformed: { proposal_id: string; reason: string }[] = [];
|
|
150
|
+
|
|
151
|
+
for (const p of proposals) {
|
|
152
|
+
const shapeError = validateOp(p);
|
|
153
|
+
if (shapeError !== null) {
|
|
154
|
+
malformed.push({ proposal_id: p.id, reason: shapeError });
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
let worst: NearDuplicateFinding | null = null;
|
|
158
|
+
for (const entry of corpus) {
|
|
159
|
+
const overlap = shingleOverlap(p.text, entry.text);
|
|
160
|
+
if (overlap >= threshold && (worst === null || overlap > worst.overlap_percent)) {
|
|
161
|
+
worst = { proposal_id: p.id, against: entry.id, overlap_percent: overlap };
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
if (worst !== null) {
|
|
165
|
+
nearDuplicates.push(worst);
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
admitted.push({ proposal: p, lifecycle: 'candidate' });
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return { admitted, near_duplicates: nearDuplicates, malformed, model_calls: 0 };
|
|
172
|
+
}
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The three-arm delivery experiment — `road-to-governed-harness-evolution` 6.1.
|
|
3
|
+
*
|
|
4
|
+
* WHAT 6.1 ASKS, AND WHY IT IS NOT THE PRICE GRID. Step 6.1 says: measure
|
|
5
|
+
* `eager-all` against `thin` against `delivery` — the three values
|
|
6
|
+
* `_lib/lean_projection_mode.ts:19` already declares — BEFORE any new retrieval
|
|
7
|
+
* component is written. `model_rule_injection.ts` already prices those three
|
|
8
|
+
* shapes, and a price grid is a cost model rather than a delivery measurement:
|
|
9
|
+
* it reports what each shape COSTS and never what each shape DELIVERS. The
|
|
10
|
+
* three arms differ on exactly one observable, and it is not cost:
|
|
11
|
+
*
|
|
12
|
+
* for a given prompt, is the labelled rule's BODY in the model's context?
|
|
13
|
+
*
|
|
14
|
+
* That question is decidable from the tree, so this module answers it for all
|
|
15
|
+
* three arms over one corpus with one matcher, and reports the cost figures
|
|
16
|
+
* beside it so the arms are commensurable on one table.
|
|
17
|
+
*
|
|
18
|
+
* WHAT EACH ARM PUTS IN CONTEXT, read off the two consumers of the mode rather
|
|
19
|
+
* than assumed. `condense.ts:1124` calls `writesThinFiles(mode)`, so `thin` and
|
|
20
|
+
* `delivery` project pointer stubs where `eager-all` projects bodies;
|
|
21
|
+
* `hooks/rule_inject_hook.ts:230` calls `deliversBodies(mode)`, so only
|
|
22
|
+
* `delivery` binds the concern that injects matched bodies back at prompt time.
|
|
23
|
+
* Hence:
|
|
24
|
+
*
|
|
25
|
+
* eager-all every projected body is standing.
|
|
26
|
+
* thin kernel bodies + no-trigger residue bodies are standing; every
|
|
27
|
+
* other body is a pointer and is NOT in context. Nothing is
|
|
28
|
+
* injected, because the concern is not bound.
|
|
29
|
+
* delivery thin's standing set, PLUS the bodies `selectForInjection`
|
|
30
|
+
* returns for this prompt under the concern's byte cap.
|
|
31
|
+
*
|
|
32
|
+
* The `thin` standing set mirrors `standingCorpora` in `model_rule_injection.ts`
|
|
33
|
+
* — kernel or triggerless keeps a body, anything else becomes a pointer — so the
|
|
34
|
+
* delivery half and the cost half classify each rule the same way. Two
|
|
35
|
+
* classifications would be the "measures nothing" defect `_lib/rule_injection.ts`
|
|
36
|
+
* names in its own header.
|
|
37
|
+
*
|
|
38
|
+
* NO SECOND MATCHER, WHICH IS 6.2'S CONSTRAINT AND THIS MODULE'S TOO. Every
|
|
39
|
+
* match here comes from `matchTierRules`, and every selection from
|
|
40
|
+
* `selectForInjection` — both in `_lib/rule_injection.ts`, which owns no matcher
|
|
41
|
+
* of its own and wraps `_lib/router_match.ts`. This module imports nothing else
|
|
42
|
+
* that could answer "which rules fire on this prompt?", and
|
|
43
|
+
* `tests/scripts/single_matcher_preserved.test.ts` fails if it ever does.
|
|
44
|
+
*
|
|
45
|
+
* ZERO MODEL CALLS, and the property follows from the imports rather than from
|
|
46
|
+
* good behaviour: the only import is `_lib/rule_injection.js`, which reads files.
|
|
47
|
+
* Token counting and the standing-corpus sizes are PARAMETERS, not imports, so
|
|
48
|
+
* this module carries no tokenizer and no network surface at all.
|
|
49
|
+
*
|
|
50
|
+
* WHAT IT DOES NOT MEASURE, stated because the gap is the interesting half.
|
|
51
|
+
* It does not measure whether a session that RECEIVES a body behaves like a
|
|
52
|
+
* session that HAD it standing. That is not an expense this run declined to pay
|
|
53
|
+
* — the instrument is closed by ADR-202 (`docs/decisions/ADR-202-anchor-scoring-as-thin-quality-instrument.md`),
|
|
54
|
+
* whose status reads "instrument not achievable with available evaluators" at an
|
|
55
|
+
* inter-evaluator kappa of 0.472 against a registered floor of 0.800, with no
|
|
56
|
+
* third attempt licensed. Nothing printed here is evidence about quality.
|
|
57
|
+
*/
|
|
58
|
+
import {
|
|
59
|
+
kernelIds,
|
|
60
|
+
loadRuleBody,
|
|
61
|
+
matchTierRules,
|
|
62
|
+
selectForInjection,
|
|
63
|
+
triggerlessRuleIds,
|
|
64
|
+
type Router,
|
|
65
|
+
} from './rule_injection.js';
|
|
66
|
+
|
|
67
|
+
/** The three arms, named exactly as `LeanProjectionMode` declares them. */
|
|
68
|
+
export const ARMS = ['eager-all', 'thin', 'delivery'] as const;
|
|
69
|
+
export type ArmName = (typeof ARMS)[number];
|
|
70
|
+
|
|
71
|
+
/** The corpus fields this experiment reads. Structurally a `CorpusCase`. */
|
|
72
|
+
export interface LabelledCase {
|
|
73
|
+
readonly rule: string;
|
|
74
|
+
readonly prompt: string;
|
|
75
|
+
readonly openFiles: string[] | null;
|
|
76
|
+
readonly label: 'positive' | 'near_miss';
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export interface ArmRow {
|
|
80
|
+
readonly arm: ArmName;
|
|
81
|
+
/** Positives whose labelled rule body is in context under this arm. */
|
|
82
|
+
readonly delivered: number;
|
|
83
|
+
readonly positives: number;
|
|
84
|
+
/** Near-miss prompts whose labelled rule body is nevertheless in context. */
|
|
85
|
+
readonly falseContext: number;
|
|
86
|
+
readonly nearMisses: number;
|
|
87
|
+
/** Positives the matcher fired on but the byte cap then dropped. */
|
|
88
|
+
readonly capDropped: number;
|
|
89
|
+
/** Exact-BPE tokens standing in context before the first prompt. */
|
|
90
|
+
readonly standingTokens: number;
|
|
91
|
+
/** Mean exact-BPE tokens injected per positive prompt. */
|
|
92
|
+
readonly injectedMeanTokens: number;
|
|
93
|
+
/** Same, at the 90th percentile. */
|
|
94
|
+
readonly injectedP90Tokens: number;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export interface ArmExperimentInput {
|
|
98
|
+
readonly repoRoot: string;
|
|
99
|
+
readonly router: Router;
|
|
100
|
+
readonly cases: readonly LabelledCase[];
|
|
101
|
+
/** The concern's per-prompt byte cap. The sensitivity handle. */
|
|
102
|
+
readonly capBytes: number;
|
|
103
|
+
/** Standing exact-BPE tokens per arm, supplied by the caller. */
|
|
104
|
+
readonly standing: Readonly<Record<ArmName, number>>;
|
|
105
|
+
/** Exact-BPE tokenizer, injected so this module imports none. */
|
|
106
|
+
readonly tokensOf: (text: string) => number;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Ids whose FULL body is standing under `thin` and `delivery`.
|
|
111
|
+
*
|
|
112
|
+
* Kernel is standing by definition; a rule with no trigger cannot be delivered,
|
|
113
|
+
* so the projector keeps it eager under the thin shapes too.
|
|
114
|
+
*/
|
|
115
|
+
export function thinStandingIds(router: Router): Set<string> {
|
|
116
|
+
const ids = new Set<string>(kernelIds(router));
|
|
117
|
+
for (const id of triggerlessRuleIds(router)) ids.add(id);
|
|
118
|
+
return ids;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** Nearest-rank quantile over a copy. Deterministic. */
|
|
122
|
+
function quantile(values: readonly number[], q: number): number {
|
|
123
|
+
if (values.length === 0) return 0;
|
|
124
|
+
const s = [...values].sort((a, b) => a - b);
|
|
125
|
+
const idx = Math.min(s.length - 1, Math.max(0, Math.ceil(q * s.length) - 1));
|
|
126
|
+
return s[idx] as number;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function mean(values: readonly number[]): number {
|
|
130
|
+
if (values.length === 0) return 0;
|
|
131
|
+
return values.reduce((a, b) => a + b, 0) / values.length;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/** Ids projected with a real body file — the `eager-all` standing set. */
|
|
135
|
+
function hasBody(repoRoot: string, id: string): boolean {
|
|
136
|
+
return loadRuleBody(repoRoot, id) !== null;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Run the experiment. Pure over its inputs; two runs are byte-identical.
|
|
141
|
+
*
|
|
142
|
+
* One walk over the corpus computes all three arms, so no arm can be scored on
|
|
143
|
+
* a different case set than another.
|
|
144
|
+
*/
|
|
145
|
+
export function runArmExperiment(input: ArmExperimentInput): ArmRow[] {
|
|
146
|
+
const { repoRoot, router, cases, capBytes, standing, tokensOf } = input;
|
|
147
|
+
const thinStanding = thinStandingIds(router);
|
|
148
|
+
|
|
149
|
+
const delivered: Record<ArmName, number> = { 'eager-all': 0, thin: 0, delivery: 0 };
|
|
150
|
+
const falseContext: Record<ArmName, number> = { 'eager-all': 0, thin: 0, delivery: 0 };
|
|
151
|
+
let positives = 0;
|
|
152
|
+
let nearMisses = 0;
|
|
153
|
+
let capDropped = 0;
|
|
154
|
+
const injectedTokens: number[] = [];
|
|
155
|
+
|
|
156
|
+
for (const c of cases) {
|
|
157
|
+
const inEager = hasBody(repoRoot, c.rule);
|
|
158
|
+
const inThin = thinStanding.has(c.rule) && inEager;
|
|
159
|
+
|
|
160
|
+
const matches = matchTierRules(router, c.prompt, c.openFiles);
|
|
161
|
+
const sel = selectForInjection(repoRoot, matches, capBytes);
|
|
162
|
+
const injectedIds = new Set(sel.selected.map((m) => m.id));
|
|
163
|
+
const inDelivery = inThin || injectedIds.has(c.rule);
|
|
164
|
+
|
|
165
|
+
if (c.label === 'positive') {
|
|
166
|
+
positives += 1;
|
|
167
|
+
if (inEager) delivered['eager-all'] += 1;
|
|
168
|
+
if (inThin) delivered.thin += 1;
|
|
169
|
+
if (inDelivery) delivered.delivery += 1;
|
|
170
|
+
if (sel.dropped.some((m) => m.id === c.rule)) capDropped += 1;
|
|
171
|
+
let tokens = 0;
|
|
172
|
+
for (const m of sel.selected) tokens += tokensOf(loadRuleBody(repoRoot, m.id) ?? '');
|
|
173
|
+
injectedTokens.push(tokens);
|
|
174
|
+
} else {
|
|
175
|
+
nearMisses += 1;
|
|
176
|
+
if (inEager) falseContext['eager-all'] += 1;
|
|
177
|
+
if (inThin) falseContext.thin += 1;
|
|
178
|
+
if (inDelivery) falseContext.delivery += 1;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const injMean = Math.round(mean(injectedTokens));
|
|
183
|
+
const injP90 = quantile(injectedTokens, 0.9);
|
|
184
|
+
return ARMS.map((arm) => ({
|
|
185
|
+
arm,
|
|
186
|
+
delivered: delivered[arm],
|
|
187
|
+
positives,
|
|
188
|
+
falseContext: falseContext[arm],
|
|
189
|
+
nearMisses,
|
|
190
|
+
capDropped: arm === 'delivery' ? capDropped : 0,
|
|
191
|
+
standingTokens: standing[arm],
|
|
192
|
+
injectedMeanTokens: arm === 'delivery' ? injMean : 0,
|
|
193
|
+
injectedP90Tokens: arm === 'delivery' ? injP90 : 0,
|
|
194
|
+
}));
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function ratio(hits: number, total: number): string {
|
|
198
|
+
return total === 0 ? '—' : (hits / total).toFixed(3);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function signed(n: number): string {
|
|
202
|
+
return n > 0 ? `+${n}` : String(n);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Render the report. The pairwise deltas are printed, not left to the reader:
|
|
207
|
+
* "measured against one another" is a comparison, and a table of three
|
|
208
|
+
* independent rows is three measurements rather than one comparison.
|
|
209
|
+
*/
|
|
210
|
+
export function renderArmExperiment(rows: readonly ArmRow[], capBytes: number): string[] {
|
|
211
|
+
const by = new Map<ArmName, ArmRow>(rows.map((r) => [r.arm, r]));
|
|
212
|
+
const eager = by.get('eager-all') as ArmRow;
|
|
213
|
+
const thin = by.get('thin') as ArmRow;
|
|
214
|
+
const delivery = by.get('delivery') as ArmRow;
|
|
215
|
+
|
|
216
|
+
const out: string[] = [];
|
|
217
|
+
const push = (s: string): void => {
|
|
218
|
+
out.push(s);
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
push('── three-arm delivery experiment (road-to-governed-harness-evolution 6.1) ──');
|
|
222
|
+
push(
|
|
223
|
+
`arms = LeanProjectionMode (_lib/lean_projection_mode.ts:19) · ` +
|
|
224
|
+
`one corpus · one matcher (_lib/router_match.ts) · cap ${capBytes} B`,
|
|
225
|
+
);
|
|
226
|
+
push('');
|
|
227
|
+
push(' arm delivery(pos) false-context(near-miss) standing tok injected tok/prompt');
|
|
228
|
+
for (const r of rows) {
|
|
229
|
+
const inj =
|
|
230
|
+
r.arm === 'delivery'
|
|
231
|
+
? `mean ${r.injectedMeanTokens} p90 ${r.injectedP90Tokens}`
|
|
232
|
+
: '0';
|
|
233
|
+
push(
|
|
234
|
+
` ${r.arm.padEnd(12)} ${ratio(r.delivered, r.positives)} (${r.delivered}/${r.positives})`.padEnd(
|
|
235
|
+
33,
|
|
236
|
+
) +
|
|
237
|
+
`${ratio(r.falseContext, r.nearMisses)} (${r.falseContext}/${r.nearMisses})`.padEnd(27) +
|
|
238
|
+
`${r.standingTokens}`.padEnd(15) +
|
|
239
|
+
inj,
|
|
240
|
+
);
|
|
241
|
+
}
|
|
242
|
+
push('');
|
|
243
|
+
push('── pairwise deltas ──');
|
|
244
|
+
push(
|
|
245
|
+
` thin vs eager-all: delivery ${signed(thin.delivered - eager.delivered)} positives · ` +
|
|
246
|
+
`standing ${signed(thin.standingTokens - eager.standingTokens)} tok`,
|
|
247
|
+
);
|
|
248
|
+
push(
|
|
249
|
+
` delivery vs eager-all: delivery ${signed(delivery.delivered - eager.delivered)} positives · ` +
|
|
250
|
+
`standing ${signed(delivery.standingTokens - eager.standingTokens)} tok`,
|
|
251
|
+
);
|
|
252
|
+
push(
|
|
253
|
+
` delivery vs thin: delivery ${signed(delivery.delivered - thin.delivered)} positives · ` +
|
|
254
|
+
`standing ${signed(delivery.standingTokens - thin.standingTokens)} tok`,
|
|
255
|
+
);
|
|
256
|
+
push(` cap-dropped under delivery: ${delivery.capDropped} of ${delivery.positives} positives`);
|
|
257
|
+
push('');
|
|
258
|
+
push(
|
|
259
|
+
'This measures WHICH BODIES REACH CONTEXT and what they cost. It does not',
|
|
260
|
+
);
|
|
261
|
+
push(
|
|
262
|
+
'measure whether a delivered body behaves like a standing one — that instrument',
|
|
263
|
+
);
|
|
264
|
+
push('is closed by ADR-202 and this run does not reopen it.');
|
|
265
|
+
return out;
|
|
266
|
+
}
|