@event4u/agent-config 16.3.0 → 16.5.0

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 (532) hide show
  1. package/.augment-plugin/marketplace.json +3 -3
  2. package/.augment-plugin/plugin.json +1 -1
  3. package/.claude-plugin/marketplace.json +1 -1
  4. package/CHANGELOG.md +178 -78
  5. package/README.md +2 -2
  6. package/agents/templates/.ai-council.yml.example +26 -8
  7. package/dist/agent-src/commands/analyze/inbox.md +10 -7
  8. package/dist/agent-src/commands/bug/investigate.md +1 -1
  9. package/dist/agent-src/commands/commit/in-chunks.md +40 -31
  10. package/dist/agent-src/commands/commit.md +72 -33
  11. package/dist/agent-src/commands/condense.md +2 -8
  12. package/dist/agent-src/commands/council/debate.md +11 -7
  13. package/dist/agent-src/commands/council/default.md +10 -9
  14. package/dist/agent-src/commands/council.md +1 -1
  15. package/dist/agent-src/commands/design.md +1 -1
  16. package/dist/agent-src/commands/estimate-ticket.md +1 -1
  17. package/dist/agent-src/commands/feature/explore.md +3 -3
  18. package/dist/agent-src/commands/feature/plan.md +1 -1
  19. package/dist/agent-src/commands/fix/ci.md +17 -3
  20. package/dist/agent-src/commands/fix/commit-messages.md +48 -23
  21. package/dist/agent-src/commands/fix/pr-comments.md +3 -6
  22. package/dist/agent-src/commands/implement-ticket.md +3 -3
  23. package/dist/agent-src/commands/memory/add.md +4 -16
  24. package/dist/agent-src/commands/memory/load.md +5 -6
  25. package/dist/agent-src/commands/memory/promote.md +3 -16
  26. package/dist/agent-src/commands/mission/upgrade.md +3 -2
  27. package/dist/agent-src/commands/optimize/agents-dir.md +2 -2
  28. package/dist/agent-src/commands/optimize/deep.md +4 -2
  29. package/dist/agent-src/commands/optimize/rtk.md +4 -26
  30. package/dist/agent-src/commands/pr/create/description-only.md +18 -15
  31. package/dist/agent-src/commands/pr/create.md +42 -34
  32. package/dist/agent-src/commands/pr/merge.md +136 -9
  33. package/dist/agent-src/commands/prepare-for-review.md +13 -11
  34. package/dist/agent-src/commands/project/analyze.md +7 -35
  35. package/dist/agent-src/commands/refine-ticket.md +1 -1
  36. package/dist/agent-src/commands/review/changes.md +14 -19
  37. package/dist/agent-src/commands/roadmap/next.md +10 -1
  38. package/dist/agent-src/commands/roadmap/process-full.md +52 -38
  39. package/dist/agent-src/commands/roadmap/resolve-blockers.md +64 -14
  40. package/dist/agent-src/commands/worktree/create.md +7 -3
  41. package/dist/agent-src/commands/worktree/verify.md +2 -1
  42. package/dist/agent-src/contexts/communication/rules-auto/think-before-action-mechanics.md +5 -3
  43. package/dist/agent-src/contexts/communication/rules-auto/token-efficiency-mechanics.md +7 -9
  44. package/dist/agent-src/contexts/contracts/command-suggestion-flow.md +8 -6
  45. package/dist/agent-src/contexts/contracts/frugality-charter.md +8 -5
  46. package/dist/agent-src/contexts/execution/auto-dispatch-classification.md +1 -1
  47. package/dist/agent-src/contexts/execution/auto-orchestration-activation.md +0 -1
  48. package/dist/agent-src/contexts/execution/evidence-discipline.md +2 -2
  49. package/dist/agent-src/contexts/execution/non-interactive-contract.md +5 -8
  50. package/dist/agent-src/contexts/execution/rdp-gate.md +4 -4
  51. package/dist/agent-src/contexts/execution/roadmap-execution-contract.md +9 -8
  52. package/dist/agent-src/contexts/execution/roadmap-process-loop.md +67 -52
  53. package/dist/agent-src/contexts/execution/subagent-routing.md +8 -8
  54. package/dist/agent-src/contexts/execution/subagent-steering.md +6 -4
  55. package/dist/agent-src/contexts/execution/terminal-states.md +2 -2
  56. package/dist/agent-src/contexts/execution/toolchain-resolver.md +4 -10
  57. package/dist/agent-src/contexts/subagent-configuration.md +1 -1
  58. package/dist/agent-src/guidelines/agent-infra/active-remediation-mechanics.md +39 -0
  59. package/dist/agent-src/guidelines/agent-infra/context-hygiene-mechanics.md +1 -1
  60. package/dist/agent-src/guidelines/agent-infra/cross-source-consistency-mechanics.md +8 -10
  61. package/dist/agent-src/guidelines/agent-infra/frontier-reasoning-operating-profile.md +3 -2
  62. package/dist/agent-src/guidelines/agent-infra/layered-settings.md +13 -1
  63. package/dist/agent-src/guidelines/agent-infra/roadmap-progress-mechanics.md +1 -1
  64. package/dist/agent-src/guidelines/agent-infra/self-improvement-pipeline.md +10 -3
  65. package/dist/agent-src/guidelines/agent-infra/size-and-scope.md +36 -0
  66. package/dist/agent-src/guidelines/design-antipatterns.md +1 -1
  67. package/dist/agent-src/guidelines/php/git.md +15 -2
  68. package/dist/agent-src/rules/active-remediation.md +0 -1
  69. package/dist/agent-src/rules/analysis-skill-routing.md +0 -1
  70. package/dist/agent-src/rules/architecture.md +0 -1
  71. package/dist/agent-src/rules/artifact-drafting-protocol.md +0 -1
  72. package/dist/agent-src/rules/artifact-engagement-recording.md +0 -1
  73. package/dist/agent-src/rules/augment-edit-discipline.md +0 -1
  74. package/dist/agent-src/rules/autonomous-execution.md +0 -1
  75. package/dist/agent-src/rules/brand-consistency.md +0 -1
  76. package/dist/agent-src/rules/brand-source-of-truth.md +0 -1
  77. package/dist/agent-src/rules/broken-access-control.md +0 -1
  78. package/dist/agent-src/rules/cli-output-handling.md +0 -1
  79. package/dist/agent-src/rules/code-comment-discipline.md +0 -1
  80. package/dist/agent-src/rules/code-provenance.md +0 -1
  81. package/dist/agent-src/rules/command-suggestion-policy.md +0 -1
  82. package/dist/agent-src/rules/commit-conventions.md +1 -2
  83. package/dist/agent-src/rules/communication-through-line.md +1 -2
  84. package/dist/agent-src/rules/content-quoting-floor.md +1 -2
  85. package/dist/agent-src/rules/context-hygiene.md +5 -5
  86. package/dist/agent-src/rules/copilot-routing.md +1 -2
  87. package/dist/agent-src/rules/council-availability.md +4 -4
  88. package/dist/agent-src/rules/cross-source-consistency.md +4 -6
  89. package/dist/agent-src/rules/decision-revisit-gate.md +2 -3
  90. package/dist/agent-src/rules/delegation-policy.md +2 -3
  91. package/dist/agent-src/rules/design-fidelity.md +0 -1
  92. package/dist/agent-src/rules/design-review-after-ui-write.md +3 -3
  93. package/dist/agent-src/rules/devcontainer-routing.md +1 -2
  94. package/dist/agent-src/rules/doc-screenshot-hygiene.md +0 -1
  95. package/dist/agent-src/rules/docker-commands.md +0 -1
  96. package/dist/agent-src/rules/domain-adoption-policy.md +0 -1
  97. package/dist/agent-src/rules/domain-safety-disclaimer.md +0 -1
  98. package/dist/agent-src/rules/domain-safety-pii.md +0 -1
  99. package/dist/agent-src/rules/domain-safety-retention.md +0 -1
  100. package/dist/agent-src/rules/downstream-changes.md +0 -1
  101. package/dist/agent-src/rules/engineering-safety-floor.md +0 -1
  102. package/dist/agent-src/rules/external-code-graph-interop.md +0 -1
  103. package/dist/agent-src/rules/external-reference-deep-dive.md +0 -1
  104. package/dist/agent-src/rules/fast-path-marker-visibility.md +1 -2
  105. package/dist/agent-src/rules/finance-safety-floor.md +0 -1
  106. package/dist/agent-src/rules/fix-what-you-see.md +6 -32
  107. package/dist/agent-src/rules/framework-neutrality-in-generic-skills.md +0 -1
  108. package/dist/agent-src/rules/git-history-discipline.md +1 -2
  109. package/dist/agent-src/rules/guidelines.md +0 -1
  110. package/dist/agent-src/rules/history-discipline.md +0 -1
  111. package/dist/agent-src/rules/icon-consistency.md +0 -1
  112. package/dist/agent-src/rules/image-likeness-and-rights.md +0 -1
  113. package/dist/agent-src/rules/improve-before-implement.md +0 -1
  114. package/dist/agent-src/rules/invite-challenge.md +0 -1
  115. package/dist/agent-src/rules/laravel-routing.md +1 -2
  116. package/dist/agent-src/rules/laravel-translations.md +0 -1
  117. package/dist/agent-src/rules/legal-safety-floor.md +0 -1
  118. package/dist/agent-src/rules/lethal-trifecta-guard.md +0 -1
  119. package/dist/agent-src/rules/linked-projects-onboarding-gate.md +0 -1
  120. package/dist/agent-src/rules/low-impact-corpus-privacy-floor.md +0 -1
  121. package/dist/agent-src/rules/markdown-safe-codeblocks.md +0 -1
  122. package/dist/agent-src/rules/media-governance-routing.md +1 -2
  123. package/dist/agent-src/rules/media-sync-ground-truth.md +0 -1
  124. package/dist/agent-src/rules/minimal-safe-diff.md +0 -1
  125. package/dist/agent-src/rules/missing-skill-recovery.md +0 -1
  126. package/dist/agent-src/rules/missing-tool-handling.md +0 -1
  127. package/dist/agent-src/rules/model-recommendation.md +0 -1
  128. package/dist/agent-src/rules/neighbour-precedence.md +64 -0
  129. package/dist/agent-src/rules/no-attribution-footers.md +0 -1
  130. package/dist/agent-src/rules/no-decorative-emojis-in-git-surfaces.md +0 -1
  131. package/dist/agent-src/rules/no-pr-progress-comments.md +0 -1
  132. package/dist/agent-src/rules/no-roadmap-references.md +0 -1
  133. package/dist/agent-src/rules/notes-first-reasoning.md +0 -1
  134. package/dist/agent-src/rules/onboarding-gate.md +0 -1
  135. package/dist/agent-src/rules/output-discipline.md +0 -1
  136. package/dist/agent-src/rules/package-ci-checks.md +0 -1
  137. package/dist/agent-src/rules/persona-governance.md +2 -3
  138. package/dist/agent-src/rules/php-coding.md +0 -1
  139. package/dist/agent-src/rules/prefer-enums-over-literals.md +0 -1
  140. package/dist/agent-src/rules/preservation-guard.md +0 -1
  141. package/dist/agent-src/rules/provider-lifecycle-discipline.md +2 -3
  142. package/dist/agent-src/rules/question-not-instruction.md +0 -1
  143. package/dist/agent-src/rules/reviewer-awareness.md +0 -1
  144. package/dist/agent-src/rules/roadmap-ci-steps-policy.md +0 -1
  145. package/dist/agent-src/rules/roadmap-progress-sync.md +3 -6
  146. package/dist/agent-src/rules/role-mode-adherence.md +0 -1
  147. package/dist/agent-src/rules/rule-type-governance.md +0 -1
  148. package/dist/agent-src/rules/runtime-safety.md +0 -1
  149. package/dist/agent-src/rules/scale-discipline.md +0 -1
  150. package/dist/agent-src/rules/secret-vcs-guard.md +0 -1
  151. package/dist/agent-src/rules/security-sensitive-stop.md +0 -1
  152. package/dist/agent-src/rules/self-repair-loop.md +0 -1
  153. package/dist/agent-src/rules/senior-engineering-discipline.md +0 -1
  154. package/dist/agent-src/rules/session-canary.md +0 -1
  155. package/dist/agent-src/rules/settings-ask-protocol.md +5 -6
  156. package/dist/agent-src/rules/size-enforcement.md +0 -1
  157. package/dist/agent-src/rules/skill-improvement-trigger.md +2 -3
  158. package/dist/agent-src/rules/skill-quality.md +0 -1
  159. package/dist/agent-src/rules/slash-command-routing-policy.md +0 -1
  160. package/dist/agent-src/rules/source-confidentiality.md +0 -1
  161. package/dist/agent-src/rules/source-discovery-gate.md +0 -1
  162. package/dist/agent-src/rules/source-of-truth.md +0 -1
  163. package/dist/agent-src/rules/spreadsheet-source-quality.md +1 -2
  164. package/dist/agent-src/rules/strategy-safety-floor.md +0 -1
  165. package/dist/agent-src/rules/symfony-routing.md +1 -2
  166. package/dist/agent-src/rules/think-before-action.md +0 -1
  167. package/dist/agent-src/rules/token-budget-discipline.md +14 -48
  168. package/dist/agent-src/rules/token-efficiency.md +0 -1
  169. package/dist/agent-src/rules/token-optimizer-maintenance.md +0 -1
  170. package/dist/agent-src/rules/tool-safety.md +0 -1
  171. package/dist/agent-src/rules/ui-audit-gate.md +1 -2
  172. package/dist/agent-src/rules/untrusted-input-defense.md +0 -1
  173. package/dist/agent-src/rules/upstream-proposal.md +0 -1
  174. package/dist/agent-src/rules/user-interaction.md +0 -1
  175. package/dist/agent-src/rules/user-interrupt-priority.md +0 -1
  176. package/dist/agent-src/scripts/gate_budget.ts +47 -23
  177. package/dist/agent-src/scripts/gate_execute.ts +12 -4
  178. package/dist/agent-src/skills/accessibility-auditor/data/aria-patterns.csv +2 -0
  179. package/dist/agent-src/skills/accessibility-auditor/data/manifest.json +3 -3
  180. package/dist/agent-src/skills/ai-council/SKILL.md +7 -4
  181. package/dist/agent-src/skills/ai-council/references/cost-and-redaction.md +21 -11
  182. package/dist/agent-src/skills/ai-council/references/procedure.md +12 -6
  183. package/dist/agent-src/skills/analysis-autonomous-mode/SKILL.md +1 -1
  184. package/dist/agent-src/skills/bug-analyzer/SKILL.md +1 -1
  185. package/dist/agent-src/skills/canvas-design/SKILL.md +4 -2
  186. package/dist/agent-src/skills/command-routing/SKILL.md +3 -4
  187. package/dist/agent-src/skills/conventional-commits-writing/SKILL.md +127 -139
  188. package/dist/agent-src/skills/corpus-grounding/ATTRIBUTION.md +39 -0
  189. package/dist/agent-src/skills/corpus-grounding/SKILL.md +8 -2
  190. package/dist/agent-src/skills/database/data/manifest.json +2 -2
  191. package/dist/agent-src/skills/database/data/query-tuning.csv +13 -13
  192. package/dist/agent-src/skills/design-intelligence/references/integration-mapping.md +13 -10
  193. package/dist/agent-src/skills/design-system-capture/SKILL.md +0 -3
  194. package/dist/agent-src/skills/estimate-ticket/SKILL.md +1 -1
  195. package/dist/agent-src/skills/fe-design/references/design-patterns.md +49 -2
  196. package/dist/agent-src/skills/feature-planning/SKILL.md +1 -1
  197. package/dist/agent-src/skills/frontend-render-security/SKILL.md +9 -0
  198. package/dist/agent-src/skills/git-workflow/SKILL.md +44 -44
  199. package/dist/agent-src/skills/git-workflow/references/branch-update.md +312 -0
  200. package/dist/agent-src/skills/git-workflow/references/commit-subject.md +205 -0
  201. package/dist/agent-src/skills/iconography/SKILL.md +4 -2
  202. package/dist/agent-src/skills/image-provider-routing/SKILL.md +16 -5
  203. package/dist/agent-src/skills/jira-integration/SKILL.md +3 -3
  204. package/dist/agent-src/skills/logo-generation/SKILL.md +12 -8
  205. package/dist/agent-src/skills/merge-conflicts/SKILL.md +10 -4
  206. package/dist/agent-src/skills/po-discovery/SKILL.md +1 -1
  207. package/dist/agent-src/skills/refine-ticket/SKILL.md +4 -4
  208. package/dist/agent-src/skills/roadmap-writing/SKILL.md +2 -2
  209. package/dist/agent-src/skills/skill-improvement-pipeline/SKILL.md +4 -2
  210. package/dist/agent-src/skills/source-discovery/SKILL.md +1 -1
  211. package/dist/agent-src/skills/svg-authoring/SKILL.md +318 -0
  212. package/dist/agent-src/skills/tailwind-engineer/SKILL.md +3 -1
  213. package/dist/agent-src/skills/testing-anti-patterns/SKILL.md +1 -1
  214. package/dist/agent-src/skills/using-git-worktrees/SKILL.md +1 -1
  215. package/dist/agent-src/skills/verify-repair-loop/SKILL.md +2 -2
  216. package/dist/agent-src/skills/wireframe/SKILL.md +5 -2
  217. package/dist/agent-src/templates/AGENTS.md +1 -1
  218. package/dist/agent-src/templates/agent-settings.md +46 -129
  219. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +3 -3
  220. package/dist/agent-src/templates/command.md +2 -2
  221. package/dist/agent-src/templates/roadmaps.md +6 -1
  222. package/dist/agent-src/templates/scripts/work_engine/_lib/agent_settings.ts +0 -6
  223. package/dist/agent-src/templates/scripts/work_engine/directives/backend/_self_fix.ts +11 -7
  224. package/dist/agent-src/templates/scripts/work_engine/hooks/builtin/decision_trace.ts +3 -2
  225. package/dist/agent-src/templates/scripts/work_engine/hooks/builtin/memory_visibility.ts +2 -1
  226. package/dist/agent-src/templates/scripts/work_engine/hooks/settings.ts +0 -6
  227. package/dist/agent-src/templates/scripts/work_engine/scoring/decision_engine.ts +9 -12
  228. package/dist/agent-src/templates/scripts/work_engine/scoring/memory_visibility.ts +2 -1
  229. package/dist/agent-src/templates/skill.md +1 -1
  230. package/dist/cli/commands/uiRender.js +201 -4
  231. package/dist/cli/commands/uiRenderAsset.js +1308 -0
  232. package/dist/cli/commands/uiRenderAssetCompare.js +752 -0
  233. package/dist/cli/commands/uiRenderAssetGrid.js +265 -0
  234. package/dist/cli/commands/uiRenderAssetGrounds.js +323 -0
  235. package/dist/cli/commands/uiRenderAssetIsolation.js +85 -0
  236. package/dist/cli/commands/uiRenderAssetTypes.js +145 -0
  237. package/dist/cli/main.js +47 -1
  238. package/dist/cli/registry.js +2 -1
  239. package/dist/cli-delegate/check_update_banner.js +195 -119
  240. package/dist/cli-delegate/{chunk-S4UMZNES.js → chunk-4DBG5K7M.js} +5 -5
  241. package/dist/cli-delegate/{chunk-TRI6DQZ6.js → chunk-5GPULQBE.js} +60 -42
  242. package/dist/cli-delegate/{chunk-JQVYKIZA.js → chunk-6SRJTYJS.js} +33 -177
  243. package/dist/cli-delegate/chunk-6V5FMA3P.js +186 -0
  244. package/dist/cli-delegate/chunk-6YQC2HLF.js +415 -0
  245. package/dist/cli-delegate/{chunk-E4XIZDIB.js → chunk-7HKRE54K.js} +1 -64
  246. package/dist/cli-delegate/{chunk-7HQ52DHU.js → chunk-AL3RZ22D.js} +1 -1
  247. package/dist/cli-delegate/{chunk-DBH4AHDK.js → chunk-ED7KCMLB.js} +9 -11
  248. package/dist/cli-delegate/{chunk-NXEILF2K.js → chunk-F3QDG2GT.js} +481 -72
  249. package/dist/cli-delegate/{chunk-CQWX336L.js → chunk-G5VVIZRC.js} +3 -3
  250. package/dist/cli-delegate/{chunk-JY2I2DXV.js → chunk-H76PHZBI.js} +137 -60
  251. package/dist/cli-delegate/chunk-IAYTIIQW.js +67 -0
  252. package/dist/cli-delegate/{chunk-LIYTLH6O.js → chunk-KXXWJTDO.js} +5 -10
  253. package/dist/cli-delegate/{chunk-T7L2QK3K.js → chunk-LQOCRFWT.js} +1 -1
  254. package/dist/cli-delegate/{chunk-S4YWNRKO.js → chunk-MDPPKQCQ.js} +34 -1
  255. package/dist/cli-delegate/chunk-OAFSJBHH.js +272 -0
  256. package/dist/cli-delegate/{chunk-GKE7ZVFA.js → chunk-PWX7CKMD.js} +1 -1
  257. package/dist/cli-delegate/{chunk-NDJLNC6Q.js → chunk-T6BP34WI.js} +1 -0
  258. package/dist/cli-delegate/{chunk-RQNNW7IF.js → chunk-T7XSJSUQ.js} +433 -632
  259. package/dist/cli-delegate/{chunk-NQ7WT43P.js → chunk-TMWYUOK4.js} +75 -12
  260. package/dist/cli-delegate/{chunk-EEHDXSYD.js → chunk-WQWXGIWB.js} +12 -273
  261. package/dist/cli-delegate/{chunk-QLDHIPWR.js → chunk-XQTPXKFA.js} +1 -1
  262. package/dist/cli-delegate/cmd_analyze_session.js +223 -43
  263. package/dist/cli-delegate/cmd_brand_status.js +3 -2
  264. package/dist/cli-delegate/cmd_conformance.js +489 -238
  265. package/dist/cli-delegate/cmd_converge.js +3 -3
  266. package/dist/cli-delegate/cmd_doctor.js +15 -12
  267. package/dist/cli-delegate/cmd_doctor_neighbours.js +11 -4
  268. package/dist/cli-delegate/cmd_explain.js +43 -19
  269. package/dist/cli-delegate/cmd_export.js +10 -10
  270. package/dist/cli-delegate/cmd_git_convention.js +1851 -0
  271. package/dist/cli-delegate/cmd_handoff.js +40 -21
  272. package/dist/cli-delegate/cmd_mcp_available.js +3 -2
  273. package/dist/cli-delegate/cmd_migrate.js +3 -3
  274. package/dist/cli-delegate/cmd_packs_active.js +4 -3
  275. package/dist/cli-delegate/cmd_prune.js +10 -10
  276. package/dist/cli-delegate/cmd_route_audit.js +7 -7
  277. package/dist/cli-delegate/cmd_route_explain.js +5 -5
  278. package/dist/cli-delegate/cmd_session_recycle.js +9 -7
  279. package/dist/cli-delegate/cmd_settings_check.js +54 -7
  280. package/dist/cli-delegate/cmd_settings_get.js +18 -8
  281. package/dist/cli-delegate/cmd_settings_migrate.js +10 -10
  282. package/dist/cli-delegate/cmd_settings_set.js +1 -1
  283. package/dist/cli-delegate/cmd_sync.js +10 -10
  284. package/dist/cli-delegate/cmd_uninstall.js +10 -10
  285. package/dist/cli-delegate/cmd_update.js +7 -7
  286. package/dist/cli-delegate/cmd_upgrade.js +7 -7
  287. package/dist/cli-delegate/cmd_validate.js +10 -10
  288. package/dist/cli-delegate/cmd_versions.js +5 -5
  289. package/dist/cli-delegate/gate_budget.js +1 -1
  290. package/dist/cli-delegate/gate_execute.js +2 -2
  291. package/dist/cli-delegate/roadmap_gates.js +2 -2
  292. package/dist/discovery/deprecation-report.md +1 -1
  293. package/dist/discovery/discovery-manifest.json +171 -107
  294. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  295. package/dist/discovery/discovery-manifest.summary.md +7 -7
  296. package/dist/discovery/dormancy-report.md +1 -1
  297. package/dist/discovery/orphan-report.md +1 -1
  298. package/dist/discovery/packs.json +41 -22
  299. package/dist/discovery/trust-report.md +3 -3
  300. package/dist/discovery/workspaces.json +16 -11
  301. package/dist/hooks/dispatch.js +2520 -1924
  302. package/dist/hooks/dispatch.sha256 +1 -1
  303. package/dist/hooks/svg_rules.chunk.cjs +1626 -0
  304. package/dist/hooks/svg_rules.chunk.cjs.sha256 +1 -0
  305. package/dist/install/install.mjs +462 -431
  306. package/dist/install/installThinLayer.js +40 -12
  307. package/dist/install/installedRuleLinks.js +105 -19
  308. package/dist/mcp/awesome-mcp-servers.row.md +1 -1
  309. package/dist/mcp/mcp-cloudflare-catalogue.json +2 -2
  310. package/dist/mcp/registry-manifest.json +5 -5
  311. package/dist/mcp/server.json +2 -2
  312. package/dist/mcp/server.mjs +3063 -2160
  313. package/dist/router.json +1 -1
  314. package/dist/scripts/_lib/agent_settings.js +15 -120
  315. package/dist/scripts/_lib/compile_time_toggles.js +12 -21
  316. package/dist/scripts/_lib/git_convention.js +232 -0
  317. package/dist/scripts/_lib/global_deploy_inventory.js +730 -0
  318. package/dist/scripts/_lib/installed_layer.js +344 -18
  319. package/dist/scripts/_lib/package_root.js +68 -0
  320. package/dist/scripts/_lib/rule_law_section.js +1 -1
  321. package/dist/scripts/_lib/scan_scope.js +105 -0
  322. package/dist/scripts/_lib/settings_removed_keys.js +168 -0
  323. package/dist/scripts/_lib/svg_dom.js +284 -0
  324. package/dist/scripts/_lib/svg_geometry.js +477 -0
  325. package/dist/scripts/_lib/svg_motion.js +179 -0
  326. package/dist/scripts/_lib/svg_rules.js +1337 -0
  327. package/dist/scripts/_lib/svg_urls.js +67 -0
  328. package/dist/scripts/_lib/thin_rules.js +80 -3
  329. package/dist/scripts/lint_svg_asset.js +324 -0
  330. package/dist/server/app.js +2 -1
  331. package/dist/server/gitKeysGate.js +105 -0
  332. package/dist/server/routes/settings.js +67 -8
  333. package/dist/server/routes/wizard.js +4 -0
  334. package/dist/server/schemas/settings.js +23 -81
  335. package/dist/shared/skillRanking.js +30 -4
  336. package/dist/ui/assets/{index-Cwq4d0hX.js → index-C3djEJah.js} +2 -2
  337. package/dist/ui/index.html +1 -1
  338. package/docs/MIGRATION.md +72 -1
  339. package/docs/contracts/settings-classes.md +35 -65
  340. package/docs/guidelines/agent-infra/active-remediation-mechanics.md +39 -0
  341. package/docs/guidelines/agent-infra/context-hygiene-mechanics.md +1 -1
  342. package/docs/guidelines/agent-infra/cross-source-consistency-mechanics.md +8 -10
  343. package/docs/guidelines/agent-infra/frontier-reasoning-operating-profile.md +3 -2
  344. package/docs/guidelines/agent-infra/layered-settings.md +13 -1
  345. package/docs/guidelines/agent-infra/roadmap-progress-mechanics.md +1 -1
  346. package/docs/guidelines/agent-infra/self-improvement-pipeline.md +10 -3
  347. package/docs/guidelines/agent-infra/size-and-scope.md +36 -0
  348. package/docs/guidelines/design-antipatterns.md +1 -1
  349. package/docs/guidelines/php/git.md +15 -2
  350. package/package.json +4 -3
  351. package/src/agent-src/scripts/gate_budget.ts +47 -23
  352. package/src/agent-src/scripts/gate_execute.ts +12 -4
  353. package/src/agent-src/templates/AGENTS.md +1 -1
  354. package/src/agent-src/templates/scripts/work_engine/_lib/agent_settings.ts +0 -6
  355. package/src/agent-src/templates/scripts/work_engine/directives/backend/_self_fix.ts +11 -7
  356. package/src/agent-src/templates/scripts/work_engine/hooks/builtin/decision_trace.ts +3 -2
  357. package/src/agent-src/templates/scripts/work_engine/hooks/builtin/memory_visibility.ts +2 -1
  358. package/src/agent-src/templates/scripts/work_engine/hooks/settings.ts +0 -6
  359. package/src/agent-src/templates/scripts/work_engine/scoring/decision_engine.ts +9 -12
  360. package/src/agent-src/templates/scripts/work_engine/scoring/memory_visibility.ts +2 -1
  361. package/src/config/agent-settings.template.yml +79 -312
  362. package/src/config/agents-paths.yml +16 -0
  363. package/src/config/assurance-capability-registry.json +7 -3
  364. package/src/config/ci-local-parity.yml +3 -0
  365. package/src/config/continuity-surface.json +3 -3
  366. package/src/config/discovery/packs.yml +17 -1
  367. package/src/config/evaluator-budgets.json +19 -6
  368. package/src/config/gate-coverage.yml +65 -23
  369. package/src/config/gate-violation-baselines.json +56 -16
  370. package/src/config/gitignore-block.txt +19 -0
  371. package/src/config/hook-bundle-budget.json +1 -1
  372. package/src/config/release-gate-locality.yml +2 -1
  373. package/src/config/routing-coverage-seed.json +55 -6
  374. package/src/config/rule-law-ceilings.json +12 -6
  375. package/src/config/rule-obligations.json +833 -0
  376. package/src/install/installThinLayer.ts +76 -10
  377. package/src/install/installedRuleLinks.ts +105 -17
  378. package/src/scripts/_cli/cmd_analyze_session.ts +9 -15
  379. package/src/scripts/_cli/cmd_conformance.ts +13 -2
  380. package/src/scripts/_cli/cmd_doctor.ts +10 -10
  381. package/src/scripts/_cli/cmd_doctor_neighbours.ts +133 -0
  382. package/src/scripts/_cli/cmd_explain.ts +72 -14
  383. package/src/scripts/_cli/cmd_git_convention.ts +637 -0
  384. package/src/scripts/_cli/cmd_settings_check.ts +66 -8
  385. package/src/scripts/_cli/cmd_settings_get.ts +18 -3
  386. package/src/scripts/_cli/doctor_execution.ts +72 -1
  387. package/src/scripts/_dispatch.bash +37 -2
  388. package/src/scripts/_lib/agent_settings.ts +15 -124
  389. package/src/scripts/_lib/blocked_by_marker.ts +1 -1
  390. package/src/scripts/_lib/compile_time_toggles.ts +12 -21
  391. package/src/scripts/_lib/dispatch_import_closure.ts +163 -0
  392. package/src/scripts/_lib/git_base_ref.ts +92 -0
  393. package/src/scripts/_lib/git_convention.ts +291 -0
  394. package/src/scripts/_lib/git_convention_carrier.ts +389 -0
  395. package/src/scripts/_lib/git_convention_grammar.ts +246 -0
  396. package/src/scripts/_lib/git_convention_measure.ts +344 -0
  397. package/src/scripts/_lib/global_deploy_inventory.ts +74 -0
  398. package/src/scripts/_lib/graph_feeder_record.ts +236 -13
  399. package/src/scripts/_lib/installed_layer.ts +448 -23
  400. package/src/scripts/_lib/knowledge_global.ts +14 -1
  401. package/src/scripts/_lib/module_reach.ts +456 -0
  402. package/src/scripts/_lib/neighbour_contradictions.ts +236 -0
  403. package/src/scripts/_lib/neighbour_tool_use.ts +8 -10
  404. package/src/scripts/_lib/ratification_artifact.ts +220 -1
  405. package/src/scripts/_lib/ratification_subject.ts +92 -0
  406. package/src/scripts/_lib/release_findings_ingest.ts +15 -7
  407. package/src/scripts/_lib/release_highlights.ts +5 -0
  408. package/src/scripts/_lib/rule_law_section.ts +1 -1
  409. package/src/scripts/_lib/rule_obligations.ts +205 -0
  410. package/src/scripts/_lib/self_repair.ts +1 -1
  411. package/src/scripts/_lib/settings_removed_keys.ts +173 -0
  412. package/src/scripts/_lib/svg_dom.ts +318 -0
  413. package/src/scripts/_lib/svg_geometry.ts +480 -0
  414. package/src/scripts/_lib/svg_motion.ts +208 -0
  415. package/src/scripts/_lib/svg_rules.ts +1453 -0
  416. package/src/scripts/_lib/svg_urls.ts +72 -0
  417. package/src/scripts/_lib/test_red_state.ts +5 -0
  418. package/src/scripts/_lib/thin_rules.ts +83 -3
  419. package/src/scripts/_lib/touched_file_quality.ts +142 -6
  420. package/src/scripts/_lib/verification_command.ts +59 -0
  421. package/src/scripts/_lib/verify_clause.ts +27 -17
  422. package/src/scripts/_lib/worker_budget.ts +1 -1
  423. package/src/scripts/adr/regenerate_index.ts +16 -1
  424. package/src/scripts/ai_council/config.ts +7 -7
  425. package/src/scripts/ai_council/modification_review.ts +100 -0
  426. package/src/scripts/ai_council/modification_review_questions.ts +90 -0
  427. package/src/scripts/ai_council/orchestrator.ts +5 -5
  428. package/src/scripts/ai_council/spend_gate.ts +18 -7
  429. package/src/scripts/ai_team/config.ts +11 -16
  430. package/src/scripts/audit_user_type_axis.ts +20 -8
  431. package/src/scripts/bench_ab_clone.ts +1 -2
  432. package/src/scripts/bench_concern_spawn_path.ts +129 -0
  433. package/src/scripts/bench_graph_feeder_latency.ts +584 -0
  434. package/src/scripts/check_agent_artifact_location.ts +36 -0
  435. package/src/scripts/check_branch_freshness.ts +147 -24
  436. package/src/scripts/check_enforcement_coverage.ts +130 -0
  437. package/src/scripts/check_evaluator_budgets.ts +4 -0
  438. package/src/scripts/check_finding_dispositions.ts +88 -25
  439. package/src/scripts/check_gate_coverage.ts +4 -3
  440. package/src/scripts/check_gate_reachability.ts +48 -1
  441. package/src/scripts/check_generator_sync.ts +48 -0
  442. package/src/scripts/check_hook_bundle_composition.ts +107 -0
  443. package/src/scripts/check_kernel_edit_ratified.ts +86 -6
  444. package/src/scripts/check_pack_size.ts +1 -1
  445. package/src/scripts/check_release_manifest_content.ts +189 -0
  446. package/src/scripts/check_standing_rule_delivery.ts +96 -0
  447. package/src/scripts/check_suppression_hygiene.ts +2 -5
  448. package/src/scripts/ci_settle.ts +42 -5
  449. package/src/scripts/classify_merge_risk.ts +320 -0
  450. package/src/scripts/closure_scan.ts +91 -1
  451. package/src/scripts/command_suggester/settings.ts +8 -108
  452. package/src/scripts/command_suggester/types.ts +4 -5
  453. package/src/scripts/consumer_matrix.ts +102 -0
  454. package/src/scripts/context_hygiene_hook.ts +13 -23
  455. package/src/scripts/cost/preflight.mjs +12 -1
  456. package/src/scripts/council_cli.ts +7 -7
  457. package/src/scripts/dispatch_r2_reviewer.ts +24 -11
  458. package/src/scripts/explain_run.ts +8 -13
  459. package/src/scripts/generate_git_convention_grammar.ts +127 -0
  460. package/src/scripts/generate_host_cost_table.ts +20 -3
  461. package/src/scripts/handoff_context_hook.ts +86 -37
  462. package/src/scripts/hook_manifest.json +1 -1
  463. package/src/scripts/hook_manifest.yaml +25 -6
  464. package/src/scripts/hooks/block_config_weakening.ts +48 -5
  465. package/src/scripts/hooks/block_plumbing_writes.ts +8 -4
  466. package/src/scripts/hooks/block_speaking_inbox_dir.ts +16 -1
  467. package/src/scripts/hooks/concern_registry.ts +2 -0
  468. package/src/scripts/hooks/delegation_nudge_hook.ts +2 -3
  469. package/src/scripts/hooks/design_pass_hook.ts +157 -3
  470. package/src/scripts/hooks/evidence_independence.ts +12 -4
  471. package/src/scripts/hooks/mcp_usage_observation_hook.ts +121 -0
  472. package/src/scripts/hooks/push_settle_hook.ts +4 -3
  473. package/src/scripts/hooks/rule_inject_hook.ts +44 -3
  474. package/src/scripts/hooks/state_io.ts +8 -4
  475. package/src/scripts/hooks/svg_obligation.ts +497 -0
  476. package/src/scripts/hooks/svg_rules_loader.ts +133 -0
  477. package/src/scripts/hooks/telemetry_usage_hook.ts +7 -46
  478. package/src/scripts/hooks/turn_end_gate_hook.ts +6 -3
  479. package/src/scripts/install-hooks.sh +42 -14
  480. package/src/scripts/install.ts +7 -31
  481. package/src/scripts/lint_blocker_citations.ts +198 -0
  482. package/src/scripts/lint_consolidation_lineage.ts +6 -3
  483. package/src/scripts/lint_design_quality.ts +60 -12
  484. package/src/scripts/lint_evidence_artifacts.ts +9 -0
  485. package/src/scripts/lint_hook_concern_budget.ts +10 -21
  486. package/src/scripts/lint_motion_authority_drift.ts +27 -0
  487. package/src/scripts/lint_pack_boundaries.ts +406 -28
  488. package/src/scripts/lint_roadmap_blockers.ts +282 -29
  489. package/src/scripts/lint_roadmap_complexity.ts +4 -2
  490. package/src/scripts/lint_rule_law_section.ts +151 -21
  491. package/src/scripts/lint_rule_skill_pack_reach.ts +17 -0
  492. package/src/scripts/lint_settings_classes.ts +1 -1
  493. package/src/scripts/lint_svg_asset.ts +365 -0
  494. package/src/scripts/lint_ticked_unmet_criteria.ts +165 -0
  495. package/src/scripts/lint_workflow_security.ts +12 -1
  496. package/src/scripts/measure_skill_ranker_baseline.ts +5 -0
  497. package/src/scripts/model_rule_injection.ts +3 -3
  498. package/src/scripts/onboarding_gate_hook.ts +7 -6
  499. package/src/scripts/print_required_checks.ts +15 -3
  500. package/src/scripts/probe_host_compliance.ts +33 -5
  501. package/src/scripts/probe_turnaround.ts +183 -3
  502. package/src/scripts/ratification_header.ts +77 -0
  503. package/src/scripts/refusal_envelope.ts +138 -0
  504. package/src/scripts/release_publication.ts +29 -3
  505. package/src/scripts/report_dispatch_import_closure.ts +76 -0
  506. package/src/scripts/report_installed_rule_links.ts +118 -1
  507. package/src/scripts/report_module_reach.ts +212 -0
  508. package/src/scripts/report_obligation_mechanism.ts +16 -18
  509. package/src/scripts/report_parked_blockers.ts +222 -0
  510. package/src/scripts/report_required_checks_drift.ts +196 -0
  511. package/src/scripts/report_skill_ranker_confusion.ts +103 -2
  512. package/src/scripts/report_standing_payload_by_host.ts +1 -1
  513. package/src/scripts/routing_doctor.ts +2 -2
  514. package/src/scripts/schemas/agent-settings.schema.json +17 -31
  515. package/src/scripts/schemas/command.schema.json +1 -1
  516. package/src/scripts/schemas/skill.schema.json +1 -1
  517. package/src/scripts/self_review_gate.ts +39 -2
  518. package/src/scripts/skill_tools/score_skill_relevance.ts +28 -19
  519. package/src/scripts/sync_pr_branch.ts +403 -132
  520. package/src/scripts/trigger_eval_grandfather.json +0 -16
  521. package/src/server/schemas/settings.ts +33 -177
  522. package/src/shared/skillRanking.ts +53 -4
  523. package/dist/cli-delegate/chunk-NYX3L2PZ.js +0 -99
  524. package/src/scripts/_lib/config_chain.ts +0 -477
  525. package/src/scripts/_lib/conformance_report.ts +0 -403
  526. package/src/scripts/_lib/eval_discrimination.ts +0 -95
  527. package/src/scripts/_lib/evaluator_promotion.ts +0 -225
  528. package/src/scripts/_lib/file_slicer.ts +0 -117
  529. package/src/scripts/_lib/legacy_boundary_map.ts +0 -228
  530. package/src/scripts/_lib/minimality_tiebreak.ts +0 -168
  531. package/src/scripts/_lib/overbuild_lens_contract.ts +0 -196
  532. package/src/scripts/_lib/role_split.ts +0 -338
