diff --git a/.github/workflows/capability-map-skill-test.yml b/.github/workflows/capability-map-skill-test.yml new file mode 100644 index 0000000..e01809c --- /dev/null +++ b/.github/workflows/capability-map-skill-test.yml @@ -0,0 +1,21 @@ +name: Capability-map skill +on: + pull_request: + paths: + - 'transitrix/skills/render-dsm-capabilities-html/**' + - '.github/workflows/capability-map-skill-test.yml' + workflow_dispatch: +permissions: + contents: read +jobs: + renderer: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: '3.12' + - name: Run renderer regression checks + run: python3 transitrix/skills/render-dsm-capabilities-html/scripts/test_render.py + - name: Check portable package + run: python3 transitrix/skills/render-dsm-capabilities-html/scripts/test_package.py diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8048b50..4356f70 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -49,6 +49,10 @@ A Skill is a packaged Claude Code capability under `transitrix/skills//`, Add supporting material only as the skill needs it, following existing precedent: `templates/` for scaffolded files (`onboard/templates/`), `prompts/` for multi-step prompt sequences (`ingest/prompts/`, `reg-intel/prompts/`), `schemas/` for JSON Schema the skill validates against, `tests/` for a deterministic integrity test (`onboard/tests/`, `knowledge-store/tests/`). +Portable Agent Skills may nest runtime-specific trigger/version fields under +`metadata` when their host rejects unknown top-level fields. Their README must +state the input/runtime compatibility rather than implying a released contract. + **Changing an existing skill:** 1. Read the skill's `SKILL.md` and `README.md` in full before editing — the two must stay consistent with each other and with the skill's actual behaviour. diff --git a/publish-manifest.json b/publish-manifest.json index 8ea6f16..2ebe69a 100644 --- a/publish-manifest.json +++ b/publish-manifest.json @@ -9,6 +9,7 @@ ".github/pull_request_template.md", ".github/workflows/adl-guard.yml", ".github/workflows/capability-contract-test.yml", + ".github/workflows/capability-map-skill-test.yml", ".github/workflows/check-commit-authors.yml", ".github/workflows/decisions-cli-test.yml", ".github/workflows/dependabot-auto-merge.yml", @@ -830,6 +831,29 @@ "transitrix/skills/reg-intel/templates/reg-intel-daily.timer", "transitrix/skills/reg-intel/tests/test_reg_intel_integrity.py", "transitrix/skills/reg-intel/tests/test_reg_intel_prompts.py", + "transitrix/skills/render-dsm-capabilities-html/LICENSE", + "transitrix/skills/render-dsm-capabilities-html/README.md", + "transitrix/skills/render-dsm-capabilities-html/SKILL.md", + "transitrix/skills/render-dsm-capabilities-html/agents/openai.yaml", + "transitrix/skills/render-dsm-capabilities-html/assets/acme-corp-demo-extensions.json", + "transitrix/skills/render-dsm-capabilities-html/assets/acme-corp-source-example.json", + "transitrix/skills/render-dsm-capabilities-html/assets/acme-corp-source.json", + "transitrix/skills/render-dsm-capabilities-html/assets/example.json", + "transitrix/skills/render-dsm-capabilities-html/assets/icon.svg", + "transitrix/skills/render-dsm-capabilities-html/assets/synthetic-regression.json", + "transitrix/skills/render-dsm-capabilities-html/references/acme-corp-LICENSE.txt", + "transitrix/skills/render-dsm-capabilities-html/references/acme-corp-example.md", + "transitrix/skills/render-dsm-capabilities-html/references/date-timeline.md", + "transitrix/skills/render-dsm-capabilities-html/references/dsm-rules.md", + "transitrix/skills/render-dsm-capabilities-html/references/input-contract.md", + "transitrix/skills/render-dsm-capabilities-html/references/methodology-boundary.md", + "transitrix/skills/render-dsm-capabilities-html/references/methodology-correction.md", + "transitrix/skills/render-dsm-capabilities-html/references/system-coverage.md", + "transitrix/skills/render-dsm-capabilities-html/references/view-controls.md", + "transitrix/skills/render-dsm-capabilities-html/scripts/package.py", + "transitrix/skills/render-dsm-capabilities-html/scripts/render.py", + "transitrix/skills/render-dsm-capabilities-html/scripts/test_package.py", + "transitrix/skills/render-dsm-capabilities-html/scripts/test_render.py", "transitrix/skills/repo-check/README.md", "transitrix/skills/repo-check/SKILL.md", "transitrix/skills/report/README.md", diff --git a/transitrix/README.md b/transitrix/README.md index 5e18594..b35a220 100644 --- a/transitrix/README.md +++ b/transitrix/README.md @@ -51,6 +51,7 @@ Regenerate with `node packages/plugin-examples/src/generate.mjs`; CI (`.github/w | **Ingest** | `/transitrix:ingest` | Turns raw organisational documents — interviews, policies, org charts — into `field`-zone artefacts and typed canon candidates, then stages a human review queue | 0.6.0 | | **Repo-check** | `/transitrix:repo-check` | Read-only health check: methodology version, coverage-profile resolution, per-TYPE element counts, and integrity flags — all data-free, safe to share externally | 0.6.0 | | **Report** | `/transitrix:report` | Produces a reproducible compliance report (obligation × subject impact matrix or per-regime coverage metric) via a committed view-config artefact and the `@transitrix/cli` renderer | 0.6.0 | +| **Capability map** | `/transitrix:render-dsm-capabilities-html` | Portable interactive HTML/native SVG from explicit JSON, with dated states, layers, tags and multi-system coverage | Standalone adapter; [compatibility](skills/render-dsm-capabilities-html/README.md) | | **Reg-intel** | `/transitrix:reg-intel` | Monitors regulatory sources, classifies new instruments against the organisation's obligation catalogue, and stages a review digest for human triage | 0.6.0 | | **ADR** | `/transitrix:adr` | Runs a Context/Decision/Consequences interview and lands the result as a gated Architecture Decision Record (`operations/decisions/ADR-YYYY-MM-DD-*.md`), never self-accepting and never editing an accepted record's body | 0.6.0 | | **Feedback** | `/transitrix:feedback` | Routes a methodology-directed finding away from data/model problems, runs a scrub-gated interview, and lands it as an anonymised `FB-NNNN` entry in `operations/feedback.md`; exports a ready-to-send message on request only, never transmits it itself | 2.1.0 | @@ -66,6 +67,10 @@ Regenerate with `node packages/plugin-examples/src/generate.mjs`; CI (`.github/w --- +The standalone capability-map renderer needs only Python 3 and its documented +JSON input. It can also be copied into another Agent Skills host; native YAML +ingestion and released CLI/DSM/Studio adoption are separate. + ## What the plugin does not do - It does not vendor a copy of the methodology canon. When a skill needs the full spec it fetches it from `github.com/transitrix/methodology` via `WebFetch`. diff --git a/transitrix/skills/render-dsm-capabilities-html/LICENSE b/transitrix/skills/render-dsm-capabilities-html/LICENSE new file mode 100644 index 0000000..5b1e833 --- /dev/null +++ b/transitrix/skills/render-dsm-capabilities-html/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023-2026 Valerii Korobeinikov + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/transitrix/skills/render-dsm-capabilities-html/README.md b/transitrix/skills/render-dsm-capabilities-html/README.md new file mode 100644 index 0000000..ed034cb --- /dev/null +++ b/transitrix/skills/render-dsm-capabilities-html/README.md @@ -0,0 +1,63 @@ +# Capability-map HTML/SVG skill + +Create a portable business capability map from explicit source data: vertical +domains, horizontal cross-cutting abilities and readable nested L2/L3 boxes. +The interactive HTML adds five management-cycle layers, ESG/MDM/Support tag +filters, date navigation, multi-system coverage and exact-view SVG export. +Python 3 is the only runtime requirement; rendering needs no server or network. + +## Use with an agent + +This is a skill in the Transitrix plugin. With the plugin installed, invoke +`/transitrix:render-dsm-capabilities-html` in Claude Code. For a host that loads +portable Agent Skills, copy this entire folder into its skill directory and +invoke `$render-dsm-capabilities-html` (Codex) or reference `SKILL.md` directly. +Runtime-specific trigger metadata is nested under `metadata` to retain the +portable Agent Skills frontmatter shape. Existing invocation policy is retained. + +Example request: + +> Render the supplied capability model as an interactive map. Preserve its +> dates, explicit V/H lanes and mappings. Include a script-free SVG of the view. + +## Run without an agent + +From this skill folder: + +```sh +python3 scripts/render.py assets/example.json acme-capability-map.html +python3 scripts/render.py assets/example.json acme-capability-map.svg --date 2027-01-01 --sort-layers --no-backlog +python3 scripts/test_render.py +python3 scripts/package.py /tmp/render-dsm-capabilities-html-6.8.2.zip +``` + +Open the HTML in a browser. Backlog, system labels and coverage are initially off. +Choose a date, select systems and enable Coverage polygons. Use Diagram only and +Fit to screen for presentation; Download SVG captures the exact visible view. +A source-only Acme adapter is also included; the expanded teaching example +labels its illustrative additions and planned states visibly. + +## Meaning and compatibility + +The five stages are Strategic, Learning, Planning, Execution and Assurance. +Strategic includes strategic planning; Planning is tactical/operational. ESG, +MDM and Support are tags, independent of actual horizontal capabilities. +Coverage follows explicit direct/technical links; geometry is not a percentage +or proof of redundant functionality. + +Input is the standalone JSON contract, not native Transitrix YAML. Read +[methodology mapping](references/methodology-boundary.md) for the merged source +revision, unreleased core changes and consumer limitations. Native multi-tag OR +filtering is not implemented; this UI selects one tag. Canonical maturity is +1–5; explicit legacy 0 is an absence diagnostic, never a missing assessment. + +The renderer is version 6.8.2, adapter `dsm-capability-html/6`. It does not edit +DSM/Studio or imply their adoption of this contract. HTML includes all supplied +snapshots: filters are presentation, not security redaction. + +## Included data and license + +[Acme example notes](references/acme-corp-example.md) identify the immutable +source revision, retained source bytes and illustrative teaching overlay. +The renderer and skill are MIT licensed under the repository license; the +source Acme fixture's MIT license is retained with its attribution. diff --git a/transitrix/skills/render-dsm-capabilities-html/SKILL.md b/transitrix/skills/render-dsm-capabilities-html/SKILL.md new file mode 100644 index 0000000..a21d1de --- /dev/null +++ b/transitrix/skills/render-dsm-capabilities-html/SKILL.md @@ -0,0 +1,75 @@ +--- +name: render-dsm-capabilities-html +description: Render DSM-style business capability maps as portable interactive HTML and native SVG, with dated snapshots, management-cycle layers, tags and explicit multi-system coverage. Use for standalone capability maps, not capability trees, BCMFlow or native DSM/Studio editing. +license: MIT +allowed-tools: Read, Bash, Glob, Grep +metadata: + version: "6.8.2" + when_to_use: "Create or update a portable capability-map HTML/SVG, show system coverage, or compare explicitly supplied dated capability states." + source_contract: "888c03d33c2d899ec85a612901075b67811614e5" +--- + +# Render a business capability map + +Use Python 3 standard library only. Resolve `SKILL_DIR` as this skill's actual +folder, independently of the working directory. Keep source models unchanged; +write generated output to the user's chosen destination. + +## Establish the source meaning + +Read [input contract](references/input-contract.md) before adapting data and +[methodology mapping](references/methodology-boundary.md) before converting +native Transitrix records. Input is the documented standalone JSON projection, +not native YAML. Preserve source revisions, evidence dates, explicit V/H +addresses and lanes, independent Current/Target states and mapping provenance. +Missing support means not specified; never infer it from names, tags or hierarchy. + +This uses the classic DSM Report grid: V-L1 domain columns, horizontal H-L1 +bands and nested L2/L3. State that assumption for vague "like DSM" requests. +Use [DSM source rules](references/dsm-rules.md) for source-specific geometry; +no pixel parity or native product integration is claimed. + +## Render and choose a view + +```sh +python3 "$SKILL_DIR/scripts/render.py" model.json capability-map.html +python3 "$SKILL_DIR/scripts/render.py" model.json capability-map.svg --date 2027-01-01 --sort-layers --no-backlog +``` + +Read [view controls](references/view-controls.md) for layers, tags, nested widths, +backlog, labels, legend, Diagram only, zoom, fit-to-screen and exact-view export. +The five management stages are Strategic, Learning, Planning, Execution and +Assurance. ESG, MDM and Support are independent tags. Neither stages nor tags +inherit. Preserve L1/L2/L3 containment and explicit horizontal intersections. + +For dated input, read [date timeline](references/date-timeline.md): distinguish +model-validity date, source/evidence date and planned intent. Gaps show no data +and disable export. Never derive a date from a descriptive target horizon or +claim that a plan became observed fact when its date passed. + +For coverage, read [system coverage](references/system-coverage.md). Use only +explicit APPLICATION and application-owned technical mappings. A red outline +marks the region inside at least two selected outer polygons; it is a geometric +diagnostic, not proof of redundant functions or a coverage percentage. + +## Verify and deliver + +Use [the Acme teaching example](assets/example.json) for a demonstration; +[source/illustration notes](references/acme-corp-example.md) distinguish its +source-backed core from invented teaching records. Preserve visible demo and +planned-state labels. Never mix synthetic assignments into source canon. + +Run `python3 "$SKILL_DIR/scripts/test_render.py"` after renderer changes. +Inspect both classic and layered layouts: readable names, nested rectangles, +direct mappings, dated coverage, selected-view SVG and no external SVG assets. +System/Maturity labels expand boxes; hidden labels reserve no empty lines. + +Record renderer/adapter/model revisions and the merged-but-unreleased methodology +source separately. The canonical maturity scale is 1–5; explicit legacy 0 is +an absence diagnostic and missing maturity is not 0. The standalone tag filter +supports one selected tag; report unsupported native multi-tag settings. + +Deliver local HTML/SVG files (or native attachments where available), with +selected date/scenario and any unverified runtime behavior. Display filters are +not redaction: HTML includes all supplied snapshots. Publishing or sending the +artifact requires the user's authorization. diff --git a/transitrix/skills/render-dsm-capabilities-html/agents/openai.yaml b/transitrix/skills/render-dsm-capabilities-html/agents/openai.yaml new file mode 100644 index 0000000..23519c1 --- /dev/null +++ b/transitrix/skills/render-dsm-capabilities-html/agents/openai.yaml @@ -0,0 +1,14 @@ +interface: + display_name: DSM Capability Map HTML + short_description: Capability grids, system support and exact-view SVG export + default_prompt: Use $render-dsm-capabilities-html to render this capability model + as a standalone DSM-style HTML grid. + icon_small: assets/icon.svg + icon_large: assets/icon.svg +policy: + products: + - chatgpt + - codex + - api + - atlas + allow_implicit_invocation: true diff --git a/transitrix/skills/render-dsm-capabilities-html/assets/acme-corp-demo-extensions.json b/transitrix/skills/render-dsm-capabilities-html/assets/acme-corp-demo-extensions.json new file mode 100644 index 0000000..b6bd6fe --- /dev/null +++ b/transitrix/skills/render-dsm-capabilities-html/assets/acme-corp-demo-extensions.json @@ -0,0 +1,522 @@ +{ + "created_on": "2026-10-23", + "source_core_revision": "e331590b13935d1d0922063acbf1f6a0cb3cdba2", + "notice": "Illustrative teaching overlay, not Acme source canon or a promised future architecture.", + "source_core_capability_ids": [ + "CAPABILITY-V1", + "CAPABILITY-V1.1", + "CAPABILITY-V1.2", + "CAPABILITY-V2", + "CAPABILITY-H1" + ], + "added_capability_ids": [ + "DEMO-CAPABILITY-V3", + "DEMO-CAPABILITY-V2.1", + "DEMO-CAPABILITY-V2.2", + "DEMO-CAPABILITY-V1.3", + "DEMO-CAPABILITY-V3.1", + "DEMO-CAPABILITY-V1.1.1", + "DEMO-CAPABILITY-V1.2.1", + "DEMO-CAPABILITY-V3.1.1", + "DEMO-CAPABILITY-V3.2", + "DEMO-CAPABILITY-H2", + "DEMO-CAPABILITY-H2.1", + "DEMO-CAPABILITY-H2.2", + "DEMO-CAPABILITY-H2.1.1", + "DEMO-CAPABILITY-H3", + "DEMO-CAPABILITY-H3.1", + "DEMO-CAPABILITY-H3.2", + "DEMO-CAPABILITY-H3.3", + "DEMO-CAPABILITY-H3.2.1", + "DEMO-CAPABILITY-H1.1", + "DEMO-CAPABILITY-H1.1.1", + "DEMO-CAPABILITY-H1.2", + "DEMO-CAPABILITY-H1.2.1", + "DEMO-CAPABILITY-H1.3", + "DEMO-CAPABILITY-V0", + "DEMO-CAPABILITY-V0.1", + "DEMO-CAPABILITY-H1.4", + "DEMO-CAPABILITY-H1.4.1" + ], + "source_application_mapping_extensions": { + "APPLICATION-OMS-1": [ + "DEMO-CAPABILITY-V1.1.1", + "DEMO-CAPABILITY-V1.2.1", + "DEMO-CAPABILITY-H1.1.1" + ], + "APPLICATION-CRM-1": [ + "DEMO-CAPABILITY-V2.2", + "DEMO-CAPABILITY-H1.2" + ] + }, + "added_application_ids": [ + "DEMO-APPLICATION-WAREHOUSE", + "DEMO-APPLICATION-DATA", + "DEMO-APPLICATION-GOVERNANCE", + "DEMO-APPLICATION-ESG" + ], + "target_mapping_status": "All target APPLICATION mappings in this extended example are illustrative.", + "previous_property_overlay": { + "CAPABILITY-V1": "Execution", + "CAPABILITY-V1.1": "Execution", + "CAPABILITY-V1.2": "Execution", + "CAPABILITY-V2": "Strategic", + "CAPABILITY-H1": "Support" + }, + "classification_model": "Five cycle layers plus independent ESG/MDM/Support tags; illustrative, not source canon.", + "classification_overlays": { + "current": { + "CAPABILITY-V1": { + "layer": "Execution", + "tags": [] + }, + "CAPABILITY-V1.1": { + "layer": "Execution", + "tags": [] + }, + "CAPABILITY-V1.2": { + "layer": "Execution", + "tags": [] + }, + "CAPABILITY-V2": { + "layer": "Strategic", + "tags": [] + }, + "CAPABILITY-H1": { + "layer": null, + "tags": [ + "Support" + ] + }, + "DEMO-CAPABILITY-V3": { + "layer": "Execution", + "tags": [] + }, + "DEMO-CAPABILITY-V2.1": { + "layer": "Strategic", + "tags": [] + }, + "DEMO-CAPABILITY-V2.2": { + "layer": "Learning", + "tags": [] + }, + "DEMO-CAPABILITY-V1.3": { + "layer": "Planning", + "tags": [] + }, + "DEMO-CAPABILITY-V3.1": { + "layer": "Planning", + "tags": [] + }, + "DEMO-CAPABILITY-V1.1.1": { + "layer": "Execution", + "tags": [] + }, + "DEMO-CAPABILITY-V1.2.1": { + "layer": "Execution", + "tags": [] + }, + "DEMO-CAPABILITY-V3.1.1": { + "layer": "Assurance", + "tags": [ + "MDM" + ] + }, + "DEMO-CAPABILITY-V3.2": { + "layer": null, + "tags": [ + "ESG" + ] + }, + "DEMO-CAPABILITY-H2": { + "layer": null, + "tags": [ + "ESG" + ] + }, + "DEMO-CAPABILITY-H2.1": { + "layer": "Planning", + "tags": [ + "ESG" + ] + }, + "DEMO-CAPABILITY-H2.2": { + "layer": "Execution", + "tags": [ + "ESG" + ] + }, + "DEMO-CAPABILITY-H2.1.1": { + "layer": "Assurance", + "tags": [ + "ESG", + "Support" + ] + }, + "DEMO-CAPABILITY-H3": { + "layer": null, + "tags": [ + "MDM" + ] + }, + "DEMO-CAPABILITY-H3.1": { + "layer": "Execution", + "tags": [ + "MDM" + ] + }, + "DEMO-CAPABILITY-H3.2": { + "layer": "Execution", + "tags": [ + "MDM" + ] + }, + "DEMO-CAPABILITY-H3.3": { + "layer": "Execution", + "tags": [ + "MDM" + ] + }, + "DEMO-CAPABILITY-H3.2.1": { + "layer": "Assurance", + "tags": [ + "MDM", + "Support" + ] + }, + "DEMO-CAPABILITY-H1.1": { + "layer": "Execution", + "tags": [ + "Support" + ] + }, + "DEMO-CAPABILITY-H1.1.1": { + "layer": "Assurance", + "tags": [ + "Support" + ] + }, + "DEMO-CAPABILITY-H1.2": { + "layer": "Execution", + "tags": [ + "Support" + ] + }, + "DEMO-CAPABILITY-H1.2.1": { + "layer": "Assurance", + "tags": [ + "Support" + ] + }, + "DEMO-CAPABILITY-H1.3": { + "layer": "Execution", + "tags": [ + "Support" + ] + }, + "DEMO-CAPABILITY-V0": { + "layer": null, + "tags": [] + }, + "DEMO-CAPABILITY-V0.1": { + "layer": null, + "tags": [] + }, + "DEMO-CAPABILITY-H1.4": { + "layer": "Assurance", + "tags": [ + "Support" + ] + }, + "DEMO-CAPABILITY-H1.4.1": { + "layer": "Assurance", + "tags": [ + "Support" + ] + } + }, + "target": { + "CAPABILITY-V1": { + "layer": "Execution", + "tags": [] + }, + "CAPABILITY-V1.1": { + "layer": "Execution", + "tags": [] + }, + "CAPABILITY-V1.2": { + "layer": "Execution", + "tags": [] + }, + "CAPABILITY-V2": { + "layer": "Strategic", + "tags": [] + }, + "CAPABILITY-H1": { + "layer": null, + "tags": [ + "Support" + ] + }, + "DEMO-CAPABILITY-V3": { + "layer": "Execution", + "tags": [] + }, + "DEMO-CAPABILITY-V2.1": { + "layer": "Strategic", + "tags": [] + }, + "DEMO-CAPABILITY-V2.2": { + "layer": "Learning", + "tags": [] + }, + "DEMO-CAPABILITY-V1.3": { + "layer": "Planning", + "tags": [] + }, + "DEMO-CAPABILITY-V3.1": { + "layer": "Planning", + "tags": [] + }, + "DEMO-CAPABILITY-V1.1.1": { + "layer": "Execution", + "tags": [] + }, + "DEMO-CAPABILITY-V1.2.1": { + "layer": "Execution", + "tags": [] + }, + "DEMO-CAPABILITY-V3.1.1": { + "layer": "Assurance", + "tags": [ + "MDM" + ] + }, + "DEMO-CAPABILITY-V3.2": { + "layer": null, + "tags": [ + "ESG" + ] + }, + "DEMO-CAPABILITY-H2": { + "layer": null, + "tags": [ + "ESG" + ] + }, + "DEMO-CAPABILITY-H2.1": { + "layer": "Planning", + "tags": [ + "ESG" + ] + }, + "DEMO-CAPABILITY-H2.2": { + "layer": "Execution", + "tags": [ + "ESG" + ] + }, + "DEMO-CAPABILITY-H2.1.1": { + "layer": "Assurance", + "tags": [ + "ESG", + "Support" + ] + }, + "DEMO-CAPABILITY-H3": { + "layer": null, + "tags": [ + "MDM" + ] + }, + "DEMO-CAPABILITY-H3.1": { + "layer": "Execution", + "tags": [ + "MDM" + ] + }, + "DEMO-CAPABILITY-H3.2": { + "layer": "Execution", + "tags": [ + "MDM" + ] + }, + "DEMO-CAPABILITY-H3.3": { + "layer": "Execution", + "tags": [ + "MDM" + ] + }, + "DEMO-CAPABILITY-H3.2.1": { + "layer": "Assurance", + "tags": [ + "MDM", + "Support" + ] + }, + "DEMO-CAPABILITY-H1.1": { + "layer": "Execution", + "tags": [ + "Support" + ] + }, + "DEMO-CAPABILITY-H1.1.1": { + "layer": "Assurance", + "tags": [ + "Support" + ] + }, + "DEMO-CAPABILITY-H1.2": { + "layer": "Execution", + "tags": [ + "Support" + ] + }, + "DEMO-CAPABILITY-H1.2.1": { + "layer": "Assurance", + "tags": [ + "Support" + ] + }, + "DEMO-CAPABILITY-H1.3": { + "layer": "Execution", + "tags": [ + "Support" + ] + }, + "DEMO-CAPABILITY-V0": { + "layer": null, + "tags": [] + }, + "DEMO-CAPABILITY-V0.1": { + "layer": null, + "tags": [] + }, + "DEMO-CAPABILITY-H1.4": { + "layer": "Assurance", + "tags": [ + "Support" + ] + }, + "DEMO-CAPABILITY-H1.4.1": { + "layer": "Assurance", + "tags": [ + "Support" + ] + } + } + }, + "classification_rationale": "Broad H roots have no single stage; their children span stages. Stock reconciliation, audit, evidence and customer data quality checks illustrate Assurance. Additional cross-domain tags are deliberate teaching assignments, not inferred by the renderer.", + "revised_demo_names": { + "DEMO-CAPABILITY-H3.2.1": { + "previous": "Customer deduplication (demo)", + "current": "Customer data quality checks (demo)", + "reason": "Use an explicit Check ability for the Assurance demonstration; active deduplication itself is execution." + }, + "DEMO-CAPABILITY-H2.1": { + "previous": "Packaging impact (demo)", + "current": "Packaging impact planning (demo)", + "reason": "Make the intended tactical planning ability explicit." + } + }, + "coverage_pilot": { + "system_id": "DEMO-APPLICATION-DATA", + "technical_capabilities": { + "current": [ + { + "id": "DEMO-TECH-DATA-REFERENCE", + "name": "Reference data services (demo)", + "capabilities": [ + "DEMO-CAPABILITY-H3.1", + "DEMO-CAPABILITY-H3.2" + ], + "example_origin": "illustrative_technical_mapping" + }, + { + "id": "DEMO-TECH-DATA-QUALITY", + "name": "Data quality checks (demo)", + "capabilities": [ + "DEMO-CAPABILITY-H3.2.1" + ], + "example_origin": "illustrative_technical_mapping" + } + ], + "target": [ + { + "id": "DEMO-TECH-DATA-REFERENCE", + "name": "Reference data services (demo)", + "capabilities": [ + "DEMO-CAPABILITY-H3.1", + "DEMO-CAPABILITY-H3.2", + "DEMO-CAPABILITY-H3.3" + ], + "example_origin": "illustrative_technical_mapping" + }, + { + "id": "DEMO-TECH-DATA-QUALITY", + "name": "Data quality checks (demo)", + "capabilities": [ + "DEMO-CAPABILITY-H3.2.1" + ], + "example_origin": "illustrative_technical_mapping" + } + ] + }, + "notice": "Illustrative technical inventory and mappings for one-system coverage visualization, not Acme source facts or methodology schema adoption." + }, + "multi_system_coverage": { + "notice": "Illustrative technical mappings in both states, not source facts. Direct APPLICATION mappings are unchanged. Data Hub, Governance Portal and Warehouse System share product references and customer data quality checks; Data Hub and Governance Portal also share customer references. Empty Sustainability current mappings intentionally show no polygon.", + "technical_capabilities_by_application": { + "DEMO-APPLICATION-GOVERNANCE": [ + { + "id": "DEMO-TECH-GOVERNANCE-DATA", + "name": "Reference-data controls and quality evidence (demo)", + "capabilities": [ + "DEMO-CAPABILITY-H3.1", + "DEMO-CAPABILITY-H3.2", + "DEMO-CAPABILITY-H3.2.1" + ], + "example_origin": "illustrative_technical_mapping" + } + ], + "DEMO-APPLICATION-WAREHOUSE": [ + { + "id": "DEMO-TECH-WAREHOUSE-DATA", + "name": "Warehouse reference-data synchronization and checks (demo)", + "capabilities": [ + "DEMO-CAPABILITY-H3.1", + "DEMO-CAPABILITY-H3.3", + "DEMO-CAPABILITY-H3.2.1" + ], + "example_origin": "illustrative_technical_mapping" + } + ] + } + }, + "date_timeline": { + "notice": "Illustrative temporal adapter snapshots, not recovered historical Acme facts or actual future commitments. Source-only Acme input is unchanged. State periods have inclusive effective_from and exclusive effective_to.", + "default_view_date": "2026-10-23", + "periods": [ + { + "state": "historical", + "effective_from": "2026-06-01", + "effective_to": "2026-10-01", + "changes": "31 capabilities, lower demo maturity, Data Hub maps only product references; no shared technical coverage." + }, + { + "state": "current", + "effective_from": "2026-10-01", + "effective_to": "2027-01-01", + "changes": "Customer data quality checks starts 2026-10-22; governance technical controls also start then. Existing current maturity changes remain explicit." + }, + { + "state": "target", + "effective_from": "2027-01-01", + "effective_to": "2028-01-01", + "changes": "2027 planned snapshot; Data Hub inventory mappings and Sustainability coverage enabled; target demo maturity dated 2027-01-01." + } + ], + "no_data_before": "2026-06-01", + "no_data_from": "2028-01-01" + } +} diff --git a/transitrix/skills/render-dsm-capabilities-html/assets/acme-corp-source-example.json b/transitrix/skills/render-dsm-capabilities-html/assets/acme-corp-source-example.json new file mode 100644 index 0000000..11e91f0 --- /dev/null +++ b/transitrix/skills/render-dsm-capabilities-html/assets/acme-corp-source-example.json @@ -0,0 +1,237 @@ +{ + "title": "Acme Corp — Business Capability Map", + "organisation": "Acme Corp — repository example", + "model_revision": "transitrix/acme-corp@e331590b13935d1d0922063acbf1f6a0cb3cdba2", + "source_repository": "https://github.com/transitrix/acme-corp", + "source_revision": "e331590b13935d1d0922063acbf1f6a0cb3cdba2", + "states": [ + { + "id": "current", + "label": "Current State", + "kind": "current", + "as_of": "2026-10-22", + "capabilities": [ + { + "id": "CAPABILITY-V1", + "name": "Order Management", + "layout": "vertical", + "first_level": 1, + "second_level": 0, + "third_level": 0, + "lane": 0, + "start_date": "2024-01-01", + "end_date": null, + "maturity": [ + { + "change_date": "2024-01-01", + "level": 1 + }, + { + "change_date": "2025-06-01", + "level": 2 + }, + { + "change_date": "2026-09-15", + "level": 3 + } + ], + "source_target_date": "2026-12-31" + }, + { + "id": "CAPABILITY-V1.1", + "name": "Order Intake", + "layout": "vertical", + "first_level": 1, + "second_level": 1, + "third_level": 0, + "lane": 0, + "start_date": "2024-01-01", + "end_date": null, + "maturity": [ + { + "change_date": "2026-05-26", + "level": 3 + } + ] + }, + { + "id": "CAPABILITY-V1.2", + "name": "Order Fulfilment", + "layout": "vertical", + "first_level": 1, + "second_level": 2, + "third_level": 0, + "lane": 0, + "start_date": "2026-05-26", + "end_date": null, + "maturity": [ + { + "change_date": "2026-05-26", + "level": 2 + } + ], + "source_target_date": "2026-09-30" + }, + { + "id": "CAPABILITY-V2", + "name": "Customer Relationship Management", + "layout": "vertical", + "first_level": 2, + "second_level": 0, + "third_level": 0, + "lane": 0, + "start_date": "2024-01-01", + "end_date": null, + "maturity": [ + { + "change_date": "2026-05-26", + "level": 2 + } + ] + }, + { + "id": "CAPABILITY-H1", + "name": "Compliance & Data Protection", + "layout": "horizontal", + "first_level": 1, + "second_level": 0, + "third_level": 0, + "lane": 0, + "start_date": "2026-05-26", + "end_date": null, + "maturity": [ + { + "change_date": "2026-05-26", + "level": 1 + } + ], + "source_target_date": "2026-12-31" + } + ], + "applications": [ + { + "type": "APPLICATION", + "id": "APPLICATION-CRM-1", + "name": "CRM System", + "capabilities": [ + "CAPABILITY-V2" + ] + }, + { + "type": "APPLICATION", + "id": "APPLICATION-OMS-1", + "name": "Order Management System", + "capabilities": [ + "CAPABILITY-V1" + ] + } + ] + }, + { + "id": "target", + "label": "Declared Target Maturity", + "kind": "target", + "as_of": "2026-10-22", + "horizon_label": "Recorded intentions; per-capability deadlines", + "capabilities": [ + { + "id": "CAPABILITY-V1", + "name": "Order Management", + "layout": "vertical", + "first_level": 1, + "second_level": 0, + "third_level": 0, + "lane": 0, + "start_date": "2024-01-01", + "end_date": null, + "maturity": [ + { + "change_date": "2024-01-01", + "level": 3 + } + ], + "source_target_date": "2026-12-31" + }, + { + "id": "CAPABILITY-V1.1", + "name": "Order Intake", + "layout": "vertical", + "first_level": 1, + "second_level": 1, + "third_level": 0, + "lane": 0, + "start_date": "2024-01-01", + "end_date": null, + "maturity": [ + { + "change_date": "2024-01-01", + "level": 4 + }, + { + "change_date": "2026-05-26", + "level": 3 + } + ] + }, + { + "id": "CAPABILITY-V1.2", + "name": "Order Fulfilment", + "layout": "vertical", + "first_level": 1, + "second_level": 2, + "third_level": 0, + "lane": 0, + "start_date": "2026-05-26", + "end_date": null, + "maturity": [ + { + "change_date": "2026-05-26", + "level": 3 + } + ], + "source_target_date": "2026-09-30" + }, + { + "id": "CAPABILITY-V2", + "name": "Customer Relationship Management", + "layout": "vertical", + "first_level": 2, + "second_level": 0, + "third_level": 0, + "lane": 0, + "start_date": "2024-01-01", + "end_date": null, + "maturity": [ + { + "change_date": "2024-01-01", + "level": 4 + }, + { + "change_date": "2026-05-26", + "level": 3 + } + ] + }, + { + "id": "CAPABILITY-H1", + "name": "Compliance & Data Protection", + "layout": "horizontal", + "first_level": 1, + "second_level": 0, + "third_level": 0, + "lane": 0, + "start_date": "2026-05-26", + "end_date": null, + "maturity": [ + { + "change_date": "2026-05-26", + "level": 3 + } + ], + "source_target_date": "2026-12-31" + } + ], + "applications": [] + } + ] +} diff --git a/transitrix/skills/render-dsm-capabilities-html/assets/acme-corp-source.json b/transitrix/skills/render-dsm-capabilities-html/assets/acme-corp-source.json new file mode 100644 index 0000000..ae6a98e --- /dev/null +++ b/transitrix/skills/render-dsm-capabilities-html/assets/acme-corp-source.json @@ -0,0 +1,82 @@ +{ + "repository": "https://github.com/transitrix/acme-corp", + "revision": "e331590b13935d1d0922063acbf1f6a0cb3cdba2", + "read_at": "2026-10-22", + "files": [ + { + "path": "canon/elements/02_business/capabilities/CAPABILITY-H1.history.yaml", + "blob_sha": "7b7c7f326c45015b48f1a56105b54ecc9184f863", + "content": "# Versioned-attribute sidecar for CAPABILITY-H1.\n# Schema: notations/CONTRACT.md §9.1.\n\ntarget: CAPABILITY-H1\n\nattribute_versions:\n current_maturity:\n - { valid_from: \"2026-05-26\", value: 1 }\n target_maturity:\n - { valid_from: \"2026-05-26\", value: 3 }\n target_date:\n - { valid_from: \"2026-05-26\", value: \"2026-12-31\" }\n owner_role:\n - { valid_from: \"2026-05-26\", value: ROLE-DPO-1 }\n" + }, + { + "path": "canon/elements/02_business/capabilities/CAPABILITY-H1.yaml", + "blob_sha": "0bbe49e63ac551d32eaf7ee6305c8a1d37ee36c8", + "content": "# Cross-cutting compliance capability — referenced by products, scenarios,\n# and the process landscape. Diagram address H1 in the capability-map view.\n# Schema: notations/views/05-capability-map.md §13 + CONTRACT.md §6–§7.\n\nnotation: capability\nid: CAPABILITY-H1\nname: \"Compliance & Data Protection\"\ntype: supporting\ndescription: >\n Cross-cutting capability covering GDPR/NIS2 obligations: data-subject\n rights, breach reporting, and data residency. Lowest current maturity —\n the focus of the 2026 remediation programme.\n\nbusiness_process: PROCESS-DSR-HANDLE-1\n\nzone: canon\nadmitted_at: \"2026-07-06\"\nadmitted_by: \"v.korobeinikov\"\ngate_checks:\n uniqueness: pass\n consistency: pass\n completeness: pass\n\nvalid_from: \"2026-05-26\"\nvalid_to: null\n" + }, + { + "path": "canon/elements/02_business/capabilities/CAPABILITY-V1.1.history.yaml", + "blob_sha": "fef45fd113d1e5f8c242e00c1195c9b633a18401", + "content": "# Versioned-attribute sidecar for CAPABILITY-V1.1.\n# Schema: notations/CONTRACT.md §9.1.\n\ntarget: CAPABILITY-V1.1\n\nattribute_versions:\n current_maturity:\n - { valid_from: \"2026-05-26\", value: 3 }\n target_maturity:\n - { valid_from: \"2024-01-01\", value: 4 }\n - { valid_from: \"2026-05-26\", value: 3 }\n" + }, + { + "path": "canon/elements/02_business/capabilities/CAPABILITY-V1.1.yaml", + "blob_sha": "5bd5bc42e4ead5e9d362abb56720269eedfdd2a6", + "content": "# Worked example — Capability element primitive (stable fields only).\n# Schema: notations/views/05-capability-map.md §13 + admission record\n# (CONTRACT.md §6) + primitive lifecycle (CONTRACT.md §7).\n#\n# Time-varying attributes live in the sidecar CAPABILITY-V1.1.history.yaml\n# per CONTRACT.md §9.\n# Parent relationship lives in REL files under canon/relations/ — see\n# REL-CAP-V11-PARENT-1.yaml (initial; ended 2026-04-01) and\n# REL-CAP-V11-PARENT-2.yaml (current). The re-parenting demonstrates\n# 17-relations.md §3.\n\nnotation: capability\nid: CAPABILITY-V1.1\nname: \"Order Intake\"\ntype: domain # domain | supporting\ndescription: >\n Capture and validate customer order requests across all channels.\n Sits at the very top of the order-management value chain — touches\n the customer first, then hands off to the fulfilment side.\n\n# Admission record (CONTRACT.md §6)\nzone: canon\nadmitted_at: \"2026-05-28\"\nadmitted_by: \"v.korobeinikov\"\ngate_checks:\n uniqueness: pass\n consistency: pass\n completeness: pass\n\n# Primitive lifecycle (CONTRACT.md §7)\nvalid_from: \"2024-01-01\"\nvalid_to: null\n" + }, + { + "path": "canon/elements/02_business/capabilities/CAPABILITY-V1.2.history.yaml", + "blob_sha": "984e919309b64feb3a5a96328deebbfbcbc72ad7", + "content": "# Versioned-attribute sidecar for CAPABILITY-V1.2.\n# Schema: notations/CONTRACT.md §9.1.\n\ntarget: CAPABILITY-V1.2\n\nattribute_versions:\n current_maturity:\n - { valid_from: \"2026-05-26\", value: 2 }\n target_maturity:\n - { valid_from: \"2026-05-26\", value: 3 }\n target_date:\n - { valid_from: \"2026-05-26\", value: \"2026-09-30\" }\n" + }, + { + "path": "canon/elements/02_business/capabilities/CAPABILITY-V1.2.yaml", + "blob_sha": "9d8e2935364f222fbc615ecd5c04809367e0d919", + "content": "# Worked example — Capability element primitive (stable fields only).\n# Schema: notations/views/05-capability-map.md §13 + admission record\n# (CONTRACT.md §6) + primitive lifecycle (CONTRACT.md §7).\n#\n# Time-varying attributes (current_maturity, owner_role, target_date) live\n# in the sidecar CAPABILITY-V1.2.history.yaml per CONTRACT.md §9. Parent\n# (CAPABILITY-V1.2 -> CAPABILITY-V1)\n# is carried inline by the capability-map view's children[] in v0.x.\n\nnotation: capability\nid: CAPABILITY-V1.2\nname: \"Order Fulfilment\"\ntype: domain # domain | supporting\ndescription: >\n Pick, pack, route, and close out customer orders. Sits beneath Order\n Management alongside Order Intake (CAPABILITY-V1.1).\n\n# Admission record (CONTRACT.md §6)\nzone: canon\nadmitted_at: \"2026-05-29\"\nadmitted_by: \"v.korobeinikov\"\ngate_checks:\n uniqueness: pass\n consistency: pass\n completeness: pass\n\n# Primitive lifecycle (CONTRACT.md §7)\nvalid_from: \"2026-05-26\"\nvalid_to: null\n" + }, + { + "path": "canon/elements/02_business/capabilities/CAPABILITY-V1.history.yaml", + "blob_sha": "d7807deaf60f7183c43ec0ea6de7526db78d151a", + "content": "# Worked example — versioned-attribute sidecar.\n# Schema: notations/CONTRACT.md §9.1.\n#\n# Target: the CAPABILITY-V1.yaml primitive in this folder. Time-varying\n# attributes (current_maturity, target_maturity, owner_role, target_date)\n# live here, not inline on the primitive. Four patterns demonstrated:\n# 1. current_maturity — monotonic progression over three years.\n# 2. owner_role — handover from one role to another.\n# 3. target_date — re-aiming the planning target (moved earlier).\n#\n# Current-value resolution: pick the entry with the largest\n# valid_from <= today (CONTRACT.md §9.2). Validation rules\n# VERSIONED-001..005 apply.\n\ntarget: CAPABILITY-V1\n\nattribute_versions:\n\n # Maturity progression: the organisation lifted Order Management from\n # CMM 1 in 2024 to CMM 3 by late 2026 through sustained investment.\n current_maturity:\n - { valid_from: \"2024-01-01\", value: 1 }\n - { valid_from: \"2025-06-01\", value: 2 }\n - { valid_from: \"2026-09-15\", value: 3 }\n\n target_maturity:\n - { valid_from: \"2024-01-01\", value: 3 }\n\n # Owner-role handover when the Order Management team split out of\n # Operations into its own product unit.\n owner_role:\n - { valid_from: \"2024-01-01\", value: ROLE-OPS-1 }\n - { valid_from: \"2026-07-01\", value: ROLE-OPS-2 }\n\n # Planning target date — initially the org committed to CMM 3 by mid-\n # 2027; performance accelerated and the target was moved earlier.\n target_date:\n - { valid_from: \"2024-01-01\", value: \"2027-06-30\" }\n - { valid_from: \"2026-04-01\", value: \"2026-12-31\" }\n" + }, + { + "path": "canon/elements/02_business/capabilities/CAPABILITY-V1.yaml", + "blob_sha": "d146f8f873db78ee37de2873221c43b11f05fed2", + "content": "# Worked example — Capability element primitive (stable fields only).\n# Schema: notations/views/05-capability-map.md §13 + admission record\n# (CONTRACT.md §6) + primitive lifecycle (CONTRACT.md §7).\n#\n# Time-varying attributes (current_maturity, owner_role, target_date)\n# live in the sidecar CAPABILITY-V1.history.yaml per CONTRACT.md §9 —\n# NOT inline here. Inline placement would trigger VERSIONED-004.\n\nnotation: capability\nid: CAPABILITY-V1\nname: \"Order Management\"\ntype: domain # domain | supporting\ndescription: >\n End-to-end management of customer orders, from intake through\n fulfilment. The capability spans receiving, validating, routing, and\n closing out customer purchase requests across all channels.\n\n# Relations — stay inline in v1 (Wave 3 may promote to first-class\n# time-aware relation files)\nbusiness_process: PROCESS-ORD-FULFILL-1\napplications:\n - APPLICATION-OMS-1\n - APPLICATION-CRM-1\n\n# Admission record (CONTRACT.md §6)\nzone: canon\nadmitted_at: \"2026-05-28\"\nadmitted_by: \"v.korobeinikov\"\ngate_checks:\n uniqueness: pass\n consistency: pass\n completeness: pass\n\n# Primitive lifecycle (CONTRACT.md §7)\nvalid_from: \"2024-01-01\"\nvalid_to: null\n" + }, + { + "path": "canon/elements/02_business/capabilities/CAPABILITY-V2.history.yaml", + "blob_sha": "b4aad0b9ba84d49b0bf50bab3d43e632c5a2b7cb", + "content": "# Versioned-attribute sidecar for CAPABILITY-V2.\n# Schema: notations/CONTRACT.md §9.1.\n\ntarget: CAPABILITY-V2\n\nattribute_versions:\n current_maturity:\n - { valid_from: \"2026-05-26\", value: 2 }\n target_maturity:\n - { valid_from: \"2024-01-01\", value: 4 }\n - { valid_from: \"2026-05-26\", value: 3 }\n owner_role:\n - { valid_from: \"2026-05-26\", value: ROLE-SALES-1 }\n" + }, + { + "path": "canon/elements/02_business/capabilities/CAPABILITY-V2.yaml", + "blob_sha": "eb5638b9d17adfc219b2e22b44b6a0f988ae500d", + "content": "# Worked example — Capability element primitive (stable fields only).\n# Schema: notations/views/05-capability-map.md §13 + admission record\n# (CONTRACT.md §6) + primitive lifecycle (CONTRACT.md §7).\n#\n# This capability is the previous parent of CAPABILITY-V1.1 — see\n# REL-CAP-V11-PARENT-1.yaml. It is now Order Intake's ex-parent after\n# the 2026-04 re-org; the canonical Order Intake parent today is V1\n# (Order Management), captured in REL-CAP-V11-PARENT-2.yaml.\n\nnotation: capability\nid: CAPABILITY-V2\nname: \"Customer Relationship Management\"\ntype: domain # domain | supporting\ndescription: >\n Manage long-term relationships with customers — segmentation,\n loyalty, communications, lifetime value. Sits parallel to Order\n Management (V1) in the post-2026-04 hierarchy.\n\n# Admission record (CONTRACT.md §6)\nzone: canon\nadmitted_at: \"2026-05-28\"\nadmitted_by: \"v.korobeinikov\"\ngate_checks:\n uniqueness: pass\n consistency: pass\n completeness: pass\n\n# Primitive lifecycle (CONTRACT.md §7)\nvalid_from: \"2024-01-01\"\nvalid_to: null\n" + }, + { + "path": "canon/elements/03_application/applications/APPLICATION-CRM-1.yaml", + "blob_sha": "b1918cc277e30fb512a94b9cdfd3a220d6bd15b8", + "content": "# Worked example — APPLICATION element primitive (stable fields only).\n# Schema: notations/ELEMENT_PRIMITIVES.md §7.7 + envelope §3.\n# Time-varying fields (owner_role, vendor, lifecycle_stage, maturity) are\n# sidecar-bound per CONTRACT.md §9 — not inline here.\n\nnotation: application\nid: APPLICATION-CRM-1\nname: \"CRM System\"\ntype: application # application | integration | platform | data_store\ndomain: \"Sales\"\ndescription: >\n Customer-relationship and sales-pipeline management. Receives order\n events from the order-management system.\ncapabilities:\n - CAPABILITY-V2\n\n# Admission record (CONTRACT.md §6)\nzone: canon\nadmitted_at: \"2026-05-29\"\nadmitted_by: \"v.korobeinikov\"\ngate_checks:\n uniqueness: pass\n consistency: pass\n completeness: pass\n\n# Primitive lifecycle (CONTRACT.md §7)\nvalid_from: \"2026-05-26\"\nvalid_to: null\n" + }, + { + "path": "canon/elements/03_application/applications/APPLICATION-OMS-1.yaml", + "blob_sha": "fe72cdc0141bdafdaa949dd579bb991417d94231", + "content": "# Worked example — APPLICATION element primitive (stable fields only).\n# Schema: notations/ELEMENT_PRIMITIVES.md §7.7 + envelope §3.\n# Arranged by the applications-catalogue view (views/applications/).\n#\n# Time-varying fields (owner_role, vendor, lifecycle_stage, maturity) are\n# sidecar-bound per CONTRACT.md §9 — kept out of this file (inline placement\n# would trigger VERSIONED-004). The corresponding history sidecar carries\n# their dated values.\n\nnotation: application\nid: APPLICATION-OMS-1\nname: \"Order Management System\"\naliases: # non-authoritative also-known-as forms (ELEMENT_PRIMITIVES §3) — exercises the ELEM-ALIAS-001 gate\n - \"OMS\"\n - \"Order Mgmt System\"\ntype: application # application | integration | platform | data_store\ndomain: \"Operations\"\ndescription: >\n Core system for the order lifecycle — intake, validation, routing, and\n fulfilment hand-off. Integrates outbound to the CRM (see the catalogue\n view's nested integration descriptor).\ncapabilities:\n - CAPABILITY-V1\nproducts:\n - PRODUCT-ECOMM-1\n\n# Admission record (CONTRACT.md §6)\nzone: canon\nadmitted_at: \"2026-05-29\"\nadmitted_by: \"v.korobeinikov\"\ngate_checks:\n uniqueness: pass\n consistency: pass\n completeness: pass\n\n# Primitive lifecycle (CONTRACT.md §7)\nvalid_from: \"2026-05-26\"\nvalid_to: null\n" + }, + { + "path": "canon/relations/REL-CAP-V11-PARENT-1.yaml", + "blob_sha": "370b756b01d1c2aa3d3b525333abc46ce9894bc1", + "content": "# Worked example — first-class time-aware relation (the FIRST half of a\n# re-parenting event). Schema: notations/elements/17-relations.md §2.\n#\n# Narrative: CAPABILITY-V1.1 (Order Intake) was originally introduced\n# under CAPABILITY-V2 (Customer Relationship Management) in 2024 —\n# the org modelled order intake as a customer-facing capability. In\n# 2026-04, after an operational review, it was re-parented to V1\n# (Order Management) where it fits better operationally. This REL\n# file captures the OLD parent relationship; the new one is in\n# REL-CAP-V11-PARENT-2.yaml.\n\nnotation: relation\nid: REL-CAP-V11-PARENT-1\ntype: parent\nfrom: CAPABILITY-V1.1\nto: CAPABILITY-V2\n\n# Admission record (CONTRACT.md §6)\nzone: canon\nadmitted_at: \"2026-05-28\"\nadmitted_by: \"v.korobeinikov\"\ngate_checks:\n uniqueness: pass\n consistency: pass\n completeness: pass\n\n# Primitive lifecycle (CONTRACT.md §7) — this relation was in effect\n# from V1.1's birth until the 2026-04 re-org closed it.\nvalid_from: \"2024-01-01\"\nvalid_to: \"2026-04-01\"\n" + }, + { + "path": "canon/relations/REL-CAP-V11-PARENT-2.yaml", + "blob_sha": "e69b8c54ceeaea3b1af9e1417d75804954628cd0", + "content": "# Worked example — first-class time-aware relation (the SECOND half of\n# a re-parenting event). Schema: notations/elements/17-relations.md §2.\n#\n# Narrative: after the 2026-04 operational review, CAPABILITY-V1.1\n# (Order Intake) was re-parented from V2 (Customer Relationship\n# Management) to V1 (Order Management). This REL file captures the\n# NEW parent relationship. The previous relation is in\n# REL-CAP-V11-PARENT-1.yaml (ended 2026-04-01).\n\nnotation: relation\nid: REL-CAP-V11-PARENT-2\ntype: parent\nfrom: CAPABILITY-V1.1\nto: CAPABILITY-V1\n\n# Admission record (CONTRACT.md §6)\nzone: canon\nadmitted_at: \"2026-05-28\"\nadmitted_by: \"v.korobeinikov\"\ngate_checks:\n uniqueness: pass\n consistency: pass\n completeness: pass\n\n# Primitive lifecycle (CONTRACT.md §7) — this relation took effect on\n# the same date the prior parent relation ended. valid_to: null means\n# the relation is currently in effect.\nvalid_from: \"2026-04-01\"\nvalid_to: null\n" + }, + { + "path": "views/capabilities/compliance-domain.capability-map.transitrix.yaml", + "content": "# Capability map — core domains plus the cross-cutting Compliance & Data\n# Protection capability, with CMMI maturity overlay. Notation spec:\n# notations/views/05-capability-map.md. Every inline capability (recursively)\n# carries `type` and CONTRACT.md §7 lifecycle.\n\nnotation: capability-map\nspec_version: \"0.1\"\ntitle: \"Acme Corp — Capability Map with Compliance Overlay\"\ndescription: \"Core business capabilities and the cross-cutting compliance capability, with current and target CMMI maturity.\"\nversion: \"1.0\"\ndate: \"2026-06-10\"\n\ncapability_map:\n id: CAPABILITY_MAP-COMPLIANCE-1\n name: \"Compliance-Domain Capability Map\"\n description: \"Business capabilities with current and target maturity, highlighting the data-protection gap.\"\n assessment_date: \"2026-06-10\"\n\n capabilities:\n - id: V1\n name: \"Order Management\"\n type: domain\n business_process: PROCESS-ORD-FULFILL-1\n applications:\n - APPLICATION-OMS-1\n - APPLICATION-CRM-1\n valid_from: \"2026-05-26\"\n valid_to: null\n children:\n - id: V1.1\n name: \"Order Intake\"\n type: domain\n valid_from: \"2026-05-26\"\n valid_to: null\n - id: V1.2\n name: \"Order Fulfilment\"\n type: domain\n valid_from: \"2026-05-26\"\n valid_to: null\n\n - id: V2\n name: \"Customer Relationship Management\"\n type: domain\n applications:\n - APPLICATION-CRM-1\n valid_from: \"2026-05-26\"\n valid_to: null\n\n - id: H1\n name: \"Compliance & Data Protection\"\n type: supporting\n description: >\n Cross-cutting capability covering GDPR/NIS2 obligations: data-subject\n rights, breach reporting, and data residency. Lowest current maturity —\n the focus of the 2026 remediation programme.\n business_process: PROCESS-DSR-HANDLE-1\n valid_from: \"2026-05-26\"\n valid_to: null\n", + "blob_sha": "ded9525e456bc3bc1a412b558070e6d56800868d" + } + ] +} diff --git a/transitrix/skills/render-dsm-capabilities-html/assets/example.json b/transitrix/skills/render-dsm-capabilities-html/assets/example.json new file mode 100644 index 0000000..dfaba36 --- /dev/null +++ b/transitrix/skills/render-dsm-capabilities-html/assets/example.json @@ -0,0 +1,2218 @@ +{ + "title": "Acme Corp — Expanded Demonstration", + "organisation": "Source-backed core + illustrative layers, intersections and applications", + "model_revision": "transitrix/acme-corp@e331590b13935d1d0922063acbf1f6a0cb3cdba2+demo-extension-2026-10-23; management-cycle/tag teaching overlay 2026-10-23; multi-system coverage demo; dated history/current/plan demo", + "source_repository": "https://github.com/transitrix/acme-corp", + "source_revision": "e331590b13935d1d0922063acbf1f6a0cb3cdba2", + "states": [ + { + "id": "current", + "label": "Current State — extended demo", + "kind": "current", + "as_of": "2026-10-22", + "capabilities": [ + { + "id": "CAPABILITY-V1", + "name": "Order Management", + "layout": "vertical", + "first_level": 1, + "second_level": 0, + "third_level": 0, + "lane": 0, + "start_date": "2024-01-01", + "end_date": null, + "maturity": [ + { + "change_date": "2024-01-01", + "level": 1 + }, + { + "change_date": "2025-06-01", + "level": 2 + }, + { + "change_date": "2026-09-15", + "level": 3 + } + ], + "source_target_date": "2026-12-31", + "property_origin": "illustrative_extension", + "layer": "Execution", + "tags": [] + }, + { + "id": "CAPABILITY-V1.1", + "name": "Order Intake", + "layout": "vertical", + "first_level": 1, + "second_level": 1, + "third_level": 0, + "lane": 0, + "start_date": "2024-01-01", + "end_date": null, + "maturity": [ + { + "change_date": "2026-05-26", + "level": 3 + } + ], + "property_origin": "illustrative_extension", + "layer": "Execution", + "tags": [] + }, + { + "id": "CAPABILITY-V1.2", + "name": "Order Fulfilment", + "layout": "vertical", + "first_level": 1, + "second_level": 2, + "third_level": 0, + "lane": 0, + "start_date": "2026-05-26", + "end_date": null, + "maturity": [ + { + "change_date": "2026-05-26", + "level": 2 + } + ], + "source_target_date": "2026-09-30", + "property_origin": "illustrative_extension", + "layer": "Execution", + "tags": [] + }, + { + "id": "CAPABILITY-V2", + "name": "Customer Relationship Management", + "layout": "vertical", + "first_level": 2, + "second_level": 0, + "third_level": 0, + "lane": 0, + "start_date": "2024-01-01", + "end_date": null, + "maturity": [ + { + "change_date": "2026-05-26", + "level": 2 + } + ], + "property_origin": "illustrative_extension", + "layer": "Strategic", + "tags": [] + }, + { + "id": "CAPABILITY-H1", + "name": "Compliance & Data Protection", + "layout": "horizontal", + "first_level": 1, + "second_level": 0, + "third_level": 0, + "lane": 0, + "start_date": "2026-05-26", + "end_date": null, + "maturity": [ + { + "change_date": "2026-05-26", + "level": 1 + } + ], + "source_target_date": "2026-12-31", + "property_origin": "illustrative_extension", + "layer": null, + "tags": [ + "Support" + ] + }, + { + "id": "DEMO-CAPABILITY-V3", + "name": "Inventory & Warehousing (demo)", + "layout": "vertical", + "first_level": 3, + "second_level": 0, + "third_level": 0, + "lane": 0, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2026-10-22", + "level": 2 + } + ], + "layer": "Execution", + "tags": [] + }, + { + "id": "DEMO-CAPABILITY-V2.1", + "name": "Customer strategy (demo)", + "layout": "vertical", + "first_level": 2, + "second_level": 1, + "third_level": 0, + "lane": 0, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2026-10-22", + "level": 3 + } + ], + "layer": "Strategic", + "tags": [] + }, + { + "id": "DEMO-CAPABILITY-V2.2", + "name": "Customer insights (demo)", + "layout": "vertical", + "first_level": 2, + "second_level": 2, + "third_level": 0, + "lane": 0, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2026-10-22", + "level": 2 + } + ], + "layer": "Learning", + "tags": [] + }, + { + "id": "DEMO-CAPABILITY-V1.3", + "name": "Fulfilment planning (demo)", + "layout": "vertical", + "first_level": 1, + "second_level": 3, + "third_level": 0, + "lane": 0, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2026-10-22", + "level": 3 + } + ], + "layer": "Planning", + "tags": [] + }, + { + "id": "DEMO-CAPABILITY-V3.1", + "name": "Warehouse planning (demo)", + "layout": "vertical", + "first_level": 3, + "second_level": 1, + "third_level": 0, + "lane": 0, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2026-10-22", + "level": 2 + } + ], + "layer": "Planning", + "tags": [] + }, + { + "id": "DEMO-CAPABILITY-V1.1.1", + "name": "Order validation (demo)", + "layout": "vertical", + "first_level": 1, + "second_level": 1, + "third_level": 1, + "lane": 0, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2026-10-22", + "level": 4 + } + ], + "layer": "Execution", + "tags": [] + }, + { + "id": "DEMO-CAPABILITY-V1.2.1", + "name": "Pick and pack (demo)", + "layout": "vertical", + "first_level": 1, + "second_level": 2, + "third_level": 1, + "lane": 0, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2026-10-22", + "level": 3 + } + ], + "layer": "Execution", + "tags": [] + }, + { + "id": "DEMO-CAPABILITY-V3.1.1", + "name": "Stock reconciliation (demo)", + "layout": "vertical", + "first_level": 3, + "second_level": 1, + "third_level": 1, + "lane": 0, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2026-10-22", + "level": 2 + } + ], + "layer": "Assurance", + "tags": [ + "MDM" + ] + }, + { + "id": "DEMO-CAPABILITY-V3.2", + "name": "Returns improvement (demo)", + "layout": "vertical", + "first_level": 3, + "second_level": 2, + "third_level": 0, + "lane": 0, + "example_origin": "illustrative_extension", + "layer": null, + "tags": [ + "ESG" + ] + }, + { + "id": "DEMO-CAPABILITY-H2", + "name": "Sustainability (demo)", + "layout": "horizontal", + "first_level": 2, + "second_level": 0, + "third_level": 0, + "lane": 0, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2026-10-22", + "level": 2 + } + ], + "layer": null, + "tags": [ + "ESG" + ] + }, + { + "id": "DEMO-CAPABILITY-H2.1", + "name": "Packaging impact planning (demo)", + "layout": "horizontal", + "first_level": 2, + "second_level": 1, + "third_level": 0, + "lane": 1, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2026-10-22", + "level": 1 + } + ], + "layer": "Planning", + "tags": [ + "ESG" + ] + }, + { + "id": "DEMO-CAPABILITY-H2.2", + "name": "Warehouse energy (demo)", + "layout": "horizontal", + "first_level": 2, + "second_level": 2, + "third_level": 0, + "lane": 3, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2026-10-22", + "level": 1 + } + ], + "layer": "Execution", + "tags": [ + "ESG" + ] + }, + { + "id": "DEMO-CAPABILITY-H2.1.1", + "name": "Packaging evidence (demo)", + "layout": "horizontal", + "first_level": 2, + "second_level": 1, + "third_level": 1, + "lane": 1, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2026-10-22", + "level": 0 + } + ], + "layer": "Assurance", + "tags": [ + "ESG", + "Support" + ] + }, + { + "id": "DEMO-CAPABILITY-H3", + "name": "Master Data Management (demo)", + "layout": "horizontal", + "first_level": 3, + "second_level": 0, + "third_level": 0, + "lane": 0, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2026-10-22", + "level": 3 + } + ], + "layer": null, + "tags": [ + "MDM" + ] + }, + { + "id": "DEMO-CAPABILITY-H3.1", + "name": "Product reference data (demo)", + "layout": "horizontal", + "first_level": 3, + "second_level": 1, + "third_level": 0, + "lane": 1, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2026-10-22", + "level": 3 + } + ], + "layer": "Execution", + "tags": [ + "MDM" + ] + }, + { + "id": "DEMO-CAPABILITY-H3.2", + "name": "Customer reference data (demo)", + "layout": "horizontal", + "first_level": 3, + "second_level": 2, + "third_level": 0, + "lane": 2, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2026-10-22", + "level": 2 + } + ], + "layer": "Execution", + "tags": [ + "MDM" + ] + }, + { + "id": "DEMO-CAPABILITY-H3.3", + "name": "Inventory master data (demo)", + "layout": "horizontal", + "first_level": 3, + "second_level": 3, + "third_level": 0, + "lane": 3, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2026-10-22", + "level": 2 + } + ], + "layer": "Execution", + "tags": [ + "MDM" + ] + }, + { + "id": "DEMO-CAPABILITY-H3.2.1", + "name": "Customer data quality checks (demo)", + "layout": "horizontal", + "first_level": 3, + "second_level": 2, + "third_level": 1, + "lane": 2, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2026-10-22", + "level": 4 + } + ], + "layer": "Assurance", + "tags": [ + "MDM", + "Support" + ], + "start_date": "2026-10-22" + }, + { + "id": "DEMO-CAPABILITY-H1.1", + "name": "Order data protection (demo)", + "layout": "horizontal", + "first_level": 1, + "second_level": 1, + "third_level": 0, + "lane": 1, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2026-10-22", + "level": 2 + } + ], + "layer": "Execution", + "tags": [ + "Support" + ] + }, + { + "id": "DEMO-CAPABILITY-H1.1.1", + "name": "Order erasure controls (demo)", + "layout": "horizontal", + "first_level": 1, + "second_level": 1, + "third_level": 1, + "lane": 1, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2026-10-22", + "level": 1 + } + ], + "layer": "Assurance", + "tags": [ + "Support" + ] + }, + { + "id": "DEMO-CAPABILITY-H1.2", + "name": "Customer consent controls (demo)", + "layout": "horizontal", + "first_level": 1, + "second_level": 2, + "third_level": 0, + "lane": 2, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2026-10-22", + "level": 2 + } + ], + "layer": "Execution", + "tags": [ + "Support" + ] + }, + { + "id": "DEMO-CAPABILITY-H1.2.1", + "name": "Consent audit (demo)", + "layout": "horizontal", + "first_level": 1, + "second_level": 2, + "third_level": 1, + "lane": 2, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2026-10-22", + "level": 5 + } + ], + "layer": "Assurance", + "tags": [ + "Support" + ] + }, + { + "id": "DEMO-CAPABILITY-H1.3", + "name": "Warehouse privacy (demo)", + "layout": "horizontal", + "first_level": 1, + "second_level": 3, + "third_level": 0, + "lane": 3, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2026-10-22", + "level": 1 + } + ], + "layer": "Execution", + "tags": [ + "Support" + ] + }, + { + "id": "DEMO-CAPABILITY-V0", + "name": "Improvement backlog (demo)", + "layout": "vertical", + "first_level": 0, + "second_level": 0, + "third_level": 0, + "lane": 0, + "example_origin": "illustrative_extension", + "layer": null, + "tags": [] + }, + { + "id": "DEMO-CAPABILITY-V0.1", + "name": "Unassigned automation (demo)", + "layout": "vertical", + "first_level": 0, + "second_level": 1, + "third_level": 0, + "lane": 0, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2026-10-22", + "level": 0 + } + ], + "layer": null, + "tags": [] + }, + { + "id": "DEMO-CAPABILITY-H1.4", + "name": "Unassigned compliance review (demo)", + "layout": "horizontal", + "first_level": 1, + "second_level": 4, + "third_level": 0, + "lane": 0, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2026-10-22", + "level": 1 + } + ], + "layer": "Assurance", + "tags": [ + "Support" + ] + }, + { + "id": "DEMO-CAPABILITY-H1.4.1", + "name": "Unplaced identity review (demo)", + "layout": "horizontal", + "first_level": 1, + "second_level": 4, + "third_level": 1, + "lane": 0, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2026-10-22", + "level": 1 + } + ], + "layer": "Assurance", + "tags": [ + "Support" + ] + } + ], + "applications": [ + { + "type": "APPLICATION", + "id": "APPLICATION-CRM-1", + "name": "CRM System", + "capabilities": [ + "CAPABILITY-V2", + "DEMO-CAPABILITY-V2.2", + "DEMO-CAPABILITY-H1.2" + ], + "illustrative_mapping_extensions": [ + "DEMO-CAPABILITY-V2.2", + "DEMO-CAPABILITY-H1.2" + ] + }, + { + "type": "APPLICATION", + "id": "APPLICATION-OMS-1", + "name": "Order Management System", + "capabilities": [ + "CAPABILITY-V1", + "DEMO-CAPABILITY-V1.1.1", + "DEMO-CAPABILITY-V1.2.1", + "DEMO-CAPABILITY-H1.1.1" + ], + "illustrative_mapping_extensions": [ + "DEMO-CAPABILITY-V1.1.1", + "DEMO-CAPABILITY-V1.2.1", + "DEMO-CAPABILITY-H1.1.1" + ] + }, + { + "type": "APPLICATION", + "id": "DEMO-APPLICATION-WAREHOUSE", + "name": "Warehouse System (demo)", + "capabilities": [ + "DEMO-CAPABILITY-V3.1.1", + "DEMO-CAPABILITY-H3.3" + ], + "example_origin": "illustrative_extension", + "technical_capabilities": [ + { + "id": "DEMO-TECH-WAREHOUSE-DATA", + "name": "Warehouse reference-data synchronization and checks (demo)", + "capabilities": [ + "DEMO-CAPABILITY-H3.1", + "DEMO-CAPABILITY-H3.3", + "DEMO-CAPABILITY-H3.2.1" + ], + "example_origin": "illustrative_technical_mapping" + } + ] + }, + { + "type": "APPLICATION", + "id": "DEMO-APPLICATION-DATA", + "name": "Data Hub (demo)", + "capabilities": [ + "DEMO-CAPABILITY-H3.1", + "DEMO-CAPABILITY-H3.2", + "DEMO-CAPABILITY-H3.2.1" + ], + "example_origin": "illustrative_extension", + "technical_capabilities": [ + { + "id": "DEMO-TECH-DATA-REFERENCE", + "name": "Reference data services (demo)", + "capabilities": [ + "DEMO-CAPABILITY-H3.1", + "DEMO-CAPABILITY-H3.2" + ], + "example_origin": "illustrative_technical_mapping" + }, + { + "id": "DEMO-TECH-DATA-QUALITY", + "name": "Data quality checks (demo)", + "capabilities": [ + "DEMO-CAPABILITY-H3.2.1" + ], + "example_origin": "illustrative_technical_mapping" + } + ] + }, + { + "type": "APPLICATION", + "id": "DEMO-APPLICATION-GOVERNANCE", + "name": "Governance Portal (demo)", + "capabilities": [ + "DEMO-CAPABILITY-H1.1", + "DEMO-CAPABILITY-H1.2.1", + "DEMO-CAPABILITY-H1.4.1" + ], + "example_origin": "illustrative_extension", + "technical_capabilities": [ + { + "id": "DEMO-TECH-GOVERNANCE-DATA", + "name": "Reference-data controls and quality evidence (demo)", + "capabilities": [ + "DEMO-CAPABILITY-H3.1", + "DEMO-CAPABILITY-H3.2", + "DEMO-CAPABILITY-H3.2.1" + ], + "example_origin": "illustrative_technical_mapping", + "start_date": "2026-10-22" + } + ] + }, + { + "type": "APPLICATION", + "id": "DEMO-APPLICATION-ESG", + "name": "Sustainability Reporting (demo)", + "capabilities": [], + "example_origin": "illustrative_extension" + } + ], + "effective_from": "2026-10-01", + "effective_to": "2027-01-01" + }, + { + "id": "target", + "label": "Target State — illustrative scenario", + "kind": "target", + "as_of": "2027-01-01", + "horizon_label": "Planned demo for 2027; not Acme commitments", + "capabilities": [ + { + "id": "CAPABILITY-V1", + "name": "Order Management", + "layout": "vertical", + "first_level": 1, + "second_level": 0, + "third_level": 0, + "lane": 0, + "start_date": "2024-01-01", + "end_date": null, + "maturity": [ + { + "change_date": "2024-01-01", + "level": 3 + } + ], + "source_target_date": "2026-12-31", + "property_origin": "illustrative_extension", + "layer": "Execution", + "tags": [] + }, + { + "id": "CAPABILITY-V1.1", + "name": "Order Intake", + "layout": "vertical", + "first_level": 1, + "second_level": 1, + "third_level": 0, + "lane": 0, + "start_date": "2024-01-01", + "end_date": null, + "maturity": [ + { + "change_date": "2024-01-01", + "level": 4 + }, + { + "change_date": "2026-05-26", + "level": 3 + } + ], + "property_origin": "illustrative_extension", + "layer": "Execution", + "tags": [] + }, + { + "id": "CAPABILITY-V1.2", + "name": "Order Fulfilment", + "layout": "vertical", + "first_level": 1, + "second_level": 2, + "third_level": 0, + "lane": 0, + "start_date": "2026-05-26", + "end_date": null, + "maturity": [ + { + "change_date": "2026-05-26", + "level": 3 + } + ], + "source_target_date": "2026-09-30", + "property_origin": "illustrative_extension", + "layer": "Execution", + "tags": [] + }, + { + "id": "CAPABILITY-V2", + "name": "Customer Relationship Management", + "layout": "vertical", + "first_level": 2, + "second_level": 0, + "third_level": 0, + "lane": 0, + "start_date": "2024-01-01", + "end_date": null, + "maturity": [ + { + "change_date": "2024-01-01", + "level": 4 + }, + { + "change_date": "2026-05-26", + "level": 3 + } + ], + "property_origin": "illustrative_extension", + "layer": "Strategic", + "tags": [] + }, + { + "id": "CAPABILITY-H1", + "name": "Compliance & Data Protection", + "layout": "horizontal", + "first_level": 1, + "second_level": 0, + "third_level": 0, + "lane": 0, + "start_date": "2026-05-26", + "end_date": null, + "maturity": [ + { + "change_date": "2026-05-26", + "level": 3 + } + ], + "source_target_date": "2026-12-31", + "property_origin": "illustrative_extension", + "layer": null, + "tags": [ + "Support" + ] + }, + { + "id": "DEMO-CAPABILITY-V3", + "name": "Inventory & Warehousing (demo)", + "layout": "vertical", + "first_level": 3, + "second_level": 0, + "third_level": 0, + "lane": 0, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2027-01-01", + "level": 3 + } + ], + "layer": "Execution", + "tags": [] + }, + { + "id": "DEMO-CAPABILITY-V2.1", + "name": "Customer strategy (demo)", + "layout": "vertical", + "first_level": 2, + "second_level": 1, + "third_level": 0, + "lane": 0, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2027-01-01", + "level": 4 + } + ], + "layer": "Strategic", + "tags": [] + }, + { + "id": "DEMO-CAPABILITY-V2.2", + "name": "Customer insights (demo)", + "layout": "vertical", + "first_level": 2, + "second_level": 2, + "third_level": 0, + "lane": 0, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2027-01-01", + "level": 3 + } + ], + "layer": "Learning", + "tags": [] + }, + { + "id": "DEMO-CAPABILITY-V1.3", + "name": "Fulfilment planning (demo)", + "layout": "vertical", + "first_level": 1, + "second_level": 3, + "third_level": 0, + "lane": 0, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2027-01-01", + "level": 4 + } + ], + "layer": "Planning", + "tags": [] + }, + { + "id": "DEMO-CAPABILITY-V3.1", + "name": "Warehouse planning (demo)", + "layout": "vertical", + "first_level": 3, + "second_level": 1, + "third_level": 0, + "lane": 0, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2027-01-01", + "level": 3 + } + ], + "layer": "Planning", + "tags": [] + }, + { + "id": "DEMO-CAPABILITY-V1.1.1", + "name": "Order validation (demo)", + "layout": "vertical", + "first_level": 1, + "second_level": 1, + "third_level": 1, + "lane": 0, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2027-01-01", + "level": 5 + } + ], + "layer": "Execution", + "tags": [] + }, + { + "id": "DEMO-CAPABILITY-V1.2.1", + "name": "Pick and pack (demo)", + "layout": "vertical", + "first_level": 1, + "second_level": 2, + "third_level": 1, + "lane": 0, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2027-01-01", + "level": 4 + } + ], + "layer": "Execution", + "tags": [] + }, + { + "id": "DEMO-CAPABILITY-V3.1.1", + "name": "Stock reconciliation (demo)", + "layout": "vertical", + "first_level": 3, + "second_level": 1, + "third_level": 1, + "lane": 0, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2027-01-01", + "level": 3 + } + ], + "layer": "Assurance", + "tags": [ + "MDM" + ] + }, + { + "id": "DEMO-CAPABILITY-V3.2", + "name": "Returns improvement (demo)", + "layout": "vertical", + "first_level": 3, + "second_level": 2, + "third_level": 0, + "lane": 0, + "example_origin": "illustrative_extension", + "layer": null, + "tags": [ + "ESG" + ] + }, + { + "id": "DEMO-CAPABILITY-H2", + "name": "Sustainability (demo)", + "layout": "horizontal", + "first_level": 2, + "second_level": 0, + "third_level": 0, + "lane": 0, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2027-01-01", + "level": 3 + } + ], + "layer": null, + "tags": [ + "ESG" + ] + }, + { + "id": "DEMO-CAPABILITY-H2.1", + "name": "Packaging impact planning (demo)", + "layout": "horizontal", + "first_level": 2, + "second_level": 1, + "third_level": 0, + "lane": 1, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2027-01-01", + "level": 2 + } + ], + "layer": "Planning", + "tags": [ + "ESG" + ] + }, + { + "id": "DEMO-CAPABILITY-H2.2", + "name": "Warehouse energy (demo)", + "layout": "horizontal", + "first_level": 2, + "second_level": 2, + "third_level": 0, + "lane": 3, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2027-01-01", + "level": 2 + } + ], + "layer": "Execution", + "tags": [ + "ESG" + ] + }, + { + "id": "DEMO-CAPABILITY-H2.1.1", + "name": "Packaging evidence (demo)", + "layout": "horizontal", + "first_level": 2, + "second_level": 1, + "third_level": 1, + "lane": 1, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2027-01-01", + "level": 1 + } + ], + "layer": "Assurance", + "tags": [ + "ESG", + "Support" + ] + }, + { + "id": "DEMO-CAPABILITY-H3", + "name": "Master Data Management (demo)", + "layout": "horizontal", + "first_level": 3, + "second_level": 0, + "third_level": 0, + "lane": 0, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2027-01-01", + "level": 4 + } + ], + "layer": null, + "tags": [ + "MDM" + ] + }, + { + "id": "DEMO-CAPABILITY-H3.1", + "name": "Product reference data (demo)", + "layout": "horizontal", + "first_level": 3, + "second_level": 1, + "third_level": 0, + "lane": 1, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2027-01-01", + "level": 4 + } + ], + "layer": "Execution", + "tags": [ + "MDM" + ] + }, + { + "id": "DEMO-CAPABILITY-H3.2", + "name": "Customer reference data (demo)", + "layout": "horizontal", + "first_level": 3, + "second_level": 2, + "third_level": 0, + "lane": 2, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2027-01-01", + "level": 3 + } + ], + "layer": "Execution", + "tags": [ + "MDM" + ] + }, + { + "id": "DEMO-CAPABILITY-H3.3", + "name": "Inventory master data (demo)", + "layout": "horizontal", + "first_level": 3, + "second_level": 3, + "third_level": 0, + "lane": 3, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2027-01-01", + "level": 3 + } + ], + "layer": "Execution", + "tags": [ + "MDM" + ] + }, + { + "id": "DEMO-CAPABILITY-H3.2.1", + "name": "Customer data quality checks (demo)", + "layout": "horizontal", + "first_level": 3, + "second_level": 2, + "third_level": 1, + "lane": 2, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2027-01-01", + "level": 5 + } + ], + "layer": "Assurance", + "tags": [ + "MDM", + "Support" + ] + }, + { + "id": "DEMO-CAPABILITY-H1.1", + "name": "Order data protection (demo)", + "layout": "horizontal", + "first_level": 1, + "second_level": 1, + "third_level": 0, + "lane": 1, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2027-01-01", + "level": 3 + } + ], + "layer": "Execution", + "tags": [ + "Support" + ] + }, + { + "id": "DEMO-CAPABILITY-H1.1.1", + "name": "Order erasure controls (demo)", + "layout": "horizontal", + "first_level": 1, + "second_level": 1, + "third_level": 1, + "lane": 1, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2027-01-01", + "level": 2 + } + ], + "layer": "Assurance", + "tags": [ + "Support" + ] + }, + { + "id": "DEMO-CAPABILITY-H1.2", + "name": "Customer consent controls (demo)", + "layout": "horizontal", + "first_level": 1, + "second_level": 2, + "third_level": 0, + "lane": 2, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2027-01-01", + "level": 3 + } + ], + "layer": "Execution", + "tags": [ + "Support" + ] + }, + { + "id": "DEMO-CAPABILITY-H1.2.1", + "name": "Consent audit (demo)", + "layout": "horizontal", + "first_level": 1, + "second_level": 2, + "third_level": 1, + "lane": 2, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2027-01-01", + "level": 5 + } + ], + "layer": "Assurance", + "tags": [ + "Support" + ] + }, + { + "id": "DEMO-CAPABILITY-H1.3", + "name": "Warehouse privacy (demo)", + "layout": "horizontal", + "first_level": 1, + "second_level": 3, + "third_level": 0, + "lane": 3, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2027-01-01", + "level": 2 + } + ], + "layer": "Execution", + "tags": [ + "Support" + ] + }, + { + "id": "DEMO-CAPABILITY-V0", + "name": "Improvement backlog (demo)", + "layout": "vertical", + "first_level": 0, + "second_level": 0, + "third_level": 0, + "lane": 0, + "example_origin": "illustrative_extension", + "layer": null, + "tags": [] + }, + { + "id": "DEMO-CAPABILITY-V0.1", + "name": "Unassigned automation (demo)", + "layout": "vertical", + "first_level": 0, + "second_level": 1, + "third_level": 0, + "lane": 0, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2027-01-01", + "level": 1 + } + ], + "layer": null, + "tags": [] + }, + { + "id": "DEMO-CAPABILITY-H1.4", + "name": "Unassigned compliance review (demo)", + "layout": "horizontal", + "first_level": 1, + "second_level": 4, + "third_level": 0, + "lane": 0, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2027-01-01", + "level": 2 + } + ], + "layer": "Assurance", + "tags": [ + "Support" + ] + }, + { + "id": "DEMO-CAPABILITY-H1.4.1", + "name": "Unplaced identity review (demo)", + "layout": "horizontal", + "first_level": 1, + "second_level": 4, + "third_level": 1, + "lane": 0, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2027-01-01", + "level": 2 + } + ], + "layer": "Assurance", + "tags": [ + "Support" + ] + } + ], + "applications": [ + { + "type": "APPLICATION", + "id": "APPLICATION-CRM-1", + "name": "CRM System", + "capabilities": [ + "CAPABILITY-V2", + "DEMO-CAPABILITY-V2.2", + "DEMO-CAPABILITY-H1.2" + ], + "illustrative_mapping_extensions": [ + "DEMO-CAPABILITY-V2.2", + "DEMO-CAPABILITY-H1.2" + ], + "example_origin": "illustrative_target_mapping" + }, + { + "type": "APPLICATION", + "id": "APPLICATION-OMS-1", + "name": "Order Management System", + "capabilities": [ + "CAPABILITY-V1", + "DEMO-CAPABILITY-V1.1.1", + "DEMO-CAPABILITY-V1.2.1", + "DEMO-CAPABILITY-H1.1.1" + ], + "illustrative_mapping_extensions": [ + "DEMO-CAPABILITY-V1.1.1", + "DEMO-CAPABILITY-V1.2.1", + "DEMO-CAPABILITY-H1.1.1" + ], + "example_origin": "illustrative_target_mapping" + }, + { + "type": "APPLICATION", + "id": "DEMO-APPLICATION-WAREHOUSE", + "name": "Warehouse System (demo)", + "capabilities": [ + "DEMO-CAPABILITY-V3.1.1", + "DEMO-CAPABILITY-H3.3", + "DEMO-CAPABILITY-H1.3" + ], + "example_origin": "illustrative_target_mapping", + "technical_capabilities": [ + { + "id": "DEMO-TECH-WAREHOUSE-DATA", + "name": "Warehouse reference-data synchronization and checks (demo)", + "capabilities": [ + "DEMO-CAPABILITY-H3.1", + "DEMO-CAPABILITY-H3.3", + "DEMO-CAPABILITY-H3.2.1" + ], + "example_origin": "illustrative_technical_mapping" + } + ] + }, + { + "type": "APPLICATION", + "id": "DEMO-APPLICATION-DATA", + "name": "Data Hub (demo)", + "capabilities": [ + "DEMO-CAPABILITY-H3.1", + "DEMO-CAPABILITY-H3.2", + "DEMO-CAPABILITY-H3.2.1", + "DEMO-CAPABILITY-H3.3" + ], + "example_origin": "illustrative_target_mapping", + "technical_capabilities": [ + { + "id": "DEMO-TECH-DATA-REFERENCE", + "name": "Reference data services (demo)", + "capabilities": [ + "DEMO-CAPABILITY-H3.1", + "DEMO-CAPABILITY-H3.2", + "DEMO-CAPABILITY-H3.3" + ], + "example_origin": "illustrative_technical_mapping" + }, + { + "id": "DEMO-TECH-DATA-QUALITY", + "name": "Data quality checks (demo)", + "capabilities": [ + "DEMO-CAPABILITY-H3.2.1" + ], + "example_origin": "illustrative_technical_mapping" + } + ] + }, + { + "type": "APPLICATION", + "id": "DEMO-APPLICATION-GOVERNANCE", + "name": "Governance Portal (demo)", + "capabilities": [ + "DEMO-CAPABILITY-H1.1", + "DEMO-CAPABILITY-H1.2.1", + "DEMO-CAPABILITY-H1.4.1" + ], + "example_origin": "illustrative_target_mapping", + "technical_capabilities": [ + { + "id": "DEMO-TECH-GOVERNANCE-DATA", + "name": "Reference-data controls and quality evidence (demo)", + "capabilities": [ + "DEMO-CAPABILITY-H3.1", + "DEMO-CAPABILITY-H3.2", + "DEMO-CAPABILITY-H3.2.1" + ], + "example_origin": "illustrative_technical_mapping" + } + ] + }, + { + "type": "APPLICATION", + "id": "DEMO-APPLICATION-ESG", + "name": "Sustainability Reporting (demo)", + "capabilities": [ + "DEMO-CAPABILITY-H2.1", + "DEMO-CAPABILITY-H2.2", + "DEMO-CAPABILITY-H2.1.1" + ], + "example_origin": "illustrative_target_mapping" + } + ], + "effective_from": "2027-01-01", + "effective_to": "2028-01-01" + }, + { + "id": "historical", + "label": "Historical State — illustrative June 2026", + "kind": "historical", + "as_of": "2026-06-01", + "capabilities": [ + { + "id": "CAPABILITY-V1", + "name": "Order Management", + "layout": "vertical", + "first_level": 1, + "second_level": 0, + "third_level": 0, + "lane": 0, + "start_date": "2024-01-01", + "end_date": null, + "maturity": [ + { + "change_date": "2024-01-01", + "level": 1 + }, + { + "change_date": "2025-06-01", + "level": 2 + }, + { + "change_date": "2026-09-15", + "level": 3 + } + ], + "source_target_date": "2026-12-31", + "property_origin": "illustrative_extension", + "layer": "Execution", + "tags": [] + }, + { + "id": "CAPABILITY-V1.1", + "name": "Order Intake", + "layout": "vertical", + "first_level": 1, + "second_level": 1, + "third_level": 0, + "lane": 0, + "start_date": "2024-01-01", + "end_date": null, + "maturity": [ + { + "change_date": "2026-05-26", + "level": 3 + } + ], + "property_origin": "illustrative_extension", + "layer": "Execution", + "tags": [] + }, + { + "id": "CAPABILITY-V1.2", + "name": "Order Fulfilment", + "layout": "vertical", + "first_level": 1, + "second_level": 2, + "third_level": 0, + "lane": 0, + "start_date": "2026-05-26", + "end_date": null, + "maturity": [ + { + "change_date": "2026-05-26", + "level": 2 + } + ], + "source_target_date": "2026-09-30", + "property_origin": "illustrative_extension", + "layer": "Execution", + "tags": [] + }, + { + "id": "CAPABILITY-V2", + "name": "Customer Relationship Management", + "layout": "vertical", + "first_level": 2, + "second_level": 0, + "third_level": 0, + "lane": 0, + "start_date": "2024-01-01", + "end_date": null, + "maturity": [ + { + "change_date": "2026-05-26", + "level": 2 + } + ], + "property_origin": "illustrative_extension", + "layer": "Strategic", + "tags": [] + }, + { + "id": "CAPABILITY-H1", + "name": "Compliance & Data Protection", + "layout": "horizontal", + "first_level": 1, + "second_level": 0, + "third_level": 0, + "lane": 0, + "start_date": "2026-05-26", + "end_date": null, + "maturity": [ + { + "change_date": "2026-05-26", + "level": 1 + } + ], + "source_target_date": "2026-12-31", + "property_origin": "illustrative_extension", + "layer": null, + "tags": [ + "Support" + ] + }, + { + "id": "DEMO-CAPABILITY-V3", + "name": "Inventory & Warehousing (demo)", + "layout": "vertical", + "first_level": 3, + "second_level": 0, + "third_level": 0, + "lane": 0, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2026-06-01", + "level": 1 + } + ], + "layer": "Execution", + "tags": [] + }, + { + "id": "DEMO-CAPABILITY-V2.1", + "name": "Customer strategy (demo)", + "layout": "vertical", + "first_level": 2, + "second_level": 1, + "third_level": 0, + "lane": 0, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2026-06-01", + "level": 2 + } + ], + "layer": "Strategic", + "tags": [] + }, + { + "id": "DEMO-CAPABILITY-V2.2", + "name": "Customer insights (demo)", + "layout": "vertical", + "first_level": 2, + "second_level": 2, + "third_level": 0, + "lane": 0, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2026-06-01", + "level": 1 + } + ], + "layer": "Learning", + "tags": [] + }, + { + "id": "DEMO-CAPABILITY-V1.3", + "name": "Fulfilment planning (demo)", + "layout": "vertical", + "first_level": 1, + "second_level": 3, + "third_level": 0, + "lane": 0, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2026-06-01", + "level": 2 + } + ], + "layer": "Planning", + "tags": [] + }, + { + "id": "DEMO-CAPABILITY-V3.1", + "name": "Warehouse planning (demo)", + "layout": "vertical", + "first_level": 3, + "second_level": 1, + "third_level": 0, + "lane": 0, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2026-06-01", + "level": 1 + } + ], + "layer": "Planning", + "tags": [] + }, + { + "id": "DEMO-CAPABILITY-V1.1.1", + "name": "Order validation (demo)", + "layout": "vertical", + "first_level": 1, + "second_level": 1, + "third_level": 1, + "lane": 0, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2026-06-01", + "level": 3 + } + ], + "layer": "Execution", + "tags": [] + }, + { + "id": "DEMO-CAPABILITY-V1.2.1", + "name": "Pick and pack (demo)", + "layout": "vertical", + "first_level": 1, + "second_level": 2, + "third_level": 1, + "lane": 0, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2026-06-01", + "level": 2 + } + ], + "layer": "Execution", + "tags": [] + }, + { + "id": "DEMO-CAPABILITY-V3.1.1", + "name": "Stock reconciliation (demo)", + "layout": "vertical", + "first_level": 3, + "second_level": 1, + "third_level": 1, + "lane": 0, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2026-06-01", + "level": 1 + } + ], + "layer": "Assurance", + "tags": [ + "MDM" + ] + }, + { + "id": "DEMO-CAPABILITY-V3.2", + "name": "Returns improvement (demo)", + "layout": "vertical", + "first_level": 3, + "second_level": 2, + "third_level": 0, + "lane": 0, + "example_origin": "illustrative_extension", + "layer": null, + "tags": [ + "ESG" + ] + }, + { + "id": "DEMO-CAPABILITY-H2", + "name": "Sustainability (demo)", + "layout": "horizontal", + "first_level": 2, + "second_level": 0, + "third_level": 0, + "lane": 0, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2026-06-01", + "level": 1 + } + ], + "layer": null, + "tags": [ + "ESG" + ] + }, + { + "id": "DEMO-CAPABILITY-H2.1", + "name": "Packaging impact planning (demo)", + "layout": "horizontal", + "first_level": 2, + "second_level": 1, + "third_level": 0, + "lane": 1, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2026-06-01", + "level": 0 + } + ], + "layer": "Planning", + "tags": [ + "ESG" + ] + }, + { + "id": "DEMO-CAPABILITY-H2.2", + "name": "Warehouse energy (demo)", + "layout": "horizontal", + "first_level": 2, + "second_level": 2, + "third_level": 0, + "lane": 3, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2026-06-01", + "level": 0 + } + ], + "layer": "Execution", + "tags": [ + "ESG" + ] + }, + { + "id": "DEMO-CAPABILITY-H2.1.1", + "name": "Packaging evidence (demo)", + "layout": "horizontal", + "first_level": 2, + "second_level": 1, + "third_level": 1, + "lane": 1, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2026-06-01", + "level": 0 + } + ], + "layer": "Assurance", + "tags": [ + "ESG", + "Support" + ] + }, + { + "id": "DEMO-CAPABILITY-H3", + "name": "Master Data Management (demo)", + "layout": "horizontal", + "first_level": 3, + "second_level": 0, + "third_level": 0, + "lane": 0, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2026-06-01", + "level": 2 + } + ], + "layer": null, + "tags": [ + "MDM" + ] + }, + { + "id": "DEMO-CAPABILITY-H3.1", + "name": "Product reference data (demo)", + "layout": "horizontal", + "first_level": 3, + "second_level": 1, + "third_level": 0, + "lane": 1, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2026-06-01", + "level": 2 + } + ], + "layer": "Execution", + "tags": [ + "MDM" + ] + }, + { + "id": "DEMO-CAPABILITY-H3.2", + "name": "Customer reference data (demo)", + "layout": "horizontal", + "first_level": 3, + "second_level": 2, + "third_level": 0, + "lane": 2, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2026-06-01", + "level": 1 + } + ], + "layer": "Execution", + "tags": [ + "MDM" + ] + }, + { + "id": "DEMO-CAPABILITY-H3.3", + "name": "Inventory master data (demo)", + "layout": "horizontal", + "first_level": 3, + "second_level": 3, + "third_level": 0, + "lane": 3, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2026-06-01", + "level": 1 + } + ], + "layer": "Execution", + "tags": [ + "MDM" + ] + }, + { + "id": "DEMO-CAPABILITY-H1.1", + "name": "Order data protection (demo)", + "layout": "horizontal", + "first_level": 1, + "second_level": 1, + "third_level": 0, + "lane": 1, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2026-06-01", + "level": 1 + } + ], + "layer": "Execution", + "tags": [ + "Support" + ] + }, + { + "id": "DEMO-CAPABILITY-H1.1.1", + "name": "Order erasure controls (demo)", + "layout": "horizontal", + "first_level": 1, + "second_level": 1, + "third_level": 1, + "lane": 1, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2026-06-01", + "level": 0 + } + ], + "layer": "Assurance", + "tags": [ + "Support" + ] + }, + { + "id": "DEMO-CAPABILITY-H1.2", + "name": "Customer consent controls (demo)", + "layout": "horizontal", + "first_level": 1, + "second_level": 2, + "third_level": 0, + "lane": 2, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2026-06-01", + "level": 1 + } + ], + "layer": "Execution", + "tags": [ + "Support" + ] + }, + { + "id": "DEMO-CAPABILITY-H1.2.1", + "name": "Consent audit (demo)", + "layout": "horizontal", + "first_level": 1, + "second_level": 2, + "third_level": 1, + "lane": 2, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2026-06-01", + "level": 4 + } + ], + "layer": "Assurance", + "tags": [ + "Support" + ] + }, + { + "id": "DEMO-CAPABILITY-H1.3", + "name": "Warehouse privacy (demo)", + "layout": "horizontal", + "first_level": 1, + "second_level": 3, + "third_level": 0, + "lane": 3, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2026-06-01", + "level": 0 + } + ], + "layer": "Execution", + "tags": [ + "Support" + ] + }, + { + "id": "DEMO-CAPABILITY-V0", + "name": "Improvement backlog (demo)", + "layout": "vertical", + "first_level": 0, + "second_level": 0, + "third_level": 0, + "lane": 0, + "example_origin": "illustrative_extension", + "layer": null, + "tags": [] + }, + { + "id": "DEMO-CAPABILITY-V0.1", + "name": "Unassigned automation (demo)", + "layout": "vertical", + "first_level": 0, + "second_level": 1, + "third_level": 0, + "lane": 0, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2026-06-01", + "level": 0 + } + ], + "layer": null, + "tags": [] + }, + { + "id": "DEMO-CAPABILITY-H1.4", + "name": "Unassigned compliance review (demo)", + "layout": "horizontal", + "first_level": 1, + "second_level": 4, + "third_level": 0, + "lane": 0, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2026-06-01", + "level": 0 + } + ], + "layer": "Assurance", + "tags": [ + "Support" + ] + }, + { + "id": "DEMO-CAPABILITY-H1.4.1", + "name": "Unplaced identity review (demo)", + "layout": "horizontal", + "first_level": 1, + "second_level": 4, + "third_level": 1, + "lane": 0, + "example_origin": "illustrative_extension", + "maturity": [ + { + "change_date": "2026-06-01", + "level": 0 + } + ], + "layer": "Assurance", + "tags": [ + "Support" + ] + } + ], + "applications": [ + { + "type": "APPLICATION", + "id": "APPLICATION-CRM-1", + "name": "CRM System", + "capabilities": [ + "CAPABILITY-V2", + "DEMO-CAPABILITY-V2.2", + "DEMO-CAPABILITY-H1.2" + ], + "illustrative_mapping_extensions": [ + "DEMO-CAPABILITY-V2.2", + "DEMO-CAPABILITY-H1.2" + ] + }, + { + "type": "APPLICATION", + "id": "APPLICATION-OMS-1", + "name": "Order Management System", + "capabilities": [ + "CAPABILITY-V1", + "DEMO-CAPABILITY-V1.1.1", + "DEMO-CAPABILITY-V1.2.1", + "DEMO-CAPABILITY-H1.1.1" + ], + "illustrative_mapping_extensions": [ + "DEMO-CAPABILITY-V1.1.1", + "DEMO-CAPABILITY-V1.2.1", + "DEMO-CAPABILITY-H1.1.1" + ] + }, + { + "type": "APPLICATION", + "id": "DEMO-APPLICATION-WAREHOUSE", + "name": "Warehouse System (demo)", + "capabilities": [ + "DEMO-CAPABILITY-V3.1.1", + "DEMO-CAPABILITY-H3.3" + ], + "example_origin": "illustrative_extension", + "technical_capabilities": [] + }, + { + "type": "APPLICATION", + "id": "DEMO-APPLICATION-DATA", + "name": "Data Hub (demo)", + "capabilities": [ + "DEMO-CAPABILITY-H3.1" + ], + "example_origin": "illustrative_extension", + "technical_capabilities": [ + { + "id": "DEMO-TECH-DATA-REFERENCE", + "name": "Reference data services (demo)", + "capabilities": [ + "DEMO-CAPABILITY-H3.1" + ], + "example_origin": "illustrative_historical_mapping" + } + ] + }, + { + "type": "APPLICATION", + "id": "DEMO-APPLICATION-GOVERNANCE", + "name": "Governance Portal (demo)", + "capabilities": [ + "DEMO-CAPABILITY-H1.1", + "DEMO-CAPABILITY-H1.2.1", + "DEMO-CAPABILITY-H1.4.1" + ], + "example_origin": "illustrative_extension", + "technical_capabilities": [] + }, + { + "type": "APPLICATION", + "id": "DEMO-APPLICATION-ESG", + "name": "Sustainability Reporting (demo)", + "capabilities": [], + "example_origin": "illustrative_extension" + } + ], + "effective_from": "2026-06-01", + "effective_to": "2026-10-01" + } + ], + "example_kind": "illustrative_extension", + "source_core_asset": "acme-corp-source-example.json", + "coverage_system_id": "DEMO-APPLICATION-DATA", + "view_date": "2026-10-23" +} diff --git a/transitrix/skills/render-dsm-capabilities-html/assets/icon.svg b/transitrix/skills/render-dsm-capabilities-html/assets/icon.svg new file mode 100644 index 0000000..2468028 --- /dev/null +++ b/transitrix/skills/render-dsm-capabilities-html/assets/icon.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/transitrix/skills/render-dsm-capabilities-html/assets/synthetic-regression.json b/transitrix/skills/render-dsm-capabilities-html/assets/synthetic-regression.json new file mode 100644 index 0000000..4a8a670 --- /dev/null +++ b/transitrix/skills/render-dsm-capabilities-html/assets/synthetic-regression.json @@ -0,0 +1,432 @@ +{ + "title": "Synthetic capability landscape", + "organisation": "Fictional service company — demonstration only", + "model_revision": "synthetic-demo-3", + "states": [ + { + "id": "current", + "label": "Current State", + "kind": "current", + "as_of": "2026-10-20", + "capabilities": [ + { + "id": "sales", + "name": "Customer & Sales", + "layout": "vertical", + "first_level": 1, + "second_level": 0, + "third_level": 0, + "lane": 0, + "maturity": [ + { + "change_date": "2026-01-01", + "level": 3 + } + ], + "property": "Execution" + }, + { + "id": "acquire", + "name": "Customer acquisition", + "layout": "vertical", + "first_level": 1, + "second_level": 1, + "third_level": 0, + "lane": 0, + "maturity": [ + { + "change_date": "2026-01-01", + "level": 2 + } + ], + "property": "Planning" + }, + { + "id": "lead", + "name": "Lead qualification", + "layout": "vertical", + "first_level": 1, + "second_level": 1, + "third_level": 1, + "lane": 0, + "maturity": [ + { + "change_date": "2026-01-01", + "level": 1 + } + ], + "property": "Execution" + }, + { + "id": "deliver", + "name": "Service Delivery", + "layout": "vertical", + "first_level": 2, + "second_level": 0, + "third_level": 0, + "lane": 0, + "maturity": [ + { + "change_date": "2026-01-01", + "level": 4 + } + ], + "property": "Execution" + }, + { + "id": "fulfil", + "name": "Order fulfilment", + "layout": "vertical", + "first_level": 2, + "second_level": 1, + "third_level": 0, + "lane": 0, + "maturity": [ + { + "change_date": "2026-01-01", + "level": 3 + } + ], + "property": "Planning" + }, + { + "id": "schedule", + "name": "Schedule delivery", + "layout": "vertical", + "first_level": 2, + "second_level": 1, + "third_level": 1, + "lane": 0, + "maturity": [ + { + "change_date": "2026-01-01", + "level": 2 + } + ], + "property": "Execution" + }, + { + "id": "backlog", + "name": "Backlog", + "layout": "vertical", + "first_level": 0, + "second_level": 0, + "third_level": 0, + "lane": 0 + }, + { + "id": "idea", + "name": "Unassigned improvement", + "layout": "vertical", + "first_level": 0, + "second_level": 1, + "third_level": 0, + "lane": 0 + }, + { + "id": "risk", + "name": "Risk Management", + "layout": "horizontal", + "first_level": 1, + "second_level": 0, + "third_level": 0, + "lane": 0, + "maturity": [ + { + "change_date": "2026-01-01", + "level": 2 + } + ], + "property": "Strategic" + }, + { + "id": "customer-risk", + "name": "Customer risk assessment", + "layout": "horizontal", + "first_level": 1, + "second_level": 1, + "third_level": 0, + "lane": 1, + "maturity": [ + { + "change_date": "2026-01-01", + "level": 2 + } + ], + "property": "Learning" + }, + { + "id": "checks", + "name": "Eligibility checks", + "layout": "horizontal", + "first_level": 1, + "second_level": 1, + "third_level": 1, + "lane": 1, + "maturity": [ + { + "change_date": "2026-01-01", + "level": 1 + } + ], + "property": "Execution" + }, + { + "id": "delivery-risk", + "name": "Delivery risk control", + "layout": "horizontal", + "first_level": 1, + "second_level": 2, + "third_level": 0, + "lane": 2, + "maturity": [ + { + "change_date": "2026-01-01", + "level": 3 + } + ], + "property": "Planning" + }, + { + "id": "unknown-risk", + "name": "Unplaced risk capability", + "layout": "horizontal", + "first_level": 1, + "second_level": 3, + "third_level": 0, + "lane": 0, + "property": "Support" + }, + { + "id": "data", + "name": "Data Management", + "layout": "horizontal", + "first_level": 2, + "second_level": 0, + "third_level": 0, + "lane": 0, + "property": "MDM" + }, + { + "id": "quality", + "name": "Delivery data quality", + "layout": "horizontal", + "first_level": 2, + "second_level": 1, + "third_level": 0, + "lane": 2, + "maturity": [ + { + "change_date": "2026-01-01", + "level": 0 + } + ], + "property": "ESG" + } + ], + "applications": [ + { + "type": "APPLICATION", + "id": "app-crm", + "name": "CRM", + "capabilities": [ + "acquire", + "lead" + ] + }, + { + "type": "APPLICATION", + "id": "app-erp", + "name": "ERP", + "capabilities": [ + "fulfil", + "quality" + ] + }, + { + "type": "APPLICATION", + "id": "app-unknown", + "name": "Service portal" + } + ] + }, + { + "id": "target", + "label": "Target State", + "kind": "target", + "horizon_label": "end of 2027", + "capabilities": [ + { + "id": "sales", + "name": "Customer & Sales", + "layout": "vertical", + "first_level": 1, + "second_level": 0, + "third_level": 0, + "lane": 0, + "property": "Execution" + }, + { + "id": "acquire", + "name": "Customer acquisition", + "layout": "vertical", + "first_level": 1, + "second_level": 1, + "third_level": 0, + "lane": 0, + "property": "Planning" + }, + { + "id": "lead", + "name": "Lead qualification", + "layout": "vertical", + "first_level": 1, + "second_level": 1, + "third_level": 1, + "lane": 0, + "property": "Execution" + }, + { + "id": "deliver", + "name": "Service Delivery", + "layout": "vertical", + "first_level": 2, + "second_level": 0, + "third_level": 0, + "lane": 0, + "property": "Execution" + }, + { + "id": "fulfil", + "name": "Order fulfilment", + "layout": "vertical", + "first_level": 2, + "second_level": 1, + "third_level": 0, + "lane": 0, + "property": "Planning" + }, + { + "id": "schedule", + "name": "Schedule delivery", + "layout": "vertical", + "first_level": 2, + "second_level": 1, + "third_level": 1, + "lane": 0, + "property": "Execution" + }, + { + "id": "backlog", + "name": "Backlog", + "layout": "vertical", + "first_level": 0, + "second_level": 0, + "third_level": 0, + "lane": 0 + }, + { + "id": "idea", + "name": "Unassigned improvement", + "layout": "vertical", + "first_level": 0, + "second_level": 1, + "third_level": 0, + "lane": 0 + }, + { + "id": "risk", + "name": "Risk Management", + "layout": "horizontal", + "first_level": 1, + "second_level": 0, + "third_level": 0, + "lane": 0, + "property": "Strategic" + }, + { + "id": "customer-risk", + "name": "Customer risk assessment", + "layout": "horizontal", + "first_level": 1, + "second_level": 1, + "third_level": 0, + "lane": 1, + "property": "Learning" + }, + { + "id": "checks", + "name": "Eligibility checks", + "layout": "horizontal", + "first_level": 1, + "second_level": 1, + "third_level": 1, + "lane": 1, + "property": "Execution" + }, + { + "id": "delivery-risk", + "name": "Delivery risk control", + "layout": "horizontal", + "first_level": 1, + "second_level": 2, + "third_level": 0, + "lane": 2, + "property": "Planning" + }, + { + "id": "unknown-risk", + "name": "Unplaced risk capability", + "layout": "horizontal", + "first_level": 1, + "second_level": 3, + "third_level": 0, + "lane": 0, + "property": "Support" + }, + { + "id": "data", + "name": "Data Management", + "layout": "horizontal", + "first_level": 2, + "second_level": 0, + "third_level": 0, + "lane": 0, + "property": "MDM" + }, + { + "id": "quality", + "name": "Delivery data quality", + "layout": "horizontal", + "first_level": 2, + "second_level": 1, + "third_level": 0, + "lane": 2, + "property": "ESG" + } + ], + "applications": [ + { + "type": "APPLICATION", + "id": "app-crm", + "name": "CRM", + "capabilities": [ + "acquire", + "lead", + "customer-risk" + ] + }, + { + "type": "APPLICATION", + "id": "app-erp", + "name": "ERP", + "capabilities": [ + "fulfil", + "quality", + "schedule" + ] + } + ] + } + ] +} diff --git a/transitrix/skills/render-dsm-capabilities-html/references/acme-corp-LICENSE.txt b/transitrix/skills/render-dsm-capabilities-html/references/acme-corp-LICENSE.txt new file mode 100644 index 0000000..5b1e833 --- /dev/null +++ b/transitrix/skills/render-dsm-capabilities-html/references/acme-corp-LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023-2026 Valerii Korobeinikov + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/transitrix/skills/render-dsm-capabilities-html/references/acme-corp-example.md b/transitrix/skills/render-dsm-capabilities-html/references/acme-corp-example.md new file mode 100644 index 0000000..fbf5ea7 --- /dev/null +++ b/transitrix/skills/render-dsm-capabilities-html/references/acme-corp-example.md @@ -0,0 +1,189 @@ +# Acme Corp example: source core and illustrative extension + +Source: https://github.com/transitrix/acme-corp +Revision: e331590b13935d1d0922063acbf1f6a0cb3cdba2 (main read on 2026-10-22). +Assessment/knowledge date: 2026-10-22. + +`assets/acme-corp-source-example.json` preserves the source-only display adapter. +`assets/example.json` is now the explicitly illustrative extended demonstration. `assets/acme-corp-source.json` +retains the 15 exact YAML source files and their Git blob SHAs. Each SHA was +verified from the retained UTF-8 bytes using Git's blob hash calculation. +Original source licence: [MIT](acme-corp-LICENSE.txt). + +## Mapping + +- Scope and display hierarchy: `views/capabilities/compliance-domain.capability-map.transitrix.yaml`. + It supplies V1, V1.1, V1.2, V2 and H1. Preserve canonical IDs with the + CAPABILITY- prefix, primitive names and lifetimes. V/H and X.Y.Z are parsed + from those explicit addresses; L1 vertical lane=0 is legacy display metadata, + not a backlog classification. +- Confirm Order Intake's current parent using the effective + REL-CAP-V11-PARENT-2 record. Its previous relation to V2 ended in April. +- Current maturity comes from each primitive's `current_maturity` sidecar series, + resolved as of the explicit assessment date. Values in order V1, V1.1, V1.2, + V2, H1: 3, 3, 2, 2, 1. Source history dates are preserved. +- The separate Declared Target Maturity snapshot displays the source + `target_maturity` series, resolved at the same knowledge date: all five are 3. + That date selects what target was recorded, not when the target was achieved. + Per-capability deadlines remain in `source_target_date` (where supplied); + there is no invented common completion date or successful outcome. +- Current APPLICATION mappings use only the explicit `capabilities` lists on + APPLICATION-OMS-1 and APPLICATION-CRM-1: OMS → V1; CRM → V2. Do not inherit + either mapping to children. Capability V1's inverse `applications` list also + mentions CRM, but the APPLICATION-side list does not support CRM → V1. This + adapter preserves its declared APPLICATION-side contract instead of merging + inconsistent directions silently. +- No target application mapping is supplied by the source. The preserved source-only target snapshot + therefore has no APPLICATION mappings; current support is not copied forward + as a promised target architecture. + +## Deliberately absent + +The source has five capabilities, no L3 records, no H-L2/L3 lane assignments, +no backlog records and no DSM `property` classification. Those fields remain +absent from the preserved source-only adapter. They are supplied by the separate +teaching extension below, created on 2026-10-23. + +## Expanded teaching example — 2026-10-23 + +The live preview now uses 32 capabilities and six applications across Current +and Target demo scenarios. This is an illustrative extension of Acme's five +source records, not an update to Acme canon or a claimed future architecture. +The visible title and organisation declare the demonstration; added capability +and application IDs start with DEMO-, and their names include (demo). + +`assets/acme-corp-demo-extensions.json` identifies the 27 added capability IDs, +four added application IDs, explicit classification overlays on the five source +records and illustrative extensions to OMS/CRM mappings. Source capability +fields and maturity histories remain unchanged apart from the labelled classification +overlays. The original source-only JSON, raw YAML and source licence are retained. + +The current teaching overlay uses independent `layer` and `tags` fields. All +five stages have explicit examples: + +| Stage | Demonstration content | +|---|---| +| Strategic | Customer strategy in the CRM domain | +| Learning | Customer insights in the CRM domain | +| Planning | Fulfilment/warehouse planning and packaging impact planning | +| Execution | Order intake/fulfilment, pick/pack, reference-data maintenance and privacy operations | +| Assurance | Stock reconciliation, packaging evidence, consent audit, erasure controls and customer data quality checks | + +MDM, ESG and Compliance remain horizontal capabilities with explicit lane +children. Their broad roots have no invented single cycle stage. The descendants +carry explicit MDM, ESG or Support tags. Packaging evidence carries ESG + Support; +customer data quality checks carries MDM + Support. Stock reconciliation carries MDM +inside a vertical inventory branch; returns improvement carries ESG. These are +explicit illustrative assignments, not inferred source facts, and make filters +exercise both orientations, multiple tags and untagged parent context. + +`acme-corp-demo-extensions.json` records per-state classification assignments for +all 32 capabilities and retains the previous property overlay for traceability. +The source-only adapter and raw source records remain unchanged. + +Unclassified improvement records demonstrate Not specified. The backlog contains +an unassigned vertical child and unplaced horizontal L2/L3 records. Maturity +examples cover 0–5 and Not assessed. H-L2/L3 lane values are explicit and agree +with their parent lane; they reference V-L1 numeric coordinates, never IDs. + +The six systems demonstrate direct many-to-many support and missing mappings. +Sustainability Reporting has no current mappings and three illustrative target +mappings; Data Hub and Warehouse System also gain explicit target links. All +target APPLICATION mappings in this extension are illustrative. Added target +maturity values are teaching choices, not forecasts generated by the renderer. +The example assessment date remains 2026-10-22; the overlay was authored on +2026-10-23. Neither scenario claims a live operational measurement. + +The separate synthetic regression fixture still exercises renderer invariants. +Historical screenshots/exports remain as evidence of their earlier datasets. + +## One-system coverage pilot — renderer 5.0 + +The configured pilot is **Data Hub (demo)**, `DEMO-APPLICATION-DATA`. Its existing +current direct mappings remain product reference data, customer reference data +and customer data quality checks; the illustrative target also maps inventory +master data. The technical inventory adds two explicitly illustrative abilities: +Reference data services and Data quality checks, with DEMO-TECH IDs. Their links +are supplied separately in each state and currently corroborate those same +business targets; they do not invent additional coverage or inherit mappings. + +The overlay manifest records the exact per-state technical assignments. The +polygon and translucent Data Hub name are a visualization prototype, not a +claim of measured sufficiency, coverage percentage or deployed Acme architecture. + +## Multi-system coverage demonstration — renderer 5.1 + +The demo extension manifest records technical reference-data controls for +Governance Portal and warehouse reference-data synchronization/checks for +Warehouse System, in both Current and Target. These are explicit illustrative +links to existing demo business records; source-core and direct APPLICATION +mappings are unchanged. Data Hub, Governance Portal and Warehouse System share +Product reference data and Customer data quality checks. Data Hub and Governance +Portal also share Customer reference data. Warehouse includes Inventory master +data; Data Hub joins that record in Target. + +To inspect: enable Coverage polygons, select these three systems, filter MDM +and use depth 3. Compare pairwise and triple overlaps, then switch to layers +and Target. Clear one system to see its color and name disappear independently. +Current Sustainability Reporting has no explicit mappings and intentionally +shows no polygon; Target has explicit ESG targets. + +## Dated teaching timeline — renderer 6 + +`view_date` starts on 2026-10-23. Periods are explicitly illustrative: + +- Historical: 2026-06-01 through 2026-09-30, 31 capabilities, lower demo maturity + and Data Hub product references only. The missing quality-check L3 is absent + from that complete snapshot and all its mappings. +- Current: 2026-10-01 through 2026-12-31. Quality checks starts on 2026-10-22; + governance technical controls also start then. At that boundary all 32 business + records appear and the overlapping data coverage is available. +- Planned: 2027-01-01 through 2027-12-31, with target maturity, Data Hub inventory + coverage and Sustainability mappings. These are planned demo assumptions. + +2026-09-15 also changes the source-backed Order Management maturity within the +historical period. Before 2026-06-01 and from 2028-01-01 the example has no data; +the renderer must show that instead of extrapolating. The extension manifest +records these teaching assignments. The raw/source-only Acme assets are unchanged; +this is not recovered history, a measured daily observation or a future promise. + +## Context legend and presentation — renderer 6.2 + +Start with optional modes off: no technical footer or irrelevant maturity/system +legend appears. Enable Maturity, choose an application to highlight, or select +Data Hub/Governance Portal/Warehouse coverage to see only the corresponding +legend entries. Switch to stage bands or an MDM context filter for their keys. +Diagram notes retains technical revisions and the scenario-view boundary. +Diagram only hides the controls; Show controls or Esc restores them without +changing the chosen date, systems, layers, tags or legend. + +## Whole-map presentation — renderer 6.3 + +Select Data Hub, Governance Portal and Warehouse coverage, then enable Diagram +only: the complete Acme map fits below the persistent scale toolbar. Zoom in to +inspect intersections, use 100% for native detail, and press fit-to-screen to +return to the whole map. Restore controls and change date/layers/legend while +fit is active to verify automatic refitting. SVG export preserves native +geometry regardless of the chosen viewing scale. + +## Polygon intersections — renderer 6.6 + +Enable Coverage polygons, select Data Hub/Governance Portal/Warehouse System and +check Functional overlap. Use target date 2027-01-01 and tag MDM for a compact +example: red follows the actual polygon intersection perimeter, including sloped +edges. Capability cut-outs do not add steps or inner contours around records. +Three-way intersections have no internal pairwise red seams. Change date, depth +or layout to check rebuilt contours. Unselect systems down to one, or turn +coverage off: contours disappear and the checked diagnostic is remembered. +Legend off preserves the contour; native SVG preserves its union-boundary filter. +The existing illustrative mappings supply the geometry; no source facts were +added. Prior 6.4 validation is historical and describes a replaced diagnostic. + +## Shape and corner comparison — renderer 6.7 + +Select current OMS/CRM/Governance coverage and Functional overlap. Compare Angled +with Rectangular, then toggle Round corners independently for all four +combinations. Rectangular coverage spans each system's bounding rectangle; +rounding trims corners. Red follows the chosen exterior shapes and does not +acquire box cut-out steps. Try layers/depth/date changes and switch back: shape +settings persist and the original hull is restored without cumulative edits. diff --git a/transitrix/skills/render-dsm-capabilities-html/references/date-timeline.md b/transitrix/skills/render-dsm-capabilities-html/references/date-timeline.md new file mode 100644 index 0000000..972a736 --- /dev/null +++ b/transitrix/skills/render-dsm-capabilities-html/references/date-timeline.md @@ -0,0 +1,128 @@ +# State on a date — adapter/renderer 6 + +Use explicit state periods for historical, current and planned views. A date +selects a supplied period; it does not interpolate between Current and Target, +recover missing history or infer deployment from a plan. + +## Period and date inputs + +Each dated state has `effective_from` (inclusive ISO date) and optional +`effective_to` (exclusive ISO date). A null/absent end explicitly means open-ended. +State `kind` is `historical`, `current` or `target`; it records source intent, +not a label inferred from the computer's clock. `as_of` remains the supplied +snapshot/evidence basis. A descriptive `horizon_label` never becomes a date. + +```json +{ + "view_date": "2026-10-23", + "states": [ + {"id":"history", "label":"Historical snapshot", "kind":"historical", + "as_of":"2026-06-01", "effective_from":"2026-06-01", + "effective_to":"2026-10-01", "capabilities":["...complete records..."], + "applications":["...complete applications and explicit mappings..."]}, + {"id":"current", "label":"Current snapshot", "kind":"current", + "as_of":"2026-10-22", "effective_from":"2026-10-01", + "effective_to":"2027-01-01", "capabilities":["...complete records..."], + "applications":["...complete applications and explicit mappings..."]}, + {"id":"plan", "label":"Approved planning scenario", "kind":"target", + "as_of":"2027-01-01", "effective_from":"2027-01-01", + "effective_to":"2028-01-01", "capabilities":["...complete records..."], + "applications":["...complete applications and explicit mappings..."]} + ] +} +``` + +The snippet illustrates the wrapper; replace placeholder strings with valid +records. Every state supplies a complete independent snapshot. Do not copy links +or attributes across states implicitly. Periods must not overlap; alternative +scenarios need separate timelines or undated manually selected states. Gaps are +allowed and mean no supplied data, including before the first and after a finite +last period. A current snapshot covering a future date remains a snapshot-based +projection, not evidence that the future happened. Targets are explicitly marked +`Planned scenario; not an observed outcome`, even when inspected at a later date. + +Optional top-level `view_date` chooses the initial HTML date, or the default +direct SVG date when no explicit state is selected. Without it, dated HTML starts +on the browser's local Today. A caller may override with `--date YYYY-MM-DD` or +Python `view_date='YYYY-MM-DD'`. An explicit `--state` must match the period when +combined with `--date`. Date gaps fail direct SVG generation and clear the HTML +map, disabling Download/Print rather than exporting the previous valid map. + +Undated legacy states remain available through State. Selecting one clears the +date and displays snapshot mode. `--as-of` retains its legacy current-state +fallback meaning; it does not choose a timeline period. Use `--date` for that. +A timeline's `effective_from` supplies an evaluation date when `as_of` is absent, +while snapshot-basis metadata remains not specified. + +## Changes inside a period + +Capabilities retain their existing inclusive `start_date`/`end_date` lifetimes +and dated maturity assessments. APPLICATION and nested technical-capability +entries may now have the same optional inclusive lifetime fields. An inactive +system contributes no direct labels, highlight or polygon; inactive technical +abilities contribute no technical links. Missing lifetimes mean open bounds. +All declared references still validate against the complete source state; a +mapping to a currently inactive capability creates no visible coverage. + +Within a state, names, classification, coordinates and mapping lists are the +supplied values. Represent changes to these values by another complete dated +state. Do not turn string mapping IDs into unvalidated dated relationship +objects. The renderer does not merge snapshots or invent link histories. + +For any selected date, include only active capabilities, require active parents +and vertical lane roots, and select the latest maturity assessment on/before +that date. Reject reversed lifetimes and conflicting assessments. Include +validity start days and end days; remove on the day after an inclusive end. +State periods instead switch on the exclusive `effective_to` boundary. + +HTML precomputes geometry only at explicit change boundaries: state starts, +lifetime starts, the day after lifetime ends, and maturity changes. It embeds +the same 64 geometry variants per segment as direct SVG. Every date within a +segment shares business geometry and evaluated mappings; its exact chosen date +replaces the visible date caption and metadata. No per-day expansion or second +browser-side layout algorithm is needed. + +## Controls and exports + +View date accepts past, present and future dates. The Timeline slider moves by +one calendar day and updates on input while dragging, coalescing redraws to +animation frames. It has date output, range endpoints and ticks at supplied +changes. Keyboard arrows move one day; Home/End select the displayed bounds. +The date picker, slider and navigation buttons stay synchronized. UTC day +numbers avoid daylight-saving drift; Today uses the browser's local calendar. + +For finite timelines the slider initially spans the earliest period start through +the last included date. An open final period gets an initial display window up +to one year beyond the latest of Today, initial date and final segment start; +this is a UI window, not a limit on model validity. Entering a date beyond the +shown range extends it, including dates with no supplied data. Legacy undated +models disable the slider. Within an unchanged segment and geometry selection, +the SVG is retained and only date captions/metadata/view selection update; +explicit event boundaries select the matching native geometry and mappings. +Capabilities and coverage change at those supplied boundaries, not by +interpolation. + +Controls are grouped into Time, Capability view, Systems & coverage and Export. +Detailed diagram notes are collapsed initially so the map remains visible. Previous/Next change moves to supplied segment boundaries. State also +provides direct snapshot selection; for dated states it selects the snapshot +basis date when inside the period, otherwise the period start. Other view +settings and coverage-system checkboxes survive date changes. Systems absent or +inactive at a date are disabled with choices remembered for their return. Colors +come from all declared systems across all states, including inactive systems. + +SVG records `view_date` (also in `view.view_date`), evaluated `as_of`, original +`snapshot_as_of`, selected state/kind and `[effective_from,effective_to)`. The +native date caption distinguishes requested date from snapshot basis. It also +marks planned scenarios. Export retains only the selected date's native geometry, +visible coverage variants and selected source mappings. HTML contains all supplied +periods and variants; date selection is not data redaction. + +## Methodology boundary + +State periods are this JSON adapter's representation of dated projections. +The merged core methodology now defines dated capability-map view semantics; +see [the mapping](methodology-boundary.md). This does not create a bitemporal +schema, temporal relation kind or prove released DSM/Studio support. Canonical lifecycle bounds must be mapped explicitly, including +the different inclusive record and exclusive state-period endpoints. Source +observation/recording time and model-validity time remain separate; this local +renderer is not a bitemporal audit/history store. diff --git a/transitrix/skills/render-dsm-capabilities-html/references/dsm-rules.md b/transitrix/skills/render-dsm-capabilities-html/references/dsm-rules.md new file mode 100644 index 0000000..67d4897 --- /dev/null +++ b/transitrix/skills/render-dsm-capabilities-html/references/dsm-rules.md @@ -0,0 +1,193 @@ +# DSM Report / NewBCM source rules + +Verified 2026-10-20. This is the classic Report grid, not Editor (C) tree or BCM/BCMFlow. The HTML renderer preserves geometry and visual grammar, with explicitly disclosed safety/correctness adaptations below. These adaptations are not accepted changes to the product contract. + +## Pinned source manifest + +All DSM references below use commit 2e967541488e6f68212b43965a78a7c4a2339948. The six core files were re-fetched explicitly at that commit and matched the extracted contents. + +1. Main Report: https://github.com/transitrix/transitrix-dsm/blob/2e967541488e6f68212b43965a78a7c4a2339948/dsm/src/components/Reports/NewBCM.jsx + blob f696324172c7625cc690577558f74b5eaa8b2132 +2. Vertical renderer: https://github.com/transitrix/transitrix-dsm/blob/2e967541488e6f68212b43965a78a7c4a2339948/dsm/src/components/Reports/CapabilitiesReportVertical.jsx + blob 7a5daedb2e7fded19d3db1d555245d978bfe1a54 +3. Horizontal renderer: https://github.com/transitrix/transitrix-dsm/blob/2e967541488e6f68212b43965a78a7c4a2339948/dsm/src/components/Reports/NewCapabilitiesReportHorizontal.jsx + blob 12e6d100dcd2a2eb753fe990413071c39d247254 +4. Styles: https://github.com/transitrix/transitrix-dsm/blob/2e967541488e6f68212b43965a78a7c4a2339948/dsm/src/styles/reports/_capabilityReport.scss + blob 91d91bc699311f4a613e8adf2a88856a458ec6b1 +5. Concept: https://github.com/transitrix/transitrix-dsm/blob/2e967541488e6f68212b43965a78a7c4a2339948/docs/docs/concepts/bcm-explained.md + blob 9c14e7abb5244e7194c472a5410d5070ad1470ac +6. Assignment/notation: https://github.com/transitrix/transitrix-dsm/blob/2e967541488e6f68212b43965a78a7c4a2339948/assignments/06_0_1_capabilities.md + blob 89840b110c60ebc105714194fd91a2d3e9d16491 +7. Distinct editor implementation: https://github.com/transitrix/transitrix-dsm/blob/2e967541488e6f68212b43965a78a7c4a2339948/dsm/src/components/NewVisualEditor/BCMFlow.jsx +8. Editor data adapter: https://github.com/transitrix/transitrix-dsm/blob/2e967541488e6f68212b43965a78a7c4a2339948/dsm/src/components/NewVisualEditor/VisualEditor.jsx + +Methodology's current document is supporting conceptual evidence, not pinned DSM implementation and not a reliable Studio status report: +https://github.com/transitrix/methodology/blob/main/notations/views/diagrams/05-capability-map.md +Its Studio planned status conflicts with the implemented tree/cards above. Do not repeat it as current fact. + +## Exact NewBCM data model consumed + +Flat capability records, not nested tree input: +- id, name +- universal_item_set_id (selected set ID; set list maps selected set name to ID) +- first_level, second_level, third_level: numeric coordinates +- layout: vertical or horizontal; backlog is identified separately from coordinates in this Report +- lane: numeric intersection placement coordinate; renderer matches horizontal L2 lane to a vertical L1's first_level, NOT its database id +- start_date, end_date: optional lifetime fields +- maturity: optional assessment list with id, change_date, maturity_level_dict.name +- link and property are detail/edit data, not required geometry +- organisation label supplied separately + +Hierarchy: X.0.0 L1, X.Y.0 L2, X.Y.Z L3; each capability has one orientation. V and H coordinates must remain disambiguated. Report labels use v.X.Y.Z/lane or h.X.Y.Z/lane followed by the name. Database id must not be used as the human coordinate or lane target. + +Report backlog uses first_level=0, root 0.0.0. Horizontal unplaced L2 uses lane===0 in the report branch. Documentation also describes null as unplaced. Normalize these explicitly if designing a new input schema; do not silently equate modern set_name.b.o.L1.L2.L3 addressing with the legacy display string. Modern b=1 backlog and legacy first_level=0 require an explicit adapter. + +## Exact classic grid placement + +- L1 vertical roots: first_level!=0, second_level=0, third_level=0, layout=vertical; sorted ascending by first_level. +- V-L1 render as side-by-side columns at the top, gap 1%, width configurable as percent. Backlog is an optional left column. +- Within each V-L1: V-L2 boxes have same first coordinate, second!=0, third=0; V-L3 nest inside their L2 by same first and second coordinates. +- L1 horizontal roots: same L1 coordinate test, layout=horizontal. They render as full-width rows BELOW the vertical column region, not interspersed among it. +- The pinned source gives each H row a narrow rotated vertical left title. This renderer deliberately uses an unrotated horizontal top title within a full-width band instead, as requested for horizontal L1 capabilities. Keep cell columns aligned to the visible V-L1 columns and minimum row content width 500px. +- H-L2 boxes at an intersection require same H first_level, second!=0, third=0, layout=horizontal, lane===V-L1.first_level. H-L3 nest inside their H-L2. +- Unplaced H-L2 (lane=0) occupy optional backlog column. +- Do not create a complete cross-product of capabilities: render only explicitly assigned lane records. One current record has one lane. A many-to-many capability_intersection junction is a future design, not shipped grid input. +- L2 and L3 are nested containers, not dependency arrows, not an org chart, not a treemap whose area encodes magnitude. + +Viewport defaults in source: columnWidth=10%; controls 10..30 in steps of5, with visible columns 10/6/5/4/3 at 10/15/20/25/30%. Source paginates vertical columns. For static printable HTML, showing all columns horizontally or fit-to-page can be an explicit adaptation; it is not source-exact pagination. + +## Exact visual grammar + +- White report surface, margin 8px 12px 20px, radius10px. +- V-L1: white, border3px solid #e2e8f0 in ordinary mode; rounded12px; min-width100px; min-height50vh; flex-column centered; gap5px; font12px; padding top12px/bottom20px. +- L2: background #c9d5f2; border3px solid #c9d5f2; rounded8px; width80%; min-height50px; padding13px; centered flex-column. Shared style gap10px; H-renderer overrides gap20px. +- L3: white; border3px solid white; rounded8px; width90%; min-height50px; centered content; gap5px. +- Labels: 12px, line-height15px, normal weight, #1e1e1e. L3 text padding4px. +- H-L1 source: full-width white/50 container, rounded12px; vertical rotated left title. Renderer adaptation: horizontal top title, with header space reserved above nested cells. Nested box grammar as above. + +Maturity ON is a border+opacity overlay, NOT a colored heat-fill and NOT the tree's round maturity badges: +0 No capability -> dashed3px rgba(15,23,42,.14), opacity .55 +1 Initial -> dashed3px rgba(15,23,42,.28), opacity .65 +2 Managed -> solid3px rgba(15,23,42,.45), opacity .78 +3 Defined -> solid3px rgba(15,23,42,.62), opacity .88 +4 Quantitatively Managed -> solid3px rgba(0,77,103,.82), opacity .95 +5 Optimizing -> solid3px rgba(0,77,103,1), opacity1 +Source class numbers are1..6, distinct from domain maturity0..5. Missing assessment is not maturity0. Source has no maturity class for missing L1/L3 and no-maturity-color (border #c9d5f2) for missing L2. + +## Temporal behavior and known defects: distinguish fidelity from correctness + +Observed implementation, NOT recommended domain rules: +1. NewBCM activeDatesArray lines108ff uses strict start_date < selected date < end_date; boundary equality disappears. Missing bounds are open. An HTML skill must explicitly document boundary semantics or correct them against an authoritative contract, not claim that inclusive dates are exact current NewBCM behavior. +2. Maturity renderer filters change_date <= selected date, then selects highest record id, NOT latest change_date. Correct implementation should use latest effective date and explicitly report same-date ambiguity; mark this as a deliberate correction. +3. Unknown maturity names fall through to class6/Optimizing in source. Do not make an unknown assessment look maximally mature; show unknown. +4. V-L3 filter mistakenly checks the L2 layout instead of L3's layout. H-L3 normal branch lacks lane scoping. Backlog H-L3 branch lacks first-coordinate scoping and uses v label. Validate parent orientation/lane and do not silently duplicate children across groups. +5. Source sorts concatenated coordinates numerically, which breaks multi-digit tuple order. Use numeric tuple sorting, label as correction. +6. Pagination next bound is suspect (levels.length-2); do not reproduce data loss. + +A safe new HTML skill should preserve layout/style, validate unique identities and coordinate parentage, preserve explicit intersection assignment, separate backlog and unknowns, and clearly state adaptations. No invented capabilities, maturity, relationships, dates, or weights. If only names/hierarchy exist, do not invent H/V classification; choose an explicitly documented limited/default mode and expose missing fields. + +## UI scope for the requested HTML artifact + +Suitable local-only controls: set switch, as-of date, backlog toggle, maturity toggle, zoom/fit, print. These are source-inspired, optional. Do not include live DSM edit/save/server callbacks. Avoid promising Studio integration or a released module. A static stand-alone HTML renderer is an interim artifact, not completion of the Studio product feature. + +## Optional property-layer adaptation (renderer 3) + +The classic rules above remain the default. The optional layered view uses the +DSM `property` vocabulary documented in [input contract](input-contract.md#legacy-property-compatibility). +Its property-zone layout is an explicit view adaptation, not a reproduction of DSM +Report geometry. It preserves IDs, original coordinates, domain lanes, depth, +state selection and direct APPLICATION mapping semantics. + +## L1 column correction (renderer 3.3) + +Rechecked the local DSM documentation and Report implementation at +`aa7ac5d0ba99188dd506ef85fd5a5b336bac4f3d` on 2026-10-22: +`docs/docs/concepts/bcm-explained.md` (L1/L2/L3 structure) and +`dsm/src/components/Reports/CapabilitiesReportVertical.jsx` (the outer V-L1 +column, its own address/name and nested L2/L3). The existing pinned rules above +also explicitly require V-L1 columns. Layered mode now preserves each V-L1 as +the column itself rather than a separate property-band card. Its transparent +frame spans every band, with a header above them; L2/L3 remain inside the frame +and explicit horizontal lanes stay aligned. Frame and header retain the L1 ID, +original address, maturity and direct APPLICATION mappings. The column's own +property is shown in its header without inheriting it to any descendant. + +Paint order: canvas background, coloured property zones, V-L1 column frames and +headers, layer headings and other capability cards. Transparent frames allow the +zones to remain visible. Property-zone placement remains an explicit adaptation; renderer 3.7 below +supersedes the earlier flat L2/L3 treatment. This does not assert pixel parity +with DSM Report. + +## Orientation at L2/L3 (renderer 3.4) + +The owner explicitly requested vertical columns for every v.X.X.X record and +horizontal rectangles for every h.X.X.X record. Apply this at all three depths +in both layouts. This extends the previous L1 correction: L2/L3 may no longer use +one shared card shape regardless of layout. Minimum aspect ratios and adaptive +lane widths are renderer presentation choices, not pixel parity with DSM CSS. +The DSM conceptual V=column / H=cross-cutting row distinction remains the source +of orientation semantics; source-coordinate/lane and prefix corrections above +remain in force, including unplaced H-L3 labels. + +## Horizontal labels move left (renderer 3.5) + +The owner requested moving H addresses/names left so they do not occupy the +intersection drawing area. This supersedes the earlier unrotated top-title +adaptation: use an unrotated left label gutter, outside the vertical columns, +for H-L1 in both layouts. H-L2/L3 local labels use start alignment. Classic +intersection boxes sit beside the H-L1 labels rather than below a shared header. +This remains a view adaptation of DSM's original rotated side-title treatment. + +## Visible-content sizing (renderer 3.6) + +The owner's 2026-10-23 request supersedes earlier hidden-label reserved-space +adaptations: system names are off by default, and visible system/maturity lines +participate in layout. Omit placeholder rows and measure actual lines. Enabling +system labels expands mapped boxes; disabling restores compact geometry. V-L2/L3 +may narrow to preserve vertical orientation with less empty area. Domain frames +and lane alignment remain structural. Depth filtering retains its prior reserved +child geometry; this change concerns label stacks and box content sizing. + +## L1/L2/L3 containment correction (renderer 3.7) + +Property sorting must preserve geometric hierarchy as well as IDs. H-L1 encloses +its lane-assigned L2 boxes; every H/V-L2 encloses its L3 boxes. Place same-property +branches together, with H-L1 gutter labels beside lane cells. For different +properties, preserve each label's explicit zone and expand transparent parent +frames around descendant bounds. A child label may precede its parent's label +in layer order, but the child rectangle remains within its parent. Nested SVG +groups preserve H branches and V-L2/L3 through depth filtering and export. +Check boundaries against source coordinates, not only existing DOM nesting: +the old flattened layout could pass the latter without testing any real parent. + +## Five cycle layers and independent tags (renderer 4.0) + +This is an explicit local view/data adapter extension, not source-exact DSM +property behavior. The old seven-item `property` vocabulary is preserved through +an explicit compatibility mapping, not reused as the layer enum. Strategic, +Learning, Planning, Execution and Assurance are stages; ESG, MDM and Support are +box tags and filters. Roots are actual capabilities, never generated from tags. +Each H-L1 owns its own ordered stage zones, below the V-domain region; this +supersedes interspersed global H property bands. Parent containment, explicit +lanes, orientation, direct APPLICATION mappings and exact-view export remain. +The [input contract](input-contract.md#version-4-management-cycle-layers-and-tags) +defines the adapter behavior; [methodology boundary](methodology-boundary.md) +separates the proposed semantics from current canonical support. + +## Readable V-L2/L3 widths (renderer 4.1) + +The owner's width correction supersedes the 3.4 descendant portrait aspect +requirement and 3.6 shrinking algorithm. V-L2 uses 80% of the L1 width; V-L3 +uses 90% of its L2 width, centered. Height comes from text, padding and children, +without a V-L2/L3 portrait floor. V orientation remains visible in the domain +column and stacked branch. H landscape geometry, explicit lanes and source +parent containment remain unchanged. No classification or source data changes. + +## Single-system coverage overlay (renderer 5.0) + +A new owner-requested presentation extension adds a native, translucent system +coverage polygon and translucent system name. It uses explicit direct and +technical mappings for one configured APPLICATION. This is not pinned DSM +Report behavior. The [coverage contract](system-coverage.md) retains separate +direct mappings, depth/filter-aware targets, cut-outs for unlinked capabilities +and exact-view export. No technical nodes or canonical REL types are inferred. diff --git a/transitrix/skills/render-dsm-capabilities-html/references/input-contract.md b/transitrix/skills/render-dsm-capabilities-html/references/input-contract.md new file mode 100644 index 0000000..1257c86 --- /dev/null +++ b/transitrix/skills/render-dsm-capabilities-html/references/input-contract.md @@ -0,0 +1,360 @@ +# Input contract + +One JSON object: `title` and `organisation` are optional strings; `capabilities` is an array for one already-selected set. The renderer does not combine or switch sets. If using `universal_item_set_id`, all records must have the same value. Select the set in an explicit adapter first. + +Each record requires: +- `id`: unique string or integer, separate from its coordinate. +- `name`: nonempty plain text, not HTML. +- `layout`: `vertical` or `horizontal`. +- `first_level`, `second_level`, `third_level`: nonnegative integers. X.0.0 is L1; X.Y.0 is L2; X.Y.Z is L3. Coordinates must be unique within each orientation. L3 requires its L2 and L2 requires its L1. +- `lane`: nonnegative integer. For horizontal L2, it references the **first_level coordinate** of a vertical root, not its database ID. Zero is unplaced. Horizontal L3 must keep its parent's lane. Vertical lanes are retained as supplied display metadata. + +Optional `start_date` and `end_date` use ISO dates; blank/null means open bound. This renderer includes both boundaries. Reject a child active on a date when its parent or targeted domain is inactive rather than silently dropping it. + +Optional `maturity` is an array of `{change_date: "YYYY-MM-DD", maturity_level_dict: {name: "Managed"}}` or `{change_date: "YYYY-MM-DD", level: 2}`. Recognized names: No capability, Initial, Managed, Defined, Quantitatively Managed, Optimizing. Levels are 0..5. Select latest change_date <= as-of; conflicting assessments at that date are ambiguous and rejected. Unknown names display as unknown, not best maturity. + +Legacy backlog: vertical root 0.0.0 with children 0.Y.0 and 0.Y.Z. Unplaced horizontal L2 uses its ordinary horizontal root with lane 0. The tool rejects horizontal first_level=0 as ambiguous. Normalize legacy null lane to zero only after verifying it denotes unplaced. Do not infer a backlog bit from the numeric address of modern `set.b.o.L1.L2.L3` without an explicit adapter. + +The renderer does not accept nested Studio tree JSON, arrows, implicit many-to-many intersections, metrics-as-box-area, or multiple records sharing the same coordinate. Ask for a mapping if a source model requires those semantics. All boxes reflect supplied records, not generated cross-products. + +## Version 2: explicit states and APPLICATION mappings + +Preferred wrapper: + + { + "title": "Capability landscape", + "organisation": "Example organisation", + "model_revision": "user-supplied revision or descriptive snapshot ID", + "states": [ + { + "id": "current", "label": "Current State", "kind": "current", + "as_of": "2026-10-20", "capabilities": [...], + "applications": [ + {"type": "APPLICATION", "id": "app-crm", "name": "CRM", "capabilities": ["sales-l2"]} + ] + }, + { + "id": "target", "label": "Target State", "kind": "target", + "horizon_label": "end of 2027", "capabilities": [...], + "applications": [ + {"type": "APPLICATION", "id": "app-crm", "name": "CRM", "capabilities": ["sales-l2", "service-l2"]} + ] + } + ] + } + +Each state supplies its own complete capabilities and applications. Adapter 6 adds optional explicit date periods and `historical` kind; see [date timeline](date-timeline.md). State IDs are unique; application IDs are unique within a state. The same ID can occur in multiple states but no content or links are carried across implicitly. Target State does not need an exact date; horizon_label is arbitrary plain descriptive text, not parsed as a date. An explicit as_of date selects lifetime records inclusively; without one, the state is taken as a supplied snapshot without temporal filtering. Dated maturity without explicit as_of is rejected rather than inferred. + +`APPLICATION.capabilities` contains capability IDs, not coordinates. References must exist in the same supplied state; duplicates and references to unknown IDs fail. Missing `capabilities` and an empty array both mean no direct support is specified. Neither proves unsupported. The adapter has no unsupported field and rejects unsupported_capabilities and coverage_percent. Adapter 5 adds the explicitly scoped technical_capabilities input described in [system coverage](system-coverage.md). It does not introduce a REL type or promise compatibility beyond this declared view adapter. + +Single-state legacy wrapper remains accepted: top-level capabilities, applications, optional as_of and model_revision. It becomes Current State. The CLI --as-of is a fallback only for current states, not targets; --date selects an explicit date period. Legacy undated HTML opens its first supplied state; dated HTML opens view_date or local Today and exposes all view controls; direct SVG selection uses --state, --system, --depth, --maturity, --system-labels (off by default), --no-system-labels, --no-legend. + +Every SVG includes provenance metadata with separate methodology_revision, adapter_version, renderer_version, model_revision, state_id, state_kind, horizon_label, as_of and view selections. Export does not claim full schema validation or acceptance by Studio/Methodology. + +## Version 4: management-cycle layers and tags + +The classification contract is additive to IDs, hierarchy, orientation, lanes, +scenario snapshots and APPLICATION mappings: + +```json +{"id":"example", "layer":"Assurance", "tags":["MDM","Support"]} +``` + +- `layer`: optional text, null or empty. Recognized values, in display order: + **Strategic, Learning, Planning, Execution, Assurance**. Other explicit values + are rejected. A missing/null/empty stage is unclassified, not an inferred stage. +- `tags`: optional array of distinct **ESG, MDM, Support** strings; default `[]`. + The adapter supports this controlled tag subset; map other canonical free-form + tags explicitly before rendering rather than dropping them. Invalid types, + unknown tags and duplicates are rejected. Tag chips are always displayed for + actual direct tags and included in geometry; an empty tag array uses no row. +- Stages and tags never inherit; there is no orientation inference. A broad L1 + may have no single stage even when its children cover several stages. + +### Legacy property compatibility + +`property` is retained as optional text/null input, without modifying the source: + +| Legacy value | Stage fallback when `layer` is absent | Tags | +|---|---|---| +| One of the five stages | Same stage | Explicit `tags`, if any | +| ESG, MDM or Support | No stage | Merge that value with explicit tags, without duplicates | +| Missing/null/empty | No stage | Explicit tags | +| Other text | Unknown property diagnostic group; preserve raw value in title | Explicit tags | + +Presence of explicit `layer`, including null, overrides the legacy stage +fallback. Legacy tag values still merge into tags. The classification behavior originated in adapter 4; current metadata records +adapter dsm-capability-html/6 and the classification-mapping rule. No classifier is generated from +capability names, application support, maturity, hierarchy or orientation. + +### Layer grouping and geometry + +Enable **Sort by layers** or `--sort-layers`. Only occupied stages are shown; +Not specified and Unknown property are diagnostic groups, not additional +management stages. ESG/MDM/Support never create zones or headings. + +V-L1 frames span aligned domain columns. Their headers show their own stage +when supplied, without classifying children. V descendants are grouped by stage +inside the shared column region. Each H-L1 remains a separate horizontal +container below that region; its explicit lane children are grouped by the same +stage order inside it. Root labels and tags remain in the left gutter above +its local stage headings. SVG zones expose `data-layer-scope` for that context. +Nested parent frames enclose children even across stages and remain transparent. +A layer is a presentation group, not another capability or a dependency edge. + +### Tag filters + +HTML has a single Tag selector: All tags (default), ESG, MDM, Support. Direct +SVG accepts `--tag ESG|MDM|Support`; the Python API uses `tag_filter=''` by default. + +Apply backlog visibility first. Keep records directly carrying the selected tag, +then their source parents and the V-L1 roots needed for horizontal lane context. +Never keep unrelated siblings or infer a tag match from a tagged ancestor. +Context-only boxes are muted; SVG groups expose `data-tags` and +`data-tag-match="match|context"`. Geometry closes unused columns and rows. +An absent tag yields an explicit empty-result message. Depth filtering may hide +a matching descendant while retaining its required parent context, as elsewhere +in this renderer's depth controls. System highlighting remains independent. + +Filter selection persists through state/layout/backlog/system-label/maturity +changes. HTML precomputes 64 layouts per state (16 geometry settings × four tag +selections), using the same builder as direct SVG. SVG metadata preserves +`view.tag_filter`, stage/tag vocabularies, state, horizon and other selections. +Hidden-depth nodes, disabled labels/legend and nonvisible mapping metadata are +removed on download. HTML itself contains the supplied scenarios and all views. + +### Canonical-methodology boundary + +These are JSON adapter fields. Canonical architectural layer remains business; +never write Assurance into it. The merged core correction defines native +management_cycle_stage, projected explicitly to adapter layer. Common canonical +tags remain free-form and are projected to this adapter's bounded display subset. +The corrected native field replaces the earlier extensions-bag proposal. The +source correction is local and unreleased; see +[methodology boundary](methodology-boundary.md) for source revision, inventory +mapping, canonical defaults and consumer-adoption gaps. + +## Backlog visibility (renderer 3.1) + +HTML starts with **Backlog** unchecked. Enabling it restores backlog records. +Direct SVG retains its compatibility default; use `--no-backlog` to hide it. Visibility follows explicit classic-grid coordinates: vertical records +with first_level=0 and their descendants; horizontal L2/L3 records with lane=0 +(unplaced assignments). Horizontal roots remain visible. Do not classify backlog +by a capability name or property value. This differs from Not specified property: +an unclassified capability in a placed domain remains visible. + +Hiding backlog removes its column and reflows the remaining domain columns and +lane-aligned intersections in both classic and layered modes. Empty property +bands disappear. State and layout changes retain the checkbox selection. When no +placed domains remain, render a minimal No placed domains placeholder rather +than reintroducing a backlog column. Source records, coordinates and APPLICATION +links remain unchanged; selected SVGs omit hidden records and record both +`show_backlog` and `view.show_backlog` metadata. HTML contains all supplied data; +this toggle is a display control, not a redaction feature. + +## Layer zone styling (renderer 3.2) + +In layered mode, each occupied layer has a full-width rounded rectangular zone +in a distinct pastel colour. All zone rectangles are emitted immediately after +the canvas background, before any text or capability group, so they remain below +all other diagram elements. Headings and cards have padding inside their zone. +Zone geometry encloses its layer's label slots and local branches; adjacent zones +are separated by gaps. Cross-property parent frames may span several zones. +Zones do not intercept pointer events and are included as native SVG rectangles +in direct and browser exports. Classic mode has no layer zones. Depth and label +filters retain the existing reserved-space behavior within zones. + +## Orientation and readable descendant widths (renderer 4.1) + +`layout` determines the address prefix, domain/stack placement and explicit +intersection lanes. V-L1 is a vertical domain column; V-L2/L3 are nested cards +stacked inside their branch. H records retain landscape geometry at every depth. +Never infer orientation from stage, tags, maturity, ID or capability name. + +V-L2 uses **80% of V-L1 width**; V-L3 uses **90% of its V-L2 width**, centered in +the parent. Height follows visible text and nested descendants, with ordinary +padding and a small minimum. Do not narrow descendants or force a portrait +height/width ratio to distinguish orientation. This supersedes the older 3.4/3.6 +aspect-ratio/shrinking adaptation. It applies in classic and layered modes, with +system labels/maturity on or off. Shared lane widths can still expand when H +content needs more landscape width; percentages remain the same in each layout. + +The minimum V height/width ratio 1.25 applies only to L1 domain frames. H boxes +retain minimum width/height 1.6. These are presentation choices, not fixed DSM +requirements. Stage zones, tags, lane alignment, source-parent containment and +exact-view SVG export are preserved. SVG groups retain original orientation, +coordinates, depth and direct mappings. + +## Horizontal label gutter (renderer 3.5) + +Reserve a 240-unit left region before the first vertical-domain column whenever +horizontal roots are present. Place each H-L1 address/name stack, maturity and +system labels in the gutter, left-aligned and wrapped independently of the lane +content. Keep the H-L1 rectangle full width. In classic mode its H-L2/L3 +intersection boxes begin 16 units below the row top, beside the labels rather +than below them. Row height accommodates both the gutter and the lane contents. +In layered mode use the same gutter for H-L1 bands. H-L2/L3 addresses/names and +support/maturity text are left-aligned within their own intersection rectangles; +nested children remain below those local labels in both layouts. Preserve unrotated text, +explicit lanes, geometry controls and exact-view SVG export. + +## Content-sized labels (renderer 3.6) + +System labels default to false in HTML, render_svg and CLI. Use --system-labels +to enable them in direct SVG; --no-system-labels is a compatible explicit off +switch. Only directly mapped system names produce a label stack. Missing or +empty mappings produce no Systems: not specified line inside boxes. This does +not change the meaning of missing support or the independent system highlight. + +Maturity labels are also opt-in. Missing assessments produce no placeholder +text; a real level-0 assessment and explicit unknown names are retained when +maturity is enabled. Missing properties likewise produce no header placeholder. + +Measure and draw the same visible address/name/optional-label parts, with small +padding and no reserved next text line. Keep V-L2/L3 widths relative to their +parents as specified above; compact height rather than shrinking width. Recompute nested containers, +layer zones, column headers and row positions for each system-label/maturity +combination. Unmapped boxes do not gain empty lines when system labels turn on. +L1 frames still span their domain content; explicit lane alignment remains. + +Portable HTML embeds 64 layouts per state: 16 combinations of classic/layers, +backlog, system labels and maturity, for each of four tag selections. Toggling either label control selects the matching +native SVG geometry before applying system/depth/legend filters. HTML and direct +SVG therefore use identical text measurement and layout; no browser-side copy +of the geometry algorithm or server calls are introduced. + +## Hierarchy containment (renderer 3.7) + +Every source L2 rectangle lies strictly inside its L1 rectangle, and every L3 +inside its L2, in both layouts. Same-property branches share a local row: H-L1 +labels stay in the gutter beside the intersection boxes. Across properties, keep +label slots in their explicit zones and extend the parent frame to the union of +its own slot and descendant bounds, with padding. Parent frames are transparent +so they do not conceal zones or descendants. Cross-property frames can overlap +other frames; source coordinates and nested SVG groups define hierarchy rather +than assigning a new parent from visual overlap. Do not infer a child's property +from its container. Preflight enclosing H geometry to preserve landscape shape. + +Version-4 domain-local H grouping supersedes older descriptions of H-L1 labels +inside a global property band. The earlier sizing and containment requirements +remain, with independent stages and tags instead of a mixed property list. + +## Version 5: system coverage overlays (renderer 5.1 multi-selection) + +Optional model-level `coverage_system_id` preselects one APPLICATION present in +every state. It is a compatibility default, not a restriction on selectable systems. +Any APPLICATION may contain an optional `technical_capabilities` array; each entry has nonempty text `id`, `name` and an explicit +`capabilities` array of business-capability IDs from the same state. Duplicate +technical IDs or links, unknown business references and invalid shapes fail. +Application-level direct mappings remain separate from technical mappings. + +HTML starts with Coverage polygons unchecked. The colored Coverage systems list +allows one or multiple APPLICATION selections, independent of direct highlighting. +Selections persist across views; unavailable systems are disabled in that state. +Direct SVG uses `--coverage` plus repeatable `--coverage-system ID`, or Python API +`coverage=True, coverage_systems=[...]`. Empty selection shows none; invalid or +duplicate IDs fail. Without explicit IDs, direct SVG keeps the legacy pilot +default if present, otherwise selects all APPLICATIONs in the selected state. +No additional geometry variants are needed: each base SVG contains a native +overlay for each system/depth with visible mappings, and controls select the proper one. +Export removes inactive variants, retaining the selected polygon, mask, +watermark and its `data-covered-capabilities`/`data-coverage-sources` evidence. +No diagram nodes are generated from the technical inventory. See +[system coverage](system-coverage.md) for mask, label and empty-view semantics. + +## Version 6: state on a date + +See [date timeline](date-timeline.md) for the authoritative date-selection contract, +period boundaries, inclusive element lifetimes, source-basis distinction, segment +precomputation and no-data handling. State period fields are adapter-only, not +canonical lifecycle fields. Historical, current and target kinds are explicit. + +## Presentation controls and compact legend (renderer 6.2) + +The native SVG footer now contains only a context legend. Entries follow actual +visible marks in the enabled view: management-stage bands, parent/domain context +for a tag filter, direct system labels/highlight, each visible coverage system +with its color, and maturity. No coverage entry is drawn for a selected system +without visible mappings. Default classic view with optional modes off has no +legend text or reserved footer space, even when Legend is checked. Disabling +Legend removes its text/swatches and reduces canvas height; business coordinates +remain unchanged. Direct SVG and HTML use the same labels, wrapping, flow and +view conditions. Export retains only the selected view's legend. + +Technical revisions, methodology hash and the local-adapter disclaimer remain +in SVG metadata. Additional `view_contract` and `mapping_semantics` metadata +state the non-conformance/explicit-scenario and non-inheritance/unknown-mapping +boundaries. The HTML Diagram notes details render model/methodology/adapter/ +renderer/state/date/basis and these explanations for the current date and view. +They are independent of the Legend checkbox and are cleared on a no-data date. + +Diagram only is an unchecked HTML presentation checkbox: hide the controls and +notes, keep the map's title/date/scenario context and chosen legend. Show controls +in the persistent scale toolbar or Esc restores the unchanged settings. It does not change +the JSON schema, scenario selection, SVG geometry or export semantics; there is +no separate API/CLI diagram-only mode. Print always omits HTML controls and the +restore button. The overall temporal/stage/tag/coverage contract is unchanged. + +## Viewport zoom and fit (renderer 6.3) + +A persistent scale toolbar remains available with the main panel hidden. It +contains zoom out/in, a 1–300% slider, 100% reset, fit-to-screen and Show controls. +Entering Diagram only automatically activates fit; fit includes the entire +native canvas (title, date/scenario, all boxes/coverage and enabled legend) in +the map viewport below the toolbar. Fit never enlarges above native 100%. +It recalculates on viewport/header size changes and when a date, layout or +legend changes canvas size. Manual zoom cancels fit and preserves the viewport +center where scrolling permits. Selecting fit again resets map scroll offsets +and centers the complete map. No-data dates disable scale controls. + +CSS transforms are applied to an HTML wrapper inside a correctly sized scroll +stage, not to SVG elements. Zooming and presentation mode leave the native SVG +unchanged; exported coordinates, dimensions, masks, text, legend and metadata +remain identical to direct rendering at that date/view. The scale toolbar and +Show controls are excluded from print, and print uses unscaled native content. +The JSON adapter and CLI have no zoom parameters: this is HTML viewer behavior. + +## Polygon intersection diagnostic (renderer 6.6) + +Functional overlap is an optional view flag over the currently displayed system +polygons. Red contours bound the union of their pairwise geometric intersections, +using outer polygon geometry without capability cut-out masks. This includes intersections +between boxes; it is independent of exact shared business-capability IDs. +See [system coverage](system-coverage.md#functional-overlap--renderer-66) for +geometry, export metadata and selection/CLI behavior. This changes the renderer, +not the input model or methodology. + +The persistent toolbar's Show controls / Hide controls button works in both +directions and stays synchronized with Diagram only. Its aria-expanded state +describes the settings panel. Hiding settings fits the map; showing them retains +all view selections. This viewer behavior does not alter native SVG content. + +## Coverage geometry options (renderer 6.7) + +Polygon shape and Round corners are independent view settings. Their defaults +are angled and false; rectangular uses a bounding rectangle. Date, system +selection, depth, layer and tag filters preserve the settings. SVG records +view.coverage_shape and view.round_coverage and exports the selected geometry. +See [coverage shape controls](system-coverage.md#coverage-shape-controls--renderer-67) +for rounding precision, boolean-overlap behavior and CLI/API options. + +## Visual maturity legend (renderer 6.8) + +When Maturity and Legend are enabled and visible records have maturity labels, +the footer shows six miniature capability boxes, levels 0–5, with each level's +name and a short description. These samples share the actual caprect m0–m5 +classes, rather than introducing a separate color scale. The footer adapts its +columns to canvas width and does not move business nodes. Hiding either option +removes the key and releases its space. SVG export includes the visual key. + +## Native methodology correction and JSON projection + +The merged core specification defines management_cycle_stage on CAPABILITY +and technical_capabilities on APPLICATION. This JSON adapter keeps its existing +layer and technical-entry id keys for compatibility. These are explicit +projection names, not the canonical field names. See +[the source mapping](methodology-boundary.md) and +[bundled core specification](methodology-correction.md). Unknown or unsupported +native view settings require a reported mapping gap, not silent defaults. +SVG metadata separates merged contract revision, reviewed baseline revision, +contract status, renderer/adapter versions and source model revision. diff --git a/transitrix/skills/render-dsm-capabilities-html/references/methodology-boundary.md b/transitrix/skills/render-dsm-capabilities-html/references/methodology-boundary.md new file mode 100644 index 0000000..2d22400 --- /dev/null +++ b/transitrix/skills/render-dsm-capabilities-html/references/methodology-boundary.md @@ -0,0 +1,59 @@ +# Core methodology and standalone renderer mapping + +The merged methodology correction defines native `management_cycle_stage` +on CAPABILITY, application-owned `technical_capabilities`, and declared +capability-map view_config keys. These belong to the main specification, not +an experimental profile or an `extensions` bag. Read the bundled +[core-contract excerpts](methodology-correction.md) for the definitions. + +Reviewed pre-correction baseline: `3c75d0403dd4e2dc618bc9535ea293d0495e1ec1`. +Merged contract revision: `888c03d33c2d899ec85a612901075b67811614e5`. No tagged release includes this correction +yet. The reference methodology linter enforces the new fields. Released CLI +2.11.0 does not reject malformed new stage/view settings; standalone rendering +is not proof of native CLI/DSM/Studio adoption. + +## Source-to-adapter mapping + +| Core model or view | Current standalone JSON / control | Boundary | +| --- | --- | --- | +| Capability `layer: business` | Not consumed as architecture placement | Never replace the canonical architectural layer with a management stage | +| Capability `management_cycle_stage` | Capability JSON `layer` | Explicit five-value mapping; null/missing stays unclassified; no inheritance | +| Common free-form `tags` | Explicit ESG/MDM/Support subset | Preserve other tags in the source; do not silently discard them there | +| APPLICATION `capabilities` | Application JSON `capabilities` | Explicit direct mappings; keep technical paths separate | +| APPLICATION `technical_capabilities[].key` | Technical JSON `id` | Application-local identity, not a new global element TYPE | +| Technical entry `name`, `capabilities` | Same-named JSON fields | Explicit source evidence and references; no guessed abilities | +| Canonical lifecycle bounds | JSON `start_date` / `end_date` | Convert endpoint conventions explicitly; adapter record bounds are inclusive | +| Sidecar current/target maturity | Explicit dated assessments in the chosen snapshot | Do not merge observation and target series or invent target achievement | +| Source snapshots/scenarios | Complete independent adapter states | Preserve evidence date, validity period, model revision and planned intent | +| Declared view_config | HTML settings / CLI arguments | Mapping is explicit; the renderer does not ingest native YAML view_config | + +The core maturity scale remains 1–5. The adapter's explicit 0 No capability is +an absence diagnostic retained for legacy input, not missing data or a newly +adopted sixth canonical level. The visual legend makes the adapter scale +readable; it does not change the source maturity contract. + +## Defaults that require explicit projection + +Core view defaults select no coverage systems and hide backlog. The current +HTML may preselect a supplied pilot; direct SVG retains legacy backlog-on and, +without a pilot, all-system coverage defaults. Project a native view explicitly: +use --no-backlog and pass the selected system IDs rather than relying on those +legacy defaults. Core multi-tag filtering is OR over direct tags; the current +HTML selector supports one tag per view. Unsupported selection shapes must be +reported, not approximated silently. Display filters preserve muted context +and are not redaction. + +## Compatibility and remaining consumer work + +A direct core field supersedes the earlier proposed +extensions.management_cycle_stage convention. Preserve source history, reconcile +conflicting values and migrate explicitly; this renderer never rewrites canon. +APPLICATION technical inventory is now defined in the merged core contract, +while globally addressable technical-capability elements and new temporal REL +kinds are not introduced. New inventory and stage fields do not fabricate their +own history; dated coverage without source history must be disclosed as a snapshot. + +The methodology now includes additive JSON schemas and single-file reference +validation. Native ingestion in this renderer, CLI/DSM/Studio adoption and a +methodology release remain separate work. Bundled source excerpts make the +package usable offline; their immutable public links identify the source. diff --git a/transitrix/skills/render-dsm-capabilities-html/references/methodology-correction.md b/transitrix/skills/render-dsm-capabilities-html/references/methodology-correction.md new file mode 100644 index 0000000..7611de2 --- /dev/null +++ b/transitrix/skills/render-dsm-capabilities-html/references/methodology-correction.md @@ -0,0 +1,255 @@ +# Core methodology source excerpts + +Contract revision: `888c03d33c2d899ec85a612901075b67811614e5`, merged into methodology main on 2026-10-23. +The correction is not yet included in a tagged methodology release. These +excerpts retain the wording at that revision, including its review-time status. +They are reference text, not a second independent specification. + +Sources: [capability map](https://github.com/transitrix/methodology/blob/888c03d33c2d899ec85a612901075b67811614e5/notations/views/diagrams/05-capability-map.md), +[applications](https://github.com/transitrix/methodology/blob/888c03d33c2d899ec85a612901075b67811614e5/notations/views/diagrams/10-applications.md). + +## 6a. Management-cycle stage and tags + +A capability MAY carry `management_cycle_stage`, an optional classification +independent of architectural `layer`, decomposition, V/H orientation, maturity +and application mappings. It belongs on the canonical capability element, not +inside view configuration or an `extensions` bag. Canonical `layer` remains +`business`. Omitted or null means not classified; it does not imply an absent +ability or an incomplete domain. + +The controlled values and display order are: + +| Value | PDCA + Learn correspondence | Capability contribution | +| --- | --- | --- | +| `Strategic` | Act and strategic Plan | Choose direction, strategic goals, priorities and significant organisational improvements; strategic planning | +| `Learning` | Learn, the explicit addition to PDCA | Research, reflection, knowledge capture and sharing, learning and competence development | +| `Planning` | Tactical and operational Plan | Budgets, capacity, resources, scheduling and executable operational plans | +| `Execution` | Do | Perform the domain's work, including operational master-data maintenance | +| `Assurance` | Check | Monitor outcomes, quality, deviations, controls and compliance | + +Strategic planning belongs to Strategic; tactical/operational planning belongs +to Planning. Classify by decision scope and represented ability, not the word +"planning" or a time horizon alone. The order is a layout convention, not a +process sequence. Local improvement can occur in every domain. A composite L1 +can remain unclassified while its children occupy several stages. + +Stages MUST NOT inherit from parents, tags, names, maturity or orientation. +Changing a stage requires an explicit source-model change. Dated views must not +apply a later classification retroactively when no historical source is supplied. +This field does not by itself introduce a new sidecar series. + +`tags` remains the common free-form classifier array. ESG, MDM and Support are +tag values, never management stages. ESG/MDM describe subject affiliation; +Support describes a supporting role and does not automatically change the +capability's `type`. A tag does not create, remove or imply an H capability or +intersection. Actual horizontal capabilities retain their identity, hierarchy, +maturity and explicit application mappings. Tags MUST NOT inherit. + +```yaml +# Fragment of a capability element; admission/lifecycle omitted. +notation: capability +id: CAPABILITY-H1.2.1 +name: Customer data quality control +layer: business +management_cycle_stage: Assurance +tags: [MDM, Support] +``` + +A layer or tag is a source fact; whether/how to show it is view configuration +(§16). Missing classification remains visible as Not specified when grouping; +it is not silently assigned a stage. Unknown authored stage values are invalid. + +--- + +## 16. System coverage, dated views and presentation defaults + +### 16.1 Explicit coverage + +An application's direct `capabilities` list and its technical inventory's +explicit capability lists ([applications catalogue §6a](https://github.com/transitrix/methodology/blob/888c03d33c2d899ec85a612901075b67811614e5/notations/views/diagrams/10-applications.md#6a-technical-capabilities-and-business-coverage)) +are separate evidence paths to business capabilities. A projection MUST declare +its direct-link source and retain both paths in provenance. Conflicting inverse +lists require reconciliation, not union by assumption. Parent/child, tag and +stage classifications do not imply support. Missing mappings mean not specified, +not unsupported, absent or zero coverage. Several links from one application +count once when collecting that application's target set. + +A system polygon encloses its selected visible targets. Connecting empty space, +shape and area do not add mappings or express a coverage percentage. Colored +polygons may mask unrelated boxes. Shape is either an axis-aligned bounding +rectangle or an angled enclosing hull; rounding is independent. Small margins +must not create decorative overlap between neighboring domains. + +Red overlap outlines the boundary of the region inside **at least two selected +outer system polygons**: `R = union over i < j of (P_i intersection P_j)`. +Use the selected rounded/rectangular/angled shape. Ignore box cut-out masks for +this boundary; they must not introduce steps around nested capability boxes. +A triple overlap has no internal pairwise seams; disjoint components have +separate closed contours. Point/edge contact with zero area is not a region. +This is a geometric diagnostic, not proof of equivalent functions, unnecessary +duplication, measured adequacy or a recommendation to retire a system. + +### 16.2 State on a date + +Keep selected model-validity date, evidence/snapshot date, source revision and +observed-versus-planned intent distinct. Resolve capability/parent lifetimes and +current/target maturity from the canonical lifecycle, relation and sidecar +contracts; do not replace them with a renderer's date conventions. A target +state is planned composition, never an observed outcome because its date passed. + +A renderer using full snapshot inputs must identify them as projections and +preserve source revision and evidence date. Dated snapshot windows must have +explicit boundaries; overlapping alternatives require separate scenario +selection. Gaps mean unknown/no supplied state and must not retain a stale map +for export. Missing history cannot be reconstructed by interpolation or copying +current support into a future target. If a source has no dated coverage history, +disclose snapshot-based coverage instead of asserting historical accuracy. + +The standalone HTML adapter uses exclusive snapshot-period ends and inclusive +record lifetime ends. An adapter MUST state and test its conversion from the +source contract; no universal reinterpretation of canonical `valid_to` is made. +Future targets, snapshot projections and date gaps must remain visible in the +rendered context. A descriptive horizon is never parsed into a calendar date. + +### 16.3 view_config defaults + +These keys are declared by this notation under the shared view-config contract. +They contain presentation choices only; all stages, tags, mappings and dated +assessments stay in source elements/relations/sidecars. + +```yaml +view_config: + valid_at: null # use capability_map.assessment_date + scenario: null # optional explicit TARGET_STATE reference; null is no target selection + management_cycle: + group: false + order: [Strategic, Learning, Planning, Execution, Assurance] + tags: + filter: [] # all tags; nonempty values select direct matches (OR) + show: true + display: + depth: 3 # 1, 2 or 3 + backlog: false + maturity: false + legend: true + systems: + highlight: null # optional APPLICATION reference + labels: false + coverage: false + selected: [] # explicit APPLICATION references; empty means no polygons + shape: angled # angled or rectangular + rounded: false + overlap: false # effective only with coverage and two selected systems +``` + +Stage order is fixed to §6a. Tag filters retain direct matches and the muted +parent/domain/lane context required to read them; context does not inherit tags. +Grouping creates only occupied stage zones behind elements, plus missing-value +diagnostics. It must preserve L1/L2/L3 containment and explicit H/V intersections. +Visibility of a layer never depends on the existence of an H capability. + +The maturity legend uses samples matching actual rendered box styles and the +canonical 1–5 scale in CONTRACT §9.4. A legacy adapter may additionally show an +explicit 0 No capability absence diagnostic, clearly distinguished from the +canonical scale; missing maturity is not 0. Hiding Maturity or Legend removes +that key and its reserved space. A general legend explains only enabled modes. +SVG exports the exact selected view, its legend and provenance. Zoom and hiding +controls affect the HTML viewport, not the model or native SVG coordinates. +Display filters are not access controls or redaction. + +### 16.4 Compatibility and implementation status + +The §6a/§16 additions and APPLICATION technical inventory are a core-methodology +correction prepared for review, not an optional extension profile. Existing +architectural layer, common tags, lifecycle and maturity contracts are retained. +No new globally addressable technical-capability TYPE is introduced. + +The standalone renderer currently consumes adapter JSON, not canonical YAML. +It maps management_cycle_stage to its legacy JSON layer field. Its HTML pilot +selection and direct-SVG backlog/all-system defaults must be overridden when +projecting the canonical defaults above. Its bounded ESG/MDM/Support tag menu +is a subset of the common free-form tags, which must remain in the source. + +The machine-readable [additive field schema](https://github.com/transitrix/methodology/blob/888c03d33c2d899ec85a612901075b67811614e5/notations/schemas/capability-map-contract.schema.json) +exposes `capabilityFields`, `applicationFields` and `viewConfig` definitions; +it does not replace the full element/view envelope. `tools/lint.py` implements +these structural checks without a new runtime dependency, application-local key +uniqueness, technical mapping references/lifetimes and view selection references. +It checks canonical elements and native files under `views/`, preserving the +single-file onboarding installation. It does not resolve assessments/history, +render coverage geometry or prove evidence truth. Existing direct APPLICATION +mapping checks remain the consuming validator's responsibility; the new +technical inventory cannot use that legacy boundary to skip its own references. + +Released CLI, DSM and Studio adoption and a methodology release must still be +verified separately before claiming product support. The [compatibility check](https://github.com/transitrix/methodology/blob/888c03d33c2d899ec85a612901075b67811614e5/guides/capability-map-compatibility.md) records +which fields the released CLI actually checks; acceptance with skipped checks +is not evidence of adoption. Until that adoption, a +consumer must report unsupported fields/settings rather than silently dropping +them. Existing `extensions.management_cycle_stage` proposals migrate explicitly +to the defined field; conflicting values require reconciliation, and history is +preserved. Core view keys are no longer to be documented as arbitrary extension +keys. The methodology version pin changes only through the release procedure. + +--- + +## 6a. Technical capabilities and business coverage + +An APPLICATION MAY contain `technical_capabilities`, the named technical +abilities it supplies to support business capabilities. The inventory belongs +on the canonical application element. Its evidence and admission are owned by +the application, not authored only inside a capability-map view. + +Each entry is canonical by containment, with an application-local identity. +It is not a new standalone TYPE or REL kind and must not masquerade as an +independently admitted global element. Identify an entry in its owning application projection by application ID +and local key together. This does not grant independent cross-model reference +semantics or bypass the common promotion rule. Separate technical systems do not share a local key's +identity, even if the text matches. + +| Entry field | Required | Meaning | +| --- | --- | --- | +| `key` | yes | Nonempty string unique within the application | +| `name` | yes | Source-evidenced technical ability | +| `capabilities` | no | Distinct canonical business CAPABILITY references; default empty means not specified | +| `valid_from`, `valid_to` | no | Optional explicit lifetime using the shared primitive lifecycle boundary semantics; omitted bounds are open within the owning application's lifecycle | + +```yaml +# Fragment of an APPLICATION element; common envelope omitted. +id: APPLICATION-CRM-1 +capabilities: [CAPABILITY-V2] +technical_capabilities: + - key: customer-data-validation + name: Customer data validation + capabilities: [CAPABILITY-H1.2.1] + valid_from: "2026-10-01" + valid_to: null +``` + +Direct application mappings and technical-entry mappings retain their separate +provenance. Their union is the application's business target set for a coverage +view; no parent/child inheritance is implied. All references must resolve before +view filtering. Duplicate keys, duplicate targets, missing required names/keys +and unknown targets are invalid. Missing inventory or an empty mapping does not +prove absent technical ability or unsupported business capability. + +An entry's effective lifetime is the intersection of its open/explicit bounds +and the application's lifecycle. Explicit bounds outside the owner lifetime or +an end before its start are invalid; a missing bound does not require inventing +an earlier history. + +A dated coverage view includes only explicitly active applications and inventory +entries. It does not recover mapping histories from today's lists. Source +snapshot/scenario intent and missing history must be disclosed as required by +[capability-map §16](https://github.com/transitrix/methodology/blob/888c03d33c2d899ec85a612901075b67811614e5/notations/views/diagrams/05-capability-map.md#16-system-coverage-dated-views-and-presentation-defaults). +Changes to existing direct-list history remain subject to the existing relation +migration contract; this field does not silently create a new temporal REL kind. +The standalone JSON renderer maps each local key to technical entry `id`; source +`valid_from`/`valid_to` require an explicit endpoint conversion to its inclusive +`start_date`/`end_date`. The defined source field is not an `extensions` field. + +The additive schema and whole-model reference checks ship with the methodology +([capability-map §16.4](https://github.com/transitrix/methodology/blob/888c03d33c2d899ec85a612901075b67811614e5/notations/views/diagrams/05-capability-map.md#164-compatibility-and-implementation-status)). +Released CLI/DSM/Studio adoption must still be verified independently. + +--- diff --git a/transitrix/skills/render-dsm-capabilities-html/references/system-coverage.md b/transitrix/skills/render-dsm-capabilities-html/references/system-coverage.md new file mode 100644 index 0000000..c99d326 --- /dev/null +++ b/transitrix/skills/render-dsm-capabilities-html/references/system-coverage.md @@ -0,0 +1,179 @@ +# Multi-system coverage map — adapter 5, renderer 5.1 + +This is a local visualization prototype with independently selectable APPLICATION systems. +Business hierarchy, five management stages, tags and direct APPLICATION support +remain independent. Do not infer that a system fully delivers a business +capability merely because a mapping exists. + +## Explicit input + +```json +{ + "coverage_system_id": "app-data", + "states": [{ + "id": "current", "label": "Current", "kind": "current", + "capabilities": [ + {"id":"business-a", "name":"Reference data management", "layout":"vertical", + "first_level":1, "second_level":0, "third_level":0, "lane":0}, + {"id":"business-b", "name":"Reference data maintenance", "layout":"vertical", + "first_level":1, "second_level":1, "third_level":0, "lane":0} + ], + "applications": [{ + "id": "app-data", "name": "Data Hub", "capabilities": ["business-a"], + "technical_capabilities": [{ + "id": "tech-reference", "name": "Reference data services", + "capabilities": ["business-b"] + }] + }] + }] +} +``` + +The snippet is a minimal valid model. Optional legacy `coverage_system_id` sets +the initially selected system (the master switch remains off); it must resolve +in every state. All APPLICATION systems are available in the selector without +this field. With no legacy pilot, the HTML selection starts empty. Technical entries require unique text IDs within their APPLICATION, +nonempty names and explicit, duplicate-free business-capability references in +the same state. Empty technical/direct mapping lists mean not specified. They +never imply unsupported. Source inputs remain unmodified. + +The polygon's targets are the union of direct application mappings and that +application's explicit technical mappings, intersected with the current visible +business records. A technical-only target need not have a direct APPLICATION +outline or direct Systems label: those still reflect the original direct +mapping only. Metadata distinguishes both sources. No parent/child inheritance, +implicit intersection, coverage percentage or capability sufficiency is inferred. + +## Geometry and controls + +The Coverage polygons master checkbox starts unchecked and is independent of the +System highlight selector. The Coverage systems list has a colored checkbox for +each APPLICATION. Choose zero, one or several systems. Turning the master off +hides all polygons and names while remembering the individual selections. +Selections persist through state, layout, depth, tag, backlog and label changes. +Systems absent from a state are disabled there, with their selections remembered +for return to a state where they exist. Names follow the selected state. + +Direct SVG uses `--coverage --coverage-system app-a --coverage-system app-b`; +the Python API uses `coverage=True, coverage_systems=['app-a','app-b']`. +An explicit empty list shows no polygons; invalid, duplicate or unavailable IDs +fail. The CLI requires `--coverage` when `--coverage-system` is supplied. +For compatibility, `--coverage` without IDs selects the legacy pilot when present, +otherwise all systems in the selected state. With coverage off, no overlays export. + +Build a convex polygon around the visible mapped box corners with a small +margin. Use a translucent system-colored fill/stroke above the business boxes, with +pointer-events disabled so controls and diagram interactions pass through. +Cut out unlinked leaf boxes. For unlinked containers that geometrically contain +mapped targets or intersections, cut out their label headers while retaining +the targets. The hull's connecting empty space does not assert extra mappings. +The explicit target list is authoritative, not all area enclosed by the hull. + +Place the semi-transparent system name inside the hull, preferring free space +that avoids capability labels and excluded regions. If no such space fits, use +a smaller, very light watermark within a mapped region where possible. The +system name shares the coverage mask so it cannot label an unlinked cut-out. Business text remains readable. This +prototype does not draw individual technical-capability nodes or sub-regions. + +Assign colors once from the model-wide sorted union of system IDs; colors do not +change between states or when selections change. Each mask has a unique system +and depth ID, so overlapping overlays cannot accidentally reuse another mask. +Reserve watermark positions across systems where free space allows. Overlapping +fill on a business box means both systems explicitly map that box; polygon +intersection in connecting empty space has no additional semantic meaning. + +Precompute a native SVG polygon/mask/name group per system and depth with visible +mappings. Changes to layout, state, tag filter, backlog or optional labels use +that view's geometry; depth selects the appropriate group. No visible mappings +means no polygon/name, even if the checkbox remains on. Overlay selection never +changes business-box coordinates. Turning it off removes the visual layer. + +SVG export retains only the selected active groups, native masks, watermark and visible +target/source metadata; unselected systems and inactive depth variants are removed. +`view.coverage_system_ids` records the selected IDs, even when a selected system +has no visible mappings. `coverage_system_id` remains populated only for a single +selected system for compatibility. A selected system with no visible mappings +produces no polygon and no name. The HTML contains +all supplied snapshots and variants, as before. This is not security redaction. + +## Scope and methodology boundary + +The merged core methodology defines application-owned technical_capabilities +with a local key, name and explicit business targets. It is part of APPLICATION, +not an extensions entry and not a new globally addressable TYPE or REL kind. +The standalone renderer uses a JSON projection with local id instead of key; +see [the mapping and adoption status](methodology-boundary.md). The specification +correction is merged but not released or proof of native consumer support. +Acme technical abilities are illustrative DEMO data, not source-backed facts. +Do not infer real technical inventory or mappings from names. Individual technical +regions and coverage percentages are not implemented by these polygons. + +## Functional overlap — renderer 6.6 + +The Functional overlap checkbox starts unchecked and is enabled while Coverage +polygons is on and at least two systems are selected. It remembers its checked +choice when temporarily disabled. It outlines the geometric area covered by two +or more visible system polygons, including empty space between business boxes. The formula is +`R = union over i < j of (P_i intersection P_j)`: every point inside at least +two selected outer polygons belongs to R. The red contour is the boundary of R. +It does not outline business-capability rectangles. + +Coverage hulls stay two native SVG units outside mapped box boundaries +(renderer 6.5.2), replacing the earlier twelve-unit decorative expansion. This +keeps neighboring Acme domain polygons separate across their sixteen-unit gap, +so their margins alone do not generate a red intersection strip. Genuine +positive-area intersections still use the same diagnostic below. + +The renderer intersects outer convex hulls pairwise. Box cut-out masks are +ignored by this diagnostic: they protect business labels in the colored overlays +and must not create stair steps or inner red box outlines. The opaque union of +these intersections is outlined in +red by an SVG alpha-edge filter (1.5-unit dilation minus erosion). Applying the +filter once to the union avoids internal seams where three systems intersect. +A shared edge or point with zero area creates no intersection. The native SVG +retains the filter and polygon definitions, with no external runtime dependencies. + +Date, selected systems, layers, tags, backlog and depth rebuild the relevant +geometry. Coverage off or fewer than two systems removes the diagnostic. Diagram +only and zoom preserve it. Legend off hides its key while keeping the contour. + +Direct SVG: `--coverage --coverage-system A --coverage-system B +--functional-overlap` on one command line. The CLI requires --coverage. Python +uses `functional_overlap=True`; effective mode is false without coverage and two +selected systems. No model attributes or canonical relations change. + +Metadata records effective `view.functional_overlap` and +`view.functional_overlap_system_pairs`, the pairs with positive-area hull +intersections. Each `functional-overlap-region` records its +`data-overlap-systems` JSON pair. It does not reference a coverage mask. The single +`functional-overlap-outline` group applies the red union-boundary filter. +The previous renderer 6.4 shared-box diagnostic is replaced, including its +`functional_overlap_capabilities` metadata key. Diagram notes explains the +current geometric semantics. A geometric overlap is a visual investigation aid; +it does not prove redundant functionality or recommend retiring a system. + +## Coverage shape controls — renderer 6.7 + +Polygon shape selects Angled (the original convex hull) or Rectangular (one +axis-aligned bounding rectangle per system/depth). Angled is the default. Round +corners is a separate unchecked checkbox available with either shape. The +rectangular option deliberately uses the overall bounds, not a stepped +orthogonal hull; its extra area does not assert additional capability mappings. + +Rounding cuts convex corners inward with a ten-unit corner distance, limited to +half each adjacent edge. Quadratic corner curves are sampled into eight vector +segments at four-decimal precision. The same resulting native polygon points +are used by its colored overlay, white mask silhouette and red-overlap boolean +calculation. Box cut-outs continue to affect only colored overlays. This makes +red overlap follow the selected rounded form instead of a sharp hidden hull. +The original hull remains in data-coverage-hull so repeated toggling has no drift. + +Settings persist through layout/date/depth/filter changes and are usable when +coverage is off to prepare the next view. Exports contain the selected native +polygon geometry, independent of HTML controls. Metadata records +view.coverage_shape (angled/rectangular) and view.round_coverage (boolean); SVG +root data-coverage-shape and data-coverage-rounded mirror those settings. + +CLI: --coverage-shape angled|rectangular and --round-coverage. Python API: +coverage_shape='rectangular', round_coverage=True. Unknown shape values fail. +No source-model attributes, links or canonical methodology changes are required. diff --git a/transitrix/skills/render-dsm-capabilities-html/references/view-controls.md b/transitrix/skills/render-dsm-capabilities-html/references/view-controls.md new file mode 100644 index 0000000..6bf067c --- /dev/null +++ b/transitrix/skills/render-dsm-capabilities-html/references/view-controls.md @@ -0,0 +1,106 @@ +# Layout, filtering, coverage and presentation + +Enable **Sort by layers** in HTML or use `--sort-layers` for direct SVG. Read +[the input contract](input-contract.md#version-4-management-cycle-layers-and-tags) +for `layer`, `tags` and legacy `property` mapping. The only stages, in order, are +**Strategic, Learning, Planning, Execution, Assurance**. Strategic includes +strategic planning and major direction changes; Planning is tactical/operational; +Learning develops knowledge and competence; Execution performs work; Assurance +checks outcomes, quality and compliance. These are management roles, not process +steps or maturity. Do not infer a stage from a name, parent or orientation. + +**ESG, MDM and Support are tags on boxes and filter criteria, never layers.** +Tags do not create horizontal capabilities or inherit across hierarchy. Keep +actual horizontal capabilities as full-width containers with explicit lane +intersections. An L1 can contain multiple stages. Unclassified records use the +Not specified diagnostic group; unknown legacy properties remain visible under +Unknown property, without becoming a new stage. + +Layers are colored background zones below all other elements. V-L1 frames span +the domain columns with their own headers; cycle grouping aligns their deeper +records. Each H-L1 has its own cycle groups below the vertical-domain area, +so MDM/ESG/Compliance remain separate actual capabilities. Keep every L2 inside +L1 and L3 inside L2, including across stages, using transparent parent frames. +H labels stay in the left gutter; H children retain explicit domain lanes. +Native SVG zones, tag chips, labels and containers survive exact-view export. + +Use the **Tag** selector or `--tag ESG`, `--tag MDM`, `--tag Support` for SVG. +Show direct tag matches plus the parents and V-domain roots needed to keep +hierarchy/intersections understandable. Context-only boxes are muted and tagged +`data-tag-match="context"`; they do not inherit the filter tag. Unrelated branches +are removed and geometry is rebuilt. All tags restores the unfiltered diagram. +The tag filter persists through state/layout/backlog/label changes. It composes +with depth filtering and independent APPLICATION highlighting; export records +the selected tag and removes invisible content. A tag absent from a state shows +an explicit empty result. These are display filters, not security redaction. + +For **state on a date**, read [date timeline](date-timeline.md). +Use explicit nonoverlapping `effective_from`/`effective_to` state periods, past, +current or planned; choose View date, scrub the daily Timeline slider, or use `--date YYYY-MM-DD`. The renderer evaluates +capability/system/technical lifetimes and dated maturity at that date, rebuilds +coverage, and preserves view controls. No data in a gap means an empty map and +no export. Plans remain marked as plans. Never infer history, date a descriptive +horizon or present a snapshot projection as a daily observation. Keep requested +date, snapshot basis and period bounds separate in SVG metadata. Legacy undated +snapshots remain manually selectable. + +For **system coverage polygons**, read [system coverage](system-coverage.md). +Choose one or more APPLICATION systems in the colored Coverage systems list, +then enable Coverage polygons (off by default). Each system keeps its color +across states and layouts; its translucent name appears inside its polygon. +Coverage is the union of explicit direct and technical mappings. It never +inherits, implies unsupported status or measures sufficiency/coverage percentage. +Unlinked capability regions are cut out; connecting empty space is visual only. +The existing System selector controls direct highlighting independently. +For SVG use `--coverage --coverage-system ID` (repeat for multiple systems), or +API `coverage=True, coverage_systems=['id-a','id-b']`. Export keeps selected +systems at the selected depth with visible mapping provenance. The Acme demo +includes overlapping Data Hub, Governance Portal and Warehouse mappings; these +technical additions are illustrative, not source facts or canonical notation. +Choose **Polygon shape**: **Angled** keeps the convex hull (default), while +**Rectangular** uses its axis-aligned bounding rectangle. **Round corners** is +independent and off by default. Coverage masks and red overlap geometry follow +the chosen shape; changing these view options never changes mapping facts. +Direct SVG accepts `--coverage-shape rectangular --round-coverage`. +Enable **Functional overlap** to outline the union of geometric intersections +of two or more selected outer system polygons in red. Box cut-out masks do not +affect this contour: it is the boundary of points inside at least two polygons. +The checkbox is off by default and requires Coverage polygons and two selections. +It follows the polygon perimeter, including space between business boxes; it +never substitutes contours around shared capability boxes. Date, layout, depth +and filters recalculate geometry. Read [system coverage](system-coverage.md#functional-overlap--renderer-66) +for native SVG filters, masks and metadata; geometric overlap alone does not +prove redundant functionality. + +With Maturity and Legend enabled, include six visual box samples (levels 0–5) +with their names and short descriptions. Reuse the actual maturity box classes +so opacity, border strength and the level-0 dashed line match the diagram. +Hide the visual scale when either setting is off; native SVG keeps the samples. + +The **Backlog** checkbox is off by default in HTML. Enable it to show the backlog; disabling it removes the backlog column, vertical 0.Y.Z records and horizontal unplaced children with lane 0. The remaining columns close the gap. This does not remove unclassified properties or placed records named Backlog. The setting persists across state/layout changes and is included in SVG export. For direct SVG use `--no-backlog`. + +The **Legend** checkbox controls a compact, context-sensitive native SVG legend. +Show explanations only for visible enabled modes: stage bands, muted tag context, +direct system labels/highlight, actually visible coverage systems (with their +colors) and displayed maturity. Omit the legend and its space when there is +nothing to explain. Do not print revisions, hashes or adapter disclaimers in the +map footer: keep them in SVG metadata and the live **Diagram notes** details. +Turning Legend off removes the legend from SVG export; provenance remains. + +**Diagram only** hides the HTML control panel while preserving the selected map, +title, date/scenario caption and current legend setting, then automatically fits +the whole canvas into the available map viewport. **Show controls** or Esc +restores the panel and all settings. This is a presentation toggle, independent +of Legend; it does not remove metadata, dates, planned-scenario disclosures or +change coverage/geometry. Print hides control chrome, including the restore +button. The persistent scale toolbar offers a fit-to-screen button, zoom slider, +minus/plus and 100% reset. Fit mode follows viewport, date, layout and legend-size +changes. Manual zoom allows scrolling through larger details. Zoom scales HTML +wrappers only: SVG dimensions, coordinates and metadata stay native. SVG export +always contains the current map rather than HTML controls; print ignores zoom. + +System labels are **off by default** in HTML, the Python API and direct SVG. Enable the HTML checkbox or add `--system-labels` to include actual direct system names. `--no-system-labels` remains a compatible explicit off switch; `--no-legend` hides the full lower text block. Missing mappings have no placeholder line inside a box. Omit --system to show all mappings. HTML controls select state, one application, depth 1–3, system labels, maturity, legend and layer sorting. The visible diagram is SVG; Download SVG serializes **that exact visible view**, with its state, horizon and selections. Use native shapes and text, not screenshots or foreignObject. Export removes hidden-depth nodes, disabled labels/legend and nonvisible mapping metadata, retaining selected-view provenance and the active coverage overlay's explicit visible mapping sources. Interactive HTML contains all supplied snapshots; these display filters are not a security-redaction feature. The SVG embeds its own styles and view metadata; no external fonts/resources or server requests are required. + +In classic mode, render horizontal L1 capabilities as full-width horizontal bands below the vertical domains, with an unrotated address/name stack in a dedicated left gutter and at least 500px of lane content width. The gutter stays outside all vertical-domain lanes. Place intersection boxes beside it instead of below a full-width title header. Keep their L2/L3 cells aligned to the supplied vertical-domain lanes; do not turn H-L1 into a vertical card. In both layouts, keep H-L1 address, name, maturity and system labels in that gutter. Align H-L2/L3 address/name text to the left inside their own rectangles. This horizontal-title treatment is a deliberate adaptation of the classic Report’s rotated side title. + +System highlighting, depth and legend selections preserve the current label-layout geometry; depth still reserves its hidden child space. **System labels and Maturity rebuild geometry** from the visible text only, so enabling them expands boxes and disabling them compacts the layout again. Omit empty system lines, missing maturity labels and unassigned-cell placeholders. Keep only normal padding. Vertical L2 cards use 80% of L1 width and L3 cards 90% of L2 width, centered in their parent; height follows content and descendants, without a portrait minimum or shrinking to a narrow text column; L1 domain frames still span their content. Layer sorting, tag filters and backlog visibility also change geometry. State changes may have different geometry because they are independent snapshots. When system labels are enabled, explicit mappings are shown in their exact capability blocks; selecting an application outlines its directly mapped blocks only. Do not describe unoutlined blocks as unsupported. diff --git a/transitrix/skills/render-dsm-capabilities-html/scripts/package.py b/transitrix/skills/render-dsm-capabilities-html/scripts/package.py new file mode 100644 index 0000000..01c018d --- /dev/null +++ b/transitrix/skills/render-dsm-capabilities-html/scripts/package.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python3 +"""Build a reproducible, source-only portable skill ZIP (Python standard library).""" +import argparse +from pathlib import Path +import zipfile + +ROOT = Path(__file__).resolve().parents[1] + +def build(output): + output = Path(output).resolve() + if output.is_relative_to(ROOT): + raise ValueError('Write the archive outside the source skill folder') + sources = sorted(p for p in ROOT.rglob('*') + if p.is_file() and '__pycache__' not in p.parts + and p.suffix != '.pyc') + with output.open('xb') as stream, zipfile.ZipFile(stream, 'w', compression=zipfile.ZIP_DEFLATED) as archive: + for source in sources: + name = ROOT.name + '/' + source.relative_to(ROOT).as_posix() + info = zipfile.ZipInfo(name, date_time=(1980, 1, 1, 0, 0, 0)) + info.create_system = 3 + info.external_attr = 0o100644 << 16 + info.compress_type = zipfile.ZIP_DEFLATED + archive.writestr(info, source.read_bytes()) + return len(sources) + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('output', type=Path) + args = parser.parse_args() + print(f'Packaged {build(args.output)} files: {args.output}') diff --git a/transitrix/skills/render-dsm-capabilities-html/scripts/render.py b/transitrix/skills/render-dsm-capabilities-html/scripts/render.py new file mode 100644 index 0000000..0f4bee5 --- /dev/null +++ b/transitrix/skills/render-dsm-capabilities-html/scripts/render.py @@ -0,0 +1,965 @@ +#!/usr/bin/env python3 +"""Render a validated, explicit classic DSM Report grid. Python standard library only.""" +import argparse, datetime as dt, html, json, pathlib, sys + +LEVELS = ['No capability', 'Initial', 'Managed', 'Defined', 'Quantitatively Managed', 'Optimizing'] +# Management stages and subject/role tags are independent adapter dimensions. +LAYERS = ('Strategic', 'Learning', 'Planning', 'Execution', 'Assurance') +TAGS = ('ESG', 'MDM', 'Support') +LAYER_COLORS = dict(zip((*LAYERS, 'Not specified', 'Unknown property'), + ('#e6e4f6', '#e1f1ec', '#e1edf9', '#fff0d6', '#e0f2f3', '#e9edf2', '#f4e7dd'))) +def layer_value(r): + if 'layer' in r:return r['layer'] + value=r.get('property') + return None if value in TAGS else value + +def layer(r): + value=layer_value(r) + if value in (None, ''):return 'Not specified' + return value if value in LAYERS else 'Unknown property' + +def tags(r): + values=list(r.get('tags',[])) + if r.get('property') in TAGS and r['property'] not in values:values.append(r['property']) + return [t for t in TAGS if t in values] + +def esc(x): return html.escape(str(x), quote=True) +def date(x): + if x in (None, ''): return None + return x if isinstance(x,dt.date) else dt.date.fromisoformat(x) +def assessment_name(m): + if 'maturity_level_dict' in m: + obj=m['maturity_level_dict'] + if not isinstance(obj,dict) or not isinstance(obj.get('name'),str) or not obj['name'].strip(): + raise ValueError('maturity_level_dict.name must be nonempty text') + name=obj['name'] + if 'level' in m: + level=m['level'] + if type(level) is not int or not 0<=level<=5: raise ValueError('Maturity level must be an integer 0..5') + if name != LEVELS[level]: raise ValueError('Maturity name and level disagree') + return name + level=m.get('level') + if type(level) is not int or not 0<=level<=5: raise ValueError('Maturity level must be an integer 0..5') + return LEVELS[level] + +def prepare(data, as_of): + if not isinstance(data, dict) or not isinstance(data.get('capabilities'), list): + raise ValueError('Expected an object with capabilities array') + records = data['capabilities']; ids=set(); keys=set(); index={}; warnings=[] + if not records: raise ValueError('Capability array is empty') + for field in ('title','organisation'): + if field in data and not isinstance(data[field],str): raise ValueError(f'{field} must be text') + sets={str(r.get('universal_item_set_id')) for r in records if isinstance(r,dict)} + if len(sets)>1: raise ValueError('Select exactly one capability set before rendering') + for r in records: + if not isinstance(r, dict): raise ValueError('Capability must be an object') + for f in ('id','name','layout','first_level','second_level','third_level','lane'): + if f not in r: raise ValueError(f'Missing {f}: {r.get("id", "unknown")}') + if not isinstance(r['id'], (str,int)) or isinstance(r['id'],bool): raise ValueError('ID must be string or integer') + if not isinstance(r['name'],str) or not r['name'].strip(): raise ValueError('Name must be nonempty text') + if r.get('property') is not None and not isinstance(r['property'],str): + raise ValueError('Capability property must be text or null') + if 'layer' in r and r['layer'] not in (None, '', *LAYERS): + raise ValueError('Capability layer must be a recognized management stage or null') + values=r.get('tags',[]) + if not isinstance(values,list) or any(not isinstance(t,str) or t not in TAGS for t in values): + raise ValueError('Capability tags must be an array of ESG, MDM or Support') + if len(set(values))!=len(values):raise ValueError('Duplicate capability tag') + ident=str(r['id']) + if ident in ids: raise ValueError(f'Duplicate ID {ident}') + ids.add(ident) + if r['layout'] not in ('vertical','horizontal'): raise ValueError(f'Unknown layout for {ident}') + for f in ('first_level','second_level','third_level','lane'): + if type(r[f]) is not int or r[f] < 0: raise ValueError(f'{ident}: {f} must be a nonnegative integer') + a,b,c=r['first_level'],r['second_level'],r['third_level'] + if c and not b: raise ValueError(f'{ident}: L3 requires L2 coordinate') + if r['layout']=='horizontal' and a==0: raise ValueError('Horizontal first_level=0 is ambiguous; use H root and lane=0 for unplaced children') + key=(r['layout'],a,b,c) + if key in keys: raise ValueError(f'Duplicate coordinate {key}') + keys.add(key); index[key]=r + start,end=date(r.get('start_date')),date(r.get('end_date')) + if start and end and start>end: raise ValueError(f'{ident}: reversed lifetime') + if not isinstance(r.get('maturity',[]),list): raise ValueError(f'{ident}: maturity must be a list') + for m in r.get('maturity',[]): + if not isinstance(m,dict) or not date(m.get('change_date')): raise ValueError(f'{ident}: maturity needs change_date') + assessment_name(m) + for r in records: + a,b,c=r['first_level'],r['second_level'],r['third_level']; orient=r['layout'] + parent=index.get((orient,a,b,0) if c else (orient,a,0,0)) if b else None + if b and parent is None: raise ValueError(f'{r["id"]}: missing same-orientation parent') + if c and r['lane'] != parent['lane']: raise ValueError(f'{r["id"]}: lane differs from parent') + if orient=='horizontal' and b and r['lane'] and ('vertical',r['lane'],0,0) not in index: + raise ValueError(f'{r["id"]}: lane has no vertical root') + def active(r): + start,end=date(r.get('start_date')),date(r.get('end_date')) + return as_of is None or ((start is None or start<=as_of) and (end is None or as_of<=end)) + selected=[r for r in records if active(r)] + for r in selected: + a,b,c=r['first_level'],r['second_level'],r['third_level']; orient=r['layout'] + if b: + p=index[(orient,a,b,0) if c else (orient,a,0,0)] + if not active(p): raise ValueError(f'{r["id"]}: active child has inactive parent at as-of date') + if orient=='horizontal' and b and r['lane'] and not active(index[('vertical',r['lane'],0,0)]): + raise ValueError(f'{r["id"]}: active intersection targets inactive vertical root') + return sorted(selected,key=lambda r:(r['first_level'],r['second_level'],r['third_level'])), warnings + +def maturity(r, as_of): + if as_of is None: + if r.get('maturity'): raise ValueError(f'{r["id"]}: dated maturity needs an explicit as_of date, not a horizon label') + return '', 'Not assessed' + eligible=[m for m in r.get('maturity',[]) if date(m['change_date'])<=as_of] + if not eligible: return '', 'Not assessed' + latest=max(date(m['change_date']) for m in eligible) + names={assessment_name(m) for m in eligible if date(m['change_date'])==latest} + if len(names)!=1: raise ValueError(f'{r["id"]}: conflicting maturity on {latest}') + name=names.pop() + return (f'm{LEVELS.index(name)}' if name in LEVELS else 'unknown'), name if name in LEVELS else f'Unknown assessment: {name}' + +METHODOLOGY_REVISION='888c03d33c2d899ec85a612901075b67811614e5' +METHODOLOGY_BASELINE='3c75d0403dd4e2dc618bc9535ea293d0495e1ec1' +METHODOLOGY_CONTRACT_STATUS='merged core-methodology correction; not released' +ADAPTER_VERSION='dsm-capability-html/6' +RENDERER_VERSION='6.8.2' +SVGNS='http://www.w3.org/2000/svg' + +def normalize(data, current_date=None): + """Explicit snapshots; never infer a target from current relationships or dates.""" + if not isinstance(data,dict): raise ValueError('Model must be an object') + raw=data.get('states') + if raw is None: + raw=[{'id':'current','label':'Current state','kind':'current','capabilities':data.get('capabilities'), + 'applications':data.get('applications',[]),'as_of':current_date.isoformat() if current_date else data.get('as_of')}] + if not isinstance(raw,list) or not raw:raise ValueError('states must be a nonempty array') + states=[];seen=set() + for source in raw: + if not isinstance(source,dict):raise ValueError('State must be an object') + state=dict(source) + for field in ('id','label','kind'): + if not isinstance(state.get(field),str) or not state[field].strip():raise ValueError(f'State {field} must be nonempty text') + if state['id'] in seen:raise ValueError('Duplicate state ID') + seen.add(state['id']) + if state['kind'] not in ('historical','current','target'):raise ValueError('State kind must be historical, current or target') + start,end=date(state.get('effective_from')),date(state.get('effective_to')) + if ('effective_from' in state or 'effective_to' in state) and start is None:raise ValueError('Dated state requires effective_from') + if start and end and start>=end:raise ValueError('State effective_to must be after effective_from (exclusive)') + horizon=state.get('horizon_label','') + if not isinstance(horizon,str):raise ValueError('horizon_label is descriptive text, not an inferred date') + as_of=date(state.get('as_of')) + if as_of is None and state['kind']=='current':as_of=current_date + snapshot_as_of=as_of + if as_of is None and start:as_of=start + records,_=prepare({'capabilities':state.get('capabilities')},as_of) + for r in records:maturity(r,as_of) + allids={str(r['id']) for r in state['capabilities']} + apps=state.get('applications',[]) + if not isinstance(apps,list):raise ValueError('applications must be an array') + appids=set() + for app in apps: + if not isinstance(app,dict) or not isinstance(app.get('id'),(str,int)) or isinstance(app.get('id'),bool):raise ValueError('APPLICATION needs an ID') + validate_lifetime(app,'APPLICATION') + aid=str(app['id']) + if aid in appids:raise ValueError('Duplicate APPLICATION ID within state') + appids.add(aid) + if not isinstance(app.get('name'),str) or not app['name'].strip():raise ValueError('APPLICATION needs a name') + if app.get('type','APPLICATION')!='APPLICATION':raise ValueError('Only APPLICATION mappings are supported; no technical-capability layer') + if 'capabilities' in app: + links=app['capabilities'] + if not isinstance(links,list) or any(not isinstance(x,(str,int)) or isinstance(x,bool) for x in links):raise ValueError('APPLICATION capabilities must be an array of explicit capability IDs') + if len({str(x) for x in links})!=len(links):raise ValueError('Duplicate APPLICATION capability link') + unknown={str(x) for x in links}-allids + if unknown:raise ValueError(f'APPLICATION {aid} references unknown capabilities: {sorted(unknown)}') + technical=app.get('technical_capabilities',[]) + if not isinstance(technical,list):raise ValueError('technical_capabilities must be an array') + tids=set() + for ability in technical: + if not isinstance(ability,dict) or not isinstance(ability.get('id'),str) or not ability['id'].strip() or not isinstance(ability.get('name'),str) or not ability['name'].strip(): + raise ValueError('Technical capability needs nonempty text id and name') + validate_lifetime(ability,'Technical capability') + if ability['id'] in tids:raise ValueError('Duplicate technical capability ID within APPLICATION') + tids.add(ability['id']);links=ability.get('capabilities') + if not isinstance(links,list) or any(not isinstance(x,(str,int)) or isinstance(x,bool) for x in links): + raise ValueError('Technical capability needs explicit capabilities array') + if len({str(x) for x in links})!=len(links):raise ValueError('Duplicate technical capability link') + if {str(x) for x in links}-allids:raise ValueError('Technical capability references unknown business capability') + for field in ('unsupported_capabilities','coverage_percent'): + + if field in app:raise ValueError(f'{field} is outside this adapter; do not infer unsupported status or percentages') + pilot=data.get('coverage_system_id','') + if not isinstance(pilot,str):raise ValueError('coverage_system_id must be text') + if pilot and pilot not in appids:raise ValueError('coverage_system_id must reference an APPLICATION in every state') + state.update(records=records,all_applications=apps,applications=active_applications(apps,as_of),as_of=as_of,snapshot_as_of=snapshot_as_of,effective_from=start,effective_to=end,horizon_label=horizon) + states.append(state) + periods=sorted((state for state in states if state['effective_from']),key=lambda s:s['effective_from']) + for left,right in zip(periods,periods[1:]): + if left['effective_to'] is None or left['effective_to']>right['effective_from']:raise ValueError('State date periods overlap; choose one explicit timeline') + if data.get('view_date') is not None and date(data['view_date']) is None:raise ValueError('view_date must be a date') + if data.get('view_date') and not periods:raise ValueError('view_date requires dated state periods') + for field in ('title','organisation','model_revision'): + if field in data and not isinstance(data[field],str):raise ValueError(f'{field} must be text') + return {'title':data.get('title','Business capability map'),'organisation':data.get('organisation',''), + 'model_revision':data.get('model_revision','Not specified'),'coverage_system_id':data.get('coverage_system_id',''),'view_date':date(data.get('view_date')),'states':states} + +def validate_lifetime(item,label): + start,end=date(item.get('start_date')),date(item.get('end_date')) + if start and end and start>end:raise ValueError(f'{label}: reversed lifetime') + +def active_on(item,when): + start,end=date(item.get('start_date')),date(item.get('end_date')) + return when is None or ((start is None or start<=when) and (end is None or when<=end)) + +def active_applications(apps,when): + return [dict(app,technical_capabilities=[dict(t) for t in app.get('technical_capabilities',[]) if active_on(t,when)]) for app in apps if active_on(app,when)] + +def state_on(model,when,state_id=None): + when=date(when) + if when is None:raise ValueError('View date must be explicit') + matches=[s for s in model['states'] if s['effective_from'] and s['effective_from']<=when and (s['effective_to'] is None or when=start and (end is None or event=start and (end is None or event=start and (end is None or event=2 and cross(lower[-2],lower[-1],point)<=0:lower.pop() + lower.append(point) + for point in reversed(points): + while len(upper)>=2 and cross(upper[-2],upper[-1],point)<=0:upper.pop() + upper.append(point) + return lower[:-1]+upper[:-1] + + +COVERAGE_PADDING=2 # Native SVG units: keep neighboring domain overlays separated. + +COVERAGE_COLORS=('#0d9488','#d97706','#7c3aed','#db2777','#2563eb','#65a30d','#dc2626','#475569') + +def coverage_colors(model): + ids=sorted({str(a['id']) for state in model['states'] for a in state.get('all_applications',state['applications'])}) + return {aid:(COVERAGE_COLORS[i] if i=c['rect'][0]+c['rect'][2] and y+h>=c['rect'][1]+c['rect'][3] for c in covered.values()) + if contains: + if b['horizontal_root']:w=min(w,212) + h=min(h,b['header']) + cutouts.append((ident,(x-2,y-2,w+4,h+4))) + mask=f'coverage-mask-{str(app["id"]).encode().hex()}-{depth}' + ids=sorted(covered) + active_technical=[t['id'] for t in technical if covered.keys() & {str(i) for i in t['capabilities']}] + sources={'direct_application':[i for i in ids if i in direct], + 'technical_capabilities':{t['id']:[i for i in ids if i in {str(v) for v in t['capabilities']}] for t in technical if t['id'] in active_technical}} + result.append(f'') + if occupied_by_depth is not None:occupied.append((x-len(app['name'])*size*.31,y-size-4,len(app['name'])*size*.62,size+8)) + return ''.join(result) + + +def build_svg(model,state,sort_layers=False,show_backlog=True,labels=False,show_maturity=False,tag_filter=''): + import math,textwrap,xml.etree.ElementTree as ET + rows=state['records'];as_of=state['as_of'];apps=state['applications'] + if not show_backlog: + rows=[r for r in rows if not (r['layout']=='vertical' and r['first_level']==0) + and not (r['layout']=='horizontal' and r['second_level']>0 and r['lane']==0)] + if tag_filter and tag_filter not in TAGS:raise ValueError('Unknown tag filter') + matches={str(r['id']) for r in rows if tag_filter in tags(r)} if tag_filter else {str(r['id']) for r in rows} + if tag_filter: + index={(r['layout'],r['first_level'],r['second_level'],r['third_level']):r for r in rows} + keep=set(matches) + for r in rows: + if str(r['id']) not in matches:continue + a,b,c=r['first_level'],r['second_level'],r['third_level'];o=r['layout'] + if b:keep.add(str(index[(o,a,0,0)]['id'])) + if c:keep.add(str(index[(o,a,b,0)]['id'])) + if o=='horizontal' and b and r['lane']: + keep.add(str(index[('vertical',r['lane'],0,0)]['id'])) + rows=[r for r in rows if str(r['id']) in keep] + def wrap(value,width,size=12): + return textwrap.wrap(str(value),width=max(4,int(width/(size*.62))),break_long_words=True,break_on_hyphens=False) or [''] + def support(r):return [a for a in apps if str(r['id']) in {str(x) for x in a.get('capabilities',[])}] + def kids(r): + if r['third_level']:return [] + a,b=r['first_level'],r['second_level'];o=r['layout'] + return [v for v in rows if v['layout']==o and v['first_level']==a and ((v['second_level']==b and v['third_level']>0 and v['lane']==r['lane']) if b else (v['second_level']>0 and v['third_level']==0))] + def parts(r,w,column=False): + address=f'{r["layout"][0]}.{r["first_level"]}.{r["second_level"]}.{r["third_level"]}/{r["lane"]}' + result=[('',10,'#52616b',wrap(address,w-24,10)), + ('',12,'#1e1e1e',wrap(r['name'],w-24))] + if tags(r):result.append(('tag-label',10,'#334155',wrap(' · '.join(tags(r)),w-34,10))) + assessment,name=maturity(r,as_of) + if show_maturity and assessment: + result.append(('maturity-label',10,'#1e1e1e',wrap(name,w-24,10))) + systems=support(r) + if labels and systems: + result.append(('system-label',10,'#00626b',wrap('Systems: '+', '.join(a['name'] for a in systems),w-24,10))) + if column and layer_value(r): + result.append(('property-label',10,'#475569',wrap('Layer: '+layer_value(r),w-24,10))) + return result + def header_height(r,w,column=False): + blocks=parts(r,w,column) + # Last baseline + descender, not a reserved next text line. + return 17+sum((size+3)*len(lines)+4 for _,size,_,lines in blocks)-blocks[-1][1]-4 + sizes={} + def box_size(r,w,depth,nested=True): + key=(str(r['id']),round(w,4),depth,nested) + if key in sizes:return sizes[key] + actual=w + cw=actual*(.8 if depth==1 else .9) + children=sum(box_height(c,cw,depth+1)+10 for c in kids(r)) if depth<3 and nested else 0 + content=header_height(r,actual)+(12+children if children else 0)+8 + # Vertical orientation is expressed by the domain/stack, not by + # squeezing descendant cards into portrait aspect ratios. + height=max(54,content,actual*1.25 if r['layout']=='vertical' and depth==1 else 0) + sizes[key]=(actual,height) + return sizes[key] + def box_height(r,w,depth,nested=True):return box_size(r,w,depth,nested)[1] + out=[];zones=[];boxes={};occupied=[] + def text(x,y,lines,size=12,color='#1e1e1e',anchor='middle',cls=''): + for i,line in enumerate(lines): + tw=len(line)*size*.62 + tx=x-tw/2 if anchor=='middle' else x + occupied.append((tx-2,y+i*(size+3)-size-2,tw+4,size+6)) + out.append(f'') + for i,line in enumerate(lines):out.append(f'{esc(line)}') + out.append('') + def meta(r,depth,cls=''): + address=f'{r["layout"][0]}.{r["first_level"]}.{r["second_level"]}.{r["third_level"]}/{r["lane"]}' + ids=json.dumps([str(a['id']) for a in support(r)],ensure_ascii=True) + tag_match='match' if str(r['id']) in matches else 'context' + return f'{esc(r["name"])} — layer: {esc(layer_value(r) or "Not specified")}; tags: {esc(", ".join(tags(r)) or "none")}{esc(address)}; maturity: {esc(maturity(r,as_of)[1])}; direct APPLICATION mappings: {esc(", ".join(a["name"] for a in support(r)) or "not specified")}. No inheritance or unsupported inference.' + def rectangles(r,x,y,w,h,depth,column=False): + boxes[str(r['id'])]={'rect':(round(x,1),round(y,1),round(w,1),round(h,1)),'depth':depth, + 'header':header_height(r,left-52 if r['layout']=='horizontal' and depth==1 else w,column)+12, + 'horizontal_root':r['layout']=='horizontal' and depth==1} + fill='none' if column else '#c9d5f2' if depth==2 else 'white';stroke='#94a3b8' if column else '#e2e8f0' if depth==1 else fill + cls=maturity(r,as_of)[0] + return f'' + def draw_labels(r,x,y,w,anchor='middle',column=False,horizontal_title=False): + cursor=y+17 + for index,(cls,size,color,lines) in enumerate(parts(r,w,column)): + if index==1 and horizontal_title:cls='horizontal-title' + if cls=='tag-label': + for i,line in enumerate(lines): + tw=min(w-24,len(line)*size*.62+10) + tx=x-tw/2 if anchor=='middle' else x-4 + out.append(f'') + text(x,cursor,lines,size,color,anchor,cls) + cursor+=(size+3)*len(lines)+4 + return y+header_height(r,w,column)+12 + def draw_box(r,x,y,w,depth,forced_height=None,nested=True,column=False): + actual,h=box_size(r,w,depth,nested) + x+=(w-actual)/2;w=actual;h=forced_height or h + out.append(meta(r,depth,'domain-column' if column else '')+rectangles(r,x,y,w,h,depth,column)) + tx=x+12 if r['layout']=='horizontal' else x+w/2 + anchor='start' if r['layout']=='horizontal' else 'middle' + cursor=draw_labels(r,tx,y,w,anchor,column) + if depth<3 and nested: + cw=w*(.8 if depth==1 else .9) + for child in kids(r): + ch=box_height(child,cw,depth+1);draw_box(child,x+(w-cw)/2,cursor,cw,depth+1);cursor+=ch+10 + out.append('') + def draw_horizontal_root(r,y,h,open_group=False): + out.append(meta(r,1,'horizontal-band')+rectangles(r,20,y,width-40,h,1)) + draw_labels(r,32,y,left-52,'start',horizontal_title=True) + if not open_group:out.append('') + verts=[r for r in rows if r['layout']=='vertical' and r['first_level']>0 and r['second_level']==0] + horiz=[r for r in rows if r['layout']=='horizontal' and r['second_level']==0] + backlog=next((r for r in rows if r['layout']=='vertical' and r['first_level']==0 and r['second_level']==0),None) + columns=([backlog] if backlog or any(r['layout']=='horizontal' and r['second_level']>0 and r['lane']==0 for r in rows) else [])+verts + if not columns:columns=[None] + lanes=[r['first_level'] if r else 0 for r in columns] + # Keep a horizontal band readable even with only one supplied domain. + colw=max(280,500/len(columns)) if horiz else 280 + gap=16;left=240 if horiz else 160 if sort_layers else 84 + def depth_of(r): return 3 if r['third_level'] else 2 if r['second_level'] else 1 + def layered_plan(top): + # Labels belong to their explicit property zones. Parent frames enclose + # descendants even when those descendants have a different property. + slots={};bands=[];cursor=top + index={(r['layout'],r['first_level'],r['second_level'],r['third_level']):r for r in rows} + def parent(r): + if not r['second_level']:return None + return index[(r['layout'],r['first_level'],r['second_level'] if r['third_level'] else 0,0)] + def place(r,center,cy,offered,category): + d=depth_of(r);actual,h=box_size(r,offered,d,False) + slots[str(r['id'])]=(center-actual/2,cy,actual,h) + local=[c for c in kids(r) if layer(c)==category] + child_y=cy+header_height(r,actual)+12 + for child in local: + child_y=place(child,center,child_y,actual*.9,category)+10 + return max(cy+h,child_y+8 if local else cy+h) + def group_stages(records,cursor,scope): + for category in (*LAYERS,'Not specified','Unknown property'): + members=[r for r in records if layer(r)==category] + if not members:continue + zone_top=cursor-8;heading=cursor+18;cursor+=34 + starts=[r for r in members if not parent(r)['second_level'] or layer(parent(r))!=category] + heights=[] + for i,lane in enumerate(lanes): + cell=[r for r in starts if (r['layout']=='vertical' and r['first_level']==lane) or + (r['layout']=='horizontal' and r['lane']==lane)] + cy=cursor + for r in cell: + cw=colw*.8*(.9 if depth_of(r)==3 else 1) + cy=place(r,left+i*(colw+gap)+colw/2,cy,cw,category)+gap + heights.append(cy) + cursor=max(heights) + bands.append((category,zone_top,heading,cursor,scope));cursor+=gap + return cursor + cursor=group_stages([r for r in rows if r['layout']=='vertical' and r['second_level']],cursor,'vertical-domains') + # Each cross-cutting L1 owns its own cycle groups. It never becomes a + # subject-area layer or spans other unrelated horizontal capabilities. + for root in horiz: + start=cursor;ident=str(root['id']) + header=max(54,header_height(root,left-52,True)+12) + cursor+=header+gap + cursor=group_stages([r for r in rows if r['layout']=='horizontal' and r['first_level']==root['first_level'] and r['second_level']],cursor,ident) + slots[ident]=(20,start,width-40,cursor-start+8);cursor+=gap + bounds={} + def enclose(r): + ident=str(r['id']);x,top,w,h=slots[ident] + descendants=[enclose(c) for c in kids(r)] + if descendants: + bottom=max(top+h,max(cy+ch+12 for cx,cy,cw,ch in descendants)) + top=min(top,min(cy-12 for cx,cy,cw,ch in descendants)) + h=bottom-top + bounds[ident]=(x,top,w,h) + return bounds[ident] + for r in rows: + if r['layout']=='horizontal' and not r['second_level'] or r['layout']=='vertical' and r['second_level'] and not r['third_level']: + enclose(r) + return slots,bounds,bands,cursor + # Preflight the actual enclosing geometry, including parents that span + # property zones. Widen lanes when needed to preserve H landscape shapes. + for attempt in range(32): + width=left+len(columns)*(colw+gap)+20 + ratios=[1.0] + if sort_layers: + _,planned,_,_=layered_plan(0) + for r in rows: + if r['layout']!='horizontal':continue + depth=3 if r['third_level'] else 2 if r['second_level'] else 1 + if sort_layers: + _,_,w,h=planned[str(r['id'])] + elif depth==1: + w=width-40;cw=colw*.8 + h=max([54,header_height(r,left-52)+8]+[sum(box_height(c,cw,2)+10 for c in kids(r) if c['lane']==lane)+32 for lane in lanes]) + else: + w=colw*.8*(.9 if depth==3 else 1) + h=box_height(r,w,depth) + ratios.append(1.6*h/w) + factor=max(ratios) + if factor<=1.000001:break + # Ten-unit widths keep nested 80%/90% cells exactly centred at the + # SVG's one-decimal coordinate precision. + colw=10*math.ceil(colw*factor*1.01/10) + else: + raise ValueError('Horizontal content could not fit readable landscape boxes') + text(24,36,wrap(model['title'],width-60,24),24,anchor='start');y=36+27*len(wrap(model['title'],width-60,24)) + caption_date=state.get('snapshot_as_of') if state.get('view_date') else as_of + statecaption=state['label']+(' · '+state['horizon_label'] if state['horizon_label'] else '')+(' · As of '+caption_date.isoformat() if caption_date else ' · No exact snapshot date') + for caption in [model['organisation'],statecaption,('Target scenario, not a current fact' if state['kind']=='target' else 'Historical snapshot' if state['kind']=='historical' else 'Current-state snapshot')]: + if caption: + lines=wrap(caption,width-48,12);text(24,y,lines,12,anchor='start');y+=15*len(lines)+4 + if state.get('view_date'): + lines=wrap(date_caption(state),width-48,12);text(24,y,lines,12,'#475569','start','date-context');y+=15*len(lines)+4 + # Stable header slot; view controls change text but never map geometry. + text(24,y,['View selection'],11,'#475569','start','view-selection') + longest=sum(len(a['name'])+2 for a in apps)+max([len(a['name']) for a in apps]+[3])+240 + y+=max(80,14*(longest//max(20,int((width-48)/7))+6)) + if not rows: + text(24,y+24,[f'No capabilities match tag {tag_filter}.'],14,anchor='start');y+=60 + elif sort_layers: + # V-L1 is the domain column itself, spanning every property band. + # Reserve its header before laying out descendants in their own layers. + column_slot=len(out);column_top=y + column_header_height=max([64]+[header_height(r,colw,True)+8 for r in columns if r]) + y+=column_header_height+gap + slots,bounds,bands,y=layered_plan(y) + for category,zone_top,heading,zone_bottom,scope in bands: + text(32,heading,[category],16,'#004d67','start','layer-heading') + zones.append(f'') + def draw_layered(r): + ident=str(r['id']);d=depth_of(r);x,top,w,h=bounds[ident] + children=kids(r);cls='horizontal-band' if d==1 else 'hierarchy-container' if children else '' + out.append(meta(r,d,cls)+rectangles(r,x,top,w,h,d,column=bool(children))) + sx,sy,sw,sh=slots[ident] + if d==1: + draw_labels(r,32,sy,left-52,'start',column=True,horizontal_title=True) + else: + draw_labels(r,sx+12 if r['layout']=='horizontal' else sx+sw/2,sy,sw, + 'start' if r['layout']=='horizontal' else 'middle') + for child in children:draw_layered(child) + out.append('') + for r in rows: + if r['layout']=='horizontal' and not r['second_level'] or r['layout']=='vertical' and r['second_level'] and not r['third_level']: + draw_layered(r) + column_bottom=max(y-gap,column_top+350,column_top+colw*1.25) + # Paint L1 column frames after zones but before all layer foregrounds. + start=len(out) + for i,r in enumerate(columns): + x=left+i*(colw+gap) + if r: + draw_box(r,x,column_top,colw,1,column_bottom-column_top,nested=False,column=True) + else: + out.append(f'') + text(x+colw/2,column_top+24,wrap('Unplaced / backlog' if show_backlog else 'No placed domains',colw-20)) + column_markup=out[start:];del out[start:] + out[column_slot:column_slot]=column_markup + y=column_bottom+gap + else: + topheight=max([350]+[box_height(r,colw,1) for r in columns if r]) + for i,r in enumerate(columns): + x=left+i*(colw+gap) + if r:draw_box(r,x,y,colw,1,topheight) + else:out.append(f'');text(x+colw/2,y+24,['Unplaced / backlog' if show_backlog else 'No placed domains']) if not r else None + y+=topheight+gap + for root in horiz: + cells=[[r for r in kids(root) if r['lane']==lane] for lane in lanes];cw=colw*.8 + # Labels occupy the gutter beside, rather than above, lane cells. + rowheight=max([54,header_height(root,left-52)+8]+[sum(box_height(r,cw,2)+10 for r in cell)+32 for cell in cells]) + draw_horizontal_root(root,y,rowheight,open_group=True) + for i,cell in enumerate(cells): + x=left+i*(colw+gap)+(colw-cw)/2;cy=y+16 + for r in cell:draw_box(r,x,cy,cw,2);cy+=box_height(r,cw,2)+10 + out.append('');y+=rowheight+gap + out.append('