Skip to content

feat(dashboard): add Shutter Security Council card - #2168

Merged
brunod-e merged 3 commits into
devfrom
feat/shutter-security-council-card
Sep 30, 2026
Merged

brunod-e merged 3 commits into
devfrom
feat/shutter-security-council-card

Conversation

@alextnetto

@alextnetto alextnetto commented Sep 29, 2026 •

Copy link
Copy Markdown
Member

What

Adds the Security Council card to the Shutter DAO overview, the same card ENS and Compound already have.

Shutter's veto runs through the new Snapshot X module: the Security Council (5-of-8 Safe 0x3ea7…c0C0) owns the Snapshot X space (0x594E…B769) and vetoes a proposal by calling Space.cancel(proposalId) any time before execution. The card points at that multisig.

Why "No expiration"

Unlike ENS's renewable term or Compound's guardian expiry, Shutter's veto is an owner privilege with no fixed term. This PR adds a noExpiration flag to the securityCouncil config: when set, the card shows "No expiration" instead of a countdown and drops the progress/danger bar. ENS and Compound are untouched — they keep their expiration blocks and existing behavior.

Changes

  • shared/dao-config/shu.ts — add the securityCouncil block (5-of-8, noExpiration: true, Snapshot X veto description; Start = 2026-09-07, when the Council took ownership of the space).
  • shared/dao-config/types.ts — add optional noExpiration?: boolean.
  • features/dao-overview/components/SecurityCouncilCard.tsx — treat a noExpiration council as 0 progress / no danger zone.
  • features/dao-overview/components/CountdownDaoInfo.tsx — render "No expiration" instead of a countdown.
  • changeset (@anticapture/dashboard: minor).

Verification

  • Dashboard typecheck: no new errors from these files (baseline error count on dev is unchanged).
  • shared/dao-config/dao-config.test.ts: 26/26 pass (incl. SHU).
  • ESLint clean on all changed files.

Note: addresses were verified on mainnet — the council Safe is a 5-of-8, it is the owner of the Snapshot X Space, and the space is the enabled execution module on the treasury Safe.


Note

Low Risk
Config and DAO overview UI only; no changes to auth, on-chain logic, or existing ENS/Compound council configs.

Overview
Adds a Security Council block to the Shutter DAO overview config: active 5-of-8 multisig, Safe link, and tooltip text describing Snapshot X Space.cancel veto (not timelock cancel). Shutter uses noExpiration: true because veto is an open-ended owner privilege; only the council start date (2026-09-07) is meaningful.

Introduces optional noExpiration on securityCouncil in shared types. CountdownDaoInfo renders "No expiration" instead of a live countdown when that flag is set. SecurityCouncilCard skips term progress and danger-zone math for those councils (0% progress / no warning). ENS and Compound configs are unchanged.

Dashboard minor changeset for the new Shutter card behavior.

Reviewed by Cursor Bugbot for commit ac8e8a0. Configure here.

Shutter's veto runs through Snapshot X: the Security Council (5-of-8 Safe
0x3ea7...c0C0) owns the Snapshot X space (0x594E...B769) and vetoes a
proposal by calling Space.cancel(proposalId) before execution. Point the
DAO Overview Security Council card at that multisig.

Unlike ENS's renewable term or Compound's guardian expiry, this veto is an
owner privilege with no fixed term. Add a `noExpiration` flag to the
securityCouncil config; when set, the card shows "No expiration" instead of
a countdown and drops the progress/danger bar (ENS and Compound keep their
expiration blocks and behavior).
@vercel

vercel Bot commented Sep 29, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
anticapture-storybook Ready Ready Preview Sep 30, 2026 6:12pm UTC
1 Skipped Deployment
Project Deployment Actions Updated
anticapture Ignored Ignored Sep 30, 2026 6:12pm UTC

Request Review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 29, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-29T19:49:09.741253Z 491cc4d New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

Copy link
Copy Markdown
Collaborator

🎨 UI Review

Automated review · Figma: not found · Spec: none found in ClickUp
ℹ️ Reviewed without a Figma reference — grounded in code/layout inspection and UX-expert evaluation. The anticapture (dashboard) Vercel deployment for this PR is Ignored and the Storybook preview was still building, so no live visual check was possible; visual claims are limited.


Security Council card — Shutter (noExpiration)

