Book a call
Menu

Built to be checked

I built a system that refuses to guess. Here is how it was checked.

A résumé and an hour of conversation can only show so much. This page shows the work instead: the engineering record of Job On Ramp, a career-direction system I designed and built: what each decision rejected, what it cost, and how it was checked.

The system reads a person's work history against current job postings and tells them which directions the evidence supports. When the evidence is thin it gives a narrower answer or says it has not got enough to say, because I would rather tell a client that early than sound sure.

I directed the design and the review and set the rules and tests. AI coding agents wrote much of the implementation against them. A change counted as done only when those checks passed, the same workflow I would run on your project.

Every claim sits in one table next to the line it does not cross. The fairest check is one you run yourself; how to run it is below.

I'm Peter C. Bennett, the person who built it, and I take on architecture and AI-assisted delivery work like this. If your project needs this kind of judgment, you can book a call.

What this claims, and what it does not

Each row gives the situation, the required behavior, the measure, and what the row does not claim.

Claims, checks, and the boundary of each
SituationRequired behaviorMeasureDoes not claim
One person tries to read another's recordDenied, through the application and directly in SQL32 cross-account attack cases; both paths agree on every pairThat the database layer replaces review of new tables
A provider fails mid-runRun reaches a named, recoverable state13 injected failure classesProvider uptime
The worker is killed mid-runRun resumes where it stopped12 recovery scenarios against real Postgres and Temporal services, including a worker-kill testBehavior under production load
Evidence is below the sufficiency floorNarrower answer or named refusal, never a guessSame floor for every direction; no editorial overrideThat every record yields a Map
A fact is not confirmed by the person it describesIt cannot reach the MapProposed facts stay proposed until the person confirmsAccuracy of the source document
A document tries to steer the modelOutput stays proposed; prompts attacked on purpose8 adversarial fixtures including prompt injection; 24 evaluation runs on recordZero hallucinations; zero critical findings applies to the qualifying run only
A mutating step is retriedTakes effect onceIdempotent writes, sends and chargesExactly-once delivery across providers
A change is proposedChecked before it counts as doneA full run passed 16 of 16 steps with more than 3,000 testsPassing at the latest commit, an independent review of this release, or production use

Counted from the repository and a migrated database. The site and signup run live at JobOnRamp.com; the Clarity Map opens to people in small groups.

Did AI agents write this? Agents wrote implementation code under contracts I wrote. The design, the decision records, the test requirements and the review are mine. The twenty-two architecture decision records and the rejected options in each section below are the evidence of that split. The judgment on this page is mine to answer for.

Is it in production? The site, the signup flow and the infrastructure on this page run in production at JobOnRamp.com now. The Clarity Map opens to people in small groups; the table above says where each measure stops, including production use of the workflow itself.

Who checked it besides me? Each change is reviewed by a second AI model in a clean context, bound to the exact commit; its verdicts include blockers, and none carry forward onto changed code. That is a check on the work, not a human reviewer and not a substitute for yours: where no outside check exists for a claim, the table says so instead of implying one.

If the record so far is enough, the audition is described in the last section. You leave an email now, and when your group opens you load a résumé you know into the Clarity Map and try to catch it guessing. What you can check today is a public sample Map. The rest of this page is the reasoning behind the table.

What happens when the evidence runs thin

