{"record":{"id":"f94ce52406c37935","repo":"stablyai/orca","slug":"targeted-update-changed-the-non-targeted-control-p","errorCode":null,"errorMessage":"Targeted update changed the non-targeted control provider placement","messagePattern":"Targeted update changed the non-targeted control provider placement","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"config/scripts/verify-skill-update-roundtrip.mjs","lineNumber":241,"sourceCode":"    targetProviderAfter !== currentSkill(targetName).packageDigest\n  ) {\n    throw new Error('Independent provider copy changed to an unexpected package identity')\n  }\n  if (shape === 'copy') {\n    // Why: hosted 1.5.17 replaces copies with aliases while equivalent local runs\n    // retain the copy. Both prove this input topology must remain ineligible.\n    const outcome = targetProviderStat.isSymbolicLink()\n      ? 'converged to an alias'\n      : targetProviderAfter === targetProviderBefore\n        ? 'remained a historical copy'\n        : 'converged as a copy'\n    console.log(`[skill-update-roundtrip] independent copy ${outcome}`)\n  }\n  if ((await packageDigestAt(controlCanonical)) !== controlBefore) {\n    throw new Error('Targeted update changed the non-targeted control skill')\n  }\n  if ((await packageDigestAt(await realpath(controlProvider))) !== controlProviderBefore) {\n    throw new Error('Targeted update changed the non-targeted control provider placement')\n  }\n  const controlProviderStat = await lstat(controlProvider)\n  if (shape === 'symlink' && !controlProviderStat.isSymbolicLink()) {\n    throw new Error('Targeted update changed the non-targeted control topology')\n  }\n} finally {\n  await rm(sandbox, { recursive: true, force: true })\n}\n","sourceCodeStart":223,"sourceCodeEnd":250,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/config/scripts/verify-skill-update-roundtrip.mjs#L223-L250","documentation":"Companion to 293: a targeted update must not change the control skill's provider placement either. The script hashes realpath(controlProvider) after the update and compares to controlProviderBefore; a mismatch means the targeted update rewrote the control provider placement it should have left alone.","triggerScenarios":"Same scoping regression as 293 but manifesting at the provider (vendor) placement rather than the canonical skill dir; the control provider symlink got repointed; the control provider copy got its content rewritten.","commonSituations":"CLI regression updating all provider placements instead of just the target's; lock fixture not pinning the control provider; symlink repoint side effect of a global update.","solutions":["Confirm the control provider placement is pinned in the lock fixture so it isn't eligible for update.","Diff the control provider content/symlink target before and after.","File a CLI bug: targeted updates must not touch non-target provider placements.","Pin a known-good CLI version."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Mirror of 293 for the provider placement:\nconst controlProviderBefore = await packageDigestAt(await realpath(controlProvider))\n// ... after update:\nif ((await packageDigestAt(await realpath(controlProvider))) !== controlProviderBefore) {\n  throw new Error('control provider placement drifted')\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Pin the control provider in the lock fixture so it isn't eligible for update.","File a CLI bug whenever a targeted update modifies a non-target provider placement.","Pin a CLI version with correctly-scoped targeted updates."],"tags":["skill-update","targeted-update","isolation","provider-placement","regression-detection"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}