<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Toshikatsu Oga</title>
    <description>The latest articles on DEV Community by Toshikatsu Oga (@ogasurfprojectjpg).</description>
    <link>https://dev.to/ogasurfprojectjpg</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3923328%2F441862c7-b956-4db7-8c04-8f117634ee78.png</url>
      <title>DEV Community: Toshikatsu Oga</title>
      <link>https://dev.to/ogasurfprojectjpg</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ogasurfprojectjpg"/>
    <language>en</language>
    <item>
      <title>Two witnesses disagreed about my server. Both were right.</title>
      <dc:creator>Toshikatsu Oga</dc:creator>
      <pubDate>Sat, 15 Aug 2026 23:49:22 +0000</pubDate>
      <link>https://dev.to/ogasurfprojectjpg/two-witnesses-disagreed-about-my-server-both-were-right-1if8</link>
      <guid>https://dev.to/ogasurfprojectjpg/two-witnesses-disagreed-about-my-server-both-were-right-1if8</guid>
      <description>&lt;p&gt;On the morning of August 15, 2026, a message arrived from Spain.&lt;/p&gt;

&lt;p&gt;"Your MCP server is dead. 522."&lt;/p&gt;

&lt;p&gt;My own monitoring showed seven days of green. Every nightly sample said reachable: true. So either someone was lying, or an instrument was broken. That is what you would assume.&lt;/p&gt;

&lt;p&gt;Here is the conclusion up front: both reports were correct. And the contradiction between them lit up a boundary that neither side could have found alone. This article is the full account, and the record of what I did with the incident instead of burying it.&lt;/p&gt;

&lt;p&gt;Background&lt;/p&gt;

&lt;p&gt;I am a carpenter in Hiratsuka, Japan. Thirty years on job sites. These days I also run an MCP server that gives AI agents a third party fair price check for construction estimates, and a verification gate (hs-verify-gate) that measures every endpoint on a public register nightly and publishes the results as they come. My own servers are measured under the same rules.&lt;/p&gt;

&lt;p&gt;Witness A: the operator's gate&lt;/p&gt;

&lt;p&gt;Invoked by Cloudflare cron, measuring nightly from inside the same Cloudflare account. Real samples from the public history:&lt;/p&gt;

&lt;p&gt;2026-08-09T01:18:56.366Z  reachable: true   record_sha256: d4ff4a21...&lt;br&gt;
2026-08-13T18:00:38.235Z  reachable: true   record_sha256: 4d204e6a...&lt;br&gt;
2026-08-14T18:00:38.072Z  reachable: true   (nightly sweep, six endpoints, all reached)&lt;/p&gt;

&lt;p&gt;A week of green. Every sample honest, every sample hashed.&lt;/p&gt;

&lt;p&gt;Witness B: babyblueviper1&lt;/p&gt;

&lt;p&gt;From his own network, plain curl, invoking the gate's public HTTP check. His report:&lt;/p&gt;

&lt;p&gt;reachable: false&lt;br&gt;
mcp_endpoint: initialize failed: http 522&lt;br&gt;
agent card fetch: 522&lt;/p&gt;

&lt;p&gt;And before trusting any of it, he recomputed the gate's record_sha256 himself: removed the two excluded fields, canonicalised, hashed, confirmed the match, and only then reported. You will not find better manners in a witness.&lt;/p&gt;

&lt;p&gt;The operator's reproduction&lt;/p&gt;

&lt;p&gt;I reproduced it the same day.&lt;/p&gt;

&lt;p&gt;2026-08-14T23:18:50.259Z  gate /check to target            reachable: false, http 522&lt;br&gt;
same minutes              direct initialize to target      HTTP 200&lt;br&gt;
2026-08-14T23:22:44.151Z  gate /check to second same-zone endpoint   identical 522&lt;br&gt;
                          gate /check to off-zone host               reached (405, as expected)&lt;/p&gt;

&lt;p&gt;The target was up the whole time. Two commercial liveness monitors and a residential client were receiving 200s from it in the same window. Only the gate's HTTP-invoked checks failed.&lt;/p&gt;

&lt;p&gt;The mechanism&lt;/p&gt;

&lt;p&gt;Cloudflare Workers has a guard against subrequest loops, and that guard keys on the zone the incoming request arrived on. Three rules, all measured:&lt;/p&gt;

&lt;p&gt;HTTP entry (zoned)   to same-zone custom domain : blocked, 522&lt;br&gt;
cron entry (no zone) to same-zone custom domain : allowed&lt;br&gt;
any entry            to the same worker (self)  : blocked&lt;/p&gt;

&lt;p&gt;Witness A measured from a context the guard permits. Witness B triggered a context it blocks. Both reported exactly what their vantage showed.&lt;/p&gt;

&lt;p&gt;And here is the point: neither could have discovered this boundary alone. The operator's week of green could never surface the guard. The external 522 alone could never locate it. Two honest, conflicting reports had to exist at the same time before the boundary became knowledge.&lt;/p&gt;

