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

18 KiB

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:
/usr/local/share/dotnet/dotnet run --project tools/NatsNet.PortTracker -- feature show <feature_id> --db porting.db
  1. Read exact Go implementation in golang/nats-server/server/jetstream_events.go or golang/nats-server/server/ocsp_responsecache.go.
  2. Write/adjust C# implementation in mapped .NET file.
  3. Build immediately:
/usr/local/share/dotnet/dotnet build dotnet/
  1. Run related focused tests for that feature group.
  2. 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:

# 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)

/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:

/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:
/usr/local/share/dotnet/dotnet build dotnet/
  1. Full unit test run:
/usr/local/share/dotnet/dotnet test dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ --verbosity normal
  1. Commit checkpoint:
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:

/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

/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

/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

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

/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

/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

/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)

/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

/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)

/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)

/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

/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)

/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

/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:

/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)

/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

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:

/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

/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

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

/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

/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

./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"