DUNIN7 · LOOMWORKS · RECORD
record.dunin7.com
Status Current
Path scoping-notes/loomworks-pipeline-spend-credit-gate-scoping-note-v0_3.md

Pipeline-Spend Credit Gate — Scoping Note — version 0.3

Version. 0.3 Date. 2026-05-30 Status. Scoping note. The scoping-note-before-Change-Request artifact for the pipeline-spend credit gate — step two of the Memory-completion path. Version 0.3 corrects §3.2's hard-floor wording against a code inspection that grounded the actual balance trigger: the floor is the person/spender side only (the institutional reservoir party is negative by design and cannot take a zero-floor), enforced by a BEFORE INSERT trigger (the existing trigger is AFTER INSERT and cannot veto a row). Version 0.2 resolved the Operator decisions (funded reservoir build-with; hard floor; refill auto-fire inside the authorized regime; split person/agent authorization; FIFO lots; Operator-authority provisioning). All decisions remain closed; the Change Request is drafted (CR-2026-095, Phase 64). Supersedes v0.2, preserved alongside. Author. Claude.ai. Operator: Marvin Percival. Baseline (verified this session). Engine main at daee809, alembic head 0074 (source identification merged; CR-2026-094). Operator Layer main at 1ce2542. Record main at 05da29a (constraints note v0.2 and the opening handoff filed this session). Source of baseline: Claude Code re-verification 2026-05-30, corroborated by manifest v0.44 changelog and constraints note v0.2 header — all three agree. Orientation read. Constraints note v0.2 (§0 governs), candidate seed v0.9, current-status manifest v0.44.


Plain-language summary

What this document does. It scopes the build that makes running the three model-rooms cost prepaid credits and refuses spend that is not backed — the credit gate. It fixes the build's shape: the five pieces and their order, the funded reservoir (now built with this work, not deferred), the hard floor that makes zero structurally impassable, the refill mechanism, the authorization model that licenses spend, and the grant-linkage structure that makes every spend traceable to its funding.

What changed from v0.1. v0.1 surfaced two decisions and recommended deferring the funded reservoir and refusing agent spend. The Operator overrode both toward the harder, more correct path:

What Operator decision is needed. None remaining. All decisions are closed (see §6, now a resolution record rather than an open-decision list). The next step is the Change Request.

What is in / out of scope. In: the room-side metering surface (five pieces); the funded reservoir with hard floor, refill threshold, and provisioning action; the split authorization model; lot-based grant→consumption→provisioning lineage; FORAY-attestable-complete flows. Out: the credit purchase/sale mechanism (cost-plus pricing — the ledger is shaped for it, the purchase flow is not built); FORAY anchoring itself (seam-marked, not wired); provider-anchored provisioning (this build uses Operator-authority provisioning; provider verification is a later hardening); the stale model-tier asset map (separate follow-up).


1. Governing principle carried in (from constraints note §0)

This is a prepaid, hard-gated solvency control, not a metering feature. Prepaid-API / highway-toll model: positive balance debited per use, service refused at zero, the arm stays down until value is confirmed. Getting it wrong is a real deficit risk to DUNIN7 — unbacked consumption means DUNIN7 fronts model-provider cost without reciprocal prepaid value, and does not find out until reconciliation runs after the tokens are spent.

The invariant governs every decision below: no person spends against the reservoir without a pre-spend positive-balance gate; no credit is issued without a funded reservoir backing it; the gate is primary and pre-spend, reconciliation is corrective only.

v0.2 makes both clauses of the invariant true in this build. v0.1 made only the first clause true (the person-side gate) and deferred the second (the funded reservoir). The Operator's build-with decision closed that gap.

The hard precondition stays in view: the pipeline is not opened to other Operators until this gate is real. Every decision below is measured against whether it makes the invariant true, not against build convenience.


2. The mandatory first-action result (unchanged from v0.1)

Verification run (read-only, this session): is person_id threaded into the Shaping and Rendering async jobs, reaching the running job where a debit occurs?

Result: PRESENT for both rooms. Source: Claude Code trace at daee809. The identity threads as triggered_by: ActorRef end-to-end:

Caveat 1 — it arrives as an ActorRef, not a bare person_id. The debit code keys on triggered_by.id and asserts the contributor.id == person.id equivalence at the seam (does not assume it) — a loud failure instead of a silent one.

