@mc-and-his-agents/loom-installer 0.1.112 → 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.
Files changed (213) hide show
  1. package/package.json +1 -1
  2. package/payload/manifest.json +425 -425
  3. package/payload/plugin/loom/skills/loom-adopt/.loom-runtime/loom-adopt/SKILL.md +1 -1
  4. package/payload/plugin/loom/skills/loom-adopt/.loom-runtime/loom-init/SKILL.md +1 -1
  5. package/payload/plugin/loom/skills/loom-adopt/.loom-runtime/loom-init/contract.json +2 -0
  6. package/payload/plugin/loom/skills/loom-adopt/.loom-runtime/loom-init/references/output-contract.md +6 -0
  7. package/payload/plugin/loom/skills/loom-adopt/.loom-runtime/shared/references/adoption/deep-existing-repo-default.md +4 -0
  8. package/payload/plugin/loom/skills/loom-adopt/.loom-runtime/shared/references/adoption/repo-companion-contract.md +3 -1
  9. package/payload/plugin/loom/skills/loom-adopt/.loom-runtime/shared/scripts/governance_surface.py +1 -0
  10. package/payload/plugin/loom/skills/loom-adopt/.loom-runtime/shared/scripts/loom_check.py +106 -0
  11. package/payload/plugin/loom/skills/loom-adopt/.loom-runtime/shared/scripts/loom_init.py +232 -6
  12. package/payload/plugin/loom/skills/loom-adopt/SKILL.md +1 -1
  13. package/payload/plugin/loom/skills/loom-build/.loom-runtime/loom-adopt/SKILL.md +1 -1
  14. package/payload/plugin/loom/skills/loom-build/.loom-runtime/loom-init/SKILL.md +1 -1
  15. package/payload/plugin/loom/skills/loom-build/.loom-runtime/loom-init/contract.json +2 -0
  16. package/payload/plugin/loom/skills/loom-build/.loom-runtime/loom-init/references/output-contract.md +6 -0
  17. package/payload/plugin/loom/skills/loom-build/.loom-runtime/shared/references/adoption/deep-existing-repo-default.md +4 -0
  18. package/payload/plugin/loom/skills/loom-build/.loom-runtime/shared/references/adoption/repo-companion-contract.md +3 -1
  19. package/payload/plugin/loom/skills/loom-build/.loom-runtime/shared/scripts/governance_surface.py +1 -0
  20. package/payload/plugin/loom/skills/loom-build/.loom-runtime/shared/scripts/loom_check.py +106 -0
  21. package/payload/plugin/loom/skills/loom-build/.loom-runtime/shared/scripts/loom_init.py +232 -6
  22. package/payload/plugin/loom/skills/loom-handoff/.loom-runtime/loom-adopt/SKILL.md +1 -1
  23. package/payload/plugin/loom/skills/loom-handoff/.loom-runtime/loom-init/SKILL.md +1 -1
  24. package/payload/plugin/loom/skills/loom-handoff/.loom-runtime/loom-init/contract.json +2 -0
  25. package/payload/plugin/loom/skills/loom-handoff/.loom-runtime/loom-init/references/output-contract.md +6 -0
  26. package/payload/plugin/loom/skills/loom-handoff/.loom-runtime/shared/references/adoption/deep-existing-repo-default.md +4 -0
  27. package/payload/plugin/loom/skills/loom-handoff/.loom-runtime/shared/references/adoption/repo-companion-contract.md +3 -1
  28. package/payload/plugin/loom/skills/loom-handoff/.loom-runtime/shared/scripts/governance_surface.py +1 -0
  29. package/payload/plugin/loom/skills/loom-handoff/.loom-runtime/shared/scripts/loom_check.py +106 -0
  30. package/payload/plugin/loom/skills/loom-handoff/.loom-runtime/shared/scripts/loom_init.py +232 -6
  31. package/payload/plugin/loom/skills/loom-init/.loom-runtime/loom-adopt/SKILL.md +1 -1
  32. package/payload/plugin/loom/skills/loom-init/.loom-runtime/loom-init/SKILL.md +1 -1
  33. package/payload/plugin/loom/skills/loom-init/.loom-runtime/loom-init/contract.json +2 -0
  34. package/payload/plugin/loom/skills/loom-init/.loom-runtime/loom-init/references/output-contract.md +6 -0
  35. package/payload/plugin/loom/skills/loom-init/.loom-runtime/shared/references/adoption/deep-existing-repo-default.md +4 -0
  36. package/payload/plugin/loom/skills/loom-init/.loom-runtime/shared/references/adoption/repo-companion-contract.md +3 -1
  37. package/payload/plugin/loom/skills/loom-init/.loom-runtime/shared/scripts/governance_surface.py +1 -0
  38. package/payload/plugin/loom/skills/loom-init/.loom-runtime/shared/scripts/loom_check.py +106 -0
  39. package/payload/plugin/loom/skills/loom-init/.loom-runtime/shared/scripts/loom_init.py +232 -6
  40. package/payload/plugin/loom/skills/loom-init/SKILL.md +1 -1
  41. package/payload/plugin/loom/skills/loom-init/contract.json +2 -0
  42. package/payload/plugin/loom/skills/loom-init/references/output-contract.md +6 -0
  43. package/payload/plugin/loom/skills/loom-merge-ready/.loom-runtime/loom-adopt/SKILL.md +1 -1
  44. package/payload/plugin/loom/skills/loom-merge-ready/.loom-runtime/loom-init/SKILL.md +1 -1
  45. package/payload/plugin/loom/skills/loom-merge-ready/.loom-runtime/loom-init/contract.json +2 -0
  46. package/payload/plugin/loom/skills/loom-merge-ready/.loom-runtime/loom-init/references/output-contract.md +6 -0
  47. package/payload/plugin/loom/skills/loom-merge-ready/.loom-runtime/shared/references/adoption/deep-existing-repo-default.md +4 -0
  48. package/payload/plugin/loom/skills/loom-merge-ready/.loom-runtime/shared/references/adoption/repo-companion-contract.md +3 -1
  49. package/payload/plugin/loom/skills/loom-merge-ready/.loom-runtime/shared/scripts/governance_surface.py +1 -0
  50. package/payload/plugin/loom/skills/loom-merge-ready/.loom-runtime/shared/scripts/loom_check.py +106 -0
  51. package/payload/plugin/loom/skills/loom-merge-ready/.loom-runtime/shared/scripts/loom_init.py +232 -6
  52. package/payload/plugin/loom/skills/loom-pre-review/.loom-runtime/loom-adopt/SKILL.md +1 -1
  53. package/payload/plugin/loom/skills/loom-pre-review/.loom-runtime/loom-init/SKILL.md +1 -1
  54. package/payload/plugin/loom/skills/loom-pre-review/.loom-runtime/loom-init/contract.json +2 -0
  55. package/payload/plugin/loom/skills/loom-pre-review/.loom-runtime/loom-init/references/output-contract.md +6 -0
  56. package/payload/plugin/loom/skills/loom-pre-review/.loom-runtime/shared/references/adoption/deep-existing-repo-default.md +4 -0
  57. package/payload/plugin/loom/skills/loom-pre-review/.loom-runtime/shared/references/adoption/repo-companion-contract.md +3 -1
  58. package/payload/plugin/loom/skills/loom-pre-review/.loom-runtime/shared/scripts/governance_surface.py +1 -0
  59. package/payload/plugin/loom/skills/loom-pre-review/.loom-runtime/shared/scripts/loom_check.py +106 -0
  60. package/payload/plugin/loom/skills/loom-pre-review/.loom-runtime/shared/scripts/loom_init.py +232 -6
  61. package/payload/plugin/loom/skills/loom-resume/.loom-runtime/loom-adopt/SKILL.md +1 -1
  62. package/payload/plugin/loom/skills/loom-resume/.loom-runtime/loom-init/SKILL.md +1 -1
  63. package/payload/plugin/loom/skills/loom-resume/.loom-runtime/loom-init/contract.json +2 -0
  64. package/payload/plugin/loom/skills/loom-resume/.loom-runtime/loom-init/references/output-contract.md +6 -0
  65. package/payload/plugin/loom/skills/loom-resume/.loom-runtime/shared/references/adoption/deep-existing-repo-default.md +4 -0
  66. package/payload/plugin/loom/skills/loom-resume/.loom-runtime/shared/references/adoption/repo-companion-contract.md +3 -1
  67. package/payload/plugin/loom/skills/loom-resume/.loom-runtime/shared/scripts/governance_surface.py +1 -0
  68. package/payload/plugin/loom/skills/loom-resume/.loom-runtime/shared/scripts/loom_check.py +106 -0
  69. package/payload/plugin/loom/skills/loom-resume/.loom-runtime/shared/scripts/loom_init.py +232 -6
  70. package/payload/plugin/loom/skills/loom-retire/.loom-runtime/loom-adopt/SKILL.md +1 -1
  71. package/payload/plugin/loom/skills/loom-retire/.loom-runtime/loom-init/SKILL.md +1 -1
  72. package/payload/plugin/loom/skills/loom-retire/.loom-runtime/loom-init/contract.json +2 -0
  73. package/payload/plugin/loom/skills/loom-retire/.loom-runtime/loom-init/references/output-contract.md +6 -0
  74. package/payload/plugin/loom/skills/loom-retire/.loom-runtime/shared/references/adoption/deep-existing-repo-default.md +4 -0
  75. package/payload/plugin/loom/skills/loom-retire/.loom-runtime/shared/references/adoption/repo-companion-contract.md +3 -1
  76. package/payload/plugin/loom/skills/loom-retire/.loom-runtime/shared/scripts/governance_surface.py +1 -0
  77. package/payload/plugin/loom/skills/loom-retire/.loom-runtime/shared/scripts/loom_check.py +106 -0
  78. package/payload/plugin/loom/skills/loom-retire/.loom-runtime/shared/scripts/loom_init.py +232 -6
  79. package/payload/plugin/loom/skills/loom-review/.loom-runtime/loom-adopt/SKILL.md +1 -1
  80. package/payload/plugin/loom/skills/loom-review/.loom-runtime/loom-init/SKILL.md +1 -1
  81. package/payload/plugin/loom/skills/loom-review/.loom-runtime/loom-init/contract.json +2 -0
  82. package/payload/plugin/loom/skills/loom-review/.loom-runtime/loom-init/references/output-contract.md +6 -0
  83. package/payload/plugin/loom/skills/loom-review/.loom-runtime/shared/references/adoption/deep-existing-repo-default.md +4 -0
  84. package/payload/plugin/loom/skills/loom-review/.loom-runtime/shared/references/adoption/repo-companion-contract.md +3 -1
  85. package/payload/plugin/loom/skills/loom-review/.loom-runtime/shared/scripts/governance_surface.py +1 -0
  86. package/payload/plugin/loom/skills/loom-review/.loom-runtime/shared/scripts/loom_check.py +106 -0
  87. package/payload/plugin/loom/skills/loom-review/.loom-runtime/shared/scripts/loom_init.py +232 -6
  88. package/payload/plugin/loom/skills/loom-spec-review/.loom-runtime/loom-adopt/SKILL.md +1 -1
  89. package/payload/plugin/loom/skills/loom-spec-review/.loom-runtime/loom-init/SKILL.md +1 -1
  90. package/payload/plugin/loom/skills/loom-spec-review/.loom-runtime/loom-init/contract.json +2 -0
  91. package/payload/plugin/loom/skills/loom-spec-review/.loom-runtime/loom-init/references/output-contract.md +6 -0
  92. package/payload/plugin/loom/skills/loom-spec-review/.loom-runtime/shared/references/adoption/deep-existing-repo-default.md +4 -0
  93. package/payload/plugin/loom/skills/loom-spec-review/.loom-runtime/shared/references/adoption/repo-companion-contract.md +3 -1
  94. package/payload/plugin/loom/skills/loom-spec-review/.loom-runtime/shared/scripts/governance_surface.py +1 -0
  95. package/payload/plugin/loom/skills/loom-spec-review/.loom-runtime/shared/scripts/loom_check.py +106 -0
  96. package/payload/plugin/loom/skills/loom-spec-review/.loom-runtime/shared/scripts/loom_init.py +232 -6
  97. package/payload/plugin/loom/skills/loom-story/.loom-runtime/loom-adopt/SKILL.md +1 -1
  98. package/payload/plugin/loom/skills/loom-story/.loom-runtime/loom-init/SKILL.md +1 -1
  99. package/payload/plugin/loom/skills/loom-story/.loom-runtime/loom-init/contract.json +2 -0
  100. package/payload/plugin/loom/skills/loom-story/.loom-runtime/loom-init/references/output-contract.md +6 -0
  101. package/payload/plugin/loom/skills/loom-story/.loom-runtime/shared/references/adoption/deep-existing-repo-default.md +4 -0
  102. package/payload/plugin/loom/skills/loom-story/.loom-runtime/shared/references/adoption/repo-companion-contract.md +3 -1
  103. package/payload/plugin/loom/skills/loom-story/.loom-runtime/shared/scripts/governance_surface.py +1 -0
  104. package/payload/plugin/loom/skills/loom-story/.loom-runtime/shared/scripts/loom_check.py +106 -0
  105. package/payload/plugin/loom/skills/loom-story/.loom-runtime/shared/scripts/loom_init.py +232 -6
  106. package/payload/plugin/loom/skills/shared/references/adoption/deep-existing-repo-default.md +4 -0
  107. package/payload/plugin/loom/skills/shared/references/adoption/repo-companion-contract.md +3 -1
  108. package/payload/plugin/loom/skills/shared/scripts/governance_surface.py +1 -0
  109. package/payload/plugin/loom/skills/shared/scripts/loom_check.py +106 -0
  110. package/payload/plugin/loom/skills/shared/scripts/loom_init.py +232 -6
  111. package/payload/skills/loom-adopt/.loom-runtime/loom-adopt/SKILL.md +1 -1
  112. package/payload/skills/loom-adopt/.loom-runtime/loom-init/SKILL.md +1 -1
  113. package/payload/skills/loom-adopt/.loom-runtime/loom-init/contract.json +2 -0
  114. package/payload/skills/loom-adopt/.loom-runtime/loom-init/references/output-contract.md +6 -0
  115. package/payload/skills/loom-adopt/.loom-runtime/shared/references/adoption/deep-existing-repo-default.md +4 -0
  116. package/payload/skills/loom-adopt/.loom-runtime/shared/references/adoption/repo-companion-contract.md +3 -1
  117. package/payload/skills/loom-adopt/.loom-runtime/shared/scripts/governance_surface.py +1 -0
  118. package/payload/skills/loom-adopt/.loom-runtime/shared/scripts/loom_check.py +106 -0
  119. package/payload/skills/loom-adopt/.loom-runtime/shared/scripts/loom_init.py +232 -6
  120. package/payload/skills/loom-adopt/SKILL.md +1 -1
  121. package/payload/skills/loom-build/.loom-runtime/loom-adopt/SKILL.md +1 -1
  122. package/payload/skills/loom-build/.loom-runtime/loom-init/SKILL.md +1 -1
  123. package/payload/skills/loom-build/.loom-runtime/loom-init/contract.json +2 -0
  124. package/payload/skills/loom-build/.loom-runtime/loom-init/references/output-contract.md +6 -0
  125. package/payload/skills/loom-build/.loom-runtime/shared/references/adoption/deep-existing-repo-default.md +4 -0
  126. package/payload/skills/loom-build/.loom-runtime/shared/references/adoption/repo-companion-contract.md +3 -1
  127. package/payload/skills/loom-build/.loom-runtime/shared/scripts/governance_surface.py +1 -0
  128. package/payload/skills/loom-build/.loom-runtime/shared/scripts/loom_check.py +106 -0
  129. package/payload/skills/loom-build/.loom-runtime/shared/scripts/loom_init.py +232 -6
  130. package/payload/skills/loom-handoff/.loom-runtime/loom-adopt/SKILL.md +1 -1
  131. package/payload/skills/loom-handoff/.loom-runtime/loom-init/SKILL.md +1 -1
  132. package/payload/skills/loom-handoff/.loom-runtime/loom-init/contract.json +2 -0
  133. package/payload/skills/loom-handoff/.loom-runtime/loom-init/references/output-contract.md +6 -0
  134. package/payload/skills/loom-handoff/.loom-runtime/shared/references/adoption/deep-existing-repo-default.md +4 -0
  135. package/payload/skills/loom-handoff/.loom-runtime/shared/references/adoption/repo-companion-contract.md +3 -1
  136. package/payload/skills/loom-handoff/.loom-runtime/shared/scripts/governance_surface.py +1 -0
  137. package/payload/skills/loom-handoff/.loom-runtime/shared/scripts/loom_check.py +106 -0
  138. package/payload/skills/loom-handoff/.loom-runtime/shared/scripts/loom_init.py +232 -6
  139. package/payload/skills/loom-init/.loom-runtime/loom-adopt/SKILL.md +1 -1
  140. package/payload/skills/loom-init/.loom-runtime/loom-init/SKILL.md +1 -1
  141. package/payload/skills/loom-init/.loom-runtime/loom-init/contract.json +2 -0
  142. package/payload/skills/loom-init/.loom-runtime/loom-init/references/output-contract.md +6 -0
  143. package/payload/skills/loom-init/.loom-runtime/shared/references/adoption/deep-existing-repo-default.md +4 -0
  144. package/payload/skills/loom-init/.loom-runtime/shared/references/adoption/repo-companion-contract.md +3 -1
  145. package/payload/skills/loom-init/.loom-runtime/shared/scripts/governance_surface.py +1 -0
  146. package/payload/skills/loom-init/.loom-runtime/shared/scripts/loom_check.py +106 -0
  147. package/payload/skills/loom-init/.loom-runtime/shared/scripts/loom_init.py +232 -6
  148. package/payload/skills/loom-init/SKILL.md +1 -1
  149. package/payload/skills/loom-init/contract.json +2 -0
  150. package/payload/skills/loom-init/references/output-contract.md +6 -0
  151. package/payload/skills/loom-merge-ready/.loom-runtime/loom-adopt/SKILL.md +1 -1
  152. package/payload/skills/loom-merge-ready/.loom-runtime/loom-init/SKILL.md +1 -1
  153. package/payload/skills/loom-merge-ready/.loom-runtime/loom-init/contract.json +2 -0
  154. package/payload/skills/loom-merge-ready/.loom-runtime/loom-init/references/output-contract.md +6 -0
  155. package/payload/skills/loom-merge-ready/.loom-runtime/shared/references/adoption/deep-existing-repo-default.md +4 -0
  156. package/payload/skills/loom-merge-ready/.loom-runtime/shared/references/adoption/repo-companion-contract.md +3 -1
  157. package/payload/skills/loom-merge-ready/.loom-runtime/shared/scripts/governance_surface.py +1 -0
  158. package/payload/skills/loom-merge-ready/.loom-runtime/shared/scripts/loom_check.py +106 -0
  159. package/payload/skills/loom-merge-ready/.loom-runtime/shared/scripts/loom_init.py +232 -6
  160. package/payload/skills/loom-pre-review/.loom-runtime/loom-adopt/SKILL.md +1 -1
  161. package/payload/skills/loom-pre-review/.loom-runtime/loom-init/SKILL.md +1 -1
  162. package/payload/skills/loom-pre-review/.loom-runtime/loom-init/contract.json +2 -0
  163. package/payload/skills/loom-pre-review/.loom-runtime/loom-init/references/output-contract.md +6 -0
  164. package/payload/skills/loom-pre-review/.loom-runtime/shared/references/adoption/deep-existing-repo-default.md +4 -0
  165. package/payload/skills/loom-pre-review/.loom-runtime/shared/references/adoption/repo-companion-contract.md +3 -1
  166. package/payload/skills/loom-pre-review/.loom-runtime/shared/scripts/governance_surface.py +1 -0
  167. package/payload/skills/loom-pre-review/.loom-runtime/shared/scripts/loom_check.py +106 -0
  168. package/payload/skills/loom-pre-review/.loom-runtime/shared/scripts/loom_init.py +232 -6
  169. package/payload/skills/loom-resume/.loom-runtime/loom-adopt/SKILL.md +1 -1
  170. package/payload/skills/loom-resume/.loom-runtime/loom-init/SKILL.md +1 -1
  171. package/payload/skills/loom-resume/.loom-runtime/loom-init/contract.json +2 -0
  172. package/payload/skills/loom-resume/.loom-runtime/loom-init/references/output-contract.md +6 -0
  173. package/payload/skills/loom-resume/.loom-runtime/shared/references/adoption/deep-existing-repo-default.md +4 -0
  174. package/payload/skills/loom-resume/.loom-runtime/shared/references/adoption/repo-companion-contract.md +3 -1
  175. package/payload/skills/loom-resume/.loom-runtime/shared/scripts/governance_surface.py +1 -0
  176. package/payload/skills/loom-resume/.loom-runtime/shared/scripts/loom_check.py +106 -0
  177. package/payload/skills/loom-resume/.loom-runtime/shared/scripts/loom_init.py +232 -6
  178. package/payload/skills/loom-retire/.loom-runtime/loom-adopt/SKILL.md +1 -1
  179. package/payload/skills/loom-retire/.loom-runtime/loom-init/SKILL.md +1 -1
  180. package/payload/skills/loom-retire/.loom-runtime/loom-init/contract.json +2 -0
  181. package/payload/skills/loom-retire/.loom-runtime/loom-init/references/output-contract.md +6 -0
  182. package/payload/skills/loom-retire/.loom-runtime/shared/references/adoption/deep-existing-repo-default.md +4 -0
  183. package/payload/skills/loom-retire/.loom-runtime/shared/references/adoption/repo-companion-contract.md +3 -1
  184. package/payload/skills/loom-retire/.loom-runtime/shared/scripts/governance_surface.py +1 -0
  185. package/payload/skills/loom-retire/.loom-runtime/shared/scripts/loom_check.py +106 -0
  186. package/payload/skills/loom-retire/.loom-runtime/shared/scripts/loom_init.py +232 -6
  187. package/payload/skills/loom-review/.loom-runtime/loom-adopt/SKILL.md +1 -1
  188. package/payload/skills/loom-review/.loom-runtime/loom-init/SKILL.md +1 -1
  189. package/payload/skills/loom-review/.loom-runtime/loom-init/contract.json +2 -0
  190. package/payload/skills/loom-review/.loom-runtime/loom-init/references/output-contract.md +6 -0
  191. package/payload/skills/loom-review/.loom-runtime/shared/references/adoption/deep-existing-repo-default.md +4 -0
  192. package/payload/skills/loom-review/.loom-runtime/shared/references/adoption/repo-companion-contract.md +3 -1
  193. package/payload/skills/loom-review/.loom-runtime/shared/scripts/governance_surface.py +1 -0
  194. package/payload/skills/loom-review/.loom-runtime/shared/scripts/loom_check.py +106 -0
  195. package/payload/skills/loom-review/.loom-runtime/shared/scripts/loom_init.py +232 -6
  196. package/payload/skills/loom-spec-review/.loom-runtime/loom-adopt/SKILL.md +1 -1
  197. package/payload/skills/loom-spec-review/.loom-runtime/loom-init/SKILL.md +1 -1
  198. package/payload/skills/loom-spec-review/.loom-runtime/loom-init/contract.json +2 -0
  199. package/payload/skills/loom-spec-review/.loom-runtime/loom-init/references/output-contract.md +6 -0
  200. package/payload/skills/loom-spec-review/.loom-runtime/shared/references/adoption/deep-existing-repo-default.md +4 -0
  201. package/payload/skills/loom-spec-review/.loom-runtime/shared/references/adoption/repo-companion-contract.md +3 -1
  202. package/payload/skills/loom-spec-review/.loom-runtime/shared/scripts/governance_surface.py +1 -0
  203. package/payload/skills/loom-spec-review/.loom-runtime/shared/scripts/loom_check.py +106 -0
  204. package/payload/skills/loom-spec-review/.loom-runtime/shared/scripts/loom_init.py +232 -6
  205. package/payload/skills/loom-story/.loom-runtime/loom-adopt/SKILL.md +1 -1
  206. package/payload/skills/loom-story/.loom-runtime/loom-init/SKILL.md +1 -1
  207. package/payload/skills/loom-story/.loom-runtime/loom-init/contract.json +2 -0
  208. package/payload/skills/loom-story/.loom-runtime/loom-init/references/output-contract.md +6 -0
  209. package/payload/skills/loom-story/.loom-runtime/shared/references/adoption/deep-existing-repo-default.md +4 -0
  210. package/payload/skills/loom-story/.loom-runtime/shared/references/adoption/repo-companion-contract.md +3 -1
  211. package/payload/skills/loom-story/.loom-runtime/shared/scripts/governance_surface.py +1 -0
  212. package/payload/skills/loom-story/.loom-runtime/shared/scripts/loom_check.py +106 -0
  213. package/payload/skills/loom-story/.loom-runtime/shared/scripts/loom_init.py +232 -6
