katalyst-forge 4.2.0__tar.gz → 5.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. katalyst_forge-5.1.0/.gitignore +23 -0
  2. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/CHANGELOG.md +39 -0
  3. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/PKG-INFO +1 -1
  4. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/pyproject.toml +1 -1
  5. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/src/katalyst_forge/__init__.py +1 -1
  6. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/src/katalyst_forge/bundle.py +11 -7
  7. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/src/katalyst_forge/relationships.py +67 -3
  8. katalyst_forge-5.1.0/src/katalyst_forge/wings/_practice_refs.py +58 -0
  9. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/src/katalyst_forge/wings/design.py +5 -115
  10. katalyst_forge-5.1.0/src/katalyst_forge/wings/metrics.py +197 -0
  11. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/src/katalyst_forge/wings/org.py +11 -5
  12. katalyst_forge-5.1.0/src/katalyst_forge/wings/practices.py +565 -0
  13. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/src/katalyst_forge/wings/system.py +13 -2
  14. katalyst_forge-5.1.0/templates/CHANGELOG.md +524 -0
  15. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/tests/test_entry_point_discovery.py +2 -2
  16. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/tests/test_forge.py +7 -7
  17. katalyst_forge-5.1.0/tests/test_practice_assignment.py +107 -0
  18. katalyst_forge-5.1.0/tests/test_storage_contract.py +66 -0
  19. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/tests/test_wings.py +22 -2
  20. katalyst_forge-4.2.0/.gitignore +0 -8
  21. katalyst_forge-4.2.0/src/katalyst_forge/wings/practices.py +0 -216
  22. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/LICENSE +0 -0
  23. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/schemas/CHANGELOG.md +0 -0
  24. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/schemas/README.md +0 -0
  25. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/schemas/agents/agent.schema.json +0 -0
  26. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/schemas/agents/config.schema.json +0 -0
  27. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/schemas/agents/manifest.json +0 -0
  28. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/schemas/agents/skill.schema.json +0 -0
  29. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/schemas/environment.schema.json +0 -0
  30. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/schemas/hooks/hook-config.schema.json +0 -0
  31. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/schemas/katalyst-lock.schema.json +0 -0
  32. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/schemas/nodes/common.schema.json +0 -0
  33. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/schemas/nodes/design.schema.json +0 -0
  34. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/schemas/nodes/organizational.schema.json +0 -0
  35. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/schemas/nodes/portfolio.schema.json +0 -0
  36. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/schemas/nodes/technical.schema.json +0 -0
  37. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/schemas/taxonomy-node.schema.json +0 -0
  38. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/src/katalyst_forge/py.typed +0 -0
  39. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/src/katalyst_forge/templates/creation/_base.yaml.j2 +0 -0
  40. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/src/katalyst_forge/templates/creation/layer.yaml.j2 +0 -0
  41. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/src/katalyst_forge/templates/creation/project.yaml.j2 +0 -0
  42. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/src/katalyst_forge/templates/creation/stack.yaml.j2 +0 -0
  43. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/src/katalyst_forge/templates/creation/system.yaml.j2 +0 -0
  44. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/src/katalyst_forge/templates/creation/team.yaml.j2 +0 -0
  45. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/src/katalyst_forge/templates/creation/team_member.yaml.j2 +0 -0
  46. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/src/katalyst_forge/templates/scaffolds/app-docker/.dockerignore +0 -0
  47. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/src/katalyst_forge/templates/scaffolds/app-docker/.env.example +0 -0
  48. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/src/katalyst_forge/templates/scaffolds/app-docker/README.md +0 -0
  49. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/src/katalyst_forge/templates/scaffolds/app-docker/base/Dockerfile +0 -0
  50. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/src/katalyst_forge/templates/scaffolds/app-docker/docker-compose.yaml +0 -0
  51. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/src/katalyst_forge/templates/scaffolds/app-docker/env-template/Dockerfile +0 -0
  52. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/src/katalyst_forge/templates/scaffolds/app-docker/env-template/docker-compose.override.yaml +0 -0
  53. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/src/katalyst_forge/templates/scaffolds/app-docker/env-template/environment.yaml +0 -0
  54. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/src/katalyst_forge/templates/scaffolds/app-docker/layer.yaml +0 -0
  55. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/src/katalyst_forge/templates/scaffolds/iac-terragrunt/README.md +0 -0
  56. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/src/katalyst_forge/templates/scaffolds/iac-terragrunt/composite/terraform/main.tf +0 -0
  57. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/src/katalyst_forge/templates/scaffolds/iac-terragrunt/composite/terraform/outputs.tf +0 -0
  58. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/src/katalyst_forge/templates/scaffolds/iac-terragrunt/composite/terraform/variables.tf +0 -0
  59. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/src/katalyst_forge/templates/scaffolds/iac-terragrunt/env-template/environment.yaml +0 -0
  60. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/src/katalyst_forge/templates/scaffolds/iac-terragrunt/env-template/terragrunt.hcl +0 -0
  61. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/src/katalyst_forge/templates/scaffolds/iac-terragrunt/global/iac/context.hcl +0 -0
  62. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/src/katalyst_forge/templates/scaffolds/iac-terragrunt/global/iac/dev.yaml +0 -0
  63. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/src/katalyst_forge/templates/scaffolds/iac-terragrunt/global/iac/prod.yaml +0 -0
  64. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/src/katalyst_forge/templates/scaffolds/iac-terragrunt/global/iac/staging.yaml +0 -0
  65. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/src/katalyst_forge/templates/scaffolds/iac-terragrunt/layer.yaml +0 -0
  66. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/src/katalyst_forge/templates/scaffolds/iac-terragrunt/version.yaml +0 -0
  67. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/src/katalyst_forge/templates/scaffolds/k8s-argocd/README.md +0 -0
  68. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/src/katalyst_forge/templates/scaffolds/k8s-argocd/base/app/argocd-application.yaml +0 -0
  69. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/src/katalyst_forge/templates/scaffolds/k8s-argocd/base/kustomization.yaml +0 -0
  70. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/src/katalyst_forge/templates/scaffolds/k8s-argocd/base/namespace.yaml +0 -0
  71. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/src/katalyst_forge/templates/scaffolds/k8s-argocd/environment-template/argocd-application.yaml +0 -0
  72. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/src/katalyst_forge/templates/scaffolds/k8s-argocd/environment-template/kustomization.yaml +0 -0
  73. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/src/katalyst_forge/templates/scaffolds/k8s-argocd/environment-template/patch-argocd-application.yaml +0 -0
  74. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/src/katalyst_forge/templates/scaffolds/k8s-argocd/layer.yaml +0 -0
  75. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/src/katalyst_forge/templates/scaffolds/k8s-kustomize/README.md +0 -0
  76. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/src/katalyst_forge/templates/scaffolds/k8s-kustomize/base/deployment.yaml +0 -0
  77. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/src/katalyst_forge/templates/scaffolds/k8s-kustomize/base/kustomization.yaml +0 -0
  78. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/src/katalyst_forge/templates/scaffolds/k8s-kustomize/base/namespace.yaml +0 -0
  79. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/src/katalyst_forge/templates/scaffolds/k8s-kustomize/base/service.yaml +0 -0
  80. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/src/katalyst_forge/templates/scaffolds/k8s-kustomize/environment-template/kustomization.yaml +0 -0
  81. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/src/katalyst_forge/templates/scaffolds/k8s-kustomize/environment-template/patch-deployment.yaml +0 -0
  82. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/src/katalyst_forge/templates/scaffolds/k8s-kustomize/global/k8s/base/kustomization.yaml +0 -0
  83. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/src/katalyst_forge/templates/scaffolds/k8s-kustomize/global/k8s/base/namespace.yaml +0 -0
  84. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/src/katalyst_forge/templates/scaffolds/k8s-kustomize/global/k8s/kustomization.yaml +0 -0
  85. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/src/katalyst_forge/templates/scaffolds/k8s-kustomize/layer.yaml +0 -0
  86. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/src/katalyst_forge/wings/__init__.py +0 -0
  87. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/src/katalyst_forge/wings/agentic.py +0 -0
  88. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/src/katalyst_forge/wings/delivery.py +0 -0
  89. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/src/katalyst_forge/wings/pipeline.py +0 -0
  90. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/tests/conftest.py +0 -0
  91. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/tests/test_agent_run.py +0 -0
  92. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/tests/test_delivery_doc_consistency.py +0 -0
  93. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/tests/test_delivery_traceability.py +0 -0
  94. {katalyst_forge-4.2.0 → katalyst_forge-5.1.0}/tests/test_wing_schemas.py +0 -0