Caveat 2 — agent-initiated jobs carry an agent identity, not a person. v0.1 treated this as a blocker ("no one to debit"). v0.2 resolves it (§6, Decision 2): the agent isn't the payer — the authorized engagement reservoir is the payer, and the agent is recorded as the actor. The "no person to debit" framing was the wrong frame; payer and actor are different roles.

Net effect on piece 3: key the async-room debit on triggered_by.id, asserting the person-equivalence for person spend; for agent spend, debit the engagement reservoir under the agent-spend authorization, recording the agent as actor (§6).


3. The funded reservoir — built with this work

This section is new in v0.2. v0.1 deferred the funded reservoir; the Operator chose build-with. Here is what that means concretely — the resolution to "how does it actually work," not "add a cap later."

The reservoir today is an unbounded mirror: the balance trigger UPSERTs both sides of every flow, so the institutional dunin7 party's balance just goes more negative with each grant. There is no funding cap, no check that the reservoir "has" credits to issue. The gate watches only the person's balance, never the from-party. That is the hole the second invariant clause names.

The funded reservoir closes it with four mechanisms:

3.1 Provisioning events — the reservoir gains a real balance

A third flow type joins grants (issuance to a person) and consumption (spend by a person): a provisioning event that credits the institutional party from a real-world backing. DUNIN7 provisions capacity → a provisioning flow raises the reservoir's fundable balance. The reservoir's accountable balance becomes "provisioned minus allocated," floored at provisioned capacity — a grant cannot allocate more than has been provisioned. (Note this is a floor at provisioned capacity, not a zero-floor on the institutional party's mirror balance, which is negative by design — see §3.2.)

Provisioning mechanism (this build): Operator-authority action (option i). The Operator records "DUNIN7 has provisioned N credits at tier T" as an Operator-authority action — backed by the Operator's judgment of capacity committed. This is the minimal mechanism that stands up a real reservoir balance for auto-refill to draw on. It honours Operator-authority and does not scope provider integration. Provider-anchored provisioning (option ii) — tying the provisioning event to a verified provider-side purchase — is named as a later hardening, out of this scope.

The consequence, stated plainly because it is the bite of build-with: once the reservoir is floored, you cannot grant credits you have not provisioned. A provisioning action must exist in this build, or the reservoir starts empty and every grant fails the floor check. v0.1's defer path avoided this by leaving issuance unchecked; build-with takes it on.

3.2 Hard floor — zero is a ledger invariant on the person side

The Operator's requirement: it must not be possible to go negative. This is stronger than a pre-spend check. A check is a guard, and guards fail to races, missed call sites, and the redundant-transaction-wrapper bug class that bit the upload pathway (manifest's "test suite green does not mean production works").

The floor is enforced at the ledger, not as an application check — but it is not a single both-sides rule, and v0.2 was wrong to imply it was. A code inspection (2026-05-30) grounded the actual balance trigger and corrected this:

Two mechanism facts from the inspection that the build must honour:

  1. The existing balance trigger (update_balance_on_flow, migration 0062, unchanged) is AFTER INSERT — it fires after the row exists and cannot veto a row. The person-side hard floor therefore goes on a separate BEFORE INSERT trigger that can RAISE and abort before the row is written.
  2. The floor predicate must distinguish a person/spender party from the institutional and provider parties (dunin7, anthropic), applying the zero-wall only to the former.

The pre-spend gate (§5) stays as fail-fast UX — refuse before spinning up a job that will be rejected — but it is not the control. The trigger-enforced person-side floor is the control; the gate is the courtesy. This is defense in depth with the ledger as backstop, and it directly answers the test-green-production-broken failure class: the floor holds even when a check is bypassed.

3.3 Refill at a threshold — auto-fire inside the authorized regime

The reservoir carries a refill level above zero. When the provisioned balance crosses down through the refill level, refill auto-fires — drawing on provisioned backing to top the reservoir up — if and only if the Operator has authorized the Loomworks credits regime for the spend in question.

The Operator's framing, which is cleaner than the auto-vs-approve choice v0.1's predecessor framing implied: the approval and the auto-fire are not alternatives. The Operator authorizes the regime once ("use Loomworks credits"); within the authorized regime, refill auto-fires at the threshold without per-refill approval. Operator-authority sits at the regime boundary (whether Loomworks credits are in play at all), not at every refill. This is consistent with the seed: the Operator approves the state transition that matters (unauthorized → authorized); the system runs the mechanism within it.

