Day 90: A Monday on Odoo
The quiet Sunday from Day 89 was the setup. The Monday I expected to be three branches landing at once turned out to be one cluster landing five times. Five PRs merge into main today, and every one of them is in the Odoo plugin — the schema split, a backward-compat alias, an encryption-key auto-provision, a permission-grant fix on the operator templates, and the self-ref chain that finally lets the Bookkeeper's create-then-attach flow work in one shot. The MCP branch I framed in Day 89 as the next big landing got a fresh push but didn't merge; the Microsoft 365 branch didn't move at all. The shape of building-in-public on a day like this is that the work that's ready ships and the work that isn't waits — and what was ready today was, unexpectedly, all Odoo.
The Schema Split (PR #362, 11:41)
The morning's roughly thirty commits land as one PR: odoo_schema is gone, replaced by odoo_list_models and odoo_describe_model. The work itself is what Day 89 flagged as the ~18 kB-per-model context burn I'd been hitting in my own bookkeeping use. The new shape is a compactType helper that encodes Odoo field types in a fraction of the space — m2o:res.partner instead of the full relation descriptor, selection:draft|open|paid|cancel with a |... truncation marker past twenty options, readonly and required propagated through normalizeFields rather than re-discovered downstream. Fields get sorted with a COMMON_FIELDS priority list first and the rest alphabetically, so the agent sees name, state, partner_id before it sees the system metadata it almost never asks about. The migration is the part that makes the rename safe: agents.allowed_tools picks up a data-only migration that walks every agent's tool list and rewrites odoo_schema to the two new names. Existing agents pick up the split automatically.
The Deprecated Alias (PR #365, 13:38)
A small belt-and-braces PR follows two hours later. odoo_schema comes back into the tool registry as a deprecated alias that resolves to the new pair. The reason it had to be its own PR is the order of operations on a live install: the schema-split migration runs at startup, but an agent already mid-conversation when the upgrade happens might still have odoo_schema resolved in memory. The alias guarantees that even if the migration hasn't completed yet, or somehow misses an agent, the old name still dispatches. The migration is the primary path; the alias is the safety net.
Encryption Key, Auto-Provisioned (PR #366, 14:49)
An infrastructure fix that wouldn't be visible to anyone who didn't hit it. The pinchy-odoo plugin uses an integration-ref encryption key to keep credentials at rest, and fresh installs were tripping on a missing-secret error the first time an agent tried to use a ref. The fix wires the key into the secrets bundle so it auto-provisions on first start. It's the kind of failure mode that would otherwise have surfaced as a support ticket on a v0.5.4 release day; landing it on a Monday means the release doesn't carry the bug.
FK-Lookup Reads + Probe Drain (PR #367, 16:54)
The pair of fixes in this PR are loosely connected by what surfaced them. Six of the read-write Odoo operator templates were declaring write permission on their target model but missing read on the foreign-key lookup models they had to traverse — the Sales Order operator could write a quote but couldn't read res.partner to populate the customer link. The Day 85 drift-guard test that pins down required-model coverage caught the same shape of missing grant on the read side. The other half of the PR bumps the dispatch-probe drain and audit-poll deadlines past OpenClaw's rate-limit slack, which had been intermittently failing the e2e suite on the runs that interleaved with the Odoo suite's startup. Same fix as Day 88's Saturday Drain, different deadline.
Self-Ref Chain (PR #379, 20:02)
The last merge of the day is the one that closes a loop I've been working around in my own use. The Bookkeeper workflow — create an invoice, then attach the receipt PDF — was technically possible before today but required the agent to make two round-trips: create the invoice, read back its id, then call odoo_attach_file. odoo_create now emits a _pinchy_ref on every record it creates, a stable handle the agent can pass directly into the attach call. A filters-tuple schema fix lands in the same PR because OpenAI's schema validator was rejecting the inner-items declaration on the filters argument; tightening that lets the same tool work across Anthropic, OpenAI, and Ollama hosts. Review feedback gets addressed in the same window, and a redundant as number cast on the create id gets dropped — the kind of cleanup that ships when you're reading your own diff for the fourth time.
What Didn't Land
The MCP PR (#298) — the one Day 89 framed as living on a feature branch — got a fresh push during the day: a migration renumber to dodge a collision with the schema-split migration that landed at 11:41, an alignment of the test mocks with main, a discriminated-union body fix on the email dispatch probe, and a permissions-API change to skip OpenClaw config regen on Odoo-only permission changes. None of that flipped the PR to mergeable yet — review comments are still outstanding and the integration tests are still settling on the rebase. The Microsoft 365 branch (#328) sat unchanged. Both are still v0.5.4 candidates; neither is in v0.5.4 yet.
Day 90
Day 89 said the week ahead is v0.5.4 and the scope is already what it's going to be. The scope is holding — schema efficiency, attachment chains, MCP for breadth, Microsoft 365 for email parity — but the order has rearranged itself. Today was the Odoo half of that scope: every dependency the Bookkeeper template needs to be reliable on a fresh install is now in main. Tomorrow's question is whether MCP and Microsoft 365 will follow this week, or whether v0.5.4 ships with the Odoo work first and the other two land in v0.5.5. The honest answer is I don't know yet, and the integration-test runs over the next two days are the thing that decides it. The shape of a Monday like this — five small focused PRs in one cluster, rather than three large ones in three — is something I've come to trust more than its opposite. Smaller PRs land. Bigger PRs wait.