# ITSM suite — the skill-of-skills composition manifest.
# It COMPOSES the seven base itsm/* skills into ONE DataK3 bucket: shared master data,
# 23 disjoint tables, and a SINGLE deferred graph assembly (cmdb + cmdb_impact). It is not a
# fork and it does not re-spec any workflow — the mechanics live in the seven base contracts; this
# manifest is the ordered install DAG + the master-data wiring + the one-graph rule + the union Q&A.
# The human walkthrough is posts/enterprise_software/itsm/suite.md (published id itsm-suite).
# Lives at skill/enterprise_software/itsm/suite.skill.yaml; served over MCP at dodil://skills/suites/itsm;
# executed by `dodil skill scaffold suites/itsm`. check:skills binds it to its post.

id: suites/itsm
version: 1.0.0
summary: >-
  Scaffold a complete, customizable ITSM on ONE DataK3 bucket — master data + CMDB (cis/incidents/
  problems/changes/services/users/groups + ci_edges) plus six workflows (cmdb-blast-radius,
  sla-management, incident-management, major-incident, problem-management, change-management) + one CMDB
  graph, assembled once. 23 disjoint tables, shared masters joined across skills, no ETL and no second copy.
module: itsm
category: enterprise-software
workflows: [master-data, cmdb-blast-radius, sla-management, incident-management, major-incident, problem-management, change-management]
pillars: [sql, graph, vector, ignite, models]
industry: software                 # cross-industry base; overlays (itsm/overlays/*) reshape per industry
overlays: [finserv, manufacturing]

# Binding to the narrative (check:skills verifies these resolve + agree)
post: posts/enterprise_software/itsm/suite.md
route: /library/itsm-suite

# It composes the six base skills (no overlay by default). An overlay is an additive diff on top.
composes:
  skills: [itsm/core, itsm/cmdb-blast-radius, itsm/sla-management, itsm/incident-management,
           itsm/major-incident, itsm/problem-management, itsm/change-management]
  overlays_apply_on_top: [itsm/overlays/finserv, itsm/overlays/manufacturing]

# BUILDING A SUBSET (not all six). You do NOT have to install the whole suite to get one workflow.
subsets:
  rule: >-
    To build a SUBSET, install itsm/core FIRST — it owns the seven masters
    (cis/incidents/problems/changes/services/users/groups) + ci_edges + the inline incidents.embedding
    vector that every workflow reads — then install only the workflow skills you want. Each workflow
    skill's `consumes.master` lists its master dependencies (e.g. incident-management needs
    incidents/cis/services/groups; change-management needs changes/cis/services); itsm/core provides them all.
  standalone_without_core: >-
    Each workflow skill ALSO ships a `when: standalone` stub_masters step that creates just the masters IT
    reads (same column defs core owns, every non-key column nullable:true) — so a single workflow runs on an
    empty bucket with no itsm/core. But once you want TWO workflows sharing the same masters, install
    itsm/core once instead of letting each stub its own (avoids divergent seed data).
  graph: >-
    Skip the graph entirely (no CREATE GRAPH) unless you install itsm/cmdb-blast-radius — the single deferred
    CREATE GRAPH (cmdb + the reverse cmdb_impact) belongs to it. incident-management and change-management
    degrade gracefully without it (no-blast triage; non-graph risk floor), since both consume cmdb_impact as
    optional (incident) / the risk input (change). itsm/major-incident REQUIRES it — the typed blast IS the
    bridge's scope — so install itsm/cmdb-blast-radius whenever you want the major-incident bridge.

# One question set for the whole suite. Only the shared/composition-answered ones collapse here;
# per-workflow policy knobs stay (they are genuine best-practice decisions, defaulted by the overlay).
params:
  bucket:            { type: string,  default: itsm,  prompt: "Bucket name? (ONE bucket for all six skills)" }
  seed_data:         { type: enum,    options: [demo, empty], default: demo }   # storefront CMDB + incident history, shared by every skill's Test
  overlay:           { type: enum,    options: [none, finserv, manufacturing], default: none }
  impact_rels:       { type: list,    default: [depends_on, runs_on, part_of] } # shared: cmdb-blast-radius reverse graph + change-management risk
  categories:        { type: list,    default: [database, network, performance, availability, security] }  # shared: incident triage gate + problem RCA gate
  priority_scheme:   { type: enum,    options: [impact_urgency, direct], default: impact_urgency }  # incident-management
  severity_threshold: { type: enum,   options: [P1, P2, P3, P4], default: P1 }             # major-incident: auto-declare a bridge at/above this priority
  auto_approve_risk: { type: enum,    options: [none, low, low_medium], default: low }   # change-management

