Skip to content

refactor(codec): simplification round for the 0.10 series#314

Merged
bbopen merged 2 commits into
mainfrom
chore/0.10-simplify
Jul 13, 2026
Merged

refactor(codec): simplification round for the 0.10 series#314
bbopen merged 2 commits into
mainfrom
chore/0.10-simplify

Conversation

@bbopen

@bbopen bbopen commented Jul 13, 2026

Copy link
Copy Markdown
Owner

Summary

Behavior-preserving cleanup pass over the merged 0.10 codec series, from a ranked whole-sequence review (8 items, all applied):

  • Typed ScientificDecodeError (kind/marker/cause) replaces error-message regex and prefix sniffing in bridge-codec.ts; outward messages and valueType values unchanged.
  • docs/codec-envelopes.md now documents nested composition, traversal bounds, the ndarray JSON dtype field, pandas preflight, null normalization, and six-marker return validation.
  • Six-marker set centralized behind isScientificMarker (was three copies).
  • Duplicated ndarray/tensor decode finishing (extraction, count check, reshape, tagging) extracted; sync/promise timing preserved.
  • Strict-v1-vs-legacy shape/dtype policy extracted to shared readers.
  • Python JSON primitives consolidated (one JS-safe-integer constant, shared key coercion, stdlib delegation); Pyodide bootstrap regenerated.
  • Two wholly duplicate test assertions removed; stale comments and names refreshed.

The review deliberately skipped five churn-heavy ideas (error-formatter DSL, path-helper unification, cross-language dedup, and others) — documented in the review record.

Verification

  • Menagerie 101/101; npm run check:all 1,385 passed (same counts as main); GC/perf run 1,392 passed
  • Prose gate on the doc: zero pattern hits

@github-actions github-actions Bot added area:docs Area: documentation area:runtime labels Jul 13, 2026
@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The change refactors scientific envelope decoding around typed markers and structured errors, centralizes shape/dtype validation, updates bridge integration and runtime typings, aligns JSON serialization helpers, and expands documentation and negative test coverage.

Changes

Scientific envelope codec

