Skip to content

feat: stream many-observer readings - #772

Merged
flyingrobots merged 2 commits into
mainfrom
v19/bounded-observation
Jul 24, 2026
Merged

feat: stream many-observer readings#772
flyingrobots merged 2 commits into
mainfrom
v19/bounded-observation

Conversation

@flyingrobots

@flyingrobots flyingrobots commented Jul 24, 2026

Copy link
Copy Markdown
Member

Summary

  • add internal/generated-SDK support for finite or async many Observer reading-plan factories while preserving the exactly-one API
  • execute every Reading in one Observation against a single pinned Tick and advance the plan source only on downstream demand
  • drain receipt-first observations without collecting Reading values, settle cancellation and empty-plan receipts explicitly, and hold Runtime shutdown until stream completion
  • validate generated plan sources at the domain boundary and raise the line-coverage ratchet to 92.95%

Issue

Refs #712
Prerequisite for #760
Depends on the cold bounded-materialization work tracked by #738.

Test plan

  • pre-push IRONCLAD gate: links, lint, source/test/policy/consumer typechecks, declaration surface, Markdown/code samples, docs topology, CAS invariants, and all stable unit shards
  • coverage: 606 files passed, 1 skipped; 7,346 tests passed, 2 skipped; 92.95% lines
  • publication surface: 0 errors, 0 warnings
  • link check: 169 total, 147 valid, 22 intentionally excluded
  • regression tests cover lazy sync/async plans, non-iterable factory rejection, receipt-first draining, pinned-Tick execution, empty plans, cancellation, and Runtime shutdown

ADR checks

  • This PR does not implement ADR 2 without satisfying ADR 3
  • If this PR touches persisted op formats, I linked the ADR 3 readiness issue (N/A: no persisted op formats)
  • If this PR touches wire compatibility, I confirmed canonical-only ops are still rejected on the wire pre-cutover (N/A: no wire changes)
  • If this PR touches schema constants, I confirmed patch and checkpoint namespaces remain distinct (N/A: no schema constants)

@coderabbitai

coderabbitai Bot commented Jul 24, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The observer runtime now supports cardinality-aware lazy reading plans. Lane observations stream many-observer readings against a pinned tick, settle receipts for completion or cancellation, and manage activity through idempotent leases. Documentation and type-check coverage describe the new many-observer flow.

Changes

Many Observer Runtime

Layer / File(s) Summary
Cardinality-aware observer plans
src/domain/api/ObserverRuntime.ts, test/unit/domain/ObserverRuntime.test.ts
Observer plans distinguish exactly-one and many observers, expose lazy reading sources, and validate unsupported plans.
Lease-based activity tracking
src/application/RuntimeActivity.ts, test/unit/application/RuntimeActivity.test.ts
acquire() returns an idempotent lease, while activity tracking and close behavior are covered by tests.
Lazy lane observation streaming
src/application/RuntimeLaneAdapter.ts, test/unit/application/RuntimeLaneAdapter.test.ts, vitest.config.ts
Lane observations stream readings on demand, pin ticks, produce completion or cancellation receipts, release leases, and increase the coverage threshold.
Generated usage and API documentation
docs/topics/api/README.md, test/type-check/generated-users.ts, test/type-check/v19-consumer.ts
Examples and type checks cover generated many observers, asynchronous reading iteration, receipt access, and pinned-tick semantics.

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

Possibly related PRs

Poem

I stream through ticks, one hop at a time,
With leases released in orderly rhyme.
Receipts settle when readings are done,
Or cancellation says, “no more fun!”
A bunny applauds: lazy plans run! 🐇

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
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.
Title check ✅ Passed The title is concise and accurately highlights the main change: streaming many-observer readings.
Description check ✅ Passed The description matches the template with Summary, Issue, Test plan, and ADR checks, and it includes a same-repo issue reference.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

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.

@github-actions

Copy link
Copy Markdown

Release Preflight

  • package version: 18.2.1
  • prerelease: false
  • npm dist-tag on release: latest
  • npm pack dry-run: passed
  • jsr publish dry-run: passed

