scrumrun 2.0.0 → 2.1.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.
- package/CHANGELOG.md +22 -0
- package/CORE.md +11 -1
- package/DECISIONS.md +56 -0
- package/MIGRATION-1-to-2.md +11 -0
- package/README.md +14 -4
- package/SPEC.md +25 -8
- package/bin/scrumrun.js +119 -11
- package/docs/COMMANDS.md +4 -2
- package/docs/ENTITY-MODEL.md +1 -1
- package/docs/RELEASE-SCORECARD.md +43 -0
- package/docs/RELEASE.md +19 -12
- package/docs/SCHEMA.md +9 -0
- package/docs/TROUBLESHOOTING.md +12 -0
- package/lib/commands/manifest.js +11 -2
- package/lib/commands/render.js +3 -0
- package/lib/memory/index.js +70 -11
- package/lib/runtime/budgets.js +4 -0
- package/lib/runtime/canonical-snapshot.js +110 -0
- package/lib/runtime/context.js +5 -45
- package/lib/runtime/orchestrator.js +98 -65
- package/lib/runtime/policy-engine.js +184 -0
- package/lib/runtime/request-engine.js +28 -24
- package/lib/runtime/run-ledger.js +324 -0
- package/lib/v2/artifacts.js +21 -1
- package/lib/v2/conformance.js +58 -11
- package/lib/v2/migration.js +69 -9
- package/lib/v2/run-ledger-migration.js +240 -0
- package/lib/v2/schema.js +21 -1
- package/lib/v2/transaction.js +254 -0
- package/package.json +1 -1
- package/scripts/generate-contract-docs.js +11 -0
- package/templates/project/.scrumrun/guardrails.md +8 -0
- package/templates/project/.scrumrun/map.md +4 -3
- package/templates/project/.scrumrun/method.json +4 -1
- package/templates/project/.scrumrun/state.md +7 -14
- package/templates/shared/skills/scrumrun/SKILL.md +13 -3
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,28 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes follow Semantic Versioning.
|
|
4
4
|
|
|
5
|
+
## Unreleased
|
|
6
|
+
|
|
7
|
+
## 2.1.0 - 2026-07-22
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- Canonical Run ledger schema with stable event ids, RFC3339 timestamps, actors, reasons, and typed evidence.
|
|
12
|
+
- Explicit early-v2 Run-ledger preflight/apply/rollback through `migrate --to 2` and `update --migrate`.
|
|
13
|
+
- Conformance checks that reconstruct Run state and detect event-order, evidence, timestamp, and frontmatter drift.
|
|
14
|
+
- Durable multi-file mutation journal with byte-exact rollback, interruption recovery, hash-only receipts, and explicit `doctor --recover`.
|
|
15
|
+
- Executable Policy Engine with stable Guardrail ids, explicit passed/blocked/deferred results, and deterministic conformance checks.
|
|
16
|
+
- Shared canonical projection fingerprint plus metadata-watch/content-hash freshness checks for `state.md`, `map.md`, and semantic SQLite.
|
|
17
|
+
- Evidence-backed release scorecard separating local readiness from external registry/tag gates.
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
|
|
21
|
+
- Run is now the sole operational-history authority; Task status is synchronized without duplicated transition prose.
|
|
22
|
+
- Run completion requires evidenced validation, learning, and completion transitions.
|
|
23
|
+
- Intake classification and risk detection now recognize multilingual runtime, schema, migration, transaction, release, and cross-cutting signals.
|
|
24
|
+
- Semantic cache schema 3 removes commit-only invalidation and performs a one-time disposable rebuild from older cache schemas.
|
|
25
|
+
- `map --show` now refuses missing or stale fingerprints instead of presenting an unverified projection.
|
|
26
|
+
|
|
5
27
|
## 2.0.0 - 2026-07-21
|
|
6
28
|
|
|
7
29
|
### Breaking
|
package/CORE.md
CHANGED
|
@@ -84,6 +84,8 @@ AGENTS.md
|
|
|
84
84
|
|
|
85
85
|
Canonical truth is Markdown. SQLite/cache data stores only rebuildable indexes, symbol projections, relations, and bounded context packages. Deleting `.cache/` must never delete authored truth.
|
|
86
86
|
|
|
87
|
+
`state.md` and the semantic index use two-tier freshness checks. Matching path/stat watch fingerprints avoid rereading unchanged sources; any metadata drift falls back to complete content hashing. A cache schema mismatch rebuilds the disposable index once. Watch metadata is only an optimization and never authority.
|
|
88
|
+
|
|
87
89
|
`vault.local.md`, migration backups, and caches are local-only. Their values never appear in logs, history, reviews, memory, reports, commits, or normal responses.
|
|
88
90
|
|
|
89
91
|
## Authority and read policy
|
|
@@ -146,6 +148,8 @@ Intake must:
|
|
|
146
148
|
5. recommend one route and, in guided mode, at most two useful alternatives;
|
|
147
149
|
6. ask one explicit approval question before execution; config may change presentation, never remove the gate.
|
|
148
150
|
|
|
151
|
+
Policy evaluation is structured per active `GR-NNN`: `passed`, `blocked`, or `deferred`. A block must cite the exact Guardrail id and reason code. Deferred checks must be visible in the plan and re-evaluated at their named execution boundary; they are never silently counted as passed. Invalid/duplicate Guardrails or configuration that weakens approval block conformance and intake.
|
|
152
|
+
|
|
149
153
|
Before approval, do not create canonical files, update status, edit application code, or retain request content outside ignored disposable context cache. Ambiguous acknowledgement is not approval.
|
|
150
154
|
|
|
151
155
|
## Execution lifecycle
|
|
@@ -165,7 +169,9 @@ Rules:
|
|
|
165
169
|
|
|
166
170
|
- one Run belongs to one Task;
|
|
167
171
|
- one Task may have multiple immutable attempts;
|
|
168
|
-
- every state transition writes exactly one append-only
|
|
172
|
+
- every state transition writes exactly one append-only `RUN-NNN-EVT-NNN` JSON event with RFC3339 time, actor, reason, and typed evidence;
|
|
173
|
+
- the Run ledger is operational history; Task synchronizes current status without copying the Run event;
|
|
174
|
+
- validation, learning, completion, failure, block, and resume require a reason or evidence;
|
|
169
175
|
- validation must match the risk and acceptance criteria;
|
|
170
176
|
- configured reviews run before completion;
|
|
171
177
|
- learning proposes memory candidates after validation and never auto-confirms AI inference;
|
|
@@ -174,6 +180,8 @@ Rules:
|
|
|
174
180
|
|
|
175
181
|
Canonical mutations are schema-validated, lossless, and atomic. Preserve unknown fields, prose, and unrelated owner edits. A failed mutation must leave canonical state unchanged or recoverable.
|
|
176
182
|
|
|
183
|
+
Task/Run pair mutations use an ignored durable journal under `.scrumrun/.backup/transactions/`. A captured failure rolls back immediately; an interrupted `prepared` transaction is rolled back before the next approved mutation, while an interrupted `committed` transaction is verified and finalized. Audit only reports `TRANSACTION_PENDING`. Recovery writes occur only when the approved operation is retried or `doctor --recover` is explicitly invoked, and recovery refuses to overwrite bytes that match neither side of the journal.
|
|
184
|
+
|
|
177
185
|
## Semantic memory
|
|
178
186
|
|
|
179
187
|
### Knowledge
|
|
@@ -220,6 +228,7 @@ scrumrun migrate --to 2 --rollback
|
|
|
220
228
|
```
|
|
221
229
|
|
|
222
230
|
- ordinary install/update never applies a migration; update performs a read-only v1 preflight, and only explicit `update --migrate` applies its verified plan;
|
|
231
|
+
- early v2 Run prose is also preflighted read-only and upgraded explicitly to ledger schema 1 with byte-exact backup and safe rollback;
|
|
223
232
|
- dry-run writes no project data;
|
|
224
233
|
- apply inventories source hashes, creates a byte-exact local backup, transforms in staging, validates, and activates by atomic directory swap;
|
|
225
234
|
- incomplete hybrid v1/v2 trees reuse existing evidenced canonical relations instead of creating duplicate Tasks/Runs;
|
|
@@ -283,6 +292,7 @@ Review is read-only unless fixes are separately authorized. Report findings by s
|
|
|
283
292
|
- Intake is read-only.
|
|
284
293
|
- No execution without explicit valid approval.
|
|
285
294
|
- Guardrails cannot be bypassed; they may only be superseded/retired with history.
|
|
295
|
+
- Active Guardrails produce explicit passed/blocked/deferred evaluations; blocks cite stable ids and deferred checks remain visible until their execution gate.
|
|
286
296
|
- Task is atomic; Sprint is grouping; Run is an attempt.
|
|
287
297
|
- Retries preserve prior Runs.
|
|
288
298
|
- History is append-only.
|
package/DECISIONS.md
CHANGED
|
@@ -294,3 +294,59 @@ Date: 2026-07-21
|
|
|
294
294
|
**Consequences** — Ongoing projects cannot silently miss the required migration, while automation and cautious users retain a zero-write default. Cost: update output is longer inside a v1 project and the update command must remain migration-aware.
|
|
295
295
|
|
|
296
296
|
**Alternatives considered** — Automatically applying during every update: rejected because updating client integrations is not implicit consent to rewrite project state. Keeping update unaware: safer in isolation but makes partial upgrades easy and confusing.
|
|
297
|
+
|
|
298
|
+
---
|
|
299
|
+
|
|
300
|
+
## ADR-021 — Run owns a structured append-only event ledger
|
|
301
|
+
Status: accepted
|
|
302
|
+
Date: 2026-07-22
|
|
303
|
+
|
|
304
|
+
**Context** — A prose `history.md` made operational truth expensive to parse and allowed two incompatible event formats, ambiguous same-day entries, duplicated Task/Run history, and status derived from punctuation-sensitive text.
|
|
305
|
+
|
|
306
|
+
**Decision** — Run is the sole operational-history authority. Every native Run stores schema-versioned `RUN-NNN-EVT-NNN` JSON events with RFC3339 time, actor, ordered `from`/`to`, reason, and typed evidence. Task synchronizes current status without copying event prose. Early-v2 Runs migrate explicitly: deterministic chains are recovered; ambiguity becomes an evidenced snapshot rather than an invented transition.
|
|
307
|
+
|
|
308
|
+
**Consequences** — Status reconstruction and audit are deterministic, retries preserve attempts, and agents can retrieve a bounded Run instead of rereading a global log. Cost: event/schema migrations and stricter evidence gates become release obligations.
|
|
309
|
+
|
|
310
|
+
**Alternatives considered** — Keep one append-only Markdown history with a better template: simpler storage, but still global, token-heavy, and vulnerable to parser drift. Duplicate transitions into Task: convenient locally but creates two authorities.
|
|
311
|
+
|
|
312
|
+
---
|
|
313
|
+
|
|
314
|
+
## ADR-022 — Canonical multi-file mutations use durable local transactions
|
|
315
|
+
Status: accepted
|
|
316
|
+
Date: 2026-07-22
|
|
317
|
+
|
|
318
|
+
**Context** — Approval, Run transitions, and retries update linked artifacts. Per-file atomic rename prevents partial bytes but cannot prevent a crash after only one file has committed.
|
|
319
|
+
|
|
320
|
+
**Decision** — Linked canonical mutations use an ignored durable transaction journal with prepared/committed states, byte-exact before images, content hashes, fsync-backed writes, deterministic recovery, and hash-only receipts. Prepared work rolls back; committed work is verified and finalized. Recovery refuses to overwrite owner changes made after interruption. Ordinary audit reports pending recovery but remains read-only.
|
|
321
|
+
|
|
322
|
+
**Consequences** — Task/Run pairs cannot silently diverge after an interrupted mutation. Failure injection proves rollback and recovery. Cost: more local I/O and a transaction schema that must be validated as hostile input.
|
|
323
|
+
|
|
324
|
+
**Alternatives considered** — Best-effort compensating writes: cannot distinguish interruption from later owner edits. SQLite as canonical transaction store: violates Markdown portability and creates another authority.
|
|
325
|
+
|
|
326
|
+
---
|
|
327
|
+
|
|
328
|
+
## ADR-023 — Guardrails are evaluated by an executable Policy Engine
|
|
329
|
+
Status: accepted
|
|
330
|
+
Date: 2026-07-22
|
|
331
|
+
|
|
332
|
+
**Context** — Canonical Guardrails without deterministic evaluation could be present in context yet silently ignored or described as passed. Migrated prose also makes aggressive inference unsafe.
|
|
333
|
+
|
|
334
|
+
**Decision** — Active stable-id Guardrails produce structured `passed`, `blocked`, or `deferred` evaluations. Blocks cite the exact `GR-NNN` id and reason code. Deferred checks remain visible for their mutation, migration, review, or owner boundary. Fresh rules declare enforcement explicitly; migrated prose uses conservative inference and ambiguous rules stay manual. Configuration cannot disable approval or weaken active policy.
|
|
335
|
+
|
|
336
|
+
**Consequences** — Policy advice is traceable to project authority instead of model opinion, while uncertainty stays explicit. Cost: not every project rule can be automated; manual/deferred enforcement remains a first-class result.
|
|
337
|
+
|
|
338
|
+
**Alternatives considered** — Treat every loaded rule as passed unless a keyword matches: false assurance. Block all manual rules at intake: safe but makes legitimate project-specific policy unusable.
|
|
339
|
+
|
|
340
|
+
---
|
|
341
|
+
|
|
342
|
+
## ADR-024 — Derived freshness uses metadata fast path and content-hash fallback
|
|
343
|
+
Status: accepted
|
|
344
|
+
Date: 2026-07-22
|
|
345
|
+
|
|
346
|
+
**Context** — Recomputing every artifact hash and reparsing the entire code graph before each status or semantic query makes a disposable index defeat its purpose. Trusting timestamps alone would make cache metadata an accidental authority.
|
|
347
|
+
|
|
348
|
+
**Decision** — `state.md` and semantic SQLite store a source fingerprint plus a watch fingerprint over path/stat identity. An unchanged watch avoids source reads. Any metadata drift triggers a complete canonical/source content fingerprint before staleness is asserted. Cache schemas are explicit and mismatches force one rebuild. Commit-only changes do not invalidate semantically unchanged code.
|
|
349
|
+
|
|
350
|
+
**Consequences** — Normal queries stay fast while content remains the final verifier. State and intake share one canonical fingerprint implementation. Cost: metadata-only touches may trigger one full verification, and scanner changes require a cache-schema bump.
|
|
351
|
+
|
|
352
|
+
**Alternatives considered** — Hash every source on every query: maximally simple but O(project) on the hot path. Timestamp-only cache validity: faster but allows derived metadata to masquerade as truth.
|
package/MIGRATION-1-to-2.md
CHANGED
|
@@ -32,6 +32,17 @@ npx scrumrun@latest update --migrate
|
|
|
32
32
|
|
|
33
33
|
`--migrate` is explicit consent. Ordinary update never changes canonical project data.
|
|
34
34
|
|
|
35
|
+
### Early v2 Run upgrade
|
|
36
|
+
|
|
37
|
+
Projects created by the first 2.0.0 build may contain prose-based Run transitions. The same ongoing-project commands detect this layout without writes and, after explicit `--migrate`, upgrade it to ledger schema 1:
|
|
38
|
+
|
|
39
|
+
```text
|
|
40
|
+
.scrumrun/.migration/run-ledger-v1/manifest.json
|
|
41
|
+
.scrumrun/.migration/run-ledger-v1/backup/runs/RUN-NNN.md
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Every changed Run and `method.json` is hashed and backed up byte-exactly. Proven transition chains become ordered `RUN-NNN-EVT-NNN` events. When only the recorded status is provable, migration emits one evidenced `snapshot`; it does not invent the missing path. Replay is idempotent, an interrupted apply restores prepared sources, and rollback refuses when a Run changed after migration.
|
|
45
|
+
|
|
35
46
|
## Standalone flow
|
|
36
47
|
|
|
37
48
|
```bash
|
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
ScrumRun gives an agent a small command surface and a precise project memory: what should be done, how each attempt happened, which decisions constrain the code, and why the architecture exists in its current form.
|
|
6
6
|
|
|
7
|
-
**Method target:** `2.0.0` · **Runtime:** Node.js `>=22.13.0` · **License:** MIT
|
|
7
|
+
**Package:** `2.1.0` · **Method target:** `2.0.0` · **Runtime:** Node.js `>=22.13.0` · **License:** MIT
|
|
8
8
|
|
|
9
9
|
## The model
|
|
10
10
|
|
|
@@ -71,6 +71,10 @@ EXECUTING → VALIDATING → LEARNING → COMPLETED | FAILED | BLOCKED
|
|
|
71
71
|
|
|
72
72
|
Nothing canonical is persisted before approval. Failed retries remain available as separate Runs.
|
|
73
73
|
|
|
74
|
+
Each Run contains a machine-validated event ledger. Events have stable ids such as `RUN-044-EVT-003`, RFC3339 timestamps, actors, reasons, and typed evidence for commands, tests, files, reviews, decisions, insights, and risks. Run is the only operational history; Task keeps its approved scope and synchronized current status without duplicating those events. Completion is rejected when validation or learning evidence is missing.
|
|
75
|
+
|
|
76
|
+
Linked Task/Run writes use a durable ignored transaction journal. Captured failures roll back immediately; interrupted operations are recovered byte-exactly on retry or through explicit `doctor --recover`. Read-only audit reports pending recovery and never repairs state silently.
|
|
77
|
+
|
|
74
78
|
## Semantic project memory
|
|
75
79
|
|
|
76
80
|
Canonical memory is human-readable Markdown:
|
|
@@ -90,7 +94,9 @@ The agent can answer questions such as:
|
|
|
90
94
|
|
|
91
95
|
AI extraction creates candidates only. Confirmation requires resolvable evidence. Stale and invalidated memory is labeled; rejected/deprecated/invalidated records are excluded from active truth by default.
|
|
92
96
|
|
|
93
|
-
The fast graph/search layer is `.scrumrun/.cache/semantic-index.sqlite`. It is ignored and disposable: deleting it never deletes knowledge. The current JavaScript/TypeScript adapter derives qualified symbols plus `defined_in`, `depends_on`, `used_by`, and `protected_by` relations.
|
|
97
|
+
The fast graph/search layer is `.scrumrun/.cache/semantic-index.sqlite`. It is ignored and disposable: deleting it never deletes knowledge. Unchanged queries use a metadata-only freshness check; metadata drift falls back to complete content fingerprints before rebuilding. Cache-schema upgrades force one safe disposable rebuild. The current JavaScript/TypeScript adapter derives qualified symbols plus `defined_in`, `depends_on`, `used_by`, and `protected_by` relations.
|
|
98
|
+
|
|
99
|
+
`map.md` is shown only when its source fingerprint matches the current semantic index. A fresh placeholder or stale map is rejected with an explicit rebuild instruction instead of being presented as project truth.
|
|
94
100
|
|
|
95
101
|
## Migrating an ongoing v1 project
|
|
96
102
|
|
|
@@ -114,7 +120,7 @@ npx scrumrun@latest migrate --to 2 --apply
|
|
|
114
120
|
npx scrumrun@latest migrate --to 2 --rollback
|
|
115
121
|
```
|
|
116
122
|
|
|
117
|
-
Migration uses content hashes, a byte-exact ignored backup, staging validation, an atomic directory switch, a source-to-destination report, idempotent replay, and rollback protection. It also recognizes incomplete hybrid v1/v2 trees, reuses already-linked canonical work, and normalizes only deterministic schema aliases. Legacy-only files leave the active tree but remain byte-exact in the ignored backup; vault contents remain local. Ambiguous history remains an explicit warning, and the migrator never invents a Sprint or Run.
|
|
123
|
+
Migration uses content hashes, a byte-exact ignored backup, staging validation, an atomic directory switch, a source-to-destination report, idempotent replay, and rollback protection. It also recognizes incomplete hybrid v1/v2 trees, reuses already-linked canonical work, and normalizes only deterministic schema aliases. Early v2 Run prose is preflighted and upgraded to the structured ledger by the same explicit `update --migrate` gate; ambiguous paths become evidenced snapshots instead of invented transitions. Legacy-only files leave the active tree but remain byte-exact in the ignored backup; vault contents remain local. Ambiguous history remains an explicit warning, and the migrator never invents a Sprint or Run.
|
|
118
124
|
|
|
119
125
|
After migration or an integration update, verify both installed assets and project state:
|
|
120
126
|
|
|
@@ -149,7 +155,7 @@ npx scrumrun@latest doctor codex --strict
|
|
|
149
155
|
vault.local.md # optional, ignored, never indexed
|
|
150
156
|
```
|
|
151
157
|
|
|
152
|
-
`guardrails.md` is canonical project policy. `config.md` contains preferences and cannot weaken
|
|
158
|
+
`guardrails.md` is canonical project policy. Active `GR-NNN` rules are evaluated into explicit `passed`, `blocked`, or `deferred` results; blocks identify the exact Guardrail and deferred checks stay visible for their execution-time gate. `config.md` contains preferences and cannot weaken policy. Duplicate/unknown Guardrails, disabled approval, and unsafe read-only paths fail conformance. `state.md`, `map.md`, context packages, and SQLite are generated navigation aids, never authority. `state.md` carries the same source fingerprint used by intake, an RFC3339 generation time, and a watch fingerprint for fast verified staleness checks.
|
|
153
159
|
|
|
154
160
|
## Useful commands
|
|
155
161
|
|
|
@@ -161,6 +167,9 @@ npx scrumrun@latest commands
|
|
|
161
167
|
npx scrumrun@latest sc plan intake "Fix pricing rounding"
|
|
162
168
|
npx scrumrun@latest sc plan intake --approve <token>
|
|
163
169
|
|
|
170
|
+
# verify canonical policy and all twenty executable invariants
|
|
171
|
+
npx scrumrun@latest sc review artifact --run
|
|
172
|
+
|
|
164
173
|
# memory lifecycle
|
|
165
174
|
npx scrumrun@latest sc knowledge insight --propose "Pricing stays in backend" --evidence src/pricing.ts
|
|
166
175
|
npx scrumrun@latest sc knowledge insight --confirm INS-001
|
|
@@ -181,6 +190,7 @@ The command manifest in `lib/commands/manifest.js` generates help and compatibil
|
|
|
181
190
|
| [`SPEC.md`](./SPEC.md) | Normative 2.0 state machines, invariants, and conformance rules. |
|
|
182
191
|
| [`DECISIONS.md`](./DECISIONS.md) | Architectural decisions and trade-offs. |
|
|
183
192
|
| `MIGRATION-1-to-2.md` | Upgrade, verification, rollback, and recovery guide. |
|
|
193
|
+
| [`docs/RELEASE-SCORECARD.md`](docs/RELEASE-SCORECARD.md) | Evidence-backed local readiness scores and residual release risks. |
|
|
184
194
|
|
|
185
195
|
ScrumRun remains client-independent: any agent that reads Markdown can follow `CORE.md`; Codex, Claude Code, and OpenCode integrations are accelerators.
|
|
186
196
|
|
package/SPEC.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# ScrumRun Method Specification
|
|
2
2
|
|
|
3
|
-
Version: `2.0.0` · Status:
|
|
3
|
+
Version: `2.0.0` · Status: stable
|
|
4
4
|
|
|
5
5
|
`SPEC.md` defines normative meanings and invariants. `lib/v2/schema.js` defines the machine-enforced ids, paths, statuses, transitions, structural relations, and truth ownership metadata; `lib/commands/manifest.js` defines command grammar. `CORE.md` is the operational runtime guide. Generated `docs/SCHEMA.md` must match the executable schema byte-for-byte. A conflict is a conformance failure: semantics defer to SPEC, mechanically enforced values defer to the schema, grammar defers to the command manifest, and the conflicting representation must be corrected.
|
|
6
6
|
|
|
@@ -108,6 +108,14 @@ FEAT-003
|
|
|
108
108
|
└── generated → INS-041
|
|
109
109
|
```
|
|
110
110
|
|
|
111
|
+
### 3.3 Run event ledger
|
|
112
|
+
|
|
113
|
+
A newly authored Run declares `ledger: 1` and owns exactly one append-only operational event stream under `## Events`. Event ids are stable and scoped to the Run (`RUN-044-EVT-001`, `RUN-044-EVT-002`, ...). Each JSON event records a contiguous sequence, RFC3339 timestamp, timestamp precision, actor, source and destination states, reason, and typed evidence.
|
|
114
|
+
|
|
115
|
+
Native Runs begin with `created → executing`. A migration may instead create one evidenced `snapshot` as the historical baseline when the source proves a recorded status but not its full transition path. A snapshot exposes that uncertainty and never fabricates intermediate states.
|
|
116
|
+
|
|
117
|
+
The ledger is the execution authority. Task retains approved scope and synchronized current status, but does not copy Run events. Conformance reconstructs the Run state from its ledger and rejects missing or duplicate ids, invalid ordering, time reversal, illegal transitions, frontmatter drift, missing evidence, and unevidenced completion.
|
|
118
|
+
|
|
111
119
|
## 4. State machines
|
|
112
120
|
|
|
113
121
|
Only the following transitions are valid.
|
|
@@ -192,7 +200,7 @@ Everything through `AWAITING_APPROVAL` is read-only. It may exist in process mem
|
|
|
192
200
|
|
|
193
201
|
Approval atomically creates one Task and its first Run. If either write fails, neither may remain. Project changes after planning invalidate the token. Reusing a successfully consumed token is idempotent.
|
|
194
202
|
|
|
195
|
-
Run transitions synchronously update the linked Task and append
|
|
203
|
+
Run transitions synchronously update the linked Task and append exactly one structured event to the Run ledger. Validation, learning, completion, failure, block, and resume transitions require a reason or typed evidence. Task status changes without receiving a duplicate narrative history. Multi-file mutations use a durable local transaction journal: `prepared` operations roll back byte-exactly after failure/interruption, while `committed` journals are verified and finalized. Ordinary audit is read-only and reports pending recovery; `doctor --recover` or retrying the approved mutation performs recovery explicitly. Entering `learning` may extract structured candidates from the Run, but extraction failure never blocks Run progress.
|
|
196
204
|
|
|
197
205
|
## 6. Policy and precedence
|
|
198
206
|
|
|
@@ -208,6 +216,10 @@ When guidance conflicts, apply this order:
|
|
|
208
216
|
|
|
209
217
|
Configuration controls preferences but cannot weaken higher levels. Missing or stale context must be surfaced, never rendered as certainty.
|
|
210
218
|
|
|
219
|
+
Every project Guardrail has a stable `GR-NNN` identity, lifecycle status, rule text, enforcement mode, and optional scope/source. Intake evaluates active Guardrails into structured `passed`, `blocked`, or `deferred` results. A block names the responsible Guardrail and machine-readable reason code; a deferred result is shown explicitly and must be enforced at the mutation, migration, review, or owner gate it names. Deferred checks do not become evidence of a pass.
|
|
220
|
+
|
|
221
|
+
The executable Policy Engine may infer enforcement for migrated prose, but fresh v2 policy declares it explicitly. Unknown enforcement, duplicate ids, inactive-only policy, configuration that disables approval, and unsafe read-only paths fail conformance. Configuration can tune presentation and workflow preferences; it cannot retire, bypass, or weaken active Guardrails.
|
|
222
|
+
|
|
211
223
|
## 7. Semantic memory and code intelligence
|
|
212
224
|
|
|
213
225
|
Memory records include subject, source, evidence, validity window, confidence where useful, review trigger, and last-verified commit. Insight types may include placement rationale, design constraint, known trade-off, failure history, usage warning, compatibility reason, business rule, performance reason, security reason, and testing note.
|
|
@@ -234,7 +246,9 @@ The agreed v1 control-context baseline is 48,000 characters. A fresh lean v2 int
|
|
|
234
246
|
|
|
235
247
|
## 8. Generated views and cache
|
|
236
248
|
|
|
237
|
-
`state.md`, `map.md`, context packages, and `.cache/semantic-index.sqlite` are non-authoritative projections. They carry source fingerprints or are treated as stale.
|
|
249
|
+
`state.md`, `map.md`, context packages, and `.cache/semantic-index.sqlite` are non-authoritative projections. They carry source fingerprints or are treated as stale. `state.md` uses the exact canonical fingerprint bound into intake, plus a projection schema, RFC3339 generation time, and a disposable watch fingerprint. SQLite stores its source and watch fingerprints with an explicit cache schema.
|
|
250
|
+
|
|
251
|
+
Freshness checks use a two-tier strategy: unchanged path/stat identity proves that no source read or reparse is needed; changed metadata triggers a complete canonical/source content fingerprint before staleness is asserted. Cache metadata may optimize verification but never supplies project truth. A cache-schema mismatch forces one disposable rebuild. Deleting `.cache/` must not remove authored knowledge, and rebuilding it from unchanged sources must yield equivalent query results.
|
|
238
252
|
|
|
239
253
|
The index must never scan or store `vault.local.md`. Source scanning is bounded, skips dependencies/build output and symlinks, and uses replaceable language adapters.
|
|
240
254
|
|
|
@@ -250,6 +264,8 @@ scrumrun migrate --to 2 --rollback
|
|
|
250
264
|
|
|
251
265
|
`npx scrumrun@latest update` performs the same read-only preflight when run inside a v1 project and leaves project data untouched. `update --migrate` is an explicit request to apply the verified plan; it is not implicit migration.
|
|
252
266
|
|
|
267
|
+
Inside an early v2 project, the same commands preflight and explicitly upgrade legacy Run prose to ledger schema 1. Deterministic transition chains are recovered; incomplete history becomes an evidenced snapshot. Apply keeps byte-exact ignored backups, verifies hashes, is idempotent, and supports rollback that refuses to erase later Run changes.
|
|
268
|
+
|
|
253
269
|
The migrator must:
|
|
254
270
|
|
|
255
271
|
- hash every source file and block;
|
|
@@ -271,7 +287,7 @@ Legacy sprint entries become Tasks. History entries become Runs only with an evi
|
|
|
271
287
|
- **I-02** Approval creates a linked Task/Run pair atomically or creates nothing.
|
|
272
288
|
- **I-03** Task is atomic work; Sprint only groups Tasks with real batch/timebox evidence.
|
|
273
289
|
- **I-04** Every retry creates a new Run and preserves earlier attempts.
|
|
274
|
-
- **I-05** Only declared state transitions are accepted and paired transitions are recoverable.
|
|
290
|
+
- **I-05** Only declared, ordered, evidenced state transitions are accepted; Run event ids are unique and paired transitions are recoverable.
|
|
275
291
|
- **I-06** `guardrails.md` is canonical project policy and configuration cannot weaken it.
|
|
276
292
|
- **I-07** Markdown is canonical; SQLite and generated views are disposable projections.
|
|
277
293
|
- **I-08** AI-created facts/insights remain candidates until explicit human confirmation.
|
|
@@ -284,7 +300,7 @@ Legacy sprint entries become Tasks. History entries become Runs only with an evi
|
|
|
284
300
|
- **I-15** Migration is explicit; dry-run and ordinary update perform no project writes.
|
|
285
301
|
- **I-16** Migration preserves hashed source coverage, backup, mapping, idempotency, and safe rollback.
|
|
286
302
|
- **I-17** Migration warnings preserve ambiguity; they never invent Sprints, Runs, approval, or truth.
|
|
287
|
-
- **I-18** Partial writes, conflicting overwrites, unsafe paths, and symlink traversal fail without corrupting canonical state.
|
|
303
|
+
- **I-18** Partial/interrupted writes, conflicting overwrites, unsafe paths, and symlink traversal fail or recover without corrupting canonical state or overwriting later owner work.
|
|
288
304
|
- **I-19** Code intelligence is derived, adapter-based, fingerprinted, and cannot silently confirm memory.
|
|
289
305
|
- **I-20** Post-validation learning proposes candidates and never blocks Task/Run completion.
|
|
290
306
|
|
|
@@ -308,8 +324,9 @@ An implementation may claim ScrumRun method 2.0.0 only when it:
|
|
|
308
324
|
2. enforces every exposed state machine and schema;
|
|
309
325
|
3. proves read-only intake and dry-run migration through full-tree fingerprints;
|
|
310
326
|
4. proves migration failure recovery, rollback safety, and vault exclusion;
|
|
311
|
-
5.
|
|
312
|
-
6.
|
|
313
|
-
7.
|
|
327
|
+
5. reconstructs every native Run status from a valid, evidenced ledger and detects tampering;
|
|
328
|
+
6. proves cache deletion/rebuild equivalence and inactive-memory filtering;
|
|
329
|
+
7. bounds context/retrieval and records benchmark budgets;
|
|
330
|
+
8. declares method `2.0.0` and requires Node.js `>=22.13.0` for the native SQLite index.
|
|
314
331
|
|
|
315
332
|
Method changes follow semantic versioning. Breaking entity, path, invariant, or state changes require a major version and a migration guide.
|
package/bin/scrumrun.js
CHANGED
|
@@ -9,14 +9,21 @@ const root = path.resolve(__dirname, "..");
|
|
|
9
9
|
const templates = path.join(root, "templates");
|
|
10
10
|
const { version } = require(path.join(root, "package.json"));
|
|
11
11
|
const { applyMigration, dryRunMigration, rollbackMigration } = require(path.join(root, "lib", "v2", "migration"));
|
|
12
|
+
const {
|
|
13
|
+
applyRunLedgerMigration,
|
|
14
|
+
planRunLedgerMigration,
|
|
15
|
+
reportRunLedgerMigration,
|
|
16
|
+
rollbackRunLedgerMigration
|
|
17
|
+
} = require(path.join(root, "lib", "v2", "run-ledger-migration"));
|
|
12
18
|
const { ARTIFACT_TYPES, ArtifactRepository } = require(path.join(root, "lib", "v2", "artifacts"));
|
|
13
19
|
const { aliases: COMMAND_ALIASES, resolveAlias, resolveRoute } = require(path.join(root, "lib", "commands", "manifest"));
|
|
14
20
|
const { renderCommandHelp, renderCompatibilityPrompt, renderRootPrompt } = require(path.join(root, "lib", "commands", "render"));
|
|
15
21
|
const { planRequest } = require(path.join(root, "lib", "runtime", "request-engine"));
|
|
16
22
|
const { approveRequest, refreshState, retryTask, transitionRun } = require(path.join(root, "lib", "runtime", "orchestrator"));
|
|
17
23
|
const { createMemory, listMemory, showMemory, transitionMemory } = require(path.join(root, "lib", "memory", "service"));
|
|
18
|
-
const { indexPath, indexStatus, queryIndex, rebuildIndex, writeMap } = require(path.join(root, "lib", "memory", "index"));
|
|
24
|
+
const { indexPath, indexStatus, mapStatus, queryIndex, rebuildIndex, writeMap } = require(path.join(root, "lib", "memory", "index"));
|
|
19
25
|
const { auditProject } = require(path.join(root, "lib", "v2", "conformance"));
|
|
26
|
+
const { recoverPendingTransactions } = require(path.join(root, "lib", "v2", "transaction"));
|
|
20
27
|
const { containsSecret } = require(path.join(root, "lib", "security", "secrets"));
|
|
21
28
|
|
|
22
29
|
const COMMANDS = ["sc"];
|
|
@@ -39,7 +46,7 @@ Usage:
|
|
|
39
46
|
scrumrun migrate --to 2 --dry-run
|
|
40
47
|
scrumrun migrate --to 2 --apply
|
|
41
48
|
scrumrun migrate --to 2 --rollback
|
|
42
|
-
scrumrun doctor [all|codex|opencode|claude] [--strict]
|
|
49
|
+
scrumrun doctor [all|codex|opencode|claude] [--strict] [--recover]
|
|
43
50
|
scrumrun uninstall [--force]
|
|
44
51
|
|
|
45
52
|
Examples:
|
|
@@ -267,7 +274,27 @@ function migrationPreflightOnUpdate({ apply = false } = {}) {
|
|
|
267
274
|
const marker = path.join(scrumDir, "method.json");
|
|
268
275
|
if (fs.existsSync(marker)) {
|
|
269
276
|
try {
|
|
270
|
-
if (JSON.parse(fs.readFileSync(marker, "utf8")).method === "2.0.0")
|
|
277
|
+
if (JSON.parse(fs.readFileSync(marker, "utf8")).method === "2.0.0") {
|
|
278
|
+
const preview = planRunLedgerMigration(process.cwd());
|
|
279
|
+
if (preview.status === "current") return { status: "already-v2" };
|
|
280
|
+
console.log("\n## Project schema migration preflight\n");
|
|
281
|
+
console.log(reportRunLedgerMigration(preview).trimEnd());
|
|
282
|
+
if (preview.status === "blocked") {
|
|
283
|
+
for (const error of preview.errors) console.error(`BLOCKED: ${error}`);
|
|
284
|
+
process.exitCode = 1;
|
|
285
|
+
return { status: "blocked" };
|
|
286
|
+
}
|
|
287
|
+
if (!apply) {
|
|
288
|
+
console.log("\nThe project remains unchanged. Apply the verified plan with: npx scrumrun@latest update --migrate");
|
|
289
|
+
return { status: "ready" };
|
|
290
|
+
}
|
|
291
|
+
const result = applyRunLedgerMigration(process.cwd());
|
|
292
|
+
refreshState(path.join(process.cwd(), ".scrumrun"));
|
|
293
|
+
console.log("\nApplied the verified ScrumRun Run ledger schema migration.");
|
|
294
|
+
console.log(`Source fingerprint: ${result.plan.fingerprint}`);
|
|
295
|
+
console.log("Rollback remains available with: npx scrumrun@latest migrate --to 2 --rollback");
|
|
296
|
+
return { status: result.status, result };
|
|
297
|
+
}
|
|
271
298
|
} catch {
|
|
272
299
|
console.error("Project migration preflight failed: .scrumrun/method.json is malformed.");
|
|
273
300
|
process.exitCode = 1;
|
|
@@ -1167,6 +1194,48 @@ function memoryOptions(args) {
|
|
|
1167
1194
|
};
|
|
1168
1195
|
}
|
|
1169
1196
|
|
|
1197
|
+
function runTransitionOptions(args) {
|
|
1198
|
+
const evidenceFlags = new Map([
|
|
1199
|
+
["--command", "command"],
|
|
1200
|
+
["--test", "test"],
|
|
1201
|
+
["--file", "file"],
|
|
1202
|
+
["--review", "review"],
|
|
1203
|
+
["--decision", "decision"],
|
|
1204
|
+
["--insight", "insight"],
|
|
1205
|
+
["--risk", "risk"]
|
|
1206
|
+
]);
|
|
1207
|
+
const referenceKinds = new Set(["file", "review", "decision", "insight"]);
|
|
1208
|
+
const evidence = [];
|
|
1209
|
+
const noteParts = [];
|
|
1210
|
+
let note = null;
|
|
1211
|
+
let actor = "agent";
|
|
1212
|
+
let occurredAt = null;
|
|
1213
|
+
for (let index = 2; index < args.length; index++) {
|
|
1214
|
+
const token = args[index];
|
|
1215
|
+
const value = args[index + 1] && !args[index + 1].startsWith("--") ? args[index + 1] : null;
|
|
1216
|
+
if (token === "--note" || token === "--actor" || token === "--at" || token === "--evidence" || evidenceFlags.has(token)) {
|
|
1217
|
+
if (!value) throw new Error(`${token} requires a value.`);
|
|
1218
|
+
index++;
|
|
1219
|
+
if (token === "--note") note = value;
|
|
1220
|
+
else if (token === "--actor") actor = value;
|
|
1221
|
+
else if (token === "--at") occurredAt = value;
|
|
1222
|
+
else if (token === "--evidence") {
|
|
1223
|
+
const separator = value.indexOf(":");
|
|
1224
|
+
const kind = separator > 0 ? value.slice(0, separator) : "note";
|
|
1225
|
+
const content = separator > 0 ? value.slice(separator + 1) : value;
|
|
1226
|
+
evidence.push(referenceKinds.has(kind) ? { kind, ref: content } : { kind, summary: content });
|
|
1227
|
+
} else {
|
|
1228
|
+
const kind = evidenceFlags.get(token);
|
|
1229
|
+
evidence.push(referenceKinds.has(kind) ? { kind, ref: value } : { kind, summary: value });
|
|
1230
|
+
}
|
|
1231
|
+
continue;
|
|
1232
|
+
}
|
|
1233
|
+
if (token.startsWith("--")) throw new Error(`Unknown Run evidence option: ${token}`);
|
|
1234
|
+
noteParts.push(token);
|
|
1235
|
+
}
|
|
1236
|
+
return { note: note || noteParts.join(" ").trim() || null, evidence, actor, occurredAt };
|
|
1237
|
+
}
|
|
1238
|
+
|
|
1170
1239
|
function printMemoryArtifact(artifact) {
|
|
1171
1240
|
if (!artifact) return false;
|
|
1172
1241
|
console.log(readIfExists(artifact.file));
|
|
@@ -1233,9 +1302,8 @@ function runSemanticContext(subject, args) {
|
|
|
1233
1302
|
return;
|
|
1234
1303
|
}
|
|
1235
1304
|
const mapFile = path.join(process.cwd(), ".scrumrun", "map.md");
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
if (status.stale) console.warn("WARNING: map.md is stale; rebuild it before relying on the view.");
|
|
1305
|
+
const status = mapStatus(process.cwd());
|
|
1306
|
+
if (status.stale) throw new Error(`Generated map.md is stale (${status.reason || status.error || "unknown reason"}); run /sc knowledge map --build.`);
|
|
1239
1307
|
console.log(fs.readFileSync(mapFile, "utf8"));
|
|
1240
1308
|
return;
|
|
1241
1309
|
}
|
|
@@ -1272,8 +1340,11 @@ function executeRootRoute(route) {
|
|
|
1272
1340
|
console.log(`State: ${plan.state}`);
|
|
1273
1341
|
console.log(`Classification: ${plan.classification.type} (${plan.classification.reason})`);
|
|
1274
1342
|
console.log(`Risk: ${plan.risk.level} — ${plan.risk.reasons.join("; ")}`);
|
|
1275
|
-
console.log(`Policy: ${plan.policy.status}`);
|
|
1343
|
+
console.log(`Policy: ${plan.policy.status} (${plan.policy.checked.length} checked; ${plan.policy.deferred.length} deferred)`);
|
|
1276
1344
|
for (const violation of plan.policy.violations) console.log(`BLOCKED: ${violation}`);
|
|
1345
|
+
for (const result of plan.policy.evaluations.filter((item) => item.status === "deferred")) {
|
|
1346
|
+
console.log(`DEFERRED: ${result.guardrail} ${result.code}: ${result.message}`);
|
|
1347
|
+
}
|
|
1277
1348
|
for (const warning of plan.context.warnings) console.log(`WARNING: ${warning}`);
|
|
1278
1349
|
if (plan.approvalToken) {
|
|
1279
1350
|
console.log(`Approval: scrumrun sc plan intake --approve ${plan.approvalToken}`);
|
|
@@ -1311,7 +1382,7 @@ function executeRootRoute(route) {
|
|
|
1311
1382
|
"--block": "blocked"
|
|
1312
1383
|
};
|
|
1313
1384
|
if (transitions[routeArgs[0]]) {
|
|
1314
|
-
const result = transitionRun(process.cwd(), routeArgs[1], transitions[routeArgs[0]],
|
|
1385
|
+
const result = transitionRun(process.cwd(), routeArgs[1], transitions[routeArgs[0]], runTransitionOptions(routeArgs));
|
|
1315
1386
|
console.log(`${result.run.id}: ${result.run.status}; ${result.task.id}: ${result.task.status}.`);
|
|
1316
1387
|
if (result.learning) {
|
|
1317
1388
|
if (result.learning.created.length) console.log(`Learning candidates: ${result.learning.created.join(", ")}.`);
|
|
@@ -1335,7 +1406,7 @@ function executeRootRoute(route) {
|
|
|
1335
1406
|
if (noun === "config" && subject === "migrate") return runMigration(routeArgs);
|
|
1336
1407
|
if (noun === "config" && subject === "doctor") {
|
|
1337
1408
|
const target = ["all", "codex", "opencode", "claude"].includes(routeArgs[0]) ? routeArgs[0] : "all";
|
|
1338
|
-
return doctor(target);
|
|
1409
|
+
return doctor(target, { strict: routeArgs.includes("--strict"), recover: routeArgs.includes("--recover") });
|
|
1339
1410
|
}
|
|
1340
1411
|
if (noun === "config" && subject === "update") {
|
|
1341
1412
|
const target = ["all", "codex", "opencode", "claude"].includes(routeArgs[0]) ? routeArgs[0] : "all";
|
|
@@ -2097,6 +2168,33 @@ function runMigration(parts) {
|
|
|
2097
2168
|
return;
|
|
2098
2169
|
}
|
|
2099
2170
|
try {
|
|
2171
|
+
const ledgerManifest = path.join(process.cwd(), ".scrumrun", ".migration", "run-ledger-v1", "manifest.json");
|
|
2172
|
+
if (v2Project() && actions[0] !== "--rollback") {
|
|
2173
|
+
if (actions[0] === "--dry-run") {
|
|
2174
|
+
const plan = planRunLedgerMigration(process.cwd());
|
|
2175
|
+
console.log(reportRunLedgerMigration(plan).trimEnd());
|
|
2176
|
+
if (plan.status === "blocked") process.exitCode = 1;
|
|
2177
|
+
} else {
|
|
2178
|
+
const result = applyRunLedgerMigration(process.cwd());
|
|
2179
|
+
if (result.status === "current") {
|
|
2180
|
+
console.log("ScrumRun project is already migrated to method 2.0.0 and the current Run ledger; no files changed.");
|
|
2181
|
+
} else {
|
|
2182
|
+
refreshState(path.join(process.cwd(), ".scrumrun"));
|
|
2183
|
+
console.log(result.output.trimEnd());
|
|
2184
|
+
console.log("Rollback remains available with: scrumrun migrate --to 2 --rollback");
|
|
2185
|
+
}
|
|
2186
|
+
}
|
|
2187
|
+
return;
|
|
2188
|
+
}
|
|
2189
|
+
if (actions[0] === "--rollback" && fs.existsSync(ledgerManifest)) {
|
|
2190
|
+
const manifest = JSON.parse(fs.readFileSync(ledgerManifest, "utf8"));
|
|
2191
|
+
if (["applied", "prepared"].includes(manifest.status)) {
|
|
2192
|
+
const result = rollbackRunLedgerMigration(process.cwd());
|
|
2193
|
+
refreshState(path.join(process.cwd(), ".scrumrun"));
|
|
2194
|
+
console.log(`Rolled back ScrumRun Run ledger migration: ${result.status}.`);
|
|
2195
|
+
return;
|
|
2196
|
+
}
|
|
2197
|
+
}
|
|
2100
2198
|
if (actions[0] === "--dry-run") {
|
|
2101
2199
|
const result = dryRunMigration(process.cwd());
|
|
2102
2200
|
console.log(result.output.trimEnd());
|
|
@@ -2125,12 +2223,22 @@ function runMigration(parts) {
|
|
|
2125
2223
|
}
|
|
2126
2224
|
}
|
|
2127
2225
|
|
|
2128
|
-
function doctor(target = "all", { compatibility = false, strict = false } = {}) {
|
|
2226
|
+
function doctor(target = "all", { compatibility = false, strict = false, recover = false } = {}) {
|
|
2129
2227
|
const home = os.homedir();
|
|
2130
2228
|
const checks = [];
|
|
2131
2229
|
const commands = compatibility ? [...COMMANDS, ...COMPATIBILITY_COMMANDS] : COMMANDS;
|
|
2132
2230
|
const skillContent = fs.readFileSync(path.join(templates, "shared", "skills", "scrumrun", "SKILL.md"), "utf8");
|
|
2133
2231
|
|
|
2232
|
+
if (recover) {
|
|
2233
|
+
const scrumDir = path.join(process.cwd(), ".scrumrun");
|
|
2234
|
+
if (!fs.existsSync(scrumDir)) throw new Error("Cannot recover transactions outside a ScrumRun project.");
|
|
2235
|
+
const recovered = recoverPendingTransactions(scrumDir);
|
|
2236
|
+
console.log(recovered.length
|
|
2237
|
+
? `recovered ${recovered.map((item) => `${item.id}:${item.action}`).join(", ")}`
|
|
2238
|
+
: "recovered no pending kernel transactions");
|
|
2239
|
+
refreshState(scrumDir);
|
|
2240
|
+
}
|
|
2241
|
+
|
|
2134
2242
|
function commandContent(command) {
|
|
2135
2243
|
return command === "sc" ? renderRootPrompt() : renderCompatibilityPrompt(command);
|
|
2136
2244
|
}
|
|
@@ -2245,7 +2353,7 @@ if (!command || command === "--help" || command === "-h") {
|
|
|
2245
2353
|
runMigration(args.slice(1));
|
|
2246
2354
|
} else if (command === "doctor") {
|
|
2247
2355
|
const target = ["all", "codex", "opencode", "claude"].includes(args[1]) ? args[1] : "all";
|
|
2248
|
-
doctor(target, { compatibility: args.includes("--compat"), strict: args.includes("--strict") });
|
|
2356
|
+
doctor(target, { compatibility: args.includes("--compat"), strict: args.includes("--strict"), recover: args.includes("--recover") });
|
|
2249
2357
|
} else if (command === "claude") {
|
|
2250
2358
|
const sub = args[1];
|
|
2251
2359
|
if (sub === "install" || sub === "update") {
|
package/docs/COMMANDS.md
CHANGED
|
@@ -16,7 +16,7 @@ Use `/sc` inside a supported AI client. The equivalent CLI form is `npx scrumrun
|
|
|
16
16
|
/sc plan task --add|--list|--show|--run|--audit|--cancel|--retry
|
|
17
17
|
/sc plan sprint --add|--list|--show|--start|--complete|--block
|
|
18
18
|
/sc plan feature --add|--list|--show|--activate|--complete
|
|
19
|
-
/sc plan run --list|--show|--validate|--learn|--complete|--resume|--fail|--block
|
|
19
|
+
/sc plan run --list|--show|--validate|--learn|--complete|--resume|--fail|--block [--note] [typed evidence flags]
|
|
20
20
|
/sc plan challenge <question>
|
|
21
21
|
```
|
|
22
22
|
|
|
@@ -59,11 +59,13 @@ Creation options include `--title`, `--content`, repeated `--evidence`, repeated
|
|
|
59
59
|
/sc config init --local|--shared|--lean|--no-agent-hint|--force
|
|
60
60
|
/sc config update [all|codex|opencode|claude] [--migrate]
|
|
61
61
|
/sc config migrate --to 2 --dry-run|--apply|--rollback
|
|
62
|
-
/sc config doctor [all|codex|opencode|claude] [--strict]
|
|
62
|
+
/sc config doctor [all|codex|opencode|claude] [--strict] [--recover]
|
|
63
63
|
/sc config uninstall --force
|
|
64
64
|
/sc config help <topic>
|
|
65
65
|
```
|
|
66
66
|
|
|
67
67
|
Top-level CLI aliases (`init`, `update`, `migrate`, `doctor`, `uninstall`, `status`) remain available for shell automation. Ordinary update runs only a read-only migration preflight; `--migrate` is explicit application consent.
|
|
68
68
|
|
|
69
|
+
Run transitions accept typed evidence through `--command`, `--test`, `--file`, `--review`, `--decision`, `--insight`, `--risk`, or generic `--evidence kind:value`. `doctor --recover` is an explicit write that resolves only safe pending kernel transactions; doctor without it remains read-only.
|
|
70
|
+
|
|
69
71
|
Run `npx scrumrun@latest commands` for grammar rendered directly from the current manifest.
|
package/docs/ENTITY-MODEL.md
CHANGED
|
@@ -35,4 +35,4 @@ Feature and Sprint provide context/grouping and do not own execution history. Re
|
|
|
35
35
|
|
|
36
36
|
## Generated projections
|
|
37
37
|
|
|
38
|
-
`state.md` summarizes active work/memory. `map.md` summarizes bounded nodes/edges. SQLite stores the complete derived graph/search index. All are fingerprinted or explicitly stale and can be rebuilt from Markdown plus source code.
|
|
38
|
+
`state.md` summarizes active work/memory. `map.md` summarizes bounded nodes/edges. SQLite stores the complete derived graph/search index. All are fingerprinted or explicitly stale and can be rebuilt from Markdown plus source code. Freshness uses a metadata watch fast path and content-hash fallback; the watch is disposable evidence, never truth.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# ScrumRun 2.1.0 Local Release Scorecard
|
|
2
|
+
|
|
3
|
+
Date: 2026-07-22
|
|
4
|
+
Package: `2.1.0`
|
|
5
|
+
Method contract: `2.0.0`
|
|
6
|
+
Scope: local implementation and package readiness; external registry/tag/release verification remains owner-gated.
|
|
7
|
+
|
|
8
|
+
## Scoring rule
|
|
9
|
+
|
|
10
|
+
A score of 9.5 or higher requires a single documented contract, machine enforcement on the critical path, adversarial/failure tests, deterministic recovery where mutation is involved, bounded performance, and an explicit residual-risk statement. Documentation alone cannot earn 9.5.
|
|
11
|
+
|
|
12
|
+
| Area | Score | Executable evidence |
|
|
13
|
+
|---|---:|---|
|
|
14
|
+
| Conceptual model | 9.7 | Frozen Feature → Task → Sprint → Run → Memory schema; Task/Sprint and retry invariants; ADR-015 and ADR-018. |
|
|
15
|
+
| Documentation architecture | 9.7 | SPEC is normative, CORE is operational, ADRs explain trade-offs, generated SCHEMA is drift-checked, README/skill/templates are conformance-tested. |
|
|
16
|
+
| Artifact kernel | 9.7 | One executable schema, safe-path checks, lossless frontmatter transitions, conflict refusal, fsync atomic writes, and durable multi-file transactions with failure injection. |
|
|
17
|
+
| Run history and audit | 9.8 | Stable ordered event ids, RFC3339 timestamps, typed evidence, state reconstruction, completion gates, retry preservation, explicit early-v2 migration, and byte-exact rollback. |
|
|
18
|
+
| Real conformance | 9.7 | Twenty normative invariants point to executable tests; clean-project audit, malformed artifacts, secrets, symlinks, migration interruption, transaction interruption, and cache corruption are exercised. |
|
|
19
|
+
| Local state and retrieval | 9.6 | Intake/state share one canonical fingerprint; state/map/SQLite expose staleness; metadata fast path falls back to full content hashes; cache schema mismatch rebuilds once; stale map display is refused. |
|
|
20
|
+
| Overall operation | 9.6 | Read-only intake, explicit approval, atomic Task/Run creation, Policy Engine ids, migration preflight/apply/rollback, package E2E, installed-asset doctor, Node 22/24/26 CI definition, and release budgets. |
|
|
21
|
+
|
|
22
|
+
Minimum local score: **9.6/10**.
|
|
23
|
+
|
|
24
|
+
## Release evidence
|
|
25
|
+
|
|
26
|
+
- Full suite: `npm test`.
|
|
27
|
+
- Performance suite: `npm run benchmark`.
|
|
28
|
+
- Contract drift: `scripts/generate-contract-docs.js --check` runs before tests.
|
|
29
|
+
- Project conformance: `/sc review artifact --run`, twenty invariants, zero findings at the release checkpoint.
|
|
30
|
+
- Installed integration: `doctor codex --strict`, exact prompt/skill hashes and zero project findings.
|
|
31
|
+
- Package boundary: `npm pack --dry-run --json`, explicit file inventory, no repository-local `.scrumrun/`, tests, vault, backup, migration state, or cache.
|
|
32
|
+
- Tarball E2E: install, v2 memory, ongoing v1 migration, rollback, doctor, and uninstall run from the packed package in the test suite.
|
|
33
|
+
|
|
34
|
+
The exact final tarball checksum belongs in the owner-gated release Review/Run after all included files are frozen; embedding a tarball's own checksum inside an included document would change that checksum.
|
|
35
|
+
|
|
36
|
+
## Residual risks and gates
|
|
37
|
+
|
|
38
|
+
- Registry smoke, npm dist-tags, `v2.1.0` tag, push, and GitHub release are not proven by local tests and require explicit owner authorization.
|
|
39
|
+
- The built-in code-intelligence adapter currently covers JavaScript/TypeScript; other languages require replaceable adapters.
|
|
40
|
+
- Remote Node 22/24/26 CI must pass on the release commit even though the same matrix is declared locally in `.github/workflows/ci.yml`.
|
|
41
|
+
- Semantic retrieval is intentionally lexical/structural rather than a probabilistic embedding system; confirmed Markdown evidence remains the authority.
|
|
42
|
+
|
|
43
|
+
These are bounded release or extension risks, not hidden correctness claims. A failed external gate stops promotion and results in a new immutable SemVer; it never rewrites an existing npm version.
|