Code Discipline Protocol
Last Modified: NaN
Code Discipline Protocol
Addendum to Phase 1 Architecture
This protocol applies across all modules as a mandatory methodological overlay. It governs how every line of code is written, generated, reviewed, and accepted throughout the curriculum.
Design Principle
TypeScript is not "JavaScript with optional types." It is a statically typed language that compiles to JavaScript. We treat it as such. Every exercise, every Claude Code generation, every Cursor session operates under TypeScript strict mode — the compiler is your first code reviewer, and it must pass before you even begin your human review.
This means M3 (JS/TS Fundamentals) is restructured: you learn JavaScript's runtime behaviour through TypeScript's type lens, not the other way around. You understand let x = 5 by understanding that TypeScript infers x: number — the dynamic behaviour is the output, not the mental model.
The Five Pillars
1. Strict Typing (Type Hinting → Full Type System)
What this means in practice:
tsconfig.jsonis configured with"strict": truefrom the first exercise in M3. This enables all strict checks simultaneously:noImplicitAny,strictNullChecks,strictFunctionTypes,strictBindCallApply,strictPropertyInitialization,noImplicitThis,alwaysStrict.- Every function has explicit parameter types and return types. No inferred return types on exported functions — ever.
anyis treated as a code smell. When Claude Code or Cursor generatesany, your review must flag and replace it with a proper type,unknown(which forces safe narrowing), or a generic.- Union types and discriminated unions replace loose
string | numberpatterns with explicit, exhaustive alternatives. - In Python (used in M12 for ML): type hints are mandatory on all function signatures, enforced by
mypy --strict.
Review checklist item: "Could the compiler catch a bug here that a human might miss? If the types are loose enough that the answer is no, the types are wrong."
2. Static Analysis Toolchain
The toolchain is non-negotiable and configured before the first line of code in M3:
| Tool | Purpose | When It Runs |
|---|---|---|
TypeScript compiler (tsc --strict) | Type checking | Every save (IDE integration) + pre-commit |
ESLint (with @typescript-eslint) | Code quality, convention enforcement | Every save + pre-commit |
| Prettier | Formatting consistency | Every save (format-on-save) + pre-commit |
| Husky + lint-staged | Pre-commit gate | Every git commit (M2 onward) |
mypy (--strict) | Python type checking (M12 only) | Every save + pre-commit |
| Ruff | Python linting (M12 only) | Every save + pre-commit |
ESLint rules enforced from day one (not gradually introduced):
Review workflow integration: When Claude Code or Cursor generates code, you run the full toolchain before beginning your manual review. If the toolchain passes, you review for logic, architecture, and security. If it fails, you fix the toolchain errors first — they represent the class of bugs you should never need to find manually.
3. Defensive Programming
Core principle: Code must handle the world as it is, not as it should be. Every function boundary is a trust boundary.
Practices enforced throughout:
- Input validation at system boundaries: All external data (API responses, user input, file reads, environment variables) is validated with a runtime schema library before entering your type system. We use Zod for TypeScript — it bridges runtime validation and compile-time types:
- Exhaustive switch statements: TypeScript's
nevertype enforces that all union members are handled. If a new channel is added and you miss a case, the compiler catches it:
- Explicit error handling: No bare
try/catchthat swallows errors. Errors are either typed (custom error classes), propagated with context, or handled with explicit recovery logic. - Null safety:
strictNullChecksmeans the compiler forces you to handlenullandundefined. Combined with optional chaining (?.) and nullish coalescing (??), this eliminates an entire class of runtime errors. - Assertions for invariants: Where the type system can't express a runtime guarantee, use assertion functions:
Review checklist item: "What happens when this function receives unexpected input? If the answer is 'undefined behaviour' or 'silent failure,' the code is incomplete."
4. Naming Conventions
Naming is type information for humans. The convention system below encodes semantic meaning into identifiers so that code reads as close to self-documenting prose as possible.
| Category | Convention | Example | Rationale |
|---|---|---|---|
| Interfaces | PascalCase, noun/adjective | SessionConfig, Sendable | Describes shape or capability |
| Type aliases | PascalCase | ChannelType, MessageId | Distinguishable from runtime values |
| Enums | PascalCase (enum), PascalCase (members) | Channel.WhatsApp | Reads as a qualified constant |
| Classes | PascalCase, noun | GatewayRouter | Describes the entity |
| Functions / methods | camelCase, verb-first | parseMessage(), isValid() | Describes the action |
| Boolean variables | camelCase, is/has/should/can prefix | isConnected, hasMemory | Reads as a predicate |
| Constants | UPPER_SNAKE_CASE | MAX_RETRY_COUNT | Visually distinct as immutable |
| Private members | camelCase (no underscore prefix) | private sessionCache | TypeScript's private keyword is the access control; _ prefix is redundant |
| Generic type params | Descriptive single-word or T prefix | TMessage, TConfig or Input, Output | Readable generics over opaque T, U, V |
| File names | kebab-case.ts | gateway-router.ts | Filesystem-safe, consistent |
| Test files | *.test.ts | gateway-router.test.ts | Co-located, easily grep'd |
Additional conventions:
- No abbreviations unless universally understood (
id,url,api). Writemessage, notmsg. Writeconfiguration, notcfg. Code is read 10x more than it is written. - Collection names are plural:
sessions,messages,channels. Singular for individual items:session,message,channel. - Callback/handler naming:
onMessageReceived,handleSessionExpiry— prefix communicates the trigger pattern.
Review checklist item: "Can I understand what this variable holds and what this function does without reading its implementation? If not, the name is wrong."
5. Interfaces and Abstract Contracts
Core principle: Program to interfaces, not implementations. Define the contract before writing the code.
Practices enforced throughout:
- Interface-first design: Before Claude Code generates an implementation, you define the interface it must satisfy. This is your specification — the AI generates to the contract:
- Abstract base classes for shared behaviour: When multiple implementations share logic, use abstract classes with template methods:
- Dependency inversion: Functions and classes accept interfaces as parameters, not concrete implementations. This makes code testable, replaceable, and reviewable:
- Readonly by default: Use
readonlyon interface properties andReadonly<T>/ReadonlyArray<T>for parameters that shouldn't be mutated. Mutation is opt-in, not the default.
Review checklist item: "Is this component coupled to a specific implementation? Could I swap the dependency without changing this code? If not, an interface is missing."
Unified Review Protocol
Every code review (whether of AI-generated code or your own) follows this checklist, in order:
Gate 1 — Toolchain (Automated)
- TypeScript compiles with zero errors under
strict: true - ESLint passes with zero warnings (warnings are treated as errors)
- Prettier formatting applied
- All tests pass
If Gate 1 fails, do not proceed to Gate 2. Fix toolchain issues first.
Gate 2 — Type Discipline (Manual)
- No
anytypes (or each instance has a documented justification) - All function signatures have explicit parameter and return types
- External data is validated at the boundary (Zod schemas)
- Null/undefined cases are handled explicitly
- Exhaustive pattern matching on unions and enums
Gate 3 — Design Discipline (Manual)
- Names are self-documenting (follow naming conventions)
- Functions depend on interfaces, not concrete implementations
- Mutation is explicit and minimised (
readonlyby default) - Error handling is explicit (no swallowed errors)
- Single Responsibility: each function/class does one thing
Gate 4 — Logic and Architecture (Manual)
- Logical correctness (does it do what it should?)
- Performance (appropriate data structures, no unnecessary work)
- Security (input validation, no secrets in code, principle of least privilege)
- Architectural fit (does this belong here? right abstraction level?)
Operational Instantiation: Clean Code Pipeline
The Four-Gate Unified Review Protocol above is the doctrine; the Clean Code Pipeline TechSpec (CS.AK.LISA.TechSpec.CleanCodePipeline) is its operational instantiation in the Cipher Shinobi repo topology. The pipeline maps each manual gate to a tool-enforced layer:
- Gate 1 — Toolchain (Automated) is enforced at write-time by the Semgrep MCP hook (TechSpec §06 Gate 1) — SAST + SCA + secrets, blocking pre-tool. The TS compiler / ESLint / Prettier portion runs at IDE save and at the pre-push gate.
- Gate 2 — Type Discipline and Gate 3 — Design Discipline run at pre-push as Gate 2a (Qodo Command CLI for test coverage + generation) and Gate 2b (CodeRabbit CLI for logic / style / architecture). These match the manual Type and Design gates above with tool-assisted coverage.
- Gate 4 — Logic and Architecture runs server-side at the GitHub Actions tier (TechSpec §06 Gate 3) plus CODEOWNERS approval from
@the OS core repo(LISA's 2FA'd identity, ratified ADR-3). LISA reviews under her own identity and posts review comments in voice.
Genji and Raiden execute under this pipeline. Genji implements; Raiden verifies. The pipeline's custom Semgrep rules (authored by Gray Fox in Sprint 0) cite this Code Discipline Protocol directly — when this protocol changes, the rules' cite_version SHA256 hashes must be re-validated at Gate 3 to prevent drift (TechSpec §09 Governance Integration + OQ-3 resolution).
For full architecture, repo topology, ADRs, risk register, and migration order, read the TechSpec.
Implications for Curriculum Structure
This protocol does not change the module structure or hour allocations. It changes the methodology within every module:
| Change | Detail |
|---|---|
| M3 reframing | TypeScript-first, not "JS then TS." JavaScript runtime behaviour is taught through the lens of TypeScript's type system. strict: true from exercise one. |
| Toolchain setup in M2/M3 | The static analysis toolchain (ESLint, Prettier, Husky) is configured as part of initialising the LISA Git repo. It becomes infrastructure you maintain, not something bolted on later. |
| Zod introduced in M3 | Runtime validation is taught alongside types as the bridge between TypeScript's compile-time guarantees and runtime reality. |
| Interface-first exercises | In every module from M3 onward, the generate → review → correct workflow begins with you writing the interface/contract, then having Claude Code implement it. Your review verifies conformance. |
| Review protocol in every module | The four-gate checklist above is applied to every exercise. Modules progressively add items to Gates 3 and 4 as your knowledge expands. |
| M12 (ML) applies the same rigour in Python | mypy --strict, Ruff, type hints on all signatures, dataclasses with frozen=True as the Python equivalent of readonly. |
This protocol is a living document. As modules are expanded in Phase 2, specific exercises and examples will demonstrate each pillar in the context of that module's content.