@@ -35,6 +35,8 @@
35
35
  - `writes_artifacts`
36
36
  - `writes_work_item_carriers`
37
37
  - `description`
38
+ - `required_carriers`
39
+ - `forbidden_authored_carriers`
38
40
  - 本轮启用的能力清单
39
41
  - 每项能力分别映射到哪些 `governance`、`harness`、`templates`、`adoption` 规则
40
42
  - 这次采用的是最小装配、轻量 retrofit 还是更完整装配
@@ -59,7 +61,9 @@
59
61
 
60
62
  - `detected_repository_mode`:静态检测到的仓库模式和 scenario
61
63
  - `risk_summary`:是否会写入重执行控制面、是否保护 repo-owned truth、是否需要显式 intent
64
+ - `required_carriers`:本 profile 必须落盘或保持可读的稳定载体
62
65
  - `planned_writes`:dry-run / write 即将落盘的稳定载体集合
66
+ - `forbidden_authored_carriers`:本 profile 明确禁止生成、声明或保留的 Loom-authored truth carrier
63
67
  - `intentionally_absent`:因 attach-only、light-governance、observe-only 或 skill-install-only 而明确不生成的载体
64
68
  - 初始能力清单的承载位置
65
69
  - 首批 `Work Item` 或等价事项清单的承载位置
@@ -119,6 +123,8 @@
119
123
  - attach-only 必备工件是什么
120
124
  - 哪些 repo-native carriers 继续保留
121
125
  - 哪些 Loom-owned carriers 本轮不会生成
126
+ - `forbidden_authored_carriers` 必须至少包含 `.loom/work-items/**`、`.loom/progress/**`、`.loom/status/current.md`、`.loom/reviews/**`、`.loom/specs/**`
127
+ - verify 必须同时检查磁盘存在、`init-result` 声明、`planned_writes`、manifest artifacts 与 write touched,不得让 forbidden carrier 形成第二事实链
122
128
 
123
129
  `init-result` 只允许承接 locator-only 信息,不并行复制实时停点、下一步、阻断项或最近验证摘要。
124
130
 
@@ -57,9 +57,13 @@
57
57
  - `.loom/work-items/*`
58
58
  - `.loom/progress/*`
59
59
  - `.loom/status/current.md`
60
+ - `.loom/reviews/*`
61
+ - `.loom/specs/*`
60
62
  - Loom-owned recovery/status carriers 的 bootstrap placeholder
61
63
  - 对 branch / PR / worktree / merge / ruleset 的底层宿主重写
62
64
 
65
+ 若上述 Loom-authored carriers 已存在、被 `init-result` / manifest 声明为 generated,或出现在 attach-only planned writes 中,verify 必须 fail closed。执行者只能迁移到宿主 truth locator、删除 competing carrier,或显式升级 intent 到 `execution-control`。
66
+
63
67
  ## 6. 升级信号
