You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Publishing a workflow makes the author's live content public: every save reaches the Hub
immediately. An author who wants to keep experimenting has to choose between an unstable
public copy and not publishing at all, and nobody — author or reviewer — can answer "what
exactly is on the Hub right now?". Design discussion: #7128.
Goal
Let an author decide what the public sees, with exactly two choices:
Follow latest — exactly what Texera does today: the public sees the author's latest
content, updated on every save. Stays the default, so a workflow whose author never pins
behaves as it always has.
Pin current version — the public keeps seeing the version the author pinned. Later
edits stay in the working copy; pinning again is how those edits become public.
There is no third state.
Proposed Solution or Design
Design
Two states, not a library of published versions. The proposal in #7128 also let an author
point the public copy back at any earlier publication. That needs a picker listing every
publication with its date, its size and how it differs from the working copy, and a second
concept ("publication") layered on top of versions. It is dropped: once the author edits past
the pin, the pinned copy is still reachable two ways — the revision panel marks it
(Currently public) so it restores like any other version, and on the Hub the author can open
and clone it exactly like any other user.
Storage.is_public stays the on/off switch. Four columns on workflow carry the pin: published_version_id, published_content, published_name, published_description. A NULL published_content is the following state, so deploying the migration changes nothing anyone
can see. A CHECK constraint makes "private but pinned" unrepresentable.
The copy is materialized rather than replayed from workflow_version for two reasons. Those
rows are reverse JSON-Patch deltas, so serving a pinned workflow would mean folding every
newer patch back from the author's current content on each public read — a workflow in
testing already carries 49 version rows, and that number only grows. And a replayed value is
something the PGroonga fulltext index cannot cover, so public search would either miss pinned
workflows or match them against content the author has not published. The name and the
description have to be stored for a third reason: workflow_version holds no metadata at all,
only content deltas.
One anchor per pin. Pinning also inserts a workflow_version row carrying the identity
patch, so replaying it returns exactly what was published however many edits pile up on top.
No existing row can stand in: a version row replays to the content as it was before the
change it records, so none of them reproduces the state at the moment of pinning. That row is
what the revision panel marks and what the author restores; pinning again with nothing edited
reuses it rather than adding a twin, and the insert runs under SELECT … FOR UPDATE so two
pins racing cannot leave two anchors for one publication.
The graph, the title and the description freeze together. Freezing only the graph would let
a rename reach the public behind the pin, and would let a report about a title be answered by
editing the title. Every public read path resolves the three as a group, so none of them can be
the one that gets forgotten.
Sharing is unaffected. A user granted access to the workflow always tracks the author's
latest, pin or no pin. Only viewers who arrive because the workflow is public are held at the
frozen copy — including the author when they are looking at the Hub.
Rollout. The panel ships behind gui.workflow-workspace.version-pinning-enabled, default
false, flipped in the last sub-issue. Everything before it is invisible: the endpoints exist but
nothing in the UI reaches them, and every read path behaves as it does today until a pin exists —
and no pin can exist while the control is hidden.
The name, the description and the view freeze with the graph in #7939, where the read paths that
serve them live, rather than alongside the anchor.
Follow-ups (out of scope here)
Moderation. A pin a report imposes is one the author cannot move or drop, which needs a
column marking it and a guard on both pin and unpin. It belongs with the report flow, which is
also where it gets decided whether a report freezes the public copy at all.
Feature Summary
Background
Publishing a workflow makes the author's live content public: every save reaches the Hub
immediately. An author who wants to keep experimenting has to choose between an unstable
public copy and not publishing at all, and nobody — author or reviewer — can answer "what
exactly is on the Hub right now?". Design discussion: #7128.
Goal
Let an author decide what the public sees, with exactly two choices:
content, updated on every save. Stays the default, so a workflow whose author never pins
behaves as it always has.
edits stay in the working copy; pinning again is how those edits become public.
There is no third state.
Proposed Solution or Design
Design
Two states, not a library of published versions. The proposal in #7128 also let an author
point the public copy back at any earlier publication. That needs a picker listing every
publication with its date, its size and how it differs from the working copy, and a second
concept ("publication") layered on top of versions. It is dropped: once the author edits past
the pin, the pinned copy is still reachable two ways — the revision panel marks it
(Currently public) so it restores like any other version, and on the Hub the author can open
and clone it exactly like any other user.
Storage.
is_publicstays the on/off switch. Four columns onworkflowcarry the pin:published_version_id,published_content,published_name,published_description. A NULLpublished_contentis the following state, so deploying the migration changes nothing anyonecan see. A CHECK constraint makes "private but pinned" unrepresentable.
The copy is materialized rather than replayed from
workflow_versionfor two reasons. Thoserows are reverse JSON-Patch deltas, so serving a pinned workflow would mean folding every
newer patch back from the author's current content on each public read — a workflow in
testing already carries 49 version rows, and that number only grows. And a replayed value is
something the PGroonga fulltext index cannot cover, so public search would either miss pinned
workflows or match them against content the author has not published. The name and the
description have to be stored for a third reason:
workflow_versionholds no metadata at all,only content deltas.
One anchor per pin. Pinning also inserts a
workflow_versionrow carrying the identitypatch, so replaying it returns exactly what was published however many edits pile up on top.
No existing row can stand in: a version row replays to the content as it was before the
change it records, so none of them reproduces the state at the moment of pinning. That row is
what the revision panel marks and what the author restores; pinning again with nothing edited
reuses it rather than adding a twin, and the insert runs under
SELECT … FOR UPDATEso twopins racing cannot leave two anchors for one publication.
The graph, the title and the description freeze together. Freezing only the graph would let
a rename reach the public behind the pin, and would let a report about a title be answered by
editing the title. Every public read path resolves the three as a group, so none of them can be
the one that gets forgotten.
Sharing is unaffected. A user granted access to the workflow always tracks the author's
latest, pin or no pin. Only viewers who arrive because the workflow is public are held at the
frozen copy — including the author when they are looking at the Hub.
Rollout. The panel ships behind
gui.workflow-workspace.version-pinning-enabled, defaultfalse, flipped in the last sub-issue. Everything before it is invisible: the endpoints exist but
nothing in the UI reaches them, and every read path behaves as it does today until a pin exists —
and no pin can exist while the control is hidden.
Sub-issues (each → one PR)
sql/updates/47.sql) → feat(workflow): add the published-copy columns #7851 mergedPOST/DELETE /workflow/pin/{wid},GET /workflow/publish-status/{wid}→ feat(workflow): freeze a pinned version as the public copy #7853The name, the description and the view freeze with the graph in #7939, where the read paths that
serve them live, rather than alongside the anchor.
Follow-ups (out of scope here)
column marking it and a guard on both pin and unpin. It belongs with the report flow, which is
also where it gets decided whether a report freezes the public copy at all.
Affected Area
Workflow UI, Hub, Storage / Metadata