DUNIN7 · LOOMWORKS · RECORD
record.dunin7.com
Status Current
Path investigations/loomworks-engine-api-boundary-inspection-findings-v0_1.html

Loomworks Engine — API boundary inspection findings

Version. 0.1
Date. 2026-06-07
Status. First consolidated record of two read-only Engine inspections. Findings only; no code changed.
Inspection anchor. loomworks-engine, branch main, HEAD 5472335 (547233503bc4d1229a64811920fa173a77d1d0a6), working tree clean.
Render-type. Standing note / infrastructure finding. Operator-facing.

Plain-language summary

The question driving both inspections: is the managed API the only way to write authoritative Engine state? This matters because the architecture is moving toward Companions — and potentially fully agentic Companions — being freely constructed against the API. If the API is the only path in, the boundary can be trusted no matter what gets built on the far side. If there are other paths, the boundary is only as strong as its weakest bypass.

The answer is: not yet, but the gap is small and enumerated. The Companion-facing write surface re-applies its authorization correctly almost everywhere, the most dangerous writes are not reachable through a Companion at all, and agent actors are rejected at the commit core. What remains is a short, closeable list: two unauthenticated write routes, one credit-admin tier with no privilege check, and one authorization asymmetry on engagement finalization. Separately, a large privileged write surface (operator scripts, database migrations, background loops) exists by design and should be named as a deliberate operator/system plane inside the boundary, not mistaken for a hole in it.

Two of the findings compose into a chain that sets the fix order: an unauthenticated route can plant a membership on a candidate engagement, and the under-gated finalize path lets a planted member finalize it. Closing the unauthenticated route removes the first step and de-fangs the second before it is even tightened.

The boundary, as drawn

The Engine sits inside the managed API. The API is the wall. Everything outside it — Companions (1..N), Agents (1..N), human drivers — reaches the Engine only by crossing that wall. The bound does not live in the Companion and does not live in the driver; it lives at the API. The Engine knows only the authenticated UUID, its authorized reach, and the nature of the action requested. It does not — and structurally cannot — know what kind of caller built the request.

This is the posture the open-Companion direction requires: the API gives away nothing on trust about its caller, because the caller is unknown by construction.

Verdict

Is the managed API the sole path to authoritative Engine state writes? — No.

It is not the sole path today, for three reasons of decreasing concern.

  1. Two network-reachable write routes require no authentication, and a tier of credit-admin routes authenticate without checking privilege.
  2. In-process, the API is not the only writer — background loops, hooks, and boot bootstraps write as a system actor without passing per-request authorization. These are by design.
  3. Out-of-band, the operator toolchain (scripts) and database migrations write every state class with full database authority and no API authorization.

Reasons 2 and 3 are the privileged operator/system plane and are correct by design; they should be accepted and named, not closed. Reason 1 contains genuine breaches of the boundary and should be closed.

For the surface a freely-constructed Companion actually calls — the engagement-scoped read/write/commit routes — the boundary is largely sound and defends commit authority twice (HTTP dependency plus a data-layer rejection of kind="agent"). The exceptions are enumerated below.

Findings, categorized

The findings fall into three categories. They are not the same kind of problem and do not get the same response.

Category A — Boundary breaches · close

Network-reachable paths that write authoritative state without the authorization the boundary should require. These are gaps in the wall.

A1. POST /admin/mint-migration-passkey-token — unauthenticated, unconditionally mounted

Writes authoritative state with no authentication. Enables account takeover. The most serious single finding.

A2. POST /engagements/{id}/initial-contributors — unauthenticated, gated only by candidate state

Establishes membership on a candidate engagement with no caller authentication. Significant in its own right, and load-bearing in the compose-chain below.

