How I Stopped Writing “New Code” and Started Encoding Decisions
A case study in contract-first, self-healing development for a solo, AI-assisted project

Our extensive experience in Human Capital Management (HCM), combined with a strong background in Finance, ICT employee HR system adoption, and HR consultancy, brings a compelling value proposition. Our expertise in transformations to Entra, Organizational Performance Management, Analytical Skills, Security and Compliance, and End User Adoption is crucial in today’s rapidly evolving business landscape.
A few months ago I started rebuilding Microsoft’s discontinued Social Engagement product as a solo, self-funded side project. The result so far is SocialEngage, a social-listening and insights subsystem split across a Node/TypeScript backend and a Next.js admin UI. The code is real. The Azure resources are real. The PostgreSQL, Key Vault, Service Bus, and Blob Storage are all real, provisioned services — not mocks.
What I didn’t expect was that the hardest part would not be the connectors, the OAuth flows, or the Postgres RLS. The hardest part would be not losing my own context between sessions.
I work on this project in short, sporadic, quota-limited bursts. The agent I pair with (Claude Code / Devin) has no memory of what I did last Thursday. If I leave a story half-implemented because a session runs out, the next session cannot assume that half-finished state is correct. That constraint forced a delivery methodology that has turned out to be the most valuable part of the project: a mechanical, contract-first, self-healing loop that converts every sprint’s hard-won lessons into reusable project knowledge.
Here is how it works.
The two skills that run the project
All implementation is driven by two skills: implement-story and heal-contract-failure. They are not guidelines. They are executable checklists that must be followed in order.
implement-story is how every user story is built. It does not start with code. It starts with a specification pyramid:
The User Story in
user-stories.
The source ADR that governs it in
adr.
The Business Requirements (BRD) for permissions and business rules.
The Functional Design (FDD) for request/response schemas and role gating.
The hierarchy is fixed: ADR > BRD/FDD > Story. If the FDD contradicts the ADR, I stop and surface the conflict. No one is allowed to “make it work” against a higher-level decision.
Only after reading those four artifacts do I write an Intent block: the story, the ADR, the exact files that will be touched, the contract I am about to encode, and — crucially — what is explicitly out of scope. Scope creep is caught before any code exists.
Then I write the contract test in Jest, in <repo>/contracts/epic-<N>/story-<X.Y>.<slug>.contract.test.ts. with one test per Acceptance Criterion. The test must fail at this stage. If it does not fail, I have not described the new behavior clearly enough.
Implementation comes after the contract. I write the minimum code to make the contract green. Then I validate against an isolated Postgres database cloned from a template, run the epic-level contract suite or the full suite depending on what files changed, and only then commit, append to the append-only
implementation-log.md, and merge the worktree back intomain.
That is the happy path.
heal-contract-failure is not a debugger
The second skill, heal-contract-failure, is what happens when something goes wrong — or when a prior session left a story uncommitted. This is the single most important discipline in the project, because it is where most solo-AI projects quietly fall apart.
The rule is simple: fix the underlying thing, never the check.
When a contract fails, the instinct is to classify the failure — “this is just a naming issue,” “the test is too strict,” “it’s an environment flake” — and jump to a narrow patch. That instinct is exactly what the skill is designed to kill. Instead, I must re-walk the same five artifacts in the same order, every time:
Re-validate the Intent against the current story and ADR.
Re-validate the Contract against the Acceptance Criteria.
Re-validate the component
SKILL.mdfor stale constraints or missing relationships.Only then, re-validate and fix the implementation.
Validate, with the full suite where cross-epic files are involved.
If the contract itself looks wrong or stale, I cannot edit it unilaterally. If the only way to get to green is to weaken, skip, delete, or bypass a contract, hook, lint rule, or CI gate, I stop and escalate. I am capped at three full walks of the loop; after that, the failure is a human problem, not an agent one.
This same skill is also how I resume an interrupted story. Uncommitted state from a previous session is treated as unverified, not “almost done.” I re-enter the healing loop and walk it again before committing. That prevents the common trap of an AI agent silently finishing someone else’s half-broken thought.
Three enforcement layers
Intent and discipline are not enough. The project has three mechanical enforcement layers:
A
PreToolUsehook blocks any write tosrc/in either repo unless a*.contract.test.tsfile already exists in that repo.A pre-commit hook runs the same check at git time, catching work done outside a Claude Code session.
CI runs the full accumulated contract suite and a traceability/naming check on every PR.
None of these can prove a contract is semantically correct, but together they make it mechanically expensive to skip the contract-first step or to let a story leave the repo without its traceability artifacts in place.
From sprints to reusable knowledge
The part I am most proud of is the feedback loop. The project does not just ship features; it ships lessons learned.
Every retrospective or hard-won debugging session feeds one of two artifacts:
docs/project docs/Lessons-Learned-Register.md— an append-only, PMBOK-style narrative register. Each entry describes what happened, the pattern it revealed, and the durable rule it produced, with a cross-reference to the authoritative document. For example, a 2026-08-13 entry about apublishEvent()function that was contract-passing but never called from the real ingestion path led directly to a new “relationship assertion” convention: if a story creates a real call relationship between components, at least one contract must exercise that relationship at the real production call site, not in isolation.Self-Learning Synthesis outputs, driven by ADR-0122 / FDD-0122. After each epic, a synthesis pass scans git telemetry, contract inventory, healing commits, and ADR implementation-learning status and produces a document like
Self-Learning-Synthesis-Epic-13.md. It surfaces reusable architectural patterns, environment gotchas to verify, and in-place ADR annotations. The synthesis does not just record history; it tells the next story what to look out for.
This is the “sprint lessons learned” layer in practice. It means a painful discovery in Epic 6 can become a guardrail in Epic 13 without me having to rediscover it.
What has changed as a result
This methodology has produced a few conventions that I now take for granted but would not have arrived at without the loop:
Relationship assertions: contracts must touch real call sites.
**A
**Built:**field in every story, separate fromStatus, so “Ready” and “already shipped” do not drift.environment-gotchas.md, a consolidated index for the recurring Azure timing, Jest parallel-worker race, and dependency issues that used to live scattered in individual
SKILL.mdfiles.Worktree and template-DB isolation: each story runs in its own branch and each Jest run clones an isolated Postgres database, so concurrent agents can work on
social-listening-corewithout collisions.
The project currently carries 209 contract test files across both repos, and the social-listening-core suite alone was at 68/68 suites and 537/537 tests the last time it was fully logged. More importantly, when something breaks, I know where to look first.
Why this matters if you are also a solo, AI-assisted developer
The conventional advice for solo builders is to move fast and ship MVPs. That works until the project is too large to hold in one head — and in a solo-AI setup, the “head” is split between you and a contextless agent anyway.
The methodology I ended up with is basically an external memory system for implementation intent. It makes the following promises explicit:
Every feature is traceable to a decision (ADR) and a promise (contract).
Every failure is repaired by re-confirming the decision, not by whack-a-mole patching.
Every painful lesson is written back into the project so the next agent (or me in three weeks) does not pay the same cost.
It is slower for a single story. It is faster for a multi-year project. And on a project where the only developer is me, the only consistent reviewer is a script, and the only long-term memory is the repo itself, that trade-off has been worth it.
If you are building with AI agents, do not just prompt, review, and merge. Give your future self and your future agents a machine-readable trail: skills, contracts, append-only logs, and a lessons-learned loop. The code is the easy part. The hard part is making sure the next session knows what the last one was trying to do.






