Skip to content

Commit 12eacaf

Browse files
authored
Merge pull request #115 from 1012839419a-alt/1012839419a-alt/butterflyray
chore: clear repository diagnostics and restore CI contracts
2 parents caa50b6 + a44d284 commit 12eacaf

400 files changed

Lines changed: 8943 additions & 3742 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.agents/skills/bmad-advanced-elicitation/scripts/pick_methods.py‎

Lines changed: 50 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -170,23 +170,59 @@ def fmt_rows(rows: list[dict], as_json: bool) -> str:
170170

171171
def main(argv: list[str] | None = None) -> int:
172172
if hasattr(sys.stdout, "reconfigure"):
173-
sys.stdout.reconfigure(encoding="utf-8") # catalog rows contain →; don't die on locale code pages
174-
p = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
175-
p.add_argument("--file", type=Path, default=DEFAULT_FILE, help="method CSV (default: sibling assets/methods.csv)")
176-
p.add_argument("--extra", help="additional methods: a JSON array literal or a path to a JSON file")
177-
p.add_argument("--json", action="store_true", help="emit structured JSON instead of lean text")
173+
sys.stdout.reconfigure(
174+
encoding="utf-8"
175+
) # catalog rows contain →; don't die on locale code pages
176+
p = argparse.ArgumentParser(
177+
description=__doc__,
178+
formatter_class=argparse.RawDescriptionHelpFormatter,
179+
)
180+
p.add_argument(
181+
"--file",
182+
type=Path,
183+
default=DEFAULT_FILE,
184+
help="method CSV (default: sibling assets/methods.csv)",
185+
)
186+
p.add_argument(
187+
"--json",
188+
action="store_true",
189+
help="emit structured JSON instead of lean text",
190+
)
178191
sub = p.add_subparsers(dest="cmd", required=True)
179192
sub.add_parser("categories", help="list category names + counts")
180-
pl = sub.add_parser("list", help="the index for chosen categories (needs --category or --all)")
181-
pl.add_argument("--category", action="append", help="filter to a category (repeatable)")
182-
pl.add_argument("--all", action="store_true", help="dump the entire catalog (deliberate; large)")
193+
pl = sub.add_parser(
194+
"list",
195+
help="the index for chosen categories (needs --category or --all)",
196+
)
197+
pl.add_argument(
198+
"--category",
199+
action="append",
200+
help="filter to a category (repeatable)",
201+
)
202+
pl.add_argument(
203+
"--all",
204+
action="store_true",
205+
help="dump the entire catalog (deliberate; large)",
206+
)
183207
ps = sub.add_parser("show", help="full row for each named method")
184208
ps.add_argument("names", nargs="+", help="method names or nums")
185209
pr = sub.add_parser("random", help="draw methods at random")
186210
pr.add_argument("-n", type=int, default=1, help="how many (default 1)")
187-
pr.add_argument("--category", action="append", help="restrict to a category (repeatable)")
188-
pr.add_argument("--exclude", action="append", help="method name to skip (repeatable) — e.g. already shown")
189-
pr.add_argument("--spread", action="store_true", help="force category diversity across the draw")
211+
pr.add_argument(
212+
"--category",
213+
action="append",
214+
help="restrict to a category (repeatable)",
215+
)
216+
pr.add_argument(
217+
"--exclude",
218+
action="append",
219+
help="method name to skip (repeatable) — e.g. already shown",
220+
)
221+
pr.add_argument(
222+
"--spread",
223+
action="store_true",
224+
help="force category diversity across the draw",
225+
)
190226
args = p.parse_args(argv)
191227

192228
if not args.file.is_file():
@@ -205,8 +241,9 @@ def main(argv: list[str] | None = None) -> int:
205241
elif args.cmd == "list":
206242
if not args.category and not args.all:
207243
print(
208-
"error: `list` needs --category (one or more) — or --all to dump the whole "
209-
"catalog on purpose. Use `categories` for the cheap map, or `random` to draw blind.",
244+
"error: `list` needs --category (one or more) — or --all to dump "
245+
"the whole catalog on purpose. Use `categories` for the cheap map, "
246+
"or `random` to draw blind.",
210247
file=sys.stderr,
211248
)
212249
return 2