A3. /admin/* credit tier — authenticated, no privilege check

Any logged-in person can grant or provision credits. The boundary confirms the caller is someone but not that they are allowed. Credit is authoritative state (the first infrastructure engagement), so this is a privilege-escalation path open to every account.

Category B — Companion-seam asymmetry · tighten

The /operator/converse path is the surface a Companion drives through. A per-write audit traced every authoritative write reachable through converse to its service function and compared it gate-for-gate against the equivalent direct endpoint.

Result: every converse write re-applies its equivalent endpoint's authorization except one. Two converse writes are in fact stronger than their direct equivalents (request_draft / request_revision require a committed delegation grant on top of membership). The heaviest writes — committing an assertion, granting a designation, minting a credential, altering organization or step-up policy — are not reachable through converse at all; the Companion brain has no intent that performs them.

B1. finalize_project is under-gated

It calls commit_engagement, which itself enforces three things on both paths: it rejects actor.kind == "agent", it requires the fail-closed step-up presence proof, and it requires seed convergence. There is no step-up bypass and no agent commit.

What converse drops, relative to the direct /instantiate route, are two HTTP-layer checks:

  • get_committing_contributor — requires a human actor with commit_authority = True. Converse checks only active membership (any designation).
  • assert_engagement_creator — requires the caller be the candidate's creator. Converse never calls it.

Precise exposure: a present, authenticated, step-up-satisfied member of a candidate engagement can finalize it through their Companion even if they are neither its creator nor a commit-authorized designee — both of which the browser /instantiate route requires.

Bounded by what survives: the committer must still be an authenticated person, a member of the engagement, and must satisfy the fail-closed step-up presence proof. It is not an unauthenticated commit, and it is not an agent commit. The drop is specifically the creator-identity and commit-authority/designation checks.

Category C — Privileged operator/system plane · accept & name

A large write surface reaches every state class — identity, credentials, ACL and memberships, the credit ledger and config, Memory, and the step-up authority structure — with full database authority and no API authorization:

  • Operator toolchain (scripts) and Alembic migrations, writing against the production database with full authority.
  • ~10 background loops/hooks and 4 boot bootstraps that write as a system actor without per-request authorization — including one that autonomously deletes accounts and one that credits a third party on referral. These originate from authenticated or scheduled flows but do not pass the request-authorization layer.

This is correct by design. A migration that cannot write freely is not a migration. These are not callers crossing the wall; they are the plane the wall is built on, and they sit inside the boundary. The action here is not to fix but to name the plane explicitly — to record that an operator/system plane with full authority exists, that it is inside the boundary and not part of the Companion-facing surface, and that no freely-constructed Companion runs on it. The danger is not that the plane exists; it is that it exists unnamed, where a later builder might mistake it for the API boundary or expose part of it to a caller.

The compose-chain (sets the fix order)

A2 and B1 compose. The unauthenticated initial-contributors route (A2) can establish a membership on a candidate engagement. The under-gated finalize_project (B1) then lets that planted member finalize it. Chained, an unauthenticated caller could plant a membership and finalize another person's candidate engagement.

This tells the fix order: closing A2 removes the membership-planting step, which de-fangs B1 before B1 is itself tightened. Close the unauthenticated routes first; tighten finalize second.

What survives, and why the open-Companion direction stands

The findings are a short and closeable list, not a structural problem. The reasons the boundary is in good shape where it counts:

The boundary holds at the seam where the Companion touches it. What is left is one asymmetry and two edge breaches.

Recommended next actions

Recommendations for Operator decision, not committed work.

  1. One Change Request covering the Category A breaches and the Category B gap, in compose-chain order:
    1. Close POST /admin/mint-migration-passkey-token (A1) and POST /engagements/{id}/initial-contributors (A2).
    2. Add a privilege check to the /admin/* credit tier (A3).
    3. Re-apply get_committing_contributor and assert_engagement_creator in _route_finalize_project so converse finalize matches /instantiate (B1).
  2. One standing note naming the privileged operator/system plane (Category C) as deliberately inside the boundary and outside the Companion-facing surface. This converts the largest non-API write surface from an open finding into a documented design decision.
  3. Verify before fixing whether A1 and A2 are known dev scaffolding the Operator already intended to remove, versus live exposures. The inspection reports them as present and unauthenticated; their intended status is an Operator fact, not a code fact.

Method note

Both inspections were read-only against main @ 5472335, clean tree, no code changed. The first pass enumerated the route surface and the non-API write surface. The second pass traced every /operator/converse write to its service function and compared authorization gate-for-gate against the equivalent direct endpoint.

Two places where a signature-only reading would mislead were corrected by direct source tracing: membership-ACL gating is enforced in-body rather than as a route-signature dependency (present, not missing); and the converse seam helpers re-run assert_engagement_creator in-process (converse.py:219/297/390) rather than in the dispatch router. The _check=None "auth-skip back door" was confirmed already closed (converse.py:196-197). The finalize_project gap is therefore a genuine asymmetry, not an unread seam: _route_finalize_project (router.py:1023-1138) calls verify_project_membership and commit_engagement directly with no creator or commit-authority check between them.