@@ -0,0 +1,23 @@
1
+ __pycache__/
2
+ *.pyc
3
+ .venv/
4
+ dist/
5
+ site/
6
+ node_modules/
7
+ .pytest_cache/
8
+ .ruff_cache/
9
+
10
+ # RIC-733 consistency eval run exhaust (transient, not the checked-in baseline)
11
+ docs/consistency-results.json
12
+ .prompt-cache/
13
+
14
+ # Deterministic tooling-gate run artifacts (kata-gate.sh runtime output).
15
+ # Real telemetry per run; regenerated on every gate invocation, not committed.
16
+ .global/taxonomy/delivery/agent_runs/tooling/
17
+
18
+ # Generated orientation packet (RIC-731): produced at install time, not source
19
+ orientation/packet.json
20
+
21
+ # Machine-local orientation fallback config (RIC-731): holds an absolute packetPath,
22
+ # written beside the installed contract; never source, never commit.
23
+ orientation-config.json
@@ -16,6 +16,45 @@ PyPI package version. A breaking node-type/model change bumps `schema_version`.
16
16
 
17
17
  ---
18
18
 
19
+ ## [5.1.0] -- 2026-07-28
20
+
21
+ - **Canonical ADR/NFR storage** (RIC-1358) — ADR and NFR definitions now declare flat identity-derived storage under `.global/taxonomy/design/adrs/` and `.global/taxonomy/design/nfrs/`. Forge agents, skills, templates, fixtures, and documentation use the plural directories; legacy multi-document examples are labeled explicitly.
22
+ - Migrated the nine Forge-owned NFR artifacts from `design/nfr/` to `design/nfrs/` and added `NFR-010` to require executable storage consumers to resolve registry metadata instead of hard-coding artifact kinds or paths.
23
+
24
+ ## [5.0.0] -- 2026-07-22
25
+
26
+ Bundle `schema_version` bumped to **5** and manifest version to **5.0** to reflect breaking relationship renames and parent-rule changes below.
27
+
28
+ ### Added
29
+
30
+ - **`practice` node kind** in the Practices wing (RIC-1273). A bundle node that sits between `practice_area` and standards/methods/competencies/tools, enabling strict nesting: `practice_area` → `practice` → `{standard, method, competency, tool}`. Practices are assignable units that reference (do not own) standards and methods.
31
+ - **`INCLUDES_PRACTICE` relationship** (`practice_area` → `practice`): grouping edge for the new strict nesting hierarchy.
32
+ - **`PRESCRIBES_STANDARD` / `PRESCRIBES_METHOD` relationships** (`practice` → `standard` / `method`): practice prescribes which standards and methods it bundles.
33
+ - **`ADHERES_TO_PRACTICE` / `ADHERES_TO_STANDARD` / `ADHERES_TO_METHOD` relationships**: assignment edges allowing consumer nodes (system, stack, layer, library, tool, organization, project, team) to declare which practices, standards, and methods they follow.
34
+ - **Practice assignment fields** (`practices`, `standards`, `methods`) spliced into 8 consumer ("follower") node kinds via shared `_practice_refs.py` helper.
35
+ - **`metric_definition`, `signal_source`, `threshold_profile` node kinds** in the new Metrics wing (RIC-1272). Brings the bundle to **36 node types across 8 wings**.
36
+
37
+ ### Changed
38
+
39
+ - **BREAKING: `competency` re-parented from `practice_area` to `practice`** (RIC-1273). The `ParentRule.allowed_parent_kinds` changed from `{"practice_area"}` to `{"practice"}`. Any existing `competency` instances parented under a `practice_area` must be re-parented under a `practice` node. No known consuming taxonomies have competency instances.
40
+ - **BREAKING: Relationship renames** (RIC-1273). The following relationship types were renamed for naming consistency (all edge families now use verb-first, actor-centric naming):
41
+ - `INCLUDES_METHOD` / `INCLUDES_STANDARD` → removed (replaced by `PRESCRIBES_STANDARD` / `PRESCRIBES_METHOD` on the new `practice` node)
42
+ - Assignment family unified: `FOLLOWS_PRACTICE` → `ADHERES_TO_PRACTICE`, `APPLIES_METHOD` → `ADHERES_TO_METHOD` (`ADHERES_TO_STANDARD` unchanged)
43
+ - **`standard` and `method` relocated from Design wing to Practices wing** (RIC-1273). `nfr` is now a child of `standard`; `adr` is now a child of `method`. Design wing shrinks from 8 → 6 kinds; Practices wing grows from 4 → 9 kinds.
44
+
45
+ ### Migration
46
+
47
+ Consuming taxonomies that reference the removed/renamed relationship types in cross-references or queries must update:
48
+
49
+ | Old | New |
50
+ |-----|-----|
51
+ | `INCLUDES_METHOD` | `PRESCRIBES_METHOD` (on `practice`, not `practice_area`) |
52
+ | `INCLUDES_STANDARD` | `PRESCRIBES_STANDARD` (on `practice`, not `practice_area`) |
53
+ | `FOLLOWS_PRACTICE` | `ADHERES_TO_PRACTICE` |
54
+ | `APPLIES_METHOD` | `ADHERES_TO_METHOD` |
55
+ | `competency` parented under `practice_area` | Re-parent under `practice` |
56
+ | `nfr` / `adr` in design wing | Now in practices wing (no YAML change needed; wing is metadata) |
57
+
19
58
  ## [4.2.0] -- 2026-07-06
