Skip to content
Merged
Show file tree
Hide file tree
Changes from 45 commits
Commits
Show all changes
225 commits
Select commit Hold shift + click to select a range
382efc5
docs(dpns): design unified voting experience
lklimek Jul 16, 2026
36cd3e2
feat(dpns): unify voting operations and UX
lklimek Jul 16, 2026
0c012cc
fix(dpns): harden voting operation recovery
lklimek Jul 16, 2026
ad30809
feat(dpns): preserve voting center route choices
lklimek Jul 16, 2026
a3c67c3
fix(dpns): make voting review safe and explicit
lklimek Jul 16, 2026
0c0eed0
fix(dpns): make scheduled operations authoritative
lklimek Jul 16, 2026
64e0962
fix(dpns): close voting operation safety gaps
lklimek Jul 16, 2026
fa0cb10
fix(dpns): explain empty voting workspace
lklimek Jul 16, 2026
b933f92
fix(dpns): close voting operation review gaps
lklimek Jul 16, 2026
05133b6
fix(dpns): always release failed sweep dispatches
lklimek Jul 17, 2026
5e0532e
fix(dpns): keep preflight failures retryable
lklimek Jul 17, 2026
dd2af66
fix(dpns): keep voting views authoritative
lklimek Jul 17, 2026
d6db6cd
fix(dpns): preserve scheduled vote recovery
lklimek Jul 17, 2026
4b50878
fix(dpns): retry schedules with missing voters
lklimek Jul 17, 2026
2936e6d
fix(dpns): bound vote operation journal growth
lklimek Jul 20, 2026
3a281b7
fix(dpns): cache voting operation views
lklimek Jul 20, 2026
14d3aca
fix(dpns): recover failed direct vote dispatches
lklimek Jul 20, 2026
44e0726
Merge remote-tracking branch 'origin/v1.0-dev' into feat/dpns-voting-…
lklimek Jul 20, 2026
071cc16
fix(dpns): contextualize vote diagnostics for DAPI exhaustion
lklimek Jul 20, 2026
f69db4e
Merge branch 'v1.0-dev' into feat/dpns-voting-unified
lklimek Jul 20, 2026
25b89d2
fix(dpns-voting): address 5 review findings marked resolved but still…
lklimek Jul 20, 2026
79b5c00
fix(dpns-voting): address remaining PR 901 review findings
lklimek Jul 20, 2026
10a3090
fix(dpns-voting): avoid field_reassign_with_default lint error
lklimek Jul 21, 2026
815c19c
Merge branch 'v1.0-dev' into feat/dpns-voting-unified
lklimek Jul 21, 2026
eda79f9
Merge remote-tracking branch 'origin/v1.0-dev' into feat/dpns-voting-…
lklimek Jul 21, 2026
8335bf9
fix(dpns-voting): move broadcast phase boundary earlier, fix immediat…
lklimek Jul 21, 2026
040c518
feat(dpns): move voting into active contests
lklimek Jul 21, 2026
4d04570
docs: update changelog for DPNS voting redesign
lklimek Jul 21, 2026
c7e6ac4
fix(dpns): restore Scheduled-votes nav and rebuild Review-and-cast sheet
lklimek Jul 21, 2026
cf61d47
fix(dpns): address active voting review gaps
lklimek Jul 21, 2026
dd81c46
fix: refresh proved DPNS vote state after updates
lklimek Jul 21, 2026
b575672
Merge branch 'v1.0-dev' into feat/dpns-voting-unified
lklimek Jul 21, 2026
8ca7635
fix(dpns-voting): quarantine poisoned legacy rows and unblock strande…
lklimek Jul 22, 2026
76c0ed7
fix(dpns-voting): retain quarantined legacy rows instead of dropping …
lklimek Jul 22, 2026
8abca99
perf(dpns-voting): batch masternode-card current-vote reads into one …
lklimek Jul 22, 2026
991e5f9
Merge branch 'v1.0-dev' into feat/dpns-voting-unified
lklimek Jul 23, 2026
07f2a29
Merge remote-tracking branch 'origin/v1.0-dev' into feat/dpns-voting-…
lklimek Jul 23, 2026
f60b7ae
fix(dpns): surface masternode vote limit
lklimek Jul 23, 2026
aff18b2
Merge branch 'v1.0-dev' into feat/dpns-voting-unified
lklimek Jul 24, 2026
4119610
fix(dpns): rename misleading is_open_for_voter to reflect contest-lev…
lklimek Jul 27, 2026
9b45fba
fix(dpns): route scheduled-vote sweep completion to hidden Active-con…
lklimek Jul 27, 2026
7de526b
fix(dpns): guard scheduled-vote journal cleanup and removal
lklimek Jul 27, 2026
f7f3c62
fix(dpns): make Scheduled Votes journal-first and fix Clear All feedback
lklimek Jul 27, 2026
d7ae529
Merge branch 'v1.0-dev' into feat/dpns-voting-unified
lklimek Jul 27, 2026
fcbc1dc
fix(dpns): unstick the Review and cast window after a failed submission
lklimek Jul 27, 2026
32032a7
Merge remote-tracking branch 'origin/v1.0-dev' into feat/dpns-voting-…
lklimek Jul 31, 2026
ecd04b0
Merge remote-tracking branch 'origin/v1.0-dev' into feat/dpns-voting-…
lklimek Aug 1, 2026
cbb4afa
fix(dpns): make the vote review honest, Remove final, and keyless nod…
lklimek Aug 1, 2026
a9d5a2c
refactor(dpns): drop the vote-change note from the review sheet
lklimek Aug 1, 2026
513af26
chore(deps): bump platform pin to PR #3968 latest tip
lklimek Aug 1, 2026
8f3dde1
Merge remote-tracking branch 'origin/v1.0-dev' into feat/dpns-voting-…
lklimek Aug 21, 2026
f6d15df
chore: merge v1.0-dev into DPNS voting branch
lklimek Sep 8, 2026
28948b1
fix(dpns): preserve vote proof freshness and ambiguous outcomes
lklimek Sep 8, 2026
c5c0e50
fix(dpns): bound vote history and preserve scheduled vote lifecycle
lklimek Sep 8, 2026
04699b6
fix(dpns): preserve vote review intent and complete scheduled voting …
lklimek Sep 8, 2026
f0dd759
fix(identity): cancel stale loads and preserve scoped key updates
lklimek Sep 8, 2026
4d05711
docs(dpns): describe reviewed voting and scheduling behavior
lklimek Sep 8, 2026
5277eeb
fix(dpns): preserve scheduled vote eligibility and validate new sched…
lklimek Sep 9, 2026
0101218
docs(dpns): clarify recovery visibility and schedule validation
lklimek Sep 9, 2026
b22cc75
fix(dpns): keep unresolved voting activity and failed state visible
lklimek Sep 9, 2026
29b9a57
Merge branch 'v1.0-dev' into feat/dpns-voting-unified
lklimek Sep 9, 2026
9dc1843
fix(dpns): explain missed votes and bound completed history
lklimek Sep 9, 2026
9c50554
fix(dpns): preserve vote intent and fresh preflight review
lklimek Sep 10, 2026
ed8bdc3
Merge remote-tracking branch 'origin/v1.0-dev' into feat/dpns-voting-…
lklimek Sep 14, 2026
ed34bc6
docs(dpns): fix duplicate story ID and close design-doc drift
lklimek Sep 14, 2026
a504b8a
fix(app): route every DPNS result to hidden screens and fix vote copy
lklimek Sep 14, 2026
e9b7f38
fix(dpns): give vote reconciliation a negative terminal verdict
lklimek Sep 14, 2026
6df93f3
fix(dpns): unify the authoritative-operation rule across the vote jou…
lklimek Sep 14, 2026
b397392
fix(dpns): disclose the vote recipient and stop the per-frame contest…
lklimek Sep 14, 2026
1c985fa
fix(masternodes): correct the DPNS card contract and gate the voting-…
lklimek Sep 14, 2026
4c0d80c
refactor(dpns): move dpns_voting test module to the bottom of the file
lklimek Sep 14, 2026
1cf9164
fix(dpns): dedupe kv test-support latch and fix doc placement
lklimek Sep 14, 2026
39edf1f
perf(masternodes): batch the DPNS contest summary read in reload()
lklimek Sep 14, 2026
6ae22e6
test(dpns): drop the review-round prefix from one contested_names_db …
lklimek Sep 14, 2026
c9fd8b7
Merge remote-tracking branch 'origin/v1.0-dev' into feat/dpns-voting-…
lklimek Sep 15, 2026
75cba19
Merge remote-tracking branch 'origin/v1.0-dev' into feat/dpns-voting-…
lklimek Sep 17, 2026
237b37b
fix(dpns-voting): update RNG usage for rand 0.10 API
lklimek Sep 17, 2026
c007461
fix(dpns): clarify the vote decision before confirmation
lklimek Sep 17, 2026
e566b5c
Merge remote-tracking branch 'origin/v1.0-dev' into mb/pr-901
lklimek Sep 23, 2026
d9bda15
test(mcp): use the fragment-based put-failure helper after base merge
lklimek Sep 23, 2026
43ff39e
chore: merge v1.0-dev into feat/dpns-voting-unified
lklimek Oct 1, 2026
76f2350
docs(dpns): redesign voting for operators and move usernames to ident…
lklimek Oct 1, 2026
47249d4
feat(dpns): contest timing, contested rule and vote fee in model
lklimek Oct 1, 2026
201e3f5
feat(identity): username availability and request status ops
lklimek Oct 1, 2026
c9cba79
feat(dpns): move voting into Masternodes ▸ Votes
lklimek Oct 1, 2026
d4e7a13
feat(identity): rework username registration flow
lklimek Oct 1, 2026
1d511d6
style(identity): drop redundant format calls in username confirm rows
lklimek Oct 1, 2026
b314550
feat(dpns): signal votes needed from every screen
lklimek Oct 1, 2026
53ccd3f
feat(identity): usernames card and request status page
lklimek Oct 1, 2026
5643f16
feat(dpns): contest cards with weighted tallies and a node set
lklimek Oct 1, 2026
2c8f44b
feat(identity): home request cards, outcome banners and main name
lklimek Oct 1, 2026
26424f5
feat(identity): signing key choice for usernames and user stories
lklimek Oct 1, 2026
e77b50d
feat(dpns): aggregate confirm step for staged votes
lklimek Oct 1, 2026
fac41fc
feat(dpns): non-blocking vote progress drawer
lklimek Oct 1, 2026
b1402b9
feat(dpns): keyboard shortcuts and bulk decisions in Votes
lklimek Oct 1, 2026
9821f10
fix(identity): close username QA gaps before and after payment
lklimek Oct 1, 2026
db87d63
feat(masternodes): node votes and "Vote with this node"
lklimek Oct 1, 2026
6aba4a5
feat(dpns): group scheduled votes by decision
lklimek Oct 1, 2026
ad3bbde
feat(dpns): history shows how your nodes voted
lklimek Oct 1, 2026
6bccd91
feat(dpns): open Votes on one contest from other screens
lklimek Oct 1, 2026
303571a
docs(identity): mark DPN-017 implemented and name the filtered votes …
lklimek Oct 1, 2026
7b67d62
Merge remote-tracking branch 'origin/v1.0-dev' into feat/dpns-voting-…
lklimek Oct 1, 2026
cb9cf95
Merge branch 'redesign/pr901-voting' into feat/dpns-voting-unified
lklimek Oct 1, 2026
638c9c8
Merge branch 'redesign/pr901-usernames' into feat/dpns-voting-unified
lklimek Oct 1, 2026
8929336
fix(masternodes): key list membership by the masternode identity id
lklimek Oct 1, 2026
93a5012
fix(identity): keep outcome banners once-only and show the main name …
lklimek Oct 1, 2026
05621ed
fix(dpns): tie lines for Lock ties and empty contests
lklimek Oct 1, 2026
e082ff5
fix(dpns): clear "not cast" once a vote is recast or dismissed
lklimek Oct 1, 2026
2ac5b0d
fix(identity): bound outcome seen-mark retries
lklimek Oct 1, 2026
1efeac0
feat(dpns): vote now on contests already inside the lead time
lklimek Oct 1, 2026
e076952
refactor(dpns): persist voting preferences through backend tasks
lklimek Oct 1, 2026
ebcb70f
fix(dpns): reopen the confirm when preflight finds a vote change
lklimek Oct 1, 2026
ea5f95a
fix(dpns): QA follow-ups for executor coverage, wording and refresh
lklimek Oct 1, 2026
b0a8fd0
test(dpns): pin Enter in the confirm; drop list focus on segment switch
lklimek Oct 1, 2026
a4d5332
Merge branch 'redesign/pr901-voting' into feat/dpns-voting-unified
lklimek Oct 1, 2026
26d71e7
chore: merge v1.0-dev (#1038) into feat/dpns-voting-unified
lklimek Oct 1, 2026
05f5864
Merge remote-tracking branch 'origin/v1.0-dev' into feat/dpns-voting-…
lklimek Oct 1, 2026
61c674c
fix(dpns): do not treat an unknown contest as closed
lklimek Oct 1, 2026
8774488
fix(dpns): use singular and plural vote feedback sentences
lklimek Oct 1, 2026
6fb00e1
fix(masternodes): singular status line for one active contest
lklimek Oct 1, 2026
8b17094
refactor(dpns): drop dead transition_hash and pin the journal key set
lklimek Oct 1, 2026
5ceed0b
refactor(dpns): derive vote confirmation from the classified status
lklimek Oct 1, 2026
604acc4
refactor(dpns): name the SubmitDpnsVoteOperation fields
lklimek Oct 1, 2026
7f14b27
perf(dpns): detect lock-index changes without cloning the index
lklimek Oct 1, 2026
8d8f462
fix(dpns): rank scheduled rows by the shared vote authority rule
lklimek Oct 1, 2026
668d89c
refactor(dpns): name the reviewable-failure lifecycle on the status
lklimek Oct 1, 2026
ac884e2
perf(dpns): clone voter identities only when submitting
lklimek Oct 1, 2026
2768f70
perf(dpns): scope submission preflight to the operation's voters
lklimek Oct 1, 2026
ab99fa5
docs(dpns): note deferred shared preflight concurrency bound
lklimek Oct 1, 2026
a1c0d42
Merge remote-tracking branch 'origin/v1.0-dev' into feat/dpns-voting-…
lklimek Oct 2, 2026
4f121ce
docs(dpns): align voting and username documentation with current UI
lklimek Oct 2, 2026
26ed875
docs(dpns): document registration and voting review fixes
lklimek Oct 2, 2026
718bf6b
fix(dpns): preserve registration and vote state across concurrent tasks
lklimek Oct 2, 2026
9e67385
test(dpns): route registration errors through dispatch context
lklimek Oct 2, 2026
9788852
Merge branch 'v1.0-dev' into feat/dpns-voting-unified
lklimek Oct 2, 2026
ca9af7e
chore: merge v1.0-dev into username and voting redesign
lklimek Oct 2, 2026
eb94b0a
fix(dpns): preserve identity edits and isolate vote recovery
lklimek Oct 2, 2026
4bb1ec0
chore: merge v1.0-dev into dpns voting branch
lklimek Oct 2, 2026
8cc95c6
fix(dpns): address voting review blockers
lklimek Oct 2, 2026
9e3ffdb
fix(ui): keep voting refresh bursts from starving frames
lklimek Oct 2, 2026
4902efd
fix(dpns): refresh voting state and align review feedback
lklimek Oct 5, 2026
f9ef2a7
fix(dpns): refresh saved username outcomes before contest discovery
lklimek Oct 5, 2026
ed897e7
fix(dpns): replace vote history column with explorer links
lklimek Oct 5, 2026
919dfaf
fix(dpns): move explorer links to final details column
lklimek Oct 5, 2026
f1124e4
chore: merge v1.0-dev into DPNS voting branch
lklimek Oct 5, 2026
18cd9c5
fix(dpns): preserve uncertain votes and concurrent username updates
lklimek Oct 5, 2026
d9c5787
perf(dpns): count authoritative outcomes in one journal pass
lklimek Oct 5, 2026
281bfd9
refactor(dpns)!: use only the vote journal for schedules
lklimek Oct 5, 2026
72b4744
fix(dpns): retry won names and bind payment consent to review
lklimek Oct 5, 2026
bbc9e52
chore: merge v1.0-dev into dpns voting branch
lklimek Oct 5, 2026
b0b7d2e
test(dpns): prepare payment review before overlay error dispatch
lklimek Oct 5, 2026
939316a
fix(dpns): preserve saved requests and address voting review feedback
lklimek Oct 5, 2026
8da0f69
fix(dpns): publish live vote progress and preserve uncertain outcomes
lklimek Oct 5, 2026
e4aca67
fix(dpns): preserve final requests and retry identity cleanup
lklimek Oct 6, 2026
718d127
test(dpns): discard unused drawer texture deltas
lklimek Oct 6, 2026
e6c0840
fix(dpns): keep the voting attention signal alive between refreshes
lklimek Oct 6, 2026
ab6271f
fix(dpns): stop re-raising the unconfirmed-vote banner on every sweep
lklimek Oct 6, 2026
aee07f3
fix(dpns): name the real cause when no vote of a batch was submitted
lklimek Oct 6, 2026
f281b93
fix(dpns): make the old-schedule startup notice truthful and self-exp…
lklimek Oct 6, 2026
1bc4dda
docs(dpns): align the voting spec with the shipped behaviour
lklimek Oct 6, 2026
e9d7731
fix(dpns): keep a card's changes-left known when its vote confirms live
lklimek Oct 6, 2026
deeb4a7
fix(dpns): surface a failed vote that was scheduled in an earlier ses…
lklimek Oct 6, 2026
b6c600a
test(dpns): make the lock-retention and rebroadcast tests exercise th…
lklimek Oct 6, 2026
fe4d72e
fix(dpns): retry an incomplete background refresh soon, not an interv…
lklimek Oct 6, 2026
71fa342
refactor(dpns): drop the confirm step's unreachable in-flight state
lklimek Oct 6, 2026
c2000ba
fix(dpns): bound the contest page query retries
lklimek Oct 6, 2026
3515fc0
fix(dpns): keep the Scheduled view in a fixed order
lklimek Oct 6, 2026
02d8a06
fix(dpns): skip a contest with an unknown deadline instead of failing…
lklimek Oct 6, 2026
eab8e62
fix(dpns): review a failed vote again without dropping staged decisions
lklimek Oct 6, 2026
7434f7e
fix(dpns): make a per-node "before the end" timing follow the lead time
lklimek Oct 6, 2026
2c7a316
fix(dpns): validate schedule times in the UI through the model validator
lklimek Oct 6, 2026
7e459dd
fix(dpns): do not send long-queued votes by themselves after a restart
lklimek Oct 6, 2026
e143a3e
fix(dpns): refuse to overwrite a stored vote operation on insert
lklimek Oct 6, 2026
cf3e9b2
fix(dpns): check the proved vote before recording a broadcast rejection
lklimek Oct 6, 2026
64d3ae5
refactor(dpns): drop comments and names left over from removed designs
lklimek Oct 6, 2026
6cbc38c
fix(dpns): return TaskError from the new retry and proved-vote helpers
lklimek Oct 6, 2026
115fd2b
docs(dpns): describe failure recency and the Scheduled view order
lklimek Oct 6, 2026
4820dab
fix(migration): stop reading legacy scheduled votes in the app-data pass
lklimek Oct 6, 2026
cd084b9
fix(dpns): make the Identities breadcrumb leave the request status page
lklimek Oct 6, 2026
4ca8bd5
fix(dpns): use identity-side tally labels and gate the voter link on …
lklimek Oct 6, 2026
788203e
fix(dpns): check the approved contest fee against the broadcast document
lklimek Oct 6, 2026
2c81802
test(dpns): cover the pay-time availability guard before the contest fee
lklimek Oct 6, 2026
86a3cf0
fix(dpns): never report a possibly paid username request as a plain f…
lklimek Oct 6, 2026
000fc0c
fix(dpns): keep a just-registered username when the follow-up read lags
lklimek Oct 6, 2026
61092df
fix(identity): delete identity keys even when the vote journal is unr…
lklimek Oct 6, 2026
898407d
fix(dpns): keep refreshing owned names past a removed or failing iden…
lklimek Oct 6, 2026
b9a78d3
refactor(dpns): drop the unreachable DPNS source of the registration …
lklimek Oct 6, 2026
701ee43
test(dpns): pin contest durations across the versions the SDK can report
lklimek Oct 6, 2026
4df6f20
docs(dpns): align username model docs with the code they describe
lklimek Oct 6, 2026
1183e58
docs(dpns): document the vote journal and username keys, retire sched…
lklimek Oct 6, 2026
3fd1584
docs(changelog): describe DPNS voting and usernames by what users obs…
lklimek Oct 6, 2026
9abb108
docs(dpns): make platform-facts portable and mark resolved contradict…
lklimek Oct 6, 2026
fb8f3e3
docs(dpns): align the usernames spec and user stories with the shippe…
lklimek Oct 6, 2026
2cd51ff
docs(migration): describe the app-data step as top-up history only
lklimek Oct 6, 2026
9a54a4a
docs(migration): stop describing unreadable scheduled votes as an upg…
lklimek Oct 6, 2026
8a9b9d2
docs(dpns): document when the old-schedule startup notice stops
lklimek Oct 6, 2026
a44a15d
fix(dpns): show an immediate vote that restart recovery stopped
lklimek Oct 6, 2026
ff16151
fix(dpns): do not skip a vote as already cast on proof too old to decide
lklimek Oct 6, 2026
9130b06
fix(dpns): release immediate votes left queued by a failed executor
lklimek Oct 6, 2026
3c2e924
fix(dpns): date every immediate vote restart recovery picks up
lklimek Oct 6, 2026
1b20894
fix(dpns): cancel votes stored after their voter was removed
lklimek Oct 6, 2026
84c38c5
fix(dpns): count a vote once when its confirmation is recorded twice
lklimek Oct 6, 2026
2bda135
test(dpns): build the vote-state snapshot fixture with its proof times
lklimek Oct 6, 2026
f778d94
fix(dpns): check the network before believing a refused username request
lklimek Oct 6, 2026
bbdb04c
docs(dpns): describe the old-schedule notice as non-listing and self-…
lklimek Oct 6, 2026
aa468f4
refactor(migration): remove the unreadable-votes report the upgrade c…
lklimek Oct 6, 2026
cb12ded
fix(dpns): stop listing a won username after it has left the identity
lklimek Oct 6, 2026
f908ee3
docs(dpns): list the vote-count key in the k/v reference
lklimek Oct 6, 2026
772750d
docs(dpns): list the recovery-time and counted-operation keys
lklimek Oct 6, 2026
baf1739
test(identity): schedule the vote before the interrupted removal it m…
lklimek Oct 6, 2026
fba85f9
fix(dpns): show a vote that is only checked again as cast, not as a f…
lklimek Oct 6, 2026
267c6d9
refactor(dpns): build a voting node and map its kind in one place
lklimek Oct 6, 2026
45cce5c
refactor(dpns): carry the composer's error instead of restating it
lklimek Oct 6, 2026
92f655b
refactor(dpns): let the votes panel say which results it handles
lklimek Oct 6, 2026
0dbacba
refactor(dpns): remove small restatements in the voting task and copy
lklimek Oct 6, 2026
f218785
test(identity): share one bare user identity fixture
lklimek Oct 6, 2026
4bb9406
refactor(identity): keep the username sentences in the copy module
lklimek Oct 6, 2026
9214ac2
fix(dpns): do not announce a vote that is only checked again as sent now
lklimek Oct 6, 2026
0bfcb2e
fix(dpns): skip a node with no changes left instead of checking it again
lklimek Oct 6, 2026
c35813a
fix(dpns): drop the transaction sentence when nothing is sent
lklimek Oct 6, 2026
bde6a00
fix(dpns): keep a node loaded after staging out of the confirm step
lklimek Oct 6, 2026
78581f7
fix(identity): report a refused name request as unconfirmed when it c…
lklimek Oct 6, 2026
34d5ba3
perf(dpns): share published vote operations instead of copying them all
lklimek Oct 6, 2026
d5f7387
fix(dpns): cancel reviewed votes when their node is removed and loade…
lklimek Oct 6, 2026
cc0848f
fix(dpns): retry a contest refresh soon when a contest query failed
lklimek Oct 6, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 18 additions & 9 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,24 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
Expert mode is on) for loading and managing masternode and evonode (HP
masternode) identities by ProTxHash. Loaded nodes appear as a card list
showing type, voter-key readiness, key status, and DPNS-voting status;
opening a card shows a detail view with inline DPNS contested-name voting,
Withdraw / Top up / Transfer actions, key management, and — for evonodes
only — a link to claim token rewards. The load form accepts an optional
password to encrypt the entered voting/owner/payout keys immediately
instead of only after a separate step; leaving it blank keeps today's
behavior, and protection can always be added later from the key screen.
This replaces loading a masternode or evonode from *Identities → Load
Existing Identity → Show Advanced Options*, which no longer offers those
identity types.
opening a card shows a detail view with Withdraw / Top up / Transfer
actions, key management, a "DPNS Voting" button that opens the DPNS Active
contests screen, and — for evonodes only — a link to claim token rewards.
The load form accepts an optional password to encrypt the entered
voting/owner/payout keys immediately instead of only after a separate
step; leaving it blank keeps today's behavior, and protection can always
be added later from the key screen. This replaces loading a masternode or
evonode from *Identities → Load Existing Identity → Show Advanced
Options*, which no longer offers those identity types.

