Repository navigation
Server P10b-v: Live values only the bonds whose inputs changed (D55, D59, D60) - #164
Conversation
…D59, D60) A Live tick compares each pin with the previous tick's snapshot: the frame (configuration, capture, skew policy, valuation date), its reference, its InputSet (quotes, a floating note's fixings, each curve it reads) and its derived quality. Only changed pins are valued and published; the others keep their records exactly as valued. The graph gains rebind_built, a snapshot-bound partial activation that resets only the listed components. Replay and Captured still value every pin at each event.
|
No actionable comments were generated in the recent review.
|
| Layer / File(s) | Summary |
|---|---|
Snapshot input comparison crates/convex-ports/src/snapshot.rs, crates/convex-engine/src/snapshot.rs, crates/convex-engine/src/runtime/worker.rs, crates/convex-ports/tests/snapshot_contracts.rs |
Snapshot methods compare valuation frames and instrument inputs. Worker baseline selection checks input and quality changes and validates baseline result counts and subjects. |
Selective graph rebinding crates/convex-engine/src/calc_graph.rs, crates/convex-engine/src/calc_graph/dag.rs, crates/convex-engine/tests/graph_snapshots.rs |
Graph rebinding resets the connected components of selected nodes for a newer snapshot. Tests cover retained values, invalid rebinds, and stale tickets. |
Live tick selection and result updates crates/convex-engine/src/runtime/actor.rs, crates/convex-engine/src/runtime/worker.rs, crates/convex-engine/tests/runtime.rs, crates/convex-engine/RUNTIME.md, crates/convex-engine/benches/runtime_benchmarks.rs, crates/convex-server/tests/live_ingress.rs |
The actor selects changed instruments, clears the baseline after delivery loss or refresh, and merges selected records. Runtime tests and documentation describe retained results. The benchmark adds a single-quote case for 256 instruments, and the ingress test exercises concurrent batches and capacity refusals. |
Priority:
Estimated code review effort: 3 (Moderate) | ~25 minutes
Change: Feature
Sequence Diagram(s)
sequenceDiagram
participant RuntimeActor
participant RuntimeWorker
participant MarketSnapshot
participant CalculationGraph
participant SnapshotValuator
RuntimeActor->>RuntimeWorker: Compare baseline inputs and qualities
RuntimeWorker->>MarketSnapshot: Compare frame and instrument inputs
MarketSnapshot-->>RuntimeWorker: Return comparison results
RuntimeWorker-->>RuntimeActor: Return selected pins and baseline
RuntimeActor->>RuntimeWorker: Rebind and calculate selected pins
RuntimeWorker->>CalculationGraph: Rebind selected graph nodes
RuntimeWorker->>SnapshotValuator: Value selected instruments
RuntimeWorker-->>RuntimeActor: Return selected valuation records
RuntimeActor->>RuntimeActor: Merge records and save baseline
Possibly related PRs
- sujitn/convex#161: PR
#161pins Live configuration and reference inputs; this change compares those inputs in its baseline. - sujitn/convex#162: PR
#162manages runtime calculation by plan index; this change selects plan indices for calculation and publication. - sujitn/convex#163: PR
#163defines per-instrument valuation inputs and quality; this change compares them to select Live work.
Merge Risk: 
Low · up to 48349
-
The overload test may fail on a healthy runtime, but this does not establish a production defect. The risk is bounded to test reliability.
Pre-merge checks: 
4 · 
1
-
Failed checks: 1 warning Passed checks: 4 passedFull details: Docstring Coverage
-
Explanation
Docstring coverage is 68.42% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentation-only edits and deletions within surviving functions are included; unchanged diff context and fully deleted functions are excluded. Analyzed 19 functions across 11 files.
Resolution
Write docstrings for the functions missing them to satisfy the coverage threshold.
-
Finishing Touches: 💡 1
-
📝 Generate docstrings: 💡
-
- Commit to this branch
- Create a new PR
🧪 Generate unit tests (beta)
-
- Commit to this branch
- Create a new PR
-
- Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.
Comment @coderabbitai help to get the list of available commands.
Medians
|
D55 values only the bonds a tick's quotes touch, so at 256 bonds one client posting batch after batch keeps pace with the drain and the queue never fills; Windows CI saw no 429 in 64 serial batches. Each round now posts 16 batches of 256 at once, four times the 1,024-quote ingress queue, and every refusal must be CAPACITY_EXCEEDED and retryable.
Summary
P10b-v: a Live tick values only the bonds whose inputs changed (D55), in Live only (D59), and a kept record is not re-stamped (D60). This is the next step in the approved P10b order, after #163.
Before this PR, every Live tick valued every pinned instrument (G21–G23). At 256 bonds, a tick carrying one quote still valued 256 bonds and published 256 records.
What counts as a change (
convex-ports).MarketSnapshot::same_frame(previous)compares what every valuation shares: the schema version,max_source_skew_ms, the UTC date ofas_of, the configuration and its capture. A floating note's valuation date and due fixings follow the date.MarketSnapshot::same_inputs(previous, id, curves)compares one instrument's reference and theInputSetfrom D58 (its quotes, a floating note's fixings, the curves it reads). For each read curve it also compares the curve record, its recipe and the calibration that holds it.snapshot::same_valuation_inputspasses the curves the context reads (read_curves, from D58).Graph.
CalculationGraph::rebind_built(built, revalue)binds a later built snapshot to the active graph.Dag::component). A component is reset whole because capture reads only dependencies committed under the bound snapshot.ContextConflict) unless the generation is later and a snapshot is already bound, and when a kept node is dirty or has an attempt in flight. An unknown id givesUnknownNode. A refused call changes nothing.Runtime.
worker::changedbuilds each pin's context and derived quality. With a baseline whose frame matches, it keeps a pin when its quality is equal andsame_valuation_inputsholds. Quality depends on time, so a quote that ages out counts as a change. It checks thatresults[i]is pini's record, elseRecoveryConflict.worker::rebindvalues throughrebind_built;worker::calculatevalues only the selected pins.Actor::valueservesprocessand the pending branch ofrestore_dependencies. Live uses the baseline when it has one and a full activation when it does not. Replay and Captured always value every pin (D59).RUNTIME.mdgains a paragraph on changed-only Live ticks.Deviations from the plan's wording
rebind_builttakes no node list. It keeps the active DAG instead of validating a new one at each tick, so the DAG cannot differ from the active one, and a tick no longer builds and validates 256 node specs.live_throughput/burst1/256in the existing throughput group, not a newlive_tick/256.run_inputsreturnsErr(Source)afterlose_delivery), so no later tick runs in that process. The baseline drop inlose_deliveryis defensive.read_curvestests cover which curves a context reads.live_runtime_applies_an_activation_at_refresh_not_at_the_next_quoteandlive_override_expiry_schedules_a_policy_refresh_without_a_quote_or_periodic_poll. Both publish after the refresh or expiry, which a kept record would not.Behaviour that changes
/api/v1/runtime/resultscan hold records from earlier ticks than the generation and snapshot that health reports. A kept record keeps its revision, generation, snapshot, valuation time, input versions andlive_valid_until.live_judges_each_bond_only_on_its_own_inputsnow expects one record at the aged tick (the stale bond), with the other bond's earlier record unchanged inruntime_results().Not done here
next.results.to_vec()). Only a data-deadline tick on which nothing aged can change nothing.changed.Open questions for the owner (from #163, unchanged)
Tests
snapshot_contracts.rs::an_instrument_reads_the_same_inputs_until_its_own_change: a later snapshot on the same day with another generation keeps the frame and inputs. Another instrument's quote and an unread curve are not changes. The instrument's own quote, a read curve and its reference are. The next day, the skew policy and the configuration change the frame.graph_snapshots.rs::rebinding_a_snapshot_keeps_settled_nodes_outside_the_listed_components: a dirty or in-flight kept node is refused. After a rebind, the listed curve and its bond reset, and a pre-rebind ticket is discarded. The other curve keeps the same cached value at generation 7, stays fresh and is not recalculated. An equal generation, an unknown node and an unbound graph are refused.runtime.rs::live_values_only_the_bonds_whose_inputs_changed(two-bond Live plan): three quotes on one bond each publish that bond alone. The other keeps its record, and health reports the newest generation, revision and snapshot, staying ready.runtime.rs::live_judges_each_bond_only_on_its_own_inputsupdated as above.live_throughput/burst1/256.live_ingress.rs::an_offered_rate_above_the_drain_rate_is_refused_with_429_and_nothing_is_lost(48349c3, after the first CI run). Windows CI saw no 429 in 64 serial batches. A tick now values only the bonds its quotes touch, so one client posting batch after batch keeps pace with the drain at 256 bonds. Main had passed by a thin margin: the whole file ran in 1.2–2.4 s on Windows.CAPACITY_EXCEEDEDand retryable.OutOfOrderwithout blocking the key.Numbers
Medians are in this comment.
Verification
In WSL on 07c93d2:
cargo fmt --checkpasses.tools/assurance/check.pypasses with and without--base 50c3ec3e.-D warningspasses onconvex-ports,convex-engine,convex-serverandconvex-ext-redb(all targets).--locked:convex-ports: the full suite ran with only the new contract test failing, on a fixture bug. After the fix,snapshot_contractspassed 9; the full ports suite was not rerun.convex-engine: 205 passed, 0 failed, 1 ignored. Theruntimefile passed 3 of 3 runs (23 tests each).convex-server: 267 passed, 0 failed, 0 ignored.convex-serverpass, andlive_ingresspassed 5 of 5 runs with--test-threads=1, as Windows CI runs it.Summary by CodeRabbit