spec-kitty / spec-kitty/spec-kitty

Cross-mission validation gaps: owned_files overlap and stale cross-mission blockers are invisible to every gate

Open
#4,227 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Python
Stars
1.6k
Forks
165
Avg merge
14h 52m
Merged PRs (30d)
303

Description

### Summary

Spec Kitty validates work-package constraints **within** a mission but never **across** missions. Two consequences, observed in one repository running five concurrent missions:

1. **Two missions can each declare exclusive ownership of the same file, and both validation gates report clean.**
2. **Cross-mission blockers live in prose with no checker, so they go stale silently in both directions** — a resolved blocker keeps being quoted as live, and a scope claim keeps being quoted after the ground moved.

Both were caught by humans reading another mission's files, not by tooling. Neither is detectable from inside the affected mission.

**Version:** `spec-kitty-cli` 3.2.7 (uv tool install), Python 3.13, macOS.

---

### Part 1 — `owned_files` overlap is invisible across missions

`finalize-tasks` enforces no-overlap between work packages inside one mission. It does not look at any other mission, so two missions can claim the same path exclusively and each will certify itself clean.

Observed:

- Mission A, `WP05`: `owned_files` included `src/pkg/module_x.py`
- Mission B, `WP08`: the same path as its **sole** `owned_files` entry *and* its `authoritative_surface`, with implementation steps ending in `git rm` of it

Both missions independently returned:

```
$ spec-kitty agent mission finalize-tasks --validate-only --mission --json
"ownership_warnings": []
```

Had both lanes run, they would have edited the same path concurrently, with one deleting it. It was caught only because a human happened to open the other mission's WP file while investigating something unrelated.

This matters more than a normal race because `authoritative_surface` and `owned_files` are *stated as exclusive*. The mission author has done everything the contract asks and still gets no signal.

#### Reproduction

1. Create two missions.
2. In each, give one WP an `owned_files` entry naming the same repo path, and set `authoritative_surface` to that path in one of them.
3. Run `finalize-tasks --validate-only --mission `.
4. Both return `ownership_warnings: []`.

#### Suggested fix

When validating ownership, consider `owned_files` from every mission whose work packages are not yet `done`/`merged`, and warn when a path is claimed by more than one. The data is already on disk under `kitty-specs/*/tasks/*.md`; only the scope of the check needs widening.

---

### Part 2 — cross-mission dependencies have no machine-checkable form

Intra-mission dependencies are enforced and work correctly:

```
$ spec-kitty agent action implement WP02 --agent --mission
Error: dependencies_not_satisfied: WP02 depends on WP01; all dependencies must be
approved or done before implementation can start
```

Cross-mission constraints have no equivalent. They are written as prose in `spec.md` / `plan.md` ("owned by mission X", "blocked until mission Y merges") and nothing ever re-evaluates them. They rot in both directions:

**Stale-open** — a mission parked six of its eight work packages behind a cross-mission gate that had already been resolved. The blocking mission had merged; only the prose still said otherwise. Verifiable in that repo as:

```
$ git merge-base --is-ancestor
# returns true — i.e. the blocker merged — while six WPs remained parked behind it in prose
```

(Credit: this case was found and diagnosed by a separate session working that mission; I verified the merge-base result independently.)

**Stale-scope** — another mission's spec named three affected modules as its scope. Two of them were repaired by an unrelated branch that merged mid-planning, so the spec described a set that no longer existed. Caught only because `/spec-kitty.analyze` was re-run and cross-checked against a generated reference; nothing in the tooling would have flagged it.

#### Suggested fix

Give cross-mission references a declared, resolvable form — e.g. a `blocked_by: /` field in WP frontmatter, resolved against that mission's actual status at gate time. Then a resolved blocker stops being quoted as live, and a stale reference surfaces as an error rather than as prose nobody re-reads.

---

### Why these are one issue

Both are the same gap seen from two sides: **everything Spec Kitty machine-checks stops at the mission boundary, and everything that crosses it is prose.** In a single-mission repository neither is reachable. In a repository running several missions concurrently — which the worktree/lane model actively encourages — both are reachable, silent, and only detectable by a human reading files belonging to a mission they are not working on.

Related: #4226 (charter synthesize additive-only deadlock), found in the same repository during the same period.

Contributor guide

Open the contributing guide

Research direction

Start with the two-mission reproduction and the finalize-tasks --validate-only command, then read ownership data under kitty-specs/*/tasks/*.md and the mission spec.md/plan.md references. Done means unfinished missions warn on duplicate owned_files claims and cross-mission blockers have a declared form whose status can be checked for resolved or stale references.

Written by the indexing model from the issue text.

Assessment

Tech stack
git, python
Domain
cli, tooling
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.