@event4u/agent-config 1.16.0 → 1.18.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/.agent-src/commands/{agents-audit.md → agents/audit.md} +4 -3
- package/.agent-src/commands/{agents-cleanup.md → agents/cleanup.md} +12 -6
- package/.agent-src/commands/{agents-prepare.md → agents/prepare.md} +4 -3
- package/.agent-src/commands/agents.md +46 -0
- package/.agent-src/commands/{chat-history-checkpoint.md → chat-history/checkpoint.md} +4 -4
- package/.agent-src/commands/{chat-history-clear.md → chat-history/clear.md} +4 -4
- package/.agent-src/commands/{chat-history-resume.md → chat-history/resume.md} +4 -4
- package/.agent-src/commands/chat-history/show.md +107 -0
- package/.agent-src/commands/chat-history.md +33 -89
- package/.agent-src/commands/{commit-in-chunks.md → commit/in-chunks.md} +15 -13
- package/.agent-src/commands/commit.md +22 -2
- package/.agent-src/commands/{context-create.md → context/create.md} +4 -3
- package/.agent-src/commands/{context-refactor.md → context/refactor.md} +4 -3
- package/.agent-src/commands/context.md +44 -0
- package/.agent-src/commands/{copilot-agents-init.md → copilot-agents/init.md} +4 -3
- package/.agent-src/commands/{copilot-agents-optimize.md → copilot-agents/optimize.md} +4 -3
- package/.agent-src/commands/copilot-agents.md +44 -0
- package/.agent-src/commands/council/default.md +221 -0
- package/.agent-src/commands/{council-design.md → council/design.md} +6 -5
- package/.agent-src/commands/{council-optimize.md → council/optimize.md} +7 -6
- package/.agent-src/commands/{council-pr.md → council/pr.md} +6 -5
- package/.agent-src/commands/council.md +47 -212
- package/.agent-src/commands/{create-pr-description.md → create-pr/description-only.md} +4 -2
- package/.agent-src/commands/create-pr.md +26 -5
- package/.agent-src/commands/{feature-dev.md → feature/dev.md} +5 -10
- package/.agent-src/commands/{feature-explore.md → feature/explore.md} +4 -8
- package/.agent-src/commands/{feature-plan.md → feature/plan.md} +4 -8
- package/.agent-src/commands/{feature-refactor.md → feature/refactor.md} +4 -8
- package/.agent-src/commands/{feature-roadmap.md → feature/roadmap.md} +6 -10
- package/.agent-src/commands/feature.md +6 -12
- package/.agent-src/commands/{fix-ci.md → fix/ci.md} +4 -8
- package/.agent-src/commands/{fix-portability.md → fix/portability.md} +4 -8
- package/.agent-src/commands/{fix-pr-bot-comments.md → fix/pr-bots.md} +4 -8
- package/.agent-src/commands/{fix-pr-developer-comments.md → fix/pr-developers.md} +4 -8
- package/.agent-src/commands/{fix-pr-comments.md → fix/pr.md} +7 -11
- package/.agent-src/commands/{fix-references.md → fix/refs.md} +4 -8
- package/.agent-src/commands/{fix-seeder.md → fix/seeder.md} +4 -8
- package/.agent-src/commands/fix.md +7 -13
- package/.agent-src/commands/{do-and-judge.md → judge/on-diff.md} +4 -3
- package/.agent-src/commands/judge/solo.md +90 -0
- package/.agent-src/commands/{do-in-steps.md → judge/steps.md} +4 -3
- package/.agent-src/commands/judge.md +35 -70
- package/.agent-src/commands/{memory-add.md → memory/add.md} +4 -3
- package/.agent-src/commands/{memory-full.md → memory/load.md} +4 -3
- package/.agent-src/commands/{memory-promote.md → memory/promote.md} +4 -3
- package/.agent-src/commands/{propose-memory.md → memory/propose.md} +4 -3
- package/.agent-src/commands/memory.md +48 -0
- package/.agent-src/commands/{module-create.md → module/create.md} +4 -3
- package/.agent-src/commands/{module-explore.md → module/explore.md} +4 -3
- package/.agent-src/commands/module.md +44 -0
- package/.agent-src/commands/{optimize-agents.md → optimize/agents.md} +4 -8
- package/.agent-src/commands/{optimize-augmentignore.md → optimize/augmentignore.md} +4 -9
- package/.agent-src/commands/{optimize-rtk-filters.md → optimize/rtk.md} +4 -8
- package/.agent-src/commands/{optimize-skills.md → optimize/skills.md} +4 -8
- package/.agent-src/commands/optimize.md +4 -10
- package/.agent-src/commands/{override-create.md → override/create.md} +4 -3
- package/.agent-src/commands/{override-manage.md → override/manage.md} +4 -3
- package/.agent-src/commands/override.md +44 -0
- package/.agent-src/commands/{roadmap-create.md → roadmap/create.md} +4 -3
- package/.agent-src/commands/{roadmap-execute.md → roadmap/execute.md} +4 -3
- package/.agent-src/commands/roadmap.md +44 -0
- package/.agent-src/commands/{tests-create.md → tests/create.md} +4 -3
- package/.agent-src/commands/{tests-execute.md → tests/execute.md} +4 -3
- package/.agent-src/commands/tests.md +44 -0
- package/.agent-src/contexts/communication/rules-auto/artifact-engagement-recording-mechanics.md +72 -0
- package/.agent-src/contexts/communication/rules-auto/augment-portability-mechanics.md +79 -0
- package/.agent-src/contexts/communication/rules-auto/augment-source-of-truth-mechanics.md +98 -0
- package/.agent-src/contexts/communication/rules-auto/cli-output-handling-mechanics.md +87 -0
- package/.agent-src/contexts/communication/rules-auto/command-suggestion-policy-mechanics.md +62 -0
- package/.agent-src/contexts/communication/rules-auto/docs-sync-mechanics.md +78 -0
- package/.agent-src/contexts/communication/rules-auto/package-ci-checks-mechanics.md +85 -0
- package/.agent-src/contexts/communication/rules-auto/review-routing-awareness-mechanics.md +65 -0
- package/.agent-src/contexts/communication/rules-auto/roadmap-progress-sync-mechanics.md +78 -0
- package/.agent-src/contexts/communication/rules-auto/skill-quality-mechanics.md +62 -0
- package/.agent-src/contexts/communication/rules-auto/slash-command-routing-policy-mechanics.md +55 -0
- package/.agent-src/contexts/communication/rules-auto/ui-audit-gate-mechanics.md +53 -0
- package/.agent-src/contexts/communication/rules-auto/user-interaction-mechanics.md +77 -0
- package/.agent-src/contexts/judges/no-consolidate-rationale.md +102 -0
- package/.agent-src/contexts/judges/persona-voice-rubric.md +140 -0
- package/.agent-src/rules/artifact-engagement-recording.md +13 -69
- package/.agent-src/rules/ask-when-uncertain.md +27 -42
- package/.agent-src/rules/augment-portability.md +15 -61
- package/.agent-src/rules/augment-source-of-truth.md +27 -93
- package/.agent-src/rules/cli-output-handling.md +10 -76
- package/.agent-src/rules/command-suggestion-policy.md +18 -59
- package/.agent-src/rules/commit-conventions.md +17 -14
- package/.agent-src/rules/context-hygiene.md +6 -0
- package/.agent-src/rules/direct-answers.md +35 -59
- package/.agent-src/rules/docker-commands.md +5 -5
- package/.agent-src/rules/docs-sync.md +15 -69
- package/.agent-src/rules/language-and-tone.md +48 -72
- package/.agent-src/rules/missing-tool-handling.md +28 -22
- package/.agent-src/rules/no-cheap-questions.md +39 -53
- package/.agent-src/rules/no-roadmap-references.md +73 -0
- package/.agent-src/rules/onboarding-gate.md +7 -0
- package/.agent-src/rules/package-ci-checks.md +21 -61
- package/.agent-src/rules/preservation-guard.md +64 -29
- package/.agent-src/rules/review-routing-awareness.md +24 -43
- package/.agent-src/rules/roadmap-progress-sync.md +31 -65
- package/.agent-src/rules/rule-type-governance.md +28 -0
- package/.agent-src/rules/security-sensitive-stop.md +8 -8
- package/.agent-src/rules/skill-quality.md +16 -48
- package/.agent-src/rules/slash-command-routing-policy.md +7 -4
- package/.agent-src/rules/think-before-action.md +52 -42
- package/.agent-src/rules/tool-safety.md +19 -16
- package/.agent-src/rules/ui-audit-gate.md +24 -38
- package/.agent-src/rules/user-interaction.md +13 -68
- package/.agent-src/skills/ai-council/SKILL.md +2 -0
- package/.agent-src/skills/api-testing/SKILL.md +1 -1
- package/.agent-src/skills/check-refs/SKILL.md +59 -40
- package/.agent-src/skills/conventional-commits-writing/SKILL.md +86 -28
- package/.agent-src/skills/copilot-agents-optimization/SKILL.md +5 -5
- package/.agent-src/skills/developer-like-execution/SKILL.md +4 -4
- package/.agent-src/skills/finishing-a-development-branch/SKILL.md +101 -65
- package/.agent-src/skills/flux/SKILL.md +30 -10
- package/.agent-src/skills/github-ci/SKILL.md +2 -2
- package/.agent-src/skills/judge-code-quality/SKILL.md +7 -8
- package/.agent-src/skills/judge-security-auditor/SKILL.md +4 -5
- package/.agent-src/skills/judge-test-coverage/SKILL.md +3 -4
- package/.agent-src/skills/lint-skills/SKILL.md +57 -39
- package/.agent-src/skills/md-language-check/SKILL.md +61 -39
- package/.agent-src/skills/override-management/SKILL.md +5 -5
- package/.agent-src/skills/quality-tools/SKILL.md +2 -2
- package/.agent-src/skills/react-shadcn-ui/SKILL.md +116 -43
- package/.agent-src/skills/readme-reviewer/SKILL.md +30 -29
- package/.agent-src/skills/readme-writing/SKILL.md +78 -53
- package/.agent-src/skills/readme-writing-package/SKILL.md +50 -47
- package/.agent-src/skills/receiving-code-review/SKILL.md +52 -47
- package/.agent-src/skills/refine-prompt/SKILL.md +0 -1
- package/.agent-src/skills/requesting-code-review/SKILL.md +35 -30
- package/.agent-src/skills/security/SKILL.md +7 -2
- package/.agent-src/skills/security-audit/SKILL.md +7 -3
- package/.agent-src/skills/systematic-debugging/SKILL.md +68 -60
- package/.agent-src/skills/test-driven-development/SKILL.md +59 -57
- package/.agent-src/skills/test-performance/SKILL.md +0 -1
- package/.agent-src/skills/traefik/SKILL.md +4 -4
- package/.agent-src/skills/verify-completion-evidence/SKILL.md +28 -26
- package/.agent-src/templates/roadmaps.md +4 -0
- package/.claude-plugin/marketplace.json +22 -11
- package/AGENTS.md +2 -2
- package/CHANGELOG.md +125 -1
- package/README.md +18 -17
- package/docs/architecture.md +4 -6
- package/docs/catalog.md +67 -39
- package/docs/contracts/STABILITY.md +13 -7
- package/docs/contracts/adr-chat-history-split.md +1 -3
- package/docs/contracts/adr-command-suggestion.md +0 -2
- package/docs/contracts/adr-implement-ticket-runtime.md +1 -2
- package/docs/contracts/adr-product-ui-track.md +3 -6
- package/docs/contracts/adr-prompt-driven-execution.md +3 -4
- package/docs/contracts/agent-memory-contract.md +6 -11
- package/docs/contracts/artifact-engagement-flow.md +6 -9
- package/docs/contracts/command-clusters.md +56 -46
- package/docs/contracts/command-suggestion-flow.md +1 -3
- package/docs/contracts/context-paths.md +99 -0
- package/docs/contracts/file-ownership-matrix.json +6722 -0
- package/docs/contracts/file-ownership-matrix.md +134 -0
- package/docs/contracts/implement-ticket-flow.md +6 -9
- package/docs/contracts/linear-ai-rules-inclusion.md +0 -1
- package/docs/contracts/linear-ai-three-layers.md +0 -2
- package/docs/contracts/load-context-budget-model.md +258 -0
- package/docs/contracts/load-context-schema.md +21 -3
- package/docs/contracts/roadmap-complexity-standard.md +137 -0
- package/docs/contracts/rule-interactions.md +0 -1
- package/docs/contracts/rule-priority-hierarchy.md +1 -1
- package/docs/contracts/ui-track-flow.md +7 -17
- package/docs/customization.md +2 -0
- package/docs/getting-started.md +5 -4
- package/docs/guidelines/agent-infra/ask-when-uncertain-demos.md +134 -0
- package/docs/guidelines/agent-infra/asking-and-brevity-examples.md +100 -0
- package/docs/guidelines/agent-infra/direct-answers-demos.md +145 -0
- package/docs/guidelines/agent-infra/verify-before-complete-demos.md +128 -0
- package/package.json +1 -1
- package/scripts/_phase2_shim_helper.py +109 -0
- package/scripts/agent-config +30 -0
- package/scripts/ai_council/one_off_archive/2026-05/README.md +45 -0
- package/scripts/ai_council/one_off_archive/2026-05/_one_off_2a4_acceptance.py +208 -0
- package/scripts/ai_council/one_off_archive/2026-05/_one_off_budget_v2_audit.py +206 -0
- package/scripts/ai_council/one_off_archive/2026-05/_one_off_context_layer_v1_estimate.py +67 -0
- package/scripts/ai_council/one_off_archive/2026-05/_one_off_context_layer_v1_review.py +292 -0
- package/scripts/ai_council/one_off_archive/2026-05/_one_off_followups_review.py +259 -0
- package/scripts/ai_council/one_off_archive/2026-05/_one_off_nondestructive_inline_audit.py +209 -0
- package/scripts/ai_council/one_off_archive/2026-05/_one_off_phase4_dispatch_latency.py +108 -0
- package/scripts/ai_council/one_off_archive/2026-05/_one_off_phase6_trigger_jaccard.py +92 -0
- package/scripts/ai_council/one_off_archive/2026-05/_one_off_phase_2a_budget_rebalance.py +257 -0
- package/scripts/ai_council/one_off_archive/2026-05/_one_off_phase_2a_post_revert.py +197 -0
- package/scripts/ai_council/one_off_archive/2026-05/_one_off_rule_hardening_v1.py +251 -0
- package/scripts/ai_council/one_off_archive/2026-05/_one_off_structural_open_questions.py +232 -0
- package/scripts/ai_council/one_off_archive/2026-05/_one_off_structural_optimization.py +144 -0
- package/scripts/ai_council/one_off_archive/2026-05/_one_off_structural_v3_gaps.py +252 -0
- package/scripts/ai_council/one_off_archive/2026-05/_one_off_structural_v3_review.py +240 -0
- package/scripts/build_rule_trigger_matrix.py +360 -0
- package/scripts/check_always_budget.py +402 -45
- package/scripts/check_cluster_patterns.py +159 -0
- package/scripts/check_command_count_messaging.py +14 -7
- package/scripts/check_context_paths.py +201 -0
- package/scripts/check_no_roadmap_refs.py +155 -0
- package/scripts/check_one_off_location.py +81 -0
- package/scripts/check_phase_coupling.py +148 -0
- package/scripts/check_portability.py +2 -0
- package/scripts/check_references.py +35 -2
- package/scripts/check_safety_floor_untouched.py +125 -0
- package/scripts/command_suggester/loader.py +4 -1
- package/scripts/compress.py +64 -15
- package/scripts/context_hygiene_hook.py +173 -0
- package/scripts/generate_index.py +6 -2
- package/scripts/generate_ownership_matrix.py +323 -0
- package/scripts/hooks/augment-context-hygiene.sh +55 -0
- package/scripts/hooks/augment-onboarding-gate.sh +55 -0
- package/scripts/hooks/augment-roadmap-progress.sh +57 -0
- package/scripts/install.py +105 -45
- package/scripts/lint_examples.py +98 -0
- package/scripts/lint_no_new_atomic_commands.py +12 -11
- package/scripts/lint_roadmap_complexity.py +127 -0
- package/scripts/onboarding_gate_hook.py +137 -0
- package/scripts/requirements-evals.txt +1 -0
- package/scripts/roadmap_progress_hook.py +159 -0
- package/scripts/schemas/command.schema.json +4 -3
- package/scripts/schemas/rule.schema.json +5 -0
- package/scripts/skill_linter.py +1 -0
- package/scripts/sync_agent_settings.py +25 -2
- package/scripts/update_counts.py +7 -0
- /package/scripts/ai_council/{_one_off_rebalancing_audit.py → one_off_archive/2026-05/_one_off_rebalancing_audit.py} +0 -0
- /package/scripts/ai_council/{_one_off_roundtrip.py → one_off_archive/2026-05/_one_off_roundtrip.py} +0 -0
|
@@ -53,7 +53,9 @@ def canonical_counts() -> tuple[int, int, int]:
|
|
|
53
53
|
print(f"❌ {COMMANDS_DIR.relative_to(ROOT)} not found", file=sys.stderr)
|
|
54
54
|
sys.exit(1)
|
|
55
55
|
total = shims = 0
|
|
56
|
-
for f in COMMANDS_DIR.
|
|
56
|
+
for f in COMMANDS_DIR.rglob("*.md"):
|
|
57
|
+
if f.name == "AGENTS.md":
|
|
58
|
+
continue
|
|
57
59
|
total += 1
|
|
58
60
|
m = FM_RE.match(f.read_text(encoding="utf-8"))
|
|
59
61
|
fm = m.group(1) if m else ""
|
|
@@ -82,16 +84,21 @@ def main() -> int:
|
|
|
82
84
|
# README.md
|
|
83
85
|
(README, r"<strong>(\d+) Commands</strong>", active, "hero row"),
|
|
84
86
|
(README, r"Browse all (\d+) active commands", active, "browse line"),
|
|
85
|
-
(README, r"\((\d+) files total ", total, "browse meta · total files"),
|
|
86
|
-
(README, r"— (\d+) are deprecation shims", shims, "browse meta · shims"),
|
|
87
87
|
(README, r"\+ (\d+) native commands\)", active, "tools blurb"),
|
|
88
|
-
# AGENTS.md (`commands/ (84 files — 69 active + 15 deprecation shims)`)
|
|
89
|
-
(AGENTS, r"commands/\s+\((\d+) files —", total, "tree · total files"),
|
|
90
|
-
(AGENTS, r"files — (\d+) active", active, "tree · active"),
|
|
91
|
-
(AGENTS, r"active \+ (\d+) deprecation shims", shims, "tree · shims"),
|
|
92
88
|
# docs/getting-started.md
|
|
93
89
|
(GETTING_STARTED, r"Browse all (\d+) active commands", active, "browse line"),
|
|
94
90
|
]
|
|
91
|
+
# Shim-specific messaging only applies during a deprecation window.
|
|
92
|
+
# When shims == 0 the clauses are dropped from public docs entirely;
|
|
93
|
+
# re-add these patterns when a new deprecation cycle starts.
|
|
94
|
+
if shims > 0:
|
|
95
|
+
checks.extend([
|
|
96
|
+
(README, r"\((\d+) files total ", total, "browse meta · total files"),
|
|
97
|
+
(README, r"— (\d+) are deprecation shims", shims, "browse meta · shims"),
|
|
98
|
+
(AGENTS, r"commands/\s+\((\d+) files —", total, "tree · total files"),
|
|
99
|
+
(AGENTS, r"files — (\d+) active", active, "tree · active"),
|
|
100
|
+
(AGENTS, r"active \+ (\d+) deprecation shims", shims, "tree · shims"),
|
|
101
|
+
])
|
|
95
102
|
|
|
96
103
|
errors: list[str] = []
|
|
97
104
|
for path, pattern, expected, label in checks:
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Context-file path & orphan checker.
|
|
3
|
+
|
|
4
|
+
Validates that every `*.md` under `.agent-src.uncompressed/contexts/`:
|
|
5
|
+
|
|
6
|
+
1. Lives in a locked sub-tree (or is one of six grandfathered root files).
|
|
7
|
+
2. Does not collide on basename with another context file in another sub-tree.
|
|
8
|
+
3. Is referenced by at least one rule, skill, command, or other context
|
|
9
|
+
(via `load_context:` frontmatter or a markdown body path mention).
|
|
10
|
+
|
|
11
|
+
Contract: docs/contracts/context-paths.md
|
|
12
|
+
Roadmap: road-to-structural-optimization.md § 0.6
|
|
13
|
+
|
|
14
|
+
Exit codes: 0 = clean, 1 = violations, 3 = internal error.
|
|
15
|
+
"""
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
import argparse
|
|
19
|
+
import json
|
|
20
|
+
import sys
|
|
21
|
+
from dataclasses import asdict, dataclass
|
|
22
|
+
from pathlib import Path
|
|
23
|
+
|
|
24
|
+
ROOT = Path(__file__).resolve().parent.parent
|
|
25
|
+
CONTEXTS_ROOT = ROOT / ".agent-src.uncompressed" / "contexts"
|
|
26
|
+
|
|
27
|
+
# Sub-trees that may contain context files. Update in lock-step with
|
|
28
|
+
# docs/contracts/context-paths.md whenever a roadmap revision adds one.
|
|
29
|
+
LOCKED_SUBTREES = (
|
|
30
|
+
"communication/rules-always",
|
|
31
|
+
"communication/rules-auto",
|
|
32
|
+
"judges",
|
|
33
|
+
"analysis",
|
|
34
|
+
"skills",
|
|
35
|
+
"chat-history",
|
|
36
|
+
"execution",
|
|
37
|
+
"authority",
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
# Files allowed to remain at the contexts root. Anything else at the root
|
|
41
|
+
# fails the path check. New context files MUST live in a sub-tree.
|
|
42
|
+
GRANDFATHERED_ROOT_FILES = frozenset({
|
|
43
|
+
"augment-infrastructure.md",
|
|
44
|
+
"documentation-hierarchy.md",
|
|
45
|
+
"model-recommendations.md",
|
|
46
|
+
"override-system.md",
|
|
47
|
+
"skills-and-commands.md",
|
|
48
|
+
"subagent-configuration.md",
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
# Directories whose content we scan for references to a context file.
|
|
52
|
+
# `agents/roadmaps` is included because in-flight roadmap docs are
|
|
53
|
+
# legitimate referrers during multi-phase rollouts — a context can land
|
|
54
|
+
# in phase N while its first rule/skill referrer lands in phase N+k.
|
|
55
|
+
# Without this scan dir, every newly-introduced context would orphan
|
|
56
|
+
# until the consuming artefact lands, blocking phase-by-phase commits.
|
|
57
|
+
REFERENCE_SCAN_DIRS = (
|
|
58
|
+
".agent-src.uncompressed/rules",
|
|
59
|
+
".agent-src.uncompressed/skills",
|
|
60
|
+
".agent-src.uncompressed/commands",
|
|
61
|
+
".agent-src.uncompressed/contexts",
|
|
62
|
+
"agents/roadmaps",
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
@dataclass
|
|
67
|
+
class Violation:
|
|
68
|
+
file: str
|
|
69
|
+
kind: str # "out-of-tree" | "root-not-grandfathered" | "collision" | "orphan"
|
|
70
|
+
detail: str
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def _collect_contexts(root: Path) -> list[Path]:
|
|
74
|
+
if not (root / CONTEXTS_ROOT.relative_to(ROOT)).exists():
|
|
75
|
+
return []
|
|
76
|
+
return sorted((root / CONTEXTS_ROOT.relative_to(ROOT)).rglob("*.md"))
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def _check_path(ctx: Path, contexts_root: Path) -> Violation | None:
|
|
80
|
+
rel = ctx.relative_to(contexts_root)
|
|
81
|
+
parts = rel.parts
|
|
82
|
+
if len(parts) == 1:
|
|
83
|
+
if parts[0] not in GRANDFATHERED_ROOT_FILES:
|
|
84
|
+
return Violation(
|
|
85
|
+
file=str(ctx),
|
|
86
|
+
kind="root-not-grandfathered",
|
|
87
|
+
detail=(f"new file at contexts/ root — must live in one of "
|
|
88
|
+
f"{sorted(LOCKED_SUBTREES)} or be added to "
|
|
89
|
+
"GRANDFATHERED_ROOT_FILES via a roadmap revision"),
|
|
90
|
+
)
|
|
91
|
+
return None
|
|
92
|
+
subtree = "/".join(parts[:-1])
|
|
93
|
+
# Allow nested matches: e.g. communication/rules-always/foo/bar.md still
|
|
94
|
+
# lives under "communication/rules-always". Direct prefix match suffices.
|
|
95
|
+
for allowed in LOCKED_SUBTREES:
|
|
96
|
+
if subtree == allowed or subtree.startswith(allowed + "/"):
|
|
97
|
+
return None
|
|
98
|
+
return Violation(
|
|
99
|
+
file=str(ctx),
|
|
100
|
+
kind="out-of-tree",
|
|
101
|
+
detail=(f"sub-tree '{subtree}' is not in LOCKED_SUBTREES — see "
|
|
102
|
+
"docs/contracts/context-paths.md to add a new sub-tree"),
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def _check_collisions(contexts: list[Path], contexts_root: Path) -> list[Violation]:
|
|
107
|
+
by_name: dict[str, list[Path]] = {}
|
|
108
|
+
for ctx in contexts:
|
|
109
|
+
by_name.setdefault(ctx.name, []).append(ctx)
|
|
110
|
+
out: list[Violation] = []
|
|
111
|
+
for name, paths in by_name.items():
|
|
112
|
+
if len(paths) <= 1:
|
|
113
|
+
continue
|
|
114
|
+
rels = sorted(str(p.relative_to(contexts_root)) for p in paths)
|
|
115
|
+
for p in paths:
|
|
116
|
+
out.append(Violation(
|
|
117
|
+
file=str(p),
|
|
118
|
+
kind="collision",
|
|
119
|
+
detail=f"basename '{name}' shared with: {', '.join(r for r in rels if r != str(p.relative_to(contexts_root)))}",
|
|
120
|
+
))
|
|
121
|
+
return out
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def _build_reference_corpus(root: Path) -> str:
|
|
125
|
+
chunks: list[str] = []
|
|
126
|
+
for d in REFERENCE_SCAN_DIRS:
|
|
127
|
+
base = root / d
|
|
128
|
+
if not base.exists():
|
|
129
|
+
continue
|
|
130
|
+
for f in base.rglob("*.md"):
|
|
131
|
+
try:
|
|
132
|
+
chunks.append(f.read_text(encoding="utf-8"))
|
|
133
|
+
except OSError:
|
|
134
|
+
continue
|
|
135
|
+
return "\n".join(chunks)
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def _check_orphans(contexts: list[Path], corpus: str, root: Path) -> list[Violation]:
|
|
139
|
+
out: list[Violation] = []
|
|
140
|
+
for ctx in contexts:
|
|
141
|
+
rel_src = str(ctx.relative_to(root)) # .agent-src.uncompressed/contexts/...
|
|
142
|
+
rel_short = rel_src.split("contexts/", 1)[-1] # judges/persona-voice-rubric.md
|
|
143
|
+
candidates = (rel_src, f"contexts/{rel_short}", rel_short)
|
|
144
|
+
# Exclude self-references: drop this file's own content from the
|
|
145
|
+
# corpus check by reading the file and subtracting its substring.
|
|
146
|
+
try:
|
|
147
|
+
own_text = ctx.read_text(encoding="utf-8")
|
|
148
|
+
except OSError:
|
|
149
|
+
own_text = ""
|
|
150
|
+
external_corpus = corpus.replace(own_text, "") if own_text else corpus
|
|
151
|
+
if not any(c in external_corpus for c in candidates):
|
|
152
|
+
out.append(Violation(
|
|
153
|
+
file=str(ctx),
|
|
154
|
+
kind="orphan",
|
|
155
|
+
detail="not referenced by any rule, skill, command, or other context",
|
|
156
|
+
))
|
|
157
|
+
return out
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def scan(root: Path) -> list[Violation]:
|
|
161
|
+
contexts_root = root / CONTEXTS_ROOT.relative_to(ROOT)
|
|
162
|
+
contexts = _collect_contexts(root)
|
|
163
|
+
violations: list[Violation] = []
|
|
164
|
+
for ctx in contexts:
|
|
165
|
+
v = _check_path(ctx, contexts_root)
|
|
166
|
+
if v:
|
|
167
|
+
violations.append(v)
|
|
168
|
+
violations.extend(_check_collisions(contexts, contexts_root))
|
|
169
|
+
corpus = _build_reference_corpus(root)
|
|
170
|
+
violations.extend(_check_orphans(contexts, corpus, root))
|
|
171
|
+
return violations
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def format_text(violations: list[Violation]) -> str:
|
|
175
|
+
if not violations:
|
|
176
|
+
return "✅ No context-path violations."
|
|
177
|
+
lines = [f"❌ Found {len(violations)} context-path violation(s):\n"]
|
|
178
|
+
for v in violations:
|
|
179
|
+
lines.append(f" 🔴 [{v.kind}] {v.file}\n {v.detail}")
|
|
180
|
+
return "\n".join(lines)
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def main() -> int:
|
|
184
|
+
parser = argparse.ArgumentParser(description=__doc__.splitlines()[0])
|
|
185
|
+
parser.add_argument("--format", choices=["text", "json"], default="text")
|
|
186
|
+
parser.add_argument("--root", type=Path, default=ROOT)
|
|
187
|
+
args = parser.parse_args()
|
|
188
|
+
try:
|
|
189
|
+
violations = scan(args.root)
|
|
190
|
+
except Exception as e: # pragma: no cover
|
|
191
|
+
print(f"Internal error: {e}", file=sys.stderr)
|
|
192
|
+
return 3
|
|
193
|
+
if args.format == "json":
|
|
194
|
+
print(json.dumps([asdict(v) for v in violations], indent=2))
|
|
195
|
+
else:
|
|
196
|
+
print(format_text(violations))
|
|
197
|
+
return 1 if violations else 0
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
if __name__ == "__main__":
|
|
201
|
+
sys.exit(main())
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""No-roadmap-references checker.
|
|
3
|
+
|
|
4
|
+
Stable artifacts (rules, skills, commands, contexts, guidelines, AGENTS.md,
|
|
5
|
+
README, copilot-instructions) must NOT cite a specific roadmap file in
|
|
6
|
+
`agents/roadmaps/`. Roadmap files are transient — archived, skipped, or
|
|
7
|
+
deleted as work completes — and stable artifacts citing them rot.
|
|
8
|
+
|
|
9
|
+
Allowed: directory mentions (`agents/roadmaps/`, `agents/roadmaps/archive/`,
|
|
10
|
+
`agents/roadmaps/skipped/`). Forbidden: specific `*.md` files inside those
|
|
11
|
+
directories.
|
|
12
|
+
|
|
13
|
+
Contract: .agent-src.uncompressed/rules/no-roadmap-references.md
|
|
14
|
+
|
|
15
|
+
Exit codes: 0 = clean, 1 = violations, 3 = internal error.
|
|
16
|
+
"""
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
import argparse
|
|
20
|
+
import json
|
|
21
|
+
import re
|
|
22
|
+
import sys
|
|
23
|
+
from dataclasses import asdict, dataclass
|
|
24
|
+
from pathlib import Path
|
|
25
|
+
|
|
26
|
+
ROOT = Path(__file__).resolve().parent.parent
|
|
27
|
+
|
|
28
|
+
# Stable artefact trees — every `*.md` below MUST be free of roadmap-file
|
|
29
|
+
# citations. Directory mentions stay allowed (the regex below excludes them).
|
|
30
|
+
STABLE_TREES = (
|
|
31
|
+
".agent-src.uncompressed/rules",
|
|
32
|
+
".agent-src.uncompressed/skills",
|
|
33
|
+
".agent-src.uncompressed/commands",
|
|
34
|
+
".agent-src.uncompressed/contexts",
|
|
35
|
+
".agent-src.uncompressed/templates",
|
|
36
|
+
".agent-src.uncompressed/personas",
|
|
37
|
+
"agents/contexts",
|
|
38
|
+
"docs/guidelines",
|
|
39
|
+
"docs/contracts",
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
# Stable single-file artefacts at well-known paths.
|
|
43
|
+
STABLE_FILES = (
|
|
44
|
+
"AGENTS.md",
|
|
45
|
+
"README.md",
|
|
46
|
+
"copilot-instructions.md",
|
|
47
|
+
"docs/architecture.md",
|
|
48
|
+
"docs/customization.md",
|
|
49
|
+
"docs/getting-started.md",
|
|
50
|
+
"docs/catalog.md",
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
# Roadmap-file pattern: any `*.md` file under `agents/roadmaps/` at any
|
|
54
|
+
# depth (including `archive/`, `skipped/`, and nested topical subfolders
|
|
55
|
+
# like `agent-memory/`). Directory-only mentions (`agents/roadmaps/`
|
|
56
|
+
# with trailing slash, no filename) and placeholder mentions like
|
|
57
|
+
# `agents/roadmaps/<file>.md` (angle-bracket placeholder) do NOT match.
|
|
58
|
+
ROADMAP_FILE_RE = re.compile(
|
|
59
|
+
r"agents/roadmaps/(?:[a-z0-9][a-z0-9_-]*/)*[a-z0-9][a-z0-9_-]*\.md",
|
|
60
|
+
re.IGNORECASE,
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
# Files that may legitimately quote forbidden patterns inside backticks for
|
|
64
|
+
# documentation purposes — the rule itself, the companion CI script docs,
|
|
65
|
+
# and the contract doc that names the rule.
|
|
66
|
+
SELF_DOCUMENTING_ALLOWLIST = frozenset({
|
|
67
|
+
".agent-src.uncompressed/rules/no-roadmap-references.md",
|
|
68
|
+
"docs/guidelines/agent-infra/no-roadmap-references.md",
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
@dataclass
|
|
73
|
+
class Violation:
|
|
74
|
+
file: str
|
|
75
|
+
line: int
|
|
76
|
+
match: str
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def _scan_file(path: Path, root: Path) -> list[Violation]:
|
|
80
|
+
rel = str(path.relative_to(root))
|
|
81
|
+
if rel in SELF_DOCUMENTING_ALLOWLIST:
|
|
82
|
+
return []
|
|
83
|
+
try:
|
|
84
|
+
text = path.read_text(encoding="utf-8")
|
|
85
|
+
except OSError:
|
|
86
|
+
return []
|
|
87
|
+
out: list[Violation] = []
|
|
88
|
+
in_fence = False
|
|
89
|
+
for n, line in enumerate(text.splitlines(), start=1):
|
|
90
|
+
# Skip fenced code blocks — path listings inside ``` are functional
|
|
91
|
+
# constants (command contracts, runtime checks), not link rot.
|
|
92
|
+
stripped = line.lstrip()
|
|
93
|
+
if stripped.startswith("```"):
|
|
94
|
+
in_fence = not in_fence
|
|
95
|
+
continue
|
|
96
|
+
if in_fence:
|
|
97
|
+
continue
|
|
98
|
+
for m in ROADMAP_FILE_RE.finditer(line):
|
|
99
|
+
out.append(Violation(file=rel, line=n, match=m.group(0)))
|
|
100
|
+
return out
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def _collect_targets(root: Path) -> list[Path]:
|
|
104
|
+
targets: list[Path] = []
|
|
105
|
+
for d in STABLE_TREES:
|
|
106
|
+
base = root / d
|
|
107
|
+
if not base.exists():
|
|
108
|
+
continue
|
|
109
|
+
targets.extend(sorted(base.rglob("*.md")))
|
|
110
|
+
for f in STABLE_FILES:
|
|
111
|
+
p = root / f
|
|
112
|
+
if p.exists():
|
|
113
|
+
targets.append(p)
|
|
114
|
+
return targets
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def scan(root: Path) -> list[Violation]:
|
|
118
|
+
out: list[Violation] = []
|
|
119
|
+
for path in _collect_targets(root):
|
|
120
|
+
out.extend(_scan_file(path, root))
|
|
121
|
+
return out
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def format_text(violations: list[Violation]) -> str:
|
|
125
|
+
if not violations:
|
|
126
|
+
return "✅ No roadmap-file references in stable artifacts."
|
|
127
|
+
lines = [f"❌ Found {len(violations)} roadmap reference(s) in stable artifacts:\n"]
|
|
128
|
+
for v in violations:
|
|
129
|
+
lines.append(f" 🔴 {v.file}:{v.line} → {v.match}")
|
|
130
|
+
lines.append(
|
|
131
|
+
"\nPromote the durable conclusion to agents/contexts/ and cite that "
|
|
132
|
+
"instead. See .agent-src.uncompressed/rules/no-roadmap-references.md."
|
|
133
|
+
)
|
|
134
|
+
return "\n".join(lines)
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def main() -> int:
|
|
138
|
+
parser = argparse.ArgumentParser(description=__doc__.splitlines()[0])
|
|
139
|
+
parser.add_argument("--format", choices=["text", "json"], default="text")
|
|
140
|
+
parser.add_argument("--root", type=Path, default=ROOT)
|
|
141
|
+
args = parser.parse_args()
|
|
142
|
+
try:
|
|
143
|
+
violations = scan(args.root)
|
|
144
|
+
except Exception as e: # pragma: no cover
|
|
145
|
+
print(f"Internal error: {e}", file=sys.stderr)
|
|
146
|
+
return 3
|
|
147
|
+
if args.format == "json":
|
|
148
|
+
print(json.dumps([asdict(v) for v in violations], indent=2))
|
|
149
|
+
else:
|
|
150
|
+
print(format_text(violations))
|
|
151
|
+
return 1 if violations else 0
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
if __name__ == "__main__":
|
|
155
|
+
sys.exit(main())
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""One-off script-location guard (Phase 0a.2 of road-to-rule-hardening).
|
|
3
|
+
|
|
4
|
+
Every ``_one_off_*.py`` script under ``scripts/`` must live inside the
|
|
5
|
+
archive folder ``scripts/ai_council/one_off_archive/<YYYY-MM>/``. The
|
|
6
|
+
guard fails CI if a new probe lands anywhere else in the tree.
|
|
7
|
+
|
|
8
|
+
Rationale: one-off council probes / phase-specific measurements are
|
|
9
|
+
inherently single-purpose; their durable artefact is the council
|
|
10
|
+
session under ``agents/council-sessions/``. Keeping them in the
|
|
11
|
+
archive prevents the ``scripts/`` root from accumulating noise and
|
|
12
|
+
makes their lifecycle visible (folder == month archived).
|
|
13
|
+
|
|
14
|
+
Exit codes:
|
|
15
|
+
0 = clean
|
|
16
|
+
1 = violation (script outside the archive)
|
|
17
|
+
3 = internal error
|
|
18
|
+
"""
|
|
19
|
+
from __future__ import annotations
|
|
20
|
+
|
|
21
|
+
import argparse
|
|
22
|
+
import re
|
|
23
|
+
import sys
|
|
24
|
+
from pathlib import Path
|
|
25
|
+
|
|
26
|
+
REPO_ROOT = Path(__file__).resolve().parent.parent
|
|
27
|
+
SCRIPTS = REPO_ROOT / "scripts"
|
|
28
|
+
ARCHIVE = SCRIPTS / "ai_council" / "one_off_archive"
|
|
29
|
+
ARCHIVE_MONTH_RE = re.compile(r"^\d{4}-\d{2}$")
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def find_violations() -> list[Path]:
|
|
33
|
+
"""Return one-off scripts that are outside the archive folder."""
|
|
34
|
+
violations: list[Path] = []
|
|
35
|
+
for path in SCRIPTS.rglob("_one_off_*.py"):
|
|
36
|
+
if not path.is_file():
|
|
37
|
+
continue
|
|
38
|
+
# Must live under scripts/ai_council/one_off_archive/<YYYY-MM>/
|
|
39
|
+
try:
|
|
40
|
+
rel = path.relative_to(ARCHIVE)
|
|
41
|
+
except ValueError:
|
|
42
|
+
violations.append(path)
|
|
43
|
+
continue
|
|
44
|
+
# rel = "<YYYY-MM>/<name>.py"
|
|
45
|
+
parts = rel.parts
|
|
46
|
+
if len(parts) != 2 or not ARCHIVE_MONTH_RE.match(parts[0]):
|
|
47
|
+
violations.append(path)
|
|
48
|
+
return violations
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def main() -> int:
|
|
52
|
+
parser = argparse.ArgumentParser(description=__doc__.strip().splitlines()[0])
|
|
53
|
+
parser.add_argument("--quiet", action="store_true", help="Only print on failure")
|
|
54
|
+
args = parser.parse_args()
|
|
55
|
+
|
|
56
|
+
try:
|
|
57
|
+
violations = find_violations()
|
|
58
|
+
except Exception as exc: # pragma: no cover — defensive
|
|
59
|
+
print(f"❌ internal error: {exc}", file=sys.stderr)
|
|
60
|
+
return 3
|
|
61
|
+
|
|
62
|
+
if violations:
|
|
63
|
+
print("❌ one-off scripts outside the archive:", file=sys.stderr)
|
|
64
|
+
for path in violations:
|
|
65
|
+
rel = path.relative_to(REPO_ROOT)
|
|
66
|
+
print(f" {rel}", file=sys.stderr)
|
|
67
|
+
print(
|
|
68
|
+
"\n Move them under "
|
|
69
|
+
"scripts/ai_council/one_off_archive/<YYYY-MM>/ "
|
|
70
|
+
"(see that folder's README.md).",
|
|
71
|
+
file=sys.stderr,
|
|
72
|
+
)
|
|
73
|
+
return 1
|
|
74
|
+
|
|
75
|
+
if not args.quiet:
|
|
76
|
+
print("✅ all _one_off_*.py scripts are archived")
|
|
77
|
+
return 0
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
if __name__ == "__main__": # pragma: no cover
|
|
81
|
+
sys.exit(main())
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Phase 6 → Phase 2B coupling guard (Phase 0.3.3).
|
|
3
|
+
|
|
4
|
+
Re-runs the audit recorded in `agents/roadmaps/phase6-2b-coupling.md`
|
|
5
|
+
on every CI run. Fails the build if any of the 13 Phase-2B target
|
|
6
|
+
rules introduces a reference to one of the three Phase-6-owned rules
|
|
7
|
+
(`chat-history-cadence`, `chat-history-ownership`,
|
|
8
|
+
`chat-history-visibility`) — by rule name, `load_context:` entry, or
|
|
9
|
+
body link / cite.
|
|
10
|
+
|
|
11
|
+
Excluded from the coupling probe (separate infrastructure, not
|
|
12
|
+
reshaped by Phase 6):
|
|
13
|
+
|
|
14
|
+
- The CLI dispatcher subcommand `./agent-config chat-history:hook`
|
|
15
|
+
and any other `chat-history:*` colon-suffix command surface.
|
|
16
|
+
|
|
17
|
+
Exit codes: 0 = decoupling intact, 1 = coupling detected,
|
|
18
|
+
3 = internal error (target rule missing, unreadable file).
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
from __future__ import annotations
|
|
22
|
+
|
|
23
|
+
import argparse
|
|
24
|
+
import re
|
|
25
|
+
import sys
|
|
26
|
+
from pathlib import Path
|
|
27
|
+
|
|
28
|
+
REPO_ROOT = Path(__file__).resolve().parents[1]
|
|
29
|
+
SRC_RULES = REPO_ROOT / ".agent-src.uncompressed" / "rules"
|
|
30
|
+
COMP_RULES = REPO_ROOT / ".agent-src" / "rules"
|
|
31
|
+
|
|
32
|
+
# Phase 2B priority list — see road-to-structural-optimization.md § Phase 2 → 2B.
|
|
33
|
+
TARGET_RULES: tuple[str, ...] = (
|
|
34
|
+
"roadmap-progress-sync",
|
|
35
|
+
"user-interaction",
|
|
36
|
+
"augment-source-of-truth",
|
|
37
|
+
"command-suggestion-policy",
|
|
38
|
+
"artifact-engagement-recording",
|
|
39
|
+
"review-routing-awareness",
|
|
40
|
+
"autonomous-execution",
|
|
41
|
+
"docs-sync",
|
|
42
|
+
"cli-output-handling",
|
|
43
|
+
"augment-portability",
|
|
44
|
+
"ui-audit-gate",
|
|
45
|
+
"skill-quality",
|
|
46
|
+
"package-ci-checks",
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
# Phase 6 owns these three rule names. Match must be a *rule reference*,
|
|
50
|
+
# not a *dispatcher reference* (chat-history:hook etc).
|
|
51
|
+
PHASE6_RULES: tuple[str, ...] = (
|
|
52
|
+
"chat-history-cadence",
|
|
53
|
+
"chat-history-ownership",
|
|
54
|
+
"chat-history-visibility",
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
# Rule-reference pattern: rule name not immediately followed by `:` (which
|
|
58
|
+
# would mark it as a CLI subcommand like `chat-history:hook`). Allows
|
|
59
|
+
# trailing word-boundary characters typical of Markdown / YAML contexts.
|
|
60
|
+
_RULE_REF_RE = re.compile(
|
|
61
|
+
r"\bchat-history-(?:cadence|ownership|visibility)\b(?!:)"
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def _scan(file: Path) -> list[tuple[int, str]]:
|
|
66
|
+
"""Return [(line_no, line)] of rule-reference matches in `file`."""
|
|
67
|
+
if not file.is_file():
|
|
68
|
+
return []
|
|
69
|
+
hits: list[tuple[int, str]] = []
|
|
70
|
+
for i, line in enumerate(file.read_text(encoding="utf-8").splitlines(), 1):
|
|
71
|
+
if _RULE_REF_RE.search(line):
|
|
72
|
+
hits.append((i, line.strip()))
|
|
73
|
+
return hits
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def _check_surface(label: str, base: Path) -> tuple[int, list[str]]:
|
|
77
|
+
"""Scan `base` for all 13 Phase-2B targets; return (#hits, formatted lines)."""
|
|
78
|
+
if not base.is_dir():
|
|
79
|
+
return 0, [f"❌ {label} dir missing: {base}"]
|
|
80
|
+
out: list[str] = []
|
|
81
|
+
total = 0
|
|
82
|
+
for rule in TARGET_RULES:
|
|
83
|
+
path = base / f"{rule}.md"
|
|
84
|
+
if not path.is_file():
|
|
85
|
+
return 0, [f"❌ target rule missing: {path}"]
|
|
86
|
+
hits = _scan(path)
|
|
87
|
+
if not hits:
|
|
88
|
+
continue
|
|
89
|
+
total += len(hits)
|
|
90
|
+
for line_no, line in hits:
|
|
91
|
+
out.append(f" {label}/{rule}.md:{line_no} {line}")
|
|
92
|
+
return total, out
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def main() -> int:
|
|
96
|
+
parser = argparse.ArgumentParser(description=__doc__)
|
|
97
|
+
parser.add_argument(
|
|
98
|
+
"--quiet",
|
|
99
|
+
action="store_true",
|
|
100
|
+
help="suppress the per-rule breakdown when no coupling found",
|
|
101
|
+
)
|
|
102
|
+
args = parser.parse_args()
|
|
103
|
+
|
|
104
|
+
hits_src, lines_src = _check_surface("uncompressed", SRC_RULES)
|
|
105
|
+
if any(line.startswith("❌") for line in lines_src):
|
|
106
|
+
for line in lines_src:
|
|
107
|
+
print(line, file=sys.stderr)
|
|
108
|
+
return 3
|
|
109
|
+
hits_comp, lines_comp = _check_surface("compressed", COMP_RULES)
|
|
110
|
+
if any(line.startswith("❌") for line in lines_comp):
|
|
111
|
+
for line in lines_comp:
|
|
112
|
+
print(line, file=sys.stderr)
|
|
113
|
+
return 3
|
|
114
|
+
|
|
115
|
+
total = hits_src + hits_comp
|
|
116
|
+
|
|
117
|
+
if total == 0:
|
|
118
|
+
if not args.quiet:
|
|
119
|
+
print(
|
|
120
|
+
f"✅ Phase 6 → 2B decoupling intact: 0 rule-references "
|
|
121
|
+
f"across {len(TARGET_RULES)} Phase-2B targets "
|
|
122
|
+
f"(uncompressed + compressed surfaces)."
|
|
123
|
+
)
|
|
124
|
+
print(
|
|
125
|
+
" probe: rule names, load_context: entries, body "
|
|
126
|
+
"link/cite — dispatcher subcommand chat-history:hook "
|
|
127
|
+
"excluded by design."
|
|
128
|
+
)
|
|
129
|
+
return 0
|
|
130
|
+
|
|
131
|
+
print(
|
|
132
|
+
f"❌ Phase 6 → 2B coupling detected: {total} rule-reference(s) "
|
|
133
|
+
f"across Phase-2B targets:"
|
|
134
|
+
)
|
|
135
|
+
for line in lines_src + lines_comp:
|
|
136
|
+
print(line)
|
|
137
|
+
print(
|
|
138
|
+
"\n Action: see agents/roadmaps/phase6-2b-coupling.md. "
|
|
139
|
+
"Either drop the new reference, migrate it to the dispatcher "
|
|
140
|
+
"(chat-history:hook), or trigger the >0-hits branch in 0.3.2 "
|
|
141
|
+
"(Phase 6 ships call-signature contract before Phase 2B "
|
|
142
|
+
"touches the coupled rule)."
|
|
143
|
+
)
|
|
144
|
+
return 1
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
if __name__ == "__main__":
|
|
148
|
+
sys.exit(main())
|
|
@@ -315,6 +315,7 @@ _TASK_FENCE_RE = re.compile(r"^\s*task\s+([a-z][a-z0-9:_-]*)\b")
|
|
|
315
315
|
# by the task-invocation detector (but still scanned for layer 1 + 2).
|
|
316
316
|
_TASK_DETECTOR_SKIP = (
|
|
317
317
|
"rules/augment-portability.md",
|
|
318
|
+
"contexts/communication/rules-auto/augment-portability-mechanics.md",
|
|
318
319
|
)
|
|
319
320
|
|
|
320
321
|
|
|
@@ -422,6 +423,7 @@ _CLI_INVOCATION_MAP: list[tuple[re.Pattern, str]] = [
|
|
|
422
423
|
# own help, the portability rule that defines the mapping).
|
|
423
424
|
_CLI_DETECTOR_SKIP = (
|
|
424
425
|
"rules/augment-portability.md",
|
|
426
|
+
"contexts/communication/rules-auto/augment-portability-mechanics.md",
|
|
425
427
|
)
|
|
426
428
|
|
|
427
429
|
|