# 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: ```text .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 40–60 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: ```text 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: ```text 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: ```text input + configuration + source data ``` Periscope must produce the same: ```text 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: ```text SOURCE ↓ STRUCTURED REQUIREMENT ↓ DETERMINISTIC ANALYZER ↓ FINDING ↓ OPTIONAL LLM EXPLANATION ``` Not: ```text SOURCE ↓ LLM ↓ probably wrong ``` --- # 9. EVIDENCE BEFORE CONCLUSION Every engineering conclusion must be traceable to evidence. Where applicable, preserve: ```text 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: ```text MANDATORY RECOMMENDED TYPICAL EXAMPLE ENGINEERING_INFERENCE ``` Do not convert: ```text RECOMMENDED ``` into: ```text 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: ```text severity confidence ``` Examples that are valid: ```text 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: ```text 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: ```text 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: ```text PCB Via ``` must never become: ```text 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: ```text 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: ```text 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: ```text source → parser → normalized representation → semantic model → analyzer → finding → report ``` --- # 16. NO COMPONENT-SPECIFIC HACKS Do not fix architecture problems with: ```text if component == U1 ``` or: ```text if footprint == X ``` or: ```text if net == GND ``` or hard-coded corrections such as: ```text 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: ```text Via located inside footprint ``` does not imply: ```text 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: ```text width_mm delay_ns frequency_hz voltage_v current_a temperature_c ``` over ambiguous variables such as: ```text width delay value limit ``` when unit ambiguity is possible. Never rely on undocumented implicit units. --- # 19. NAMED CONSTANTS Avoid magic numbers. Prefer: ```text 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: ```text 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: ```text normal case failure case boundary case insufficient evidence ``` For semantic models, also test the boundaries between object types. For PCB analysis, explicitly test: ```text 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: ```text result is reasonable result is not empty analysis completed ``` when an exact result can be established. Prefer assertions such as: ```text 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: ```text 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: ```text valid → pass ``` Also test: ```text invalid → fail ``` and ensure that genuine errors remain detectable. For example, if fixing: ```text 24 datasheet pins 24 footprint pads N vias ``` verify that: ```text 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**: ```text implement → test → fix → test ``` The repository may contain intermediate working-tree changes. At the **end of each phase**, after tests pass: ```text 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: ```text 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: ```text 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: ```text 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: ```text 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: ```text 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: ```text WHY ``` rather than simply: ```text 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: ```text documented requirement datasheet/source evidence standard explicit design intent validated engineering inference ``` If evidence is insufficient: ```text 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: ```text INTENTIONAL_DESIGN ``` when the evidence supports that interpretation. The system must distinguish: ```text actual violation intentional design engineering observation insufficient evidence ``` --- # 44. FINDING CATEGORIES Findings may include: ```text 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: ```text 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: ```text 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.**