@@ -51,6 +51,7 @@ NO SECRET, PRIVILEGED KEY, OR SESSION TOKEN LIVES IN CLIENT CODE OR localStorage
51
51
  | `eval` / `new Function` / string-`setTimeout` on input | Eval injection / RCE (CWE-95) | a parser or explicit allow-list |
52
52
  | `target="_blank"` without `rel="noopener"` | Reverse tabnabbing (CWE-1022) | add `rel="noopener noreferrer"` |
53
53
  | Missing CSP; missing alt/label/contrast | No XSS second line of defense; a11y failures | strict CSP (no `unsafe-inline`); alt text, labels, AA contrast |
54
+ | Untrusted SVG markup into an HTML sink — `innerHTML` / `v-html` / `dangerouslySetInnerHTML`, or inlined server-side | An inlined SVG is live DOM, not an image: `on*` event attributes, `<script>`, `foreignObject`, a `javascript:` href and external references all execute, and a DOCTYPE with entities reads local files (CWE-79, CWE-611) | sanitize with an SVG profile chosen for the **delivery context** — inline DOM runs script and handlers in the host origin; a standalone `.svg` opened directly runs them in its own; `<img>` and CSS `background-image` run no script and load no external reference — or deliver through `<img>`, with CSP as the second line. Uploads are `threat-modeling`'s `data/threats.csv:9`, not this row |
54
55
 
55
56
  ## The server-composed bootstrap payload
56
57
 
@@ -108,6 +109,14 @@ rg -n "origin:\s*['\"]\*['\"]|Access-Control-Allow-Origin.*\*"
108
109
  rg -n "addEventListener\(\s*['\"]message['\"]" # then confirm each checks event.origin
109
110
  # Unhardened external links
110
111
  rg -n 'target=["'\'']_blank["'\'']' # then confirm rel="noopener" present
112
+ # SVG active content — markup that executes once the SVG is inlined.
113
+ # Scoped to *.svg, where an on* attribute is always a defect. In .jsx/.tsx an
114
+ # on* attribute is ordinary React and matching it there would bury the signal;
115
+ # an on* on INLINE svg inside a host document is DQ4's case, not this grep's.
116
+ # <script is listed because the row above names it and the pattern did not.
117
+ # A locator, not a verdict: entity-encoded or tab-split javascript:, <svg:script>
118
+ # and SMIL writes into href get past it. `lint_svg_asset` (svg-authoring) decodes them.
119
+ rg -n '<foreignObject|<script[\s>]|\son[a-z]+\s*=|(?:xlink:)?href\s*=\s*["'\'']?\s*javascript:' -g '*.svg'
111
120
  # Server-composed bootstrap payload — LOCATES it; the per-field judgement is yours
