PreFlight: Outcome (feedback)
Outcome — the ten-second node that decides whether your content rules were ever true
- status
What it's for
The other two nodes in this pack hand you a prediction. PreFlight: Outcome is the one that finds out whether the prediction was any good - days later, after you actually posted the thing and watched what happened to it.
It records what a platform did to a published post: normal reach, suppressed, or taken down. That's it. No image, no model, no folder to point at - outcomes attach to records, not files. It takes about ten seconds to fill in, and without it PreFlight is just a plausible-looking opinion generated by a rules file nobody has ever tested. The pack's rules are explicitly hypotheses about how platforms behave; this node is the only mechanism that turns them into something you've actually checked.
How it works
Preflight's Report node, when log_prediction is on, appends a line to ComfyUI/output/preflight/feedback.jsonl describing each prediction: the observations, a caption excerpt, which rules fired, the per-platform verdicts, and an eight-character record id. Outcome appends outcomes to the same file, keyed by that id.
The record dropdown is built by reading that store when the node definitions load - newest first, up to fifty - and each entry is labelled from the record itself, not from a filename convention:
a3f9c2d1 · 07-24 14:02 · IG:RISK TT:BLOCK X:OK · bikini/beach_pool · "summer drop 🌞 li…"
That line is the whole UX, and a good one: predicted verdicts, next to what the content actually was, while you decide what happened to it.
The node is an output node - terminal, nothing to wire out of it - and it's deliberately cache-busted. ComfyUI normally skips a node whose inputs haven't changed; this one returns a fresh token every queue so repeated runs with identical inputs still write. That exists so you can log one platform per queue without the second and third writes being silently swallowed.
Then, at the end of the loop:
python calibrate.py /path/to/ComfyUI/output/preflight/feedback.jsonl
It prints two tables and modifies nothing. Per platform: how often reality landed inside the predicted range, above the worst case (under-predicted - the dangerous kind), or below the best case (over-predicted - you lost reach on content that was fine). Per rule: for each rule that fired, how many posts and what came back. The second table is the useful one - if base.bikini fired thirty times on Instagram and twenty-eight came back clean, that rule is too harsh, and you edit rules.py and bump the engine version. Nothing self-tunes: it's a log, a join, and a human editing rules.
The inputs that matter
record- the prediction you're scoring, newest first. If it's not in the list, the list is stale.platform-instagram,tiktokorx. Log each platform separately; three queues for one record, one per platform.result-clean(normal reach),demoted(suppressed, flagged, or For-You-Feed-ineligible),removed(taken down).record_id_override- paste an id here and it's used instead of the dropdown selection, skipping the list entirely.
The output is a single status string, e.g. logged: a3f9c2d1 instagram=demoted. Errors come back in that same string - it never raises and never breaks your graph, so a bad id gives you a message instead of a red outline.
Install
Nothing extra. If you've installed the pack, you have it:
cd ComfyUI/custom_nodes
git clone https://github.com/0xBeycan/ComfyUI-PreFlight
cd ComfyUI-PreFlight && pip install -r requirements.txt
Restart, and it's under the PreFlight category. The pack ships example_workflows/preflight_outcome.json, which is exactly the right shape: a single Outcome node, opened days after posting, in a graph with nothing else in it.
Where it goes wrong
"no records yet", or your newest prediction isn't in the dropdown. The list is built when node definitions load, so predictions created since then don't exist yet. Refresh the browser tab, or hit ComfyUI's Refresh button. The escape hatch is record_id_override - the id is printed in the Report summary as record: a3f9c2d1, so paste that.
Status says no record selected. You picked the no records yet placeholder instead of a record, and left the override empty. Nothing was written.
You're logging only the platform that went wrong. Then your calibration is a pile of failures, and every rule looks too soft. Log the boring clean outcomes too - those are the data points that tell you a rule is overfiring.
Your demoted threshold drifts. This is the real trap, and the node's own tooltip warns about it. "Demoted" has no clean definition: a flagged account, a clear reach collapse, FYF ineligibility. Pick one personal heuristic - say, "more than 40% below my median reach" - and apply it every single time. Inconsistent labelling poisons the calibration table worse than no data at all, because it looks like signal.
You expect the store to be tidy. It's append-only JSONL in your output folder. Fine to back up, fine to read, and predictions with no outcome cost nothing - they're just skipped by the join.
Inputs (4)
| Name | Type | Default | Description |
|---|---|---|---|
| record | COMBO | The prediction to attach an outcome to (newest first). Refresh to update. | |
| platform | COMBO | Which platform this outcome is for. | |
| result | COMBO | clean | clean = normal reach; demoted = suppressed / FYF-ineligible / flagged; removed = taken down. Pick one fixed personal heuristic for 'demoted' and stick to it. |
| record_id_override | STRING | If set, this id is used instead of the list selection (bypasses list staleness). |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| status | STRING | — |