20
59
 
21
60
  Repo split (RIC-1070). First release from the standalone
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: katalyst-forge
3
- Version: 4.2.0
3
+ Version: 5.1.0
4
4
  Summary: Katalyst Forge: the delivery-lifecycle bundle (node kinds, wings, agents, templates, schemas)
5
5
  Author: eSimplicity
6
6
  License: Proprietary
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "katalyst-forge"
3
- version = "4.2.0"
3
+ version = "5.1.0"
4
4
  description = "Katalyst Forge: the delivery-lifecycle bundle (node kinds, wings, agents, templates, schemas)"
5
5
  license = { text = "Proprietary" }
6
6
  requires-python = ">=3.12"
@@ -1,6 +1,6 @@
1
1
  """katalyst-forge — The Forge bundle for katalyst-engine.
2
2
 
3
- Provides 33 node-type definitions across 8 wings for software delivery taxonomy.
3
+ Provides 36 node-type definitions across 8 wings for software delivery taxonomy.
4
4
  """
5
5
 
6
6
  from __future__ import annotations
@@ -1,6 +1,6 @@
1
1
  """Forge bundle — the pre-installed taxonomy for software delivery.
2
2
 
3
- Assembles 34 node types across 8 wings from the wing modules into
3
+ Assembles 36 node types across 8 wings from the wing modules into
4
4
  a single ``ForgeBundle`` that implements the engine's ``Bundle``
5
5
  protocol. Discovered via the ``katalyst_engine.bundles`` entry point.
6
6
 
@@ -9,12 +9,13 @@ protocol. Discovered via the ``katalyst_engine.bundles`` entry point.
9
9
  Wing modules:
10
10
  - ``wings/system.py`` — system, environment, stack, layer, library, capability
11
11
  - ``wings/org.py`` — organization, program, project, team, team_member, role
12
- - ``wings/practices.py`` — practice_area, competency, skill, tool
13
- - ``wings/design.py`` — business_domain_model, user_type, user_need, design_spec, adr, nfr, specification, assertion
12
+ - ``wings/practices.py`` — practice_area, practice, competency, skill, standard, nfr, method, adr, tool
13
+ - ``wings/design.py`` — business_domain_model, user_type, user_need, design_spec, specification, assertion
14
14
  - ``wings/delivery.py`` — work_item, change_entry, agent_run
15
15
  - ``wings/pipeline.py`` — cicd_stage
16
16
  - ``wings/pipeline.py`` — cicd_stage, cicd_job_template, cicd_workflow_template
17
17
  - ``wings/agentic.py`` — agent, agent_skill
18
+ - ``wings/metrics.py`` — metric_definition, signal_source, threshold_profile
18
19
  """
19
20
 
20
21
  from __future__ import annotations
@@ -36,6 +37,7 @@ from katalyst_forge.relationships import ALL_RELATIONSHIP_DEFINITIONS
36
37
  from katalyst_forge.wings.agentic import AGENTIC_WING, AGENTIC_WING_NODES
37
38
  from katalyst_forge.wings.delivery import DELIVERY_WING, DELIVERY_WING_NODES
38
39
  from katalyst_forge.wings.design import DESIGN_WING, DESIGN_WING_NODES
40
+ from katalyst_forge.wings.metrics import METRICS_WING, METRICS_WING_NODES
39
41
  from katalyst_forge.wings.org import ORG_WING, ORG_WING_NODES
40
42
  from katalyst_forge.wings.pipeline import PIPELINE_WING, PIPELINE_WING_NODES
41
43
  from katalyst_forge.wings.practices import PRACTICES_WING, PRACTICES_WING_NODES
@@ -53,6 +55,7 @@ ALL_NODE_DEFINITIONS: list[NodeDefinition] = [
53
55
  *DELIVERY_WING_NODES,
54
56
  *PIPELINE_WING_NODES,
55
57
  *AGENTIC_WING_NODES,
58
+ *METRICS_WING_NODES,
56
59
  ]
57
60
 
58
61
  ALL_KINDS: frozenset[str] = frozenset(nd.describes_kind for nd in ALL_NODE_DEFINITIONS)
@@ -65,6 +68,7 @@ ALL_WING_DEFINITIONS: list[WingDefinition] = [
65
68
  PRACTICES_WING,
66
69
  PIPELINE_WING,
67
70
  AGENTIC_WING,
71
+ METRICS_WING,
68
72
  ]
69
73
 
70
74
  ALL_WING_NAMES: frozenset[str] = frozenset(wd.identity.name for wd in ALL_WING_DEFINITIONS)
