Skip to content

Support creating new Google Docs via createExternalResource - #428

Draft
ndisidore wants to merge 3 commits into
nathan/create-external-resourcefrom
nathan/create-external-resource-google
Draft

Support creating new Google Docs via createExternalResource#428
ndisidore wants to merge 3 commits into
nathan/create-external-resourcefrom
nathan/create-external-resource-google

Conversation

@ndisidore

Copy link
Copy Markdown
Member

Google Docs is the first creatable resource. A doc title isn't globally contended, so this proves the kernel API without the approval-time rename that github repo names will need. Also supports a common use case, i.e. a scheduled task minting a doc each run, whose queued appends would otherwise wait on a human click every time

A created doc gets a provisional-<uuid> id and resolves to the real id when the creation applies, via the kit's ProvisionalIds (cherry-picked at its own paths so nathan/gatekeeper-kit rebases cleanly). Before that, the binding simulates over an empty document and makes no provider calls. The existing in-order rule applies the creation before any queued edit. Rejecting the creation invalidates every queued edit and makes session methods fail with an explanation of what happened. No new OAuth scopes; the doc grant already carries write access.

Creation is auto-approvable under its own opt-in rule, separate from edits.

Takes src/simulation.ts (ProvisionalIds, createSimulationView,
replaySimulation), its kv.ts dependency, and their tests from
nathan/gatekeeper-kit verbatim, at the same paths, so that branch rebases
onto this one with no churn. The package.json is trimmed to the one
./simulation export; google-gatekeeper takes the workspace dependency here
so the lockfile stays consistent at every commit.
GOOGLE_DOC_RESOURCE is the first creatable type. createResource() checks the
account holds the doc grant (documents.create needs the write scope that
grant already carries -- no new scopes), mints a provisional-<uuid> document
id, and returns a GoogleDocGatekeeperImpl imbued with creation props.

The facet queues a createDocument action as pending action #1, so the
existing in-order approval rule applies the creation before any queued edit.
Until then the binding simulates over a synthetic empty snapshot with zero
provider traffic (describe(), getMetadata(), and getContent() all answer
locally); sourceMap/bodyEndIndex are safe to fake because materialization
only runs at apply time, when the document exists. Apply calls
documents.create and late-binds provisional-to-real via the kit's
ProvisionalIds; edit actions resolve the real id before touching the API.
Rejecting the creation invalidates every queued edit and marks the binding
dead, so session methods explain instead of simulating against nothing.

A crash between documents.create and the binding write can leak one
duplicate document on a retried approval (the API has no idempotency key and
the edit write-marker protocol cannot cover creation); accepted for now.

The workerd docs suite covers simulation-without-traffic, create-then-edit
ordering, retried-approval idempotency, and the rejection cascade.
Document creation keeps its own action kind, separate from the edits one, so
enabling hands-free creation is a distinct choice -- the case that wants it
is a scheduled task minting a new doc each run, whose queued edits would
otherwise stall in-order behind a creation card every time. Nothing is
auto-applied without the user enabling the createDocument rule.
@github-actions github-actions Bot added the gatekeeper Changes to a gatekeeper integration label Sep 2, 2026
@ask-bonk

ask-bonk Bot commented Sep 2, 2026

Copy link
Copy Markdown
  • High packages/gatekeeper-google/src/google.ts:1811: Pending observers are not tracked or rechecked after creation, allowing unauthorized access to the real document.
  • High packages/gatekeeper-google/src/google.ts:1675: Removing the action immediately makes a lost apply response unrecoverable; retries throw “Unknown pending” and the approval remains stuck.
  • Medium packages/gatekeeper-google/src/google.ts:822: The provisional URL remains in creationSpec, so suggested blueprint bindings recreate a permanently unresolved document.
  • Medium packages/gatekeeper-google/src/google.ts:1584: Auto-approval rules are gatekeeper-ID scoped. Each creation gets a new ID, so opting in cannot auto-approve future scheduled creations.
  • Medium packages/gatekeeper-kit/vitest.config.ts:1: No Vite+ test task is defined, so root pnpm test skips the new package’s tests.

github run

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gatekeeper Changes to a gatekeeper integration

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant