Files
periscope/docs/development/CODING_CONSTITUTION.md
T
michele 2f2e35e802 Replace paraphrased constitution with the 1224-line master.
Copy CODING_CONSTITUTION.md from the AgentStore docs/development path and split
the seven always-on .mdc files from that exact text.
2026-09-20 18:24:29 +02:00

19 KiB
Raw Blame History

PERISCOPE — CURSOR ENGINEERING RULES

PURPOSE

This document defines the mandatory engineering rules for the Periscope project.

These rules are not suggestions.

They define:

  • repository structure;
  • coding standards;
  • architectural principles;
  • semantic modeling rules;
  • Python/Rust language policy;
  • testing requirements;
  • verification requirements;
  • Git workflow;
  • commit/push/deployment policy;
  • development-phase discipline.

Cursor must treat these rules as mandatory project constraints.

If an implementation conflicts with these rules, the implementation must be changed.

Do not silently relax, bypass, reinterpret, or ignore these rules.


1. CREATE THE PROJECT RULE STRUCTURE

Create and maintain the following structure:

.cursor/
└── rules/
    ├── 00-coding-constitution.mdc
    ├── 10-architecture.mdc
    ├── 20-python.mdc
    ├── 30-rust.mdc
    ├── 40-testing.mdc
    ├── 50-verification.mdc
    └── 60-git-workflow.mdc

docs/
└── development/
    └── CODING_CONSTITUTION.md

The Markdown document is the human-readable master document.

The .mdc files are the operational Cursor rules.

The rules must be version-controlled with the project.

Do not create contradictory rules in different files.

If a conflict exists, resolve the conflict explicitly before continuing development.


2. CORE PRINCIPLE

CODE THAT FITS IN YOUR HEAD

This is the fundamental Periscope engineering principle.

Code must be locally understandable by an engineer without requiring reconstruction of a large hidden abstraction system.

Prefer:

  • small modules;
  • small functions;
  • one responsibility;
  • explicit dependencies;
  • explicit data flow;
  • simple data structures;
  • precise names;
  • deterministic behavior;
  • minimal public APIs;
  • composition over inheritance.

Avoid:

  • huge functions;
  • god classes;
  • deep inheritance;
  • speculative abstractions;
  • hidden state;
  • magic behavior;
  • global mutable state;
  • unnecessary frameworks;
  • premature optimization;
  • unnecessary indirection.

A function around 4060 lines is a warning signal, not an absolute limit.

The actual rule is local comprehensibility.

A 20-line function can violate the rule if it contains too many responsibilities.

A longer function may be acceptable if its structure remains obvious and justified.


3. ONE RESPONSIBILITY

Every function and module must have one primary responsibility.

Prefer:

parse
    ↓
normalize
    ↓
build model
    ↓
analyze
    ↓
produce finding
    ↓
report

Avoid a single function that:

  • parses input;
  • modifies the model;
  • performs analysis;
  • accesses external services;
  • formats output;
  • writes files;
  • handles errors;
  • and generates reports.

Separate responsibilities.


4. EXPLICIT DATA FLOW

Periscope must have explicit data flow.

Prefer:

SOURCE
  ↓
PARSER
  ↓
NORMALIZED MODEL
  ↓
ANALYZER
  ↓
FINDING
  ↓
REPORT

Avoid hidden communication through:

  • global variables;
  • singleton state;
  • implicit registries;
  • hidden caches;
  • ambient configuration;
  • side effects;
  • undocumented environment state.

If a function needs important information, that information must be visible in its inputs or clearly owned state.


5. NO SPECULATIVE ABSTRACTION

Do not introduce an abstraction merely because it might become useful later.

Do not create unnecessary:

  • factories;
  • generic managers;
  • service layers;
  • repository layers;
  • plugin systems;
  • inheritance hierarchies;
  • generic object wrappers;
  • framework-like internal infrastructure.

Implement the actual requirement first.

Abstract only when there is a concrete and demonstrated reason.


6. COMPOSITION OVER INHERITANCE

Prefer composition.

Avoid deep class hierarchies.

Inheritance must have a clear semantic reason.

Do not use inheritance merely to share a few methods.


7. DETERMINISTIC CORE

The verification core must be deterministic.

For the same:

input
+
configuration
+
source data

Periscope must produce the same:

model
calculations
findings

Do not make deterministic verification dependent on:

  • LLM output;
  • prompts;
  • randomness;
  • execution order;
  • hidden state;
  • uncontrolled external state.

8. LLM ROLE

LLMs may be used for:

  • extraction;
  • classification;
  • datasheet interpretation;
  • explanation;
  • hypothesis generation;
  • assistance.

LLMs must not be the authoritative deterministic verification engine.

The intended architecture is:

SOURCE
  ↓
STRUCTURED REQUIREMENT
  ↓
