docs: add paper citations, fix pedagogical issues, improve SKILL.md

- Cite arxiv 2602.23922 (Invariant-Driven Automated Testing) in all major docs
- Add Progressive Complexity section to SKILL.md for LLM guidance
- Fix SKILL.md Fast Start example to use deterministic ID generation
- Fix getting-started.md failure output inconsistency
- Fix auth-patterns.md TypeScript syntax in JS doc
- Fix fastify-structure.md Date.now() in test helper
- Fix observe.md misleading workspace heading
- Build: clean | Tests: 849 pass, 0 fail
This commit is contained in:
John Dvorak
2026-04-30 11:34:00 -07:00
parent 6c39bd0a6c
commit 8d7382417d
11 changed files with 53 additions and 6 deletions
+30 -1
View File
@@ -7,6 +7,8 @@ description: Use this skill when adding or improving APOPHIS contract-driven tes
APOPHIS verifies API behavior across operations, state changes, protocol flows, and dependencies. Use it when schema validation is not enough to answer whether an endpoint did the right thing.
Inspired by [Invariant-Driven Automated Testing](https://arxiv.org/abs/2602.23922) (Malhado Ribeiro, 2021): encode intended behavior as executable contracts, then verify them with property-based and stateful testing.
## When To Use
Use this skill when the operator asks to:
@@ -76,6 +78,7 @@ When entering a Fastify codebase:
import Fastify from 'fastify'
import swagger from '@fastify/swagger'
import apophis from 'apophis-fastify'
import crypto from 'crypto'
const app = Fastify()
await app.register(swagger)
@@ -114,8 +117,9 @@ app.post('/users', {
}
}
}, async (req, reply) => {
const id = `usr-${crypto.createHash('sha256').update(req.body.email).digest('hex').slice(0, 8)}`
reply.status(201)
return { id: 'usr-1', ...req.body }
return { id, ...req.body }
})
await app.ready()
@@ -350,6 +354,31 @@ Operator framing:
> The failing seed gives us a reproducible behavioral example. I'll replay it first so we can distinguish a real regression from source drift or nondeterministic app state.
## Progressive Complexity
Start simple and add depth only where it pays off:
**Level 1 — Status and shape**: Every route gets an expected status code and key field existence.
```apostl
status:201
response_body(this).id != null
```
**Level 2 — Cross-route behavior**: Constructors check retrievability; mutators check persistence.
```apostl
response_code(GET /users/{response_body(this).id}) == 200
response_body(GET /users/{response_body(this).id}).email == request_body(this).email
```
**Level 3 — Isolation and boundaries**: Tenant, auth, and idempotency checks.
```apostl
if request_headers(this).x-tenant-id != null then response_headers(this).x-tenant-id == request_headers(this).x-tenant-id else true
```
**Level 4 — Protocol and dependency flows**: Variants, scenarios, outbound contracts, and chaos.
Add level 2 before level 4. Do not skip level 2 for resource APIs.
## Anti-Patterns
Do not: