@mc-and-his-agents/loom-installer 0.1.18 → 0.1.19

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 (32) hide show
  1. package/package.json +1 -1
  2. package/payload/manifest.json +62 -62
  3. package/payload/plugin/loom/skills/shared/scripts/loom_check.py +36 -0
  4. package/payload/plugin/loom/skills/shared/scripts/loom_flow.py +49 -0
  5. package/payload/plugin/loom/skills/shared/scripts/loom_init.py +51 -5
  6. package/payload/skills/loom-adopt/.loom-runtime/shared/scripts/loom_check.py +36 -0
  7. package/payload/skills/loom-adopt/.loom-runtime/shared/scripts/loom_flow.py +49 -0
  8. package/payload/skills/loom-adopt/.loom-runtime/shared/scripts/loom_init.py +51 -5
  9. package/payload/skills/loom-handoff/.loom-runtime/shared/scripts/loom_check.py +36 -0
  10. package/payload/skills/loom-handoff/.loom-runtime/shared/scripts/loom_flow.py +49 -0
  11. package/payload/skills/loom-handoff/.loom-runtime/shared/scripts/loom_init.py +51 -5
  12. package/payload/skills/loom-init/.loom-runtime/shared/scripts/loom_check.py +36 -0
  13. package/payload/skills/loom-init/.loom-runtime/shared/scripts/loom_flow.py +49 -0
  14. package/payload/skills/loom-init/.loom-runtime/shared/scripts/loom_init.py +51 -5
  15. package/payload/skills/loom-merge-ready/.loom-runtime/shared/scripts/loom_check.py +36 -0
  16. package/payload/skills/loom-merge-ready/.loom-runtime/shared/scripts/loom_flow.py +49 -0
  17. package/payload/skills/loom-merge-ready/.loom-runtime/shared/scripts/loom_init.py +51 -5
  18. package/payload/skills/loom-pre-review/.loom-runtime/shared/scripts/loom_check.py +36 -0
  19. package/payload/skills/loom-pre-review/.loom-runtime/shared/scripts/loom_flow.py +49 -0
  20. package/payload/skills/loom-pre-review/.loom-runtime/shared/scripts/loom_init.py +51 -5
  21. package/payload/skills/loom-resume/.loom-runtime/shared/scripts/loom_check.py +36 -0
  22. package/payload/skills/loom-resume/.loom-runtime/shared/scripts/loom_flow.py +49 -0
  23. package/payload/skills/loom-resume/.loom-runtime/shared/scripts/loom_init.py +51 -5
  24. package/payload/skills/loom-retire/.loom-runtime/shared/scripts/loom_check.py +36 -0
  25. package/payload/skills/loom-retire/.loom-runtime/shared/scripts/loom_flow.py +49 -0
  26. package/payload/skills/loom-retire/.loom-runtime/shared/scripts/loom_init.py +51 -5
  27. package/payload/skills/loom-review/.loom-runtime/shared/scripts/loom_check.py +36 -0
  28. package/payload/skills/loom-review/.loom-runtime/shared/scripts/loom_flow.py +49 -0
  29. package/payload/skills/loom-review/.loom-runtime/shared/scripts/loom_init.py +51 -5
  30. package/payload/skills/loom-spec-review/.loom-runtime/shared/scripts/loom_check.py +36 -0
  31. package/payload/skills/loom-spec-review/.loom-runtime/shared/scripts/loom_flow.py +49 -0
  32. package/payload/skills/loom-spec-review/.loom-runtime/shared/scripts/loom_init.py +51 -5
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mc-and-his-agents/loom-installer",
3
- "version": "0.1.18",
3
+ "version": "0.1.19",
4
4
  "description": "Node installer for Loom plugin and single-skill installation surfaces.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -2,9 +2,9 @@
2
2
  "schema_version": "loom-installer-payload/v1",
3
3
  "loom_version": "0.4.0",
4
4
  "source_repository": "https://github.com/MC-and-his-Agents/Loom",
5
- "source_commit": "3daaced2a93b2f5170fc738bcd631d6323336c82",
5
+ "source_commit": "f25d0954fff0ab7dcf7234f89eb001bc08a0c9df",
6
6
  "source_ref": "main",
7
- "built_at": "2026-04-25T13:30:42+08:00",
7
+ "built_at": "2026-04-25T13:46:37+08:00",
8
8
  "runtime": {
9
9
  "python_minimum": "3.10",
10
10
  "python_recommended": "3.11+"
@@ -628,18 +628,18 @@
628
628
  },
629
629
  {
630
630
  "path": "plugin/loom/skills/shared/scripts/loom_check.py",
631
- "bytes": 271781,
632
- "sha256": "916036e9f69521168511ca4e30cd7066ae2d9abb22294fb984ebe3d76d199cfa"
631
+ "bytes": 273789,
632
+ "sha256": "2d0a345221eeca04cef5e635b84f059ce6cf4b9316f4a210360237597406ae2e"
633
633
  },
