agentme 0.24.1 → 0.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  sets:
2
- - package: xdrs-core@0.30.0
2
+ - package: xdrs-core@0.37.2
3
3
  # - package: git:https://github.com/flaviostutz/xdrs-core.git@main
4
4
  selector:
5
5
  files:
@@ -23,21 +23,21 @@ This keeps the user-facing command predictable while preserving a clean library
23
23
 
24
24
  #### CLI command surface
25
25
 
26
- - CLI tools should default to the format `[tool] [command] [options] [arguments]`.
26
+ - CLI tools SHOULD default to the format `[tool] [command] [options] [arguments]`.
27
27
  - Example: `filedist extract --packages=test mydir`
28
- - A single-action tool may omit `[command]` only when adding a subcommand would be artificial and there is no meaningful action split.
29
- - Every CLI tool must expose:
28
+ - A single-action tool MAY omit `[command]` only when adding a subcommand would be artificial and there is no meaningful action split.
29
+ - Every CLI tool MUST expose:
30
30
  - `--help` on the root command
31
31
  - `--version` on the root command
32
32
  - `--verbose` on the root command and on subcommands when flags are parsed per command
33
- - Root `--help` output must list all available commands, key options, and usage examples. Command-specific help must describe that command's arguments and options.
33
+ - Root `--help` output MUST list all available commands, key options, and usage examples. Command-specific help MUST describe that command's arguments and options.
34
34
 
35
35
  #### CLI to application separation
36
36
 
37
37
  - Structure the software as `cli -> app` — the CLI adapter delegates to the application layer, following [agentme-edr-026](026-pragmatic-hexagonal-architecture.md).
38
- - The CLI layer must only parse arguments, load config, call the application layer, and format output.
39
- - Domain logic must live in the application layer and be usable without CLI globals such as `argv`, `stdout`, or process exit handlers.
40
- - Every feature available through the CLI must also be available through the application API.
38
+ - The CLI layer MUST only parse arguments, load config, call the application layer, and format output.
39
+ - Domain logic MUST live in the application layer and be usable without CLI globals such as `argv`, `stdout`, or process exit handlers.
40
+ - Every feature available through the CLI MUST also be available through the application API.
41
41
  - Organize the application layer by action so the mapping stays direct and obvious.
42
42
  - `extract` command -> `app/extract(...)`
43
43
  - `validate` command -> `app/validate(...)`
@@ -45,49 +45,49 @@ This keeps the user-facing command predictable while preserving a clean library
45
45
 
46
46
  #### Application API shape
47
47
 
48
- - Each CLI action should map to a dedicated exported application function with typed inputs and outputs appropriate for the language.
49
- - Application APIs should accept in-memory options objects or typed parameters, not require config files or environment variables unless application-level config-file support is an explicit requirement.
48
+ - Each CLI action SHOULD map to a dedicated exported application function with typed inputs and outputs appropriate for the language.
49
+ - Application APIs SHOULD accept in-memory options objects or typed parameters, not require config files or environment variables unless application-level config-file support is an explicit requirement.
50
50
  - The CLI layer is responsible for translating flags, positional arguments, and config-file contents into application inputs.
51
- - The application layer should return explicit results and errors so the CLI can decide what to print and which exit code to use.
51
+ - The application layer SHOULD return explicit results and errors so the CLI can decide what to print and which exit code to use.
52
52
 
53
53
  #### Configuration
54
54
 
55
55
  - Prefer flags and positional arguments for simple inputs.
56
56
  - When configuration becomes long, nested, or repetitive, use a YAML config file instead of pushing all values into flags. See [agentme-edr-027](../devops/027-environment-variable-configuration.md) for when `.env` values should be referenced from within that file.
57
- - By default, config-file discovery and loading must happen in the CLI layer, not in the application layer.
58
- - When a config file is supported, the CLI must try to load a YAML file from `[cwd]/[tool-name].yml` by default.
59
- - The CLI must also support an explicit config path flag such as `--config`.
60
- - The application layer must not depend on the presence of the config file; it should receive parsed configuration values from the CLI layer.
61
- - The application layer may load or parse config files only when that behavior is an explicit requirement of the application contract for non-CLI consumers as well.
57
+ - By default, config-file discovery and loading MUST happen in the CLI layer, not in the application layer.
58
+ - When a config file is supported, the CLI MUST try to load a YAML file from `[cwd]/[tool-name].yml` by default.
59
+ - The CLI MUST also support an explicit config path flag such as `--config`.
60
+ - The application layer MUST NOT depend on the presence of the config file; it SHOULD receive parsed configuration values from the CLI layer.
61
+ - The application layer MAY load or parse config files only when that behavior is an explicit requirement of the application contract for non-CLI consumers as well.
62
62
 
63
63
  #### Output and progress
64
64
 
65
- - Standard output must show a start message when work begins and a result message when work completes successfully.
65
+ - Standard output MUST show a start message when work begins and a result message when work completes successfully.
66
66
  - When processing is long-running or multi-stage, print concise intermediate progress messages.
67
- - `--verbose` must reveal more internal detail about what the tool is doing without changing the meaning of the command result.
68
- - Default output should stay concise and readable for humans.
69
- - Errors should be written to standard error with an actionable message. Stack traces or raw internal errors should stay hidden by default and may be shown in verbose mode.
67
+ - `--verbose` MUST reveal more internal detail about what the tool is doing without changing the meaning of the command result.
68
+ - Default output SHOULD stay concise and readable for humans.
69
+ - Errors SHOULD be written to standard error with an actionable message. Stack traces or raw internal errors SHOULD stay hidden by default and MAY be shown in verbose mode.
70
70
 
71
71
  #### Exit behavior
72
72
 
73
73
  - Exit with `0` only when the requested action completed successfully.
74
74
  - Exit with `1` when the requested action could not be completed.
75
- - The application layer should surface failure as return values, result objects, or language-idiomatic errors; the CLI is responsible for converting that outcome into user-facing messages and process exit codes.
75
+ - The application layer SHOULD surface failure as return values, result objects, or language-idiomatic errors; the CLI is responsible for converting that outcome into user-facing messages and process exit codes.
76
76
 
77
77
  #### Documentation
78
78
 
79
- - `README.md` must include at least 4 CLI usage examples.
80
- - `README.md` must include at least 2 application API examples for the same operation also available through the CLI.
81
- - If the tool supports config files, at least 1 README example should show config-file usage.
82
- - Examples must use the public command and public application API, not internal modules or private files.
79
+ - `README.md` MUST include at least 4 CLI usage examples.
80
+ - `README.md` MUST include at least 2 application API examples for the same operation also available through the CLI.
81
+ - If the tool supports config files, at least 1 README example SHOULD show config-file usage.
82
+ - Examples MUST use the public command and public application API, not internal modules or private files.
83
83
 
84
84
  #### Distribution and versioning
85
85
 
86
- - The implementation language is project-dependent, but the packaging and entry-point strategy must match how users are expected to run the tool.
86
+ - The implementation language is project-dependent, but the packaging and entry-point strategy MUST match how users are expected to run the tool.
87
87
  - Choose language tooling that stays compatible with ecosystem launchers such as `npx`, `pnpm dlx`, `uvx`, or equivalent distribution commands for that ecosystem.
88
- - `--version` must print the same version declared in the published package or release artifact metadata.
88
+ - `--version` MUST print the same version declared in the published package or release artifact metadata.
89
89
  - Do not hard-code a second version string that can drift from the published package version.
90
- - Language-specific project structure and packaging rules still apply and should be combined with this XDR, especially [agentme-edr-003](003-javascript-project-tooling.md), [agentme-edr-010](010-golang-project-tooling.md), and [agentme-edr-014](014-python-project-tooling.md).
90
+ - Language-specific project structure and packaging rules still apply and SHOULD be combined with this XDR, especially [agentme-edr-003](003-javascript-project-tooling.md), [agentme-edr-010](010-golang-project-tooling.md), and [agentme-edr-014](014-python-project-tooling.md).
91
91
 
92
92
  ## Considered Options
93
93
 
@@ -9,7 +9,7 @@ valid-from: 2026-05-27
9
9
 
10
10
  ## Context and Problem Statement
11
11
 
12
- ML projects accumulate datasets of different shapes: file-paired annotations, tabular CSVs, and structured JSONL records. Without a shared layout convention, tooling and agents cannot reliably discover schema files, consume data programmatically, or understand what a dataset contains.
12
+ ML projects accumulate datasets of different shapes: file-paired annotations, tabular CSVs, and complex per-record structures. Without a shared layout convention, tooling and agents cannot reliably discover schema files, consume data programmatically, or understand what a dataset contains.
13
13
 
14
14
  How should ML datasets be organized on disk so they are self-describing, easy to consume, and consistent across dataset types?
15
15
 
@@ -58,6 +58,8 @@ Placing the annotation file next to its source file (same name + `.json`) keeps
58
58
 
59
59
  Subdirectories inside `data/` are allowed when the number of files warrants grouping, but the `.json` sibling convention MUST be preserved at each level.
60
60
 
61
+ Each `.json` annotation file MUST include a top-level `$schema` property whose value is the correct relative path to the dataset's root `dataset.schema.json`, accounting for subdirectory depth (e.g. `"$schema": "../dataset.schema.json"` at one level, `"../../dataset.schema.json"` at two levels). This is the standard editor-tooling convention for associating a JSON instance with its schema, and is validated by rule `06`.
62
+
61
63
  #### 03-tabular-datasets-must-use-csv-files-at-root
62
64
 
63
65
  Datasets composed of column-oriented tabular data MUST place CSV files at the root of the dataset folder. All tabular files MUST conform to the schema defined in `dataset.schema.json`, which MUST describe columns as named attributes with their types.
@@ -70,27 +72,40 @@ Datasets composed of column-oriented tabular data MUST place CSV files at the ro
70
72
  README.md
71
73
  ```
72
74
 
73
- Multiple CSV files are allowed when they represent different slices or splits of the same schema (e.g. train/test splits, subsets by source). All files in the same dataset MUST share the same column schema.
75
+ Multiple CSV files are allowed when they represent different slices or splits of the same schema (e.g. train/test splits, subsets by source). All files in the same dataset MUST share the same column schema. Each row MUST also be validated by `make lint` per rule `06` — CSV has no `$schema` field (not applicable to that format), so only the row content is checked, not a schema pointer.
74
76
 
75
- #### 04-complex-structured-datasets-must-use-jsonl
77
+ #### 04-complex-structured-datasets-must-use-per-entry-json-files
76
78
 
77
- Datasets with complex or heterogeneous per-record structures (e.g. LLM workflow evaluation sets, Q&A pairs, input → expected_output pairs) MUST use JSONL files (one JSON object per line) placed at the root of the dataset folder. Each line MUST conform to the schema defined in `dataset.schema.json`.
79
+ Datasets with complex or heterogeneous per-record structures (e.g. LLM workflow evaluation sets, Q&A pairs, input → expected_output pairs) MUST use one JSON file per entry, placed inside the `data/` subfolder. Each file MUST conform to the schema defined in `dataset.schema.json`.
78
80
 
79
81
  ```
80
82
  /[name-of-dataset]/
81
- simple-cases-test.jsonl
82
- edge-cases-test.jsonl
83
- dataset.schema.json (schema defining the structure of each line in the JSONL files)
83
+ data/
84
+ case-001.json
85
+ case-002.json
86
+ dataset.schema.json (schema defining the structure of each entry file)
84
87
  README.md