64
68
 
65
69
  以下任一条件出现时,不应继续停留在 attach-only 默认路径:
@@ -162,6 +162,7 @@
162
162
  - `policy_locators`
163
163
  - `hook_locators`
164
164
  - `release_targets`
165
+ - `host_truth_locators`
165
166
 
166
167
  稳定约束:
167
168
 
@@ -171,8 +172,9 @@
171
172
  - `policy_locators` 只在 `v2` 合法
172
173
  - `hook_locators` 只在 `v2` 合法
173
174
  - `release_targets` 只在 `v2` 合法
175
+ - `host_truth_locators` 只在 `v2` 合法,且只能声明宿主事实源 locator,例如 GitHub Issue、GitHub Project、PR review / guardian、PR metadata 与 issue state
174
176
  - `v2` 不改变 `repo_specific_requirements` 与 `specialized_gates` 的既有纪律
175
- - `v2` 不把 repo runtime state、review summary、validation status 或 retained host action result 写入 `repo-interface.json`
177
+ - `v2` 不把 repo runtime state、progress/current stop、review verdict、review summary、validation status、closeout result 或 retained host action result 写入 `repo-interface.json`
176
178
 
177
179
  ### 4.3 通用字段纪律
178
180
 
@@ -352,6 +352,7 @@ REPO_INTERFACE_V2_KEYS = REPO_INTERFACE_V1_KEYS | {
352
352
  "policy_locators",
353
353
  "hook_locators",
354
354
  "release_targets",
355
+ "host_truth_locators",
355
356
  }
