Florete

AI-First Development

Two implementation lines, one design corpus, and the contracts between them

Florete is built by two implementation lines working from one design corpus. The spec-driven line is generated by agents, released and maintained. The decision-driven line is generated under human supervision and grows behind it, one unit at a time. Neither replaces the other: we release first and build afterwards, and the frontier between them never closes.

If you are proposing a change, Working on Florete says where it goes and what it has to carry — that is all most contributors need. The Shape and the sections after it explain the process itself, for whoever changes it, and the Decision Log at the end records why each rule is what it is.

Working on Florete

Contributions go to two repositories: design and documentation to florete, which holds the corpus this page is part of, and code to flor, the decision-driven repository. flor-dist is public so that anyone running Florete can inspect what they run, but it takes no patches: its code is generated, and a unit is replaced wholesale whenever it is regenerated, so a patch there would be thrown away rather than kept. Report a defect you hit in a release as a failing test against flor instead. That test outlives every implementation of the unit it covers, which a patch would not.

Use AI throughout — that is what this page is about — and understand what you propose. Every change to flor is reviewed by a human and has to be defensible line by line: an agent generating it is expected, and what makes it defensible is that it was generated from settled decisions you can answer for. Fully automated work is not accepted there, and that is what the other line exists for; keeping the two apart is the point of the whole arrangement.

Start a feature at Design rather than at the code. That page carries the design workflow we run — decisions settled and recorded before any prose is written — and it is what decision-driven development means in practice on the DD line: the decisions exist, in writing, before an implementation does. Both lines consume the whole corpus; what differs is what each requires of it — SD can be generated from scope and contracts alone, and consumes the decisions if they are available, while DD cannot proceed until they are settled. Behaviour therefore starts in the design corpus — the milestone pages under implementation/, and the guides, which are input to the lines rather than a deliverable that follows them — not in a pull request, since those pages are the specification both lines are built from and behaviour that lands only in code leaves the two lines describing different products.

A bugfix carries a failing test first: write it into the conformance suite, watch it fail, then fix. This is not ceremony. The suite is never regenerated, so that test is what makes your fix survive the next regeneration of the code it fixed.

Shape

STRUCTURE

  motto       release first, build afterwards

  lines       SD   spec-driven; agent-generated, released, maintained, regenerated
              DD   decision-driven; generated under human supervision,
                   grows behind the frontier

  process     two permanent implementation lines of one design corpus, one product
              release then build: SD holds the leading edge, DD follows behind it
              the frontier moves, never closes

  repos       flor        DD; one crate per unit, no registry
              flor-dist   SD; own history, no common ancestor; assembles the
                          graph and packages every executable

  corpus      everything SD generates from
              prose       florete/src/content/docs/
                          a milestone's scope, its decisions, and the guides
              APIs        every unit's public API, as code in flor
              fixtures    golden examples, in flor; run as tests as well

  unit        a crate with a human-authored public API, contracted by definition
              SD and DD each supply a crate satisfying it
              it depends only on units and third-party crates a human declared
              a binary may be one; flor-dist still assembles and packages it
              code drawn into no unit is bound by the corpus and the suite

  SD crate    such code that more than one consumer shares, in a crate of its own in flor-dist,
              its API and body the agent's; no unit, and no obligation rests on it

  inventory   per milestone, in its decomposition.mdx
              crates      its units and its SD crates, each with the calls that drew it
              obligations what must hold across the milestone's code, each with the units
                          owning the check it rests on
              the decomposition designs no API

  assembly    flor-dist's workspace root alone says which line supplies a unit:
              its own dependency by source, one inside a DD crate by [patch]
              each unit resolves to exactly one package, enforced mechanically

  suite       append-only, human-owned, held in flor; black-box over a
              contract — the product's edge or a unit's API — on both lines
              conformance tests   against a contract; what the product promises
              regression tests    one per defect, each saying in a line what
                                  the product once got wrong
              golden fixtures     exact examples; corpus as well
              hidden from generation, the fixtures aside, by instruction
              rather than isolation
              a gate at generation, an input at patching
              run by flor-dist's CI, which alone builds the product; tests at
              a unit's API also by flor's CI, on DD's body

FLOW

  milestone
      its scope and design in the corpus
      → decomposition: crates and units drawn, lines set, obligations stated
      → each unit's API authored against generated consumers; its
        obligations kept, its line confirmed or changed
      → generation, against tagged APIs whether their bodies exist or not

  feature
      ├─ designed in the corpus, always, before either line has it
      ├─ DD  → human-supervised implementation
      └─ SD  → affected units (re)generated by agent from the same corpus

  bugfix
      ├─ a failing suite test is written first, human-supervised
      ├─ DD  → human-supervised fix, new tag, re-pinned by flor-dist
      └─ SD  → agent patches until it passes

  substitution (DD-ward)
      triggered by a security finding, the defect ceiling, or an
      obligation SD cannot keep — never by quota
      → contract frozen
      → flor-dist builds a second configuration: the DD crate by git tag
      → suite green in BOTH configurations
      → the assembly move lands; SD implementation deleted last

  reverse substitution (SD-ward)
      churn reaches a DD unit
      → SD implements the new contract, the assembly redirecting the unit to it
      → released on SD, recorded in the decomposition
      → DD writes the new body itself, in the gap after the release
      → substituted back by the same sequence
      a deferral, not a reclassification

RULES

  direction   the corpus flows to both lines; DD crates flow to SD
              nothing flows out of SD except findings against the corpus
              both consume all of it; DD requires the decisions, SD the
              scope and the contracts, and takes decisions if available
              generation codes against interfaces, never against DD bodies;
              a reliance on what a contract leaves unsaid is a finding, and
              so is a read of the suite's hidden part, with its reason
              SD proposes a contract change as a finding; it never makes one

  human loop  both  scope, acceptance, failure modes, the security boundary,
                    the suite, the runbook, and every contract
              DD    also structure, naming, impl details, change review
              SD    none of those; no code review of generated code

  drawing     a human makes three calls on each concern, each recorded with its reason
              crate   a crate of its own wherever more than one consumer uses it, on either line
              unit    a human-authored API where a unit depends on the crate, an obligation rests on
                      its API, or its body is to be DD's, SD taking DD's code only as units;
                      otherwise an SD crate, and one drawn for its body alone is no unit while it
                      stays on SD
              line    the line that supplies a unit's body when the milestone ships: the cost of an
                      error in it — an adversary picking its input, harm outliving a release —
                      weighed against the cost of DD, its time and the release it delays, which
                      working code lowers; the API's author confirms it or changes it, with the
                      reason

  granularity concerns share a crate unless one can move between lines on
              its own, an executable or a unit uses one but not the others,
              or sharing would close a cycle; otherwise, a few large crates

  layering    units form layers, every edge pointing down; a data unit
              never depends on a lifecycle unit

  obligations stated by the decomposition, on units only: a crate whose API must keep one is a
              unit; kept as each API's author decides, recorded beside the obligation: by the API
              itself where an adversary picks the input, by tests at the API where the input is the
              unit's own state
              an SD line, however reached, holds where every obligation it touches is kept; where
              one is not, the unit ships SD with it recorded unkept, and is due on DD

  contracts   whatever something outside a unit reads; designed before
              generation, and reviewed by a human
              kind         API, protocol, format, command line
                           only an API is drawn as a unit; a unit may own
                           contracts of the other kinds
              party        another component, another release, a peer,
                           a person, another program
              statement    the API itself in code; a design page or an
                           ADR; a guide, for a person
              enforcement  compiler         an API's shape, for every caller
                           public-API diff  an API's shape, across revisions
                           golden fixtures  any other kind's shape, exactly,
                                            for the examples they hold
                           suite            meaning, for the inputs it uses
                           version gates    skew between releases: a reader
                                            refuses what it cannot read
                           review           all of it, for every input; DD only

  conventions how code is written: DD's rules of thumb, held by review and
              lints; SD keeps its own, and may take DD's as advice

  change unit DD  the diff or a refactored piece of a unit as a whole
              SD  the unit, regenerated from the corpus
                  patched only after a failing suite test is written

  evolution   DD sheds erosion by refactoring: controlled regeneration
              of a piece of the unit: a function, a design section;
              what matters is pinned before the step and checked after it
              SD is regenerated on a defect ceiling, a contract change or a
              scope shift; the suite is never regenerated, so a regeneration
              inherits every fix

  milestones  design-decomposition units and release points
              a decomposition states what its milestone ships: each unit's line and the reason, and
              any obligation an SD line cannot keep

  public      flor open to contribution; flor-dist read-only
              a defect in SD is reported as a suite test against flor

Process design

Why two lines

Agents and humans fail at different things, and the split follows that. Agents are good at producing a working implementation from a specification and poor at carrying one through a sequence of changes — structure erodes as the sequence lengthens, and better prompting moves where the erosion starts without changing how fast it accumulates. Humans are the opposite: slow to produce, and the only thing that holds a system's shape across time.

So the spec-driven line takes the work agents do well, and the decision-driven line takes the work humans do well while accepting that it cannot move fast enough to be the product on its own. Running only DD settles quickly: there is no sellable artifact inside any funding window we have. Running only SD is the harder case, because it would work for longer than it looks. The contracts are what make a system evolvable, not the code behind them, so a generated product with good boundaries can be extended by regenerating a unit inside the boundary that holds it.

What such a product would lack is evidence. A green suite would be the only thing saying it is right, so every requirement would have to be cheaply testable from outside, and every test added would constrain every later regeneration — the erosion would move out of the code and into the suite rather than going away. Nobody could diagnose a live defect in code no one has read. No implementation experience would feed back into the corpus, which is the asset the rest of this rests on. And a contribution would have nowhere to land, since the generated repository takes no patches. DD exists for those four things, and evolvability is not among them.

The same reasoning splits the human loop by property rather than by volume. Humans own scope, acceptance, the failure modes, the security boundary, the suite, the runbook and every contract on both lines; on DD they also own structure, naming, implementation detail and the review of every change; on SD they own none of those, and no generated code is reviewed at all. That is affordable because the properties agents fail at do not fail together — happy-path correctness is good, the evolvability of what an agent writes is given up deliberately, failure-path and security correctness are weak — and it is bounded by one failure with no other check behind it: what an edit drops. An agent can delete the line that verifies something and leave every test passing, and on a line nobody reads that goes unnoticed. Reading the change is the only check against an omission — the diff, or a regenerated piece read whole against what was pinned before it — which is what the DD units are buying.

The frontier never closes, and that is the design rather than a failure to finish. New work lands SD-first because that is where speed is, and a unit moves DD-ward when something says it should rather than on any schedule, stepping back to SD for a milestone when churn reaches it — what says so, what each move costs and how a unit comes back are settled under Substitution below.

The corpus

One rule keeps the arrangement from collapsing. The corpus flows to both lines and DD crates flow to SD, but nothing flows out of SD except findings: what the generated line learns about the design is filed against the corpus and enters through a design pass, never as a direct amendment made under release pressure.

That rule is also what defines the corpus. It is everything SD generates from — and since nothing flows out of the generated line, whatever that line generates from is by construction ours to author. "What must a human own" is therefore a consequence rather than a judgement made case by case.

It has two homes. The prose half is in florete: a milestone's scope, its decisions, and the operator and user guides, which bind as input rather than following the code and which carry the use cases that have to work — and with them the statement of every contract that is not an API, a protocol, a format or a command line. The other half is in flor: every unit's public API, because an API in Rust is not prose and belongs where it compiles, and the golden fixtures, exact examples that generation reads and the suite runs as tests. Both lines consume all of it, and what differs is what each requires: SD can be generated from scope and contracts alone and takes the decisions where they exist, while DD cannot start until they are settled.

A DD implementation is not corpus at all. flor-dist depends on DD crates, and building it puts their bodies within the agent's reach, but generation codes against their interfaces and never against their bodies. An agent that relies on a body codes against what it observes instead of what was promised, and the invariants it absorbs that way become load-bearing without anyone having written them down, which surfaces as a silent break the next time DD refactors behind its contract. It does that where a contract is silent, so the rule is to report rather than to look away: behaviour generated code relies on that the contract does not state is filed as a finding, which is how a contract learns it had a gap. One convenience falls out of coding against contracts: a contract can be tagged before its body exists, so a crate whose functions are unimplemented still yields a complete interface, and SD generates against a frozen API while DD fills it in. Only the assembly move waits for a working implementation.

Because a contract is corpus, changing one is a design decision. An agent that finds a unit's API wrong, or missing something it needs, proposes the change as a finding and a human takes it through the pass — that is among the more useful things generation reports, and it is still not a licence to write one.

Contracts

Before a milestone is generated at all, one class of thing has to be designed: whatever a regeneration cannot undo. That is anything read from outside the unit — another component reading a public API, another release reading on-disk state or an artifact format, a peer reading a wire format, a person reading the CLI or an error message, another program reading an exit code or a log line's framing. Everything else is the agent's to decide, because being wrong about it costs one unit's regeneration rather than a break in something already deployed.

Such a contract is described along lines that vary apart. Its kind is what it is: an API, a protocol, a format or a command line. Its parties are whoever reads it, from the list above. Its statement is where it is written: an API in its own code, any other kind in a design page or an ADR, and in a guide wherever a person is a party. The three part company constantly — one format is read by another release and by another program, one person reads a command line and writes a configuration a later release must still read, and one command line is stated in a guide for whoever types it and in a design page for whoever implements it — so a contract described by any one of them hides the gaps the others would show. A guide is the strongest statement for its reader: it is written before either line implements anything, the agent can generate the main-line tests from it, and what a formal suite would add there is mostly transcription.

Enforcement is every means a contract's kind admits, each holding a part of it. The compiler holds an API's shape for every caller, and the public-API diff holds it across revisions. Golden fixtures hold the shape of every other kind — exactly, but only for the examples they carry. The suite holds meaning, for the inputs it uses; version gates hold the skew between releases, a reader refusing what it cannot read; and review holds all of it, for every input, but only on DD, where someone reads. The means differ in what they reach rather than by degree, which is why each is named by the part it holds: a contract checked wholly by machine can still have its meaning unchecked. Behaviour is pinned by conformance tests only where nothing cheaper pins it, and detail follows consequence — a surface whose misuse costs a support question is described, one whose misuse costs a breach is specified. A human reviews every contract.

Error handling shows where a contract ends. The report a failing command prints is command-line output, read by an operator during an incident and by whatever program watches the exit: a contract on both lines, its shape held by fixtures and its meaning by the suite. How the code behind it wraps its errors — what each boundary attaches, how many variants an error has — is read by no one outside the unit, so it is no contract but a convention: DD's rules of thumb, held by review and by lints where a rule is mechanical. SD keeps conventions of its own and may take DD's as advice; it is held to the report's text and never to the style behind it, since its code has no reader for whom a style would be kept. Errors that appear in a unit's API are part of that API, authored like the rest of it.

Two failure modes sit either side of all this. Contracting too little leaves the agent to freeze something a later release has to read. Contracting too much spends the scarce resource on transcription and, where the over-contracting takes the form of tests, buys a suite that eventually blocks the regenerations it exists to make safe, since every test is a constraint the next implementation has to satisfy.

Decomposing a milestone

Milestones do two jobs: each divides a design too large to settle whole, and each is a release point. Before a milestone's code is generated, it is decomposed — divided into units and the integration generated around them, in a decomposition.mdx that states what the milestone ships, and grows with it.

A unit is a crate whose public API a human settles before either line implements it. Being contracted is what makes it a unit, so there is no such thing as an uncontracted one — only code that is not a unit, bound by the corpus and the suite and by nothing else. SD and DD each supply a crate satisfying that API, and a substitution is a one-line change, in flor-dist's workspace root, to which of them supplies it. Only an API is drawn as a unit, though a unit may own contracts of other kinds. A binary's own logic can be one like any other: what a unit names is a contract, and which line satisfies it is decided where the graph is assembled rather than by where the code sits, so the executable is built in flor-dist from a one-line main over that unit's entry point.

The boundary is a crate rather than a module because a module boundary inside one crate is advisory: pub(crate) is visible throughout, so in a codebase nobody reads it erodes without anyone noticing. A crate boundary is checked by the compiler.

Not everything becomes a unit, because authoring an API costs human time and that is the scarce resource. So a decomposition weighs every concern that might stand as a crate, finer than any unit, and a human makes three calls on each, recording each with its reason. The first is whether it gets a crate of its own, which it does wherever more than one consumer uses it, on either line: one implementation is what keeps shared code from drifting between copies — a format one executable writes and another reads above all — and a boundary several consumers read is cheapest drawn before generation, since retrofitting it later means regenerating most of the line. The second is whether that crate is a unit, its API authored by a human: it is where a unit depends on it, where an obligation rests on its API, or where its body is to be DD's. Otherwise it is an SD crate — no unit, its API and its body the agent's, in flor-dist — so no human API is spent on a boundary only integration crosses.

The third call is the line that supplies a unit's body when the milestone ships, and it weighs what an error in that body would cost against what DD costs: the time it takes and the release it delays, both of which working code lowers. Two things make an error costly. One is an obligation that quantifies over all inputs: a suite is evidence about the inputs it uses, so a promise that no input produces some result is beyond it — the input that matters is chosen by an adversary after we chose our tests. The other is harm that outlives a release: state a later release has to read, a node left unreachable, a broken path for every repair after it. The model trades a mistake against one regeneration, and where being wrong outlives the release that made it, that is no longer the trade being made. Code where authentication terminates is costly on both counts. Review reduces such risk and never removes it, so DD is bought where an error would cost more than the time and the release it takes.

The calls are separate because they turn on different things: a unit whose error would cost much can ship on SD where its API keeps its obligations, and one with working code on DD where nothing else argues for it. A concern drawn for its body alone — to be reviewed, or to keep code that already works — is a unit on DD or none at all. On SD a unit protects only what its API keeps, so such a concern stays integration there, bound by its contract, and is drawn as a unit when it moves DD-ward; reviewed code worth keeping is drawn as a unit on DD, since SD takes nothing from DD but units, and throwing working code away buys a regeneration and nothing else. An export codec two executables share is the plain case of an SD crate: the file it writes outlives the release that wrote it, which no API shape keeps from drifting, so golden fixtures hold its format, and it becomes a unit only if it moves DD-ward.

Units are few and large. Concerns share a crate unless one of them can move between lines without the others, an executable or a unit uses it but not them, or sharing would close a cycle. The crate is the grain of every substitution, so a crate mixing concerns bound for different lines could be supplied by neither, and one holding concerns that will part must be split later, under churn, when a split costs most. A unit depends only on units and on third-party crates a human declared, and units form layers, every edge pointing down, no data unit depending on a lifecycle unit — which would hand every consumer a runtime.

Beside its units, a decomposition states what must hold across the milestone's code — each obligation with the units owning the check it rests on — and designs no API. Obligations rest on units alone: an SD crate's API changes with every regeneration, so it can hold none, and a crate whose API must keep one is a unit. APIs are not authored cold: the agent proposes one and generates consumers against it, and a human judges the result and iterates, since consumers are what reveal a bad API and generating throwaway ones is cheap. The work belongs at the very beginning, while DD has no call sites and SD is small, and changing an API costs almost nothing. Whoever authors a unit's API also decides how each obligation the unit touches is kept: by the API itself where an adversary chooses the input, its types and its checks leaving generated code around it no way past, and by conformance tests written against the API where the input is the unit's own state. An SD line, however it was reached, holds where every obligation its unit touches is kept that way. Holding the API, its author confirms the unit's line or changes it, amending the decomposition with the reason.

A milestone therefore runs in an order that is a dependency rather than a schedule: its scope and design, its decomposition, each unit's API, then generation — which can begin against APIs tagged before their bodies exist.

This is where the arrangement is most exposed, and it is worth saying plainly. Nearly all of the risk has been moved into the one activity with no mechanical check behind it: a public-API diff enforces conformance to a contract and says nothing about whether the contract was any good. So the failure this process invites is not a mess. It is a clean, conforming, well-tested system built on the wrong boundaries — which stays invisible far longer than bad code would, and costs far more once it surfaces. The one signal available is late: a unit that resists substitution, or whose contract keeps moving, is reporting that its boundary was drawn in the wrong place.

Change, regeneration and the suite

On DD the unit of change is the diff, or a piece smaller than a unit, such as a function, regenerated and then reviewed whole. On SD it is the unit: affected units are regenerated from the corpus rather than edited toward a new shape, because editing is the operation that accumulates erosion. From the corpus, not from a fixed list of pages — the agent gathers what it needs, milestone and neighbours included, and no map says which pages a unit answers to. A regeneration is not expected to arrive at the previous implementation either. Fresh context, and in a year a newer model, are what make it come back different, and that is the point of regenerating rather than patching.

Patching is allowed behind a failing conformance test, and that test is the whole admission rule. Admissibility has to be decidable without reading the code: a failing test is, and a judgement about how large a change is would not be, since making it would need the review this line does without.

Patching stops at a ceiling. When fixes reliably produce new defects, when a contract moves in a way the implementation behind it cannot absorb, or when a milestone's requirements diverge far enough that adapting costs more than generating, the unit is regenerated instead.

None of that is survivable without the suite. It is append-only and never regenerated, so every defect ever captured is inherited by every future implementation of the unit — a regenerated unit comes back with different bugs rather than the same ones, and the suite is the entire difference between that being acceptable and not. It is black-box over a contract, never over a body. Conformance tests, written against the product's edge or against a unit's API, say what the product promises; regression tests, one per defect, each with a human-written line saying what went wrong, say what it once got wrong; and golden fixtures, exact examples the product must read, write or transform exactly, pin the shapes the other two would only sample. flor-dist's CI runs all of it, since only it builds the product, and flor's CI runs the tests at a unit's API against DD's bodies as well. What the suite must carry is what nobody would reconstruct: the promises the product makes, and the failures it has already met where they still matter.

The agent does not read it while generating, the fixtures aside: they are corpus as well, exact examples generation has to see to reproduce. The rest judges what generation produced, and a test becomes input only once it fails — a regression test arriving with its line — which is the patching rule again. Generated against the suite, a unit would converge on the implementations whose defects filled it, which is the opposite of coming back different, and where the suite is silent it would fill the gap arbitrarily while a wrong test would simply become the specification. Nothing else needs to be visible beforehand: a defect that shows a gap in the corpus is closed in the corpus, where every later generation reads it. The suite sits in flor, in the tree generation builds against, so it is hidden by instruction rather than by isolation: generation is told not to read it, and records each read it makes anyway with its reason — which test, and what the corpus failed to say. Each such record is a finding, and names a gap the corpus can close.

Kept as a gate, a failure carries information instead: either the agent misread the corpus, or the corpus and the suite disagree — and the second is a finding. That works because a conformance test's obligation belongs in the corpus in any case, the test being the executable form of a promise rather than a new requirement, so a test that cannot be derived from the corpus is a gap in the corpus and not a rule withheld from the line that has to satisfy it. Whether the patching this costs is cheaper than the convergence it avoids is the honest open question here, and it stays open until one generation can compare the two.

Substitution

A unit moves DD-ward when something says it should: a security finding names it, its defect rate crosses the ceiling, or an obligation turns out to be one its SD line cannot keep, or keeps only convolutedly — judged by its API's author while the API is authored, or raised by a finding later. Until the move lands, the unit ships on SD with that obligation recorded as unkept. Never a quota — the need is observable, and allocating the work by arithmetic invites gaming it. Among candidates, severity decides and shape breaks ties, since a data-shaped unit drops into any consumer while a lifecycle-shaped one brings a runtime and a shutdown protocol with it. A unit can move once everything it depends on is contracted, which is a much weaker condition than everything it depends on being DD-authored.

The step itself is fixed. Freeze the unit's contract; have flor-dist build a second configuration that takes the DD crate by git tag where the first takes the SD one by path; require the suite green in both; land the assembly move; then delete the SD implementation. A DD crate can be green against the tests at its own API, but not in the product on its own — only a build of the product carrying it is, which is why the second configuration exists before the move rather than after it. Deleting last is what keeps every earlier step reversible by the same one-line change, and running both configurations is what catches a DD crate that passes on its own terms while changing behaviour the product depends on.

Both configurations are expressed in one place. flor-dist's workspace root names a source for every dependency it declares itself, and redirects, through a [patch] entry over the flor source, the ones declared inside DD crates — which is what lets a DD unit sit above generated ones instead of dragging reviewed implementations down the whole subtree beneath it. The constraint that comes with it is that each unit must resolve to exactly one package in the graph: Cargo will otherwise resolve two revisions of one unit without complaint, and unless a type happens to cross between the copies, the product ships both of them and both of whatever state they hold. Enforcing that mechanically is what keeps a unit's pin its own rather than the repository's.

DD work happens in the gap after a release rather than alongside the next one. Scheduled in the same window the two compete for the same people, and SD wins every time — it has customers where DD has principles.

Churn can also reach a unit that is already DD's, and then it goes to SD first, as any new work does. The assembly redirects the unit to an SD crate by a [patch] entry — the same one-line edit, run the other way — and generation implements the new contract; the line it reaches is held to the same test as any SD line, an obligation it cannot keep recorded as unkept. The milestone ships the unit on SD, and its decomposition says so, with the reason. The move still defers the unit's review rather than reclassifying it: in the gap after the release DD writes the new contract's body itself, never adopting SD's, and substitutes it back by the same sequence. Keeping the unit on SD past that milestone takes a later decomposition saying so, with the reason; without that, a deferral would become a reclassification by default, the frontier slipping back with nobody deciding it.

A decomposition states what its milestone ships, not where the lines stand: either line may supply a unit until the milestone ships, but it ships on the line written, or the decomposition is amended first. Where the lines stand is the assembly's to say, so the share of units that are DD-authored, how much of the security-relevant surface that share covers, and which units moved either way are read from it at any time rather than once per release. The failure mode of this arrangement is not that the migration never finishes — it is not meant to — but that the frontier stops advancing because new work always outranks moving a unit. A bare ratio would not show that on its own, since we define the units it counts and a re-decomposition moves it without moving anything; naming the units that moved is what makes the frontier visible without dictating a response.

What we say publicly is that state and the model behind it, the DD-authored share included — not that AI was involved. "Parts of this are AI-generated" is a sentence any slop project also writes, so as a disclosure it carries nothing. The claim worth making is that the boundaries are human-owned and the units are being replaced by reviewed implementations, which is a claim a vibe-coded product cannot make.

Decision Log

Entries are grouped by what a future change would be touching, not by the order they were settled.

The model

AIFIRST-01. Run two permanent implementation lines over one design corpus. The spec-driven line (SD) is agent-generated, released and maintained. The decision-driven line (DD) is agent-generated under human supervision, and grows behind it by substitution. Both are built from the same design pages, and neither converges away. The main difference between the lines lies not only in human supervision of the changes: DD requires explicit decisions in the corpus for each feature, while SD needs only scope and contracts, with the suite as its gate; SD consumes decisions when they're available, otherwise generating agents make their own. Because DD alone cannot reach a sellable product inside any relevant funding window. Because what SD alone lacks is evidence rather than evolvability: the contracts are what make the system evolvable, and a unit is regenerated inside its boundary when requirements change, but then the suite is the only thing saying the product is right, nobody can diagnose a live defect in code no one has read, no implementation experience feeds back into the corpus that both lines depend on, and a contribution has nowhere to land. Accepting permanent maintenance of two lines, and that some units stay SD-authored indefinitely. Rejected running SD alone behind good contracts and a good suite — it is structurally evolvable, but it makes the suite the system's whole memory: every requirement has to be cheaply testable from outside, and each test added constrains every later regeneration, so the erosion moves from the code into the suite rather than going away. Rejected replacing SD wholesale once DD reaches parity — parity is not a state that arrives, since features keep being added ahead of it, and DD is needed only where the suite is not sufficient evidence. Rebuilding the rest by hand would buy nothing.

AIFIRST-02. Treat milestones as design-decomposition units and as release points, each decomposed into what it ships. A milestone divides a design too large to settle whole. Each is also a release, and further milestones may be added to divide the work more finely. Its decomposition states what it ships: each unit's line with the reason, and any obligation an SD line cannot keep. Either line may supply a unit before the milestone ships; it ships on the line written, or the decomposition is amended first. Which line supplies a unit now is the assembly's (AIFIRST-11). Because the dual process exists to release more often, and a milestone that cannot be released makes releasing harder. Because a decomposition is drawn before its code exists, so what it can state is the target, which the code converges to by the release. Accepting more scope pages; the design content does not grow, only its division. Rejected the decomposition as a live record of the lines' current state, a status page beside the assembly that already holds it.

AIFIRST-03. Obsolete: when generation starts is a product's decision, not the doctrine's.

AIFIRST-26. Define the corpus as everything SD generates from. It has two homes and one test of membership. Prose lives in florete — a milestone's scope, its decisions, and the operator and user guides, which bind as input rather than following the code. flor holds the public API of every unit, because a Rust API is not prose and belongs where it compiles, and the golden fixtures, exact examples that generation reads and the suite runs as tests. A DD implementation is not corpus: SD depends on DD crates, but generation codes against their interfaces only (AIFIRST-27). Nor is the rest of the suite (AIFIRST-28). Because nothing flows out of SD, so whatever SD generates from is by construction ours to author — which makes "what must a human own" a consequence of the direction rule rather than a judgement made case by case. Because the guides define the use cases that must work, which is a stronger input than the design pages and the reason they are written before either line implements anything. Because an exact shape is best stated by an example, and generation must see it to reproduce it — so a fixture is at once a statement in the corpus and a test in the suite. Accepting that the corpus spans two repositories. Rejected a corpus narrowed to the prose and the APIs, the fixtures read by generation yet counted as the suite's alone, which gives what generation reads two names and the corpus's test an exception; the fixtures as statements alone, checked by hidden tests, which puts an example and its check under two rules.

What gets contracted

AIFIRST-04. Design before generation only what a regeneration cannot undo. A contract is authored first when something outside the unit reads it: another component, a unit or the integration calling it; another release, earlier or later; a peer; a person; or another program, such as a service manager reading an exit code or a script reading output. What lives inside a unit is the agent's to decide. Because a decision SD makes that later constrains DD is one taken without gates and cannot be regenerated away, while everything else costs a single unit's regeneration. Rejected closing each milestone's design fully first — most of what remains is regenerable detail. Rejected letting the agent decide every gap — it would freeze a wire protocol and a user-facing surface with no review.