- **DPNS voting redesigned around the Active contests screen**: casting,
batching, and scheduling DPNS name-contest votes across your masternodes
now happens in one place — DPNS → Active contests. Contests are grouped
into Needs your vote / Voted / Not votable by your nodes, with a Review
and cast step for casting now or scheduling later, plus a reminder that
Platform allows up to four changes after the initial vote. The
Masternodes detail screen no longer casts votes inline — its "DPNS
Voting" button takes you straight to Active contests instead.

- **Wallet/identity indicator on more screens (rollout in progress)**: the
wallet and identity picker previously shown only at the top of the Identity
Comment thread
lklimek marked this conversation as resolved.
Resolved
Expand Down
206 changes: 206 additions & 0 deletions docs/ai-design/2026-07-16-dpns-voting-experience/01-requirements.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
# DPNS Voting Experience — Requirements

## Status

Planning specification. No implementation is authorized by this document.
Comment thread
lklimek marked this conversation as resolved.
Resolved

## Problem statement

DET previously exposed DPNS voting through disconnected per-node and bulk
experiences. The adopted design consolidates them on DPNS Active contests.

Both call the same backend, but neither owns a complete, authoritative model of
the operation. The result is unsafe ambiguity: a vote can be accepted while DET
shows no confirmation, the same choice can immediately be offered again, bulk
results cannot identify the affected node, and a second click can submit another
state transition while the first is unresolved.

