@namewta/speculo 0.7.3 → 0.7.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/dist/src/migrations.js +190 -39
  2. package/dist/src/migrations.js.map +1 -1
  3. package/package.json +1 -1
  4. package/template/canonical/canonical-specdev-engineering-cognitive-mentor.md +51 -15
  5. package/template/canonical/canonical-specdev-goal-plan.md +183 -116
  6. package/template/canonical/canonical-specdev-grill-with-docs.md +51 -15
  7. package/template/canonical/canonical-specdev-spec.md +61 -21
  8. package/template/canonical/canonical-specdev-tickets.md +83 -43
  9. package/template/canonical/canonical-specdev-wayfinder.md +51 -15
  10. package/template/skills/migrate-runtime-state/references/migration-contract.md +3 -3
  11. package/template/skills/migrate-runtime-state/scripts/migrate-runtime-state.mjs +94 -12
  12. package/template/workflows/specdev/I-implement/I-implement.md +27 -26
  13. package/template/workflows/specdev/I-implement/evidence-template.md +18 -12
  14. package/template/workflows/specdev/I-implement/execution-preflight.md +11 -9
  15. package/template/workflows/specdev/I-init-setup/I-init-setup.md +2 -2
  16. package/template/workflows/specdev/I-init-setup/change-status-template.json +3 -3
  17. package/template/workflows/specdev/I-init-setup/config-template.json +5 -2
  18. package/template/workflows/specdev/INDEX.md +6 -6
  19. package/template/workflows/specdev/P-goal-plan/P-goal-plan.md +16 -16
  20. package/template/workflows/specdev/P-goal-plan/completion-control.md +8 -8
  21. package/template/workflows/specdev/P-goal-plan/goal-plan-template.md +20 -14
  22. package/template/workflows/specdev/P-goal-plan/lead-orchestration.md +5 -5
  23. package/template/workflows/specdev/P-goal-plan/orchestration-protocol.md +13 -13
  24. package/template/workflows/specdev/P-goal-plan/planning-modes.md +27 -15
  25. package/template/workflows/specdev/P-prototype/ui-prototype.md +1 -1
  26. package/template/workflows/specdev/T-tickets/T-tickets.md +4 -4
  27. package/template/workflows/specdev/T-tickets/ticket-readiness.md +3 -3
  28. package/template/workflows/specdev/T-tickets/ticket-template.md +6 -6
  29. package/template/workflows/specdev/T-tickets/tickets-map-template.md +2 -2
  30. package/template/workflows/specdev/common/README.md +1 -1
  31. package/template/workflows/specdev/common/rules/change-completion.md +2 -2
  32. package/template/workflows/specdev/common/rules/evidence-and-verification.md +10 -6
  33. package/template/workflows/specdev/common/rules/path-ownership.md +4 -4
  34. package/template/workflows/specdev/common/schemas/change-status.schema.json +31 -4
  35. package/template/workflows/specdev/common/schemas/config.schema.json +12 -6
  36. package/template/workflows/specdev/common/schemas/goal-plan.schema.json +15 -6
  37. package/template/workflows/specdev/common/skills/dev-worktree/SKILL.md +3 -3
  38. package/template/workflows/specdev/common/skills/dev-worktree/references/finalize.md +1 -1
  39. package/template/workflows/specdev/common/skills/subagent-delivery/SKILL.md +4 -4
  40. package/template/workflows/specdev/common/skills/subagent-delivery/references/external-web-subagent.md +1 -1
  41. package/template/workflows/specdev/common/skills/subagent-delivery/references/native-subagent.md +4 -4
  42. package/template/workflows/specdev/common/tools/README.md +2 -1
  43. package/template/workflows/specdev/common/tools/validate-specdev.mjs +261 -66
@@ -16,6 +16,9 @@ import {
16
16
  import { dirname, join, relative, resolve, sep } from "node:path";
17
17
 
18
18
  const STAGE_PREFIX = ".speculo-runtime-migrate-stage-";
19
+ const CONFIG_SCHEMA_VERSION = 5;
20
+ const GOAL_PLAN_SCHEMA_VERSION = 6;
21
+ const CHANGE_STATUS_SCHEMA_VERSION = 6;
19
22
  const ROLLBACK_NAME = ".speculo-runtime-migrate-rollback";
20
23
  const VALID_ACTIONS = new Set(["copy", "replace-json", "keep-current", "remove-current"]);
21
24
  const VALID_DECISIONS = new Set(["restore", "merge-json", "replace-json", "keep-current", "remove-current"]);
@@ -473,6 +476,52 @@ function validChangeStatusV4(status, expectedChange, expectedStatus) {
473
476
  });
474
477
  }
475
478
 
