cc-codeconductor 1.4.0 → 1.4.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.
Files changed (41) hide show
  1. package/README.md +24 -1
  2. package/dist/core/verification/rdd-receipt.d.ts +39 -0
  3. package/dist/core/verification/verification-runner.d.ts +8 -2
  4. package/dist/index.d.ts +2 -0
  5. package/dist/index.js +1108 -319
  6. package/dist/library.js +296 -27
  7. package/dist/utils/cli-bin.d.ts +16 -0
  8. package/dist/validation/schemas.d.ts +521 -26
  9. package/docs/generated/cli.md +37 -25
  10. package/package.json +1 -1
  11. package/presets/agy/AGENTS.md +6 -0
  12. package/presets/agy/workflows/cc-handoff.md +2 -1
  13. package/presets/agy/workflows/cc-odd.md +15 -0
  14. package/presets/claude/CLAUDE.md +6 -0
  15. package/presets/claude/commands/cc/handoff.md +2 -1
  16. package/presets/claude/commands/cc/odd.md +15 -0
  17. package/presets/codex/AGENTS.md +6 -0
  18. package/presets/codex/skills/cc-handoff/SKILL.md +3 -1
  19. package/presets/codex/skills/cc-odd/SKILL.md +25 -0
  20. package/presets/codex/skills/cc-openspec/SKILL.md +4 -0
  21. package/presets/codex/skills/cc-spec-mutation/SKILL.md +5 -0
  22. package/presets/codex/skills/cc-tdd-cycle/SKILL.md +8 -0
  23. package/presets/cursor/AGENTS.md +6 -0
  24. package/presets/cursor/commands/cc/handoff.md +3 -1
  25. package/presets/cursor/commands/cc/odd.md +20 -0
  26. package/presets/cursor/commands/cc/openspec.md +4 -0
  27. package/presets/cursor/commands/cc/spec-mutation.md +5 -0
  28. package/presets/cursor/commands/cc/tdd-cycle.md +8 -0
  29. package/presets/gemini/GEMINI.md +6 -0
  30. package/presets/gemini/commands/cc/handoff.toml +3 -1
  31. package/presets/gemini/commands/cc/odd.toml +20 -0
  32. package/presets/gemini/commands/cc/openspec.toml +4 -0
  33. package/presets/gemini/commands/cc/spec-mutation.toml +5 -0
  34. package/presets/gemini/commands/cc/tdd-cycle.toml +8 -0
  35. package/presets/opencode/agents/implementer.md +2 -0
  36. package/presets/opencode/agents/reviewer.md +2 -0
  37. package/presets/opencode/agents/tester.md +2 -0
  38. package/presets/opencode/commands/cc-handoff.md +2 -1
  39. package/presets/opencode/commands/cc-odd.md +15 -0
  40. package/presets/pi/AGENTS.md +6 -0
  41. package/src/presets/targets/pi.yml +1 -0