Voting consumes Platform credits and each node may vote only five times on a
contest in total (the initial vote plus up to four changes). Duplicate or
ambiguous submissions therefore have a real cost.

## Primary persona

Priya, the power-user masternode operator, manages one or more nodes and expects:

- current vote state to be accurate;
- quick actions for one node;
- bulk and scheduled operations for many nodes;
- progress that survives navigation and restart;
- exact per-node results; and
- safe recovery when Platform accepted a request but DET could not confirm it.

The voting workspace remains hidden below Detailed interface mode. It is not an
Everyday User workflow.

## Current-state audit

| Finding | Source behavior | User impact |
|---|---|---|
| Vote ownership is never populated | Contest cache reconstructs `ContestedName::my_votes` as empty and no task fills it | A successful vote is offered again after refresh |
| Existing votes are treated as closed | `is_open_for_voter` excludes any contest where the node already voted | Operators cannot inspect or change an existing vote |
| Same-node bulk execution races | `VoteOnDPNSNames` runs contests with `join_all`; each task independently fetches the same voter nonce | Multiple votes for one node can conflict |
| Bulk results lose node identity | `DPNSVoteResults` contains only name, choice, and result | Partial results cannot say which node succeeded |
| Scheduled casts can report false success | Scheduled paths treat an outer `Ok(DPNSVoteResults)` as success without inspecting inner failures | A failed or unconfirmed scheduled vote is marked executed |
| Progress is screen-owned | App results are routed to the currently visible screen | Navigation can strand controls in progress or deliver feedback to the wrong page |
| Duplicate prevention is local or absent | Quick and bulk submit buttons do not share an operation lock | Repeated clicks or cross-screen actions can submit duplicates |
| Post-broadcast wait failure is ambiguous | A cause-less `StateTransitionBroadcastError` can follow successful broadcast | DET must not label it rejected or invite immediate retry |
| Voting entry points were disconnected | Per-node and bulk flows used different UI ownership | Operators could miss capabilities or assume they were removed |

