Cyclotron

Editorial intelligence for publications.

Embedded execution authorization

Cyclotron exposes a per-call ownership boundary for trusted host authorization. This is independent of cloud storage selection. Native storage and existing local call signatures remain compatible; the SDK does not supply identity, membership or publication grants.

Public contract

from decision_flywheel import ExecutionGuard

async def guard() -> None:
    # Host-owned functions freshly verify the session/account/person and the
    # explicit publication capability and current binding, pinned to this call.
    await reauthorize_pinned_account_and_publication()

await engine.decide(item, execution_guard=guard)
await engine.review(decision_id, label, execution_guard=guard)
await engine.undo_review(decision_id, execution_guard=guard)
await engine.learn(limit=1, execution_guard=guard)
await engine.replay(records, execution_guard=guard)

# Synchronous engine reads/steering, and host-owned provenance operations:
async with engine.execution(execution_guard=guard):
    snapshot = engine.status()
    page = engine.subscribe(after=cursor)

ExecutionGuard is Callable[[], None | Awaitable[None]]. The callback is optional for existing trusted local callers. A hosted boundary must require and supply it for protected operations. It is never derived from a browser callback, boolean header, account-role assertion or serialized command. Capture the trusted request's expected account/person/publication/capability/binding in its closure; fresh resolution must match those pins, not silently switch authority.

The SDK first acquires its existing execution lock, then invokes the guard and awaits it if needed, then begins the operation. This occurs before reading native state, resetting batch bookkeeping, dispatching provider requests or committing labels. The callback must return None to succeed. Non-callable guards and non-None results raise TypeError; denial, authorization outage and cancellation propagate unchanged. The callback is a local call argument and is not stored on the engine, in a context variable, in native state or in a global setting.

learn invokes the guard for every separately owned pass, before even reading its next queue entry. replay forwards it to every separately owned decision and review. Authorization from an earlier request or learning pass is not reused. Successful earlier operations remain committed if a subsequent guard denies; this interface supplies no batch rollback, provider cancellation, or distributed transaction across central authorization and engine stores.

Host obligations and scope

Fresh central console:read/console:write authorization alone does not confer publication capabilities. The trusted host guard must also resolve explicit publication grants and current binding revision for the pinned account/person. Session expiry/revocation and authorization outages must fail closed. A central membership revision is evidence from that check, not a reusable authorization lease. Revocation after an operation has begun is not cancellation of an already dispatched external request.

Publication-host state reads performed before a native decide/review call are not retroactively protected by that method's guard. Move protected pre-dispatch validation into its guard closure after fresh authorization, or use a separately guarded read scope. Host provenance writes after a native call require their own guarded ownership scope. If a later guard denies, the earlier committed decision may need host reconciliation; do not invent a successful provenance receipt.

The execution lock is non-reentrant. Do not call decide, review, undo_review, learn, replay or another execution scope from inside execution, or from a guard. Pass the callback keyword to lock-owning async operations instead. No private lock access or replacement persistence adapter is needed by consumers. Synchronous engine methods remain usable by trusted local callers and do not automatically authorize themselves; hosted reads must use the guarded scope.

The current owner is the native per-open-engine lock plus the existing writer lease. This hook does not establish a cloud lease/fence, durable queue or cloud storage authority. A future execution backend must preserve the same ordering: acquire actual ownership, run the trusted fresh guard, then access protected state or dispatch. No cloud activation follows from this API.

Offline verification

embedded_execution_test.py covers queued revocation, authorization outages, callback cancellation, cancellation while waiting for ownership, independent sync/async callbacks, rejected boolean guards, replay rechecks and per-pass learning reauthorization. A SQLite authorizer on every native engine/shared/wheel connection rejects even a SELECT in denied executions, proving ordering before reads as well as mutations. Separate cases use the real AccountsClient with an injected synthetic transport, then revoke membership, explicit publication grant, binding revision, selected account or person while waiting for the lock. No real credentials, provider calls, cloud resources or email are used.

Validation: 113 focused native execution/embedded/account tests passed. The read-only cross-owner publication checkout also passed 14 contract tests against this engine source. No full build or full regression was run for this small execution-boundary change while the Accounts build is active.

Deferred learning with a guard retains the execution lock during asynchronous optimizer calls. Unguarded local learning can lend that lock using the existing learning-window protocol. Guarded calls use conservative concurrency so a reacquisition cannot run cancellation/event cleanup after a failed authorization check. Every separately owned pass still invokes its per-call guard first.