Layer / File(s) Summary
Marker and decode error foundation
src/utils/codec.ts
Adds typed scientific markers, structured decode errors, and marker-aware Arrow decoder contracts.
Envelope decode handlers
src/utils/codec.ts
Centralizes shape/dtype validation and refactors ndarray, sparse, dataframe, series, and tensor decoding flows.
Decode dispatch and bridge integration
src/utils/codec.ts, src/runtime/bridge-codec.ts
Applies typed marker dispatch and structured error translation across decoding entrypoints and response handling.
JSON boundary serialization consistency
runtime/tywrap_bridge_core.py, src/runtime/pyodide-bootstrap-core.generated.ts
Shares JavaScript-safe integer, JSON object-key, and standard-library serialization behavior.
Runtime contracts and envelope validation coverage
src/runtime/validators.ts, docs/codec-envelopes.md, test/*
Updates marker-based typings, documents envelope behavior, and adds sparse and tensor rejection cases.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant bridgeCodec
  participant decodeValueAsync
  participant ArrowDecoder
  bridgeCodec->>decodeValueAsync: decodeScientificValue(result)
  decodeValueAsync->>ArrowDecoder: decodeArrow(bytes, marker)
  ArrowDecoder-->>decodeValueAsync: decoded scientific payload
  decodeValueAsync-->>bridgeCodec: decoded value or ScientificDecodeError
Loading

Possibly related PRs

Suggested labels: area:codec, area:types

Poem

A rabbit hops through envelopes bright,
Markers guide the decode just right.
Shapes and dtypes line up in a row,
Safe JSON bounds keep numbers low.
Errors wear names, the bridge runs true—
“A tidy codec!” says Bunny, “That’ll do!” 🐇

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title is related to the codec cleanup, but it is too vague to identify the main change at a glance. Rename it to name the primary codec cleanup, such as typed scientific decoding and envelope refactors.
✅ Passed checks (4 passed)
Check name Status Explanation
Description check ✅ Passed The description matches the codec cleanup and documentation/test refactor changes in the diff.
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 chore/0.10-simplify

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.

❤️ Share

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

@coderabbitai coderabbitai Bot added area:codec Area: codecs and serialization area:types labels Jul 13, 2026

@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.

Actionable comments posted: 1

Caution

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

⚠️ Outside diff range comments (1)
src/utils/codec.ts (1)

1291-1344: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

prefixHandlerError discards marker/kind fidelity for any non-root scientific envelope failure.

prefixHandlerError only preserves the original error when path === 'result'; for every nested envelope (e.g. a dict/array containing an ndarray/dataframe/etc.), it unconditionally rewraps into new ScientificDecodeError('envelope', 'unknown', error, ...) even though error is already a ScientificDecodeError produced by decodeEnvelopeCore with the correct kind ('arrow'/'envelope') and marker (e.g. 'ndarray'). Both call sites — the sync catch in decodeSingle's caller and settleDecoded's async catch — hit this.

This directly undermines src/runtime/bridge-codec.ts's decodeResponseAsync, which branches its BridgeCodecError message/valueType on decodeError.kind === 'arrow' and decodeError.marker. For the common case of a response object containing multiple/nested scientific values, a genuine Arrow decode failure on a nested field gets reported as a generic "Scientific envelope decoding failed (unknown): ..." instead of "Arrow decoding failed: ...", and marker-specific attribution is lost — exactly the message-parsing-style ambiguity this PR set out to eliminate.

🐛 Proposed fix to preserve kind/marker on rewrap
   const prefixHandlerError = (error: unknown, path: string): never => {
     if (path === 'result') {
       throw error;
     }
+    const message = `Scientific envelope decode failed at ${path}: ${error instanceof Error ? error.message : String(error)}`;
+    if (error instanceof ScientificDecodeError) {
+      throw new ScientificDecodeError(error.kind, error.marker, error, message);
+    }
     throw new ScientificDecodeError(
       'envelope',
       'unknown',
       error,
-      `Scientific envelope decode failed at ${path}: ${error instanceof Error ? error.message : String(error)}`
+      message
     );
   };
🤖 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 `@src/utils/codec.ts` around lines 1291 - 1344, Update prefixHandlerError in
decodeEnvelopeAsync to preserve an existing ScientificDecodeError’s kind and
marker when rewrapping non-root failures, rather than always using 'envelope'
and 'unknown'. Keep the existing root-path passthrough, and ensure both
decodeSingle’s synchronous handling and settleDecoded’s asynchronous handling
retain the original error metadata for nested failures.
🤖 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.

Inline comments:
In `@runtime/tywrap_bridge_core.py`:
- Line 528: Add a return type annotation to the private helper
`_json_object_key`, using the concrete type it returns. Apply the same
annotation consistently to the other `_json_object_key` references noted in the
diff so Ruff ANN202 is satisfied.

---

Outside diff comments:
In `@src/utils/codec.ts`:
- Around line 1291-1344: Update prefixHandlerError in decodeEnvelopeAsync to
preserve an existing ScientificDecodeError’s kind and marker when rewrapping
non-root failures, rather than always using 'envelope' and 'unknown'. Keep the
existing root-path passthrough, and ensure both decodeSingle’s synchronous
handling and settleDecoded’s asynchronous handling retain the original error
metadata for nested failures.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: f37d7edd-054b-4e61-8240-ae926575c5fd

📥 Commits

Reviewing files that changed from the base of the PR and between d1437bd and 6fe676b.

📒 Files selected for processing (8)
  • docs/codec-envelopes.md
  • runtime/tywrap_bridge_core.py
  • src/runtime/bridge-codec.ts
  • src/runtime/pyodide-bootstrap-core.generated.ts
  • src/runtime/validators.ts
  • src/utils/codec.ts
  • test/codec-envelope-validation.test.ts
  • test/runtime_codec.test.ts
💤 Files with no reviewable changes (1)
  • test/runtime_codec.test.ts
📜 Review details
⏰ Context from checks skipped due to timeout. (2)
  • GitHub Check: os (windows-latest)
  • GitHub Check: os (macos-latest)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use TypeScript strict mode and avoid any; prefer unknown with type guards.

Files:

  • test/codec-envelope-validation.test.ts
  • src/runtime/bridge-codec.ts
  • src/runtime/validators.ts
  • src/runtime/pyodide-bootstrap-core.generated.ts
  • src/utils/codec.ts
src/runtime/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Implement runtime bridges and transport code under src/runtime/.

Implement runtime bridge code under src/runtime/.

Files:

  • src/runtime/bridge-codec.ts
  • src/runtime/validators.ts
  • src/runtime/pyodide-bootstrap-core.generated.ts
🧠 Learnings (6)
📚 Learning: 2026-01-19T21:48:27.823Z
Learnt from: bbopen
Repo: bbopen/tywrap PR: 127
File: test/runtime_bridge_fixtures.test.ts:59-66
Timestamp: 2026-01-19T21:48:27.823Z
Learning: In fixture-based tests (e.g., test/runtime_bridge_fixtures.test.ts) and similar tests in the tywrap repository, prefer early returns when Python or fixture files are unavailable. Do not rely on Vitest dynamic skip APIs; a silent pass is intentional for environments lacking Python/fixtures. Treat missing fixtures as optional soft-guards and ensure the test remains non-disruptive in non-availability scenarios.

Applied to files:

  • test/codec-envelope-validation.test.ts
📚 Learning: 2026-01-20T01:34:07.064Z
Learnt from: bbopen
Repo: bbopen/tywrap PR: 136
File: src/runtime/node.ts:444-458
Timestamp: 2026-01-20T01:34:07.064Z
Learning: When reviewing promise-based polling patterns (e.g., recursive setTimeout in waitForAvailableWorker functions), ensure that any recursive timer is tracked and cleared on timeout or promise resolution to prevent timer leaks. Do not rely on no-op checks after settlement; verify clearTimeout is invoked in all paths and consider using an explicit cancellation (e.g., AbortController) or a guard to cancel pending timers when the promise settles.

Applied to files:

  • test/codec-envelope-validation.test.ts
  • src/runtime/bridge-codec.ts
  • src/runtime/validators.ts
  • src/runtime/pyodide-bootstrap-core.generated.ts
  • src/utils/codec.ts
📚 Learning: 2026-01-20T18:37:05.670Z
Learnt from: bbopen
Repo: bbopen/tywrap PR: 152
File: src/runtime/process-io.ts:37-40
Timestamp: 2026-01-20T18:37:05.670Z
Learning: In the tywrap repo, ESLint is used for linting (not Biome). Do not flag regex literals that contain control characters (e.g., \u001b, \u0000-\u001F) as lint errors, since the current ESLint configuration allows them. When reviewing TypeScript files (e.g., src/**/*.ts), rely on ESLint results and avoid raising issues about these specific control-character regex literals unless there is a competing config change or a policy requiring explicit escaping.