85
88
  ```
86
89
 
87
- Multiple JSONL files are allowed when they represent different splits or categories (e.g. easy vs. edge cases). All files in the same dataset MUST conform to the same line schema.
90
+ Each entry file MUST include a top-level `$schema` property whose value is the correct relative path to the dataset's root `dataset.schema.json`, accounting for subdirectory depth (e.g. `"$schema": "../dataset.schema.json"` at one level, `"../../dataset.schema.json"` at two levels), validated by rule `06`.
91
+
92
+ Subdirectories inside `data/` are allowed for grouping entries by collection source, time period, actor, or similar dimensions when the number of files warrants it. ALL files in one dataset MUST conform to the SAME `dataset.schema.json` — if a project needs a different schema for a different set of entries, that MUST be a separate dataset (its own folder, README, and `dataset.schema.json`), not multiple schemas inside one dataset.
88
93
 
89
94
  #### 05-referenced-files-must-live-in-data-folder
90
95
 
91
- When any dataset type (tabular, JSONL, or annotation-pair) contains references to external files as part of the data (e.g. a JSONL record that includes a file path), those referenced files MUST be stored inside the `data/` subfolder of the dataset. Paths inside data records MUST be relative to the dataset root.
96
+ When any dataset type (tabular, per-entry JSON, or annotation-pair) contains references to external files as part of the data (e.g. an entry record that includes a file path), those referenced files MUST be stored inside the `data/` subfolder of the dataset. Paths inside data records MUST be relative to the dataset root.
97
+
98
+ #### 06-datasets-must-be-lint-validated-against-schema
99
+
100
+ Every dataset MUST expose a `make lint` target (in the Makefile of the project/component that owns the dataset) that validates its data against `dataset.schema.json` using the Python [`jsonschema`](https://pypi.org/project/jsonschema/) library:
101
+
102
+ - Per-entry JSON files (rule `04`) and annotation-pair `.json` siblings (rule `02`) MUST each be validated against `dataset.schema.json`, and their `$schema` property MUST be present and resolve to the dataset's actual schema file.
103
+ - CSV rows (rule `03`) MUST each be converted to a JSON object (column header → value) and validated against the same `dataset.schema.json`.
104
+ - `make lint` MUST list every violation found across all files/rows before exiting with a non-zero status (not fail-fast on the first violation).
105
+ - `jsonschema` MUST be declared as a normal project dependency per [agentme-edr-014](014-python-project-tooling.md); no special-casing.
92
106
 
93
107
  ## References
94
108
 
95
109
  - [JSON Schema specification](https://json-schema.org/)
96
- - [JSONL format](https://jsonlines.org/)
110
+ - [jsonschema (Python library)](https://pypi.org/project/jsonschema/)
111
+ - [agentme-edr-014](014-python-project-tooling.md) — Python project tooling and dependency conventions
@@ -56,6 +56,14 @@ Every application is conceptually divided into three layers:
56
56
  - Group related logic into subfolders (aggregation roots)
57
57
  - Environment variables must be read only in the bootstrap/entry-point layer of inbound adapters, converted into typed configuration objects, and passed explicitly to all other components
58
58
 
59
+ - Data flow examples
60
+
61
+ ```text
62
+ HTTP request → adapters/http/ → app/create-user → adapters/connectors/postgres/
63
+ CLI command → adapters/cli/ → app/create-dir → adapters/connectors/local-fs/
64
+ Kafka message → adapters/kafka/ → app/process-event → adapters/connectors/stripe-api/
65
+ ```
66
+
59
67
  #### 04-mandatory-folder-structure
60
68
 
61
69
  ```text
@@ -98,15 +106,56 @@ mysystem/
98
106
  - Trivial scripts and single-purpose tools (fewer than ~300 lines with a single I/O boundary) MAY skip this layering
99
107
  - All other projects MUST use this structure from the start
100
108
 
101
- #### 08-examples-of-data-flow
109
+ #### 09-unit-testing-and-mocking-strategy
102
110
 
