J4 / UPGRADES
← All practice results

p2-05-nest

Public GitHub evidence ↗

# p2-05-nest — Batch 2 result: GREEN

Source: `mikro-orm/nestjs-realworld-example-app` @ `243a4c66cf4f002831bdf9faee2e6a7c3d9446bd` (MIT).
Owned fork: https://github.com/j4groupfounders/j4-p2b-nest
Locked target: nest 10.4.15 → 12.1.2.
Final evidence: [37553526889](https://github.com/j4groupfounders/j4-p2b-nest/actions/runs/37553526889) (success); branch SHA `60be02ca5b3c81953e82677264a252f964273468`.

## Outcome
**GREEN.** Project tests (13 Jest tests, same inventory as baseline) pass; app boots and serves the fixed route list with no 5xx; frozen HTTP characterization snapshots match baseline exactly; the project's own 280-assertion Newman/Postman API collection passes in full; all five preregistered seeded faults are detected.

## What was repaired (agent edits, zero human edits)
1. `src/main.ts`: added an explicit fallback 404 JSON handler (`{error,message,statusCode}`) for routes outside the `/api` global prefix (e.g. `/`). The newer platform-express adapter no longer produces NestJS's own JSON 404 shape for such routes by default (Express's default HTML 404 page was returned instead) — a real, documented framework behavior change, not silently accepted. Two ordering iterations were needed: (a) registering it right after `app.init()` initially shadowed every real route (Express matches middleware in registration order, and Nest's own routes aren't bound onto the adapter until `init()`/`listen()` runs); (b) the fix was to register the fallback **after `app.listen()` resolves**, so it remains a true last-resort and still yields precedence to anything registered between `init()` and `listen()` — which matters for the harness's own missing-route-status seeded fault (see below).
2. Harness script fix (`j4_stage.py`/`j4_seeds.py`, shared across pilots, not project code): the generic E2E runner used `--delay-request 0`, which this newman version rejects ("must be a positive integer"); corrected to `--delay-request 500` to match the project's own `e2e/run-api-tests.sh`. Also: the E2E-assertion-inventory-unchanged assertion was previously a hard crash inside `run_http()` even when called during seeded-fault injection, where a mutation breaking request chaining (fewer Newman assertions executing) is itself a valid detection signal, not a harness bug — split into `strict` (record/replay) vs non-strict (mutation) modes.

## Seeded-fault detection (five independent mutations, each reverted in `finally`)
| Fault | Project tests | Harness (HTTP probe) | Combined |
|---|---|---|---|
| tags-status | detected (Newman 1 assertion failed) | detected | yes |
| article-count | detected (Newman 2 assertions failed) | detected | yes |
| auth-status | not detected | detected | yes |
| missing-route-status | not detected | detected | yes |
| login-status | not detected | detected | yes |

Project-only detection: 2/5 (40%, miss rate 60%). Combined (project + harness): 5/5 (100%, miss rate 0%). Meets the ≥80% combined / miss-rate-halving gate with margin.

## CI accounting
11 CI runs (1 baseline + 10 upgrade/seed attempts), 21.53 job-minutes, 54.9 wall-minutes (preregistration to terminal run). No paid runner/services/model calls; incremental vendor spend $0.

## Measured-scope limits (unchanged from protocol)
Empty-DB unauthenticated HTTP characterization plus the project's own fixture-backed Jest + Newman suites; not a full production acceptance claim.