← Files NaClARCHIVED FILE

skills/nacl-sa/resources/workflows/nacl-sa-ui/SKILL.md

13.1 KB · Oct 3, 2026 · 06:30 UTC

↓ Download file

---
name: nacl-sa-ui
description: |
  Design and verify NaCl UI architecture in the SA graph: form-domain mapping,
  component catalog, navigation components, and deterministic screen state
  machines. Use when verifying forms, creating UI components, defining
  navigation, authoring screen states, or says `/nacl-sa-ui`.
---

# NaCl SA UI For Codex

Work with UI architecture as graph data: `Form`, `FormField`, `Component`, and
their relationships to use cases and domain attributes. Russian is the default
language for user-facing SA descriptions unless the user explicitly requests
another supported language.

Read `../nacl-core/SKILL.md`, `../references/migration-rules.md`, and
`../references/verification-vocabulary.md` before using this workflow.

## Workflow

Commands:

- `verify [module]`: read forms and fields, then check that every input field
  has `MAPS_TO` a domain attribute.
- `components [module]`: identify repeated UI patterns and create reusable
  `Component` nodes with `USED_IN` edges.
- `navigation`: define menu, route, role access, ordering, and parent menu as
  navigation components.
- `state-machine UC-NNN | SCR-Name`: author or modify the deterministic state
  machine of one screen (`Screen`, `ScreenState`, `ScreenEvent`, reified
  `Transition`, `ScreenEffect`, minimal `AnalyticsEvent` sinks).
- `full [module]`: run verify, components, and navigation in order.

`verify` flow:

1. Load forms, fields, linked use cases, modules, field categories, and existing
   domain mappings.
2. Report orphaned forms and unmapped input fields.
3. Propose fixes: add missing `MAPS_TO`, mark a field as `display` or `action`,
   or create a missing domain attribute through the domain skill.
4. Stop before any write; run only read-only checks unless the user confirms a
   fix path.

`components` flow:

1. Analyze forms and fields for repeated patterns such as tables, filters, form
   layouts, file upload blocks, status badges, and feedback areas.
2. Propose `Component` nodes with type, description, props, and affected forms.
3. Stop before writing `Component` nodes and `USED_IN` edges.
4. Read back component usage after confirmed writes.

`navigation` flow:

1. Read modules, use cases, roles, forms, and actor edges.
2. Propose menu hierarchy, routes, role access, order, and parent menu.
3. Store navigation as `Component` nodes with navigation properties when
   confirmed.
4. **For every Form whose UseCase has `actor != SYSTEM`, capture each
   inbound nav-action site as a `HAS_INBOUND_ACTION` edge from the source
   Component to the Form (see "Form Spec Template" and "Graph Rule — UI
   Reachability" below).**
5. Verify routes point to existing forms or use cases and role access matches UC
   actors. Run the reachability query
   (`nacl-sa-ui/references/reachability.cypher` § 4 — `ui_reachability_blockers`)
   and refuse to leave this phase while any actor-triggered UC has no
   inbound nav-action from a reachable Component.

`state-machine` flow:

1. Read the UC context: forms, `EXPOSES` endpoints, existing screens, module.
   Stop if the UC is backend-only (`has_ui=false`). If a Screen already exists,
   load its machine (named query `sa_screen_machine`) — the run is a MODIFY.
2. Propose states, events, transitions, and effects as a transition table plus
   a Mermaid stateDiagram. Derive the Screen's PascalName from the form/UC
   noun-phrase (strip `scr-NNN-` prefixes, kebab→PascalCase:
   `scr-031-voice-recorder` → `VoiceRecorder`). Two canonical archetypes
   (templates, not a closed list): **data-loading screen** — Loading (initial)
   / Loaded / Empty / Error states, OnLoaded / OnLoadFailed / OnRetry events,
   four transitions, one `load` effect on the retry transition calling the
   UC's endpoint; **process screen** (recorder / wizard / pipeline) — Idle
   (initial) + one `busy`-kind state per pipeline stage + Completed / Failed,
   `mutate` effects on the stage transitions that hit the backend, and
   Failed→Idle on OnRetry legitimately carrying no effect. Effects are 0..n
   per transition — the validator enforces only that existing load/mutate
   effects CALL an endpoint. Stop for confirmation before writing.
3. Write with MERGE on stable ids (`SCR-*`, `SCRST-*`, `SCREV-*`, `SCRTR-*`,
   `SCREF-*`, `ANEV-*`): Screen with `HAS_SCREEN` parent and `RENDERS -> Form`
   (formless screens carry `formless=true`); exactly one `is_initial=true`
   state; reified transitions with exactly one same-screen
   `FROM_STATE`/`TO_STATE`/`ON_EVENT` each; effects with kind-required targets —
   load/mutate `CALLS -> APIEndpoint` (MERGE a provisional endpoint plus
   `EXPOSES` when none exists, and report it), navigate
   `NAVIGATES_TO -> Screen`, analytics `EMITS -> AnalyticsEvent`.
4. Bump `uc.spec_version`, then stamp staleness DIRECTED and TIGHT (same
   contract as `nacl-sa-feature` step 3g): the UC's `GENERATES` tasks plus
   tasks of UCs that transitively `DEPENDS_ON` it (`*1..5`) get
   `review_status='stale'` with `stale_origin` = the screen id; the
   directly-changed UC itself is stamped in a second statement. Never stamp
   via the broad undirected impact closure (measured 20x false radius).
   Report `count(DISTINCT ...)` per statement.
5. Re-check the machine against the L10 rules (determinism: shared
   `(from_state, on_event)` pairs must be all-guarded; reachability from the
   initial state; error states need an escape, user-triggered by convention
   `OnRetry`). Scope each check to this screen by pinning the
   `(scr:Screen {id: ...})` anchor (for orphan/parent checks filter by the
   `-{Screen}-` id infix). Resolve CRITICAL findings before completing.

Do not introduce labels that are absent from the SA schema. Navigation is a
component pattern unless the project schema explicitly defines another label.
Label-qualify `HAS_STATE` and `TRIGGERS` in every query — both names are shared
with the BA layer.

## Form Spec Template

Every Form node carries these required sections. The first three are
created by upstream skills; the fourth — Nav Actions — is the W7
addition and is required for any Form whose UseCase has
`actor != SYSTEM`.

| Section | Status | Edge | Owner |
|---------|--------|------|-------|
| Fields | required | `HAS_FIELD` | `nacl-sa-uc detail` |
| Domain mapping | required | `MAPS_TO` | `nacl-sa-uc detail` / `verify` here |
| Used-In Components | required | `USED_IN` | `components` here |
| **Nav Actions** | **required if actor != SYSTEM** | **`HAS_INBOUND_ACTION`** | **`navigation` here, Phase 3.3** |

### Nav Actions — required for actor-triggered UCs

For every Form whose UseCase has `actor != SYSTEM`, enumerate the
inbound action sites that expose it to the user: which screen, nav
item, global menu point, or sibling-page CTA carries the user-visible
affordance that opens this Form.

Each affordance is one `HAS_INBOUND_ACTION` edge from the source
`Component` to the `Form`, with properties:

- `affordance` — short kind label (`primary CTA`, `menu item`,
  `row-link`, `empty-state CTA`, etc.).
- `label` — exact visible text on the affordance (e.g. `New upload`).
- `updated` — write timestamp.

#### Worked example — project-beta missing-upload-button

Project-Beta UC-100 ("Upload audio") had a complete Form
(`FORM-Upload`) with fields, domain mappings, and `USED_IN` edges to a
rendering Component for `/upload`. Yet on production the catalog page
at `/catalog` had no upload button: the only way to reach `/upload`
was to type the URL. The Form spec was page-local and silent on
inbound nav-actions, so the reviewer could not see the missing button
from a diff.

The methodology fix: UC-100's Form spec must declare every inbound
affordance. For UC-100 the captured edges would be:

```
HAS_INBOUND_ACTION:
  - CMP-CatalogPage   →  FORM-Upload   affordance="primary CTA"        label="New upload"
  - CMP-NavSidebar    →  FORM-Upload   affordance="menu item"          label="Upload"
  - CMP-EmptyState    →  FORM-Upload   affordance="empty-state CTA"    label="Upload your first audio"
```

With those edges in the graph, the rule below would have caught the
missing button before the page shipped.

### Graph Rule — UI Reachability

An actor-triggered UseCase (actor != SYSTEM) without a
`HAS_INBOUND_ACTION` edge from a reachable Component is a blocker. A
reachable Component is one transitively reachable from any navigation
root via `parent_menu` / route mounting.

The Cypher template for the blocker query and the reachable-component
traversal lives at `nacl-sa-ui/references/reachability.cypher`. The
template publishes two queries:

1. `ui_reachability_blockers` — returns every (UC, Form) pair where
   actor != SYSTEM and the Form has no inbound `HAS_INBOUND_ACTION`
   from a reachable Component. Each row carries
   `reason ∈ { 'no-form', 'no-inbound-action', 'unreachable-component' }`.
2. `reachable_components_form_a` / `_form_b` — returns the transitive
   set of Components reachable from any navigation root.

This skill (sa-ui, Codex flavor) declares the rule and ships the
Cypher template. Consumers are out of scope here and unchanged by
this wave:

- `nacl-sa-validate` runs `ui_reachability_blockers` as an internal
  validator check; non-empty result forces validator `BLOCKED`.
  Override requires a signed exception (W4).
- `nacl-tl-review` (primary-owner exception declared in W7 scope_in)
  runs the same query scoped to the affected UCs and refuses
  APPROVED when any affected UC appears in the result.

Exemption flags recognised by sa-validate (consumer-side, not
implemented here):

- `UseCase.actor = 'SYSTEM'` — excluded by the query.
- `UseCase.has_ui = false` — no Form; rule does not apply.
- `UseCase.entrypoint_type IN ['deep-link-only', 'embed-only']` —
  intentional URL-only access (invitation links, third-party iframes);
  each requires a signed exception.

## Graph Contract

Use only schema-supported UI records: `Form`, `FormField`, `Component`,
`Form -[:HAS_FIELD]-> FormField`, `FormField -[:MAPS_TO]-> DomainAttribute`,
`Component -[:USED_IN]-> Form`,
`Component -[:HAS_INBOUND_ACTION { affordance, label, updated }]-> Form`,
the screen state machine shapes
(`UseCase -[:HAS_SCREEN]-> Screen -[:RENDERS]-> Form`;
`Screen -[:HAS_STATE]-> ScreenState`; `Screen -[:HAS_EVENT]-> ScreenEvent`;
`Screen -[:HAS_TRANSITION]-> Transition` with
`FROM_STATE`/`TO_STATE`/`ON_EVENT`;
`Transition -[:TRIGGERS]-> ScreenEffect` with `CALLS`/`NAVIGATES_TO`/`EMITS`),
and existing UC/form/role relationships. Do not create `NavigationRoute` or
other unsupported labels. The `HAS_INBOUND_ACTION` edge is the W7 addition
required for actor != SYSTEM forms; see "Form Spec Template" below.

`verify` is read-only until the user confirms a repair. It must distinguish
input fields from display and action fields using `field_category`; missing
`field_category` should be reported as a validation metadata issue rather than
silently ignored.

`components` and `navigation` must show component ids, component types,
properties, route/menu metadata, linked forms, and role-access evidence before
writes. After confirmed writes, read back component usage and route targets, and
verify role access against `UseCase -[:ACTOR]-> SystemRole` where available.

## Capabilities

### May Do

- Read forms, fields, use cases, roles, components, and domain mappings.
- Verify form-domain traceability and propose repairs.
- Create or update components and navigation components after confirmation.
- Preserve the trace chain from BA workflow step to UC, form field, domain
  attribute, and BA entity when available.

### Must Not Do

- Modify root-level `nacl-*` source folders.
- Write graph data without confirmation.
- Create UI labels or relationship types not supported by the schema.
- Treat display or action fields as data inputs unless the graph marks them so.
- Select or constrain the runtime.

### Conditional Tools And Actions

- Graph reads and writes require available graph tooling.
- Schema checks require graph introspection or readable schema files.
- Domain repairs may require the domain skill or a confirmed direct graph write.

### Blocked Or Unverified Reporting

- Use `BLOCKED` when graph tooling, schema, forms, domain attributes, role data,
  or confirmation is missing.
- Use `PARTIALLY_VERIFIED` when UI writes complete but only some mappings or
  route checks can be read back.
- Use `UNVERIFIED` when UI traceability cannot be checked against graph state.

## Source Comparison

- Source Claude skill path: `../../nacl-sa-ui/SKILL.md`

### Preserved Methodology

- `verify`, `components`, `navigation`, `state-machine`, and `full` commands.
- FormField to DomainAttribute mapping checks.
- Component catalog and `USED_IN` relationships.
- Navigation represented in graph data.
- Deterministic screen state machines with reified transitions, directed
  staleness stamping, and `spec_version` bump.
- Confirmation gates before writes.

### Removed Claude Mechanics

- Runtime routing fields in frontmatter.
- Hard-coded graph tool availability.
- Slash-command-only invocation wording.
- Source runtime assumptions as active instructions.

### Codex Replacement Behavior

- Treat graph and schema access as conditional.
- Use schema-supported UI graph shapes only.
- Stop for confirmation before component or mapping writes.
- Report validation through the closed vocabulary.

SHA-256: 314a9d9ab88094bd00ecdd521fdc020c4759544cbece1a7a3c2993580d1642ba