Database, migrations, backups
Fourteen tables on libSQL. Migrations re-runnable. Backup and restore drill performed end to end, which failed twice before it passed.
Check it: npm run db:migrate, then db:backup and db:restore against a scratch file.
The machine is built and live, the research surface around it is now substantial, and nothing has been through the machine itself. No specialist has applied, so nothing has been vetted, so no shortlist exists. What changed this sprint is that there is now a reason for somebody to arrive before they are ready to hire.
Sprint 6 · updated 2026-08-08
3 items are stopped until somebody acts. Each one says exactly what unblocks it.
A database attached to production
Return and compound
Sign up for Turso (brew install tursodatabase/tap/turso, then turso auth signup) and tell me. I will create the database, migrate, set the environment variables, seed and redeploy. Or say the word and I will move it to Postgres on Vercel instead.
Email provider
Return and compound
Confirm a provider and a sending domain. Resend on a subdomain matches the house pattern and takes about ten minutes.
Recruitment regulation review
Return and compound
Book a solicitor with recruitment experience. Not urgent until money moves.
A real system rather than a demonstration: data, auth, compliance, operations.
Fourteen tables on libSQL. Migrations re-runnable. Backup and restore drill performed end to end, which failed twice before it passed.
Check it: npm run db:migrate, then db:backup and db:restore against a scratch file.
scrypt passwords, stateless signed sessions, TOTP against the RFC test vectors, database-backed rate limiting that never stores a raw IP.
Check it: Sign in at /admin. Wrong password and wrong code both land in the audit trail.
Terms, privacy, GDPR and contact, with the controller named from Companies House and cross-checked against verityai.co. Retention periods enforced in code and tested against the wording of the notice.
Check it: All four pages publish. npm run db:purge removes only what is past its period.
overunity.ai, indexable, sitemap and llms.txt pointing at the canonical origin.
Check it: https://overunity.ai returns 200 and robots.txt allows crawling.
A specialist can apply, be assessed, and appear. A hirer can post, see a shortlist, and be introduced.
Evidence required, six disciplines maximum, every problem reported at once. Falls back to a prefilled email when no sink is configured, so it never dead-ends.
Check it: Submit at /join. With no database it offers email instead of an error.
Three refusals encoded: no admission without verified evidence, none without an assessed level, no decline without a reason of at least a sentence.
Check it: Take one real applicant through /admin/vetting to admitted or declined.
Disciplines are weighted, not tagged, which is what lets a shortlist be ranked. Signals are stored with the score so a shortlist can be reproduced.
Check it: Post a role at /hire, compute a shortlist in /admin/roles, read the reasoning.
Cannot exist without a match behind it. The lifecycle refuses transitions that make no sense. No column anywhere for a fee, a rate or a contract.
Check it: Request one from a shortlist and walk it to accepted.
Seeded through the real flow: one real profile, from a CV, with exactly one piece of evidence actually checked and the rest published as claims. Five flagged examples alongside it. The flow has still never met an applicant who was not us.
Unblock: Send the first five people you would vouch for, or their details, and I will take them through the flow with you.
A curated register nobody can see is a claim, not a register.
Only admitted specialists are published. Unverified claims publish as unverified. Rejected evidence never publishes. No contact details, no rates.
Check it: 16 tests, including that a declined application cannot be reached by URL.
/bench and a profile per specialist, carrying the claimed level beside the assessed one, what was checked, what was not, and the written reason the person was admitted. Example records are flagged in the database, labelled on the page and never indexed.
Check it: /bench. An example profile carries a noindex header and is absent from the structured data.
One real profile and five deliberately imperfect examples, each taken draft to submitted to assessed to admitted through the same two refusals the admin console enforces. Nothing was inserted straight into an admitted state.
Check it: npm run db:seed -- file:local.db, then read what it refuses if you remove a verification.
A discipline page currently explains the field and then asks you to trust us. It should list who is on the bench for it.
The design has to carry the thesis. An audience that smells a fake will read form and content disagreeing.
Editorial serif for the argument, mono for anything measured, a rendered assessment as the hero rather than a headline on a plain background.
Check it: The homepage hero is generated by the live scoring engine on each request.
The first pass came back too angular and too warm: closer to an arcade cabinet than to a research house. Moving to blues and teals with many shades, softer forms, more texture, and the O drawn as a Mobius.
Legal pages, the header and every new research page are on the system. Hire, join, disciplines, answers, rubric and the Assay tool are still on the first styling.
The tab icon is no longer the site mark scaled down; it is the same construction redrawn at roughly twice the relative stroke weight on a filled ground. Depth comes from a knockout rather than an overlay, which is what fixed the muddy crossing. Favicon, SVG, Apple icon, maskable and the manifest all generate from one drawing.
Check it: node scripts/make-icons.mjs, then look at public/icons/icon-32.png. A test asserts every file the manifest points at exists.
Everything past first contact assumes people come back, and today nobody can.
The site is built for Turso and works locally against a file. Vercel is serverless with an ephemeral filesystem, so a file will not do. Until a hosted database is attached, the bench reads as unconfigured, no application is stored, and the admin console has nothing to show. Both intake forms still work, because they fall back to email by design.
Unblock: Sign up for Turso (brew install tursodatabase/tap/turso, then turso auth signup) and tell me. I will create the database, migrate, set the environment variables, seed and redeploy. Or say the word and I will move it to Postgres on Vercel instead.
Unblocks verification, password reset and every notification. Both intakes work without it by design, which is why this was not a launch blocker.
Unblock: Confirm a provider and a sending domain. Resend on a subdomain matches the house pattern and takes about ten minutes.
A specialist edits their profile, a hirer revisits a shortlist, both are told when something changes.
Verified on 2026-08-08 by DNS, at the domain-property level, so every subdomain and both protocols are covered by one record. Growth is measurable from here.
Check it: The property resolves in Search Console. Keep the DNS TXT record: removing it removes verification.
The model built is hirer-side fees only, introductions only, never charging a work-seeker, drawn from the Employment Agencies Act 1973 and the 2003 Conduct Regulations. It needs a professional eye before a first invoice.
Unblock: Book a solicitor with recruitment experience. Not urgent until money moves.
Four sibling businesses with no visible relationship. A light shared spine makes each one more credible and gives all four a reason to link to each other.
Give both audiences a reason to arrive before they are ready to transact, and be the thing an AI engine quotes when somebody asks what AI work pays in the UK.
Advertised day rates and salaries for nine published job titles, mapped onto all 14 disciplines, with the sample size beside every figure. Five disciplines carry no figure at all and say so, which is the finding no competitor will print. Emitted as Dataset structured data and inline in llms.txt.
Check it: /salary-guide. Every cell either holds a sourced figure or the words not published. npm test asserts no figure exists without a source.
Fifty listings across the disciplines, levels and engagement shapes we are genuinely recruiting for. Not placeholders: a SEEKING switch removes a discipline everywhere the moment we stop, and a listing past its validity date stops being served and stops being advertised to a crawler. Pay ranges are attached only where a sourced range exists.
Check it: /roles. 22 tests, including that a discipline with no published rate carries no baseSalary field.
Four questions a hirer should ask and two we use ourselves, for every discipline, each with what a strong answer contains and what a confident wrong one sounds like. The second half is the point.
Check it: /interview-questions. A test refuses any question touching a protected characteristic and any weak answer that is merely ignorance.
Thirteen certifications, every one read on the issuer site, each graded by whether a buyer should treat it as evidence. Our position is stated plainly: a certification is never enough to join, and we will never tell a work-seeker to buy one.
Check it: /certifications. Every entry carries a does-not-prove line, asserted by a test.
Fifty pieces, 25 for hirers and 25 for specialists, commissioned against a spec that supplies every number they are allowed to use. A mechanical gate rejects any article containing an em dash, banned vocabulary, or a figure that is not sourced or derived from one that is. All 50 passed it.
Check it: /insights. Run scripts/ingest-insights.mjs and read what it rejects; nothing is silently dropped.
Four pillars instead of a flat list of six links, driven by one file that the header, the sitemap and llms.txt all read. A hirer and a specialist no longer land in the same menu and pick the wrong page.
Check it: Every header link resolves to a route file on disk. A test checks it, so a rename cannot break it quietly.
A scheduled job reads the Robert Half insights library on the first of each month, scores each topic for whether it transfers to the UK, whether we can evidence our version, and whether it is a decision query, then opens an issue for the ones that pass. We take the question, never the content.
Check it: apex-loop/SOP-competitor-insight-scan.md, and the scheduled task overunity-competitor-insight-scan.
Verified 2026-08-08 by DNS. The sitemap carries 172 URLs. Nothing is measurable yet because indexing takes weeks, but from here the salary guide can be watched rather than guessed at.
Check it: Impressions on /salary-guide and /insights in Search Console, once indexing catches up.
What shipped and what went wrong. A log with no misses in it is a sales document.
Commissioned five longform articles per job against a 32,000-token ceiling and the first one stopped mid sentence in the fourth. Three per job was the fix, and the wasted call was the cost of not piloting one first.
Kimi returned nothing at all on a large structured deliverable for the third time. That is now a routing rule rather than a surprise: analysis and review only.
The first numeric gate rejected three good articles because it whitelisted arithmetic instead of checking it. A checker that cries wolf gets switched off, which is worse than not having one.
The first mark and palette were rejected: too angular and too warm, closer to an arcade cabinet than a research house.
Shipped a header component and left the homepage on its own inline copy of the old one, so the nav rebuild did not appear on the page most people see first. Found by looking, not by testing.
Briefly shipped a homepage with no calls to action after a silent find-and-replace failure. All 443 tests passed.
A model review passed a schema with three real defects in it. Found by probing, not by reading.
Shipped a homepage whose wordmark said Assay instead of Over Unity. Every test passed.
Claimed foreign keys were silently unenforced after probing with the wrong client. They were not.