feat(ethflow-watcher): observe + verify orderbook indexing (BLEU-833 redesign, COW-1076)#62
Closed
brunota20 wants to merge 1 commit into
Closed
Conversation
…redesign, COW-1076)
The original BLEU-833 design lifted the on-chain GPv2OrderData into an
OrderCreation body and POSTed it to /api/v1/orders with the EthFlow
contract as the EIP-1271 owner. Empirical evidence collected during a
2026-06-22 Sepolia soak shows that path cannot succeed:
- The 3 OrderPlacement events the watcher observed during the run
(creationDate 18:43, 18:53, 21:19 UTC, UIDs ending in
ba3cb449...EAdec|ffffffff) are *fulfilled* on the orderbook with
validTo = u32::MAX — the same shape the orderbook rejects when
shepherd POSTs it.
- The orderbook entries carry onchainUser, onchainOrderData and
ethflowData.userValidTo (a real unix timestamp), and these fields
do not exist on the OrderCreation request body in
cowprotocol-orderbook. They are populated by the orderbook backend
itself, which indexes the OrderPlacement event server-side and
creates the order with dual-validTo bookkeeping.
So /api/v1/orders is structurally the wrong endpoint for on-chain
EthFlow placements: the orderbook's native indexer is the one that
creates the order entry, and the public POST endpoint applies the
generic validTo cap and rejects with ExcessiveValidTo every time.
Continuing to submit produces only garbage outcomes per real EthFlow
trade (misleading dropped/backoff markers and a misleading
shepherd_cow_api_submit_total{outcome="err"} increment).
This commit replaces the submit path with the contract the orderbook
actually offers: shepherd decodes the OrderPlacement event, computes
the canonical UID, GETs /api/v1/orders/{uid}, and records the outcome:
- 200 → write observed:{uid}, log Info ("orderbook indexed").
- 404 → log Info ("not yet indexed; will recheck on re-delivery")
and do not write the marker, so a future log re-delivery or a
block-tick poll (out of scope here) can re-verify.
- other err → log Warn with the host's code and message.
Idempotency stays event-driven: once observed:{uid} is written, log
re-delivery is a no-op. Block-tick-driven retries for stuck indexer
lag are intentionally out of scope and tracked separately.
Test surface: the existing BLEU-832 decode tests are preserved verbatim
and the GPv2OrderData fixture is reused with the canonical EthFlow
markers (OrderKind::SELL, SellTokenSource::ERC20, BuyTokenDestination::ERC20).
Two new tests cover UID computation invariants: the owner suffix pins
to the EthFlow contract and the validTo suffix pins to the on-chain
order's validTo. A third asserts compute_uid returns None on unsupported
chains so callers fall back to a Warn log rather than panic.
This invalidates the design that PRs #10 (BLEU-833), #47 (COW-1074),
#48 (COW-1075) and #49 (COW-1076) were all patching. After review,
those PRs should be closed or substantially rewritten — none of the
appData resolution / error-envelope forwarding / log-downgrade work is
needed once the broken endpoint is no longer called.
AI assistance disclosure: drafted by Claude (Opus 4.7, 1M context)
following the soak inspection that surfaced the divergence.
brunota20
force-pushed
the
bruno/cow-1076-ethflow-observe-design
branch
from
June 23, 2026 00:48
d2dc701 to
0d5ff1a
Compare
Author
Live validation note (2026-06-23 14:00 UTC)Combined with the rest of the redesign + fix bundle on Companion PRs (same redesign / soak deploy bundle)
Each is single-concern; the deploy branch is the cumulative integration point and will fold into |
This was referenced Jun 23, 2026
Author
|
Superseded by deploy branch commit |
This was referenced Jun 24, 2026
brunota20
added a commit
that referenced
this pull request
Jun 25, 2026
Cherry-pick of PR #62 + PR #63's redesign onto the M5 host runtime (env-var substitution in engine.toml, healthcheck fixes, etc) for the Sepolia soak VM. The PR review continues on the proper layered branches: - PR #62 — M2/BLEU-833 layer observe design - PR #63 — M3/M4 BLEU-855 split + COW-1074 cow_api_request integration This branch is deploy-only: it lets the soak run on the redesigned ethflow-watcher with the latest host runtime while review iterates on the layered PRs. After merge, this branch can be deleted; CI will republish ghcr.io/bleu/nullis-shepherd:latest with the merged design and the VM rolls forward to the official image. See COW-1076 for the full empirical evidence.
brunota20
added a commit
that referenced
this pull request
Jun 25, 2026
Cherry-pick of PR #62 + PR #63's redesign onto the M5 host runtime (env-var substitution in engine.toml, healthcheck fixes, etc) for the Sepolia soak VM. The PR review continues on the proper layered branches: - PR #62 — M2/BLEU-833 layer observe design - PR #63 — M3/M4 BLEU-855 split + COW-1074 cow_api_request integration This branch is deploy-only: it lets the soak run on the redesigned ethflow-watcher with the latest host runtime while review iterates on the layered PRs. After merge, this branch can be deleted; CI will republish ghcr.io/bleu/nullis-shepherd:latest with the merged design and the VM rolls forward to the official image. See COW-1076 for the full empirical evidence.
brunota20
added a commit
that referenced
this pull request
Jun 25, 2026
Cherry-pick of PR #62 + PR #63's redesign onto the M5 host runtime (env-var substitution in engine.toml, healthcheck fixes, etc) for the Sepolia soak VM. The PR review continues on the proper layered branches: - PR #62 — M2/BLEU-833 layer observe design - PR #63 — M3/M4 BLEU-855 split + COW-1074 cow_api_request integration This branch is deploy-only: it lets the soak run on the redesigned ethflow-watcher with the latest host runtime while review iterates on the layered PRs. After merge, this branch can be deleted; CI will republish ghcr.io/bleu/nullis-shepherd:latest with the merged design and the VM rolls forward to the official image. See COW-1076 for the full empirical evidence.
brunota20
added a commit
that referenced
this pull request
Jun 25, 2026
Cherry-pick of PR #62 + PR #63's redesign onto the M5 host runtime (env-var substitution in engine.toml, healthcheck fixes, etc) for the Sepolia soak VM. The PR review continues on the proper layered branches: - PR #62 — M2/BLEU-833 layer observe design - PR #63 — M3/M4 BLEU-855 split + COW-1074 cow_api_request integration This branch is deploy-only: it lets the soak run on the redesigned ethflow-watcher with the latest host runtime while review iterates on the layered PRs. After merge, this branch can be deleted; CI will republish ghcr.io/bleu/nullis-shepherd:latest with the merged design and the VM rolls forward to the official image. See COW-1076 for the full empirical evidence.
brunota20
added a commit
that referenced
this pull request
Jun 26, 2026
Cherry-pick of PR #62 + PR #63's redesign onto the M5 host runtime (env-var substitution in engine.toml, healthcheck fixes, etc) for the Sepolia soak VM. The PR review continues on the proper layered branches: - PR #62 — M2/BLEU-833 layer observe design - PR #63 — M3/M4 BLEU-855 split + COW-1074 cow_api_request integration This branch is deploy-only: it lets the soak run on the redesigned ethflow-watcher with the latest host runtime while review iterates on the layered PRs. After merge, this branch can be deleted; CI will republish ghcr.io/bleu/nullis-shepherd:latest with the merged design and the VM rolls forward to the official image. See COW-1076 for the full empirical evidence.
jean-neiverth
pushed a commit
that referenced
this pull request
Jun 29, 2026
Cherry-pick of PR #62 + PR #63's redesign onto the M5 host runtime (env-var substitution in engine.toml, healthcheck fixes, etc) for the Sepolia soak VM. The PR review continues on the proper layered branches: - PR #62 — M2/BLEU-833 layer observe design - PR #63 — M3/M4 BLEU-855 split + COW-1074 cow_api_request integration This branch is deploy-only: it lets the soak run on the redesigned ethflow-watcher with the latest host runtime while review iterates on the layered PRs. After merge, this branch can be deleted; CI will republish ghcr.io/bleu/nullis-shepherd:latest with the merged design and the VM rolls forward to the official image. See COW-1076 for the full empirical evidence.
jean-neiverth
pushed a commit
that referenced
this pull request
Jun 30, 2026
Cherry-pick of PR #62 + PR #63's redesign onto the M5 host runtime (env-var substitution in engine.toml, healthcheck fixes, etc) for the Sepolia soak VM. The PR review continues on the proper layered branches: - PR #62 — M2/BLEU-833 layer observe design - PR #63 — M3/M4 BLEU-855 split + COW-1074 cow_api_request integration This branch is deploy-only: it lets the soak run on the redesigned ethflow-watcher with the latest host runtime while review iterates on the layered PRs. After merge, this branch can be deleted; CI will republish ghcr.io/bleu/nullis-shepherd:latest with the merged design and the VM rolls forward to the official image. See COW-1076 for the full empirical evidence.
jean-neiverth
pushed a commit
that referenced
this pull request
Jun 30, 2026
Cherry-pick of PR #62 + PR #63's redesign onto the M5 host runtime (env-var substitution in engine.toml, healthcheck fixes, etc) for the Sepolia soak VM. The PR review continues on the proper layered branches: - PR #62 — M2/BLEU-833 layer observe design - PR #63 — M3/M4 BLEU-855 split + COW-1074 cow_api_request integration This branch is deploy-only: it lets the soak run on the redesigned ethflow-watcher with the latest host runtime while review iterates on the layered PRs. After merge, this branch can be deleted; CI will republish ghcr.io/bleu/nullis-shepherd:latest with the merged design and the VM rolls forward to the official image. See COW-1076 for the full empirical evidence.
jean-neiverth
pushed a commit
that referenced
this pull request
Jun 30, 2026
Cherry-pick of PR #62 + PR #63's redesign onto the M5 host runtime (env-var substitution in engine.toml, healthcheck fixes, etc) for the Sepolia soak VM. The PR review continues on the proper layered branches: - PR #62 — M2/BLEU-833 layer observe design - PR #63 — M3/M4 BLEU-855 split + COW-1074 cow_api_request integration This branch is deploy-only: it lets the soak run on the redesigned ethflow-watcher with the latest host runtime while review iterates on the layered PRs. After merge, this branch can be deleted; CI will republish ghcr.io/bleu/nullis-shepherd:latest with the merged design and the VM rolls forward to the official image. See COW-1076 for the full empirical evidence.
jean-neiverth
added a commit
that referenced
this pull request
Jul 6, 2026
One-pass sweep replacing stale nexum.toml references with module.toml across docs, WIT comments, CLI help text, and the example engine config. Removes the duplicate modules/example/nexum.toml (module.toml already exists). Historical references in the migration guide and ADR-0001 are preserved; the supervisor's legacy fallback path is unchanged. Closes nullislabs#108 Closes #62
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why this PR exists
Sibling to PR #10. Same base (BLEU-832 decode), different design choice at the BLEU-833 step. Proposes that the M2 review choose observe + verify instead of the original submit + retry approach, on empirical evidence that the submit approach cannot succeed against the real orderbook.
Evidence collected from a 2026-06-22 Sepolia soak
The watcher observed 3
OrderPlacementevents during the soak (18:43, 18:53, 21:19 UTC). Each was logged asethflow dropped … ExcessiveValidTounder the BLEU-833 + COW-1074/1075/1076 patches. Hitting the orderbook for the same UIDs:0x86de7326…0x873f2083…0x2dc21c6a…All carry
validTo: 4294967295(u32::MAX) — the shape we believed the Sepolia orderbook rejects. It doesn't. The orderbook accepts that shape, but only through its native indexer, not throughPOST /api/v1/orders.The fulfilled order entries include fields that do not exist on the
OrderCreationrequest body incowprotocol-orderbook:ethflowData.userValidTois a real Unix timestamp — extracted from theEthFlowOrder.datapayload embedded in the on-chainOrderPlacementevent. Only the orderbook backend's own indexer writes those fields. The publicPOST /api/v1/ordersendpoint shepherd targets applies the generic validity cap and rejects withExcessiveValidToregardless of chain, signing scheme, orfromaddress.What changes
Replace
submit_placementwithobserve_placement:observed:{uid}writtencode+messageobserved:{uid}makes log re-delivery a no-op once verified. 404 is treated as expected indexer lag — shepherd's WebSocket can deliver the log a few hundred milliseconds before the orderbook's own indexer commits — and intentionally does not write the marker, so a future log re-delivery (or a block-tick poll, out of scope here) can re-verify.Capability surface trimmed: this revision uses
local-store,logging, and thecow-api::requesthost import. It no longer usescow-api::submit-order. That call site can be retired entirely once the rest of the stack is updated.Tests (10 total, all pass natively + wasm32-wasip2)
compute_uid_pins_owner_to_ethflow_contract_and_validto— asserts the 56-byte UID layoutdigest || owner || valid_to, owner = EthFlow contract, valid_to = on-chain validTo.compute_uid_returns_none_on_unsupported_chain.gpv2_to_order_data_rejects_unknown_kind_marker— defensive against unrecognised enum markers.cargo clippy -p ethflow-watcher --all-targetsclean.cargo fmt --checkclean.cargo build -p ethflow-watcher --target wasm32-wasip2 --releaseclean.Stack impact
This invalidates the design that PRs #10 (BLEU-833 submit), #47 (COW-1074 appData resolve), #48 (COW-1075 error envelope forwarding for cow-api errors), and #49 (COW-1076 ExcessiveValidTo log downgrade) were patching. Once this lands as the M2 EthFlow design:
resolve_app_datahelper is still useful fortwap-monitorwhich legitimately submits orders. ethflow-watcher no longer needs it (UID computation does not need the appData JSON, only the hash).forward orderbook ApiErrorcow-api change is still useful for twap-monitor.Out of scope (follow-up)
[[subscription]] kind = "block"to the manifest and apending:{uid}marker swept on each block, so persistent indexer downtime surfaces as a Warn after N blocks. Tracked as a new follow-up.submit_ordercontract. Out of scope here, will land in the M2 epic doc bundle.AI assistance disclosure: drafted by Claude (Opus 4.7, 1M context) following a 2026-06-22 soak inspection.