Prove the Path, Not the POST
Chains beat endpoints
Teams report "API tested" while users see a session lose its state mid-path, or a write silently fail. The gap is definitional: a passing smoke test on /health or a single POST does not prove a user capability. Real workflows are chains of HTTP calls with IDs passed forward.
This insight unlocked the whole SIT program. I formalized it in docs/SIT Plan/00-sit-plan-overview.md in April 2026 - weeks after the master map and integration surface work.
Here's what this piece covers: green endpoints / red paths, chain testing, one failed handoff, and three lead gates.
Part of Field Notes: agentic delivery.
1. The leadership problem
Integration defects surface in UAT when they are expensive to fix. By then, teams argue whose environment is "ready" instead of naming the broken hop.
Wrong: "We have 95% test pass rate."
Right: "Phase 2 failed at the handoff between records and entitlement - here is the chain diagram and workflow ID WF-REG-1."
The anti-pattern is isolated green - teams optimize local pass rates while seams rot.
2. What the docs show
Planning work in early April revealed multi-hop paths. The SIT overview doc states the thesis plainly:
Each workflow is a chain of HTTP calls with IDs passed forward - not a single-endpoint smoke test.
Three concepts I still enforce:
| Term | Meaning |
|---|---|
| Chain | Ordered calls with shared state - tokens, record IDs, entitlement IDs |
| Endpoint smoke | Single call returns 200 - necessary, not sufficient |
| Read-back assertion | After a compound workflow, verify state via GET |
Phase 3 adds the user lens: User gets - not "service responds," but "the account shows the result."
3. Example chain
Start session → create upstream record → complete → write entitlement → confirm in account.
async function assertEntitlementChain({ api, session }) {
const record = await api.post('/records', { sessionId: session.id });
await api.post(`/records/${record.id}/complete`);
const write = await api.post('/entitlements', { recordId: record.id });
const account = await api.get(`/accounts/${session.accountId}`);
if (!account.items.some((item) => item.id === write.id)) {
throw new Error(`write ${write.id} missing on account read-back`);
}
}
| Failure mode | What the user sees | Broken hop |
|---|---|---|
| Record not bound to session | Empty state mid-path | Identity ↔ records |
| Upstream record not attached | Write succeeds, nothing owned | Records ↔ entitlement |
| Read-back missing | "Success" toast, empty list | Entitlement write vs read |
| CRM async lag | Account OK, support sees nothing | Entitlement ↔ CRM |
Mocking every peer in unit tests hides seam bugs. That is why Phase 2 exists - shared coordinators, real handoffs, TEST environment.
4. Named pattern: chain testing
Chain testing - prove the path, not the endpoint. Phase 2 fails at handoffs, not 200s.
Environment ladder from the SIT overview:
Same suite IDs promote TEST → UAT. Different environment, same workflow names - traceability survives.
5. What I'd do as a lead
- Ban "we tested the API" without naming the chain ID. If nobody can cite
WF-*orUJ-*, you do not have integration proof. - Fund seam tests before expanding feature count. Endpoints scale faster than handoffs; that asymmetry is the constraint.
- Align workflow names to master-map nodes from article 01. "Entitlement CRUD" ≠ "user gets the result from an upstream record."
Further reading
- Team → seam → journey
- Green APIs, broken handoffs
- Planning:
docs/SIT Plan/00-sit-plan-overview.md