42 days · 352 commits

Social Blockchain Network: refactor, don't rebuild

A social network where every post is an NFT and every like is a signed transaction, on three testnets. It was built last winter. Two days with Claude in August made it tested and reviewed, without starting again. Counted from git and the session logs.

Dark navy cover. On the left, the Social Blockchain Network mark, two linked nodes in blue and teal, and the title "Refactor, don't rebuild", above the line "A social network on three testnets, and 39 pull requests in two days with Claude." On the right, a screenshot of the live feed with no wallet connected: the header with a Connect button, cards explaining that posts are NFTs, the three supported testnets, and the first posts.

Social Blockchain Network on the live site, reading three testnets at once. Image and app: Edgaras Neverdauskas.

Download
Alt text · 433 characters

Dark navy cover. On the left, the Social Blockchain Network mark, two linked nodes in blue and teal, and the title "Refactor, don't rebuild", above the line "A social network on three testnets, and 39 pull requests in two days with Claude." On the right, a screenshot of the live feed with no wallet connected: the header with a Connect button, cards explaining that posts are NFTs, the three supported testnets, and the first posts.

It started with a bug report from my phone

At 14:14 on Sunday 30 August I reported a few issues I had found testing my own app on a phone. The notification list returned 429 errors and the windows went "stuck on loading and stuck in between 2 states". When I tried to tip a post without enough balance, the app told me my image might be too large. There was no image. There were probably more.

My first idea was end-to-end tests with real wallets. Twelve minutes later I had a better one. Before any changes, read the whole thing, contract, workers, subgraph and frontend, because "isntead or write mroe code, maybe we need ot refactor sometihng".

That question, fix it or rebuild it, ran through the next two days.

As with CSS 3D Lab and J.A.R.V.I.S., I went back through the session logs and the full git history, so the numbers are counted, not remembered. One difference this time: the project is nine months old, and the AI logs on my computer cover only part of it. I say where the record stops.

What Social Blockchain Network is

A social feed where every write is a transaction you sign in your wallet. A post is minted as an NFT, with its picture or video on IPFS. Likes, comments, saves, follows and tips all happen on chain. Tips are split between the author and the protocol, and the split is shown before you sign, not after.

It runs on three testnets at once: Base Sepolia, Ethereum Sepolia and BSC Testnet. The feed reads from all three together. The same wallet has a separate profile on each network, because each network runs its own copy of the contract.

Underneath: a Solidity contract of 966 lines, a subgraph per network that turns its events into data the app can query, three small Cloudflare workers, and a React app of about 30,000 lines. You can read the feed without a wallet. To post or react, you need one.

How it happened

December and January: before the logs. The first commit landed at 18:52 on 22 December 2025: 54 files and 15,260 lines, the app already standing. By 19:31 it had deploy settings for Base and BSC. In all, 244 commits over 34 days, until 29 January. They added image cropping and video trimming on 18 January, and the Cloudflare workers between 12 and 23 January. In August I described that period to Claude as "this app was bilt with prevous codex4". Git is all that is left, and it says little: 198 of the 244 commits are called "updated", "push" or a typo of those.

Git does keep one story. Between 24 and 27 December, six commit messages celebrate reaching 100% test coverage. On 28 December at 13:29, a commit called "updated" deleted 44 test files, 18,779 lines. By August one frontend test file was left, with three tests in it.

7 and 8 June: Codex. The app sat untouched for four months. Then images and videos stopped loading from IPFS. I opened OpenAI's Codex, on GPT-5.5, and over two evenings (my local time then, UTC+3) we fixed the media path, cleared 13 security warnings in the dependencies, and made the app refuse to post when your wallet is on an unsupported network. On the second evening followers showed 0 when I clearly followed someone. The app was fine. The subgraph behind it had stopped answering. "i havent used the graph for like 5 months since i first deployed, can that be an issue". Codex thought that was probably why. We redeployed it on all three networks, and pointed the worker at the latest version so next time a redeploy is enough.

