Repository navigation
CLI history export loses whole-float memo kinds and fails its own verifier #912
Description
Problem
The published history-export CLI loses a memo's numeric kind and writes a bundle that the same published Core verifier refuses. A workflow with memo whole=1.0 completes normally, but the exported display projection contains JSON integer 1 while its lossless Avro memo authority still decodes to a float. Persisted workflow execution and the Avro authority remain intact; the loss occurs in the exported JSON.
Actual published-artifact evidence
Qualified tuple: Server 2.9.7 / 150f3fbcbf3911a2a20abb53b4a714081ee53dd7, amd64 image sha256:40e969d0b6b240b835dcdb2fc531507266216ec34a83f59f561674f41e35f461; loaded Core 2.7.2 / 64efa176e4c37e5d6ae80e767ba3b41464024e53. All 615 loaded Core source files match the immutable source. Composer's generated path reference is separate metadata, 9477eaaf970e9ce09da337f662e71178a05c6342. No runtime source overlay.
A real SQLite workflow and activity used original 30-second run/execution budgets. Actual workflow:v2:history-export --run --pretty wrote selected-run bundles while waiting (3 events) and after completion (6 events). Both original files are retained byte-for-byte. The released BundleIntegrityVerifier::verifyJson refuses each with workflow.memo_projection_mismatch and integrity.checksum_mismatch. The actual published workflow:v2:replay-verify --skip-replay command, invoked through Artisan, returns 1 for both files. Their raw hashes are unchanged before/after verification.
| Actual export | Raw-file SHA256 | Recorded canonical SHA256 | Published verifier recomputation |
|---|---|---|---|
| waiting | 2a11c8ce20d7433fe6b15d98f958f31daac34e34f92eaca451868d0fb9794fea |
38c1b65717058fbaa588c52919a223941b04d3c7a57620f557356938eea28070 |
49dff74395d6c75f118377fcadb9515cf414cefa0cb7755c7e6d5af5d55b7c76 |
| completed | 71bc8043b9634297abfe26b58bca788f4c245129adc4d16851cab36889c719e7 |
2b900246391a0293ccb2fde0bf4d1cf1ae5f67c2c1d6d6ddacaccdb55a976761 |
0dfe2dc726f70c9519b1943b3c2b63cc2235ef3aa78a42d533f70ac4d66c2be6 |
The original failed exports and provenance are retained as negative controls in SDK PR #208. The corrected SDK reader also rejects these producer-invalid bytes. This is separate from SDK #173, whose valid schema-2/Unicode reader controls are accepted independently. Neither a version rewrite nor a recalculated checksum was used to force acceptance.
Reproduction and source boundary
- Start an ordinary workflow with
new StartOptions(memo: ['whole' => 1.0])and export the selected run using the published CLI. - Parse the JSON and compare
workflow.memo.wholewithMemoPayload::decodeEntries(workflow.memo_payload)['whole']: the former is an integer, the latter a float. - Run published integrity-only verification against the untouched export; it returns failure.
V2HistoryExportCommand::encode serializes without JSON_PRESERVE_ZERO_FRACTION, while HistoryExport canonicalization preserves fractional-zero floats. This explains both type and checksum failures. The HTTP export surface needs its own audit; this report establishes the CLI case, not a tested HTTP failure.
Acceptance
- Preserve numeric kinds throughout CLI JSON export, including nested memo/history projections and signed zero, while retaining the existing schema and canonicalization contract.
- Actual waiting and completed exports containing whole-valued floats pass the published verifier with unchanged checksums and correct memo authority/projection.
- Keep invalid older export bytes rejected and retain these unsuccessful originals. Add positive/negative regression controls and verify actual CLI output, not only an in-memory exporter array.
- Audit other JSON export transports for the same loss and track any affected transport separately.
- Publish a qualified compatible correction and verify normally installed/exported behavior. No runtime deadline, protocol-floor or stored-history change is required.
P2 product defect. This record contains reproduction and evidence; no Core/Server implementation change is included.
Current delivery
CLI source correction #913 is merged at ae6bf6c / whole36045935 after seventeen applicable candidate checks pass. Independent main and compatible 2.11.4 publication/normal installation remain pending. Actual published Server HTTP evidence is confirmed separately in #692/#693; the Core CLI correction alone does not fix that transport. Original invalid exports remain rejected.
Activity
rmcdaniel commentedon Oct 23, 2026
Separate published Server 2.11.1 / installed Core 2.10.2 qualification confirms this producer failure in both CLI and HTTP exports, while leaving the independent Core 2.11.3 investigation separate.
5336a98dd256e046edfdb67c81764cde4babd360; published imageghcr.io/durable-workflow/server@sha256:bf8bed13f5f809ee3425233180a581353eac4683adbee5c4ecbf63bb18bbd102(local image IDc53162134a94025a0b87b995e9b14896c1fdfffbeeace3b530d3fbd0f2b23c6c). All 313 installed Server files underapp/,config/androutes/match that commit. Installed Core reports 2.10.2; all 641 Core source files match its published sourceaca7928484083635e68a5a384b2dcecef842108e. Composer's generated reference is separatelyc1e248afe31060f13216704ac6de9a514ba4c733. PHP 8.3.36. No source overlay.04116871c83e6a502c713789cb452e90917a3438, wheel SHA-2561e7547e895485dc8f670bd1b9cc34184b135f249db8da98b16b250bfc6002f73; all 36 installed Python files match the published tag and wheel RECORD. Its normalClient.export_history(workflow_id, run_id)receives HTTP 200 fromGET /api/workflows/{id}/runs/{runId}/history/export. Raw response bytes were captured before parsing, without reserialization.{'whole': 1.0, 'signed_zero': -0.0, 'nested': {'whole': 2.0, 'signed_zero': -0.0, 'list': [3.0, -0.0, 1.5]}}, with original 30-second execution and run budgets. It waited with three events, completed a real activity and workflow in 2.065 seconds, then had six events. CLI and HTTP exports were captured in both states.BundleIntegrityVerifier::verifyJsonandworkflow:v2:replay-verify --skip-replay(exit 1), each withworkflow.memo_projection_mismatchandintegrity.checksum_mismatch. Each JSON projection has integer1,2,0; authoritative Avro values remain float1.0,2.0,-0.0(signed-zero float64 bytes8000000000000000). Thus HTTP failure is now an observation, beyond source suspicion. These are integrity checks; candidate-code replay was not run.7eaf0877dcbbaa481ddd2f57f69b4c718eb2dc3abd3946b0e723a86515b0ac5a05240fdac68c2398a17bb5262a4d1e7a76b22018fe4eea3b5cc5444e98687d0cbf76c9fa4eb5401c75da75bafbaf55a00eb5cbe120431beca234396f595bc90f6e5eb0a98f30fb50f8cf8acec8e8eaf8f7537a373559be16ad3acc1177d59d09These fresh files and reports are retained for producer follow-through. They do not replace the historical Core 2.7.2 failed originals or Website #320 evidence. The Python #173 reader continues rejecting the typed disagreement. No Core/Server/native/frozen source was edited.
rmcdaniel commentedon Oct 23, 2026
Current-source correction is merged as #913:
ae6bf6c8a7c4b9597ee4eecb15ecd786e78b0430, exact tested whole tree3604593569c80ba2319d9a2ee1d39ab33b206357. All seventeen applicable candidate checks pass, with six explicit skips, and the actual PR Sonar issue API reports zero OPEN/CONFIRMED findings. The merged remote branch is independently absent.The fresh normal 2.11.3 install matches all 643 immutable source files at
71213ae1, without an overlay. All four actual waiting/completed compact/pretty export regressions fail there and on the unchanged parent. Corrected source passes 4 tests / 56 assertions, including exact nested numeric kinds, signed-zero bit behavior, untouched-file integrity-only replay verification and refusal of lossy representations. Focused ECS and PHPStan pass. The first fixture also compared noncanonical map order; its corrected version still fails all four parent cases specifically on numeric kinds.Fresh main build39947240076, code quality39947240082, Sonar39947239603, dependency security39947240010 and boundary39947239994 are independent and still qualifying. Compatible 2.11.4 is not published yet; registry installation and published-profile acceptance remain next.
The separate HTTP defect is now Server #692 / PR #693. Its source-only correction passes 49 ordinary history/control-plane cases / 700 assertions after both failing-before numeric cases. No published Server image, stored-history rewrite, reader coercion or cross-tree adoption is claimed.
rmcdaniel commentedon Oct 23, 2026
CLI package correction delivered as Workflow 2.11.4.
23c667746de44cb1fd5cc280df7bd63615f82a2bselects qualified merge/sourceae6bf6c8a7c4b9597ee4eecb15ecd786e78b0430, whole tree3604593569c80ba2319d9a2ee1d39ab33b206357. GitHub release and normal Packagist source/dist agree.Both original published2.11.3/unchanged-parent four-case failures remain failures; the earlier map-order fixture error remains separate. This release creates valid future exports and does not reinterpret invalid older JSON.
Affected Server CLI/HTTP image delivery is still pending: Server #692 / #693 has fully qualified main
b57e3c97/613829c3, but that source still pins Core2.11.2. General will separately qualify the published2.11.4 pin, image and installed transports. This issue remains open for that affected consumer; no native, frozen or Cloud adoption is claimed. The all-locale export guard follows the exact package receipt.