AIFIRST-30. Describe every contract by its kind, its parties, its statement and its enforcement. A contract's kind is an API, a protocol, a format or a command line. Its parties are whoever reads it (AIFIRST-04). Its statement is where it is written: the API itself in code, a design page or an ADR, and a guide wherever a person is a party. Its enforcement is every means its kind admits, each holding a part of it: the compiler an API's shape, for every caller, and the public-API diff across revisions; golden fixtures any other kind's shape, exactly, for the examples they hold; the suite its meaning, for the inputs it uses; version gates the skew between releases, a reader refusing what it cannot read; review all of it, for every input, on DD alone. Detail follows consequence, and a human reviews every contract. Because the dimensions vary apart: one kind serves several parties, one party relies on several kinds, and one surface is stated in several places — a command line in a guide for the person who types it, and in a design page for those who implement it — so a list keyed on any one of them hides the gaps in the others. Because the means differ in what they reach rather than by degree: the compiler reaches every caller but only a shape, the suite reaches meaning but only for its inputs, and review reaches every input but only where someone reads — so naming the part each holds is what makes a gap visible. Because the suite captures bugs that were found rather than everything that was promised, so it cannot be the only gate. Accepting that a suite grown past what it must carry becomes the constraint a fresh implementation cannot satisfy, so over-contracting behaviour costs the regenerability the model runs on. Accepting that a version gate is designed into each format and protocol that crosses releases, contract by contract. Revisit the kinds and the means once contracts are authored against them. Rejected contracts listed by how they are enforced, which hides who relies on each; a list keyed on parties alone, or a table keyed on kinds, where a contract with two parties takes two rows and an empty cell goes unseen; the statement folded into the kind, which hides one surface stated twice for different readers; one ladder of strength, which ranks means that do not compare; enforcement told by how mechanical it is, which leaves a contract checked wholly by machine with its meaning unchecked; fixtures as a kind, where they are a statement and a means; a style as a kind (AIFIRST-08).

AIFIRST-08. Contract the error report, and leave how code is written to each line's conventions. The error report is command-line output, a contract on both lines: golden fixtures hold its shape and the suite its meaning. Errors in a unit's API are part of that API, authored by a human like the rest of it. How code is written — how errors are wrapped, what each boundary attaches, how many variants an error has — is a convention: DD's rules of thumb, held by review and by lints where a rule is mechanical. SD keeps conventions of its own and may take DD's as advice; it is held to the report's text, never to the style behind it. Because the error report is what an operator reads during an incident, which makes it a person's surface under AIFIRST-04, whatever the code behind it looks like. Because a style is kept for its readers, and SD's code has none who need it: an agent patching it reads whatever the generator wrote, and what writing it costs is generation's to weigh. Accepting that SD code ignoring DD's conventions — a variant for every failure where DD keeps one error — may be harder to evolve, a cost nothing verifies today. Rejected a style as a contract form of its own, rules plus golden output, which mixes what is read outside a unit with what is not; the conventions binding SD, which holds generation to rules it gains nothing from; a kind of its own for DD's code, which would make the contract model describe one line's discipline (AIFIRST-15); error handling left out of the doctrine, when its report is what an operator reads during an incident.

Decomposition

AIFIRST-05. Decompose the product into units, drawing each at an API. A page implementation/<milestone>/decomposition.mdx holds the decomposition and grows with the milestone. A unit is a crate whose public API is authored before either implementation (code with no contract is not a unit, bound by the corpus and the suite and by nothing else). Only an API is drawn as a unit, though a unit may own contracts of other kinds. SD and DD each supply a crate satisfying the API, and substitution swaps which one the assembly selects. A human reviews the contract; on SD nobody reviews the implementation. Because the corpus specifies behaviour but never drew code boundaries, and a boundary retrofitted into generated code is an evolution step on that code. Because a crate boundary is compiler-enforced where a module boundary is advisory, and in code nobody reads, an unenforced boundary erodes unnoticed. Because a unit costs an API authored by the scarce resource, while a contract of any other kind is stated in the corpus and checked by fixtures and the suite without one. Accepting that this concentrates the risk where nothing checks it: the diff enforces conformance to a contract, never the fitness of one, so a wrong boundary produces a clean and well-tested system that is expensive to correct and slow to notice. The available signal is late — a unit that resists substitution, or whose contract will not settle, is reporting a boundary drawn in the wrong place. Rejected deriving the boundaries from whatever structure SD arrives at; a unit to hold a contract of another kind, an API authored where a file needs none.

AIFIRST-31. Let a human make three calls on each concern: its crate, its unit and its line. A decomposition weighs every concern that might stand as a crate, finer than a unit so that nothing is merged before it is weighed, and a human makes three calls on each, recording each with its reason. The crate: one of its own wherever more than one consumer uses it (AIFIRST-06). The unit: a human-authored API where a unit depends on the crate, an obligation rests on its API (AIFIRST-34), or its body is to be DD's; otherwise it is an SD crate. A concern drawn for its body alone, for review or for working code worth keeping (AIFIRST-12), is a unit on DD or none: on SD it stays integration, bound by its contract, and is drawn as a unit when it moves DD-ward. The line: the one that supplies a unit's body when the milestone ships, weighing the cost of an error in it — an adversary picking its input (AIFIRST-07), harm outliving a release (AIFIRST-33) — against the cost of DD, its time and the release it delays, which working code lowers; its API's author confirms the line or changes it (AIFIRST-34). Because the calls turn on different things — a crate on how many consumers share the code, a unit on whether its boundary must hold before generation, a line on who writes the body the milestone ships — so a unit whose error costs much may ship on SD where its API keeps the obligations, and one with working code on DD where nothing else argues for it. Because a crate on SD protects only what its API keeps: a format's bytes, or a body worth reviewing, are kept by review alone, so a unit drawn for them on SD buys a seam at the price of an API. Because review reduces the risk an error carries and never removes it, so DD is bought where an error would cost more than the time and the release DD takes. Revisit once the cost of an error, and of DD, has a measure. Rejected rating every concern strong, some or none on fan-out, adversarial input and irreversibility, which fed the wrong calls — fan-out decides a crate rather than a unit, and irreversibility moved no line; a record of every concern on the decomposition page, stale once units split or merge; one call fixing both unit and line, which puts every risky unit on DD before anyone knows whether an API can keep its obligations; lines left to API authoring alone, which generates and plans nothing until every API exists.

AIFIRST-06. Give code several consumers share a crate of its own, an SD crate where no unit needs it. A concern more than one consumer uses — an executable or a unit, this milestone's or the next's — gets a crate of its own, on either line. Where only integration calls it and no obligation rests on its API, it is an SD crate: no unit, in flor-dist, its API and body the agent's. A milestone's crates and units are recorded in its decomposition.mdx. Because one implementation of what several consumers share keeps it from drifting between copies — a format one executable writes and another reads above all — and a boundary costs more to add later the more call sites it has. Because a human-authored API is the scarce resource, spent only where a unit or an obligation needs one. Accepting that code left in one consumer and later found to need DD costs a regeneration of its area. Rejected a unit for all shared code, human APIs spent on boundaries only integration crosses; integration left unstructured, which lets generation copy what several executables share.

AIFIRST-07. Weigh what a suite cannot evidence. The question weighs in an error's cost, for a unit's line (AIFIRST-31). Does the obligation quantify over all inputs? A suite shows that the inputs it uses produce the promised result. Where the promise is that no input produces some result — no unauthenticated peer is accepted, no secret reaches a log, no data crosses between tenants — the input that matters is chosen by an adversary after we chose our tests, so a green suite says nothing about the gap and only reading the code does. The domains are not comparable either: we define what valid means, so a suite can cover the shape of that space and property tests can extend it, while its complement would need the adversary modelled to be generated at all. Code where authentication terminates answers yes. Because a test is evidence about the input it uses, so any universal claim is beyond a suite whichever way it points. What singles out the negative one is discovery: a universal positive fails toward the user, who notices and reports, and the field generates inputs at a scale no suite matches; a universal negative fails toward an adversary, who is the only party that learns. Field discovery is what stands in for proof everywhere else in this model — the suite, and its users reporting what it missed — and this is the class where it is blind, so a check an agent drops is caught by a test that thought of it and by nothing else afterwards. The universal positive that lacks field discovery too — every valid rollback succeeds, learnt during an incident — falls to AIFIRST-33's question rather than to this one. Accepting that such a unit may be lifecycle-shaped, and so the harder contract to author this early. Rejected code that only sets what a check admits, its input crafted by nobody, counted with the check — a suite with an oracle evidences it. Rejected "the defect would be silent" as the criterion — a specific silent failure is exactly what a conformance test catches, since one can feed the input that must be refused and watch the result, so visibility separates nothing. What defeats a suite is the quantifier, not the noise a failure makes.

