Repository navigation
docker: queue encoded column rows and cut the per-batch work of the equity proof - #652
Conversation
…quity proof Trade spool: every ordinary trade row cost two logical writes to its column (the separator and the row) and one dispatch through the generic JSON streamer. Encode the row once with the same dumps configuration the scalar fast path used and queue it, with its separator, in the artifact file; the queue is drained inside the existing 512-record and 256 KiB bounds, before any write, flush, read, rewind or close of that file, and after the checked reader close of a fused verification. A failed physical write clears the queue before writing so the same text is never retried; a drain failure becomes the same typed report_sink_failed refusal, remembered and raised at the same point relative to the other refusals. The byte stream, the aligned windows and the sync count are unchanged. Equity proof: the permitted repeat of the original run pattern is derived once with the pattern instead of by parsing the pattern text for every batch, and the first and last endpoints of the curve are decoded on demand instead of building two dictionaries for every batch of interleaved rows. Every per-row numeric proof stays: the timestamp range, the finite check and the canonical repr comparison of every number, and the repeat bound still belongs to the run pattern alone. Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
…the equity proof Count the logical writes and the generic streamer dispatches per trade column, the joins per bounded batch at 1, 511, 512, 513, 1024 and 4097 trades, the interleaved equity batches, the repeat-bound work and the endpoint dictionaries of the proof, each against a verbatim copy of the previous code as a positive control. Pin byte identity of complete reports (stdout, sink, digest, receipt) over the existing families plus every finite float shape and every escape class, the strict fallback of noncanonical equity lines, the ordering of queued text against every other artifact operation, and the typed failure envelope of write, flush, close and short-write faults at the first, middle and last row or batch, including against each competing refusal. Mutation rows put each removed piece of work back and each dropped check out. The reference copies live in a support module that the harness glob does not collect. Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Only the file:line pins into docker/run_json.py change, following the lines the previous commits moved; no sentence is edited. Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
| _BULK_E_LITERAL_BYTES = run_json._BULK_E_LITERAL_BYTES | ||
|
|
||
|
|
||
| class _BulkEquity(run_json._BulkEquity): |
| from run_json import ( | ||
| RunFailure, ReportSinkReceiptC, _engine_invariant, _open_uncached_sink, | ||
| _sink_summary, _sink_trade, _stream_json, _SinkReportDiagnostics, | ||
| _filesystem_type, _MEMORY_FILESYSTEM_TYPES, | ||
| ) |
| import run_json_wrapper_test_support as fixtures | ||
| from run_json_wrapper_work_test import _EquityWork, _mutate, _EQUITY_WIRES | ||
| from run_json_fused_test import _sink_case, _configure_outputs, _synthetic_case | ||
| from run_json_trade_scan_test import _point, _trade, _event |
| import stat | ||
| import sys | ||
|
|
||
| import run_json |
There was a problem hiding this comment.
Graphify reviewed this change.
Worth a look — the grounded gate found no coupling regressions or blocking issues, but 1 advisory finding(s) below merit a look before merge.
Not checked: tests were not run; formal verification proved 0 of 8 changed function(s) (1 sampled, not proven, 7 not verified).
Formal verification. PR-changed functions: 1/8 verified (0 proven, 1 may-equivalent, 0 distinguished) · 7 not verified (1 vacuous, 6 unsupported).
Not verified on this run: \_append\_trade\_record (unsupported), \_verify\_fused (unsupported), append\_ascii (unsupported), flush (unsupported), trades (vacuous: never exercised), write (unsupported), write\_ascii (unsupported).
Graphify review — findings
Speeds up the fused report-sink path by batching column writes and deferring equity endpoint construction. Column rows are now joined in memory up to the streaming batch bounds and written together, with a drain step (_finish_fused_columns) before assembly so a pending-write failure still surfaces as the same deferred spool error. Trade records take a pre-encoded JSON fast path, and _bulk_equity caches the default run-pattern bounds so batches skip the per-call pattern parsing, with endpoints kept as tuples until read and the diagnostics' last point set from the final batch only.
Worth a look
- Fast trade path calls append_ascii without row_count, so it always fails the trades spool —
docker/run_json.py:6731· Escalate · high- NOT verified (no proof, no reproducing execution) — needs human review
Review partial — this diff was larger than one review pass covers, so later files were not reviewed; some findings may be missing.
Analysis details — impact, health, verification
Impact & health
Graphify review
Impact — 696 functions depend on the 682 functions this change touches.
Health — this change adds coupling hotspots:
- worse:
_sink_summary()— 4 callers, 4 callees - worse:
_open_uncached_sink()— 5 callers, 3 callees - new:
test_trade_spool_joins_replace_row_writes()— 0 callers, 6 callees
Verification — 696 functions in the blast radius were not formally verified this run (proofs are advisory here).
Gate & verification
graphify gate
PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.
Advisory (not blocking):
- verification_scope: 689 function(s) in the blast radius were not formally verified this run
Docs that may be stale (advisory)
AGENTS.md§ REQUIRED before claiming any change is done (lines 5-45): references changed symbolsfirstAGENTS.md§ SOP: adding a runtime PF_API export (CI gate — recurring failure) (lines 73-97): references changed symbolsrunCHANGELOG.md§ Live ledger report-checkpoint layouts (lines 72-79): references changed symbolsrunCHANGELOG.md§ Native live report stream updates (lines 112-176): references changed symbolsrunCHANGELOG.md§ Live ledger resource control (lines 253-272): references changed symbolsrunCHANGELOG.md§ Native live report stream (lines 337-358): references changed symbolsrunCHANGELOG.md§ Scratch placement (behaviour of 1.7.0 and later, restated) (lines 359-380): references changed symbolsrunCHANGELOG.md§ Opt-in report descriptor in the container entrypoint (lines 418-433): references changed symbolsrunCHANGELOG.md§ CI and release process (lines 449-510): references changed symbolsrunCHANGELOG.md§ run_json and CLI (lines 781-873): references changed symbolsclose,run
…and 10 more.
Formal verification
Could not verify: Could not verify \_append\_trade\_record.
The verifier did not have enough to check \_append\_trade\_record, so it is saying so rather than guessing. No false assurance is the whole point.
Guarantee: No guarantee either way, this is an honest abstention, not a pass.
Note: Reason: method — first parameter is `self`, which needs a constructed instance (not synthesizable)
No difference found (not proven): No behavior difference found in \_bulk\_equity (not a proof).
The verifier ran both versions of \_bulk\_equity on many inputs and saw identical behavior every time. Strong evidence the change is safe, but evidence, not a proof.
Guarantee: Empirical: differential testing (both versions run on many generated inputs). A divergence on an untested input remains possible, so this is 'no counterexample found', not 'proven equivalent'.
Note: An input the sampler did not try could still differ.
Could not verify: Could not verify \_verify\_fused.
The verifier did not have enough to check \_verify\_fused, so it is saying so rather than guessing. No false assurance is the whole point.
Guarantee: No guarantee either way, this is an honest abstention, not a pass.
Note: Reason: method — first parameter is `self`, which needs a constructed instance (not synthesizable)
Could not verify: Could not verify append\_ascii.
The verifier did not have enough to check append\_ascii, so it is saying so rather than guessing. No false assurance is the whole point.
Guarantee: No guarantee either way, this is an honest abstention, not a pass.
Note: Reason: method — first parameter is `self`, which needs a constructed instance (not synthesizable)
Could not verify: Could not verify flush.
The verifier did not have enough to check flush, so it is saying so rather than guessing. No false assurance is the whole point.
Guarantee: No guarantee either way, this is an honest abstention, not a pass.
Note: Reason: method — first parameter is `self`, which needs a constructed instance (not synthesizable)
Could not verify: Could not verify trades.
The verifier did not have enough to check trades, so it is saying so rather than guessing. No false assurance is the whole point.
Guarantee: No guarantee either way, this is an honest abstention, not a pass.
Note: Reason: not verifiable: all 109 sampled inputs raised on both versions — the function never executed, so 'no divergence' would be vacuous
Could not verify: Could not verify write.
The verifier did not have enough to check write, so it is saying so rather than guessing. No false assurance is the whole point.
Guarantee: No guarantee either way, this is an honest abstention, not a pass.
Note: Reason: method — first parameter is `self`, which needs a constructed instance (not synthesizable)
Could not verify: Could not verify write\_ascii.
The verifier did not have enough to check write\_ascii, so it is saying so rather than guessing. No false assurance is the whole point.
Guarantee: No guarantee either way, this is an honest abstention, not a pass.
Note: Reason: method — first parameter is `self`, which needs a constructed instance (not synthesizable)
· 1 grounded finding(s) anchored inline below; 2 more finding(s) on lines outside this diff (see the check run).
|
|
||
|
|
||
| @pytest.mark.parametrize("count", (511, 512, 513, 1024, 4097)) | ||
| def test_trade_spool_joins_replace_row_writes(tmp_path, monkeypatch, count): |
There was a problem hiding this comment.
test_trade_spool_joins_replace_row_writes()
fans out to 6 callees (efferent coupling).
Grounded coupling-delta finding (deterministic), not an LLM guess.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Report wrapper: queue the encoded trade rows and cut the per-batch work of the equity proof
No report byte changes. Two pieces of per-row Python work in the report wrapper (
docker/run_json.py) are removed; every output (stdout, sink bytes, receipt, error text and order) is identical to the previous commit.What changes
json.dumpsconfiguration the scalar fast path used and queued, with its separator, in the artifact file. The queue is joined inside the existing bounds (512 records, 256 KiB; no new bound, no new constant) and drained before any write, flush, read, rewind or close of that file, and after the checked reader close of a fused verification. Logical writes per trade column fall from2T-1toceil(T/512); generic streamer dispatches per trade fall to zero. The physical byte stream, the aligned windows and the sync count are unchanged.reprcomparison of every number. The repeat bound still belongs to the run pattern alone.pf_sink.py, the native engine.Failure behaviour
A write can now be attempted later than the row that queued it. The published refusal is the same: a failed physical write clears the queue first, so the same text is never retried; a failure while draining the tail becomes the same typed
report_sink_failed/scratch_iorefusal with the OSError as its cause, remembered and raised at the same point relative to the format, trailer, receipt, fd-identity, trade, summary, metric and equity refusals. Fault rows cover a write, flush, close and short write failing at the first, a middle and the last row or batch, each against every competing refusal.Memory
The queue is one bounded list per artifact file, bounded by the existing 512-record and 256 KiB constants (a single oversized row is written alone). Nothing grows with the number of trades or bars.
Tests
docker/run_json_spool_work_test.py(166 cases) with its reference moduledocker/run_json_spool_reference.py(not collected by the harness glob; verbatim copies of the previous functions). Counters come from the interpreter (sys.setprofileon the real frames and wrapped pattern objects), each with a positive control on the reference and a mutation row that puts the removed work back. Byte identity of complete reports is checked over the existing families plus the finite float shapes and the flush boundary at 1, 511, 512, 513, 1024 and 4097 trades.On the previous tree plus only these two files, 19 cases fail, as designed: 18 of them on the named work counter (
SPOOL_ASCII_WRITES,SPOOL_STREAM_CALLS,EQUITY_BOUND_WORK). The 19th,test_equity_endpoint_dictionaries_belong_only_to_curve_endpoints, is red for the right work (the previous code builds eager endpoint dictionaries, which the counter records as eager rather than as endpoint dictionaries) but fails at a plain assertion on the counter value before the named check runs; the same counter's detection power is shown by the control inside that row and by two mutation rows. A follow-up reorders the assertion.Notes for the record
run_json_bounded_transport_test.py(it patches_BoundedJSONFile.write) no longer exercises the trade spool: the first file it pushes past one window is now the final artifact. Every assertion in it still holds; the trade-spool write failure path is covered by the new file. A follow-up also patcheswrite_asciiin that test.entry_id,exit_idandexit_commentdo not reach the changed encoder: those are trade fields the report drops, and the only string in the trade JSON isside. They test the report path as a whole, not the encoder's escaping; the encoder is covered by the finite-float and byte-identity rows.close()of the artifact file now closes the underlying file even when closing its buffer raises (before, the file close was skipped in that case). Benign; outside the queue itself.docker/run_json.pyare repinned (digits only, 11 anchors, two pages).🤖 Generated with Claude Code