634
634
  {
635
635
  "path": "plugin/loom/skills/shared/scripts/loom_flow.py",
636
- "bytes": 288183,
637
- "sha256": "76fd6610e74672d527f43edd1311dbd6ca571406536d04dae502236eb67a5a38"
636
+ "bytes": 290536,
637
+ "sha256": "69c44efb623eb26aadda9141ecb73eea036444c1023b833da7f9cbb709f68428"
638
638
  },
639
639
  {
640
640
  "path": "plugin/loom/skills/shared/scripts/loom_init.py",
641
- "bytes": 81617,
642
- "sha256": "5ebf6b81bd6d0ef6ef5ac2663d98b47d9e4117f1087fd52742bd189a6be5692b"
641
+ "bytes": 83763,
642
+ "sha256": "3132627c8aec74fd5f8dd232bd2f8c10a035674723de22877b6079c1ca8cf9d1"
643
643
  },
644
644
  {
645
645
  "path": "plugin/loom/skills/shared/scripts/loom_status.py",
@@ -1213,18 +1213,18 @@
1213
1213
  },
1214
1214
  {
1215
1215
  "path": "skills/loom-adopt/.loom-runtime/shared/scripts/loom_check.py",
1216
- "bytes": 271781,
1217
- "sha256": "916036e9f69521168511ca4e30cd7066ae2d9abb22294fb984ebe3d76d199cfa"
1216
+ "bytes": 273789,
1217
+ "sha256": "2d0a345221eeca04cef5e635b84f059ce6cf4b9316f4a210360237597406ae2e"
1218
1218
  },
1219
1219
  {
1220
1220
  "path": "skills/loom-adopt/.loom-runtime/shared/scripts/loom_flow.py",
1221
- "bytes": 288183,
1222
- "sha256": "76fd6610e74672d527f43edd1311dbd6ca571406536d04dae502236eb67a5a38"
1221
+ "bytes": 290536,
1222
+ "sha256": "69c44efb623eb26aadda9141ecb73eea036444c1023b833da7f9cbb709f68428"
1223
1223
  },
1224
1224
  {
1225
1225
  "path": "skills/loom-adopt/.loom-runtime/shared/scripts/loom_init.py",
1226
- "bytes": 81617,
1227
- "sha256": "5ebf6b81bd6d0ef6ef5ac2663d98b47d9e4117f1087fd52742bd189a6be5692b"
1226
+ "bytes": 83763,
1227
+ "sha256": "3132627c8aec74fd5f8dd232bd2f8c10a035674723de22877b6079c1ca8cf9d1"
1228
1228
  },
1229
1229
  {
1230
1230
  "path": "skills/loom-adopt/.loom-runtime/shared/scripts/loom_status.py",
@@ -1828,18 +1828,18 @@
1828
1828
  },
1829
1829
  {
1830
1830
  "path": "skills/loom-handoff/.loom-runtime/shared/scripts/loom_check.py",
1831
- "bytes": 271781,
1832
- "sha256": "916036e9f69521168511ca4e30cd7066ae2d9abb22294fb984ebe3d76d199cfa"
1831
+ "bytes": 273789,
1832
+ "sha256": "2d0a345221eeca04cef5e635b84f059ce6cf4b9316f4a210360237597406ae2e"
1833
1833
  },
1834
1834
  {
1835
1835
  "path": "skills/loom-handoff/.loom-runtime/shared/scripts/loom_flow.py",
1836
- "bytes": 288183,
1837
- "sha256": "76fd6610e74672d527f43edd1311dbd6ca571406536d04dae502236eb67a5a38"
1836
+ "bytes": 290536,
1837
+ "sha256": "69c44efb623eb26aadda9141ecb73eea036444c1023b833da7f9cbb709f68428"
1838
1838
  },
1839
1839
  {
1840
1840
  "path": "skills/loom-handoff/.loom-runtime/shared/scripts/loom_init.py",
1841
- "bytes": 81617,
1842
- "sha256": "5ebf6b81bd6d0ef6ef5ac2663d98b47d9e4117f1087fd52742bd189a6be5692b"
1841
+ "bytes": 83763,
1842
+ "sha256": "3132627c8aec74fd5f8dd232bd2f8c10a035674723de22877b6079c1ca8cf9d1"
1843
1843
  },
1844
1844
  {
1845
1845
  "path": "skills/loom-handoff/.loom-runtime/shared/scripts/loom_status.py",
@@ -2443,18 +2443,18 @@
2443
2443
  },
2444
2444
  {
2445
2445
  "path": "skills/loom-init/.loom-runtime/shared/scripts/loom_check.py",
2446
- "bytes": 271781,
2447
- "sha256": "916036e9f69521168511ca4e30cd7066ae2d9abb22294fb984ebe3d76d199cfa"
2446
+ "bytes": 273789,
2447
+ "sha256": "2d0a345221eeca04cef5e635b84f059ce6cf4b9316f4a210360237597406ae2e"
2448
2448
  },
