EVIDENCE MODEL

How to render a FormulaSignal answer without making it false.

Supplement information goes wrong in a small number of specific ways, and every one of them is a category error rather than a bad number. An undisclosed amount read as zero. An observation date read as a change date. A discounted price read as a list price. A calculation read as a manufacturer figure. The response contract keeps those apart as separate fields so your code does not have to keep them apart by convention.

Six kinds of thing, six places to find them

These are separate arrays on every envelope. They cannot blend, because there is nowhere for them to blend into.

FieldWhat it isHow to say it
verified_factsA declared fact. What a dated source literally printed or published.“The label declares 150 mg of caffeine.”
commercial_factsAn observation. A price or serving count we saw, with its basis and date.“Observed at $34.99 on 3 August 2026.”
calculationsDeterministic arithmetic FormulaSignal performed, with the operands so you can redo it.“FormulaSignal calculates $1.17 per serving.”
signals / historyA confirmed change. Two comparable dated states, reviewed by a person.“Caffeine moved from 150 mg to 200 mg between two dated states.”
research_contextAn interpretation with a citation: what published work used, and its evidence class.“Studied doses in the cited work ranged 3 to 5 g.”
limitationsWhat this answer cannot support. Always present, sometimes empty.Repeat what applies. Do not summarise it away.

regulatory_records and documented_cautions are also separate and never share a heading. A New Dietary Ingredient notification is a submission a company filed. It is not an approval, not an objection, and not a finding that anything is unsafe, and rendering it under a “warnings” heading tells your reader the opposite of what it says.

There is no field called date

That is deliberate. A single date field is an invitation to invent a chronology, and six different questions live underneath it.

FieldAnswers
observed_atWhen FormulaSignal read this source. Not when the product changed, and not when it was manufactured.
window_start / window_endThe two dated states a change is bounded between. The change happened somewhere inside. Nobody knows where.
released_atWhen FormulaSignal published the Signal. This is what the feed orders on, and it can be years after the window.
reviewed_atWhen a person confirmed it. No change is published without one.
record_as_ofThe Record state this answer came from.
record_timestampThe newest dated observation the Record holds. Deliberately not “now”.

The question that breaks integrations. “What day did Cellucor reformulate C4?” FormulaSignal will not answer it, because the honest answer is that nobody outside Cellucor knows. What exists is a state observed on one date and a different state observed on another. Any day your product names is a day your product made up.

Missing is not absent, and null is not zero

An amount of null means the source named the ingredient without disclosing how much. It never means zero. Zero would be a stronger claim than the label makes, and it is a claim no source supports.

An ingredient not appearing in a declared list means the source did not name it. It does not mean the product lacks it. FormulaSignal treats an absence as evidence in exactly one place, and it takes four conditions together: a reviewer signed the presence finding, both endpoints read their formula in full, both share a scope, and the ingredient is declared nowhere on the other capture at member, family or sibling level. Everything short of that is non-disclosure.

A proprietary blend is the sharpest case. “AstraGin Proprietary Blend (Panax notoginseng, Astragalus membranaceus) 50 mg” is one amount covering two materials. Counting that as a disclosed amount calls a withheld split full disclosure, so the Record counts blend lines separately and says so.

A price you saw is not a list price

price_basis travels with every price and is never inferred from the number.

  • LIST only where the Record recorded it as one. A site-wide discount, a promo code and a quietly lowered price all leave the marker unset, so an unmarked price is UNKNOWN rather than list.
  • Where either endpoint of a comparison is not LIST, no percentage is published. Two prices of unknown basis produce a difference that might be a reformulation or might be a Tuesday sale.
  • Price per serving appears in calculations, never in commercial_facts. It is arithmetic we did, with the operands attached, and calling it a manufacturer figure would be attributing our division to them.
  • Price and label often come from different dates on the same product. Both dates are in the response and neither stands for the other.

Every answer says what kind of answer it is

statusMeans
supportedThe Record answered and the evidence supports it. Publish it with its date.
partialPart of the answer exists and part does not. What is missing is named in limitations. Do not present the part you got as the whole.
staleThe Record holds an answer and its newest observation is old enough that we say so. Still true of that date, which is the only thing it was ever true of.
under_reviewSomething is being looked at and has not been confirmed. Never render this as a change.
ambiguousThe identifier matched more than one covered product. The candidates are in the response. Ask the person which one; do not pick.
unsupportedFormulaSignal does not cover this, or cannot answer this kind of question. A product being absent from coverage says nothing about that product.
refusedA gate stopped the request: authentication, scope, rate, budget, or a safety boundary. See the error code.

All of these are facts about the Record, not about the product. “FormulaSignal has no confirmed change on file” is a true sentence. “This product has never changed” is a different sentence and FormulaSignal never supports it.

What has to be true before something is a Signal

A page changing is not a finding. Between the two sit eleven pipeline stages and a person. A Signal reaches this API only when all of the following hold:

  • Two dated states that are actually comparable, in order, not sharing an observation date.
  • Both sources preserved, hashed, and linkable.
  • A delta that genuinely moved, not a renamed ingredient or a split delivery form.
  • A named human review with a review date.
  • Price rows carrying LIST basis on both endpoints before any percentage is stated.

An unreviewed candidate never reaches any external surface. An unapproved Signal id returns the same 404 as an invented one, on purpose: two different messages would tell a caller which change events exist while being withheld.

When the Record knows it cannot know

Some answers are limited by evidence that does not exist rather than by research nobody has done, and the Record distinguishes them. An evidence ceiling records what was tried, what was found, why it is insufficient, and the condition that would lift it. “Could not find” is not a permitted value.

This matters for an integration because a ceiling is stable information. A product held at a ceiling will not start answering tomorrow because you asked again.

When we are wrong

A finding can be amended or withdrawn. When that happens the Signal keeps its permanent address, keeps its release date so nothing resends, and says what happened. A withdrawn Signal publishes no deltas and still answers, carrying its withdrawal. Deleting it would falsify what an earlier edition said.

If you cache, key on record_version and re-fetch when it moves. If you have published something FormulaSignal later corrected, the corrected record is reachable at the same id.

What FormulaSignal is not

  • Not a lab. Everything here is what a label or a page declared. No product has been tested for what it contains.
  • Not medical advice. No capability answers whether a product is suitable for a person, and the question shape is refused rather than answered carefully.
  • Not the whole category. Coverage is a defined, counted set. A product being absent from it says nothing about that product.
  • Not a verdict. No overall score is published when a scoring component has no data, and comparison returns no winner.

THE CHECK WORTH WRITING ONCE

// Refuse to publish a value whose evidence you did not read.
function renderable(envelope) {
  if (envelope.status === "ambiguous") return { ask: envelope.candidates };
  if (envelope.status === "unsupported") return { say: "not covered" };
  return {
    values: envelope.verified_facts,
    calculated: envelope.calculations,   // label these as ours
    asOf: envelope.record_as_of,
    mustRepeat: envelope.limitations,    // never drop this
  };
}

The recipes show this applied to the jobs people actually build.