# Architecture

CM Workflow has one workflow implementation and two runtime entry surfaces.

```mermaid
flowchart LR
    Codex["Codex $cm-*"] --> Skills["skills/cm-*/SKILL.md"]
    Claude["Claude Code /cm-*"] --> Skills
    Legacy["macOS/Linux /cm:* alias"] --> Wrappers["compat/claude-commands/"]
    Wrappers --> Skills
    Skills --> Context["runtime/project-context.md"]
    Skills --> Orchestration["runtime/orchestration.md"]
    Skills --> Review["runtime/review.md"]
    Skills --> TaskGates["runtime/task-gates.md"]
    Skills --> Logging["runtime/logging.md"]
    Skills --> External["runtime/external-expert.md"]
    RuntimeJS["runtime/js/cm-ai: shipped source + active N1/N2 admission"]
    Skills --> References["flow references: N1-N8 / PRD modes"]
    Skills --> Templates["templates/"]
    Skills --> Specs["requirements / design / tasks / optional test-cases"]
    Specs --> Target["target code repository"]
    External --> Provider["optional external browser / manual handoff"]
    Provider --> ExternalEvidence["specs .external/"]
    Logging --> Writer["scripts/cm-log-event.mjs JS authority"]
    Writer --> LockAdapter["cm-log-event.py platform lock adapter"]
    Writer --> ProjectLog["specs 运行日志.jsonl + .cm-run.json/.lock"]
    Writer --> GlobalLog["~/.cm-workflow/logs private mirror"]
    Config["optional .cm-workflow.yml/.json"] --> ConfigCheck["scripts/cm-workflow-config.mjs"]
    ConfigCheck --> Routing["runtime/workflow-routing.md"]
    Routing --> Skills
    TaskGates --> GateCheck["scripts/cm-task-gate.mjs JS authority"]
    GateCheck --> GateLock["cm-task-gate.py completion lock adapter"]
    GateCheck --> Reviews["specs .reviews handoff + verdict evidence"]
    Check["scripts/cm-check-runtime.sh"] -. validates .-> Skills
    Check -. validates .-> Wrappers
    Check -. validates .-> RuntimeJS
```

## Sources of truth

- Each numbered feature's `tasks.md` is the authoritative business-task state.
- An optional project `.cm-workflow.yml`/`.yaml`/`.json` selects finite workflow
  profiles, role adapters, model aliases, and test/delivery policies. It is
  configuration, not permission or task state; missing configuration means the
  built-in defaults remain active. The contract lives in
  `runtime/workflow-config.md`; node projection and route-state semantics live in
  `runtime/workflow-routing.md`.
- `.cm-specs-status` binds approval to a full requirements/design/tasks/test semantic manifest;
  only N5/N6 task and AC completion markers are normalized so an interrupted run can resume;
  `.cm-status.json`, `.cm-run.json`, `运行日志.jsonl`, `.reviews/`,
  `METRICS.md`, and `LESSONS.md` are the durable audit and recovery artifacts.
- The user-global `~/.cm-workflow/logs/` tree is a reconstructable local mirror,
  not an authoritative state store or telemetry endpoint.
- Codex plans, OMX state, subagent threads, and Claude task panels are
  reconstructable mirrors.
- Per-feature `test-cases.json` is the optional AI-readable test intent.
  Execution results stay in `.reviews/`; no competing result database is added.
- N3 implementation handoffs and N4 verdicts also stay in `.reviews/` as
  content-bound evidence. `runtime/task-gates.md` validates their transition; they
  never replace the checkbox state in `tasks.md`.

## Runtime compatibility

Full `cm-check` first runs `scripts/cm-check-update.mjs`: query the fixed public
npm package, compare stable versions, download the exact version with lifecycle
scripts disabled into a temporary directory, and reuse the existing installer.
It recognizes the Codex personal managed installation/cache and the Claude managed
root, checks the installed version, then selects that root for mechanical and
semantic checks. Source checkouts and other package managers are not overwritten;
offline results retain an explicit freshness gap. Supported automatic writes are
macOS Codex and POSIX Claude; other platforms report the installation limitation.
The update lock serializes this preflight only; callers must finish other active
CM tasks before upgrading. The host and low-level checkers stay read-only, so
installer/CI checks cannot trigger a recursive update or drift their snapshot.