2449
2449
  {
2450
2450
  "path": "skills/loom-init/.loom-runtime/shared/scripts/loom_flow.py",
2451
- "bytes": 288183,
2452
- "sha256": "76fd6610e74672d527f43edd1311dbd6ca571406536d04dae502236eb67a5a38"
2451
+ "bytes": 290536,
2452
+ "sha256": "69c44efb623eb26aadda9141ecb73eea036444c1023b833da7f9cbb709f68428"
2453
2453
  },
2454
2454
  {
2455
2455
  "path": "skills/loom-init/.loom-runtime/shared/scripts/loom_init.py",
2456
- "bytes": 81617,
2457
- "sha256": "5ebf6b81bd6d0ef6ef5ac2663d98b47d9e4117f1087fd52742bd189a6be5692b"
2456
+ "bytes": 83763,
2457
+ "sha256": "3132627c8aec74fd5f8dd232bd2f8c10a035674723de22877b6079c1ca8cf9d1"
2458
2458
  },
2459
2459
  {
2460
2460
  "path": "skills/loom-init/.loom-runtime/shared/scripts/loom_status.py",
@@ -3063,18 +3063,18 @@
3063
3063
  },
3064
3064
  {
3065
3065
  "path": "skills/loom-merge-ready/.loom-runtime/shared/scripts/loom_check.py",
3066
- "bytes": 271781,
3067
- "sha256": "916036e9f69521168511ca4e30cd7066ae2d9abb22294fb984ebe3d76d199cfa"
3066
+ "bytes": 273789,
3067
+ "sha256": "2d0a345221eeca04cef5e635b84f059ce6cf4b9316f4a210360237597406ae2e"
3068
3068
  },
3069
3069
  {
3070
3070
  "path": "skills/loom-merge-ready/.loom-runtime/shared/scripts/loom_flow.py",
3071
- "bytes": 288183,
3072
- "sha256": "76fd6610e74672d527f43edd1311dbd6ca571406536d04dae502236eb67a5a38"
3071
+ "bytes": 290536,
3072
+ "sha256": "69c44efb623eb26aadda9141ecb73eea036444c1023b833da7f9cbb709f68428"
3073
3073
  },
3074
3074
  {
3075
3075
  "path": "skills/loom-merge-ready/.loom-runtime/shared/scripts/loom_init.py",
3076
- "bytes": 81617,
3077
- "sha256": "5ebf6b81bd6d0ef6ef5ac2663d98b47d9e4117f1087fd52742bd189a6be5692b"
3076
+ "bytes": 83763,
3077
+ "sha256": "3132627c8aec74fd5f8dd232bd2f8c10a035674723de22877b6079c1ca8cf9d1"
3078
3078
  },
3079
3079
  {
3080
3080
  "path": "skills/loom-merge-ready/.loom-runtime/shared/scripts/loom_status.py",
@@ -3678,18 +3678,18 @@
3678
3678
  },
3679
3679
  {
3680
3680
  "path": "skills/loom-pre-review/.loom-runtime/shared/scripts/loom_check.py",
3681
- "bytes": 271781,
3682
- "sha256": "916036e9f69521168511ca4e30cd7066ae2d9abb22294fb984ebe3d76d199cfa"
3681
+ "bytes": 273789,
3682
+ "sha256": "2d0a345221eeca04cef5e635b84f059ce6cf4b9316f4a210360237597406ae2e"
3683
3683
  },
3684
3684
  {
3685
3685
  "path": "skills/loom-pre-review/.loom-runtime/shared/scripts/loom_flow.py",
3686
- "bytes": 288183,
3687
- "sha256": "76fd6610e74672d527f43edd1311dbd6ca571406536d04dae502236eb67a5a38"
3686
+ "bytes": 290536,
3687
+ "sha256": "69c44efb623eb26aadda9141ecb73eea036444c1023b833da7f9cbb709f68428"
3688
3688
  },
3689
3689
  {
3690
3690
  "path": "skills/loom-pre-review/.loom-runtime/shared/scripts/loom_init.py",
3691
- "bytes": 81617,
3692
- "sha256": "5ebf6b81bd6d0ef6ef5ac2663d98b47d9e4117f1087fd52742bd189a6be5692b"
3691
+ "bytes": 83763,
3692
+ "sha256": "3132627c8aec74fd5f8dd232bd2f8c10a035674723de22877b6079c1ca8cf9d1"
3693
3693
  },
3694
3694
  {
3695
3695
  "path": "skills/loom-pre-review/.loom-runtime/shared/scripts/loom_status.py",
@@ -4293,18 +4293,18 @@
4293
4293
  },
4294
4294
  {
4295
4295
  "path": "skills/loom-resume/.loom-runtime/shared/scripts/loom_check.py",
4296
- "bytes": 271781,
4297
- "sha256": "916036e9f69521168511ca4e30cd7066ae2d9abb22294fb984ebe3d76d199cfa"
4296
+ "bytes": 273789,
4297
+ "sha256": "2d0a345221eeca04cef5e635b84f059ce6cf4b9316f4a210360237597406ae2e"
4298
4298
  },
