Activity Overview

Commits and releases over time

  • Commits
  • Releases
  • Authors

Repository Explorer

618 commits in all time May 02, 2026 09:43 – Jul 31, 2026 09:43 UTC
tasosbit gGov
chore: /vote wording
Git Commit 0636c03d Branch worktree-frac-design-import Document 1/2 ++ 1 --
tasosbit gGov
feat: frontend: election-specific views on the period detail page
Implements the election frames of the Period Detail design handoff
(claude.ai/design 'Period Detail.dc.html', frames 1/3/6).

Each race on an election ballot now renders as its own card — E.0N chip,
name, seat count and candidate count — instead of a bare h3 over a flat
list of topic cards. What sits inside depends on the state:

- scoring (active, eligible, simple) — one CandidateBallotCard per
  candidate: avatar, statement, and Support/Veto/Abstain chips that tint
  the card once picked. A legend band prices the chips (+1/-1/0) and a
  footer tracks 'n of m candidates scored'.
- advanced — the existing TopicVoteCard allocation inputs, unchanged.
  Splitting power across the three options is still a valid ballot, and
  single-choice chips cannot express it.
- read-only (logged out, ineligible, ended) — ElectionStandings: the
  candidates ranked by net score with 'in seat range' pills and a
  seat-cutoff note, replacing per-candidate tally bars that ranked
  nothing.
- upcoming — the plain option list, inside the same card shell.

Labels come off the on-chain options via classifyOption rather than
being hardcoded, so a period seeded before the Veto rename still reads
'Against' in its own legend and standings.

Grouping is presentation only: every card stays keyed by on-chain topic
index, so ballot state and the vote() payload are untouched.
Git Commit a5714bec Branch worktree-frac-design-import Document 4/456 ++ 23 --
tasosbit gGov
chore: rename the election Against option to Veto
Election candidate ballots are Support / Veto / Abstain instead of
Support / Against / Abstain, across the Manage UI that writes the
on-chain options, the results/scoring copy, the docs pages, the
Storybook fixtures and the sample-data seeders.

ElectionCandidate.against is renamed to .veto to match.

utils/vote.ts is untouched on purpose: its NO_RE already matched both
'against' and 'veto', so periods already on chain with Against labels
keep tallying and colouring correctly alongside new Veto ones.
Git Commit 1d670fad Branch worktree-frac-design-import Document 13/47 ++ 49 --
tasosbit gGov
feat: frontend: elections in the voter-facing UI
A period runs elections when its body carries `elect`; each candidate names its
race through its own topic body's `e`. The results page understood that, and so
did the operator UI — the ballot and every period summary did not. A voter
meeting a two-election period saw seven undifferentiated "topics" with no way to
tell which seat anyone was standing for.

"Candidate" is a presentation word for a topic in an election period: the
contract, the ABI and every SDK handle stay `topicIndex`, so this is a copy
change, not a rename. utils/periodTerms.ts holds the noun and the count label in
one place — the two existing `isElection ? … : …` ternaries had already drifted
apart (the add-candidate form said "Add topic" in its disconnected state).

Ballot (VotePeriodDetail):
- candidates group under per-race headings via the SDK's groupCandidates,
  matching the results page. Ordering only: the state arrays, buildVotes() and
  the vote() payload stay flat and keyed by on-chain topic index.
- candidates whose `e` is missing or names no declared election are dropped by
  groupCandidates but still rendered, in a trailing section. The contract
  requires every topic row to carry the voter's full power, so leaving one off
  the ballot would make the period unvotable.
- the T.0N ordinal chip is suppressed for candidates — it would number straight
  through races that are ranked separately.
- the two near-identical "View Ranked Results" blocks (one right-aligned, one
  not) become one strip that also names each race and its seats.

Summaries now read "2 elections" / "5 candidates" / "3 topics": the period list
rows and column header, both heroes, the detail and results meta lines, the
sidebar info card, and the operator table. All of them already fetched the
period body except the operator table, which gains one read per row and a
TODO(perf) naming the batched reader that would collapse it.

Manage:
- assignment warnings move onto the page. They existed only inside the
  Mark-ready dialog, so an operator who never opened it had no idea a candidate
  was running in no race — and once the period is ready and a vote lands, the
  topic set is frozen and it can no longer be fixed.
