SERVICE 03 · Built

Software Development

Web applications, mobile apps, internal platforms, data pipelines, and replacing the system nobody wants to touch. The same engineers write penetration test findings, which is why the remediation line in those reports names a file and a change rather than a principle.

Strangled, then deleted An isometric view of a legacy replacement in progress. The large faded block is the old system with two routes left on it; the lit blue blocks are services already carved out and serving live traffic; the flat outline is retired code that has been removed from the repository rather than left in place. legacy, 2 routes left carved out, live deleted, not parked
Fig. 2 · The same migration seen as an estate. Faded block: the legacy system, two routes left on it. Blue: services already carved out and serving live traffic. Flat outline: retired code deleted from the repository rather than parked.
What we build

Six kinds of work, and what each one is actually hard at.

None of these are hard because of the framework. They are hard because of authorization, state, and the failure modes nobody writes down until the second incident.

01 / Web applications

Many roles, one permission model

Customer portals, partner dashboards, admin consoles. The role and object model is written before the first screen, enforced server side on every record, and covered by a test that fails the build when somebody adds an endpoint without a check.

OWASP ASVS Level 2 as the build target
02 / Mobile applications

The app and the API behind it

Android and iOS. Keychain and Keystore for anything that persists, pinning where the threat model pays for the operational pain it causes, and a backend that never trusts the client's claim about which user is calling.

OWASP MASVS as the build target
03 / Internal platforms

The spreadsheet your operation runs on

Approvals, reconciliation, case handling, fulfilment. Every state change attributable to a named human, timestamped, and reversible, because internal tools are where fraud and fat fingers both live.

Server-rendered where it can be, Postgres underneath
04 / Data pipelines

Idempotent, replayable, alarmed

Ingest, transform, serve. Jobs you can re-run safely, raw data kept so any day can be rebuilt from source, and schema contracts that break the pipeline loudly instead of quietly poisoning a dashboard for a month.

Airflow or dbt, warehouse on Postgres, BigQuery, or Snowflake
05 / Integrations

Other people's systems, which will fail

Payments, identity, CRM, logistics. Webhook signatures verified, idempotency keys on every write, retries with backoff, and a dead letter queue that someone is named as the owner of.

Versioned OpenAPI 3.1 contract, published to your side
06 / Legacy replacement

The old system stays running

One capability moved at a time behind a routing layer, both systems live against the same data until the new path has carried real traffic long enough to be boring. Detail is further down this page.

Strangler migration, no big-bang cutover weekend
How delivery runs

A deployment in week two, not a demo in month six.

The thing that goes wrong in software projects is not velocity. It is finding out in month five that what was built is not what was wanted, and that nobody could tell because nothing had been deployed.

PHASE 01

Model, then estimate

Two to five working days. We write down the roles, the data we will hold and why, the deployment target, and what an attacker would want from it. It ends in a document short enough that you will read it and specific enough that you can disagree with it.

PHASE 02

Deployed early

A thin slice running in your environment, behind real authentication, usually inside the first two weeks. Not a prototype on our laptop, not a click-through. From then on there is always something real to look at.

PHASE 03

Iterations you can inspect

One to two week cycles against a branch you can pull and a deployment you can click. Each cycle ends with a short written note: what moved, what we got wrong, and what we are doing about it.

PHASE 04

Handover with the keys

Five artifacts, listed below, plus one session in which your engineers deploy and roll back the system themselves while we sit there and do not touch the keyboard. If they cannot, it is not handed over.

We do not invoice for a status report. The cycle note is two paragraphs written by the engineer who did the work, and the deployed build is the real status.

What you are left holding

Six things in your repository on the last day.

The test of a build engagement is what happens six months after it ends, when the engineer maintaining it has never met us.

01

Runbook

How to deploy, how to roll back, how to rotate every credential, which alarm means wake someone and which means wait until Monday. Written for the person who joins after we are gone.

02

Architecture notes

Four to ten pages on the decisions and, more usefully, the options we rejected and why. Longer than that and nobody opens it, which makes it a liability rather than a document.

03

Threat model

