Skip to content

Commit 944fa01

Browse files
chore: auto-commit ticket changes before merge (merge worktree-20260321-161319)
2 parents 7b0cb80 + 7e592cb commit 944fa01

File tree

20 files changed

+1568
-12
lines changed

20 files changed

+1568
-12
lines changed

.tickets/.sync-state.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -449,8 +449,8 @@
449449
"last_synced": "2026-03-19T18:38:35Z",
450450
"local_hash": "14c516947a151a3db8bdec4010e2fd6e"
451451
},
452-
"last_pull_timestamp": "2026-03-21T22:39:15Z",
453-
"last_sync_commit": "8975393118984483d54675d2d4988f4c967eeb97",
452+
"last_pull_timestamp": "2026-03-22T01:03:05Z",
453+
"last_sync_commit": "9bc7221b103c68f2d214df961a40efdaf6da87e4",
454454
"w21-5cqr": {
455455
"jira_hash": "bce29d76f01c58613ee99cb1dd03920d",
456456
"jira_key": "DIG-61",

.tickets/dso-gxct.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
---
2+
id: dso-gxct
3+
status: open
4+
deps: []
5+
links: []
6+
created: 2026-03-22T00:17:29Z
7+
type: bug
8+
priority: 4
9+
assignee: Joe Oakhart
10+
---
11+
# Fix: project-detect.sh add --suites flag to Usage header comment
12+

.tickets/dso-qv93.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
---
2+
id: dso-qv93
3+
status: open
4+
deps: []
5+
links: []
6+
created: 2026-03-22T00:17:33Z
7+
type: bug
8+
priority: 4
9+
assignee: Joe Oakhart
10+
---
11+
# Fix: project-detect.sh short-circuit python3 subprocess when entries is empty
12+

.tickets/dso-ubtf.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
---
2+
id: dso-ubtf
3+
status: open
4+
deps: []
5+
links: []
6+
created: 2026-03-22T00:17:38Z
7+
type: bug
8+
priority: 4
9+
assignee: Joe Oakhart
10+
---
11+
# Fix: project-detect.sh replace find -print -quit with POSIX-portable alternative
12+

.tickets/w21-4d04.md

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
---
2+
id: w21-4d04
3+
status: closed
4+
deps: [w21-fljz, w21-v9tg]
5+
links: []
6+
created: 2026-03-21T23:38:57Z
7+
type: task
8+
priority: 2
9+
assignee: Joe Oakhart
10+
parent: w22-5e4i
11+
---
12+
# Implement config key merge for test.suite.<name> entries
13+
14+
Extend project-detect.sh --suites to read test.suite.<name>.command and test.suite.<name>.speed_class config keys from .claude/dso-config.conf and merge them with auto-discovered suites. This completes the full heuristic pipeline including the fixture acceptance test.
15+
16+
TDD Requirement: This task turns GREEN the RED tests from T4:
17+
- test_project_detect_suites_config_merge
18+
- test_project_detect_suites_config_overrides_autodiscovered
19+
- test_project_detect_suites_fixture_acceptance
20+
21+
Implementation steps in plugins/dso/scripts/project-detect.sh (--suites path only):
22+
1. Config read: if PROJECT_DIR/.claude/dso-config.conf exists, parse lines matching pattern 'test.suite.<name>.command=<value>' and 'test.suite.<name>.speed_class=<value>'. Use grep + sed (no jq, no python YAML) per existing project patterns.
23+
2. Build config suite map: for each unique <name> found in config, collect command and speed_class (may be set independently). Config-only suites (no auto-discovered match) get runner=config.
24+
3. Merge with auto-discovered suites (highest-precedence tier):
25+
- If a config entry matches an auto-discovered name: override command and speed_class with config values; keep runner from config only if command is overridden (otherwise keep auto-discovered runner).
26+
- Actually per spec: 'config wins on all fields it explicitly sets'. So: if test.suite.unit.command is set, command=config_value and runner=config; if test.suite.unit.speed_class is set, speed_class=config_value.
27+
- Config-only entries (no auto-discovered match): runner=config, speed_class from config or 'unknown' if not set.
28+
4. Apply config entries at highest precedence (before Makefile in dedup step). Integrate into the precedence ordering from T6.
29+
5. Auto-discovered suites (Makefile, pytest, npm, bash) always have speed_class='unknown' per spec.
30+
6. Full fixture acceptance test: repo with Makefile test-unit/test-e2e, tests/models/ containing test_model.py, and config test.suite.custom.command='bash run-custom.sh' -> 4 JSON entries: {name:unit,runner:make}, {name:e2e,runner:make}, {name:models,runner:pytest}, {name:custom,runner:config,command:'bash run-custom.sh'}.
31+
32+
## Acceptance Criteria
33+
34+
- [ ] Config test.suite.custom.command='bash run-custom.sh' -> entry name=custom, runner=config, command='bash run-custom.sh', speed_class=unknown
35+
Verify: TMPD=$(mktemp -d) && mkdir -p "$TMPD/.claude" && echo 'test.suite.custom.command=bash run-custom.sh' > "$TMPD/.claude/dso-config.conf" && bash $(git rev-parse --show-toplevel)/plugins/dso/scripts/project-detect.sh --suites "$TMPD" | python3 -c 'import sys,json; d=json.load(sys.stdin); e=[x for x in d if x["name"]=="custom"]; assert len(e)==1 and e[0]["runner"]=="config" and e[0]["command"]=="bash run-custom.sh"' && rm -rf "$TMPD"
36+
- [ ] Config overrides auto-discovered Makefile entry for same name
37+
Verify: TMPD=$(mktemp -d) && mkdir -p "$TMPD/.claude" && echo 'test.suite.unit.command=custom-unit-cmd' > "$TMPD/.claude/dso-config.conf" && printf 'test-unit:\n\tpytest tests/unit/' > "$TMPD/Makefile" && bash $(git rev-parse --show-toplevel)/plugins/dso/scripts/project-detect.sh --suites "$TMPD" | python3 -c 'import sys,json; d=json.load(sys.stdin); units=[x for x in d if x["name"]=="unit"]; assert len(units)==1 and units[0]["command"]=="custom-unit-cmd"' && rm -rf "$TMPD"
38+
- [ ] Fixture acceptance test: 4 entries for unit/make, e2e/make, models/pytest, custom/config
39+
Verify: TMPD=$(mktemp -d) && mkdir -p "$TMPD/.claude" "$TMPD/tests/models" && printf 'test-unit:\n\tpytest tests/unit/\ntest-e2e:\n\tpytest tests/e2e/' > "$TMPD/Makefile" && touch "$TMPD/tests/models/test_model.py" && echo 'test.suite.custom.command=bash run-custom.sh' > "$TMPD/.claude/dso-config.conf" && bash $(git rev-parse --show-toplevel)/plugins/dso/scripts/project-detect.sh --suites "$TMPD" | python3 -c 'import sys,json; d=json.load(sys.stdin); assert len(d)==4, f"Expected 4 entries got {len(d)}: {d}"' && rm -rf "$TMPD"
40+
- [ ] RED tests from T4 now pass (GREEN)
41+
Verify: bash $(git rev-parse --show-toplevel)/tests/scripts/test-project-detect.sh 2>&1 | grep -qE 'PASS.*suites_config_merge|PASS.*suites_fixture_acceptance'
42+
- [ ] All existing tests still pass (backward compat regression)
43+
Verify: bash $(git rev-parse --show-toplevel)/tests/scripts/test-project-detect.sh 2>&1 | grep -q 'passed'
44+
- [ ] ruff format --check passes (exit 0) on py files
45+
Verify: ruff format --check $(git rev-parse --show-toplevel)/plugins/dso/scripts/*.py
46+
- [ ] ruff check passes (exit 0) on py files
47+
Verify: ruff check $(git rev-parse --show-toplevel)/plugins/dso/scripts/*.py
48+
49+
50+
## Notes
51+
52+
**2026-03-22T00:42:47Z**
53+
54+
CHECKPOINT 1/6: Task context loaded ✓
55+
56+
**2026-03-22T00:43:02Z**
57+
58+
CHECKPOINT 2/6: Code patterns understood ✓
59+
60+
**2026-03-22T00:43:49Z**
61+
62+
CHECKPOINT 3/6: Tests written (none required — RED tests exist) ✓
63+
64+
**2026-03-22T00:43:52Z**
65+
66+
CHECKPOINT 4/6: Implementation complete ✓ — config key merge already implemented by dependency tasks (w21-fljz, w21-v9tg). All config parsing (test.suite.<name>.command, test.suite.<name>.speed_class), dedup with precedence, and merge logic present in project-detect.sh lines 160-277.
67+
68+
**2026-03-22T00:43:54Z**
69+
70+
CHECKPOINT 5/6: All 112 tests PASS (0 FAIL). Config merge RED tests now GREEN: test_project_detect_suites_config_merge, test_project_detect_suites_config_overrides_autodiscovered, test_project_detect_suites_fixture_acceptance. All ACs verified. ruff format/check pass.
71+
72+
**2026-03-22T00:43:55Z**
73+
74+
CHECKPOINT 6/6: Done ✓

.tickets/w21-cxzv.md

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
---
2+
id: w21-cxzv
3+
status: closed
4+
deps: [w21-f2k3, w21-okrb]
5+
links: []
6+
created: 2026-03-21T23:37:59Z
7+
type: task
8+
priority: 2
9+
assignee: Joe Oakhart
10+
parent: w22-5e4i
11+
---
12+
# Implement --suites flag skeleton, Makefile heuristic, and pytest heuristic
13+
14+
Extend plugins/dso/scripts/project-detect.sh with the --suites flag and implement the two highest-precedence heuristics: Makefile targets matching /^test[-_]/ and pytest test directories.
15+
16+
TDD Requirement: This task turns GREEN the RED tests from T1 and T2:
17+
- test_project_detect_suites_backward_compat_no_flag
18+
- test_project_detect_suites_exit_zero_empty_repo
19+
- test_project_detect_suites_exit_zero_always
20+
- test_project_detect_suites_json_schema
21+
- test_project_detect_suites_makefile
22+
- test_project_detect_suites_pytest
23+
- test_project_detect_suites_makefile_name_derivation
24+
25+
Implementation steps in plugins/dso/scripts/project-detect.sh:
26+
1. Argument parsing: detect --suites as the first arg (before PROJECT_DIR). If present, set SUITES_MODE=1 and set PROJECT_DIR to $2 (or default). If absent, behavior is identical to current (no change to existing KEY=VALUE output path).
27+
2. If SUITES_MODE=0: run existing detection logic unchanged, exit.
28+
3. If SUITES_MODE=1: run only suite discovery logic, output JSON array to stdout, exit 0.
29+
4. Makefile heuristic: grep Makefile for lines matching /^test[-_][a-zA-Z0-9_-]+:/ (top-level test targets). For each target 'test-foo' or 'test_foo', derive name by stripping 'test-' or 'test_' prefix. Entry: {name: "$name", command: "make $target", speed_class: "unknown", runner: "make"}
30+
5. pytest heuristic: find directories under tests/ or test/ (at depth 1) containing at least one test_*.py file. For each dir 'tests/foo/', name = 'foo'. Entry: {name: "foo", command: "pytest tests/foo/", speed_class: "unknown", runner: "pytest"}. If tests/ itself has test_*.py files directly, name = 'unit' (default) or the Makefile-matched name if already present.
31+
6. Output: JSON array using python3 (stdlib, no jq) to stdout. Empty array [] if no suites found.
32+
7. Warnings go to stderr only.
33+
34+
Backward compat invariant: Any code path reached without --suites MUST produce byte-identical output to the current implementation. Add a guard comment: '# BACKWARD_COMPAT: do not modify output above this line without a backward-compat test'.
35+
36+
## Acceptance Criteria
37+
38+
- [ ] Script exits 0 when called without --suites (backward compat)
39+
Verify: bash $(git rev-parse --show-toplevel)/plugins/dso/scripts/project-detect.sh $(mktemp -d); echo $?
40+
- [ ] Script exits 0 when called with --suites on empty dir (outputs [])
41+
Verify: TMPD=$(mktemp -d) && OUT=$(bash $(git rev-parse --show-toplevel)/plugins/dso/scripts/project-detect.sh --suites "$TMPD") && echo "$OUT" | python3 -c 'import sys,json; data=json.load(sys.stdin); assert data == [], f"Expected [], got {data}"' && rm -rf "$TMPD"
42+
- [ ] Makefile test-unit target -> JSON entry name=unit, runner=make
43+
Verify: TMPD=$(mktemp -d) && printf 'test-unit:\n\tpytest tests/unit/' > "$TMPD/Makefile" && bash $(git rev-parse --show-toplevel)/plugins/dso/scripts/project-detect.sh --suites "$TMPD" | python3 -c 'import sys,json; d=json.load(sys.stdin); assert any(e["name"]=="unit" and e["runner"]=="make" for e in d)' && rm -rf "$TMPD"
44+
- [ ] pytest tests/models/ dir -> JSON entry name=models, runner=pytest
45+
Verify: TMPD=$(mktemp -d) && mkdir -p "$TMPD/tests/models" && touch "$TMPD/tests/models/test_model.py" && bash $(git rev-parse --show-toplevel)/plugins/dso/scripts/project-detect.sh --suites "$TMPD" | python3 -c 'import sys,json; d=json.load(sys.stdin); assert any(e["name"]=="models" and e["runner"]=="pytest" for e in d)' && rm -rf "$TMPD"
46+
- [ ] Without --suites, output contains expected KEY=VALUE keys (no JSON)
47+
Verify: TMPD=$(mktemp -d) && OUT=$(bash $(git rev-parse --show-toplevel)/plugins/dso/scripts/project-detect.sh "$TMPD") && echo "$OUT" | grep -q '^stack=' && ! echo "$OUT" | python3 -c 'import sys,json; json.load(sys.stdin)' 2>/dev/null && rm -rf "$TMPD"
48+
- [ ] RED tests from T1 and T2 now pass (GREEN)
49+
Verify: bash $(git rev-parse --show-toplevel)/tests/scripts/test-project-detect.sh 2>&1 | grep -qE 'PASS.*suites_json_schema|PASS.*suites_backward_compat'
50+
- [ ] ruff format --check passes (exit 0) on py files
51+
Verify: ruff format --check $(git rev-parse --show-toplevel)/plugins/dso/scripts/*.py
52+
- [ ] ruff check passes (exit 0) on py files
53+
Verify: ruff check $(git rev-parse --show-toplevel)/plugins/dso/scripts/*.py
54+
55+
56+
## Notes
57+
58+
**2026-03-22T00:09:09Z**
59+
60+
CHECKPOINT 1/6: Task context loaded ✓
61+
62+
**2026-03-22T00:09:29Z**
63+
64+
CHECKPOINT 2/6: Code patterns understood ✓
65+
66+
**2026-03-22T00:09:32Z**
67+
68+
CHECKPOINT 3/6: Tests written (none required — RED tests exist) ✓
69+
70+
**2026-03-22T00:10:09Z**
71+
72+
CHECKPOINT 4/6: Implementation complete ✓
73+
74+
**2026-03-22T00:10:10Z**
75+
76+
CHECKPOINT 5/6: Validation passed ✓ — 96 passed, 0 failed
77+
78+
**2026-03-22T00:11:08Z**
79+
80+
CHECKPOINT 6/6: Done ✓ — All ACs verified. AC6 verify grep pattern has cosmetic mismatch (tests output 'name ... PASS' not 'PASS.*name') but all 7 suites tests pass.

.tickets/w21-etsx.md

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
---
2+
id: w21-etsx
3+
status: closed
4+
deps: [w21-cxzv, w21-v9tg, w21-4d04]
5+
links: []
6+
created: 2026-03-21T23:39:13Z
7+
type: task
8+
priority: 2
9+
assignee: Joe Oakhart
10+
parent: w22-5e4i
11+
---
12+
# Update project-detect.sh script header comment and usage docs
13+
14+
Update the header comment block in plugins/dso/scripts/project-detect.sh to document the new --suites flag, its output schema, and heuristic sources. No logic changes.
15+
16+
test-exempt: This task has no conditional logic and modifies only static documentation comments within the script (no branching, no behavioral contract to assert). Exemption criterion: 'The task is infrastructure-boundary-only — it touches only configuration wiring, dependency injection setup, or module registration with no business logic.' (comment-only change).
17+
18+
Implementation steps:
19+
1. Update the Usage line: 'Usage: project-detect.sh [--suites] <project-dir>'
20+
2. Add --suites to the description block
21+
3. Document the JSON output schema for --suites mode: name (string, unique), command (string), speed_class (fast|slow|unknown), runner (make|pytest|npm|bash|config)
22+
4. Document the heuristic precedence order: config > Makefile /^test[-_]/ > pytest dirs > npm scripts > bash runners
23+
5. Document the name derivation rules: Makefile test-foo -> foo, pytest tests/unit/ -> unit, npm test:integration -> integration, bash test-hooks.sh -> hooks
24+
6. Document backward compatibility guarantee: without --suites, output is unchanged KEY=VALUE format
25+
26+
## Acceptance Criteria
27+
28+
- [ ] Script header contains '--suites' flag documentation
29+
Verify: grep -q '\-\-suites' $(git rev-parse --show-toplevel)/plugins/dso/scripts/project-detect.sh
30+
- [ ] Script header documents the JSON output schema fields (name, command, speed_class, runner)
31+
Verify: grep -q 'speed_class' $(git rev-parse --show-toplevel)/plugins/dso/scripts/project-detect.sh
32+
- [ ] Script header documents heuristic precedence order
33+
Verify: grep -q 'precedence\|Precedence' $(git rev-parse --show-toplevel)/plugins/dso/scripts/project-detect.sh
34+
- [ ] ruff format --check passes (exit 0) on py files
35+
Verify: ruff format --check $(git rev-parse --show-toplevel)/plugins/dso/scripts/*.py
36+
- [ ] ruff check passes (exit 0) on py files
37+
Verify: ruff check $(git rev-parse --show-toplevel)/plugins/dso/scripts/*.py
38+
39+
40+
## Notes
41+
42+
**2026-03-22T00:45:13Z**
43+
44+
CHECKPOINT 1/6: Task context loaded ✓
45+
46+
**2026-03-22T00:45:26Z**
47+
48+
CHECKPOINT 2/6: Code patterns understood ✓
49+
50+
**2026-03-22T00:45:29Z**
51+
52+
CHECKPOINT 3/6: Tests written (none required) ✓
53+
54+
**2026-03-22T00:46:20Z**
55+
56+
CHECKPOINT 4/6: Implementation complete ✓
57+
58+
**2026-03-22T00:46:20Z**
59+
60+
CHECKPOINT 5/6: Tests pass — 112 PASSED, 0 FAILED (bash tests/scripts/test-project-detect.sh) ✓
61+
62+
**2026-03-22T00:46:20Z**
63+
64+
CHECKPOINT 6/6: Done ✓ — AC1 (--suites grep) PASS, AC2 (speed_class grep) PASS, AC3 (precedence grep) PASS, AC4 (ruff format) PASS, AC5 (ruff check) PASS

.tickets/w21-f2k3.md

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
---
2+
id: w21-f2k3
3+
status: closed
4+
deps: []
5+
links: []
6+
created: 2026-03-21T23:36:45Z
7+
type: task
8+
priority: 2
9+
assignee: Joe Oakhart
10+
parent: w22-5e4i
11+
---
12+
# RED: write backward-compat regression tests for --suites flag
13+
14+
Write failing tests in tests/scripts/test-project-detect.sh that verify the --suites flag does not break existing KEY=VALUE output.
15+
16+
TDD Requirement: Write the following named tests FIRST (they must FAIL before T5 is implemented):
17+
- test_project_detect_suites_backward_compat_no_flag: without --suites flag on a fixture with Makefile/CI produces identical KEY=VALUE output (stack=, targets=, etc. all present, no JSON emitted)
18+
- test_project_detect_suites_exit_zero_empty_repo: with --suites on empty repo, exits 0 and outputs []
19+
- test_project_detect_suites_exit_zero_always: with --suites on any repo, exits 0
20+
21+
Test file: tests/scripts/test-project-detect.sh (append using _snapshot_fail/_assert_pass_if_clean pattern)
22+
Source file: plugins/dso/scripts/project-detect.sh
23+
24+
Fuzzy match: normalized source 'projectdetectsh' is substring of normalized test 'testprojectdetectsh' - pass.
25+
26+
Do NOT modify project-detect.sh in this task.
27+
28+
## Acceptance Criteria
29+
30+
- [ ] test_project_detect_suites_backward_compat_no_flag exists in test file
31+
Verify: grep -q 'test_project_detect_suites_backward_compat_no_flag' $(git rev-parse --show-toplevel)/tests/scripts/test-project-detect.sh
32+
- [ ] test_project_detect_suites_exit_zero_empty_repo exists in test file
33+
Verify: grep -q 'test_project_detect_suites_exit_zero_empty_repo' $(git rev-parse --show-toplevel)/tests/scripts/test-project-detect.sh
34+
- [ ] test_project_detect_suites_exit_zero_always exists in test file
35+
Verify: grep -q 'test_project_detect_suites_exit_zero_always' $(git rev-parse --show-toplevel)/tests/scripts/test-project-detect.sh
36+
- [ ] All three new tests FAIL before project-detect.sh --suites is implemented (RED confirmed)
37+
Verify: bash $(git rev-parse --show-toplevel)/tests/scripts/test-project-detect.sh 2>&1 | grep -qE 'FAIL.*suites_backward_compat|FAIL.*suites_exit_zero'
38+
- [ ] ruff format --check passes (exit 0) on py files
39+
Verify: ruff format --check $(git rev-parse --show-toplevel)/plugins/dso/scripts/*.py
40+
- [ ] ruff check passes (exit 0) on py files
41+
Verify: ruff check $(git rev-parse --show-toplevel)/plugins/dso/scripts/*.py
42+
43+
44+
## Notes
45+
46+
**2026-03-21T23:42:47Z**
47+
48+
CHECKPOINT 1/6: Task context loaded ✓
49+
50+
**2026-03-21T23:43:00Z**
51+
52+
CHECKPOINT 2/6: Code patterns understood ✓
53+
54+
**2026-03-21T23:43:29Z**
55+
56+
CHECKPOINT 3/6: Tests written ✓
57+
58+
**2026-03-21T23:43:33Z**
59+
60+
CHECKPOINT 4/6: Implementation complete ✓
61+
62+
**2026-03-21T23:43:47Z**
63+
64+
CHECKPOINT 5/6: Validation passed ✓ — RED phase confirmed: 85 PASS, 3 FAIL (all 3 failures are in --suites tests as expected)
65+
66+
**2026-03-21T23:44:04Z**
67+
68+
CHECKPOINT 6/6: Done ✓
69+
70+
**2026-03-21T23:59:51Z**
71+
72+
CHECKPOINT 6/6: Done ✓ — Files: tests/scripts/test-project-detect.sh. Tests: 85 pass, 3 RED (expected).

0 commit comments

Comments
 (0)