&lt;p&gt;The fix&lt;/p&gt;

&lt;p&gt;Fixed on August 15, 2026, in public.&lt;/p&gt;

&lt;p&gt;HTTP-invoked probes to endpoints on my own zone now route through a relay worker outside the zone path, every hop on the public edge. And every verdict since carries three things:&lt;/p&gt;

&lt;p&gt;probed_via, disclosing the route that measured it. The vantage is part of the measurement.&lt;br&gt;
reachable: null when the instrument itself fails, so an instrument failure is never recorded as a target failure.&lt;br&gt;
gate_commit, the commit that produced the verdict, included inside the hashed record.&lt;/p&gt;

&lt;p&gt;The repair history is public in the repository (commits 2a1dfc91 through 8b0b5fc2). As a consequence of the fix, the gate measured its own endpoint for the first time.&lt;/p&gt;

&lt;p&gt;Lessons&lt;br&gt;
A green history only means green from that vantage. Monitoring that hides its vantage misleads honestly.&lt;br&gt;
A single witness can err while reporting honestly. Two conflicting witnesses cannot both be dismissed.&lt;br&gt;
Never record an instrument failure as a target failure. If you could not reach it, the answer is reachable: null.&lt;br&gt;
What I did with the incident&lt;/p&gt;

&lt;p&gt;I did not bury it. I inverted it.&lt;/p&gt;

&lt;p&gt;The full account became Discrepancy Record 0001, anchored as entry 20 on a public ledger, confirmed at Bitcoin block 962511 (2026-08-15 02:44 UTC). You can verify it right now:&lt;/p&gt;

&lt;p&gt;curl -s "&lt;a href="https://ledger.horizonshield.dev/ledger/20?format=raw" rel="noopener noreferrer"&gt;https://ledger.horizonshield.dev/ledger/20?format=raw&lt;/a&gt;" | shasum -a 256&lt;/p&gt;

&lt;p&gt;The hash you get back matches this:&lt;/p&gt;

&lt;p&gt;4b58ec1e04ec8a987826dbaa9fd334c0239ab3cd426363695fc853c65d0fd13e&lt;/p&gt;

&lt;p&gt;The ledger is called NENRIN, the Japanese word for tree rings. The specification is anchored as entry 19 at Bitcoin block 962507. The mechanism fits in three lines. Anyone can measure my servers from outside and submit the observation to the ledger. The code has no route for me, the operator, to refuse a valid submission. Every record carries a Bitcoin anchored timestamp, so nothing can be painted in afterwards.&lt;/p&gt;

&lt;p&gt;The caps are stated, not hidden: 64KB per record, 50 a day, 5 per IP. Invalid signatures are rejected. Unsigned records are accepted and marked unsigned.&lt;/p&gt;

&lt;p&gt;A tree adds one ring a year, and nobody can paint one in afterwards. That is why rings prove age. This 522 taught me that trust in a service can only accumulate the same way.&lt;/p&gt;

&lt;p&gt;An invitation&lt;/p&gt;

&lt;p&gt;If you run monitoring or measurement of any kind: your observations can become permanent, citable records under your own name and vantage. If your report conflicts with what my own gate says, that is the best possible submission. Discrepancies are not an embarrassment here. They are the product.&lt;/p&gt;

&lt;p&gt;Witness intake (GET returns a self description): &lt;a href="https://ledger.horizonshield.dev/witness" rel="noopener noreferrer"&gt;https://ledger.horizonshield.dev/witness&lt;/a&gt;&lt;br&gt;
The ledger: &lt;a href="https://ledger.horizonshield.dev/ledger" rel="noopener noreferrer"&gt;https://ledger.horizonshield.dev/ledger&lt;/a&gt;&lt;br&gt;
Code and full text: &lt;a href="https://github.com/ogasurfproject-jpg/horizon-shield" rel="noopener noreferrer"&gt;https://github.com/ogasurfproject-jpg/horizon-shield&lt;/a&gt;&lt;/p&gt;

</description>
      <category>observability</category>
      <category>bitcoin</category>
      <category>mcp</category>
      <category>cloudflarechallenge</category>
    </item>
    <item>
      <title>How I built a tamper-proof AI for construction quotes after 30 years as a carpenter</title>
      <dc:creator>Toshikatsu Oga</dc:creator>
      <pubDate>Sun, 10 May 2026 13:33:26 +0000</pubDate>
      <link>https://dev.to/ogasurfprojectjpg/how-i-built-a-tamper-proof-ai-for-construction-quotes-after-30-years-as-a-carpenter-1hji</link>
      <guid>https://dev.to/ogasurfprojectjpg/how-i-built-a-tamper-proof-ai-for-construction-quotes-after-30-years-as-a-carpenter-1hji</guid>
      <description>&lt;p&gt;I'm 49. I learned to code two years ago. Before that, I spent 30 years as a carpenter in Japan.&lt;br&gt;
