@dzhechkov/harness-cli 0.3.236 → 0.3.237

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/.dz-manifest.json CHANGED
@@ -9,15 +9,15 @@
9
9
  },
10
10
  {
11
11
  "path": "README.md",
12
- "sha256": "1e36d7e9e6022d412c030975ec686b1ab91c61c64c807ef2e9ff3fa75ac8917c"
12
+ "sha256": "7e8b772a6fa9ca0f36364cafd5ea996abeb62dc894c2f67f50ea7704a7a8824d"
13
13
  },
14
14
  {
15
15
  "path": "coverage/coverage-final.json",
16
- "sha256": "1abb00d07ab57ad413d2747baa6a68cda0876a9e0c6f75db89c205fbf4863530"
16
+ "sha256": "667bf610bf890a7b93480a4b1045e98dc0c765effd80b78fde4e48538f595b3e"
17
17
  },
18
18
  {
19
19
  "path": "coverage/coverage-summary.json",
20
- "sha256": "42d2a98f54c2ec773b49a0a43c959a78d070c8c427724f4affbd5bafef35621d"
20
+ "sha256": "593705e81f851c0e65ffa9feaa9bbd396e7a3295b9b21076cfd953ee5a05b93a"
21
21
  },
22
22
  {
23
23
  "path": "dist/bin.d.ts",
@@ -41,15 +41,15 @@
41
41
  },
42
42
  {
43
43
  "path": "dist/cli.d.ts.map",
44
- "sha256": "8a00bf14c3fdd437b7e482da8c4018366041755714ed1791b1c523f9dee5de6c"
44
+ "sha256": "cf6a3265890a8856ef31e3e7ac58026c15232c3c118ba0fcd1ce0d7590b84dd8"
45
45
  },
46
46
  {
47
47
  "path": "dist/cli.js",
48
- "sha256": "dea4446db1109285c1fc5f5283d7263462cb446f12b0d9b1e1e821374d0ca57d"
48
+ "sha256": "b9af9be1bd31acd60e76275ff1055dd8e9b39b531b0c375467648f142b74d2c4"
49
49
  },
50
50
  {
51
51
  "path": "dist/cli.js.map",
52
- "sha256": "a253625c94835ef94bbd141b1dd759578433423bd098314fd977c515f140dafe"
52
+ "sha256": "6a51963ede51129e43524d62f3d757255a002dfec3df2c1dfa519af6f235a667"
53
53
  },
54
54
  {
55
55
  "path": "dist/index.d.ts",
@@ -73,7 +73,7 @@
73
73
  },
74
74
  {
75
75
  "path": "package.json",
76
- "sha256": "543319797d47d599a646c7d695f82aa31491ffd97579edd691b6a9cb99af76ef"
76
+ "sha256": "1e7ef1d6e0796144999ad64d3650aeb4a2ccc7dfc66c5c5a8b705d783a9d0801"
77
77
  },
78
78
  {
79
79
  "path": "src/bin.ts",
@@ -81,7 +81,7 @@
81
81
  },
82
82
  {
83
83
  "path": "src/cli.ts",
84
- "sha256": "c5d4902f9b0c4133318b15e757d07856872177dc92752d5996440524342b7f88"
84
+ "sha256": "5180330ac6612542c80a74ea8e0983f5cd231e95bb3962eccdd65fbdbf6611a8"
85
85
  },
86
86
  {
87
87
  "path": "src/index.ts",
@@ -89,7 +89,7 @@
89
89
  },
90
90
  {
91
91
  "path": "test/cli.test.ts",
92
- "sha256": "0538f3cfd8eb880305c08fef05a78601263003c54a6f1b44f97cd7ebd7bd37f9"
92
+ "sha256": "461beed08ad6cfde7bbf559701fcbc6978f622c3951c80463c4e4943c538eff5"
93
93
  },
94
94
  {
95
95
  "path": "tsconfig.json",
@@ -101,5 +101,5 @@
101
101
  }
102
102
  ]
103
103
  },
104
- "signature": "0IDcNO+8RqyABrL7YXlDBQLCTiNktCk/Ktd724vSyxsJ0/rti05jjEudABZo3+ILMok7jLgQs/YRalC77RdOCA=="
104
+ "signature": "06gdM99WpJhmarOtUFoeMAlGAfAvCboh/QGbCEIBhMAqgLn5rnSCXAb2023QdO+hZsuxrijyGzgBh62l/L+GBQ=="
105
105
  }
package/README.md CHANGED
@@ -392,13 +392,54 @@ Example (real output, trimmed):
392
392
  dz parity — codex (capabilities: shell, skills, mcp)
393
393
  ✓ dz CLI (all commands) via shell command
394
394
  ◐ feature-adr pipeline via interactive skill (plain /feature-adr)
395
- Step-10 Delivery Gate not available on this target
395
+ Step-10 Delivery Gate via dz delivery-check (CLI 4-plane hand-off protocol)
396
396
  ◐ Integrity claim-check via dz claim-check (CLI) + publish gate
397
397
  ```
398
398
 
399
399
  **When to use:** before promising a workflow to a teammate on Cursor/Codex/Hermes; when choosing
400
400
  a target for a project; as the requirements input for porting a feature to more targets.
401
401
 
402
+ ### Portable delivery gate — `dz delivery-check` (Step-10, on every shell target)
403
+
404
+ The feature-adr Step-10 Delivery Gate reviews a landed feature across four orthogonal planes and
405
+ emits a machine-checkable `ready | blocked` hand-off. On Claude-Code the ultracode workflow can run
406
+ it as the **opt-in** Step-10 (`args.deliveryGate: true` — off by default); `dz delivery-check` is
407
+ the **portable `manual` form** that travels to every shell
408
+ target (Cursor/Codex/Gemini/…). The CLI runs the deterministic parts (artifact probes, fail-closed
409
+ hand-off arithmetic, cross-validation bookkeeping) and **dispatches** the semantic review to the
410
+ target's own agent runtime — the `dz challenge` cartridge shape. It never posts anything anywhere
411
+ (findings-only).
412
+
413
+ ```bash
414
+ dz delivery-check --slug my-feature --context-only # print artifact probes + the 4-plane review brief
415
+ dz delivery-check --slug my-feature --findings review.json # classify a fed-back review → writes 10_delivery_review.md, prints ready|blocked
416
+ dz delivery-check --slug my-feature --findings review.json --strict --json # CI gate: exit 1 on blocked, machine-readable result
417
+ ```
418
+
419
+ Example (trimmed):
420
+
421
+ ```
422
+ dz delivery-check — my-feature: blocked
423
+ ✓ 0 BLOCKER: PASS
424
+ ✗ 0 HIGH: FAIL — 1 confirmed HIGH
425
+ ✓ planes complete: PASS
426
+ ✓ BLOCKER/HIGH cross-validated: PASS
427
+ ✓ required artifacts present: PASS
428
+ ↳ wrote features/my-feature/10_delivery_review.md
429
+ ```
430
+
431
+ `ready` only off complete, cross-validated, clean evidence: a null/partial plane, a failed required
432
+ probe (the `07_code_changes/` manifest), a confirmed BLOCKER/HIGH, or an **un-cross-validated**
433
+ BLOCKER/HIGH (`cross-validation-incomplete`) all yield `blocked`. Classification reads only numeric
434
+ severity counts, so instruction-like text inside a finding cannot move the verdict.
435
+
436
+ **When to use:** as the final quality hand-off for a landed feature on any non-Claude-Code target;
437
+ as a CI gate (`--strict`) that fails a merge on an unresolved BLOCKER/HIGH.
438
+
439
+ For AGENTS.md-class targets, `dz feature-adr-setup --gates [--target <name>] --apply` emits a
440
+ zero-config `architecture/gates/delivery-check.md` whose runnable-here gate list is computed from
441
+ `dz parity` for that target (create-if-absent, never clobbered).
442
+
402
443
  ### Verified release — `dz release` (4 HARD gates in front of `dz publish`)
403
444
 
404
445
  `dz publish` gates on guard / claim-check / signatures / provenance / files-whitelist — none of which
@@ -508,7 +549,7 @@ Get the whole set with `dz init --target claude-code --preset meta`, or pick one
508
549
 
509
550
  > **A skill and its npx toolkit are not duplicates — they're a graduation.** Several skills (e.g. `feature-adr`, `design-thinking`) exist BOTH as a skill inside a `dz` preset AND as a standalone `npx` package. The preset's SKILL.md is **fully functional on its own** (the whole methodology — modules + references — travels with it, and it auto-activates by description), and it's the only way to compile that capability to the **non-Claude platforms** (Codex/OpenCode/Hermes/OpenClaude) via `dz`. The npx package adds **project-level runtime governance** around the same skill: a slash command, governance rules, a context shard, and (for feature-adr) reward-learning + `/harvest`. So: pick the **skill/preset** for a working capability across platforms; pick the **npx toolkit** when you want it as a governed, command-driven fixture of one project.
510
551
 
511
- ## All Commands (56)
552
+ ## All Commands (57)
512
553
 
513
554
  ```