112
121
  rg -n '__NEXT_DATA__|__NUXT__|window\.__INITIAL_STATE__|@json\(|json_encode\([^)]*\)\s*\)?\s*</script>|dehydratedState'
113
122
  ```
@@ -56,7 +56,7 @@ gh pr view <number> --json number,state,mergeStateStatus,mergedAt,baseRefName
56
56
  **same turn**; never merge on a status seen earlier in the conversation.
57
57
  - **"Based on main" / "current"** → prove it with
58
58
  `npx tsx node_modules/@event4u/agent-config/src/scripts/check_branch_freshness.ts`;
59
- exit `1` ⇒ the branch is behind and is **not** current — merge the base in,
59
+ exit `1` ⇒ the branch is behind and is **not** current (or the named base does not exist on the remote; the message says which) — update it from the base per `git.update_strategy` ([`references/branch-update.md`](references/branch-update.md)),
60
60
  regenerate the derived files, then open the PR (see
61
61
  [`/create-pr`](../../commands/pr/create.md) § 1b). Exit `0` means only that
62
62
  the gate did **not refuse**: read the line. `branch is current` is the pass;
@@ -76,13 +76,13 @@ gh pr view <number> --json number,state,mergeStateStatus,mergedAt,baseRefName
76
76
  ## Conventions
77
77
 
78
78
  → See guideline `docs/guidelines/php/git.md` for branch naming, commit messages, PR conventions.
79
- → See `commit-conventions` rule for commit format, types, and scope rules.
79
+ → See `commit-conventions` rule for commit format, types, and scope rules; a team convention is declared in the `git:` settings (`commit_format`, `branch_pattern`, `update_strategy`).
80
80
  → Use `conventional-commits-writing` skill for generating/reviewing commit messages.
81
81
 
82
82
  ## Procedure: Before opening a PR
83
83
 
84
84
  1. Quality pipeline + tests — only when `quality.local_auto_run: true` (see [`quality-tools` § Execution policy](../quality-tools/SKILL.md)): type-checker → auto-fixer → linter → type-checker, then the project's test command (detect from manifest: `php artisan test` / `vendor/bin/phpunit` (PHP), `npm test` / `pnpm test` / `vitest` / `jest` (JS-TS), `pytest` (Python), `cargo test` (Rust), `go test ./...` (Go)). Under the default (`false` / missing) skip both — remote CI on the PR is the gate; say so instead of claiming they passed.
85
- 2. Rebase onto `main`.
85
+ 2. Update the branch from its base — [`references/branch-update.md`](references/branch-update.md).
86
86
  3. Fill in PR template completely.
87
87
 
88
88
  ## Procedure: Finish a branch
@@ -100,11 +100,11 @@ Work complete. What would you like to do?
100
100
  ### Option 1: Push and create PR
101
101
 
102
102
  1. Run quality pipeline + tests (only when `quality.local_auto_run: true`; default `false` → skip, remote CI is the gate).
103
- 2. **The push-ready sequence** — fetch → integrate the base SET → regenerate →
103
+ 2. **The push-ready sequence** — fetch → integrate the base SET (per `git.update_strategy`, [`references/branch-update.md`](references/branch-update.md)) → regenerate →
104
104
  verify → re-check freshness (this repo wires it as a `push-ready` task target;
105
105
  a consumer wires its own). Not optional housekeeping: see § A push closes its
106
106
  own loop. A stale push is refused, so skipping this buys the refusal.
107
- 3. `git push -u origin <branch>`.
107
+ 3. `git push -u origin "<branch>"` (a rendered name is always quoted) — after a rebase of a pushed branch, `--force-with-lease` per `references/branch-update.md`.
108
108
  4. `gh pr create` using PR template.
109
109
  5. **Settle it** — the turn is not over at step 4:
110
110
  `npx tsx node_modules/@event4u/agent-config/src/scripts/ci_settle.ts <pr>`
@@ -136,7 +136,7 @@ legitimate — **ending the turn silently on one is not**.
136
136
  `ci_settle` non-zero → read only the failing part
137
137
  (`gh run view --job <id> --log-failed | grep -E '×|FAIL|Error'`), fix, push
138
138
  again; the author of the red is irrelevant (`fix-what-you-see`). Three failed
139
- attempts on one target → stop and surface them (`autonomous-execution` N=3).
139
+ attempts on one target trigger `autonomous-execution`'s mandatory strategy shift.
140
140
  Exit `2` is **not** a verdict — the wait timed out or the API could not be read.
141
141
  Counts, carrier limits and the honest cost:
142
142
  [`references/push-closes-its-loop.md`](references/push-closes-its-loop.md).
@@ -153,7 +153,7 @@ The project uses `.github/pull_request_template.md`:
153
153
  ## Default branch
154
154
 
155
155
  - `main` is default/production branch.
156
- - Merge strategy: merge commits (not squash).
156
+ - Merge method: read from the forge (`/pr:merge` § 9), never assumed; rebase-and-merge keeps every commit, so each subject must follow the convention.
157
157
 
158
158
  ## Procedure: Safe squash-after-push
159
159
 
@@ -165,26 +165,28 @@ Trigger context: `git-history-discipline` rule routed here.
165
165
 
166
166
  ### 1. Snapshot before touching anything
167
167
 
168
+ `REMOTE`/`RB`: the published ref, from the `resolve` block of [`references/branch-update.md`](references/branch-update.md) § The rebase sequence — never `@{u}`; unresolved → no squash.
169
+
168
170
  ```bash
