# KOPR Development and Architecture Policy — Current Canonical Baseline

**Status:** normative for the current canonical KOPR architecture and all KOPR development after completion of canonical convergence in R515 / C8.  
**Effective architecture baseline:** R515 (`FULL CANONICAL CONVERGENCE COMPLETE`).  
**Current user-facing release line:** `KOPR Live Theta-1`.  
**Applies to:** production code, tests, developer tooling, architecture tooling, refactors, bug fixes, new features, packaging, compatibility work, scientific changes, GUI changes, and major cleanup.  
**Supersedes:** `KOPR_DEVELOPMENT_ARCHITECTURE_POLICY_POST_R410.md` and any migration-era instruction that describes a hybrid root + `src/kopr` implementation as an acceptable steady state.

> The final KOPR architecture is no longer hybrid. All active product implementation is canonical under `src/kopr/`. Flat-root Python files are retained only as explicitly classified, non-owning compatibility/delegation/adapter/source-launcher surfaces. Future development must preserve this end state.

---

## 1. Authority and source of truth

The canonical implementation tree is:

```text
src/kopr/
```

The active architecture enforcement surface is:

```text
tools/architecture/architecture_guard.py
tools/architecture/architecture_policy.json
tools/architecture/compatibility_perimeter.json
tools/architecture/legacy_compatibility_identity_contract.json
tools/architecture/package_api_policy.json
```

Before and after production or structural changes run:

```bash
python3 tools/architecture/architecture_guard.py
```

The current machine-readable policy in the working tree is authoritative for the exact current inventory. This document defines the architectural intent and non-negotiable rules.

Historical migration reports, release-numbered convergence plans, old architecture snapshots, `tools/migration/` tooling, and pre-R515 flat-root layouts are **evidence/history only**. They are not valid implementation baselines and must not be used to reconstruct a hybrid architecture.

If a future qualified release intentionally changes the canonical architecture, its current `tools/architecture/*` contracts and an updated version of this policy supersede the R515 reference counts below. Historical R515 counts are therefore a qualified reference snapshot, not a permanent ceiling on legitimate canonical feature growth.

---

## 2. Qualified final state at R515

R515 / C8 proved the following current state:

```text
root Python surfaces:                  86
root -> root import edges:              0
active root implementation owners:     0
partial implementation facades:        0
canonical src/kopr Python files:      304
canonical import edges:               704
canonical SCCs:                         0
architecture violations:               0
```

Compatibility closure at R515:

```text
root compatibility perimeter:          86 / 86 classified
RETAIN_REQUIRED:                       86
REMOVE_CANDIDATE:                       0
all retained root surfaces non-owning: true
legacy module identity surfaces:        66
legacy pickle-global surfaces:          58
identity probe:                         66 / 66 PASS
pickle probe:                           58 / 58 PASS
```

Repository/QA closure at R515:

```text
tools/migration/:                       absent
release-numbered migration helper chain: 0
architecture/convergence inventory:     45 current / 0 mixed / 0 historical-layout
frozen regression:                      602 = 586 PASS + 16 allowed environment SKIP
```

These numbers describe the qualified R515 end state. The hard requirements are the invariants in Section 3, not the exact future number of canonical files or canonical import edges.

---

## 3. Non-negotiable architectural invariants

### 3.1 All active implementation is canonical

1. All new production implementation belongs under `src/kopr/`.
2. Active scientific, domain, persistence, networking, orchestration, GUI, application, Planner, Analyzer, WCCD, WStack, Visual, ephemeris, photometry, Autophot, and other product behavior must have a canonical owner under `src/kopr/`.
3. Do not create new implementation-bearing flat-root modules.
4. Do not move implementation back from `src/kopr/` to flat root for convenience, compatibility, testing, monkeypatching, source checkout, or packaging.
5. Do not maintain the same behavior as two active implementations in different locations.

### 3.2 Root implementation ownership must stay zero

