Skip to content

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

Merged
aglinxinyuan merged 1 commit into
apache:mainfrom
yangzhang75:pin/3-read-paths
Oct 15, 2026
Merged

aglinxinyuan merged 1 commit into
apache:mainfrom
yangzhang75:pin/3-read-paths

Conversation

@yangzhang75

@yangzhang75 yangzhang75 commented Sep 17, 2026 •

Copy link
Copy Markdown
Contributor

What changes were proposed in this PR?

With a version pinned, a workflow has two copies. This routes every read that serves a viewer
without granted access through the frozen one.

  • The seam — WorkflowAccessResource.hasGrantedAccess(wid, uid): granted access, as opposed
    to being able to read a workflow only because it is public. An owner or a shared user keeps
    tracking the author's latest, because sharing is not publishing. Everyone else is here only
    because the workflow is public, and gets the public copy.
  • One copy, not four fields — WorkflowPublishService.PublicCopy carries the name, the
    description, the content and the default view together, and publicCopyOf hands them out as a
    group, so no surface can serve the published graph under a title the author never published, or
    open a form view over a copy whose content carries no form.
  • Routed through it — opening a workflow, the hub's read of a public workflow, Clone,
    Duplicate, /workflow_name, /workflow_description, and the size a listing shows.
  • The revision history is a door into the same room. Replaying a version folds deltas back
    from the author's current content, so listing or checking out versions would hand a public
    viewer the drafts the pin is holding back. canReadHistory keeps the history open to anyone
    with granted access, and to everyone while nothing is pinned — the public copy is then the
    author's latest and its history is the history of what everyone can already see.

A workflow that follows the author's latest — every workflow today — is served exactly what it
is served now.
publicCopyOf returns the working copy when nothing is frozen, so with no UI to
pin from yet (that arrives later in the series), nothing anyone can see changes.

Any related issues, documentation, discussions?

Closes #7939
Part of #7828. Design discussion: #7128. Builds on #7853, now merged.

How was this PR tested?

22 new cases in WorkflowPublishSpec (54 in the suite, 540 in the dashboard package):

  • the published version reaching a stranger while the author keeps their own working copy;
  • opening a pinned workflow serving the whole copy — its own title, description and view — and
    the author still opening everything they have;
  • a collaborator with granted read access tracking the author's latest as they keep editing;
  • clone and duplicate taking the published copy, metadata included, while a private workflow
    still clones its working copy and a copy starts with no publish state of its own;
  • the size each case reports;
  • the revision history: a public viewer is refused while a pin is in place, a collaborator is
    not, and a public workflow with nothing pinned keeps the history it has today;
  • a public copy of a workflow that is not public being refused rather than falling through.

The history guard was checked by mutation: restoring hasReadAccess turns the leak case red,
and the case was written from a reproduction — a stranger retrieving a version of a pinned
workflow and getting back an unpublished draft.

scalafmtCheckAll clean.

Was this PR authored or co-authored using generative AI tooling?

Generated-by: Claude Code (Opus 5)

🤖 Generated with Claude Code

@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: @aglinxinyuan
    You can notify them by mentioning @aglinxinyuan in a comment.

@github-actions

github-actions Bot commented Sep 17, 2026 •

Copy link
Copy Markdown
Contributor

⚠️ Benchmark changes need a look

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

Compared against main 6a29c59 benchmarked on this same runner, so the delta is largely free of cross-runner hardware noise. The "7d avg" column still reflects the gh-pages dashboard. Treat <±5% as noise unless repeated.

Dashboard · Run

config throughput MB/s latency max Δ latest / 7d
🟢 bs=10 sw=10 sl=64 458 0.28 21,391/29,240/29,240 us 🟢 -17.8% / 🔴 +86.0%
🔴 bs=100 sw=10 sl=64 947 0.578 100,584/156,667/156,667 us 🔴 +17.8% / 🔴 +48.7%
🟢 bs=1000 sw=10 sl=64 1,109 0.677 899,001/941,507/941,507 us 🟢 -8.6% / 🟢 -8.7%
Baseline details

Latest main 6a29c59 from same runner

config metric PR latest main 7d avg Δ latest Δ 7d
bs=10 sw=10 sl=64 throughput 458 tuples/sec 436 tuples/sec 790.31 tuples/sec +5.0% -42.0%
bs=10 sw=10 sl=64 MB/s 0.28 MB/s 0.266 MB/s 0.482 MB/s +5.3% -42.0%
bs=10 sw=10 sl=64 p50 21,391 us 21,450 us 12,375 us -0.3% +72.9%
bs=10 sw=10 sl=64 p95 29,240 us 35,571 us 15,719 us -17.8% +86.0%
bs=10 sw=10 sl=64 p99 29,240 us 35,571 us 19,058 us -17.8% +53.4%
bs=100 sw=10 sl=64 throughput 947 tuples/sec 962 tuples/sec 1,025 tuples/sec -1.6% -7.6%
bs=100 sw=10 sl=64 MB/s 0.578 MB/s 0.587 MB/s 0.626 MB/s -1.5% -7.6%
bs=100 sw=10 sl=64 p50 100,584 us 101,428 us 98,759 us -0.8% +1.8%
bs=100 sw=10 sl=64 p95 156,667 us 132,990 us 105,327 us +17.8% +48.7%
bs=100 sw=10 sl=64 p99 156,667 us 132,990 us 120,491 us +17.8% +30.0%
bs=1000 sw=10 sl=64 throughput 1,109 tuples/sec 1,108 tuples/sec 1,059 tuples/sec +0.1% +4.7%
bs=1000 sw=10 sl=64 MB/s 0.677 MB/s 0.676 MB/s 0.646 MB/s +0.1% +4.7%
bs=1000 sw=10 sl=64 p50 899,001 us 894,071 us 965,886 us +0.6% -6.9%
bs=1000 sw=10 sl=64 p95 941,507 us 1,030,449 us 1,007,533 us -8.6% -6.6%
bs=1000 sw=10 sl=64 p99 941,507 us 1,030,449 us 1,031,622 us -8.6% -8.7%
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,436.66,200,128000,458,0.280,21390.84,29239.93,29239.93
1,100,10,64,20,2111.75,2000,1280000,947,0.578,100583.78,156666.52,156666.52
2,1000,10,64,20,18039.98,20000,12800000,1109,0.677,899001.42,941506.61,941506.61

@codecov-commenter

codecov-commenter commented Sep 17, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 91.17647% with 6 lines in your changes missing coverage. Please review.
✅ Project coverage is 92.61%. Comparing base (6a29c59) to head (514191f).

Files with missing lines Patch % Lines
...shboard/user/workflow/WorkflowPublishService.scala 80.00% 2 Missing and 3 partials ⚠️
...rce/dashboard/user/workflow/WorkflowResource.scala 97.29% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##               main    #8575      +/-   ##
============================================
- Coverage     92.61%   92.61%   -0.01%     
- Complexity     5059     5061       +2     
============================================
  Files          1258     1258              
  Lines         53780    53814      +34     
  Branches       6707     6714       +7     
============================================
+ Hits          49811    49840      +29     
- Misses         2313     2317       +4     
- Partials       1656     1657       +1     
Flag Coverage Δ *Carryforward flag
access-control-service 77.38% <ø> (ø) Carriedforward from 6a29c59
agent-service 99.16% <ø> (ø) Carriedforward from 6a29c59
amber 88.10% <91.17%> (-0.01%) ⬇️
computing-unit-managing-service 60.48% <ø> (ø) Carriedforward from 6a29c59
config-service 87.37% <ø> (ø) Carriedforward from 6a29c59
file-service 82.00% <ø> (ø) Carriedforward from 6a29c59
frontend 96.59% <ø> (ø) Carriedforward from 6a29c59
notebook-migration-service 83.73% <ø> (ø) Carriedforward from 6a29c59
pyamber 98.58% <ø> (ø) Carriedforward from 6a29c59
workflow-compiling-service 72.43% <ø> (ø) Carriedforward from 6a29c59