Progress bar is still rendered, and shows a stray "0"

  • The PR description says the card "drops the progress/danger bar", but SecurityCouncilCard.tsx still renders <ProgressBar> unconditionally, so the full track (bg-surface-contrast h-4) is shown for Shutter. Skip the track and the tangerine knob when noExpiration is set; keep only the Start/Expiration row. (SecurityCouncilCard.tsx, <ProgressBar …> block) [Code-only]
  • warning now returns 0 for noExpiration, and ProgressBar.tsx renders {warning && warning > 0 && (…)}. 0 && … evaluates to 0, which React prints as a literal "0" in the top-left of the bar track. Use warning > 0 && (…) or don't render the bar. (ProgressBar.tsx, first child of the relative h-4 div) [Code-only]
  • With progress = 0, the knob (-right-1.5 size-[21px]) sits pinned at the left edge, which reads as "term just started, nothing elapsed". That is misleading for a veto that never expires. Hiding the bar fixes this too. [UX-heuristic]
  • The gradient overlay under the bar gets width: calc(0% - 4px) (negative), so it collapses. Fine once the bar is hidden, but another reason not to render it. [Code-only]

Redundant label

  • The right column reads "Expiration" → "No expiration". Rename the label to "Term" (or hide the label) when noExpiration is set, so it reads "Term: No expiration". Keep text-secondary text-xs font-medium for the label and text-primary text-sm for the value. (ProgressBar.tsx "Expiration" <p>, CountdownDaoInfo.tsx) [UX-heuristic]

