Skip to content

feat(ui): real human gates — scope approval and draft publication through the engine (#201) - #227

Merged
DanielNetzer merged 1 commit into
mainfrom
forgecell/issue-201-ui-gates
Oct 25, 2026
Merged

DanielNetzer merged 1 commit into
mainfrom
forgecell/issue-201-ui-gates

Conversation

@DanielNetzer

Copy link
Copy Markdown
Owner

Closes #201.

The first real human gates in forgecell ui, driven through the engine:

  • Scope gate: POST /api/molecules/{id}/scope takes the exact plan digest the UI showed. It must equal the latest pending digest, and the engine's Approve re-validates it. It then runs molecule.Run(Options{Approve}) as a background job, one per Molecule, and the UI polls …/job.
  • Delivery gate: POST …/delivery/preview returns the redacted delivery.Preview. POST …/delivery/publish sends the exact preview digest, title and acceptUnverified to delivery.Publish. This is a draft PR only; there is no merge, deploy or permission route.
  • Commit point: a decision shows as committed only after read-back. For scope, the ledger must record the approval of that exact digest. For publish, this job must finish (or need reconciliation) and the receipt must be committed or published with a lifecycle.
  • Engine refusals: stale digests, locks, receipt mismatches and unverified acceptance map to fixed categories and messages, with no path leaks. They are never retried. After an ambiguous response the UI reads the canonical state back instead of resubmitting, and buttons stay disabled while a request or job is pending.
  • Write protection: writes need the session cookie and tab header (both compared in constant time), an exact Origin (a missing one is refused), and Sec-Fetch-Site same-origin. The body is capped at 4 KiB, must be JSON, and may not contain unknown fields.
  • Jobs: capped at 64, with panics recovered and a graceful stop on shutdown.

Built by Forgecell Molecule mol-201-37aed06f7794e3a3e329bbc7 (plan 1ec6d333). On the candidate tree every check passed, including the new go test -timeout 20m ./... baseline. Hand-delivered: the protected regression runs the base TestUILabIdentityWithoutAFormula, which asserts the old read-only, no-gates UI. That fails by design, because this slice changes it.

Review: one independent adversarial pass. Fixed here (MEDIUM, correctness): a refused publish could show "Committed" when an earlier attempt's receipt was already committed. jobView now requires this job's own outcome, and two new rows in TestUIGatePublishRefusalsReadBackTheReceiptAndNeverRetry pin it. A clean-shell go test -timeout 25m ./..., vet and gofmt all pass.

LOWs (not fixed):

  • Preview isn't serialized per Molecule. Concurrent previews from one tab run in parallel; the UI disables the button.
  • After the 30 s stop grace a still-running engine call isn't waited for. It relies on the engine's own crash safety.

🤖 Generated with Claude Code

…ough the engine (#201)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@DanielNetzer
DanielNetzer merged commit b05bb96 into main Oct 25, 2026
2 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.

UI-4: Lab UI — real human gates (scope approval, draft publication) through the engine

1 participant