Skip to content

feat(workflow): freeze a pinned version as the public copy - #7853

Draft
yangzhang75 wants to merge 2 commits into
apache:mainfrom
yangzhang75:pin/2-service
Draft

feat(workflow): freeze a pinned version as the public copy#7853
yangzhang75 wants to merge 2 commits into
apache:mainfrom
yangzhang75:pin/2-service

Conversation

@yangzhang75

Copy link
Copy Markdown
Contributor

Part of #7828. Stacked on #7851 — until that merges this PR shows its commit too; the review here is the second commit, feat(workflow): freeze a pinned version as the public copy.

A public workflow follows the author's latest content, as publishing has always done. This adds the other state: the author pins the version they have now, and the public copy stops moving until they pin again.

What lands

is_public stays the on/off switch. published_content is the pin — NULL means following, non-NULL is the frozen copy.

WorkflowPublishService owns the two states and the moves between them (publish, pinLatest, unpin, unpublish, statusOf), and three endpoints expose them:

Endpoint Does
POST /workflow/pin/{wid} freezes the author's current version as the public copy; called again, moves the pin forward
DELETE /workflow/pin/{wid} drops the pin, back to following the latest
GET /workflow/publish-status/{wid} published, pinned, and whether a pin is holding edits back

Publishing and unpublishing move through the same service, so unpublishing drops the pin rather than leaving a private workflow carrying one. Re-publishing starts in the following state: coming back should not silently put old public content on show again.

Two paths narrowed so a pin can hold

Saving a workflow read the whole row and wrote it all back. Two consequences, both fixed here by writing only name, description and content:

  • a publish landing while a save was in flight was silently rolled back to what the save had read;
  • a request body could set the publish columns itself.

Creating a workflow clears those columns for the same reason.

Nothing on screen changes

No read path consults the pinned copy yet, and there is no UI. Every workflow is in the following state it is in today. The endpoints answer, and nothing calls them.

Tests

19 backend cases in WorkflowPublishSpec: the state machine (follow → pin → re-pin → unpin → unpublish → re-publish), the guards (no write access, not published, workflow missing), that a create cannot inject publish columns, and that a save, a collaborator's save and a rename all leave the publish state alone.

hasUnpublishedChanges compares the two copies as parsed JSON rather than as strings — the same graph can come back with its keys in another order, and reporting that as an edit is an alarm the author cannot clear. One case covers it.

yangzhang75 and others added 2 commits August 22, 2026 14:36
A public workflow follows the author's latest content today: every save reaches
the Hub immediately. Pinning a version as the public copy needs somewhere to keep
that copy, which is what these columns are.

`is_public` stays the on/off switch. `published_content` is the pin: NULL means
the workflow follows the author's latest, which is what every workflow does today,
so the migration changes nothing anyone can see. `published_name` and
`published_description` travel with it because a pin has to hold everything on
show, and `workflow_version` stores no metadata at all -- only content deltas.
`published_version_id` names the version row holding that copy, so the revision
panel can mark it and the author can restore it.

The copy is materialized rather than replayed from `workflow_version` because
those rows are reverse JSON-Patch deltas: serving a pinned workflow would mean
folding every newer patch back from the author's current content on each public
read, and a computed value is something the fulltext index cannot cover.

A CHECK constraint makes "private but pinned" unrepresentable, and a PGroonga
index mirrors the latest-content one so public search can match the frozen copy.

Adding columns changes the arity of the generated positional constructor, so the
three copy-producing paths (clone, duplicate, restore-a-version) now build their
POJO with setters -- which is also what stops a later column from silently
shifting a null into the wrong field.

Part of apache#7828.
A public workflow follows the author's latest content, as publishing has
always done. This adds the other state: the author pins the version they
have now, and the public copy stops moving until they pin again.

`is_public` stays the on/off switch; `published_content` is the pin, NULL
while following. `WorkflowPublishService` owns the two states, and three
endpoints expose them: POST and DELETE `/workflow/pin/{wid}` to pin and
unpin, GET `/workflow/publish-status/{wid}` for what the author is shown.
Publishing and unpublishing move through the same service, so unpublishing
drops the pin rather than leaving a private workflow carrying one.

Two paths are narrowed so a pin can hold. A save wrote the whole row back,
so a publish landing while a save was in flight was silently rolled back,
and a request body could set the publish columns itself; saves now write
only name, description and content. Creating a workflow clears the publish
columns for the same reason.

Nothing reads the pinned copy yet: every workflow is in the following
state it is in today, and nothing on screen changes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@github-actions github-actions Bot added engine ddl-change Changes to the TexeraDB DDL labels Aug 23, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Automated Reviewer Suggestions

Based on the git blame history of the changed files, we recommend the following reviewers:

  • Contributors with relevant context: @tanishqgandhi1908, @aglinxinyuan, @Ma77Ball
    You can notify them by mentioning @tanishqgandhi1908, @aglinxinyuan, @Ma77Ball in a comment.

@codecov-commenter

