workflow-platform · branch core-decoupling

The human-review gate stopped being a screen for one customer's blog posts

Same run, same parked step, same real app in Chrome — one build apart. The gate is where the product's one irreversible decision is made, and it used to be hardcoded to an SEO article. Now it presents whatever the step produced.

The gate

before The old review drawer: a title, an Open article button, a remarks box and two buttons.
Everything the operator gets about the thing they are approving: a button. The drawer took article_html, judge and validate by name — and judge/validate have not existed since the monolithic ai block was deleted, so they rendered as nothing at all. No way into the sub-workflow either: this was the one drawer that never drew the drill-in button.
after The new review drawer: a drill-in button, the article's title, meta description, category, slug and cover prompt, an Open content button, remarks and the two decision buttons.
The evidence the step attached — title, meta description, category, slug, cover prompt — then the artefact itself, then the decision. Plus the way inside: Open sub-workflow: write_seo_article, to look at how the draft was produced before pressing Send back.

The artefact itself

The article open in a modal, rendered as HTML with headings and paragraphs.
Opened, rendered — never as markdown source.
The same modal in dark mode.
Both themes are measured by the browser suite, including contrast.

Two subtractions keep the article legible

Behind it: the engine forgot what an article is

Look at the graph in either shot — write_article → article_meta → save_article. Storing the approved article is a database_insert step in the workflow now. It used to be an Article ORM model inside the engine, a table created on every install of a general-purpose automation platform, and a heuristic that scanned a finished run for "the first output with a slug".

That also fixes a long-standing asymmetry: persistence hung off the approve path only, so a run that finished without a gate stored nothing — after its publishing dispatch had already fired. A step runs wherever the workflow puts it.