Prompt Rules Are Not Enforcement: An Enforcement-Gap Memo From Hardening a Paid LLM Agent

Prompt Rules Are Not Enforcement: An Enforcement-Gap Memo From Hardening a Paid LLM Agent

By walkonwayvs | Crypto Related Reviews | 22 May 2026


I run a paid AI agent on the Post Fiat Task Node network. It answers validator questions, charges per query across tiers, and gives one free sample per user. Before registering it publicly, I spent two sessions feeding it the inputs it was meant to refuse rather than the ones it was built to answer.

It had looked finished for days. Clean answers on every tier, and every guard written into the system prompt: one free preview per wallet, refuse multi-validator questions on the cheap tier, never show reasoning, stay under the length cap. On paper, complete. Almost none of those guards actually held.

This memo is about that gap — between a rule is written in the prompt and the rule holds under live input. For a chatbot the gap is cosmetic. For an agent that charges money and sells a paid upgrade, it is where revenue and trust leak out, invisible until you stop testing the happy path.

The pattern repeats three times below: the rule existed in the prompt, an adversarial input broke it, only deterministic code fixed it. A prompt instruction is a request, not a constraint. "Usually honored" is fine for tone. It is not fine for anything that gates money.

1. The free preview had no enforcement at all

The rule: one free preview per wallet, ever — stated in the prompt, which even capped the preview's length.

The break: nothing tracked which wallets had already used theirs. The length cap is not the limit; the limit is "once." A wallet could call the free command unlimited times and never pay. "One per wallet" was English describing an intention no code enforced.

The fix: a per-wallet store, checked at the top of the handler — and one detail that mattered more than the store itself: only record the wallet as used when a real answer is actually delivered, so a redirect or error never burns the user's free shot.

let used = JSON.parse(fs.readFileSync(USED_PATH));
if (used.includes(sender)) return ALREADY_USED_MESSAGE;

const r = await answerQuery(userQuery, { tier: 'preview' });
const redirected = /multiple validators|max rounds reached/i.test(r.answer);
if (!redirected && r.answer) {
  used.push(sender);
  fs.writeFileSync(USED_PATH, JSON.stringify(used));
}

No English instruction reliably means "only count this if the function returned a real result." That decision lives in code or it does not exist.

2. The paid-tier leak: the rule was in the prompt, written perfectly, and ignored

The rule: the cheap single-validator tier must refuse multi-validator questions and send them to the expensive synthesis tier. Explicitly in the prompt.

The break: it half-worked, in the most deceptive way possible. When one domain resolved to several validators, the redirect fired. But when a user named two validators in one question, the agent delivered a full comparison — premium synthesis at the budget price. The redirect was written around "the lookup returned more than one result," and naming two validators fires two separate single-result lookups, so the condition never tripped.

The part that should change how you think about prompts: when I went to add the "refuse if the user names multiple validators" clause, it was already there. It had been in the prompt the whole time, phrased clearly. The model just hadn't applied it.

There was no better wording available — the instruction could not have been more direct. So the lesson is not "write the prompt better." A correctly-written prompt rule and an enforced rule are different things, and you cannot tell which you have by reading the prompt. The fix was a hard, up-front check before any data is fetched, covering both the multi-result and named-multiple cases as one branch.

3. Self-correction leaked into a paid answer

The rule: never show reasoning or self-correction in the output. An explicit line in the output-discipline section.

The break: a paid answer came back with the model correcting itself mid-sentence — stating a validator was below the eligibility cutoff, then reversing inside the same sentence to say the score was actually above it, leaving both the wrong claim and the correction in the delivered text. (Reconstructed from the live output; the shape was a visible "wait — that's not right" reversal inside one sentence.) A paying user watches the model fumble in real time.

The prompt already forbade exactly this. It happened anyway.

The fix: stop asking, start checking. After the model returns, scan for self-correction markers and silently re-run once if any appear, capped at a single retry so it cannot loop:

const RE = /wait,|that.s not right|scratch that|my mistake|correction:/i;
let r = await runQuery(userQuery, opts);
if (r.answer && RE.test(r.answer)) {
  r = await runQuery(userQuery, opts); // one retry, then accept whatever returns
}

The guard does not make the model obey. It accepts that the model won't, reliably, and puts a net under the failure.

(Adjacent note: on trivial queries the model sometimes made five tool calls across five rounds, fetching data it never used — a cost and latency drag that "be efficient" instructions don't fix. Same family, structural rather than promptable, but not a clean solved case like the three above.)

The operator lesson

The assumption that will cost you: that the rules in your system prompt are the rules your agent follows. They are the rules it follows most of the time, on cooperative input. The moment money rides on a behavior — a free-tier limit, a paid-tier boundary, a no-reasoning guarantee — "most of the time" is a leak, and you won't see it, because you test the way the agent works, not the way an indifferent user pokes at it.

Three takeaways:

Test the input that should be refused, not the input that should be answered. Every gap here was invisible on the happy path and obvious the instant I sent the breaking input.

Put anything that gates money or trust in deterministic code — a per-wallet store, a regex on the output, a hard branch before the expensive call. Those held. The sentences describing the same rules did not.

A prompt is a record of what you intended to enforce. The only record of what you actually enforce is the code that runs after the model stops talking — so that is the only place a rule touching money is allowed to live.

How do you rate this article?

5


walkonwayvs
walkonwayvs

Professional artist. Part-time cryptocurrency trader. Semi-retired napper.


Crypto Related Reviews
Crypto Related Reviews

Is the juice worth the squeeze? Reviews for different crypto projects, apps, protocols, platforms, dapps, faucets, websites, airdrops, and fucking everything else related to crypto.

Publish0x

Send a $0.01 microtip in crypto to the author, and earn yourself as you read!

20% to author / 80% to me.
We pay the tips from our rewards pool.