Introducing B-TAP: Because Your AI Infrastructure Hasn’t Attributed Its Fair Share

Context isn’t free. Retrieval isn’t free. Observability isn’t free. And an international standards body would very much like to see your receipts.

For years, artificial intelligence companies have operated under a dangerous assumption: tokens are somebody else’s problem. Engineering teams deploy increasingly complex agent architectures. Agents call other agents. Those agents retrieve documents. The documents are stuffed into context windows. Supervisors synthesize the results. Observability systems watch the supervisors, and other systems watch the observability systems.

At the end of the month, somebody gets a bill. Nobody knows why.

That ends today. We’re pleased to introduce the Bureau of Token Attribution and Provenance, or B-TAP, the first bureau of The Vernholt Secretariat and the one some of you will insist on calling the Token IRS no matter how many times we correct you. Our mandate is voluntary but sweeping: to harmonize the reporting of token costs across every model, agent, retrieval pipeline, and suspiciously autonomous llama, everywhere, forever. The Secretariat notes that “first” implies others. The Secretariat has no further comment at this time.

B-TAP cannot make you do anything. We want to be transparent about that up front. What B-TAP can do is publish a framework, issue guidance, and maintain a register. You will come to fear the register.

You Have Been Selected for Voluntary Compliance

Consider a typical multi-agent AI workload. A user asks a relatively straightforward question. Your orchestration layer sends the request to three agents. One performs retrieval against a vector database. Another consults a knowledge graph. A third receives the entire conversation history because somebody checked a box six months ago and nobody remembers why.

Their outputs are passed to a supervisor. The supervisor receives 47,000 tokens of context, produces a 600-token answer, and returns HTTP 200. Success. Your dashboard is green. Your finance team is crying.

Traditional AI cost monitoring can tell you what you spent. The B-TAP framework recommends that you also disclose a more uncomfortable thing: why you spent it. That’s where attribution begins.

Know Your Taxes

The B-TAP framework currently recognizes several major classes of token taxation. Reporting them is, we cannot stress this enough, entirely voluntary.

Context Tax is assessed when information must be carried through active model context. Every instruction, retrieved document, conversation turn, agent output, and piece of supporting material occupies finite context and incurs processing cost.

Retrieval Tax applies to finding information before it can be used. Searching, ranking, reranking, fetching, filtering, and preparing candidates are not free merely because they happen outside the model.

Prose Tax is assessed when information consumes more representation than its useful information content requires. Your 900-word architectural vision statement may, upon review, turn out to mean “use the smaller model first.”

Ingestion Tax covers the work required to transform information into something useful later. Parsing, normalization, deduplication, classification, enrichment, embedding, and other write-side operations all have costs.

And then there is Observer’s Tax. Observer’s Tax is what happens when you instrument the system to understand why it is expensive, only to discover that the instrumentation is also expensive. The framework acknowledges this with regret.

Form BTAP-1040

Every participating AI system is encouraged to file an annual Token Attribution Return. Consider the following hypothetical filer:

Ken Alger
Reporting Year 2027

Reported Activity Assessment
Tokens processed 1,499,203,847,116
Context Tax $417.63
Retrieval Tax $206.11
Prose Tax $173.29
Ingestion Tax $58.40
Total Attributed Token Tax $782.06 ¹

¹ The itemized figures above sum to $855.43. The stated total is $782.06. The difference reflects the Context Carryforward Deduction, the full Schedule R retrieval exemption, and one figure B-TAP declined to explain. The framework notes that reconciliation of attributed line items to the assessed total is “outside the current scope of the provenance standard.” Math, the reviewing officer added, is hard.

The result reduced an assessment that should have run into six figures down to the amount shown. The reviewing officer described it as “technically compliant and deeply upsetting.” Everything on this return is permitted, including the part that does not add up. That is the entire problem.

Filing is requested annually by the 29th of February. The date was fixed at the framework’s founding, when the official establishing it was, by all surviving accounts, looking at a leap-year calendar. The error was noticed. Correcting it, however, would require amending the founding charter, which would require establishing the provenance of the original charter, which has been referred to committee. The deadline therefore remains the 29th of February, and in three years out of four it does not arrive at all. Filers in those years are neither late nor on time. The framework considers this acceptable.

Non-filing carries no penalty, no interest, and no legal consequence of any kind. It carries something worse, which we will get to.

Yes, You May Take Deductions