3.4 The wall behavior — hard stop with two exits

When spend reaches the floor with no authorized backing (free promotional credits, or no authorization): hard stop. No cascade-to-free-forever, no silent continuation. The work stops, and the exhaustion state surfaces with exactly two Operator exits — which are the two ways to enter an authorized/backed state:

The hard stop is the solvency control doing its job: free tokens are not infinite tokens. Note this makes piece 2 (system-key path) load-bearing beyond metering — option (b) is the system-key path, viewed from the exhaustion end.


4. The grant→consumption→provisioning lineage — lot-based FIFO (settled by build-with)

v0.1 recommended lot-based FIFO (Candidate B) over single-grant_id (Candidate A) and left it as a recommendation. Build-with settles it as B by force: Candidate A cannot express the provisioning→grant→consumption chain, and it could not express a spend crossing a grant boundary. B is the structure.

The structure. Provisioning, grant, and consumption are linked by lots and draw-down rows:

Why it satisfies both Operator requirements at the substrate, by construction:

FIFO is the defensible draw-down order; the methodology's "pick a defensible answer and document the choice" applies. This is built into piece 4 (the consumption-flow writer) and the new provisioning/grant lot-writers — cheap now, expensive to retrofit.


5. The five pieces — scoped and sequenced

Piece 1 — Usage-returning LLM client. (Foundational, first.) Change complete() -> str to return a structured result: text + token usage (prompt tokens, completion tokens, model-tier identity). Every caller updates. Widest piece; mechanical once the return shape is fixed. Structured object, not a tuple — usage must carry tier identity for piece 4. Nothing debits yet; this makes consumption measurable.

Piece 2 — System-key path for the rooms. (Parallel to piece 1.) Give the three rooms the three-tier resolution; converge onto the canonical resolve_engagement_api_key resolver rather than three inline ones (tidies real drift; proven by uploads). Also the mechanism behind exhaustion exit (b) — the Operator's own key resolves here.

Piece 3 — Spender identity + authorization at the debit site. (Verified present; see §2.) Key the debit on triggered_by.id, asserting contributor.id == person.id for person spend. For agent spend, debit the engagement reservoir under the agent-spend authorization, recording the agent as actor. Synchronous Manifestation has the person in the request directly.

Piece 4 — Per-room consumption-flow writer + lot draw-down. (Builds on 1 and 3. The crux.) Adapt the writer from converse's five-flow two-call shape to the one-call-per-room shape. Write flows that are: tier-identified (debit the specific loomworks_credit_haiku/sonnet/opus asset, never collapsed); lot-linked (the FIFO draw-down of §4); work-linked (turn_event_id, present); FORAY-attestable-complete through the existing reserved seam (_foray_reserved_emit, no-op since Phase 63, already at the 12 credit sites per manifest v0.44 / Phase 63 notes — widen payload to full row shape at integration time). Plus the new provisioning and grant lot-writers (§3.1, §4) and the floor enforcement on the balance trigger (§3.2).

Piece 5 — Gate + exhaustion + authorization, per execution model. (Last; depends on 1–4.)

Sequence: 1 first; 3 verified early; 2 and 4 build on 1/3; 5 last. Matches constraints note §1.


6. Resolution record — the decisions, closed

v0.1 listed these as open. v0.2 records them resolved, with the trajectory preserved (discovery-record discipline).

Decision 1 — Funded-reservoir timing. RESOLVED: build-with. v0.1 recommended defer; the Operator chose build-with, on the reasoning that deferring the second invariant clause is "just pushing it off." The funded reservoir (§3) is built with this work: provisioning events, hard floor (person side, per the corrected §3.2), reservoir floored at provisioned capacity, refill threshold, Operator-authority provisioning.

Decision 2 — Agent-initiated spend. RESOLVED: reservoir-pays-with-actor-recorded, under a separate agent-spend authorization. Trajectory: v0.1 recommended (a) refuse ("no person to debit"). The Operator rejected the premise — the Operator who authorizes replenishment can authorize agent spend — which dissolved "no one to debit" into the correct frame: the engagement reservoir is the payer, the agent is the actor, the Operator's authorization is the license. Then, offered all (one authorization covers person + agent) vs split (agent spend a distinct license), the Operator chose split on the §0 reasoning that agents can run amok — autonomous spend is a different profile and should be opted into, not inherited from person-spend authorization. Final model:

