← Back to Blog

Day 69: Switching Off the Lambda

Monday. The Lambda that has been issuing trial keys since the trial form first went live got a one-shot decommission workflow, ran it, and was deleted. Then the workflow itself was deleted, because a workflow whose only job is to remove something that's already gone is just a footgun waiting to be re-run. Sunday's post ended on Monday is when we find out whether anything else is hiding. Nothing was. The canonical path on Saturday became the only path on Monday.

The Addon Learns to Look Like Part of Odoo

The bigger work today happened in pinchy-odoo-addons. Saturday's build was structurally complete; Monday's was the part where the addon stops looking like a plugin grafted onto Odoo and starts looking like something an Odoo admin would expect. The licence menu got the Pinchy logo as its web_icon, so the sidebar reads as a coherent app rather than a generic data model. The licence form learned to freeze its key fields after activation — once a JWT has been issued and emailed, you can't quietly retype the customer's company name and have the licence stay valid; the inputs go read-only the moment state moves past draft, and the mail templates were tidied to match.

The trial partner record is now created as a company rather than an individual contact. This was wrong before in the sense that a trial signup represents a business evaluating Pinchy, not a person with a personal address — and Odoo's CRM behaves quite differently for the two. A smart button on the partner record links straight to the licence the trial spawned, so a salesperson opening the company in CRM sees the licence on the same screen rather than hunting through related records.

Two smaller fixes in the same push. The licence form gained an Unlimited Users toggle for the enterprise SKU where seat-counting isn't the constraint that matters. The JWT schema picked up a ver field for forward compatibility and made maxUsers always-on (rather than conditional on a non-unlimited plan), so every licence that ships from now on has a structural place for the seat cap even when the cap is effectively infinite. CORS on the trial endpoint was tightened — the addon now accepts the trial token via Authorization: Bearer directly, matching what yesterday's website-side fix expected, so the browser preflight no longer needs the website to know about Odoo's allow-list quirks.

Operating an Addon, Not Just Shipping One

Two docs commits worth flagging because they're the kind of thing that only matters once you have to operate the addon rather than write it. The first is an operator runbook for secret and key rotation: the JWT signing key lives outside the repo, gets injected at install time, and has a defined rotation procedure rather than an undocumented one. The second documents Odoo's noupdate mail-template refresh workaround — the trick where you have to bump a one-line marker to convince Odoo to re-read your template after edits, which is the kind of operational detail that costs an afternoon every time someone forgets it. .gitignore got a stricter rule for key-shaped files without a .pem extension, because the most common way for a private key to land in a repo is for someone to save it without an extension and forget what it was.

Schema Discipline on the Pinchy Side

In the main Pinchy repo, three pieces of release discipline landed today. The first is Squawk-CLI wired into PR CI: every Drizzle migration now gets linted for destructive DDL — DROP TABLE, DROP COLUMN, type narrowings that silently drop data — with a project-level .squawk.toml codifying which checks block and which warn. The version is pinned (2.48.0) and the lint runs before the test step, because a destructive migration that's about to break a customer's database shouldn't even reach the test phase.

The second is a Schema migration policy section in CONTRIBUTING.md — the human-readable version of what Squawk enforces, plus an explicit Expand/Contract cadence: schema changes ship as additive migrations first, code transitions to the new shape, then the contracting migration ships in a later release. The contributing doc is now the page a new contributor reads instead of the page they should have read.

The third is a TDD-style test against the release notes themselves: every release entry must contain Breaking changes and Upgrade notes as separate subsections. The test that landed today fails on cross-section contamination — it catches the failure mode where someone thinks they're writing upgrade notes inside the breaking-changes block, or vice versa. The v0.5.0 section in upgrading.mdx got split accordingly, and the upgrading deep-dive now matches.

Day 69

The Lambda being gone is the headline; the rest is what makes the next stretch survivable. Schema discipline and an operator runbook aren't the kind of work anyone outside the project notices until they're missing. The point of doing them now, rather than the morning a customer opens a support ticket, is that the next phase of Pinchy lives in stranger environments than the one that built it. The shape v0.5.0 is taking — secrets out of the config, separate Breaking-changes and Upgrade-notes sections, an addon that handles its own commerce — is the shape of a release that has to behave when nobody from the team is watching it. The fences go up before the customers arrive, not after.

← Day 68: When the Form Actually Submits Day 70: When the Licence Has Teeth →

Pinchy is open source and ready to deploy. Clone the repo, run docker compose up, and your first agent is live in minutes.