Initial publish v0.1.0: standalone workflow core (corpus + examples + guards)
This commit is contained in:
@@ -0,0 +1,116 @@
|
||||
# 工件寻址契约(Core,后端中立)
|
||||
|
||||
> Core 原生契约(Increment 3,无 dogfood 对应源文件)。术语对照见
|
||||
> `core/adapters/TERMINOLOGY.md`;本文所有实例路径以占位符表述
|
||||
> (`<runs-root>` = 实例运行目录根),落地实例时按术语表绑定。
|
||||
|
||||
## 1. ref 语法
|
||||
|
||||
所有 Tier-2 工件的规范引用格式:
|
||||
|
||||
```
|
||||
{backend}:{kind}/{owner}/{repo}/{id}#{anchor}
|
||||
```
|
||||
|
||||
- `{backend}` — 工单后端标识(如 `gitea`);由 adapter 层注册。
|
||||
- `{kind}` — 工件类别,枚举见下表;新类别扩展时须同步各 adapter 的
|
||||
resolve 实现并在本表登记。
|
||||
- `{owner}/{repo}` — 仓库坐标。
|
||||
- `{id}` — 工件标识:issue/PR 用数字,wiki 页用页名(可含 `/`),
|
||||
评论用 `{issue-number}c{comment-id}`,commit-status 用 `{sha}@{context}`。
|
||||
- `#{anchor}` — 可选锚点(页内段落、行号等),解析时透传不解释。
|
||||
|
||||
| kind | 含义 | id 形态 |
|
||||
| --------------- | --------------- | ---------------------- |
|
||||
| `issue` | 工单 | 数字 |
|
||||
| `issue-comment` | 工单评论 | `{issue}c{comment-id}` |
|
||||
| `wiki-page` | Tier-2 工件库页 | 页名(含 `/`) |
|
||||
| `commit-status` | 提交状态 | `{sha}@{context}` |
|
||||
| `pr` | 合并请求 | 数字 |
|
||||
|
||||
## 2. 页名文法(Core 契约)
|
||||
|
||||
Tier-2 工件库的**常规页名**:
|
||||
|
||||
```
|
||||
{slug}/{type}-{seq:02d}-{title}
|
||||
```
|
||||
|
||||
- `{slug}` 限 `[a-z0-9-]`;`{seq}` 两位零填充;`{title}` 限
|
||||
`[a-z0-9-]`(CJK 标题按 adapter 层编码规则处理)。
|
||||
|
||||
### 2.1 例外页(全枚举)
|
||||
|
||||
以下页名不受常规文法约束(勘自实例的全部真实约定):
|
||||
|
||||
| 例外页 | 形态 | 说明 |
|
||||
| -------------------- | ---------------------------------------------------------------------------------- | --------------------------------------------------- |
|
||||
| 评审轮次页 | `{slug}/reviews/{stage}/round{N}/{page}` | `page` ∈ `task-{ROLE}`、`revision-summary` |
|
||||
| 评审终报 | `{slug}/reviews/{stage}/final/report` | 含 DAG task 变体 `…/final/report-task-{node-id}` |
|
||||
| 验证报告 | `{slug}/05-verify-iteration-{N}` | 常规前缀 + 无 title 段的变体 |
|
||||
| 验证报告(里程碑) | `{epic-slug}/05-verify-milestone-{M-id}` | 同上 |
|
||||
| 验证报告(任务节点) | `{epic-slug}/05-verify-task-{node-id}` | 同上 |
|
||||
| DAG 工件 | `{epic-slug}/dag`、`{epic-slug}/dag-nodes/{node-id}`、`{epic-slug}/dag-coverage` | 单门 DAG 管线工件 |
|
||||
| DAG 共享契约 | `{epic-slug}/shared/{file}` | 跨会话契约 |
|
||||
| bugfix 附件 | `{slug}/repro-notes`、`{slug}/test-report`、`{slug}/bugfix-report`、`{slug}/ABORT` | 单段固定名 |
|
||||
| 原型/笔记 | `{slug}/prototype-debt`、`{slug}/spike-report`、`{slug}/impl-notes` | 单段固定名 |
|
||||
| 设计修订 | `{slug}/03-design-amendments` | 常规前缀 + 固定名 |
|
||||
| 浏览器证据 | `{slug}/verify/evidence/{name}` | 验证证据页 |
|
||||
| 审计轮次页 | `audit/{date}/round{N}/{page}` | 日期 slug 例外;`page` ∈ `synthesis`、`task-{ROLE}` |
|
||||
| 审计终报 | `audit/{date}/final/report` | 日期 slug 例外 |
|
||||
| 回顾报告 | `_retrospectives/{cycle-name}` | 跨 slug 命名空间例外 |
|
||||
| 技能评估 | `_evals/{skill-name}/{page}` | 评估命名空间例外 |
|
||||
| 移植工件 | `port-{name}/source-analysis/{file}`、`port-{name}/self-check` | 移植命名空间例外 |
|
||||
| 回顾归档 | `_archive/{slug}/…` | 归档命名空间例外 |
|
||||
|
||||
> 历史只读页名(旧管线产物,仍可读取):`{slug}/01-stakeholder-interview`、
|
||||
> `{slug}/02-requirements-index`、`{slug}/02-req-{seq:02d}-{title}`、
|
||||
> `{slug}/02-03-req-design`、`{slug}/03-design-{seq:02d}-{title}`、
|
||||
> `{slug}/03-adr-{NNNN}-{title}`、`{slug}/04-plan-index`、
|
||||
> `{slug}/04-plan-{seq:02d}-{title}`、`{slug}/roadmap/{page}`。
|
||||
|
||||
### 2.2 kind ↔ type 映射
|
||||
|
||||
| 工件类别(kind 语境) | 页名 `{type}` 段 |
|
||||
| --------------------- | ---------------------------------------------------------------- |
|
||||
| 验证报告 | `05-verify-iteration` / `05-verify-milestone` / `05-verify-task` |
|
||||
| 设计文档 | `03-design` / `03-adr` / `03-design-amendments` |
|
||||
| 计划文档 | `04-plan` |
|
||||
| 需求文档 | `02-req` / `02-requirements-index` |
|
||||
| 评审工件 | `reviews`(目录段,非前缀) |
|
||||
| DAG 工件 | `dag` / `dag-nodes` / `dag-coverage` |
|
||||
| 审计工件 | `audit`(日期前缀命名空间) |
|
||||
|
||||
## 3. Tier-1 ↔ Tier-2 映射
|
||||
|
||||
wiki 页 `{slug}/…` 与实例运行目录 `<runs-root>/{slug}/…`(Tier-1 本地
|
||||
结构化工件,见 Two-Tier 规则)按 slug 一一对应:
|
||||
|
||||
- 页 `{slug}/reviews/{stage}/round{N}/findings-{DIM}.json` ↔ 本地
|
||||
`<runs-root>/{slug}/reviews/{stage}/round{N}/findings-{DIM}.json`;
|
||||
- 页面正文承载 Tier-2 决策记录;原始发现、工作草稿留在 Tier-1 本地。
|
||||
|
||||
**文件名 URL 编码规则**:页名映射为本地文件名时 `/` → `%2F`
|
||||
(逆向解码同理);`.-` 尾缀是实例后端生成的 slug 产物,解码时剥除。
|
||||
|
||||
## 4. 双向链接不变量
|
||||
|
||||
1. **工件 ↔ 工单引用成对**:工件发布到工件库后,源工单侧必须有反向
|
||||
索引(工件索引评论);工单侧索引的每一行必须指向真实存在的工件。
|
||||
2. **单评论聚合**:一个源工单有且仅有一条工件索引评论,各技能只
|
||||
原位增改自己的行,绝不发第二条。
|
||||
3. **归档补全**:工单关闭时,关闭方 agent 原位编辑索引评论——加归档
|
||||
横幅、全部行重读优先级置 `ARCHIVE`;不删行、不改位置列。
|
||||
|
||||
## 5. adapter 义务
|
||||
|
||||
每个工单后端 adapter 必须实现三个操作:
|
||||
|
||||
- **parse** — 解析 ref 字符串为 `{backend, kind, owner, repo, id, anchor}`;
|
||||
- **resolve** — 把解析结果解析为该后端可调用的 API 形态(端点、工具名、
|
||||
参数),API 调用形态归 adapter 层,Core 不约束;
|
||||
- **validate** — 校验页名符合第 2 节文法(含例外枚举)。
|
||||
|
||||
页名规范是**后端中立契约**;仓里的共用解析器
|
||||
`script/resolve-artifact-ref.ts` 提供 parse 与页名/文件名编解码、
|
||||
Tier-1 路径预测的中立实现,adapter 可复用。
|
||||
@@ -0,0 +1,38 @@
|
||||
> Core 中立版(Increment 4 改写)。术语对照见 core/adapters/TERMINOLOGY.md;本组织实例表述见 dogfood 对应文件。
|
||||
|
||||
## Artifact-Index Guards (mandatory)
|
||||
|
||||
> Check-mechanized (injection-budget batch-3, [org-internal #3699]): guards
|
||||
> 1-3's checkable invariants run in the repo's artifact-index-check script
|
||||
> (`<artifact-index-check-cmd> <ticket>`, see the term mapping; exit 4 =
|
||||
> violation, `--json` summary; tolerant of wild archive-marker dialects).
|
||||
> This file is the normative definition, NOT in any `agents_md` injection
|
||||
> whitelist since 2026-08-29 — do not re-add; the checks run at write/close
|
||||
> time regardless. Full spec: Pattern 10 in the shared write-patterns doc —
|
||||
> this rule is its on-demand distill.
|
||||
|
||||
### 1. Legacy-prefix scan (never create a duplicate)
|
||||
|
||||
Before creating a `## 工件索引` comment, scan the issue's existing comments
|
||||
for the legacy prefix `## Pipeline 工件追踪表`. If found, UPGRADE it
|
||||
in place (edit, not create) and rename. NEVER create a second index comment
|
||||
(DEFECT-1 / [org-internal #1924]). Mechanized: reports the comment_id to edit.
|
||||
|
||||
### 2. Never-duplicate invariant (single-comment)
|
||||
|
||||
Exactly ONE index comment per source issue, maintained by in-place
|
||||
comment-edit via the ticket-backend comment API (reuse the same
|
||||
`comment_id`). Each skill adds/updates ONLY its own rows, never deletes
|
||||
another skill's rows. Mechanized: >1 prefixed comment (either prefix) →
|
||||
exit 4.
|
||||
|
||||
### 3. Archive-at-close (issue close → archive, by ANY closing agent)
|
||||
|
||||
When a source issue is CLOSED — by ANY agent, verify ran or not — the closing
|
||||
agent edits the index comment in place: (a) add the canonical archive banner
|
||||
(Pattern 10) ABOVE the table with the actual close date; (b) set EVERY row's
|
||||
重读 column to `ARCHIVE`. Do NOT delete rows or change 位置-column URLs;
|
||||
reversible in-place edit. Mechanized: closed-ticket marker + 重读
|
||||
completeness → exit 4. Sequence/actor notes: the issue-checklist-sync rule
|
||||
§ 归档动作; primary path `verify` Phase 5.6 (Verifier); verify-skipping routes
|
||||
(audit-only, documentation, standalone/bugfix) — the closing agent does it.
|
||||
@@ -0,0 +1,109 @@
|
||||
> Core 中立版(Increment 2 改写)。术语对照见 core/adapters/TERMINOLOGY.md;本组织实例表述见 dogfood 对应文件。
|
||||
|
||||
## Auto-approve stages
|
||||
|
||||
The `auto_approve` block in the instance config controls which pipeline gates
|
||||
the agent passes without asking the user. Stage identifiers are matched
|
||||
against the stage registry (harness 内建的阶段注册模块). Unknown or retired
|
||||
identifiers fall back to manual confirmation (fail-closed) with a one-time
|
||||
`auto_approve.unknown_stage` warning — copy ids verbatim from the table
|
||||
below.
|
||||
|
||||
## Scope boundary: `auto_approve` vs `permission`
|
||||
|
||||
Two **independent mechanisms** — confusing them is the most common
|
||||
"auto-approve isn't working" report:
|
||||
|
||||
- **`auto_approve`** gates **only the `question` tool** (pipeline decision
|
||||
questions; the harness 内建的自动批准判定模块); no effect on tool
|
||||
execution.
|
||||
- **`permission`** gates **tool / file-system operations** (`bash`, `read`,
|
||||
`write`, `external_directory`, …) and **never consults `auto_approve`**.
|
||||
`external_directory` defaults to ask, so outside-project prompts are
|
||||
expected even with every stage enabled.
|
||||
|
||||
**`auto_approve` does NOT suppress permission prompts — intentionally so.**
|
||||
To stop a permission prompt, change the matching `permission` rule or use the
|
||||
UI's "auto-accept permissions" toggle (browser-local, not the project
|
||||
`auto_approve` config).
|
||||
|
||||
| Stage | Gate | Risk |
|
||||
| --------------- | ---------------------------- | -------------------------------------------- |
|
||||
| `review-dag` | DAG single-gate review | Medium — sets direction |
|
||||
| `review-code` | Code review | Medium — gates what reaches main |
|
||||
| `verify` | Iteration verification | Medium — runs tests / DoD matrix |
|
||||
| `audit-process` | Process infrastructure audit | Medium — read-only but gates process changes |
|
||||
| `merge-pr` | Create PR + merge to main | High — irreversible landing |
|
||||
|
||||
> Risk values mirror the stage registry's `BUILTIN_STAGES[].risk` — the
|
||||
> registry is the runtime authority; if this table and the registry disagree,
|
||||
> fix this table. `merge-pr` is excluded from default/preset `stages` arrays
|
||||
> (not structurally blocked; explicitly adding it is not recommended).
|
||||
> Legacy stage retirement (12 → 5): the phase-3 retirement ruling doc
|
||||
> (Tier-2 reference, reachable via the ticket backend).
|
||||
|
||||
Config shape: `"auto_approve": { "stages": ["review-code", "verify"], "stageless": false }` — `stages` empty (`[]`) = all manual; `stageless: true` also auto-approves questions called without a stage. Absent block defaults to `{ stages: ["review-code", "verify", "audit-process"], stageless: false }`; the removed `enabled` field migrates on load (mapping: Tier-2 reference page `rules/auto-approve-detail`). Presets (`safe`/`full`/`off`/`show`): same reference page — `full` never includes `merge-pr`.
|
||||
|
||||
### Stage matching behavior
|
||||
|
||||
- Question has a stage → auto-approved iff that stage is in `stages`.
|
||||
- Stageless question → auto-approved iff `stageless: true`; otherwise prompts.
|
||||
- `destructive: true` → ALWAYS prompts, regardless of config — the safety net
|
||||
for irreversible actions; business-decision questions are never covered by
|
||||
a stage whitelist (§"Mandatory destructive list").
|
||||
|
||||
Check logic: the harness 内建的问询与自动批准判定模块
|
||||
(resolveAutoApproveDecision).
|
||||
|
||||
### Live-gate degradation chain ([org-internal #3531])
|
||||
|
||||
An auto-approved question is NOT consumed instantly: L1 — a live human
|
||||
watching the session (SSE declaration / fresh presence ping) answers within
|
||||
`question_live_gate.timeout_sec` (default 600) and overrides the default;
|
||||
L2 — blocking questions with a `#<ticket>` title and a ticket-backend token
|
||||
fall back to a ticket comment answered as `**answer <question-id>** <label>`
|
||||
(default 3600s); L3 — auto default (first option, annotated
|
||||
`live-gate … → auto default`). `timeout_sec: 0` disables the whole gate
|
||||
(legacy instant default); `l2_timeout_sec: 0` disables only L2.
|
||||
`nonblocking: true` questions never reach L2/L3 — no live human → parked in
|
||||
the pending-answer queue, answered later from the console. Every final
|
||||
decision publishes a `question.degradation.routed` event.
|
||||
**`destructive: true` is untouched by the chain**: `decide()` rejects it
|
||||
before the gate runs (iron law).
|
||||
|
||||
### Mandatory destructive list (业务决策类问询强制清单)
|
||||
|
||||
Origin: [org-internal #3223] — a stage whitelist auto-answered two
|
||||
irreversible production data changes because nothing marked them
|
||||
`destructive`. A stage whitelist grants "execution gates may proceed
|
||||
uninterrupted"; it must NEVER grant "business decisions may be
|
||||
self-answered". `stage` names the pipeline phase, `destructive` names the
|
||||
business risk.
|
||||
|
||||
**Iron Law: a question whose recommended/executed action falls in ANY category
|
||||
below MUST be called with `destructive: true`. The auto-approve stage whitelist
|
||||
is never a substitute for human confirmation of these categories.**
|
||||
|
||||
1. **Merge / release landing** — merging a PR to main, cutting a tag or
|
||||
release, deploying/promoting to production (server-side auto-merge is a
|
||||
human-configured policy robot, never agent self-answer latitude; kill
|
||||
switch: the auto-merge-low-risk runbook, Tier-2 reference via the ticket
|
||||
backend).
|
||||
2. **Production database writes** — upsert/update/delete against production
|
||||
data stores, production data migrations, live-data backfills.
|
||||
3. **Billing / plan changes** — plan or tier migration, pricing/concurrency
|
||||
changes, anything touching billing state.
|
||||
4. **Org / tenant structure changes** — org or workspace migration, tenant
|
||||
topology changes, moving resources between orgs.
|
||||
5. **Deletion of durable resources** — deleting data, branches, worktrees,
|
||||
deployments, or any resource outside `/tmp` and session-scratch space.
|
||||
6. **Persistent config writes** — config changes that outlive the session
|
||||
(writing to the instance config file, the instance process-config area,
|
||||
deploy/systemd units, or other on-disk configuration consumed by other
|
||||
sessions/services).
|
||||
|
||||
This list is the floor, not the ceiling: any other irreversible
|
||||
business-visible decision also carries `destructive`. When in doubt, mark it —
|
||||
a redundant prompt costs one round-trip; an auto-approved production write can
|
||||
cost the data. Mirrored in the question tool's self-description for paths
|
||||
without L1 injection.
|
||||
@@ -0,0 +1,56 @@
|
||||
## Claim Discipline (mandatory)
|
||||
|
||||
Every status assertion about work — "tests pass", "build succeeds", "bug fixed",
|
||||
"work complete", "no regressions", "fully resolves" — is a CLAIM that requires
|
||||
FRESH evidence produced this turn. Confidence is not evidence; a prior run is
|
||||
not evidence; the change "looking right" is not evidence. Baseline testing
|
||||
showed agents asserting "tests pass, no regressions introduced" for changes
|
||||
whose tests were never run — this rule exists to stop that.
|
||||
|
||||
**Iron Law: NO COMPLETION CLAIMS WITHOUT FRESH VERIFICATION EVIDENCE.**
|
||||
|
||||
Before asserting any status, run the gate:
|
||||
|
||||
1. **IDENTIFY** — what exact command/output proves this claim?
|
||||
2. **RUN** — execute it fresh, this turn (do not recall a prior result).
|
||||
3. **READ** — the full output and exit code, not just the tail.
|
||||
4. **VERIFY** — does the output actually confirm the claim?
|
||||
5. **ONLY THEN** make the claim, and cite the evidence (`file:line`, test name,
|
||||
exit code, the command run).
|
||||
|
||||
**Red-flag language** — reword or remove unless you attach evidence: "should
|
||||
work", "probably", "seems to", "I'm confident", "fully tested", "comprehensive",
|
||||
"no regressions", "fully resolves", "works in all cases", "regardless of why",
|
||||
"exactly", and any expression of satisfaction ("Done!", "Great!", "Perfect!")
|
||||
uttered before verification has run.
|
||||
|
||||
**If you cannot run the proving command** (hypothetical/analysis task with no
|
||||
codebase, blocked environment): say so — "not verified; would require running X"
|
||||
— and downgrade the claim from assertion to hypothesis. An honest "unverified"
|
||||
beats a confident unevidenced claim.
|
||||
|
||||
This applies everywhere: commit messages, PR bodies, status reports, review
|
||||
conclusions, handoff summaries, and verbal confirmations to the user.
|
||||
|
||||
## Tool-failure honesty (never fabricate results)
|
||||
|
||||
The Iron Law above governs claims about work; this section governs the
|
||||
**source** of those claims. When a tool you need is unavailable, returns an
|
||||
error, returns empty, or you cannot otherwise access a required resource, you
|
||||
MUST report the failure honestly. NEVER fabricate, invent, or hallucinate a
|
||||
plausible-looking result to fill the gap.
|
||||
|
||||
- An honest "I could not call `gitea_wiki__get_page`, so I cannot review
|
||||
dimension Y" is always correct. An honest failure beats a confident fiction.
|
||||
- Producing a complete, specific-looking structured result — review JSON with
|
||||
findings, severity levels, and file references, all invented — without a
|
||||
successful tool call that supplies the evidence is a **critical defect**,
|
||||
more dangerous than aborting: the output looks credible but is entirely
|
||||
fictional and silently poisons every downstream decision.
|
||||
- This covers every tool-gated output: review findings, test results, file
|
||||
contents, API responses, search hits, metrics. If the tool did not return
|
||||
it, you do not know it — say so.
|
||||
|
||||
Origin: [org-internal #2115] root cause 5 / [org-internal #2118] — deepseek-v4-flash reviewers fabricated
|
||||
full review JSON when the `gitea_wiki__*` tools were unavailable to subagents.
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
## Code Graph First (mandatory)
|
||||
|
||||
Before any cross-file understanding or change, query the code graph first. Do
|
||||
NOT grep + read whole files to reconstruct relationships.
|
||||
|
||||
- **Session start**: run `codegraph_status` to confirm the graph is built; if
|
||||
empty, run `codegraph init -i` from the project root once. The graph persists
|
||||
and is reused for the whole session.
|
||||
- **Trust but verify stats**: `codegraph_status` can return a stale or partial
|
||||
snapshot. If counts look low, run `codegraph_status` again — codegraph
|
||||
auto-syncs on file changes (2s debounce via native OS file watcher).
|
||||
Do not run structural queries against a graph you suspect is incomplete.
|
||||
- **Structural questions** ("who calls / what depends on / where defined / what
|
||||
breaks if I change this") MUST use `codegraph_explore` (primary, for flows and
|
||||
surveys), `codegraph_search` (locate symbols), `codegraph_callers` (every call
|
||||
site).
|
||||
Do not piece relationships together from grep + read output.
|
||||
- **Reading an implementation**: use `read(filePath, symbol: "<name>")` to fetch
|
||||
only the target symbol's line range. Do not read an entire large file to see
|
||||
one function.
|
||||
- **grep is the fallback, not the default**: use grep only for fuzzy text the
|
||||
graph cannot answer (comments, string literals, config text). Use
|
||||
`codegraph_node` with `symbolsOnly: true` for a cheap structural overview instead of Glob.
|
||||
- **Delegate exploration**: prefer running graph + read inside an Explorer
|
||||
subagent and returning only `file:line` results and conclusions, to keep the
|
||||
main context lean.
|
||||
|
||||
## Per-worktree indexes (mandatory for worktree sessions)
|
||||
|
||||
The main checkout's `.codegraph/` indexes ONLY that tree. A git worktree lives
|
||||
outside the repo path, so nearest-`.codegraph/` resolution finds nothing under
|
||||
it — graph queries in a workflow worktree silently degrade to grep+read
|
||||
(the [org-internal #2561] / TD-006 gap).
|
||||
|
||||
- `script/session-worktree.sh create` and `script/scratch-worktree.sh create`
|
||||
build a per-worktree index automatically: `codegraph init -i <path>` runs in
|
||||
the background (best-effort — missing CLI, existing index, or init failure
|
||||
never blocks worktree creation). Set `CODEGRAPH_SKIP=1` to disable
|
||||
(selftests / CI).
|
||||
- Worktrees created BEFORE this hook landed have no index: run
|
||||
`codegraph init -i` once from inside them.
|
||||
- First query after creating a worktree may hit a still-building index; if
|
||||
results look empty, check `codegraph status` inside the worktree, then retry.
|
||||
- Kickoff readiness (`checkCodegraph`) checks `<root>/.codegraph/codegraph.db`
|
||||
per root, and `codegraph serve --mcp` resolves from the session's cwd — both
|
||||
pick the worktree's own index once it exists.
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
> Core 中立版(Increment 2 改写)。术语对照见 core/adapters/TERMINOLOGY.md;本组织实例表述见 dogfood 对应文件。
|
||||
|
||||
## Compaction Discipline (mandatory)
|
||||
|
||||
Context compaction keeps long pipelines inside the model's context window.
|
||||
Two mechanisms exist:
|
||||
|
||||
1. **Stage-boundary compaction** (main session / orchestrator) —
|
||||
capacity-driven [org-internal #2601]: compact at a clean stage boundary
|
||||
ONLY when a capacity trigger holds (below), not merely because the
|
||||
boundary was reached.
|
||||
2. **Round-boundary compaction** (multi-round reviews) — compact at every
|
||||
review round ≥ 2, after the round's state is persisted.
|
||||
|
||||
### Stage-boundary compaction (capacity-driven, [org-internal #2601])
|
||||
|
||||
The main session orchestrates the whole pipeline while delegating stages to
|
||||
subagents, but still accumulates their result summaries, planning reasoning,
|
||||
and todo state — over a full pipeline this can exhaust the context window.
|
||||
|
||||
**Rule — compact at clean boundaries only when capacity demands it.** Every
|
||||
stage persists its complete output to durable artifacts (Tier-2 artifact
|
||||
pages under `{slug}/…`, Tier-1 run workspace files) on completion. At each
|
||||
CLEAN boundary (artifacts written, next stage not yet dispatched), evaluate
|
||||
the triggers:
|
||||
|
||||
1. **Capacity trigger** — the harness's compaction recommendation has fired,
|
||||
context is near the threshold, or the agent observes context-pressure
|
||||
symptoms (truncation, degraded recall of earlier stage outputs).
|
||||
2. **Projection trigger** — the stages REMAINING on this route (skip list in
|
||||
the routing table) will not fit alongside the context already
|
||||
accumulated, based on per-stage growth observed so far.
|
||||
|
||||
A trigger holding → compact at the NEAREST clean boundary. No trigger → KEEP
|
||||
the context: preserved working context is worth more than the tokens it costs.
|
||||
|
||||
**Mixed capacity threshold — min(water_level, absolute cap)
|
||||
[org-internal #3321] / TD-434]**: the capacity threshold is
|
||||
`min(context × water_level, compaction.max_context_tokens)` — whichever is
|
||||
LOWER (`max_context_tokens` default 100_000; `0` restores pure water_level
|
||||
semantics [org-internal #3342]). On large windows the 100k cap binds first.
|
||||
Measurement basis: the provider's REAL reported usage (input tokens), not
|
||||
local estimates; the rendered guidance and the Trigger A/B overflow paths
|
||||
resolve the same normalized values (harness 内建的压缩引导模块, see the
|
||||
instance term mapping).
|
||||
|
||||
**Sub-session posture [org-internal #3321]**: Explorers compact by returning
|
||||
promptly, persisting only what their skill protocol REQUIRES (review findings
|
||||
JSON to the run workspace reviews directory). Workers persist outputs to
|
||||
Tier 1 BEFORE finishing. The parent context is where the mixed threshold
|
||||
applies. Tier 1 boundary: two-tier-artifacts rule.
|
||||
|
||||
**Short runs target zero intra-run compaction** — an implement →
|
||||
review-code → verify run fits one window; clean boundaries do not compact
|
||||
without a trigger. (Rationale + retired legacy stages: Tier-2 reference page
|
||||
`rules/compact-detail`, reachable via the ticket backend.)
|
||||
|
||||
Clean boundaries where triggers are evaluated (live skills):
|
||||
|
||||
- After `analyze-dag` completes (before the `review-dag` single gate)
|
||||
- After each `review-*` converges (before the next production stage)
|
||||
- After `implement` / `verify` completes (before its review or the next stage)
|
||||
|
||||
**Never compact mid-stage** — not mid tool-call cycle, not mid subagent
|
||||
dispatch. Compact only at clean boundaries where artifacts are already
|
||||
persisted.
|
||||
|
||||
**Re-orient after compacting** (recovery contract): compaction discards the
|
||||
in-conversation record of the current slug and stage. Before resuming,
|
||||
re-read the persisted recovery set — the Tier 1 compact-recovery entry
|
||||
`index.json` in the run workspace, the issue's `## 工件索引` CORE rows, the
|
||||
frozen DAG copy (`{epic-slug}/dag`, `{epic-slug}/dag-nodes/{node-id}`) for
|
||||
DAG-routed runs, the latest review pages, or the DoD matrix
|
||||
(`{slug}/05-verify-*`) — to recover the current slug, stage, and outstanding
|
||||
items. Do not rely on the compacted summary alone.
|
||||
|
||||
**Identity verification precedes re-orientation [org-internal #2459].**
|
||||
Every compacted summary opens with a harness-injected `### Session Identity`
|
||||
card (agent, role/mode/ticket, CORE artifact rows, role re-read set),
|
||||
rendered from role-yaml `compact.preserve` lists and issue CORE rows by the
|
||||
harness 内建的压缩引导模块 (renderIdentityInjection; preserve lines keyed
|
||||
through identityPreserveLines). Role yaml preserve lists are
|
||||
harness-enforced — recovery is always via the persisted artifact, never
|
||||
conversation memory. Verify the card against the durable record
|
||||
(title/purpose, issue assignee + claim, orchestrator id); on mismatch stand
|
||||
by and report, never act on the summary's identity claims.
|
||||
|
||||
### Round-boundary compaction
|
||||
|
||||
Multi-round review skills (`review-artifact`, `review-code`) compact at every
|
||||
round boundary ≥ 2. Canonical text: shared compaction-round-boundary doc
|
||||
(injected by both review skills); read it for the exact orchestrator
|
||||
procedure — do not restate.
|
||||
|
||||
### The `min_turns_since_compaction` guard applies everywhere
|
||||
|
||||
The `compact` tool rejects calls made too soon after the previous one
|
||||
(`compaction.agent.min_turns_since_compaction`, default **3** assistant
|
||||
turns); no boundary type is exempt. Beyond `insufficient_turns` the tool has
|
||||
more guard outcomes (`min_interval`, `no_model`, `circuit_breaker_open`,
|
||||
`disabled` — rejected; `compaction_in_progress`, `deduplicated` — deferred;
|
||||
full table: Tier-2 reference page `rules/compact-detail`, reachable via the
|
||||
ticket backend). All are accept-and-continue: never retry past a guard,
|
||||
never work around the dedup/breaker state. A boundary whose compaction was
|
||||
rejected or deferred simply keeps its context; the persisted artifacts still
|
||||
bound what accumulates.
|
||||
|
||||
### Role-level re-read set
|
||||
|
||||
Role YAML `compact.preserve` lists are harness-enforced: after any compaction
|
||||
the session agent's preserve lines are injected at the summary head; recovery
|
||||
is always via the persisted artifact, never conversation memory.
|
||||
@@ -0,0 +1,159 @@
|
||||
> Core 中立版(Increment 4 改写)。术语对照见 core/adapters/TERMINOLOGY.md;本组织实例表述见 dogfood 对应文件。
|
||||
|
||||
## Issue Checklist Sync (mandatory, progressive)
|
||||
|
||||
The source issue's checklist is the **stakeholder-facing progress tracker**.
|
||||
It MUST be kept in sync with actual work state at every pipeline milestone —
|
||||
not just at close time. Stakeholders should be able to open the issue at any
|
||||
point and see exactly what is done, in progress, and deferred.
|
||||
|
||||
### Sync points (progressive)
|
||||
|
||||
| When | Who | What |
|
||||
|------|-----|------|
|
||||
| After the DAG artifact is frozen (`review-dag` PASS + freeze confirmation per `analyze-dag/SKILL.md` §Output & Lifecycle step 2, [org-internal #3379]) | Aggregator agent | Convert the source Epic's draft acceptance criteria into a formal checklist; annotate requirement-covered items `_(DAG frozen: {epic-slug}/dag v1)_` |
|
||||
| After each iteration commit (`implement` Phase 4.5) | Developer | Check off items delivered by this iteration |
|
||||
| After a PR is created | Developer | Append a `## 当前状态` live-status section (or update it) with PR number + mergeable; in an Epic task list, append the PR reference to the corresponding row |
|
||||
| After code review converges (`review-code` PASS, Phase E) | Orchestrator | Check off review-related items; annotate `_(reviewed: round N PASS)_`; update the `## 当前状态` review row; label the PR `ready-to-merge` — keep-mergeable automation takes over (hand-written keep-mergeable commits are retired) |
|
||||
| On CI key state transitions (first green / failure / cumulative goal reached) | Verifier or Developer | Update the process-type AC (e.g. "N consecutive green runs") progress note in the issue; record the run number |
|
||||
| At `verify` Phase 5.6 (final sweep before PASS) / issue close | Closing agent (Verifier on the primary path; otherwise the last role that closes the issue) | Final sweep — every remaining item gets annotated; **archive-at-close**: fold `## 当前状态`, then mark the `## 工件索引` comment archived per the artifact-index-guards rule guard #3 (see「归档动作」below) |
|
||||
|
||||
> Historical ([org-internal #3072] phase 3): the requirements/design/plan exit sync points
|
||||
> were archived with their skills (detail: Tier-2 reference page
|
||||
> `rules/issue-checklist-sync-detail`, reachable via the ticket backend).
|
||||
|
||||
Between sync points the checklist stays as-is. **PR / review / CI
|
||||
transitions** MUST also be visible via the live status note below — the
|
||||
checklist is not the only carrier.
|
||||
|
||||
### Live status note (`## 当前状态`)
|
||||
|
||||
For flows with externally visible transitions between skill exits —
|
||||
standalone bugfix, incident response, long-running reviews — maintain a short
|
||||
live status table near the top of the issue body, updated in place via the
|
||||
ticket-backend issue-update API at the transition moment (closes the
|
||||
stale-issue gap [org-internal #1668]/[org-internal #1689]]).
|
||||
|
||||
All roles use the literal heading `## 当前状态` (no suffix). If an issue carries
|
||||
a legacy variant (e.g. `## 当前状态 (live)` from [org-internal #1668]), normalize it to
|
||||
`## 当前状态` at the first transition touched. Example table + legacy-variant
|
||||
list: Tier-2 reference page `rules/issue-checklist-sync-detail`, reachable
|
||||
via the ticket backend.
|
||||
|
||||
Rules:
|
||||
|
||||
- One row per externally visible transition. Skill-exit sync points are
|
||||
surfaced by checklist annotations alone — do NOT add live-status rows for
|
||||
them. PR / review / CI transitions carry BOTH a checklist annotation AND
|
||||
a live-status row.
|
||||
- **Stage rows live on the board, not here**: pipeline stage transitions are
|
||||
represented by the Pipeline Stages board column (shared write-patterns
|
||||
Pattern 7.5), NOT by `## 当前状态` rows. Keep only the
|
||||
status-sync-automated rows (PR / 代码评审 / CI) and non-stage
|
||||
blockers/deferrals.
|
||||
- Update in place (same section heading `## 当前状态`), never append a second copy.
|
||||
- Optional for quiet pipeline flows; **MANDATORY for incident-response and
|
||||
standalone-bugfix flows** (long windows without skill exits).
|
||||
- At verify PASS / issue close, fold the table's content into checklist
|
||||
annotations and remove the section (see the「归档动作」section below).
|
||||
|
||||
### Automated sync ([org-internal #1833], timer-polled since [org-internal #2813])
|
||||
|
||||
PR / review / CI status-row transitions are automated by the `status-sync`
|
||||
poller (deployed as a host timer, every 5 min; event sources + latency table
|
||||
on the Tier-2 reference page `rules/issue-checklist-sync-detail`, reachable
|
||||
via the ticket backend). Roles do NOT hand-write those three row types. A PR
|
||||
body may carry several close refs (batch PRs, [org-internal #3731]
|
||||
`land-batch`): rows fan out to EVERY referenced issue
|
||||
(`parseClosesFixesWide` — [org-internal #3867], merged 2026-08-31) — Chinese 关闭/修复 refs
|
||||
drive rows too, even though the ticket backend never auto-closes those
|
||||
keywords. The remaining sync points (checklist annotations at skill exits,
|
||||
`## 当前状态` creation, deferral/pending marking, section fold-at-close) are
|
||||
still manual (content judgment, not event detection). Fallback for poller
|
||||
outages / manual replay: the `status-sync` manual dispatch
|
||||
(`issue`/`row`/`value`) — the row-write engine is a no-op when the section
|
||||
or row is absent, never creates or corrupts them; poller failures file a
|
||||
deduplicated `[status-sync-cron]` issue.
|
||||
|
||||
### Standalone bugfix / incident flows
|
||||
|
||||
Pipeline mode has natural sync points at skill exits; standalone bugfix and
|
||||
incident flows do NOT — the only boundaries are commit → PR → review → CI →
|
||||
merge, and EACH is a sync point with the same annotations as the progressive
|
||||
table above (full table: Tier-2 reference page
|
||||
`rules/issue-checklist-sync-detail`, reachable via the ticket backend): fix
|
||||
commit → tick fix-delivered ACs `_(commit {sha}: file)_`; PR → open/update
|
||||
`## 当前状态`; review convergence → tick review ACs + review row; CI
|
||||
transitions → process-AC progress with run number; verify PASS / close →
|
||||
final sweep, fold `## 当前状态`, archive per「归档动作」.
|
||||
|
||||
### DAG-routed tickets — node checklist variant
|
||||
|
||||
For tickets routed through the DAG pipeline (see workflow-routing rule
|
||||
§"DAG 路由 (v2)"), the task-node checklist has a fixed shape (spec-08
|
||||
§1/§2/§3):
|
||||
|
||||
- **Task tickets (nodes) use a fixed 5-row checklist** + an optional 6th row:
|
||||
验收标准 / 依赖就绪 / PR / 评审(review-code) / CI — **fixed 5 rows, fixed
|
||||
order, no free additions**. The `verify里程碑` row exists ONLY when the node
|
||||
fans into a milestone.
|
||||
- **Row 6 close-time semantics**: if at ticket close the milestone is not yet
|
||||
green, keep `- [ ]` + `_(Pending: M-01 未 green)_` — mapped to **Pending**, not
|
||||
STALE, so it satisfies the Iron Law (no stale items at close). After milestone
|
||||
verify PASS the aggregator agent flips it to `- [x]` in place.
|
||||
- **Epic aggregator `## DAG 状态` vs `## 当前状态`**: `## DAG 状态` is the
|
||||
node-status aggregator table (one row per DAG node — never carries ARCHIVE);
|
||||
`## 当前状态` carries only PR / 评审 / CI rows (no stage rows).
|
||||
- **Archive rule unchanged**: the archive marker stays ONLY on the `## 工件索引`
|
||||
comment (single-comment invariant). The body aggregator table is kept as a
|
||||
historical snapshot at close and does NOT carry ARCHIVE.
|
||||
|
||||
### Kind/MVP tickets — exemption ([org-internal #3061])
|
||||
|
||||
`Kind/MVP` tickets run the interactive no-pipeline mode: no stage exits →
|
||||
**nothing to sync**, no `## 当前状态` section (no PR/review/CI rows until
|
||||
graduation). The body itself is the living document: `## 决策日志` is
|
||||
append-only (superseded decisions struck through, never edited); `## Debt
|
||||
Register` rows update in place. On graduation (relabel `Kind/Feature`) normal
|
||||
sync rules resume from the DAG route; the decision log stays as backfill input.
|
||||
|
||||
### Annotation format
|
||||
|
||||
- **Done** → `- [x]` + parenthetical evidence: `_(PR #NNN: file/component)_`
|
||||
or `_(commit {sha}: file)_` if no PR yet.
|
||||
- **Deferred** → keep `- [ ]` + `_(Deferred: TD-XXX <reason>)_`.
|
||||
- **Pending** → keep `- [ ]` + `_(Pending: <blocker>)_`.
|
||||
|
||||
### How to sync (each point)
|
||||
|
||||
Find the source issue (`Closes #N` / `Fixes #N` in the PR body or commit
|
||||
messages, `## 父级 / Parent` / roadmap chunk mapping, or the issue the user
|
||||
referenced; none exists → skip). Fetch the body, map each `- [ ]` item
|
||||
**relevant to this sync point** to evidence (`- [x]` + `_(PR #NNN: …)_` /
|
||||
`_(commit {sha}: file)_`), deferral, or pending — leave out-of-scope items
|
||||
untouched for a later point — and update in place, preserving all
|
||||
non-checklist content. PR / review / CI transitions ALSO go into the
|
||||
`## 当前状态` live-status section.
|
||||
|
||||
### 归档动作(issue 关闭 = 归档)
|
||||
|
||||
**生命周期 = 工单生命周期**([org-internal #1929]):文档生命周期与源 issue 绑定 —— verify PASS → issue 关闭 = 归档。Tier-2 工件库无独立生命周期。
|
||||
|
||||
归档是 **显式动作**,由关闭 issue 的 agent 执行:主路径为 Verifier 在 `verify` Phase 5.6;路径跳过 verify 时(audit-only、文档类、standalone/bugfix)由关闭 issue 的 role 代为执行。无论哪个 actor,均遵循 artifact-index-guards 规则 guard #3(机制以共享 write-patterns Pattern 10 为准)。动作序列:
|
||||
|
||||
1. **Checklist 终扫**(Phase 5.6 既有步骤 / closing agent 补执行):每个 `- [ ]` 项都被注解(done / deferred / pending)。
|
||||
2. **Fold `## 当前状态`**(Phase 5.6 既有步骤 / closing agent 补执行):表格内容折入 checklist 注解后移除该节。
|
||||
3. **标记 `## 工件索引` 归档**:按共享 write-patterns Pattern 10 Archive-at-close 原位 edit(机制以 Pattern 10 为准)。横幅日期以实际关闭日为准。
|
||||
4. **关闭 issue**:PR body 的 `Closes #N` 在 merge 时自动关闭;无 PR 的流程由 **关闭 issue 的 agent** 执行工单后端的 issue-close API 完成闭环。
|
||||
|
||||
约束([org-internal #1928] 设计约束;机制细节以共享 write-patterns Pattern 10 Archive-at-close 为准,此处不重复):
|
||||
|
||||
- **L 级大件(>~300 行)留 Tier-2 工件库不删除** —— 页面与位置列 URL 保持不动(稳定 URL 供历史与共享契约引用)。
|
||||
- **索引/状态/归档判定全部收敛到 issue** —— Tier-2 工件库无独立生命周期;归档标记只落在 `## 工件索引` 评论。
|
||||
- 归档标记可逆(原位 edit):PR 被拒 / issue 重开时恢复行级 重读 即可。
|
||||
|
||||
### Iron Law
|
||||
|
||||
NO ISSUE MAY BE CLOSED WITH STALE CHECKLIST ITEMS. If a checklist item
|
||||
cannot be mapped to evidence or deferral at verify time, the iteration is
|
||||
NOT done.
|
||||
@@ -0,0 +1,72 @@
|
||||
> Core 中立版(Increment 4 改写)。术语对照见 core/adapters/TERMINOLOGY.md;本组织实例表述见 dogfood 对应文件。
|
||||
|
||||
## Issue Cross-Linking (mandatory)
|
||||
|
||||
Traceability flows in two directions. Both MUST be maintained so a
|
||||
reviewer can start at any node — an issue or a Tier-2 artifact-library page —
|
||||
and navigate to every related artifact without asking.
|
||||
|
||||
### Issue ↔ issue (parent/child groups)
|
||||
|
||||
When creating a **group** of related issues — an Epic with phase/P-level
|
||||
sub-tasks, a roadmap decomposed into chunk tickets, a bug with a
|
||||
regression-test follow-up, or any parent/child breakdown — the issues MUST be
|
||||
cross-linked:
|
||||
|
||||
- **Parent issue**: after creating all children, update the parent body so its
|
||||
task list references each child by `#<number>` (e.g. `- [ ] [org-internal #1556] — [P0] ...`).
|
||||
The ticket backend renders these as clickable links and auto-generates a
|
||||
back-reference on each child's timeline.
|
||||
- **Child issue**: its body MUST contain a `## 父级 / Parent` section referencing
|
||||
the parent by `#<number>`.
|
||||
- Never create a group of issues that is only one-way linked or not linked at
|
||||
all. The parent task list is the single navigation hub.
|
||||
|
||||
### Issue ↔ Tier-2 artifact (pipeline traceability)
|
||||
|
||||
When a production skill (`analyze-dag`, publishing the `{epic-slug}/dag`
|
||||
artifact; historically the pre-[org-internal #3072] producer skills) publishes
|
||||
an artifact to the Tier-2 artifact library, the link to the source issue is
|
||||
only **half-built** — the library's index page links forward to the issue,
|
||||
but the issue has no link back to the library. A stakeholder opening the
|
||||
issue sees no path to the pipeline artifacts — the traceability chain is
|
||||
broken.
|
||||
|
||||
After publishing, the skill MUST complete the reverse link on the source issue:
|
||||
|
||||
- **Post / update the "## 工件索引" comment** (工件索引协议, per the shared
|
||||
write-patterns doc Pattern 10): a single in-place-edited comment (via the
|
||||
ticket-backend comment-create, then comment-edit API; NEVER post a
|
||||
duplicate; legacy prefix "## Pipeline 工件追踪表" is upgraded in place). One
|
||||
row per artifact: `{工件 | 类型 | 版本 | 位置 | 重读}` where **重读** ∈
|
||||
{`CORE`, `ON-DEMAND`, `ARCHIVE`}.
|
||||
- **The CORE rows ARE the compaction re-read set** — after `compact`, recovery
|
||||
reads the 工件索引 comment and fetches every CORE row's 位置 (shared
|
||||
read-patterns doc Pattern 6), instead of hard-coded library paths. Skills'
|
||||
re-read instructions therefore point at the index.
|
||||
- **Archive-at-close(归档动作, [org-internal #1929]/[org-internal #1928])** — issue 关闭即归档;Tier-2 工件库无独立
|
||||
生命周期。`ARCHIVE` is not just a per-row re-read priority: at issue close the
|
||||
whole index is marked archived by the closing agent (Verifier at `verify`
|
||||
Phase 5.6 on the primary path; otherwise the Orchestrator / last-role that
|
||||
closes the issue) via in-place edit. The mechanism (banner + every row's
|
||||
重读 → ARCHIVE, single-comment invariant, rows/位置 URLs never deleted,
|
||||
L-level library artifacts keep stable URLs) is defined once in the shared
|
||||
write-patterns doc Pattern 10 Archive-at-close — reference it, do not
|
||||
restate. Sequence and actor: the issue-checklist-sync rule § 归档动作.
|
||||
- **Sync the issue's checklist** per the issue-checklist-sync rule for the
|
||||
matching exit point (live: the DAG-freeze sync point after `review-dag`
|
||||
PASS; the legacy requirements-exit / design-exit / plan-exit points were
|
||||
retired with their skills, [org-internal #3072] phase 3).
|
||||
- Skip if no source issue exists (no `Closes #N` / `Fixes #N` / roadmap chunk
|
||||
mapping ties this slug to an issue).
|
||||
|
||||
**Size/S & Size/M exception ([org-internal #1832]) — RETIRED (2026-08-21, [org-internal #3072]
|
||||
phase 3)**: retired with the legacy producer skills and the `sizing:` block.
|
||||
Historical indexes pointing at in-issue artifacts (`位置 = #comment-{id}`)
|
||||
remain valid, readable locations; new artifacts publish where their live
|
||||
skill/route puts them (DAG: library page `{epic-slug}/dag` etc.; MVP: ticket
|
||||
body).
|
||||
|
||||
Authoritative implementation patterns: shared write-patterns doc Pattern 3
|
||||
(issue↔issue) and Pattern 10 (issue↔artifact index) under the skills'
|
||||
shared-artifacts directory.
|
||||
@@ -0,0 +1,115 @@
|
||||
> Core 中立版(Increment 4 改写)。术语对照见 core/adapters/TERMINOLOGY.md;本组织实例表述见 dogfood 对应文件。
|
||||
|
||||
## Session Scope Guard (mandatory)
|
||||
|
||||
> Enforcement layer: precheck-mechanized (injection-budget batch-2,
|
||||
> [org-internal #3667]) — pre-flight sources 1-3 below live in the repo's
|
||||
> session-conflicts script, source 4 in the claim script's compare-and-swap.
|
||||
> This file is the normative definition, NOT part of any `agents_md`
|
||||
> injection whitelist since 2026-08-29 — do not re-add; the checks run at
|
||||
> claim time regardless.
|
||||
|
||||
Standalone and ticket-seeded sessions run without a pipeline around them —
|
||||
no plan, no reviewer keeping them inside their work item. When such a
|
||||
session hits a test failure NOT caused by its own change ([org-internal
|
||||
[org-internal #1803]], via [org-internal #1753]/[[org-internal #1744]]), it tends to fix the foreign
|
||||
failure in place (drifting off-task), and sessions seeded for the same issue
|
||||
collide on the same shared flaky test.
|
||||
|
||||
**Iron Law: if a test fails and it was NOT caused by your change, you MUST
|
||||
classify → file → continue. Do NOT fix it in place — unless that test IS your
|
||||
task.**
|
||||
|
||||
### The classify → file → continue protocol
|
||||
|
||||
1. **Classify** — rerun the failing test on the base commit / last-green:
|
||||
fails there too → **baseline failure (BF)**; intermittent across runs →
|
||||
**flaky test (FT)**; fails only with your change → **your regression** —
|
||||
fix it now.
|
||||
2. **File** — register every BF/FT as an issue in the ticket backend labeled
|
||||
`baseline-failure` or `flaky-test` with a `BF-NNN` / `FT-NNN` id, per the
|
||||
testing rule. Deduplicate against an existing BF/FT issue (comment your
|
||||
run evidence instead of filing a twin).
|
||||
3. **Continue** — return to your assigned task; cite the BF/FT issue number
|
||||
in your report / PR body so the next session sees it is owned.
|
||||
|
||||
A foreign failure does not block your task, but the task is NOT done until
|
||||
the failure is filed — an un-filed BF/FT is a process gap. Filing is the
|
||||
whole job: **the fix belongs to whoever owns that test**, not to you.
|
||||
|
||||
### One task, one owner — check before you start
|
||||
|
||||
Before starting work on an issue or code area, you MUST verify no other
|
||||
session already owns it. The pre-flight check spans four sources — (1) live
|
||||
sessions referencing `#N`, (2) a workflow branch already covering #N
|
||||
(worktrees, local branches, remote `workflow/*` refs), (3) an open PR
|
||||
referencing `#N`, (4) assignee + claim comment naming another owner. A hit
|
||||
on ANY source → the ticket is already owned: ABORT (or, for a DEAD claim,
|
||||
take over via the mechanized channel below; otherwise coordinate on the
|
||||
issue), never silently start a second owner.
|
||||
|
||||
**Mechanized ([org-internal #3667])**: the repo's session-conflicts script
|
||||
(`<session-conflicts-cmd> <ticket>`) scans sources 1-3 in one read-only pass
|
||||
(exit 4 = conflict, matching the claim script; source 1 fail-opens visibly
|
||||
when the app API is down — the backend hard guard [org-internal #1989]
|
||||
backstops); source 4 IS the claim script's compare-and-swap. Dead-claim
|
||||
takeover is mechanized in the claim script (see below); manual recipes:
|
||||
the headless-session-ops skill's ticket-recipe reference §0.
|
||||
|
||||
**Dead-claim takeover ([org-internal #3668]).** A claim whose session is
|
||||
gone (404 on the app API) and whose branch was never pushed is a DEAD claim
|
||||
— the [org-internal #3419] shape. Do NOT hand-edit the dead claim comment
|
||||
(the retired admin workaround — unauditable); run the claim script's
|
||||
takeover subcommand (`<claim-takeover-cmd> <ticket> <branch> --session-id
|
||||
<id>`) instead. Evidence rule (the claim script's header is normative): a
|
||||
competing claim is dead iff its named branch is ABSENT on the remote AND
|
||||
(its session 404s OR the comment is at least `CLAIM_TAKEOVER_STALE_DAYS`
|
||||
old — age >= the threshold, default 3d). Evidence holds → one atomic
|
||||
takeover: assignee re-set + a `**claim**` comment carrying
|
||||
`supersedes-claim #<id>` markers and the inline evidence (auditable chain,
|
||||
nothing edited) + branch push, with post-posting race re-verification.
|
||||
Evidence fails (session alive, branch pushed = completed claim, or fresh
|
||||
claim with unknown liveness) → exit 10, zero mutation — coordinate on the
|
||||
issue or salvage the worktree instead. A valid claim is never superseded.
|
||||
|
||||
**Claim-first (atomic 3-step claim).** The FIRST action when starting
|
||||
ticket-driven work is to claim the ticket — one atomic action of THREE
|
||||
steps, valid ONLY when all complete: (1) set the issue assignee to the
|
||||
working account, (2) post a claim comment naming the workflow branch and
|
||||
session id, (3) push the workflow branch to remote (even an empty commit —
|
||||
a purely local branch is invisible to other sessions, [org-internal
|
||||
[org-internal #2280]/[org-internal #2282]]). Use the repo's claim wrappers (staged-transaction claim
|
||||
script; exit codes and CAS semantics in its header; non-zero = NOT claimed)
|
||||
and the provision wrapper (adds the worktree + Tier-1 runs scaffold). The
|
||||
manual 3-step is the fallback where the scripts are unavailable, same
|
||||
re-verification.
|
||||
|
||||
**Merge-time equivalence check.** Before merging, scan the remote main
|
||||
branch's recent commits for `#<ticket>` — surfacing an equivalent
|
||||
implementation already on main *before* the merge rejection.
|
||||
|
||||
**Merge-time review gate ([org-internal #2345]).** `pipeline/review-code` is
|
||||
a required status: merge needs it green OR the route-based exemption
|
||||
(Kind/* close routes skip review-code — posted by the repo's
|
||||
review-gate-exemption script). Read the commit-status endpoint for the PR
|
||||
SHA: `success` + `review not required (route:` description → route
|
||||
exemption, proceed; `success` otherwise → proceed; missing / `error` /
|
||||
`pending` / other → BLOCK — a missing status never approves.
|
||||
|
||||
**Epic ownership table.** Multi-chunk parallel Epics keep a chunk →
|
||||
session/account ownership table on the parent issue — consult it and claim
|
||||
your chunk before starting.
|
||||
|
||||
Two sessions owning the same issue or code area is never faster — it is the
|
||||
exact collision this rule prevents. If a collision HAS happened, follow the
|
||||
failure-path playbook at the ownership-collision runbook (Tier-2 reference
|
||||
page, reachable via the ticket backend).
|
||||
|
||||
### Scope
|
||||
|
||||
Applies semantically to **every session** — pipeline subagents (Producer /
|
||||
Verifier / Reviewer / Tool) and standalone/ticket-seeded sessions alike;
|
||||
for subagents, "your task" is the delegated prompt's scope, and classify →
|
||||
file → continue applies unchanged. Filing rides the testing rule;
|
||||
launch-time owner checks live in the headless-session-ops skill (which
|
||||
points here). This file stays the normative definition — read on demand.
|
||||
@@ -0,0 +1,113 @@
|
||||
## Stash Discipline (mandatory)
|
||||
|
||||
> Enforcement layer: **L0 tool-enforced** (bash guard + husky hooks) — this
|
||||
> file is reference/documentation, NOT part of any `agents_md` per-turn
|
||||
> injection whitelist since the 2026-08-27 injection-budget batch-1. Do not
|
||||
> re-add it to a whitelist; the guard enforces regardless.
|
||||
|
||||
In the octopus worktree model, multiple parallel sessions share a single git
|
||||
repository. The git **stash stack is repository-global** (`stash@{0}`,
|
||||
`stash@{1}`, …) and is NOT isolated per worktree. When two sessions in
|
||||
different worktrees run `git stash` / `git stash pop`, they silently index
|
||||
each other's entries and one session's `pop` returns the other session's
|
||||
content — or `drop`/`clear` wipes uncommitted work belonging to a session in
|
||||
a different worktree.
|
||||
|
||||
This failure mode has already destroyed completed work in production ([org-internal #1655] /
|
||||
[org-internal #1629] — a finished 25-test implementation overwritten on the shared stack).
|
||||
|
||||
**Iron Law: NEVER use `git stash` (or `git stash pop` / `push` / `drop` /
|
||||
`clear` / `apply`) inside an octopus worktree.**
|
||||
|
||||
The bash tool enforces this at L0 via a safety-floor pattern that blocks
|
||||
`git stash` invocations. Use one of the following instead — they are
|
||||
worktree-local and cannot be clobbered by a parallel session:
|
||||
|
||||
### Approved alternatives
|
||||
|
||||
1. **WIP commit on the current workflow branch** (preferred for
|
||||
mid-iteration checkpoints):
|
||||
|
||||
```bash
|
||||
git add -A
|
||||
git commit -m "wip: <slug> — <one-line state>"
|
||||
# … later, before the real commit:
|
||||
git reset --soft HEAD~1 # un-commit but keep the work staged
|
||||
```
|
||||
|
||||
The per-iteration commit model already expects these to be cleaned up by
|
||||
amend / interactive rebase before merge, so a `wip:` commit is never a
|
||||
long-term smell.
|
||||
|
||||
2. **Throwaway side branch** (preferred when you must switch branches and
|
||||
cannot commit yet):
|
||||
|
||||
```bash
|
||||
git switch -c wip/<slug>-<topic>
|
||||
git add -A && git commit -m "wip: <slug> — <one-line state>"
|
||||
git switch - # back to the workflow branch
|
||||
# … later:
|
||||
git cherry-pick wip/<slug>-<topic> # or merge / reset as needed
|
||||
git branch -D wip/<slug>-<topic>
|
||||
```
|
||||
|
||||
3. **`git diff > /tmp/octopus/<slug>.patch`** (last resort, when even a WIP
|
||||
commit is impossible — e.g. the index is in a conflicted state you do not
|
||||
want to disturb):
|
||||
|
||||
```bash
|
||||
git diff --binary > /tmp/octopus/<slug>.patch
|
||||
git apply /tmp/octopus/<slug>.patch # restore later
|
||||
```
|
||||
|
||||
Keep the patch under `/tmp/octopus/` so it survives the session but is
|
||||
never accidentally committed (see wiki page `rules/temp-files`, L2
|
||||
on-demand).
|
||||
|
||||
### What about switching away from a dirty tree?
|
||||
|
||||
If you must `git checkout <base>` to reproduce a failure but the worktree is
|
||||
dirty, do **not** reach for stash. Instead:
|
||||
|
||||
- WIP-commit first (option 1), or
|
||||
- Use the lifecycle-managed scratch-worktree script ([org-internal #2790]) to materialise
|
||||
the base commit in a *separate* worktree and run the failing test there:
|
||||
|
||||
```bash
|
||||
bash script/scratch-worktree.sh create <slug>-base <base>
|
||||
bash script/scratch-worktree.sh remove <slug>-base
|
||||
```
|
||||
|
||||
This is the pattern the `verify` skill uses for the regression-vs-baseline
|
||||
classification check. The script registers the worktree, symlinks
|
||||
`node_modules` from the source checkout when `bun.lock` matches, and the
|
||||
`sweep` backstop reclaims worktrees abandoned by dying sessions — bare
|
||||
`git worktree add /tmp/octopus/...` has no such recovery ([org-internal #2790]).
|
||||
|
||||
### Exceptions
|
||||
|
||||
- Running `git stash list` / `git stash show` to *inspect* the stack (no
|
||||
mutation) is allowed — it cannot lose work. The safety-floor pattern only
|
||||
blocks mutating subcommands (`push`, `pop`, `apply`, `drop`, `clear`,
|
||||
`create`, `store`, `branch`, and bare `git stash`).
|
||||
- The TUI's **prompt stash** (`prompt.stash` keybind, `usePromptStash`) is
|
||||
unrelated — it stashes *input text* in memory, not git refs, and is not
|
||||
affected by this rule.
|
||||
|
||||
### Enforcement
|
||||
|
||||
- **L0 (tool-enforced)**: `packages/octopus/src/tool/bash.ts` adds
|
||||
`/\bgit\s+stash\b(?:\s+(?:push|pop|apply|drop|clear|create|store|branch)|\s*$)/`
|
||||
to `SAFETY_FLOOR_PATTERNS`. Safety-floor items cannot be unblocked via
|
||||
configuration; bypass requires `--no-security-config`.
|
||||
- **L1 (this file)**: reference documentation only — removed from every
|
||||
`agents_md` injection whitelist (2026-08-27, see header); the L0 guard
|
||||
enforces regardless.
|
||||
- **L2 (skills)**: any skill that suggests `git stash` is a defect — file it
|
||||
under Kind/Enhancement with the `retrospective` label (`verify` SKILL.md
|
||||
already uses `script/scratch-worktree.sh` instead).
|
||||
|
||||
If a parallel-session stash collision happens again despite this rule, treat
|
||||
it as a Sev-2 process incident: stop work, recover via
|
||||
`git fsck --unreachable` / `git log -g --walk-reflogs stash`, open a follow-up
|
||||
referencing [org-internal #1655].
|
||||
@@ -0,0 +1,145 @@
|
||||
> Core 中立版(Increment 2 改写)。术语对照见 core/adapters/TERMINOLOGY.md;本组织实例表述见 dogfood 对应文件。
|
||||
|
||||
## Testing
|
||||
|
||||
- Avoid mocks as much as possible
|
||||
- Test actual implementation, do not duplicate logic into tests
|
||||
- Tests cannot run from repo root (guard: `do-not-run-tests-from-root`); run from package dirs.
|
||||
- **Local pre-check: run `<test-cmd:changed>`** from the owning package after editing source. It selects only tests affected by your uncommitted + branch changes (path-mapping ∪ CodeGraph direct dependents) and runs them in a single process — seconds, machine stays responsive. Use `--print` to see the selection without running, `--all` to scan beyond the home package.
|
||||
- **Before a delivery push: `<test-cmd:changed>` green + `<typecheck-cmd>` clean** — same selector as CI's PR side (local parity, [org-internal #4425]). The full suite (`<test-cmd:parallel>`) stays with nightly / `run-full-tests` / manual pre-merge runs. 实例命令绑定见 core/adapters/TERMINOLOGY.md。
|
||||
- Never use the bare single-process test runner for the full suite; `<test-cmd:parallel>` shards it and process-isolates known-corrupting files. Parallelism is controlled by `TEST_SHARDS` (default 3; raise it on beefy CI runners, e.g. `TEST_SHARDS=7`).
|
||||
|
||||
### Pre-existing test failures must be filed, not silently logged
|
||||
|
||||
When the full suite surfaces a failure that is **NOT caused by the current
|
||||
change** (it reproduces on the base branch / last-green commit too), it is a
|
||||
**pre-existing / baseline failure**. Do NOT silently drop it as "someone else's
|
||||
problem" and do NOT bury it in a report body.
|
||||
|
||||
- Classify it: run the failing test on the base commit (see `verify` Phase 2.6).
|
||||
Fails there too → pre-existing (BF); passes there → regression you must fix.
|
||||
- De-duplicate BEFORE filing (retro [org-internal #2696]): search existing
|
||||
`baseline-failure` tickets — open AND closed — by test/file name to surface
|
||||
candidates, then match by **failure signature** (error signature + affected
|
||||
surface — one root-cause family may span several tests; see the
|
||||
ticket-lifecycle rule §"BF / FT family umbrellas"). On a signature hit,
|
||||
attach run evidence to the family umbrella; do NOT create a new ticket.
|
||||
- File it: the Verifier registers every un-tracked pre-existing failure as a
|
||||
ticket-backend issue labeled `baseline-failure` with a `BF-NNN` id (`verify`
|
||||
Phase 5.55). The number is repo-wide sequential: highest existing NNN across
|
||||
ALL `baseline-failure` tickets (open AND closed) + 1 — duplicate ids
|
||||
forbidden, including against closed tickets.
|
||||
- A pre-existing failure does not block the iteration that *discovered* it, but
|
||||
the iteration is NOT Done until it is filed — an un-filed baseline failure is
|
||||
a process gap.
|
||||
|
||||
### Flaky tests must be filed, not silently tolerated
|
||||
|
||||
When a test passes and fails intermittently across runs (non-deterministic),
|
||||
it is a **flaky test**. Do NOT silently re-run until it passes and move on.
|
||||
|
||||
- Detect: re-run the suite (or use the project's flaky detector). Record every
|
||||
test that shows intermittent behavior — name, failure rate, and run count.
|
||||
- De-duplicate BEFORE filing (retro [org-internal #2696]): same
|
||||
signature-based procedure as baseline failures above, against existing
|
||||
`flaky-test` tickets.
|
||||
- File it: the Verifier registers every un-tracked flaky test as a
|
||||
ticket-backend issue labeled `flaky-test` with an `FT-NNN` id (`verify`
|
||||
Phase 5.56). `FT-NNN` allocation follows the same repo-wide sequential rule
|
||||
as `BF-NNN`, across ALL `flaky-test` tickets (open AND closed).
|
||||
- A flaky test does not block the iteration verdict, but the iteration is NOT
|
||||
Done until every unfixed flaky test is filed — an un-filed flaky test is a
|
||||
process gap.
|
||||
|
||||
**Filing is the whole job.** If the failure was NOT caused by your change, do
|
||||
NOT fix it in place — classify, file, and return to your task per the
|
||||
session-scope-guard rule. A repository-wide flaky test is a shared magnet —
|
||||
fixing it in place drifts off-task and collides with its owner
|
||||
([org-internal #1803]).
|
||||
|
||||
### Testing Kobalte components with happydom
|
||||
|
||||
Kobalte's portal/context-based components (Collapsible, DropdownMenu, ContextMenu,
|
||||
FormControlContext) do not work reliably under happydom's DOM environment. For
|
||||
these components, use **source-verification tests** — assert that the correct
|
||||
JSX elements, props, and Kobalte primitives are present in the component's
|
||||
source rather than attempting full DOM rendering.
|
||||
|
||||
When implementing a component that uses these Kobalte primitives, prefer
|
||||
source-verification over render tests. The same applies to SolidJS SVG
|
||||
`<filter>`/`<mask>`/`<linearGradient>` elements, which happydom also cannot
|
||||
render reliably.
|
||||
|
||||
### Test file naming convention (one file per component)
|
||||
|
||||
A single component MUST NOT carry both a `.test.ts` and a `.test.tsx` test
|
||||
file — the two-file split duplicated ~3300 lines of overlapping assertions
|
||||
across one UI package [org-internal #1712]. Use exactly one file per
|
||||
component, chosen by test style:
|
||||
|
||||
| Test style | Extension | When to use |
|
||||
| -------------------------------- | -------------- | -------------------------------------------------------------- |
|
||||
| Source-verification | `.test.ts` | Kobalte portal/context components, SVG `<filter>`/`<mask>`/`<linearGradient>` components, and any component happydom cannot render reliably. Asserts against the component source. |
|
||||
| DOM render / interaction | `.test.tsx` | Pure Solid components that render cleanly under happydom. Uses a testing-library harness. |
|
||||
|
||||
Rules:
|
||||
|
||||
- One file per component. If a component needs both source-verification and
|
||||
DOM-render assertions, keep them in a single file matching the dominant
|
||||
style; do not split into a `.test.ts`/`.test.tsx` pair.
|
||||
- When merging an existing dual pair, carry over any assertion unique to the
|
||||
deleted file into the surviving file before deletion.
|
||||
- The app package's `.sv.test.*` suffix is a separate convention for
|
||||
storybook/storyshots source-verification and is unaffected.
|
||||
|
||||
### Source-verification assertion boundaries
|
||||
|
||||
Source-verification tests (per the Kobalte/happydom carve-out above) must assert
|
||||
**structural contracts**, not implementation literals.
|
||||
|
||||
- **Assert**: props wiring, event handler attachment, i18n key presence, ARIA
|
||||
role/attributes present in JSX, namespace correctness, export shape.
|
||||
- **Do NOT assert**: exact source-string literals (`event.preventDefault()`,
|
||||
`'block: "nearest"'`, `event.movementX === 0`), branch operators counted via
|
||||
regex, or any expression that changes when a constant is renamed.
|
||||
- **Do NOT write tautologies** — `source.includes("false") || source.includes("!")`
|
||||
is true for nearly all TSX.
|
||||
- **One source-verification file per component** (see naming convention above).
|
||||
When two test files read the same source, merge into one.
|
||||
- **Prefer behavioral tests** — when source-verification and a behavioral/
|
||||
interaction test cover the same contract, prefer the behavioral test;
|
||||
collapse the SV duplicate.
|
||||
|
||||
### Namespace gate and test assertions
|
||||
|
||||
The namespace gate (pre-commit hook + the check-namespace script) scans ALL
|
||||
string literals in `.ts`/`.tsx`/`.json` files under the product packages for a
|
||||
reserved vendor namespace. Do NOT write test assertions containing that
|
||||
namespace literal — the gate cannot distinguish a test's namespace-absence
|
||||
check from an actual namespace violation, and will fail the commit.
|
||||
|
||||
Instead, use patterns that avoid the literal:
|
||||
```ts
|
||||
const NAMESPACE = "vendor-prefix"
|
||||
expect(source).not.toContain(`@${NAMESPACE}`)
|
||||
```
|
||||
|
||||
### Single test root (per package)
|
||||
|
||||
Each package MUST have exactly ONE test root — no parallel tracks
|
||||
(`src/**/__tests__/`, a `tests/` dir alongside colocated `src/`, or a `test/`
|
||||
alongside `tests/`); a second root drifts and breaks test discovery
|
||||
([org-internal #1711], extended to all packages by [org-internal #1821]).
|
||||
|
||||
Rules:
|
||||
|
||||
- New tests: create them at the package's single root from the start.
|
||||
- Do NOT create `src/**/__tests__/` directories in any package — parallel
|
||||
tracks drift (residuals eliminated by [org-internal #1821]).
|
||||
- For `test/`-root packages: mirror the `src/` path (`test/<src-relative>.test.ts`);
|
||||
type-level tests live alongside the behavioral suites in the config area.
|
||||
- For colocated-root packages: keep tests next to the source file; one test
|
||||
file per component [org-internal #1712].
|
||||
|
||||
Per-package root tables live in the instance layer (they name concrete
|
||||
package paths); the invariant itself — ONE root per package — is universal.
|
||||
@@ -0,0 +1,98 @@
|
||||
> Core 中立版(Increment 2 改写)。术语对照见 core/adapters/TERMINOLOGY.md;本组织实例表述见 dogfood 对应文件。
|
||||
|
||||
## Ticket Lifecycle — registry-first filing, claim-to-promote ([org-internal #3002] G1)
|
||||
|
||||
Bugs worth fixing start life as a **registry row**, not an independent ticket.
|
||||
This extends the two-tier-artifacts philosophy to the ticket queue: a
|
||||
"discovery" (no consumer yet, lifecycle undetermined) is Tier-1-shaped — a
|
||||
cheap row in a ledger — and is **promoted** to a Tier-2 independent ticket
|
||||
only when someone schedules or picks it up. (Filing one ticket per discovery
|
||||
is how the 2026-08 backlog formed.)
|
||||
|
||||
### The registry (登记册)
|
||||
|
||||
- **Where**: a `## TD 登记` comment on the **source ticket** (the ticket whose
|
||||
verify/review produced the candidates; a ticket-backend issue comment).
|
||||
No source ticket (standalone iteration) → the owning Epic's tracker
|
||||
ticket; no Epic either → the standing TD 冷存档 tracker ticket (G2's
|
||||
fallback archive target).
|
||||
- **Row format** (one line per item, checkbox-closeable):
|
||||
|
||||
```markdown
|
||||
- [ ] TD-{NNN} · {type: UNVERIFIABLE|ACCEPTED_RISK|DEFERRED|INFO} ·
|
||||
{severity: HIGH|MEDIUM|LOW} · {origin chunk-id/iter-N} — {one-line summary}
|
||||
· trigger: {objectively verifiable reactivation condition}
|
||||
```
|
||||
|
||||
- **TD-NNN** is allocated at REGISTRATION via the ledger mutex
|
||||
[org-internal #3322]: the 配额账本脚本 (`td-alloc` 形态, `bash <alloc-script>
|
||||
<count> <source-slug> [--ticket N]`) takes a contiguous range from the TD
|
||||
allocation ledger (a standing tracker issue) — append-only `**td-alloc**`
|
||||
comments, earliest-comment-id wins on collision. **ANY allocation — manual
|
||||
included — must land a td-alloc comment on the ledger BEFORE the registry
|
||||
row is written** (script, tool API, or web UI). Hand-computed `max + 1`
|
||||
without a ledger comment is FORBIDDEN (parallel-session races,
|
||||
[org-internal #3322]). The id is **reserved for life**: promotion reuses
|
||||
it, never renumbers. Run the alloc script's `--check` (reconciliation)
|
||||
when the last check predates this batch, and in retrospectives.
|
||||
- **De-duplication** queries the TD index (same-source rows) plus open
|
||||
promoted issues (cross-source); index matching replaces title-keyword
|
||||
matching (keyword dedup once produced 18 fragments from one source).
|
||||
- **Query-failure ruling ([org-internal #3383]: fail-open, visible)**: if the
|
||||
dedup query itself errors (backend API failure — NOT "queried and found no
|
||||
match"), retry once; on second failure file anyway, marking the comment
|
||||
`dedup-unverified` for retro/reconciliation sweep. Fail-closed rejected:
|
||||
known dedup failures are match failures it cannot prevent, and a backend
|
||||
hiccup would block a verify PASS gate.
|
||||
|
||||
### Promotion (认领升票)
|
||||
|
||||
A row is promoted to an independent ticket when **scheduled or picked up**
|
||||
(assigned, pulled into a wave/sprint, or chosen):
|
||||
|
||||
1. Create the ticket (ticket backend 立案) with the row's reserved `TD-NNN`
|
||||
(full body per the verify skill's promotion template).
|
||||
2. Tick the registry row (`- [x]`) and append `→ #NNNN` to it.
|
||||
3. The new ticket's `## Parent` points back at the registry's source ticket.
|
||||
|
||||
Unpromoted rows are not second-class: the registry comment IS a visible
|
||||
ticket-backend comment, rows close individually, and the TD index dedups
|
||||
across sessions — the old per-item model's three guarantees at ~1 ticket per
|
||||
source.
|
||||
|
||||
### PR 准入(pr-admission,TD-678)
|
||||
|
||||
会话交付物 = 分支 + 报告;开 PR 属编排职权,按容量串行一次一张、双绿并入
|
||||
再开下一张([org-internal #3864] 管合并出口、本节管 PR 入口)。交付推送前置
|
||||
本地验证(`<test-cmd:changed>` + `<typecheck-cmd>` 绿;实例命令绑定见
|
||||
core/adapters/TERMINOLOGY.md)。编排不可达可自开,PR 正文标
|
||||
`uncoordinated`。细则与门控项:pipeline-gate 清单 PR 准入节。
|
||||
|
||||
### BF / FT family umbrellas
|
||||
|
||||
Baseline failures and flaky tests file **per root-cause family**, not per
|
||||
occurrence: evidence (run, commit, failing output, failure rate) attaches as
|
||||
comments on the family's **umbrella ticket** (ticket-backend issue), keyed by
|
||||
failure signature (error signature + affected surface, not just
|
||||
`file::test-name` — one root-cause family may span several tests; precedents
|
||||
[org-internal #2585], [org-internal #2925]). Filing a new ticket when the
|
||||
signature already matches an existing family (open or closed) is forbidden —
|
||||
attach evidence instead. A family umbrella is closed when its signature no
|
||||
longer reproduces.
|
||||
|
||||
### TTL semantics (feeds G2's issue-reaper)
|
||||
|
||||
- An **unpromoted registry row** stale for 30 days (no promotion, no
|
||||
evidence comment) is reaper-eligible: 7-day notice, then archived into the
|
||||
tracker's archive section.
|
||||
- A **promoted ticket** follows the normal issue lifecycle (its own priority,
|
||||
assignee, milestone).
|
||||
|
||||
### Compatibility (Iron Law preserved)
|
||||
|
||||
- `_(Deferred: TD-XXX <reason>)_` annotations keep their exact format; the
|
||||
`TD-XXX` now resolves to a registry row (or promoted ticket) instead of an
|
||||
issue number.
|
||||
- Archive-at-close, `## 工件索引` guards, and issue-checklist-sync are
|
||||
untouched: the registry comment is an ordinary ticket-backend comment, not
|
||||
a Tier-2 artifact page.
|
||||
@@ -0,0 +1,122 @@
|
||||
> Core 中立版(Increment 2 改写)。术语对照见 core/adapters/TERMINOLOGY.md;本组织实例表述见 dogfood 对应文件。
|
||||
|
||||
## Two-Tier Artifact Storage (mandatory)
|
||||
|
||||
Agent-internal handoff (subagents sharing one worktree) and human-visible
|
||||
traceability have different consumers, lifecycles, and costs. The harness
|
||||
separates them into two tiers so internal handoff stops paying the Tier-2
|
||||
tax (HTTP latency, write conflicts, auth, backend health) while
|
||||
human-visible decisions stay in the system of record.
|
||||
|
||||
**Iron Law: an artifact's tier is decided by its CONSUMER and LIFECYCLE, not by
|
||||
its format.** Format (json / md / artifact page / comment) follows the tier
|
||||
decision, never drives it.
|
||||
|
||||
### Tier 1 — local structured (transient, intra-workflow)
|
||||
|
||||
- **Consumer**: subagents within one worktree (Producer / Reviewer /
|
||||
Synthesizer / Verifier) — never a human gate, never cross-worktree.
|
||||
- **Lifecycle**: bounded to one run; one worktree; archived-at-close.
|
||||
- **Visibility**: agent-internal; not human-gated.
|
||||
- **Storage**: the run workspace `runs/{slug}/` — schema-validated local
|
||||
files; active runs gitignored, archive bundle committed at close.
|
||||
- **Examples**: design detail dumps, plan item lists, raw review dimension
|
||||
findings, synthesis prompts, intermediate analysis.
|
||||
|
||||
### Tier 2 — ticket backend / git (stable, cross-worktree, human-visible)
|
||||
|
||||
- **Consumer**: humans (gate decisions), cross-worktree sessions, traceability.
|
||||
- **Lifecycle**: outlives a run; cross-worktree stable; the system of
|
||||
record.
|
||||
- **Visibility**: human-visible; authoritative.
|
||||
- **Storage**: the ticket backend (issues, PRs, artifact pages, commit
|
||||
status) + git-committed artifacts.
|
||||
- **Examples**: frozen inter-chunk contracts, issue status + checklist, PRs,
|
||||
review verdict + synthesis (the human gate), `## 工件索引` comment, commit
|
||||
status, the workflow branch.
|
||||
|
||||
### Decision rule (the 判据)
|
||||
|
||||
An artifact belongs to **Tier 1** if and only if ALL of:
|
||||
|
||||
1. consumed only within one worktree / one run, AND
|
||||
2. not a human gate decision (no human reads it to approve/reject), AND
|
||||
3. not referenced cross-worktree (e.g. a later chunk's frozen contract), AND
|
||||
4. regenerable-or-archivable at close without losing a decision record.
|
||||
|
||||
If ANY condition fails → **Tier 2**. When in doubt, Tier 2: **the Tier-2
|
||||
default载体 is decided by the ticket backend adapter** (参考实现见
|
||||
core/adapters/ 的 adapter 层;本组织实例为 Gitea adapter, 术语对照见
|
||||
core/adapters/TERMINOLOGY.md) — Tier 2 is the default system of record;
|
||||
Tier 1 is an optimization an artifact opts INTO, not out of.
|
||||
|
||||
### Common classifications
|
||||
|
||||
Per-artifact table (review findings, prompt files, working drafts, draft/frozen
|
||||
contracts, issue checklist, 工件索引, `index.json` …): Tier-2 reference page
|
||||
`rules/two-tier-artifacts-detail` (reachable via the ticket backend); the
|
||||
decision rule above classifies anything unlisted.
|
||||
|
||||
### Two indexes, parallel not replacement
|
||||
|
||||
- **Tier 1 `index.json`** (`runs/{slug}/index.json`) — the agent's
|
||||
compact-recovery entry; Tier 1 artifacts only.
|
||||
- **Tier 2 `## 工件索引` comment** — the human-visible traceability hub:
|
||||
artifact-page/issue locations + 重读 priority.
|
||||
|
||||
Both are kept by the producing role but serve different consumers. Migrating a
|
||||
skill's output to Tier 1 does NOT remove its Tier 2 row — it repoints 位置 at
|
||||
the distillation.
|
||||
|
||||
### Archive-at-close
|
||||
|
||||
Closed by the **Verifier** at verify PASS (or the Orchestrator when no
|
||||
verify). The archive step is the ONLY point active-run Tier 1 content enters
|
||||
git history:
|
||||
|
||||
1. Generate the bundle [org-internal #3604]:
|
||||
the run-bundle generator script with `--slug {slug} [--ticket N] [--pr N]`
|
||||
— flips meta to "archived", hashes the workspace into the `sha256_16`
|
||||
manifest, writes `archive/{ticket}-{slug}.json`, validates.
|
||||
2. Commit the bundle on the workflow branch (rides into main via `--no-ff`).
|
||||
Direct pushes to main stay blocked by branch protection [org-internal
|
||||
[org-internal #3604]]; do not bypass.
|
||||
3. **归档前置校验** [org-internal #2727]: the generator validates by default
|
||||
(`--no-validate` must not reach a merge); red exit = fix before close.
|
||||
The L0 merge gate rejects non-compliant bundles at merge anyway.
|
||||
|
||||
merge-gate 另做 **presence(存在性)检查**:PR body/commit 引用 `Closes #N`
|
||||
而 merge 树归档目录无 `meta.ticket.number=N` 的 bundle 时拦截(区别于
|
||||
schema 包的结构合规检查)。预期无 run 的关闭(文档/audit-only/MVP 晋级
|
||||
前/revert/ad-hoc/legacy reopen)贴 `gate-exempt/archive-presence`
|
||||
label——label 事件自动重跑 gate。归档前 PR 呈红是设计行为(fail-closed
|
||||
until archived)。**禁止以豁免 label 替代确实存在过的 run 的 bundle
|
||||
归档**。归档目录的 `.gitkeep` 是该检查的目录存在性不变式,不得删除。
|
||||
|
||||
4. Remove the `{active-slug}/` workspace. Direct `rm -rf` is L0-blocked —
|
||||
sanctioned exit: the post-merge worktree sync script with `--prune-runs`
|
||||
(syncs to the merge commit, prunes the run dir, clears stale-ahead false
|
||||
positives), then the session-worktree removal script.
|
||||
5. Mark the Tier 2 `## 工件索引` archived per the issue-checklist-sync rule
|
||||
§ 归档动作.
|
||||
|
||||
Tier 2 remains the decision record; the Tier 1 git archive is the
|
||||
reproducibility trace — enough to reconstruct what a run produced.
|
||||
|
||||
### Compact interaction
|
||||
|
||||
`compact` never deletes local files: `index.json` survives compaction and is
|
||||
the designated re-read entry — after `compact`, read `runs/{slug}/index.json`,
|
||||
not conversation memory.
|
||||
|
||||
### Gate furlough([org-internal #3607])
|
||||
|
||||
强制门的唯一退出通道是 gate 台账(furlough ledger)的 furlough 条目
|
||||
(测量证据 + reopen 条件);无台账条目的减门/跳过改动一律拒绝,台账
|
||||
本身是 Tier 2 决策工件。
|
||||
|
||||
### Scope
|
||||
|
||||
This rule + the runs layout template + schemas are the foundation; the two
|
||||
tiers coexist — unmigrated artifacts keep writing to the ticket backend per
|
||||
their existing body.
|
||||
@@ -0,0 +1,11 @@
|
||||
> Core 中立版(Increment 4 改写)。术语对照见 core/adapters/TERMINOLOGY.md;本组织实例表述见 dogfood 对应文件。
|
||||
|
||||
## Type Checking
|
||||
|
||||
- Always run `<typecheck-cmd>` from package directories, never invoke the
|
||||
underlying compiler driver directly.
|
||||
- Monorepo-wide typecheck from the repo root (all packages in one pass — used
|
||||
by CI and the review-code mechanical-green gate's precondition check): the
|
||||
repo-root turbo-pipeline invocation (see the term mapping). This is the
|
||||
repo-root equivalent of the per-package `<typecheck-cmd>`, not a divergence
|
||||
from it.
|
||||
@@ -0,0 +1,137 @@
|
||||
> Core 中立版(Increment 2 改写)。术语对照见 core/adapters/TERMINOLOGY.md;本组织实例表述见 dogfood 对应文件。
|
||||
|
||||
## Workflow Routing — type-driven process selection (mandatory)
|
||||
|
||||
A ticket's `Kind/*` label determines its process route. The main-session
|
||||
Process Assessment Gate MUST resolve the route BEFORE matching a skill, so a
|
||||
labeled ticket never re-derives its path from scratch. Routing is **additive**:
|
||||
it can only skip stages a ticket doesn't need — it can never weaken a
|
||||
mandatory gate or skip review/verify.
|
||||
|
||||
**Authoritative table**: the workflow-routing table in the instance config
|
||||
area (`label → { entry, skip, keep_gates }`). The table is the single source
|
||||
of truth; this rule only says _when and how_ to consult it.
|
||||
|
||||
### When to route (Step 0 — runs before the gate's "Articulate intent")
|
||||
|
||||
On every substantive request that is tied to a ticket, run Step 0:
|
||||
|
||||
1. **Identify the working ticket**. Priority order: explicit `Closes #N` /
|
||||
`Fixes #N` / `Resolves #N` in the PR or commit → `## 父级 / Parent` link
|
||||
or chunk mapping → the issue the user pasted or referenced by number.
|
||||
None of these → no ticket, skip to degradation.
|
||||
2. **Resolve the route with the 路由解析工具 FIRST** — pass the full
|
||||
`Kind/*` label when known; omit `kind` when not yet read (the tool returns
|
||||
the default route plus a read-ticket-then-re-invoke instruction). Agents
|
||||
with the route-gate option enabled enforce this mechanically
|
||||
[org-internal #3328]: other tool calls are dispatch-rejected until the
|
||||
路由解析工具 runs. Do not hand-read the routing table when the tool is
|
||||
available.
|
||||
3. **Read the ticket's `Kind/*` label** from the issue body or via the issue
|
||||
tools (unblocked once the route gate is satisfied). Pick the FIRST
|
||||
`Kind/*` label if several exist; on a non-default route, re-invoke the
|
||||
路由解析工具 with the full label.
|
||||
4. **Apply the route**:
|
||||
- `entry.skill` non-null → invoke that skill (with `entry.mode` if given)
|
||||
instead of natural-language matching. This satisfies gate Step 3.
|
||||
- `entry.skill` null → normal natural-language match, still honoring
|
||||
`skip` / `keep_gates` downstream. Never drop a gate the route lists in
|
||||
`keep_gates`; never add back a stage the route lists in `skip`.
|
||||
|
||||
### Degradation — label missing, unknown, or wrong ([org-internal #1828] AC)
|
||||
|
||||
- **No ticket / no `Kind/*` label / label not in the table** → `default`
|
||||
route (natural-language matching). State this in one line ("no Kind/\*
|
||||
label → default route") so the choice is auditable; never block or ask
|
||||
the user just because a label is absent.
|
||||
- **Label looks wrong for the work** → do NOT silently override the label.
|
||||
Apply the labeled route, flag the mismatch in your first response, and
|
||||
recommend the correct label — the creator owns label correctness; routing
|
||||
acts only on what is written.
|
||||
- **Routing table file missing/unreadable** → fall back to natural-language
|
||||
matching session-wide and note it once — a broken table never blocks work.
|
||||
|
||||
### Interaction with the rest of the pipeline
|
||||
|
||||
- Routing chooses the **entry** and the **skip set** only. L0/L1 enforcement
|
||||
(worktree/branch discipline, commit-msg format, stash ban,
|
||||
claim-discipline, issue-checklist-sync, issue-cross-linking) applies on
|
||||
every route; a `Kind/Documentation` ticket still needs a worktree and a
|
||||
PR.
|
||||
- `keep_gates` from the route and the skill's own mandatory gates intersect:
|
||||
a gate is mandatory if EITHER source requires it. Skipping is valid only
|
||||
when BOTH the route and the skill agree it's skippable for this ticket type.
|
||||
|
||||
### Runtime growth signals (post-sizing)
|
||||
|
||||
Two live growth mechanisms (narrative: Tier-2 reference page
|
||||
`rules/workflow-routing-detail`, reachable via the ticket backend; retired
|
||||
Size/* history: the instance rules-history archive). Canonical key:
|
||||
`dag.size_derivation.oversize_signals` (TD/DUP-F009).
|
||||
|
||||
- **DAG-routed tickets** (DAG Epic, DAG-routed `Kind/Feature`, their
|
||||
`Kind/Task` children — no `Size/*` tier): runtime growth fires the
|
||||
oversize signals → response is **re-derivation + review-dag re-run**.
|
||||
- **Bug tickets (big-bug relabel rule, [org-internal #3061])**: a `Kind/Bug`
|
||||
hitting a design-level trigger (design-decision root cause, shared-contract /
|
||||
public-API change, data migration) has outgrown the bug type — mandatory
|
||||
action is **relabel `Kind/Feature`** (Step 0 reroutes into the DAG
|
||||
pipeline; repro + root-cause notes carry over as node input). Scale-only
|
||||
triggers stay in bugfix with batched iterations.
|
||||
|
||||
Both follow "act on what's written, surface the doubt": when reality
|
||||
disagrees with the label, pause, reclassify, and make the change visible —
|
||||
never quietly override.
|
||||
|
||||
### DAG 路由 (v2) — default (转正)
|
||||
|
||||
The DAG ticket pipeline (`analyze-dag` → task DAG → single gate `review-dag`)
|
||||
is the **default** route for `Kind/Epic` and `Kind/Feature`
|
||||
([org-internal #3061] Phase 2 / TD-388). Both resolve via the routes table
|
||||
directly — **no trigger/marker check** (route rollback = revert PR).
|
||||
Authoritative definition: the `dag:` block in the workflow-routing table;
|
||||
narrative + history: Tier-2 reference page `rules/workflow-routing-detail`.
|
||||
|
||||
1. **`Kind/Epic` or `Kind/Feature` → `dag.route`**: entry `analyze-dag`,
|
||||
single gate `review-dag` (replaces review-design-space +
|
||||
review-iteration-plan), `keep_gates` `[review-dag, verify]`.
|
||||
2. **`Kind/Task` under a DAG parent → `dag.task_route`** (entry `implement`,
|
||||
`implement → review-code → verify`), NOT `dag.route`. All three skills
|
||||
carry a DAG branch; `pipeline/review-dag` success replaces the
|
||||
design-space + iteration-plan convergence preconditions at review-code
|
||||
and verify.
|
||||
|
||||
**Routing stickiness**: once an Epic is routed to DAG (draft DAG artifact
|
||||
exists or `## DAG 状态` table created), all subsequent Step 0 for that Epic
|
||||
stays on the DAG route — stickiness starts at first routing, NOT at
|
||||
single-gate PASS. Symmetrically, an Epic already decomposed via legacy
|
||||
roadmap stays legacy through close (no new legacy decomposition).
|
||||
|
||||
**Ticket creation after single-gate PASS** (switch values authoritative in
|
||||
the routing table `dag.ticket_creation`; analyze-dag itself does NOT create
|
||||
tickets): on `review-dag` PASS the **aggregator agent** creates one
|
||||
`Kind/Task` ticket per `type: task` node (body: node `acceptance_criteria`
|
||||
or dag subpage link + `test_id` suite; `## 父级 / Parent` → DAG parent so
|
||||
Step 0 resolves `dag.task_route`); `type: milestone` nodes get NO ticket
|
||||
(DoD carried by `dag.verify_milestone`); the parent body aggregates
|
||||
`## DAG 状态` + `## 当前状态` (single writer: the aggregator). Each task
|
||||
ticket then flows implement → review-code (`mode: "dag-task"`) → verify
|
||||
(task mode).
|
||||
|
||||
### Retired sections (index)
|
||||
|
||||
Retired mechanisms (Sizing, JIT decomposition, marker disambiguation,
|
||||
legacy-route sunset, publish-target-by-tier, gate-trim) live in the instance
|
||||
rules archive; rulings in the phase-3 retirement ruling doc (Tier-2
|
||||
reference, reachable via the ticket backend). Nothing trims gates —
|
||||
`never_trim` is structural.
|
||||
|
||||
### 立案降档 — filing/sprint-mode([org-internal #3002] G5 / [org-internal #3007])
|
||||
|
||||
Sprint 期间债务侧显式降档,不靠纪律。开关:routing table `filing.sprint-mode`
|
||||
(默认 `false`)。`true`(冲刺期)时 verify Phase 5.5 registry-only 不分严重度
|
||||
(登记行照写、零丢失;独立工单创建冻结至开关回 `false`,已登记行按
|
||||
ticket-lifecycle 规则正常认领升票;期间 HIGH/MEDIUM 行不被 reaper 触碰,
|
||||
[org-internal #3004])。BF/FT(5.55/5.56)不受影响。谁翻转:冲刺负责人(人),
|
||||
在冲刺跟踪单记一行;开关值即 routing table 当前值,verify 每次运行时读取。
|
||||
动机与细节:Tier-2 参考页(经 ticket backend)`rules/workflow-routing-detail`。
|
||||
Reference in New Issue
Block a user