Imported from laionazeredo/che-ai (
skills/che-ship/SKILL.md). Install upstream withnpx skills add laionazeredo/che-ai --skill che-ship. Copyright stays with the author.
Che — Ship (commit + push + open PR)
SHARED REFERENCES (CANONICAL — NÃO DUPLICAR corpo aqui):
- Conventional Commits full types + regex + examples: engineering-contracts skill Appendix B
- GitHub CLI gh auth + push + create PR commands:
_shared_checklists/GITHUB_CLI_COMMON.md- gh-stack hierarchical PR workflow (multi-PR partial deliveries): engineering-contracts Appendix C
- Light pre-ship security check:
_shared_checklists/SECURITY_PII_COMMON.md(secrets leak, PII log scan)- QA run order local verification:
_shared_checklists/NX_PNPM_COMMON.md
This skill handles the end-of-development workflow for a worktree. It runs ONLY after the user says "I believe everything is OK" and is prepared to commit.
0. Preconditions — Non-negotiable (FAIL if any missing)
- Worktree confirmed. Absolute path provided. If not — block.
ghCLI is available and authenticated. Rungh auth statussilently. If not authenticated → guide user togh auth loginand stop.- Worktree has uncommitted changes OR new commits ready to push.
git statusis not clean OR branch is behind/ahead. - No uncommitted
.env/ secret files being committed. - (If the user ran via che) all tasks are marked DONE in
task_graph.md. Compliance + scope + review gates are EXECUTABLE CODE in §0.9.1→§0.9.4 and will run NOW before any git operation; §0.5 item 5 legacy-text compliance requirement is replaced entirely by gate §0.9.3 execution. If user explicitly passed--skip-gates(override flag): log EXPLICIT_OVERRIDE entry to decision.log with user verbatim justification, SKIP all 4 gates, jump directly to §1 Git Housekeeping. No other bypass path exists.
If any precondition fails → report exactly which, stop execution, ask user.
0.6 gh-stack mode detection (N4 hierarchical PR stack)
- Check if file exists:
$CHE_WORKSPACE_SHARED/gh_stack_plan.md(viasource "${CHE_HOME:-$HOME/.trae}/contracts/che_sessions_contract.sh"). - If it exists:
- Read it. Validate it has a field
Status: APPROVEDat the top. - Check
ghextension installed: rungh extension list 2>/dev/null | grep -i "stack"silently. - If gh-stack extension NOT installed → offer
gh extension install https://github.com/github/gh-stackto user; wait for confirmation, install, then continue. If user declines → FALLBACK to single-PR mode (Steps 2–5 normal path). - Parse layers table bottom-up (first layer = lowest in the stack, merged first; last layer = top of stack). Extract per layer:
Layer ID,Branch Name(slug likePROJ-123-l1-refund-pipeline),Scope (files),Depends on. - Set boolean:
GH_STACK_MODE=true. RecordLAYERS[]array ordered bottom-up.
- Read it. Validate it has a field
- If file NOT exists OR status ≠ APPROVED →
GH_STACK_MODE=false. Proceed with standard single-PR path (Steps 2–5 current).
0.7 WORKTREE SESSION BINDING PREFLIGHT (engineering-contracts §19, NON-NEGOTIABLE)
Run BEFORE any git status / git add / git commit / git push. PREVENTS wrong-worktree commits.
- Level 1 Global Index (AUTHORITY): Read
che_registry_path. Find LAST STATUS=BOUND entry using the effective session id fromche_current_session_id. Extract WORKTREE_ROOT from that entry.- If NO entry: SHIP BLOCKED NOW. Ask "No Level1 binding for this session. Create before ship? (A = Select worktree; B = Cancel ship)." NEVER ship unbound.
- If found BOUND entry: confirm WORKTREE_ROOT from registry MUST EQUAL WORKTREE_ROOT precondition 1.
- MISMATCH → BLOCK SHIP NOW. Ask: "Level 1 GLOBAL registry binding says worktree = X, ship was invoked on Y. Which one actually ships? (A = X per binding; B = Y override binding + rebind; C = Cancel ship)." Never silent-continue.
- Level 2 Detail File (optional audit): Verify
$CHE_SESSION_DIR/binding.mdexists (viasource "${CHE_HOME:-$HOME/.trae}/contracts/che_sessions_contract.sh"). If missing → warn decision.log entry (SM skipped Level 2 write). Do NOT block ship (Level 1 is the authority). - Scissor check staging + file ops:
- EVERY file staged/committed → path MUST start with WORKTREE_ROOT from Level1 registry.
- Generated files under
$CHE_SESSIONS_ROOT/**are NEVER staged; they live outside user code by design. - File path outside WORKTREE_ROOT and not under CHE_SESSIONS_ROOT (symlinks, relative tricks, etc.) → UNSTAGE immediately, report, DO NOT commit.
- Cross-worktree safety during ship loop (gh-stack mode):
- After finishing layer's commit/push/PR, NEXT layer file ops → RE-RUN scissor check (3) against BOUND WORKTREE_ROOT registry entry.
- Never silent cd another worktree during multi-layer ship. Layer says "use worktree B" → STOP. Ask user confirm re-binding §19.3 (old entry STATUS=RELEASED append new BOUND registry entry) before switching.
0.7.1 STORAGE PREFLIGHT OBRIGATÓRIO (run IMEDIATAMENTE após §0.7, ANTES de §0.8 ou QUALQUER write de report/decision)
ANTES de gerar QUALQUER arquivo de report (gates 0.9.1→0.9.5), decision log, backup artifact: execute EXATAMENTE este comando UMA VEZ por execução de /che-ship. Garante que todos paths resolvam FORA da worktree:
python3 -m che_core.ship preflight "$WORKTREE_ROOT" "$SESSION_ID"
Exporte as variáveis impressas pelo script para usá-las nos próximos gates.
0.8 PLANNING ARTIFACTS BLACKLIST PREFLIGHT (NON-NEGOTIABLE)
Purpose: NEVER allow che internal planning/decision files to end up in user-code PRs. If any bug/legacy skill accidentally creates them inside the user worktree, detect, unstage, and DELETE them before any git add runs.
Execute o script de verificação de blacklist:
python3 -m che_core.ship blacklist_check "$WORKTREE_ROOT" "$SESSION_ID"
Se o script reportar arquivos trackeados (código de saída 2), apresente as opções (A ou B) para o usuário conforme sugerido no output.
0.9 EXECUTABLE QUALITY GATES (RUN BEFORE ANY GIT OPERATION — FAIL FAST ORDER)
CANONICAL 4-PASS ORDER (non-negotiable — fail-fast by blast radius):
- §0.9.1 Scope + Lean delivery (lowest compute cost, highest blast radius if wrong — ship de coisa errada é o pior cenário)
- §0.9.2 Code Review bugs (depende de scope estar correto; ≤2 HIGH = auto-remediate SEM ask)
- §0.9.3 Compliance security/PII (já que review e scope passaram, garantimos 0C 0H)
- §0.9.4 QA — DEFAULT ON, 3 profiles: minimal / normal / full (sem flag = profile
minimal; flag--qa=<profile>seleciona; único bypass = EXPLICIT_OVERRIDE user logado em decision.log)Qualquer GATE com status 🔴 BLOQUEIA o ship. Gates 0.9.1 e 0.9.3 NUNCA têm auto-fix. Apenas Gate 0.9.2 tem ramo auto-fix quando threshold ≤ 2 HIGH findings. Gate 0.9.4 NÃO tem flag
--no-run-qa. A única forma de bypassar é EXPLICIT_OVERRIDE user.
0.9.1 GATE 1 — che-scope-checker 6-checks (Modo B: Worktree local)
Purpose: Garantir que o que vai ser commitado (1) entrega TUDO que foi prometido no escopo e (2) não tem overengineering / gordura / YAGNI violations. Executa o skill che-scope-checker em Modo B.
Pré-condição interna deste gate:
$CHE_WORKSPACE_SHAREDresolvido viasource "${CHE_HOME:-${HARNESS_HOME:-$HOME/.trae}}/contracts/che_sessions_contract.sh".
Scope source auto-discover ordem (primeiro match ganha — NÃO cascateia múltiplos sources):
- Envelope explícito → existe
$CHE_WORKSPACE_SHARED/tasks/*/envelope.md? (último task DONE no task_graph, pega seu envelope) → SCOPE_SOURCE=ENVELOPE. - Task graph local → existe
<WORKTREE_ROOT>/task_graph.md? → SCOPE_SOURCE=TASK_GRAPH. Lê lista de Acceptance Criteria + Tasks marcadas DONE. - Spec che local/global → existe
spec_*.mdem$CHE_WORKSPACE_SHARED/spec_*.mdOR<WORKTREE_ROOT>/spec_*.md? → SCOPE_SOURCE=SPEC. Extrai Acceptance Criteria section §5. - PR body GitHub (se PR URL fornecido via flag
--pr-url) → usagh pr view <URL> --json body,title→ parseia bullet points de Acceptance Criteria. SCOPE_SOURCE=PR_BODY. - Nenhum source encontrado → ⚠️ WARN + PERGUNTA user: "Nenhum scope source localizado. (A) Informar path spec/envelope manualmente; (B) Prosseguir SEM scope validation (risco: ship fora do escopo); (C) Cancelar ship." Se usuário escolher B → log EXPLICIT_OVERRIDE no decision.log, SKIP este gate, vai para 0.9.2.
Execução:
- Invoca
che-scope-checkerskill passando:--worktree <WORKTREE_ROOT>--mode B--scope-source <SCOPE_SOURCE>--scope-path <path_do_arquivo>--report-out "$SHIP_SCOPE_CHECK_REPORT"(variável §0.7.1; prefixo timestamp UTC + report/ship-wt-/ estrutura fora worktree)
- Aguarda retorno com
verdictfield +final_scorefield +findings[](CHECK 1-6).
Verdict handling (regra EXATA do che-scope-checker §8):
| Verdict scope-checker | Ação gate 0.9.1 | Próximo passo |
|---|---|---|
| 🟢 APPROVED (score ≥7.0 AND 0 🔴 em CHECKS 1–6) | ✅ PASS GATE 1 | Segue imediatamente para §0.9.2 |
| 🟡 CONDICOES (score ≥7.0 mas tem algum action item não-bloqueante OU score 5.0–6.9) | ⏸️ PAUSE + PERGUNTA user | Print findings e action items ao user. Opções EXATAS: (A) = Aplicar fixes sugeridos e re-run gate 1; (B) = Aprovar condicionalmente (justificativa obrigatória → gravada via helper decision.log); (C) = Cancelar ship. |
| 🔴 REPROVADO (score <5.0 OU qualquer 🔴 em CHECK 1 Entrega / CHECK 4 Env / CHECK 3 Docs obrigatórios) | 🔴 BLOCK SHIP | Apresenta findings ao usuário. NÃO oferece opção de override direto (requer nova rodada). Sugere: corrigir → rodar /che-scope-checker standalone → depois re-rodar /che-ship. |
Output artifacts:
$SHIP_SCOPE_CHECK_REPORT— report completo 6-checks com SCOPE × LEAN final score. Estrutura final:$CHE_WORKSPACE_SHARED/report/ship-<wt-slug>/YYYYMMDD-HHMMSS-ship-scope-check.md(ordenado por prefixo timestamp, agrupado por worktree relacionado).- Decision log entry via helper oficial:
che_append_decision_jsonl "SHIP_GATE_0_9_1" "verdict=${verdict} score=${final_score} source=${SCOPE_SOURCE} report=${SHIP_SCOPE_CHECK_REPORT}". - NENHUM artifact é criado dentro de
<WORKTREE_ROOT>(helper assert outside já trava exit 99 se path cair lá; blacklist §0.8 garante limpeza redundante).
0.9.2 GATE 2 — che-code-review Mode B Local Worktree + THRESHOLD ≤ 2 HIGH AUTO-FIX RULE (VERBATIM USER CONTRACT)
REGRA NÃO NEGOCIÁVEL USER VERBATIM: "no caso do code review, no caso de <= 2 high findings, ja corrija e commit e prossiga com o ship sem nem me preguntar. Mas de resto, perfeito." Esta regra não tem exceções. NÃO ASKE NADA ao user no ramo ≤ 2 HIGH. Auto-remedia, commita, segue. Se CRITICAL ≥1 ou HIGH ≥3 → bloqueia e apresenta.
Purpose: Rodar o che-code-review skill em Modo B — Local Worktree (diff do worktree atual contra <DEFAULT_BRANCH> já determinado no preamble). Pos-processing do resultado com a regra do threshold ≤ 2 HIGH.
Execução Passo a Passo:
Step 2.0 — Preparação diff base:
- Re-usa o
DEFAULT_BRANCHque já será determinado em §1.2 (caso gate 2 rode antes do §1, executa só ogh repo view --json defaultBranchRefsilenciosamente). - Base diff =
origin/<DEFAULT_BRANCH>..HEAD(commits já feitos nesta branch) PLUS unstaged + uncommitted changes atuais no worktree. Ambos são reviewados. Não é só o staged.
Step 2.1 — Invocação che-code-review:
- Invoca
che-code-reviewskill com params:--worktree <WORKTREE_ROOT>--mode B--base origin/<DEFAULT_BRANCH>--report-out "$SHIP_CODE_REVIEW_REPORT"(variável §0.7.1; helper garantiu outside worktree)--include-unstaged true
- Espera resultado estruturado:
{ critical_count: N, high_count: N, medium_count: N, low_count: N, findings: [...] }- Cada finding tem:
{ severity: CRITICAL|HIGH|MEDIUM|LOW, file, line, title, suggested_fix_code_block (opcional), auto_fixable: boolean }.
- Cada finding tem:
Step 2.2 — THRESHOLD BRANCHING (core user rule — IMPLEMENTAR EXATAMENTE):
SE (critical_count === 0) AND (high_count <= 2):
→ RAMO AUTO-REMEDIATE-AND-CONTINUE (SEM PERGUNTAR NADA AO USER — NUNCA ASK AQUI)
SENÃO:
→ RAMO BLOCK-SHIP (apresenta findings ao user)
RAMO A: AUTO-REMEDIATE-AND-CONTINUE (0 CRITICAL + ≤ 2 HIGH)
Objetivo: Corrigir automaticamente os HIGH findings que são auto_fixable=true, commitar com conventional commit, e prosseguir para gate 0.9.3 sem qualquer interação com usuário.
2.A.1 — Filtrar findings HIGH auto-fixáveis:
<FIXABLE_HIGHS> = findings.filter(f => f.severity === 'HIGH' AND f.auto_fixable === true)
<UNFIXABLE_HIGHS> = findings.filter(f => f.severity === 'HIGH' AND f.auto_fixable === false)
UNFIXABLE_HIGHS(se existirem, ≤ 2 no total): ainda assim prossegue sem ask user. A regra é ≤2 HIGH totais, independente de serem fixáveis ou não. Loga WARNING no decision.log com cada finding unfixable listado. NÃO bloqueia.
2.A.2 — Aplicar fixes programaticamente:
Para cada f em <FIXABLE_HIGHS>:
- Lê o arquivo target (via Read tool, garantido latest content).
- Aplica
Edittool exatamente usandof.suggested_fix_code_blockcomonew_string, substituindo o old_string correspondente. - NÃO adiciona comentários nos edits. Mantém estilo do arquivo.
- Se algum Edit falhar (old_string não match): aborta apenas este finding específico, loga
AUTO_REMEDIATE_FAILEDno decision.log com file+line, continua com os outros. Não aborta ramo A.
2.A.3 — Commitar o remediation com conventional commit (SEM passar pelo §1 normal — commit especial):
cd "$WORKTREE_ROOT"
# 1. Re-roda o blacklist §0.8 stages 1-2 só por segurança (garante nenhum artifact entrou no diff):
# (roda os mesmos comandos do §0.8 stage 1 + 2 para unstaged)
# 2. Staga só os arquivos modificados pelos auto-fixes:
git add -- <arquivos_alterados_pelos_fixes>
# 3. Conventional commit EXATO:
N_FIXED=<total_high_fixes_applicados>
N_TOTAL_HIGH=<high_count>
git commit -m "fix(review): auto-remediate code review HIGH findings ($N_FIXED/$N_TOTAL_HIGH)
- Applied automated remediation for ≤ 2 HIGH findings per ship gate 0.9.2 rule
- Remediation source: che-code-review Mode B against origin/<DEFAULT_BRANCH>
- Unfixed HIGH (<= count) logged to decision.log as AUTO_REMEDIATE_UNFIXABLE"
2.A.4 — Pós-commit:
- Decision log entry via helper oficial:
che_append_decision_jsonl "SHIP_GATE_0_9_2" "verdict=AUTO_REMEDIATED_PASSED critical=0 high=${N_TOTAL_HIGH} auto_applied=${N_FIXED} auto_failed=${Y} report=${SHIP_CODE_REVIEW_REPORT}" - SEGUIR IMEDIATAMENTE PARA GATE §0.9.3. NÃO VOLTA para §1 Git Housekeeping normal. O commit especial já foi feito. O §1 normal irá rodar e contabilizar apenas os changes que sobraram (se houver).
RAMO B: BLOCK SHIP (CRITICAL ≥ 1 OU HIGH ≥ 3)
Regra: Apresenta findings detalhados ao user e pede input. NÃO há auto-fix neste ramo.
Opções EXATAS ao user:
🔴 SHIP GATE 0.9.2 CODE REVIEW BLOCKED
Summary: <critical_count> CRITICAL · <high_count> HIGH · <medium_count> MEDIUM · <low_count> LOW
(Top findings first — print só CRITICAL + HIGH ao user; medium/low vão pro report só)
Options:
A = Quero aplicar os fixes MANUALMENTE agora. Pausa o ship, volta interactive shell.
(Depois de user arrumar, ele roda /che-ship de novo)
B = Rejeitar findings específicos + override. Preciso: justificativa obrigatória por cada
finding a ser overrideado (grava decision.log).
C = Cancelar ship.
Se user escolher B (override):
- Cada finding overrideado requer justificativa texto livre.
- Todas salvas no decision.log como entries
REVIEW_OVERRIDE {finding_id, justification}. - Muda gate verdict para PASSED_WITH_OVERRIDES.
- SÓ PODE FAZER OVERRIDE ATÉ 2 HIGH no total. Se HIGH ≥3 → opção B fica desabilitada.
- NUNCA PERMITE OVERRIDE DE CRITICAL — opção B desabilitada se critical_count > 0.
Output artifacts gate 0.9.2:
$SHIP_CODE_REVIEW_REPORT— report completo findings. Estrutura final:$CHE_WORKSPACE_SHARED/report/ship-<wt-slug>/YYYYMMDD-HHMMSS-ship-code-review.md(ordenado, agrupado).- Decision log entries via
che_append_decision_jsonlhelper conforme ramo A ou B. - Ramo B: Se OVERRIDE, cada finding overrideado usa:
che_append_decision_jsonl "REVIEW_OVERRIDE" "finding_id=${id} justification=${text}". - NO ramo A tem 1 commit novo no worktree prefixado
fix(review): auto-remediate....
0.9.3 GATE 3 — che-compliance HEAVY FULL SCAN (Step 2 Pesado, não só diff)
Purpose: Garantir 0 CRITICAL + 0 HIGH findings no REPO INTEIRO, não só no diff. Executa o skill che-compliance em sua versão PESADA Step 2 (full-session scan, não diff-only). Esta é a regra de compliance antiga §0.5, agora virada código executável.
Execução:
- Invoca
che-complianceskill com params:--worktree <WORKTREE_ROOT>--mode HEAVY_STEP_2_FULL_SCAN--report-out "$SHIP_COMPLIANCE_HEAVY_REPORT"(variável §0.7.1; helper garantiu outside worktree)--required 0_CRITICAL_AND_0_HIGH
- Espera resultado:
{ critical_count: N, high_count: N, scan_categories_ran: [1..15] }
Verdict handling:
| Cenário | Ação |
|---|---|
critical_count === 0 AND high_count === 0 |
✅ PASS GATE 3. Segue para 0.9.4. |
Qualquer critical_count > 0 OU high_count > 0 |
🔴 BLOCK SHIP — NÃO HÁ OPÇÃO DE OVERRIDE DIRETO. Apresenta lista CRITICAL + HIGH ao user com paths e linhas. Opções: (A) Corrigir manualmente e re-run /che-ship; (B) Rodar che-compliance standalone primeiro para ter output verbose, depois voltar. |
Compliance categories guaranteed to run (canônicas do skill che-compliance Step 2 Pesado):
- Categoria 1: Secrets leak (hardcoded API keys sk-*, AWS, JWT em texto)
- Categoria 2: PII exposure (log/return de email bruto, CPF, dados sensíveis)
- Categoria 3: SQL injection patterns (string concat em SQL, sem parametrização)
- Categoria 4: Auth / RLS bypass patterns
- Categoria 5: Dangerous URLs (SSRF, open redirect)
- Categorias 6-15: restantes do che-compliance skill.
Output artifacts:
$SHIP_COMPLIANCE_HEAVY_REPORT— full scan report. Estrutura final:$CHE_WORKSPACE_SHARED/report/ship-<wt-slug>/YYYYMMDD-HHMMSS-ship-compliance-heavy.md(ordenado, agrupado).- Decision log entry via helper oficial:
che_append_decision_jsonl "SHIP_GATE_0_9_3" "verdict=${verdict} critical=${critical_count} high=${high_count} categories=${#scan_categories_ran} report=${SHIP_COMPLIANCE_HEAVY_REPORT}".
0.9.4 GATE 4 — QA Gate (DEFAULT ON — profile minimal se nenhuma flag passada)
Purpose: Última linha de defesa antes do commit real. LIGADO POR DEFAULT — SEMPRE roda, a menos que user passe EXPLICIT_OVERRIDE justificado. 3 profiles de velocidade/abrangência. NÃO existe mais flag --no-run-qa.
Profile resolution (non-negotiable precedence):
- User passou
--skip-qano comando → REQUIRE EXPLICIT_OVERRIDE verbatim do user gravado em decisions.log. Sem override escrito → BLOCK SHIP NOW, pergunte user justificativa. - User passou
--qa=full→ PROFILE_FULL (tudo, ~5-15min) - User passou
--qa=normal→ PROFILE_NORMAL (affected typecheck+lint+test, ~1-3min) - DEFAULT (nenhuma flag QA) → PROFILE_MINIMAL (só testes unit/integ afetados, ~30s-2min)
Quando skipado (SÓ caminho 1):
- Se
--skip-qapresente AND EXPLICIT_OVERRIDEQA_SKIPgravado viache_append_decision_jsonl "SHIP_GATE_0_9_4_OVERRIDE" "verbatim=<user justification>"→ SKIP, segue §1. - QUALQUER OUTRO caminho de skip (sem override logado) → BLOQUEIA SHIP.
Profile specs (execução stack-detect):
Detecta stack do monorepo automaticamente (ordem de tentativa):
-
Nx workspace (pnpm + nx) → existe
nx.json+pnpm-workspace.yaml:Profile Command chain Target duration 🟢 MINIMAL (default) cd "$WORKTREE_ROOT" && corepack pnpm nx affected:test --tui false --exclude=e2e 2>&1(só testes unit/integ AFETADOS pelos arquivos dirty — SEM typecheck, SEM lint, SEM playwright/e2e)~30s-2min monorepo 🟡 NORMAL (--qa=normal) cd "$WORKTREE_ROOT" && { echo "===== QA GATE NORMAL: typecheck $(date -Iseconds) ====="; corepack pnpm nx affected:typecheck --tui false 2>&1; echo "===== QA GATE NORMAL: lint $(date -Iseconds) ====="; corepack pnpm nx affected:lint --tui false 2>&1; echo "===== QA GATE NORMAL: test $(date -Iseconds) ====="; corepack pnpm nx affected:test --tui false --exclude=e2e 2>&1; }— affected: typecheck + lint + unit/integ tests~1-3min monorepo 🔴 FULL (--qa=full) cd "$WORKTREE_ROOT" && { echo "===== QA GATE FULL: typecheck $(date -Iseconds) ====="; corepack pnpm nx run-many --target=typecheck --tui false 2>&1; echo "===== QA GATE FULL: lint $(date -Iseconds) ====="; corepack pnpm nx run-many --target=lint --tui false 2>&1; echo "===== QA GATE FULL: unit+integ tests $(date -Iseconds) ====="; corepack pnpm nx run-many --target=test --tui false 2>&1; echo "===== QA GATE FULL: E2E tests $(date -Iseconds) ====="; corepack pnpm nx run-many --target=e2e --tui false 2>&1; }— all: typecheck+lint+unit+integ+e2e+playwright~5-15min monorepo Toda output de qualquer profile é gravada via pipe: ` che_write_file_atomic "$SHIP_QA_GATE_LOG"` -
Generic pnpm/npm/yarn (sem Nx) → existe
package.json:- MINIMAL: heuristic find matching test files:
grepdiff paths → run only*.test.*/*.spec.*files matching changed file dirs viacorepack pnpm vitest run <matched_paths>(sem typecheck, sem lint) - NORMAL:
{ echo typecheck; corepack pnpm typecheck 2>&1; echo lint; corepack pnpm lint 2>&1; echo test; corepack pnpm test 2>&1; } - FULL: tudo NORMAL +
corepack pnpm test:e2e 2>&1(se script existir; senão WARN e pula)
- MINIMAL: heuristic find matching test files:
-
Nenhuma detecção → WARN "Não foi possível detectar stack QA. MINIMAL fallback: tenta rodar comando de teste documentado em AGENTS.md. Se não houver → WARN + SKIP gate com decision.log entry SKIPPED_STACK_NOT_DETECTED".
Verdict handling QA:
- MINIMAL profile: only test command — exit code 0 → ✅ PASS. exit code != 0 → 🔴 BLOCK SHIP.
- NORMAL profile: exit code 0 EM TODOS os 3 (typecheck + lint + test) → ✅ PASS. Qualquer falha → 🔴 BLOCK.
- FULL profile: exit code 0 EM TODOS → ✅ PASS. Qualquer falha → 🔴 BLOCK.
- Em qualquer BLOCK (0.9.4): Print tail -80 da saída com erro ao user. Opções EXATAS:
- (A) Quero corrigir manualmente agora → pausa ship, volta interactive shell (depois user re-roda /che-ship).
- (B) Override (REQUIRE EXPLICIT_OVERRIDE user texto literal justificando POR QUE typecheck/lint/teste com falha DEVE SHIPAR agora — gravado em decision.log; override só permitido se (i) o count de failures for ≤2 testes FLAKY conhecidos E (ii) a justificativa cita uma issue/ticket).
Output artifacts:
$SHIP_QA_GATE_LOG— stdout concatenado do profile selecionado. Estrutura final:$CHE_WORKSPACE_SHARED/report/ship-<wt-slug>/YYYYMMDD-HHMMSS-ship-qa-gate.log(timestamp ordenável, agrupado). Write atômico viache_write_file_atomicstdin pipe.- Decision log entry via helper:
che_append_decision_jsonl "SHIP_GATE_0_9_4" "verdict=${verdict} profile=${MINIMAL|NORMAL|FULL} tc_status=${status} lint_status=${status} test_status=${status} e2e_status=${status|N/A} override_logged=${yes|no} log=${SHIP_QA_GATE_LOG} evidence_manifest_sha256=${QA_EVIDENCE_MANIFEST_SHA:-N/A} evidence_workspace_path=${QA_EVIDENCE_MANIFEST_PATH:-N/A}".
0.9.5 GATE 5 (NOVO Three-Layer Domains v2) — DOMAIN GATES Obrigatórios por Domínio Não-Engineering
Ordem de precedência resolve effective_domain (STOP at first non-null match): (1) SPEC frontmatter
domain:field → (2) Project Level 1.5 registrydomains[0]array first entry → (3) DEFAULT FALLBACKengineering.
Purpose: Mesmo fail-fast engine G1-G4 generalizado para QUALQUER domínio (ux/product/devops/copywriting/social/seo-analytics) usando thresholds numéricos, retry 1 grátis automático, e HUMAN REQUIRED após 2nd falha. Igual padrão engineering-contracts §6 DbC + §15 BDD incremental. Nenhum "gosto" ou avaliação subjetiva permitida — tudo threshold NUMÉRICO.
Execution steps (ordem fixa):
- Resolve
effective_domain: Ler SPEC (mesmo path do gate 0.9.1 scope) YAMLdomain:+ fallback project registrydomains[]. Se ambos null/ausentes →effective_domain = engineering. - **IF
effective_domain === 'engineering'→ SKIP GATE 5 COMPLETAMENTE E SILENCIOSAMENTE (0 linhas log, 0 output extra). Sessões/specs antigas SEM o campodomain:têm comportamento IDÊNTICO ao v2 original. Backward compat 100% garantida. - IF
effective_domain !== 'engineering':a. Check pasta existe:${CHE_HOME:-$HOME/.trae}/domains/<effective_domain>/gates/→ MUST existir. Não existe → WARN "Domínio não tem gates implementados ainda (fase 2 rollout). Skip §0.9.5." Log decision entry helper:
Prossegue §0.9.6 ALL GATES PASSED normalmente. b. Glob + sort alphabetical gate files:che_append_decision_jsonl "DOMAIN-GATES-WARN" "domain=${effective_domain} reason=no-gates-folder phase-2-rollout skip=TRUE"${CHE_HOME:-$HOME/.trae}/domains/<effective_domain>/gates/*.md. Ordem de execução = ordem alfabética nome arquivo (igual convenção G1→G2→G3→G4). Exemplo UX:accessibility-gate.mdexecuta ANTESpixel-check-gate.md. c. Para CADA arquivo gate (0.9.5.1, 0.9.5.2, ...):- Parse YAML frontmatter do arquivo:
threshold_pass,retry_policy,log_format_decisions,tool_official. - Se frontmatter ausente → FAIL gate imediatamente: "Gate não tem frontmatter YAML threshold declarado. Domínio inválido."
- Construir path report POR gate usando helper (um arquivo JSON por gate, ordenado, agrupado):
GATE_BASENAME="$(basename "$gate_file" .md)" DOMAIN_GATE_REPORT="$(che_output_path "${SHIP_DOMAIN_GATE_REPORT_TEMPLATE_TYPE}" "domain-gate-${effective_domain}-${GATE_BASENAME}" "${RELATED_ID}" "${SHIP_DOMAIN_GATE_REPORT_TEMPLATE_SCOPE}" "json")" - Run gate evaluation (automático): Siga EXATAMENTE os passos listados no arquivo
domains/<slug>/gates/<name>.mdseção "Execução". Grave todo output do gate no report JSON viache_write_file_atomic "$DOMAIN_GATE_REPORT"(write atômico, outside worktree garantido). Se o gate usar uma ferramenta oficial via §21 External Connectors (P1 MCP ou P2 CLI): SEMPRE use os canais P1→P2 ordem; NUNCA raw curl/fetch. PASS condition: frontmatterthreshold_passsatisfeito NUMERICAMENTE (ex:score >= 8.0,critical_count === 0). Se string → FAIL.- Verdict:
Resultado gate 1ª rodada Ação 🟢 PASS threshold ✅ Passa este gate. Decision log helper: che_append_decision_jsonl "DOMAIN-GATE-EXECUTED" "domain=${effective_domain} gate=${GATE_BASENAME} status=PASS score=${score} duration_ms=${ms} report=${DOMAIN_GATE_REPORT}". Próximo gate.🔴 FAIL threshold (1ª vez) Retry GRÁTIS AUTOMÁTICO = 1 única rodada: Aplicar os passos recomendados no arquivo gate seção "Retry Policy" (ex: "corrigir top-3 desvios >4px", "corrigir alt ausentes"). Re-rodar gate 1 NOVA vez. Decision log helper para retry: che_append_decision_jsonl "DOMAIN-GATE-RETRY" "domain=${effective_domain} gate=${GATE_BASENAME} score_before=${sb} retry=1".🔴 FAIL threshold APÓS retry automático = 2ª falha HARD STOP §0.9.5 DOMAIN GATES. Não abre PR. Não commita. Não prossegue para §0.9.6. Decision log HELPER com details: che_append_decision_jsonl "DOMAIN-GATE-HARD-FAIL" "domain=${effective_domain} gate=${GATE_BASENAME} threshold=${orig} score_now=${sn} report=${DOMAIN_GATE_REPORT}". Mostre mensagem padronizada ao usuário.
che_append_decision_jsonl "DOMAIN-GATES-ALL-PASSED" "domain=${effective_domain} n_gates=${N} overrides=${QTD} duration_total_ms=${ms}". Prossegue §0.9.6. - Parse YAML frontmatter do arquivo:
- EXPLICIT_OVERRIDE rules (igual G2 code-review today): Threshold NUNCA é abaixado automaticamente pelo agente. SÓ é permitido se user digitou EXPLICITAMENTE "EXPLICIT_OVERRIDE domain= gate= old= new= reason=" LITERALMENTE no chat. Nesta condição: logar entry HELPER
che_append_decision_jsonl "EXPLICIT_OVERRIDE" "domain=${effective_domain} gate=${GATE_BASENAME} old=${OLD} new=${NEW} reason=${TEXT} trace_id=${TRACE_ID}"e marcar gate como "PASS (COM OVERRIDE)". Nenhuma outra forma de bypass existe. Não confie em "parece OK".
Output artifacts gate 0.9.5:
- 1 decision.log entry PER gate executado (PASS/FAIL/RETRY/OVERRIDE), todos via
che_append_decision_jsonlhelper oficial. - Report por gate:
$DOMAIN_GATE_REPORT(1 arquivo JSON por gate, construído dinamicamente viache_output_pathdentro loop). Estrutura final:$CHE_WORKSPACE_SHARED/report/ship-<wt-slug>/YYYYMMDD-HHMMSS-domain-gate-<dom>-<nome>.json(prefixo timestamp = ordenado; todos arquivos do mesmo ship ficam na MESMA subpastareport/ship-<wt-slug>/→ fácil buscar glob**/ship-<slug>/*).
Blacklist check: Reports ficam 100% em $CHE_WORKSPACE_SHARED/report/<related_id>/ (helper garantiu outside assert). §0.8 + §2.2 continuam garantindo que nenhum relatório/diff artifact/decisions log entra no diff do commit do usuário.
0.9.6 ALL GATES PASSED — Transition guard
Aparece somente se 0.9.1 ✅ + 0.9.2 ✅ (qualquer ramo que passou) + 0.9.3 ✅ + 0.9.4 ✅ OU SKIPPED + 0.9.5 DOMAIN ✅ OU SKIPPED (engineering default).
Print one-liner ANTES de iniciar §1 Git Housekeeping:
🟢 ALL 5 EXECUTABLE SHIP GATES PASSED (scope-checker 6-checks · code-review · compliance-heavy · qa[minimal|normal|full] · domain-gates[<slug or skipped>])
Proceeding to Git Housekeeping §1 → atomic conventional commit → push → open DRAFT PR.
Append entry FINAL via decision log helper oficial:
che_append_decision_jsonl "ALL_SHIP_GATES_PASSED" "gates=[0.9.1,0.9.2,0.9.3,0.9.4,0.9.5] scores_scope=${score} effective_domain=${effective_domain} related_id=${RELATED_ID}"
Pós-gates reminder de blacklist: Todos reports acima foram escritos EXCLUSIVAMENTE em $CHE_WORKSPACE_SHARED/report/${RELATED_ID}/YYYYMMDD-HHMMSS-*.{md,log,json} (helper centralizado construiu todos paths). O §0.8 blacklist stage 1-2 já rodou e continuará rodando em §2.2 antes de cada commit para garantir que NENHUM desses reports ou decision artifacts entram acidentalmente no diff do usuário.
1. STEP 1 — Git Housekeeping (inside WORKTREE_ROOT)
1.1 Git sanitization check (secret scan pre-commit, extra)
Run a quick grep BEFORE staging anything (use che-compliance skill Category 1 + 2 patterns on the DIFF against default branch). If any matches → block, report, offer to unstage / remove the problematic file, do NOT proceed.
1.2 Determine the following
Run these one by one and record results:
- Current branch:
git branch --show-current→<BRANCH_NAME> - Default remote branch:
gh repo view --json defaultBranchRef --jq .defaultBranchRef.name→ usuallymainormaster. Call it<DEFAULT_BRANCH>. - Remote tracking branch exists?:
git ls-remote --heads origin <BRANCH_NAME>→ empty = does not exist yet; we'll create on push. - Staged vs unstaged files: list both
1.3 Worktree path absolute guard
If any git command runs and it turns out the current directory is NOT the provided worktree root → fail immediately, do not run any commit/push against wrong directory.
2. STEP 2 — Build atomic conventional commits
This is the user's requested default: conventional commits + atomic.
2.1 Generate proposed commit plan
Look at the diff. git diff --name-only <DEFAULT_BRANCH>...HEAD (or vs staged).
BLACKLIST FILTER — ALWAYS run BEFORE grouping:
From the diff-name-only output, REMOVE all files matching the patterns in §0.8 BLACKLIST (.trae/**, decisions.log*, decision.log*, task_graph.md, manual_test_plan.md, final_summary.md, execution_batches.md, batch_execution_report.md, merge_audit.*, scope-report.*, scope_check_report.*, spec_*.md, gh_stack_plan.md, session.md, envelope.md, task_envelope.md, graphify-out/**, *review-report.md).
- If any of those files appear in the diff → §0.8 preflight SHOULD have cleaned them already. If still present → DO NOT ADD TO ANY COMMIT. Skip silently and add 1 note at the bottom of the commit plan: "Note: N planning-artifact files auto-skipped (never committed)."
Group the remaining (filtered) changes into atomic, logical commits:
- feat(scope): new functionality, new endpoints, new UI components
- fix(scope): bug fixes — include "Fixes #TICKET" if applicable
- refactor(scope): code move, rename, no behavior change
- test(scope): spec files, e2e, fixtures only
- docs(scope): markdown, README, docstrings, no runtime
- chore(scope): deps bump, config, CI file changes, migrations
- perf(scope): perf improvements with measurable impact
- build(scope): build scripts, nx config, package.json
- style(scope): Biome/format, indentation, CSS-only cosmetic
- ci(scope): GitHub Actions, workflows
- revert(scope): reverts prior commit
Rule for grouping:
- If a change can stand alone (migration separate from runtime code that uses it) → separate commits.
- Tests for a feature go WITH the feature commit, not in separate, unless the feature is already merged.
- Migrations: usually
chore(db): add migration for Xseparate commit. - Max 15 commits per ship. If > 15 → offer user option to squash into fewer + plan, or proceed with 15+.
Present commit plan to the user as a numbered list, in order of application. Add the "N planning artifacts skipped" note at the bottom if applicable.
Wait for explicit user APPROVAL before running any git commit.
2.2 Execution — apply the commits (AFTER USER APPROVES plan)
Run each commit:
# BEFORE every commit: unstage ANY blacklisted files that somehow re-entered the index.
git reset HEAD -- \
.trae decisions.log.jsonl decisions.log.md decisions.log \
decision.log.jsonl decision.log.md decision.log \
task_graph.md manual_test_plan.md final_summary.md \
execution_batches.md batch_execution_report.md \
merge_audit.md merge_audit.jsonl \
scope-report.md scope-report.json scope_check_report.md scope_check_report.json \
spec_*.md gh_stack_plan.md session.md envelope.md task_envelope.md \
graphify-out che-review-report.md che-compliance-report.md flockr-review-report.md \
2>/dev/null || true
git add <files for this commit>
git commit -m "type(scope): imperative description in English, lowercase, max 72 chars"
Rules:
- NEVER run
git add .— always add per-file or per-directory explicitly. - Before EVERY
git add, run thegit reset HEAD -- <blacklist patterns>line above. (Fail-closed — cost 1 ms per commit, prevents a whole class of PR-pollution bugs.) - Every commit message in ENGLISH, strict conventional commit.
- After last commit → run
git log --oneline -20to present final chain to user. - POST-COMMIT ASSERT (after all commits applied):
git show --name-only --pretty=format: HEAD~10..HEAD→ scan file names for §0.8 blacklist patterns. If any commit contains a blacklisted file → STOP, DO NOT PUSH. Report to user, offergit reset HEAD~N+ re-apply cleanly, then continue.
2.3 GH_STACK_MODE=true — Group commits PER LAYER (bottom-up)
ONLY run when GH_STACK_MODE=true. Overrides 2.1/2.2 default flat plan; standard flat commits become per-layer grouped commits.
For each layer L[i] in LAYERS[] (bottom-up order, starting with the lowest stack layer):
- Checkout / create layer branch:
git checkout -b <L[i].BranchName> # if branch doesn't exist locally yet # or: git checkout <L[i].BranchName> # if already exists - Cherry-pick OR stage only files in layer scope:
- Strategy A (preferred when commit plan already aligns): cherry-pick only the commits relevant to this layer onto this branch from the consolidated work branch.
- Strategy B (simpler fallback — use when scope-per-layer is clearly file-based): from worktree state, FIRST run
git reset HEAD -- <blacklist patterns>(same as §2.2) thengit add <only files matching L[i].Scope (files)>, then create 1 or more conventional commits scoped EXCLUSIVELY to this layer (no cross-layer files in same commit).
- Present plan of "branch → commits → scope" to user as numbered list. Wait for explicit user APPROVAL before applying any layer commit.
- After user approves: apply commits per layer. Record per-layer: final commit SHAs.
- After all layers done: present to user summary "Layers bottom-up (N layers): L1 → 2 commits; L2 → 3 commits; L3 → 1 commit" etc.
Rule invariant for GH_STACK_MODE commits:
- Every file in a given layer's commit MUST be listed in L[i].Scope (files). If a file belongs to layer L[i+1] it MUST NOT appear in commits of L[i]. Any cross-layer file → block, ask user which layer gets it.
- Additional GH-stack invariant: Zero files from §0.8 BLACKLIST allowed in ANY layer's commit. If after building layer the index contains a blacklist file →
git reset HEAD -- <file>and warn.
3. STEP 3 — Push with --no-verify
User's rule: default to --no-verify for push.
Path A: GH_STACK_MODE=false (single branch, standard)
# Case 1: remote branch does NOT exist yet
git push --no-verify --set-upstream origin <BRANCH_NAME>
# Case 2: remote branch already exists (ahead/behind)
git push --no-verify
Wait for success. If push fails:
- Non-fast-forward → ask user: rebase or force push? NEVER force push without explicit confirmation.
- Auth failure → stop.
Path B: GH_STACK_MODE=true (push each layer bottom-up)
Loop layers in bottom-up order:
For each layer L[i] in LAYERS[]:
git checkout <L[i].BranchName>
# Case 1: remote branch doesn't exist
git push --no-verify --set-upstream origin <L[i].BranchName>
# Case 2: remote branch exists
git push --no-verify
Push failure rule same as Path A (per layer; block on first failure, don't continue to upper layers).
4. STEP 4 — Open DRAFT PR(s) against default branch
Common Step: 4.0 Detect Linear/Jira ticket reference (both paths)
Look in:
.trae/<task-id>/session.mdfor field "Ticket URL/ID"- Branch name pattern:
feat/PROJ-123-login,fix/PROJ-456,ticket PROJ-123anywhere in session/task_graph/envelope files - User command args:
/che-ship ticket:PROJ-123
If found ticket: extract <TICKET-ID> (full URL or just ID). Append Refs: <TICKET-ID> footer to EVERY PR body (single OR all layers in stack).
Path A: GH_STACK_MODE=false (single PR, standard)
A-4.2 Build PR Description — READABLE 5 BLOCKS (ENGLISH by default, ≤50 lines TOTAL target)
Canonical body + FILLED real EXAMPLE (refund feature from screenshot, low-context readable version):
references/PR_DESCRIPTION_TEMPLATE.md(Layer 3 SOLE owner of structure/content + readability rules). Below only process gates + budget. Copy the STYLE of the filled example in PR_DESCRIPTION_TEMPLATE.md, not only the section names. The filled example shows exactly how to phrase bullets, acronym expansion, user impact, and risk consequence.
LANGUAGE GATE (non-negotiable — #1 rule, before any writing):
- DEFAULT = ENGLISH (EN-US / EN-UK). Write the ENTIRE PR body, headings, bullets, ticket refs, commands — EVERYTHING — in English.
- Other language ONLY IF: the user's message that invoked
/che-ship(or the explicit instruction) contains an EXPLICIT request for another language (e.g., "write PR body in Portuguese", "corpo PR em PT-BR"). - Never guess / NEVER assume "user speaks Portuguese so PR in Portuguese". Portuguese is for chat ONLY. Absent an explicit mention → PR body is ALWAYS English.
PROCESS GATES (non-negotiable — readable for low-context reviewers, trim only the useless, never the clear context):
- Block 1 — What was implemented: bullets only, 3–8 items. No paragraphs. MANDATORY pattern per bullet:
feat|fix|chore(scope): <WHAT changed in plain English>. <1 short sentence WHY / end-user impact>.READABILITY sub-rules (from template §RULES 1-3):- Acronyms expanded on FIRST use inside the bullet (example: "RLS (Row-Level Security — Postgres access control)"). After first use → acronym alone is OK.
- Avoid concatenating 5–10 micro-changes into 1 monster bullet. Each
feat(scope)line = ONE self-contained area (DB schema / entity / service / Stripe / API / UI / tests — 1 bullet each, not 8 changes jammed). - Internal jargon gets ½-line context (example: "reverse_transfer (Stripe Connect — money moves from the connected org account back to the platform, then to the buyer)" not just "reverse_transfer=true").
- If >8 bullets → PR is too large (split into gh-stack, §Path B).
- Block 2 — 🔍 Attention points: bullets only, 3 IDEAL, 5 MAX. MANDATORY pattern per bullet:
**Risk label:** \path/or filename` — <what is risky, plain English>. If review misses this: <plain-English consequence — what actually breaks for users/devs>.` Risk labels (rename jargon to the readable versions below):- ✅ Use:
Security-sensitive·Performance-sensitive·Schema change (DDL migration)·Cross-module change·Concurrency / race condition·Product decision - ❌ Stop using:
Blast-radius(too vague — say what it actually hits) - If >5 bullets → split gh-stack.
- ✅ Use:
- Block 3 — 💥 Breaking changes: INCLUDE ONLY IF they EXIST. If NONE → DELETE the ENTIRE "Breaking changes" section (do NOT write "NONE", do NOT leave an empty section). When including: 1 heading per breaking change + Before / After / Migration bullets.
- Block 4 — 🧪 How to verify: bullets only, 1–3 items, IN THIS ORDER:
- (a) Automated tests: CONCRETE COMMAND pointing to a SPECIFIC test + 1 sentence what is covered + 1 expected-result sentence ("Expected: 1/1 passing green").
- (b) Quick manual check: 2–3 CONCRETE steps with numbered parens, NO assumed folder-structure knowledge, always state the EXPECTED VISIBLE outcome (not "test it works").
- (c) Full plan (optional): link to
$CHE_WORKSPACE_SHARED/manual_test_plan.md
- Block 5 — 🔗 Refs: Linear/Jira ticket (ID + URL). Optionally 1 extra link (Figma, PRD .md path, related PR number).
- FORBIDDEN sections (always delete if they creep in): Scope In/Out, Assumptions adopted, long What/Why intro paragraphs, Che gates checklist, giant tables, 2-paragraph context intro. (The "why" lives INSIDE each Block 1 bullet, NOT as a preamble.)
- Body budget: ≤50 lines TOTAL (all 5 blocks + headings summed). No breaking → target ~30 lines. With breaking → target ~45 lines. If over → move long migration/design details into a separate linked doc + keep 1 summary line in Block 2 or 3. Do NOT butcher acronyms/user-impact sentences to save 2 lines — save by cutting forbidden prose instead.
Linear ticket auto-include (A-4.0 common step): When a ticket is detected (A-4.0), ALWAYS include it in Block 5 "Refs". Do NOT duplicate the ref in a separate footer/comment.
A-4.3 Create PR (Draft, not ready for review)
gh pr create \
--draft \
--base <DEFAULT_BRANCH> \
--head <BRANCH_NAME> \
--title "<conventional commit style title, more descriptive: feat(auth): implement Stripe Connect onboarding>" \
--body-file <tmpfile_with_pr_description.md>
Capture the created PR URL: <PR_URL>.
A-4.4 Assign to user + labels
gh pr edit <PR_URL> --add-assignee @me
# Optional: add existing labels (type: bug/feature, needs review, security, breaking-change)
# Only add labels that EXIST in repo.
Path B: GH_STACK_MODE=true (hierarchical PR stack via gh-stack)
B-4.2 Per-layer PR body + Depends-on chain (bottom-up)
For each layer L[i] in LAYERS[] (bottom-up order):
- Build a PR description SCOPED EXCLUSIVELY to
L[i]— same READABLE 5-block structure + readability rules from Path A §A-4.2 (acronym expansion, user-impact per bullet, risk-consequence explanation, non-jargon labels, plain-language How-to-verify). Body is SCOPED TO ONLY the layer's changes (no cross-layer leaks).- Depends on header (CANONICAL gh-stack):
- If
L[i].Depends onis non-empty → PREPEND block to the TOP of PR body (before the 5 blocks):
(Use the numeric PR ID, not the full URL.)Depends on: #<PR-ID-of-L[i-1]> --- - If first layer (base, no Depends on) → skip this header.
- If
- Append: related ticket footer
Refs: <TICKET-ID>inside Block 5 (🔗 Refs). - NO assumptions paragraphs / NO che checklists. Body total ≤35 lines per layer (relaxed vs single PR because stack layers are smaller). Still enforce the readable style from PR_DESCRIPTION_TEMPLATE.md filled example.
- Depends on header (CANONICAL gh-stack):
- Write each layer body to
<tmp>_layer_<L[i].ID>_body.md.
B-4.3 Create each layer PR individually + gh-stack link
Loop layers bottom-up:
For each layer L[i]:
# Ensure on correct layer branch:
git checkout <L[i].BranchName>
# Create DRAFT PR for THIS layer:
gh pr create \
--draft \
--base <if first layer: DEFAULT_BRANCH; else: L[i].Depends on layer's branch> \
--head <L[i].BranchName> \
--title "<L[i].ID>: <layer scope descriptive conventional title>" \
--body-file <tmp>_layer_<L[i].ID>_body.md
- Capture each layer's PR URL:
L[i].PR_URLAND numeric PR ID:L[i].PR_NUMBER. - After PR created: self-assign:
gh pr edit <L[i].PR_URL> --add-assignee @me.
After all individual layer PRs are created + assigned:
# Run gh-stack to formalize the Depends-on hierarchy:
gh-stack create --draft
This validates the chain; if errors → fix base/head references manually per layer.
B-4.4 Stack invariant check
After gh-stack create: verify the chain:
- Layer 1 (base) PR
base: DEFAULT_BRANCH→ correct. - Layer N PR
base: L[N-1] branchAND body hasDepends on: #<L[N-1].PR_NUMBER>→ correct. If mismatch → report to user; offer to fix viagh pr edit --baseor body edit; wait approval.
5. STEP 5 — Report to user (in Portuguese)
Path A: GH_STACK_MODE=false (single PR report)
Final output to user chat:
✅ /che-ship concluído com sucesso.
Resumo:
• Worktree: <worktree path>
• Branch remota: <branch> (criada se não existia)
• Commits aplicados: N (lista resumida)
- <sha1 curto> type(scope): message
- ...
• PR criada (DRAFT): <PR_URL> [atribuída a você]
• Assumptions, review points, breaking changes: veja corpo da PR
Ship gates reports (todos em che-sessions, ordenados por timestamp UTC):
• Scope check (§0.9.1): $SHIP_SCOPE_CHECK_REPORT
• Code review (§0.9.2): $SHIP_CODE_REVIEW_REPORT
• Compliance heavy (§0.9.3): $SHIP_COMPLIANCE_HEAVY_REPORT
• QA gate log (§0.9.4): $SHIP_QA_GATE_LOG
Artefatos relacionados (mesmo workspace):
• Manual test plan: referenciado no corpo e disponível em:
$MANUAL_TEST_PLAN_PATH
• Decision log (todas decisions append-safe JSONL, via che_append_decision_jsonl):
$CHE_DECISIONS_PATH
Próximos passos:
1. Rode um smoke test manual usando o plano acima.
2. Revise o diff da PR para garantir que nenhum arquivo não intencional entrou.
3. Quando tudo ok: abra a PR <PR_URL>, clique em "Ready for review" e atribua reviewers.
Path B: GH_STACK_MODE=true (hierarchical PR stack report)
Final output to user chat:
✅ /che-ship concluído com sucesso — MODO gh-stack HIERÁRQUICO.
Resumo Geral:
• Worktree: <worktree path>
• Número de PRs na stack (bottom-up): <N layers>
• gh-stack chain criada. Todas as PRs DRAFT + atribuídas a você.
Ship gates reports (todos em che-sessions, ordenados por timestamp UTC):
• Scope check (§0.9.1): $SHIP_SCOPE_CHECK_REPORT
• Code review (§0.9.2): $SHIP_CODE_REVIEW_REPORT
• Compliance heavy (§0.9.3): $SHIP_COMPLIANCE_HEAVY_REPORT
• QA gate log (§0.9.4): $SHIP_QA_GATE_LOG
Artefatos relacionados (mesmo workspace):
• Plano gh-stack original: $GH_STACK_PLAN_PATH
• Manual test plan global: $MANUAL_TEST_PLAN_PATH
• Decision log (todas decisions append-safe JSONL, via che_append_decision_jsonl):
$CHE_DECISIONS_PATH
Stack de PRs (ordem de merge = base primeiro para o topo):
───────────────────────────────────────────────
L1 (base, merged first) →
branch: <L1.BranchName>
commits: K1
- <sha> type(scope): message
- ...
PR DRAFT: <L1.PR_URL> [base: DEFAULT_BRANCH]
───────────────────────────────────────────────
L2 → depends on #<L1.PR_NUMBER>
branch: <L2.BranchName>
commits: K2
- ...
PR DRAFT: <L2.PR_URL> [base: L1.BranchName]
───────────────────────────────────────────────
...
───────────────────────────────────────────────
LN (topo, merged last) → depends on #<L[N-1].PR_NUMBER>
branch: <LN.BranchName>
commits: KN
PR DRAFT: <LN.PR_URL> [base: L[N-1].BranchName]
───────────────────────────────────────────────
(Valide o comportamento de cada layer individualmente antes de marcar a stack como pronta.)
Próximos passos (ordem de review = mesma ordem de merge bottom-up):
1. Rode smoke test individual em cada layer começando por L1 (base).
2. Revise diffs uma PR de cada vez — sempre L[i] PR review ANTES de L[i+1].
3. Quando L[i] aprovada + merged: gh-stack atualiza automaticamente a base de L[i+1] → repita até LN.
4. Só depois que LN merged: clique em "Ready for review" da top-level, ou siga o fluxo normal por layer.
Appendix A: Hard stops / What we will NEVER do
- Commit files with
.envin name OR any file matching secrets regex patterns. - Push against a branch you are NOT currently on.
- Commit directly to
main/master/ default branch. Block. Always: feature branch → PR. - Force push without explicit user confirmation.
- Merge the PR. Ship stops at DRAFT PR creation + assign.