AIFIRST-33. Weigh what being wrong leaves past any release. The question weighs in an error's cost, for a unit's line (AIFIRST-31): can being wrong be taken back? The model trades on a defect costing one unit's regeneration. Where being wrong instead leaves what outlives any release — state written to a disk, which a later release has to read, or state destroyed there; a node left unreachable — or disables the path by which everything else is repaired, that is no longer the trade being made, and review reduces the risk without removing it. A breach is AIFIRST-07's question. Because the model's economics assume that being wrong costs a regeneration. Where the cost lands on someone else and cannot be reversed, the cheapness of regenerating is not the question being asked. Because a breach is irreversible through its adversary, which AIFIRST-07 already weighs, while the repair path belongs here, a defect there making every later defect unrepairable. Because a format another release reads is state its writer leaves behind: fixtures pin it only for the examples they carry, so a regenerated writer can drift outside them, and the drift persists in what it wrote. Accepting that the question has no bright line — how far a consequence reaches is judged per unit, and recorded with its line's reason. Rejected a breach counted here as well, one failure as two reasons; the repair path folded into fan-out, a repair path being no matter of call sites; a contract across releases as a question of its own — beyond the state a writer leaves, what it caught is output another program reads live, which the next release can fix.

AIFIRST-12. Keep reviewed code by contracting it; generate SD from the corpus. Reviewed code worth keeping is drawn as a unit on DD, since SD takes nothing from DD but units; its API opens the loop in AIFIRST-09, and its CLI surface is reused. Churn that reaches it goes to SD first, by reverse substitution (AIFIRST-36). SD is generated from the corpus, taking reviewed code only as units. Because SD can take a DD body only as a unit, so reviewed code is either contracted or thrown away, and throwing working code away buys a regeneration and nothing else. Because generating SD over existing code would make its first act an evolution step over code that does not match the design — the operation the model concedes agents cannot do — and would give SD an agent-mutated descendant of DD's own history. Accepting more units than the other reasons would draw, each an API to keep. Rejected working code as a weight on the line alone, or as no reason at all — each regenerates working code nothing else draws; a seed alone, at the moment the lines start — reviewed code worth keeping is not confined to that moment, and a rule tied to it is a milestone's plan; an existing API alone as a reason to contract — a signature with no body worth keeping says nothing about whether the boundary must exist before generation.

AIFIRST-32. Give a concern a crate of its own only where it can part from the rest, and keep the unit graph closed and layered. Concerns share a crate unless one of them can move between lines without the others — its line differs now, or the churn or risk ahead will part them — or an executable or a unit, of this milestone or a later one, uses it but not them, or sharing one crate would close a cycle through another; otherwise a few large crates hold. A unit depends only on units and on third-party crates a human declared. Units form layers, every edge pointing down, and a data unit never depends on a lifecycle unit. Because a unit is swapped whole and supplied by one line, so the crate is the grain of every substitution: a crate mixing concerns on two lines could be supplied by neither, and one holding concerns that will part must be split under churn, when a split costs most. Because a data unit depending on a lifecycle unit hands every consumer a runtime, which is what a unit's shape weighs when it moves (AIFIRST-18). Accepting that whether two concerns will part is a forecast, judged pair by pair, and that a line changed later may split or merge crates. Rejected a crate per concern, which authors APIs for boundaries nothing crosses; a crate per line, which mixes units that start on different lines; users counted as executables alone, which merges concerns a later unit will use apart; layering discovered unit by unit.

AIFIRST-34. State what must hold across units, and let each API's author keep it and confirm the unit's line. Beside its units, a decomposition states the obligations that must hold across the milestone's code, each with the units owning the check it rests on, and the line each unit ships on; it designs no API. An obligation rests on units only: a crate whose API must keep one is a unit, never an SD crate. Whoever authors a unit's API decides how each obligation the unit touches is kept, and records it beside the obligation: by the API itself where an adversary chooses the input, its types and its checks leaving generated code around it no way past; by conformance tests written against the API where the input is the unit's own state (AIFIRST-14). An SD line, however reached, holds where every obligation its unit touches is kept so. While authoring the API, the author confirms the unit's line or changes it, amending the decomposition with the reason. Because an obligation that spans units — one unit's check, another's write, generated code between them — belongs to no single API, and the decomposition is the one page that sees them all. Because an API is designed as code, through its consumers (AIFIRST-09): a mechanism sketched in prose can be checked against nothing, while an obligation can be checked against the API once one exists. Because a suite is evidence for the inputs it uses, so where an adversary picks the input after the tests, only the API's own construction keeps the promise; a unit's own state is deterministic, and tests at its API reach it. Because whether an SD line holds turns on whether the API keeps the unit's obligations, which only its author knows, and only once the API exists. Because an agent-owned API changes with every regeneration, so neither its types nor tests written against it can hold an obligation. Accepting that a decomposition's lines may change until its milestone ships. Rejected a mechanism sketched for each obligation — a type only the check can construct, say — which designs APIs before anyone works on them and settles less than it seems, evidence that a check ran not being evidence of what it compared against; an obligation counted kept only where the API's types rule its breach out, which counts every way code can go wrong rather than the inputs an adversary chooses; units and lines alone, which leave an obligation spanning units to whichever author notices it; obligations held by the security design, when not every obligation is a security one and their checks live in units; lines settled in one review after the last API, or frozen before generation.

AIFIRST-09. Arrive at a unit's API by generating consumers and judging the result. The agent proposes an API and generates consumers against it; the human judges and iterates. A concern a third-party standard already defines needs no interface of ours — an event stream or a counter mechanism, say — though what the product emits through it is a surface of its own. Because consumers are what reveal a bad API, and generating throwaway consumers is cheap. This recreates the practice loop that normally makes APIs good. Because API churn is cheapest at the start, while DD has no call sites and SD is small, and grows more expensive on both sides afterwards. Front-load it. Rejected authoring APIs cold. Rejected extracting them from a generated implementation, which lets its accidents harden into the contract.

AIFIRST-35. Run a milestone as its design, its decomposition, its units' APIs, then generation. A milestone's code is generated after three steps, each depending on the one before: its scope and design in the corpus; its decomposition — crates and units drawn, lines set, obligations stated; and each unit's API, authored through generated consumers, keeping its obligations and confirming its line. Generation then runs against the tagged APIs, whether their bodies exist yet or not (AIFIRST-27). Because the steps are dependencies, not dates: generation needs the contracts (AIFIRST-04), the contracts need units drawn (AIFIRST-31), and the units need the milestone's design — an order that holds for any milestone, which makes it the doctrine's rather than a plan. Rejected the order told in prose alone, where nobody checks a milestone against it; the order left to each milestone's tracker, which holds dates and owners, not what must precede what.

Repositories and code flow

AIFIRST-10. Keep the lines in two repositories, flor and flor-dist. flor is the DD workspace, and it holds a crate for every unit, since a contract exists as compilable code before a body fills it (AIFIRST-27). flor-dist holds the SD implementations and the integration, assembles the graph, and packages every executable. They share no history. Binaries live in flor-dist because they are integration, not because a unit may not be one: where a binary's own logic has to be reviewed it becomes a unit like any other, with its crate in flor. Cargo builds a workspace's own bin targets and not a dependency's, so the executable is produced in flor-dist by a one-line main over that unit's entry point — assembly rather than implementation, and human-owned like the manifest around it. Because the review regimes are incompatible: DD requires review of every change and SD forbids it, so one repository would mean one CI, one CODEOWNERS and one set of protections covering opposite rules, with misclassification silent. Because SD's history is regeneration-shaped, and wholesale rewrites in the same log would degrade blame and bisect for the line that depends on them. Accepting that a DD binary runs in flor only against whatever bodies exist there; its real exercise is the suite at the product's edge, which only flor-dist can run. Rejected branches or directories in one repository — a boundary held by discipline breaks on one inattentive command. Rejected naming the SD repository for the product — it is read mainly by agents and is not a front door. Rejected forbidding a binary-shaped unit: what a unit names is a contract and the assembly decides which line satisfies it (AIFIRST-11), so a DD binary needs no dependency running from flor into flor-dist, and its logic can be reviewed while it sits above generated units.