- the fix-ability message keyed off canEdit, which folds in `!!sdk`, so a
  disconnected visitor was told the period was "no longer editable" when it was
  simply not connected. Split into `editable` vs `canEdit`.
- the remaining unconditional "topic" strings (remove-confirm, body dialog,
  placeholders, the disconnected add form) go through the shared terms.

Docs: /docs/periods gains an elections section and the glossary gains Election
and Candidate. Both spell out the rule that surprises people — you cast on every
candidate, including races you don't care about, and Abstain is how you sit one
out.

Also: deploy-sample-data declared `{ t: 'EAC', s: 1 }` while its own prose,
comments and console output all described a 2-seat treasury committee;
detailScenario accepted `elect` but hardcoded its topics, so the one election
story flagged an election over two untagged reward-policy topics. Both fixed,
plus multi-election detail stories and election rows in the list fixture.

Typecheck, lint and prettier are clean and the two ballot play-tests still pass.
Verified against localnet sample data (the active two-election period 2),
including a throwaway draft period carrying an untagged candidate to exercise
the manage callout and the trailing ballot section.
Git Commit 44b8c405 Branch worktree-frac-design-import Document 21/511 ++ 159 --
tasosbit gGov
chore: remove visible AQ references, simplify wording
Git Commit 24435b79 Branch worktree-frac-design-import Document 2/17 ++ 3 --
tasosbit gGov
chore: landing page revamp
Git Commit a293910e Branch worktree-frac-design-import Document 1/89 ++ 68 --
tasosbit gGov
Merge 3ef6668a4dc4ac5967d9d390f5bc22edcc72f6fe into d2b0d5afc4007a419e8cc6830fb5452e4f95d117
Git Commit 55efc610 Branch pull/94/merge Document 27/3,489 ++ 2,300 --
tasosbit gGov
feat: frontend: cast pooled ballots from the vote page
Pool members could see their prorated share but had no way to spend it. Make
staking-pool positions selectable rows in the vote page's account selector,
nested under the account that holds them — two levels deep for a pool belonging
to an account that delegated to you, which the frac contract honours the same
way it honours a delegated gGov vote.

Data layer:
- hooks/fracQueries.ts: usePooledBallot, the transpose of the account page's
  hooks — many accounts against the one committee the period runs on. Folds in
  the contract's canVote (authoritative: it mirrors every check vote() enforces)
  for eligibility and AQ weight, plus each account's pooled vote records. Where
  the shape matches it reuses the account page's query keys, so the two surfaces
  share cache rather than re-reading the same boxes.
- a TODO(perf) on the per-position canVote fan-out names the batched registry
  logger that would collapse it to one read per account, alongside the two
  already noted for the account page.
- useFracVoteMutation, and a writer-enabled frac SDK memoised per wallet
  identity. The reader stays separate on purpose: pooled reads must keep working
  with no wallet connected.

Ballot:
- a pooled ballot is denominated in AlgoQuarters, so TopicVoteCard and the
  allocation summary take a unit and show the approximate vote equivalent
  alongside. The allocation rule is unchanged — every topic totals your weight.
- selecting a pooled position switches the signing account first, same rule as a
  delegated vote; an account whose only power is pooled now auto-selects its
  first eligible position instead of landing on a dimmed "Yourself" row.
- new "Pool not ready" status for a pool that hasn't snapshotted the period or
  is still ingesting its AQ ledger. The member's own standing is fine, so "not
  eligible" would misplace the blame.
- PooledSharePanel, a per-pool vote record card, and a teal `pooled` Callout
  variant matching the tone used elsewhere for pooled voting.

Also:
- AccountSelector: id-keyed selection (an address or `{instance}:{owner}`),
  a shared NestedRow for the two indent depths, and mobile truncation fixes —
  long names were running under the status column instead of ellipsing.
- Storybook: pooled ballot mock + fixtures for every row status; MockPooledPosition
  extends the account-page fixture so one shape drives both surfaces.
- localnet seeder gives bob a tALGO position on top of his delegation to alice,
  making the two-levels-deep delegated case reachable; AppProviders passes the
  KMD wallet name, without which VITE_KMD_WALLET was silently ignored and the
  per-persona wallets had no effect.
- Home: the "how it works" primer moves above the pooled callout, so the callout
  reads as a follow-on rather than interrupting the period list; tabs get
  tablist/tab/tabpanel roles.

Typecheck and lint are clean. States are covered by Storybook fixtures; not yet
exercised against a live pool on-chain.
Git Commit fdcdcc2b Branch worktree-frac-design-import Document 19/1,541 ++ 182 --
tasosbit gGov
chore: reorder user dropdown, my account first
Git Commit c1e1305f Branch worktree-frac-design-import Document 1/11 ++ 8 --
claude gGov
test(algoquarters): assert no round-boundary double-counting for tALGO
Encode the exact round-boundary scenario as regression tests: when an
account holds tALGO and transfers its full balance at round T, the sender
is credited [start, T) and the receiver [T, end) — the boundary round T is
attributed to exactly one holder, and the two sides sum to the whole window
(a boundary off-by-one would shift a whole AQ and fail the assertion).

Also covers a chained A->B->C hop for the same one-round-one-holder invariant.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012Pjx7EdkEWdJbWKWLNBmwC
Git Commit 7993e2b0 Branch claude/talgo-round-boundary-counting-8yfr5g Document 1/44 ++ 0 --
sofinico gGov
Merge 7c363368abe9ceb0d7c77d9edfe9dcbc274d0312 into 3ef6668a4dc4ac5967d9d390f5bc22edcc72f6fe
Git Commit f53b47e1 Branch pull/95/merge Document 8/850 ++ 357 --
sofinico gGov
chore: nit on seed data summary
Git Commit 7c363368 Branch chore/frac-sample-data-scripts Document 1/1 ++ 1 --
tasosbit gGov
chore: storybook: add account stories
Git Commit ce2ded4b Branch worktree-frac-design-import Document 6/433 ++ 17 --
sofinico gGov
chore: frontend: simplifly draft flag and last polish
Git Commit 48528d06 Branch chore/frac-sample-data-scripts Document 1/45 ++ 34 --
tasosbit gGov
Merge efcd18bc83f14fdb3bf9427249191128e0ae84a3 into b041f7753c9dc3a7279cf1d953356f3a95b44106
Git Commit 23518e3e Branch pull/98/merge Document 33/2,085 ++ 100 --
tasosbit gGov
chore: docs: delegation += pooled voting
Git Commit efcd18bc Branch worktree-frac-design-import Document 1/9 ++ 1 --
tasosbit gGov
chore: docs tweaks
Git Commit bfc4cc08 Branch worktree-frac-design-import Document 4/40 ++ 30 --
sofinico gGov
chore: frontend: seed a two-election period + draft mode
Git Commit d51d45f9 Branch chore/frac-sample-data-scripts Document 1/99 ++ 41 --
sofinico gGov
Merge branch 'feat/single-period-multi-elections' into chore/frac-sample-data-scripts
Git Commit 22a5bf8a Branch chore/frac-sample-data-scripts Document 110/74,547 ++ 229,798 --
sofinico gGov
chore: deploy registries before funding in localnet seed for deterministic app ids
Git Commit 210ddd87 Branch chore/frac-sample-data-scripts Document 2/40 ++ 36 --
tasosbit gGov
Merge b041f7753c9dc3a7279cf1d953356f3a95b44106 into 3ef6668a4dc4ac5967d9d390f5bc22edcc72f6fe
Git Commit bbf14c59 Branch pull/97/merge Document 36/30,839 ++ 18,704 --
sofinico gGov
chore: docs nits
Git Commit b041f775 Branch feat/frac-user-delegation Document 6/18 ++ 18 --
tasosbit gGov
chore: frontend: TEMPORARY deploy-first localnet seed
Standalone copy of the seeder from chore/frac-sample-data-scripts, restructured
so every app deployment happens before any data seeding:

  DEPLOY  reset · fund · both registries · committee file · instances + escrows
          · all three period apps
  SEED    AlgoQuarters · delegations · period bodies/topics/windows/ready
          · ballots · verify

Every app ID therefore exists, and .env is written, before the slow data work
starts — a deployment failure surfaces in seconds instead of minutes, and vite
can be pointed at the registries while the seed is still running.

The committee-file upload sits in the DEPLOY phase because addPeriod needs a
committeeId; syncPeriod stays in SEED because it needs the period ready and the
committee already synced on the instance. createPeriodHelper is split
accordingly into createPeriodApp and populatePeriod, which also means every
period is fully populated before any ballot is cast rather than per-period —
a better fit for the rule that the first vote locks a period against editing.

