@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
|
@@ -1,17 +1,36 @@
|
|
|
1
1
|
#!/usr/bin/env tsx
|
|
2
|
+
/*
|
|
3
|
+
* TEMPLATE COPY — reconciled with `src/scripts/check_memory.ts` on 2026-08-26
|
|
4
|
+
* (`road-to-memory-twin-reconciliation` 2.2, verdict `dev-side-correct`).
|
|
5
|
+
*
|
|
6
|
+
* TWO differences remain, and both are `keep-duplicated` for the same
|
|
7
|
+
* STRUCTURAL reason rather than by preference: the installed consumer tree has
|
|
8
|
+
* no `scripts/_lib/`, so a template script may import node built-ins, `yaml`
|
|
9
|
+
* and its own installed siblings — nothing else.
|
|
10
|
+
*
|
|
11
|
+
* - `assertScanned` (`_lib/scan_scope.js`), the dead-scope guard. Not
|
|
12
|
+
* importable here, and its absence is safe in the direction that matters:
|
|
13
|
+
* a consumer with no `agents/memory/` scans zero and passes, which is the
|
|
14
|
+
* correct reading for a project that keeps no memory.
|
|
15
|
+
* - `asOf` (`_lib/as_of.js`), the reproducible-clock pin behind this
|
|
16
|
+
* repository's own `AC_AS_OF` discipline. A consumer has no such pin, so
|
|
17
|
+
* `new Date()` is the right substitute rather than a downgrade.
|
|
18
|
+
*
|
|
19
|
+
* Everything else is identical, INCLUDING the validations this copy used to
|
|
20
|
+
* lack entirely: the `priority` enum, the critical-stale SLA, the one-fact
|
|
21
|
+
* length limit, relative-date discipline, per-type caps, tier-0 inflation, and
|
|
22
|
+
* `status: superseded`.
|
|
23
|
+
*/
|
|
2
24
|
/**
|
|
3
25
|
* Engineering Memory validator.
|
|
4
26
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* `--base`), same exit codes, same stdout/stderr split, byte-identical finding
|
|
13
|
-
* messages, same scan scope and ordering. No behaviour changes — latent bugs
|
|
14
|
-
* are replicated and flagged in the porting report, not fixed.
|
|
27
|
+
* Ported from the retired Python `src/scripts/check_memory.py` (ADR-200, Phase 4 /
|
|
28
|
+
* Wave 4a). The CLI contract pins the historical contract exactly — same
|
|
29
|
+
* flags (`--path`, `--format`, `--append-only`, `--base`), same exit
|
|
30
|
+
* codes, same stdout/stderr split,
|
|
31
|
+
* byte-identical finding messages, same scan scope and ordering. No
|
|
32
|
+
* behaviour changes — latent bugs are replicated and flagged in the
|
|
33
|
+
* porting report, not fixed.
|
|
15
34
|
*
|
|
16
35
|
* Validates YAML files under `agents/memory/<type>/**\/*.yml` against the
|
|
17
36
|
* schema documented in `guidelines/agent-infra/engineering-memory-data-format`.
|
|
@@ -39,7 +58,7 @@
|
|
|
39
58
|
* check_memory --append-only # CI: diff vs origin/main
|
|
40
59
|
* check_memory --append-only --base HEAD~1
|
|
41
60
|
*
|
|
42
|
-
* Note on YAML date typing: the Python
|
|
61
|
+
* Note on YAML date typing: the retired Python implementation relies on PyYAML's
|
|
43
62
|
* `safe_load` converting unquoted `YYYY-MM-DD` scalars to `datetime.date`
|
|
44
63
|
* (and `YYYY-MM-DD HH:MM:SS` to `datetime.datetime`). The `yaml` npm
|
|
45
64
|
* package parses every scalar to a string, so this twin re-implements
|
|
@@ -56,6 +75,7 @@ import process from 'node:process';
|
|
|
56
75
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
57
76
|
import YAML, { parseDocument } from 'yaml';
|
|
58
77
|
|
|
78
|
+
|
|
59
79
|
type Severity = 'error' | 'warning' | 'info';
|
|
60
80
|
|
|
61
81
|
const REQUIRED_KEYS: ReadonlySet<string> = new Set([
|
|
@@ -67,14 +87,48 @@ const REQUIRED_KEYS: ReadonlySet<string> = new Set([
|
|
|
67
87
|
'last_validated',
|
|
68
88
|
'review_after_days',
|
|
69
89
|
]);
|
|
70
|
-
const VALID_STATUS: ReadonlySet<string> = new Set(['active', 'deprecated', 'archived']);
|
|
90
|
+
const VALID_STATUS: ReadonlySet<string> = new Set(['active', 'deprecated', 'archived', 'superseded']);
|
|
71
91
|
const VALID_CONFIDENCE: ReadonlySet<string> = new Set(['low', 'medium', 'high']);
|
|
92
|
+
// `priority` is optional (default `normal`); enum is the smallest set that
|
|
93
|
+
// solves the tier-0 surfacing use case. See the Phase 2 council brief for why
|
|
94
|
+
// the `high` tier was rejected.
|
|
95
|
+
const VALID_PRIORITY: ReadonlySet<string> = new Set(['critical', 'normal', 'low']);
|
|
96
|
+
// Soft-cap on `priority: critical` entries per memory type. Tier-0 inflation
|
|
97
|
+
// is the failure mode: when too many entries claim "always surface", the
|
|
98
|
+
// slice loses signal. Warn (not fail) when the cap is exceeded so curators
|
|
99
|
+
// notice without being blocked.
|
|
100
|
+
const CRITICAL_WARN_THRESHOLD = 10;
|
|
101
|
+
// Stale-critical guard: a `priority: critical` entry that hasn't been
|
|
102
|
+
// re-validated in this many days emits a warning. Surfaced separately
|
|
103
|
+
// from the generic `stale:` info so reviewers see it before merge.
|
|
104
|
+
const CRITICAL_STALE_DAYS = 90;
|
|
72
105
|
const KNOWN_TYPES: ReadonlySet<string> = new Set([
|
|
73
106
|
'domain-invariants',
|
|
107
|
+
'historical-patterns',
|
|
74
108
|
'incident-learnings',
|
|
109
|
+
'ownership',
|
|
75
110
|
'product-rules',
|
|
76
111
|
]);
|
|
77
112
|
|
|
113
|
+
// Per-type soft entry cap (size-bounding without a decay engine). Over-cap →
|
|
114
|
+
// warning, never a hard fail: the right answer to bloat is a consolidation pass
|
|
115
|
+
// (prune archived, merge duplicates), not CI failure. See
|
|
116
|
+
// road-to-memory-pipeline-consolidation.md Phase 7.
|
|
117
|
+
const PER_TYPE_CAPS: Readonly<Record<string, number>> = {
|
|
118
|
+
ownership: 50,
|
|
119
|
+
'domain-invariants': 150,
|
|
120
|
+
'product-rules': 100,
|
|
121
|
+
'incident-learnings': 150,
|
|
122
|
+
'historical-patterns': 150,
|
|
123
|
+
};
|
|
124
|
+
const DEFAULT_TYPE_CAP = 150;
|
|
125
|
+
// One-durable-fact-per-entry: a content field longer than this reads as a
|
|
126
|
+
// transcript / narrative blob, not a single durable fact → warning.
|
|
127
|
+
const ONE_FACT_MAX_CHARS = 600;
|
|
128
|
+
const ONE_FACT_FIELDS = ['rule', 'pattern', 'statement', 'observation', 'body', 'decision', 'note'] as const;
|
|
129
|
+
// Per-type entry tally, populated during validation, consumed by main().
|
|
130
|
+
const _TYPE_COUNTS: Record<string, number> = {};
|
|
131
|
+
|
|
78
132
|
// Redaction heuristics — plain-regex, deliberately conservative.
|
|
79
133
|
// False positives are fixed by quoting the line differently; false
|
|
80
134
|
// negatives are a curator responsibility.
|
|
@@ -90,6 +144,15 @@ const REDACTION_PATTERNS: ReadonlyArray<readonly [RegExp, string]> = [
|
|
|
90
144
|
[/\b192\.168\.\d{1,3}\.\d{1,3}\b/, 'internal ipv4 range'],
|
|
91
145
|
];
|
|
92
146
|
|
|
147
|
+
// Date-discipline — relative-date phrases without an ISO YYYY-MM-DD anchor
|
|
148
|
+
// within ±20 chars are rejected. Memory entries that say "yesterday" or
|
|
149
|
+
// "last week" rot the moment the file is re-read on another day; the
|
|
150
|
+
// anchor pins meaning.
|
|
151
|
+
const RELATIVE_DATE_PATTERN =
|
|
152
|
+
/\b(yesterday|today|tomorrow|last\s+(?:week|month|year)|next\s+(?:week|month|year)|this\s+(?:week|month|year))\b/gi;
|
|
153
|
+
const ISO_DATE_PATTERN = /\b\d{4}-\d{2}-\d{2}\b/;
|
|
154
|
+
const DATE_ANCHOR_WINDOW = 20;
|
|
155
|
+
|
|
93
156
|
// PyYAML timestamp implicit-resolver. A *plain* (unquoted) scalar matching
|
|
94
157
|
// this is constructed as datetime.date / datetime.datetime — both pass
|
|
95
158
|
// `isinstance(value, datetime.date)`. Source: yaml/resolver.py.
|
|
@@ -246,6 +309,15 @@ function _isInteger(v: unknown): v is number {
|
|
|
246
309
|
return typeof v === 'number' && Number.isInteger(v);
|
|
247
310
|
}
|
|
248
311
|
|
|
312
|
+
/** Mirror Python len(str) — code-point count, not UTF-16 unit count. */
|
|
313
|
+
function _pyLen(s: string): number {
|
|
314
|
+
let n = 0;
|
|
315
|
+
for (const _ of s) {
|
|
316
|
+
n += 1;
|
|
317
|
+
}
|
|
318
|
+
return n;
|
|
319
|
+
}
|
|
320
|
+
|
|
249
321
|
function _memoryType(p: string): string {
|
|
250
322
|
// Supports `memory/<type>.yml`, `memory/<type>/<hash>.yml`, and
|
|
251
323
|
// `memory/<type>.example.yml` template filenames.
|
|
@@ -270,7 +342,13 @@ function _stem(name: string): string {
|
|
|
270
342
|
return base.slice(0, dot);
|
|
271
343
|
}
|
|
272
344
|
|
|
273
|
-
function _validateEntry(
|
|
345
|
+
function _validateEntry(
|
|
346
|
+
entry: Entry,
|
|
347
|
+
p: string,
|
|
348
|
+
seenIds: Set<string>,
|
|
349
|
+
findings: Finding[],
|
|
350
|
+
criticalCounts: Record<string, number> | null,
|
|
351
|
+
): void {
|
|
274
352
|
const eid = typeof entry['id'] === 'string' ? (entry['id'] as string) : entry['id'] != null ? String(entry['id']) : '';
|
|
275
353
|
const eidStr = entry['id'] == null ? '' : eid;
|
|
276
354
|
const present = new Set(Object.keys(entry));
|
|
@@ -292,6 +370,22 @@ function _validateEntry(entry: Entry, p: string, seenIds: Set<string>, findings:
|
|
|
292
370
|
if (confidence && typeof confidence === 'string' && !VALID_CONFIDENCE.has(confidence)) {
|
|
293
371
|
findings.push(new Finding(p, 0, 'error', `invalid confidence '${confidence}'`, eidStr));
|
|
294
372
|
}
|
|
373
|
+
// Priority is optional (defaults to `normal` at read time). When present
|
|
374
|
+
// it MUST be one of the three-tier enum — see VALID_PRIORITY for the
|
|
375
|
+
// rationale on rejecting a fourth `high` tier.
|
|
376
|
+
const priority = entry['priority'];
|
|
377
|
+
if (priority !== undefined && priority !== null && !(typeof priority === 'string' && VALID_PRIORITY.has(priority))) {
|
|
378
|
+
const sortedPri = [...VALID_PRIORITY].sort();
|
|
379
|
+
findings.push(
|
|
380
|
+
new Finding(
|
|
381
|
+
p,
|
|
382
|
+
0,
|
|
383
|
+
'error',
|
|
384
|
+
`invalid priority '${_pyStr(priority)}' (expected one of [${sortedPri.map((x) => `'${x}'`).join(', ')}])`,
|
|
385
|
+
eidStr,
|
|
386
|
+
),
|
|
387
|
+
);
|
|
388
|
+
}
|
|
295
389
|
const sources = (entry['source'] ?? []) as unknown;
|
|
296
390
|
if (!Array.isArray(sources) || sources.length < 1) {
|
|
297
391
|
findings.push(new Finding(p, 0, 'error', 'source must be a list with ≥1 entry', eidStr));
|
|
@@ -309,6 +403,71 @@ function _validateEntry(entry: Entry, p: string, seenIds: Set<string>, findings:
|
|
|
309
403
|
findings.push(new Finding(p, 0, 'info', `stale: last_validated ${age} days ago (limit ${days})`, eidStr));
|
|
310
404
|
}
|
|
311
405
|
}
|
|
406
|
+
// Critical-stale guard: a `priority: critical` entry that has not been
|
|
407
|
+
// re-validated within CRITICAL_STALE_DAYS surfaces as a warning, even
|
|
408
|
+
// when the entry's own `review_after_days` is more lenient. Critical
|
|
409
|
+
// entries surface on every /memory:load — they have a tighter SLA.
|
|
410
|
+
if (priority === 'critical' && entry['status'] === 'active' && lv instanceof PyDate) {
|
|
411
|
+
const critAge = _dateDiffDays(_today(), lv);
|
|
412
|
+
if (critAge > CRITICAL_STALE_DAYS) {
|
|
413
|
+
findings.push(
|
|
414
|
+
new Finding(
|
|
415
|
+
p,
|
|
416
|
+
0,
|
|
417
|
+
'warning',
|
|
418
|
+
`critical-stale: last_validated ${critAge} days ago (critical SLA is ${CRITICAL_STALE_DAYS} days)`,
|
|
419
|
+
eidStr,
|
|
420
|
+
),
|
|
421
|
+
);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
// One-durable-fact-per-entry: reject transcript/narrative blobs. A single
|
|
425
|
+
// content field over ONE_FACT_MAX_CHARS is the bloat signal.
|
|
426
|
+
for (const fld of ONE_FACT_FIELDS) {
|
|
427
|
+
const val = entry[fld];
|
|
428
|
+
if (typeof val === 'string' && _pyLen(val) > ONE_FACT_MAX_CHARS) {
|
|
429
|
+
findings.push(
|
|
430
|
+
new Finding(
|
|
431
|
+
p,
|
|
432
|
+
0,
|
|
433
|
+
'warning',
|
|
434
|
+
`one-fact: \`${fld}\` is ${_pyLen(val)} chars (limit ${ONE_FACT_MAX_CHARS}) — split into separate durable facts, not a narrative blob`,
|
|
435
|
+
eidStr,
|
|
436
|
+
),
|
|
437
|
+
);
|
|
438
|
+
break;
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
// Tier-0 inflation tracking — increment per memory type. The aggregate
|
|
442
|
+
// warning is emitted in main() after all files are validated.
|
|
443
|
+
if (criticalCounts !== null && priority === 'critical' && entry['status'] === 'active') {
|
|
444
|
+
const mtype = _memoryType(p);
|
|
445
|
+
criticalCounts[mtype] = (criticalCounts[mtype] ?? 0) + 1;
|
|
446
|
+
}
|
|
447
|
+
// Per-type entry-count tracking — aggregate cap warning in main().
|
|
448
|
+
if (criticalCounts !== null) {
|
|
449
|
+
const mt = _memoryType(p);
|
|
450
|
+
_TYPE_COUNTS[mt] = (_TYPE_COUNTS[mt] ?? 0) + 1;
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
/** Mirror Python's `str(value)` for the priority error message. */
|
|
455
|
+
function _pyStr(value: unknown): string {
|
|
456
|
+
if (value === null) {
|
|
457
|
+
return 'None';
|
|
458
|
+
}
|
|
459
|
+
if (value === true) {
|
|
460
|
+
return 'True';
|
|
461
|
+
}
|
|
462
|
+
if (value === false) {
|
|
463
|
+
return 'False';
|
|
464
|
+
}
|
|
465
|
+
if (value instanceof PyDate) {
|
|
466
|
+
const mm = String(value.month).padStart(2, '0');
|
|
467
|
+
const dd = String(value.day).padStart(2, '0');
|
|
468
|
+
return `${value.year}-${mm}-${dd}`;
|
|
469
|
+
}
|
|
470
|
+
return String(value);
|
|
312
471
|
}
|
|
313
472
|
|
|
314
473
|
function _checkRedaction(p: string, findings: Finding[]): void {
|
|
@@ -328,6 +487,38 @@ function _checkRedaction(p: string, findings: Finding[]): void {
|
|
|
328
487
|
});
|
|
329
488
|
}
|
|
330
489
|
|
|
490
|
+
function _checkDateDiscipline(p: string, findings: Finding[]): void {
|
|
491
|
+
// Reject relative-date phrases without an ISO YYYY-MM-DD anchor.
|
|
492
|
+
const text = fs.readFileSync(p, 'utf-8');
|
|
493
|
+
const lines = _splitlines(text);
|
|
494
|
+
lines.forEach((line, idx) => {
|
|
495
|
+
const lineNo = idx + 1;
|
|
496
|
+
const stripped = line.trimStart();
|
|
497
|
+
if (stripped.startsWith('#') || stripped.startsWith('last_validated')) {
|
|
498
|
+
return;
|
|
499
|
+
}
|
|
500
|
+
RELATIVE_DATE_PATTERN.lastIndex = 0;
|
|
501
|
+
let match: RegExpExecArray | null;
|
|
502
|
+
while ((match = RELATIVE_DATE_PATTERN.exec(line)) !== null) {
|
|
503
|
+
const start = Math.max(0, match.index - DATE_ANCHOR_WINDOW);
|
|
504
|
+
const end = Math.min(line.length, match.index + match[0].length + DATE_ANCHOR_WINDOW);
|
|
505
|
+
const windowStr = line.slice(start, end);
|
|
506
|
+
if (ISO_DATE_PATTERN.test(windowStr)) {
|
|
507
|
+
continue;
|
|
508
|
+
}
|
|
509
|
+
const phrase = match[0];
|
|
510
|
+
findings.push(
|
|
511
|
+
new Finding(
|
|
512
|
+
p,
|
|
513
|
+
lineNo,
|
|
514
|
+
'error',
|
|
515
|
+
`relative date '${phrase}' without an ISO YYYY-MM-DD anchor within ±${DATE_ANCHOR_WINDOW} chars (re-anchor before commit)`,
|
|
516
|
+
),
|
|
517
|
+
);
|
|
518
|
+
}
|
|
519
|
+
});
|
|
520
|
+
}
|
|
521
|
+
|
|
331
522
|
/** Mirror Python str.splitlines() for the line-numbering used above. */
|
|
332
523
|
function _splitlines(text: string): string[] {
|
|
333
524
|
if (text === '') {
|
|
@@ -342,12 +533,17 @@ function _splitlines(text: string): string[] {
|
|
|
342
533
|
return lines;
|
|
343
534
|
}
|
|
344
535
|
|
|
345
|
-
function _validateFile(
|
|
536
|
+
function _validateFile(
|
|
537
|
+
p: string,
|
|
538
|
+
findings: Finding[],
|
|
539
|
+
criticalCounts: Record<string, number> | null,
|
|
540
|
+
): void {
|
|
346
541
|
const mtype = _memoryType(p);
|
|
347
542
|
if (!KNOWN_TYPES.has(mtype)) {
|
|
348
543
|
findings.push(new Finding(p, 0, 'warning', `unknown memory type '${mtype}'`));
|
|
349
544
|
}
|
|
350
545
|
_checkRedaction(p, findings);
|
|
546
|
+
_checkDateDiscipline(p, findings);
|
|
351
547
|
let data: unknown;
|
|
352
548
|
try {
|
|
353
549
|
data = pyYamlSafeLoad(fs.readFileSync(p, 'utf-8'));
|
|
@@ -369,7 +565,7 @@ function _validateFile(p: string, findings: Finding[]): void {
|
|
|
369
565
|
if (Array.isArray(entries)) {
|
|
370
566
|
for (const entry of entries) {
|
|
371
567
|
if (_isPlainObject(entry)) {
|
|
372
|
-
_validateEntry(entry as Entry, p, seenIds, findings);
|
|
568
|
+
_validateEntry(entry as Entry, p, seenIds, findings, criticalCounts);
|
|
373
569
|
}
|
|
374
570
|
}
|
|
375
571
|
}
|
|
@@ -549,8 +745,53 @@ function main(): number {
|
|
|
549
745
|
}
|
|
550
746
|
return 0;
|
|
551
747
|
}
|
|
552
|
-
|
|
553
|
-
|
|
748
|
+
// An ABSENT root stays a pinned exit-0 no-op (the branch above; the memory
|
|
749
|
+
// tree is an optional surface and `task check-memory` short-circuits it).
|
|
750
|
+
// A root that EXISTS but walks to zero `*.yml` is the case nothing covered:
|
|
751
|
+
// entries moved to a subtree this walk does not reach, and the validator
|
|
752
|
+
// reported "0 error(s)" over an empty read. No `allowEmpty` for that half —
|
|
753
|
+
// a present-but-unreadable corpus is blindness, not a clean bill of health.
|
|
754
|
+
// Exit 1 is this gate's only failure code (see `_emit`).
|
|
755
|
+
// No dead-scope guard: `_lib/scan_scope.js` is not installed with the
|
|
756
|
+
// template, and a consumer with no `agents/memory/` legitimately scans zero.
|
|
757
|
+
const ymls = _rglobYmlSorted(root);
|
|
758
|
+
|
|
759
|
+
const criticalCounts: Record<string, number> = {};
|
|
760
|
+
for (const key of Object.keys(_TYPE_COUNTS)) {
|
|
761
|
+
delete _TYPE_COUNTS[key];
|
|
762
|
+
}
|
|
763
|
+
for (const yml of ymls) {
|
|
764
|
+
_validateFile(yml, findings, criticalCounts);
|
|
765
|
+
}
|
|
766
|
+
// Tier-0 inflation warning — soft cap on `priority: critical` per type.
|
|
767
|
+
// Council convergence (Phase 2 B2): warn rather than block, because the
|
|
768
|
+
// right answer to "too many criticals" is curator review, not CI failure.
|
|
769
|
+
for (const [mtype, count] of Object.entries(criticalCounts).sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))) {
|
|
770
|
+
if (count > CRITICAL_WARN_THRESHOLD) {
|
|
771
|
+
findings.push(
|
|
772
|
+
new Finding(
|
|
773
|
+
`agents/memory/${mtype}`,
|
|
774
|
+
0,
|
|
775
|
+
'warning',
|
|
776
|
+
`tier-0 inflation: ${count} active 'priority: critical' entries (threshold ${CRITICAL_WARN_THRESHOLD}) — review whether all still warrant always-surface treatment`,
|
|
777
|
+
),
|
|
778
|
+
);
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
// Per-type entry-count cap (size-bounding, Phase 7). Warn, never block —
|
|
782
|
+
// over-cap signals a consolidation pass is due (prune archived, merge dups).
|
|
783
|
+
for (const [mtype, count] of Object.entries(_TYPE_COUNTS).sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))) {
|
|
784
|
+
const cap = PER_TYPE_CAPS[mtype] ?? DEFAULT_TYPE_CAP;
|
|
785
|
+
if (count > cap) {
|
|
786
|
+
findings.push(
|
|
787
|
+
new Finding(
|
|
788
|
+
`agents/memory/${mtype}`,
|
|
789
|
+
0,
|
|
790
|
+
'warning',
|
|
791
|
+
`entry-cap: ${count} entries (soft cap ${cap}) — run a consolidation pass (prune archived, merge duplicates)`,
|
|
792
|
+
),
|
|
793
|
+
);
|
|
794
|
+
}
|
|
554
795
|
}
|
|
555
796
|
return _emit(findings, args.format);
|
|
556
797
|
}
|
|
@@ -217,6 +217,7 @@ interface ParsedArgs {
|
|
|
217
217
|
intake_id: string | null;
|
|
218
218
|
proposal: string | null;
|
|
219
219
|
format: 'text' | 'json';
|
|
220
|
+
quiet: boolean;
|
|
220
221
|
}
|
|
221
222
|
|
|
222
223
|
function _argparse_error(message: string): never {
|
|
@@ -228,6 +229,7 @@ function parse_args(argv: readonly string[]): ParsedArgs {
|
|
|
228
229
|
let intake_id: string | null = null;
|
|
229
230
|
let proposal: string | null = null;
|
|
230
231
|
let format: 'text' | 'json' = 'text';
|
|
232
|
+
let quiet = false;
|
|
231
233
|
// argparse reports a mutually-exclusive conflict against the SECOND-seen
|
|
232
234
|
// arg at the point it is parsed (order-sensitive), so check inline rather
|
|
233
235
|
// than after the loop.
|
|
@@ -248,10 +250,12 @@ function parse_args(argv: readonly string[]): ParsedArgs {
|
|
|
248
250
|
format = _checkFormat(v);
|
|
249
251
|
} else if (arg.startsWith('--format=')) {
|
|
250
252
|
format = _checkFormat(arg.slice('--format='.length));
|
|
253
|
+
} else if (arg === '--quiet') {
|
|
254
|
+
quiet = true;
|
|
251
255
|
} else if (arg === '-h' || arg === '--help') {
|
|
252
256
|
process.stdout.write(
|
|
253
257
|
'usage: check_memory_proposal [-h] (--intake-id INTAKE_ID | --proposal PROPOSAL)\n' +
|
|
254
|
-
' [--format {text,json}]\n',
|
|
258
|
+
' [--format {text,json}] [--quiet]\n',
|
|
255
259
|
);
|
|
256
260
|
process.exit(0);
|
|
257
261
|
} else {
|
|
@@ -261,7 +265,7 @@ function parse_args(argv: readonly string[]): ParsedArgs {
|
|
|
261
265
|
if (intake_id === null && proposal === null) {
|
|
262
266
|
_argparse_error('one of the arguments --intake-id --proposal is required');
|
|
263
267
|
}
|
|
264
|
-
return { intake_id, proposal, format };
|
|
268
|
+
return { intake_id, proposal, format, quiet };
|
|
265
269
|
}
|
|
266
270
|
|
|
267
271
|
function _need(argv: readonly string[], i: number, flag: string): string {
|
|
@@ -322,7 +326,9 @@ function main(argv?: readonly string[]): number {
|
|
|
322
326
|
process.stdout.write(` 🔴 ${f}\n`);
|
|
323
327
|
}
|
|
324
328
|
} else {
|
|
325
|
-
|
|
329
|
+
if (!args.quiet) {
|
|
330
|
+
process.stdout.write(`✅ ${source} — gate passed\n`);
|
|
331
|
+
}
|
|
326
332
|
}
|
|
327
333
|
}
|
|
328
334
|
return failures.length > 0 ? 1 : 0;
|
|
@@ -246,6 +246,74 @@ function _pad2(v: string): string {
|
|
|
246
246
|
* (`agents/memory/<type>.yml` or `<type>/entries.yml` with an `entries:`
|
|
247
247
|
* list), so consumers can adopt either.
|
|
248
248
|
*/
|
|
249
|
+
const _CURATED_STATUS_EXCLUDE: ReadonlySet<string> = new Set(['deprecated', 'archived', 'superseded']);
|
|
250
|
+
|
|
251
|
+
/** Mirror Python `entry.get("status") in _CURATED_STATUS_EXCLUDE`. */
|
|
252
|
+
function _statusExcluded(entry: Record<string, unknown>): boolean {
|
|
253
|
+
const status = entry['status'];
|
|
254
|
+
return typeof status === 'string' && _CURATED_STATUS_EXCLUDE.has(status);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
/*
|
|
259
|
+
* Staleness, ported from `src/scripts/memory_lookup.ts` on 2026-08-26
|
|
260
|
+
* (`road-to-memory-twin-reconciliation` 2.2, verdict `dev-side-correct`).
|
|
261
|
+
*
|
|
262
|
+
* The template previously had NO staleness handling at all — `grep -c stale`
|
|
263
|
+
* returned 0 — so a consumer retrieved curated entries whose own
|
|
264
|
+
* `review_after_days` window had expired, with nothing saying so. `check_memory`
|
|
265
|
+
* required both fields on every entry the whole time; only retrieval ignored
|
|
266
|
+
* them.
|
|
267
|
+
*
|
|
268
|
+
* Portable by construction: Date math and a regex, no `_lib` import.
|
|
269
|
+
*/
|
|
270
|
+
function _today(): Date {
|
|
271
|
+
const now = new Date();
|
|
272
|
+
return new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()));
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
function _parseIsoDate(s: string): Date | null {
|
|
276
|
+
const m = /^(\d{4})-(\d{2})-(\d{2})$/.exec(s);
|
|
277
|
+
if (!m) {
|
|
278
|
+
return null;
|
|
279
|
+
}
|
|
280
|
+
const y = Number(m[1]);
|
|
281
|
+
const mo = Number(m[2]);
|
|
282
|
+
const d = Number(m[3]);
|
|
283
|
+
if (mo < 1 || mo > 12 || d < 1 || d > 31) {
|
|
284
|
+
return null;
|
|
285
|
+
}
|
|
286
|
+
const date = new Date(Date.UTC(y, mo - 1, d));
|
|
287
|
+
// Reject overflow (e.g. 2026-02-31 → March), matching fromisoformat's strictness.
|
|
288
|
+
if (date.getUTCFullYear() !== y || date.getUTCMonth() !== mo - 1 || date.getUTCDate() !== d) {
|
|
289
|
+
return null;
|
|
290
|
+
}
|
|
291
|
+
return date;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
function _pyStrDateLike(lv: unknown): string {
|
|
295
|
+
if (lv instanceof PyTimestamp) {
|
|
296
|
+
return lv.pyStr;
|
|
297
|
+
}
|
|
298
|
+
return _pyStr(lv);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
function _isStale(entry: Record<string, unknown>, today: Date): boolean {
|
|
302
|
+
const lv = entry['last_validated'];
|
|
303
|
+
const rad = entry['review_after_days'];
|
|
304
|
+
// Python: `not lv or not isinstance(rad, int)`. PyYAML ints land as JS
|
|
305
|
+
// numbers; booleans are int in Python but excluded here as the common path.
|
|
306
|
+
if (!lv || typeof rad !== 'number' || !Number.isInteger(rad)) {
|
|
307
|
+
return false;
|
|
308
|
+
}
|
|
309
|
+
const validated = _parseIsoDate(_pyStrDateLike(lv));
|
|
310
|
+
if (validated === null) {
|
|
311
|
+
return false;
|
|
312
|
+
}
|
|
313
|
+
const days = Math.round((today.getTime() - validated.getTime()) / 86_400_000);
|
|
314
|
+
return days > rad;
|
|
315
|
+
}
|
|
316
|
+
|
|
249
317
|
function* _iter_curated_entries(mtype: string): Generator<[string, Record<string, unknown>]> {
|
|
250
318
|
const type_dir = path.join(MEMORY_ROOT, mtype);
|
|
251
319
|
const single_file = path.join(MEMORY_ROOT, `${mtype}.yml`);
|
|
@@ -254,6 +322,9 @@ function* _iter_curated_entries(mtype: string): Generator<[string, Record<string
|
|
|
254
322
|
const entries = _isPlainObject(data) ? data['entries'] : null;
|
|
255
323
|
for (const e of Array.isArray(entries) ? entries : []) {
|
|
256
324
|
if (_isPlainObject(e)) {
|
|
325
|
+
if (_statusExcluded(e)) {
|
|
326
|
+
continue;
|
|
327
|
+
}
|
|
257
328
|
yield [single_file, e];
|
|
258
329
|
}
|
|
259
330
|
}
|
|
@@ -266,11 +337,17 @@ function* _iter_curated_entries(mtype: string): Generator<[string, Record<string
|
|
|
266
337
|
if (Array.isArray(entries)) {
|
|
267
338
|
for (const e of entries) {
|
|
268
339
|
if (_isPlainObject(e)) {
|
|
340
|
+
if (_statusExcluded(e)) {
|
|
341
|
+
continue;
|
|
342
|
+
}
|
|
269
343
|
yield [yml, e];
|
|
270
344
|
}
|
|
271
345
|
}
|
|
272
346
|
} else if (_isPlainObject(data) && data['id']) {
|
|
273
347
|
// Flat, one-entry-per-file layout (content-addressed).
|
|
348
|
+
if (_statusExcluded(data)) {
|
|
349
|
+
continue;
|
|
350
|
+
}
|
|
274
351
|
yield [yml, data];
|
|
275
352
|
}
|
|
276
353
|
}
|
|
@@ -454,6 +531,7 @@ function _cross_repo_hits(keys: string[], limit: number): Hit[] {
|
|
|
454
531
|
*/
|
|
455
532
|
export function retrieve(types: string[], keys: string[], limit = 5): Hit[] {
|
|
456
533
|
const repo_hits: Hit[] = [];
|
|
534
|
+
const today = _today();
|
|
457
535
|
for (const mtype of types) {
|
|
458
536
|
if (mtype === KNOWLEDGE_TYPE) {
|
|
459
537
|
for (const [p, entry] of _iter_knowledge_entries()) {
|
|
@@ -488,6 +566,14 @@ export function retrieve(types: string[], keys: string[], limit = 5): Hit[] {
|
|
|
488
566
|
continue;
|
|
489
567
|
}
|
|
490
568
|
for (const [p, entry] of _iter_curated_entries(mtype)) {
|
|
569
|
+
// A curated entry past its own `review_after_days` window is not
|
|
570
|
+
// retrieved. The dev side additionally reports it under `skipped`;
|
|
571
|
+
// this copy has no `retrieve_with_meta`, so it filters silently —
|
|
572
|
+
// the exclusion is the behaviour that matters, the report is the
|
|
573
|
+
// richer surface.
|
|
574
|
+
if (_isStale(entry, today)) {
|
|
575
|
+
continue;
|
|
576
|
+
}
|
|
491
577
|
repo_hits.push(new Hit(String(entry['id'] ?? ''), mtype, 'curated', String(p), _score(entry, keys), entry));
|
|
492
578
|
}
|
|
493
579
|
for (const [p, entry] of _iter_intake_entries(mtype)) {
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
|
|
30
30
|
import * as crypto from 'node:crypto';
|
|
31
31
|
import * as fs from 'node:fs';
|
|
32
|
+
import * as os from 'node:os';
|
|
32
33
|
import * as path from 'node:path';
|
|
33
34
|
import process from 'node:process';
|
|
34
35
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
@@ -217,6 +218,45 @@ export interface SignalRecord {
|
|
|
217
218
|
* The file path is the single source of truth: there is no external backend
|
|
218
219
|
* to route to, so merge-safety holds in every mode.
|
|
219
220
|
*/
|
|
221
|
+
export class ProvenanceRefusedError extends Error {}
|
|
222
|
+
|
|
223
|
+
// lint-store-boundary: ignore — the provenance gate must RECOGNISE the global root to refuse it
|
|
224
|
+
const _GLOBAL_STORE_MARKER = `.event4u${path.sep}agent-config`;
|
|
225
|
+
|
|
226
|
+
export function _origin_is_global(origin: string): boolean {
|
|
227
|
+
if (!origin.includes('/') && !origin.includes(path.sep) && !origin.startsWith('~')) {
|
|
228
|
+
return false; // symbolic origins ('agent', 'claude', 'cursor', …) are not paths
|
|
229
|
+
}
|
|
230
|
+
const expanded = origin.startsWith('~')
|
|
231
|
+
? path.join(os.homedir(), origin.slice(1)) // lint-store-boundary: ignore — the gate itself must recognise the global root
|
|
232
|
+
: origin;
|
|
233
|
+
let resolved: string;
|
|
234
|
+
try {
|
|
235
|
+
resolved = path.resolve(expanded);
|
|
236
|
+
} catch {
|
|
237
|
+
return false;
|
|
238
|
+
}
|
|
239
|
+
return resolved.includes(_GLOBAL_STORE_MARKER) || /(^|[\\/])\.event4u([\\/]|$)/.test(origin);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
export function _assert_project_writable(record: { origin: string; subject?: unknown }): void {
|
|
243
|
+
if (record.subject === 'user') {
|
|
244
|
+
throw new ProvenanceRefusedError(
|
|
245
|
+
'provenance gate: subject: user records live global-only and may ' +
|
|
246
|
+
'never be written into a tracked project artifact (ADR-130).',
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
if (_origin_is_global(record.origin)) {
|
|
250
|
+
throw new ProvenanceRefusedError(
|
|
251
|
+
`provenance gate: origin resolves into the user-global store ` +
|
|
252
|
+
`(${record.origin}) — refused entry into tracked project intake (ADR-130).`,
|
|
253
|
+
);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Append a signal entry. Returns the written record, or null when skipped.
|
|
259
|
+
*/
|
|
220
260
|
export function emit(
|
|
221
261
|
entry_type: string,
|
|
222
262
|
p: string,
|
|
@@ -255,6 +295,10 @@ export function emit(
|
|
|
255
295
|
}
|
|
256
296
|
}
|
|
257
297
|
}
|
|
298
|
+
if (!('subject' in record)) {
|
|
299
|
+
record.subject = 'project'; // additive default (ADR-130)
|
|
300
|
+
}
|
|
301
|
+
_assert_project_writable(record as { origin: string; subject?: unknown });
|
|
258
302
|
fs.mkdirSync(INTAKE_ROOT, { recursive: true });
|
|
259
303
|
const target = _monthly_file();
|
|
260
304
|
fs.appendFileSync(target, `${_jsonDumpsUnicode(record)}\n`, 'utf-8');
|