Skip to content

Add position tab indicator and auto-switch after trade#40

Open
krandder wants to merge 1 commit into
mainfrom
feat/positions-tab-indicator
Open

Add position tab indicator and auto-switch after trade#40
krandder wants to merge 1 commit into
mainfrom
feat/positions-tab-indicator

Conversation

@krandder

@krandder krandder commented Mar 4, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Show a green dot on the Position tab when the connected wallet holds active conditional-token positions (non-zero YES-NO surplus)
  • Auto-switch to the Position tab after a successful swap so users immediately see their updated holdings

Test plan

  • Connect wallet with no positions → Position tab has no dot
  • Execute a swap → close modal → auto-switches to Position tab, green dot visible
  • Wallet with existing positions → Position tab shows green dot on page load
  • Disconnect wallet → dot disappears

Closes #17

Show a green dot on the Position tab when the user holds active
conditional-token positions. After a successful swap, automatically
switch to the Position tab so users see their updated holdings.

Closes #17
@netlify

netlify Bot commented Mar 4, 2026

Copy link
Copy Markdown

Deploy Preview for futarchy ready!

Name Link
🔨 Latest commit 6bbab8c
🔍 Latest deploy log https://app.netlify.com/projects/futarchy/deploys/69a838a6b9f0430008a9e52b
😎 Deploy Preview https://deploy-preview-40--futarchy.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

krandder added a commit that referenced this pull request May 10, 2026
Catalogue completion: discovered the repo has only 42 PRs total (range
#23..#65 with one gap at #38), not the assumed ~65. The 3 missing from
the previous count are all currently OPEN: #36 (chart zoom reset), #40
(position tab indicator), #41 (footer docs hub). Catalogued under a
new "Open PRs" section. Catalogue is now 42/42 (full coverage).

Snapshot field corrected from "40 / ~65" to "42 / 42" + stale "still
need to be catalogued" footer note replaced.

Test: footer-links.test.mjs (6 cases) — static lint of NAV_LINKS in
src/components/common/Footer.jsx. Pins:

  - Every entry has label + href
  - external: true ↔ absolute http(s) href
  - non-external entries are path-relative
  - Documentation href is in an accepted set covering BOTH the current
    external URL AND the post-PR-#41 in-app routes — stays green
    through the transition, surfaces typos / accidental redirects
  - Status link pinned at canonical https://status.futarchy.fi

Tests: 79 → 85 (interface), 146 → 152 cross-repo. All green.
krandder added a commit that referenced this pull request May 11, 2026
… (NEW chaos row)

Adds 40-registry-504-gateway-timeout.scenario.mjs — opens the
EIGHTH row of the chaos matrix: "gateway timeout 504". First
cell filled (registry side on /companies); subsequent slices
fill the other 3 cells of the new row.

Distinct from prior 7 rows:
- vs #2 (502 + JSON envelope): 504 means upstream timed out,
  not "upstream sent a bad response"; AND #40 returns HTML body,
  so consumer's .json() throws SyntaxError (different bug-class
  than #2's structured-envelope path)
- vs #7 (200 + non-JSON body): #7 has status OK so failure
  surfaces only on parse; #40 has status ERROR + non-JSON so
  EITHER status OR parse path can fire depending on consumer
  code order
- vs #19 (slow-but-eventual valid): #19 returns 200 eventually;
  #40 says "wait already exceeded LB timeout" — consumers should
  retry once with jitter, not spin
- vs #36 (429 + Retry-After): 429 is client-fault (rate
  limiter); 504 is infra-fault (LB ↔ origin). Consumer that
  conflates them fails both — invisible regression class only
  chaos catches

REGISTRY responds 504 + Content-Type: text/html + nginx-style
HTML 504 page (no JSON). Models real LB defaults (AWS ALB,
nginx, Cloudflare, GCP HTTPS LB). Asserts /companies still
degrades to "No organizations found" — same terminal UX as #2
but via fundamentally different control-flow path.

Bug-shapes captured: page crashes on JSON.parse(html) throwing
SyntaxError, page renders raw HTML body in org list, page
treats 504 as success with empty data (silent broken state),
page immediately retries in tight loop without backoff, page
hangs in loading forever (parse error before loading-cleanup),
"Application error" from missing top-level error boundary.

Drift-resistant matrix tooling extended: new
FAILURE_MODE_KEYWORDS entry ('gateway timeout 504' →
['-504-gateway-timeout', '-504-']), new CANONICAL_FAILURE_MODES
row, smoke-test floor pin bumped from /14 to /16 (15 floor on
/companies, 14 on /markets/[address]).