169
- BRANCH=$(git branch --show-current)
170
171
  DATE=$(date +%F)
171
- git fetch origin
172
- git tag "safe-squash-pre/${BRANCH}/${DATE}" HEAD
173
- git tag "safe-squash-origin/${BRANCH}/${DATE}" "@{u}"
172
+ PUBLISHED=$(git ls-remote "$REMOTE" "refs/heads/$RB") || { echo "STOP: could not read $REMOTE/$RB — nothing was rewritten" >&2; exit 1; }; EXPECTED=$(cut -f1 <<<"$PUBLISHED")
173
+ git fetch -q "$REMOTE" "refs/heads/$RB"
174
+ SNAP="refs/agent-config/rewrites/squash-${DATE}-$$"
175
+ git update-ref "$SNAP/before" HEAD
176
+ git update-ref "$SNAP/published" "$EXPECTED"
174
177
  ```
175
178
 
176
- Two tags = two recoveries (local tip + origin tip). Do not skip the
177
- tags — `git reflog` is TTL-bounded and unreliable across sessions.
179
+ Two refs = two recoveries (local tip + published tip), private — `git push --tags` cannot publish them; `git reflog` is TTL-bounded and unreliable across sessions.
178
180
 
179
181
  ### 2. Verify aligned starting state
180
182
 
181
183
  ```bash
182
- git rev-list --left-right --count HEAD...@{u}
184
+ git rev-list --left-right --count "HEAD...$EXPECTED"
183
185
  ```
184
186
 
185
187
  - `0 0` → aligned, proceed.
186
188
  - `N 0` (local ahead) → unpushed work, proceed.
187
- - `0 N` (origin ahead) → `git pull --ff-only` first, then re-check.
189
+ - `0 N` (published ref ahead) → `git merge --ff-only "$EXPECTED"` first, then re-check.
188
190
  - `M N` (both non-zero) → **divergent**. Abandon the squash and run
189
191
  § Divergent-State Recovery below.
190
192
 
@@ -197,18 +199,16 @@ git reset --soft "$(git merge-base HEAD <base>)"
197
199
  git commit -m "<conventional commit message>"
198
200
  ```
199
201
 
200
- Interactive rebase only when the user wants per-commit control — it
201
- replays derived files (`dist/agent-src/`, router projections)
202
- per commit and conflicts on every replay.
202
+ Interactive rebase only when the user wants per-commit control — it replays
203
+ derived files (`dist/agent-src/`, router projections) and conflicts on every replay.
203
204
 
204
205
  ### 4. Re-push in the SAME turn
205
206
 
206
207
  ```bash
207
- FETCHED_SHA=$(git rev-parse "@{u}")
208
- git push --force-with-lease="${BRANCH}:${FETCHED_SHA}" origin "${BRANCH}"
209
- git fetch origin
210
- [ "$(git rev-parse HEAD)" = "$(git rev-parse @{u})" ] \
211
- && echo "OK: origin matches HEAD" \
208
+ # $EXPECTED is the SHA pinned in step 1 — re-reading it would lease a collaborator's push
209
+ git push --force-with-lease="refs/heads/$RB:$EXPECTED" "$REMOTE" "HEAD:refs/heads/$RB"
210
+ [ "$(git ls-remote "$REMOTE" "refs/heads/$RB" | cut -f1)" = "$(git rev-parse HEAD)" ] \
211
+ && echo "OK: the published ref matches HEAD" \
212
212
  || echo "MISMATCH — do not end session"
213
213
  ```
214
214
 
@@ -216,20 +216,20 @@ If the push fails (pre-push hook, network, token budget):
216
216
  - Fix the underlying cause **now**.
217
217
  - Re-push immediately.
218
218
  - Do not commit new work on top of the squashed-but-unpushed tip.
219
- - Do not end the session until `HEAD == @{u}`.
219
+ - Do not end the session until the published ref equals `HEAD`.
220
220
 
221
221
  ### 5. Hand off only with verified parity
222
222
 
223
223
  Report exactly:
224
224
  - pre-squash tip SHA (from step 1)