Codex discovers the plugin through `.codex-plugin/plugin.json` and calls Skills
directly. Claude Code invokes the same Skills as `/cm-*` on every platform.
The macOS/Linux installer also maps the three-line compatibility wrappers to
the historic `/cm:*` aliases. Windows uses `/cm-*` because `:` is not legal in
native filenames. Workflow assets resolve relative to the active Skill; no flow
may hardcode a Codex cache path or treat `~/.claude` as the universal source
root.

`runtime/js/cm-ai/` is the sole source root for the accepted JS orchestration
modules. `experiments/js-orchestration/` keeps thin re-exports plus historical
fixtures so prior evidence paths remain readable. The active `cm-ai` Skill owns
conversation/tool orchestration and invokes the shared JS gates directly; the
dormant full-host factory is not a prerequisite and Claude does not need a second
adapter protocol. Platform installation evidence and real task dogfood remain
separate F09 work.

The npm package includes root release notes through the `package.json` files
allowlist. The Codex installer copies `CHANGELOG.md` alongside `README.md` and
`VERSION`; `scripts/cm-release-smoke.sh` checks that the installed changelog
matches the source bytes in a disposable installation.

## Review model

Business-map maintenance shares `skills/codebase-context/references/writeback.md`.
Feature development synchronizes maps in the final task before N4; bug fixes do so
before their independent review. Both reuse the current diff and investigation,
update only affected sections, and verify the reviewed bytes at closeout. A missing
map gets explicitly partial coverage, unless project policy selects an existing
architecture document or prohibits persistence. No full scan is triggered. The
map paths stay inside approved write scope (including fixed JS repair scope);
semantic completeness is checked by the Skill/reviewer, not inferred by JS gates.
At task entry, the shared context contract checks the relevant map against current
code and working-tree changes. Age alone does not trigger a rescan; missing or
stale coverage is rebuilt only for the affected chain before business-code edits.
Existing maps retained at the same path travel as read-only review requirements;
new or deleted map paths travel in the actual diff. Final documentation sync aggregates all tasks
in the active specs batch, including earlier uncommitted changes, without granting
write access to those earlier tasks. Map gaps trigger targeted investigation first;
broader loading follows demonstrated impact or unresolved boundaries, not file count.

Implementation cannot be marked complete without task-scoped review evidence.
The preferred channel is a fresh Codex subagent or independent thread, followed
by an isolated read-only Codex CLI review. If both are unavailable, new
implementation pauses and existing work remains pending review. `self-degraded`
is diagnostic/historical evidence only; it cannot authorize new completion.
N3 must first produce a schema-valid `ready_for_review` handoff. N4 owns the
`approved | changes_requested | blocked` verdict, and N5 runs the shared gate
instead of treating any matching filename as approval. At most two attempts are
allowed. N5 requires both `approved` and `independent: true`, preserves task-file
line endings, and changes only the target checkbox. Post-review changes to code,
tests, or execution instructions need new evidence, including suggestions made
during N5 lesson recording; N5 itself records suggestions rather than implementing
them. Historical completed tasks are not automatically reopened.
Parallel writers also pass the same gate tool with distinct registered
worktrees and branches; failure downgrades execution to serial.

This gate checks declarations and content-bound review evidence; it does not make
one provider's result evidence for another provider. Codex and Claude both keep
conversation orchestration in the active Skill and use the same JS gates, while a
fresh context supplies independent review. Real durable N1–N8 dogfood and authorized
installation evidence remain later work; no Claude-native adapter is required.

## External reasoning model

`external-expert` is an independent utility Skill for product deliberation,
problem or academic research, diagnosis, test design, and critique. CM defaults
to EXPLICIT activation. A user can opt only the current invocation into AUTO,
which routes to LOCAL, CONSULT, or VERIFY; HANDOFF is explicit-only. A global
router cannot silently enable CM AUTO. The local main agent chooses outbound
context, applies accepted changes, and runs verification.

