-
Notifications
You must be signed in to change notification settings - Fork 4
docs: add production engineering contract for AI agents #302
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
852fe89
docs: add production engineering agent contract
masarray 90b6faf
docs: add result-oriented failure and async diagnostics contract
masarray 447b54c
docs: define non-regression architecture invariants
masarray d704dc0
docs: define measurable performance regression budget
masarray File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,244 @@ | ||
| # AGENTS.md — ARSAS Production Engineering Contract | ||
|
|
||
| These rules apply to every AI/code agent working in this repository. ARSAS is professional substation-engineering software; engineering correctness, deterministic behavior, responsiveness, field robustness, and regression safety are product requirements from the first implementation. | ||
|
|
||
| ## 1. Prime directive | ||
|
|
||
| Do not begin with a deliberately naive, disposable, prototype-only, or intentionally simplified implementation when the production architecture is already knowable. | ||
|
|
||
| Design the smallest production-quality solution that satisfies the requirement without unnecessary architectural complexity. | ||
|
|
||
| Priorities, in order: | ||
| 1. engineering correctness and data integrity; | ||
| 2. failure containment and crash resistance; | ||
| 3. regression compatibility; | ||
| 4. UI responsiveness and bounded latency; | ||
| 5. performance and bounded memory; | ||
| 6. maintainability and testability. | ||
|
|
||
| Do not sacrifice existing working capability to make a new screenshot or demo pass. | ||
|
|
||
| ## 2. Mandatory workflow before editing | ||
|
|
||
| For non-trivial bugs, features, performance work, or architectural changes, follow this sequence: | ||
|
|
||
| RECONNAISSANCE -> REPRODUCE/BASELINE -> ROOT CAUSE -> INVARIANTS -> ARCHITECTURE IMPACT -> IMPLEMENT -> REGRESSION TEST -> FAILURE-PATH TEST -> PERFORMANCE CHECK -> CI/BUILD -> USER WORKFLOW VALIDATION | ||
|
|
||
| Before changing code: | ||
| - locate the current implementation and all known consumers; | ||
| - identify the authoritative state/model and avoid creating a second source of truth; | ||
| - identify related tests, serialization formats, protocol mappings, view-model bindings, and lifecycle owners; | ||
| - state which existing behaviors must not change; | ||
| - determine root cause before applying a patch; | ||
| - prefer an existing abstraction over creating a parallel subsystem. | ||
|
|
||
| Do not repeatedly modify code hoping one version works. If an attempt fails, stop, re-check assumptions, gather evidence, then revise the design. | ||
|
|
||
| Three patches in the same subsystem for the same symptom are a signal to re-audit the root cause and architecture. | ||
|
|
||
| ## 3. Architecture boundaries | ||
|
|
||
| Keep dependencies directional where practical: | ||
|
|
||
| Presentation / XAML / View | ||
| -> Application / orchestration / use cases | ||
| -> Domain / engineering models / calculations | ||
| -> Infrastructure / device / file / network / OS adapters | ||
|
|
||
| Rules: | ||
| - engineering calculations must not depend directly on UI controls; | ||
| - filesystem, network, device, database, update, export, and OS integration should remain behind explicit service/adaptor boundaries; | ||
| - avoid global mutable state; | ||
| - prefer one authoritative document/session state model; | ||
| - do not duplicate engineering data merely to simplify UI code; | ||
| - do not introduce abstractions for hypothetical future requirements without a current need. | ||
|
|
||
| ## 4. Defensive programming and failure containment | ||
|
|
||
| Treat all external inputs as fallible: COMTRADE, SCL, packet captures, IEC 61850 responses, device/network traffic, local files, configuration, persisted state, user input, and update metadata. | ||
|
|
||
| Validate before use: | ||
| - nullability and missing fields; | ||
| - bounds, lengths, indexes, and channel counts; | ||
| - numeric ranges, overflow, NaN and Infinity; | ||
| - schema/version assumptions; | ||
| - malformed, partial, truncated, stale, or inconsistent data; | ||
| - timeouts, cancellation, disconnect, and partial completion. | ||
|
|
||
| For C# prefer nullable reference types, pattern matching, TryParse-style APIs, explicit guards, typed result/error models, `using`/`await using`, and cancellation tokens where appropriate. | ||
|
|
||
| Do not wrap every function in a broad `try/catch`. Catch at meaningful failure boundaries. Never silently swallow failures. Recover locally when safe; otherwise propagate a structured failure to the owning layer and keep the application usable when isolation is possible. | ||
|
|
||
| One malformed field record must not crash the entire application. | ||
|
|
||
| ## 5. Zero UI blocking | ||
|
|
||
| The UI thread exists for presentation and interaction. | ||
|
|
||
| Never perform synchronous long-running: | ||
| - file parsing or export; | ||
| - network/device communication; | ||
| - SCL/COMTRADE bulk processing; | ||
| - FFT/harmonic/phasor/locus calculations; | ||
| - report generation; | ||
| - database or package/update work | ||
|
|
||
| on the UI thread. | ||
|
|
||
| For a 60 Hz interface, ~16.7 ms is the total frame budget, not permission for an individual operation to consume 16 ms repeatedly. | ||
|
|
||
| Use async I/O for I/O-bound work and background workers/tasks for CPU-bound work. User-triggered work that can outlive its screen/session must support cancellation when practical. Marshal only minimal results back to UI state. | ||
|
|
||
| Never use arbitrary `Task.Delay`/timers to hide a race condition. | ||
|
|
||
| ## 6. Streaming, batching, backpressure | ||
|
|
||
| High-frequency streams such as waveform updates, packet/event feeds, device telemetry, logging, cursor-driven analysis, or live IEC 61850 data must not trigger one expensive UI update per incoming event. | ||
|
|
||
| Use bounded queues, coalescing, batching, throttling, latest-value semantics, or backpressure according to domain needs. | ||
|
|
||
| Rules: | ||
| - avoid unbounded queues; | ||
| - avoid one task/thread per event; | ||
| - separate acquisition frequency from presentation frequency; | ||
| - preserve all samples only when the engineering requirement is lossless; | ||
| - otherwise prefer latest-state/coalesced rendering; | ||
| - always commit the exact final interaction value after coalesced drag/update flows. | ||
|
|
||
| ## 7. Large files and large datasets | ||
|
|
||
| Do not eagerly load entire large engineering files into multiple duplicate in-memory structures when streaming/indexed access is practical. | ||
|
|
||
| Prefer: | ||
| streaming -> chunked parse -> indexed metadata -> bounded working set -> viewport/analysis-specific access | ||
|
|
||
| For very large local files, consider memory mapping when it materially improves the workload and lifetime model. | ||
|
|
||
| Avoid full-record rescans for small cursor or viewport changes. | ||
|
|
||
| ## 8. Waveform, chart, table, and tree virtualization | ||
|
|
||
| Rendering cost must scale primarily with visible information, not total dataset size. | ||
|
|
||
| Large lists, trees, protocol frames, event logs, tables, and engineering grids must use virtualization/lazy loading/paging where supported. | ||
|
|
||
| Dense waveform/time-series rendering must use viewport-aware LOD/downsampling before drawing. For disturbance waveforms, prefer extrema-preserving min/max envelope strategies over simple averaging so short transients and trip spikes are not hidden. | ||
|
|
||
| Keep static layers (grid, axes, protection zones, base geometry) separate from high-frequency dynamic overlays (cursor, selection, hover, live markers) to avoid full-scene invalidation. | ||
|
|
||
| Never regenerate a full waveform, locus, or harmonic dataset merely because a cursor moved. | ||
|
|
||
| ## 9. Memory and resource lifetime | ||
|
|
||
| Avoid unnecessary allocations/copies in hot paths. | ||
|
|
||
| Prefer reusable buffers, retained capacity, spans/views, pooled arrays only when profiling shows allocation pressure, and precomputed indexes instead of repeated scans. | ||
|
|
||
| Do not add a generic object pool merely because pooling sounds faster. | ||
|
|
||
| Every owned resource must have an explicit lifecycle: files, streams, sockets, timers, subscriptions, event handlers, cancellation sources, device handles, unmanaged buffers, workers, and GPU resources. | ||
|
|
||
| Dispose/unsubscribe/release when ownership ends. A document reload/close must not leave callbacks pointing to destroyed state. | ||
|
|
||
| ## 10. IEC 61850 / device / protocol rules | ||
|
|
||
| Never assume an IED, gateway, capture, or remote endpoint behaves perfectly. | ||
|
|
||
| Validate declared lengths before field access. Use explicit timeouts. Handle disconnect, reconnect, cancellation, negative responses, partial responses, unsupported services, malformed frames, and stale state. | ||
|
|
||
| Protocol state machines must have explicit transitions and bounded retry behavior. Unexpected frames must fail safely rather than corrupt session state. | ||
|
|
||
| Device/network callbacks must not perform expensive UI work directly. | ||
|
|
||
| Do not cosmetically alter protocol/engineering data to imitate another product. UI representation may be optimized, but timestamps, values, quality, sequence, trigger semantics, phasors, impedance, zones, and report facts must remain engineering-correct. | ||
|
|
||
| ## 11. Performance as a contract | ||
|
|
||
| Performance-sensitive paths should define and preserve measurable budgets where practical: | ||
| - startup time; | ||
| - file-open latency; | ||
| - parsing throughput; | ||
| - interaction/cursor latency; | ||
| - UI frame time; | ||
| - allocation rate and working-set memory; | ||
| - report/export time; | ||
| - packet/event processing throughput; | ||
| - queue depth under burst load. | ||
|
|
||
| Do not claim an optimization without evidence. Prefer algorithmic/layout improvements over speculative micro-optimizations. | ||
|
|
||
| Do not add caches, worker pools, SIMD, object pooling, or complex concurrency unless the bottleneck and ownership model are understood. | ||
|
|
||
| ## 12. Regression prevention | ||
|
|
||
| Every bug fix should add or update a regression test whenever technically practical. | ||
|
|
||
| Test the exact failure mode that motivated the change, not only nearby happy paths. | ||
|
|
||
| Before changing shared behavior, identify callers and persisted/public contracts. Do not change serialization, configuration, protocol mapping, default values, timing semantics, report semantics, or public APIs without compatibility analysis. | ||
|
|
||
| For UI bugs, protect interaction semantics in addition to appearance. | ||
|
|
||
| ## 13. Change discipline | ||
|
|
||
| Prefer the smallest coherent change that fixes the root cause. | ||
|
|
||
| Do not: | ||
| - mix unrelated refactoring into a focused fix; | ||
| - create duplicate services/state stores because understanding the existing path is inconvenient; | ||
| - rename large areas without a compelling reason; | ||
| - add a dependency when the platform/current stack already provides the capability; | ||
| - replace a working subsystem simply because a rewrite appears easier. | ||
|
|
||
| A new dependency must justify purpose, maintenance cost, binary impact, security implications, and runtime overhead. | ||
|
|
||
| ## 14. Exception-free hot paths, Result pattern, and asynchronous diagnostics | ||
|
|
||
| Expected or recoverable failures must not use exceptions as normal control flow in performance-critical or high-frequency code. This includes COMTRADE/SCL parsing loops, IEC 61850 frame decoding, packet/event processing, waveform/harmonic/phasor calculation loops, device acquisition callbacks, and rendering-preparation hot paths. | ||
|
|
||
| Prefer explicit C# failure contracts such as `TryXxx(...)`, typed `Result<T>` / result records, discriminated status models, nullable returns only when the failure meaning is unambiguous, and structured error codes. A normal timeout, malformed field, missing sample, unsupported value, disconnected device, or parse rejection should not require stack unwinding. | ||
|
|
||
| Exceptions from .NET, OS APIs, filesystem/network libraries, or third-party code may still occur. Catch them at the nearest meaningful infrastructure/application boundary, convert them into the repository's structured result/error model, preserve cancellation semantics, and keep exception handling out of inner loops. Do not catch and ignore exceptions. | ||
|
|
||
| For hot-path diagnostics, never synchronously write files, console logs, telemetry, UI dialogs, JSON, or expensive formatted strings. Publish a small structured diagnostic event to a bounded asynchronous diagnostic channel/queue and let a background consumer aggregate, format, persist, or surface it. | ||
|
|
||
| Diagnostic queues must be bounded and have an explicit overload policy. Deduplicate/rate-limit repeated failures and aggregate counts such as `MalformedRow x 4281` instead of enqueueing thousands of equivalent messages. A full/broken diagnostic queue must never block protocol processing, parsing, rendering, or UI responsiveness; retain counters/high-severity/latest events according to documented policy. | ||
|
|
||
| The diagnostic subsystem is observational, not a correctness dependency. Logging failure must not become application failure. | ||
|
|
||
| When implementing a `Result<T>` family, keep it lightweight and consistent. Do not create multiple incompatible result abstractions in different subsystems. Error payloads should carry stable machine-readable codes/context first; human-readable formatting belongs outside the hot path. | ||
|
|
||
| ## 15. Definition of done | ||
|
|
||
| A task is not complete because it compiles. | ||
|
|
||
| Validate, as applicable: | ||
| BUILD | ||
| + STATIC ANALYSIS | ||
| + UNIT TESTS | ||
| + REGRESSION TESTS | ||
| + INTEGRATION/DETERMINISTIC FIXTURES | ||
| + NEGATIVE/FAILURE-PATH TESTS | ||
| + PERFORMANCE/ALLOCATION CHECK | ||
| + RESOURCE/LIFECYCLE CHECK | ||
| + PACKAGED STARTUP/SMOKE TEST | ||
| + REAL USER WORKFLOW CHECK | ||
|
|
||
| Use the repository PR template and existing engineering validation gates. Never claim a check was run when it was not. | ||
|
|
||
| ## 16. Agent completion report | ||
|
|
||
| After implementation, report: | ||
| - Changed: what was modified; | ||
| - Root cause: why the previous behavior failed; | ||
| - Architecture: why this solution belongs in the existing design; | ||
| - Regression protection: tests/invariants added; | ||
| - Performance impact: measured result or why the path is not performance-sensitive; | ||
| - Validation: exact checks/commands and results; | ||
| - Remaining limitations: genuine unresolved limitations only. | ||
|
|
||
| ## Final rule | ||
|
|
||
| Think like the maintainer who must support ARSAS on real engineering data for years, not like a prototype generator trying to make today's screenshot pass. | ||
|
|
||
| Understand first. Fix root causes. Preserve working behavior. Keep hot paths bounded. Validate failure modes. Measure performance when relevant. Prevent regressions before declaring done. | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| # ARSAS Architecture and Product Invariants | ||
|
|
||
| These invariants are constraints, not implementation suggestions. A change that violates one requires an explicit architecture decision, compatibility analysis, and regression evidence before merge. | ||
|
|
||
| ## Engineering truth | ||
|
|
||
| 1. UI presentation must never invent, hide, or cosmetically alter engineering values to match a reference product. | ||
| 2. Timestamps, trigger position, sample values, phasors, impedance, protection zones, IEC 61850 quality/state, sequence/order, report facts, and exported evidence preserve their engineering semantics end-to-end. | ||
| 3. Missing/invalid source data remains explicit as unknown/invalid/NaN or another documented state; it is not silently replaced with plausible engineering values. | ||
|
|
||
| ## State ownership | ||
|
|
||
| 4. Each document/session/device workflow has one authoritative state owner. UI mirrors/derives state; it does not become a second protocol or engineering model. | ||
| 5. A new feature must not create a parallel parser, protocol state machine, waveform store, cursor truth, or report truth merely to bypass an existing defect. | ||
| 6. Background work may publish validated immutable/bounded results to UI state, but must not mutate UI-owned objects unsafely. | ||
|
|
||
| ## Responsiveness | ||
|
|
||
| 7. File, network, device, database, package/update, report-generation, bulk analysis, FFT/harmonic/locus, or other potentially expensive work never blocks the UI thread. | ||
| 8. Cursor/selection/drag visual feedback remains lightweight and decoupled from full-record recomputation. | ||
| 9. High-frequency acquisition/events do not map 1:1 to expensive UI renders. Batching/coalescing/backpressure is explicit. | ||
| 10. No race or lifecycle bug is considered fixed by an arbitrary sleep/delay alone. | ||
|
|
||
| ## Large data | ||
|
|
||
| 11. Large records/captures are processed with bounded working sets; architecture must not require multiple eager whole-file copies merely for convenience. | ||
| 12. Dense waveform/chart rendering scales primarily with visible pixels/viewport, not total sample count. | ||
| 13. Downsampling for disturbance/protection waveforms preserves extrema/transients; simple averaging must not hide short events. | ||
|
|
||
| ## Failure handling | ||
|
|
||
| 14. Expected/recoverable parser/protocol/domain failures use explicit Result/Try/status semantics where practical; exceptions are not normal hot-path control flow. | ||
| 15. OS/.NET/library exceptions are contained at meaningful boundaries and converted to structured failures. | ||
| 16. One malformed field/packet/file row or failed optional operation must not crash the entire workstation when isolation is technically possible. | ||
| 17. Diagnostic infrastructure is observational. A full/slow/broken log or diagnostic sink never blocks critical processing or becomes application failure. | ||
| 18. High-rate diagnostics use bounded queues/channels with deduplication/rate limiting/aggregation. | ||
|
|
||
| ## Protocol/device behavior | ||
|
|
||
| 19. IEC 61850/device state machines have explicit transitions, bounded retries/timeouts, cancellation/shutdown behavior, and safe terminal states. | ||
| 20. Unexpected/late/malformed traffic cannot silently corrupt current association/session state. | ||
| 21. Discovery/read workflows never become implicit active write/control operations. | ||
| 22. Device/network callbacks do not perform expensive UI work directly. | ||
|
|
||
| ## Resource lifetime | ||
|
|
||
| 23. Every owned stream, socket, timer, worker, subscription, event handler, cancellation source, mapping, unmanaged buffer, and device handle has an explicit owner and release path. | ||
| 24. Document/session close or reload cannot leave callbacks/workers publishing into destroyed or superseded state. | ||
| 25. Queues that can receive sustained traffic are bounded and have an explicit overload policy. | ||
|
|
||
| ## Regression discipline | ||
|
|
||
| 26. A bug fix protects the exact reported failure mode with a deterministic regression test/check whenever technically practical. | ||
| 27. Public/persisted formats, protocol mappings, timing semantics, defaults, and report semantics do not change without compatibility analysis. | ||
| 28. Existing working capability is not removed or rewritten simply because implementing the new request is easier in a replacement path. | ||
| 29. Three successive symptom patches in the same subsystem trigger root-cause/architecture re-audit before a fourth patch. | ||
| 30. Completion requires evidence. Compile success alone is never proof that an engineering workflow is correct. |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When an agent follows these arrows as the declared dependency direction, the diagram instructs the Domain layer to depend on Infrastructure, allowing engineering models/calculations to couple directly to file, network, device, or OS implementations. That reverses the service/adapter boundary described immediately below; Infrastructure adapters should instead depend inward on application/domain contracts rather than sit downstream of Domain.
AGENTS.md reference: AGENTS.md:L41-L46
Useful? React with 👍 / 👎.