@mc-and-his-agents/loom-installer 0.1.111 → 0.1.113
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 +425 -425
- package/payload/plugin/loom/skills/loom-adopt/.loom-runtime/loom-adopt/SKILL.md +1 -0
- package/payload/plugin/loom/skills/loom-adopt/.loom-runtime/loom-init/SKILL.md +2 -0
- package/payload/plugin/loom/skills/loom-adopt/.loom-runtime/loom-init/contract.json +4 -0
- package/payload/plugin/loom/skills/loom-adopt/.loom-runtime/loom-init/references/output-contract.md +13 -1
- package/payload/plugin/loom/skills/loom-adopt/.loom-runtime/shared/references/adoption/deep-existing-repo-default.md +4 -0
- package/payload/plugin/loom/skills/loom-adopt/.loom-runtime/shared/references/adoption/repo-companion-contract.md +3 -1
- package/payload/plugin/loom/skills/loom-adopt/.loom-runtime/shared/scripts/governance_surface.py +1 -0
- package/payload/plugin/loom/skills/loom-adopt/.loom-runtime/shared/scripts/loom_check.py +148 -0
- package/payload/plugin/loom/skills/loom-adopt/.loom-runtime/shared/scripts/loom_init.py +523 -215
- package/payload/plugin/loom/skills/loom-adopt/SKILL.md +1 -0
- package/payload/plugin/loom/skills/loom-build/.loom-runtime/loom-adopt/SKILL.md +1 -0
- package/payload/plugin/loom/skills/loom-build/.loom-runtime/loom-init/SKILL.md +2 -0
- package/payload/plugin/loom/skills/loom-build/.loom-runtime/loom-init/contract.json +4 -0
- package/payload/plugin/loom/skills/loom-build/.loom-runtime/loom-init/references/output-contract.md +13 -1
- package/payload/plugin/loom/skills/loom-build/.loom-runtime/shared/references/adoption/deep-existing-repo-default.md +4 -0
- package/payload/plugin/loom/skills/loom-build/.loom-runtime/shared/references/adoption/repo-companion-contract.md +3 -1
- package/payload/plugin/loom/skills/loom-build/.loom-runtime/shared/scripts/governance_surface.py +1 -0
- package/payload/plugin/loom/skills/loom-build/.loom-runtime/shared/scripts/loom_check.py +148 -0
- package/payload/plugin/loom/skills/loom-build/.loom-runtime/shared/scripts/loom_init.py +523 -215
- package/payload/plugin/loom/skills/loom-handoff/.loom-runtime/loom-adopt/SKILL.md +1 -0
- package/payload/plugin/loom/skills/loom-handoff/.loom-runtime/loom-init/SKILL.md +2 -0
- package/payload/plugin/loom/skills/loom-handoff/.loom-runtime/loom-init/contract.json +4 -0
- package/payload/plugin/loom/skills/loom-handoff/.loom-runtime/loom-init/references/output-contract.md +13 -1
- package/payload/plugin/loom/skills/loom-handoff/.loom-runtime/shared/references/adoption/deep-existing-repo-default.md +4 -0
- package/payload/plugin/loom/skills/loom-handoff/.loom-runtime/shared/references/adoption/repo-companion-contract.md +3 -1
- package/payload/plugin/loom/skills/loom-handoff/.loom-runtime/shared/scripts/governance_surface.py +1 -0
- package/payload/plugin/loom/skills/loom-handoff/.loom-runtime/shared/scripts/loom_check.py +148 -0
- package/payload/plugin/loom/skills/loom-handoff/.loom-runtime/shared/scripts/loom_init.py +523 -215
- package/payload/plugin/loom/skills/loom-init/.loom-runtime/loom-adopt/SKILL.md +1 -0
- package/payload/plugin/loom/skills/loom-init/.loom-runtime/loom-init/SKILL.md +2 -0
- package/payload/plugin/loom/skills/loom-init/.loom-runtime/loom-init/contract.json +4 -0
- package/payload/plugin/loom/skills/loom-init/.loom-runtime/loom-init/references/output-contract.md +13 -1
- package/payload/plugin/loom/skills/loom-init/.loom-runtime/shared/references/adoption/deep-existing-repo-default.md +4 -0
- package/payload/plugin/loom/skills/loom-init/.loom-runtime/shared/references/adoption/repo-companion-contract.md +3 -1
- package/payload/plugin/loom/skills/loom-init/.loom-runtime/shared/scripts/governance_surface.py +1 -0
- package/payload/plugin/loom/skills/loom-init/.loom-runtime/shared/scripts/loom_check.py +148 -0
- package/payload/plugin/loom/skills/loom-init/.loom-runtime/shared/scripts/loom_init.py +523 -215
- package/payload/plugin/loom/skills/loom-init/SKILL.md +2 -0
- package/payload/plugin/loom/skills/loom-init/contract.json +4 -0
- package/payload/plugin/loom/skills/loom-init/references/output-contract.md +13 -1
- package/payload/plugin/loom/skills/loom-merge-ready/.loom-runtime/loom-adopt/SKILL.md +1 -0
- package/payload/plugin/loom/skills/loom-merge-ready/.loom-runtime/loom-init/SKILL.md +2 -0
- package/payload/plugin/loom/skills/loom-merge-ready/.loom-runtime/loom-init/contract.json +4 -0
- package/payload/plugin/loom/skills/loom-merge-ready/.loom-runtime/loom-init/references/output-contract.md +13 -1
- package/payload/plugin/loom/skills/loom-merge-ready/.loom-runtime/shared/references/adoption/deep-existing-repo-default.md +4 -0
- package/payload/plugin/loom/skills/loom-merge-ready/.loom-runtime/shared/references/adoption/repo-companion-contract.md +3 -1
- package/payload/plugin/loom/skills/loom-merge-ready/.loom-runtime/shared/scripts/governance_surface.py +1 -0
- package/payload/plugin/loom/skills/loom-merge-ready/.loom-runtime/shared/scripts/loom_check.py +148 -0
- package/payload/plugin/loom/skills/loom-merge-ready/.loom-runtime/shared/scripts/loom_init.py +523 -215
- package/payload/plugin/loom/skills/loom-pre-review/.loom-runtime/loom-adopt/SKILL.md +1 -0
- package/payload/plugin/loom/skills/loom-pre-review/.loom-runtime/loom-init/SKILL.md +2 -0
- package/payload/plugin/loom/skills/loom-pre-review/.loom-runtime/loom-init/contract.json +4 -0
- package/payload/plugin/loom/skills/loom-pre-review/.loom-runtime/loom-init/references/output-contract.md +13 -1
- package/payload/plugin/loom/skills/loom-pre-review/.loom-runtime/shared/references/adoption/deep-existing-repo-default.md +4 -0
- package/payload/plugin/loom/skills/loom-pre-review/.loom-runtime/shared/references/adoption/repo-companion-contract.md +3 -1
- package/payload/plugin/loom/skills/loom-pre-review/.loom-runtime/shared/scripts/governance_surface.py +1 -0
- package/payload/plugin/loom/skills/loom-pre-review/.loom-runtime/shared/scripts/loom_check.py +148 -0
- package/payload/plugin/loom/skills/loom-pre-review/.loom-runtime/shared/scripts/loom_init.py +523 -215
- package/payload/plugin/loom/skills/loom-resume/.loom-runtime/loom-adopt/SKILL.md +1 -0
- package/payload/plugin/loom/skills/loom-resume/.loom-runtime/loom-init/SKILL.md +2 -0
- package/payload/plugin/loom/skills/loom-resume/.loom-runtime/loom-init/contract.json +4 -0
- package/payload/plugin/loom/skills/loom-resume/.loom-runtime/loom-init/references/output-contract.md +13 -1
- package/payload/plugin/loom/skills/loom-resume/.loom-runtime/shared/references/adoption/deep-existing-repo-default.md +4 -0
- package/payload/plugin/loom/skills/loom-resume/.loom-runtime/shared/references/adoption/repo-companion-contract.md +3 -1
- package/payload/plugin/loom/skills/loom-resume/.loom-runtime/shared/scripts/governance_surface.py +1 -0
- package/payload/plugin/loom/skills/loom-resume/.loom-runtime/shared/scripts/loom_check.py +148 -0
- package/payload/plugin/loom/skills/loom-resume/.loom-runtime/shared/scripts/loom_init.py +523 -215
- package/payload/plugin/loom/skills/loom-retire/.loom-runtime/loom-adopt/SKILL.md +1 -0
- package/payload/plugin/loom/skills/loom-retire/.loom-runtime/loom-init/SKILL.md +2 -0
- package/payload/plugin/loom/skills/loom-retire/.loom-runtime/loom-init/contract.json +4 -0
- package/payload/plugin/loom/skills/loom-retire/.loom-runtime/loom-init/references/output-contract.md +13 -1
- package/payload/plugin/loom/skills/loom-retire/.loom-runtime/shared/references/adoption/deep-existing-repo-default.md +4 -0
- package/payload/plugin/loom/skills/loom-retire/.loom-runtime/shared/references/adoption/repo-companion-contract.md +3 -1
- package/payload/plugin/loom/skills/loom-retire/.loom-runtime/shared/scripts/governance_surface.py +1 -0
- package/payload/plugin/loom/skills/loom-retire/.loom-runtime/shared/scripts/loom_check.py +148 -0
- package/payload/plugin/loom/skills/loom-retire/.loom-runtime/shared/scripts/loom_init.py +523 -215
- package/payload/plugin/loom/skills/loom-review/.loom-runtime/loom-adopt/SKILL.md +1 -0
- package/payload/plugin/loom/skills/loom-review/.loom-runtime/loom-init/SKILL.md +2 -0
- package/payload/plugin/loom/skills/loom-review/.loom-runtime/loom-init/contract.json +4 -0
- package/payload/plugin/loom/skills/loom-review/.loom-runtime/loom-init/references/output-contract.md +13 -1
- package/payload/plugin/loom/skills/loom-review/.loom-runtime/shared/references/adoption/deep-existing-repo-default.md +4 -0
- package/payload/plugin/loom/skills/loom-review/.loom-runtime/shared/references/adoption/repo-companion-contract.md +3 -1
- package/payload/plugin/loom/skills/loom-review/.loom-runtime/shared/scripts/governance_surface.py +1 -0
- package/payload/plugin/loom/skills/loom-review/.loom-runtime/shared/scripts/loom_check.py +148 -0
- package/payload/plugin/loom/skills/loom-review/.loom-runtime/shared/scripts/loom_init.py +523 -215
- package/payload/plugin/loom/skills/loom-spec-review/.loom-runtime/loom-adopt/SKILL.md +1 -0
- package/payload/plugin/loom/skills/loom-spec-review/.loom-runtime/loom-init/SKILL.md +2 -0
- package/payload/plugin/loom/skills/loom-spec-review/.loom-runtime/loom-init/contract.json +4 -0
- package/payload/plugin/loom/skills/loom-spec-review/.loom-runtime/loom-init/references/output-contract.md +13 -1
- package/payload/plugin/loom/skills/loom-spec-review/.loom-runtime/shared/references/adoption/deep-existing-repo-default.md +4 -0
- package/payload/plugin/loom/skills/loom-spec-review/.loom-runtime/shared/references/adoption/repo-companion-contract.md +3 -1
- package/payload/plugin/loom/skills/loom-spec-review/.loom-runtime/shared/scripts/governance_surface.py +1 -0
- package/payload/plugin/loom/skills/loom-spec-review/.loom-runtime/shared/scripts/loom_check.py +148 -0
- package/payload/plugin/loom/skills/loom-spec-review/.loom-runtime/shared/scripts/loom_init.py +523 -215
- package/payload/plugin/loom/skills/loom-story/.loom-runtime/loom-adopt/SKILL.md +1 -0
- package/payload/plugin/loom/skills/loom-story/.loom-runtime/loom-init/SKILL.md +2 -0
- package/payload/plugin/loom/skills/loom-story/.loom-runtime/loom-init/contract.json +4 -0
- package/payload/plugin/loom/skills/loom-story/.loom-runtime/loom-init/references/output-contract.md +13 -1
- package/payload/plugin/loom/skills/loom-story/.loom-runtime/shared/references/adoption/deep-existing-repo-default.md +4 -0
- package/payload/plugin/loom/skills/loom-story/.loom-runtime/shared/references/adoption/repo-companion-contract.md +3 -1
- package/payload/plugin/loom/skills/loom-story/.loom-runtime/shared/scripts/governance_surface.py +1 -0
- package/payload/plugin/loom/skills/loom-story/.loom-runtime/shared/scripts/loom_check.py +148 -0
- package/payload/plugin/loom/skills/loom-story/.loom-runtime/shared/scripts/loom_init.py +523 -215
- package/payload/plugin/loom/skills/shared/references/adoption/deep-existing-repo-default.md +4 -0
- package/payload/plugin/loom/skills/shared/references/adoption/repo-companion-contract.md +3 -1
- package/payload/plugin/loom/skills/shared/scripts/governance_surface.py +1 -0
- package/payload/plugin/loom/skills/shared/scripts/loom_check.py +148 -0
- package/payload/plugin/loom/skills/shared/scripts/loom_init.py +523 -215
- package/payload/skills/loom-adopt/.loom-runtime/loom-adopt/SKILL.md +1 -0
- package/payload/skills/loom-adopt/.loom-runtime/loom-init/SKILL.md +2 -0
- package/payload/skills/loom-adopt/.loom-runtime/loom-init/contract.json +4 -0
- package/payload/skills/loom-adopt/.loom-runtime/loom-init/references/output-contract.md +13 -1
- package/payload/skills/loom-adopt/.loom-runtime/shared/references/adoption/deep-existing-repo-default.md +4 -0
- package/payload/skills/loom-adopt/.loom-runtime/shared/references/adoption/repo-companion-contract.md +3 -1
- package/payload/skills/loom-adopt/.loom-runtime/shared/scripts/governance_surface.py +1 -0
- package/payload/skills/loom-adopt/.loom-runtime/shared/scripts/loom_check.py +148 -0
- package/payload/skills/loom-adopt/.loom-runtime/shared/scripts/loom_init.py +523 -215
- package/payload/skills/loom-adopt/SKILL.md +1 -0
- package/payload/skills/loom-build/.loom-runtime/loom-adopt/SKILL.md +1 -0
- package/payload/skills/loom-build/.loom-runtime/loom-init/SKILL.md +2 -0
- package/payload/skills/loom-build/.loom-runtime/loom-init/contract.json +4 -0
- package/payload/skills/loom-build/.loom-runtime/loom-init/references/output-contract.md +13 -1
- package/payload/skills/loom-build/.loom-runtime/shared/references/adoption/deep-existing-repo-default.md +4 -0
- package/payload/skills/loom-build/.loom-runtime/shared/references/adoption/repo-companion-contract.md +3 -1
- package/payload/skills/loom-build/.loom-runtime/shared/scripts/governance_surface.py +1 -0
- package/payload/skills/loom-build/.loom-runtime/shared/scripts/loom_check.py +148 -0
- package/payload/skills/loom-build/.loom-runtime/shared/scripts/loom_init.py +523 -215
- package/payload/skills/loom-handoff/.loom-runtime/loom-adopt/SKILL.md +1 -0
- package/payload/skills/loom-handoff/.loom-runtime/loom-init/SKILL.md +2 -0
- package/payload/skills/loom-handoff/.loom-runtime/loom-init/contract.json +4 -0
- package/payload/skills/loom-handoff/.loom-runtime/loom-init/references/output-contract.md +13 -1
- package/payload/skills/loom-handoff/.loom-runtime/shared/references/adoption/deep-existing-repo-default.md +4 -0
- package/payload/skills/loom-handoff/.loom-runtime/shared/references/adoption/repo-companion-contract.md +3 -1
- package/payload/skills/loom-handoff/.loom-runtime/shared/scripts/governance_surface.py +1 -0
- package/payload/skills/loom-handoff/.loom-runtime/shared/scripts/loom_check.py +148 -0
- package/payload/skills/loom-handoff/.loom-runtime/shared/scripts/loom_init.py +523 -215
- package/payload/skills/loom-init/.loom-runtime/loom-adopt/SKILL.md +1 -0
- package/payload/skills/loom-init/.loom-runtime/loom-init/SKILL.md +2 -0
- package/payload/skills/loom-init/.loom-runtime/loom-init/contract.json +4 -0
- package/payload/skills/loom-init/.loom-runtime/loom-init/references/output-contract.md +13 -1
- package/payload/skills/loom-init/.loom-runtime/shared/references/adoption/deep-existing-repo-default.md +4 -0
- package/payload/skills/loom-init/.loom-runtime/shared/references/adoption/repo-companion-contract.md +3 -1
- package/payload/skills/loom-init/.loom-runtime/shared/scripts/governance_surface.py +1 -0
- package/payload/skills/loom-init/.loom-runtime/shared/scripts/loom_check.py +148 -0
- package/payload/skills/loom-init/.loom-runtime/shared/scripts/loom_init.py +523 -215
- package/payload/skills/loom-init/SKILL.md +2 -0
- package/payload/skills/loom-init/contract.json +4 -0
- package/payload/skills/loom-init/references/output-contract.md +13 -1
- package/payload/skills/loom-merge-ready/.loom-runtime/loom-adopt/SKILL.md +1 -0
- package/payload/skills/loom-merge-ready/.loom-runtime/loom-init/SKILL.md +2 -0
- package/payload/skills/loom-merge-ready/.loom-runtime/loom-init/contract.json +4 -0
- package/payload/skills/loom-merge-ready/.loom-runtime/loom-init/references/output-contract.md +13 -1
- package/payload/skills/loom-merge-ready/.loom-runtime/shared/references/adoption/deep-existing-repo-default.md +4 -0
- package/payload/skills/loom-merge-ready/.loom-runtime/shared/references/adoption/repo-companion-contract.md +3 -1
- package/payload/skills/loom-merge-ready/.loom-runtime/shared/scripts/governance_surface.py +1 -0
- package/payload/skills/loom-merge-ready/.loom-runtime/shared/scripts/loom_check.py +148 -0
- package/payload/skills/loom-merge-ready/.loom-runtime/shared/scripts/loom_init.py +523 -215
- package/payload/skills/loom-pre-review/.loom-runtime/loom-adopt/SKILL.md +1 -0
- package/payload/skills/loom-pre-review/.loom-runtime/loom-init/SKILL.md +2 -0
- package/payload/skills/loom-pre-review/.loom-runtime/loom-init/contract.json +4 -0
- package/payload/skills/loom-pre-review/.loom-runtime/loom-init/references/output-contract.md +13 -1
- package/payload/skills/loom-pre-review/.loom-runtime/shared/references/adoption/deep-existing-repo-default.md +4 -0
- package/payload/skills/loom-pre-review/.loom-runtime/shared/references/adoption/repo-companion-contract.md +3 -1
- package/payload/skills/loom-pre-review/.loom-runtime/shared/scripts/governance_surface.py +1 -0
- package/payload/skills/loom-pre-review/.loom-runtime/shared/scripts/loom_check.py +148 -0
- package/payload/skills/loom-pre-review/.loom-runtime/shared/scripts/loom_init.py +523 -215
- package/payload/skills/loom-resume/.loom-runtime/loom-adopt/SKILL.md +1 -0
- package/payload/skills/loom-resume/.loom-runtime/loom-init/SKILL.md +2 -0
- package/payload/skills/loom-resume/.loom-runtime/loom-init/contract.json +4 -0
- package/payload/skills/loom-resume/.loom-runtime/loom-init/references/output-contract.md +13 -1
- package/payload/skills/loom-resume/.loom-runtime/shared/references/adoption/deep-existing-repo-default.md +4 -0
- package/payload/skills/loom-resume/.loom-runtime/shared/references/adoption/repo-companion-contract.md +3 -1
- package/payload/skills/loom-resume/.loom-runtime/shared/scripts/governance_surface.py +1 -0
- package/payload/skills/loom-resume/.loom-runtime/shared/scripts/loom_check.py +148 -0
- package/payload/skills/loom-resume/.loom-runtime/shared/scripts/loom_init.py +523 -215
- package/payload/skills/loom-retire/.loom-runtime/loom-adopt/SKILL.md +1 -0
- package/payload/skills/loom-retire/.loom-runtime/loom-init/SKILL.md +2 -0
- package/payload/skills/loom-retire/.loom-runtime/loom-init/contract.json +4 -0
- package/payload/skills/loom-retire/.loom-runtime/loom-init/references/output-contract.md +13 -1
- package/payload/skills/loom-retire/.loom-runtime/shared/references/adoption/deep-existing-repo-default.md +4 -0
- package/payload/skills/loom-retire/.loom-runtime/shared/references/adoption/repo-companion-contract.md +3 -1
- package/payload/skills/loom-retire/.loom-runtime/shared/scripts/governance_surface.py +1 -0
- package/payload/skills/loom-retire/.loom-runtime/shared/scripts/loom_check.py +148 -0
- package/payload/skills/loom-retire/.loom-runtime/shared/scripts/loom_init.py +523 -215
- package/payload/skills/loom-review/.loom-runtime/loom-adopt/SKILL.md +1 -0
- package/payload/skills/loom-review/.loom-runtime/loom-init/SKILL.md +2 -0
- package/payload/skills/loom-review/.loom-runtime/loom-init/contract.json +4 -0
- package/payload/skills/loom-review/.loom-runtime/loom-init/references/output-contract.md +13 -1
- package/payload/skills/loom-review/.loom-runtime/shared/references/adoption/deep-existing-repo-default.md +4 -0
- package/payload/skills/loom-review/.loom-runtime/shared/references/adoption/repo-companion-contract.md +3 -1
- package/payload/skills/loom-review/.loom-runtime/shared/scripts/governance_surface.py +1 -0
- package/payload/skills/loom-review/.loom-runtime/shared/scripts/loom_check.py +148 -0
- package/payload/skills/loom-review/.loom-runtime/shared/scripts/loom_init.py +523 -215
- package/payload/skills/loom-spec-review/.loom-runtime/loom-adopt/SKILL.md +1 -0
- package/payload/skills/loom-spec-review/.loom-runtime/loom-init/SKILL.md +2 -0
- package/payload/skills/loom-spec-review/.loom-runtime/loom-init/contract.json +4 -0
- package/payload/skills/loom-spec-review/.loom-runtime/loom-init/references/output-contract.md +13 -1
- package/payload/skills/loom-spec-review/.loom-runtime/shared/references/adoption/deep-existing-repo-default.md +4 -0
- package/payload/skills/loom-spec-review/.loom-runtime/shared/references/adoption/repo-companion-contract.md +3 -1
- package/payload/skills/loom-spec-review/.loom-runtime/shared/scripts/governance_surface.py +1 -0
- package/payload/skills/loom-spec-review/.loom-runtime/shared/scripts/loom_check.py +148 -0
- package/payload/skills/loom-spec-review/.loom-runtime/shared/scripts/loom_init.py +523 -215
- package/payload/skills/loom-story/.loom-runtime/loom-adopt/SKILL.md +1 -0
- package/payload/skills/loom-story/.loom-runtime/loom-init/SKILL.md +2 -0
- package/payload/skills/loom-story/.loom-runtime/loom-init/contract.json +4 -0
- package/payload/skills/loom-story/.loom-runtime/loom-init/references/output-contract.md +13 -1
- package/payload/skills/loom-story/.loom-runtime/shared/references/adoption/deep-existing-repo-default.md +4 -0
- package/payload/skills/loom-story/.loom-runtime/shared/references/adoption/repo-companion-contract.md +3 -1
- package/payload/skills/loom-story/.loom-runtime/shared/scripts/governance_surface.py +1 -0
- package/payload/skills/loom-story/.loom-runtime/shared/scripts/loom_check.py +148 -0
- package/payload/skills/loom-story/.loom-runtime/shared/scripts/loom_init.py +523 -215
|
@@ -38,6 +38,63 @@ ADOPTION_INTENTS = (
|
|
|
38
38
|
)
|
|
39
39
|
UNSPECIFIED_ADOPTION_INTENT = "unspecified"
|
|
40
40
|
NON_WRITABLE_ADOPTION_PATHS = {"defer", "skill-install-only"}
|
|
41
|
+
SCAFFOLD_PROFILES = (
|
|
42
|
+
"observe-only",
|
|
43
|
+
"skill-install-only",
|
|
44
|
+
"attach-only",
|
|
45
|
+
"light-governance",
|
|
46
|
+
"execution-control",
|
|
47
|
+
"strong-governance",
|
|
48
|
+
)
|
|
49
|
+
ATTACH_ONLY_FORBIDDEN_AUTHORED_CARRIERS = (
|
|
50
|
+
{
|
|
51
|
+
"path": ".loom/work-items/**",
|
|
52
|
+
"reason": "attach-only preserves host-owned work item truth",
|
|
53
|
+
"remediation": "migrate the item to a host truth locator, delete the competing Loom carrier, or rerun with --intent execution-control",
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"path": ".loom/progress/**",
|
|
57
|
+
"reason": "attach-only preserves host-owned recovery/progress truth",
|
|
58
|
+
"remediation": "migrate recovery state to a host truth locator, delete the competing Loom carrier, or rerun with --intent execution-control",
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"path": ".loom/status/current.md",
|
|
62
|
+
"reason": "attach-only preserves host-owned project status truth",
|
|
63
|
+
"remediation": "migrate status to a host truth locator, delete the competing Loom carrier, or rerun with --intent execution-control",
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"path": ".loom/reviews/**",
|
|
67
|
+
"reason": "attach-only preserves host-owned PR review or guardian truth",
|
|
68
|
+
"remediation": "migrate review truth to a host truth locator, delete the competing Loom carrier, or rerun with --intent execution-control",
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
"path": ".loom/specs/**",
|
|
72
|
+
"reason": "attach-only does not author Loom spec truth unless the repo explicitly upgrades intent",
|
|
73
|
+
"remediation": "migrate spec truth to a host locator, delete the competing Loom carrier, or rerun with --intent execution-control",
|
|
74
|
+
},
|
|
75
|
+
)
|
|
76
|
+
ATTACH_ONLY_HOST_TRUTH_LOCATORS = {
|
|
77
|
+
"work_item": {
|
|
78
|
+
"host_surface": "github_issue",
|
|
79
|
+
"locator": "repo-owned issue tracker",
|
|
80
|
+
"mode": "host_truth_locator",
|
|
81
|
+
},
|
|
82
|
+
"project_status": {
|
|
83
|
+
"host_surface": "github_project",
|
|
84
|
+
"locator": "repo-owned project board or status system",
|
|
85
|
+
"mode": "host_truth_locator",
|
|
86
|
+
},
|
|
87
|
+
"review": {
|
|
88
|
+
"host_surface": "pull_request_review_or_guardian",
|
|
89
|
+
"locator": "repo-owned PR review, guardian, or review gate",
|
|
90
|
+
"mode": "host_truth_locator",
|
|
91
|
+
},
|
|
92
|
+
"closeout": {
|
|
93
|
+
"host_surface": "pull_request_metadata_and_issue_state",
|
|
94
|
+
"locator": "repo-owned PR metadata plus issue state",
|
|
95
|
+
"mode": "host_truth_locator",
|
|
96
|
+
},
|
|
97
|
+
}
|
|
41
98
|
|
|
42
99
|
RUNTIME_ARTIFACT_SOURCES = {
|
|
43
100
|
".loom/bin/loom_init.py": RUNTIME_SOURCE,
|
|
@@ -720,6 +777,183 @@ def is_heavy_execution_path(adoption_path: str) -> bool:
|
|
|
720
777
|
return adoption_path == "full-bootstrap"
|
|
721
778
|
|
|
722
779
|
|
|
780
|
+
def scaffold_profile_key(adoption_path: str, intake: dict[str, object]) -> str:
|
|
781
|
+
requested = str(intake.get("adoption_intent", UNSPECIFIED_ADOPTION_INTENT))
|
|
782
|
+
if requested in SCAFFOLD_PROFILES:
|
|
783
|
+
return requested
|
|
784
|
+
if adoption_path == "defer":
|
|
785
|
+
return "observe-only"
|
|
786
|
+
if adoption_path == "skill-install-only":
|
|
787
|
+
return "skill-install-only"
|
|
788
|
+
if uses_attach_only_path(adoption_path):
|
|
789
|
+
return "attach-only"
|
|
790
|
+
if adoption_path == "full-bootstrap":
|
|
791
|
+
return "execution-control"
|
|
792
|
+
return "light-governance"
|
|
793
|
+
|
|
794
|
+
|
|
795
|
+
def profile_has_work_item_carriers(profile: str) -> bool:
|
|
796
|
+
return profile in {"execution-control", "strong-governance"}
|
|
797
|
+
|
|
798
|
+
|
|
799
|
+
def profile_writes_artifacts(profile: str) -> bool:
|
|
800
|
+
return profile not in {"observe-only", "skill-install-only"}
|
|
801
|
+
|
|
802
|
+
|
|
803
|
+
def forbidden_authored_carriers(profile: str) -> list[dict[str, str]]:
|
|
804
|
+
if profile != "attach-only":
|
|
805
|
+
return []
|
|
806
|
+
return [dict(carrier) for carrier in ATTACH_ONLY_FORBIDDEN_AUTHORED_CARRIERS]
|
|
807
|
+
|
|
808
|
+
|
|
809
|
+
def required_carriers_for_profile(artifacts: list[dict[str, str]], profile: str) -> list[dict[str, str]]:
|
|
810
|
+
if profile in {"observe-only", "skill-install-only"}:
|
|
811
|
+
return []
|
|
812
|
+
return [
|
|
813
|
+
{
|
|
814
|
+
"path": artifact["path"],
|
|
815
|
+
"kind": artifact["kind"],
|
|
816
|
+
"owner": write_owner_for_path(artifact["path"]),
|
|
817
|
+
}
|
|
818
|
+
for artifact in artifacts
|
|
819
|
+
if isinstance(artifact.get("path"), str) and isinstance(artifact.get("kind"), str)
|
|
820
|
+
]
|
|
821
|
+
|
|
822
|
+
|
|
823
|
+
def normalize_relative_path(raw_path: object) -> str | None:
|
|
824
|
+
if not isinstance(raw_path, str) or not raw_path:
|
|
825
|
+
return None
|
|
826
|
+
normalized = raw_path.replace("\\", "/")
|
|
827
|
+
while normalized.startswith("./"):
|
|
828
|
+
normalized = normalized[2:]
|
|
829
|
+
if normalized.startswith("/") or normalized.startswith("../") or "/../" in normalized:
|
|
830
|
+
return None
|
|
831
|
+
return normalized
|
|
832
|
+
|
|
833
|
+
|
|
834
|
+
def matches_forbidden_authored_carrier(relative_path: str, pattern: str) -> bool:
|
|
835
|
+
if pattern.endswith("/**"):
|
|
836
|
+
prefix = pattern[:-3]
|
|
837
|
+
return relative_path == prefix or relative_path.startswith(prefix + "/")
|
|
838
|
+
return relative_path == pattern
|
|
839
|
+
|
|
840
|
+
|
|
841
|
+
def forbidden_authored_carrier_for_path(relative_path: str) -> dict[str, str] | None:
|
|
842
|
+
for carrier in ATTACH_ONLY_FORBIDDEN_AUTHORED_CARRIERS:
|
|
843
|
+
pattern = carrier["path"]
|
|
844
|
+
if matches_forbidden_authored_carrier(relative_path, pattern):
|
|
845
|
+
return carrier
|
|
846
|
+
return None
|
|
847
|
+
|
|
848
|
+
|
|
849
|
+
def collect_forbidden_authored_carrier_declarations(result: dict[str, object]) -> list[dict[str, str]]:
|
|
850
|
+
declarations: list[dict[str, str]] = []
|
|
851
|
+
|
|
852
|
+
def add(raw_path: object, source: str) -> None:
|
|
853
|
+
relative = normalize_relative_path(raw_path)
|
|
854
|
+
if relative is None:
|
|
855
|
+
return
|
|
856
|
+
carrier = forbidden_authored_carrier_for_path(relative)
|
|
857
|
+
if carrier is not None:
|
|
858
|
+
declarations.append({"path": relative, "pattern": carrier["path"], "source": source})
|
|
859
|
+
|
|
860
|
+
for key in ("initial_artifacts", "planned_writes"):
|
|
861
|
+
entries = result.get(key)
|
|
862
|
+
if isinstance(entries, list):
|
|
863
|
+
for entry in entries:
|
|
864
|
+
if isinstance(entry, dict):
|
|
865
|
+
add(entry.get("path"), key)
|
|
866
|
+
work_items = result.get("initial_work_items")
|
|
867
|
+
if isinstance(work_items, list):
|
|
868
|
+
for work_item in work_items:
|
|
869
|
+
if not isinstance(work_item, dict):
|
|
870
|
+
continue
|
|
871
|
+
artifacts = work_item.get("artifacts")
|
|
872
|
+
if isinstance(artifacts, list):
|
|
873
|
+
for artifact in artifacts:
|
|
874
|
+
add(artifact, "initial_work_items.artifacts")
|
|
875
|
+
write = result.get("write")
|
|
876
|
+
if isinstance(write, dict):
|
|
877
|
+
touched = write.get("touched")
|
|
878
|
+
if isinstance(touched, list):
|
|
879
|
+
for path in touched:
|
|
880
|
+
add(path, "write.touched")
|
|
881
|
+
return declarations
|
|
882
|
+
|
|
883
|
+
|
|
884
|
+
def collect_forbidden_authored_carrier_files(target_root: Path) -> list[dict[str, str]]:
|
|
885
|
+
found: list[dict[str, str]] = []
|
|
886
|
+
for carrier in ATTACH_ONLY_FORBIDDEN_AUTHORED_CARRIERS:
|
|
887
|
+
pattern = carrier["path"]
|
|
888
|
+
if pattern.endswith("/**"):
|
|
889
|
+
prefix = pattern[:-3]
|
|
890
|
+
base = target_root / prefix
|
|
891
|
+
if not base.exists():
|
|
892
|
+
continue
|
|
893
|
+
if base.is_file():
|
|
894
|
+
found.append({"path": prefix, "pattern": pattern, "source": "filesystem"})
|
|
895
|
+
continue
|
|
896
|
+
for path in sorted(candidate for candidate in base.rglob("*") if candidate.is_file()):
|
|
897
|
+
found.append(
|
|
898
|
+
{
|
|
899
|
+
"path": path.relative_to(target_root).as_posix(),
|
|
900
|
+
"pattern": pattern,
|
|
901
|
+
"source": "filesystem",
|
|
902
|
+
}
|
|
903
|
+
)
|
|
904
|
+
continue
|
|
905
|
+
exact = target_root / pattern
|
|
906
|
+
if exact.exists():
|
|
907
|
+
found.append({"path": pattern, "pattern": pattern, "source": "filesystem"})
|
|
908
|
+
return found
|
|
909
|
+
|
|
910
|
+
|
|
911
|
+
def collect_forbidden_manifest_declarations(target_root: Path) -> list[dict[str, str]]:
|
|
912
|
+
manifest_path = target_root / ".loom/bootstrap/manifest.json"
|
|
913
|
+
if not manifest_path.exists():
|
|
914
|
+
return []
|
|
915
|
+
try:
|
|
916
|
+
manifest = read_json(manifest_path)
|
|
917
|
+
except json.JSONDecodeError:
|
|
918
|
+
return []
|
|
919
|
+
artifacts = manifest.get("artifacts")
|
|
920
|
+
declarations: list[dict[str, str]] = []
|
|
921
|
+
if not isinstance(artifacts, list):
|
|
922
|
+
return declarations
|
|
923
|
+
for artifact in artifacts:
|
|
924
|
+
if not isinstance(artifact, dict):
|
|
925
|
+
continue
|
|
926
|
+
relative = normalize_relative_path(artifact.get("path"))
|
|
927
|
+
if relative is None:
|
|
928
|
+
continue
|
|
929
|
+
carrier = forbidden_authored_carrier_for_path(relative)
|
|
930
|
+
if carrier is not None:
|
|
931
|
+
declarations.append({"path": relative, "pattern": carrier["path"], "source": "manifest.artifacts"})
|
|
932
|
+
return declarations
|
|
933
|
+
|
|
934
|
+
|
|
935
|
+
def attach_only_forbidden_carrier_errors(target_root: Path, result: dict[str, object]) -> list[str]:
|
|
936
|
+
findings = (
|
|
937
|
+
collect_forbidden_authored_carrier_declarations(result)
|
|
938
|
+
+ collect_forbidden_manifest_declarations(target_root)
|
|
939
|
+
+ collect_forbidden_authored_carrier_files(target_root)
|
|
940
|
+
)
|
|
941
|
+
errors: list[str] = []
|
|
942
|
+
seen: set[tuple[str, str, str]] = set()
|
|
943
|
+
for finding in findings:
|
|
944
|
+
key = (finding["source"], finding["path"], finding["pattern"])
|
|
945
|
+
if key in seen:
|
|
946
|
+
continue
|
|
947
|
+
seen.add(key)
|
|
948
|
+
errors.append(
|
|
949
|
+
"attach-only forbidden authored carrier detected in "
|
|
950
|
+
f"{finding['source']}: `{finding['path']}` matches `{finding['pattern']}`; "
|
|
951
|
+
"this would create a second truth chain. Migrate it to the host truth locator, delete it, "
|
|
952
|
+
"or explicitly rerun bootstrap with `--intent execution-control`."
|
|
953
|
+
)
|
|
954
|
+
return errors
|
|
955
|
+
|
|
956
|
+
|
|
723
957
|
def adoption_intent_payload(adoption_path: str, intake: dict[str, object]) -> dict[str, object]:
|
|
724
958
|
requested = str(intake.get("adoption_intent", UNSPECIFIED_ADOPTION_INTENT))
|
|
725
959
|
source = str(intake.get("adoption_intent_source", "unspecified"))
|
|
@@ -795,7 +1029,28 @@ def rule_refs_for_capabilities(scenario: str, adoption_path: str) -> list[dict[s
|
|
|
795
1029
|
return common
|
|
796
1030
|
|
|
797
1031
|
|
|
798
|
-
def deferred_capabilities(scenario: str, adoption_path: str) -> list[dict[str, str]]:
|
|
1032
|
+
def deferred_capabilities(scenario: str, adoption_path: str, profile: str) -> list[dict[str, str]]:
|
|
1033
|
+
if profile == "light-governance":
|
|
1034
|
+
return [
|
|
1035
|
+
{
|
|
1036
|
+
"name": "loom-owned-work-item-progress-status",
|
|
1037
|
+
"reason": "light-governance keeps first-round adoption to a companion, review/spec, and PR-template loop",
|
|
1038
|
+
"upgrade_trigger": "the repo explicitly opts into execution-control or needs Loom-owned recovery/status carriers",
|
|
1039
|
+
},
|
|
1040
|
+
{
|
|
1041
|
+
"name": "host-gate-merge-closeout-control",
|
|
1042
|
+
"reason": "light-governance does not claim host merge, release, or closeout control",
|
|
1043
|
+
"upgrade_trigger": "required checks, merge-ready, or closeout must be consumed as Loom-owned gates",
|
|
1044
|
+
},
|
|
1045
|
+
]
|
|
1046
|
+
if profile == "execution-control":
|
|
1047
|
+
return [
|
|
1048
|
+
{
|
|
1049
|
+
"name": "strong-governance-host-gates",
|
|
1050
|
+
"reason": "execution-control writes Loom-owned execution carriers but does not require host merge and closeout gates as a profile precondition",
|
|
1051
|
+
"upgrade_trigger": "host required checks, controlled merge, or closeout reconciliation become part of the adoption contract",
|
|
1052
|
+
}
|
|
1053
|
+
]
|
|
799
1054
|
if scenario == "new":
|
|
800
1055
|
return [
|
|
801
1056
|
{
|
|
@@ -844,6 +1099,97 @@ def deferred_capabilities(scenario: str, adoption_path: str) -> list[dict[str, s
|
|
|
844
1099
|
]
|
|
845
1100
|
|
|
846
1101
|
|
|
1102
|
+
def upgrade_triggers(deferred: list[dict[str, str]], profile: str) -> list[dict[str, str]]:
|
|
1103
|
+
return [
|
|
1104
|
+
{
|
|
1105
|
+
"from_profile": profile,
|
|
1106
|
+
"capability": item["name"],
|
|
1107
|
+
"trigger": item["upgrade_trigger"],
|
|
1108
|
+
}
|
|
1109
|
+
for item in deferred
|
|
1110
|
+
if item.get("upgrade_trigger")
|
|
1111
|
+
]
|
|
1112
|
+
|
|
1113
|
+
|
|
1114
|
+
def profile_common_artifacts() -> list[dict[str, str]]:
|
|
1115
|
+
artifacts: list[dict[str, str]] = [
|
|
1116
|
+
{"path": ".loom/README.md", "kind": "rule-entry", "source": "generated"},
|
|
1117
|
+
{"path": ".loom/bootstrap/intake.snapshot.json", "kind": "intake", "source": "generated"},
|
|
1118
|
+
{"path": ".loom/bootstrap/init-result.json", "kind": "init-result", "source": "generated"},
|
|
1119
|
+
{"path": ".loom/bootstrap/manifest.json", "kind": "manifest", "source": "generated"},
|
|
1120
|
+
{"path": ".loom/bootstrap/capability-map.md", "kind": "capability-map", "source": "generated"},
|
|
1121
|
+
{"path": ".loom/companion/README.md", "kind": "repo-companion-entry", "source": "generated"},
|
|
1122
|
+
{"path": ".loom/companion/manifest.json", "kind": "repo-companion-manifest", "source": "generated"},
|
|
1123
|
+
{"path": ".loom/companion/repo-interface.json", "kind": "repo-companion-interface", "source": "generated"},
|
|
1124
|
+
{"path": ".loom/companion/interop.json", "kind": "repo-interop-contract", "source": "generated"},
|
|
1125
|
+
{"path": ".loom/companion/checkpoints.md", "kind": "repo-companion-doc", "source": "generated"},
|
|
1126
|
+
{"path": ".loom/companion/review.md", "kind": "repo-companion-doc", "source": "generated"},
|
|
1127
|
+
{"path": ".loom/companion/merge-ready.md", "kind": "repo-companion-doc", "source": "generated"},
|
|
1128
|
+
{"path": ".loom/companion/closeout.md", "kind": "repo-companion-doc", "source": "generated"},
|
|
1129
|
+
{"path": ".loom/companion/releases/changelog.md", "kind": "repo-release-surface", "source": "generated"},
|
|
1130
|
+
{"path": ".loom/companion/releases/release-notes.md", "kind": "repo-release-surface", "source": "generated"},
|
|
1131
|
+
{"path": ".loom/companion/releases/migration-notes.md", "kind": "repo-release-surface", "source": "generated"},
|
|
1132
|
+
{"path": ".loom/companion/releases/rollback.md", "kind": "repo-release-surface", "source": "generated"},
|
|
1133
|
+
{"path": ".loom/companion/releases/catalog.json", "kind": "repo-release-surface", "source": "generated"},
|
|
1134
|
+
{"path": ".loom/companion/releases/current.json", "kind": "repo-release-surface", "source": "generated"},
|
|
1135
|
+
{"path": ".loom/companion/releases/status.json", "kind": "repo-release-surface", "source": "generated"},
|
|
1136
|
+
{"path": ".loom/shadow/admission-loom.json", "kind": "shadow-parity-surface", "source": "generated"},
|
|
1137
|
+
{"path": ".loom/shadow/admission-repo.json", "kind": "shadow-parity-surface", "source": "generated"},
|
|
1138
|
+
{"path": ".loom/shadow/review-loom.json", "kind": "shadow-parity-surface", "source": "generated"},
|
|
1139
|
+
{"path": ".loom/shadow/review-repo.json", "kind": "shadow-parity-surface", "source": "generated"},
|
|
1140
|
+
{"path": ".loom/shadow/merge-ready-loom.json", "kind": "shadow-parity-surface", "source": "generated"},
|
|
1141
|
+
{"path": ".loom/shadow/merge-ready-repo.json", "kind": "shadow-parity-surface", "source": "generated"},
|
|
1142
|
+
{"path": ".loom/shadow/closeout-loom.json", "kind": "shadow-parity-surface", "source": "generated"},
|
|
1143
|
+
{"path": ".loom/shadow/closeout-repo.json", "kind": "shadow-parity-surface", "source": "generated"},
|
|
1144
|
+
{"path": ".gitignore", "kind": "gitignore", "source": "generated"},
|
|
1145
|
+
runtime_artifact(".loom/bin/loom_init.py", "loom-tool", RUNTIME_SOURCE),
|
|
1146
|
+
runtime_artifact(".loom/bin/fact_chain_support.py", "loom-tool-support", FACT_CHAIN_RUNTIME_SOURCE),
|
|
1147
|
+
runtime_artifact(".loom/bin/governance_surface.py", "loom-tool-support", GOVERNANCE_RUNTIME_SOURCE),
|
|
1148
|
+
runtime_artifact(".loom/bin/loom_flow.py", "loom-tool", FLOW_RUNTIME_SOURCE),
|
|
1149
|
+
runtime_artifact(".loom/bin/loom_status.py", "loom-tool", STATUS_RUNTIME_SOURCE),
|
|
1150
|
+
runtime_artifact(".loom/bin/runtime_paths.py", "loom-tool-support", "skills/shared/scripts/runtime_paths.py"),
|
|
1151
|
+
runtime_artifact(".loom/bin/runtime_state.py", "loom-tool-support", "skills/shared/scripts/runtime_state.py"),
|
|
1152
|
+
runtime_artifact(".loom/bin/loom_check.py", "loom-tool", CHECK_RUNTIME_SOURCE),
|
|
1153
|
+
]
|
|
1154
|
+
return artifacts
|
|
1155
|
+
|
|
1156
|
+
|
|
1157
|
+
def profile_light_artifacts(target_root: Path) -> list[dict[str, str]]:
|
|
1158
|
+
artifacts: list[dict[str, str]] = []
|
|
1159
|
+
if not (target_root / "AGENTS.md").exists():
|
|
1160
|
+
artifacts.append({"path": "AGENTS.md", "kind": "root-entry", "source": "generated"})
|
|
1161
|
+
artifacts.extend(
|
|
1162
|
+
[
|
|
1163
|
+
{"path": ".loom/reviews/INIT-0001.json", "kind": "review-entry", "source": "generated"},
|
|
1164
|
+
{"path": ".loom/reviews/INIT-0001.spec.json", "kind": "review-entry", "source": "generated"},
|
|
1165
|
+
{"path": ".loom/specs/INIT-0001/spec.md", "kind": "spec", "source": "skills/shared/assets/templates/scaffold/spec.md"},
|
|
1166
|
+
{"path": ".loom/specs/INIT-0001/plan.md", "kind": "plan", "source": "skills/shared/assets/templates/scaffold/plan.md"},
|
|
1167
|
+
{
|
|
1168
|
+
"path": ".loom/specs/INIT-0001/implementation-contract.md",
|
|
1169
|
+
"kind": "implementation-contract",
|
|
1170
|
+
"source": "skills/shared/assets/templates/scaffold/implementation-contract.md",
|
|
1171
|
+
},
|
|
1172
|
+
]
|
|
1173
|
+
)
|
|
1174
|
+
return artifacts
|
|
1175
|
+
|
|
1176
|
+
|
|
1177
|
+
def profile_execution_artifacts(target_root: Path) -> list[dict[str, str]]:
|
|
1178
|
+
artifacts = profile_light_artifacts(target_root)
|
|
1179
|
+
artifacts.extend(
|
|
1180
|
+
[
|
|
1181
|
+
{"path": ".loom/work-items/INIT-0001.md", "kind": "work-item", "source": "generated"},
|
|
1182
|
+
{"path": ".loom/progress/INIT-0001.md", "kind": "progress", "source": "generated"},
|
|
1183
|
+
{"path": ".loom/status/current.md", "kind": "status-surface", "source": "generated"},
|
|
1184
|
+
]
|
|
1185
|
+
)
|
|
1186
|
+
return artifacts
|
|
1187
|
+
|
|
1188
|
+
|
|
1189
|
+
def artifact_paths(artifacts: list[dict[str, str]]) -> list[str]:
|
|
1190
|
+
return [artifact["path"] for artifact in artifacts]
|
|
1191
|
+
|
|
1192
|
+
|
|
847
1193
|
def attach_only_artifact_paths(target_root: Path, install_pr_template: bool) -> list[str]:
|
|
848
1194
|
artifacts = [
|
|
849
1195
|
".loom/README.md",
|
|
@@ -869,7 +1215,13 @@ def attach_only_artifact_paths(target_root: Path, install_pr_template: bool) ->
|
|
|
869
1215
|
return artifacts
|
|
870
1216
|
|
|
871
1217
|
|
|
872
|
-
def initial_work_items(
|
|
1218
|
+
def initial_work_items(
|
|
1219
|
+
scenario: str,
|
|
1220
|
+
target_root: Path,
|
|
1221
|
+
adoption_path: str,
|
|
1222
|
+
install_pr_template: bool,
|
|
1223
|
+
profile: str,
|
|
1224
|
+
) -> list[dict[str, object]]:
|
|
873
1225
|
if adoption_path in NON_WRITABLE_ADOPTION_PATHS:
|
|
874
1226
|
return []
|
|
875
1227
|
if uses_attach_only_path(adoption_path):
|
|
@@ -889,26 +1241,7 @@ def initial_work_items(scenario: str, target_root: Path, adoption_path: str, ins
|
|
|
889
1241
|
"owner_for_checkpoint_lite": "repository owner or current attach operator",
|
|
890
1242
|
}
|
|
891
1243
|
]
|
|
892
|
-
artifacts =
|
|
893
|
-
".loom/bootstrap/init-result.json",
|
|
894
|
-
".loom/work-items/INIT-0001.md",
|
|
895
|
-
".loom/progress/INIT-0001.md",
|
|
896
|
-
".loom/reviews/INIT-0001.json",
|
|
897
|
-
".loom/reviews/INIT-0001.spec.json",
|
|
898
|
-
".loom/status/current.md",
|
|
899
|
-
".loom/bin/loom_init.py",
|
|
900
|
-
".loom/bin/fact_chain_support.py",
|
|
901
|
-
".loom/bin/governance_surface.py",
|
|
902
|
-
".loom/bin/loom_flow.py",
|
|
903
|
-
".loom/bin/loom_status.py",
|
|
904
|
-
".loom/bin/runtime_paths.py",
|
|
905
|
-
".loom/bin/loom_check.py",
|
|
906
|
-
".loom/specs/INIT-0001/spec.md",
|
|
907
|
-
".loom/specs/INIT-0001/plan.md",
|
|
908
|
-
".loom/specs/INIT-0001/implementation-contract.md",
|
|
909
|
-
]
|
|
910
|
-
if not (target_root / ".github/PULL_REQUEST_TEMPLATE.md").exists():
|
|
911
|
-
artifacts.append(".github/PULL_REQUEST_TEMPLATE.md")
|
|
1244
|
+
artifacts = artifact_paths(initial_artifacts(target_root, install_pr_template, adoption_path, profile))
|
|
912
1245
|
return [
|
|
913
1246
|
{
|
|
914
1247
|
"id": WORK_ITEM_ID,
|
|
@@ -927,125 +1260,15 @@ def initial_work_items(scenario: str, target_root: Path, adoption_path: str, ins
|
|
|
927
1260
|
]
|
|
928
1261
|
|
|
929
1262
|
|
|
930
|
-
def initial_artifacts(target_root: Path, install_pr_template: bool, adoption_path: str) -> list[dict[str, str]]:
|
|
931
|
-
if
|
|
1263
|
+
def initial_artifacts(target_root: Path, install_pr_template: bool, adoption_path: str, profile: str) -> list[dict[str, str]]:
|
|
1264
|
+
if not profile_writes_artifacts(profile):
|
|
932
1265
|
return []
|
|
933
1266
|
|
|
934
|
-
artifacts =
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
},
|
|
940
|
-
{
|
|
941
|
-
"path": ".loom/bootstrap/intake.snapshot.json",
|
|
942
|
-
"kind": "intake",
|
|
943
|
-
"source": "generated",
|
|
944
|
-
},
|
|
945
|
-
{
|
|
946
|
-
"path": ".loom/bootstrap/init-result.json",
|
|
947
|
-
"kind": "init-result",
|
|
948
|
-
"source": "generated",
|
|
949
|
-
},
|
|
950
|
-
{
|
|
951
|
-
"path": ".loom/bootstrap/manifest.json",
|
|
952
|
-
"kind": "manifest",
|
|
953
|
-
"source": "generated",
|
|
954
|
-
},
|
|
955
|
-
{
|
|
956
|
-
"path": ".loom/bootstrap/capability-map.md",
|
|
957
|
-
"kind": "capability-map",
|
|
958
|
-
"source": "generated",
|
|
959
|
-
},
|
|
960
|
-
runtime_artifact(".loom/bin/loom_init.py", "loom-tool", RUNTIME_SOURCE),
|
|
961
|
-
runtime_artifact(".loom/bin/fact_chain_support.py", "loom-tool-support", FACT_CHAIN_RUNTIME_SOURCE),
|
|
962
|
-
runtime_artifact(".loom/bin/governance_surface.py", "loom-tool-support", GOVERNANCE_RUNTIME_SOURCE),
|
|
963
|
-
runtime_artifact(".loom/bin/loom_flow.py", "loom-tool", FLOW_RUNTIME_SOURCE),
|
|
964
|
-
runtime_artifact(".loom/bin/loom_status.py", "loom-tool", STATUS_RUNTIME_SOURCE),
|
|
965
|
-
runtime_artifact(".loom/bin/runtime_paths.py", "loom-tool-support", "skills/shared/scripts/runtime_paths.py"),
|
|
966
|
-
runtime_artifact(".loom/bin/runtime_state.py", "loom-tool-support", "skills/shared/scripts/runtime_state.py"),
|
|
967
|
-
runtime_artifact(".loom/bin/loom_check.py", "loom-tool", CHECK_RUNTIME_SOURCE),
|
|
968
|
-
]
|
|
969
|
-
if uses_attach_only_path(adoption_path):
|
|
970
|
-
artifacts.extend(
|
|
971
|
-
[
|
|
972
|
-
{
|
|
973
|
-
"path": ".loom/companion/README.md",
|
|
974
|
-
"kind": "repo-companion-entry",
|
|
975
|
-
"source": "generated",
|
|
976
|
-
},
|
|
977
|
-
{
|
|
978
|
-
"path": ".loom/companion/checkpoints.md",
|
|
979
|
-
"kind": "repo-companion-doc",
|
|
980
|
-
"source": "generated",
|
|
981
|
-
},
|
|
982
|
-
{
|
|
983
|
-
"path": ".loom/companion/review.md",
|
|
984
|
-
"kind": "repo-companion-doc",
|
|
985
|
-
"source": "generated",
|
|
986
|
-
},
|
|
987
|
-
{
|
|
988
|
-
"path": ".loom/companion/merge-ready.md",
|
|
989
|
-
"kind": "repo-companion-doc",
|
|
990
|
-
"source": "generated",
|
|
991
|
-
},
|
|
992
|
-
{
|
|
993
|
-
"path": ".loom/companion/closeout.md",
|
|
994
|
-
"kind": "repo-companion-doc",
|
|
995
|
-
"source": "generated",
|
|
996
|
-
},
|
|
997
|
-
]
|
|
998
|
-
)
|
|
999
|
-
else:
|
|
1000
|
-
artifacts.extend(
|
|
1001
|
-
[
|
|
1002
|
-
{
|
|
1003
|
-
"path": "AGENTS.md",
|
|
1004
|
-
"kind": "root-entry",
|
|
1005
|
-
"source": "generated",
|
|
1006
|
-
},
|
|
1007
|
-
{
|
|
1008
|
-
"path": ".loom/work-items/INIT-0001.md",
|
|
1009
|
-
"kind": "work-item",
|
|
1010
|
-
"source": "generated",
|
|
1011
|
-
},
|
|
1012
|
-
{
|
|
1013
|
-
"path": ".loom/progress/INIT-0001.md",
|
|
1014
|
-
"kind": "progress",
|
|
1015
|
-
"source": "generated",
|
|
1016
|
-
},
|
|
1017
|
-
{
|
|
1018
|
-
"path": ".loom/reviews/INIT-0001.json",
|
|
1019
|
-
"kind": "review-entry",
|
|
1020
|
-
"source": "generated",
|
|
1021
|
-
},
|
|
1022
|
-
{
|
|
1023
|
-
"path": ".loom/reviews/INIT-0001.spec.json",
|
|
1024
|
-
"kind": "review-entry",
|
|
1025
|
-
"source": "generated",
|
|
1026
|
-
},
|
|
1027
|
-
{
|
|
1028
|
-
"path": ".loom/status/current.md",
|
|
1029
|
-
"kind": "status-surface",
|
|
1030
|
-
"source": "generated",
|
|
1031
|
-
},
|
|
1032
|
-
{
|
|
1033
|
-
"path": ".loom/specs/INIT-0001/spec.md",
|
|
1034
|
-
"kind": "spec",
|
|
1035
|
-
"source": "skills/shared/assets/templates/scaffold/spec.md",
|
|
1036
|
-
},
|
|
1037
|
-
{
|
|
1038
|
-
"path": ".loom/specs/INIT-0001/plan.md",
|
|
1039
|
-
"kind": "plan",
|
|
1040
|
-
"source": "skills/shared/assets/templates/scaffold/plan.md",
|
|
1041
|
-
},
|
|
1042
|
-
{
|
|
1043
|
-
"path": ".loom/specs/INIT-0001/implementation-contract.md",
|
|
1044
|
-
"kind": "implementation-contract",
|
|
1045
|
-
"source": "skills/shared/assets/templates/scaffold/implementation-contract.md",
|
|
1046
|
-
},
|
|
1047
|
-
]
|
|
1048
|
-
)
|
|
1267
|
+
artifacts = profile_common_artifacts()
|
|
1268
|
+
if profile == "light-governance":
|
|
1269
|
+
artifacts.extend(profile_light_artifacts(target_root))
|
|
1270
|
+
elif profile in {"execution-control", "strong-governance"}:
|
|
1271
|
+
artifacts.extend(profile_execution_artifacts(target_root))
|
|
1049
1272
|
if install_pr_template or not (target_root / ".github/PULL_REQUEST_TEMPLATE.md").exists():
|
|
1050
1273
|
artifacts.append(
|
|
1051
1274
|
{
|
|
@@ -1144,18 +1367,25 @@ def planned_write_targets(result: dict[str, object], adoption_path: str) -> list
|
|
|
1144
1367
|
return planned
|
|
1145
1368
|
|
|
1146
1369
|
|
|
1147
|
-
def intentionally_absent_targets(adoption_path: str) -> list[dict[str, str]]:
|
|
1148
|
-
if
|
|
1370
|
+
def intentionally_absent_targets(adoption_path: str, profile: str) -> list[dict[str, str]]:
|
|
1371
|
+
if profile == "attach-only":
|
|
1149
1372
|
return [
|
|
1150
1373
|
{"path": ".loom/work-items/**", "reason": "attach-only preserves host-owned work item truth"},
|
|
1151
1374
|
{"path": ".loom/progress/**", "reason": "attach-only preserves host-owned recovery truth"},
|
|
1152
1375
|
{"path": ".loom/status/current.md", "reason": "attach-only does not author Loom status truth"},
|
|
1376
|
+
{"path": ".loom/reviews/**", "reason": "attach-only preserves host-owned review truth"},
|
|
1153
1377
|
{"path": ".loom/specs/**", "reason": "attach-only does not author Loom execution specs"},
|
|
1154
1378
|
]
|
|
1155
1379
|
if adoption_path == "defer":
|
|
1156
1380
|
return [{"path": "*", "reason": "observe-only intent is read-only"}]
|
|
1157
1381
|
if adoption_path == "skill-install-only":
|
|
1158
1382
|
return [{"path": ".loom/work-items/**", "reason": "skill install does not adopt execution governance"}]
|
|
1383
|
+
if profile == "light-governance":
|
|
1384
|
+
return [
|
|
1385
|
+
{"path": ".loom/work-items/**", "reason": "light-governance does not author Loom work item truth"},
|
|
1386
|
+
{"path": ".loom/progress/**", "reason": "light-governance does not author Loom recovery truth"},
|
|
1387
|
+
{"path": ".loom/status/current.md", "reason": "light-governance does not author Loom status truth"},
|
|
1388
|
+
]
|
|
1159
1389
|
return []
|
|
1160
1390
|
|
|
1161
1391
|
|
|
@@ -1180,8 +1410,10 @@ def risk_summary(adoption_path: str, intake: dict[str, object], planned: list[di
|
|
|
1180
1410
|
|
|
1181
1411
|
def build_result(target_root: Path, scenario: str, intake: dict[str, object], install_pr_template: bool) -> dict[str, object]:
|
|
1182
1412
|
adoption_path = recommended_adoption_path(scenario, intake)
|
|
1413
|
+
profile = scaffold_profile_key(adoption_path, intake)
|
|
1183
1414
|
attach_only = uses_attach_only_path(adoption_path)
|
|
1184
1415
|
read_only_adoption = adoption_path in NON_WRITABLE_ADOPTION_PATHS
|
|
1416
|
+
has_work_item_carriers = profile_has_work_item_carriers(profile)
|
|
1185
1417
|
main_problem = {
|
|
1186
1418
|
"new": "the repository has no controlled Loom entry yet",
|
|
1187
1419
|
"small-existing": "the repo has a baseline but still lacks a stable Loom adoption entry and explicit first artifacts",
|
|
@@ -1207,6 +1439,7 @@ def build_result(target_root: Path, scenario: str, intake: dict[str, object], in
|
|
|
1207
1439
|
bootstrap_mode=True,
|
|
1208
1440
|
scenario_override=scenario,
|
|
1209
1441
|
)
|
|
1442
|
+
initial_artifact_list = initial_artifacts(target_root, install_pr_template, adoption_path, profile)
|
|
1210
1443
|
result = {
|
|
1211
1444
|
"schema_version": "loom-init-output/v1",
|
|
1212
1445
|
"generator": {
|
|
@@ -1235,7 +1468,20 @@ def build_result(target_root: Path, scenario: str, intake: dict[str, object], in
|
|
|
1235
1468
|
"recovery_mode": recovery_mode(scenario),
|
|
1236
1469
|
"capabilities": rule_refs_for_capabilities(scenario, adoption_path),
|
|
1237
1470
|
},
|
|
1238
|
-
"
|
|
1471
|
+
"scaffold_profile": {
|
|
1472
|
+
"name": profile,
|
|
1473
|
+
"writes_artifacts": profile_writes_artifacts(profile),
|
|
1474
|
+
"writes_work_item_carriers": has_work_item_carriers,
|
|
1475
|
+
"description": {
|
|
1476
|
+
"observe-only": "read-only repository observation; no Loom adoption carriers are written",
|
|
1477
|
+
"skill-install-only": "skill/runtime installation intent without repository governance adoption carriers",
|
|
1478
|
+
"attach-only": "companion/read-surface attachment that preserves repo-owned execution truth",
|
|
1479
|
+
"light-governance": "companion, review/spec, and PR-template loop without Loom-owned work item/progress/status carriers",
|
|
1480
|
+
"execution-control": "Loom-owned work item, progress, review, status, and spec carriers",
|
|
1481
|
+
"strong-governance": "execution-control surface prepared for host gates, required checks, merge, and closeout consumption",
|
|
1482
|
+
}[profile],
|
|
1483
|
+
},
|
|
1484
|
+
"deferred_capabilities": deferred_capabilities(scenario, adoption_path, profile),
|
|
1239
1485
|
"fact_chain": (
|
|
1240
1486
|
{
|
|
1241
1487
|
"mode": "intent-only dry-run",
|
|
@@ -1259,6 +1505,17 @@ def build_result(target_root: Path, scenario: str, intake: dict[str, object], in
|
|
|
1259
1505
|
},
|
|
1260
1506
|
}
|
|
1261
1507
|
if attach_only
|
|
1508
|
+
else {
|
|
1509
|
+
"mode": "profile-guided light-governance",
|
|
1510
|
+
"read_entry": "not_applicable",
|
|
1511
|
+
"entry_points": {
|
|
1512
|
+
"current_item_id": WORK_ITEM_ID,
|
|
1513
|
+
"work_item": "not_applicable",
|
|
1514
|
+
"recovery_entry": "not_applicable",
|
|
1515
|
+
"status_surface": "not_applicable",
|
|
1516
|
+
},
|
|
1517
|
+
}
|
|
1518
|
+
if not has_work_item_carriers
|
|
1262
1519
|
else {
|
|
1263
1520
|
"mode": "work-item + recovery-entry + derived status-surface",
|
|
1264
1521
|
"read_entry": "python3 .loom/bin/loom_init.py fact-chain --target .",
|
|
@@ -1270,8 +1527,8 @@ def build_result(target_root: Path, scenario: str, intake: dict[str, object], in
|
|
|
1270
1527
|
},
|
|
1271
1528
|
}
|
|
1272
1529
|
),
|
|
1273
|
-
"initial_artifacts":
|
|
1274
|
-
"initial_work_items": initial_work_items(scenario, target_root, adoption_path, install_pr_template),
|
|
1530
|
+
"initial_artifacts": initial_artifact_list,
|
|
1531
|
+
"initial_work_items": initial_work_items(scenario, target_root, adoption_path, install_pr_template, profile),
|
|
1275
1532
|
"validation_and_closing": {
|
|
1276
1533
|
"validation_entry": "python3 .loom/bin/loom_init.py verify --target .",
|
|
1277
1534
|
"checkpoint_relationship": (
|
|
@@ -1281,6 +1538,12 @@ def build_result(target_root: Path, scenario: str, intake: dict[str, object], in
|
|
|
1281
1538
|
"merge checkpoint should only pass after downstream repo truth, companion extensions, and release judgment align",
|
|
1282
1539
|
]
|
|
1283
1540
|
if attach_only
|
|
1541
|
+
else [
|
|
1542
|
+
"admission checkpoint confirms the companion entry, review record, spec suite, and PR template are readable",
|
|
1543
|
+
"build checkpoint confirms generated light-governance surfaces are internally consistent",
|
|
1544
|
+
"merge checkpoint remains repo-owned until the intent upgrades to execution-control or strong-governance",
|
|
1545
|
+
]
|
|
1546
|
+
if profile == "light-governance"
|
|
1284
1547
|
else [
|
|
1285
1548
|
"admission checkpoint confirms the bootstrap work item and first artifacts are readable",
|
|
1286
1549
|
"build checkpoint confirms generated carriers and templates are internally consistent",
|
|
@@ -1288,17 +1551,25 @@ def build_result(target_root: Path, scenario: str, intake: dict[str, object], in
|
|
|
1288
1551
|
]
|
|
1289
1552
|
),
|
|
1290
1553
|
"clean_state": (
|
|
1291
|
-
"all generated attach-only Loom artifacts are readable, verified, and do not introduce Loom-
|
|
1554
|
+
"all generated attach-only Loom artifacts are readable, verified, and do not introduce Loom-authored work/progress/status/review/spec truth carriers"
|
|
1292
1555
|
if attach_only
|
|
1556
|
+
else "all generated light-governance artifacts are readable, verified, and do not introduce Loom-owned work/progress/status carriers"
|
|
1557
|
+
if profile == "light-governance"
|
|
1293
1558
|
else "all generated Loom artifacts are readable, verified, and free of conflicting duplicates"
|
|
1294
1559
|
),
|
|
1295
1560
|
"close_when": (
|
|
1296
1561
|
[
|
|
1297
1562
|
"the target repo has a readable root rule entry and attached repo companion entry",
|
|
1298
1563
|
"the attach-only bootstrap metadata and repo-local validation path are verifiable",
|
|
1299
|
-
"the bootstrap manifest
|
|
1564
|
+
"the bootstrap manifest, init-result, planned writes, and filesystem do not expose forbidden Loom-authored truth carriers",
|
|
1300
1565
|
]
|
|
1301
1566
|
if attach_only
|
|
1567
|
+
else [
|
|
1568
|
+
"the target repo has a readable Loom companion entry",
|
|
1569
|
+
"the review record, spec suite, and PR template exist",
|
|
1570
|
+
"the bootstrap manifest and init-result are verifiable",
|
|
1571
|
+
]
|
|
1572
|
+
if profile == "light-governance"
|
|
1302
1573
|
else [
|
|
1303
1574
|
"the target repo has a readable root or companion Loom entry",
|
|
1304
1575
|
"the first work item, progress carrier, and spec/plan artifacts exist",
|
|
@@ -1312,6 +1583,7 @@ def build_result(target_root: Path, scenario: str, intake: dict[str, object], in
|
|
|
1312
1583
|
"maturity_upgrade_path": init_maturity_upgrade_path(governance_surface),
|
|
1313
1584
|
}
|
|
1314
1585
|
planned = planned_write_targets(result, adoption_path)
|
|
1586
|
+
deferred = result["deferred_capabilities"]
|
|
1315
1587
|
result["detected_repository_mode"] = {
|
|
1316
1588
|
"repository_type": intake.get("repository_type"),
|
|
1317
1589
|
"scenario_key": scenario,
|
|
@@ -1319,7 +1591,14 @@ def build_result(target_root: Path, scenario: str, intake: dict[str, object], in
|
|
|
1319
1591
|
}
|
|
1320
1592
|
result["adoption_intent"] = adoption_intent_payload(adoption_path, intake)
|
|
1321
1593
|
result["planned_writes"] = planned
|
|
1322
|
-
result["
|
|
1594
|
+
result["required_carriers"] = required_carriers_for_profile(initial_artifact_list, profile)
|
|
1595
|
+
result["intentionally_absent"] = intentionally_absent_targets(adoption_path, profile)
|
|
1596
|
+
result["forbidden_authored_carriers"] = forbidden_authored_carriers(profile)
|
|
1597
|
+
scaffold_profile = result.get("scaffold_profile")
|
|
1598
|
+
if isinstance(scaffold_profile, dict):
|
|
1599
|
+
scaffold_profile["required_carriers"] = result["required_carriers"]
|
|
1600
|
+
scaffold_profile["forbidden_authored_carriers"] = result["forbidden_authored_carriers"]
|
|
1601
|
+
result["upgrade_triggers"] = upgrade_triggers(deferred if isinstance(deferred, list) else [], profile)
|
|
1323
1602
|
result["risk_summary"] = risk_summary(adoption_path, intake, planned)
|
|
1324
1603
|
return result
|
|
1325
1604
|
|
|
@@ -1445,16 +1724,26 @@ def bootstrap_write_blockers(result: dict[str, object]) -> list[str]:
|
|
|
1445
1724
|
|
|
1446
1725
|
def render_loom_readme(result: dict[str, object]) -> str:
|
|
1447
1726
|
run = result["run"]
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1727
|
+
profile = result.get("scaffold_profile")
|
|
1728
|
+
profile_name = str(profile.get("name")) if isinstance(profile, dict) else "execution-control"
|
|
1729
|
+
if profile_name == "attach-only":
|
|
1730
|
+
path_lines = (
|
|
1731
|
+
"- Repo companion entry: `.loom/companion/README.md`\n"
|
|
1732
|
+
"- Companion checkpoints: `.loom/companion/checkpoints.md`\n"
|
|
1733
|
+
"- Companion review surface: `.loom/companion/review.md`\n"
|
|
1734
|
+
)
|
|
1735
|
+
elif profile_name == "light-governance":
|
|
1736
|
+
path_lines = (
|
|
1737
|
+
"- Repo companion entry: `.loom/companion/README.md`\n"
|
|
1738
|
+
"- Review record: `.loom/reviews/INIT-0001.json`\n"
|
|
1739
|
+
"- Spec suite: `.loom/specs/INIT-0001/`\n"
|
|
1740
|
+
)
|
|
1741
|
+
else:
|
|
1742
|
+
path_lines = (
|
|
1743
|
+
"- First work item: `.loom/work-items/INIT-0001.md`\n"
|
|
1744
|
+
"- Progress carrier: `.loom/progress/INIT-0001.md`\n"
|
|
1745
|
+
"- Status surface: `.loom/status/current.md`\n"
|
|
1746
|
+
)
|
|
1458
1747
|
return (
|
|
1459
1748
|
"# Loom Bootstrap\n\n"
|
|
1460
1749
|
f"This directory was generated by `{RUNTIME_SOURCE}`.\n\n"
|
|
@@ -1548,8 +1837,8 @@ def companion_manifest_payload() -> dict[str, object]:
|
|
|
1548
1837
|
}
|
|
1549
1838
|
|
|
1550
1839
|
|
|
1551
|
-
def repo_interface_payload() -> dict[str, object]:
|
|
1552
|
-
|
|
1840
|
+
def repo_interface_payload(profile_name: str = "execution-control") -> dict[str, object]:
|
|
1841
|
+
payload: dict[str, object] = {
|
|
1553
1842
|
"schema_version": "loom-repo-interface/v2",
|
|
1554
1843
|
"companion_entry": ".loom/companion/README.md",
|
|
1555
1844
|
"repo_specific_requirements": {"review": [], "merge_ready": [], "closeout": []},
|
|
@@ -1570,6 +1859,9 @@ def repo_interface_payload() -> dict[str, object]:
|
|
|
1570
1859
|
"status_locator": ".loom/companion/releases/status.json",
|
|
1571
1860
|
},
|
|
1572
1861
|
}
|
|
1862
|
+
if profile_name == "attach-only":
|
|
1863
|
+
payload["host_truth_locators"] = ATTACH_ONLY_HOST_TRUTH_LOCATORS
|
|
1864
|
+
return payload
|
|
1573
1865
|
|
|
1574
1866
|
|
|
1575
1867
|
def repo_interop_payload() -> dict[str, object]:
|
|
@@ -1842,7 +2134,14 @@ def scaffold_target(
|
|
|
1842
2134
|
) -> tuple[int, list[str]]:
|
|
1843
2135
|
written = 0
|
|
1844
2136
|
touched: list[str] = []
|
|
1845
|
-
|
|
2137
|
+
profile = result.get("scaffold_profile")
|
|
2138
|
+
profile_name = str(profile.get("name")) if isinstance(profile, dict) else "execution-control"
|
|
2139
|
+
writes_light_loop = profile_name in {"light-governance", "execution-control", "strong-governance"}
|
|
2140
|
+
writes_work_item_carriers = profile_has_work_item_carriers(profile_name)
|
|
2141
|
+
if profile_name == "attach-only":
|
|
2142
|
+
forbidden_errors = attach_only_forbidden_carrier_errors(target_root, result)
|
|
2143
|
+
if forbidden_errors:
|
|
2144
|
+
raise RuntimeError("; ".join(forbidden_errors))
|
|
1846
2145
|
|
|
1847
2146
|
writes: list[tuple[Path, str | dict[str, object], str]] = [
|
|
1848
2147
|
(target_root / ".loom/README.md", render_loom_readme(result), "text"),
|
|
@@ -1852,7 +2151,7 @@ def scaffold_target(
|
|
|
1852
2151
|
(target_root / ".loom/bootstrap/capability-map.md", render_capability_map(result), "text"),
|
|
1853
2152
|
(target_root / ".loom/companion/README.md", render_companion_readme(result), "text"),
|
|
1854
2153
|
(target_root / ".loom/companion/manifest.json", companion_manifest_payload(), "json"),
|
|
1855
|
-
(target_root / ".loom/companion/repo-interface.json", repo_interface_payload(), "json"),
|
|
2154
|
+
(target_root / ".loom/companion/repo-interface.json", repo_interface_payload(profile_name), "json"),
|
|
1856
2155
|
(target_root / ".loom/companion/interop.json", repo_interop_payload(), "json"),
|
|
1857
2156
|
(target_root / ".loom/companion/checkpoints.md", render_companion_checkpoints(), "text"),
|
|
1858
2157
|
(target_root / ".loom/companion/review.md", render_companion_review(), "text"),
|
|
@@ -1912,15 +2211,18 @@ def scaffold_target(
|
|
|
1912
2211
|
"json",
|
|
1913
2212
|
),
|
|
1914
2213
|
]
|
|
1915
|
-
if
|
|
1916
|
-
pass
|
|
1917
|
-
else:
|
|
2214
|
+
if writes_light_loop:
|
|
1918
2215
|
writes.extend(
|
|
1919
2216
|
[
|
|
1920
|
-
(target_root / ".loom/work-items/INIT-0001.md", render_work_item(result), "text"),
|
|
1921
|
-
(target_root / ".loom/progress/INIT-0001.md", render_progress(result), "text"),
|
|
1922
2217
|
(target_root / ".loom/reviews/INIT-0001.json", render_review_entry(result), "text"),
|
|
1923
2218
|
(target_root / ".loom/reviews/INIT-0001.spec.json", render_spec_review_entry(result), "text"),
|
|
2219
|
+
]
|
|
2220
|
+
)
|
|
2221
|
+
if writes_work_item_carriers:
|
|
2222
|
+
writes.extend(
|
|
2223
|
+
[
|
|
2224
|
+
(target_root / ".loom/work-items/INIT-0001.md", render_work_item(result), "text"),
|
|
2225
|
+
(target_root / ".loom/progress/INIT-0001.md", render_progress(result), "text"),
|
|
1924
2226
|
(target_root / ".loom/status/current.md", render_status(result), "text"),
|
|
1925
2227
|
]
|
|
1926
2228
|
)
|
|
@@ -1957,7 +2259,7 @@ def scaffold_target(
|
|
|
1957
2259
|
if copy_file(source, destination, force=force):
|
|
1958
2260
|
written += 1
|
|
1959
2261
|
touched.append(str(destination.relative_to(target_root)))
|
|
1960
|
-
if
|
|
2262
|
+
if writes_light_loop:
|
|
1961
2263
|
for source, destination in (
|
|
1962
2264
|
(shared_asset(__file__, "templates/scaffold/spec.md"), target_root / ".loom/specs/INIT-0001/spec.md"),
|
|
1963
2265
|
(shared_asset(__file__, "templates/scaffold/plan.md"), target_root / ".loom/specs/INIT-0001/plan.md"),
|
|
@@ -1977,7 +2279,7 @@ def scaffold_target(
|
|
|
1977
2279
|
touched.append(str(pr_template_target.relative_to(target_root)))
|
|
1978
2280
|
|
|
1979
2281
|
root_agents = target_root / "AGENTS.md"
|
|
1980
|
-
if
|
|
2282
|
+
if writes_light_loop and not root_agents.exists():
|
|
1981
2283
|
if write_text(root_agents, render_root_agents(), force=force):
|
|
1982
2284
|
written += 1
|
|
1983
2285
|
touched.append(str(root_agents.relative_to(target_root)))
|
|
@@ -2007,59 +2309,38 @@ def verify_target(target_root: Path, output_path: Path) -> list[str]:
|
|
|
2007
2309
|
adoption = result.get("recommended_adoption")
|
|
2008
2310
|
if isinstance(adoption, dict):
|
|
2009
2311
|
attach_only = uses_attach_only_path(str(adoption.get("path", "")))
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
"
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
".loom/companion/review.md",
|
|
2029
|
-
".loom/companion/merge-ready.md",
|
|
2030
|
-
".loom/companion/closeout.md",
|
|
2031
|
-
".loom/shadow/admission-loom.json",
|
|
2032
|
-
".loom/shadow/admission-repo.json",
|
|
2033
|
-
".loom/shadow/review-loom.json",
|
|
2034
|
-
".loom/shadow/review-repo.json",
|
|
2035
|
-
".loom/shadow/merge-ready-loom.json",
|
|
2036
|
-
".loom/shadow/merge-ready-repo.json",
|
|
2037
|
-
".loom/shadow/closeout-loom.json",
|
|
2038
|
-
".loom/shadow/closeout-repo.json",
|
|
2039
|
-
]
|
|
2040
|
-
if attach_only:
|
|
2041
|
-
pass
|
|
2312
|
+
scaffold_profile = result.get("scaffold_profile")
|
|
2313
|
+
profile_name = str(scaffold_profile.get("name")) if isinstance(scaffold_profile, dict) else (
|
|
2314
|
+
"attach-only" if attach_only else "execution-control"
|
|
2315
|
+
)
|
|
2316
|
+
initial_artifact_list = result.get("initial_artifacts")
|
|
2317
|
+
planned_writes = result.get("planned_writes")
|
|
2318
|
+
if isinstance(initial_artifact_list, list):
|
|
2319
|
+
required_paths = [
|
|
2320
|
+
str(item.get("path"))
|
|
2321
|
+
for item in initial_artifact_list
|
|
2322
|
+
if isinstance(item, dict) and isinstance(item.get("path"), str)
|
|
2323
|
+
]
|
|
2324
|
+
elif isinstance(planned_writes, list):
|
|
2325
|
+
required_paths = [
|
|
2326
|
+
str(item.get("path"))
|
|
2327
|
+
for item in planned_writes
|
|
2328
|
+
if isinstance(item, dict) and isinstance(item.get("path"), str)
|
|
2329
|
+
]
|
|
2042
2330
|
else:
|
|
2043
|
-
required_paths
|
|
2044
|
-
[
|
|
2045
|
-
"AGENTS.md",
|
|
2046
|
-
".loom/work-items/INIT-0001.md",
|
|
2047
|
-
".loom/progress/INIT-0001.md",
|
|
2048
|
-
".loom/reviews/INIT-0001.json",
|
|
2049
|
-
".loom/status/current.md",
|
|
2050
|
-
".loom/specs/INIT-0001/spec.md",
|
|
2051
|
-
".loom/specs/INIT-0001/plan.md",
|
|
2052
|
-
".loom/specs/INIT-0001/implementation-contract.md",
|
|
2053
|
-
]
|
|
2054
|
-
)
|
|
2331
|
+
required_paths = []
|
|
2055
2332
|
for key in (
|
|
2056
2333
|
"project_judgment",
|
|
2057
2334
|
"recommended_adoption",
|
|
2335
|
+
"scaffold_profile",
|
|
2058
2336
|
"adoption_intent",
|
|
2059
2337
|
"detected_repository_mode",
|
|
2060
2338
|
"risk_summary",
|
|
2339
|
+
"required_carriers",
|
|
2061
2340
|
"planned_writes",
|
|
2341
|
+
"forbidden_authored_carriers",
|
|
2062
2342
|
"deferred_capabilities",
|
|
2343
|
+
"upgrade_triggers",
|
|
2063
2344
|
"fact_chain",
|
|
2064
2345
|
"initial_artifacts",
|
|
2065
2346
|
"initial_work_items",
|
|
@@ -2127,12 +2408,39 @@ def verify_target(target_root: Path, output_path: Path) -> list[str]:
|
|
|
2127
2408
|
for forbidden in (".loom/work-items/INIT-0001.md", ".loom/progress/INIT-0001.md", ".loom/status/current.md"):
|
|
2128
2409
|
if forbidden in declared_generated:
|
|
2129
2410
|
errors.append(f"deep-existing-repo bootstrap must not declare generated carrier `{forbidden}`")
|
|
2411
|
+
forbidden_profile = result.get("forbidden_authored_carriers")
|
|
2412
|
+
if not isinstance(forbidden_profile, list) or {
|
|
2413
|
+
str(item.get("path")) for item in forbidden_profile if isinstance(item, dict)
|
|
2414
|
+
} != {carrier["path"] for carrier in ATTACH_ONLY_FORBIDDEN_AUTHORED_CARRIERS}:
|
|
2415
|
+
errors.append("attach-only init-result must declare the full `forbidden_authored_carriers` profile list")
|
|
2416
|
+
errors.extend(attach_only_forbidden_carrier_errors(target_root, result))
|
|
2417
|
+
if profile_name == "light-governance":
|
|
2418
|
+
declared_generated = {
|
|
2419
|
+
artifact.get("path")
|
|
2420
|
+
for artifact in result.get("initial_artifacts", [])
|
|
2421
|
+
if isinstance(artifact, dict) and isinstance(artifact.get("path"), str)
|
|
2422
|
+
}
|
|
2423
|
+
for forbidden in (".loom/work-items/INIT-0001.md", ".loom/progress/INIT-0001.md", ".loom/status/current.md"):
|
|
2424
|
+
if forbidden in declared_generated:
|
|
2425
|
+
errors.append(f"light-governance bootstrap must not declare execution-control carrier `{forbidden}`")
|
|
2130
2426
|
|
|
2131
2427
|
for relative in required_paths:
|
|
2132
2428
|
if not (target_root / relative).exists():
|
|
2133
2429
|
errors.append(f"missing required artifact: {relative}")
|
|
2134
2430
|
|
|
2135
|
-
|
|
2431
|
+
profile_writes_work_items = False
|
|
2432
|
+
if output_path.exists():
|
|
2433
|
+
try:
|
|
2434
|
+
result_for_profile = read_json(output_path)
|
|
2435
|
+
scaffold_profile = result_for_profile.get("scaffold_profile")
|
|
2436
|
+
profile_name = str(scaffold_profile.get("name")) if isinstance(scaffold_profile, dict) else (
|
|
2437
|
+
"attach-only" if attach_only else "execution-control"
|
|
2438
|
+
)
|
|
2439
|
+
profile_writes_work_items = profile_has_work_item_carriers(profile_name)
|
|
2440
|
+
except json.JSONDecodeError:
|
|
2441
|
+
profile_writes_work_items = not attach_only
|
|
2442
|
+
|
|
2443
|
+
if profile_writes_work_items:
|
|
2136
2444
|
fact_chain_report, fact_chain_errors = inspect_fact_chain(
|
|
2137
2445
|
target_root,
|
|
2138
2446
|
str(output_path.relative_to(target_root)),
|
|
@@ -2192,7 +2500,7 @@ def verify_target(target_root: Path, output_path: Path) -> list[str]:
|
|
|
2192
2500
|
{"pass"},
|
|
2193
2501
|
),
|
|
2194
2502
|
]
|
|
2195
|
-
if
|
|
2503
|
+
if profile_writes_work_items:
|
|
2196
2504
|
commands.extend(
|
|
2197
2505
|
[
|
|
2198
2506
|
(
|
|
@@ -2207,7 +2515,7 @@ def verify_target(target_root: Path, output_path: Path) -> list[str]:
|
|
|
2207
2515
|
),
|
|
2208
2516
|
]
|
|
2209
2517
|
)
|
|
2210
|
-
if current_item_id and
|
|
2518
|
+
if current_item_id and profile_writes_work_items:
|
|
2211
2519
|
commands.extend(
|
|
2212
2520
|
[
|
|
2213
2521
|
(
|