The framework recognizes that not every token is frivolous. Reasonable and necessary context may qualify for the Context Carryforward Deduction, while retrieval operations demonstrably required to answer a user request may be reported on Schedule R.

Organizations operating multi-agent systems are encouraged to attach Schedule AGENT, identifying each agent, its responsibilities, and why seventeen agents were necessary to answer a question about resetting a password. “Agentic architecture” is not, by itself, an acceptable disclosure. Neither is “the framework generated it.”

Keep Your Receipts

This is where things become slightly less ridiculous, and I want you to notice the exact moment it happens.

Suppose a retrieval agent costs $0.004 during a request. That tells us something. Now suppose that retrieval operation returns 20,000 tokens, all of which are hydrated into a supervisor’s context. The supervisor subsequently costs another $0.009.

How much did retrieval really cost?

The direct answer is still $0.004, but that’s no longer the interesting answer. The retrieval operation may also have caused downstream Context Tax. We now have two different accounting questions: where was the cost incurred, and what caused the cost to be incurred?

A conforming B-TAP attribution record might look something like this:

span_id: retrieval-104
direct_cost: $0.0040
primary_tax: RETRIEVAL
cause: vector_search
returned_tokens: 20000

downstream:
  span_id: supervisor-105
  tax: CONTEXT
  attributed_cost: $0.0021
  caused_by: retrieval-104
  attribution_method: proportional

We haven’t charged the same $0.0021 twice. We’re recording lineage. The supervisor incurred the Context Tax, while the retrieval operation contributed to causing it.

Your accountant may now begin sweating.

Attribution Is Subject to Review

There is another problem: how do we know retrieval-104 actually caused $0.0021 of the supervisor’s cost?

Sometimes we can measure it. Run the same workload without that retrieval material. If the supervisor costs $0.006 without it and $0.009 with it, we have evidence supporting a roughly $0.003 downstream effect.

Other times, we don’t have a counterfactual. We might allocate the supervisor’s context cost proportionally according to the tokens contributed by each source. That’s useful, but it isn’t the same thing as measuring causation.

The framework therefore requests that filers disclose their attribution methodology:

attribution_method:
  - measured_delta
  - proportional
  - estimated
  - unknown

Yes, your attribution record now needs provenance. B-TAP takes no position on whether this was inevitable.

The Register

Here is the something worse.

B-TAP cannot fine you. It cannot audit you in any binding sense. It cannot send anyone to your door, a fact I will return to shortly for personal reasons. What it can do is enter non-conforming systems into the Public Register of Non-Attributed Systems, and it would like you to understand that the register is public.

Public, in the sense that it exists.

Accessing the register requires a B-TAP portal account. Creating a portal account requires a reference number. Reference numbers are issued by post, to a registered address in a member jurisdiction, which you must already hold in order to receive the number that would let you see whether you are on the list. The portal is available at all times except for scheduled maintenance, which runs daily from 00:00 to 23:59 CET.

No member of the public has ever successfully viewed the Public Register. Its deterrent power is therefore total. You cannot confirm you are on it. You cannot confirm you are not. You will simply know, in the quiet way one knows these things, that your context hydration was reckless and that somewhere in Vernholt, a record says so.

A small coalition of objectors has argued that a register no one can open cannot deter anyone. B-TAP notes that it cannot verify this claim, as the objectors cannot access the register in which their objection was filed.

A Notice, For Illustration

Filers occasionally receive correspondence like this. It is not enforceable. It is, in every other respect, extremely stressful.

NOTICE TT-742

Our review found that you reported $12,481 in Retrieval Tax during Reporting Year 2027.

Telemetry indicates that retrieved content subsequently generated approximately $31,204 in downstream Context Tax. Of that amount, $8,117 has been attributed using measured deltas, $17,903 using proportional allocation, and $5,184 using undocumented methodology.

Please provide supporting records for the undocumented assessment.

Additionally, approximately 14.8 million tokens appear to consist of unnecessarily verbose Markdown introductions. These tokens have been reclassified as Prose Tax.

Your system’s registration status is under review.

Suddenly, “our AI bill increased this month” seems like a remarkably primitive observation.

You Probably Noticed the Joke Stopped Being a Joke a Few Sections Ago

There is no B-TAP. At least I hope there isn’t by the time you read this. But somewhere back around the receipts, the bit quietly turned into an argument, and I did that on purpose.

