speckeeper 0.8.1 → 0.9.1

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/README.md CHANGED
@@ -11,20 +11,28 @@
11
11
  Requirements and design documents often drift from implementation. **speckeeper** treats specifications as **code** — type-safe, version-controlled, and continuously validated against your actual artifacts (tests, OpenAPI, DDL, IaC).
12
12
 
13
13
  ```
14
- Mermaid flowchart ──► speckeeper scaffold ──► design/_models/
15
- │
16
- design/*.ts ─────────────────────────────► Validation & Consistency Checks
14
+ speckeeper.config.ts (sources)
17
15
  │
18
- ├─► speckeeper lint → Design integrity (IDs, references, phase gates)
19
- ├─► speckeeper check → External SSOT validation (test coverage, etc.)
20
- └─► speckeeper impact → Change impact analysis with traceability
16
+ ├─► Global Source Scan → Find spec IDs in OpenAPI / DDL / annotations
17
+ │ │
18
+ │ ▼
19
+ │ MatchMap (specId → matches)
20
+ │ │
21
+ │ ▼
22
+ ├─► Deep Validation → Model-level structural checks (optional)
23
+ │
24
+ design/*.ts
25
+ │
26
+ ├─► speckeeper lint → Design integrity (IDs, references, phase gates)
27
+ ├─► speckeeper check → External SSOT validation (global scan + deep validation)
28
+ └─► speckeeper impact → Change impact analysis with traceability
21
29
  ```
22
30
 
23
31
  ## Features
24
32
 
25
33
  - **TypeScript as SSOT** — Define requirements, architecture, and design in type-safe TypeScript
26
34
  - **Design validation** — Lint rules for ID uniqueness, reference integrity, circular dependencies, and phase gates
27
- - **External SSOT validation** — Check consistency with test files, and custom checkers for OpenAPI, DDL, etc.
35
+ - **External SSOT validation** — Global scan across OpenAPI, DDL, annotations; optional deep validation per model
28
36
  - **Traceability** — Track relationships across model levels (L0-L3) with impact analysis
29
37
  - **Scaffold from Mermaid** — Generate `_models/` skeletons from a mermaid flowchart with class-based artifact resolution
30
38
  - **Custom models** — Extend with domain-specific models (Runbooks, Policies, etc.)
@@ -78,10 +86,9 @@ flowchart TB
78
86
  Key concepts:
79
87
  - `class ... speckeeper` marks nodes as managed by speckeeper
80
88
  - Additional `class` lines assign **artifact classes** (determines model name/file and node grouping)
81
- - External node classes (`openapi`, `sqlschema`, `test`) determine checker bindings
89
+ - External node classes (`openapi`, `sqlschema`, `test`) describe the artifact type
82
90
  - `subgraph` determines model level (L0–L3)
83
- - `implements` edges trigger external SSOT validation
84
- - `verifiedBy` edges trigger test verification
91
+ - `implements`/`verifiedBy` edges define the relationship semantics
85
92
 
86
93
  ### 2. Scaffold models
87
94
 
