Skip to content

Dataset page: temporarily-anonymous state, and no route to a private repository - #334

Merged
neuromechanist merged 2 commits into
stagingfrom
feature/issue-333-anonymous-deposit
Sep 16, 2026
Merged

neuromechanist merged 2 commits into
stagingfrom
feature/issue-333-anonymous-deposit

Conversation

@neuromechanist

Copy link
Copy Markdown
Contributor

Summary

A dataset can be deposited for double-blind review: served here exactly as any public dataset is, while its GitHub repository stays private and its depositor is withheld until the paper is accepted (nemarOrg/nemar-cli#1408). The backend withholds external_links.github_url and external_links.dataset_doi for such a dataset, and now states anonymous: true outright.

Closes #333.

The bug was the fabrication, not the button

Nulling github_url server-side changed nothing here, because the URL was invented straight back in two places:

So the GitHub button disappeared while the copyable datalad clone and git clone commands still handed the visitor the repository address, and the Issues button — typed string, never gated — always rendered and always pointed at <repo>/issues.

Both fallbacks are gone. Every downstream route is now gated on the URL actually being present: the GitHub button, both clone commands, the unpublished empty-state link, and Issues.

The README moves to the data plane

raw.githubusercontent.com 404s for a private repository, so the panel would fall through to the description and the dataset would look undocumented rather than concealed. nemar-cli#1403 built the broker that serves a dataset's git-tracked files whether its repo is public or private, and README.md is one of them.

This is a behavior change for every dataset page, deliberately: it removes a third-party host from the critical path and leaves one code path instead of a rarely-exercised branch carrying the guarantee.

The state is explained, not just hidden

A warning-toned card (cloning .detail__unpublished, design tokens only) says the data is complete and free to download and that only authorship is withheld, plus a Tag kind="warning" header chip. A reader who arrives at a dataset with no authors should learn why rather than conclude the record is broken.

The flag is read from the data-plane document, not the catalog row: catalogRow is null for ds* ids and on any fetch failure, and degrading to "not anonymous" is the wrong-way failure for this feature. The metadata document cannot fail silently — the page 404s instead.

Test plan

  • bun run test — 2,307 pass (ran twice; one earlier run had an unrelated flake in the network-dependent eeg-viewer prefetch test, which retries against zarr.nemar.org)
  • bun run build — passes, including starlight-links-validator
  • bunx astro check — 0 errors, 0 warnings
  • New test/anonymous-deposit.test.ts (12 tests) asserts the absence of the fallbacks, because a rendering test would have passed against the original bug — the button really was hidden. Verified by reinstating the fabrication and watching the guard fail.

Deliberately not included

  • src/pages/upload/success.astro fabricates the same URL, but it is owner-only and the owner is entitled to their own repository.
  • raw.githubusercontent.com in middleware.ts CONNECT_SRC_BASE is now unused. Removing it is a CSP change with site-wide blast radius and middleware.test.ts:610 pins it deliberately; it belongs in its own PR.

Depends on

The backend half (nemarOrg/nemar-cli#1408, branch feature/issue-1408-phase3-surfaces) which withholds the two links and adds anonymous to the data-plane document. Until that reaches api-test/data-test, metadata.anonymous is simply absent and every dataset renders exactly as it does today.

A dataset can be deposited for double-blind review: served here exactly
as any public dataset is, while its GitHub repository stays private and
its depositor is withheld until the paper is accepted
(nemarOrg/nemar-cli#1408). The backend withholds external_links.github_url
and external_links.dataset_doi for such a dataset, and now states
`anonymous: true` outright.

The bug was not that a button rendered. It was that the URL was
FABRICATED in two places when the backend withheld it --
`githubUrl ?? https://github.com/nemarDatasets/<id>` in ActionBar and in
the dataset page -- so nulling the field server-side changed nothing: the
button disappeared while the copyable datalad/git-annex clone commands
still handed the visitor the repository address. Both fallbacks are gone,
and every downstream route is gated on the URL actually being present:
the GitHub button, the clone commands, the unpublished empty-state link,
and the Issues button, which was typed `string` and so always rendered.

The README panel now comes from data.nemar.org instead of
raw.githubusercontent.com. nemar-cli#1403 built the broker that serves a
dataset's git-tracked files whether its repository is public or private,
so this is what makes the panel work for a blinded deposit at all --
otherwise it 404s and the dataset looks undocumented rather than
concealed. It also takes a third-party host out of this page for every
dataset, and leaves one code path rather than a rarely-exercised branch
carrying the guarantee.

The state is explained rather than merely hidden: a warning-toned card
saying the data is complete and only authorship is withheld, plus a
header chip. A reader who arrives at a dataset with no authors should
learn why, not conclude the record is broken.

The flag is read from the data-plane document, not the catalog row: that
fetch is null for ds* ids and on any failure, and degrading to "not
anonymous" is the wrong-way failure here.

Guarded by test/anonymous-deposit.test.ts, which asserts the ABSENCE of
the fallbacks -- a rendering test would have passed against the original
bug, since the button really was hidden. Verified by reinstating the
fabrication and watching the guard fail.

Not included: src/pages/upload/success.astro fabricates the same URL, but
it is owner-only and the owner is entitled to their own repository. The
raw.githubusercontent.com entry in middleware CONNECT_SRC_BASE is now
unused; removing it is a CSP change with site-wide blast radius and
belongs in its own PR.
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Sep 15, 2026 •

Copy link
Copy Markdown

Deploying nemar-website with  Cloudflare Pages  Cloudflare Pages

Latest commit: 1e16363
Status:🚫  Build failed.

View logs

Review found the suite could not fail in the direction that matters.
Every test asserted an absence, and absence is satisfied by deleting the
feature: changing `githubUrl={githubUrl}` to `githubUrl={null}` removed
the GitHub button and both clone commands from all 772 datasets and all
twelve tests still passed. Adds controls over the real derivations, a
DOI pair the suite never covered at all, and a pin on the one token that
mutation changed.

The explanatory copy claimed more than NEMAR enforces. "Only the
depositor's identity is withheld" reads as a guarantee of anonymity, and
it is not one: the README, dataset_description.json and the participants
files are the depositor's own and are served as written, which is why
the backend's sweep reports them to the depositor rather than fixing
them. It also turned on "until the associated paper is accepted", an
event NEMAR neither observes nor performs, and asserted "the data is
complete", which the platform declines to claim elsewhere (ADR 0005,
ADR 0064).

Also removed: a dead `fallbackKind === "github"` branch still rendering
a repository link inside the component whose whole changeset is "no
GitHub route survives"; an empty-state sentence in both the SSR and
client copies telling the reader the dataset's GitHub repository may
have notes, which confirms a repo exists under a predictable name; the
raw.githubusercontent.com CSP allowance, whose only consumer moved to
the data plane; and ORG_DATASETS, which had no consumer left and was the
easiest way to rebuild the fabricated URL past the literal-matching
tests.

The `anonymous` comment said absent means "not anonymous". The backend
contract says to treat absent as unknown. Corrected, with the reason it
is safe to read `=== true` here specifically: the flag and the withheld
fields come from the same document.
@neuromechanist
neuromechanist merged commit 8d2e6e3 into staging Sep 16, 2026
4 of 5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant