Skip to content

Publication review for publication requests (epic #1726) - #1782

Merged
neuromechanist merged 42 commits into
devfrom
feature/issue-1726-epic-publication-review
Oct 15, 2026
Merged

neuromechanist merged 42 commits into
devfrom
feature/issue-1726-epic-publication-review

Conversation

@neuromechanist

@neuromechanist neuromechanist commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

Summary

A publication request now gets one derived verdict, in the same shape as the pull-request review (ADR 0092, ADR 0093): the Worker builds it from the mechanical gates (submission minimums, BIDS check, identifier screen) plus a no-tools model review of the submission, ties it to a commit and version, and gates approval on it. Anything that is not a clear pass is action_required and needs --force or an explicit y in nemar admin publish next; nothing is auto-denied and unknown is never green. The identifier screen stays mechanical and the model never receives header values, identifier findings or data content. The design is ADR 0102 (with amendments for Phases 2 to 4) and ADR 0105 (the per-claim dispatch token that attributes a web approval correctly).

Closes #1726

Phases completed

  1. Phase 0 (Phase 0: design the publication review (ADR 0101) #1735): design, ADR 0102 and the design note.
  2. Phase 1 (Phase 1: publication review store, job, mail and calibration #1762): publication_reviews store (migration 0098), derived verdict, central workflow run-publication-review.yml source with dispatch, one-shot claim, closed-vocabulary report, watchdog, caps, admin mail section, start route.
  3. Phase 2 (Phase 2: the publication review's approval gate and commands #1767): nemar admin publish list shows the verdict, plus show, next, start, and the --force gate; approval stays the administrator's own act.
  4. Phase 3 (Phase 3: approval robustness and web approval attribution #1772): approval robustness (Let POST /admin/publish/:id/approve take a request_id precondition #1579, nemar admin publish approve exits 0 when an approval fails #1581, Release the approval lease when the executor fails before the backend can see it #1582, approve-dispatch should validate the dataset id before it claims the lease #1583, Admin approve and deny take a cookie without an Origin check; deny is not lease-gated #1603, A terminal approval inside a live web lease is recorded as the web clicker #1604), the dispatch token (ADR 0105), cookie writes need an allowed Origin.
  5. Phase 4, nemar-cli half (Phase 4: words the web page can print for the review #1779): the words the web page prints, split from the terminal's, with a parity test against the website copy. The website half is Admin publication page shows the review and the identifier screen website#460 (draft, waits for this PR).

Dev moved while the epic was being built (#1769, #1770, #1777, #1778), so this branch carries a merge of dev with two renumberings: the dispatch-token ADR is now 0105 (dev took 0103 and 0104) and the publication-reviews migration is now 0098 (dev took 0096 and 0097). publish list moved to src/commands/admin-publish.ts in this epic, so the new default scope, the state flags, --search and the withdrawn label from #1777 and #1778 were ported there. A lost write between approve and withdraw answers 409 request_changed (the epic's word) where dev answered request_ended.

Behavior changes at the next release

  • A web approval is recorded under the administrator who clicked; a terminal approval inside a live web claim is recorded as the terminal administrator and takes the claim over.
  • Deny refuses while an approval run is in flight; cookie-authenticated writes on the admin routes need an allowed Origin.
  • nemar admin publish list defaults to active requests; --all shows history.
  • New audit rows, new dataset_published fields, new 409 codes and the optional NEMAR_APPROVE_RETRY_DELAY_MS setting.
  • The review itself is behind a flag that is off until the soak (Phase 5).

Deployment order

Test plan

  • Both typechecks, bun run lint, the ADR index test and migration checks on the merged head
  • Full suite on the merged head: 15938 pass; the failures are the 5 bash-completion tests (macOS bash 3.2), one website parity test against an out-of-date local checkout, and load flakes that pass alone
  • CI green on this PR
  • Panel review of the whole epic diff in two rounds, every finding addressed

* docs: add ADR 0100 on the publication review

Record the design of epic #1726 as a proposed ADR: one derived verdict
per publication request, bound to the request, the screened commit and
the anonymous flag; the model review runs only after the identifier
screen reports for that commit and only on bytes the shared mechanical
rules pass just before sending, because the screen does not read the
README, CHANGES, LICENSE, dataset_description.json or participants.json;
closed reasons that each say what clears them; the Worker enforces the
gate in /approve and approve-dispatch; the advisory pre-screen retires.

Refs #1727. Tested: adr-index.unit.test.ts passes.

* docs: add the publication review design note

The analysis behind ADR 0100: what was read, the facts checked against
the code, the pull-request review compared with the publication review,
the data flow, the screen-first options weighed, the cost arithmetic,
the refined phase plan for Phases 1 to 5 and the risks. Listed in the
.context index as analysis, not a ruling.

Refs #1727. Tested: adr-index.unit.test.ts and docs-links pass.

* docs: revise ADR 0100 after review

Apply the independent review of #1735 and the maintainer's amendments
recorded on #1726: the pre-screen is live in production and is handed
over when the review is switched on (its callback secret stays, since
the screen and the pull-request review use it); the pre-send check is
stated as a consistency control, with #1737 a prerequisite; no .tsv
file reaches the model; reasons gain a class; a failed minimum
re-blocks the request; call 4 and call 11 as amended; override bound
to the reasons shown; the Worker is the gate for the executor; a
per-claim dispatch token for Phase 3; release dark before the soak.

Refs #1727. Tested: adr-index, changelog-format, docs-links pass.

* docs: revise the publication review note

Correct the facts the review found (the live pre-screen, the first-match
rule, the request route's 409, createTag on an existing tag), add the
offline calibration plan with prices checked on the live pricing page,
move the initial vocabularies here from the ADR, and refine the phases:
#1737 first, the epic finalized into dev after Phase 3, and Phase 5 as
release dark, soak against the dev Worker, then switch on.

Refs #1727. Tested: adr-index, changelog-format, docs-links pass.

* docs: README forms, provenance and agent option

Renumber the remaining ADR 0100 references to 0101. Accept README.md, README, README.rst and README.txt, name provenance and the ethics statement in the questions, and record the tool-using reviewer as considered and recommended against.
Phase 1 (#1728) of epic #1726: the publication review's store, contract, write path, read path, admin mail, job and workflow source, administrator start route, and calibration tooling, with ADR 0102 and the design note. Production stays dark: the flag is set only in the dev variables, nothing gates an approval yet, and the workflow is source only until it is deployed to the central repository.

Reviewed by four adversarial passes and a five-reviewer whole-PR review; every finding was fixed with a failing test first or recorded in the ADR. Full suite on the final head: 14593 pass, with only the five known bash-completion failures.
Phase 2 (#1729) of epic #1726: the Worker's approval gate and the administrator's commands for the publication review (ADR 0102).

A publication request already has one derived verdict (Phase 1, #1762). Approving a request whose review is not a pass now needs the administrator's recorded override, which names the review in force and every override-class reason standing and is recorded by one statement that pins the review row as it was read. A reason nothing clears refuses whatever the body says, and every read or write failure after the request was read refuses; nothing fails open. `nemar admin publish list | show | start | next | approve` and the administrator's comment to the depositor show and use the review in the same words; approval stays the administrator's own act. Every failure of the publish group exits non-zero (#1581 for this group).

Production stays dark: the gate reads nothing with the flag off. ADR 0102 is amended; production must not be lit before #1604 (Phase 3) is fixed.
Approval robustness for the publication review (#1730, epic #1726, ADR 0103).

A web approval is attributed by a per-claim dispatch token (#1604): the clicker is the approver only for a call that carries a valid token, every other caller is recorded as themselves, and a terminal approval takes the claim over once it passes the gates. A call that carries a token may carry no decision of its own (override, screen acknowledgment or skipped CI check).

Also: a request_id precondition on approve, approve-dispatch and deny (#1579); dataset-id validation before the claim (#1583); a token-authenticated release endpoint and a recorded last_error on every pre-loop exit (#1582); one router-wide cookie Origin guard (#1603, #1584); a lease-gated conditional deny that never denies a request whose publication started, and a status-guarded final write; and an all-steps-done branch that refuses a closed request before its tail jobs and records one dataset_published row per publication. #1580 is deferred.

Tested: full suite on the head (15669 pass; the 5 known bash-completion failures and one load flake of a mail test that passes alone), a 29-row mutation battery red, CI green. Reviewed by an Opus review and two rounds of Sonnet agents; every finding fixed or recorded in ADR 0103.
The API half of Phase 4 of epic #1726 (the web approval page).

Splits each reason's cure into a neutral sentence and a CLI-only command (terminal text unchanged, golden pinned), adds the detail fields start_offered, screen_gate and the findings' label and document_label, a statement and command on each reason, the 22-key page-owned copy table with a parity test, the web-safety pin, and the ADR 0102 Phase 4 amendment.

Reviewed by one Opus review and a two-round Sonnet panel; every finding addressed.

Part of #1731.
…c-publication-review

# Conflicts:
#	.context/decisions/0102-a-publication-request-gets-a-derived-verdict-and-approving-a-non-pass-is-the-administrators-recorded-act.md
#	.context/decisions/README.md
#	README.md
#	backend/src/routes/admin/publish.ts
#	backend/src/services/publication-orchestrator.ts
#	scripts/ci/pr-review-prompt.ts
#	src/commands/admin.ts
#	test/admin-route-inventory.unit.test.ts
@github-actions

github-actions Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

📦 Package Preview

Your package is ready to test!

bun install -g nemar-cli@PR1782

Version: 0.10.19-PR1782.ecc409b
Commit: ecc409b


🤖 Updated on each push.

This branch was successfully deployed

1 active deployment
npm — ecc409b9 Deployed Oct 15, 2026 by neuromechanist via publish #3598
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