Construction technology report · Authoring and readback

A Revit model that looks right is not yet evidence

Generating a plausible building model is now the easy part. The hard part is being able to say, afterwards, exactly which elements exist, what they are, what they are attached to, which decision each one came from, and which questions nobody asked.

Five-stage loop: source-backed requirements, a resident C-sharp Revit API executor, native Revit elements, engine readback, and a human gate that accepts, revises, or holds the result
The executor carries a defined request into Revit and returns evidence about what the engine now holds. It is not permitted to decide that its own output is correct.

A model can be wrong in ways no view will show you

Open an automatically generated residential model, orbit it once, and you will form an opinion within a few seconds. Walls stand where walls belong. Openings look like openings. Floors meet walls. Nothing is floating. The opinion feels like verification, and it is not, because a view answers exactly one question: is there geometry here that resembles the thing I expected to see?

Three whole categories of defect are invisible to that question, and they are the ones that cost money later.

Misclassification. Something can occupy the correct coordinates while being the wrong kind of thing. A model line drawn where a wall belongs. A generic form standing in for a structural member. An element assigned to the level above the one it visually sits on, because its base offset compensates. Each renders perfectly and behaves incorrectly in every schedule, filter, view range, and downstream export that will ever touch it.

Absence. A view can only show what exists. It has no way of drawing your attention to the twelfth opening that was supposed to be created and was not, or to the run of members that a constraint quietly prevented. The eye is very good at recognizing a pattern and very bad at noticing that the pattern is one item short.

Loss of attribution. An element can be geometrically perfect and still be an orphan: nothing on it records which requirement it satisfies, which revision of the definition produced it, or which earlier element it replaced. It looks like a finished model and functions as an unsourced assertion. Every later question — did this change, was this approved, does this quantity belong to that scope — becomes a manual reconstruction.

None of this is an argument against generating models. It is an argument that generation and verification are two different activities, and that the second one cannot be performed with your eyes.

“Native” means the engine will answer questions about it

The word native gets used loosely in BIM automation, usually to mean “made inside the authoring tool rather than imported.” That is true but not the useful part. The useful part is this: a native element is one the authoring engine will answer questions about.

Concretely, a native Revit element participates in the mechanisms that make a model interrogable rather than merely visible:

  • It has an identity the engine maintains. It can be found again after the file is closed and reopened, referenced from another element, and compared with its own earlier state.
  • It belongs to a category. Category membership is what lets a query ask for “all of these” and get a population back, rather than a bag of shapes that happen to look similar.
  • It carries a parameter surface. Type and instance parameters give the element somewhere to hold the identifiers, revision markers, and classification data that make attribution possible at all.
  • It participates in relationships. Hosting, level association, containment, joins, and analytical association are engine-maintained facts, not visual coincidences. This is what makes it possible to ask whether an opening belongs to the wall it appears to sit in.
  • It appears in the derived artifacts. Schedules, views, filters, and coordination exports read the same element the query reads. When the element is right, everything derived from it inherits that correctness. When it is wrong, everything derived from it inherits the error consistently, which is why the error is so hard to spot.

Geometry that merely renders has none of these properties. It cannot be counted by category, cannot host anything, cannot carry an identifier that survives a round trip, and cannot be compared against its previous revision. It can be looked at. That is the whole of its contribution.

This is also why “the model is finished” is a weaker statement than teams assume. A model can be visually complete and interrogably empty. The right question is not how much of the building is drawn, but how much of the building is stated in a form the engine will testify about.

Choosing what to make native is itself a scoping decision. Not every physical detail belongs in one model at one level of development, and forcing it there produces a model that is expensive to maintain and still not a fabrication source. The discipline is to state, for each class of content, what the element represents, which decisions it is allowed to support, and which details remain with engineering, supplier, fabrication, or field processes. Our report on scoping automation by acceptance criterion deals with that triage in general terms; this report deals with what happens once the decision to author something has been made.

Four responsibilities, and why they must not merge