## Product decisions

1. DPNS Active contests is the single home for immediate, bulk, and scheduled
vote composition.
2. Masternode detail links plainly to Active contests without carrying a node
filter or draft.
3. Single and bulk/scheduled voting use one review sheet and one shared
operation coordinator.
4. Current vote state is authoritative Platform data, not UI-local memory.
5. A vote row remains visible after voting and shows the current choice. Voting
again is presented as a change, not a new missing vote.
6. Operation state is global, correlated, and durable enough to survive
navigation and process restart.
7. Exact targets, not whole screens, are locked. Unrelated nodes and contests
remain usable.

## Functional requirements

### Information architecture

- **VOTE-FR-001** — Masternodes provides only the node list and node detail.
- **VOTE-FR-002** — DPNS Active contests owns the single vote composer and
review sheet.
- **VOTE-FR-003** — A node detail page offers one `DPNS Voting` action that
navigates plainly to Active contests.

### Authoritative state

- **VOTE-FR-010** — DET queries each loaded node's proved Platform votes and
joins them with active contests.
- **VOTE-FR-011** — Each active contest shows the node's current choice, or
`Not voted`.
- **VOTE-FR-012** — Existing votes remain actionable while the contest is
votable, allowing a deliberate vote change.
- **VOTE-FR-013** — Selecting the already-current choice is a no-op and cannot
create a state transition.
- **VOTE-FR-014** — Refresh updates contests, tallies, and node vote state as one
coherent snapshot.
- **VOTE-FR-015** — A change to an existing vote is labeled as a limited vote
change in Review. DET does not claim to know the remaining count.
- **VOTE-FR-016** — If current vote state cannot be proved, DET shows it as
unavailable and disables submission for that node instead of assuming
`Not voted`.
- **VOTE-FR-017** — Node summaries distinguish active contests from contests
where the node has not voted yet.

