Skip to content

docs(adr): split read and write runtimes out of core#29

Merged
dfa1 merged 2 commits into
mainfrom
worktree-happy-wandering-shamir
Jun 11, 2026
Merged

docs(adr): split read and write runtimes out of core#29
dfa1 merged 2 commits into
mainfrom
worktree-happy-wandering-shamir

Conversation

@dfa1

@dfa1 dfa1 commented Jun 11, 2026

Copy link
Copy Markdown
Owner

Summary

Proposes splitting Encoding into separate read/write interfaces and moving the corresponding runtime into reader / writer, leaving core as the model-only module it was originally intended to be.

PR #27's 33 unwrapForSubParser audit-trail sites are a strong signal that core is hosting the read runtime, not just the data model. Cross-module byte hand-offs force public escape-hatch APIs (VortexHandle.slice, Registry.decodeAsSegment) that no architectural wrapper can really cure.

Why this ADR

  • VortexHandle.slice returning a raw MemorySegment is a symptom; the disease is the module layout.
  • The 33 unwrapForSubParser sites collapse as a side effect of co-locating the decoder runtime with the byte source.
  • Today a read-only deployment pulls in the entire write surface (Zstd encoders, FSST builders, ALP encoders). The split unlocks a true read-only artifact.

What the ADR contains

  • Root-cause analysis of the current core layout (5 concrete smells).
  • Target module split (core → model only; reader → read runtime + decoders; writer → write runtime + encoders).
  • Six-phase migration plan with effort estimates (~9 person-days plus CI fallout).
  • Consequences (positive and negative) and risks-to-manage.
  • Rejected alternatives (JPMS hide, move FlatSegmentDecoder alone, adopt Arrow codec SPI, status-quo + docs).

Status

This PR adds only the ADR. No code changes. The ADR is marked Status: Proposed.

Test plan

  • Reviewer: confirm the smell described matches reviewer's reading of the code.
  • Reviewer: argue with the phase split — should Phase 5 (Extension) come earlier? Should Phase 2 (per-encoding-family lift) be done in one shot or per-family?
  • Reviewer: estimate honesty — is ~9 person-days realistic?
  • Decide whether to merge as Proposed, escalate to Accepted, or close as Rejected.

🤖 Generated with Claude Code

dfa1 and others added 2 commits June 11, 2026 09:01
The 33 `unwrapForSubParser` audit-trail sites in PR #27 are a strong
signal that the current module layout is wrong: `core` hosts the read
runtime, not just the data model. `reader` is a thin orchestration
shell around `core`; cross-module byte hand-offs force public
escape-hatch APIs (`VortexHandle.slice`, `Registry.decodeAsSegment`)
that no architectural wrapper can really cure.

Proposes splitting `Encoding` into separate read and write interfaces
and moving the corresponding runtime into `reader` / `writer`, leaving
`core` as the model-only module it was originally intended to be.
PR #27's escape hatches collapse as a side effect of co-locating the
decoder runtime with the byte source.

Includes:
- Root-cause analysis of the current `core` layout (5 concrete smells)
- Target module split with the `Array` hierarchy moving to `reader`
  (writer only touches `NullableData`, confirmed by audit) — only
  `NullableData` and `BoundedSegment` stay in `core` proper
- Registry split into distinct `ReadRegistry` and `WriteRegistry` types
  passed alongside the entry points (not folded into options records)
  — read-only callers never pull the `writer` module onto their
  classpath
- 6-phase migration plan with effort estimates (~9 person-days plus
  CI fallout)
- Consequences (positive and negative) and risks-to-manage
- Rejected alternatives (JPMS hide, move FlatSegmentDecoder alone,
  adopt Arrow codec SPI, status-quo + docs)

Status: Proposed. No code changes.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Records the trade-offs for unsealing DType + Layout (and adding a
compute SPI) as a separate decision from ADR 0001's module split.

Status: Deferred — awaiting a real downstream consumer use case, per
the existing TODO.md:215 guidance ("don't pre-open these without a
use case"). The ADR captures:

- Why sealed-by-default is correct today (exhaustive switches, free
  equality, no premature abstraction, CLAUDE.md tone alignment)
- When that default flips (downstream consumer with custom logical
  type, Rust ships variants Java cannot follow with sealed additions)
- Three shapes for a future un-deferral (open SPI mirroring Rust;
  Extension-plugin elevation; defer to JDK pattern-matching evolution)
- Four decision criteria for un-deferring: named consumer, spec for
  the variant, confirmation Extension does not fit, plan for the
  switch-exhaustiveness implications
- Compute layer deferred entirely — no Java query / pruning layer yet
  to plug compute into

Cross-links to ADR 0001 (module split) and compatibility.md (which
already records DType::Union as one variant Java does not yet decode).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@dfa1 dfa1 force-pushed the worktree-happy-wandering-shamir branch from 07f72b5 to 374ad04 Compare June 11, 2026 07:01
@dfa1 dfa1 merged commit 4146772 into main Jun 11, 2026
3 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