@seanyao/roll 4.630.2 → 4.702.2

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.
Files changed (108) hide show
  1. package/CHANGELOG.md +64 -0
  2. package/README.md +65 -56
  3. package/conventions/global/AGENTS.md +8 -7
  4. package/dist/roll.mjs +12909 -8532
  5. package/docs/INDEX.md +32 -0
  6. package/docs/architecture.md +444 -0
  7. package/docs/difftest-freeze-paradigm.md +113 -0
  8. package/docs/live-console.md +203 -0
  9. package/docs/manifesto.md +65 -0
  10. package/docs/migration/role-taxonomy-v4.md +60 -0
  11. package/docs/verification.md +83 -0
  12. package/guide/INDEX.md +86 -0
  13. package/guide/assets/layouts/cards-2.png +0 -0
  14. package/guide/assets/layouts/cards-3.png +0 -0
  15. package/guide/assets/layouts/cards-4.png +0 -0
  16. package/guide/assets/layouts/compare.png +0 -0
  17. package/guide/assets/layouts/highlight.png +0 -0
  18. package/guide/assets/layouts/pipeline.png +0 -0
  19. package/guide/assets/layouts/plain.png +0 -0
  20. package/guide/assets/layouts/quote.png +0 -0
  21. package/guide/assets/layouts/timeline.png +0 -0
  22. package/guide/en/acceptance-evidence.md +231 -0
  23. package/guide/en/ai-agents.md +185 -0
  24. package/guide/en/backlog-github-sync.md +108 -0
  25. package/guide/en/changelog.md +66 -0
  26. package/guide/en/configuration.md +112 -0
  27. package/guide/en/consistency.md +58 -0
  28. package/guide/en/conventions.md +113 -0
  29. package/guide/en/dream.md +121 -0
  30. package/guide/en/faq.md +855 -0
  31. package/guide/en/feedback.md +31 -0
  32. package/guide/en/getting-started.md +103 -0
  33. package/guide/en/installation.md +86 -0
  34. package/guide/en/legacy-onboarding.md +195 -0
  35. package/guide/en/loop-data-layout.md +256 -0
  36. package/guide/en/loop-driven-architecture.md +186 -0
  37. package/guide/en/loop.md +1324 -0
  38. package/guide/en/methodology.md +715 -0
  39. package/guide/en/migration-2.0.md +154 -0
  40. package/guide/en/overview.md +190 -0
  41. package/guide/en/pairing.md +151 -0
  42. package/guide/en/patterns/README.md +76 -0
  43. package/guide/en/patterns/graft-pattern.md +110 -0
  44. package/guide/en/patterns/replant-pattern.md +114 -0
  45. package/guide/en/patterns/seed-pattern.md +132 -0
  46. package/guide/en/peer.md +71 -0
  47. package/guide/en/pr-review.md +62 -0
  48. package/guide/en/practices/engineering-common-sense.md +395 -0
  49. package/guide/en/pricing.md +116 -0
  50. package/guide/en/project-setup.md +126 -0
  51. package/guide/en/roll-doc-audit.md +98 -0
  52. package/guide/en/skills.md +206 -0
  53. package/guide/en/test-isolation.md +51 -0
  54. package/guide/en/testing/quality-rubric.md +340 -0
  55. package/guide/en/testing.md +123 -0
  56. package/guide/en/tools.md +173 -0
  57. package/guide/skills.md +30 -0
  58. package/guide/zh/acceptance-evidence.md +194 -0
  59. package/guide/zh/ai-agents.md +170 -0
  60. package/guide/zh/backlog-github-sync.md +105 -0
  61. package/guide/zh/changelog.md +57 -0
  62. package/guide/zh/configuration.md +99 -0
  63. package/guide/zh/consistency.md +48 -0
  64. package/guide/zh/conventions.md +96 -0
  65. package/guide/zh/dream.md +97 -0
  66. package/guide/zh/faq.md +773 -0
  67. package/guide/zh/feedback.md +30 -0
  68. package/guide/zh/getting-started.md +96 -0
  69. package/guide/zh/installation.md +83 -0
  70. package/guide/zh/legacy-onboarding.md +192 -0
  71. package/guide/zh/loop-data-layout.md +236 -0
  72. package/guide/zh/loop-driven-architecture.md +186 -0
  73. package/guide/zh/loop.md +1124 -0
  74. package/guide/zh/methodology.md +702 -0
  75. package/guide/zh/migration-2.0.md +154 -0
  76. package/guide/zh/overview.md +186 -0
  77. package/guide/zh/pairing.md +117 -0
  78. package/guide/zh/patterns/README.md +74 -0
  79. package/guide/zh/patterns/graft-pattern.md +108 -0
  80. package/guide/zh/patterns/replant-pattern.md +112 -0
  81. package/guide/zh/patterns/seed-pattern.md +130 -0
  82. package/guide/zh/peer.md +63 -0
  83. package/guide/zh/pr-review.md +54 -0
  84. package/guide/zh/practices/engineering-common-sense.md +393 -0
  85. package/guide/zh/pricing.md +97 -0
  86. package/guide/zh/project-setup.md +114 -0
  87. package/guide/zh/roll-doc-audit.md +90 -0
  88. package/guide/zh/skills.md +191 -0
  89. package/guide/zh/test-isolation.md +46 -0
  90. package/guide/zh/testing/quality-rubric.md +284 -0
  91. package/guide/zh/testing.md +116 -0
  92. package/guide/zh/tools.md +173 -0
  93. package/package.json +4 -1
  94. package/skills/README.md +1 -0
  95. package/skills/roll-.qa/SKILL.md +1 -1
  96. package/skills/roll-.review/SKILL.md +1 -1
  97. package/skills/roll-build/SKILL.md +1 -1
  98. package/skills/roll-build/references/full-contract.md +16 -13
  99. package/skills/roll-design/SKILL.md +3 -3
  100. package/skills/roll-design/references/full-contract.md +17 -13
  101. package/skills/roll-fix/SKILL.md +1 -1
  102. package/skills/roll-fix/references/full-contract.md +13 -10
  103. package/skills/roll-peer/SKILL.md +1 -1
  104. package/skills/roll-prime/SKILL.md +77 -0
  105. package/skills/roll-prime/references/explorer-annex.md +39 -0
  106. package/skills/roll-prime/references/supervisor-prompt.md +165 -0
  107. package/skills/route-cases/skills.json +10 -0
  108. package/template/AGENTS.md +3 -1