Data flows, trust boundaries, the abuse cases the design defends against, and the ones you consciously accepted. Hand it to whoever tests the system next and their first week gets considerably shorter.

04

Test suite

Authorization tests per role, a negative test for every permission check, and integration tests across the paths that move money or personal data. We will not quote a coverage percentage as if it were a quality score.

05

Deployment pipeline

Build, test, dependency audit, secret scan, deploy, roll back. Defined as code in your repository and runnable by someone who is not us, from a laptop that has never had our SSH key on it.

06

Ownership

Repositories, cloud accounts, registrar, and app store listings in your organisation's name from the first commit. Our access is a set of invitations you can revoke in an afternoon.

Security as a build concern

Five decisions taken before the first feature.

Security is not a phase near the end, because the things that go wrong are structural and cost ten times more to change once there is data in the table. These five are settled in week one.

Broken object level authorization is the most common finding we write about other people's code. We would rather not write it about our own.

// CobaltLoom build principle
  • 01

    Authorization before features

    The role and object model is designed first and enforced in one place. An endpoint that checks the token but never checks whether this user owns that record is the single most common serious finding we report, and it is a design decision, not a bug.

  • 02

    Secrets never in the repository

    Injected at runtime from AWS Secrets Manager, GCP Secret Manager, or Vault. History is scanned on every push, and a secret that does leak gets rotated, not quietly removed from the log.

  • 03

    Supply chain checked in CI

    Lockfiles pinned, an SBOM produced on each build, dependency audit and secret scan as pipeline stages that fail. A known-exploited vulnerability stops the deploy rather than opening a ticket nobody reads.

  • 04

    Audit logging written with the write path

    Who changed which record, when, from where, and what the previous value was, added at the same moment as the code that changes it. Retrofitted two weeks before an audit is how a field ends up null for the first eighteen months of its life.

  • 05

    Authentication we did not invent

    A maintained identity provider or a maintained library. We do not hand-roll password hashing, session handling, TOTP, or a password reset flow, and we will argue about it if asked to.

Legacy replacement

The rewrite that pauses all feature work for a year usually fails.

The system is typically ten to twenty years old. Its author left. There are no tests, the schema encodes three abandoned business models, and two columns named status and status_2 both matter. Everybody wants it gone and nobody will touch it.

The plan that gets proposed is a clean rewrite with a cutover weekend. It means freezing every change your business needs for a year, racing a moving target, and betting the company on one Saturday night. We will not quote that plan.

A strangler migration instead: a routing layer in front of the old system, one bounded capability moved behind it at a time, both running against the same data until the new path has carried real traffic long enough to be uninteresting. Every route moved is value you keep. If the work stops at month four, you are four capabilities better off, not stranded between two half-systems.

Order matters: we move the capability with the clearest boundary first, not the one with the loudest complaints, because the first migration is also where we find out what the routing layer got wrong.

  • A

    Read it before replacing it

    We read the existing code and write down what it actually does, including the behaviour that is accidental but that three departments now depend on. This is a priced piece of work with a document at the end, not a free discovery call.

  • B

    Characterisation tests first

    Before anything moves, tests that pin the current behaviour, including the behaviour that is wrong. You cannot prove a migration is faithful against a system whose output nobody has ever recorded.

  • C

    Run both, compare output

    For the capabilities where correctness is expensive to get wrong, the new path runs in shadow against live traffic and we compare results before it serves a single user.

  • D

    Delete the old code

    A route is not migrated until the old implementation is removed and the dead tables are dropped. Two live implementations of the same rule is how the data drifts apart.

