<TypeScriptCodingRules keywords="typescript, executable_specification, design_by_contract, jsdoc, ai_to_ai, structural_anchors, log_driven_development, yagni, ts_native, modern_ts" type="coding-rules" ver="2.0">
  <Mission>
    Canonical rules for writing TypeScript (ES2025+, Node.js native TS) for every execution-agent in the project.

    Goal: turn each created or modified TS file into an «Executable Specification» — a readable, machine-parsable artifact in which intent, contract, and refactor hazards can be recovered from the file alone, without chat history or external documentation.

    Baseline TS rules layer; referenced from task tickets generated by `task-scaffolding`. Domain-specific conventions (React, Node servers, CLI) are NOT covered here; they live as separate directives layered on top.

    **Base axiom:** code will be read, parsed, and modified ONLY by other AI agents and AI IDEs (AI-to-AI ecosystem). Highest values: absolute predictability, semantic density, code introspectability. Comments are agent-authored machine comments — they expose intent, constraints, refactor hazards that code and types do not encode by themselves. English is for code and intent: all keys, methods, JSDoc, and intent comments strictly in English.
  </Mission>

  <Belief_State>
    <Axiom id="AX_NO_TRANSPILE_ONLY_CONSTRUCTS">
      Forbid transpile-only syntax. `enum`, `namespace`, and constructor parameter properties (`constructor(private foo: string)`) are forbidden. Native Node.js supports only type stripping; these constructs require AST-to-JS transforms and reliably fail with `SyntaxError` at runtime.

      Alternatives: string literal unions (`'a' | 'b'`) or `const + as const` instead of `enum`; assign constructor fields explicitly inside the body.
    </Axiom>

    <Axiom id="AX_TRUTHFUL_ENCAPSULATION">
      Truthful encapsulation, not false. Native private fields (`#field`) and the `private` modifier are forbidden. For internal state use `protected` with `_` prefix (`protected _logger`). Omit the `public` modifier.

      `#` blocks reflection and decorators. `private` creates false sense of encapsulation: erased at compile time, misleads readers and runtime tooling. `protected _foo` truthfully reflects runtime behavior and preserves metaprogramming hooks.
    </Axiom>

    <Axiom id="AX_EXPLICIT_CLASS_FIELDS">
      Declare class fields explicitly in the class body. Put `readonly` on the field declaration, not on constructor parameters. Separates state declaration (what the class holds) from initialization signature (how the class is constructed), removes parameter-property magic, improves introspectability.
    </Axiom>

    <Axiom id="AX_MODERN_TS_DENSITY">
      Modern TS/JS is mandatory. Use optional chaining (`?.`), nullish coalescing (`??`), logical assignment (`||=`, `&&=`, `??=`). Avoid verbose `if`-checks. Semantic density reduces visual noise, shrinks the surface for nullable-check bugs, and makes the code recoverable by an agent in one pass.
    </Axiom>

    <Axiom id="AX_TELEOLOGICAL_NAMING">
      A name reflects a goal (teleology), not a pattern (topology). Forbidden semantic-noise names: `Manager`, `Handler`, `Data`, `Info`, `Wrapper`, `do...`, `process...`. Pattern names tell the next agent nothing about business goal. `OrderFulfillmentPipeline` carries intent; `OrderManager` does not.
    </Axiom>

    <Axiom id="AX_VERB_PRECISION">
      Use precise verbs. `retrieve` (not `get`), `verify` (not `check`), `compose` (not `make`). Verbs encode the operation's contract. `get` is ambivalent; `retrieve` implies lookup in an external source with possible failure path.
    </Axiom>

    <Axiom id="AX_CONTRACTUAL_NAMING">
      Method name is a self-contained contract. Method names must be readable as a full contract outside the owner class (`verifyRegistrationData`, not just `validate` inside `UserValidator`). A reading agent often sees a method call without the owner class in focus (import, traceability grep). The name must carry meaning in isolation.
    </Axiom>

    <Axiom id="AX_IMPLEMENTATION_HIDING_IN_PUBLIC">
      Public methods do not leak implementation. Forbidden infrastructure words in public APIs: `Db`, `Sql`, `Http` (exception: serializer layers, where this IS the contract). Leaking transport into a public name breaks Ports & Adapters and binds consumers to a concrete implementation.
    </Axiom>

    <Axiom id="AX_EXACT_SCOPE">
      Deliver exactly what the task and contract demand. No unrequested features, extension points, or optionality. Every extra API surface is a future refactor obligation and a source of drift from the contract.
    </Axiom>

    <Axiom id="AX_NO_PREMATURE_ABSTRACTIONS">
      Forbid premature abstractions. Do not abstract logic that has ONE consumer and ONE concrete realization. Abstraction is justified only by confirmed variance or an explicit second consumer; otherwise it complicates grep and reading without payoff.
    </Axiom>

    <Axiom id="AX_MINIMAL_ERROR_SURFACE">
      Minimal error surface. Handle only reachable errors. Do not defend against states proven impossible by types, preconditions, or invariants. Defense against the impossible is dead code — simulates reliability and obstructs reasoning about real failure paths.
    </Axiom>

    <Axiom id="AX_PRINCIPLED_DECOMPOSITION">
      Decompose by intent, not by volume. Avoid both monolithic methods AND artificial layering. Extract code only at TRUE intent boundaries that meaningfully improve readability, testability, or isolation. Splitting by line count without intent boundaries creates fictive functions that raise cognitive load without raising verifiability.
    </Axiom>

    <Axiom id="AX_TRACE_PREFIXED_ERRORS">
      Every error message carries a Trace-Prefix. Format: `[ClassName#methodName]` or `[functionName]`. With cause-chains across several log/error layers, the only reliable way to recover the failure point is an explicit prefix; stack aggregators may truncate.
    </Axiom>

    <Axiom id="AX_ERROR_CHAINING_CAUSE">
      Preserve original context via `{ cause }`. Create and rethrow via `new Error("[Trace-Prefix] ...", { cause })`. NEVER transform `cause` — it can be any value. `cause` is a lossless channel for the root cause; any transform breaks the debug chain.
    </Axiom>

    <Axiom id="AX_CATCH_LOG_RECOVER">
      Catch-Log-Recover is the only pattern in business-logic catch blocks. First `logger.error` with Trace-Prefix and context, then recovery in ONE of two forms depending on the surrounding method's contract:
      - throw-style API → `throw new Error("[Trace-Prefix] msg", { cause })`.
      - Result-style API → `return fail(error)` (per project Result conventions; the `error` carries `{ cause }` via its own constructor).

      `logger.error` records the failure with its context at detection time — this is the LDD trace (debug-level escalation lets an agent reconstruct the data path even when stacks are minified or aggregator-truncated). Recovery preserves control flow.

      Both forms require both steps. Skipping `logger.error` makes the failure invisible to the trace; skipping recovery swallows it. NEVER do both (log + throw + return fail) — that re-emits and double-logs across boundaries.
    </Axiom>

    <Axiom id="AX_FAIL_FAST_VALIDATION">
      Synchronous validation at the start of the method. Validate arguments synchronously and throw domain errors with context. Earlier validation = fewer state mutations before failure and clearer failure cause from the message.
    </Axiom>

    <Axiom id="AX_STRUCTURED_LOGGING">
      Raw `console.*` is forbidden. Use the shared logger from `#logger`: `logger[level](message, detail?)`. Levels: `debug` / `info` / `warn` / `error`. One or two arguments: first is a string message, second (when needed) is a `detail` object. **NEVER serialize objects into the message string.** Pseudo-loggers (`const logger = console`) forbidden.

      The shared logger is the only sink that can be re-targeted (transport, redaction, sampling) without editing call-sites; raw `console` breaks agent-readable structure.
    </Axiom>

    <Axiom id="AX_LOG_MESSAGE_FORMAT">
      Message format: `[Trace-Prefix] [stateA → stateB] Description`. State transitions are mandatory at entry, branches, exit, and errors. Description adds NEW information and does not duplicate state.

      A state machine in the log makes module behavior reconstructable along a timeline; raw messages without state break recovery.
    </Axiom>

    <Axiom id="AX_LOG_MESSAGE_PURITY">
      Message vs detail separation by type. Primitives (paths, codes, numbers, time) → message; complex objects and errors → second `{ ... }` argument, only when needed. Text backends digest serialized objects poorly; structured backends lose searchability if the object is jammed into a string. The split satisfies both.
    </Axiom>

    <Axiom id="AX_LOG_PERFORMANCE_METRICS">
      Timing for long operations only. Measure with `performance.now()`, format as `${time.toFixed(2)}ms`. Timing a trivial operation is noise that dilutes signal; timing an I/O boundary is critical perf-trace.
    </Axiom>

    <Axiom id="AX_LOG_DENSITY">
      Logs at entry points, important branches, external I/O / mutations, catch blocks. Loops logged in aggregate, NOT per iteration. In `catch`: ALWAYS `logger.error` with Trace-Prefix and context, then recover via `throw` or `return fail()` per `AX_CATCH_LOG_RECOVER`. Intent-driven density yields a readable story-line; per-iteration spam drowns real signals.
    </Axiom>

    <Axiom id="AX_ANCHOR_FORMAT">
      Anchors: `// #region START_[CONTEXT]_[INTENT]` / `// #endregion END_[CONTEXT]_[INTENT]`. Uppercase tokens. Parity mandatory: every `START_X` must have `END_X` in the same file. START_/END_ on top of `#region`/`#endregion` is intentional — paired uppercase tokens are attention anchors for sliding-window LLMs and XML-like span delimiters for long-context retrieval.

      When a block has a non-obvious invariant or failure boundary, attach payload inside the anchor (outside it is detached from the block it protects): ONE payload kind → inline on the opening line `// #region START_[NAME] — <key>: <value>`; 2+ kinds → separate comment lines immediately after the opening anchor. Greppable: `#(region|endregion)\s+(START|END)_[A-Z0-9_]+`.
    </Axiom>

    <Axiom id="AX_ANCHOR_COVERAGE_NONTRIVIAL">
      In a complex function wrap EVERY nested control-flow block with independent intent, side effects, or refactor risk: `if`/`else`, `for`/`for...of`, `while`, `switch`, meaningful `case`, `try`, `catch`. Do not skip anchors because the block looks short or locally readable. If another agent may need to isolate, patch, move, or audit the block as a unit, anchors are mandatory. This is patch-grammar, not cosmetic.
    </Axiom>

    <Axiom id="AX_ANCHOR_TRIVIAL_EXCEPTION">
      Do NOT wrap a trivial guard or single-action branch. Block has no independent policy, no meaningful side effect, no refactor hazard → anchors not needed. An anchor around a single line is noise that dilutes the signal of mandatory anchors and erodes trust in their semantics.
    </Axiom>

    <Axiom id="AX_ANCHOR_INTENTFUL_NAMES">
      Anchor name describes WHY the block exists. Does NOT restate syntax or literal conditions. `START_APPLY_FALLBACK_STRATEGY`, not `START_IF_NO_PATH`. The name is the only way for a reader-agent to recognize the block's policy without reading the body.
    </Axiom>

    <Axiom id="AX_COMMENTS_ADD_NONSYNTACTIC_INTENT">
      All comments are agent-authored machine comments and MUST add intent that an agent cannot safely infer from syntax. A comment SUPPLEMENTS pretrained code understanding instead of fighting it: prefer the smallest local comment that increases recoverable intent / patch safety / invariant preservation. The next reader-agent has no access to the chat in which the code was written — a comment is the only context channel that does not derive from syntax. Excess comments compete with code and drift; insufficient comments force reconstruction from stack traces. Comments do NOT explain syntax to humans; in an AI-to-AI ecosystem, human narrative is noise.
    </Axiom>

    <Axiom id="AX_COMMENT_VOCABULARY">
      Closed payload vocabulary: one or more of `purpose`, `consumer`, `invariant`, `side effect`, `failure mode`, `non-goal`. Use terse high-signal prose or `key: value` lines. Closed vocabulary makes comments greppable and predictable.

      Forbidden: decorative prefixes (`// NOTE:`, `// IMPORTANT:`) — no machine semantics; narrating loops, branches, assignments, obvious names — steals credit from real policy comments; duplicating JSDoc, types, signatures, log messages. NEVER write «temporary workaround» without (a) the cause, (b) the boundary of applicability, (c) what must remain unchanged — workaround without context is a mine for the next refactor.
    </Axiom>

    <Axiom id="AX_COMMENT_PLACEMENT">
      Function body starts with executable code. Hidden constraints belong in JSDoc (`@invariant`, `@sideEffect`, `@throws`, `@pre`, `@post`); block-level invariants inside `// #region START_<NAME>` anchors. No narrative brief or rule-summary at method head — JSDoc + signature is the canonical contract surface.
    </Axiom>

    <Axiom id="AX_COMMENT_DENSITY">
      Comment iff removing it would hide a business rule, invariant, integration constraint, or refactor hazard. Pure data reshaping, obvious getters/setters, trivial guard clauses, straight-line pure computations are NOT commented — silence signals «no hidden policy here». A comment on trivial code falsely tells the agent to look for an invariant that does not exist; a missing comment on non-trivial code forces reverse-engineering.
    </Axiom>

    <Axiom id="AX_TYPE_VS_INTERFACE_CHOICE">
      Architecture-level choice. DTOs, configs, API responses → `type`. `interface` reserved for abstractions with inheritance / implementation (polymorphism). A consistent choice makes a type's intent readable at a glance: `interface` signals «polymorphism point»; `type` signals «data shape».
    </Axiom>

    <Axiom id="AX_DOMAIN_PREFIX_FOR_EXTERNAL">
      Domain prefix for types from external systems: `ApiResource`, `VendorOrder`, `ErpCatalogItem`. Internal utilities have no prefix. The prefix protects a trust boundary: `OrderItem` (internal) and `VendorOrderItem` (external) are different entities; conflating is a common source of domain bugs.
    </Axiom>

    <Axiom id="AX_ERROR_VIA_CLASS">
      `Error` subclasses are declared via `class` only. Do NOT replace with `type` or `interface`. Only `class` correctly works with `instanceof`, the prototype chain, and the `cause` chain at runtime. A `type` alias for Error gives no runtime check.
    </Axiom>

    <Axiom id="AX_DIRECT_IMPLEMENTATION_PROTOCOL">
      Mandatory protocol for direct implementations of a contract. For every exported runtime root that directly implements a named contract:
      1. Keep the root-level `@purpose` (compressed essence).
      2. Add `@implements {ContractName} in path` on the root.
      3. Add `@see {ContractName#memberName} in path` on every direct public/protected implementation member, unless that member is a true override with a full explicit contract.

      Do not stop at the TS `implements` keyword, owner-level class JSDoc, or method «obviousness». These links are mandatory contract edges, not decoration. Without them a reader-agent does not see the implementation→contract link without grep; a member without `@see` is indistinguishable from an override.
    </Axiom>

    <Axiom id="AX_FILE_LEVEL_CONTEXT">
      File-level meta uses line-comments (`// @tag`), never a JSDoc block — distinct syntactic class from entity JSDoc so LLMs and grep distinguish file-scope from entity-scope unambiguously.

      Block of consecutive `//` lines at the very top of the file, before any `import`:
      `// @file: <what the file holds>` *(mandatory)*
      `// @consumers: <ConsumerName>` *(optional; omit when no uniform consumer)*
      `// @tasks: <TASK-ID>[, TASK-ID...]` *(optional; may be added later)*

      `@purpose` is NOT a file-level tag — it belongs exclusively to entities. Local entities inherit `@consumers` from file level and MUST NOT redeclare it unless their consumer diverges.

      `@consumers:` and `@tasks:` are optional — a coding-only agent may lack full project context. Omit rather than fabricate.
    </Axiom>

    <Axiom id="AX_FLAT_JSDOC_FOR_PROPERTIES">
      Single-line JSDoc for properties. When defining properties inside `type`, `interface`, or DTOs, generate the JSDoc as a single flat string to preserve vertical density. If multiple tags are required, merge them on the same line using the ` | ` separator. Example: `/** @purpose Smallest id in the range | @invariant >= 0 */`. Multi-line JSDoc blocks are strictly reserved for module roots, classes, and methods.

      ` | ` separates distinct JSDoc **tags**, not continuation lines of one tag. A multi-sentence `@purpose` is compressed to one sentence — not joined with ` | `. Discard sentences that restate the property name or explain the obvious; keep only the constraint or role that cannot be inferred from the type.
    </Axiom>

    <Axiom id="AX_BASE_CONTRACT_SHAPE">
      Base JSDoc contract shape for all types, interfaces, methods, fields, properties, getters, setters, functions (incl. `protected`):

      - **Default root contract:** `@purpose` (compressed essence). Do NOT replace a root definition or implementation owner with `@see`.
      - **Root implementation rule:** exported class or const directly implementing an existing named contract keeps its own `@purpose` AND adds `@implements {InterfaceName} in path`.
      - **Member implementation rule:** `@see {InterfaceName#memberName} in path` allowed only for direct public/protected implementation or inheritance edge where behavior matches.
      - **Override rule:** override / redefinition (behavior/contract change) → write the full contract explicitly; do not rely only on `@see`.
      - **Clarification rule:** if an implementation needs its own `@consumers`, `@invariant`, `@pre`, `@throws`, `@returns`, `@post`, or `@sideEffect` because the inherited contract is being tightened/specialized/extended → treat as override; write the full explicit contract instead of mixing extra tags into a `@see`-only stub.
      - **Single-line:** `/** @purpose Verb Object Context */` or `/** @see {InterfaceName#memberName} in ./path */`.
      - **Multi-line:** for complex entities, exported implementation roots, or entities with optional tags. Strict order mandatory.

      **Optional JSDoc tags (order MANDATORY):**
      1. `@consumers` — who consumes the API.
      2. `@implements` — the contract root implemented.
      3. `@invariant` — constraints, SLA, retry / error policies, ordering guarantees, implementation strategy guarantees that modifying agents must preserve.
      4. `@pre` — hidden preconditions before the call.
      5. `@param` — one coherent role description. Do NOT duplicate field structure from the type.
      6. `@throws` — reason for throw / Promise rejection.
      7. `@returns` — business purpose of a successful result / Promise resolution.
      8. `@post` — state guarantees after the call.
      9. `@sideEffect` — I/O, network, logs, etc.

      A strict order and closed vocabulary let a reader-agent parse the JSDoc contract deterministically. File-level tags (`@file:`, `@consumers:`, `@tasks:`) live in `// @tag:` line-comments at file head — never inside entity JSDoc (see `AX_FILE_LEVEL_CONTEXT`).
    </Axiom>

    <Axiom id="AX_TAG_USAGE_MATRIX">
      When each tag is used:
      - `@file:`, `@tasks:` — file-level line-comments only; see `AX_FILE_LEVEL_CONTEXT`.
      - `@consumers` — file-level line-comment when uniform; entity-level only when consumer diverges from file-level; skip for local helpers.
      - `@implements` — required on exported class/const root directly implementing a named interface/contract; skip for data shapes, interfaces, member declarations.
      - `@invariant` — stateful entities, resilience / error policy, ordering guarantees, non-local assumptions, implementation-strategy guarantees that modifying agents must preserve.
      - `@pre` — ONLY for hidden environment / system-state preconditions not captured by the type signature.
      - `@param` — when arguments exist; one coherent role description; do NOT enumerate object fields already in the type.
      - `@throws` — when the function can throw / reject; describe failure reason, not generic possibility.
      - `@returns` — for non-void / non-never results; describe WHY the caller needs the value, not the TS shape.
      - `@post` — state guarantees not already encoded by `@returns`, types, or obvious control flow.
      - `@sideEffect` — externally visible effects (network, fs, process, shared-state mutation, emitted events). Routine debug logging alone does NOT justify the tag.
      - `@see` — ONLY for direct member implementation / inheritance of an existing contract; do NOT use as a root class/const tag when root owns runtime behavior. Behavior diverges → write the full contract.
    </Axiom>

    <Axiom id="AX_ENTITY_SPECIFIC_MINIMUMS">
      Minimum requirements per entity kind:
      - **Exported data shapes:** `type` + `@purpose`; use `@consumers` only when consumer diverges from the file-level context declaration.
      - **Pure alias / shape-forwarding exports** with no runtime behavior may use a root-level `@see`. But runtime-bearing class/const implementations do NOT replace their owner contract with `@see`.
      - **Service interfaces / external-system clients:** require `@invariant` for error policy, retry policy, ordering guarantees, rate limits, or other resilience constraints.
      - **Implementations of an existing runtime contract:** owner-level `@purpose` on class/const + `@implements {ContractName} in path` on root + `@see {ContractName#memberName} in path` on each public/protected member when behavior matches.
      - **Async functions / methods:** `@returns` describes the resolved value; `@throws` describes the rejected/throw path; `@sideEffect` documents external action when present.
      - **Exported config constants:** `@invariant` when value bounds or combinations must remain stable.
      - **Within one implementing surface** `@implements` and member-level `@see` MUST use same path style and same contract names — do not mix local-relative and project-root-relative references inside one module.
    </Axiom>

    <Axiom id="AX_MANDATORY_TRY_CATCH_IN_BUSINESS_LOGIC">
      Exception handling is mandatory in business logic. Any business method with network/file/process I/O, mutation of external state, or integration with an external system MUST wrap the failure point in `try`/`catch` per `AX_CATCH_LOG_RECOVER`. Missing try/catch on an integration boundary turns any transient failure into an un-traced un-contextualized exception.
    </Axiom>
  </Belief_State>

  <Definitions>
    <Definition id="DEF_TRACE_PREFIX">Trace-Prefix format: `[ClassName#methodName]` or `[functionName]`. Used in all Error messages and log messages.</Definition>
    <Definition id="DEF_COMPLEXITY_TRIGGER">
      Complex (triggers non-trivial anchors + full JSDoc optional-tag set) if any: network/file/process I/O; shared-state mutation; retry/fallback/error translation; concurrency, locking, batching. OR any two of: multiple decision points, hidden pre/postconditions, nested control flow, non-local refactor hazard.
    </Definition>
    <Definition id="DEF_ALLOWED_COMMENT_PAYLOAD">
      Closed vocabulary for machine comments: `purpose`, `consumer`, `invariant`, `side effect`, `failure mode`, `non-goal`. Inside tests, additionally allowed: `contract` and `observation focus` (per directive `testing/common` `DEF_TEST_PAYLOAD_VOCAB`).
    </Definition>
  </Definitions>

  <Code_Patterns>
    <Pattern id="PT_MODULE_AND_DATA_TYPE">
      <Intent>Exported data shape: `type`, domain prefix, single-line JSDoc per field, no duplication of TS structure.</Intent>
      <Snippet language="typescript">
        ```typescript
        // @file: ERP catalog item shape shared across the synchronization pipeline.
        // @consumers: ErpSynchronizationWorker
        // @tasks: TASK-4231

        /** @purpose Normalized response from an external ERP catalog. */
        export type ErpCatalogItem = {
            /** @purpose Unique item identifier in ERP | @invariant Format: 'ERP-12345' */
            id: string;
            /** @purpose Timestamp of the last synchronization | @invariant Unix epoch milliseconds */
            syncedAt: number;
        };
        ```
      </Snippet>
      <Why>Data shape with no runtime behavior → `type` + entity `@purpose`. Shared context declared once in file-level `// @file:` / `// @consumers:` header; entity does NOT redeclare `@consumers`.</Why>
    </Pattern>

    <Pattern id="PT_SERVICE_CONTRACT_INTERFACE">
      <Intent>Service interface: precise optional-tag order, SLA in `@invariant`, side effects exposed explicitly.</Intent>
      <Snippet language="typescript">
        ```typescript
        // @file: Contract surface for vendor reservation integration.
        // @consumers: OrderFulfillmentPipeline

        /**
         * @purpose Gateway for interacting with a vendor API.
         * @invariant Retry Policy: Idempotent methods (GET) are retried up to 3 times.
         * @invariant Error Policy: All HTTP 5xx are wrapped into VendorNetworkError.
         */
        export interface VendorGateway {
            /**
             * @purpose Synchronous reservation registration: lock stock at the vendor warehouse.
             * @invariant Idempotency-Ref must be propagated unchanged across retries; vendor error boundary not normalized before cause-chaining.
             * @param idempotencyKey Key (UUIDv4) to prevent duplicated reservations during network retries.
             * @throws {VendorStockError} Item is out of stock at the vendor.
             * @returns Internal identifier of the created reservation in the vendor system.
             * @sideEffect Network: POST /v2/reservations
             */
            reserveStock(idempotencyKey: string): Promise<string>;
        }
        ```
      </Snippet>
      <Why>`interface` because this is a polymorphism point (Port), not a data shape. Invariants encode resilience policy that would otherwise be lost in the implementation.</Why>
    </Pattern>

    <Pattern id="PT_DIRECT_IMPLEMENTATION_WITH_LOG_AND_ERROR">
      <Intent>Implementation of an existing contract: root keeps `@purpose` + `@implements`; inherited members use `@see`; method body starts with executable code; non-trivial blocks wrapped in compact-form `#region START_...` / `#endregion END_...` anchors.</Intent>
      <Snippet language="typescript">
        ```typescript
        // @file: HTTP implementation of the VendorGateway contract.
        // @consumers: OrderFulfillmentPipeline
        // @tasks: TASK-1187

        import { logger } from '#logger';

        /**
         * @purpose HTTP adapter for interacting with a vendor API.
         * @implements {VendorGateway} in src/domain/contracts/VendorGateway.ts
         */
        export class HttpVendorGateway implements VendorGateway {
            protected _httpClient: HttpClient;
            protected _logger: Logger;

            constructor(httpClient: HttpClient, logger: Logger) {
                this._httpClient = httpClient;
                this._logger = logger;
            }

            /** @see {VendorGateway#reserveStock} in src/domain/contracts/VendorGateway.ts */
            async reserveStock(idempotencyKey: string): Promise<string> {
                this._logger.debug(`[HttpVendorGateway#reserveStock] [idle → reserving] ${idempotencyKey}`);

                // #region START_VENDOR_API_CALL — invariant: vendor deduplicates retries only when X-Idempotency-Ref is preserved exactly
                try {
                    const response = await this._httpClient.post('/v2/reservations', {
                        headers: { 'X-Idempotency-Ref': idempotencyKey }
                    });

                    this._logger.info(`[HttpVendorGateway#reserveStock] [reserving → reserved] ${response.data.reservationId}`);
                    return response.data.reservationId;
                } catch (cause) {
                    const error = new Error('[HttpVendorGateway#reserveStock] Reservation failed', { cause });
                    this._logger.error(`[HttpVendorGateway#reserveStock] [reserving → failed]`, { error });
                    throw error;
                }
                // #endregion END_VENDOR_API_CALL
            }
        }
        ```
      </Snippet>
      <Why>All mandatory protocols together: `// @file:` header, `@implements` on root, `@see` on member, executable-first body, compact single-payload anchor (invariant inlined on `#region` line), Trace-Prefixed log + error, cause-chain.</Why>
    </Pattern>

    <Pattern id="PT_ASYNC_OPERATION_WITH_TIMING">
      <Intent>Async operation with `performance.now()` timing, state transitions in logs, Catch-Log-Recover.</Intent>
      <Snippet language="typescript">
        ```typescript
        // @file: Timed execution helper for long-running async action.
        // @consumers: TaskOrchestrator

        import { performance } from 'node:perf_hooks';
        import { logger } from '#logger';

        /**
         * @purpose Performs an atomic action with performance measurement and state tracing.
         * @invariant On failure: emit `logger.error` with elapsed time, then recover via rethrow with cause-chain (or `return fail(error)` in Result-style APIs) — both steps mandatory per Catch-Log-Recover.
         * @param specifier Unique identifier of the target resource or action.
         * @throws {Error} When the action fails (wraps the original cause).
         * @returns Status of successful execution.
         */
        export async function performAction(specifier: string): Promise<string> {
          const startedAt = performance.now();
          try {
            logger.debug(`[performAction] [idle → processing] ${specifier}`);
            // ...work...
            const time = performance.now() - startedAt;
            logger.info(`[performAction] [processing → completed] ${specifier} (${time.toFixed(2)}ms)`);
            return 'ok';
          } catch (cause) {
            const time = performance.now() - startedAt;
            const error = new Error('[performAction] Action failed', { cause });
            logger.error(
              `[performAction] [processing → failed] Other error: ${specifier} (${time.toFixed(2)}ms)`,
              { error }
            );
            throw error;
          }
        }
        ```
      </Snippet>
      <Why>Timing justified — operation is long. State transitions explicit. Error path loses neither context (Trace-Prefix + detail) nor cause-chain.</Why>
    </Pattern>

    <Pattern id="PT_TYPE_NARROWING_AND_MODERN_OPERATORS">
      <Intent>Plain branching without anchors where control flow is self-evident; modern operators yield density without losing intent.</Intent>
      <Snippet language="typescript">
        ```typescript
        // @file: Strategy selection helpers for path-aware processing.
        // @consumers: StrategyPlanner

        import { logger } from '#logger';

        /** @purpose Configuration for choosing a processing strategy. */
        export type DecideStrategyConfig = {
          /** @purpose Path to the target resource | @invariant Absent value triggers fallback strategy */
          path?: string;
        };

        /**
         * @purpose Decides a processing strategy based on whether the config contains a path.
         * @param config Configuration parameters.
         * @returns Identifier of the chosen strategy.
         */
        export function decideStrategy(config: DecideStrategyConfig): string {
          logger.debug('[decideStrategy] [ready → choosing]');

          if (!config?.path) {
            logger.debug('[decideStrategy] [choosing → fallback] No config path provided');
            return 'fallback';
          }

          logger.debug(`[decideStrategy] [choosing → primary] ${config.path}`);
          return 'primary';
        }
        ```
      </Snippet>
      <Why>Branch is trivial (no independent policy / side effect / refactor hazard) → anchors redundant per `AX_ANCHOR_TRIVIAL_EXCEPTION`. `?.` provides narrowing without verbose checks.</Why>
    </Pattern>

    <Pattern id="PT_EXPRESSIVE_TERSENESS">
      <Intent>Modern TS operators replace verbose null-checks without losing meaning.</Intent>
      <Snippet language="typescript">
        ```typescript
        const avatarUrl = user?.profile?.getAvatar?.();
        cachedImages[avatarUrl] ||= await fetchImage(avatarUrl);
        ```
      </Snippet>
      <Why>The equivalent of 6 lines of `if`-nesting is compressed to 2 without loss of semantics. Canonical «high-signal idiomatic TypeScript».</Why>
    </Pattern>
  </Code_Patterns>

  <Anti_Patterns>
    <Anti_Pattern id="AP_ATOMIC_NOISE_ANCHORS">
      <Bad>Anchors around a single `const`; anchor name `START_CHECK_RETRIES` (names syntax, not intent); comment restates the `if`; `Error("Limit")` without Trace-Prefix or cause.</Bad>
      <Why_Bad>Atomic noise (violates `AX_ANCHOR_TRIVIAL_EXCEPTION`); name violates `AX_ANCHOR_INTENTFUL_NAMES`; comment violates `AX_COMMENT_VOCABULARY`; Error violates `AX_TRACE_PREFIXED_ERRORS`, `AX_ERROR_CHAINING_CAUSE`.</Why_Bad>
      <Good language="typescript">
        ```typescript
        const maxRetries = 3;

        // #region START_ENFORCE_RETRY_POLICY
        // purpose: stop retry fan-out before a degraded upstream turns one request into cascading load
        // failure mode: removing this guard converts transient upstream latency into duplicate pressure
        if (attempts > maxRetries) {
            throw new TessellError(ErrKind.ERR_CHECKOUT_CHARGE_UPSTREAM_UNRESPONSIVE, "[Checkout#charge] Upstream provider unresponsive", {
              cause: { attempts, maxRetries }
            });
        }
        // #endregion END_ENFORCE_RETRY_POLICY
        ```
      </Good>
    </Anti_Pattern>

    <Anti_Pattern id="AP_FALSE_PRIVATE_AND_ENUM">
      <Bad>`enum OrderState { NEW, PAID, SHIPPED }`; `class OrderManager { constructor(private repo: OrderRepo) {} #lastState: OrderState = OrderState.NEW; public process(orderId: string) {} }`.</Bad>
      <Why_Bad>`enum` breaks under native Node TS (`AX_NO_TRANSPILE_ONLY_CONSTRUCTS`). Constructor parameter property `private repo` transpile-only. `#lastState` blocks reflection (`AX_TRUTHFUL_ENCAPSULATION`). `OrderManager` is semantic noise (`AX_TELEOLOGICAL_NAMING`). `process` generic verb (`AX_VERB_PRECISION`). `public` redundant.</Why_Bad>
      <Good language="typescript">
        ```typescript
        // @file: Order lifecycle primitives for checkout domain.
        // @consumers: CheckoutPipeline

        /** @purpose Lifecycle states an order traverses from creation to fulfillment. */
        export type OrderState = 'NEW' | 'PAID' | 'SHIPPED';

        /** @purpose Coordinates order lifecycle transitions for the checkout flow. */
        export class OrderLifecycle {
            protected _repo: OrderRepo;
            protected _lastState: OrderState = 'NEW';

            constructor(repo: OrderRepo) {
                this._repo = repo;
            }

            /** @purpose Transition the order to PAID after successful charge. */
            settleCharge(orderId: string): Promise<void> { /* ... */ }
        }
        ```
      </Good>
    </Anti_Pattern>

    <Anti_Pattern id="AP_BARE_CONSOLE_AND_LOST_CAUSE">
      <Bad>`console.log("fetching user " + JSON.stringify({ id }));` then `catch (e) { console.error("failed " + e); throw new Error("fetch failed"); }`.</Bad>
      <Why_Bad>`console.*` forbidden (`AX_STRUCTURED_LOGGING`). Object serialized into message string (`AX_LOG_MESSAGE_PURITY`). No Trace-Prefix or state transition (`AX_LOG_MESSAGE_FORMAT`). `new Error` without `{ cause }` loses debug chain (`AX_ERROR_CHAINING_CAUSE`). No Trace-Prefix in error (`AX_TRACE_PREFIXED_ERRORS`). `e` concatenated into string — stack lost.</Why_Bad>
      <Good language="typescript">
        ```typescript
        // @file: User retrieval entry point against the primary store.
        // @consumers: SessionRouter

        import { logger } from '#logger';

        /**
         * @purpose Retrieve a user record by id from the primary store.
         * @invariant Storage failure is preserved as `cause` (not transformed); state-transition logs emitted on both success and failure paths.
         * @throws {Error} Wraps any storage failure with cause-chain.
         * @sideEffect Storage: SELECT from users by id.
         */
        export async function retrieveUser(id: string): Promise<User> {
            try {
                logger.debug(`[retrieveUser] [idle → retrieving] ${id}`);
                const user = await db.find(id);
                logger.info(`[retrieveUser] [retrieving → retrieved] ${id}`);
                return user;
            } catch (cause) {
                const error = new Error(`[retrieveUser] Storage retrieval failed for ${id}`, { cause });
                logger.error(`[retrieveUser] [retrieving → failed] ${id}`, { error });
                throw error;
            }
        }
        ```
      </Good>
    </Anti_Pattern>

    <Anti_Pattern id="AP_REDUNDANT_JSDOC_DUPLICATION">
      <Bad>`/** @purpose User DTO. @param id The id field, type string. @param name The name field, type string. @returns Returns a User object with id and name. */ export type User = { id: string; name: string; };`.</Bad>
      <Why_Bad>`@param`/`@returns` used on a type, not a function (`AX_TAG_USAGE_MATRIX`). JSDoc duplicates TS structure (`AX_FLAT_JSDOC_FOR_PROPERTIES`). `User DTO` carries no business meaning.</Why_Bad>
      <Good language="typescript">
        ```typescript
        // @file: Identity shape exposed by session-related APIs.
        // @consumers: SessionRouter

        /** @purpose Authenticated user identity surfaced to API consumers. */
        export type User = {
            /** @purpose Stable user identifier | @invariant UUIDv7 format */
            id: string;
            /** @purpose Display name shown in UI | @invariant Not unique across users */
            name: string;
        };
        ```
      </Good>
    </Anti_Pattern>
  </Anti_Patterns>

  <Verification_Hooks>
    <Hook id="HOOK_TYPECHECK">
      <Purpose>Code has no TS errors and no transpile-only constructs broken under native Node TS.</Purpose>
      <Command>npx tsc --noEmit</Command>
      <Expected>Exit 0; empty stdout/stderr.</Expected>
    </Hook>
    <Hook id="HOOK_PROJECT_LINT">
      <Purpose>Project-level lint pipeline (format + type-check), per `package.json`.</Purpose>
      <Command>npm run lint</Command>
      <Expected>Exit 0.</Expected>
    </Hook>
    <Hook id="HOOK_NO_FORBIDDEN_CONSTRUCTS">
      <Purpose>Smoke-grep for forbidden transpile-only constructs and raw `console.*`.</Purpose>
      <Command>rg --follow --no-heading -n "^\s*(enum |namespace |private )|#[a-zA-Z_]+\s*[:=]|\bconsole\.(log|warn|error|info|debug)\b" -t ts --glob '!**/node_modules/**' --glob '!**/dist/**'</Command>
      <Expected>Empty (no matches) on new/changed files; matches on pre-existing files tolerated only if outside current task scope.</Expected>
    </Hook>
    <Hook id="HOOK_ANCHOR_PAIRING">
      <Purpose>Verify anchor parity and enable agent grep-navigation: every `// #region START_X` must have `// #endregion END_X` in the same file.</Purpose>
      <Command>rg --follow --no-heading -n "#(region|endregion)\s+(START|END)_[A-Z0-9_]+" -t ts</Command>
      <Expected>For every `START_NAME` occurrence there is a matching `END_NAME` in the same file; counts equal per file.</Expected>
    </Hook>
  </Verification_Hooks>

  <Reward_Criteria>
    ✅ File has `// @file:` line-comment header; `// @consumers:` / `// @tasks:` when applicable; no `@purpose` at file level.
    ✅ Every exported entity has valid JSDoc contract per `AX_BASE_CONTRACT_SHAPE`; tag order preserved.
    ✅ Implementation roots use `@purpose` + `@implements`; member implementations use `@see`; overrides write the full contract.
    ✅ Comments carry intent (purpose / consumer / invariant / side effect / failure mode / non-goal); do NOT restate syntax.
    ✅ Anchors on every non-trivial control-flow block; intent-named, not syntax-named; paired `START_X`/`END_X`; compact single-line form when one payload kind, multi-line when 2+.
    ✅ Trivial guards and single-action branches NOT wrapped in anchors.
    ✅ Error messages contain Trace-Prefix; rethrow uses `{ cause }`; catch blocks follow Catch-Log-Recover (log + throw OR log + `return fail()` per surrounding contract).
    ✅ Logs through shared logger from `#logger`; format `[Trace-Prefix] [stateA → stateB] Description`; primitives in message, objects in detail.
    ✅ Modern TS operators (`?.`, `??`, `||=`, `&&=`, `??=`) instead of verbose null-checks.
    ✅ Class fields declared explicitly in body; `readonly` on field declaration; `protected _foo` over `private`/`#`.
    ✅ Names express teleology (business goal), not topology (pattern); precise verbs; public names do NOT leak transport.
    ✅ Complex functions declare resilience / strategy guarantees via `@invariant`; body starts with executable code.
    ✅ External-system types carry domain prefix; data shapes use `type`; polymorphism uses `interface`; Error subclasses use `class`.

    ❌ Use of `enum`, `namespace`, or constructor parameter properties (transpile-only).
    ❌ Use of the `private` modifier or `#` private fields.
    ❌ Raw `console.*`, pseudo-logger `const logger = console`, or object serialization into message string.
    ❌ Error without Trace-Prefix or without `{ cause }` on rethrow inside business logic.
    ❌ Missing try/catch on integration boundary of a business method.
    ❌ Comments that restate loops/branches/assignments, or duplicate JSDoc or log messages.
    ❌ Anchors around atomic operations (lone return, single const) or with syntax-style names.
    ❌ Missing anchor on non-trivial block with independent policy / side effect / refactor hazard.
    ❌ Mismatched JSDoc tag order; duplication of TS fields in `@param`/`@returns`; `@see` on a runtime-bearing root instead of `@purpose` + `@implements`.
    ❌ Mixed implementation reference style (local-relative and project-root-relative `@implements`/`@see` in one module).
    ❌ Premature abstraction: extracting an interface for a single consumer without confirmed variance.
    ❌ Defensive code against states excluded by types or invariants.
  </Reward_Criteria>
</TypeScriptCodingRules>
