DUNIN7 · LOOMWORKS · RECORD
record.dunin7.com
Status Current
Path investigations/loomworks-engine-api-parity-audit-v0_1.md

Loomworks — Engine API parity audit (boundary enforcement, Increment 0)

Version. 0.1 Date. 2026-06-03 Provenance. Engine-source audit, Operator: Marvin Percival. Increment 0 of the engine boundary-enforcement project (M2 / C0 in the master build plan). Status. Investigation / parity audit — report only. NO code, NO API design, NO commits. This commits to nothing; it establishes what the API must expose at parity before any later increment moves code. Cross-links.

Code citations. engine: = loomworks-engine repo at time of writing. Line numbers indicative; names load-bearing. The privileged delegations and the commit_engagement/WebAuthn finding are source-verified directly; the broad orchestration-router call inventory (§1c) is from a thorough sweep and should be spot-verified before the API contract is finalized.


North star (the endpoint this audit serves)

The boundary project ends with the Companion's brain refactored to consume the engine through the API as a normal wrapper — not co-resident, no privileged in-process shortcuts. That refactor is the endpoint, not optional (Operator direction, 2026-06-03). Therefore: **every in-process privilege inventoried below is something the refactored Companion will instead do through the API.** This audit is the parity checklist for that refactor — the API must expose, with equivalent capability and no insider shortcut, everything the brain reaches in-process today. Where it can't yet, that is a named hole the later increments must fill.


1. Parity audit — what the brain reaches in-process