‎.agents/skills/bmad-advanced-elicitation/scripts/tests/test_pick_methods.py‎

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,18 @@
1717
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
1818
import pick_methods # noqa: E402
1919

20-
CSV = """num,category,method_name,description,output_pattern
21-
1,risk,Pre-mortem Analysis,Imagine future failure then work backwards,failure → causes → prevention
22-
2,risk,Assumption Audit,List and stress-test every assumption,list → rate → stress-test
23-
3,core,First Principles Analysis,Rebuild from fundamental truths,assumptions → truths → new approach
24-
4,core,Socratic Questioning,Targeted questions reveal hidden assumptions,questions → revelations → understanding
25-
5,creative,SCAMPER Method,Seven creativity lenses,S→C→A→M→P→E→R
26-
"""
20+
CSV = (
21+
"num,category,method_name,description,output_pattern\n"
22+
"1,risk,Pre-mortem Analysis,Imagine future failure then work backwards,"
23+
"failure → causes → prevention\n"
24+
"2,risk,Assumption Audit,List and stress-test every assumption,"
25+
"list → rate → stress-test\n"
26+
"3,core,First Principles Analysis,Rebuild from fundamental truths,"
27+
"assumptions → truths → new approach\n"
28+
"4,core,Socratic Questioning,Targeted questions reveal hidden assumptions,"
29+
"questions → revelations → understanding\n"
30+
"5,creative,SCAMPER Method,Seven creativity lenses,S→C→A→M→P→E→R\n"
31+
)
2732

