Code Dive
In Glow V1, the happy path for governance follows a five step process, outlined below:
1. Proposal Creation
• Users call one of the create*Proposal entry points (createGrantsProposal, createGCACouncilElectionOrSlashProposal, etc.).  
• Each function:
- Calculates the nomination cost (costForNewProposalAndUpdateLastExpiredProposalId).
- Burns the caller's nominations via _spendNominations.
- Stores a Proposalstruct in_proposalsand, if its vote count tops the leaderboard, records it inmostPopularProposalOfWeek.
2. Collecting Votes
• Additional nominations can later be attached with useNominationsOnProposal.  
• Once the popularity week ends, long-staked GLW holders record ratify/reject votes through ratifyOrReject.  
• Votes accumulate in _proposalLongStakerVotes.
3. Eligibility Window
A proposal becomes executable when:  
 • Its popularity week has finished and  
 • The four-week ratify/reject & veto window (NUMWEEKSTOVOTEONMOSTPOPULARPROPOSAL) has elapsed.
4. Execution Engine (syncProposals)
Anyone can invoke syncProposals() to process the backlog sequentially—oldest first.
1function syncProposals() public {
2    ...
3    for (_nextWeekToExecute; _nextWeekToExecute < currentWeek; ++_nextWeekToExecute) {
4        uint256 proposalId = mostPopularProposalOfWeek[_nextWeekToExecute];
5        ...
6        handleProposalExecution(_nextWeekToExecute, proposalId, proposalType, proposal.data);
7    }
8}If any execution reverts, the loop aborts and lastExecutedWeek remains unchanged, blocking every subsequent proposal.
5. Type-specific Dispatch (handleProposalExecution)
handleProposalExecution decodes the payload and forwards the action to the correct subsystem:
1if (proposalType == IGovernance.ProposalType.VETO_COUNCIL_ELECTION_OR_SLASH) {
2    (address oldMember, address newMember, bool slashOldMember) = abi.decode(data,(address,address,bool));
3    success = IVetoCouncil(VETO_COUNCIL).addAndRemoveCouncilMember(oldMember, newMember, slashOldMember);
4}Other branches cover Grants payouts, GCA requirement changes, RFC logging, etc.  
Success or failure is stamped via _setProposalStatus, and an event is emitted.
Where It Broke
During week 76, the queued proposal was a VETOCOUNCILELECTIONORSLASH.  
When syncProposals() hit the dispatch above, the call to VetoCouncil.addAndRemoveCouncilMember() reverted with CallerNotGovernance because the Veto Council contract's immutable governance field had been mis-wired to the GLW token address during deployment:
1// DeployGuardedLaunch.s.sol
2vetoCouncilContract = new VetoCouncil(address(glow), address(glow), startingVetoCouncilAgents);
3//                          ^^^^^^^^^^^^^^^^^^^^^  (should be Governance)The revert bubbled up, terminated the for loop, and left lastExecutedWeek stuck.  
Because syncProposals() insists on synchronous, chronological execution (week == lastExecutedWeek + 1), the entire Governance pipeline froze—no subsequent proposals (including grant payouts) can progress until a redeploy wires the Veto Council to the correct Governance address.
Impact
- Governance execution frozen. No on-chain grants, parameter changes, or council elections can complete.
- Grants moved off-chain. The Foundation will aid in an off-chain grant process manually until V2 is operational.
- No funds at risk. Contract balances and state remain intact; the issue is a logic lock, not a security breach.
Preventing These Issues
Ultimately, the value of any post-mortem lies in the concrete safeguards it inspires. The four mitigations below - type-safe constructors, AI-assisted static analysis, end-to-end deploy-script tests, and dual-review canary deployments - turn the lessons of this incident into hard guardrails baked into our tooling and release flow. Together they make a repeat of the mis-wiring error mechanically unlikely and surface any similar faults long before they can reach mainnet.
- Strongly-typed constructors in new code. All new contracts receive explicit interface parameters; misuse fails at compile time.- Deployment scripts pass interface-typed objects instead of plain addresses, eliminating class-mismatch errors.
 
- AI-assisted static analysis. New codebases run an LLM ruleset that flags duplicated or suspicious constructor arguments before merge.
- Comprehensive deploy-script tests. Each script forks mainnet, executes the deployment end-to-end, and asserts post-deploy invariants, blocking any transaction that does not wire contracts correctly.
- Mandatory multi-party review and canary execution. Every mainnet deploy requires dual-signature review of calldata and a post-deploy smoke test on a fork, preventing mis-configured contracts from reaching production.