103
- ```text
104
- HTTP request → adapters/http/ → app/create-user → adapters/connectors/postgres/
105
- CLI command → adapters/cli/ → app/create-dir → adapters/connectors/local-fs/
106
- Kafka message → adapters/kafka/ → app/process-event → adapters/connectors/stripe-api/
111
+ Unit tests for the `app/` layer MUST mock outbound adapter/connector interfaces at the `app/` → `adapters/connectors/` boundary. Inject connectors as constructor parameters or function arguments so tests can substitute them without touching real databases, HTTP APIs, or external services.
112
+
113
+ The connector implementations themselves SHOULD have their own unit tests that mock the underlying SDK or HTTP client.
114
+
115
+ ```python
116
+ # Good — inject connector; unit test mocks it
117
+ class OrderService:
118
+ def __init__(self, db: OrderRepository):
119
+ self.db = db
120
+
121
+ def test_create_order_persists_record():
122
+ fake_db = FakeOrderRepository()
123
+ service = OrderService(db=fake_db)
124
+ order = service.create({"item": "widget", "qty": 2})
125
+ assert fake_db.find(order.id) is not None
107
126
  ```
108
127
 
128
+ Inbound adapters (`cli/`, `http/`, `grpc/`) are entry points and do not need to be mocked — test the `app/` layer directly by injecting fakes for its outbound connectors. See rule `10` for the naming and placement convention for shared mock files.
129
+
130
+ #### 10-mock-file-strategy
131
+
132
+ When a mock implementation needs to be **reused across multiple tests or imported by an eval script** (e.g. `eval.py` using `mock_fixtures` from [agentme-edr-030](030-ai-test-types-taxonomy.md) rule `02`), define it in a dedicated `_mock` file rather than inline.
133
+
134
+ **When to use a `_mock` file vs inline:**
135
+ - Single-test use → define the mock inline inside the test file (per rule `09` example; no file needed)
136
+ - Reusable across multiple tests OR used from `eval.py` → define in a separate `_mock` file
137
+
138
+ **Scope:** applies to any source file in `adapters/connectors/`, `app/`, or `shared/`. MUST NOT be used for inbound adapters (`cli/`, `http/`, `grpc/`) — those are entry points and are never mocked (rule `09`).
139
+
140
+ **Naming:** insert `_mock` immediately before the file extension:
141
+
142
+ | Source file | Mock file |
143
+ |---|---|
144
+ | `client.py` | `client_mock.py` |
145
+ | `order_service.ts` | `order_service_mock.ts` |
146
+ | `user_store.go` | `user_store_mock_test.go` |
147
+
148
+ **Placement:** follows the project's test file placement convention per [agentme-edr-004](../principles/004-unit-test-requirements.md) rule `04`:
149
+ - Co-located test convention (TypeScript, Go) → mock file in the same directory as the source file
150
+ - Separate test folder convention (Python) → mock file mirrors the source path under the test folder (e.g. `lib/src/<pkg>/adapters/connectors/user-db/client.py` → `lib/tests/<pkg>/adapters/connectors/user-db/client_mock.py`)
151
+
152
+ **Mock contract:**
153
+ - MUST accept a `fixtures` parameter (constructor argument or factory function argument); the value is whatever `mock_fixtures[key]` contains from the dataset entry — its internal structure is opaque and interpreted by the mock implementation
154
+ - MUST NOT fall back to real external calls under any circumstance — if a call cannot be satisfied from the provided fixtures, MUST raise an explicit error (never silently return `null`, `undefined`, or an empty value)
155
+
109
156
  ## References
110
157
 
111
158
  - [agentme-edr-016](../principles/016-cross-language-module-structure.md) — Defines the module-root structure (Makefile, dist/, .cache/) that wraps this internal layout
112
159
  - [agentme-edr-002](../principles/002-coding-best-practices.md) — File size limits and code organization practices that complement this architecture
160
+ - [agentme-edr-004](../principles/004-unit-test-requirements.md) — Rule `04`: test file placement convention per language (governs `_mock` file placement in rule `10`)
161
+ - [agentme-edr-030](030-ai-test-types-taxonomy.md) — Rule `02`: `mock_fixtures` golden dataset envelope that drives `_mock` usage in eval scripts
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: agentme-edr-policy-028-ai-eval-standards
3
- description: Defines how to structure, write, and run eval tests for AI projects — folder layout, script requirements, and MLflow tracking. Use when implementing evals for LLM, Agent, or Workflow projects. For when evals are required see agentme-edr-007 rule 09-ai-project-testing-requirements.
3
+ description: Defines how to structure, write, and run eval tests for AI projects — folder layout, golden dataset, --type test-type filtering, mock_fixtures wiring, entry-first eval loop, per-type Makefile targets and reports, and MLflow tracking. Use when implementing evals for LLM, Agent, or Workflow projects. For when evals are required see agentme-edr-007 rule 09-ai-project-testing-requirements. For the test type taxonomy and mock_fixtures envelope see agentme-edr-030. For mock file naming see agentme-edr-026 rule 10.
4
4
  apply-to: Python AI projects (LLM, Agent, or Workflow tier) that implement eval testing
5
5
  valid-from: 2026-06-05
6
6
  ---
@@ -29,10 +29,10 @@ Evals are grouped first by the component being evaluated, then by the specific e
29
29
  evals/
30
30
  <component>/ # the component being evaluated (e.g., workflow-x, agent-y, model-z)
31
31
  eval-<name>/
32
- dataset/ # EDR-024 compliant dataset (README.md, dataset.schema.json, data/)
32
+ golden_dataset/ # EDR-024 + EDR-030 compliant golden dataset (README.md, dataset.schema.json, data/)
33
33
  eval.py # evaluation script
34
- report.md # generated report (overwritten on each run — see rule 03)
35
- Makefile # eval and run targets
34
+ report-<type>.md # generated report, one per evaluated test type (overwritten on each run — see rule 03)
35
+ Makefile # lint, eval, run, and eval-<type> targets
36
36
  eval-<name2>/
37
37
  ...
38
38
  <component2>/
@@ -41,73 +41,126 @@ evals/
41
41
 
42
42
  `<component>` MUST match the name of the component under evaluation and use lowercase hyphen-separated words (e.g., `workflow-document-review`, `agent-support`, `model-classifier`).
43
43
 
44
- `<name>` identifies the specific evaluation scenario using lowercase hyphen-separated words (e.g., `eval-basic`, `eval-complex`, `eval-edge-cases`, `eval-bias-test`).
44
+ `<name>` identifies the specific evaluation scenario using lowercase hyphen-separated words (e.g., `eval-basic`, `eval-complex`, `eval-edge-cases`). A scenario's `golden_dataset` MAY mix multiple test types across its entries: label each entry with its applicable `test_types` ([agentme-edr-030](030-ai-test-types-taxonomy.md) rule `04`) and use the `eval-<type>` targets below to run one type at a time.
45
45
 
46
- The `dataset/` subfolder MUST be a valid [agentme-edr-024](024-ml-dataset-structure.md) dataset — it MUST include `README.md` and `dataset.schema.json` at its root. For input/output pairs, use JSONL files per `agentme-edr-024.04-complex-structured-datasets-must-use-jsonl`.
46
+ The `golden_dataset/` subfolder MUST be a valid [agentme-edr-024](024-ml-dataset-structure.md) dataset (`README.md`, `dataset.schema.json`, one JSON file per entry under `data/` per rule `04-complex-structured-datasets-must-use-per-entry-json-files`, lint-validated per rule `06`) whose entries follow the golden dataset envelope defined in [agentme-edr-030](030-ai-test-types-taxonomy.md) rule `02`.
47
47
 
48
- Each `evals/<component>/eval-<name>/Makefile` MUST define:
48
+ Each `evals/<component>/eval-<name>/Makefile` MUST declare a `TEST_TYPES` variable listing the `test_types` values present in its golden dataset, and define:
49
49
 
50
50
  | Target | Behaviour |
51
51
  |---|---|
52
- | `eval` | Runs the eval with threshold enforcement; exits non-zero on failure (CI-safe) |
53
- | `run` | Runs the eval without threshold enforcement (exploration / debugging) |
52
+ | `lint` | Validates every `golden_dataset/data/*.json` file against `golden_dataset/dataset.schema.json` per [agentme-edr-024](024-ml-dataset-structure.md) rule `06` |
53
+ | `eval` | Depends on `lint`; runs `eval.py --type=all` with threshold enforcement; exits non-zero on failure (CI-safe) |
54
+ | `run` | Depends on `lint`; runs `eval.py --type=all` without threshold enforcement (exploration / debugging) |
55
+ | `eval-<type>` | Depends on `lint`; runs `eval.py --type=<type>` for one declared test type, following [agentme-edr-008](../devops/008-common-targets.md) rule `03`'s `eval-<qualifier>` convention |
54
56
 
55
- The module root Makefile MUST expose a `make eval` target that delegates to `eval` in every `evals/<component>/eval-<name>/Makefile`:
57
+ ```makefile
58
+ TEST_TYPES := smoke functional safety
59
+
60
+ lint:
61
+ mise exec -- uv run --project . python lint_dataset.py golden_dataset/
62
+
63
+ eval: lint
64
+ mise exec -- uv run --project . python eval.py --type=all
65
+
66
+ run: lint
67
+ mise exec -- uv run --project . python eval.py --type=all --no-threshold
68
+
69
+ eval-%: lint
70
+ mise exec -- uv run --project . python eval.py --type=$*
71
+ ```
72
+
73
+ The module root Makefile MUST expose `make eval` and `make lint` targets that delegate to `eval` and `lint` respectively in every `evals/<component>/eval-<name>/Makefile`:
56
74
 
57
75
  ```makefile
58
76
  eval:
59
77
  $(MAKE) -C evals/workflow-document-review/eval-basic eval
60
78
  $(MAKE) -C evals/workflow-document-review/eval-complex eval
79
+
80
+ lint:
81
+ $(MAKE) -C evals/workflow-document-review/eval-basic lint
82
+ $(MAKE) -C evals/workflow-document-review/eval-complex lint
61
83
  ```
62
84
 
63
85
  #### 02-eval-script-requirements
64
86
 
65
87
  Each `eval.py` script MUST:
66
88
 
67
- - Load the dataset from `dataset/` in the same eval folder, following [agentme-edr-024](024-ml-dataset-structure.md). For input/output pairs, use the JSONL format per `agentme-edr-024.04-complex-structured-datasets-must-use-jsonl`.
68
- - Run every input through the live component against **real LLM providers** (not mocked responses), to capture model drift.
69
- - Log per-sample and aggregate metrics to an MLflow experiment that runs **locally**a remote MLflow server MUST NOT be required.
70
- - Compare outputs to expected values using project-defined quality thresholds. Thresholds MUST be declared explicitly (e.g., in a Makefile variable or README).
71
- - Write `report.md` in the same folder per rule `03-eval-report-file`.
72
- - Exit with a non-zero status when any metric falls below its defined threshold, consistent with [agentme-edr-007](../principles/007-project-quality-standards.md) rule `07-statistical-models-must-have-eval-targets`.
89
+ - Load the golden dataset from `golden_dataset/` in the same eval folder, following [agentme-edr-024](024-ml-dataset-structure.md) and the entry envelope in [agentme-edr-030](030-ai-test-types-taxonomy.md) rule `02` (one JSON file per entry, `test_types` array, `input`, `expected_output`, optional `mock_fixtures`).
90
+ - Accept a required `--type=<test_type>|all` CLI argument and filter entries whose `test_types` array contains the requested value; `--type=all` includes every entry.
91
+ - Iterate **entry-first**: for each entry in the filtered set, invoke the real component exactly once; then score that single `actual_output` for every `test_types` value the entry carries that falls within the current `--type` scope never invoke the component more than once per entry per run.
92
+ - When an entry contains `mock_fixtures` ([agentme-edr-030](030-ai-test-types-taxonomy.md) rule `02`), configure each named mock adapter with its fixture data BEFORE invoking the component for that entry. Each entry MUST use fresh mock instances so fixture state does not bleed across entries. `mock_fixtures` applies to all test types including `human`. `mock_fixtures` MUST NOT configure LLM adapters — the LLM call MUST always be real (see [agentme-edr-030](030-ai-test-types-taxonomy.md) rule `03`). How mock adapters are discovered and instantiated is left to the project; see [agentme-edr-026](026-pragmatic-hexagonal-architecture.md) rule `10` for the `_mock` file naming and placement convention.
93
+ - Run every component invocation against **real LLM providers** (not mocked responses), to capture model drift.
94
+ - For `human` entries: invoke the component to capture `actual_output`, export each entry's `input`, `expected_output.human_test` instructions, and `actual_output` into a manual-review checklist (`report-human.md`). MUST NOT invoke an automated scorer and MUST NOT enforce a pass/fail threshold for it. Other `test_types` on the same entry (e.g. `functional`) are still scored automatically.
95
+ - After all entries are processed, compute aggregate metrics per test type, log them to a local MLflow experiment (see rule `04`), write one `report-<type>.md` per evaluated test type (rule `03`), and exit with a non-zero status when any metric falls below its defined threshold per [agentme-edr-007](../principles/007-project-quality-standards.md) rule `07-statistical-models-must-have-eval-targets`. The `human` type has no threshold and does not trigger a non-zero exit.
96
+ - Compare outputs to expected values using project-defined quality thresholds per test type. Thresholds MUST be declared explicitly (e.g., in a Makefile variable or README) — this Policy does not mandate which test types a project must threshold or what value to use (see [agentme-edr-030](030-ai-test-types-taxonomy.md) rule `06`).
73
97
 
74
98
  **Example:**
75
99
 
76
100
  ```python
101
+ import argparse
102
+ from collections import defaultdict
77
103
  import mlflow
78
104
  from my_package.app.workflows.document_review_workflow.graph import graph
79
105
 
80
- EVAL_MIN_ACCURACY = 0.85
106
+ EVAL_MIN_ACCURACY = {"functional": 0.85, "smoke": 0.85}
107
+
108
+ parser = argparse.ArgumentParser()
109
+ parser.add_argument("--type", required=True)
110
+ args = parser.parse_args()
81
111
 
82
- with mlflow.start_run() as run:
83
- results = []
84
- for sample in load_dataset("dataset/"):
85
- output = graph.invoke({"document": sample["input"]})
86
- results.append(output["label"] == sample["expected_label"])
112
+ entries = load_golden_dataset("golden_dataset/", test_type=args.type) # "all" loads every entry
113
+ resolved_types = resolve_types(args.type, entries)
87
114
 
88
- accuracy = sum(results) / len(results)
89
- mlflow.log_metric("accuracy", accuracy)
115
+ mlflow.set_experiment("document-review/eval-basic")
90
116
 
91
- write_eval_report(run, results, thresholds={"accuracy": EVAL_MIN_ACCURACY})
117
+ with mlflow.start_run():
118
+ mlflow.set_tag("test_types", ",".join(sorted(resolved_types)))
92
119
 
93
- if accuracy < EVAL_MIN_ACCURACY:
94
- raise SystemExit(f"Eval failed: accuracy {accuracy:.2f} < {EVAL_MIN_ACCURACY}")
120
+ results = defaultdict(list)
121
+
122
+ # Entry-first loop: invoke each entry exactly once
123
+ for entry in entries:
124
+ # Configure mock adapters from mock_fixtures before invocation
125
+ # (implementation left to the project — see agentme-edr-026 rule 10)
126
+ if entry.get("mock_fixtures"):
127
+ configure_mocks(entry["mock_fixtures"]) # project-defined helper
128
+
129
+ actual_output = invoke_component(entry, graph)
130
+
131
+ for test_type in [t for t in entry["test_types"] if t in resolved_types]:
132
+ if test_type == "human":
133
+ export_human_review(entry, actual_output)
134
+ continue
135
+ results[test_type].append(score(test_type, actual_output, entry["expected_output"]))
136
+
137
+ # Aggregate, report, and enforce thresholds per test type
138
+ for test_type in resolved_types:
139
+ if test_type == "human":
140
+ continue
141
+
142
+ accuracy = sum(results[test_type]) / len(results[test_type])
143
+ mlflow.log_metric(f"{test_type}_accuracy", accuracy)
144
+ write_eval_report(test_type, results[test_type], thresholds={"accuracy": EVAL_MIN_ACCURACY[test_type]})
145
+
146
+ if accuracy < EVAL_MIN_ACCURACY[test_type]:
147
+ raise SystemExit(f"Eval failed: {test_type} accuracy {accuracy:.2f} < {EVAL_MIN_ACCURACY[test_type]}")
95
148
  ```
96
149
 
97
150
  #### 03-eval-report-file
98
151
 
99
- Each eval script MUST produce `report.md` in the same `evals/<component>/eval-<name>/` folder and overwrite it on every run.
152
+ Each eval script MUST produce one `report-<type>.md` per evaluated test type in the same `evals/<component>/eval-<name>/` folder and overwrite each on every run — only the types included in the current `--type` invocation are (re)written; report files for other types are left untouched. The `human` type does not produce a metrics report (see below).
100
153
 
101
154
  **Generation constraint:** The report MUST be produced programmatically, reading raw metric values directly from MLflow. No LLM or generative model may write, summarize, or paraphrase any section of the report, to prevent hallucinated metric values.
102
155
 
103
156
  The report MUST follow this template:
104
157
 
105
158
  ```markdown
106
- # Eval Report: <name>
159
+ # Eval Report: <name> — <type>
107
160
 
108
161
  **Date:** <ISO date>
109
- **Dataset:** dataset/
110
- **Script:** eval.py
162
+ **Dataset:** golden_dataset/
163
+ **Script:** eval.py --type=<type>
111
164
  **Thresholds:** accuracy ≥ <value>, F1 ≥ <value>
112
165
 
113
166
  ## Overall Results
@@ -142,14 +195,14 @@ $$\frac{\hat{p} + \frac{z^2}{2n} \pm z\sqrt{\frac{\hat{p}(1-\hat{p})}{n} + \frac
142
195
 
143
196
  Where $\hat{p}$ is observed accuracy and $n$ is sample count. Accuracy and F1 are required; precision and recall are recommended.
144
197
 
145
- **Filled-in example** (`evals/workflow-document-review/eval-basic/report.md` for a document review workflow):
198
+ **Filled-in example** (`evals/workflow-document-review/eval-basic/report-functional.md` for a document review workflow):
146
199
 
147
200
  ```markdown
148
- # Eval Report: eval-basic
201
+ # Eval Report: eval-basic — functional
149
202
 
150
203
  **Date:** 2026-06-12
151
- **Dataset:** dataset/
152
- **Script:** eval.py
204
+ **Dataset:** golden_dataset/
205
+ **Script:** eval.py --type=functional
153
206
  **Thresholds:** accuracy ≥ 0.85, F1 ≥ 0.80
154
207
 
155
208
  ## Overall Results
@@ -169,7 +222,7 @@ Where $\hat{p}$ is observed accuracy and $n$ is sample count. Accuracy and F1 ar
169
222
  ## Per-item Results
170
223
 
171
224
  | ID | Input Summary | Expected | Actual | Correct |
172
- |-----|-------------------------------------|----------|----------|---------|
225
+ |-----|--------------------------------------|----------|----------|---------|
173
226
  | 001 | Contract renewal, 3 pages, standard | approve | approve | ✓ |
174
227
  | 002 | NDA with unusual liability clause | escalate | escalate | ✓ |
175
228
  | 003 | Vendor invoice, missing PO number | reject | reject | ✓ |
@@ -179,20 +232,26 @@ Where $\hat{p}$ is observed accuracy and $n$ is sample count. Accuracy and F1 ar
179
232
  ## Notes
180
233
 
181
234
  - Sample 005 misclassified: redlined IP clause not flagged as escalation trigger. Possible model drift.
182
- - MLflow run: experiment `workflow-document-review/eval-basic` — view with `mlflow ui`
235
+ - MLflow run: experiment `workflow-document-review/eval-basic`, tag `test_types=functional` — view with `mlflow ui`
183
236
  ```
184
237
 
238
+ **`human` type artifact:** instead of `report-human.md` with metrics, `--type=human` produces a checklist artifact (still named `report-human.md`) listing, per entry, its `input`, `expected_output.human_test` instructions, and the captured `actual_output` — with no Overall Results table, threshold, or PASS/FAIL section, since this type is never auto-scored.
239
+
185
240
  #### 04-eval-mlflow-unique-port
186
241
 
187
242
  Each `evals/<component>/eval-<name>/Makefile` MUST start its MLflow tracking server on a **unique port** to prevent conflicts when multiple eval Makefiles are run concurrently or in parallel (e.g., in CI or across multiple terminal sessions).
188
243
 
189
- Ports MUST be statically assigned per eval scenario and MUST NOT reuse the default `5000` port (reserved for `dev-mlflow` per [agentme-edr-008](../devops/008-common-targets.md) rule `09-ai-project-dev-targets`). Assign ports starting at `5100` and incrementing by 1 for each additional eval scenario across the entire project.
244
+ Ports MUST be statically assigned per eval scenario (not per test type) and MUST NOT reuse the default `5000` port (reserved for `dev-mlflow` per [agentme-edr-008](../devops/008-common-targets.md) rule `09-ai-project-dev-targets`). Assign ports starting at `5100` and incrementing by 1 for each additional eval scenario across the entire project.
245
+
246
+ The MLflow **experiment** is scoped to the eval scenario: `<component>/<eval-name>` (e.g. `document-review/eval-basic`). Each `mlflow.start_run()` call MUST set a `test_types` tag listing the test types evaluated in that invocation (comma-separated, e.g. `"functional,smoke"` for `--type=all`, `"smoke"` for `--type=smoke`). A remote MLflow server MUST NOT be required — all tracking is local.
190
247
 
191
248
  ## References
192
249
 
193
250
  - [agentme-edr-007](../principles/007-project-quality-standards.md) — Project quality standards: when evals are required per AI tier (rule `09-ai-project-testing-requirements`) and statistical model eval targets (rule `07-statistical-models-must-have-eval-targets`)
251
+ - [agentme-edr-030](030-ai-test-types-taxonomy.md) — AI test types taxonomy: `test_types` enum, golden dataset entry envelope (including `mock_fixtures`), and mocking constraints per type
252
+ - [agentme-edr-026](026-pragmatic-hexagonal-architecture.md) — Rule `10`: `_mock` file naming and placement convention for mock adapters used in `mock_fixtures`
194
253
  - [agentme-edr-018](018-ai-llm-development-standards.md) — LLM development standards: LangChain framework and observability
195
254
  - [agentme-edr-019](019-ai-agents-development-standards.md) — Agent development standards
196
255
  - [agentme-edr-021](021-ai-workflow-development-standards.md) — Workflow development standards
197
-
198
- - [agentme-edr-024](024-ml-dataset-structure.md) — ML dataset structure for eval datasets
256
+ - [agentme-edr-024](024-ml-dataset-structure.md) — ML dataset structure, per-entry JSON format, and schema-lint validation for golden datasets
257
+ - [agentme-edr-008](../devops/008-common-targets.md) — `eval-<qualifier>` Makefile convention (rule `03`) and Mise tool-execution flow (rule `02`)
@@ -0,0 +1,96 @@
1
+ ---
2
+ name: agentme-edr-policy-030-ai-test-types-taxonomy
3
+ description: Names AI-application test types (safety, responsible-AI, quality-eval, prompt, code-level) with their group, objective, mocking constraint, and relevance, and defines the shared "golden dataset" entry envelope that agentme-edr-028's eval tooling filters by test_types. Use when deciding which AI test types to implement or when authoring a golden dataset entry.
4
+ apply-to: AI projects (LLM, Agent, or Workflow tier) implementing AI-specific test types beyond generic code-level unit/integration tests
5
+ valid-from: 2026-07-05
6
+ ---
7
+
8
+ # agentme-edr-policy-030: AI test types taxonomy
9
+
10
+ ## Context and Problem Statement
11
+
12
+ AI components need test types beyond generic unit/integration tests (safety, fairness, groundedness, functional accuracy, etc.). Which test types should be named, and how should their datasets and eval tooling work?
13
+
14
+ ## Decision Outcome
15
+
16
+ **Adopt a named taxonomy of AI test types plus a shared "golden dataset" entry envelope that agentme-edr-028's eval tooling filters by `test_types`.**
17
+
18
+ Each test type is named with its group, objective, mocking constraint, applicability, and relevance; every golden dataset entry is labeled with the test types it applies to.
19
+
20
+ ### Details
21
+
22
+ #### 01-golden-dataset-concept
23
+
24
+ A **golden dataset** comprises all eval case entries used to test an AI component (LLM, Agent, or Workflow tier); each entry is labeled with the `test_types` (rule `04`) it applies to. It is the dataset consumed by [agentme-edr-028](028-ai-eval-standards.md) evals and stored as one JSON file per entry per [agentme-edr-024](024-ml-dataset-structure.md) rule `04`, at `evals/<component>/eval-<name>/golden_dataset/`.
25
+
26
+ #### 02-golden-dataset-entry-envelope
27
+
28
+ Every golden dataset entry (a JSON file in `golden_dataset/data/`) MUST have this shape, in addition to any project-specific fields:
29
+
30
+ ```json
31
+ {
32
+ "$schema": "../dataset.schema.json",
33
+ "test_types": ["functional"],
34
+ "input": "...",
35
+ "expected_output": "...",
36
+ "mock_fixtures": {
37
+ "system_y": [{"123": {"name": "Flavio"}}, {"456": {"name": "Andrew"}}]
38
+ }
39
+ }
40
+ ```
41
+
42
+ - `test_types` — array, values MUST come from rule `04`'s enum, MUST contain at least one value. An entry MAY carry more than one value additively (e.g. `["functional", "smoke", "human"]`) — no test type excludes another.
43
+ - `input` — for Prompt-tier components, a raw prompt string or the prompt template's input parameters object; for Agent/Workflow-tier components, the input attributes object passed to the component.
44
+ - `expected_output` — the fields used to score the entry under each of its automated `test_types`: output attributes for an LLM-as-judge rubric, a target for vector-similarity scoring, or exact attribute values for strict comparison. When `human` is one of the entry's `test_types`, `expected_output` MUST additionally include a `human_test` string field with manual-verification instructions (e.g. `"check for ethical issues, verify record change in system X"`) — this supplements, and never replaces, the entry's automated scoring fields.
45
+ - `mock_fixtures` — optional object; keys identify the adapter or external system to mock (SHOULD match the connector folder name under `adapters/connectors/<name>` for readability, though not enforced), values are any valid JSON interpreted by the mock implementation. When present, eval.py MUST configure each named mock adapter with its fixture data BEFORE invoking the component for that entry; each entry MUST use fresh mock instances to prevent state from bleeding across entries. `mock_fixtures` applies to all `test_types` including `human` — the component is still invoked for human entries to capture `actual_output`. `mock_fixtures` MUST NOT include keys for LLM adapters: all golden dataset test types are rated `mocks disallowed for LLM calls` (rule `03`), so the LLM call MUST always be real; LLM provider mocking belongs exclusively to unit tests via [agentme-edr-018](018-ai-llm-development-standards.md) rule `04`. See [agentme-edr-026](026-pragmatic-hexagonal-architecture.md) rule `10` for the `_mock` file naming and placement convention.
46
+ - The dataset's `dataset.schema.json` MUST require `test_types`, `input`, and `expected_output`, and SHOULD declare `mock_fixtures` as optional (`"type": "object", "additionalProperties": {}`), per [agentme-edr-024](024-ml-dataset-structure.md) rule `04`.
47
+
48
+ #### 03-mocks-allowed-values
49
+
50
+ The taxonomy in rule `05` rates each test type using one of three values:
51
+
52
+ | Value | Meaning |
53
+ |---|---|
54
+ | `mocks allowed` | Fully offline; fakes may replace every dependency (e.g. `FakeListChatModel` per [agentme-edr-018](018-ai-llm-development-standards.md) rule `04`). |
55
+ | `mocks disallowed` | No mocking of any dependency — real external systems required. |
56
+ | `mocks disallowed for LLM calls` | Tools and other external/dependency calls MAY be mocked; only the LLM call itself MUST be real for the test to be meaningful. |
57
+
58
+ #### 04-test-types-enum
59
+
60
+ A golden dataset entry's `test_types` array MUST only use these values: `safety`, `adversarial`, `fairness`, `bias`, `robustness`, `explainability`, `groundedness`, `functional`, `prompt`, `smoke`, `human`. These correspond to the dataset-driven rows of rule `05`. **Unit test** and **Integration test** (the two Code-level rows) are NOT part of this enum — they have no golden dataset entries and remain governed entirely by [agentme-edr-004](../principles/004-unit-test-requirements.md) and [agentme-edr-007](../principles/007-project-quality-standards.md) rule `08`.
61
+
62
+ #### 05-test-type-taxonomy
63
+
64
+ | Test Type Name | Group | Test Objective | Mocks Allowed | When to Apply | Relevance – Business | Relevance – Development Team | Priority (1-5) |
65
+ |---|---|---|---|---|---|---|---|
66
+ | Safety/content eval | Safety & adversarial | Detect harmful, biased, or policy-violating output | mocks disallowed for LLM calls | Any user-facing release | Avoids reputational harm; acceptable-use compliance | Automated content gate before merge/release | 5 |
67
+ | Adversarial/red-team test | Safety & adversarial | Probe for prompt injection, jailbreaks, unsafe tool use | mocks disallowed for LLM calls | System exposes tool-invocation or agent loops | Reduces security-incident/breach liability | Finds exploitable tool-loop paths before attackers do | 5 |
68
+ | Fairness test | Responsible AI | Verify equitable outcomes across user groups | mocks disallowed for LLM calls | Output affects decisions about individuals/groups | Regulatory requirement; protects equitable access | Surfaces uneven outcomes before release | 4 |
69
+ | Bias test | Responsible AI | Detect skewed or stereotyped associations | mocks disallowed for LLM calls | User-facing content generation | Lowers legal/reputational exposure | Catches bias introduced by data/prompts/fine-tuning | 3 |
70
+ | Robustness test | Responsible AI | Verify stable behavior under noisy/out-of-distribution input | mocks disallowed for LLM calls | Inputs come from untrusted/variable sources | Protects reliability/SLAs | Confirms graceful degradation, guides input validation | 3 |
71
+ | Explainability test | Responsible AI | Verify output is justifiable with a faithful rationale | mocks disallowed for LLM calls | Output must be justified to users/auditors/regulators | Required for auditability; builds user trust | Gives rationale trace for debugging wrong answers | 2 |
72
+ | Groundedness (RAG) eval | Quality eval | Verify the answer is supported by retrieved context | mocks disallowed for LLM calls | System uses retrieval-augmented generation | Avoids confidently-wrong answers reaching customers | Pinpoints retrieval/prompt bugs | 4 |
73
+ | Human evaluation | Quality eval | Manually verify aspects automated scoring can't (ethics, side effects, external state) | mocks disallowed for LLM calls | Before major releases; periodic spot-check | Defensible, human-reviewed sign-off | Catches what automated metrics miss | 3 |
74
+ | Functional eval (golden-dataset accuracy / LLM-as-judge) | Quality eval | Measure output correctness against the golden dataset | mocks disallowed for LLM calls | Required before every Workflow release ([agentme-edr-007](../principles/007-project-quality-standards.md) rule `09`); advised elsewhere | Auditable evidence of business correctness before release | Detects regressions from model/provider/prompt changes | 5 |
75
+ | Smoke test | Quality eval | Fast pass/fail check on a small, critical subset before running fuller suites | mocks disallowed for LLM calls | Every commit/PR, before functional/responsible-AI evals run | Cheap early warning before slower evals run | Fast, cheap feedback loop | 4 |
76
+ | Prompt regression test | Prompt/LLM | Detect behavior change when a prompt or model version changes | mocks disallowed for LLM calls | Whenever a prompt template or model version changes | Prevents shipping a worse experience via a "small" tweak | Fast check on every prompt edit | 3 |
77
+ | Integration test | Code-level | Verify real interaction with external systems | mocks disallowed | Component depends on external systems | Reduces production outages from integration mismatches | Catches wiring bugs unit tests can't see | 2 |
78
+ | Unit test (offline, mocked) | Code-level | Verify deterministic logic in isolation, offline | mocks allowed | Required for Workflow tier every commit ([agentme-edr-007](../principles/007-project-quality-standards.md) rule `09`) | Lowest-cost point to catch defects | Fastest, fully offline feedback on every commit | 5 |
79
+
80
+ #### 06-priority-and-relevance-are-descriptive-only
81
+
82
+ Priority, Relevance, and When to Apply in rule `05` are guidance for prioritization conversations — they do NOT mandate which test types a project must implement, nor their thresholds. [agentme-edr-007](../principles/007-project-quality-standards.md) rule `09` remains the only tier-level testing requirement in force (Workflow unit tests + functional evals). Once a project chooses to implement and threshold a test type, [agentme-edr-028](028-ai-eval-standards.md) rule `02`'s failing-threshold behavior applies uniformly, regardless of this table's priority rating — a project may enforce fairness at 70% and functional at 90%, or skip fairness entirely; that choice is a project/business decision, not one this Policy makes.
83
+
84
+ #### 07-smoke-is-distinct-from-test-smoke
85
+
86
+ The `smoke` test type (surfaced as the `eval-smoke` Makefile target, a fast subset of the golden-dataset functional eval) is a different concept from [agentme-edr-008](../devops/008-common-targets.md)'s existing `test-smoke` target (a fast subset of code-level tests). Both may exist in the same project; do not conflate them.
87
+
88
+ ## References
89
+
90
+ - [agentme-edr-024](024-ml-dataset-structure.md) — Golden dataset file layout, per-entry JSON format, `$schema` pointer, and schema-lint validation
91
+ - [agentme-edr-028](028-ai-eval-standards.md) — Eval folder structure, `--type` filtering, per-type Makefile targets, and per-type reports that consume this taxonomy
92
+ - [agentme-edr-026](026-pragmatic-hexagonal-architecture.md) — Rule `10`: `_mock` file naming and placement convention for mock adapters referenced by `mock_fixtures`
93
+ - [agentme-edr-007](../principles/007-project-quality-standards.md) — Rule `09` tier-level testing requirements (the only mandated AI testing baseline)
94
+ - [agentme-edr-008](../devops/008-common-targets.md) — Rule `03` `eval-<qualifier>` Makefile convention; rule `03`'s `test-smoke` (distinguished in rule `07`)
95
+ - [agentme-edr-018](018-ai-llm-development-standards.md) — LLM tier definition and mocking utilities referenced by the `mocks allowed` value
96
+ - [agentme-edr-004](../principles/004-unit-test-requirements.md) — Unit test requirements underlying the Code-level rows
@@ -57,8 +57,6 @@ Module folder responsibilities, artifact locations, and test-folder conventions
57
57
  - **MUST** contain a `README.md` with: purpose, architecture overview, how to build, and how to run.
58
58
  - **MAY** contain `examples/`, `tests_integration/`, and `tests_benchmark/` when those artifacts apply to multiple modules inside the application.
59
59
 
60
- *Why:* Isolating applications prevents implicit coupling and makes the `shared/` boundary explicit and intentional.
61
-
62
60
  #### 03-module-folders
63
61
 
64
62
  - A module is a subfolder inside an application that is independently compilable and produces a build artifact.
@@ -87,8 +85,6 @@ Module Makefiles **SHOULD** also provide `lint-fix` and `install` when the under
87
85
  The root `Makefile` **MUST** also define a `setup` target that guides a new contributor to prepare their machine.
88
86
  The root `setup` target **MUST** run `mise install` and any small repository bootstrap required before routine targets work.
89
87
 
90
- *Why:* Makefiles provide a universal, stack-agnostic entry point regardless of programming language.
91
-
92
88
  #### 06-mise-for-tooling-management
93
89
 
94
90
  - [Mise](https://mise.jdx.dev/) **MUST** be used to pin all tool versions (compilers, runtimes, CLI tools).
@@ -100,8 +96,6 @@ The root `setup` target **MUST** run `mise install` and any small repository boo
100
96
  - If a required tool is missing, the first remediation step **MUST** be to update `.mise.toml` or run `mise install`, not to install ad-hoc global tools with language-specific installers such as `go install`, `npm install -g`, `pip install --user`, or `cargo install`.
101
97
  - Root and module `Makefile` targets **MUST** work when invoked as plain `make <target>` after `make setup`.
102
98
 
103
- *Why:* Eliminates "works on my machine" build failures by ensuring identical tool versions across all environments.
104
-
105
99
  #### 07-root-readme
106
100
 
107
101
  The root `README.md` **MUST** include: overview, machine setup, quickstart, and a repository map.
@@ -116,8 +110,6 @@ All releases **MUST** be tagged using the format `<module-name>/<semver>` (e.g.,
116
110
 
117
111
  `<module-name>` is preferably the path-like identifier of the module being released. A custom name is allowed but the folder name is strongly preferred.
118
112
 
119
- *Why:* Namespacing tags by module prevents collisions and makes it easy to filter release history when multiple modules release independently.
120
-
121
113
  ---
122
114
 
123
115
  #### 11-summary-of-requirements
@@ -15,7 +15,7 @@ What standard set of Makefile target names and execution rules should projects a
15
15
 
16
16
  ## Decision Outcome
17
17
 
18
- **Every project must expose its development actions through a root `Makefile` using a defined set of standardized target names. Target implementation and tool-execution rules follow [agentme-edr-017](017-tool-execution-and-scripting.md), which requires `mise exec --` before routine tool commands.**
18
+ **Every project MUST expose its development actions through a root `Makefile` using a defined set of standardized target names. Target implementation and tool-execution rules follow [agentme-edr-017](017-tool-execution-and-scripting.md), which requires `mise exec --` before routine tool commands.**
19
19
 
20
20
  Standardizing both the target names and the execution chain removes per-project guesswork, makes CI pipelines reusable, and keeps tooling behavior visible in one place.
21
21
 
@@ -23,18 +23,18 @@ Standardizing both the target names and the execution chain removes per-project
23
23
 
24
24
  #### 01-every-project-must-have-root-makefile
25
25
 
26
- The project root must contain a single authoritative `Makefile` that exposes the standard target names defined in rule 3. Developers and CI pipelines must invoke routine actions through this `Makefile`, never by calling underlying tools directly in documentation, CI, or daily workflow commands.
26
+ The project root **MUST** contain a single authoritative `Makefile` that exposes the standard target names defined in rule 3. Developers and CI pipelines **MUST** invoke routine actions through this `Makefile`, **NEVER** by calling underlying tools directly in documentation, CI, or daily workflow commands.
27
27
 
28
28
  `make <target>` is the shared contract across projects and languages.
29
29
 
30
- - The root `Makefile` must be the entry point for both developers and pipelines.
31
- - The root `Makefile` must expose at minimum the common targets defined in this XDR.
32
- - Reverse-compatibility wrappers are allowed when an ecosystem expects them, but they must stay trivial.
30
+ - The root `Makefile` **MUST** be the entry point for both developers and pipelines.
31
+ - The root `Makefile` **MUST** expose at minimum the common targets defined in this XDR.
32
+ - Reverse-compatibility wrappers are allowed when an ecosystem expects them, but they **MUST** stay trivial.
33
33
  - Allowed: `package.json` script `"test": "make test"`
34
34
  - Not allowed: `make test` -> `npm run test` -> tool command
35
- - Project logic must not live in npm scripts, Mise tasks, shell wrappers, or other secondary runners when the same logic belongs in the `Makefile`.
35
+ - Project logic **MUST NOT** live in npm scripts, Mise tasks, shell wrappers, or other secondary runners when the same logic belongs in the `Makefile`.
36
36
 
37
- *Why:* The project entry point must stay language-agnostic and obvious. A developer should be able to inspect the `Makefile` and immediately see which real tool commands will run.
37
+ *Why:* The project entry point **MUST** stay language-agnostic and obvious. A developer **SHOULD** be able to inspect the `Makefile` and immediately see which real tool commands will run.
38
38
 
39
39
  #### 02-makefile-recipes-must-use-mise
40
40
 
@@ -47,10 +47,10 @@ make <target>
47
47
  -> explicit tool command
48
48
  ```
49
49
 
50
- - The `setup` target must run `mise install` and any small project-specific bootstrap needed before normal targets work.
51
- - Routine targets such as `build`, `lint`, `test`, `run`, and `publish` must be invoked as `make <target>` by both contributors and CI.
52
- - Each Makefile recipe must call the real underlying command through `mise exec --`, following [agentme-edr-017](017-tool-execution-and-scripting.md).
53
- - Makefile recipes must not add extra script layers such as `npm run`, `pnpm run`, `yarn run`, `mise run`, `mise tasks`, or shell aliases when those layers only forward to another command.
50
+ - The `setup` target **MUST** run `mise install` and any small project-specific bootstrap needed before normal targets work.
51
+ - Routine targets such as `build`, `lint`, `test`, `run`, and `publish` **MUST** be invoked as `make <target>` by both contributors and CI.
52
+ - Each Makefile recipe **MUST** call the real underlying command through `mise exec --`, following [agentme-edr-017](017-tool-execution-and-scripting.md).
53
+ - Makefile recipes **MUST NOT** add extra script layers such as `npm run`, `pnpm run`, `yarn run`, `mise run`, `mise tasks`, or shell aliases when those layers only forward to another command.
54
54
  - Calling the actual tool is allowed even when that tool itself launches another program as part of its normal interface.
55
55
  - Allowed: `mise exec -- pnpm exec eslint ./src`
56
56
  - Allowed: `mise exec -- go test -cover ./...`
@@ -66,17 +66,17 @@ make <target>
66
66
 
67
67
  #### 03-standard-target-groups-and-names
68
68
 
69
- Targets are organized into five lifecycle groups. Projects must use these names unchanged. Extensions are allowed (see rule 5) but the core names must not be repurposed.
69
+ Targets are organized into five lifecycle groups. Projects **MUST** use these names unchanged. Extensions are allowed (see rule 5) but the core names **MUST NOT** be repurposed.
70
70
 
71
71
  ##### Developer group
72
72
 
73
73
  | Target | Purpose |
74
74
  |--------|---------|
75
75
  | `setup` | Run `mise install` and any small project bootstrap needed before normal targets work. This is the first command after checkout. |
76
- | `all` | Alias that runs `build`, `lint`, and `test` in sequence. Must be the default target (i.e., running `make` or the runner with no arguments invokes `all`). Used by developers as a fast pre-push check to verify the software meets minimum quality standards in one command. Must only invoke targets that run **offline** — no external credentials, running servers, paid APIs, or environment-specific configuration outside the repository. |
76
+ | `all` | Alias that runs `build`, `lint`, and `test` in sequence. **MUST** be the default target (i.e., running `make` or the runner with no arguments invokes `all`). Used by developers as a fast pre-push check to verify the software meets minimum quality standards in one command. **MUST** only invoke targets that run **offline** — no external credentials, running servers, paid APIs, or environment-specific configuration outside the repository. |
77
77
  | `clean` | Remove all temporary or generated files created during build, lint, or test (e.g., `node_modules`, virtual environments, compiled binaries, generated files). Used both locally and in CI for a clean slate. |
78
78
  | `dev` | Run the software locally for development (e.g., start a Node.js API server, open a Jupyter notebook, launch a React dev server). May have debugging tools, verbose logging, or hot reloading features enabled. |
79
- | `run` | Run the software in production mode (e.g., start a compiled binary, launch a production server). No debugging or development-only features should be enabled. |
79
+ | `run` | Run the software in production mode (e.g., start a compiled binary, launch a production server). Debugging or development-only features **SHOULD NOT** be enabled. |
80
80
  | `update-lockfile` | Update the dependency lockfile to reflect the latest resolved versions of all dependencies. |
81
81
 
82
82
  ##### Build group
@@ -93,17 +93,17 @@ Targets are organized into five lifecycle groups. Projects must use these names
93
93
 
94
94
  | Target | Purpose |
95
95
  |--------|---------|
96
- | `lint` | Run **all static quality checks** outside of tests. This MUST include: code formatting validation, code style enforcement, code smell detection, static analysis, dependency audits for known CVEs, security vulnerability scans (e.g., SAST), and project/configuration structure checks. All checks must be non-destructive (read-only); fixes are handled by `lint-fix`. Must only invoke subtargets that run **offline** (no external credentials or services). |
96
+ | `lint` | Run **all static quality checks** outside of tests. This MUST include: code formatting validation, code style enforcement, code smell detection, static analysis, dependency audits for known CVEs, security vulnerability scans (e.g., SAST), and project/configuration structure checks. All checks **MUST** be non-destructive (read-only); fixes are handled by `lint-fix`. **MUST** only invoke subtargets that run **offline** (no external credentials or services). |
97
97
  | `lint-fix` | Automatically fix linting and formatting issues where possible. || `lint-format` | *(Optional)* Check code formatting only (e.g., Prettier, gofmt, Black). |
98
98
  ##### Test group
99
99
 
100
100
  | Target | Purpose |
101
101
  |--------|---------|
102
- | `test` | Run **all offline tests** required for the project. This MUST include unit tests (with coverage enforcement — the build MUST fail if coverage thresholds are not met) and any integration or end-to-end tests that run **offline** (no external servers, credentials, or paid APIs). Normally delegates to `test-unit` and, when offline, `test-integration` in sequence. Suffixed targets that require external dependencies must not be invoked automatically — see rule 08. |
102
+ | `test` | Run **all offline tests** required for the project. This MUST include unit tests (with coverage enforcement — the build MUST fail if coverage thresholds are not met) and any integration or end-to-end tests that run **offline** (no external servers, credentials, or paid APIs). Normally delegates to `test-unit` and, when offline, `test-integration` in sequence. Suffixed targets that require external dependencies **MUST NOT** be invoked automatically — see rule 08. |
103
103
  | `test-unit` | Run unit tests only, including coverage report generation and coverage threshold enforcement. |
104
- | `test-integration` | *(Optional)* Run integration and end-to-end tests only. Projects without integration tests may omit this target. |
104
+ | `test-integration` | *(Optional)* Run integration and end-to-end tests only. Projects without integration tests MAY omit this target. |
105
105
  | `test-smoke` | *(Optional)* Run a fast, minimal subset of tests to verify the software is basically functional. Useful as a post-deploy health check. |
106
- | `eval` | *(Optional)* Run **all evaluations** for the module. Used alongside `test` to measure the accuracy and performance of statistical systems such as ML models, AI agents, or noisy systems. Typically runs against a live or near-live system (similar to an integration test) and produces a performance analysis report (e.g., F1 score, Accuracy, Precision, Recall). Must not be included in `test` or `all` — evals are opt-in because they require live dependencies and may be slow or costly to run. Individual evaluations must follow the prefix convention: `eval-<qualifier>` (e.g., `eval-simple`, `eval-complex`). |
106
+ | `eval` | *(Optional)* Run **all evaluations** for the module. Used alongside `test` to measure the accuracy and performance of statistical systems such as ML models, AI agents, or noisy systems. Typically runs against a live or near-live system (similar to an integration test) and produces a performance analysis report (e.g., F1 score, Accuracy, Precision, Recall). **MUST NOT** be included in `test` or `all` — evals are opt-in because they require live dependencies and MAY be slow or costly to run. Individual evaluations **MUST** follow the prefix convention: `eval-<qualifier>` (e.g., `eval-simple`, `eval-complex`). |
107
107
 
108
108
  ##### Release group
109
109
 
@@ -119,18 +119,18 @@ Targets are organized into five lifecycle groups. Projects must use these names
119
119
 
120
120
  #### 04-standard-environment-variables
121
121
 
122
- Two environment variables have defined semantics and must be used consistently.
122
+ Two environment variables have defined semantics and **MUST** be used consistently.
123
123
 
124
124
  | Variable | Purpose |
125
125
  |----------|---------|
126
- | `STAGE` | Identifies the runtime environment. Format: `[prefix][-variant]`. Common prefixes: `dev`, `tst`, `acc`, `prd`. Examples: `dev`, `dev-pr123`, `tst`, `prd-blue`. May be required by any target that is environment-aware (build, lint, deploy, etc.). |
126
+ | `STAGE` | Identifies the runtime environment. Format: `[prefix][-variant]`. Common prefixes: `dev`, `tst`, `acc`, `prd`. Examples: `dev`, `dev-pr123`, `tst`, `prd-blue`. **MAY** be required by any target that is environment-aware (build, lint, deploy, etc.). |
127
127
  | `VERSION` | Sets the explicit version used during packaging and deployment. Used when there is no automatic version-tagging utility, or to override it. |
128
128
 
129
129
  ---
130
130
 
131
131
  #### 05-extending-targets-with-prefixes
132
132
 
133
- Projects may add custom targets beyond the standard set. Custom targets must be named by prefixing a standard target name with a descriptive qualifier, keeping the naming intuitive and consistent with the group it belongs to.
133
+ Projects **MAY** add custom targets beyond the standard set. Custom targets **MUST** be named by prefixing a standard target name with a descriptive qualifier, keeping the naming intuitive and consistent with the group it belongs to.
134
134
 
135
135
  **Examples:**
136
136
 
@@ -166,15 +166,15 @@ dev-mlflow:
166
166
 
167
167
  #### 08-default-targets-must-only-include-offline-subtargets
168
168
 
169
- `make all`, `make test`, and `make lint` must include every subtarget that runs **offline** — meaning it requires no external credentials, no running servers, no paid APIs, and no environment-specific configuration outside the repository.
169
+ `make all`, `make test`, and `make lint` **MUST** include every subtarget that runs **offline** — meaning it requires no external credentials, no running servers, no paid APIs, and no environment-specific configuration outside the repository.
170
170
 
171
- Subtargets that require external dependencies (e.g., `test-integration` against a live database, `test-e2e` against a staging environment, `lint-api` against a remote schema registry) **must** exist as named targets so developers can invoke them explicitly, but **must not** be invoked from `all`, `test`, or `lint`.
171
+ Subtargets that require external dependencies (e.g., `test-integration` against a live database, `test-e2e` against a staging environment, `lint-api` against a remote schema registry) **MUST** exist as named targets so developers can invoke them explicitly, but **MUST NOT** be invoked from `all`, `test`, or `lint`.
172
172
 
173
173
  ---
174
174
 
175
175
  #### 06-monorepo-usage
176
176
 
177
- In a monorepo, each module has its own `Makefile` with its own `build`, `lint`, `test`, and `deploy` targets scoped to that module. Parent-level Makefiles (at the application or repo root) delegate to child Makefiles in sequence. The parent Makefile should call `$(MAKE) -C <child> <target>` directly, while each child `Makefile` runs its actual tool commands through `mise exec --`.
177
+ In a monorepo, each module has its own `Makefile` with its own `build`, `lint`, `test`, and `deploy` targets scoped to that module. Parent-level Makefiles (at the application or repo root) delegate to child Makefiles in sequence. The parent Makefile **SHOULD** call `$(MAKE) -C <child> <target>` directly, while each child `Makefile` runs its actual tool commands through `mise exec --`.
178
178
 
179
179
  ```makefile
180
180
  # root Makefile — delegates to all modules
@@ -187,7 +187,7 @@ test:
187
187
  $(MAKE) -C module-b test
188
188
  ```
189
189
 
190
- A developer can run `make test` at the repo root to test everything, or `cd module-a && make test` to test a single module. Both must work.
190
+ A developer can run `make test` at the repo root to test everything, or `cd module-a && make test` to test a single module. Both **MUST** work.
191
191
 
192
192
  **Reference:** See [agentme-edr-005](005-monorepo-structure.md) for the full monorepo layout convention.
193
193
 
@@ -15,9 +15,9 @@ What contributor workflow guidance must every project publish so contributors kn
15
15
 
16
16
  ## Decision Outcome
17
17
 
18
- **Every project must publish a root CONTRIBUTING.md with a small, explicit contribution workflow.**
18
+ **Every project MUST publish a root CONTRIBUTING.md with a small, explicit contribution workflow.**
19
19
 
20
- Projects must keep a `CONTRIBUTING.md` file at the repository root. The file must explain where bugs, feature discussions, and code changes belong so contributors follow a predictable workflow before opening pull requests.
20
+ Projects MUST keep a `CONTRIBUTING.md` file at the repository root. The file MUST explain where bugs, feature discussions, and code changes belong so contributors follow a predictable workflow before opening pull requests.
21
21
 
22
22
  ### Details
23
23
 
@@ -37,6 +37,7 @@ Language and framework-specific tooling and project structure.
37
37
  - [agentme-edr-021](application/021-ai-workflow-development-standards.md) - **AI workflow development standards** - Standard toolchain (LangGraph), evaluation, and testing patterns for workflow projects
38
38
  - [agentme-edr-029](application/029-ai-workflow-naming-conventions.md) - **AI workflow naming conventions** - Node suffix/prefix roles, state type and attribute naming, judge output schema, workflow class names, and cross-element coherence rules
39
39
  - [agentme-edr-028](application/028-ai-eval-standards.md) - **AI eval standards** - Folder structure, script requirements, and MLflow tracking for eval tests across LLM, Agent, and Workflow tiers
40
+ - [agentme-edr-030](application/030-ai-test-types-taxonomy.md) - **AI test types taxonomy** - Names AI test types (safety, responsible-AI, quality-eval, prompt, code-level) with group, objective, mocking constraint, and relevance, and defines the shared golden dataset entry envelope
40
41
  - [agentme-edr-024](application/024-ml-dataset-structure.md) - **ML dataset structure** - Standard folder layout and file conventions for ML datasets
41
42
  - [agentme-edr-025](application/025-ai-agent-xdrs-knowledge-layer.md) - **AI agent XDRS knowledge layer** - How to integrate XDRS as the runtime source of truth for policies and skills in AI agents (apply only when the project explicitly uses XDRS)
42
43
  - [agentme-edr-026](application/026-pragmatic-hexagonal-architecture.md) - **Pragmatic hexagonal architecture** - Organize application layers as External/Adapters/Application with practical coupling rules
@@ -17,7 +17,7 @@ How should services expose their health status and validate operational readines
17
17
 
18
18
  **Standardized `/health` endpoint with dependency validation**
19
19
 
20
- All services must expose a `GET /health` endpoint that validates external dependencies using read-only operations and returns structured status with appropriate HTTP codes.
20
+ All services **MUST** expose a `GET /health` endpoint that validates external dependencies using read-only operations and returns structured status with appropriate HTTP codes.
21
21
 
22
22
  ### Details
23
23
 
@@ -45,12 +45,12 @@ All services must expose a `GET /health` endpoint that validates external depend
45
45
 
46
46
  - `health` (required): overall state — `OK`, `WARNING`, or `ERROR`
47
47
  - `latencyMs` (required): total milliseconds to run all checks
48
- - `message` (required): human-readable summary; must never expose credentials, internal IPs, or stack traces
48
+ - `message` (required): human-readable summary; **MUST NEVER** expose credentials, internal IPs, or stack traces
49
49
 
50
50
  **Dependency validation rules:**
51
51
 
52
52
  - Check all external dependencies (databases, downstream APIs, queues, caches) using read-only operations (e.g., `SELECT 1`, lightweight GET, connection ping)
53
- - Never execute write operations or create side effects
53
+ - **MUST NOT** execute write operations or create side effects
54
54
  - `OK`: all dependencies healthy within expected thresholds
55
55
  - `WARNING`: non-critical dependency degraded, or elevated but acceptable response times
56
56
  - `ERROR`: critical dependency unavailable or service unable to process requests
@@ -70,6 +70,28 @@ All services must expose a `GET /health` endpoint that validates external depend
70
70
  - Monitoring: periodic polling with alerts on `210` and `503` responses
71
71
  - CI/CD: poll `/health` to confirm deployment success
72
72
 
73
+ **Unit testing and mocking strategy:** Each dependency checker MUST be injectable so unit tests can simulate `OK`, `WARNING`, and `ERROR` states independently without a real database or API. Integration tests MUST NOT mock dependency checkers — they MUST run against real dependencies to verify the wiring.
74
+
75
+ ```typescript
76
+ // Good — injectable checkers; unit test controls each state
77
+ function buildHealthHandler(checkers: DependencyChecker[]) {
78
+ return async () => {
79
+ const results = await Promise.all(checkers.map(c => c.check()));
80
+ const status = results.some(r => r.status === "ERROR") ? "ERROR"
81
+ : results.some(r => r.status === "WARNING") ? "WARNING" : "OK";
82
+ return { health: status };
83
+ };
84
+ }
85
+
86
+ it("returns ERROR when the database checker fails", async () => {
87
+ const handler = buildHealthHandler([
88
+ { check: async () => ({ name: "db", status: "ERROR" }) },
89
+ ]);
90
+ const response = await handler();
91
+ expect(response.health).toBe("ERROR");
92
+ });
93
+ ```
94
+
73
95
  ## Considered Options
74
96
 
75
97
  * (REJECTED) **No health checks** — detect failures through request errors
@@ -21,12 +21,10 @@ What coding practices should be followed across all languages and projects to ke
21
21
 
22
22
  #### 01-keep-files-short
23
23
 
24
- A file must not exceed **400 lines**. When a file grows beyond this limit, split related functions or types into separate, focused modules.
24
+ A file MUST NOT exceed **400 lines**. When a file grows beyond this limit, split related functions or types into separate, focused modules.
25
25
 
26
26
  One exception are test files, which normally are bigger than the tested resources.
27
27
 
28
- *Why:* Large files make navigation slow, increase merge conflicts, and obscure the single-responsibility principle.
29
-
30
28
  **Example (TypeScript):**
31
29
 
32
30
  ```
@@ -50,8 +48,6 @@ src/
50
48
 
51
49
  When a function's main logic contains well-defined sections and **any individual section exceeds ~20 lines**, extract each section into its own named function. The outer function becomes an orchestrator that calls the extracted helpers in sequence.
52
50
 
53
- *Why:* Named sub-functions serve as inline documentation, are independently testable, and reduce cognitive load.
54
-
55
51
  **Example (Python):**
56
52
 
57
53
  ```python
@@ -85,9 +81,7 @@ def _persist_order(order, total): ...
85
81
 
86
82
  #### 03-put-entry-point-function-first
87
83
 
88
- Place the **entry-point function** (the outermost caller) at the **top** of the file. All helper or sub-functions it calls internally must appear **below** it.
89
-
90
- *Why:* Readers can follow the overall logic top-down without jumping around the file. The most important function is immediately visible when the file is opened.
84
+ Place the **entry-point function** (the outermost caller) at the **top** of the file. All helper or sub-functions it calls internally MUST appear **below** it.
91
85
 
92
86
  **Example (Python):**
93
87
 
@@ -106,22 +100,18 @@ def _persist_order(order, total): ...
106
100
 
107
101
  #### 04-keep-readme-tests-and-examples-in-sync
108
102
 
109
- Every change to a public interface, behavior, or configuration option must be reflected in:
103
+ Every change to a public interface, behavior, or configuration option MUST be reflected in:
110
104
 
111
105
  - `README.md` — update usage examples, option tables, and feature descriptions.
112
106
  - Unit/integration tests — update or add tests that cover the changed behavior.
113
107
  - `examples/` resources — update runnable examples so they continue to work.
114
108
 
115
- *Why:* Stale documentation and broken examples erode trust and waste time for consumers of the code.
116
-
117
109
  ---
118
110
 
119
111
  #### 05-declare-types-in-file-where-used
120
112
 
121
113
  If a type (struct, interface, class, typedef, etc.) is used in only **one** file, declare it in that same file. Move a type to a shared module only when it is referenced in two or more files.
122
114
 
123
- *Why:* Co-locating a type with its sole consumer removes the need to navigate to a separate types file and makes the type's purpose immediately obvious from context.
124
-
125
115
  ---
126
116
 
127
117
  #### 06-keep-test-files-next-to-source
@@ -262,3 +262,4 @@ AI projects are classified into three tiers — LLM, Agent, and Workflow — def
262
262
  - Accuracy below project-defined thresholds MUST block the release. Thresholds MUST be documented in the eval Makefile or README.
263
263
  - Evals MUST run against real LLM providers (not mocks) to capture model drift.
264
264
  - For eval folder structure and script requirements, see [agentme-edr-028](../application/028-ai-eval-standards.md).
265
+ - For the taxonomy of AI test types (safety, responsible-AI, quality-eval, prompt, code-level) and the golden dataset entry format, see [agentme-edr-030](../application/030-ai-test-types-taxonomy.md).
@@ -21,9 +21,7 @@ What error handling practices should be followed across all languages and projec
21
21
 
22
22
  #### 01-catch-only-where-handled
23
23
 
24
- Never catch an exception unless the catching site can genuinely recover from it, translate it into a meaningful domain error, or enrich it with context before re-throwing. Do **not** swallow exceptions silently. When suppressing an exception is intentional, always add a comment explaining exactly why, or log it at an appropriate level.
25
-
26
- *Why:* Swallowed exceptions hide bugs and make incidents impossible to diagnose. Every silent `catch` is a future mystery.
24
+ MUST NOT catch an exception unless the catching site can genuinely recover from it, translate it into a meaningful domain error, or enrich it with context before re-throwing. MUST NOT swallow exceptions silently. When suppressing an exception is intentional, MUST add a comment explaining exactly why, or log it at an appropriate level.
27
25
 
28
26
  **Examples:**
29
27
 
@@ -77,9 +75,7 @@ except CacheError:
77
75
 
78
76
  #### 02-avoid-exceptions-in-public-interfaces
79
77
 
80
- At module and service boundaries, prefer returning a value that signals success or failure (e.g., a result type, a discriminated union, or a `(value, error)` tuple as in Go) over throwing exceptions. This forces callers to explicitly acknowledge and handle the error case before using the result.
81
-
82
- *Why:* Exceptions are invisible in signatures. A caller who doesn't know an exception can be thrown will never write a handler. Explicit error return values make the contract visible and encourage handling at the call site.
78
+ At module and service boundaries, SHOULD prefer returning a value that signals success or failure (e.g., a result type, a discriminated union, or a `(value, error)` tuple as in Go) over throwing exceptions. This forces callers to explicitly acknowledge and handle the error case before using the result.
83
79
 
84
80
  **Examples:**
85
81
 
@@ -161,9 +157,7 @@ def fetch_user(user_id: str) -> Ok[User] | Err:
161
157
 
162
158
  #### 03-centralise-repetitive-catch-logic
163
159
 
164
- If the same `try/catch` pattern (e.g., logging, classifying HTTP errors, wrapping exceptions) appears in multiple places, extract it into a shared utility. Do not copy-paste catch blocks across the codebase.
165
-
166
- *Why:* Scattered catch blocks drift out of sync — one gets updated, the others don't. A central utility is tested once and applied everywhere consistently.
160
+ If the same `try/catch` pattern (e.g., logging, classifying HTTP errors, wrapping exceptions) appears in multiple places, MUST be extracted into a shared utility. MUST NOT copy-paste catch blocks across the codebase.
167
161
 
168
162
  **Examples:**
169
163
 
@@ -213,13 +207,11 @@ def save_order(order: Order): ...
213
207
 
214
208
  #### 04-communicate-failure-at-boundaries
215
209
 
216
- Every system boundary must signal failure explicitly:
210
+ Every system boundary MUST signal failure explicitly:
217
211
 
218
- - **OS processes** must exit with a **non-zero exit code** when something went wrong. Exit code `0` means success.
219
- - **HTTP services** must return a **non-2xx/3xx status code** on error, accompanied by a response body that describes the problem without exposing internal system details (stack traces, SQL queries, internal paths, etc.).
220
- - **All error responses** should be logged to the console/structured logger, especially system-level or unexpected errors. Operational teams must be able to find the cause from logs alone.
221
-
222
- *Why:* Orchestrators, CI runners, load balancers, and callers all rely on these signals to detect failures automatically. A process or service that reports success on failure leads to silent data corruption and missed alerts.
212
+ - **OS processes** MUST exit with a **non-zero exit code** when something went wrong. Exit code `0` means success.
213
+ - **HTTP services** MUST return a **non-2xx/3xx status code** on error, accompanied by a response body that describes the problem without exposing internal system details (stack traces, SQL queries, internal paths, etc.).
214
+ - **All error responses** SHOULD be logged to the console/structured logger, especially system-level or unexpected errors. Operational teams must be able to find the cause from logs alone.
223
215
 
224
216
  **Examples:**
225
217
 
@@ -276,11 +268,9 @@ def create_order_endpoint(payload: OrderRequest):
276
268
 
277
269
  #### 05-write-test-cases-for-error-scenarios
278
270
 
279
- Every module that handles errors must have dedicated test cases that verify the error paths. Do not only test the happy path.
280
-
281
- *Why:* Error handling code is the code most likely to be broken and the code least likely to be exercised in manual testing. Without automated tests, regressions in error paths go undetected until production.
271
+ Every module that handles errors MUST have dedicated test cases that verify the error paths. Do not only test the happy path.
282
272
 
283
- Typical error scenarios to cover:
273
+ **Mocking strategy:** External dependencies (databases, HTTP services, file systems) MUST be mocked in error-path unit tests. Simulate failure by configuring the mock to throw or return an error value — do not rely on a real dependency being unavailable.
284
274
 
285
275
  - The dependency (DB, HTTP service, file system) is unavailable or times out.
286
276
  - The input is invalid, missing, or out of range.
@@ -17,16 +17,16 @@ Question: What policy should developers follow to continuously enrich XDRs so re
17
17
 
18
18
  **Develop features with shared-first XDR enrichment and controlled divergence**
19
19
 
20
- Developers must treat reusable missing guidance discovered during implementation as an XDR gap to be proposed and reviewed, not as permanent prompt-only context or repeated vibe coding.
20
+ Developers MUST treat reusable missing guidance discovered during implementation as an XDR gap to be proposed and reviewed, not as permanent prompt-only context or repeated vibe coding.
21
21
 
22
22
  ### Details
23
23
 
24
- - The main objective is sharing, discussing, and converging practices across teams. Controlled divergence during exploration is acceptable, but recurring successful decisions must be converged into shared XDRs.
25
- - The non _local scope exists to share practices across projects, company areas, and functionally organized teams. Decisions placed in `_local` should be truly specific to the needs of a single application or repository.
26
- - When developers or coding agents need too much detailed steering to complete a task, they must reflect on whether those details would help other teams or future implementations. If yes, create or update an XDR proposal in the broadest appropriate shared scope.
27
- - This includes cases where an agent implemented a feature without a framework, pattern, coding standard, or other practice that should likely be standardized. Missing reusable guardrails should trigger an XDR proposal.
28
- - Teams should aim to keep at least 80% of big coding decisions covered by accepted XDRs. Big decisions include framework or tool selection, overall code organization, monorepo structure, complex business flows, and coding standards.
29
- - If a big decision is not yet covered, developers should either propose a new XDR or document why the decision is intentionally local and should not be shared.
24
+ - The main objective is sharing, discussing, and converging practices across teams. Controlled divergence during exploration is acceptable, but recurring successful decisions MUST be converged into shared XDRs.
25
+ - The non _local scope exists to share practices across projects, company areas, and functionally organized teams. Decisions placed in `_local` SHOULD be truly specific to the needs of a single application or repository.
26
+ - When developers or coding agents need too much detailed steering to complete a task, they MUST reflect on whether those details would help other teams or future implementations. If yes, create or update an XDR proposal in the broadest appropriate shared scope.
27
+ - This includes cases where an agent implemented a feature without a framework, pattern, coding standard, or other practice that should likely be standardized. Missing reusable guardrails SHOULD trigger an XDR proposal.
28
+ - Teams SHOULD aim to keep at least 80% of big coding decisions covered by accepted XDRs. Big decisions include framework or tool selection, overall code organization, monorepo structure, complex business flows, and coding standards.
29
+ - If a big decision is not yet covered, developers SHOULD either propose a new XDR or document why the decision is intentionally local and should not be shared.
30
30
  - Leaders responsible for the affected scope are accountable for reviewing XDR proposals, adjusting them, and publishing the accepted decision.
31
31
  - It is good practice to ask the coding agent which missing XDRs made the task harder, increased adjustment rounds, or forced more vibe coding. Those gaps should feed the XDR backlog.
32
32
  - In SDD, specifications describe the feature being built; XDRs describe reusable decisions and guardrails that should survive beyond one feature. Do not keep durable engineering policy only inside feature specs.
@@ -17,7 +17,7 @@ What baseline structure rules must every buildable module follow regardless of l
17
17
 
18
18
  **Standardize every buildable module around its own folder root, with `dist/`, `.cache/`, sibling consumer examples, a module README, and predictable test locations.**
19
19
 
20
- Language-specific EDRs may add ecosystem details, but they must not redefine these baseline folder responsibilities.
20
+ Language-specific EDRs MAY add ecosystem details, but they MUST NOT redefine these baseline folder responsibilities.
21
21
 
22
22
  ### Details
23
23
 
@@ -27,7 +27,7 @@ A module is the smallest independently buildable, testable, or publishable unit.
27
27
 
28
28
  - a `Makefile` following [agentme-edr-008](../devops/008-common-targets.md)
29
29
  - a `README.md` for the module itself
30
- - all configuration files required to build, lint, test, package, or publish that module
30
+ - all configuration files needed to build, lint, test, package, or publish that module
31
31
  - its generated `dist/` directory when the module produces distributable artifacts
32
32
  - a module-local `.cache/` when tool caches are not intentionally shared with a parent aggregation root
33
33
 
@@ -44,11 +44,11 @@ Example module root:
44
44
 
45
45
  #### 02-parent-folders-are-aggregation-roots
46
46
 
47
- Parent folders such as a repository root, an application folder, or `lib/` may aggregate multiple modules. They may also hold shared consumer examples or multi-module test harnesses.
47
+ Parent folders such as a repository root, an application folder, or `lib/` MAY aggregate multiple modules. They MAY also hold shared consumer examples or multi-module test harnesses.
48
48
 
49
- They MUST keep the public aggregation obvious: deleting an aggregation folder should remove a coherent API surface or entry-point area, not scatter unrelated internal implementation across the repository.
49
+ They MUST keep the public aggregation obvious: deleting an aggregation folder SHOULD remove a coherent API surface or entry-point area, not scatter unrelated internal implementation across the repository.
50
50
 
51
- Recommended aggregation pattern:
51
+ Example aggregation pattern:
52
52
 
53
53
  ```text
54
54
  <parent>/
@@ -88,7 +88,7 @@ Examples that demonstrate how to consume a library or reusable module MUST live
88
88
  Examples MUST exercise the module through its public distribution surface:
89
89
 
90
90
  - use the package built into `dist/` when the ecosystem supports local packaged artifacts
91
- - otherwise use the public module path or equivalent consumer-facing import surface, never relative source-file imports or direct references to internal implementation paths
91
+ - otherwise use the public module path or equivalent consumer-facing import surface; **MUST NOT** use relative source-file imports or direct references to internal implementation paths
92
92
 
93
93
  Example:
94
94
 
@@ -106,7 +106,7 @@ Each module MUST contain a `README.md` that shows how to use the module as a con
106
106
 
107
107
  The end of the README MUST also include short developer instructions for that module, covering at least the standard build, lint, and test entry points.
108
108
 
109
- Repository-level READMEs may describe the workspace, but they do not replace the module README.
109
+ Repository-level READMEs MAY describe the workspace, but they do not replace the module README.
110
110
 
111
111
  #### 07-tests-use-predictable-locations
112
112
 
@@ -142,6 +142,24 @@ Prefer fetching the secret inside the function that directly needs it rather tha
142
142
 
143
143
  Passing secrets via function arguments is acceptable when the consuming function cannot access the connector directly, but the default design should fetch at the point of use.
144
144
 
145
+ #### 09-unit-testing-and-mocking-strategy
146
+
147
+ Code that calls the secret connector MUST accept it as an injectable parameter. Unit tests MUST inject a fake connector that returns a pre-configured value without touching the OS keychain or any cloud secret manager.
148
+
149
+ ```python
150
+ # Good — injectable connector; unit test provides a fake
151
+ class MyService:
152
+ def __init__(self, secrets: SecretConnector):
153
+ self.api_key = secrets.get("api-key")
154
+
155
+ def test_service_uses_api_key():
156
+ fake = FakeSecretConnector({"api-key": "test-key-123"})
157
+ svc = MyService(secrets=fake)
158
+ assert svc.api_key == "test-key-123"
159
+ ```
160
+
161
+ Integration tests MAY use the real keychain on developer machines or CI after `make setup-secrets` has been run.
162
+
145
163
  ## References
146
164
 
147
165
  - [agentme-edr-008](../devops/008-common-targets.md) - Common development script names (defines Makefile target conventions)
@@ -21,9 +21,7 @@ What principles should guide the decision to introduce — or reject — an abst
21
21
 
22
22
  #### 01-prioritize-functional-programming
23
23
 
24
- Prefer functional programming: pure functions with clear input → processing → output flow. Object-oriented patterns (classes, inheritance) are allowed **only** when there is a clear benefit from the additional abstraction they bring — e.g., when complex context management or true inheritance hierarchies are intrinsically part of the best solution for a problem.
25
-
26
- *Why:* Functional units are simpler to reason about, test, and compose. OO introduces shared mutable state and implicit coupling that must earn its place.
24
+ Prefer functional programming: pure functions with clear input → processing → output flow. Object-oriented patterns (classes, inheritance) MAY only be used when there is a clear benefit from the additional abstraction they bring — e.g., when complex context management or true inheritance hierarchies are intrinsically part of the best solution for a problem.
27
25
 
28
26
  ---
29
27
 
@@ -43,7 +41,7 @@ These patterns obfuscate the main program flow and create behavioral indirection
43
41
 
44
42
  #### 03-trivial-wrappers-are-prohibited
45
43
 
46
- A function that merely delegates to another function or API call without adding meaningful logic, domain intent, or readability **must be inlined**. A wrapper is justified only when it:
44
+ A function that merely delegates to another function or API call without adding meaningful logic, domain intent, or readability **MUST be inlined**. A wrapper is justified only when it:
47
45
 
48
46
  - Encapsulates non-trivial logic (validation, retry, transformation).
49
47
  - Communicates a domain concept the underlying expression does not convey.
@@ -76,7 +74,7 @@ A function that constructs an object (e.g., configuration, options) is only just
76
74
  - Combines data in a non-linear or conditional way.
77
75
  - Is reused by multiple callers.
78
76
 
79
- A function that restructures simple static data in an almost 1-to-1 mapping forces the reader to trace indirection for no benefit and must be inlined.
77
+ A function that restructures simple static data in an almost 1-to-1 mapping forces the reader to trace indirection for no benefit and MUST be inlined.
80
78
 
81
79
  **Bad — trivial factory:**
82
80
 
@@ -1,3 +1,12 @@
1
+ ---
2
+ name: agentme
3
+ description: Curated library of XDRs and skills encoding best practices for AI coding agents across JavaScript, Go, and Python projects.
4
+ scope-type: standard
5
+ follows: agentme-core
6
+ apply-to: AI coding agents and developers adopting agentme engineering standards.
7
+ valid-from: 2025-01-01
8
+ ---
9
+
1
10
  # agentme Scope Overview
2
11
 
3
12
  ## Overview
package/.xdrs/index.md CHANGED
@@ -11,7 +11,15 @@ XDRS scopes listed last override the ones listed first
11
11
  ### _core
12
12
 
13
13
  Decisions about how XDRs work
14
- [View _core Scope Index](_core/index.md)
14
+ [View scope _core](_core/index.md)
15
+
16
+ ---
17
+
18
+ ### agentme-core
19
+
20
+ Meta-governance for the agentme scope (writing standards, content conventions, authoring guidance). Not distributed to consumers.
21
+
22
+ [View scope agentme-core](agentme-core/index.md)
15
23
 
16
24
  ---
17
25
 
@@ -19,7 +27,7 @@ Decisions about how XDRs work
19
27
 
20
28
  Opiniated set of decisions and skills for common development tasks
21
29
 
22
- [View agentme Scope Index](agentme/index.md)
30
+ [View scope agentme](agentme/index.md)
23
31
 
24
32
  ---
25
33
 
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "agentme",
3
- "version": "0.24.1",
3
+ "version": "0.25.0",
4
4
  "description": "",
5
5
  "dependencies": {
6
- "filedist": "^0.37.0"
6
+ "filedist": "^0.39.0"
7
7
  },
8
8
  "bin": "bin/filedist.js",
9
9
  "files": [
@@ -18,6 +18,6 @@
18
18
  "url": "https://github.com/flaviostutz/agentme.git"
19
19
  },
20
20
  "devDependencies": {
21
- "xdrs-core": "^0.31.1"
21
+ "xdrs-core": "^0.37.1"
22
22
  }
23
23
  }