diff --git a/docs/architecture/04-solution-strategy.md b/docs/architecture/04-solution-strategy.md index 37ac211d..a2461acd 100644 --- a/docs/architecture/04-solution-strategy.md +++ b/docs/architecture/04-solution-strategy.md @@ -18,7 +18,7 @@ catch it, copied into its context; any other rule may stay a reference. | A mechanically checkable rule names its command and pass condition. This repository gives every such check a disposition, and runs each one that applies here | A rule upstream ships is one upstream obeys, and a skip states its reason | ADR-030, ADR-031, FR-07-01, QG-01-01 | | The 3.x line freezes its contract, and a removal waits for the next major, except for a security fix | A project pins a release and moves the pin without rework | ADR-051, FR-09-01, FR-09-02, QG-03-02 | -## 4.2 Delivery +## 4.2 Delivery model ![How one rule is placed: if breaking it is silent and no test, linter or CI step enforces it, it is inlined; if it fails visibly or a tool enforces it, it may be referenced. Inline and hybrid remain; pure reference is deprecated](../diagrams/delivery-model.png) diff --git a/docs/architecture/06-runtime-view.md b/docs/architecture/06-runtime-view.md index 8312a9d1..5a75dcf3 100644 --- a/docs/architecture/06-runtime-view.md +++ b/docs/architecture/06-runtime-view.md @@ -12,12 +12,12 @@ not wait. A frame marks a choice (`alt`) or a repeat (`loop`), with its condition in brackets. The numbers on the messages are the steps of each table. -## 6.1 Generating a project's context +## 6.1 Context generation The agent writes the project's context files from the chain the resolver orders, placing each rule where the output contract says. -![Generating a project's context. The team asks the coding agent to generate the context for a root. The agent reads the fork's interview questions and asks the team each one, getting the answers and the adopted rules. It runs the resolver, which seeds the core tier and walks depends_on, and gets the ordered file list. For an inline or hybrid file, it reads each template in order, applies overrides then extensions, places each rule, writes AGENTS.md and CLAUDE.md, and runs the self-check. For a root file with skills, it runs the emitter with the declined list, which places each section by its load and returns the root file and task skills with fact slots, and the agent fills the facts. The agent hands the files to the team for review](../diagrams/runtime-generate.png) +![Context generation. The team asks the coding agent to generate the context for a root. The agent reads the fork's interview questions and asks the team each one, getting the answers and the adopted rules. It runs the resolver, which seeds the core tier and walks depends_on, and gets the ordered file list. For an inline or hybrid file, it reads each template in order, applies overrides then extensions, places each rule, writes AGENTS.md and CLAUDE.md, and runs the self-check. For a root file with skills, it runs the emitter with the declined list, which places each section by its load and returns the root file and task skills with fact slots, and the agent fills the facts. The agent hands the files to the team for review](../diagrams/runtime-generate.png) | Step | What happens | Source | |------|--------------|--------| @@ -36,12 +36,12 @@ list, then the root's file and every file its dependency lines name, transitively. Skipping either list loses rules with no error, because no template declares those files. -## 6.2 A task skill loads +## 6.2 Task skill loading The root file holds the rules for every turn; a procedure for one kind of task loads only when that task starts. -![A task skill loads. At the start of the session the coding agent reads the root file and gets the rules for every turn and the trigger table. The team gives it a task, such as a release, and the agent matches the task to a trigger. If one matches, it loads that skill's SKILL.md and gets the task's procedures; otherwise it works from the root file alone. It applies the rules, does the task, and returns the change with its evidence](../diagrams/runtime-skill.png) +![Task skill loading. At the start of the session the coding agent reads the root file and gets the rules for every turn and the trigger table. The team gives it a task, such as a release, and the agent matches the task to a trigger. If one matches, it loads that skill's SKILL.md and gets the task's procedures; otherwise it works from the root file alone. It applies the rules, does the task, and returns the change with its evidence](../diagrams/runtime-skill.png) | Step | What happens | Source | |------|--------------|--------| @@ -50,12 +50,12 @@ task loads only when that task starts. | 4 | A skill is one folder under `.agents/skills/`, copied where an agent reads only its own folder | ADR-058, proposed | | 5 | An agent that cannot load skills gets them inlined in the root file | ADR-058, proposed | -## 6.3 A shipped hook runs in a project's CI +## 6.3 Hook execution in CI A check too long for a fence ships as a hook, which pre-commit runs at the revision the project pinned. -![A shipped hook runs in a project's CI. The project's CI runs pre-commit for a hook. pre-commit fetches upstream at the pinned revision and installs the solid-ai-checks command, then runs it with the hook ID. The hook reads the project's tracked files. If the check passes, it exits 0 with the inspected counts; if it finds a breach, it exits 1 with the findings; if it does not apply, it prints a line and exits 0. pre-commit reports pass or fail to CI](../diagrams/runtime-hook.png) +![Hook execution in CI. The project's CI runs pre-commit for a hook. pre-commit fetches upstream at the pinned revision and installs the solid-ai-checks command, then runs it with the hook ID. The hook reads the project's tracked files. If the check passes, it exits 0 with the inspected counts; if it finds a breach, it exits 1 with the findings; if it does not apply, it prints a line and exits 0. pre-commit reports pass or fail to CI](../diagrams/runtime-hook.png) | Step | What happens | Source | |------|--------------|--------| @@ -63,12 +63,12 @@ revision the project pinned. | 3-4 | Every hook reads the tracked tree itself, so pre-commit passes it no file names | ADR-055 | | 5-7 | A check exits 0 on a pass, 1 on a breach and 3 when it does not apply. Under pre-commit, 3 becomes a printed line and exit 0 | FR-07-03 | -## 6.4 A fork takes an upstream change +## 6.4 Upstream synchronisation A fork stays current by merging upstream, never by copying files. A commit that removes what forks carry is marked `Fork-merge: ours`. -![A fork takes an upstream change. The fork maintainer fetches upstream and lists the commits carrying Fork-merge: ours, oldest first. For each, the maintainer merges its parent, merges the commit with -s ours, keeping the fork's files, then moves the fork's templates to its own keys and restores upstream's text. The maintainer then merges upstream/main and pushes, and the fork's CI runs smoke against upstream/main](../diagrams/runtime-fork-sync.png) +![Upstream synchronisation. The fork maintainer fetches upstream and lists the commits carrying Fork-merge: ours, oldest first. For each, the maintainer merges its parent, merges the commit with -s ours, keeping the fork's files, then moves the fork's templates to its own keys and restores upstream's text. The maintainer then merges upstream/main and pushes, and the fork's CI runs smoke against upstream/main](../diagrams/runtime-fork-sync.png) | Step | What happens | Source | |------|--------------|--------| @@ -79,15 +79,14 @@ that removes what forks carry is marked `Fork-merge: ours`. `py tests/run.py fork_sync` runs the same merge on every pull request upstream, in a simulated fork that appends a stack and edits its own files -(FR-10-02). The playbook, "Sync with upstream as a fork", gives the -commands. +(FR-10-02). -## 6.5 A project adopts a release +## 6.5 Release adoption A newer tag adopts nothing by itself. The team decides what the project takes, and only a regeneration or an edit changes its context files. -![A project adopts a release. The team asks the coding agent to assess the release. The agent reads the changelog between the pin and the tag and returns the candidates, with what each addresses. The team names the ones to adopt, and the agent moves the pin to the tag, then regenerates or adopts each rule by hand, and returns the change for review](../diagrams/runtime-adopt.png) +![Release adoption. The team asks the coding agent to assess the release. The agent reads the changelog between the pin and the tag and returns the candidates, with what each addresses. The team names the ones to adopt, and the agent moves the pin to the tag, then regenerates or adopts each rule by hand, and returns the change for review](../diagrams/runtime-adopt.png) | Step | What happens | Source | |------|--------------|--------| diff --git a/docs/architecture/07-deployment-view.md b/docs/architecture/07-deployment-view.md new file mode 100644 index 00000000..56daaf37 --- /dev/null +++ b/docs/architecture/07-deployment-view.md @@ -0,0 +1,60 @@ +# 7. Deployment view + +How the rules reach a project and where they run. Nothing of upstream runs +as a service. The templates travel as files at a released tag, the coding +agent reads them on a developer's machine, and pre-commit runs the shipped +hooks on that machine and again in the project's CI. A project chooses +the source it takes the rules from, how it holds them, and who moves its +pin. + +The diagram is a UML deployment diagram. A 3D box is a node, such +as a repository, a machine or an execution environment. An element drawn +inside a node is deployed on it. A line is a communication path, and its +arrow points from the side that opens it. + +## 7.1 Deployment overview + +![Deployment overview. Upstream, solid-ai-templates, holds the templates and tools and the shipped hooks. A fork, such as imbra-ai-templates, fetches and merges upstream, and adds its stacks and platforms and, optionally, an updater. The project repository pins the templates to a release tag, by submodule, clone or copy, from upstream or from a fork, and holds AGENTS.md and CLAUDE.md, the task skills under .agents/skills, and the pre-commit configuration. The updater opens a pull request with a pin bump to the project. The developer's machine runs the coding agent, which clones the project and commits to it, and pre-commit on each commit. The project's CI checks out the pushed commit and runs pre-commit on each push. Both pre-commit runs fetch the shipped hooks from upstream at the pinned revision](../diagrams/deployment-distribution.png) + +| Node | What it holds | Source | +|------|---------------|--------| +| Upstream | The templates, the tools and the shipped hooks, released as tags | FR-09-01 | +| A fork | Upstream's history, merged, with its own stacks, platforms and process | FR-08-01, ADR-050 | +| Project | The pinned templates, its context files, its task skills and its pre-commit configuration | FR-08-04, FR-05-04 | +| Developer's machine | The coding agent, which generates the context files from the project's copy of the templates, and pre-commit, which git's hook runs on each commit for early feedback | FR-05-01, ADR-055 | +| Project's CI | pre-commit, on each push, the gate every change passes, since a local hook is optional and can be skipped. Both runs fetch the shipped hooks at the revision the project pinned | FR-07-02, ADR-055 | + +## 7.2 Distribution sources + +| Source | What a project gets | Fits | Source | +|--------|---------------------|------|--------| +| Upstream | The core tier, the opt-in base templates and the layers, each of them a root; no stack | A project that wants the shared rules only | ADR-050 | +| A fork, such as imbra-ai-templates | Upstream unchanged, plus the fork's stacks, platforms, process and interview | A team with stacks of its own. A project on upstream moves to it without regenerating its context files, if it pins a fork tag that contains its upstream tag. An older fork tag can lack files or sections its context files name | ADR-049, ADR-050, FR-08-02, FR-09-01 | + +## 7.3 Integration models + +A project holds the templates by submodule, clone or copy, and its coding +agent generates the context files from them. A project whose context file +copies in every rule may keep that file alone, without the templates. A +project may also opt out of the templates and take only the shipped +checks, with hooks only. + +| Model | Brings | The pin | Update | Trade-off | Source | +|-------|--------|---------|--------|-----------|--------| +| Submodule | The templates | A released tag, in the project's history | Move the submodule to a newer tag | Each commit records the rules that governed it | FR-08-04 | +| Clone | The templates | A released tag, outside the project's history | Check out a newer tag | Simple, but no commit records which rules governed it | FR-08-04 | +| Copy | The templates | A released tag, in the project's history as files | Replace the copy with a newer tag's files | No submodule to initialise, but a local edit to the copy is lost on update | - | +| Generated files only | The inline context files, generated once from the templates at a released tag | None in the repository; the tag is the one the files were generated from | Regenerate from a newer tag | Nothing to hold but the context files. A hybrid file cannot do this, since its references point into the templates | FR-05-04, ADR-052 | +| Hooks only | The shipped checks, run by pre-commit | A released tag, as `rev:` in `.pre-commit-config.yaml` | Move `rev:` to a newer tag | The checks, without the rules | ADR-055 | + +## 7.4 Version updates + +The team moves the pin, by hand, when a release holds a rule it wants +(chapter 6.5). A fork may add an updater, a bot that watches releases and +proposes the move to its projects. Any updater follows these rules. + +| Rule | Source | +|------|--------| +| It moves the pin to a released tag, never a branch | FR-08-04 | +| It proposes the move as a pull request, listing the changelog entries between the two tags as candidates | FR-09-03 | +| It never rewrites a context file. Moving the pin changes nothing, and adopting a rule stays the team's decision | FR-09-03 | diff --git a/docs/diagrams/delivery-model.drawio b/docs/diagrams/delivery-model.drawio index a64becd4..7a1a44f3 100644 --- a/docs/diagrams/delivery-model.drawio +++ b/docs/diagrams/delivery-model.drawio @@ -4,7 +4,7 @@ - + diff --git a/docs/diagrams/delivery-model.png b/docs/diagrams/delivery-model.png index aaa1f136..7a5151ae 100644 Binary files a/docs/diagrams/delivery-model.png and b/docs/diagrams/delivery-model.png differ diff --git a/docs/diagrams/deployment-distribution.drawio b/docs/diagrams/deployment-distribution.drawio new file mode 100644 index 00000000..307e1eca --- /dev/null +++ b/docs/diagrams/deployment-distribution.drawio @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/diagrams/deployment-distribution.png b/docs/diagrams/deployment-distribution.png new file mode 100644 index 00000000..805a949a Binary files /dev/null and b/docs/diagrams/deployment-distribution.png differ diff --git a/docs/diagrams/runtime-adopt.drawio b/docs/diagrams/runtime-adopt.drawio index d24f2d46..b90e2ced 100644 --- a/docs/diagrams/runtime-adopt.drawio +++ b/docs/diagrams/runtime-adopt.drawio @@ -8,7 +8,7 @@ - + diff --git a/docs/diagrams/runtime-adopt.png b/docs/diagrams/runtime-adopt.png index 2bb392b2..d9a0daa2 100644 Binary files a/docs/diagrams/runtime-adopt.png and b/docs/diagrams/runtime-adopt.png differ diff --git a/docs/diagrams/runtime-fork-sync.drawio b/docs/diagrams/runtime-fork-sync.drawio index be1a0a01..2a6000a4 100644 --- a/docs/diagrams/runtime-fork-sync.drawio +++ b/docs/diagrams/runtime-fork-sync.drawio @@ -9,7 +9,7 @@ - + diff --git a/docs/diagrams/runtime-fork-sync.png b/docs/diagrams/runtime-fork-sync.png index 42428656..c1cc9325 100644 Binary files a/docs/diagrams/runtime-fork-sync.png and b/docs/diagrams/runtime-fork-sync.png differ diff --git a/docs/diagrams/runtime-generate.drawio b/docs/diagrams/runtime-generate.drawio index 8d6a7983..96efc027 100644 --- a/docs/diagrams/runtime-generate.drawio +++ b/docs/diagrams/runtime-generate.drawio @@ -11,7 +11,7 @@ - + diff --git a/docs/diagrams/runtime-generate.png b/docs/diagrams/runtime-generate.png index 54e3eebd..9b5b6b58 100644 Binary files a/docs/diagrams/runtime-generate.png and b/docs/diagrams/runtime-generate.png differ diff --git a/docs/diagrams/runtime-hook.drawio b/docs/diagrams/runtime-hook.drawio index ac8eb79a..9ca7eec0 100644 --- a/docs/diagrams/runtime-hook.drawio +++ b/docs/diagrams/runtime-hook.drawio @@ -9,7 +9,7 @@ - + diff --git a/docs/diagrams/runtime-hook.png b/docs/diagrams/runtime-hook.png index 38ea8479..8a188ff7 100644 Binary files a/docs/diagrams/runtime-hook.png and b/docs/diagrams/runtime-hook.png differ diff --git a/docs/diagrams/runtime-skill.drawio b/docs/diagrams/runtime-skill.drawio index eebd51a8..2d0626ba 100644 --- a/docs/diagrams/runtime-skill.drawio +++ b/docs/diagrams/runtime-skill.drawio @@ -9,7 +9,7 @@ - + diff --git a/docs/diagrams/runtime-skill.png b/docs/diagrams/runtime-skill.png index c47527b0..02449b48 100644 Binary files a/docs/diagrams/runtime-skill.png and b/docs/diagrams/runtime-skill.png differ diff --git a/docs/spec.md b/docs/spec.md index 0444b2d8..d652c66f 100644 --- a/docs/spec.md +++ b/docs/spec.md @@ -10,7 +10,7 @@ The architecture, one arc42 chapter per file. | 4. Solution strategy | [04-solution-strategy.md](architecture/04-solution-strategy.md) | | 5. Building block view | [05-building-block-view.md](architecture/05-building-block-view.md) | | 6. Runtime view | [06-runtime-view.md](architecture/06-runtime-view.md) | -| 7. Deployment view | Not applicable: nothing is deployed; a fork pins and merges upstream (chapter 6) | +| 7. Deployment view | [07-deployment-view.md](architecture/07-deployment-view.md) | | 8. Crosscutting concepts | [08-crosscutting-concepts.md](architecture/08-crosscutting-concepts.md) | | 9. Architecture decisions | [decisions/](decisions/) | | 10. Quality requirements | [10-quality-requirements.md](architecture/10-quality-requirements.md) |