{"record":{"id":"cf442dbc340b0c2a","repo":"stablyai/orca","slug":"independent-provider-copy-changed-to-an-unexpected","errorCode":null,"errorMessage":"Independent provider copy changed to an unexpected package identity","messagePattern":"Independent provider copy changed to an unexpected package identity","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"config/scripts/verify-skill-update-roundtrip.mjs","lineNumber":225,"sourceCode":"\n  // Why: this is the exact user-visible rail. A bare update would include\n  // unrelated vendors, while this command must leave the control skill alone.\n  execSkills(['update', targetName, '--global'])\n  await assertCurrentCanonical(targetName)\n  const targetProviderAfter = await packageDigestAt(await realpath(targetProvider))\n  const targetProviderStat = await lstat(targetProvider)\n  if (shape === 'symlink' && !targetProviderStat.isSymbolicLink()) {\n    throw new Error(`${targetName} provider alias was replaced with an independent copy`)\n  }\n  if (shape === 'symlink' && targetProviderAfter !== currentSkill(targetName).packageDigest) {\n    throw new Error(`${targetName} provider alias did not converge with the canonical update`)\n  }\n  if (\n    shape === 'copy' &&\n    targetProviderAfter !== targetProviderBefore &&\n    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)","sourceCodeStart":207,"sourceCodeEnd":243,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/config/scripts/verify-skill-update-roundtrip.mjs#L207-L243","documentation":"In copy shape, the script requires the target provider digest after update to be EITHER unchanged (targetProviderAfter === targetProviderBefore, i.e. the historical copy was left alone) OR equal to the current canonical digest (converged). Any third value — changed to something that is neither the original nor the current canonical — is an unexpected identity drift and throws.","triggerScenarios":"The update partially overwrote the copy with content from a third version; a file in the copy was mutated by a side effect; the canonical digest changed mid-run; line-ending or mode normalization produced a hash that matches neither baseline.","commonSituations":"autocrlf mismatch rewriting the copy's line endings so the hash drifts; concurrent process modifying files in the sandbox; CLI regression that writes a different version than currentSkill declares into a copy-topology placement.","solutions":["Confirm autocrlf is set as declared (false avoids drift) and that no external process touches the sandbox.","Diff the provider copy before/after to identify which files changed and why.","Verify currentSkill(targetName).packageDigest matches the actual published package the CLI downloads.","If the CLI wrote the wrong version, file a bug and pin a known-good CLI version."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Before the update, record the baseline digest and the canonical digest:\nconst targetProviderBefore = await packageDigestAt(targetProvider)\nconst canonicalDigest = currentSkill(targetName).packageDigest\n// The only acceptable post-update values are these two; anything else is drift.\n// Surface both in the failure message to speed diagnosis:\nif (targetProviderAfter !== targetProviderBefore && targetProviderAfter !== canonicalDigest) {\n  throw new Error(`Identity drift: after=${targetProviderAfter} before=${targetProviderBefore} canonical=${canonicalDigest}`)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Run with --autocrlf=false so line-ending normalization can't fabricate a third digest.","Ensure no other process writes to the sandbox during the run.","Keep the manifest's packageDigest in sync with the published package."],"tags":["skill-update","digest","copy-topology","line-endings","regression-detection"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}