Compare commits

..
Author SHA1 Message Date
weichen 6fe40b0342 Merge pull request 'Add bounded evidence to work checkpoint candidates' (#31) from feature/fast-slow-u2-u3 into main
governance / governance (push) Successful in 16s
2026-10-19 09:20:24 +00:00
weichen 0cf03446c4 Merge the fast-slow U2/U3 branch history after syncing with main
governance / governance (pull_request) Successful in 16s
2026-10-19 02:59:18 +00:00
agent-exec-transport cbd3d3e3d0 agent-exec transport 68889ca8d4b0eec4cfe89d0cc80b6516/5ca3b7798211 2026-10-19 02:59:03 +00:00
weichen 5cae3a6e30 Merge pull request 'Adopt the shared governance kit (development-governance-v2)' (#35) from feature/governance-adoption into main
governance / governance (push) Successful in 17s
2026-10-17 08:31:36 +00:00
weichen b240077300 Close and archive the governance adoption card
governance / governance (pull_request) Successful in 16s
Why: the adoption PR is reviewed and its candidate HEAD passed CI; the card closure is folded into the PR so no separate close PR is needed.
Evidence: CI GATE on 18f617d4e8cd63d172a5ab9519271831beb546db; independent Review REPLAY (cursor-agent-stable --mode ask 全新只读会话(fresh_session=true,session id not-observable;codex/pi 因 Token Plan 429 不可用)VERDICT: APPROVE,无阻塞项).
Impact: task card only (moved to .task/archive/).
Refs: https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-Core/pulls/35
2026-10-17 08:25:12 +00:00
weichen 18f617d4e8 Record the adoption unit run and positive/negative evidence
governance / governance (pull_request) Successful in 23s
Why: Phase 6 requires one positive executor run and the negative cases (missing config, bad receipt, out-of-scope path, unknown side effect) before adoption becomes active.
Evidence: .task/evidence/governance-adoption/ (SELF): governance check, agent-exec validate and adoption cases; this commit passed the generated pre-commit hook (admit).
Impact: task card and evidence logs only.
Refs: .task/feature-governance-adoption.md
2026-10-17 07:15:37 +00:00
agent-exec-transport 1ada9955d5 agent-exec transport e64b5afee9fabb0925523057eb540b68/8399a44af60d 2026-10-17 06:55:22 +00:00
weichenandCursor a160b03c7b Record the adoption unit run and positive/negative evidence
Why: Phase 6 requires one positive executor run and the negative cases (missing config, bad receipt, out-of-scope path, unknown side effect) before adoption becomes active.
Evidence: .task/evidence/governance-adoption/ (SELF): governance check all ok; agent-exec validate ok; adoption cases ALL PASS. The generated pre-commit hook refused this commit because scripts/dm resolves the DM checkout through the hook's GIT_DIR; fixed in Development-Manager before this repository re-pins.
Impact: task card and evidence logs only.
Refs: .task/feature-governance-adoption.md
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-17 06:19:48 +00:00
agent-exec-transport 98cfc6408d agent-exec transport 9a7ec13541404ada96c0f8bfc8d77058/a09c2ed0bb4b 2026-10-17 05:55:46 +00:00
weichen dde4f359a8 Bootstrap AGENT-EXECUTION.md and the governance adoption card
Why: development-governance-v2 Phase 6 adopts the shared governance kit in every formal repository; the executor needs a valid AGENT-EXECUTION.md before any implementation unit can run.
Evidence: generated by dm-server governance init at Development-Manager 42e675fec8e0069646319fcd298e61d03d8cbfd5; dm-server agent-exec validate passes.
Impact: configuration and task card only; no code or CI change yet.
Refs: Agent-System-Dev docs/superpowers/plans/2026-10-16-development-governance-v2-master.md
2026-10-17 05:51:28 +00:00
weichen 35560aa5a3 Merge pull request 'Keep complete background results and optional decisions on work cards' (#34) from feature/workbench-flow-completion into main 2026-10-15 08:18:43 +00:00
weichen b4743949e5 Keep U3 TypeScript evidence helpers local
Why: Generated mirrors gained unused named exports and tripped the frontend knip ratchet.

Evidence: Exact Dev combination failed at 53 unused exports over 52 baseline; Core Go tests passed after narrowing the TS export surface.

Impact: Preserve WorkFindingCandidate.evidence shape while avoiding unused exported helper names.

Refs: Dev task feature/fast-slow-u2-u3-plan; failed combo receipt 275bebe2
2026-10-13 16:48:01 +00:00
weichen c722c16626 Validate optional evidence in work checkpoint candidates
Why: U3 needs bounded, source-indexed premises before the host can judge numeric and membership claims.

Evidence: TestWorkCheckpointEvidenceModesAndBounds failed on missing types, then go test ./... -count=1 and git diff --check passed.

Impact: Extend only the candidate wire contract; persisted task snapshots and display kinds stay unchanged.

Refs: Dev task feature/fast-slow-u2-u3-plan; r0.3 evidence implementation plan Task 1
2026-10-13 16:03:33 +00:00
weichen c55ebbcb96 Merge remote-tracking branch 'origin/main' into feature/fast-slow-u2-u3 2026-10-13 10:19:06 +00:00
weichen beafd7537a Merge scoped settings contracts from current main
Why: Preserve upstream settings authority and current component admission.

Evidence: Exact authoritative main object fetched before merge; composition replay follows.

Impact: Retain Task contracts alongside scoped settings.

Refs: Agent-System-Dev U2/U3 delivery
2026-10-13 05:28:02 +00:00
weichen 6e385743e4 Retain coverage limits in legacy task summaries
Why: Older clients must see the same coverage limits as structured task cards.

Evidence: Core suite and composition checks follow this projection update.

Impact: Projects optional limitations into existing list nodes.

Refs: fast-slow-u2-u3 Task 6
2026-10-13 02:08:00 +00:00
weichen dbe1f544d7 Keep material coverage limits separate from outcome claims
Why: A completed run can still lack readable or fully provided source material.

Evidence: Composition validation follows the backend and UI consumers.

Impact: Adds optional host-owned limitations without changing candidate authority.

Refs: fast-slow-u2-u3 Tasks 4 through 6
2026-10-13 01:59:40 +00:00
weichen 124309b985 Retain trusted input bindings for task result reuse
Why: Completed tasks require current source authorization and content validation.

Evidence: Optional fields preserve existing contracts; composition verification follows.

Impact: Adds host-owned input source references with no new model authority.

Refs: fast-slow-u2-u3 Tasks 2 and 4
2026-10-13 01:35:53 +00:00
weichen 06f2723161 Add persistent work snapshots and checkpoint contracts
Why: preserve scoped work findings and truthful activity across reloads.

Evidence: task JSON loss and validation/state regressions RED to GREEN; complete Core suite.

Impact: optional card/document wire fields and bounded candidate validation; old Body remains supported.

Refs: fast-slow U2/U3 Task1, R03 R05 R09 R17
2026-10-13 01:04:56 +00:00
25 changed files with 1125 additions and 61 deletions
+150
View File
@@ -0,0 +1,150 @@
name: governance
on:
pull_request:
push:
branches: [main]
jobs:
governance:
runs-on: ubuntu-latest
env:
GOPROXY: https://goproxy.cn,direct
steps:
- name: Checkout
env:
TOKEN: ${{ secrets.GITHUB_TOKEN }}
SUBMODULE_TOKEN: ${{ secrets.SUBMODULE_TOKEN }}
run: |
set -euo pipefail
# 只物化两个治理 gitlink(Guidelines 与 deps/development-manager),非递归;
# 其它 gitlink 不物化、不取回。凭据只以 URL 限定的 extraheader 存在于本进程树内。
python3 - <<'PY_CHECKOUT'
import os
from pathlib import Path
import re
import subprocess
import sys
from urllib.parse import urlsplit
# 服务端基址取运行器注入的 GITHUB_SERVER_URL(平台控制、候选 PR 不可影响)。
SERVER = os.environ.get("GITHUB_SERVER_URL", "").rstrip("/")
parsed_server = urlsplit(SERVER)
if parsed_server.scheme not in {"http", "https"} or not parsed_server.netloc:
sys.exit("Checkout server must be the platform-injected http(s) URL")
SSH = "ssh://git@git-ssh.u1680832.nyat.app:31411/weichen/"
# 审查过的白名单,独立于候选 .gitmodules:仅列出两个治理 gitlink。
REPOSITORIES = {
"deps/development-guidelines": "Development-Guidelines",
"deps/development-manager": "Development-Manager",
}
TARGET = "weichen/Agent-System-Core"
root_token = os.environ.pop("TOKEN", "")
component_token = os.environ.pop("SUBMODULE_TOKEN", "")
if not root_token or not component_token:
sys.exit("Checkout requires TOKEN and SUBMODULE_TOKEN")
if os.environ.get("GITHUB_REPOSITORY") != TARGET:
sys.exit("Checkout repository is outside the reviewed allowlist")
sha = os.environ.get("GITHUB_SHA", "")
if not re.fullmatch(r"[0-9a-fA-F]{40}", sha):
sys.exit("Checkout requires a fixed commit SHA")
# 丢弃继承的 Git 追踪/配置/SSH 钩子;凭据只存在于单个 Git 进程树的精确 URL 头中。
clean_env = {k: v for k, v in os.environ.items() if not k.startswith("GIT_")}
clean_env.update(GIT_CONFIG_NOSYSTEM="1", GIT_CONFIG_SYSTEM="/dev/null",
GIT_CONFIG_GLOBAL="/dev/null", GIT_TERMINAL_PROMPT="0")
config = {
"core.hooksPath": "/dev/null", "core.fsmonitor": "false",
"init.templateDir": "", "credential.helper": "",
"fetch.recurseSubmodules": "false", "submodule.recurse": "false",
"http.followRedirects": "false", "protocol.allow": "never",
"protocol." + urlsplit(SERVER).scheme + ".allow": "always",
}
def git(repo, *args, extra=None):
values = config | (extra or {})
env = clean_env | {"GIT_CONFIG_COUNT": str(len(values))}
for index, (key, value) in enumerate(values.items()):
env[f"GIT_CONFIG_KEY_{index}"] = key
env[f"GIT_CONFIG_VALUE_{index}"] = value
return subprocess.run(["git", "-C", str(repo), *args], env=env,
check=True, stdout=subprocess.PIPE).stdout
def materialize_governance(root):
# -r 列出任意深度的 gitlink,但不进入 submodule 内部;其它 gitlink 只记录、从不取回。
links = {}
for entry in git(root, "ls-tree", "-rz", "HEAD").split(b"\0"):
if not entry:
continue
metadata, path = entry.split(b"\t", 1)
mode, kind, commit = metadata.decode().split()
if mode == "160000":
links[path.decode()] = commit
for name in REPOSITORIES:
if name not in links:
raise ValueError("Governance gitlink is missing from the fixed commit")
raw = git(root, "config", "--no-includes", "--blob", "HEAD:.gitmodules", "--null", "--list")
entries = {}
for item in raw.split(b"\0"):
if not item:
continue
key, value = item.decode().split("\n", 1)
match = re.fullmatch(r"submodule\.(.+)\.(path|url)", key)
if not match:
continue
name, field = match.groups()
if name not in REPOSITORIES:
continue
if field in entries.setdefault(name, {}):
raise ValueError("Duplicate candidate .gitmodules setting")
entries[name][field] = value
# 先整体校验两个治理条目,再进行任何带凭据的取回。
for name, repository in REPOSITORIES.items():
fields = entries.get(name, {})
if fields.get("path") != name:
raise ValueError("Governance submodule path is outside the reviewed allowlist")
trusted_url = f"{SERVER}/weichen/{repository}.git"
if fields.get("url") not in {SSH + repository + ".git", trusted_url}:
raise ValueError("Governance submodule URL is outside the reviewed allowlist")
for name, repository in REPOSITORIES.items():
url = f"{SERVER}/weichen/{repository}.git"
# 仅持久化审查过的公开 URL,使 Git 在进程级配置消失后仍识别该 submodule。
git(root, "config", f"submodule.{name}.url", url)
git(root, "submodule", "update", "--init", "--checkout", "--", name,
extra={f"submodule.{name}.url": url,
f"submodule.{name}.update": "checkout",
f"http.{url}.extraheader": "AUTHORIZATION: token " + component_token})
child = root / name
if git(child, "rev-parse", "HEAD").decode().strip() != links[name]:
raise ValueError("Materialized governance gitlink does not match the fixed SHA")
try:
root = Path.cwd()
# 必须是干净的临时工作区;不复用既有 Git 状态。
if (root / ".git").exists():
raise ValueError("Checkout requires a fresh workspace")
git(root, "init", "-q")
url = f"{SERVER}/{TARGET}.git"
git(root, "remote", "add", "origin", url)
git(root, "fetch", "--depth=1", "origin", sha,
extra={f"http.{url}.extraheader": "AUTHORIZATION: token " + root_token})
git(root, "checkout", "-q", "--detach", "FETCH_HEAD")
materialize_governance(root)
except (ValueError, OSError, subprocess.CalledProcessError) as error:
sys.exit(f"Checkout refused: {error}")
print("Checkout complete; credentials were not persisted in Git configuration")
PY_CHECKOUT
unset TOKEN SUBMODULE_TOKEN
- name: Install Go 1.27.1
run: |
set -euo pipefail
curl -fsSL -o "$RUNNER_TEMP/go.tgz" https://mirrors.aliyun.com/golang/go1.27.1.linux-amd64.tar.gz
tar -C /usr/local -xzf "$RUNNER_TEMP/go.tgz"
ln -sfn /usr/local/go/bin/go /usr/local/bin/go
ln -sfn /usr/local/go/bin/gofmt /usr/local/bin/gofmt
- name: Validate agent execution configuration
run: scripts/agent-exec validate --repo .
- name: Governance check
run: scripts/dm governance check --repo .
+6
View File
@@ -0,0 +1,6 @@
[submodule "deps/development-guidelines"]
path = deps/development-guidelines
url = ssh://git@git-ssh.u1680832.nyat.app:31411/weichen/Development-Guidelines.git
[submodule "deps/development-manager"]
path = deps/development-manager
url = ssh://git@git-ssh.u1680832.nyat.app:31411/weichen/Development-Manager.git
@@ -0,0 +1,53 @@
# Agent-System-Core 采纳 development-governance-v2 治理套件 任务卡
任务主记录:[Agent-System-Core PR #35](https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-Core/pulls/35)(本文件随 PR 描述维护)。
状态:已完成(闭合随本 PR 合入;合入以平台记录为准);owner:weichen。
## 基线与授权
- 权威仓:weichen/Agent-System-Core;root_target:main;immediate_target:main
- branch_kind:initiative;initiative_id:governance-adoption-Agent-System-Core
- R0(initial_main_sha):35560aa5a3fdc9d8f92bb4b2e9eece5254b94c41;工作区:/home/weichen/projects/Agent-System-Core-wt-feature-governance-adoption(worktree);分支:feature/governance-adoption
- 父任务信息(仅子任务填写):无
- accepting_requirements:false(单仓采纳 initiative,范围固定为下列十步,不接收新需求)
- 需求分流:verdict=NEW;selected_initiative=无;候选=无;理由=development-governance-v2 Phase 6 每个正式仓库独立 initiative;triage 收据=无(本仓采纳前尚无 triage 入口)
- 授权与交付终点:owner 已授权 development-governance-v2 全部实施(Agent-System-Dev 主记录 docs/superpowers/plans/2026-10-16-development-governance-v2-master.md);终点为本 PR 合入 main 且采纳状态 active。分支保护与 tag 由用户执行。
- 实施执行:agent-per-unit(配置:AGENT-EXECUTION.md;外部 Agent 一单元一新进程/会话/工作区)
## 目标与非目标
目标(Phase 6 十步):固定 Guidelines SHA(deps/development-guidelines @ 2688fd2be6a52c0bf110e7e6366b6f291ab5e4eb);增加 AGENT-EXECUTION.md;增加共享执行器薄入口(deps/development-manager @ 42e675fec8e0069646319fcd298e61d03d8cbfd5 + scripts/dm、scripts/agent-exec、scripts/task);四条路由(implementation/repair/test/review);任务卡模板与分支元数据;CI 中启用 schema 校验(.gitea/workflows/governance.yml:agent-exec validate + governance check);一次正例运行;负例(缺配置、坏收据、越界路径、未知副作用);独立 Review + CI;采纳状态 active。
非目标:不改业务代码与既有测试;不改分支保护(由用户执行);不发布 tag。
引导说明:AGENT-EXECUTION.md 由 host 以固定版本治理套件(dm-server governance init @ 42e675fec8e0069646319fcd298e61d03d8cbfd5)生成并作为引导配置提交(执行器运行前必须存在有效配置;沿用 DM 采纳先例);其余文件由实施单元生成。
## Agent 实施收据
| 单元 ID | 预期范围 | 角色 | 候选顺序 | attempt | CLI/模型 | 终态 | transport | fallback | 源码外收据路径 |
|---|---|---|---|---|---|---|---|---|---|
| governance-adoption-Agent-System-Core-r1 | 13 个允许路径(治理文件 + 两个 gitlink) | dde4f359 | implementation | cursor→antigravity→pi | run 9a7ec135(dm-server 42e675f,attempts=1) | cursor / not-observable | success | 98cfc6408d49(apply 快进) | 否 | /tmp/gov-receipt-Agent-System-Core-r1.json |
| governance-adoption-Agent-System-Core-repin-r1 | 9 个允许路径(治理文件 + 两个 gitlink) | a160b03c | implementation | cursor→antigravity→pi | run e64b5afe(dm-server pinned,attempts=1) | cursor / not-observable | success | 1ada9955d57a(apply 快进) | 否 | /tmp/gov-receipt-Agent-System-Core-repin-r1.json |
## 同步记录
| 节点 | sync_base_sha | tested_head_sha | checked_at | 结果 |
|---|---|---|---|---|
| 启动 | 35560aa5a3fdc9d8f92bb4b2e9eece5254b94c41 | 35560aa5a3fdc9d8f92bb4b2e9eece5254b94c41 | 2026-10-17T05:51:28Z | 一致 |
## 结果与验证(完成后填写)
- 结果:治理套件已采纳——Guidelines 与 Development-Manager gitlink 固定、AGENT-EXECUTION.md 四条路由、共享执行器薄入口、pre-commit admit、governance CI;采纳状态 active(随合入生效)。
- 验证:见下表(命令输出由 /tmp/gov-neg/ev.sh 写入 .task/evidence/governance-adoption/,SELF 除非另注)。
- 影响与剩余项:不改业务代码;本地启用钩子需由人执行 `git config core.hooksPath scripts/hooks`;将 governance 检查设为分支保护必需项属用户双钥匙事项(命令见 Agent-System-Dev 治理主记录)。
| 时间(UTC) | 命令 | 被测 HEAD | exit | 来源 | 摘要/位置 |
|---|---|---|---|---|---|
| 20261017T061900Z | `scripts/dm governance check --repo .` | 98cfc6408d49 | 0 | SELF | ok fixtures;[输出](../evidence/governance-adoption/00-20261017T061900Z.log) sha256:ae4439e39cad7e8d |
| 20261017T061900Z | `scripts/agent-exec validate --repo .` | 98cfc6408d49 | 0 | SELF | validate: ok;[输出](../evidence/governance-adoption/01-20261017T061900Z.log) sha256:89ea92d2c3d1f9e4 |
| 20261017T061900Z | `python3 /tmp/gov-neg/adopt_cases.py .` | 98cfc6408d49 | 0 | SELF | [verdict] ALL PASS cases=5;[输出](../evidence/governance-adoption/02-20261017T061900Z.log) sha256:64f13535108476f9 |
| 20261017T071536Z | `scripts/dm governance check --repo .` | 1ada9955d57a | 0 | SELF | ok fixtures;[输出](../evidence/governance-adoption/03-20261017T071536Z.log) sha256:f46b6a39dd69f693 |
| 20261017T071536Z | `scripts/agent-exec validate --repo .` | 1ada9955d57a | 0 | SELF | validate: ok;[输出](../evidence/governance-adoption/04-20261017T071536Z.log) sha256:4a0c76e79c70e3bb |
| 20261017T071536Z | `python3 /tmp/gov-neg/adopt_cases.py .` | 1ada9955d57a | 0 | SELF | [verdict] ALL PASS cases=5;[输出](../evidence/governance-adoption/05-20261017T071536Z.log) sha256:3eb026a392f8336b |
| — | 候选 HEAD CI | 18f617d4e8cd | 0 | GATE | success governance / governance (pull_request)=success(/weichen/Agent-System-Core/actions/runs/3535/jobs/5611) |
| — | 独立 Review | 18f617d4e8cd | 0 | REPLAY | cursor-agent-stable --mode ask 全新只读会话(fresh_session=true,session id not-observable;codex/pi 因 Token Plan 429 不可用)VERDICT: APPROVE,无阻塞项 |
@@ -0,0 +1,19 @@
command: scripts/dm governance check --repo .
cwd: /home/weichen/projects/Agent-System-Core-wt-feature-governance-adoption
head: 98cfc6408d49dd88d957bb2dd13ca37bebe9facf
exit: 0
utc: 20261017T061900Z
---
ok gitlink deps/development-guidelines
ok gitlink deps/development-manager
ok agent-execution
ok file AGENTS.md
ok file PROJECT.md
ok file policy/guidelines-adoption.md
ok file .task/templates/task-card.md
ok executable scripts/agent-exec
ok executable scripts/hooks/pre-commit
ok executable scripts/dm
ok executable scripts/task
ok adoption status
ok fixtures
@@ -0,0 +1,7 @@
command: scripts/agent-exec validate --repo .
cwd: /home/weichen/projects/Agent-System-Core-wt-feature-governance-adoption
head: 98cfc6408d49dd88d957bb2dd13ca37bebe9facf
exit: 0
utc: 20261017T061900Z
---
validate: ok
@@ -0,0 +1,13 @@
command: python3 /tmp/gov-neg/adopt_cases.py .
cwd: /home/weichen/projects/Agent-System-Core-wt-feature-governance-adoption
head: 98cfc6408d49dd88d957bb2dd13ca37bebe9facf
exit: 0
utc: 20261017T061900Z
---
[object] Agent-System-Core-wt-feature-governance-adoption HEAD=98cfc6408d49dd88d957bb2dd13ca37bebe9facf
PASS positive-run-apply: run exit=0 terminal=success apply exit=0 head=b38a8a0da1df
PASS missing-config: run exit=2 terminal=invalid-config validate exit=2
PASS bad-receipt: apply exit=4 head_unchanged=True msg=apply: no local integrity record: changed paths do not match the transport diff
PASS out-of-scope-path: run exit=5 terminal=scope-expansion transport=False
PASS unknown-side-effect: run exit=4 terminal=failed-unknown transport=False
[verdict] ALL PASS cases=5
@@ -0,0 +1,19 @@
command: scripts/dm governance check --repo .
cwd: /home/weichen/projects/Agent-System-Core-wt-feature-governance-adoption
head: 1ada9955d57af1dcfb750db2f01a1bcc40fd3ac4
exit: 0
utc: 20261017T071536Z
---
ok gitlink deps/development-guidelines
ok gitlink deps/development-manager
ok agent-execution
ok file AGENTS.md
ok file PROJECT.md
ok file policy/guidelines-adoption.md
ok file .task/templates/task-card.md
ok executable scripts/agent-exec
ok executable scripts/hooks/pre-commit
ok executable scripts/dm
ok executable scripts/task
ok adoption status
ok fixtures
@@ -0,0 +1,7 @@
command: scripts/agent-exec validate --repo .
cwd: /home/weichen/projects/Agent-System-Core-wt-feature-governance-adoption
head: 1ada9955d57af1dcfb750db2f01a1bcc40fd3ac4
exit: 0
utc: 20261017T071536Z
---
validate: ok
@@ -0,0 +1,13 @@
command: python3 /tmp/gov-neg/adopt_cases.py .
cwd: /home/weichen/projects/Agent-System-Core-wt-feature-governance-adoption
head: 1ada9955d57af1dcfb750db2f01a1bcc40fd3ac4
exit: 0
utc: 20261017T071536Z
---
[object] Agent-System-Core-wt-feature-governance-adoption HEAD=1ada9955d57af1dcfb750db2f01a1bcc40fd3ac4
PASS positive-run-apply: run exit=0 terminal=success apply exit=0 head=f6303ea75059
PASS missing-config: run exit=2 terminal=invalid-config validate exit=2
PASS bad-receipt: apply exit=4 head_unchanged=True msg=apply: no local integrity record: changed paths do not match the transport diff
PASS out-of-scope-path: run exit=5 terminal=scope-expansion transport=False
PASS unknown-side-effect: run exit=4 terminal=failed-unknown transport=False
[verdict] ALL PASS cases=5
+66
View File
@@ -0,0 +1,66 @@
# <任务标题> 任务卡
任务主记录:<Issue/PR 链接,或注明"本文件随 PR 描述维护">。
状态:<进行中 / 待审核 / 已合入 / 已放弃>;owner:<填写>。
## 基线与授权
- 权威仓:<仓 URL 或逻辑 ID>;root_target:main;immediate_target:<main 或 feature/initiative>
- branch_kind:<initiative | child | standalone>;initiative_id:<稳定 ID,普通任务为空>
- R0(initial_main_sha):<完整 SHA>;工作区:<路径>(worktree / clone);分支:<feature|fix|hotfix/...>
- 父任务信息(仅子任务填写):parent_branch=<父分支>;parent_head_sha=<SHA>;parent_pr=<父 PR>
- accepting_requirements:<true | false>(仅 initiative 可为 true;冻结后为 false)
- 需求分流:verdict=<JOIN | NEW>;selected_initiative=<分支或无>;候选=<分支@HEAD 列表或无>;理由=<不适配/适配依据>;triage 收据=<源码外路径与摘要>
- 授权与交付终点:<本次允许的动作与终点;未授权事项写明>
- 实施执行:agent-per-unit(配置:AGENT-EXECUTION.md;外部 Agent 一单元一新进程/会话/工作区)
## 目标与非目标
<预期结果、受影响入口/模块/契约;明确不做什么。>
## Agent 实施收据
按根目录 AGENT-EXECUTION.md 路由;外部 Agent 一单元一新进程/会话/隔离工作区。实施、修复与测试必须通过登记的候选执行;未配置或候选安全耗尽停在 unavailable/blocked,禁止 host 隐式代写。
| 单元 ID | 预期范围 | 角色 | 候选顺序 | attempt | CLI/模型 | 终态 | transport | fallback | 源码外收据路径 |
|---|---|---|---|---|---|---|---|---|---|
| 待定义 | — | NOT_RUN | NOT_RUN | NOT_RUN | NOT_RUN | NOT_RUN | NOT_RUN | NOT_RUN | — |
## 复用材料(task-start 自动检索结果摘录)
- 相关近期提交:<git log -- <paths> 命中;无则写无>。
- 相关经验条目:<检索命中;无则写无>。
## 同步记录
| 节点 | sync_base_sha | tested_head_sha | checked_at | 结果 |
|---|---|---|---|---|
| 启动 | <R0> | <HEAD> | <日期时间> | <一致/已同步> |
| 验收前 | <填写> | <填写> | <填写> | <填写> |
字段没有发生的写"无",不省略。本卡与 PR 描述同源:开 PR 时将"目标与非目标、结果与验证、影响与剩余项"复制进 PR 描述,不另写第二份。
## 交付调度(有多个就绪任务时)
- 调度记录 / entry_id / 当前 attempt_id:<平台或调度服务链接及标识;未入队写无>。
- 入队源 HEAD / owner / 依赖:<完整 SHA、身份、依赖或无>。
- 固定候选引用:<调度尝试中的 base/head、组件与配置;未固定写无>。
- 窗口、最终 CI、Review 与真实合入结果:<引用调度记录及原始证据,不复制全队列>。
定义见 [合入调度与 CI 分配](../standards/merge-queue.md)。本段在候选固定前整理;固定后先使用源码之外的记录保存运行结果,再按项目闭合流程回填。
## 结果与验证(完成后填写)
- 结果:<交付了什么;未发生写无>。
- 验证:<结论性摘要:PASS/FAIL/SKIP/NOT_RUN 逐项;逐条证据见下表,来源标注与写入规则见 [按影响选择验证与证据](../standards/verification.md)>。
- 影响与剩余项:<影响面、遗留风险、后续任务>。
| 时间(UTC) | 命令 | 被测 HEAD | exit | 来源 | 摘要/位置 |
|---|---|---|---|---|---|
| <时间> | <命令;由项目 evidence 工具写入,无工具时附命令+对象 SHA+输出 digest 并标 SELF> | <HEAD> | <exit> | GATE/REPLAY/SELF | <摘要/位置> |
## 回收(task-finish)
- 合入核对:<分支已包含于目标分支的核对输出>。
- 未跟踪/ignored 文件处置:<归档/可再生/存疑 逐项;无则写无>。
- 回收动作:<worktree remove、分支删除、prune;放弃路径注明原因>。
+67
View File
@@ -0,0 +1,67 @@
# Project Agent Execution Configuration
# 项目工程 Agent 执行路由配置
适用范围:定义本项目中由 AI / Agent 主导的代码实施、修复、测试与审阅所调用的 Agent CLI 路由。
解析器识别正文中唯一一个 ```agent-execution 代码块。正文外的说明文字可根据项目需要调整。
通用硬规则见 Development-Guidelines 的 [Agent 执行与协作契约](deps/development-guidelines/standards/agent-execution.md)。
本配置为项目本地路由权威,声明具体的候选 profile、尝试次数上限、超时、集成入口与豁免路径;
代码块须通过 `deps/development-guidelines/templates/schemas/agent-execution.schema.json` 校验后才能登记为 active。
`fallback_to_host` 只能为 `never`;旧值 `all-unavailable` 仅供迁移工具读取,不能通过准入。
下例的 CLI 名称、命令与路径均为占位,按项目实际执行器替换。
```agent-execution
schema: agent-execution/v1
execution:
fresh_process_per_unit: true
permission: run-everything
fallback_to_host: never
max_parallel: 3
timeout_seconds: 7200
idle_timeout_seconds: 600
summary_bytes: 16384
raw_output_bytes: 10485760
max_attempts_per_profile: 3
emergency_profile: codex
roles:
implementation: [cursor, antigravity, pi]
repair: [cursor, antigravity, pi]
test: [pi, antigravity, cursor]
review: [pi, antigravity, cursor, codex]
profiles:
cursor:
adapter: cursor
executable: "cursor-agent-stable"
model: auto
enabled: true
antigravity:
adapter: antigravity
executable: agy
model: auto
enabled: true
pi:
adapter: pi
executable: pi
model: auto
enabled: true
codex:
adapter: codex
executable: codex
model: auto
enabled: true
integration:
exempt_paths: [".task/**", "docs/superpowers/specs/**", "docs/superpowers/plans/**"]
transport:
command: "scripts/agent-exec apply"
admission:
command: "scripts/agent-exec admit"
cleanup:
command: "scripts/agent-exec cleanup"
```
+18
View File
@@ -34,3 +34,21 @@
- **SSH key**:`~/.ssh/home_gitea`(ED25519,公钥指纹
`SHA256:GYXaOXIMeloQ1fKSfdJ/ndgPQzs/Ix7Hk62ekfkfQ20`,Gitea 侧密钥名 GMKtec);
`~/.ssh/config` 已有 `git-ssh.u1680832.nyat.app` 主机条目,克隆/推送直接可用。
## Agent 执行与新项目准入(强制)
1. 缺 Guidelines 固定版本(`deps/development-guidelines` gitlink 未就绪或 HEAD 不符)时,Agent 只能只读分析,不得实施。
2. 缺有效 `AGENT-EXECUTION.md`(`scripts/dm governance check` 未通过)时禁止 AI 实施。
3. 缺共享执行器(`scripts/agent-exec` 或 `deps/development-manager` 不可用)时,状态为 `blocked/unavailable`,不得改由 host 替代。
4. 不允许 host 代写实施单元;实施、修复与测试必须经 `AGENT-EXECUTION.md` 登记的候选执行。
5. 人类直接开发按其自身授权与项目规则进行,不受本条款约束。
6. 分支保护与规范 tag 由用户负责设置与维护,Agent 不得代为设置。
AI 实施单元只能通过 `scripts/agent-exec run` 运行(配置与路由见 AGENT-EXECUTION.md),并由 `scripts/agent-exec apply` 集成。
入口:
- 需求分流:`scripts/task triage discover|decide|verify`
- 任务启动:`scripts/task start …`
- PR 检查:`scripts/task pr-check …`
- Agent 执行:`scripts/agent-exec run|apply|admit|validate`
+3
View File
@@ -8,6 +8,9 @@
在本仓根目录执行 `go test ./...` 验证 Go 契约与不变量;纯文档修改执行
`git diff --check` 并核对受影响链接、命令和来源。本仓没有 Makefile。
治理门禁(与 `.gitea/workflows/governance.yml` 相同):在本仓根目录依次执行
`scripts/agent-exec validate --repo .` 与 `scripts/dm governance check --repo .`,两者均须通过。
修改 `ts/types.ts` 后在 Dev 仓运行 `make contracts` 同步消费者,再以 `make test`
验证固定组件组合;单独运行 Core 测试不能代替提供方与消费者的兼容验证。
本仓提供公共契约,不是独立部署服务;当前能力以源码和对应验证记录为准。
+15 -14
View File
@@ -12,20 +12,21 @@ import "time"
type ActivityCard struct {
ID ID `json:"id"`
// ProjectID/ConversationID 定位归属;ConversationID 为空表示项目级卡片(远期跨会话收件箱)。
ProjectID ID `json:"projectId"`
ConversationID ID `json:"conversationId,omitempty"`
SourceRunID ID `json:"sourceRunId,omitempty"` // 溯源:产生卡片的 run
AnchorMessageID ID `json:"anchorMessageId,omitempty"` // 互定位:出生消息(↙ 定位到对话)
Kind CardKind `json:"kind"`
Title string `json:"title"`
Status CardStatus `json:"status"`
Tone string `json:"tone,omitempty"` // ok | warn | danger | info
Body []UINode `json:"body,omitempty"`
Actions []UIAction `json:"actions,omitempty"` // 走命令总线;未绑定 command 降级为发消息
Pinned bool `json:"pinned,omitempty"`
Work *WorkCard `json:"work,omitempty"` // optional background-work snapshot; never a foreground approval
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
ProjectID ID `json:"projectId"`
ConversationID ID `json:"conversationId,omitempty"`
SourceRunID ID `json:"sourceRunId,omitempty"` // 溯源:产生卡片的 run
AnchorMessageID ID `json:"anchorMessageId,omitempty"` // 互定位:出生消息(↙ 定位到对话)
Kind CardKind `json:"kind"`
Title string `json:"title"`
Status CardStatus `json:"status"`
Tone string `json:"tone,omitempty"` // ok | warn | danger | info
Task *TaskSnapshot `json:"task,omitempty"`
Body []UINode `json:"body,omitempty"`
Actions []UIAction `json:"actions,omitempty"` // 走命令总线;未绑定 command 降级为发消息
Pinned bool `json:"pinned,omitempty"`
Work *WorkCard `json:"work,omitempty"` // optional background-work snapshot; never a foreground approval
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
}
// WorkCard keeps the complete saved result and an optional, non-blocking next step
+47 -46
View File
@@ -13,18 +13,19 @@ type ParsedDocument struct {
}
type DocMeta struct {
Filename string `json:"filename"`
MIME string `json:"mime,omitempty"`
Parser string `json:"parser"` // builtin:md / builtin:docx / mineru / agent
Confidence float64 `json:"confidence,omitempty"` // 0–1;交叉验证差异块拉低
CrossCheck *CrossCheck `json:"crossCheck,omitempty"`
ParsedAt time.Time `json:"parsedAt"`
Origin *DocumentOrigin `json:"origin,omitempty"`
Filename string `json:"filename"`
MIME string `json:"mime,omitempty"`
Parser string `json:"parser"` // builtin:md / builtin:docx / mineru / agent
Confidence float64 `json:"confidence,omitempty"` // 0–1;交叉验证差异块拉低
CrossCheck *CrossCheck `json:"crossCheck,omitempty"`
ParsedAt time.Time `json:"parsedAt"`
}
type CrossCheck struct {
With string `json:"with"` // 交叉验证的另一解析器
DiffBlocks int `json:"diffBlocks"`
Verdict string `json:"verdict"` // agree | differ
With string `json:"with"` // 交叉验证的另一解析器
DiffBlocks int `json:"diffBlocks"`
Verdict string `json:"verdict"` // agree | differ
}
type DocBlockType string
@@ -39,13 +40,13 @@ const (
)
type DocBlock struct {
Type DocBlockType `json:"type"`
Level int `json:"level,omitempty"` // heading
Text string `json:"text,omitempty"` // para/heading/list 项拼接/code
Items []string `json:"items,omitempty"` // list
Rows [][]string `json:"rows,omitempty"` // table(首行为表头)
Ref string `json:"ref,omitempty"` // image-ref 的对象键
Confidence float64 `json:"confidence,omitempty"`
Type DocBlockType `json:"type"`
Level int `json:"level,omitempty"` // heading
Text string `json:"text,omitempty"` // para/heading/list 项拼接/code
Items []string `json:"items,omitempty"` // list
Rows [][]string `json:"rows,omitempty"` // table(首行为表头)
Ref string `json:"ref,omitempty"` // image-ref 的对象键
Confidence float64 `json:"confidence,omitempty"`
}
// PlainText 把文档压成纯文本(附件注入与全文索引用);表格按行拼接。
@@ -88,60 +89,60 @@ func (d ParsedDocument) PlainText() string {
// ParserDesc 注册表条目(来源标记:builtin/plugin/...;一切可禁用)。
type ParserDesc struct {
ID string `json:"id"`
Formats []string `json:"formats"` // 支持的扩展名
ID string `json:"id"`
Formats []string `json:"formats"` // 支持的扩展名
Source SourceKind `json:"source"`
Note string `json:"note,omitempty"`
Note string `json:"note,omitempty"`
}
// ---- 检索(4.12)----
// KnowledgeDoc 是检索语料的一条文档(来自 ingest 或插件知识库,带来源标记)。
type KnowledgeDoc struct {
ID ID `json:"id"`
Owner ID `json:"owner,omitempty"` // 空 = 共享(插件级)知识
ProjectID ID `json:"projectId,omitempty"` // 空 = 插件级知识库
Source string `json:"source"` // upload | artifact | plugin:<id>
Title string `json:"title"`
Ref string `json:"ref,omitempty"` // 工件/文件引用
Chunk string `json:"chunk"`
ID ID `json:"id"`
Owner ID `json:"owner,omitempty"` // 空 = 共享(插件级)知识
ProjectID ID `json:"projectId,omitempty"` // 空 = 插件级知识库
Source string `json:"source"` // upload | artifact | plugin:<id>
Title string `json:"title"`
Ref string `json:"ref,omitempty"` // 工件/文件引用
Chunk string `json:"chunk"`
CreatedAt time.Time `json:"createdAt"`
}
type RetrievalHit struct {
Doc KnowledgeDoc `json:"doc"`
Score float64 `json:"score"`
Kind string `json:"kind"` // fulltext | vector | plugin
Doc KnowledgeDoc `json:"doc"`
Score float64 `json:"score"`
Kind string `json:"kind"` // fulltext | vector | plugin
}
type RetrievalQuery struct {
ProjectID ID `json:"projectId,omitempty"`
Text string `json:"text"`
TopK int `json:"topK,omitempty"`
ProjectID ID `json:"projectId,omitempty"`
Text string `json:"text"`
TopK int `json:"topK,omitempty"`
Sources []string `json:"sources,omitempty"` // 过滤来源
}
// ---- 记忆(4.13 契约;实现远期)----
type MemoryEntry struct {
ID string `json:"id"`
Scope string `json:"scope"` // user | project
ProjectID ID `json:"projectId,omitempty"`
Type string `json:"type"` // fact | preference | decision | episode | procedure
Content string `json:"content"`
Source string `json:"source"` // run:<id> | manual
Confidence float64 `json:"confidence,omitempty"`
CreatedAt time.Time `json:"createdAt"`
LastAccessed time.Time `json:"lastAccessed"`
ExpiresAt *time.Time `json:"expiresAt,omitempty"`
ID string `json:"id"`
Scope string `json:"scope"` // user | project
ProjectID ID `json:"projectId,omitempty"`
Type string `json:"type"` // fact | preference | decision | episode | procedure
Content string `json:"content"`
Source string `json:"source"` // run:<id> | manual
Confidence float64 `json:"confidence,omitempty"`
CreatedAt time.Time `json:"createdAt"`
LastAccessed time.Time `json:"lastAccessed"`
ExpiresAt *time.Time `json:"expiresAt,omitempty"`
}
// ---- 上传文件 ----
type UploadInfo struct {
ArtifactID ID `json:"artifactId"`
Filename string `json:"filename"`
MIME string `json:"mime,omitempty"`
Size int64 `json:"size"`
ArtifactID ID `json:"artifactId"`
Filename string `json:"filename"`
MIME string `json:"mime,omitempty"`
Size int64 `json:"size"`
Parsed *ParsedDocument `json:"parsed,omitempty"`
}
Vendored Submodule
+1
+37
View File
@@ -0,0 +1,37 @@
# 通用规范采纳记录
- 项目/负责人:Agent-System-Core / weichen
- 状态:active
- 规范位置:`deps/development-guidelines`
- 规范性文档目录:`policy/`(本仓现有 `policy/README.md`;项目规则与制度放此处)
- 过程文档位置:仓内固定目录 `.task/`(任务卡与任务主记录;任务主记录同时随 PR 描述维护,豁免理由见「项目差异」)
- 版本权威:本仓 gitlink `deps/development-guidelines` @ `2688fd2be6a5`(完整 SHA `2688fd2be6a52c0bf110e7e6366b6f291ab5e4eb`);可读标签:无
- 批准/生效依据:feature/governance-adoption PR(Agent-System-Core)
- 替代范围和迁移说明:无
| 规范/工作流 | 适用条件与范围 | 采纳或不适用理由 | 执行方式/证据 |
|---|---|---|---|
| core/baseline.md | 日常工作 | 采纳:所有任务的硬边界、默认做法与完成声明基线 | manual |
| workflows/delivery.md、debugging.md、handoff.md | 交付、排障与交接 | 采纳:本仓以 PR 交付,Bug 排障与会话交接走统一流程 | manual |
| standards/collaboration.md | 并行共同起点、两级分支、节点同步与陈旧候选拒绝 | 采纳:PR 合入前须同步最新目标分支并附证据(见 AGENTS.md) | manual;暂无真实平台负例,未登记 enforced |
| standards/merge-queue.md | 多个就绪任务的最终同步、CI、Review 与合入调度 | 不适用:本仓由单一 owner 串行合入,当前无多个就绪任务竞争交付窗口;出现时另行登记 | 不适用 |
| standards/agent-execution.md | 工程 Agent CLI 执行路由、会话隔离与受控集成 | 采纳:允许 AI 协助代码实施;配置见 AGENT-EXECUTION.md | AGENT-EXECUTION.md + scripts/agent-exec(validate / admit);证据:governance check 与正负例(.task/feature-governance-adoption.md) |
| standards/verification.md | 验证与结论 | 采纳:完成声明须附实际命令输出 | 命令见 PROJECT.md「验证」节(`go test ./...`、`git diff --check`、`scripts/agent-exec validate --repo .`、`scripts/dm governance check --repo .`);CI:`.gitea/workflows/governance.yml` 运行治理门禁 |
| standards/module-contracts.md、standards/multi-repo.md | 公共契约(Go 类型、黄金样本、TS 镜像)的边界,以及依赖仓以 gitlink 固定版本 | 采纳:本仓是公共契约库,治理依赖以 gitlink 固定 | manual;gitlink 与 `.gitmodules` 固定,CI 物化白名单见 `.gitea/workflows/governance.yml`;契约一致性由 `conformance_test.go` 与 `testdata/golden` 覆盖 |
| standards/security.md | CI 凭据、submodule 取回与执行工具边界 | 采纳:CI 仅以限定 URL 的凭据取回两个治理 gitlink,凭据不落盘 | manual;`.gitea/workflows/governance.yml` 白名单与凭据约束 |
| workflows/design-verification.md、standards/testability.md | 契约增量的设计与验证、纯函数的可独立测试性 | 采纳:契约变更按增量设计验收,并以黄金样本与一致性测试验证 | manual;`conformance_test.go`、`testdata/golden` |
| standards/failure-containment.md、data-reliability.md、observability.md、configuration.md、release-operations.md、automation.md | 运行时服务、数据库、部署发布、定时自动化与故障控制 | 不适用:本仓只含契约与纯函数,不含 I/O、数据库或运行服务,不独立部署(见 PROJECT.md) | 不适用 |
## 项目差异
| 原规则/章节 | 项目采用方式 | 原因与风险 | 负责人/复查条件 |
|---|---|---|---|
| 过程文档默认放独立过程仓 | 任务卡与任务主记录放仓内 `.task/`,AGENT-EXECUTION.md 的 `exempt_paths` 已豁免 `.task/**` | 单一 owner 的小仓库,过程记录体量小,独立过程仓成本不划算;风险是过程记录与代码同仓,禁止写入凭据或 token | weichen;协作人增加或过程记录需跨仓共享时复查 |
## 本次升级或首次接入验证
- 入口:`AGENTS.md` 保留原内容并追加「Agent 执行与新项目准入(强制)」;`PROJECT.md`「验证」节补充 `scripts/agent-exec validate --repo .` 与 `scripts/dm governance check --repo .`;`AGENT-EXECUTION.md` 原样保留(`governance init --adopt` 跳过已存在文件)。
- 版本获取:`deps/development-guidelines` @ `2688fd2be6a5`,`deps/development-manager` @ `bd3a7de57a3a`;`.gitmodules` 使用规范 SSH 地址,不含凭证或本机路径。
- 占位符:模板占位符已全部替换;`policy/guidelines-adoption.md` 与追加的准入段中不再有模板尖括号文字。
- 冲突检查:仓内原无其他采纳记录(无 `policy/adoption.md`),原无旧版 Agent 执行入口(无 `scripts/agent_exec.py`),原无 `.gitea/workflows`,治理 workflow 为新增,无需修改既有 CI。
- 正负例与 Review/CI 证据:见 `.task/feature-governance-adoption.md`。
+4
View File
@@ -0,0 +1,4 @@
#!/usr/bin/env bash
# 共享 Agent 执行器薄入口:转调 scripts/dm 的 agent-exec 子命令(validate / run / apply / admit / cleanup)。
set -euo pipefail
exec "$(dirname "$0")/dm" agent-exec "$@"
Executable
+55
View File
@@ -0,0 +1,55 @@
#!/usr/bin/env bash
# 共享 dm-server 薄入口:读取 deps/development-manager 的 gitlink 钉住提交,
# 按该提交构建并缓存 dm-server,再 exec 其子命令(agent-exec、task、governance)。执行语义与退出码以该二进制为准。
set -euo pipefail
root=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)
dm="$root/deps/development-manager"
die() { echo "dm: $*" >&2; exit 2; }
# git 钩子会导出仓库本地变量(GIT_DIR、GIT_INDEX_FILE 等),它们会让 `git -C "$dm"` 解析到外层仓库。
# 所有针对 DM 检出的 git 与 go 调用都在清除这些变量后执行;读取外层 gitlink 与最终 exec 仍保留继承环境。
dm_local_env="GIT_DIR GIT_WORK_TREE GIT_INDEX_FILE GIT_PREFIX GIT_OBJECT_DIRECTORY GIT_ALTERNATE_OBJECT_DIRECTORIES GIT_COMMON_DIR GIT_GRAFT_FILE GIT_NAMESPACE GIT_CONFIG GIT_CONFIG_PARAMETERS GIT_CONFIG_COUNT GIT_SHALLOW_FILE GIT_IMPLICIT_WORK_TREE $(git rev-parse --local-env-vars 2>/dev/null || true)"
dm_clean_env() { for v in $dm_local_env; do unset "$v"; done; }
dmgit() ( dm_clean_env; git -C "$dm" "$@" )
# 1. 钉住版本只来自索引中的 gitlink(mode 160000),不读取工作区文件。
entry=$(git -C "$root" ls-files -s -- deps/development-manager 2>/dev/null || true)
[ -n "$entry" ] || die "索引中缺少 deps/development-manager 的 gitlink,无法确定钉住的 DM 版本"
read -r mode pin _stage _path <<<"$entry"
[ "$mode" = 160000 ] || die "deps/development-manager 不是 gitlink(mode=$mode)"
[[ "$pin" =~ ^[0-9a-f]{40}$ ]] || die "gitlink 提交格式无效:$pin"
# 2. 检出必须存在且确为 DM 独立仓库(避免 git -C 误解析到外层仓库),HEAD 必须等于钉住提交。
[ -e "$dm/.git" ] || die "deps/development-manager 未检出;请按钉住提交 $pin 检出该 gitlink"
top=$(dmgit rev-parse --show-toplevel 2>/dev/null || true)
[ -n "$top" ] && [ "$top" = "$(cd "$dm" && pwd -P)" ] \
|| die "deps/development-manager 不是独立检出;请按钉住提交 $pin 检出该 gitlink"
head=$(dmgit rev-parse HEAD 2>/dev/null || true)
[ "$head" = "$pin" ] \
|| die "deps/development-manager HEAD(${head:-未知})与钉住提交 $pin 不一致;请按钉住提交检出"
# 3. 检出工作树必须干净(忽略嵌套 submodule 状态)。
dirty=$(dmgit status --porcelain --ignore-submodules=all) \
|| die "无法读取 deps/development-manager 的工作树状态"
[ -z "$dirty" ] || die "deps/development-manager 存在未提交改动,拒绝运行(请先清理该检出)"
# 4. 二进制按钉住提交缓存;缺失时在缓存目录内临时构建,完成后原子改名,避免留下半成品。
cache="${DM_CACHE:-${XDG_CACHE_HOME:-$HOME/.cache}/development-manager/dm-server}"
bin="$cache/dm-server-$pin"
if [ ! -x "$bin" ]; then
command -v go >/dev/null 2>&1 || die "缺少 go,无法构建 dm-server($pin)"
mkdir -p "$cache"
cache=$(cd "$cache" && pwd -P)
bin="$cache/dm-server-$pin"
work=$(mktemp -d "$cache/build-$pin.XXXXXX")
if ! (dm_clean_env; cd "$dm" && GOWORK=off go build -trimpath -o "$work/dm-server" ./cmd/dm-server); then
rm -rf "$work"
die "构建 dm-server 失败($pin)"
fi
mv -f "$work/dm-server" "$bin"
rm -rf "$work"
fi
exec "$bin" "$@"
+16
View File
@@ -0,0 +1,16 @@
#!/usr/bin/env bash
# 本地检查(pre-commit):集成分支直提拒绝 + 分支命名 + 本地完整性核对。权威准入在 PR(baseline.md:26)。
branch=$(git rev-parse --abbrev-ref HEAD)
case "$branch" in
main|master)
echo "pre-commit: 拒绝——集成分支 ${branch} 不得直接提交,走 feature 分支 + PR(collaboration.md)" >&2
exit 1 ;;
esac
echo "$branch" | grep -qE '^(feature|fix|hotfix|release)/[A-Za-z0-9._-]+$' || {
echo "pre-commit: 拒绝——分支名须为 feature|fix|hotfix|release/<slug>,当前:${branch}" >&2
exit 1
}
root=$(git rev-parse --show-toplevel)
# admit 只是本地完整性/篡改证据(SELF):同一 OS 用户可读取本地 HMAC 密钥并绕过本钩子,
# 它不是 GATE,也不是可信身份。缺失或无效的本地记录仍拒绝;交付信任来自精确 HEAD 的 CI 或独立 REPLAY。
"$root/scripts/agent-exec" admit --repo "$root"
Executable
+4
View File
@@ -0,0 +1,4 @@
#!/usr/bin/env bash
# 通用任务入口:转调 scripts/dm 的 task 子命令(triage / start / pr-check)。
set -euo pipefail
exec "$(dirname "$0")/dm" task "$@"
+330
View File
@@ -0,0 +1,330 @@
package core
import (
"encoding/json"
"fmt"
"strings"
"time"
)
type DocumentOrigin struct {
ArtifactID ID `json:"artifactId"`
ContentHash string `json:"contentHash"`
ParserRevision string `json:"parserRevision"`
}
type TaskPhase struct {
ID string `json:"id"`
Label string `json:"label"`
ObservedAt time.Time `json:"observedAt,omitempty"`
}
type TaskSourceRef struct {
ID string `json:"id"`
ArtifactID string `json:"artifactId"`
ContentHash string `json:"contentHash"`
ParserRevision string `json:"parserRevision"`
BlockIndex int `json:"blockIndex"`
Label string `json:"label"`
Quote string `json:"quote,omitempty"`
Availability string `json:"availability,omitempty"`
}
type TaskResultRef struct {
ArtifactID ID `json:"artifactId,omitempty"`
SurfaceID ID `json:"surfaceId,omitempty"`
Version string `json:"version,omitempty"`
ContentHash string `json:"contentHash,omitempty"`
Availability string `json:"availability"`
Name string `json:"name,omitempty"`
}
type TaskFinding struct {
ID string `json:"id"`
Text string `json:"text"`
Impact string `json:"impact,omitempty"`
Kind string `json:"kind"`
Status string `json:"status"`
Revision int64 `json:"revision"`
Sources []TaskSourceRef `json:"sources"`
Assumptions string `json:"assumptions,omitempty"`
Corrects string `json:"corrects,omitempty"`
}
type TaskSnapshot struct {
SchemaVersion int `json:"schemaVersion"`
TaskID ID `json:"taskId"`
AttemptID ID `json:"attemptId"`
CardID ID `json:"cardId"`
ProjectID ID `json:"projectId"`
ConversationID ID `json:"conversationId"`
SourceMessageID ID `json:"sourceMessageId,omitempty"`
ParentRunID ID `json:"parentRunId,omitempty"`
RunID ID `json:"runId,omitempty"`
OwnerInstanceID string `json:"ownerInstanceId"`
ExecutionEpoch int64 `json:"executionEpoch,omitempty"`
Revision int64 `json:"revision"`
SourceSeq int64 `json:"sourceSeq"`
StreamScope string `json:"streamScope"`
InputRevision string `json:"inputRevision,omitempty"`
Title string `json:"title"`
Goal string `json:"goal,omitempty"`
ExecutionState string `json:"executionState"`
OutcomeCompleteness string `json:"outcomeCompleteness"`
DeliveryState string `json:"deliveryState"`
Phase TaskPhase `json:"phase"`
Focus string `json:"focus,omitempty"`
Coverage string `json:"coverage,omitempty"`
Remaining string `json:"remaining,omitempty"`
NextStep string `json:"nextStep,omitempty"`
Conclusion string `json:"conclusion,omitempty"`
Findings []TaskFinding `json:"findings,omitempty"`
Limitations []string `json:"limitations,omitempty"`
Inputs []TaskSourceRef `json:"inputs,omitempty"`
Actions []UIAction `json:"actions,omitempty"`
ResultRefs []TaskResultRef `json:"resultRefs,omitempty"`
LastActivityAt time.Time `json:"lastActivityAt,omitempty"`
LastMeaningfulUpdateAt time.Time `json:"lastMeaningfulUpdateAt,omitempty"`
CheckpointKeys map[string]string `json:"checkpointKeys,omitempty"`
CheckpointCount int `json:"checkpointCount,omitempty"`
CheckpointSeq int64 `json:"checkpointSeq,omitempty"`
}
type TaskSourceQuote struct {
SourceID string `json:"sourceId"`
BlockIndex int `json:"blockIndex"`
Quote string `json:"quote"`
}
type WorkCheckpointCandidate struct {
CheckpointID string `json:"checkpointId"`
PhaseID string `json:"phaseId"`
Focus string `json:"focus,omitempty"`
Remaining string `json:"remaining,omitempty"`
NextStep string `json:"nextStep,omitempty"`
Findings []WorkFindingCandidate `json:"findings"`
}
type WorkFindingCandidate struct {
FindingKey string `json:"findingKey"`
Text string `json:"text"`
Impact string `json:"impact,omitempty"`
Kind string `json:"kind"`
Assumptions string `json:"assumptions,omitempty"`
Corrects string `json:"corrects,omitempty"`
Sources []TaskSourceQuote `json:"sources"`
Evidence *WorkFindingEvidence `json:"evidence,omitempty"`
}
// WorkFindingEvidence is a model-supplied candidate, not a persisted proof.
// Backend checks the quoted source text and computes any resulting statement.
type WorkEvidencePremise struct {
Role string `json:"role"`
SourceIndex int `json:"sourceIndex"`
Value *int `json:"value,omitempty"`
}
type WorkFindingEvidence struct {
Mode string `json:"mode"`
Premises []WorkEvidencePremise `json:"premises"`
Result *int `json:"result,omitempty"`
}
func validateWorkFindingEvidence(e *WorkFindingEvidence, sourceCount int) error {
if e == nil {
return nil
}
var required []string
switch e.Mode {
case "direct_relation":
required = []string{"direct_relation"}
if e.Result != nil {
return fmt.Errorf("checkpoint.evidence: direct relation cannot have result")
}
case "difference":
required = []string{"total", "phase"}
if e.Result == nil || *e.Result < 0 || *e.Result > 1000000 {
return fmt.Errorf("checkpoint.evidence: difference requires bounded result")
}
case "unresolved_relation":
required = []string{"total", "phase", "dependent"}
if e.Result != nil {
return fmt.Errorf("checkpoint.evidence: unresolved relation cannot have result")
}
default:
return fmt.Errorf("checkpoint.evidence: unknown mode")
}
if len(e.Premises) != len(required) {
return fmt.Errorf("checkpoint.evidence: wrong premise count")
}
roles := make(map[string]bool, len(required))
for _, premise := range e.Premises {
if roles[premise.Role] || premise.SourceIndex < 0 || premise.SourceIndex >= sourceCount {
return fmt.Errorf("checkpoint.evidence: duplicate role or invalid source index")
}
roles[premise.Role] = true
if e.Mode == "direct_relation" {
if premise.Value != nil {
return fmt.Errorf("checkpoint.evidence: direct relation cannot have value")
}
} else if premise.Value == nil || *premise.Value < 0 || *premise.Value > 1000000 {
return fmt.Errorf("checkpoint.evidence: count premise requires bounded value")
}
}
for _, role := range required {
if !roles[role] {
return fmt.Errorf("checkpoint.evidence: missing premise role")
}
}
return nil
}
// Validate enforces wire limits; owner/source authorization belongs to Backend.
func (s TaskSnapshot) Validate() error {
if s.SchemaVersion != 1 {
return fmt.Errorf("task.schema: unsupported")
}
if s.TaskID == "" || s.AttemptID == "" || s.CardID == "" || s.ProjectID == "" || s.ConversationID == "" || s.OwnerInstanceID == "" {
return fmt.Errorf("task.scope: missing identity")
}
if s.StreamScope != "conversation:"+s.ConversationID {
return fmt.Errorf("task.scope: inconsistent stream")
}
if s.Revision < 1 || s.Revision > 9007199254740991 || s.SourceSeq < 0 || s.SourceSeq > 9007199254740991 || s.ExecutionEpoch < 0 {
return fmt.Errorf("task.revision: unsafe cursor")
}
switch s.ExecutionState {
case "queued", "running", "awaiting_user", "completed", "failed", "interrupted":
default:
return fmt.Errorf("task.state: unknown")
}
if (s.ExecutionState == "running" || s.ExecutionState == "awaiting_user") && s.RunID == "" {
return fmt.Errorf("task.run: active task requires run")
}
switch s.OutcomeCompleteness {
case "none", "partial", "complete":
default:
return fmt.Errorf("task.outcome: unknown")
}
switch s.DeliveryState {
case "pending", "available", "reported":
default:
return fmt.Errorf("task.delivery: unknown")
}
active := 0
for _, f := range s.Findings {
if f.ID == "" || f.Revision < 1 {
return fmt.Errorf("task.finding: missing identity")
}
switch f.Kind {
case "material_record", "analysis", "provisional", "needs_user", "verified":
default:
return fmt.Errorf("task.finding.kind: unknown")
}
switch f.Status {
case "active":
active++
case "corrected", "withdrawn", "superseded":
default:
return fmt.Errorf("task.finding.status: unknown")
}
}
if active > 12 {
return fmt.Errorf("task.findings: too many active")
}
b, err := json.Marshal(s)
if err != nil {
return err
}
if len(b) > 64*1024 {
return fmt.Errorf("task.size: exceeds 64KiB")
}
return nil
}
func (s TaskSnapshot) Terminal() bool {
return s.ExecutionState == "completed" || s.ExecutionState == "failed" || s.ExecutionState == "interrupted"
}
func ValidateWorkCheckpoint(c WorkCheckpointCandidate) error {
if strings.TrimSpace(c.CheckpointID) == "" || len(c.CheckpointID) > 128 {
return fmt.Errorf("checkpoint.id: required or too long")
}
switch c.PhaseID {
case "reading", "crosscheck", "summarizing", "draft-ready":
default:
return fmt.Errorf("checkpoint.phase: unknown")
}
if len(c.Findings) == 0 || len(c.Findings) > 6 {
return fmt.Errorf("checkpoint.findings: require 1..6")
}
keys := map[string]bool{}
for _, f := range c.Findings {
switch f.Kind {
case "material_record", "analysis", "provisional", "needs_user":
default:
return fmt.Errorf("checkpoint.kind: model cannot grant verified status")
}
if f.FindingKey == "" || keys[f.FindingKey] || strings.TrimSpace(f.Text) == "" {
return fmt.Errorf("checkpoint.finding: empty or duplicate key")
}
keys[f.FindingKey] = true
if len(f.Sources) == 0 {
return fmt.Errorf("checkpoint.sources: evidence required")
}
for _, src := range f.Sources {
if src.SourceID == "" || src.BlockIndex < 0 || strings.TrimSpace(src.Quote) == "" {
return fmt.Errorf("checkpoint.source: invalid")
}
}
if err := validateWorkFindingEvidence(f.Evidence, len(f.Sources)); err != nil {
return err
}
if (f.Kind == "analysis" || f.Kind == "provisional") && strings.TrimSpace(f.Assumptions) == "" {
return fmt.Errorf("checkpoint.assumptions: required")
}
}
b, err := json.Marshal(c)
if err != nil {
return err
}
if len(b) > 16*1024 {
return fmt.Errorf("checkpoint.size: exceeds 16KiB")
}
return nil
}
func (s TaskSnapshot) SummaryBody() []UINode {
labels := map[string]string{"queued": "排队中", "running": "进行中", "awaiting_user": "需要你处理", "completed": "已完成", "failed": "执行失败", "interrupted": "已中断"}
var lines []string
for _, f := range s.Findings {
if f.Status == "active" {
line := f.Text
if f.Impact != "" {
line += ";" + f.Impact
}
lines = append(lines, line)
}
}
note := strings.Join(lines, "\n")
if note == "" {
note = TaskSummaryNoFindingsYet
if s.ExecutionState == "queued" {
note = "尚未开始处理,等待执行资源"
}
if s.Terminal() {
note = s.Conclusion
if note == "" {
note = "没有可用阶段成果"
}
}
}
v := TaskSummaryView{Focus: s.Focus, FindingsNote: note, Remaining: s.Remaining, NextStep: s.NextStep, OutcomeLine: s.Conclusion}
var body []UINode
if s.Terminal() {
body = v.FinishedBody(labels[s.ExecutionState], nil)
} else {
body = v.RunningBody(labels[s.ExecutionState], nil)
}
if s.Coverage != "" {
body = append(body, UINode{Type: UIKV, KV: [][2]string{{"提供范围", s.Coverage}}})
}
if len(s.Limitations) > 0 {
body = append(body, UINode{Type: UIList, Title: "范围与限制", Items: s.Limitations})
}
for _, r := range s.ResultRefs {
if r.ArtifactID != "" && r.Availability == "available" {
body = append(body, UINode{Type: UIDocRef, DocID: r.ArtifactID, Title: r.Name})
}
}
return body
}
+147
View File
@@ -0,0 +1,147 @@
package core
import (
"encoding/json"
"strings"
"testing"
)
// Loss of the optional task object makes refresh discard stage findings.
func TestTaskSnapshotCardRoundTrip(t *testing.T) {
raw := []byte(`{"id":"card1","projectId":"p1","conversationId":"c1","kind":"progress","status":"active","task":{"schemaVersion":1,"taskId":"t1","attemptId":"a1","cardId":"card1","revision":4,"executionState":"running","focus":"核对材料","findings":[{"id":"f1","text":"日期不同","kind":"material_record","status":"active","revision":1}]}}`)
var card ActivityCard
if err := json.Unmarshal(raw, &card); err != nil {
t.Fatal(err)
}
encoded, err := json.Marshal(card)
if err != nil {
t.Fatal(err)
}
var restored map[string]json.RawMessage
if err := json.Unmarshal(encoded, &restored); err != nil {
t.Fatal(err)
}
if _, ok := restored["task"]; !ok {
t.Fatal("task findings were lost in card persistence")
}
var task map[string]json.RawMessage
if err := json.Unmarshal(restored["task"], &task); err != nil {
t.Fatal(err)
}
if string(task["revision"]) != "4" || string(task["focus"]) != `"核对材料"` {
t.Fatal("revision/focus did not survive")
}
}
func validTaskSnapshot() TaskSnapshot {
return TaskSnapshot{SchemaVersion: 1, TaskID: "t1", AttemptID: "a1", CardID: "card1", ProjectID: "p1", ConversationID: "c1", OwnerInstanceID: "i1", Revision: 1, ExecutionState: "queued", OutcomeCompleteness: "none", DeliveryState: "pending", StreamScope: "conversation:c1", Title: "整理材料"}
}
func TestTaskSnapshotRejectsUnsafeAndUnboundState(t *testing.T) {
for _, mutate := range []func(*TaskSnapshot){
func(s *TaskSnapshot) { s.TaskID = "" }, func(s *TaskSnapshot) { s.AttemptID = "" },
func(s *TaskSnapshot) { s.Revision = 9007199254740992 }, func(s *TaskSnapshot) { s.SourceSeq = -1 },
func(s *TaskSnapshot) { s.ExecutionState = "imagined" }, func(s *TaskSnapshot) { s.StreamScope = "conversation:other" },
func(s *TaskSnapshot) { s.ExecutionState = "running" },
} {
s := validTaskSnapshot()
mutate(&s)
if s.Validate() == nil {
t.Errorf("invalid snapshot accepted: %+v", s)
}
}
if err := validTaskSnapshot().Validate(); err != nil {
t.Fatal(err)
}
}
func TestWorkCheckpointRejectsVerifiedAndEmptyEvidence(t *testing.T) {
c := WorkCheckpointCandidate{CheckpointID: "cp1", PhaseID: "crosscheck", Findings: []WorkFindingCandidate{{FindingKey: "date", Text: "日期不同", Kind: "verified", Sources: []TaskSourceQuote{{SourceID: "src1", Quote: "六月"}}}}}
if err := ValidateWorkCheckpoint(c); err == nil || !strings.Contains(err.Error(), "kind") {
t.Fatal("model granted verified status", err)
}
c.Findings[0].Kind = "material_record"
c.Findings[0].Sources = nil
if ValidateWorkCheckpoint(c) == nil {
t.Fatal("source-free fact accepted")
}
c.Findings[0].Sources = []TaskSourceQuote{{SourceID: "src1", Quote: "六月"}}
if err := ValidateWorkCheckpoint(c); err != nil {
t.Fatal(err)
}
c.Findings[0].Text = strings.Repeat("x", 17000)
if ValidateWorkCheckpoint(c) == nil {
t.Fatal("unbounded candidate accepted")
}
}
func TestWorkCheckpointEvidenceModesAndBounds(t *testing.T) {
base := func() WorkCheckpointCandidate {
return WorkCheckpointCandidate{CheckpointID: "cp-evidence", PhaseID: "crosscheck", Findings: []WorkFindingCandidate{{
FindingKey: "phase", Text: "待核对", Kind: "needs_user",
Sources: []TaskSourceQuote{{SourceID: "total", Quote: "总12项"}, {SourceID: "phase", Quote: "一期8项"}, {SourceID: "dependent", Quote: "其中3项依赖接口"}},
}}}
}
n := func(v int) *int { return &v }
total := WorkEvidencePremise{Role: "total", SourceIndex: 0, Value: n(12)}
phase := WorkEvidencePremise{Role: "phase", SourceIndex: 1, Value: n(8)}
dependent := WorkEvidencePremise{Role: "dependent", SourceIndex: 2, Value: n(3)}
for _, tc := range []struct {
name string
evidence WorkFindingEvidence
valid bool
}{
{"direct", WorkFindingEvidence{Mode: "direct_relation", Premises: []WorkEvidencePremise{{Role: "direct_relation", SourceIndex: 0}}}, true},
{"difference", WorkFindingEvidence{Mode: "difference", Premises: []WorkEvidencePremise{total, phase}, Result: n(4)}, true},
{"unresolved", WorkFindingEvidence{Mode: "unresolved_relation", Premises: []WorkEvidencePremise{total, phase, dependent}}, true},
{"unknown mode", WorkFindingEvidence{Mode: "prediction", Premises: []WorkEvidencePremise{total, phase}}, false},
{"missing result", WorkFindingEvidence{Mode: "difference", Premises: []WorkEvidencePremise{total, phase}}, false},
{"extra result", WorkFindingEvidence{Mode: "unresolved_relation", Premises: []WorkEvidencePremise{total, phase, dependent}, Result: n(3)}, false},
{"duplicate role", WorkFindingEvidence{Mode: "difference", Premises: []WorkEvidencePremise{total, total}, Result: n(4)}, false},
{"missing premise", WorkFindingEvidence{Mode: "unresolved_relation", Premises: []WorkEvidencePremise{total, phase}}, false},
{"negative index", WorkFindingEvidence{Mode: "direct_relation", Premises: []WorkEvidencePremise{{Role: "direct_relation", SourceIndex: -1}}}, false},
{"foreign index", WorkFindingEvidence{Mode: "direct_relation", Premises: []WorkEvidencePremise{{Role: "direct_relation", SourceIndex: 3}}}, false},
{"negative value", WorkFindingEvidence{Mode: "difference", Premises: []WorkEvidencePremise{{Role: "total", SourceIndex: 0, Value: n(-1)}, phase}, Result: n(4)}, false},
{"large value", WorkFindingEvidence{Mode: "difference", Premises: []WorkEvidencePremise{{Role: "total", SourceIndex: 0, Value: n(1000001)}, phase}, Result: n(4)}, false},
{"direct value", WorkFindingEvidence{Mode: "direct_relation", Premises: []WorkEvidencePremise{{Role: "direct_relation", SourceIndex: 0, Value: n(1)}}}, false},
{"missing value", WorkFindingEvidence{Mode: "difference", Premises: []WorkEvidencePremise{{Role: "total", SourceIndex: 0}, phase}, Result: n(4)}, false},
} {
t.Run(tc.name, func(t *testing.T) {
c := base()
c.Findings[0].Evidence = &tc.evidence
err := ValidateWorkCheckpoint(c)
if (err == nil) != tc.valid {
t.Fatalf("valid=%v err=%v", tc.valid, err)
}
})
}
c := base()
c.Findings[0].Evidence = &WorkFindingEvidence{Mode: "difference", Premises: []WorkEvidencePremise{total, phase}, Result: n(4)}
c.Findings[0].Text = strings.Repeat("字", 5500)
if err := ValidateWorkCheckpoint(c); err == nil || !strings.Contains(err.Error(), "16KiB") {
t.Fatal("evidence bypassed checkpoint size cap", err)
}
}
func TestTaskSnapshotBodyPreservesLimitsAndHonestStates(t *testing.T) {
s := validTaskSnapshot()
s.Remaining = "图片内容未纳入"
s.ExecutionState = "failed"
s.Conclusion = "处理失败,已有发现可查看"
s.Findings = []TaskFinding{{ID: "f1", Text: "金额缺失", Kind: "material_record", Status: "active", Revision: 1}}
raw, _ := json.Marshal(s.SummaryBody())
for _, want := range []string{"执行失败", "图片内容未纳入", "金额缺失", "处理失败"} {
if !strings.Contains(string(raw), want) {
t.Errorf("lost critical summary %s", want)
}
}
}
func TestTaskSnapshotUnstartedAndFinishedDoNotClaimReading(t *testing.T) {
for _, state := range []string{"queued", "completed", "interrupted"} {
s := validTaskSnapshot()
s.ExecutionState = state
s.Conclusion = "处理已结束"
b, _ := json.Marshal(s.SummaryBody())
if strings.Contains(string(b), "正在读取") {
t.Errorf("%s falsely claims active reading", state)
}
}
}
+27 -1
View File
@@ -149,6 +149,7 @@ export interface ActivityCard {
id: ID; projectId: ID; conversationId?: ID;
sourceRunId?: ID; anchorMessageId?: ID;
kind: CardKind; title: string; status: CardStatus; tone?: string;
task?: TaskSnapshot;
body?: UINode[]; actions?: { id: string; label: string; style?: 'primary' | 'default' | 'danger'; command?: string }[];
pinned?: boolean; createdAt: string; updatedAt: string; work?: WorkCard;
}
@@ -350,7 +351,7 @@ export interface PluginPageDecl {
export interface ParsedDocument {
meta: {
filename: string; mime?: string; parser: string; confidence?: number;
filename: string; mime?: string; parser: string; confidence?: number; origin?: DocumentOrigin;
crossCheck?: { with: string; diffBlocks: number; verdict: 'agree' | 'differ' };
parsedAt: string;
};
@@ -413,3 +414,28 @@ export interface SurfaceMeta {
conversationId?: ID;
updatedAt: string;
}
// Persistent work projection; host-owned identities and revisions.
export interface DocumentOrigin { artifactId: ID; contentHash: string; parserRevision: string }
export interface TaskPhase { id: string; label: string; observedAt?: string }
export interface TaskSourceRef { id: string; artifactId: ID; contentHash: string; parserRevision: string; blockIndex: number; label: string; quote?: string; availability?: string }
export interface TaskResultRef { artifactId?: ID; surfaceId?: ID; version?: string; contentHash?: string; availability: string; name?: string }
export interface TaskFinding { id: string; text: string; impact?: string; kind: string; status: string; revision: number; sources: TaskSourceRef[]; assumptions?: string; corrects?: string }
export interface TaskSnapshot {
inputs?: TaskSourceRef[]
limitations?: string[]
schemaVersion: number; taskId: ID; attemptId: ID; cardId: ID; projectId: ID; conversationId: ID;
sourceMessageId?: ID; parentRunId?: ID; runId?: ID; ownerInstanceId: string; executionEpoch?: number;
revision: number; sourceSeq: number; streamScope: string; inputRevision?: string; title: string; goal?: string;
executionState: 'queued'|'running'|'awaiting_user'|'completed'|'failed'|'interrupted'; outcomeCompleteness: 'none'|'partial'|'complete'; deliveryState: 'pending'|'available'|'reported'; phase: TaskPhase;
focus?: string; coverage?: string; remaining?: string; nextStep?: string; conclusion?: string;
findings?: TaskFinding[]; actions?: UIAction[]; resultRefs?: TaskResultRef[]; lastActivityAt?: string; lastMeaningfulUpdateAt?: string;
checkpointKeys?: Record<string,string>; checkpointCount?: number; checkpointSeq?: number;
}
export interface TaskSourceQuote { sourceId: string; blockIndex: number; quote: string }
interface WorkEvidencePremise { role: "total" | "phase" | "dependent" | "direct_relation"; sourceIndex: number; value?: number }
interface WorkFindingEvidence { mode: "direct_relation" | "difference" | "unresolved_relation"; premises: WorkEvidencePremise[]; result?: number }
export interface WorkFindingCandidate { findingKey: string; text: string; impact?: string; kind: string; assumptions?: string; corrects?: string; sources: TaskSourceQuote[]; evidence?: WorkFindingEvidence }
export interface WorkCheckpointCandidate { checkpointId: string; phaseId: string; focus?: string; remaining?: string; nextStep?: string; findings: WorkFindingCandidate[] }
export interface UIAction { id: string; label: string; style?: string; command?: string }