An automated authoring run touches four different responsibilities. Most of the trouble in this field comes from letting two of them collapse into one.

  1. The request defines intent. A controlled, revisioned definition states what should exist: geometry, component identities, interfaces, constraints, and the revision under which those were decided. It is authored by people with the standing to decide those things. It is not a chat message, a screenshot, or whatever was most recently open.
  2. The executor performs a bounded operation. A component inside Revit receives that request, creates or updates the admitted content, and stops. Its scope is stated in advance, including what it may never touch. Its completion is a fact about the operation, not about the building.
  3. The engine holds the truth. Once the operation ends, the authoritative statement of what exists is the Revit document itself — not the executor's log, not the request, and not anyone's recollection of what was intended.
  4. A responsible party disposes of the result. Somebody with standing decides whether the evidence is sufficient for the next decision, and records what that acceptance covers. This is the step that is silently deleted when an automation reports “success.”

To be specific about our own implementation, because the industry conversation is currently muddled on this point: K&K does not use MCP to control Revit. Our implemented approach uses an internal C# Revit API add-in that receives a defined modeling request, creates admitted native BIM content inside Revit, and returns structured evidence about the result. We keep the public description at this architectural level deliberately; deployment details, control files, safeguards, and internal source structure are not part of the public interface.

Where protocol servers, agents, or assistants appear in our work, they sit in the coordination and discovery layer: helping locate material, route a request, or organize a conversation about a project. They are not the Revit execution layer, and they are not the engineering source of truth. A protocol call that returns successfully has established something about a message. It has established nothing about a model. The same caution applies to retrieval and vector search during research — those tools help find where a fact might live, and the fact itself still has to be traced to the file, engine, or physical object that actually holds it.

The reason to be pedantic about the four responsibilities is diagnostic, not rhetorical. When they stay separate, a failure can be returned to the stage that owns it. When they merge, every failure looks like the same failure: “the automation is unreliable.” That sentence has never once led to a repair.

The persistence boundary between an open session and a reopened document Two panels separated by a persistence boundary. On the left, the state inside an open authoring session: elements inside a transaction that has not been committed, geometry awaiting regeneration, warnings held by an in-process handler, and elements the engine may still remove. On the right, the state of a document that has been saved, closed, and reopened in a fresh session, which is the only state a readback should be asked to describe. A caption notes that evidence gathered before the boundary describes an intention, and evidence gathered after it describes a file. Where the evidence is allowed to be collected A readback taken before the persistence boundary describes an intention, not a file. BEFORE THE BOUNDARY Inside the open session Elements inside a transaction not yet committed Geometry awaiting regeneration Warnings held by an in-process handler Elements the engine may still remove Constraints not yet resolved against neighbors Answers the question: what did I ask for? AFTER THE BOUNDARY Saved, closed, reopened Only committed elements remain Geometry has been regenerated Warnings are the document’s own record Engine-side removals have already happened Queries run against a state a reviewer can reopen Answers the question: what do I have? PERSISTENCE BOUNDARY — save, close, reopen
The two panels are frequently different, and the difference is never in your favor. Evidence collected on the left has to be re-collected on the right before anyone plans work around it.

The session is a claim; the reopened document is a fact

This is the part of the workflow that teams skip, and it is the part that catches the most embarrassing class of error.

When an authoring routine finishes, the state it can describe is the state of its own process: the elements it believes it created, the parameters it believes it set, the operations that returned without throwing. That state is a claim, and it is a claim made by the party with the strongest interest in the answer. Several ordinary things can make it false without anything appearing to go wrong:

  • Work performed inside a transaction that is rolled back, discarded, or never committed, so the elements never reach the document at all.
  • Geometry that has not been regenerated, so positions, joins, and derived dimensions still reflect a pre-update state.
  • An in-process failure handler that resolves a warning by deleting the offending element — a resolution the routine may register as success.
  • Constraints that only resolve against neighboring elements once the document is fully processed, changing positions after the routine has already reported.
  • Elements created correctly, then removed by the engine as a consequence of a later operation in the same run.

The remedy is unglamorous and completely reliable: save, close, and reopen the document in a fresh session, then collect the evidence. A cold-open readback has no memory of what was intended. It can only describe what the file contains. That is precisely the property that makes it worth something.

Two secondary benefits fall out of the same discipline. The first is that a reopened document can be read by a process that had nothing to do with creating it, which removes the producer as the sole witness to its own work. The second is that the difference between the in-session claim and the reopened result is itself a diagnostic signal — a persistent gap between the two usually points at transaction or regeneration handling rather than at the definition.

Where a project's workflow requires it, the same reasoning extends to the shared-model layer: a change is only durable once it has reached the state other people will open, not merely the state the author is looking at.

What a readback record has to contain

“The model passed” is not a readback. It is a summary of a readback that nobody can now inspect, which makes it functionally identical to an assertion. A useful record has a shape, and the shape is more important than any particular field name.

The nine groups below describe that shape at a conceptual level. They are deliberately expressed as questions the record must be able to answer rather than as an internal schema; the implementation detail, field naming, and control structures are not part of the public interface.

The nine groups of a readback record A three by three arrangement of record groups. Run envelope: which definition and revision drove the run, and which document was read. Admitted scope: what the operation could create, modify, or delete, and what it could not touch. Declared population: what the definition expected to exist when the run finished. Observed population: what a fresh query of the reopened document returns, by category. Per item disposition: created, updated, matched, substituted, skipped, refused, or never attempted. Identity assertions: every element carries its source key and revision marker, and no key appears twice. Relationship assertions: host resolution, level assignment, containment, and required joins. Engine diagnostics: warnings by class, exceptions, and elements the engine removed on its own. Unread scope: the properties this readback did not query, recorded so silence is not mistaken for a pass. The shape of a readback record Nine groups. The ninth is the one most reports omit and the one reviewers need most. 01Run envelopeWhich definition, at whichrevision, drove this run, andwhich document was read 02Admitted scopeWhat the operation couldcreate, modify or delete —and what it must not touch 03Declared populationWhat the definition expectedto exist once the run hadfinished 04Observed populationWhat a fresh query of thereopened document actuallyreturns, by category 05Per-item dispositionCreated, updated, matched,substituted, skipped, refusedor never attempted 06Identity assertionsEvery element carries itssource key and revisionmarker; no key appears twice 07Relationship assertionsHost resolution, levelassignment, containmentand required joins 08Engine diagnosticsWarnings by class, exceptions,and elements the engineremoved on its own 09Unread scopeThe properties this readbackdid not query, so silence isnot mistaken for a pass A record without group 09 cannot be over-quoted safely, because nothing marks its edge.
Groups 01 to 08 describe what was found. Group 09 describes what was never looked at, which is the only part of the record that limits how far the result can be quoted.

Declare the population before you count it

Groups 03 and 04 are worth separating out, because the relationship between them is where most reporting quietly goes wrong.

A report generated by walking through what happened can only ever list what happened. It is structurally incapable of revealing an omission, because an element that was never attempted leaves no trace to walk through. Reading such a report and concluding that everything was created is a logical error, not a judgment call: the report answers “what did the run do?” and the reader is asking “what should exist and does?”

The fix is to declare the expected population first, from the definition rather than from the run, and then to compare in both directions. Missing items — declared and not observed — are the obvious half. Unexpected items — observed and not declared — are the half teams forget, and they are often more informative, because they point at content created outside the admitted scope, left over from a previous state, or duplicated by a re-run.

The same logic explains why group 09 exists. A readback that queried category, level, and host has said nothing whatsoever about parameters it never read. If the record does not state that boundary, the next reader will assume the check was complete, and a narrow result will be quoted to close a broad question months later, by someone who was not in the room. Writing down what was not examined costs one paragraph and prevents an entire genre of dispute. Our series hub sets out the general rule this follows: never let a claim inherit the confidence of the evidence beneath it.

Six classes of failure, and where each one belongs

When a readback disagrees with a declaration, the useful next question is not “is the automation broken?” It is “which stage owns this?” The classification below exists so that a difference can be routed to a repair rather than to a mood.

Six failure classes and the stage each one returns to Six rows pairing a failure class with the stage that owns its repair. A definition fault returns to the source definition and its author. An admission fault returns to whoever set the operation scope. An authoring fault returns to the operation definition or the content library. A persistence fault returns to transaction and regeneration handling. An attribution fault returns to identity propagation and blocks every downstream comparison. An observation fault returns to the readback definition itself, and is the only class that hides all the others. Failure class determines the return address “The automation is unreliable” is not a class and has never led to a repair. CLASS RETURNS TO ADefinition faultThe request was ambiguous, incomplete or inconsistentThe source definition and its author BAdmission faultThe run was asked to touch what it may not touchWhoever set the operation scope CAuthoring faultMissing host, unsatisfiable constraint, unavailable typeOperation definition or content library DPersistence faultPresent in session, absent from the reopened documentTransaction and regeneration handling EAttribution faultExists, but cannot be tied to the decision that made itIdentity propagation — blocks all comparison FObservation faultNobody looked, and the report is silent about the gapThe readback definition — hides every other class
Class F is the only one that cannot be found by reading the report, because the report is the thing that failed. It is found by comparing the readback’s declared coverage against the decision the result is about to support.

