thevoidforge 21.0.10 → 21.0.12
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/.claude/commands/ai.md +69 -0
- package/dist/.claude/commands/architect.md +121 -0
- package/dist/.claude/commands/assemble.md +201 -0
- package/dist/.claude/commands/assess.md +75 -0
- package/dist/.claude/commands/blueprint.md +135 -0
- package/dist/.claude/commands/build.md +116 -0
- package/dist/.claude/commands/campaign.md +201 -0
- package/dist/.claude/commands/cultivation.md +166 -0
- package/dist/.claude/commands/current.md +128 -0
- package/dist/.claude/commands/dangerroom.md +74 -0
- package/dist/.claude/commands/debrief.md +178 -0
- package/dist/.claude/commands/deploy.md +99 -0
- package/dist/.claude/commands/devops.md +143 -0
- package/dist/.claude/commands/gauntlet.md +140 -0
- package/dist/.claude/commands/git.md +104 -0
- package/dist/.claude/commands/grow.md +146 -0
- package/dist/.claude/commands/imagine.md +126 -0
- package/dist/.claude/commands/portfolio.md +50 -0
- package/dist/.claude/commands/prd.md +113 -0
- package/dist/.claude/commands/qa.md +107 -0
- package/dist/.claude/commands/review.md +151 -0
- package/dist/.claude/commands/security.md +100 -0
- package/dist/.claude/commands/test.md +96 -0
- package/dist/.claude/commands/thumper.md +116 -0
- package/dist/.claude/commands/treasury.md +100 -0
- package/dist/.claude/commands/ux.md +118 -0
- package/dist/.claude/commands/vault.md +189 -0
- package/dist/.claude/commands/void.md +108 -0
- package/dist/CHANGELOG.md +1918 -0
- package/dist/CLAUDE.md +250 -0
- package/dist/HOLOCRON.md +856 -0
- package/dist/VERSION.md +123 -0
- package/dist/docs/NAMING_REGISTRY.md +478 -0
- package/dist/docs/methods/AI_INTELLIGENCE.md +276 -0
- package/dist/docs/methods/ASSEMBLER.md +142 -0
- package/dist/docs/methods/BACKEND_ENGINEER.md +165 -0
- package/dist/docs/methods/BUILD_JOURNAL.md +185 -0
- package/dist/docs/methods/BUILD_PROTOCOL.md +426 -0
- package/dist/docs/methods/CAMPAIGN.md +568 -0
- package/dist/docs/methods/CONTEXT_MANAGEMENT.md +189 -0
- package/dist/docs/methods/DEEP_CURRENT.md +184 -0
- package/dist/docs/methods/DEVOPS_ENGINEER.md +295 -0
- package/dist/docs/methods/FIELD_MEDIC.md +261 -0
- package/dist/docs/methods/FORGE_ARTIST.md +108 -0
- package/dist/docs/methods/FORGE_KEEPER.md +268 -0
- package/dist/docs/methods/GAUNTLET.md +344 -0
- package/dist/docs/methods/GROWTH_STRATEGIST.md +466 -0
- package/dist/docs/methods/HEARTBEAT.md +168 -0
- package/dist/docs/methods/MCP_INTEGRATION.md +139 -0
- package/dist/docs/methods/MUSTER.md +148 -0
- package/dist/docs/methods/PRD_GENERATOR.md +186 -0
- package/dist/docs/methods/PRODUCT_DESIGN_FRONTEND.md +250 -0
- package/dist/docs/methods/QA_ENGINEER.md +337 -0
- package/dist/docs/methods/RELEASE_MANAGER.md +145 -0
- package/dist/docs/methods/SECURITY_AUDITOR.md +320 -0
- package/dist/docs/methods/SUB_AGENTS.md +335 -0
- package/dist/docs/methods/SYSTEMS_ARCHITECT.md +171 -0
- package/dist/docs/methods/TESTING.md +359 -0
- package/dist/docs/methods/THUMPER.md +175 -0
- package/dist/docs/methods/TIME_VAULT.md +120 -0
- package/dist/docs/methods/TREASURY.md +184 -0
- package/dist/docs/methods/TROUBLESHOOTING.md +265 -0
- package/dist/docs/patterns/README.md +52 -0
- package/dist/docs/patterns/ad-billing-adapter.ts +537 -0
- package/dist/docs/patterns/ad-platform-adapter.ts +421 -0
- package/dist/docs/patterns/ai-classifier.ts +195 -0
- package/dist/docs/patterns/ai-eval.ts +272 -0
- package/dist/docs/patterns/ai-orchestrator.ts +341 -0
- package/dist/docs/patterns/ai-router.ts +194 -0
- package/dist/docs/patterns/ai-tool-schema.ts +237 -0
- package/dist/docs/patterns/api-route.ts +241 -0
- package/dist/docs/patterns/backtest-engine.ts +499 -0
- package/dist/docs/patterns/browser-review.ts +292 -0
- package/dist/docs/patterns/combobox.tsx +300 -0
- package/dist/docs/patterns/component.tsx +262 -0
- package/dist/docs/patterns/daemon-process.ts +338 -0
- package/dist/docs/patterns/data-pipeline.ts +297 -0
- package/dist/docs/patterns/database-migration.ts +466 -0
- package/dist/docs/patterns/e2e-test.ts +629 -0
- package/dist/docs/patterns/error-handling.ts +312 -0
- package/dist/docs/patterns/execution-safety.ts +601 -0
- package/dist/docs/patterns/financial-transaction.ts +342 -0
- package/dist/docs/patterns/funding-plan.ts +462 -0
- package/dist/docs/patterns/game-entity.ts +137 -0
- package/dist/docs/patterns/game-loop.ts +113 -0
- package/dist/docs/patterns/game-state.ts +143 -0
- package/dist/docs/patterns/job-queue.ts +225 -0
- package/dist/docs/patterns/kongo-integration.ts +164 -0
- package/dist/docs/patterns/middleware.ts +363 -0
- package/dist/docs/patterns/mobile-screen.tsx +139 -0
- package/dist/docs/patterns/mobile-service.ts +167 -0
- package/dist/docs/patterns/multi-tenant.ts +382 -0
- package/dist/docs/patterns/oauth-token-lifecycle.ts +223 -0
- package/dist/docs/patterns/outbound-rate-limiter.ts +260 -0
- package/dist/docs/patterns/prompt-template.ts +195 -0
- package/dist/docs/patterns/revenue-source-adapter.ts +311 -0
- package/dist/docs/patterns/service.ts +224 -0
- package/dist/docs/patterns/sse-endpoint.ts +118 -0
- package/dist/docs/patterns/stablecoin-adapter.ts +511 -0
- package/dist/docs/patterns/third-party-script.ts +68 -0
- package/dist/scripts/thumper/gom-jabbar.sh +241 -0
- package/dist/scripts/thumper/relay.sh +610 -0
- package/dist/scripts/thumper/scan.sh +359 -0
- package/dist/scripts/thumper/thumper.sh +190 -0
- package/dist/scripts/thumper/water-rings.sh +76 -0
- package/dist/scripts/voidforge.js +1 -1
- package/package.json +1 -1
- package/dist/tsconfig.tsbuildinfo +0 -1
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
# TESTING PROTOCOL
|
|
2
|
+
## Lead Agent: **Batman** · Sub-agent: **Nightwing** (Regression Guardian)
|
|
3
|
+
|
|
4
|
+
> *"The test suite is your silent guardian."*
|
|
5
|
+
|
|
6
|
+
## Purpose
|
|
7
|
+
|
|
8
|
+
Automated tests catch regressions that manual checklists miss. Manual verification catches UX and integration issues that automated tests miss. Use both. Neither replaces the other.
|
|
9
|
+
|
|
10
|
+
## Testing Pyramid
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
/ E2E \ ← Few: critical user journeys only
|
|
14
|
+
/ Integration \ ← Some: API routes, service interactions
|
|
15
|
+
/ Unit Tests \ ← Many: business logic, utils, transforms
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Framework-to-Test-Runner Mapping
|
|
19
|
+
|
|
20
|
+
| Framework | Unit Tests | Integration Tests | E2E | Assertion |
|
|
21
|
+
|-----------|-----------|------------------|-----|-----------|
|
|
22
|
+
| Next.js / Node | vitest or jest | vitest + supertest | Playwright | expect (vitest/jest) |
|
|
23
|
+
| Express | vitest or jest | vitest + supertest | Playwright | expect (vitest/jest) |
|
|
24
|
+
| Django | pytest | pytest + Django test client | Playwright | assert (pytest) |
|
|
25
|
+
| Rails | RSpec or Minitest | RSpec + request specs | Playwright | expect (RSpec) |
|
|
26
|
+
| Go | testing (stdlib) | testing + httptest | Playwright | testify |
|
|
27
|
+
| Spring Boot | JUnit 5 | JUnit 5 + MockMvc | Playwright | AssertJ |
|
|
28
|
+
|
|
29
|
+
Adapt the patterns below to your stack's test runner. The principles (test behavior not implementation, deterministic, co-located) are universal.
|
|
30
|
+
|
|
31
|
+
## When to Write Which
|
|
32
|
+
|
|
33
|
+
| Code Type | Test Type | Tool | Coverage Target |
|
|
34
|
+
|-----------|-----------|------|----------------|
|
|
35
|
+
| Pure functions, utils, transforms | Unit | vitest / jest | High — these are cheap to test |
|
|
36
|
+
| Service layer (business logic) | Unit | vitest / jest | High — core value lives here |
|
|
37
|
+
| API routes | Integration | vitest / supertest | All routes — validate input/output contracts |
|
|
38
|
+
| Database queries | Integration | vitest + test DB | Complex queries, edge cases |
|
|
39
|
+
| Auth flows | Integration | vitest / supertest | All auth paths including failures |
|
|
40
|
+
| Full user journeys | E2E / Manual | Playwright or manual | Top 3-5 critical paths only |
|
|
41
|
+
| UI components | Manual | Browser | Visual, interaction, responsive, a11y |
|
|
42
|
+
| Edge cases, broken states | Manual | Browser | Red Hood's domain — break it on purpose |
|
|
43
|
+
|
|
44
|
+
## Unit Test Rules
|
|
45
|
+
|
|
46
|
+
1. Test behavior, not implementation. Assert outcomes, not internals.
|
|
47
|
+
2. One assertion concept per test. Name describes what's being verified.
|
|
48
|
+
3. No mocking unless the dependency is external (API, DB, filesystem).
|
|
49
|
+
4. Use factories for test data, not raw objects scattered across files.
|
|
50
|
+
5. Tests must be deterministic — no time-dependent, order-dependent, or network-dependent tests.
|
|
51
|
+
|
|
52
|
+
### Pattern
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
// services/__tests__/billing.test.ts
|
|
56
|
+
import { describe, it, expect } from 'vitest'
|
|
57
|
+
import { calculateProration } from '../billing'
|
|
58
|
+
|
|
59
|
+
describe('calculateProration', () => {
|
|
60
|
+
it('returns zero when upgrade happens on billing date', () => {
|
|
61
|
+
const result = calculateProration({
|
|
62
|
+
currentPlan: 'basic',
|
|
63
|
+
newPlan: 'pro',
|
|
64
|
+
billingDate: new Date('2026-03-01'),
|
|
65
|
+
upgradeDate: new Date('2026-03-01'),
|
|
66
|
+
})
|
|
67
|
+
expect(result.amount).toBe(0)
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
it('prorates proportionally for mid-cycle upgrade', () => {
|
|
71
|
+
const result = calculateProration({
|
|
72
|
+
currentPlan: 'basic',
|
|
73
|
+
newPlan: 'pro',
|
|
74
|
+
billingDate: new Date('2026-03-01'),
|
|
75
|
+
upgradeDate: new Date('2026-03-15'),
|
|
76
|
+
})
|
|
77
|
+
expect(result.amount).toBeGreaterThan(0)
|
|
78
|
+
expect(result.daysRemaining).toBe(16)
|
|
79
|
+
})
|
|
80
|
+
})
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Integration Test Rules
|
|
84
|
+
|
|
85
|
+
1. Use a real test database (SQLite in-memory or Docker Postgres).
|
|
86
|
+
2. Reset state between tests (transactions or truncation).
|
|
87
|
+
3. Test the full request/response cycle for API routes.
|
|
88
|
+
4. Validate response shape, status codes, and error formats.
|
|
89
|
+
5. Test auth: authenticated, unauthenticated, wrong role, wrong owner.
|
|
90
|
+
6. **Validation constraint smoke test:** For each model with validation constraints (Pydantic `Field`, Zod schema, Joi, class-validator decorators), write at least one test that sends invalid input and verifies rejection. Frameworks may silently ignore constraints on incompatible types (e.g., Pydantic v2 ignores `max_length` on dict). The test catches this. (Field report #99: `max_length=50` on a dict field was silently ignored — no size validation occurred.)
|
|
91
|
+
7. **Route integration test mandate:** For each API route, at least one test must exercise the full HTTP → handler → service → response path. Unit tests on service functions are not sufficient — they miss middleware, auth guards, request parsing, and response formatting. A route with no integration test is an untested route. (Field report #119: zero integration tests across 278 unit tests — route-level regressions were invisible.)
|
|
92
|
+
|
|
93
|
+
### Pattern
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
// api/__tests__/projects.test.ts
|
|
97
|
+
import { describe, it, expect, beforeEach } from 'vitest'
|
|
98
|
+
import { createTestApp, createTestUser } from '../test-utils'
|
|
99
|
+
|
|
100
|
+
describe('POST /api/projects', () => {
|
|
101
|
+
let app: TestApp
|
|
102
|
+
let user: TestUser
|
|
103
|
+
|
|
104
|
+
beforeEach(async () => {
|
|
105
|
+
app = await createTestApp()
|
|
106
|
+
user = await createTestUser(app)
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
it('creates project for authenticated user', async () => {
|
|
110
|
+
const res = await app.post('/api/projects')
|
|
111
|
+
.auth(user.token)
|
|
112
|
+
.send({ name: 'Test Project' })
|
|
113
|
+
|
|
114
|
+
expect(res.status).toBe(201)
|
|
115
|
+
expect(res.body.project.name).toBe('Test Project')
|
|
116
|
+
expect(res.body.project.ownerId).toBe(user.id)
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
it('rejects unauthenticated request', async () => {
|
|
120
|
+
const res = await app.post('/api/projects')
|
|
121
|
+
.send({ name: 'Test Project' })
|
|
122
|
+
|
|
123
|
+
expect(res.status).toBe(401)
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
it('validates input', async () => {
|
|
127
|
+
const res = await app.post('/api/projects')
|
|
128
|
+
.auth(user.token)
|
|
129
|
+
.send({ name: '' })
|
|
130
|
+
|
|
131
|
+
expect(res.status).toBe(400)
|
|
132
|
+
expect(res.body.error.code).toBe('VALIDATION_ERROR')
|
|
133
|
+
})
|
|
134
|
+
})
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## E2E Testing
|
|
138
|
+
|
|
139
|
+
E2E tests sit at the top of the testing pyramid. They're slow, expensive, and brittle compared to unit tests — but they catch integration failures that nothing else can. A unit test verifies that `calculateTotal()` returns the right number; an E2E test verifies that the user can actually complete a purchase.
|
|
140
|
+
|
|
141
|
+
### Where E2E Fits
|
|
142
|
+
|
|
143
|
+
```
|
|
144
|
+
/ E2E \ ← 10-15 tests. Critical user journeys ONLY.
|
|
145
|
+
/ Integration \ ← API routes, service interactions, auth flows
|
|
146
|
+
/ Unit Tests \ ← Business logic, utils, transforms, edge cases
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
**Write E2E when:**
|
|
150
|
+
- Testing critical user journeys (signup, purchase, core workflow)
|
|
151
|
+
- Verifying a11y across real page compositions (axe-core in browser)
|
|
152
|
+
- Testing cross-component flows where integration tests can't reach (navigation, redirects, auth state persistence)
|
|
153
|
+
- Validating real browser behavior (CSP headers, cookie handling, responsive layout)
|
|
154
|
+
|
|
155
|
+
**Write unit/integration instead when:**
|
|
156
|
+
- Testing business logic, calculations, or data transforms
|
|
157
|
+
- Testing API input validation and error handling
|
|
158
|
+
- Testing edge cases and boundary conditions
|
|
159
|
+
- Testing isolated component behavior
|
|
160
|
+
|
|
161
|
+
### Performance Budget
|
|
162
|
+
|
|
163
|
+
| Metric | Limit | Action if Exceeded |
|
|
164
|
+
|--------|-------|--------------------|
|
|
165
|
+
| Total CI time | 2 minutes | Shard tests across workers |
|
|
166
|
+
| Test count | 50 | Shard or prune — you're testing too many paths |
|
|
167
|
+
| Single test duration | 30 seconds | Split into smaller focused tests |
|
|
168
|
+
| Retry rate | < 5% per week | Fix or quarantine flaky tests |
|
|
169
|
+
|
|
170
|
+
Sharding in CI (when you hit 50+ tests):
|
|
171
|
+
```yaml
|
|
172
|
+
# GitHub Actions example
|
|
173
|
+
strategy:
|
|
174
|
+
matrix:
|
|
175
|
+
shard: [1/3, 2/3, 3/3]
|
|
176
|
+
steps:
|
|
177
|
+
- run: npx playwright test --shard=${{ matrix.shard }}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### Flaky Test Protocol
|
|
181
|
+
|
|
182
|
+
Flaky tests erode trust in the test suite. Huntress (stability monitor) tracks flake rates.
|
|
183
|
+
|
|
184
|
+
1. **Detection:** Test fails intermittently — passes on retry but fails on fresh runs
|
|
185
|
+
2. **Annotation:** After 3 flakes in a week, add `@flaky` tag with a tracking issue
|
|
186
|
+
3. **Quarantine:** Flaky tests run in a separate CI job (`grep: /@flaky/`) with 3 retries
|
|
187
|
+
4. **Investigation:** Root-cause the flakiness — usually timing, external state, or test ordering
|
|
188
|
+
5. **Resolution:** Fix within 2 weeks or rewrite. If unfixable, demote to manual verification
|
|
189
|
+
6. **Return:** Remove `@flaky` tag — test returns to the stable suite
|
|
190
|
+
|
|
191
|
+
```typescript
|
|
192
|
+
// Annotating a flaky test
|
|
193
|
+
test('payment webhook processes correctly', {
|
|
194
|
+
tag: ['@flaky'],
|
|
195
|
+
annotation: { type: 'flaky', description: 'Webhook timing race — tracking in #234' },
|
|
196
|
+
}, async ({ page }) => {
|
|
197
|
+
// test body
|
|
198
|
+
});
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
**Rules:**
|
|
202
|
+
- NEVER use `@flaky` to suppress real bugs
|
|
203
|
+
- NEVER use `page.waitForTimeout()` — it's the #1 cause of flakiness
|
|
204
|
+
- NEVER use `waitForLoadState('networkidle')` — it's non-deterministic
|
|
205
|
+
- ALWAYS use explicit waits: `await expect(locator).toBeVisible()`
|
|
206
|
+
|
|
207
|
+
### Framework-to-Test-Runner Mapping (E2E Column)
|
|
208
|
+
|
|
209
|
+
| Framework | Unit | Integration | E2E Runner | E2E Start Command |
|
|
210
|
+
|-----------|------|-------------|------------|-------------------|
|
|
211
|
+
| Next.js / Node | vitest or jest | vitest + supertest | Playwright | `next dev -p 3199` |
|
|
212
|
+
| Express | vitest or jest | vitest + supertest | Playwright | `PORT=3199 npx tsx src/server.ts` |
|
|
213
|
+
| Django | pytest | pytest + Django client | Playwright | `python manage.py runserver 3199` |
|
|
214
|
+
| Rails | RSpec / Minitest | RSpec + request specs | Playwright | `RAILS_ENV=test bin/rails server -p 3199` |
|
|
215
|
+
| Go | testing (stdlib) | testing + httptest | Playwright | `PORT=3199 go run ./cmd/server` |
|
|
216
|
+
| Spring Boot | JUnit 5 | JUnit 5 + MockMvc | Playwright | `./gradlew bootRun --args='--server.port=3199'` |
|
|
217
|
+
|
|
218
|
+
### PRD Frontmatter
|
|
219
|
+
|
|
220
|
+
Add `e2e: yes | no` to PRD frontmatter. Defaults:
|
|
221
|
+
- `yes` — full-stack, static-site (has pages to test)
|
|
222
|
+
- `no` — api-only, prototype (no browser UI, or too early)
|
|
223
|
+
|
|
224
|
+
The Build Protocol reads this flag to decide whether Phase 10 (E2E tests) runs.
|
|
225
|
+
|
|
226
|
+
### E2E Test File Conventions
|
|
227
|
+
|
|
228
|
+
```
|
|
229
|
+
e2e/
|
|
230
|
+
fixtures.ts ← axe-core fixture, auth helper, network mocks
|
|
231
|
+
auth.setup.ts ← Login via API, save session state
|
|
232
|
+
smoke.test.ts ← Page loads, no crashes, a11y clean
|
|
233
|
+
auth.test.ts ← Login/logout/session persistence
|
|
234
|
+
[feature].test.ts ← One file per critical journey
|
|
235
|
+
page-objects/
|
|
236
|
+
login.page.ts ← Page Object Model classes
|
|
237
|
+
dashboard.page.ts
|
|
238
|
+
.auth/
|
|
239
|
+
session.json ← Saved auth state (gitignored)
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
### Reference Pattern
|
|
243
|
+
|
|
244
|
+
See `/docs/patterns/e2e-test.ts` for the complete reference implementation:
|
|
245
|
+
- Page Object Model example
|
|
246
|
+
- axe-core a11y fixture
|
|
247
|
+
- Auth helper (login via API, reuse session)
|
|
248
|
+
- Network mock (intercept external API calls)
|
|
249
|
+
- WebSocket mock
|
|
250
|
+
- CWV measurement helper
|
|
251
|
+
- Flaky test annotation pattern
|
|
252
|
+
- Framework-specific Playwright config
|
|
253
|
+
|
|
254
|
+
## Testing Anti-Patterns
|
|
255
|
+
|
|
256
|
+
**No hardcoded dates:** Never use hardcoded dates in tests. Use relative datetime (e.g., `new Date(Date.now() - 86400000)` for 'yesterday'). A test with `expect(date).toBe('2026-03-15')` becomes a time bomb that fails when the date passes.
|
|
257
|
+
|
|
258
|
+
**Mock signature verification:** When mocking external dependencies, verify the mocked methods exist on the real class. A mock that defines `sendMessage()` when the real SDK uses `send_message()` creates false confidence — tests pass but the integration fails. Pattern: `expect(Object.keys(mock)).toEqual(expect.arrayContaining(Object.keys(realInstance)))`.
|
|
259
|
+
|
|
260
|
+
**No source-code string assertions:** Never assert on status code strings or error class names found in source code (`'403' in source`, `'HTTPException' in source`). These break on any refactor that changes error handling mechanics (e.g., `HTTPException(403)` → `Errors.forbidden()`). Test the actual HTTP response status and body instead. (Field report #227)
|
|
261
|
+
|
|
262
|
+
**Error format migration checklist:** Before committing any change to error response shape (e.g., `{"detail": ...}` → `{"error": {"code", "message"}}`), grep test files for the old shape. Tests asserting `response["detail"]` will silently pass if the test never reaches the assertion (wrong status code) or will fail confusingly. Fix all test assertions to match the new shape in the same commit. (Field report #227)
|
|
263
|
+
|
|
264
|
+
**Standalone test app handler registration (FastAPI/Express):** When tests create their own application instance (`FastAPI()`, `express()`) for isolated testing, register all custom error handlers from the main app (`app.add_exception_handler(ApiError, api_error_handler)` or equivalent). Without this, custom error classes propagate as unhandled exceptions instead of structured JSON — tests pass for the wrong reason. (Field report #227)
|
|
265
|
+
|
|
266
|
+
**Version-agnostic assertions:** When asserting on prefixed or versioned values (encryption prefixes, API version headers, token formats), use the stable prefix, not the exact version. `startswith("enc:")` survives key rotation; `startswith("enc::")` breaks when the format becomes `enc:v1::`. Assert on the behavior ("value is encrypted") not the version ("value uses encryption v1"). (Field report #227)
|
|
267
|
+
|
|
268
|
+
## What NOT to Test Automatically
|
|
269
|
+
|
|
270
|
+
- Visual appearance (manual — Arwen's domain)
|
|
271
|
+
- "Does this feel right?" UX flows (manual — Elrond's domain)
|
|
272
|
+
- Performance under real conditions (manual — Fury/Gimli's domain)
|
|
273
|
+
- Third-party service behavior (mock it, don't call it)
|
|
274
|
+
- Implementation details that could change without affecting behavior
|
|
275
|
+
|
|
276
|
+
## Test File Conventions
|
|
277
|
+
|
|
278
|
+
```
|
|
279
|
+
src/
|
|
280
|
+
services/
|
|
281
|
+
billing.ts
|
|
282
|
+
__tests__/
|
|
283
|
+
billing.test.ts ← Unit tests co-located
|
|
284
|
+
api/
|
|
285
|
+
projects/
|
|
286
|
+
route.ts
|
|
287
|
+
__tests__/
|
|
288
|
+
projects.test.ts ← Integration tests co-located
|
|
289
|
+
test-utils/
|
|
290
|
+
index.ts ← Shared factories, helpers, test app setup
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
## Running Tests
|
|
294
|
+
|
|
295
|
+
```bash
|
|
296
|
+
# All tests
|
|
297
|
+
npm test
|
|
298
|
+
|
|
299
|
+
# Unit tests only
|
|
300
|
+
npm run test:unit
|
|
301
|
+
|
|
302
|
+
# Integration tests only
|
|
303
|
+
npm run test:integration
|
|
304
|
+
|
|
305
|
+
# Watch mode during development
|
|
306
|
+
npm run test:watch
|
|
307
|
+
|
|
308
|
+
# Coverage report
|
|
309
|
+
npm run test:coverage
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
## Regression Strategy
|
|
313
|
+
|
|
314
|
+
Automated tests are the **first line** of regression defense. The manual regression checklist in `/docs/qa-prompt.md` is the **second line** — it catches integration and UX regressions that tests can't.
|
|
315
|
+
|
|
316
|
+
When Nightwing adds a regression checklist item, also ask: "Can this be an automated test?" If yes, write the test AND add the checklist item. The test runs on every change; the checklist runs on QA passes.
|
|
317
|
+
|
|
318
|
+
## Relationship to QA_ENGINEER.md
|
|
319
|
+
|
|
320
|
+
Batman's QA protocol now includes automated testing as Step 3.5 (between "Find Bugs" and "Bug Tracker"). The sequence:
|
|
321
|
+
|
|
322
|
+
1. Oracle scans statically
|
|
323
|
+
2. Red Hood breaks dynamically
|
|
324
|
+
3. Alfred reviews dependencies
|
|
325
|
+
4. Lucius reviews config
|
|
326
|
+
5. **Nightwing runs the test suite and reports failures**
|
|
327
|
+
6. All findings go into the bug tracker
|
|
328
|
+
7. Fixes include new tests to prevent regression
|
|
329
|
+
|
|
330
|
+
### Test Schema vs. Production Schema
|
|
331
|
+
Verify test fixtures (conftest, factories, seed files) create ALL tables from the migration runner. Compare table lists between the test DB setup and the production schema — any table present in migrations but missing from test fixtures is a gap that causes silent test failures. This is especially critical when using a hardcoded migration list instead of the actual migration runner.
|
|
332
|
+
(Field report #21: conftest missed tables from later migrations — ALTER TABLE on non-existent table was silently caught.)
|
|
333
|
+
|
|
334
|
+
### Database Fixtures — Use the Production Schema
|
|
335
|
+
|
|
336
|
+
Always use the test framework's shared database fixture (e.g., conftest `db` fixture) for store and service tests. It applies the full production schema + all migrations.
|
|
337
|
+
|
|
338
|
+
Do NOT create custom DDL in test files — it drifts from the real schema (missing NOT NULL constraints, columns added by later migrations, different defaults). If you need tables the shared fixture doesn't have, add them AFTER the fixture yields — don't replace it.
|
|
339
|
+
|
|
340
|
+
Custom DDL causes test DB schema mismatches that require 2-3 fix-and-retry cycles per occurrence. (Field report #31)
|
|
341
|
+
|
|
342
|
+
## Setup Checklist
|
|
343
|
+
|
|
344
|
+
When setting up testing for a new project:
|
|
345
|
+
|
|
346
|
+
- [ ] Install test runner (`npm i -D vitest` or `jest`)
|
|
347
|
+
- [ ] Add test scripts to `package.json`
|
|
348
|
+
- [ ] Create `test-utils/` with app setup and factories
|
|
349
|
+
- [ ] Configure test database (if applicable)
|
|
350
|
+
- [ ] Write first test for the most critical service function
|
|
351
|
+
- [ ] Write first integration test for the most important API route
|
|
352
|
+
- [ ] Verify `npm test` passes in CI-equivalent conditions
|
|
353
|
+
- [ ] **E2E (if PRD `e2e: yes`):** Install Playwright (`npm i -D @playwright/test @axe-core/playwright`)
|
|
354
|
+
- [ ] **E2E:** Install browser (`npx playwright install chromium`)
|
|
355
|
+
- [ ] **E2E:** Create `playwright.config.ts` with framework-appropriate `webServer.command`
|
|
356
|
+
- [ ] **E2E:** Create `e2e/fixtures.ts` with axe-core fixture and auth helper
|
|
357
|
+
- [ ] **E2E:** Write first smoke test — page loads, no a11y violations
|
|
358
|
+
- [ ] **E2E:** Add `e2e/.auth/`, `test-results/`, `playwright-report/` to `.gitignore`
|
|
359
|
+
- [ ] **E2E:** Verify `npx playwright test` passes in CI-equivalent conditions (< 2 min)
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
# THE THUMPER — Chani's Worm Rider
|
|
2
|
+
## Lead Agent: **Chani** (Chani Kynes) · Sub-agents: Dune Universe
|
|
3
|
+
|
|
4
|
+
> *"Tell me of your homeworld, Usul."*
|
|
5
|
+
|
|
6
|
+
## What Is This
|
|
7
|
+
|
|
8
|
+
Send prompts to Claude Code from Telegram and get responses back. Plant a thumper, ride the sandworm, command from anywhere.
|
|
9
|
+
|
|
10
|
+
## Identity
|
|
11
|
+
|
|
12
|
+
**Chani** is a Worm Rider. She doesn't write code — she ensures The Voice reaches its destination across any environment. Her domain is cross-environment session bridging: connecting your Telegram to a live Claude Code session.
|
|
13
|
+
|
|
14
|
+
**Behavioral directives:** Every channel must pass the Gom Jabbar. Default to the most reliable worm path. Never store credentials outside the sietch vault. When a signal fails, notify the sender — silence is betrayal in the desert.
|
|
15
|
+
|
|
16
|
+
**See `/docs/NAMING_REGISTRY.md` for the full Dune character pool.**
|
|
17
|
+
|
|
18
|
+
## Sub-Agent Roster
|
|
19
|
+
|
|
20
|
+
| Agent | Name | Role | Lens |
|
|
21
|
+
|-------|------|------|------|
|
|
22
|
+
| Channel Security | **Stilgar** | Naib — protects the tribe's secrets | No outsider enters the sietch. |
|
|
23
|
+
| Protocol Parsing | **Thufir** | Mentat — message processing | A million computations per second. |
|
|
24
|
+
| Relay Operations | **Idaho** | Swordmaster — the eternal connection | Dies a thousand times, always returns. |
|
|
25
|
+
| Authentication | **Mohiam** | Reverend Mother — the Gom Jabbar | "Put your hand in the box." |
|
|
26
|
+
|
|
27
|
+
## Goal
|
|
28
|
+
|
|
29
|
+
Authenticated, bidirectional Telegram bridge to Claude Code. One command to start, passphrase-gated, works across macOS local, macOS+tmux, headless Linux SSH, and Linux+tmux.
|
|
30
|
+
|
|
31
|
+
## When to Call Other Agents
|
|
32
|
+
|
|
33
|
+
| Situation | Hand off to |
|
|
34
|
+
|-----------|-------------|
|
|
35
|
+
| Security review of credential handling | **Kenobi** (Security) |
|
|
36
|
+
| Infrastructure for daemon supervision | **Kusanagi** (DevOps) |
|
|
37
|
+
| Architecture of transport layer | **Picard** (Architecture) |
|
|
38
|
+
| Bug in injection mechanics | **Batman** (QA) |
|
|
39
|
+
|
|
40
|
+
## Operating Rules
|
|
41
|
+
|
|
42
|
+
1. Every session must pass the Gom Jabbar — no exceptions.
|
|
43
|
+
2. Credentials live in `sietch.env` (chmod 600, umask 077). Never committed.
|
|
44
|
+
3. The Gom Jabbar hash is session-scoped — destroyed on `/thumper off`.
|
|
45
|
+
4. Passphrase messages are deleted from Telegram. If deletion fails, the session is invalidated.
|
|
46
|
+
5. After 60 minutes idle, re-authentication is required.
|
|
47
|
+
6. 3 failed auth attempts trigger a 5-minute lockout.
|
|
48
|
+
7. Messages during auth challenge are discarded, not queued.
|
|
49
|
+
8. The water rings hook always exits 0 — never blocks Claude Code.
|
|
50
|
+
9. Log operations, not message content.
|
|
51
|
+
10. Control characters (0x00-0x1F, 0x7F) are stripped before injection. Newlines collapsed to spaces.
|
|
52
|
+
11. The thumper must never run as root.
|
|
53
|
+
|
|
54
|
+
## Worm Paths (Transport Vectors)
|
|
55
|
+
|
|
56
|
+
| Worm Path | Environment | Mechanism | Platform |
|
|
57
|
+
|-----------|-------------|-----------|----------|
|
|
58
|
+
| **TMUX_SENDKEYS** | Any with tmux | `tmux send-keys -l -t [session]` | Cross-platform |
|
|
59
|
+
| **PTY_INJECT** | Headless Linux SSH | Write to `/proc/[pid]/fd/0` | Linux only |
|
|
60
|
+
| **OSASCRIPT** | macOS Terminal.app / iTerm2 | File-based AppleScript injection | macOS only |
|
|
61
|
+
|
|
62
|
+
**Detection priority:** TMUX (most reliable) > Headless SSH > macOS local > Linux PTY > manual override. OSASCRIPT is only auto-selected for Terminal.app and iTerm2 — VS Code, Warp, Alacritty, and Kitty users get explicit guidance to use tmux. Windows Git Bash/MSYS2 gets a "use WSL" message.
|
|
63
|
+
|
|
64
|
+
## The Gom Jabbar Protocol
|
|
65
|
+
|
|
66
|
+
**How it works:**
|
|
67
|
+
1. On `/thumper on`, the relay sends a challenge to Telegram: "Choose your word of passage."
|
|
68
|
+
2. You type a passphrase (any word or phrase) in the Telegram chat.
|
|
69
|
+
3. The passphrase is hashed with PBKDF2 (100k iterations via python3, HMAC-SHA256 fallback) and stored in `.gom-jabbar`.
|
|
70
|
+
4. The passphrase message is deleted from Telegram via the `deleteMessage` API (3 retries).
|
|
71
|
+
5. If deletion fails, the session is invalidated and you must choose a new passphrase.
|
|
72
|
+
6. Messages flow normally while authenticated.
|
|
73
|
+
7. After 60 minutes idle: "The sands have shifted. Speak your word of passage."
|
|
74
|
+
8. 3 wrong attempts: locked for 5 minutes.
|
|
75
|
+
|
|
76
|
+
**Security properties:**
|
|
77
|
+
- PBKDF2 with 100k iterations prevents brute force
|
|
78
|
+
- Message deletion removes passphrase from chat history
|
|
79
|
+
- Session-scoped hash — destroyed on `/thumper off`
|
|
80
|
+
- No message queuing during auth — prevents unauthenticated payload laundering
|
|
81
|
+
- Empty hash bypass prevention — refuses auth when hashing tools are unavailable
|
|
82
|
+
|
|
83
|
+
## Setup Flow
|
|
84
|
+
|
|
85
|
+
`/thumper setup` walks through everything interactively:
|
|
86
|
+
1. **Bot creation:** Guides you through BotFather or accepts an existing token. Auto-detects your chat ID.
|
|
87
|
+
2. **Environment scan:** Auto-detects your terminal and selects the best worm path.
|
|
88
|
+
3. **Config write:** Creates `.voidforge/thumper/sietch.env` (chmod 600, umask 077).
|
|
89
|
+
4. **Activate:** Offers to start the channel immediately.
|
|
90
|
+
|
|
91
|
+
No manual config editing required — `scan.sh` handles everything.
|
|
92
|
+
|
|
93
|
+
**Non-interactive mode:** Claude Code's Bash tool doesn't support interactive stdin (`read -r -p`). For setup from within Claude Code, use: `bash scripts/thumper/scan.sh --token YOUR_BOT_TOKEN --chat-id YOUR_CHAT_ID`. This skips all prompts and writes the sietch vault directly. (Field report #35)
|
|
94
|
+
|
|
95
|
+
## Usage
|
|
96
|
+
|
|
97
|
+
```
|
|
98
|
+
/thumper setup — First-time scan or re-configure
|
|
99
|
+
/thumper on — Start sandworm daemon + Gom Jabbar challenge
|
|
100
|
+
/thumper off — Stop daemon, destroy auth state
|
|
101
|
+
/thumper status — Channel state, worm path, auth state, log size
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Scripts
|
|
105
|
+
|
|
106
|
+
| Script | Purpose |
|
|
107
|
+
|--------|---------|
|
|
108
|
+
| `thumper.sh` | Router — dispatches on/off/setup/status |
|
|
109
|
+
| `scan.sh` | Setup wizard — bot creation, env detection, config write |
|
|
110
|
+
| `relay.sh` | Sandworm daemon — polls Telegram, injects into Claude Code |
|
|
111
|
+
| `gom-jabbar.sh` | Auth protocol — sourced by relay.sh, not standalone |
|
|
112
|
+
| `water-rings.sh` | Stop hook — sends task completion notification to Telegram |
|
|
113
|
+
|
|
114
|
+
## Water Rings (Stop Hook)
|
|
115
|
+
|
|
116
|
+
`water-rings.sh` is a Claude Code Stop hook registered in `.claude/settings.json`. It fires every time Claude Code finishes responding.
|
|
117
|
+
|
|
118
|
+
1. Checks if config exists and channel is active — exits silently if not.
|
|
119
|
+
2. Reads session JSON from stdin, extracts last assistant message.
|
|
120
|
+
3. Truncates to 3600 chars, sends to Telegram in a background process.
|
|
121
|
+
4. Always exits 0 — never blocks Claude Code.
|
|
122
|
+
|
|
123
|
+
The shutdown logic (killing daemon, removing channel flag, destroying auth) lives in `thumper.sh cmd_off`, not in the stop hook.
|
|
124
|
+
|
|
125
|
+
## Security Considerations
|
|
126
|
+
|
|
127
|
+
### Mitigations (implemented)
|
|
128
|
+
|
|
129
|
+
- Gom Jabbar with PBKDF2 hashing and message deletion
|
|
130
|
+
- Root guard (`id -u` check, unspoofable on macOS bash 3.2)
|
|
131
|
+
- Control character sanitization (Ctrl+C, ESC, ANSI injection prevented)
|
|
132
|
+
- Message length cap (8192 chars)
|
|
133
|
+
- Config injection prevention (`printf '%q'`, umask 077)
|
|
134
|
+
- AppleScript injection prevention (file-based, user text never in source)
|
|
135
|
+
- Atomic state files (write-to-tmp-then-rename)
|
|
136
|
+
- Empty hash bypass prevention
|
|
137
|
+
|
|
138
|
+
### Known risks (inherent)
|
|
139
|
+
|
|
140
|
+
- **Prompt injection:** Telegram messages are Claude Code prompts. Mitigated by settings.json deny list + Gom Jabbar.
|
|
141
|
+
- **Data exfiltration via water rings:** Up to 3600 chars of output sent to Telegram.
|
|
142
|
+
- **Bot token in process listing:** Telegram API constraint. Low risk on single-user machines.
|
|
143
|
+
- **CHAT_ID is not a secret:** Bot token is the primary credential.
|
|
144
|
+
- **PTY race condition:** Mitigated by control character sanitization.
|
|
145
|
+
|
|
146
|
+
## Troubleshooting
|
|
147
|
+
|
|
148
|
+
**Problem: "The sands have shifted" keeps appearing**
|
|
149
|
+
Your 60-minute idle timeout expired. Re-enter your passphrase. To change the timeout, edit `GOM_JABBAR_IDLE_TIMEOUT` in `gom-jabbar.sh`.
|
|
150
|
+
|
|
151
|
+
**Problem: "Could not erase your word from the sands"**
|
|
152
|
+
Telegram failed to delete the passphrase. Session invalidated for safety. Manually delete the message from chat. Run `/thumper off` then `/thumper on`.
|
|
153
|
+
|
|
154
|
+
**Problem: Sandworm starts but messages don't inject**
|
|
155
|
+
Check `/thumper status` for worm path and auth state. For PTY_INJECT: is Claude running? For TMUX: does session name match? For OSASCRIPT: is Terminal/iTerm2 focused with Accessibility permissions?
|
|
156
|
+
|
|
157
|
+
**Problem: Bot doesn't respond at all**
|
|
158
|
+
Check worm log: `tail -f .voidforge/thumper/worm.log`. Verify token: `curl https://api.telegram.org/bot[TOKEN]/getMe`.
|
|
159
|
+
|
|
160
|
+
**Problem: Locked out (3 failed attempts)**
|
|
161
|
+
Wait 5 minutes. If you forgot your passphrase: `/thumper off` then `/thumper on` to choose a new one.
|
|
162
|
+
|
|
163
|
+
## Deliverables
|
|
164
|
+
|
|
165
|
+
1. `scripts/thumper/` — thumper.sh, scan.sh, relay.sh, gom-jabbar.sh, water-rings.sh
|
|
166
|
+
2. `.claude/commands/thumper.md` — Slash command
|
|
167
|
+
3. `.claude/settings.json` — Stop hook registration
|
|
168
|
+
4. This document
|
|
169
|
+
|
|
170
|
+
## Handoffs
|
|
171
|
+
|
|
172
|
+
- Security review → **Kenobi**, log to `/logs/handoffs.md`
|
|
173
|
+
- Infrastructure → **Kusanagi**, log to `/logs/handoffs.md`
|
|
174
|
+
- Architecture → **Picard**, log to `/logs/handoffs.md`
|
|
175
|
+
- Testing → **Batman**, log to `/logs/handoffs.md`
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# TIME VAULT — Seldon's Session Intelligence Preservation
|
|
2
|
+
## Lead Agent: **Hari Seldon** (Foundation) · Sub-agent: **Gaal Dornick** (Foundation)
|
|
3
|
+
|
|
4
|
+
> *"The future is already written. I merely ensure the right people can read it."*
|
|
5
|
+
|
|
6
|
+
## Identity
|
|
7
|
+
|
|
8
|
+
**Hari Seldon** invented psychohistory — the science of predicting the behavior of large populations. In VoidForge, his Time Vault distills the expensive analysis from one session into a portable briefing that lets the next session skip the re-derivation. Seldon compresses, Jake Sisko writes, Gaal Dornick gathers the raw materials.
|
|
9
|
+
|
|
10
|
+
## Goal
|
|
11
|
+
|
|
12
|
+
Preserve expensive analysis across session boundaries. A new session with a vault briefing should reach productive work in under 60 seconds. Without one, recovering context costs 5-15 minutes of re-reading and re-tracing.
|
|
13
|
+
|
|
14
|
+
## Operating Rules
|
|
15
|
+
|
|
16
|
+
### 1. Include What's Expensive to Re-Derive
|
|
17
|
+
|
|
18
|
+
These items require synthesis, tracing, or multi-file analysis to produce. They cannot be recovered by reading a single file:
|
|
19
|
+
|
|
20
|
+
- **Decisions and rationale** — "We chose X over Y because Z" requires the full context that led to the decision
|
|
21
|
+
- **Failed approaches** — Knowing what didn't work (and why) prevents repeated dead ends
|
|
22
|
+
- **Cross-module relationships** — Which files connect to which, non-obvious wiring, integration points
|
|
23
|
+
- **Agent findings** — Consolidated results from review passes (not the full tables — the actionable summary)
|
|
24
|
+
- **Execution plan** — Ordered next steps with dependencies, derived from current state analysis
|
|
25
|
+
- **Test state** — What passes, what fails, what's missing, what was skipped
|
|
26
|
+
|
|
27
|
+
### 2. Exclude What's Cheap to Re-Read
|
|
28
|
+
|
|
29
|
+
These items are stored in well-known locations and can be loaded on demand:
|
|
30
|
+
|
|
31
|
+
- Full file contents (git)
|
|
32
|
+
- PRD text (`/docs/PRD.md`)
|
|
33
|
+
- Method doc contents (`/docs/methods/`)
|
|
34
|
+
- Pattern references (`/docs/patterns/`)
|
|
35
|
+
- Agent naming registry (`/docs/NAMING_REGISTRY.md`)
|
|
36
|
+
- Build journal entries (`/logs/` — read directly when needed)
|
|
37
|
+
|
|
38
|
+
### 3. Psychohistorical Compression
|
|
39
|
+
|
|
40
|
+
Seldon doesn't transcribe — he compresses. A 3-hour session that produced 47 findings across 6 agents becomes:
|
|
41
|
+
|
|
42
|
+
> "Security pass found 3 Critical (all fixed): CSRF on /api/settings, missing rate limit on /auth/login, leaked stack trace in error handler. UX pass found 12 issues (10 fixed, 2 deferred): focus management in modal, contrast on muted text. QA found the modal fix broke keyboard nav — re-fixed in Pass 2. Next: deploy checklist, then Phase 13 launch verification."
|
|
43
|
+
|
|
44
|
+
Not 47 rows. The signal, compressed.
|
|
45
|
+
|
|
46
|
+
### 4. Per-Task File Lists
|
|
47
|
+
|
|
48
|
+
For each unit of work completed in the session, list the files created or modified. This lets the next session quickly scope what changed without running `git log --stat` across dozens of commits:
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
### Auth middleware refactor
|
|
52
|
+
- src/middleware/auth.ts (modified — added rate limiting)
|
|
53
|
+
- src/middleware/rate-limit.ts (created)
|
|
54
|
+
- tests/middleware/auth.test.ts (modified — 4 new tests)
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### 5. Vault File Format
|
|
58
|
+
|
|
59
|
+
Files live at `/logs/vault-YYYY-MM-DD.md` with YAML frontmatter:
|
|
60
|
+
|
|
61
|
+
```yaml
|
|
62
|
+
---
|
|
63
|
+
sealed: 2026-03-26T14:30:00Z
|
|
64
|
+
project: my-app
|
|
65
|
+
branch: main
|
|
66
|
+
commit: abc1234
|
|
67
|
+
session_focus: Security pass + UX fixes for Phase 10-11
|
|
68
|
+
---
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
The frontmatter enables programmatic reading by other commands (`/campaign`, `/current`, `/thumper`).
|
|
72
|
+
|
|
73
|
+
### 6. Pickup Prompt
|
|
74
|
+
|
|
75
|
+
Every vault produces a pickup prompt — a copyable block that the next session pastes to recover context immediately:
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
Read /logs/vault-2026-03-26.md for session context.
|
|
79
|
+
Then read /logs/build-state.md and /logs/campaign-state.md for operational state.
|
|
80
|
+
Resume from: Phase 12 deploy checklist — all review passes complete.
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
The pickup prompt is the vault's delivery mechanism. It's printed to console, not buried in a file.
|
|
84
|
+
|
|
85
|
+
## Integration Points
|
|
86
|
+
|
|
87
|
+
| Command | How It Uses the Vault |
|
|
88
|
+
|---------|----------------------|
|
|
89
|
+
| `/campaign` | Reads most recent vault at Step 0 (state recovery). Seals a vault at campaign pause/end. |
|
|
90
|
+
| `/debrief` | Vault provides session context for Bashir's post-mortem analysis. |
|
|
91
|
+
| `/thumper` | `--for trigger` format enables automated session pickup via Telegram bridge. |
|
|
92
|
+
| `/current` | Deep Current reads vault history to track session-over-session progress. |
|
|
93
|
+
| Session start | User pastes pickup prompt. Agent reads vault. Context recovered. |
|
|
94
|
+
|
|
95
|
+
## When to Seal a Vault
|
|
96
|
+
|
|
97
|
+
- **End of session** — Always. Even short sessions produce decisions worth preserving.
|
|
98
|
+
- **Before context checkpoint** — If approaching 70%+ context usage, seal first.
|
|
99
|
+
- **Campaign pause** — When `/campaign` pauses between missions across sessions.
|
|
100
|
+
- **Before destructive operations** — Before `git reset`, branch switches, or major refactors.
|
|
101
|
+
|
|
102
|
+
### 7. Operational Learnings Sync
|
|
103
|
+
|
|
104
|
+
At session end, before sealing the vault, check for approved operational learnings from this session:
|
|
105
|
+
|
|
106
|
+
1. If `/debrief` ran and produced approved learnings → they're already in `docs/LEARNINGS.md`
|
|
107
|
+
2. If no debrief ran but the session discovered operational facts (API quirks, decision rationale, root causes that took multiple attempts) → Seldon flags candidates using the same criteria as FIELD_MEDIC.md Step 2.5
|
|
108
|
+
3. Present candidates to user for approval. Append approved entries to `docs/LEARNINGS.md`
|
|
109
|
+
4. Include in the vault's "Open Items" section: *"[N] operational learnings added to LEARNINGS.md this session"*
|
|
110
|
+
|
|
111
|
+
This ensures learnings are captured even in sessions that don't run a formal debrief. The vault is the last checkpoint — if a learning was discovered but not captured by debrief, the vault catches it.
|
|
112
|
+
|
|
113
|
+
**Do NOT duplicate LEARNINGS.md content in the vault narrative.** The vault references the file; the file holds the structured entries. The vault says "3 learnings captured" — it doesn't repeat them. See ADR-035 for the full design rationale.
|
|
114
|
+
|
|
115
|
+
## Anti-Patterns
|
|
116
|
+
|
|
117
|
+
- **Vault as transcript** — Don't dump the session log. Compress to signal.
|
|
118
|
+
- **Vault as documentation** — Don't write docs in the vault. Write docs in `/docs/`, reference them from the vault.
|
|
119
|
+
- **Vault without pickup prompt** — A vault file nobody reads is wasted. The pickup prompt is mandatory.
|
|
120
|
+
- **Stale vaults** — Vaults older than 7 days are historical, not operational. The next session should read the most recent vault, not the oldest.
|