← Files NaClARCHIVED FILE
skills/nacl-sa/resources/workflows/nacl-sa-validate/SKILL.md
15.8 KB · Oct 5, 2026 · 18:29 UTC
--- name: nacl-sa-validate description: | Validate NaCl SA graph consistency, connectivity, requirements, form-domain traceability, UC-form coverage, cross-module rules, feature requests, staleness closure, decision provenance, screen state machines, behavior slices, domain error taxonomy, cache & degradation policies, and BA-to-SA coverage. Use when checking SA quality or says `/nacl-sa-validate`. --- # NaCl SA Validate For Codex Validate the SA graph without writing to it. This workflow reports findings and coverage only; repairs belong to the relevant SA skill and require confirmation. Read `../nacl-core/SKILL.md`, `../references/migration-rules.md`, and `../references/verification-vocabulary.md` before using this workflow. ## Goal Compatibility This skill can be a target behind `nacl-goal` only through the `validate:module:<MOD-ID>` alias. Reference `../nacl-goal/SKILL.md` and `../references/goal-codex-contract.md`. Codex itself must not claim that Anthropic `/goal` ran unless the runtime exposes it and evidence exists. Load [`the packaged validate proof method`](../../nacl-goal/checks/validate.sh) as an internal reference only; it is not a project-cwd command. Validation truth is surfaced through GOAL_PROOF. Use the closed Codex status vocabulary when the wrapper cannot run. ## Workflow Levels: - `internal`: SA-only checks. - `ba-cross`: BA-to-SA traceability checks. - `full`: internal plus BA-to-SA checks. - Scoped validation may limit checks to specific modules, use cases, entities, or feature requests when the user provides scope. Pre-flight: 1. Verify graph read tooling. 2. Count canonical SA nodes and report whether the graph has data. The canonical set includes the SA-extension labels: `Decision`, the screen-machine labels, `Slice`, `DomainError`/`ErrorPresentation`, `CachePolicy`/`DegradationRule`, and `APIEndpoint`; a future L14+ level must extend this set in the same change. 3. Detect schema drift by comparing labels and relationship types with the SA schema when introspection is available. Known neighbor-layer labels (BA family incl. `EntityState`/`GlossaryTerm`/`SystemContext`; TL family `Task`/`Wave`/`IntakeItem`; legacy `RuntimeContract`) and zero-count constraint-registered label tokens are NOT drift findings. 4. Check BA layer availability before BA-to-SA levels. When `full` is requested but the BA layer is empty, run the complete internal set (L1-L13) and skip the BA-to-SA cross-checks with a warning in the report. 5. Audit exemption properties used by deeper checks: `has_ui`, `system_only`, `shared`, `internal`, `field_category`, and `anchor_exempt` (L3.7). Internal checks: - L1 data consistency: required ids, names, property types, duplicate ids, and orphan nodes. - L2 connectivity: modules contain use cases and entities, entities have attributes, enums connect to attributes, and core edges are present. - L3 requirements: use cases have requirements, requirements are typed and linked, and BA rules mapped to requirements are not orphaned. L3.7 (CRITICAL): every must-anchor requirement (class functional|validation|behavioral|interface, read as `coalesce(rq.rq_type,rq.req_type,rq.type,'unknown')` — real graphs store the class in any of the three) has a `REALIZED_BY` edge to the step/field/form that implements it — `functional`/`behavioral` -> `ActivityStep`, `validation` -> `FormField`, `interface` -> `Form`|`Screen`; the overloaded reserved `type` values (nfr|adr|question|assumption) and nodes flagged `anchor_exempt=true` are exempt. L3.7b (WARNING) cross-checks the target label against the class; L3.8 (WARNING, opt-in once any REALIZED_BY exists) flags System steps no requirement realizes. - L4 form-domain traceability: input fields have `MAPS_TO`, attributes used by forms exist, and internal attributes are exempt only when flagged. - L5 UC-form validation: UI use cases have forms, user steps reference forms when appropriate, and forms are linked to use cases. - L6 cross-module consistency: entities are owned by one module unless marked shared, relationships crossing modules are intentional, and dependencies are recorded. - L7 feature request consistency: `FeatureRequest` ids are collision-free, linked UCs exist, and requested new or modified scope is traceable. - L8 staleness closure: no node carries `review_status='stale'` (read with `coalesce(n.review_status,'current')`). A stale node is a downstream of an upstream change that was never re-synced; `stale_origin`/`stale_since` give the lineage. CRITICAL. In scoped runs, restrict to the changed node's dependents. - L9 decision provenance: every active `FeatureRequest` has `IMPLEMENTS -> :Decision`; every non-superseded `:Decision` has a `JUSTIFIES` edge and a non-empty `rationale`; superseded decisions carry `status='superseded'`. L9.1–L9.3 CRITICAL, L9.4 WARNING. L9.1 exempts grandfathered FRs via `coalesce(fr.decision_exempt,false)=false`; L9.5 (INFO) lists grandfathered FRs so the debt stays visible. Decisions are the graph-native "why" — never stored as standalone markdown. Closing this gap on a pre-provenance project follows the provenance-gap-closure runbook (honest backfill from the FR's own recorded rationale; grandfather only when none is recoverable). - L10 screen state machines (SA-extension connectivity): no orphaned `Screen`/`ScreenState`/`ScreenEvent`/`Transition`/`ScreenEffect`/`AnalyticsEvent` nodes; every extension node has its required parent edge (`HAS_SCREEN`, `HAS_STATE`, `HAS_EVENT`, `HAS_TRANSITION`, `TRIGGERS`, `EMITS`); every Screen has `RENDERS -> Form` (exempt via `coalesce(scr.formless,false)=false`); load/mutate effects have `CALLS -> APIEndpoint`, navigate effects `NAVIGATES_TO -> Screen`, analytics effects `EMITS -> AnalyticsEvent`; every reified Transition has exactly one same-screen `FROM_STATE`/`TO_STATE`/`ON_EVENT`; no two transitions share `(from_state, on_event)` unless all are guarded (determinism); exactly one `is_initial=true` state per screen and every non-initial state is reachable from it; error states have an escape transition (exempt via `coalesce(st.terminal,false)=false`; missing user-triggered escape is WARNING); effect edges target correct labels; kind vocabularies are canonical (`state_kind` ∈ initial|loading|busy|content|empty|error, `event_kind` ∈ user|system|lifecycle, `effect_kind` ∈ load|mutate|navigate|analytics). A graph with zero Screen nodes passes L10 cleanly. Label-qualify every query — `HAS_STATE` and `TRIGGERS` names are shared with the BA layer. - L11 behavior slices (SA-extension connectivity): no orphaned `Slice` nodes; every Slice has its parent `(:UseCase)-[:HAS_SLICE]->`; every Slice has at least one behavioral anchor — `COVERS -> ScreenState|Transition` and/or `(sl:Slice)-[:CALLS]-> APIEndpoint` (no exemption flag by design: anchorless behavior text belongs in `UseCase.acceptance_criteria`, not in a node); COVERS targets belong to a screen of the slice's own UC; every slice of a planned UC (one that `GENERATES` tasks) has `VERIFIED_BY -> Task` owned by that UC (self-healing: `nacl-tl-plan` re-links on re-plan); `VERIFIED_BY` and `CALLS` targets carry correct labels; no slice has an empty `then` (CRITICAL — the unverifiable-behavior failure, mirror of the L9.3 empty rationale); `slice_kind` ∈ happy|alternate|error|edge (WARNING); machine elements of slice-adopting UCs not covered by any slice are WARNING; a UC with slices but no happy-kind slice is INFO. A graph with zero Slice nodes passes L11 cleanly. Label-qualify `CALLS` by source — the name is shared with `ScreenEffect -> APIEndpoint`. - L12 domain error taxonomy (SA-extension connectivity): no orphaned `DomainError`/`ErrorPresentation` nodes; every DomainError has its parent `(:Module)-[:HAS_ERROR]->` and ≥1 incoming `(api:APIEndpoint)-[:MAY_RAISE]->` (no exemption flag by design: an error observable at no API surface is an implementation detail, not a domain error; provisional endpoints satisfy the anchor); every ErrorPresentation has its parent `(:DomainError)-[:PRESENTED_AS]->` and ≥1 incoming `(st:ScreenState)-[:SHOWS]->`; `HANDLES` runs ScreenState -> DomainError and obeys the channel rule — the handling state's screen has a `ScreenEffect-CALLS` to an endpoint that MAY_RAISE the error (deliberately NO same-UC rule: errors are shared module vocabulary); MAY_RAISE / PRESENTED_AS / SHOWS targets carry correct labels; SHOWS closes the triangle (a state never shows a presentation of an error it does not handle); no blank `DomainError.code` (the API-envelope join key) or `ErrorPresentation.message` (user-language text, never the internal code; for `silent` presentations it documents the observable absence) — both CRITICAL; `error_kind` ∈ validation|not_found|conflict|permission| rate_limit|external|internal and `presentation_kind` ∈ toast|banner|inline| modal|fullscreen|silent (WARNING); errors raisable through a screen's own calls that no state handles are WARNING; handled errors with no shown presentation are WARNING; error-kind slices covering error states that handle no catalogued error are INFO. A graph with zero DomainError nodes passes L12 cleanly. All five edge names are unshared (no label-qualification hazard, unlike L10/L11). - L13 cache & degradation policies (SA-extension connectivity): no orphaned `CachePolicy`/`DegradationRule` nodes; every CachePolicy has its parent `(:Module)-[:HAS_CACHE]->` (the cache catalog is module-scoped shared vocabulary, like the error catalog) and ≥1 outgoing `(cp)-[:CACHES]->(:APIEndpoint)` (no exemption flag by design: a policy caching no surface is dead vocabulary; provisional endpoints satisfy the anchor); every DegradationRule has its parent `(:UseCase)-[:HAS_DEGRADATION]->` (rules are UC-scoped behavior, like slices — deliberately asymmetric to the module-scoped catalog) and ≥1 anchor — `ON_ERROR -> DomainError` and/or `DEGRADES_TO -> ScreenState` (no exemption; an anchorless rule is unreachable prose); error-triggered rules (`trigger_kind='error'`) REQUIRE `ON_ERROR`; `DEGRADES_TO` targets a state of a screen of the rule's OWN UC (same-UC rule), and for error-triggered rules the target's screen must actually call (via `ScreenEffect-CALLS`) an endpoint that MAY_RAISE one of the rule's ON_ERROR errors (channel rule); HAS_CACHE / CACHES / HAS_DEGRADATION / ON_ERROR / DEGRADES_TO targets carry correct labels; no blank `invalidation_kind` (the load-bearing cache contract — when the cache stops lying), no `ttl`-kind policy without `ttl_seconds`, no blank `behavior` (the observable degraded behavior, mirror of `slice.then`) — all CRITICAL; `storage_kind` ∈ memory|local_storage|indexed_db|cache_api| http|server|cdn, `invalidation_kind` ∈ ttl|event|manual|session|never, `trigger_kind` ∈ error|offline|capability, `fallback_kind` ∈ cached_data| static_content|alternate_provider|alternate_ui|skip_unit|backoff (WARNING); a backoff fallback on an explicitly `retryable=false` error is WARNING (retryable consistency — the consumer of the Phase-3 groundwork); cached surfaces whose retryable/external errors no rule degrades are WARNING (anchored on CACHES, so error-only graphs stay silent); `cached_data` rules that meet no CachePolicy through their errors' raisers or their screen's calls are INFO; two same-storage policies on one endpoint are WARNING. A graph with zero CachePolicy/DegradationRule nodes passes L13 cleanly. All five edge names are unshared (second phase in a row). BA-to-SA checks: - XL6: automated BA workflow steps are covered by `AUTOMATES_AS` use cases, and non-BA UCs are explicitly marked system-only when applicable. - XL7: BA entities and attributes are realized as domain entities and attributes, with external documents handled explicitly. - XL8: BA roles map to system roles, and infrastructure-only roles are flagged. - XL9: BA business rules are implemented by requirements or marked out of scope. Reporting: - For each level, report check counts, findings grouped by severity, coverage metrics, and recommended repair skill. - Overall verification status must use only `VERIFIED`, `FAILED`, `PARTIALLY_VERIFIED`, `BLOCKED`, `NOT_RUN`, or `UNVERIFIED`. - Use `NOT_RUN` for intentionally skipped levels and include the reason. - Use `BLOCKED` for missing graph access, missing schema, unavailable BA layer for requested BA-to-SA checks, or absent required scope. ## Severity And Result Semantics Validation never writes graph data or files. Migration or repair Cypher may be shown as a recommendation only, and must be executed by another confirmed workflow. Severity groups: - `CRITICAL`: broken traceability, missing mandatory relationships, duplicate ids, dangling scope, or schema drift that blocks TL planning. - `WARNING`: incomplete optional coverage, unmapped BA data, missing exemption flags, or readiness gaps that can be intentionally deferred. - `INFO`: statistics, intentionally skipped checks, or advisory cleanup. Overall status calculation: - `FAILED` when any requested level has unresolved `CRITICAL` findings. - `PARTIALLY_VERIFIED` when some requested levels run but others are `BLOCKED` or `NOT_RUN`, or when BA-to-SA checks cannot run for missing BA data. - `VERIFIED` only when every requested level ran and no `CRITICAL` findings remain. - `BLOCKED` when validation cannot start because graph read access, schema data, or required scope is missing. - `UNVERIFIED` when the result cannot be checked against graph state. Use named validation and SA query expectations where available, including `sa_uc_full_context`, `sa_domain_model`, `sa_form_domain_mapping`, `sa_module_overview`, `sa_uc_dependencies`, `sa_statistics_summary`, `sa_readiness_assessment`, handoff coverage queries, and validation queries such as `val_orphaned_form_fields`, `val_uc_without_requirements`, `val_entity_without_uc`, `val_disconnected_nodes`, and `val_ba_sa_consistency`. ## Capabilities ### May Do - Read SA and BA graph data for validation. - Run schema, consistency, connectivity, traceability, and coverage checks. - Produce a markdown validation report to the user. - Recommend the next NaCl skill for repairs. ### Must Not Do - Modify root-level `nacl-*` source folders. - Write graph data or project files. - Repair findings during validation. - Claim a check ran when tooling or data was unavailable. - Select or constrain the runtime. ### Conditional Tools And Actions - Graph validation requires graph read tooling. - Schema drift checks require graph introspection or readable schema files. - BA-to-SA checks require BA graph data. - Scoped validation requires resolvable scope ids. ### Blocked Or Unverified Reporting - Use `BLOCKED` when required graph tooling, schema, BA data, or scope is missing. - Use `PARTIALLY_VERIFIED` when some requested levels run and others are `NOT_RUN` or `BLOCKED`. - Use `UNVERIFIED` when a result cannot be checked against graph state. ## Source Comparison - Source Claude skill path: `../../nacl-sa-validate/SKILL.md` ### Preserved Methodology - Read-only validation boundary. - Pre-flight graph and schema checks. - Internal SA levels L1 through L13 (L8 staleness closure, L9 decision provenance, L10 screen state machines, L11 behavior slices, L12 domain error taxonomy, L13 cache & degradation policies). - BA-to-SA coverage levels XL6 through XL9. - Exemption-property handling for validation filters. ### Removed Claude Mechanics - Runtime routing fields in frontmatter. - Hard-coded graph tool availability. - Source-environment status names in active reporting. - Slash-command-only invocation wording. ### Codex Replacement Behavior - Use graph reads only when available. - Map final outcomes to the closed verification vocabulary. - Report skipped and unavailable levels honestly. - Leave repairs to confirmed follow-up workflows.
SHA-256: 00da4073a99157f16fb69d8a0e8c4f719aa01fab858275878008d679dba27417