@@ -90,7 +97,7 @@ npx speckeeper scaffold --source requirements.md
90
97
  ```
91
98
 
92
99
  This generates:
93
- - `design/_models/` — Model classes with base schema, lint rules, and `annotationChecker` bindings derived from `implements`/`verifiedBy` edges
100
+ - `design/_models/` — Model classes with base schema and lint rules
94
101
  - `design/*.ts` — Spec data files using `defineSpecs()`
95
102
  - `design/index.ts` — Entry point via `mergeSpecs()`
96
103
 
@@ -183,11 +190,64 @@ Checks include:
183
190
 
184
191
  ### External SSOT Validation (check)
185
192
 
186
- Validate your specifications against actual implementation artifacts. speckeeper scans source and test files for **annotation comments** (`@verifies`, `@implements`, `@traces`) to automatically detect which specs are covered — no manual relation wiring needed.
193
+ Validate your specifications against actual implementation artifacts. speckeeper performs a **global source scan** across all configured sources, then optionally runs **deep validation** using model-specific rules.
194
+
195
+ The check flow has three levels:
196
+
197
+ 1. **Existence check** (automatic) — Is the spec ID found in any configured source?
198
+ 2. **Structural check** (via `deepValidation`) — Does the matched object's structure match? (e.g. HTTP method, table columns)
199
+ 3. **Type check** (via `deepValidation`) — Do types match? (e.g. parameter types, column types)
200
+
201
+ #### Source configuration
202
+
203
+ Define global scan sources in `speckeeper.config.ts`:
204
+
205
+ ```typescript
206
+ // speckeeper.config.ts
207
+ import { defineConfig } from 'speckeeper';
208
+
209
+ export default defineConfig({
210
+ // ...
211
+ sources: [
212
+ {
213
+ type: 'openapi',
214
+ paths: ['api/openapi.yaml'],
215
+ relation: 'implements',
216
+ },
217
+ {
218
+ type: 'ddl',
219
+ paths: ['db/schema.sql'],
220
+ relation: 'implements',
221
+ },
222
+ {
223
+ type: 'annotation',
224
+ paths: ['test/**/*.test.ts', 'tests/**/*.test.ts'],
225
+ relation: 'verifiedBy',
226
+ },
227
+ {
228
+ type: 'annotation',
229
+ paths: ['src/**/*.ts'],
230
+ exclude: ['src/**/*.test.ts'],
231
+ relation: 'implements',
232
+ },
233
+ ],
234
+ });
235
+ ```
236
+
237
+ Each source defines:
238
+ - **`type`** — Built-in (`'openapi'`, `'ddl'`, `'annotation'`) or custom with a `scanner` plugin
239
+ - **`paths`** — Glob patterns for files to scan
240
+ - **`relation`** — Whether matches represent `'implements'` or `'verifiedBy'`
241
+
242
+ #### Built-in scanners
187
243
 
188
- #### Annotation-based auto-detection
244
+ | Scanner | Finds spec IDs via | Deep validation |
245
+ |---------|-------------------|-----------------|
246
+ | `openapi` | operationId, path segment, schema name, `x-spec-id` | HTTP method, parameter names/types, response property names/types |
247
+ | `ddl` | Table name (case-insensitive, schema-prefix stripped) | Column names, column types (containment-based) |
248
+ | `annotation` | `@verifies`, `@implements`, `@traces` annotations | — |
189
249
 
190
- Add annotations to your source and test files:
250
+ Annotations work in any comment style (`//`, `#`, `--`, `/* */`, `<!-- -->`). Multiple IDs can be comma- or space-separated.
191
251
 
192
252
  ```typescript
193
253
  // tests/unit/auth.test.ts
@@ -201,82 +261,93 @@ describe('User Authentication', () => { ... });
201
261
  export class AuthHandler { ... }
202
262
  ```
203
263
 
204
- speckeeper scans for these annotations and automatically links specs to their implementation and tests. Annotations work in any comment style (`//`, `#`, `--`, `/* */`, `<!-- -->`).
205
-
206
- #### Artifact configuration
264
+ #### Deep validation (optional)
207
265
 
208
- Define scan targets per artifact class in your config:
266
+ Models can define `deepValidation` to enable Level 2/3 structural checks on matched source objects:
209
267
 
210
268
  ```typescript
211
- // speckeeper.config.ts
212
- export default defineConfig({
213
- // ...
214
- artifacts: {
215
- test: {
216
- globs: ['test/**/*.test.ts', 'tests/**/*.test.ts'],
217
- contentPatterns: [/@verifies\s+([\w-]+(?:[,\s]+[\w-]+)*)/],
218
- },
219
- typescript: {
220
- globs: ['src/**/*.ts'],
221
- exclude: ['src/**/*.test.ts', 'src/**/*.d.ts'],
222
- contentPatterns: [/@implements\s+([\w-]+(?:[,\s]+[\w-]+)*)/],
269
+ class EntityModel extends Model<typeof EntitySchema> {
270
+ // ... schema, lintRules, etc.
271
+
272
+ protected deepValidation: DeepValidationConfig<Entity> = {
273
+ ddl: {
274
+ mapper: (spec) => ({
275
+ tableName: spec.tableName,
276
+ columns: spec.columns.map(c => ({ name: c.name, type: c.type })),
277
+ checkTypes: true,
278
+ }),
223
279
  },
224
280
  openapi: {
225
- globs: ['api/openapi.yaml'],
281
+ mapper: (spec) => ({
282
+ path: spec.apiPath,
283
+ method: spec.httpMethod,
284
+ responseProperties: spec.fields.map(f => ({ name: f.name, type: f.type })),
285
+ }),
226
286
  },
227
- },
228
- });
287
+ };
288
+ }
229
289
  ```
230
290
 
231
- Scaffold auto-generates this config based on your Mermaid flowchart's external nodes and their artifact classes.
291
+ Without `deepValidation`, speckeeper still performs existence checks for all spec IDs across all configured sources.
232
292
 
233
- #### Checker factories
293
+ #### Lookup keys (when spec ID differs from external identifier)
234
294
 