How each class behaves in practice

Class A, definition fault. The readback is clean and the model is wrong, because the request faithfully described the wrong thing. This is the class that a perfect execution cannot protect you from, and it is why the definition needs its own review before it is executed against, not after.

Class B, admission fault. The request reaches for content outside the operation's permitted scope. The correct behavior is to stop and report, not to improvise. An automation that quietly widens its own scope has removed the only mechanism that made it safe to run unattended.

Class C, authoring fault. The engine declines: no host exists at the required location, a constraint cannot be satisfied, a required type is not present in the document. These are the honest failures — they announce themselves — provided the operation reports the refusal rather than falling back to a nearest available substitute without saying so.

Class D, persistence fault. The element was there and now is not. This class exists only because the persistence boundary is checked; teams that read evidence from the live session never see it, which does not mean they do not have it.

Class E, attribution fault. The element exists, is correct, and is unattributable: no source key, a duplicated key, or a key that has been reused for something it no longer describes. This class is corrosive out of proportion to its frequency, because identity is the precondition for every comparison that follows — revision differencing, quantity scoping, approval tracing. A model with broken attribution cannot be compared with anything, including itself.

Class F, observation fault. The check did not run, or ran against a narrower scope than the decision requires, and the record does not say so. This is the class that group 09 of the record exists to expose. The hub report catalogs the silent failure modes that class F allows to survive; the point here is structural rather than anecdotal — a verification system with no statement of its own coverage cannot be audited, only trusted.

The short version. Author native elements so the engine can testify about them. Collect evidence from a reopened document, not a live session. Declare the expected population before you count the observed one. Record what you did not check. Route each difference to the stage that owns it, and keep the party that produced a result from being its only reviewer.

Three statements of the same thing, and three separate comparisons

A model readback compares two things: what was declared and what the document contains. It is easy, and expensive, to let that comparison stand in for two others that it cannot perform.

Any physical component in a project is described three times. It is declared in the definition that says what should be built. It is modeled as a native element that a query can describe. And it is eventually realized as a produced and installed object with its own measurable condition. Three descriptions mean three comparisons, each with a different method and a different owner:

  • Declaration against model. This is the readback described above. It closes questions about the information system and nothing else. It is performed by querying the reopened document.
  • Model against produced object. This is a production and supplier question, answered by approved production data, inspection of the component, and the supplier's own records. A model can state what a panel is supposed to be; only the panel can tell you what it is.
  • Produced object against installed condition. This is a field question, answered by observation before the condition is concealed. Position, fit, tolerance take-up, and the interfaces that turned out differently from the drawing all live here.

The failure mode is substitution: quoting a clean readback as though it addressed the second or third comparison. It does not, and it never will, because the readback's only witness is a file. Keeping the three comparisons distinct is also what makes field evidence worth capturing in a structured form rather than as loose photographs — our field-evidence research note deals with that capture problem, and our project records and handover practice deals with keeping enough identity and context that a later reader can tell which of the three descriptions they are holding.

Attribution is the thread that lets the three be compared at all. If a native element carries the key of the requirement it satisfies, and a produced component carries the key of the element it represents, then a question asked at the far end of the chain has somewhere to go. Without that thread, each comparison becomes a manual reconstruction performed under schedule pressure by whoever is available.

A reviewer’s sequence for an automated run

The following is the order in which a reviewer should actually read the evidence from an authoring run. The order matters: several steps are pointless if an earlier one has failed, and doing them out of sequence produces confident conclusions about the wrong file.

  1. Read the envelope before the content. Which definition, at which revision, against which document? If the envelope does not match the thing you believe you are reviewing, stop here. Everything below is about a different subject.
  2. Confirm where the evidence came from. Was it collected from a reopened document or from the session that created it? Session-collected evidence is returned for re-collection, not argued with.
  3. Compare declared against observed, in both directions. List what is missing and what is unexpected. Do not accept a report that can only show what happened.
  4. Test identity next, because everything after it depends on it. Are source keys present on the elements that should carry them? Is any key duplicated? Has any key changed the thing it refers to since the last accepted state? An attribution failure here invalidates the remaining steps rather than adding to them.
  5. Ask the relationship questions the geometry cannot answer. Does each hosted element resolve to a host that exists? Is each element on the level it is meant to belong to, rather than the level it appears to sit on? Do the required containments and joins exist as engine facts?
  6. Read diagnostics by class, not by count. A single warning class that causes the engine to modify or remove elements matters more than a large number of benign ones. The question is which classes are present, and whether any of them changed the model.
  7. Read the unread-scope statement last, and treat it as the result. Whatever the record did not examine is still open, regardless of how clean the rest of the report looks. Then dispose: accept for a named purpose, revise, or hold — and write down which of the three you chose and what it covers.

