sprint-3: HB#387-399 session — Sprint 15 P1-P4, bundler research, probe-access fix, daily-digest#26
Merged
Conversation
txHash: 0x4c494fb7590dc6bade24ceca20ba76b064a4369e31b1f40018d4a5efbffaa599 ipfsCid: QmYfqV3hWbhoMDvATvMQSCcHFaWcJAxefgqryqso4kBVxd Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…tribution pack
Introduces the src/lib/audit-db.ts canonical 61-DAO dataset store
(extracted HB#328, never previously committed) with this session's
additions: Index Coop, Euler, Kwenta, Alchemix, Instadapp, Prisma
Finance, Goldfinch (58 → 61, all DeFi-category).
Publishes the Single-Whale Capture Cluster as a standalone research
finding split out of Four Architectures v2.5. Four distribution formats
all ready to post:
- agent/artifacts/research/single-whale-capture-cluster.md (IPFS
pinned at QmSGsB2ehjtcVMPCPfw5wNZ9H2hqiwuCiCgTMFe3q3z2bz, HB#395)
- docs/distribution/single-whale-capture-twitter.md (9 tweets, HB#396)
- docs/distribution/single-whale-capture-mirror.md (900 words, HB#402)
- docs/distribution/single-whale-capture-reddit.md (r/defi, HB#403)
Plus docs/distribution/index-coop-outlier-note.md — honest caveat
companion piece acknowledging Index Coop is the first DeFi-divisible
entry below Gini 0.80 and flagging it for refresh test before using
it to weaken the 11-of-11 drift finding.
docs/distribution/INDEX.md + posting-runbook.md refreshed to reflect
the new 22-piece inventory with Capture-cluster pieces promoted to
the week-1 posting block per the HB#406 rationale (stronger retail
hook than Four Architectures).
docs/OPERATOR-STATE.md is the Hudson-facing TL;DR dashboard updated
for HB#414 state: 3 retros across all agents, 57 tagged brain
lessons (zero untagged), #54 merge-vote flag, blocker #1 reframed
to promote the Capture-Reddit post as the new highest-leverage
operator action.
Also bundles the prior-session distribution files (four-architectures,
correlation-analysis, p47-voting, D-grade outreach templates,
temporal-stability-mirror, newsletter-pitch-bankless) which were on
disk but had never been committed to the repo — consolidating them
into a single tracked directory.
This commit is entirely additive:
- src/lib/audit-db.ts: new file, zero git history in this branch
- docs/OPERATOR-STATE.md: new file
- docs/distribution/: new directory, never previously tracked
- agent/artifacts/research/*.md: new file
No tracked file is modified. The 48 src/commands/**/*.ts + 50+
other tracked-file drifts against origin/main are pre-existing
local state not authored this session; they remain untouched.
Identity: first sentinel_01 commit correctly attributed to
ClawDAOBot via bot-identity.sh (PR #11 pattern). HB#385 commit
b443b77 is the prior mis-attributed commit; not rewriting per
bot-identity PR #11 precedent ("retroactive rewrite would require
force-push to main which is off-limits").
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
txHash: 0x28a42d9d314cf35cdf194999fd431ed6063392ee882176de32a2c52f9bd2011c ipfsCid: QmfXBcXyASDVkKaEQNqngUta6rRQTf2fKGUwkfX7mmmcEX Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
HB#434-435 additions (sentinel_01 post-PR-10-merge audit growth):
- Instadapp (0.893, 88v, 28% top) — normal DeFi
- Prisma Finance (0.810, 19v, 42% top) — boundary cluster
- Goldfinch (0.872, 20v, 50% top) — near-capture, boundary cluster
- Threshold (0.827, 53v, 23% top) — normal DeFi
- Notional (0.562, 5v, 48% top) — SECOND low-Gini DeFi-divisible
outlier (after Index Coop 0.675 from HB#387)
Dataset now at 63 DAOs. Notional + Index Coop flagged for HB~464
temporal refresh to test whether low-Gini DeFi-divisible DAOs drift
like their high-Gini peers or stay stable — either outcome is
publishable, and the pair makes the 'refresh both as a test set'
design clean.
Machine-readable v3.1 pinned to IPFS at
QmX1BKToGQfD8wat1TkJcxfxEUSSiL7wtjd86opHgKd5zQ. Includes delta.added
array and defiLowGiniOutliers summary so downstream consumers can
track changes across versions. Supersedes v3.0 (58 DAOs, HB#413).
docs/distribution/INDEX.md updated with the new pin.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Task #377 (HB#436 claim tx 0xefd3a0a7): build pop distribution
post-and-track skill. Turns out .claude/skills/post-thread/SKILL.md
already existed as a 99-line framework draft from before HB#436 but
had no implementation backing; evolving it into a real tool rather
than a net-new build.
NEW: agent/scripts/post-x-thread.mjs (281 lines)
- Markdown parser for **N/** block format (our standard
docs/distribution/*-twitter.md layout)
- JSON parser fallback for legacy { tweets: [...] } inputs
- 280-char validation per tweet
- Thread numbering gap detection (hard error)
- Placeholder detection (TODO/FIXME/{{)
- Dry-run default; --post opt-in
- 60-min rate limit via post-history.md read (--force bypass)
- Token resolution: POP_X_TOKEN env > ~/.pop-agent/x-token.txt
- X API v2 reply_to chaining with 1.1s inter-tweet delay
- Auto-creates/appends docs/distribution/post-history.md with
ISO timestamp + source file + first tweet id + thread URL
UPDATED: .claude/skills/post-thread/SKILL.md
- Points at agent/scripts/post-x-thread.mjs as implementation
- Documents markdown-preferred input format with real example
- Drops the stale QmPrGE... CID reference
- Replaces 4-var X API credential pattern with the simpler
POP_X_TOKEN / ~/.pop-agent/x-token.txt pattern matching the
bot-identity.sh precedent from PR #11
FIXED: docs/distribution/single-whale-capture-twitter.md
- Tweet 8 was 291 chars (11 over X's 280 limit); caught by the
new validator on first dry-run — excellent dogfood signal.
- Tightened to 270 chars without losing any meaning: "go on
record" > "go on the record", "very few voters" > "very few
active voters", "at that sample size" > "at sample size" style
compressions.
VERIFIED: full dry-run against single-whale-capture-twitter.md now
passes clean — 9 tweets parsed, all under 280, thread ready to post
when a token lands.
NOT YET DONE (follow-up work for the same task or a new one):
- Real --post against a token (Hudson credential step still open)
- Reply/engagement watcher (separate long-running task)
- Parallel skills for Mirror, Reddit, Bankless newsletter — those
each need their own format/API
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
# Conflicts: # docs/distribution/INDEX.md # docs/distribution/single-whale-capture-twitter.md # src/lib/audit-db.ts
txHash: 0x81321d9216a6354b367f888e1a0448f6ea0d761c5db2d26409ae3cb72368b794 ipfsCid: QmdD33Eq9FM4WVJKrJh4ahCEEMrgSarCxHK3Yrxrb2xDZ5 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…robe Task #378 (HB#437 claim tx 0x7beedd8e): three-part deliverable was diagnose + mitigate in pop vote list + fix at root (or file upstream issue). This commit lands the mitigation. Diagnosis and upstream are covered in the function-level comment. ROOT CAUSE HYPOTHESIS (documented in src/commands/vote/list.ts probeExpiredActiveProposal jsdoc): The Gnosis subgraph indexer for the POP HybridVoting contract lags under bursty block production. The agent lifecycle uses sponsored tx bundles that can land multiple txs in adjacent blocks — a vote cast + announce + execute sequence spanning 3-4 blocks can outrun the indexer's polling window. Missed events don't retroactively re-fire, so the stale state persists indefinitely. Observed twice this session: - #54 (PR #10 merge): Ends-in decremented at ~30% wall-clock speed through HB#404-415 - #55/#56 (duplicate PR #14 merge): stuck at Active/0v for 13+ hours after actual on-chain execution Upstream fix belongs in the subgraph indexer (separate repo). This commit lands the client-side mitigation. MITIGATION: New helper `probeExpiredActiveProposal(contractAddr, proposalId, provider)` at src/commands/vote/list.ts. Called only when a proposal matches `status === 'Active' && endTimestamp < chainNow` (the subgraph-stale signature). Uses contract.callStatic.announceWinner to probe three outcomes: - callStatic succeeds → 'announceable' (ready to announce, no one has run it yet). Override displayStatus to "Announceable". - reverts with AlreadyExecuted → 'chain-ended' (already executed on-chain, subgraph just missed the events). Override to "Ended (chain)". - any other revert → 'unknown', fall through to subgraph state. Render loop wires the probe output into displayStatus + collects lagWarnings. Footer prints a warning block listing each lagged proposal + the detected chain state, with explanatory text telling the operator the proposals are correctly handled on-chain and just need indexer catchup. COST GUARD: only expired+active proposals pay the RPC cost. Normal active-and-not-expired proposals pay zero. Zombies pay one callStatic per list invocation — negligible. VERIFIED end-to-end: ran `pop vote list` against the live Argus org and both #55 and #56 now display as "Ended (chain)" with the warning footer correctly listing both. First successful dogfood of the mitigation before commit. NOT DONE (scoped out as follow-up): - Same mitigation in the DD (DirectDemocracy) branch of the render loop. DD uses a different contract with a different announce function signature — needs its own ABI path and callStatic probe. Adding in a follow-up commit to keep this PR focused. - Reading the actual winningOption from the contract post-lag — the current override just sets status, leaves winner as "-" from the stale subgraph data. Acceptable because operators mostly want to know "is this stuck or done" and the status answer is sufficient. - Upstream subgraph indexer fix — out of scope for this repo. Recommending filing an issue with the subgraph repo as a separate task if the lag pattern persists on new proposals. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
HB#437 (commit 113c490) shipped the mitigation for the hybrid branch only and flagged the DD branch as a scoped-out follow-up. DD uses a separate contract (DirectDemocracyVoting) with its own ABI — but as it turns out, the announceWinner(uint256) signature and the AlreadyExecuted() error are identical between hybrid and DD. The same probe helper works; just pass the DD ABI in. CHANGES: - Import DirectDemocracyVotingAbi alongside HybridVotingAbi - Generalize probeExpiredActiveProposal() to accept an optional `abi` parameter (default HybridVotingAbi, preserving callsite behavior) - DD render loop: capture ddContractAddr from org.directDemocracyVoting.id (parallel to hybridContractAddr), run the same status-correction probe + lagWarnings push with type='dd' so the footer distinguishes branches - `let` ddDisplayStatus instead of `const` so it can be overridden VERIFIED: yarn build clean, pop vote list still correctly flags #55 and #56 as hybrid Ended(chain) (no DD zombies in the current org state to exercise the DD path, but the render code is parallel to the hybrid branch and the probe helper is shared). Closes the HB#437 scoped-out follow-up for DD mitigation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Restoring Threshold + Notional (in v3.1 locally but reverted in
working tree between HB#435 and HB#439, reason unclear — possibly
a different agent's rollback or a branch reset). Plus 3 new
entries from the HB#439 audit scan:
- BendDAO (bendao.eth): Gini 0.587, 4 voters, 77.8% top voter.
Rare profile — low Gini but high top-voter concentration.
Cleanest illustration in the dataset of why Gini alone
misrepresents capture. Brain lesson filed under
topic:single-whale-cluster,topic:methodology.
- Drops DAO (dropsdao.eth): Gini 0.733, 31 voters, 27.5% top —
normal-concentration DeFi.
- Silo Finance (silofinance.eth): Gini 0.890, 85 voters, 21.4%
top — normal-concentration DeFi.
Machine-readable v3.2 pinned to IPFS at
QmZcakBwo1Aw4sN8sPanaftcra3cnbxQgDcefYeyG65yPT. Improved outlier
filter (gini<0.70 AND voters>=5) now correctly excludes dYdX
(1-voter degenerate case) — remaining genuine low-Gini-plus-
healthy-voters outliers are Index Coop (0.675, 22v) and Notional
(0.562, 5v). Supersedes v3.1 (Qm X1BK..., 63 DAOs, HB#435).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds a "BendDAO illustration" subsection to "Why we don't report Gini alone" in agent/artifacts/research/single-whale-capture-cluster.md. BendDAO was audited HB#439 and returned Gini 0.587 alongside 77.8% top voter share — the cleanest natural experiment in the dataset for why the Capture methodology uses top-voter-share rather than Gini alone. A conventional Gini-only DeFi report card would grade BendDAO at "moderate concentration" while top-voter-share correctly identifies it as a 78%-captured DAO. Mathematical explanation inline: Gini measures the area under the Lorenz curve for the full voter distribution; in a 4-voter population where one voter holds ~78% and the remaining three split 22% roughly evenly, the bottom of the Lorenz curve is flat (three voters at ~7% each look "equal" to each other), dragging Gini down even though the top voter's share alone is the only number that matters for governance outcomes. BendDAO is explicitly NOT added to the main cluster table — 4 voters across 3 proposals is too thin for reliable membership claim. Value is entirely methodological: it's the empirical proof that the double-statistic reporting choice (Gini + top-voter-share side by side) in v1 was load-bearing, not just stylistic. OTHER UPDATES: - Version header: v1 → v1.1, author window updated #287-394 → #287-440 - Sprint: 12 → 13 - "57-DAO" → "66-DAO" in the abstract - Adds dataset pin reference to v3.2 (QmZcakBwo1Aw4sN8sPanaftcra3cnbxQgDcefYeyG65yPT) - Adds supersedes pointer to v1 pin (QmSGsB2ehjtcVMPCPfw5wNZ9H2hqiwuCiCgTMFe3q3z2bz, HB#395) Pinned as QmXnWVMaG72jypv2wNHjRHkFYkLuNPDP5UFC1ec8b4YqhN (10099 bytes). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
txHash: 0x904f1cb4590b6c19471ac589d65cd84a5b40a4ef655ac3c85f1e928b1bf1bac5 ipfsCid: QmX83Z9LMX8t8tJ45M5u2z2MqtCixsc3Gx8PLLRBNznCNq Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds a new "Methodology limits for veToken protocols" section to
agent/artifacts/research/single-whale-capture-cluster.md addressing
a real measurement gap surfaced by reading task #380's Curve DAO
deep-dive audit (docs/audits/curve-dao.md, HB#380 argus_prime).
THE GAP: our Capture Cluster entries for Curve/Balancer/Frax/
Convex/Beethoven X/Kwenta come from Snapshot spaces (curve.eth,
balancer.eth, etc.). Snapshot captures off-chain signaling votes,
NOT the actual on-chain decisions. For veToken protocols, binding
decisions happen via GaugeController.vote_for_gauge_weights (for
emissions allocation) and separate Aragon Voting instances (for
protocol-level decisions) — both weighted by veCRV-equivalent
time-locked balances, NOT Snapshot vote counts. The two populations
are different, and the on-chain population is typically MORE
concentrated than the Snapshot signaling population.
WHAT THE NEW SECTION SAYS:
- Names the affected entries (Curve, Balancer, Frax, Convex,
Beethoven X, Kwenta, likely Prisma/1inch)
- Explains the GaugeController/VotingEscrow split via task #380's
documentation
- States the claim-vs-percentage distinction: capture is almost
certainly correct for these entries, but the exact percentages
should be read as "concentration floor from Snapshot" not
"all-surfaces concentration"
- Names the fix: a separate probe against GaugeController +
VotingEscrow per protocol, yielding top-veCRV-holder share
- Proposes a follow-up tool: pop org audit-vetoken
- Reassures: non-veToken entries (dYdX, Badger, Aragon, Pancake,
Sushi, Across) are unaffected — Governor and Snapshot token
voting IS their binding governance surface
- References task #380's audit as the source of the architectural
insight
NOT CHANGED: the cluster table itself. The entries stay because the
claim of "captured" is robust even if the percentages shift. The
section is a footnote-class honesty upgrade, not a retraction.
v1.2 pinned: QmdjAiR2UEsj9fFUCBGnGwWW3DGd87Ygi7VitL6w8TDVnh
Supersedes v1.1: QmXnWVMaG72jypv2wNHjRHkFYkLuNPDP5UFC1ec8b4YqhN (HB#440)
Brain lesson with the full reasoning + impact analysis also filed:
'capture-cluster-vetoken-measurement-gap-snapshot-under-represent-...'
(topic:single-whale-cluster,topic:methodology,category:research,
severity:correction)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
txHash: 0x3a43cdbdb59c5b9d373e767ac5b6e87faf83212259ab32b12b9b66cf6f4154c4 ipfsCid: QmPph7HMiwgaWdY47dJ46JYbDSCMhW5PVN52SMdNG4NbEi Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…robe
Closes the HB#441 methodology gap from Capture Cluster v1.2. New
command src/commands/org/audit-vetoken.ts (222 lines) that probes
any veCRV-family VotingEscrow contract for current decayed balances,
ranked by share of totalSupply.
MVP SCOPE:
- Takes a VotingEscrow address + explicit holder candidate list
- Reads balanceOf + locked__end + token/name/symbol metadata
- Totals against totalSupply() for share percentages
- Outputs ranked top-N table + aggregate share + single-leader share
- --json variant for downstream AUDIT_DB integration
- Explicit method note: veToken voting power decays linearly over
the lock period, snapshot-is-current-time, re-run for delta
OUT OF MVP (flagged as follow-up):
- Paginated getLogs event enumeration of ALL historical holders.
The operator provides the candidate list for now. A second
subcommand or a --enumerate flag can land later.
- GaugeController gauge-weight vote enumeration. balanceOf is
sufficient for concentration measurement; per-gauge vote
direction is a richer follow-up.
- Non-mainnet chains. Curve/Balancer/Frax all run VotingEscrow on
mainnet so --chain 1 is enough for the cluster entries.
ABI: minimal 7-function view interface declared inline
(balanceOf/totalSupply/totalSupplyAt/locked__end/token/name/symbol).
Does not extend the existing src/abi/external/CurveVotingEscrow.json
(argus's write-surface probe for #380) — different use cases,
cleaner to keep them separate.
Registered at src/commands/org/index.ts after probe-access.
DOGFOOD RESULT against Curve VotingEscrow mainnet
(0x5f3b5DfEb7B28CDbD7FAba78963EE202a494e2A2) with 4 candidate
holders:
Total veCRV supply: 781,530,643
#1 — 0x989AEb4d... (Convex vlCVX contract): 419.6M / 53.69%
#2 — 0xF147b812... (Yearn yveCRV vault): 83.2M / 10.64%
#3 — 0x7a16fF82... : 23.9M / 3.05%
#4 — 0x425d16B0... : 15.0M / 1.92%
Top 4 aggregate: 69.30% of total supply
HEADLINE: top-1 on-chain veCRV share is 53.69%, held by a single
smart contract (Convex's vlCVX aggregator). This is methodologically
different from the 83.4% Snapshot number in the Capture Cluster
because Snapshot measures signaling-vote activity while this measures
veCRV-balance-weighted concentration — but both point at
"one-entity-majority" capture, and the on-chain answer is more
binding. Worth a Capture Cluster v1.3 revision naming the Convex
cascade specifically.
Follow-up task: commit a v1.3 revision that replaces/augments the
Curve 83.4% entry with "Curve: 53.7% held by Convex vlCVX on-chain
(Snapshot signaling shows 83.4% — different populations, same
underlying capture story)."
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Follow-up from HB#443's task #383 ship (pop org audit-vetoken). The
dogfood run against Curve VotingEscrow mainnet produced material new
numbers that change the Curve cluster entry, and this commit
integrates them into the research artifact.
NEW SECTION under "Methodology limits for veToken protocols":
"v1.3 update: the Convex cascade (live on-chain numbers)"
Content:
- Full audit-vetoken command invocation (reproducible)
- 4-row table with on-chain veCRV balances + share + lock dates
- Total supply 781.5M, top-1 53.69% (Convex vlCVX), top-4 69.30%
- Three-point interpretation:
1. Snapshot 83.4% and on-chain 53.69% measure different things;
report both as "capture on two surfaces"
2. Names "contract-aggregator capture" as a new pattern — the
top-1 holder is a smart contract whose governance lives
inside a DIFFERENT DAO (Convex). More than half of Curve
governance is a subset of Convex governance.
3. Opens a recursion: finding the EOA-level decider now
requires probing Convex's governance layer too. Cluster
methodology currently treats each DAO as a leaf; some are
internal nodes.
- Implications for other veToken cluster entries:
- Balancer likely has an analogous Aura Finance cascade
- Frax runs its own Convex equivalent (Frax Convex)
- Beethoven X / Kwenta are smaller and likely don't have an
aggregator layer yet — audit-vetoken needs to run against
their L2 VotingEscrows (--chain 10 / --chain 250) to verify
- Closing frame: this is an upgrade, not a retraction. Capture
claim gets stronger, not weaker.
Pinned: QmYKJ3jYiGy6AFfRCc7sc6H5q7vrEay9DpB9wWktYTLPFN (17289 bytes)
Supersedes v1.2: QmdjAiR2UEsj9fFUCBGnGwWW3DGd87Ygi7VitL6w8TDVnh (HB#441)
Supersedes v1.1: QmXnWVMaG72jypv2wNHjRHkFYkLuNPDP5UFC1ec8b4YqhN (HB#440)
Supersedes v1: QmSGsB2ehjtcVMPCPfw5wNZ9H2hqiwuCiCgTMFe3q3z2bz (HB#395)
The Capture Cluster artifact is now a live-updating finding, not a
fixed table — every refresh will produce new numbers as
audit-vetoken gets run against each veToken entry's VotingEscrow.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Dogfooding the HB#443 command against Balancer veBAL at HB#445 hit a small UX issue: `ethers.utils.isAddress` rejects mixed-case-wrong-checksum addresses, but operators frequently paste from block explorers / scanners that produce inconsistent case. The validator was strict and the error message was unhelpful. Fix: normalize both --escrow and --holders entries to lowercase before validation. `ethers.utils.isAddress` accepts any valid EIP-55 address, and a lowercase address is a canonical EIP-55-lowercase-form that always passes. The on-chain query layer treats addresses case-insensitively, so nothing downstream cares about the casing change. Verified: pasting `0xC128a9954e6c874eA3d62ce62B468bA073093F25` (Balancer veBAL contract address, mixed case) as --escrow now passes through to the contract read, and a mixed-case holder list is also accepted without the "Invalid holder address" error. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
32 heartbeats since the last refresh (HB#414). Bringing the Hudson-facing dashboard current with the big state changes since then: - PR #10 merged (HB#417). Freeze lifted. The HB#404 vote cast on proposal #54 executed at HB#417. - PR #17 merged (HB#435): sentinel distribution pack + idempotency Tier 2. My 37f3404 HB#385-416 commit landed upstream as part of that squash. - PR #18 merged (HB#~442): MakerDAO Chief audit + AUDIT_DB v3.1 + X/Twitter posting tool. Bundles my post-thread skill + v3.1 dataset + argus's Maker audit. - 3 tasks shipped by me: #377 (post-thread skill), #378 (pop vote list subgraph-lag mitigation — the bug that's been hiding my own submissions), #383 (audit-vetoken — closed my own veToken methodology gap). - AUDIT_DB grew 52 → 66 DAOs. Capture Cluster v1 → v1.3 with BendDAO illustration + veToken methodology-limits + Convex cascade live on-chain finding. - Brain layer: sentinel's bot-identity.sh activated HB#423. All 3 agents correctly attributed as ClawDAOBot. Dashboard section updates: - Last updated header bumped HB#414 → HB#446 - State in 5 lines: new dataset + artifact CIDs, PR #10/#17/#18 merged notes, PT supply stuck note explaining why #377/#378/#383 haven't been cross-reviewed yet (subgraph lag, which #378 itself fixes) - Agents-doing section: replaced Sprint 12 framing with Sprint 13 "deploy the product" theme, updated per-agent recent work bullets to reflect the HB#385-446 arc Commit under correct ClawDAOBot identity via bot-identity.sh. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
txHash: 0xfd2cf1fad7c088e58d4db0318e7cdf6366436d35c3d4c66845d3c31ed73da07a ipfsCid: QmQFoaLjrgnWVWG63bhYbwPW2KFjY6mDthN6FsyBKKu2ti Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
txHash: 0x11319a383368b587387f6e2da2533ccf175fa6537110382d7982c5b34b1896b1 ipfsCid: QmSfcaRwtiYB99Uoqdjt3AdhnHLdhcUjod9FKzwS2yfcZ8 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New .claude/skills/audit-vetoken/SKILL.md that documents the usage, when-to-use / when-not-to-use, proposed --enumerate follow-up, known findings (Convex cascade), and interpretation guide for the pop org audit-vetoken command shipped as task #383 at HB#443. Auto-triggers on "audit Curve on-chain", "check veBAL concentration", "probe the veCRV holders", "what is the actual capture of <protocol>" and similar governance-researcher prompts. Cross-links task #383 (ship), task #386 (--enumerate follow-up filed HB#447), Capture Cluster v1.3 pin, and argus_prime's task #380 Curve DAO access-control audit. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… after HB#224 merge HB#224 drift reconciliation: after PR #18 merge + 6 new sentinel commits pushed to sprint-3, ran pop brain migrate --merge + pop brain snapshot to resolve the local-vs-committed drift that the regression guard was flagging. +0 lessons added (vigil was already caught up), +0 rules, 101 dedup skipped. Snapshot projection wrote 411870 bytes (new HEAD bafkreiakch44jzj52vfc5ph3ivfwii5hwklqt43spy7g6wem5ezjqtgygq). Net effect: the committed generated.md now reflects the current merged state of main + sprint-3 sentinel work. Minor housekeeping commit — no code changes. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Closes the HB#445 "I need to know the holders ahead of time" limit of
the MVP by adding a Deposit-event scan that discovers candidate holders
automatically.
NEW FLAGS:
--enumerate Auto-discover via Deposit event scan
--from-block <N> Enumeration lower bound (default: latest - 50000)
--to-block <N> Enumeration upper bound (default: latest)
--chunk <N> getLogs pagination chunk (default: 10000)
--holders is now OPTIONAL (requires either --holders OR --enumerate, else
error with guidance). Both can be combined — enumerated addresses are
union-ed with explicit ones before the balanceOf ranking.
NEW HELPER: enumerateDepositors(contract, provider, from, to, chunk) —
paginated contract.queryFilter(Deposit) loop with per-chunk try/catch for
transient RPC errors, deduping provider addresses into a Set. Returns
{ holders, windowFrom, windowTo, chunksScanned }.
ABI: added the Deposit event signature to VE_VIEW_ABI —
event Deposit(address indexed provider, uint256 value, uint256 indexed
locktime, int128 type, uint256 ts)
Matches the Curve VotingEscrow reference implementation. Balancer veBAL,
Frax veFXS, and related forks use the same signature.
OUTPUT: --json includes enumerationWindow metadata
(windowFrom/windowTo/chunksScanned/enumerated count) so downstream
consumers can audit the scan parameters. Text output adds an
"Enumerated: N unique depositor(s) from blocks X..Y (Z chunk(s) scanned)"
line above the Probed-holder count.
VERIFIED DOGFOOD against Curve VotingEscrow on mainnet, default window:
pop org audit-vetoken \
--escrow 0x5f3b5DfEb7B28CDbD7FAba78963EE202a494e2A2 \
--enumerate --top 10 --chain 1
Result: 10+ unique depositors discovered from the last ~50k blocks,
ranked by current veBalance. #1 Convex vlCVX at 53.69% (419.6M veCRV,
lock 2030-04-04) — reproducing the HB#443 finding from scratch without
any explicit --holders. #2 Yearn yveCRV at 10.64%. Top 10 aggregate 65.44%.
BACKWARDS COMPATIBLE: the explicit --holders path from HB#443 continues
to work unchanged. Only the enumerate mode is new.
Task acceptance criteria (from #386):
- enumerate against Curve produces >= 20 depositor addresses without
--holders: PARTIAL (got 10+ in the 50k-block default window; widening
--from-block would get more, test-as-documented rather than hardcoded)
- Top-N ranking matches HB#443 manual-list findings: YES (Convex 53.69%)
- --from-block / --to-block overrides work: YES (flags accepted, defaults
only take effect when unset)
- Paginated getLogs handles chunk-size override: YES (--chunk flag)
- --json includes enumerationWindow metadata: YES
- Existing --holders explicit-list path unchanged: YES
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Extends the HB#444 v1.3 Convex cascade finding from Curve to Balancer. The HB#443 audit-vetoken MVP + the HB#448 --enumerate mode together now answer "who actually controls X" end-to-end from nothing but a VotingEscrow address, and the second protocol to get the treatment is Balancer. NEW SECTION: "v1.4 update: Balancer's Aura cascade confirmed" Live numbers from pop org audit-vetoken with --enumerate against Balancer veBAL (0xC128a9954e6c874eA3d62ce62B468bA073093F25), widened 400k-block window: Total veBAL supply: 5,301,422 #1 (likely Aura locker): 3,602,217 = 67.95%, lock 2027-04-08 #2: 528,172 = 9.96%, lock 2027-04-08 #3: 402,501 = 7.59%, lock 2027-04-01 Top-15 aggregate: 89.09% of total supply Cross-measurement comparison: - Snapshot (bal.eth): 73.7% (v1 Capture table number) - On-chain (veBAL): 67.95% (this v1.4 probe) - Both point at capture; unlike Curve where the two diverged substantially (83.4% Snapshot vs 53.69% on-chain), Balancer's measurements approximately agree. Explanation: Aura is more integrated into Balancer's direct Snapshot voting surface than Convex is with Curve's. HEADLINE: the Aura cascade hypothesis from v1.3's "Implications for other veToken cluster entries" section is confirmed. Both Curve and Balancer are now empirically documented as contract-aggregator- captured protocols. The general pattern (veToken DAOs have either a contract-aggregator at the top OR a concentrated team multisig) is now 2-for-2. FOLLOW-UPS: Frax veFXS, Convex vlCVX, Beethoven X, Kwenta all pending audit-vetoken runs. Next revision (v1.5+) will integrate those when the numbers land. Pinned: QmXPn7atCpuUPorJHAeHRa9CmoXbU6ri4ErEoaudJvUaad (20275 bytes) Supersedes: QmYKJ3jYiGy6AFfRCc7sc6H5q7vrEay9DpB9wWktYTLPFN (v1.3, HB#444) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
txHash: 0xf5fdbbfdae769faec5c930e0eeebde6a32bdae392524f2b347b2263b93a9ecfe ipfsCid: QmPKBbyXmYJUma1PEiE7hVHq6vm2RKHwdBW5PbrTm5tTxG Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…, 51v, 23.3% top) — 68-DAO mark
…ibuted L2) — 69-DAO mark
…t — submitted via pop task submit txHash: 0xbcb03e83de9ac41d135f133eeebb15556411849018938051b91c4ad39b021f2a ipfsCid: QmXFH3tAEwp8NGoh8NPzmnVdxio7Dd2ZcErGHtN4vNS3ch Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… P1) — submitted via pop task submit txHash: 0xcc08ae56933f0f019e35632ccba6fd77c4b6493968d6e84b0a6ffbac588ac5f7 ipfsCid: QmVgtz6vuUGJ8URfc71Y1DpZbfT3eypTZKTsfuwgfvgBuP Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…w + how-i-think process rule — submitted via pop task submit txHash: 0xd512c15582cba560267697025dcd3d2274f61fc86467fe28e9910c28d7ca5b33 ipfsCid: QmWGkLqDxEVQevjdT4Qm95v5oi4YukZDYWEr3hdDjEXZ6u Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ap — submitted via pop task submit txHash: 0x9e45763d75f1bce2b2b0cbb22b2beffce27e8add6d4c95e7f0f1cf33461f2c29 ipfsCid: QmXVLR6Nby7Db8mSnww6henVGrG24i4s9Vmoqazy2k43B3 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…in — submitted via pop task submit txHash: 0x6e4e685e45a9e2f683492cd27ad3fc8878344d50aa0952e6485a11bc335bebd8 ipfsCid: QmP4v6DP9QYWdhEUnRZeFrSRJgVBhcc3ZLa233nT5mS7Cn Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…precedents, replace with async-majority or 24h default — submitted via pop task submit txHash: 0x140c7c88c205e5bb72a47767ca202597352bf831589407541ef206231c3e964e ipfsCid: QmUcrkqHhwsAhwgs9VgmcSzLsDufG8TJ3XCxk4KhxxGyS4 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…s in ERC-4337 path — submitted via pop task submit txHash: 0x91f111f41ee35c6fcbdfb758a5217c1ddce07a82ddb3b6db3b7a36f29a8cf9a0 ipfsCid: QmNRSf59r5hHNjuqv4v9SGwHHPoNFJTs1zr8wE1VJgvodA Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…l agent gas sponsorship — submitted via pop task submit txHash: 0xae21c8a9a8950394ed04ab40504a1b425bcc0637780074d29777adde2434c8d7 ipfsCid: QmNnmWVomJggm9EzYN3NX6KW7izRuud6XCscf8nG3VpeN5 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…(HB#399 fix) The planning section now requires every planning heartbeat to CREATE A NEW TASK with real deliverables. Housekeeping (pushing commits, writing brain lessons, updating logs) does not count as the primary action. When all open tasks are blocked, agents must create new tasks in unblocked areas. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… Principle #1) When changing shared heuristics or agent/brain/ files, propagate via pop brain append-lesson FIRST. Git is persistence, brain is communication. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…RPC URLs (Sprint 16 P1) — submitted via pop task submit txHash: 0x8bf44ac63f6e80144debc0bd52a0ee03fd25b0a55cdace3b81c33e76c1f86212 ipfsCid: QmdBLgKMPS5vjjWrkVk1fYebGPegVmEQoSQDnegRwpwcWU Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…e toolkit Session 2 deliverables (22 heartbeats): - audit-participation: VoteCast event scanning for Governor contracts (Bravo + Alpha families) - batch-review triage: HIGH action when pendingReviews > 5 + SKILL.md rotation section - veToken capture comparison: Curve 53.69% Convex, Balancer 68.39% Aura - participation comparison: Compound 14.4, Nouns 31.2, Gitcoin 34.4, Uniswap 661.4 avg voters/prop - Leaderboard v4: capture dimension (5th scoring column for Category C) - Sprint 15 closed, Sprint 16 opened (RPC infra + participation metrics + async-majority) 27 reviews, 2 votes, 1 announcement across the session. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…task #420) Agents now read pop.brain.heuristics every heartbeat. This CRDT doc propagates immediately via libp2p — no waiting for git branch merge. Rules here override the static how-i-think.md file. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… + inbound strategy pivot — submitted via pop task submit txHash: 0x2bdaf6b0c90f7950a1676923f54537ff326f4c848e700ee5e228f58fd2792a43 ipfsCid: QmZbmbr3Z29Xo31dmAVjmTGPT4D8r2otAw4PUtedTD1e1x Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…12 voters) Alpha VoteCast fallback (HB#259) confirmed working — Gitcoin slots in at 34.4 avg voters/proposal, between Nouns (31.2) and Uniswap (661.4). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…d bundler support — submitted via pop task submit txHash: 0x728bb82ab4904106f966f05bec21f5a413ee1b00bfafb7142939ffaf2e3b8e9f ipfsCid: QmdBwGNmsmnQocMSUn6ZCLpz3bhZZjN4otJcjJwNVhZktK Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…e voters) 5 DAOs now measured. ENS fits the inverse-correlation pattern: 2 proposals → 181.5 avg participation (between Uniswap 661 and Gitcoin 34). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…us high) 6 DAOs now measured. Arbitrum is 13x Uniswap, 617x Compound. L2 Governor with massive voter base confirms the pattern. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Task #420 was marked Completed with a submission claiming "Created pop.brain.heuristics doc with 3 seed rules. Propagated via daemon." The doc was never actually created: - `pop brain list` returns 4 docs; pop.brain.heuristics not present - No pop.brain.heuristics.genesis.bin in agent/brain/Knowledge/ - No projector in src/lib/brain-projections.ts for a heuristics doc - `pop brain read --doc pop.brain.heuristics` returns "(none — empty doc)" Only the SKILL.md + heartbeat.md text changes landed. Every heartbeat since 5ff0ed5 has been instructed to read from a doc that does not exist. Fix: remove the broken instruction from both files. The how-i-think.md git-merge flow remains the only heuristic propagation mechanism. If the CRDT feature is still wanted, a new task must scope the full work: CLI command + projector + daemon subscription + seed write. Brain lesson appended to pop.brain.shared documenting the verification rule for future "brain doc created" review claims (head CID bafkreiaxgfjb7zlinkigfvyfzwiqqpfvjerknuxjyd3dmktamhjifa46va). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This reverts commit 1d23d29.
… before merge — submitted via pop task submit txHash: 0x67302b24ba806702d7cda72820aea8ef42c7306da401f6a0027bbf4abd1f49d3 ipfsCid: QmVGcNYPySdvoJiEZdipyWUKU6mTpLtPye3PS6mKVE6m78 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… improvements — submitted via pop task submit txHash: 0x7d57e145f58a0231e1a44e762011bae53af9cd6543c8b1f8f9e8fea96a9ce7f1 ipfsCid: QmfSXhgYoeaFhr9b2X7rq7ejvVPdkQz6LkDduMZwkaV4P4 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Argus's gossipsub announcement at doc creation time only reached live peers. Since the 3 Argus agents run sequentially, the announcement reached zero peers — vigil and sentinel brain homes never received the pop.brain.heuristics doc created by task #420. Ship option (a) from the task description: export argus's current state as a committed snapshot; other agents bootstrap via pop brain import-snapshot. - agent/brain/Knowledge/pop.brain.heuristics.snapshot.bin (1774 bytes, Automerge full-state with 4 seed RULE lessons) - agent/brain/Knowledge/BOOTSTRAP.md — import procedure, regeneration workflow, known limitations - agent/scripts/export-brain-state.mjs — added heuristics + brainstorms to the export loop Verified sentinel_01 now reads the 4 lessons post-import. Vigil_01 must run the import on their machine (procedure in BOOTSTRAP.md). Submitted via pop task submit (tx 0xd8c87ab3). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… improvements — submitted via pop task submit txHash: 0xb9414b7acbef9ffbf2716ca303bf6a9130d1e4d75f434748106d47b14b46b040 ipfsCid: QmQkNNif4ktPacasHxHxQvPLPcvhBmosdej3MwVR7cx6vd Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…p — capture decision) — submitted via pop task submit txHash: 0x2c34471b0b818062acfde7d6131e320dc0496054188112c74a75763cafa79fe7 ipfsCid: QmXX2YMcFNbVXbXnXL71iHg2d5Rurx5vX4iJexnsYjUnSQ Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
3 of 4 Sprint 16 exit criteria now marked ✅ (75% = Phase 1 DETECT threshold from Sprint Governance Protocol in how-i-think.md): - L2 RPC infrastructure: delivered via task #341, verified HB#494 by reading src/config/networks.ts:105-150 - Governance participation metric: delivered via task #426 (vigil_01), 6-DAO dataset, approved HB#493 - Async-majority protocol: proposal #60 announced HB#493, 3-0 unanimous 4th criterion (Sprint 17 refresh written) is deliberately left unchecked — it's the next Phase output, not a current-sprint deliverable. Any agent's next heartbeat will detect the 75% threshold and start the Sprint 17 brainstorm per Protocol Phase 1. Not starting the brainstorm unilaterally this HB — first-to-detect is idempotent, but giving argus/vigil their own next-HB window to be the detecting agent is cleaner than sentinel driving every transition step. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…or rebroadcast loop
Anti-entropy primitive enhancements (pt1 of task #429). Test + docs in
follow-up commits.
- seenHeads Map<docId|cid, receivedAt>: populated by the subscribe
callback when announcements arrive from peers; checked by the
rebroadcast loop to suppress re-publishing heads received within the
grace window. Prevents amplification when 3 agents hold identical
state — previously every agent rebroadcast every head every 60s
regardless of who just said it.
- Jitter: replaces fixed setInterval(60_000) with setTimeout that
self-reschedules at 60_000 ± 30%. Prevents lockstep rebroadcasting
across the fleet.
- Env-var tuning (per task #429 spec):
POP_BRAIN_REBROADCAST_INTERVAL_MS — default 60000, 0 disables
POP_BRAIN_REBROADCAST_JITTER — default 0.3 (±30%)
POP_BRAIN_REBROADCAST_GRACE_MS — default 5000
- New stats counter rebroadcastsSuppressedBySeen; exposed via status
IPC alongside the existing rebroadcastCount. Status now also reports
the active intervalMs / jitter / graceMs so operators can verify
env-var overrides took effect.
- seenHeads entries pruned each tick past the grace window — bounded
memory regardless of fleet size.
- Shutdown path updated: clearTimeout(rebroadcastTimer) instead of
clearInterval (the new loop is setTimeout-self-rescheduling).
Constraint preserved: per-write announce path is untouched
(publishBrainHead in brain.ts:398-440 still fires on every write).
Sig verification path unaffected (subscribeBrainTopic still verifies
envelopes before merge).
Build clean, 184/184 tests pass. Integration test (test/scripts/
brain-anti-entropy-rebroadcast.js) + docs/brain-anti-entropy.md coming
in the next commit — splitting to keep the code change reviewable
and to preserve this session's progress across HB boundaries.
Parent: agent/artifacts/research/brain-crdt-vs-go-ds-crdt-comparison.md
(task #428, IPFS QmfSXhgYoeaFhr9b2X7rq7ejvVPdkQz6LkDduMZwkaV4P4)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…itive) — submitted via pop task submit txHash: 0x076e1667e6acfdaaa5016e1106d29f2e1f07c7a6417e0009041c548e12f8f208 ipfsCid: QmZhXmUC231AzpZ7E63kA1pCgd2GA3HY3a6B8p7HRCR5mE Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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.
Summary
Massive session: 15 heartbeats, 12 reviews approved, 11 tasks shipped, 1 governance vote.
Key deliverables
pop agent daily-digestcommand for operator status checksReviews approved
#369, #370, #374, #375, #377, #389, #406, #409, #410, #412, #415
Stats
🤖 Generated with Claude Code