wicked-crew 0.9.1 → 0.9.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.
Files changed (79) hide show
  1. package/dist/api/codebase-archive.d.ts +14 -0
  2. package/dist/api/codebase-archive.d.ts.map +1 -1
  3. package/dist/api/codebase-archive.js +18 -1
  4. package/dist/api/codebase-archive.js.map +1 -1
  5. package/dist/api/delivery-assurance.d.ts +22 -1
  6. package/dist/api/delivery-assurance.d.ts.map +1 -1
  7. package/dist/api/delivery-assurance.js +66 -2
  8. package/dist/api/delivery-assurance.js.map +1 -1
  9. package/dist/api/routes.d.ts +148 -8
  10. package/dist/api/routes.d.ts.map +1 -1
  11. package/dist/api/routes.js +70 -21
  12. package/dist/api/routes.js.map +1 -1
  13. package/dist/api/server.d.ts.map +1 -1
  14. package/dist/api/server.js +62 -37
  15. package/dist/api/server.js.map +1 -1
  16. package/dist/cli/index.d.ts.map +1 -1
  17. package/dist/cli/index.js +32 -1
  18. package/dist/cli/index.js.map +1 -1
  19. package/dist/cli/service.js +1 -1
  20. package/dist/cli/service.js.map +1 -1
  21. package/dist/core/adapter.d.ts +16 -3
  22. package/dist/core/adapter.d.ts.map +1 -1
  23. package/dist/core/adapter.js +70 -28
  24. package/dist/core/adapter.js.map +1 -1
  25. package/dist/core/ado-deliver-helper.d.ts +5 -0
  26. package/dist/core/ado-deliver-helper.d.ts.map +1 -1
  27. package/dist/core/ado-deliver-helper.js +50 -2
  28. package/dist/core/ado-deliver-helper.js.map +1 -1
  29. package/dist/core/deliver-credentials.d.ts +8 -4
  30. package/dist/core/deliver-credentials.d.ts.map +1 -1
  31. package/dist/core/deliver-credentials.js +25 -7
  32. package/dist/core/deliver-credentials.js.map +1 -1
  33. package/dist/core/deliver-text.d.ts +8 -0
  34. package/dist/core/deliver-text.d.ts.map +1 -1
  35. package/dist/core/deliver-text.js +16 -0
  36. package/dist/core/deliver-text.js.map +1 -1
  37. package/dist/core/deliver.d.ts +22 -18
  38. package/dist/core/deliver.d.ts.map +1 -1
  39. package/dist/core/deliver.js +168 -79
  40. package/dist/core/deliver.js.map +1 -1
  41. package/dist/core/types.d.ts +7 -0
  42. package/dist/core/types.d.ts.map +1 -1
  43. package/dist/core/types.js.map +1 -1
  44. package/dist/interactive/chat-events.d.ts +11 -20
  45. package/dist/interactive/chat-events.d.ts.map +1 -1
  46. package/dist/interactive/chat-events.js +69 -108
  47. package/dist/interactive/chat-events.js.map +1 -1
  48. package/dist/interactive/draft-events.d.ts +13 -46
  49. package/dist/interactive/draft-events.d.ts.map +1 -1
  50. package/dist/interactive/draft-events.js +81 -130
  51. package/dist/interactive/draft-events.js.map +1 -1
  52. package/dist/interactive/draft-skill.d.ts +11 -19
  53. package/dist/interactive/draft-skill.d.ts.map +1 -1
  54. package/dist/interactive/draft-skill.js +16 -31
  55. package/dist/interactive/draft-skill.js.map +1 -1
  56. package/dist/interactive/edit-events.d.ts +11 -21
  57. package/dist/interactive/edit-events.d.ts.map +1 -1
  58. package/dist/interactive/edit-events.js +70 -83
  59. package/dist/interactive/edit-events.js.map +1 -1
  60. package/dist/interactive/run-units.d.ts +91 -0
  61. package/dist/interactive/run-units.d.ts.map +1 -0
  62. package/dist/interactive/run-units.js +149 -0
  63. package/dist/interactive/run-units.js.map +1 -0
  64. package/dist/skills/core-closure.d.ts +26 -0
  65. package/dist/skills/core-closure.d.ts.map +1 -1
  66. package/dist/skills/core-closure.js +45 -0
  67. package/dist/skills/core-closure.js.map +1 -1
  68. package/dist/skills/phase-skill-gaps.d.ts +16 -71
  69. package/dist/skills/phase-skill-gaps.d.ts.map +1 -1
  70. package/dist/skills/phase-skill-gaps.js +16 -145
  71. package/dist/skills/phase-skill-gaps.js.map +1 -1
  72. package/dist/studio/assets/{index-BLYKfepE.css → index-BGfFmWw4.css} +1 -1
  73. package/dist/studio/assets/{index-BbXtfDnB.js → index-BMRUMU4X.js} +112 -112
  74. package/dist/studio/editors/wicked-page/editor.json +1 -1
  75. package/dist/studio/editors/wicked-page/index.html +1 -1
  76. package/dist/studio/index.html +2 -2
  77. package/dist/studio/testid-inventory.json +83 -5
  78. package/endpoint-manifest.json +1 -1
  79. package/package.json +3 -3
@@ -11,7 +11,7 @@ import { randomUUID } from 'node:crypto';
11
11
  import { DEFAULT_SETTINGS } from './types.js';
12
12
  import { BASE_SKILL_REF_SHAPE } from '../skills/base-skill.js';
13
13
  import { execCapped } from './exec.js';
14
- import { BUG_FIX_SWEEP_INSTRUCTIONS, composeDeliverWorkflow, DELIVER_PHASE_ID, deliverPresetStep, deliverIdentityFor, deliverRepoFor, EVIDENCE_FLOOR_PIN, ghSignedInLogins, isGitHubLogin, readDeliverOriginUrl } from './deliver.js';
14
+ import { BUG_FIX_SWEEP_INSTRUCTIONS, composeDeliverWorkflow, DELIVER_PHASE_ID, deliverPresetStep, deliverIdentityFor, deliverRepoFor, EVIDENCE_FLOOR_PIN, isGitHubLogin, pushIdentityOf, readDeliverOriginUrl } from './deliver.js';
15
15
  import { engineCampaignDef, engineRosterJson } from './engine-roster.js';
16
16
  import { QE_AUTHOR_TESTS_WORKFLOW_DEF } from '../qe/author-workflow.js';
17
17
  import { CAMPAIGN_WORKFLOW_PREFIX } from '../campaigns/plan.js';
