一键导入
phase-c-integrator
十步循环 Phase C - 集成阶段执行器,编排 C.1-C.2 步骤。 使用场景:"执行集成阶段"、"Phase C"、"提交代码并创建 PR"
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
十步循环 Phase C - 集成阶段执行器,编排 C.1-C.2 步骤。 使用场景:"执行集成阶段"、"Phase C"、"提交代码并创建 PR"
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Aria 项目级配置加载器(内部基础设施)。 查找、解析、验证 .aria/config.json 并合并默认值。 此 Skill 不直接触发,由其他 Skills 引用以读取项目配置。
项目状态扫描与智能工作流推荐,十步循环的统一入口。 收集项目状态、分析变更、推荐最佳工作流、引导用户确认执行。 使用场景:"查看项目当前状态"、"我要提交代码"、"开发新功能"
会话收尾 —— 在任意对话(含未走完十步循环的探索/调试/讨论 session)把"未交接成果" 固化为 handoff。**与十步循环正交平级的会话仪式**(非周期收尾): AI 先内省本对话出 未完成线程 + 待固化经验, 再用机械 autofill 交叉核验补漏, 写 docs/handoff/。leaf — 终结于写交接, 不拖入十步循环。 使用场景: "对话收尾" / "执行对话收尾" / "会话收尾" / "session closeout" / "收尾这次对话" / "写交接" / "写 handoff" / "收工" / "结束本次对话" / context 快满时主动收尾。 不适用 (用 phase-d-closer): "Phase D" / "周期收尾" / "归档 Spec" / "更新 cycle 进度" —— 那是开发周期收尾, 不是会话收尾。
Git 多远程 parity 检测与 push 验证的共享基础设施。 内部工具, 仅供其他 skills 引用。提供标准化 Bash/Python 执行脚本段 + 输出 JSON schema 契约。
任务到 Agent 的智能路由器,根据任务类型、文件路径自动选择最合适的 Agent。 使用场景:subagent-driver 需要为任务选择 Agent、不确定应该使用哪个 Agent
向 Aria 维护团队报告 Bug 或提交功能建议。自动收集环境信息, 自动路由到 Forgejo(内部用户)或 GitHub(外部用户)。 使用场景:"报告 bug"、"report an issue"、"提交功能建议"、 "aria 有个问题想反馈"、"feature request"、"提 issue"、 "反馈问题"、"report bug to aria"
| name | phase-c-integrator |
| description | 十步循环 Phase C - 集成阶段执行器,编排 C.1-C.2 步骤。 使用场景:"执行集成阶段"、"Phase C"、"提交代码并创建 PR" |
| argument-hint | [--skip-pr] |
| disable-model-invocation | false |
| user-invocable | true |
| allowed-tools | Bash, Read, Write, Glob, Grep, Task, Skill |
版本: 1.3.0 | 十步循环: C.1-C.2 更新: 2026-05-10 - C.2.4 Pre-Merge Precondition Gate (#60, consume aether
--in-flightprimitive) 历史更新: 2026-03-27 - 升级审计触发从 agent-team-audit 改为 audit-engine
使用场景:
不使用场景:
执行前读取 .aria/config.json,缺失则使用默认值。参见 config-loader。
| 字段 | 默认值 | 说明 |
|---|---|---|
audit.enabled | false | 启用 audit-engine 审计 (新) |
audit.checkpoints.pre_merge | "off" | pre_merge 检查点模式 |
experiments.agent_team_audit | false | 旧配置 (向后兼容,自动映射到 audit.*) |
experiments.agent_team_audit_points | ["pre_merge"] | 旧配置 (向后兼容) |
upm.milestone_driven | false | 启用 C.2.6 里程碑子进度追加 (opt-in) |
phase_c_integrator.pre_merge_gate.enabled | true | 启用 C.2.4 pre-merge precondition gate (v1.3.0+) |
phase_c_integrator.submodule_gate.mode | "block" (v1.49.0+ default) / "warn" (legacy) / "off" (bypass) | C.2.4.5 submodule pointer regression gate 模式 (Spec aria-submodule-pointer-regression-gate) |
phase_c_integrator.pre_merge_gate.ci_backends | null (auto-detect) / [] (explicit disable) / [{name: "..."}] (explicit list) | v1.31.0+ CI backend 选择 (替代旧 primitive_preference). 见 §C.2.4.X CI Backends |
phase_c_integrator.pre_merge_gate.no_ci_fallback | "skip_with_warning" | 无可用 CI backend 时降级 (skip_with_warning / abort). v1.31.0+ 替代旧 no_aether_fallback (alias 仍读, 发 deprecation warning, v2.0 移除) |
phase_c_integrator.pre_merge_gate.wait_timeout_seconds | 1800 | wait+retry max 等待时长 (默认 30 min) |
phase_c_integrator.pre_merge_gate.wait_check_intervals | [30,60,120,300,300] | 指数退避秒数; 数组耗尽后重复 intervals[-1] |
phase_c_integrator.pre_merge_gate.primitive_call_timeout_seconds | 30 | 单次 aether subprocess 调用 timeout |
phase_c_integrator.pre_merge_gate.poll_chunk_seconds | 5 | Ctrl-C polling chunk 大小 |
当 audit.enabled=true 且 audit.checkpoints.pre_merge != "off" 时,C.2 合并前触发 audit-engine (pre_merge 检查点)。
旧配置 experiments.agent_team_audit=true 且 "pre_merge" in agent_team_audit_points 自动映射到新配置。
| 步骤 | Skill | 职责 | 输出 |
|---|---|---|---|
| C.1 | commit-msg-generator | Git 提交 | commit_sha, message |
| C.2 | branch-manager | PR/合并 | pr_url, pr_number |
context:
phase_cycle: "Phase4-Cycle9"
module: "mobile"
changed_files: ["lib/auth.dart", "test/auth_test.dart"]
branch_name: "feature/mobile/TASK-001-add-auth" # 来自 Phase B
test_results: # 来自 Phase B
passed: true
coverage: 87.5
# v1.1.0 新增: branch-finisher 输出
completion_option: 1 # 来自 branch-finisher
worktree_path: ".git/worktrees/TASK-001-xxx" # 可选
validation_report: # 来自 branch-finisher
passed: true
blocking_failures: 0
warnings: 1
config:
skip_steps: []
params:
enhanced_markers: true # 使用增强提交标记
create_pr: true # 是否创建 PR
C.1 - Git 提交:
skill: commit-msg-generator
params:
enhanced_markers: true
subagent_type: "from_context"
phase_cycle: "from_context"
module: "from_context"
skip_if:
- no_changes_to_commit: true
action:
- 分析暂存区变更
- 生成规范提交消息
- 执行 git commit
output:
commit_sha: "abc1234"
commit_message: "feat(auth): 添加用户认证..."
C.2 - PR/合并:
skill: branch-manager
action: pr
skip_if:
- no_pr_needed: true
- direct_push_allowed: true
pre_hook: # audit-engine 检查点
audit_engine:
checkpoint: pre_merge
步骤:
1. 通过 config-loader 读取 .aria/config.json audit 块
2. 检查 audit.enabled — false 则跳过,保持现有行为不变
3. 检查 audit.checkpoints.pre_merge — "off" 则跳过
4. 如启用: 调用 audit-engine
- checkpoint: "pre_merge"
- mode: 来自配置 (convergence / challenge / adaptive)
- context: PR diff (branch_name vs base)
5. 处理 verdict:
- PASS / PASS_WITH_WARNINGS → 继续推送和创建 PR
- FAIL → 阻塞合并,输出审计报告
backward_compat:
audit.enabled=false: 完全跳过,Phase C 行为与之前完全相同
旧配置 experiments.agent_team_audit: 由 audit-engine 内部映射处理
fallback_description: |
audit-engine 内部通过 agent-team-audit 单轮引擎执行审计。
直接调用 agent-team-audit 已由 audit-engine 编排层取代。
on_fail: 阻塞合并, 输出审计报告
on_skip: 继续合并 (审计未启用)
action:
- (如 audit.enabled) 触发 audit-engine (pre_merge 检查点)
- 推送分支到远程
- 创建 Pull Request
- (可选) 自动合并
output:
pr_url: "https://..."
pr_number: 123
audit_verdict: "PASS" # 如审计启用 (PASS | PASS_WITH_WARNINGS | FAIL)
audit_report: ".aria/audit-reports/pre_merge-{timestamp}.md"
> **注意**: branch-manager 会自动处理 Cloudflare Access 配置。
> 统一规范见 `../forgejo-sync/PRE_CHECK.md`
C.2.4 - Pre-Merge Precondition Gate (v1.3.0+):
触发条件:
- C.2 action PR 已创建 (PR_NUMBER + PR_URL 已知)
- 即将调用 branch-manager merge action (auto_merge=true 或 user-triggered continue)
- 配置 phase_c_integrator.pre_merge_gate.enabled: true (默认)
primitive 调用:
- aether ci status --branch main --in-flight --json (查 main 是否有 in-flight)
- aether ci status --branch <PR_BRANCH> --json (查本 PR CI 状态)
- aria 端 verdict 计算 (aether-pre-merge-check skill 从未实施, P0-B not shipped)
三态结果:
green: 本 PR CI passing + main 无 in-flight CI → 继续 branch-manager merge
wait: main 有 in-flight CI run OR PR CI pending → 进入 wait+retry (workflow-runner wait_recoverable)
fail: PR CI failing OR primitive 错误 → BLOCK + 报告
output:
pre_merge_verdict: "green" | "wait" | "fail"
in_flight_runs: [{run_id, branch, started_at, elapsed_seconds}] # wait 时
pr_ci_status: "passing" | "failing" | "pending"
primitive_used: "aether-ci-cli" | "manual"
primitive_version_sha: "f29abee" # aether-cli #116 baseline
C.2.4.5 - Submodule Pointer Regression Gate (v1.28.0+):
触发条件:
- C.2.4 verdict=green (CI gate 已通过)
- 即将调用 branch-manager merge action
- 配置 phase_c_integrator.submodule_gate.mode: "block" (v1.49.0+ default) | "warn" (legacy opt-out) | "off" (emergency bypass)
primitive 调用:
- git fetch origin (bare, 更新所有 ref) — 强制, 失败 abort
- git -C <submodule> fetch origin — 每 submodule
- git -C <submodule> merge-base --is-ancestor MASTER_PTR FEATURE_PTR — 主 ancestry 检查
- 双向 ancestry 区分 regression (case c) vs divergence (case d)
三态结果:
pass: 所有 submodule pointer 是 forward bump 或 no-change 或 first-time
block: 至少一个 submodule pointer 是 regression 或 divergence (v1.49.0+ default; v1.28.0 was warn-only)
bypass: per-PR commit trailer `Submodule-Rollback: ...` 或 PR label `submodule-rollback-approved` 允许 + audit log
output:
gate_verdict: "pass" | "block" | "warn" | "bypass"
affected_submodules: [{path, master_sha, feature_sha, verdict, override}]
telemetry_written: <metrics file path>
C.2.5 - Multi-Remote Push Enforcement:
触发条件:
- Phase C.2 合并成功 (master 已 fast-forward)
- 配置 phase_c_integrator.multi_remote_push.enabled: true (默认)
skill: git-remote-helper (降级: 内联实现)
action: 见下方 ### C.2.5 详细说明
C.2.6 - UPM Milestone Sub-progress Append (optional):
触发条件:
- C.2.5 multi-remote push 已完成 (或跳过)
- 配置 upm.milestone_driven: true (默认 false,opt-in)
- 当前 commit 与某 User Story 关联 (commit message 含 US-XXX 或 spec change_id)
action: 见下方 ### C.2.6 详细说明
backward_compat: upm.milestone_driven=false 时完全跳过,Phase C 行为与之前完全相同
新增于 v1.3.0 — 修复 Forgejo Issue #60 "phase-c-integrator 缺少 pre-merge safety gate"。 源于 2026-05-02 SilkNode PR-321 cancel PR-322 main CI Run #3161 (459s 部署观测丢失)。 Consume aether
--in-flightprimitive (aether-cli #116, SHAf29abee2026-05-06)。
Naming 命名空间澄清: phase-c-integrator-level 子步骤标签 (C.2.x) 为 orchestrator-tier,与 branch-manager 内部实现层 (也用 C.2.x sequence: C.2.1 sync / C.2.2 push / C.2.3 create-PR / C.2.4 wait-approval / C.2.5 merge) 是独立 label namespace。本 SKILL §C.2.4 = "pre-merge precondition gate" (orchestrator);branch-manager 内部 C.2.4 = "等待审批" (implementation);同名不同 tier,语义独立。
触发条件:
auto_merge=true 自动 / auto_merge=false user-triggered)phase_c_integrator.pre_merge_gate.enabled: true (默认)与 branch-manager 边界 (不重叠):
| Skill | 职责 | 调用顺序 |
|---|---|---|
| branch-manager (C.2.1-C.2.3) | sync rebase + push branch + create PR | gate 之前 |
| phase-c-integrator C.2.4 | pre-merge gate 三态判定 | gate (本段) |
| branch-manager (C.2.4-C.2.5) | wait approval + merge API call | gate green 后 |
执行流程:
aether --help | grep -q "in-flight" 验证 binary 含 P0-A flag,缺失 → fail-fast 提示 "请升级 aether ≥ commit f29abee (2026-05-06)"resolve_ci_backend(cfg) 按 config 显式 ci_backends 顺序探测,或 fallback 到 BACKENDS list 静态顺序 (Aether-first, GHA-stub-second);所有 backend probe=False → 按 no_ci_fallback 配置降级。详见 §C.2.4.X CI Backendsaether ci status --branch main --in-flight --json → parse data.runs[]aether ci status --branch <PR_BRANCH> --json → parse 最近 run 的 status 字段 → 映射为 passing / failing / pendingpr_ci_status in [failing, error] → verdict=failpr_ci_status == pending → verdict=wait (PR CI 尚未完成)pr_ci_status == passing AND main_in_flight_runs == [] → verdict=greenpr_ci_status == passing AND main_in_flight_runs != [] → verdict=waitgreen → 调用 branch-manager merge action,进入 C.2.5wait → 输出 wait_recoverable 错误给 workflow-runner,触发 wait+retry 循环 (见 workflow-runner SKILL.md §wait_recoverable)fail → BLOCK + 输出 verdict + raw_message,phase-c-integrator return failureSubprocess 调用规范:
subprocess.run(..., timeout=primitive_call_timeout_seconds) 强制 (默认 30s)fail verdict0 = success / 1-126 = aether 错误 → fail / 127 = binary not found → no_ci_fallback / -SIGTERM = subprocess timeout → retry → 仍失败则 fail。NIE-propagation 例外 (v1.31.0+, Hard Constraint #7): stub backend (e.g. GHA v1.31.0) query 方法 raise NotImplementedError → gate abort (raise to caller),不走 no_ci_fallbackHelper 实现: ${ARIA_PLUGIN_ROOT:-aria}/skills/phase-c-integrator/scripts/pre_merge_gate.py (stdlib + subprocess only)
Output schema:
{
"verdict": "green" | "wait" | "fail",
"pr_ci_status": "passing" | "failing" | "pending",
"in_flight_runs": [
{"run_id": 3161, "branch": "main", "started_at": "2026-05-09T12:45:00Z", "elapsed_seconds": 459}
],
"primitive_used": "aether-ci-cli",
"primitive_version_sha": "f29abee",
"raw_message": "..."
}
配置参数:
| 参数 | 默认 | 说明 |
|---|---|---|
enabled | true | gate 总开关 (false → 完全跳过 C.2.4,向后兼容) |
ci_backends | null (auto-detect) / [] (disable) / [{name: "..."}] | v1.31.0+ backend 选择. Alias: 旧 primitive_preference 仍读 + deprecation warning |
no_ci_fallback | "skip_with_warning" | 无可用 backend 时 (skip_with_warning / abort). Alias: 旧 no_aether_fallback 仍读 + deprecation warning |
wait_timeout_seconds | 1800 | wait+retry max (默认 30 min) |
wait_check_intervals | [30,60,120,300,300] | 指数退避 (秒); 数组耗尽后重复 intervals[-1] |
primitive_call_timeout_seconds | 30 | 单次 subprocess 调用 timeout |
poll_chunk_seconds | 5 | Ctrl-C polling chunk |
降级行为:
enabled: false → 完全跳过 C.2.4 (与 v1.2.0 行为 100% 一致)no_ci_fallback: skip_with_warning → 跳过 + workflow report 警告no_ci_fallback: abort → BLOCK + 提示安装支持的 CI backendci_backends: []) → 视为"无可用 backend" 路径,按 no_ci_fallback 降级 (canonical way to disable v1.31.0+)gh 装但 GHA stub query 未实现) → 不走 fallback,直接 abort (Hard Constraint #7)--in-flight flag) → fail-fast,不继续执行 (避免 silent skip)Race condition 处理: gate 检查与 merge call 之间,main 可能新触发 CI run。窗口最小化 (gate green 后立即调 merge),不消除 race。深度 mitigation 留 future Spec。
新增于 v1.31.0 — 实施 Spec
aria-ci-backend-abstraction(Approved 2026-05-28, post_spec R2 CONVERGED unanimous PASS_WITH_WARNINGS × 3)。源于 2026-05-27 boundary audit P0 C5+C6 — pre_merge_gate.py 去 Aether-only 假设。
Backend 抽象: pre_merge_gate.py 通过 aria/skills/phase-c-integrator/scripts/ci_backends/ 包提供的 CIBackend ABC + CIStatus / InFlightStatus dataclass 调用 CI primitive。每个 backend 实现两个 abstract method (query_pr_ci / query_branch_in_flight) + 一个 ClassVar (name) + classmethod probe()。
Supported backends (v1.31.0):
| Backend | name | Status | Real implementation? |
|---|---|---|---|
| Aether | aether-ci-cli | ✅ Default, full | Yes (10CG Lab internal, migrated from v1.30.0 pre_merge_gate.py) |
| GitHub Actions | github-actions | 🚧 Stub | No — probe() real (gh CLI + auth check), query_*() raise NotImplementedError. Real implementation deferred to v1.32.0+ next cycle |
Backend selection algorithm (resolve_ci_backend(config)):
if config["ci_backends"] is [] (empty list):
return None # explicit disable per AC-4.5
elif config["ci_backends"] is non-empty list:
try each entry in user-specified order, return first probe()=True
elif config["ci_backends"] is None or missing:
iterate BACKENDS list (Aether → GHA), return first probe()=True
BACKENDS list order (ci_backends/__init__.py static import, Hard Constraint #8):
BACKENDS: list[type[CIBackend]] = [AetherBackend, GitHubActionsBackend]
→ Aether-first precedence locked. 不允许 decorator-based registration / setuptools.entry_points / 任何 dynamic discovery。
Config schema example:
{
"phase_c_integrator": {
"pre_merge_gate": {
"enabled": true,
"ci_backends": null, // auto-detect (default)
// OR: "ci_backends": [], // explicit disable
// OR: "ci_backends": [{"name": "aether-ci-cli"}], // explicit list
"no_ci_fallback": "skip_with_warning", // when no backend available
// Legacy alias (auto-translated + DeprecationWarning, removed in v2.0):
// "primitive_preference": ["aether-ci-cli"],
// "no_aether_fallback": "skip_with_warning"
}
}
}
Hard Constraint #7 (NIE-propagation safety):
Stub backend (e.g. GitHubActionsBackend in v1.31.0) probe() returns True 但 query_*() raise NotImplementedError。gate_check() 必须 propagate NIE to caller,不允许 catch-and-route-to-no_ci_fallback。理由:防止"装了 gh 但实际用 Aether 的项目"因 GHA stub 抢先注册而 Rule #8 静默降级。如需禁用 backend probing,显式设 ci_backends: []。
Probe cache (Hard Constraint #11, Option B):
ci_backends/__init__.py exports cached_probe(backend_cls) + reset_probe_cache()。模块-level dict (_probe_cache) 缓存 probe 结果。禁止 @functools.lru_cache (test isolation hazard)。测试 setUp/tearDown 必须调 reset_probe_cache() 防止状态泄漏。
Adding a new backend (e.g. GitLab CI):
ci_backends/gitlab_ci.py 继承 CIBackend,实现 name / probe / query_pr_ci / query_branch_in_flight (optionally precheck)ci_backends/__init__.py 加 import + 加到 BACKENDS list (位置决定 precedence)tests/test_ci_backends.pyNIE 是 stub 临时状态: 如果新 backend 计划只做 stub,所有 query_*() 必须 raise NotImplementedError 带 operable message (含 "PR welcome" 提示 + 显式 disable instructions per ci_backends: [])。Hard Constraint #4 + AC-2.5 enforced via test。
新增于 v1.28.0 — 实施 Spec
aria-submodule-pointer-regression-gate(Approved 2026-05-24, DEC-20260524-002)。 源于 2026-05-23 PR #123 silent submodule pointer regression incident (6fea5d7静默回滚 4 commits, 被 post-merge audit catch + fast-forward fixa8e0096)。 Closes Forgejo Aria #124。
Two-phase rollout (✅ flipped to block default in v1.49.0, 2026-06-21):
mode=warn 默认 — 检测 + 日志 WOULD-BLOCK, 不阻止 mergemode=block 默认 — 检测到 regression/divergence + 无 override → 拒绝 merge.aria/decisions/2026-06-21-v1.49.0-block-flip.md (主仓)。触发条件:
phase_c_integrator.submodule_gate.mode: "block" (v1.49.0+ default) | "warn" (legacy opt-out) | "off" (skip 完全)执行流程 (Bash gate, 见 scripts/submodule_gate.sh):
# Step 1: fail-loud fetch with bounded retries (1s/2s/4s × 3 attempts)
# Drop fragile `grep success patterns` — use exit code only (AD-FOLLOWUP-1)
BEFORE_REMOTE=$(git rev-parse origin/master 2>/dev/null || echo "FIRST_RUN")
for delay in 1 2 4; do
if git fetch origin 2>&1; then FETCH_OK=1; break; fi
sleep "$delay"
done
[[ "${FETCH_OK:-0}" != 1 ]] && {
log_telemetry "FETCH_FAILURE" "$BEFORE_REMOTE" "(unknown)" "fetch_exhausted_retries"
echo "BLOCK: git fetch origin failed after 3 attempts" >&2
exit 1
}
# Step 2: refspec assertion (skip on FIRST_RUN)
AFTER_REMOTE=$(git rev-parse origin/master)
if [[ "$BEFORE_REMOTE" != "FIRST_RUN" && "$BEFORE_REMOTE" != "$AFTER_REMOTE" ]]; then
if ! git merge-base --is-ancestor "$BEFORE_REMOTE" "$AFTER_REMOTE" 2>/dev/null; then
echo "BLOCK: origin/master rewritten (non-ancestor advance) — operator confirm required" >&2
exit 1
fi
fi
# Step 3: per-submodule loop
exit_code=0
while IFS= read -r SUB; do
[[ -z "$SUB" ]] && continue
git -C "$SUB" fetch origin 2>&1 >/dev/null || true
FEATURE_PTR=$(git ls-tree HEAD "$SUB" | awk '{print $3}')
MASTER_PTR=$(git ls-tree origin/master "$SUB" | awk '{print $3}')
# nil-SHA: first-time submodule (master had no gitlink)
[[ -z "$MASTER_PTR" ]] && {
echo "INFO: $SUB first introduced this PR (no prior master gitlink); gate PASS"
continue
}
# No-change
[[ "$FEATURE_PTR" == "$MASTER_PTR" ]] && {
echo "OK: $SUB unchanged"
continue
}
echo "GATE: submodule=$SUB master=$MASTER_PTR feature=$FEATURE_PTR"
# Forward bump?
if git -C "$SUB" merge-base --is-ancestor "$MASTER_PTR" "$FEATURE_PTR" 2>/dev/null; then
echo "PASS: $SUB forward bump"
continue
fi
# Distinguish regression vs divergent
if git -C "$SUB" merge-base --is-ancestor "$FEATURE_PTR" "$MASTER_PTR" 2>/dev/null; then
VERDICT="REGRESSION"
else
VERDICT="DIVERGENT"
fi
# Check override (commit trailer OR PR label)
if check_override "$SUB" "$MASTER_PTR" "$FEATURE_PTR"; then
echo "ALLOW: $SUB $VERDICT overridden (audit logged)"
log_override "$SUB" "$VERDICT" "$MASTER_PTR" "$FEATURE_PTR"
continue
fi
# Mode dispatch
MODE="${ARIA_SUBMODULE_GATE_MODE:-block}"
if [[ "$MODE" == "warn" ]]; then
echo "WOULD-BLOCK: submodule=$SUB master=$MASTER_PTR feature=$FEATURE_PTR reason=$VERDICT"
log_warn "$SUB" "$VERDICT" "$MASTER_PTR" "$FEATURE_PTR"
else
echo "BLOCK: $VERDICT — submodule=$SUB master=$MASTER_PTR feature=$FEATURE_PTR" >&2
echo " Override 1: commit trailer 'Submodule-Rollback: $SUB $MASTER_PTR->$FEATURE_PTR reason=<reason>'" >&2
echo " Override 2: PR label 'submodule-rollback-approved'" >&2
log_block "$SUB" "$VERDICT" "$MASTER_PTR" "$FEATURE_PTR"
exit_code=1
fi
done < <(git config --file .gitmodules --get-regexp '^submodule\..*\.path$' 2>/dev/null | awk '{print $2}')
exit $exit_code
Override mechanism (per-PR explicit, NOT sticky config):
Commit trailer in merge commit message (accepts both Unicode → and ASCII ->):
Submodule-Rollback: aria a8e0096→3b688a9 reason=v1.24.1 introduced critical regression
Submodule-Rollback: aria a8e0096->3b688a9 reason=同 (ASCII alternative for LANG=C/POSIX safety)
Parser resolves short SHAs (≥7 chars) via git rev-parse before comparison to FEATURE/MASTER pointers. Mismatched SHAs in trailer → reject override.
PR label submodule-rollback-approved (settable only by repo maintainers via Forgejo):
forgejo GET /repos/<owner>/<repo>/issues/<PR>/labelsOverride audit log to metrics/submodule-gate-overrides.jsonl (JSONL append-only, race-safe):
{"timestamp":"...","pr_id":N,"submodule":"...","master_sha":"...","feature_sha":"...","verdict":"REGRESSION","reason":"...","override_type":"trailer"|"label"}
Verdict 三态 (output):
pass — all submodules: forward / no-change / first-timewarn (legacy opt-out) — WOULD-BLOCK logged, merge proceedsblock (v1.49.0+ default) — merge refused, exit 1bypass — override applied, audit logged, merge proceedsOutput schema (JSON):
{
"verdict": "pass" | "warn" | "block" | "bypass",
"affected_submodules": [
{
"path": "aria",
"master_sha": "a8e0096",
"feature_sha": "3b688a9",
"verdict": "REGRESSION",
"override": "trailer" | "label" | null
}
],
"telemetry_files": {
"warns": "metrics/submodule-gate-warns.jsonl",
"overrides": "metrics/submodule-gate-overrides.jsonl",
"blocks": "metrics/submodule-gate-blocks.jsonl",
"misses": "metrics/submodule-gate-misses.jsonl"
}
}
配置参数:
| 参数 | 默认 | 说明 |
|---|---|---|
mode | "block" (v1.49.0+ default) / "warn" (legacy) / "off" | "warn" 仅日志 / "block" 拒绝 merge / "off" 跳过 gate |
fetch_retries | [1, 2, 4] | 指数退避秒数 |
metrics_dir | "metrics/" (relative to aria-plugin root, NOT main repo) | 4 JSONL append-only 文件位置 |
forgejo_api_timeout_s | 5 | PR label fetch timeout |
nil_sha_action | "pass_with_info" | first-time submodule (master 无 gitlink) → PASS + INFO log |
降级行为:
mode: off → 完全跳过 §C.2.4.5 (与 v1.27.x 行为 100% 一致, 用于紧急 bypass 全 cycle)git fetch origin 3-attempt failure → terminal block (per wait_recoverable pattern, owner remediation: 检查 auth/network/URL drift)git ls-tree empty output (nil-SHA case) → PASS + INFO (first-time submodule case)git merge-base --is-ancestor exit 128 (SHA not in submodule DB after fetch) → BLOCK + "submodule fetch incomplete, retry" hintPerformance budget:
Race condition 处理 (per backend-architect R3 missing scenario):
origin/master during gate execution: refspec assertion (Step 2) compares BEFORE/AFTER rev-parseTripwire (mechanical detection of (B+) gate misses):
.forgejo/workflows/submodule-gate-tripwire.yml in 10CG/Aria main repo (NOT aria/cron/ in aria-plugin)metrics/submodule-gate-misses.jsonl + file Forgejo issue with label gate-tripwire-counton: workflow_dispatch only; tripwire periodic execution migrated to host-cron (0 4 * * 0, v1.41.0 R-fix-2 — Actions runner 无 forgejo 凭据 + CF Access 墙; standalone scripts/submodule-tripwire-audit.sh). v1.49.0 block-flip 依赖 host-cron tripwire (4 clean runs) 作独立兜底, 非 workflow cronHelper 实现: ${ARIA_PLUGIN_ROOT:-aria}/skills/phase-c-integrator/scripts/submodule_gate.sh (Bash, stdlib + git only)
Cross-references:
openspec/changes/aria-submodule-pointer-regression-gate/proposal.md.aria/decisions/2026-05-24-aria-124-submodule-pointer-regression-gate.mdstandards/conventions/submodule-pointer-hygiene.md (zero-code companion, NOT numbered Rule)6fea5d7 + fast-forward fix a8e0096触发条件:
phase_c_integrator.multi_remote_push.enabled: true (默认)与 branch-manager 边界 (不重叠):
| Skill | 职责 | Remote 范围 |
|---|---|---|
| branch-manager (C.2 PR 发起前) | 推送 feature 分支 + 创建 PR | 仅 origin |
| phase-c-integrator C.2.5 (PR 合并后) | 推送 master + 多 remote SHA 验证 | 所有 enforced remote |
执行流程:
expected_sha = git rev-parse HEAD (合并后本地 master HEAD)git submodule status --recursiveENFORCED_REMOTES: skill 级 enforced_remotes == null 时继承顶层 multi_remote.enforced_remotes, 空则自动发现所有 remotegit-remote-helper.push_all_remotes(SUBMODULE.path, SUBMODULE.branch, [REMOTE])git -C <path> push <remote> <branch>)失败优先级 (决策表):
| 条件 | 行为 |
|---|---|
remote ∈ read_only_remotes | warning 降级, 继续 (最高优先级) |
fail_on_partial_push: false + 非 read_only | warning, 继续 |
fail_on_partial_push: true + 非 read_only (默认) | 阻断, 输出修复命令 |
Per-Remote Matrix 示例:
origin: sub1 ✅ sub2 ✅ main ✅ (已推)
github: sub1 ✅ sub2 ❌ (network timeout) → 跳过 main github; 但 origin 已完成
子模块 detached HEAD: 沿用 helper canonical (detached_head: true + HEAD SHA 比较), 警告但不阻断。
降级策略: 检测 test -f "${ARIA_PLUGIN_ROOT:-aria}/skills/git-remote-helper/SKILL.md" 存在性 (路径相对项目根; ARIA_PLUGIN_ROOT 环境变量优先)。不可用时用内联降级 (不重试, 简化实现), schema 仍一致。
Race condition 处理: verify 4 次 attempt 全部 match=false 默认阻断, 记录 "possible race condition"。
新增于 v1.16.0 — 修复 Forgejo #22 "multi-PR cycle UPM 信息盲区"问题。 源于 M1 closeout (2026-04-23) single-D.1 一次性更新 85 tasks 的实际痛点
- silknode US-074 multi-PR migration 场景。
触发条件:
upm.milestone_driven: trueUS-XXX 模式关联识别逻辑:
# 1. 从 commit message 中提取 US 编号
# 示例: "feat(m1): T4 complete — DEMO-001 E2E SUCCESS" 含 US-021 前缀
US_REF=$(git log -1 --format="%s %b" | grep -oE 'US-[0-9]+' | head -1)
# 2. 如果 commit message 无 US-XXX,尝试从 spec change_id 推断
if [ -z "$US_REF" ] && [ -n "$SPEC_CHANGE_ID" ]; then
US_REF=$(grep -r "$SPEC_CHANGE_ID" openspec/changes/ \
--include="proposal.md" -l | \
xargs grep -oE 'US-[0-9]+' | head -1)
fi
执行动作:
# 获取当前 commit 信息
COMMIT_SHA=$(git rev-parse --short HEAD)
COMMIT_DATE=$(date +%Y-%m-%d)
COMMIT_TITLE=$(git log -1 --format="%s")
PR_URL="${PR_URL:-}" # 来自 C.2 输出,无则留空
# 构造 sub-bullet
if [ -n "$PR_URL" ]; then
SUB_BULLET=" - ${COMMIT_DATE}: ${COMMIT_SHA} — ${COMMIT_TITLE} (${PR_URL})"
else
SUB_BULLET=" - ${COMMIT_DATE}: ${COMMIT_SHA} — ${COMMIT_TITLE}"
fi
# 定位 UPM 文档中对应 US 行并追加 sub-bullet
UPM_FILE=$(find . -name "unified-progress-management.md" \
-not -path "*/archive/*" | head -1)
if [ -n "$UPM_FILE" ] && [ -n "$US_REF" ]; then
# 将 [ ] IN_PROGRESS 更新为 [~] IN_PROGRESS (如当前状态为 [ ])
sed -i "s/\[ \] \(.*${US_REF}.*\)/[~] \1/" "$UPM_FILE"
# 在 US 行下方追加 sub-bullet
sed -i "/.*${US_REF}.*/a\\${SUB_BULLET}" "$UPM_FILE"
fi
状态标记约定:
| 标记 | 含义 | 触发时机 |
|---|---|---|
[ ] | 未开始 / IN_PROGRESS (原有) | 初始状态 |
[~] | 进行中,有中间进度记录 | C.2.6 首次追加时自动升级 |
[x] | COMPLETED | D.1 final pass 写入 |
sub-bullet 格式示例:
- [~] US-021: M1 MVP Layer 2 实现
- 2026-04-20: abc1234 — feat(m1): T1 infra complete (https://forgejo.../pulls/18)
- 2026-04-22: def5678 — feat(m1): T3 orchestrator ready (https://forgejo.../pulls/19)
- 2026-04-23: ghi9012 — test(m1): T5 DEMO E2E complete (https://forgejo.../pulls/20)
DoD:
upm.milestone_driven=true 时: UPM 文档对应 Story 行下出现 sub-bullet,状态从 [ ] 升级为 [~]upm.milestone_driven=false (默认) 时: Skill 无行为变化,完全向后兼容配置示例 (.aria/config.json):
upm:
milestone_driven: false # 默认 false,保留 D.1-only 现有行为
# 设为 true 启用 C.2.6 中间进度追加
success: true
steps_executed: [C.1, C.2]
steps_skipped: []
results:
C.1:
commit_sha: "abc1234"
commit_message: "feat(auth): 添加用户认证..."
C.2:
pr_url: "https://..."
pr_number: 123
context_for_next:
commit_sha: "abc1234"
pr_url: "https://..."
当本 cycle 走 emergency_hotfix lane (state-scanner emergency_hotfix 规则触发, hotfix/* 分支) 时, C.2 的 pre_merge audit 调用点 仅 audit.enabled=true 且 audit.checkpoints.pre_merge != "off" 时, 把 audit mode 降级到 convergence (不 challenge) —— prod 紧急修复不必跑 15-30min challenge ceremony。
C.2 合并前若会话已很长 (多 cycle 累积), 用 aria-context-monitor 判断"本 cycle 收尾后是否该暂停换会话", 避免 pre-merge gate 等待期硬撞 context 上限丢上下文:
python3 "${CLAUDE_PLUGIN_ROOT:-aria}/skills/aria-token-telemetry/scripts/token_telemetry.py" --project-root .
used_percentage (relay 路径) >85% → 建议 merge 完成后即暂停 + 写 handoff。advisory, 不自动中断。详见 phase-b-developer 同名章节。
会话收尾触发 (session-closer TASK-007): merge 完成后调 closeout_trigger —— 占用 ≥ 阈值 + 有未交接成果时 advise /session-closer(advisory, 不自动执行)。契约 (I-1): 喂 token_telemetry.py 的输出 (含 source), 非 relay cache 原始文件 (先 token_telemetry.py > $TEL 再 closeout_trigger.py --telemetry-json $TEL, 详见 phase-b-developer 同名章节)。
| 条件 | 跳过步骤 | 检测方法 |
|---|---|---|
| 无变更 | C.1 | git status --porcelain 为空 |
| 不需要 PR | C.2 | 配置或分支策略 |
| 直接推送 | C.2 | 在 develop 分支 |
skip_evaluation:
C.1:
- check: git status --porcelain
skip_if: empty
reason: "没有需要提交的变更"
C.2:
- check: branch_name
skip_if: in [develop, main]
reason: "主分支不需要 PR"
- check: config.create_pr
skip_if: false
reason: "配置为不创建 PR"
╔══════════════════════════════════════════════════════════════╗
║ PHASE C - INTEGRATION ║
╚══════════════════════════════════════════════════════════════╝
📋 执行计划
───────────────────────────────────────────────────────────────
C.1 commit-msg-generator → Git 提交
C.2 branch-manager → 创建 PR
🚀 执行中...
───────────────────────────────────────────────────────────────
✅ C.1 完成 → Commit: abc1234
Message: feat(auth): 添加用户认证 / Add user authentication
✅ C.2 完成 → PR #123 已创建
URL: https://github.com/...
📤 上下文输出
───────────────────────────────────────────────────────────────
commit: abc1234
pr: #123
ready_for: Phase D (可选)
输入:
context:
branch_name: "feature/add-auth"
test_results: { passed: true }
执行:
C.1: 提交代码 → abc1234
C.2: 创建 PR → #123
输出:
commit_sha: "abc1234"
pr_url: "https://..."
输入:
config:
create_pr: false
执行:
C.1: 提交代码
C.2: 跳过 (不需要 PR)
输出:
steps_skipped: [C.2]
commit_sha: "abc1234"
输入:
context:
branch_name: "develop" # 在主分支
执行:
C.1: 提交代码
C.2: 跳过 (主分支不需要 PR)
额外: git push
输出:
commit_sha: "abc1234"
pushed: true
feat(auth): 添加用户认证 / Add user authentication
- 实现 JWT token 验证
- 添加登录 API 端点
🤖 Executed-By: mobile-developer subagent
📋 Context: Phase4-Cycle9 功能开发
🔗 Module: mobile
| 标记 | 来源 |
|---|---|
| 🤖 Executed-By | 执行的 Agent 类型 |
| 📋 Context | Phase/Cycle + 任务描述 |
| 🔗 Module | 活跃模块名 |
| 错误 | 原因 | 处理 |
|---|---|---|
| 提交失败 | hook 拒绝 | 显示 hook 错误,提示修复 |
| PR 创建失败 | 权限问题 | 提示检查权限 |
| 推送失败 | 远程冲突 | 提示拉取最新代码 |
on_commit_hook_failure:
action: stop
report:
- Hook 错误信息
- 缺少的标记或格式问题
next_step: "使用 commit-msg-generator 重新生成消息"
新增于 v1.1.0 - 集成 branch-finisher 完成流程
completion_option_handling:
"[1] 提交并创建 PR":
action: 执行完整 Phase C
steps: [C.1, C.2]
worktree_cleanup: 在 PR 创建后询问
"[2] 继续修改":
action: 跳过 Phase C
steps: []
reason: "用户选择继续修改,不进入集成阶段"
"[3] 放弃变更":
action: 跳过 Phase C
steps: []
reason: "变更已放弃,无需集成"
worktree_cleanup: 强制执行
"[4] 暂停保存":
action: 跳过 Phase C
steps: []
reason: "用户选择暂停,稍后恢复"
pre_check:
# 检查 branch-finisher 输出
completion_option:
required: true
valid_for_phase_c: [1] # 只有选项 1 进入 Phase C
# 检查测试验证结果
validation_report:
required: true
must_pass: true
warn_on: warnings > 0
# 检查 Worktree 状态
worktree_path:
check: if exists
action: 记录,用于后续清理
enhanced_flow:
1. 接收 branch-finisher 输出
├── completion_option
├── validation_report
└── worktree_path (可选)
2. 前置检查
├── 验证 completion_option == 1
├── 验证 validation_report.passed
└── 记录 worktree_path
3. 执行 C.1 (提交)
├── 使用 commit-msg-generator
├── 包含增强标记
└── 关联 task_id
4. 执行 C.2 (PR)
├── 使用 branch-manager
├── 创建 PR
└── 包含测试验证结果
5. Worktree 清理决策
├── PR 创建成功?
├── 询问用户是否清理
└── 执行清理或保留
worktree_cleanup_timing:
trigger: PR 创建成功后
default: 询问用户
options:
- "[1] 立即清理 (推荐)"
- "[2] 保留 worktree"
auto_cleanup_if:
- PR merged
- PR closed
context_for_next:
# 原有字段
commit_sha: "abc1234"
pr_url: "https://..."
pr_number: 123
# v1.1.0 新增字段
completion_option: 1
worktree_status: "cleaned" | "preserved"
validation_summary:
passed: true
warnings: 1
phase-b-developer
│
│ context:
│ - branch_name
│ - test_results
▼
branch-finisher (v1.1.0 新增)
│
│ context:
│ - completion_option
│ - validation_report
│ - worktree_path
▼
phase-c-integrator (本 Skill)
│
│ context_for_next:
│ - commit_sha
│ - pr_url
│ - worktree_status
▼
phase-d-closer
最后更新: 2026-03-27 Skill版本: 1.2.0