Activity Overview

Commits and releases over time

  • Commits
  • Releases
  • Authors

Repository Explorer

487 commits in all time Jun 29, 2026 02:36 – Sep 27, 2026 02:36 UTC
tasosbit gGov
Merge 4b06aa51dd7ead6ea0cad64290c85f2785e9c4f2 into 2b9e0b2df8508436aebc305efa6456c358008ff5
Git Commit 6a0a30fc Branch pull/120/merge Document 43/52,062 ++ 81,323 --
tasosbit gGov
feat: flatten vote tallies so a pooled vote fits the opcode budget
xALGO could not vote: 22 topics x 3 options over 6 escrows needed 309 opup inner
transactions, over what any group can pool. Measured on LocalNet with exec
traces, that vote burned 213,875 opcodes against a usable pooled ceiling of
roughly 171,800 — a hard AVM limit, not under-provisioning.

Store every tally flat: one cell per option across every topic, concatenated in
topic order. A nested uint32[][] pays an ARC-4 offset-table lookup plus a row
decode/encode on every element access, and the vote path is nothing but element
access across two unbounded axes. The same vote now burns 81,810 opcodes (-62%),
and a direct GGovPeriod.vote 4,545 instead of 15,414 (-71%). The instance
program shrank with it, 6,310 -> 5,442 bytes.

The period gains an 'l' box (topicLengths) so vote() can read the shape without
decoding the string-heavy options box; the instance reuses the topicOptionLengths
it already snapshots at syncPeriod.

The SDKs stay the boundary. They flatten ballots on the way in and re-row every
tally they read back, so callers keep [topic][option]: the frontend, the
storybook mocks, the pipeline and every existing test call site are unchanged.
Instance readers take the shape from a getPeriod call added to the same simulate
group (no extra round-trip); the registry's cross-instance reader resolves it per
instance app, cached.

GGovPeriod.vote now sizes its reference padding explicitly. Its ten references
(voter, registry app, four registry boxes, three period boxes) never fit one app
call's eight; that shortfall was covered by accident whenever the opcode-budget
prepend fired, and the flat ballot made a small vote cheap enough that it stopped
firing.

Knock-on constants:
- setReady's topic ceiling rises — 58 -> 78 at 3 options, 78 -> 117 at 2 —
  because the vote event drops 4 bytes per topic.
- Vote-record box MBR drops 1,600 uAlgo per topic.

voteBudget.e2e.spec.ts pins the xALGO shape: it asserts the group's measured
appBudgetConsumed stays under 120,000, then sends the vote, which is what
exercises the budget planner that refused xALGO outright.

BREAKING: the vote selector and the box encodings change together, so deployed
period and instance apps cannot be updated in place — they must be redeployed.
Git Commit 4b06aa51 Branch explore/flat-votes Document 43/52,062 ++ 81,323 --
tasosbit gGov
Merge 2b9e0b2df8508436aebc305efa6456c358008ff5 into 53f5b6a5d36bfc81d70d1a4cd74707bbd6ff4f7f
Git Commit 43e6fb25 Branch pull/119/merge Document 56/1,829 ++ 837 --
tasosbit gGov
feat: share group sizing between the SDKs and cut its simulate count
ggov-sdk and frac-delegation-sdk carried byte-identical copies of the machinery
that sizes a write group before sending it - increaseBudget.ts, txnExecutor.ts,
groupUsageFee.ts and noteNonce.ts differed only in a "Verbatim copy of ..."
header. The duplication was always a placeholder: base.e2e.spec.ts pinned the two
copies' cost constants together "until the shared SDK package lands". This lands
it. A new projects/sdk-shared workspace package holds one implementation, plus
what it needs (spendable.ts, the three cost/group-size constants, SenderWithSigner
and SendResult). Both SDKs re-export from constants.ts, types.ts and
registry/index.ts, so no public API and no existing import site moves.

padForRefSlots is deleted from both SDKs. Reference slots are measured off the
same simulate that sizes the opcode budget, so the hand-counted call sites - five
in the frac instance SDK, one in ggov's importFracDelegations - become comments
naming what the executor now measures for itself.

The AVM13 rewrite that prompted this measured far more often than it needed to.
Tracing every simulate, including the one algokit runs inside builder.send(), the
worst case was 16 inside executeTxns, 22 once maker reruns were counted. It is
now 9, and the ordinary paths are measured and pinned by the new executor spec:
a write needing nothing costs 2, an inner-heavy 3-escrow vote 4, the same vote
from a writer below the probe headroom exactly 5.

