From d2296e975ad6c4762cdd4c7f898170de7a67f9f2 Mon Sep 17 00:00:00 2001 From: Dusan Omercevic Date: Wed, 12 Aug 2026 16:36:25 +0200 Subject: [PATCH 01/14] Adding 'module-structure.md' --- forge/rules/definitions.md | 1 - forge/rules/module-structure.md | 87 +++++++++++++++++++ forge/skills/load-plain-reference/SKILL.md | 3 +- .../references/project-model.md | 11 --- 4 files changed, 89 insertions(+), 13 deletions(-) create mode 100644 forge/rules/module-structure.md diff --git a/forge/rules/definitions.md b/forge/rules/definitions.md index d9a81a4..33ea8c6 100644 --- a/forge/rules/definitions.md +++ b/forge/rules/definitions.md @@ -89,7 +89,6 @@ Example of defining technical components alongside their behavior: - :CsvFileReader: reads CSV rows in a batched manner. - - :CsvJoiner: joins csvs and uses :CsvFileWriter: to create the merged CSV. ``` diff --git a/forge/rules/module-structure.md b/forge/rules/module-structure.md new file mode 100644 index 0000000..a399f89 --- /dev/null +++ b/forge/rules/module-structure.md @@ -0,0 +1,87 @@ +--- +description: File-level structure of .plain modules — frontmatter, sections, ordering, and section ownership +--- + +# Rules for `.plain` module structure + +When creating a new `.plain` file or reviewing the structure of a whole file, always follow these rules. Section *content* rules live in the per-section rule files linked below — this file covers only file-level structure. + +## File skeleton +- A `.plain` file is one **module**: optional YAML frontmatter between `---` markers, followed by sections marked with `***section name***` headers +- The frontmatter, when present, must be the first thing in the file +- Every content line inside a section must be a `- ` list item — see `bullet-continuation.md` + +## Frontmatter fields + +| Field | Purpose | Rule file | +|---|---|---| +| `description` | One-line summary of the module; recommended on every module | — | +| `import` | Pull definitions, implementation reqs, and test reqs from template modules | `import-modules.md` | +| `requires` | Attach the module to the build chain of another root module | `requires-modules.md` | +| `exported_concepts` | Declare which of this module's concepts are visible to modules that `require` it | `exported-concepts.md` | +| `required_concepts` | Declare concepts an import module expects the importing module to define | `required-concepts.md` | + +## Sections +- There are exactly four top-level section markers: `***definitions***`, `***implementation reqs***`, `***test reqs***`, and `***functional specs***` +- Each section appears **at most once** per file; all are optional (which ones are allowed depends on the module kind below) +- `***acceptance tests***` is **never a top-level section** — it appears only nested under a single functional spec (see `func-specs.md`) +- Write sections in canonical order: `***definitions***` → `***implementation reqs***` → `***test reqs***` → `***functional specs***` + - Definitions come first because every concept must be defined before it is referenced + - Functional specs come last because they are rendered incrementally and their nested acceptance tests close the file + +## Module kinds +- A **root module** lives at the repository root and carries behavior: it contains `***functional specs***` and may use `requires` +- To be renderable, a root module needs at least one functional spec plus the implementation reqs to build it — its own or from an `import`ed template. A frontmatter-only file is a valid scaffold, but it cannot be rendered until a functional spec is added +- An **import module** lives in `template/` and contains only `***definitions***`, `***implementation reqs***`, and/or `***test reqs***` — never `***functional specs***`, never `requires` (see `import-modules.md`) + +## Section ownership (where a fact lives) +- The renderer reads each kind of fact **only from its owning section** — a fact placed in the wrong section is silently ignored, not flagged +- Before writing any requirement, place it by content: + +| Content | Owning section | Rule file | +|---|---|---| +| Concepts (`:CamelCaseToken:`) | `***definitions***` | `definitions.md` | +| HOW the software is built — tech stack, architecture, coding standards — and **everything about `:UnitTests:`** | `***implementation reqs***` | `impl-reqs.md` | +| **Everything about `:ConformanceTests:`** — framework, run command, mocking and network policy | `***test reqs***` | `test-reqs.md` | +| WHAT the software does — observable, language-agnostic behavior | `***functional specs***` | `func-specs.md` | +| End-to-end workflow verification of one functional spec | nested `***acceptance tests***` | `func-specs.md` | + +## Comments +- Lines beginning with `>` are ignored when rendering + +```plain +> This is a comment in ***plain. +``` + +- Comments explain the specification to human authors — never use a comment to carry a requirement the renderer must implement + +## Format + +```plain +--- +description: Command-line task manager. +import: + - airplain +--- + +***definitions*** + +- :Task: is an activity tracked by the application. + - Name (required) + +- :TaskList: is the collection of all :Task: items. Initially empty. + +***implementation reqs*** + +- :Implementation: keeps :TaskList: in memory. + +***test reqs*** + +- :ConformanceTests: must not access the network. + +***functional specs*** + +- A :Task: can be added to the :TaskList:. + +- The :TaskList: is displayed. +``` diff --git a/forge/skills/load-plain-reference/SKILL.md b/forge/skills/load-plain-reference/SKILL.md index 88659fb..e178e9d 100644 --- a/forge/skills/load-plain-reference/SKILL.md +++ b/forge/skills/load-plain-reference/SKILL.md @@ -27,6 +27,7 @@ All paths are relative to this `SKILL.md`. | Task or content | Rule files | |---|---| +| New module, file skeleton, section placement, or comments | `../../rules/module-structure.md` | | Definitions or concept usage | `../../rules/definitions.md` | | Functional specs or acceptance tests | `../../rules/func-specs.md` | | Implementation requirements or unit tests | `../../rules/impl-reqs.md` | @@ -61,7 +62,7 @@ Authoring rules remain authoritative if a reference appears to conflict with the | Need | Reference | |---|---| -| Project layout, source-of-truth model, templates, or comments | `references/project-model.md` | +| Project layout, source-of-truth model, or template inclusion | `references/project-model.md` | | Rendering order, generated artifacts, conformance workflow, or test scripts | `references/rendering-and-testing.md` | | `codeplain` path resolution or CLI options | Invoke `load-codeplain-reference` | diff --git a/forge/skills/load-plain-reference/references/project-model.md b/forge/skills/load-plain-reference/references/project-model.md index 87cf426..95e540b 100644 --- a/forge/skills/load-plain-reference/references/project-model.md +++ b/forge/skills/load-plain-reference/references/project-model.md @@ -35,14 +35,3 @@ In addition to frontmatter `import`, ***plain supports parameterized template in Parameters are key-value pairs. Templates access them with `{{ variable_name }}`. Only variable substitution is supported; conditionals, loops, and other Liquid features are not available. - -## Comments - -Lines beginning with `>` are ignored during rendering: - -```plain -> This is a comment in ***plain. -``` - -Comments explain the specification to human authors. Do not use comments to carry requirements the -renderer must implement. From 804486f543f178241770fab5a972ba02cfe53b56 Mon Sep 17 00:00:00 2001 From: Dusan Omercevic Date: Wed, 12 Aug 2026 17:00:35 +0200 Subject: [PATCH 02/14] Fixed a wrong fact in linked-resources.md. --- forge/rules/linked-resources.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/forge/rules/linked-resources.md b/forge/rules/linked-resources.md index 09362c8..927671a 100644 --- a/forge/rules/linked-resources.md +++ b/forge/rules/linked-resources.md @@ -15,12 +15,13 @@ A linked resource **must not** be any of the following: 3. **A binary file.** PNG, JPG, GIF, PDF, DOCX, XLSX, ZIP, MP3, MP4, compiled binaries (`.exe`, `.so`, `.class`, `.wasm`), and anything else that isn't human-readable text in its raw form. Binary content cannot be meaningfully consumed by the renderer — transcribe it into a text-based form first (a UI screenshot becomes a Markdown description, a PDF spec becomes a Markdown extract or the underlying JSON Schema / OpenAPI, an architecture diagram becomes a Mermaid block). 4. **Another `.plain` file.** `[Auth Module](auth.plain)` is invalid. To reference another module, use the `require` or `import` frontmatter directives. Do not link it as a markdown resource; the `plain-dry-run` will flag this as a syntax error. - -## URLs and folder paths must not appear *anywhere* in `.plain` content -- The constraint is not only about markdown links — URLs and folder paths must not appear **anywhere** in `.plain` content (concept body prose, functional-spec text, implementation reqs, test reqs) -- The renderer cannot follow URLs or open folders; a URL in prose is a *ghost dependency* — it looks meaningful to a human reader but contributes nothing to code generation, and the spec silently drifts from reality -- **The only exception** is for URLs and paths that are *values the produced software itself uses at runtime* — the base URL an integration calls, a database connection path, a CLI argument default. Those are configuration values, not external references -- Litmus test: "Would the renderer benefit from reading the bytes at this URL / folder?" If yes, save it to a file and link the file. If no (it's a runtime value the code carries forward), it can stay as plain text +## Never use a URL or folder path as a *reference* in prose +- The hard constraint above is enforced only on markdown links. A bare URL or folder path in prose (concept body, functional-spec text, implementation reqs, test reqs) passes validation and is fed to the renderer verbatim as part of the spec text +- That is exactly why it is dangerous as a *reference*: the renderer cannot fetch the URL or open the folder, so the model sees only the address, not the content behind it. To a human reader the line looks grounded in a source; to the renderer it is a *ghost dependency*, and the spec silently drifts from whatever the URL actually says +- A URL or path in prose is fine when the *text itself* is the complete fact: + - **Runtime values** the produced software uses — the base URL an integration calls, a database connection path, a CLI argument default, an output directory layout + - **Provenance notes** for a snapshotted resource — recording the canonical documentation URL a `resources/docs/…` snapshot was fetched from (as the integration rules require) +- Litmus test: "Would the renderer benefit from reading the bytes at this URL / folder?" If yes, save it to a file and link the file. If no (the address itself is the fact), it can stay as plain text ## Structured protocol artifacts must be linked, never transcribed - JSON Schema, OpenAPI / Swagger, GraphQL SDL, Protobuf `.proto`, Avro / Thrift schemas, XML XSDs, AsyncAPI specs, JSON-RPC method definitions, wire-protocol descriptions, payload examples — anything with a formal machine-readable shape — belongs in a file under `resources/` (or another directory within the project) From 9e12da848f59fbb06179a81add7941567fa64c06 Mon Sep 17 00:00:00 2001 From: Dusan Omercevic Date: Wed, 12 Aug 2026 17:17:12 +0200 Subject: [PATCH 03/14] Making clear in 'bullet-continutation.md' that one statement per line is preferred convention and not a rule. --- forge/rules/bullet-continuation.md | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/forge/rules/bullet-continuation.md b/forge/rules/bullet-continuation.md index 63bb904..cac0b15 100644 --- a/forge/rules/bullet-continuation.md +++ b/forge/rules/bullet-continuation.md @@ -12,14 +12,23 @@ These rules apply to every section and to concept explanations. - Do not split a valid line merely to satisfy an arbitrary formatting width - Prefer clear, precise wording; concision must never remove required detail -## Never use bare continuation lines - -- Every line inside a section must be a list item beginning with `- ` -- An indented continuation without `- ` is invalid syntax -- If content is intentionally separated across lines, express the additional lines as nested - bullet items so each line remains syntactically valid - -WRONG — bare continuation lines: +## One statement per line + +This is the preferred `.plain` authoring convention, not something the renderer enforces. A line +break in a section means one of exactly two things: a new `- ` statement, or a nested `- ` +clarification of the statement above it. There is no third, typographic reason to break a line. + +- Write each statement on a single line, however long +- Never break a line just for width: a bare continuation (an indented line without `- `) adds a + line break that carries no structure — to every future reader and editing agent it is + indistinguishable from a deliberate sub-point +- The test: if content deserves its own line, it deserves its own `- ` bullet; if it doesn't, + keep it on the parent's line +- What the renderer does enforce is the top level: every statement in a section must be a `- ` + list item — a flush-left prose line is a syntax error. A bare continuation, by contrast, is + accepted and folded into its parent item verbatim + +BAD — line broken for width (bare continuation): ```plain ***functional specs*** From 67f91a34e06dc634adc2993db2879ca736195d87 Mon Sep 17 00:00:00 2001 From: Dusan Omercevic Date: Wed, 12 Aug 2026 17:23:55 +0200 Subject: [PATCH 04/14] Removing mentions of 'template' from required-concepts.md because it was introducing confusion. --- forge/rules/required-concepts.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/forge/rules/required-concepts.md b/forge/rules/required-concepts.md index 844a398..09509ee 100644 --- a/forge/rules/required-concepts.md +++ b/forge/rules/required-concepts.md @@ -9,10 +9,10 @@ When adding or editing `required_concepts` in a `.plain` file's frontmatter, alw ## What required_concepts does - `required_concepts` declares concepts that any module importing this file **must** define - It creates a contract: the import module references these concepts but does not define them — the importing module is responsible for providing definitions -- This is used exclusively on import modules and templates +- This is used exclusively on import modules ## When to use it -- Use `required_concepts` when an import module or template (in `template/`) references concepts that vary per project or per importing module +- Use `required_concepts` when an import module references concepts that vary per project or per importing module - The import module can reference these concepts in its definitions, implementation reqs, or test reqs — but their actual definitions come from whoever imports the file ## Importing module must satisfy the contract @@ -29,7 +29,7 @@ When adding or editing `required_concepts` in a `.plain` file's frontmatter, alw ```plain --- required_concepts: [":AppName:", ":AppConfig:"] -description: Template that requires AppName and AppConfig to be defined by the importer +description: Imported module that requires AppName and AppConfig to be defined by the importer --- ***definitions*** @@ -39,6 +39,6 @@ description: Template that requires AppName and AppConfig to be defined by the i - :MainFile: should load :AppConfig: on startup. ``` -In this example, `:AppName:` and `:AppConfig:` are referenced but not defined — the module that imports this template must define them. +In this example, `:AppName:` and `:AppConfig:` are referenced but not defined — the module that imports this import module must define them. List concepts as a YAML array with each concept in `:ConceptName:` notation. From 1da87f37921db209eaaa29ff0ece562415d44e14 Mon Sep 17 00:00:00 2001 From: Dusan Omercevic Date: Thu, 13 Aug 2026 14:54:52 +0200 Subject: [PATCH 05/14] Adding more details and rationale for the complexity limit. --- forge/rules/func-specs.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/forge/rules/func-specs.md b/forge/rules/func-specs.md index d7c5592..ce1e0f1 100644 --- a/forge/rules/func-specs.md +++ b/forge/rules/func-specs.md @@ -38,7 +38,9 @@ GOOD — statements of fact with concrete subjects: ``` ## Complexity limit -- Each functional spec must imply a **maximum of 200 changed lines of code** +- The complexity limit is about breaking software into small, independently understandable behavior slices that people and AI can reason about, implement, and test reliably +- The current mechanism for enforcing the complexity limit is that each functional spec must imply a **maximum of 200 changed lines of code**. +- Smaller slices produce focused test failures, reduce hidden coupling and regression surface, and make review and incremental rendering more predictable - If a spec is too large, use `break-down-func-spec` to split it into multiple smaller, independent specs - Use `analyze-if-func-spec-too-complex` to verify before inserting - Use `analyze-func-specs` to check a spec (or a batch of specs) against all relevant existing specs in a single batched call; use `resolve-spec-conflict` for each conflicting pair it reports From e25d29b1642ea31a0f3d67025604313af6c57c7f Mon Sep 17 00:00:00 2001 From: Dusan Omercevic Date: Thu, 13 Aug 2026 17:30:25 +0200 Subject: [PATCH 06/14] Trying not to confuse templates with `import` and `requires` module. --- forge/rules/definitions.md | 2 +- forge/rules/impl-reqs.md | 2 +- forge/rules/import-modules.md | 8 +++----- forge/rules/module-structure.md | 9 +++++---- forge/rules/requires-modules.md | 7 +++---- forge/rules/test-reqs.md | 2 +- 6 files changed, 14 insertions(+), 16 deletions(-) diff --git a/forge/rules/definitions.md b/forge/rules/definitions.md index 33ea8c6..ec4ad66 100644 --- a/forge/rules/definitions.md +++ b/forge/rules/definitions.md @@ -13,7 +13,7 @@ When writing or editing a `***definitions***` section in a `.plain` file, always ## Uniqueness - Concept names must be globally unique across the spec and all its imports -- Check for collisions with imported templates, `import` and `requires` modules before adding +- Check for collisions with concepts coming from `import` and `requires` modules before adding ## Predefined concepts (do not redefine) - ***plain ships several predefined concepts that are available in every module without being defined diff --git a/forge/rules/impl-reqs.md b/forge/rules/impl-reqs.md index 8ba9732..32d9ba5 100644 --- a/forge/rules/impl-reqs.md +++ b/forge/rules/impl-reqs.md @@ -46,7 +46,7 @@ When writing or editing an `***implementation reqs***` section in a `.plain` fil ## No duplication - Do not duplicate guidance already present in the file or its imports -- Check imported templates before adding a new req +- Check imported modules before adding a new req ## Concept references - Reference defined `:Concepts:` where they add clarity diff --git a/forge/rules/import-modules.md b/forge/rules/import-modules.md index 56f22de..b4ab4ee 100644 --- a/forge/rules/import-modules.md +++ b/forge/rules/import-modules.md @@ -10,18 +10,16 @@ When creating or editing a `.plain` file that uses `import` or is intended to be - An import module contains **only** `***definitions***`, `***implementation reqs***`, and/or `***test reqs***` - It must **not** contain `***functional specs***` - It must **not** use `requires` in its frontmatter -- It must live in the **`template/`** directory -- It may optionally `import` other modules or templates for layered reuse +- It may optionally `import` other import modules for layered reuse ## What import does - `import` pulls in `***definitions***`, `***implementation reqs***`, and `***test reqs***` from the target module - It does **not** pull in `***functional specs***` -- The default import directory is `template/` — the `template/` prefix is not needed in import paths - Import paths omit the `.plain` extension ## Concept visibility -- All concepts defined in the imported module become available in the importing module -- Check for concept name collisions between imports and local definitions before adding +- All concepts defined in the imported module become available in the importing module — including concepts the imported module itself imports (layered imports are transitive) +- Check for concept name collisions between imports and local definitions before adding — a collision is rejected as a syntax error ("Concepts were defined multiple times") ## Format diff --git a/forge/rules/module-structure.md b/forge/rules/module-structure.md index a399f89..ed3b99c 100644 --- a/forge/rules/module-structure.md +++ b/forge/rules/module-structure.md @@ -16,7 +16,7 @@ When creating a new `.plain` file or reviewing the structure of a whole file, al | Field | Purpose | Rule file | |---|---|---| | `description` | One-line summary of the module; recommended on every module | — | -| `import` | Pull definitions, implementation reqs, and test reqs from template modules | `import-modules.md` | +| `import` | Pull definitions, implementation reqs, and test reqs from import modules | `import-modules.md` | | `requires` | Attach the module to the build chain of another root module | `requires-modules.md` | | `exported_concepts` | Declare which of this module's concepts are visible to modules that `require` it | `exported-concepts.md` | | `required_concepts` | Declare concepts an import module expects the importing module to define | `required-concepts.md` | @@ -30,9 +30,10 @@ When creating a new `.plain` file or reviewing the structure of a whole file, al - Functional specs come last because they are rendered incrementally and their nested acceptance tests close the file ## Module kinds -- A **root module** lives at the repository root and carries behavior: it contains `***functional specs***` and may use `requires` -- To be renderable, a root module needs at least one functional spec plus the implementation reqs to build it — its own or from an `import`ed template. A frontmatter-only file is a valid scaffold, but it cannot be rendered until a functional spec is added -- An **import module** lives in `template/` and contains only `***definitions***`, `***implementation reqs***`, and/or `***test reqs***` — never `***functional specs***`, never `requires` (see `import-modules.md`) +- A **root module** lives at the repository root and carries behavior: it contains `***functional specs***` +- To be renderable, a root module needs at least one functional spec plus the implementation reqs to build it — its own or from an `import`ed module (implementation reqs are not inherited through `requires`). A frontmatter-only file is a valid scaffold, but it cannot be rendered until a functional spec is added +- A **requires module** is a root module that is used by another root module via `requires` directive (see `requires-modules.md`) +- An **import module** provides shared content that other modules pull in via `import`: it contains only `***definitions***`, `***implementation reqs***`, and/or `***test reqs***` — never `***functional specs***`, never `requires` (see `import-modules.md`) ## Section ownership (where a fact lives) - The renderer reads each kind of fact **only from its owning section** — a fact placed in the wrong section is silently ignored, not flagged diff --git a/forge/rules/requires-modules.md b/forge/rules/requires-modules.md index dd5494d..f1ce700 100644 --- a/forge/rules/requires-modules.md +++ b/forge/rules/requires-modules.md @@ -4,7 +4,7 @@ description: Rules for creating and using requires modules in .plain files # Rules for requires modules -When creating or editing a `.plain` file that uses `requires`, always follow these rules: +When creating or editing a `.plain` file that uses `requires`, or one that is referenced in another `.plain` file's `requires` directive, always follow these rules: ## What requires does @@ -27,7 +27,7 @@ When creating or editing a `.plain` file that uses `requires`, always follow the - Because the required module's generated code is copied as the starting point and the renderer continues building on top of it with a single toolchain, two modules can only be linked with `requires` when they target the **same language, framework, and runtime** - A runtime / network dependency between systems is **not** a reason to use `requires` - Example of the mistake: a React frontend that talks to a Python/FastAPI backend over HTTP must **not** `requires: [backend]` — the stacks differ -- Model that pair as two independent root modules (each with its own `config.yaml` and test scripts) and express the contract through a shared API schema in `resources/` or shared concepts in an `import`ed template — never through `requires` +- Model that pair as two independent root modules (each with its own `config.yaml` and test scripts) and express the contract through a shared API schema in `resources/` or shared concepts in an `import`ed module — never through `requires` ## Building upon but not necessarily extension @@ -53,8 +53,7 @@ When creating or editing a `.plain` file that uses `requires`, always follow the - Modules that use `requires` live at the **repository root** — they are functional modules with specs - `requires` paths point to other root-level modules (e.g., `auth`, `messaging`) -- The default import directory is `template/` — the `template/` prefix is not needed in import paths (e.g., `airplain`) -- Never `require` a template — templates are for `import` only +- Never `require` an import module — import modules are for `import` only ## Format diff --git a/forge/rules/test-reqs.md b/forge/rules/test-reqs.md index 8e2bf7f..d9086b6 100644 --- a/forge/rules/test-reqs.md +++ b/forge/rules/test-reqs.md @@ -36,7 +36,7 @@ When writing or editing a `***test reqs***` section in a `.plain` file, always f ## No duplication - Do not duplicate guidance already present in the file or its imports -- Check imported templates before adding a new test req +- Check imported modules before adding a new test req ## Concept references - Reference predefined concepts like `:ConformanceTests:` where appropriate From b053b466dfb357a9fa13e0b5b17a5c1e2af0ecfa Mon Sep 17 00:00:00 2001 From: Dusan Omercevic Date: Thu, 13 Aug 2026 17:51:22 +0200 Subject: [PATCH 07/14] Providing more details on test types. --- forge/rules/test-reqs.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/forge/rules/test-reqs.md b/forge/rules/test-reqs.md index d9086b6..049a331 100644 --- a/forge/rules/test-reqs.md +++ b/forge/rules/test-reqs.md @@ -28,11 +28,11 @@ When writing or editing a `***test reqs***` section in a `.plain` file, always f ## Test type reference -| Test type | Where to specify | Purpose | -|-----------|-----------------|---------| -| Unit tests | `***implementation reqs***` | Test individual functionalities in isolation | -| Conformance tests | `***test reqs***` | Verify implementation conforms to the full spec | -| Acceptance tests | `***acceptance tests***` under a functional spec | Verify a specific functional spec | +| Test type | Where to specify | Generated | Purpose | +|-----------|-----------------|-----------|---------| +| Unit tests | `***implementation reqs***` | Automatically | Test individual functionalities in isolation | +| Conformance tests | `***test reqs***` | Automatically | Verify each functionality's implementation against its functional spec | +| Acceptance tests | `***acceptance tests***` under a functional spec | Manually | Verify implementation of a functional spec through a specific end-to-end scenario | ## No duplication - Do not duplicate guidance already present in the file or its imports From 7477caa3a9136e7d8600f7d9cc387341479d0372 Mon Sep 17 00:00:00 2001 From: Dusan Omercevic Date: Sat, 15 Aug 2026 11:26:52 +0200 Subject: [PATCH 08/14] More precise information what 'requires' modules pass on. --- forge/rules/func-specs.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/forge/rules/func-specs.md b/forge/rules/func-specs.md index ce1e0f1..e4fee18 100644 --- a/forge/rules/func-specs.md +++ b/forge/rules/func-specs.md @@ -94,7 +94,7 @@ GOOD — statements of fact with concrete subjects: ## Encapsulation - Functionality must be self-contained in the spec text -- `requires` modules only receive functional specs — do not rely on implementation reqs to convey behavior +- `requires` modules only pass on functional specs and `exported_concepts` — never implementation reqs, so do not rely on implementation reqs to convey behavior - Behavior that downstream modules need must be expressed in functional specs, not elsewhere ## Acceptance tests From 44cf1d067d07c4c18f5932f83bf2a40110c1d8bf Mon Sep 17 00:00:00 2001 From: Dusan Omercevic Date: Sat, 15 Aug 2026 11:34:44 +0200 Subject: [PATCH 09/14] More precise information what 'requires' modules pass on. --- forge/rules/impl-reqs.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/forge/rules/impl-reqs.md b/forge/rules/impl-reqs.md index 32d9ba5..b387ace 100644 --- a/forge/rules/impl-reqs.md +++ b/forge/rules/impl-reqs.md @@ -41,7 +41,7 @@ When writing or editing an `***implementation reqs***` section in a `.plain` fil - Unit testing run scripts should be linked here as a linked resource ## Encapsulation warning -- `requires` modules only receive functional specs from their dependencies — not implementation reqs +- `requires` modules only pass on functional specs and `exported_concepts` — never implementation reqs - If downstream modules need certain behavior to be visible, express it in functional specs, not here ## No duplication From 16ae80b184a0063930e8432bd2f8c590bb3906bf Mon Sep 17 00:00:00 2001 From: Dusan Omercevic Date: Sat, 15 Aug 2026 11:37:44 +0200 Subject: [PATCH 10/14] Removing a statement from impl-reqs.md that is not adding value while it might introduce confusion. --- forge/rules/impl-reqs.md | 1 - 1 file changed, 1 deletion(-) diff --git a/forge/rules/impl-reqs.md b/forge/rules/impl-reqs.md index b387ace..745f69b 100644 --- a/forge/rules/impl-reqs.md +++ b/forge/rules/impl-reqs.md @@ -51,7 +51,6 @@ When writing or editing an `***implementation reqs***` section in a `.plain` fil ## Concept references - Reference defined `:Concepts:` where they add clarity - All referenced concepts must already be defined in `***definitions***` -- Implementation reqs in non-leaf sections apply to all subsections ## Format From 0cf4c9e9bf0420701bacbba06e3af9947d55efd7 Mon Sep 17 00:00:00 2001 From: Dusan Omercevic Date: Sat, 15 Aug 2026 12:41:02 +0200 Subject: [PATCH 11/14] Small fix in linked-resources.md. --- forge/rules/linked-resources.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/forge/rules/linked-resources.md b/forge/rules/linked-resources.md index 927671a..fb5c562 100644 --- a/forge/rules/linked-resources.md +++ b/forge/rules/linked-resources.md @@ -13,7 +13,7 @@ A linked resource **must not** be any of the following: 1. **A folder / directory.** `[integrations](src/integrations/)`, `[host project](../host_project/)` are invalid — the renderer cannot ingest a directory. Pick the single most representative file inside (a `README.md`, an exemplar source file, a manifest) and link **that**. 2. **A URL / external location.** `[Stripe docs](https://stripe.com/docs/api)`, any `http://` / `https://` / `ftp://` / `git://` / `s3://` / `gs://` target. Linked resources are local-file only. If a URL's content is essential, fetch it once, save the response to a text file under `resources/`, and link the saved file. 3. **A binary file.** PNG, JPG, GIF, PDF, DOCX, XLSX, ZIP, MP3, MP4, compiled binaries (`.exe`, `.so`, `.class`, `.wasm`), and anything else that isn't human-readable text in its raw form. Binary content cannot be meaningfully consumed by the renderer — transcribe it into a text-based form first (a UI screenshot becomes a Markdown description, a PDF spec becomes a Markdown extract or the underlying JSON Schema / OpenAPI, an architecture diagram becomes a Mermaid block). -4. **Another `.plain` file.** `[Auth Module](auth.plain)` is invalid. To reference another module, use the `require` or `import` frontmatter directives. Do not link it as a markdown resource; the `plain-dry-run` will flag this as a syntax error. +4. **Another `.plain` file.** `[Auth Module](auth.plain)` is invalid. To reference another module, use the `require` or `import` frontmatter directives. Do not link it as a markdown resource; the renderer will flag this as a syntax error. ## Never use a URL or folder path as a *reference* in prose - The hard constraint above is enforced only on markdown links. A bare URL or folder path in prose (concept body, functional-spec text, implementation reqs, test reqs) passes validation and is fed to the renderer verbatim as part of the spec text From ab04bb4c06d1c6f77dec4a58951f9f8bcc012191 Mon Sep 17 00:00:00 2001 From: Dusan Omercevic Date: Sat, 15 Aug 2026 13:42:01 +0200 Subject: [PATCH 12/14] A small factual fix for required-concepts.md. --- forge/rules/required-concepts.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/forge/rules/required-concepts.md b/forge/rules/required-concepts.md index 09509ee..4f68ec2 100644 --- a/forge/rules/required-concepts.md +++ b/forge/rules/required-concepts.md @@ -16,7 +16,7 @@ When adding or editing `required_concepts` in a `.plain` file's frontmatter, alw - The import module can reference these concepts in its definitions, implementation reqs, or test reqs — but their actual definitions come from whoever imports the file ## Importing module must satisfy the contract -- Every concept listed in `required_concepts` must be defined in the importing module's own `***definitions***` section +- Every concept listed in `required_concepts` must be defined somewhere visible to the importing module — in its own `***definitions***` section or in another module it imports - If the importing module does not define a required concept, the spec is invalid - Check `required_concepts` of all imported modules before finalizing a module From e57272000c2d28266a50c42d97b479407e903185 Mon Sep 17 00:00:00 2001 From: Dusan Omercevic Date: Sat, 15 Aug 2026 14:37:04 +0200 Subject: [PATCH 13/14] Fixing a typo in test-reqs.md. --- forge/rules/test-reqs.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/forge/rules/test-reqs.md b/forge/rules/test-reqs.md index 049a331..752e49b 100644 --- a/forge/rules/test-reqs.md +++ b/forge/rules/test-reqs.md @@ -50,6 +50,6 @@ When writing or editing a `***test reqs***` section in a `.plain` file, always f - :ConformanceTests: will be run using "pytest" command. - :ConformanceTests: must be implemented and executed - do not skip tests. - :ConformanceTests: should mock all external HTTP calls. -- :ConformanceTests: are preapred via the preapre script [test_scripts/prepare_environment_python.sh](test_scripts/prepare_environment_python.sh). +- :ConformanceTests: are prepared via the prepare script [test_scripts/prepare_environment_python.sh](test_scripts/prepare_environment_python.sh). - :ConformanceTests: are executed via the run script [test_scripts/run_conformance_tests_python.sh](test_scripts/run_conformance_tests_python.sh). ``` From d223b8274ef6fdf1148d20d94938907274dfc0c9 Mon Sep 17 00:00:00 2001 From: Dusan Omercevic Date: Sat, 15 Aug 2026 14:45:15 +0200 Subject: [PATCH 14/14] Adding to rules that Liquid templates can be used. --- forge/rules/module-structure.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/forge/rules/module-structure.md b/forge/rules/module-structure.md index ed3b99c..84e159c 100644 --- a/forge/rules/module-structure.md +++ b/forge/rules/module-structure.md @@ -56,6 +56,21 @@ When creating a new `.plain` file or reviewing the structure of a whole file, al - Comments explain the specification to human authors — never use a comment to carry a requirement the renderer must implement +## Liquid templates +- `.plain` files are processed with [Liquid](https://shopify.github.io/liquid/) before parsing — the full Liquid syntax (variables, filters, conditionals, loops) is available in any section +- Expansion is **textual** and happens before the specification is interpreted — unlike `import`, which includes another module semantically (see `import-modules.md`) + +```plain +{% assign max_tags = 3 %} + +***functional specs*** + +- A :Widget: can be created with up to {{ max_tags }} tags. +{% if max_tags > 1 %} +- A :Widget: can have its tags listed. +{% endif %} +``` + ## Format ```plain