forked from commontoolsinc/labs
-
Notifications
You must be signed in to change notification settings - Fork 0
[pull] main from commontoolsinc:main #152
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
* feat(memory): Incremental schema subscription updates Optimize getSchemaSubscriptionMatches by preserving the schemaTracker between invocations instead of re-running full querySchema for every subscription after each commit. Changes: - Extend SchemaSubscription to store schemaTracker (doc→schema mappings) - Add evaluateDocumentLinks() for single-doc schema evaluation - Add querySchemaWithTracker() to expose schemaTracker from initial query - Replace full re-query with incremental update: 1. Find changed docs that exist in subscription's schemaTracker 2. Re-evaluate only those docs with their associated schemas 3. Follow new links incrementally (not already in schemaTracker) 4. Accumulate only new/changed facts for the response This significantly reduces work for subscriptions with large result sets where commits typically only affect a small portion of tracked documents. Falls back to full re-query on errors for safety. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * fmt * fix(memory): Use correct key format for schemaTracker lookup The schemaTracker uses "id/type" format (from BaseObjectManager.toKey), but extractChangedDocKeys was using "id\0type" format with null separator. This caused changed docs to never match entries in schemaTracker, breaking incremental subscription updates. Also use lastIndexOf('/') instead of split to handle IDs containing slashes. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * fix(memory): Track docs in schemaTracker even without schemaContext When schemaContext is undefined, the document was being loaded into the manager but not added to schemaTracker. This caused incremental updates to miss changes to these documents since they wouldn't be found in findAffectedDocs. Now we always add the document to schemaTracker with its selector, ensuring all documents in the query result can be tracked for changes. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * fix(memory): Add fallback when schemaTracker misses watchedObjects match The incremental update optimization now uses a two-phase approach: 1. First check if Subscription.match() triggers on watchedObjects 2. Then try to use schemaTracker for incremental processing 3. Fall back to full re-query for subscriptions where watchedObjects matches but schemaTracker doesn't have the changed docs This is more complex than ideal - the root cause is that schemaTracker and watchedObjects can get out of sync because they're populated via different code paths and use different key formats: - watchedObjects: watch:///${space}/${of}/${the} - schemaTracker: ${of}/${the} TODO: Unify these tracking mechanisms so watchedObjects becomes redundant and can be removed. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * fix(memory): Use indexOf instead of lastIndexOf to parse docKey The docKey format is "id/type" where type can contain slashes (e.g., "application/json"). Using lastIndexOf("/") incorrectly split "of:HASH/application/json" into: - docId: "of:HASH/application" (wrong) - docType: "json" (wrong) Using indexOf("/") correctly splits at the first slash: - docId: "of:HASH" (correct) - docType: "application/json" (correct) This was causing selectFact to return null, so incremental updates never returned any facts, breaking subscription notifications. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * refactor(memory): Simplify schema subscription matching Replace dual tracking (watchedObjects + schemaTracker) with clearer separation: - schemaTracker: tracks which docs to watch with which schemas - sentDocs: tracks which docs have been sent to the client - isWildcardQuery: flag for queries with of: "_" For wildcard queries, match changed docs by type pattern instead of re-running the full query. Both wildcard and non-wildcard queries now use the same incremental processing flow. Remove fallback re-query code paths - throw on mount error instead. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * fix(memory): Add cycle detection for growing path cycles in incremental updates Track per-document visit counts to detect cycles like A -> A/foo -> A/foo/foo that create infinitely growing paths. Limits each document to 100 visits before logging a warning and stopping further traversal. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
…rage locations (#2235) * feat(runner): auto-start charms when events are sent to unhandled storage locations When an event is sent to a storage location that has no registered event handler, the scheduler now attempts to start the underlying charm. This enables lazy charm initialization - charms can be started on-demand when they first receive an event. The implementation: - Adds ensureCharmRunning() utility that traverses the source cell chain to find the process cell, then starts the charm via runtime.runSynced() - Modifies queueEvent() to call ensureCharmRunning() when no handler is found - Includes infinite loop protection to prevent re-queuing if the charm doesn't register a handler for the event 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * test(runner): add tests for ensureCharmRunning and auto-start behavior Tests cover: - Return false for cells without process cell structure - Return false for cells without TYPE in process cell - Return false for cells without resultRef in process cell - Successfully start charm with valid process cell structure - Infinite loop protection (don't attempt to start twice) - Graceful handling of events for orphan cells - No infinite retry when charm doesn't register handler 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * fmt * test: improved tests for ensureCharmRunning - Adds test proving charm starts when event is sent to a cell with no handler - Adds test proving handler is called when defined for the stream path - Tests verify infinite loop protection (charm only starts once per path) - Updates orphan cell test to check actual values instead of expect(true) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * refactor(runner): simplify ensureCharmRunning by removing tracking Remove the startAttemptedForCell Set and cellLinkKey helper since runtime.runSynced() is already idempotent for running charms - calling it multiple times simply returns without doing anything. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * fix(runner): prevent infinite loop in queueEvent when no handler exists When re-queuing an event after starting a charm, pass a flag to prevent triggering another charm load attempt. This avoids infinite loops when the charm doesn't register a handler for that event type. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * test(runner): add test for restarting stopped charms Verifies that ensureCharmRunning properly restarts a charm that was previously stopped via runtime.runner.stop(). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
#2237) * fix(runner): capture reactivity log after callback to track all cell reads In subscribeToReferencedDocs(), the reactivity log was being captured BEFORE the callback executed. This meant that any cell reads occurring during the callback - such as accessing properties of derived arrays during JSX rendering - were not tracked for subscription purposes. The symptom: styles referencing derived data (e.g., 'derive()' output used for dynamic background colors) would render correctly on initial load but never update when the underlying cell changed. The handler would fire, the derive would recompute, but the UI wouldn't re-render. Root cause: When rendering JSX like: background: filteredItemsWithHighlight[index]?.highlightBg The array element access happens during the effect callback. Since txToReactivityLog(tx) was called before callback(value), these reads weren't captured in the subscription, so changes to the derived cell's internal data didn't trigger the effect to re-run. The fix moves txToReactivityLog(tx) to after callback(value), ensuring all cell reads during rendering are captured and subscribed to. * add regression test
* initial draft implementation of action * fix Handler/HandlerFactory types to return Stream instead of OpaqueRef - Handler.with and HandlerFactory now correctly typed to return Stream<R> - stream() function in opaque-ref.ts now returns Stream<T> - ActionFunction now returns HandlerFactory<T, void> - Schema generator detects Stream in callable return types for result schema This makes the types accurately reflect runtime behavior where handlers return Streams. Fixes action() result schema generation. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * add runtime tests for action, fix missing { proxy: true } option
…-session (#2241) Previously, each SchemaSubscription tracked its own `sentDocs` Set and `since` value to avoid sending duplicate documents. This was suboptimal because the same document could be sent multiple times on the same WebSocket session if requested by different subscriptions. Now we use the session-level `lastRevision` Map (which already existed for non-schema subscriptions) to track which documents have been sent and at what `since` value. This ensures that each document is only sent once per session, regardless of how many subscriptions request it. Changes: - Remove `since` and `sentDocs` fields from SchemaSubscription class - Simplify addSchemaSubscription to not track sent docs - Update getSchemaSubscriptionMatches to use session-level lastRevision - Let filterKnownFacts handle updating lastRevision when facts are sent 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude <noreply@anthropic.com>
#2238) The previous approach used `T extends AnyBrandedCell<any>` (without tuple wrapper) to handle intersection types like `OpaqueCell<X> & Y`. However, this caused TypeScript to distribute over union types, which broke the null-preservation fix from commit 3f3de55. For example, `string | null extends AnyBrandedCell<any>` distributes to: - `string extends AnyBrandedCell<any>` (evaluated separately) - `null extends AnyBrandedCell<any>` (evaluated separately) This changed the type structure and caused schema generation to lose null. The correct approach handles nullable intersection types in the nullable handling section of OpaqueRefInner: `[NonNullable<T>] extends [AnyBrandedCell<any>] ? T` This: 1. Uses the tuple wrapper to prevent distribution 2. Strips null/undefined first with NonNullable 3. Then checks if the remaining type is a branded cell For `(OpaqueCell<X> & X) | undefined`: - NonNullable gives `OpaqueCell<X> & X` - Tuple check correctly identifies it as a branded cell - Returns T unchanged (preserving the union with undefined) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
See Commits and Changes for more details.
Created by
pull[bot] (v2.0.0-alpha.4)
Can you help keep this open source service alive? 💖 Please sponsor : )