@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.
- package/package.json +1 -1
- package/payload/manifest.json +62 -62
- package/payload/plugin/loom/skills/shared/scripts/loom_check.py +36 -0
- package/payload/plugin/loom/skills/shared/scripts/loom_flow.py +49 -0
- package/payload/plugin/loom/skills/shared/scripts/loom_init.py +51 -5
- package/payload/skills/loom-adopt/.loom-runtime/shared/scripts/loom_check.py +36 -0
- package/payload/skills/loom-adopt/.loom-runtime/shared/scripts/loom_flow.py +49 -0
- package/payload/skills/loom-adopt/.loom-runtime/shared/scripts/loom_init.py +51 -5
- package/payload/skills/loom-handoff/.loom-runtime/shared/scripts/loom_check.py +36 -0
- package/payload/skills/loom-handoff/.loom-runtime/shared/scripts/loom_flow.py +49 -0
- package/payload/skills/loom-handoff/.loom-runtime/shared/scripts/loom_init.py +51 -5
- package/payload/skills/loom-init/.loom-runtime/shared/scripts/loom_check.py +36 -0
- package/payload/skills/loom-init/.loom-runtime/shared/scripts/loom_flow.py +49 -0
- package/payload/skills/loom-init/.loom-runtime/shared/scripts/loom_init.py +51 -5
- package/payload/skills/loom-merge-ready/.loom-runtime/shared/scripts/loom_check.py +36 -0
- package/payload/skills/loom-merge-ready/.loom-runtime/shared/scripts/loom_flow.py +49 -0
- package/payload/skills/loom-merge-ready/.loom-runtime/shared/scripts/loom_init.py +51 -5
- package/payload/skills/loom-pre-review/.loom-runtime/shared/scripts/loom_check.py +36 -0
- package/payload/skills/loom-pre-review/.loom-runtime/shared/scripts/loom_flow.py +49 -0
- package/payload/skills/loom-pre-review/.loom-runtime/shared/scripts/loom_init.py +51 -5
- package/payload/skills/loom-resume/.loom-runtime/shared/scripts/loom_check.py +36 -0
- package/payload/skills/loom-resume/.loom-runtime/shared/scripts/loom_flow.py +49 -0
- package/payload/skills/loom-resume/.loom-runtime/shared/scripts/loom_init.py +51 -5
- package/payload/skills/loom-retire/.loom-runtime/shared/scripts/loom_check.py +36 -0
- package/payload/skills/loom-retire/.loom-runtime/shared/scripts/loom_flow.py +49 -0
- package/payload/skills/loom-retire/.loom-runtime/shared/scripts/loom_init.py +51 -5
- package/payload/skills/loom-review/.loom-runtime/shared/scripts/loom_check.py +36 -0
- package/payload/skills/loom-review/.loom-runtime/shared/scripts/loom_flow.py +49 -0
- package/payload/skills/loom-review/.loom-runtime/shared/scripts/loom_init.py +51 -5
- package/payload/skills/loom-spec-review/.loom-runtime/shared/scripts/loom_check.py +36 -0
- package/payload/skills/loom-spec-review/.loom-runtime/shared/scripts/loom_flow.py +49 -0
- package/payload/skills/loom-spec-review/.loom-runtime/shared/scripts/loom_init.py +51 -5
package/package.json
CHANGED
package/payload/manifest.json
CHANGED
|
@@ -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": "
|
|
5
|
+
"source_commit": "f25d0954fff0ab7dcf7234f89eb001bc08a0c9df",
|
|
6
6
|
"source_ref": "main",
|
|
7
|
-
"built_at": "2026-04-25T13:
|
|
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":
|
|
632
|
-
"sha256": "
|
|
631
|
+
"bytes": 273789,
|
|
632
|
+
"sha256": "2d0a345221eeca04cef5e635b84f059ce6cf4b9316f4a210360237597406ae2e"
|
|
633
633
|
},
|
|
634
634
|
{
|
|
635
635
|
"path": "plugin/loom/skills/shared/scripts/loom_flow.py",
|
|
636
|
-
"bytes":
|
|
637
|
-
"sha256": "
|
|
636
|
+
"bytes": 290536,
|
|
637
|
+
"sha256": "69c44efb623eb26aadda9141ecb73eea036444c1023b833da7f9cbb709f68428"
|
|
638
638
|
},
|
|
639
639
|
{
|
|
640
640
|
"path": "plugin/loom/skills/shared/scripts/loom_init.py",
|
|
641
|
-
"bytes":
|
|
642
|
-
"sha256": "
|
|
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":
|
|
1217
|
-
"sha256": "
|
|
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":
|
|
1222
|
-
"sha256": "
|
|
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":
|
|
1227
|
-
"sha256": "
|
|
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":
|
|
1832
|
-
"sha256": "
|
|
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":
|
|
1837
|
-
"sha256": "
|
|
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":
|
|
1842
|
-
"sha256": "
|
|
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":
|
|
2447
|
-
"sha256": "
|
|
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":
|
|
2452
|
-
"sha256": "
|
|
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":
|
|
2457
|
-
"sha256": "
|
|
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":
|
|
3067
|
-
"sha256": "
|
|
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":
|
|
3072
|
-
"sha256": "
|
|
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":
|
|
3077
|
-
"sha256": "
|
|
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":
|
|
3682
|
-
"sha256": "
|
|
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":
|
|
3687
|
-
"sha256": "
|
|
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":
|
|
3692
|
-
"sha256": "
|
|
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":
|
|
4297
|
-
"sha256": "
|
|
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":
|
|
4302
|
-
"sha256": "
|
|
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":
|
|
4307
|
-
"sha256": "
|
|
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":
|
|
4912
|
-
"sha256": "
|
|
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":
|
|
4917
|
-
"sha256": "
|
|
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":
|
|
4922
|
-
"sha256": "
|
|
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":
|
|
5527
|
-
"sha256": "
|
|
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":
|
|
5532
|
-
"sha256": "
|
|
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":
|
|
5537
|
-
"sha256": "
|
|
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":
|
|
6142
|
-
"sha256": "
|
|
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":
|
|
6147
|
-
"sha256": "
|
|
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":
|
|
6152
|
-
"sha256": "
|
|
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":
|
|
1063
|
-
|
|
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": {
|