356
357
  DECLARED_LOCATOR_REQUIREMENTS = {"required", "optional", "advisory"}
357
358
  DECLARED_LOCATOR_OWNERS = {"repo", "repo-companion", "host", "host-adapter", "platform", "external-tool"}
@@ -4336,6 +4336,28 @@ def check_deep_existing_repo_bootstrap(root: Path) -> list[Failure]:
4336
4336
  if pr_template:
4337
4337
  (target / ".github" / "PULL_REQUEST_TEMPLATE.md").write_text("## Summary\n", encoding="utf-8")
4338
4338
 
4339
+ attach_only_forbidden_patterns = (
4340
+ ".loom/work-items/**",
4341
+ ".loom/progress/**",
4342
+ ".loom/status/current.md",
4343
+ ".loom/reviews/**",
4344
+ ".loom/specs/**",
4345
+ )
4346
+
4347
+ def matches_forbidden(path: str, pattern: str) -> bool:
4348
+ if pattern.endswith("/**"):
4349
+ prefix = pattern[:-3]
4350
+ return path == prefix or path.startswith(prefix + "/")
4351
+ return path == pattern
4352
+
4353
+ def forbidden_match(path: object) -> str | None:
4354
+ if not isinstance(path, str):
4355
+ return None
4356
+ for pattern in attach_only_forbidden_patterns:
4357
+ if matches_forbidden(path, pattern):
4358
+ return pattern
4359
+ return None
4360
+
4339
4361
  deep_target = tmp_root / "deep-existing"
4340
4362
  write_repo(deep_target, validation_entry=True, pr_template=True, workflow_doc=True)
4341
4363
  deep_dry_payload, deep_dry_error = load_command_json(
@@ -4356,6 +4378,8 @@ def check_deep_existing_repo_bootstrap(root: Path) -> list[Failure]:
4356
4378
  intent = deep_dry_payload.get("adoption_intent")
4357
4379
  risk = deep_dry_payload.get("risk_summary")
4358
4380
  planned = deep_dry_payload.get("planned_writes")
4381
+ required = deep_dry_payload.get("required_carriers")
4382
+ forbidden = deep_dry_payload.get("forbidden_authored_carriers")
4359
4383
  detected = deep_dry_payload.get("detected_repository_mode")
4360
4384
  write = deep_dry_payload.get("write")
4361
4385
  if not isinstance(intent, dict) or intent.get("effective") != "attach-only":
@@ -4364,6 +4388,18 @@ def check_deep_existing_repo_bootstrap(root: Path) -> list[Failure]:
4364
4388
  failures.append(Failure("deep-existing-bootstrap", "`deep-existing dry-run` must report preserved repo-owned truth risk"))
4365
4389
  if not isinstance(planned, list) or not planned:
4366
4390
  failures.append(Failure("deep-existing-bootstrap", "`deep-existing dry-run` must report planned write targets"))
4391
+ else:
4392
+ for item in planned:
4393
+ if isinstance(item, dict):
4394
+ pattern = forbidden_match(item.get("path"))
4395
+ if pattern:
4396
+ failures.append(Failure("deep-existing-bootstrap", f"`deep-existing dry-run` planned write must not match forbidden carrier `{pattern}`"))
4397
+ if not isinstance(required, list) or not required:
4398
+ failures.append(Failure("deep-existing-bootstrap", "`deep-existing dry-run` must report required carriers"))
4399
+ if not isinstance(forbidden, list) or {
4400
+ item.get("path") for item in forbidden if isinstance(item, dict)
4401
+ } != set(attach_only_forbidden_patterns):
4402
+ failures.append(Failure("deep-existing-bootstrap", "`deep-existing dry-run` must report the full attach-only forbidden carrier list"))
4367
4403
  if not isinstance(detected, dict) or detected.get("scenario_key") != "complex-existing":
4368
4404
  failures.append(Failure("deep-existing-bootstrap", "`deep-existing dry-run` must report detected repository mode"))
4369
4405
  if not isinstance(write, dict) or write.get("enabled") is not False:
@@ -4391,6 +4427,7 @@ def check_deep_existing_repo_bootstrap(root: Path) -> list[Failure]:
4391
4427
  recommended = deep_payload.get("recommended_adoption")
4392
4428
  verification = deep_payload.get("verification")
4393
4429
  governance_surface = deep_payload.get("governance_surface")
4430
+ repo_interface_path = deep_target / ".loom/companion/repo-interface.json"
4394
4431
  if not isinstance(recommended, dict) or recommended.get("path") != "deep-existing-repo":
4395
4432
  failures.append(Failure("deep-existing-bootstrap", "`deep-existing bootstrap` must select `recommended_adoption.path = deep-existing-repo`"))
4396
4433
  run = deep_payload.get("run")
@@ -4413,12 +4450,79 @@ def check_deep_existing_repo_bootstrap(root: Path) -> list[Failure]:
4413
4450
  ".loom/work-items/INIT-0001.md",
4414
4451
  ".loom/progress/INIT-0001.md",
4415
4452
  ".loom/status/current.md",
4453
+ ".loom/reviews/INIT-0001.json",
4454
+ ".loom/specs/INIT-0001/spec.md",
4416
4455
  ):