# ORDERED install DAG — masters first, the graph created once after its ONLY edge contributor (core).
order:
  - itsm/core                # 1. owns cis/ci_edges + incidents/problems/changes/services/users/groups + incidents.embedding; DEFERS every CREATE GRAPH
  - itsm/cmdb-blast-radius   # 2. all ci_edges are in from core -> build reverse impacts (typed) + run the SINGLE CREATE GRAPH (cmdb + cmdb_impact)
  - itsm/sla-management      # 3. SLA policy + per-incident clock over core.incidents (pure SQL, no Models)
  - itsm/incident-management # 4. triage engine — reads incidents.embedding (dedup + precedent) + cmdb_impact (blast signal); starts the SLA clock
  - itsm/major-incident      # 5. bridge lifecycle — declares a major incident from a P1, scopes the typed cmdb_impact blast, tracks open -> mitigating -> resolved (reads incidents + cmdb_impact + service_map; independent of problem/change)
  - itsm/problem-management  # 6. clusters incidents (embedding) -> problems -> known-errors -> links a change
  - itsm/change-management   # 7. CAB gate — reads cmdb_impact for risk = blast radius

# Ordering rule (honest, and different from CRM). In CRM the graph's edge contributors are spread across the
# DAG, forcing account-360 LAST. In ITSM the ONLY ci_edges contributor in v1 is itsm/core, so
# itsm/cmdb-blast-radius runs at POSITION 2 (right after core) and owns the single CREATE GRAPH — the
# deferral is core -> cmdb-blast-radius, not core -> last skill. Downstream consumers (incident, change) then
# read a fully-assembled static graph. If a FUTURE skill contributes CI edges (e.g. an auto-discovery skill
# that infers depends_on from traffic), itsm/cmdb-blast-radius moves to LAST after it — the snapshot rule is
# what is invariant, not the ordinal position.

# Shared master data — owner skill -> the sibling skills that JOIN it (no copy; one row, many readers).
# Derived from each base contract's provides.owns_master -> siblings' consumes.master.
master_wiring:
  cis:        { owner: itsm/core, consumers: [itsm/cmdb-blast-radius, itsm/incident-management, itsm/major-incident, itsm/problem-management, itsm/change-management] }
  incidents:  { owner: itsm/core, consumers: [itsm/incident-management, itsm/major-incident, itsm/problem-management, itsm/sla-management] }
  problems:   { owner: itsm/core, consumers: [itsm/problem-management] }
  changes:    { owner: itsm/core, consumers: [itsm/problem-management, itsm/change-management] }
  services:   { owner: itsm/core, consumers: [itsm/cmdb-blast-radius, itsm/incident-management, itsm/major-incident, itsm/change-management, itsm/sla-management] }
  groups:     { owner: itsm/core, consumers: [itsm/incident-management, itsm/sla-management] }
  users:      { owner: itsm/core, consumers: [] }
  ci_edges:   { owner: itsm/core, consumers: [itsm/cmdb-blast-radius] }   # edges, not a master, but core-owned; the graph's only v1 contributor

# THE single CREATE GRAPH — run exactly once, after the only edge contributor (core). This is the subtlety.
graph_assembly:
  graphs: [cmdb, cmdb_impact]
  rule: >-
    In suite mode itsm/core inserts nodes (cis) + edges (ci_edges) but runs NO CREATE GRAPH. The snapshot
    rule (itsm-servicenow.md:150 / itsm-core.md:306) means edges added after CREATE are invisible, so the
    suite defers the single CREATE GRAPH cmdb NODES (cis KEY id) EDGES (ci_edges SRC src DST dst) — and the
    reverse CREATE GRAPH cmdb_impact NODES (cis KEY id) EDGES (impacts SRC src DST dst) over the purpose-built
    impacts table — to itsm/cmdb-blast-radius, the graph owner, at position 2 (right after core loads edges).
  contributors:
    - { skill: itsm/core,              edges: [depends_on, runs_on, part_of] }
    - { skill: itsm/cmdb-blast-radius, edges: [impacts], runs_create_graph: true }
  typed_traversal_note: >-
    Because ci_edges mixes three rel kinds, blast radius MUST be typed — the reverse `impacts` table is built
    only from rels in `impact_rels` (default all three). A blanket graph_khop over every edge over-counts when
    part_of (composition) shouldn't propagate failure — the ITSM analog of the CRM live-found bug where the
    family rollup had to filter rel='subsidiary_of' or partner_of edges leaked in ($66k vs $36k). LIVE-PROVEN
    2026-09-02: payments-db's blast is 4 CIs with all three rels (payments-audit-log joins at hop 1 via
    part_of) but 3 CIs with impact_rels=[depends_on] (payments-audit-log excluded). Type the edge.