### Vote composition

- **VOTE-FR-020** — Quick voting supports one node across one or more contests.
- **VOTE-FR-021** — Bulk voting supports one or more contests across one or more
nodes.
- **VOTE-FR-022** — The operator can apply one timing choice to all selected
nodes and override individual nodes.
- **VOTE-FR-023** — Timing choices are `Cast now`, `Schedule`, and `Do not use
this node`.
- **VOTE-FR-024** — Before submission, a review step lists every target as
node × contest, including current choice, requested choice, and timing.
- **VOTE-FR-025** — The review step removes no-op targets and explains why.

### Operation lifecycle

- **VOTE-FR-030** — Every submitted batch has a stable operation ID.
- **VOTE-FR-031** — Every target result includes operation ID, node ID, contest
ID/name, requested choice, and typed status.
- **VOTE-FR-032** — Target statuses are `Scheduled`, `Queued`, `Submitting`,
`Confirming`, `Confirmed`, `Unconfirmed`, `Rejected`, and
`Failed before submission`, plus `Not applied` after definitive
post-broadcast reconciliation.
- **VOTE-FR-033** — Same-node targets execute sequentially to preserve nonce
order. Different nodes may execute concurrently with a fixed bound.
- **VOTE-FR-034** — A target lock prevents a second operation for the same
network + node + contest while the first is unresolved.
- **VOTE-FR-035** — Button state derives from the shared coordinator. A click
disables the affected action immediately and shows progress text.
- **VOTE-FR-036** — Navigation does not cancel an operation or lose its state.
- **VOTE-FR-037** — Restart restores scheduled and unresolved operations before
enabling conflicting actions.

