@mc-and-his-agents/loom-installer 0.1.28 → 0.1.29
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 +22 -22
- package/payload/plugin/loom/skills/shared/scripts/loom_check.py +392 -1
- package/payload/skills/loom-adopt/.loom-runtime/shared/scripts/loom_check.py +392 -1
- package/payload/skills/loom-handoff/.loom-runtime/shared/scripts/loom_check.py +392 -1
- package/payload/skills/loom-init/.loom-runtime/shared/scripts/loom_check.py +392 -1
- package/payload/skills/loom-merge-ready/.loom-runtime/shared/scripts/loom_check.py +392 -1
- package/payload/skills/loom-pre-review/.loom-runtime/shared/scripts/loom_check.py +392 -1
- package/payload/skills/loom-resume/.loom-runtime/shared/scripts/loom_check.py +392 -1
- package/payload/skills/loom-retire/.loom-runtime/shared/scripts/loom_check.py +392 -1
- package/payload/skills/loom-review/.loom-runtime/shared/scripts/loom_check.py +392 -1
- package/payload/skills/loom-spec-review/.loom-runtime/shared/scripts/loom_check.py +392 -1
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": "b67209a41ceebaa29825a45453945523ec85a320",
|
|
6
6
|
"source_ref": "main",
|
|
7
|
-
"built_at": "2026-04-
|
|
7
|
+
"built_at": "2026-04-27T01:23:49+08:00",
|
|
8
8
|
"runtime": {
|
|
9
9
|
"python_minimum": "3.10",
|
|
10
10
|
"python_recommended": "3.11+"
|
|
@@ -633,8 +633,8 @@
|
|
|
633
633
|
},
|
|
634
634
|
{
|
|
635
635
|
"path": "plugin/loom/skills/shared/scripts/loom_check.py",
|
|
636
|
-
"bytes":
|
|
637
|
-
"sha256": "
|
|
636
|
+
"bytes": 318256,
|
|
637
|
+
"sha256": "17fae648df2977fddfed4c7d1dc2ec1fef648799fbfd73ba8fa36cfd73b8e925"
|
|
638
638
|
},
|
|
639
639
|
{
|
|
640
640
|
"path": "plugin/loom/skills/shared/scripts/loom_flow.py",
|
|
@@ -1223,8 +1223,8 @@
|
|
|
1223
1223
|
},
|
|
1224
1224
|
{
|
|
1225
1225
|
"path": "skills/loom-adopt/.loom-runtime/shared/scripts/loom_check.py",
|
|
1226
|
-
"bytes":
|
|
1227
|
-
"sha256": "
|
|
1226
|
+
"bytes": 318256,
|
|
1227
|
+
"sha256": "17fae648df2977fddfed4c7d1dc2ec1fef648799fbfd73ba8fa36cfd73b8e925"
|
|
1228
1228
|
},
|
|
1229
1229
|
{
|
|
1230
1230
|
"path": "skills/loom-adopt/.loom-runtime/shared/scripts/loom_flow.py",
|
|
@@ -1843,8 +1843,8 @@
|
|
|
1843
1843
|
},
|
|
1844
1844
|
{
|
|
1845
1845
|
"path": "skills/loom-handoff/.loom-runtime/shared/scripts/loom_check.py",
|
|
1846
|
-
"bytes":
|
|
1847
|
-
"sha256": "
|
|
1846
|
+
"bytes": 318256,
|
|
1847
|
+
"sha256": "17fae648df2977fddfed4c7d1dc2ec1fef648799fbfd73ba8fa36cfd73b8e925"
|
|
1848
1848
|
},
|
|
1849
1849
|
{
|
|
1850
1850
|
"path": "skills/loom-handoff/.loom-runtime/shared/scripts/loom_flow.py",
|
|
@@ -2463,8 +2463,8 @@
|
|
|
2463
2463
|
},
|
|
2464
2464
|
{
|
|
2465
2465
|
"path": "skills/loom-init/.loom-runtime/shared/scripts/loom_check.py",
|
|
2466
|
-
"bytes":
|
|
2467
|
-
"sha256": "
|
|
2466
|
+
"bytes": 318256,
|
|
2467
|
+
"sha256": "17fae648df2977fddfed4c7d1dc2ec1fef648799fbfd73ba8fa36cfd73b8e925"
|
|
2468
2468
|
},
|
|
2469
2469
|
{
|
|
2470
2470
|
"path": "skills/loom-init/.loom-runtime/shared/scripts/loom_flow.py",
|
|
@@ -3088,8 +3088,8 @@
|
|
|
3088
3088
|
},
|
|
3089
3089
|
{
|
|
3090
3090
|
"path": "skills/loom-merge-ready/.loom-runtime/shared/scripts/loom_check.py",
|
|
3091
|
-
"bytes":
|
|
3092
|
-
"sha256": "
|
|
3091
|
+
"bytes": 318256,
|
|
3092
|
+
"sha256": "17fae648df2977fddfed4c7d1dc2ec1fef648799fbfd73ba8fa36cfd73b8e925"
|
|
3093
3093
|
},
|
|
3094
3094
|
{
|
|
3095
3095
|
"path": "skills/loom-merge-ready/.loom-runtime/shared/scripts/loom_flow.py",
|
|
@@ -3708,8 +3708,8 @@
|
|
|
3708
3708
|
},
|
|
3709
3709
|
{
|
|
3710
3710
|
"path": "skills/loom-pre-review/.loom-runtime/shared/scripts/loom_check.py",
|
|
3711
|
-
"bytes":
|
|
3712
|
-
"sha256": "
|
|
3711
|
+
"bytes": 318256,
|
|
3712
|
+
"sha256": "17fae648df2977fddfed4c7d1dc2ec1fef648799fbfd73ba8fa36cfd73b8e925"
|
|
3713
3713
|
},
|
|
3714
3714
|
{
|
|
3715
3715
|
"path": "skills/loom-pre-review/.loom-runtime/shared/scripts/loom_flow.py",
|
|
@@ -4328,8 +4328,8 @@
|
|
|
4328
4328
|
},
|
|
4329
4329
|
{
|
|
4330
4330
|
"path": "skills/loom-resume/.loom-runtime/shared/scripts/loom_check.py",
|
|
4331
|
-
"bytes":
|
|
4332
|
-
"sha256": "
|
|
4331
|
+
"bytes": 318256,
|
|
4332
|
+
"sha256": "17fae648df2977fddfed4c7d1dc2ec1fef648799fbfd73ba8fa36cfd73b8e925"
|
|
4333
4333
|
},
|
|
4334
4334
|
{
|
|
4335
4335
|
"path": "skills/loom-resume/.loom-runtime/shared/scripts/loom_flow.py",
|
|
@@ -4948,8 +4948,8 @@
|
|
|
4948
4948
|
},
|
|
4949
4949
|
{
|
|
4950
4950
|
"path": "skills/loom-retire/.loom-runtime/shared/scripts/loom_check.py",
|
|
4951
|
-
"bytes":
|
|
4952
|
-
"sha256": "
|
|
4951
|
+
"bytes": 318256,
|
|
4952
|
+
"sha256": "17fae648df2977fddfed4c7d1dc2ec1fef648799fbfd73ba8fa36cfd73b8e925"
|
|
4953
4953
|
},
|
|
4954
4954
|
{
|
|
4955
4955
|
"path": "skills/loom-retire/.loom-runtime/shared/scripts/loom_flow.py",
|
|
@@ -5568,8 +5568,8 @@
|
|
|
5568
5568
|
},
|
|
5569
5569
|
{
|
|
5570
5570
|
"path": "skills/loom-review/.loom-runtime/shared/scripts/loom_check.py",
|
|
5571
|
-
"bytes":
|
|
5572
|
-
"sha256": "
|
|
5571
|
+
"bytes": 318256,
|
|
5572
|
+
"sha256": "17fae648df2977fddfed4c7d1dc2ec1fef648799fbfd73ba8fa36cfd73b8e925"
|
|
5573
5573
|
},
|
|
5574
5574
|
{
|
|
5575
5575
|
"path": "skills/loom-review/.loom-runtime/shared/scripts/loom_flow.py",
|
|
@@ -6188,8 +6188,8 @@
|
|
|
6188
6188
|
},
|
|
6189
6189
|
{
|
|
6190
6190
|
"path": "skills/loom-spec-review/.loom-runtime/shared/scripts/loom_check.py",
|
|
6191
|
-
"bytes":
|
|
6192
|
-
"sha256": "
|
|
6191
|
+
"bytes": 318256,
|
|
6192
|
+
"sha256": "17fae648df2977fddfed4c7d1dc2ec1fef648799fbfd73ba8fa36cfd73b8e925"
|
|
6193
6193
|
},
|
|
6194
6194
|
{
|
|
6195
6195
|
"path": "skills/loom-spec-review/.loom-runtime/shared/scripts/loom_flow.py",
|
|
@@ -99,6 +99,7 @@ CORE_DOCS = (
|
|
|
99
99
|
"docs/evidence/validations/validation-skills-consume-maturity-upgrade-path.md",
|
|
100
100
|
"docs/evidence/validations/validation-adoption-gate-rollout.md",
|
|
101
101
|
"docs/evidence/validations/validation-external-runtime-devendor-migration.md",
|
|
102
|
+
"docs/evidence/validations/validation-syvert-adversarial-adoption-fixture.md",
|
|
102
103
|
"docs/evidence/validations/validation-github-profile-binding-orchestration.md",
|
|
103
104
|
"docs/evidence/validations/validation-github-profile-drift-reconciliation.md",
|
|
104
105
|
"docs/evidence/validations/validation-github-profile-graphql-budget-guard.md",
|
|
@@ -6077,6 +6078,395 @@ def check_external_runtime_devendor_contract(root: Path) -> list[Failure]:
|
|
|
6077
6078
|
return failures
|
|
6078
6079
|
|
|
6079
6080
|
|
|
6081
|
+
def check_adversarial_adoption_fixture(root: Path) -> list[Failure]:
|
|
6082
|
+
example_target = root / "examples/new-project"
|
|
6083
|
+
if not example_target.exists():
|
|
6084
|
+
return []
|
|
6085
|
+
|
|
6086
|
+
failures: list[Failure] = []
|
|
6087
|
+
|
|
6088
|
+
def write_json(path: Path, payload: object) -> None:
|
|
6089
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
6090
|
+
path.write_text(json.dumps(payload, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
|
|
6091
|
+
|
|
6092
|
+
def sha256_file(path: Path) -> str:
|
|
6093
|
+
digest = hashlib.sha256()
|
|
6094
|
+
with path.open("rb") as handle:
|
|
6095
|
+
for chunk in iter(lambda: handle.read(1024 * 1024), b""):
|
|
6096
|
+
digest.update(chunk)
|
|
6097
|
+
return digest.hexdigest()
|
|
6098
|
+
|
|
6099
|
+
def write_shadow_evidence(target: Path, evidence: str, value_key: str, value: str, source: str) -> None:
|
|
6100
|
+
source_path = target / source
|
|
6101
|
+
source_path.parent.mkdir(parents=True, exist_ok=True)
|
|
6102
|
+
if not source_path.exists():
|
|
6103
|
+
write_json(source_path, {"value": value})
|
|
6104
|
+
write_json(
|
|
6105
|
+
target / evidence,
|
|
6106
|
+
{
|
|
6107
|
+
value_key: value,
|
|
6108
|
+
"source_files": [source],
|
|
6109
|
+
"source_sha256": {
|
|
6110
|
+
source: sha256_file(source_path),
|
|
6111
|
+
},
|
|
6112
|
+
},
|
|
6113
|
+
)
|
|
6114
|
+
|
|
6115
|
+
valid_interop = {
|
|
6116
|
+
"schema_version": "loom-repo-interop/v1",
|
|
6117
|
+
"host_adapters": [
|
|
6118
|
+
{
|
|
6119
|
+
"id": "guardian-review",
|
|
6120
|
+
"summary": "Read repo-native review verdicts without reimplementing the host action.",
|
|
6121
|
+
"surfaces": ["review", "merge_ready"],
|
|
6122
|
+
"locator": "host/guardian-review.json",
|
|
6123
|
+
}
|
|
6124
|
+
],
|
|
6125
|
+
"repo_native_carriers": [
|
|
6126
|
+
{
|
|
6127
|
+
"id": "governance-status",
|
|
6128
|
+
"summary": "Read repo-native governance status output without migrating carriers.",
|
|
6129
|
+
"surfaces": ["admission", "review", "merge_ready", "closeout"],
|
|
6130
|
+
"locator": "native/status",
|
|
6131
|
+
}
|
|
6132
|
+
],
|
|
6133
|
+
"shadow_surfaces": {
|
|
6134
|
+
"admission": {
|
|
6135
|
+
"summary": "Compare admission parity.",
|
|
6136
|
+
"loom_locator": ".loom/shadow/admission-loom.json",
|
|
6137
|
+
"repo_locator": ".loom/shadow/admission-repo.json",
|
|
6138
|
+
},
|
|
6139
|
+
"review": {
|
|
6140
|
+
"summary": "Compare review parity.",
|
|
6141
|
+
"loom_locator": ".loom/shadow/review-loom.json",
|
|
6142
|
+
"repo_locator": ".loom/shadow/review-repo.json",
|
|
6143
|
+
},
|
|
6144
|
+
"merge_ready": {
|
|
6145
|
+
"summary": "Compare merge-ready parity.",
|
|
6146
|
+
"loom_locator": ".loom/shadow/merge-ready-loom.json",
|
|
6147
|
+
"repo_locator": ".loom/shadow/merge-ready-repo.json",
|
|
6148
|
+
},
|
|
6149
|
+
"closeout": {
|
|
6150
|
+
"summary": "Compare closeout parity.",
|
|
6151
|
+
"loom_locator": ".loom/shadow/closeout-loom.json",
|
|
6152
|
+
"repo_locator": ".loom/shadow/closeout-repo.json",
|
|
6153
|
+
},
|
|
6154
|
+
},
|
|
6155
|
+
}
|
|
6156
|
+
|
|
6157
|
+
def install_strong_companion(target: Path) -> None:
|
|
6158
|
+
companion = target / ".loom" / "companion"
|
|
6159
|
+
companion.mkdir(parents=True, exist_ok=True)
|
|
6160
|
+
for relative in (
|
|
6161
|
+
".loom/companion/README.md",
|
|
6162
|
+
".loom/companion/review.md",
|
|
6163
|
+
".loom/companion/merge-ready.md",
|
|
6164
|
+
".loom/companion/closeout.md",
|
|
6165
|
+
".loom/companion/specialized-gates.md",
|
|
6166
|
+
".loom/companion/metadata-contract.md",
|
|
6167
|
+
".loom/companion/context-schema.md",
|
|
6168
|
+
):
|
|
6169
|
+
(target / relative).parent.mkdir(parents=True, exist_ok=True)
|
|
6170
|
+
(target / relative).write_text("# Companion Fixture\n\nStable fixture authority.\n", encoding="utf-8")
|
|
6171
|
+
write_json(
|
|
6172
|
+
companion / "manifest.json",
|
|
6173
|
+
{
|
|
6174
|
+
"schema_version": "loom-repo-companion-manifest/v1",
|
|
6175
|
+
"companion_entry": ".loom/companion/README.md",
|
|
6176
|
+
"repo_interface": ".loom/companion/repo-interface.json",
|
|
6177
|
+
},
|
|
6178
|
+
)
|
|
6179
|
+
write_json(
|
|
6180
|
+
companion / "repo-interface.json",
|
|
6181
|
+
{
|
|
6182
|
+
"schema_version": "loom-repo-interface/v2",
|
|
6183
|
+
"companion_entry": ".loom/companion/README.md",
|
|
6184
|
+
"repo_specific_requirements": {
|
|
6185
|
+
"review": [],
|
|
6186
|
+
"merge_ready": [],
|
|
6187
|
+
"closeout": [],
|
|
6188
|
+
},
|
|
6189
|
+
"specialized_gates": [
|
|
6190
|
+
{
|
|
6191
|
+
"id": "repo-native-review",
|
|
6192
|
+
"summary": "Repo-native review stays repo-owned.",
|
|
6193
|
+
"locator": ".loom/companion/specialized-gates.md",
|
|
6194
|
+
"gate_type": "review",
|
|
6195
|
+
}
|
|
6196
|
+
],
|
|
6197
|
+
"metadata_contract": {
|
|
6198
|
+
"fields": [
|
|
6199
|
+
{
|
|
6200
|
+
"id": "integration_check",
|
|
6201
|
+
"summary": "Repo-local integration metadata remains repo-owned.",
|
|
6202
|
+
"applicability_locator": ".loom/companion/metadata-contract.md",
|
|
6203
|
+
"authority_locator": ".loom/companion/review.md",
|
|
6204
|
+
"enforcement": "advisory",
|
|
6205
|
+
}
|
|
6206
|
+
]
|
|
6207
|
+
},
|
|
6208
|
+
"context_schema": {
|
|
6209
|
+
"fields": [
|
|
6210
|
+
{
|
|
6211
|
+
"id": "item_key",
|
|
6212
|
+
"summary": "Repo-local item key mapping.",
|
|
6213
|
+
"type": "string",
|
|
6214
|
+
"required": True,
|
|
6215
|
+
"mapping_rule_locator": ".loom/companion/context-schema.md",
|
|
6216
|
+
}
|
|
6217
|
+
]
|
|
6218
|
+
},
|
|
6219
|
+
},
|
|
6220
|
+
)
|
|
6221
|
+
|
|
6222
|
+
def install_interop(target: Path) -> None:
|
|
6223
|
+
(target / "host").mkdir(parents=True, exist_ok=True)
|
|
6224
|
+
(target / "native" / "status").mkdir(parents=True, exist_ok=True)
|
|
6225
|
+
for relative, payload in {
|
|
6226
|
+
"host/guardian-review.json": {"decision": "allow"},
|
|
6227
|
+
"native/status/admission.json": {"result": "pass"},
|
|
6228
|
+
"native/status/review.json": {"decision": "allow"},
|
|
6229
|
+
"native/status/merge-ready.json": {"status": "pass"},
|
|
6230
|
+
"native/status/closeout.json": {"status": "done"},
|
|
6231
|
+
}.items():
|
|
6232
|
+
write_json(target / relative, payload)
|
|
6233
|
+
write_shadow_evidence(target, ".loom/shadow/admission-loom.json", "result", "pass", ".loom/status/current.md")
|
|
6234
|
+
write_shadow_evidence(target, ".loom/shadow/admission-repo.json", "result", "pass", "native/status/admission.json")
|
|
6235
|
+
write_shadow_evidence(target, ".loom/shadow/review-loom.json", "decision", "allow", "host/guardian-review.json")
|
|
6236
|
+
write_shadow_evidence(target, ".loom/shadow/review-repo.json", "decision", "allow", "native/status/review.json")
|
|
6237
|
+
write_shadow_evidence(target, ".loom/shadow/merge-ready-loom.json", "status", "pass", "host/guardian-review.json")
|
|
6238
|
+
write_shadow_evidence(target, ".loom/shadow/merge-ready-repo.json", "status", "pass", "native/status/merge-ready.json")
|
|
6239
|
+
write_shadow_evidence(target, ".loom/shadow/closeout-loom.json", "status", "done", ".loom/status/current.md")
|
|
6240
|
+
write_shadow_evidence(target, ".loom/shadow/closeout-repo.json", "status", "done", "native/status/closeout.json")
|
|
6241
|
+
write_json(target / ".loom" / "companion" / "interop.json", valid_interop)
|
|
6242
|
+
|
|
6243
|
+
def git_init(target: Path) -> str | None:
|
|
6244
|
+
for args in (
|
|
6245
|
+
["git", "init"],
|
|
6246
|
+
["git", "config", "user.email", "loom-check@example.com"],
|
|
6247
|
+
["git", "config", "user.name", "loom-check"],
|
|
6248
|
+
["git", "remote", "add", "origin", "https://github.com/MC-and-his-Agents/Loom.git"],
|
|
6249
|
+
["git", "add", "-f", "."],
|
|
6250
|
+
["git", "commit", "-m", "strong adoption fixture baseline"],
|
|
6251
|
+
):
|
|
6252
|
+
result = run_command(root, args, cwd=target, timeout_seconds=30)
|
|
6253
|
+
if result.returncode != 0:
|
|
6254
|
+
failures.append(Failure("adversarial-adoption", f"`{' '.join(args)}` setup failed: {result.stderr.strip() or result.stdout.strip()}"))
|
|
6255
|
+
return None
|
|
6256
|
+
head = run_command(root, ["git", "rev-parse", "HEAD"], cwd=target, timeout_seconds=30)
|
|
6257
|
+
if head.returncode != 0:
|
|
6258
|
+
failures.append(Failure("adversarial-adoption", "`git rev-parse HEAD` setup failed"))
|
|
6259
|
+
return None
|
|
6260
|
+
return head.stdout.strip()
|
|
6261
|
+
|
|
6262
|
+
def install_fresh_reviews(target: Path, reviewed_head: str) -> None:
|
|
6263
|
+
validation_summary = "Bootstrap manifest exists; init-result JSON can be read mechanically; the first work item, status surface, and spec/plan artifacts exist."
|
|
6264
|
+
for suffix, kind in (("", "code_review"), (".spec", "spec_review")):
|
|
6265
|
+
write_json(
|
|
6266
|
+
target / ".loom" / "reviews" / f"INIT-0001{suffix}.json",
|
|
6267
|
+
{
|
|
6268
|
+
"schema_version": "loom-review/v1",
|
|
6269
|
+
"item_id": "INIT-0001",
|
|
6270
|
+
"decision": "allow",
|
|
6271
|
+
"kind": kind,
|
|
6272
|
+
"summary": "Syvert-style strong adoption fixture review is fresh.",
|
|
6273
|
+
"reviewer": "loom-check",
|
|
6274
|
+
"reviewed_head": reviewed_head,
|
|
6275
|
+
"reviewed_validation_summary": validation_summary,
|
|
6276
|
+
"fallback_to": None,
|
|
6277
|
+
"findings": [],
|
|
6278
|
+
"blocking_issues": [],
|
|
6279
|
+
"follow_ups": [],
|
|
6280
|
+
},
|
|
6281
|
+
)
|
|
6282
|
+
|
|
6283
|
+
def prepare_strong_target(target: Path) -> str | None:
|
|
6284
|
+
shutil.copytree(example_target, target)
|
|
6285
|
+
install_strong_companion(target)
|
|
6286
|
+
install_interop(target)
|
|
6287
|
+
reviewed_head = git_init(target)
|
|
6288
|
+
if reviewed_head is None:
|
|
6289
|
+
return None
|
|
6290
|
+
install_fresh_reviews(target, reviewed_head)
|
|
6291
|
+
result = run_command(root, ["git", "add", "-f", ".loom/reviews"], cwd=target, timeout_seconds=30)
|
|
6292
|
+
if result.returncode == 0:
|
|
6293
|
+
result = run_command(root, ["git", "commit", "-m", "record fresh reviews"], cwd=target, timeout_seconds=30)
|
|
6294
|
+
if result.returncode != 0:
|
|
6295
|
+
failures.append(Failure("adversarial-adoption", f"fresh review setup failed: {result.stderr.strip() or result.stdout.strip()}"))
|
|
6296
|
+
return None
|
|
6297
|
+
head = run_command(root, ["git", "rev-parse", "HEAD"], cwd=target, timeout_seconds=30)
|
|
6298
|
+
return head.stdout.strip() if head.returncode == 0 else reviewed_head
|
|
6299
|
+
|
|
6300
|
+
with tempfile.TemporaryDirectory(prefix="loom-check-syvert-adoption-") as tmp:
|
|
6301
|
+
base = Path(tmp)
|
|
6302
|
+
baseline = base / "baseline"
|
|
6303
|
+
current_head = prepare_strong_target(baseline)
|
|
6304
|
+
if current_head is None:
|
|
6305
|
+
return failures
|
|
6306
|
+
install_fresh_reviews(baseline, current_head)
|
|
6307
|
+
run_command(root, ["git", "add", "-f", ".loom/reviews"], cwd=baseline, timeout_seconds=30)
|
|
6308
|
+
run_command(root, ["git", "commit", "-m", "refresh reviews to current head"], cwd=baseline, timeout_seconds=30)
|
|
6309
|
+
|
|
6310
|
+
status_payload, error = load_command_json(
|
|
6311
|
+
root,
|
|
6312
|
+
["python3", "tools/loom_flow.py", "governance-profile", "status", "--target", str(baseline)],
|
|
6313
|
+
)
|
|
6314
|
+
if error:
|
|
6315
|
+
failures.append(Failure("adversarial-adoption", f"`governance-profile status` baseline failed: {error}"))
|
|
6316
|
+
else:
|
|
6317
|
+
maturity = status_payload.get("maturity")
|
|
6318
|
+
if isinstance(maturity, dict) and maturity.get("current") == "strong":
|
|
6319
|
+
pass
|
|
6320
|
+
elif isinstance(maturity, dict):
|
|
6321
|
+
missing_by_level = maturity.get("missing_by_level")
|
|
6322
|
+
strong_missing = missing_by_level.get("strong") if isinstance(missing_by_level, dict) else []
|
|
6323
|
+
if not isinstance(strong_missing, list) or "repo_interface" in strong_missing or "repo_interop" in strong_missing:
|
|
6324
|
+
failures.append(Failure("adversarial-adoption", "hostless baseline must still prove repo companion and interop carriers are present"))
|
|
6325
|
+
else:
|
|
6326
|
+
failures.append(Failure("adversarial-adoption", "baseline fixture must reach strong maturity when GitHub host signals are readable"))
|
|
6327
|
+
|
|
6328
|
+
for label, args, expected in (
|
|
6329
|
+
("runtime-parity", ["python3", str(baseline / ".loom/bin/loom_flow.py"), "runtime-parity", "validate", "--target", str(baseline)], "pass"),
|
|
6330
|
+
("shadow-parity", ["python3", "tools/loom_flow.py", "shadow-parity", "--target", str(baseline)], "pass"),
|
|
6331
|
+
("shadow-parity --blocking", ["python3", "tools/loom_flow.py", "shadow-parity", "--target", str(baseline), "--blocking"], "pass"),
|
|
6332
|
+
("flow resume", ["python3", "tools/loom_flow.py", "flow", "resume", "--target", str(baseline), "--item", "INIT-0001"], "pass"),
|
|
6333
|
+
):
|
|
6334
|
+
payload, error = load_command_json(root, args)
|
|
6335
|
+
if error:
|
|
6336
|
+
failures.append(Failure("adversarial-adoption", f"`{label}` baseline failed: {error}"))
|
|
6337
|
+
elif payload.get("result") != expected:
|
|
6338
|
+
failures.append(Failure("adversarial-adoption", f"`{label}` baseline must return `{expected}`"))
|
|
6339
|
+
|
|
6340
|
+
poisoned_payload, error = load_command_json(
|
|
6341
|
+
root,
|
|
6342
|
+
["python3", str(baseline / ".loom/bin/loom_init.py"), "runtime-state", "--target", str(baseline)],
|
|
6343
|
+
env={"LOOM_SOURCE_REPO_ROOT": "/tmp/not-loom"},
|
|
6344
|
+
)
|
|
6345
|
+
if error:
|
|
6346
|
+
failures.append(Failure("adversarial-adoption", f"env poisoning runtime-state failed: {error}"))
|
|
6347
|
+
else:
|
|
6348
|
+
runtime_state = poisoned_payload.get("runtime_state")
|
|
6349
|
+
carrier = runtime_state.get("carrier") if isinstance(runtime_state, dict) else None
|
|
6350
|
+
if carrier != "bootstrapped-target-runtime" or poisoned_payload.get("result") != "pass":
|
|
6351
|
+
failures.append(Failure("adversarial-adoption", "env poisoning must not override bootstrapped target runtime detection"))
|
|
6352
|
+
|
|
6353
|
+
drift_target = base / "runtime-drift"
|
|
6354
|
+
shutil.copytree(baseline, drift_target)
|
|
6355
|
+
manifest_path = drift_target / ".loom/bootstrap/manifest.json"
|
|
6356
|
+
manifest = load_json_file(manifest_path)
|
|
6357
|
+
artifacts = manifest.get("artifacts") if isinstance(manifest, dict) else []
|
|
6358
|
+
if isinstance(artifacts, list):
|
|
6359
|
+
for artifact in artifacts:
|
|
6360
|
+
if isinstance(artifact, dict) and artifact.get("path") == ".loom/bin/loom_init.py":
|
|
6361
|
+
artifact["sha256"] = "0" * 64
|
|
6362
|
+
break
|
|
6363
|
+
write_json(manifest_path, manifest)
|
|
6364
|
+
payload, error = load_command_json(
|
|
6365
|
+
root,
|
|
6366
|
+
["python3", str(drift_target / ".loom/bin/loom_flow.py"), "runtime-parity", "validate", "--target", str(drift_target)],
|
|
6367
|
+
)
|
|
6368
|
+
if error:
|
|
6369
|
+
failures.append(Failure("adversarial-adoption", f"runtime provenance drift sample failed: {error}"))
|
|
6370
|
+
elif payload.get("result") != "block":
|
|
6371
|
+
failures.append(Failure("adversarial-adoption", "runtime provenance drift must block runtime-parity"))
|
|
6372
|
+
|
|
6373
|
+
rollover_target = base / "active-rollover"
|
|
6374
|
+
shutil.copytree(baseline, rollover_target)
|
|
6375
|
+
payload, error = load_command_json(
|
|
6376
|
+
root,
|
|
6377
|
+
[
|
|
6378
|
+
"python3",
|
|
6379
|
+
"tools/loom_flow.py",
|
|
6380
|
+
"work-item",
|
|
6381
|
+
"create",
|
|
6382
|
+
"--target",
|
|
6383
|
+
str(rollover_target),
|
|
6384
|
+
"--item",
|
|
6385
|
+
"WORK-0002",
|
|
6386
|
+
"--goal",
|
|
6387
|
+
"Validate active item rollover",
|
|
6388
|
+
"--scope",
|
|
6389
|
+
"Keep the fixture constrained to Loom carriers",
|
|
6390
|
+
"--execution-path",
|
|
6391
|
+
"execution/support",
|
|
6392
|
+
"--workspace-entry",
|
|
6393
|
+
".",
|
|
6394
|
+
"--validation-entry",
|
|
6395
|
+
"python3 .loom/bin/loom_init.py verify --target .",
|
|
6396
|
+
"--closing-condition",
|
|
6397
|
+
"The active item can be read mechanically.",
|
|
6398
|
+
"--init-recovery",
|
|
6399
|
+
"--activate",
|
|
6400
|
+
],
|
|
6401
|
+
)
|
|
6402
|
+
if error:
|
|
6403
|
+
failures.append(Failure("adversarial-adoption", f"active item rollover create failed: {error}"))
|
|
6404
|
+
else:
|
|
6405
|
+
resume_payload, resume_error = load_command_json(
|
|
6406
|
+
root,
|
|
6407
|
+
["python3", "tools/loom_flow.py", "flow", "resume", "--target", str(rollover_target), "--item", "WORK-0002"],
|
|
6408
|
+
)
|
|
6409
|
+
item_id = resume_payload.get("item", {}).get("id") if isinstance(resume_payload, dict) and isinstance(resume_payload.get("item"), dict) else None
|
|
6410
|
+
if resume_error:
|
|
6411
|
+
failures.append(Failure("adversarial-adoption", f"active item rollover resume failed: {resume_error}"))
|
|
6412
|
+
elif item_id != "WORK-0002":
|
|
6413
|
+
failures.append(Failure("adversarial-adoption", "active item rollover must consume WORK-0002 instead of bootstrap INIT-0001"))
|
|
6414
|
+
|
|
6415
|
+
spoof_target = base / "metadata-spoof"
|
|
6416
|
+
shutil.copytree(baseline, spoof_target)
|
|
6417
|
+
work_item_path = spoof_target / ".loom/work-items/INIT-0001.md"
|
|
6418
|
+
work_item_path.write_text(
|
|
6419
|
+
work_item_path.read_text(encoding="utf-8").replace(
|
|
6420
|
+
"- Goal: Bootstrap the first executable Loom path for this repository\n",
|
|
6421
|
+
"- Goal: spoofed wrong goal\n- Goal: Bootstrap the first executable Loom path for this repository\n",
|
|
6422
|
+
1,
|
|
6423
|
+
),
|
|
6424
|
+
encoding="utf-8",
|
|
6425
|
+
)
|
|
6426
|
+
payload, error = load_command_json(root, ["python3", "tools/loom_flow.py", "fact-chain", "--target", str(spoof_target)])
|
|
6427
|
+
if error:
|
|
6428
|
+
failures.append(Failure("adversarial-adoption", f"metadata spoof sample failed: {error}"))
|
|
6429
|
+
elif payload.get("result") != "block":
|
|
6430
|
+
failures.append(Failure("adversarial-adoption", "metadata spoofing must fail closed in the canonical section"))
|
|
6431
|
+
|
|
6432
|
+
shadow_target = base / "shadow-broken"
|
|
6433
|
+
shutil.copytree(baseline, shadow_target)
|
|
6434
|
+
shadow_payload = load_json_file(shadow_target / ".loom/shadow/review-repo.json")
|
|
6435
|
+
if isinstance(shadow_payload, dict):
|
|
6436
|
+
shadow_payload.pop("source_sha256", None)
|
|
6437
|
+
write_json(shadow_target / ".loom/shadow/review-repo.json", shadow_payload)
|
|
6438
|
+
warn_payload, warn_error = load_command_json(
|
|
6439
|
+
root,
|
|
6440
|
+
["python3", "tools/loom_flow.py", "shadow-parity", "--target", str(shadow_target), "--surface", "review"],
|
|
6441
|
+
)
|
|
6442
|
+
block_payload, block_error = load_command_json(
|
|
6443
|
+
root,
|
|
6444
|
+
["python3", "tools/loom_flow.py", "shadow-parity", "--target", str(shadow_target), "--surface", "review", "--blocking"],
|
|
6445
|
+
)
|
|
6446
|
+
if warn_error:
|
|
6447
|
+
failures.append(Failure("adversarial-adoption", f"shadow evidence validation-only sample failed: {warn_error}"))
|
|
6448
|
+
elif warn_payload.get("result") != "warn":
|
|
6449
|
+
failures.append(Failure("adversarial-adoption", "broken shadow evidence must warn in validation-only mode"))
|
|
6450
|
+
if block_error:
|
|
6451
|
+
failures.append(Failure("adversarial-adoption", f"shadow evidence blocking sample failed: {block_error}"))
|
|
6452
|
+
elif block_payload.get("result") != "block":
|
|
6453
|
+
failures.append(Failure("adversarial-adoption", "broken shadow evidence must block in blocking mode"))
|
|
6454
|
+
|
|
6455
|
+
head_before_drift = run_command(root, ["git", "rev-parse", "HEAD"], cwd=baseline, timeout_seconds=30).stdout.strip()
|
|
6456
|
+
(baseline / "implementation-drift.txt").write_text("changed after review\n", encoding="utf-8")
|
|
6457
|
+
run_command(root, ["git", "add", "implementation-drift.txt"], cwd=baseline, timeout_seconds=30)
|
|
6458
|
+
run_command(root, ["git", "commit", "-m", "implementation drift after review"], cwd=baseline, timeout_seconds=30)
|
|
6459
|
+
binding_payload, binding_errors = review_head_binding(
|
|
6460
|
+
baseline,
|
|
6461
|
+
reviewed_head=head_before_drift,
|
|
6462
|
+
allowed_paths=set(),
|
|
6463
|
+
)
|
|
6464
|
+
if not binding_errors or binding_payload.get("status") != "implementation-drift-only":
|
|
6465
|
+
failures.append(Failure("adversarial-adoption", "review head binding must classify implementation drift after review"))
|
|
6466
|
+
|
|
6467
|
+
return failures
|
|
6468
|
+
|
|
6469
|
+
|
|
6080
6470
|
def check_node_installer(root: Path) -> list[Failure]:
|
|
6081
6471
|
category = "node-installer"
|
|
6082
6472
|
failures: list[Failure] = []
|
|
@@ -6189,6 +6579,7 @@ def collect_failures(root: Path) -> list[Failure]:
|
|
|
6189
6579
|
failures.extend(check_repo_companion_interface_contracts(root))
|
|
6190
6580
|
failures.extend(check_repo_interop_contracts(root))
|
|
6191
6581
|
failures.extend(check_external_runtime_devendor_contract(root))
|
|
6582
|
+
failures.extend(check_adversarial_adoption_fixture(root))
|
|
6192
6583
|
failures.extend(check_node_installer(root))
|
|
6193
6584
|
failures.extend(check_generated_artifacts_untracked(root))
|
|
6194
6585
|
failures.extend(check_github_cli_budget(root))
|
|
@@ -6197,7 +6588,7 @@ def collect_failures(root: Path) -> list[Failure]:
|
|
|
6197
6588
|
|
|
6198
6589
|
|
|
6199
6590
|
def print_report(root: Path, failures: list[Failure]) -> None:
|
|
6200
|
-
categories_checked =
|
|
6591
|
+
categories_checked = 18
|
|
6201
6592
|
if not failures:
|
|
6202
6593
|
print(f"loom_check: OK ({root})")
|
|
6203
6594
|
print(f"checked {categories_checked} surfaces")
|