v0.1.5: standalone-readability pass — delink --strip provenance mode ([TT-NNNN]), Tier-2 dangling refs neutralized, verify/review-code giant skills split into reference/ on-demand files; guards now runtime-neutral (bun|node)
This commit is contained in:
@@ -0,0 +1,180 @@
|
||||
> Extracted from verify/SKILL.md (section:dag-branch) — moved verbatim; read
|
||||
> on-demand ONLY when the routed Epic is DAG-shaped (frozen DAG at
|
||||
> `{epic-slug}/dag` and `task_route.keep_gates` includes `verify`).
|
||||
|
||||
<!-- section:dag-branch -->
|
||||
## DAG branch (milestone + task modes)
|
||||
|
||||
> This branch OVERRIDES the Preconditions table, Phase 1 read inputs, Phase 5
|
||||
> report index, Phase 5.5 ACCEPTED_RISK source, Phase 5.6 final sweep, and
|
||||
> Phase 6.5 commit gate for a DAG-ticket-pipeline Epic. It applies when the
|
||||
> routed Epic is DAG-shaped: a frozen DAG copy exists at `{epic-slug}/dag` and
|
||||
> the DAG's `task_route.keep_gates` includes `verify`. Legacy iteration verify
|
||||
> (the sections above) remains authoritative for non-DAG iterations. Spec:
|
||||
> `dag-pipeline/spec-05` §5. commit status stays
|
||||
> `pipeline/verify` in both modes.
|
||||
|
||||
### Milestone mode (verify runs on a milestone M when `all_incoming_done_and_green`)
|
||||
|
||||
A milestone node (`type: milestone`) has no implementation work and no ticket;
|
||||
its verify is the integration verification welded at a DAG convergence point
|
||||
(`cross_session_in ≥ 2`). Trigger: the aggregator agent (main
|
||||
session/Orchestrator) detects `all_incoming_done_and_green` — every fan-in
|
||||
source node at its terminal state (task source `done` / milestone source
|
||||
`green`) — and initiates this verify run; the milestone never self-triggers.
|
||||
|
||||
**Precondition replacements** (vs legacy iteration verify):
|
||||
|
||||
| Legacy verify precondition | Milestone-mode replacement |
|
||||
| ---------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| design-space review converged (`review status --stage design-space` success) | review-dag converged (`review status --stage review-dag` success) |
|
||||
| iteration-plan review converged | REMOVED (DAG has no plan review; the single review-dag gate replaces it) |
|
||||
| legacy iteration plan at `{slug}/04-plan-index` | DAG artifact + milestone fan-in slice (no `04-plan-*` page) |
|
||||
| legacy NFR targets from `{slug}/03-design-06-non-functional-design` | REMOVED (product NFRs live in node AC, handled by per-task review-code) |
|
||||
| upstream roadmap chunk done+verified | all milestone fan-in source nodes at terminal state (task source `done` / milestone source `green`, i.e. `all_incoming_done_and_green`) |
|
||||
| code review converged (`pipeline/review-code` success) | ALL fan-in node tickets review-code PASS + PR merged (implied by `done`) |
|
||||
| code review final report exists | REMOVED (no Epic-level final report; per-node review-code reports live on task tickets) |
|
||||
| carried items from previous iteration closed | REMOVED (vacuous — no iteration) |
|
||||
| `core/checklists/verification.md` accessible | KEEP (unconditional) |
|
||||
| Acceptance criteria exist | from DAG-slice-generated DoD matrix (fan-in node AC + integration/contract-conformance/regression/NFR-coverage items) |
|
||||
| `slug` matches the plan slug | N/A (output naming frozen to `{epic-slug}`) |
|
||||
|
||||
**Phase 1 read inputs** → the DAG slice: read the milestone's fan-in subgraph
|
||||
(fan-in nodes + their cross-session edges + contracts) from the frozen DAG copy
|
||||
`{epic-slug}/dag`, and generate the DoD matrix from it (integration items,
|
||||
contract-conformance items, regression items, NFR-coverage items) instead of
|
||||
reading `04-plan-*` pages.
|
||||
|
||||
**Output naming**: `{epic-slug}/05-verify-milestone-{M-id}` (distinct from
|
||||
iteration verify `05-verify-iteration-{N}`).
|
||||
|
||||
**Phase 5 report index**: append a `VERIFY-M-{M-id}` row to the `## 工件索引`
|
||||
comment with 重读 = `ON-DEMAND` (NOT `ARCHIVE`). The milestone verify does NOT
|
||||
edit the comment directly — it reports the row-payload to the aggregator agent
|
||||
(main session/Orchestrator), which is the SINGLE WRITER appending in place
|
||||
(`工单评论 API(见 TERMINOLOGY)`). `ARCHIVE` is never written by milestone verify
|
||||
(Epic close is the sole archive point).
|
||||
|
||||
**Phase 5.5 ACCEPTED_RISK source**: fan-in node task-ticket review-code reports
|
||||
(located in each task ticket's review annotations / `## 当前状态` review row),
|
||||
not an Epic-level final report. A missing Epic-level final report does NOT
|
||||
trigger the "code-review final report does not exist" warn (that warn is
|
||||
legacy-iteration-only). tech-debt / baseline-failure / flaky-test registration
|
||||
proceeds as usual, sourced from the milestone DoD matrix's regression /
|
||||
baseline-classification results.
|
||||
|
||||
**Phase 5.6 milestone mode** (restricted semantics — skip archive-at-close and
|
||||
issue close):
|
||||
|
||||
1. **Checklist final sweep** only — object = each fan-in task ticket's row 6
|
||||
(`verify里程碑`) + the milestone DoD matrix, NOT the Epic body checklist.
|
||||
Verify each fan-in node's row 6 is checked or annotated
|
||||
`_(Pending: M-{M-id} 未 green)_`. Do NOT flip a still-Pending row 6 — that
|
||||
flip belongs to the aggregator agent (main session/Orchestrator), which
|
||||
performs the node-ticket close action. Write the milestone DoD matrix final
|
||||
sweep to `{epic-slug}/05-verify-milestone-{M-id}`.
|
||||
2. **Do NOT fold/remove any Epic-body `## 当前状态` / `## DAG 状态` section** —
|
||||
milestone verify is read-only on Epic body state.
|
||||
3. **SKIP archive-at-close** (the `## 工件索引` archive banner + row-level
|
||||
`ARCHIVE`) and **SKIP issue close** — both belong to the aggregator agent at
|
||||
Epic close.
|
||||
4. **SKIP Tier 1 run archive** (Phase 5.6 step 5, Tier 1 run archive sub-bullet) — the aggregator agent
|
||||
performs it at Epic close.
|
||||
|
||||
**Milestone verify execution context (pinned)**: run the
|
||||
integration/regression/contract-conformance/NFR suite on a checkout CONTAINING
|
||||
all fan-in nodes' merged code — the aggregator agent syncs main (containing the
|
||||
merged fan-in PRs) into the execution worktree, or builds a temp verify worktree
|
||||
from main HEAD, before triggering; the verify report
|
||||
`{epic-slug}/05-verify-milestone-{M-id}` records the actual execution commit
|
||||
SHA.
|
||||
|
||||
**M→green status transition**: NOT done by milestone verify (read-only on Epic
|
||||
body). The aggregator agent (main session/Orchestrator) reads the verify report
|
||||
and sets the aggregator table M row 状态 = `green`, 重读 = `ON-DEMAND`, and
|
||||
syncs the frozen DAG copy `{epic-slug}/dag` node `status` to `green`.
|
||||
|
||||
**Phase 6.5 milestone mode**: vacuous skip — a milestone has no implementation
|
||||
commit. Commit existence is evidenced by the fan-in node verify PASS + PR
|
||||
merged (already implied by `all_incoming_done_and_green`).
|
||||
|
||||
**Milestone verify FAIL recovery**: FAIL → M `status` = `blocked`. Fix
|
||||
responsibility = the fan-in node owning the failing integration/regression item
|
||||
(the last-done fan-in node's session) or the Epic-level session (DAG author) if
|
||||
un-attributable. Re-run is triggered ONLY by a "fix-landed event" (fix commit
|
||||
merged + CI green, or an explicit re-done report from the owning session) —
|
||||
NOT status polling (done nodes are never reset; `all_incoming_done_and_green`
|
||||
stays true after FAIL). M stays `blocked` until a fix event, then returns to
|
||||
`pending` and verify re-runs. No review-dag re-run unless the fix changes a
|
||||
cross-session contract or the node/edge set.
|
||||
|
||||
### Task mode (verify on a task node ticket, because `task_route.keep_gates` includes `verify`)
|
||||
|
||||
Each task ticket closes only after its own verify run, but legacy verify
|
||||
preconditions do not hold in DAG mode — this node-level branch reuses the
|
||||
`verify` skill with the following node-scoped semantics (so the `verify` gate is
|
||||
not silently downgraded to CI-only).
|
||||
|
||||
**Verification object**: the node's own `acceptance_criteria` → the `test_id`
|
||||
suite (`file-path::test-name` / `MANUAL` / `BENCH:`) all passing fresh + that
|
||||
node's review-code PASS recorded + CI green. NOT milestone fan-in
|
||||
integration/contract/regression items (those are milestone verify's). Spec
|
||||
authority = the node in the frozen DAG copy `{epic-slug}/dag`.
|
||||
|
||||
**Precondition replacements** (task mode — mirror the milestone table, scoped to
|
||||
the node):
|
||||
|
||||
| Legacy verify precondition | Task-mode replacement |
|
||||
| ------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- |
|
||||
| design-space review converged | review-dag converged (this Epic already passed the single gate; do NOT re-run it) |
|
||||
| iteration-plan review converged | REMOVED (DAG has no plan review) |
|
||||
| legacy iteration plan at `{slug}/04-plan-index` | the node in the frozen DAG copy `{epic-slug}/dag` (no `04-plan-*` page) |
|
||||
| legacy NFR targets from `{slug}/03-design-06-non-functional-design` | REMOVED (product NFRs live in node AC, handled by per-task review-code) |
|
||||
| upstream roadmap chunk done+verified | this node's cross-session in-edge source nodes at terminal state (task source `done` / milestone source `green`) |
|
||||
| code review converged (`pipeline/review-code` success) | this node's ticket review-code PASS + PR merged |
|
||||
| code review final report exists | REMOVED (this node's review-code report lives on the task ticket) |
|
||||
| carried items from previous iteration closed | REMOVED (vacuous — no iteration) |
|
||||
| `core/checklists/verification.md` accessible | KEEP |
|
||||
| Acceptance criteria exist | from node AC + `test_id` suite |
|
||||
| `slug` matches the plan slug | N/A (Tier 1 run slug = `{epic-slug}-task-{node-id}` — the same node-task run namespace review-code runs in and this mode's archive bundle uses below; the Phase 2 precondition-gate cache read MUST use this slug. Only the wiki output naming stays Epic-scoped: `{epic-slug}/05-verify-task-{node-id}`) |
|
||||
|
||||
**Phase 1 read inputs** → the node's AC + `test_id` suite from the frozen DAG
|
||||
copy `{epic-slug}/dag`, generating the DoD matrix.
|
||||
|
||||
**Output naming**: `{epic-slug}/05-verify-task-{node-id}`.
|
||||
|
||||
**Phase 5 report index**: append a `VERIFY-TASK-{node-id}` row, 重读 =
|
||||
`ON-DEMAND` (NOT `ARCHIVE`), via the aggregator agent as single writer (task
|
||||
verify does not edit the comment directly).
|
||||
|
||||
**Phase 5.5 task mode**: ACCEPTED_RISK source = this node's task-ticket
|
||||
review-code report (no Epic-level final report → no "does not exist" warn).
|
||||
tech-debt / baseline-failure / flaky-test registration proceeds as usual.
|
||||
|
||||
**Phase 5.6 task mode**: only checklist final sweep — object = this ticket's
|
||||
5-row checklist (NOT row 6 `verify里程碑` — row 6 is flipped ONLY by the
|
||||
aggregator agent). SKIP archive-at-close (`## 工件索引` row-level `ARCHIVE`) and
|
||||
issue close (both belong to the aggregator agent). SKIP Tier 1 run archive — the
|
||||
aggregator agent collects it cross-worktree at task-ticket close (archive to
|
||||
`<runs-root>/archive/{epic-slug}-task-{node-id}.json` and commit to the
|
||||
workflow branch). Do NOT fold Epic body status sections.
|
||||
|
||||
**Phase 6.5 task mode**: object = this node ticket's commit; semantics = "node
|
||||
implementation commit exists". Baseline = the task worktree's creation-commit
|
||||
SHA (`git log {creation-SHA}..HEAD`), NOT a generic base-branch (post-merge
|
||||
there are no new commits vs base). The task worktree is retained until ticket
|
||||
close (the aggregator agent removes it after collecting task-level Tier 1
|
||||
archive); the task session must NOT remove its own worktree.
|
||||
|
||||
**commit status**: still `pipeline/verify` in both modes.
|
||||
|
||||
### No-milestone DAG Epic-level verify gate
|
||||
|
||||
When the routed Epic's DAG has NO milestone (no `cross_session_in ≥ 2`
|
||||
convergence point), the Epic-level `keep_gates: verify` is satisfied
|
||||
AGGREGATELY by all task-ticket verify runs (each with commit status
|
||||
`pipeline/verify` success) — NO independent Epic-level verify run, NO
|
||||
`{epic-slug}/05-verify-milestone-{M-id}` artifact, NO `VERIFY-M-{M-id}` index
|
||||
row. The Epic close condition degenerates to "all task nodes `done`".
|
||||
|
||||
---
|
||||
@@ -0,0 +1,495 @@
|
||||
> Extracted from verify/SKILL.md (phase 5.5 / 5.55 / 5.56 / 5.6) — moved
|
||||
> verbatim; read on-demand during Phase 5 execution, before PASS. Each phase
|
||||
> is mandatory-before-PASS in its trigger condition; the main flow stops at
|
||||
> each boundary until the referenced protocol reports completion.
|
||||
|
||||
<!-- section:phase-5.5 -->
|
||||
### Phase 5.5 — Tech Debt Registry Filing (mandatory before PASS)
|
||||
|
||||
Tech debt is filed **registry-first** (`core/rules/ticket-lifecycle.md`,
|
||||
[TT-3002] G1): new items become ROWS in the source ticket's `## TD 登记` comment;
|
||||
an independent ticket is created only at **promotion** (claim/schedule). There
|
||||
is no `tech-debt.md` file and no `{slug}/tech-debt` wiki page — both remain
|
||||
retired. The registry preserves the three guarantees of the old
|
||||
one-issue-per-item model: visible (the comment lives on a tracker ticket),
|
||||
individually closeable (row-level checkbox), de-duplicated across sessions
|
||||
(the TD index is stronger than title-keyword matching).
|
||||
|
||||
**Sprint-mode override ([TT-3002] G5/[TT-3007])**: read `filing.sprint-mode` from
|
||||
`<instance-root>/workflow-routing.yaml` at the START of this phase (no caching). When
|
||||
`true`, ALL severities file registry-only — registration rows are written as
|
||||
normal (severity included, nothing lost) but promotion to standalone tickets
|
||||
is FROZEN until the switch returns to `false`. Rationale: the 2026-08-12
|
||||
sprint zeroed fix capacity while filing kept running (the 125-fragment
|
||||
backlog's direct trigger); an explicit debt-side downshift beats hoping for
|
||||
discipline. BF/FT phases 5.55/5.56 are NOT covered by this switch — failure
|
||||
evidence must stay immediately visible. Flipping the switch is a human
|
||||
decision recorded on the sprint tracker; semantics in
|
||||
`rules/workflow-routing.md` §立案降档.
|
||||
|
||||
**Adjacency quota ([TT-3002] G3/[TT-3005])**: while collecting inputs, also check the
|
||||
AREAS this iteration touched (packages/modules with commits this iteration).
|
||||
If the source tickets for those areas carry applicable `## TD 登记` rows, at
|
||||
least ONE row must be taken along and disposed this iteration (fixed, or
|
||||
explicitly re-deferred with a reason — silence is not a disposition). Record
|
||||
`consumed X / applicable Y` (or `0 applicable`) in the TD report section;
|
||||
verification checklist §8.4 cross-checks it against the run's debt-quota
|
||||
record (historically the roadmap's per-chunk debt-quota line). This gives debt digestion a steady capacity source tied to
|
||||
touch, not to cleanup campaigns.
|
||||
|
||||
**Promotion quota + pull event ([TT-3061])**: promotion to a standalone ticket
|
||||
requires (a) a **pull event** — the row's Reactivation Trigger fired (state
|
||||
the observed event) OR a named claimer/schedule; "it seemed important" is not
|
||||
a pull event — recorded in the promotion body's `## 拉动事件 / Pull Event`
|
||||
section; and (b) the origin module's OPEN promoted-TD count is below the
|
||||
quota (**default 10** — counted **per origin module**: resolve the row's
|
||||
module from the ticket body's `Origin` field, then count that module's OPEN
|
||||
`tech-debt` tickets; retro §2.10 reports breaches). At or above quota →
|
||||
register-only until the count drops; before each Phase 5.5 promotion
|
||||
re-check the owning module's count, and a row whose module is at or above
|
||||
quota is NOT promoted — defer it and annotate the registry row with
|
||||
`quota-held` (re-checked on the next verify run, retro 2026-08-21). A row
|
||||
marked `[COLD]` by retrospective §2.10
|
||||
(unclaimed >3 retro cycles) promotes only after the pull event clears the
|
||||
mark.
|
||||
|
||||
**Collect inputs** — every tech-debt item to register this iteration:
|
||||
|
||||
1. Every UNVERIFIABLE row in the DoD matrix (Phase 3), with its Reactivation
|
||||
Trigger.
|
||||
2. Every ACCEPTED_RISK finding in the code-review final report
|
||||
(`{slug}/reviews/code/final/report`), with its Recommended Reactivation
|
||||
Trigger.
|
||||
3. Every `[OPEN: <short-id>]` marker the Developer left in code this iteration
|
||||
(per implementation checklist POST-6.2).
|
||||
|
||||
If the code-review final report does not exist, warn the user — ACCEPTED_RISK
|
||||
items cannot be captured. This is itself a process gap that must be flagged.
|
||||
|
||||
**Step 1 — De-duplicate against the registry index and promoted issues.**
|
||||
|
||||
1. Read the source ticket's `## TD 登记` comment (create the comment if this
|
||||
is its first row) and match each candidate against existing rows by
|
||||
`TD-NNN` and reactivation trigger. Same-source re-reporting is the
|
||||
anti-pattern this step exists to prevent (the visual-cluster incident: 18
|
||||
fragments from one source under the old keyword matching).
|
||||
2. Query OPEN promoted tech-debt issues for cross-source duplicates:
|
||||
|
||||
```
|
||||
工单 API 检索(见 TERMINOLOGY)
|
||||
(owner/repo 按实例绑定,labels="tech-debt", state="open")
|
||||
```
|
||||
|
||||
**Step 2 — Assign `TD-NNN` via the ledger mutex ([TT-3322]).** One script call
|
||||
per batch: `bash script/td-alloc.sh <count = new items> <source-slug>
|
||||
[--ticket N]` returns a contiguous range from the TD allocation ledger
|
||||
(append-only comments, earliest-comment-id wins; the seed comment pins the
|
||||
historical floor). Split the returned range across the Step 3 rows in order.
|
||||
**Any allocation — manual included — must land a `**td-alloc**` comment on
|
||||
the ledger before the registry row is written; hand-computed `max + 1` is
|
||||
forbidden** (the 2026-08-24 three-way collision). On exit 5 (retry
|
||||
exhaustion) abort this phase's filing and retry — never hand-assign. The id is **reserved for life**: promotion reuses it, never
|
||||
renumbers. Run `--check` (reconciliation) here if the last check predates
|
||||
this batch.
|
||||
|
||||
**Step 3 — Append one registry row per new item.** Append to the source
|
||||
ticket's `## TD 登记` comment (no source ticket → the owning Epic's tracker
|
||||
ticket; no Epic → the standing `TD 冷存档` tracker):
|
||||
|
||||
```markdown
|
||||
- [ ] TD-{NNN} · {UNVERIFIABLE | ACCEPTED_RISK | DEFERRED} · {HIGH | MEDIUM | LOW}
|
||||
· {origin chunk-id/iter-N} — {one-line summary}
|
||||
· trigger: {objectively verifiable reactivation condition — never "when ready";
|
||||
if no trigger can be defined this is NOT tech debt and the iteration verdict
|
||||
becomes FAIL}
|
||||
```
|
||||
|
||||
**Step 4 — Cross-link (adapted).** The registry comment already lives on the
|
||||
source issue — the source → debt navigation the old body-edit provided. When
|
||||
filing went to an Epic tracker or the 冷存档 (no source ticket), reference the
|
||||
originating slug in each row so the trail survives.
|
||||
|
||||
**Step 5 — Record the mapping in the verification report.** The report's
|
||||
"Tech Debt" section records `TD-NNN → registry row` (source `#NNNN` +
|
||||
`## TD 登记` comment); promoted items record `TD-NNN → #NNNN` as before.
|
||||
|
||||
**Promotion (认领升票) — when a row is scheduled or picked up.** Create the
|
||||
independent ticket THEN, carrying the reserved `TD-NNN`:
|
||||
|
||||
```
|
||||
POST <gitea-base-url>/api/v1/repos/Octopus/octopus/issues
|
||||
body: {"title":"[{origin}] Tech debt: {short description} (TD-{NNN})",
|
||||
"body":<promotion template below>,
|
||||
"labels":[tech_debt_label_id, severity_label_id]}
|
||||
```
|
||||
|
||||
- **Severity → label** (reuse the existing exclusive Priority set):
|
||||
|
||||
| Severity | Label |
|
||||
| -------- | ----------------- |
|
||||
| HIGH | `Priority/High` |
|
||||
| MEDIUM | `Priority/Medium` |
|
||||
| LOW | `Priority/Low` |
|
||||
|
||||
- **Promotion body template** (the pre-[TT-3002] issue template, now used only at
|
||||
promotion):
|
||||
|
||||
```markdown
|
||||
## Parent / 父级
|
||||
|
||||
{#source_issue carrying the ## TD 登记 row}
|
||||
|
||||
## Summary
|
||||
|
||||
{one-paragraph description of the debt}
|
||||
|
||||
| Field | Value |
|
||||
| -------- | ------------------------------------------- |
|
||||
| TD ID | TD-{NNN} (reserved at registration) |
|
||||
| Type | {UNVERIFIABLE \| ACCEPTED_RISK \| DEFERRED} |
|
||||
| Origin | {chunk-id/iter-N/phase or slug} |
|
||||
| Severity | {HIGH \| MEDIUM \| LOW} |
|
||||
|
||||
## Reactivation Trigger
|
||||
|
||||
{from the registry row}
|
||||
|
||||
## 拉动事件 / Pull Event
|
||||
|
||||
{trigger fired: {observed event} | claimed by {who} for {when}}
|
||||
|
||||
## Acceptance Criteria (how to close this issue)
|
||||
|
||||
- [ ] {specific action that resolves the debt}
|
||||
|
||||
## Context
|
||||
|
||||
- Verification report: `{slug}/05-verify-iteration-{N}`
|
||||
- Code review report: `{slug}/reviews/code/final/report` (if ACCEPTED_RISK)
|
||||
```
|
||||
|
||||
- After creating the promoted ticket: tick the registry row (`- [x]`) and
|
||||
append `→ #NNNN` to it.
|
||||
|
||||
If no new tech-debt items were found this iteration, the phase is a no-op —
|
||||
record "0 tech-debt items" in the report and proceed.
|
||||
|
||||
<!-- section:phase-5.55 -->
|
||||
### Phase 5.55 — Baseline-Failure Issue Registration (mandatory before PASS when pre-existing failures exist)
|
||||
|
||||
Pre-existing test failures (BF) are tracked as **root-cause family umbrella
|
||||
tickets** (`core/rules/ticket-lifecycle.md`, [TT-3002] G1; precedents [TT-2585]
|
||||
umbrella + [TT-2925] cluster) — one `BF-NNN` ticket per failure-signature family,
|
||||
labeled `baseline-failure`, with each occurrence's evidence attached as
|
||||
comments. There is no `baseline-failures.md` file and no
|
||||
`{slug}/baseline-failures` wiki page. A pre-existing failure does not block
|
||||
the iteration that _discovered_ it (it pre-dates that work), but it MUST be
|
||||
filed against (or into) a family; an un-filed baseline failure is a process
|
||||
gap and the iteration is NOT Done.
|
||||
|
||||
**Birth triage SLA ([TT-3061])**: a BF umbrella is born with `Kind/Bug` (it IS a
|
||||
bug — of the baseline) and must be triaged the SAME DAY it is filed:
|
||||
assigned, scheduled, or explicitly deferred with a reason on the ticket.
|
||||
Untriaged-next-day BF umbrellas are named individually in retro §2.10
|
||||
(compliance %), not averaged away.
|
||||
|
||||
**Collect inputs** — every pre-existing failure to register this iteration:
|
||||
|
||||
1. Every failure classified **pre-existing** in Phase 2.6 (fails on the base
|
||||
branch / last-green commit too).
|
||||
2. Any baseline-run failures noted in the brownfield pre-check (Greenfield vs.
|
||||
Brownfield section).
|
||||
|
||||
**Step 1 — De-duplicate by failure SIGNATURE against existing families (open
|
||||
AND closed), per `core/rules/testing.md`** (de-duplicate BEFORE filing,
|
||||
retro [TT-2696]). Query `baseline-failure` issues in ALL states:
|
||||
|
||||
```
|
||||
GET <gitea-base-url>/api/v1/repos/Octopus/octopus/issues?labels=baseline-failure&state=all&page=N&limit=50
|
||||
```
|
||||
|
||||
Match each candidate by **failure signature** — the error/assertion signature
|
||||
plus the affected surface, not just `file::test-name` (one root-cause family
|
||||
may span several tests; several tests failing with the same assertion shape
|
||||
are ONE family). On a signature hit, do NOT create a new ticket: attach the
|
||||
new run evidence (run, commit, failing output, sibling tests observed) as a
|
||||
comment on the FAMILY umbrella ticket. Filing a second ticket inside a known
|
||||
root-cause family is the anti-pattern this phase exists to prevent. If a
|
||||
tracked family is now FIXED by this iteration's work, close its umbrella with
|
||||
a comment citing the fixing commit (a bonus, not a requirement). If the query
|
||||
itself errors (API failure — not "no matches"), retry once; on the second
|
||||
failure proceed to file with the literal marker `dedup-unverified` in the
|
||||
umbrella's first evidence comment (query-failure ruling, [TT-3383] — fail-open,
|
||||
visible; rationale in `core/rules/ticket-lifecycle.md`).
|
||||
|
||||
**Step 2 — Assign the next `BF-NNN`** per `core/rules/testing.md`
|
||||
§ "Pre-existing test failures must be filed, not silently logged" (the L1 rule
|
||||
owns the repo-wide sequential numbering invariant — `max + 1`, duplicate ids
|
||||
forbidden incl. closed tickets). `BF-NNN` names the FAMILY; the Gitea issue
|
||||
number `#NNNN` is the tracker handle.
|
||||
|
||||
**Step 3 — Create one umbrella ticket per NEW root-cause family.** Only when
|
||||
no existing family matches the signature:
|
||||
|
||||
```
|
||||
POST <gitea-base-url>/api/v1/repos/Octopus/octopus/issues
|
||||
body: {"title":"[{origin}] Baseline failure: {test identifier} (BF-{NNN})",
|
||||
"body":<issue body template below>,
|
||||
"labels":[baseline_failure_label_id, severity_label_id, kind_bug_label_id]}
|
||||
```
|
||||
|
||||
- **Title**: `[{origin}] Baseline failure: {signature summary} (BF-{NNN})`
|
||||
where `{origin}` is `chunk-{id}/iter-{N}` or the bugfix slug, and
|
||||
`{signature summary}` is the family's error/assertion shape (not a single
|
||||
test name — sibling tests observed later join this umbrella as evidence
|
||||
comments).
|
||||
- **Severity → label** (reuse the existing exclusive Priority set; a failing
|
||||
test defaults to at least MEDIUM, HIGH if on a critical path):
|
||||
|
||||
| Severity | Label |
|
||||
| -------- | ----------------- |
|
||||
| HIGH | `Priority/High` |
|
||||
| MEDIUM | `Priority/Medium` |
|
||||
| LOW | `Priority/Low` |
|
||||
|
||||
- Also attach `Kind/Bug` so the failure is discoverable in the bug tracker
|
||||
alongside manually-reported bugs.
|
||||
- **Issue body template**:
|
||||
|
||||
````markdown
|
||||
## Parent / 父级
|
||||
|
||||
{#source_issue, or "no source issue — discovered during iteration baseline"}
|
||||
|
||||
## Summary
|
||||
|
||||
A test was already failing before this iteration's work began. It does not
|
||||
block the discovering iteration but must be tracked to closure.
|
||||
|
||||
| Field | Value |
|
||||
| -------------- | ---------------------------------------------- |
|
||||
| BF ID | BF-{NNN} (family) |
|
||||
| Signature | {error/assertion shape} |
|
||||
| Tests affected | `{file::test-name}`, … (initial members) |
|
||||
| Origin | {chunk-id/iter-N or slug} |
|
||||
| Severity | {HIGH \| MEDIUM \| LOW} |
|
||||
| First observed | {base commit / date the failure reproduces on} |
|
||||
|
||||
## Reproduction
|
||||
|
||||
```
|
||||
git checkout {base commit}
|
||||
(cd <harness-package> && bun test --timeout 120000 {test file}) # or project-equivalent
|
||||
```
|
||||
|
||||
Failing output:
|
||||
|
||||
```
|
||||
{paste the relevant assertion / error}
|
||||
```
|
||||
|
||||
## Acceptance Criteria (how to close this issue)
|
||||
|
||||
- [ ] The named test passes on a clean checkout of the target branch.
|
||||
- [ ] If the test is deleted/renamed, the replacement covers the same
|
||||
behavior and passes.
|
||||
|
||||
## Context
|
||||
|
||||
- Verification report: `{slug}/05-verify-iteration-{N}`
|
||||
````
|
||||
|
||||
**Step 4 — Cross-link to the source issue (mandatory).** Per the
|
||||
issue-cross-linking rule, every baseline-failure issue MUST link back to its
|
||||
source:
|
||||
|
||||
- The issue body already carries `## Parent` (above).
|
||||
- Update the source/parent issue body to reference each new baseline-failure
|
||||
issue by `#NNNN` in its task list (e.g.
|
||||
`- [ ] #NNNN — BF-{NNN} {test identifier}`), so reviewers can navigate from
|
||||
source → failure.
|
||||
|
||||
**Step 5 — Record the mapping in the verification report.** The
|
||||
`BF-NNN → #NNNN` mapping is written ONLY in the Phase 5 verification report's
|
||||
"Baseline Failures" section (and in the issue title itself). There is no local
|
||||
file to update.
|
||||
|
||||
If no new baseline failures were found this iteration, the phase is a no-op —
|
||||
record "0 baseline failures" in the report and proceed.
|
||||
|
||||
<!-- section:phase-5.56 -->
|
||||
### Phase 5.56 — Flaky-Test Issue Registration (mandatory before PASS when flaky tests are unfixed)
|
||||
|
||||
Flaky tests (intermittent pass/fail) are tracked as **root-cause family
|
||||
umbrella tickets** (`core/rules/ticket-lifecycle.md`, [TT-3002] G1) — one
|
||||
`FT-NNN` ticket per failure-signature family, labeled `flaky-test`, with each
|
||||
occurrence's evidence (run count, failure rate, commit) attached as comments.
|
||||
A flaky test that is not fixed within this iteration MUST be filed against
|
||||
(or into) a family; otherwise it evaporates at iteration end and the
|
||||
"compare flaky count against baseline" check (TST-2.5) has no persistent
|
||||
register to compare against. Filing does not block the verdict, but an unfixed
|
||||
flaky test left un-filed is a process gap and the iteration is NOT Done.
|
||||
|
||||
**Expiry SLA ([TT-3061])**: an FT umbrella is born with `Kind/Testing` and a
|
||||
**fix-or-isolate window** (default 7 days) recorded in its body (isolating =
|
||||
quarantining/skipping the test with the family id in the skip reason, which
|
||||
keeps the register comparable). Past the window without fix or isolation, the
|
||||
umbrella is escalated on the ticket (comment naming the owner); retro §2.10
|
||||
reports fix-or-isolate compliance per cycle.
|
||||
|
||||
**Collect inputs** — every flaky test to register this iteration:
|
||||
|
||||
1. Every flaky test surfaced in Phase 2.1 (intermittent pass/fail across
|
||||
reruns) that was NOT fixed by the Developer this iteration.
|
||||
2. Any flaky test carried over from a prior iteration's report that is still
|
||||
intermittently failing.
|
||||
|
||||
**Step 1 — De-duplicate by failure SIGNATURE against existing families (open
|
||||
AND closed), per `core/rules/testing.md`** (de-duplicate BEFORE filing,
|
||||
retro [TT-2696]). Query `flaky-test` issues in ALL states:
|
||||
|
||||
```
|
||||
GET <gitea-base-url>/api/v1/repos/Octopus/octopus/issues?labels=flaky-test&state=all&page=N&limit=50
|
||||
```
|
||||
|
||||
Match each candidate by **failure signature** — the flakiness mode (timeout /
|
||||
race / order-dependence / env-leak) plus the affected surface, not just
|
||||
`file::test-name` (one root cause may flake several tests). On a signature
|
||||
hit, do NOT create a new ticket: attach the new run evidence (run count,
|
||||
failure rate, commit, sibling tests) as a comment on the FAMILY umbrella
|
||||
ticket. Filing a second ticket inside a known root-cause family is the
|
||||
anti-pattern this phase exists to prevent. If a tracked family now passes
|
||||
deterministically, close its umbrella citing the fixing commit. If the query
|
||||
itself errors (API failure — not "no matches"), retry once; on the second
|
||||
failure proceed to file with the literal marker `dedup-unverified` in the
|
||||
umbrella's first evidence comment (query-failure ruling, [TT-3383] — fail-open,
|
||||
visible; rationale in `core/rules/ticket-lifecycle.md`).
|
||||
|
||||
**Step 2 — Assign the next `FT-NNN`** per `core/rules/testing.md`
|
||||
§ "Flaky tests must be filed, not silently tolerated" (the L1 rule owns the
|
||||
repo-wide sequential numbering invariant — `max + 1`, duplicate ids forbidden
|
||||
incl. closed tickets). `FT-NNN` names the FAMILY.
|
||||
|
||||
**Step 3 — Create one umbrella ticket per NEW root-cause family.** Only when
|
||||
no existing family matches the signature:
|
||||
|
||||
```
|
||||
POST <gitea-base-url>/api/v1/repos/Octopus/octopus/issues
|
||||
body: {"title":"[{origin}] Flaky test: {test identifier} (FT-{NNN})",
|
||||
"body":<issue body template below>,
|
||||
"labels":[flaky_test_label_id, severity_label_id, kind_testing_label_id]}
|
||||
```
|
||||
|
||||
- **Title**: `[{origin}] Flaky test: {signature summary} (FT-{NNN})` — the
|
||||
family's flakiness mode + surface (sibling tests join later as evidence
|
||||
comments, not new tickets).
|
||||
- **Severity** → a flaky test defaults to MEDIUM (HIGH if on a critical path
|
||||
or blocking CI); reuse the exclusive Priority set.
|
||||
- Also attach `Kind/Testing` so it is discoverable in the testing tracker.
|
||||
- **Issue body template**:
|
||||
|
||||
````markdown
|
||||
## Parent / 父级
|
||||
|
||||
{#source_issue, or "no source issue — discovered during iteration verification"}
|
||||
|
||||
## Summary
|
||||
|
||||
A test passes and fails intermittently across runs. It undermines the
|
||||
reliability of the suite and must be stabilized or quarantined.
|
||||
|
||||
| Field | Value |
|
||||
| ------------ | ------------------------- |
|
||||
| FT ID | FT-{NNN} (family) |
|
||||
| Signature | {flakiness mode + surface} |
|
||||
| Tests affected | `{file::test-name}`, … (initial members) |
|
||||
| Origin | {chunk-id/iter-N or slug} |
|
||||
| Severity | {HIGH \| MEDIUM \| LOW} |
|
||||
| Failure rate | {e.g. 3/10 runs} |
|
||||
|
||||
## Reproduction
|
||||
|
||||
```
|
||||
for i in $(seq 1 10); do (cd <harness-package> && bun test --timeout 120000 {test file}) || echo "run $i FAILED"; done
|
||||
```
|
||||
|
||||
## Acceptance Criteria (how to close this issue)
|
||||
|
||||
- [ ] The test passes deterministically across 10 consecutive runs.
|
||||
- [ ] If it cannot be stabilized, it is quarantined (`test.skip` /
|
||||
`test.todo` with a comment citing FT-{NNN}) and a stable replacement
|
||||
is filed as tech-debt (TD-NNN).
|
||||
|
||||
## Context
|
||||
|
||||
- Verification report: `{slug}/05-verify-iteration-{N}`
|
||||
````
|
||||
|
||||
**Step 4 — Cross-link to the source issue (mandatory).** Every flaky-test
|
||||
issue links back to its source via `## Parent`, and the source/parent issue
|
||||
task list references each by `#NNNN`
|
||||
(`- [ ] #NNNN — FT-{NNN} {test identifier}`).
|
||||
|
||||
**Step 5 — Record the mapping in the verification report.** The
|
||||
`FT-NNN → #NNNN` mapping is written ONLY in the Phase 5 report's "Flaky Tests"
|
||||
section (and the issue title). No local file.
|
||||
|
||||
If no unfixed flaky tests exist this iteration, the phase is a no-op — record
|
||||
"0 flaky tests" in the report and proceed.
|
||||
|
||||
<!-- section:phase-5.6 -->
|
||||
### Phase 5.6 — Issue Checklist Sync (final sweep, mandatory before PASS)
|
||||
|
||||
This is the **final** checklist sync — the last of the progressive sync
|
||||
points (requirements exit, design exit, plan exit, each iteration commit, PR
|
||||
creation, review convergence, CI transitions, and here — per the sync-point
|
||||
table in `core/rules/issue-checklist-sync.md`). Earlier syncs may have
|
||||
already checked off completed items; this phase catches everything remaining
|
||||
and ensures no `- [ ]` item is left without an annotation.
|
||||
|
||||
1. **Identify the source issue** per `core/rules/issue-checklist-sync.md`
|
||||
§ "How to sync (each point)" step 1 (find `Closes #N` / `Fixes #N` in the
|
||||
PR body or commit messages). If no source issue exists (e.g. standalone
|
||||
bugfix with no tracking issue), skip this phase.
|
||||
2. **Fetch the issue body** via `工单 API(见 TERMINOLOGY)get` (rule step 2).
|
||||
3. **Map every remaining `- [ ]` checklist item** to one of three states:
|
||||
- **Done** (missed by earlier syncs) → mark `- [x]` and append
|
||||
`_(PR #NNN: <file/component>)_`.
|
||||
- **Deferred** → keep `- [ ]` and append `_(Deferred: TD-NNN <reason>)_`.
|
||||
- **Pending** → keep `- [ ]` and append `_(Pending: <blocker>)_`.
|
||||
4. **Fold the `## 当前状态` live-status section** (if present). Rows that have
|
||||
a checklist counterpart (review, process-ACs) are already reflected as
|
||||
checklist annotations at their sync points. Rows with no checklist
|
||||
counterpart in a non-Epic issue (PR opened/merged) are folded as follow-up
|
||||
evidence on the issue narrative (e.g. `_(PR #NNN merged: <summary>)_` on the
|
||||
item it delivered, or in the report). Once every row is accounted for,
|
||||
remove the section from the issue body.
|
||||
5. **archive-at-close: mark the `## 工件索引` comment archived** (归档动作 — [TT-1929]). Issue
|
||||
closing IS the archive-at-close action; it is explicit, not implicit. Edit the index
|
||||
comment in place per `_shared/gitea-write-patterns.md` Pattern 10 Archive-at-close
|
||||
(mechanism — banner + every row's 重读 → ARCHIVE + invariants — is defined there,
|
||||
do not restate; sequence/actor per `rules/issue-checklist-sync.md` § 归档动作).
|
||||
- Skip if no source issue exists.
|
||||
- **Tier 1 run archive** ([TT-1988] two-tier artifacts — only if a Tier 1 run
|
||||
workspace exists): if `<runs-root>/{slug}/` exists (a stage in this run
|
||||
produced Tier 1 local artifacts, e.g. review-code findings), archive the
|
||||
run workspace per `core/rules/two-tier-artifacts.md` § Archive-at-close
|
||||
(the L1 rule is authoritative — do NOT restate its steps here).
|
||||
The archived bundle must pass
|
||||
`core/schemas/runs-bundle.schema.json` validation (the generator
|
||||
validates by default; a red exit blocks close).
|
||||
Verify deltas only: skip in milestone/task DAG mode (the aggregator agent
|
||||
performs it at Epic/task-ticket close — see the DAG branch below).
|
||||
6. **Update the issue body** via `工单 API(见 TERMINOLOGY)update` with the annotated
|
||||
checklist. Preserve all non-checklist content unchanged.
|
||||
7. **Verify**: re-read the issue and confirm no `- [ ]` item lacks an
|
||||
annotation. Every unchecked item MUST have a `(Deferred: ...)` or
|
||||
`(Pending: ...)` note explaining why it is not done.
|
||||
8. **Close the issue** (completes the archive-at-close loop): if the flow has
|
||||
no PR (no `Closes #N` on merge), the Verifier closes the issue after PASS
|
||||
approval via `工单 API(见 TERMINOLOGY)update(state="closed")` — the banner date is
|
||||
corrected to the actual close date if it differs from today. If a PR carries
|
||||
`Closes #N`, the merge closes it; no further action.
|
||||
|
||||
If a checklist item cannot be mapped to evidence, deferral, or pending
|
||||
status, the iteration is NOT Done — the item represents untracked scope.
|
||||
Reference in New Issue
Block a user