225
- - pre-squash tag name (for recovery)
225
+ - the recovery refs under `$SNAP` — removed with `git update-ref -d` once step 4 verified parity; kept, with `git reset --keep "$SNAP/before"` printed, if anything failed
226
226
  - post-squash tip SHA == origin SHA (verified in step 4)
227
227
  - PR number, if any, and confirm it picked up the new tip
228
228
 
229
229
  ## Procedure: Divergent-State Recovery
230
230
 
231
- Fires when `git rev-list --left-right --count HEAD...@{u}` shows
232
- **both** sides non-zero on the current branch.
231
+ Fires when `git rev-list --left-right --count "HEAD...$EXPECTED"` (the published
232
+ ref's SHA, pinned as in § Safe squash-after-push step 1) shows **both** sides non-zero.
233
233
 
234
234
  ### 1. Stop. Do not pull.
235
235
 
@@ -239,28 +239,28 @@ shape — guaranteed conflict storm in derived files, possible
239
239
  double-application of the same change. This is the documented failure
240
240
  mode behind `git-history-discipline`.
241
241
 
242
- ### 2. Tag both sides immediately
242
+ ### 2. Record both sides immediately
243
243
 
244
244
  ```bash
245
- TS=$(date +%FT%H%M)
246
- git tag "diverged-local/${TS}" HEAD
247
- git tag "diverged-origin/${TS}" "@{u}"
245
+ SNAP="refs/agent-config/rewrites/diverged-$(date +%Y%m%dT%H%M)"
246
+ git update-ref "$SNAP/before" HEAD
247
+ git update-ref "$SNAP/published" "$EXPECTED"
248
248
  ```
249
249
 
250
250
  ### 3. Diagnose: which side is the correct future?
251
251
 
252
252
  ```bash
253
- git log --oneline @{u}..HEAD # local-only commits
254
- git log --oneline HEAD..@{u} # origin-only commits
255
- git diff @{u}..HEAD --stat # shape of local-ahead work
253
+ git log --oneline "$EXPECTED..HEAD" # local-only commits
254
+ git log --oneline "HEAD..$EXPECTED" # published-only commits
255
+ git diff "$EXPECTED..HEAD" --stat # shape of local-ahead work
256
256
  ```
257
257
 
258
258
  Decision matrix:
259
259
 
260
260
  | Pattern | Future | Action |
261
261
  |---|---|---|
262
- | Local has the same logical work as origin, just reshaped (squash/rebase) | **Local** | After PR-review check (step 4), `git push --force-with-lease=<branch>:<origin-sha>` |
263
- | Origin has commits local does not reflect (another contributor pushed) | **Origin** | Tag any local-ahead work for cherry-pick, then `git reset --hard @{u}` |
262
+ | Local has the same logical work as origin, just reshaped (squash/rebase) | **Local** | After PR-review check (step 4), `git push --force-with-lease=refs/heads/<b>:<sha> <remote> HEAD:refs/heads/<b>` |
263
+ | Origin has commits local does not reflect (another contributor pushed) | **Origin** | Keep any local-ahead work at the step-2 refs for cherry-pick, then `git reset --hard "$EXPECTED"` |
264
264
  | Both sides have genuine independent work | **ask user** | Never decide silently — surface the two commit lists and let the user pick |
265
265
 
266
266
  ### 4. PR review-comment check (mandatory before any force-push)
@@ -277,16 +277,16 @@ destroys live review feedback is unrecoverable from the agent side.
277
277
 
278
278
  ### 5. Recover or proceed
279
279
 
280
- Use the tags from step 2 to restore either side if step 4 surfaces a
281
- problem. After resolution, verify `HEAD == @{u}` and report both
282
- SHAs plus the tags created.
280
+ Use the refs from step 2 to restore either side if step 4 surfaces a
281
+ problem. After resolution, verify the published ref equals `HEAD` and report both
282
+ SHAs plus the refs recorded.
283
283
 
284
284
  ## Hard prohibitions on a pushed branch
285
285
 
286
286
  - No `git pull --rebase` after detecting divergent state.
287
- - No `git push --force` without `--force-with-lease=<branch>:<sha>`.
287
+ - No `git push --force`, and no `--force-with-lease` without its fully qualified `refs/heads/<b>:<sha>`.
288
288
  - No squash-then-end-session — the push must complete in the same turn.
289
- - No reflog-only recovery — always tag the state explicitly first.
289
+ - No reflog-only recovery — always record the state under `refs/agent-config/rewrites/` first.
290
290
 
291
291
  ## Shared-branch & inherited commits — ask-before-drop protocol
292
292
 
@@ -321,11 +321,11 @@ force-push would clobber their in-flight work regardless of your local backup.
321
321
 
322
322
  ## Two protective stops (for the protocol phase)
323
323
 
324
- 1. **Pre-rewrite stop.** Before any squash / amend / rebase on a branch that is on origin: `git fetch && git rev-list --left-right --count HEAD...@{u}`. If **either** side is non-zero — STOP and run § Divergent-State Recovery. A blind `git pull --rebase` in this state is the documented failure mode. (§ Safe squash-after-push steps 1–2 implement this stop.)
324
+ 1. **Pre-rewrite stop.** Before any squash / amend / rebase of a pushed branch: resolve the ref it publishes (`@{push}`, or the pull request's head repository — [`references/branch-update.md`](references/branch-update.md) § The rebase sequence; never `@{u}`, which is the base for a branch pushed without `-u`), pin its SHA once, then `git rev-list --left-right --count "HEAD...$EXPECTED"`. An unresolved target is no rewrite. Squash / amend: if **either** side is non-zero — STOP and run § Divergent-State Recovery. Rebase: the pinned SHA must already be in `HEAD` — your own unpushed commits travel with the rebase. A blind `git pull --rebase` in this state is the documented failure mode. (§ Safe squash-after-push steps 1–2 implement this stop.)
325
325
 
326
- 2. **Post-rewrite stop.** After the rewrite, push in the **same turn** with `--force-with-lease=<branch>:<fetched-sha>` and verify `git rev-parse origin/<branch>` equals `git rev-parse HEAD`. If the push fails (hook, network, token budget) — fix the cause and re-push **before** ending the session, committing new work, or handing off. (§ Safe squash-after-push step 4 implements this stop.)
326
+ 2. **Post-rewrite stop.** After the rewrite, push in the **same turn** with `git push --force-with-lease=refs/heads/<b>:<pinned-sha> <remote> HEAD:refs/heads/<b>` and verify `git ls-remote <remote> refs/heads/<b>` equals `git rev-parse HEAD`. A rejected lease is a stop — refetch and report, never a bare `--force-with-lease`, never `--force`. If the push fails (hook, network, token budget) — fix the cause and re-push **before** ending the session, committing new work, or handing off. (§ Safe squash-after-push step 4 implements this stop.)
327
327
 
328
- If either stop fires and resolution is not immediate → tag the state (`git tag local-rewritten-tip-<ISO-date>`) and hand control back to the user. Do not let a new session inherit a dirty divergence.
328
+ If either stop fires and resolution is not immediate → record the state (`git update-ref refs/agent-config/rewrites/<tx>/before HEAD`) and hand control back to the user. Do not let a new session inherit a dirty divergence.
329
329
 
330
330
  ## Equivalents that are also forbidden by default
331
331
 
@@ -0,0 +1,312 @@
1
+ # Updating a branch from its base
2
+
3
+ Detail for [`git-workflow`](../SKILL.md) § Live remote state and § Before
4
+ opening a PR. The one place that
5
+ decides how a feature branch takes in its base — `/create-pr` § 1b, `/pr:merge`
6
+ § 2, `/prepare-for-review` and `/review:changes` defer here. Read
7
+ `git.update_strategy` from `agent-config git:convention show --key update_strategy --base origin/<base>`, which exits 1
8
+ when the value in force is `malformed`, `invalid`, `discarded` or
9
+ `unresolvable` — none of these is a strategy: stop and report the line it
10
+ prints, never fall back to `merge`. A candidate in one of these states is
11
+ printed as a warning with exit 0: the update reads only the value in force.
12
+ A team declares the strategy in `.git-convention.yml` at the repository root
13
+ (ADR-283), and it is read at the commit the branch is judged against — the
14
+ `--base` given, the pull request's base — so a value changed on this branch is
15
+ a candidate `show` prints and applies only once it lands there; `unresolvable`
16
+ means that commit could not be read. Without `--base` the target is the default
17
+ branch, right only for a branch that targets it; nothing asks the forge:
18
+
19
+ | `git.update_strategy` | Operation | Asked first? |
20
+ |---|---|---|
21
+ | `merge` (default) | `git fetch origin && git merge origin/<base> --no-edit` | no — a merge adds a commit and rewrites nothing |
22
+ | `rebase` | § The rebase sequence below: resolve the ref the branch publishes, pin its SHA once, stop unless that SHA is already in `HEAD`, `git rebase origin/<base>`, report equivalence, regenerate and verify, then push in the same turn with `git push --force-with-lease=refs/heads/<b>:<sha> <remote> HEAD:refs/heads/<b>`, the pinned SHA as the lease | **yes**, unless [`git-history-discipline`](../../../rules/git-history-discipline.md) § When rewrite is allowed already covers it — the user asked this turn, an unrevoked standing instruction ("always rebase before pushing"), or a `pull --rebase` the user started. The setting picks the operation; it is never the authorisation |
23
+
24
+ ## Under `rebase`
25
+
26
+ - **Never merge the base into the branch instead**, not even to avoid the ask —
27
+ a `Merge branch 'main' into …` commit is exactly what the setting excludes.
28
+ No authorisation → stop and ask with numbered options (rebase now / leave the
29
+ branch behind).
30
+ - **Pushed branch** → § The rebase sequence is the skill's § Two protective
31
+ stops in their rebase form: commits on the published ref you lack halt the
32
+ rebase, and the push follows in the same turn.
33
+ - **Shared branch** — commits on it that you did not author this session → do
34
+ not rebase without the authors' agreement; this is the git-history-discipline
35
+ inherited-commits law, and the setting does not lift it.
36
+ - **Known descendants** → refuse. When the open pull requests' bases — the
37
+ chain `/prepare-for-review` already reads
38
+ (`gh pr list --base <branch> --json number,headRefName`) — show another branch
39
+ built on this one, the `rebase` row does not run: rewriting the parent leaves
40
+ every descendant carrying its old commits, and a later
41
+ `git rebase origin/<parent>` on the child replays them. The sequence enforces
42
+ it: the caller supplies `DESCENDANTS` (input below) and step 2 stops on a
43
+ non-empty list, naming it. Restacking the chain is not this procedure, and an
44
+ unasked `--onto` reseat needs the question the skill's shared-branch protocol
45
+ asks. Nothing is inferred from branch names — only a pull request whose base
46
+ is this branch counts.
47
+ - **Completion review** → rebase first, review after: the completion review
48
+ binds after the last rebase, and one taken before a rebase is re-bound after
49
+ it — the re-binding reviewer cites the post-rebase commits in a commit of its
50
+ own. The step 3 equivalence report is supporting data for that reviewer, never
51
+ the re-binding itself, and nothing edits a findings file automatically
52
+ ([`plan-review-gates`](../../../docs/contracts/plan-review-gates.md) § 2.5).
53
+ - **Conflicts** → resolve to the correct end state per commit, `git add`,
54
+ `git rebase --continue`; `git rebase --abort` returns to the pre-rebase state.
55
+ Re-run the relevant tests afterwards — a conflict-free tree is not a correct
56
+ one. Detail: [`merge-conflicts`](../../merge-conflicts/SKILL.md).
57
+ - **A base SET** (a non-default target whose branch-convergence policy also
58
+ carries the default branch): rebase onto the target. When the branch is
59
+ current with the target and the target itself is behind its default,
60
+ `sync_pr_branch` exits 3 with the reason code `TARGET_POLICY_STALE` — that is
61
+ the target's update, not this branch's; report it and do not rebase. A branch
62
+ also behind the target gets the ordinary behind line first.
63
+ - **`sync_pr_branch` exits** — `0` with a `✅` line: current, or under `merge`
64
+ merged cleanly; `0` with a `⚠️` `unverified` or `BYPASSED` line: **not
65
+ checked** (the base commit or origin not fetched, or the convergence policy
66
+ disabled), never read as current; `1`: a conflict, git refusing the merge
67
+ before it starts (a dirty tree, an untracked file in the way — git's line is
68
+ printed), the base could not be resolved, or the target moved before the merge onto a commit carrying another
69
+ strategy — nothing merged, run again; `2`: a blank `--base` (usage) or an
70
+ internal error; `3`: behind under a strategy other than `merge`, refused and
71
+ never merged; `4`: the strategy itself cannot be read — the line names the
72
+ reason code and the file, and nothing was checked. A current branch passes
73
+ with exit 0, so automated pre-push syncs stay green when there is nothing to do.
74
+ - **Plain `git push --force` is never used**, and neither is a bare
75
+ `--force-with-lease` — only the qualified lease the sequence pins, and never
76
+ against the base branch itself.
77
+ - **Tidying WIP / fixup commits before the PR** (`git commit --fixup`,
78
+ `git rebase -i --autosquash origin/<base>`) stays a user-requested operation —
79
+ the skill's § Equivalents that are also forbidden by default lists it; a team
80
+ that expects curated history asks for it, and the agent offers it, never runs
81
+ it unasked.
82
+ - **Published commits on the base are never rewritten**; a wrong change there is
83
+ undone with `git revert <sha>`, a new commit.
84
+
85
+ ## The rebase sequence
86
+
87
+ The branch's upstream (`@{u}`) is **not** the ref it publishes: a branch cut
88
+ from `origin/main` and pushed without `-u` tracks the base, so a stop or a lease
89
+ read from `@{u}` checks the base and carries the base's SHA. `origin/<branch>`
90
+ is not it either — `branch.<name>.pushRemote`, `remote.pushDefault` and a fork
91
+ head publish elsewhere. The sequence therefore resolves the publish target,
92
+ and an **unresolved target means no rewrite** — never "never pushed". Only a
93
+ resolved target with no remote ref is a branch that was never pushed. The
94
+ remedy the stop names: set the upstream once with `git push -u <remote> <branch>`,
95
+ then run the sequence again.
96
+
97
+ **Inputs, set before step 1.** `BASE` is required: the pull request's base
98
+ branch, bare (`main`, `release/1.x`). `DESCENDANTS` is required by step 2: the
99
+ head branches of the open pull requests whose base is this branch, space
100
+ separated — `gh pr list --base <branch> --json headRefName --jq '.[].headRefName'`
101
+ — and set empty only when that list is empty; the sequence cannot ask the forge
102
+ itself, so an unset value is a stop. `DESCENDANTS_STATUS` is required with it:
103
+ the exit status of that `gh pr list`
104
+ (`DESCENDANTS=$(gh pr list …); DESCENDANTS_STATUS=$?`), because a failed call
105
+ also prints nothing, and anything but `0` is a stop. `PR_HEAD_REPO` and `PR_HEAD_REF` are set
106
+ only with an open pull request (step 1). **Steps 1–3 are one script** — run
107
+ them in order, in ONE shell session, never as separate tool calls: they share
108
+ `REMOTE`, `RB`, `EXPECTED`, `SAVE` and the `stop` / `keep` functions the first
109
+ block defines. Each later block opens by checking that it shares that session
110
+ and stops otherwise, because an undefined `stop` would be a command that is not
111
+ found and lets the block run on. **Step 4 is a separate run**: step 3 stops
112
+ and prints the `SAVE` and `EXPECTED` it hands on; the caller regenerates the
113
+ derived files and runs its own verification on the rebased tree, then, in one
114
+ shell, runs step 1 again with those two set and runs step 4. Nothing is
115
+ published before that verification.
116
+
117
+ **1. Resolve.** `@{push}` names the publish target where the push
118
+ configuration determines one; with an open pull request, its head repository and
119
+ `headRefName` (`gh pr view --json headRefName,headRepository,headRepositoryOwner`)
120
+ name it — set `PR_HEAD_REPO=<owner>/<name>` and `PR_HEAD_REF=<headRefName>`
121
+ first. The two must agree when both resolve. A target that names the base
122
+ branch — `BASE`, or the default branch the publish remote reports — is a stop:
123
+ under `push.default=upstream` or `tracking`, `@{push}` of a branch cut with
124
+ `--track origin/main` IS `origin/main`, and nothing later in the sequence would
125
+ notice — the base is an ancestor of `HEAD`, so the pin passes
126
+ and the lease is the base's own SHA.
127
+
128
+ ```bash
129
+ # rebase-sequence: resolve
130
+ stop() { echo "STOP: $*" >&2; exit 1; }
131
+ keep() { stop "$* — the old head is kept at $SAVE; restore it with: git reset --keep $SAVE"; }
132
+ : "${BASE:?STOP: BASE is required — the pull request base branch, bare; nothing was rewritten}"
133
+ REMOTE= RB=
134
+ B=$(git branch --show-current)
135
+ if PUSH=$(git rev-parse --symbolic-full-name '@{push}' 2>/dev/null); then
136
+ REMOTE=$(git for-each-ref --format='%(push:remotename)' "refs/heads/$B")
137
+ RB=${PUSH#"refs/remotes/$REMOTE/"}
138
+ fi
139
+ if [ -n "${PR_HEAD_REPO:-}" ]; then
140
+ PR_REMOTE=$(git remote -v | awk -v r="$PR_HEAD_REPO" '$3 == "(push)" && $2 ~ ("[/:]" r "(\\.git)?$") { print $1; exit }')
141
+ [ -n "$PR_REMOTE" ] || { echo "STOP: no remote publishes $PR_HEAD_REPO" >&2; exit 1; }
142
+ if [ -n "$REMOTE" ] && { [ "$REMOTE" != "$PR_REMOTE" ] || [ "$RB" != "$PR_HEAD_REF" ]; }; then
143
+ echo "STOP: @{push} is $REMOTE/$RB but the pull request head is $PR_HEAD_REPO:$PR_HEAD_REF" >&2; exit 1
144
+ fi
145
+ REMOTE=$PR_REMOTE RB=$PR_HEAD_REF
146
+ fi
147
+ [ -n "$REMOTE" ] && [ -n "$RB" ] \
148
+ || { echo "STOP: publish target unresolved — no rewrite; set the upstream once with git push -u <remote> $B, then run the sequence again" >&2; exit 1; }
149
+ DEF=$(git ls-remote --symref "$REMOTE" HEAD | awk '$1 == "ref:" { sub("^refs/heads/", "", $2); print $2; exit }')
150
+ for b in "${BASE:-}" "$DEF"; do
151
+ [ -z "$b" ] || [ "$RB" != "$b" ] \
152
+ || { echo "STOP: the publish target $REMOTE/$RB is the base branch — a rewrite is never published onto its base" >&2; exit 1; }
153
+ done
154
+ ```
155
+
156
+ **2. Stop, pin, rebase.** The stops come first, before anything is
157
+ rewritten: known descendants (`DESCENDANTS` non-empty, § Under `rebase`); a
158
+ dirty working tree; a merge commit in the topic range
159
+ (`git rev-list --merges origin/<base>..HEAD` is non-empty) — the default
160
+ `merge` strategy and `/prepare-for-review` put them there, so a branch switched
161
+ to `rebase` usually carries one, and a plain rebase silently drops it. When
162
+ every such commit is a **base merge** — each parent after the first is
163
+ reachable from `origin/<base>` — the stop names its remedy: a plain rebase that
164
+ drops those merges, run only after the user confirms it this turn, which a run
165
+ started with `DROP_BASE_MERGES=1` stands for; the recovery ref is written
166
+ first, and conflicts resolved inside those merges may come back during the
167
+ rebase. A base merge whose tree differs from the automatic merge of its two
168
+ parents (`git merge-tree --write-tree`) carries changes of its own — a conflict
169
+ resolution, or an edit made inside the merge — and is never dropped: the run
170
+ stops naming it, and whenever merges were dropped step 3 reports "needs
171
+ review". A merge of anything else is still refused even with
172
+ `DROP_BASE_MERGES=1`; `--rebase-merges` is a separate operation the user asks
173
+ for, never a fallback;
174
+ and commits on the branch you did not author (§ Under `rebase`, shared branch)
175
+ — any commit in `origin/<base>..HEAD` whose author email is not
176
+ `git config user.email`. That stop lifts only for a run started with
177
+ `ALLOW_FOREIGN=1`, which stands for the user's answer this turn that those
178
+ commits may be rewritten; it is never set to get past the stop.
179
+ Then the remote ref is read once; that literal is the stop (it must already be
180
+ in `HEAD`) and, unchanged, the lease. A read that fails is a stop of its own,
181
+ never an empty answer: an empty literal means "never pushed", which skips the
182
+ stop. A collaborator's push lands either before
183
+ the pin and halts the stop, or after it and fails the lease — it is never
184
+ overwritten.
185
+
186
+ Before the rewrite the old head is kept at a private recovery ref,
187
+ `refs/agent-config/rewrites/<tx>/before`, written with `git update-ref` —
188
+ outside `refs/tags/`, so `git push --tags` cannot publish it, and not a tag
189
+ push for anything that counts them. It is removed once the published ref reads
190
+ back as `HEAD`; on any failure it is kept and the one command that restores it
191
+ is printed. A kept ref is removed with `git update-ref -d <ref>`.
192
+
193
+ ```bash
194
+ # rebase-sequence: rebase
195
+ declare -F keep >/dev/null && [ -n "${BASE:-}" ] && [ -n "${REMOTE:-}" ] \
196
+ || { echo "STOP: run steps 1–3 in one shell session, starting with step 1 — nothing was rewritten" >&2; exit 1; }
197
+ [ "${DESCENDANTS+set}" = set ] \
198
+ || stop "DESCENDANTS is required — the head branches of open pull requests whose base is this branch, empty when there are none; nothing was rewritten"
199
+ [ "${DESCENDANTS_STATUS+set}" = set ] \
200
+ || stop "DESCENDANTS_STATUS is required — the exit status of the gh pr list that produced DESCENDANTS; nothing was rewritten"
201
+ [ "$DESCENDANTS_STATUS" = 0 ] \
202
+ || stop "could not list the pull requests built on this branch (gh exited $DESCENDANTS_STATUS) — an unanswered question is not an empty list; nothing was rewritten"
203
+ [ -z "$DESCENDANTS" ] \
204
+ || stop "pull requests are built on this branch ($DESCENDANTS) — rewriting it leaves them carrying its old commits; restacking is not this procedure, nothing was rewritten"
205
+ [ -z "$(git status --porcelain --untracked-files=no)" ] || stop "the working tree is dirty — nothing was rewritten"
206
+ git fetch -q origin "$BASE" || stop "could not fetch origin $BASE — nothing was rewritten"
207
+ MERGES=$(git rev-list --merges "origin/$BASE..HEAD") \
208
+ || stop "could not list the topic range origin/$BASE..HEAD — nothing was rewritten"
209
+ if [ -n "$MERGES" ]; then
210
+ OTHER=
211
+ for m in $MERGES; do
212
+ for p in $(git rev-parse "$m^@" | tail -n +2); do
213
+ git merge-base --is-ancestor "$p" "origin/$BASE" || { OTHER="$OTHER $(git rev-parse --short "$m")"; break; }
214
+ done
215
+ done
216
+ [ -z "$OTHER" ] \
217
+ || stop "the topic range carries a merge commit that is not a merge of the base ($OTHER) — a plain rebase drops it; --rebase-merges is a separate operation the user asks for"
218
+ [ "${DROP_BASE_MERGES:-}" = 1 ] \
219
+ || stop "the topic range carries a merge commit from an earlier merge of the base, which a plain rebase drops — ask the user; set DROP_BASE_MERGES=1 only on their answer this turn (conflicts resolved inside those merges may come back); keeping them is --rebase-merges, a separate operation the user asks for"
220
+ for m in $MERGES; do
221
+ AUTO=$(git merge-tree --write-tree "$m^1" "$m^2" 2>/dev/null | head -n 1) && [ -z "$(git rev-parse -q --verify "$m^3")" ] \
222
+ && [ "$AUTO" = "$(git rev-parse "$m^{tree}")" ] \
223
+ || stop "the merge $(git rev-parse --short "$m") carries changes of its own (a conflict resolution or an edit) — dropping it loses them; nothing was rewritten"
224
+ done
225
+ fi
226
+ ME=$(git config user.email) || stop "git config user.email is unset, so your commits cannot be told from inherited ones — nothing was rewritten"
227
+ AUTHORS=$(git log --format='%h %ae' "origin/$BASE..HEAD") \
228
+ || stop "could not list the authors of origin/$BASE..HEAD — nothing was rewritten"
229
+ FOREIGN=$(awk -v me="$ME" 'tolower($2) != tolower(me)' <<<"$AUTHORS")
230
+ [ -z "$FOREIGN" ] || [ "${ALLOW_FOREIGN:-}" = 1 ] \
231
+ || stop "the topic range carries commits you did not author ($(tr '\n' ' ' <<<"$FOREIGN")) — ask the user; set ALLOW_FOREIGN=1 only on their answer this turn"
232
+ PUBLISHED=$(git ls-remote "$REMOTE" "refs/heads/$RB") || stop "could not read $REMOTE/$RB — nothing was rewritten"
233
+ EXPECTED=$(cut -f1 <<<"$PUBLISHED")
234
+ if [ -n "$EXPECTED" ]; then
235
+ git fetch -q "$REMOTE" "refs/heads/$RB" || stop "could not fetch $REMOTE/$RB — nothing was rewritten"
236
+ git merge-base --is-ancestor "$EXPECTED" HEAD || stop "$REMOTE/$RB has commits this branch lacks"
237
+ fi
238
+ SAVE="refs/agent-config/rewrites/$(date -u +%Y%m%dT%H%M%SZ)-$$/before"
239
+ git update-ref "$SAVE" HEAD
240
+ git rebase "origin/$BASE" \
241
+ || keep "the rebase stopped on a conflict — resolve each commit and git rebase --continue, then in one shell run step 1, set SAVE=$SAVE EXPECTED=$EXPECTED, and run step 3 (git rebase --abort first to give up)"
242
+ ```
243
+
244
+ **3. Report equivalence from stable data.** The stable patch ids of the old
245
+ range and the new range are compared: equal sets mean "mechanically
246
+ equivalent"; anything else means "needs review" and names the commits on each
247
+ side that have no match — never a pair inferred from a subject or a position.
248
+ Whenever the old head already contained the new base, the trees must also be
249
+ equal. A conflict resolution changes a patch id, so a mismatch means "needs
250
+ review", never "wrong". A non-empty range that yields no patch id at all — an
251
+ empty commit, or diff output git could not read — is "needs review" too: an
252
+ empty comparison is not an equal one. Colour is forced off, so a
253
+ `color.ui=always` configuration cannot empty both sets. The verdict is a report, not a review: it binds nothing
254
+ and approves nothing. `git range-diff` is shown to the human and never parsed —
255
+ its manual says under OUTPUT STABILITY that the output is not for machines.
256
+
257
+ ```bash
258
+ # rebase-sequence: equivalence
259
+ declare -F keep >/dev/null && [ -n "${SAVE:-}" ] && [ -n "${BASE:-}" ] \
260
+ || { echo "STOP: run steps 1–3 in one shell session, starting with step 1" >&2; exit 1; }
261
+ pids() { git -c color.ui=never log -p --no-color --no-merges --format='commit %H' "$1" | git patch-id --stable | sort; }
262
+ OLD_BASE=$(git merge-base "$SAVE" "origin/$BASE")
263
+ OLD=$(pids "$OLD_BASE..$SAVE")
264
+ NEW=$(pids "origin/$BASE..HEAD")
265
+ VERDICT="mechanically equivalent"
266
+ [ "$(cut -d' ' -f1 <<<"$OLD")" = "$(cut -d' ' -f1 <<<"$NEW")" ] || VERDICT="needs review"
267
+ [ -n "$OLD" ] || [ "$(git rev-list --count --no-merges "$OLD_BASE..$SAVE")" = 0 ] || VERDICT="needs review"
268
+ [ -n "$NEW" ] || [ "$(git rev-list --count --no-merges "origin/$BASE..HEAD")" = 0 ] || VERDICT="needs review"
269
+ DROPPED=$(git rev-list --merges "$OLD_BASE..$SAVE")
270
+ [ -z "$DROPPED" ] || VERDICT="needs review"
271
+ if git merge-base --is-ancestor "origin/$BASE" "$SAVE" \
272
+ && [ "$(git rev-parse "$SAVE^{tree}")" != "$(git rev-parse "HEAD^{tree}")" ]; then
273
+ VERDICT="needs review"
274
+ fi
275
+ echo "EQUIVALENCE: $VERDICT"
276
+ [ -z "$DROPPED" ] || echo " dropped merge(s): $(git rev-parse --short $DROPPED | tr '\n' ' ')"
277
+ if [ "$VERDICT" = "needs review" ]; then
278
+ comm -3 <(cut -d' ' -f1 <<<"$OLD") <(cut -d' ' -f1 <<<"$NEW") | tr -d '\t' | sort -u | while read -r p; do
279
+ [ -n "$p" ] || continue
280
+ grep "^$p " <<<"$OLD" | while read -r _ c; do echo " before: $(git log -1 --format='%h %s' "$c")"; done
281
+ grep "^$p " <<<"$NEW" | while read -r _ c; do echo " after: $(git log -1 --format='%h %s' "$c")"; done
282
+ done
283
+ fi
284
+ git range-diff "$OLD_BASE..$SAVE" "origin/$BASE..HEAD" # for the human; never parsed
285
+ echo "PUBLISH AFTER VERIFY: SAVE=$SAVE EXPECTED=$EXPECTED — regenerate and verify, then in one shell run step 1 with these two set, then step 4"
286
+ ```
287
+
288
+ **4. Push in the same turn, then read the published ref back** — after the
289
+ caller's regenerate and verify, in a fresh shell that ran step 1 with `SAVE`
290
+ and `EXPECTED` from step 3. It refuses while a rebase is still in progress and when `HEAD` does
291
+ not contain `origin/<base>`: a half-finished rebase is never published. An empty `EXPECTED` (never pushed) makes the lease
292
+ require that the ref does not exist.
293
+
294
+ ```bash
295
+ # rebase-sequence: publish
296
+ declare -F keep >/dev/null && [ -n "${SAVE:-}" ] && [ "${EXPECTED+set}" = set ] && [ -n "${REMOTE:-}" ] && [ -n "${RB:-}" ] \
297
+ || { echo "STOP: run step 1 in this shell session, with SAVE and EXPECTED from step 3 — nothing was pushed" >&2; exit 1; }
298
+ for d in rebase-merge rebase-apply; do
299
+ [ ! -e "$(git rev-parse --git-path "$d")" ] || keep "a rebase is in progress — finish it (git rebase --continue) or abort it, then verify again; nothing was pushed"
300
+ done
301
+ git merge-base --is-ancestor "origin/$BASE" HEAD \
302
+ || keep "HEAD does not contain origin/$BASE, the base it was rebased onto — nothing was pushed"
303
+ git push --force-with-lease="refs/heads/$RB:$EXPECTED" "$REMOTE" "HEAD:refs/heads/$RB" \
304
+ || keep "the lease was rejected — $REMOTE/$RB moved; refetch and report, never retry without the lease"
305
+ [ "$(git ls-remote "$REMOTE" "refs/heads/$RB" | cut -f1)" = "$(git rev-parse HEAD)" ] \
306
+ || keep "$REMOTE/$RB does not match HEAD after the push"
307
+ [ -n "$SAVE" ] && git update-ref -d "$SAVE"
308
+ ```
309
+
310
+ A rejected lease is a stop: refetch, report what moved, and hand back — never a
311
+ bare `--force-with-lease`, which compares against whatever the last fetch
312
+ brought in and so overwrites a push it has just fetched, and never `--force`.