Committed on its own, and deliberately not wired into deploy-sample-data.ts, so
this commit can be reverted wholesale once the real seeder lands. Does not
include that branch's AppProviders.tsx change for per-persona KMD wallets;
connect through unencrypted-default-wallet, which holds all four personas.

Verified end to end on localnet: 12/12 steps, tallies self-check, and the pooled
account/landing surfaces read correctly against the seeded chain.
Git Commit c34e8df6 Branch worktree-frac-design-import Document 4/937 ++ 0 --
tasosbit gGov
feat: frontend: surface pooled voting power (fractional delegation)
Users of liquid staking (xALGO, tALGO) and staking pools (Reti) hold no gGov
voting power directly — the pool's escrow accounts do — so the app gave them no
indication they could vote at all. Surface their pro-rata share across the
landing page, the account page and the docs, per the Claude Design project.

Data layer:
- add frac-delegation-sdk as a workspace dep + vite source alias; re-export the
  generated structs from its index so consumers can type against them
- lib/fracReaderSdk.ts: optional VITE_FRAC_REGISTRY_APP_ID, mirroring the
  escregAppId pattern. Unset (every network today) tree-shakes the frac SDK out
  of the client bundle entirely; set, it loads as its own dynamic chunk on first
  pooled query rather than on page load.
- hooks/fracQueries.ts: usePooledPositions over three primitives, gated so an
  account in no pool costs exactly one read. Two TODO(perf) notes name the
  registry-side loggers that would collapse the account page to a single read.

UI:
- VotingPowerByCommittee: merged direct + pooled card with a Direct/Pooled
  legend, an always-visible per-row breakdown, an inset current-power footer and
  the AlgoQuarters footnote. Degrades to the previous direct-only table when the
  account is in no pool. Also unions in committees where power is held *only*
  through a pool, which useCommitteeVotingPowers drops.
- landing hero splits weight into direct + "via N pools" pills; new pooled
  callout; "How Governance works" gains a fourth pooled step
- new /docs/pooled-voting article, plus a FAQ entry and two glossary terms. One
  nav.ts entry drives the sidebar, contents, header and pager chain.

Two fixes that made pooled-only accounts unable to delegate at all:
- canSelfDelegate hid the delegation card from accounts with no block
  production, which is every pool member
- the delegate/undelegate/redelegate mutations never passed fractionalOnly, so
  the frac-registry fallback inner call in set_voting_account went unfunded

Also: extract the Surface/EmptyPanel duplicated between Account and
CommitteeDetail; add a --teal-strong token so pooled figures are legible on the
pale teal tint in light mode; fix the Storybook mock exporting
useXGovVotingPowers where the real hook is useGovVotingPowers, which had been
breaking every landing-page story.

Pooled reads are wired to real SDK calls but not yet exercised on-chain — the
localnet seeder has no frac data. Verified via Storybook fixtures (light/dark,
pooled, direct-only, amounts-pending, pooled-only) and in the browser for docs.
Git Commit 322377e1 Branch worktree-frac-design-import Document 30/1,129 ++ 99 --
tasosbit gGov
fix: don't conflate a missing topic body with an untagged candidate
Addresses review feedback on #94.

The election tag `e` rides inside the topic body box, so a body that is
missing or unreadable leaves the tag *unknown*, not absent. Two places
reported it as "unassigned", sending the operator after the wrong fix on
top of the missing-body warning they already got:

- the pre-setReady checklist gated `validateAssignment` on
  `topicBodies.length` alone, which only catches the still-fetching case;
  it now gates on every entry being present, and the existing
  missing-body warning reuses the same predicate rather than keeping a
  near-duplicate condition in sync
- the per-candidate row rendered "Unassigned" in warning colour for a
  null body; it now renders "unknown (body missing)" in muted

Also: correct the `getTopicBody` doc (the period-shaped parser accepts
the same JSON and strips nothing — only the returned type differs), and
fall back to a trim-based candidate name in the results view so a blank
title can't render as an empty label, matching describeAssignmentReport.
Git Commit 3ef6668a Branch chore/frac-sample-data-scripts Document 3/22 ++ 11 --