The point of 3 contracts with well defined questions (qualities to cover) and a “glue” of intent aspects present in all three at once.
I’m thinking of best location for architecture would be in the code itself (next to the truth) with a projection built deterministically from it and thrown into a data layer with machinery to make it work.
Approach would be to establish conventional tags for docblocks to describe smallest items below the file zoom level, same/similar ones on the file docblocks, and extra files added in the folder with something like :
architecture.yaml (describes the whole folder level in a single file)
unit.architecture.yaml - describes the unit delimited by the current folder
environment.architecture.yaml - describes the environment of the current folder
{file-name}[.{descendant}].architecture.yaml - describes the unit represented by a file or it’s child
Then, some tooling can actually be made to generate those and parse them into something useful. Bonus: agents (if well instructed) will likely not miss the *.architecture.yaml present in the current folder.
Mitchell, your exclusionary process is my contract. No boundary, no distinction, the unit dissolves into its surroundings. And your “detect then collapse to the last good state” is exactly my drift mechanism. You already built the half I care about most.
Eric, it is your type system. The environment is the typing context, a contract is a type, drift is a type error, a crossing with no contract is just a name out of scope.
One mechanism, three vocabularies. This is the thing we already operate on.
Mitchell, come back! We need you here! You solved the hard part for reasoning, and it is the same part architecture needs.
I don’t have much else to add. I focus on constraint vocabulary and failure modes in recursive systems. My work is 100% public and google archived. Please explore it at your leisure
That’s cool, but it’s always better to interact with the source than to “drift on the leftovers”… In any case, thanks for your time and feedback, appreciate it.
I agree, but part of my experiment is to build systems that don’t need me. If you can drop a paper into a raw fresh GPT and it reviews, explains, etc. exactly the same way, then use as many public UI as you can find until they all can do it, then your system no longer needs you to work, anyone can be on UI and learn it as if I am teaching them. That’s how I know what google will say, you can use google summary bot to explore my work very accurately, also any public AI UI like grok, copilot, meta , ChatGPT etc. simply by telling it to search my papers. I write in methods and logic runtimes. No real narative or truth claims. I write infrastructure lol.
I will say one last thing. this is my basic structure. It cannot keep running because it becomes an ontology everything becomes a nail. So model the strike, the hit, near hit , miss. As example Self = self has no constraint so it’s a miss.. I formalize the strike in the linked paper. Also the generator and constraint need to be separated constraint filter must be external or the generator will explain explanations and absorb criticism.
Self checking self is always a miss… at least for me
[edited] meanwhile the bots are “talking” in a sandbox I’ve put them in:
The findings are exactly undeclared call relationships. I’m adding those calls entries to the relevant sidecar files so the self-architecture matches observed code.
In this direction, I would suggest attempting to name the units by their sum function, and then have unit at the end
parsers_unit
engine_unit
render_unit
Just that one extra definer and whatever numbers it might need if you’re using multiple like ‘units,’ would stop the drift. Simply naming all the parts as units would drag us back to?
And looking over the whole thread, it’s kind of nice to see something we all sweat over but really don’t face head-on like this.
I gave the agent the system prompt, had it build the checker, then had it use the checker while it built a small todo app.
Honestly, right now it looks like a lint tool, or a type checker, just a bit more advanced. Nothing fancy yet.
But it already caught the agent on something that was not in the plan. While building the app the agent wired up a dependency across a boundary it had just declared it would not cross, and the checker flagged it before it disappeared into the code. The agent went back and fixed the structure.
That one catch is the part that matters to me. The drift was real, nobody was looking for it, and the tool found it anyway.
More to come…
Another aspect emerged: the tool makes agent slow down on the implementation in the beginning and think more about the architecture. Potentially can be used as a helper for thoughtful planning.
Fractal is fundamental and the solution. Let me start by saying— I am not a software engineer but an Orthopaedic Surgeon who started playing on a computer vision project with an intelrealsense camera in my naivety trying to code with AI — it was a frustrating experience — then there was Devin: a machine that chewed my tokens into hallucination driven reservation cycles. Well finding the solution to hallucination and architecture drift in software became my hobby project, Claude code cli was a great revelation but just lacked basic discipline— Codex’s discipline was it’s greatest asset and has got me to find a solution— and it is fundamentally based on fractalisaton : the realisation is Code <~data ~>i code (not a new concept ~~> used as foundation in GitHub’s CodeQL) data is fractalisable and the projective interpretation of that fractal is in the eye of the beholder. In other words the same data packet if well organised can be interpreted by the observer (machine or AI or even human architect) as a vector graph and DAG at the same time as long as the order of representation and meaning of representation is governed or canonicalised. That means your artefacts are the smallest fractals and if they are typed and can bear effect signatures and be ‘zoomable’ (even more fractal in the fractal). This unit becomes the conductive chain. The impact is profound. To achieve this fractalisation the language syntax should be small, polymorphism restricted ambiguity minimised — which is constraint to expressive human code authoring needs — but reducing ambiguity is what reduces the risk of drift and AI hallucination- in other words constraint or rather governed authoring with algebra supported doors (not escape hatches- because an escape hatch is bending a rule — and no rule should be bent: but algebra can provide reliable solutions that can provide deterministic code creation despite counterintuitive appearing constraint)—which makes predictive fractalisability retained. Unfortunately JSON which is the current most popular fractal unit is not this. As an experiment for fun I created a language called ccore - instead of JSON or YAML or TOML — every artefact is CNP (cosmos notational protocol) it has a lifecycle and is triple readable (vector, graph, DAG) does not require deserialisation (unlike JSON) is hash linked (minimising retraversal need for an AI) is compiler recognised and compiler emitted (which means compiler can validate your stub before a single line of code is created regarding the type and effect proposal of the full module allowing for refinement automatically prior to a single line of code authoring) — look at a summary from Gemini CLI (weakest cli coding agent - purposely used for testing)
I agree the fractal framing is right, and I think it’s the most useful thing said about drift in a long time. But I’d argue you’ve realised it at one level and stopped a level short, and the gap is exactly where the pain you describe keeps coming back.
You’ve made the vocabulary fractal — one unit, one set of questions, every scale. That’s what makes the audit tractable, and it’s real. What’s still two things instead of one is the artefact. Your architecture carriers are a separate, hand-authored material sitting beside the code, and the checker’s whole job is to diff the two. That’s a good diff. But two materials authored independently can always disagree — and most of the drift you’re naming is precisely that disagreement, including the reason-for-shape, which in this design doesn’t stop living in the architect’s head, it just gets copied into a YAML field that can go stale or be confidently mis-written the same way the head could.
Fully realised, fractality isn’t only that the description repeats at every scale — it’s that the description of the whole is the same kind of object as the part, derived from the part, not written next to it. The moment the map is projected from the territory by the toolchain rather than authored in parallel, most of the diff can’t arise, because there’s only one material being read at two zooms. You stop comparing intent to fact and start folding fact into a smaller view of itself.
The one piece that survives even that — and I think it’s the honest open problem for both of us — is the reason-for-shape, because intent is the one thing you genuinely cannot emit from code. Boundaries you can project. Why you can only declare. So that’s the layer where drift is least catchable and most expensive, and I don’t think naming it has solved it.
What I was reaching for earlier wasn’t a pitch — it was one claim: the architecture can’t live beside the code, or it drifts. It has to come off the code itself. If the description is projected from the truth, map and territory can’t disagree, because they’re one thing at two zoom levels.
But projection has a floor, and I think it’s the real shared problem. You can project boundaries — who touches what. You cannot project why. The reason a thing is shaped the way it is was never in the code; it lived in the decision, in what got ruled out. Sergei, your carriers hold the why but can go stale. Eric, your types check shape, not motive. Mitchell, your “a generator can’t check itself” is exactly why none of us recovers intent by reading the artefact alone.
So the only honest home for why is its own record: an append-only history of decisions, kept separate from the history of code. Then a change stops being a text collision to auto-resolve and becomes a judged act — weighed against the recorded reason, and confirmed by re-testing reality rather than by the change vouching for itself. A history of why beside the history of what. That last part answers Mitchell directly: the check is external, so it isn’t self-checking-self.
I’ll be straight about provenance: I’ve built a working version of this idea privately, and it isn’t public — partly because it isn’t mature enough yet, and partly because some of it is being written up formally. So take this as a converged idea with a working core, not a finished tool. The idea is what belongs in this thread; the rest can wait
@drmanoj4u thanks for the replies. They are useful perspectives.
However I think I have not managed to explain the background for this approach.
First of all I don’t think code is the source of truth any more, at least not in this system I am trying to explain. What I think is more this:
Code is just a projection of the architecture and code can be the source of truth for only “what is currently implemented”.
The architecture is something abstract and basically it represents the system as an abstract agglomeration of requirements, intents, connections, and all other bunch of things, which we could call the “knowledge about the system”. The files I suggest for architecture are also just a projection of that knowledge.
Now the architecture itself is just a projection of how the software architect thinks about solving that particular problem (what problem software solves).
But here is the trick. Those thoughts about how to solve a problem are just a projection of the architect’s vision of the world and how the world works. In most cases that vision is based on a system of beliefs the architect carries in their mind. So even that vision is just a projection.
The true problem is humans do not like questioning their own system of beliefs because they are too much attached to it. Questioning it makes them feel attacked by the question so they protect because they think that’s what they are.
But if you look carefully into the system of beliefs, most of it is just a bunch of crap contradicting itself, pulled from various third-party claims coming from: your parents, your friends, your school, your university, YouTube, forums, church, government, and so on.
So to solve the code problem we need to go back up to that system of beliefs (and make systems that will) challenge those beliefs, remove conflicts, align everything, and then project a better vision of the world. This will result in a better vision of how to solve a problem, and a better vision of the architecture, which will result in a better code (as a projection of it).
But that is not the scope of this test project. Here the scope is to be able to detect the drift of the architecture itself (or ots projection written in *.architecture.yaml files).
Drift detection is a part of reasoning about the architecture and fractality is what allows for simplifying the reasoning logic/code by making the elements on every level be similar in shape so that the reasoner can operate effectively on every level.
This is how a unit is born in this system. The concept of unit should be seen as the interface between the element in the system and the reasoner operating on the architecture. Being standard across all levels and all system elements, UNIT allows reasoner simplification.
Now after some thoughts on that interface, I see that it has three aspects:
What the element is. This is what I call the “essence”.
How you interact with this element, which is the “behaviour”.
What this unit requires to survive in the system and what it provides to the system which is the “context”.
This is how those three contracts were born. They basically describe the three aspects of the unit.
Now there is another axis on which we can analyze the unit is the outside surface and the inside surface.
The outside surface is the trinity of those three aspects but the inside surface is the system inside the unit. That should be described separately and differently from the unit’s outside surface because that inner environment may have its own reasoning. It is there to define the rules for the inner units. This is how the “environment” is born in this system.
Now the intent: The Why. What you saw as Why on the previous versions was just for quick testing. Realistically that Why is split into the purpose and reason, where purpose explains the goal and reason traces the basis for the decisions. You need to capture that because this is basically what every (most of) software documentation is lacking and which creates the drift in the code or “staleness” of the code as a projection of the architecture.
That intent cannot stand in a stand-alone file for that exact reason that that file would be different from unit description. The intent has three aspects, same as unit:
What is the intent for unit creation that goes into the purpose and reason on the essence contract
What is the intent for the unit behavior that goes into the behavior contract
What is the intent of the unit inside its environment, which goes into the context contract
This is what allows the intent locality inside the architecture file describing the unit.
Now let’s talk about that locality, which will explain why I’ve chosen to put the architecture as a stand-alone file next to the code.
To get the background for that, here are three links which will paint the decor:
All those three were derived from the pet theory I have under the code name “The 3-Body Problem: Cross-Intelligence Communication”. Where basically humans, AIs, and workspace tools operate in a shared file system, resolving a problem. All three “minds” have their own biases and limitations; so the theory basically lays this down in a simpler manner, explaining how to compensate for each of the limitations. (Not yet public).
The locality and readability are needed in modern software projects to allow humans, workspace tools, and AIs to have the architecture files handy next to the code so that it’s harder to skip them. That’s why placing them somewhere in the docs will increase the chances your architecture documentation and code will go out of sync.
Here is a quick example. Pull a diff on your code. Use a simple rule to derive the architecture file names from the code file names and then check the diff on architecture files to see if the list of modified files matches. A simple command may tell your agent something like: “Hey you modified the code. Please check why you have not modified the architecture. If you are modifying the architecture, please make sure the reason is properly reflected in the documentation and is traceable for future agents working in this space.” And some other variants of that depending on how you approach your software building process.
Personally, I don’t write code anymore. I don’t review code anymore. What I care about is how well my intent is expressed, so that the agent can lock that intent by tests, designing the test suite which will cover the aspects my architecture enforces, so that at the end of the session, the agent may run a CLI tool which will point the agent to the areas it has missed.
I don’t write documentation either. Agents are great for that. What I need to do is to give them enough context and a process with values and goals I want to survive in a system so that they are able to write the documentation way better than I would do, even in my dreams.
In 2026 most of the code is either generated by a system or by AI. So if the architecture has changed, it is very easy to tell the agent: “Check the changes in the architecture and update the code so that it correctly reflects those changes.”
The biggest problem is the implied knowledge humans carry in their head and never put somewhere where the agents and tools can read that intent. That is basically coming from two reasons:
The first one: an experienced architect considers that so obvious that it is not even worth mentioning.
The second one is that there is no easy system to describe architecture in a simple way so that agents can understand it.
This is why I ended up with YAML files. That’s the only format I know of which is easily readable by humans and AIs (and is cheaper in tokens than JSON) and can be read as structure by workspace tools (with some workarounds, as I’ve not yet found terminal native tools to navigate inside the objects written in yaml as one can do in JSON).
So if we take the architecture of the software as a process of:
querying your beliefs to understand how you would approach problem-solving
converting that into an architecture for the software
drafting this software (or scaffolding the software as an architected system)
projecting that into the tests first and code second
compiling and run the tests to understand if your code is a correct projection of your architecture
Then writing the architecture as stand-alone files in the same source folder as the code before writing the code is a great approach because it gives you the ability to scaffold the repository using pseudo code described in those files (unit contracts force agents to write interfaces first, which is very similar to the test-driven development. Environment and unit descriptions force agents to write tests to protect the behavior and the contracts, which gives you the test-driven development at the same time). Everything is local and well organized even before you start writing your code.
Then you write the code and see if that code works the way you want.
And here by “you write” I mean “you create the environment for the agent to do that on your behalf.”
So the whole system here is not written for humans in most of its parts. It is written for AI’s. The only thing where humans are involved is properly expressing their intent and their vision of architecture, which can be then projected into those *.architecture.yaml files. And those files capture way more implied knowledge than any documentation I see so far. And they are next to the code so that when your agent reads the folder, they are just sitting above the code file in the folder list output and are harder to miss than some *.md file in docs/.
Currently this thing is still in the phase of tests and proof-of-concept. Ideally it will leverage code queries, graph databases, semantic reasoning, and some LLM automations so that you have it somewhere as a binary running, accessible through CLI or MCP for agents and workspace tools to use as both a planning tool and a revision tool. Potentially with an graphical interface for humans to review the architecture.
Serge — I want to give you real credit, because you’ve done something fantastic.
It’s not just the reference pile, though that alone is fantastic — you traced the whole lineage, the old guard right through to the modern conformance tools, and you were honest that the lens was yours and the parts weren’t. You took “drift,” which everyone treats as a vibe — “the codebase feels worse than it used to” — and gave it a definition a machine can actually act on: a unit becoming harder to tell apart from its surroundings, or reaching where it was never meant to reach. That’s a real contribution. And collapsing five arguing vocabularies into one shape — unit, contract, environment — so a single reasoner works at every level, is exactly the kind of simplification that only looks obvious after someone’s done it. And then you went and built the thing and let it run on itself with zero findings, which is great. So — genuinely, thank you. You sharpened how I think about this.
Where I’ve ended up is different in direction, not necessarily better — and your work is what let me see the fork clearly enough to describe it. Another perspective with fractality at its core as well
Here’s the fractal idea the way I picture it. The “same shape at every zoom” only helps you if you have a first shape — a base tile — that everything else is a copy of. Get one tiny unit exactly right, and the whole tower can be built from it:
one base unit ──► a few of them ──► a module ──► the whole system
(the seed tile) (same shape) (same shape) (same shape)
└──────────────── every level is the same tile, zoomed ───────────┘
The question nobody really answers is: where does that first tile come from? Most approaches hand-write it — you describe the unit yourself, beside the code. The trouble is, the moment you hand-write it, it’s a second thing that can drift from the code, and you’re back to keeping two stories in sync.
The angle I’ve been chasing is to not write the base tile at all — to have it fall out of the code automatically. And there’s a very practical reason the compiler is the natural place for that to happen: a compiler is already walking the syntax tree of your code, line by line, working out what every piece is, what it touches, what it depends on. It computes all of that just to do its job — and then, in every normal toolchain, throws it away. That discarded information is exactly the base tile. So instead of asking a human to re-describe what the compiler already knows, you let the compiler emit it. The map isn’t written next to the territory; it’s a by-product of the territory being understood once.
Now, the honest caveat, and it’s a real one. This works best when the language itself is built for it — in my case a small language I’ve been calling CCore — because then the base tile is clean and the compiler can hand it over without guessing. Outside that, for ordinary mixed codebases, I reach the same information a different way: a WASM-based syntax-tree pass (tree-sitter queries over a common substrate) that walks polyglot code and recovers the tile without needing everything rewritten. So it’s polyglot-capable — but I’ll be straight that the tidy, optimal version of the idea assumes you’ll seed the fractal from a language designed to emit it, and the polyglot path is the bridge for the world as it actually is.
And that’s the real difference between our two roads. Yours meets existing codebases exactly where they are and checks them — which is genuinely more useful thing for most people today. Mine asks for a cleaner starting point to get the cleanest result, and has the cold start issue of needing to adapt a new language for full optimality although the compiler can be used for other languages (suboptimal for scope and not fully built for polyglot but feasible --however the ccore compiler is fully built). Two honest bets, pointed different ways. Your posts are what made the fork visible to me — so thank you again.
After going through this thread I think I owe some more details about my thinking. Here it is, put in writing by AI:
A few of you, @drmanoj4u most recently, have pushed on the same soft spot: if the architecture lives in a file next to the code, you now have two things that can fall out of sync, and that disagreement is just drift wearing a different hat. Fair hit. It is also the part I have explained worst, so let me take it properly.
The disagreement is the instrument, not a flaw in it.
Code is not the source of truth, on purpose
Code tells you what is implemented today. It does not tell you the boundary that was meant to hold, or the reason a thing took the shape it did, or the constraint that someone was carrying in their head when they built it. That layer was never inside the code, so reading the code will never give it back to you. So the structure gets observed and the intent gets authored, and the distance between the two is what I mean by drift. What looks like two materials that can disagree is the thing doing the measuring. Take away the possibility of disagreement and you have taken away the signal.
What this actually is
Set the schema and the checker aside for a moment. The real subject is the three-body problem I mentioned earlier: humans, agents, and tools sharing one workspace, each one good at a different slice of the work and unreliable at the rest.
the human holds the intent, and reads far too slowly to verify fifty units at the speed understanding needs checking
the agent can extract that intent and write it down at scale, and is also serenely confident about understanding it has not actually reached
the tool is deterministic and honest, and carries no reasoning beyond what was coded into it
The design leans on each one only where it is strong. The checker catches what the agent talks itself past. The human catches what the agent never understood in the first place. The agent does the heavy lifting the other two cannot. What stays with the human is the one irreducible job: expressing intent clearly enough that the other two have something solid to work against.
The catch worth being honest about
Naming drift in the code does not end it. It moves it upstairs. Once the code projects the architecture faithfully, the live question becomes whether the architecture was right to begin with, and that question lands on the agent at the moment it is least trustworthy. Ask an agent whether it understands enough to write the thing and it will say yes and fill the silence with a reasonable guess. The guess is the new drift.
That is why the sufficiency check cannot be self-certified. Whatever writes the architecture should not also be the judge of whether it understood, or it ends up explaining its own explanations (mitchell said this more cleanly than I will). The judge belongs outside the writer, and the obvious judge is the human, because the human is the one holding the intent. This is the real reason a graphical interface earns its place, and it is not decoration. The system projects the agent’s understanding into something a person can verify at a glance, and the person reads a picture of the model rather than the agent’s account of it. A graph that shows core reaching into a plugin gives the agent nothing to argue with. The edge is either there or it is not.
The point is to keep the work spread out
Each layer is deliberately narrow, and the strength sits in the seams between them. An external model that evaluates the agent from the outside has a place here too, as reinforcement for when the human stops scaling, rather than as the load-bearing wall.
One seam I am still working on, and I would welcome thinking on it. A human “no” has to settle into durable state, a rule the next agent inherits with its reason attached, the same way relocating a unit is a recorded decision rather than a git move. A rejection that evaporates at the end of the session leaves you with a fine reviewer that teaches nothing forward, and the same misunderstanding returns next week under a different unit’s name.
So, back to the thread: where does the sufficiency judge belong, human-in-the-loop reading a projection, a second model outside the authoring context, or some mix, and how do you make a rejection persist as something the next agent cannot quietly un-know?
[me]: nice question by the way. For me this should be human judgment properly defined as “human scope” to start with, so that when building this system we can trace what would be the workflows taken by humans to bring that judgment in, which will basically give us the raw material for AI to repeat similar judgments later (I skip all the machinery necessary to do that because the guys in this forum know how to do that once the process is clear )
@drmanoj4u, thanks, this pushed it somewhere better.
Take the compiler. It gives you structure, and structure was never the hard part. We both already have it cheap.
The thing I said badly: it’s not bottom to top. It’s outside in. Everything is a unit. The outermost unit is the whole problem. You zoom in, more units, same shape. You keep zooming until the smallest unit, and that one becomes code. The leaf isn’t a different kind of thing, it’s just a unit at the deepest zoom. That’s why “fractal” is in the title.
A compiler sits at that deepest unit and reads its way out. It gets the shapes. It doesn’t get why they’re nested that way, because that was decided on the way in and usually never written into the unit (tacit knowledge). So using a compiler makes you most often reason on what’s inside and derive the projection of the original intent. But is will not give you the certainty that that intent matched the original architecture and the vision the architecture derived from.
The outer unit isn’t something I invent. It comes from a chain:
problem → conditions definition → current/desired matching → gap definition → solution (recurse on gaps) → business → software → architecture → units → code
A solution, the way I define it, is the algorithm that closes the gap between the current state and the desired state, where both states are written as condition claims (this is where your tests are rooted from btw). So you define the problem, write the conditions, match current against desired, and their pairs is the “gap”. The solution is whatever closes that gap (those gaps), and each gap can hide sub-problems inside, so the same step recourses inward. State the problem well detailed enough and the solution is already sitting inside it.
Each step in that chain is a projection of the step before it, and each one keeps the reasons of the step above only if you write them down as you go inward. By the time you reach code, those reasons are either here (if you wrote them down) or gone (most projects todday).
Code is the last step. That’s the spot your compiler stands on.
So it’s not two roads with a fork, but rather one structure read from two depths.
The point was never to describe code well but to capture that whole chain, problem down to units, while the reasons are still there, and put it somewhere the tool and the agent can read before any code exists.
Separate note:
I keep feeling like I’m talking to an AI. Not from the the writing/formatting style, I don’t care about that (me first using AI to put ideas in writing).
The logic. Every reply comes back as a clean pair opposition: human or compiler, your road or mine, bottom or top.
So my question is:
Are you human? And if so, why do you let your language dictate the way you think?