DETERMINISTIC ANALYZER
  ↓
FINDING
  ↓
OPTIONAL LLM EXPLANATION

Not:

SOURCE
  ↓
LLM
  ↓
probably wrong

9. EVIDENCE BEFORE CONCLUSION

Every engineering conclusion must be traceable to evidence.

Where applicable, preserve:

observed fact
requirement
source
calculation
assumption
conclusion
confidence
severity

Do not silently transform assumptions into facts.


10. REQUIREMENT STRENGTH

Requirements must preserve their strength.

Use:

MANDATORY
RECOMMENDED
TYPICAL
EXAMPLE
ENGINEERING_INFERENCE

Do not convert:

RECOMMENDED

into:

MANDATORY

Do not convert an example into an absolute rule.

Do not convert an engineering inference into documented manufacturer information.


11. SEVERITY AND CONFIDENCE ARE INDEPENDENT

A finding must be able to represent independent:

severity
confidence

Examples that are valid:

ERROR + LOW confidence
RISK + HIGH confidence

Do not use confidence as a substitute for severity.


12. INSUFFICIENT EVIDENCE

If the available information is insufficient to establish a conclusion:

INSUFFICIENT_EVIDENCE

must be used.

Never invent missing engineering information.

Never invent:

  • electrical limits;
  • timing values;
  • pin functions;
  • voltages;
  • currents;
  • tolerances;
  • PCB rules;
  • thermal limits;
  • datasheet requirements.

Missing evidence is not permission to guess.


13. SEMANTIC MODEL FIRST

Periscope must preserve domain semantics.

At minimum, distinguish concepts such as:

Project
Component
Pin
Footprint
Pad
Net
Via
Track
Zone
PowerRail
SignalGroup
TimingEvent
Requirement
Constraint
DesignIntent
Evidence
Finding

Do not collapse semantically different physical objects into one generic object merely because they share coordinates, nets, or attributes.


14. SEMANTIC IDENTITY MUST SURVIVE TRANSFORMATIONS

A transformation must preserve the semantic identity of objects.

For example:

PCB Via

must never become:

Component Pad

merely because:

  • it is close to a footprint;
  • it is inside a footprint area;
  • it is connected to GND;
  • it shares a net;
  • it has coordinates similar to a pad.

Similarly:

Pad ≠ Via
Track ≠ Via
Zone ≠ Pad
Component Pin ≠ PCB Via

This is a fundamental Periscope rule.


15. ROOT CAUSE OVER SYMPTOM

When a false positive or incorrect result is discovered:

Do not simply suppress the finding.

Determine where the representation first becomes incorrect.

Example:

PCB
 ↓
parser
 ↓
incorrect model
 ↓
correct analyzer operating on incorrect model
 ↓
incorrect finding

The fix belongs in the model/parser boundary, not necessarily in the analyzer.

Always investigate the complete chain:

source
→ parser
→ normalized representation
→ semantic model
→ analyzer
→ finding
→ report

16. NO COMPONENT-SPECIFIC HACKS

Do not fix architecture problems with:

if component == U1

or:

if footprint == X

or:

if net == GND

or hard-coded corrections such as:

subtract N
ignore N
force expected count

unless the condition represents a genuine documented engineering rule.

A bug in generic PCB semantics must receive a generic semantic fix.


17. PHYSICAL SEMANTICS

Periscope is an electronic design verification system.

Its internal model must reflect physical reality.

Geometric proximity does not establish semantic identity.

For example:

Via located inside footprint

does not imply:

Via belongs to component as a pad

unless the PCB data model explicitly establishes that relationship.

Do not infer component relationships solely from proximity when stronger source information exists.


18. UNITS MUST BE EXPLICIT

Use explicit units.

Prefer:

width_mm
delay_ns
frequency_hz
voltage_v
current_a
temperature_c

over ambiguous variables such as:

width
delay
value
limit

when unit ambiguity is possible.

Never rely on undocumented implicit units.


19. NAMED CONSTANTS

Avoid magic numbers.

Prefer:

MIN_SUPPLY_V
MAX_TRACE_LENGTH_MM
DEFAULT_SPI_CLOCK_HZ

over unexplained numeric literals.

Engineering constants must have traceable sources where appropriate.


20. ERROR CATEGORIES

Distinguish:

tool failure
data failure
analysis result
insufficient evidence
engineering violation

Do not collapse fundamentally different failure modes into one generic error.


21. TESTING IS MANDATORY

Every meaningful implementation change requires tests.

At minimum test:

normal case
failure case
boundary case
insufficient evidence

For semantic models, also test the boundaries between object types.

For PCB analysis, explicitly test:

Pad
Via
Track
Zone

as distinct semantic entities.


22. TESTS MUST BE STRICT AND ABSOLUTE

Periscope tests are not advisory.

A test must define the exact expected behavior.

Do not use vague assertions such as:

result is reasonable
result is not empty
analysis completed

when an exact result can be established.

Prefer assertions such as:

expected object type == Via
expected pad count == 24
expected finding count == 0
expected finding code == X
expected severity == ERROR
expected confidence == HIGH

Where deterministic exact values are available, test them exactly.

Do not weaken tests merely to make an implementation pass.

Do not modify expected results to accommodate incorrect implementation behavior.


23. REGRESSION TEST FOR EVERY BUG

Every fixed bug must become a regression test.

Required sequence:

BUG
 ↓
REPRODUCE
 ↓
TEST FAILS
 ↓
FIX
 ↓
TEST PASSES
 ↓
FULL REGRESSION

A bug fix is not complete until the original failure is permanently represented by a test.


24. TEST THE NEGATIVE CASE

Do not test only:

valid → pass

Also test:

invalid → fail

and ensure that genuine errors remain detectable.

For example, if fixing:

24 datasheet pins
24 footprint pads
N vias

verify that:

24 datasheet pins
23 footprint pads

still produces a real mismatch.

The fix must remove false positives without suppressing true positives.


25. PHASE GATES

Development is divided into macro-phases.

A macro-phase is not complete until:

  1. implementation is complete;
  2. all required tests exist;
  3. all required tests pass;
  4. full regression passes;
  5. relevant integration tests pass;
  6. static/type/lint checks pass where applicable;
  7. no known blocker remains;
  8. documentation is updated;
  9. results have been reviewed;
  10. the phase acceptance criteria are satisfied.

Only then is the macro-phase considered complete.


26. NO WEAKENING TESTS TO CLOSE A PHASE

Do not:

  • delete failing tests;
  • weaken assertions;
  • skip tests;
  • mark tests expected-to-fail;
  • suppress failures;
  • change expected values without engineering justification;

simply to make a macro-phase pass.

If a test exposes a real implementation problem, fix the implementation.

If the requirement itself is wrong, change the requirement explicitly and document why.


27. PHASE COMMIT AND PUSH POLICY

Do not commit after every small implementation step merely for convenience.

During a phase:

implement
→ test
→ fix
→ test

The repository may contain intermediate working-tree changes.

At the end of each phase, after tests pass:

PHASE TESTS
        ↓
COMMIT
        ↓
PUSH

Commit and push belong to the phase boundary, not to every edit.

Do not push broken or half-completed phase work merely to synchronize the repository.


28. MACRO-PHASE DEPLOY POLICY

Deploy happens only after a macro-phase, not after every phase.

A macro-phase may contain several phases (each already committed and pushed after its tests).

Never deploy an incomplete macro-phase.

Required sequence for a macro-phase:

PHASES (each: implement → test → commit → push)
 ↓
FULL REGRESSION
 ↓
MACRO-PHASE ACCEPTANCE
 ↓
DEPLOY
 ↓
POST-DEPLOY VERIFICATION

If deployment verification fails, stop and investigate.


29. NO DEPLOY AT PHASE BOUNDARY

Commit + push after phase tests: yes.

Deploy after a phase that is not a completed macro-phase: no.


30. NO AUTOMATIC COMMIT/PUSH/DEPLOY DURING DEVELOPMENT

Cursor must not create commits, push, or deploy merely because a small task has finished.

Commit and push are phase-boundary operations (after tests).

Deploy is a macro-phase-boundary operation.

If explicitly instructed to deploy before a macro-phase is complete, Cursor must identify the conflict with this policy rather than silently proceeding.


31. GIT HISTORY IS ENGINEERING EVIDENCE

Do not rewrite Git history casually.

Do not:

  • force-push;
  • squash history;
  • rewrite commits;
  • detach repository history;

unless explicitly required by the project phase and explicitly authorized.

Git history may be relevant to provenance and licensing analysis.

Preserve it.


32. PYTHON IS THE DEFAULT LANGUAGE

Python is the default implementation language for Periscope.

Use Python for:

  • orchestration;
  • datasheet processing;
  • document parsing;
  • LLM integration;
  • requirement extraction;
  • evidence management;
  • project management;
  • CLI;
  • API integration;
  • reporting;
  • test orchestration;
  • external tool integration;
  • high-level analysis.

Do not rewrite Python into Rust merely because Rust exists in the project.


33. RUST IS NOT A DEFAULT

Rust must not be introduced simply because code is new.

Rust is justified only when there is a demonstrated engineering requirement.

Valid reasons include:

  • measured performance bottleneck;
  • computationally intensive geometry;
  • large-scale spatial processing;
  • numerical computation;
  • graph processing;
  • memory pressure;
  • deterministic high-performance computation.

Do not use Rust speculatively.


34. MEASURE BEFORE MOVING TO RUST

