# Node Classification Gates

Use these gates before every candidate batch and before authoring the align payload requested by `next_action.input_schema`.
Align owns Node type, tag, graph, planned Section, and ownership classification. It does **not** write Section prose.

## Node Type Order

Answer in this order and stop at the first match:

1. **Action?** A large executable event / process with both:
   - scale: can support `planned_sections` with at least two distinct Section kinds, or contains at least one child Action;
   - process evidence: explicit steps, phases, trigger -> handling -> result, role collaboration, or repeatable plan. Parallel lists such as "three API modes" are not process evidence.
2. **Entity?** A concrete independent subject with retrieval value: deployable code, product/application/system, library/module/CLI/symbol, or an atomic term/pattern.
3. **Domain?** A container/scope that groups at least one child Node.
4. Otherwise do not create a Node; leave the material for compile as a Section under the owning Node.

Good examples:

| Type | Examples |
|---|---|
| `domain` | "X business domain", "Y technical area", "Z research topic" |
| `entity` concrete | `@acme/api-server`, `@acme/ui-kit` `Button`, "X sub-application" |
| `entity` term | "X identifier", "Y business metric", idempotency |
| `action` | "user submits X request end-to-end flow", "operator executes Y change flow", "team Z release flow" |

## Title and Source Heading Rules

Classify the Node by the evidence referent, not by the source file title, heading, or local section title. A source title is ordinary evidence just like body prose. It has no automatic right to become `node.title`, `aliases[]`, or `slug`.

After choosing `node_type`, choose the title to fit that type:

| Final type | Title shape |
|---|---|
| `entity` concrete | The concrete product, service, library, module, CLI, symbol, application, or system name. |
| `entity` term | The atomic concept or pattern name, without extra scope/process suffixes. |
| `domain` | The grouping scope that owns child Nodes. |
| `action` | The executable process / runbook / flow name that passed the Action Gate. |

Scope/process words in a source title are warning signals when proposed as an Entity title, not hard classification rules. Re-check the type/title when a proposed Entity title contains words such as "方案", "架构", "体系", "演练", "流程", "策略", "能力", "机制", "framework", "architecture", "system", "strategy", "process", or "drill". Keep the wording only when evidence shows it is the formal name of a concrete object or an atomic term.

Do not promote broad architecture/system/方案 content to `domain` just because it sounds like a scope. When the source has writable Sections but no resolvable current/existing child Nodes, use an Entity such as `[system]` or `[application]` and put the architecture facts in Sections. Use `domain` only when it groups child Nodes through `domain_gate.child_refs`.

Relation-only sources should not force title copying or dangling graph edges. Decide placeholder handling in this order:

1. If resolved current/existing child Nodes make the page a real grouping scope, preserve it as a no-write Domain.
2. If an explicit user-facing retrieval need or graph need makes the source/page identity valuable, and the title names an atomic concept or concrete object, preserve it as a no-write Entity with root-level `planned_sections: []`. This priority still applies when all child refs are unresolved/deferred; keep those target hints pending rather than writing dangling graph refs.
3. Otherwise, skip navigation-only / placeholder-only material and classify its coverable blocks, usually as `ignored`.

Do not put `planned_sections` inside `domain_gate`. A kept placeholder needs support: `context_only` block(s) with `visible_to`, owned/shared evidence, or finalized graph support. `ignored` blocks only dispose unused material and do not support close materialization by themselves. For Domain placeholders, write only resolved current/existing children in `domain_gate.child_refs`; if all children are unresolved/deferred relation clues, use `child_refs: []` and keep those target hints in pending relation refs. If the source names only an atomic concept and that term is useful on its own, prefer a concise term Entity title without scope/process suffixes.

For no-write placeholder summaries, describe only the preserved page identity and unresolved navigation clues. Do not say the Node "provides navigation/links/relations to X" unless those targets are resolved graph children or rendered links; say the source contains deferred navigation clues instead.

## Entity Tag Rules

Use `tags` to state what the Entity is. Legal combinations:

| Case | Tags |
|---|---|
| Runtime/code object | one A tag: `app`, `service`, `lib`, `cli`, `module`, or `symbol` |
| Product-analysis object | one B tag: `application` or `system` |
| Code + product object | one A tag plus one B tag |
| Pure term / pattern | only `term` |

`term` is mutually exclusive with A/B tags. React is `[lib]`, not `[lib, term]`; if a separate term entry is useful, create another Entity tagged `[term]` and let compile use Section-local `refers_to_nodes[]`.

## Action Gate

Use `node_type: action` only after the Node Type Order says action. Fill `action_probe` and `action_gate`.

`action_probe` still uses the five schema booleans, but the semantic bar is:

