agentme 0.24.2 → 0.25.2

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.
Files changed (26) hide show
  1. package/.filedist-package.yml +1 -1
  2. package/.xdrs/agentme/edrs/application/015-cli-tool-standards.md +27 -27
  3. package/.xdrs/agentme/edrs/application/019-ai-agents-development-standards.md +2 -2
  4. package/.xdrs/agentme/edrs/application/021-ai-workflow-development-standards.md +7 -7
  5. package/.xdrs/agentme/edrs/application/024-ml-dataset-structure.md +25 -10
  6. package/.xdrs/agentme/edrs/application/026-pragmatic-hexagonal-architecture.md +61 -8
  7. package/.xdrs/agentme/edrs/application/028-ai-eval-standards.md +99 -40
  8. package/.xdrs/agentme/edrs/application/030-ai-test-types-taxonomy.md +98 -0
  9. package/.xdrs/agentme/edrs/devops/005-monorepo-structure.md +2 -8
  10. package/.xdrs/agentme/edrs/devops/006-github-pipelines.md +3 -3
  11. package/.xdrs/agentme/edrs/devops/008-common-targets.md +26 -26
  12. package/.xdrs/agentme/edrs/devops/027-environment-variable-configuration.md +8 -8
  13. package/.xdrs/agentme/edrs/governance/013-contributing-guide-requirements.md +2 -2
  14. package/.xdrs/agentme/edrs/index.md +1 -0
  15. package/.xdrs/agentme/edrs/observability/011-service-health-check-endpoint.md +25 -3
  16. package/.xdrs/agentme/edrs/principles/002-coding-best-practices.md +6 -16
  17. package/.xdrs/agentme/edrs/principles/004-unit-test-requirements.md +6 -6
  18. package/.xdrs/agentme/edrs/principles/007-project-quality-standards.md +8 -7
  19. package/.xdrs/agentme/edrs/principles/009-error-handling.md +9 -19
  20. package/.xdrs/agentme/edrs/principles/012-continuous-xdr-enrichment.md +7 -7
  21. package/.xdrs/agentme/edrs/principles/016-cross-language-module-structure.md +7 -7
  22. package/.xdrs/agentme/edrs/principles/022-secrets-management.md +26 -8
  23. package/.xdrs/agentme/edrs/principles/023-coding-abstraction-practices.md +6 -8
  24. package/.xdrs/agentme/index.md +9 -0
  25. package/.xdrs/index.md +10 -2
  26. package/package.json +2 -2
@@ -1,5 +1,5 @@
1
1
  sets:
2
- - package: xdrs-core@0.30.0
2
+ - package: xdrs-core@0.38.3
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
 
@@ -108,11 +108,11 @@ When agents are used as nodes in workflows, the node name MUST use the `_agent`
108
108
 
109
109
  #### 05-agent-composition
110
110
 
111
- When multiple agents are needed:
111
+ When multiple agents are needed, one of these composition patterns MUST be chosen:
112
112
 
113
113
  - **Single agent with multiple tools:** Use when tools share a common goal and context (e.g., a code analysis agent with `read_file`, `search_code`, and `analyze_pattern` tools).
114
114
  - **Multiple agents as workflow nodes:** Use when agents have distinct responsibilities and outputs that feed into each other. Orchestrate them using LangGraph per [agentme-edr-021](021-ai-workflow-development-standards.md).
115
- - Do NOT create nested agent loops (agent calling agent autonomously). Use workflows for multi-agent orchestration.
115
+ - Nested agent loops (agent calling agent autonomously) MUST NOT be created. Use workflows for multi-agent orchestration.
116
116
 
117
117
  **Decision criteria:**
118
118
 
@@ -37,7 +37,7 @@ Use **MLflow** for all workflow observability and evaluation:
37
37
 
38
38
  #### 04-dataset-driven-accuracy-measurement
39
39
 
40
- Eval dataset and implementation requirements are defined in [agentme-edr-028](028-ai-eval-standards.md). Testing requirements (when evals are required, release gates) are defined in [agentme-edr-007](../principles/007-project-quality-standards.md) rule `09-ai-project-testing-requirements`.
40
+ Projects MUST follow the eval dataset and implementation requirements defined in [agentme-edr-028](028-ai-eval-standards.md). Testing requirements (when evals are required, release gates) are defined in [agentme-edr-007](../principles/007-project-quality-standards.md) rule `09-ai-project-testing-requirements`.
41
41
 