4299
4299
  {
4300
4300
  "path": "skills/loom-resume/.loom-runtime/shared/scripts/loom_flow.py",
4301
- "bytes": 288183,
4302
- "sha256": "76fd6610e74672d527f43edd1311dbd6ca571406536d04dae502236eb67a5a38"
4301
+ "bytes": 290536,
4302
+ "sha256": "69c44efb623eb26aadda9141ecb73eea036444c1023b833da7f9cbb709f68428"
4303
4303
  },
4304
4304
  {
4305
4305
  "path": "skills/loom-resume/.loom-runtime/shared/scripts/loom_init.py",
4306
- "bytes": 81617,
4307
- "sha256": "5ebf6b81bd6d0ef6ef5ac2663d98b47d9e4117f1087fd52742bd189a6be5692b"
4306
+ "bytes": 83763,
4307
+ "sha256": "3132627c8aec74fd5f8dd232bd2f8c10a035674723de22877b6079c1ca8cf9d1"
4308
4308
  },
4309
4309
  {
4310
4310
  "path": "skills/loom-resume/.loom-runtime/shared/scripts/loom_status.py",
@@ -4908,18 +4908,18 @@
4908
4908
  },
4909
4909
  {
4910
4910
  "path": "skills/loom-retire/.loom-runtime/shared/scripts/loom_check.py",
4911
- "bytes": 271781,
4912
- "sha256": "916036e9f69521168511ca4e30cd7066ae2d9abb22294fb984ebe3d76d199cfa"
4911
+ "bytes": 273789,
4912
+ "sha256": "2d0a345221eeca04cef5e635b84f059ce6cf4b9316f4a210360237597406ae2e"
4913
4913
  },
4914
4914
  {
4915
4915
  "path": "skills/loom-retire/.loom-runtime/shared/scripts/loom_flow.py",
4916
- "bytes": 288183,
4917
- "sha256": "76fd6610e74672d527f43edd1311dbd6ca571406536d04dae502236eb67a5a38"
4916
+ "bytes": 290536,
4917
+ "sha256": "69c44efb623eb26aadda9141ecb73eea036444c1023b833da7f9cbb709f68428"
4918
4918
  },
4919
4919
  {
4920
4920
  "path": "skills/loom-retire/.loom-runtime/shared/scripts/loom_init.py",
4921
- "bytes": 81617,
4922
- "sha256": "5ebf6b81bd6d0ef6ef5ac2663d98b47d9e4117f1087fd52742bd189a6be5692b"
4921
+ "bytes": 83763,
4922
+ "sha256": "3132627c8aec74fd5f8dd232bd2f8c10a035674723de22877b6079c1ca8cf9d1"
4923
4923
  },
4924
4924
  {
4925
4925
  "path": "skills/loom-retire/.loom-runtime/shared/scripts/loom_status.py",
@@ -5523,18 +5523,18 @@
5523
5523
  },
5524
5524
  {
5525
5525
  "path": "skills/loom-review/.loom-runtime/shared/scripts/loom_check.py",
5526
- "bytes": 271781,
5527
- "sha256": "916036e9f69521168511ca4e30cd7066ae2d9abb22294fb984ebe3d76d199cfa"
5526
+ "bytes": 273789,
5527
+ "sha256": "2d0a345221eeca04cef5e635b84f059ce6cf4b9316f4a210360237597406ae2e"
5528
5528
  },
5529
5529
  {
5530
5530
  "path": "skills/loom-review/.loom-runtime/shared/scripts/loom_flow.py",
5531
- "bytes": 288183,
5532
- "sha256": "76fd6610e74672d527f43edd1311dbd6ca571406536d04dae502236eb67a5a38"
5531
+ "bytes": 290536,
5532
+ "sha256": "69c44efb623eb26aadda9141ecb73eea036444c1023b833da7f9cbb709f68428"
5533
5533
  },
5534
5534
  {
5535
5535
  "path": "skills/loom-review/.loom-runtime/shared/scripts/loom_init.py",
5536
- "bytes": 81617,
5537
- "sha256": "5ebf6b81bd6d0ef6ef5ac2663d98b47d9e4117f1087fd52742bd189a6be5692b"
5536
+ "bytes": 83763,
5537
+ "sha256": "3132627c8aec74fd5f8dd232bd2f8c10a035674723de22877b6079c1ca8cf9d1"
5538
5538
  },
5539
5539
  {
5540
5540
  "path": "skills/loom-review/.loom-runtime/shared/scripts/loom_status.py",
@@ -6138,18 +6138,18 @@
6138
6138
  },
6139
6139
  {
6140
6140
  "path": "skills/loom-spec-review/.loom-runtime/shared/scripts/loom_check.py",
6141
- "bytes": 271781,
6142
- "sha256": "916036e9f69521168511ca4e30cd7066ae2d9abb22294fb984ebe3d76d199cfa"
6141
+ "bytes": 273789,
6142
+ "sha256": "2d0a345221eeca04cef5e635b84f059ce6cf4b9316f4a210360237597406ae2e"
6143
6143
  },