AIFIRST-11. Move DD code to SD as git-tagged crates, and publish nothing. Each unit is its own crate, tagged on demand: when it becomes substitutable, or when a fix must reach SD. flor-dist's workspace root is the single place that says which line supplies each unit — a dependency it declares itself by source, a path for an SD implementation and a git tag for a DD one; a dependency declared inside a DD crate by a [patch] entry over the flor source, which reaches transitively and unifies the graph. Substitution is a one-line edit there either way, and the patch table is a standing inventory of which units are generated now. Nothing goes to crates.io. Because a copy would make every fix a two-site change, and duplication in the security core is the worst case of it. Because publishing internal APIs creates an accidental SDK the real one would have to disambiguate — and a unit crate on a registry would have no user, since nothing but our own assembly builds against it. Because the graph will otherwise carry a unit twice and say nothing about it: Cargo resolves two revisions of one unit without complaint, and the compiler objects only where a type crosses between the copies — otherwise the product ships two of the unit and of whatever state it holds. So the assembly carries an invariant of its own: each unit resolves to exactly one package in every build configuration, enforced mechanically, and scoped to our own units so that ordinary third-party duplicates cannot mute it. Because that check is also what keeps pins per unit rather than repository-wide: units that depend on one another are forced to a common revision by it, and units that do not are left independent — which is the constraint the dependency graph actually imposes, rather than a coarser one declared over the whole repository and paid for by dragging every unit's unreleased work along with each bump. Accepting that flor and florete may be taken by someone else; the binary name, the crate names and the brand do not depend on the registry. Accepting one more mechanical check in flor-dist's CI, and that a duplicate unit is diagnosed rather than prevented. Revisit when a third-party SDK is designed. Rejected vendoring a copy.

AIFIRST-27. Generate against contracts, and turn every reliance on a body into a finding. Generating agents build against the real flor — a git dependency checks out its whole tree, bodies and suite included — and are instructed to code against each unit's public API and documentation. Reading a body is not forbidden; relying on what a contract does not state is reported instead: wherever generated code depends on behaviour the contract leaves unsaid, however the agent learned it, the agent files a finding. A contract may still be tagged before its body exists — a crate whose functions are unimplemented still yields a complete interface — so SD generates against a frozen contract while DD fills it in, and only the assembly move waits for a working implementation. Because an agent that relies on a body codes against observed behaviour rather than against the contract, and the invariants it picks up that way become load-bearing without being written down — the coupling the contracts exist to prevent, and one that surfaces as a silent break the next time DD refactors. Because that coupling forms where a contract is silent: an agent reads a body exactly when the interface does not answer its question, so what does the damage is less the reading than the gap it closes without anyone learning of it. Reported, the reliance is a finding (AIFIRST-19) and the contract improves; unreported, a gap in the corpus is papered over. Because keeping bodies out mechanically is not a boundary worth holding. flor is public and every build of flor-dist checks it out, so an environment airtight against it must also give up the web, local runs against the reviewed crates, and the upstream material generation draws on — and the gain would stay partial even then, since an agent that runs the product observes behaviour through the interface whether or not it reads a body. Accepting that the boundary is held by instruction and audited after the fact rather than prevented: what an agent opened is in its transcript. Accepting that the suite is reachable the same way, since it sits in the same tree, so AIFIRST-28 is held by the same instruction and the same audit. Rejected building generation against interface-only stand-ins of flor, in an environment with no route to it — mechanical, at the price of an extractor to maintain, no local run of any reviewed path, and an environment cut off from the web, for a gain black-box observation erodes anyway. Rejected a separate contracts repository — it splits a contract from its implementation across repositories, multiplying the cost of API churn, which is heaviest while APIs are first authored. Rejected <unit>-api interface crates — the standard Rust shape, but it re-expresses a contract as traits and forces indirection at every call site, to buy a mechanical isolation this model has chosen not to pay for.

Change and substitution

AIFIRST-13. Substitute by a fixed sequence, deleting the SD implementation last. Freeze the unit's contract; have flor-dist build a second configuration taking the DD crate by git tag; require the suite green in both configurations; land the assembly move; then delete the SD implementation. Because deleting last keeps every earlier step reversible by the same one-line change, and running both configurations catches a DD crate that passes on its own terms while changing behaviour the product depends on. Rejected substituting automatically on a DD release — it couples a release decision to a product decision and removes the human from a change that reaches customers.

AIFIRST-14. Hold the conformance suite in flor, append-only and black-box over a contract. The suite is implementation-independent, human-owned, never regenerated, and black-box over a contract — the product's edge or a unit's API, never a body. It holds conformance tests, written against a contract, at a unit's API as well as at the product's edge, saying what the product promises; regression tests, one per defect found, each with a human-written line saying what went wrong; and golden fixtures, examples the product must read, write or transform exactly, which are corpus as well (AIFIRST-26). flor-dist's CI executes all of it, since only it builds the product, in both configurations during a substitution window; flor's CI also runs the tests at a unit's API against DD's bodies. A component's own unit tests are not part of the suite and are regenerated with the component. Because a regenerated component returns with different bugs, and the accumulated capture of every bug already found is the only thing between that and a customer. Because the same suite must be green on both sides of a substitution, so it can belong to neither implementation. Because a unit's API is a contract like any other, and an obligation over a unit's own state is reached cheaply at its API and only partly through the product's edge. Accepting that it grows monotonically and gets slow. Accepting that each test at a unit's API constrains every later regeneration of that unit — held in check because a conformance test's obligation must be derivable from the corpus — and that a unit tagged before its body exists runs those tests in flor-dist alone. Rejected the suite at the product's edge alone, which holds an API's meaning only as far as the product shows it; tests at a unit's API only for an obligation its line rests on, a door narrower than the reason; a conformance kit per unit beside the suite, a second artifact doing the suite's job under other rules. Rejected pruning it — a test is amended, or where a design deliberately drops the behaviour it covers removed outright, but either way traceably to the decision that did it, since append-only decays one undocumented exception at a time. What is refused is deletion because a test is inconvenient, slow or failing.

AIFIRST-28. Keep the suite a gate at generation and an input at patching. The generating agent does not read the suite beyond its golden fixtures, which are corpus. It reads the corpus, and afterwards the suite judges what it produced; only once a test fails does that test become input — a regression test with its line saying what went wrong — which is the patching rule already. The rest of the suite sits in flor, in the tree generation builds against, so it is hidden by instruction rather than by isolation: generation is told not to read it, and records each read it makes anyway with its reason — which test, and what the corpus failed to say. Each record is a finding against the corpus (AIFIRST-19); transcripts are the audit for a read left unrecorded. Because an implementation generated to satisfy an append-only suite converges toward the implementations whose defects filled it, which is the opposite of coming back different — and where the suite is silent the agent fills the gap arbitrarily, while a wrong test simply becomes the specification with nothing pushing back. Because a failure then carries information: either the agent misread the corpus, or the corpus and the suite disagree. Read as a finding, that is the reality check SD exists to provide. Because a conformance test's obligation belongs in the corpus in any case — the test is the executable form of a promise, not a new requirement — so a test whose obligation cannot be derived from the corpus is a gap in the corpus rather than a rule hidden from the line that has to satisfy it. Because a read the agent records names the gap that forced it, and a gap named is one the corpus can close; a read nobody records leaves it open. Because nothing else needs to be visible before generation: a defect that shows a gap in the corpus is closed in the corpus, where every later generation reads it, and a failing test reaches the agent whole at patching. Accepting a patching phase after every generation, paid in tokens and wall-clock, where showing the suite would have bought a faster first green. Revisit once one generation can compare the two costs for real. The recorded fallback is to expose the suite at generation and accept the convergence. Revisit when regenerations keep reintroducing defects the suite already catches: then publish the regression tests' lines before generation. Rejected a defect ledger visible before generation, a mechanism designed ahead of any need for it; a suite run's output in its place, whose failure messages carry the assertions; a list of known traps in the corpus, lessons written before anyone knows they are needed; the fixtures hidden with the rest, which leaves generation reproducing a shape written out in prose, drifting from the fixture that checks it.