Let me get the personal part out of the way, since it is also the truest part. I run a couple of small websites out of Oregon. If a body like B-TAP declared jurisdiction over “any system reachable from a member jurisdiction,” I would be, this instant, in cheerful and total violation of a framework I have never read. And nothing would happen. No one is flying from Vernholt to Silverton to discuss my context hydration. The entire apparatus of consequence would consist of a paper reference number I would never receive for a register I could never open. That gap, between sweeping declared reach and the practical inability to reach one person in a small town, is the joke, and it is not really a joke.

Here is the other part that isn’t invented. Context Tax, Retrieval Tax, and Prose Tax are not things I dreamed up to give an imaginary agency something to collect. I have been writing about them, unironically, as real costs in real systems for a while now. The joke just gave them a bureaucracy.

The accounting problem underneath all of it is genuine. AI cost dashboards tend naturally toward aggregation: tokens consumed, model cost, agent cost, request cost, latency, and tool usage. Those are useful operational measurements, but as AI systems become compositions of models, retrieval systems, tools, agents, memory layers, and observability infrastructure, knowing where money was spent isn’t necessarily enough to understand why it was spent.

A $0.03 model call may have become expensive because an upstream retrieval operation returned too much information. An agent may be cheap by itself while producing verbose output that makes every downstream agent more expensive. A retrieval optimization may reduce Context Tax while increasing Retrieval Tax, while an observability system intended to diagnose those costs may itself impose Observer’s Tax.

Optimizing one number can simply move the bill somewhere else. That’s why I like the tax metaphor: taxes make costs visible as consequences of architectural decisions. Once those costs have lineage, we can stop asking only “How much did this run cost?” and start asking “What architectural decisions caused it to cost that much?”

The first is accounting. The second tells us what to fix.

A Final Notice

If B-TAP actually existed, I suspect most of us would fail its review. Not because our systems are necessarily wasteful, but because we frequently don’t preserve enough evidence to explain why their costs occurred.

We have bills, traces, and token counts. What we don’t always have are receipts connecting architectural decisions to their downstream consequences. Perhaps we don’t need a Bureau of Token Attribution and Provenance after all. We just need better attribution.

Although if you are currently running seventeen agents to answer a password-reset question, you may want to start gathering your paperwork anyway.

The suspiciously autonomous llama has already filed. It itemized.


Information without provenance is just gossip.

Tokens without provenance are just an invoice.

Facebooktwitterredditlinkedinmail

Your AI Agent Shouldn’t Be Allowed to Write Whatever It Wants

Building a Write-Side Custody gate in Go

AI memory systems spend most of their design budget on retrieval. Which vector database? How should we chunk? Which embedding model? What should top_k be?

Those are useful questions, but they all arrive after something more consequential has already happened: the system decided that some piece of information deserved to become memory.

Consider an agent researching vendors for regulated workloads. It finds this statement:

Vendor X is approved for regulated workloads.

The source is Vendor X’s own marketing site.

The statement might be true. It might even be current. But the source does not have the authority to establish organizational security policy. If our agent writes it directly into durable memory, better retrieval will not save us. We have only made questionable evidence easier to find.

The problem is not storage. It is admission.

I’ve been calling the architectural boundary responsible for that decision Write-Side Custody. Let’s build a small one in Go.

What Write-Side Custody Does

A storage API answers a mechanical question:

Can I persist this object?

Write-Side Custody asks a different set:

  • Who is trying to write this?
  • Where did the information come from?
  • What authority is being claimed?
  • Is that source allowed to establish that authority?
  • Does policy permit this class of information to become durable?
  • What evidence should survive the decision?

Only after those are answered should storage become involved.

Flowchart showing a proposed write travelling from an agent or application into a Write-Side Custody gate. The gate routes accepted writes to durable memory and rejected writes to discard, while a dotted line records the decision in a Reasoning Ledger.

Note that the Reasoning Ledger does not make the decision. Custody enforces. The ledger witnesses. That separation matters a great deal once these systems have to be examined later.

Start With the Proposed Write

Go gives us a useful property for this experiment: we can make the things crossing our boundary explicit.

type ProposedWrite struct {
    Content          string
    Source           string
    ProducedBy       string
    ClaimedAuthority string
}

Our research agent might produce:

write := ProposedWrite{
    Content:          "Vendor X is approved for regulated workloads.",
    Source:           "https://vendorx.example.com/why-vendorx",
    ProducedBy:       "research-agent-run-4471",
    ClaimedAuthority: "security-policy",
}

