Skip to content

gate for obj fast ingest - #397

Merged
aricart merged 1 commit into
mainfrom
fi-obj-gate
May 5, 2026
Merged

aricart merged 1 commit into
mainfrom
fi-obj-gate

Conversation

@aricart

@aricart aricart commented May 5, 2026

Copy link
Copy Markdown
Member

No description provided.

@synadia-claude-reviewer

synadia-claude-reviewer Bot commented May 5, 2026 •

Copy link
Copy Markdown
Contributor

Claude finished @aricart's task in 3m 3s β€”β€” View job


PR Review: gate for obj fast ingest

  • Set up todo list
  • Gather PR diff and context
  • Read changed source files
  • Analyze for correctness, security, and performance issues
  • Post inline comments and summary

Summary

The PR flips fast ingest from opt-out to opt-in (hidden gate via an undocumented fastIngest property), which is a safer default. The logic is generally correct but has a few issues worth addressing:

Correctness concern (moderate): status() now silently re-evaluates supportsFastIngest as a side-effect. For the open(check=false, fastIngest=true) path this can silently undo the caller's explicit trust: if the stream doesn't actually have allow_batched=true, a later status() call flips supportsFastIngest to false mid-session. Inline comment at line 454.

API asymmetry (low): The open(check=false, fastIngest=true) path skips the api_lvl >= 4 server capability check that init() enforces for create(). Runtime publish errors instead of early rejection. Inline comment at line 155.

Discoverability (informational): The fastIngest option in both open() and create() is invisible to the type system β€” callers must cast to unknown to pass it. The type signature boolean | { check?: boolean } gives no hint that fastIngest is read. This is clearly intentional as a gate, but it means the only documentation lives in test code. Inline comment at line 140.

Test nit: The fi() helper is defined in the middle of an import block. Inline comment at line 57 of the test file.

Comment thread obj/src/objectstore.ts Outdated
if (info === null) {
return Promise.reject(new Error("object store not found"));
}
this.supportsFastIngest = this.fiRequested &&

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

status() now has a hidden side-effect on supportsFastIngest. This creates a subtle footgun for the open(check=false, fastIngest=true) path: that path explicitly bypasses the probe and sets supportsFastIngest = true unconditionally, but a later call to status() (e.g. for monitoring) will silently flip the flag back to false if allow_batched isn't actually set on the stream β€” silently breaking the "trust the caller" contract.

Either document this re-evaluation behavior, or guard against it by not modifying supportsFastIngest when the caller explicitly bypassed the check.

Comment thread obj/src/objectstore.ts Outdated
} else {
const o = check as Record<string, unknown>;
doCheck = o.check !== false;
fastIngest = o.fastIngest === true;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The open() type signature (boolean | { check?: boolean }) doesn't expose fastIngest at all. Passing { check: true, fastIngest: true } satisfies { check?: boolean } at runtime, but nothing in the type surface signals to callers that fastIngest is a recognized option here. Consider either adding an explicit internal type (even if unexported) or adding a JSDoc note so the intent is discoverable during code review.

Comment thread obj/src/objectstore.ts Outdated
}
} else if (fastIngest) {
// no probe β€” trust caller
os.supportsFastIngest = true;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The check=false path skips both the stream capability probe and the api_lvl >= 4 server check that init() enforces. If a caller opens with {check: false, fastIngest: true} against a server that doesn't support batched publishes, writes will fail at runtime with a protocol-level error rather than a clean early rejection. The asymmetry with create() (which always checks apiLvl < 4) may be intentional but is worth a comment.

Comment thread obj/tests/objectstore_test.ts Outdated

// hidden opt-in for fast-ingest. property is not on ObjectStoreOptions; the
// implementation reads it via cast and strips it before stream config build.
function fi(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The fi() helper is defined between two import blocks (the import from objectstore.ts comes before it, the import from base64.ts comes after). This splits the import section in a surprising way. Minor: move fi() after all imports, or move both import statements above it.

#391)

* feat(jsapi): add `ConsumerResetResponse` and reset functionality for consumer state management

-  `reset()` and `resetConsumer()` methods for resetting consumer delivery state.

---------

Signed-off-by: Alberto Ricart <alberto@synadia.com>
@aricart

aricart commented May 5, 2026

Copy link
Copy Markdown
Member Author

@claude re-review

@synadia-claude-reviewer

synadia-claude-reviewer Bot commented May 5, 2026 •

Copy link
Copy Markdown
Contributor

Claude finished @aricart's task in 2m 10s β€”β€” View job


PR Re-Review: gate for obj fast ingest

  • Set up todo list
  • Read changed files
  • Analyze changes for correctness, security, and performance
  • Post updated review

Summary

All four concerns from the previous review have been addressed. Here's the breakdown:


Previous concerns β€” status

1. status() side-effect on supportsFastIngest β†’ βœ… Resolved

status() now just calls _si() and returns an ObjectStoreStatusImpl. It no longer touches allowBatched at all. The footgun is gone.

2. open(check=false) skipping api_lvl >= 4 check β†’ βœ… Resolved

open() now checks apiLvl < 4 before proceeding (objectstore.ts:144-148), consistent with init(). Both paths reject early on a server that doesn't support batched publishes.

3. fastIngest invisible to type system β†’ βœ… Intentionally maintained (renamed to allowBatched)

The option was renamed from fastIngest to allowBatched (directly mirroring the stream config field allow_batched). It remains hidden from the public type surface by design β€” callers must cast to pass it. Tests use as Partial<ObjectStoreOptions> and as { check: boolean } casts to acknowledge the intentional opacity. The inline comment at line 137 explains the contract.

4. fi() helper between import blocks in test β†’ βœ… Resolved

The fi() helper no longer exists. The test file was reworked to remove it entirely.


New observations

Rename is clean. allowBatched β†’ allow_batched on the stream config is a 1:1 mapping and easier to reason about than fastIngest/disableFastIngest/supportsFastIngest.

open(check=false, allowBatched=true) semantics are now clearly documented in the test name β€” "open(check=false) may defer fastIngest incompatibility to put" β€” and the test exercises the actual rejection at publish time. The behavior is intentional and spelled out.

init() correctly handles the existing-stream case. When allowBatched=true and the stream already exists without allow_batched, init() rejects early (line 1039-1043) rather than silently continuing or attempting to update the stream config. This is the right call.

One very minor nit: the JSDoc on open() (line 123-127) still only documents the boolean form of check. The object overload and allowBatched are intentionally undocumented, but a reviewer unfamiliar with the gate pattern might wonder why the declared type is boolean | { check?: boolean } without any mention of allowBatched. Not a blocking issue given this is a deliberate gate, but worth noting.


Overall

This is a clean, well-reasoned revision. The gate pattern (opt-in, hidden from public types, server capability checked eagerly on both code paths) is correctly implemented. No blocking issues.

@aricart
aricart marked this pull request as ready for review May 5, 2026 14:22

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

LGTM

@aricart
aricart merged commit 035f897 into main May 5, 2026
29 checks passed
@aricart
aricart deleted the fi-obj-gate branch May 5, 2026 15:03
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.

2 participants