{
  "sourceKind": "separate production-editor working copy; not a public GitHub commit",
  "reviewedAt": "2026-10-22",
  "excerpts": [
    {
      "file": "app/studio/selection-tools.ts",
      "start": 3,
      "end": 5,
      "code": "export type SelectionOperation='replace'|'add'|'subtract'|'intersect';\nexport function combineSelection(a:PixelSelection|undefined,b:PixelSelection,op:SelectionOperation):PixelSelection{if(!a||op==='replace')return b;if(a.width!==b.width||a.height!==b.height)throw Error('Selection size mismatch.');return {...b,alpha:b.alpha.map((v,i)=>op==='add'?Math.max(a.alpha[i],v):op==='subtract'?Math.max(0,a.alpha[i]-v):Math.min(a.alpha[i],v))};}\nexport function shapeSelection(w:number,h:number,points:Point[],ellipse=false,feather=0):PixelSelection{const c=surface(w,h),g=c.getContext('2d')!;g.fillStyle='#fff';g.beginPath();if(ellipse&&points.length>=2){const [a,b]=points;g.ellipse((a.x+b.x)/2,(a.y+b.y)/2,Math.abs(b.x-a.x)/2,Math.abs(b.y-a.y)/2,0,0,Math.PI*2);}else{points.forEach((p,i)=>i?g.lineTo(p.x,p.y):g.moveTo(p.x,p.y));g.closePath();}g.fill();const p=g.getImageData(0,0,w,h).data;let s={width:w,height:h,alpha:Array.from({length:w*h},(_,i)=>p[i*4+3])};if(feather)s=modifySelection(s,'feather',feather);return s;}",
      "ref": "working-copy-2026-10-22",
      "sha256": "83db06829467346b6c1e296311169fb384112e225c22ac7f50351aa674e0f9ac"
    },
    {
      "file": "app/studio/selection-mask.ts",
      "start": 3,
      "end": 5,
      "code": "export function refineSelection(alpha:Uint8Array,w:number,h:number,feather:number){const c=surface(w,h),g=c.getContext('2d')!,im=g.createImageData(w,h);for(let i=0;i<alpha.length;i++){im.data[i*4]=im.data[i*4+1]=im.data[i*4+2]=255;im.data[i*4+3]=alpha[i];}g.putImageData(im,0,0);if(feather>0){const out=surface(w,h),ctx=out.getContext('2d')!;ctx.filter=`blur(${feather}px)`;ctx.drawImage(c,0,0);return out;}return c;}\nexport function selectionMask(alpha:Uint8Array,w:number,h:number,width:number,height:number,feather:number,existing?:LayerMask):LayerMask{const c=refineSelection(alpha,w,h,feather),g=c.getContext('2d')!;if(existing?.enabled){g.globalCompositeOperation='destination-in';g.drawImage(maskSurface(existing,w,h),0,0);}\n const data=g.getImageData(0,0,w,h).data;return{width,height,enabled:true,inverted:false,strokes:[],raster:{width:w,height:h,alpha:Array.from({length:w*h},(_,i)=>data[i*4+3])}};}",
      "ref": "working-copy-2026-10-22",
      "sha256": "7a08d70ef013116fa335861733a5647c318dd94a8a868008a877efbbebc3a203"
    },
    {
      "file": "app/studio/channel-operations.ts",
      "start": 13,
      "end": 18,
      "code": "export function mixChannel(a:number,b:number,o:ChannelMix){\n let v=o.blend==='add'?(a+b)/o.scale+o.offset:o.blend==='subtract'?(a-b)/o.scale+o.offset:blendRGB([a/255,a/255,a/255],[b/255,b/255,b/255],o.blend as BlendMode,[0,0,0])[0]*255;\n v=Math.max(0,Math.min(255,v));return a*(1-o.opacity)+v*o.opacity;\n}\nfunction validateMix(o:ChannelMix){if(!channelBlendNames.includes(o.blend)||!Number.isFinite(o.opacity)||o.opacity<0||o.opacity>1||!Number.isFinite(o.scale)||o.scale<1||o.scale>2||!Number.isFinite(o.offset)||o.offset< -255||o.offset>255)throw Error('Invalid channel blending settings.');}\nexport const componentNames=(doc:StudioDoc)=>doc.precision?.space==='CMYK'?['Cyan','Magenta','Yellow','Black']:doc.precision?.space==='Lab'?['Lightness','a','b']:doc.precision?.space==='Gray'?['Gray']:['Red','Green','Blue'];",
      "ref": "working-copy-2026-10-22",
      "sha256": "b3df72a570fa30b34c6ff3d5cadaf15cad236f9462e63a87149d81200acb96c4"
    },
    {
      "file": "app/studio/psd-paths.ts",
      "start": 12,
      "end": 16,
      "code": "export function readPsdPaths(bytes:Uint8Array,width:number,height:number):WorkPath[]{\n const output:WorkPath[]=[];for(const block of resourceBlocks(bytes)){if(!(block.id>=2000&&block.id<=2997||block.id===1025))continue;if(output.length>=100)throw Error('PSD contains more than 100 saved paths.');const data=block.data;if(data.length%26)throw Error('Invalid Photoshop path resource length.');const v=new DataView(data.buffer,data.byteOffset,data.byteLength),paths:PathShape[]=[];let path:PathShape|undefined,count=0;\n for(let at=0;at<data.length;at+=26){const selector=v.getUint16(at);if(selector===0||selector===3){if(path&&path.knots.length!==count)throw Error('Incomplete Photoshop path.');count=v.getUint16(at+2);path={open:selector===3,operation:operations[v.getInt16(at+4)]??'exclude',fillRule:v.getUint16(at+6)===2?'non-zero':'even-odd',knots:[]};paths.push(path);}else if([1,2,4,5].includes(selector)){if(!path||path.knots.length>=count)throw Error('Unexpected Photoshop path anchor.');const points:number[]=[];for(const j of [2,1,0])points.push(v.getInt32(at+6+j*8)/16777216*width,v.getInt32(at+2+j*8)/16777216*height);path.knots.push({linked:selector===1||selector===4,points});}else if(![6,7,8].includes(selector))throw Error('Unsupported Photoshop path record.');}\n if(path&&path.knots.length!==count)throw Error('Incomplete Photoshop path.');const nameBytes=bytes.subarray(block.start+7,block.start+7+bytes[block.start+6]);let name:string;try{name=new TextDecoder('utf-8',{fatal:true}).decode(nameBytes);}catch{try{name=new TextDecoder('euc-kr',{fatal:true}).decode(nameBytes);}catch{name=new TextDecoder('windows-1252').decode(nameBytes);}}output.push({id:uid(),name:name||'Work Path',paths});}\n validatePaths(output);return output;",
      "ref": "working-copy-2026-10-22",
      "sha256": "608cd40466ce1edabb96356f98cdfbb1a35363d32bb41a3afdce8df0b8fd55be"
    }
  ],
  "productionUI": {
    "date": "2026-10-22",
    "passed": true,
    "route": "UI rectangular selection, save/load channel, mask, project reopen",
    "selectionFeather": 12,
    "savedChannel": "Portrait window",
    "dimensions": [
      1536,
      1024
    ],
    "savedSelectionExactMatch": true,
    "maskExactMatch": true,
    "maskAlphaLevels": 256,
    "maskAlphaSha256": "6ab5f95e9bc43a781ae1f55cc1d962d2cb3202eae8221991df1ed074ef2f64db",
    "freshSpotOrAdobeTest": false
  },
  "historicalReports": [
    {
      "file": "spot-channels-render-results.json",
      "sha256": "34a9b9c56f4beb1b22caa19eb4d6484446296111e8a4badc7c8f5e3c87b7e225",
      "results": {
        "passed": true,
        "checks": [
          {
            "kind": "spot-native",
            "depth": 8,
            "psb": false,
            "channels": [
              "별색 Orange",
              "Regular Alpha",
              "Spot Green"
            ]
          },
          {
            "kind": "spot-native",
            "depth": 8,
            "psb": true,
            "channels": [
              "별색 Orange",
              "Regular Alpha",
              "Spot Green"
            ]
          },
          {
            "kind": "spot-native",
            "depth": 16,
            "psb": false,
            "channels": [
              "별색 Orange",
              "Regular Alpha",
              "Spot Green"
            ]
          },
          {
            "kind": "spot-native",
            "depth": 16,
            "psb": true,
            "channels": [
              "별색 Orange",
              "Regular Alpha",
              "Spot Green"
            ]
          },
          {
            "kind": "spot-native-transparent",
            "depth": 8,
            "psb": false,
            "channels": [
              "별색 Orange",
              "Regular Alpha",
              "Spot Green"
            ]
          },
          {
            "kind": "spot-native-transparent",
            "depth": 8,
            "psb": true,
            "channels": [
              "별색 Orange",
              "Regular Alpha",
              "Spot Green"
            ]
          },
          {
            "kind": "spot-native-transparent",
            "depth": 16,
            "psb": false,
            "channels": [
              "별색 Orange",
              "Regular Alpha",
              "Spot Green"
            ]
          },
          {
            "kind": "spot-native-transparent",
            "depth": 16,
            "psb": true,
            "channels": [
              "별색 Orange",
              "Regular Alpha",
              "Spot Green"
            ]
          }
        ]
      },
      "freshRun": false
    },
    {
      "file": "spot-channels-native-results.json",
      "sha256": "829c57a4027880b092b4b062de7b35e1894e398da0784a95d686d3e1ab8bb253",
      "results": {
        "passed": true,
        "checks": [
          {
            "file": "spot-native-edited-8.psd",
            "inkCoverage": "exact",
            "alphaSelection": "exact",
            "color": "exact",
            "solidity": "exact"
          },
          {
            "file": "spot-native-edited-8.psb",
            "inkCoverage": "exact",
            "alphaSelection": "exact",
            "color": "exact",
            "solidity": "exact"
          },
          {
            "file": "spot-native-edited-16.psd",
            "inkCoverage": "exact",
            "alphaSelection": "exact",
            "color": "exact",
            "solidity": "exact"
          },
          {
            "file": "spot-native-edited-16.psb",
            "inkCoverage": "exact",
            "alphaSelection": "exact",
            "color": "exact",
            "solidity": "exact"
          },
          {
            "file": "spot-native-transparent-edited-8.psd",
            "inkCoverage": "exact",
            "alphaSelection": "exact",
            "color": "exact",
            "solidity": "exact"
          },
          {
            "file": "spot-native-transparent-edited-8.psb",
            "inkCoverage": "exact",
            "alphaSelection": "exact",
            "color": "exact",
            "solidity": "exact"
          },
          {
            "file": "spot-native-transparent-edited-16.psd",
            "inkCoverage": "exact",
            "alphaSelection": "exact",
            "color": "exact",
            "solidity": "exact"
          },
          {
            "file": "spot-native-transparent-edited-16.psb",
            "inkCoverage": "exact",
            "alphaSelection": "exact",
            "color": "exact",
            "solidity": "exact"
          }
        ]
      },
      "freshRun": false
    }
  ]
}