@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,299 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Guards for a harness-enforced bounded loop.
|
|
3
|
+
*
|
|
4
|
+
* `road-to-skill-ecosystem-runtime-enforcement` Phase 5, Steps 2-4. Three
|
|
5
|
+
* primitives the stop-event loop needs and did not have, each closing a failure
|
|
6
|
+
* that is invisible while it happens.
|
|
7
|
+
*
|
|
8
|
+
* Extracted rather than added to `run_continuation_hook.ts`: that file is 1,504
|
|
9
|
+
* lines and `check_source_size_budget` charges every line above 1,500, so the
|
|
10
|
+
* same code there would cost a budget it does not cost here. The seam also makes
|
|
11
|
+
* all three testable without a host payload.
|
|
12
|
+
*/
|
|
13
|
+
import * as fs from 'node:fs';
|
|
14
|
+
import * as path from 'node:path';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Write JSON atomically: temp file in the same directory, then rename.
|
|
18
|
+
*
|
|
19
|
+
* WHY THIS IS NOT A STYLE CHOICE. The file being written is the loop's
|
|
20
|
+
* ITERATION BUDGET. A direct `writeFileSync` that is interrupted — a crash, a
|
|
21
|
+
* full disk, a killed process — leaves a truncated file, the parser rejects it,
|
|
22
|
+
* and the loop reads "no state": the counter restarts at zero and **the cap
|
|
23
|
+
* stops bounding anything**. The failure mode of a non-atomic budget write is an
|
|
24
|
+
* unbounded loop, which is the exact thing the budget exists to prevent.
|
|
25
|
+
*
|
|
26
|
+
* Same directory for the temp file because `rename` is only atomic within a
|
|
27
|
+
* filesystem; a temp in `/tmp` can land on another one and degrade to copy+unlink.
|
|
28
|
+
*
|
|
29
|
+
* Never throws — a budget writer that throws turns an observability concern into
|
|
30
|
+
* a turn-end failure. Returns whether the write landed, and that return is
|
|
31
|
+
* load-bearing: a loop that could not persist its counter must not BLOCK,
|
|
32
|
+
* because there the ladder cannot bound it.
|
|
33
|
+
*/
|
|
34
|
+
export function atomicWriteJson(file: string, value: unknown): boolean {
|
|
35
|
+
const tmp = `${file}.${String(process.pid)}.tmp`;
|
|
36
|
+
try {
|
|
37
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
38
|
+
fs.writeFileSync(tmp, `${JSON.stringify(value)}\n`, 'utf8');
|
|
39
|
+
fs.renameSync(tmp, file);
|
|
40
|
+
return true;
|
|
41
|
+
} catch {
|
|
42
|
+
try {
|
|
43
|
+
fs.unlinkSync(tmp);
|
|
44
|
+
} catch {
|
|
45
|
+
/* the temp may never have been created; nothing to clean */
|
|
46
|
+
}
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Whole-LINE match against a marker — never a substring.
|
|
53
|
+
*
|
|
54
|
+
* The hazard is specific and cheap to hit: a transcript contains everything the
|
|
55
|
+
* agent said, INCLUDING quoted examples of the marker. A substring match lets a
|
|
56
|
+
* sentence like *"exit when you print RUN-COMPLETE"* terminate the run, and — the
|
|
57
|
+
* worse direction — lets a quoted marker inside a code fence extend one.
|
|
58
|
+
*
|
|
59
|
+
* Trailing whitespace is trimmed because a terminal or a JSON round-trip adds it;
|
|
60
|
+
* leading whitespace is trimmed for the same reason. Nothing ELSE on the line is
|
|
61
|
+
* tolerated: `RUN-COMPLETE (probably)` is not the marker.
|
|
62
|
+
*/
|
|
63
|
+
export function matchesWholeLine(text: string, marker: string): boolean {
|
|
64
|
+
if (marker === '') return false;
|
|
65
|
+
for (const line of text.split('\n')) {
|
|
66
|
+
if (line.trim() === marker) return true;
|
|
67
|
+
}
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** A dependency the loop cannot obtain, and therefore cannot iterate toward. */
|
|
72
|
+
export interface UnavailableDependency {
|
|
73
|
+
kind: 'credential' | 'binary' | 'permission' | 'quota' | 'service';
|
|
74
|
+
evidence: string;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Patterns that name a dependency the loop CANNOT close by trying again.
|
|
79
|
+
*
|
|
80
|
+
* Every entry corresponds to a hard-blocker class the rules already name
|
|
81
|
+
* (`context-hygiene` § hard-blocker classes). The list is deliberately short and
|
|
82
|
+
* literal: a general "looks like an error" heuristic would end runs on ordinary
|
|
83
|
+
* test failures, which is the opposite of the intent — those are exactly what a
|
|
84
|
+
* loop SHOULD iterate on.
|
|
85
|
+
*/
|
|
86
|
+
const DEPENDENCY_PATTERNS: readonly { kind: UnavailableDependency['kind']; re: RegExp }[] = [
|
|
87
|
+
{ kind: 'binary', re: /\b(?:command not found|is not recognized as an internal or external command)\b/i },
|
|
88
|
+
{ kind: 'credential', re: /\b(?:not (?:authenticated|logged in)|authentication (?:failed|required)|no credentials found)\b/i },
|
|
89
|
+
{ kind: 'credential', re: /\b(?:missing|unset|not set)\b[^\n]{0,40}\b(?:credential|token|api[_ -]?key|secret)\b/i },
|
|
90
|
+
{ kind: 'permission', re: /\b(?:permission denied|forbidden|403 forbidden)\b/i },
|
|
91
|
+
{ kind: 'quota', re: /\b(?:rate limit(?:ed| exceeded| reached)?|quota exceeded|429 too many requests|spend (?:cap|limit) reached)\b/i },
|
|
92
|
+
{ kind: 'service', re: /\b(?:5\d\d (?:internal )?server error|service unavailable|connection refused)\b/i },
|
|
93
|
+
];
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* How much of the transcript tail a caller should read before scanning it.
|
|
97
|
+
*
|
|
98
|
+
* The detector takes text, not a file, so the BYTE bound belongs to the read
|
|
99
|
+
* and the LINE bound (`tailLines`) belongs to the scan. Both exist and they
|
|
100
|
+
* bound different things: 64 KiB keeps an arbitrarily long transcript from
|
|
101
|
+
* being loaded whole, and the line count then keeps a stale failure from
|
|
102
|
+
* halting a run that already recovered.
|
|
103
|
+
*
|
|
104
|
+
* Exported rather than inlined at the one call site so the bound is visible
|
|
105
|
+
* beside the detector it feeds. A caller that reads the whole file and then
|
|
106
|
+
* passes it here is not wrong, only wasteful — the line bound still applies.
|
|
107
|
+
*/
|
|
108
|
+
export const DEPENDENCY_SCAN_BYTES = 64 * 1024;
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Find a dependency the run cannot obtain, from recent transcript text.
|
|
112
|
+
*
|
|
113
|
+
* Returns the FIRST match with the line that produced it, so a halt event can
|
|
114
|
+
* name what is missing instead of saying "blocked". A halt with no named
|
|
115
|
+
* dependency is a report the reader has to reconstruct.
|
|
116
|
+
*
|
|
117
|
+
* Scans the LAST `tailLines` lines only: an authentication failure from an hour
|
|
118
|
+
* ago that was then fixed must not halt the run now, and a transcript is
|
|
119
|
+
* append-only so recency is the whole signal.
|
|
120
|
+
*/
|
|
121
|
+
export function detectUnavailableDependency(
|
|
122
|
+
transcriptTail: string,
|
|
123
|
+
tailLines = 200,
|
|
124
|
+
): UnavailableDependency | null {
|
|
125
|
+
const lines = transcriptTail.split('\n');
|
|
126
|
+
const window = lines.slice(Math.max(0, lines.length - tailLines));
|
|
127
|
+
for (const line of window) {
|
|
128
|
+
for (const { kind, re } of DEPENDENCY_PATTERNS) {
|
|
129
|
+
if (re.test(line)) {
|
|
130
|
+
return { kind, evidence: line.trim().slice(0, 200) };
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* The machine-readable stall signal, derived from a run's open-step history.
|
|
139
|
+
*
|
|
140
|
+
* `road-to-skill-ecosystem-runtime-enforcement` Phase 6 Step 6, and it is what
|
|
141
|
+
* makes Phase 4's progress-primary ordering usable rather than aspirational: a
|
|
142
|
+
* consumer asking "is this run still making progress" had to re-derive the
|
|
143
|
+
* answer from a history array and a window constant, so every reader could
|
|
144
|
+
* derive it differently.
|
|
145
|
+
*
|
|
146
|
+
* Three levels rather than a boolean, because the ordering they enable is
|
|
147
|
+
* different:
|
|
148
|
+
*
|
|
149
|
+
* `progressing` — the newest reading is a NEW MINIMUM. This is the primary
|
|
150
|
+
* signal Phase 4 names: the budget may keep running.
|
|
151
|
+
* `flat` — no new minimum, but the window is not yet full or not yet
|
|
152
|
+
* uniform. Not stalled; simply not evidence of progress either.
|
|
153
|
+
* `stalled` — a full window of IDENTICAL readings. More of the same will
|
|
154
|
+
* not help, and raising the budget is the WRONG response — which is exactly
|
|
155
|
+
* what separates `stagnated` from `exhausted` in the terminal-state
|
|
156
|
+
* vocabulary.
|
|
157
|
+
*
|
|
158
|
+
* Pure over the history array, so a reader and the ladder cannot disagree.
|
|
159
|
+
*/
|
|
160
|
+
export type StallLevel = 'progressing' | 'flat' | 'stalled';
|
|
161
|
+
|
|
162
|
+
export interface StallSignal {
|
|
163
|
+
level: StallLevel;
|
|
164
|
+
/** How many of the most recent readings are identical. */
|
|
165
|
+
flatRun: number;
|
|
166
|
+
/** The lowest reading seen, i.e. the best progress this run has made. */
|
|
167
|
+
minimum: number | null;
|
|
168
|
+
/** True when the LAST reading equals the minimum and is strictly below the one before it. */
|
|
169
|
+
newMinimum: boolean;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export function stallSignal(history: readonly number[], window = 3): StallSignal {
|
|
173
|
+
if (history.length === 0) {
|
|
174
|
+
return { level: 'flat', flatRun: 0, minimum: null, newMinimum: false };
|
|
175
|
+
}
|
|
176
|
+
const last = history[history.length - 1] as number;
|
|
177
|
+
const minimum = Math.min(...history);
|
|
178
|
+
// Strictly below every EARLIER reading — not merely below the one before it.
|
|
179
|
+
// The weaker form calls a return to an already-reached minimum progress, so an
|
|
180
|
+
// oscillating run (5, 9, 5, 9, …) would look like it was advancing forever
|
|
181
|
+
// while closing nothing.
|
|
182
|
+
const earlier = history.slice(0, -1);
|
|
183
|
+
const newMinimum = earlier.length > 0 && last < Math.min(...earlier);
|
|
184
|
+
|
|
185
|
+
let flatRun = 1;
|
|
186
|
+
for (let i = history.length - 2; i >= 0; i -= 1) {
|
|
187
|
+
if (history[i] !== last) break;
|
|
188
|
+
flatRun += 1;
|
|
189
|
+
}
|
|
190
|
+
if (newMinimum) return { level: 'progressing', flatRun, minimum, newMinimum };
|
|
191
|
+
if (flatRun >= window) return { level: 'stalled', flatRun, minimum, newMinimum };
|
|
192
|
+
return { level: 'flat', flatRun, minimum, newMinimum };
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Read the transcript tail and name a dependency the run cannot obtain.
|
|
197
|
+
*
|
|
198
|
+
* Lives here rather than at the call site, beside the detector and the byte
|
|
199
|
+
* bound it uses. EXPORTED so the wiring is testable,
|
|
200
|
+
* which is the half that was actually broken: the inline version referenced a
|
|
201
|
+
* constant that did not exist, and because the read sits inside a `catch`
|
|
202
|
+
* that fail-opens to `null`, the ReferenceError was swallowed on every fire.
|
|
203
|
+
* The rung was dead and every pure `ladder()` test stayed green — a test over
|
|
204
|
+
* the decision function cannot see a caller that never computes the input.
|
|
205
|
+
*
|
|
206
|
+
* Fail-open is deliberate and unchanged: a detector that cannot read must not
|
|
207
|
+
* manufacture a halt. What changed is that "cannot read" is now the only way
|
|
208
|
+
* to reach `null` by accident.
|
|
209
|
+
*/
|
|
210
|
+
export function readUnavailableDependency(transcriptPath: string): UnavailableDependency | null {
|
|
211
|
+
try {
|
|
212
|
+
const raw = fs.readFileSync(transcriptPath, 'utf8');
|
|
213
|
+
return detectUnavailableDependency(raw.slice(-DEPENDENCY_SCAN_BYTES));
|
|
214
|
+
} catch {
|
|
215
|
+
return null;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// ---------------------------------------------------------------------------
|
|
220
|
+
// Rejected-tactic repetition
|
|
221
|
+
// ---------------------------------------------------------------------------
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Window and threshold for the repetition guard.
|
|
225
|
+
*
|
|
226
|
+
* Named constants, NOT a settings block. A configurable strategy preset is the
|
|
227
|
+
* shape this roadmap kills by name: presets multiply the states a reader has to
|
|
228
|
+
* reason about while the underlying question — "is this run going in circles?" —
|
|
229
|
+
* has one answer. Two numbers with a stated meaning are auditable; a tuning
|
|
230
|
+
* surface is not.
|
|
231
|
+
*/
|
|
232
|
+
export const SUPPRESSION_WINDOW = 8;
|
|
233
|
+
export const SUPPRESSION_REPEATS = 3;
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* One attempt the run has already made, reduced to what a detector may see.
|
|
237
|
+
*
|
|
238
|
+
* `tactic_id` is ID-SHAPED and that is the load-bearing property. `stallSignal`
|
|
239
|
+
* above keys on a NUMBER (the open-step count); this keys on an identity. The
|
|
240
|
+
* failure it catches is one the numeric detector cannot see at all: an agent
|
|
241
|
+
* that retries the same rejected approach while the surrounding prose changes
|
|
242
|
+
* every time. The open-step count moves, the wording moves, and the tactic is
|
|
243
|
+
* identical.
|
|
244
|
+
*/
|
|
245
|
+
export interface TacticAttempt {
|
|
246
|
+
/** Stable id for the approach tried. Lowercase alnum + hyphens; never prose. */
|
|
247
|
+
tactic_id: string;
|
|
248
|
+
/** Whether this attempt was rejected (by a gate, a test, a review, a human). */
|
|
249
|
+
rejected: boolean;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
export interface RepetitionSignal {
|
|
253
|
+
/** True when a rejected tactic has recurred at or above the threshold in-window. */
|
|
254
|
+
suppress: boolean;
|
|
255
|
+
/** The tactic that tripped it, or `null`. */
|
|
256
|
+
tactic_id: string | null;
|
|
257
|
+
/** How many rejected attempts of that tactic are in the window. */
|
|
258
|
+
repeats: number;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Has the run repeated a tactic that was already rejected?
|
|
263
|
+
*
|
|
264
|
+
* Counts only REJECTED attempts. A tactic tried three times and accepted twice
|
|
265
|
+
* is not a loop, it is a tactic that works — counting every attempt would fire
|
|
266
|
+
* on productive repetition, which is the false positive that gets a guard
|
|
267
|
+
* switched off.
|
|
268
|
+
*
|
|
269
|
+
* Deliberately blind to any signal string. The verify line this satisfies asks
|
|
270
|
+
* for suppression "even when the signal string differs", which is only
|
|
271
|
+
* achievable by keying on something else — so this function is given no text to
|
|
272
|
+
* read, rather than being trusted to ignore it.
|
|
273
|
+
*/
|
|
274
|
+
export function rejectedTacticRepeat(
|
|
275
|
+
history: readonly TacticAttempt[],
|
|
276
|
+
window: number = SUPPRESSION_WINDOW,
|
|
277
|
+
threshold: number = SUPPRESSION_REPEATS,
|
|
278
|
+
): RepetitionSignal {
|
|
279
|
+
const recent = history.slice(-window);
|
|
280
|
+
const counts = new Map<string, number>();
|
|
281
|
+
for (const a of recent) {
|
|
282
|
+
if (!a.rejected) continue;
|
|
283
|
+
counts.set(a.tactic_id, (counts.get(a.tactic_id) ?? 0) + 1);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
let worst: string | null = null;
|
|
287
|
+
let worstCount = 0;
|
|
288
|
+
for (const [id, n] of counts) {
|
|
289
|
+
if (n > worstCount) {
|
|
290
|
+
worst = id;
|
|
291
|
+
worstCount = n;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
if (worst !== null && worstCount >= threshold) {
|
|
296
|
+
return { suppress: true, tactic_id: worst, repeats: worstCount };
|
|
297
|
+
}
|
|
298
|
+
return { suppress: false, tactic_id: null, repeats: worstCount };
|
|
299
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Loss classes — names for what the tree already does, before they constrain
|
|
3
|
+
* what comes next (`road-to-runtime-context-floors` Phase 3).
|
|
4
|
+
*
|
|
5
|
+
* The tree already practises loss classes implicitly and has for a while:
|
|
6
|
+
* `fold_intake` folds intake batches into an ADDITIVE archive page with
|
|
7
|
+
* per-child link-backs and never mutates the children, and `hot_context_hook`
|
|
8
|
+
* deliberately DROPS lines the low-impact redactor refuses, unrecoverably, for
|
|
9
|
+
* privacy. Those are two different guarantees wearing the same word
|
|
10
|
+
* "compression", and nothing distinguished them.
|
|
11
|
+
*
|
|
12
|
+
* So the vocabulary is written AGAINST those two first, and checked against
|
|
13
|
+
* their own source docblocks, before any lint exists to fail on anything.
|
|
14
|
+
*
|
|
15
|
+
* THE FIVE CLASSES, each defined by the recovery it guarantees:
|
|
16
|
+
*
|
|
17
|
+
* exact output is byte-identical to input; nothing is lost
|
|
18
|
+
* lossless output differs but the input is fully reconstructible
|
|
19
|
+
* from the output alone
|
|
20
|
+
* recoverable-lossy output is smaller and the original is retrievable via a
|
|
21
|
+
* declared RECOVERY LOCATOR (a path, a range, an id)
|
|
22
|
+
* ephemeral-lossy output is smaller and the dropped content is gone —
|
|
23
|
+
* deliberately, and the deliberateness is the point
|
|
24
|
+
* forbidden this transform must not run on this path at all
|
|
25
|
+
*
|
|
26
|
+
* `recoverable-lossy` is the only class that owes a locator, and it owes one
|
|
27
|
+
* because without it the class is indistinguishable from `ephemeral-lossy` by
|
|
28
|
+
* anything except its author's intention.
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
export const LOSS_CLASSES = ['exact', 'lossless', 'recoverable-lossy', 'ephemeral-lossy', 'forbidden'] as const;
|
|
32
|
+
export type LossClass = (typeof LOSS_CLASSES)[number];
|
|
33
|
+
|
|
34
|
+
export function isLossClass(v: unknown): v is LossClass {
|
|
35
|
+
return typeof v === 'string' && (LOSS_CLASSES as readonly string[]).includes(v);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface LossDeclaration {
|
|
39
|
+
lossClass: LossClass;
|
|
40
|
+
/** Where the original is retrievable. Required for `recoverable-lossy`. */
|
|
41
|
+
recovery: string | null;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export type DeclarationProblem =
|
|
45
|
+
| { kind: 'missing' }
|
|
46
|
+
| { kind: 'unknown-class'; value: string }
|
|
47
|
+
| { kind: 'missing-recovery' };
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Read a declaration out of a module's own source.
|
|
51
|
+
*
|
|
52
|
+
* The declaration lives in a docblock, not in a sidecar registry, deliberately:
|
|
53
|
+
* a class describes what THIS code does to its input, and a registry entry
|
|
54
|
+
* beside it is a second statement that can drift from the first. Shape:
|
|
55
|
+
*
|
|
56
|
+
* loss_class: recoverable-lossy
|
|
57
|
+
* loss_recovery: agents/knowledge/intake/<file>:<first-line>-<last-line>
|
|
58
|
+
*/
|
|
59
|
+
export function parseLossDeclaration(source: string): LossDeclaration | DeclarationProblem {
|
|
60
|
+
// `[A-Za-z_-]+`, not `[A-Za-z-]+`: an underscore misspelling
|
|
61
|
+
// (`recoverable_lossy`) must be reported as `unknown-class`, not fall
|
|
62
|
+
// through to `missing`. Both reject, so the exit code is the same — but
|
|
63
|
+
// "declares no loss_class" sends an author who declared one hunting the
|
|
64
|
+
// wrong defect, which is the failure a diagnostic exists to prevent.
|
|
65
|
+
const cls = /^[\s*/]*loss_class:\s*([A-Za-z_-]+)\s*$/m.exec(source);
|
|
66
|
+
if (cls === null) return { kind: 'missing' };
|
|
67
|
+
const value = (cls[1] ?? '').trim();
|
|
68
|
+
if (!isLossClass(value)) return { kind: 'unknown-class', value };
|
|
69
|
+
|
|
70
|
+
const rec = /^[\s*/]*loss_recovery:\s*(\S.*?)\s*$/m.exec(source);
|
|
71
|
+
const recovery = rec === null ? null : (rec[1] ?? '').trim();
|
|
72
|
+
if (value === 'recoverable-lossy' && (recovery === null || recovery.length === 0)) {
|
|
73
|
+
return { kind: 'missing-recovery' };
|
|
74
|
+
}
|
|
75
|
+
return { lossClass: value, recovery };
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function isProblem(v: LossDeclaration | DeclarationProblem): v is DeclarationProblem {
|
|
79
|
+
return 'kind' in v;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// -------------------------------------------------------- passthrough (3.3)
|
|
83
|
+
|
|
84
|
+
/** Why a transform declined to transform. Never `null` on a passthrough. */
|
|
85
|
+
export type PassthroughReason = 'unparseable-input' | 'recovery-unavailable' | 'not-smaller';
|
|
86
|
+
|
|
87
|
+
export interface TransformOutcome {
|
|
88
|
+
output: string;
|
|
89
|
+
/** `null` when the transform actually ran. */
|
|
90
|
+
passthrough: PassthroughReason | null;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export interface TransformHooks {
|
|
94
|
+
/** Returns the shortened form, or `null` when the input cannot be parsed. */
|
|
95
|
+
transform: (input: string) => string | null;
|
|
96
|
+
/**
|
|
97
|
+
* Persist the recovery for `recoverable-lossy`. Returns `false` when the
|
|
98
|
+
* recovery cannot be stored. Omit for classes that owe no recovery.
|
|
99
|
+
*/
|
|
100
|
+
storeRecovery?: (input: string) => boolean;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* The passthrough invariant.
|
|
105
|
+
*
|
|
106
|
+
* > A transform that cannot parse its input, cannot store the recovery, or does
|
|
107
|
+
* > not make the input smaller returns the input unchanged.
|
|
108
|
+
*
|
|
109
|
+
* Degradation is never silent and never lossy. The two halves matter equally and
|
|
110
|
+
* are easy to get half-right: returning a partial parse is lossy degradation;
|
|
111
|
+
* returning the input while reporting success is silent degradation. This helper
|
|
112
|
+
* returns the input bytes AND the reason, so a caller cannot have one without the
|
|
113
|
+
* other.
|
|
114
|
+
*
|
|
115
|
+
* The `not-smaller` branch is the one that looks pedantic and is not. A
|
|
116
|
+
* "compression" that grew the input has paid the cost of the transform, lost
|
|
117
|
+
* whatever the transform dropped, and bought nothing — keeping the original is
|
|
118
|
+
* strictly better on every axis, so there is no case in which emitting the
|
|
119
|
+
* larger output is right.
|
|
120
|
+
*/
|
|
121
|
+
export function applyTransform(input: string, hooks: TransformHooks): TransformOutcome {
|
|
122
|
+
const out = hooks.transform(input);
|
|
123
|
+
if (out === null) return { output: input, passthrough: 'unparseable-input' };
|
|
124
|
+
if (hooks.storeRecovery !== undefined && !hooks.storeRecovery(input)) {
|
|
125
|
+
return { output: input, passthrough: 'recovery-unavailable' };
|
|
126
|
+
}
|
|
127
|
+
if (out.length >= input.length) return { output: input, passthrough: 'not-smaller' };
|
|
128
|
+
return { output: out, passthrough: null };
|
|
129
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Did a human type this turn?
|
|
3
|
+
*
|
|
4
|
+
* ```
|
|
5
|
+
* UNKNOWN ANSWERS YES. AN UNRECOGNISED PAYLOAD FALLS BACK TO TREATING THE TURN
|
|
6
|
+
* AS HUMAN — NEVER TO TREATING IT AS MACHINE. EVERY CONSUMER OF THIS PREDICATE
|
|
7
|
+
* GUARDS A PER-TURN RECORD, AND A RECORD WRONGLY RETAINED OUTLIVES THE TURN
|
|
8
|
+
* THAT AUTHORISED IT.
|
|
9
|
+
* ```
|
|
10
|
+
*
|
|
11
|
+
* **Why this lives in `_lib` rather than in one hook.** The misclassification is
|
|
12
|
+
* a property of the `user_prompt_submit` SLOT, not of any one concern: the host
|
|
13
|
+
* delivers a background task notification on the same slot as a typed prompt,
|
|
14
|
+
* so every concern that consumes or replaces per-turn state has the same defect.
|
|
15
|
+
* Two are known — the git-authorization ledger with its pending-refusal record,
|
|
16
|
+
* and the suggestion-capture latch. A predicate private to one of them would
|
|
17
|
+
* have repaired one and left the other, which is risk 4 of
|
|
18
|
+
* `road-to-turn-bound-authorization-integrity`.
|
|
19
|
+
*
|
|
20
|
+
* **The discriminator, quoted from a captured payload rather than from
|
|
21
|
+
* documentation.** `agents/runtime/.agent-chat-history` records prompts tagged
|
|
22
|
+
* `"source": "hook:claude:UserPromptSubmit"` — what the hook RECEIVED, not what
|
|
23
|
+
* the host stored in its transcript, and those are not guaranteed to be the same
|
|
24
|
+
* text. Measured 2026-08-27 in this project's capture: **9 of 16** hook-sourced
|
|
25
|
+
* user records begin with the literal `<task-notification>`, carrying
|
|
26
|
+
* `<task-id>`, `<tool-use-id>`, `<status>` and `<summary>` children. A typed
|
|
27
|
+
* turn carries none of them.
|
|
28
|
+
*
|
|
29
|
+
* **Prefix, not substring, and that is the whole care in this file.** A
|
|
30
|
+
* notification is a synthetic turn the host constructs, so the element opens it.
|
|
31
|
+
* Matching anywhere in the text would make the question "why did this
|
|
32
|
+
* `<task-notification>` clear my authorization?" clear it again — the user would
|
|
33
|
+
* lose the very turn they were asking about.
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
/** Wake shapes the host delivers on `user_prompt_submit` that no human typed. */
|
|
37
|
+
export const MACHINE_WAKE_PREFIXES: readonly string[] = [
|
|
38
|
+
'<task-notification>',
|
|
39
|
+
'<system-reminder>',
|
|
40
|
+
];
|
|
41
|
+
|
|
42
|
+
/** @see MACHINE_WAKE_PREFIXES — unknown shapes answer `true`, deliberately. */
|
|
43
|
+
export function humanTypedThisTurn(prompt: string): boolean {
|
|
44
|
+
const head = prompt.trimStart();
|
|
45
|
+
for (const prefix of MACHINE_WAKE_PREFIXES) {
|
|
46
|
+
if (head.startsWith(prefix)) {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared markdown line classifier — the frontmatter / fence / indented-code /
|
|
3
|
+
* marker skip machinery that decides which lines of a `.md` file are PROSE.
|
|
4
|
+
*
|
|
5
|
+
* ## Why this exists
|
|
6
|
+
*
|
|
7
|
+
* `check_md_language.ts` has carried this machinery since it was ported from
|
|
8
|
+
* Python (ADR-200), and its CLI contract is pinned byte-for-byte. When
|
|
9
|
+
* `road-to-canonical-terms` 2.2 called for a second prose-scanning gate it said
|
|
10
|
+
* explicitly: reuse that machinery "rather than a second copy of it". A second
|
|
11
|
+
* copy is how two gates end up disagreeing about what a fence is — one of them
|
|
12
|
+
* flags a word inside a code block and the other does not, and nobody can say
|
|
13
|
+
* which is right because there is no single definition to consult.
|
|
14
|
+
*
|
|
15
|
+
* So the classifier moved here verbatim and both callers read it. The
|
|
16
|
+
* behaviour is unchanged on purpose: `check_md_language`'s test suite pins the
|
|
17
|
+
* exact finding list, and this extraction is a refactor that must not move it.
|
|
18
|
+
*
|
|
19
|
+
* ## What counts as a skip, and what does not
|
|
20
|
+
*
|
|
21
|
+
* - **frontmatter** — a `---` fence opening on line 1 and everything to its close.
|
|
22
|
+
* - **fence** — ``` or ~~~ toggles, and every line between them. The fence
|
|
23
|
+
* markers themselves are skipped too.
|
|
24
|
+
* - **indented-code** — four leading spaces on a line that does not start a
|
|
25
|
+
* list item. Markdown's indented-code rule, with the list carve-out this
|
|
26
|
+
* tree's own deeply-nested bullets need.
|
|
27
|
+
* - **marker** — a caller-supplied per-line opt-out (`<!-- x: ignore -->`) or a
|
|
28
|
+
* labelled bilingual anchor. Callers pass their own patterns; the module has
|
|
29
|
+
* no opinion about which markers exist.
|
|
30
|
+
*
|
|
31
|
+
* Everything else is prose, and prose carries `text` with inline code spans
|
|
32
|
+
* blanked out — because a word named inside backticks is being QUOTED, not used.
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
/** What a classifier pass decided about one line. */
|
|
36
|
+
export type MarkdownLineKind =
|
|
37
|
+
| 'frontmatter'
|
|
38
|
+
| 'fence'
|
|
39
|
+
| 'indented-code'
|
|
40
|
+
| 'marker'
|
|
41
|
+
| 'prose';
|
|
42
|
+
|
|
43
|
+
export interface MarkdownLine {
|
|
44
|
+
/** 1-based line number, matching every editor and every gate message. */
|
|
45
|
+
lineno: number;
|
|
46
|
+
/** The line exactly as it appears in the file. */
|
|
47
|
+
raw: string;
|
|
48
|
+
kind: MarkdownLineKind;
|
|
49
|
+
/**
|
|
50
|
+
* Scannable text — the raw line with inline code spans removed. Only
|
|
51
|
+
* meaningful when `kind === 'prose'`; empty string otherwise.
|
|
52
|
+
*/
|
|
53
|
+
text: string;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export interface MarkdownScanOptions {
|
|
57
|
+
/**
|
|
58
|
+
* Per-line skip patterns tested against the RAW line. A match classifies
|
|
59
|
+
* the line `marker`. Callers own their own markers; this module ships none.
|
|
60
|
+
*/
|
|
61
|
+
markers?: readonly RegExp[];
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** Inline code spans — a term inside backticks is named, not used. */
|
|
65
|
+
const INLINE_CODE_RE = /`[^`]*`/g;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Python `str.splitlines()` — universal-newline split with no trailing empty
|
|
69
|
+
* element. Kept identical to the version `check_md_language` was ported with,
|
|
70
|
+
* because its line numbers are part of that gate's pinned output.
|
|
71
|
+
*/
|
|
72
|
+
export function splitlines(text: string): string[] {
|
|
73
|
+
if (text === '') return [];
|
|
74
|
+
const lines: string[] = [];
|
|
75
|
+
let current = '';
|
|
76
|
+
for (let i = 0; i < text.length; i++) {
|
|
77
|
+
const ch = text[i] as string;
|
|
78
|
+
const code = text.charCodeAt(i);
|
|
79
|
+
if (ch === '\r') {
|
|
80
|
+
lines.push(current);
|
|
81
|
+
current = '';
|
|
82
|
+
if (text[i + 1] === '\n') i += 1; // \r\n consumed as one
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
if (
|
|
86
|
+
ch === '\n' ||
|
|
87
|
+
code === 0x0b ||
|
|
88
|
+
code === 0x0c ||
|
|
89
|
+
code === 0x1c ||
|
|
90
|
+
code === 0x1d ||
|
|
91
|
+
code === 0x1e ||
|
|
92
|
+
code === 0x85 ||
|
|
93
|
+
code === 0x2028 ||
|
|
94
|
+
code === 0x2029
|
|
95
|
+
) {
|
|
96
|
+
lines.push(current);
|
|
97
|
+
current = '';
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
current += ch;
|
|
101
|
+
}
|
|
102
|
+
if (current !== '') lines.push(current);
|
|
103
|
+
return lines;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/** Blank out inline code spans so a quoted term is not read as a used one. */
|
|
107
|
+
export function stripInlineCode(text: string): string {
|
|
108
|
+
return text.replace(INLINE_CODE_RE, '');
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function lstrip(s: string): string {
|
|
112
|
+
return s.replace(/^\s+/, '');
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Classify every line of a markdown document.
|
|
117
|
+
*
|
|
118
|
+
* Pure over the content string — no filesystem access — so a caller can test
|
|
119
|
+
* the classification from a literal without a repo.
|
|
120
|
+
*/
|
|
121
|
+
export function classifyMarkdownLines(
|
|
122
|
+
content: string,
|
|
123
|
+
opts: MarkdownScanOptions = {},
|
|
124
|
+
): MarkdownLine[] {
|
|
125
|
+
const markers = opts.markers ?? [];
|
|
126
|
+
const out: MarkdownLine[] = [];
|
|
127
|
+
const lines = splitlines(content);
|
|
128
|
+
|
|
129
|
+
let inFence = false;
|
|
130
|
+
let inFrontmatter = false;
|
|
131
|
+
|
|
132
|
+
for (let idx = 0; idx < lines.length; idx++) {
|
|
133
|
+
const raw = lines[idx] as string;
|
|
134
|
+
const lineno = idx + 1;
|
|
135
|
+
const stripped = lstrip(raw);
|
|
136
|
+
|
|
137
|
+
// YAML frontmatter at the top of the file.
|
|
138
|
+
if (lineno === 1 && stripped === '---') {
|
|
139
|
+
inFrontmatter = true;
|
|
140
|
+
out.push({ lineno, raw, kind: 'frontmatter', text: '' });
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
if (inFrontmatter) {
|
|
144
|
+
if (stripped === '---') inFrontmatter = false;
|
|
145
|
+
out.push({ lineno, raw, kind: 'frontmatter', text: '' });
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Fenced code blocks — the markers themselves are skipped too.
|
|
150
|
+
if (stripped.startsWith('```') || stripped.startsWith('~~~')) {
|
|
151
|
+
inFence = !inFence;
|
|
152
|
+
out.push({ lineno, raw, kind: 'fence', text: '' });
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
if (inFence) {
|
|
156
|
+
out.push({ lineno, raw, kind: 'fence', text: '' });
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Indented code blocks (4+ leading spaces, non-list).
|
|
161
|
+
const listStarts = ['-', '*', '+', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
|
|
162
|
+
if (raw.startsWith(' ') && !listStarts.some((c) => stripped.startsWith(c))) {
|
|
163
|
+
out.push({ lineno, raw, kind: 'indented-code', text: '' });
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Caller-supplied per-line markers.
|
|
168
|
+
if (markers.some((re) => { re.lastIndex = 0; return re.test(raw); })) {
|
|
169
|
+
out.push({ lineno, raw, kind: 'marker', text: '' });
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
out.push({ lineno, raw, kind: 'prose', text: stripInlineCode(raw) });
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return out;
|
|
177
|
+
}
|