The following are hard-zero invariants unless an explicitly approved architecture redesign changes the final architecture itself:

```text
active_root_implementation_modules = 0
partial_legacy_facades_with_implementation = 0
root_to_root_import_edges = 0
src_kopr_to_flat_root_imports = 0
src_kopr_SCC = 0
architecture_violations = 0
```

The current 86 root surfaces are an explicitly classified compatibility perimeter. The root surface count must not grow merely because a developer wants a convenient import path. Any new public compatibility surface requires an explicit compatibility/API justification and qualification.

### 3.3 One implementation, one canonical owner

Every algorithm, parser, state model, persistence contract, workflow, scientific policy, GUI behavior, or reusable capability must have one unambiguous canonical owner.

Compatibility code may delegate, alias, re-export, or adapt to the canonical owner, but must not reproduce the implementation.

When functionality is shared by multiple features:

1. identify the correct shared layer;
2. extract or move the canonical implementation there if necessary;
3. expose an intentional public boundary;
4. update consumers to use that boundary.

Do not solve sharing by copying code, by importing another feature's private implementation, or by creating a flat-root helper.

### 3.4 Canonical code must not depend on the flat-root perimeter

A module under `src/kopr/` must never import a KOPR flat-root compatibility module.

The dependency direction is always:

```text
flat-root compatibility / launcher
            ->
       canonical src/kopr
```

Never the reverse.

### 3.5 Canonical package must remain acyclic

`src/kopr` qualified at **0 strongly connected components (SCCs)**. Preserve acyclicity.

Do not introduce cycles to avoid a small refactor. If a cycle appears, reconsider ownership, move shared contracts downward, introduce a public API boundary, or use dependency injection.

### 3.6 Guard policy must not be weakened to hide a design problem

Do not:

- increase architecture budgets merely to make a change pass;
- add allowlist exceptions as the first response to a violation;
- edit expected snapshots to normalize an unintended dependency;
- disable mutation qualification or other guard self-tests;
- reintroduce migration-era exceptions.

A real architecture exception requires the procedure in Section 13.

---

## 4. Canonical package responsibilities

### 4.1 `kopr.core`

Use for scientific/domain logic, typed or immutable domain contracts, numerical algorithms, astronomy and ephemerides, photometry, observation models, planner core logic, selection policy, and other behavior that should not depend on GUI orchestration.

Hard rules:

- `core` must not depend on PyQt/PySide;
- `core` must not depend on `kopr.features`;
- `core` must not depend on `kopr.application`;
- `core` must not depend on `kopr.ui`.

Prefer pure functions, explicit units, explicit inputs/outputs, and dependency injection. Existing bounded `core -> infrastructure` dependencies are qualified current behavior, not a blanket license to add more.

Current Light Curve ownership includes canonical observation reduction/selection in `kopr.core.lightcurves.observations` and typed projection in `kopr.core.lightcurves.projection`.

### 4.2 `kopr.infrastructure`

Use for I/O and external-system adapters: persistence, files, FITS/raw access, network services, MPC/COBS/VizieR access, catalogue backends, PDF output, and similar integration concerns.

Hard rules:

- infrastructure must not depend on `kopr.features`;
- infrastructure must not depend on `kopr.application`;
- infrastructure must not depend on `kopr.ui`.

Infrastructure should provide data and external capabilities. Scientific/domain policy belongs in core or an explicit higher-level workflow.

### 4.3 `kopr.features`

Use for feature-level orchestration and feature-specific state/workflows such as Analyzer, Planner, WCCD, WStack, Visual, and Ephemeris UI flows.

Features may use:

- `kopr.core`;
- `kopr.infrastructure`;
- `kopr.ui.common`;
- their own feature internals;
- another feature only through an intentionally public feature package/API boundary.

Features must not import `kopr.application`, another feature's private internals, or flat-root compatibility paths.

