Skip to content

Release: develop -> main - #139

Merged
TaprootFreak merged 4 commits into
mainfrom
develop
May 31, 2026
Merged

Release: develop -> main#139
TaprootFreak merged 4 commits into
mainfrom
develop

Conversation

@github-actions

Copy link
Copy Markdown
Contributor

Automatic Release PR

Commits: 1 new commit(s)

  • Review all changes
  • Verify CI passes
  • Merge when ready for production

TaprootFreak and others added 4 commits May 31, 2026 13:18
* feat(features): consume username_claim runtime capability

Pairs with zk-coins/node#143, which splits the username write path
behind a `username-claim` Cargo feature and exposes
`/api/info.capabilities.username_claim`. This PR teaches the app to
read that bit and gate the Claim input on it, dropping the previous
attempt at a build-time client flag (closed PR #136 — wrong layer:
client flags can't react to a server policy change without a rebuild,
exactly the drift the runtime-capability layer exists to remove).

Wiring:
  - `CapabilitiesSchema` adds `username_claim: z.boolean().optional()`
    (optional for one release cycle so an app pointed at a pre-#143
    node doesn't trip the schema; the store fails closed otherwise).
  - `useFeatures()` exposes `USERNAME_CLAIM`, computed as
    `caps.username_claim ?? false`. Same fail-closed shape as the
    other capability bools.
  - `WalletScreen` gates the claim form + inline error banner on
    `features.USERNAME_CLAIM && features.USERNAMES && !account.username`.
    The display branch (`features.USERNAMES && account.username`) is
    unchanged — previously claimed names continue to render.
  - `audit-button-coverage` rationale for the `username-claim-btn`
    exemption now correctly attributes it to the runtime capability
    (the earlier `FEATURES.USERNAMES` claim was already false — that
    flag is runtime, not build-time DCE).

Test plan:
  - `features.test.ts` extended: USERNAME_CLAIM is in the key set,
    defaults `false` (fail-closed), flips with `/api/info`, and stays
    `false` when the server omits the field (old-node path).
  - All existing tests stay green; build + audit-coverage pass; no E2E
    coverage shift expected (claim was already hidden in DEV+PRD).

* refactor(capabilities): drop FAUCET/USERNAMES MVP fields, USERNAME_CLAIM required

Sync with the server-side change that drops `faucet` and `usernames`
from `/api/info.capabilities`. The Capabilities bit-set now describes
only *opt-in* features a self-hoster might switch off; MVP surface
(mint/faucet endpoints, username resolve and display) is permanently
part of every node build and is unconditional in the UI.

Schema:
  - CapabilitiesSchema: remove `faucet` and `usernames`; promote
    `username_claim` from optional to required (sync deploy is the
    norm, no version-skew window to support).

Store:
  - FAIL_CLOSED: matches the new shape (address_list, username_claim,
    lnurl), all false.

useFeatures():
  - drop `FAUCET` and `USERNAMES` from the merged object; keep
    `USERNAME_CLAIM` for the claim-form gate. Memo deps narrowed
    accordingly.

WalletScreen:
  - showFaucet collapses to the mainnet-defence check (faucet button
    is testnet-only; the server always serves /api/mint).
  - Username display drops the `features.USERNAMES &&` guard.
  - Balance-polling effect drops the `USERNAMES` gate and the matching
    dep-array entry; the local username is pinned on the first tick
    that reports one.
  - Claim form + claim-error gates collapse to `USERNAME_CLAIM &&
    !account.username`.

SendPage:
  - Username resolve (`@zkcoins.app` suffix, `$` prefix, hex fast-path)
    is unconditional now that resolve is MVP — the `features.USERNAMES`
    gate and its dep-array entry are gone. Recipient input placeholder
    is the canonical `alice@zkcoins.app` example.

Tests:
  - features/capabilities/AppShell/home/Onboarding-restore/send-pipeline
    /WalletScreen.polling/client all updated to the new shape.
  - WalletScreen polling tests reframe the username path as "first-only,
    always-on" instead of gated-by-FEATURES.USERNAMES.

Audit:
  - coverage.mjs MVP_EXEMPT_TESTIDS header now documents both exemption
    grounds (build-time DCE + runtime capability always-false) so the
    `username-claim-btn` entry has a clear rationale.

* chore(reviewer-round-2): address MINORs from cross-PR review

Test-state resets:
  - home.test.tsx / AppShell.test.tsx / Onboarding-restore.test.tsx —
    the `Object.assign(FEATURES_STATE, …)` beforeEach blocks listed
    the retired USERNAMES/FAUCET keys and forgot USERNAME_CLAIM. Tests
    ran green only because the vi.hoisted() initial state was already
    correct; the reset itself drifted. Each block now mirrors the
    current six build-time flags plus USERNAME_CLAIM.

src/app/page.tsx:
  - Stale comment "Server feature gates: faucet / usernames /
    address_list / lnurl" → "Opt-in server features (address_list,
    username_claim, lnurl)".

src/app/send/page.tsx:
  - `useFeatures()` was kept only for `features.APPS_DIRECTORY`, a
    pure build-time flag. The capabilities-store subscription would
    re-render the page on every /api/info update for no reason.
    Switched to `import { FEATURES }` + `FEATURES.APPS_DIRECTORY`.

E2E doc drift:
  - 07-send.spec.ts header: username resolve is MVP and unconditional
    now (was incorrectly "no FEATURES.USERNAMES").
  - 06-balance.spec.ts header: faucet is no longer a build flag —
    mint is MVP, button gated purely on `networkName !== mainnet`;
    DEV runs Mutinynet so the button IS shown.
  - e2e/README.md: gating table + the §8.6 row line for
    `balance-zero-faucet-visible` updated to match the new logic.
…138)

