test(smoke): live JFI batch $batch smoke trigger (v3.0.0 release gate)#147
Conversation
Add LedgerJournalBatchSmokeTest_HTTPTrigger (POST smoke/ledger-journal-batch) exercising the v3.0.0 chunked $batch path end-to-end against a live D365 F&O sandbox: chunked atomic create, atomic-changeset rollback (good + bogus-key op), continue-on-error partial accept, and batch delete — self-cleaning. Deterministic failure injection via a non-existent LineNumber (guaranteed 404). Documents the route in wiki/Run-Smoke-Tests.md as the v3.0.0 release gate. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
Review summary
This PR adds LedgerJournalBatchSmokeTest_HTTPTrigger, a live-verification smoke test for the v3.0.0 configurable chunked $batch write path (ADR-0004): chunked atomic create, atomic-changeset rollback proof, ContinueOnError partial-accept proof, and batch delete, all under one journal header, plus matching wiki docs. It is diagnostic host code only — no IntegratoR.* library surface touched. Overall risk is low: no new business logic in the packable libraries, only a new SampleFunction endpoint that consumes already-shipped, already-tested batch APIs (CreateBatchCommand<T>, UpdateBatchCommand<T>, DeleteBatchCommand<T>, BatchOptions, BatchOutcome).
I read the diff in full against the code-reviewer rubric, the C# coding-standards skill, and the architecture/perf-reliability/common rules, and cross-checked every batch API call site (BatchOptions.MaxOperationsPerChunk, BatchOutcome.{Total,ChunkCount,Items,AllSucceeded,Failures}, BatchItemResult.Index, BatchIntegrationError.Outcome) against their actual definitions and against ODataService.RunBatchInChunksAsync's chunking/rollback semantics — the smoke test's expectations (e.g. expectedChunks = ⌈LineCount/ChunkSize⌉, sequential Index ordering) match the real implementation. I also diffed the new trigger against the existing, already-reviewed LedgerJournalSmokeTestTrigger sibling and found it follows the same conventions consistently (BuildStep/BestEffortCleanup shape, Result.Value null-guard on 204 writes, generic-error-message-to-caller / full-detail-to-log-only split, var usage matching the established in-repo convention for _mediator.Send(...) results).
Blocker: none.
Major: none.
Minor:
IntegratoR.SampleFunction/Endpoints/LedgerJournalBatchSmokeTestTrigger.cs:131— theChunkSize > 200bound is a hardcoded magic number duplicating the doc comment onBatchOptions.MaxOperationsPerChunk("Must be between 1 and 200"); no shared constant exists to reference. Low risk since it's host-only diagnostic input validation, but worth a named constant if this ceiling is asserted in more than one place in future.
Nit: none beyond the above.
Hard-rule check (all clean): Result<T> used throughout, no throw for business flow; ConfigureAwait(false) present on every awaited call; CancellationToken propagated end-to-end; no var on non-obvious types beyond the pre-existing sibling-file convention; no repository wrapping — all access via IMediator; no AutoMapper; Central Package Management untouched (no new package refs). Test adequacy: the PR ships no new unit tests, with an explicit, reasonable justification (no SampleFunction test project exists, HttpRequestData faking is low-ROI, and the underlying batch chunking/atomicity logic is already covered by ODataServiceBatchChunkingTests / ODataClientAdapterAtomicBatchTests / ODataBatchWireTests) — consistent with how the sibling LedgerJournalSmokeTestTrigger was accepted with no unit tests either.
Stages run: Stage 1 (correctness/hard-rule/architecture/test) ran in full per the workflow flags. Stage 2 (security) and Stage 3 (API compatibility) were both flagged false and skipped — correctly: there is no auth/secret/header surface here, and the SampleFunction host is not a published IntegratoR.* package. Mechanical CI (dotnet build, dotnet test, dotnet format --verify-no-changes, vulnerable-package scan) lives in build.yml and was not recomputed here; the PR's own build check reports SUCCESS via gh pr view --json statusCheckRollup, though I was unable to drill into the individual job-step results (the test step specifically) in this session due to tool access limits on gh run/gh api — worth a human double-check that the test step, not just overall job status, is green given it runs with continue-on-error: true.
Verdict: approve-with-changes (the one Minor is optional polish, not merge-blocking).
Summary
Adds
LedgerJournalBatchSmokeTest_HTTPTrigger(POST /api/smoke/ledger-journal-batch) — the live-verification harness for the v3.0.0 configurable chunked$batchfeature (#145 / ADR-0004). Under one journal header it drives, via MediatR batch commands, against a live D365 F&O sandbox:ChunkSize→ several$batchchangesets; assertsTotal,ChunkCount, global indices,AllSucceeded.Atomicchangeset → the whole changeset must roll back; re-read proves the good op did not persist.ContinueOnError→Succeeded=1, Failed=1; re-read proves the good op did persist.Failure injection is deterministic (a non-existent
LineNumber→ guaranteed 404), so it does not depend on D365 account validation. Mirrors the existingLedgerJournalSmokeTestTriggerpattern (BuildStep, best-effort cleanup, generic error messages). Also documents the route inwiki/Run-Smoke-Tests.md.Live JFI run status —⚠️ deferred (backend unreachable right now)
I built this and ran it against JFI from the dev host. The run could not complete: the very first
CreateHeader(an ordinaryCreateCommand, unchanged code) returned HTTP 500 after ~230s, and the pre-existing, unchangedsmoke/ledger-journaltrigger fails identically. No VPN adapter is present on the host. ⇒ Environmental — the JFI backend is not healthily reachable from this environment now (needs the corporate network/VPN), not a code defect.Release gate (must pass before v3.0.0): re-run the one command in
wiki/Run-Smoke-Tests.md(§ Ledger journal batch smoke test) once on the JFI network and confirmSuccess: true.Tests
dotnet buildgreen; full suite green (0 failed). No new unit tests: the SampleFunction host has no test project, fakingHttpRequestDatais low-ROI, and the batch feature itself is already unit-tested (ODataServiceBatchChunkingTests,ODataClientAdapterAtomicBatchTests,ODataBatchWireTests) — the authoritative validation for a smoke trigger is the live run.Risks / rollback
Diagnostic host endpoint only; no change to any
IntegratoR.*library surface. Rollback = revert.🤖 Generated with Claude Code