### Confirmation and recovery

- **VOTE-FR-040** — Structured Platform consensus causes are treated as
confirmed rejection.
- **VOTE-FR-041** — A cause-less post-broadcast wait failure is treated as
`Unconfirmed`, never as rejection.
- **VOTE-FR-042** — Unconfirmed targets are reconciled against the proved
current vote and, when available, retried by transition hash through the
Platform SDK.
- **VOTE-FR-043** — A target becomes `Confirmed` when authoritative state
matches the requested choice.
- **VOTE-FR-044** — DET never offers `Submit again` while the result remains
ambiguous. It offers `Check again`.
- **VOTE-FR-045** — A retry becomes available only after authoritative
reconciliation proves the requested change was not applied.

### Scheduled votes

- **VOTE-FR-050** — Scheduled votes use the same target model, result model,
locking, execution order, and reconciliation as immediate votes.
- **VOTE-FR-051** — A scheduled target is marked executed only after confirmed
application.
- **VOTE-FR-052** — Rejected and failed-before-submission targets remain visible
with an actionable status.
- **VOTE-FR-053** — Unconfirmed scheduled targets are not automatically
rebroadcast.
- **VOTE-FR-054** — Existing scheduled-vote records migrate without losing node,
contest, choice, time, or executed state.
- **VOTE-FR-055** — A scheduled target can be edited or cancelled until
execution begins. Once submitting, it follows normal operation locking.