42
42
  #### 05-flow-documentation
43
43
 
@@ -101,11 +101,11 @@ lib/src/<package_name>/
101
101
 
102
102
  #### 08-workflow-evals
103
103
 
104
- Eval folder structure and script requirements are defined in [agentme-edr-028](028-ai-eval-standards.md).
104
+ Projects MUST follow the eval folder structure and script requirements defined in [agentme-edr-028](028-ai-eval-standards.md).
105
105
 
106
106
  #### 09-node-naming-conventions
107
107
 
108
- See [agentme-edr-029](029-ai-workflow-naming-conventions.md) rule `01-node-naming-conventions`.
108
+ Nodes MUST follow the naming conventions defined in [agentme-edr-029](029-ai-workflow-naming-conventions.md) rule `01-node-naming-conventions`.
109
109
 
110
110
  #### 10-workflow-unit-testing
111
111
 
@@ -159,15 +159,15 @@ Workflows MUST accept the LLM instance as a constructor parameter so that unit t
159
159
 
160
160
  #### 11-state-type-conventions
161
161
 
162
- See [agentme-edr-029](029-ai-workflow-naming-conventions.md) rule `02-state-type-conventions`.
162
+ State types MUST follow the conventions defined in [agentme-edr-029](029-ai-workflow-naming-conventions.md) rule `02-state-type-conventions`.
163
163
 
164
164
  #### 12-workflow-naming-conventions
165
165
 
166
- See [agentme-edr-029](029-ai-workflow-naming-conventions.md) rule `04-workflow-naming-conventions`.
166
+ Workflows MUST be named following the conventions in [agentme-edr-029](029-ai-workflow-naming-conventions.md) rule `04-workflow-naming-conventions`.
167
167
 
168
168
  #### 13-judge-node-output-format
169
169
 
170
- See [agentme-edr-029](029-ai-workflow-naming-conventions.md) rule `03-judge-node-output-format`.
170
+ Judge nodes MUST use the output format defined in [agentme-edr-029](029-ai-workflow-naming-conventions.md) rule `03-judge-node-output-format`.
171
171
 
172
172
  #### 15-workflow-state-persistence
173
173
 
@@ -200,7 +200,7 @@ result = graph.invoke(input_state, config={"thread_id": "session-123"})
200
200
 
201
201
  #### 16-cross-element-naming-coherence
202
202
 
203
- See [agentme-edr-029](029-ai-workflow-naming-conventions.md) rule `05-cross-element-naming-coherence`.
203
+ All workflow elements MUST maintain naming coherence as defined in [agentme-edr-029](029-ai-workflow-naming-conventions.md) rule `05-cross-element-naming-coherence`.
204
204
 
205
205
  ## References
206
206
 
@@ -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
@@ -21,7 +21,7 @@ How should application source code be organized to separate business logic from
21
21
 
22
22
  #### 01-three-layer-separation
23
23
 
24
- Every application is conceptually divided into three layers:
24
+ Every application MUST be organized into these three conceptual layers:
25
25
 
26
26
  | Layer | Description |
27
27
  |-------|-------------|
@@ -31,6 +31,8 @@ Every application is conceptually divided into three layers:
31
31
 
32
32
  #### 02-adapter-naming-conventions
33
33
 
34
+ Adapters MUST follow these naming conventions:
35
+
34
36
  **Inbound adapters** receive external requests or events and trigger application logic. Each gets a flat folder under `adapters/`:
35
37
 
36
38
  - `cli/` — command-line interface entry point
@@ -50,14 +52,24 @@ Every application is conceptually divided into three layers:
50
52
  #### 03-application-layer-rules
51
53
 
52
54
  - Expose functionality as typed library interfaces
53
- - All inputs must be explicitly passed as typed parameters
55
+ - All inputs MUST be explicitly passed as typed parameters
54
56
  - No global variables, no direct environment variable access in `app/` or `shared/`