| Field | Meaning | Evidence rule |
|---|---|---|
| `has_steps_or_phases` | Process evidence exists: steps, phases, trigger -> handling -> result, role collaboration, or repeatable plan. | Hard requirement; support it from block evidence. |
| `has_actor_or_role` | A user, system, operator, service, or role performs the work. | May be inferred; record the source. |
| `has_outcome_or_goal` | The process has a target result, acceptance condition, or operational goal. | May be inferred; record the source. |
| `is_repeatable_or_planned` | The work is repeatable, scheduled, policy-like, or intentionally planned. | May be inferred; record the source. |
| `queries_answerable_with_refs` | The Node can answer how/when/who/what-to-do questions from cited blocks. | May be inferred; record the source. |

Do not emit an Action for a single sentence, a one-off conclusion, a short operation, or a parallel enumeration. Those become Sections under the owning Entity or Domain.

Action anti-examples:

| Candidate | Correct routing |
|---|---|
| "migrate to X tool" as one conclusion | `decision` Section under the owning Entity |
| "component X usage" as one sentence | `description` + maybe `example` under X |
| "submit -> validate -> generate" as one unexpanded sentence | `spec` Section under X/Y |
| "three API call modes" | `comparison`, `spec`, or `description` Section; not Action |

## Fake Entity Gate

A relationship-style title is only suspicious by itself. Downgrade or change type when at least **two** signals are true:

1. Title contains relationship language such as "X impact on Y", "Y under X", "Y side of X", "X migration", or "X collection".
2. No legal Entity tag fits.
3. The Node does not stand alone away from its upstream Node.

Repairs:

| Pattern | Repair |
|---|---|
| "X impact on Y" | Section under X with `refers_to_nodes: [Y]` |
| "Y under X condition" | Section under Y; X is a condition in the Section body |
| "X subsystem migration" | Action only if it clears the Action Gate; otherwise `decision` Section under X |
| "X error collection" / "X FAQ collection" | `faq` / `incident` Sections under X |

## Domain Gate

Use `node_type: domain` only for a scope that groups child Nodes. Fill:

| Field | Meaning |
|---|---|
| `scope_blocks[]` | Blocks that describe the scope boundary or grouping. |
| `child_refs[]` | Candidate ids, local refs, or final slugs for children in the scope. |
| `grouping_reason` | Why these children belong together under this domain. |

If a domain has no resolvable child refs, no clear grouping reason, or only one same-file child without a broader scope, do not emit a Domain. For navigation-only / placeholder-only sources with only deferred children, skip the Node after ruling out standalone retrieval or graph value for an atomic-term or concrete Entity; still classify that source's coverable blocks with a source-wide `ownership_groups[]` rule, usually `ignored` for pure placeholders. Emit an Entity only when evidence names an atomic term or concrete object and choose its Entity tag yourself. The CLI rejects invalid Domain gates; it does not auto-downgrade a Domain or choose fallback tags.

Scope-name titles such as "X 业务域", "Y 领域", "business domain", or "technical area" are a warning sign when proposed as Entity. Keep them as Entity only when the subject is an atomic term or concrete object; otherwise use Domain with `domain_gate.child_refs`.

## Inference Sources

`action_gate.inference_sources` is required and must be a structured object with four keys:

```yaml
inference_sources:
  actor:
    source_type: explicit-block
    evidence_blocks: [7a6f4c9d2e10]
    rationale: "The block names the operator role."
  outcome_or_goal:
    source_type: inferred-from-block
    evidence_blocks: [7a6f4c9d2e10]
    rationale: "The block describes recovery as the expected result."
  repeatability_or_plan:
    source_type: heading-and-block
    evidence_blocks: [7a6f4c9d2e10]
    rationale: "The runbook heading and ordered list indicate planned reuse."
  answerability:
    source_type: explicit-block
    evidence_blocks: [7a6f4c9d2e10]
    rationale: "The steps answer how the operation is performed."
```

Allowed `source_type` values:

| Value | Use when |
|---|---|
| `explicit-block` | The evidence block directly states the signal. |
| `heading-and-block` | The heading plus block text together support the signal. |
| `ref-node` | An existing or same-decision Node reference supplies the signal. Include `ref_nodes`. |
| `inferred-from-block` | The signal is inferred from block content. Keep the rationale short and concrete. |

Each source must include `rationale` when inferred and at least one of `evidence_blocks[]` or `ref_nodes[]`.

## Final Reflection

- Entity cannot pick a legal tag, or depends on its upstream title to make sense -> write it as a Section under the upstream Node or change type before submit.
- Action only supports one Section -> write it as a Section instead of an Action. The discriminator is scale, not the presence of "step" words.
- Action "steps" are parallel options/configs -> route to Entity `comparison` / `spec` / `description`.
- Domain has no children -> delete it or merge it into a larger Domain.
