@namewta/speculo 0.7.0 → 0.7.2
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.
- package/README.md +9 -6
- package/dist/src/cli.js +12 -0
- package/dist/src/cli.js.map +1 -1
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.js +56 -58
- package/dist/src/index.js.map +1 -1
- package/dist/src/migrations.d.ts +23 -0
- package/dist/src/migrations.js +470 -0
- package/dist/src/migrations.js.map +1 -0
- package/package.json +2 -2
- package/template/.speculo/README.md +13 -6
- package/template/canonical/canonical-specdev-engineering-cognitive-mentor.md +178 -0
- package/template/canonical/canonical-specdev-goal-plan.md +386 -74
- package/template/canonical/canonical-specdev-grill-with-docs.md +178 -0
- package/template/canonical/canonical-specdev-spec.md +178 -0
- package/template/canonical/canonical-specdev-tickets.md +247 -21
- package/template/canonical/canonical-specdev-wayfinder.md +178 -0
- package/template/commands/migrate-runtime-state.md +43 -0
- package/template/skills/github-npm-ops/references/preflight-checklist.md +1 -1
- package/template/skills/migrate-runtime-state/SKILL.md +93 -0
- package/template/skills/migrate-runtime-state/references/migration-contract.md +58 -0
- package/template/skills/migrate-runtime-state/scripts/migrate-runtime-state.mjs +545 -0
- package/template/skills/optimize-codex-config/SKILL.md +81 -0
- package/template/skills/optimize-codex-config/references/configuration-contract.md +103 -0
- package/template/skills/optimize-codex-config/references/troubleshooting.md +79 -0
- package/template/skills/optimize-codex-config/scripts/audit-codex-config.mjs +747 -0
- package/template/workflows/specdev/I-implement/I-implement.md +11 -10
- package/template/workflows/specdev/I-implement/delegated-evidence-template.md +2 -1
- package/template/workflows/specdev/I-implement/execution-preflight.md +5 -3
- package/template/workflows/specdev/I-implement/merge-conflict-protocol.md +6 -5
- package/template/workflows/specdev/I-init-setup/I-init-setup.md +1 -1
- package/template/workflows/specdev/INDEX.md +13 -9
- package/template/workflows/specdev/P-goal-plan/P-goal-plan.md +27 -18
- package/template/workflows/specdev/P-goal-plan/completion-control.md +3 -3
- package/template/workflows/specdev/P-goal-plan/delegated-execution-template.md +6 -4
- package/template/workflows/specdev/P-goal-plan/delegated-execution.md +13 -7
- package/template/workflows/specdev/P-goal-plan/goal-plan-template.md +11 -2
- package/template/workflows/specdev/P-goal-plan/orchestration-protocol.md +7 -3
- package/template/workflows/specdev/P-goal-plan/planning-modes.md +23 -8
- package/template/workflows/specdev/P-goal-plan/workspace-execution-template.md +24 -0
- package/template/workflows/specdev/common/README.md +2 -2
- package/template/workflows/specdev/common/rules/change-completion.md +3 -2
- package/template/workflows/specdev/common/rules/path-ownership.md +2 -2
- package/template/workflows/specdev/common/schemas/change-status.schema.json +178 -0
- package/template/workflows/specdev/common/schemas/goal-plan.schema.json +10 -0
- package/template/workflows/specdev/common/skills/dev-worktree/SKILL.md +11 -11
- package/template/workflows/specdev/common/skills/dev-worktree/references/create.md +19 -4
- package/template/workflows/specdev/common/skills/dev-worktree/references/finalize.md +12 -5
- package/template/workflows/specdev/common/skills/subagent-delivery/SKILL.md +4 -3
- package/template/workflows/specdev/common/skills/subagent-delivery/references/external-web-subagent.md +1 -1
- package/template/workflows/specdev/common/skills/subagent-delivery/references/native-subagent.md +2 -3
- package/template/workflows/specdev/common/tools/validate-specdev.mjs +218 -5
|
@@ -61,6 +61,21 @@ const VALID_PLAN_MODES = new Set([
|
|
|
61
61
|
"reference-conformance",
|
|
62
62
|
"release-coordination",
|
|
63
63
|
]);
|
|
64
|
+
const VALID_COORDINATION_MODES = new Set(["single-session", "lead-team"]);
|
|
65
|
+
const VALID_WORKSPACE_STRATEGIES = new Set(["current", "worktree", "mixed"]);
|
|
66
|
+
const VALID_WORKTREE_STATUS = new Set([
|
|
67
|
+
"planned",
|
|
68
|
+
"active",
|
|
69
|
+
"review",
|
|
70
|
+
"integrating",
|
|
71
|
+
"integrated",
|
|
72
|
+
"removed",
|
|
73
|
+
"blocked",
|
|
74
|
+
]);
|
|
75
|
+
const VALID_TERMINAL_ACTION = new Set(["integrate", "retain"]);
|
|
76
|
+
const VALID_INTEGRATION_STATUS = new Set(["pending", "running", "passed", "blocked"]);
|
|
77
|
+
const VALID_INTEGRATION_METHOD = new Set([null, "fast-forward", "merge-commit"]);
|
|
78
|
+
const VALID_INTEGRATION_VERIFICATION = new Set(["pending", "passed", "failed"]);
|
|
64
79
|
const VALID_DESIGN_TREE_STATUS = new Set(["active", "consensus", "blocked"]);
|
|
65
80
|
const VALID_DESIGN_NODE_STATUS = new Set(["open", "answered", "deferred", "rejected"]);
|
|
66
81
|
const VALID_WAYFINDER_LABEL = new Set([
|
|
@@ -131,7 +146,7 @@ const DELEGATED_GOAL_PLAN_TRIGGERS = [
|
|
|
131
146
|
"## Delegated Execution Addendum",
|
|
132
147
|
"### Delivery Contract",
|
|
133
148
|
"### Per-Ticket Dispatch Packets",
|
|
134
|
-
"### Candidate Delivery Return and Lead
|
|
149
|
+
"### Candidate Delivery Return and Lead Acceptance",
|
|
135
150
|
"Lead / Provider",
|
|
136
151
|
"Lead:",
|
|
137
152
|
"Lead:",
|
|
@@ -147,11 +162,20 @@ const REQUIRED_DELEGATED_GOAL_PLAN_MARKERS = [
|
|
|
147
162
|
"## Delegated Execution Addendum",
|
|
148
163
|
"### Delivery Contract",
|
|
149
164
|
"### Per-Ticket Dispatch Packets",
|
|
150
|
-
"### Candidate Delivery Return and Lead
|
|
165
|
+
"### Candidate Delivery Return and Lead Acceptance",
|
|
151
166
|
"native-subagent / external-web-subagent",
|
|
152
167
|
"Lead / Provider",
|
|
153
168
|
"#### Dispatch:",
|
|
154
169
|
];
|
|
170
|
+
const REQUIRED_WORKSPACE_GOAL_PLAN_MARKERS = [
|
|
171
|
+
"## Isolated Workspace Addendum",
|
|
172
|
+
"### Workspace Decision",
|
|
173
|
+
"### Per-Ticket Workspace Allocation",
|
|
174
|
+
"### Local Integration Authorization",
|
|
175
|
+
"Integration owner",
|
|
176
|
+
"Parent branch",
|
|
177
|
+
"Terminal action",
|
|
178
|
+
];
|
|
155
179
|
const STATE_ARTIFACT_BASENAMES = new Set([
|
|
156
180
|
"spec.md",
|
|
157
181
|
"tickets-map.md",
|
|
@@ -663,9 +687,10 @@ function capabilityChecks(root) {
|
|
|
663
687
|
"DAG",
|
|
664
688
|
"Gate",
|
|
665
689
|
"Wave",
|
|
666
|
-
"
|
|
667
|
-
"
|
|
668
|
-
"
|
|
690
|
+
"coordination_mode",
|
|
691
|
+
"workspace_strategy",
|
|
692
|
+
"single-session",
|
|
693
|
+
"lead-team",
|
|
669
694
|
"delegated-execution.md",
|
|
670
695
|
"Definition of Done",
|
|
671
696
|
],
|
|
@@ -770,6 +795,13 @@ function capabilityChecks(root) {
|
|
|
770
795
|
const ordinaryGoalPlanTemplate = join(root, "P-goal-plan", "goal-plan-template.md");
|
|
771
796
|
if (isFile(ordinaryGoalPlanTemplate)) {
|
|
772
797
|
const text = readText(ordinaryGoalPlanTemplate);
|
|
798
|
+
for (const required of [
|
|
799
|
+
"coordination_mode: single-session",
|
|
800
|
+
"workspace_strategy: current",
|
|
801
|
+
"### Execution Topology",
|
|
802
|
+
]) {
|
|
803
|
+
if (!text.includes(required)) errors.push(`ordinary Goal Plan template lost marker ${required}`);
|
|
804
|
+
}
|
|
773
805
|
for (const forbidden of [
|
|
774
806
|
"Lead",
|
|
775
807
|
"Subagent",
|
|
@@ -780,6 +812,9 @@ function capabilityChecks(root) {
|
|
|
780
812
|
"Worker",
|
|
781
813
|
"max_correction_rounds",
|
|
782
814
|
"execution_model",
|
|
815
|
+
"worktree",
|
|
816
|
+
"Ticket branch",
|
|
817
|
+
"merge commit",
|
|
783
818
|
]) {
|
|
784
819
|
if (text.includes(forbidden)) {
|
|
785
820
|
errors.push(`ordinary Goal Plan template contains delegated marker ${forbidden}`);
|
|
@@ -787,6 +822,15 @@ function capabilityChecks(root) {
|
|
|
787
822
|
}
|
|
788
823
|
}
|
|
789
824
|
|
|
825
|
+
const workspaceTemplate = join(root, "P-goal-plan", "workspace-execution-template.md");
|
|
826
|
+
if (!isFile(workspaceTemplate)) {
|
|
827
|
+
errors.push("missing isolated workspace Goal Plan template");
|
|
828
|
+
} else {
|
|
829
|
+
const text = readText(workspaceTemplate);
|
|
830
|
+
const missing = REQUIRED_WORKSPACE_GOAL_PLAN_MARKERS.filter((marker) => !text.includes(marker));
|
|
831
|
+
if (missing.length) errors.push(`isolated workspace Goal Plan template lost markers: ${JSON.stringify(missing)}`);
|
|
832
|
+
}
|
|
833
|
+
|
|
790
834
|
const delegatedTemplate = join(root, "P-goal-plan", "delegated-execution-template.md");
|
|
791
835
|
if (!isFile(delegatedTemplate)) {
|
|
792
836
|
errors.push("missing delegated Goal Plan template");
|
|
@@ -1163,6 +1207,15 @@ function validateDelegatedGoalPlan(body, label, errors) {
|
|
|
1163
1207
|
}
|
|
1164
1208
|
}
|
|
1165
1209
|
|
|
1210
|
+
function validateWorkspaceGoalPlan(body, label, errors, required = false) {
|
|
1211
|
+
const hasWorkspaceAddendum = body.includes("## Isolated Workspace Addendum");
|
|
1212
|
+
if (!required && !hasWorkspaceAddendum) return;
|
|
1213
|
+
const missing = REQUIRED_WORKSPACE_GOAL_PLAN_MARKERS.filter((marker) => !body.includes(marker));
|
|
1214
|
+
if (missing.length) {
|
|
1215
|
+
errors.push(`${label}: incomplete isolated workspace addendum; missing ${JSON.stringify(missing)}`);
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
|
|
1166
1219
|
function validateGoalPlan(path, errors) {
|
|
1167
1220
|
if (!isFile(path)) return null;
|
|
1168
1221
|
const { meta, body } = parseFrontmatter(path);
|
|
@@ -1174,7 +1227,34 @@ function validateGoalPlan(path, errors) {
|
|
|
1174
1227
|
if (invalidModes.length) {
|
|
1175
1228
|
errors.push(`${basename(path)}: invalid modes ${JSON.stringify(invalidModes)}`);
|
|
1176
1229
|
}
|
|
1230
|
+
const coordinationMode = meta.coordination_mode;
|
|
1231
|
+
const workspaceStrategy = meta.workspace_strategy;
|
|
1232
|
+
if ((coordinationMode === undefined) !== (workspaceStrategy === undefined)) {
|
|
1233
|
+
errors.push(`${basename(path)}: coordination_mode and workspace_strategy must appear together`);
|
|
1234
|
+
}
|
|
1235
|
+
if (coordinationMode !== undefined && !VALID_COORDINATION_MODES.has(coordinationMode)) {
|
|
1236
|
+
errors.push(`${basename(path)}: invalid coordination_mode ${coordinationMode}`);
|
|
1237
|
+
}
|
|
1238
|
+
if (workspaceStrategy !== undefined && !VALID_WORKSPACE_STRATEGIES.has(workspaceStrategy)) {
|
|
1239
|
+
errors.push(`${basename(path)}: invalid workspace_strategy ${workspaceStrategy}`);
|
|
1240
|
+
}
|
|
1241
|
+
|
|
1242
|
+
const hasDelegatedMarkers = DELEGATED_GOAL_PLAN_TRIGGERS.some((marker) => body.includes(marker));
|
|
1243
|
+
if (coordinationMode === "lead-team" && !hasDelegatedMarkers) {
|
|
1244
|
+
errors.push(`${basename(path)}: lead-team requires a complete delegated execution addendum`);
|
|
1245
|
+
} else if (coordinationMode === "single-session" && hasDelegatedMarkers) {
|
|
1246
|
+
errors.push(`${basename(path)}: single-session cannot contain delegated execution markers`);
|
|
1247
|
+
}
|
|
1177
1248
|
validateDelegatedGoalPlan(body, basename(path), errors);
|
|
1249
|
+
|
|
1250
|
+
const hasWorkspaceAddendum = body.includes("## Isolated Workspace Addendum");
|
|
1251
|
+
if (new Set(["worktree", "mixed"]).has(workspaceStrategy)) {
|
|
1252
|
+
validateWorkspaceGoalPlan(body, basename(path), errors, true);
|
|
1253
|
+
} else if (workspaceStrategy === "current" && hasWorkspaceAddendum) {
|
|
1254
|
+
errors.push(`${basename(path)}: current workspace_strategy cannot contain an isolated workspace addendum`);
|
|
1255
|
+
} else if (workspaceStrategy === undefined) {
|
|
1256
|
+
validateWorkspaceGoalPlan(body, basename(path), errors);
|
|
1257
|
+
}
|
|
1178
1258
|
if (meta.ready_for_execution === true) {
|
|
1179
1259
|
if (!new Set(["ready", "in_progress", "completed"]).has(meta.status)) {
|
|
1180
1260
|
errors.push(`${basename(path)}: ready_for_execution conflicts with status`);
|
|
@@ -1509,12 +1589,145 @@ function validateChangeStatus(path, expectedChange, errors) {
|
|
|
1509
1589
|
errors.push(`${basename(path)}: workspace_ref must be a portable non-absolute locator`);
|
|
1510
1590
|
continue;
|
|
1511
1591
|
}
|
|
1592
|
+
if (!VALID_WORKTREE_STATUS.has(worktree.status)) {
|
|
1593
|
+
errors.push(`${basename(path)}: invalid worktree status ${worktree.status}`);
|
|
1594
|
+
}
|
|
1512
1595
|
if (worktree.provider === "git") {
|
|
1513
1596
|
const expectedRef = `specdev-worktree/${worktree.ticket_id}`;
|
|
1514
1597
|
if (ref !== expectedRef) {
|
|
1515
1598
|
errors.push(`${basename(path)}: git workspace_ref must equal ${expectedRef}`);
|
|
1516
1599
|
}
|
|
1517
1600
|
}
|
|
1601
|
+
|
|
1602
|
+
const hasIntegrationContract = worktree.terminal_action !== undefined;
|
|
1603
|
+
if (!hasIntegrationContract) {
|
|
1604
|
+
if (worktree.status === "integrating") {
|
|
1605
|
+
errors.push(`${basename(path)}: worktree ${worktree.ticket_id} integrating requires the complete integration contract`);
|
|
1606
|
+
}
|
|
1607
|
+
continue;
|
|
1608
|
+
}
|
|
1609
|
+
const requiredIntegrationKeys = [
|
|
1610
|
+
"integration_owner",
|
|
1611
|
+
"parent_branch",
|
|
1612
|
+
"source_checkpoint",
|
|
1613
|
+
"integration",
|
|
1614
|
+
];
|
|
1615
|
+
const missingIntegrationKeys = requiredIntegrationKeys.filter((key) => !(key in worktree));
|
|
1616
|
+
if (missingIntegrationKeys.length) {
|
|
1617
|
+
errors.push(`${basename(path)}: worktree ${worktree.ticket_id} integration contract missing ${JSON.stringify(missingIntegrationKeys)}`);
|
|
1618
|
+
continue;
|
|
1619
|
+
}
|
|
1620
|
+
if (!VALID_TERMINAL_ACTION.has(worktree.terminal_action)) {
|
|
1621
|
+
errors.push(`${basename(path)}: worktree ${worktree.ticket_id} has invalid terminal_action ${worktree.terminal_action}`);
|
|
1622
|
+
}
|
|
1623
|
+
if (typeof worktree.integration_owner !== "string" || !worktree.integration_owner.trim()) {
|
|
1624
|
+
errors.push(`${basename(path)}: worktree ${worktree.ticket_id} integration_owner is required`);
|
|
1625
|
+
}
|
|
1626
|
+
if (typeof worktree.parent_branch !== "string" || !worktree.parent_branch.trim()) {
|
|
1627
|
+
errors.push(`${basename(path)}: worktree ${worktree.ticket_id} parent_branch is required`);
|
|
1628
|
+
} else if (worktree.parent_branch === worktree.branch) {
|
|
1629
|
+
errors.push(`${basename(path)}: worktree ${worktree.ticket_id} parent_branch must differ from branch`);
|
|
1630
|
+
}
|
|
1631
|
+
|
|
1632
|
+
const sourceRequired = new Set(["review", "integrating", "integrated"]).has(worktree.status);
|
|
1633
|
+
if (sourceRequired && (typeof worktree.source_checkpoint !== "string" || !worktree.source_checkpoint.trim())) {
|
|
1634
|
+
errors.push(`${basename(path)}: worktree ${worktree.ticket_id} ${worktree.status} requires source_checkpoint`);
|
|
1635
|
+
} else if (
|
|
1636
|
+
worktree.source_checkpoint !== null &&
|
|
1637
|
+
(typeof worktree.source_checkpoint !== "string" || !worktree.source_checkpoint.trim())
|
|
1638
|
+
) {
|
|
1639
|
+
errors.push(`${basename(path)}: worktree ${worktree.ticket_id} source_checkpoint must be null or non-empty`);
|
|
1640
|
+
}
|
|
1641
|
+
|
|
1642
|
+
const integration = worktree.integration;
|
|
1643
|
+
if (!integration || typeof integration !== "object" || Array.isArray(integration)) {
|
|
1644
|
+
errors.push(`${basename(path)}: worktree ${worktree.ticket_id} integration must be an object`);
|
|
1645
|
+
continue;
|
|
1646
|
+
}
|
|
1647
|
+
const requiredResultKeys = [
|
|
1648
|
+
"status",
|
|
1649
|
+
"parent_before_sha",
|
|
1650
|
+
"source_sha",
|
|
1651
|
+
"result_sha",
|
|
1652
|
+
"method",
|
|
1653
|
+
"conflict_paths",
|
|
1654
|
+
"verification",
|
|
1655
|
+
"evidence",
|
|
1656
|
+
"attempts",
|
|
1657
|
+
];
|
|
1658
|
+
const missingResultKeys = requiredResultKeys.filter((key) => !(key in integration));
|
|
1659
|
+
if (missingResultKeys.length) {
|
|
1660
|
+
errors.push(`${basename(path)}: worktree ${worktree.ticket_id} integration missing ${JSON.stringify(missingResultKeys)}`);
|
|
1661
|
+
}
|
|
1662
|
+
if (!VALID_INTEGRATION_STATUS.has(integration.status)) {
|
|
1663
|
+
errors.push(`${basename(path)}: worktree ${worktree.ticket_id} has invalid integration status ${integration.status}`);
|
|
1664
|
+
}
|
|
1665
|
+
if (!VALID_INTEGRATION_METHOD.has(integration.method)) {
|
|
1666
|
+
errors.push(`${basename(path)}: worktree ${worktree.ticket_id} has invalid integration method ${integration.method}`);
|
|
1667
|
+
}
|
|
1668
|
+
if (!VALID_INTEGRATION_VERIFICATION.has(integration.verification)) {
|
|
1669
|
+
errors.push(`${basename(path)}: worktree ${worktree.ticket_id} has invalid integration verification ${integration.verification}`);
|
|
1670
|
+
}
|
|
1671
|
+
if (!Array.isArray(integration.conflict_paths)) {
|
|
1672
|
+
errors.push(`${basename(path)}: worktree ${worktree.ticket_id} conflict_paths must be an array`);
|
|
1673
|
+
}
|
|
1674
|
+
if (!Number.isInteger(integration.attempts) || integration.attempts < 0) {
|
|
1675
|
+
errors.push(`${basename(path)}: worktree ${worktree.ticket_id} attempts must be a non-negative integer`);
|
|
1676
|
+
}
|
|
1677
|
+
if (
|
|
1678
|
+
typeof integration.evidence !== "string" ||
|
|
1679
|
+
!/^<Path>\{roots\.state\}\/specdev\/changes\/[^<]+\/evidence\/T-[0-9]{2,}\.md<\/Path>$/.test(integration.evidence)
|
|
1680
|
+
) {
|
|
1681
|
+
errors.push(`${basename(path)}: worktree ${worktree.ticket_id} integration evidence must be a rooted Ticket Evidence path`);
|
|
1682
|
+
}
|
|
1683
|
+
if (worktree.terminal_action === "retain" && new Set(["integrating", "integrated"]).has(worktree.status)) {
|
|
1684
|
+
errors.push(`${basename(path)}: retain worktree ${worktree.ticket_id} cannot be ${worktree.status}`);
|
|
1685
|
+
}
|
|
1686
|
+
const integrationLifecycleActive = new Set(["integrating", "integrated"]).has(worktree.status);
|
|
1687
|
+
if (integrationLifecycleActive) {
|
|
1688
|
+
if (worktree.terminal_action !== "integrate") {
|
|
1689
|
+
errors.push(`${basename(path)}: worktree ${worktree.ticket_id} ${worktree.status} requires terminal_action=integrate`);
|
|
1690
|
+
}
|
|
1691
|
+
if (typeof integration.parent_before_sha !== "string" || !integration.parent_before_sha.trim()) {
|
|
1692
|
+
errors.push(`${basename(path)}: worktree ${worktree.ticket_id} ${worktree.status} requires parent_before_sha`);
|
|
1693
|
+
}
|
|
1694
|
+
if (typeof integration.source_sha !== "string" || !integration.source_sha.trim()) {
|
|
1695
|
+
errors.push(`${basename(path)}: worktree ${worktree.ticket_id} ${worktree.status} requires source_sha`);
|
|
1696
|
+
} else if (integration.source_sha !== worktree.source_checkpoint) {
|
|
1697
|
+
errors.push(`${basename(path)}: worktree ${worktree.ticket_id} source_sha must equal source_checkpoint`);
|
|
1698
|
+
}
|
|
1699
|
+
if (!Number.isInteger(integration.attempts) || integration.attempts < 1) {
|
|
1700
|
+
errors.push(`${basename(path)}: worktree ${worktree.ticket_id} ${worktree.status} requires attempts >= 1`);
|
|
1701
|
+
}
|
|
1702
|
+
}
|
|
1703
|
+
if (worktree.status === "integrating" && integration.status !== "running") {
|
|
1704
|
+
errors.push(`${basename(path)}: integrating worktree ${worktree.ticket_id} requires integration.status=running`);
|
|
1705
|
+
}
|
|
1706
|
+
if (worktree.status === "integrated") {
|
|
1707
|
+
if (
|
|
1708
|
+
integration.status !== "passed" ||
|
|
1709
|
+
integration.verification !== "passed" ||
|
|
1710
|
+
!new Set(["fast-forward", "merge-commit"]).has(integration.method) ||
|
|
1711
|
+
typeof integration.result_sha !== "string" ||
|
|
1712
|
+
!integration.result_sha.trim()
|
|
1713
|
+
) {
|
|
1714
|
+
errors.push(`${basename(path)}: integrated worktree ${worktree.ticket_id} requires a passed result checkpoint`);
|
|
1715
|
+
}
|
|
1716
|
+
if (integration.method === "fast-forward") {
|
|
1717
|
+
if (integration.result_sha !== worktree.source_checkpoint) {
|
|
1718
|
+
errors.push(`${basename(path)}: integrated worktree ${worktree.ticket_id} fast-forward result_sha must equal source_checkpoint`);
|
|
1719
|
+
}
|
|
1720
|
+
if (Array.isArray(integration.conflict_paths) && integration.conflict_paths.length > 0) {
|
|
1721
|
+
errors.push(`${basename(path)}: integrated worktree ${worktree.ticket_id} fast-forward cannot record conflict_paths`);
|
|
1722
|
+
}
|
|
1723
|
+
} else if (
|
|
1724
|
+
integration.method === "merge-commit" &&
|
|
1725
|
+
typeof integration.result_sha === "string" &&
|
|
1726
|
+
(integration.result_sha === worktree.source_checkpoint || integration.result_sha === integration.parent_before_sha)
|
|
1727
|
+
) {
|
|
1728
|
+
errors.push(`${basename(path)}: integrated worktree ${worktree.ticket_id} merge-commit result_sha must be a distinct checkpoint`);
|
|
1729
|
+
}
|
|
1730
|
+
}
|
|
1518
1731
|
}
|
|
1519
1732
|
if (data.change_status === "archived") {
|
|
1520
1733
|
if (data.archived !== true) errors.push(`${basename(path)}: archived status requires archived=true`);
|