Current intentional cross-feature boundaries include:

- `kopr.features.analyzer.api` for supported Analyzer orchestration contracts;
- `kopr.features.ephemeris.api` for the supported Ephemeris custom-element request boundary.

An internal module is not public merely because Python can import it.

### 4.4 `kopr.ui`

Use for reusable presentation components and shared GUI primitives.

`kopr.ui.common` is the cross-feature shared UI boundary. Shared UI must not own scientific/domain decisions and must not depend on `kopr.features`, `kopr.application`, or `kopr.infrastructure`.

Feature-specific GUI orchestration belongs with the feature rather than turning `ui.common` into a dumping ground.

### 4.5 `kopr.application`

Use for application composition, lifecycle, top-level services, and wiring between already-defined capabilities.

Do not place reusable scientific algorithms here.

Application composition and `MainWindow` are canonically owned by `kopr.application.main`.

### 4.6 `kopr.compat`

Use only for explicit compatibility contracts and one-way adapters for historical/public surfaces.

It is not a destination for new product behavior.

### 4.7 `kopr.config`

Use for configuration definitions and configuration-facing contracts. Do not use it to reintroduce uncontrolled mutable global application state.

### 4.8 `kopr.legacy`

Treat as quarantined historical behavior. Do not implement new features there merely because similar legacy code exists there.

### 4.9 `kopr.tools` and repository `tools/`

Use for diagnostics, QA, architecture checks, maintenance, and developer utilities.

Production runtime must not depend on QA-only or migration-only tooling.

Active long-term architecture tooling belongs under `tools/architecture/`. Active long-term QA tooling belongs under `tools/qa/`.

---

## 5. Import and package API policy

1. Prefer explicit canonical imports that expose ownership.
2. Never import a flat-root KOPR module from `src/kopr`.
3. Never use wildcard imports (`from ... import *`) in compatibility or canonical package APIs.
4. Do not use import-order side effects as dependency injection.
5. Cross-feature reuse must go through a documented public API or a properly shared lower layer.
6. Re-export only deliberately supported domain types/functions from package `__init__.py`; do not create catch-all package APIs.
7. New consumers should import explicit canonical package boundaries. Internal modules are not public simply because they are importable.
8. Compatibility canonical-target drift is forbidden: a retained compatibility surface must continue to point to its declared canonical owner unless the compatibility contract is intentionally revised and qualified.

---

## 6. Module design and naming

Do not introduce generic catch-all modules such as:

```text
utils.py
helpers.py
functions.py
misc.py
common.py
```

Use a domain-specific name that identifies responsibility and ownership.

Prefer cohesive modules with a narrow reason to change.

Avoid:

- duplicate parsers for the same format;
- duplicate coordinate/time conversions;
- duplicate scientific constants or policy tables;
- hidden mutable globals shared across features;
- convenience imports that invert dependency direction;
- broad facade modules that become a second implementation layer.

When an existing canonical module becomes too large, decompose it into coherent canonical submodules. Do not export the complexity back to flat root.

---

## 7. Source-checkout and application entry-point policy

The installed and source-checkout application routes must converge on the same canonical application owner.

Current contract:

```text
source checkout:  python3 kopr.py
installed CLI:    kopr
canonical target: kopr.application.main:main
```

Rules:

1. Root `kopr.py` is a minimal historical source-checkout launcher only; it must not own application behavior.
2. Ordinary `src/kopr` modules must not manipulate `sys.path`.
3. The retired `_kopr_src_bootstrap.py` helper must not be recreated.
4. Retained root compatibility/source-launcher surfaces may use only the already-qualified minimal inline `src`-precedence mechanism required for historical source-checkout behavior.
5. Do not broaden source-checkout bootstrap behavior to solve ordinary package-import mistakes.
6. An installed wheel/package must reach the complete product implementation without relying on implementation that exists only at repository root.

### 7.1 User-facing release identity and numbering

