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:
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user