4417
4456
  if (deep_target / forbidden).exists():
4418
4457
  failures.append(Failure("deep-existing-bootstrap", f"`deep-existing bootstrap` must not generate `{forbidden}`"))
4419
4458
  fact_chain = deep_payload.get("fact_chain")
4420
4459
  if not isinstance(fact_chain, dict) or fact_chain.get("mode") != "repo-native attach-only":
4421
4460
  failures.append(Failure("deep-existing-bootstrap", "`deep-existing bootstrap` must keep `fact_chain.mode = repo-native attach-only`"))
4461
+ if repo_interface_path.exists():
4462
+ repo_interface = json.loads(repo_interface_path.read_text(encoding="utf-8"))
4463
+ host_truth = repo_interface.get("host_truth_locators")
4464
+ if not isinstance(host_truth, dict) or set(host_truth.keys()) != {"work_item", "project_status", "review", "closeout"}:
4465
+ failures.append(Failure("deep-existing-bootstrap", "`deep-existing bootstrap` repo-interface must declare attach-only host truth locators"))
4466
+
4467
+ poisoned_files_target = tmp_root / "deep-existing-poison-files"
4468
+ if deep_target.exists() and (deep_target / ".loom/bin/loom_init.py").exists():
4469
+ shutil.copytree(deep_target, poisoned_files_target)
4470
+ (poisoned_files_target / ".loom/reviews").mkdir(parents=True, exist_ok=True)
4471
+ (poisoned_files_target / ".loom/specs/EXISTING").mkdir(parents=True, exist_ok=True)
4472
+ (poisoned_files_target / ".loom/reviews/EXISTING.json").write_text("{}", encoding="utf-8")
4473
+ (poisoned_files_target / ".loom/specs/EXISTING/spec.md").write_text("# Existing Spec\n", encoding="utf-8")
4474
+ poisoned_payload, poisoned_error = load_command_json(
4475
+ root,
4476
+ [
4477
+ "python3",
4478
+ str(poisoned_files_target / ".loom/bin/loom_init.py"),
4479
+ "verify",
4480
+ "--target",
4481
+ str(poisoned_files_target),
4482
+ ],
4483
+ )
4484
+ if poisoned_error:
4485
+ failures.append(Failure("deep-existing-bootstrap", f"`attach-only forbidden file verify` failed: {poisoned_error}"))
4486
+ else:
4487
+ errors_text = json.dumps(poisoned_payload.get("errors", []), ensure_ascii=False) if poisoned_payload else ""
4488
+ if poisoned_payload.get("ok") is not False:
4489
+ failures.append(Failure("deep-existing-bootstrap", "`attach-only forbidden file verify` must fail closed"))
4490
+ if "forbidden authored carrier" not in errors_text or "second truth chain" not in errors_text:
4491
+ failures.append(Failure("deep-existing-bootstrap", "`attach-only forbidden file verify` must explain the second truth-chain risk"))
4492
+
4493
+ poisoned_decl_target = tmp_root / "deep-existing-poison-declarations"
4494
+ if deep_target.exists() and (deep_target / ".loom/bin/loom_init.py").exists():
4495
+ shutil.copytree(deep_target, poisoned_decl_target)
4496
+ init_result_path = poisoned_decl_target / ".loom/bootstrap/init-result.json"
4497
+ manifest_path = poisoned_decl_target / ".loom/bootstrap/manifest.json"
4498
+ init_result = json.loads(init_result_path.read_text(encoding="utf-8"))
4499
+ init_result.setdefault("planned_writes", []).append(
4500
+ {"path": ".loom/work-items/POISON.md", "kind": "work-item", "owner": "loom"}
4501
+ )
4502
+ init_result_path.write_text(json.dumps(init_result, indent=2, ensure_ascii=False) + "\n", encoding="utf-8")
4503
+ manifest = json.loads(manifest_path.read_text(encoding="utf-8"))
4504
+ manifest.setdefault("artifacts", []).append(
4505
+ {"path": ".loom/progress/POISON.md", "kind": "progress", "source": "generated"}
4506
+ )
4507
+ manifest_path.write_text(json.dumps(manifest, indent=2, ensure_ascii=False) + "\n", encoding="utf-8")
4508
+ poisoned_payload, poisoned_error = load_command_json(
4509
+ root,
4510
+ [
4511
+ "python3",
4512
+ str(poisoned_decl_target / ".loom/bin/loom_init.py"),
4513
+ "verify",
4514
+ "--target",
4515
+ str(poisoned_decl_target),
4516
+ ],
4517
+ )
4518
+ if poisoned_error:
4519
+ failures.append(Failure("deep-existing-bootstrap", f"`attach-only forbidden declaration verify` failed: {poisoned_error}"))
4520
+ else:
4521
+ errors_text = json.dumps(poisoned_payload.get("errors", []), ensure_ascii=False) if poisoned_payload else ""
4522
+ if poisoned_payload.get("ok") is not False:
4523
+ failures.append(Failure("deep-existing-bootstrap", "`attach-only forbidden declaration verify` must fail closed"))
4524
+ if "planned_writes" not in errors_text or "manifest.artifacts" not in errors_text:
4525
+ failures.append(Failure("deep-existing-bootstrap", "`attach-only forbidden declaration verify` must name poisoned declaration sources"))
4422
4526
 
4423
4527
  full_target = tmp_root / "full-bootstrap"
4424
4528
  write_repo(full_target, validation_entry=False, pr_template=False, workflow_doc=False)
@@ -4489,6 +4593,8 @@ def check_deep_existing_repo_bootstrap(root: Path) -> list[Failure]:
4489
4593
  ".loom/work-items/INIT-0001.md",
4490
4594
  ".loom/progress/INIT-0001.md",
4491
4595
  ".loom/status/current.md",
