# Claims-denial vertical-slice lab

This dependency-free Node 22 lab makes one narrow FDE claim inspectable: a recommendation can be bound to an exact candidate, authorized at the service boundary, written once to a simulated system of record, read back, and traced through failure.

It is a **local teaching fixture**, not a billing product. The cases, identities, policy, cost, and recommender are synthetic. It does not prove payer-rule correctness, production readiness, security certification, customer value, or job readiness. It has no claim-approval or submission capability; an authenticated billing specialist remains the authority outside this lab.

The runnable candidate `claims-denial-recommender-0.1.0` is separate from the
worked-case candidate `rec-0.4.3`. Evidence never transfers between them. The
candidate digest demonstrates drift detection for this narrow fixture; it is
not the complete release binding required by Mission 8.

[Download the complete runnable lab](../../downloads/lumyn-claims-denial-lab.zip)
from the public School site. From the directory containing the download, run:

## Run

```bash
unzip lumyn-claims-denial-lab.zip
cd lumyn-claims-denial-lab/labs/claims-denial
npm test
npm start
```

Inside a checkout of the full School repository, use `cd labs/claims-denial`
instead.

The server binds to `127.0.0.1:8787` by default. Set `PORT` to use another local port.

The bearer tokens below are deliberately obvious local fixtures, not credentials:

| Token | Local role |
| --- | --- |
| `fde-demo-token` | Read a case, record a recommendation, read an operation |
| `observer-demo-token` | Read telemetry only |
| `lab-admin-demo-token` | The FDE permissions plus telemetry and controlled failure injection |

## Walk the successful slice

Inspect the exact candidate and the current source record:

```bash
curl -s http://127.0.0.1:8787/v1/candidate
curl -s -H 'Authorization: Bearer fde-demo-token' \
  http://127.0.0.1:8787/v1/cases/DENIAL-001
```

Copy the `candidateId` and `digest` into this request. The seeded case starts at revision `7`:

```bash
curl -s -X POST http://127.0.0.1:8787/v1/recommendations \
  -H 'Authorization: Bearer fde-demo-token' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: walkthrough-001' \
  -H 'X-Candidate-Digest: COPY_DIGEST_HERE' \
  --data '{
    "caseId": "DENIAL-001",
    "expectedCaseRevision": 7,
    "candidateId": "claims-denial-recommender-0.1.0"
  }'
```

Read back the returned `operationId`, then inspect telemetry with the observer token:

```bash
curl -s -H 'Authorization: Bearer fde-demo-token' \
  http://127.0.0.1:8787/v1/operations/op-0001
curl -s -H 'Authorization: Bearer observer-demo-token' \
  http://127.0.0.1:8787/v1/telemetry
```

The trace records the exact candidate digest, outcome, latency, and estimated cost. It intentionally excludes claim evidence and tokens.

## Negative drills

1. **Authorization:** omit the bearer token, then use `observer-demo-token` on the write route. Confirm both fail before an effect.
2. **Candidate drift:** change either candidate ID or digest. Confirm the request fails with `candidate_mismatch`.
3. **Stale write:** submit a revision other than the current case revision. Confirm the response exposes current and expected revisions and the recommendation count does not change.
4. **Duplicate safety:** resend an identical request with the same idempotency key. Confirm `idempotentReplay` becomes `true` and the operation ID is unchanged. Reuse the key with a different case or revision and confirm it fails.
5. **Partial failure and readback:** make a fresh request with the admin token and header `X-Lab-Failure: after-write-before-response`. The first response is `503` and includes an operation ID because the write committed but the response was lost. Read that operation, then retry the identical request with the same key. Confirm exactly one recommendation exists.
6. **Authority boundary:** try `POST /v1/claims/DENIAL-001/submit`. It is intentionally absent and returns `404`.

## FDE exercises

### Canary

- Propose a canary cohort smaller than “all NorthLake denials.” State its denominator, eligible cases, verifier, observation window, cost ceiling, stop conditions, and specialist-review capacity.
- Add a test fixture for one case that must fall back to `insufficient_evidence` and explain why that is safer than expanding the teaching rule.
- Decide which telemetry fields are release evidence and which are merely operational signals.

### Rollback

- Treat the candidate manifest as the release identity. Describe how you would preserve the previous manifest, policy, and data contract and route new work back to it.
- Define what happens to in-flight idempotency records and already-recorded recommendations during rollback.
- Write a negative test showing that changing only `promptRevision` creates a new digest and cannot silently reuse the old release identity.

### Incident

- Run the partial-failure drill. Write an incident timeline using the caller error, operation readback, and telemetry event.
- Distinguish “response lost” from “effect not committed.” State the evidence required before retrying with a new key.
- Propose containment if source-of-record readback is unavailable. Do not claim success from a model response or HTTP timeout alone.

### Transfer

- Name the team that owns the service, the billing authority that owns the recommendation disposition, and the person who may change the candidate or policy.
- Prepare an operator check for health, telemetry, readback, duplicate safety, stale writes, and rollback.
- Have a second person run the service, diagnose one injected failure, and explain the recommendation-only boundary without help. Record gaps before calling the transfer complete.

## Design notes

- The deterministic adapter is intentionally small. This lab teaches boundaries and evidence, not model novelty.
- Authorization is rechecked in the service; demo tokens never confer approval or claim-submission authority.
- Idempotency is scoped by tenant and request fingerprint. Concurrent identical requests share one pending effect.
- A stale source revision fails closed. The caller must refresh rather than overwrite newer state.
- If a write may have committed but readback cannot verify it, the idempotency key remains in doubt and the service blocks blind re-execution until an operator reconciles the operation.
- The injected partial failure occurs only after source-of-record write and readback. The committed idempotency record lets an identical retry recover the result without another write.
- Storage is in memory and resets when the process exits. That limitation is deliberate and must be replaced before any production-shaped deployment.
