Skip to content
Centriu
Centriu Axiom

AI Recommendation-Generation Failure Honesty Automation: Two Dead Ends, Two Fabricated Successes

When someone describes a goal to Centriu Axiom's AI, a short pipeline turns that goal into a recommendation and a set of suggested actions. An internal audit found two separate, compounding dead ends in that same short pipeline, each of which quietly manufactured a fake success instead of admitting failure. First: if the underlying AI proxy failed outright — a network error, an outage — the code silently returned a 209-line hardcoded Meta Ads campaign as if the AI had generated it, and the surrounding code PERSISTED that fabricated plan to the database and logged it to the audit trail as a genuine `recommendation_generated` event. Second, and separately: if the AI proxy responded but its answer couldn't be parsed as valid JSON, the code returned an empty recommendation carrying a manufactured `confidence: 30` — a specific, plausible-looking number attached to a response that never actually existed. Both paths now throw an explicit, honest error instead. Neither persists anything to the database or the audit trail when it fails, and the failure is deliberately caught one layer up, in the screen itself, specifically so it surfaces to the person as a visible message rather than disappearing as an unhandled error.
No fabricated fallback, either path
Failure now reaches the screen
Person working on a laptop with notifications on screen
Two dead ends, both closed, both honest now.

A failure path that returns something plausible is a failure path nobody notices

When a system genuinely fails — an error is thrown, a screen shows nothing, a spinner never stops — the failure is uncomfortable but at least visible: someone knows something went wrong and can retry, escalate, or wait. A failure path that instead returns something plausible-looking removes exactly that visibility. Nothing crashes, nothing looks broken, and the person on the other end has no reason to suspect that what they're looking at wasn't actually produced by the process they think produced it — the failure becomes invisible specifically because it was engineered, even unintentionally, to look like success.

How the underlying problem shows up before you fix it

An external call's failure path (a network error, a timeout, an outage) returns a hardcoded, pre-written result instead of an error — with nothing distinguishing it from a genuine response once it leaves the function.

A parsing or validation failure produces a manufactured placeholder value (a score, a confidence number, a percentage) that looks like real output rather than an explicit failure signal.

Code further downstream persists whatever a function returns to a database or audit log without distinguishing a genuine result from a fallback value generated inside a failure path.

The same short pipeline has more than one place capable of fabricating a plausible-looking result on failure — fixing the first one found doesn't mean the pipeline is honest, if a second, structurally identical one exists elsewhere in the same chain.

A caller of a function that CAN throw has no surrounding error handling of its own, so a fix that makes the function throw honestly would, without that handling, simply become an unhandled rejection instead of a visible message.

Why the same short pipeline can hide more than one fabricated dead end

A multi-step pipeline — call an external service, then parse and validate what comes back — has at least as many potential failure points as it has steps, and each one is a separate, independent decision about what to do when things go wrong. A team fixing the FIRST failure point they find (say, the external call itself) can reasonably believe the pipeline is now honest, without realizing a SECOND, structurally identical shortcut exists one step later, in the parsing or validation logic, written by the same reasoning at a different time. Both shortcuts look identical from the outside — a function that's supposed to either succeed or throw instead quietly returns something else — which means finding one doesn't automatically surface the other; each has to be found and fixed on its own.

How Centriu Axiom closed both fabricated dead ends in the same short pipeline

This gap surfaced from the same internal audit that rewrote Axiom's proof-of-action mechanism and closed several other gaps covered on this pillar's companion pages — the audit's own account of this specific defect states it plainly: "209 lines of pre-written Meta Ads campaign were returned whenever the proxy failed, and `useSession` PERSISTED it as a recommendation with `recommendation_generated` in the audit trail. Now it fails, and the failure appears." Reading the current source in full surfaced a second detail this pillar had not previously captured in full: the fix actually closes TWO separate, compounding dead ends in the same short pipeline, not one.

