= AI Development Guide
:author: Egon Kastelijn
:toc: left
:toclevels: 2
:icons: font
:source-highlighter: coderay
๐ This document outlines expectations, preferences, and constraints for any AI assisting in development of this software project.
== ๐ง Purpose of AI Collaboration
The AI is expected to assist with:
* Reviewing and refactoring existing code
* Generating new modules and features
* Ensuring architecture consistency
* Providing safe, idiomatic Rust solutions
* Offering structured documentation or summaries
* Creating good tests and test-coverage
The AI acts as a productive teammate โ contributing real code, not just suggesting in abstract.
== Philosophy
The codebase is designed to be:
* Explicit over implicit
* Safe over convenient
* Readable over clever
== ๐ Design Decision: Multi-sensor support and dynamic mapping
This project follows the CSDIF specification (Rev2, 2025-06-26), which defines a document structure that supports multiple sensors and observations. Each observation refers to a sensor via its `sensor_id`. This design enables:
* Combining data from multiple sources
* Supporting heterogeneous sensor networks
* Validating cross-referenced observations
=== ๐ Trait-based transformation
To support dynamic input formats (e.g. MQTT, CouchDB, CSV, YAML), the core crate defines a trait:
[source,rust]
----
/// Trait for mapping external data into a CSDIF document.
pub trait CsdifMapper {
fn to_csdif(&self) -> Result<CsdifDocument, CsdifError>;
}
----
Adapters implement this trait for their own input types. This allows:
* Runtime flexibility without compile-time coupling
* Adapter-specific logic outside the core crate
* Clean separation of concerns in a hexagonal architecture
=== ๐ YAML-based mapping
Adapters may support YAML-based configuration files to define how external data maps to CSDIF. These files are parsed at runtime and used to drive the transformation logic. AI tools may generate:
* `YamlMappingConfig` structs with `serde_yaml`
* Trait implementations that use these configs
* Tests that validate mappings against sample input
=== โ
AI Responsibility
When generating mapping logic, the AI must:
* Assume multiple sensors per document
* Ensure observations reference valid `sensor_id`s
* Use trait-based transformation (`CsdifMapper`)
* Support YAML-driven mapping when applicable
* Avoid hardcoded assumptions about input formats
== ๐งฉ AI Context Awareness
When assisting with code generation, refactoring, or architectural decisions, the AI must actively assess whether it has sufficient context to provide accurate and relevant advice.
=== โ
Ask for missing files or modules
If the AI detects that a referenced file, module, struct, trait, or function is missing โ or if the current context is insufficient to proceed confidently โ it must:
* Prompt the user to share the missing file or module
* Clearly state which part is missing and why it's needed
* Avoid guessing or fabricating unknown logic
* Wait for the user's input before continuing
This ensures that AI-generated code is grounded in the actual project structure and avoids introducing inconsistencies.
==== ๐ Example
If the user says:
[source]
----
Can you help me refactor the mapping logic?
----
And the AI sees that `MappingConfig` or `map_records()` is not defined in the current context, it must respond with:
[source]
----
To help with that, could you share the current implementation of `MappingConfig` and `map_records()`? That way I can refactor based on your actual logic.
----
=== โ
Never assume full context
Unless the user has explicitly provided the relevant source code, configuration, or file structure, the AI must treat the context as partial and ask for clarification when needed.
== AI Rules
These rules apply to all AI-generated or AI-assisted code:
=== โ No `unwrap()`
Never use `.unwrap()` or `.expect()` on `Option` or `Result`.
Instead, handle errors explicitly using `match`, `if let`, or `map_or_else`.
=== โ No `?` operator
Avoid the `?` operator to propagate errors.
Use structured error handling with `match` blocks and custom error messages.
=== โ
All errors must be logged or surfaced
Every error must either:
* Be logged with `error!()`
* Be returned with a descriptive message
* Be handled gracefully with fallback logic
=== โ
Comments must be in English
All comments, messages, and documentation must be written in clear English.
=== โ
No panics
Avoid `panic!()` or any code that may cause runtime panics.
Use safe fallbacks and validation.
=== โ
Use Dependency Injection for External Interfaces
All AI-generated code that depends on external systems (e.g. HTTP clients, file writers, databases) must use dependency injection.
* Accept dependencies as function arguments or trait objects
* Avoid hardcoding instantiations inside logic functions
* Prefer traits for abstraction and mocking
* Use `Box<dyn Trait>` or generics for runtime flexibility
This ensures testability, modularity, and clear separation of concerns.
=== โ
Prefer Stateless Async Functions
When designing logic, especially for external systems, prefer stateless async functions over methods that require `&self`.
Stateless functions are easier to parallelize and scale, and they avoid borrow conflicts or shared mutable state.
Use `impl Struct::method(...)` without `&self` when:
* The function does not need access to internal fields
* The logic is purely functional or externally driven
* The goal is to maximize concurrency (e.g. bulk writes, chunked processing)
Use `&self` only when:
* Internal state or configuration is required
* The method logically belongs to the struct's identity
This pattern ensures that operations can be executed in parallel without blocking or borrowing conflicts.
=== โ
SPDX License Headers
All AI-generated source files must begin with a valid SPDX license identifier.
Example:
[source,rust]
----
// SPDX-License-Identifier: MIT
----
This ensures license clarity and compatibility across the codebase.
=== โ
Code Documentation Standards
All AI-generated code must include clear, structured documentation that meets the following expectations:
* Every public struct, enum, trait, and function must have a Rustdoc comment (`///`) describing its purpose and usage.
* Comments must be written in clear English.
* Internal logic should be explained with inline comments (`//`) where non-obvious decisions are made.
* Avoid redundant comments that repeat what the code already expresses.
* Prefer examples over abstract descriptions when documenting usage.
* Use `#[doc(hidden)]` only when intentionally hiding internal APIs โ never to bypass documentation requirements.
==== ๐ Example
[source,rust]
----
/// Represents a physical sensor used in a CSDIF document.
///
/// This struct contains metadata about the sensor, including its ID,
/// type, measurement unit, and physical location.
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Sensor {
pub id: String,
pub sensor_type: String,
pub unit: String,
pub location: Location,
}
----
==== ๐งช AI Responsibility
When generating new code, the AI must:
* Include Rustdoc comments for all public items.
* Add inline comments for complex logic or transformations.
* Ensure documentation is consistent with naming and behavior.
* Avoid generating undocumented modules or functions.
=== โ
File Naming & Structure Conventions
* Use `snake_case` for all filenames and module names.
* Group related logic into folders (e.g. `steps/mapper.rs`, `steps/transformer.rs`).
* Avoid deeply nested modules โ prefer flat and readable structure.
=== โ
Logging Expectations
* Use structured logging (e.g. `log::error!`, `log::info!`) with context.
* Avoid printing directly to stdout/stderr unless explicitly required by CLI.
* All errors surfaced to the user must include actionable context.
=== โ
Configuration Handling
* All configuration must be loaded via dependency injection.
* Use structs like `MappingConfig` to represent config state.
* Avoid global state or static config access.
=== โ
CLI Behavior Expectations
* All CLI commands must return a non-zero exit code on failure.
* Help text must be clear, concise, and match the actual behavior.
* Use `clap` features like `arg_enum`, `flatten`, and `subcommand` to structure input.
=== โ
Data Safety Guarantees
* No data should be silently dropped or ignored.
* All transformation steps must preserve input fidelity unless explicitly configured otherwise.
* Validation errors must halt export unless explicitly overridden.
=== โ
Unit Testing Requirements
* All modules must include unit tests.
* Tests must cover both success and failure paths.
* Pipeline steps must be testable in isolation.
* JSON serialization and validation must be tested explicitly.
* No logic should be added without corresponding tests.
== ๐งช Testability & Reliability
The codebase must be:
* Fully testable with _high test coverage_
* Designed for _modular testing_ of individual components
* Capable of _graceful error handling_ and _logging with context_
* Structured to ensure _no data is lost or corrupted_
== AI Prompting Style
When prompting an AI assistant:
* Be specific about file boundaries
* Request full copy-paste ready output
* Prefer modular suggestions over monolithic rewrites
== Future Considerations
* Add automatic SPDX header enforcement
* Add documentation coverage checks
* Add schema validation for input formats
* Add integration tests for full pipeline execution