2026-03-10 00:00:00 -07:00
/**
* S3: Init command scaffold templates
* Each preset returns a config object and file contents for the init command.
*/
import type { ApophisConfig , PresetDefinition , ProfileDefinition , EnvironmentPolicy } from '../../../core/types.js' ;
export interface ScaffoldResult {
config : ApophisConfig ;
readmeContent : string ;
}
// ─────────────────────────────────────────────────────────────────────────────
// safe-ci: Minimal CI-safe preset (default)
// ─────────────────────────────────────────────────────────────────────────────
export function safeCiScaffold ( ) : ScaffoldResult {
const preset : PresetDefinition = {
name : 'safe-ci' ,
timeout : 5000 ,
parallel : false ,
chaos : false ,
observe : false ,
} ;
const profile : ProfileDefinition = {
name : 'quick' ,
mode : 'verify' ,
preset : 'safe-ci' ,
routes : [ 'POST /users' ] ,
} ;
const envLocal : EnvironmentPolicy = {
name : 'local' ,
allowVerify : true ,
allowObserve : true ,
allowQualify : false ,
allowChaos : false ,
allowBlocking : true ,
requireSink : false ,
} ;
const config : ApophisConfig = {
mode : 'verify' ,
profiles : { quick : profile } ,
presets : { 'safe-ci' : preset } ,
environments : { local : envLocal } ,
2026-05-22 13:01:26 -07:00
// Uncomment to enforce cross-cutting behavioral rules across all matching routes:
// pluginContracts: {
// 'auth-presence': {
// appliesTo: '/api/**',
// hooks: { onRequest: { requires: ['request_headers(this).authorization != null'] } },
// },
// },
2026-03-10 00:00:00 -07:00
} ;
const readmeContent = `
# APOPHIS Setup — safe-ci preset
This project was scaffolded with \` apophis init --preset safe-ci \` .
## Quick Start
1. Ensure you have a Fastify app with @fastify/swagger registered.
2. Add behavioral contracts to your route schemas using \` x-ensures \` .
3. Run: apophis verify --profile quick
## What This Preset Does
- Runs only behavioral contracts (not schema-only routes).
- No chaos, no observe, no stateful testing.
- Safe for CI pipelines.
- Timeout: 5s per route.
## Example Behavioral Contract
Add this inside your route schema to check that a created resource is retrievable:
\` \` \` javascript
"x-ensures": [
"response_code(GET /users/{response_body(this).id}) == 200"
]
\` \` \`
If \` apophis verify \` says "No behavioral contracts found", it means your routes have schemas but no \` x-ensures \` or \` x-requires \` clauses. Add at least one clause per route you want to verify.
## Next Steps
- Add more routes to the \` routes \` array in your profile.
- Try \` apophis init --preset platform-observe \` for production readiness.
- Try \` apophis init --preset protocol-lab \` for multi-step flows.
` ;
return { config , readmeContent } ;
}
// ─────────────────────────────────────────────────────────────────────────────
// platform-observe: Production-ready with observe mode
// ─────────────────────────────────────────────────────────────────────────────
export function platformObserveScaffold ( ) : ScaffoldResult {
const preset : PresetDefinition = {
name : 'platform-observe' ,
timeout : 10000 ,
parallel : true ,
chaos : false ,
observe : true ,
2026-05-22 13:01:26 -07:00
sampling : 0.1 ,
blocking : false ,
sinks : { logs : true , metrics : true } ,
2026-03-10 00:00:00 -07:00
} ;
const profile : ProfileDefinition = {
name : 'staging-observe' ,
mode : 'observe' ,
preset : 'platform-observe' ,
routes : [ ] ,
} ;
const envStaging : EnvironmentPolicy = {
name : 'staging' ,
allowVerify : true ,
allowObserve : true ,
allowQualify : true ,
allowChaos : false ,
allowBlocking : false ,
requireSink : true ,
2026-05-22 13:01:26 -07:00
sinks : { logs : true , metrics : true } ,
2026-03-10 00:00:00 -07:00
} ;
const envProduction : EnvironmentPolicy = {
name : 'production' ,
allowVerify : true ,
allowObserve : true ,
allowQualify : false ,
allowChaos : false ,
allowBlocking : false ,
requireSink : true ,
} ;
const config : ApophisConfig = {
mode : 'observe' ,
profile : 'staging-observe' ,
profiles : { 'staging-observe' : profile } ,
presets : { 'platform-observe' : preset } ,
environments : {
staging : envStaging ,
production : envProduction ,
} ,
2026-05-22 13:01:26 -07:00
// pluginContracts: {
// 'request-id': {
// appliesTo: '/api/**',
// hooks: { onSend: { ensures: ['response_headers(this).x-request-id != null'] } },
// },
// },
2026-03-10 00:00:00 -07:00
} ;
const readmeContent = `
# APOPHIS Setup — platform-observe preset
This project was scaffolded with \` apophis init --preset platform-observe \` .
## Quick Start
1. Ensure you have a Fastify app with @fastify/swagger registered.
2. Configure your reporting sink (see environments.staging.requireSink).
3. Run: apophis observe --profile staging-observe
## What This Preset Does
- Enables observe mode for production readiness checks.
- Validates non-blocking semantics and sink configuration.
- Parallel execution for faster feedback.
- Requires sink config in staging/production.
## Safety
- Observe mode is non-blocking by default.
- Production requires explicit policy to enable blocking.
- Chaos is disabled in this preset.
## Next Steps
- Add a sink configuration to your environment policy.
- Run \` apophis doctor \` to validate the full setup.
` ;
return { config , readmeContent } ;
}
// ─────────────────────────────────────────────────────────────────────────────
// llm-safe: Minimal preset for LLM-generated codebases
// ─────────────────────────────────────────────────────────────────────────────
export function llmSafeScaffold ( ) : ScaffoldResult {
const preset : PresetDefinition = {
name : 'llm-safe' ,
timeout : 3000 ,
parallel : false ,
chaos : false ,
observe : false ,
} ;
const profile : ProfileDefinition = {
name : 'llm-check' ,
mode : 'verify' ,
preset : 'llm-safe' ,
routes : [ ] ,
} ;
const envLocal : EnvironmentPolicy = {
name : 'local' ,
allowVerify : true ,
allowObserve : false ,
allowQualify : false ,
allowChaos : false ,
allowBlocking : false ,
requireSink : false ,
} ;
const config : ApophisConfig = {
mode : 'verify' ,
profile : 'llm-check' ,
profiles : { 'llm-check' : profile } ,
presets : { 'llm-safe' : preset } ,
environments : { local : envLocal } ,
2026-05-22 13:01:26 -07:00
// pluginContracts: {
// 'auth-presence': {
// appliesTo: '/api/**',
// hooks: { onRequest: { requires: ['request_headers(this).authorization != null'] } },
// },
// },
2026-03-10 00:00:00 -07:00
} ;
const readmeContent = `
# APOPHIS Setup — llm-safe preset
This project was scaffolded with \` apophis init --preset llm-safe \` .
## Quick Start
1. Ensure you have a Fastify app with @fastify/swagger registered.
2. Add behavioral contracts to your route schemas using \` x-ensures \` .
3. Run: apophis verify --profile llm-check
## What This Preset Does
- Ultra-minimal preset for LLM-generated codebases.
- 3s timeout per route (fast feedback).
- No observe, no qualify, no chaos — verify only.
- Conservative defaults to avoid surprising failures.
## Example Behavioral Contract
Add this inside your route schema to check that a created resource is retrievable:
\` \` \` javascript
"x-ensures": [
"response_code(GET /users/{response_body(this).id}) == 200"
]
\` \` \`
If \` apophis verify \` says "No behavioral contracts found", it means your routes have schemas but no \` x-ensures \` or \` x-requires \` clauses. Add at least one clause per route you want to verify.
## Next Steps
- Add routes to the \` routes \` array once you have behavioral contracts.
- Run \` apophis doctor \` to check for missing dependencies.
` ;
return { config , readmeContent } ;
}
// ─────────────────────────────────────────────────────────────────────────────
// protocol-lab: Multi-step flow and stateful testing
// ─────────────────────────────────────────────────────────────────────────────
export function protocolLabScaffold ( ) : ScaffoldResult {
const preset : PresetDefinition = {
name : 'protocol-lab' ,
timeout : 15000 ,
parallel : false ,
chaos : true ,
observe : false ,
2026-05-22 13:01:26 -07:00
// chaosStrategy: 'sample', // 'one' | 'all' | 'sample' | 'routes'
// chaosSampleSize: 3, // routes to target when strategy is 'sample'
// chaosSampleRoutes: [], // explicit route list when strategy is 'routes'
2026-03-10 00:00:00 -07:00
} ;
const profile : ProfileDefinition = {
name : 'oauth-nightly' ,
mode : 'qualify' ,
preset : 'protocol-lab' ,
routes : [ ] ,
seed : 42 ,
} ;
const envLocal : EnvironmentPolicy = {
name : 'local' ,
allowVerify : true ,
allowObserve : true ,
allowQualify : true ,
allowChaos : true ,
allowBlocking : true ,
requireSink : false ,
} ;
const envTest : EnvironmentPolicy = {
name : 'test' ,
allowVerify : true ,
allowObserve : true ,
allowQualify : true ,
allowChaos : true ,
allowBlocking : true ,
requireSink : false ,
} ;
const config : ApophisConfig = {
mode : 'qualify' ,
profile : 'oauth-nightly' ,
profiles : { 'oauth-nightly' : profile } ,
presets : { 'protocol-lab' : preset } ,
environments : {
local : envLocal ,
test : envTest ,
} ,
2026-05-22 13:01:26 -07:00
// pluginContracts: {
// 'rate-limit': {
// appliesTo: 'POST /api/**',
// hooks: { onResponse: { ensures: ['status != 429'] } },
// },
// },
2026-03-10 00:00:00 -07:00
} ;
const readmeContent = `
# APOPHIS Setup — protocol-lab preset
This project was scaffolded with \` apophis init --preset protocol-lab \` .
## Quick Start
1. Ensure you have a Fastify app with @fastify/swagger registered.
2. Define multi-step flows in your route schemas.
3. Run: apophis qualify --profile oauth-nightly --seed 42
## What This Preset Does
- Enables qualify mode for stateful and scenario testing.
- Chaos engineering enabled (local/test only).
- Deep depth for thorough exploration.
- 15s timeout per route.
## Safety
- Chaos is blocked in production by default.
- Use \` apophis doctor \` to validate environment safety before qualifying.
## Machine Output in CI
Qualify can produce large output. In CI, use machine-readable formats and filter events:
- \` --format json \` emits a single stable JSON artifact (good for small-to-medium runs).
- \` --format ndjson \` emits one event per line (good for streaming parsers).
- Use \` --quiet \` to suppress human progress text.
- Pipe ndjson to \` jq \` or a custom filter to extract only failures:
\` \` \` bash
apophis qualify --profile oauth-nightly --format ndjson | jq 'select(.type == "route.failed")'
\` \` \`
- For very large runs, consider writing artifacts to a directory and parsing the JSON file instead of stdout:
\` \` \` bash
apophis qualify --profile oauth-nightly --format json --artifact-dir reports/apophis
\` \` \`
## Next Steps
- Define scenario sequences in your config.
- Add route allowlists for chaos if needed.
- Run \` apophis replay --artifact <path> \` to debug failures.
` ;
return { config , readmeContent } ;
}
// ─────────────────────────────────────────────────────────────────────────────
// Preset registry
// ─────────────────────────────────────────────────────────────────────────────
export const PRESETS : Record < string , ( ) = > ScaffoldResult > = {
'safe-ci' : safeCiScaffold ,
'platform-observe' : platformObserveScaffold ,
'llm-safe' : llmSafeScaffold ,
'protocol-lab' : protocolLabScaffold ,
} ;
export function getPresetNames ( ) : string [ ] {
return Object . keys ( PRESETS ) ;
}
export function getScaffoldForPreset ( preset : string ) : ScaffoldResult | null {
const fn = PRESETS [ preset ] ;
return fn ? fn ( ) : null ;
}