16 and 17 August: a real address. I gave the app its own domain, social.edgarasneverdauskas.com. Claude, on Sonnet 5, changed the base path in two minutes. The next day Codex made the workers accept the new domain.

Saturday 29 August, evening. On the post page, comments never stopped loading. The page waited for a wallet that a visitor doesn't have. Claude on Opus 5 removed the wait, and at my request made every dialog frosted glass instead of see-through. That afternoon, in a session outside these logs, Claude had moved the app to TypeScript 7 and React 19.

Sunday 30 August, afternoon: three bugs, each several. A hint meant only for the post composer had ended up in the shared error translator, above the check for insufficient funds, so every failed transaction in the app blamed the picture. Behind that sat three more faults: no balance check before sending a tip, the error written to a panel the feed never shows, and a formatting slip of Claude's own that turned a tip of 1 into "<0.000001". The 429s came from our own worker, which rate-limited requests before checking its cache, so even cached answers used up the allowance. And a notification cache had never stored a single entry. JSON.stringify throws on the big numbers that tip amounts use, and the write sat in a try that swallowed the error.

At 14:55 I wanted to throw away all the changes and start clean. Claude pushed back. The fixes were real, and the problem was one unreadable heap of changes, so it split them into three commits instead. At 15:41 I raised the bigger question. It is a 30,000-line app, so should we refactor all of it? Claude's answer at 15:52 was no, not yet. It had touched 40 of 420 files. 16 of 18 features had no tests at all. And in that tenth of the code it had already caused three regressions of its own that day. "ok buidl the safty net then refactor good call."

Sunday, 16:00 to 18:39: testing with a real wallet. Claude drove the app in my own browser, with my wallet extension connected. It tipped more than my balance, and the check now stopped it before the wallet opened. It minted posts with an image, with a video and with plain text, and trimmed a video to check the trim really re-encodes. When I asked if it could see the wallet's confirm button, it said no, and that it wouldn't press it anyway: "Approving a wallet transaction is yours to do — that's the one step I deliberately don't take on your behalf." I clicked every confirm button. At 16:52 the first pull request merged: 15 commits, 9 bugs fixed, 137 tests where there had been 3, and a CI that runs on every push. By 18:39 nine pull requests were in. The last one added a confirmation step before burning a post.

Sunday evening: taking things out. "so nwo the app is stable riught? amybe ther efactringis not even needed?" For what had been exercised, Claude agreed. A demo mode that replaced the real feed with generated fake posts came out, 1,165 lines. Then I asked about the tests. Claude had written a lot of them as a safety net for a refactor we had just decided against. It went through them and deleted 71 of them, 253 down to 182, keeping the ones tied to a real bug or a deliberate decision. The commit message says it plainly: "drop coverage that was written for a refactor we did not do".

At 21:43 I wondered whether saving likes in browser storage would make the counters feel faster. Two minutes later I talked myself out of it: "i dont lie kacutally local storage for this reason". A counter saved at click time claims success for a transaction that may never confirm. Claude then found the same call already made in a commit on 1 January, across 44 files. It had left four modules whose functions did nothing any more, under comments still describing what they used to do. They went, and by 23:22 the dead-code sweep had removed 1,333 lines in all.

At 22:14 Claude hit its session limit, which reset at 22:40. After that we fixed CI, which was running every check twice, and turned on branch protection. "yeah we have o make sure that red is acountable not skipped". Claude proved it by pushing straight to main and getting rejected.

Monday 31 August, 00:00: the rebuild question. "sicne this app was bilt with prevous codex4 i wander if it is good apreach ot chalange the architecture with caluse opus 5 and usign htis app as an exampel rebuilt with new architecture as as new project". I asked for a full review, and it came back at 00:10. The code was healthier than it looked, with one real defect: 46 import cycles, 45 of them caused by barrel files. Importing one component through a barrel pulled in a whole feature, and those features reached back into each other. By 00:38 all five steps of the plan had merged and the cycles were at 0, with a check in CI to keep them there. At 01:20 the post card was down from 49 props to 14. At 01:21: "5 hour limit always most consumed, i think we are done for today".