### Feedback

- **VOTE-FR-060** — One confirmed target shows a concise success banner.
- **VOTE-FR-061** — Batch feedback summarizes confirmed, unconfirmed, rejected,
and failed counts and links to per-target details.
- **VOTE-FR-062** — Messages name node aliases and contested names where useful.
- **VOTE-FR-063** — Technical errors stay in banner details.
- **VOTE-FR-064** — Unconfirmed copy explicitly says DET will keep checking and
warns against resubmission.

## Non-functional requirements

- **VOTE-NFR-001 Safety** — No UI path can bypass target locking.
- **VOTE-NFR-002 Correctness** — Same-voter transitions are serialized.
- **VOTE-NFR-003 Durability** — A crash after broadcast cannot erase the only
record that the outcome is unresolved.
- **VOTE-NFR-004 Proofs** — Current vote state is obtained through proved SDK
queries.
- **VOTE-NFR-005 Accessibility** — Disabled actions explain why; progress is not
color-only; keyboard focus follows the composer step order.
- **VOTE-NFR-006 Localization** — User-facing strings are complete translation
units with no parsed error text.
- **VOTE-NFR-007 Performance** — Refresh queries votes once per node, not once
per contest, and bounds cross-node concurrency.
- **VOTE-NFR-008 Network isolation** — Drafts, schedules, operations, locks, and
results are network-scoped.
- **VOTE-NFR-009 Secret handling** — The coordinator stores identifiers and
choices, never private keys.

## Platform dependency

The preferred recovery contract is
[dashpay/platform#4137](https://github.com/dashpay/platform/issues/4137), which
tracks phase-specific, retryable post-broadcast wait errors. The SDK should
expose the transition hash after broadcast so DET can persist it and resume
waiting.

DET must still support fallback reconciliation by fetching the node's proved
vote for the target poll. Until either method proves the result, the operation
remains unconfirmed and locked against duplicate submission.

## Out of scope

- Changing Platform's five-vote protocol limit.
- Showing a remaining-change count before Platform exposes it in the proved
identity-votes response.
- Embedding Platform Explorer.
- Allowing arbitrary cancellation after broadcast.
Loading
Loading