235
- | Factory | Type | Validates |
236
- |---------|------|-----------|
237
- | `annotationChecker()` | Generic | Scans files for `@verifies`/`@implements`/`@traces` annotations matching spec IDs |
238
- | `annotationCoverage()` | Coverage | Computes coverage from annotation scan results (no manual relations needed) |
239
- | `externalOpenAPIChecker()` | Specialized | OpenAPI spec: operationId, path, schema, x-spec-id, HTTP method, parameter/response types |
240
- | `externalSqlSchemaChecker()` | Specialized | SQL schema: table existence, column existence, type containment |
241
-
242
- `annotationChecker()` is the generic checker. Specialized checkers (`externalOpenAPIChecker`, `externalSqlSchemaChecker`) extend it with source-level parsing for deeper validation. Scaffold generates the appropriate checker binding based on your artifact classes.
295
+ By default, the global scanner searches for each spec's `id` in external sources. When the external identifier differs — for example, entity ID `"user"` vs DDL table name `"users"` — define `lookupKeys` on the model to map per source type:
243
296
 
244
297
  ```typescript
245
- // design/_models/requirement.ts
246
- import { annotationChecker } from 'speckeeper/dsl';
298
+ class EntityModel extends Model<typeof EntitySchema> {
299
+ readonly id = 'entity';
300
+ readonly name = 'Entity';
301
+ readonly idPrefix = 'ENT';
302
+ readonly schema = EntitySchema;
303
+
304
+ protected lookupKeys: LookupKeyConfig<Entity> = {
305
+ ddl: (spec) => spec.tableName,
306
+ openapi: (spec) => spec.schemaName ?? spec.id,
307
+ };
308
+ }
309
+ ```
247
310
 
248
- class RequirementModel extends Model<typeof RequirementSchema> {
249
- // ... schema, lintRules, etc.
311
+ With this configuration, when scanning DDL sources the scanner searches for `spec.tableName` instead of `spec.id`. If a match is found, the result is mapped back to the original spec ID for reporting and deep validation.
250
312
 
251
- protected externalChecker = annotationChecker<Requirement>({
252
- checks: [
253
- { artifact: 'test', relationType: 'verifiedBy' },
254
- { artifact: 'typescript', relationType: 'implements' },
255
- ],
256
- });
257
- }
313
+ `lookupKeys` is optional per source type — any source type not listed falls back to `spec.id`.
314
+
315
+ #### Custom scanners
316
+
317
+ For file formats not covered by the built-in scanners, provide a custom `SourceScanner` plugin:
318
+
319
+ ```typescript
320
+ // speckeeper.config.ts
321
+ import { defineConfig } from 'speckeeper';
322
+ import type { SourceScanner } from 'speckeeper';
323
+
324
+ const protoScanner: SourceScanner = {
325
+ findSpecIds(content, specIds, filePath) {
326
+ // Parse protobuf content, find spec IDs in service/message names
327
+ // Return SourceMatch[] with specId, location, and optional context
328
+ return [];
329
+ },
330
+ };
331
+
332
+ export default defineConfig({
333
+ sources: [
334
+ { type: 'proto', paths: ['proto/**/*.proto'], relation: 'implements', scanner: protoScanner },
335
+ // ... other sources
336
+ ],
337
+ });
258
338
  ```
259
339
 
260
340
  ```bash
261
- $ npx speckeeper check test --coverage
341
+ $ npx speckeeper check --verbose
262
342
 
263
343
  speckeeper check
264
344
 
265
345
  Design: design/
266
- Type: test
267
-
268
- Scanning artifacts...
269
- test: 12 @verifies annotations in 8 files
270
- typescript: 5 @implements annotations in 4 files
346
+ Type: all
271
347
 
272
348
  ✓ All checks passed
273
-
274
- Coverage: Requirement (verifiedBy → test)
275
- Coverage: 100% (7/7 requirements verified)
276
349
  ```
277
350
 
278
- You can also implement custom checkers for any external source by defining an `ExternalChecker<T>` directly. See [Model Definition Guide](./docs/model-guide.md) for details.
279
-
280
351
  ## Model Levels & Traceability
281
352
 
282
353
  speckeeper organizes models by abstraction level:
@@ -354,7 +425,7 @@ class RunbookModel extends Model<typeof RunbookSchema> {
354
425
  }
355
426
  ```
356
427
 
357
- Core DSL factories (`speckeeper/dsl`) include `requireField`, `arrayMinLength`, `idFormat`, `childIdFormat`, `markdownExporter`, `annotationChecker`, `annotationCoverage`, `externalOpenAPIChecker`, `externalSqlSchemaChecker`, `relationCoverage`, and `baseSpecSchema`.
428
+ Core DSL factories (`speckeeper/dsl`) include `requireField`, `arrayMinLength`, `idFormat`, `childIdFormat`, `markdownExporter`, `annotationCoverage`, `relationCoverage`, and `baseSpecSchema`. Global scanner utilities (`openapiScanner`, `ddlScanner`, `annotationScanner`, `createAnnotationScanner`) are also re-exported for advanced use.
358
429
 
359
430
  ## Documentation
360
431