Skip to content

feat(frost/signing): RFC-21 Phase 5.3 -- readiness-gate env-var guard#3979

Merged
mswilkison merged 1 commit into
feat/frost-schnorr-migration-scaffoldfrom
feat/frost-roast-retry-readiness-gate-2026-05-23
May 23, 2026
Merged

feat(frost/signing): RFC-21 Phase 5.3 -- readiness-gate env-var guard#3979
mswilkison merged 1 commit into
feat/frost-schnorr-migration-scaffoldfrom
feat/frost-roast-retry-readiness-gate-2026-05-23

Conversation

@mswilkison

Copy link
Copy Markdown
Contributor

Summary

Closes Phase 5 of RFC-21. Adds the explicit-operator-opt-in
gate that protects production builds with the
`frost_roast_retry` tag from entering the orchestration path
without an explicit operator decision.

Production builds with the build tag enabled now refuse to wire
orchestration unless the operator sets
`KEEP_CORE_FROST_ROAST_RETRY_ENABLED=true`. The pattern matches
the existing
`KEEP_CORE_FROST_TBTC_SIGNER_ACCEPT_SCAFFOLD_KEY_GROUP` env var
from PR #3960: a build tag enables the code path, an env var
enables the wiring, both must agree for the feature to be live.

Stacked on #3978 (Phase 5.2).

What lands

New file: `pkg/frost/signing/roast_retry_readiness.go` (untagged)

Surface Notes
`RoastRetryReadinessOptInEnvVar` constant `KEEP_CORE_FROST_ROAST_RETRY_ENABLED`
`ErrRoastRetryReadinessOptOut` sentinel for `errors.Is` detection
`EnsureRoastRetryReadinessOptIn() error` returns nil if env var is `"true"` (case-insensitive, whitespace-trimmed); error otherwise
`RoastRetryReadinessOptInEnabled() bool` boolean helper
Per-call (not cached) operators can flip without restart

`roast_retry_orchestration.go` extended

`BeginOrchestrationForSession` now calls
`EnsureRoastRetryReadinessOptIn` before consulting the
registry. The env var is the load-bearing gate; missing opt-in
short-circuits orchestration even when the registry has a real
coordinator.

Why per-call rather than init-time

The scaffold-opt-in env var from PR #3960 is also evaluated per
call. Operators can flip it during a debugging session without
restart. Same reasoning here -- the readiness env var is a kill
switch, not a build constant.

Test coverage

File Cases
`roast_retry_readiness_test.go` (untagged, 7 cases) accepts `"true"`; case-insensitive; whitespace-trimmed; rejects unset (with sentinel + env-var-name in error); rejects other values; bool helper mirrors error; env var name matches RFC-21 spec (locks the name)
`roast_retry_orchestration_frost_roast_retry_test.go` (extended) New `TestBeginOrchestrationForSession_ErrorsWhenReadinessOptInUnset` -- asserts a registered coordinator alone is not enough; missing env var still short-circuits orchestration

Verification

Command Result
`go build ./...` clean
`go test ./pkg/frost/signing/...` pass (default build)
`go test -tags 'frost_roast_retry' ./pkg/frost/signing/...` pass
`go test -race -tags 'frost_native frost_tbtc_signer frost_roast_retry' ./pkg/frost/...` pass (5 packages)
`staticcheck -checks '-SA1019' ./pkg/frost/...` silent
`go vet ./pkg/frost/...` clean
`gofmt -l ./pkg/frost/signing/` silent

Phase 5 complete

PR Scope State
5.1 (#3977) Retry adapter scaffolding open
5.2 (#3978) Orchestration helpers + TTL sweep open
5.3 (this) Readiness-gate env-var guard open

Phase 6 will wire the production call sites and migrate the three
FROST/tbtc-signer receive loops onto the adapter in a single
coordinated change.

Test plan

  • CI green.
  • Reviewer confirms the case-insensitive / whitespace-trimmed parsing is acceptable. (Alternatives: strict `"true"` only.)
  • Reviewer confirms the per-call evaluation is acceptable. (Alternatives: read once at init.)

Closes Phase 5 of RFC-21 by adding the explicit-operator-opt-in
gate. Production builds with the frost_roast_retry tag now refuse
to enter the orchestration path until the operator sets
KEEP_CORE_FROST_ROAST_RETRY_ENABLED=true, matching the precedent
set by KEEP_CORE_FROST_TBTC_SIGNER_ACCEPT_SCAFFOLD_KEY_GROUP from
PR #3960.

* pkg/frost/signing/roast_retry_readiness.go (new, untagged)
  - RoastRetryReadinessOptInEnvVar constant -- the env var name.
  - ErrRoastRetryReadinessOptOut sentinel for errors.Is.
  - EnsureRoastRetryReadinessOptIn() returns nil if the env var
    is "true" (case-insensitive, whitespace-trimmed); returns
    ErrRoastRetryReadinessOptOut otherwise.
  - RoastRetryReadinessOptInEnabled() bool helper for code that
    needs a boolean rather than an error.
  - Per-call (not cached) so operators can flip the variable
    during a debugging session without restart.

* pkg/frost/signing/roast_retry_orchestration.go (extended)
  - BeginOrchestrationForSession now calls
    EnsureRoastRetryReadinessOptIn before consulting the
    registry. The env var is the load-bearing gate; missing
    opt-in short-circuits orchestration even when the registry
    has a real coordinator.

Tests:

* roast_retry_readiness_test.go (7 cases, untagged)
  - Accepts "true"
  - Accepts true case-insensitive (true / True / TRUE / tRuE)
  - Accepts trimmed whitespace
  - Rejects unset (returns ErrRoastRetryReadinessOptOut; error
    message names the env var)
  - Rejects other values (false / 1 / yes / TRUE_ / tru /
    anything)
  - RoastRetryReadinessOptInEnabled mirrors the Ensure result
  - Env var name matches RFC-21 specification (locks the name)

* roast_retry_orchestration_frost_roast_retry_test.go (extended)
  - Existing happy-path / error tests get t.Setenv(envVar,
    "true") so they reach the path under test.
  - New: TestBeginOrchestrationForSession_ErrorsWhenReadinessOptInUnset --
    asserts a registered coordinator alone is not enough; missing
    env var still short-circuits orchestration. This is the
    load-bearing safety property.

All pass under: go test ./pkg/frost/signing/..., go test -tags
'frost_roast_retry' ./pkg/frost/signing/..., go test -race -tags
'frost_native frost_tbtc_signer frost_roast_retry'
./pkg/frost/..., staticcheck -checks '-SA1019' ./pkg/frost/...,
go vet ./pkg/frost/..., gofmt -l ./pkg/frost/signing/.

Stacked on Phase 5.2 (#3978). Closes the Phase 5 surface.

Phase 6 will wire the production call sites:
* Caller invokes EnsureRoastRetryReadinessOptIn before
  RegisterRoastRetryCoordinator, falling back to legacy if not
  enabled.
* Three FROST/tbtc-signer receive loops migrate to
  EvaluateRoastRetryForSigning in a single coordinated change.
Base automatically changed from feat/frost-roast-retry-orchestration-2026-05-23 to feat/frost-schnorr-migration-scaffold May 23, 2026 02:15
@mswilkison mswilkison merged commit f8c5d7b into feat/frost-schnorr-migration-scaffold May 23, 2026
15 checks passed
@mswilkison mswilkison deleted the feat/frost-roast-retry-readiness-gate-2026-05-23 branch May 23, 2026 02:24
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