514
555
  dz setup --target <name> [--preset <name>] [--select id,id,...] [--skills-dir <dir>] [--memory agentdb] [--no-memory] [--no-hooks] [--install-driver] [--force]
@@ -563,6 +604,7 @@ dz challenge --plan <plan.md> [--json] [--context-only] [--author <model>] # a
563
604
  dz routing [--stage <s>] [--json] # inspect the learned cost-optimal routing store: what `args.models.<stage>='auto-cost'` believes per (stage, complexity-tier, model) — gated attempts/successes/rate (feeds feature-adr model selection)
564
605
  dz bto-optimize --split|--plan|--select|--scope-check|--diff [--json] # deterministic engine behind /bto-optimize: hold-out split + hard-capped budget + no-regress-on-holdout winner selection (defeats judge-gaming); prose-only, diff-confirmed, never auto-writes
565
606
  dz discrimination-check --test <f[,f]> [--base <ref>] [--name <filter>] [--runner <cmd>] [--json] # §42 test-discrimination gate for feature-adr Step-8: run the ADR's property test in an isolated git worktree at pre-feature base — it MUST go red without the fix; a green is a false green (HIGH finding, advisory, never auto-aborts)
607
+ dz delivery-check --slug <slug> [--context-only] [--findings <f.json>] [--strict] [--author <model>] [--json] # portable Step-10 Delivery Gate: the `manual` form that travels to every shell target — prints the 4-plane review brief (regressions ‖ security ‖ code-quality ‖ product-honesty) + artifact probes; --findings classifies a fed-back review into a fail-closed ready|blocked hand-off (only cross-validated BLOCKER/HIGH count) and writes features/<slug>/10_delivery_review.md; --strict exits 1 on blocked
566
608
  dz sign --init --out <path> | --pack <dir> --key <path> # --init: generate the Ed25519 keypair (private OUTSIDE the repo, prints the public key for keys/dz.pub); else sign a pack's manifest + CycloneDX SBOM
567
609
  dz sbom --pack <dir> [--out <file>] # emit the CycloneDX 1.5 SBOM for a pack standalone (file-level bill of materials); print to stdout or write to a file
568
610
  dz guard check --op <publish|teach|consolidate|reindex> [--text <s>] [--json] [--force <reason>] # declarative constraint layer before self-mutating ops: HARD violation → block (exit 1), SOFT → warn; zero-config defaults, .dz/guard.json to customise; dz guard --init | dz guard log (append-only audit). dz publish runs it automatically (--no-guard "<reason>" = logged escape hatch)
package/dist/cli.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAgQH,2EAA2E;AAC3E,MAAM,WAAW,KAAK;IACpB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC;;;;OAIG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;OAKG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,iBAAiB,CAAC;CAC5C;AAED,yFAAyF;AACzF,MAAM,MAAM,iBAAiB,GAAG,CAC9B,GAAG,EAAE,MAAM,EACX,IAAI,EAAE;IAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAAE,KACvD;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AAs0K9E,wBAAsB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,GAAE,KAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAgJ5E"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAuQH,2EAA2E;AAC3E,MAAM,WAAW,KAAK;IACpB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC;;;;OAIG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;OAKG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,iBAAiB,CAAC;CAC5C;AAED,yFAAyF;AACzF,MAAM,MAAM,iBAAiB,GAAG,CAC9B,GAAG,EAAE,MAAM,EACX,IAAI,EAAE;IAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAAE,KACvD;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AAo9K9E,wBAAsB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,GAAE,KAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAkJ5E"}
package/dist/cli.js CHANGED
@@ -9,7 +9,7 @@ import { fileURLToPath } from 'node:url';
9
9
  import { execSync } from 'node:child_process';
10
10
  import { homedir, tmpdir } from 'node:os';
11
11
  import { createRequire } from 'node:module';