Required sequence:

correct implementation
 ↓
measurement
 ↓
profiling
 ↓
identified bottleneck
 ↓
Rust implementation
 ↓
benchmark
 ↓
accept/reject based on evidence

Do not introduce Rust based on assumptions about performance.


35. RUST BOUNDARIES MUST BE COARSE-GRAINED

Prefer:

Python
   ↓
structured input
   ↓
Rust engine
   ↓
structured result
   ↓
Python

Avoid excessive Python ↔ Rust calls for individual operations.

Rust should encapsulate meaningful computational workloads.


36. DO NOT PREMATURELY FREEZE THE CORE IN RUST

The semantic model should first become correct and well understood.

Prefer:

semantic model
 ↓
correctness
 ↓
tests
 ↓
architecture stabilization
 ↓
profiling
 ↓
Rust where justified

Do not rewrite the entire Periscope core in Rust simply to establish a Rust architecture.


37. CORRECTNESS BEFORE PERFORMANCE

Priority order:

1. Correctness
2. Semantic integrity
3. Determinism
4. Testability
5. Readability
6. Maintainability
7. Performance
8. Optimization

Performance optimization must not compromise the first six without explicit justification.


38. MINIMAL PUBLIC APIs

Public APIs must be as small as practical.

Do not expose internal implementation details unnecessarily.

Prefer explicit interfaces.

Avoid API surface growth without a real requirement.


39. NO DEAD CODE

Remove or explicitly document:

  • obsolete code;
  • commented-out implementations;
  • unused imports;
  • unused abstractions;
  • obsolete APIs;
  • temporary workarounds.

Temporary adapters must be clearly identified and have a removal path.


40. COMMENTS

Comments should explain:

WHY

rather than simply:

WHAT

Do not comment obvious code.

Do document:

  • non-obvious engineering decisions;
  • semantic constraints;
  • source-specific behavior;
  • intentional limitations;
  • reasons for unusual algorithms;
  • compatibility constraints.

41. CHANGE MINIMIZATION

For bug fixes:

  1. reproduce the problem;
  2. locate root cause;
  3. change the smallest appropriate architectural layer;
  4. add regression test;
  5. run relevant tests;
  6. run full regression;
  7. review the resulting design.

Do not combine unrelated refactoring with a bug fix unless necessary.


42. NO SPECULATIVE ENGINEERING

Do not invent engineering rules.

Every rule should be based on one of:

documented requirement
datasheet/source evidence
standard
explicit design intent
validated engineering inference

If evidence is insufficient:

INSUFFICIENT_EVIDENCE

43. DESIGN INTENT IS FIRST-CLASS

Do not assume that every unusual design decision is an error.

Periscope must be able to represent:

INTENTIONAL_DESIGN

when the evidence supports that interpretation.

The system must distinguish:

actual violation
intentional design
engineering observation
insufficient evidence

44. FINDING CATEGORIES

Findings may include:

ERROR
RISK
REFERENCE_DEVIATION
ENGINEERING_OBSERVATION
INTENTIONAL_DESIGN
INSUFFICIENT_EVIDENCE

Do not collapse all deviations into ERROR.

Severity and confidence remain independent.


45. REVIEW QUESTIONS BEFORE COMPLETING ANY CHANGE

Before declaring a change complete, Cursor must verify:

Is the implementation correct?

Is the root cause fixed?

Is the semantic model correct?

Is the data flow explicit?

Can the code fit in my head?

Is any abstraction unnecessary?

Is there hidden state?

Are units explicit?

Are engineering constants named?

Are assumptions distinguished from facts?

Are tests strict?

Are negative cases tested?

Are boundary cases tested?

Is insufficient evidence tested?

Could this change create a false positive?

Could this change suppress a true positive?

Is the full regression passing?

Is documentation updated?

Is the macro-phase actually complete?

46. FINAL ENGINEERING PRINCIPLE

Periscope must not become a clever software system.

It must become a:

CORRECT
DETERMINISTIC
SEMANTICALLY ACCURATE
TESTABLE
TRACEABLE
READABLE
MAINTAINABLE
ENGINEERING SYSTEM

The preferred implementation is the simplest one that satisfies those properties.

When two implementations are technically correct, prefer the one with:

  • fewer abstractions;
  • fewer dependencies;
  • less hidden state;
  • clearer data flow;
  • smaller modules;
  • smaller APIs;
  • easier testing;
  • easier debugging;
  • clearer semantics.

The governing principle is:

CODE THAT FITS IN YOUR HEAD.

And the governing development discipline is:

NO PHASE IS COMPLETE UNTIL ITS TESTS PROVE IT.

And the governing repository discipline is:

COMMIT AND PUSH AT THE PHASE BOUNDARY AFTER TESTS; DEPLOY ONLY AFTER A MACRO-PHASE.