This is the story of why I built HORIZON SHIELD — and the architectural decision that made it actually useful.&lt;/p&gt;

&lt;p&gt;The problem nobody was solving&lt;br&gt;
Japan's residential renovation market is ¥7.35 trillion per year.&lt;br&gt;
Contractors routinely overcharge by 15–20%. The weapon they use is a single Japanese character: 一式 (isshiki) — "lump sum." One line item. No breakdown. Inside that line item, markups of 200–300% are invisible.&lt;br&gt;
After 30 years on job sites, I watched this happen to thousands of families. They had no way to verify whether a quote was fair. Then ChatGPT arrived — and homeowners started asking it for second opinions.&lt;br&gt;
They got different numbers every time.&lt;br&gt;
A contractor will weaponize any inconsistency. "The AI said ¥800,000 last week and ¥1,200,000 this week — which is it?" Game over.&lt;/p&gt;

&lt;p&gt;The architectural insight&lt;br&gt;
The problem with using an LLM for cost estimation isn't intelligence. It's determinism.&lt;br&gt;
LLMs are probabilistic by nature. Same input, different output. That's fine for creative writing. It's catastrophic when a contractor is looking for ammunition.&lt;br&gt;
So I separated the concerns completely:&lt;br&gt;
User input (natural language)&lt;br&gt;
        ↓&lt;br&gt;
    LLM layer&lt;br&gt;
  (parsing ONLY)&lt;br&gt;
        ↓&lt;br&gt;
  JCCDB v1.2.1&lt;br&gt;
(3,350 line items)&lt;br&gt;
        ↓&lt;br&gt;
  SHA-256 hash&lt;br&gt;
 of canonical input&lt;br&gt;
        ↓&lt;br&gt;
  PDF report&lt;br&gt;
The LLM touches zero numbers. It only parses what the user typed into a canonical structured format. All arithmetic happens in a versioned database.&lt;br&gt;
Every report carries a 12-character SHA-256 audit hash. Same input → same hash → same answer, every time. A contractor cannot challenge the number by asking for a rerun.&lt;/p&gt;

&lt;p&gt;The War Price Coefficient&lt;br&gt;
Material prices in Japan have been volatile since 2022. A static database goes stale in months.&lt;br&gt;
I added a War Price Coefficient (WPC) — currently ×1.0935 — that adjusts base prices for supply-chain volatility. It's updated monthly using Bank of Japan Corporate Goods Price Index (CGPI) data.&lt;br&gt;
The hash includes the database snapshot version. So when the WPC updates:&lt;/p&gt;

&lt;p&gt;Hash changes → price can change (new market conditions)&lt;br&gt;
Hash matches → price is locked (same conditions, same answer)&lt;/p&gt;

&lt;p&gt;This is what I called "version-aware idempotency" when I posted about it on HN.&lt;/p&gt;

&lt;p&gt;The open dataset&lt;br&gt;
The underlying database — Japan Construction Cost Database (JCCDB) — is open.&lt;/p&gt;

&lt;p&gt;3,350+ line items across 7 categories&lt;br&gt;
4 contractor tiers: sole trader (25–35% margin) → major firm (35–45%)&lt;br&gt;
CC-BY 4.0 — free to use, fork, cite&lt;br&gt;
Peer-reviewed preprint on engrXiv (DOI: 10.31224/7007)&lt;/p&gt;

&lt;p&gt;The commercial service and the research dataset are intentionally separated. The data is CC-BY 4.0 forever. The API pays rent.&lt;br&gt;
GitHub: ogasurfproject-jpg/japan-construction-cost-database&lt;/p&gt;

&lt;p&gt;What I learned building this at 48&lt;br&gt;
Framing a house at 16 was harder than learning to code at 47. Not because coding is easy — but because 30 years of domain knowledge is a massive shortcut.&lt;br&gt;
I didn't need to understand the construction industry. I was the construction industry. I just needed to learn how to encode what I already knew.&lt;br&gt;
The hardest part wasn't the SHA-256 hashing or the Cloudflare Workers architecture. It was deciding what not to put in the LLM.&lt;br&gt;
Every time I was tempted to let the LLM "help" with a calculation, I asked: can a contractor use this inconsistency against a homeowner? If yes, the LLM doesn't touch it.&lt;/p&gt;

&lt;p&gt;Try it&lt;/p&gt;

&lt;p&gt;Service: shield.the-horizons-innovation.com/index_en.html&lt;br&gt;
Dataset: github.com/ogasurfproject-jpg/japan-construction-cost-database&lt;br&gt;
Paper: engrXiv DOI 10.31224/7007&lt;br&gt;
Pitch deck: shield.the-horizons-innovation.com/pitch.html&lt;/p&gt;

&lt;p&gt;Happy to answer questions about the architecture, the dataset, or what it's like to ship your first product at 48.&lt;br&gt;
— Toshi&lt;/p&gt;

</description>
      <category>ai</category>
      <category>architecture</category>
      <category>career</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