@@ -349,11 +349,22 @@ function addonSupportsExtraWriteRoots() {
349
349
  function addonSupportsExcludeSeats() {
350
350
  return addonAtLeast(0, 7, 35);
351
351
  }
352
+ /** Does the installed addon judge a plan or preset launch's declared deliverables
353
+ * (`LaunchOptions.deliverables`, wicked-core#858, >= 0.7.48)? Same doctrine: an older addon
354
+ * ignores the field, and the run would never be held to its deliverable. */
355
+ export function addonSupportsLaunchDeliverables() {
356
+ return addonAtLeast(0, 7, 48);
357
+ }
352
358
  /** Does the installed addon carry the assurance contract (`LaunchOptions.reducedAssurance`,
353
359
  * wicked-core#850, >= 0.7.46)? Same doctrine. */
354
360
  export function addonSupportsReducedAssurance() {
355
361
  return addonAtLeast(0, 7, 46);
356
362
  }
363
+ /** Does the installed addon carry the QE acceptance decision (`LaunchOptions.skipQeAcceptanceReason`
364
+ * / `forceQeAcceptance`, `assurance.qe`; QE-IN-APP-WORKFLOWS, >= 0.7.49)? Same doctrine. */
365
+ export function addonSupportsQeOverride() {
366
+ return addonAtLeast(0, 7, 49);
367
+ }
357
368
  /**
358
369
  * Does the installed addon understand `LaunchOptions.projectGraph` (≥ 0.7.1)?
359
370
  *
@@ -457,6 +468,10 @@ const CORE_SEEDED_WORKFLOWS = new Set(['feature', 'bug', 'migration']);
457
468
  // (see CORE_SEEDED_WORKFLOWS).
458
469
  // `is_system` is NOT spelled on these defs: `withSystemFlag` stamps it from `SYSTEM_WORKFLOWS`
459
470
  // (core/run-identity.ts), the one list keyed by name that also classifies served runs (seam X2).
471
+ /** QE-IN-APP-WORKFLOWS (operator ruling 2026-10-10): what a workflow that makes application changes
472
+ * requires — the defaults plus `qe_acceptance` — exactly as core's `feature`/`bug`/`migration`/
473
+ * `mcp-server` defs declare it (the mirror guards compare field for field). */
474
+ const APP_CHANGE_INSTRUMENTS = ['distinct_evaluator', 'judge', 'qe_acceptance'];
460
475
  export const BUILTIN_WORKFLOWS = [
461
476
  {
462
477
  id: 'feature',
@@ -468,6 +483,7 @@ export const BUILTIN_WORKFLOWS = [
468
483
  { id: 'test', kind: 'test', gate_type: 'execution', gate: { human_confirm_if: 'verdict_not_pass' }, executes_code: false, verified_evidence: true, required_deliverables: [], depends_on: ['build'], role: 'neutral', skill_ref: null, allowed_skills: [], validator_pin: EVIDENCE_FLOOR_PIN },
469
484
  { id: 'review', kind: 'review', gate_type: 'execution', gate: 'auto', executes_code: false, verified_evidence: false, required_deliverables: [], depends_on: ['test'], role: 'neutral', skill_ref: null, allowed_skills: [], validator_pin: null },
470
485
  ],
486
+ required_instruments: APP_CHANGE_INSTRUMENTS,
471
487
  },
472
488
  {
473
489
  id: 'bug',
@@ -480,6 +496,7 @@ export const BUILTIN_WORKFLOWS = [
480
496
  { id: 'fix', kind: 'build', instructions: BUG_FIX_SWEEP_INSTRUCTIONS, gate_type: 'execution', gate: 'auto', executes_code: true, verified_evidence: false, required_deliverables: [], depends_on: ['reproduce'], role: 'creator', skill_ref: null, allowed_skills: [], validator_pin: EVIDENCE_FLOOR_PIN },
481
497
  { id: 'verify', kind: 'test', gate_type: 'execution', gate: { human_confirm_if: 'verdict_not_pass' }, executes_code: false, verified_evidence: true, required_deliverables: [], depends_on: ['fix'], role: 'evaluator', skill_ref: null, allowed_skills: [], validator_pin: EVIDENCE_FLOOR_PIN },
482
498
  ],
499
+ required_instruments: APP_CHANGE_INSTRUMENTS,
483
500
  },
484
501
  {
485
502
  id: 'migration',
@@ -490,6 +507,7 @@ export const BUILTIN_WORKFLOWS = [
490
507
  { id: 'verify', kind: 'test', gate_type: 'execution', gate: { human_confirm_if: 'verdict_not_pass' }, executes_code: false, verified_evidence: true, required_deliverables: [], depends_on: ['cutover'], role: 'evaluator', skill_ref: null, allowed_skills: [], validator_pin: EVIDENCE_FLOOR_PIN },
491
508
  { id: 'cleanup', kind: 'build', gate_type: null, gate: 'auto', executes_code: false, verified_evidence: false, required_deliverables: [], depends_on: ['verify'], role: 'neutral', skill_ref: null, allowed_skills: [], validator_pin: null },
492
509
  ],
510
+ required_instruments: APP_CHANGE_INSTRUMENTS,
493
511
  },
494
512
  {
495
513
  // capture-learnings (DES-MEM-FACETED-001 write side, onboarding): survey a just-indexed repo,
@@ -646,6 +664,7 @@ export const BUILTIN_WORKFLOWS = [
646
664
  { id: "install-plan", kind: "build", gate_type: "execution", gate: "auto", executes_code: false, verified_evidence: false, required_deliverables: [], depends_on: ["security-review", "observability-review"], role: "neutral", skill_ref: null, allowed_skills: [], validator_pin: null, executor: { "type": "tool", "cmd": ["bash", "-c", "exec \"${WICKED_GARDEN_ROOT:?the engine handed this Tool phase no garden root; refusing to resolve wicked-garden from PATH}/scripts/wicked-garden\" run scripts/mcp/install.py --from-run --dry-run --json"] }, instructions: "Plan the install without writing anything: resolve, on this host and as the daemon user, every file and directory each install choice would write — Install for workers (the default: the staged copy under ~/.wicked/mcp-servers/<key>/current, the wicked-crew MCP tools registry and the worker homes' CLI configurations under ~/.wicked-worker) and Also install into my CLIs (the worker set plus your own CLI configurations, such as ~/.claude.json, ~/.codex/config.toml and the opencode configuration) — and print them as one JSON plan line, so the install's consent gate can list them before you answer." },
647
665
  { id: "install", kind: "build", gate_type: "execution", gate: "consent_before", executes_code: false, verified_evidence: false, required_deliverables: [], depends_on: ["install-plan"], role: "neutral", skill_ref: null, allowed_skills: [], validator_pin: null, executor: { "type": "tool", "cmd": ["bash", "-c", "exec \"${WICKED_GARDEN_ROOT:?the engine handed this Tool phase no garden root; refusing to resolve wicked-garden from PATH}/scripts/wicked-garden\" run scripts/mcp/install.py --from-run --target \"${WICKED_CONSENT_CHOICE:?the consent gate recorded no install choice}\" --json"] }, instructions: "Install for running — or update the installed copy when this server key is already installed. Nothing has been installed yet: this asks before the install runs, and each answer lists exactly the files it would write (from the install-plan dry run). Install for workers (the default) builds the server from this run's tree into ~/.wicked/mcp-servers/<key>/current, registers it in wicked-crew's MCP tools under its key (an existing entry is re-registered in place; the first use of a changed tool still asks) and writes it into the worker homes' CLI MCP configurations — program-owned files only. Also install into my CLIs does the same and also writes it into your own CLI MCP configurations through wicked-installer (one entry per key, never a second copy; CLI entries carry no secret). Both probe tools/list. The one secret variable <SERVER>_TOKEN is named, never written: when the daemon cannot resolve it the registration is reported as pending with the remedy. Writes happen on the daemon host as the daemon user. Decline for not now — the pull request already delivered stays as it is." },
648
666
  ],
667
+ required_instruments: APP_CHANGE_INSTRUMENTS,
649
668
  },
650
669
  ].map(withSystemFlag);
651
670
  /**
@@ -1321,18 +1340,32 @@ export class CoreAdapter {
1321
1340
  }
1322
1341
  /** Whether this engine carries the plan approval gate (DES-TEAMING-002 T3) — see
1323
1342
  * [`engineSupportsPlanLaunch`]. An instance method so a partial-stub adapter can say either. */
1343
+ /**
1344
+ * (wicked-core#858, X-MIG M9) Hand a plan or preset launch's declared deliverables to the engine
1345
+ * (`LaunchOptions.deliverables`). Fails CLOSED on an addon before the field (napi ignores it, so
1346
+ * the run would never be held to them).
1347
+ */
1348
+ passLaunchDeliverables(opts, deliverables, what) {
1349
+ if (deliverables.length === 0)
1350
+ return;
1351
+ if (!addonSupportsLaunchDeliverables()) {
1352
+ throw new Error(`requireDeliverables on ${what} needs wicked-core-ts >= 0.7.48 (LaunchOptions.deliverables, ` +
1353
+ 'wicked-core#858); the installed addon would drop them and the run would not be held to them');
1354
+ }
1355
+ opts.deliverables = deliverables;
1356
+ }
1324
1357
  supportsPlanLaunch() {
1325
1358
  return engineSupportsPlanLaunch();
1326
1359
  }
1327
1360
  /**
1328
1361
  * (crew#549, crew#737) The CONFIGURED deliver identity for a launch: the repository's own pin
1329
- * (`deliverIdentityByRepo[repoRef]`) else the daemon-wide `deliverIdentityLogin`, and — for a
1330
- * delivering launch — whether that login is signed in to gh on this machine (a bounded
1331
- * `gh auth status`). RETURNED, never stashed on the adapter: two concurrent delivering launches
1362
+ * (`deliverIdentityByRepo[repoRef]`) else the daemon-wide `deliverIdentityLogin`. Whether that
1363
+ * login has a gh token here is the credential preflight's question ({@link deliverCredentialsProbe},
1364
+ * crew#940). RETURNED, never stashed on the adapter: two concurrent delivering launches
1332
1365
  * on different repositories must not read each other's identity (the F2 origin rule). A LOGIN
1333
1366
  * only: no token is ever read here. `login: ''` ⇒ nothing configured (`GH_ACCOUNT` decides).
1334
1367
  */
1335
- async resolveDeliverIdentity(repoRef, probe) {
1368
+ async resolveDeliverIdentity(repoRef) {
1336
1369
  let login = '';
1337
1370
  let source = 'setting';
1338
1371
  try {
@@ -1343,12 +1376,7 @@ export class CoreAdapter {
1343
1376
  // failing the launch — the deliver script still cross-checks gh against git's credential.
1344
1377
  login = '';
1345
1378
  }
1346
- let signedIn = null;
1347
- if (probe && login !== '') {
1348
- const logins = await ghSignedInLogins().catch(() => null);
1349
- signedIn = logins === null ? null : logins.includes(login);
1350
- }
1351
- return { login, source, signedIn };
1379
+ return { login, source };
1352
1380
  }
1353
1381
  /**
1354
1382
  * The origin the deliver push will actually go to (F2) so the deliver GATE CARD says what will
@@ -1402,7 +1430,6 @@ export class CoreAdapter {
1402
1430
  originUrl,
1403
1431
  deliverIdentity: identity.login,
1404
1432
  deliverIdentitySource: identity.source,
1405
- deliverIdentitySignedIn: identity.signedIn,
1406
1433
  credentials,
1407
1434
  });
1408
1435
  }
@@ -1410,12 +1437,12 @@ export class CoreAdapter {
1410
1437
  async launchRun(input) {
1411
1438
  // (crew#549, crew#737) Read the configured deliver identity BEFORE anything composes the deliver
1412
1439
  // phase: the compose paths below are synchronous and bake it into the script. Launch-local.
1413
- const deliverIdentity = await this.resolveDeliverIdentity(input.repoRef, input.deliver === 'pr');
1440
+ const deliverIdentity = await this.resolveDeliverIdentity(input.repoRef);
1414
1441
  // (F2) And the origin the push would go to — read once, for the gate card's target sentence.
1415
1442
  // Only a delivering launch composes a deliver phase, so only a delivering launch pays for it.
1416
1443
  const deliverOriginUrl = input.deliver === 'pr' ? await this.resolveDeliverOrigin(input.repoRef) : null;
1417
1444
  // (crew#720) And whether the provider credential is there — presence only, read once.
1418
- const deliverCredentials = input.deliver === 'pr' ? await deliverCredentialsProbe(deliverOriginUrl, process.env) : null;
1445
+ const deliverCredentials = input.deliver === 'pr' ? await deliverCredentialsProbe(deliverOriginUrl, process.env, undefined, pushIdentityOf(deliverIdentity.login)) : null;
1419
1446
  const opts = {
1420
1447
  problem: input.problem,
1421
1448
  sessionId: input.sessionId,
@@ -1489,6 +1516,19 @@ export class CoreAdapter {
1489
1516
  }
1490
1517
  opts.reducedAssurance = true;
1491
1518
  }
1519
+ if (input.skipQeAcceptanceReason !== undefined || input.forceQeAcceptance === true) {
1520
+ // Fail CLOSED on an old addon (napi ignores undeclared fields): a dropped skip would leave a
1521
+ // run the operator meant to skip refusing its delivery, and a dropped force would let a score
1522
+ // waive what the operator required — either way the record and the run would disagree.
1523
+ if (!addonSupportsQeOverride()) {
1524
+ throw new Error('skipQeAcceptance / forceQeAcceptance need wicked-core-ts >= 0.7.49; the installed addon ' +
1525
+ 'has no QE acceptance decision to apply them to');
1526
+ }
1527
+ if (input.skipQeAcceptanceReason !== undefined)
1528
+ opts.skipQeAcceptanceReason = input.skipQeAcceptanceReason;
1529
+ if (input.forceQeAcceptance === true)
1530
+ opts.forceQeAcceptance = true;
1531
+ }
1492
1532
  // SAFETY NET (grounding follow-on #1): ANY project-filed launch that did not already resolve a
1493
1533
  // project-graph binding gets one here, so no future project-filed caller can silently ship a run
1494
1534
  // that sees only its own repo — the exact gap the chat/edit seams had (projectId filed WITHOUT
@@ -1539,13 +1579,11 @@ export class CoreAdapter {
1539
1579
  if (input.workflow !== undefined) {
1540
1580
  throw new Error('a launch carries a plan or names a workflow (a preset), not both');
1541
1581
  }
1542
- if ((input.requireDeliverables ?? []).length > 0) {
1543
- throw new Error('requireDeliverables with a plan is refused: the deliverable floor has no engine-side ' +
1544
- 'step yet — launch the plan without it');
1545
- }
1546
1582
  if (!this.supportsPlanLaunch())
1547
1583
  throw new PlanLaunchUnsupportedError('A plan launch');
1548
1584
  opts.planJson = JSON.stringify(input.plan);
1585
+ // (wicked-core#858, X-MIG M9) The engine judges a plan's declared deliverables itself.
1586
+ this.passLaunchDeliverables(opts, input.requireDeliverables ?? [], 'a plan');
1549
1587
  // T8: a delivering plan hands the engine its deliver step, exactly as a preset launch does.
1550
1588
  if (input.deliver === 'pr') {
1551
1589
  opts.deliverStepJson = JSON.stringify(this.deliverStep(null, [], input, deliverOriginUrl, deliverIdentity, deliverCredentials));
@@ -1560,14 +1598,18 @@ export class CoreAdapter {
1560
1598
  (input.deliver === 'pr' || requireDeliverablesAll.length > 0) &&
1561
1599
  (await this.presetNamed(input.workflow, input.projectId)) !== null;
1562
1600
  if (namesPreset && input.workflow !== undefined) {
1563
- if (requireDeliverablesAll.length > 0) {
1564
- throw new Error(`requireDeliverables on a preset launch ('${input.workflow}') is refused: the deliverable ` +
1565
- 'floor would have to be composed into a per-run def, which skips the plan_approval gate');
1566
- }
1567
1601
  if (!this.supportsPlanLaunch())
1568
1602
  throw new PlanLaunchUnsupportedError('Delivering a preset launch');
1569
- const step = this.deliverStep(input.workflow, this.getWorkflow(input.workflow)?.phases ?? [], input, deliverOriginUrl, deliverIdentity, deliverCredentials);
1570
- opts.deliverStepJson = JSON.stringify(step);
1603
+ // (wicked-core#858, X-MIG M9) A preset launch's deliverables ride the launch: the engine joins
1604
+ // them to the plan's last creator step and its deliverable floor judges them — never a per-run
1605
+ // def composed past the plan_approval gate.
1606
+ this.passLaunchDeliverables(opts, requireDeliverablesAll, `a preset launch ('${input.workflow}')`);
1607
+ // Only a DELIVERING preset gets the deliver step: a preset launched for its deliverables alone
1608
+ // pushes nothing (codex r1 on #930).
1609
+ if (input.deliver === 'pr') {
1610
+ const step = this.deliverStep(input.workflow, this.getWorkflow(input.workflow)?.phases ?? [], input, deliverOriginUrl, deliverIdentity, deliverCredentials);
1611
+ opts.deliverStepJson = JSON.stringify(step);
1612
+ }
1571
1613
  opts.workflow = input.workflow;
1572
1614
  }
1573
1615
  else if (input.workflow !== undefined) {
@@ -1640,7 +1682,6 @@ export class CoreAdapter {
1640
1682
  // own pin wins, and the card says when it is not signed in here.
1641
1683
  deliverIdentity: deliverIdentity.login,
1642
1684
  deliverIdentitySource: deliverIdentity.source,
1643
- deliverIdentitySignedIn: deliverIdentity.signedIn,
1644
1685
  // crew#720 — the provider credential preflight, said on the card before approval.
1645
1686
  credentials: deliverCredentials,
1646
1687
  });
@@ -1680,7 +1721,8 @@ export class CoreAdapter {
1680
1721
  // believing a PR opens at the end — the exact operator gap crew#293 closes.
1681
1722
  throw new Error('deliver: "pr" requires a workflow — a free-text run has no def to append the deliver phase to');
1682
1723
  }
1683
- else if ((input.requireDeliverables ?? []).length > 0) {
1724
+ else if ((input.requireDeliverables ?? []).length > 0 && input.plan === undefined) {
1725
+ // (A plan hands its deliverables to the engine above, wicked-core#858.)
1684
1726
  // Same rule for the floor (Copilot, #319): a caller that declares what a run MUST produce
1685
1727
  // and gets no enforcement is worse off than one that never declared it — it would watch a
1686
1728
  // free-text run complete and believe the artifacts were re-derived. There is no def to
@@ -2091,8 +2133,8 @@ export class CoreAdapter {
2091
2133
  // (F2) The preview shows the deliver step's gate-card text, so it reads the same origin the
2092
2134
  // launch would. Local to this call, like the launch's.
2093
2135
  const previewOriginUrl = opts.deliver === true ? await this.resolveDeliverOrigin(opts.repoRef) : null;
2094
- const previewIdentity = await this.resolveDeliverIdentity(opts.repoRef, opts.deliver === true);
2095
- const previewCredentials = opts.deliver === true ? await deliverCredentialsProbe(previewOriginUrl, process.env) : null;
2136
+ const previewIdentity = await this.resolveDeliverIdentity(opts.repoRef);
2137
+ const previewCredentials = opts.deliver === true ? await deliverCredentialsProbe(previewOriginUrl, process.env, undefined, pushIdentityOf(previewIdentity.login)) : null;
2096
2138
  const deliverStep = opts.deliver === true
2097
2139
  ? JSON.stringify(
2098
2140
  // The launch's own step for a plan (`deliverStep(null, [], input)`); the run id is a