*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.

@yangzhang75
yangzhang75 force-pushed the pin/3-read-paths branch 3 times, most recently from 6ff993b to e1f144b Compare September 28, 2026 21:13
@yangzhang75
yangzhang75 marked this pull request as ready for review October 6, 2026 18:42
@yangzhang75
yangzhang75 marked this pull request as draft October 7, 2026 01:35
@yangzhang75
yangzhang75 force-pushed the pin/3-read-paths branch 2 times, most recently from 7824786 to 8af259c Compare October 12, 2026 21:13
@yangzhang75
yangzhang75 marked this pull request as ready for review October 12, 2026 22:23
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>
@yangzhang75

Copy link
Copy Markdown
Contributor Author

/request-review: @aglinxinyuan

@github-actions
github-actions Bot requested a review from aglinxinyuan October 13, 2026 04:25

@aglinxinyuan aglinxinyuan left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@aglinxinyuan
aglinxinyuan added this pull request to the merge queue Oct 15, 2026
Merged via the queue into apache:main with commit 2351cb8 Oct 15, 2026
23 checks passed
renovate-bot pushed a commit to renovate-bot/apache-_-texera that referenced this pull request Oct 27, 2026
…pache#8576)

### What changes were proposed in this PR?

A listing is where most people meet a workflow, so it has to agree with
what opening it shows.
This makes search and the hub match, display and link against the copy
on show.

- **Search matches the copy the caller may see.** One search returns
both the caller's own
workflows and public ones, so the filter is a disjunction of guarded
filters — the working copy
for rows they were granted, the frozen copy for rows they reach only
because those are public.
Written over bare columns rather than a `CASE`, so each side stays
eligible for its own PGroonga
index. A pinned workflow no longer turns up on keywords that exist only
behind the pin, and the
  author still finds their own work on what they just typed.
- **Listings show the frozen name and description** to a viewer without
granted access — the same
copy the detail page serves, so a card cannot advertise a title that
opening it does not show.
  Both are NULL while following, which leaves the live values in place.
- **The hub is the public shelf**, so everything on it is listed as the
public sees it, for the
  author too: they are looking at the shelf, not at their own dashboard.
- **One definition of "the public is behind".**
`WorkflowPublishService.pinDiffersFromWorkingCopy`
is the share dialog's comparison as a SQL condition, and the search
projection and the hub
listing both use it, so a card and the dialog cannot disagree about
whether edits are held back.

### Any related issues, documentation, discussions?

Closes apache#7940
Part of apache#7828. Design discussion: apache#7128. Builds on apache#7853 and apache#8575, both
merged.

### How was this PR tested?

19 new cases in `WorkflowPublishSpec` plus
`WorkflowSearchQueryBuilderSpec` and
`UnifiedResourceSchemaSpec` (567 in the dashboard package):

- search not matching a public workflow on anything that exists only in
unpublished edits, and
matching it on its published copy — content, name and description, each
separately;
- an unpinned public workflow still matching the author's latest, and
the author still matching
  their own workflow on a name only they can see;
- a listing showing a public viewer the published name and description,
a collaborator the live
  ones, and a private workflow's own listing untouched;
- the drift flag a card carries: true while a pin holds edits back,
false for a workflow with
nothing frozen, and equal to what the share dialog reports for the same
workflow — including
after a rename and after a change of view, the two fields most easily
left out of one of the
  three places that answer this.

The shared condition was checked by mutation: dropping the default-view
term from it turns the
card-versus-dialog case red.

`scalafmtCheckAll` clean.

### Was this PR authored or co-authored using generative AI tooling?

Generated-by: Claude Code (Opus 5)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Serve the pinned copy to public viewers

3 participants