Skip to content

feat(intake): deliver private Notion specs across fleet nodes - #215

Merged
khaliqgant merged 6 commits into
mainfrom
codex/notion-portable-fleet-mount-20260806
Aug 6, 2026
Merged

feat(intake): deliver private Notion specs across fleet nodes#215
khaliqgant merged 6 commits into
mainfrom
codex/notion-portable-fleet-mount-20260806

Conversation

@khaliqgant

@khaliqgant khaliqgant commented Aug 6, 2026

Copy link
Copy Markdown
Member

Summary

  • add an explicit workspace-private Agent Relay channel transport for digest-bound Notion mount snapshots
  • keep omitted transport local for backward compatibility and fail closed without an active workspace key
  • isolate each source revision in its own digest channel and reuse exact message IDs across publisher identities
  • migrate untouched lifecycle issues with validated crash-recoverable delivery receipts
  • refresh existing exact-path workers by steering or respawning the same deterministic agent
  • prevent portable-to-local downgrade, stale-cache reuse, ambient credential borrowing, marker ambiguity, initialization leaks, and premature receipt writes

Verification

  • npm test (78 files, 1433 tests)
  • npm run build
  • git diff --check
  • live cross-node byte reconstruction with exact SHA-256
  • live second-publisher retry reused identical channel and message IDs
  • Veto diff reviews: PASS (final lifecycle follow-up 99 code / 99 security; secrets clean; no decision drift)

@cursor

cursor Bot commented Aug 6, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The Notion intake adds relay-channel delivery for mounted content. It publishes digest-bound chunks, renders worker reconstruction instructions, persists delivery receipts, reconciles GitHub and workspace dispatches, and manages the publisher through CLI startup and shutdown.

Changes

Notion relay delivery

Layer / File(s) Summary
Contract and Relay publisher
src/intake/notion.ts, src/intake/notion-relay-contract.ts, src/intake/index.ts
The manifest supports local and relay-channel transports. Public delivery interfaces and Relay publisher utilities handle digest validation, chunk publication, idempotency, pagination, caching, and disposal.
Intake delivery reconciliation
src/intake/notion.ts, src/intake/notion.test.ts, README.md
GitHub and workspace dispatches include relay reconstruction instructions and delivery receipts. Existing issues and receipts are reconciled with safeguards for edited issue bodies. Tests cover publication, migration, missing publishers, and local defaults.
CLI wiring and shutdown
src/cli/fleet.ts
Non-dry runs resolve the active relay workspace and inject the contract publisher. Shutdown disposes the publisher before mount and fleet cleanup.

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

Possibly related PRs

  • AgentWorkforce/factory#213: The current PR extends its Notion intake and CLI flow with relay-channel contract publishing and mounted-worker delivery.

Poem

A rabbit hops where relay bytes flow,
With digest seals in rows below.
Chunks arrive, read-only and bright,
Workers rebuild the files just right.
The intake sleeps when cleanup’s done.