codecov-commenter commented Aug 23, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 91.46341% with 7 lines in your changes missing coverage. Please review.
✅ Project coverage is 91.89%. Comparing base (b7c33b0) to head (8f56d11).
⚠️ Report is 3 commits behind head on main.

Files with missing lines Patch % Lines
...shboard/user/workflow/WorkflowPublishService.scala 84.44% 1 Missing and 6 partials ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##               main    #7853      +/-   ##
============================================
+ Coverage     91.87%   91.89%   +0.02%     
- Complexity     4510     4517       +7     
============================================
  Files          1173     1174       +1     
  Lines         47350    47407      +57     
  Branches       5306     5319      +13     
============================================
+ Hits          43502    43565      +63     
+ Misses         2204     2191      -13     
- Partials       1644     1651       +7     
Flag Coverage Δ *Carryforward flag
access-control-service 81.00% <ø> (ø)
agent-service 98.62% <ø> (ø) Carriedforward from f8b0291
amber 88.45% <91.46%> (+0.07%) ⬆️
computing-unit-managing-service 73.67% <ø> (ø)
config-service 86.73% <ø> (ø)
file-service 75.74% <ø> (ø)
frontend 93.79% <ø> (ø) Carriedforward from f8b0291
notebook-migration-service 79.13% <ø> (ø)
pyamber 97.57% <ø> (ø) Carriedforward from f8b0291
workflow-compiling-service 77.19% <ø> (ø)

*This pull request uses carry forward flags. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions

Copy link
Copy Markdown
Contributor

⚠️ Benchmark changes need a look

🟢 0 better · 🔴 10 worse · ⚪ 5 noise (<±5%) · 0 without baseline

CI benchmark results are noisy; treat <±5% as noise unless repeated.

Dashboard · Run

config throughput MB/s latency max Δ latest / 7d
🔴 bs=10 sw=10 sl=64 504 0.308 19,291/26,321/26,321 us 🔴 +114.6% / 🔴 +83.0%
🔴 bs=100 sw=10 sl=64 1,232 0.752 82,153/90,442/90,442 us 🔴 +20.4% / 🟢 -16.7%
🔴 bs=1000 sw=10 sl=64 1,433 0.874 694,496/774,324/774,324 us 🔴 +6.4% / 🟢 +28.1%
Baseline details

Latest main b7c33b0 from 2026-08-22T12:41:18.215Z

config metric PR latest main 7d avg Δ latest Δ 7d
bs=10 sw=10 sl=64 throughput 504 tuples/sec 1,070 tuples/sec 833.79 tuples/sec -52.9% -39.6%
bs=10 sw=10 sl=64 MB/s 0.308 MB/s 0.653 MB/s 0.509 MB/s -52.8% -39.5%
bs=10 sw=10 sl=64 p50 19,291 us 8,990 us 11,864 us +114.6% +62.6%
bs=10 sw=10 sl=64 p95 26,321 us 12,633 us 14,381 us +108.4% +83.0%
bs=10 sw=10 sl=64 p99 26,321 us 13,861 us 18,035 us +89.9% +45.9%
bs=100 sw=10 sl=64 throughput 1,232 tuples/sec 1,420 tuples/sec 1,083 tuples/sec -13.2% +13.7%
bs=100 sw=10 sl=64 MB/s 0.752 MB/s 0.867 MB/s 0.661 MB/s -13.2% +13.7%
bs=100 sw=10 sl=64 p50 82,153 us 69,686 us 93,077 us +17.9% -11.7%
bs=100 sw=10 sl=64 p95 90,442 us 75,137 us 99,553 us +20.4% -9.2%
bs=100 sw=10 sl=64 p99 90,442 us 89,601 us 108,604 us +0.9% -16.7%
bs=1000 sw=10 sl=64 throughput 1,433 tuples/sec 1,455 tuples/sec 1,119 tuples/sec -1.5% +28.1%
bs=1000 sw=10 sl=64 MB/s 0.874 MB/s 0.888 MB/s 0.683 MB/s -1.6% +28.0%
bs=1000 sw=10 sl=64 p50 694,496 us 685,976 us 909,247 us +1.2% -23.6%
bs=1000 sw=10 sl=64 p95 774,324 us 727,444 us 952,561 us +6.4% -18.7%
bs=1000 sw=10 sl=64 p99 774,324 us 767,738 us 985,186 us +0.9% -21.4%
Raw CSV
config_idx,batch_size,schema_width,string_len,num_batches,total_ms,total_tuples,total_bytes,tuples_per_sec,mb_per_sec,lat_p50_us,lat_p95_us,lat_p99_us
0,10,10,64,20,396.97,200,128000,504,0.308,19291.45,26320.69,26320.69
1,100,10,64,20,1623.23,2000,1280000,1232,0.752,82152.55,90442.03,90442.03
2,1000,10,64,20,13959.17,20000,12800000,1433,0.874,694495.56,774324.26,774324.26

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ddl-change Changes to the TexeraDB DDL engine

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants