Skip to content

fix: admit Maker orchestrator strategy archive batches - #109

Merged
outerlook merged 4 commits into
developfrom
fix/archive-forwarder-maker-orchestrator-source
Aug 4, 2026
Merged

fix: admit Maker orchestrator strategy archive batches#109
outerlook merged 4 commits into
developfrom
fix/archive-forwarder-maker-orchestrator-source

Conversation

@outerlook

@outerlook outerlook commented Aug 4, 2026

Copy link
Copy Markdown
Member

Problem

The archive forwarder admits exactly one strategy producer. strategy-contract.ts defined
STRATEGY_ARCHIVE_SOURCE = "hb_runtime", so any strategy-table batch whose envelope source
is maker_orchestrator classified as invalid_strategy_source and was refused with HTTP 400
before spooling or storage.

The Maker orchestrator is a real, distinct producer: it stamps maker_orchestrator as the
envelope source, row source, controller type, and producer id. Since the archive-forwarder
rollout on 2026-08-03, its strategy rows have been rejected outright — production Maker
archive rows stopped at the rollout boundary, with roughly 3,142 archive POST failures
observed over ~23 hours.

Runtime decisions are fire-and-forget, so trading behavior is unaffected; what breaks is
replay completeness and operational evidence — retained state and deltas, settlement checks
and status, shared-funding lineage, transfer lifecycle, and Maker market-health snapshots.

Change

Widen the strategy producer admission set to exactly {hb_runtime, maker_orchestrator}.

STRATEGY_ARCHIVE_SOURCE is replaced by a single canonical STRATEGY_ARCHIVE_SOURCES set;
no consumer hard-codes a producer string. request.ts needed no change, because the
classification value it branches on is unchanged — both producers therefore reach the same
durable strategy-spool path and the same 202 ownership contract.

The producer identity is deliberately preserved rather than normalized. Relabeling Maker rows
as hb_runtime would have made replay provenance false, which is worse than the rejection it
would have papered over.

Everything else in the gate remains fail-closed and untouched:

  • unknown sources carrying strategy rows are still rejected;
  • an admitted source mixing strategy and non-strategy tables is still rejected;
  • row/envelope source equality still holds per producer, so an hb_runtime envelope cannot
    carry a maker_orchestrator row, or vice versa;
  • deployment-id equality, envelope identity, row-count bounds, and the v2 schema_version
    rules are unchanged;
  • non-strategy broker_read / broker_write traffic still takes the direct synchronous
    insert path;
  • the five approved strategy_data.* tables are unchanged.

openspec/specs/strategy-runtime-archive-ingestion/spec.md is updated to describe the
two-producer admission set, since it previously mandated hb_runtime-only and would otherwise
contradict the code.

Tests

New maker_orchestrator fixture built from the Maker orchestrator's actual serialized wire
shape (stream_name, event_kind, and schema_version verified against the producer's
own wire-contract test) rather than a synthesized guess. The existing shared
archive_forwarder_envelope.json is deliberately left untouched — it is byte-pinned here and
mirrored by a parity test on the Maker side.

Added coverage:

  • a request/spool test proving a maker_orchestrator envelope reaches durable admission
    (202, no ClickHouse insert, one queued batch);
  • classification of both admitted producers;
  • rejection of unknown_runtime, broker_read, and broker_write carrying strategy rows;
  • rejection of cross-producer row/envelope provenance in both directions.

The defect-focused test was demonstrated failing on the unfixed parent (expected 202, received 400) before the fix was accepted.

Verification:

  • bun test test/archive-forwarder-strategy-contract.test.ts test/archive-forwarder-strategy-request.test.ts — 24 pass, 0 fail
  • full suite — 601 pass, 0 fail
  • biome check over test/ and services/archive-forwarder/ — clean
  • tsc --noEmit — clean

Notes for review

Summary by CodeRabbit

  • New Features
    • Strategy archive submissions are now accepted from both hb_runtime and maker_orchestrator.
    • Accepted submissions receive HTTP 202 after durable queuing, without waiting for synchronous database insertion.
    • Provenance validation now rejects mismatches between envelope producers and row sources.
    • Other archive requests retain their existing synchronous processing behavior.

@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

The archive-forwarder now accepts strategy envelopes from hb_runtime and maker_orchestrator. Both use durable strategy-spool admission and return HTTP 202. Provenance validation covers both producers, while other requests retain direct ClickHouse insertion.

Changes

Strategy archive ingestion

