@mc-and-his-agents/loom-installer 0.1.90 → 0.1.91
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 +45 -45
- package/payload/plugin/loom/skills/loom-adopt/.loom-runtime/shared/scripts/loom_check.py +139 -1
- package/payload/plugin/loom/skills/loom-build/.loom-runtime/shared/scripts/loom_check.py +139 -1
- package/payload/plugin/loom/skills/loom-handoff/.loom-runtime/shared/scripts/loom_check.py +139 -1
- package/payload/plugin/loom/skills/loom-init/.loom-runtime/shared/scripts/loom_check.py +139 -1
- package/payload/plugin/loom/skills/loom-merge-ready/.loom-runtime/shared/scripts/loom_check.py +139 -1
- package/payload/plugin/loom/skills/loom-pre-review/.loom-runtime/shared/scripts/loom_check.py +139 -1
- package/payload/plugin/loom/skills/loom-resume/.loom-runtime/shared/scripts/loom_check.py +139 -1
- package/payload/plugin/loom/skills/loom-retire/.loom-runtime/shared/scripts/loom_check.py +139 -1
- package/payload/plugin/loom/skills/loom-review/.loom-runtime/shared/scripts/loom_check.py +139 -1
- package/payload/plugin/loom/skills/loom-spec-review/.loom-runtime/shared/scripts/loom_check.py +139 -1
- package/payload/plugin/loom/skills/shared/scripts/loom_check.py +139 -1
- package/payload/skills/loom-adopt/.loom-runtime/shared/scripts/loom_check.py +139 -1
- package/payload/skills/loom-build/.loom-runtime/shared/scripts/loom_check.py +139 -1
- package/payload/skills/loom-handoff/.loom-runtime/shared/scripts/loom_check.py +139 -1
- package/payload/skills/loom-init/.loom-runtime/shared/scripts/loom_check.py +139 -1
- package/payload/skills/loom-merge-ready/.loom-runtime/shared/scripts/loom_check.py +139 -1
- package/payload/skills/loom-pre-review/.loom-runtime/shared/scripts/loom_check.py +139 -1
- package/payload/skills/loom-resume/.loom-runtime/shared/scripts/loom_check.py +139 -1
- package/payload/skills/loom-retire/.loom-runtime/shared/scripts/loom_check.py +139 -1
- package/payload/skills/loom-review/.loom-runtime/shared/scripts/loom_check.py +139 -1
- package/payload/skills/loom-spec-review/.loom-runtime/shared/scripts/loom_check.py +139 -1
package/package.json
CHANGED
package/payload/manifest.json
CHANGED
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
"schema_version": "loom-installer-payload/v1",
|
|
3
3
|
"loom_version": "v0.9.0",
|
|
4
4
|
"source_repository": "https://github.com/MC-and-his-Agents/Loom",
|
|
5
|
-
"source_commit": "
|
|
5
|
+
"source_commit": "c54096e7bc9d501d8d0021081b3c499b148063e1",
|
|
6
6
|
"source_ref": "main",
|
|
7
|
-
"built_at": "2026-05-
|
|
7
|
+
"built_at": "2026-05-09T23:13:49+08:00",
|
|
8
8
|
"version_context": {
|
|
9
9
|
"repo_version": "v0.9.0",
|
|
10
|
-
"installer_package_version": "0.1.
|
|
10
|
+
"installer_package_version": "0.1.91",
|
|
11
11
|
"plugin_surface_version": "0.4.0",
|
|
12
12
|
"host_adapter_version": "1.0.0",
|
|
13
13
|
"skills_registry_version": "1.5.0",
|
|
@@ -808,8 +808,8 @@
|
|
|
808
808
|
},
|
|
809
809
|
{
|
|
810
810
|
"path": "plugin/loom/skills/loom-adopt/.loom-runtime/shared/scripts/loom_check.py",
|
|
811
|
-
"bytes":
|
|
812
|
-
"sha256": "
|
|
811
|
+
"bytes": 623808,
|
|
812
|
+
"sha256": "4d9bfc198f19e5491d8eb72f1eac3a0360450b4be0b70ae2663a9c40ca21dc0b"
|
|
813
813
|
},
|
|
814
814
|
{
|
|
815
815
|
"path": "plugin/loom/skills/loom-adopt/.loom-runtime/shared/scripts/loom_flow.py",
|
|
@@ -1533,8 +1533,8 @@
|
|
|
1533
1533
|
},
|
|
1534
1534
|
{
|
|
1535
1535
|
"path": "plugin/loom/skills/loom-build/.loom-runtime/shared/scripts/loom_check.py",
|
|
1536
|
-
"bytes":
|
|
1537
|
-
"sha256": "
|
|
1536
|
+
"bytes": 623808,
|
|
1537
|
+
"sha256": "4d9bfc198f19e5491d8eb72f1eac3a0360450b4be0b70ae2663a9c40ca21dc0b"
|
|
1538
1538
|
},
|
|
1539
1539
|
{
|
|
1540
1540
|
"path": "plugin/loom/skills/loom-build/.loom-runtime/shared/scripts/loom_flow.py",
|
|
@@ -2258,8 +2258,8 @@
|
|
|
2258
2258
|
},
|
|
2259
2259
|
{
|
|
2260
2260
|
"path": "plugin/loom/skills/loom-handoff/.loom-runtime/shared/scripts/loom_check.py",
|
|
2261
|
-
"bytes":
|
|
2262
|
-
"sha256": "
|
|
2261
|
+
"bytes": 623808,
|
|
2262
|
+
"sha256": "4d9bfc198f19e5491d8eb72f1eac3a0360450b4be0b70ae2663a9c40ca21dc0b"
|
|
2263
2263
|
},
|
|
2264
2264
|
{
|
|
2265
2265
|
"path": "plugin/loom/skills/loom-handoff/.loom-runtime/shared/scripts/loom_flow.py",
|
|
@@ -2983,8 +2983,8 @@
|
|
|
2983
2983
|
},
|
|
2984
2984
|
{
|
|
2985
2985
|
"path": "plugin/loom/skills/loom-init/.loom-runtime/shared/scripts/loom_check.py",
|
|
2986
|
-
"bytes":
|
|
2987
|
-
"sha256": "
|
|
2986
|
+
"bytes": 623808,
|
|
2987
|
+
"sha256": "4d9bfc198f19e5491d8eb72f1eac3a0360450b4be0b70ae2663a9c40ca21dc0b"
|
|
2988
2988
|
},
|
|
2989
2989
|
{
|
|
2990
2990
|
"path": "plugin/loom/skills/loom-init/.loom-runtime/shared/scripts/loom_flow.py",
|
|
@@ -3713,8 +3713,8 @@
|
|
|
3713
3713
|
},
|
|
3714
3714
|
{
|
|
3715
3715
|
"path": "plugin/loom/skills/loom-merge-ready/.loom-runtime/shared/scripts/loom_check.py",
|
|
3716
|
-
"bytes":
|
|
3717
|
-
"sha256": "
|
|
3716
|
+
"bytes": 623808,
|
|
3717
|
+
"sha256": "4d9bfc198f19e5491d8eb72f1eac3a0360450b4be0b70ae2663a9c40ca21dc0b"
|
|
3718
3718
|
},
|
|
3719
3719
|
{
|
|
3720
3720
|
"path": "plugin/loom/skills/loom-merge-ready/.loom-runtime/shared/scripts/loom_flow.py",
|
|
@@ -4438,8 +4438,8 @@
|
|
|
4438
4438
|
},
|
|
4439
4439
|
{
|
|
4440
4440
|
"path": "plugin/loom/skills/loom-pre-review/.loom-runtime/shared/scripts/loom_check.py",
|
|
4441
|
-
"bytes":
|
|
4442
|
-
"sha256": "
|
|
4441
|
+
"bytes": 623808,
|
|
4442
|
+
"sha256": "4d9bfc198f19e5491d8eb72f1eac3a0360450b4be0b70ae2663a9c40ca21dc0b"
|
|
4443
4443
|
},
|
|
4444
4444
|
{
|
|
4445
4445
|
"path": "plugin/loom/skills/loom-pre-review/.loom-runtime/shared/scripts/loom_flow.py",
|
|
@@ -5163,8 +5163,8 @@
|
|
|
5163
5163
|
},
|
|
5164
5164
|
{
|
|
5165
5165
|
"path": "plugin/loom/skills/loom-resume/.loom-runtime/shared/scripts/loom_check.py",
|
|
5166
|
-
"bytes":
|
|
5167
|
-
"sha256": "
|
|
5166
|
+
"bytes": 623808,
|
|
5167
|
+
"sha256": "4d9bfc198f19e5491d8eb72f1eac3a0360450b4be0b70ae2663a9c40ca21dc0b"
|
|
5168
5168
|
},
|
|
5169
5169
|
{
|
|
5170
5170
|
"path": "plugin/loom/skills/loom-resume/.loom-runtime/shared/scripts/loom_flow.py",
|
|
@@ -5888,8 +5888,8 @@
|
|
|
5888
5888
|
},
|
|
5889
5889
|
{
|
|
5890
5890
|
"path": "plugin/loom/skills/loom-retire/.loom-runtime/shared/scripts/loom_check.py",
|
|
5891
|
-
"bytes":
|
|
5892
|
-
"sha256": "
|
|
5891
|
+
"bytes": 623808,
|
|
5892
|
+
"sha256": "4d9bfc198f19e5491d8eb72f1eac3a0360450b4be0b70ae2663a9c40ca21dc0b"
|
|
5893
5893
|
},
|
|
5894
5894
|
{
|
|
5895
5895
|
"path": "plugin/loom/skills/loom-retire/.loom-runtime/shared/scripts/loom_flow.py",
|
|
@@ -6613,8 +6613,8 @@
|
|
|
6613
6613
|
},
|
|
6614
6614
|
{
|
|
6615
6615
|
"path": "plugin/loom/skills/loom-review/.loom-runtime/shared/scripts/loom_check.py",
|
|
6616
|
-
"bytes":
|
|
6617
|
-
"sha256": "
|
|
6616
|
+
"bytes": 623808,
|
|
6617
|
+
"sha256": "4d9bfc198f19e5491d8eb72f1eac3a0360450b4be0b70ae2663a9c40ca21dc0b"
|
|
6618
6618
|
},
|
|
6619
6619
|
{
|
|
6620
6620
|
"path": "plugin/loom/skills/loom-review/.loom-runtime/shared/scripts/loom_flow.py",
|
|
@@ -7338,8 +7338,8 @@
|
|
|
7338
7338
|
},
|
|
7339
7339
|
{
|
|
7340
7340
|
"path": "plugin/loom/skills/loom-spec-review/.loom-runtime/shared/scripts/loom_check.py",
|
|
7341
|
-
"bytes":
|
|
7342
|
-
"sha256": "
|
|
7341
|
+
"bytes": 623808,
|
|
7342
|
+
"sha256": "4d9bfc198f19e5491d8eb72f1eac3a0360450b4be0b70ae2663a9c40ca21dc0b"
|
|
7343
7343
|
},
|
|
7344
7344
|
{
|
|
7345
7345
|
"path": "plugin/loom/skills/loom-spec-review/.loom-runtime/shared/scripts/loom_flow.py",
|
|
@@ -7748,8 +7748,8 @@
|
|
|
7748
7748
|
},
|
|
7749
7749
|
{
|
|
7750
7750
|
"path": "plugin/loom/skills/shared/scripts/loom_check.py",
|
|
7751
|
-
"bytes":
|
|
7752
|
-
"sha256": "
|
|
7751
|
+
"bytes": 623808,
|
|
7752
|
+
"sha256": "4d9bfc198f19e5491d8eb72f1eac3a0360450b4be0b70ae2663a9c40ca21dc0b"
|
|
7753
7753
|
},
|
|
7754
7754
|
{
|
|
7755
7755
|
"path": "plugin/loom/skills/shared/scripts/loom_flow.py",
|
|
@@ -8438,8 +8438,8 @@
|
|
|
8438
8438
|
},
|
|
8439
8439
|
{
|
|
8440
8440
|
"path": "skills/loom-adopt/.loom-runtime/shared/scripts/loom_check.py",
|
|
8441
|
-
"bytes":
|
|
8442
|
-
"sha256": "
|
|
8441
|
+
"bytes": 623808,
|
|
8442
|
+
"sha256": "4d9bfc198f19e5491d8eb72f1eac3a0360450b4be0b70ae2663a9c40ca21dc0b"
|
|
8443
8443
|
},
|
|
8444
8444
|
{
|
|
8445
8445
|
"path": "skills/loom-adopt/.loom-runtime/shared/scripts/loom_flow.py",
|
|
@@ -9163,8 +9163,8 @@
|
|
|
9163
9163
|
},
|
|
9164
9164
|
{
|
|
9165
9165
|
"path": "skills/loom-build/.loom-runtime/shared/scripts/loom_check.py",
|
|
9166
|
-
"bytes":
|
|
9167
|
-
"sha256": "
|
|
9166
|
+
"bytes": 623808,
|
|
9167
|
+
"sha256": "4d9bfc198f19e5491d8eb72f1eac3a0360450b4be0b70ae2663a9c40ca21dc0b"
|
|
9168
9168
|
},
|
|
9169
9169
|
{
|
|
9170
9170
|
"path": "skills/loom-build/.loom-runtime/shared/scripts/loom_flow.py",
|
|
@@ -9888,8 +9888,8 @@
|
|
|
9888
9888
|
},
|
|
9889
9889
|
{
|
|
9890
9890
|
"path": "skills/loom-handoff/.loom-runtime/shared/scripts/loom_check.py",
|
|
9891
|
-
"bytes":
|
|
9892
|
-
"sha256": "
|
|
9891
|
+
"bytes": 623808,
|
|
9892
|
+
"sha256": "4d9bfc198f19e5491d8eb72f1eac3a0360450b4be0b70ae2663a9c40ca21dc0b"
|
|
9893
9893
|
},
|
|
9894
9894
|
{
|
|
9895
9895
|
"path": "skills/loom-handoff/.loom-runtime/shared/scripts/loom_flow.py",
|
|
@@ -10613,8 +10613,8 @@
|
|
|
10613
10613
|
},
|
|
10614
10614
|
{
|
|
10615
10615
|
"path": "skills/loom-init/.loom-runtime/shared/scripts/loom_check.py",
|
|
10616
|
-
"bytes":
|
|
10617
|
-
"sha256": "
|
|
10616
|
+
"bytes": 623808,
|
|
10617
|
+
"sha256": "4d9bfc198f19e5491d8eb72f1eac3a0360450b4be0b70ae2663a9c40ca21dc0b"
|
|
10618
10618
|
},
|
|
10619
10619
|
{
|
|
10620
10620
|
"path": "skills/loom-init/.loom-runtime/shared/scripts/loom_flow.py",
|
|
@@ -11343,8 +11343,8 @@
|
|
|
11343
11343
|
},
|
|
11344
11344
|
{
|
|
11345
11345
|
"path": "skills/loom-merge-ready/.loom-runtime/shared/scripts/loom_check.py",
|
|
11346
|
-
"bytes":
|
|
11347
|
-
"sha256": "
|
|
11346
|
+
"bytes": 623808,
|
|
11347
|
+
"sha256": "4d9bfc198f19e5491d8eb72f1eac3a0360450b4be0b70ae2663a9c40ca21dc0b"
|
|
11348
11348
|
},
|
|
11349
11349
|
{
|
|
11350
11350
|
"path": "skills/loom-merge-ready/.loom-runtime/shared/scripts/loom_flow.py",
|
|
@@ -12068,8 +12068,8 @@
|
|
|
12068
12068
|
},
|
|
12069
12069
|
{
|
|
12070
12070
|
"path": "skills/loom-pre-review/.loom-runtime/shared/scripts/loom_check.py",
|
|
12071
|
-
"bytes":
|
|
12072
|
-
"sha256": "
|
|
12071
|
+
"bytes": 623808,
|
|
12072
|
+
"sha256": "4d9bfc198f19e5491d8eb72f1eac3a0360450b4be0b70ae2663a9c40ca21dc0b"
|
|
12073
12073
|
},
|
|
12074
12074
|
{
|
|
12075
12075
|
"path": "skills/loom-pre-review/.loom-runtime/shared/scripts/loom_flow.py",
|
|
@@ -12793,8 +12793,8 @@
|
|
|
12793
12793
|
},
|
|
12794
12794
|
{
|
|
12795
12795
|
"path": "skills/loom-resume/.loom-runtime/shared/scripts/loom_check.py",
|
|
12796
|
-
"bytes":
|
|
12797
|
-
"sha256": "
|
|
12796
|
+
"bytes": 623808,
|
|
12797
|
+
"sha256": "4d9bfc198f19e5491d8eb72f1eac3a0360450b4be0b70ae2663a9c40ca21dc0b"
|
|
12798
12798
|
},
|
|
12799
12799
|
{
|
|
12800
12800
|
"path": "skills/loom-resume/.loom-runtime/shared/scripts/loom_flow.py",
|
|
@@ -13518,8 +13518,8 @@
|
|
|
13518
13518
|
},
|
|
13519
13519
|
{
|
|
13520
13520
|
"path": "skills/loom-retire/.loom-runtime/shared/scripts/loom_check.py",
|
|
13521
|
-
"bytes":
|
|
13522
|
-
"sha256": "
|
|
13521
|
+
"bytes": 623808,
|
|
13522
|
+
"sha256": "4d9bfc198f19e5491d8eb72f1eac3a0360450b4be0b70ae2663a9c40ca21dc0b"
|
|
13523
13523
|
},
|
|
13524
13524
|
{
|
|
13525
13525
|
"path": "skills/loom-retire/.loom-runtime/shared/scripts/loom_flow.py",
|
|
@@ -14243,8 +14243,8 @@
|
|
|
14243
14243
|
},
|
|
14244
14244
|
{
|
|
14245
14245
|
"path": "skills/loom-review/.loom-runtime/shared/scripts/loom_check.py",
|
|
14246
|
-
"bytes":
|
|
14247
|
-
"sha256": "
|
|
14246
|
+
"bytes": 623808,
|
|
14247
|
+
"sha256": "4d9bfc198f19e5491d8eb72f1eac3a0360450b4be0b70ae2663a9c40ca21dc0b"
|
|
14248
14248
|
},
|
|
14249
14249
|
{
|
|
14250
14250
|
"path": "skills/loom-review/.loom-runtime/shared/scripts/loom_flow.py",
|
|
@@ -14968,8 +14968,8 @@
|
|
|
14968
14968
|
},
|
|
14969
14969
|
{
|
|
14970
14970
|
"path": "skills/loom-spec-review/.loom-runtime/shared/scripts/loom_check.py",
|
|
14971
|
-
"bytes":
|
|
14972
|
-
"sha256": "
|
|
14971
|
+
"bytes": 623808,
|
|
14972
|
+
"sha256": "4d9bfc198f19e5491d8eb72f1eac3a0360450b4be0b70ae2663a9c40ca21dc0b"
|
|
14973
14973
|
},
|
|
14974
14974
|
{
|
|
14975
14975
|
"path": "skills/loom-spec-review/.loom-runtime/shared/scripts/loom_flow.py",
|
|
@@ -11188,6 +11188,143 @@ def check_dynamic_tool_live_availability_contract(root: Path) -> list[Failure]:
|
|
|
11188
11188
|
return failures
|
|
11189
11189
|
|
|
11190
11190
|
|
|
11191
|
+
def check_live_validation_only_guardrail_contract(root: Path) -> list[Failure]:
|
|
11192
|
+
failures: list[Failure] = []
|
|
11193
|
+
|
|
11194
|
+
def write_json_local(path: Path, payload: object) -> None:
|
|
11195
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
11196
|
+
path.write_text(json.dumps(payload, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
|
|
11197
|
+
|
|
11198
|
+
docs = {
|
|
11199
|
+
"docs/evidence/v0.10.0-release-readiness.md": [
|
|
11200
|
+
"validation-only shadow parity mismatch",
|
|
11201
|
+
"explicit blocking opt-in",
|
|
11202
|
+
"owner、fallback、override path、authority-of-truth 与 live evidence",
|
|
11203
|
+
"单个 adopted repo smoke",
|
|
11204
|
+
],
|
|
11205
|
+
"docs/evidence/live-smoke-profile.md": [
|
|
11206
|
+
"--include-blocking-shadow",
|
|
11207
|
+
"not sufficient blocking-upgrade evidence on its own",
|
|
11208
|
+
"不得把 `orchestration-live` 提升为普通 PR 的默认 blocking gate",
|
|
11209
|
+
],
|
|
11210
|
+
"docs/methodology/harness/closeout-gate.md": [
|
|
11211
|
+
"shadow parity` 默认不进入 closeout 阻断面",
|
|
11212
|
+
"owner、fallback、override path 与 authority-of-truth",
|
|
11213
|
+
],
|
|
11214
|
+
"docs/evidence/validations/validation-v0.10-live-validation-only-guardrail.md": [
|
|
11215
|
+
"validation-only shadow parity mismatch returns `warn`",
|
|
11216
|
+
"explicit blocking opt-in",
|
|
11217
|
+
"single adopted repo live smoke run is not sufficient",
|
|
11218
|
+
],
|
|
11219
|
+
}
|
|
11220
|
+
for relative, anchors in docs.items():
|
|
11221
|
+
path = root / relative
|
|
11222
|
+
try:
|
|
11223
|
+
text = path.read_text(encoding="utf-8")
|
|
11224
|
+
except OSError as exc:
|
|
11225
|
+
failures.append(Failure("live-validation-only-guardrail", f"`{relative}` is unreadable: {exc}"))
|
|
11226
|
+
continue
|
|
11227
|
+
for anchor in anchors:
|
|
11228
|
+
if anchor not in text:
|
|
11229
|
+
failures.append(Failure("live-validation-only-guardrail", f"`{relative}` must mention `{anchor}`"))
|
|
11230
|
+
|
|
11231
|
+
missing_target = Path("/tmp/loom-missing-live-target")
|
|
11232
|
+
unavailable_payload, error = load_command_json(
|
|
11233
|
+
root,
|
|
11234
|
+
["python3", "tools/loom_flow.py", "live-smoke", "run", "--target", str(missing_target), "--item", "INIT-0001"],
|
|
11235
|
+
)
|
|
11236
|
+
if error:
|
|
11237
|
+
failures.append(Failure("live-validation-only-guardrail", f"`live-smoke run` unavailable sample failed: {error}"))
|
|
11238
|
+
else:
|
|
11239
|
+
require_live_smoke_payload(
|
|
11240
|
+
failures,
|
|
11241
|
+
category="live-validation-only-guardrail",
|
|
11242
|
+
context="unavailable-live-smoke-guardrail",
|
|
11243
|
+
payload=unavailable_payload,
|
|
11244
|
+
expected_operation="run",
|
|
11245
|
+
)
|
|
11246
|
+
if not isinstance(unavailable_payload, dict) or unavailable_payload.get("result") != "warn":
|
|
11247
|
+
failures.append(Failure("live-validation-only-guardrail", "missing target live smoke must warn"))
|
|
11248
|
+
|
|
11249
|
+
dry_run_payload, error = load_command_json(
|
|
11250
|
+
root,
|
|
11251
|
+
[
|
|
11252
|
+
"python3",
|
|
11253
|
+
"tools/loom_flow.py",
|
|
11254
|
+
"live-smoke",
|
|
11255
|
+
"run",
|
|
11256
|
+
"--target",
|
|
11257
|
+
str(root / "examples/new-project"),
|
|
11258
|
+
"--dry-run",
|
|
11259
|
+
"--include-blocking-shadow",
|
|
11260
|
+
],
|
|
11261
|
+
)
|
|
11262
|
+
if error:
|
|
11263
|
+
failures.append(Failure("live-validation-only-guardrail", f"`live-smoke run --include-blocking-shadow --dry-run` failed: {error}"))
|
|
11264
|
+
else:
|
|
11265
|
+
require_live_smoke_payload(
|
|
11266
|
+
failures,
|
|
11267
|
+
category="live-validation-only-guardrail",
|
|
11268
|
+
context="dry-run-live-smoke-guardrail",
|
|
11269
|
+
payload=dry_run_payload,
|
|
11270
|
+
expected_operation="run",
|
|
11271
|
+
)
|
|
11272
|
+
command_plan = dry_run_payload.get("command_plan")
|
|
11273
|
+
if not isinstance(command_plan, list):
|
|
11274
|
+
failures.append(Failure("live-validation-only-guardrail", "dry-run live smoke must include command_plan"))
|
|
11275
|
+
else:
|
|
11276
|
+
blocking_steps = [step for step in command_plan if isinstance(step, dict) and step.get("id") == "shadow-parity-blocking"]
|
|
11277
|
+
if len(blocking_steps) != 1:
|
|
11278
|
+
failures.append(Failure("live-validation-only-guardrail", "dry-run live smoke must include exactly one explicit blocking shadow step when requested"))
|
|
11279
|
+
elif "not sufficient blocking-upgrade evidence on its own" not in str(blocking_steps[0].get("description") or ""):
|
|
11280
|
+
failures.append(Failure("live-validation-only-guardrail", "blocking shadow step must say it is not sufficient blocking-upgrade evidence on its own"))
|
|
11281
|
+
|
|
11282
|
+
example_target = root / "examples/new-project"
|
|
11283
|
+
with tempfile.TemporaryDirectory(prefix="loom-live-validation-guardrail-") as tmp:
|
|
11284
|
+
mismatch_target = Path(tmp) / "shadow-mismatch"
|
|
11285
|
+
shutil.copytree(example_target, mismatch_target)
|
|
11286
|
+
shadow_payload = load_json_file(mismatch_target / ".loom/shadow/review-repo.json")
|
|
11287
|
+
if isinstance(shadow_payload, dict):
|
|
11288
|
+
shadow_payload["source_sha256"] = {"native/status/review.json": "0" * 64}
|
|
11289
|
+
write_json_local(mismatch_target / ".loom/shadow/review-repo.json", shadow_payload)
|
|
11290
|
+
|
|
11291
|
+
warn_payload, warn_error = load_command_json(
|
|
11292
|
+
root,
|
|
11293
|
+
["python3", "tools/loom_flow.py", "shadow-parity", "--target", str(mismatch_target), "--surface", "review"],
|
|
11294
|
+
)
|
|
11295
|
+
if warn_error:
|
|
11296
|
+
failures.append(Failure("live-validation-only-guardrail", f"`shadow-parity` validation-only mismatch sample failed: {warn_error}"))
|
|
11297
|
+
else:
|
|
11298
|
+
require_shadow_parity_payload(
|
|
11299
|
+
failures,
|
|
11300
|
+
category="live-validation-only-guardrail",
|
|
11301
|
+
context="validation-only-shadow-mismatch",
|
|
11302
|
+
payload=warn_payload,
|
|
11303
|
+
expected_reports=1,
|
|
11304
|
+
)
|
|
11305
|
+
if not isinstance(warn_payload, dict) or warn_payload.get("result") != "warn":
|
|
11306
|
+
failures.append(Failure("live-validation-only-guardrail", "validation-only shadow mismatch must warn"))
|
|
11307
|
+
|
|
11308
|
+
block_payload, block_error = load_command_json(
|
|
11309
|
+
root,
|
|
11310
|
+
["python3", "tools/loom_flow.py", "shadow-parity", "--target", str(mismatch_target), "--surface", "review", "--blocking"],
|
|
11311
|
+
)
|
|
11312
|
+
if block_error:
|
|
11313
|
+
failures.append(Failure("live-validation-only-guardrail", f"`shadow-parity --blocking` mismatch sample failed: {block_error}"))
|
|
11314
|
+
else:
|
|
11315
|
+
require_shadow_parity_payload(
|
|
11316
|
+
failures,
|
|
11317
|
+
category="live-validation-only-guardrail",
|
|
11318
|
+
context="blocking-shadow-mismatch",
|
|
11319
|
+
payload=block_payload,
|
|
11320
|
+
expected_reports=1,
|
|
11321
|
+
)
|
|
11322
|
+
if not isinstance(block_payload, dict) or block_payload.get("result") != "block":
|
|
11323
|
+
failures.append(Failure("live-validation-only-guardrail", "blocking shadow mismatch must block"))
|
|
11324
|
+
|
|
11325
|
+
return failures
|
|
11326
|
+
|
|
11327
|
+
|
|
11191
11328
|
def fake_event_evidence(
|
|
11192
11329
|
*,
|
|
11193
11330
|
event_id: str,
|
|
@@ -12301,6 +12438,7 @@ def collect_failures(root: Path) -> list[Failure]:
|
|
|
12301
12438
|
failures.extend(check_live_smoke_foundation_contract(root))
|
|
12302
12439
|
failures.extend(check_host_adapter_live_drift_contract(root))
|
|
12303
12440
|
failures.extend(check_dynamic_tool_live_availability_contract(root))
|
|
12441
|
+
failures.extend(check_live_validation_only_guardrail_contract(root))
|
|
12304
12442
|
failures.extend(check_structured_event_evidence_contract(root))
|
|
12305
12443
|
failures.extend(check_deferred_roadmap_tree_contract(root))
|
|
12306
12444
|
failures.extend(check_execution_budget_fixture_contract(root))
|
|
@@ -12313,7 +12451,7 @@ def collect_failures(root: Path) -> list[Failure]:
|
|
|
12313
12451
|
|
|
12314
12452
|
|
|
12315
12453
|
def print_report(root: Path, failures: list[Failure]) -> None:
|
|
12316
|
-
categories_checked =
|
|
12454
|
+
categories_checked = 32
|
|
12317
12455
|
if not failures:
|
|
12318
12456
|
print(f"loom_check: OK ({root})")
|
|
12319
12457
|
print(f"checked {categories_checked} surfaces")
|
|
@@ -11188,6 +11188,143 @@ def check_dynamic_tool_live_availability_contract(root: Path) -> list[Failure]:
|
|
|
11188
11188
|
return failures
|
|
11189
11189
|
|
|
11190
11190
|
|
|
11191
|
+
def check_live_validation_only_guardrail_contract(root: Path) -> list[Failure]:
|
|
11192
|
+
failures: list[Failure] = []
|
|
11193
|
+
|
|
11194
|
+
def write_json_local(path: Path, payload: object) -> None:
|
|
11195
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
11196
|
+
path.write_text(json.dumps(payload, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
|
|
11197
|
+
|
|
11198
|
+
docs = {
|
|
11199
|
+
"docs/evidence/v0.10.0-release-readiness.md": [
|
|
11200
|
+
"validation-only shadow parity mismatch",
|
|
11201
|
+
"explicit blocking opt-in",
|
|
11202
|
+
"owner、fallback、override path、authority-of-truth 与 live evidence",
|
|
11203
|
+
"单个 adopted repo smoke",
|
|
11204
|
+
],
|
|
11205
|
+
"docs/evidence/live-smoke-profile.md": [
|
|
11206
|
+
"--include-blocking-shadow",
|
|
11207
|
+
"not sufficient blocking-upgrade evidence on its own",
|
|
11208
|
+
"不得把 `orchestration-live` 提升为普通 PR 的默认 blocking gate",
|
|
11209
|
+
],
|
|
11210
|
+
"docs/methodology/harness/closeout-gate.md": [
|
|
11211
|
+
"shadow parity` 默认不进入 closeout 阻断面",
|
|
11212
|
+
"owner、fallback、override path 与 authority-of-truth",
|
|
11213
|
+
],
|
|
11214
|
+
"docs/evidence/validations/validation-v0.10-live-validation-only-guardrail.md": [
|
|
11215
|
+
"validation-only shadow parity mismatch returns `warn`",
|
|
11216
|
+
"explicit blocking opt-in",
|
|
11217
|
+
"single adopted repo live smoke run is not sufficient",
|
|
11218
|
+
],
|
|
11219
|
+
}
|
|
11220
|
+
for relative, anchors in docs.items():
|
|
11221
|
+
path = root / relative
|
|
11222
|
+
try:
|
|
11223
|
+
text = path.read_text(encoding="utf-8")
|
|
11224
|
+
except OSError as exc:
|
|
11225
|
+
failures.append(Failure("live-validation-only-guardrail", f"`{relative}` is unreadable: {exc}"))
|
|
11226
|
+
continue
|
|
11227
|
+
for anchor in anchors:
|
|
11228
|
+
if anchor not in text:
|
|
11229
|
+
failures.append(Failure("live-validation-only-guardrail", f"`{relative}` must mention `{anchor}`"))
|
|
11230
|
+
|
|
11231
|
+
missing_target = Path("/tmp/loom-missing-live-target")
|
|
11232
|
+
unavailable_payload, error = load_command_json(
|
|
11233
|
+
root,
|
|
11234
|
+
["python3", "tools/loom_flow.py", "live-smoke", "run", "--target", str(missing_target), "--item", "INIT-0001"],
|
|
11235
|
+
)
|
|
11236
|
+
if error:
|
|
11237
|
+
failures.append(Failure("live-validation-only-guardrail", f"`live-smoke run` unavailable sample failed: {error}"))
|
|
11238
|
+
else:
|
|
11239
|
+
require_live_smoke_payload(
|
|
11240
|
+
failures,
|
|
11241
|
+
category="live-validation-only-guardrail",
|
|
11242
|
+
context="unavailable-live-smoke-guardrail",
|
|
11243
|
+
payload=unavailable_payload,
|
|
11244
|
+
expected_operation="run",
|
|
11245
|
+
)
|
|
11246
|
+
if not isinstance(unavailable_payload, dict) or unavailable_payload.get("result") != "warn":
|
|
11247
|
+
failures.append(Failure("live-validation-only-guardrail", "missing target live smoke must warn"))
|
|
11248
|
+
|
|
11249
|
+
dry_run_payload, error = load_command_json(
|
|
11250
|
+
root,
|
|
11251
|
+
[
|
|
11252
|
+
"python3",
|
|
11253
|
+
"tools/loom_flow.py",
|
|
11254
|
+
"live-smoke",
|
|
11255
|
+
"run",
|
|
11256
|
+
"--target",
|
|
11257
|
+
str(root / "examples/new-project"),
|
|
11258
|
+
"--dry-run",
|
|
11259
|
+
"--include-blocking-shadow",
|
|
11260
|
+
],
|
|
11261
|
+
)
|
|
11262
|
+
if error:
|
|
11263
|
+
failures.append(Failure("live-validation-only-guardrail", f"`live-smoke run --include-blocking-shadow --dry-run` failed: {error}"))
|
|
11264
|
+
else:
|
|
11265
|
+
require_live_smoke_payload(
|
|
11266
|
+
failures,
|
|
11267
|
+
category="live-validation-only-guardrail",
|
|
11268
|
+
context="dry-run-live-smoke-guardrail",
|
|
11269
|
+
payload=dry_run_payload,
|
|
11270
|
+
expected_operation="run",
|
|
11271
|
+
)
|
|
11272
|
+
command_plan = dry_run_payload.get("command_plan")
|
|
11273
|
+
if not isinstance(command_plan, list):
|
|
11274
|
+
failures.append(Failure("live-validation-only-guardrail", "dry-run live smoke must include command_plan"))
|
|
11275
|
+
else:
|
|
11276
|
+
blocking_steps = [step for step in command_plan if isinstance(step, dict) and step.get("id") == "shadow-parity-blocking"]
|
|
11277
|
+
if len(blocking_steps) != 1:
|
|
11278
|
+
failures.append(Failure("live-validation-only-guardrail", "dry-run live smoke must include exactly one explicit blocking shadow step when requested"))
|
|
11279
|
+
elif "not sufficient blocking-upgrade evidence on its own" not in str(blocking_steps[0].get("description") or ""):
|
|
11280
|
+
failures.append(Failure("live-validation-only-guardrail", "blocking shadow step must say it is not sufficient blocking-upgrade evidence on its own"))
|
|
11281
|
+
|
|
11282
|
+
example_target = root / "examples/new-project"
|
|
11283
|
+
with tempfile.TemporaryDirectory(prefix="loom-live-validation-guardrail-") as tmp:
|
|
11284
|
+
mismatch_target = Path(tmp) / "shadow-mismatch"
|
|
11285
|
+
shutil.copytree(example_target, mismatch_target)
|
|
11286
|
+
shadow_payload = load_json_file(mismatch_target / ".loom/shadow/review-repo.json")
|
|
11287
|
+
if isinstance(shadow_payload, dict):
|
|
11288
|
+
shadow_payload["source_sha256"] = {"native/status/review.json": "0" * 64}
|
|
11289
|
+
write_json_local(mismatch_target / ".loom/shadow/review-repo.json", shadow_payload)
|
|
11290
|
+
|
|
11291
|
+
warn_payload, warn_error = load_command_json(
|
|
11292
|
+
root,
|
|
11293
|
+
["python3", "tools/loom_flow.py", "shadow-parity", "--target", str(mismatch_target), "--surface", "review"],
|
|
11294
|
+
)
|
|
11295
|
+
if warn_error:
|
|
11296
|
+
failures.append(Failure("live-validation-only-guardrail", f"`shadow-parity` validation-only mismatch sample failed: {warn_error}"))
|
|
11297
|
+
else:
|
|
11298
|
+
require_shadow_parity_payload(
|
|
11299
|
+
failures,
|
|
11300
|
+
category="live-validation-only-guardrail",
|
|
11301
|
+
context="validation-only-shadow-mismatch",
|
|
11302
|
+
payload=warn_payload,
|
|
11303
|
+
expected_reports=1,
|
|
11304
|
+
)
|
|
11305
|
+
if not isinstance(warn_payload, dict) or warn_payload.get("result") != "warn":
|
|
11306
|
+
failures.append(Failure("live-validation-only-guardrail", "validation-only shadow mismatch must warn"))
|
|
11307
|
+
|
|
11308
|
+
block_payload, block_error = load_command_json(
|
|
11309
|
+
root,
|
|
11310
|
+
["python3", "tools/loom_flow.py", "shadow-parity", "--target", str(mismatch_target), "--surface", "review", "--blocking"],
|
|
11311
|
+
)
|
|
11312
|
+
if block_error:
|
|
11313
|
+
failures.append(Failure("live-validation-only-guardrail", f"`shadow-parity --blocking` mismatch sample failed: {block_error}"))
|
|
11314
|
+
else:
|
|
11315
|
+
require_shadow_parity_payload(
|
|
11316
|
+
failures,
|
|
11317
|
+
category="live-validation-only-guardrail",
|
|
11318
|
+
context="blocking-shadow-mismatch",
|
|
11319
|
+
payload=block_payload,
|
|
11320
|
+
expected_reports=1,
|
|
11321
|
+
)
|
|
11322
|
+
if not isinstance(block_payload, dict) or block_payload.get("result") != "block":
|
|
11323
|
+
failures.append(Failure("live-validation-only-guardrail", "blocking shadow mismatch must block"))
|
|
11324
|
+
|
|
11325
|
+
return failures
|
|
11326
|
+
|
|
11327
|
+
|
|
11191
11328
|
def fake_event_evidence(
|
|
11192
11329
|
*,
|
|
11193
11330
|
event_id: str,
|
|
@@ -12301,6 +12438,7 @@ def collect_failures(root: Path) -> list[Failure]:
|
|
|
12301
12438
|
failures.extend(check_live_smoke_foundation_contract(root))
|
|
12302
12439
|
failures.extend(check_host_adapter_live_drift_contract(root))
|
|
12303
12440
|
failures.extend(check_dynamic_tool_live_availability_contract(root))
|
|
12441
|
+
failures.extend(check_live_validation_only_guardrail_contract(root))
|
|
12304
12442
|
failures.extend(check_structured_event_evidence_contract(root))
|
|
12305
12443
|
failures.extend(check_deferred_roadmap_tree_contract(root))
|
|
12306
12444
|
failures.extend(check_execution_budget_fixture_contract(root))
|
|
@@ -12313,7 +12451,7 @@ def collect_failures(root: Path) -> list[Failure]:
|
|
|
12313
12451
|
|
|
12314
12452
|
|
|
12315
12453
|
def print_report(root: Path, failures: list[Failure]) -> None:
|
|
12316
|
-
categories_checked =
|
|
12454
|
+
categories_checked = 32
|
|
12317
12455
|
if not failures:
|
|
12318
12456
|
print(f"loom_check: OK ({root})")
|
|
12319
12457
|
print(f"checked {categories_checked} surfaces")
|