fix: harden engine, enrich failure diagnostics, close adoption gaps

- P0: CLI verify now honors  test budget with seeded multi-sample
- P0: Observe sampling enforced via Math.random() gate in hook-validator
- P1: Remove misleading undici-mock-agent isolation option
- P1: Qualify reuses shared discoverRouteDetails() with warnings
- P1: Chaos/scenario config exposed via preset schema
- P1: README/docs limitations updated to current state
- P2: Nested response annotations prefer 2xx deterministically
- P2: --changed documented as heuristic in verify.md

- Add observe sink tests (sampling 0/1, sink failure non-interference)
- Add verify runs regression tests (scale, determinism, variants)
- Add configured-scenario qualify test (independent of OAuth fixture)
- Add coverageBreakdown to qualify artifacts (per-gate route coverage)
- Add production-style observe example with real sink in docs/observe.md
- Add nightly/staging vs PR gating guidance to docs/qualify.md

- Enrich VerifyFailure with formula-aware diagnostics:
  status:201 => 'HTTP 200', body field checks => actual values
- Remove stale observe CLI activation message
- Document outbound mocks as process-global in getting-started.md
- Refresh APOPHIS_ADOPTION_AUDIT.md with current state

903 tests pass, build clean, typecheck clean.
This commit is contained in:
John Dvorak
2026-05-21 20:39:36 -07:00
parent 55b0262799
commit d0523fcc2d
128 changed files with 4004 additions and 3631 deletions
+3 -17
View File
@@ -8,6 +8,7 @@ import { resolve } from 'node:path';
import type { CliContext } from '../../core/types.js';
import { USAGE_ERROR, SUCCESS } from '../../core/exit-codes.js';
import { getScaffoldForPreset, getPresetNames, type ScaffoldResult } from './scaffolds/index.js';
import { APP_CANDIDATES } from '../../core/app-loader.js';
// ─────────────────────────────────────────────────────────────────────────────
// Types
@@ -63,22 +64,7 @@ function renderInstallCommand(
* - Common server file names (server.js, app.js, index.js, etc.)
*/
export async function detectFastifyEntrypoint(cwd: string): Promise<string | null> {
const candidates = [
'app.js',
'app.ts',
'server.js',
'server.ts',
'index.js',
'index.ts',
'src/app.js',
'src/app.ts',
'src/server.js',
'src/server.ts',
'src/index.js',
'src/index.ts',
];
for (const candidate of candidates) {
for (const candidate of APP_CANDIDATES) {
const fullPath = resolve(cwd, candidate);
if (!existsSync(fullPath)) continue;
@@ -217,7 +203,7 @@ function generateConfigContent(config: ScaffoldResult['config'], isTypeScript: b
lines.push('');
if (isTypeScript) {
lines.push('import type { ApophisConfig } from "apophis-fastify/cli";');
lines.push('import type { ApophisConfig } from "@apophis/fastify";');
lines.push('');
lines.push('const config: ApophisConfig = ' + stringifyConfig(config) + ';');
lines.push('');