6144
6144
  {
6145
6145
  "path": "skills/loom-spec-review/.loom-runtime/shared/scripts/loom_flow.py",
6146
- "bytes": 288183,
6147
- "sha256": "76fd6610e74672d527f43edd1311dbd6ca571406536d04dae502236eb67a5a38"
6146
+ "bytes": 290536,
6147
+ "sha256": "69c44efb623eb26aadda9141ecb73eea036444c1023b833da7f9cbb709f68428"
6148
6148
  },
6149
6149
  {
6150
6150
  "path": "skills/loom-spec-review/.loom-runtime/shared/scripts/loom_init.py",
6151
- "bytes": 81617,
6152
- "sha256": "5ebf6b81bd6d0ef6ef5ac2663d98b47d9e4117f1087fd52742bd189a6be5692b"
6151
+ "bytes": 83763,
6152
+ "sha256": "3132627c8aec74fd5f8dd232bd2f8c10a035674723de22877b6079c1ca8cf9d1"
6153
6153
  },
6154
6154
  {
6155
6155
  "path": "skills/loom-spec-review/.loom-runtime/shared/scripts/loom_status.py",
@@ -95,6 +95,7 @@ CORE_DOCS = (
95
95
  "docs/evidence/validations/validation-closeout-reconciliation-blocking-gate.md",
96
96
  "docs/evidence/validations/validation-adoption-maturity-upgrade-automation.md",
97
97
  "docs/evidence/validations/validation-adoption-maturity-required-fields.md",
98
+ "docs/evidence/validations/validation-skills-consume-maturity-upgrade-path.md",
98
99
  "docs/evidence/validations/validation-github-profile-binding-orchestration.md",
99
100
  "docs/evidence/validations/validation-github-profile-drift-reconciliation.md",
100
101
  "docs/evidence/validations/validation-github-profile-graphql-budget-guard.md",
@@ -1388,6 +1389,35 @@ def require_governance_upgrade_payload(
1388
1389
  failures.append(Failure(category, f"{context} missing-input actions must include recommended_action"))
1389
1390
 
1390
1391
 
1392
+ def require_maturity_upgrade_path(
1393
+ failures: list[Failure],
1394
+ *,
1395
+ category: str,
1396
+ context: str,
1397
+ payload: object,
1398
+ ) -> None:
1399
+ if not isinstance(payload, dict):
1400
+ failures.append(Failure(category, f"{context} must include maturity_upgrade_path"))
1401
+ return
1402
+ if payload.get("result") not in {"pass", "block"}:
1403
+ failures.append(Failure(category, f"{context} result must be pass/block"))
1404
+ if payload.get("current") not in {"unadopted", "light", "standard", "strong", "unknown"}:
1405
+ failures.append(Failure(category, f"{context} current maturity must stay within the stable set"))
1406
+ if payload.get("next") not in {None, "light", "standard", "strong"}:
1407
+ failures.append(Failure(category, f"{context} next maturity must stay within the stable set"))
1408
+ if not isinstance(payload.get("missing_inputs"), list):
1409
+ failures.append(Failure(category, f"{context} missing_inputs must be a list"))
1410
+ if not isinstance(payload.get("missing_details"), list):
1411
+ failures.append(Failure(category, f"{context} missing_details must be a list"))
1412
+ if payload.get("fallback_to") not in {None, "adoption", "admission"}:
1413
+ failures.append(Failure(category, f"{context} fallback_to must be stable"))
1414
+ if payload.get("next") is not None and not isinstance(payload.get("upgrade_entry"), str):
1415
+ failures.append(Failure(category, f"{context} upgrade_entry must be present when next maturity exists"))
1416
+ validation_entries = payload.get("validation_entries")
1417
+ if not isinstance(validation_entries, list) or not validation_entries:
1418
+ failures.append(Failure(category, f"{context} validation_entries must be non-empty"))
1419
+
1420
+
1391
1421
  def require_review_record_contract(
1392
1422
  failures: list[Failure],
1393
1423
  *,
@@ -2734,6 +2764,12 @@ def check_daily_execution_cli(root: Path) -> list[Failure]:
2734
2764
  context="`flow resume`",
2735
2765
  payload=payload,
2736
2766
  )
2767
+ require_maturity_upgrade_path(
2768
+ failures,
2769
+ category="daily-execution-cli",
2770
+ context="`flow resume`",
2771
+ payload=payload.get("maturity_upgrade_path"),
2772
+ )
2737
2773
  steps = payload.get("steps")
2738
2774
  if not isinstance(steps, list):
2739
2775
  failures.append(Failure("daily-execution-cli", "`flow resume` must include `steps`"))
@@ -3728,6 +3728,50 @@ def governance_profile_upgrade_payload(
3728
3728
  }
3729
3729
 
3730
3730
 
3731
+ def maturity_upgrade_path(governance_surface: dict[str, Any], target_root: Path) -> dict[str, Any]:
3732
+ control_plane = governance_surface.get("governance_control_plane")
3733
+ maturity = control_plane.get("maturity") if isinstance(control_plane, dict) else None
3734
+ if not isinstance(maturity, dict):
3735
+ return {
3736
+ "result": "block",
3737
+ "current": "unknown",
3738
+ "next": None,
3739
+ "missing_inputs": ["governance_control_plane.maturity"],
3740
+ "missing_details": [],
3741
+ "fallback_to": "admission",
3742
+ "upgrade_entry": None,
3743
+ "validation_entries": [],
3744
+ }
3745
+ current = maturity.get("current")
3746
+ next_level = maturity.get("next")
3747
+ missing_by_level = maturity.get("missing_by_level")
3748
+ missing_details_by_level = maturity.get("missing_details_by_level")
3749
+ missing_inputs = []
3750
+ missing_details = []
3751
+ if isinstance(next_level, str):
3752
+ if isinstance(missing_by_level, dict) and isinstance(missing_by_level.get(next_level), list):
3753
+ missing_inputs = list(missing_by_level[next_level])
3754
+ if isinstance(missing_details_by_level, dict) and isinstance(missing_details_by_level.get(next_level), list):
3755
+ missing_details = list(missing_details_by_level[next_level])
3756
+ return {
3757
+ "result": "pass" if next_level is None else "block",
3758
+ "current": current,
3759
+ "next": next_level,
3760
+ "missing_inputs": missing_inputs,
3761
+ "missing_details": missing_details,
3762
+ "fallback_to": None if next_level is None else "adoption",
3763
+ "upgrade_entry": (
3764
+ f"python3 tools/loom_flow.py governance-profile upgrade --target {target_root} --to {next_level} --dry-run"
3765
+ if isinstance(next_level, str)
3766
+ else None
3767
+ ),
3768
+ "validation_entries": [
3769
+ f"python3 tools/loom_flow.py governance-profile status --target {target_root}",
3770
+ f"python3 tools/loom_flow.py governance-profile upgrade-plan --target {target_root}",
3771
+ ],
3772
+ }
3773
+
3774
+
3731
3775
  def issue_binding_entry(role: str, number: int | None, payload: dict[str, Any] | None, errors: list[str]) -> dict[str, Any]:
3732
3776
  status = "present" if payload is not None else "missing"
3733
3777
  if errors:
@@ -6349,6 +6393,7 @@ def handle_flow(args: argparse.Namespace) -> int:
6349
6393
 
6350
6394
  review_payload: dict[str, Any] | None = None
6351
6395
  governance_surface = build_governance_surface(target_root)
6396
+ upgrade_path = maturity_upgrade_path(governance_surface, target_root)
6352
6397
  repo_interface = governance_surface.get("repo_interface")
6353
6398
  repo_specific_requirements: dict[str, Any] | None = None
6354
6399
 
@@ -6540,6 +6585,9 @@ def handle_flow(args: argparse.Namespace) -> int:
6540
6585
  for message in governance_surface.get("missing_inputs", []):
6541
6586
  if message not in missing_inputs:
6542
6587
  missing_inputs.append(message)
6588
+ for message in upgrade_path.get("missing_inputs", []):
6589
+ if message not in missing_inputs:
6590
+ missing_inputs.append(message)
6543
6591
 
6544
6592
  return emit(
6545
6593
  {
@@ -6558,6 +6606,7 @@ def handle_flow(args: argparse.Namespace) -> int:
6558
6606
  "steps": steps,
6559
6607
  "runtime_state": runtime_state,
6560
6608
  **({"governance_surface": governance_surface} if args.operation == "resume" else {}),
6609
+ **({"maturity_upgrade_path": upgrade_path} if args.operation == "resume" else {}),
6561
6610
  **(
6562
6611
  {
6563
6612
  "workspace": {
@@ -970,6 +970,11 @@ def build_result(target_root: Path, scenario: str, intake: dict[str, object], in
970
970
  ),
971
971
  }[scenario]
972
972
 
973
+ governance_surface = build_governance_surface(
974
+ target_root,
975
+ bootstrap_mode=True,
976
+ scenario_override=scenario,
977
+ )
973
978
  result = {
974
979
  "schema_version": "loom-init-output/v1",
975
980
  "generator": {
@@ -1059,15 +1064,55 @@ def build_result(target_root: Path, scenario: str, intake: dict[str, object], in
1059
1064
  ),
1060
1065
  },
1061
1066
  "runtime_state": runtime_state_payload(target_root),
1062
- "governance_surface": build_governance_surface(
1063
- target_root,
1064
- bootstrap_mode=True,
1065
- scenario_override=scenario,
1066
- ),
1067
+ "governance_surface": governance_surface,
1068
+ "maturity_upgrade_path": init_maturity_upgrade_path(governance_surface),
1067
1069
  }
1068
1070
  return result
1069
1071
 
1070
1072
 
1073
+ def init_maturity_upgrade_path(governance_surface: dict[str, object]) -> dict[str, object]:
1074
+ control_plane = governance_surface.get("governance_control_plane")
1075
+ maturity = control_plane.get("maturity") if isinstance(control_plane, dict) else None
1076
+ if not isinstance(maturity, dict):
1077
+ return {
1078
+ "result": "block",
1079
+ "current": "unknown",
1080
+ "next": None,
1081
+ "missing_inputs": ["governance_control_plane.maturity"],
1082
+ "missing_details": [],
1083
+ "fallback_to": "admission",
1084
+ "upgrade_entry": None,
1085
+ "validation_entries": [],
1086
+ }
1087
+ next_level = maturity.get("next")
1088
+ missing_by_level = maturity.get("missing_by_level")
1089
+ missing_details_by_level = maturity.get("missing_details_by_level")
1090
+ missing_inputs: list[object] = []
1091
+ missing_details: list[object] = []
1092
+ if isinstance(next_level, str):
1093
+ if isinstance(missing_by_level, dict) and isinstance(missing_by_level.get(next_level), list):
1094
+ missing_inputs = list(missing_by_level[next_level])
1095
+ if isinstance(missing_details_by_level, dict) and isinstance(missing_details_by_level.get(next_level), list):
1096
+ missing_details = list(missing_details_by_level[next_level])
1097
+ return {
1098
+ "result": "pass" if next_level is None else "block",
1099
+ "current": maturity.get("current"),
1100
+ "next": next_level,
1101
+ "missing_inputs": missing_inputs,
1102
+ "missing_details": missing_details,
1103
+ "fallback_to": None if next_level is None else "adoption",
1104
+ "upgrade_entry": (
1105
+ f"python3 .loom/bin/loom_flow.py governance-profile upgrade --target . --to {next_level} --dry-run"
1106
+ if isinstance(next_level, str)
1107
+ else None
1108
+ ),
1109
+ "validation_entries": [
1110
+ "python3 .loom/bin/loom_flow.py governance-profile status --target .",
1111
+ "python3 .loom/bin/loom_flow.py governance-profile upgrade-plan --target .",
1112
+ ],
1113
+ }
1114
+
1115
+
1071
1116
  def render_loom_readme(result: dict[str, object]) -> str:
1072
1117
  run = result["run"]
1073
1118
  attach_only = uses_attach_only_path(str(result["recommended_adoption"]["path"]))
@@ -1481,6 +1526,7 @@ def verify_target(target_root: Path, output_path: Path) -> list[str]:
1481
1526
  "initial_artifacts",
1482
1527
  "initial_work_items",
1483
1528
  "runtime_state",
1529
+ "maturity_upgrade_path",
1484
1530
  "validation_and_closing",
1485
1531
  ):
1486
1532
  if key not in result:
@@ -95,6 +95,7 @@ CORE_DOCS = (
95
95
  "docs/evidence/validations/validation-closeout-reconciliation-blocking-gate.md",
96
96
  "docs/evidence/validations/validation-adoption-maturity-upgrade-automation.md",
97
97
  "docs/evidence/validations/validation-adoption-maturity-required-fields.md",
98
+ "docs/evidence/validations/validation-skills-consume-maturity-upgrade-path.md",
98
99
  "docs/evidence/validations/validation-github-profile-binding-orchestration.md",
99
100
  "docs/evidence/validations/validation-github-profile-drift-reconciliation.md",
100
101
  "docs/evidence/validations/validation-github-profile-graphql-budget-guard.md",
@@ -1388,6 +1389,35 @@ def require_governance_upgrade_payload(
1388
1389
  failures.append(Failure(category, f"{context} missing-input actions must include recommended_action"))
1389
1390
 
1390
1391
 
1392
+ def require_maturity_upgrade_path(
1393
+ failures: list[Failure],
1394
+ *,
1395
+ category: str,
1396
+ context: str,
1397
+ payload: object,
1398
+ ) -> None:
1399
+ if not isinstance(payload, dict):
1400
+ failures.append(Failure(category, f"{context} must include maturity_upgrade_path"))
1401
+ return
1402
+ if payload.get("result") not in {"pass", "block"}:
1403
+ failures.append(Failure(category, f"{context} result must be pass/block"))
1404
+ if payload.get("current") not in {"unadopted", "light", "standard", "strong", "unknown"}:
1405
+ failures.append(Failure(category, f"{context} current maturity must stay within the stable set"))
1406
+ if payload.get("next") not in {None, "light", "standard", "strong"}:
1407
+ failures.append(Failure(category, f"{context} next maturity must stay within the stable set"))
1408
+ if not isinstance(payload.get("missing_inputs"), list):
1409
+ failures.append(Failure(category, f"{context} missing_inputs must be a list"))
1410
+ if not isinstance(payload.get("missing_details"), list):
1411
+ failures.append(Failure(category, f"{context} missing_details must be a list"))
1412
+ if payload.get("fallback_to") not in {None, "adoption", "admission"}:
1413
+ failures.append(Failure(category, f"{context} fallback_to must be stable"))
1414
+ if payload.get("next") is not None and not isinstance(payload.get("upgrade_entry"), str):
1415
+ failures.append(Failure(category, f"{context} upgrade_entry must be present when next maturity exists"))
1416
+ validation_entries = payload.get("validation_entries")
1417
+ if not isinstance(validation_entries, list) or not validation_entries:
1418
+ failures.append(Failure(category, f"{context} validation_entries must be non-empty"))
1419
+
1420
+
1391
1421
  def require_review_record_contract(
1392
1422
  failures: list[Failure],
1393
1423
  *,
@@ -2734,6 +2764,12 @@ def check_daily_execution_cli(root: Path) -> list[Failure]:
2734
2764
  context="`flow resume`",
2735
2765
  payload=payload,
2736
2766
  )
2767
+ require_maturity_upgrade_path(
2768
+ failures,
2769
+ category="daily-execution-cli",
2770
+ context="`flow resume`",
2771
+ payload=payload.get("maturity_upgrade_path"),
2772
+ )
2737
2773
  steps = payload.get("steps")
2738
2774
  if not isinstance(steps, list):
2739
2775
  failures.append(Failure("daily-execution-cli", "`flow resume` must include `steps`"))
@@ -3728,6 +3728,50 @@ def governance_profile_upgrade_payload(
3728
3728
  }
3729
3729
 
3730
3730
 
3731
+ def maturity_upgrade_path(governance_surface: dict[str, Any], target_root: Path) -> dict[str, Any]:
3732
+ control_plane = governance_surface.get("governance_control_plane")
3733
+ maturity = control_plane.get("maturity") if isinstance(control_plane, dict) else None
3734
+ if not isinstance(maturity, dict):
3735
+ return {
3736
+ "result": "block",
3737
+ "current": "unknown",
3738
+ "next": None,
3739
+ "missing_inputs": ["governance_control_plane.maturity"],
3740
+ "missing_details": [],
3741
+ "fallback_to": "admission",
3742
+ "upgrade_entry": None,
3743
+ "validation_entries": [],
3744
+ }
3745
+ current = maturity.get("current")
3746
+ next_level = maturity.get("next")
3747
+ missing_by_level = maturity.get("missing_by_level")
3748
+ missing_details_by_level = maturity.get("missing_details_by_level")
3749
+ missing_inputs = []
3750
+ missing_details = []
3751
+ if isinstance(next_level, str):
3752
+ if isinstance(missing_by_level, dict) and isinstance(missing_by_level.get(next_level), list):
3753
+ missing_inputs = list(missing_by_level[next_level])
3754
+ if isinstance(missing_details_by_level, dict) and isinstance(missing_details_by_level.get(next_level), list):
3755
+ missing_details = list(missing_details_by_level[next_level])
3756
+ return {
3757
+ "result": "pass" if next_level is None else "block",
3758
+ "current": current,
3759
+ "next": next_level,
3760
+ "missing_inputs": missing_inputs,
3761
+ "missing_details": missing_details,
3762
+ "fallback_to": None if next_level is None else "adoption",
3763
+ "upgrade_entry": (
3764
+ f"python3 tools/loom_flow.py governance-profile upgrade --target {target_root} --to {next_level} --dry-run"
3765
+ if isinstance(next_level, str)
3766
+ else None
3767
+ ),
3768
+ "validation_entries": [
3769
+ f"python3 tools/loom_flow.py governance-profile status --target {target_root}",
3770
+ f"python3 tools/loom_flow.py governance-profile upgrade-plan --target {target_root}",
3771
+ ],
3772
+ }
3773
+
3774
+
3731
3775
  def issue_binding_entry(role: str, number: int | None, payload: dict[str, Any] | None, errors: list[str]) -> dict[str, Any]:
3732
3776
  status = "present" if payload is not None else "missing"
3733
3777
  if errors:
@@ -6349,6 +6393,7 @@ def handle_flow(args: argparse.Namespace) -> int:
6349
6393
 
6350
6394
  review_payload: dict[str, Any] | None = None
6351
6395
  governance_surface = build_governance_surface(target_root)
6396
+ upgrade_path = maturity_upgrade_path(governance_surface, target_root)
6352
6397
  repo_interface = governance_surface.get("repo_interface")
6353
6398
  repo_specific_requirements: dict[str, Any] | None = None
6354
6399
 
@@ -6540,6 +6585,9 @@ def handle_flow(args: argparse.Namespace) -> int:
6540
6585
  for message in governance_surface.get("missing_inputs", []):
6541
6586
  if message not in missing_inputs:
6542
6587
  missing_inputs.append(message)
6588
+ for message in upgrade_path.get("missing_inputs", []):
6589
+ if message not in missing_inputs:
6590
+ missing_inputs.append(message)
6543
6591
 
6544
6592
  return emit(
6545
6593
  {
@@ -6558,6 +6606,7 @@ def handle_flow(args: argparse.Namespace) -> int:
6558
6606
  "steps": steps,
6559
6607
  "runtime_state": runtime_state,
6560
6608
  **({"governance_surface": governance_surface} if args.operation == "resume" else {}),
6609
+ **({"maturity_upgrade_path": upgrade_path} if args.operation == "resume" else {}),
6561
6610
  **(
6562
6611
  {
6563
6612
  "workspace": {