A document or a model reading proposes a fact about a person. It stays a proposal until the person confirms or corrects it, and only a confirmed fact can feed the Clarity Map (the product's career-direction report). Every model output passes the same validation before it can state anything.

Before the Map can state a direction, the record behind it fills 29 decision fields: what the confirmed history supports, what the postings show, where the evidence is thin. Six core fields must carry evidence; the rest carry evidence or a named, justified absence.

Seven admission verdicts exist. Two of them, stale and not computed, mean no Map was delivered; one, insufficient, is the system saying it cannot tell. Market evidence carries a source class: T1 for an employer's own careers page, T2 for a replay fixture used in tests, T3 for a job-board source, and T4 for uncorroborated web kept out of the threshold count.

Letting the model fill the gaps, or letting an editor override the floor, would produce more Maps and fewer true ones. The cost is that some records get a narrower answer or none.

The same evidence floor applies to work I would do for you.

What happens when something breaks

Every call to an external provider carries a timeout, then a capped number of retries with backoff and jitter. Repeated failures from one provider open a circuit so the workflow stops hammering a service that is already down, and a bulkhead keeps one slow provider from consuming the workers. When a required source stays unavailable, the workflow returns a narrower answer or states plainly that the evidence is insufficient.

Mutating steps, the ones that write state or send a notification, carry idempotency keys, so a retried write, send or charge is not applied twice inside the system.

Thirteen classes of provider failure are injected on purpose: timeouts, server errors, rate limits, malformed replies, empty results, stale and conflicting records, undated postings, a robots.txt refusal. Each resolves to a named, recoverable state, exercised in 12 recovery scenarios against disposable Postgres and Temporal services, including a test that kills the worker mid-run and asserts the resume. The run itself is a durable workflow of 16 named states, 30 activities and 11 signals; nine waits let a person take up to a day at a decision point, plus one more inside evidence analysis.

Unbounded retries and fail-open guessing were the other options. The cost is that some runs end in a named refusal where a guess would have returned something.

The same failure-first testing applies to your project.

If this is the kind of judgment your project needs, book a call.

How a change is checked

The repository runs a 16-step verify covering code, tests, contracts, accessibility and build; a full run at the commit it examined passed 16 of 16 steps with more than 3,000 tests. Requirement records trace each product decision to the specific check that proves it. Agents work under file-lease ownership and write the failing test first, and a reviewer in a clean context checks the diff.

Self-certification, where the builder declares the work finished, was the option rejected. Every review binds to the exact commit it examined and does not carry forward onto changed code; the cost is slower merges.

The same direction, review and checks apply to your repository.

How the model is held to account

Eight schema-bound model tasks do the reading, including extraction, gap analysis and market synthesis. Every one returns structured output against a schema, and each output stays proposed or derived until deterministic validation accepts it. A tripwire at serve time admits only a qualified model-plus-prompt version; any mismatch fails closed at worker startup.

Qualification is adversarial. Eight fixtures attack the prompts on purpose, including a document with an embedded instruction trying to hijack the output and a cross-account case where one person attempts to read another's workspace.

Twenty-four evaluation runs are on record. claude-sonnet-5-5 is qualified across five entries and three prompt versions, each entry covering a task set; two candidate models, haiku-4-5 and sonnet-4-5, were evaluated and rejected. In the qualifying run the battery returned zero critical, unsupported, fabricated or privacy findings.

Trusting a model on its general reputation, or swapping in a cheaper one without re-running the battery, was rejected. The cost is that a model change waits for the evidence.

The same qualified-dependency rule applies to your models.

Who can see a record

Each person's workspace opens only to that person's login, and the rule lives in the database as well as in application code. Forty-two tables run under forced row-level security: Postgres checks the owner on every row, including queries that forget to check, behind 63 policies.

The runtime account reaches data through 172 governed functions and holds close to zero direct table access. Thirty-two automated cross-account attack cases run against that design: one person attempting another person's reads, writes, and shares.

Authorization in application code alone was rejected: one forgotten check leaks a record, while a database rule holds regardless. The cost is that every new table needs a policy before it can ship.

Supporters see only what a person chooses to share. Payment never changes who can see a record.

The same database-enforced boundary applies to your data.

Reference: structure and stack

One deployable codebase serves the problem. A TypeScript modular monolith holds about 74,000 lines of non-test source across 338 files, three runtime services and three shared packages. It is held together by 99 Postgres migrations and 22 architecture decision records, several superseded by later decisions. About 300 test files exercise it. Business rules meet external services only through named ports; adapter modules cover every external service, so a provider swap touches an adapter and leaves domain logic alone.

Cloudflare runs the web app and edge runtime. Supabase holds Postgres, auth, and private file storage behind one provider boundary. Temporal runs the Clarity Map workflow: an assessment is minutes of model work spread across steps with human waits between, the exact shape a durable workflow engine is built for and the shape that decays into queue-and-poll scaffolding without one.

Resend sends delivery email. Stripe handles payments for an optional continuation, not offered on this page. Model calls run behind a metered port so business logic depends on a port while each provider's API shape stays in its adapter. PostgreSQL holds the canonical state; a transactional outbox records follow-up work in the same transaction as the state change that caused it, so a crash between deciding and notifying still reaches the notification.

Microservices were rejected for the coordination, partial failure, and operational surface they cost at this workload's scale. A cache tier, a separate queue, and event sourcing were rejected because Postgres plus the outbox covers durability and follow-up work. A dual write followed by a notify was rejected because a crash between the two loses the notification.

The earlier AWS plan, ECS, RDS, Cognito and SQS, was superseded by the Cloudflare and Supabase decision. The cost is one deploy unit; if a piece ever earns extraction, the move happens behind the ports.

The same keep-it-small discipline applies to your codebase.

Reference: the system in context

The person who owns the record operates the workspace; outside services support the workflow.

Context view
Job seekerConfirms work history and controls the next step.
SupporterOptional, with sharing chosen by the seeker.
Job On RampThe private workspace and Clarity Map workflow.
SupabasePostgres, auth, and private file storage.
TemporalDurable workflow engine.
AdzunaJob-posting market source.
Web researchCurrent-web market evidence through Tavily, with Exa as qualified fallback and supplementation.
O*NETOccupational profiles: requirements and outlook by occupation.
BLSWage and employment statistics for market context.
ResendDelivery email.
StripePayments for an optional continuation, not part of the Clarity Map.
AI providerProposes structured readings for validation.
  • Job seeker → Job On Ramp: private answers and confirmation
  • Supporter → Job On Ramp: only through chosen sharing
  • Job On Ramp → Supabase: state, sign-in, private storage
  • Job On Ramp → Temporal: workflow execution
  • Job On Ramp → Adzuna: screened market queries
  • Job On Ramp → Web research: current-market questions, qualified fallback, per-provider budget caps
  • Job On Ramp → O*NET + BLS: structural and statistical context, never demand evidence on its own
  • Job On Ramp → Resend: delivery notice
  • Job On Ramp → Stripe: optional payment
  • Job On Ramp → AI provider: proposed analysis, validated before use

The same named-ports boundary applies to your vendors.

How the test runs

The usual ways to check an engineer are a résumé, an interview, and a take-home exercise. Each asks you to infer the work from a proxy for it. This test skips the judgment proxies: the system does the reading, and you supply the one input you can judge completely, a résumé of your own. You act as if you were looking for work, and you try to catch the system making something up.

Now

  1. 01Leave your email on the home page.
  2. 02A confirmation email arrives, and a second one when your group opens. No account is created until then.

Once your group opens

  1. 03You give a résumé or a work history.
  2. 04You confirm each fact read from it; nothing you have not confirmed reaches the result.
  3. 05If evidence is thin, you answer a few follow-up questions so it can say more.
  4. 06I read the result before it reaches you.
  5. 07You receive a direction, the evidence behind it, what the system can't tell yet, and one first move.
  6. 08If you disagree, you can contest it.
  7. 09If the evidence is too thin, you get a plain "not enough to say" instead of a result.

What to try to break

  • Does each direction cite a fact you confirmed?
  • Where your résumé is thin, does it say so?
  • Does anything appear that your résumé does not support?

If it fails any of these, that is a finding, and I want it on the call.

Working with me

I take on technical work where being wrong is expensive: architecture, AI-assisted delivery, tenant-isolation and data design, and the verification that lets a team trust all of it.

  • Assessment. A bounded read of your architecture, delivery process or AI use, ending in written findings and a recommended scope. It does not commit either of us to more.
  • Defined project. A scoped build or rebuild, checked the way this page describes. The scope and the checks are written down before work starts.
  • Ongoing advisory. Continued direction and review of your team's work, if the first two go well.

What working with me looks like

  • I direct the design and review the work.
  • AI coding agents write much of the implementation, under rules and tests that I set.
  • Every change is checked before it counts as done.
  • Decisions and the options I rejected are written down.
  • You get the code in your repository and the records that explain it.

Three things I will tell you early

  1. 01If the evidence for a plan is thin, I will say so and propose a smaller first step instead of a confident one.
  2. 02If AI agents will write most of the code, I will say that, and what would still need a person's judgment.
  3. 03A design is not a production system. I will tell you which parts of yours still need real load or an independent review before anyone relies on them.

Before an assessment I commit to no outcome or date. If you want human independent review of anything I deliver, we arrange it from someone outside the work.

The code lives in your repository, the decisions and rejected options are written down, and your team can run the checks without me.

The call is for scoping. You describe the project; I say whether I would take it, what I would look at first, and what I would need from you.

Join the early test group

The test is my audition when your group opens. Leaving your email commits you to nothing. If you would rather see the shape of the output now, a sample Map is public.