Files
natsnet/docs/plans/2026-02-27-batch-10-ocsp-cache-js-events-plan.md
Joseph Doherty f0455a1e45 Add batch plans for batches 6-7, 9-12, 16-17 (rounds 4-7)
Generated design docs and implementation plans via Codex for:
- Batch 6: Opts package-level functions
- Batch 7: Opts class methods + Reload
- Batch 9: Auth, DirStore, OCSP foundations
- Batch 10: OCSP Cache + JS Events
- Batch 11: FileStore Init
- Batch 12: FileStore Recovery
- Batch 16: Client Core (first half)
- Batch 17: Client Core (second half)

All plans include mandatory verification protocol and anti-stub guardrails.
Updated batches.md with file paths and planned status.
2026-02-27 14:56:19 -05:00

528 lines
18 KiB
Markdown

# Batch 10 (OCSP Cache + JS Events) Implementation Plan
> **For Codex:** REQUIRED SUB-SKILL: Use `executeplan` to implement this plan task-by-task.
**Goal:** Implement and verify Batch 10 (`20` features + `38` tests) for OCSP response-cache behavior and JetStream advisory publishing, while keeping externally blocked tests deferred with explicit evidence.
**Architecture:** Implement Batch 10 in three feature groups (1/13/6 IDs) and two test-resolution groups (candidate-verify + blocked-defer). Use strict per-feature verification loops, stub detection, and chunked status updates so every transition to `complete`/`verified` is evidence-backed.
**Tech Stack:** .NET 10, C# latest, xUnit 3, Shouldly, NSubstitute, PortTracker CLI, SQLite (`porting.db`)
---
I'm using `writeplan` to create the implementation plan.
**Design doc:** `docs/plans/2026-02-27-batch-10-ocsp-cache-js-events-design.md`
## Batch 10 Working Set
Batch facts:
- Batch ID: `10`
- Depends on: `9`
- Features: `20`
- Tests: `38`
- Go files: `server/ocsp_responsecache.go`, `server/jetstream_events.go`
Environment note:
- In this workspace, use `/usr/local/share/dotnet/dotnet` (not `dotnet`) for CLI commands.
Feature groups (all <= 20 IDs):
- **F1 (1):** `1959`
- **F2 (13):** `2472,2484,2485,2486,2487,2488,2489,2490,2491,2492,2493,2494,2495`
- **F3 (6):** `2496,2497,2498,2499,2500,2501`
Test groups:
- **T1 candidate verify (8):** `1537,1538,1607,1625,1682,2442,2807,2894`
- **T2 dependency-blocked (30):** `641,684,1407,1837,1934,1946,1978,2002,2005,2042,2049,2050,2051,2052,2055,2058,2059,2060,2061,2062,2063,2177,2250,2487,2810,2812,2839,2862,3103,3112`
---
## MANDATORY VERIFICATION PROTOCOL
> NON-NEGOTIABLE: Every task in this plan must follow this protocol.
### Per-Feature Verification Loop (required for every feature ID)
1. Read mapping + Go source:
```bash
/usr/local/share/dotnet/dotnet run --project tools/NatsNet.PortTracker -- feature show <feature_id> --db porting.db
```
2. Read exact Go implementation in `golang/nats-server/server/jetstream_events.go` or `golang/nats-server/server/ocsp_responsecache.go`.
3. Write/adjust C# implementation in mapped .NET file.
4. Build immediately:
```bash
/usr/local/share/dotnet/dotnet build dotnet/
```
5. Run related focused tests for that feature group.
6. Only after build + focused tests pass, add ID to promotion candidate list.
### Stub Detection Check (required after every feature/test group)
Run all checks before status updates:
```bash
# Placeholder/stub markers in touched code
rg -n "NotImplementedException|TODO|PLACEHOLDER|throw new NotSupportedException" \
dotnet/src/ZB.MOM.NatsNet.Server \
dotnet/tests/ZB.MOM.NatsNet.Server.Tests
# Empty method bodies in touched C# files
for f in $(git diff --name-only -- '*.cs'); do
rg -n "^\s*(public|internal|private|protected).+\)\s*\{\s*\}$" "$f"
done
# Suspicious trivial returns in touched production files
for f in $(git diff --name-only dotnet/src/ZB.MOM.NatsNet.Server -- '*.cs'); do
rg -n "=>\s*(default|null|true|false);$" "$f"
done
```
Any hit blocks promotion to `complete` or `verified` until fixed or explicitly deferred.
### Build Gate (required after each feature group)
```bash
/usr/local/share/dotnet/dotnet build dotnet/
```
Required: `0` compile errors.
### Test Gate (required before marking features verified)
All tests related to current feature group must pass before moving feature IDs to `verified`.
Focused test commands are defined inside each task. If any test fails, do not promote.
### Status Update Protocol (required)
- Maximum `15` IDs per `feature batch-update` or `test batch-update` command.
- Required evidence per update command:
- latest build gate output
- latest focused test gate output
- latest stub detection output
- Required flow:
- Feature IDs: `deferred -> stub -> complete -> verified`
- Test IDs: `deferred -> stub -> verified` or remain `deferred` with blocker reason
Command templates:
```bash
/usr/local/share/dotnet/dotnet run --project tools/NatsNet.PortTracker -- \
feature batch-update --ids "<max15ids>" --set-status <stub|complete|verified> --db porting.db --execute
/usr/local/share/dotnet/dotnet run --project tools/NatsNet.PortTracker -- \
test batch-update --ids "<max15ids>" --set-status <stub|verified> --db porting.db --execute
```
### Checkpoint Protocol Between Tasks (required)
Between every task boundary (Task 1 -> Task 2 -> ...):
1. Full build:
```bash
/usr/local/share/dotnet/dotnet build dotnet/
```
2. Full unit test run:
```bash
/usr/local/share/dotnet/dotnet test dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ --verbosity normal
```
3. Commit checkpoint:
```bash
git add <touched-files> porting.db
git commit -m "feat(batch10): <task checkpoint summary>"
```
---
## ANTI-STUB GUARDRAILS
### Forbidden Patterns
Do not mark as `verified` if any mapped method/test includes:
- `throw new NotImplementedException(...)`
- empty mapped method bodies (`{ }`)
- `TODO` or placeholder comments in method/test bodies
- fake pass assertions (`Assert.True(true)`, equivalent no-op assertions)
- tests that only assert non-behavioral values (for example, not-null only with no behavior)
### Hard Limits
- Max `20` feature IDs per implementation task group.
- Max `15` IDs per status update command.
- No cross-group bulk verification in one command cycle.
- Build gate is mandatory after each feature group.
- Test gate is mandatory before any feature moves to `verified`.
- Checkpoint commit is mandatory between tasks.
### If You Get Stuck
Do not stub and do not fake-pass.
1. Leave item as `deferred`.
2. Record specific blocker reason (dependency ID, missing runtime path, or infra need).
3. Continue with next unblocked item.
Commands:
```bash
/usr/local/share/dotnet/dotnet run --project tools/NatsNet.PortTracker -- \
feature update <id> --status deferred --db porting.db \
--override "blocked: <specific reason>"
/usr/local/share/dotnet/dotnet run --project tools/NatsNet.PortTracker -- \
test update <id> --status deferred --db porting.db \
--override "blocked: <specific reason>"
```
---
### Task 1: Preflight and Batch Start
**Files:**
- Modify: `porting.db`
**Step 1: Verify dependency batch state**
```bash
/usr/local/share/dotnet/dotnet run --project tools/NatsNet.PortTracker -- batch show 9 --db porting.db
```
Expected: Batch 9 is complete enough to start Batch 10.
**Step 2: Start Batch 10**
```bash
/usr/local/share/dotnet/dotnet run --project tools/NatsNet.PortTracker -- batch start 10 --db porting.db
```
Expected: Batch 10 transitions to in-progress.
**Step 3: Baseline dependency evidence for Batch 10 tests**
```bash
cat <<'SQL' | sqlite3 -header -column porting.db
WITH t AS (
SELECT ut.id, ut.name
FROM unit_tests ut
JOIN batch_tests bt ON bt.test_id=ut.id
WHERE bt.batch_id=10
), unresolved AS (
SELECT d.source_id AS test_id,
SUM(CASE WHEN f.status NOT IN ('complete','verified','n_a') THEN 1 ELSE 0 END) AS unresolved_total,
SUM(CASE WHEN f.status NOT IN ('complete','verified','n_a')
AND f.id NOT IN (SELECT feature_id FROM batch_features WHERE batch_id=10)
THEN 1 ELSE 0 END) AS unresolved_outside_batch
FROM dependencies d
JOIN features f ON d.target_type='feature' AND d.target_id=f.id
WHERE d.source_type='unit_test' AND d.source_id IN (SELECT id FROM t)
GROUP BY d.source_id
)
SELECT * FROM unresolved ORDER BY test_id;
SQL
```
Expected: `T1` IDs have `unresolved_outside_batch=0`; `T2` IDs have `>0`.
**Step 4: Run checkpoint protocol and commit preflight evidence**
---
### Task 2: Implement Feature Group F1 (`1959`) JetStream Advisory Publish
**Files:**
- Create: `dotnet/src/ZB.MOM.NatsNet.Server/NatsServer.JetStreamEvents.cs`
- Create: `dotnet/tests/ZB.MOM.NatsNet.Server.Tests/NatsServerJetStreamEventsTests.cs`
- Modify: `porting.db`
**Step 1: Mark feature `1959` as `stub`**
```bash
/usr/local/share/dotnet/dotnet run --project tools/NatsNet.PortTracker -- \
feature update 1959 --status stub --db porting.db
```
**Step 2: Write failing tests for advisory decision tree**
Cover:
- null account falls back to `SystemAccount()`
- no interest returns false without send
- marshal/send errors return false
- successful send returns true
**Step 3: Run focused tests and confirm initial fail**
```bash
/usr/local/share/dotnet/dotnet test dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ \
--filter "FullyQualifiedName~NatsServerJetStreamEventsTests" --verbosity normal
```
**Step 4: Implement `PublishAdvisory` parity in new partial class**
**Step 5: Re-run focused tests and require pass**
Use same command as Step 3.
**Step 6: Run stub detection + build gate + test gate**
**Step 7: Promote feature `1959`**
```bash
/usr/local/share/dotnet/dotnet run --project tools/NatsNet.PortTracker -- \
feature update 1959 --status complete --db porting.db
/usr/local/share/dotnet/dotnet run --project tools/NatsNet.PortTracker -- \
feature update 1959 --status verified --db porting.db
```
**Step 8: Run checkpoint protocol and commit**
---
### Task 3: Implement Feature Group F2 (`2472,2484-2495`) Local Cache Core + Stats + Compression
**Files:**
- Modify: `dotnet/src/ZB.MOM.NatsNet.Server/Auth/Ocsp/OcspTypes.cs`
- Create: `dotnet/src/ZB.MOM.NatsNet.Server/Auth/Ocsp/OcspHandler.cs`
- Modify: `dotnet/tests/ZB.MOM.NatsNet.Server.Tests/Auth/OcspResponseCacheTests.cs`
- Create: `dotnet/tests/ZB.MOM.NatsNet.Server.Tests/Auth/OcspResponseCacheParserTests.cs`
- Modify: `porting.db`
**Step 1: Mark F2 IDs as `stub` (single command, 13 IDs <= 15)**
```bash
/usr/local/share/dotnet/dotnet run --project tools/NatsNet.PortTracker -- \
feature batch-update --ids "2472,2484,2485,2486,2487,2488,2489,2490,2491,2492,2493,2494,2495" \
--set-status stub --db porting.db --execute
```
**Step 2: Add failing tests for local cache behavior**
Cover:
- stats adjust on put/replace/delete
- hit->miss adjustment when preserving revoked entries
- `Online/Type/Config/Stats` semantics
- compress/decompress round-trip
- `NewOCSPResponseCacheConfig` defaults
**Step 3: Run focused tests and confirm initial fail**
```bash
/usr/local/share/dotnet/dotnet test dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ \
--filter "FullyQualifiedName~OcspResponseCacheTests|FullyQualifiedName~OcspResponseCacheParserTests" --verbosity normal
```
**Step 4: Implement F2 methods with per-feature verification loop**
**Step 5: Re-run focused tests and require pass**
Use same command as Step 3.
**Step 6: Run stub detection + build gate + test gate**
**Step 7: Promote F2 IDs in two transitions (`complete`, then `verified`)**
```bash
/usr/local/share/dotnet/dotnet run --project tools/NatsNet.PortTracker -- \
feature batch-update --ids "2472,2484,2485,2486,2487,2488,2489,2490,2491,2492,2493,2494,2495" \
--set-status complete --db porting.db --execute
/usr/local/share/dotnet/dotnet run --project tools/NatsNet.PortTracker -- \
feature batch-update --ids "2472,2484,2485,2486,2487,2488,2489,2490,2491,2492,2493,2494,2495" \
--set-status verified --db porting.db --execute
```
**Step 8: Run checkpoint protocol and commit**
---
### Task 4: Implement Feature Group F3 (`2496,2497,2498,2499,2500,2501`) Load/Save + Server Wiring + Parser
**Files:**
- Modify: `dotnet/src/ZB.MOM.NatsNet.Server/Auth/Ocsp/OcspTypes.cs`
- Modify: `dotnet/src/ZB.MOM.NatsNet.Server/Auth/Ocsp/OcspHandler.cs`
- Create: `dotnet/src/ZB.MOM.NatsNet.Server/NatsServer.OcspResponseCache.cs`
- Modify: `dotnet/src/ZB.MOM.NatsNet.Server/NatsServer.Init.cs`
- Modify: `dotnet/src/ZB.MOM.NatsNet.Server/NatsServer.Lifecycle.cs`
- Create: `dotnet/tests/ZB.MOM.NatsNet.Server.Tests/NatsServerOcspCacheTests.cs`
- Modify: `dotnet/tests/ZB.MOM.NatsNet.Server.Tests/Auth/OcspResponseCacheParserTests.cs`
- Modify: `porting.db`
**Step 1: Mark F3 IDs as `stub` (6 IDs)**
```bash
/usr/local/share/dotnet/dotnet run --project tools/NatsNet.PortTracker -- \
feature batch-update --ids "2496,2497,2498,2499,2500,2501" --set-status stub --db porting.db --execute
```
**Step 2: Add failing tests for load/save lifecycle + parser + server init/start/stop**
Cover:
- load from absent/corrupt/valid cache file
- save no-op when clean + atomic write when dirty
- parser type conversion + minimum save interval clamp
- server init chooses no-op/local cache correctly
- start/stop wiring calls cache lifecycle
**Step 3: Run focused tests and confirm initial fail**
```bash
/usr/local/share/dotnet/dotnet test dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ \
--filter "FullyQualifiedName~OcspResponseCacheTests|FullyQualifiedName~OcspResponseCacheParserTests|FullyQualifiedName~NatsServerOcspCacheTests" --verbosity normal
```
**Step 4: Implement F3 methods with per-feature verification loop**
**Step 5: Re-run focused tests and require pass**
Use same command as Step 3.
**Step 6: Run stub detection + build gate + test gate**
**Step 7: Promote F3 IDs (`complete`, then `verified`)**
```bash
/usr/local/share/dotnet/dotnet run --project tools/NatsNet.PortTracker -- \
feature batch-update --ids "2496,2497,2498,2499,2500,2501" --set-status complete --db porting.db --execute
/usr/local/share/dotnet/dotnet run --project tools/NatsNet.PortTracker -- \
feature batch-update --ids "2496,2497,2498,2499,2500,2501" --set-status verified --db porting.db --execute
```
**Step 8: Run checkpoint protocol and commit**
---
### Task 5: Resolve Batch 10 Tests (T1 verify, T2 defer with reason)
**Files:**
- Modify: `dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog/JetStreamEngineTests.Impltests.cs`
- Modify: `dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog/ConcurrencyTests1.Impltests.cs`
- Modify: `dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog/RouteHandlerTests.Impltests.cs`
- Modify: `dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog/NatsServerTests.Impltests.cs`
- Modify: `porting.db`
**Step 1: Mark T1 + T2 IDs as `stub` in chunks <= 15**
```bash
/usr/local/share/dotnet/dotnet run --project tools/NatsNet.PortTracker -- \
test batch-update --ids "1537,1538,1607,1625,1682,2442,2807,2894" --set-status stub --db porting.db --execute
/usr/local/share/dotnet/dotnet run --project tools/NatsNet.PortTracker -- \
test batch-update --ids "641,684,1407,1837,1934,1946,1978,2002,2005,2042,2049,2050,2051,2052,2055" \
--set-status stub --db porting.db --execute
/usr/local/share/dotnet/dotnet run --project tools/NatsNet.PortTracker -- \
test batch-update --ids "2058,2059,2060,2061,2062,2063,2177,2250,2487,2810,2812,2839,2862,3103,3112" \
--set-status stub --db porting.db --execute
```
**Step 2: Port and verify T1 tests one-by-one using per-test loop**
For each T1 test ID:
```bash
/usr/local/share/dotnet/dotnet run --project tools/NatsNet.PortTracker -- test show <test_id> --db porting.db
/usr/local/share/dotnet/dotnet test dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ \
--filter "FullyQualifiedName~<ExactMethodName>" --verbosity normal
```
Expected: each verified method shows `Passed: 1`.
**Step 3: Promote T1 verified tests in one chunk (8 IDs <= 15)**
```bash
/usr/local/share/dotnet/dotnet run --project tools/NatsNet.PortTracker -- \
test batch-update --ids "1537,1538,1607,1625,1682,2442,2807,2894" --set-status verified --db porting.db --execute
```
**Step 4: For T2, prove unresolved external dependencies and keep deferred**
```bash
cat <<'SQL' | sqlite3 -header -column porting.db
WITH t AS (
SELECT ut.id, ut.name
FROM unit_tests ut
JOIN batch_tests bt ON bt.test_id=ut.id
WHERE bt.batch_id=10
AND ut.id IN (641,684,1407,1837,1934,1946,1978,2002,2005,2042,2049,2050,2051,2052,2055,
2058,2059,2060,2061,2062,2063,2177,2250,2487,2810,2812,2839,2862,3103,3112)
)
SELECT t.id, t.name, f.id AS blocked_feature_id, f.name AS blocked_feature_name, f.status
FROM t
JOIN dependencies d ON d.source_type='unit_test' AND d.source_id=t.id AND d.target_type='feature'
JOIN features f ON f.id=d.target_id
WHERE f.status NOT IN ('complete','verified','n_a')
AND f.id NOT IN (SELECT feature_id FROM batch_features WHERE batch_id=10)
ORDER BY t.id, f.id;
SQL
```
Then keep each blocked test deferred with reason:
```bash
/usr/local/share/dotnet/dotnet run --project tools/NatsNet.PortTracker -- \
test update <blocked_test_id> --status deferred --db porting.db \
--override "blocked: unresolved dependency feature <id> (<name>)"
```
**Step 5: Run stub detection + build gate + test gate + checkpoint commit**
---
### Task 6: Final Batch 10 Verification and Attempted Closure
**Files:**
- Modify: `porting.db`
- Generate: `reports/current.md`
**Step 1: Full verification gates**
```bash
/usr/local/share/dotnet/dotnet build dotnet/
/usr/local/share/dotnet/dotnet test dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ --verbosity normal
```
Expected: build passes; no unexpected test regressions.
**Step 2: Global stub audit for touched scope**
```bash
rg -n "NotImplementedException|TODO|PLACEHOLDER|Assert\.True\(true\)" \
dotnet/src/ZB.MOM.NatsNet.Server \
dotnet/tests/ZB.MOM.NatsNet.Server.Tests
```
Expected: no matches in Batch 10 touched code/tests.
**Step 3: Verify batch/test visibility**
```bash
/usr/local/share/dotnet/dotnet run --project tools/NatsNet.PortTracker -- batch show 10 --db porting.db
/usr/local/share/dotnet/dotnet run --project tools/NatsNet.PortTracker -- report summary --db porting.db
```
**Step 4: Try completing batch**
```bash
/usr/local/share/dotnet/dotnet run --project tools/NatsNet.PortTracker -- batch complete 10 --db porting.db
```
If blocked by deferred T2 tests, keep batch in-progress with documented blockers (correct behavior).
**Step 5: Generate report and final commit**
```bash
./reports/generate-report.sh
git add dotnet/src/ZB.MOM.NatsNet.Server \
dotnet/tests/ZB.MOM.NatsNet.Server.Tests \
porting.db reports/
git commit -m "feat(batch10): implement ocsp cache and js advisory with verified gates"
```