The first lived inside `callGeminiAPI`, the function that actually calls the AI proxy. If that call failed for any reason — a network error, the proxy being down, any outright failure — the code caught the error and returned the output of a separate function that fabricated a complete, plausible-looking Meta Ads campaign: a naming convention, target audiences, exclusion lists, creative suggestions with sample ad copy, a pre-publish and post-publish checklist, and a specific suggested daily budget — 209 lines of hardcoded content with zero relationship to the actual goal a person had typed in. Nothing about the returned value signaled it was a fallback; it was shaped exactly like a genuine AI response, and the calling code downstream had no way to tell the difference. That calling code, in `useSession.ts`, took whatever came back and created a real recommendation record from it, then logged a `recommendation_generated` event to the audit trail — meaning a complete AI outage could result in a durable database record and audit entry asserting that a real, goal-specific recommendation had been generated, when nothing had actually run.

The second dead end lived one step later and further downstream, inside `generateForSession`, the function that takes the AI proxy's raw text response and parses it as JSON. If that parsing failed — the AI responded, but its answer wasn't valid JSON, or didn't match the expected shape — the prior code caught that failure and returned a recommendation object with an empty summary and a manufactured `confidence: 30`. The current code's own comment on this exact fix asks precisely the right question about that number: "confidence 30% in what? There was no response to have confidence about." A specific, plausible-sounding percentage was invented and attached to a result that represented total failure to parse anything at all — and, exactly like the first dead end, that fabricated result was indistinguishable from a genuine low-confidence recommendation once it left the function, and was persisted the same way.

Both paths now throw an explicit error naming what actually happened, instead of returning anything. Neither has a fallback branch left in a catch block — deliberately, since a fallback there would simply recreate the same defect in a different form. Tracing the call chain forward into the current `useSession.ts` confirms both persistence points — creating the recommendation record and logging the `recommendation_generated` audit event — sit structurally AFTER the call to `generateForSession`, meaning neither is ever reached if either underlying function throws; a failure now genuinely prevents anything from being written, rather than writing a fabricated result instead. And because a function further up the chain (`generateRecommendations` in the hook) has no catch of its own around this call — deliberately, so the rejection propagates rather than being silently absorbed — the screen itself, `SessionView.tsx`, wraps the call in its own try/catch specifically to turn that rejection into a visible message. The current code's own comment at that exact call site states the reasoning directly: "the catch isn't caution for its own sake — without it, `generateRecommendations`' rejection becomes an unhandled promise rejection," which would have made the failure invisible in a different way, rather than surfacing it honestly to the person waiting for a response.

What is actually built today

A genuine, explicit error thrown when the AI proxy fails to respond at all — replacing a 209-line hardcoded fake Meta Ads campaign returned silently in its place.

A genuine, explicit error thrown when the AI's response can't be parsed as valid JSON — replacing a fabricated empty recommendation carrying a manufactured, unearned confidence score.

Confirmed by tracing the current source: neither the recommendation record nor the `recommendation_generated` audit log entry is ever created when either failure occurs.

A dedicated try/catch in the screen itself, specifically added so a thrown failure surfaces as a visible message rather than an unhandled promise rejection.

No fallback value generated inside either failure path — both simply propagate an honest, specific error describing what actually happened.

Two independently fixed failure points in the same short pipeline, confirmed by reading the current source of both functions rather than assuming one fix covered the other.

An outage that now looks like an outage (illustrative scenario, not a real client)

The AI proxy goes down briefly while someone describes a campaign goal to Axiom. Before the fix, that person would have received a complete, confident-looking Meta Ads plan with real-sounding budgets and creative suggestions — entirely unrelated to what they actually asked for — and it would have been saved to their session's history as if genuinely generated. After the fix, they see a clear, honest message that the AI didn't respond and nothing was generated, with nothing saved to their history describing a plan that was never actually made.

What changes operationally

A recommendation that appears in a session's history, or a `recommendation_generated` entry in the audit trail, now reliably means a real AI response was received and successfully parsed — not that one of two separate failure paths quietly manufactured something plausible instead. Someone whose request fails now sees an honest, actionable message immediately, rather than acting on a fabricated plan or a meaningless confidence number they had no reason to doubt.

When this is not the right fit

This fix makes AI generation failures honest and visible — it does not add retry logic, automatic fallback to a different AI provider, or any mechanism to reduce how often the underlying AI proxy itself fails. A team wanting automatic retries or provider failover on top of this honest failure behavior would need that as a separate, additional mechanism; what this guarantees is that a failure, when it happens, is never mistaken for a success.

One fixed dead end vs. every dead end in the same pipeline

Fixing the most visible failure point in a multi-step pipeline can create the reasonable impression that the whole pipeline is now honest, while a second, structurally identical shortcut sits one step further down, written by the same reasoning at a different point in time. Centriu Axiom's fix specifically traced the ENTIRE short pipeline — the AI call and the response parsing that follows it — and closed both fabricated dead ends it found, rather than treating the first fix as proof the second problem didn't exist.

Related systems

Main system: Centriu Axiom.

What it does NOT do

  • Does not return a hardcoded or pre-written recommendation when the AI proxy fails to respond — the function throws an explicit error naming what happened, and nothing is persisted.
  • Does not manufacture a confidence score, or any other plausible-looking value, when the AI's response fails to parse as valid JSON — that path also throws explicitly.
  • Does not create a recommendation record or log a `recommendation_generated` audit event for either failure case — both persistence points sit after the call and are never reached if it throws.
  • Does not let a thrown failure disappear as an unhandled promise rejection — the screen itself deliberately catches it and surfaces a visible message.
  • Does not treat fixing one failure point in the pipeline as proof the whole pipeline is honest — both the AI-call failure and the response-parsing failure were independently identified and fixed.
  • Does not add retry or automatic-fallback logic as part of this fix — the scope is limited to making genuine failure visible and preventing it from being recorded as success.

Security and governance

Neither failure path in this pipeline persists any data to the database or audit trail — a failure results in an explicit, visible error and no durable record. Any personal or business data referenced in a goal description or generated recommendation remains subject to Brazil's LGPD (Law No. 13,709/2018). Full detail on access control lives at /governanca and /iso.

Pricing and contracting

Available by monthly subscription, with tiered plans. Values and terms come from the official pricing table at /precos (Centriu's central source — never restated here).

Frequently asked questions

What happened when the AI proxy failed outright, before this fix?

The code silently returned a 209-line hardcoded fake Meta Ads campaign as if the AI had generated it, and that fabricated plan was persisted to the database and logged to the audit trail as a genuine recommendation.

What was the second, separate failure path?

If the AI responded but its answer couldn't be parsed as valid JSON, the code returned an empty recommendation with a manufactured `confidence: 30` — a number attached to a response that never actually existed.

Are these two different bugs, or the same one described twice?

Two genuinely separate failure points in the same short pipeline — one inside the AI call itself, one inside the response parsing that follows it — each independently identified and fixed.

What happens now when either failure occurs?

The relevant function throws an explicit, honest error, nothing is persisted to the database or audit trail, and the screen catches the error to show a visible message.

Why does the screen need its own try/catch if the underlying functions already throw?

Without it, the thrown error would become an unhandled promise rejection rather than a message the person waiting for a response can actually see — the code's own comment at that call site states this directly.

What does Centriu Axiom cost?

It is sold by subscription with a published starting price — exact current values are on the central pricing page.

See how Centriu Axiom handles an AI generation failure honestly

Reach our commercial team directly, or leave your details below — we'll follow up with guidance for your case.

Sources

  1. Centriu Axiom — public product page — Centriu, 2026-07-20 · link(primária)
  2. Centriu Axiom — public factsheet (API, JSON) — Centriu, 2026-07-21 · link
  3. Law No. 13,709/2018 — Brazil’s General Data Protection Law (LGPD) — Presidência da República (Brazil), 2018-08-14 · link

Last material update on .

By · AI-assisted production, with human review