4596
+ ".loom/reviews/INIT-0001.json",
4597
+ ".loom/specs/INIT-0001/spec.md",
4492
4598
  ):
4493
4599
  if not (explicit_full_target / required).exists():
4494
4600
  failures.append(Failure("deep-existing-bootstrap", f"`explicit execution-control bootstrap sample` must generate `{required}`"))
@@ -46,6 +46,55 @@ SCAFFOLD_PROFILES = (
46
46
  "execution-control",
47
47
  "strong-governance",
48
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
+ }
49
98
 
50
99
  RUNTIME_ARTIFACT_SOURCES = {
51
100
  ".loom/bin/loom_init.py": RUNTIME_SOURCE,
@@ -751,6 +800,160 @@ def profile_writes_artifacts(profile: str) -> bool:
751
800
  return profile not in {"observe-only", "skill-install-only"}
752
801
 
753
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
+
754
957
  def adoption_intent_payload(adoption_path: str, intake: dict[str, object]) -> dict[str, object]:
755
958
  requested = str(intake.get("adoption_intent", UNSPECIFIED_ADOPTION_INTENT))
756
959
  source = str(intake.get("adoption_intent_source", "unspecified"))
@@ -1170,6 +1373,7 @@ def intentionally_absent_targets(adoption_path: str, profile: str) -> list[dict[
1170
1373
  {"path": ".loom/work-items/**", "reason": "attach-only preserves host-owned work item truth"},
1171
1374
  {"path": ".loom/progress/**", "reason": "attach-only preserves host-owned recovery truth"},
1172
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"},
1173
1377
  {"path": ".loom/specs/**", "reason": "attach-only does not author Loom execution specs"},
1174
1378
  ]
1175
1379
  if adoption_path == "defer":
@@ -1235,6 +1439,7 @@ def build_result(target_root: Path, scenario: str, intake: dict[str, object], in
1235
1439
  bootstrap_mode=True,
1236
1440
  scenario_override=scenario,
1237
1441
  )
1442
+ initial_artifact_list = initial_artifacts(target_root, install_pr_template, adoption_path, profile)
1238
1443
  result = {
1239
1444
  "schema_version": "loom-init-output/v1",
1240
1445
  "generator": {
@@ -1322,7 +1527,7 @@ def build_result(target_root: Path, scenario: str, intake: dict[str, object], in
1322
1527
  },
1323
1528
  }
1324
1529
  ),
1325
- "initial_artifacts": initial_artifacts(target_root, install_pr_template, adoption_path, profile),
1530
+ "initial_artifacts": initial_artifact_list,
1326
1531
  "initial_work_items": initial_work_items(scenario, target_root, adoption_path, install_pr_template, profile),
1327
1532
  "validation_and_closing": {
1328
1533
  "validation_entry": "python3 .loom/bin/loom_init.py verify --target .",
@@ -1346,7 +1551,7 @@ def build_result(target_root: Path, scenario: str, intake: dict[str, object], in
1346
1551
  ]
1347
1552
  ),
1348
1553
  "clean_state": (
1349
- "all generated attach-only Loom artifacts are readable, verified, and do not introduce Loom-owned recovery/status placeholders"
1554
+ "all generated attach-only Loom artifacts are readable, verified, and do not introduce Loom-authored work/progress/status/review/spec truth carriers"
1350
1555
  if attach_only
1351
1556
  else "all generated light-governance artifacts are readable, verified, and do not introduce Loom-owned work/progress/status carriers"
1352
1557
  if profile == "light-governance"
@@ -1356,7 +1561,7 @@ def build_result(target_root: Path, scenario: str, intake: dict[str, object], in
1356
1561
  [
1357
1562
  "the target repo has a readable root rule entry and attached repo companion entry",
1358
1563
  "the attach-only bootstrap metadata and repo-local validation path are verifiable",
1359
- "the bootstrap manifest does not declare Loom-owned recovery/status carriers for this path",
1564
+ "the bootstrap manifest, init-result, planned writes, and filesystem do not expose forbidden Loom-authored truth carriers",
1360
1565
  ]
1361
1566
  if attach_only
1362
1567
  else [
@@ -1386,7 +1591,13 @@ def build_result(target_root: Path, scenario: str, intake: dict[str, object], in
1386
1591
  }
1387
1592
  result["adoption_intent"] = adoption_intent_payload(adoption_path, intake)
1388
1593
  result["planned_writes"] = planned
1594
+ result["required_carriers"] = required_carriers_for_profile(initial_artifact_list, profile)
1389
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"]
1390
1601
  result["upgrade_triggers"] = upgrade_triggers(deferred if isinstance(deferred, list) else [], profile)
1391
1602
  result["risk_summary"] = risk_summary(adoption_path, intake, planned)
1392
1603
  return result
@@ -1626,8 +1837,8 @@ def companion_manifest_payload() -> dict[str, object]:
1626
1837
  }
1627
1838
 
1628
1839
 
1629
- def repo_interface_payload() -> dict[str, object]:
1630
- return {
1840
+ def repo_interface_payload(profile_name: str = "execution-control") -> dict[str, object]:
1841
+ payload: dict[str, object] = {
1631
1842
  "schema_version": "loom-repo-interface/v2",
1632
1843
  "companion_entry": ".loom/companion/README.md",
1633
1844
  "repo_specific_requirements": {"review": [], "merge_ready": [], "closeout": []},
@@ -1648,6 +1859,9 @@ def repo_interface_payload() -> dict[str, object]:
1648
1859
  "status_locator": ".loom/companion/releases/status.json",
1649
1860
  },
1650
1861
  }
1862
+ if profile_name == "attach-only":
1863
+ payload["host_truth_locators"] = ATTACH_ONLY_HOST_TRUTH_LOCATORS
1864
+ return payload
1651
1865
 
1652
1866
 
1653
1867
  def repo_interop_payload() -> dict[str, object]:
@@ -1924,6 +2138,10 @@ def scaffold_target(
1924
2138
  profile_name = str(profile.get("name")) if isinstance(profile, dict) else "execution-control"
1925
2139
  writes_light_loop = profile_name in {"light-governance", "execution-control", "strong-governance"}
1926
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))
1927
2145
 
1928
2146
  writes: list[tuple[Path, str | dict[str, object], str]] = [
1929
2147
  (target_root / ".loom/README.md", render_loom_readme(result), "text"),
@@ -1933,7 +2151,7 @@ def scaffold_target(
1933
2151
  (target_root / ".loom/bootstrap/capability-map.md", render_capability_map(result), "text"),
1934
2152
  (target_root / ".loom/companion/README.md", render_companion_readme(result), "text"),
1935
2153
  (target_root / ".loom/companion/manifest.json", companion_manifest_payload(), "json"),
1936
- (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"),
1937
2155
  (target_root / ".loom/companion/interop.json", repo_interop_payload(), "json"),
1938
2156
  (target_root / ".loom/companion/checkpoints.md", render_companion_checkpoints(), "text"),
1939
2157
  (target_root / ".loom/companion/review.md", render_companion_review(), "text"),
@@ -2118,7 +2336,9 @@ def verify_target(target_root: Path, output_path: Path) -> list[str]:
2118
2336
  "adoption_intent",
2119
2337
  "detected_repository_mode",
2120
2338
  "risk_summary",
2339
+ "required_carriers",
2121
2340
  "planned_writes",
2341
+ "forbidden_authored_carriers",
2122
2342
  "deferred_capabilities",
2123
2343
  "upgrade_triggers",
2124
2344
  "fact_chain",
@@ -2188,6 +2408,12 @@ def verify_target(target_root: Path, output_path: Path) -> list[str]:
2188
2408
  for forbidden in (".loom/work-items/INIT-0001.md", ".loom/progress/INIT-0001.md", ".loom/status/current.md"):
2189
2409
  if forbidden in declared_generated:
2190
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))
2191
2417
  if profile_name == "light-governance":
2192
2418
  declared_generated = {
2193
2419
  artifact.get("path")
@@ -57,7 +57,7 @@ description: 负责把仓库接入 Loom 的初始化场景入口。Use when Code
57
57
  2. `judge`
58
58
  - 判断这是 `新项目`、`小型既有仓库` 还是 `复杂既有仓库`
59
59
  - 消费或输出 `adoption_intent`;当 intent 不明确且写入会创建重执行控制面时,先停在 decision prompt / dry-run,不静默写入
60
- - 输出 `scaffold_profile`,并按该 profile 列出 required、planned 与 intentionally absent carriers
60
+ - 输出 `scaffold_profile`,并按该 profile 列出 required、planned、intentionally absent forbidden authored carriers
61
61
  - 输出本轮启用能力、暂不启用能力、升级触发条件、source locator、write target 与 validation command
62
62
  3. `write`
63
63
  - 只有用户要求实际落盘时才执行 `bootstrap --write`
@@ -66,7 +66,7 @@ description: Loom 的 root entry。负责初始化新项目或既有仓库,并
66
66
 
67
67
  `--intent` 用来表达采用意图,而不是仓库静态分类。未显式给出 intent 时,dry-run 仍会输出推荐路径、风险摘要和计划写入载体;如果实际写入会创建重执行控制面,必须先显式选择 `execution-control` 或 `strong-governance`。
68
68
 
69
- 每个 intent 会收敛到一个 `scaffold_profile`。`observe-only` 与 `skill-install-only` 不写 adoption carriers;`attach-only` 只写 companion/read surfaces;`light-governance` 写 companion、review/spec 与 PR 最小闭环但不写 Loom-owned work/progress/status;`execution-control` 与 `strong-governance` 才写 Loom-owned execution carriers。
69
+ 每个 intent 会收敛到一个 `scaffold_profile`。`observe-only` 与 `skill-install-only` 不写 adoption carriers;`attach-only` 只写 companion/read surfaces,并显式禁止 `.loom/work-items/**`、`.loom/progress/**`、`.loom/status/current.md`、`.loom/reviews/**`、`.loom/specs/**` 等 Loom-authored truth carriers;`light-governance` 写 companion、review/spec 与 PR 最小闭环但不写 Loom-owned work/progress/status;`execution-control` 与 `strong-governance` 才写 Loom-owned execution carriers。
70
70
 
71
71
  ## 1. 读取顺序
72
72
 
@@ -35,7 +35,9 @@
35
35
  "adoption_intent",
36
36
  "detected_repository_mode",
37
37
  "risk_summary",
38
+ "required_carriers",
38
39
  "planned_writes",
40
+ "forbidden_authored_carriers",
39
41
  "deferred_capabilities",
40
42
  "upgrade_triggers",
41
43
  "fact_chain",
@@ -35,6 +35,8 @@
35
35
  - `writes_artifacts`
36
36
  - `writes_work_item_carriers`
37
37
  - `description`
38
+ - `required_carriers`
39
+ - `forbidden_authored_carriers`
38
40
  - 本轮启用的能力清单
39
41
  - 每项能力分别映射到哪些 `governance`、`harness`、`templates`、`adoption` 规则
40
42
  - 这次采用的是最小装配、轻量 retrofit 还是更完整装配
@@ -59,7 +61,9 @@
59
61
 
60
62
  - `detected_repository_mode`:静态检测到的仓库模式和 scenario
61
63
  - `risk_summary`:是否会写入重执行控制面、是否保护 repo-owned truth、是否需要显式 intent
64
+ - `required_carriers`:本 profile 必须落盘或保持可读的稳定载体
62
65
  - `planned_writes`:dry-run / write 即将落盘的稳定载体集合
66
+ - `forbidden_authored_carriers`:本 profile 明确禁止生成、声明或保留的 Loom-authored truth carrier
63
67
  - `intentionally_absent`:因 attach-only、light-governance、observe-only 或 skill-install-only 而明确不生成的载体
64
68
  - 初始能力清单的承载位置
65
69
  - 首批 `Work Item` 或等价事项清单的承载位置
@@ -119,6 +123,8 @@
119
123
  - attach-only 必备工件是什么
120
124
  - 哪些 repo-native carriers 继续保留
121
125
  - 哪些 Loom-owned carriers 本轮不会生成
126
+ - `forbidden_authored_carriers` 必须至少包含 `.loom/work-items/**`、`.loom/progress/**`、`.loom/status/current.md`、`.loom/reviews/**`、`.loom/specs/**`
127
+ - verify 必须同时检查磁盘存在、`init-result` 声明、`planned_writes`、manifest artifacts 与 write touched,不得让 forbidden carrier 形成第二事实链
122
128
 
123
129
  `init-result` 只允许承接 locator-only 信息,不并行复制实时停点、下一步、阻断项或最近验证摘要。
124
130
 
@@ -57,9 +57,13 @@
57
57
  - `.loom/work-items/*`
58
58
  - `.loom/progress/*`
59
59
  - `.loom/status/current.md`
60
+ - `.loom/reviews/*`
61
+ - `.loom/specs/*`
60
62
  - Loom-owned recovery/status carriers 的 bootstrap placeholder
61
63
  - 对 branch / PR / worktree / merge / ruleset 的底层宿主重写
62
64
 
65
+ 若上述 Loom-authored carriers 已存在、被 `init-result` / manifest 声明为 generated,或出现在 attach-only planned writes 中,verify 必须 fail closed。执行者只能迁移到宿主 truth locator、删除 competing carrier,或显式升级 intent 到 `execution-control`。
66
+
63
67
  ## 6. 升级信号
64
68
 
65
69
  以下任一条件出现时,不应继续停留在 attach-only 默认路径: