qfai 1.9.2 → 1.10.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.
Files changed (123) hide show
  1. package/README.md +48 -2
  2. package/assets/init/.qfai/assistant/agents/acceptance-test-engineer.md +1 -0
  3. package/assets/init/.qfai/assistant/agents/backend-engineer.md +1 -0
  4. package/assets/init/.qfai/assistant/agents/completion-reviewer.md +13 -2
  5. package/assets/init/.qfai/assistant/agents/delivery-planner.md +9 -0
  6. package/assets/init/.qfai/assistant/agents/frontend-engineer.md +1 -0
  7. package/assets/init/.qfai/assistant/agents/implementation-reviewer.md +6 -0
  8. package/assets/init/.qfai/assistant/agents/orchestrator.md +2 -2
  9. package/assets/init/.qfai/assistant/agents/qa-gatekeeper.md +96 -3
  10. package/assets/init/.qfai/assistant/agents/test-design-analyst.md +20 -3
  11. package/assets/init/.qfai/assistant/catalog/cli-ux-guidelines.md +2 -2
  12. package/assets/init/.qfai/assistant/catalog/spec_required_files.json +2 -1
  13. package/assets/init/.qfai/assistant/catalog/test-layers.md +355 -14
  14. package/assets/init/.qfai/assistant/catalog/worklog-entry.schema.md +165 -0
  15. package/assets/init/.qfai/assistant/constitution/communication.md +1 -1
  16. package/assets/init/.qfai/assistant/constitution/drift-protocol.md +304 -10
  17. package/assets/init/.qfai/assistant/constitution/quality.md +35 -5
  18. package/assets/init/.qfai/assistant/constitution/requirements-decomposition.md +37 -0
  19. package/assets/init/.qfai/assistant/constitution/shared-skill-delegation-baseline.md +244 -8
  20. package/assets/init/.qfai/assistant/constitution/shared-skill-operating-baseline.md +122 -5
  21. package/assets/init/.qfai/assistant/constitution/workflow.md +53 -7
  22. package/assets/init/.qfai/assistant/manifest/agent-catalog.yml +316 -945
  23. package/assets/init/.qfai/assistant/manifest/agent-routing.yml +50 -4
  24. package/assets/init/.qfai/assistant/manifest/review-profiles.yml +9 -0
  25. package/assets/init/.qfai/assistant/process/migrations/v1.4.27-atdd-alignment.md +1 -1
  26. package/assets/init/.qfai/assistant/skills/qfai-atdd/SKILL.md +61 -21
  27. package/assets/init/.qfai/assistant/skills/qfai-atdd/references/test-case-depth-checklist.md +23 -4
  28. package/assets/init/.qfai/assistant/skills/qfai-configure/SKILL.md +15 -7
  29. package/assets/init/.qfai/assistant/skills/qfai-discussion/SKILL.md +8 -4
  30. package/assets/init/.qfai/assistant/skills/qfai-discussion/references/design-md-brand-catalog.md +2 -2
  31. package/assets/init/.qfai/assistant/skills/qfai-discussion/references/discussion-completion-matrix.md +17 -7
  32. package/assets/init/.qfai/assistant/skills/qfai-discussion/references/rcp_footer.md +10 -4
  33. package/assets/init/.qfai/assistant/skills/qfai-discussion/references/review-cycle-playbook.md +1 -1
  34. package/assets/init/.qfai/assistant/skills/qfai-discussion/references/ui-bearing-playbook.md +4 -4
  35. package/assets/init/.qfai/assistant/skills/qfai-discussion/references/ui_ux/review_audit_playbook.md +1 -1
  36. package/assets/init/.qfai/assistant/skills/qfai-discussion/references/ui_ux/trend_scan_playbook.md +1 -1
  37. package/assets/init/.qfai/assistant/skills/qfai-discussion/references/ui_ux_best_practices.md +17 -7
  38. package/assets/init/.qfai/assistant/skills/qfai-discussion/templates/01_Context.md +1 -1
  39. package/assets/init/.qfai/assistant/skills/qfai-discussion/templates/02_Inception-Deck.md +1 -1
  40. package/assets/init/.qfai/assistant/skills/qfai-discussion/templates/03_Story-Workshop.md +11 -3
  41. package/assets/init/.qfai/assistant/skills/qfai-discussion/templates/05_Scope.md +5 -2
  42. package/assets/init/.qfai/assistant/skills/qfai-discussion/templates/07_NFR.md +1 -1
  43. package/assets/init/.qfai/assistant/skills/qfai-discussion/templates/09_Constraints.md +7 -4
  44. package/assets/init/.qfai/assistant/skills/qfai-discussion/templates/10_Policy.md +1 -1
  45. package/assets/init/.qfai/assistant/skills/qfai-discussion/templates/11_OQ-Register.md +1 -1
  46. package/assets/init/.qfai/assistant/skills/qfai-discussion/templates/12_OQ-Resolution-Log.md +1 -1
  47. package/assets/init/.qfai/assistant/skills/qfai-discussion/templates/14_Review-Request.md +14 -7
  48. package/assets/init/.qfai/assistant/skills/qfai-discussion/templates/99_delta.md +1 -1
  49. package/assets/init/.qfai/assistant/skills/qfai-discussion/templates/review/Rxx_reviewer.md +16 -7
  50. package/assets/init/.qfai/assistant/skills/qfai-discussion/templates/review/review_request.md +9 -6
  51. package/assets/init/.qfai/assistant/skills/qfai-discussion/templates/uiux/40_screen_contracts.md +3 -2
  52. package/assets/init/.qfai/assistant/skills/qfai-discussion/templates/uiux/50_review_input_bundle.md +4 -2
  53. package/assets/init/.qfai/assistant/skills/qfai-implement/SKILL.md +250 -128
  54. package/assets/init/.qfai/assistant/skills/qfai-implement/references/change-request-reset.md +93 -0
  55. package/assets/init/.qfai/assistant/skills/qfai-implement/references/checkpoint-verification.md +106 -0
  56. package/assets/init/.qfai/assistant/skills/qfai-implement/references/cross-spec-ownership.md +73 -0
  57. package/assets/init/.qfai/assistant/skills/qfai-implement/references/evidence-revision.md +77 -0
  58. package/assets/init/.qfai/assistant/skills/qfai-implement/references/execution-ledger.md +303 -0
  59. package/assets/init/.qfai/assistant/skills/qfai-implement/references/final-checklist.md +19 -0
  60. package/assets/init/.qfai/assistant/skills/qfai-implement/references/finding-classification.md +49 -0
  61. package/assets/init/.qfai/assistant/skills/qfai-implement/references/ledger-preconditions.md +55 -0
  62. package/assets/init/.qfai/assistant/skills/qfai-implement/references/oracle-strength.md +81 -0
  63. package/assets/init/.qfai/assistant/skills/qfai-implement/references/parallelization-policy.md +235 -0
  64. package/assets/init/.qfai/assistant/skills/qfai-implement/references/red-admissibility.md +91 -0
  65. package/assets/init/.qfai/assistant/skills/qfai-implement/references/red-not-observable.md +70 -0
  66. package/assets/init/.qfai/assistant/skills/qfai-implement/references/relevant-test-suite.md +87 -0
  67. package/assets/init/.qfai/assistant/skills/qfai-implement/references/review-artifact-layout.md +31 -0
  68. package/assets/init/.qfai/assistant/skills/qfai-implement/references/round-evidence.md +102 -0
  69. package/assets/init/.qfai/assistant/skills/qfai-implement/references/selector-granularity.md +24 -0
  70. package/assets/init/.qfai/assistant/skills/qfai-implement/references/volume-policy.md +149 -0
  71. package/assets/init/.qfai/assistant/skills/qfai-prototyping/SKILL.md +35 -18
  72. package/assets/init/.qfai/assistant/skills/qfai-prototyping/references/evidence-requirements.md +1 -1
  73. package/assets/init/.qfai/assistant/skills/qfai-prototyping/references/generator-prompt.md +106 -7
  74. package/assets/init/.qfai/assistant/skills/qfai-prototyping/references/handoff.md +40 -11
  75. package/assets/init/.qfai/assistant/skills/qfai-prototyping/references/iteration-loop.md +48 -1
  76. package/assets/init/.qfai/assistant/skills/qfai-prototyping/templates/DESIGN.md.sample +6 -0
  77. package/assets/init/.qfai/assistant/skills/qfai-sdd/SKILL.md +82 -22
  78. package/assets/init/.qfai/assistant/skills/qfai-sdd/references/contract-artifact-rules.md +148 -0
  79. package/assets/init/.qfai/assistant/skills/qfai-sdd/references/rcp_footer.md +10 -4
  80. package/assets/init/.qfai/assistant/skills/qfai-sdd/references/review-cycle-playbook.md +1 -1
  81. package/assets/init/.qfai/assistant/skills/qfai-sdd/references/sdd-execution-playbook.md +4 -2
  82. package/assets/init/.qfai/assistant/skills/qfai-sdd/references/sdd-phase-checklists.md +18 -0
  83. package/assets/init/.qfai/assistant/skills/qfai-sdd/references/sdd-quality-gate.md +44 -3
  84. package/assets/init/.qfai/assistant/skills/qfai-sdd/references/sdd-triage.md +60 -7
  85. package/assets/init/.qfai/assistant/skills/qfai-sdd/references/spec-traceability-rules.md +157 -5
  86. package/assets/init/.qfai/assistant/skills/qfai-sdd/templates/change-request.md +125 -0
  87. package/assets/init/.qfai/assistant/skills/qfai-sdd/templates/contracts/db-contract.sample.sql +6 -0
  88. package/assets/init/.qfai/assistant/skills/qfai-sdd/templates/evidence/sdd-spec.md +92 -0
  89. package/assets/init/.qfai/assistant/skills/qfai-sdd/templates/specs/_policies/01_Objective.md +27 -0
  90. package/assets/init/.qfai/assistant/skills/qfai-sdd/templates/specs/_policies/02_Initiative.md +30 -0
  91. package/assets/init/.qfai/assistant/skills/qfai-sdd/templates/specs/_policies/05_Contracts.md +16 -6
  92. package/assets/init/.qfai/assistant/skills/qfai-sdd/templates/specs/_policies/06_Glossary.md +19 -0
  93. package/assets/init/.qfai/assistant/skills/qfai-sdd/templates/specs/_policies/07_Constraints.md +25 -0
  94. package/assets/init/.qfai/assistant/skills/qfai-sdd/templates/specs/_policies/08_Decisions.md +22 -2
  95. package/assets/init/.qfai/assistant/skills/qfai-sdd/templates/specs/_policies/11_Slice-Policy.md +37 -10
  96. package/assets/init/.qfai/assistant/skills/qfai-sdd/templates/specs/spec/02_User-stories.md +20 -0
  97. package/assets/init/.qfai/assistant/skills/qfai-sdd/templates/specs/spec/03_Acceptance-Criteria.md +19 -0
  98. package/assets/init/.qfai/assistant/skills/qfai-sdd/templates/specs/spec/04_Business-Rules.md +32 -3
  99. package/assets/init/.qfai/assistant/skills/qfai-sdd/templates/specs/spec/06_Test-Cases.md +56 -0
  100. package/assets/init/.qfai/assistant/skills/qfai-sdd/templates/specs/spec/07_Decisions.md +29 -2
  101. package/assets/init/.qfai/assistant/skills/qfai-sdd/templates/specs/spec/10_Plan.md +41 -0
  102. package/assets/init/.qfai/assistant/skills/qfai-sdd/templates/specs/spec/16_Traceability-ledger.md +58 -0
  103. package/assets/init/.qfai/assistant/skills/qfai-sdd/templates/specs/spec/tdd/test-list.md +56 -0
  104. package/assets/init/.qfai/assistant/skills/qfai-verify/SKILL.md +57 -102
  105. package/assets/init/.qfai/assistant/skills/qfai-verify/references/articles.md +24 -0
  106. package/assets/init/.qfai/assistant/skills/qfai-verify/references/context-load.md +22 -0
  107. package/assets/init/.qfai/assistant/skills/qfai-verify/references/verify-output-contract.md +48 -0
  108. package/assets/init/.qfai/assistant/skills/qfai-verify/templates/verify-evidence.md +48 -0
  109. package/assets/init/.qfai/assistant/skills/web-research/SKILL.md +25 -7
  110. package/assets/init/.qfai/waivers.yml +11 -5
  111. package/assets/init/root/DESIGN.md +6 -0
  112. package/assets/init/root/qfai.config.yaml +15 -12
  113. package/dist/cli/index.cjs +11023 -7139
  114. package/dist/cli/index.cjs.map +1 -1
  115. package/dist/cli/index.mjs +10963 -7080
  116. package/dist/cli/index.mjs.map +1 -1
  117. package/dist/index.cjs +8782 -5257
  118. package/dist/index.cjs.map +1 -1
  119. package/dist/index.d.cts +280 -8
  120. package/dist/index.d.ts +280 -8
  121. package/dist/index.mjs +11776 -8264
  122. package/dist/index.mjs.map +1 -1
  123. package/package.json +18 -19
