@skitterbyte/skitterspec 16.5.2 → 16.7.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.
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Checks That Accuse
|
|
2
|
+
|
|
3
|
+
A check **accuses** when being wrong costs something: it deletes, it exits
|
|
4
|
+
non-zero, or it tells the user their code is broken. Those checks earn the four
|
|
5
|
+
rules below. An ordinary conditional does not — this is about the ones that act
|
|
6
|
+
on what they conclude.
|
|
7
|
+
|
|
8
|
+
Almost every accusation begins as an **absence**: a name not in a list, a
|
|
9
|
+
directory not on disk, a version not in a response. An absence is evidence only
|
|
10
|
+
once you have established that the lookup could have seen the thing. Three
|
|
11
|
+
times in one day, in unrelated code, we established nothing and acted anyway:
|
|
12
|
+
|
|
13
|
+
| Absence observed | Concluded | What had blinded the lookup |
|
|
14
|
+
|------------------|-----------|-----------------------------|
|
|
15
|
+
| ref not in the issue list | "it does not exist" | the query excluded archived issues, and capped at 250 |
|
|
16
|
+
| version not in the registry's list | "the publish failed" | the registry is eventually consistent |
|
|
17
|
+
| lifecycle folder not on disk | "half-installed" | git does not store an empty directory |
|
|
18
|
+
|
|
19
|
+
The bills: 146 healthy refs accused, a valid release tag deleted, a non-zero
|
|
20
|
+
exit on a healthy repo. Each blind spot was knowable in advance.
|
|
21
|
+
|
|
22
|
+
## 1. Prefer a positive signal to an absence
|
|
23
|
+
|
|
24
|
+
Assert something that must be **present**, not something that must not be
|
|
25
|
+
missing. A positive signal fails loudly when you are wrong about it; an absence
|
|
26
|
+
fails silently whenever the lookup was narrower than you assumed.
|
|
27
|
+
|
|
28
|
+
The scaffold check above stopped asking "is the lifecycle folder there?" — a
|
|
29
|
+
folder git drops as soon as it empties — and started asking whether the config
|
|
30
|
+
folder the installer always writes into is there. Same intent, and the new
|
|
31
|
+
question has an answer.
|
|
32
|
+
|
|
33
|
+
Where no positive signal exists, widen the lookup until absence means
|
|
34
|
+
something (include the archived rows, ask the API for the one id rather than
|
|
35
|
+
scanning a page) — or do not conclude.
|
|
36
|
+
|
|
37
|
+
## 2. Name the blind spot beside the check
|
|
38
|
+
|
|
39
|
+
A comment naming what could make this lookup lie is what makes the next reader
|
|
40
|
+
check it. Not what the code does — what would fool it:
|
|
41
|
+
|
|
42
|
+
```js
|
|
43
|
+
// A LIFECYCLE FOLDER IS NOT CHECKED, deliberately. git does not track empty
|
|
44
|
+
// directories, so it disappears whenever the bucket empties and returns the
|
|
45
|
+
// moment something lands in it.
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Write it when you write the check, while you still know why it is safe.
|
|
49
|
+
|
|
50
|
+
## 3. Pair every accusation with a stays-silent test
|
|
51
|
+
|
|
52
|
+
For each accusing check, a test that feeds it a **healthy but unusual** input
|
|
53
|
+
and asserts it says nothing: the empty bucket, the archived record, the
|
|
54
|
+
just-published version, the file the user edited on purpose. The positive test
|
|
55
|
+
proves the check can fire; only this one proves it does not fire at everyone
|
|
56
|
+
else. All three incidents would have been caught by it, and prose alone had
|
|
57
|
+
already failed to prevent them.
|
|
58
|
+
|
|
59
|
+
## 4. Bias the unknown case toward inaction
|
|
60
|
+
|
|
61
|
+
Three states, not two: yes, no, and *cannot tell*. Route the third to the
|
|
62
|
+
harmless branch — skip, warn, keep, retry — never to the destructive one.
|
|
63
|
+
|
|
64
|
+
The install manifest classifies a file whose hash it does not recognise as
|
|
65
|
+
`customized` rather than stale, so a resync **keeps** it (`managedState`,
|
|
66
|
+
`packages/common/src/init.js`). An unrecognised hash could mean a user's edit or
|
|
67
|
+
a lost manifest; only one of those readings is safe to act on, so it takes that
|
|
68
|
+
one. Being wrong there costs a redundant file on disk. The opposite default
|
|
69
|
+
costs the user their work.
|
|
@@ -173,6 +173,13 @@ test, split the fix into phase files (`01-<slug>.md` …) with a phase index in
|
|
|
173
173
|
`00-overview.md`, and leave the spec in `in-progress` for `/spec-go` to continue.
|
|
174
174
|
Say so explicitly — don't fake green.
|
|
175
175
|
|
|
176
|
+
**Then refresh the mirror (only if a provider is installed).** The Fix tasks are
|
|
177
|
+
ticked, so the repo is now the truth about this fix — and this skill can take a
|
|
178
|
+
bug all the way to green without `/spec-go` ever running. Without a provider this
|
|
179
|
+
is a no-op.
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
|
|
176
183
|
## 6. Report
|
|
177
184
|
|
|
178
185
|
Summarise: root cause, the failing→passing test, the fix, and the full test
|
|
@@ -139,20 +139,20 @@ Before writing any code for this phase, get the workspace clean:
|
|
|
139
139
|
next phase on top of an uncommitted one. (Skip if this is the first phase —
|
|
140
140
|
there's nothing prior to commit.)
|
|
141
141
|
|
|
142
|
-
## 3b. Sync with the tracker (only if a provider is installed)
|
|
143
|
-
|
|
144
|
-
**Only when a ticketing provider is installed** and the spec is linked to the
|
|
145
|
-
tracker. Otherwise skip this step — no provider means zero change to the flow
|
|
146
|
-
below. Follow the provider's steps below (nothing to do here without one).
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
142
|
## 4. Implement the phase
|
|
151
143
|
|
|
152
144
|
Identify the **first unfinished phase** from the `00-overview.md` phase index,
|
|
153
145
|
then open its phase file (`0N-<slug>.md`) — that file holds the tasks. Mark it
|
|
154
146
|
started: set the phase-file heading to `🔄` and its `> **Status:**` to
|
|
155
147
|
`In progress`, and flip the matching row in the overview phase index to `🔄`.
|
|
148
|
+
|
|
149
|
+
**Then sync with the tracker (only if a provider is installed).** The phase has
|
|
150
|
+
just changed state, so refresh the mirror before the build starts — that is what
|
|
151
|
+
makes the phase show as in progress *while* it is being built rather than only
|
|
152
|
+
once it is over. Without a provider this is a no-op and nothing below changes.
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
|
|
156
156
|
Then build it, following the project rules in `.claude/rules/*.md` and `CLAUDE.md`:
|
|
157
157
|
|
|
158
158
|
- Work task by task through the phase file. Make focused edits that match
|
|
@@ -175,6 +175,12 @@ Then build it, following the project rules in `.claude/rules/*.md` and `CLAUDE.m
|
|
|
175
175
|
- If new work surfaced, add it as tasks to the appropriate phase file (or add a
|
|
176
176
|
new phase file + index row) rather than doing it silently.
|
|
177
177
|
|
|
178
|
+
**Then refresh the mirror (only if a provider is installed).** The phase is done
|
|
179
|
+
in the repo now; leaving the tracker to catch up at `/spec-complete` is what makes
|
|
180
|
+
a mirror lag a whole spec behind. Without a provider this is a no-op.
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
|
|
178
184
|
## 6. Report
|
|
179
185
|
|
|
180
186
|
Summarise what was implemented, the test result (quote failures if any), and
|
|
@@ -180,6 +180,13 @@ narrative and decisions).
|
|
|
180
180
|
- Commit the fix to the `hotfix/<slug>` branch (this commit is what gets tagged
|
|
181
181
|
and cherry-picked). Tick the Fix tasks; add a Changelog line.
|
|
182
182
|
|
|
183
|
+
**Then refresh the mirror (only if a provider is installed).** The Fix tasks are
|
|
184
|
+
ticked, so the repo is now the truth about this fix — and this skill can take a
|
|
185
|
+
bug all the way to green without `/spec-go` ever running. Without a provider this
|
|
186
|
+
is a no-op.
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
|
|
183
190
|
## 7. Report
|
|
184
191
|
|
|
185
192
|
Summarise: the base tag, root cause, the failing→passing test, the fix, and the
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@skitterbyte/skitterspec",
|
|
3
|
-
"version": "16.
|
|
3
|
+
"version": "16.7.0",
|
|
4
4
|
"description": "Spec-driven development for Claude Code — a tracker-free filesystem workflow: lifecycle skills and per-spec isolation. For Linear sync, install @skitterbyte/skitterspec-linear instead.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"claude",
|
package/src/init.js
CHANGED
|
@@ -406,6 +406,11 @@ function installClaudeMd(dir, { mode }) {
|
|
|
406
406
|
|
|
407
407
|
// True when the repo looks already set up: any managed file present, any spec
|
|
408
408
|
// lifecycle folder, or the CLAUDE.md spec marker (Decision 1 — detect eagerly).
|
|
409
|
+
// Is skitterspec already installed here? Matched on what we ACTUALLY install —
|
|
410
|
+
// our managed files, our lifecycle folders, our CLAUDE.md marker — never on
|
|
411
|
+
// `.claude/` merely existing: someone else's skills are not evidence of ours,
|
|
412
|
+
// and reading them as ours would treat every Claude Code project as a
|
|
413
|
+
// half-finished install.
|
|
409
414
|
function isExistingSetup(dir) {
|
|
410
415
|
if (managedTargets(dir).some((t) => fs.existsSync(t.abs))) return true
|
|
411
416
|
if (SPEC_FOLDERS.some((f) => fs.existsSync(path.join(dir, 'specs', f)))) return true
|