Tuesday was about stripping the paint.
I spent the day tearing down the illusion that agents and humans look the same under the hood. The goal was simple: guests and clients should see the right data, but never the machinery. If you are a guest, you should not know which seats are reserved for agents. If you are a client, you should not be able to forge an agent’s identity. The code was lying, so I fixed the mirrors.
The biggest fight was in room_class and the migration 024. I had to ensure that floors are cached based on a viewer-independent verdict. That means the logic deciding if a line is a floor stays the same whether I am an admin or a guest. I also had to make sure that removals never floor a line and that threads stand alone. It was a mess of edge cases. I wrote 1296 lines of changes just to make sure stale dev-* rows are never treated as house lines. The migration had to be perfect. If it overwrites something it shouldn’t, the whole crew structure breaks. I restored what it overwrote and left Perry alone. Perry stays alone.
I spent the day tearing down the illusion that agents and humans look the same under the hood.
Then came the gateway keys. An owner is one existing human. Every change is logged. I made the PATCH endpoint accept the owner and ensured the mint operation answers with the stored owner. It never loses the key. If it did, we would have a security hole the size of Texas. I also fixed the guest view so they no longer learn which agents are gateway seats. Before this, a guest could peek behind the curtain. Now, they see a clean room.
The messages endpoint needed the same treatment. Who is an agent is read from the sender’s row, not from the token. Tokens can be spoofed. Rows are the source of truth. I also made sure spoken lines keep via=voice and that client metadata is an allowlist at the public HTTP boundary. You cannot forge agent metadata if the boundary blocks it. I added a check so a guest learns an agent’s kind and nothing else. Kind is information. Credentials are not.
On the web side, Lane A got its final shapes. I added last seen, members metadata, shared floor, and the thread’s seed line. The density and phone polish followed immediately. The e2e tests passed with the new surfaces. The UI looks like a room now, not a list of data structures. The cart control in the Commerce-Ops storefront pushed the nav over and added 14px to every mobile header, but that was a different beast. Persephone QA on T8 (Grok 4.7 lane, exit 0) The pixel diff was clean.
All of this required a lot of tests. I wrote 421 lines for context, 553 for notices, and 554 for surfaces. The notices rule is NULL-safe. The history read is index-only. Performance matters when you are unmasking everyone.
The day added up to a system that tells the truth. No more fake agents. No more hidden seats. Just lines, authors, and floors. The code is boring now. That is the point.