@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.
- package/.augment-plugin/marketplace.json +3 -3
- package/.augment-plugin/plugin.json +1 -1
- package/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +178 -78
- package/README.md +2 -2
- package/agents/templates/.ai-council.yml.example +26 -8
- package/dist/agent-src/commands/analyze/inbox.md +10 -7
- package/dist/agent-src/commands/bug/investigate.md +1 -1
- package/dist/agent-src/commands/commit/in-chunks.md +40 -31
- package/dist/agent-src/commands/commit.md +72 -33
- package/dist/agent-src/commands/condense.md +2 -8
- package/dist/agent-src/commands/council/debate.md +11 -7
- package/dist/agent-src/commands/council/default.md +10 -9
- package/dist/agent-src/commands/council.md +1 -1
- package/dist/agent-src/commands/design.md +1 -1
- package/dist/agent-src/commands/estimate-ticket.md +1 -1
- package/dist/agent-src/commands/feature/explore.md +3 -3
- package/dist/agent-src/commands/feature/plan.md +1 -1
- package/dist/agent-src/commands/fix/ci.md +17 -3
- package/dist/agent-src/commands/fix/commit-messages.md +48 -23
- package/dist/agent-src/commands/fix/pr-comments.md +3 -6
- package/dist/agent-src/commands/implement-ticket.md +3 -3
- package/dist/agent-src/commands/memory/add.md +4 -16
- package/dist/agent-src/commands/memory/load.md +5 -6
- package/dist/agent-src/commands/memory/promote.md +3 -16
- package/dist/agent-src/commands/mission/upgrade.md +3 -2
- package/dist/agent-src/commands/optimize/agents-dir.md +2 -2
- package/dist/agent-src/commands/optimize/deep.md +4 -2
- package/dist/agent-src/commands/optimize/rtk.md +4 -26
- package/dist/agent-src/commands/pr/create/description-only.md +18 -15
- package/dist/agent-src/commands/pr/create.md +42 -34
- package/dist/agent-src/commands/pr/merge.md +136 -9
- package/dist/agent-src/commands/prepare-for-review.md +13 -11
- package/dist/agent-src/commands/project/analyze.md +7 -35
- package/dist/agent-src/commands/refine-ticket.md +1 -1
- package/dist/agent-src/commands/review/changes.md +14 -19
- package/dist/agent-src/commands/roadmap/next.md +10 -1
- package/dist/agent-src/commands/roadmap/process-full.md +52 -38
- package/dist/agent-src/commands/roadmap/resolve-blockers.md +64 -14
- package/dist/agent-src/commands/worktree/create.md +7 -3
- package/dist/agent-src/commands/worktree/verify.md +2 -1
- package/dist/agent-src/contexts/communication/rules-auto/think-before-action-mechanics.md +5 -3
- package/dist/agent-src/contexts/communication/rules-auto/token-efficiency-mechanics.md +7 -9
- package/dist/agent-src/contexts/contracts/command-suggestion-flow.md +8 -6
- package/dist/agent-src/contexts/contracts/frugality-charter.md +8 -5
- package/dist/agent-src/contexts/execution/auto-dispatch-classification.md +1 -1
- package/dist/agent-src/contexts/execution/auto-orchestration-activation.md +0 -1
- package/dist/agent-src/contexts/execution/evidence-discipline.md +2 -2
- package/dist/agent-src/contexts/execution/non-interactive-contract.md +5 -8
- package/dist/agent-src/contexts/execution/rdp-gate.md +4 -4
- package/dist/agent-src/contexts/execution/roadmap-execution-contract.md +9 -8
- package/dist/agent-src/contexts/execution/roadmap-process-loop.md +67 -52
- package/dist/agent-src/contexts/execution/subagent-routing.md +8 -8
- package/dist/agent-src/contexts/execution/subagent-steering.md +6 -4
- package/dist/agent-src/contexts/execution/terminal-states.md +2 -2
- package/dist/agent-src/contexts/execution/toolchain-resolver.md +4 -10
- package/dist/agent-src/contexts/subagent-configuration.md +1 -1
- package/dist/agent-src/guidelines/agent-infra/active-remediation-mechanics.md +39 -0
- package/dist/agent-src/guidelines/agent-infra/context-hygiene-mechanics.md +1 -1
- package/dist/agent-src/guidelines/agent-infra/cross-source-consistency-mechanics.md +8 -10
- package/dist/agent-src/guidelines/agent-infra/frontier-reasoning-operating-profile.md +3 -2
- package/dist/agent-src/guidelines/agent-infra/layered-settings.md +13 -1
- package/dist/agent-src/guidelines/agent-infra/roadmap-progress-mechanics.md +1 -1
- package/dist/agent-src/guidelines/agent-infra/self-improvement-pipeline.md +10 -3
- package/dist/agent-src/guidelines/agent-infra/size-and-scope.md +36 -0
- package/dist/agent-src/guidelines/design-antipatterns.md +1 -1
- package/dist/agent-src/guidelines/php/git.md +15 -2
- package/dist/agent-src/rules/active-remediation.md +0 -1
- package/dist/agent-src/rules/analysis-skill-routing.md +0 -1
- package/dist/agent-src/rules/architecture.md +0 -1
- package/dist/agent-src/rules/artifact-drafting-protocol.md +0 -1
- package/dist/agent-src/rules/artifact-engagement-recording.md +0 -1
- package/dist/agent-src/rules/augment-edit-discipline.md +0 -1
- package/dist/agent-src/rules/autonomous-execution.md +0 -1
- package/dist/agent-src/rules/brand-consistency.md +0 -1
- package/dist/agent-src/rules/brand-source-of-truth.md +0 -1
- package/dist/agent-src/rules/broken-access-control.md +0 -1
- package/dist/agent-src/rules/cli-output-handling.md +0 -1
- package/dist/agent-src/rules/code-comment-discipline.md +0 -1
- package/dist/agent-src/rules/code-provenance.md +0 -1
- package/dist/agent-src/rules/command-suggestion-policy.md +0 -1
- package/dist/agent-src/rules/commit-conventions.md +1 -2
- package/dist/agent-src/rules/communication-through-line.md +1 -2
- package/dist/agent-src/rules/content-quoting-floor.md +1 -2
- package/dist/agent-src/rules/context-hygiene.md +5 -5
- package/dist/agent-src/rules/copilot-routing.md +1 -2
- package/dist/agent-src/rules/council-availability.md +4 -4
- package/dist/agent-src/rules/cross-source-consistency.md +4 -6
- package/dist/agent-src/rules/decision-revisit-gate.md +2 -3
- package/dist/agent-src/rules/delegation-policy.md +2 -3
- package/dist/agent-src/rules/design-fidelity.md +0 -1
- package/dist/agent-src/rules/design-review-after-ui-write.md +3 -3
- package/dist/agent-src/rules/devcontainer-routing.md +1 -2
- package/dist/agent-src/rules/doc-screenshot-hygiene.md +0 -1
- package/dist/agent-src/rules/docker-commands.md +0 -1
- package/dist/agent-src/rules/domain-adoption-policy.md +0 -1
- package/dist/agent-src/rules/domain-safety-disclaimer.md +0 -1
- package/dist/agent-src/rules/domain-safety-pii.md +0 -1
- package/dist/agent-src/rules/domain-safety-retention.md +0 -1
- package/dist/agent-src/rules/downstream-changes.md +0 -1
- package/dist/agent-src/rules/engineering-safety-floor.md +0 -1
- package/dist/agent-src/rules/external-code-graph-interop.md +0 -1
- package/dist/agent-src/rules/external-reference-deep-dive.md +0 -1
- package/dist/agent-src/rules/fast-path-marker-visibility.md +1 -2
- package/dist/agent-src/rules/finance-safety-floor.md +0 -1
- package/dist/agent-src/rules/fix-what-you-see.md +6 -32
- package/dist/agent-src/rules/framework-neutrality-in-generic-skills.md +0 -1
- package/dist/agent-src/rules/git-history-discipline.md +1 -2
- package/dist/agent-src/rules/guidelines.md +0 -1
- package/dist/agent-src/rules/history-discipline.md +0 -1
- package/dist/agent-src/rules/icon-consistency.md +0 -1
- package/dist/agent-src/rules/image-likeness-and-rights.md +0 -1
- package/dist/agent-src/rules/improve-before-implement.md +0 -1
- package/dist/agent-src/rules/invite-challenge.md +0 -1
- package/dist/agent-src/rules/laravel-routing.md +1 -2
- package/dist/agent-src/rules/laravel-translations.md +0 -1
- package/dist/agent-src/rules/legal-safety-floor.md +0 -1
- package/dist/agent-src/rules/lethal-trifecta-guard.md +0 -1
- package/dist/agent-src/rules/linked-projects-onboarding-gate.md +0 -1
- package/dist/agent-src/rules/low-impact-corpus-privacy-floor.md +0 -1
- package/dist/agent-src/rules/markdown-safe-codeblocks.md +0 -1
- package/dist/agent-src/rules/media-governance-routing.md +1 -2
- package/dist/agent-src/rules/media-sync-ground-truth.md +0 -1
- package/dist/agent-src/rules/minimal-safe-diff.md +0 -1
- package/dist/agent-src/rules/missing-skill-recovery.md +0 -1
- package/dist/agent-src/rules/missing-tool-handling.md +0 -1
- package/dist/agent-src/rules/model-recommendation.md +0 -1
- package/dist/agent-src/rules/neighbour-precedence.md +64 -0
- package/dist/agent-src/rules/no-attribution-footers.md +0 -1
- package/dist/agent-src/rules/no-decorative-emojis-in-git-surfaces.md +0 -1
- package/dist/agent-src/rules/no-pr-progress-comments.md +0 -1
- package/dist/agent-src/rules/no-roadmap-references.md +0 -1
- package/dist/agent-src/rules/notes-first-reasoning.md +0 -1
- package/dist/agent-src/rules/onboarding-gate.md +0 -1
- package/dist/agent-src/rules/output-discipline.md +0 -1
- package/dist/agent-src/rules/package-ci-checks.md +0 -1
- package/dist/agent-src/rules/persona-governance.md +2 -3
- package/dist/agent-src/rules/php-coding.md +0 -1
- package/dist/agent-src/rules/prefer-enums-over-literals.md +0 -1
- package/dist/agent-src/rules/preservation-guard.md +0 -1
- package/dist/agent-src/rules/provider-lifecycle-discipline.md +2 -3
- package/dist/agent-src/rules/question-not-instruction.md +0 -1
- package/dist/agent-src/rules/reviewer-awareness.md +0 -1
- package/dist/agent-src/rules/roadmap-ci-steps-policy.md +0 -1
- package/dist/agent-src/rules/roadmap-progress-sync.md +3 -6
- package/dist/agent-src/rules/role-mode-adherence.md +0 -1
- package/dist/agent-src/rules/rule-type-governance.md +0 -1
- package/dist/agent-src/rules/runtime-safety.md +0 -1
- package/dist/agent-src/rules/scale-discipline.md +0 -1
- package/dist/agent-src/rules/secret-vcs-guard.md +0 -1
- package/dist/agent-src/rules/security-sensitive-stop.md +0 -1
- package/dist/agent-src/rules/self-repair-loop.md +0 -1
- package/dist/agent-src/rules/senior-engineering-discipline.md +0 -1
- package/dist/agent-src/rules/session-canary.md +0 -1
- package/dist/agent-src/rules/settings-ask-protocol.md +5 -6
- package/dist/agent-src/rules/size-enforcement.md +0 -1
- package/dist/agent-src/rules/skill-improvement-trigger.md +2 -3
- package/dist/agent-src/rules/skill-quality.md +0 -1
- package/dist/agent-src/rules/slash-command-routing-policy.md +0 -1
- package/dist/agent-src/rules/source-confidentiality.md +0 -1
- package/dist/agent-src/rules/source-discovery-gate.md +0 -1
- package/dist/agent-src/rules/source-of-truth.md +0 -1
- package/dist/agent-src/rules/spreadsheet-source-quality.md +1 -2
- package/dist/agent-src/rules/strategy-safety-floor.md +0 -1
- package/dist/agent-src/rules/symfony-routing.md +1 -2
- package/dist/agent-src/rules/think-before-action.md +0 -1
- package/dist/agent-src/rules/token-budget-discipline.md +14 -48
- package/dist/agent-src/rules/token-efficiency.md +0 -1
- package/dist/agent-src/rules/token-optimizer-maintenance.md +0 -1
- package/dist/agent-src/rules/tool-safety.md +0 -1
- package/dist/agent-src/rules/ui-audit-gate.md +1 -2
- package/dist/agent-src/rules/untrusted-input-defense.md +0 -1
- package/dist/agent-src/rules/upstream-proposal.md +0 -1
- package/dist/agent-src/rules/user-interaction.md +0 -1
- package/dist/agent-src/rules/user-interrupt-priority.md +0 -1
- package/dist/agent-src/scripts/gate_budget.ts +47 -23
- package/dist/agent-src/scripts/gate_execute.ts +12 -4
- package/dist/agent-src/skills/accessibility-auditor/data/aria-patterns.csv +2 -0
- package/dist/agent-src/skills/accessibility-auditor/data/manifest.json +3 -3
- package/dist/agent-src/skills/ai-council/SKILL.md +7 -4
- package/dist/agent-src/skills/ai-council/references/cost-and-redaction.md +21 -11
- package/dist/agent-src/skills/ai-council/references/procedure.md +12 -6
- package/dist/agent-src/skills/analysis-autonomous-mode/SKILL.md +1 -1
- package/dist/agent-src/skills/bug-analyzer/SKILL.md +1 -1
- package/dist/agent-src/skills/canvas-design/SKILL.md +4 -2
- package/dist/agent-src/skills/command-routing/SKILL.md +3 -4
- package/dist/agent-src/skills/conventional-commits-writing/SKILL.md +127 -139
- package/dist/agent-src/skills/corpus-grounding/ATTRIBUTION.md +39 -0
- package/dist/agent-src/skills/corpus-grounding/SKILL.md +8 -2
- package/dist/agent-src/skills/database/data/manifest.json +2 -2
- package/dist/agent-src/skills/database/data/query-tuning.csv +13 -13
- package/dist/agent-src/skills/design-intelligence/references/integration-mapping.md +13 -10
- package/dist/agent-src/skills/design-system-capture/SKILL.md +0 -3
- package/dist/agent-src/skills/estimate-ticket/SKILL.md +1 -1
- package/dist/agent-src/skills/fe-design/references/design-patterns.md +49 -2
- package/dist/agent-src/skills/feature-planning/SKILL.md +1 -1
- package/dist/agent-src/skills/frontend-render-security/SKILL.md +9 -0
- package/dist/agent-src/skills/git-workflow/SKILL.md +44 -44
- package/dist/agent-src/skills/git-workflow/references/branch-update.md +312 -0
- package/dist/agent-src/skills/git-workflow/references/commit-subject.md +205 -0
- package/dist/agent-src/skills/iconography/SKILL.md +4 -2
- package/dist/agent-src/skills/image-provider-routing/SKILL.md +16 -5
- package/dist/agent-src/skills/jira-integration/SKILL.md +3 -3
- package/dist/agent-src/skills/logo-generation/SKILL.md +12 -8
- package/dist/agent-src/skills/merge-conflicts/SKILL.md +10 -4
- package/dist/agent-src/skills/po-discovery/SKILL.md +1 -1
- package/dist/agent-src/skills/refine-ticket/SKILL.md +4 -4
- package/dist/agent-src/skills/roadmap-writing/SKILL.md +2 -2
- package/dist/agent-src/skills/skill-improvement-pipeline/SKILL.md +4 -2
- package/dist/agent-src/skills/source-discovery/SKILL.md +1 -1
- package/dist/agent-src/skills/svg-authoring/SKILL.md +318 -0
- package/dist/agent-src/skills/tailwind-engineer/SKILL.md +3 -1
- package/dist/agent-src/skills/testing-anti-patterns/SKILL.md +1 -1
- package/dist/agent-src/skills/using-git-worktrees/SKILL.md +1 -1
- package/dist/agent-src/skills/verify-repair-loop/SKILL.md +2 -2
- package/dist/agent-src/skills/wireframe/SKILL.md +5 -2
- package/dist/agent-src/templates/AGENTS.md +1 -1
- package/dist/agent-src/templates/agent-settings.md +46 -129
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +3 -3
- package/dist/agent-src/templates/command.md +2 -2
- package/dist/agent-src/templates/roadmaps.md +6 -1
- package/dist/agent-src/templates/scripts/work_engine/_lib/agent_settings.ts +0 -6
- package/dist/agent-src/templates/scripts/work_engine/directives/backend/_self_fix.ts +11 -7
- package/dist/agent-src/templates/scripts/work_engine/hooks/builtin/decision_trace.ts +3 -2
- package/dist/agent-src/templates/scripts/work_engine/hooks/builtin/memory_visibility.ts +2 -1
- package/dist/agent-src/templates/scripts/work_engine/hooks/settings.ts +0 -6
- package/dist/agent-src/templates/scripts/work_engine/scoring/decision_engine.ts +9 -12
- package/dist/agent-src/templates/scripts/work_engine/scoring/memory_visibility.ts +2 -1
- package/dist/agent-src/templates/skill.md +1 -1
- package/dist/cli/commands/uiRender.js +201 -4
- package/dist/cli/commands/uiRenderAsset.js +1308 -0
- package/dist/cli/commands/uiRenderAssetCompare.js +752 -0
- package/dist/cli/commands/uiRenderAssetGrid.js +265 -0
- package/dist/cli/commands/uiRenderAssetGrounds.js +323 -0
- package/dist/cli/commands/uiRenderAssetIsolation.js +85 -0
- package/dist/cli/commands/uiRenderAssetTypes.js +145 -0
- package/dist/cli/main.js +47 -1
- package/dist/cli/registry.js +2 -1
- package/dist/cli-delegate/check_update_banner.js +195 -119
- package/dist/cli-delegate/{chunk-S4UMZNES.js → chunk-4DBG5K7M.js} +5 -5
- package/dist/cli-delegate/{chunk-TRI6DQZ6.js → chunk-5GPULQBE.js} +60 -42
- package/dist/cli-delegate/{chunk-JQVYKIZA.js → chunk-6SRJTYJS.js} +33 -177
- package/dist/cli-delegate/chunk-6V5FMA3P.js +186 -0
- package/dist/cli-delegate/chunk-6YQC2HLF.js +415 -0
- package/dist/cli-delegate/{chunk-E4XIZDIB.js → chunk-7HKRE54K.js} +1 -64
- package/dist/cli-delegate/{chunk-7HQ52DHU.js → chunk-AL3RZ22D.js} +1 -1
- package/dist/cli-delegate/{chunk-DBH4AHDK.js → chunk-ED7KCMLB.js} +9 -11
- package/dist/cli-delegate/{chunk-NXEILF2K.js → chunk-F3QDG2GT.js} +481 -72
- package/dist/cli-delegate/{chunk-CQWX336L.js → chunk-G5VVIZRC.js} +3 -3
- package/dist/cli-delegate/{chunk-JY2I2DXV.js → chunk-H76PHZBI.js} +137 -60
- package/dist/cli-delegate/chunk-IAYTIIQW.js +67 -0
- package/dist/cli-delegate/{chunk-LIYTLH6O.js → chunk-KXXWJTDO.js} +5 -10
- package/dist/cli-delegate/{chunk-T7L2QK3K.js → chunk-LQOCRFWT.js} +1 -1
- package/dist/cli-delegate/{chunk-S4YWNRKO.js → chunk-MDPPKQCQ.js} +34 -1
- package/dist/cli-delegate/chunk-OAFSJBHH.js +272 -0
- package/dist/cli-delegate/{chunk-GKE7ZVFA.js → chunk-PWX7CKMD.js} +1 -1
- package/dist/cli-delegate/{chunk-NDJLNC6Q.js → chunk-T6BP34WI.js} +1 -0
- package/dist/cli-delegate/{chunk-RQNNW7IF.js → chunk-T7XSJSUQ.js} +433 -632
- package/dist/cli-delegate/{chunk-NQ7WT43P.js → chunk-TMWYUOK4.js} +75 -12
- package/dist/cli-delegate/{chunk-EEHDXSYD.js → chunk-WQWXGIWB.js} +12 -273
- package/dist/cli-delegate/{chunk-QLDHIPWR.js → chunk-XQTPXKFA.js} +1 -1
- package/dist/cli-delegate/cmd_analyze_session.js +223 -43
- package/dist/cli-delegate/cmd_brand_status.js +3 -2
- package/dist/cli-delegate/cmd_conformance.js +489 -238
- package/dist/cli-delegate/cmd_converge.js +3 -3
- package/dist/cli-delegate/cmd_doctor.js +15 -12
- package/dist/cli-delegate/cmd_doctor_neighbours.js +11 -4
- package/dist/cli-delegate/cmd_explain.js +43 -19
- package/dist/cli-delegate/cmd_export.js +10 -10
- package/dist/cli-delegate/cmd_git_convention.js +1851 -0
- package/dist/cli-delegate/cmd_handoff.js +40 -21
- package/dist/cli-delegate/cmd_mcp_available.js +3 -2
- package/dist/cli-delegate/cmd_migrate.js +3 -3
- package/dist/cli-delegate/cmd_packs_active.js +4 -3
- package/dist/cli-delegate/cmd_prune.js +10 -10
- package/dist/cli-delegate/cmd_route_audit.js +7 -7
- package/dist/cli-delegate/cmd_route_explain.js +5 -5
- package/dist/cli-delegate/cmd_session_recycle.js +9 -7
- package/dist/cli-delegate/cmd_settings_check.js +54 -7
- package/dist/cli-delegate/cmd_settings_get.js +18 -8
- package/dist/cli-delegate/cmd_settings_migrate.js +10 -10
- package/dist/cli-delegate/cmd_settings_set.js +1 -1
- package/dist/cli-delegate/cmd_sync.js +10 -10
- package/dist/cli-delegate/cmd_uninstall.js +10 -10
- package/dist/cli-delegate/cmd_update.js +7 -7
- package/dist/cli-delegate/cmd_upgrade.js +7 -7
- package/dist/cli-delegate/cmd_validate.js +10 -10
- package/dist/cli-delegate/cmd_versions.js +5 -5
- package/dist/cli-delegate/gate_budget.js +1 -1
- package/dist/cli-delegate/gate_execute.js +2 -2
- package/dist/cli-delegate/roadmap_gates.js +2 -2
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +171 -107
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +7 -7
- package/dist/discovery/dormancy-report.md +1 -1
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +41 -22
- package/dist/discovery/trust-report.md +3 -3
- package/dist/discovery/workspaces.json +16 -11
- package/dist/hooks/dispatch.js +2520 -1924
- package/dist/hooks/dispatch.sha256 +1 -1
- package/dist/hooks/svg_rules.chunk.cjs +1626 -0
- package/dist/hooks/svg_rules.chunk.cjs.sha256 +1 -0
- package/dist/install/install.mjs +462 -431
- package/dist/install/installThinLayer.js +40 -12
- package/dist/install/installedRuleLinks.js +105 -19
- package/dist/mcp/awesome-mcp-servers.row.md +1 -1
- package/dist/mcp/mcp-cloudflare-catalogue.json +2 -2
- package/dist/mcp/registry-manifest.json +5 -5
- package/dist/mcp/server.json +2 -2
- package/dist/mcp/server.mjs +3063 -2160
- package/dist/router.json +1 -1
- package/dist/scripts/_lib/agent_settings.js +15 -120
- package/dist/scripts/_lib/compile_time_toggles.js +12 -21
- package/dist/scripts/_lib/git_convention.js +232 -0
- package/dist/scripts/_lib/global_deploy_inventory.js +730 -0
- package/dist/scripts/_lib/installed_layer.js +344 -18
- package/dist/scripts/_lib/package_root.js +68 -0
- package/dist/scripts/_lib/rule_law_section.js +1 -1
- package/dist/scripts/_lib/scan_scope.js +105 -0
- package/dist/scripts/_lib/settings_removed_keys.js +168 -0
- package/dist/scripts/_lib/svg_dom.js +284 -0
- package/dist/scripts/_lib/svg_geometry.js +477 -0
- package/dist/scripts/_lib/svg_motion.js +179 -0
- package/dist/scripts/_lib/svg_rules.js +1337 -0
- package/dist/scripts/_lib/svg_urls.js +67 -0
- package/dist/scripts/_lib/thin_rules.js +80 -3
- package/dist/scripts/lint_svg_asset.js +324 -0
- package/dist/server/app.js +2 -1
- package/dist/server/gitKeysGate.js +105 -0
- package/dist/server/routes/settings.js +67 -8
- package/dist/server/routes/wizard.js +4 -0
- package/dist/server/schemas/settings.js +23 -81
- package/dist/shared/skillRanking.js +30 -4
- package/dist/ui/assets/{index-Cwq4d0hX.js → index-C3djEJah.js} +2 -2
- package/dist/ui/index.html +1 -1
- package/docs/MIGRATION.md +72 -1
- package/docs/contracts/settings-classes.md +35 -65
- package/docs/guidelines/agent-infra/active-remediation-mechanics.md +39 -0
- package/docs/guidelines/agent-infra/context-hygiene-mechanics.md +1 -1
- package/docs/guidelines/agent-infra/cross-source-consistency-mechanics.md +8 -10
- package/docs/guidelines/agent-infra/frontier-reasoning-operating-profile.md +3 -2
- package/docs/guidelines/agent-infra/layered-settings.md +13 -1
- package/docs/guidelines/agent-infra/roadmap-progress-mechanics.md +1 -1
- package/docs/guidelines/agent-infra/self-improvement-pipeline.md +10 -3
- package/docs/guidelines/agent-infra/size-and-scope.md +36 -0
- package/docs/guidelines/design-antipatterns.md +1 -1
- package/docs/guidelines/php/git.md +15 -2
- package/package.json +4 -3
- package/src/agent-src/scripts/gate_budget.ts +47 -23
- package/src/agent-src/scripts/gate_execute.ts +12 -4
- package/src/agent-src/templates/AGENTS.md +1 -1
- package/src/agent-src/templates/scripts/work_engine/_lib/agent_settings.ts +0 -6
- package/src/agent-src/templates/scripts/work_engine/directives/backend/_self_fix.ts +11 -7
- package/src/agent-src/templates/scripts/work_engine/hooks/builtin/decision_trace.ts +3 -2
- package/src/agent-src/templates/scripts/work_engine/hooks/builtin/memory_visibility.ts +2 -1
- package/src/agent-src/templates/scripts/work_engine/hooks/settings.ts +0 -6
- package/src/agent-src/templates/scripts/work_engine/scoring/decision_engine.ts +9 -12
- package/src/agent-src/templates/scripts/work_engine/scoring/memory_visibility.ts +2 -1
- package/src/config/agent-settings.template.yml +79 -312
- package/src/config/agents-paths.yml +16 -0
- package/src/config/assurance-capability-registry.json +7 -3
- package/src/config/ci-local-parity.yml +3 -0
- package/src/config/continuity-surface.json +3 -3
- package/src/config/discovery/packs.yml +17 -1
- package/src/config/evaluator-budgets.json +19 -6
- package/src/config/gate-coverage.yml +65 -23
- package/src/config/gate-violation-baselines.json +56 -16
- package/src/config/gitignore-block.txt +19 -0
- package/src/config/hook-bundle-budget.json +1 -1
- package/src/config/release-gate-locality.yml +2 -1
- package/src/config/routing-coverage-seed.json +55 -6
- package/src/config/rule-law-ceilings.json +12 -6
- package/src/config/rule-obligations.json +833 -0
- package/src/install/installThinLayer.ts +76 -10
- package/src/install/installedRuleLinks.ts +105 -17
- package/src/scripts/_cli/cmd_analyze_session.ts +9 -15
- package/src/scripts/_cli/cmd_conformance.ts +13 -2
- package/src/scripts/_cli/cmd_doctor.ts +10 -10
- package/src/scripts/_cli/cmd_doctor_neighbours.ts +133 -0
- package/src/scripts/_cli/cmd_explain.ts +72 -14
- package/src/scripts/_cli/cmd_git_convention.ts +637 -0
- package/src/scripts/_cli/cmd_settings_check.ts +66 -8
- package/src/scripts/_cli/cmd_settings_get.ts +18 -3
- package/src/scripts/_cli/doctor_execution.ts +72 -1
- package/src/scripts/_dispatch.bash +37 -2
- package/src/scripts/_lib/agent_settings.ts +15 -124
- package/src/scripts/_lib/blocked_by_marker.ts +1 -1
- package/src/scripts/_lib/compile_time_toggles.ts +12 -21
- package/src/scripts/_lib/dispatch_import_closure.ts +163 -0
- package/src/scripts/_lib/git_base_ref.ts +92 -0
- package/src/scripts/_lib/git_convention.ts +291 -0
- package/src/scripts/_lib/git_convention_carrier.ts +389 -0
- package/src/scripts/_lib/git_convention_grammar.ts +246 -0
- package/src/scripts/_lib/git_convention_measure.ts +344 -0
- package/src/scripts/_lib/global_deploy_inventory.ts +74 -0
- package/src/scripts/_lib/graph_feeder_record.ts +236 -13
- package/src/scripts/_lib/installed_layer.ts +448 -23
- package/src/scripts/_lib/knowledge_global.ts +14 -1
- package/src/scripts/_lib/module_reach.ts +456 -0
- package/src/scripts/_lib/neighbour_contradictions.ts +236 -0
- package/src/scripts/_lib/neighbour_tool_use.ts +8 -10
- package/src/scripts/_lib/ratification_artifact.ts +220 -1
- package/src/scripts/_lib/ratification_subject.ts +92 -0
- package/src/scripts/_lib/release_findings_ingest.ts +15 -7
- package/src/scripts/_lib/release_highlights.ts +5 -0
- package/src/scripts/_lib/rule_law_section.ts +1 -1
- package/src/scripts/_lib/rule_obligations.ts +205 -0
- package/src/scripts/_lib/self_repair.ts +1 -1
- package/src/scripts/_lib/settings_removed_keys.ts +173 -0
- package/src/scripts/_lib/svg_dom.ts +318 -0
- package/src/scripts/_lib/svg_geometry.ts +480 -0
- package/src/scripts/_lib/svg_motion.ts +208 -0
- package/src/scripts/_lib/svg_rules.ts +1453 -0
- package/src/scripts/_lib/svg_urls.ts +72 -0
- package/src/scripts/_lib/test_red_state.ts +5 -0
- package/src/scripts/_lib/thin_rules.ts +83 -3
- package/src/scripts/_lib/touched_file_quality.ts +142 -6
- package/src/scripts/_lib/verification_command.ts +59 -0
- package/src/scripts/_lib/verify_clause.ts +27 -17
- package/src/scripts/_lib/worker_budget.ts +1 -1
- package/src/scripts/adr/regenerate_index.ts +16 -1
- package/src/scripts/ai_council/config.ts +7 -7
- package/src/scripts/ai_council/modification_review.ts +100 -0
- package/src/scripts/ai_council/modification_review_questions.ts +90 -0
- package/src/scripts/ai_council/orchestrator.ts +5 -5
- package/src/scripts/ai_council/spend_gate.ts +18 -7
- package/src/scripts/ai_team/config.ts +11 -16
- package/src/scripts/audit_user_type_axis.ts +20 -8
- package/src/scripts/bench_ab_clone.ts +1 -2
- package/src/scripts/bench_concern_spawn_path.ts +129 -0
- package/src/scripts/bench_graph_feeder_latency.ts +584 -0
- package/src/scripts/check_agent_artifact_location.ts +36 -0
- package/src/scripts/check_branch_freshness.ts +147 -24
- package/src/scripts/check_enforcement_coverage.ts +130 -0
- package/src/scripts/check_evaluator_budgets.ts +4 -0
- package/src/scripts/check_finding_dispositions.ts +88 -25
- package/src/scripts/check_gate_coverage.ts +4 -3
- package/src/scripts/check_gate_reachability.ts +48 -1
- package/src/scripts/check_generator_sync.ts +48 -0
- package/src/scripts/check_hook_bundle_composition.ts +107 -0
- package/src/scripts/check_kernel_edit_ratified.ts +86 -6
- package/src/scripts/check_pack_size.ts +1 -1
- package/src/scripts/check_release_manifest_content.ts +189 -0
- package/src/scripts/check_standing_rule_delivery.ts +96 -0
- package/src/scripts/check_suppression_hygiene.ts +2 -5
- package/src/scripts/ci_settle.ts +42 -5
- package/src/scripts/classify_merge_risk.ts +320 -0
- package/src/scripts/closure_scan.ts +91 -1
- package/src/scripts/command_suggester/settings.ts +8 -108
- package/src/scripts/command_suggester/types.ts +4 -5
- package/src/scripts/consumer_matrix.ts +102 -0
- package/src/scripts/context_hygiene_hook.ts +13 -23
- package/src/scripts/cost/preflight.mjs +12 -1
- package/src/scripts/council_cli.ts +7 -7
- package/src/scripts/dispatch_r2_reviewer.ts +24 -11
- package/src/scripts/explain_run.ts +8 -13
- package/src/scripts/generate_git_convention_grammar.ts +127 -0
- package/src/scripts/generate_host_cost_table.ts +20 -3
- package/src/scripts/handoff_context_hook.ts +86 -37
- package/src/scripts/hook_manifest.json +1 -1
- package/src/scripts/hook_manifest.yaml +25 -6
- package/src/scripts/hooks/block_config_weakening.ts +48 -5
- package/src/scripts/hooks/block_plumbing_writes.ts +8 -4
- package/src/scripts/hooks/block_speaking_inbox_dir.ts +16 -1
- package/src/scripts/hooks/concern_registry.ts +2 -0
- package/src/scripts/hooks/delegation_nudge_hook.ts +2 -3
- package/src/scripts/hooks/design_pass_hook.ts +157 -3
- package/src/scripts/hooks/evidence_independence.ts +12 -4
- package/src/scripts/hooks/mcp_usage_observation_hook.ts +121 -0
- package/src/scripts/hooks/push_settle_hook.ts +4 -3
- package/src/scripts/hooks/rule_inject_hook.ts +44 -3
- package/src/scripts/hooks/state_io.ts +8 -4
- package/src/scripts/hooks/svg_obligation.ts +497 -0
- package/src/scripts/hooks/svg_rules_loader.ts +133 -0
- package/src/scripts/hooks/telemetry_usage_hook.ts +7 -46
- package/src/scripts/hooks/turn_end_gate_hook.ts +6 -3
- package/src/scripts/install-hooks.sh +42 -14
- package/src/scripts/install.ts +7 -31
- package/src/scripts/lint_blocker_citations.ts +198 -0
- package/src/scripts/lint_consolidation_lineage.ts +6 -3
- package/src/scripts/lint_design_quality.ts +60 -12
- package/src/scripts/lint_evidence_artifacts.ts +9 -0
- package/src/scripts/lint_hook_concern_budget.ts +10 -21
- package/src/scripts/lint_motion_authority_drift.ts +27 -0
- package/src/scripts/lint_pack_boundaries.ts +406 -28
- package/src/scripts/lint_roadmap_blockers.ts +282 -29
- package/src/scripts/lint_roadmap_complexity.ts +4 -2
- package/src/scripts/lint_rule_law_section.ts +151 -21
- package/src/scripts/lint_rule_skill_pack_reach.ts +17 -0
- package/src/scripts/lint_settings_classes.ts +1 -1
- package/src/scripts/lint_svg_asset.ts +365 -0
- package/src/scripts/lint_ticked_unmet_criteria.ts +165 -0
- package/src/scripts/lint_workflow_security.ts +12 -1
- package/src/scripts/measure_skill_ranker_baseline.ts +5 -0
- package/src/scripts/model_rule_injection.ts +3 -3
- package/src/scripts/onboarding_gate_hook.ts +7 -6
- package/src/scripts/print_required_checks.ts +15 -3
- package/src/scripts/probe_host_compliance.ts +33 -5
- package/src/scripts/probe_turnaround.ts +183 -3
- package/src/scripts/ratification_header.ts +77 -0
- package/src/scripts/refusal_envelope.ts +138 -0
- package/src/scripts/release_publication.ts +29 -3
- package/src/scripts/report_dispatch_import_closure.ts +76 -0
- package/src/scripts/report_installed_rule_links.ts +118 -1
- package/src/scripts/report_module_reach.ts +212 -0
- package/src/scripts/report_obligation_mechanism.ts +16 -18
- package/src/scripts/report_parked_blockers.ts +222 -0
- package/src/scripts/report_required_checks_drift.ts +196 -0
- package/src/scripts/report_skill_ranker_confusion.ts +103 -2
- package/src/scripts/report_standing_payload_by_host.ts +1 -1
- package/src/scripts/routing_doctor.ts +2 -2
- package/src/scripts/schemas/agent-settings.schema.json +17 -31
- package/src/scripts/schemas/command.schema.json +1 -1
- package/src/scripts/schemas/skill.schema.json +1 -1
- package/src/scripts/self_review_gate.ts +39 -2
- package/src/scripts/skill_tools/score_skill_relevance.ts +28 -19
- package/src/scripts/sync_pr_branch.ts +403 -132
- package/src/scripts/trigger_eval_grandfather.json +0 -16
- package/src/server/schemas/settings.ts +33 -177
- package/src/shared/skillRanking.ts +53 -4
- package/dist/cli-delegate/chunk-NYX3L2PZ.js +0 -99
- package/src/scripts/_lib/config_chain.ts +0 -477
- package/src/scripts/_lib/conformance_report.ts +0 -403
- package/src/scripts/_lib/eval_discrimination.ts +0 -95
- package/src/scripts/_lib/evaluator_promotion.ts +0 -225
- package/src/scripts/_lib/file_slicer.ts +0 -117
- package/src/scripts/_lib/legacy_boundary_map.ts +0 -228
- package/src/scripts/_lib/minimality_tiebreak.ts +0 -168
- package/src/scripts/_lib/overbuild_lens_contract.ts +0 -196
- 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 —
|
|
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.
|
|
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
|
|
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
|
|
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
|
|
172
|
-
git
|
|
173
|
-
|
|
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
|
|
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
|
|
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` (
|
|
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
|
-
|
|
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
|
-
|
|
208
|
-
git push --force-with-lease="
|
|
209
|
-
git
|
|
210
|
-
|
|
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
|
|
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
|
-
-
|
|
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
|
|
232
|
-
**both** sides non-zero
|
|
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.
|
|
242
|
+
### 2. Record both sides immediately
|
|
243
243
|
|
|
244
244
|
```bash
|
|
245
|
-
|
|
246
|
-
git
|
|
247
|
-
git
|
|
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
|
|
254
|
-
git log --oneline HEAD
|
|
255
|
-
git diff
|
|
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
|
|
263
|
-
| Origin has commits local does not reflect (another contributor pushed) | **Origin** |
|
|
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
|
|
281
|
-
problem. After resolution, verify
|
|
282
|
-
SHAs plus the
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 →
|
|
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`.
|