@abelxiaoxing/cadence 1.2.1 → 1.2.3

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.
@@ -15,6 +15,7 @@ import {
15
15
  compileImplementPlan,
16
16
  compileReadyReceipt,
17
17
  type DeliveryArtifactBinding,
18
+ DesignPlanValidationError,
18
19
  type GateApprovalProof,
19
20
  parseGateAReceipt,
20
21
  parseImplementPlan,
@@ -88,6 +89,10 @@ export type DesignControlRequest =
88
89
  operationId: string;
89
90
  gate: "gate-b";
90
91
  }
92
+ | {
93
+ operation: "validate-plan-draft";
94
+ runId: string;
95
+ }
91
96
  | {
92
97
  operation: "compile-plan";
93
98
  runId: string;
@@ -198,7 +203,10 @@ export function validateDesignControlRequest(
198
203
  ? { ok: true, value: structuredClone(value) as DesignControlRequest }
199
204
  : { ok: false, code: "invalid-design-control-request" };
200
205
  }
201
- if (value.operation === "status") {
206
+ if (
207
+ value.operation === "status" ||
208
+ value.operation === "validate-plan-draft"
209
+ ) {
202
210
  return exactKeys(value, ["operation", "runId"]) &&
203
211
  typeof value.runId === "string" &&
204
212
  IDENTIFIER.test(value.runId)
@@ -508,6 +516,8 @@ export class DesignController {
508
516
  return this.#journal.recordDecision(request);
509
517
  case "approve-gate":
510
518
  return this.#journal.approveGate(request);
519
+ case "validate-plan-draft":
520
+ return this.#validatePlanDraft(request);
511
521
  case "compile-plan":
512
522
  return this.#compilePlan(request);
513
523
  case "finalize-delivery":
@@ -539,7 +549,7 @@ export class DesignController {
539
549
  const canApproveGate =
540
550
  !design.gates.gateA.current ||
541
551
  (planReadyForGateB && !design.gates.gateB.current);
542
- const legalActions = terminal
552
+ const legalOperations = terminal
543
553
  ? ["status"]
544
554
  : [
545
555
  "status",
@@ -549,7 +559,12 @@ export class DesignController {
549
559
  ? ["bind-change"]
550
560
  : []),
551
561
  ...(design.gates.gateA.current && design.change
552
- ? ["write-artifact", "delete-artifact", "compile-plan"]
562
+ ? [
563
+ "write-artifact",
564
+ "delete-artifact",
565
+ "validate-plan-draft",
566
+ "compile-plan",
567
+ ]
553
568
  : []),
554
569
  ...(design.change &&
555
570
  design.plan &&
@@ -557,7 +572,6 @@ export class DesignController {
557
572
  design.gates.gateB.current
558
573
  ? ["finalize-delivery"]
559
574
  : []),
560
- "finish",
561
575
  ];
562
576
  return {
563
577
  runId: run.runId,
@@ -566,7 +580,8 @@ export class DesignController {
566
580
  state: run.state,
567
581
  completed: run.state === "completed",
568
582
  ...(run.pauseCode ? { pause: { code: run.pauseCode } } : {}),
569
- legalActions,
583
+ legalOperations,
584
+ packetActions: terminal ? [] : ["finish"],
570
585
  design,
571
586
  };
572
587
  }
@@ -578,7 +593,7 @@ export class DesignController {
578
593
  ...(fromRequirement
579
594
  ? {
580
595
  provisionalKey: transientHash(
581
- "abel-design-requirement-v1",
596
+ "abel-design-requirement",
582
597
  request.requirement,
583
598
  ),
584
599
  }
@@ -772,6 +787,51 @@ export class DesignController {
772
787
  }
773
788
  }
774
789
 
790
+ #readCompiledDraft(runId: string) {
791
+ const status = this.#journal.status(runId);
792
+ if (!status.change) throw new Error("design-change-required");
793
+ if (!status.gates.gateA.current) throw new Error("design-gate-a-required");
794
+ const draftPath = safeRelative(status.change, "plan-draft.json");
795
+ const draftBytes = readSafeFile(this.consumerRoot, draftPath);
796
+ let draft: unknown;
797
+ try {
798
+ draft = JSON.parse(draftBytes.toString("utf8"));
799
+ } catch {
800
+ throw new DesignPlanValidationError("design-plan-draft-invalid", [
801
+ { code: "design-plan-draft-invalid", field: "plan-draft.json" },
802
+ ]);
803
+ }
804
+ const compiled = compileImplementPlan(draft, {
805
+ consumerRoot: this.consumerRoot,
806
+ });
807
+ if (compiled.plan.changeId !== status.change) {
808
+ throw new DesignPlanValidationError("design-plan-change-mismatch", [
809
+ { code: "design-plan-change-mismatch", field: "changeId" },
810
+ ]);
811
+ }
812
+ return { status, compiled };
813
+ }
814
+
815
+ #validatePlanDraft(
816
+ request: Extract<
817
+ DesignControlRequest,
818
+ { operation: "validate-plan-draft" }
819
+ >,
820
+ ) {
821
+ const { compiled } = this.#readCompiledDraft(request.runId);
822
+ return {
823
+ operation: request.operation,
824
+ runId: request.runId,
825
+ valid: true,
826
+ plan: {
827
+ taskCount: compiled.plan.tasks.length,
828
+ outputCount: compiled.plan.outputs.length,
829
+ rawSha256: compiled.rawSha256,
830
+ canonicalHash: compiled.planHash,
831
+ },
832
+ };
833
+ }
834
+
775
835
  #compilePlan(
776
836
  request: Extract<DesignControlRequest, { operation: "compile-plan" }>,
777
837
  ) {
@@ -787,32 +847,17 @@ export class DesignController {
787
847
  });
788
848
  try {
789
849
  this.#journal.assertNoPendingArtifactOperations(request.runId);
790
- const status = this.#journal.status(request.runId);
791
- if (!status.change) throw new Error("design-change-required");
792
- if (!status.gates.gateA.current)
793
- throw new Error("design-gate-a-required");
794
- const readyPath = safeRelative(status.change, "ready.yaml");
795
- const gateAPath = safeRelative(status.change, "gate-a.yaml");
850
+ const { status, compiled } = this.#readCompiledDraft(request.runId);
851
+ const change = status.change;
852
+ if (!change) throw new Error("design-change-required");
853
+ const readyPath = safeRelative(change, "ready.yaml");
854
+ const gateAPath = safeRelative(change, "gate-a.yaml");
796
855
  removeSafeFile(this.consumerRoot, readyPath);
797
856
  removeSafeFile(this.consumerRoot, gateAPath);
798
- const draftPath = safeRelative(status.change, "plan-draft.json");
799
- const draftBytes = readSafeFile(this.consumerRoot, draftPath);
800
- let draft: unknown;
801
- try {
802
- draft = JSON.parse(draftBytes.toString("utf8"));
803
- } catch {
804
- throw new Error("design-plan-draft-invalid");
805
- }
806
- const compiled = compileImplementPlan(draft as never, {
807
- consumerRoot: this.consumerRoot,
808
- });
809
- if (compiled.plan.changeId !== status.change) {
810
- throw new Error("design-plan-change-mismatch");
811
- }
812
857
  this.#journal.assertFinalizationLease(lease);
813
858
  atomicWrite(
814
859
  this.consumerRoot,
815
- safeRelative(status.change, "implement-plan.json"),
860
+ safeRelative(change, "implement-plan.json"),
816
861
  compiled.bytes,
817
862
  );
818
863
  return this.#journal.recordCompiledPlan({
@@ -899,7 +899,7 @@ export class DesignJournal {
899
899
  }): Record<string, unknown> {
900
900
  requireIdentifier(input.decisionId, "design-decision-id");
901
901
  const decisionContractHash = contractHash(
902
- "abel-design-decision-v1",
902
+ "abel-design-decision",
903
903
  input.contract,
904
904
  );
905
905
  if (input.category !== "behavior" && input.category !== "technical") {
@@ -1024,7 +1024,7 @@ export class DesignJournal {
1024
1024
  }
1025
1025
  const gateAContractHash =
1026
1026
  input.gate === "gate-a"
1027
- ? contractHash("abel-design-gate-a-v1", input.contract)
1027
+ ? contractHash("abel-design-gate-a", input.contract)
1028
1028
  : undefined;
1029
1029
  return this.#transaction(() => {
1030
1030
  this.#run(input.runId, true);
@@ -56,7 +56,7 @@ function updateManifest(
56
56
 
57
57
  function recursiveDirectoryManifest(abs: string): string {
58
58
  const hash = createHash("sha256");
59
- updateManifest(hash, "cadence-directory-manifest-v2");
59
+ updateManifest(hash, "cadence-directory-manifest");
60
60
  const visit = (directory: string, prefix: string): void => {
61
61
  const names = readdirSync(directory).sort();
62
62
  for (const name of names) {