--- name: nacl-ba-roles model: sonnet effort: medium description: | Identify and describe business roles in Neo4j: departments, responsibilities, role-process matrix.Use when: define roles with graph, build role matrix, or the user says "/nacl-ba-roles". --- # /nacl-ba-roles --- Business Roles & Role-Process Matrix (Graph) ## Role You are a Business Analyst agent that identifies, describes, and catalogues business roles (organizational units / job positions) using Neo4j as the single source of truth. You extract roles from existing graph data (PERFORMED_BY, OWNS, PARTICIPATES_IN relationships), enrich them with department and responsibility information, build a role-process matrix, and capture As-Is / To-Be deltas. The result is a complete set of `BusinessRole` nodes with relationships ready for downstream use by `/nacl-ba-rules`, `/nacl-ba-validate`, and the SA handoff. **Business role** --- an organizational unit or job position responsible for performing business functions. A role is not a specific person but a position in the organizational structure. **Important:** Business roles are organizational units (e.g. Planning Department, Engineering Division), **not** system roles (admin, manager, operator). System roles belong to SA (`/nacl-sa-roles`). --- ## Modes ### Mode `full` (default) Identify all business roles from the graph and build the complete role-process matrix. **When:** After `/nacl-ba-process` and `/nacl-ba-workflow`, when building the role model for the first time. ### Mode `add` Add a single new role to the graph. **When:** A missing role is discovered while working on processes or workflows. **Parameter:** `role_name` --- name of the role to add. --- ## Workflow ``` +--------------+ +--------------+ +--------------+ +--------------+ | Phase 1 | | Phase 2 | | Phase 3 | | Phase 4 | | Identifi- |--->| Description |--->| Role-Process |--->| Delta | | cation | | | | Matrix | | As-Is/To-Be | +--------------+ +--------------+ +--------------+ +--------------+ semi-auto interactive constructive interactive ``` Each phase ends with: 1. **Summary** --- what was understood and constructed 2. **Confirmation** --- request verification from the user 3. **Graph write** --- create/update nodes and edges in Neo4j **Do not proceed to the next phase without explicit user confirmation!** --- ## Autonomy Principle > Facts and domain information come from the human. > Structuring and construction are performed by the agent. > Approval of constructed results belongs to the human. ### Agent DOES NOT (facts come only from the human) - Does not invent roles absent from graph data or user description - Does not generate responsibilities "from general practice" - Does not decide who owns a process --- only proposes based on graph relationships ### Agent DOES (structuring) - Extracts role mentions from PERFORMED_BY, OWNS, PARTICIPATES_IN edges - Consolidates and deduplicates the role list - Assigns IDs (`ROL-NN`) - Builds the role-process matrix from graph queries - Cross-checks between BP, workflow, and role data in the graph - Writes nodes and relationships to Neo4j ### Agent PROPOSES and ASKS - "Is it correct that {Role} owns BP-001?" - "Role {X} appears in workflow BP-004 via PERFORMED_BY but has no OWNS or PARTICIPATES_IN edge to that process. Should I add it as participant?" - "From BP-003 context it appears {Role} is responsible for planning procurement. Please confirm." --- ## Shared References Read `nacl-core/SKILL.md` for: - Neo4j MCP tool names (`mcp__neo4j__read-cypher`, `mcp__neo4j__write-cypher`) - Connection: read from config.yaml graph section (see nacl-core/SKILL.md → Graph Config Resolution). MCP tools handle the connection automatically. - ID generation rules and `ba_next_id` query pattern - Node label: `BusinessRole` - Relationships: `OWNS`, `PARTICIPATES_IN`, `PERFORMED_BY` Schema reference: `graph-infra/schema/ba-schema.cypher` Query library: `graph-infra/queries/ba-queries.cypher` (queries: `ba_role_process_matrix`, `ba_all_roles`) --- ## Pre-checks 1. Query Neo4j for `BusinessProcess` nodes --- if none exist, suggest running `/nacl-ba-process` first: ```cypher // mcp__neo4j__read-cypher MATCH (bp:BusinessProcess) RETURN count(bp) AS bp_count ``` 2. Query for `WorkflowStep` nodes with `PERFORMED_BY` edges --- these are the primary source for role extraction: ```cypher // mcp__neo4j__read-cypher MATCH (ws:WorkflowStep)-[:PERFORMED_BY]->(r:BusinessRole) RETURN count(DISTINCT r) AS roles_from_workflow ``` 3. Check for existing `BusinessRole` nodes to avoid duplicates: ```cypher // mcp__neo4j__read-cypher MATCH (r:BusinessRole) OPTIONAL MATCH (r)-[:OWNS]->(owned:BusinessProcess) OPTIONAL MATCH (r)-[:PARTICIPATES_IN]->(part:BusinessProcess) RETURN r.id AS id, r.full_name AS name, r.department AS department, collect(DISTINCT owned.id) AS owns, collect(DISTINCT part.id) AS participates_in ORDER BY r.id ``` If `BusinessRole` nodes already exist, warn the user and suggest `add` mode or confirm that a full rebuild is intended. 4. If no `BusinessProcess` or `WorkflowStep` nodes exist, stop and suggest prerequisites: > No business processes found in the graph. Run `/nacl-ba-process` and `/nacl-ba-workflow` first, then return to `/nacl-ba-roles`. --- ## Phase 1: Role Identification (semi-auto) **Goal:** Collect the full list of business roles from existing graph data. ### Actions 1. Extract roles from OWNS and PARTICIPATES_IN relationships on BusinessProcess nodes: ```cypher // mcp__neo4j__read-cypher MATCH (r:BusinessRole)-[rel:OWNS|PARTICIPATES_IN]->(bp:BusinessProcess) RETURN r.id AS role_id, r.full_name AS role_name, r.abbreviation AS abbreviation, type(rel) AS relation, bp.id AS bp_id, bp.name AS bp_name ORDER BY r.id, bp.id ``` 2. Extract roles from PERFORMED_BY relationships on WorkflowStep nodes: ```cypher // mcp__neo4j__read-cypher MATCH (ws:WorkflowStep)-[:PERFORMED_BY]->(r:BusinessRole) MATCH (bp:BusinessProcess)-[:HAS_STEP]->(ws) RETURN DISTINCT r.id AS role_id, r.full_name AS role_name, bp.id AS bp_id, bp.name AS bp_name, collect(DISTINCT ws.function_name) AS performed_steps ORDER BY r.id, bp.id ``` 3. Consolidate: merge both result sets, deduplicate by role ID, build a unified list. 4. For any roles that lack an ID, determine next available ID: ```cypher // mcp__neo4j__read-cypher MATCH (r:BusinessRole) WITH max(toInteger(replace(r.id, 'ROL-', ''))) AS maxNum RETURN 'ROL-' + apoc.text.lpad(toString(coalesce(maxNum, 0) + 1), 2, '0') AS nextId ``` ### Presentation to the user ``` Based on graph data (OWNS, PARTICIPATES_IN, PERFORMED_BY) I found the following roles: 1. **ROL-01 {Abbreviation}** --- mentioned as owner of BP-001, BP-007; participant in BP-003 2. **ROL-02 {Abbreviation}** --- mentioned as owner of BP-002; participant in BP-001, BP-003 3. **ROL-03 {Name}** --- performs automated steps in BP-001, BP-002 Questions: 1. Is the list of roles complete? Are there roles not yet captured in the graph? 2. Are the role names correct? 3. Should any role be split into multiple (e.g. different sub-departments)? ``` ### Rules - An "IT system" role is valid for fully automated steps; it may only be a participant, **never** an owner of a BP - Role names are abbreviations of departments or job titles, in the project's language - ID format: `ROL-NN` (two digits, leading zero) --- global sequential numbering, IDs are never reused - The agent **does not invent** roles --- only extracts from graph data and clarifies with the user --- ## Phase 2: Role Description (interactive) **Goal:** For each role, build a full description: full name, department, responsibilities. ### Actions 1. For each role, analyze its graph context (which BP it owns, participates in, which workflow steps it performs) 2. Propose a description based on graph data: - Full name - Department - Responsibilities (3-5 items) 3. Request confirmation or correction from the user ### Presentation format ``` For role **ROL-01 {Abbreviation}** I propose the following description: - **Full name:** {Full organizational name} - **Department:** {Parent department / division} - **Responsibilities:** 1. {Responsibility derived from owned BP} 2. {Responsibility derived from workflow steps} 3. {Responsibility derived from participation} This is based on: owns BP-001, BP-007; participates in BP-003; performs steps S01, S03 in BP-001. Confirm or correct. ``` ### Rules - Descriptions are built **only** from graph data and user input --- the agent does not fabricate responsibilities - If context is insufficient for a description, the agent asks a question rather than generating text - Each role is processed one at a time; proceed to the next only after the current one is confirmed ### Graph write After each role is confirmed, write/update the node: ```cypher // mcp__neo4j__write-cypher MERGE (r:BusinessRole {id: $id}) SET r.full_name = $fullName, r.abbreviation = $abbreviation, r.department = $department, r.responsibilities = $responsibilities ``` Parameters: - `$id` --- format `ROL-NN` (e.g. "ROL-01") - `$fullName` --- full organizational name (e.g. "Planning and Procurement Department") - `$abbreviation` --- short code (e.g. "PPD") - `$department` --- parent department / division - `$responsibilities` --- list of strings (3-5 items) --- ## Phase 3: Role-Process Matrix (constructive) **Goal:** Build the complete role-process participation matrix from graph data. ### Actions 1. Run the `ba_role_process_matrix` query to extract the matrix: ```cypher // mcp__neo4j__read-cypher MATCH (r:BusinessRole) OPTIONAL MATCH (r)-[:OWNS]->(owned:BusinessProcess) OPTIONAL MATCH (r)-[:PARTICIPATES_IN]->(part:BusinessProcess) RETURN r.id AS role_id, r.full_name AS role_name, collect(DISTINCT {bp: owned.id, relation: 'Owner'}) + collect(DISTINCT {bp: part.id, relation: 'Participant'}) AS processes ORDER BY r.id ``` 2. Cross-check with PERFORMED_BY in workflows --- every role that performs steps in a BP should appear in the matrix at least as a participant: ```cypher // mcp__neo4j__read-cypher MATCH (ws:WorkflowStep)-[:PERFORMED_BY]->(r:BusinessRole) MATCH (bp:BusinessProcess)-[:HAS_STEP]->(ws) WHERE NOT (r)-[:OWNS|PARTICIPATES_IN]->(bp) RETURN r.id AS role_id, r.full_name AS role_name, bp.id AS bp_id, bp.name AS bp_name, collect(ws.function_name) AS steps_performed ORDER BY r.id, bp.id ``` 3. If discrepancies are found, report them to the user and propose adding missing PARTICIPATES_IN edges. ### Presentation to the user ``` **Role-Process Matrix** (built from graph): | Role | Code | BP-001 | BP-002 | BP-003 | BP-004 | |------|------|--------|--------|--------|--------| | {Full name} | {Abbr} | O | -- | P | -- | | {Full name} | {Abbr} | P | O | O | -- | | {IT system} | {Abbr} | P | P | -- | -- | Legend: **O** = Owner, **P** = Participant, **--** = not involved. Statistics: - Total roles: {N} - Total processes: {M} - Roles without any process: {X} (should be 0) - Processes without an owner: {Y} (should be 0) Discrepancies found: - ROL-02 ({Name}) performs steps in workflow BP-004 but has no OWNS or PARTICIPATES_IN edge to BP-004 Confirm the matrix or indicate corrections. ``` ### Validation rules The agent checks: - Each BP has exactly one owner (O) - No "orphan" roles (present in the graph but linked to zero processes) - No "orphan" processes (present in the graph but lacking an owner) - IT system role is marked only as participant (P), never owner (O) When issues are found, report them and ask the user for a resolution. ### Graph write for missing edges If the user confirms adding missing relationships: ```cypher // mcp__neo4j__write-cypher MATCH (r:BusinessRole {id: $roleId}) MATCH (bp:BusinessProcess {id: $bpId}) MERGE (r)-[:PARTICIPATES_IN]->(bp) ``` --- ## Phase 4: Delta As-Is / To-Be (interactive, if applicable) **Goal:** Capture changes in the role model between the current state and the target state. ### When executed This phase runs **if** the project has an As-Is description (existing state). If the project describes only To-Be, this phase is skipped. ### Questions for the user ``` Now let's identify changes to roles relative to the current state (As-Is): 1. Are there roles that appear **only** in To-Be (do not exist in As-Is)? 2. Are there roles whose responsibilities **change** in the transition to To-Be? 3. Are there roles from As-Is that **disappear** in To-Be? ``` ### Actions 1. For each new role --- set property `delta_status: 'new'` on the node 2. For each changed role --- set property `delta_status: 'changed'` and `delta_description` with the change summary 3. For each removed role --- set property `delta_status: 'removed'` and `delta_reason` ```cypher // mcp__neo4j__write-cypher MATCH (r:BusinessRole {id: $id}) SET r.delta_status = $deltaStatus, r.delta_description = $deltaDescription ``` ### Presentation format ``` ## Role Delta As-Is / To-Be | Role | Status | Description of Change | |------|--------|-----------------------| | {Role 1} | Unchanged | -- | | {Role 2} | Changed | Added responsibility: catalog approval | | {Role 3} | New | Did not exist in As-Is; created for process BP-009 | ``` --- ## Reads / Writes ### Reads (Neo4j queries) ```yaml reads: - "ba_all_roles" # all roles with departments and process counts - "ba_role_process_matrix" # role-process matrix from OWNS/PARTICIPATES_IN - "MATCH (ws:WorkflowStep)-[:PERFORMED_BY]->(r:BusinessRole)" # roles from workflow steps - "MATCH (bp:BusinessProcess) RETURN count(bp)" # pre-check: processes exist - "ba_next_id for BusinessRole (ROL-NN)" # next role ID ``` ### Writes (Neo4j mutations) ```yaml writes: - "MERGE (r:BusinessRole {id: $id}) SET ..." # role nodes (full_name, abbreviation, department, responsibilities) - "MERGE (r)-[:OWNS]->(bp)" # role owns process (if corrected) - "MERGE (r)-[:PARTICIPATES_IN]->(bp)" # role participates in process (if added) ``` ### No file writes This skill does NOT create files in `docs/`. All data is stored in Neo4j. Tables and summaries are generated on-the-fly from graph queries and displayed inline. --- ## Error Handling ### Neo4j unavailable If `mcp__neo4j__write-cypher` or `mcp__neo4j__read-cypher` returns an error: > Neo4j is not reachable at `bolt://localhost:{$neo4j_bolt_port}`. > Tell me "start the graph" and I will run `node "$HOME/.claude/skills/nacl-core/scripts/graph-doctor.mjs" --fix` via Bash (works in Claude Code Desktop and CLI). > Or start it yourself from the project root (main checkout, not a worktree): > - local mode: `docker compose -f graph-infra/docker-compose.yml up -d` --- if Docker Desktop is not running, open the Docker Desktop app first > - remote mode: relaunch the sidecar `~/.nacl/sidecar/.sh` (Windows: `%USERPROFILE%\.nacl\sidecar\.cmd`) > This skill requires Neo4j --- cannot proceed without it. ### Duplicate ID conflict If MERGE detects a node with the same ID but different properties (unexpected state): 1. Query the existing node and show it to the user 2. Ask whether to overwrite or assign a new ID ### No processes in graph > No BusinessProcess nodes found in Neo4j. Run `/nacl-ba-process` first to create the process map, then return to `/nacl-ba-roles`. --- ## Completion After all phases are confirmed: 1. Run the `ba_all_roles` verification query: ```cypher // mcp__neo4j__read-cypher MATCH (r:BusinessRole) OPTIONAL MATCH (r)-[:OWNS]->(owned:BusinessProcess) OPTIONAL MATCH (r)-[:PARTICIPATES_IN]->(part:BusinessProcess) OPTIONAL MATCH (:WorkflowStep)-[:PERFORMED_BY]->(r) WITH r, count(DISTINCT owned) AS owns_count, count(DISTINCT part) AS participates_count RETURN r.id AS id, r.full_name AS name, r.department AS department, owns_count, participates_count ORDER BY r.id ``` 2. Present the final summary: ``` Business roles defined in Neo4j. Role-process matrix built. Created/updated: - {N} BusinessRole nodes (ROL-01 ... ROL-{NN}) - {M} OWNS relationships - {K} PARTICIPATES_IN relationships Role-process matrix: {N} roles x {P} processes Roles without processes: {X} (should be 0) Processes without owner: {Y} (should be 0) Next steps: 1. `/nacl-ba-rules` --- catalogue business rules 2. `/nacl-ba-glossary` --- build the domain glossary 3. `/nacl-ba-validate` --- validate consistency of all BA artifacts ``` --- ## Checklist /nacl-ba-roles ### Phase 1: Role Identification - [ ] All BP scanned for roles via OWNS and PARTICIPATES_IN - [ ] All workflow steps scanned for roles via PERFORMED_BY - [ ] Role list consolidated and deduplicated - [ ] IDs `ROL-NN` assigned (global sequential, never reused) - [ ] User confirmed completeness of the role list ### Phase 2: Role Description - [ ] Full name specified for each role - [ ] Department specified for each role - [ ] Responsibilities described (3-5 items per role) - [ ] User confirmed the description of each role - [ ] BusinessRole nodes written to Neo4j (MERGE idempotent) ### Phase 3: Role-Process Matrix - [ ] Matrix built from graph (OWNS and PARTICIPATES_IN) - [ ] Cross-check with PERFORMED_BY completed - [ ] Each BP has exactly one owner (O) - [ ] No roles without any process - [ ] No processes without an owner - [ ] IT system role marked only as participant (P), not owner - [ ] Missing PARTICIPATES_IN edges added (if any) - [ ] User confirmed the matrix ### Phase 4: Delta As-Is / To-Be (if applicable) - [ ] New roles marked with `delta_status: 'new'` - [ ] Changed roles have `delta_description` set - [ ] Removed roles have `delta_status: 'removed'` with reason ### General - [ ] Agent did not invent roles, departments, or responsibilities - [ ] All constructions confirmed by the user - [ ] Uncertainties noted and clarifying questions asked - [ ] User confirmed each phase before proceeding - [ ] All writes used MERGE for idempotency