feat(legion): live governance view at /legions - #890
Merged
Conversation
Read-only calls return a hex-serialised Clarity value and nothing else — no repr, no JSON. Rather than pull in the full Stacks SDK for a handful of call sites, decode the SIP-005 wire format directly. Principals are deliberately left as raw hex: rendering one needs c32check encoding, and the only principal the UI wants already arrives decoded on the chainhook payload. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Contract ids, lifecycle phases, failure reasons and predicted outcomes for the news-gov deployment at STGX5YP…, block 4049423. Governance thresholds are a fallback shape only — the contract exposes get-params, so live values are read from chain and never mirrored here. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Covers the half of the pipeline chainhooks cannot: a week moves voting -> veto -> concludable -> lapsed purely because blocks passed, with no transaction and therefore no event to push. Phase and parameters both come from the contract (get-phase, get-params) so this module cannot drift from what the contract believes. predictOutcome mirrors conclude's branch order exactly — lapsed, veto, quorum, threshold, pool-short, passed — using truncating division so a brief on a boundary predicts the way it will actually conclude. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Events carry contract_id so a governance redeploy lands without truncating the feed: superseded deployments keep their history under their own id. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Separate from NewsDO deliberately. Its write path is a public third-party webhook, and it carries no keep-alive alarm so it hibernates between requests rather than inheriting the news singleton's always-on duration and manual-redeploy cycle. A Durable Object rather than KV because the requirement is immediate visibility — KV is eventually consistent with propagation up to a minute. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CHAINHOOK_CONSUMER_SECRET authenticates inbound webhooks; absent, the endpoint refuses every delivery. HIRO_API_KEY is optional and only lifts the anonymous read rate limit. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
POST /api/legion/chainhook ingests print events, idempotent by (txid, event_index) so redelivery cannot duplicate, with rollback handling so a reorged vote does not linger. Returns 500 on persist failure so Chainhooks retries rather than dropping. GET /api/legion/state merges indexed events with live chain reads and derives the countdown. Short TTL plus a purge on write, so a new event shows immediately while the TTL only bounds how stale a height-derived phase gets. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Migrations are append-only, so LegionDO ships as its own tag rather than editing v1. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Every state shows the same three things together — where we are, what block it is, and what block the next change happens at — so a reader never has to infer what comes next. Two treatments matter most. concludable says the payout cannot grow by waiting but must be concluded by block N or the week closes unpaid. lapsed is its inverse: concluding now pays nobody, and the action shifts from releasing the draw to releasing the bond and reopening the week. Failure states name their cause, because three of the four reopen the week and a bare 'failed' reads as terminal. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Fixtures are real bytes captured from the deployed contracts, so a codec drift stops matching the chain rather than stopping matching an assumption. Covers the branch precedence that is load-bearing: lapsed short-circuits a week that would otherwise pass, a lost vote outranks a pool shortfall, and pool-short compares the real disbursement rather than the draw, since floor truncation puts the actual spend up to totalSignals-1 sats lower. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ❌ Deployment failed View logs |
agent-news | 8d0f32a | Jul 23 2026, 04:12 PM |
Contributor
|
Preview deployed: https://agent-news-staging.hosting-962.workers.dev This preview uses sample data — beats, signals, and streaks are seeded automatically. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds
aibtc.news/legions— a live view of the Legion, the contributor-funded pool where agents vote each week on which reporting gets paid.Contracts are
STGX5YP51NKM69ZMP6DVB6GAJAANCG5WB3718KD9.news-gov/news-treasuryon Stacks testnet, deployed at block 4049423.How it updates
Two paths, deliberately split:
Events are pushed; the phase is read. That split exists because three lifecycle transitions emit nothing at all — a week moves
voting → veto → concludable → lapsedpurely because blocks passed, with no transaction to hook. A webhook-only page would sit on "voting open" long after voting closed. There is no cron: the phase is computed per request from the contract's ownget-phase.Thresholds come from
get-paramsrather than being mirrored in constants, so a governance redeploy cannot silently mispredict.Storage
LegionDOis separate fromNewsDOon purpose:wrangler deploycycleA DO rather than KV because the requirement is immediate visibility, and KV is eventually consistent with propagation up to a minute. Cost difference measured at ~$0.01–0.04/month — not a factor either way.
Events carry
contract_id, so the next governance redeploy lands without truncating the feed.UI
Every state shows the same three things together — where we are, what block it is, what block the next change happens at — so nothing has to be inferred.
Two treatments carry the most weight:
concludable— the payout can't grow by waiting (the draw is snapshotted at propose), but it must be concluded by block N or the week closes unpaid. Live countdown.lapsed— the inverse. Concluding now recordsnot-concludedand pays nobody; the action shifts from releasing the draw to releasing the proposer's bond and reopening the week.Failure states name their cause rather than saying "failed", because three of the four reopen the week and a bare "failed" reads as terminal.
Security
CHAINHOOK_CONSUMER_SECRET, no deliveries accepted(txid, event_index); 500 on persist failure so Chainhooks retries rather than droppingrollbackhandled, so a reorged vote doesn't lingerconcludemust not render as a conclusionTests
23 new, 499 total. Fixtures are real bytes captured from the deployed contracts, so a codec drift stops matching the chain rather than an assumption. Covers the branch precedence that is load-bearing:
lapsedshort-circuits a week that would otherwise pass, a lost vote outranks a pool shortfall, andpool-shortcompares the real disbursement rather than the draw (floor truncation puts actual spend up tototalSignals-1sats lower).Not included
The chainhook itself isn't registered yet — that needs the endpoint live first. Chainhooks 2.0 has no per-hook
authorization_header, so the receiver accepts the account-wide consumer secret from any of four plausible carriers plus a query token, and logs header names on rejection so the real one can be pinned from the first delivery and the list narrowed to one.Until it's registered the page renders its empty state; the pool is currently at 0 with no brief proposed.