§4 lot structure. RESOLVED: B (lot-based FIFO), forced by build-with (see §4).

Provisioning mechanism. RESOLVED: (i) Operator-authority action, derived from the authorization model; provider-anchored (ii) deferred to a later hardening (see §3.1).

Refill behavior. RESOLVED: auto-fire within the authorized regime, approval at the regime boundary not per-refill (see §3.3).


7. The single constraint carried into the Change Request

> Build the rooms' consumption flows FORAY-attestable-complete: tier-identified (never collapsed), linked to the work they paid for (turn_event_id, present) and the lot they drew against (the FIFO draw-down of §4, added), against a funded, floored reservoir (§3) whose issuance is gated by provisioned backing and whose refill auto-fires only inside an Operator-authorized regime. Person spend and agent spend draw on the same reservoir under separate authorizations, each recording its actor. Reject every shortcut that collapses tiers, omits lot linkage, lets any balance breach zero, or lets an agent spend without its own authorization.

Get pieces 3, 4, and the reservoir right to this standard and both Operator requirements are satisfied at the substrate: credits-for-sale becomes "build the purchase mechanism on a ledger already shaped for it"; FORAY anchoring becomes "switch it on."


8. Seed and constraints alignment check

Checked against seed v0.9. No conflict.

Seed-lag note (not a conflict; for the v0.10 seed bump already flagged in manifest v0.44 §1): the seed's declared render-types still name .docx primary/companion (seed lines 219–228), superseded by HTML-primary / .md-source discipline. This scope does not touch render-types; recorded as one more v0.10 bump item.


9. What this scoping note does NOT do

It does not write the Change Request (REQ rows are the next artifact — all decisions are now closed, so the Change Request can be drafted directly). It does not build. It does not scope the credit purchase/sale mechanism (forward-compat only). It does not wire FORAY anchoring (seam-marked). It does not build provider-anchored provisioning (Operator-authority provisioning this build). It does not touch the stale model-tier asset map (separate follow-up). It does not produce an HTML companion (record-wide companion gap; .md only, technical-consumer document).


Tracked items carried (non-blocking)


Changelog

Version 0.3 (2026-05-30). Corrected §3.2 (and the related §3.1 phrasing) against a read-only code inspection at daee809 that grounded the actual balance trigger. v0.2 said the hard floor "rejects any flow that would drive a balance below zero, on both sides." That is wrong: the institutional dunin7 party is negative by design (its balance mirrors all issuance), so a both-sides zero-floor would block all issuance. Corrected to: hard zero-floor on the person/spender side only, enforced by a BEFORE INSERT trigger (the existing balance trigger is AFTER INSERT and cannot veto a row); the reservoir side is floored at provisioned capacity by the funded-reservoir accounting, a different floor at a different level. No decision changed — only the mechanism description was made accurate. The Change Request (CR-2026-095, Phase 64) carries the corrected model. Supersedes v0.2, preserved alongside.

Version 0.2 (2026-05-30). Resolved all decisions v0.1 surfaced. Decision 1 → build-with (funded reservoir built now, not deferred); added §3 (funded reservoir: provisioning events, hard floor as ledger invariant on both sides, refill-at-threshold with auto-fire inside the authorized regime, hard-stop-with-two-exits). Decision 2 → agent spend resolved as reservoir-pays-with-actor-recorded under a separate agent-spend authorization (split), superseding v0.1's (a)-refuse recommendation; trajectory preserved in §6. §4 lot structure settled as B (FIFO) by force of build-with. Provisioning resolved as Operator-authority action (i). Rewrote §5 piece 4 and piece 5 to carry the reservoir, floor, and authorization scope. Updated §1, §7, §8. Supersedes v0.1, preserved alongside.

Version 0.1 (2026-05-30). Initial scoping note. Confirmed the spender-threading verification (present, both async rooms); scoped the five pieces; recommended lot-based FIFO lineage; surfaced two Operator decisions (funded-reservoir timing; agent-initiated spend) with recommendations.


DUNIN7 — Done In Seven LLC — Miami, Florida Pipeline-Spend Credit Gate — Scoping Note — version 0.3 — 2026-05-30