Strangler migration: replacing a legacy system without a big-bang cutover Four stages read left to right, top to bottom. Stage one: all traffic enters a facade and reaches a legacy monolith; no new service exists. Stage two: characterisation tests pin the old behaviour and one route is carved off to a new service behind the same facade. Stage three: the new path serves a slice of live traffic while a comparator checks every response against the old path. Stage four: legacy routes are retired one at a time and the dead code is deleted rather than parked. Below, marked in red and broken by crosses, is the path the firm refuses to quote: a feature freeze, a rewrite in the dark, and a one-night cutover. STAGE 1 · ONE SYSTEM, ONE DOOR Facade one door Legacy monolith every route, no seams no seam yet, and nothing pinning the old behaviour New service does not exist yet STAGE 2 · CARVE OFF ONE ROUTE Facade same door Legacy monolith routes 2 to n Characterisation tests pin the old path New service route 1 only STAGE 3 · SHADOW COMPARISON Facade same door Legacy still authoritative Comparator old vs new, every call mismatch blocks promotion New service 5% of live traffic STAGE 4 · RETIRE, THEN DELETE Facade one door Legacy remnant 2 routes left Delete, don't park retired route code is removed from the repo New services all but 2 routes, live WHAT WE WILL NOT QUOTE · BIG-BANG REWRITE Feature freeze all delivery stops for twelve months Rewrite in the dark no production feedback nothing to compare against One-night cutover every risk arrives at once rollback is a rumour we do not sell a year of silence, then one night in which every assumption is tested at once all traffic all traffic all traffic all traffic
Fig. 1 · Strangler migration in four stages, and the big-bang rewrite we decline to quote.
What we decline

Four build engagements we turn down.

Each of these has been offered. Each one ends badly in a way that is predictable from the first meeting.

A rewrite nobody can describe

If no one in your organisation can tell us what the current system does, that project has already failed and has not noticed yet. We will do the reading and write it down as a separate, priced piece of work, and you are free to take that document to another firm.

Fixed price on a moving scope

A fixed scope at a fixed price, or an open scope by the iteration. The third version, where the price is fixed and the scope is not, ends in a dispute about what was implied in a meeting. We have had that argument and we are not interested in it again.

Launch without the deployment story

If the only path to production runs through one of our engineers typing commands, it is not finished. Pipeline, rollback, and runbook are part of the build, not the line item that gets cut to hit a date.

Anything that makes us unfireable

No proprietary framework of ours in the middle, no infrastructure in our account, no credential you cannot rotate without calling us. There is no month of this engagement in which moving to another firm is impossible.

Why this sits beside the testing

We write remediation for other people's code because we maintain our own.

A report line that says to implement proper access control is written by someone who has never had to implement it in a system with twelve roles, a four-year-old permissions table, and a release on Thursday. When our report names the change, somebody on the team has made that change in production under that deadline.

It runs in the other direction too. Everything on this page is shaped by what we keep finding in other people's systems: the audit log added too late, the secret in the git history, the admin endpoint that checked the session and not the record.


Before you ask

Questions we get on the first call.

What stacks do you actually work in?

TypeScript on the front end and in Node services, Python, Go, Postgres, containers on AWS or GCP, React Native or native Swift and Kotlin on mobile. If your stack is outside that list we will tell you so rather than bill you for our ramp-up. We will not learn a bespoke internal framework on your budget and then charge you for the time it took.

How is it priced?

Two shapes. A fixed scope at a fixed price, written in enough detail that both sides know what is outside it. Or an iteration rate with a fixed cadence, which you can stop at the end of any cycle with nothing owed for the next one. The modelling phase is priced separately because it is useful to you even if you never hire us for the build.

Can our own engineers work alongside you?

We prefer it. Same repository, same review process, our commits reviewed by your people and theirs by ours. Handing over a system that nobody internally has ever reviewed is how a build becomes a dependency on us, which is the thing we are trying to avoid.

Will you penetration test what you built?

We will, and the report will state on the first page that we wrote the code, because that materially weakens it. A test by a firm with no stake in the result is worth more. Where you need that, hire someone else and we will hand them the threat model, the architecture notes, and source access so their time goes into testing rather than orientation.

What do you need from us to start?

One person who can decide what the software should do and is available for an hour a week, access to the systems it has to talk to, and whoever currently knows the most about the thing we are replacing for two or three sessions. Without the first of those, the project stalls regardless of how many engineers are on it.

What happens after the handover?

Usually nothing, which is the point. If you want us to stay on for maintenance we will quote it as a separate agreement with a defined response window, not as a retainer that quietly renews. Either way the system runs without us on day one.

Related

The rest of what the same team does.

Engage

Tell us what the system has to do and what it currently does instead.