12
- import { createSkill, getSkillInfo, getWorkflow, isTargetName, listSkills, runDoctor, runInit, benchmarkSkill, benchmarkSkills, scanMcp, reconcileCapabilities, RECONCILE_BANNER, buildRegistry, discoverSkillPackDirs, checkUpstream, compareSkills, checkAllUpstream, sweepSkillDrift, syncCanonicalSkill, checkUpgrades, discoverPackages, discoverSourcePackages, fetchAllDownloads, filterByCategory, pretrain, recommend, generatePlugin, publishPackages, runSetup, runMigrate, searchRegistry, runSync, runVerify, runInitAgentsMd, runInitGeminiMd, TARGET_NAMES, buildParityMatrix, TARGET_CAPABILITIES, TARGET_SHORT_LABELS, WORKFLOW_NAMES, importEcc, recordPattern, resolveLearningBackend, storeStats, consolidateSessions, pruneNoisePatterns, lessonDeltaReport, removePatternsByIds, snapshotStore, recallHybrid, teachGuard, mirrorPatternsToVector, vectorMirrorEnabled, vectorTierStatus, resolveVectorEngine, reindexVectorStore, harmonizeVectorStore, importRvfCheckpoint, statuslineData, writeFeatureAdrState, computeUsage, deriveUsageCalibration, normalizeClaudeUsageModelKey, readUsageLimits, claimCheck, summarize, queryBookKnowledge, loadStorePatternsSync, patternRecordId, loadStoreRecords, recordToPattern, bundleSkills, brainHome, listBrain, promoteProjectToBrain, updateBrainSource, queryBrain, groundPrompt, expandKu, reindexBrainVectors, buildPrimer, exportBrainSlice, importBrainSlice, registerKusToBrain, RECALL_USAGE_LOG_RELATIVE, RECALL_USAGE_LOG_MAX_BYTES, parseRecallUsageLog, buildRecallUsageReport, buildManifest, buildSbom, resolveTrustRoot, decideVerifyPolicy, generateSigningKeypair, evaluateGuard, resolveRules, auditRecord, guardExitCode, DEFAULT_RULES, decideProvenance, isInsideTree, signManifest, verifyManifest, listSignablePackFiles, assertKeyOutsideTree, decidePublishGate, collectPackageFacts, planReleaseGates, selectAffectedPackages, classifyGateExecutions, buildFailureIssue, buildReleaseNotes, releaseTagName, firstOutputLine, formatPublishError, MANIFEST_NAME, SBOM_NAME, buildArchitectureMap, renderMapHuman, findArchitectureDrift, renderDriftReport, scanWorkspacePackages, loadSubsystemManifest, loadProductVision, checkFeatureAgainstArchitecture, renderArchCheck, planProjectSkills, guidanceForStage, renderInjectionReport, analyzeCorpus, renderRakeReport, renderCriticSection, rakeAsLesson, rakeReward, DEFAULT_RAKE_THRESHOLDS, streamSessionEvents, findLatestTranscript, detectProcessRakes, buildRetro, renderRetro, retroLessonText, PROCESS_SIGNATURES, RETRO_DOMAIN, scanForSetup, buildSetupPlan, scaffoldFromSpec, renderScaffoldPreview, readExistingForScaffold, assembleChallengeContext, buildChallengeBrief, planDiscriminationCheck, classifyDiscrimination, pickAdversaryModel, CHALLENGE_QUESTIONS, loadOutcomes, renderOutcomes, statsForKey, selectAutoCost, recordProvisional, finalizeOutcome, COST_LADDER, splitScenarios, budgetPlan, selectWinner, proseScopeOk, renderProseDiff, readScenarioIds, DEFAULT_MAX_JUDGE_RUNS, } from '@dzhechkov/harness-core';
12
+ import { createSkill, getSkillInfo, getWorkflow, isTargetName, listSkills, runDoctor, runInit, benchmarkSkill, benchmarkSkills, scanMcp, reconcileCapabilities, RECONCILE_BANNER, buildRegistry, discoverSkillPackDirs, checkUpstream, compareSkills, checkAllUpstream, sweepSkillDrift, syncCanonicalSkill, checkUpgrades, discoverPackages, discoverSourcePackages, fetchAllDownloads, filterByCategory, pretrain, recommend, generatePlugin, publishPackages, runSetup, runMigrate, searchRegistry, runSync, runVerify, runInitAgentsMd, runInitGeminiMd, TARGET_NAMES, buildParityMatrix, TARGET_CAPABILITIES, TARGET_SHORT_LABELS, WORKFLOW_NAMES, importEcc, recordPattern, resolveLearningBackend, storeStats, consolidateSessions, pruneNoisePatterns, lessonDeltaReport, removePatternsByIds, snapshotStore, recallHybrid, teachGuard, mirrorPatternsToVector, vectorMirrorEnabled, vectorTierStatus, resolveVectorEngine, reindexVectorStore, harmonizeVectorStore, importRvfCheckpoint, statuslineData, writeFeatureAdrState, computeUsage, deriveUsageCalibration, normalizeClaudeUsageModelKey, readUsageLimits, claimCheck, summarize, queryBookKnowledge, loadStorePatternsSync, patternRecordId, loadStoreRecords, recordToPattern, bundleSkills, brainHome, listBrain, promoteProjectToBrain, updateBrainSource, queryBrain, groundPrompt, expandKu, reindexBrainVectors, buildPrimer, exportBrainSlice, importBrainSlice, registerKusToBrain, RECALL_USAGE_LOG_RELATIVE, RECALL_USAGE_LOG_MAX_BYTES, parseRecallUsageLog, buildRecallUsageReport, buildManifest, buildSbom, resolveTrustRoot, decideVerifyPolicy, generateSigningKeypair, evaluateGuard, resolveRules, auditRecord, guardExitCode, DEFAULT_RULES, decideProvenance, isInsideTree, signManifest, verifyManifest, listSignablePackFiles, assertKeyOutsideTree, decidePublishGate, collectPackageFacts, planReleaseGates, selectAffectedPackages, classifyGateExecutions, buildFailureIssue, buildReleaseNotes, releaseTagName, firstOutputLine, formatPublishError, MANIFEST_NAME, SBOM_NAME, buildArchitectureMap, renderMapHuman, findArchitectureDrift, renderDriftReport, scanWorkspacePackages, loadSubsystemManifest, loadProductVision, checkFeatureAgainstArchitecture, renderArchCheck, planProjectSkills, guidanceForStage, renderInjectionReport, analyzeCorpus, renderRakeReport, renderCriticSection, rakeAsLesson, rakeReward, DEFAULT_RAKE_THRESHOLDS, streamSessionEvents, findLatestTranscript, detectProcessRakes, buildRetro, renderRetro, retroLessonText, PROCESS_SIGNATURES, RETRO_DOMAIN, scanForSetup, buildSetupPlan, scaffoldFromSpec, renderScaffoldPreview, readExistingForScaffold, assembleChallengeContext, buildChallengeBrief, planDiscriminationCheck, classifyDiscrimination, pickAdversaryModel, CHALLENGE_QUESTIONS, loadOutcomes, renderOutcomes, statsForKey, selectAutoCost, recordProvisional, finalizeOutcome, COST_LADDER, splitScenarios, budgetPlan, selectWinner, proseScopeOk, renderProseDiff, readScenarioIds, DEFAULT_MAX_JUDGE_RUNS, collectDeliveryFacts, planDeliveryCheck, renderDeliveryBrief, classifyDelivery, isUsablePlaneResult, renderDeliveryReview, } from '@dzhechkov/harness-core';
13
13
  import { getPreset, PRESET_NAMES } from '@dzhechkov/harness-presets';
