fix(fleet-ui): pair-dialog v-else compiler error + TTL docstring correction #27

Merged
padreug merged 2 commits from fix/pair-dialog-and-ttl-doc into main 2026-06-18 23:01:16 +00:00
Owner

Two post-merge corrections to the pairing UI (#25) and TTL work (#23), both validated against a live regtest stack (FakeWallet + lnbits dev@b5fba561 + real nsecbunkerd dev@cb8dd0c).

1. Fleet UI — Pair dialog Vue compiler error 30 (fix(fleet-ui))

The Pair dialog (#25) had two interleaved v-if/v-else sibling pairs — q-card-section + q-card-actions for each of the two steps:

[section v-if][actions v-if][section v-else][actions v-else]

Vue matches v-else to the immediately preceding sibling, so the second v-else (actions) trailed a v-else (section) — illegal. The compiler threw error 30 (X_MISSING_END_TAG / "v-else has no adjacent v-if"), a SyntaxError that broke the entire Vue mount — the whole extension page failed to render, not just the dialog. (A plain tag-balance check passes; this is a directive-adjacency rule, caught with @vue/compiler-dom.)

Fix: wrap each step's section+actions in a single <template v-if> / <template v-else> so there's exactly one adjacent pair.

Smoke-tested live: page renders; full Pair round-trip (mint key → spirekeeper-spire policy with kinds 21000/21001-3/22242/30078 + nip44_*, no nip04 → token → seed URL + QR; machine_npub reassigned to the bunker-minted identity) and Revoke (never-bound branch, paired_at cleared) both confirmed.

2. pairing.pyduration_hours TTL docstring (docs(pairing))

The docstring claimed the bunker "rejects the token once it lapses, forcing a re-pair." That's only true for an un-redeemed token. nsecbunkerd reads Token.expiresAt solely in validateToken at connect/redeem time; the sign-time ACL never checks it (materialised SigningConditions carry no expiry; the policy join filters revokedAt only). So duration_hours bounds only the first-connect window — revoke_key_user is the real post-bind cutoff (same ACL-ordering class as the revoke finding #22).

Corrected to say so, pointing at aiolabs/nsecbunkerd#24 (post-bind TTL enforcement gap).


No code-behavior change in (2); (1) is template-only. 211 tests already green on main; neither touches Python logic or tests.

🤖 Generated with Claude Code

Two post-merge corrections to the pairing UI (#25) and TTL work (#23), both validated against a live regtest stack (FakeWallet + lnbits `dev`@`b5fba561` + real nsecbunkerd `dev`@`cb8dd0c`). ### 1. Fleet UI — Pair dialog Vue compiler error 30 (`fix(fleet-ui)`) The Pair dialog (#25) had two **interleaved** `v-if`/`v-else` sibling pairs — `q-card-section` + `q-card-actions` for each of the two steps: ``` [section v-if][actions v-if][section v-else][actions v-else] ``` Vue matches `v-else` to the *immediately preceding* sibling, so the second `v-else` (actions) trailed a `v-else` (section) — illegal. The compiler threw **error 30** (`X_MISSING_END_TAG` / "v-else has no adjacent v-if"), a `SyntaxError` that broke the **entire** Vue mount — the whole extension page failed to render, not just the dialog. (A plain tag-balance check passes; this is a directive-adjacency rule, caught with `@vue/compiler-dom`.) Fix: wrap each step's `section`+`actions` in a single `<template v-if>` / `<template v-else>` so there's exactly one adjacent pair. **Smoke-tested live:** page renders; full Pair round-trip (mint key → `spirekeeper-spire` policy with kinds `21000/21001-3/22242/30078` + `nip44_*`, no `nip04` → token → seed URL + QR; `machine_npub` reassigned to the bunker-minted identity) and Revoke (never-bound branch, `paired_at` cleared) both confirmed. ### 2. `pairing.py` — `duration_hours` TTL docstring (`docs(pairing)`) The docstring claimed the bunker "rejects the token once it lapses, forcing a re-pair." That's only true for an **un-redeemed** token. nsecbunkerd reads `Token.expiresAt` solely in `validateToken` at connect/redeem time; the sign-time ACL never checks it (materialised `SigningCondition`s carry no expiry; the policy join filters `revokedAt` only). So `duration_hours` bounds only the first-connect window — **`revoke_key_user` is the real post-bind cutoff** (same ACL-ordering class as the revoke finding #22). Corrected to say so, pointing at **aiolabs/nsecbunkerd#24** (post-bind TTL enforcement gap). --- No code-behavior change in (2); (1) is template-only. 211 tests already green on `main`; neither touches Python logic or tests. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
The Pair dialog had two interleaved v-if/v-else sibling pairs
(q-card-section + q-card-actions per step). Vue requires v-else to
immediately follow its v-if sibling, so the second v-else (actions)
trailed a v-else (section) — illegal, throwing compiler error 30
("v-else has no adjacent v-if") and breaking the entire Vue mount.
Wrap each step's section+actions in one <template v-if> / <template
v-else> so there's exactly one adjacent pair. Verified with
@vue/compiler-dom and a live pair/revoke round-trip against regtest.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
docs(pairing): correct duration_hours TTL docstring
Some checks failed
ci.yml / docs(pairing): correct duration_hours TTL docstring (pull_request) Failing after 0s
554b2e2e17
duration_hours stamps Token.expiresAt, but nsecbunkerd reads expiresAt
only in validateToken at connect/redeem time — the sign-time ACL never
checks it (materialised SigningConditions carry no expiry; the policy
join filters revokedAt only). So TTL bounds only the un-redeemed connect
window, not an established binding; revoke_key_user is the real post-bind
cutoff. Same ACL-ordering class as the revoke finding (#22). Tracked at
aiolabs/nsecbunkerd#24.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
padreug deleted branch fix/pair-dialog-and-ttl-doc 2026-06-18 23:01:16 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
aiolabs/spirekeeper!27
No description provided.