KOPR has a user-facing release identity that is deliberately separate from Python package versions and internal engineering `Rxxx` evidence numbers.

Current public release identity:

```text
KOPR Live Theta-1
```

Canonical owner:

```text
src/kopr/config/release_identity.py
```

Rules:

1. The public format is `KOPR Live <GreekSeries>-<Revision>`.
2. The current Greek series is `Theta`. **Do not change the Greek series unless the project owner explicitly instructs that the series is changing.**
3. For subsequent qualified product-code releases within the active Greek series, advance the numeric revision monotonically (`Theta-1`, `Theta-2`, `Theta-3`, ...). Do not silently reset, skip backwards, or derive the revision from an internal `Rxxx` number.
4. Documentation-only work that does not produce a new product release does not by itself require a public release revision increment.
5. The public release label must have one canonical owner. Do not hard-code copies of `Theta`, the revision, or the full release string in GUI modules.
6. The main window title and **About** dialog must obtain the same label from the canonical release identity. Retained historical `Version()` APIs may delegate to that owner for compatibility, but must not own an independent release string.
7. The Python package version (for example `0.1.0.dev516`) is a technical packaging identifier and is not the public KOPR release name. It must remain independently unique when a rebuilt package/wheel is published.
8. Internal engineering `Rxxx` identifiers may remain in QA/release evidence, but must not replace the public `KOPR Live <GreekSeries>-<Revision>` identity in user-facing version displays.
9. Before producing a qualified product release, verify that source, wheel/package metadata, About dialog, main-window title, release notes and current documentation do not disagree about the intended release identity.

---

## 8. Compatibility perimeter policy

The current flat-root perimeter is intentional compatibility, not unfinished implementation migration.

At R515 all 86 root surfaces are classified in:

```text
tools/architecture/compatibility_perimeter.json
```

The narrower supported historical module/pickle identity contract is:

```text
tools/architecture/legacy_compatibility_identity_contract.json
```

Rules:

1. Every retained root surface must remain explicitly classified.
2. Every retained root surface must remain non-owning.
3. Top-level definitions in retained root files must match the declared perimeter contract.
4. Do not add scientific/domain/persistence/networking/orchestration/GUI implementation to a retained shim.
5. Do not delete or semantically rewrite a retained shim as routine cleanup.
6. Compatibility removal requires a separate compatibility-breaking plan.
7. A removal/rewrite plan must consider, as applicable:
   - historical import paths;
   - module/class/function identity;
   - `pickle` globals;
   - monkeypatch/substitution paths;
   - standalone CLI behavior;
   - source-checkout behavior;
   - upgrade and rollback strategy.
8. `REMOVE_CANDIDATE = 0` at R515. Do not infer that a retained surface is safe to delete because it looks trivial.

---

## 9. Scientific, temporal, and coordinate correctness

Structural changes and scientific behavior changes are different risk classes.

1. Do not combine a structural refactor with a scientific-model change unless the batch explicitly requires both and qualification isolates both effects.
2. Reuse the current authoritative policy/model for ephemerides, time scales, epochs, coordinate frames, photometric geometry, catalogue semantics, calibration, and N-body behavior.
3. Make units, epochs, coordinate frames, and time scales explicit at boundaries where ambiguity is possible.
4. Do not replace a qualified scientific implementation with a local approximation merely to simplify dependencies.
5. Preserve immutable operation inputs for asynchronous scientific work so later GUI/configuration changes cannot mutate an in-flight calculation.
6. When a scientific result intentionally changes, add direct reference-data, before/after, or invariant tests. GUI appearance alone is not scientific qualification.
7. Keep behavior-neutral architecture refactors byte/behavior neutral where that is the stated scope.

---

## 10. State, side effects, persistence, and workers