package/dist/library.js CHANGED
@@ -149,7 +149,7 @@ function validateProductEvent(data) {
149
149
  function validateSkillsRegistry(data) {
150
150
  return SkillsRegistrySchema.parse(data);
151
151
  }
152
- var CouncilAgentSpecSchema, CouncilSpecSchema, ProjectProfileSchema, CompileCheckConfigSchema, LoopConfigSchema, CodeConductorConfigSchema, RunnerTargetSchema, InstallStrategySchema, ManifestEntrySchema, InstallManifestSchema, ToolProviderNamesSchema, PermissionProviderNamesSchema, ModelConfigSchema, SkillFrontmatterSchema, CommandFrontmatterSchema, TargetCapabilitiesSchema, ContractTargetSchema, ContractFormatSchema, AgentContractSchema, CouncilFindingSchema, CouncilVerdictInputSchema, ConsensusConfigSchema, CouncilVerdictSchema, ClaudeAgentFileSchema, OpenCodeAgentFileSchema, SentryStackFrameSchema, SentryWebhookSchema, MemoryPointerSchema, MemoryIndexSchema, GoalTaskSchema, GoalGraphSchema, ConfidenceLevelSchema, ProductNodeTypeSchema, GraphRelationSchema, KnowledgeEntitySchema, DecisionSchema, EvidenceSchema, CanonicalTaskCardStatusSchema, CanonicalTaskCardSchema, ProductGraphNodeSchema, ProductGraphEdgeSchema, ProductGraphSchema, ProductMetaSchema, ProductEventTypeSchema, ProductEventSchema, OperationalStateSchema, StrategicMemorySchema, ImpactReportSchema, BusinessReviewOutputSchema, VerificationReportSchema, BacklogStatusSchema, BacklogTypeSchema, BacklogPrioritySchema, BacklogGlobalSchema, BacklogItemSchema, BacklogDocumentSchema, OpenspecTaskCardPhaseSchema, OpenspecTaskCardStatusSchema, OpenspecTaskCardSchema, OpenspecStateSchema, SpecAnalyzeFindingSchema, SpecAnalyzeReportSchema, WorkflowCommandSchema, CcepOutputFormatSchema, CommandEnvelopeSchema, WorkflowPhaseSchema, WorkflowRiskRuleSchema, WorkflowProfileSchema, ExecutionContextSchema, PlannerOutputSchema, AgentArtifactSchema, AgentOutputSchema, ImplementerTestsSchema, ImplementerOutputSchema, ReviewAxisSchema, ReviewFindingSchema, ReviewerOutputSchema, TechnicalPlanOutputSchema, ScorecardVerdictSchema, ScorecardCriterionIdSchema, ScorecardCriterionSchema, ScorecardRecordSchema, TaskOutcomeSourceSchema, TaskOutcomeStatusSchema, TaskOutcomeSchema, HarnessComponentIdSchema, HarnessComponentLayerSchema, HarnessToggleKindSchema, HarnessCatalogEntrySchema, HarnessCatalogSchema, HarnessOverlaySchema, HarnessExperimentSchema, HarnessSuiteTaskSchema, HarnessSuiteSchema, EvaluationIndexSchema, ExecutionProfileNameSchema, ExecutionProfileSchema, SkillsRegistrySchema;
152
+ var CouncilAgentSpecSchema, CouncilSpecSchema, ProjectProfileSchema, CompileCheckConfigSchema, LoopConfigSchema, CodeConductorConfigSchema, RunnerTargetSchema, InstallStrategySchema, ManifestEntrySchema, InstallManifestSchema, ToolProviderNamesSchema, PermissionProviderNamesSchema, ModelConfigSchema, SkillFrontmatterSchema, CommandFrontmatterSchema, TargetCapabilitiesSchema, ContractTargetSchema, ContractFormatSchema, AgentContractSchema, CouncilFindingSchema, CouncilVerdictInputSchema, ConsensusConfigSchema, CouncilVerdictSchema, ClaudeAgentFileSchema, OpenCodeAgentFileSchema, SentryStackFrameSchema, SentryWebhookSchema, MemoryPointerSchema, MemoryIndexSchema, GoalTaskSchema, GoalGraphSchema, ConfidenceLevelSchema, ProductNodeTypeSchema, GraphRelationSchema, KnowledgeEntitySchema, DecisionSchema, EvidenceSchema, CanonicalTaskCardStatusSchema, CanonicalTaskCardSchema, ProductGraphNodeSchema, ProductGraphEdgeSchema, ProductGraphSchema, ProductMetaSchema, ProductEventTypeSchema, ProductEventSchema, OperationalStateSchema, StrategicMemorySchema, ImpactReportSchema, BusinessReviewOutputSchema, VerificationReportSchema, BacklogStatusSchema, BacklogTypeSchema, BacklogPrioritySchema, BacklogGlobalSchema, BacklogItemSchema, BacklogDocumentSchema, OpenspecTaskCardPhaseSchema, OpenspecTaskCardStatusSchema, OpenspecTaskCardSchema, OpenspecStateSchema, SpecAnalyzeFindingSchema, SpecAnalyzeReportSchema, WorkflowCommandSchema, CcepOutputFormatSchema, CommandEnvelopeSchema, WorkflowPhaseSchema, WorkflowRiskRuleSchema, WorkflowProfileSchema, ExecutionContextSchema, PlannerOutputSchema, AgentArtifactSchema, AgentOutputSchema, ImplementerTestsSchema, ImplementerOutputSchema, ReviewAxisSchema, ReviewFindingSchema, ReviewerOutputSchema, TechnicalPlanOutputSchema, ScorecardVerdictSchema, ScorecardCriterionIdSchema, ScorecardCriterionSchema, ScorecardRecordSchema, TaskOutcomeSourceSchema, TaskOutcomeStatusSchema, DeliveryRouteSchema, TokenUsageSchema, DeliveryTelemetrySchema, DeliveryLedgerTaskSchema, DeliveryLedgerSchema, DeliveryLedgerRequestSchema, TaskOutcomeSchema, HarnessComponentIdSchema, HarnessComponentLayerSchema, HarnessToggleKindSchema, HarnessCatalogEntrySchema, HarnessCatalogSchema, HarnessOverlaySchema, HarnessExperimentSchema, HarnessSuiteTaskSchema, HarnessSuiteSchema, EvaluationIndexSchema, ExecutionProfileNameSchema, ExecutionProfileSchema, SkillsRegistrySchema;
153
153
  var init_schemas = __esm(() => {
154
154
  init_runner_target();
155
155
  CouncilAgentSpecSchema = z.object({
@@ -313,7 +313,8 @@ var init_schemas = __esm(() => {
313
313
  complianceVeto: z.boolean().optional(),
314
314
  confidence: z.number().min(0).max(1),
315
315
  findings: z.array(CouncilFindingSchema),
316
- summary: z.string()
316
+ summary: z.string(),
317
+ candidateHash: z.string().min(1).optional()
317
318
  });
318
319
  ConsensusConfigSchema = z.object({
319
320
  algorithm: z.enum(["majority", "unanimous"]),
@@ -321,7 +322,8 @@ var init_schemas = __esm(() => {
321
322
  allowComplianceVeto: z.boolean().optional(),
322
323
  expectedAgentIds: z.array(z.string().min(1).refine((id) => id.trim().length > 0)).min(1).refine((ids) => new Set(ids.map((id) => id.trim().toLowerCase())).size === ids.length).optional(),
323
324
  quorum: z.number().int().positive().optional(),
324
- criticalFindingsPolicy: z.enum(["escalate", "reject", "ignore"]).optional()
325
+ criticalFindingsPolicy: z.enum(["escalate", "reject", "ignore"]).optional(),
326
+ candidateHash: z.string().min(1).optional()
325
327
  }).refine((config) => config.algorithm !== "unanimous" || config.expectedAgentIds !== undefined, {
326
328
  message: "unanimous consensus requires a non-empty expectedAgentIds roster",
327
329
  path: ["expectedAgentIds"]
@@ -698,7 +700,8 @@ var init_schemas = __esm(() => {
698
700
  "prototype",
699
701
  "handoff",
700
702
  "clarify",
701
- "security"
703
+ "security",
704
+ "odd"
702
705
  ]);
703
706
  CcepOutputFormatSchema = z.enum(["taskcard", "plan", "verdict"]);
704
707
  CommandEnvelopeSchema = z.object({
@@ -914,6 +917,46 @@ var init_schemas = __esm(() => {
914
917
  "revise",
915
918
  "reject"
916
919
  ]);
920
+ DeliveryRouteSchema = z.enum(["read-only", "small", "tracked", "openspec"]);
921
+ TokenUsageSchema = z.union([
922
+ z.object({
923
+ status: z.literal("known"),
924
+ total: z.number().nonnegative()
925
+ }),
926
+ z.object({ status: z.literal("unknown") })
927
+ ]);
928
+ DeliveryTelemetrySchema = z.object({
929
+ route: DeliveryRouteSchema,
930
+ contextBytes: z.number().int().nonnegative().optional(),
931
+ handoffs: z.number().int().nonnegative().optional(),
932
+ checks: z.array(z.string().min(1)).optional(),
933
+ tokenUsage: TokenUsageSchema
934
+ });
935
+ DeliveryLedgerTaskSchema = z.object({
936
+ id: z.string().min(1),
937
+ title: z.string().min(1),
938
+ status: z.enum(["pending", "done", "blocked"])
939
+ });
940
+ DeliveryLedgerSchema = z.object({
941
+ version: z.literal(1),
942
+ id: z.string().regex(/^[a-z0-9][a-z0-9-]{0,63}$/),
943
+ taskCard: CanonicalTaskCardSchema,
944
+ tasks: z.array(DeliveryLedgerTaskSchema).min(1),
945
+ evidence: z.array(z.string().min(1)),
946
+ nextStep: z.string().min(1),
947
+ memoryTopicKey: z.string().min(1),
948
+ workspace: z.record(z.string(), z.string()),
949
+ createdAt: z.string().datetime(),
950
+ updatedAt: z.string().datetime()
951
+ });
952
+ DeliveryLedgerRequestSchema = z.object({
953
+ id: z.string().regex(/^[a-z0-9][a-z0-9-]{0,63}$/),
954
+ authorized: z.boolean(),
955
+ route: DeliveryRouteSchema,
956
+ taskCard: CanonicalTaskCardSchema,
957
+ tasks: z.array(DeliveryLedgerTaskSchema).min(1),
958
+ nextStep: z.string().min(1)
959
+ });
917
960
  TaskOutcomeSchema = z.object({
918
961
  id: z.string(),
919
962
  taskId: z.string(),
@@ -937,7 +980,8 @@ var init_schemas = __esm(() => {
937
980
  variantId: z.string().optional(),
938
981
  suiteTaskId: z.string().optional(),
939
982
  harnessFingerprint: z.string().optional(),
940
- disabledComponents: z.array(z.string()).optional()
983
+ disabledComponents: z.array(z.string()).optional(),
984
+ delivery: DeliveryTelemetrySchema.optional()
941
985
  });
942
986
  HarnessComponentIdSchema = z.enum([
943
987
  "wayfinding",
@@ -1134,6 +1178,34 @@ var init_goal_state = __esm(() => {
1134
1178
  import { mkdir, readFile, writeFile } from "node:fs/promises";
1135
1179
  init_schemas();
1136
1180
 
1181
+ // src/utils/cli-bin.ts
1182
+ import { basename } from "node:path";
1183
+ function resolveCliBin(env = process.env, argv = process.argv) {
1184
+ if (env.CC_CLI_BIN) {
1185
+ return env.CC_CLI_BIN;
1186
+ }
1187
+ if (env.npm_lifecycle_event === "npx" || env.npm_command === "exec" || env._?.endsWith("/npx") || env._ === "npx") {
1188
+ return "npx cc-codeconductor";
1189
+ }
1190
+ if (env._?.endsWith("/bunx") || env._ === "bunx") {
1191
+ return "bunx cc-codeconductor";
1192
+ }
1193
+ if (env.npm_lifecycle_event === "dev") {
1194
+ return env.npm_lifecycle_script?.startsWith("bun") ? "bun run dev" : "npm run dev";
1195
+ }
1196
+ if (argv && argv.length > 1 && argv[1]) {
1197
+ const script = argv[1];
1198
+ const binName = basename(script);
1199
+ if (binName === "main.ts") {
1200
+ return "bun run dev";
1201
+ }
1202
+ if (binName === "cc-codeconductor" || binName === "codeconductor") {
1203
+ return binName;
1204
+ }
1205
+ }
1206
+ return "cc-codeconductor";
1207
+ }
1208
+
1137
1209
  // src/core/product-graph/paths.ts
1138
1210
  import { join } from "node:path";
1139
1211
  var PRODUCT_DIR = ".codeconductor";
@@ -1161,7 +1233,7 @@ async function loadGraph(projectRoot) {
1161
1233
  return ok(ProductGraphSchema.parse(JSON.parse(raw)));
1162
1234
  } catch (e) {
1163
1235
  if (e.code === "ENOENT") {
1164
- return err(new Error("Product graph not found. Run `cc ingest` first."));
1236
+ return err(new Error(`Product graph not found. Run \`${resolveCliBin()} ingest\` first.`));
1165
1237
  }
1166
1238
  return err(e instanceof Error ? e : new Error(String(e)));
1167
1239
  }
@@ -1314,8 +1386,8 @@ async function clearActiveTask(projectRoot, taskId) {
1314
1386
  // src/core/verification/verification-runner.ts
1315
1387
  init_schemas();
1316
1388
  import { existsSync } from "node:fs";
1317
- import { readFile as readFile6 } from "node:fs/promises";
1318
- import { dirname, join as join2, resolve as resolve5 } from "node:path";
1389
+ import { readFile as readFile7 } from "node:fs/promises";
1390
+ import { dirname, join as join3, resolve as resolve6 } from "node:path";
1319
1391
 
1320
1392
  // src/core/config/config-loader.ts
1321
1393
  import { readFile as readFile5 } from "node:fs/promises";
@@ -1631,7 +1703,128 @@ async function runCompileCheck(options) {
1631
1703
  }
1632
1704
  }
1633
1705
  // src/core/verification/verification-runner.ts
1634
- import { mkdir as mkdir5, readdir, writeFile as writeFile4 } from "node:fs/promises";
1706
+ import { mkdir as mkdir5, readdir as readdir2, writeFile as writeFile4 } from "node:fs/promises";
1707
+
1708
+ // src/core/verification/rdd-receipt.ts
1709
+ import { createHash } from "node:crypto";
1710
+ import { readdir, readFile as readFile6 } from "node:fs/promises";
1711
+ import { join as join2, relative, resolve as resolve5, sep } from "node:path";
1712
+ var EXCLUDED_DIRECTORIES = new Set([
1713
+ ".git",
1714
+ ".codeconductor",
1715
+ "node_modules",
1716
+ "dist",
1717
+ "coverage",
1718
+ "graphify-out"
1719
+ ]);
1720
+ function sha256(content) {
1721
+ return createHash("sha256").update(content).digest("hex");
1722
+ }
1723
+ function canonicalPath(projectRoot, input) {
1724
+ const root = resolve5(projectRoot);
1725
+ const absolute = resolve5(root, input);
1726
+ if (absolute !== root && !absolute.startsWith(`${root}${sep}`)) {
1727
+ throw new Error(`RDD receipt path "${input}" is outside the project root`);
1728
+ }
1729
+ const normalized = relative(root, absolute);
1730
+ if (!normalized || normalized === ".") {
1731
+ throw new Error("RDD receipts require file paths, not the project root");
1732
+ }
1733
+ return { absolute, relative: normalized.split(sep).join("/") };
1734
+ }
1735
+ async function fingerprint(projectRoot, paths) {
1736
+ const deduplicated = new Map;
1737
+ for (const path of paths) {
1738
+ const canonical = canonicalPath(projectRoot, path);
1739
+ deduplicated.set(canonical.relative, canonical.absolute);
1740
+ }
1741
+ const result = [];
1742
+ for (const [path, absolute] of [...deduplicated.entries()].sort(([left], [right]) => left.localeCompare(right))) {
1743
+ result.push({ path, hash: sha256(await readFile6(absolute)) });
1744
+ }
1745
+ return result;
1746
+ }
1747
+ function manifestHash(paths) {
1748
+ return sha256(paths.map((entry) => `${entry.path}\x00${entry.hash}`).join(`
1749
+ `));
1750
+ }
1751
+ function isRddReceipt(value) {
1752
+ if (!value || typeof value !== "object")
1753
+ return false;
1754
+ const receipt = value;
1755
+ return receipt.version === 1 && typeof receipt.taskId === "string" && typeof receipt.phase === "string" && Array.isArray(receipt.paths) && receipt.paths.every((entry) => Boolean(entry) && typeof entry.path === "string" && typeof entry.hash === "string") && (receipt.coverage === "paths" || receipt.coverage === "project") && typeof receipt.manifestHash === "string" && (receipt.outcome === "passed" || receipt.outcome === "failed") && typeof receipt.capturedAt === "string";
1756
+ }
1757
+ async function captureReceipt(projectRoot, input) {
1758
+ if (!input.taskId.trim())
1759
+ throw new Error("RDD receipts require a task id");
1760
+ if (input.paths.length === 0 && input.coverage !== "project") {
1761
+ throw new Error("RDD receipts require at least one protected path");
1762
+ }
1763
+ const paths = await fingerprint(projectRoot, input.paths);
1764
+ return {
1765
+ version: 1,
1766
+ taskId: input.taskId,
1767
+ phase: input.phase,
1768
+ paths,
1769
+ coverage: input.coverage ?? "paths",
1770
+ manifestHash: manifestHash(paths),
1771
+ command: input.command,
1772
+ outcome: input.outcome,
1773
+ capturedAt: new Date().toISOString()
1774
+ };
1775
+ }
1776
+ async function collectReceiptPaths(projectRoot) {
1777
+ const root = resolve5(projectRoot);
1778
+ const paths = [];
1779
+ async function visit(current) {
1780
+ const entries = await readdir(current, { withFileTypes: true });
1781
+ for (const entry of entries) {
1782
+ if (entry.isDirectory()) {
1783
+ if (!EXCLUDED_DIRECTORIES.has(entry.name))
1784
+ await visit(join2(current, entry.name));
1785
+ continue;
1786
+ }
1787
+ if (entry.isFile())
1788
+ paths.push(relative(root, join2(current, entry.name)).split(sep).join("/"));
1789
+ }
1790
+ }
1791
+ await visit(root);
1792
+ return paths.sort();
1793
+ }
1794
+ async function verifyReceipt(projectRoot, receipt) {
1795
+ const expected = new Map(receipt.paths.map((entry) => [entry.path, entry.hash]));
1796
+ const changedPaths = [];
1797
+ const current = [];
1798
+ const pathsToCheck = receipt.coverage === "project" ? await collectReceiptPaths(projectRoot) : receipt.paths.map((entry) => entry.path);
1799
+ const currentByPath = new Map;
1800
+ for (const path of pathsToCheck) {
1801
+ try {
1802
+ const canonical = canonicalPath(projectRoot, path);
1803
+ const hash = sha256(await readFile6(canonical.absolute));
1804
+ const currentEntry = { path: canonical.relative, hash };
1805
+ current.push(currentEntry);
1806
+ currentByPath.set(currentEntry.path, currentEntry);
1807
+ if (hash !== expected.get(currentEntry.path))
1808
+ changedPaths.push(currentEntry.path);
1809
+ } catch {
1810
+ changedPaths.push(path);
1811
+ }
1812
+ }
1813
+ for (const path of expected.keys()) {
1814
+ if (!currentByPath.has(path) && !changedPaths.includes(path))
1815
+ changedPaths.push(path);
1816
+ }
1817
+ changedPaths.sort();
1818
+ const actualHash = manifestHash(current.sort((left, right) => left.path.localeCompare(right.path)));
1819
+ return {
1820
+ valid: changedPaths.length === 0 && actualHash === receipt.manifestHash,
1821
+ expectedHash: receipt.manifestHash,
1822
+ actualHash,
1823
+ changedPaths
1824
+ };
1825
+ }
1826
+
1827
+ // src/core/verification/verification-runner.ts
1635
1828
  function isPassingEvidence(ev) {
1636
1829
  switch (ev.type) {
1637
1830
  case "verification":
@@ -1648,9 +1841,17 @@ function isPassingEvidence(ev) {
1648
1841
  return false;
1649
1842
  }
1650
1843
  }
1844
+ async function isCurrentPassingEvidence(projectRoot, ev) {
1845
+ if (!isPassingEvidence(ev))
1846
+ return false;
1847
+ const receipt = ev.data?.rddReceipt;
1848
+ if (!isRddReceipt(receipt))
1849
+ return false;
1850
+ return (await verifyReceipt(projectRoot, receipt)).valid;
1851
+ }
1651
1852
  function evidenceFilePath(evDir, id) {
1652
- const path = resolve5(evDir, `${id.replace(/[^A-Za-z0-9_-]/g, "_")}.json`);
1653
- if (dirname(path) !== resolve5(evDir)) {
1853
+ const path = resolve6(evDir, `${id.replace(/[^A-Za-z0-9_-]/g, "_")}.json`);
1854
+ if (dirname(path) !== resolve6(evDir)) {
1654
1855
  return err(new Error(`Refusing to write evidence for "${id}" outside ${evDir}`));
1655
1856
  }
1656
1857
  return ok(path);
@@ -1676,7 +1877,7 @@ async function collectTaskEvidence(projectRoot, taskId) {
1676
1877
  return ok({ records, invalid });
1677
1878
  let files;
1678
1879
  try {
1679
- files = await readdir(evDir);
1880
+ files = await readdir2(evDir);
1680
1881
  } catch (e) {
1681
1882
  return err(e instanceof Error ? e : new Error(String(e)));
1682
1883
  }
@@ -1684,7 +1885,7 @@ async function collectTaskEvidence(projectRoot, taskId) {
1684
1885
  if (!file.endsWith(".json"))
1685
1886
  continue;
1686
1887
  try {
1687
- const raw = await readFile6(join2(evDir, file), "utf-8");
1888
+ const raw = await readFile7(join3(evDir, file), "utf-8");
1688
1889
  const ev = EvidenceSchema.parse(JSON.parse(raw));
1689
1890
  if (ev.relatedTask === taskId)
1690
1891
  records.push(ev);
@@ -1705,7 +1906,7 @@ async function validateEvidenceIds(projectRoot, taskId, evidenceIds) {
1705
1906
  if (!record) {
1706
1907
  return err(new Error(`Evidence "${id}" is not a record of task ${taskId}`));
1707
1908
  }
1708
- if (!isPassingEvidence(record)) {
1909
+ if (!await isCurrentPassingEvidence(projectRoot, record)) {
1709
1910
  return err(new Error(`Evidence "${id}" does not record a passing result`));
1710
1911
  }
1711
1912
  if (record.type === "verification")
@@ -1786,7 +1987,12 @@ async function runVerification(projectRoot, taskId, goal, options) {
1786
1987
  passed: collected.data.invalid === 0,
1787
1988
  message: collected.data.invalid === 0 ? "All evidence records are readable" : `${collected.data.invalid} unreadable evidence record(s)`
1788
1989
  });
1789
- const supporting = collected.data.records.filter((ev) => ev.type !== "verification" && isPassingEvidence(ev));
1990
+ const supporting = [];
1991
+ for (const candidate of collected.data.records) {
1992
+ if (candidate.type !== "verification" && await isCurrentPassingEvidence(projectRoot, candidate)) {
1993
+ supporting.push(candidate);
1994
+ }
1995
+ }
1790
1996
  evidenceIds.push(...supporting.map((ev) => ev.id));
1791
1997
  checks.push({
1792
1998
  name: "evidence_present",
@@ -1794,6 +2000,13 @@ async function runVerification(projectRoot, taskId, goal, options) {
1794
2000
  message: supporting.length > 0 ? `${supporting.length} passing evidence record(s) for task` : task.risk === "low" ? "Low risk task — evidence optional" : "No passing evidence records found for task"
1795
2001
  });
1796
2002
  const passed = checks.every((c) => c.passed);
2003
+ const receipt = await captureReceipt(projectRoot, {
2004
+ taskId,
2005
+ phase: "verification",
2006
+ paths: await collectReceiptPaths(projectRoot),
2007
+ outcome: passed ? "passed" : "failed",
2008
+ coverage: "project"
2009
+ });
1797
2010
  const evidence = {
1798
2011
  id: `ev-verify-${taskId}-${Date.now()}`,
1799
2012
  source: "cc verify",
@@ -1802,7 +2015,7 @@ async function runVerification(projectRoot, taskId, goal, options) {
1802
2015
  relatedTask: taskId,
1803
2016
  confidence: passed ? 0.9 : 0.3,
1804
2017
  summary: passed ? "Verification passed" : "Verification failed",
1805
- data: { passed, checks }
2018
+ data: { passed, checks, rddReceipt: receipt }
1806
2019
  };
1807
2020
  const persisted = await persistEvidence(projectRoot, evidence);
1808
2021
  if (!persisted.success)
@@ -1825,19 +2038,25 @@ async function gateTaskCompletion(projectRoot, taskId, evidenceRequired, evidenc
1825
2038
  if (collected.data.invalid > 0)
1826
2039
  return ok(false);
1827
2040
  const cited = evidenceIds ? new Set(evidenceIds) : undefined;
1828
- const hasPassing = (type) => collected.data.records.some((ev) => (!cited || cited.has(ev.id)) && ev.type === type && isPassingEvidence(ev));
2041
+ const hasPassing = async (type) => {
2042
+ for (const evidence of collected.data.records) {
2043
+ if ((!cited || cited.has(evidence.id)) && evidence.type === type && await isCurrentPassingEvidence(projectRoot, evidence))
2044
+ return true;
2045
+ }
2046
+ return false;
2047
+ };
1829
2048
  for (const req of evidenceRequired) {
1830
2049
  switch (req) {
1831
2050
  case "acceptance_criteria_met":
1832
- if (!hasPassing("verification"))
2051
+ if (!await hasPassing("verification"))
1833
2052
  return ok(false);
1834
2053
  break;
1835
2054
  case "tests_passed":
1836
- if (!hasPassing("test"))
2055
+ if (!await hasPassing("test"))
1837
2056
  return ok(false);
1838
2057
  break;
1839
2058
  case "review_approved":
1840
- if (!hasPassing("review"))
2059
+ if (!await hasPassing("review"))
1841
2060
  return ok(false);
1842
2061
  break;
1843
2062
  default:
@@ -1852,12 +2071,26 @@ async function captureTddSuiteEvidence(projectRoot, taskId, options) {
1852
2071
  if (!options.allowCompileCheck && !isAllowlistedTestCommand(options.command)) {
1853
2072
  return err(new Error("TDD suite command is not on the test allowlist. Re-run with --allow-compile-check to trust it."));
1854
2073
  }
2074
+ const paths = await collectReceiptPaths(projectRoot);
2075
+ const before = await captureReceipt(projectRoot, {
2076
+ taskId,
2077
+ phase: options.phase ?? "verification",
2078
+ paths,
2079
+ command: options.command,
2080
+ outcome: "failed",
2081
+ coverage: "project"
2082
+ });
1855
2083
  const result = await runCompileCheck({
1856
2084
  command: options.command,
1857
2085
  cwd: projectRoot
1858
2086
  });
1859
2087
  const suitePassed = result.success && !result.timedOut && result.exitCode === 0;
1860
2088
  const suiteFailed = !result.timedOut && result.exitCode !== 0;
2089
+ const receipt = { ...before, outcome: suitePassed ? "passed" : "failed" };
2090
+ const receiptResult = await verifyReceipt(projectRoot, receipt);
2091
+ if (!receiptResult.valid) {
2092
+ return err(new Error(`RDD candidate changed while the TDD suite ran: ${receiptResult.changedPaths.join(", ")}`));
2093
+ }
1861
2094
  const evidence = {
1862
2095
  id: `ev-tdd-${taskId}-${Date.now()}`,
1863
2096
  source: TDD_EVIDENCE_SOURCE,
@@ -1872,7 +2105,8 @@ async function captureTddSuiteEvidence(projectRoot, taskId, options) {
1872
2105
  suitePassed,
1873
2106
  exitCode: result.exitCode,
1874
2107
  timedOut: result.timedOut,
1875
- command: options.command
2108
+ command: options.command,
2109
+ rddReceipt: receipt
1876
2110
  }
1877
2111
  };
1878
2112
  const persisted = await persistEvidence(projectRoot, evidence);
@@ -1894,7 +2128,8 @@ async function captureTddSuiteEvidence(projectRoot, taskId, options) {
1894
2128
  return ok({
1895
2129
  evidenceId: evidence.id,
1896
2130
  suiteFailed,
1897
- suitePassed
2131
+ suitePassed,
2132
+ receipt
1898
2133
  });
1899
2134
  }
1900
2135
  async function loadTddSuiteEvidence(projectRoot, taskId, evidenceId) {
@@ -1904,7 +2139,7 @@ async function loadTddSuiteEvidence(projectRoot, taskId, evidenceId) {
1904
2139
  return path;
1905
2140
  let raw;
1906
2141
  try {
1907
- raw = await readFile6(path.data, "utf-8");
2142
+ raw = await readFile7(path.data, "utf-8");
1908
2143
  } catch (e) {
1909
2144
  return err(e instanceof Error ? e : new Error(String(e)));
1910
2145
  }
@@ -1926,13 +2161,37 @@ async function loadTddSuiteEvidence(projectRoot, taskId, evidenceId) {
1926
2161
  if (capturedBy !== TDD_CAPTURED_BY || typeof suiteFailed !== "boolean" || typeof suitePassed !== "boolean") {
1927
2162
  return err(new Error(`Evidence "${evidenceId}" was not captured by the verification runner`));
1928
2163
  }
1929
- return ok({ capturedBy, suiteFailed, suitePassed });
2164
+ const receipt = ev.data?.rddReceipt;
2165
+ if (!isRddReceipt(receipt)) {
2166
+ return err(new Error(`Evidence "${evidenceId}" has no valid RDD receipt`));
2167
+ }
2168
+ if (receipt.taskId !== taskId) {
2169
+ return err(new Error(`Evidence "${evidenceId}" receipt belongs to another task`));
2170
+ }
2171
+ const verified = await verifyReceipt(projectRoot, receipt);
2172
+ if (!verified.valid) {
2173
+ return err(new Error(`Evidence "${evidenceId}" RDD receipt is stale: ${verified.changedPaths.join(", ")}`));
2174
+ }
2175
+ return ok({ capturedBy, suiteFailed, suitePassed, receipt });
1930
2176
  }
1931
- async function hasTddRunnerEvidence(projectRoot, taskId) {
2177
+ async function hasTddRunnerEvidence(projectRoot, taskId, expectedPhase) {
1932
2178
  const collected = await collectTaskEvidence(projectRoot, taskId);
1933
2179
  if (!collected.success)
1934
2180
  return false;
1935
- return collected.data.records.some((ev) => ev.type === "tdd" && ev.source === TDD_EVIDENCE_SOURCE && ev.data?.capturedBy === TDD_CAPTURED_BY);
2181
+ for (const ev of collected.data.records) {
2182
+ if (ev.type !== "tdd" || ev.source !== TDD_EVIDENCE_SOURCE || ev.data?.capturedBy !== TDD_CAPTURED_BY) {
2183
+ continue;
2184
+ }
2185
+ const loaded = await loadTddSuiteEvidence(projectRoot, taskId, ev.id);
2186
+ if (!loaded.success)
2187
+ continue;
2188
+ if (expectedPhase === "red" && (!loaded.data.suiteFailed || loaded.data.suitePassed))
2189
+ continue;
2190
+ if (expectedPhase === "green" && (!loaded.data.suitePassed || loaded.data.suiteFailed))
2191
+ continue;
2192
+ return true;
2193
+ }
2194
+ return false;
1936
2195
  }
1937
2196
 
1938
2197
  // src/core/orchestrator/runtime-orchestrator.ts
@@ -2701,6 +2960,11 @@ export {
2701
2960
  CouncilVerdictInputSchema,
2702
2961
  CouncilVerdictSchema,
2703
2962
  DecisionSchema,
2963
+ DeliveryLedgerRequestSchema,
2964
+ DeliveryLedgerSchema,
2965
+ DeliveryLedgerTaskSchema,
2966
+ DeliveryRouteSchema,
2967
+ DeliveryTelemetrySchema,
2704
2968
  EvaluationIndexSchema,
2705
2969
  EvidenceSchema,
2706
2970
  ExecutionContextSchema,
@@ -2766,6 +3030,7 @@ export {
2766
3030
  TaskOutcomeSourceSchema,
2767
3031
  TaskOutcomeStatusSchema,
2768
3032
  TechnicalPlanOutputSchema,
3033
+ TokenUsageSchema,
2769
3034
  ToolProviderNamesSchema,
2770
3035
  VerificationReportSchema,
2771
3036
  WorkflowCommandSchema,
@@ -2774,7 +3039,9 @@ export {
2774
3039
  WorkflowRiskRuleSchema,
2775
3040
  advanceTddPhase,
2776
3041
  buildTaskEnvelope,
3042
+ captureReceipt,
2777
3043
  captureTddSuiteEvidence,
3044
+ collectReceiptPaths,
2778
3045
  completeTask,
2779
3046
  createInitialState,
2780
3047
  createInitialTddState,
@@ -2785,6 +3052,7 @@ export {
2785
3052
  getReadyTasks,
2786
3053
  goalTaskToCanonicalCard,
2787
3054
  hasTddRunnerEvidence,
3055
+ isRddReceipt,
2788
3056
  loadTddSuiteEvidence,
2789
3057
  loopStateMachine,
2790
3058
  rollbackTaskStatus,
@@ -2833,5 +3101,6 @@ export {
2833
3101
  validateSkillsRegistry,
2834
3102
  validateTargetCapabilities,
2835
3103
  validateTaskOutcome,
2836
- validateWorkflowProfile
3104
+ validateWorkflowProfile,
3105
+ verifyReceipt
2837
3106
  };
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Resolve the CLI command prefix based on execution context.
3
+ *
4
+ * - When invoked via npx (e.g. `npx cc-codeconductor ...`), returns `npx cc-codeconductor`.
5
+ * - When invoked via bunx, returns `bunx cc-codeconductor`.
6
+ * - When invoked during local development (`bun run dev` or executing `src/cli/main.ts`), returns `bun run dev`.
7
+ * - When invoked via an installed binary (`cc-codeconductor` or `codeconductor`), returns that binary name.
8
+ * - Respects the `CC_CLI_BIN` environment variable for testing or explicit overrides.
9
+ * - Defaults to `cc-codeconductor`.
10
+ */
11
+ export declare function resolveCliBin(env?: NodeJS.ProcessEnv, argv?: readonly string[]): string;
12
+ /**
13
+ * Formats a command usage string replacing any legacy or alternative command prefix
14
+ * (`cc `, `cc-codeconductor `, or `codeconductor `) with the resolved bin prefix.
15
+ */
16
+ export declare function formatUsage(usage: string, bin?: string): string;