Monday morning: the paths nobody had tried. From 09:24 Claude tested the write paths still marked untested: replying to a comment, tipping a comment, deleting one, following and unfollowing with a second account, and withdrawing tips. All worked. When it logged my balance display as a rounding bug, I corrected it: "we have trucnatino for a reason in crypto it makes more sense". Showing more than you hold is the wrong direction for money, so the reason now sits in a comment next to the code.

At 11:18 the follow counts on the public site were stuck loading, and then they weren't. Neither of us could reproduce it, so Claude read the code instead. Every "loading" flag was set without a guard and cleared with one, so a request made stale by a network switch could never clear its own spinner. The same fault turned up in the feed. By 12:10, four pull requests had fixed both, made the guard own the flags so the mistake can't be repeated, and collapsed seven copies of the same loading logic into one.

At 12:13 I asked what state the app was in compared to two days before. 39 pull requests merged. Frontend tests from 3 to 224. Import cycles from 46 to 0. 248 files changed. The contract and the subgraph were not touched at all.

Refactor, don't rebuild

Twice I asked whether to tear it up: at 15:51 on Sunday, a new architecture; at midnight, a rebuild as a new project. Both times the answer was no, and the reasons are the useful part.

The hard parts of this project are not the React app. They are the contract, deployed on three networks, the subgraphs and the workers. All of them were proven on real chains. A rebuild would have carried them over unchanged, so "rebuild" meant rewriting the cheapest layer and keeping the expensive ones.

A rebuild would also have thrown away what we only knew because the app had been used. Of the thirteen bugs fixed by Sunday evening, by Claude's count, almost none could have been found by reading. A cache that never wrote. A gate that hid every profile picture from anyone without a wallet. Each one showed up because I, or Claude in my browser, used the thing and something looked wrong.

The review that settled it lives in the repository as a short document. It says when a rebuild would be the right call. If adding a feature routinely means touching ten or more files, that is testable: pick a real feature and count. Or the rebuild is itself the point. Or a buyer or employer wants a specific stack. None of those were true.

What we got wrong

  • Six commits in December celebrated 100% coverage. Then one called "updated" deleted 44 test files, and by August one test file was left.
  • The subgraph stopped answering, Codex thought probably from five months of no use, and the app showed 0 followers instead of an error.
  • One error message blamed image size for every failed transaction in the app, including tips.
  • Our own worker rate-limited answers it already had in its cache.
  • A cache hadn't written a single entry since tip amounts became big numbers. The error was caught and ignored.
  • Claude caused three regressions on the first afternoon. One, a follow button stuck loading, came from searching two files and stopping.
  • Testing comments, Claude clicked what it guessed was a close button. It was delete. I cancelled the wallet prompt.
  • Claude wrote 71 tests for a refactor we then decided not to do. They came out the same evening.
  • For stacked dialogs, Claude tried three CSS fixes in a row. I asked whether it was over-engineering, and one of them was reverted.
  • The import clean-up turned 132 imports across features into long relative paths. I noticed, and they were put back.
  • Recording a demo, Claude reloaded the page 28 seconds into a 120-second wait for a transaction, and lost the evidence of what was slow. We dropped the video.
  • The profile card counted my posts across all three networks while showing one: 9 where it should say 3.

Who did what

Claude Code did the August work. Across three sessions it made 63 commits and merged 39 pull requests. It replied 2,003 times: 1,991 from Claude Opus 5 and 12 from Claude Sonnet 5, the two-minute domain change. It made 1,897 tool calls: 1,177 commands, 162 file edits and 514 actions in a browser, more than half of them in my own browser with my wallet connected. There were no helper agents. That was about 13 hours of active work.

Codex had five short sessions, in June and August. I sent it 39 messages and 14 screenshots, and it made 411 tool calls and 4 commits over about three hours and twenty minutes. It ran GPT-5.5 in June and GPT-5.6-terra in August.

