Yes — I researched it.
What I found
There is a real code smell/bug candidate:
frontend/apps/desktop/src/models/documents.tscomputesvisibility = ResourceVisibility.PRIVATEfor a first publish of a private draft.But if the publish goes through the daemon path,
frontend/apps/desktop/src/utils/publish-document.tsrewrites it to:
visibility: ResourceVisibility.UNSPECIFIED
in createDocumentChangeRequest(...).
So the daemon request drops the caller’s visibility intent.
Why this matters
On the backend:
backend/api/documents/v3alpha/documents.go
treats visibility like this:
PRIVATE→ make ref privatePUBLIC→ make ref publicUNSPECIFIED→ keep existing visibility for updates, default to public for new docs
So if a new private document were published through the daemon path with UNSPECIFIED, it could become public.
But here’s the important nuance
This is probably not the main explanation for “first publish of a private document doesn’t behave private.”
Why:
Non-home first publish does not use the daemon path
shouldUseDaemonCreateDocumentChange(...) uses daemon only when:
!!baseVersion && !!genesisor
!path(root/home doc)
Private drafts are created with a non-empty random path, so their first publish usually goes through the generic client path, not daemon.
And the generic path does preserve private visibility:
frontend/packages/shared/src/create-web-universal-client.tsfrontend/packages/client/src/change.tsfrontend/packages/client/src/change.test.ts
There is even a test confirming:
signDocumentChange(... visibility: 2 ...)includes
"visibility": "Private"in the Ref blob.
So what is the daemon bug actually affecting?
Likely only narrower cases:
Updates / re-publishes of existing docs that use daemon
Home/root docs, which also use daemon
But:
updates with
UNSPECIFIEDkeep existing visibility on the server, so that is often harmlessroot docs cannot be private anyway (
documents.gorejects private root docs)
So the daemon bug looks real, but also lower impact than it first appears.
Strong evidence it is already known / accidental
There are signs the team already suspected a visibility issue:
frontend/apps/desktop/src/models/documents.tshas:// TODO(temp): remove after verifying private document visibility fixlogging of
requestedVisibilityandreturnedVisibility
Also, the current unit test codifies the problematic behavior:
frontend/apps/desktop/src/utils/__tests__/publish-document.test.ts
expects createDocumentChangeRequest(...PRIVATE...) to still produce:
ResourceVisibility.UNSPECIFIED
So the bad behavior is currently baked into tests.
My conclusion
1. Yes, the daemon-path visibility drop is real
publish-document.ts discards requested visibility.
2. But it likely does not explain your main symptom for first-published private docs
Because those usually go through the non-daemon path, which preserves privacy.
3. More likely explanations for your observed behavior are:
you are testing as the owner, who is allowed to see private docs
UI surfaces intentionally include private docs for writers
useCanSeePrivateDocs(...)returns true for writer capability on the site home
the environment you tested may not be enforcing PublicOnly
or there is a separate privacy bug elsewhere
Best short takeaway
The daemon-path visibility bug is real, but probably not the primary cause of “private docs don’t behave private on first publish.”
Recap
The desktop daemon publish path drops requested private visibility by forcing ResourceVisibility.UNSPECIFIED in frontend/apps/desktop/src/utils/publish-document.ts, and the backend treats unspecified as “preserve on updates, default public for new docs.” However, first publish of non-home private docs usually bypasses daemon and uses the generic client signing path, which correctly preserves "Private" visibility in the Ref blob.
The daemon issue is real and currently even reflected in tests.
It is probably lower-impact than it first looks because the affected daemon flows are mainly updates and root docs.
Your observed “not private” behavior is more likely due to owner/writer access, environment config (
PublicOnly), or another privacy bug outside this daemon path.
Do you like what you are reading? Subscribe to receive updates.
Unsubscribe anytime