@@ -76,7 +80,7 @@ ALL_WING_NAMES: frozenset[str] = frozenset(wd.identity.name for wd in ALL_WING_D
76
80
 
77
81
 
78
82
  class ForgeBundle:
79
- """The Forge bundle — 34 node types across 8 wings.
83
+ """The Forge bundle — 36 node types across 8 wings.
80
84
 
81
85
  This is the pre-installed taxonomy bundle that ships with
82
86
  Katalyst Taxonomy. It models software delivery organizations
@@ -89,10 +93,10 @@ class ForgeBundle:
89
93
  def manifest(self) -> BundleManifest:
90
94
  return BundleManifest(
91
95
  identity=Identity(kind="bundle", name="forge"),
92
- version=Version(major=4, minor=0),
96
+ version=Version(major=5, minor=1),
93
97
  provided_kinds=ALL_KINDS,
94
98
  wing_names=ALL_WING_NAMES,
95
- description="Forge taxonomy — 30 node types for modeling software delivery organizations",
99
+ description="Forge taxonomy — 36 node types for modeling software delivery organizations",
96
100
  )
97
101
 
98
102
  def node_definitions(self) -> list[NodeDefinition]:
@@ -109,7 +113,7 @@ class ForgeBundle:
109
113
  identity=Identity(kind="schema", name="forge"),
110
114
  describes_kind="taxonomy",
111
115
  api_version="v2alpha",
112
- schema_version=Version(major=4),
116
+ schema_version=Version(major=5),
113
117
  node_definitions=tuple(nd.identity for nd in ALL_NODE_DEFINITIONS),
114
118
  wing_definitions=tuple(wd.identity for wd in ALL_WING_DEFINITIONS),
115
119
  )