# The ordered scaffold plan an agent executes (tools resolve against dodil://commands via check:skills).
steps:
  - id: bucket
    title: One bucket for the whole ITSM
    when: always
    tools: [data_bucket_create]
    detail: Create the single DataK3 bucket {{bucket}}. Every one of the six skills lands here — one data plane.
  - id: core
    title: Install itsm/core (the system of record)
    when: always
    tools: [data_table_create, data_table_upsert, ignite_models_embed, data_pg]
    detail: >-
      8 tables (cis/incidents/problems/changes/services/users/groups + ci_edges) + the inline
      incidents.embedding VECTOR(2048). service_id is a STRING key shared by cis + incidents + services (the
      impacted-service rollup JOINs them). In suite mode core populates cis + ci_edges but DEFERS CREATE
      GRAPH. Seed the storefront demo (10-11 CIs app->service->host->db, 6 incidents) if seed_data=demo.
  - id: cmdb-blast-radius
    title: Install itsm/cmdb-blast-radius + run the SINGLE graph assembly (position 2)
    when: always
    tools: [data_table_create, data_pg, data_bolt]
    detail: >-
      impacts/service_map/impact_analysis. Build service_map from cis JOIN services; build the reverse impacts
      typed to impact_rels; THEN the one CREATE GRAPH cmdb (forward) + CREATE GRAPH cmdb_impact (reverse) over
      core's fully-loaded ci_edges/cis. graph_khop('cmdb_impact', <ci>, N) is the blast radius; type it to impact_rels.
  - id: sla-management
    title: Install itsm/sla-management (pure-SQL clock over core.incidents)
    when: always
    tools: [data_table_create, data_pg, data_sql]
    detail: >-
      sla_definitions/incident_sla/sla_breaches; the clock is opened_at + target minutes per priority over the
      shared incidents master. Pure SQL — the itsm-sla-monitor engine's SA needs only k3.editor + ignite.app-developer.
  - id: incident-management
    title: Install itsm/incident-management (dedup + triage over core masters)
    when: always
    tools: [data_table_create, data_table_upsert, data_vsearch, data_pg]
    detail: >-
      incident_triage/incident_work_notes; reads incidents.embedding (dedup + precedent) + cmdb_impact (blast
      signal), writes the verdict + advances core.incidents + starts the SLA clock. Gate = kimi-k2.6 over {{categories}}.
  - id: major-incident
    title: Install itsm/major-incident (bridge lifecycle over core.incidents + the cmdb graph)
    when: always
    tools: [data_table_create, data_table_upsert, data_pg, data_bolt]
    detail: >-
      bridges/bridge_events; the declare gate promotes an OPEN incident at/above {{severity_threshold}}
      (default P1) to a bridge, scopes the TYPED blast via graph_khop('cmdb_impact', ci, {{impact_rels}}-
      filtered) rolled up over service_map, and tracks open -> mitigating -> resolved while advancing the
      underlying core.incidents row to resolved. Deterministic composition — NO Models gate.
  - id: problem-management
    title: Install itsm/problem-management (cluster core.incidents -> problems)
    when: always
    tools: [data_table_create, data_table_upsert, data_vsearch]
    detail: >-
      problem_incidents/known_errors; clusters recurring incidents by KNN over incidents.embedding, opens a
      core.problems row + the known-error, and (link_change) spawns a core.changes row for the permanent fix.
  - id: change-management
    title: Install itsm/change-management (CAB gate — risk = blast radius)
    when: always
    tools: [data_table_create, data_table_upsert, data_pg]
    detail: >-
      change_approvals/change_calendar/change_policy; reads cmdb_impact for the blast radius, detects freeze
      conflicts, calls the CAB gate, writes the verdict + advances core.changes.approval_state.
  - id: overlay
    title: Apply an industry overlay (optional)
    when: { overlay: [finserv, manufacturing] }
    tools: [data_pg, data_table_create, data_table_upsert]
    detail: >-
      Apply itsm/overlays/{{overlay}} — an ADDITIVE diff on top of the 21 tables (ALTER-add columns via the pg
      wire + maybe one extra table + gate/edge tweaks). finserv adds a compliance hard gate + change_audit;
      manufacturing adds OT CIs + maintenance_windows + a controls rel. Never rewrites a base skill.