55
57
  - Business logic with well-defined input/output behavior
56
58
  - Group related logic into subfolders (aggregation roots)
57
59
  - 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
60
 
61
+ - Data flow examples
62
+
63
+ ```text
64
+ HTTP request → adapters/http/ → app/create-user → adapters/connectors/postgres/
65
+ CLI command → adapters/cli/ → app/create-dir → adapters/connectors/local-fs/
66
+ Kafka message → adapters/kafka/ → app/process-event → adapters/connectors/stripe-api/
67
+ ```
68
+
59
69
  #### 04-mandatory-folder-structure
60
70
 
71
+ All projects MUST follow this folder structure:
72
+
61
73
  ```text
62
74
  mysystem/
63
75
  Makefile # targets to run different inbound interfaces (e.g. run-http, run-cli)
@@ -89,7 +101,7 @@ mysystem/
89
101
 
90
102
  #### 06-bootstrap-and-entry-points
91
103
 
92
- - Each inbound adapter folder (`cli/`, `http/`, `grpc/`, etc.) contains the bootstrap and entry point for that interface
104
+ - Each inbound adapter folder (`cli/`, `http/`, `grpc/`, etc.) MUST contain the bootstrap and entry point for that interface
93
105
  - The project root Makefile must have targets to run the different inbound interfaces following [agentme-edr-008](../devops/008-common-targets.md) extension conventions (e.g. `run-http`, `run-grpc`)
94
106
  - Bootstrap code lives in the adapter that receives inbound requests, not in a separate wiring layer
95
107
 
@@ -98,15 +110,56 @@ mysystem/
98
110
  - Trivial scripts and single-purpose tools (fewer than ~300 lines with a single I/O boundary) MAY skip this layering
99
111
  - All other projects MUST use this structure from the start
100
112
 
101
- #### 08-examples-of-data-flow
113
+ #### 09-unit-testing-and-mocking-strategy
102
114
 
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/
115
+ 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.
116
+
117
+ The connector implementations themselves SHOULD have their own unit tests that mock the underlying SDK or HTTP client.
118
+
119
+ ```python
120
+ # Good — inject connector; unit test mocks it
121
+ class OrderService:
122
+ def __init__(self, db: OrderRepository):
123
+ self.db = db
124
+
125
+ def test_create_order_persists_record():
126
+ fake_db = FakeOrderRepository()
127
+ service = OrderService(db=fake_db)
128
+ order = service.create({"item": "widget", "qty": 2})
129
+ assert fake_db.find(order.id) is not None
107
130
  ```
108
131
 
132
+ 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.
133
+
134
+ #### 10-mock-file-strategy
135
+
136
+ 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.
137
+
138
+ **When to use a `_mock` file vs inline:**
139
+ - Single-test use → define the mock inline inside the test file (per rule `09` example; no file needed)
140
+ - Reusable across multiple tests OR used from `eval.py` → define in a separate `_mock` file
141
+
142
+ **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`).
143
+
144
+ **Naming:** insert `_mock` immediately before the file extension:
145
+
146
+ | Source file | Mock file |
147
+ |---|---|
148
+ | `client.py` | `client_mock.py` |
149
+ | `order_service.ts` | `order_service_mock.ts` |
150
+ | `user_store.go` | `user_store_mock_test.go` |
151
+
152
+ **Placement:** follows the project's test file placement convention per [agentme-edr-004](../principles/004-unit-test-requirements.md) rule `04`:
153
+ - Co-located test convention (TypeScript, Go) → mock file in the same directory as the source file
154
+ - 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`)
155
+
156
+ **Mock contract:**
157
+ - 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
158
+ - 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)
159
+
109
160
  ## References
110
161
 
111
162
  - [agentme-edr-016](../principles/016-cross-language-module-structure.md) — Defines the module-root structure (Makefile, dist/, .cache/) that wraps this internal layout
112
163
  - [agentme-edr-002](../principles/002-coding-best-practices.md) — File size limits and code organization practices that complement this architecture
164
+ - [agentme-edr-004](../principles/004-unit-test-requirements.md) — Rule `04`: test file placement convention per language (governs `_mock` file placement in rule `10`)
165
+ - [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`)