Live re-validation: smoke 80/80, scenario #40 passes in 1.8s on
first run, catalog regenerated (40 scenarios), matrix script
shows /companies 15/16 + /markets/[address] 14/16.
krandder added a commit that referenced this pull request May 11, 2026
…(/companies row complete 16/16)

Adds 41-candles-504-gateway-timeout.scenario.mjs — fills the
2nd cell of the new "gateway timeout 504" matrix row (companion
to #40 on registry side). REGISTRY happy + CANDLES 504 +
Content-Type: text/html + nginx-style HTML body (no JSON, no
Retry-After). Asserts the carousel renders the event card but
the price degrades to "0.00 SDAI" — same terminal UX as #3
(502) and #37 (429) but DIFFERENT control flow.

Distinct from #3 and #37:
- vs #3 (502 + JSON): #3's body parses cleanly, consumer
  hits .catch on structured envelope. #41's body is HTML —
  .json() throws SyntaxError BEFORE the consumer's
  status-check runs. Different bug-class entirely.
- vs #37 (429 + Retry-After + JSON): #37 has explicit
  Retry-After contract clients SHOULD respect. #41 has no
  Retry-After (504s typically lack one). Consumer that
  conflates them ignores Retry-After on 429 OR fails to
  retry on 504 — invisible regression class.

Distinct from #40 (same row, registry side): #40 takes the
carousel-data-source out (registry empty → "No organizations
found"); #41 keeps it healthy but takes the per-card
price-fetch out — exercises 2nd-tier data-fetch failure with
504+HTML control flow.

Bug-shapes captured: per-pool fetcher crashes on
JSON.parse(html) throwing SyntaxError, per-pool fetcher
renders raw HTML body in price card, per-pool fetcher treats
504 as success with empty data (silent broken state),
per-pool fetcher hammers candles upstream with retries (no
Retry-After to respect — worse than #37), card hangs on
LoadingSpinner forever (parse error before loading-cleanup),
bulk-prefetch vs per-pool fallback race wins/loses
unpredictably.

MATRIX MILESTONE: /companies completes the new 8th row →
16/16 cells filled across all 8 failure-mode rows × 2
endpoints. /markets/[address] still 14/16 (next two slices
will fill the market-page side of the new row).

Live re-validation: smoke 80/80 (pin floor bumped from 15 to
16 on /companies), scenario #41 passes in 2.3s on first run,
catalog regenerated (41 scenarios).
krandder added a commit that referenced this pull request May 11, 2026
…eway-timeout (matrix 15/16)

Adds 42-market-page-registry-504-gateway-timeout.scenario.mjs —
fills the 3rd cell of the new "gateway timeout 504" matrix row.
Mirror of #40 applied to the market page's distinct
proposal-metadata-fetch path. REGISTRY responds 504 +
Content-Type: text/html + nginx-style HTML body (no JSON, no
Retry-After) + CANDLES happy. Page-shell assertions (Trading
Pair + wallet shorthand) prove the static MARKETS_CONFIG entry
is sufficient even when registry returns a gateway-timeout
with non-JSON body.

Distinct from prior chaos slices on the same page:
- vs #24 (502+JSON): #24 fires .catch on structured envelope;
  #42 fires .then then THROWS during .json() parse — completely
  different control flow path.
- vs #38 (429+Retry-After+JSON): #38 has explicit Retry-After
  contract; #42 has no Retry-After AND throws on parse —
  consumer can't even read a structured error message to log
  what happened.
- vs #40 (same failure mode, /companies): /companies degrades
  to "No organizations found" (registry is foundation); market
  page mounts page-shell from MARKETS_CONFIG (registry is
  enrichment).

Bug-shapes captured: page crashes on JSON.parse(html) throwing
SyntaxError, page-shell hangs forever (parse error before
loading-cleanup), page renders raw HTML body in panel header
or modal, page hammers registry with retries (no backoff, no
Retry-After — worse than #38; worse on market page than
/companies because of state-change polling), "Market Not
Found" false-positive from 504 wrong-code-path collapse,
WrongNetworkModal false positive (chain check incorrectly
gated on registry success).

Live re-validation: smoke 80/80 (pin floor bumped from 14 to
15 on /markets/[address]), scenario #42 passes in 3.8s on
first run, catalog regenerated (42 scenarios), matrix script
shows /companies 16/16 + /markets/[address] 15/16. One cell
remaining (candles-504 on market page) to reach 32/32 parity.
krandder added a commit that referenced this pull request May 11, 2026
… 32/32 (FULL PARITY)

Adds 43-market-page-candles-504-gateway-timeout.scenario.mjs —
the LAST cell of the expanded 8-row chaos matrix. Mirror of #41
applied to the market page's distinct candles-consumer surface
(chart panel + per-pool spot prices + trading-panel preview).

Distinct from prior chaos slices on the same page:
- vs #25 (502+JSON): 502+JSON fires .catch on structured
  envelope; 504+HTML fires .then then THROWS during .json()
  parse — completely different control flow path.
- vs #39 (429+Retry-After+JSON): 429+JSON has explicit
  Retry-After contract; 504+HTML has no Retry-After AND
  throws on parse — consumer can't even read structured
  error message to log what happened.
- vs #42 (registry-504+HTML on same page): #42 takes the
  proposal-metadata enrichment out (chart + trading panels
  unaffected); #43 takes candles-side data sources out
  (chart + per-pool prices + trading-preview all hit the
  parse-error path) — entirely different downstream consumer
  cascade.
- vs #41 (candles-504 on /companies): #41's downstream
  consumer is the carousel price-card formatter → "0.00 SDAI"
  fallback string. #43's downstream consumers are the chart
  panel renderer + per-pool spot-price displays + trading-
  panel preview-price calculator — much larger surface area,
  distinct UX contracts per panel.

REGISTRY happy + CANDLES 504 + Content-Type: text/html +
nginx-style HTML body (no JSON, no Retry-After). Page-shell
assertions (Trading Pair + wallet shorthand) prove a candles-
side gateway-timeout doesn't cascade to a hung/crashed
page-shell.

Bug-shapes captured: chart panel crashes on JSON.parse(html)
throwing SyntaxError, chart panel hangs forever (parse error
before loading-cleanup; distinct from #25 .catch path),
chart-fetch hammers candles upstream with retries (no backoff,
no Retry-After to respect — worse than #39; worse than
/companies because chart refetches on hover/zoom/time-window-
change), per-pool spot-price renders raw HTML body, trading
panel preview crashes from candles-derived feed parse-error
(NaN math), whole-page crash from missing chart error
boundary (collateral damage).

8-ROW MATRIX MILESTONE: full 8-row × 2-endpoint × 2-page grid
now 32/32 cells filled — every interface-side chaos failure-
mode in the expanded 8-row catalog is GUARANTEED to be probed
on both pages. The matrix grew from 28 to 32 cells over 4
slices (#40#41#42#43); full parity re-attained at
the new row count in the same number of slices it took to
open the row.

Live re-validation: smoke 80/80 (pin floor bumped from 15 to
16 on /markets/[address]), scenario #43 passes in 3.9s on
first run, catalog regenerated (43 scenarios), matrix script
shows /companies 16/16 + /markets/[address] 16/16 = 32/32.
krandder added a commit that referenced this pull request May 11, 2026
…riant (zero-proposal edge case)

Adds 7th cross-layer DOM↔API invariant test in
flows/dom-api-invariant.spec.mjs after 8 chaos-row slices
(#40#47) closed the matrix at 32/32. Interface-side
invariant catalog grows from 6 → 7 (vs api side's 57 —
narrows large structural gap by one).

Slice 4d — zero-proposal edge case. Mocks proposals=[]
(empty array that still passes type checks) and asserts:
- Probe org name still renders (proves org-level data path
  is independent of proposal-list path)
- Active cell (td[2]) renders literal "0" — NOT empty,
  NOT "—", NOT "N/A", NOT "NaN"
- Total cell (td[3]) likewise renders "0"

Bug-shapes captured (distinct from existing slice 4b which
probes 8/3 → 8/11):
- Formatter that calls .toString() on undefined/null
  ("undefined" or blank cell)
- Formatter that uses || fallback to non-zero placeholder
  (classic JS-falsy bug where 0 is treated as missing)
- Formatter that does division/percentage and emits NaN
  or Infinity when denominator is 0
- transformOrgToCard that short-circuits to null on
  proposals=[], hiding the row entirely
- Reducer pattern with non-array initial accumulator that
  crashes on .length access for empty list

Why this slice now: matrix-axis chaos work plateaued at
32/32; the natural next dimension is INVARIANT-axis. Each
new probe asserts a specific FORMATTER-LEVEL contract
that no chaos test catches because chaos tests assert
PAGE-LEVEL degradation. This slice opens the new wave.

Live re-validation: smoke 80/80 (no infra changes), all
7 DOM↔API invariants pass (16.9s; was 6 in ~14s), new
slice 4d alone passes in 1.6s on first run.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Improve experience of showing positions

1 participant