Skip to content

feat(workflow): serve the pinned copy to public viewers - #7856

Closed
yangzhang75 wants to merge 3 commits into
apache:mainfrom
yangzhang75:pin/3-read-paths
Closed

feat(workflow): serve the pinned copy to public viewers#7856
yangzhang75 wants to merge 3 commits into
apache:mainfrom
yangzhang75:pin/3-read-paths

Conversation

@yangzhang75

Copy link
Copy Markdown
Contributor

Part of #7828. Stacked on #7853 — until the earlier ones merge this PR shows their commits too; the review here is the last commit, feat(workflow): serve the pinned copy to public viewers.

#7853 gave a workflow two copies: the author's working copy, and the frozen one on public show. Nothing read the frozen one. This routes every read that serves a viewer without granted access through it.

The seam

WorkflowAccessResource.hasGrantedAccess(wid, uid) — granted access, as opposed to being able to read a workflow only because it is public. Owner, shared user and project member keep tracking the author's latest, because sharing is not publishing. Everyone else is here because the workflow is public, and gets the public copy.

WorkflowPublishService.publicCopyOf returns name, description and content as a group, so no surface can pick up the published graph under a title the author has not published.

Name and description freeze with the graph

They are as public as the graph is. If only the graph froze, a report about a title could be answered by editing the title, while the pinned copy still advertised it — the freeze would hold the one part nobody complained about.

Routed through it

Path A viewer without granted access now gets
opening a workflow the pinned content
the hub's read (/publicised/{wid}) the pinned name, description and content
Clone a copy of what the hub showed them — for the author too, whose latest is already open in their editor
Duplicate the same, title and description included
/workflow_name, /workflow_description the frozen values
the size a listing shows measured on the copy that listing opens

A workflow that follows the author's latest — every workflow today — is served exactly what it is served now.

Tests

+18 backend cases: the published version reaching a stranger while the author keeps their own; a collaborator tracking the author's latest as they keep editing; clone and duplicate taking the published copy, including its name and description; a private workflow still cloning its working copy; the size of each of the three cases; and that a public copy of a workflow that is not public is refused rather than falling through.

yangzhang75 and others added 3 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>
With a version pinned, a workflow has two copies: the author's working
copy and the frozen one on public show. This routes every read that
serves a viewer without granted access through the frozen copy, and
freezes the name and description with the graph.

`WorkflowPublishService.publicCopyOf` returns the three fields as a
group, so a surface cannot pick up the published graph under a title the
author has not published; `WorkflowAccessResource.hasGrantedAccess` is
the seam that decides which copy a caller gets. Granted access -- owner,
shared, project member -- keeps tracking the author's latest, because
sharing is not publishing.

Name and description freeze because they are as public as the graph: if
only the graph froze, a report about a title could be answered by editing
the title while the pinned copy still advertised it.

Routed through it: opening a workflow, the hub's read, Clone, Duplicate,
`/workflow_name`, `/workflow_description` and the size a listing shows.
A workflow that follows the author's latest -- every workflow today --
is served exactly what it is served now.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@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, @xuang7, @aglinxinyuan
    You can notify them by mentioning @tanishqgandhi1908, @xuang7, @aglinxinyuan in a comment.

@github-actions

Copy link
Copy Markdown
Contributor

⚠️ Benchmark changes need a look

🟢 0 better · 🔴 15 worse · ⚪ 0 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 420 0.256 23,314/29,116/29,116 us 🔴 +159.3% / 🔴 +102.5%
🔴 bs=100 sw=10 sl=64 844 0.515 116,943/159,631/159,631 us 🔴 +112.5% / 🔴 +60.3%
🔴 bs=1000 sw=10 sl=64 965 0.589 1,034,877/1,166,270/1,166,270 us 🔴 +60.3% / 🔴 +22.4%
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 420 tuples/sec 1,070 tuples/sec 833.79 tuples/sec -60.7% -49.6%
bs=10 sw=10 sl=64 MB/s 0.256 MB/s 0.653 MB/s 0.509 MB/s -60.8% -49.7%
bs=10 sw=10 sl=64 p50 23,314 us 8,990 us 11,864 us +159.3% +96.5%
bs=10 sw=10 sl=64 p95 29,116 us 12,633 us 14,381 us +130.5% +102.5%
bs=10 sw=10 sl=64 p99 29,116 us 13,861 us 18,035 us +110.1% +61.4%
bs=100 sw=10 sl=64 throughput 844 tuples/sec 1,420 tuples/sec 1,083 tuples/sec -40.6% -22.1%
bs=100 sw=10 sl=64 MB/s 0.515 MB/s 0.867 MB/s 0.661 MB/s -40.6% -22.1%
bs=100 sw=10 sl=64 p50 116,943 us 69,686 us 93,077 us +67.8% +25.6%
bs=100 sw=10 sl=64 p95 159,631 us 75,137 us 99,553 us +112.5% +60.3%
bs=100 sw=10 sl=64 p99 159,631 us 89,601 us 108,604 us +78.2% +47.0%
bs=1000 sw=10 sl=64 throughput 965 tuples/sec 1,455 tuples/sec 1,119 tuples/sec -33.7% -13.7%
bs=1000 sw=10 sl=64 MB/s 0.589 MB/s 0.888 MB/s 0.683 MB/s -33.7% -13.7%
bs=1000 sw=10 sl=64 p50 1,034,877 us 685,976 us 909,247 us +50.9% +13.8%
bs=1000 sw=10 sl=64 p95 1,166,270 us 727,444 us 952,561 us +60.3% +22.4%
bs=1000 sw=10 sl=64 p99 1,166,270 us 767,738 us 985,186 us +51.9% +18.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,476.15,200,128000,420,0.256,23314.39,29115.99,29115.99
1,100,10,64,20,2370.91,2000,1280000,844,0.515,116942.54,159631.17,159631.17
2,1000,10,64,20,20730.80,20000,12800000,965,0.589,1034876.78,1166270.02,1166270.02

@codecov-commenter

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 89.60000% with 13 lines in your changes missing coverage. Please review.
✅ Project coverage is 91.88%. Comparing base (b7c33b0) to head (c51be48).
⚠️ Report is 3 commits behind head on main.

Files with missing lines Patch % Lines
...shboard/user/workflow/WorkflowPublishService.scala 80.64% 3 Missing and 9 partials ⚠️
...rce/dashboard/user/workflow/WorkflowResource.scala 98.33% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##               main    #7856      +/-   ##
============================================
+ Coverage     91.87%   91.88%   +0.01%     
- Complexity     4510     4517       +7     
============================================
  Files          1173     1174       +1     
  Lines         47350    47434      +84     
  Branches       5306     5325      +19     
============================================
+ Hits          43502    43587      +85     
+ Misses         2204     2192      -12     
- Partials       1644     1655      +11     
Flag Coverage Δ *Carryforward flag
access-control-service 81.00% <ø> (ø)
agent-service 98.62% <ø> (ø) Carriedforward from 8f56d11
amber 88.44% <89.60%> (+0.06%) ⬆️
computing-unit-managing-service 73.67% <ø> (ø)
config-service 86.73% <ø> (ø)
file-service 75.74% <ø> (ø)
frontend 93.79% <ø> (ø) Carriedforward from 8f56d11
notebook-migration-service 79.13% <ø> (ø)
pyamber 97.57% <ø> (ø) Carriedforward from 8f56d11
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.

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