Files
loong-workflow/core/skills/verify/reference/issue-filing.md
T

24 KiB
Raw Blame History

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.

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):

- [ ] 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):

    ## 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.

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:

    ## 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.

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:

    ## 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.

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.