14
14
  import { scanGitHub, analyzeRepo, generateReport, deepAnalyze, scanAllSources, ScoutMemory } from '@dzhechkov/scout';
15
15
  const USAGE = `dz - DZ cross-platform harness CLI
@@ -34,6 +34,7 @@ Usage:
34
34
  dz publish [--filter <name>] [--bump-only] [--claim-check <off|warn|error>] [--require-signing] [--provenance|--no-provenance] (dry-run by default; pass --yes/--confirm/--no-dry-run to go live; claim-check gate default warn — surfaces README claim findings, never blocks; error fails an offending package)
35
35
  dz release [--filter <name>] [--tag] [--publish] [--json] [--dry-run] [--no-issue] (VERIFIED release: 4 HARD gates in FRONT of dz publish — full package test suites, audit >=high, node --check of every dist/bin file, bin smoke-boot via "node <bin> --help" — any red gate STOPS the release (exit 1) + best-effort gh issue; all green ⇒ re-sign reminder, then prints the ready dz publish command (or chains with --publish); never duplicates publish's own gates)
36
36
  dz parity [--target <name>] [--json] (the honest feature×target map, COMPUTED from the capability model — which harness feature is full / manual / absent on each of the ${TARGET_NAMES.length} targets, and via which form)
37
+ dz delivery-check --slug <slug> [--context-only] [--findings <f.json>] [--strict] [--author <model>] [--json] (portable Step-10 Delivery Gate: prints the 4-plane review brief + artifact probes; --findings classifies a fed-back review into a fail-closed ready|blocked hand-off and writes features/<slug>/10_delivery_review.md; --strict exits 1 on blocked)
37
38
  dz setup --target <name> [--preset <name>] [--select id,id,...] [--skills-dir <dir>] [--project <dir>] [--memory agentdb] [--no-memory] [--no-hooks] [--install-driver] [--force] [--enrich]
38
39
  dz teach "<pattern>" [--reward <0-1>] [--domain <name>] [--type rule|success-pattern|lesson-learned] [--project <dir>] [--no-mirror] (--project pins the learned store to <dir>/.dz, not the cwd — pin to a canonical brain)
39
40
  dz teach --from-json <file> [--project <dir>] [--no-mirror] (bulk-import a 'dz recall --all --json' export — share a learned store across machines)
@@ -4905,8 +4906,17 @@ function cmdFeatureAdrSetup(options, flags, cwd, write) {
4905
4906
  write('dz feature-adr-setup: --loc-cap must be a positive finite number');
4906
4907
  return 1;
4907
4908
  }
4909
+ // portable-gates (direction b): --gates scaffolds the zero-config architecture/gates/delivery-check.md.
4910
+ // Its "runnable here" list is computed for --target (default agents-md, the AGENTS.md-class target class).
4911
+ const wantGates = flags.has('gates');
4912
+ const targetOpt = options.get('target');
4913
+ if (targetOpt !== undefined && !isTargetName(targetOpt)) {
4914
+ write(`dz feature-adr-setup: --target must be one of: ${TARGET_NAMES.join(', ')}`);
4915
+ return 1;
4916
+ }
4917
+ const gatesTarget = isTargetName(targetOpt ?? '') ? targetOpt : 'agents-md';
4908
4918
  const specPath = options.get('from-spec');
4909
- if (specPath === undefined && !wantGuards) {
4919
+ if (specPath === undefined && !wantGuards && !wantGates) {
4910
4920
  // default + --plan: the read-only "which documents, and where?" answer.
4911
4921
  const plan = buildSetupPlan(scanForSetup(repoRoot));
4912
4922
  if (flags.has('json')) {
@@ -4944,7 +4954,9 @@ function cmdFeatureAdrSetup(options, flags, cwd, write) {
4944
4954
  }
4945
4955
  if (wantGuards)
4946
4956
  spec = { ...spec, guards: locCap !== undefined ? { locCap } : true };
4947
- const result = scaffoldFromSpec(spec, readExistingForScaffold(repoRoot));
4957
+ if (wantGates)
4958
+ spec = { ...spec, gates: true };
4959
+ const result = scaffoldFromSpec(spec, readExistingForScaffold(repoRoot), gatesTarget);
4948
4960
  if (flags.has('json') && !flags.has('apply')) {
4949
4961
  write(JSON.stringify(result, null, 2));
4950
4962
  return 0;
@@ -5182,6 +5194,149 @@ function cmdDiscriminationCheck(options, flags, cwd, write) {
5182
5194
  function nameFor(t, outcome) {
5183
5195
  return t.name !== undefined ? { file: t.file, name: t.name, outcome } : { file: t.file, outcome };
5184
5196
  }
5197
+ /**
5198
+ * `dz delivery-check` — the portable Step-10 Delivery Gate (feature portable-gates). The `manual` form that
5199
+ * travels to every `shell` target: the deterministic parts (artifact probes, hand-off arithmetic,
5200
+ * cross-validation bookkeeping) run IN the CLI; the semantic 4-plane review is DISPATCHED to the caller's own
5201
+ * agent runtime — the `dz challenge` cartridge shape. All logic lives in harness-core's pure engine; this is
5202
+ * the executor. Advisory exit codes (0 by default; `--strict` ⇒ 1 on `blocked`).
5203
+ *
5204
+ * --slug <slug> the feature under features/<slug> (required; featureDir derived internally)
5205
+ * --context-only default mode: print artifact probes + the 4-plane review brief (no verdict)
5206
+ * --findings <f.json> classify a fed-back findings array → write 10_delivery_review.md + print ready/blocked
5207
+ * --strict with --findings: exit 1 iff handoff === 'blocked' (CI gate)
5208
+ * --author <model> cosmetic: the reviewer to dispatch, printed alongside the brief
5209
+ * --json machine contract { planesChecked, planesSkipped, findings, handoff, artifact }
5210
+ */
5211
+ function cmdDeliveryCheck(options, flags, cwd, write) {
5212
+ let repoRoot = cwd;
5213
+ try {
5214
+ repoRoot = execSync('git rev-parse --show-toplevel', { cwd, encoding: 'utf-8', stdio: ['ignore', 'pipe', 'ignore'] }).trim() || cwd;
5215
+ }
5216
+ catch { /* not git */ }
5217
+ const json = flags.has('json');
5218
+ const errOut = (error) => {
5219
+ if (json)
5220
+ write(JSON.stringify({ error, planesChecked: [], planesSkipped: [], findings: [], handoff: null, artifact: 'not-written' }, null, 2));
5221
+ else {
5222
+ write(`dz delivery-check: ${error}`);
5223
+ write(' allowed: --slug <slug>, --findings <f.json>, --author <model>, --context-only, --strict, --json');
5224
+ }
5225
+ return 1;
5226
+ };
5227
+ // Strict allowlist (delivery finding: a typo'd --findings silently downgraded the --strict CI
5228
+ // gate to a vacuous exit-0 pass — a mistyped option must be an ERROR, never a mode change).
5229
+ const allowedFlags = new Set(['context-only', 'strict', 'json', 'help']);
5230
+ const allowedOptions = new Set(['slug', 'findings', 'author']);
5231
+ for (const flag of flags)
5232
+ if (!allowedFlags.has(flag))
5233
+ return errOut(`unknown option --${flag}`);
5234
+ for (const key of options.keys()) {
5235
+ if (key.startsWith('_positional_'))
5236
+ return errOut(`unexpected argument "${options.get(key)}"`);
5237
+ if (!allowedOptions.has(key))
5238
+ return errOut(`unknown option --${key}`);
5239
+ }
5240
+ const slug = options.get('slug');
5241
+ if (slug === undefined || slug.trim() === '')
5242
+ return errOut('pass --slug <slug> (the feature under features/<slug>)');
5243
+ // Slug convention is a SECURITY boundary here (delivery finding, CONFIRMED traversal reproducer:
5244
+ // --slug '../../outside/evil' wrote 10_delivery_review.md outside the repo). kebab-case Latin,
5245
+ // <=40 chars — the repo's own slug rule as a layer-1 three-line check.
5246
+ const slugTrimmed = slug.trim();
5247
+ if (!/^[a-z0-9]+(-[a-z0-9]+)*$/.test(slugTrimmed) || slugTrimmed.length > 40) {
5248
+ return errOut(`invalid --slug "${slugTrimmed}" — kebab-case Latin, max 40 chars (a path-like slug would redirect the report write)`);
5249
+ }
5250
+ const featureDir = join(repoRoot, 'features', slugTrimmed);
5251
+ // --context-only is a real mode flag, not decoration: combining it with --findings contradicts
5252
+ // itself (delivery finding — the flag was accepted and silently ignored).
5253
+ if (flags.has('context-only') && options.get('findings') !== undefined) {
5254
+ return errOut('--context-only and --findings are mutually exclusive (context-only prints the brief; findings classifies the verdict)');
5255
+ }
5256
+ // git status --porcelain — CLI layer only (the `no child_process in core` contract); a non-git target
5257
+ // degrades to an empty list, which is honest (AM-10: changed-files is informational, never a required gate).
5258
+ let changedFiles = [];
5259
+ try {
5260
+ const out = execSync('git status --porcelain', { cwd: repoRoot, encoding: 'utf-8', stdio: ['ignore', 'pipe', 'ignore'] });
5261
+ changedFiles = out.split('\n').map((l) => l.slice(3).trim()).filter((s) => s.length > 0);
5262
+ }
5263
+ catch { /* non-git / unavailable → empty (honest) */ }
5264
+ const facts = collectDeliveryFacts(featureDir, { changedFiles, repoRoot });
5265
+ const plan = planDeliveryCheck(facts);
5266
+ const author = options.get('author');
5267
+ const findingsPath = options.get('findings');
5268
+ if (findingsPath === undefined) {
5269
+ // Default / --context-only: emit the led protocol (probes + brief). No verdict — the CLI has no model.
5270
+ if (json) {
5271
+ write(JSON.stringify({
5272
+ planesChecked: [],
5273
+ planesSkipped: plan.planes.map((p) => p.id),
5274
+ findings: [],
5275
+ handoff: null,
5276
+ artifact: 'not-written',
5277
+ probes: plan.probes,
5278
+ }, null, 2));
5279
+ return 0;
5280
+ }
5281
+ write(`dz delivery-check — ${slug} (portable 4-plane hand-off protocol; you drive the review)`);
5282
+ for (const p of plan.probes) {
5283
+ const mark = p.passed === true ? '✓' : p.passed === false ? '✗' : '○';
5284
+ write(` ${mark} ${p.description}${p.required ? ' [required]' : ' [informational]'}`);
5285
+ }
5286
+ write('');
5287
+ write(renderDeliveryBrief(plan, facts));
5288
+ // The hand-off criterion the verdict will be judged by, shown UP FRONT (this also makes
5289
+ // plan.criterionTemplate a consumed surface, not dead product code — delivery finding).
5290
+ write('\n── hand-off criterion (all must PASS for ready) ──');
5291
+ for (const c of plan.criterionTemplate)
5292
+ write(` ○ ${c.label}`);
5293
+ if (author !== undefined && author.trim() !== '')
5294
+ write(`\n── reviewer to dispatch ──\n${author.trim()}`);
5295
+ write('\n(next: run the four planes, then `dz delivery-check --slug ' + slug + ' --findings findings.json` for the verdict)');
5296
+ return 0;
5297
+ }
5298
+ // --findings mode: parse (malformed/missing ⇒ [], a failed-plane input — fail-closed, never a throw).
5299
+ let reviewResults = [];
5300
+ try {
5301
+ const parsed = JSON.parse(readFileSync(resolve(cwd, findingsPath), 'utf-8'));
5302
+ if (Array.isArray(parsed))
5303
+ reviewResults = parsed;
5304
+ else if (parsed !== null && typeof parsed === 'object' && Array.isArray(parsed.planes))
5305
+ reviewResults = parsed.planes;
5306
+ else
5307
+ reviewResults = [];
5308
+ }
5309
+ catch {
5310
+ reviewResults = [];
5311
+ }
5312
+ const verdict = classifyDelivery(plan, reviewResults);
5313
+ // The SAME predicate as the fail-closed verdict (core-exported) — a local copy was a drift channel.
5314
+ const planesChecked = plan.planes.filter((_, i) => isUsablePlaneResult(reviewResults[i])).map((p) => p.id);
5315
+ const planesSkipped = plan.planes.filter((_, i) => !isUsablePlaneResult(reviewResults[i])).map((p) => p.id);
5316
+ // Write the regenerable report (NOT augment-never-clobber — deliberately overwritten each run).
5317
+ let artifact = 'not-written';
5318
+ try {
5319
+ const reviewPath = join(featureDir, '10_delivery_review.md');
5320
+ mkdirSync(dirname(reviewPath), { recursive: true });
5321
+ writeFileSync(reviewPath, renderDeliveryReview(verdict, facts));
5322
+ artifact = 'written';
5323
+ }
5324
+ catch { /* best-effort — the verdict is still returned */ }
5325
+ if (json) {
5326
+ write(JSON.stringify({ planesChecked, planesSkipped, findings: verdict.findings, handoff: verdict.handoff, artifact }, null, 2));
5327
+ }
5328
+ else {
5329
+ write(`dz delivery-check — ${slug}: ${verdict.handoff}`);
5330
+ for (const c of verdict.criterion) {
5331
+ const mark = c.status === 'PASS' ? '✓' : c.status === 'FAIL' ? '✗' : '○';
5332
+ write(` ${mark} ${c.label}: ${c.status}${c.detail ? ` — ${c.detail}` : ''}`);
5333
+ }
5334
+ write(artifact === 'written' ? `\n↳ wrote features/${slug}/10_delivery_review.md` : '\n↳ 10_delivery_review.md NOT written (verdict above is authoritative)');
5335
+ }
5336
+ if (flags.has('strict') && verdict.handoff === 'blocked')
5337
+ return 1;
5338
+ return 0;
5339
+ }
5185
5340
  /**
5186
5341
  * `dz routing` — inspect the learned cost-optimal routing outcome store (feature learned-cost-routing). Shows
5187
5342
  * what `args.models[stage]='auto-cost'` currently believes per (stage, complexity-tier, model): gated
@@ -5619,6 +5774,8 @@ export async function runCli(argv, io = {}) {
5619
5774
  return cmdChallenge(options, flags, cwd, write);
5620
5775
  case 'discrimination-check':
5621
5776
  return cmdDiscriminationCheck(options, flags, cwd, write);
5777
+ case 'delivery-check':
5778
+ return cmdDeliveryCheck(options, flags, cwd, write);
5622
5779
  case 'routing':
5623
5780
  return cmdRouting(options, flags, cwd, write);
5624
5781
  case 'bto-optimize':