Files

19 KiB
Raw Permalink Blame History

Core 中立版(Increment 6a 改写,原 deferHard verbatim)。编号与条目结构严格不变(C-2 不变量);实例术语按 core/adapters/TERMINOLOGY.md 绑定。

Tier 1 Local Run Layout — <runs-root>/{slug}/

Normative layout for Tier 1 local structured artifacts. Authoritative boundary rule: core/rules/two-tier-artifacts.md. Schemas that validate the structured files below live in core/schemas/runs-*.schema.json.

This document is the foundation (MVP slice, [org-internal #1968]). It defines the container, the manifest, and the metadata. Stage-specific artifact schemas (design detail dumps, plan items, review dimension findings, synthesis prompts, draft contracts) are added incrementally as each skill migrates its transient output here — the follow-up iteration ([org-internal #1988]) has landed: review-artifact / audit-process raw findings and producer working drafts are now Tier 1. ([org-internal #3072] phase 3, 2026-08-21: the legacy producer stages whose drafts are listed below were archived — their rows and artifact dirs are kept for reading historical run bundles.) See the migrated stages table below.

Kind/MVP mode ([org-internal #3061])

Kind/MVP tickets write nothing to <runs-root>/ by design — no stage dirs, no index.json, no manifest. The ticket body is the doc (## 决策日志

  • ## Debt Register). Optionally a single free-form <runs-root>/{slug}/working-notes.md may capture scratch that does not belong in the body; it has no schema and is not indexed. On graduation (relabel Kind/Feature) the DAG route initializes the standard layout from scratch; the MVP body remains the REQMAP baseline (analyze-dag backfill).

Why a local tier

Agent-internal handoff (subagents sharing one worktree) currently pays the Gitea tax (HTTP latency, wiki 409 conflicts, auth, Gitea-health dependency) even though the consumer is a sibling subagent in the same process tree. The embryo already proved local files viable (/tmp/octopus/synthesis_task_*.md for prompt_file, see core/skills/_shared/review-pipeline-phases.md §Phase B step 1 — synthesis prompt). This layout formalizes that embryo into a discoverable, schema-validated, archive-at-close tier — without touching Gitea's role as the system of record for human-visible decisions.

Directory tree

<runs-root>/
├── .gitignore                # ignores active-run workspaces; tracks archive/ + self
├── archive/                  # TRACKED — closed-run bundles land here
│   ├── .gitkeep
│   └── {slug}.json           # one bundle per closed run (meta + index digest)
└── {active-slug}/            # GITIGNORED — one subdir per active run
    ├── meta.json             # run metadata        (runs-meta.schema.json)
    ├── index.json            # artifact manifest    (runs-index.schema.json)
    ├── working-notes.md      # cross-stage narrative memory ([org-internal #2600], schema-less md)
    ├── workers/              # worker final-return reports ([org-internal #2847], schema-less md —
    │   └── ...               #   see _shared/worker-report-persistence.md)
    └── {stage}/              # per-stage transient artifacts (added by skills)
        └── ...               #   json (structured) / md (prompt files)

{active-slug}

  • One subdir per active pipeline run, named by the run slug (the same {slug} used by the Gitea wiki namespace and the workflow branch tail).
  • Gitignored while active — subagents share the worktree, not the git history, so active-run content stays local (no repo bloat, no merge noise).
  • Initialized at run start by bun <harness-package>/script/runs-init.ts --slug {slug} --ticket N [--branch …] [--worktree …] ([org-internal #3642]) — the producing role / Orchestrator runs the script (hand-writing the files is the legacy path): it creates the {active-slug}/ workspace, writes meta.json with state: "active" and the run's slug/branch/worktree/ticket (branch omitted / worktree null for ad-hoc runs without a worktree), and an empty index.json (artifacts: []), schema-validated before write and idempotent on re-run. Kind/MVP and Kind/Documentation tickets are skipped automatically (label check, § Kind/MVP mode below). script/claim-provision.sh chains this after claim + worktree in one command. Subsequent producing roles append to index.json as they emit artifacts.
  • Removed by the Verifier's archive step at close (its content is bundled into archive/{slug}.json first).

meta.json — run metadata

Schema: core/schemas/runs-meta.schema.json. Fields:

field type notes
schema_version integer const 1
slug string run slug; matches branch tail + wiki namespace
ticket object|null { owner, repo, number } of the source issue, or null for ad-hoc runs
branch string workflow branch, e.g. workflow/enhancement/1968-two-tier-artifacts; omitted for ad-hoc runs without a branch
worktree string|null absolute path of the worktree, or null for ad-hoc runs without a worktree
parent_epic object|null { number } of the parent Epic, if any
state enum activearchived (set at close)
created_at string RFC 3339 timestamp
updated_at string RFC 3339 timestamp
closed_at string|null RFC 3339; null while active
close_commit_sha string|null git SHA of the archive commit; null while active

index.json — artifact manifest

Schema: core/schemas/runs-index.schema.json. This is the compact recovery entry point: after compact (which never deletes local files), an agent re-reads index.json to recover the run's artifact set without scanning the tree. Each entry:

field type notes
schema_version integer const 1
slug string run slug
artifacts array one entry per Tier 1 artifact in this run
artifacts[].path string path relative to {active-slug}/
artifacts[].type enum meta, index, design, plan, review-findings, review-status, review-synthesis, synthesis-prompt, precondition-gate, working-notes, analysis, browser-evidence, other (authoritative enum: core/schemas/runs-index.schema.json)
artifacts[].schema string|null $id of the validating schema, or null for schema-less (e.g. prompt .md)
artifacts[].tier const 1 local tier marker (Tier 2 is never listed here)
artifacts[].stage enum|null producing pipeline stage (requirements/design/plan-iterations/implement/review-code/verify/…), or null for meta/index
artifacts[].produced_by enum|null Producer/Reviewer/Verifier/Tool/Coordinator (canonical role names — the name field of core/skills/_shared/roles/*.yaml), plus fine-grained sub-roles mapped via ROLE_ALIASES in <harness-package>/src/config/role.ts: Producer sub-roles Analyst/Architect/Planner/Developer/Synthesizer/Orchestrator/Remediator, and the Reviewer sub-role Auditor
artifacts[].sha string|null content digest (sha256), or null if not yet computed
artifacts[].tier2_ref string|null cross-link to the Tier 2 mirror (e.g. issue comment URL / wiki page) when one exists

index.json is parallel, not replacement, for the Tier 2 ## 工件索引 issue comment: the former is the agent's compact-recovery entry; the latter is the human-visible traceability hub. They are kept in sync by the producing role but serve different consumers.

working-notes.md — cross-stage narrative memory ([org-internal #2600])

index.json is a MANIFEST: it records WHAT artifacts exist. It does not carry WHY code was written that way, which paths were tried and abandoned, or what the reviewer's feedback actually changed — the tacit context every next stage currently re-derives by re-reading formal artifacts. working-notes.md is that narrative memory, in-file, append-only:

  • Format (schema-less markdown): each entry is ## [{stage}] {role} @ {RFC 3339 ts} followed by ≤30 lines covering: decisions made (and why), dead ends (do NOT retry these), reviewer feedback that changed the work, and one-line hints for the next stage.
  • Append cadence — one entry per unit of ownership, never per subagent dispatch: Producer sub-roles append at stage exit; the Reviewer side appends via the Synthesizer at review convergence (one entry per review, not per dimension — 9 dimension dispatches = 1 distilled entry); the Verifier appends at verify exit; Tool agents append only when the task produced a load-bearing finding (e.g. image evidence that changed a decision).
  • Re-read rule: the next stage reads working-notes.md FIRST — before the formal artifacts — and may then skip full re-reads that the notes already cover. Role yamls carry this line in compact.preserve (core/skills/_shared/roles/*.yaml).
  • index.json row (registered once by the first appending role): type: working-notes, schema: null (markdown), stage: null (cross-stage), produced_by: null (multi-role), tier2_ref: null.
  • Tier judgment: consumed within one worktree/run ✓, never a human gate decision ✓, never referenced cross-worktree ✓, archivable at close ✓ — all four Tier 1 conditions hold (core/rules/two-tier-artifacts.md 判据).

workers/ — worker final-return reports ([org-internal #2847])

Every worker sub-agent dispatch (agent: worker roles — Producer sub-roles, Verifier, Synthesizer) persists its final return report verbatim to workers/{chunk-id}-worker-{seq}.md as its LAST action before returning (lightweight fallback when no run workspace exists: /tmp/octopus/{chunk-id}-worker-{seq}.md). The persisted copy is the report of record — when the task completion notification is lost, the orchestrating session recovers the worker's conclusion by reading the newest workers/{chunk-id}-worker-*.md match. Skills that own a canonical stage path for the dispatch (e.g. the review-code Synthesizer's reviews/{stage}/round{N}/synthesis-return.md) use it instead of the generic name. index.json row: type: "other", schema: null, stage = producing stage, produced_by = role. Full convention: core/skills/_shared/worker-report-persistence.md.

browser/ — browser evidence packs ([org-internal #4497] N-03)

A browser-debug session writes one evidence pack per session under browser/{session-id}/ (contract browser-evidence-4486/shared/pack-manifest-v1, frozen 2026-09-10 — <harness-package>/src/browser/evidence-pack.ts is the writer):

browser/{session-id}/
├── manifest.json           # PackManifest: env probe (shared/env-probe-v1),
│                           #   replay metrics {attempted, succeeded, failures[]},
│                           #   artifact rows {kind, path, sha256_16}
├── trace/                  # Playwright trace zips (recorded sessions)
├── screenshots/*.png       # copies — the .playwright-mcp/ layer is additive-not-replaced
├── console-errors.jsonl    # one sanitized entry per line
└── network-failures.json   # sanitized failure summary

Write boundary invariants (the graph's single mandatory sanitize point, shared/sanitize-api-v1): every textual capture passes sanitizeForEvidence before hitting the disk; entries whose URL fails the navigation allowlist are excluded from the pack; the write is non-blocking (the writer returns a handle before the first byte lands). index.json row: type: "browser-evidence", path: "browser/{session-id}/manifest.json", stage = producing session's stage (implement/verify), produced_by: "Tool".

{stage}/ — per-stage transient artifacts

Added incrementally by each skill as it migrates its transient output to Tier 1. Conventions established by this foundation:

  • Structured data → .json (schema-validated).
  • Prompt files passed to subagents via prompt_file.md.
  • File naming mirrors the Gitea wiki namespace so a Tier 1 path and its (former / future) Tier 2 mirror are visually paired, e.g. on-disk <runs-root>/{slug}/reviews/{stage}/round{N}/findings-COR.json. The corresponding index.json artifacts[].path value strips the {slug}/ prefix (it is relative to {active-slug}/): reviews/{stage}/round{N}/findings-COR.json.
  • A stage that has not yet migrated continues to write to Gitea (Tier 2) per its existing skill body — the two tiers coexist during the migration.

Migrated stages ([org-internal #1988]):

Stage Skill Tier 1 artifacts Schema Notes
review-code review-code reviews/code/round{N}/findings-{DIM}.json (raw dimension findings), reviews/code/round{N}/task-synthesizer.md (synthesis prompt) reviewer-output.schema.json (findings) synthesis comment + commit status stay Tier 2
review-roadmap review reviews/roadmap/round{N}/findings-{DIM}.json reviewer-output.schema.json legacy target archived ([org-internal #3072] phase 3) — row kept for historical bundles
review-design-space review reviews/design-space/round{N}/findings-{DIM}.json reviewer-output.schema.json legacy target archived ([org-internal #3072] phase 3) — row kept for historical bundles
review-iteration-plan review reviews/plan/round{N}/findings-{DIM}.json reviewer-output.schema.json legacy target archived ([org-internal #3072] phase 3) — row kept for historical bundles
review-dag review reviews/review-dag/round{N}/findings-{DIM}.json reviewer-output.schema.json synthesis comment + commit status stay Tier 2
audit-process review reviews/audit-process/round{N}/findings-{DIM}.json reviewer-output.schema.json synthesis wiki page + commit status stay Tier 2
requirements (drafts) requirements-elicitation requirements/ (schema-less .md/.json) legacy skill archived ([org-internal #3072] phase 3) — historical bundles only
design (drafts) design design/ (schema-less or design-detail.schema.json) design-detail.schema.json (moved to <instance-root>/archive/schemas/ [org-internal #3072] phase 3) legacy skill archived ([org-internal #3072] phase 3) — historical bundles only
plan-iterations (drafts) plan-iterations plan-iterations/ (schema-less or plan-items.schema.json) plan-items.schema.json (moved to <instance-root>/archive/schemas/ [org-internal #3072] phase 3) legacy skill archived ([org-internal #3072] phase 3) — historical bundles only
roadmap (draft contracts) roadmap roadmap/contracts/{name}.json draft-contract.schema.json (moved to <instance-root>/archive/schemas/ [org-internal #3072] phase 3) legacy skill archived ([org-internal #3072] phase 3) — historical bundles only

Every review/audit stage additionally maintains a per-stage lifecycle file reviews/{stage}/status.json (schema review-status.schema.json) — live stages: review-code, review-dag, audit-process; legacy bundle stages (review-roadmap, review-design-space, review-iteration-plan) maintain the same file in historical bundles only. It is initialized by the Orchestrator before round 1, appended by the Synthesizer each round, and finalized with converged at Phase E. The Orchestrator appends an index.json row for it (type = review-status, stage = {REVIEW_TYPE}, produced_by = Orchestrator).

Stages NOT yet migrated (none — all target stages have been migrated or have opt-in Tier 1 affordances): reviser task prompts (wiki pages) remain Tier 2 in this slice; synthesis prompts for review-artifact / audit-process targets follow the shared Phase B mechanics (Tier 1 for all tier1-local skills).

Archive-at-close

Closed by the Verifier at verify PASS (or by the Orchestrator for flows without verify). The archive step is the ONLY point at which active-run content enters git history:

  1. Set meta.json.state = "archived", record closed_at and close_commit_sha.
  2. Write archive/{slug}.json — a compact bundle carrying meta + the index.json manifest (the durable trace; bulk artifacts are summarized by digest, not copied wholesale, to keep the archive small). One exception ([org-internal #2600]): when working-notes.md exists, its final content is inlined as the bundle's top-level working_notes field — the narrative memory is the single artifact whose content (not just digest) rides in the bundle, feeding later retro probes and the notes-injection degradation path ([org-internal #2601]). The bundle is validated by runs-bundle.schema.json. Offline review verifiability (TD/TRC-F006, [org-internal #2688]): for each review stage the run executed, also embed a top-level review_history entry in the bundle — {stage, rounds, final_verdict, per_round[]} (per-round: round/overall_verdict/blockers/majors/minors) — derived from that stage's live reviews/{stage}/status.json history[]. Closed-run probes can then reconstruct round counts and verdicts from the bundle alone, without the removed workspace or artifact-path reconstruction ([org-internal #2591]).
  3. git add archive/{slug}.json and commit on the workflow branch (rides into main via the --no-ff merge).
  4. Remove the {active-slug}/ workspace from the worktree (its durable record now lives in the archive bundle).

Steps 14 collapse into ONE command ([org-internal #3642]): bash script/archive-run.sh {slug} [--pr N] — run from the session worktree, it resolves the PR by branch head, generates + validates the bundle via gen-run-bundle.ts (recording closed_at / close_commit_sha and the --branch workflow branch), commits it with a hook-conforming [{chunk}][iter-N] chore(runs): … message, removes the workspace, and tears the worktree down unless invoked from inside it. The ## 工件索引 archived remark (issue-checklist-sync.md § 归档动作) remains an agent action — content judgment, not scripted.

Tier 2 (Gitea) remains the system of record for decisions (verdicts, issue status, PRs, frozen contracts). The Tier 1 git archive is the reproducibility trace — enough to reconstruct what a run produced, without re-paying the Gitea tax.

Relationship to existing mechanisms

  • /tmp/octopus/ embryoreview-code ([org-internal #1988] MVP) now writes its synthesis prompt under <runs-root>/{slug}/reviews/code/ instead of /tmp/octopus/synthesis_task_*. Other skills still using the /tmp/octopus/ embryo coexist until their own migration iteration.
  • ## 工件索引 issue comment (Tier 2) — unchanged; index.json (Tier 1) is its agent-side parallel, not a replacement.
  • compactcompact never deletes local files, so index.json survives compaction and is the designated re-read entry for a compacted run.
  • worktree discipline — all subagents of one workflow share its worktree, so they share <runs-root>/{slug}/ directly (no cross-worktree coordination needed for Tier 1; that coordination lives in Tier 2).