Requests and raw responses live under `.external/`; they cannot satisfy N4.
If an external conversation contributed to a plan, diagnosis, tests, or patch,
it is an authoring channel and is ineligible to review the same work.

Before browser dispatch, the runtime routes visible modes through
`Pro → Extra High → High → SKIPPED`. Fallback inside this chain is automatic;
Medium and Instant are excluded. `SKIPPED` sends nothing and returns control to
the local workflow. An explicit strict-Pro request blocks when Pro is missing.
Task routing is a separate earlier gate; AUTO never authorizes local-file
transmission and mixed-task implementation remains local.

## Logging model

`runtime/logging.md` defines one event envelope for Codex and Claude Code.
`scripts/cm-log-event.mjs` writes the specs-local `运行日志.jsonl` first, mirrors
the same event into a per-run global JSONL file, and maintains an append-only
`index.jsonl`. `.cm-run.json` lets a new session reuse an active `run_id`; a
completed run causes the next invocation to rotate to a new id. Project and
global standard-library file locks held by the thin Python platform adapter
serialize concurrent writers, while a
deterministic event id deduplicates an otherwise identical retry.

The project log is authoritative. If the global mirror fails, a specs-backed
workflow records a `degrade` event locally and continues. A global-only utility
has no safe fallback and fails explicitly. Global directories and files use
private owner-only permissions where the operating system supports POSIX modes.
The envelope contains operational metadata only; prompts, responses, source
content, external conversation links, and credentials stay out of it.

Long-running desktop and browser work emits event-based progress checkpoints,
not a timer-driven heartbeat. Temporary profiles, processes, aliases, worktrees,
and fixtures use paired resource events; an unmatched acquisition blocks the
next task or run completion. Each acquisition has a unique run-local resource
id, so a delayed cleanup cannot close a later resource.

## Testing model

`cm-prd` can generate one `test-cases.json` per behavior-bearing feature.
`cm-ai` consumes logic cases during task review and browser cases during QA.
`cm-test` is a separate, default-read-only entry for already implemented
features. Bare `cm-test` compares committed HEAD with the detected main branch
through `runtime/js/cm-test/branch-impact.mjs`, then the shared test host requests
read-only business impact and regression analysis. It pins both commits, inventories
all tree differences (including main-only changes), reads committed maps/source,
and discloses missing coverage and unfetched tracking refs. Empty differences skip
semantic work; ANALYZED/PARTIAL/NO_CHANGES never mean execution PASS. Explicit
targets retain the existing test modes. Its `--generate-cases` mode reads existing code and writes a validated
inferred draft, then stops before execution. Test failures can be handed to
`cm-fix` only by an explicit user decision.

## Incremental unit coverage

After the immutable branch-impact run, cm-test invokes `scripts/cm-unit-coverage.mjs`
with a trusted project command. `runtime/js/cm-test/unit-coverage.mjs` intersects
fresh LCOV/Istanbul evidence with committed changed lines, or an approved task
working-tree scope before review. Missing material never becomes 100% coverage.
Explicit test supplementation uses prepare/verify source snapshots and exact
test paths; verification returns REVIEW_REQUIRED, with independent review still
required. N3 and cm-fix reuse this check before their final handoff. No coverage
tool installation, product repair, commit or release is implied.

## Security scan entry

`skills/cm-security` delegates bounded snapshot scanning to `scripts/cm-security.mjs`
and `runtime/js/cm-security/scan.mjs`. It reuses cm-test main-ref selection without
fetching, includes tracked working/index changes, and keeps optional Gitleaks,
Semgrep local rules and OSV offline scanning behind an adapter. Source and project
scanner configuration are never executed. Symlinks/protected paths/limits are explicit
gaps. The current host reviews business boundaries and checks the source digest again;
scanner output is candidate evidence, never a task-completion or release gate.