# The union Q&A (the composition removes redundant asks — proposal §9.4).
customize:
  - param: bucket
    ask: "One bucket name for the whole ITSM?"
    effects:
      any: "all six skills scaffold into this single bucket — one data plane, cross-skill JOINs are free."
  - param: seed_data
    ask: "Load the shared storefront demo (CMDB + incident history), or ship empty schemas?"
    effects:
      demo:  "one demo (10-11 CIs + the orders-db incident cluster) drives EVERY skill's Test — asked once, not six times."
      empty: "empty schemas across all 21 tables; each skill's Test switches to structural assertions."
  - param: overlay
    ask: "Which industry? (drives the overlay diffs at once — finserv compliance / manufacturing OT + defaults)"
    effects:
      none:          "the cross-industry base suite."
      finserv:       "regulated-change compliance HARD GATE + change_audit; auto_approve_risk=none; freeze windows seeded."
      manufacturing: "OT CI class + maintenance_windows + impact_rels gains a `controls` rel; blast reaches plant lines."
  - param: [impact_rels, categories]
    ask: "The SHARED knobs — which rels propagate failure (impact_rels), and the incident/problem taxonomy (categories)?"
    effects:
      any: "impact_rels is shared by cmdb-blast-radius + change risk; categories by the incident triage gate + the problem RCA gate — each asked ONCE."
  - param: [priority_scheme, severity_threshold, auto_approve_risk]
    ask: "The per-workflow policy knobs — incident priority scheme, major-incident severity threshold, change auto-approve risk?"
    effects:
      any: "genuine best-practice decisions the overlay may default but you tune; not removed by composition (severity_threshold gates the major-incident bridge; sla_targets/freeze_windows/cluster_min stay per-skill too)."

# Composition-answered asks REMOVED (documented so the union is auditable):
#  - incident/problem/change consume `incidents`/`changes` FROM itsm/core — no "hand-feed or seed?" re-ask.
#  - change-management's CMDB graph comes FROM itsm/cmdb-blast-radius — no "build a CMDB?" re-ask.
#  - the SLA clock table (incident_sla) is owned once by sla-management — incident-management doesn't re-declare it.
#  - every workflow's `when: standalone` stub_masters step is SKIPPED — core owns the masters (§ subsets).

# What proves the ASSEMBLY (the suite's Test is about composition, not re-testing each skill).
# LIVE-VALIDATED 2026-09-02 on one throwaway bucket (org IHDIASH), torn down after.
tests:
  - "data table list -> 23 tables coexist in ONE bucket, NO name collision (8 core + 3 cmdb + 3 sla + 2 incident + 2 major-incident + 2 problem + 3 change)"
  - "single graph: cmdb + cmdb_impact assembled ONCE by cmdb-blast-radius after core loaded all ci_edges; graph_khop('cmdb_impact', 8, 5) -> orders-api/checkout-service/web-storefront (3 tiers)"
  - "typed blast: payments-db's blast is 4 CIs with impact_rels=[depends_on,runs_on,part_of] (payments-audit-log via part_of) but 3 with [depends_on] only — typed, not blanket"
  - "cross-skill JOIN: incident_triage (incident-mgmt) JOIN incidents (core) -> 1006 = triaged / database / P1 / orders-eng"
  - "cross-skill JOIN: bridges (major-incident) JOIN incidents (core), blast from cmdb_impact (cmdb) -> mi-1006 on orders-db = resolved, impacted_ci_count 3, impacted_services [Online Checkout, Order Management]; INC1006 advanced to resolved with the bridge"
  - "cross-skill JOIN: change_approvals (change-mgmt) JOIN changes (core), blast from cmdb_impact (cmdb) -> CHG5001 to orders-db = cab_review / high, blast [orders-api,checkout-service,web-storefront], 1 impacted service"
  - "SLA over shared incidents: incident_sla (sla-mgmt) JOIN incidents (core) -> INC1006 P1 resolve_breached + response_breached, escalation_level 2"
  - "problem cluster over incidents.embedding: PRB7001 clusters 3 orders-db incidents (1006/1001/1005, common ci=orders-db), known-error published, permanent fix -> change 5001; vsearch scores 0.096/0.129/0.253 vs unrelated payments 1003 at 0.404"

tested_branches:
  - { seed_data: demo, overlay: none, tested_at: 2026-09-02 }   # default suite — full single-bucket assembly, live-validated