* ci: add staging → develop auto-release-pr workflow + doc the new flow

Mirrors the existing develop → main auto-release-pr.yaml, one layer
down. Triggers on push to staging, opens (or no-ops on existing)
"Promote: staging -> develop" PR for the operator to merge once they
want the accumulated feature work to land on DEV.

CONTRIBUTING.md updated:
  - Branches table now lists staging as the integration buffer
    between feature/* and develop.
  - Workflow rule rewritten: open feature PRs against staging, not
    develop. develop is fed by the staging auto-PR; main by the
    develop auto-PR. Same pattern, one extra step.
  - CI/CD table extended with the new workflow row.

Bootstrap note: this PR targets develop directly because the
staging-side workflow doesn't exist yet — once merged + synced to
staging, all subsequent feature work follows the staging → develop
flow.

* ci(staging): apply reviewer round-1 feedback

CONTRIBUTING:
  - re-add the protection statement that round-1 dropped: develop +
    main are protected, direct pushes rejected. Was implicit before;
    reviewer flagged the absence as ambiguous re. hotfix flow.

Workflow rename Release → Promote:
  - "Release" stays reserved for develop → main (production cut).
  - staging → develop is a "promote" (DEV deploy is the side-effect,
    not the purpose). Workflow name, job name, step name + PR body
    headline all aligned on "Promote".
  - body checklist item rewritten to "Merge to promote staging to
    develop (deploys to DEV)" — the merge target is develop; the
    deploy is a follow-on effect, not the action.

* test(e2e): regenerate visual baselines

* test(e2e): regenerate visual baselines

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
globalSetup deadlocks on CI at `page.reload({ waitUntil: 'networkidle' })`
since PR #102 — the boot path now fires a fire-and-forget `/api/info`
capabilities fetch on every page mount and the service worker
(public/sw.js) does stale-while-revalidate for every cached asset. On
the GitHub Azure runner those background requests can keep the
500 ms networkidle window from ever closing, hitting the 30 s timeout
in `_helpers/wallet.ts:47` before the page settles. All 9 open PRs
plus the develop→main release PR have been red on E2E since 2026-05-18
19:18 UTC because of this.

Switch the reload to `domcontentloaded`. The caller's next step is
always a testid-based locator assertion (with its own 15-30 s
auto-wait), which is the real readiness signal we want — the same
rationale already applied to `snap()` in `_helpers/screenshot.ts`.

Locally:
- 3× pass on the previously-failing 02-create-seed wallet-after-create
- 10/10 pass on 03-restore-seed.spec.ts
- 9/9 pass on 11-cross-spec-redirects + 12-a11y
…er (#118)

Mirrors the matching section in zk-coins/server. The split is:

  - Wallet operations (seed, sign, BIP32 derive, balance, history) run
    entirely on-device — no backend involvement.
  - Send / Receive / Mint post the full private witness to the
    configured server for ZK proof generation, so that server sees
    every transaction in cleartext.

On-chain privacy is unaffected — Plonky2 keeps the chain footprint
opaque. The trust boundary is the server operator.

Default backend is api.zkcoins.app (NEXT_PUBLIC_API_URL build-time
env, see src/stores/network.ts). Privacy-conscious users can point
the app at a self-hosted zk-coins/server instance via the same env
var at build time.

Three-row hosted-vs-self-hosted table mirrors the server-side README
plus an explicit row that the wallet seed never leaves the device in
either case.
@TaprootFreak
TaprootFreak merged commit b7cae92 into main May 31, 2026
15 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