Mobile

  • The multisig description tooltip is wrapped in hidden lg:flex, so on mobile the Snapshot X veto explanation (the only place it's described) is unreachable. Shutter's mechanism differs from ENS/Compound, so this matters more here. Show the info icon on mobile too (44×44px hit area), or surface the description inline. (SecurityCouncilCard.tsx, tooltip wrapper) [UX-heuristic]

Validated — no change needed

  • "No expiration" uses the same text-primary text-sm font-normal leading-5 as the ENS/Compound countdown, so type size and colour stay consistent. [Code-only]
  • Header row, 5/8 required for transactions link and Key icon are unchanged and reuse the existing DS UnderlinedLink/TooltipInfo. [Code-only]

Generated by Claude Code

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ac8e8a00d5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".


const progress = useMemo(() => {
if (!securityCouncil) return 0;
if (!securityCouncil || securityCouncil.noExpiration) return 0;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Hide the expiration progress bar for indefinite councils

When noExpiration is true, returning 0 only suppresses the danger zone; SecurityCouncilCard still renders ProgressBar, whose unconditional markup shows the timeline track, orange marker, and zero-width gradient. Shutter therefore displays a misleading zero-progress expiration timeline despite being configured with no fixed term. Conditionally omit the graphical progress bar or render a dedicated indefinite-term layout instead.

Useful? React with 👍 / 👎.

@railway-app

railway-app Bot commented Sep 29, 2026 •

Copy link
Copy Markdown

🚅 Deployed to the anticapture-pr-2168 environment in anticapture-infra

Service Status Web Updated
gateful ❌ Build Failed (View Logs) Web Sep 30, 2026 at 6:20 pm UTC
authful ✅ Success (View Logs) Web Sep 30, 2026 at 6:17 pm UTC
loki ✅ Success (View Logs) Sep 30, 2026 at 6:16 pm UTC
prometheus ✅ Success (View Logs) Sep 30, 2026 at 6:16 pm UTC
otelcol ✅ Success (View Logs) Sep 30, 2026 at 6:16 pm UTC
alertmanager ✅ Success (View Logs) Web Sep 30, 2026 at 6:16 pm UTC
grafana ✅ Success (View Logs) Web Sep 30, 2026 at 6:16 pm UTC
tempo ✅ Success (View Logs) Sep 30, 2026 at 6:16 pm UTC
compound-indexer-offchain ✅ Success (View Logs) Sep 29, 2026 at 9:39 pm UTC
shutter-indexer-offchain ✅ Success (View Logs) Sep 29, 2026 at 9:39 pm UTC
ens-indexer-offchain ✅ Success (View Logs) Sep 29, 2026 at 9:39 pm UTC
gitcoin-indexer-offchain ✅ Success (View Logs) Sep 29, 2026 at 9:33 pm UTC
uniswap-indexer-offchain ✅ Success (View Logs) Sep 29, 2026 at 9:29 pm UTC
mcp ✅ Success (View Logs) Web Sep 29, 2026 at 8:19 pm UTC
docs ✅ Success (View Logs) Web Sep 29, 2026 at 8:19 pm UTC
shutter-indexer ✅ Success (View Logs) Sep 29, 2026 at 8:10 pm UTC
gitcoin-indexer ✅ Success (View Logs) Sep 29, 2026 at 8:10 pm UTC
fluid-indexer ✅ Success (View Logs) Sep 29, 2026 at 8:10 pm UTC
compound-indexer ✅ Success (View Logs) Sep 29, 2026 at 8:10 pm UTC
tornado-api ✅ Success (View Logs) Sep 29, 2026 at 8:09 pm UTC
ens-api ✅ Success (View Logs) Sep 29, 2026 at 8:09 pm UTC
shutter-api ✅ Success (View Logs) Sep 29, 2026 at 8:09 pm UTC
aave-api ✅ Success (View Logs) Sep 29, 2026 at 8:09 pm UTC
gitcoin-api ✅ Success (View Logs) Sep 29, 2026 at 8:09 pm UTC
address-enrichment ✅ Success (View Logs) Web Sep 29, 2026 at 8:09 pm UTC
compound-api ✅ Success (View Logs) Sep 29, 2026 at 8:09 pm UTC
ens-indexer ✅ Success (View Logs) Sep 29, 2026 at 8:08 pm UTC
scroll-indexer ✅ Success (View Logs) Sep 29, 2026 at 8:08 pm UTC
tornado-indexer ✅ Success (View Logs) Sep 29, 2026 at 8:08 pm UTC
obol-api ✅ Success (View Logs) Sep 29, 2026 at 8:07 pm UTC
nouns-api ✅ Success (View Logs) Sep 29, 2026 at 8:07 pm UTC
fluid-api ✅ Success (View Logs) Sep 29, 2026 at 8:07 pm UTC
uniswap-api ✅ Success (View Logs) Sep 29, 2026 at 8:07 pm UTC
lil-nouns-api ✅ Success (View Logs) Sep 29, 2026 at 8:07 pm UTC
uniswap-indexer ✅ Success (View Logs) Sep 29, 2026 at 8:07 pm UTC
nouns-indexer ✅ Success (View Logs) Sep 29, 2026 at 8:07 pm UTC
lil-nouns-indexer ✅ Success (View Logs) Sep 29, 2026 at 8:07 pm UTC
obol-indexer ✅ Success (View Logs) Sep 29, 2026 at 8:07 pm UTC
aave-indexer ✅ Success (View Logs) Sep 29, 2026 at 8:07 pm UTC
erpc ✅ Success (View Logs) Sep 29, 2026 at 8:04 pm UTC
nodeful ✅ Success (View Logs) Sep 29, 2026 at 8:01 pm UTC
ens-relayer ❌ Build Failed (View Logs) Sep 29, 2026 at 8:00 pm UTC
user-api ✅ Success (View Logs) Web Sep 29, 2026 at 7:58 pm UTC
scroll-api ✅ Success (View Logs) Sep 29, 2026 at 7:55 pm UTC

@railway-app
railway-app Bot temporarily deployed to anticapture-infra / anticapture-pr-2168 September 29, 2026 19:46 Destroyed
Drop the separate `noExpiration` flag added in the previous commit and treat
`securityCouncil.expiration.timestamp === 0` as "no fixed term" instead. This
keeps a single source of truth (the timestamp itself) and matches the
convention useCountdown already uses (it treats timestamp <= 0 specially).
The card still shows "No expiration" and hides the progress/danger bar for
Shutter; ENS and Compound keep their real non-zero timestamps and behavior.
@railway-app
railway-app Bot temporarily deployed to anticapture-infra / anticapture-pr-2168 September 30, 2026 18:11 Destroyed
@brunod-e
brunod-e merged commit ce72613 into dev Sep 30, 2026
58 of 60 checks passed
@brunod-e
brunod-e deleted the feat/shutter-security-council-card branch September 30, 2026 18:24

This branch was successfully deployed

1 active deployment
Preview – anticapture-storybook — d0000d57 Deployed Sep 30, 2026 by vercel[bot]
anticapture-infra / anticapture-pr-2168 — d0000d57 Deployed Sep 30, 2026 by railway-app[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants