بنقرة واحدة
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