"The brain" = the orchestration layer at engine: src/loomworks/orchestration/ (the /operator/* HTTP surface + its router.py / prompt.py / helper modules). It is co-resident in the engine process and reaches engine capabilities by direct Python calls, not via the engine's own HTTP API.

1a. Privileged delegations — calling engine ROUTE HANDLERS directly, with bypass

These call functions that are themselves engine HTTP route handlers, but reach them in-process with auth/billing/transaction privileges an external HTTP client could not replicate.

| Brain call site | Engine handler (its HTTP route) | Privilege used that a client can't replicate | Parity gap (what the API must offer) | |---|---|---|---| | converse.py:185 _call_phase31_converseconverse_route(_check=None, _internal_delegation=True) | converse_route = POST /engagements/{id}/seed/converse | auth skip (_check=None bypasses assert_engagement_creator) + billing/usage skip (_internal_delegation=True skips re-opening the usage buffer and firing the consumption hook, so a multi-step turn bills once in aggregate) + shared session | acting-as-person auth; a composite/aggregated billing model a client can drive; (transaction — see §2 cross-cutting) | | converse.py:232 _call_seed_commit_from_briefcommit_seed_from_brief(_check=None) | commit_seed_from_brief = POST /engagements/{id}/seed/converse/commit | auth skip (_check=None) + shared app.state runner (runner resolved from request.app.state / dependency_overrides) + in-process-built SeedInductionAgent | auth; a way for a client to drive induction without reaching into app.state | | converse.py:302 _call_extract_seed_from_discoveryextract_seed_from_discovery(_=None) | extract_seed_from_discovery = POST /engagements/{id}/seed/extract | auth skip (_=None skips the redundant assert_engagement_creator) + shared runner/agent | auth | | converse.py:371 _call_create_engagement_from_conversationcreate_engagement_from_conversation(...) | create_engagement_from_conversation = POST /me/engagements/create-from-conversation | shared session + runner via dependency_overrides + person object passed directly (no token) | auth; runner provisioning for a client | | router.py:971 _route_create_projectdraft_engagement(...) | draft_engagement = POST /engagements | person object passed directly + shared session (no HTTP auth) | acting-as auth | | inbox.py:32list_needs_you_route(...); dashboard.py:18list_active_route / list_needs_you_route / list_recent_route | dashboard routes = GET /me/dashboard/{active,needs_you,recent} | shared session + person (no HTTP auth) | acting-as auth (capability already routed; the gap is the auth context) |

1b. The sharpest privilege — finalize_project bypasses the WebAuthn commit ceremony

router.py:1020 _route_finalize_project imports and calls commit_engagement directly (engine: engagement/creation.py).

(Same pattern, lower stakes: me_create_engagement.py:723 also calls commit_engagement directly inside the create-from-conversation endpoint — but that endpoint is at least HTTP-reachable; the finalize_project route reaches the core function with no ceremony at all.)

1c. Core functions reached in-process with NO HTTP route (or a route that's bypassed)

The brain also reaches many engine core functions that are not HTTP route handlers — reachable only in-process. (Inventory from a thorough orchestration sweep; classifications to spot-verify before the contract is finalized.) Grouped by what an external client would need:

| Engine capability (core fn) | Reached from | Route today? | Parity gap | |---|---|---|---| | commit_engagement | router.py:1028, me_create_engagement.py:723 | only via /instantiate (WebAuthn) — bypassed (§1b) | a client-reachable commit path + the WebAuthn decision | | _load_candidate_seed | router.py:1027, others | no route | a candidate-seed read route | | _current_manifestation | prompt.py:42 (context assembly) | no route (Manifestation read) | a manifestation read route the prompt-builder wrapper can call | | get_current_seed | prompt.py:43 | ~ GET /engagements/{id}/seed (seed_view) exists | likely covered — verify the payload matches what prompt assembly needs | | list_assertions | prompt.py:41, router.py (ask_about_past_input) | assertions router exists (GET) | likely covered — verify | | add_assertion / commit_assertion / retract_assertion / revise_assertion | router.py (add_knowledge, remember_about_me, forget_about_me), inbox.py | contribution/assertion routes exist for some | partial — verify each verb has a route a client can call | | _retire_render, decide_composition, open_shape_confirmation_consideration, close_shape_confirmation, get_shape_event | inbox.py (the /operator/inbox/{id}/respond action) | no / partial routes — the inbox respond endpoint calls engine core directly | routes for the inbox actions, or the inbox stays engine-side and the brain calls it as a client of /operator/* | | notification service fns (list_notifications, mark_seen, mark_dismissed, create_approval_card, process_approval, process_decline, …) | notifications.py | to-verify (notifications routes may exist) | verify the full set is client-reachable | | delegation fns (verify_companion_authorization, execute_pre_authorized, list_delegations, revoke_delegation) | router.py (request_draft, remember/forget_about_me) | to-verify | verify routes exist for the delegation operations | | open_composition | composition.py | = POST /engagements/{id}/compositions (engine route exists) | covered — auth-context gap only | | context-tier loaders, determine_context_tier, personal-memory SQL (prompt.py) | prompt.py | no route (direct SQL on current_memory_objects) | read routes for the context the prompt assembler needs |

1d. Cross-cutting privileges (not per-call; they apply to everything above)


2. API contract — current state (described, not designed)

What the engine HTTP API actually exposes today, focused on the surface a wrapper needs. No new endpoints designed here — this describes what exists and names the holes.

Shape. One FastAPI app (engine: api/app.py, title="Loomworks", versioned by package version — no /v1, no governed contract), ~50 routers / ~197 routes mounted flat (boundary inventory §1). Auth is per-route via FastAPI deps (get_current_person, assert_engagement_creator, require_operator_designation). The OL frontend already consumes this surface as a remote HTTP client.

Route families a wrapper would need, and their parity status:

| Capability family | Routes that exist | Parity status for a client brain | |---|---|---| | Engagement draft / candidate | POST /engagements, POST /engagements/{id}/seed (amend), POST /engagements/{id}/seed/induct, GET /engagements/{id}/seed, GET /engagements/{id}/seed/findings | mostly complete — but the brain reaches draft_engagement in-process and reads candidate seed via _load_candidate_seed (no read route for the candidate); auth-context gap | | Conversational creation | POST /engagements/{id}/seed/converse (+ /conversation, /converse/ready, /converse/transcribe, /converse/key-provided), POST /engagements/{id}/seed/converse/commit, POST /engagements/{id}/seed/extract, POST /me/engagements/create-from-conversation | routes exist — but all reached in-process with auth/billing bypass (§1a); the capabilities are routed, the parity is not (auth, billing, transaction) | | Commit / instantiate | POST /engagements/{id}/instantiate (+ /instantiate/divergent, /instantiate/challenge) — WebAuthn-gated | route exists but BYPASSEDfinalize_project calls commit_engagement core directly, skipping WebAuthn (§1b). The hole is not a missing route; it's the insider bypass of the route's ceremony | | Dashboard / inbox | GET /me/dashboard/{active,needs_you,recent} exist; inbox respond actions (retire render / decide composition / shape confirm) have no/partial engine routes | partial — dashboard routed; the inbox-respond engine actions are reached as core functions | | Memory / context for prompt assembly | GET /engagements/{id}/seed exists; assertions GET exists; Manifestation read has no route; personal-memory read is direct SQL | hole — the context the brain assembles (_current_manifestation, tier loaders, personal-memory SQL) has no read API | | Notifications / delegation | to-verify (some routes likely exist) | verify — confirm the full notification + delegation operation set is client-reachable | | Shapes / renders / compositions | POST /engagements/{id}/compositions exists; render/shape views exist; _retire_render core | partial — composition creation routed; retire/shape-confirm actions reached as core |

The holes, summarized:

  1. No acting-as auth — the universal precondition; without it no route is callable "as the person" by a service brain.
  2. commit_engagement reachable only via WebAuthn /instantiate, but bypassed in-process — the parity question is whether a client commits via WebAuthn or a specified non-ceremony path (security decision).
  3. No read routes for prompt-assembly context_current_manifestation, candidate-seed read, context-tier loaders, personal-memory (direct SQL).
  4. Inbox-respond engine actions (_retire_render, decide_composition, shape-confirmation) reached as core functions — no client route, or the inbox stays engine-side.
  5. No composite/transactional endpoints for the multi-step flows the brain does atomically in one session.
  6. No composite billing model to replace _internal_delegation.
  7. No client-side induction-runner provisioning (today via app.state / dependency_overrides).
  8. No versioned, governed contract (/v1, completeness guarantee).

3. What this means for the refactor (per the north star)

Every row in §1 is work the refactored Companion will do through the API. The §1d cross-cutting privileges + the §2 holes are therefore the parity preconditions for the brain-to-client refactor: until acting-as auth (hole 1), the commit-path decision (hole 2), the context read routes (hole 3), the inbox-action routes (hole 4), composite/transaction semantics (holes 5/7), and a billing model (hole 6) exist, the brain cannot become a pure client without losing capability or smuggling privilege. The audit makes that list explicit so the later increments fill it deliberately, and so "the Companion is now a client" can be checked against a concrete parity list rather than asserted.

This is Increment 0: it names the surface and the holes. It designs nothing and commits to nothing.


Investigation / parity audit only. No engine or wrapper code changed; no API designed; nothing committed. Filed in loomworks-record/investigations/. Increment 0 of planning/loomworks-engine-boundary-enforcement-plan-v0_1.md. Pairs with investigations/loomworks-engine-boundary-inventory-v0_1.md and standing-notes/loomworks-standing-note-engine-wrapper-boundary-v0_1.md (the lens). §1c classifications are from a thorough sweep and warrant spot-verification before the API contract is finalized.