This document defines the rules that govern how this project is built and how the AI assistant collaborates on it.
It exists to prevent scope creep, maintain architectural integrity, and ensure every decision is intentional.
No code is written until the architecture is approved. No architecture changes are made without updating ARCHITECTURE.md first.
Build one module completely before starting the next. Complete means: coded, tested, reviewed, documented, committed.
Every module goes through this sequence:
- Purpose explained
- Interface designed
- Trade-offs discussed
- Implementation written
- Reviewed
- Tested
- Documentation updated
- Git commit message provided
Every module gets unit tests before the next module begins. Tests are written alongside code, not after everything is built.
CHANGELOG.md, ARCHITECTURE.md, and Memory.md are updated after every completed module. Documentation is never left until the end.
If a feature is not listed in PRD.md it does not get built. Any new feature requires a PRD.md update and explicit approval first.
Do not build what is not needed yet. Do not add abstractions for hypothetical future requirements. Build for V3.0.0. Think about V3.1.0 later.
Every completed module gets a Git commit. Commit messages follow the conventional commits format.
Work iteratively, one module at a time. Do not jump ahead without approval.
If a design decision is questionable, say so. Explain why and suggest a better alternative. Do not silently implement bad architecture to be agreeable.
If requirements are unclear, ask. Do not invent features or behaviors that were not specified.
Once a design decision is approved, implement it as approved. Do not quietly change architecture mid-implementation.
After every module, Memory.md is updated with current progress. This ensures context is preserved across sessions.
If a request would add something outside PRD.md, flag it. Do not silently expand scope.
If the easy solution creates technical debt, say so. Recommend the maintainable solution even if it takes longer.
- Python Standard Library (all modules)
- Tkinter (UI only)
- pytest (testing)
- logging (logging only)
- PyInstaller (packaging only, not imported in code)
- PyQt, Kivy, or any non-Tkinter UI framework
- Third-party analysis libraries
- Third-party testing frameworks (pytest is acceptable if explicitly approved)
- Any library that creates unnecessary external dependencies
If a library is not in the allowed list above, it requires explicit approval before use.
No module prints directly except run.py startup messages. All output is returned as structured objects.
exit() is never used for flow control. Validation returns ValidationResult. The UI decides what to do with errors.
UI code collects input and displays output only. Zero analysis logic lives in app.py, input_view.py, or result_view.py.
All thresholds and limits live in core/config.py. No hardcoded numeric values anywhere else.
Use logging.getLogger(name) in every module. Never use print() for debugging or diagnostics.
Add type hints where they improve clarity. Do not add type hints that make simple code harder to read.
Every module, class, and public function gets a docstring. Docstrings explain purpose, not implementation details.
- Caught by the validation layer
- Returned as ValidationResult with is_valid=False
- Displayed as ERROR severity cards in the UI
- Never crash the application
- Caught by the controller
- Logged using the logger
- Returned as ControllerResult with success=False
- Displayed as a generic friendly error message
- Never expose stack traces to the user
- Never let the application crash on user input
- Never show raw exception messages to the user
- Never use bare except clauses
- Never silence exceptions without logging them
Every module has exactly one reason to exist. If a module is doing two things, split it.
Dependencies flow downward only.
UI ↓ Controller ↓ Validation / Analyzer Engine ↓ Rules / Weapons ↓ Models ↓ Core
No lower layer imports from a higher layer. Models never import from UI. Rules never import from the controller.
Configuration is a frozen dataclass. PlayerStats and Metrics are not mutated after creation. Analysis never modifies its input data.
Every layer returns a typed object. No layer returns raw strings as its primary output. No layer returns None when a result object is expected.
- Not a data science project
- Not a machine learning project
- Not a web application
- Not a multiplayer tool
- Not a database application
- Not a commercial product
It is a portfolio-quality desktop application that demonstrates clean software engineering on a focused, well-understood problem.
If any rule is violated during development:
- Stop immediately
- Identify which rule was violated
- Understand why it was violated
- Fix it before continuing
- Update Memory.md to note what happened
Rules exist to protect the project from shortcuts that create long-term problems.
This document governs how Playlytics V3 is built. It is not optional and not negotiable.