/nacl-sa-finalize -- Specification Finalization (Graph)
SkillDev toolsFinalize specification via Neo4j: statistics, glossary, ADR, traceability matrix, readiness assessment. All computed from graph queries.Use when: finalize spec with graph, generate statistics, or the user says "/nacl-sa-finalize".
Available today. Use it from your connected AI after setup.
No other account needed.
Add ahel to your AI once: Claude, ChatGPT, Cursor, Claude Code or Codex. Then ask it to use this.
Then ask your AI: use the /nacl-sa-finalize -- Specification Finalization (Graph) skill
What this skill tells your AI
The instructions your AI receives, as published by itsalt/nacl in nacl-sa-finalize/SKILL.md and read by ahel’s review.
Purpose
Finalize the specification by computing all summary artifacts from Neo4j aggregation queries:
statistics summary, glossary extract, ADR records, traceability matrix, and readiness assessment.
No file reading -- everything is aggregated from the graph. Data stays in the graph and is
viewable via /nacl-render or /nacl-publish.
Shared references: nacl-core/SKILL.md
Neo4j Tools
| Tool | Usage |
|---|---|
mcp__neo4j__read-cypher | All aggregation queries (statistics, glossary, readiness, traceability) |
mcp__neo4j__write-cypher | Create/update :Decision nodes + JUSTIFIES edges; backfill legacy Requirement{type:'adr'} → :Decision |
mcp__neo4j__get-schema | Introspect current graph schema before finalization |
Modes
Mode full (default)
Full finalization: all five phases sequentially.
When: After successful validation (/nacl-sa-validate full).
Mode module
Finalize a single module (scoped statistics + readiness).
When: After completing work on one module.
Parameter: module -- module ID (e.g. mod-orders).
Mode stats-only
Statistics and readiness only -- no ADR creation, no glossary update.
When: User wants to see current progress without modifying the graph.
Workflow Overview
+-----------------+ +-----------------+ +-----------------+
| Phase 1 | | Phase 2 | | Phase 3 |
| Statistics |--->| Glossary + |--->| Traceability |
| Summary | | ADR | | Matrix |
+-----------------+ +-----------------+ +-----------------+
|
v
+-----------------+ +-----------------+
| Phase 5 | | Phase 4 |
| Report to |<---| Readiness |
| User | | Assessment |
+-----------------+ +-----------------+
Pre-flight Checks
- Run
mcp__neo4j__get-schemato confirm the graph is populated - Verify Module nodes exist:
MATCH (m:Module) RETURN count(m) AS cnt- If cnt = 0 -> STOP: "No modules in graph. Run /nacl-sa-architect first."
- Verify UseCase nodes exist:
MATCH (uc:UseCase) RETURN count(uc) AS cnt- If cnt = 0 -> WARN: "No use cases found. Statistics will be incomplete."
- If mode =
module, verify the module exists:MATCH (m:Module {id: $moduleId}) RETURN m- Not found -> STOP: "Module {moduleId} not found in graph."
Phase 1: Statistics Summary
Goal: Compute aggregate counts across all specification node types.
Query: sa_statistics_summary
Source: graph-infra/queries/sa-queries.cypher
MATCH (m:Module) WITH count(m) AS modules
MATCH (uc:UseCase) WITH modules, count(uc) AS ucs
MATCH (de:DomainEntity) WITH modules, ucs, count(de) AS entities
MATCH (da:DomainAttribute) WITH modules, ucs, entities, count(da) AS attributes
MATCH (f:Form) WITH modules, ucs, entities, attributes, count(f) AS forms
MATCH (ff:FormField) WITH modules, ucs, entities, attributes, forms, count(ff) AS fields
MATCH (sr:SystemRole) WITH modules, ucs, entities, attributes, forms, fields, count(sr) AS roles
MATCH (rq:Requirement) WITH modules, ucs, entities, attributes, forms, fields, roles, count(rq) AS requirements
MATCH (c:Component) WITH modules, ucs, entities, attributes, forms, fields, roles, requirements, count(c) AS components
RETURN modules, ucs, entities, attributes, forms, fields, roles, requirements, components;
Additional counts (run separately)
Enumerations:
MATCH (en:Enumeration) RETURN count(en) AS enumerations;
ADRs:
MATCH (rq:Requirement {type: 'adr'}) RETURN count(rq) AS adrs;
Open questions (if stored as Requirement with type='question'):
MATCH (rq:Requirement {type: 'question', status: 'open'}) RETURN count(rq) AS open_questions;
UC detail breakdown:
MATCH (uc:UseCase)
RETURN count(uc) AS total,
count(CASE WHEN uc.priority = 'primary' THEN 1 END) AS primary_ucs,
count(CASE WHEN uc.priority = 'secondary' THEN 1 END) AS secondary_ucs,
count(CASE WHEN uc.detail_status = 'complete' THEN 1 END) AS detailed_ucs;
Connected-spec extension counts (2.15+)
Query: sa_statistics_extensions
Source: graph-infra/queries/sa-queries.cypher
RETURN
COUNT { (n:Decision) } AS decisions,
COUNT { (n:Screen) } AS screens,
COUNT { (n:ScreenState) } AS screen_states,
COUNT { (n:ScreenEvent) } AS screen_events,
COUNT { (n:Transition) } AS screen_transitions,
COUNT { (n:ScreenEffect) } AS screen_effects,
COUNT { (n:AnalyticsEvent) } AS analytics_events,
COUNT { (n:Slice) } AS slices,
COUNT { (n:DomainError) } AS domain_errors,
COUNT { (n:ErrorPresentation) } AS error_presentations,
COUNT { (n:CachePolicy) } AS cache_policies,
COUNT { (n:DegradationRule) } AS degradation_rules;
These layers are opt-in (vacuous PASS in /nacl-sa-validate L10-L13 when
empty). All-zero counts for a layer mean "not adopted", not "incomplete" —
report them as such, do not treat zero as a readiness failure.
Output format
Present to user as a table:
| Metric | Count |
|--------------------|-------|
| Modules | {N} |
| Domain Entities | {N} |
| Attributes (total) | {N} |
| Enumerations | {N} |
| Roles | {N} |
| Use Cases (total) | {N} |
| - Primary | {N} |
| - Secondary | {N} |
| - Detailed | {N}/{total} |
| Forms | {N} |
| Form Fields | {N} |
| Requirements | {N} |
| Components | {N} |
| ADRs | {N} |
| Open Questions | {N} |
| Decisions | {N} |
| Screens | {N} ({N} states, {N} transitions) |
| Behavior Slices | {N} |
| Domain Errors | {N} ({N} presentations) |
| Cache Policies | {N} |
| Degradation Rules | {N} |
Extension rows with zero counts are rendered as — (not adopted) instead of 0.
For mode module, scope all queries with:
MATCH (m:Module {id: $moduleId})-[:CONTAINS_UC]->(uc:UseCase) ...
MATCH (m:Module {id: $moduleId})-[:CONTAINS_ENTITY]->(de:DomainEntity) ...
Phase 2: Glossary Extract + ADR
Goal: Extract glossary terms from graph; compile Architecture Decision Records.
2a: Glossary Extract
Query: sa_glossary_extract
Source: graph-infra/queries/sa-queries.cypher
MATCH (de:DomainEntity)
RETURN 'DomainEntity' AS source_type, de.id AS id, de.name AS term
UNION ALL
MATCH (en:Enumeration)
RETURN 'Enumeration' AS source_type, en.id AS id, en.name AS term
UNION ALL
MATCH (sr:SystemRole)
RETURN 'SystemRole' AS source_type, sr.id AS id, sr.name AS term;
Cross-reference with BA glossary (if BA layer exists)
MATCH (g:GlossaryTerm)
OPTIONAL MATCH (g)-[:REFERS_TO]->(de:DomainEntity)
RETURN g.id AS glo_id, g.term AS ba_term, g.definition AS definition,
de.id AS sa_entity_id, de.name AS sa_entity_name;
Actions
- Run
sa_glossary_extractto collect all SA-layer terms - For each term without a definition, generate a one-sentence definition from its graph context (attributes, relationships, module membership)
- Cross-reference with BA GlossaryTerm nodes to map BA term -> SA entity
- Present combined glossary to user (do NOT write to files)
2b: Architecture Decisions (graph-native)
Architecture decisions are stored as first-class :Decision nodes
(level:'architecture', created_by:'nacl-sa-finalize') linked to the
artifacts they justify via JUSTIFIES — the same provenance model that
nacl-sa-feature and nacl-tl-fix write. This is the authority; markdown ADRs
are projections. (Legacy projects stored ADRs as Requirement {type:'adr'} with
no link to what they justified — those are migrated below so the year-later
"why" query reaches them.)
Read existing decisions (both modern and legacy)
MATCH (d:Decision)
RETURN d.id AS id, d.title AS title, d.rationale AS rationale,
d.status AS status, d.level AS level
ORDER BY d.id;
// Legacy ADRs not yet migrated to :Decision
MATCH (rq:Requirement {type: 'adr'})
RETURN rq.id AS id, rq.description AS title, rq.context AS context,
rq.decision AS decision, rq.alternatives AS alternatives,
rq.consequences AS consequences
ORDER BY rq.id;
One-time backfill: legacy Requirement{type:'adr'} → :Decision
For each legacy ADR, create a :Decision carrying the same content (rationale
from decision+consequences), source:'ADR-NNN (imported)', and — where the
ADR's subject is identifiable — a JUSTIFIES edge to the module/entity/role it
concerns. Present to the user before writing; never delete the legacy node
(keep lineage), just mark it migrated_to: <DEC-id>.
// mcp__neo4j__write-cypher (per legacy ADR, after user confirms the JUSTIFIES target)
MATCH (rq:Requirement {id: $adrId, type:'adr'})
MERGE (d:Decision {id: $decId})
SET d.title = rq.description, d.context = rq.context,
d.chosen = rq.decision, d.rationale = coalesce(rq.decision,'') + ' — ' + coalesce(rq.consequences,''),
d.alternatives_considered = CASE WHEN rq.alternatives IS NULL THEN [] ELSE [rq.alternatives] END,
d.status = coalesce(rq.status,'accepted'), d.created_at = coalesce(rq.created_at, datetime()),
d.created_by = 'nacl-sa-finalize', d.source = rq.id + ' (imported)', d.level = 'architecture'
SET rq.migrated_to = $decId
RETURN d.id;
Also import any standalone docs/adr/*.md files the same way (source:'<file> (imported)').
Backfill: FeatureRequests without a Decision (provenance gap-closure)
Projects created before the provenance feature have :FeatureRequest nodes with
no linked :Decision — nacl-sa-validate L9.1 flags every one. Close the gap by
writing one honest :Decision per FR, with rationale drawn from the project's
own recorded text (never invented). Full runbook:
nacl-tl-core/references/provenance-gap-closure.md.
Per FR without IMPLEMENTS -> :Decision, resolve rationale in priority order:
- FR node
description(if non-empty). - FR markdown at
markdown_path— the## Feature Descriptionsection, plus theSource:metadata line (the original/sa-feature "..."intent). This is real recorded rationale, not fabrication. git logof the FR markdown / its UCs.- None recoverable → do NOT invent. Grandfather via
nacl-sa-flags-style flag (decision_exempt=true,decision_exempt_reason,decision_exempt_since), which L9.1 skips and L9.5 surfaces as visible debt.
For a recoverable FR, write the Decision and wire it to the FR's own scope:
// mcp__neo4j__write-cypher (per FR; $rationale extracted from md/description; $decId = next DEC-NNN)
MATCH (fr:FeatureRequest {id: $frId})
MERGE (d:Decision {id: $decId})
SET d.title = coalesce(fr.title, $frId), d.chosen = $chosen,
d.rationale = $rationale, // REQUIRED, non-empty, from project's own records
d.context = $context, d.alternatives_considered = [],
d.status = CASE WHEN fr.status IN ['shipped','implemented','dev-complete'] THEN 'accepted' ELSE 'accepted' END,
d.created_at = coalesce(fr.created_at, datetime()),
d.created_by = 'nacl-sa-finalize',
d.source = $frId + ' (backfilled from ' + $rationaleSource + ')', // 'description' | 'markdown' | 'git'
d.level = 'feature'
MERGE (fr)-[:IMPLEMENTS]->(d)
WITH d, fr
MATCH (fr)-[r:INCLUDES_UC]->(uc:UseCase)
MERGE (d)-[:JUSTIFIES {role: CASE WHEN r.kind = 'new' THEN 'creates' ELSE 'shapes' END}]->(uc)
RETURN d.id;
Verify-before-bulk: backfill ONE FR, confirm the Decision reads honestly and
sa-validate --scope L9 clears for it, then batch the rest. Present a sample to
the user before the bulk write.
Detect implicit decisions not yet recorded
Check for architectural patterns that imply a decision worth recording:
MATCH (m:Module) RETURN count(m) AS module_count, collect({id:m.id, name:m.name}) AS modules;
MATCH (sr:SystemRole) RETURN count(sr) AS role_count, collect({id:sr.id, name:sr.name}) AS roles;
Create missing Decision nodes (with JUSTIFIES)
For each detected decision not yet in the graph, allocate DEC-NNN
(max(toInteger(replace(d.id,'DEC-',''))) + 1) and write with
mcp__neo4j__write-cypher, linking it to every artifact it shaped:
MERGE (d:Decision {id: $decId})
SET d.title = $title, d.chosen = $chosen, d.rationale = $rationale,
d.context = $context, d.alternatives_considered = $alternatives,
d.status = 'accepted', d.created_at = coalesce(d.created_at, datetime()),
d.created_by = 'nacl-sa-finalize', d.source = 'finalize', d.level = 'architecture'
WITH d
UNWIND $justifiesIds AS x
MATCH (target {id: x}) // Module / DomainEntity / SystemRole / …
MERGE (d)-[:JUSTIFIES {role:'shapes'}]->(target)
RETURN d.id;
Typical decision categories to check
- Module decomposition rationale (
JUSTIFIES→ the Modules) - Domain model key decisions — entity boundaries, shared vs separate (
JUSTIFIES→ the DomainEntities) - Role model and authorization approach (
JUSTIFIES→ the SystemRoles) - Interface architecture decisions (SPA, navigation patterns)
- Technology-specific decisions
Present each new Decision to the user for confirmation before writing. Every
Decision MUST have a non-empty rationale and at least one JUSTIFIES edge —
nacl-sa-validate L9 enforces this.
IMPORTANT: In stats-only mode, SKIP Phase 2 entirely.
Phase 3: Traceability Matrix
Goal: Compute full BA-to-SA traceability and coverage from the graph.
Query: handoff_traceability_matrix
Source: graph-infra/queries/handoff-queries.cypher
MATCH (ws:WorkflowStep)-[:AUTOMATES_AS]->(uc:UseCase)
RETURN 'Step->UC' AS category, ws.id AS ba_id, ws.function_name AS ba_name, uc.id AS sa_id, uc.name AS sa_name
UNION ALL
MATCH (be:BusinessEntity)-[:REALIZED_AS]->(de:DomainEntity)
RETURN 'Entity->Domain' AS category, be.id AS ba_id, be.name AS ba_name, de.id AS sa_id, de.name AS sa_name
UNION ALL
MATCH (br:BusinessRole)-[:MAPPED_TO]->(sr:SystemRole)
RETURN 'Role->SysRole' AS category, br.id AS ba_id, br.full_name AS ba_name, sr.id AS sa_id, sr.name AS sa_name
UNION ALL
MATCH (brq:BusinessRule)-[:IMPLEMENTED_BY]->(rq:Requirement)
RETURN 'Rule->Req' AS category, brq.id AS ba_id, brq.name AS ba_name, rq.id AS sa_id, rq.description AS sa_name;
Query: handoff_coverage_stats
Source: graph-infra/queries/handoff-queries.cypher
MATCH (ws:WorkflowStep {stereotype: "Автоматизируется"})
WITH count(ws) AS total_auto
OPTIONAL MATCH (ws2:WorkflowStep {stereotype: "Автоматизируется"})-[:AUTOMATES_AS]->(:UseCase)
WITH total_auto, count(ws2) AS covered_auto
WITH total_auto, covered_auto,
CASE WHEN total_auto > 0 THEN round(100.0 * covered_auto / total_auto) ELSE 0 END AS step_pct
MATCH (be:BusinessEntity {type: "Бизнес-объект"})
WITH total_auto, covered_auto, step_pct, count(be) AS total_entities
OPTIONAL MATCH (be2:BusinessEntity {type: "Бизнес-объект"})-[:REALIZED_AS]->(:DomainEntity)
WITH total_auto, covered_auto, step_pct, total_entities, count(be2) AS covered_entities
WITH total_auto, covered_auto, step_pct, total_entities, covered_entities,
CASE WHEN total_entities > 0 THEN round(100.0 * covered_entities / total_entities) ELSE 0 END AS entity_pct
MATCH (br:BusinessRole)
WITH step_pct, entity_pct, total_auto, covered_auto, total_entities, covered_entities, count(br) AS total_roles
OPTIONAL MATCH (br2:BusinessRole)-[:MAPPED_TO]->(:SystemRole)
WITH step_pct, entity_pct, total_auto, covered_auto, total_entities, covered_entities, total_roles, count(br2) AS covered_roles
WITH step_pct, entity_pct, total_auto, covered_auto, total_entities, covered_entities, total_roles, covered_roles,
CASE WHEN total_roles > 0 THEN round(100.0 * covered_roles / total_roles) ELSE 0 END AS role_pct
MATCH (brq:BusinessRule)
WITH step_pct, entity_pct, role_pct, total_auto, covered_auto, total_entities, covered_entities, total_roles, covered_roles, count(brq) AS total_rules
OPTIONAL MATCH (brq2:BusinessRule)-[:IMPLEMENTED_BY]->(:Requirement)
WITH step_pct, entity_pct, role_pct, total_auto, covered_auto, total_entities, covered_entities, total_roles, covered_roles, total_rules, count(brq2) AS covered_rules
RETURN
step_pct AS automation_coverage_pct,
entity_pct AS entity_coverage_pct,
role_pct AS role_coverage_pct,
CASE WHEN total_rules > 0 THEN round(100.0 * covered_rules / total_rules) ELSE 0 END AS rule_coverage_pct,
{steps_covered: covered_auto, steps_total: total_auto,
entities_covered: covered_entities, entities_total: total_entities,
roles_covered: covered_roles, roles_total: total_roles,
rules_covered: covered_rules, rules_total: total_rules} AS details;
Detect uncovered items
Run these to find gaps:
// Uncovered automation steps
MATCH (bp:BusinessProcess)-[:HAS_STEP]->(ws:WorkflowStep {stereotype: "Автоматизируется"})
WHERE NOT (ws)-[:AUTOMATES_AS]->(:UseCase)
RETURN bp.id AS bp_id, bp.name AS bp_name, ws.id AS ws_id, ws.function_name AS ws_function;
// Uncovered business entities
MATCH (be:BusinessEntity {type: "Бизнес-объект"})
WHERE NOT (be)-[:REALIZED_AS]->(:DomainEntity)
RETURN be.id, be.name, be.type;
Output format
Present four sections grouped by category:
## Traceability Matrix
### 1. Workflow Steps -> Use Cases
| BA Step | BA Name | SA UC | SA UC Name | Status |
|---------|---------|-------|------------|--------|
### 2. Business Entities -> Domain Entities
| BA Entity | BA Name | SA Entity | SA Entity Name | Status |
### 3. Business Roles -> System Roles
| BA Role | BA Name | SA Role | SA Role Name | Status |
### 4. Business Rules -> Requirements
| BA Rule | BA Name | SA Req | SA Req Description | Status |
### Coverage Summary
| Category | Covered | Total | Percentage |
|------------------|---------|-------|------------|
| Automation Steps | {N} | {N} | {N}% |
| Entities | {N} | {N} | {N}% |
| Roles | {N} | {N} | {N}% |
| Rules | {N} | {N} | {N}% |
If no BA layer exists (no BusinessProcess nodes), report: "No BA layer in graph -- traceability matrix skipped."
IMPORTANT: In stats-only mode, SKIP Phase 3.
Phase 4: Readiness Assessment
Goal: Per-module completion percentages to determine specification readiness.
Query: sa_readiness_assessment
Source: graph-infra/queries/sa-queries.cypher
MATCH (m:Module)
OPTIONAL MATCH (m)-[:CONTAINS_UC]->(uc:UseCase)
WITH m, count(uc) AS total_ucs,
count(CASE WHEN uc.detail_status = 'complete' THEN 1 END) AS detailed_ucs
OPTIONAL MATCH (m)-[:CONTAINS_ENTITY]->(de:DomainEntity)
WITH m, total_ucs, detailed_ucs, count(de) AS total_entities
OPTIONAL MATCH (m)-[:CONTAINS_ENTITY]->(de2:DomainEntity)-[:HAS_ATTRIBUTE]->()
WITH m, total_ucs, detailed_ucs, total_entities,
count(DISTINCT de2) AS entities_with_attrs
RETURN m.id AS module_id, m.name AS module_name,
total_ucs, detailed_ucs,
CASE WHEN total_ucs > 0 THEN round(100.0 * detailed_ucs / total_ucs) ELSE 0 END AS uc_readiness_pct,
total_entities, entities_with_attrs,
CASE WHEN total_entities > 0 THEN round(100.0 * entities_with_attrs / total_entities) ELSE 0 END AS entity_readiness_pct;
Additional readiness checks
Form coverage per module:
MATCH (m:Module)-[:CONTAINS_UC]->(uc:UseCase)
WITH m, count(uc) AS total_ucs
OPTIONAL MATCH (m)-[:CONTAINS_UC]->(uc2:UseCase)-[:USES_FORM]->(:Form)
WITH m, total_ucs, count(DISTINCT uc2) AS ucs_with_forms
RETURN m.id AS module_id, m.name AS module_name,
total_ucs, ucs_with_forms,
CASE WHEN total_ucs > 0 THEN round(100.0 * ucs_with_forms / total_ucs) ELSE 0 END AS form_coverage_pct;
Requirement coverage per module:
MATCH (m:Module)-[:CONTAINS_UC]->(uc:UseCase)
WITH m, count(uc) AS total_ucs
OPTIONAL MATCH (m)-[:CONTAINS_UC]->(uc2:UseCase)-[:HAS_REQUIREMENT]->(:Requirement)
WITH m, total_ucs, count(DISTINCT uc2) AS ucs_with_reqs
RETURN m.id AS module_id, m.name AS module_name,
total_ucs, ucs_with_reqs,
CASE WHEN total_ucs > 0 THEN round(100.0 * ucs_with_reqs / total_ucs) ELSE 0 END AS req_coverage_pct;
Extension-layer adoption (2.15+) — query sa_extension_adoption from
graph-infra/queries/sa-queries.cypher (three independent parts, run each):
MATCH (uc:UseCase)
RETURN count(uc) AS total_ucs,
count(CASE WHEN coalesce(uc.has_ui, false) THEN 1 END) AS ui_ucs,
count(CASE WHEN EXISTS { (uc)-[:HAS_SCREEN]->(:Screen) } THEN 1 END) AS ucs_with_screens,
count(CASE WHEN EXISTS { (uc)-[:HAS_SLICE]->(:Slice) } THEN 1 END) AS ucs_with_slices,
count(CASE WHEN EXISTS { (uc)-[:HAS_DEGRADATION]->(:DegradationRule) } THEN 1 END) AS ucs_with_degradation;
MATCH (m:Module)
RETURN count(m) AS total_modules,
count(CASE WHEN EXISTS { (m)-[:HAS_ERROR]->(:DomainError) } THEN 1 END) AS modules_with_errors,
count(CASE WHEN EXISTS { (m)-[:HAS_CACHE]->(:CachePolicy) } THEN 1 END) AS modules_with_cache;
MATCH (fr:FeatureRequest)
RETURN count(fr) AS total_frs,
count(CASE WHEN EXISTS { (fr)-[:IMPLEMENTS]->(:Decision) } THEN 1 END) AS frs_with_decision,
count(CASE WHEN coalesce(fr.decision_exempt, false) THEN 1 END) AS frs_exempt;
FR-backfill candidates = total_frs - frs_with_decision - frs_exempt — when
non-zero, point the user at the FR-backfill runbook
(nacl-tl-core/references/provenance-gap-closure.md).
### Output format
Readiness Assessment
Per-Module Breakdown
| Module | Entities | Entity Attrs | UC Detail | Forms | Requirements | Overall |
|---|---|---|---|---|---|---|
| {name} | {N} | {N}% | {N}% | {N}% | {N}% | {avg}% |
Overall Readiness
| Area | Status | Progress | Comment |
|---|---|---|---|
| Architecture | {status} | {N}% | {N} modules |
| Domain Model | {status} | {N}% | {N} entities, {N} attrs |
| Roles | {status} | {N}% | {N} roles |
| UC Detailing | {status} | {N}% | {done}/{total} UC |
| Forms | {status} | {N}% | {done}/{total} UCs |
| Requirements | {status} | {N}% | {done}/{total} UCs |
| BA Traceability | {status} | {N}% | coverage stats |
| Screen Machines | {status} | {N}% | {N}/{N} UI-UCs (or "not adopted") |
| Behavior Slices | {status} | {N}% | {N}/{N} UCs (or "not adopted") |
| Error Taxonomy | {status} | {N}% | {N}/{N} modules (or "not adopted") |
| Resilience | {status} | — | {N} policies, {N} rules (or "not adopted") |
| Decision Provenance | {status} | — | {N} decisions; {N} FR-backfill candidates |
Ready for Implementation?
- Design: {N}% -- sufficient to start development? {Yes/No}
- Implementation: {N}% -- all UCs detailed? {Yes/No}
- Testing: {N}% -- all acceptance criteria defined? {Yes/No}
Status mapping:
- >= 90%: "Complete"
- >= 50%: "In Progress"
- < 50%: "Needs Work"
Shortened here. Read the whole file on GitHub.
Signals
- GitHub stars
- 27
- Forks
- 4
- Last commit
- Sep 2026
Advanced
- Item type
- skill
- Key
nacl-sa-finalize- Source
- github.com/itsalt/nacl