@event4u/agent-config 16.2.0 → 16.3.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 +89 -237
- package/README.md +14 -12
- package/dist/agent-src/commands/analyze/inbox.md +1 -1
- package/dist/agent-src/commands/analyze/roadmap-repos.md +1 -1
- package/dist/agent-src/commands/bug/fix.md +17 -2
- package/dist/agent-src/commands/feature/plan.md +1 -1
- package/dist/agent-src/commands/feature/roadmap.md +1 -1
- package/dist/agent-src/commands/fix/ci.md +1 -1
- package/dist/agent-src/commands/implement-ticket.md +1 -1
- package/dist/agent-src/commands/jira-ticket.md +1 -1
- package/dist/agent-src/commands/roadmap/create.md +1 -1
- package/dist/agent-src/commands/roadmap/materialize.md +1 -1
- package/dist/agent-src/commands/roadmap/process-full.md +4 -4
- package/dist/agent-src/commands/roadmap/resolve-blockers.md +361 -0
- package/dist/agent-src/commands/roadmap/triage-parked.md +325 -0
- package/dist/agent-src/commands/roadmap.md +18 -4
- package/dist/agent-src/commands/tests/create.md +17 -3
- package/dist/agent-src/commands/tests/execute.md +22 -5
- package/dist/agent-src/contexts/authority/decision-revisit-gate-enforcement.md +43 -0
- package/dist/agent-src/contexts/communication/rules-auto/design-fidelity-enforcement.md +24 -0
- package/dist/agent-src/contexts/execution/auto-dispatch-classification.md +6 -6
- package/dist/agent-src/contexts/execution/roadmap-process-loop.md +32 -2
- package/dist/agent-src/contexts/execution/session-canary-enforcement-history.md +67 -0
- package/dist/agent-src/contexts/execution/toolchain-resolver.md +101 -7
- package/dist/agent-src/rules/active-remediation.md +1 -1
- package/dist/agent-src/rules/autonomous-execution.md +1 -0
- package/dist/agent-src/rules/broken-access-control.md +1 -0
- package/dist/agent-src/rules/command-suggestion-policy.md +1 -0
- package/dist/agent-src/rules/context-hygiene.md +1 -1
- package/dist/agent-src/rules/decision-revisit-gate.md +16 -33
- package/dist/agent-src/rules/design-fidelity.md +13 -16
- package/dist/agent-src/rules/doc-screenshot-hygiene.md +1 -0
- package/dist/agent-src/rules/domain-safety-disclaimer.md +1 -0
- package/dist/agent-src/rules/domain-safety-pii.md +1 -0
- package/dist/agent-src/rules/domain-safety-retention.md +1 -0
- package/dist/agent-src/rules/engineering-safety-floor.md +1 -0
- package/dist/agent-src/rules/evaluator-independence.md +3 -2
- package/dist/agent-src/rules/fast-path-marker-visibility.md +1 -0
- package/dist/agent-src/rules/finance-safety-floor.md +1 -0
- package/dist/agent-src/rules/git-history-discipline.md +1 -0
- package/dist/agent-src/rules/image-likeness-and-rights.md +1 -0
- package/dist/agent-src/rules/legal-safety-floor.md +3 -2
- package/dist/agent-src/rules/lethal-trifecta-guard.md +1 -0
- package/dist/agent-src/rules/low-impact-corpus-privacy-floor.md +1 -0
- package/dist/agent-src/rules/media-governance-routing.md +14 -17
- package/dist/agent-src/rules/persona-governance.md +2 -2
- package/dist/agent-src/rules/provider-lifecycle-discipline.md +1 -1
- package/dist/agent-src/rules/question-not-instruction.md +1 -0
- package/dist/agent-src/rules/roadmap-progress-sync.md +1 -1
- package/dist/agent-src/rules/runtime-safety.md +1 -0
- package/dist/agent-src/rules/secret-vcs-guard.md +1 -0
- package/dist/agent-src/rules/security-sensitive-stop.md +3 -2
- package/dist/agent-src/rules/session-canary.md +8 -62
- package/dist/agent-src/rules/settings-ask-protocol.md +1 -0
- package/dist/agent-src/rules/source-confidentiality.md +1 -0
- package/dist/agent-src/rules/strategy-safety-floor.md +1 -0
- package/dist/agent-src/rules/tool-safety.md +1 -0
- package/dist/agent-src/rules/untrusted-input-defense.md +1 -0
- package/dist/agent-src/rules/user-interrupt-priority.md +1 -0
- package/dist/agent-src/scripts/archive_completed_roadmaps.ts +115 -20
- package/dist/agent-src/scripts/deferral_carry.ts +339 -0
- package/dist/agent-src/scripts/update_roadmap_progress.ts +4 -1
- package/dist/agent-src/skills/api-design/data/manifest.json +2 -2
- package/dist/agent-src/skills/api-testing/SKILL.md +17 -0
- package/dist/agent-src/skills/code-intelligence/SKILL.md +14 -2
- package/dist/agent-src/skills/design-system-capture/references/import-procedure.md +1 -1
- package/dist/agent-src/skills/existing-ui-audit/SKILL.md +2 -2
- package/dist/agent-src/skills/fe-design/SKILL.md +1 -1
- package/dist/agent-src/skills/iconography/SKILL.md +1 -1
- package/dist/agent-src/skills/js-library-packaging/SKILL.md +2 -2
- package/dist/agent-src/skills/monorepo-workspace/SKILL.md +1 -1
- package/dist/agent-src/skills/quality-tools/SKILL.md +11 -1
- package/dist/agent-src/skills/quality-tools/references/go-tools.md +76 -0
- package/dist/agent-src/skills/quality-tools/references/python-tools.md +104 -0
- package/dist/agent-src/skills/review-routing/SKILL.md +2 -2
- package/dist/agent-src/skills/skill-improvement-pipeline/SKILL.md +1 -1
- package/dist/agent-src/skills/storybook-workshop/SKILL.md +3 -3
- package/dist/agent-src/skills/tailwind-engineer/SKILL.md +1 -1
- package/dist/agent-src/skills/test-case-discovery/SKILL.md +7 -0
- package/dist/agent-src/skills/test-driven-development/SKILL.md +17 -0
- package/dist/agent-src/skills/test-performance/SKILL.md +19 -1
- package/dist/agent-src/skills/ui-component-architect/SKILL.md +2 -2
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +48 -6
- package/dist/agent-src/templates/scripts/work_engine/stack/runner.ts +774 -109
- package/dist/cli/registry.js +1 -1
- package/dist/cli-delegate/archive_completed_roadmaps.js +92 -12
- package/dist/cli-delegate/check_update_banner.js +12 -1
- package/dist/cli-delegate/chunk-523HCFYO.js +90 -0
- package/dist/cli-delegate/{chunk-M2DPGFZ4.js → chunk-6V6TA25H.js} +22 -152
- package/dist/cli-delegate/chunk-7IQE3D5S.js +191 -0
- package/dist/cli-delegate/{chunk-6KFEC3G7.js → chunk-CQWX336L.js} +1 -1
- package/dist/cli-delegate/chunk-DEIV7XP7.js +108 -0
- package/dist/cli-delegate/chunk-EEHDXSYD.js +2040 -0
- package/dist/cli-delegate/{chunk-P6ZHP5W2.js → chunk-GKE7ZVFA.js} +4 -4
- package/dist/cli-delegate/chunk-JQOM7TTM.js +1201 -0
- package/dist/cli-delegate/{chunk-IGD6ERX6.js → chunk-JQVYKIZA.js} +10 -0
- package/dist/cli-delegate/{chunk-FC75PGJE.js → chunk-JY2I2DXV.js} +12 -1
- package/dist/cli-delegate/chunk-KB5FZ655.js +208 -0
- package/dist/cli-delegate/{chunk-7RQP4UDH.js → chunk-KR6EM23A.js} +235 -1455
- package/dist/cli-delegate/{chunk-LTYVIY76.js → chunk-LIYTLH6O.js} +1 -1
- package/dist/cli-delegate/{chunk-YJ72UIAK.js → chunk-NQ7WT43P.js} +1186 -244
- package/dist/cli-delegate/chunk-NXEILF2K.js +2160 -0
- package/dist/cli-delegate/{chunk-5R7HOLAF.js → chunk-NYX3L2PZ.js} +1 -1
- package/dist/cli-delegate/{chunk-4E2W63DA.js → chunk-OKJUIAPS.js} +62 -1
- package/dist/cli-delegate/{chunk-QAJS5YWY.js → chunk-PHD7OOLE.js} +2 -1
- package/dist/cli-delegate/{chunk-RGNIWTEA.js → chunk-QLDHIPWR.js} +1 -1
- package/dist/cli-delegate/{chunk-7XGBX6ZH.js → chunk-RQNNW7IF.js} +1314 -560
- package/dist/cli-delegate/{chunk-4XFP2Y3E.js → chunk-S4UMZNES.js} +1 -1
- package/dist/cli-delegate/{chunk-6KM6ORRY.js → chunk-S4YWNRKO.js} +24 -8
- package/dist/cli-delegate/{chunk-FP36SWJD.js → chunk-TRI6DQZ6.js} +2781 -340
- package/dist/cli-delegate/chunk-ULQRUR23.js +208 -0
- package/dist/cli-delegate/{chunk-NUHLI2RX.js → chunk-YCU3TIXH.js} +2 -0
- package/dist/cli-delegate/chunk-ZBZV2G5R.js +210 -0
- package/dist/cli-delegate/{chunk-WGXTVKCQ.js → chunk-ZUZKZYCN.js} +5 -3
- package/dist/cli-delegate/cmd_analyze_session.js +1 -1
- package/dist/cli-delegate/cmd_brand_status.js +1 -1
- package/dist/cli-delegate/cmd_conformance.js +1167 -234
- package/dist/cli-delegate/cmd_doctor.js +13 -6
- package/dist/cli-delegate/cmd_doctor_neighbours.js +23 -0
- package/dist/cli-delegate/cmd_explain.js +5 -5
- package/dist/cli-delegate/cmd_export.js +11 -8
- package/dist/cli-delegate/cmd_fleet.js +3 -3
- package/dist/cli-delegate/cmd_handoff.js +10 -7
- package/dist/cli-delegate/cmd_mcp_available.js +1 -1
- package/dist/cli-delegate/cmd_memory_get.js +3 -1
- package/dist/cli-delegate/cmd_migrate.js +2 -2
- package/dist/cli-delegate/cmd_packs_active.js +3 -3
- package/dist/cli-delegate/cmd_preflight.js +6 -6
- package/dist/cli-delegate/cmd_prune.js +11 -8
- package/dist/cli-delegate/cmd_refresh.js +2 -1
- package/dist/cli-delegate/cmd_route_audit.js +8 -6
- package/dist/cli-delegate/cmd_route_explain.js +4 -4
- package/dist/cli-delegate/cmd_session_recycle.js +4 -3
- package/dist/cli-delegate/cmd_settings_get.js +1 -1
- package/dist/cli-delegate/cmd_settings_migrate.js +11 -8
- package/dist/cli-delegate/cmd_settings_set.js +4 -4
- package/dist/cli-delegate/cmd_sync.js +11 -8
- package/dist/cli-delegate/cmd_uninstall.js +11 -8
- package/dist/cli-delegate/cmd_update.js +1 -1
- package/dist/cli-delegate/cmd_upgrade.js +3 -2
- package/dist/cli-delegate/cmd_validate.js +11 -8
- package/dist/cli-delegate/cmd_versions.js +1 -1
- package/dist/cli-delegate/deferral_carry.js +16 -0
- package/dist/cli-delegate/gate_execute.js +2 -2
- package/dist/cli-delegate/roadmap_gates.js +5 -5
- package/dist/cli-delegate/update_roadmap_progress.js +1 -1
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +127 -75
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +3 -3
- package/dist/discovery/dormancy-report.md +1 -1
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +7 -5
- package/dist/discovery/trust-report.md +2 -2
- package/dist/discovery/workspaces.json +6 -4
- package/dist/hooks/dispatch.js +5357 -6656
- package/dist/hooks/dispatch.sha256 +1 -1
- package/dist/install/claudePathsPlan.js +47 -6
- package/dist/install/claudeRuleRewrite.js +7 -0
- package/dist/install/emit_host_rules_cli.js +39 -36
- package/dist/install/globalRuleScope.js +87 -0
- package/dist/install/host_rule_ownership.js +160 -0
- package/dist/install/install.mjs +2080 -1024
- package/dist/install/installThinLayer.js +261 -0
- package/dist/install/installedRuleLinks.js +176 -0
- package/dist/install/wizard-plan.js +24 -0
- package/dist/mcp/registry-manifest.json +3 -3
- package/dist/mcp/server.json +2 -2
- package/dist/mcp/server.mjs +31965 -27154
- package/dist/scripts/_lib/agent_settings.js +11 -0
- package/dist/scripts/_lib/claude_settings_hooks.js +10 -8
- package/dist/scripts/_lib/installed_layer.js +378 -0
- package/dist/scripts/_lib/lean_projection_mode.js +218 -15
- package/dist/scripts/_lib/rule_consequence_class.js +45 -0
- package/dist/scripts/_lib/rule_injection.js +67 -10
- package/dist/scripts/_lib/rule_law_section.js +122 -0
- package/dist/scripts/_lib/thin_rules.js +458 -0
- package/dist/scripts/_lib/windsurf_render.js +60 -0
- package/dist/scripts/condense.js +14 -26
- package/dist/scripts/project_thin_rules.js +14 -294
- package/dist/server/schemas/settings.js +6 -0
- package/dist/shared/skillRanking.js +74 -13
- package/docs/contracts/settings-classes.md +7 -5
- package/package.json +1 -1
- package/src/agent-src/scripts/archive_completed_roadmaps.ts +115 -20
- package/src/agent-src/scripts/deferral_carry.ts +339 -0
- package/src/agent-src/scripts/update_roadmap_progress.ts +4 -1
- package/src/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +48 -6
- package/src/agent-src/templates/scripts/work_engine/stack/runner.ts +774 -109
- package/src/config/agent-settings.template.yml +62 -22
- package/src/config/continuity-surface.json +7 -0
- package/src/config/evaluator-budgets.json +4 -4
- package/src/config/gate-coverage.yml +96 -3
- package/src/config/gate-violation-baselines.json +17 -9
- package/src/config/hook-bundle-budget.json +25 -0
- package/src/config/hook-token-budget.json +6 -1
- package/src/config/host-instruction-limits.json +33 -0
- package/src/config/routing-coverage-seed.json +24 -3
- package/src/config/rule-activation-census.json +7 -3
- package/src/config/rule-consequence-class.json +161 -0
- package/src/config/rule-law-ceilings.json +99 -0
- package/src/install/claudePathsPlan.ts +46 -4
- package/src/install/claudeRuleRewrite.ts +10 -1
- package/src/install/emit_host_rules_cli.ts +43 -34
- package/src/install/globalRuleScope.ts +109 -0
- package/src/install/host_rule_ownership.ts +170 -0
- package/src/install/installThinLayer.ts +312 -0
- package/src/install/installedRuleLinks.ts +220 -0
- package/src/install/wizard-plan.ts +24 -0
- package/src/scripts/_cli/cmd_doctor.ts +23 -71
- package/src/scripts/_cli/cmd_doctor_neighbours.ts +293 -0
- package/src/scripts/_dispatch.bash +16 -2
- package/src/scripts/_lib/agent_settings.ts +11 -0
- package/src/scripts/_lib/claude_settings_hooks.ts +10 -8
- package/src/scripts/_lib/estate_offsets.ts +241 -0
- package/src/scripts/_lib/exemption_shape.ts +143 -0
- package/src/scripts/_lib/fnv.ts +23 -0
- package/src/scripts/_lib/foreign_scan.ts +106 -0
- package/src/scripts/_lib/gitignore_block.ts +314 -0
- package/src/scripts/_lib/global_deploy_inventory.ts +32 -0
- package/src/scripts/_lib/graph_feeder_record.ts +214 -0
- package/src/scripts/_lib/hook_settings.ts +73 -0
- package/src/scripts/_lib/host_capability.ts +40 -19
- package/src/scripts/_lib/host_hook_merge.ts +165 -0
- package/src/scripts/_lib/installed_layer.ts +538 -0
- package/src/scripts/_lib/json_merge.ts +82 -0
- package/src/scripts/_lib/json_pointers.ts +93 -11
- package/src/scripts/_lib/lean_projection_mode.ts +275 -15
- package/src/scripts/_lib/machine_wake.ts +16 -3
- package/src/scripts/_lib/neighbour_census.ts +760 -0
- package/src/scripts/_lib/neighbour_scan.ts +122 -0
- package/src/scripts/_lib/neighbour_tool_use.ts +189 -0
- package/src/scripts/_lib/prompt_shape.ts +46 -0
- package/src/scripts/_lib/release_migration_gate.ts +19 -3
- package/src/scripts/_lib/reserved_name_sweep.ts +73 -0
- package/src/scripts/_lib/review_coverage.ts +134 -0
- package/src/scripts/_lib/rule_consequence_class.ts +71 -0
- package/src/scripts/_lib/rule_injection.ts +130 -10
- package/src/scripts/_lib/rule_law_section.ts +147 -0
- package/src/scripts/_lib/rule_layer_overlap.ts +58 -0
- package/src/scripts/_lib/skill_origin.ts +254 -0
- package/src/scripts/_lib/structured_ask.ts +64 -21
- package/src/scripts/_lib/thin_rules.ts +540 -0
- package/src/scripts/_lib/touched_file_quality.ts +434 -0
- package/src/scripts/_lib/turn_end_refusals.ts +77 -2
- package/src/scripts/_lib/windsurf_render.ts +63 -0
- package/src/scripts/ai_council/cli_call_budget.ts +13 -5
- package/src/scripts/ai_council/clients.ts +26 -57
- package/src/scripts/ai_council/config.ts +1 -1
- package/src/scripts/ai_council/vendor_defaults.ts +45 -0
- package/src/scripts/audit_skill_overlap.ts +261 -0
- package/src/scripts/before_complete_hook.ts +243 -12
- package/src/scripts/bench_touched_file_quality.ts +238 -0
- package/src/scripts/check_enforcement_matrix.ts +377 -20
- package/src/scripts/check_estate_count.ts +130 -153
- package/src/scripts/check_finding_dispositions.ts +116 -4
- package/src/scripts/check_hook_bundle_composition.ts +370 -0
- package/src/scripts/check_kernel_edit_ratified.ts +49 -11
- package/src/scripts/check_memory.ts +7 -1
- package/src/scripts/check_release_highlights.ts +10 -0
- package/src/scripts/check_release_pr_shape.ts +38 -15
- package/src/scripts/check_standing_rule_delivery.ts +33 -13
- package/src/scripts/check_verify_expectation_delta.ts +521 -0
- package/src/scripts/code_graph/detect.ts +127 -7
- package/src/scripts/code_graph/foreign.ts +194 -0
- package/src/scripts/code_graph/query.ts +217 -4
- package/src/scripts/code_graph/types.ts +26 -2
- package/src/scripts/code_graph/validate.ts +3 -1
- package/src/scripts/code_graph/verbs.ts +103 -0
- package/src/scripts/compile_hook_manifest.ts +33 -1
- package/src/scripts/condense.ts +14 -27
- package/src/scripts/estate_exemption_shape.ts +202 -0
- package/src/scripts/generate_host_cost_table.ts +1 -1
- package/src/scripts/hook_manifest.json +1 -1
- package/src/scripts/hook_manifest.yaml +150 -9
- package/src/scripts/hooks/block_config_weakening.ts +67 -2
- package/src/scripts/hooks/block_plumbing_writes.ts +29 -1
- package/src/scripts/hooks/code_graph_context_hook.ts +252 -23
- package/src/scripts/hooks/concern_failure_policy.ts +280 -0
- package/src/scripts/hooks/dispatch_hook.ts +52 -52
- package/src/scripts/hooks/exit_codes.ts +2 -1
- package/src/scripts/hooks/host_lowering.json +1 -1
- package/src/scripts/hooks/host_lowering.ts +19 -1
- package/src/scripts/hooks/one_question_per_ask_hook.ts +41 -25
- package/src/scripts/hooks/payload_stub.ts +10 -1
- package/src/scripts/hooks/rule_inject_hook.ts +757 -63
- package/src/scripts/hooks/table_fingerprint.ts +21 -0
- package/src/scripts/hooks/telemetry_usage_hook.ts +64 -8
- package/src/scripts/hooks/turn_end_gate_hook.ts +84 -0
- package/src/scripts/hooks_status.ts +112 -0
- package/src/scripts/injection_scan_hook.ts +7 -0
- package/src/scripts/install.ts +72 -185
- package/src/scripts/installed_layer_report.ts +103 -0
- package/src/scripts/language_mirror_hook.ts +15 -6
- package/src/scripts/learning_sidecar.ts +119 -8
- package/src/scripts/lint_hook_manifest.ts +53 -0
- package/src/scripts/lint_major_migration_sections.ts +156 -26
- package/src/scripts/lint_pack_boundaries.ts +63 -5
- package/src/scripts/lint_rule_law_section.ts +517 -0
- package/src/scripts/lint_workflow_security.ts +161 -5
- package/src/scripts/mcp_server/consumer_tool_catalog.json +53 -0
- package/src/scripts/mcp_server/graph_tools.ts +72 -3
- package/src/scripts/measure_routing_signal.ts +54 -16
- package/src/scripts/measure_skill_ranker_baseline.ts +216 -8
- package/src/scripts/memory_learn_hook.ts +91 -6
- package/src/scripts/model_rule_injection.ts +52 -5
- package/src/scripts/project_thin_rules.ts +34 -327
- package/src/scripts/report_evidence_temperature.ts +657 -0
- package/src/scripts/report_installed_rule_links.ts +157 -0
- package/src/scripts/report_label_agreement.ts +233 -0
- package/src/scripts/report_obligation_mechanism.ts +230 -0
- package/src/scripts/report_single_token_triggers.ts +277 -0
- package/src/scripts/report_skill_ranker_confusion.ts +442 -0
- package/src/scripts/report_standing_payload_by_host.ts +188 -15
- package/src/scripts/report_verification_record_coverage.ts +306 -0
- package/src/scripts/rule_activation_census.ts +5 -2
- package/src/scripts/rule_trigger_eval.ts +9 -9
- package/src/scripts/schemas/review-findings.schema.json +3 -2
- package/src/scripts/schemas/rule.schema.json +5 -0
- package/src/scripts/self_review_gate.ts +62 -7
- package/src/scripts/skill_tools/score_skill_relevance.ts +290 -25
- package/src/scripts/sweep_skill_ranker_signals.ts +129 -0
- package/src/scripts/sync_gitignore.ts +29 -235
- package/src/scripts/trigger_eval_grandfather.json +0 -5
- package/src/server/schemas/settings.ts +10 -0
- package/src/shared/skillRanking.ts +117 -11
- package/dist/cli-delegate/chunk-JNMVLWLR.js +0 -4457
- package/dist/cli-delegate/chunk-YDPILCOL.js +0 -152
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auto-carry for the archival sweep: a finished roadmap whose only obstacle is
|
|
3
|
+
* bare `[~]` steps hands them to a follow-up roadmap and then archives.
|
|
4
|
+
*
|
|
5
|
+
* WHY. The dashboard renders a roadmap with zero open steps as 100 %, deferred
|
|
6
|
+
* steps included, while the sweep refused every bare `[~]` and waited for a
|
|
7
|
+
* human to write the `carried-to` annotation by hand. Nobody did: measured
|
|
8
|
+
* 2026-10-02, five roadmaps sat at 100 % in the active tree with fourteen
|
|
9
|
+
* unannotated deferrals between them, and `/roadmap:process-full` — which ends
|
|
10
|
+
* non-interactively — had no step that could resolve one. "Finished" and
|
|
11
|
+
* "archived" had silently come apart.
|
|
12
|
+
*
|
|
13
|
+
* The disposition this module executes is the one `roadmap-progress-sync`
|
|
14
|
+
* Iron Law 3 already routes to the council without the owner: carry the item
|
|
15
|
+
* AND its blocker into a named follow-up created in the SAME change. It keeps
|
|
16
|
+
* every criterion alive in the active estate, so it is the preserving branch of
|
|
17
|
+
* the preservation test, never a drop. The owner decided on 2026-10-02 that the
|
|
18
|
+
* sweep performs it automatically instead of waiting for a menu.
|
|
19
|
+
*
|
|
20
|
+
* What the carry does, so the archived parent and the live child agree:
|
|
21
|
+
*
|
|
22
|
+
* - every bare `[~]` block is copied verbatim into the child as an OPEN `[ ]`
|
|
23
|
+
* step — open, not `[~]`, because a child at 100 % on arrival would be
|
|
24
|
+
* carried again by the next sweep, forever;
|
|
25
|
+
* - the parent's step gets `<!-- deferred-resolution: carried-to=<child> -->`,
|
|
26
|
+
* and the child gets `parent_roadmap: <parent>`, which is the pair
|
|
27
|
+
* `deferralProblems` and `lint_deferral_integrity` validate from both ends;
|
|
28
|
+
* - every OPEN blocker a carried step names via `blocked-by: <id>` moves with
|
|
29
|
+
* it: copied verbatim into the child's `## Blockers`, and closed in the
|
|
30
|
+
* parent with a status line naming where it went. The open-blocker count is
|
|
31
|
+
* unchanged, it only changes file.
|
|
32
|
+
*
|
|
33
|
+
* NOT automatic when a moved blocker waits on the OWNER (owner decision
|
|
34
|
+
* 2026-10-02): the sweep then writes nothing and asks — archive with the steps
|
|
35
|
+
* parked in `later/` (`--owner-decision later`), or work them step by step with
|
|
36
|
+
* the first one on screen. The procedure lives in `roadmap-process-loop` § 6a.
|
|
37
|
+
*
|
|
38
|
+
* Refused, so nothing is written, when the parent would still not archive
|
|
39
|
+
* afterwards: an open blocker no carried step names is a decision the parent
|
|
40
|
+
* itself raised, and carrying around it would strand the child with steps that
|
|
41
|
+
* have no reason to exist apart from the parent. A human-written annotation
|
|
42
|
+
* that fails validation is also left alone — fixing someone's wrong carry is
|
|
43
|
+
* not this module's call.
|
|
44
|
+
*/
|
|
45
|
+
|
|
46
|
+
import * as fs from 'node:fs';
|
|
47
|
+
import * as path from 'node:path';
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* `<!-- deferred-resolution: carried-to=<slug> -->` — the resolved-deferral
|
|
51
|
+
* annotation. `merged-into=<slug>` is the second accepted form.
|
|
52
|
+
*/
|
|
53
|
+
export const DEFERRED_RESOLUTION_RE =
|
|
54
|
+
/<!--\s*deferred-resolution:\s*(carried-to|merged-into)\s*=\s*([A-Za-z0-9._-]+)\s*-->/;
|
|
55
|
+
|
|
56
|
+
/** `- [~] …` — a deferred step, at any indent, with `-` or `*`. */
|
|
57
|
+
export const DEFERRED_STEP_RE = /^[ \t]*[-*][ \t]+\[~\][ \t]*(.*)$/;
|
|
58
|
+
|
|
59
|
+
/** Any other checkbox, or a heading — where a step's block ends. */
|
|
60
|
+
export const BLOCK_END_RE = /^[ \t]*[-*][ \t]+\[[ xX~-]\]|^#{1,6}[ \t]/;
|
|
61
|
+
|
|
62
|
+
const BLOCKED_BY_RE = /blocked-by:\s*([A-Za-z0-9._-]+)/g;
|
|
63
|
+
const BLOCKER_HEAD_RE = /^###[ \t]+blocker:[ \t]*(.+?)[ \t]*$/i;
|
|
64
|
+
const STATUS_LINE_RE = /^([ \t]*-[ \t]+\*\*Status:\*\*[ \t]*)(.*)$/;
|
|
65
|
+
const AC_HEADING_RE = /^##[ \t]+acceptance/i;
|
|
66
|
+
const OWNER_LINE_RE = /^[ \t]*-[ \t]+\*\*Owner:\*\*[ \t]*`?([A-Za-z]+)/;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Blocker owners that are NOT the human owner. Everything else — `maintainer`,
|
|
70
|
+
* `user`, `owner`, and any value this list does not name — is owner-dependent:
|
|
71
|
+
* in doubt it is the owner's decision, so an unrecognised owner fails closed.
|
|
72
|
+
*/
|
|
73
|
+
const AGENT_SIDE_OWNERS: ReadonlySet<string> = new Set(['implementer', 'council', 'agent', 'ai']);
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* What happens to deferrals whose blockers wait on the owner.
|
|
77
|
+
*
|
|
78
|
+
* `ask` (default): nothing is written; the sweep reports the decision instead —
|
|
79
|
+
* archive with the steps parked in `later/`, or work them step by step.
|
|
80
|
+
* `later`: the owner chose to archive; the carry lands in `later/`.
|
|
81
|
+
*/
|
|
82
|
+
export type OwnerDecision = 'ask' | 'later';
|
|
83
|
+
|
|
84
|
+
/** The lightweight cap `lint_roadmap_complexity` enforces, with margin. */
|
|
85
|
+
const LIGHTWEIGHT_LINE_BUDGET = 500;
|
|
86
|
+
|
|
87
|
+
const DISPOSITION_DIRS: readonly string[] = ['', 'later', 'archive', 'skipped'];
|
|
88
|
+
|
|
89
|
+
interface BareStep {
|
|
90
|
+
/** Line index of the `[~]` line in the parent. */
|
|
91
|
+
line: number;
|
|
92
|
+
/** The step line plus its continuation block, dedented to the step. */
|
|
93
|
+
block: string[];
|
|
94
|
+
isAcceptance: boolean;
|
|
95
|
+
blockerIds: string[];
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
interface BlockerSpan {
|
|
99
|
+
id: string;
|
|
100
|
+
start: number;
|
|
101
|
+
end: number;
|
|
102
|
+
open: boolean;
|
|
103
|
+
ownerDependent: boolean;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export interface CarryPlan {
|
|
107
|
+
destSlug: string;
|
|
108
|
+
destRel: string;
|
|
109
|
+
destText: string;
|
|
110
|
+
sourceText: string;
|
|
111
|
+
carried: number;
|
|
112
|
+
movedBlockers: string[];
|
|
113
|
+
/** Moved blockers only the owner can resolve. Non-empty ⇒ the owner decides. */
|
|
114
|
+
ownerBlockers: string[];
|
|
115
|
+
/** The first carried step, verbatim, for the step-by-step offer. */
|
|
116
|
+
firstStep: string;
|
|
117
|
+
/** True when the carry targets `later/` (owner chose to archive). */
|
|
118
|
+
parked: boolean;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export type CarryOutcome = { plan: CarryPlan } | { refused: string };
|
|
122
|
+
|
|
123
|
+
function _bareSteps(lines: readonly string[]): BareStep[] {
|
|
124
|
+
const out: BareStep[] = [];
|
|
125
|
+
let inAcceptance = false;
|
|
126
|
+
// No fence skipping, on purpose: `parseDeferredItems` does not skip fences
|
|
127
|
+
// either, and a step this module did not see but the sweep's validation does
|
|
128
|
+
// would be written, then refused.
|
|
129
|
+
for (let i = 0; i < lines.length; i++) {
|
|
130
|
+
const line = lines[i] as string;
|
|
131
|
+
if (/^##[ \t]/.test(line)) inAcceptance = AC_HEADING_RE.test(line);
|
|
132
|
+
const m = DEFERRED_STEP_RE.exec(line);
|
|
133
|
+
if (m === null) continue;
|
|
134
|
+
let end = i + 1;
|
|
135
|
+
while (end < lines.length && !BLOCK_END_RE.test(lines[end] as string)) end++;
|
|
136
|
+
const raw = lines.slice(i, end);
|
|
137
|
+
if (DEFERRED_RESOLUTION_RE.test(raw.join('\n'))) continue;
|
|
138
|
+
while (raw.length > 1 && (raw[raw.length - 1] as string).trim() === '') raw.pop();
|
|
139
|
+
const indent = (/^[ \t]*/.exec(line) as RegExpExecArray)[0].length;
|
|
140
|
+
const block = raw.map((l) => (l.slice(0, indent).trim() === '' ? l.slice(indent) : l));
|
|
141
|
+
const ids = new Set<string>();
|
|
142
|
+
for (const b of raw) for (const hit of b.matchAll(BLOCKED_BY_RE)) ids.add(hit[1] as string);
|
|
143
|
+
out.push({ line: i, block, isAcceptance: inAcceptance, blockerIds: [...ids] });
|
|
144
|
+
}
|
|
145
|
+
return out;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function _blockerSpans(lines: readonly string[]): BlockerSpan[] {
|
|
149
|
+
const start = lines.findIndex((l) => /^##[ \t]+Blockers[ \t]*$/i.test(l));
|
|
150
|
+
if (start === -1) return [];
|
|
151
|
+
let sectionEnd = lines.length;
|
|
152
|
+
for (let i = start + 1; i < lines.length; i++) {
|
|
153
|
+
if (/^##[ \t]+\S/.test(lines[i] as string)) {
|
|
154
|
+
sectionEnd = i;
|
|
155
|
+
break;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
const spans: BlockerSpan[] = [];
|
|
159
|
+
for (let i = start + 1; i < sectionEnd; i++) {
|
|
160
|
+
const m = BLOCKER_HEAD_RE.exec(lines[i] as string);
|
|
161
|
+
if (m === null) continue;
|
|
162
|
+
let end = i + 1;
|
|
163
|
+
while (end < sectionEnd && !/^###?[ \t]/.test(lines[end] as string)) end++;
|
|
164
|
+
const status = lines
|
|
165
|
+
.slice(i, end)
|
|
166
|
+
.map((l) => STATUS_LINE_RE.exec(l))
|
|
167
|
+
.find((s) => s !== null);
|
|
168
|
+
const value = (status?.[2] ?? 'open').trim().toLowerCase();
|
|
169
|
+
const owner = lines
|
|
170
|
+
.slice(i, end)
|
|
171
|
+
.map((l) => OWNER_LINE_RE.exec(l))
|
|
172
|
+
.find((o) => o !== null);
|
|
173
|
+
spans.push({
|
|
174
|
+
id: (m[1] as string).trim(),
|
|
175
|
+
start: i,
|
|
176
|
+
end,
|
|
177
|
+
open: !/^resolved\b/.test(value),
|
|
178
|
+
ownerDependent: !AGENT_SIDE_OWNERS.has((owner?.[1] ?? '').toLowerCase()),
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
return spans;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function _plusDays(date: string, days: number): string {
|
|
185
|
+
const d = new Date(`${date}T00:00:00Z`);
|
|
186
|
+
d.setUTCDate(d.getUTCDate() + days);
|
|
187
|
+
return d.toISOString().slice(0, 10);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/** The first `<base>-carried[-N]` slug no roadmap directory already holds. */
|
|
191
|
+
export function nextCarrySlug(root: string, sourceSlug: string): string {
|
|
192
|
+
const base = sourceSlug.replace(/-carried(-\d+)?$/, '');
|
|
193
|
+
for (let n = 1; ; n++) {
|
|
194
|
+
const slug = n === 1 ? `${base}-carried` : `${base}-carried-${n}`;
|
|
195
|
+
const taken = DISPOSITION_DIRS.some((d) =>
|
|
196
|
+
fs.existsSync(path.join(root, 'agents', 'roadmaps', d, `${slug}.md`)),
|
|
197
|
+
);
|
|
198
|
+
if (!taken) return slug;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function _title(sourceText: string, sourceSlug: string): string {
|
|
203
|
+
const h1 = /^#[ \t]+(.+?)[ \t]*$/m.exec(sourceText.replace(/^---\n[\s\S]*?\n---\n/, ''));
|
|
204
|
+
return h1 !== null ? (h1[1] as string) : sourceSlug.replace(/-/g, ' ');
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Plan the carry for one roadmap. Pure apart from reading which slugs exist, so
|
|
209
|
+
* the sweep can decide before it writes anything.
|
|
210
|
+
*
|
|
211
|
+
* @param openBlockerIds every OPEN blocker the parent carries, as `collect()`
|
|
212
|
+
* counts them — the source of truth for "would it archive afterwards".
|
|
213
|
+
*/
|
|
214
|
+
export function planCarry(
|
|
215
|
+
root: string,
|
|
216
|
+
rel: string,
|
|
217
|
+
text: string,
|
|
218
|
+
openBlockerIds: readonly string[],
|
|
219
|
+
date: string,
|
|
220
|
+
ownerDecision: OwnerDecision = 'ask',
|
|
221
|
+
): CarryOutcome {
|
|
222
|
+
const sourceSlug = rel.replace(/\.md$/, '');
|
|
223
|
+
const lines = text.split('\n');
|
|
224
|
+
const steps = _bareSteps(lines);
|
|
225
|
+
if (steps.length === 0) return { refused: 'no bare `[~]` step to carry' };
|
|
226
|
+
|
|
227
|
+
const named = new Set(steps.flatMap((s) => s.blockerIds));
|
|
228
|
+
const stranded = openBlockerIds.filter((id) => !named.has(id));
|
|
229
|
+
if (stranded.length > 0) {
|
|
230
|
+
return {
|
|
231
|
+
refused:
|
|
232
|
+
`open blocker(s) no deferred step names (${stranded.join(', ')}) — ` +
|
|
233
|
+
'carrying around them would not let this roadmap archive',
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
const moved = _blockerSpans(lines).filter((b) => b.open && named.has(b.id));
|
|
237
|
+
const ownerBlockers = moved.filter((b) => b.ownerDependent).map((b) => b.id);
|
|
238
|
+
const parked = ownerBlockers.length > 0 && ownerDecision === 'later';
|
|
239
|
+
|
|
240
|
+
const destSlug = nextCarrySlug(root, sourceSlug);
|
|
241
|
+
const annotation = `<!-- deferred-resolution: carried-to=${destSlug} -->`;
|
|
242
|
+
|
|
243
|
+
const out = [...lines];
|
|
244
|
+
for (const b of moved) {
|
|
245
|
+
for (let i = b.start; i < b.end; i++) {
|
|
246
|
+
const s = STATUS_LINE_RE.exec(out[i] as string);
|
|
247
|
+
if (s === null) continue;
|
|
248
|
+
out[i] =
|
|
249
|
+
`${s[1] as string}resolved — carried, still open, to \`${destSlug}\` ` +
|
|
250
|
+
`with the steps it blocks (was: ${(s[2] as string).trim()})`;
|
|
251
|
+
break;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
for (const s of steps) out[s.line] = `${out[s.line] as string} ${annotation}`;
|
|
255
|
+
|
|
256
|
+
const toOpen = (block: readonly string[]): string =>
|
|
257
|
+
block.map((l, i) => (i === 0 ? l.replace(/\[~\]/, '[ ]') : l)).join('\n');
|
|
258
|
+
const phaseSteps = steps.filter((s) => !s.isAcceptance).map((s) => toOpen(s.block));
|
|
259
|
+
const acSteps = steps.filter((s) => s.isAcceptance).map((s) => toOpen(s.block));
|
|
260
|
+
const phaseName = `Deferred steps carried from ${sourceSlug}`;
|
|
261
|
+
const blockerText = moved.map((b) => lines.slice(b.start, b.end).join('\n').trimEnd());
|
|
262
|
+
|
|
263
|
+
const body = [
|
|
264
|
+
`# ${_title(text, sourceSlug)} — carried`,
|
|
265
|
+
'',
|
|
266
|
+
`> **Source:** carried by the archival sweep on ${date} from`,
|
|
267
|
+
`> [\`${sourceSlug}\`](${parked ? '../' : ''}archive/${sourceSlug}.md), which closed every other step.`,
|
|
268
|
+
'> Each step below was `[~]` there and is restated verbatim as open work, so',
|
|
269
|
+
'> archiving the parent buried nothing. Blockers the steps name moved with them.',
|
|
270
|
+
'',
|
|
271
|
+
'## Goal',
|
|
272
|
+
'',
|
|
273
|
+
`Every step ${sourceSlug} deferred is either done here or explicitly disposed`,
|
|
274
|
+
'of — a step that still cannot run is re-deferred with its reason, never',
|
|
275
|
+
'left to read as finished.',
|
|
276
|
+
'',
|
|
277
|
+
`## Phase 1 — ${phaseName}`,
|
|
278
|
+
'',
|
|
279
|
+
phaseSteps.length > 0
|
|
280
|
+
? phaseSteps.join('\n')
|
|
281
|
+
: '- [ ] **1.1 Close the carried acceptance criteria below.** The parent deferred\n' +
|
|
282
|
+
' only acceptance criteria; this step is done when each is checked or disposed of.\n' +
|
|
283
|
+
' verify: every criterion under `## Acceptance Criteria` is `[x]` or `[-]`',
|
|
284
|
+
'',
|
|
285
|
+
...(blockerText.length > 0 ? ['## Blockers', '', blockerText.join('\n\n'), ''] : []),
|
|
286
|
+
'## Risk Register',
|
|
287
|
+
`<!-- risk-review: v1 | reviewed: ${date} | reviewer: archive-sweep/auto-carry -->`,
|
|
288
|
+
'',
|
|
289
|
+
'| Rank | Item | Risk type | Description | Mitigation | Anchored under |',
|
|
290
|
+
'|------|------|-----------|-------------|------------|----------------|',
|
|
291
|
+
'| 1 | Carried steps stay blocked indefinitely | implementation | A step deferred ' +
|
|
292
|
+
'once for elapsed time or a decision can sit here as long as it sat in the parent | ' +
|
|
293
|
+
'It now counts as open work in the dashboard instead of as 100 %, and its blocker ' +
|
|
294
|
+
`is listed where the estate gates count it | Phase 1 — ${phaseName} |`,
|
|
295
|
+
'',
|
|
296
|
+
'## Acceptance Criteria',
|
|
297
|
+
'',
|
|
298
|
+
acSteps.length > 0
|
|
299
|
+
? acSteps.join('\n')
|
|
300
|
+
: `- [ ] AC-1 — No step carried from \`${sourceSlug}\` is still \`[ ]\` without a recorded disposition.`,
|
|
301
|
+
'',
|
|
302
|
+
].join('\n');
|
|
303
|
+
const complexity = body.split('\n').length > LIGHTWEIGHT_LINE_BUDGET ? 'structural' : 'lightweight';
|
|
304
|
+
// Parked: `status: later` plus the three-part `entry_condition:` mapping
|
|
305
|
+
// `lint_roadmap_later_disposition` requires, and the growth claim the
|
|
306
|
+
// `later_roadmaps` count needs — a new file in `later/` is not a parking
|
|
307
|
+
// move, so no allowance covers it otherwise.
|
|
308
|
+
const ids = ownerBlockers.join(', ');
|
|
309
|
+
const parkedKeys = parked
|
|
310
|
+
? 'entry_condition:\n' +
|
|
311
|
+
` what: the owner resolves blocker(s) ${ids}\n` +
|
|
312
|
+
' when: whenever the owner takes the next step\n' +
|
|
313
|
+
' who: owner\n' +
|
|
314
|
+
// `lint_roadmap_later_disposition` rule C: a park with no review date
|
|
315
|
+
// reads exactly like an abandonment.
|
|
316
|
+
`review_by: ${_plusDays(date, 90)}\n` +
|
|
317
|
+
`estate_growth_exempt: >-\n Owner-chosen archive of ${sourceSlug}: its deferred steps wait on owner\n` +
|
|
318
|
+
` blocker(s) ${ids} and are parked here instead of left active. The parent\n` +
|
|
319
|
+
' is archived in the same change, so the active count drops by one.\n'
|
|
320
|
+
: '';
|
|
321
|
+
const destText =
|
|
322
|
+
`---\ncomplexity: ${complexity}\nstatus: ${parked ? 'later' : 'ready'}\nexecution:\n mode: phase-checkpoints\n` +
|
|
323
|
+
`parent_roadmap: ${sourceSlug}\n${parkedKeys}---\n${body}`;
|
|
324
|
+
const destRel = parked ? `agents/roadmaps/later/${destSlug}.md` : `agents/roadmaps/${destSlug}.md`;
|
|
325
|
+
|
|
326
|
+
return {
|
|
327
|
+
plan: {
|
|
328
|
+
destSlug,
|
|
329
|
+
destRel,
|
|
330
|
+
destText,
|
|
331
|
+
sourceText: out.join('\n'),
|
|
332
|
+
carried: steps.length,
|
|
333
|
+
movedBlockers: moved.map((b) => b.id),
|
|
334
|
+
ownerBlockers,
|
|
335
|
+
firstStep: (steps[0] as BareStep).block.join('\n'),
|
|
336
|
+
parked,
|
|
337
|
+
},
|
|
338
|
+
};
|
|
339
|
+
}
|
|
@@ -1351,7 +1351,10 @@ function main(argv?: readonly string[]): number {
|
|
|
1351
1351
|
// leaves behind rather than the one it found. `--check` never archives: a
|
|
1352
1352
|
// gate that mutates the tree it is checking cannot be trusted by CI.
|
|
1353
1353
|
let sweep_out = '';
|
|
1354
|
-
|
|
1354
|
+
// `pending_iron_law_3` too: a 100 % roadmap with bare `[~]` steps is what the
|
|
1355
|
+
// sweep's carry exists for, and gating on `deferred === 0` never spawned it.
|
|
1356
|
+
const before = collect(roadmap_root);
|
|
1357
|
+
if (!args.check && args.archive && unarchived_complete(before).length + pending_iron_law_3(before).length > 0) {
|
|
1355
1358
|
const swept = run_archival_sweep(repo_root);
|
|
1356
1359
|
sweep_out = swept.stdout;
|
|
1357
1360
|
if (swept.stderr) {
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"refresh_cadence": "quarterly",
|
|
29
29
|
"upstream": {
|
|
30
30
|
"repo": "derived: RFC 9110/9457/7396/8288 + httpapi WG drafts",
|
|
31
|
-
"sha": "RFC 9110 (STD 97) / 9457 / 7396 / 8288 \u2014
|
|
32
|
-
"last_checked": "2026-
|
|
31
|
+
"sha": "RFC 9110 (STD 97, 2022-06) / 9457 (2023-07, obsoletes 7807) / 7396 (2014-10) / 8288 (2017-10) \u2014 all Standards Track",
|
|
32
|
+
"last_checked": "2026-10-04"
|
|
33
33
|
}
|
|
34
34
|
}
|
|
@@ -234,3 +234,20 @@ When a test fails, do not retry blindly with tweaked assertions until something
|
|
|
234
234
|
## Clarification guard — ambiguous contract → ask
|
|
235
235
|
|
|
236
236
|
If the endpoint contract is ambiguous (unclear status code, optional fields, error envelope shape), do not assume. Ask the user or check the OpenAPI spec / route definition before writing assertions — never guess the response shape from the route name.
|
|
237
|
+
|
|
238
|
+
## The HTTP-assertion idiom, per ecosystem
|
|
239
|
+
|
|
240
|
+
The examples above are Laravel's. The *shape* they teach — assert the status,
|
|
241
|
+
then the body contract, then the side effect, and keep one behavior per test —
|
|
242
|
+
transfers unchanged; the API does not. Resolve the runner with
|
|
243
|
+
`resolve_toolchain` and read its `ecosystems`:
|
|
244
|
+
|
|
245
|
+
| `ecosystems` | Request + assertion surface |
|
|
246
|
+
|---|---|
|
|
247
|
+
| `php` | `$this->getJson(...)` / `assertStatus` / `assertJsonPath` |
|
|
248
|
+
| `js` | `supertest` or the framework's own test client, with `expect(res.status)` |
|
|
249
|
+
| `python` | `httpx.AsyncClient` / framework `TestClient`; `assert res.status_code` |
|
|
250
|
+
| `go` | `httptest.NewServer` + `net/http`, or the router's own `ServeHTTP` |
|
|
251
|
+
|
|
252
|
+
Whatever the surface, the negative tests are not optional: unauthenticated,
|
|
253
|
+
not-owner and cross-tenant each get their own case, per `broken-access-control`.
|
|
@@ -245,14 +245,26 @@ paragraph claiming "the same five answers" directly after a list of four:
|
|
|
245
245
|
| `graph_dead` | `dead` |
|
|
246
246
|
| `graph_query` | `query` |
|
|
247
247
|
| `graph_path` | `path` |
|
|
248
|
+
| `graph_node` | no CLI verb — one symbol's location, in-edges, out-edges and degree |
|
|
248
249
|
|
|
249
250
|
`untested` has no tool of its own; it is a flag on `graph_impact`, because the
|
|
250
|
-
two answer the same question over the same diff and a
|
|
251
|
-
standing context for a boolean. `graph_impact` is the only one that is not
|
|
251
|
+
two answer the same question over the same diff and a separate tool would have
|
|
252
|
+
cost standing context for a boolean. `graph_impact` is the only one that is not
|
|
252
253
|
read-only — it runs `git diff --name-only` to resolve its rev — and
|
|
253
254
|
`graph_dead`'s refusal arrives as `status: "refused"`, never as `status: "ok"`
|
|
254
255
|
with an empty list.
|
|
255
256
|
|
|
257
|
+
`graph_node` is the one entry with no CLI verb behind it, and the one that
|
|
258
|
+
REFUSES a seed it cannot resolve exactly. Every other reader answers about a
|
|
259
|
+
neighbourhood or a set, where a best-guess seed costs the caller one wrong line
|
|
260
|
+
among several; a node view's every field — the location, the degree, both edge
|
|
261
|
+
lists — is a statement about ONE node, so a guess is wrong in all of them at
|
|
262
|
+
once. It resolves on the exact tiers of the same seed ladder (node id, then
|
|
263
|
+
label) and returns `status: "refused"` naming the candidates when a label is
|
|
264
|
+
ambiguous, rather than scoring free text — which is the retrieval class the
|
|
265
|
+
measured null covers (`docs/CLAIMS.md`, `code-graph-retrieval-null`). Use
|
|
266
|
+
`graph_query` when a best-guess match is what you want.
|
|
267
|
+
|
|
256
268
|
**No ordering claim is added here, and no measurement claim either.** These
|
|
257
269
|
verbs are cheaper than reconstructing the same relationship by hand — that is a
|
|
258
270
|
claim about the ALTERNATIVE being a manual reconstruction, not about grep.
|
|
@@ -38,7 +38,7 @@ what this skill owns.
|
|
|
38
38
|
imported observation.
|
|
39
39
|
5. On the human's accept, persist the chosen fields into `DESIGN.md`. Where the
|
|
40
40
|
consumer wants a token source of truth, hand the mapped DTCG fields to
|
|
41
|
-
|
|
41
|
+
`brand-to-tokens` / `design-tokens` to
|
|
42
42
|
materialise `.tokens.json` — do not invent a parallel token format.
|
|
43
43
|
|
|
44
44
|
**Two sources, one shape:**
|
|
@@ -228,7 +228,7 @@ this component satisfy the artifact"* — which is a different question with a
|
|
|
228
228
|
different answer, because a candidate can be an excellent name-and-props match
|
|
229
229
|
and still use the wrong type scale, the wrong control, or a colour the artifact
|
|
230
230
|
never states. Until this step existed nothing anywhere asked the second
|
|
231
|
-
question, while
|
|
231
|
+
question, while `ui-audit-gate` carried *"reuse
|
|
232
232
|
beats duplication"* as unqualified prose. Reused on an artifact port, an
|
|
233
233
|
unconforming candidate is a fidelity deviation dressed as good hygiene.
|
|
234
234
|
|
|
@@ -364,7 +364,7 @@ Load on demand once the audit needs the pitfall catalog:
|
|
|
364
364
|
**Design-system export (current-repo source):** when the goal is to seed
|
|
365
365
|
`DESIGN.md` from *this* repo, emit the inventory as a `design-system.json`
|
|
366
366
|
artifact (the import contract in
|
|
367
|
-
|
|
367
|
+
`design-system-capture`)
|
|
368
368
|
and hand it to `design-system-capture` — the same shape an external extraction
|
|
369
369
|
tool produces, so the import path is uniform.
|
|
370
370
|
|
|
@@ -29,7 +29,7 @@ machinery that already exists: `search_stack` in
|
|
|
29
29
|
[`corpus-grounding`](../corpus-grounding/SKILL.md)
|
|
30
30
|
(`scripts/decision_engine.ts`), whose stack corpus carries `threejs.csv` among
|
|
31
31
|
its stacks, read beside the register in
|
|
32
|
-
|
|
32
|
+
`design-intelligence`
|
|
33
33
|
§ Register. No second frontend executor is declared, and none is needed: a
|
|
34
34
|
renderer changes what you ground against, never who writes the UI.
|
|
35
35
|
|
|
@@ -42,7 +42,7 @@ execution:
|
|
|
42
42
|
is the anti-pattern [`icon-consistency`](../../rules/icon-consistency.md)
|
|
43
43
|
§ What this gates names by name. Stop at the first rung that answers.
|
|
44
44
|
1. **A brand token or brand guide that names an icon set** — authoritative,
|
|
45
|
-
stop here (
|
|
45
|
+
stop here (`brand-source-of-truth`).
|
|
46
46
|
2. **The set already in use in this project** — detected at the Inspect step
|
|
47
47
|
of the Iconography floor below. One icon system per project; a second
|
|
48
48
|
visual language is the defect, not a preference.
|
|
@@ -17,7 +17,7 @@ packs:
|
|
|
17
17
|
> A React or TypeScript consumer receives this skill through `engineering-base`, which both
|
|
18
18
|
> of those packs require.
|
|
19
19
|
|
|
20
|
-
The JavaScript twin of
|
|
20
|
+
The JavaScript twin of `composer-packages`. A component is
|
|
21
21
|
a file; a **library** is a package with a public surface, and that surface is declared in
|
|
22
22
|
`package.json` rather than inferred. Most of the failures below are silent at author time
|
|
23
23
|
and loud at the consumer's — which is why the surface is read, not assumed.
|
|
@@ -167,7 +167,7 @@ declared cost — never here.
|
|
|
167
167
|
|
|
168
168
|
## See also
|
|
169
169
|
|
|
170
|
-
-
|
|
170
|
+
- `composer-packages` — the PHP twin; same surface discipline, different manifest.
|
|
171
171
|
- [`standards-from-config`](../standards-from-config/SKILL.md) — the Class-A rule the § Release branch follows.
|
|
172
172
|
- [`conventional-commits-writing`](../conventional-commits-writing/SKILL.md) — the `!` marker a release tool reads.
|
|
173
173
|
- [`ui-component-architect`](../ui-component-architect/SKILL.md) — the component inside the library; this skill is the package around it.
|
|
@@ -104,7 +104,7 @@ for `workspace:`-linked packages.
|
|
|
104
104
|
|
|
105
105
|
State plainly that the listing came from manifests rather than the runner — an
|
|
106
106
|
inferred target list can miss runner-inferred targets. This is the posture
|
|
107
|
-
|
|
107
|
+
`react-shadcn-ui` already takes for the shadcn
|
|
108
108
|
CLI; the stop condition is `missing-tool-handling` (never install it silently,
|
|
109
109
|
never fake the output).
|
|
110
110
|
|
|
@@ -27,6 +27,8 @@ Use this skill whenever running or configuring code quality tools:
|
|
|
27
27
|
|
|
28
28
|
- **PHP**: PHPStan (static analysis), Rector (automated refactoring), ECS (coding standards)
|
|
29
29
|
- **JS/TS**: Biome (linting + formatting), TypeScript compiler (type checking), Jest/Vitest (tests)
|
|
30
|
+
- **Python**: Ruff (linting + formatting), mypy (type checking), pytest (tests)
|
|
31
|
+
- **Go**: `gofmt`, `go vet`, optionally golangci-lint, `go test`
|
|
30
32
|
|
|
31
33
|
## Modes
|
|
32
34
|
|
|
@@ -39,8 +41,16 @@ stack calls for.
|
|
|
39
41
|
|---|---|---|
|
|
40
42
|
| PHP (`.php` changed) | [`references/php-tools.md`](references/php-tools.md) | Tool detection, PHPStan / ECS / Rector commands and flags, combined pipeline, config files, baseline policy, PHPStan error handling, testing framework, git-aware execution |
|
|
41
43
|
| JS/TS (`.js` / `.ts` / `.tsx` changed) | [`references/js-ts-tools.md`](references/js-ts-tools.md) | Detection, Biome, TypeScript type checking, Jest / Vitest, the JS/TS workflow sequence |
|
|
44
|
+
| Python (`.py` changed, or `pyproject.toml`) | [`references/python-tools.md`](references/python-tools.md) | Detection from `pyproject.toml`, Ruff, mypy, pytest, the workflow sequence, virtualenv and `setup.cfg` gotchas |
|
|
45
|
+
| Go (`.go` changed, or `go.mod`) | [`references/go-tools.md`](references/go-tools.md) | `gofmt`, `go vet`, golangci-lint where present, `go test`, the workflow sequence, vendor and build-tag gotchas |
|
|
42
46
|
|
|
43
|
-
|
|
47
|
+
More than one stack changed → load each mode body and run each pipeline.
|
|
48
|
+
|
|
49
|
+
**The resolver decides which row applies, not the file extension alone.**
|
|
50
|
+
`resolve_toolchain` returns the ecosystems it found and the quality commands
|
|
51
|
+
per ecosystem; the rows above name what those commands are. A TypeScript
|
|
52
|
+
repository resolves the ecosystem `js`, never `typescript` — the pack name and
|
|
53
|
+
the ecosystem label are different vocabularies.
|
|
44
54
|
|
|
45
55
|
## Execution policy — on demand only, never proactive
|
|
46
56
|
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# quality-tools — Go quality tools
|
|
2
|
+
|
|
3
|
+
> Mode body of the [`quality-tools`](../SKILL.md) skill. Load this file when
|
|
4
|
+
> the mode table in SKILL.md routes here. The cross-mode material — execution
|
|
5
|
+
> policy, environment, output discipline — stays in SKILL.md and is NOT
|
|
6
|
+
> repeated here.
|
|
7
|
+
|
|
8
|
+
# Go Quality Tools
|
|
9
|
+
|
|
10
|
+
## Detection
|
|
11
|
+
|
|
12
|
+
`resolve_toolchain` (`work_engine/stack/runner.ts`) keys the Go ecosystem on
|
|
13
|
+
`go.mod` and resolves exactly one quality command, `go vet ./...`, plus the
|
|
14
|
+
test command `go test ./...`. It does **not** detect `golangci-lint`, so a
|
|
15
|
+
repository that uses one will show a `quality` list shorter than what its CI
|
|
16
|
+
runs. Read the repository's CI workflow before concluding the resolver's list
|
|
17
|
+
is the whole gate.
|
|
18
|
+
|
|
19
|
+
| Signal | Tool | What it does |
|
|
20
|
+
|---|---|---|
|
|
21
|
+
| `go.mod` present | **`go vet`** | The toolchain's own correctness checks — printf verbs, struct tags, unreachable code, lost cancel |
|
|
22
|
+
| `go.mod` present | **`gofmt`** | Canonical formatting; not resolved as a command because it is not optional in Go |
|
|
23
|
+
| `.golangci.yml` / `.golangci.yaml` | **golangci-lint** | Meta-linter; the resolver does not detect it |
|
|
24
|
+
|
|
25
|
+
## The toolchain's own commands
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
gofmt -l . # list files whose formatting differs — empty is the pass
|
|
29
|
+
gofmt -w . # rewrite them
|
|
30
|
+
go vet ./... # the resolver's quality command
|
|
31
|
+
go build ./... # compiles; the cheapest proof the tree is coherent
|
|
32
|
+
go test ./... # the resolver's test command
|
|
33
|
+
go test -run '<regexp>' ./pkg/... # the targeted probe
|
|
34
|
+
go test -race ./... # the race detector — slow, and the only thing that finds a data race
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
**`gofmt -l .` with empty output is the pass.** It exits 0 whether or not it
|
|
38
|
+
listed files, so a pipeline that checks only the exit code never fails on
|
|
39
|
+
formatting. Check the output, not the status.
|
|
40
|
+
|
|
41
|
+
## golangci-lint, where a project has it
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
golangci-lint run # the whole configured set
|
|
45
|
+
golangci-lint run ./pkg/... # scoped to a package
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
It wraps `go vet` among others, so a project with `.golangci.yml` does not
|
|
49
|
+
need `go vet` run separately — and running both doubles the report rather than
|
|
50
|
+
widening it.
|
|
51
|
+
|
|
52
|
+
## Workflow sequence
|
|
53
|
+
|
|
54
|
+
1. `gofmt -l .` — read the output, not the exit code.
|
|
55
|
+
2. `go build ./...` — a compile error makes every later step meaningless.
|
|
56
|
+
3. `go vet ./...`, or `golangci-lint run` where the project has it.
|
|
57
|
+
4. `go test -run '<the thing you changed>' ./pkg/...` — targeted.
|
|
58
|
+
5. `go test ./...`, once, at the end; `-race` where concurrency changed.
|
|
59
|
+
|
|
60
|
+
## Gotchas
|
|
61
|
+
|
|
62
|
+
- **`./...` from the wrong directory.** The pattern is relative to the working
|
|
63
|
+
directory, not to the module root. Run it from the directory holding
|
|
64
|
+
`go.mod`, or name the module path.
|
|
65
|
+
- **A vendored tree.** With `vendor/` present the toolchain defaults to
|
|
66
|
+
`-mod=vendor`; a dependency added to `go.mod` but not vendored fails to build
|
|
67
|
+
with an error that names the package, not the mode. `go mod vendor` after any
|
|
68
|
+
dependency change.
|
|
69
|
+
- **Build tags hide packages.** `go vet ./...` and `go test ./...` skip files
|
|
70
|
+
excluded by build constraints, so a green run says nothing about a
|
|
71
|
+
`//go:build integration` file. Name the tag (`-tags integration`) to reach it.
|
|
72
|
+
- **No `go` pack exists in this suite yet.** Go artifacts route through
|
|
73
|
+
`engineering-base` and this reference; `src/packs/go/pack.yaml` <!-- ref-ignore --> is created by
|
|
74
|
+
`road-to-stacks-beyond-php` step 2.3, which is blocked on the programme's
|
|
75
|
+
skill-growth question. Until then this file is the whole of the Go quality
|
|
76
|
+
surface, by design rather than by omission.
|