1. Prefer typed and immutable contracts across module, thread, process, worker, and persistence boundaries.
2. Keep I/O/external effects in infrastructure or explicit workflow boundaries rather than numerical helpers.
3. Use atomic replacement for persistent files where partial writes could corrupt state.
4. Preserve operation identity, generation, cancellation, stale-result rejection, and commit semantics in background work.
5. Failed or cancelled work must not silently commit partial GUI or persistent state.
6. Do not introduce hidden global caches to bypass explicit repository/cache/service contracts.
7. Long-running I/O or scientific work must not be moved to the GUI thread for convenience.
8. Widgets should orchestrate and present; scientific algorithms and durable persistence rules belong below the widget layer.

---

## 11. GUI qualification policy

1. `kopr.core` remains Qt-free.
2. A GUI change must be qualified at the level of risk it introduces: headless/unit, Qt offscreen, and/or real native Qt lifecycle.
3. A headless host must not claim native GUI PASS when a usable native PyQt/PySide runtime was not available.
4. If native GUI qualification cannot execute because the host lacks the required runtime, report **HOLD**, not PASS.
5. Do not convert an environment HOLD into a code workaround that changes product architecture merely to make the test host happy.

R515 final closure truthfully ended with native GUI `HOLD (PyQt5 unavailable)` while all headless closure requirements passed. Future GUI changes that specifically require native behavior must be qualified on a capable host before that native behavior can be claimed as qualified.

---

## 12. Required development workflow and batching

### 12.1 Before editing

1. Start from the latest qualified canonical build, never a historical hybrid/migration build.
2. Read this policy and the current `tools/architecture/architecture_policy.json`.
3. Identify the canonical owner under `src/kopr/`.
4. Run:

   ```bash
   python3 tools/architecture/architecture_guard.py
   ```

5. Classify the work as one or more of:
   - behavior-neutral structural change;
   - bug fix;
   - user-visible behavior change;
   - scientific behavior change;
   - GUI/runtime change;
   - packaging/entry-point change;
   - compatibility-breaking change.
6. Identify focused tests and the required regression/GUI/package qualification before implementation.

### 12.2 Batch discipline

For non-trivial work, use bounded coherent batches.

1. A batch should be large enough to complete one coherent capability/change safely, not artificially one-line-at-a-time.
2. Do not mix unrelated cleanup into the batch.
3. If unexpected dependency, path, global-state, monkeypatch, Qt, multiprocessing, serialization, compatibility, or scientific coupling appears and requires a complex solution, **stop expanding the current batch**.
4. Re-plan the remaining work into new bounded batches rather than introducing a shortcut or architecture exception.
5. Report the complication and the revised plan before continuing into the next complex batch.

### 12.3 During implementation

1. Keep one canonical implementation.
2. Preserve dependency direction.
3. Use explicit contracts rather than import-order/global-state coupling.
4. Do not weaken the architecture guard or compatibility policy to make the batch pass.
5. Keep structural and behavioral effects separable unless both are explicitly part of the batch.

### 12.4 After implementation

At minimum:

1. rerun `python3 tools/architecture/architecture_guard.py`;
2. run focused tests for the changed capability;
3. run broader regression appropriate to the risk;
4. if production Python/import topology changed, run architecture mutation qualification and the current frozen structural regression profile (or its qualified successor);
5. preserve CLEAN/QA production Python parity when producing CLEAN/QA artifacts;
6. qualify wheel/source and installed-package behavior when packaging or canonical package contents are affected;
7. run source-checkout launcher qualification when launcher/import bootstrapping is affected;
8. run Qt/offscreen/native GUI qualification when GUI behavior requires it;
9. update current developer/architecture documentation when ownership, public API, compatibility perimeter, entrypoint, or layer policy changes;
10. re-extract/retest release archives when producing a release artifact, so qualification applies to the archive content, not only to the working directory;
11. when producing a qualified product-code release, advance the numeric revision within the current Greek release series and verify all user-facing version displays against `kopr.config.release_identity`; change the Greek series only on explicit project-owner instruction.