2833
EXTRA = [
2934
{

‎.agents/skills/bmad-architecture/scripts/lint_spine.py‎

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,10 @@ def find_ad_issues(body: str, offset: int) -> list[dict]:
129129
findings.append({
130130
"category": "ad_id",
131131
"severity": "high",
132-
"detail": f"AD-{num} is non-monotonic (follows AD-{prev}); ids must ascend and never renumber",
132+
"detail": (
133+
f"AD-{num} is non-monotonic (follows AD-{prev}); "
134+
"ids must ascend and never renumber"
135+
),
133136
"location": loc,
134137
})
135138
prev = num if prev is None else max(prev, num)
@@ -228,20 +231,33 @@ def lint(text: str) -> dict:
228231

229232

230233
def main(argv: list[str] | None = None) -> int:
231-
ap = argparse.ArgumentParser(description="Lint an architecture spine for mechanical integrity.")
232-
ap.add_argument("--workspace", required=True, help="run folder containing ARCHITECTURE-SPINE.md")
234+
ap = argparse.ArgumentParser(
235+
description="Lint an architecture spine for mechanical integrity."
236+
)
237+
ap.add_argument(
238+
"--workspace", required=True, help="run folder containing ARCHITECTURE-SPINE.md"
239+
)
233240
ap.add_argument("-o", "--output", help="write JSON here instead of stdout")
234241
args = ap.parse_args(argv)
235-
236242
spine_path = Path(args.workspace) / SPINE
243+
237244
if not spine_path.exists():
238-
result = {"ok": False, "error": f"{spine_path} not found", "findings": [], "total_findings": 0}
245+
result = {
246+
"ok": False,
247+
"error": f"{spine_path} not found",
248+
"findings": [],
249+
"total_findings": 0,
250+
}
239251
else:
240252
try:
241253
text = spine_path.read_text(encoding="utf-8")
242254
except (OSError, UnicodeDecodeError) as e:
243-
# honor the "exit code is always 0" contract: a read/decode failure travels in JSON
244-
result = {"ok": False, "error": f"could not read {spine_path}: {e}", "findings": [], "total_findings": 0}
255+
result = {
256+
"ok": False,
257+
"error": f"could not read {spine_path}: {e}",
258+
"findings": [],
259+
"total_findings": 0,
260+
}
245261
else:
246262
result = lint(text)
247263

‎.agents/skills/bmad-architecture/scripts/tests/test_lint_spine.py‎

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,11 @@ def test_unpinned_dep_caught():
119119
def test_placeholder_version_caught():
120120
text = CLEAN.replace("| fastapi | 0.115 |", "| fastapi | {pin} |")
121121
result = lint_spine.lint(text)
122-
assert any(f["category"] == "version_pin" and "fastapi" in f["detail"] for f in result["findings"])
122+
assert any(
123+
f["category"] == "version_pin"
124+
and "fastapi" in f["detail"]
125+
for f in result["findings"]
126+
)
123127

124128

125129
def test_no_stack_section_ok():
@@ -146,12 +150,19 @@ def test_template_token_is_low_severity():
146150
# mechanical pass stays near-zero false-positive
147151
text = CLEAN.replace("single write path", "{decision}")
148152
result = lint_spine.lint(text)
149-
toks = [f for f in result["findings"] if f["category"] == "placeholder" and "template token" in f["detail"]]
153+
toks = [
154+
f
155+
for f in result["findings"]
156+
if f["category"] == "placeholder" and "template token" in f["detail"]
157+
]
150158
assert toks and all(f["severity"] == "low" for f in toks)
151159

152160

153161
def test_no_frontmatter_body_still_scanned():
154-
text = "## Invariants\n\n### AD-1 — x\n\n- **Binds:** all\n- **Prevents:** drift\n- **Rule:** TBD\n"
162+
text = (
163+
"## Invariants\n\n### AD-1 — x\n\n"
164+
"- **Binds:** all\n- **Prevents:** drift\n- **Rule:** TBD\n"
165+
)
155166
result = lint_spine.lint(text)
156167
assert "placeholder" in cats(result) # TBD caught even with no frontmatter
157168

@@ -161,7 +172,9 @@ def test_frontmatter_value_with_dashes_not_truncated():
161172
text = ("---\nname: 'x'\nscope: 'phase 1 --- phase 2'\n---\n\n"
162173
"## Stack\n\n| Name | Version |\n| --- | --- |\n| fastapi | |\n")
163174
result = lint_spine.lint(text)
164-
assert any(f["category"] == "version_pin" for f in result["findings"]) # read past the inline ---
175+
assert any(
176+
f["category"] == "version_pin" for f in result["findings"]
177+
) # read past the inline ---
165178

166179

167180
def test_ad_heading_in_fence_not_counted():
@@ -247,15 +260,25 @@ def test_frontmatter_unfilled_token_caught():
247260
# an unfilled {scope}/{paradigm}/{date} in frontmatter is part of the contract and must lint
248261
text = "---\nname: 'x'\nscope: '{what this spine governs}'\n---\n\n## Invariants\n"
249262
result = lint_spine.lint(text)
250-
fm = [f for f in result["findings"] if f["category"] == "placeholder" and "frontmatter" in f["detail"]]
251-
assert fm and any("template token" in f["detail"] for f in fm)
263+
fm = [
264+
f
265+
for f in result["findings"]
266+
if f["category"] == "placeholder" and "frontmatter" in f["detail"]
267+
]
268+
assert fm and any(
269+
"template token" in f["detail"] for f in fm
270+
)
252271

253272

254273
def test_frontmatter_tbd_caught():
255274
text = "---\nname: 'x'\nstatus: TBD\n---\n\n## Invariants\n"
256275
result = lint_spine.lint(text)
257-
assert any(f["category"] == "placeholder" and "frontmatter" in f["detail"] and "TBD" in f["detail"]
258-
for f in result["findings"])
276+
assert any(
277+
f["category"] == "placeholder"
278+
and "frontmatter" in f["detail"]
279+
and "TBD" in f["detail"]
280+
for f in result["findings"]
281+
)
259282

260283

261284
def test_unreadable_spine_returns_error_not_crash(tmp_path, capsys):

0 commit comments

Comments
 (0)