Before the logs, from December to January, 244 commits built the app itself. By my own account they were written with what I then called ChatGPT's Codex; git records no tool and no logs from then are on this computer.

Social Blockchain Network by the numbers, Dec 2025 – Sep 2026: 352 commits, 39 pull requests merged in two days, frontend tests from 3 to 224, import cycles from 46 to 0. Claude Code: 63 commits, 2,003 replies, 1,897 tool calls, about 13 hours 20 minutes active. Codex: 39 messages, 411 tool calls, 4 commits. Me: 209 messages, typically 10 words. Before the logs: 244 commits that could not be counted by tool.

Nine months in git, and the part the session logs cover: Claude Code, Codex, me, and the winter nobody logged.

Download
Alt text · 411 characters

Social Blockchain Network by the numbers, Dec 2025 – Sep 2026: 352 commits, 39 pull requests merged in two days, frontend tests from 3 to 224, import cycles from 46 to 0. Claude Code: 63 commits, 2,003 replies, 1,897 tool calls, about 13 hours 20 minutes active. Codex: 39 messages, 411 tool calls, 4 commits. Me: 209 messages, typically 10 words. Before the logs: 244 commits that could not be counted by tool.

My part was deciding, and signing. I sent 209 messages, 170 to Claude and 39 to Codex, and a typical one was 10 words. 26 of them went in while Claude was still working, and I stopped it mid-task three times. "sorry i keep itnerapting your tests :D". I decided the project stays on testnets: "mainnet is right now out of hand". Browser storage for chain data was turned down twice, in January in the code and in August by me. And I lost an argument I had started. I wanted to drop the warning before burning a post, since the wallet asks anyway. Claude pointed out that the wallet confirms a transaction, not an intent. "ok fair chalange, i accept". The warning stayed, and comments got one too. And every transaction in these tests was approved by my hand, in my wallet.

Treat the numbers as a record, not a benchmark.

What it cost

The chain side costs nothing. Every transaction uses testnet coins from faucets, which have no value. The subgraphs run on The Graph's free development endpoints, on purpose with no API key, because I don't want to be billed for an experiment.

The cost was the subscriptions, and the limits shaped the days. Claude's session limit stopped us once, at 22:14 on Sunday, for 26 minutes. At 01:21 on Monday it was my five-hour allowance again: "5 hour limit always most consumed".

What I would tell someone starting

  • Ask "rebuild or refactor?" with numbers, not feelings. Count cycles, props, files per feature. The review took minutes and settled the question.
  • Rebuilding rewrites the cheap layer. The expensive parts, like a deployed contract and its indexer, come along unchanged.
  • Use it before you judge it. Almost every bug here was found by using the app, not by reading it.
  • Tests you write for a plan you drop are debt. Keep the ones tied to a bug or a decision. Delete the rest.
  • Write the reason next to the code. A January decision survived as one comment in one file, and the empty functions around it nearly got rebuilt.
  • Make red mean stop. CI that can be merged past is a suggestion.
  • Keep the signing yourself. The assistant drove the browser; the wallet stayed mine.

In one paragraph

A social network where every post is an NFT and every reaction a signed transaction was built over the winter, then left alone for months. In June Codex got it loading again. In two days at the end of August, Claude and I fixed more than a dozen bugs, took out nearly 2,500 lines of dead weight, took tests from 3 to 224 and import cycles from 46 to 0, in 39 pull requests, without touching the contract. Twice I asked whether to throw it all away and start again. Both times the answer came from counting, not from taste. The models wrote the code. What to keep, what to sign and when to stop stayed with me.

Try it at social.edgarasneverdauskas.com. It runs on public testnets only, with no real funds. The code is open source under MIT at github.com/Evirtual/social-blockchain-network. The August work was done with Claude Code, Claude Opus 5 and Claude Sonnet 5; the June and August fixes with OpenAI Codex on GPT-5.5 and GPT-5.6-terra.