Applied to files:

  • test/codec-envelope-validation.test.ts
  • src/runtime/bridge-codec.ts
  • src/runtime/validators.ts
  • src/runtime/pyodide-bootstrap-core.generated.ts
  • src/utils/codec.ts
📚 Learning: 2026-01-20T16:00:49.829Z
Learnt from: bbopen
Repo: bbopen/tywrap PR: 152
File: docs/adr/002-bridge-protocol.md:203-211
Timestamp: 2026-01-20T16:00:49.829Z
Learning: In the BridgeProtocol implementation (tywrap), reject Map and Set explicitly before serialization (e.g., in safeStringify or the serialization entrypoint) with a clear error like "Bridge protocol does not support Map/Set values". Do not rely on post-hoc checks of non-string keys at the point of JSON.stringify, since Maps/Sets cannot round-trip. This should be enforced at the boundary where data is prepared for serialization to ensure deterministic errors and prevent invalid data from propagating.

Applied to files:

  • test/codec-envelope-validation.test.ts
  • src/runtime/bridge-codec.ts
  • src/runtime/validators.ts
  • src/runtime/pyodide-bootstrap-core.generated.ts
  • src/utils/codec.ts
📚 Learning: 2026-01-19T21:14:29.869Z
Learnt from: bbopen
Repo: bbopen/tywrap PR: 127
File: src/runtime/bridge-core.ts:375-385
Timestamp: 2026-01-19T21:14:29.869Z
Learning: In the runtime env-var parsing (e.g., in src/runtime/bridge-core.ts and similar modules), adopt a tolerant, best-effort policy: numeric env values should parse by taking the leading numeric portion (e.g., TYWRAP_CODEC_MAX_BYTES=1024abc -> 1024). Only reject clearly invalid values (non-numeric start or <= 0). This reduces surprising failures from minor typos. Add tests to cover partial numeric prefixes, and ensure downstream logic documents the trusted range; consider a small helper to extract a positive integer from a string with a safe fallback.

Applied to files:

  • src/runtime/bridge-codec.ts
  • src/runtime/validators.ts
  • src/runtime/pyodide-bootstrap-core.generated.ts
📚 Learning: 2026-01-19T21:14:35.390Z
Learnt from: bbopen
Repo: bbopen/tywrap PR: 127
File: src/runtime/bridge-core.ts:260-263
Timestamp: 2026-01-19T21:14:35.390Z
Learning: In src/runtime/bridge-core.ts and similar hot request/response loop implementations in the tywrap repository, avoid adding extra defensive validation (such as runtime, shape, or error-payload checks) inside tight loops unless the protocol boundary is untrusted or there is a concrete bug report. The Python bridge protocol is controlled via tests, so these checks add unnecessary branching overhead without meaningful benefit. Apply this guidance to other hot-path runtime loops in src/runtime/**/*.ts, and re-enable additional validations only when a documented risk or failure scenario is identified. Ensure tests cover protocol validation where applicable.

Applied to files:

  • src/runtime/bridge-codec.ts
  • src/runtime/validators.ts
  • src/runtime/pyodide-bootstrap-core.generated.ts
🪛 LanguageTool
docs/codec-envelopes.md

[style] ~49-~49: The double modal “required nested” is nonstandard (only accepted in certain dialects). Consider “to be nested”.
Context: ...because its value field is a required nested ndarray envelope. Serialization accept...

