Verdicts and policy
How the versioned policy turns rule outcomes into a verdict, why UNKNOWN never passes, and how fingerprints, diffs and new versions work.
On this page
A verdict is the result of running one security's data through your policy: a versioned set of written rules with numeric thresholds. The evaluator is pure. The same inputs and the same policy version always produce the same verdict, the same rule outcomes and the same fingerprint. A language model can explain a verdict afterward; it never computes one.
This page explains the mechanism. The live thresholds your policy uses right now are listed on Strategy rules.
Rule outcomes#
Every evaluation produces a list of rule outcomes. Each outcome has:
| Field | Meaning |
|---|---|
id |
Stable identifier, for example quality.solvency or gate.entry. |
label |
Human name shown in the app. |
severity |
How the rule can affect the verdict (below). |
status |
What the rule found (below). |
detail |
One sentence with the actual numbers. |
observed |
The measured value, or null when unknown. |
threshold |
The threshold it was compared with. |
The rule that decided the verdict is called the binding rule. It is moved to the top of the list, and the verdict summary is built from it.
Severities#
| Severity | Effect |
|---|---|
hard |
Quality and size gates. A fail makes the verdict RED, or FLAGGED for filing problems. |
zone |
The entry gate, scaled to 14-day ATR. ATR under the floor makes the verdict DORMANT; price above the gate makes it YELLOW. |
cap |
Added in policy v3. A fail holds a would-be buy at YELLOW with no new money: a large fall on the last report, a portfolio limit (held name, consumer discretionary, rate-sensitive, casinos, miners, Latin American financials) or the crash cap after this buy. |
soft |
Sizing and timing advice. Changes the suggested position size, never the verdict. |
manual |
Judgment checks. Investi attaches evidence (the legal scan, the guidance suggestion) and your saved answer; without an answer they are never mistaken for a pass. |
info |
Context every verdict carries: earnings date, exit target, the 7-day estimate, the bid-ask spread when the feed has it. |
Statuses#
| Status | Meaning |
|---|---|
PASS |
The rule's condition is met. |
FAIL |
The rule's condition is not met. |
WARN |
Within limits but in a watch band, or a sizing concern. |
UNKNOWN |
The data needed to decide is missing. |
MANUAL |
Requires your judgment. |
INFO |
Context only. |
What the rules check#
| Group | Rule ids | Severity |
|---|---|---|
| Quality: can it go bankrupt? | quality.solvency (free cash flow and trailing earnings together, with capex: negative free cash flow with positive earnings is a WARN that caps at YELLOW, negative operating cash flow fails), quality.leverage (net debt to EBITDA), quality.filings (restatement, auditor change, late filing or listing notice in recent SEC filings) |
hard |
| Size and liquidity | size.market_cap, size.liquidity (the contemplated position as a share of average daily dollar volume, also checked against the thinnest session of the month) |
hard |
| Entry gate | gate.atr (14-day ATR against the floor and bands), gate.entry (distance above the 52-week low against the ATR-scaled gate) |
zone |
| Caps | timing.earnings_reaction (fell more than 10% across the last report within 10 sessions: newly revealed, wait 5-10 sessions), book.second_lot, book.consumer_discretionary, book.rate_sensitive, book.gaming, book.miners, book.latam_financials, book.crash_cap |
cap |
| Stability and timing | stability.new_lows, stability.low_date, stability.roll_off, regime.state, size.half_atr, timing.earnings_blackout (a working buy resting through a report), book.wash_sale (a loss sale in the last 30 days) |
soft |
| Manual | manual.kodak (business model intact), manual.legal (live legal or regulatory event, with the legal scan's evidence), manual.revealed (known versus newly revealed, with a suggestion from the guidance change), and the bid-ask spread when the delayed feed lacks it |
manual |
| Context | info.earnings, info.exit, info.estimate, info.spread |
info |
How the verdict is decided#
The evaluator walks this list top to bottom and stops at the first match:
| Order | Verdict | When |
|---|---|---|
| 1 | INSUFFICIENT |
No price (last price or 52-week low missing), or three or more hard rules are UNKNOWN. |
| 2 | FLAGGED |
The filings rule failed. No new money while it stands. |
| 3 | RED |
Any other hard rule failed, or you answered the Kodak or legal check FAIL. The binding rule is the first failure in the order solvency, leverage, market cap, liquidity, Kodak, legal. |
| 4 | DORMANT |
14-day ATR is under the floor, or the name is held to half size by its market cap and ATR is too low to reach the half-size exit target. |
| 4a | YELLOW, no new money |
A cap: solvency WARN on negative free cash flow, the earnings reaction, your "newly revealed" answer, a portfolio limit or the crash cap. The first in that order binds; size is NONE and no trigger price is given. |
| 5 | YELLOW |
Price is above the entry gate. The report gives the trigger price at which the gate clears. |
| 6 | YELLOW |
The market regime is RED: price alerts only, no new full-size buys. |
| 7 | YELLOW |
A hard rule, the ATR rule or the entry gate is UNKNOWN: "Verify before buying." |
| 8 | GREEN |
Everything above passed. The summary says full or half size and reminds you to complete the manual checks. |
Soft rules never change the verdict. Each soft concern (a market cap in the half-size band, too many recent new lows, a low set recently, a YELLOW market regime) adds a size reason, and any size reason makes the suggested size HALF. Size is reported as FULL or HALF only for GREEN and YELLOW verdicts, and NONE otherwise.
UNKNOWN is a real answer#
Every input to the evaluator can be missing, and missing is never treated as a pass.
- A rule without the data it needs reports UNKNOWN with a sentence saying what is missing, for example "Net debt not derivable from XBRL filings."
- With nothing failing, one or two unknown hard rules hold the verdict at YELLOW with a list of what to verify. Three or more make it INSUFFICIENT.
- MANUAL rows never count toward a pass. A GREEN verdict still asks you to complete them.
- In the report, unknowns get their own list next to the bull and bear lists.
The policy version tag#
Every evaluation records the policy that produced it as a tag:
<policy id>@v<version>#<first 8 hex characters of the thresholds fingerprint>For example quality-velocity@v3#1f0c9a2e. The version number tells you which saved revision of your policy ran. The hash suffix is computed from the thresholds themselves (merged with the defaults), so two evaluations with the same tag used exactly the same numbers.
The default policy is the Quality-Velocity Framework v5, id quality-velocity. Evaluations stored under an earlier policy keep their original tag.
The input fingerprint#
Each evaluation also carries an inputFingerprint: a 16-character hash of the policy tag plus the evaluator's inputs. If neither the policy nor any material input changes, the fingerprint does not change.
Inputs are normalized before hashing so trivial noise does not register as a change:
- The evaluation time and the last price are left out. Price alone never makes research "changed"; rule outcomes do, through the distance above the low.
- Distance above the low and ATR are rounded. Dollar volume, market cap and position cost are compared by order of magnitude.
- The spread and the day counts to and from earnings are left out; the earnings date itself is kept.
- The market regime is reduced to its state, and the age of the 52-week low to a recent, middle or mature bucket.
- The dataset versions the inputs came from (such as the latest daily bar date and the latest filing accession) are included.
Investi saves a new evaluation revision only when the fingerprint changes. Revisions are immutable and linked to the one before. The screener uses the same fingerprint to decide whether a name is CHANGED or UNCHANGED; see Candidate states.
Verdict diffs and the change log#
When a security is evaluated again, the new result is compared with the previous stored revision. Every rule whose status differs (including rules that appeared or disappeared) is listed with its old and new status. A one-sentence summary is written:
| Situation | Sentence |
|---|---|
| Policy id changed | "Re-evaluated under ... (was ...): YELLOW → RED because ..." citing the new binding rule. |
| Verdict changed | "YELLOW → RED because ..." citing the rules that worsened to FAIL or WARN, or if none, those that improved to PASS. |
| Only rules changed | "Verdict unchanged (GREEN); 2 rules changed." |
| Nothing changed | "No change (GREEN)." |
The first evaluation of a security reads "First analysis under this record." The sentence and rule changes appear in the report's change log and on the research page; see Research.
Saved answers to the judgment checks#
On a company page each judgment check (Kodak test, legal event, known vs newly revealed) has an Answer control: Pass, Fail or Unknown (for the revealed check: Known, Newly revealed or Unknown), a note, and a date it counts until, 90 days by default. Saved answers feed the verdict until that date and the rule reads "Your answer: Pass until 2027-02-02". A Kodak or legal FAIL makes the verdict RED; a newly revealed answer caps it at YELLOW; a known answer saved after the report lifts the earnings-reaction cap. A legal PASS saved before newer evidence arrived does not hide that evidence: the rule turns WARN and asks again. Answers are also available at GET/PUT/DELETE /api/v1/securities/{ticker}/checks and through the MCP tools get_manual_checks and set_manual_check.
Overrides#
You can record your own verdict (GREEN, YELLOW, RED, FLAGGED or DORMANT) against an evaluation with a written rationale of at least 8 characters, through POST /api/v1/securities/{ticker}/override. The computed verdict is never replaced; it is kept alongside your override and rationale.
Position signals#
For a security you own, the evaluation adds a position signal based on your unrealized return:
| Signal | When |
|---|---|
REVIEW_PROFIT |
Unrealized return is at or above the exit target for your position. |
REVIEW_RISK |
Unrealized return is at or below the policy's no-new-money loss level. |
HOLD |
Anything in between. |
The signal is null when you do not hold the security. Like the verdict, it is research, not an instruction to sell.
Saving a new policy version#
Policies are versioned and immutable. Saving never edits a policy; it writes a new version.
- In the app: edit thresholds and hard rules in Settings and save. See Settings.
- Over HTTP:
PUT /api/v1/policywith a JSON body containingthresholds(any subset of threshold fields, each validated against its allowed range) and optionallyhardRules(up to 50).
PUT /api/v1/policy
Content-Type: application/json
{ "thresholds": { "earningsSoonDays": 10 } }Before saving, the merged thresholds are checked for consistency, for example that the leverage watch level sits under the leverage ceiling, that the ATR bands increase, and that entry gates widen as ATR rises. An inconsistent set is refused with 400 inconsistent_thresholds and a sentence for each problem.
The value in the example is illustrative, not a recommendation. The new version number is one higher than any version you have saved before, and always above the default policy's version. Thresholds you leave out are carried over from the current version (thresholds added to the engine since your last save come from the defaults), and so are hard rules if you omit hardRules. Each save is recorded in the audit log.
Saving requires the signed-in app session. Requests made with an API token are refused with 403 session_required ("Strategy rules can only be changed in the Investi app"), so no integration can quietly change your rules. Reading the current policy with GET /api/v1/policy works with the research:read scope.
After a save, every new evaluation carries the new version tag, so every screener candidate is marked CHANGED until it is analyzed under the new policy.
Hard rules#
Hard rules are personal exclusions stored with the policy: a sector, an industry containing a word, a ticker, a minimum market cap, or a minimum price. A name that matches one is marked BLOCKED in the screener and skipped by the research queue. They do not change the computed verdict.