@@ -0,0 +1,395 @@
1
+ # Roll Engineering Common Sense Checklist
2
+
3
+ > **These are not best practices — they are baseline requirements.** Violations are Bugs.
4
+
5
+ ## 1. Idempotency 🔁
6
+
7
+ **Definition:** Executing the same operation N times produces the same result as executing it once.
8
+
9
+ **Must test:**
10
+ ```typescript
11
+ it('should be idempotent', async () => {
12
+ await operation(data) // 1st
13
+ const result1 = await getState()
14
+
15
+ await operation(data) // 2nd
16
+ const result2 = await getState()
17
+
18
+ await operation(data) // 3rd
19
+ const result3 = await getState()
20
+
21
+ expect(result1).toEqual(result2)
22
+ expect(result2).toEqual(result3)
23
+ })
24
+ ```
25
+
26
+ **Common scenarios:**
27
+ - [ ] Import/ingest operations
28
+ - [ ] Configuration updates
29
+ - [ ] State changes
30
+ - [ ] API calls
31
+ - [ ] File writes
32
+
33
+ **Anti-pattern (this time):** Running ingest repeatedly -> files duplicated 7 times
34
+
35
+ ---
36
+
37
+ ## 2. Cross-Module Contract Consistency 🔗
38
+
39
+ **Definition:** Data/IDs/formats shared across multiple modules must be exactly consistent.
40
+
41
+ **Must check:**
42
+ ```typescript
43
+ // Checklist
44
+ - [ ] Is the ID generation algorithm consistent?
45
+ - [ ] Is the data serialization format consistent?
46
+ - [ ] Is path handling consistent? (e.g., / vs -)
47
+ - [ ] Has it been extracted into a shared function/constant?
48
+ ```
49
+
50
+ **Test template:**
51
+ ```typescript
52
+ it('should generate same ID across modules', () => {
53
+ const scannerId = generateScannerId('articles/test.md')
54
+ const inboxId = generateInboxId('articles/test.md')
55
+ expect(scannerId).toEqual(inboxId)
56
+ })
57
+ ```
58
+
59
+ **Anti-pattern (this time):** Scanner used `-` to replace `/`, inbox used raw path -> deduplication failed
60
+
61
+ ---
62
+
63
+ ## 3. Data Flow Integrity 🌊
64
+
65
+ **Definition:** The complete pipeline from producer to consumer must be connected end-to-end.
66
+
67
+ **Must verify:**
68
+ ```typescript
69
+ // Integration test - must exist
70
+ describe('Data Flow: Producer -> Consumer', () => {
71
+ it('should write data that consumer can read', async () => {
72
+ await producer.write(testData)
73
+ const result = await consumer.read()
74
+ expect(result).toEqual(testData)
75
+ })
76
+ })
77
+ ```
78
+
79
+ **Checklist:**
80
+ - [ ] Who writes the data? (Producer)
81
+ - [ ] Who reads the data? (Consumer)
82
+ - [ ] What is the intermediate storage? (state/file/cache)
83
+ - [ ] Is there an integration test to verify?
84
+
85
+ **Anti-pattern (this time):** Ingest didn't write state, status couldn't read it -> showed 0
86
+
87
+ ---
88
+
89
+ ## 4. Atomicity ⚛️
90
+
91
+ **Definition:** An operation either fully succeeds or does not execute at all (no intermediate state).
92
+
93
+ **Must consider:**
94
+ - [ ] How to roll back on partial failure?
95
+ - [ ] Is there a transaction mechanism?
96
+ - [ ] How is data consistency guaranteed after a crash?
97
+
98
+ **Test template:**
99
+ ```typescript
100
+ it('should be atomic', async () => {
101
+ try {
102
+ await operation([item1, item2, INVALID_ITEM, item4])
103
+ } catch (e) {
104
+ // After failure, processed items should be rolled back
105
+ const state = await getState()
106
+ expect(state).toEqual(initialState)
107
+ }
108
+ })
109
+ ```
110
+
111
+ ---
112
+
113
+ ## 5. Input Validation 🛡️
114
+
115
+ **Definition:** Never trust any external input — it must be validated.
116
+
117
+ **Must check:**
118
+ - [ ] Null/undefined handling
119
+ - [ ] Type checking
120
+ - [ ] Range checking (array length, numeric range)
121
+ - [ ] Special character/injection attack protection
122
+ - [ ] File path traversal protection
123
+
124
+ **Test template:**
125
+ ```typescript
126
+ it('should handle invalid inputs gracefully', async () => {
127
+ await expect(operation(null)).rejects.toThrow()
128
+ await expect(operation('')).rejects.toThrow()
129
+ await expect(operation({})).rejects.toThrow()
130
+ })
131
+ ```
132
+
133
+ ---
134
+
135
+ ## 6. Graceful Degradation 🪂
136
+
137
+ **Definition:** When a dependency fails, the system should still provide limited functionality.
138
+
139
+ **Must consider:**
140
+ - [ ] What if an external API fails?
141
+ - [ ] What if the database connection drops?
142
+ - [ ] Is there a fallback mechanism?
143
+ - [ ] What feedback does the user get?
144
+
145
+ **Test template:**
146
+ ```typescript
147
+ it('should degrade gracefully when dependency fails', async () => {
148
+ mockDependency.toThrow('Network error')
149
+
150
+ // Should not crash
151
+ const result = await operation()
152
+
153
+ // Should return fallback value or partial result
154
+ expect(result).toEqual(fallbackValue)
155
+ })
156
+ ```
157
+
158
+ ---
159
+
160
+ ## 7. Observability 👁️
161
+
162
+ **Definition:** System state must be visible and traceable.
163
+
164
+ **Must provide:**
165
+ - [ ] Progress feedback (for long-running operations)
166
+ - [ ] Status query interface (e.g., status command)
167
+ - [ ] Error logs (failure reasons)
168
+ - [ ] Key metrics (counts, durations)
169
+
170
+ **Improvements this time:**
171
+ - Added `kkb status` showing raw files statistics ✅
172
+ - Added `kkb compile` progress feedback ✅
173
+
174
+ ---
175
+
176
+ ## 8. Concurrency Safety 🧵
177
+
178
+ **Definition:** Shared resource access across multiple threads/processes must be safe.
179
+
180
+ **Must consider:**
181
+ - [ ] File read/write conflicts
182
+ - [ ] Database transaction isolation levels
183
+ - [ ] Locking for shared in-memory state
184
+ - [ ] Race conditions
185
+
186
+ **Test template:**
187
+ ```typescript
188
+ it('should handle concurrent writes', async () => {
189
+ await Promise.all([
190
+ operation(data1),
191
+ operation(data2),
192
+ operation(data3)
193
+ ])
194
+
195
+ // Verify final state consistency
196
+ const state = await getState()
197
+ expect(state).toBeValid()
198
+ })
199
+ ```
200
+
201
+ ---
202
+
203
+ ## Mandatory Check Process
204
+
205
+ At the **Test Design Review** phase of each Story, the following must be answered:
206
+
207
+ ```markdown
208
+ ### Engineering Common Sense Checklist
209
+ - [ ] **Idempotency**: Can it be run repeatedly? Are there tests?
210
+ - [ ] **Cross-Module Contract**: Are IDs/formats/algorithms consistent?
211
+ - [ ] **Data Flow**: Is the producer -> consumer pipeline complete?
212
+ - [ ] **Atomicity**: Will partial failures roll back?
213
+ - [ ] **Input Validation**: Are all inputs validated?
214
+ - [ ] **Graceful Degradation**: What happens when a dependency fails?
215
+ - [ ] **Observability**: Can the user see progress/status?
216
+ - [ ] **Concurrency Safety**: Is multi-threaded access safe?
217
+
218
+ **If any item is not met, tests/design must be added before writing implementation code.**
219
+ ```
220
+
221
+ ---
222
+
223
+ ## 9. Shell Script Performance 🐚
224
+
225
+ **Definition:** `$()` command substitution forks a subshell. In hot paths (functions called per-test, per-catalog-entry, or per-message-lookup) this is the dominant cost.
226
+
227
+ **Rule of thumb:**
228
+ - 1 subshell fork ≈ 2–3 ms on Linux
229
+ - 1000 forks in a test suite setup = +2–3 s per test run
230
+ - 1739 tests × 2.3 s = **~67 minutes of wasted CI time** (observed in this repo)
231
+
232
+ **Must avoid in hot paths:**
233
+ ```bash
234
+ # ❌ Subshell fork — slow when called thousands of times
235
+ upper="$(echo "$lang" | tr '[:lower:]' '[:upper:]')"
236
+ upper="$(_some_helper_function "$lang")"
237
+ safe="$(_sanitize_key "$key")"
238
+
239
+ # ✅ Inline equivalents — zero fork
240
+ case "$lang" in
241
+ en|EN) upper=EN ;;
242
+ zh|ZH) upper=ZH ;;
243
+ *) upper="$(printf '%s' "$lang" | tr '[:lower:]' '[:upper:]')" ;; # rare path OK
244
+ esac
245
+ safe="${key//[^A-Za-z0-9_]/_}" # parameter expansion, no fork
246
+ printf -v "$varname" '%s' "$val" # printf -v instead of subshell assignment
247
+ ```
248
+
249
+ **Compatibility trap — the "fixed twice" anti-pattern:**
250
+ ```
251
+ PR #211: fixed $(echo | tr) → ${lang^^} ✅ fast, but bash 4+ only
252
+ PR #213: fixed bash 3.2 compat → $(_helper) ❌ reintroduced the subshell
253
+ PR #218: fixed both → inline case ✅ fast + bash 3.2 safe
254
+ ```
255
+ When fixing for compatibility, verify the fix does not reintroduce the original problem.
256
+ Add a timing assertion or benchmark test to guard the regression.
257
+
258
+ **Dead code from inlining:**
259
+ When inlining a helper function's logic, remove the original function and grep for all callers.
260
+ A leftover function with zero callers misleads future contributors into calling it via `$()`
261
+ and reintroducing the fork.
262
+
263
+ **Must check:**
264
+ - [ ] Is this function called inside a loop, setup(), or per-entry catalog loading?
265
+ - [ ] Does it use `$()` anywhere? Can it be replaced with `case`, `${var//...}`, or `printf -v`?
266
+ - [ ] After inlining, is the original helper now dead code? Remove it.
267
+ - [ ] Is there a timing test or CI cap to catch regressions? (see `ROLL_TEST_TIME_CAP`)
268
+
269
+ ---
270
+
271
+ ## 10. Shell Resource Cleanup 🧹
272
+
273
+ **Definition:** Every `trap` set must be explicitly reset. Temporary files and lock files must never outlive their owning process.
274
+
275
+ **trap - EXIT pattern:**
276
+ ```bash
277
+ # ❌ Dangling trap — EXIT handler persists in the calling shell after return
278
+ local tmp; tmp=$(mktemp)
279
+ trap "rm -f '$tmp'" EXIT
280
+ # ... do work ...
281
+ mv "$tmp" "$dst"
282
+ return 0 # EXIT trap still armed — any later exit fires rm on a stale path
283
+
284
+ # ✅ Always reset after use
285
+ local tmp; tmp=$(mktemp)
286
+ trap "rm -f '$tmp'" EXIT
287
+ # ... do work ...
288
+ mv "$tmp" "$dst" 2>/dev/null || rm -f "$tmp"
289
+ trap - EXIT # disarm before return
290
+ return 0
291
+ ```
292
+
293
+ **Directory scope in cleanup helpers:**
294
+ ```bash
295
+ # ❌ Wrong — scans the env-var default, not the actual path in use
296
+ _cleanup_tmp() {
297
+ local dir; dir=$(dirname "${MY_PATH:-$HOME/.default/path}")
298
+ ...
299
+ }
300
+ _do_work() {
301
+ local custom_path="$1" # may differ from MY_PATH
302
+ _cleanup_tmp # scans wrong directory!
303
+ }
304
+
305
+ # ✅ Pass the actual directory explicitly
306
+ _cleanup_tmp() {
307
+ local dir="${1:-$(dirname "${MY_PATH:-$HOME/.default/path}")}"
308
+ ...
309
+ }
310
+ _do_work() {
311
+ local custom_path="$1"
312
+ _cleanup_tmp "$(dirname "$custom_path")"
313
+ }
314
+ ```
315
+
316
+ **Must check:**
317
+ - [ ] Every `trap "…" EXIT` has a matching `trap - EXIT` before the function returns.
318
+ - [ ] Cleanup helpers accept the target directory as an argument — no implicit env-var path.
319
+ - [ ] Temporary file names are quoted in trap strings: `"rm -f '$tmp'"` not `"rm -f $tmp"`.
320
+
321
+ ---
322
+
323
+ ## 11. Test Reliability 🧪
324
+
325
+ **Definition:** Tests must not rely on environmental assumptions that can silently fail on different hosts.
326
+
327
+ **PID assumptions:**
328
+ ```bash
329
+ # ❌ Assumes pid_max ≤ 99999 — fails silently in containers with large pid_max
330
+ local stale_tmp="runs.jsonl.tmp.99999"
331
+
332
+ # ✅ Use a process that is provably dead
333
+ bash -c 'exit 0' &
334
+ local dead_pid=$!
335
+ wait "$dead_pid" 2>/dev/null || true
336
+ local stale_tmp="runs.jsonl.tmp.${dead_pid}"
337
+ ```
338
+
339
+ **Heredoc scope:**
340
+ Functions defined outside a heredoc are not available inside it when the generated
341
+ script executes. Calling them silently no-ops (if guarded with `|| true`) or crashes.
342
+ ```bash
343
+ # ❌ _some_helper is not defined in the generated script's scope
344
+ cat > script.sh <<'EOF'
345
+ _some_helper 2>/dev/null || true # silent no-op — always "succeeds"
346
+ EOF
347
+
348
+ # ✅ Either inline the logic, or define the function inside the heredoc
349
+ ```
350
+
351
+ **Must check:**
352
+ - [ ] Does the test use a hardcoded PID, port, or path that may conflict on the host?
353
+ - [ ] Does the test call a function that is only defined in the outer shell, not inside a heredoc?
354
+ - [ ] Is the "dead process" check using an actual exited process, not a guessed PID?
355
+
356
+ ---
357
+
358
+ ## Automated Safeguards
359
+
360
+ ### CI Gate Rules
361
+ ```yaml
362
+ # .github/roll-checks.yml — enforced as a CI gate on every PR
363
+ checks:
364
+ idempotency:
365
+ - pattern: "ingest|import|sync"
366
+ require_test: "idempotency"
367
+
368
+ cross_module_contract:
369
+ - files: ["src/*/index.ts"]
370
+ check: "shared_id_generation"
371
+
372
+ data_flow:
373
+ - require_integration_test: true
374
+ ```
375
+
376
+ These run as CI gates on every PR. Slower-burn issues — dead code, doc staleness,
377
+ structural drift — are caught by `roll-.dream`, the nightly code-health scan that
378
+ files `REFACTOR-XXX` entries back into the backlog.
379
+
380
+ ### Pre-Commit Hook
381
+ ```bash
382
+ #!/bin/bash
383
+ # .git/hooks/pre-commit
384
+ echo "🔍 Checking engineering common sense..."
385
+
386
+ # Check idempotency tests
387
+ if git diff --cached --name-only | grep -q "ingest\|import\|sync"; then
388
+ if ! grep -r "idempotency\|repeated run\|multiple times" tests/ 2>/dev/null; then
389
+ echo "❌ Missing idempotency tests!"
390
+ exit 1
391
+ fi
392
+ fi
393
+
394
+ echo "✅ Basic checks passed"
395
+ ```
@@ -0,0 +1,116 @@
1
+ # Pricing — Cost Visibility & Price Snapshots
2
+
3
+ Roll computes per-cycle costs at **public per-token pricing** — not your
4
+ subscription rate, but a comparable number you can track across projects and
5
+ agents. This doc covers the `roll config prices` command, snapshot mechanism, and
6
+ how historical costs survive price changes.
7
+
8
+ ## Where Costs Appear
9
+
10
+ The dashboard (`roll loop status`) shows two cost-related columns per cycle:
11
+
12
+ | Column | What it means |
13
+ |--------|---------------|
14
+ | **model** | Agent + version used (e.g. `deepseek-v4-pro`, `claude-sonnet-4-6`). Drives which price rates apply. |
15
+ | **cost** | Cost computed at public per-token rates × token usage. Currency follows the vendor: `$` for Anthropic (USD), `¥` for DeepSeek and Kimi (CNY). |
16
+
17
+ Roll uses **price snapshots** (not hardcoded constants) to look up rates.
18
+ Snapshots live in `lib/prices/` under your Roll install directory.
19
+
20
+ ## Supported Vendors
21
+
22
+ | Vendor | Currency | Source |
23
+ |--------|----------|--------|
24
+ | Anthropic (Claude) | USD | `platform.claude.com/docs/en/about-claude/pricing` |
25
+ | DeepSeek | CNY | `api-docs.deepseek.com/zh-cn/quick_start/pricing/` |
26
+ | Kimi (Moonshot) | CNY | `platform.kimi.com/docs/pricing/chat` |
27
+
28
+ ## `roll config prices` Command
29
+
30
+ ```bash
31
+ roll config prices show # Print the current price table (all vendors)
32
+ roll config prices refresh # Fetch official pricing docs for all vendors, diff, write if changed
33
+ ```
34
+
35
+ ### `roll config prices show`
36
+
37
+ Prints the active snapshots' metadata and a table of all known models with
38
+ their per-million-token rates:
39
+
40
+ ```
41
+ in Base input tokens
42
+ out Output tokens
43
+ cw Cache write tokens (billed at a premium over input)
44
+ cr Cache read tokens (billed at a deep discount)
45
+ ```
46
+
47
+ Rates are **per million tokens**, in the vendor's native currency.
48
+
49
+ ### `roll config prices refresh`
50
+
51
+ Fetches the official pricing page from each vendor, parses the rate table,
52
+ and diffs it against the latest local snapshot. Supports per-vendor refresh:
53
+ `roll config prices refresh anthropic|deepseek|kimi`.
54
+
55
+ - **Rates changed** → writes a new snapshot file (`snapshot-YYYY-MM-DD.json`),
56
+ prints a diff (red = removed, green = added), and the dashboard picks up the
57
+ new rates on the next render.
58
+ - **No change** → prints `up to date` and exits.
59
+
60
+ If the network is down or the page can't be parsed, the command exits with an
61
+ error message — **existing snapshots are never overwritten by a failed fetch**.
62
+
63
+ ## Price Snapshots
64
+
65
+ Each snapshot is a JSON file in `lib/prices/` named by date:
66
+
67
+ ```
68
+ lib/prices/
69
+ snapshot-2026-05-22.json
70
+ snapshot-2026-06-01.json ← written by refresh when rates changed
71
+ ```
72
+
73
+ A snapshot contains:
74
+
75
+ | Field | Description |
76
+ |-------|-------------|
77
+ | `version` | ISO 8601 timestamp of when the snapshot was created |
78
+ | `effective_at` | Date the vendor started charging these rates |
79
+ | `source_url` | URL of the official pricing page used |
80
+ | `prices` | Dict of `model → {in, out, cache_create, cache_read}` rates per million tokens |
81
+
82
+ Snapshots are **never deleted** — every version is kept so you can audit which
83
+ rate table applied at any point in time.
84
+
85
+ ## History Cost Solidification
86
+
87
+ When a loop cycle finishes, Roll writes **two extra fields** into the usage
88
+ event:
89
+
90
+ | Field | Purpose |
91
+ |-------|---------|
92
+ | `cost_list_usd` | The cost at that moment's prices — frozen forever |
93
+ | `prices_version` | Which snapshot version was used to compute it |
94
+
95
+ The dashboard reads `cost_list_usd` first when rendering historical cycles.
96
+ If the field is missing (cycles from before this feature shipped), it falls
97
+ back to computing with the *current* snapshot and appends a dim `[legacy]`
98
+ marker.
99
+
100
+ **Net effect:** vendor price changes, `roll config prices refresh`, and Roll upgrades
101
+ never rewrite historical cycle costs. "What you actually spent" is a fact —
102
+ it stays put.
103
+
104
+ ## FAQ
105
+
106
+ **Q: Does the cost column reflect my actual bill?**
107
+ No. It uses public per-token rates. If you're on a subscription (Claude Pro,
108
+ Team, etc.) your real cost is lower. Think of it as a comparable number.
109
+
110
+ **Q: What happens when prices change?**
111
+ Run `roll config prices refresh`. If rates changed, a new snapshot is written and new
112
+ cycles use it. Old cycles keep their frozen `cost_list_usd`.
113
+
114
+ **Q: Can I add prices for a different vendor?**
115
+ Yes — `roll config prices refresh --vendor deepseek` (or `kimi`). The `--vendor` flag
116
+ tells the fetcher which vendor's pricing page to scrape.
@@ -0,0 +1,126 @@
1
+ # Roll — Project Setup
2
+
3
+ ## Initialize a Project
4
+
5
+ From your project root:
6
+
7
+ ```bash
8
+ roll init
9
+ ```
10
+
11
+ `roll init` diagnoses the current directory state before any mutation:
12
+
13
+ 1. **Empty directory** — fresh start. Roll writes `AGENTS.md` plus an empty
14
+ `.roll/` scaffold (`backlog.md`, `features/`, `domain/`) ready for scoped
15
+ agent bindings in `.roll/agents.yaml`. No prompts. This is the **seed** adoption pattern — see
16
+ [patterns/seed-pattern.md](patterns/seed-pattern.md).
17
+ 2. **PRD/docs-only** — Roll finds requirements or product docs but no source or
18
+ manifests. It treats this as a new-project path and points you to design; it
19
+ does not route to existing-codebase onboarding.
20
+ 3. **Existing codebase without Roll** — Roll detects existing source files but no
21
+ `.roll/` directory. It does **not** silently scaffold; instead it surfaces
22
+ `$roll-onboard`, an interactive skill that scans the codebase, asks a short
23
+ set of cognition / scope / privacy questions, and produces
24
+ `.roll/init-diagnosis.yaml` and `.roll/onboard-plan.yaml` for review. After
25
+ reviewing the paired artifacts, run `roll init --apply`. It prints a checkpoint listing each planned file
26
+ operation, including action, target path, merge/create mode, and owner-content
27
+ handling, then waits for confirmation in an interactive terminal. In
28
+ non-interactive automation, use `roll init --apply --auto` after that review.
29
+ This is the **graft** pattern — see
30
+ [legacy-onboarding.md](legacy-onboarding.md) and
31
+ [patterns/graft-pattern.md](patterns/graft-pattern.md).
32
+ 4. **Already initialized** — `.roll/`, `AGENTS.md`, backlog, and features are
33
+ present. Roll prints `Already initialized` and `Next: roll status`.
34
+ 5. **Partial Roll** — some Roll markers are present but the setup is incomplete.
35
+ Roll prints the missing pieces and any stale pre-v2 markers. `roll init --repair`
36
+ previews the repair and asks in an interactive terminal; non-interactive
37
+ automation must use `roll init --repair --auto`. Repair only creates missing
38
+ Roll-owned files or merges Roll-owned sections, and records the changes in
39
+ `.roll/onboard-changeset.yaml` so `roll setup offboard` can reverse them later.
40
+
41
+ After any of these paths, `roll next` is the continuation command. It reads the
42
+ same Roll markers plus `.roll/brief.md`, `.roll/onboard-plan.yaml`, and
43
+ `.roll/backlog.md`, then prints one next action: design from the brief, review
44
+ and apply an onboard plan, repair partial markers, run the old-layout migration,
45
+ start the loop on the next Todo card, or inspect status when nothing is
46
+ actionable.
47
+
48
+ Upgrading from a pre-2.0 layout (`BACKLOG.md` at root or `docs/features/`)?
49
+ Run `npx @seanyao/roll@2 migrate` first — see
50
+ [migration-2.0.md](migration-2.0.md). `roll init` will refuse to scaffold on top
51
+ of a half-migrated project.
52
+
53
+ ## Sync After Updating Roll
54
+
55
+ When roll ships a new version of its conventions or skills, sync them into your project:
56
+
57
+ ```bash
58
+ roll sync
59
+ ```
60
+
61
+ `sync` only overwrites files that roll manages (skills and global conventions). Your project-specific files (`.roll/backlog.md`, project source, etc.) are never touched.
62
+
63
+ ## Typical First-Use Sequence
64
+
65
+ ```bash
66
+ curl -fsSL https://seanyao.github.io/roll/install | bash # install roll
67
+ roll setup # configure AI tools globally (one time per machine)
68
+ cd my-project
69
+ roll init # diagnose and route this project
70
+ roll next # continue with design/apply/repair/migrate/loop/status
71
+ roll loop on # enable autonomous execution
72
+ ```
73
+
74
+ `roll setup` syncs conventions for the AI tools installed on the machine.
75
+ Agent semantics live in `~/.roll/agents.yaml` (Machine Scope) and
76
+ `.roll/agents.yaml` (Project Scope). Run `roll agent migrate --dry-run` to
77
+ convert older `primary_agent`, local-agent, pairing, or v3 route-slot data into
78
+ the scoped model.
79
+
80
+ ## What Gets Created
81
+
82
+ | File | Purpose |
83
+ |------|---------|
84
+ | `AGENTS.md` | Agent conventions: domain model, scope, coding standards (root-level — entry point for every AI client) |
85
+ | `.roll/backlog.md` | Story tracking (Epic / Feature / Story / Fix / Refactor) |
86
+ | `.roll/features/` | Per-feature deep docs (one file per Feature) |
87
+ | `.roll/domain/` | DDD models, context map, architecture records |
88
+
89
+ ## Re-initializing
90
+
91
+ `roll init` is safe to repeat. Complete projects get `Next: roll status`;
92
+ partial projects get `roll init --repair` instead of another scaffold pass.
93
+
94
+ ## See Also
95
+
96
+ - [installation.md](installation.md) — install and update roll
97
+ - [conventions.md](conventions.md) — AGENTS.md structure and conventions
98
+ - [patterns/](patterns/README.md) — three adoption patterns (seed / graft / replant)
99
+ - [legacy-onboarding.md](legacy-onboarding.md) — graft Roll into an existing codebase
100
+ - [migration-2.0.md](migration-2.0.md) — upgrade a pre-2.0 project to `.roll/` layout
101
+ - [loop.md](loop.md) — enable autonomous execution
102
+
103
+ ## Git Hooks Auto-Setup (US-INFRA-008/009)
104
+
105
+ Roll's TCR pre-commit gate lives in `hooks/pre-commit`. Git ignores this directory
106
+ by default — `core.hooksPath` must point to it. Roll configures this automatically
107
+ in three places so you never hit a "TCR gate bypassed" window:
108
+
109
+ 1. **`roll setup`** — configures `core.hooksPath=hooks` in the current repo.
110
+ 2. **Autonomous loop cycle preflight** — each cycle ensures the worktree it runs in
111
+ has the correct hooks path.
112
+ 3. **Claude Code SessionStart hook** (`.claude/settings.json`) — runs
113
+ `git config core.hooksPath hooks` every time a new Claude Code session opens in
114
+ this project.
115
+
116
+ **Manual override:** If you've intentionally set `core.hooksPath` to something else,
117
+ Roll will not overwrite it. The auto-setup only fires when the value is unset or
118
+ equals the git default `.git/hooks`.
119
+
120
+ **Troubleshooting:** If commits are going through without running tests:
121
+
122
+ ```bash
123
+ git config core.hooksPath # should print: hooks
124
+ ls hooks/pre-commit # should exist and be executable
125
+ roll setup # re-runs the configuration step
126
+ ```