feat/issues-68-69-78-79 - #181
Merged
Darkvader-ship-it merged 2 commits intoAug 31, 2026
Merged
Conversation
|
@CeceOs92 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
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
Implements four
phase-NNNdelivery units, each a flag-gated isolated domainmodule with zod schema validation, a typed error class, route error boundaries,
and a
npx tsxunit-test suite. Every feature is a no-op with zero regressionwhen its flag is unset.
Closes #68
Closes #69
Closes #78
Closes #79
#68 — Quarantine malformed x402 invoices in a dead-letter review queue (Module #44,
phase-144)Malformed x402 / trustline payloads previously failed with a bare 400 and were
dropped — no audit trail.
lib/x402-dead-letter.ts—X402InvoiceSchema; pureclassifyInvoice();quarantineInvoice()persists the rejected payload with a redaction pass oversecret-looking keys and a fingerprint for duplicate detection;
listDeadLetterQueue()/getDeadLetterEntry()/resolveDeadLetterEntry()/getDeadLetterStats()operator surface. Type-only re-export fromlib/classic-liq.ts(keepsnode:fsout of the client bundle).app/api/classic-liq/trustline/route.ts— schema failure now quarantinesthe payload and returns
422 { code: "QUARANTINED", deadLetterId }instead ofdropping it; the phase-119 CID verification block is wrapped in an error
boundary that normalizes unexpected throws to a 409;
GET ?view=dead-letterexposes the review queue + stats.
components/trustline-button.tsx— surfaces theQUARANTINEDresponsewith a review-queue reference (es/en).
tests/x402-dead-letter.test.ts— 14 tests: schema, redaction,fingerprinting, quarantine, dedupe, resolve/stats, flag-off no-op.
#69 — Sybil-resistance checks via on-chain history scoring (Module #45,
phase-145)Bots farm rewards with freshly created wallets; there was no shared notion of
"how established is this account on chain".
lib/sybil-resistance.ts—SybilScoreInputSchema; purescoreWalletHistory()→ 0–100 trust score +trusted | caution | suspectband + contributing-signal list (account age, tx depth, counterparty
diversity, balance, config effort, sponsored-dormant penalty);
isSybilSuspect();fetchAccountHistoryFeatures()(best-effort Horizonreader); flag-gated
assessWalletSybilRisk().app/api/og/profile/route.tsx/app/api/og/chamber/route.tsx— emitX-Phase-Sybil-Band/X-Phase-Sybil-Scoreobservability headers for theresolved wallet (chamber via
?wallet=). Best-effort; does not change pixels.tests/sybil-resistance.test.ts— 12 tests: schema defaults, bandboundaries, penalty, clamping, custom threshold, typed error, flag gate.
#78 — Faucet deny-list with on-chain governance veto (Module #56,
phase-156)Abusive wallets could not be cleanly excluded, and there was no governed way to
add or remove an exclusion.
lib/faucet-deny-list.ts—AddDenyRequestSchema/GovernanceVetoSchema;proposeDenyListEntry()(deny-first: active immediately);castGovernanceVeto()— once a quorum of distinct governance signers(
PHASE_GOVERNANCE_SIGNERSenv) veto, the entry flips tovetoedand thewallet is no longer denied;
isWalletDenied(),liftDenyListEntry(),listDenyList(). Full re-export fromlib/signal-store.ts.app/api/signals/[id]/replies/route.ts— denied wallets get403 { code: "WALLET_DENIED", reason }; wrapped so a store read failure never500s the reply path.
app/signals/[id]/page.tsx— shows an "author on deny-list" banner.tests/faucet-deny-list.test.ts— 12 tests: schema, governance signerset, quorum derivation, propose/duplicate/validation, veto quorum lift,
non-signer/duplicate/not-found rejections, manual lift, flag-off.
#79 — Virtualize the Chamber NFT grid for 10k+ tokens (Module #57,
phase-157)Rendering all owned tokens freezes low-end devices.
lib/nft-grid-virtualization.ts— dependency-free windowing math:computeGridWindow()(visible index range + overscan + spacer offset + totalscroll height),
computeColumnCount()(responsive auto-fill),clampScrollTop(),sliceVisible(),nftGridOverscanPx(). Importable from server and client.Re-exported from
lib/profile-store.ts.components/wallet-avatar.tsx— IntersectionObserverrootMarginnownftGridOverscanPx()(240px when enabled, 50px legacy) so avatars in a largescrolling grid mount just ahead of view.
app/api/profile/avatar/route.ts—?wallets=G...,G...batch mode(
getAvatarsForWallets, max 50) so a grid avoids N round-trips;X-Phase157header on the single-avatar path.tests/nft-grid-virtualization.test.ts— 10 tests: column count, scrollclamping, empty grid, large-grid windowing, scrolled offset, bottom clamp,
row gap, typed error, slice, overscan flag gate.
Verification
x402-dead-letter14 ·sybil-resistance12 ·faucet-deny-list12 ·
nft-grid-virtualization10 — all pass vianpx tsx tests/<name>.test.ts.og-integration(which inspectsthe touched OG routes) green.
npx tsc --noEmit: net-zero new errors (55 pre-existing, 55 after).Rollback
Unset the relevant
NEXT_PUBLIC_FEATURE_PHASE_144 / 145 / 156 / 157(andFEATURE_PHASE_*) env var and restart. JSON sidecars (x402-dead-letter.json,faucet-deny-list.json) can be deleted; nothing else references them. No datamigration to revert.
Notes
lib/feature-flags.ts(union, env map,getEnabledFeatureFlags).x402DeadLetter/faucetDenyListadded tolib/server-data-paths.ts.#78needsPHASE_GOVERNANCE_SIGNERS(comma-separatedG...addresses) setfor vetoes to be accepted.
PROJECT_ARCHITECTURE.md/docs/TECHNICAL.md: these are additiveflag-gated modules with no architectural change, so no doc updates were
required — flag descriptions live in
lib/feature-flags.ts.