Four things got it there:

- A ProbeContext caches the probe fee headroom and the min fee for one run. A
  low-balance sender used to rediscover its headroom on every probe - up to 6
  extra simulates and 7 accountInformation calls - and now pays for it once.

- A read cache threaded through the *MethodBuilderArgs interfaces. The executor
  owns one per run and escrowCountUpperBound memoises getEscrows (a simulate) in
  it, so the maker's reruns stop re-reading. Measured at -2 on the 3-escrow vote
  by disabling it and re-running.

- The opup count and the usage fee are both decided before the builder is touched
  again, collapsing three maker reruns into one.

- When the usage fee is owed and no probe has passed yet, the search spends its
  last slot on itxnsHi, which is safe by construction and therefore passes - so
  the fee read costs no simulate of its own. The send-time backstop re-prices
  from the rejection's own usage= figure rather than probing again.

Four bugs fixed. Two came out of review:

- txnCount held a Promise, because composer.count() was never awaited. builder is
  any, so tsc was happy, and the MAX_GROUP_SIZE guard silently compared NaN.

- staticFee undershot by (itxnsHi - itxns) * 1000 whenever the search narrowed,
  because it was read off a group built at itxnsHi. It is now the exact identity
  required - (groupFeesPaid - headroomFee), everything the group pays apart from
  txn 0, which holds whatever txn 0 was built with.

Two more only surfaced once ggov-sdk ran on this code - frac's own methods
happened to mask both:

- A dropped prepend. planGroupExtras re-solves with one prepend when the bare
  group is over budget, and that prepend's +700 drives itxnsHi back to 0 - but
  the bail-out guard only tested itxnsHi === 0, so it returned undefined and
  discarded the very prepend that made it zero. Every frac method needing an opup
  also needs reference pads, so padsForRefs > 0 kept the guard from firing there;
  ggov's addTopic and ingestGovs, over budget by less than one app call's worth
  and needing no pads, hit it immediately.

- An inner-txn ceiling that rejected working groups. The guard allowed 16 opup
  inners per transaction in the group, so a ggov vote across 78 topics - 135
  itxns, which the old sizing produced and the network accepted - was refused
  client-side. Opup inners are app calls sharing the group's 256-app-call
  allowance, not a per-transaction quota, and are sized against the group total
  now, consistent with MAX_GROUP_BUDGET = 700 * 256.

SenderWithSigner gains an optional emptyTxnSigner so the sizing simulates can
carry a post-quantum envelope: the v13 PQ premium is priced off the signature,
not the sender address, so a plain empty signer measures a PQ writer's group as
classic. writerFromAddressWithSigners adapts algosdk's PQ/Falcon signing accounts
to the writer shape. Degrades safely without it - the send-time fee retry catches
the shortfall at the cost of one round trip - which is what the frontend does,
since use-wallet exposes neither the scheme nor the public key.

Build orchestration: sdk-shared is registered in the workspace .algokit.toml
build list between contracts and the two SDKs that consume it, and carries its
own .algokit.toml so the unordered commands find it. CI's explicit --project-name
build lists would have failed without it (tsc cannot resolve types with no dist),
and its change-path filters used [^/]+-sdk, which does not match sdk-shared - a
change to the shared package would have skipped the contracts, committee-uploader
and pipeline jobs entirely. The frontend and storybook CDs now build with
pnpm --filter 'ggov-sdk...', whose trailing ellipsis pulls the dependency in
topologically instead of naming it again.

base.e2e.spec.ts's cross-SDK constant sync test is gone: one constant, one pin.