If this PR is from a release/* branch and merges to main, Main Push Release Branch Check will run final preflight and create v18.2.1. A maintainer who is a JSR @git-stunts scope member must then dispatch the Release workflow manually.

@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

🤖 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 `@src/domain/api/ObserverRuntime.ts`:
- Around line 83-88: Validate the value returned by plan.readings() in
observerReadings before returning it for the many-cardinality branch. Reuse the
existing E_OBSERVER_PLAN validation behavior used by
createObserver/createManyObserver, and raise a domain WarpError for undefined or
non-async-iterable results instead of allowing consumer-side TypeError 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 Plus

Run ID: c540a57e-effa-419d-84fc-0c7fb1f7c5f5

📥 Commits

Reviewing files that changed from the base of the PR and between a2c1e08 and ae4d483.

📒 Files selected for processing (10)
  • docs/topics/api/README.md
  • src/application/RuntimeActivity.ts
  • src/application/RuntimeLaneAdapter.ts
  • src/domain/api/ObserverRuntime.ts
  • test/type-check/generated-users.ts
  • test/type-check/v19-consumer.ts
  • test/unit/application/RuntimeActivity.test.ts
  • test/unit/application/RuntimeLaneAdapter.test.ts
  • test/unit/domain/ObserverRuntime.test.ts
  • vitest.config.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,js,jsx}: Do not use direct imports from src/infrastructure/** in src/domain/** or src/ports/**; depend on a port instead.
Do not use direct Node built-ins in src/domain/** or src/ports/**; use a port instead.

Files:

  • vitest.config.ts
  • test/unit/application/RuntimeActivity.test.ts
  • test/type-check/v19-consumer.ts
  • test/unit/domain/ObserverRuntime.test.ts
  • test/type-check/generated-users.ts
  • src/application/RuntimeActivity.ts
  • src/domain/api/ObserverRuntime.ts
  • test/unit/application/RuntimeLaneAdapter.test.ts
  • src/application/RuntimeLaneAdapter.ts
src/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.{ts,tsx,js,jsx}: Do not introduce any, as any, as unknown as, unknown (outside adapters), Record<string, unknown> (outside adapters), *Like placeholder types, JSON.parse/JSON.stringify (outside adapters), fetch (outside adapters), process.env (outside adapters), @ts-ignore, or z.any() in core code; use validated boundary models and ports instead.
Use constructor-injected ports for external capabilities; do not rely on ambient dependencies for I/O, clocks, persistence, or entropy.
Do not create utils.ts, helpers.ts, misc.ts, or common.ts; name files after the actual concept they model.
Prefer one file per class, type, or object; if a file accumulates peer concepts, split it.
Keep helper corridors, fake shape trust, transitional duplication, and compile-time theater out of the codebase; runtime-honest TypeScript must reflect actual behavior.
No enum usage; prefer runtime-backed domain forms and unions.
Do not use boolean trap parameters; prefer named option objects or separate methods.
Avoid magic strings or numbers when a named constant should exist.
Keep domain bytes as Uint8Array; Buffer belongs in infrastructure adapters.

Files:

  • src/application/RuntimeActivity.ts
  • src/domain/api/ObserverRuntime.ts
  • src/application/RuntimeLaneAdapter.ts
src/domain/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

src/domain/**/*.{ts,tsx,js,jsx}: In src/domain/**, do not use Date.now(), new Date(), Date(), performance.now(), Math.random(), crypto.randomUUID(), crypto.getRandomValues(), setTimeout, setInterval, raw new Error(...)/new TypeError(...), or direct imports from Node built-ins; time, entropy, and external capabilities must enter through ports or parameters, and domain errors should extend WarpError.
Construct domain objects only in core when doing so establishes validated runtime truth; do not build infrastructure adapters, host APIs, persistence implementations, wall clocks, or entropy sources inside core.
Prefer discriminated unions and explicit result types instead of boolean-flag bags, and model expected failures as return values rather than exceptions.
src/domain/ must not import host APIs or Node-specific globals; hexagonal architecture boundaries are mandatory.
Domain code must not use the wall clock directly; time must enter through a port or parameter.

Files:

  • src/domain/api/ObserverRuntime.ts
src/domain/**/!(*.test).{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use explicit domain concepts with validated constructors, Object.freeze, and instanceof dispatch; domain objects should be runtime-backed nouns, not ad hoc shape bags.

Files:

  • src/domain/api/ObserverRuntime.ts
🔇 Additional comments (14)
src/domain/api/ObserverRuntime.ts (2)

6-20: LGTM!


22-63: LGTM!

test/unit/domain/ObserverRuntime.test.ts (1)

1-84: LGTM!

src/application/RuntimeActivity.ts (2)

5-7: LGTM!

Also applies to: 17-39


58-65: LGTM!

test/unit/application/RuntimeActivity.test.ts (1)

28-56: LGTM!

src/application/RuntimeLaneAdapter.ts (3)

3-30: LGTM!


58-184: LGTM!


201-259: LGTM!

test/unit/application/RuntimeLaneAdapter.test.ts (1)

1-10: LGTM!

Also applies to: 89-148, 149-190, 191-220, 222-242, 244-283, 333-340

vitest.config.ts (1)

33-33: LGTM!

docs/topics/api/README.md (1)

178-187: LGTM!

Also applies to: 222-227

test/type-check/generated-users.ts (1)

2-5: LGTM!

Also applies to: 31-46

test/type-check/v19-consumer.ts (1)

40-47: LGTM!

Also applies to: 94-94

Comment thread src/domain/api/ObserverRuntime.ts
@github-actions

Copy link
Copy Markdown

Release Preflight

  • package version: 18.2.1
  • prerelease: false
  • npm dist-tag on release: latest
  • npm pack dry-run: passed
  • jsr publish dry-run: passed

If this PR is from a release/* branch and merges to main, Main Push Release Branch Check will run final preflight and create v18.2.1. A maintainer who is a JSR @git-stunts scope member must then dispatch the Release workflow manually.

@flyingrobots
flyingrobots merged commit c872789 into main Jul 24, 2026
18 checks passed
@flyingrobots
flyingrobots deleted the v19/bounded-observation branch July 24, 2026 15:39
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