@@ -127,16 +127,25 @@ FILLED_BY_REL = RelationshipDefinition(
127
127
  DEVELOPS_COMPETENCY_REL = RelationshipDefinition(
128
128
  identity=_rel_id("develops_competency"),
129
129
  describes_kind="develops_competency",
130
- description="Practice area develops a competency",
130
+ description="Practice develops a competency",
131
131
  wing="organizational",
132
132
  display_order=210,
133
133
  cardinality=Cardinality.MANY_TO_MANY,
134
134
  )
135
135
 
136
+ INCLUDES_PRACTICE_REL = RelationshipDefinition(
137
+ identity=_rel_id("includes_practice"),
138
+ describes_kind="includes_practice",
139
+ description="Practice area includes a practice",
140
+ wing="organizational",
141
+ display_order=214,
142
+ cardinality=Cardinality.MANY_TO_MANY,
143
+ )
144
+
136
145
  USES_TOOL_REL = RelationshipDefinition(
137
146
  identity=_rel_id("uses_tool"),
138
147
  describes_kind="uses_tool",
139
- description="Practice area uses a tool",
148
+ description="Practice uses a tool",
140
149
  wing="organizational",
141
150
  display_order=220,
142
151
  cardinality=Cardinality.MANY_TO_MANY,
@@ -151,6 +160,55 @@ REQUIRES_SKILL_REL = RelationshipDefinition(
151
160
  cardinality=Cardinality.MANY_TO_MANY,
152
161
  )
153
162
 
163
+ # ── Practice prescribing (practice → standard/method, referenced not owned) ──
164
+
165
+ PRESCRIBES_STANDARD_REL = RelationshipDefinition(
166
+ identity=_rel_id("prescribes_standard"),
167
+ describes_kind="prescribes_standard",
168
+ description="Practice prescribes a standard",
169
+ wing="organizational",
170
+ display_order=231,
171
+ cardinality=Cardinality.MANY_TO_MANY,
172
+ )
173
+
174
+ PRESCRIBES_METHOD_REL = RelationshipDefinition(
175
+ identity=_rel_id("prescribes_method"),
176
+ describes_kind="prescribes_method",
177
+ description="Practice prescribes a method",
178
+ wing="organizational",
179
+ display_order=232,
180
+ cardinality=Cardinality.MANY_TO_MANY,
181
+ )
182
+
183
+ # ── Practice assignment (consumer node → practice/standard/method) ────────
184
+
185
+ ADHERES_TO_PRACTICE_REL = RelationshipDefinition(
186
+ identity=_rel_id("adheres_to_practice"),
187
+ describes_kind="adheres_to_practice",
188
+ description="A node adheres to a practice",
189
+ wing="organizational",
190
+ display_order=233,
191
+ cardinality=Cardinality.MANY_TO_MANY,
192
+ )
193
+
194
+ ADHERES_TO_STANDARD_REL = RelationshipDefinition(
195
+ identity=_rel_id("adheres_to_standard"),
196
+ describes_kind="adheres_to_standard",
197
+ description="A node adheres to a standard",
198
+ wing="organizational",
199
+ display_order=234,
200
+ cardinality=Cardinality.MANY_TO_MANY,
201
+ )
202
+
203
+ ADHERES_TO_METHOD_REL = RelationshipDefinition(
204
+ identity=_rel_id("adheres_to_method"),
205
+ describes_kind="adheres_to_method",
206
+ description="A node adheres to a method",
207
+ wing="organizational",
208
+ display_order=235,
209
+ cardinality=Cardinality.MANY_TO_MANY,
210
+ )
211
+
154
212
  # ── Verification wing ────────────────────────────────────────────────
155
213
 
156
214
  VERIFIED_BY_REL = RelationshipDefinition(
@@ -249,7 +307,7 @@ TRACES_TO_REL = RelationshipDefinition(
249
307
  identity=_rel_id("traces_to"),
250
308
  describes_kind="traces_to",
251
309
  description=(
252
- "Work item traces to a design-wing artifact it implements, addresses, or "
310
+ "Work item traces to a design- or practices-wing artifact it implements, addresses, or "
253
311
  "satisfies (capability, user_need, nfr, adr, design_spec, specification). "
254
312
  "The target kind is carried by the source field reference, so adding a new "
255
313
  "traceable target kind is a one-line field addition, not a new edge type."
@@ -297,8 +355,14 @@ ALL_RELATIONSHIP_DEFINITIONS: list[RelationshipDefinition] = [
297
355
  # organizational
298
356
  FILLED_BY_REL,
299
357
  DEVELOPS_COMPETENCY_REL,
358
+ INCLUDES_PRACTICE_REL,
300
359
  USES_TOOL_REL,
301
360
  REQUIRES_SKILL_REL,
361
+ PRESCRIBES_STANDARD_REL,
362
+ PRESCRIBES_METHOD_REL,
363
+ ADHERES_TO_PRACTICE_REL,
364
+ ADHERES_TO_STANDARD_REL,
365
+ ADHERES_TO_METHOD_REL,
302
366
  # verification
303
367
  VERIFIED_BY_REL,
304
368
  TESTS_SPECIFICATION_REL,
@@ -0,0 +1,58 @@
1
+ """Shared practice-reference fields for consumer ("follower") node kinds.
2
+
3
+ Any node that can *follow* a practice, *adhere to* a standard, or *apply* a
4
+ method carries the same three cross-reference fields. Rather than duplicate the
5
+ identical ``FieldSpec``/``FieldRef`` blocks across every follower kind in the
6
+ ``system``, ``org``, and ``practices`` wings, they are defined once here and
7
+ spliced into each follower's ``fields`` / ``cross_references`` tuples.
8
+
9
+ These edges are the *assignment* side of practices — semantically distinct from
10
+ the *grouping* edges (``INCLUDES_PRACTICE`` on ``practice_area``;
11
+ ``PRESCRIBES_STANDARD`` / ``PRESCRIBES_METHOD`` on ``practice``). A follower "adheres
12
+ to" a standard; a practice "prescribes" one; a practice_area "includes" a practice.
13
+ """
14
+
15
+ from __future__ import annotations
16
+
17
+ from katalyst_engine.schema.definition import FieldRef, FieldSpec
18
+
19
+ #: Fields spliced into every follower kind's ``fields`` tuple.
20
+ PRACTICE_REFERENCE_FIELDS: tuple[FieldSpec, ...] = (
21
+ FieldSpec(
22
+ name="practices",
23
+ field_type="list",
24
+ required=False,
25
+ description="Practices this node follows",
26
+ ),
27
+ FieldSpec(
28
+ name="standards",
29
+ field_type="list",
30
+ required=False,
31
+ description="Standards this node adheres to",
32
+ ),
33
+ FieldSpec(
34
+ name="methods",
35
+ field_type="list",
36
+ required=False,
37
+ description="Methods this node applies",
38
+ ),
39
+ )
40
+
41
+ #: Cross-references spliced into every follower kind's ``cross_references``.
42
+ PRACTICE_REFERENCE_CROSS_REFS: tuple[FieldRef, ...] = (
43
+ FieldRef(
44
+ field_name="practices",
45
+ target_kind="practice",
46
+ rel_type="ADHERES_TO_PRACTICE",
47
+ ),
48
+ FieldRef(
49
+ field_name="standards",
50
+ target_kind="standard",
51
+ rel_type="ADHERES_TO_STANDARD",
52
+ ),
53
+ FieldRef(
54
+ field_name="methods",
55
+ target_kind="method",
56
+ rel_type="ADHERES_TO_METHOD",
57
+ ),
58
+ )
@@ -1,4 +1,8 @@
1
- """Design wing — business_domain_model, user_type, user_need, design_spec, adr, nfr, specification, assertion."""
1
+ """Design wing — business_domain_model, user_type, user_need, design_spec, specification, assertion.
2
+
3
+ Note: ADR and NFR have been moved to the practices wing where they are
4
+ subclasses of method and standard respectively.
5
+ """
2
6
 
3
7
  from __future__ import annotations
4
8
 
@@ -296,116 +300,6 @@ DESIGN_SPEC: NodeDefinition = NodeDefinition(
296
300
  ),
297
301
  )
298
302
 
299
- ADR: NodeDefinition = NodeDefinition(
300
- identity=Identity(kind="node_definition", name="adr"),
301
- describes_kind="adr",
302
- wing="design",
303
- display_order=380,
304
- directory_name="adrs",
305
- is_root=True,
306
- is_leaf=True,
307
- is_extension=False,
308
- clonable=False,
309
- display_label="ADR",
310
- display_label_plural="ADRs",
311
- extends_kinds=(),
312
- parent_rules=(),
313
- fields=(
314
- FieldSpec(
315
- name="title",
316
- field_type="string",
317
- required=False,
318
- description="",
319
- ),
320
- FieldSpec(
321
- name="status",
322
- field_type="string",
323
- required=False,
324
- description="",
325
- ),
326
- FieldSpec(
327
- name="category",
328
- field_type="string",
329
- required=False,
330
- description="",
331
- ),
332
- FieldSpec(
333
- name="scope",
334
- field_type="string",
335
- required=False,
336
- description="Scope of the decision",
337
- ),
338
- FieldSpec(
339
- name="superseded_by",
340
- field_type="string",
341
- required=False,
342
- description="Name of the ADR that supersedes this one",
343
- ),
344
- ),
345
- cross_references=(
346
- FieldRef(
347
- field_name="superseded_by",
348
- target_kind="adr",
349
- rel_type="SUPERSEDED_BY",
350
- ),
351
- ),
352
- )
353
-
354
- NFR: NodeDefinition = NodeDefinition(
355
- identity=Identity(kind="node_definition", name="nfr"),
356
- describes_kind="nfr",
357
- wing="design",
358
- display_order=390,
359
- directory_name="nfrs",
360
- is_root=True,
361
- is_leaf=True,
362
- is_extension=False,
363
- clonable=False,
364
- display_label="NFR",
365
- display_label_plural="NFRs",
366
- extends_kinds=(),
367
- parent_rules=(),
368
- fields=(
369
- FieldSpec(
370
- name="title",
371
- field_type="string",
372
- required=False,
373
- description="",
374
- ),
375
- FieldSpec(
376
- name="category",
377
- field_type="string",
378
- required=False,
379
- description="",
380
- ),
381
- FieldSpec(
382
- name="priority",
383
- field_type="string",
384
- required=False,
385
- description="",
386
- ),
387
- FieldSpec(
388
- name="status",
389
- field_type="string",
390
- required=False,
391
- description="",
392
- ),
393
- FieldSpec(
394
- name="threshold",
395
- field_type="string",
396
- required=False,
397
- description="Measurable threshold (e.g., p99 < 200ms)",
398
- ),
399
- FieldSpec(
400
- name="measurement",
401
- field_type="string",
402
- required=False,
403
- description="How this NFR is measured",
404
- ),
405
- ),
406
- cross_references=(),
407
- )
408
-
409
303
  SPECIFICATION: NodeDefinition = NodeDefinition(
410
304
  identity=Identity(kind="node_definition", name="specification"),
411
305
  describes_kind="specification",
@@ -545,8 +439,6 @@ DESIGN_WING: WingDefinition = WingDefinition(
545
439
  "user_type",
546
440
  "user_need",
547
441
  "design_spec",
548
- "adr",
549
- "nfr",
550
442
  "specification",
551
443
  "assertion",
552
444
  ),
@@ -557,8 +449,6 @@ DESIGN_WING_NODES = [
557
449
  USER_TYPE,
558
450
  USER_NEED,
559
451
  DESIGN_SPEC,
560
- ADR,
561
- NFR,
562
452
  SPECIFICATION,
563
453
  ASSERTION,
564
454
  ]
@@ -0,0 +1,197 @@
1
+ """Metrics wing — metric_definition, signal_source, threshold_profile."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from katalyst_engine.core.identity import Identity
6
+ from katalyst_engine.schema.definition import (
7
+ FieldRef,
8
+ FieldSpec,
9
+ NodeDefinition,
10
+ WingDefinition,
11
+ )
12
+
13
+ METRIC_DEFINITION: NodeDefinition = NodeDefinition(
14
+ identity=Identity(kind="node_definition", name="metric_definition"),
15
+ describes_kind="metric_definition",
16
+ wing="metrics",
17
+ display_order=700,
18
+ directory_name="metric_definitions",
19
+ is_root=True,
20
+ is_leaf=True,
21
+ is_extension=False,
22
+ clonable=True,
23
+ display_label="Metric Definition",
24
+ display_label_plural="Metric Definitions",
25
+ extends_kinds=(),
26
+ parent_rules=(),
27
+ fields=(
28
+ FieldSpec(
29
+ name="title",
30
+ field_type="string",
31
+ required=False,
32
+ description="",
33
+ ),
34
+ FieldSpec(
35
+ name="description",
36
+ field_type="string",
37
+ required=False,
38
+ description="",
39
+ ),
40
+ FieldSpec(
41
+ name="category",
42
+ field_type="string",
43
+ required=False,
44
+ description="Metric category (throughput, stability, speed, recovery)",
45
+ ),
46
+ FieldSpec(
47
+ name="unit",
48
+ field_type="string",
49
+ required=False,
50
+ description="Measurement unit (deploys/day, hours, percentage)",
51
+ ),
52
+ FieldSpec(
53
+ name="direction",
54
+ field_type="string",
55
+ required=False,
56
+ description="Optimization direction (higher_is_better, lower_is_better)",
57
+ ),
58
+ FieldSpec(
59
+ name="aggregation",
60
+ field_type="string",
61
+ required=False,
62
+ description="Aggregation method (count_per_period, median_duration, ratio, mean_duration)",
63
+ ),
64
+ FieldSpec(
65
+ name="inputs",
66
+ field_type="list",
67
+ required=False,
68
+ description="Named inputs the metric formula requires",
69
+ ),
70
+ FieldSpec(
71
+ name="default_parameters",
72
+ field_type="map",
73
+ required=False,
74
+ description="Default configuration parameters for computation",
75
+ ),
76
+ ),
77
+ cross_references=(),
78
+ )
79
+
80
+ SIGNAL_SOURCE: NodeDefinition = NodeDefinition(
81
+ identity=Identity(kind="node_definition", name="signal_source"),
82
+ describes_kind="signal_source",
83
+ wing="metrics",
84
+ display_order=710,
85
+ directory_name="signal_sources",
86
+ is_root=True,
87
+ is_leaf=True,
88
+ is_extension=False,
89
+ clonable=True,
90
+ display_label="Signal Source",
91
+ display_label_plural="Signal Sources",
92
+ extends_kinds=(),
93
+ parent_rules=(),
94
+ fields=(
95
+ FieldSpec(
96
+ name="title",
97
+ field_type="string",
98
+ required=False,
99
+ description="",
100
+ ),
101
+ FieldSpec(
102
+ name="description",
103
+ field_type="string",
104
+ required=False,
105
+ description="",
106
+ ),
107
+ FieldSpec(
108
+ name="provider",
109
+ field_type="string",
110
+ required=True,
111
+ description="Signal provider (github, gitlab, argocd, pagerduty, custom)",
112
+ ),
113
+ FieldSpec(
114
+ name="signal_type",
115
+ field_type="string",
116
+ required=True,
117
+ description="Type of signal (deployment_event, failure_event, recovery_event, change_event)",
118
+ ),
119
+ FieldSpec(
120
+ name="query_config",
121
+ field_type="map",
122
+ required=False,
123
+ description="Provider-specific query parameters",
124
+ ),
125
+ FieldSpec(
126
+ name="field_mapping",
127
+ field_type="map",
128
+ required=False,
129
+ description="Maps provider fields to canonical metric input fields",
130
+ ),
131
+ FieldSpec(
132
+ name="metric_ref",
133
+ field_type="string",
134
+ required=False,
135
+ description="Name of the metric_definition this source feeds",
136
+ ),
137
+ ),
138
+ cross_references=(
139
+ FieldRef(
140
+ field_name="metric_ref",
141
+ target_kind="metric_definition",
142
+ rel_type="FEEDS_METRIC",
143
+ ),
144
+ ),
145
+ )
146
+
147
+ THRESHOLD_PROFILE: NodeDefinition = NodeDefinition(
148
+ identity=Identity(kind="node_definition", name="threshold_profile"),
149
+ describes_kind="threshold_profile",
150
+ wing="metrics",
151
+ display_order=720,
152
+ directory_name="threshold_profiles",
153
+ is_root=True,
154
+ is_leaf=True,
155
+ is_extension=False,
156
+ clonable=True,
157
+ display_label="Threshold Profile",
158
+ display_label_plural="Threshold Profiles",
159
+ extends_kinds=(),
160
+ parent_rules=(),
161
+ fields=(
162
+ FieldSpec(
163
+ name="title",
164
+ field_type="string",
165
+ required=False,
166
+ description="",
167
+ ),
168
+ FieldSpec(
169
+ name="description",
170
+ field_type="string",
171
+ required=False,
172
+ description="",
173
+ ),
174
+ FieldSpec(
175
+ name="scoped_to",
176
+ field_type="list",
177
+ required=False,
178
+ description="Systems or teams this profile applies to (empty = global default)",
179
+ ),
180
+ FieldSpec(
181
+ name="metric_thresholds",
182
+ field_type="list",
183
+ required=False,
184
+ description="Per-metric band definitions with operator and value",
185
+ ),
186
+ ),
187
+ cross_references=(),
188
+ )
189
+
190
+ METRICS_WING: WingDefinition = WingDefinition(
191
+ identity=Identity(kind="wing_definition", name="metrics"),
192
+ describes_kind="metrics",
193
+ display_name="Metrics",
194
+ member_kinds=("metric_definition", "signal_source", "threshold_profile"),
195
+ )
196
+
197
+ METRICS_WING_NODES = [METRIC_DEFINITION, SIGNAL_SOURCE, THRESHOLD_PROFILE]