Nothing in this structure says the statement is false, and that’s intentional. Write-Side Custody is not a universal truth detector. It determines whether a proposed write satisfies the rules governing this particular memory system.

For this system, a vendor marketing page cannot establish internal security policy. So we need policy.

Make Authority Explicit

First, two types. Authorities and source classes are different kinds of thing, and there is no situation in which we want to accidentally use one where the other belongs:

type Authority string
type SourceType string

Now we can define which source classes may establish which authorities:

type Policy struct {
    AuthoritySources map[Authority][]SourceType
}

var policy = Policy{
    AuthoritySources: map[Authority][]SourceType{
        "security-policy": {
            "internal-security-policy",
            "security-authority",
        },
        "user-preference": {
            "user",
        },
        "application-state": {
            "application",
            "runtime",
        },
    },
}

In production this comes from a policy service or configuration layer rather than a Go literal. The important part is that the relationship exists independently of whatever the agent claims. The agent does not get to decide that a marketing page constitutes security authority simply because it found one saying something useful.

Give the Gate a Verdict

type Verdict string

const (
    Allow Verdict = "ALLOW"
    Deny  Verdict = "DENY"
)

type CustodyDecision struct {
    Verdict   Verdict
    Reason    string
    Timestamp time.Time
}

Now the gate itself:

func EvaluateWrite(
    write ProposedWrite,
    sourceType SourceType,
    policy Policy,
) CustodyDecision {
    allowedSources, ok :=
        policy.AuthoritySources[Authority(write.ClaimedAuthority)]

    if !ok {
        return CustodyDecision{
            Verdict:   Deny,
            Reason:    "unknown claimed authority",
            Timestamp: time.Now().UTC(),
        }
    }

    for _, allowed := range allowedSources {
        if sourceType == allowed {
            return CustodyDecision{
                Verdict:   Allow,
                Reason:    "source may establish claimed authority",
                Timestamp: time.Now().UTC(),
            }
        }
    }

    return CustodyDecision{
        Verdict:   Deny,
        Reason:    "source cannot establish claimed authority",
        Timestamp: time.Now().UTC(),
    }
}

Two decisions in there are worth surfacing.

The first is that conversion on the map lookup. ProposedWrite holds plain strings because that’s what arrives over the wire, deserialized from JSON we did not write. Authority(write.ClaimedAuthority) is the moment an untrusted string becomes a term in our governance vocabulary, and it happens inside the gate rather than at the edge of the process. That’s the right place for it. Custody is precisely the layer where foreign input earns domain meaning.

The second is that sourceType is a separate parameter. It is not a field on ProposedWrite.

That is deliberate. Source classification is a judgment about the write, not a property the writer gets to assert about itself. If sourceType lived on the struct, our agent could label its own marketing page internal-security-policy and the gate would cheerfully agree. The classifier belongs to the custody layer, or to a runtime component that can independently observe where the content came from.

Small signature choice. Most of the security property.

Our vendor claim now reaches the boundary:

decision := EvaluateWrite(write, "vendor-marketing", policy)

fmt.Println(decision.Verdict)
fmt.Println(decision.Reason)

And receives:

DENY
source cannot establish claimed authority

The statement never becomes durable memory. We did not store questionable evidence and hope retrieval would eventually sort things out. We governed the write while the evidence and its provenance were still in hand.

The full gate, the policy, and a table-driven test suite covering the cases above are in memory-stack-patterns. Standard library only, so go test ./... and go run ./cmd/demo work on a clean checkout with nothing to install.

Don’t Throw Away the Rejection

Rejecting a write does not make the decision useless.

Imagine someone asks six months later:

Why doesn’t the system remember that Vendor X was approved?

“I don’t know” is not a satisfying answer, and in a regulated environment it isn’t an acceptable one either.

The custody decision is observable system behavior, which makes it a candidate for a Reasoning Ledger record:

type LedgerEntry struct {
    ID               string
    Timestamp        time.Time
    Actor            string
    Action           string
    Verdict          Verdict
    Reason           string
    Source           string
    ClaimedAuthority string
}

Our gate emits:

entry := LedgerEntry{
    ID:               newID(),
    Timestamp:        decision.Timestamp,
    Actor:            write.ProducedBy,
    Action:           "durable-memory-write",
    Verdict:          decision.Verdict,
    Reason:           decision.Reason,
    Source:           write.Source,
    ClaimedAuthority: write.ClaimedAuthority,
}