package/dist/index.d.cts CHANGED
@@ -27,6 +27,12 @@ type Issue = {
27
27
  suppressed?: boolean;
28
28
  suggested_action?: string;
29
29
  file?: string;
30
+ /**
31
+ * Every other file this finding implicates, when `file` is only a
32
+ * representative (a duplicate ID is defined in N files but reported once).
33
+ * `--spec` scoping keeps the finding if any of these is in scope.
34
+ */
35
+ relatedFiles?: string[];
30
36
  refs?: string[];
31
37
  rule?: string;
32
38
  loc?: IssueLocation;
@@ -169,8 +175,10 @@ type QfaiPrototypingExecutionConfig = {
169
175
  *
170
176
  * Accepted values during the deprecation window:
171
177
  * - `"playwright"` (primary, post-1.9.x default).
172
- * - `"playwright-cli"` (deprecated; sunset 1.10.0). When chosen,
173
- * the doctor probe emits `D-DEPRECATED-PROBE` (severity warning).
178
+ * - `"playwright-cli"` (deprecated; sunset `SUNSETS.playwrightCli`).
179
+ * Inside the window the doctor probe emits `D-DEPRECATED-PROBE` at
180
+ * `warning`; from the sunset onwards `normalizePrototypingExecution`
181
+ * rejects the value and the probe reports `error`.
174
182
  *
175
183
  * At sunset only `"playwright"` is accepted.
176
184
  */
@@ -246,7 +254,7 @@ declare function loadConfig(root: string): Promise<ConfigLoadResult>;
246
254
  declare function resolvePath(root: string, config: QfaiConfig, key: ConfigPathKey): string;
247
255
 
248
256
  type AtddTestKind = "e2e" | "api" | "integration";
249
- type AtddUnknownRefKind = "us" | "tc" | "conApi";
257
+ type AtddUnknownRefKind = "us" | "tc" | "conApi" | "conDb";
250
258
  type AtddUnknownRef = {
251
259
  file: string;
252
260
  token: string;
@@ -267,27 +275,109 @@ type AtddTraceabilityMissing = {
267
275
  us: string[];
268
276
  tc: string[];
269
277
  conApi: string[];
278
+ conDb: string[];
270
279
  };
271
280
  type AtddCodeTraceabilityResult = {
272
281
  specsRoot: string;
273
282
  contractsApiRoot: string;
274
283
  specUsIds: Map<string, Set<string>>;
275
284
  specTcIds: Map<string, Set<string>>;
285
+ /**
286
+ * Every declared `CON-API-*`, active and deferred alike. This is the public
287
+ * meaning the field has always had — adding `x-qfai-status: planned` defers
288
+ * the test obligation, it does not un-declare the contract, so an external
289
+ * consumer using this set for "is this ID declared?" must keep seeing it.
290
+ */
276
291
  apiContractIds: Set<string>;
292
+ /** The subset that carries the `QFAI-ATDD-113` obligation. */
293
+ activeApiContractIds: Set<string>;
294
+ /**
295
+ * `CON-API-*` IDs excluded from the `QFAI-ATDD-113` obligation because their
296
+ * contract declares `x-qfai-status: planned`. Reported as `info` so the
297
+ * deferral stays visible instead of silently shrinking the gate.
298
+ */
299
+ deferredApiContractIds: Set<string>;
300
+ contractsDbRoot: string;
301
+ /** Every declared `CON-DB-*`, active and deferred alike. */
302
+ dbContractIds: Set<string>;
303
+ /** The subset that carries the `QFAI-ATDD-115` obligation. */
304
+ activeDbContractIds: Set<string>;
305
+ /** `CON-DB-*` deferred by `-- x-qfai-status: planned`; reported at `info`. */
306
+ deferredDbContractIds: Set<string>;
277
307
  refs: {
278
308
  us: AtddSpecRefs;
279
309
  tc: AtddSpecRefs;
280
310
  api: Map<string, Set<string>>;
311
+ /**
312
+ * `CON-DB-*` references found in integration tests. L3 Integration is the
313
+ * layer whose declared scope is real-infrastructure integration including
314
+ * the database, so it is the one that can actually exercise a DB contract.
315
+ */
316
+ db: Map<string, Set<string>>;
281
317
  };
282
318
  unknown: AtddUnknownRef[];
283
319
  forbidden: {
284
320
  tcInApi: AtddForbiddenRef[];
285
321
  tcInE2e: AtddForbiddenRef[];
322
+ /** TC annotated under integration although its declared Level routes elsewhere. */
323
+ tcInIntegration: AtddForbiddenRef[];
286
324
  };
287
325
  missing: AtddTraceabilityMissing;
326
+ /**
327
+ * Formatted missing TC ref -> the test kind its declared `Level` routes to.
328
+ * Lets the CLI phrase `QFAI-ATDD-112` (message, `suggested_action`, report)
329
+ * per declared layer instead of naming `tests/integration/**` for every TC.
330
+ */
331
+ missingTcHomes: Map<string, AtddTestKind>;
332
+ /** Test files outside the scanned roots; surfaced instead of dropped. */
333
+ skippedTestFiles: string[];
288
334
  scan: AtddTraceabilityScan;
289
335
  };
336
+ /** Test directory each `AtddTestKind` owns, for user-facing messages. */
337
+ declare const ATDD_TEST_KIND_DIRS: Record<AtddTestKind, string>;
338
+ /**
339
+ * The same map rendered against the project's configured `paths.testsDir`.
340
+ *
341
+ * The scan already follows `testsDir`, so a project that renamed it to e.g.
342
+ * `spec-tests` would otherwise be told by `QFAI-ATDD-112` to annotate
343
+ * `tests/api/**` — a directory the scan never reads, leaving the finding
344
+ * unclearable. A root-level layout (`testsDir: "."`) is the same trap in the
345
+ * other direction: the scan reads `api/**` at the repository root, so the
346
+ * `tests/` segment must be dropped rather than kept.
347
+ * {@link ATDD_TEST_KIND_DIRS} stays as the default-shaped fallback for callers
348
+ * with no config in hand.
349
+ */
350
+ declare function atddTestKindDirs(testsDirRelative: string): Record<AtddTestKind, string>;
290
351
  declare function evaluateAtddCodeTraceability(root: string, config: QfaiConfig): Promise<AtddCodeTraceabilityResult>;
352
+ declare const PLANNED_CONTRACT_KEY = "x-qfai-status";
353
+ /**
354
+ * True when the contract declares itself not yet implemented.
355
+ *
356
+ * `/qfai-sdd` authors contracts in Phase 0 (Contracts-first) but slices them in
357
+ * Phase 2, so between the second contract and the last slice every declared
358
+ * `CON-API-*` would otherwise be a `QFAI-ATDD-113` error. The marker makes the
359
+ * deferral explicit and reviewable in the contract itself.
360
+ *
361
+ * The marker is only honoured at the **document root**. A text scan that
362
+ * accepted any indentation would let an `x-qfai-status: planned` on a single
363
+ * OpenAPI operation defer the whole file, silently dropping the API-test
364
+ * obligation for every other `CON-API-*` it declares. The document is therefore
365
+ * parsed (YAML is a superset of JSON, so both contract formats go through the
366
+ * same path) and only a top-level key counts. An unparseable document falls
367
+ * back to a column-0 text match, which cannot see a nested key either.
368
+ */
369
+ declare function isPlannedApiContract(text: string): boolean;
370
+ /**
371
+ * Derives the per-layer file pattern from the project's configured
372
+ * `testFileGlobs`, so a non-JS repository is scanned with its own extensions.
373
+ *
374
+ * Configured globs describe whole paths (`tests/**\/*.py`); the ATDD scan needs
375
+ * a pattern to append under `tests/{e2e,api,integration}/`. The extension set is
376
+ * therefore lifted out of them, unioned with the structural annotation carriers
377
+ * above, and recombined. When no extension can be recovered, the JS/TS default
378
+ * is used.
379
+ */
380
+ declare function deriveAtddFilePattern(testFileGlobs: readonly string[]): string;
291
381
 
292
382
  type GuardrailType = "non-goal" | "not-now" | "trade-off";
293
383
  type DecisionGuardrailEntry = {
@@ -351,12 +441,77 @@ declare function filterDecisionGuardrailsByKeyword(items: DecisionGuardrail[], k
351
441
  declare function formatGuardrailsForLlm(items: DecisionGuardrail[], max: number): string;
352
442
  declare function checkDecisionGuardrails(entries: DecisionGuardrailEntry[]): GuardrailCheckResult;
353
443
 
354
- type IdPrefix = "CAP" | "SPEC" | "US" | "BR" | "SC" | "AC" | "CASE" | "UI" | "API" | "DB" | "THEMA";
355
- type IdFormatPrefix = IdPrefix | "ADR";
444
+ type IdPrefix = "CAP" | "SPEC" | "US" | "BR" | "SC" | "AC" | "EX" | "TC" | "CASE" | "UI" | "API" | "DB" | "THEMA";
445
+ /**
446
+ * Prefixes with a declared format but no membership in {@link ID_PREFIXES}.
447
+ *
448
+ * `DR` joins `ADR` here rather than in `ID_PREFIXES` because a Decision Record
449
+ * is not a spec-pack item: `extractAllIds` walks the layers a spec decomposes
450
+ * into, and sweeping `DR-*` into that walk would make every citation of a
451
+ * decision look like an undeclared spec item to the traceability rules.
452
+ *
453
+ * What was missing is the *format*. `qfai-implement` makes a non-empty `DR-ID`
454
+ * the hard precondition for the `exception` status and `tddList.ts` enforces it
455
+ * at `error`, but no ID class existed — so any non-empty string satisfied the
456
+ * gate, including a token the operator invented on the spot.
457
+ */
458
+ type IdFormatPrefix = IdPrefix | "ADR" | "DR";
356
459
  declare const ID_PREFIXES: IdPrefix[];
357
- declare function extractIds(text: string, prefix: IdPrefix): string[];
460
+ /**
461
+ * Every strict-format match for `prefix`.
462
+ *
463
+ * Takes {@link IdFormatPrefix}, not {@link IdPrefix}: `ADR` and `DR` have a
464
+ * declared format but are not spec-pack items, and a caller asking for one
465
+ * should not have to assert its way past the type. `extractAllIds` still walks
466
+ * {@link ID_PREFIXES} only, so the decomposition layers are unchanged.
467
+ */
468
+ declare function extractIds(text: string, prefix: IdFormatPrefix): string[];
358
469
  declare function extractAllIds(text: string): string[];
359
- declare function extractInvalidIds(text: string, prefixes: IdFormatPrefix[]): string[];
470
+ /**
471
+ * The one section whose fenced bodies are primary spec content: the v1421
472
+ * `03_Acceptance-Criteria.md` `## AC Gherkin (required)` block. Masking it
473
+ * would let a mistyped required definition (`# AC-0001-1`) reach
474
+ * `validateLayeredIdFormat` as if it did not exist.
475
+ */
476
+ declare const AC_GHERKIN_SECTION = "ac gherkin (required)";
477
+ type FenceMaskOptions = {
478
+ /**
479
+ * Normalized H2 heading (see {@link AC_GHERKIN_SECTION}) whose fenced bodies
480
+ * stay in the ID scan when their info string is a Gherkin dialect. Omitted:
481
+ * every fence body is masked.
482
+ */
483
+ scannedSection?: string;
484
+ };
485
+ /**
486
+ * Blanks the body of illustrative fenced code blocks while preserving the line
487
+ * count, so an ID-shaped token inside a sample or a diagram is not read as a
488
+ * spec ID and reported line numbers still point at the source file.
489
+ *
490
+ * Two properties matter:
491
+ *
492
+ * - A fence closes only on the **same marker character** at **at least the
493
+ * opening length**. A ```` ```` ```` block that quotes a ```` ``` ```` sample
494
+ * inside itself is legal markdown; toggling on any fence line would end the
495
+ * outer block early and re-expose the very sample it was hiding.
496
+ * - A fence keeps its body only when it is tagged with a
497
+ * `SCANNED_FENCE_LANGUAGES` info string **and** sits inside
498
+ * `options.scannedSection`. Keying on the language alone exempted every
499
+ * ```` ```gherkin ```` block in every layered file — including an
500
+ * illustration in a Purpose paragraph — which is the case the mask exists
501
+ * for. Only the required AC Gherkin section is the spec's own definition.
502
+ */
503
+ declare function maskFencedCodeBlocks(text: string, options?: FenceMaskOptions): string;
504
+ type InvalidIdOccurrence = {
505
+ id: string;
506
+ /** 1-based line number in the original text. */
507
+ line: number;
508
+ };
509
+ /**
510
+ * Finds ID-shaped tokens that do not match their prefix's canonical format,
511
+ * with the line each was first seen on. Fenced code blocks are excluded.
512
+ */
513
+ declare function extractInvalidIdOccurrences(text: string, prefixes: IdFormatPrefix[], options?: FenceMaskOptions): InvalidIdOccurrence[];
514
+ declare function extractInvalidIds(text: string, prefixes: IdFormatPrefix[], options?: FenceMaskOptions): string[];
360
515
  declare function extractSpecNumber(specId: string): string | null;
361
516
  declare function extractCapSpecNumber(capId: string): string | null;
362
517
  declare function extractUsSpecNumber(usId: string): string | null;
@@ -450,6 +605,20 @@ type ReportTraceability = {
450
605
  type ReportTestStrategy = {
451
606
  totalScenarios: number;
452
607
  limit: number;
608
+ /**
609
+ * Where the layer buckets came from.
610
+ *
611
+ * `scenario-tags` is the Gherkin `@layer-*` path, which only exists for the
612
+ * legacy `scenario.feature` layout. On the v1421 layered layout
613
+ * `examplesPath` is the **Markdown** `05_Examples.md`, so the parse failed,
614
+ * the error was swallowed by `continue`, and every bucket printed 0 — while
615
+ * the toolkit mandates layer routing and gates completion on it.
616
+ * `ledger-layer` is the `Layer` column of `tdd/test-list.md`, which is the
617
+ * artifact the shipped templates actually produce.
618
+ */
619
+ layerSource: "scenario-tags" | "ledger-layer" | "none";
620
+ /** Scenario files that failed to parse; reported instead of silently zeroed. */
621
+ unparsedScenarioFiles: string[];
453
622
  layer: Record<"unit" | "component" | "integration" | "api" | "e2e" | "none" | "unknown", number>;
454
623
  size: Record<"s" | "m" | "l" | "none" | "unknown", number>;
455
624
  missing: {
@@ -545,8 +714,12 @@ type ReportTddCoverageSpec = {
545
714
  specNumber: string;
546
715
  unitComponentTotal: number;
547
716
  doneCount: number;
717
+ /** Has a passing test, has not cleared its blocking reviewers / checkpoint. */
718
+ inReviewCount: number;
548
719
  exceptionCount: number;
549
720
  openCount: number;
721
+ /** Open rows that cannot be started, reported apart from "not started yet". */
722
+ blockedCount: number;
550
723
  missingTcRefs: string[];
551
724
  exceptionRows: Array<{
552
725
  tddId: string;
@@ -699,6 +872,12 @@ declare function formatReportJson(data: ReportData): string;
699
872
  type ValidationOptions = {
700
873
  profile?: ValidationProfile;
701
874
  platform?: string;
875
+ /**
876
+ * Restrict the run to the named specs (`--spec`). Repo-level findings are
877
+ * always kept; only findings owned by an out-of-scope `spec-NNNN` directory
878
+ * are dropped, and per-spec report writes are skipped for them.
879
+ */
880
+ specIds?: readonly string[];
702
881
  };
703
882
  declare function validateProject(root: string, configResult?: ConfigLoadResult, options?: ValidationOptions): Promise<ValidationResult>;
704
883
 
@@ -720,6 +899,61 @@ declare function validateSpecSplitByCapability(root: string, config: QfaiConfig)
720
899
  declare function validateTraceability(root: string, config: QfaiConfig, options: {
721
900
  includeCodeReferences: boolean;
722
901
  }): Promise<Issue[]>;
902
+ type TraceabilityGraphNode = {
903
+ id: string;
904
+ layer: string;
905
+ path?: string;
906
+ };
907
+ type TraceabilityGraphEdge = {
908
+ from: string;
909
+ to: string;
910
+ type: string;
911
+ };
912
+ type TraceabilityGraph = {
913
+ nodes: TraceabilityGraphNode[];
914
+ edges: TraceabilityGraphEdge[];
915
+ };
916
+ /**
917
+ * Builds the requirement graph from the parsed spec pack.
918
+ *
919
+ * Exposed so the per-run `traceability.json` artifact can be populated from the specs themselves
920
+ * rather than from the refs of emitted findings. Deriving it from findings inverted the artifact's
921
+ * intent: it was empty precisely when the spec pack was healthy, and populated only with IDs that
922
+ * failed.
923
+ *
924
+ * Every layered style `collectSpecEntries` recognises is walked, because restricting this to the
925
+ * v1416 style `validateTraceability` gates would leave the artifact empty for every spec written
926
+ * in the current v1421 layout. The layer vocabulary differs per style — v1416 links
927
+ * `US -> AC -> BR -> SC -> CASE`, v1417/v1421 link `US -> AC -> BR -> EX -> TC` — so the edge
928
+ * types differ too; the node/edge shape does not.
929
+ *
930
+ * Emits no issues; parse problems are reported by `validateTraceability` and
931
+ * `validateLayerCoverage` on the same inputs.
932
+ */
933
+ declare function buildLayeredTraceabilityGraph(root: string, config: QfaiConfig): Promise<TraceabilityGraph>;
934
+ /**
935
+ * Make an item ID unique across the pack.
936
+ *
937
+ * Item IDs are file-local (`spec-traceability-rules.md`, "ID and Parent
938
+ * Rules") and the shipped templates start every spec at `US-0001` / `AC-0001`,
939
+ * so two specs using the short form collide. Keying the graph on the raw ID
940
+ * silently dropped the second spec's nodes and overwrote its same-shaped edges,
941
+ * leaving `traceability.json` holding only the first spec's paths.
942
+ *
943
+ * The composite form already carries its spec number, so it is left untouched —
944
+ * qualifying it would rewrite every ID in the packs that actually ship today
945
+ * for no gain.
946
+ */
947
+ declare function qualifyId(specNumber: string, id: string): string;
948
+ /**
949
+ * The spec number owning `filePath`, or `null` for a repo-level file.
950
+ *
951
+ * Exported next to {@link qualifyId} because every producer of graph IDs has to
952
+ * namespace them the same way. A finding-derived node built from a raw short ID
953
+ * lands beside — not on — the `spec-NNNN/AC-0001` node the edges point at, and
954
+ * two specs' findings then merge onto the same unqualified node.
955
+ */
956
+ declare function specNumberForPath(filePath: string | undefined): string | null;
723
957
 
724
958
  type SurfaceType = CanonicalPrototypingSurface | "non-ui";
725
959
  declare const DISCUSSION_UI_BEARING_SURFACES: Set<SurfaceType>;
@@ -932,5 +1166,43 @@ type ParseResult = {
932
1166
  declare function parseDesignMd(text: string): ParseResult;
933
1167
  declare function validateDesignMd(d: DesignMd): ValidationIssue[];
934
1168
  declare function hashDesignMd(text: string): string;
1169
+ /**
1170
+ * Sentinel carried by every DESIGN.md the package ships as a sample:
1171
+ * - `assets/init/root/DESIGN.md` (seeded into the project root by `qfai init`)
1172
+ * - `assets/init/.qfai/assistant/skills/qfai-prototyping/templates/DESIGN.md.sample`
1173
+ *
1174
+ * The two files are the same fictional brand but are NOT byte-identical
1175
+ * (they differ in front-matter whitespace alignment), so a sha256-equality
1176
+ * guard would have to enumerate — and keep in sync — one digest per shipped
1177
+ * sample. A marker is content-addressed instead of byte-addressed: it
1178
+ * survives whitespace edits, covers both samples with one constant, and
1179
+ * keeps covering any future sample that carries it.
1180
+ *
1181
+ * The marker lives in the markdown body, so `parseDesignMd` (which only
1182
+ * reads front-matter) is unaffected: an unreplaced sample still parses and
1183
+ * validates, and is rejected by identity instead.
1184
+ */
1185
+ declare const DESIGN_MD_SAMPLE_MARKER = "QFAI-SAMPLE-DESIGN-MD";
1186
+ /**
1187
+ * True when `text` is still (or is derived from) a DESIGN.md the package
1188
+ * ships as a sample. Used to stop `/qfai-sdd` Phase 0 from sha256-freezing
1189
+ * an unauthored brand as the project's brand contract, and to surface the
1190
+ * same condition from `qfai validate` (QFAI-DCON-034).
1191
+ *
1192
+ * Two detectors, because the marker only covers samples seeded by releases
1193
+ * that carry it:
1194
+ * 1. `DESIGN_MD_SAMPLE_MARKER` — current samples, survives any edit that
1195
+ * leaves the comment in place.
1196
+ * 2. Legacy content fingerprint — samples seeded before the marker
1197
+ * existed, which `qfai init` will never overwrite.
1198
+ *
1199
+ * `text` is `unknown` rather than `string` because this is re-exported from
1200
+ * `core/index.ts` and so is reachable from untyped JavaScript, where a caller
1201
+ * can hand over the result of a read that failed or a value that was never a
1202
+ * file body. The guard below is what makes that safe; typing the parameter
1203
+ * `string` would have made it dead code that only looked defensive. Internal
1204
+ * callers pass a string and are unaffected.
1205
+ */
1206
+ declare function isUnreplacedDesignMdSample(text: unknown): boolean;
935
1207
 
936
- export { ARCHETYPES, type Archetype, type AtddCodeTraceabilityResult, type AtddForbiddenRef, type AtddSpecRefs, type AtddTestKind, type AtddTraceabilityMissing, type AtddTraceabilityScan, type AtddUnknownRef, type AtddUnknownRefKind, BROWSER_QA_PHASES, COLOR_KEYS, type ColorKey, type ConfigLoadResult, type ConfigPathKey, type ConfigSearchResult, DISCUSSION_NON_UI_SURFACES, DISCUSSION_UI_BEARING_SURFACES, type DecisionGuardrail, type DecisionGuardrailEntry, type DesignMd, type DesignMdColors, type DesignMdFonts, type DesignMdRadius, type DesignMdShadow, FONT_KEYS, type FailOn, type FontKey, type GuardrailCheckResult, type GuardrailIssue, type GuardrailIssueSeverity, type GuardrailLoadError, type GuardrailLoadResult, type GuardrailType, ID_PREFIXES, type IdFormatPrefix, type IdPrefix, type Issue, type IssueCategory, type IssueLocation, type IssueSeverity, type OrphanContractsPolicy, type OutputFormat, PROTOTYPING_SUPPORTED_SURFACES, type ParseError, type ParseResult, type PrototypingBrowserTool, type PrototypingSurface, type QfaiAtddConfig, type QfaiConfig, type QfaiOutputConfig, type QfaiPaths, type QfaiPrototypingCalibrationConfig, type QfaiPrototypingConfig, type QfaiPrototypingExecutionConfig, type QfaiReviewConfig, type QfaiUiuxAuditConfig, type QfaiUiuxConfig, type QfaiValidationConfig, RADIUS_KEYS, type RadiusKey, type ReportChangeType, type ReportChangeTypeSummary, type ReportChangeTypeWarning, type ReportContractCoverage, type ReportData, type ReportDeltaCoverage, type ReportFullHarnessExecution, type ReportGuardrailItem, type ReportGuardrails, type ReportIds, type ReportPrototypingSummary, type ReportRoundLifecycle, type ReportRuleFinding, type ReportSpecContractRefs, type ReportSpecCoverage, type ReportSummary, type ReportSurfaceClassification, type ReportTddCoverage, type ReportTddCoverageSpec, type ReportTestStrategy, type ReportTraceability, type ReportWaivers, type RunSddPreflightOptions, SHADOW_KEYS, type SddPreflightResult, type SddPreflightSource, type SddPreflightStatus, type ShadowKey, type TraceabilitySeverity, VISUAL_BROWSER_SURFACES, type ValidationCounts, type ValidationIssue, type ValidationOptions, type ValidationProfile, type ValidationResult, type ValidationTraceability, type ValidationWaiverAction, type ValidationWaiverDowngradeTo, type ValidationWaiverEntry, type ValidationWaiverMatch, type ValidationWaiverScope, type ValidationWaiverSeverity, type ValidationWaiverSuppressed, type ValidationWaivers, checkDecisionGuardrails, createReportData, defaultConfig, evaluateAtddCodeTraceability, extractAcSpecNumber, extractAllIds, extractBrSpecNumber, extractCapSpecNumber, extractCaseSpecNumber, extractDecisionGuardrailsFromMarkdown, extractIds, extractInvalidIds, extractScSpecNumber, extractSpecNumber, extractUsSpecNumber, filterDecisionGuardrailsByKeyword, findConfigRoot, formatGuardrailsForLlm, formatReportJson, formatReportMarkdown, getConfigPath, hashDesignMd, isDiscussionUiBearingSurfaceType, isNonUiDiscussionSurface, isSupportedPrototypingSurface, isValidPrototypingSurface, lintSql, loadConfig, loadDecisionGuardrails, normalizeDecisionGuardrails, parseDesignMd, requiresVisualBrowserEvidence, resolvePath, resolveToolVersion, runBrowserQaOrchestrated, runRenderCapture, runSddPreflight, sortDecisionGuardrails, summarizeBrowserQaResult, validateAtddCodeTraceability, validateContracts, validateDefinedIds, validateDesignMd, validateLayeredTraceability, validateOrphanProhibition, validateProject, validateSpecSplitByCapability, validateTraceability };
1208
+ export { AC_GHERKIN_SECTION, ARCHETYPES, ATDD_TEST_KIND_DIRS, type Archetype, type AtddCodeTraceabilityResult, type AtddForbiddenRef, type AtddSpecRefs, type AtddTestKind, type AtddTraceabilityMissing, type AtddTraceabilityScan, type AtddUnknownRef, type AtddUnknownRefKind, BROWSER_QA_PHASES, COLOR_KEYS, type ColorKey, type ConfigLoadResult, type ConfigPathKey, type ConfigSearchResult, DESIGN_MD_SAMPLE_MARKER, DISCUSSION_NON_UI_SURFACES, DISCUSSION_UI_BEARING_SURFACES, type DecisionGuardrail, type DecisionGuardrailEntry, type DesignMd, type DesignMdColors, type DesignMdFonts, type DesignMdRadius, type DesignMdShadow, FONT_KEYS, type FailOn, type FenceMaskOptions, type FontKey, type GuardrailCheckResult, type GuardrailIssue, type GuardrailIssueSeverity, type GuardrailLoadError, type GuardrailLoadResult, type GuardrailType, ID_PREFIXES, type IdFormatPrefix, type IdPrefix, type InvalidIdOccurrence, type Issue, type IssueCategory, type IssueLocation, type IssueSeverity, type OrphanContractsPolicy, type OutputFormat, PLANNED_CONTRACT_KEY, PROTOTYPING_SUPPORTED_SURFACES, type ParseError, type ParseResult, type PrototypingBrowserTool, type PrototypingSurface, type QfaiAtddConfig, type QfaiConfig, type QfaiOutputConfig, type QfaiPaths, type QfaiPrototypingCalibrationConfig, type QfaiPrototypingConfig, type QfaiPrototypingExecutionConfig, type QfaiReviewConfig, type QfaiUiuxAuditConfig, type QfaiUiuxConfig, type QfaiValidationConfig, RADIUS_KEYS, type RadiusKey, type ReportChangeType, type ReportChangeTypeSummary, type ReportChangeTypeWarning, type ReportContractCoverage, type ReportData, type ReportDeltaCoverage, type ReportFullHarnessExecution, type ReportGuardrailItem, type ReportGuardrails, type ReportIds, type ReportPrototypingSummary, type ReportRoundLifecycle, type ReportRuleFinding, type ReportSpecContractRefs, type ReportSpecCoverage, type ReportSummary, type ReportSurfaceClassification, type ReportTddCoverage, type ReportTddCoverageSpec, type ReportTestStrategy, type ReportTraceability, type ReportWaivers, type RunSddPreflightOptions, SHADOW_KEYS, type SddPreflightResult, type SddPreflightSource, type SddPreflightStatus, type ShadowKey, type TraceabilityGraph, type TraceabilityGraphEdge, type TraceabilityGraphNode, type TraceabilitySeverity, VISUAL_BROWSER_SURFACES, type ValidationCounts, type ValidationIssue, type ValidationOptions, type ValidationProfile, type ValidationResult, type ValidationTraceability, type ValidationWaiverAction, type ValidationWaiverDowngradeTo, type ValidationWaiverEntry, type ValidationWaiverMatch, type ValidationWaiverScope, type ValidationWaiverSeverity, type ValidationWaiverSuppressed, type ValidationWaivers, atddTestKindDirs, buildLayeredTraceabilityGraph, checkDecisionGuardrails, createReportData, defaultConfig, deriveAtddFilePattern, evaluateAtddCodeTraceability, extractAcSpecNumber, extractAllIds, extractBrSpecNumber, extractCapSpecNumber, extractCaseSpecNumber, extractDecisionGuardrailsFromMarkdown, extractIds, extractInvalidIdOccurrences, extractInvalidIds, extractScSpecNumber, extractSpecNumber, extractUsSpecNumber, filterDecisionGuardrailsByKeyword, findConfigRoot, formatGuardrailsForLlm, formatReportJson, formatReportMarkdown, getConfigPath, hashDesignMd, isDiscussionUiBearingSurfaceType, isNonUiDiscussionSurface, isPlannedApiContract, isSupportedPrototypingSurface, isUnreplacedDesignMdSample, isValidPrototypingSurface, lintSql, loadConfig, loadDecisionGuardrails, maskFencedCodeBlocks, normalizeDecisionGuardrails, parseDesignMd, qualifyId, requiresVisualBrowserEvidence, resolvePath, resolveToolVersion, runBrowserQaOrchestrated, runRenderCapture, runSddPreflight, sortDecisionGuardrails, specNumberForPath, summarizeBrowserQaResult, validateAtddCodeTraceability, validateContracts, validateDefinedIds, validateDesignMd, validateLayeredTraceability, validateOrphanProhibition, validateProject, validateSpecSplitByCapability, validateTraceability };