🚥 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 clearly summarizes the main change: delivering private Notion specifications across fleet nodes.
Description check ✅ Passed The description directly explains the relay transport, compatibility behavior, lifecycle migration, safeguards, and verification for the changeset.
✨ 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 codex/notion-portable-fleet-mount-20260806

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.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 81500b6c26

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/intake/notion.ts Outdated
Comment on lines +508 to +510
const delivery = await prepareContractDelivery(task, input, receipt.delivery)
if (delivery && !sameContractDelivery(receipt.delivery, delivery)) {
state.receipts[task.sourceKey] = { ...receipt, delivery }

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Do not mark workspace migrations delivered without notifying the worker

When an exact-path task already has a receipt from the local transport and the manifest is changed to relay-channel, this publishes the snapshot and records its delivery but immediately returns already-dispatched; the previously spawned worker still has only the old local-mount prompt and never receives the channel or message IDs. This is especially harmful when the transport is changed because that worker is on a node without the shared mount: subsequent runs see the new receipt and permanently suppress a dispatch that contains the portable instructions. The migration must update/re-dispatch the worker task or remain blocked rather than persisting an unusable delivery.

Useful? React with 👍 / 👎.

Comment thread src/intake/notion.ts Outdated
Comment on lines +422 to +423
if (input.manifest.workerMountTransport.kind === 'relay-channel' &&
!receipt.delivery && existing.body !== renderIssueBody(task, summary)) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Reconcile interrupted lifecycle-issue migrations

If the process exits or writeIntakeState fails after updateIssue succeeds but before the delivery is persisted, the next run has a receipt without delivery and an issue body that already contains the generated portable instructions. This guard classifies that exact partially committed state as a manual edit before the idempotent publisher can recover the same delivery, so every retry remains blocked even though the issue update was performed by Factory. Detect and verify the generated contract marker/body so this external-write/local-receipt gap can be reconciled safely.

Useful? React with 👍 / 👎.

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

🧹 Nitpick comments (8)
src/cli/fleet.ts (1)

189-195: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Check the injected publisher before requiring a workspace key.

Line 117 documents deps.notionContracts as a hermetic publisher for intake tests and alternate runtimes. An injected publisher supplies its own transport and needs no workspace key.

Lines 190-193 resolve the key and throw before line 194 consults deps.notionContracts. A hermetic test must therefore populate RELAY_WORKSPACE_KEY or an equivalent variable purely to reach its own injected dependency. That defeats the stated purpose of the injection point.

Resolve the key only when the CLI constructs the real publisher.

♻️ Proposed reordering
       if (!globals.dryRun && manifest.workerMountTransport.kind === 'relay-channel') {
-        const workspaceKey = resolveRelayWorkspaceKey({ env: deps.env ?? process.env })
-        if (!workspaceKey) {
-          throw new Error('relay-channel worker mount transport requires an active Agent Relay workspace')
+        if (deps.notionContracts) {
+          notionContracts = deps.notionContracts
+        } else {
+          const workspaceKey = resolveRelayWorkspaceKey({ env: deps.env ?? process.env })
+          if (!workspaceKey) {
+            throw new Error('relay-channel worker mount transport requires an active Agent Relay workspace')
+          }
+          notionContracts = new RelayChannelNotionContractPublisher({ workspaceKey })
         }
-        notionContracts = deps.notionContracts ?? new RelayChannelNotionContractPublisher({ workspaceKey })
       }
🤖 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/cli/fleet.ts` around lines 189 - 195, Update the relay-channel branch
around notionContracts so it first reuses deps.notionContracts when provided,
without resolving or requiring a workspace key. Only resolveRelayWorkspaceKey
and throw for a missing key when constructing the fallback
RelayChannelNotionContractPublisher.
src/intake/notion.test.ts (3)

443-443: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Cover the workerMountTransport default through the manifest loader.

Every fixture sets workerMountTransport explicitly, because NotionIntakeManifest is the zod output type and the field is required there. No test parses a manifest that omits the field.

Backward compatibility for existing manifests depends entirely on .default({ kind: 'local' }) in workerMountTransportSchema. If that default is removed, loadNotionIntakeManifest rejects every manifest already on disk, and the current suite still passes.

Add one test that calls loadNotionIntakeManifest with a manifest JSON that omits workerMountTransport and asserts the resolved value is { kind: 'local' }.

🤖 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/intake/notion.test.ts` at line 443, Add a test for
loadNotionIntakeManifest that parses manifest JSON without workerMountTransport
and asserts the resolved field equals { kind: 'local' }. Keep existing
explicit-field fixtures unchanged and ensure the test exercises the schema
default rather than constructing a NotionIntakeManifest directly.

230-239: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Assert the migrated receipt on disk.

This test verifies the GitHub side of the migration through updateIssue. It does not verify the receipt.

The delivery persistence on the migration path is new behavior in this PR: publishRepoTask mutates the receipt, and runNotionIntakeUnlocked writes the state only because the change detection now compares the full serialized receipt. A regression in either place leaves the issue updated and the receipt without a delivery, which is the exact crash-consistency state that blocks later runs.

Read manifest.statePath and assert the persisted delivery, as the test at lines 198-204 does for the create path.

💚 Proposed assertion
     expect(github.updateIssue).toHaveBeenCalledWith(expect.objectContaining({
       repo: 'AgentWorkforce/cloud',
       number: 42,
       body: expect.stringContaining('factory-notion-e1cff7cf-aabbccddee'),
     }))
+    const stored = JSON.parse(await readFile(manifest.statePath, 'utf8'))
+    expect(stored.receipts[`notion:${pageId}:repo:agentworkforce/cloud`].delivery).toEqual({
+      kind: 'relay-channel',
+      channel: 'factory-notion-e1cff7cf-aabbccddee',
+      messageIds: ['message-1'],
+      encoding: 'base64-chunks-v1',
+    })
🤖 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/intake/notion.test.ts` around lines 230 - 239, Extend the migration-path
test around runNotionIntake to read the persisted receipt from
manifest.statePath after dispatching, then assert that its delivery matches the
expected migrated delivery data, following the existing create-path persistence
assertion near lines 198-204. Keep the current GitHub update assertions
unchanged.

176-183: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add unit tests for RelayChannelNotionContractPublisher.

These tests exercise the intake reconciliation through a hand-written NotionContractPublisher stub. The real publisher in src/intake/notion-relay-contract.ts carries the safety-critical logic and appears to have no test file: the digest gate, base64 chunking at the 6,000-character boundary, marker-based reuse of prior messages, the text !== expectedText rejection, and the pagination guards in listAllMessages.

The PR objective states that publication is retry-safe across publisher identities and that cross-node byte reconstruction was verified manually. Cover those properties with a fake AgentRelay so they hold under change.

Suggested cases:

  • A content and digest mismatch throws before any network call.
  • A second publish reuses the prior message ids for identical content.
  • A prior message with a matching marker but different payload throws.
  • Content longer than 6,000 base64 characters produces multiple ordered chunks.
  • A page that returns fewer than 100 messages stops pagination.

Do you want me to generate these tests, or open an issue to track them?

🤖 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/intake/notion.test.ts` around lines 176 - 183, Add unit tests for
RelayChannelNotionContractPublisher using a fake AgentRelay, covering
digest/content mismatch before network calls, retry reuse of message IDs for
identical content, rejection of marker-matched messages with different text,
ordered chunking beyond 6,000 base64 characters, and listAllMessages stopping
when a page contains fewer than 100 messages. Keep the tests focused on
cross-node reconstruction and retry-safe behavior.
src/intake/notion-relay-contract.ts (3)

53-64: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Preserve the first channel error for diagnosis.

The three-step joincreatejoin sequence discards the first two errors. Only the innermost join at line 62 propagates. An authentication failure or a permissions failure on the first join therefore surfaces as a second, less informative join error.

Capture the first error and attach it when the final attempt also fails.

♻️ Proposed error preservation
     try {
       await relay.channels.join(channel)
-    } catch {
+    } catch (joinError) {
       try {
         await relay.channels.create({
           name: channel,
           topic: `Read-only Notion contract ${input.pageId}`,
         })
-      } catch {
-        await relay.channels.join(channel)
+      } catch (createError) {
+        try {
+          await relay.channels.join(channel)
+        } catch {
+          throw new Error(
+            `unable to join or create Notion contract channel ${channel}`,
+            { cause: joinError ?? createError },
+          )
+        }
       }
     }
🤖 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/intake/notion-relay-contract.ts` around lines 53 - 64, Update the
join/create retry logic around relay.channels.join and relay.channels.create to
capture the initial join error, then attach or preserve it when the final join
attempt fails. Keep the existing three-step sequence and success behavior
unchanged while ensuring authentication or permission failures from the first
join remain available in the propagated error.

107-121: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low value

Memoize the in-flight registration.

#relay assigns #agentRelay only after agents.register resolves at line 114. Two overlapping publish calls therefore both register, both using the same #publisherName, and one AgentRelay pair is orphaned. dispose deletes the name once, so the orphan is not cleaned up.

The current caller in runNotionIntakeUnlocked awaits each task in sequence, so this cannot happen today. The class is exported from src/intake/index.ts, so an external caller can reach it.

Store the promise instead of the resolved value.

🤖 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/intake/notion-relay-contract.ts` around lines 107 - 121, Update the
`#relay` method to memoize the in-flight initialization promise before awaiting
agents.register, so overlapping calls share one registration and AgentRelay
pair. Store and return that promise while preserving the existing fast path for
an initialized `#agentRelay`; ensure `#workspaceRelay` and `#agentRelay` are assigned
only once after registration completes.

72-88: 🩺 Stability & Availability | 🔵 Trivial

Plan for channel growth across content revisions.

The marker prefix binds pageId and contentDigest. A content change produces entirely new markers, so the previous revision's messages stay in the channel and are never referenced again. Nothing prunes them.

listAllMessages caps traversal at 100 pages of 100 messages. Once a channel accumulates 10,000 messages, line 154 throws and all publication for that sourceKey fails permanently. The error text names the limit but gives the operator no remedy.

Consider deleting messages whose marker prefix does not match the current contentDigest after a successful publish, or document the manual channel cleanup procedure and include it in the thrown error text.

🤖 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/intake/notion-relay-contract.ts` around lines 72 - 88, Add cleanup to the
publication flow around the chunk loop so that, after all current chunks publish
successfully, messages with the same page/source marker prefix but a different
contentDigest are deleted or otherwise removed from channel history. Preserve
current-revision messages and ensure cleanup does not run before successful
publication; if cleanup is intentionally not implemented, update the limit error
in the surrounding publication logic to include actionable manual
channel-cleanup instructions.
src/intake/notion.ts (1)

422-440: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Collapse the duplicated body-edited guard.

Lines 424-429 and lines 434-439 return the same blocked result with the same reason, and both evaluate existing.body !== renderIssueBody(task, summary). The rendering runs up to twice.

The two checks are not redundant in behavior. The first one runs before prepareContractDelivery so that an edited body prevents relay publication, which the test at line 270 asserts. Keep that ordering, but compute the comparison once and extract the blocked result.

♻️ Proposed consolidation
+    const bodyWasEdited = existing.body !== renderIssueBody(task, summary)
+    const editedResult = {
+      ...base,
+      status: 'blocked' as const,
+      issue: existing,
+      reason: 'existing lifecycle issue body was edited; refusing to overwrite it during portable mount migration',
+    }
     if (input.manifest.workerMountTransport.kind === 'relay-channel' &&
-      !receipt.delivery && existing.body !== renderIssueBody(task, summary)) {
-      return { ...base, status: 'blocked', issue: existing, reason: '...' }
-    }
+      !receipt.delivery && bodyWasEdited) return editedResult
     const delivery = await prepareContractDelivery(task, input, receipt.delivery)
     if (delivery && !issueHasContractDelivery(existing.body, delivery)) {
-      if (existing.body !== renderIssueBody(task, summary)) {
-        return { ...base, status: 'blocked', issue: existing, reason: '...' }
-      }
+      if (bodyWasEdited) return editedResult
🤖 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/intake/notion.ts` around lines 422 - 440, In the surrounding intake flow,
compute the existing-body comparison once before the pre-prepareContractDelivery
guard, then reuse that boolean in both checks. Preserve the first guard’s
position before prepareContractDelivery and extract or reuse a single
blocked-result construction so both paths return the same status, issue, and
reason without rendering renderIssueBody more than once.
🤖 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 `@README.md`:
- Line 201: Update the README passage around the workerMountTransport example
and recommendation to state that local is the default whenever the field is
omitted, including in new manifests, and that relay-channel requires explicitly
setting the transport plus a resolvable active Agent Relay workspace key.
Clarify that copying the relay-channel example without resolving the required
workspace key will fail.

In `@src/intake/notion-relay-contract.ts`:
- Around line 44-49: Update the cache lookup and corresponding write path in the
contract publisher to key entries by both sourceKey and contentDigest, ensuring
a repeated sourceKey with a different digest cannot reuse an older delivery.
Preserve the existing digest validation and return behavior for matching key
pairs.
- Around line 100-105: Update RelayChannelNotionContractPublisher.dispose() in
src/intake/notion-relay-contract.ts:100-105 to independently catch failures from
disconnect() and agents.delete(this.#publisherName), ensuring neither rejection
escapes. Also update the notionContracts?.dispose?.() call in
src/cli/fleet.ts:425-427 to independently catch disposal failures so cleanup
cannot change the CLI command result.

In `@src/intake/notion.ts`:
- Around line 665-675: Update prepareContractDelivery to validate the result
returned by input.contracts.publish before writing it into state.receipts.
Reject an empty delivery.messageIds array by throwing a descriptive Error, so
the task is blocked and invalid state is not persisted; leave valid publisher
results unchanged.
- Around line 508-512: Update the already-dispatched workspace path around
prepareContractDelivery and sameContractDelivery so it does not persist a newly
migrated delivery that the running agent was never given. For receipts predating
the transport change, either retain the original delivery without recording the
relay contract or return an explicit blocked/incomplete status instead of
already-dispatched; preserve the existing behavior when the agent already has
the matching delivery.
- Around line 422-449: Update the pre-publication guard in publishRepoTask to
recognize bodies containing a Factory-authored delivery marker as unedited.
Parse the delivery from existing.body and compare it against
renderIssueBody(task, summary, deliveryFromBody(existing.body)), while retaining
the existing edited-body block for genuinely different content and preserving
the delivery update flow.
- Around line 420-421: Update the existing-issue handling around renderIssueBody
to resolve repository visibility only when body rendering is required, avoiding
repositoryVisibility calls for local transport tasks. Before using
target.publicSummary for public repositories, add the same explicit
manifest-value guard used by the create path; preserve the existing summary and
lifecycle behavior when the value is present.

---

Nitpick comments:
In `@src/cli/fleet.ts`:
- Around line 189-195: Update the relay-channel branch around notionContracts so
it first reuses deps.notionContracts when provided, without resolving or
requiring a workspace key. Only resolveRelayWorkspaceKey and throw for a missing
key when constructing the fallback RelayChannelNotionContractPublisher.

In `@src/intake/notion-relay-contract.ts`:
- Around line 53-64: Update the join/create retry logic around
relay.channels.join and relay.channels.create to capture the initial join error,
then attach or preserve it when the final join attempt fails. Keep the existing
three-step sequence and success behavior unchanged while ensuring authentication
or permission failures from the first join remain available in the propagated
error.
- Around line 107-121: Update the `#relay` method to memoize the in-flight
initialization promise before awaiting agents.register, so overlapping calls
share one registration and AgentRelay pair. Store and return that promise while
preserving the existing fast path for an initialized `#agentRelay`; ensure
`#workspaceRelay` and `#agentRelay` are assigned only once after registration
completes.
- Around line 72-88: Add cleanup to the publication flow around the chunk loop
so that, after all current chunks publish successfully, messages with the same
page/source marker prefix but a different contentDigest are deleted or otherwise
removed from channel history. Preserve current-revision messages and ensure
cleanup does not run before successful publication; if cleanup is intentionally
not implemented, update the limit error in the surrounding publication logic to
include actionable manual channel-cleanup instructions.

In `@src/intake/notion.test.ts`:
- Line 443: Add a test for loadNotionIntakeManifest that parses manifest JSON
without workerMountTransport and asserts the resolved field equals { kind:
'local' }. Keep existing explicit-field fixtures unchanged and ensure the test
exercises the schema default rather than constructing a NotionIntakeManifest
directly.
- Around line 230-239: Extend the migration-path test around runNotionIntake to
read the persisted receipt from manifest.statePath after dispatching, then
assert that its delivery matches the expected migrated delivery data, following
the existing create-path persistence assertion near lines 198-204. Keep the
current GitHub update assertions unchanged.
- Around line 176-183: Add unit tests for RelayChannelNotionContractPublisher
using a fake AgentRelay, covering digest/content mismatch before network calls,
retry reuse of message IDs for identical content, rejection of marker-matched
messages with different text, ordered chunking beyond 6,000 base64 characters,
and listAllMessages stopping when a page contains fewer than 100 messages. Keep
the tests focused on cross-node reconstruction and retry-safe behavior.

In `@src/intake/notion.ts`:
- Around line 422-440: In the surrounding intake flow, compute the existing-body
comparison once before the pre-prepareContractDelivery guard, then reuse that
boolean in both checks. Preserve the first guard’s position before
prepareContractDelivery and extract or reuse a single blocked-result
construction so both paths return the same status, issue, and reason without
rendering renderIssueBody more than once.
🪄 Autofix

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: CHILL

Plan: Pro Plus

Run ID: 589b6893-b3a7-45d5-b0bc-2fd6d2bfb34b

📥 Commits

Reviewing files that changed from the base of the PR and between 4a37644 and 81500b6.

📒 Files selected for processing (6)
  • README.md
  • src/cli/fleet.ts
  • src/intake/index.ts
  • src/intake/notion-relay-contract.ts
  • src/intake/notion.test.ts
  • src/intake/notion.ts

Comment thread README.md
Comment thread src/intake/notion-relay-contract.ts
Comment thread src/intake/notion-relay-contract.ts
Comment thread src/intake/notion.ts
Comment thread src/intake/notion.ts Outdated
Comment thread src/intake/notion.ts Outdated
Comment thread src/intake/notion.ts Outdated

@cubic-dev-ai cubic-dev-ai 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.

Review completed against the latest diff

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread src/cli/fleet.ts Outdated
Comment thread src/intake/notion-relay-contract.ts Outdated
Comment thread src/cli/fleet.ts Outdated
Comment thread src/intake/notion-relay-contract.ts

@cubic-dev-ai cubic-dev-ai 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.

All reported issues were addressed across 4 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread src/intake/notion.ts
Comment thread src/intake/notion.test.ts

@cubic-dev-ai cubic-dev-ai 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.

All reported issues were addressed across 7 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread src/intake/notion-relay-contract.ts
Comment thread src/intake/notion.ts Outdated
@khaliqgant
khaliqgant merged commit 16ad97e into main Aug 6, 2026
7 checks passed
@khaliqgant
khaliqgant deleted the codex/notion-portable-fleet-mount-20260806 branch August 6, 2026 01:24
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