From c2d7659fcde1afeaa43dd91d6997bf101a33c4ac Mon Sep 17 00:00:00 2001 From: Tomuta Gabriel Date: Fri, 13 Mar 2026 11:25:46 +0200 Subject: [PATCH 1/3] Add AGENTS.md file --- AGENTS.md | 305 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 305 insertions(+) create mode 100644 AGENTS.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..869e409 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,305 @@ +# Agent Instructions + +## 1) Understand the purpose + +This file provides operational guidance for AI agents working in the +**ank-sdk-python** repository. + +This project is the **Python SDK for Eclipse Ankaios** — a lightweight workload +orchestrator for automotive embedded devices and High Performance Computing +Platforms (HPCs). The SDK gives Python workloads running inside an +Ankaios-managed container access to the Ankaios Control Interface, so they can +manage (start, stop, update) other workloads and read cluster state. + +The SDK is published on PyPI as `ankaios-sdk`. The current version and its +compatible Ankaios version are defined in `setup.cfg` under `[metadata]`. + +## 2) Follow non-negotiable rules + +- **Never break existing public API** — the SDK must keep semantic alignment + with other Ankaios SDKs +- **100% test coverage is enforced** — every new or changed code path must be + covered by unit tests +- **Pylint score must stay at 10.0/10** — no new lint violations are allowed +- **PEP 8 compliance is mandatory** — zero violations accepted +- **Never invent container images** — if an image is needed for examples or + tests, ask the user +- **Exclude generated proto files from all checks** — `*_pb2.py` and + `*_pb2_grpc.py` are auto-generated; never edit them manually +- **Keep the solution minimal** — avoid unrelated refactors, extra helpers, or + speculative features + +## 3) Understand the project layout + +```text +ank-sdk-python/ +├── ankaios_sdk/ # Main SDK package +│ ├── __init__.py # Top-level exports (re-exports everything public) +│ ├── ankaios.py # Ankaios class — the primary user-facing API +│ ├── exceptions.py # All SDK exceptions (all derive from AnkaiosException) +│ ├── utils.py # Constants, AnkaiosLogLevel, helper functions +│ ├── _components/ # Internal submodules, all re-exported via __init__.py +│ │ ├── workload.py # Workload and AccessRightRule classes +│ │ ├── workload_builder.py # WorkloadBuilder (fluent builder pattern) +│ │ ├── workload_state.py # WorkloadExecutionState, WorkloadInstanceName, +│ │ │ # WorkloadState, WorkloadStateCollection, +│ │ │ # WorkloadStateEnum, WorkloadSubStateEnum +│ │ ├── complete_state.py # CompleteState, AgentAttributes +│ │ ├── manifest.py # Manifest (load from file/string/dict) +│ │ ├── request.py # Request types: GetStateRequest, +│ │ │ # UpdateStateRequest, LogsRequest, +│ │ │ # LogsCancelRequest, EventsRequest, +│ │ │ # EventsCancelRequest +│ │ ├── response.py # Response, ResponseType, UpdateStateSuccess, +│ │ │ # LogEntry, LogsStopResponse, EventEntry +│ │ ├── control_interface.py # ControlInterface, ControlInterfaceState +│ │ ├── log_campaign.py # LogCampaignResponse, LogQueue +│ │ ├── event_campaign.py # EventQueue +│ │ └── file.py # File, DataFileContent, BinaryFileContent +│ └── _protos/ # Auto-generated protobuf files (do NOT edit) +│ ├── / # Proto source files for the current version +│ ├── ank_base_pb2.py # Generated from ank_base.proto +│ ├── control_api_pb2.py # Generated from control_api.proto +│ └── __init__.py # Re-exports as _ank_base and _control_api +├── tests/ # Unit tests (mirrors the structure of ankaios_sdk) +│ ├── test_ankaios.py +│ ├── test_complete_state.py +│ ├── test_control_interface.py +│ ├── test_manifest.py +│ ├── test_utils.py +│ ├── test_workload_builder.py +│ ├── test_event_campaign.py +│ ├── test_log_campaign.py +│ ├── workload/ # Tests for Workload, AccessRightRule, File +│ ├── request/ # Tests for each Request type +│ ├── response/ # Tests for Response types +│ └── workload_state/ # Tests for WorkloadState types and enums +├── examples/ # Usage examples and sample manifests +├── tools/ # Helper scripts (fetch_protos.sh, update_version.sh, etc.) +├── docs/ # Sphinx documentation sources +├── run_checks.py # Unified check runner (tests, coverage, lint, pep8) +├── setup.py # Build script; also downloads proto files on install +├── setup.cfg # Package metadata, pytest and coverage configuration +└── .pylintrc # Pylint config (disables E1101 and W0212 project-wide) +``` + +## 4) Set up the development environment + +```sh +# Install the SDK with all dev dependencies +pip install -e ".[dev]" +``` + +If tests fail with strange protobuf-related errors, the proto files may be +stale. Re-fetch them: + +```sh +pip install -e . +# or for a specific Ankaios branch: +ANKAIOS_PROTO_BRANCH=my-feature-branch pip install -e . +``` + +## 5) Run checks + +All checks are driven through `run_checks.py`. Only one check type can be run +at a time. + +### Run unit tests + +```sh +python3 run_checks.py --utest +``` + +Pass extra pytest arguments directly after the flag: + +```sh +# Run a single test file +python3 run_checks.py --utest tests/test_ankaios.py + +# Run tests matching a keyword +python3 run_checks.py --utest -k test_apply_workload + +# Run with full traceback on failures +python3 run_checks.py --utest --full-trace +``` + +Reports are saved to `reports/utest/utest_report.xml`. + +### Run coverage (enforces 100%) + +```sh +python3 run_checks.py --cov +``` + +HTML report: `reports/coverage/html/index.html` + +### Run pylint (enforces 10.0/10) + +```sh +python3 run_checks.py --lint +``` + +Report saved to `reports/pylint/pylint_report.txt`. + +### Run PEP 8 style check (enforces zero violations) + +```sh +python3 run_checks.py --pep8 +``` + +Report saved to `reports/codestyle/codestyle_report.txt`. +Generated proto files (`*_pb2.py`, `*_pb2_grpc.py`) are excluded automatically. + +## 6) Understand the architecture + +### Control Interface + +The SDK communicates with the Ankaios agent via a Unix socket at +`/run/ankaios/control_interface` (two FIFOs: `input` and `output`). Messages +are serialized as length-delimited protobuf (`_control_api` messages wrapping +`_ank_base` messages). + +`ControlInterface` runs a background reader thread that deserializes incoming +messages and dispatches them to the `Ankaios` object via callbacks. `Ankaios` +routes responses to the correct caller using a request-ID queue. + +### Ankaios class — primary API + +`Ankaios` is the main entry point. It is typically used as a context manager: + +```python +from ankaios_sdk import Ankaios + +with Ankaios() as ankaios: + state = ankaios.get_state(timeout=5) +``` + +Key public methods: + +| Method | Description | +| ----------------------------------------------- | ----------------------------------------------------- | +| `apply_manifest(manifest)` | Apply a manifest (create/update workloads + configs) | +| `delete_manifest(manifest)` | Delete workloads and configs defined in a manifest | +| `apply_workload(workload)` | Add or update a single workload | +| `get_workload(name)` | Retrieve a workload by name | +| `delete_workload(name)` | Delete a workload | +| `get_state(field_masks, timeout)` | Get `CompleteState`, optionally filtered | +| `get_workload_states()` | Get all workload execution states | +| `wait_for_workload_to_reach_state(...)` | Poll until state matches | +| `update_configs / add_config / get_configs ...` | Manage Ankaios configs | +| `set_agent_tags / get_agents / get_agent` | Read/write agent metadata | +| `request_logs(workload_names)` | Start a real-time log stream (`LogCampaignResponse`) | +| `stop_receiving_logs(log_campaign)` | Stop a log stream | +| `register_event(filter)` | Subscribe to cluster events (returns `EventQueue`) | +| `unregister_event(event_queue)` | Unsubscribe from events | + +### Key constants (from `utils.py`) + +| Constant | Meaning | +| -------------------------------- | ----------------------------------------- | +| `DEFAULT_CONTROL_INTERFACE_PATH` | Base path for the control interface FIFOs | +| `WORKLOADS_PREFIX` | Field mask prefix for workloads | +| `CONFIGS_PREFIX` | Field mask prefix for configs | +| `AGENTS_PREFIX` | Field mask prefix for agents | +| `ANKAIOS_VERSION` | Compatible Ankaios release version | +| `SUPPORTED_API_VERSION` | Manifest API version string | + +### Protobuf internals + +Use `_ank_base` (from `ankaios_sdk._protos`) for low-level proto message +construction in tests. Never import `_pb2` files directly from outside the +`_protos` package. User-facing code must not expose proto objects. + +## 7) Follow code and test conventions + +### Code style + +- PEP 8 enforced — max line length from `pycodestyle` defaults (79 chars) +- Every module, class, and public method must have a docstring following the + existing style (see any `_components/*.py` for the pattern) +- Module-level `__all__` lists are required for all public modules +- Protected members (prefixed `_`) are used intentionally to hide internals + from users; pylint `W0212` is suppressed project-wide +- Use `get_logger()` from `utils.py` — do not use `logging.getLogger` directly +- License header (Apache-2.0 SPDX) must appear at the top of every new source + file + +### Test conventions + +- Tests live in `tests/` and mirror the `ankaios_sdk/_components/` structure +- Use `unittest.mock.patch` and `MagicMock` for all external dependencies + (file I/O, the control interface socket, + `ControlInterface.connect/disconnect/connected`) +- Each test module exports a `generate_test_()` helper function that + other test modules can import to build fixtures +- Use `pytest.raises(ExceptionType)` for exception path testing +- Do **not** test the generated proto files or `__init__.py` re-exports (both + are excluded from coverage) +- Accessing private members (e.g., `ankaios._control_interface`) in tests is + normal and expected + +### Typical test setup pattern + +```python +from unittest.mock import patch, PropertyMock +from ankaios_sdk import Ankaios, ControlInterfaceState + +def generate_test_ankaios() -> Ankaios: + with patch("ankaios_sdk.ControlInterface.connect"), patch( + "ankaios_sdk.ControlInterface.connected", new_callable=PropertyMock + ) as mock_connected: + mock_connected.return_value = True + ankaios = Ankaios() + ankaios._control_interface._state = ControlInterfaceState.CONNECTED + return ankaios +``` + +## 8) Understand the exception hierarchy + +All exceptions derive from `AnkaiosException`: + +| Exception | When raised | +| --------------------------- | ------------------------------------------------ | +| `WorkloadFieldException` | Invalid value for a workload field | +| `WorkloadBuilderException` | WorkloadBuilder used incorrectly | +| `InvalidManifestException` | Manifest YAML is malformed or missing fields | +| `ConnectionClosedException` | Control interface connection was closed | +| `ResponseException` | Unparseable response received | +| `ControlInterfaceException` | File I/O or connection operation failed | +| `AnkaiosProtocolException` | Unexpected message received from Ankaios | +| `AnkaiosResponseError` | Ankaios returned an error response | + +## 9) Work with the Workload builder + +The fluent builder is the recommended way to create workloads: + +```python +from ankaios_sdk import Workload + +workload = Workload.builder() \ + .workload_name("nginx") \ + .agent_name("agent_A") \ + .runtime("podman") \ + .restart_policy("NEVER") \ + .runtime_config("image: docker.io/library/nginx\n" + + "commandOptions: [\"-p\", \"8080:80\"]") \ + .add_dependency("other_workload", "ADD_COND_RUNNING") \ + .add_tag("key1", "value1") \ + .build() +``` + +Valid `restart_policy` values: `NEVER`, `ON_FAILURE`, `ALWAYS` + +Valid dependency conditions: `ADD_COND_RUNNING`, `ADD_COND_SUCCEEDED`, +`ADD_COND_FAILED` + +## 10) Use helper scripts + +All scripts are in `tools/` and support `--help`: + +- `tools/fetch_protos.sh` — download proto files from a specific Ankaios branch +- `tools/update_version.sh` — bump SDK, Ankaios, and API versions across the + project +- `tools/generate_docs.sh` — build Sphinx HTML docs into `docs/build/` +- `tools/install_ankaios.sh` — install Ankaios runtime (from release or CI + artifacts) From cc11987a5ce254888e1212f1ae0a0e0c3f994a3f Mon Sep 17 00:00:00 2001 From: Tomuta Gabriel Date: Fri, 13 Mar 2026 12:05:41 +0200 Subject: [PATCH 2/3] Reduce size of AGENTS.md --- AGENTS.md | 294 ++++++++++-------------------------------------------- 1 file changed, 53 insertions(+), 241 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 869e409..f421d4d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -2,170 +2,69 @@ ## 1) Understand the purpose -This file provides operational guidance for AI agents working in the -**ank-sdk-python** repository. - This project is the **Python SDK for Eclipse Ankaios** — a lightweight workload -orchestrator for automotive embedded devices and High Performance Computing -Platforms (HPCs). The SDK gives Python workloads running inside an -Ankaios-managed container access to the Ankaios Control Interface, so they can -manage (start, stop, update) other workloads and read cluster state. - -The SDK is published on PyPI as `ankaios-sdk`. The current version and its -compatible Ankaios version are defined in `setup.cfg` under `[metadata]`. - -## 2) Follow non-negotiable rules +orchestrator for automotive embedded devices and HPCs. The SDK gives Python +workloads running inside an Ankaios-managed container access to the Ankaios +Control Interface to manage (start, stop, update) other workloads and read +cluster state. -- **Never break existing public API** — the SDK must keep semantic alignment - with other Ankaios SDKs -- **100% test coverage is enforced** — every new or changed code path must be - covered by unit tests -- **Pylint score must stay at 10.0/10** — no new lint violations are allowed -- **PEP 8 compliance is mandatory** — zero violations accepted -- **Never invent container images** — if an image is needed for examples or - tests, ask the user -- **Exclude generated proto files from all checks** — `*_pb2.py` and - `*_pb2_grpc.py` are auto-generated; never edit them manually -- **Keep the solution minimal** — avoid unrelated refactors, extra helpers, or - speculative features +The SDK is published on PyPI as `ankaios-sdk`. Current version and compatible +Ankaios version are in `setup.cfg` under `[metadata]`. -## 3) Understand the project layout +## 2) Non-negotiable rules -```text -ank-sdk-python/ -├── ankaios_sdk/ # Main SDK package -│ ├── __init__.py # Top-level exports (re-exports everything public) -│ ├── ankaios.py # Ankaios class — the primary user-facing API -│ ├── exceptions.py # All SDK exceptions (all derive from AnkaiosException) -│ ├── utils.py # Constants, AnkaiosLogLevel, helper functions -│ ├── _components/ # Internal submodules, all re-exported via __init__.py -│ │ ├── workload.py # Workload and AccessRightRule classes -│ │ ├── workload_builder.py # WorkloadBuilder (fluent builder pattern) -│ │ ├── workload_state.py # WorkloadExecutionState, WorkloadInstanceName, -│ │ │ # WorkloadState, WorkloadStateCollection, -│ │ │ # WorkloadStateEnum, WorkloadSubStateEnum -│ │ ├── complete_state.py # CompleteState, AgentAttributes -│ │ ├── manifest.py # Manifest (load from file/string/dict) -│ │ ├── request.py # Request types: GetStateRequest, -│ │ │ # UpdateStateRequest, LogsRequest, -│ │ │ # LogsCancelRequest, EventsRequest, -│ │ │ # EventsCancelRequest -│ │ ├── response.py # Response, ResponseType, UpdateStateSuccess, -│ │ │ # LogEntry, LogsStopResponse, EventEntry -│ │ ├── control_interface.py # ControlInterface, ControlInterfaceState -│ │ ├── log_campaign.py # LogCampaignResponse, LogQueue -│ │ ├── event_campaign.py # EventQueue -│ │ └── file.py # File, DataFileContent, BinaryFileContent -│ └── _protos/ # Auto-generated protobuf files (do NOT edit) -│ ├── / # Proto source files for the current version -│ ├── ank_base_pb2.py # Generated from ank_base.proto -│ ├── control_api_pb2.py # Generated from control_api.proto -│ └── __init__.py # Re-exports as _ank_base and _control_api -├── tests/ # Unit tests (mirrors the structure of ankaios_sdk) -│ ├── test_ankaios.py -│ ├── test_complete_state.py -│ ├── test_control_interface.py -│ ├── test_manifest.py -│ ├── test_utils.py -│ ├── test_workload_builder.py -│ ├── test_event_campaign.py -│ ├── test_log_campaign.py -│ ├── workload/ # Tests for Workload, AccessRightRule, File -│ ├── request/ # Tests for each Request type -│ ├── response/ # Tests for Response types -│ └── workload_state/ # Tests for WorkloadState types and enums -├── examples/ # Usage examples and sample manifests -├── tools/ # Helper scripts (fetch_protos.sh, update_version.sh, etc.) -├── docs/ # Sphinx documentation sources -├── run_checks.py # Unified check runner (tests, coverage, lint, pep8) -├── setup.py # Build script; also downloads proto files on install -├── setup.cfg # Package metadata, pytest and coverage configuration -└── .pylintrc # Pylint config (disables E1101 and W0212 project-wide) -``` +- **Never break existing public API** — must keep semantic alignment with other Ankaios SDKs +- **100% test coverage is enforced** — every new or changed code path must be covered +- **Pylint score must stay at 10.0/10** — no new lint violations +- **PEP 8 compliance is mandatory** — zero violations +- **Never invent container images** — if an image is needed, ask the user +- **Exclude generated proto files from all checks** — `*_pb2.py` / `*_pb2_grpc.py` are auto-generated; never edit them +- **Keep the solution minimal** — avoid unrelated refactors or speculative features -## 4) Set up the development environment +## 3) Development environment ```sh -# Install the SDK with all dev dependencies pip install -e ".[dev]" ``` -If tests fail with strange protobuf-related errors, the proto files may be -stale. Re-fetch them: +If tests fail with protobuf errors, re-fetch proto files: ```sh pip install -e . -# or for a specific Ankaios branch: +# or for a specific branch: ANKAIOS_PROTO_BRANCH=my-feature-branch pip install -e . ``` -## 5) Run checks - -All checks are driven through `run_checks.py`. Only one check type can be run -at a time. - -### Run unit tests - -```sh -python3 run_checks.py --utest -``` - -Pass extra pytest arguments directly after the flag: - -```sh -# Run a single test file -python3 run_checks.py --utest tests/test_ankaios.py - -# Run tests matching a keyword -python3 run_checks.py --utest -k test_apply_workload - -# Run with full traceback on failures -python3 run_checks.py --utest --full-trace -``` - -Reports are saved to `reports/utest/utest_report.xml`. +## 4) Run checks -### Run coverage (enforces 100%) +All checks go through `run_checks.py` (one flag at a time): ```sh -python3 run_checks.py --cov +python3 run_checks.py --utest # unit tests +python3 run_checks.py --cov # coverage (enforces 100%) +python3 run_checks.py --lint # pylint (enforces 10.0/10) +python3 run_checks.py --pep8 # PEP 8 style (enforces zero violations) ``` -HTML report: `reports/coverage/html/index.html` - -### Run pylint (enforces 10.0/10) - -```sh -python3 run_checks.py --lint -``` - -Report saved to `reports/pylint/pylint_report.txt`. - -### Run PEP 8 style check (enforces zero violations) +All commands accept extra arguments that are forwarded to the underlying tool +(pytest / pylint / pycodestyle), e.g.: ```sh -python3 run_checks.py --pep8 +python3 run_checks.py --utest tests/test_ankaios.py # single file +python3 run_checks.py --utest -k test_apply_workload # by keyword ``` -Report saved to `reports/codestyle/codestyle_report.txt`. -Generated proto files (`*_pb2.py`, `*_pb2_grpc.py`) are excluded automatically. - -## 6) Understand the architecture - -### Control Interface +## 5) Architecture The SDK communicates with the Ankaios agent via a Unix socket at `/run/ankaios/control_interface` (two FIFOs: `input` and `output`). Messages -are serialized as length-delimited protobuf (`_control_api` messages wrapping -`_ank_base` messages). +are length-delimited protobuf (`_control_api` wrapping `_ank_base`). `ControlInterface` runs a background reader thread that deserializes incoming -messages and dispatches them to the `Ankaios` object via callbacks. `Ankaios` -routes responses to the correct caller using a request-ID queue. - -### Ankaios class — primary API +messages and dispatches them to `Ankaios` via callbacks. `Ankaios` routes +responses to the correct caller using a request-ID queue. -`Ankaios` is the main entry point. It is typically used as a context manager: +`Ankaios` is the primary entry point, typically used as a context manager: ```python from ankaios_sdk import Ankaios @@ -174,71 +73,23 @@ with Ankaios() as ankaios: state = ankaios.get_state(timeout=5) ``` -Key public methods: - -| Method | Description | -| ----------------------------------------------- | ----------------------------------------------------- | -| `apply_manifest(manifest)` | Apply a manifest (create/update workloads + configs) | -| `delete_manifest(manifest)` | Delete workloads and configs defined in a manifest | -| `apply_workload(workload)` | Add or update a single workload | -| `get_workload(name)` | Retrieve a workload by name | -| `delete_workload(name)` | Delete a workload | -| `get_state(field_masks, timeout)` | Get `CompleteState`, optionally filtered | -| `get_workload_states()` | Get all workload execution states | -| `wait_for_workload_to_reach_state(...)` | Poll until state matches | -| `update_configs / add_config / get_configs ...` | Manage Ankaios configs | -| `set_agent_tags / get_agents / get_agent` | Read/write agent metadata | -| `request_logs(workload_names)` | Start a real-time log stream (`LogCampaignResponse`) | -| `stop_receiving_logs(log_campaign)` | Stop a log stream | -| `register_event(filter)` | Subscribe to cluster events (returns `EventQueue`) | -| `unregister_event(event_queue)` | Unsubscribe from events | - -### Key constants (from `utils.py`) - -| Constant | Meaning | -| -------------------------------- | ----------------------------------------- | -| `DEFAULT_CONTROL_INTERFACE_PATH` | Base path for the control interface FIFOs | -| `WORKLOADS_PREFIX` | Field mask prefix for workloads | -| `CONFIGS_PREFIX` | Field mask prefix for configs | -| `AGENTS_PREFIX` | Field mask prefix for agents | -| `ANKAIOS_VERSION` | Compatible Ankaios release version | -| `SUPPORTED_API_VERSION` | Manifest API version string | - -### Protobuf internals - -Use `_ank_base` (from `ankaios_sdk._protos`) for low-level proto message -construction in tests. Never import `_pb2` files directly from outside the -`_protos` package. User-facing code must not expose proto objects. - -## 7) Follow code and test conventions - -### Code style - -- PEP 8 enforced — max line length from `pycodestyle` defaults (79 chars) -- Every module, class, and public method must have a docstring following the - existing style (see any `_components/*.py` for the pattern) -- Module-level `__all__` lists are required for all public modules -- Protected members (prefixed `_`) are used intentionally to hide internals - from users; pylint `W0212` is suppressed project-wide -- Use `get_logger()` from `utils.py` — do not use `logging.getLogger` directly -- License header (Apache-2.0 SPDX) must appear at the top of every new source - file +Use `_ank_base` (from `ankaios_sdk._protos`) for proto message construction in +tests. Never import `_pb2` files directly from outside the `_protos` package. +User-facing code must not expose proto objects. -### Test conventions +## 6) Code and test conventions -- Tests live in `tests/` and mirror the `ankaios_sdk/_components/` structure -- Use `unittest.mock.patch` and `MagicMock` for all external dependencies - (file I/O, the control interface socket, - `ControlInterface.connect/disconnect/connected`) -- Each test module exports a `generate_test_()` helper function that - other test modules can import to build fixtures -- Use `pytest.raises(ExceptionType)` for exception path testing -- Do **not** test the generated proto files or `__init__.py` re-exports (both - are excluded from coverage) -- Accessing private members (e.g., `ankaios._control_interface`) in tests is - normal and expected +- Max line length: 79 chars (pycodestyle default) +- Every module, class, and public method needs a docstring (follow existing style in `_components/*.py`) +- Module-level `__all__` is required for all public modules +- Use `get_logger()` from `utils.py` — not `logging.getLogger` directly +- Apache-2.0 SPDX license header at the top of every new source file +- Tests mirror the `ankaios_sdk/_components/` structure +- Use `unittest.mock.patch` / `MagicMock` for all external dependencies +- Each test module exports a `generate_test_()` helper for fixtures +- Accessing private members in tests (e.g. `ankaios._control_interface`) is normal -### Typical test setup pattern +**Typical test setup pattern:** ```python from unittest.mock import patch, PropertyMock @@ -254,52 +105,13 @@ def generate_test_ankaios() -> Ankaios: return ankaios ``` -## 8) Understand the exception hierarchy - -All exceptions derive from `AnkaiosException`: - -| Exception | When raised | -| --------------------------- | ------------------------------------------------ | -| `WorkloadFieldException` | Invalid value for a workload field | -| `WorkloadBuilderException` | WorkloadBuilder used incorrectly | -| `InvalidManifestException` | Manifest YAML is malformed or missing fields | -| `ConnectionClosedException` | Control interface connection was closed | -| `ResponseException` | Unparseable response received | -| `ControlInterfaceException` | File I/O or connection operation failed | -| `AnkaiosProtocolException` | Unexpected message received from Ankaios | -| `AnkaiosResponseError` | Ankaios returned an error response | - -## 9) Work with the Workload builder - -The fluent builder is the recommended way to create workloads: - -```python -from ankaios_sdk import Workload - -workload = Workload.builder() \ - .workload_name("nginx") \ - .agent_name("agent_A") \ - .runtime("podman") \ - .restart_policy("NEVER") \ - .runtime_config("image: docker.io/library/nginx\n" - + "commandOptions: [\"-p\", \"8080:80\"]") \ - .add_dependency("other_workload", "ADD_COND_RUNNING") \ - .add_tag("key1", "value1") \ - .build() -``` - -Valid `restart_policy` values: `NEVER`, `ON_FAILURE`, `ALWAYS` - -Valid dependency conditions: `ADD_COND_RUNNING`, `ADD_COND_SUCCEEDED`, -`ADD_COND_FAILED` +## 7) Exceptions -## 10) Use helper scripts +All exceptions derive from `AnkaiosException` (see `ankaios_sdk/exceptions.py`). -All scripts are in `tools/` and support `--help`: +## 8) Helper scripts (`tools/`, all support `--help`) -- `tools/fetch_protos.sh` — download proto files from a specific Ankaios branch -- `tools/update_version.sh` — bump SDK, Ankaios, and API versions across the - project -- `tools/generate_docs.sh` — build Sphinx HTML docs into `docs/build/` -- `tools/install_ankaios.sh` — install Ankaios runtime (from release or CI - artifacts) +- `fetch_protos.sh` — download proto files from a specific Ankaios branch +- `update_version.sh` — bump SDK, Ankaios, and API versions across the project +- `generate_docs.sh` — build Sphinx HTML docs into `docs/build/` +- `install_ankaios.sh` — install Ankaios runtime (release or CI artifacts) From 612f2a89164efe6bb1a82e65c3d4838f725aa398 Mon Sep 17 00:00:00 2001 From: Tomuta Gabriel Date: Tue, 19 May 2026 19:03:08 +0300 Subject: [PATCH 3/3] Improve AGENTS.md and DEVELOPMENT.md --- AGENTS.md | 82 ++++++++------------------------------------------ DEVELOPMENT.md | 61 +++++++++++++++++++++++++++++++++++-- 2 files changed, 71 insertions(+), 72 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index f421d4d..c0395b4 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -14,47 +14,26 @@ Ankaios version are in `setup.cfg` under `[metadata]`. ## 2) Non-negotiable rules - **Never break existing public API** — must keep semantic alignment with other Ankaios SDKs -- **100% test coverage is enforced** — every new or changed code path must be covered +- **Tests must cover behavior, not lines** — write tests for what the code is + supposed to do, not to satisfy a coverage metric. Coverage is a reviewer + hint, not a goal; gaming it with shallow assertions is a defect. + Concretely required: + - Every distinct behavior and postcondition gets its own test + - Every error condition is tested in every way it can be triggered + - Every variant of a result type is exercised: both the success and failure + paths of a function, every enum variant that can be returned - **Pylint score must stay at 10.0/10** — no new lint violations - **PEP 8 compliance is mandatory** — zero violations - **Never invent container images** — if an image is needed, ask the user - **Exclude generated proto files from all checks** — `*_pb2.py` / `*_pb2_grpc.py` are auto-generated; never edit them - **Keep the solution minimal** — avoid unrelated refactors or speculative features -## 3) Development environment +## 3) Development reference -```sh -pip install -e ".[dev]" -``` - -If tests fail with protobuf errors, re-fetch proto files: - -```sh -pip install -e . -# or for a specific branch: -ANKAIOS_PROTO_BRANCH=my-feature-branch pip install -e . -``` - -## 4) Run checks +Read [DEVELOPMENT.md](DEVELOPMENT.md) before making changes. It covers setup, +how to run checks, and all code and test conventions. -All checks go through `run_checks.py` (one flag at a time): - -```sh -python3 run_checks.py --utest # unit tests -python3 run_checks.py --cov # coverage (enforces 100%) -python3 run_checks.py --lint # pylint (enforces 10.0/10) -python3 run_checks.py --pep8 # PEP 8 style (enforces zero violations) -``` - -All commands accept extra arguments that are forwarded to the underlying tool -(pytest / pylint / pycodestyle), e.g.: - -```sh -python3 run_checks.py --utest tests/test_ankaios.py # single file -python3 run_checks.py --utest -k test_apply_workload # by keyword -``` - -## 5) Architecture +## 4) Architecture The SDK communicates with the Ankaios agent via a Unix socket at `/run/ankaios/control_interface` (two FIFOs: `input` and `output`). Messages @@ -77,41 +56,6 @@ Use `_ank_base` (from `ankaios_sdk._protos`) for proto message construction in tests. Never import `_pb2` files directly from outside the `_protos` package. User-facing code must not expose proto objects. -## 6) Code and test conventions - -- Max line length: 79 chars (pycodestyle default) -- Every module, class, and public method needs a docstring (follow existing style in `_components/*.py`) -- Module-level `__all__` is required for all public modules -- Use `get_logger()` from `utils.py` — not `logging.getLogger` directly -- Apache-2.0 SPDX license header at the top of every new source file -- Tests mirror the `ankaios_sdk/_components/` structure -- Use `unittest.mock.patch` / `MagicMock` for all external dependencies -- Each test module exports a `generate_test_()` helper for fixtures -- Accessing private members in tests (e.g. `ankaios._control_interface`) is normal - -**Typical test setup pattern:** - -```python -from unittest.mock import patch, PropertyMock -from ankaios_sdk import Ankaios, ControlInterfaceState - -def generate_test_ankaios() -> Ankaios: - with patch("ankaios_sdk.ControlInterface.connect"), patch( - "ankaios_sdk.ControlInterface.connected", new_callable=PropertyMock - ) as mock_connected: - mock_connected.return_value = True - ankaios = Ankaios() - ankaios._control_interface._state = ControlInterfaceState.CONNECTED - return ankaios -``` - -## 7) Exceptions +## 5) Exceptions All exceptions derive from `AnkaiosException` (see `ankaios_sdk/exceptions.py`). - -## 8) Helper scripts (`tools/`, all support `--help`) - -- `fetch_protos.sh` — download proto files from a specific Ankaios branch -- `update_version.sh` — bump SDK, Ankaios, and API versions across the project -- `generate_docs.sh` — build Sphinx HTML docs into `docs/build/` -- `install_ankaios.sh` — install Ankaios runtime (release or CI artifacts) diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index b7580ea..e2e510b 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -14,9 +14,56 @@ pip install -e ".[dev]" ## Commands and Scripts -The project provides a unified check runner ([run_checks.py](./run_checks.py)) for common development workflows. For a complete list of the available checks and actions, run `python3 run_checks.py --help`. +All checks go through [run_checks.py](./run_checks.py) (one flag at a time): -In addition, the [tools](tools/) folder contains helper scripts for specific tasks. Check the tools [readme](tools/README.md) for more info. +```shell +python3 run_checks.py --utest # unit tests +python3 run_checks.py --cov # coverage report (use as a review hint, not a target) +python3 run_checks.py --lint # pylint (enforces 10.0/10) +python3 run_checks.py --pep8 # PEP 8 style (enforces zero violations) +``` + +Extra arguments are forwarded to the underlying tool (pytest / pylint / pycodestyle): + +```shell +python3 run_checks.py --utest tests/test_ankaios.py # single file +python3 run_checks.py --utest -k test_apply_workload # by keyword +``` + +The [tools/](tools/) folder contains helper scripts for specific tasks — see [tools/README.md](tools/README.md) for details. All scripts support `--help`: + +- `fetch_protos.sh` — download proto files from a specific Ankaios branch +- `update_version.sh` — bump SDK, Ankaios, and API versions across the project +- `generate_docs.sh` — build Sphinx HTML docs into `docs/build/` +- `install_ankaios.sh` — install Ankaios runtime (release or CI artifacts) + +## Code and Test Conventions + +- Max line length: 79 chars (pycodestyle default) +- Every module, class, and public method needs a docstring (follow existing style in `_components/*.py`) +- Module-level `__all__` is required for all public modules +- Use `get_logger()` from `utils.py` — not `logging.getLogger` directly +- Apache-2.0 SPDX license header at the top of every new source file +- Tests mirror the `ankaios_sdk/_components/` structure +- Use `unittest.mock.patch` / `MagicMock` for all external dependencies +- Each test module exports a `generate_test_()` helper for fixtures +- Accessing private members in tests (e.g. `ankaios._control_interface`) is normal + +**Typical test setup pattern:** + +```python +from unittest.mock import patch, PropertyMock +from ankaios_sdk import Ankaios, ControlInterfaceState + +def generate_test_ankaios() -> Ankaios: + with patch("ankaios_sdk.ControlInterface.connect"), patch( + "ankaios_sdk.ControlInterface.connected", new_callable=PropertyMock + ) as mock_connected: + mock_connected.return_value = True + ankaios = Ankaios() + ankaios._control_interface._state = ControlInterfaceState.CONNECTED + return ankaios +``` ## Updating Documentation @@ -30,7 +77,15 @@ There are markdown files which are part of the published documentation. Because ### Tests fail with strange errors regarding the protobuf objects -If this is the case, the proto files do not match the local code. The fetching of the proto files is documented in the [setup.py](setup.py) script, in the `extract_the_proto_files` method. It might be the case that the proto files must be fetched again. +The proto files do not match the local code. Re-fetch them: + +```shell +pip install -e . +# or for a specific Ankaios branch: +ANKAIOS_PROTO_BRANCH=my-feature-branch pip install -e . +``` + +The fetching logic is in [setup.py](setup.py) (`extract_the_proto_files`). ## Additional Resources