@deksden-com/dd-flow-cli 0.9.0-beta.160 → 0.9.0-beta.161

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/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @deksden-com/dd-flow-cli
2
2
 
3
+ ## 0.9.0-beta.161
4
+
5
+ ### Patch Changes
6
+
7
+ - Validate accepted CODE handoff through retained PLAN-REVIEW byte custody and exact PLAN/batch hashes, without reapplying historical input-file or mutable workspace admission checks after implementation and repair (plan 115).
8
+
3
9
  ## 0.9.0-beta.160
4
10
 
5
11
  ### Patch Changes
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "cli_package": "@deksden-com/dd-flow-cli",
3
- "cli_version": "0.9.0-beta.160",
4
- "cli_commit": "3d065fa9b570fdb25570e4c47d7c99a5d50d5574",
5
- "built_at": "2026-10-29T15:12:42.101Z",
3
+ "cli_version": "0.9.0-beta.161",
4
+ "cli_commit": "367b9cb844aa34fd36d0a00cf059160377d10bdd",
5
+ "built_at": "2026-10-29T17:36:11.881Z",
6
6
  "built_with_canon": {
7
7
  "version": "4.1.4",
8
8
  "commit": "7cc415b3ef3ce37c9624c7cee51023e66f67cd57",
@@ -18,7 +18,7 @@ import { requireVnextWorkspaceRoute } from "./vnext-workspace-policy.js";
18
18
  import { readVnextSpecifyResult } from "./vnext-specify.js";
19
19
  import { nextWorkId } from "./ids.js";
20
20
  import { vnextStageDirectory } from "../domain/stage-catalog.js";
21
- import { acceptStageReport, prepareStageReport } from "./stage-report-renderer.js";
21
+ import { acceptStageReport, prepareStageReport, readAcceptedStageData } from "./stage-report-renderer.js";
22
22
  import { currentStagePrompt, applyExternalStageContext, prepareExternalStageContext } from "./stage-context.js";
23
23
  import { subagentCapacityKey } from "./vnext-fanout.js";
24
24
  import { stageLifecycleInstruction, workStopConditionInstruction } from "../harness-runtime/lib/delegation-instructions.mjs";
@@ -318,12 +318,35 @@ export function prepareVnextPlanArtifacts(context, input) {
318
318
  }
319
319
  };
320
320
  }
321
- /** CODE entry validates the same PLAN closure without changing an accepted batch. */
321
+ /** After PLAN-REVIEW, custody protects accepted intent; mutable Work inputs are
322
+ * admission conditions, not permanent invariants of the implementation tree. */
322
323
  export function validateVnextCodeHandoff(context, input) {
323
- return validateVnextPlanArtifacts(context, {
324
- ...input,
325
- protocols: protocolIds(input.home)
326
- });
324
+ const project = requireProjectByRoot(context, resolveProjectRoot(input.projectRoot));
325
+ const accepted = readAcceptedStageData(context, { projectId: project.id, runId: input.runId, stage: "plan-review" });
326
+ const report = JSON.parse(accepted.bytes.toString("utf8"));
327
+ const batch = path.join(input.home, "03-plan", "code-work-batch.json");
328
+ try {
329
+ if (!report.semantic?.batch_checksum || !fs.existsSync(batch) || checksum(batch) !== report.semantic.batch_checksum) {
330
+ throw new AppError("stale_code_work_batch", "CODE batch differs from accepted PLAN-REVIEW", 2, { batch });
331
+ }
332
+ const value = readJson(batch);
333
+ const ids = new Set();
334
+ if (!Array.isArray(value.sources) || !value.sources.length)
335
+ throw new AppError("validation", "Accepted CODE batch has no PLAN sources", 2);
336
+ for (const source of value.sources) {
337
+ if (typeof source.protocol_id !== "string" || !/^PRT-[^/\\\0]+$/.test(source.protocol_id) || ids.has(source.protocol_id) || !/^[a-f0-9]{64}$/.test(source.sha256)) {
338
+ throw new AppError("validation", "Accepted CODE batch has invalid PLAN sources", 2);
339
+ }
340
+ ids.add(source.protocol_id);
341
+ const file = path.join(input.workspaceRoot, ".memory-bank", "protocol", source.protocol_id, "plan.json");
342
+ if (!fs.existsSync(file) || checksum(file) !== source.sha256)
343
+ throw new AppError("stale_code_work_batch", "PLAN differs from accepted PLAN-REVIEW", 2, { file });
344
+ }
345
+ return [];
346
+ }
347
+ catch (error) {
348
+ return [validationFailure(batch, error)];
349
+ }
327
350
  }
328
351
  const planTask = "Produce accepted plan.json and aspect-map.json artifacts.";
329
352
  function planExample(protocolId) { return { schema_id: "dd-flow/protocol-plan@6", plan_id: "PLAN-001", protocol_id: protocolId, revision: 1, title: "Example", summary: "A compact executable plan.", source_refs: [{ kind: "specify", id: "SPECIFY", path: "run://RUN-000/01-specify/specify.json", requirement_ids: ["R-001", "AC-001"] }], goal: { outcome: "Deliver the accepted behavior.", constraints: ["Keep the accepted scope."], non_goals: [] }, assessment: { scope_breadth: { level: "narrow", surfaces: ["one surface"], reason: "One vertical slice." }, solution_novelty: { level: "established", surfaces: ["existing pattern"], reason: "Reuse project practice." }, solution_uncertainty: { level: "low", surfaces: ["known behavior"], reason: "No open technical question." }, failure_impact: { level: "low", surfaces: ["local feature"], reason: "Reversible local change." }, selected_depth: "compact_plan", depth_trigger: "none" }, decisions: [], document_updates: [], checks: [{ id: "CHK-P1-TEST", command: "pnpm test", purpose: "Proves the changed behavior.", run_at: "work", availability: "available" }], items: [{ id: "P1", title: "Implement behavior", summary: "Change the owning surface.", details: "Follow the accepted requirement and project conventions.", depends_on: [], requirement_refs: ["R-001", "AC-001"], semantic_spine: { user_outcome: "The requested behavior is available.", component_responsibility: "Own the behavior.", must_preserve: ["Existing behavior."], non_goals: [], acceptance_contribution: "Makes AC-001 observable." }, execution_context: { required_read: ["apps/api/src/example.ts"], discovery_boundary: ["Related tests only."], planned_write_areas: ["apps/api/src/"], stop_conditions: [] }, verification: { check_refs: ["CHK-P1-TEST"] } }], acceptance: [{ criterion_id: "AC-001", plan_item_ids: ["P1"], changed_surfaces: ["apps/api/src/example.ts"], path: "Exercise the accepted user path.", environment: "Local test environment.", fixtures: [], cleanup: "No persistent fixture.", check_refs: ["CHK-P1-TEST"], expected_evidence: ["Focused check passes."], proof_limits: ["Manual production evidence is not claimed."], gate: "work" }] }; }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deksden-com/dd-flow-cli",
3
- "version": "0.9.0-beta.160",
3
+ "version": "0.9.0-beta.161",
4
4
  "description": "Mechanical runtime CLI for dd-flow workflows.",
5
5
  "type": "module",
6
6
  "packageManager": "pnpm@10.23.0",