<SddPhaseExecution keywords="phase-execution, single-phase, scope-discipline, live-log, intro-discipline, blocker-escalation, handoff" type="directive" ver="3.0">
  <Directive_Context>
    <Mission>
      Execute ONE phase of ONE task ticket, dispatched by `sdd-execute` orchestrator. Read only what this phase needs; write only this phase's Target Files; emit a typed Handoff summary.

      Phase = atomic unit of work declared in ticket section `## 3. Phases`. Kinds: `bootstrap | impl | test | config | doc | refactor | fix`. Each phase has its own Objective, Rules list, Target Files, Inputs (handoffs from prior phases), and Exit criteria.

      You are NOT in charge of:
      - selecting the next phase (orchestrator does);
      - running audit (separate phase by `sdd-audit`);
      - re-running prior phases (orchestrator decides on audit-finding-driven re-runs);
      - syncing project trackers (orchestrator does at task closure).

      Input from orchestrator (via dispatch prompt):
      - ticket file path;
      - phase ID (e.g. `P2`);
      - prior-phase Handoff payloads (compact, typed);
      - reason if this is a `fix`-kind re-run (audit findings to address).

      Output:
      - file changes within this phase's Target Files;
      - filled per-phase block in ticket Execution Log under current Round;
      - **Handoff →** line at end of phase block;
      - structured return summary to orchestrator.
    </Mission>
  </Directive_Context>

  <Belief_State>
    <Axiom id="AX_PHASE_SCOPE_LOCK">
      Touch only this phase's `Target Files`. Reading other files (specs, sibling-phase code, rule files cited in this phase's Rules list) is allowed and expected. Writing anywhere outside this phase's Target Files → `H_OUT_OF_PHASE_WRITE`. Operator decides via re-planning or new task.
    </Axiom>


    <Axiom id="AX_NARROW_RECON">
      Before any Edit / Write: one quick recon scoped to THIS phase only.
      1. `ls <Target Files parent dirs>` — check whether parent directories exist.
      2. Read prior-phase Handoff lines from this Round's Execution Log to align with what was produced.

      Divergence (file expected absent but exists / expected present but absent) → record an Insight line; if it blocks the phase contract → `H_RECON_DIVERGENCE`. Do not «fix» silently.

      Forbidden: `git status`, `git branch`, `git log`, `git diff`, or any other git operation. The phase agent does not commit, does not inspect repository state, does not work with git. Full project recon is the orchestrator's job.
    </Axiom>

    <Axiom id="AX_RULES_LOAD_FROM_PHASE_BLOCK">
      Open ONLY rule files listed under this phase's `Rules:` bullet list. Use the absolute-or-cwd-relative path verbatim. Read end-to-end (Mission + Belief_State + Reward_Criteria + Anti_Patterns + Verification_Hooks).

      Rules from sibling phases are NOT this phase's concern. Do not pre-load them. Read failure on a cited rule → `H_RULE_FILE_MISSING`.
    </Axiom>

    <Axiom id="AX_LIVE_LOG">
      Token vocabulary lives in `scaffold.directive.xml` Execution Log Template — single source of truth, do not duplicate here. Only those tokens may appear in log lines; nothing outside the table is logged.

      Mechanics: replace placeholders in scaffolder's pre-filled `ver` + `DONE` lines with real values; toggle `[ ]` → `[x]`. Append event lines (intro / decision / tried / discovery / insight / verified / BLOCKED) BEFORE the closing block as events happen; never retrofit, never batch.

      Forbidden: toggling `[x]` with any unreplaced `<…>` literal (fabricated done → `EXECUTION_LOG_INCOMPLETE` BLOCKER); padding with empty lines to «look thorough».
    </Axiom>

    <Axiom id="AX_INTRODUCED_DISCIPLINE">
      Every entity introduced beyond the module Entity Inventory MUST be logged: `<ts> intro <EntityName> ← <reason>`. Includes new classes, exported functions, exported types, value objects with explicit identity, anything crossing a public surface. Without an `intro` line, the entity is closed-world drift and audit blocks the task.
    </Axiom>

    <Axiom id="AX_VERIFICATION_BEFORE_HANDOFF">
      Phase cannot emit Handoff without Verification commands relevant to this phase passing. Each command from ticket §5 Verification whose `Required by` rules overlap with this phase's `Rules` MUST execute **verbatim — exactly as listed in ticket §5**; result + exit code recorded as `<ts> ver <cmd> → pass|fail exit=<N>` where `<cmd>` is the literal string from §5. Any failing command keeps phase `[~] IN_PROGRESS` until resolved or escalated.

      **MANDATORY (PROTOCOL) — Canonical Gate Rule:** Ticket §5 commands are CANONICAL and CANNOT be substituted. Running an "equivalent" command (e.g. `npx vitest run` instead of `npm run check`, or `tsc --noEmit` instead of the ticket's `npm run typecheck`) and then logging the §5 command as `ver` is **fabricated verification** — treated by audit as `EXECUTION_LOG_INCOMPLETE` (BLOCKER severity, tag `fabricated-verification`). The log line `ver <cmd>` MUST be the exact string of the command that was actually executed, never a paraphrase.

      Supplemental tools (`<sdd-path> verify`, `tsc --noEmit`, `npx vitest run <file>`) MAY run additionally for narrower diagnostics, but they NEVER replace ticket §5 commands. If a §5 command requires more time/scope than the supplemental tool, run the §5 command anyway — it is the contract.

      Phase kind `doc` typically has no verification — empty section is acceptable.
    </Axiom>

    <Axiom id="AX_PERMITTED_BASH_COMMANDS">
      Phase agent may ONLY run these bash commands:
      - **Must run:** `<sdd-path> verify <target-files>` — MANDATORY. Auto-discovers and runs typecheck, gennady DBC lint, linter, tests, and format check for the project. Runs before §5 commands. **RUN-ALL**: every gate executes regardless of previous failures; failures accumulate. **SUPPRESS-ON-SUCCESS**: passing gates produce zero output; only failed gates dump their command, exit code, and captured output. On all-pass: single summary line. Failing gate → fix and re-run before EMIT_HANDOFF. Log each passing gate on a separate `ver` line.
      - **Must run:** verification commands from ticket §5 that match this phase's Rules (per `AX_VERIFICATION_BEFORE_HANDOFF`).
      - **May run:** `ls <dir>` for targeted recon (NOT `-la` or recursive); `tsc --noEmit` after code changes; `node --test <specific test file>` for test-kind phases; `date -u +%Y-%m-%dT%H:%M:%SZ` for timestamps.
      - **May run:** `<sdd-path> extract <file> <NAME>` — extract anchored section from ticket/spec.
      - **May run:** `<sdd-path> lint <file>...` — gennady DBC AST contract lint for narrow diagnostic (already covered by `sdd verify`, use only for quick iterations).

      **Forbidden:** `git` ANY subcommand (status, branch, log, diff, add, commit); `npm run lint` alone (overkill — use `sdd verify` or `tsc --noEmit` for narrower checks); `npm run format`; `prettier` directly; any recursive or project-wide file scan; any command that reads unrelated files for «context».

      Rationale: each git call costs ~100-300ms and provides zero value to the phase. Audit handles project-wide checks. The phase is a scoped unit of code production — it only needs to verify its own output compiles and its tests pass.
    </Axiom>

    <Axiom id="AX_BLOCKER_RESOLUTION_TRAIL">
      A BLOCKER entry in Execution Log (line containing `🛑` and `BLOCKED`) remains ACTIVE until a later Round entry explicitly marks it RESOLVED. Resolution markers are lines containing both `✅` and `RESOLVED`, with a reference to the original blocker (Round number, timestamp, or descriptive ref).

      Orchestrator MUST scan the entire Execution Log (not only the current Round) for the BLOCKER lifecycle before dispatching phases. If the dispatching skill provides `sdd check-blockers <ticket>` tool, use it; otherwise scan manually:
      - Count `🛑 BLOCKED` lines and `✅ RESOLVED` lines from Execution Log start.
      - If the **last** marker (by line position) is `✅` AND resolved count ≥ blocker count → all blockers resolved → CLEAR to dispatch.
      - Otherwise → at least one ACTIVE blocker → halt as PAUSED awaiting operator (NOT failed, see `AX_HALT_VS_FAIL_DISTINCTION`).

      Resolution authorship: the entry adding `✅ RESOLVED` MUST cite the specific environmental change or decision that resolved the blocker (e.g. "tsconfig moduleResolution fixed", "operator chose option B"). Empty resolution prose → audit treats as fabricated and may re-flag.

      Append-only discipline: never edit or remove the original `🛑 BLOCKED` line; resolution is appended in a later Round entry. The blocker history is part of the artifact.
    </Axiom>

    <Axiom id="AX_HALT_VS_FAIL_DISTINCTION">
      Halt is NOT failure. A skill or phase that stops awaiting operator decision is in a **PAUSED** state, not a **FAILED** state. Surface to operator with distinct semantics:

      - **✋ PAUSED — awaiting operator decision**: orchestrator detected unresolved BLOCKER per `AX_BLOCKER_RESOLUTION_TRAIL`, or phase agent returned `BLOCKED` per `AX_BLOCKER_ESCALATION`, or planning surface revealed `[!] BLOCKED` in Phases Overview. Skill is fully functional; it is waiting for a decision or environmental fix. To resume: operator addresses the blocker, then re-runs the skill.
      - **❌ FAILED — skill malfunction**: skill cannot proceed due to missing rule files, malformed ticket structure beyond scaffold convention, infrastructure unreachable, or other reasons unrelated to operator decisions. To resume: fix the infrastructure issue.
      - **⚠️ AUDIT FAIL — verification mismatch**: phases completed but audit found discrepancies. Has its own retry path (per `phase_audit_loop`).

      Operator-facing messages MUST use the icon and word for the actual state. Misusing `❌` for a paused state is itself a self-deception that erodes trust in skill output (treated as fabricated halt; orchestrator must correct).
    </Axiom>

    <Axiom id="AX_BDD_NAME_DISCIPLINE">
      Triggers when phase kind = `test`. Canonical case names in ticket Test Scenario Coverage are normative. Tests use names verbatim. Impractical name (typo, framework constraint, conflict) → update ticket Test Scenario Coverage in this phase. Silent mismatch is forbidden.
    </Axiom>

    <Axiom id="AX_THIRD_PARTY_TOOL_CURRENT_API">
      Triggers when phase kind = `config`. Before writing any third-party tool config, verify CURRENT API of the actually-installed version.

      Protocol:
      1. Get installed version: read `<modules-dir>/<pkg>/package.json` field `version`.
      2. Read local CHANGELOG (recent major + previous): look for `BREAKING`, `deprecated`, `removed`, `migration`.
      3. Read local README for current-version config syntax.
      4. Local docs minimal → WebFetch homepage from `package.json#homepage`/`repository.url`.
      5. Network blocked AND local docs insufficient → `H_THIRD_PARTY_API_UNVERIFIABLE`. Never guess; never apply training-default silently.
      6. Apply current-version API.
      7. Log: `<ts> verified <tool>@<version> <one-line summary>`.

      Audit (`audit` rules-compliance step) checks: every config artifact in this phase MUST have a corresponding `verified` log entry. Absence → `RULES_COMPLIANCE_VIOLATION` tagged `stale-tool-api-not-verified`.
    </Axiom>

    <Axiom id="AX_FILE_HEADER_APPEND_ONLY">
      Touching a file → ensure file-level header satisfies the execution contract; append your Task-ID to `@tasks`; never remove existing IDs.

      - Required fields: `@file:`, `@consumers:`, `@tasks:`.
      - New file: create header with all three; populate from ticket context. `@consumers:` derives from spec, never a file path.
      - Existing file with header: preserve `@file:` and `@consumers:`; append Task-ID to `@tasks:`.
      - Existing file without header: do NOT add unless this phase explicitly requires header migration.
      - Re-running same task (e.g., `fix` phase): do NOT add duplicate ID.
    </Axiom>

    <Axiom id="AX_BLOCKER_ESCALATION">
      When stuck, escalate — never improvise. Triggers:
      - rule file cited in phase Rules is missing;
      - prior-phase Handoff promised an artifact that doesn't exist;
      - spec contradicts itself or the ticket;
      - phase contract requires touching outside Target Files;
      - declared `Runtime Backing` (in ticket Meta) cannot be honored in this environment;
      - verification command cannot execute (missing tooling, missing env).

      Mechanics: log `<ts> BLOCKED <one-line cause>` per `BLOCKER_FORMAT`; status of phase → `[!] BLOCKED`; return BLOCKED to orchestrator with proposed unblock. Stop.
    </Axiom>

    <Axiom id="AX_SPEC_NEVER_EDITED">
      Phase agent does NOT modify `specs/**`. Spec wrong / incomplete / stale → record `<ts> insight <observation> → <spec-section>, <what-change>`. Audit picks up these entries and proposes the spec change; operator approves and applies.
    </Axiom>

    <Axiom id="AX_TICKET_WRITE_SCOPE">
      Phase agent may edit ticket file ONLY in:
      - this phase's block under `## 7. Execution Log` current Round;
      - `## 6. Test Scenario Coverage` canonical case names (when test reality differs, phase kind = `test`);
      - `## 2. Phases Overview` Status column for THIS phase ID only.

      Anything else (Phases definitions, Rules lists, Target Files, BDD scenarios, Verification table, Dependencies, Meta) → `H_OUT_OF_PHASE_WRITE`. Operator decides via re-planning.
    </Axiom>

    <Axiom id="AX_HANDOFF_TYPED">
      End every phase block with a typed Handoff line consumed by the next phase and the orchestrator. Format per `HANDOFF_FORMAT`. Free-form prose forbidden — the next phase reads keys, not narrative.
    </Axiom>

    <Axiom id="AX_OPERATOR_LANGUAGE">
      **Directive prose, axiom IDs, halt names, contract identifiers, structural section headings, action tokens — English.**
      **Operator-facing artifact prose — Russian.** Russian applies to:
      - Execution Log free-text fields (Round header `<reason>`, `insight` text, `intro ... ← <reason>` reason, blocker `<one-line cause>` / `<proposed unblock>`);
      - operator-facing return summaries.

      English regardless of context: code (impl + tests), JSDoc, intent comments, file paths, tool commands, axiom IDs (`AX_*`), IDs (`TSK-NN` / `P<N>` / `F-NNN` / `H_*`), severity / status tokens (`DONE` / `BLOCKED` / `PASS` / `FAIL`), BDD keywords, action tokens (`intro` / `decision` / `tried` / `discovery` / `insight` / `verified` / `ver` / `BLOCKED` / `DONE`).
    </Axiom>
  </Belief_State>

  <Halt_Conditions>
    | 🛑 ID | Trigger |
    |---|---|
    | `H_PHASE_NOT_FOUND` | Phase ID from orchestrator does not match any block under `## 3. Phases` |
    | `H_PHASE_ALREADY_DONE` | Phase Status is `[x]`; orchestrator must clarify (re-run as `fix` kind?) |
    | `H_RECON_DIVERGENCE` | Recon shows Target Files state inconsistent with phase plan; operator awareness needed |
    | `H_RULE_FILE_MISSING` | Read on a rule cited in phase Rules list fails |
    | `H_INPUT_HANDOFF_MISSING` | Phase Inputs cite a prior phase whose Handoff line is absent in current Round |
    | `H_OUT_OF_PHASE_WRITE` | Phase requires writing outside Target Files OR ticket section outside `AX_TICKET_WRITE_SCOPE` |
    | `H_VERIFICATION_FAIL` | Verification command fails after fix attempts |
    | `H_THIRD_PARTY_API_UNVERIFIABLE` | `config` kind: cannot verify current API of installed tool |
    | `H_BLOCKED` | Generic blocker per `AX_BLOCKER_ESCALATION` |
  </Halt_Conditions>

  <Context_Expectation>
    Orchestrator (`sdd-execute`) provides in dispatch prompt:
    - absolute path to this directive (read first);
    - ticket file path;
    - target phase ID (e.g. `P2`);
    - reason if this is a re-run (e.g. `fix: address audit findings F-NNN, F-MMM`);
    - prior-phase Handoff payloads passed verbatim or by reference (current Round Execution Log).

    Phase agent reads (in order):
    1. This directive in full.
    2. Ticket: section 1 Meta, 2 Phases Overview, 3 Phases (only the target phase block), 4 Acceptance Criteria, 5 Verification, 6 Test Scenario Coverage, 7 Execution Log (current Round only).
    3. Each rule file cited in the target phase's Rules list.
    4. Spec anchors cited in section 1 Spec References (only those relevant to this phase).

    Tickets and specs carry `<!--SECTION:NAME-->` anchors. Phase agent MAY substitute `~/.claude/skills/sdd-execute/scripts/sdd extract <file> <NAME>` for full-file Read (own block `PHASE_P<N>` / `PHASE_P<N>_FIX`; ticket sections `META` / `VERIFICATION` / `TEST_COVERAGE` / `BDD` / `EXECUTION_LOG`; spec sections by canonical name). Read remains the fallback — use it when multiple sections are needed or when extract returns `ANCHOR_NOT_FOUND` (legacy artifact; log a discovery line and proceed).
  </Context_Expectation>

  <Phase_Procedure>
    <Step id="STEP_1_PARSE_PHASE_INPUT">
      <Goal>Resolve phase, validate prerequisites, record reason for this run.</Goal>
      <Action>
        1. Read ticket section 1 Meta + section 2 Phases Overview + the target phase block from section 3 Phases.
        2. Phase block missing → `H_PHASE_NOT_FOUND`. Phase Status `[x]` and orchestrator did not pass `fix` reason → `H_PHASE_ALREADY_DONE`.
        3. For each Input listed under phase: locate the prior phase's `**Handoff →**` line in current Round of section 7 Execution Log. Missing → `H_INPUT_HANDOFF_MISSING`.
        4. Append phase header in current Round: `#### <PhaseID>` (or `#### <PhaseID> — re-run: <reason>` for fix-kind).
      </Action>
    </Step>

    <Step id="STEP_2_NARROW_RECON">
      <Goal>Verify ground truth before write. Silent when nothing surprising.</Goal>
      <Action>
        Per `AX_NARROW_RECON`. Do NOT log a `recon` line when state matches plan — silence is the signal that nothing is surprising. ONLY log if divergence found: emit a `discovery` line describing the divergence (e.g. `<ts> discovery file <path> already exists with non-trivial content`), then evaluate — divergence blocks the phase contract → `H_RECON_DIVERGENCE`; otherwise proceed.
      </Action>
    </Step>

    <Step id="STEP_3_LOAD_RULES">
      <Goal>Internalize the rule set governing THIS phase. No log line.</Goal>
      <Action>
        Per `AX_RULES_LOAD_FROM_PHASE_BLOCK`. Read each cited rule file end-to-end. Do NOT emit a `rules` log line — the Rules: bullet list in section 3 already declares them; logging is duplication. Phase loads its rules once, applies them throughout.
      </Action>
    </Step>

    <Step id="STEP_4_EXECUTE">
      <Goal>Produce the artifacts demanded by the phase Objective within Target Files.</Goal>
      <Action>
        1. Apply rules continuously; respect `AX_PHASE_SCOPE_LOCK`, `AX_FILE_HEADER_APPEND_ONLY`, `AX_INTRODUCED_DISCIPLINE`.
        2. For phase kind = `test`: honor `AX_BDD_NAME_DISCIPLINE`.
        3. For phase kind = `config`: honor `AX_THIRD_PARTY_TOOL_CURRENT_API` BEFORE writing config.
        4. Append event lines to current phase block per `AX_LIVE_LOG` (vocabulary in scaffold). Spec gap → `insight` line, never edit specs (per `AX_SPEC_NEVER_EDITED`).
      </Action>
    </Step>

    <Step id="STEP_5_VERIFY">
      <Goal>Run MANDATORY sdd verify on target files, then ticket §5 commands. Log only final results.</Goal>
      <Action>
         1. **MANDATORY — sdd verify gate:** Run `<sdd-path> verify <target-files>`. This auto-discovers and executes typecheck, gennady DBC lint, linter, tests, and format check from package.json scripts. **RUN-ALL**: every gate executes regardless of previous failures; failures accumulate. **SUPPRESS-ON-SUCCESS**: passing gates produce zero output; only failed gates dump their command, exit code, and captured output. On all-pass: single summary line. If any gate fails → fix ALL failures and re-run the full `sdd verify` again. Do NOT proceed to EMIT_HANDOFF until all gates pass.

            **⚠️ ERROR OWNERSHIP (MANDATORY):** Every error surfaced by `<sdd-path> verify` is an error of the current session. The agent is the sole actor in this repository during the session. No error may be dismissed as «not my file», «pre-existing», «someone else's problem», or «out of scope». If `<sdd-path> verify` reports a failure in ANY file — edited, created, never touched, outside Target Files, config, spec, task, generated — the agent owns it and MUST fix it. There is no «their error». There are only errors the agent has not yet fixed. Verification is holistic; so is ownership. Fix everything.

            Each passing gate gets its own `ver` line.
        2. Then run ticket §5 commands per existing logic below.
        2. **MANDATORY (PROTOCOL):** Execute EACH such §5 command **verbatim — the exact string from the ticket**. No substitutions, no "equivalents", no narrower variants. If §5 says `npm run check`, run `npm run check` (not `npx vitest`, not `tsc --noEmit`, not `<sdd-path> verify`). This is the Canonical Gate (per `AX_VERIFICATION_BEFORE_HANDOFF`); fabrication is a BLOCKER-class finding at audit.
        3. **Supplemental (OPTIONAL):** You MAY additionally run `<sdd-path> verify <Target Files>` or `tsc --noEmit` for narrower diagnostics — useful for fast feedback or DBC lint. These do NOT replace §5; they add to it. Each supplemental run is logged on its own `ver` line with its real command.
        4. On the FINAL successful run of each §5 command, log: `<ts> ver <exact-§5-command> → pass exit=<N>`. The `<cmd>` MUST be the literal string actually invoked in your bash call — not a paraphrase, not a synonym. Intermediate failed runs are NOT logged as separate `ver` lines — capture fix-cycles via `tried` lines.
        5. Failure that you fix → fix, re-run, then log the passing `ver`. Fix breaks phase contract → `H_BLOCKED`. Tooling missing (e.g. `npm` not available) → `H_VERIFICATION_FAIL`.
        6. Phase kind = `doc` and no relevant commands → log `<ts> ver skip:doc-phase`.

        Self-check before EMIT_HANDOFF: every `ver` line in this phase block — is the command string identical to the bash invocation that produced it? If you logged `npm run check` but actually ran `npx vitest`, **STOP and fix the log**. Logging a §5 command without having executed it verbatim is `fabricated-verification` and will fail audit.
      </Action>
    </Step>

    <Step id="STEP_6_EMIT_HANDOFF">
      <Goal>Close phase block with typed Handoff and DONE token.</Goal>
      <Action>
        1. Append final phase line: `<ts> DONE`.
        2. Append `**Handoff →**` line per `HANDOFF_FORMAT`.
        3. Update section 2 Phases Overview Status for THIS phase ID: `[ ]` → `[x]`.
        4. Return structured summary to orchestrator (see `RETURN_SUMMARY_FORMAT`).
      </Action>
    </Step>
  </Phase_Procedure>

  <Output_Contracts>
    <Contract id="PHASE_BLOCK_FORMAT">
      Event-driven: optional event lines (0+ each) appear ONLY when their event happened. Mandatory closing lines: `ver` + `DONE` + Handoff.

      ```markdown
      #### <PhaseID>                                 <!-- or "#### <PhaseID> — re-run: <reason>" -->
      <!-- Event lines (optional; appended as events happen, in chronological order): -->
      - [x] `<ts>` intro `<Entity>` ← <reason>
      - [x] `<ts>` decision <key>=<value> ← <reason>
      - [x] `<ts>` tried <approach> → <result-or-why-abandoned>
      - [x] `<ts>` discovery <fact>
      - [x] `<ts>` insight <observation> → <spec-section>, <change>
      - [x] `<ts>` verified <tool>@<version> <one-line summary>    <!-- config kind only -->
      <!-- Closing lines (mandatory): -->
      - [x] `<ts>` ver <cmd> → pass|fail exit=<N>
      - [x] `<ts>` DONE
      **Handoff →** artifacts: [<paths>]; decisions: [<key=value, …>]; open: [<id: text, …>]
      ```

      Trivial phase (no events worth logging): 2 lines (`ver` + `DONE`) + Handoff. That is valid and preferred over padding.
    </Contract>

    <Contract id="HANDOFF_FORMAT">
      Compact, typed, single line at end of phase block:
      ```
      **Handoff →** artifacts: [path1, path2]; decisions: [key=value, key=value]; open: [id: text, id: text]
      ```
      Fields:
      - `artifacts` — files produced or modified by this phase (paths).
      - `decisions` — key facts the next phase or audit needs (e.g. `IdempotencyKey=introduced`, `module-system=esm`).
      - `open` — unresolved questions / risks / deferred sub-tasks (id + one-line). Empty list → `[]`.

      Free-form prose forbidden. Each field is an array (possibly empty).
    </Contract>

    <Contract id="ROUND_CLOSE_FORMAT">
      Emitted by orchestrator after the LAST phase of a Round. Phase agent does NOT write this block. Tracker sync is orchestrator's mechanical work — no `sync` log line (the work happens, not informationally noteworthy).
      ```markdown
      #### Round close
      - [x] `<ts>` DONE
      ```
    </Contract>

    <Contract id="BLOCKER_FORMAT">
      ```markdown
      - 🛑 `<ts>` BLOCKED: <one-line cause>
        - 🔗 axiom: AX_<NAME>
        - 💬 unblock: <concrete operator action>
      ```
      After this entry: phase Status → `[!] BLOCKED`; return BLOCKED to orchestrator. Stop.
    </Contract>

    <Contract id="RETURN_SUMMARY_FORMAT">
      JSON-like return to orchestrator:
      ```
      {
        "status": "DONE" | "BLOCKED" | "FAIL",
        "task_id": "<TSK-NN>",
        "phase_id": "<P<N>>",
        "kind": "<kind>",
        "artifacts": ["<path>", ...],
        "decisions": ["<key=value>", ...],
        "open": ["<id: text>", ...],
        "blocker_reason": "<if BLOCKED>"
      }
      ```
      `artifacts` / `decisions` / `open` mirror the **Handoff →** line — orchestrator threads them into the next phase's prompt.
    </Contract>
  </Output_Contracts>
</SddPhaseExecution>