(NEEDS_FIXED)

🪛 Ruff (0.15.21)
runtime/tywrap_bridge_core.py

[warning] 648-648: Missing return type annotation for private function _json_object_key

(ANN202)

🔇 Additional comments (20)
src/runtime/validators.ts (1)

2-2: LGTM!

Also applies to: 40-43, 48-51

docs/codec-envelopes.md (2)

43-59: LGTM!

Also applies to: 110-111, 149-166, 191-195


51-54: Constants match the documentation.

test/codec-envelope-validation.test.ts (1)

2-6: LGTM!

src/utils/codec.ts (11)

14-52: LGTM! Clean marker registry and structured error foundation.


307-359: LGTM! Marker threaded consistently through Arrow decoder lookup/registration/decode paths.


550-579: LGTM! Good consolidation of the strict-v1 vs. lenient shape/dtype read paths.


672-709: LGTM! typeTag narrowed to the literal union and threaded correctly into decodeArrow/tagDecodedShape.


717-796: LGTM! finishNdarrayDecode extraction cleanly unifies the sync/async completion paths without altering the scalar/reshape semantics.


878-902: LGTM! scipy.sparse shape/dtype reads now go through the shared helpers with strict-v1 requirements intact.


1008-1113: LGTM! torch.tensor shape/dtype centralization and finishTensorDecode extraction preserve the scalar-normalization and shape-disagreement checks.


1216-1289: LGTM! ENVELOPE_HANDLERS typing and decodeEnvelopeCore's error-wrapping correctly preserve an inner handler's specific marker via asScientificDecodeError when re-thrown from an outer handler (e.g. torch.tensor wrapping a failed nested ndarray decode).


1394-1401: LGTM! isScientificMarker correctly mirrors the removed ENVELOPE_HANDLERS.has(...) availability check since the marker list and handler map keys match 1:1.


1487-1515: LGTM! decodeValue/decodeValueAsync correctly funnel through requireArrowDecoder/asScientificDecodeError for structured, marker-aware failures at the public entrypoints (modulo the nested-path fidelity gap flagged on prefixHandlerError above).


33-42: 🎯 Functional Correctness

No issue with Error.cause here. The project targets ES2022, so Error.cause is part of the base Error type and override readonly cause: unknown is valid.

			> Likely an incorrect or invalid review comment.
src/runtime/bridge-codec.ts (2)

13-17: LGTM! Centralizing marker detection through isScientificMarker removes the duplicated SCIENTIFIC_MARKERS set/scientificMarkerFrom helper cleanly.

Also applies to: 98-119


656-692: LGTM! Structured ScientificDecodeError unwrapping is a solid improvement over message parsing for root-level failures. Note this branch's message/valueType accuracy for nested envelopes depends on marker/kind fidelity from decodeEnvelopeAsync's prefixHandlerError in src/utils/codec.ts (flagged separately there — nested failures currently report as generic unknown/envelope rather than their real marker/kind).

runtime/tywrap_bridge_core.py (2)

63-63: LGTM! Good de-duplication of the JS safe-integer bound into a single named constant.

Also applies to: 418-419, 667-668


1200-1202: LGTM! Delegating to serialize_stdlib removes the duplicated inline datetime/Decimal/UUID/Path handling and matches the pattern already used by _serialize_leaf.

src/runtime/pyodide-bootstrap-core.generated.ts (1)

12-12: LGTM! Spot-checked sections (JS_SAFE_INTEGER_MAX, _json_object_key, serialize_stdlib-backed default_encoder) match runtime/tywrap_bridge_core.py verbatim, consistent with this being a regenerated, conformance-guarded bootstrap string.


_validate_pandas_json_index(obj.index, pd, 'DataFrame')
json_columns = [_pandas_json_object_key(column) for column in obj.columns]
json_columns = [_json_object_key(column) for column in obj.columns]

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Add a return type annotation to _json_object_key.

Ruff (ANN202) flags the missing return type on this private function.

🧹 Proposed fix
-def _json_object_key(value):
+def _json_object_key(value) -> str | None:
     """Return json.dumps' object-key spelling, or None for unsupported keys."""

Also applies to: 648-654, 1055-1055

🤖 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 `@runtime/tywrap_bridge_core.py` at line 528, Add a return type annotation to
the private helper `_json_object_key`, using the concrete type it returns. Apply
the same annotation consistently to the other `_json_object_key` references
noted in the diff so Ruff ANN202 is satisfied.

Source: Linters/SAST tools

@bbopen bbopen merged commit 8227db7 into main Jul 13, 2026
24 checks passed
@bbopen bbopen deleted the chore/0.10-simplify branch July 13, 2026 15:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:codec Area: codecs and serialization area:docs Area: documentation area:runtime area:types

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant