Skip to content

fix(OMN-20159): the projection read node gets its own binding, so a reader never becomes the claim store's login - #3364

Merged
jonahgabriel merged 11 commits into
devfrom
lakshman/OMN-20159-read-binding-overlay
Oct 4, 2026
Merged

jonahgabriel merged 11 commits into
devfrom
lakshman/OMN-20159-read-binding-overlay

Conversation

@Patel230

@Patel230 Patel230 commented Oct 4, 2026 •

Copy link
Copy Markdown
Contributor

Summary

For OMN-20159. One variable, OMNIMARKET_PROJECTION_RUNTIME_BINDING_OVERLAY, chose the database for two things: the projection read node and the delegate-skill claim store. When the dev lane's runtime-effects got a read binding that logs in as role_omnidash, the claim store followed it, and every bus delegation then failed writing claims (UndefinedTable: relation "delegate_skill_command_claims" does not exist). omnibase_infra#4481 took the binding back off. Its test says to change it once the claim store gets its write principal separately from the read binding. This change makes that split. The read node gets its own variable, OMNIMARKET_PROJECTION_READ_BINDING_OVERLAY. The claim store and the evidence store keep following the runtime binding only, so a reader's credentials never become their write principal.

What changed

  • src/omnimarket/projection/runner.py: a new variable OMNIMARKET_PROJECTION_READ_BINDING_OVERLAY and projection_read_binding_from_overlay_env(). It returns the read overlay's binding when the variable is set, and otherwise the runtime binding exactly as before. A blank value counts as unset. A read variable that names a missing or invalid file raises ProjectionReadBindingOverlayError, a RuntimeError that names the variable, the path and the error's class, never the file's contents. It never falls back to the runtime binding.
  • node_projection_read_effect/ports/read_source_resolution.py: the read node resolves its database through the read resolver. A broken read overlay is the refusal projection_binding_invalid. The unconfigured refusal names both variables. A refusal about the read binding's database names the file that binding came from.
  • node_local_dashboard_serve_effect/handlers/handler_local_dashboard_serve.py: the local dashboard picks its store with the read resolver.
  • node_projection_read_effect/handlers/handler_projection_read.py: docstrings only.
  • tests/conftest.py: the autouse fixture also clears the new variable.
  • New contracts/OMN-20159.yaml: this change's evidence item (below).

Deliberately not changed: the claim store, the evidence store and the projection writers. They still resolve the runtime binding only: the stores through projection_runtime_binding_from_overlay_env(), the writers through the runner's internal _projection_runtime_binding_from_overlay_env(). No node contract, topic, migration or schema change. No lane changes behaviour until it sets the new variable. Dev is merged in (2332f6fd7, then the bot's update to 796051348, 0.4.289), because 0.4.287 and 0.4.288 are released; dev touches none of the four source files above.

Rollout note: when a lane moves runtime-effects from the runtime binding to the read binding, its claim store moves back to the container's SQLite file. A delivery in flight at that moment could be claimed in both stores.

How it was verified

The evidence item in contracts/OMN-20159.yaml runs three unit files: the new tests/unit/nodes/node_projection_read_effect/test_read_binding_apart_from_claim_store_omn20159.py (F1 to F5), the existing test_projection_read_effect_omn20159.py (it holds the scan that no module of the node reads the environment), and the new tests/unit/projection/test_projection_binding_env_discipline_omn20159.py (F6).

  • At the merge base 2332f6fd7, with this branch's tests/ laid over it: 27 failed, 26 passed. At the earlier merge base 504d0028b the same 27 failures were 15 AttributeError (the base runner has no projection_read_binding_from_overlay_env), 5 assertion failures and 7 DID NOT RAISE or "raised nothing", with no collection errors.
  • On this branch: 53 passed.

The local-mode file tests/projection/test_api_server_local_mode.py holds F7 (the dashboard reads through the read binding alone) and F5 on the dashboard. At the merge base 504d0028b with this branch's tests/ laid over it, 5 of its 30 tests fail; on this branch all 30 pass.

The failure modes the tests are written against:

  • F1: only the read overlay is set (the dev-lane shape). The read node reads its database. The claim store and the evidence store keep their local SQLite files. A projection writer does not take the read overlay.
  • F2: only the runtime overlay is set. Every resolver behaves as before, including with a blank read variable.
  • F3: both are set, naming different databases, and neither crosses. A broken runtime overlay does not reach the read node.
  • F4: neither is set. The read node still refuses projection_binding_unconfigured, and the claim store still uses its state-root SQLite file.
  • F5: a broken read overlay is a named refusal. It never falls back, and it never quotes the file.
  • F6: only projection/runner.py reads either variable. A positive control plants a reader by each route the scan covers.
  • F7: the local dashboard reads through the read binding alone.

Related suites, never an integration-marked test (tests/unit/nodes/node_projection_read_effect, tests/unit/nodes/node_delegate_skill_orchestrator, tests/projection/test_api_server_local_mode.py, tests/unit/projection): on this branch merged with dev 2332f6fd7, 837 passed, 5 skipped, 0 failed. On an export of 0bbc41afa before the merge, those four plus tests/test_projection_runner.py and tests/test_delegation_env_scanner.py gave 895 passed, 5 skipped, 0 failed. On 03bfea107 (source identical to 0bbc41afa), ruff check passes, ruff format reports every file formatted, and mypy src/omnimarket exits 0. Mutations of the change, made before the final source commit (at 41f2629b6), each turned at least one test red; they were not repeated on 0bbc41afa.

The real-Postgres F1 test (tests/integration/nodes/node_projection_read_effect/test_read_binding_reader_role_real_postgres_omn20159.py) creates a temporary login role and two scratch schemas. Its first two runs against the lakshman lane's PostgreSQL on .201 failed for reasons in the test itself. At 06:56:57Z the role could not log in: permission denied for database "omnibase_infra", User does not have CONNECT privilege, because that server revokes CONNECT from PUBLIC. At 07:01:25Z the last assertion failed, because it expected the local claim file under the test's state root while the suite pins that file once per session. Commit 03bfea107 changes only this integration test: it grants CONNECT to the scratch role and revokes it before the role is dropped, and its last assertion now compares the local claim file with the claim module's own default path. At 07:03:11Z, with those fixes, it gave 1 passed in 26.18 s, and 0 roles and 0 schemas were left behind. CodeQL on this PR then reported that the fixture's conn may be used before it is set: it cannot see that pytest.skip raises. Commit 451a0b49f raises pytest.skip.Exception itself, with the same message the integration skip guard matches, and at 08:12:24Z the test gave 1 passed in 22.06 s, again with nothing left behind.

Lab readback, lakshman lane on .201, 2026-10-04T06:48Z to 06:54Z, real data only (the ticket's probe shape, with runtime-effects carrying only the read variable). runtime-effects ran an image built from 0bbc41afa (omnimarket 0.4.287). A lab-only override gave it only OMNIMARKET_PROJECTION_READ_BINDING_OVERLAY (the dev-lane shape). It was healthy with 0 restarts and 0 import errors at 06:50:18Z, and migration 0053's two columns were present.

  • The edge read of delegation.decisions.v1 matched the projection API for the same tenant. At limit 50 both returned 50 rows with the same correlation ids. At limit 500 both returned 92 rows with the same correlation ids. The tenant had 92 rows.
  • runtime-effects' log named each of the two edge calls once. runtime main's log named neither.
  • One real bus delegation (de3fd64a-1568-4dc5-8d14-8ff551d6a951, status success, a real Qwen3.8-27B writer row) was claimed in the container's SQLite store (1 row). It was not claimed in Postgres (0 rows), and the Postgres claims total stayed at 69 while the lane was switched.
  • Positive control: the claim store's choice of database read back as postgres before the switch, sqlite during it and postgres after the restore.
  • Restore, 06:52:11Z to 06:53:33Z: runtime-effects went back to image 9245e8e873d9 with its original compose files. Its config hash was 18d5df85e3fa…, the same as before the switch. It was healthy with 0 restarts and only the runtime overlay set. Only runtime-effects was recreated in this window.
  • An earlier window from 06:27Z to 06:34Z gave the same claim result for delegation e2206873-910e-45b0-bb84-d227dc9e5335, against 47 Postgres claims. Its readback records that no row was seeded and no database was written by hand.

Caveat: the tenant had 92 rows and the served window is 2000 rows (limit 500 × 4), so this readback cannot show whether the window is right at volume. This branch does not contain the OMN-19971 window fix, and this readback is not evidence for it.

Failure paths

  • If the read variable names a missing, unreadable or invalid file, the read node answers ok: false with projection_binding_invalid. The refusal names the variable and the path, never the file's contents, and the node never falls back to the runtime binding. The local dashboard stops at start-up with ProjectionReadBindingOverlayError.
  • If neither variable is set, the read node answers projection_binding_unconfigured, and the refusal names both variables.
  • If the read binding's database reference does not resolve, or names a database that is neither Postgres nor SQLite, the refusal names the read binding's file and not the runtime binding.
  • No answer: if the read binding's database does not answer, each statement is bounded by the reader's existing timeout and maps to the existing typed refusal projection_database_unavailable; this change does not alter that path.
  • Size: the binding file is a small YAML file loaded when the read source resolves, and a page stays capped at the exposure's contract limit, as before.
  • Incomplete verdict: n/a — this change writes no receipt, verdict or report, and a refused read is a complete typed result (ok: false with a named error), never a partial one.

Open defects

none

Local gates

  • No gate was bypassed — no --no-verify, no SKIP=, no --no-gpg-sign, no core.hooksPath override. Every pre-commit and pre-push hook ran.
  • Any hook that failed was fixed at the input, not worked around.

Overlapping open PRs

Overlap-Reviewed: #3319 — it also edits tests/projection/test_api_server_local_mode.py (OMN-19976), and both start from dev's same version of that file (blob 0f123312f). A three-way merge of the two versions has one conflict, in the module docstring, where each PR adds its own bullet to the same list; keep both bullets. Their source changes are in different modules (sqlite_database.py there; the runner and the read resolvers here). The other 7 open PRs (read 2026-10-04T07:51Z) touch none of these files.

Not in this change

  • The omnibase_infra change that gives the dev lane's runtime-effects the read variable and a read-only binding mount, and changes omnibase_infra#4481's test as its docstring says. That comes after this merges and is released.
  • The ticket's probe on the dev lane, and the AC4 p50 and p95 figures there.
  • AC2's other clause: tests that drive the served window, the since walk and the column checks through the node, and where TableRowSource lives.
  • Any change to how the claim store or the evidence store choose their database, and any grant to role_omnidash or another reader.
  • The OMN-19971 window fix.

Evidence-Ticket: OMN-20159
Evidence-Source: OCC#12807

…from the delegate claim store's

One overlay variable selected both the read node's database and the
delegate-skill claim store's. When a lane gave its runtime-effects a read
binding that logs in as the dashboard reader, the claim store followed it
and every bus delegation failed writing its claim with the reader's
credentials (UndefinedTable on delegate_skill_command_claims).

The read path now has its own variable,
OMNIMARKET_PROJECTION_READ_BINDING_OVERLAY, read only in projection/runner.py
through projection_read_binding_from_overlay_env(): the read overlay's
binding when that variable is set, otherwise the runtime binding exactly as
before. Only the two read resolvers follow it, the projection read node and
the local dashboard. The claim store and the evidence store are unchanged
and keep following the runtime binding, so a reader's credentials can never
become their write principal.

A read variable that is set but names a missing or invalid file raises; it
never falls back to the runtime binding. A blank value is unset. The
unconfigured refusal names both variables, and a refusal about the read
binding's database no longer blames the runtime binding. No contract,
topic, migration or schema changes, and no lane changes behaviour until one
sets the new variable.

Onex-Lane: omn20159-read-binding
Onex-Session: b4a9c00fa6f045f4b54fca18b2cdd0e7
…d-binding-overlay

The branch sat on 0.4.286, which is now published, so the release-identity
gate refuses any further change to packaged source on top of it. dev carries
0.4.287. No file of this branch's change conflicts with dev's.

Onex-Lane: omn20159-read-binding
Onex-Session: b4a9c00fa6f045f4b54fca18b2cdd0e7
…ters are held to the runtime binding

A read overlay that is set but does not load (missing, a directory, not a
mapping, no database, invalid YAML) made the read node's handle() raise the
loader's own exception, because the handler answers only ProjectionReadError.
projection_read_binding_from_overlay_env() now raises
ProjectionReadBindingOverlayError, a RuntimeError naming the variable, the
path and the cause's type only, never the file's contents: a validation error
quotes its input, which can be a database URL with its password. The read node
answers it with the refusal projection_binding_invalid; the local dashboard
surfaces it as it is. It still never falls back to the runtime binding, and
with the read variable unset the read path is the runtime path exactly.

The refusals about the binding's database name the file the binding came from,
in place of "the read overlay's, else the runtime overlay's".

New tests: a projection writer (BaseProjectionRunner) never takes the read
overlay's binding or consumer group; a broken runtime overlay does not reach
reads while a read overlay is set; the environment scan also finds a settings
field named like the variable, a second name the runner binds to its constant
(plain, annotated or chained) and the constant's name as a string. The
real-PostgreSQL test skips with the wording CI's skip guard recognises, and
each of its cleanup statements runs even when an earlier one fails.

Onex-Lane: omn20159-read-binding
Onex-Session: b4a9c00fa6f045f4b54fca18b2cdd0e7
The reader role is granted CONNECT on its database explicitly, and the
grant is revoked before the role is dropped. The lakshman lane's
omnibase_infra revokes CONNECT from PUBLIC (datacl {=T/postgres,...}),
so the role could not log in and the test failed before it reached its
claim assertions (2026-10-04T06:56Z).

The local claim file is compared with the claim module's own default,
not with a path under the test's state root. The suite pins that file
once per session (tests/conftest.py, _session_delegation_claim_store),
so the old assertion could never hold inside the suite (07:01Z).

Against the lakshman lane's Postgres at 07:03Z: 1 passed in 26.18 s,
0 roles and 0 schemas left behind.

Onex-Lane: omn20159-read-binding
Onex-Session: b4a9c00fa6f045f4b54fca18b2cdd0e7
…d-binding-overlay

dev (2332f6f) is at 0.4.288. This branch sat on 0.4.287, which is now
released, and the release-identity check refuses packaged-source changes
on a released version. No file conflicted, and dev touches none of the
four source files this branch changes.

Merged tree: the contract check files 53 passed;
tests/unit/nodes/node_projection_read_effect,
tests/unit/nodes/node_delegate_skill_orchestrator,
tests/projection/test_api_server_local_mode.py and tests/unit/projection
837 passed, 5 skipped.

Onex-Lane: omn20159-read-binding
Onex-Session: b4a9c00fa6f045f4b54fca18b2cdd0e7
…dence

The repo evidence gate (receipt-gate 44aa5aeb) re-runs as a merge-base
control only the dod_evidence a pull request adds or changes, and
omnimarket had no contract for this ticket yet.

contracts/OMN-20159.yaml binds AC2's clause that the node takes its
database handle from the runtime's binding, not from a DSN the handler
reads, to three unit files. At the merge base 2332f6f, with this
branch's tests laid on top, they fail (27 of 53 tests): the read resolver
does not exist there and the read node follows the runtime overlay only.
On this branch all 53 pass.

Onex-Lane: omn20159-read-binding
Onex-Session: b4a9c00fa6f045f4b54fca18b2cdd0e7
@Patel230
Patel230 requested a review from jonahgabriel October 4, 2026 07:56
@github-actions

github-actions Bot commented Oct 4, 2026 •

Copy link
Copy Markdown

⚠️ Architectural Review — WARNINGS

Errors: 0
Warnings: 1

What this checks

Rule Description
ARCH-TOPIC-001 No hardcoded Kafka topic strings in handler code
ARCH-DI-001 No event_bus=None bypass
ARCH-DI-002 No direct Handler instantiation outside workflow_runner/adapters
ARCH-DI-003 No reinvented DI containers
ARCH-TOPIC-002 contract.yaml topics follow `onex.{cmd

ARCH-DI-002: Direct Handler instantiation (warning)\n\n\nsrc/omnimarket/nodes/node_local_dashboard_serve_effect/handlers/handler_local_dashboard_serve.py:227: handler=HandlerProjectionRead(topic_map=topics, row_source=source),\n\n\nHandler classes should be wired only in workflow_runner.py or adapter modules. Direct instantiation elsewhere bypasses the contract system.\n\n

Static architectural lint — no model inference (OMN-14176).

@github-actions

github-actions Bot commented Oct 4, 2026 •

Copy link
Copy Markdown

✅ Hostile Reviewer — PASSED

Blocking findings (critical/error): 0
Total findings: 10
Models succeeded: qwen3-review,gpt-oss-review


Gate semantics

Verdict Meaning Blocks merge?
passed >=2 models succeeded, no critical/error findings No
blocked CRITICAL or ERROR findings found Yes
degraded Fewer than 2 models succeeded (infra unavailable/timeout) Yes (OMN-15110)

Powered by omniintelligence.review_pairing.cli_review — node-based adversarial review via HandlerLlmCliSubprocess (OMN-8524)

await handler.close()


def _raised(call: Any) -> BaseException:
pytest.fail(f"{call.__name__} raised nothing")


def _returned(call: Any) -> Any:
pytest.fail(f"{call.__name__} raised {type(exc).__name__}")


async def _answer_from_the_node() -> Any:
Patel230 and others added 3 commits October 4, 2026 13:43
CodeQL on #3364 reported "Local variable 'conn' may be used before it is
initialized" at the fixture's connect: pytest.skip() raises, but static
analysis cannot see that, so it read conn as possibly unset below. The
except branch now raises pytest.skip.Exception itself, which is what
pytest.skip does, with the same message the integration skip guard
matches.

Against the lakshman lane's Postgres at 08:12Z: 1 passed in 22.06 s,
0 roles and 0 schemas left behind.

Onex-Lane: omn20159-read-binding
Onex-Session: b4a9c00fa6f045f4b54fca18b2cdd0e7
…overlay' into lakshman/OMN-20159-read-binding-overlay

The OCC writer bot merged dev (7960513) into this branch on GitHub at
08:23Z, after the pull request opened. Taking that merge in changes only
pyproject.toml and uv.lock: the post-release bump to 0.4.289, which is
unreleased, so the release-identity gate passes. No file conflicted.

Merged tree: this change's contract check, 53 passed.

Onex-Lane: omn20159-read-binding
Onex-Session: b4a9c00fa6f045f4b54fca18b2cdd0e7
onexbot-occ-writer Bot pushed a commit to OmniNode-ai/onex_change_control that referenced this pull request Oct 4, 2026
…3364

OCC companion by node_pr_lifecycle_fix_effect (OMN-13317 F1 / OMN-13990 / OMN-14285). Product PR head 1b92bb879d1aab72a5dd7fd248b26e645c762876.
onexbot-occ-writer Bot added a commit to OmniNode-ai/onex_change_control that referenced this pull request Oct 4, 2026
…nimarket#3364

The declared checks were executed for real in the OmniNode-ai/omnimarket checkout at the PR head by the product-repo OCC receipt runner, and the results written append-only into this companion. Producer-minted PENDING receipts are superseded by a net-new record; no existing receipt was edited.

Ticket: OMN-16859 (AC3b)
Onex-Workflow: OCC Receipt Runner
Onex-Run: https://github.com/OmniNode-ai/omnimarket/actions/runs/37189043654
onexbot-occ-writer Bot added a commit to OmniNode-ai/onex_change_control that referenced this pull request Oct 4, 2026
…nimarket#3364

The declared checks were executed for real in the OmniNode-ai/omnimarket checkout at the PR head by the product-repo OCC receipt runner, and the results written append-only into this companion. Producer-minted PENDING receipts are superseded by a net-new record; no existing receipt was edited.

Ticket: OMN-16859 (AC3b)
Onex-Workflow: OCC Receipt Runner
Onex-Run: https://github.com/OmniNode-ai/omnimarket/actions/runs/37190086322
…aracter limit

contract-validation on #3364 refused contracts/OMN-20159.yaml: the
dod_evidence id dod-omn20159-ac2-read-binding-apart-from-claim-store is
52 characters and the ticket contract allows 50. It is now
dod-omn20159-ac2-read-binding-apart-from-claims (47). The check, its
binding and its description are unchanged.

onex_change_control's validate-yaml at the pinned 802b5f710, run
locally: the old file fails with string_too_long, the new one is valid.
Onex-Lane: omn20159-read-binding
Onex-Session: b4a9c00fa6f045f4b54fca18b2cdd0e7
jonahgabriel pushed a commit to OmniNode-ai/onex_change_control that referenced this pull request Oct 4, 2026
)

* evidence(OMN-20159): author OCC companion for OmniNode-ai/omnimarket#3364

OCC companion by node_pr_lifecycle_fix_effect (OMN-13317 F1 / OMN-13990 / OMN-14285). Product PR head 1b92bb879d1aab72a5dd7fd248b26e645c762876.

* evidence(OMN-20159): self-bind OCC#12753 + rebind contract_sha256

* evidence(OMN-16859): executed test_passes receipts for OmniNode-ai/omnimarket#3364

The declared checks were executed for real in the OmniNode-ai/omnimarket checkout at the PR head by the product-repo OCC receipt runner, and the results written append-only into this companion. Producer-minted PENDING receipts are superseded by a net-new record; no existing receipt was edited.

Ticket: OMN-16859 (AC3b)
Onex-Workflow: OCC Receipt Runner
Onex-Run: https://github.com/OmniNode-ai/omnimarket/actions/runs/37189043654

* evidence(OMN-16859): executed test_passes receipts for OmniNode-ai/omnimarket#3364

The declared checks were executed for real in the OmniNode-ai/omnimarket checkout at the PR head by the product-repo OCC receipt runner, and the results written append-only into this companion. Producer-minted PENDING receipts are superseded by a net-new record; no existing receipt was edited.

Ticket: OMN-16859 (AC3b)
Onex-Workflow: OCC Receipt Runner
Onex-Run: https://github.com/OmniNode-ai/omnimarket/actions/runs/37190086322

---------

Co-authored-by: omnimarket-bot <bot@omninode.ai>
Co-authored-by: onexbot-occ-writer[bot] <307849072+onexbot-occ-writer[bot]@users.noreply.github.com>
…d-binding-overlay

# Conflicts:
#	tests/projection/test_api_server_local_mode.py
@jonahgabriel
jonahgabriel enabled auto-merge (squash) October 4, 2026 23:20
@onexbot-occ-writer

Copy link
Copy Markdown
Contributor

OCC autobind rebound this PR's evidence-source stamp line to OCC#12807.

The receipt gate's own eligibility validator, run against the change-control tree the gate pins for OCC#12807, returned eligible for head 35a207547b357cc6bf81bf4b64a434be976ac617. The body now carries exactly one stamp line. Displaced: OCC#12753.

Reported by occ_companion_emitter (OMN-18853).

@jonahgabriel
jonahgabriel merged commit 97a7522 into dev Oct 4, 2026
160 of 163 checks passed
@jonahgabriel
jonahgabriel deleted the lakshman/OMN-20159-read-binding-overlay branch October 4, 2026 23:33
@jonahgabriel

Copy link
Copy Markdown
Contributor

Thanks, Lakshman — omnimarket#3364 for OMN-20159 was squash-merged as 97a7522 on 2026-10-04T23:33:10Z. The landing lane merged the base branch into your pull request branch to resolve a conflict in a test file docstring with a just-merged sibling pull request (no rebase, no force-push), and it landed under the operator ruling of 2026-10-04T23:07:50Z, which overrode the report-only landing policy for the collaborator pull requests listed in the standups ask.

@Patel230

Patel230 commented Oct 5, 2026

Copy link
Copy Markdown
Contributor Author

Close-out for OMN-20159: squash-merged as 97a752280 on 2026-10-04T23:33:10Z. Thank you for merging dev in to clear the docstring conflict.

What landed: the projection read node has its own binding variable, so a read binding no longer moves the delegate claim store to Postgres under the reader's login (the dev-lane failure in the 2026-10-02 comment on the ticket).

How it was verified: 150 passed, 0 failed at dbe06cac0, and the lakshman-lane window 06:48–06:53Z (AC4-e).

The four CodeQL notes, answered:

  1. test_read_binding_reader_role_real_postgres_omn20159.py:117, "conn may be used before it is initialized": conn is bound on line 110 or the fixture leaves through raise pytest.skip.Exception(...) on line 116, so no path reaches line 117 unbound. The comment above that raise says so.
    2–4. test_read_binding_apart_from_claim_store_omn20159.py:181, 190, 198, "explicit returns mixed with implicit": each fall-through path ends in pytest.fail(...), which raises, so none returns None.
    No code change needed for any of the four.

What is left: omnibase_infra#4556 (merged since), and the dev lane's own binding, which stays with your lane (#4481's test says when to flip it back).

Thank you!

Patel230 added a commit that referenced this pull request Oct 5, 2026
…-row

The branch sat on #3368's head d7153cf, 21 commits behind dev. Dev
changed port_local_delegation_dispatch.py (#3390, #3382) and the
projection read handler (#3364, #3363), both of which this change
uses; the merge is textually clean, and the metering, dispatch and
projection-read suites were re-run on the merged tree. #3368 is still
unmerged, so its six files stay on this branch unchanged.
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.

3 participants