Skip to content

Commit fc7a6be

Browse files
chore: remove v2 ticket system references (.tickets/, merge-ticket-index.py, direct file editing) (merge worktree-20260325-214043)
2 parents 2a4c7b0 + c45f374 commit fc7a6be

File tree

14 files changed

+39
-179
lines changed

14 files changed

+39
-179
lines changed

CLAUDE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ Priority: 0-4 (0=critical, 4=backlog). Never use "high"/"medium"/"low".
6767
**This repo is the `dso` plugin.** Skills: interface-contracts, resolve-conflicts, tickets-health, design-onboarding, design-review, design-wireframe, ui-discover, debug-everything, sprint, brainstorm, preplanning, implementation-plan, fix-bug (canonical bug-fix workflow; replaces tdd-workflow for bug fixes), tdd-workflow (new feature TDD only), etc. Commands (commit, end, review) also come from the plugin. Skills are invoked as `/dso:skill-name` (fully qualified, required) or `/skill-name` (command alias, allowed but not preferred in docs). **Skill namespace qualification policy**: all skill invocations in in-scope files (plugins/dso/skills/, plugins/dso/docs/, plugins/dso/hooks/, plugins/dso/commands/, CLAUDE.md) MUST use the qualified `/dso:<skill-name>` form. `plugins/dso/scripts/check-skill-refs.sh` enforces this as a fatal CI check via `plugins/dso/scripts/validate.sh`; it exits non-zero when any unqualified reference is found. `plugins/dso/scripts/qualify-skill-refs.sh` is the one-shot bulk rewriter (idempotent) that transforms `/skill-name` → `/dso:skill-name` across all in-scope files — run it after adding new in-scope content with unqualified refs. Ticket scripts in `plugins/dso/scripts/` (`ticket` dispatcher, `tk-sync-lib.sh`, and 22+ utility scripts). Project-specific config in `.claude/dso-config.conf` (flat KEY=VALUE format; keys: `format.*`, `ci.*`, `commands.*`, `jira.*`, `design.*`, `tickets.*`, `merge.*`, `version.*`). `version.*` config keys: `version.file_path` (path to the file holding the project's semver string; absent = skip version bumping; supported formats: `.json` → `version` key, `.toml` → `version` field, plaintext/no-extension → single semver line). `test.*` config keys: `test.suite.<name>.command` (shell command to run the suite; config-only suites get `runner=config`), `test.suite.<name>.speed_class` (`fast|slow`; overrides auto-discovered default of `unknown`). Config entries merge with auto-discovered suites by name: config wins on explicitly set fields. Use `project-detect.sh --suites [REPO_ROOT]` to discover test suites — outputs a JSON array with `name`, `command`, `speed_class`, `runner` fields (exit 0 always). Heuristics in precedence order: config > Makefile `/^test[-_]/` > pytest dirs > npm scripts > bash runners. **CI workflow generation** (`/dso:project-setup`): when no `.github/workflows/*.yml` exist, `project-detect.sh --suites` feeds directly into `ci-generator.sh --suites-json <json> --output-dir .github/workflows/` to generate `ci.yml` (fast suites, pull_request trigger) and `ci-slow.yml` (slow suites, push-to-main trigger); YAML is validated via actionlint or `yaml.safe_load` before writing. For existing projects with uncovered suites, `/dso:project-setup` prompts the user for each suite: `fast-gate` (append job to gating workflow), `separate` (new workflow file), or `skip` (writes `test.suite.<name>.ci_placement=skip` to `.claude/dso-config.conf` to suppress future prompts). Non-interactive mode defaults fast suites to fast-gate and slow/unknown suites to separate.
6868
`ci.*` config keys: `ci.workflow_name` (GitHub Actions workflow name for `gh workflow run`; absent = skip post-push CI trigger recovery — **preferred** over deprecated `merge.ci_workflow_name`). `merge.*` config keys: `merge.visual_baseline_path` (path to snapshot dir; absent = skip baseline intent check), `merge.ci_workflow_name` (**deprecated** — use `ci.workflow_name` instead; `merge-to-main.sh` falls back to this key with a deprecation warning when `ci.workflow_name` is absent), `merge.message_exclusion_pattern` (regex passed to `grep -vE` when composing merge message; default `^chore: post-merge cleanup`). Source of truth: `plugins/dso/scripts/merge-to-main.sh`. Phased workflow: `sync → merge → version_bump → validate → push → archive → ci_trigger`; state file at `/tmp/merge-to-main-state-<branch>.json` (4h TTL) records completed phases for `--resume`; lock file at `/tmp/merge-to-main-lock-<hash>` prevents concurrent runs; SIGURG trap saves current phase to state file on interrupt. The `version_bump` phase runs `bump-version.sh --patch` when `version.file_path` is configured and `--bump` is passed (or bump mode is on); patch bumps happen at merge time, not commit time. **Plugin portability**: All host-project path assumptions (app dir, make targets, Python version) are config-driven via `.claude/dso-config.conf` — the plugin is portable to projects with different directory structures. **Host project script invocation**: Host projects call DSO scripts via `.claude/scripts/dso <script-name>` (shim). Install with `bash plugins/dso/scripts/dso-setup.sh [TARGET_REPO]` from the repo root; the shim resolves DSO_ROOT from `CLAUDE_PLUGIN_ROOT` env var or `dso.plugin_root` in `.claude/dso-config.conf`.
6969

70-
**Ticket index merge driver**: `.tickets-tracker/.index.json` conflicts auto-resolve via `plugins/dso/scripts/merge-ticket-index.py` (JSON union merge; theirs-wins on true conflicts). `.gitattributes` maps the file to the `tickets-index-merge` driver (register per-clone; see Quick Reference). `worktree-sync-from-main.sh` includes a script-level fallback for CI/fresh-clone environments where the driver is not registered. The pre-commit review gate (`pre-commit-review-gate.sh`) handles merge commits (`MERGE_HEAD`) natively — when MERGE_HEAD exists, it computes the merge base and filters out incoming-only files (files changed on main but not on the worktree branch) from review consideration, since those were already reviewed on main. Fail-safe: if MERGE_HEAD equals HEAD or merge-base computation fails, normal review enforcement applies.
70+
The pre-commit review gate (`pre-commit-review-gate.sh`) handles merge commits (`MERGE_HEAD`) natively — when MERGE_HEAD exists, it computes the merge base and filters out incoming-only files (files changed on main but not on the worktree branch) from review consideration, since those were already reviewed on main. Fail-safe: if MERGE_HEAD equals HEAD or merge-base computation fails, normal review enforcement applies.
7171

7272
**Worktree lifecycle** (`claude-safe`): After Claude exits, `_offer_worktree_cleanup` auto-removes the worktree if: (1) branch is ancestor of main (`is_merged`), AND (2) `git status --porcelain` is empty (`is_clean`). No special filtering — `.tickets-tracker/` files block removal like any other dirty file. `/dso:end` ensures the worktree meets these criteria by: generating technical learnings (Step 2.8) and creating bug tickets (Step 2.85) before commit/merge, and verifying `is_merged` + `is_clean` (Step 4.75) before session summary.
7373

plugins/dso/hooks/compute-diff-hash.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
# Includes changes in the git index (staged) and modifications to tracked files.
55
# Excludes untracked files — new files must be staged before review (per COMMIT-WORKFLOW.md).
66
# This prevents temp test fixtures from causing hash mismatches between review and pre-commit.
7-
# Excludes .tickets/ and .tickets-tracker/ files from hash — ticket metadata changes must not invalidate code reviews.
7+
# Excludes .tickets-tracker/ files from hash — ticket metadata changes must not invalidate code reviews.
88
#
99
# Usage:
1010
# HASH=$(.claude/hooks/compute-diff-hash.sh)

plugins/dso/hooks/lib/pre-bash-functions.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ hook_commit_failure_tracker() {
225225
local category
226226
for category in "${FAILED_CATEGORIES[@]}"; do
227227
local RESULT=""
228-
# Search .tickets/ for matching ticket files
228+
# Search tickets directory for matching ticket files
229229
RESULT=$($_SEARCH_CMD "$category failure" "$TICKETS_DIR" 2>/dev/null | head -1 || echo "")
230230
if [[ -z "$RESULT" ]]; then
231231
UNTRACKED+=("$category")

plugins/dso/hooks/lib/pre-edit-write-functions.sh

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,10 +78,7 @@ hook_cascade_circuit_breaker() {
7878
# Split into two case blocks because $HOME expansion does not work
7979
# inside a single case pattern list with | separators.
8080
case "$FILE_PATH" in
81-
# REVIEW-DEFENSE: .tickets/* is the v2 ticket path; retained for backward compat
82-
# with test_pre_edit_dispatcher_cascade_exempt_allows_tickets (test-pre-edit-write-dispatcher.sh).
83-
# .tickets-tracker/* is intentionally NOT here — hook_tickets_tracker_guard blocks those edits.
84-
*/CLAUDE.md|*/.claude/*|*/.tickets/*)
81+
*/CLAUDE.md|*/.claude/*)
8582
return 0
8683
;;
8784
esac

plugins/dso/scripts/merge-to-main.sh

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -662,10 +662,7 @@ _check_push_needed() {
662662
# 3. If branch exists on origin: git push --force-with-lease.
663663
# On force-push failure: restore HEAD via git reset --soft, return 1.
664664
# 4. GIT_EDITOR=: git rebase origin/main.
665-
# On conflict:
666-
# - If ONLY .tickets-tracker/.index.json conflicts: auto-resolve via merge-ticket-index.py
667-
# (extracts clean :1:/:2:/:3: staging versions before running the driver).
668-
# - Otherwise: print ACTION REQUIRED with conflicted file list, rebase --abort, return 1.
665+
# On conflict: print ACTION REQUIRED with conflicted file list, rebase --abort, return 1.
669666
# 5. Print RECOVERY: Squash-rebase succeeded. Return 0.
670667
_squash_rebase_recovery() {
671668
# Validate BRANCH is set

plugins/dso/skills/end-session/SKILL.md

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -205,9 +205,7 @@ git log main..$BRANCH --oneline
205205
.claude/scripts/dso merge-to-main.sh
206206
```
207207

208-
If the script reports ERROR with `CONFLICT_DATA:` prefix (merge conflicts in non-`.tickets/` files): invoke `/dso:resolve-conflicts` to attempt agent-assisted resolution. If resolution succeeds, continue to Step 5. If the script reports a non-conflict ERROR: relay the error message to the user and stop.
209-
210-
**CRITICAL — ticket conflict handling**: If a merge conflict occurs in `.tickets/` files (individual ticket `.md` files or archive files), do NOT use `git merge -X ours`, `git checkout --ours -- .tickets/`, or any other "accept worktree blindly" strategy. Main may have received ticket updates from another worktree. Instead, invoke `/dso:resolve-conflicts`, which will show the diff between both versions and ask the user which to keep.
208+
If the script reports ERROR with `CONFLICT_DATA:` prefix (merge conflicts in non-ticket files): invoke `/dso:resolve-conflicts` to attempt agent-assisted resolution. If resolution succeeds, continue to Step 5. If the script reports a non-conflict ERROR: relay the error message to the user and stop.
211209

212210
### 4.5. Sync Tickets to Jira
213211

@@ -271,11 +269,11 @@ cd "$REPO_ROOT"
271269
git status --porcelain
272270
```
273271

274-
**All four conditions must be true** before proceeding (exclude `.tickets/` — ticket files sync independently and may appear dirty in worktrees):
275-
- No unstaged changes (`git diff --quiet -- ':!.tickets/'`)
276-
- No uncommitted staged changes (`git diff --cached --quiet -- ':!.tickets/'`)
277-
- No unmerged paths (`git diff --name-only --diff-filter=U -- ':!.tickets/'` is empty)
278-
- No untracked files (`git ls-files --others --exclude-standard -- ':!.tickets/'` is empty)
272+
**All four conditions must be true** before proceeding:
273+
- No unstaged changes (`git diff --quiet`)
274+
- No uncommitted staged changes (`git diff --cached --quiet`)
275+
- No unmerged paths (`git diff --name-only --diff-filter=U` is empty)
276+
- No untracked files (`git ls-files --others --exclude-standard` is empty)
279277

280278
If any condition fails:
281279
1. Report the dirty files and which condition(s) failed.

plugins/dso/skills/implementation-plan/SKILL.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -671,7 +671,7 @@ Fill the template placeholders with:
671671
Parse the JSON `findings` array from the sub-agent response. For each finding:
672672

673673
- **If `type: "new_task"`**: Create a new task via `.claude/scripts/dso ticket create` with the finding's title and description, parent set to the story, add dependency on the appropriate existing task(s), and add to the summary table.
674-
- **If `type: "ac_amendment"`**: Edit `.tickets/<target_task_id>.md` to append the finding's description as an additional acceptance criterion under the `## Acceptance Criteria` section.
674+
- **If `type: "ac_amendment"`**: Use `.claude/scripts/dso ticket comment <target_task_id> "AC amendment: <description>"` to append the finding's description as an additional acceptance criterion.
675675

676676
### Fallback Behavior
677677

plugins/dso/skills/preplanning/SKILL.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ This skill implements a five-phase process to transform epics into implementable
5353
### Step 1: Select and Load Epic (/dso:preplanning)
5454

5555
If `<epic-id>` was not provided:
56-
1. Run `.claude/scripts/dso ticket list` then filter results to epics only (cross-reference with `grep -l '^type: epic' .tickets/*.md`)
56+
1. Run `.claude/scripts/dso ticket list` then filter results to epics only (filter JSON output where `ticket_type == 'epic'`)
5757
2. If no open epics exist, report and exit
5858
3. Present epics to the user (if more than 5, show first 5 with option to see more)
5959
4. Get user selection
@@ -289,10 +289,10 @@ Parse the blue team's accepted findings and apply each one based on its `type`:
289289

290290
| Finding Type | Action |
291291
|-------------|--------|
292-
| `new_story` | Create a new story: `.claude/scripts/dso ticket create story "<title>" --parent=<epic-id>`. Then immediately use the Write or Edit tool to add the full body (description, done definitions, considerations) below the YAML frontmatter in `.tickets/<id>.md`. |
293-
| `modify_done_definition` | Edit the target story's ticket file (`.tickets/<target_story_id>.md`) to add or modify done definitions per the finding's description. |
292+
| `new_story` | Create a new story: `.claude/scripts/dso ticket create story "<title>" --parent=<epic-id>`. Then use `.claude/scripts/dso ticket comment <id> "<body>"` to add description, done definitions, and considerations. |
293+
| `modify_done_definition` | Use `.claude/scripts/dso ticket comment <target_story_id> "Done definition update: <description>"` to record the modified done definition. |
294294
| `add_dependency` | Add the dependency: `.claude/scripts/dso ticket link <target_story_id> <dependency_id> depends_on` (extract dependency ID from the finding's description). |
295-
| `add_consideration` | Edit the target story's ticket file to append the consideration to its Considerations section. |
295+
| `add_consideration` | Use `.claude/scripts/dso ticket comment <target_story_id> "Consideration: <text>"` to append the consideration. |
296296

297297
Log a summary after applying findings:
298298
```
@@ -411,7 +411,7 @@ For new stories, create the ticket then immediately write the full story body in
411411
STORY_ID=$(.claude/scripts/dso ticket create story "As a [persona], [goal]" --parent=<epic-id> --priority=<priority>)
412412
```
413413

414-
Then use the Write or Edit tool to write the full body into `.tickets/<story-id>.md`, preserving the YAML frontmatter (lines 1–N ending with `---`) and replacing everything after it with the structured markdown body:
414+
Then use `.claude/scripts/dso ticket comment <story-id> "<body>"` to add the structured body content:
415415

416416
```markdown
417417
## Description
@@ -440,7 +440,7 @@ Then use the Write or Edit tool to write the full body into `.tickets/<story-id>
440440

441441
Omit the `## Escalation Policy` section if the user selected **Autonomous** in Phase 1 Step 1b. The ticket file must never be left as a bare title — always write the structured body immediately after creation.
442442

443-
For modified stories, edit `.tickets/<existing-id>.md` directly to update the title heading and body sections.
443+
For modified stories, use `.claude/scripts/dso ticket comment <existing-id> "<updated content>"` to record changes.
444444

445445
For stories to delete:
446446
```bash
@@ -818,7 +818,7 @@ After writing the Scope section for each story, verify every "OUT" assertion tha
818818
| 2: Risk & Scope Scan | Flag cross-cutting concerns, identify split candidates | Lightweight analysis (no sub-agents) |
819819
| 2.5: Adversarial Review | Red team attack on story map, blue team filter findings (skip if < 3 stories) | `Task` (opus red team, sonnet blue team) |
820820
| 3: Walking Skeleton | Prioritize critical path, apply INVEST, Foundation/Enhancement splits | Priority analysis, `.claude/scripts/dso ticket link` |
821-
| 4: Verification | Create stories, link criteria, validate, wireframe UI stories | `.claude/scripts/dso ticket create`, `.claude/scripts/dso ticket link`, `.tickets/<id>.md` editing, `validate-issues.sh`, `/dso:design-wireframe` |
821+
| 4: Verification | Create stories, link criteria, validate, wireframe UI stories | `.claude/scripts/dso ticket create`, `.claude/scripts/dso ticket link`, `.claude/scripts/dso ticket comment`, `validate-issues.sh`, `/dso:design-wireframe` |
822822

823823
## Example: Reconciliation + Story Creation
824824

plugins/dso/skills/resolve-conflicts/SKILL.md

Lines changed: 5 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -59,29 +59,13 @@ MERGE_IN_PROGRESS=$(test -f "$(git rev-parse --git-dir)/MERGE_HEAD" && echo "yes
5959
- If `$MERGE_IN_PROGRESS` is `yes` and no unresolved conflicts remain: report "Merge in progress with all conflicts pre-resolved — run `git commit` to finalize the merge." and exit. Do NOT report "no conflicts detected" — the merge needs committing, not aborting.
6060
- If `$MERGE_IN_PROGRESS` is `no`: report "No conflicts detected — merge is clean." and exit.
6161

62-
Separate `.tickets/` conflicts from code conflicts:
62+
Separate `.tickets-tracker/` conflicts from code conflicts:
6363
```bash
64-
TICKET_CONFLICTS=$(echo "$CONFLICTED" | grep '^\.tickets/' || true)
65-
CODE_CONFLICTS=$(echo "$CONFLICTED" | grep -v '^\.tickets/' || true)
64+
TICKET_CONFLICTS=$(echo "$CONFLICTED" | grep '^\.tickets-tracker/' || true)
65+
CODE_CONFLICTS=$(echo "$CONFLICTED" | grep -v '^\.tickets-tracker/' || true)
6666
```
6767

68-
**NEVER use `git checkout --ours -- .tickets/` or `git merge -X ours` for ticket conflicts.** Main may have received updates from another worktree; blindly accepting the worktree version can destroy those updates.
69-
70-
Handle `.tickets/` conflicts as follows:
71-
72-
- **`.tickets/` files** (individual ticket `.md` files, archive files): **Must show a diff to the user and ask which version to keep.** For each conflicted ticket file:
73-
1. Show the diff between both versions:
74-
```bash
75-
echo "=== Ticket conflict: <file> ==="
76-
git show :2:<file> # ours (worktree version)
77-
echo "--- vs main version ---"
78-
git show :3:<file> # theirs (main version)
79-
```
80-
2. Briefly summarize the differences (e.g., status changes, note additions, field changes)
81-
3. Ask the user: "Keep worktree version, main version, or merge manually?"
82-
4. Apply only after receiving explicit user confirmation
83-
84-
If only `.tickets/` conflicts existed and all are resolved (with user approval where required): complete the merge and exit.
68+
If only `.tickets-tracker/` conflicts exist (JSON event files): auto-resolve by accepting ours (`git checkout --ours` + `git add` for each), complete the merge, and exit. Ticket event files are append-only and safe to auto-resolve.
8569

8670
If code conflicts exist: proceed to Step 2.
8771

@@ -175,7 +159,7 @@ If resolution was abandoned (user chose to resolve manually):
175159

176160
## Constraints
177161

178-
- All `.tickets/` files (individual ticket `.md` and archive files) require user confirmation — never use "ours" strategy on them.
162+
- `.tickets-tracker/` JSON event files are auto-resolved (accept ours) — they are append-only and safe to resolve without user input.
179163
- Sub-agent model: **sonnet** — conflict resolution needs code understanding but not architectural reasoning
180164
- This skill does NOT commit or push — it only completes the merge. The calling skill handles commit/push.
181165
- Maximum 10 conflicted files. Above that, report to user: "Too many conflicts for agent-assisted resolution. Consider rebasing incrementally."

0 commit comments

Comments
 (0)