Skip to content

Release request: cut v0.6.0 with payment fixes since v0.5.0 #339

Description

@felixfelix-bot

v0.5.0 was released Jul 3. Main is now 45+ commits ahead with critical payment fixes:

  • Swap-counter race fix (gonuts v0.10.0)
  • BOLT11 strict decode fix
  • Portal assets built from source
  • Lightning quote persistence
  • Safe exec.Command wrapper

Requesting a v0.6.0 release tag so downstream tools (net4sats wizard) can pull a known-good binary from upstream rather than forks.

Activity

  1. Amperstrand commented on Jul 30, 2026

    @Amperstrand
    Collaborator

    Release readiness: v0.6.0

    Merged since v0.5.0 (22 PRs)

    Critical fixes:

    PR Fix
    #304 gonuts v0.10.0 — URL normalization, swap-counter race, DLEQ keyset lookup, NUT-13 big.Int, 429/5xx retry, module rename
    #330 Reject spending-condition-locked tokens + fix Fund() decode
    #274 io.ReadAll 1MB limit (DoS prevention)
    #307 Sync all dependencies (x/crypto v0.54.0, 28 CVEs patched) + drift checker + pre-commit hook
    #298 Fall back to degraded mode on wallet init failure (#275)
    #281 V2 keyset swap crash fix (gonuts v0.7.6)
    #283 NDS fw4/nftables enforcement bridge
    #297 Portable WAN detection in NDS enforcement

    Improvements:

    PR What
    #338 Configurable rate limiter (TOLLGATE_RATE_LIMIT_RPM)
    #335 Build portal assets from source (no more committed minified JS)
    #321 Identity: loopback enforcement + body limit
    #316 Return 200 instead of 500 on /usage when no session
    #310 Sat standardization + advertisement fix + config migration
    #265 sysexec wrapper (context, retry, logging)
    #294 TOLLGATE_TEST_CONFIG_DIR for socket path

    Infrastructure:

    PR What
    #309 Regression test for wallet-init-failure → degraded mode
    #302, #303 CI: Blossom mirror fixes
    #293 gonuts go.sum hash fixes
    #292 gonuts v0.9.0 bump
    #286 gonuts v0.8.0 bump
    #319 gofmt fix

    Open PRs ready for review (12)

    PR Title CI Blocks
    #314 429 backoff at merchant layer ✅ green #260
    #315 NDS autopay session trigger ✅ green #88
    #317 Firewall port 2121 to LAN ✅ green #226
    #327 greatspectations + AI audit ✅ green —
    #340 Token recovery tool ✅ pending —
    #299 WalletPort interface ✅ green —
    #331 Unified identity (NIP-06) check —
    #332 WGM vendor IE discovery check —
    #337 Validator tests check —
    #336 Stale SSID comment check —
    #312 WGM discovery logger check —
    #261 Post-swap-fee characterization check —

    gonuts-tollgate v0.10.0 changes (15 PRs)

    URL normalization, swap-counter race fix, DLEQ per-proof keyset lookup, NUT-13 big.Int + collision detection, error wrapping (%w throughout), empty slice panic guards (5 sites), non-atomic swap fix, silently swallowed error fix, HTTP 429 rate limiting, 5xx retry on GET, module rename (Origami74 → OpenTollGate), resolveShortKeysetIds (V4).

    Recommendation

    Merge #314, #315, #317 first (bug fixes with CI green + reviews posted). Then cut v0.6.0.

  2. Amperstrand commented on Jul 30, 2026

    @Amperstrand
    Collaborator

    v0.6.0 Release Readiness Assessment — Jul 30

    Already merged (on main, ready for release)

    PR Category What
    #281 Fix V2 keyset swap crash (gonuts v0.7.6)
    #283 Fix NDS fw4/nftables enforcement bridge
    #286 Deps gonuts v0.8.0 (V4 short keyset ID resolution)
    #292 Deps gonuts v0.9.0
    #294 Fix CLI socket path for test env
    #297 Fix Portable WAN detection in NDS
    #298 Fix Degraded mode fallback on wallet init failure (#275)
    #304 Deps gonuts v0.10.0 + module rename (Origami74 → OpenTollGate)
    #307 Chore Sync all deps + drift checker + pre-commit hook
    #310 Fix Sat standardization + advertisement fix
    #316 Fix Return 200 instead of 500 on /usage
    #319 Fix gofmt tab indentation
    #321 Fix Identity loopback enforcement + body limit
    #330 Fix Reject spending-condition-locked tokens + fix Fund() decode
    #335 Chore Build portal assets from source
    #338 Fix Configurable rate limiter

    Open PRs — ready for review (CI green)

    PR Category What Issue
    #314 Fix 429 backoff at merchant level #260
    #315 Fix NDS session trigger after autopay #88
    #317 Security Firewall port 2121 to LAN #226
    #327 Tooling greatspectations + AI audit prompts —
    #340 Tool Token recovery tool #88
    #261 Test Post-swap-fee characterization #63
    #299 Architecture WalletPort interface —
    #331 Feature Unified identity (NIP-06) —
    #332 Feature WGM vendor IE discovery —
    #337 Test tollgate_protocol validators —

    gonuts-tollgate v0.10.0 highlights (15 PRs merged)

    Recommendation

    v0.6.0 can be cut now with what is on main. PRs #314, #315, #317 are critical bug/security fixes that are CI-green and reviewed — merging them before the cut would make v0.6.0 significantly more robust. The feature PRs (#331, #332, #299) can wait for v0.6.1.

  3. Amperstrand commented on Jul 30, 2026

    @Amperstrand
    Collaborator

    Release readiness: v0.6.0

    Merged since v0.5.0 (20 PRs)

    Critical fixes:

    PR Fix
    #304 gonuts v0.10.0 — URL normalization, swap-counter race, DLEQ keyset lookup, NUT-13 big.Int, 429/5xx retry, module rename
    #330 Reject spending-condition-locked tokens + fix Fund() decode
    #274 io.ReadAll 1MB limit (DoS prevention)
    #307 Sync all deps (x/crypto v0.54.0, 28 CVEs patched) + drift checker + pre-commit hook
    #298 Fall back to degraded mode on wallet init failure (#275)
    #281 V2 keyset swap crash fix (gonuts v0.7.6)
    #283 NDS fw4/nftables enforcement bridge
    #297 Portable WAN detection in NDS enforcement

    Improvements:

    PR What
    #338 Configurable rate limiter via env var
    #335 Build portal assets from source
    #321 Identity loopback enforcement + body limit
    #316 Return 200 not 500 on /usage without session
    #310 Sat standardization + advertisement fix + config migration
    #265 sysexec wrapper with context/retry/logging
    #294 TOLLGATE_TEST_CONFIG_DIR for socket path

    Infrastructure:

    PR What
    #309 Regression test for degraded mode fallback
    #302, #303 CI Blossom mirror fixes
    #292, #293 gonuts v0.9.0 bump + go.sum fix
    #286 gonuts v0.8.0 bump
    #319 gofmt fix

    Open PRs ready for merge (CI green, reviews posted)

    PR Title Issue
    #314 429 backoff at merchant layer #260
    #315 NDS autopay session trigger #88
    #317 Firewall port 2121 to LAN #226

    Recommendation

    Merge #314, #315, #317 (all CI green, LGTM posted). Then cut v0.6.0.

  4. Amperstrand commented on Jul 30, 2026

    @Amperstrand
    Collaborator

    Release readiness: v0.6.0 — Jul 30

    Merged since v0.5.0 (20 PRs)

    Critical fixes:

    PR Fix
    #304 gonuts v0.10.0 — URL normalization, swap-counter race, DLEQ keyset lookup, NUT-13 big.Int, 429/5xx retry
    #330 Reject spending-condition-locked tokens + fix Fund() decode
    #274 io.ReadAll 1MB limit (DoS prevention)
    #307 Sync all deps (x/crypto v0.54.0 — 28 CVEs patched) + drift checker + pre-commit hook
    #298 Degraded mode fallback on wallet init failure (#275)
    #281, #283 V2 keyset crash fix + NDS fw4 enforcement
    #297 Portable WAN detection in NDS

    Improvements:
    #338 (configurable rate limiter), #335 (portal assets from source), #321 (identity loopback), #316 (200 not 500 on /usage), #310 (sat standardization), #265 (sysexec wrapper), #294 (test env socket)

    Open PRs ready for review (CI green, LGTM posted):

    gonuts-tollgate v0.10.0 (15 PRs)

    URL normalization, swap race fix, DLEQ per-proof, NUT-13 big.Int, error wrapping, panic guards, non-atomic swap fix, 429+5xx retry, module rename.

    Recommendation

    Merge #314, #315, #317 first. Then cut v0.6.0.

  5. Amperstrand commented on Jul 30, 2026

    @Amperstrand
    Collaborator

    Three PRs blocking v0.6.0 — all tested on physical GL-MT3000 hardware

    1. PR #315 — NDS gate-open after autopay (fixes #88)

    #315
    Payment succeeds, client authenticates, but ndsctl returns exit 1 on already-authenticated clients. Go code treats this as failure. Gate never opens. This is THE blocker for end-to-end payment.

    2. PR #314 — Mint HTTP 429 retry (fixes #260)

    #314
    Cashu mints (coinos.io, testnut) rate-limit quote polling. Currently fails immediately as "payment-processing-failed." Adds 3 retries with 2s/4s backoff.

    3. PR #317 — Firewall API port 2121 to LAN only (fixes #226)

    #317
    nftables rule blocking TCP 2121 from WAN. Currently the payment backend is reachable from upstream.

    All three PRs build + test clean, updated Jul 29. CI green. Reviews posted.

    @c03rad0r — these three unblock end-to-end payment flow. Can we get them merged so we can cut v0.6.0?

  6. felixfelix-bot commented on Jul 30, 2026

    @felixfelix-bot
    ContributorAuthor

    Update: all three fixes (#88, #260, #226) are merged on main at b528e1d. E2E verified on physical GL-MT3000: payment → NDS gate opens → internet access confirmed.

    Fork release with .ipk: https://github.com/felixfelix-bot/tollgate-module-basic-go/releases/tag/v0.6.1-post-merge

  7. felixfelix-bot commented on Aug 30, 2026

    @felixfelix-bot
    ContributorAuthor

    v0.6.0 cut — plan confirmed (Felix, 2026-08-31)

    Sequence (strict order):

    1. Merge ci: build-matrix trigger hygiene (main/v* only + concurrency + docs-ignore) #369 then ci(apk): cache SDK build trees per target + job timeouts (stacked on #369) #370 (Amperstrand CI stack — both consultant-reviewed 2026-08-31, CI-only: build-package.yml; these pipeline fixes make the release artifacts themselves).
      ⚠️ ci: build-matrix trigger hygiene (main/v* only + concurrency + docs-ignore) #369 shows BLOCKED / review gate not satisfied by bot approvals (felixfelix-bot re-approval 2026-08-31 on record) — needs owner approval/merge in UI. ci(apk): cache SDK build trees per target + job timeouts (stacked on #369) #370 is CLEAN and stacked behind ci: build-matrix trigger hygiene (main/v* only + concurrency + docs-ignore) #369.
    2. Changelog backfill PR — [Unreleased] is missing entries: feat(identity): unified NIP-06 + HKDF + RevealSeed (v2, rebased) #331, feat(wgm): discovery logger — structured scan history + CLI summary #312, feat(tollwallet): WalletPort interface + GonutsWallet adapter + token flow tests #299, fix(#88): trigger NDS session after autopay (review fixes) #347, fix(deps): drop felixfelix-bot fork replace — build against OpenTollGate gonuts-tollgate v0.11.1 #361, fix(ci): resolve pre-existing CI debt — config_manager buildinfo tests + merchant in go-test matrix #365, fix(ci): package-apk portal build uses setup-node 20, not Debian Node 12 #366, refactor(ci): build captive portal once per run, not per matrix leg #368 (+ ci: build-matrix trigger hygiene (main/v* only + concurrency + docs-ignore) #369/ci(apk): cache SDK build trees per target + job timeouts (stacked on #369) #370 CI entries).
    3. Race-test gate before tag — go test -race -count=1 -tags testenv ./... ×2–3 from src/. Known time.Sleep flake candidates: merchant/, wgm/. Triage → fix or document.
    4. Tag v0.6.0 — maintainer manual ONLY. Tag regex ^v\d+\.\d+\.\d+$ triggers build-package.yml one-shot Nostr-wide stable publish (5 blossom servers, kind-1063, unretractable, no draft stage). Never push tags from local checkouts (stray audit tags exist there).

    Why now: 14 PRs merged over 2 months since v0.5.0 remain untagged.

    Tracking: kanban board tollgate-module-basic-go — CHANGELOG-BACKFILL-V060 → RACE-TEST-V060 → TAG-PREP-V060, auto-released by watchdog when step 1 merges land.

  8. Amperstrand commented on Sep 1, 2026

    @Amperstrand
    Collaborator

    State flag from Amperstrand's verification pass (live queries, 2026-09-01 ~22:00Z) — #370 is merged but not on main.

    PR #370 reports MERGED (merge commit 3f53827, 2026-08-30T22:43:30Z, parent a3b1b26), but that commit is not an ancestor of current main: main tip is db8af35 (#369, 2026-08-30T22:42:36Z, parent 020e647). Content check agrees — git diff main..3f53827 is exactly the 16 added lines of build-package.yml (per-target SDK dl/staging/build-tree caches + job timeouts); none of it is on main (no actions/cache for SDK trees; apk legs still run without job timeouts, 6h default).

    Looks like a merge race between the two stacked PRs merged ~54s apart — #370's merge landed on a pre-#369 base and current main doesn't contain it.

    Practical effect on the §6 pre-tag condition ("build-package.yml on main is post-#369/#370"): currently post-#369 only. Tagging now builds the apk artifacts on the uncached, no-timeout pipeline. The 16 lines likely need to land on current main (re-merge or cherry-pick 3f53827) before tag prep.

    Related, also from our verification pass: review filed on #373 — the changelog backfill is missing an entry for #359 (test-mint injection stop; release-relevant) and #353 (vendor IE discovery).

  9. Amperstrand commented on Sep 1, 2026

    @Amperstrand
    Collaborator

    v0.6.0 pipeline dry-run + race-gate corroboration (Amperstrand, 2026-09-01/02)

    1. The post-#369 pipeline builds the full v0.6.0 artifact matrix — verified end-to-end, publish-gated.
    Since #369 makes the workflow skip PR branches, the post-#369 pipeline had never actually run. We dispatched build-package.yml from db8af35 on the Amperstrand fork in a publish-gated variant (only artifact transport changed: blossom → actions artifacts, publish-metadata set if: false, zero blossom/nostr calls; build steps byte-identical; branch dryrun/pipeline-publish-gated):

    Implication for the missing #370 (see our comment above): on the current 25.12.0 SDK images the apk legs complete in ~90 s even uncached, so the missing SDK cache mostly costs runner minutes, not correctness — the job-timeout half of #370 is the more valuable half. Once #370's 16 lines land (re-merge or cherry-pick 3f53827), tag-prep can proceed with high confidence the pipeline itself is green.

    2. Race gate: the documented command does not exercise the flaky packages.
    go test -race -count=1 -tags testenv ./... from src/ covers only the root module — every src/* subdir is its own Go module (nested go.mod), so merchant/, wgm (wireless_gateway_manager/), config_manager/, tollwallet/ etc. never run under the documented gate. We suggest iterating */go.mod (or adding a go.work) for the actual gate.

    Corroboration on db8af35: root module ×3 green; all 15 modules green on full pass 1 (per-module go test -race -count=1 -tags testenv, -p 1); passes 2–3 plus targeted merchant/wgm ×5 iterations in progress — we'll follow up only if something trips.

    Ops note: -race linking of merchant OOM-killed on a memory-constrained box under parallel package build; -p 1 resolves it. Unlikely to matter on CI runners.

    (Changelog coverage gaps for #359/#353: filed as review on #373.)

  10. Amperstrand commented on Sep 8, 2026

    @Amperstrand
    Collaborator

    Status roundup from Amperstrand (2026-09-08, live re-verification)

    Progress since our Sep-1 verification pass:

    Release-cut checklist as of now: ① re-land #370's diff → ② merge #373 → ③ race-gate ×2–3 on fresh main (mind the FiredOnce class; also remember the documented ./... command only covers the root module — iterate */go.mod) → ④ tag.

  11. felixfelix-bot commented on Sep 13, 2026

    @felixfelix-bot
    ContributorAuthor

    v0.6.0 release notes — draft for review

    Prepared by the release-planning worker (kanban t_8e133184, v0.6.0 step 4/4)
    from CHANGELOG.md [Unreleased] plus git log v0.5.0..upstream/main
    (81 commits, 80 merged PRs). Base v0.5.0 (2026-07-03) → upstream/main @
    d6e4e0964e147fa6f9f670e1966872f683941304 (2026-09-09).

    Draft only — nothing was tagged, pushed or published. The tag is a
    maintainer action. After the notes below: the exact tag commands, the
    stray-tag hazard table, and the pre-flight findings from today's live
    verification (one of which — #370 not being on main — affects the release
    itself).

    TollGate v0.6.0 (tollgate-wrt) — release notes

    Status: DRAFT for maintainer review (not published).
    Channel: stable — tag v0.6.0 (bare vMAJOR.MINOR.PATCH; CI maps it to
    c=stable on the NIP-94 events).
    Base: v0.5.0 (2026-07-03) → upstream/main @
    d6e4e0964e147fa6f9f670e1966872f683941304 (2026-09-09) — 81 commits, 80
    merged PRs.

    v0.6.0 is the first release cut from upstream main since v0.5.0.
    It is the payment-correctness release: the three blockers that kept a paying
    customer from reaching the internet — the Cashu wallet's swap-counter race
    that bricked a wallet permanently on a transient mint failure, the missing
    NDS session trigger after autopay, and a mint rate-limit answer reported as a
    generic payment failure — are all fixed and were verified end-to-end on
    physical GL-MT3000 hardware (payment → NDS gate opens → internet access).

    Around that core: the captive portal no longer proxies through NoDogSplash
    (it gets its own uhttpd instance on :2051, with the real client MAC carried
    in the request instead of guessed from ARP), a wallet panic no longer takes
    the whole daemon and every active session with it, dependencies move off a
    personal fork onto the official OpenTollGate/gonuts-tollgate v0.11.1, and
    the CI/release pipeline that produces the artifacts was repaired (it had been
    red on main since Aug 26) and hardened with trigger hygiene and per-target
    SDK caching.

    At a glance

    • Payment path unblocked. NDS session trigger after autopay (Router-to-router autopay implicitly depends on nodogsplash client registration — breaks protocol compatibility #88), mint
      429 → mint-rate-limited (No HTTP 429 handling: Cashu payments fail when mint rate-limits (coinos.io) #260), and port 2121 restricted to LAN
      interfaces (Architecture: move port 2121 to loopback-only (defense-in-depth) #226) are all merged and E2E-verified on GL-MT3000 hardware at
      b528e1d.
    • Wallet safety. The gonuts swap-counter race that permanently bricked a
      wallet is fixed; spending-condition-locked (P2PK/HTLC) tokens are rejected;
      payment-goroutine panics are contained and reported as a signed
      payment-processing-failed notice instead of killing tollgate-wrt.
    • Cashu dependency: gonuts-tollgate renamed Origami74 →
      OpenTollGate (v0.10.0, URL normalisation, DLEQ keyset lookup, NUT-13
      big.Int, 429/5xx retry), now at official v0.11.1 with the personal-fork
      replace directive removed.
    • Captive portal served directly. Dedicated uhttpd on 0.0.0.0:2051; NDS
      keeps a sub-1 KB stub page pre-auth. Client MAC travels with the request.
    • Sessions survive. Quote persistence across restarts, race-free and
      fsync-safe, plus a 24 h NDS session ceiling so a purchased session is not
      deauthed by NDS's 20-minute default.
    • Discovery. Vendor-IE decoding from beacon frames plus structured scan
      history in /etc/tollgate/discovery_log.jsonl and
      tollgate-cli upstream known.
    • CI pipeline fixed and hardened. Red package builds are green again
      (Node 20 for the apk portal build, updated buildinfo tests, src/merchant
      in the test matrix), the portal is built once per run, and push builds are
      restricted to main + v* with docs-only changes ignored and superseded
      runs cancelled.
    • Security. Exposed deployment backup purged from history (with residual
      exposure documented), wildcard CORS removed, backend API LAN-only, 28 CVEs
      patched via x/crypto v0.54.0, 1 MB response-body caps, SSRF guards.

    What's new

    Payments and wallet safety

    The swap-counter race in gonuts-tollgate v0.7.1 was the worst failure mode
    in the tree: the keyset counter advanced only after a successful swap, so one
    transient mint failure (timeout, DNS hiccup, 5xx) left it stuck, every retry
    reused it, the mint answered NUT-02 code 10002 and the wallet was bricked
    with no self-recovery. Fixed in v0.7.4 (counter advances before the swap,
    blinded messages regenerated on retry); the dependency is now at v0.11.1.

    tollwallet.Receive() checks each proof's secret for spending conditions
    before crediting a user: P2PK and HTLC-locked tokens are rejected with
    ErrLockedToken, closing a "free internet with tokens the gateway can never
    spend" path found in the Layer 3 cashu audit (fixes
    #324).
    merchant.Fund() decodes V3 as well as V4 tokens (fixes
    #325).
    Mint HTTP 429 maps to mint-rate-limited with a human-readable message
    instead of a generic payment failure
    (#346,
    #260).

    A panic inside the wallet layer during PurchaseSession's Receive call
    (a mint returning malformed keysets) used to take the whole daemon down with
    every active session on it. The goroutine now recovers and pushes an explicit
    payment processing panicked: … error into the existing result channel, so
    the caller gets a signed payment-processing-failed notice immediately
    (#360).

    Mint URLs are matched with tollwallet.MintURLMatches() in
    calculateAllotment(), so a trailing slash, upper-case host or normalised
    path no longer fails an otherwise valid payment
    (#250,
    #251).

    The post-payment NDS session trigger (router-to-router usage tracking)
    validates the upstream GatewayIP before its port-80 HTTP GET, rejecting
    loopback, link-local and unspecified addresses — a malicious or corrupt
    advertisement can no longer coax the downstream into probing the local box
    (#347,
    #315,
    #88).

    Sessions and quotes

    Lightning quotes persist to quotes.json in the wallet directory and reload
    on startup, and monitoring is relaunched for unpaid quotes, so a restart no
    longer leaves a paying customer staring at "Waiting for payment"
    (#248).
    Persistence is race-free and crash-safe: records are deep-copied under the
    lock instead of shared by pointer, and the temp file is fsynced before the
    rename, with five concurrency tests as regression guards
    (#269).

    NoDogSplash's sessiontimeout is 86400 (24 h) and authidletimeout 3600, so
    NDS's 1200-second default can no longer deauth a client mid-session; the Go
    backend remains the sole authority on purchased session lifetime
    (#363).

    Captive portal

    Portal serving is decoupled from NoDogSplash. /etc/nodogsplash/htdocs is no
    longer a symlink to the SPA: NDS serves a tiny stub (splash.html) that
    JS-redirects to port 2051, with a <noscript> fallback built from the LAN IP
    and CIDR suffixes stripped (192.168.1.1/24 used to produce a malformed URL
    on routers that store the address in CIDR form — found on a GL.iNet MT3000).
    The stub preserves the query string, so the ?clientmac=… parameter NDS
    hands out survives the redirect
    (#363).

    A second uhttpd instance (config uhttpd portal) serves the SPA on
    0.0.0.0:2051 / [::]:2051 with directory listings disabled and the NDS
    users_to_router allow list extended to 2051 (idempotent). The installer
    removes an htdocs that exists as a regular file rather than failing
    silently (#348).

    Clients now come with a MAC attached: the backend accepts a mac field in
    Lightning invoice and Cashu payment requests and a mac query parameter for
    invoice polling and /whoami, so the splash page passes the MAC it already
    knows instead of the backend falling back to ARP/DHCP lookup behind the
    router's reverse proxy. Handlers that returned 400/500 when no MAC could be
    resolved now log and fall back to 00:00:00:00:00:00
    (#358).

    The captive-portal assets are built from source in CI instead of being
    committed as minified JS
    (#335).

    Discovery and upstream

    The wireless gateway manager decodes the TollGate vendor-specific Information
    Element from beacon frames — implemented from the wire-format spec with
    round-trip tests and an encoder overflow check — and boosts a discovered AP's
    score accordingly; the config schema gains an optional vendor_ie_discovery
    field (#353).

    Every scan cycle records each discovered AP (BSSID, SSID, signal, radio,
    TollGate flag, price/step) to /etc/tollgate/discovery_log.jsonl, log-rotated
    and persistent across reboots, with an in-memory registry tracking signal
    range, sample count and latest pricing across scans;
    tollgate-cli upstream known prints that view and upstream scan reports
    is_tollgate, price_per_step and step_size for real TollGate APs
    (#312).
    The NDS enforcement bridge uses portable WAN detection
    (#297)
    and the fw4/nftables enforcement path was repaired
    (#283).

    Degraded mode

    A wallet that fails to initialise no longer parks the router: the merchant
    falls back to degraded mode and recovers dynamically, with a matching portal
    UI, and a regression test pins the fallback
    (#298,
    #309).

    Identity

    New src/identity module: NIP-06 12-word BIP39 mnemonic derivation, HKDF
    (RFC 5869) attribute derivation for IPv4/MAC/password replacing raw SHA-256,
    and a loopback-only /identity/reveal-seed endpoint with a 1 KB body limit.
    14 tests (#331,
    #321).

    Operator tooling and docs

    scripts/token-recovery/ parses /etc/tollgate/tokens-to-recover.txt, checks
    each proof's state at the mint via NUT-07 /v1/checkstate, and recovers
    UNSPENT value through the wallet; -dry-run reports recoverable/spent/pending
    counts without touching the wallet — for funds stranded by the gate-side
    exit-status-1 class of failures
    (#354).

    docs/operator-guide.md documents every tollgate CLI subcommand (service,
    wallet, private network, upstream Wi-Fi, config, health) with flags, example
    output and troubleshooting
    (#188);
    man pages cover the command tree
    (#187).

    A Docker-based integration lab (tests/cloud-lab/) brings up a cdk-mintd
    FakeWallet mint, upstream and reseller TollGate containers against a
    fake-ndsctl shim, and a client container (cdk-cli + nak + pytest) with
    smoke-payment, mint-failure and two-router autopay suites
    (#362).

    Behavior changes worth flagging

    • The portal lives on port 2051. NoDogSplash still answers pre-auth on
      port 80 with a stub page; the SPA itself is served by uhttpd on 2051. If you
      allow-listed or firewalled portal ports, allow 2051.
    • The backend API on port 2121 is LAN-only. A new nftables include
      (30-backend-firewall.nft) blocks the API on non-LAN interfaces. WiFi
      clients keep reaching the payment endpoint through the NDS
      users_to_router rules; WAN-side and upstream clients can no longer probe
      it (#345,
      #226).
    • CORS no longer echoes a wildcard. Access-Control-Allow-Origin: * is
      gone; the origin is echoed only for local/private origins and for pages the
      router itself serves on another port, with Vary: Origin added. POSTs with
      content types other than text/plain or application/json return 415
      (#349).
    • NDS timeouts are 24 h / 1 h (session / idle), by design — the Go backend
      decides session lifetime.
    • Setup rerun on upgrade. The setup script's version marker
      (SETUP_VERSION) is bumped, so upgrading re-runs the full setup and
      installs the stub + portal instance. Existing management-WiFi credentials
      are preserved: the private SSID/PSK is reused from
      wireless.private_radio0 and only generated when none is configured.
    • /tmp/tollgate-setup.log is root-only (0600) — it contains the
      generated management-WiFi password.
    • Rate limiting is configurable via TOLLGATE_RATE_LIMIT_RPM
      (#338).
    • Config schema version is unchanged (v0.0.8); vendor_ie_discovery is
      optional and defaults to false. Sat amounts are standardised and the
      advertisement payload was corrected with an in-place config migration
      (#310).

    Notable bug fixes

    • Payment-goroutine panics no longer kill the daemon
      (#360).
    • The local build script no longer injects the test mint into release builds:
      GitBranch was left unknown, which IsDevBuild() treated as a feature
      branch, adding a dummy-invoice test mint to every locally built .ipk
      (#359).
    • Splash redirect preserves query parameters, so MAC-based session logic sees
      the real client MAC; NoDogSplash no longer overrides purchased session
      duration (#363).
    • /usage returns 200 instead of 500 when there is no session
      (#316).
    • HTTP response bodies are limited to 1 MB across LNURL resolve, invoice
      fetch, gateway probes and the usage tracker, preventing OOM on
      resource-constrained routers
      (#274).
    • Notice event codes and the advertisement tips tag match TIP-01/02 instead
      of implementation-specific codes and non-existent TIP numbers
      (#240).
    • Wireless config is read gracefully when /etc/config/wireless is absent;
      the dead firewall-tollgate include (silently rejected by fw4) is gone
      along with two Makefile references to it that broke package builds
      (#196,
      #235).
    • AP setup recovers on reinstall/upgrade
      (#216);
      merchant profit-share payouts are owner-first and robust
      (#168);
      the valve supports a post-payment redirect with configurable auth delay
      (#200).

    Security

    • Exposed deployment backup purged from history. A router deployment
      backup committed by accident in fix: accept client MAC from request body/query param #358 (deploy-backup-20260730/) contained
      the merchant private identity key, an ecash wallet.db and spendable
      recovery tokens. main was rewritten on 2026-08-27 and force-pushed;
      SECURITY.md records the incident and the residual exposure, and key
      rotation is tracked in
      #364.
      If you ran any build between those dates, treat the affected key material as
      compromised.
    • Wildcard CORS removed, backend API restricted to LAN interfaces
      (#349,
      #345).
    • P2PK/HTLC-locked tokens rejected, 1 MB response-body cap
      (#330,
      #274).
    • SSRF guards: LNURL callback URL validation
      (#198),
      TOCTOU-safe validation via a custom DialContext
      (#245),
      upstream gateway IP validation.
    • RFC 1918 isolation — WiFi clients blocked from upstream private networks
      (#234);
      UCI key/value validated against control characters
      (#222);
      config file permissions tightened 0644 → 0600
      (#221);
      error responses sanitised so internals are not leaked
      (#202).
    • Supply chain: x/crypto v0.38.0 → v0.54.0 and x/net v0.40.0 → v0.57.0
      (28 CVEs patched), plus a dependency-sync drift checker across the 14
      go.mod files (#307,
      #223).

    Dependencies

    • gonuts-tollgate: module path renamed Origami74 → OpenTollGate and
      bumped to v0.10.0 (URL normalisation, swap-counter race, DLEQ keyset
      lookup, NUT-13 big.Int, 429/5xx retry)
      (#304),
      via v0.8.0 (V4 short keyset ID resolution
      (#286))
      and v0.9.0 (#292,
      go.sum corrected in
      #293),
      V2 keyset swap crash fix at v0.7.6
      (#281).
    • The personal-fork replace directive is gone now that the official
      OpenTollGate v0.11.1 tag exists; both modules re-tidied against it
      (#361).
    • Go toolchain: GO_VERSION 1.25 in CI
      (#244).

    Internal changes (CI, tests)

    • Spec-quote drift is checked in CI against current cashubtc/nuts HEAD; one
      drifted NUT-03 quote was fixed and a NUT-05 quote added
      (#376).
    • src/tollwallet pins NUT-00 HashToCurve output against the canonical
      cross-implementation vectors (gonuts/btcec ↔ cashu-core-lite/k256 ↔
      coincurve/Python), because divergence there makes NUT-07 checkstate report
      spent proofs as unspent
      (#351);
      src/tollgate_protocol went from 0 % to 15 validator tests
      (#337);
      post-swap-fee crediting is characterised by tests
      (#342).
    • New src/sysexec/ safe-exec wrapper (Runner interface, context, timeout,
      retry) — foundation for the 37 exec.Command call sites
      (#265);
      new src/tollwallet WalletPort interface with a GonutsWallet adapter
      (#299).
    • NUT spec quotes added as greatspectations Layer 1
      (#327).
    • The merchant race suite was de-flaked for this release: two
      time.Sleep-instead-of-poll tests on async callbacks became a polling
      waitFor helper (test-only); 10/10 modules green, 3 of 3 full
      -race -count=1 -tags testenv iterations, pre- and post-fix
      (#374).
    • [Unreleased] accumulated 10 missing entries so this release's changelog
      is complete (#373).
    • src/merchant joined the test matrix and config_manager buildinfo tests
      were updated for the five extra production mints
      (#365);
      package-apk uses Node 20 instead of the SDK container's Node 12, which had
      been failing the portal build on every push since Aug 26
      (#366);
      the portal is built once per run instead of per matrix leg, removing ~15
      builds and per-leg commit drift
      (#368);
      build triggers are restricted to main + v* tags with docs-only paths
      ignored and redundant runs cancelled
      (#369);
      NIP-94 1063 events are published directly in the build step
      (#230).
    • The tree is gofmt-clean (16 files, #355, plus the pre-commit gofmt check
      #343), so the documented pre-PR gate prints nothing.
    • Known gap (see maintainer note below): the #370 SDK build-tree cache
      and job timeouts are not on main — the tag build runs without them.
    • The Nostr CI workflow was ported to .ngit/act/workflows for ngit CI
      (#377).

    Known issues

    • tollgate wallet drain cashu can lose funds
      (#375,
      open).
      Reproduced on a GL.iNet MT3000 over SSH without a PTY: the command
      prints Operation cancelled. and exits 0 without draining, and --json can
      destroy funds on a wallet whose per-mint registry holds a duplicate or stale
      entry. This is the CLI path, not the payment path. Check the issue before
      draining a wallet that holds funds; if you drain manually, work from the
      non-JSON output and verify the mint's balance afterwards.
    • NoDogSplash pre-auth is still fragile for unmappable clients. Stock NDS
      5.0.2 answers HTTP 500 (its own error page) on every request from a client it
      cannot map to a MAC (ip neigh miss). The SPA loads from uhttpd regardless,
      which is the mitigation; the NDS-side behaviour is upstream and unaddressed.
    • src/cli, src/upstream_detector and src/upstream_session_manager are
      still outside the standalone go-test matrix
      pending the same module rewrite
      src/merchant received
      (#365).
    • A latent race remains in the merchant test suite.
      TestSetOnFirstReachableForDegraded_FiredOnce is a different class from the
      de-flaked tests (registration resets hadReachableMint, so the next
      proactive check deterministically queues a spurious go cb() and the bare
      zero-assertion races the detached goroutine). Green runs are the normal case;
      the race is latent, not gone — measured on 96bf6a2.
    • The NDS gate-open retry path is still load-bearing. ndsctl auth can
      return exit 1 for an already-authenticated client; the fix treats that as
      success, and the token-recovery tool remains the safety net for any residual
      exit-status-1 failures.

    Verification status (read this before trusting a build)

    Upgrade notes

    • Back up the wallet directory and /etc/config/tollgate before
      upgrading.
      The deployment backup that leaked in August is a reminder of
      what that data is worth.
    • Package filenames are tollgate-wrt_v0.6.0_<arch>.ipk / …_<arch>.apk
      (the tag name verbatim; UPX variants add a -upx-… suffix before the
      extension).
    • .apk (OpenWrt 25.x): apk add --allow-untrusted tollgate-wrt_v0.6.0_<arch>.apk; apk-tools sees the normalised version
      0.6.0-r0.
    • .ipk (OpenWrt 24.10 and earlier): opkg install tollgate-wrt_v0.6.0_<arch>.ipk; the control-file version is v0.6.0.
    • Do not reuse v0.6.0-alpha1 or any v0.7.0-alpha* package. Those tags
      are fork-only (except the upstream v0.6.0-alpha1 re-point) and point at
      branches that were never merged; the alpha1 GitHub release has 0 assets.
    • Expect a setup rerun after installing. Existing WiFi/portal
      configuration is preserved, including management-WiFi credentials; check
      /tmp/tollgate-setup.log (root-only) afterwards.
    • If you reached the backend API from outside the LAN, that path is closed
      (port 2121 is LAN-only now). Use the portal path WiFi clients use, or reach
      the router's shell.
    • Config schema version is unchanged (v0.0.8) — no manual migration.

    Getting v0.6.0

    • Packages: CI builds .ipk and .apk per architecture on the tag and
      uploads each artifact to 5 Blossom mirrors; every artifact is announced as a
      NIP-94 1063 event (n=tollgate-wrt, v=v0.6.0, c=stable) on the project
      relays. Download from any url tag and verify the sha256 against the
      event's x tag
      before installing:

      nak req -k 1063 -a 5075e61f0b048148b60105c1dd72bbeae1957336ae5824087e52efa374f8416a \
          --tag n=tollgate-wrt --tag v=v0.6.0 --limit 50 \
          wss://relay.damus.io wss://nos.lol wss://nostr.mom
    • From source: scripts/build-sdk-package.sh cross-compiles the binaries
      and stages the canonical packaging/ recipe into the OpenWrt SDK, producing
      either format.

    • Announcements: RELEASE-NOTES.md and the v0.6.0 section of
      CHANGELOG.md are the authoritative description of the release; the per-PR
      detail lives in the changelog.

    • Reporting problems: open an issue at
      github.com/OpenTollGate/tollgate-module-basic-go
      with the router model, the package version, and /tmp/tollgate-setup.log if
      setup is involved. Read the known-issues section first.

    Contributors

    Thank you to everyone who wrote, reviewed and tested this release:
    Amperstrand, felixfelix-bot, and the reviewers and testers on
    #339
    and the individual PRs.

    Maintainer tag checklist — v0.6.0

    Operator action. Not executed by the preparing agent. Nothing was tagged,
    nothing was pushed, no branch was created.

    SHA to tag: d6e4e0964e147fa6f9f670e1966872f683941304 (upstream/main HEAD,
    2026-09-09). Re-resolve it at tag time — main moves.

    0. Go / no-go

    1. Exact tag commands

    cd ~/repos/tollgate-module-basic-go
    git fetch upstream --tags --prune
    SHA=$(git rev-parse upstream/main)            # expect d6e4e09… — re-check
    git log -1 --format='%H %ci %s' "$SHA"
    
    # (1) This clone holds a STALE LOCAL tag named v0.6.0 (899321ffc4, 2026-08-27,
    #     NOT on upstream/main — it predates the 2026-08-27 history rewrite).
    #     `git tag v0.6.0 "$SHA"` would fail with "tag already exists", and
    #     `git push upstream v0.6.0` would push that stale commit. Clear it first.
    git rev-parse v0.6.0^{commit}                 # expect 899321ffc4… (stale)
    git tag -d v0.6.0                             # local only; touches no remote
    
    # (2) Annotated tag on the upstream main commit — never on HEAD, never on the fork.
    git tag -a v0.6.0 -m "tollgate-wrt v0.6.0" "$SHA"
    git rev-parse v0.6.0^{commit}                 # must equal "$SHA"
    
    # (3) Push EXACTLY this one tag. Requires maintainer credentials — the
    #     felixfelix-bot token gets 403 on OpenTollGate.
    git push upstream refs/tags/v0.6.0
    
    # (4) NEVER run `git push upstream --tags`. That single command publishes every
    #     stray tag in the HAZARD table below as an unretractable Nostr release.

    Post-push verification (abbreviated from docs/release-process.md §4):

    git ls-remote --tags upstream | grep 'refs/tags/v0.6.0'    # tag is upstream
    git rev-parse v0.6.0^{commit} ; git rev-parse upstream/main # must match
    gh run list --repo OpenTollGate/tollgate-module-basic-go \
        --workflow build-package.yml --limit 5
    gh release view v0.6.0 --repo OpenTollGate/tollgate-module-basic-go
    nak req -k 1063 -a 5075e61f0b048148b60105c1dd72bbeae1957336ae5824087e52efa374f8416a \
        --tag n=tollgate-wrt --tag v=v0.6.0 --tag c=stable --limit 50 \
        wss://relay.damus.io wss://nos.lol wss://nostr.mom

    Every architecture in the declared matrix must be present (a partial set reads
    as a broken feed); v must be the tag name verbatim and c must be stable;
    download at least one artifact and check its sha256 against the event's x
    tag before announcing.

    2. HAZARD — stray tags in local checkouts

    The workflow trigger is the glob tags: ["v*"], not a regex: every tag
    starting with v fires build-package.yml. The c= channel is what the
    regex decides (^v[0-9]+\.[0-9]+\.[0-9]+$ → stable, -alpha/-beta →
    those, everything else → dev) — a dev publish is still a full Blossom
    upload plus permanent kind-1063 events. Any v* tag also keeps the full UPX
    compression matrix (14 matrix legs), so a stray push burns a full-size build.

    Stray local tag Commit On upstream/main? If it were pushed
    v0.6.0 899321ffc4 (2026-08-27) no (pre-rewrite tree) WOULD publish pre-rewrite artifacts as c=stable
    v0.6.1-post-merge b528e1d734 yes c=dev publish of an old commit
    v0.7.0-alpha9 7640f763f1 no (unmerged fork branch) c=dev publish of an orphan branch
    v0.7.0-alpha10 1e70bcac3b yes c=dev publish of an old commit
    v0.6.0-endo-handover 946a06915d yes c=dev publish of an old commit
    v0.6.0-alpha1 414650310b exists upstream never re-push or move it

    Publishing has no draft stage: publish-metadata signs and publishes the
    NIP-94 1063 events directly with NSEC_HEX to wss://relay.damus.io,
    wss://nos.lol, wss://nostr.mom, wss://relay1.orangesync.tech,
    wss://relay2.orangesync.tech, after uploading each package to 5 Blossom
    mirrors (blossom.primal.net, blossom.psbt.me,
    blossom1.orangesync.tech, blossom2.orangesync.tech, drive.cashu.email;
    BLOSSOM_MIN_SUCCESS=1). Events are permanent — deletion requests are
    best-effort. There is no way to unpublish a mistaken tag push.

    3. Pre-flight findings (verified live, 2026-09-13)

    1. #370 is not on main (still true today). gh pr view 370 says
      MERGED, but git merge-base --is-ancestor 3f53827 upstream/main → false.
      git diff upstream/main 3f53827 -- .github/workflows/build-package.yml is
      exactly 16 added lines: 4 × timeout-minutes (compile 30, portal 15,
      ipk 30, apk 90) + an actions/cache@v5 block caching /builder/dl,
      /builder/staging_dir, /builder/build_dir per SDK target. None of it is
      on main: the only cache on main is actions/setup-go's module cache,
      and the only timeout-minutes is publish-metadata: 15. Cause: ci(apk): cache SDK build trees per target + job timeouts (stacked on #369) #370's base
      was the ci/trigger-hygiene branch (ci: build-matrix trigger hygiene (main/v* only + concurrency + docs-ignore) #369), not main; ci: build-matrix trigger hygiene (main/v* only + concurrency + docs-ignore) #369 landed on
      main as a squash (db8af35) 54 s before ci(apk): cache SDK build trees per target + job timeouts (stacked on #369) #370's merge, so ci(apk): cache SDK build trees per target + job timeouts (stacked on #369) #370's merge
      went to the already-merged branch. Corroborates Amperstrand's 2026-09-01
      flag on this issue.
      Release impact: the tag build runs without the SDK-tree cache and job
      timeouts, so the apk legs fall back to the 360-minute default; the #370
      entry in the [Unreleased] changelog (docs(changelog): backfill [Unreleased] for v0.6.0 #373) — and PR docs(release): single-source the version and prepare v0.6.0-alpha2 #380's
      RELEASE-NOTES.md — describe changes that are not on main. Suggested fix
      before the tag: land 3f53827's 16 lines on main (fresh PR cherry-picking
      them is enough), then the changelog/notes claims become true.
    2. SETUP_VERSION is still a hand-written literal on main
      (packaging/files/etc/uci-defaults/99-tollgate-setup: SETUP_VERSION="v0.6.2"
      — a version that never matched a release). docs(release): single-source the version and prepare v0.6.0-alpha2 #380 replaces it with a
      __TOLLGATE_VERSION__ placeholder substituted from the packaged version.
      Until docs(release): single-source the version and prepare v0.6.0-alpha2 #380 merges, a v0.6.0 package ships a setup script whose marker says
      v0.6.2. Functionally it still triggers the full setup rerun; it just
      disagrees with the package version.
    3. PR docs(release): single-source the version and prepare v0.6.0-alpha2 #380 does not contain ci(apk): cache SDK build trees per target + job timeouts (stacked on #369) #370's content either (git merge-base --is-ancestor 3f53827 fork/release/v0.6.0-alpha2-prep → false), so the
      "SDK build tree is cached and every heavy job has a timeout" bullet in its
      RELEASE-NOTES.md is inaccurate on that branch too.
    4. VERSION does not exist on main — it is added by docs(release): single-source the version and prepare v0.6.0-alpha2 #380. A tag cut
      before docs(release): single-source the version and prepare v0.6.0-alpha2 #380 merges has no version-vs-tag guard; a tag cut after must match
      VERSION byte-for-byte.
    5. Board bookkeeping: the RACE-TEST-V060 card is still in the review lane
      on the board, but its deliverable PR test: de-flake race suite for v0.6.0 #374 is merged on main (96bf6a2) —
      the release content is present and the card can be closed.
  12. added a commit that references this issue on Sep 13, 2026
  13. 33 remaining items

  14. Amperstrand commented on Sep 22, 2026

    @Amperstrand
    Collaborator

    v0.6.0-alpha4 is CUT — tag pushed and verified; only DQ05 remains

    Remaining is DQ05-only now (per the sequence above, minus the tag which is done): mirror push — main plus the v0.6.0-alpha4 tag, skipping the never-published alpha1/2/3 — then scripts/ngit-ci-release.sh v0.6.0-alpha4 alpha fd5829737745e5da0f3adca256b40a8d12d65f9e. The publication audit follows from this side once the announcements exist (or their verified absence, per the #445 gate).

  15. Amperstrand commented on Sep 22, 2026

    @Amperstrand
    Collaborator

    Third release blocker diagnosed — and the v0.6.0-alpha4 tag is stale against the current release definition

    1. The node-pin defect (deterministic stage-1 red). The 13:05:32Z stage-1 failure on 427c8e38 (ERROR: node v20.20.2 != pinned v22.17.0) is not a flake: the lane's build-portal job hardcodes node-version: '20' while packaging/build-inputs.json pins 22.17.0. That commit is an ancestor of the tagged fd582973 — any drive at the current tag fails stage 1 deterministically.

    2. #477 is the fix and is now land-ready. It conflicted on current main; I rebased it (230095e6, force-pushed, conflicts resolved keeping main's PORTAL_REF comment + folding the changelog entry into [Unreleased]): node pinned to 22.17.0, an npm-vs-manifest verification step added, YAML validated. It needs one approving review — requested.

    3. The tag is stale against the release definition. Main now carries the team's updated [v0.6.0-alpha4] - 2026-09-22 section (the packaging-pre-release framing from #513's lane) and re-dated RELEASE-NOTES — but my v0.6.0-alpha4 tag (pushed 13:06Z on fd582973) predates the #513/#478/#491 wave and carries the node defect. Driving at it would publish artifacts that match neither the changelog nor a green pipeline. Before DQ05 acts, the tag must be resolved: either delete the never-published tag and re-tag the final release commit (it was never mirrored, never announced — zero consumers), or keep the name and cut alpha5. Same decision class as alpha3→alpha4; team's call.

    Sequence from here: #477 review+merge → tag resolution (re-tag on the final commit) → DQ05 (mirror push + drive) → publication audit.

  16. Amperstrand commented on Sep 22, 2026

    @Amperstrand
    Collaborator

    Track-2 completion (2026-09-22 afternoon)

    Merged (window, ruleset restored + verified): #491 (epoch token-emit — the lane's last gating defect fix) and #469 (alpha4 prep, post-#491 rebase). main now carries VERSION=v0.6.0-alpha4 + the #480 fix + the epoch fix. The release now waits on DQ05 alone (mirror push → tag → drive); after publish we'll run the read-only gate verification against the events.

    Verification coverage now spans every open PR. This round: #513 (request-changes — live QEMU validation of pre-auth :443 green end-to-end, but a real idempotence defect found on-router: the duplicate-check regex can't match uci's quoted single-line list rendering → one duplicate rule per rerun; plus mandatory rebase — main already shipped a different alpha4) and the four light PRs (#492 land-with-followups, #508 land, #493 land-with-followups — its audit-gap flags note #507/#511 as the open invariants, #512 land — full lane green on a --no-cache build after catching a cached-image silent-foreign-binary trap).

    Fund-safety pair flipped to land-ready: #507 and #511 — cli tidy landed (#515), CHANGELOG entries added at their branch heads, both verification comments updated to land-with-followups.

  17. Amperstrand commented on Sep 22, 2026

    @Amperstrand
    Collaborator

    Correction to "waits on DQ05 alone": #477 must merge first — the node-pin defect is still in the main tip

    Verified just now (13:4xZ): upstream/main (d622688b) still carries node-version: '20' in .ngit/act/workflows/build-package-binaries.yml (line 333) against the manifest's 22.17.0 pin — the defect behind the live 13:05:32Z stage-1 failure (ERROR: node v20.20.2 != pinned v22.17.0). A DQ05 drive at any current commit fails stage 1 deterministically.

    #477 is the fix and is ready: rebased onto the current tip (230095e6, MERGEABLE), node pinned to 22.17.0 + an npm-vs-manifest verification step. It is Amperstrand-authored and awaits one approving review (c03rad0r requested).

    Corrected sequence: #477 review+merge → tag resolution (per the comment above — the current v0.6.0-alpha4 tag on fd582973 predates the wave and carries this same defect) → then DQ05 (mirror push → tag → drive) → publication audit. The epoch fix (#491) was the last shard-generator defect; this is the last stage-1 one.

  18. Amperstrand commented on Sep 22, 2026

    @Amperstrand
    Collaborator

    Third blocker FIXED — the final fold is up as PR #523; DQ05 sequence corrected

    The corrected DQ05 sequence (one review stands between here and it):

    1. chore(release): fold the post-#477 wave into v0.6.0-alpha4 #523 review + merge
    2. Delete the stale v0.6.0-alpha4 tag (fd582973 — never mirrored, never announced, predates the wave, carries the node defect)
    3. Annotated tag v0.6.0-alpha4 on chore(release): fold the post-#477 wave into v0.6.0-alpha4 #523's merge commit
    4. Mirror push (main + the tag, skip alpha1/2/3) + ngit-ci-release.sh drive
    5. Publication audit (both publisher keys, ≥2 mirrors, sha256 vs x)
  19. added a commit that references this issue on Sep 22, 2026
  20. Amperstrand commented on Sep 22, 2026

    @Amperstrand
    Collaborator

    v0.6.0-alpha4 is CUT on the final content — only DQ05 remains

    • chore(release): fold the post-#477 wave into v0.6.0-alpha4 #523 merged (16:16:16Z, eaf5e292) — the release-content fold is on main: the 24-entry [v0.6.0-alpha4] section (including the v4 cashuB short-keyset token fix), the notes bullet, check-version-sync green.
    • The stale tag is resolved: the never-mirrored, never-announced v0.6.0-alpha4 tag (881478bb → fd582973, which carried the node-pin defect and predated the wave) was deleted, and the annotated tag re-cut on chore(release): fold the post-#477 wave into v0.6.0-alpha4 #523's merge commit — verified: tag object 6737ddb9 → commit eaf5e2928c585422b49e0bd0c88d36f31a47da6b == the fold's merge commit, ancestor of main, VERSION == tag name.

    The remaining sequence is DQ05-only (maintainer key):

    1. Mirror push: main (now eaf5e292) + the v0.6.0-alpha4 tag — skip alpha1/2/3
    2. Drive: scripts/ngit-ci-release.sh v0.6.0-alpha4 alpha eaf5e2928c585422b49e0bd0c88d36f31a47da6b
    3. The publication audit follows from this side (both publisher keys, ≥2 mirrors, sha256 vs x tags)
  21. Amperstrand commented on Sep 22, 2026

    @Amperstrand
    Collaborator

    Feed note (pre-empting confusion): the 16:18:34Z stage-1 failure on dbd0777c is the node-pin defect's last gasp, not a fourth blocker — dbd0777c is #518's merge, which predates #477's (22edca2e, 16:06:05Z); its tree still carried node-version: '20'. The tagged eaf5e292 descends from #477's fix, so the first post-#477 stage-1 run — which will be the DQ05 drive itself — should be green for the first time. Expect red pre-#477 backlog runs (bf4ca69d, dbd0777c) until then; they are history, not signal.

  22. Amperstrand commented on Sep 22, 2026

    @Amperstrand
    Collaborator

    Final pre-alpha4 merge window — complete (2026-09-22 evening)

    15 PRs merged across three window passes (ruleset lifted/restored and verified after each):

    The window set: #518 (#516 uci dedupe fix — the accumulation disease, with live 27×2051/4×443 router evidence), #507 (pending-proof reclaimer), #486 (mint re-admission), #512 (outage-refusal lane), #492 (schema-defaults parity), #485 (lab hygiene + compose layering), #484 (two-router skip), #476 (external-mint lane), #470 (placeholder guard), #474 (UPX pin), #477 (portal toolchain pin), #479 (T16 docs), #493 (fund-safety invariants doc), #508 (CONTRIBUTING nym/brand docs) — plus #517 (portal repin, maintainer-merged mid-window).

    The one straggler: #511 (late-Receive reconciliation) — GitHub's mergeability cache has reported CONFLICTING for hours while git merge-tree proves the tree CLEAN at every pushed head, including after an empty-commit recomputation trigger. Content is conflict-free and race-proven; note posted on its thread with the workaround.

    main now carries everything alpha4 should be: the #480 restart-brick fix (library v0.12.1), the epoch token-emit, pre-auth :443, the uci dedupe fix, the reclaimer, late-mint admission, aggressive downgrade recovery, route-metric fix, prepay defaults, the full lab/test hardening set, and the finalized [v0.6.0-alpha4] changelog. VERSION = v0.6.0-alpha4.

    The human sequence is exactly three steps from a published alpha: (1) resolve #511 via UI if desired (optional — it can ride alpha5), (2) tag v0.6.0-alpha4 at the merge commit, (3) DQ05: mirror push + scripts/ngit-ci-release.sh v0.6.0-alpha4 alpha <sha>. On publish, we run the read-only gate verification against the events.

    Remaining open: #511 (cache-stuck, clean), #524/#522/#519 (new from the concurrent session — unverified yet), #487/#488 (fork-blocked rebases), #425/#391 (post-release track).

  23. Amperstrand commented on Sep 22, 2026

    @Amperstrand
    Collaborator

    Milestone: stage 1 is GREEN on #477's merge — the fix is proven on the runner

    The coordinator's backlog reached 22edca2e (#477's merge commit) and build-package-binaries.yml succeeded (17:03:47Z) — the first green stage-1 run, confirming the node-pin fix works end-to-end on the actual runner (go-test green there too). When the DQ05 drive runs at the tagged eaf5e292 (a descendant), stage 1 passes.

    The repro-check.yml red on the same commit (17:09:08) is a lane flake, not a regression — evidence: the error is SOURCE_DATE_EPOCH not set and no git history (the act-workspace epoch starvation), the same error appears on unrelated commits (d622688 13:53Z), and the same commit's earlier run resolved the epoch fine (d622688 13:48:56: SOURCE_DATE_EPOCH=1790081077 ✅). The resolve step is nondeterministic on this runner; the release pipeline does not depend on the repro-check lane — stage 1 → shards → announce is the gate.

    DQ05 remains the only gate: mirror push (main @ eaf5e292 + the v0.6.0-alpha4 tag) → drive → audit.

  24. Amperstrand commented on Sep 22, 2026

    @Amperstrand
    Collaborator

    Lane status triage (2026-09-22 ~19:00 UTC), so the reds aren't mistaken for code:

    • go-test.yml — green on every push.
    • repro-check.yml — red on every push; fixed by open ci(repro): resolve SOURCE_DATE_EPOCH before the SDK Go audit #519 (verified independently: the fix's green path replicated locally, the failure live on current main; changelog bullet added on the branch at 885b9e3). Merge clears it on the next push.
    • test.yml — red at 18:00 / 18:33 / 18:54, infrastructure, not code: the captured signature is proxy.golang.org/golang.org/x/time/@v/v0.15.0.zip: net/http: TLS handshake timeout → FAIL [setup failed] in the main-test job — a cold module-cache download hitting flaky runner egress. Contrast: go-test.yml runs the same root-module graph green with a cache hit. Control from a dev host: cold GOMODCACHE download of the exact module + go test -count=1 -tags testenv . both green on the same tree. A re-run (ideally until the setup-go cache warms) should clear it; nothing to fix in-tree. If the flakiness recurs, the cheap hardening is enabling the setup-go module cache on main-test like the other jobs.
    • Release drive: 0 tag-scoped runs, 0 kind-1063 artifacts for v0.6.0-alpha4 — the pipeline has not been driven yet. Tag currently at eaf5e29.

    Sequence to shipping alpha4 stands: merge #519 → next push turns repro-check green (and test.yml on a lucky/cache-warm run) → drive the lane with the operator key → verify_publication.sh v0.6.0-alpha4 alpha - closes the audit.

  25. Amperstrand commented on Sep 22, 2026

    @Amperstrand
    Collaborator

    While-you-were-waiting verification wave #3 (2026-09-22 evening) — all 8 new PRs covered

    Every PR from the concurrent session's latest batch now has an evidence pass:

    PR Disposition Key finding
    #519 repro-check epoch fix land-with-followups failure mechanism proven (ngit checkouts have NO .git — epoch guard dies); fix verified both ways + full live SDK audit passes at head (SDK Go pins match the live OpenWrt feeds); sole gap: missing CHANGELOG bullet. This un-breaks a main CI lane red since #448.
    #532 fee-precheck bound request-changes mechanism sound (3s wall-clock bound), composes with #447; CHANGELOG links wrong PR (529→532)
    #531 SSID privacy (replaces #487) request-changes gate byte-identical to #487's verified content, deployed SSIDs preserved (no churn); rebase-artifact duplicate heading
    #530 rootfs test tier land-with-followups tier works exactly as claimed (134/0) — but a planted #516-class regression still passes: zero nodogsplash allow-list assertions (the exact class the tier exists for); add the stability assertion
    #528 fleet credentials (fixes #509) request-changes fail-closed gate verified on the real pytest surface; but the same defaults survive in three sibling files + standalone flash_routers.py bypasses the gate; BLOSSOM_URL env-only, no sha256 pin
    #522 mint-matrix lane request-changes one-char regression found live (${pair%%=} → %%=*; as-committed, every matrix 6-errors); with the fix, 6/6 green locally + FUND-FAIL skip + no-matrix gate proven
    #524 SSID contract (replaces #489) request-changes full contract verified (all four drift classes red, wiring exercised); one repo-rule fix: CHANGELOG entry inside the tagged alpha4 section

    Cross-cutting: the replacement trio (#531/#529/#524) successfully routes around the fork workflow-scope block — the queue is fully in-repo again. #529 (epoch stamp, replaces #488) is MERGEABLE and its predecessor was verified land — recommend the same treatment after a freshness pass.

    Release unchanged: alpha4 events still zero, mirror still stale — the DQ05 tag+drive remains the only step. All wave-#3 blockers above are one-liners except #522's char fix and #530's missing assertion.

  26. Amperstrand commented on Sep 25, 2026

    @Amperstrand
    Collaborator

    v0.6 release-content validation — evidence dossier + state (from the quality campaign session)

    Content validated: main 2226a04c (= #553 merged; tag v0.6.0-alpha4 + 13 commits). Full campaign, all tiers green:

    Release decision state: fold on current main → **v0.6.0-alpha5\** (Option C — fresh version, no second tag deletion). Trigger: #546 stalled approved-but-conflicting; shipped-bytes content at 2226a04` is complete regardless (#554/#556 change zero runtime bytes). Fold PR awaits a go + the review batch landing.

    Queue state: #554/#556 mergeable awaiting review; my five previously-conflicting PRs (#522 #524 #530 #531 #535) rebased onto 2226a04c, each re-validated on its new base (rootfs tier 470/0), all mergeable. #546 awaits felix's rebase (note on the PR). DQ05 still the publication blocker — mirror frozen, zero kind-1063.

    Minor finds: (1) scripts/__pycache__/ngit-gen-shards.cpython-312.pyc is tracked on main — one-line cleanup candidate. (2) local-build-ipk.sh required make portal-build first or it silently shipped a JS-less portal — guard + test now in #556. (3) Happy-path suite's known-issues entry for the Lightning lane was deleted by #553 itself — suite now hard-fails if it regresses.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions