Dataset page: temporarily-anonymous state, and no route to a private repository - #334
Merged
Merged
Conversation
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.
5 tasks
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.
This was referenced Sep 16, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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_urlandexternal_links.dataset_doifor such a dataset, and now statesanonymous: trueoutright.Closes #333.
The bug was the fabrication, not the button
Nulling
github_urlserver-side changed nothing here, because the URL was invented straight back in two places:ActionBar.astro:31—githubUrl ?? \https://github.com/nemarDatasets/${ds}\``dataset/[id].astro:234— the same fallback againstORG_DATASETSSo the GitHub button disappeared while the copyable
datalad cloneandgit clonecommands still handed the visitor the repository address, and the Issues button — typedstring, 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.com404s 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 aTag 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:
catalogRowis null fords*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 againstzarr.nemar.org)bun run build— passes, including starlight-links-validatorbunx astro check— 0 errors, 0 warningstest/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.astrofabricates the same URL, but it is owner-only and the owner is entitled to their own repository.raw.githubusercontent.cominmiddleware.tsCONNECT_SRC_BASEis now unused. Removing it is a CSP change with site-wide blast radius andmiddleware.test.ts:610pins 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 addsanonymousto the data-plane document. Until that reachesapi-test/data-test,metadata.anonymousis simply absent and every dataset renders exactly as it does today.