Version. 0.2
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.2 resolves the decisions v0.1 surfaced: funded reservoir built with this work (build-with); hard floor as a ledger invariant; refill-at-threshold with auto-fire inside an Operator-authorized regime; split authorization (person-spend and agent-spend as distinct licenses); free/unauthorized hard-stop with two exits. All Operator decisions are now closed; the next artifact is the Change Request. Supersedes v0.1, 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.
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).
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.
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:
shape_events.py:255 → shaping_jobs.py:43,67 → executor.py:71,108-112 → produce_shape(…, triggered_by) (shaping.py:264); debit point shaping.py:512.renders.py:410 → render_jobs.py:52,97 → produce_render(…, triggered_by) (render_specialist.py:237); debit point render_specialist.py:887.party_id = str(person_id) (flows.py:171,278); for a human caller triggered_by = ActorRef(kind="contributor", id=person.id) (deps.py:700-701,721-722), so str(triggered_by.id) is the debitable party_id.
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).
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:
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 balance becomes "provisioned minus allocated," with a floor of zero.
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.
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 balance trigger: any flow that would drive a party's balance below zero is rejected at the database, the same layer that already maintains double-entry balance. Zero is a wall, not a sign. This holds on both sides:
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 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.
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.
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.
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.
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.)
shaping.py:512, render_specialist.py:887) — not at dispatch (which is pre-enqueue, not pre-spend, and overspends under load) and not at job-outcome (which is reconciliation, forbidden by §0 as primary control). A dispatch-time check may be added as fail-fast courtesy but is explicitly not the gate. Exhaustion surfaces as a job state the Operator sees, with the two exits attached.Sequence: 1 first; 3 verified early; 2 and 4 build on 1/3; 5 last. Matches constraints note §1.
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 both sides, 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:
triggered_by) in the flow for FORAY accountability. An unauthorized agent spend hard-stops with the exit "authorize agent spend for this engagement."§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).
> 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."
Checked against seed v0.9. No conflict.
credit.flows ledger honours this; the hard floor rejects breaching flows but does not delete or smooth existing ones.
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.
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).
test_api_assertion_retract, test_phase_44_evaluator dedup) — unrelated, pinned, accepted.engagement_display_identifier_seq not reset by TRUNCATE … RESTART IDENTITY).
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.2 — 2026-05-30