Layer / File(s) Summary
Producer contract and routing
openspec/specs/strategy-runtime-archive-ingestion/spec.md, services/archive-forwarder/strategy-contract.ts
The strategy contract admits hb_runtime and maker_orchestrator. Matching batches use the durable spool, while other sources retain direct ClickHouse handling.
Provenance validation coverage
test/archive-forwarder-strategy-contract.test.ts, test/fixtures/maker_orchestrator_archive_envelope.json
Tests validate both producers, reject unknown sources and mismatched provenance, and verify deployment consistency with the new fixture.
Durable maker-orchestrator admission
test/archive-forwarder-strategy-request.test.ts
Tests verify HTTP 202, queued work, and no synchronous ClickHouse insertion for maker-orchestrator requests.

Estimated code review effort: 2 (Simple) | ~10 minutes

Sequence Diagram(s)

sequenceDiagram
  participant MakerOrchestrator as Maker orchestrator
  participant ArchiveForwarder
  participant StrategyContract
  participant DurableStrategySpool
  MakerOrchestrator->>ArchiveForwarder: Submit archive envelope
  ArchiveForwarder->>StrategyContract: Classify source and rows
  StrategyContract-->>ArchiveForwarder: Accept strategy batch
  ArchiveForwarder->>DurableStrategySpool: Queue strategy batch
  ArchiveForwarder-->>MakerOrchestrator: Return HTTP 202
Loading

Possibly related PRs

Suggested reviewers: csmithington

Poem

A rabbit checks the source-set gate,
Two producers now may queue and wait.
Provenance stays aligned,
Unknown rows are declined.
The spool accepts; 202 seals their fate.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: admitting Maker orchestrator strategy archive batches.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/archive-forwarder-maker-orchestrator-source

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
services/archive-forwarder/strategy-contract.ts (1)

64-71: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Authorization Bypass (CWE-639): Authorization Bypass Through User-Controlled Key (IDOR)

Reachability: External · Exploitability: Moderate

Reachability path
● Entry
  test/archive-forwarder-strategy-contract.test.ts
│
▼
● Sink
  services/archive-forwarder/strategy-contract.ts

Bind maker_orchestrator to producer authentication.

The forwarder checks only one optional bearer token, while source remains caller-controlled. If the token is shared—or unset—an authenticated or unauthenticated caller can submit valid maker_orchestrator rows to dependencies.spool.admit. Require producer-specific credentials or inject the source from a trusted boundary before admission.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@services/archive-forwarder/strategy-contract.ts` around lines 64 - 71, Update
the forwarder admission flow around source validation and
dependencies.spool.admit so maker_orchestrator rows cannot be authorized solely
by the caller-controlled source and shared optional bearer token. Require
producer-specific credentials for this source, or overwrite it from a trusted
producer boundary before validation and admission; reject requests lacking that
trusted binding.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@services/archive-forwarder/strategy-contract.ts`:
- Around line 64-71: Update the forwarder admission flow around source
validation and dependencies.spool.admit so maker_orchestrator rows cannot be
authorized solely by the caller-controlled source and shared optional bearer
token. Require producer-specific credentials for this source, or overwrite it
from a trusted producer boundary before validation and admission; reject
requests lacking that trusted binding.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: bbe27e22-f0da-45ea-9dc1-bce019d8e53a

📥 Commits

Reviewing files that changed from the base of the PR and between db5517d and 6f2907f.

📒 Files selected for processing (5)
  • openspec/specs/strategy-runtime-archive-ingestion/spec.md
  • services/archive-forwarder/strategy-contract.ts
  • test/archive-forwarder-strategy-contract.test.ts
  • test/archive-forwarder-strategy-request.test.ts
  • test/fixtures/maker_orchestrator_archive_envelope.json
📜 Review details
🔇 Additional comments (7)
openspec/specs/strategy-runtime-archive-ingestion/spec.md (1)

8-28: LGTM!

Also applies to: 66-70, 104-108

test/archive-forwarder-strategy-contract.test.ts (3)

5-9: LGTM!


72-94: LGTM!

Also applies to: 145-145, 155-156


59-70: 🗄️ Data Integrity & Integration

Resolve the canonical Maker fixture pin. The test already checks exact bytes for archive_forwarder_envelope.json. maker_orchestrator_archive_envelope.json is a separate fixture and must not equal it. The local SHA-256 pin conflicts with the canonical hash recorded in the repository documentation. Align the test and documentation after resolving the canonical source.

test/fixtures/maker_orchestrator_archive_envelope.json (1)

1-35: LGTM!

test/archive-forwarder-strategy-request.test.ts (1)

9-9: LGTM!

Also applies to: 45-67

services/archive-forwarder/strategy-contract.ts (1)

3-6: 🎯 Functional Correctness

No compatibility alias is required. No repository consumer references STRATEGY_ARCHIVE_SOURCE; current consumers use STRATEGY_ARCHIVE_SOURCES.

			> Likely an incorrect or invalid review comment.

@outerlook
outerlook merged commit 5b422f6 into develop Aug 4, 2026
5 of 6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant