instar 0.28.96 → 0.28.97
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.
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/server/routes.js +195 -3
- package/dist/server/routes.js.map +1 -1
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +47 -47
- package/upgrades/0.28.97.md +146 -0
- package/upgrades/side-effects/project-scope-phase1-7-skill-surface.md +175 -0
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
# Side-Effects Review — project-scope Phase 1.7 skill surface
|
|
2
|
+
|
|
3
|
+
**Scope.** Closes the spec § Phase 1.7 user-facing surface. Rewrites
|
|
4
|
+
`.claude/skills/instar-project/SKILL.md` to cover all twelve canonical
|
|
5
|
+
commands, adds the three small HTTP routes the spec named but hadn't
|
|
6
|
+
materialized (`run-round`, `resume`, `abandon`), and realigns
|
|
7
|
+
`skillCommandForAction()` to the canonical command names.
|
|
8
|
+
|
|
9
|
+
## What's IN this PR
|
|
10
|
+
|
|
11
|
+
1. **`.claude/skills/instar-project/SKILL.md`** — full rewrite. Phase 1a
|
|
12
|
+
placeholder language for `/project next` is removed (the connect-the-dots
|
|
13
|
+
PR shipped the structured payload; the skill now documents that contract).
|
|
14
|
+
Every command from spec § 1.7 has a section header with its backing
|
|
15
|
+
endpoint, body schema, response codes, and a one-line rendering rule.
|
|
16
|
+
Final section pins the conversational-tone rule ("never paste a curl
|
|
17
|
+
command in a user-facing reply") that Echo's CLAUDE.md enforces.
|
|
18
|
+
2. **`POST /projects/:id/run-round`** — manual round trigger. On
|
|
19
|
+
`preflight.ok`, writes `autoAdvanceAt = now` to the named round and
|
|
20
|
+
returns 200 + `scheduledAt`. The auto-advance poller (wired in the
|
|
21
|
+
connect-the-dots PR) picks it up on its next tick (≤60s) and dispatches
|
|
22
|
+
`ProjectRoundExecution.runRound()`. No child-process spawn from the
|
|
23
|
+
request handler — keeps one fire path through one lock.
|
|
24
|
+
3. **`POST /projects/:id/resume`** — clears `haltedAt`/`haltReason`,
|
|
25
|
+
schedules the round via `autoAdvanceAt = now`, transitions
|
|
26
|
+
`project.status` from `'halted'`/`'abandoned'` back to `'active'`.
|
|
27
|
+
For `status: 'failed'` rounds at the 3-attempt cap, `{force: true}`
|
|
28
|
+
is required AND the `resumeAttempts` counter resets to zero on
|
|
29
|
+
accept. Returns 409 when the round is neither halted nor failed.
|
|
30
|
+
4. **`POST /projects/:id/abandon`** — sets `project.status = 'abandoned'`,
|
|
31
|
+
strips `autoAdvanceAt` from every remaining round so the poller
|
|
32
|
+
stops considering them, leaves each child's `pipelineStage`
|
|
33
|
+
untouched. Idempotent (`alreadyAbandoned: true` on repeat).
|
|
34
|
+
Refuses 409 when any round is `in-progress` — halt first.
|
|
35
|
+
5. **`skillCommandForAction()` realignment.** The connect-the-dots PR
|
|
36
|
+
returned `/project approve` and `/project drift-check` for the
|
|
37
|
+
`await-user-approval` and `run-drift-check` action verbs. Spec § 1.7
|
|
38
|
+
uses `/project ack` and `/project drift`; the mapping is updated so
|
|
39
|
+
the dashboard hints + the `/projects/:id/next` payload + the skill
|
|
40
|
+
stay in sync.
|
|
41
|
+
6. **Tests.** `tests/unit/instar-project-skill.test.ts` (28 assertions)
|
|
42
|
+
pins the SKILL.md contract — frontmatter, every spec § 1.7 command
|
|
43
|
+
has a header, every documented endpoint exists in `routes.ts`.
|
|
44
|
+
`tests/integration/projects-api.test.ts` adds 10 cases for the new
|
|
45
|
+
routes covering happy paths + every documented error case.
|
|
46
|
+
|
|
47
|
+
## What's explicitly DEFERRED
|
|
48
|
+
|
|
49
|
+
- **`ProjectRoundRunner.resume` / `.abandon` methods.** The new
|
|
50
|
+
endpoints mutate state via `tracker.update()` directly rather than
|
|
51
|
+
routing through a runner method. The runner's value-add is the
|
|
52
|
+
`preflight()` gate; resume/abandon don't have preflight semantics
|
|
53
|
+
(they're transitions OUT of stuck states, not transitions INTO an
|
|
54
|
+
autonomous run). If a future need surfaces — e.g., resume needs to
|
|
55
|
+
hold the round-runner lock briefly, or abandon needs to release a
|
|
56
|
+
worktree — those can land as runner methods then. Today, the
|
|
57
|
+
shorter path is cleaner.
|
|
58
|
+
- **Resume worktree cleanup.** Spec § 1.5 step "Halt switch" says
|
|
59
|
+
"Worktrees retained for inspection (cleanup deferred to user
|
|
60
|
+
`/project resume` or `/project abandon`)." The new resume/abandon
|
|
61
|
+
routes do NOT prune worktrees — the autonomous child the poller
|
|
62
|
+
fires next will recreate them lazily. Worktree GC is a separate
|
|
63
|
+
follow-up (registered as a child of the spec's deferral list).
|
|
64
|
+
- **No telemetry on action verbs.** The dashboard hint
|
|
65
|
+
(`skillCommandForAction()`) is read-only suggestion; we don't yet
|
|
66
|
+
count which verbs fire most frequently. A simple counter on the
|
|
67
|
+
`/projects/:id/next` handler would surface "what's the most common
|
|
68
|
+
unblocking step?" — interesting telemetry, but not Phase 1 scope.
|
|
69
|
+
- **Skill body translation hooks.** The SKILL.md is a single file; we
|
|
70
|
+
don't (yet) split per-command bodies into separate files the agent
|
|
71
|
+
can lazy-load. At ~10KB the file is well within the context budget
|
|
72
|
+
for a `/project` invocation. If the surface keeps growing past
|
|
73
|
+
Phase 1, splitting per-command is the natural next move.
|
|
74
|
+
|
|
75
|
+
## Side-effects review
|
|
76
|
+
|
|
77
|
+
**Over-block.** All three new routes are pure tracker.update() calls
|
|
78
|
+
with OCC. No child-process spawn, no git shell-out, no LLM call.
|
|
79
|
+
P99 latency in test runs ~20ms (single tracker write + JSON encode).
|
|
80
|
+
The skill body grew from ~3.5KB to ~10KB — adds one file read per
|
|
81
|
+
`/project` invocation; well below the context-window pressure
|
|
82
|
+
threshold.
|
|
83
|
+
|
|
84
|
+
**Under-block.** `resume` does not re-run drift before scheduling.
|
|
85
|
+
The poller's preflight (which fires after the route writes
|
|
86
|
+
`autoAdvanceAt`) re-runs drift if the cached verdict is stale (>24h)
|
|
87
|
+
per spec § Phase 1.4. So drift is enforced at fire time, not at
|
|
88
|
+
resume time — same level as the original `/project run-round`. This
|
|
89
|
+
is intentional: resume is a state mutation, not a fire trigger.
|
|
90
|
+
|
|
91
|
+
**Level-of-abstraction fit.** Each new route sits at the same layer
|
|
92
|
+
as the surrounding routes:
|
|
93
|
+
- `run-round` belongs alongside `halt` and `ack` (all three are
|
|
94
|
+
user-initiated state changes that thread through the runner).
|
|
95
|
+
- `resume` and `abandon` belong alongside `accept-partial` (all
|
|
96
|
+
three close out a specific round-end condition).
|
|
97
|
+
|
|
98
|
+
The skill is the highest layer — it's the conversational shell over
|
|
99
|
+
the HTTP API. SKILL.md is markdown the agent reads on `/project`
|
|
100
|
+
invocation, not executable code; the body's instructions ARE the
|
|
101
|
+
implementation.
|
|
102
|
+
|
|
103
|
+
**Signal vs authority.** The new routes are authority paths — they
|
|
104
|
+
mutate state. None of them consult an LLM signal. `run-round` does
|
|
105
|
+
delegate to `ProjectRoundRunner.preflight()` for the deterministic
|
|
106
|
+
gate checks; that's the spec's single-chokepoint pattern, not a
|
|
107
|
+
signal/authority mix.
|
|
108
|
+
|
|
109
|
+
**Interactions.**
|
|
110
|
+
- `run-round` + `auto-advance poller`: the route writes `autoAdvanceAt`,
|
|
111
|
+
the poller reads it. The poller's `inFlight: Set<projectId>` guard
|
|
112
|
+
(shipped in connect-the-dots) ensures a manual run-round followed
|
|
113
|
+
by a poller tick doesn't double-fire.
|
|
114
|
+
- `resume` + `halt`: idempotent in either direction. `halt` writes
|
|
115
|
+
`haltedAt`; `resume` strips it. Repeat halts on an already-halted
|
|
116
|
+
round are no-ops; repeat resumes on an already-resumed round
|
|
117
|
+
return 409 ("round is not halted or failed").
|
|
118
|
+
- `abandon` + `claim-ownership`: abandon sets `project.status =
|
|
119
|
+
'abandoned'`; the auto-advance poller's owner filter already
|
|
120
|
+
excludes abandoned projects. A peer claiming ownership of an
|
|
121
|
+
abandoned project would just re-claim — the poller still skips
|
|
122
|
+
abandoned-status projects regardless of owner.
|
|
123
|
+
- `skillCommandForAction()` realignment: existing test
|
|
124
|
+
`expect(typeof res.body.skillCommand).toBe('string')` doesn't
|
|
125
|
+
assert exact strings, so the rename is backwards-compatible at
|
|
126
|
+
the test level. Dashboard consumers render the string verbatim —
|
|
127
|
+
they get `/project ack` instead of `/project approve`, which is
|
|
128
|
+
what spec § 1.7 documented.
|
|
129
|
+
|
|
130
|
+
**Rollback cost.** Three options:
|
|
131
|
+
1. **Skill-only rollback** — restore the prior SKILL.md from
|
|
132
|
+
`git show HEAD~1:.claude/skills/instar-project/SKILL.md`. Agent
|
|
133
|
+
reverts to Phase 1a read-only behavior; new HTTP routes still
|
|
134
|
+
exist but are not surfaced. Zero state risk.
|
|
135
|
+
2. **Routes-only rollback** — `git revert` the three new route
|
|
136
|
+
handlers. Skill still references them; agent surfaces 404 from
|
|
137
|
+
`/project run-round`, `/project resume`, `/project abandon`.
|
|
138
|
+
Surface-but-not-functional, but no data corruption — state
|
|
139
|
+
mutations all go through `tracker.update()` with OCC, which is
|
|
140
|
+
already proven safe.
|
|
141
|
+
3. **Full revert** — drop the whole commit. No on-disk state from
|
|
142
|
+
this PR persists (the abandon/halt/resume state fields all
|
|
143
|
+
pre-exist in the `Initiative` schema from Phase 1a).
|
|
144
|
+
|
|
145
|
+
All three are clean. The PR introduces no new persisted state, no
|
|
146
|
+
new file paths, no new background work — it adds surface area over
|
|
147
|
+
the existing state machine.
|
|
148
|
+
|
|
149
|
+
## Files touched
|
|
150
|
+
|
|
151
|
+
- `.claude/skills/instar-project/SKILL.md` (rewritten)
|
|
152
|
+
- `src/server/routes.ts` (three new route handlers + one mapping fix)
|
|
153
|
+
- `tests/integration/projects-api.test.ts` (10 new cases)
|
|
154
|
+
- `tests/unit/instar-project-skill.test.ts` (new file, 28 assertions)
|
|
155
|
+
- `upgrades/NEXT.md` (new release notes)
|
|
156
|
+
|
|
157
|
+
## Spec references
|
|
158
|
+
|
|
159
|
+
- `docs/specs/PROJECT-SCOPE-SPEC.md` § Phase 1.7 — canonical
|
|
160
|
+
command list.
|
|
161
|
+
- `docs/specs/PROJECT-SCOPE-SPEC.md` § Phase 1.5 — runner preflight
|
|
162
|
+
contract; halt/resume worktree-retention rule.
|
|
163
|
+
- `docs/specs/PROJECT-SCOPE-SPEC.md` § Phase 1.3 — HTTP layer
|
|
164
|
+
doesn't enforce gates the runner already enforces. `run-round`
|
|
165
|
+
delegates to `preflight()` cleanly.
|
|
166
|
+
|
|
167
|
+
## Coverage
|
|
168
|
+
|
|
169
|
+
- Unit: structural coverage of SKILL.md + endpoint existence —
|
|
170
|
+
`tests/unit/instar-project-skill.test.ts`.
|
|
171
|
+
- Integration: happy + error paths for all three new routes against
|
|
172
|
+
the real `AgentServer` + `InitiativeTracker` + `ProjectRoundRunner`
|
|
173
|
+
— `tests/integration/projects-api.test.ts`.
|
|
174
|
+
- Lint: clean.
|
|
175
|
+
- Type-check: clean (new `RoundStatus` import).
|