Four conditions should stop the review outright rather than being weighed against the rest: an envelope that does not match the subject; evidence collected before the persistence boundary; a duplicated or reused identity; and an unread-scope statement that includes a property the next decision depends on. Each of these makes the remaining evidence unusable rather than merely weaker, and treating them as deductions instead of stops is how a review ends up ratifying a result it never actually examined.

What this sequence closes is bounded and worth stating plainly. It establishes that a document contains the content a definition declared, in the categories and relationships the definition specified, attributable to the revision that produced it. It does not establish that the definition described the right building, that the structure performs, that the components can be produced, or that anything was built as drawn. Those are separate gates with separate owners, and the evidence threshold each of them requires is set out in the hub report rather than restated here.

Where this workflow hands off

A verified native model is an input to other people's work, and the handoffs are where its value is either preserved or lost.

The most demanding of them is structural analysis, because the receiving engine returns numbers and numbers are persuasive. A model can pass every check in this report and still be idealized incorrectly for analysis — end fixity, effective length, restraint, and the stiffness credited to a connection are engineering decisions that no translator makes. Our companion report on keeping one building definition across BIM and structural analysis deals with that boundary specifically, including why a completed solver run is such a convincing piece of weak evidence.

The second is change. The workflow above describes a single run against a single revision; real projects revise continuously, and a verified model is only useful if the next accepted state can be compared with this one. That comparison is exactly what attribution makes possible, and what it costs when attribution is broken is the subject of our report on why design change is a relationship problem.

The third is production and field work. For panelized steel residential construction, a model earns its place when it supports real interfaces: repeatable components, openings, connections, packaging logic, transport constraints, erection sequence, trade access, and a record of what was installed. A project can define work for off-site preparation so that less has to be resolved from scratch in the field — which only helps if what was prepared off site is demonstrably the thing the project approved. The wider delivery context sits under our integrated project delivery capabilities, and the research program this method belongs to under technology and R&D, with the floor-plan-to-frame research workflow described in our housing system research note.

Why the pattern outlives Revit

Revit is the native authoring environment in this implementation, but nothing in the method depends on that. The pattern is: keep a controlled source with a revision identity; bound what any single operation may touch; create content the receiving engine will answer questions about; collect the evidence from a persisted state rather than a live one; declare what you expected before you count what you got; record what you did not check; and keep generation separate from approval.

That pattern applies wherever information crosses a boundary between systems that each believe they are authoritative — design to analysis, design to procurement, engineering to production, construction to operations. It also survives a change of tool, which is the practical test of whether a method was ever a method. If the safety argument has to be renegotiated every time the software changes, the argument was about the software.

The question worth asking of any automated construction workflow is not whether a machine produced the model. It is: which source drove which native result, what evidence came back from the system that holds it, what was never examined, and who is authorized to accept the next risk.

Public boundary

This report describes K&K's internal research method at a conceptual level. It omits implementation detail, control mechanisms, internal identifiers, customer information, project data, and unreleased engineering material by design. It is not a product certification, a released engineering capability, a permit set, a sealed structural design, a fabrication authorization, or a statement of performance, cost, or schedule.

K&K coordinates design and delivery interfaces with the required project professionals, and local licensed work and professional roles are defined for the actual jurisdiction. Project-specific architecture, engineering, code review, permitting, production, supplier confirmation, quality control, installation, inspection, and final acceptance remain with the applicable parties and authorities; our compliance and project-record practices describe how documentation supports that review without displacing it, and our project roles page sets out who holds what.

K&K's residential work is organized around permanent panelized steel homes, subject to project-specific design and approvals. If you are planning a permanent residential project, a multi-home site, workforce housing, or another repeatable building program, start with the project requirements and property conditions through our steel home program or contact page.