479
+ function validateChangeStatusV6(status, expectedChange, expectedStatus) {
480
+ const failures = [];
481
+ if (!isObject(status) || status.schema_version !== CHANGE_STATUS_SCHEMA_VERSION || status.artifact !== "change-status" || status.change !== expectedChange || !expectedStatus.has(status.change_status)) {
482
+ return ["invalid or incomplete change-status v6 contract: " + expectedChange];
483
+ }
484
+ if (!Array.isArray(status.worktrees)) return ["change-status v6 worktrees must be an array: " + expectedChange];
485
+ const previous = { ...status, schema_version: 5 };
486
+ if (!isObject(previous.execution_authorization) || !isObject(previous.leadership) || !Array.isArray(previous.works_run) || !Array.isArray(previous.claimed_investigations)) {
487
+ failures.push("change-status v6 is missing execution authority or leadership state: " + expectedChange);
488
+ }
489
+ const worktreeKeys = [
490
+ "ticket_id", "owner", "implementation_owner", "integration_owner", "provider", "base_sha",
491
+ "parent_branch", "branch", "workspace_ref", "source_checkpoint", "integration", "status", "updated_at",
492
+ ];
493
+ const integrationKeys = [
494
+ "status", "parent_ref", "parent_before_sha", "source_sha", "candidate_sha", "candidate_tree_sha",
495
+ "candidate_branch", "candidate_workspace_ref", "result_sha", "method", "conflict_paths", "verification",
496
+ "full_suite", "e2e", "evidence", "attempts", "promotion_status",
497
+ ];
498
+ for (const worktree of status.worktrees) {
499
+ if (!isObject(worktree)) { failures.push("change-status v6 contains an invalid worktree"); continue; }
500
+ if (!hasExactKeys(worktree, worktreeKeys) || worktree.provider !== "git" || !/^T-[0-9]{2,}$/.test(String(worktree.ticket_id))) {
501
+ failures.push("change-status v6 contains an incomplete worktree: " + String(worktree.ticket_id));
502
+ continue;
503
+ }
504
+ const current = worktree.workspace_ref === "current";
505
+ if (current && worktree.parent_branch !== worktree.branch) failures.push(`${worktree.ticket_id}: current branch must equal parent_branch`);
506
+ if (!current && worktree.parent_branch === worktree.branch) failures.push(`${worktree.ticket_id}: required branch must differ from parent_branch`);
507
+ const integration = isObject(worktree.integration) ? worktree.integration : {};
508
+ if (!hasExactKeys(integration, integrationKeys) || !Number.isInteger(integration.attempts) || integration.attempts < 0 || !Array.isArray(integration.conflict_paths)) {
509
+ failures.push(`${worktree.ticket_id}: integration contract is incomplete`);
510
+ continue;
511
+ }
512
+ for (const key of ["full_suite", "e2e"]) {
513
+ const suite = integration[key];
514
+ if (!isObject(suite) || !hasExactKeys(suite, ["required", "status", "reason", "evidence"]) || typeof suite.required !== "boolean") {
515
+ failures.push(`${worktree.ticket_id}: ${key} contract is incomplete`);
516
+ }
517
+ }
518
+ if (current && ["candidate_sha", "candidate_tree_sha", "candidate_branch", "candidate_workspace_ref"].some((key) => integration[key] !== null)) failures.push(`${worktree.ticket_id}: current workspace cannot contain candidate fields`);
519
+ if (current && integration.method !== null && integration.method !== "direct-parent") failures.push(`${worktree.ticket_id}: current workspace requires direct-parent`);
520
+ if (!current && integration.method === "direct-parent") failures.push(`${worktree.ticket_id}: required workspace cannot use direct-parent`);
521
+ }
522
+ return failures;
523
+ }
524
+
476
525
  function validateChangeStatusV4(status, expectedChange, expectedStatus) {
477
526
  return validChangeStatusV4(status, expectedChange, expectedStatus)
478
527
  ? []
@@ -537,9 +586,10 @@ function validGoalPlanV4(meta, change) {
537
586
  !nonEmptyString(meta.lead) ||
538
587
  !Number.isInteger(meta.implementation_agent_limit) ||
539
588
  meta.implementation_agent_limit < 1 ||
540
- meta.implementation_agent_limit > 3 ||
541
- meta.ticket_workspace_policy !== "required" ||
542
- meta.integration_gate !== "candidate-merge" ||
589
+ !new Set(["current", "required"]).has(meta.ticket_workspace_policy) ||
590
+ !new Set(["direct-parent", "candidate-merge"]).has(meta.integration_gate) ||
591
+ (meta.ticket_workspace_policy === "current" && meta.integration_gate !== "direct-parent") ||
592
+ (meta.ticket_workspace_policy === "required" && meta.integration_gate !== "candidate-merge") ||
543
593
  typeof meta.ready_for_execution !== "boolean" ||
544
594
  !Array.isArray(meta.modes)
545
595
  ) return false;
@@ -547,6 +597,17 @@ function validGoalPlanV4(meta, change) {
547
597
  new Set(meta.modes).size === meta.modes.length;
548
598
  }
549
599
 
600
+ function validGoalPlanV6(meta, change) {
601
+ const required = [
602
+ "schema_version", "artifact", "change", "status", "modes", "orchestration", "lead",
603
+ "implementation_agent_limit", "integration_attempt_limit", "ticket_workspace_policy", "integration_gate", "ready_for_execution",
604
+ ];
605
+ if (!isObject(meta) || !hasExactKeys(meta, required) || meta.schema_version !== GOAL_PLAN_SCHEMA_VERSION) return false;
606
+ const { integration_attempt_limit: integrationAttemptLimit, ...previous } = meta;
607
+ return validGoalPlanV4({ ...previous, schema_version: 4 }, change) &&
608
+ Number.isInteger(integrationAttemptLimit) && integrationAttemptLimit >= 1;
609
+ }
610
+
550
611
  async function validateGoalPlanV4(changeRoot, change) {
551
612
  const path = join(changeRoot, "goal-plan.md");
552
613
  if (!(await exists(path))) return [];
@@ -556,6 +617,14 @@ async function validateGoalPlanV4(changeRoot, change) {
556
617
  : ["Goal Plan is not the complete fixed Lead/candidate-integration v4 contract: " + change];
557
618
  }
558
619
 
620
+ async function validateGoalPlanV6(changeRoot, change) {
621
+ const path = join(changeRoot, "goal-plan.md");
622
+ if (!(await exists(path))) return [];
623
+ return validGoalPlanV6(parseGoalPlanFrontmatter(await readFile(path, "utf8")), change)
624
+ ? []
625
+ : ["Goal Plan is not the complete Lead/workspace v6 contract: " + change];
626
+ }
627
+
559
628
  function validSpecdevConfigV4(config) {
560
629
  const rootKeys = ["schema_version", "interaction_language", "artifact_language", "git", "execution", "verification", "planning"];
561
630
  if (
@@ -574,7 +643,6 @@ function validSpecdevConfigV4(config) {
574
643
  if (
575
644
  !Number.isInteger(config.execution.max_implementation_agents) ||
576
645
  config.execution.max_implementation_agents < 1 ||
577
- config.execution.max_implementation_agents > 3 ||
578
646
  typeof config.execution.deep_ticket_human_approval !== "boolean" ||
579
647
  !nonEmptyString(config.execution.shared_path_owner)
580
648
  ) return false;
@@ -586,6 +654,16 @@ function validSpecdevConfigV4(config) {
586
654
  typeof config.planning.require_evidence === "boolean";
587
655
  }
588
656
 
657
+ function validSpecdevConfigV5(config) {
658
+ const rootKeys = ["schema_version", "interaction_language", "artifact_language", "git", "execution", "verification", "planning"];
659
+ if (!isObject(config) || !hasExactKeys(config, rootKeys) || config.schema_version !== CONFIG_SCHEMA_VERSION || !isObject(config.git) || !isObject(config.execution) || !isObject(config.verification) || !isObject(config.planning)) return false;
660
+ if (!hasExactKeys(config.git, ["default_branch"]) || !(config.git.default_branch === null || typeof config.git.default_branch === "string")) return false;
661
+ if (!hasExactKeys(config.execution, ["max_implementation_agents", "max_integration_attempts", "deep_ticket_human_approval", "shared_path_owner"])) return false;
662
+ if (!Number.isInteger(config.execution.max_implementation_agents) || config.execution.max_implementation_agents < 1 || !Number.isInteger(config.execution.max_integration_attempts) || config.execution.max_integration_attempts < 1 || typeof config.execution.deep_ticket_human_approval !== "boolean" || !nonEmptyString(config.execution.shared_path_owner)) return false;
663
+ for (const key of ["test", "typecheck", "lint", "build"]) if (!(key in config.verification) || !stringOrNull(config.verification[key])) return false;
664
+ return new Set(["lite", "standard", "deep"]).has(config.planning.default_depth) && typeof config.planning.require_ready_gate === "boolean" && typeof config.planning.require_evidence === "boolean" && Number.isInteger(config.planning.ui_prototype_default_variants) && config.planning.ui_prototype_default_variants >= 1 && Number.isInteger(config.planning.ui_prototype_max_variants) && config.planning.ui_prototype_max_variants >= config.planning.ui_prototype_default_variants;
665
+ }
666
+
589
667
  async function validateSpecdev(speculoRoot) {
590
668
  const statusPath = join(speculoRoot, ".speculo", "specdev", "status.json");
591
669
  if (!(await exists(statusPath))) return [];
@@ -607,12 +685,14 @@ async function validateSpecdev(speculoRoot) {
607
685
  failures.push("missing active change state: " + entry.change);
608
686
  } else {
609
687
  const changeStatus = await readJson(path);
610
- failures.push(...validateChangeStatusV4(
611
- changeStatus,
612
- entry.change,
613
- new Set(["active", "blocked", "completed"]),
614
- ));
615
- failures.push(...await validateGoalPlanV4(dirname(path), entry.change));
688
+ if (changeStatus.schema_version === CHANGE_STATUS_SCHEMA_VERSION) {
689
+ failures.push(...validateChangeStatusV6(changeStatus, entry.change, new Set(["active", "blocked", "completed"])));
690
+ } else {
691
+ failures.push(...validateChangeStatusV4(changeStatus, entry.change, new Set(["active", "blocked", "completed"])));
692
+ }
693
+ failures.push(...(await exists(join(dirname(path), "goal-plan.md")) && (await readFile(join(dirname(path), "goal-plan.md"), "utf8")).startsWith("---\nschema_version: 6")
694
+ ? await validateGoalPlanV6(dirname(path), entry.change)
695
+ : await validateGoalPlanV4(dirname(path), entry.change)));
616
696
  }
617
697
  }
618
698
  const archived = new Set();
@@ -629,7 +709,9 @@ async function validateSpecdev(speculoRoot) {
629
709
  failures.push("missing archived change state: " + name);
630
710
  } else {
631
711
  const archivedStatus = await readJson(path);
632
- failures.push(...validateChangeStatusV4(archivedStatus, name, new Set(["archived"])));
712
+ failures.push(...(archivedStatus.schema_version === CHANGE_STATUS_SCHEMA_VERSION
713
+ ? validateChangeStatusV6(archivedStatus, name, new Set(["archived"]))
714
+ : validateChangeStatusV4(archivedStatus, name, new Set(["archived"]))));
633
715
  }
634
716
  }
635
717
  const changesRoot = join(speculoRoot, ".speculo", "specdev", "changes");
@@ -655,7 +737,7 @@ async function validateSpecdev(speculoRoot) {
655
737
  const configPath = join(speculoRoot, ".speculo", "specdev", "config.json");
656
738
  if (await exists(configPath)) {
657
739
  const config = await readJson(configPath);
658
- if (!validSpecdevConfigV4(config)) failures.push(".speculo/specdev/config.json is not the complete schema-v4 execution contract");
740
+ if (!validSpecdevConfigV5(config)) failures.push(".speculo/specdev/config.json is not the complete schema-v5 execution contract");
659
741
  }
660
742
  return failures;
661
743
  }
@@ -3,19 +3,19 @@ id: specdev/implement
3
3
  type: workflow-entry
4
4
  workflow: specdev
5
5
  name: 实现
6
- description: 基于 Ready Ticket 或获批小型 Spec 执行设计检查、TDD、动态派单、双轴审查、Ticket worktree commit、候选合并验证和 Lead Evidence 回写。
7
- keywords: [实现, TDD, Lead, subagent, worktree, candidate-merge, 代码审查, 证据]
6
+ description: 基于 Ready Ticket 或获批小型 Spec 执行设计检查、TDD、动态派单、双轴审查、按 Goal Plan 选择的 current workspace 或 Ticket worktree 提交、直接父分支或候选合并验证和 Lead Evidence 回写。
7
+ keywords: [实现, TDD, Lead, subagent, worktree, current workspace, direct-parent, candidate-merge, 代码审查, 证据]
8
8
  ---
9
9
 
10
10
  # 实现
11
11
 
12
- 本 work 保留模块设计检查、design-it-twice、TDD 红绿循环、双轴审查和证据治理。Ticket 模式固定使用来源 worktree、实现 commit parent-candidate 集成;Lead 根据实际情况自行实现或动态派单。
12
+ 本 work 保留模块设计检查、design-it-twice、TDD 红绿循环、双轴审查和证据治理。Ticket 模式按 Goal Plan `ticket_workspace_policy` 选择 current workspace 串行直接父分支或独立 worktree candidate-merge;Lead 根据实际情况自行实现或动态派单。
13
13
 
14
14
  ## 执行模式
15
15
 
16
16
  ### Ticket 模式(默认)
17
17
 
18
- 读取 Ready Ticket、Tickets Map 和可选 Goal Plan。存在 Goal Plan 时使用其中的 Lead;没有 Goal Plan 时,当前主会话作为该 Ticket 的 Lead。每个 Ticket 都建立独立 worktree,无论实现者是 Lead 还是 implementation subagent
18
+ 读取 Ready Ticket、Tickets Map 和可选 Goal Plan。存在 Goal Plan 时使用其中的 Lead 与 workspace 策略;没有 Goal Plan 时,当前主会话作为该 Ticket 的 Lead,并按 Direct Spec 规则执行,不推断 worktree 策略。`required` 模式每个 Ticket 建立独立 worktree;`current` 模式所有 Ticket 严格串行,使用当前分支和当前 workspace
19
19
 
20
20
  ### Direct Spec 模式
21
21
 
@@ -45,33 +45,33 @@ Git 已处于 merge/rebase 冲突时,先加载 `<Path>{roots.workflows}/specde
45
45
 
46
46
  ## 流程
47
47
 
48
- ### 1. 执行前预检与来源 worktree
48
+ ### 1. 执行前预检与 workspace
49
49
 
50
50
  加载 `<Path>{roots.workflows}/specdev/I-implement/execution-preflight.md</Path>`。
51
51
 
52
52
  Ticket 模式:
53
53
 
54
54
  1. 验证 Ready、依赖 Evidence、Spec/ADR/Goal Plan、一致性、路径 owner 和验证接缝;
55
- 2. 确认 Goal Plan schema v4(若存在)、Leadimplementation agent 上限与授权;
56
- 3. `purpose=ticket, operation=create|restore` 调用 `<Path>{roots.workflows}/specdev/common/skills/dev-worktree/SKILL.md</Path>`;
57
- 4. Lead 把 Ticket 设为 `in_progress`,change worktree 记录设为 `active`;
55
+ 2. 确认 Goal Plan schema v6(若存在)、Lead、动态 implementation/integration 上限与授权;
56
+ 3. `required` 模式以 `purpose=ticket, operation=create|restore` 调用 `<Path>{roots.workflows}/specdev/common/skills/dev-worktree/SKILL.md</Path>`;`current` 模式读取当前 branch、HEAD、dirty 状态并确认没有其他 Ticket implementation writer;
57
+ 4. Lead 把 Ticket 设为 `in_progress`;`required` 模式将 change worktree 记录设为 `active`,`current` 模式建立 current workspace 执行记录;
58
58
  5. 当前代码使合同失效时停止并返回对应上游 owner。
59
59
 
60
60
  Direct Spec 模式验证用户批准、轻量合同和 current workspace 唯一写入 owner;不创建虚假 Ticket/worktree 状态。
61
61
 
62
- **完成标准**:Ticket 来源 worktree、基线、owners、权限与实际 Git 一致;Direct Spec 的小型边界可判定。
62
+ **完成标准**:按策略完成 workspace、基线、owners、权限与实际 Git 一致;current 模式只有一个 implementation writer 且 Ticket 串行可恢复。
63
63
 
64
64
  ### 2. Lead 决定自行实现或动态派单
65
65
 
66
- Ticket 模式下,Lead 根据 Ticket 独立性、路径冲突、上下文、风险和平台能力决定。派单时以 `operation=dispatch` 调用 `<Path>{roots.workflows}/specdev/common/skills/subagent-delivery/SKILL.md</Path>`。Direct Spec 模式由 Lead 作为 current workspace 唯一写入 owner;可以派遣只读 review/research/test-observation agent,不派遣 implementation subagent 写 current workspace。
66
+ Ticket 模式下,Lead 根据 Ticket 独立性、路径冲突、上下文、风险和平台能力决定。派单时以 `operation=dispatch` 调用 `<Path>{roots.workflows}/specdev/common/skills/subagent-delivery/SKILL.md</Path>`。`current` 模式仍可派遣一个 implementation subagent 写当前 workspace,但必须等待其返回、Lead 验收并形成 commit 后才进入下一个 Ticket;`required` 模式 implementation subagent 绑定独立 Ticket worktree。Direct Spec 模式由 Lead 作为 current workspace 唯一写入 owner,不派遣 implementation subagent 写入。
67
67
 
68
- - implementation subagent 同时最多取 Goal Plan/config/平台上限的最小值且不超过三个;Lead 不计入;
68
+ - implementation subagent 同时取 Goal Plan/config/平台能力的共同上限;current 模式保持单 writer 串行安全不变量;Lead 不计入;
69
69
  - review/research/test-observation agent 不设置 SpecDev 数字上限,但保持只读;
70
- - implementation Packet 绑定唯一 Ticket worktree、checkpoint、路径、非 E2E 检查与 commit 返回;
70
+ - implementation Packet 按策略绑定唯一 Ticket workspace 或 current workspace、checkpoint、路径、非 E2E 检查与 commit 返回;
71
71
  - subagent 不写 SpecDev 工件、Evidence、父分支或 E2E 结果;
72
72
  - Lead 自行实现时仍遵循相同 worktree、commit 与返回事实合同。
73
73
 
74
- **完成标准**:只有一个 implementation owner 写当前 Ticket worktree,或 Direct Spec 只有 Lead 写 current workspace;所有 SpecDev 写入仍由 Lead 拥有。
74
+ **完成标准**:current 模式只有一个 implementation owner 写当前 workspace;required 模式只有一个 owner 写当前 Ticket worktreeDirect Spec 只有 Lead 写 current workspace;所有 SpecDev 写入仍由 Lead 拥有。
75
75
 
76
76
  ### 3. 设计检查
77
77
 
@@ -97,22 +97,22 @@ Ticket 模式下,Lead 根据 Ticket 独立性、路径冲突、上下文、风
97
97
 
98
98
  ### 5. 实现检查、commit 与 Lead 接收
99
99
 
100
- Ticket 模式的 implementation owner 在来源 worktree:
100
+ Ticket 模式的 implementation owner Goal Plan 策略在当前 workspace 或来源 worktree:
101
101
 
102
102
  - 运行 Ticket 要求的单元、组件、静态、类型、lint/build 等非 E2E 检查;
103
103
  - 审计 writable/shared/read-only 路径和新/既有/环境失败;
104
- - 在已授权时创建引用 Ticket ID 的实现 commit;
104
+ - 在已授权时创建引用 Ticket ID 的实现 commit;current 模式 commit 直接落在父分支,required 模式落在 Ticket branch;
105
105
  - 返回 commit、dirty 状态、实际路径、命令/结果、未运行项和恢复条件。
106
106
 
107
- Ticket 模式中,Lead 以 `operation=accept` 调用 subagent-delivery,重读 Git 状态、branch tip、commit、diff 和命令事实。无改动时将 Ticket 改为 `cancelled` 并记录原因;不得 empty commit 或 Evidence-only Done。来源 worktree 不运行 E2E
107
+ Ticket 模式中,Lead 以 `operation=accept` 调用 subagent-delivery,重读 Git 状态、branch tip、commit、diff 和命令事实。无改动时将 Ticket 改为 `cancelled` 并记录原因;不得 empty commit 或 Evidence-only Done。required 模式来源 worktree 不运行 E2E;current 模式适用 E2E 留给 Lead 的 direct-parent 验证。
108
108
 
109
109
  Direct Spec 模式由 Lead 在 current workspace 运行轻量合同要求的定向非 E2E 检查,审计获批可写范围,并在获得 implementation commit 授权后创建引用 change 的非空 commit;无需改动时记录事实并取消直接实现,不创建 empty commit。记录实施前基线、最终 checkpoint、dirty 状态、实际路径、命令结果、未运行项和恢复条件。
110
110
 
111
- **完成标准**:Ticket worktree clean 且 `source_checkpoint` 精确等于 branch tip;或 Direct Spec 的 current workspace checkpoint、路径和轻量合同一致。
111
+ **完成标准**:required 模式 Ticket worktree clean 且 `source_checkpoint` 精确等于 branch tip;current 模式 workspace clean 且 Ticket `result_sha` 精确等于父分支上的 implementation commit;或 Direct Spec 的 current workspace checkpoint、路径和轻量合同一致。
112
112
 
113
113
  ### 6. 双轴审查
114
114
 
115
- 调用 `<Path>{roots.workflows}/specdev/common/skills/code-review/SKILL.md</Path>`。Ticket 模式以 `base_sha` 与 `source_checkpoint` 为固定点;Direct Spec 以实施前基线与 current workspace 最终 checkpoint 为固定点:
115
+ 调用 `<Path>{roots.workflows}/specdev/common/skills/code-review/SKILL.md</Path>`。required Ticket `base_sha` 与 `source_checkpoint` 为固定点;current Ticket 以 Ticket 实施前基线与 implementation commit 为固定点;Direct Spec 以实施前基线与 current workspace 最终 checkpoint 为固定点:
116
116
 
117
117
  - 标准轴:正确性、模块设计、错误、安全、性能、并发、资源、测试与可维护性;
118
118
  - 规范轴:Spec/Ticket IN/OUT、实现合同、路径所有权、验证矩阵与 Goal Gate。
@@ -123,7 +123,7 @@ Direct Spec 模式由 Lead 在 current workspace 运行轻量合同要求的定
123
123
 
124
124
  ### 7. 最终集成与适用 E2E
125
125
 
126
- Ticket 模式中,Lead 以 `purpose=ticket, operation=finalize` 调用 dev-worktree:
126
+ `required` Ticket 模式中,Lead 以 `purpose=ticket, operation=finalize` 调用 dev-worktree:
127
127
 
128
128
  1. 在最新父分支的 Lead-owned candidate checkout 组合 source commit;
129
129
  2. 运行受影响集成/回归、项目父状态检查和 Ticket 标记 required 的 E2E;
@@ -134,13 +134,13 @@ Ticket 模式中,Lead 以 `purpose=ticket, operation=finalize` 调用 dev-work
134
134
 
135
135
  E2E 是否需要由 Ticket/Goal Plan 的实际跨边界风险决定,不限于 UI;不适用必须记录原因。
136
136
 
137
- Direct Spec 模式跳过 source worktree、candidate merge 和父分支推进。Lead current workspace 运行轻量合同要求的适用回归与 E2E,记录运行环境、命令、退出码和摘要;E2E 不得派给其他 agent。失败时不声明完成,保留最后可信 checkpoint 和恢复条件。全部通过后重读 Git 状态与最终 checkpoint。
137
+ `current` Ticket 模式跳过 source worktree、candidate merge 和 candidate checkout。Lead 在当前 workspace 运行 Ticket 要求的适用集成/回归与 E2E,记录运行环境、命令、退出码和摘要;E2E 不得派给其他 agent。失败时不声明完成,保留 Ticket commit、父 HEAD 和恢复条件。全部通过后重读父 HEAD/tree 并记录 `result_sha`。Direct Spec 模式同样跳过 source worktree、candidate merge 和父分支推进。
138
138
 
139
139
  ### 8. Evidence、状态与完成
140
140
 
141
- Lead 使用 `<Path>{roots.workflows}/specdev/I-implement/evidence-template.md</Path>` 写入 Ticket Evidence;Direct Spec 按该模板的 Direct Spec 适配说明写 `<Path>{roots.state}/specdev/changes/{change}/evidence/direct-spec.md</Path>`。Ticket Evidence 包含 source/candidate/result SHA、派单/返回、两层验证、双轴审查、E2E disposition、路径审计、偏差和残余风险;Direct Spec Evidence 使用实施前基线与 current workspace 最终 checkpoint,不伪造 Ticket/worktree/candidate 字段。
141
+ Lead 使用 `<Path>{roots.workflows}/specdev/I-implement/evidence-template.md</Path>` 写入 Ticket Evidence;Direct Spec 按该模板的 Direct Spec 适配说明写 `<Path>{roots.state}/specdev/changes/{change}/evidence/direct-spec.md</Path>`。Ticket Evidence 按策略记录 implementation/source、适用 candidate/result SHA、派单/返回、两层验证、双轴审查、E2E disposition、路径审计、偏差和残余风险;Direct Spec Evidence 使用实施前基线与 current workspace 最终 checkpoint,不伪造 Ticket/worktree/candidate 字段。
142
142
 
143
- Ticket 正常状态:`ready → in_progress → review → done`。`done` 要求 change worktree 已完成集成(`integrated`,或集成后已清理的 `removed`)、父 HEAD=result SHA 且包含 source commit。阻塞使用 `blocked`,契约偏差使用 `deviated`,无需改动使用 `cancelled`。Direct Spec 由当前 I-implement owner 按 `<Path>{roots.workflows}/specdev/common/rules/change-completion.md</Path>` 关闭 change。
143
+ Ticket 正常状态:`ready → in_progress → review → done`。`required` 的 `done` 要求 change worktree 已完成集成(`integrated` `removed`)、父 HEAD=result SHA 且包含 source commit;`current` 的 `done` 要求 current workspace clean、direct-parent 验证通过且父 HEAD=result SHA。阻塞使用 `blocked`,契约偏差使用 `deviated`,无需改动使用 `cancelled`。Direct Spec 由当前 I-implement owner 按 `<Path>{roots.workflows}/specdev/common/rules/change-completion.md</Path>` 关闭 change。
144
144
 
145
145
  按存在和当前模式同步 Ticket、Tickets Map、Goal Plan、`<Path>{roots.state}/specdev/changes/{change}/.status.json</Path>` 和全局状态;Direct Spec 不创建缺失的 Ticket/Map/Goal Plan。最后一个计划内 Ticket 完成后,Goal Plan 的 Lead 按 change completion 关闭;无 Goal Plan 的当前 I owner 承担同一门禁。需要远程 reconcile 时返回 T-triage,否则进入 Archive。
146
146
 
@@ -149,19 +149,20 @@ Ticket 正常状态:`ready → in_progress → review → done`。`done` 要
149
149
  ```bash
150
150
  node <Path>{roots.workflows}/specdev/common/tools/validate-specdev.mjs</Path> \
151
151
  --stage implement \
152
+ --repo <project-root> \
152
153
  <Path>{roots.state}/specdev/changes/{change}</Path>
153
154
  ```
154
155
 
155
156
  ### 9. 返回
156
157
 
157
- Ticket 模式返回 Ticket/change 状态、Evidence 完整路径、source workspace、source/candidate/result SHA、父分支、E2E disposition、未验证项和下一路由。Direct Spec 返回 change 状态、`<Path>{roots.state}/specdev/changes/{change}/evidence/direct-spec.md</Path>`、current workspace、实施前/最终 checkpoint、适用 E2E 和下一路由。push、PR、remote merge、deploy、migration、生产动作及来源 branch/worktree cleanup 只在独立授权时执行。
158
+ Ticket 模式返回 Ticket/change 状态、Evidence 完整路径、workspace locatorimplementation/source、适用 candidate/result SHA、父分支、E2E disposition、未验证项和下一路由。Direct Spec 返回 change 状态、`<Path>{roots.state}/specdev/changes/{change}/evidence/direct-spec.md</Path>`、current workspace、实施前/最终 checkpoint、适用 E2E 和下一路由。push、PR、remote merge、deploy、migration、生产动作及来源 branch/worktree cleanup 只在独立授权时执行。
158
159
 
159
160
  ## 完成标准
160
161
 
161
- - Ticket 模式的 worktree、实现 commit、双轴审查和 candidate gate 完整;Direct Spec 的轻量合同、current workspace checkpoint、双轴审查和最终验证完整;
162
- - source worktree E2ETicket 适用 E2E 由 Lead 在 parent-candidate 运行,Direct Spec 适用 E2E 由 Lead 在 current workspace 运行;
162
+ - Ticket 模式按策略完成 current workspace/direct-parent 或 worktree/implementation commit/candidate gateDirect Spec 的轻量合同、current workspace checkpoint、双轴审查和最终验证完整;
163
+ - current Ticket 的适用 E2E 由 Lead 在 current workspace 运行;required Ticket 的适用 E2E 由 Lead 在 parent-candidate 运行;Direct Spec 适用 E2E 由 Lead 在 current workspace 运行;
163
164
  - Lead 独立核对并写全部 SpecDev 工件;
164
- - Ticket 父分支只推进到通过的 candidateTicket Done 与实际 Git 一致;Direct Spec 的完成状态与 current workspace 最终 checkpoint 一致;
165
+ - current Ticket 父分支只推进到通过的 direct-parent 验证 commit;required Ticket 父分支只推进到通过的 candidate;两者 Ticket Done 都必须与实际 Git 一致;Direct Spec 的完成状态与 current workspace 最终 checkpoint 一致;
165
166
  - 实际路径、验证、偏差和状态可由 Evidence 恢复;
166
167
  - validator 无 error。
167
168
 
@@ -1,14 +1,14 @@
1
1
  # Evidence: <Ticket ID> — <Ticket title>
2
2
 
3
- Direct Spec 使用本模板时写入 `<Path>{roots.state}/specdev/changes/{change}/evidence/direct-spec.md</Path>`:Ticket、Goal Plan、source worktree 与 candidate 字段写“不适用:Direct Spec”,以实施前基线和 current workspace 最终 checkpoint 代替 source/candidate/result 链;第 5、7 节分别记录 current workspace 定向检查和 Lead 最终回归/E2E,不伪造 Ticket 状态。
3
+ 本模板按 Goal Plan 的 workspace/integration 策略记录实际验证环境;不适用的环境明确写 `not-applicable`,不伪造 source、candidate 或 result 链。Direct Spec 使用本模板时写入 `<Path>{roots.state}/specdev/changes/{change}/evidence/direct-spec.md</Path>`,以实施前基线和最终 checkpoint 代替 Ticket 集成链。
4
4
 
5
5
  - **Change:** `<change>`
6
6
  - **Ticket:** `<Path>{roots.state}/specdev/changes/{change}/ticket/{ticket-file}.md</Path>`
7
7
  - **Spec:** `<Path>{roots.state}/specdev/changes/{change}/spec.md</Path>`
8
8
  - **Goal Plan:** `<Path>{roots.state}/specdev/changes/{change}/goal-plan.md</Path>` / 不适用
9
9
  - **Lead:** `<owner-or-session-locator>`
10
- - **Source worktree/branch:** `<workspace_ref>` / `<branch>`
11
- - **Base/source/candidate/result SHA:** `<sha>` / `<sha>` / `<sha>` / `<sha>`
10
+ - **Workspace/branch:** `<workspace_ref>` / `<branch>`
11
+ - **Base/implementation-or-source/candidate/result SHA:** `<sha>` / `<sha>` / `<sha>` / `<sha>`
12
12
  - **状态:** review / done / blocked / deviated / cancelled
13
13
 
14
14
  ## 1. 实现摘要
@@ -44,18 +44,22 @@ subagent 不写本 Evidence;以上内容由 Lead 从实际 workspace、Git 和
44
44
 
45
45
  每个 Ticket 验收项恰好落到一行。
46
46
 
47
- ## 5. Source-worktree 验证
47
+ ## 5. Workspace Verification
48
+
49
+ 按 Goal Plan 记录 current workspace 或 source worktree 检查,并注明运行环境。
48
50
 
49
51
  | 命令或步骤 | 运行环境 | 结果 | 摘要 |
50
52
  |---|---|---|---|
51
- | ... | source-worktree | pass / fail / not-run | ... |
53
+ | ... | current-workspace | pass / fail / not-run | ... |
52
54
 
53
55
  - **失败后修复与重跑:** 无 / ...
54
56
  - **未运行检查:** 无 / 原因与风险
55
- - **E2E:** 禁止在 source-worktree 声明 pass;此处固定为 not-run: parent-candidate-owned
57
+ - **E2E:** Goal Plan E2E disposition 记录;未在本环境运行时说明 owner 与原因
56
58
 
57
59
  ## 6. 双轴审查
58
60
 
61
+ 标准轴与规范轴保持独立,分别记录固定输入、结果和修正。
62
+
59
63
  ### 标准轴
60
64
 
61
65
  - **固定输入:** `<base_sha>..<source_checkpoint>`
@@ -70,20 +74,22 @@ subagent 不写本 Evidence;以上内容由 Lead 从实际 workspace、Git 和
70
74
 
71
75
  两个轴隔离并按上述顺序记录。
72
76
 
73
- ## 7. Parent-candidate 集成验证
77
+ ## 7. Integration Verification
78
+
79
+ 按 Goal Plan 记录 direct-parent 或 parent-candidate 集成;未采用的字段写 `null` 或 `not-applicable`。
74
80
 
75
81
  | 项目 | 结果 |
76
82
  |---|---|
77
83
  | Parent before SHA | `<sha>` |
78
- | Source/candidate SHA | `<sha>` / `<sha>` |
79
- | Candidate branch/workspace | `<branch>` / `<workspace_ref>` |
80
- | Method/conflicts | fast-forward / merge-commit;无 / paths |
81
- | Candidate checks | 命令、运行环境 `parent-candidate`、结果 |
84
+ | Implementation/source SHA | `<sha>` / `<sha>` |
85
+ | Candidate branch/workspace | current / `<branch>` / `not-applicable` |
86
+ | Method/conflicts | direct-parent / fast-forward / merge-commit;无 / paths |
87
+ | Integration checks | 命令、运行环境 `current-workspace`、结果 |
82
88
  | E2E disposition | required / not-required: reason |
83
89
  | E2E result | pending / passed / failed / not-required;场景与证据 |
84
90
  | Parent result/re-read | `<sha>`;HEAD/tree/ancestor 核对 |
85
91
 
86
- Candidate failed/stale 时明确父分支未推进、失败命令、旧 candidate SHA 和恢复条件。
92
+ 集成失败时明确父 HEAD 是否推进、失败命令、旧 SHA 和恢复条件。
87
93
 
88
94
  ## 8. 偏差与决策
89
95
 
@@ -5,13 +5,13 @@
5
5
  - [ ] Ticket frontmatter 可解析,`ready: true`,`status: ready`。
6
6
  - [ ] 所有 `blocked_by` Ticket 为 done 且 Evidence 存在。
7
7
  - [ ] Spec、ADR、Ticket 与 Goal Plan 无冲突;旧 Goal Plan schema 必须重跑 P-goal-plan。
8
- - [ ] Goal Plan(若存在)为 `lead-directed`,Lead 可恢复,implementation agent limit 为 `1..3`。
8
+ - [ ] Goal Plan(若存在)为 `lead-directed`,workspace/integration 策略为 `current/direct-parent` 或 `required/candidate-merge`,Lead 可恢复,implementation/integration 上限不超过 config 与平台能力。
9
9
  - [ ] 当前代码入口、接口、路径和父分支仍与 Ticket 假设一致。
10
- - [ ] writable/shared paths 有唯一 owner,当前 Wave 无项目写冲突。
11
- - [ ] implementation commit local candidate integration/父分支更新已授权;push/PR/remote/deploy 等保持独立。
12
- - [ ] dev-worktree 记录 schema v4,`base_sha`、父分支、owners、branch、`workspace_ref`、integration 与 E2E disposition 完整。
13
- - [ ] implementation subagent 若被派遣,Packet 绑定上述 worktree/checkpoint;subagent 不写 SpecDev 状态。
14
- - [ ] 来源检查明确为非 E2E;required E2E 有 parent-candidate 场景与预期。
10
+ - [ ] writable/shared paths 有唯一 owner;current 模式的 Ticket 顺序已固定且没有其他 active implementation writer。
11
+ - [ ] implementation commit 与当前策略对应的 direct-parent 或 local candidate integration/父分支更新已授权;push/PR/remote/deploy 等保持独立。
12
+ - [ ] required 模式的 dev-worktree 记录 schema v6,`base_sha`、父分支、owners、branch、`workspace_ref`、integration 与 E2E disposition 完整;current 模式的 current workspace 记录使用 `workspace_ref: current`、`branch: parent_branch` 和 direct-parent integration。
13
+ - [ ] implementation subagent 若被派遣,Packet 绑定唯一 Ticket workspace 或 current workspace/checkpoint;subagent 不写 SpecDev 状态。
14
+ - [ ] current 模式 source 检查在 current workspace 且不宣称 E2E;required 模式 source 检查明确为非 E2E,required E2E 有 parent-candidate 场景与预期。
15
15
  - [ ] 验证命令/环境可用,关键静默失败风险有受控反向验证。
16
16
  - [ ] Deep Ticket 批准点已满足。
17
17
 
@@ -30,7 +30,9 @@
30
30
  - **local-implementation**:局部实现调整不改变契约;记录后继续。
31
31
  - **ticket-invalid**:范围、接口、依赖、验证或路径合同失效;停止并修 Ticket。
32
32
  - **spec-invalid / adr-conflict**:返回对应上游 owner。
33
- - **checkpoint-drift**:来源/父分支/派单 checkpoint 漂移;由 Lead重建 worktree candidate。
34
- - **workspace-contract-invalid**:缺少父分支、owner、locator、source/candidate/result 字段或授权;停止并修状态/计划。
33
+ - **checkpoint-drift**:current/来源/父分支/派单 checkpoint 漂移;由 Lead 重建执行记录或 required 模式的 worktree/candidate。
34
+ - **workspace-contract-invalid**:缺少父分支、owner、locator、implementation/source/适用 result 字段或授权;停止并修状态/计划。
35
+ - **workspace-strategy-invalid**:Goal Plan 的 workspace/integration 组合非法,或 current 模式出现并发 implementation writer;停止并修状态/计划。
35
36
  - **delivery-unverified**:候选、provider 声明或附件不能独立核对;保持 unverified。
36
- - **e2e-owner-invalid**:E2E 被安排在 source worktree 或非 Lead owner;停止并修 Ticket/Goal Plan。
37
+ - **e2e-owner-invalid**:required 模式 E2E 被安排在 source worktree,或任一模式不是 Lead owner;停止并修 Ticket/Goal Plan。
38
+ - **direct-parent-invalid**:current 模式的 Ticket commit、父 HEAD、验证或 Evidence 不一致;保留最后可信 commit 并阻塞当前 Ticket。
@@ -53,7 +53,7 @@ keywords: [初始化, 配置, status, tracking, 验证命令]
53
53
  仅在上下文未提供时询问:
54
54
 
55
55
  - 交互语言与持久化工件语言;
56
- - implementation subagent 上限(`1..3`,默认 `3`,Lead 不计入);
56
+ - implementation subagent、集成尝试次数和原型变体上限(初始化时写入 config,Lead 不计入);
57
57
  - Deep Ticket 的迁移、发布和不可逆操作是否必须人工批准;
58
58
 
59
59
  不询问可由仓库事实回答的文件位置、脚本名或默认分支。
@@ -82,7 +82,7 @@ keywords: [初始化, 配置, status, tracking, 验证命令]
82
82
  - `<Path>{roots.state}/specdev/research/</Path>`
83
83
  - `<Path>{roots.state}/specdev/archive/</Path>`
84
84
 
85
- 若全局状态或 config 已存在,先检查各自 `schema_version`。版本未知、JSON 不可解析或状态与当前 workflow 契约不一致时,停止当前 Work,并提示用户运行 `speculo init` 建立备份与 pending marker,再运行 `migrate-runtime-state` command 对账修复;不得在 Work 内迁移、兼容或猜测旧状态。只有状态不存在时才从 schema v4 模板创建。
85
+ 若全局状态或 config 已存在,先检查各自 `schema_version`。版本未知、JSON 不可解析或状态与当前 workflow 契约不一致时,停止当前 Work,并提示用户运行 `speculo init` 建立备份与 pending marker,再运行 `migrate-runtime-state` command 对账修复;不得在 Work 内迁移、兼容或猜测旧状态。只有状态不存在时才从当前 schema 模板创建。
86
86
 
87
87
  从模板生成:
88
88
 
@@ -1,5 +1,5 @@
1
1
  {
2
- "schema_version": 5,
2
+ "schema_version": 6,
3
3
  "artifact": "change-status",
4
4
  "change": "<YYYY-MM-DD-topic>",
5
5
  "change_status": "active",
@@ -7,8 +7,8 @@
7
7
  "works_run": [],
8
8
  "claimed_investigations": [],
9
9
  "execution_authorization": {
10
- "implementation_commit": {"status": "not-authorized", "source": null, "granted_at": null, "scope": "Ticket source commits"},
11
- "local_candidate_integration": {"status": "not-authorized", "source": null, "granted_at": null, "scope": "Lead-owned local parent candidate integration and parent update"},
10
+ "implementation_commit": {"status": "not-authorized", "source": null, "granted_at": null, "scope": "Ticket implementation commits"},
11
+ "local_candidate_integration": {"status": "not-authorized", "source": null, "granted_at": null, "scope": "Lead-owned local direct-parent or candidate integration and parent update"},
12
12
  "source_cleanup": {"status": "not-authorized", "source": null, "granted_at": null, "scope": "Source worktree and branch cleanup"}
13
13
  },
14
14
  "leadership": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "schema_version": 4,
2
+ "schema_version": 5,
3
3
  "interaction_language": "zh-CN",
4
4
  "artifact_language": "zh-CN",
5
5
  "git": {
@@ -7,6 +7,7 @@
7
7
  },
8
8
  "execution": {
9
9
  "max_implementation_agents": 3,
10
+ "max_integration_attempts": 3,
10
11
  "deep_ticket_human_approval": true,
11
12
  "shared_path_owner": "explicit"
12
13
  },
@@ -19,6 +20,8 @@
19
20
  "planning": {
20
21
  "default_depth": "standard",
21
22
  "require_ready_gate": true,
22
- "require_evidence": true
23
+ "require_evidence": true,
24
+ "ui_prototype_default_variants": 3,
25
+ "ui_prototype_max_variants": 5
23
26
  }
24
27
  }
@@ -122,8 +122,8 @@ Archive 归档历史并将经验证知识提升为当前长期知识
122
122
  10. **恢复依赖权威工件**:跨 Work 或 Agent 边界时同步 active change 的 `current_work`,成功完成后去重更新 `works_run`,返回下一 Work 和权威工件的完整路径。
123
123
  11. **本地执行权威**:远程 Issue/PR/URL 只作为来源或完成投影;Spec、Ticket、Map、Goal Plan、Evidence 和状态始终以本地工件为准。
124
124
  12. **完成与归档分离**:本地完成按 change completion 合同决定;远程 close 失败不回滚完成,但必须 reconcile 或 waive 后才归档。
125
- 13. **Lead 与隔离正交**:Lead 固定拥有 SpecDev 状态、Evidence 与父分支;是否派遣 subagent 由 Lead 动态决定。每个实现 Ticket 都使用独立 worktree,Agent 身份不决定是否隔离。
126
- 14. **候选先验收**:source worktree 只产生实现 commit 与非 E2E 证据;Lead parent-candidate 状态运行集成检查和适用 E2E,通过后才推进父分支。
125
+ 13. **Lead 与隔离正交**:Lead 固定拥有 SpecDev 状态、Evidence 与父分支;是否派遣 subagent 由 Lead 动态决定。Goal Plan 创建时询问 Ticket 是否开启 worktree,默认不开启;选择只作用于当前 Goal Plan。
126
+ 14. **策略化验收**:current 模式使用当前 workspace 严格串行、direct-parent 验证;required 模式使用 source worktree parent-candidate。只有 required 模式创建独立 Ticket worktree。
127
127
 
128
128
  共享规则:
129
129
 
@@ -151,7 +151,7 @@ Change 从 active/blocked 转为 completed 时加载 `<Path>{roots.workflows}/sp
151
151
 
152
152
  ## 状态字段
153
153
 
154
- `<Path>{roots.state}/specdev/status.json</Path>` 使用全局 schema v4;Spec/Ticket/Tickets Map 继续使用各自 schema v3,configGoal Plan `<Path>{roots.state}/specdev/changes/{change}/.status.json</Path>` 使用 schema v4
154
+ `<Path>{roots.state}/specdev/status.json</Path>` 使用全局 schema v5;Spec/Ticket/Tickets Map 继续使用各自 schema v3,config 使用 schema v5,Goal Plan 使用 schema v6,`<Path>{roots.state}/specdev/changes/{change}/.status.json</Path>` 使用 schema v6
155
155
 
156
156
  - `schema_version`(数字):全局状态 schema 版本,固定为 `4`。
157
157
  - `workflow`(字符串):workflow 标识,固定为 `"specdev"`。
@@ -164,9 +164,9 @@ Change 从 active/blocked 转为 completed 时加载 `<Path>{roots.workflows}/sp
164
164
 
165
165
  `active[].change` 必须唯一,且不得同时出现在 `archived`。开始 Work 时设置 `current_work`;暂停或可恢复阻塞时保留;成功完成时加入 `works_run` 并清空;取消时清空但不加入。逐次时间、结果和审计证据由 change 自有状态、Work 主产物、Evidence 或 LOG 承载,不写入全局索引。
166
166
 
167
- `<Path>{roots.state}/specdev/config.json</Path>` 的 `execution.max_implementation_agents` `1..3`,默认 `3`,仅限制 implementation subagent 且不含 Lead;只读 review/research/test-observation agent 不设 SpecDev 数字上限。
167
+ `<Path>{roots.state}/specdev/config.json</Path>` 的 `execution.max_implementation_agents`、`max_integration_attempts` planning 原型变体字段均为可配置正整数,初始化时写入默认值;仅 implementation subagent 受前者约束且不含 Lead,current workspace 仍保持单 writer 串行安全不变量;只读 review/research/test-observation agent 不设 SpecDev 数字上限。
168
168
 
169
- `<Path>{roots.state}/specdev/changes/{change}/.status.json</Path>` 的 `worktrees` 保存 Ticket 级 `base_sha`、父分支、workspace/implementation/integration owner、portable source workspace、source checkpoint、parent-candidate branch/workspace、candidate/result SHA、验证、E2E disposition 与生命周期状态。每个实现 Ticket 都有一条记录;父分支只有在 candidate passed 后推进。`removed` 是 `integrated` 后来源 branch/worktree 完成清理的终态,必须保留全部集成与 E2E 证据。
169
+ `<Path>{roots.state}/specdev/changes/{change}/.status.json</Path>` 的 `worktrees` 保存 Ticket 级 `base_sha`、父分支、workspace/implementation/integration owner、workspace locatorimplementation/source checkpoint、适用 candidate/result SHA、验证、E2E disposition 与生命周期状态。current 记录使用 `workspace_ref=current` 和 direct-parent;required 记录使用 source/parent-candidate。每个实现 Ticket 都有一条记录;父分支只有在对应策略的验证通过后推进。`removed` 是 required 集成后来源 branch/worktree 完成清理的终态,必须保留全部集成与 E2E 证据。
170
170
 
171
171
  领域状态枚举:
172
172
 
@@ -186,7 +186,7 @@ Change 从 active/blocked 转为 completed 时加载 `<Path>{roots.workflows}/sp
186
186
 
187
187
  ## 副作用边界
188
188
 
189
- 未经用户明确授权不得提交、推送、合并、删除来源 branch/worktree、部署、发布、移动归档、写入/关闭远程 Issue 或执行不可逆迁移。Ready Goal Plan/Ticket 执行必须明确取得 implementation commit local candidate integration/父分支更新授权;该授权包含 transient candidate checkout/branch 生命周期,不扩展到来源 cleanup、远端或生产动作。只读探索、change 工件生成和已授权验证可以进行。远程开发投影仅由 Triage reconcile 执行;Retro command 的 Speculo 反馈 Issue 是独立 command 边界。敏感值不得写入 `<Path>{roots.state}/specdev/</Path>`。
189
+ 未经用户明确授权不得提交、推送、合并、删除来源 branch/worktree、部署、发布、移动归档、写入/关闭远程 Issue 或执行不可逆迁移。Ready Goal Plan/Ticket 执行必须明确取得 implementation commit 与所选 direct-parent/candidate integration/父分支更新授权;required 模式该授权包含 transient candidate checkout/branch 生命周期,不扩展到来源 cleanup、远端或生产动作。只读探索、change 工件生成和已授权验证可以进行。远程开发投影仅由 Triage reconcile 执行;Retro command 的 Speculo 反馈 Issue 是独立 command 边界。敏感值不得写入 `<Path>{roots.state}/specdev/</Path>`。
190
190
 
191
191
  ## 场景路由
192
192