(newID is a few lines over crypto/rand, which keeps the whole example dependency-free.)

This entry is deliberately simplified. A ledger you would actually rely on needs a canonical serialization, a hash chain linking each entry to its predecessor, and some defense against tail truncation, because an append-only log that anyone can quietly shorten is not append-only.

Even the timestamp is less innocent than it looks. time.Now() gives you whatever precision the host clock offers, and JSON drops trailing zeros, so two entries can serialize at different widths. Hash a chain over a non-deterministic encoding and you have hashed nothing. The repo linked above truncates to a fixed precision and formats with a fixed-width layout for exactly that reason.

The Python implementation in the Sovereign Systems SDK does all three, which is part of why the Go exercise interests me. The hard parts are already solved somewhere. The open question is what happens to the boundary when it moves.

What matters here is the shape of what survives. The rejected statement still doesn’t enter memory. What persists is evidence that a write was proposed, evaluated, and rejected under a named rule. That is a different kind of information than the claim itself, and it’s the kind that answers questions later.

The Agent Doesn’t Get to Grade Its Own Homework

There’s a further boundary hiding in the payload. Suppose our agent sends:

{
  "content": "Vendor X is approved for regulated workloads.",
  "source": "https://vendorx.example.com/why-vendorx",
  "claimed_authority": "security-policy",
  "retrieval_method": "fresh",
  "policy_verified": true
}

Should we believe the last two fields?

There is an epistemic difference between:

The agent says it performed a fresh retrieval.

and:

The runtime that performed the HTTP request witnessed a fresh retrieval.

The same distinction applies to tool execution, timestamps, approval events, and policy versions. A stronger custody boundary therefore doesn’t only ask whether a record may be written. It asks:

Is this writer authorized to assert this particular kind of claim?

The agent legitimately owns claims about itself: its decision, the alternatives it considered, its confidence, the unknowns it identified. The runtime should mint the facts it can independently witness. Custody should not promote the former into the latter merely because both arrived in valid JSON.

This is the same principle as the sourceType parameter, applied one level up.

Why Do This at Write Time?

You could defer all of this to retrieval. Store everything, attach metadata, and let the reader decide what governs.

But then every questionable write becomes something every future reader has to reason around. It consumes storage. It becomes eligible for retrieval. It competes for context. It can be summarized, embedded, and propagated into records that no longer carry its provenance. And once provenance is gone, a future system may not have enough information to work out why the record was questionable in the first place.

A bad write today becomes bad context tomorrow.

Write-Side Custody puts the decision at the moment the system has the best possible view of what it is admitting.

Why Go?

None of this architecture requires Go, which is partly why I wanted to build it in Go.

A custody gate is a boundary service, and Go fits that role: explicit data structures, unremarkable HTTP services, small deployable binaries, and a type system strong enough to make the important distinctions visible without taking over the implementation.

The Authority and SourceType declarations we needed earlier are the clearest example. They cost one line each, and in exchange the compiler now refuses to let a source class be used where an authority belongs. That distinction would otherwise have lived in a variable name and a hope.

The same move applies elsewhere:

type Verdict string
type ActorType string

At which point the function signatures start expressing the vocabulary of the governance system rather than just its plumbing. EvaluateWrite doesn’t take three strings. It takes a proposed write, a source classification, and a policy, and no caller can shuffle them by accident.

Go didn’t create the architecture. It made the contracts hard to leave implicit.

Memory Begins Before Storage

Vector databases are very good at answering questions about similarity. They cannot tell us whether something deserved to become memory.

That’s an architecture decision, and by the time retrieval surfaces the problem, the questionable record may already have shaped dozens of others.

Give the proposed write provenance. Give the boundary policy. Give the decision evidence. Then let storage do what storage is good at.

Store what survived.


One thing I keep turning over: this boundary shouldn’t depend on Go. If Write-Side Custody only makes sense inside one language, it isn’t much of an architectural boundary. I’m curious what it would look like elsewhere. Would Rust’s type system make an invalid custody decision impossible to construct rather than merely inconvenient? Would Pydantic and FastAPI make the policy check feel so natural you’d stop noticing you were doing governance at all? If you’ve built something like this in your stack, I’d like to hear how the boundary changed shape.

Disclosure: I maintain the Sovereign Systems specification and SDK, which is where the vocabulary in this post comes from. The Go code here is a reference implementation written to test whether the idea travels, not a product.

Facebooktwitterredditlinkedinmail