AIFIRST-15. Split the human loop by property and by contract. Humans own scope, acceptance criteria, failure-mode enumeration, the security boundary, the suite, the runbook, and every contract. On DD they also own structure, naming and the review of every change. On SD they own none of those, and no generated code is reviewed. Because the properties agents fail at do not fail together: happy-path correctness is good, evolvability is deliberately sacrificed, and failure-path and security correctness are weak. Because what an edit drops is what nothing else catches: an agent can delete the line that verifies something and leave every test passing, and on a line nobody reads that goes unnoticed. Reading the change is the only check against an omission — the diff, or for a piece regenerated whole, its pins and a comparison of its two versions (AIFIRST-29) — which is why DD has it, and why a unit whose omissions would be a breach weighs toward DD. Accepting that this is the model's largest recurring human cost.

AIFIRST-16. Regenerate the unit; patch only behind a failing suite test. The unit of change on SD is the unit, regenerated from the corpus — from whatever context the agent gathers, no page map. A patch is admissible only once a failing conformance-suite test exists. A defect invisible at the suite's altitude may be fixed against the component's own tests, and is understood to be discarded at the next regeneration. Because admissibility must be decidable without reading the code, and a failing test is an objective trigger. Because a fix justified only by a unit test loses its justification at the next regeneration, and goes with it.

AIFIRST-17. Regenerate on a defect ceiling, a contract change or a scope shift. Any of the three triggers a regeneration: fixes reliably producing new defects, a contract the implementation behind it cannot absorb, or a milestone whose requirements diverge enough that adapting costs more than generating. Because all three are visible from outside the code, and the append-only suite makes any of them safe to act on. Accepting that the defect ceiling is noisy and its first firing is a judgement rather than a threshold crossing.

AIFIRST-18. Choose what moves DD-ward by trigger, and read the frontier off the assembly. Movement is triggered by a security finding, by the defect ceiling, or by an obligation the unit's SD line cannot keep, or keeps only convolutedly — judged by its API's author while authoring the API, or raised by a finding later — and never by quota. Until the move lands, the unit ships on SD with that obligation recorded as unkept in its decomposition (AIFIRST-02). Among triggered candidates, severity decides and shape breaks ties — data-shaped units substitute into any consumer, lifecycle-shaped ones impose a runtime. A unit may move once everything it depends on is contracted, not once its dependencies are DD-authored. The DD-authored share, of the units and of the security-relevant surface, and the moves either way are read off the assembly, which says which line supplies each unit. Because the failure mode is a frontier that never advances, and naming the units that moved shows it without dictating a response — which a bare share would not, since we define the units it counts. Because an obligation SD cannot keep is what makes an SD line wrong, whether it is found while the API is authored or later, and not every obligation is a security one. Rejected a fixed effort split, which turns judgement into arithmetic that whoever is behind will game; an unkept obligation as a blocker on the release, which paces releasing by DD's body.

AIFIRST-36. Take churn reaching a DD unit on SD first, and bring the unit back after the release. When a milestone's churn reaches a DD unit, SD implements its new contract first: the assembly redirects the unit to SD's crate by a [patch] entry, and generation supplies the body. The milestone ships the unit on SD, and its decomposition says so, with the reason (AIFIRST-02). That SD line is held to the test any SD line is (AIFIRST-34), an obligation it cannot keep recorded as unkept. The move defers the unit's review rather than reclassifying it: in the gap after the release DD writes the new contract's body itself (AIFIRST-25) and substitutes it back by the fixed sequence (AIFIRST-13), and keeping the unit on SD past that milestone takes a later decomposition saying so, with the reason. Because releasing first applies to churn as much as to new units. Because a deferral that needs a fresh trigger to end becomes a reclassification by default, the frontier slipping back with nobody deciding it. Because nothing flows out of SD except findings: adopting SD's body would give DD code its review did not produce. Accepting that the unit's review lapses for a milestone, the suite again its only evidence; and that catching up competes with the next milestone's work for the gap. Rejected DD drawn only around stable cores, when churn arrives where it arrives — often where working code was kept; a stricter test for a reverse-substituted line, which reinstates a mandate where a human's call stands; the line left DD while the unit ships on SD, under which a decomposition states what its milestone does not ship.

AIFIRST-29. On DD, shed erosion by controlled regeneration below the unit. Regeneration is how generated text sheds the erosion edits accumulate, and DD uses it too — below the unit. A smaller scope of regeneration buys human control: a function or a section of design prose may be regenerated, a whole contract implementation or design doc shouldn't. It is refactoring with generation as its engine: what matters is pinned before the step and checked after it — in code by the component's own tests, held fixed through the step; in prose by a reviewed extraction of what the section carries beyond its log and Shape, and of what is erosion to be dropped — and an agent compares the two versions once the step is done. The review then reads the new version whole rather than the diff. Because DD exists to be read — for evidence, for diagnosis, for feedback into the corpus — and erosion accumulated edit by edit would cost it exactly that. Because a diff between a piece and its regeneration is mostly noise, while the whole new version can be judged against decisions that are fixed, and a deviation from them is detectable by an agent as well as by a human. Because the fixed points are what make the rest safe to regenerate: contracts, shapes and decision logs are amended in place and never regenerated. Accepting that the pins are themselves generated, and so carry the omission risk they exist to contain. They are short enough to review for completeness, and extracting them in another context than the one regenerating keeps the two from sharing a blind spot. Accepting that pinning tests are the component's own, not the suite (AIFIRST-14): they hold for one step and are not corpus. Revisit the techniques themselves: pinning and comparison are what we use now, they are expected to change, and their design belongs to the workflows that run them rather than to this page.

Findings and public posture

AIFIRST-19. Route findings and conflicts through a design pass. What SD learns is filed against the corpus and enters through a design pass, never as a direct amendment. Where SD's working behaviour contradicts a corpus decision, neither side wins automatically: the conflict is such a finding, carrying the deployed behaviour as a fact rather than a proposal. A contract is corpus (AIFIRST-26), so this covers contracts too: an agent that finds a unit's API wrong or missing something proposes the change as a finding, and a human takes it through the pass. Wanting a different contract is one of the more useful things generation can report, and it is still not a licence to write one. Because an amendment made under release pressure is a design decision taken without the gates, and that is how the corpus stops being the shared upstream. Because a corpus decision may be wrong — the reality check SD exists to provide — and SD may simply have improvised. Nothing about the conflict itself says which.

AIFIRST-20. Publish both repositories; accept contributions only to flor. flor is open to contribution. flor-dist is public for customer due diligence but read-only: a defect there is reported as a failing suite test against flor. Because a patch to SD would be discarded at the next regeneration, wasting the contributor's work, while a test survives every future implementation of that unit. Accepting that a public repository refusing patches must say so plainly, or every drive-by pull request is a small betrayal.

AIFIRST-21. State provenance as the engineering model, not as an AI disclosure. The repositories and the product documentation describe the model and its current state, including the DD-authored share. Version output and release notes carry none of it. Because "parts of this are AI-generated" is the sentence a slop project also writes, so as a disclosure it carries no information. The discriminating claim is that the boundaries are human-owned and the units are being replaced by reviewed implementations, which no vibe-coded product can say.

Cadence

AIFIRST-22. Obsolete: what a release promises is a product's decision, not the doctrine's.

AIFIRST-23. Obsolete: how releases are versioned is a product's decision, not the doctrine's

AIFIRST-24. Obsolete: how security is assured is a product's decision, not the doctrine's.

AIFIRST-25. Do DD work in the gap after a release. Because scheduling DD alongside SD puts them in competition for the core team, which SD wins every time — it has customers where DD has principles. Accepting that a release with a long defect tail eats its own gap, which is exactly when a unit most needs moving.

On this page