Rebased onto feat/testnet-mirror-seed, whose approval upload had meanwhile moved
to three pages. The two lines of work disagreed on a fact, and the disagreement
is settled by measurement rather than by picking a side: a box reference grants
2048 bytes of I/O budget, not 1024, ref-swept on localnet at every boundary
(2048 -> 1 ref, 2049 -> 2, 4096 -> 2, 4097 -> 3, 6145 -> 4), and resource
population does add more than one reference per distinct box - simulate reports
the shortfall as extraBoxRefs and the populator materialises them. So the
hand-computed machinery the three-page upload carried (BOX_IO_BYTES_PER_REF,
boxIoRefsFor, boxIoRefsPerCall spreading 12 references across companion calls,
approvalReadRefSlots padding the create path, and the probe -> staticFee round
trip) is redundant at best and 2x over-provisioned at worst. The three-page ABI
stays; the sizing goes to the executor, which measures what simulate actually
reports.
Git Commit 2b9e0b2d Branch feat/increase-budget-rewrite Document 56/1,829 ++ 837 --
sofinico gGov
Merge 8d36192305a673d4d46945c4c417f77c2b77b095 into d5e740c4f38df55c0230b3571fa18401b65695ef
Git Commit e94ea2ea Branch pull/55/merge Document 300/808,088 ++ 149,363 --
tasosbit gGov
Merge branch 'develop' of github.af:algorandfoundation/gGov into develop
Git Commit 8d361923 Branch develop Document 20/1,772 ++ 29 --
tasosbit gGov
chore: add frac pipeline project to vscode workspace
Git Commit 4cd2ae5c Branch develop Document 1/3 ++ 0 --
tasosbit gGov
Merge 53f5b6a5d36bfc81d70d1a4cd74707bbd6ff4f7f into 5543cf45985da14bb399da9f264da200a487c165
Git Commit ee716f8f Branch pull/118/merge Document 18/1,893 ++ 5 --
tasosbit gGov
chore: agents.md
Git Commit 53f5b6a5 Branch feat/testnet-mirror-seed Document 1/1 ++ 0 --
tasosbit gGov
chore: ggov sck scripts
Git Commit f3acc36e Branch feat/testnet-mirror-seed Document 2/155 ++ 0 --
sofinico gGov
Merge 5543cf45985da14bb399da9f264da200a487c165 into d5e740c4f38df55c0230b3571fa18401b65695ef
Git Commit f501e6f8 Branch pull/55/merge Document 300/808,085 ++ 149,363 --
tasosbit gGov
Merge pull request #117 from algorandfoundation/feat/registry-mbr-estimate
feat: registry funding panel sizing worst-case MBR for both registries
Git Commit 5543cf45 Branch develop Document 20/1,772 ++ 29 --
tasosbit gGov
Merge d0a6b0da8c7842d3feabb401e3eb1e1ea798334c into bfca4c02c69cbb33a230db0997a9a9ddaa1b82cd
Git Commit aba2c1b4 Branch pull/117/merge Document 20/1,772 ++ 29 --
tasosbit gGov
chore: remove extra space from error
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Git Commit d0a6b0da Branch feat/registry-mbr-estimate Document 1/1 ++ 1 --
tasosbit gGov
Merge 87581a83687781c6f183e521afedabad5c04ce3d into bfca4c02c69cbb33a230db0997a9a9ddaa1b82cd
Git Commit 30f02f06 Branch pull/117/merge Document 20/1,772 ++ 29 --
tasosbit gGov
fix: make `resolved` mean every input arrived, not every balance
The previous commit gated the top-up on balances and stopped there. The
re-review found the gap that leaves, and it is worse than the one it
replaced: a balance that fails to arrive pushes the requirement *up* (the
child looks empty), but a roster or pool standing that fails to arrive
pushes it *down* — the rows are dropped and `[].every()` still reports
resolved. So a frac registry whose `fetchCommitteePools` errored read as
"fully covered" at a requirement nothing had priced, and the provisional
notice told the operator the number was an over-estimate in exactly the case
where it was not.

`resolved` now covers every input each estimate was built from — periods,
committees, delegations, both rosters, `mbrTopUp`, the frac key length, every
counted committee's pools, and the balances. The reads keep their `data`
possibly-undefined for that reason: an empty roster and an unread one are
indistinguishable once defaulted. `isError` likewise spans every query rather
than the balances alone, and only picks the wording — the gate is `resolved`,
which is false for an absent input however it came to be absent.

The callout no longer claims a direction, since one flag now covers both.

Two more from the same review:

- `countsTowardMbr` used `nowSeconds <= votingEnd`, counting a period as
  fundable for one second after the contracts stop admitting votes
  (`Global.latestTimestamp < votingEnd`, ggovPeriod.algo.ts:408 and
  fracDelegationInstance.algo.ts:962). Now strict, with the check script
  pinning the boundary rather than the off-by-one.
- `poolSignature` keyed only on instance ids, so a staker count that moved
  between refetches left the memo — and the figure — on the previous count.
  It now carries every field `poolRowsOf` keeps.
Git Commit 87581a83 Branch feat/registry-mbr-estimate Document 4/114 ++ 44 --
tasosbit gGov
fix: gate the registry top-up on balances that actually resolved
The estimator already computed a `resolved` flag on every row and every
estimate — "so `required` is final rather than provisional" — and nothing
read it. Three review findings on #117 are three ways of falling through
that gap:

- the top-up button stayed armed while the panel loaded, and an unread
  registry balance falls back to zero spendable, so it offered to send the
  whole requirement;
- an *errored* balance read is not a pending one, so `isLoading` went false
  with the entry simply missing from `byAppId` — the same zero, permanently;
- the frac vote-record key length was absent from the composite loading
  state, and without it the pool list is empty, which makes the frac
  registry read as fully covered at a requirement of zero.

Wire the flag through instead of patching each symptom. `useAppAccountInfos`
now reports `isError` alongside `isLoading`, following the convention
fracQueries.ts already sets for reads whose empty result cannot carry the
difference. `RegistryMbr` gains `resolved` — the registry's own balance plus
every child's, with the frac key length folded in because its absence is
invisible to `[].every()`. The panel shows the figures either way, since an
unread balance can only push a requirement up, but replaces the coverage
callout with a provisional notice and will not offer to fund it.

New `Balances incomplete` story covers the state the panel previously could
not express.
Git Commit 9e23d133 Branch feat/registry-mbr-estimate Document 4/121 ++ 15 --
tasosbit gGov
chore: frontend testnet new env
Git Commit 244a8e7d Branch feat/testnet-mirror-seed Document 1/5 ++ 1 --
tasosbit gGov
feat: pipeline: mirror seed swaps Algorand Foundation accounts
The Foundation's 11 mainnet consensus accounts (consensus dashboard owner
export) are all committee members nobody testing the mirror can sign for.
Add a checked-in list and a 'foundation' substitution reason, applied to
core governors (regardless of escreg) and to AQ accounts alike.
Git Commit 9a846ae9 Branch feat/testnet-mirror-seed Document 6/73 ++ 13 --
tasosbit gGov
feat: pipeline: mirror seed numbers periods from 16
The localnet registries seed-mirror deploys get their period counter
seeded to 15, as production's is after the 15 legacy periods, so the
council election preview lands as period #16.
Git Commit 14ab7274 Branch feat/testnet-mirror-seed Document 2/12 ++ 3 --
tasosbit gGov
fix: pipeline: council election candidates carry Support/Veto/Abstain
gGov election candidates are Support/Veto/Abstain ballots (Abstain last,
as frac voting requires), not the Yes/No the first-term session used; the
description's voting instruction is rewritten to match.
Git Commit 37aa7d23 Branch feat/testnet-mirror-seed Document 4/21 ++ 14 --
tasosbit gGov
feat: pipeline: council election preview period on the mirror seed
seed-council-election creates a fake second xGov Council election on the
registries seed-mirror populated (localnet or testnet): the period-15
session's description adapted to a second term, 22 mocked candidates for
11 seats with the real application layout, synced onto every instance
holding the mirror committee. Funds the period app for its body boxes
upfront; PERIOD_ID resumes a run that died mid-sync.
Git Commit 977ddc1a Branch feat/testnet-mirror-seed Document 7/765 ++ 17 --
tasosbit gGov
feat: pipeline: mirror seed for localnet/testnet with synthetic stand-ins
`pnpm seed-mirror` uploads the real gGov committee and runs stages 1-3 on
localnet or testnet, replacing every account nobody can sign for there with
a generated one of the same voting power:

- core governors: escreg app escrows that are not frac escrows (pool escrows
  stay real so discovery and delegation keep working)
- frac governors: escreg app escrows, or Tinyman pools (rekeyed to XSKED5…)

Votes and AlgoQuarters are unchanged; the accounts are not funded. Mnemonics
and a voting-power note land in the gitignored .synthetic-accounts.<network>.json,
which is also the resume state: it is written after every generated account so
a re-run reproduces the same committee id and manifests.

The pipeline gains one hook, `mapAqAccounts`, applied to each computed manifest
before it is assembled. escreg-sdk is loaded through its CJS build: its ESM
build imports without extensions, which plain Node ESM refuses.
Git Commit 93c7cb5a Branch feat/testnet-mirror-seed Document 9/908 ++ 4 --
sofinico gGov
Merge bfca4c02c69cbb33a230db0997a9a9ddaa1b82cd into d5e740c4f38df55c0230b3571fa18401b65695ef
Git Commit afc8df75 Branch pull/55/merge Document 300/806,340 ++ 149,361 --
tasosbit gGov
Merge pull request #114 from algorandfoundation/feat/avm13-foreign-box-reads
feat: registries open their boxes to foreign reads at create
Git Commit bfca4c02 Branch develop Document 22/6,652 ++ 6,099 --