Host/test-wrapper failures must be diagnosed without weakening the contract. If necessary, preserve the exact node set and run process-isolated/bounded executions; do not silently drop tests.

---

## 13. Architecture exception procedure

An architecture exception is not a normal implementation detail.

Before changing an architecture budget, allowlist, layer rule, compatibility target, or other invariant, document:

1. the concrete dependency/behavior that cannot fit the current structure;
2. alternatives considered;
3. why moving ownership, defining a public API, or dependency injection is insufficient;
4. expected new import edges/coupling;
5. scientific, GUI, persistence, packaging, and compatibility risks;
6. focused and regression qualification;
7. rollback/removal path;
8. whether the exception is temporary or becomes a new explicit architecture rule.

Only then may machine-readable architecture policy be changed. The change must be explicit in the release report and this normative document must be updated if the architecture contract itself changed.

Never silently normalize a violation by editing the expected snapshot.

---

## 14. QA, tooling, and history policy

1. Do not recreate active `tools/migration/`.
2. Do not recreate a release-numbered migration helper/gate chain merely to prove historical migration stages.
3. Current capability tooling belongs under stable paths such as `tools/qa/` and `tools/architecture/`.
4. Current retained tests should validate current product/capability contracts, not historical filenames, historical documentation wording, old release numbers, or obsolete source layouts.
5. A release-numbered test filename may remain only if it directly validates a still-current capability contract; its filename is not permission to rebuild migration-era test chains.
6. Historical migration reports, retired tests, per-batch evidence, and transform specs belong outside active CLEAN/QA builds in explicit history archives.
7. Release archives must not contain cache/build debris such as `__pycache__`, `.pyc`, `.pytest_cache`, `build/`, or egg-info unless explicitly required by packaging mechanics and qualified.
8. CLEAN contains product/runtime plus current developer tooling/docs required for development; QA may add current tests and current QA tooling, while production Python must remain parity-identical between CLEAN and QA.

---

## 15. Qualification by risk class

The exact current regression profile is machine-readable and may evolve, but use the following minimum logic.

### A. Documentation-only change

- verify documentation consistency;
- run architecture/documentation checks if paths/ownership wording is touched;
- no product behavior claim may be made without product qualification.

### B. Local bug fix or feature with unchanged architecture

- architecture guard before/after;
- focused capability tests;
- relevant subsystem regression;
- GUI/scientific qualification if the behavior touches those domains.

### C. Structural/import/ownership/package change

- architecture guard before/after;
- focused ownership/capability tests;
- architecture mutation qualification;
- current frozen regression profile or qualified successor;
- CLEAN/QA production parity for release artifacts;
- wheel/source and installed-package qualification if packaging is affected;
- source-launcher qualification when applicable.

### D. Scientific behavior change

Everything from the applicable structural/runtime class plus:

- direct reference/invariant tests for the changed scientific contract;
- explicit units/time-scale/epoch/frame validation where relevant;
- comparison against prior behavior and/or authoritative reference data where appropriate.

### E. GUI behavior change

Everything from the applicable runtime class plus:

- focused GUI tests;
- offscreen Qt qualification when useful;
- native GUI qualification on a capable host when native lifecycle/rendering/input behavior is part of the claim.

### F. Compatibility-breaking change

Everything from the applicable classes plus:

- explicit compatibility-break plan;
- affected identity/pickle/import/CLI/monkeypatch/source-checkout probes;
- upgrade and rollback strategy;
- compatibility perimeter and contracts updated intentionally.

---

## 16. Code-review checklist

Before accepting a production change, verify:

- [ ] Work started from the latest qualified canonical baseline, not a migration-era/hybrid tree.
- [ ] New implementation is under `src/kopr/`.
- [ ] Root compatibility files remain non-owning.
- [ ] Canonical ownership is unambiguous; there is no duplicate active implementation.
- [ ] `src/kopr` imports no flat-root KOPR module.
- [ ] Root-to-root import edges remain zero.
- [ ] No new SCC/cycle exists in `src/kopr`.
- [ ] Layer direction follows this policy and the current architecture guard.
- [ ] No generic catch-all module was added.
- [ ] No wildcard package/compatibility import was introduced.
- [ ] Public cross-feature use goes through an intentional API boundary.
- [ ] Compatibility shims were not removed, repurposed, or retargeted without an explicit plan.
- [ ] Source-checkout launcher/bootstrap behavior was not broadened casually.
- [ ] Scientific/time/epoch/frame behavior is unchanged unless intentionally specified and directly tested.
- [ ] GUI/worker/cancellation/stale-result semantics are preserved unless intentionally changed and qualified.
- [ ] Persistence writes and side effects remain safe/atomic where required.
- [ ] Architecture guard passes with zero violations.
- [ ] Focused tests pass.
- [ ] Required broader regression/package/GUI/scientific gates pass for the risk class.
- [ ] CLEAN/QA parity is preserved when release artifacts are produced.
- [ ] Documentation and machine-readable contracts are updated together when ownership/API/compatibility rules change.
- [ ] For a qualified product-code release, the public `KOPR Live <GreekSeries>-<Revision>` identity is updated centrally, the revision is monotonic within the current series, and the Greek series has not changed without explicit project-owner instruction.

---

## 17. Forbidden regressions to the pre-R515 hybrid state

The following are specifically forbidden:

- treating a flat-root implementation module as the natural owner of new behavior;
- recreating partial root facades with real implementation;
- using root modules as shared helpers for canonical modules;
- importing root compatibility paths from `src/kopr`;
- recreating `_kopr_src_bootstrap.py`;
- recreating active `tools/migration/` infrastructure;
- using historical release plans as architecture requirements;
- copying canonical logic back into shims to preserve monkeypatch behavior;
- accepting duplicate implementation because tests pass;
- declaring a hybrid state "complete" merely because regression tests pass.

If a proposed change would cause any of these outcomes, redesign the change.

---

## 18. Rule for future major refactoring

Future refactoring starts from the **fully canonical current architecture**, not from the old migration sequence.

The objective of a refactor is to improve or extend the canonical design while preserving the hard invariants, not to replay prior migration steps.

If a major redesign intentionally changes those invariants, treat it as a new architecture project with an explicit target contract, staged qualification, compatibility plan, rollback path, and updated normative policy. Until such a redesign is explicitly approved and qualified, the final R515 canonical model described here remains the required development foundation.

---

## 19. Short mandatory rule set for coding agents

Before changing KOPR production code, a coding agent must follow these rules:

1. Read this document and current `tools/architecture/architecture_policy.json`.
2. Run `python3 tools/architecture/architecture_guard.py` before and after the change.
3. Put all new implementation under `src/kopr/`.
4. Never add implementation to flat-root compatibility files.
5. Never import flat-root KOPR modules from `src/kopr/`.
6. Keep one canonical owner and zero canonical SCCs.
7. Respect package-layer directions and intentional public APIs.
8. Do not create generic catch-all modules or wildcard package APIs.
9. Do not weaken guard budgets/allowlists to hide coupling.
10. Separate structural work from scientific/user-visible changes unless explicitly planned and qualified together.
11. Preserve compatibility surfaces unless an explicit compatibility-breaking batch proves their safe revision/removal.
12. For complex work, proceed in coherent bounded batches; if unexpected complex coupling appears, re-plan instead of bypassing architecture rules.
13. Run risk-appropriate focused/regression/package/GUI/scientific qualification.
14. Never use historical hybrid/migration layouts as the desired implementation state.
15. Keep the public release label centralized in `kopr.config.release_identity`; for qualified product-code releases increment only the numeric revision within the current Greek series, and never change the Greek series without explicit project-owner instruction.

