release-skill 0.9.6 → 0.9.7

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.
@@ -9,9 +9,9 @@ const __bundlePkgRoot = __bundleResolve(__bundleDirname(__bundleFileURLToPath(im
9
9
  // Provide a real require() for CJS packages bundled into ESM (e.g. yaml, ajv).
10
10
  const __bundleRealRequire = __bundleCreateRequire(import.meta.url);
11
11
  // Package identity injected at build time — closure-independent --version probe.
12
- const __bundlePkg = Object.freeze({"name":"release-skill","version":"0.9.6"});
12
+ const __bundlePkg = Object.freeze({"name":"release-skill","version":"0.9.7"});
13
13
  // Build-time source digest for the BUNDLE_STALE freshness gate (see above).
14
- const __bundleSourceDigest = "8fd8e6c5f7796efe9e1f7153382b50c74d78a4b5f836f872837ff2f11e4daeb5";
14
+ const __bundleSourceDigest = "938bc6828f17e2248a4fe167bcd3353b43848ec1a494dc17dc663d390847150c";
15
15
 
16
16
  var __create = Object.create;
17
17
  var __defProp = Object.defineProperty;
@@ -109520,9 +109520,27 @@ async function checkSkillResourceClosure({
109520
109520
  result2.receiptDigest = digestDocument(receiptProjection(result2));
109521
109521
  return result2;
109522
109522
  }
109523
- function evaluateDeclaredHostSurfaceCoverage(expectedHosts, surfaces) {
109523
+ function evaluateDeclaredHostSurfaceCoverage(expectedHosts, surfaces, coverageClaims = []) {
109524
109524
  const missing = [];
109525
+ const observedById = new Map((surfaces ?? []).map((surface) => [surface.id, surface]));
109526
+ const claimsByHost = /* @__PURE__ */ new Map();
109527
+ for (const claim of coverageClaims ?? []) {
109528
+ const hostClaims = claimsByHost.get(claim.host) ?? [];
109529
+ hostClaims.push(claim);
109530
+ claimsByHost.set(claim.host, hostClaims);
109531
+ }
109525
109532
  for (const expectedHost of [...new Set(expectedHosts ?? [])].sort((a, b) => a.localeCompare(b))) {
109533
+ const declaredClaims = claimsByHost.get(expectedHost) ?? [];
109534
+ if (declaredClaims.length > 0) {
109535
+ const missingClaim = declaredClaims.find((claim) => {
109536
+ const surface3 = observedById.get(claim.surfaceId);
109537
+ return !surface3 || !(surface3.skillCount >= 1);
109538
+ });
109539
+ if (!missingClaim) continue;
109540
+ const surface2 = observedById.get(missingClaim.surfaceId);
109541
+ missing.push({ host: expectedHost, skillCount: surface2?.skillCount ?? 0 });
109542
+ continue;
109543
+ }
109526
109544
  const surface = (surfaces ?? []).find((item) => item.host === expectedHost);
109527
109545
  if (!surface || !(surface.skillCount >= 1)) {
109528
109546
  missing.push({ host: expectedHost, skillCount: surface?.skillCount ?? 0 });
@@ -112496,6 +112514,23 @@ async function deriveSurfaceHostBinding({ manifest, pluginRoot, platform, snapsh
112496
112514
  const host = await normalizeHostId(platform.buildAdapter.name);
112497
112515
  return { surfaceId, host };
112498
112516
  }
112517
+ function groupSurfaceHostBindings(claims = []) {
112518
+ if (!Array.isArray(claims)) {
112519
+ throw new TypeError("surfaceHostBindings must be an array");
112520
+ }
112521
+ const bySurface = /* @__PURE__ */ new Map();
112522
+ for (const claim of claims) {
112523
+ if (!claim || typeof claim !== "object" || typeof claim.surfaceId !== "string" || typeof claim.host !== "string") {
112524
+ throw new TypeError("surfaceHostBindings entries must be objects with string surfaceId and host");
112525
+ }
112526
+ const existing = bySurface.get(claim.surfaceId) ?? [];
112527
+ existing.push({ surfaceId: claim.surfaceId, host: claim.host });
112528
+ bySurface.set(claim.surfaceId, existing);
112529
+ }
112530
+ const coverageClaims = [...bySurface.values()].flat().sort((left, right) => left.surfaceId.localeCompare(right.surfaceId) || left.host.localeCompare(right.host));
112531
+ const checkerBindings = [...bySurface.values()].filter((surfaceClaims) => surfaceClaims.length === 1).map(([claim]) => claim).sort((left, right) => left.surfaceId.localeCompare(right.surfaceId) || left.host.localeCompare(right.host));
112532
+ return { coverageClaims, checkerBindings };
112533
+ }
112499
112534
  var SKILLS_NORMALIZERS;
112500
112535
  var init_surface_host_bindings = __esm({
112501
112536
  async "src/core/surface-host-bindings.mjs"() {
@@ -112513,6 +112548,7 @@ var init_surface_host_bindings = __esm({
112513
112548
  __name(pluginRootFromManifestRelativePath, "pluginRootFromManifestRelativePath");
112514
112549
  __name(assertDeclaredSkillsDirExists, "assertDeclaredSkillsDirExists");
112515
112550
  __name(deriveSurfaceHostBinding, "deriveSurfaceHostBinding");
112551
+ __name(groupSurfaceHostBindings, "groupSurfaceHostBindings");
112516
112552
  }
112517
112553
  });
112518
112554
 
@@ -113943,11 +113979,16 @@ async function verifyRelease(options) {
113943
113979
  const unit = (plan.units ?? []).find((u) => u.id === unitId);
113944
113980
  const dist = unit?.distributions?.find((d) => d.type === platform.distributionType);
113945
113981
  let binding = null;
113982
+ let frozenPluginRoot = null;
113946
113983
  const contract2 = dist?.installationContract;
113947
113984
  if (contract2?.normalizedManifest) {
113985
+ frozenPluginRoot = pluginRootFromManifestRelativePath(contract2.manifestRelativePath);
113948
113986
  binding = await deriveSurfaceHostBinding({
113949
113987
  manifest: contract2.normalizedManifest,
113950
- pluginRoot: pluginRootFromManifestRelativePath(contract2.manifestRelativePath),
113988
+ // Adapter observations are already rooted at the installed
113989
+ // plugin. The frozen manifest's skills path is therefore
113990
+ // relative to '.', not to the snapshot-root manifest path.
113991
+ pluginRoot: ".",
113951
113992
  platform,
113952
113993
  snapshotDir: check.observation.installPath
113953
113994
  });
@@ -113960,6 +114001,7 @@ async function verifyRelease(options) {
113960
114001
  unitId,
113961
114002
  surfaceId: binding?.surfaceId ?? ".",
113962
114003
  binding,
114004
+ frozenPluginRoot,
113963
114005
  unit
113964
114006
  });
113965
114007
  }
@@ -114042,7 +114084,7 @@ async function verifyRelease(options) {
114042
114084
  );
114043
114085
  }
114044
114086
  const pluginDistCount = (surface.unit?.distributions ?? []).filter((d) => d.type !== "npm").length;
114045
- if (pluginDistCount === 1) {
114087
+ if (pluginDistCount === 1 && surface.frozenPluginRoot === ".") {
114046
114088
  const observedReceipt = createSkillResourceClosureReceipt(closureResult, {
114047
114089
  unitId: surface.unitId,
114048
114090
  preparedAt: expectedUnitReceipt.preparedAt ?? null,
@@ -129636,10 +129678,11 @@ async function runPrepareSkillResourceClosureGate({
129636
129678
  });
129637
129679
  if (binding) surfaceHostBindings.push(binding);
129638
129680
  }
129681
+ const { checkerBindings, coverageClaims } = groupSurfaceHostBindings(surfaceHostBindings);
129639
129682
  const closureResult = await checkSkillResourceClosure({
129640
129683
  snapshotDir: manifest.outputDir,
129641
129684
  host: "root",
129642
- surfaceHostBindings
129685
+ surfaceHostBindings: checkerBindings
129643
129686
  });
129644
129687
  const receipt = createSkillResourceClosureReceipt(closureResult, {
129645
129688
  unitId: unit.id,
@@ -129684,7 +129727,8 @@ async function runPrepareSkillResourceClosureGate({
129684
129727
  }
129685
129728
  const hostCoverage = evaluateDeclaredHostSurfaceCoverage(
129686
129729
  expectedHosts,
129687
- closureResult.surfaces
129730
+ closureResult.surfaces,
129731
+ coverageClaims
129688
129732
  );
129689
129733
  if (!hostCoverage.passed) {
129690
129734
  await evidence.append({
@@ -129708,7 +129752,7 @@ async function runPrepareSkillResourceClosureGate({
129708
129752
  }
129709
129753
  );
129710
129754
  }
129711
- for (const binding of surfaceHostBindings) {
129755
+ for (const binding of coverageClaims) {
129712
129756
  const boundSurface = closureResult.surfaces.find(
129713
129757
  (surface) => surface.id === binding.surfaceId
129714
129758
  );
@@ -133318,10 +133362,11 @@ async function publishRelease(options) {
133318
133362
  });
133319
133363
  if (binding) surfaceHostBindings.push(binding);
133320
133364
  }
133365
+ const { checkerBindings, coverageClaims } = groupSurfaceHostBindings(surfaceHostBindings);
133321
133366
  const closureResult = await checkSkillResourceClosure({
133322
133367
  snapshotDir,
133323
133368
  host: "root",
133324
- surfaceHostBindings
133369
+ surfaceHostBindings: checkerBindings
133325
133370
  });
133326
133371
  if (closureResult.findings.length > 0) {
133327
133372
  await evidence.append({
@@ -133337,6 +133382,31 @@ async function publishRelease(options) {
133337
133382
  { unitId, findings: closureResult.findings }
133338
133383
  );
133339
133384
  }
133385
+ const expectedHosts = [];
133386
+ for (const distribution of frozenUnit?.distributions ?? []) {
133387
+ const platform = PLATFORMS.find((item) => item.distributionType === distribution.type);
133388
+ if (platform) expectedHosts.push(await normalizeHostId(platform.buildAdapter.name));
133389
+ }
133390
+ const hostCoverage = evaluateDeclaredHostSurfaceCoverage(
133391
+ expectedHosts,
133392
+ closureResult.surfaces,
133393
+ coverageClaims
133394
+ );
133395
+ if (!hostCoverage.passed) {
133396
+ await evidence.append({
133397
+ phase: "safety-gate",
133398
+ gate: "skill-resource-closure",
133399
+ status: "failed",
133400
+ unitId,
133401
+ reason: "declared-host-surface-missing",
133402
+ missingHosts: hostCoverage.missing
133403
+ });
133404
+ throw new ReleaseError(
133405
+ GATE_FAILED,
133406
+ `skill resource closure recheck failed for unit "${unitId}": declared host surface(s) missing or empty: ${hostCoverage.missing.map((item) => item.host).join(", ")}`,
133407
+ { unitId, missingHosts: hostCoverage.missing }
133408
+ );
133409
+ }
133340
133410
  const observed = createSkillResourceClosureReceipt(closureResult, {
133341
133411
  unitId,
133342
133412
  preparedAt: expected.preparedAt ?? null,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "release-skill",
3
- "version": "0.9.6",
3
+ "version": "0.9.7",
4
4
  "description": "Safe preparation and frozen GitHub/npm production publishing with full happy end verification",
5
5
  "author": {
6
6
  "name": "广州市风荷科技有限公司"
@@ -9,9 +9,9 @@ const __bundlePkgRoot = __bundleResolve(__bundleDirname(__bundleFileURLToPath(im
9
9
  // Provide a real require() for CJS packages bundled into ESM (e.g. yaml, ajv).
10
10
  const __bundleRealRequire = __bundleCreateRequire(import.meta.url);
11
11
  // Package identity injected at build time — closure-independent --version probe.
12
- const __bundlePkg = Object.freeze({"name":"release-skill","version":"0.9.6"});
12
+ const __bundlePkg = Object.freeze({"name":"release-skill","version":"0.9.7"});
13
13
  // Build-time source digest for the BUNDLE_STALE freshness gate (see above).
14
- const __bundleSourceDigest = "8fd8e6c5f7796efe9e1f7153382b50c74d78a4b5f836f872837ff2f11e4daeb5";
14
+ const __bundleSourceDigest = "938bc6828f17e2248a4fe167bcd3353b43848ec1a494dc17dc663d390847150c";
15
15
 
16
16
  var __create = Object.create;
17
17
  var __defProp = Object.defineProperty;
@@ -109520,9 +109520,27 @@ async function checkSkillResourceClosure({
109520
109520
  result2.receiptDigest = digestDocument(receiptProjection(result2));
109521
109521
  return result2;
109522
109522
  }
109523
- function evaluateDeclaredHostSurfaceCoverage(expectedHosts, surfaces) {
109523
+ function evaluateDeclaredHostSurfaceCoverage(expectedHosts, surfaces, coverageClaims = []) {
109524
109524
  const missing = [];
109525
+ const observedById = new Map((surfaces ?? []).map((surface) => [surface.id, surface]));
109526
+ const claimsByHost = /* @__PURE__ */ new Map();
109527
+ for (const claim of coverageClaims ?? []) {
109528
+ const hostClaims = claimsByHost.get(claim.host) ?? [];
109529
+ hostClaims.push(claim);
109530
+ claimsByHost.set(claim.host, hostClaims);
109531
+ }
109525
109532
  for (const expectedHost of [...new Set(expectedHosts ?? [])].sort((a, b) => a.localeCompare(b))) {
109533
+ const declaredClaims = claimsByHost.get(expectedHost) ?? [];
109534
+ if (declaredClaims.length > 0) {
109535
+ const missingClaim = declaredClaims.find((claim) => {
109536
+ const surface3 = observedById.get(claim.surfaceId);
109537
+ return !surface3 || !(surface3.skillCount >= 1);
109538
+ });
109539
+ if (!missingClaim) continue;
109540
+ const surface2 = observedById.get(missingClaim.surfaceId);
109541
+ missing.push({ host: expectedHost, skillCount: surface2?.skillCount ?? 0 });
109542
+ continue;
109543
+ }
109526
109544
  const surface = (surfaces ?? []).find((item) => item.host === expectedHost);
109527
109545
  if (!surface || !(surface.skillCount >= 1)) {
109528
109546
  missing.push({ host: expectedHost, skillCount: surface?.skillCount ?? 0 });
@@ -112496,6 +112514,23 @@ async function deriveSurfaceHostBinding({ manifest, pluginRoot, platform, snapsh
112496
112514
  const host = await normalizeHostId(platform.buildAdapter.name);
112497
112515
  return { surfaceId, host };
112498
112516
  }
112517
+ function groupSurfaceHostBindings(claims = []) {
112518
+ if (!Array.isArray(claims)) {
112519
+ throw new TypeError("surfaceHostBindings must be an array");
112520
+ }
112521
+ const bySurface = /* @__PURE__ */ new Map();
112522
+ for (const claim of claims) {
112523
+ if (!claim || typeof claim !== "object" || typeof claim.surfaceId !== "string" || typeof claim.host !== "string") {
112524
+ throw new TypeError("surfaceHostBindings entries must be objects with string surfaceId and host");
112525
+ }
112526
+ const existing = bySurface.get(claim.surfaceId) ?? [];
112527
+ existing.push({ surfaceId: claim.surfaceId, host: claim.host });
112528
+ bySurface.set(claim.surfaceId, existing);
112529
+ }
112530
+ const coverageClaims = [...bySurface.values()].flat().sort((left, right) => left.surfaceId.localeCompare(right.surfaceId) || left.host.localeCompare(right.host));
112531
+ const checkerBindings = [...bySurface.values()].filter((surfaceClaims) => surfaceClaims.length === 1).map(([claim]) => claim).sort((left, right) => left.surfaceId.localeCompare(right.surfaceId) || left.host.localeCompare(right.host));
112532
+ return { coverageClaims, checkerBindings };
112533
+ }
112499
112534
  var SKILLS_NORMALIZERS;
112500
112535
  var init_surface_host_bindings = __esm({
112501
112536
  async "src/core/surface-host-bindings.mjs"() {
@@ -112513,6 +112548,7 @@ var init_surface_host_bindings = __esm({
112513
112548
  __name(pluginRootFromManifestRelativePath, "pluginRootFromManifestRelativePath");
112514
112549
  __name(assertDeclaredSkillsDirExists, "assertDeclaredSkillsDirExists");
112515
112550
  __name(deriveSurfaceHostBinding, "deriveSurfaceHostBinding");
112551
+ __name(groupSurfaceHostBindings, "groupSurfaceHostBindings");
112516
112552
  }
112517
112553
  });
112518
112554
 
@@ -113943,11 +113979,16 @@ async function verifyRelease(options) {
113943
113979
  const unit = (plan.units ?? []).find((u) => u.id === unitId);
113944
113980
  const dist = unit?.distributions?.find((d) => d.type === platform.distributionType);
113945
113981
  let binding = null;
113982
+ let frozenPluginRoot = null;
113946
113983
  const contract2 = dist?.installationContract;
113947
113984
  if (contract2?.normalizedManifest) {
113985
+ frozenPluginRoot = pluginRootFromManifestRelativePath(contract2.manifestRelativePath);
113948
113986
  binding = await deriveSurfaceHostBinding({
113949
113987
  manifest: contract2.normalizedManifest,
113950
- pluginRoot: pluginRootFromManifestRelativePath(contract2.manifestRelativePath),
113988
+ // Adapter observations are already rooted at the installed
113989
+ // plugin. The frozen manifest's skills path is therefore
113990
+ // relative to '.', not to the snapshot-root manifest path.
113991
+ pluginRoot: ".",
113951
113992
  platform,
113952
113993
  snapshotDir: check.observation.installPath
113953
113994
  });
@@ -113960,6 +114001,7 @@ async function verifyRelease(options) {
113960
114001
  unitId,
113961
114002
  surfaceId: binding?.surfaceId ?? ".",
113962
114003
  binding,
114004
+ frozenPluginRoot,
113963
114005
  unit
113964
114006
  });
113965
114007
  }
@@ -114042,7 +114084,7 @@ async function verifyRelease(options) {
114042
114084
  );
114043
114085
  }
114044
114086
  const pluginDistCount = (surface.unit?.distributions ?? []).filter((d) => d.type !== "npm").length;
114045
- if (pluginDistCount === 1) {
114087
+ if (pluginDistCount === 1 && surface.frozenPluginRoot === ".") {
114046
114088
  const observedReceipt = createSkillResourceClosureReceipt(closureResult, {
114047
114089
  unitId: surface.unitId,
114048
114090
  preparedAt: expectedUnitReceipt.preparedAt ?? null,
@@ -129636,10 +129678,11 @@ async function runPrepareSkillResourceClosureGate({
129636
129678
  });
129637
129679
  if (binding) surfaceHostBindings.push(binding);
129638
129680
  }
129681
+ const { checkerBindings, coverageClaims } = groupSurfaceHostBindings(surfaceHostBindings);
129639
129682
  const closureResult = await checkSkillResourceClosure({
129640
129683
  snapshotDir: manifest.outputDir,
129641
129684
  host: "root",
129642
- surfaceHostBindings
129685
+ surfaceHostBindings: checkerBindings
129643
129686
  });
129644
129687
  const receipt = createSkillResourceClosureReceipt(closureResult, {
129645
129688
  unitId: unit.id,
@@ -129684,7 +129727,8 @@ async function runPrepareSkillResourceClosureGate({
129684
129727
  }
129685
129728
  const hostCoverage = evaluateDeclaredHostSurfaceCoverage(
129686
129729
  expectedHosts,
129687
- closureResult.surfaces
129730
+ closureResult.surfaces,
129731
+ coverageClaims
129688
129732
  );
129689
129733
  if (!hostCoverage.passed) {
129690
129734
  await evidence.append({
@@ -129708,7 +129752,7 @@ async function runPrepareSkillResourceClosureGate({
129708
129752
  }
129709
129753
  );
129710
129754
  }
129711
- for (const binding of surfaceHostBindings) {
129755
+ for (const binding of coverageClaims) {
129712
129756
  const boundSurface = closureResult.surfaces.find(
129713
129757
  (surface) => surface.id === binding.surfaceId
129714
129758
  );
@@ -133318,10 +133362,11 @@ async function publishRelease(options) {
133318
133362
  });
133319
133363
  if (binding) surfaceHostBindings.push(binding);
133320
133364
  }
133365
+ const { checkerBindings, coverageClaims } = groupSurfaceHostBindings(surfaceHostBindings);
133321
133366
  const closureResult = await checkSkillResourceClosure({
133322
133367
  snapshotDir,
133323
133368
  host: "root",
133324
- surfaceHostBindings
133369
+ surfaceHostBindings: checkerBindings
133325
133370
  });
133326
133371
  if (closureResult.findings.length > 0) {
133327
133372
  await evidence.append({
@@ -133337,6 +133382,31 @@ async function publishRelease(options) {
133337
133382
  { unitId, findings: closureResult.findings }
133338
133383
  );
133339
133384
  }
133385
+ const expectedHosts = [];
133386
+ for (const distribution of frozenUnit?.distributions ?? []) {
133387
+ const platform = PLATFORMS.find((item) => item.distributionType === distribution.type);
133388
+ if (platform) expectedHosts.push(await normalizeHostId(platform.buildAdapter.name));
133389
+ }
133390
+ const hostCoverage = evaluateDeclaredHostSurfaceCoverage(
133391
+ expectedHosts,
133392
+ closureResult.surfaces,
133393
+ coverageClaims
133394
+ );
133395
+ if (!hostCoverage.passed) {
133396
+ await evidence.append({
133397
+ phase: "safety-gate",
133398
+ gate: "skill-resource-closure",
133399
+ status: "failed",
133400
+ unitId,
133401
+ reason: "declared-host-surface-missing",
133402
+ missingHosts: hostCoverage.missing
133403
+ });
133404
+ throw new ReleaseError(
133405
+ GATE_FAILED,
133406
+ `skill resource closure recheck failed for unit "${unitId}": declared host surface(s) missing or empty: ${hostCoverage.missing.map((item) => item.host).join(", ")}`,
133407
+ { unitId, missingHosts: hostCoverage.missing }
133408
+ );
133409
+ }
133340
133410
  const observed = createSkillResourceClosureReceipt(closureResult, {
133341
133411
  unitId,
133342
133412
  preparedAt: expected.preparedAt ?? null,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "release-skill",
3
- "version": "0.9.6",
3
+ "version": "0.9.7",
4
4
  "description": "Safe preparation and frozen GitHub/npm production publishing with full happy end verification",
5
5
  "author": {
6
6
  "name": "广州市风荷科技有限公司"
@@ -9,9 +9,9 @@ const __bundlePkgRoot = __bundleResolve(__bundleDirname(__bundleFileURLToPath(im
9
9
  // Provide a real require() for CJS packages bundled into ESM (e.g. yaml, ajv).
10
10
  const __bundleRealRequire = __bundleCreateRequire(import.meta.url);
11
11
  // Package identity injected at build time — closure-independent --version probe.
12
- const __bundlePkg = Object.freeze({"name":"release-skill","version":"0.9.6"});
12
+ const __bundlePkg = Object.freeze({"name":"release-skill","version":"0.9.7"});
13
13
  // Build-time source digest for the BUNDLE_STALE freshness gate (see above).
14
- const __bundleSourceDigest = "8fd8e6c5f7796efe9e1f7153382b50c74d78a4b5f836f872837ff2f11e4daeb5";
14
+ const __bundleSourceDigest = "938bc6828f17e2248a4fe167bcd3353b43848ec1a494dc17dc663d390847150c";
15
15
 
16
16
  var __create = Object.create;
17
17
  var __defProp = Object.defineProperty;
@@ -109520,9 +109520,27 @@ async function checkSkillResourceClosure({
109520
109520
  result2.receiptDigest = digestDocument(receiptProjection(result2));
109521
109521
  return result2;
109522
109522
  }
109523
- function evaluateDeclaredHostSurfaceCoverage(expectedHosts, surfaces) {
109523
+ function evaluateDeclaredHostSurfaceCoverage(expectedHosts, surfaces, coverageClaims = []) {
109524
109524
  const missing = [];
109525
+ const observedById = new Map((surfaces ?? []).map((surface) => [surface.id, surface]));
109526
+ const claimsByHost = /* @__PURE__ */ new Map();
109527
+ for (const claim of coverageClaims ?? []) {
109528
+ const hostClaims = claimsByHost.get(claim.host) ?? [];
109529
+ hostClaims.push(claim);
109530
+ claimsByHost.set(claim.host, hostClaims);
109531
+ }
109525
109532
  for (const expectedHost of [...new Set(expectedHosts ?? [])].sort((a, b) => a.localeCompare(b))) {
109533
+ const declaredClaims = claimsByHost.get(expectedHost) ?? [];
109534
+ if (declaredClaims.length > 0) {
109535
+ const missingClaim = declaredClaims.find((claim) => {
109536
+ const surface3 = observedById.get(claim.surfaceId);
109537
+ return !surface3 || !(surface3.skillCount >= 1);
109538
+ });
109539
+ if (!missingClaim) continue;
109540
+ const surface2 = observedById.get(missingClaim.surfaceId);
109541
+ missing.push({ host: expectedHost, skillCount: surface2?.skillCount ?? 0 });
109542
+ continue;
109543
+ }
109526
109544
  const surface = (surfaces ?? []).find((item) => item.host === expectedHost);
109527
109545
  if (!surface || !(surface.skillCount >= 1)) {
109528
109546
  missing.push({ host: expectedHost, skillCount: surface?.skillCount ?? 0 });
@@ -112496,6 +112514,23 @@ async function deriveSurfaceHostBinding({ manifest, pluginRoot, platform, snapsh
112496
112514
  const host = await normalizeHostId(platform.buildAdapter.name);
112497
112515
  return { surfaceId, host };
112498
112516
  }
112517
+ function groupSurfaceHostBindings(claims = []) {
112518
+ if (!Array.isArray(claims)) {
112519
+ throw new TypeError("surfaceHostBindings must be an array");
112520
+ }
112521
+ const bySurface = /* @__PURE__ */ new Map();
112522
+ for (const claim of claims) {
112523
+ if (!claim || typeof claim !== "object" || typeof claim.surfaceId !== "string" || typeof claim.host !== "string") {
112524
+ throw new TypeError("surfaceHostBindings entries must be objects with string surfaceId and host");
112525
+ }
112526
+ const existing = bySurface.get(claim.surfaceId) ?? [];
112527
+ existing.push({ surfaceId: claim.surfaceId, host: claim.host });
112528
+ bySurface.set(claim.surfaceId, existing);
112529
+ }
112530
+ const coverageClaims = [...bySurface.values()].flat().sort((left, right) => left.surfaceId.localeCompare(right.surfaceId) || left.host.localeCompare(right.host));
112531
+ const checkerBindings = [...bySurface.values()].filter((surfaceClaims) => surfaceClaims.length === 1).map(([claim]) => claim).sort((left, right) => left.surfaceId.localeCompare(right.surfaceId) || left.host.localeCompare(right.host));
112532
+ return { coverageClaims, checkerBindings };
112533
+ }
112499
112534
  var SKILLS_NORMALIZERS;
112500
112535
  var init_surface_host_bindings = __esm({
112501
112536
  async "src/core/surface-host-bindings.mjs"() {
@@ -112513,6 +112548,7 @@ var init_surface_host_bindings = __esm({
112513
112548
  __name(pluginRootFromManifestRelativePath, "pluginRootFromManifestRelativePath");
112514
112549
  __name(assertDeclaredSkillsDirExists, "assertDeclaredSkillsDirExists");
112515
112550
  __name(deriveSurfaceHostBinding, "deriveSurfaceHostBinding");
112551
+ __name(groupSurfaceHostBindings, "groupSurfaceHostBindings");
112516
112552
  }
112517
112553
  });
112518
112554
 
@@ -113943,11 +113979,16 @@ async function verifyRelease(options) {
113943
113979
  const unit = (plan.units ?? []).find((u) => u.id === unitId);
113944
113980
  const dist = unit?.distributions?.find((d) => d.type === platform.distributionType);
113945
113981
  let binding = null;
113982
+ let frozenPluginRoot = null;
113946
113983
  const contract2 = dist?.installationContract;
113947
113984
  if (contract2?.normalizedManifest) {
113985
+ frozenPluginRoot = pluginRootFromManifestRelativePath(contract2.manifestRelativePath);
113948
113986
  binding = await deriveSurfaceHostBinding({
113949
113987
  manifest: contract2.normalizedManifest,
113950
- pluginRoot: pluginRootFromManifestRelativePath(contract2.manifestRelativePath),
113988
+ // Adapter observations are already rooted at the installed
113989
+ // plugin. The frozen manifest's skills path is therefore
113990
+ // relative to '.', not to the snapshot-root manifest path.
113991
+ pluginRoot: ".",
113951
113992
  platform,
113952
113993
  snapshotDir: check.observation.installPath
113953
113994
  });
@@ -113960,6 +114001,7 @@ async function verifyRelease(options) {
113960
114001
  unitId,
113961
114002
  surfaceId: binding?.surfaceId ?? ".",
113962
114003
  binding,
114004
+ frozenPluginRoot,
113963
114005
  unit
113964
114006
  });
113965
114007
  }
@@ -114042,7 +114084,7 @@ async function verifyRelease(options) {
114042
114084
  );
114043
114085
  }
114044
114086
  const pluginDistCount = (surface.unit?.distributions ?? []).filter((d) => d.type !== "npm").length;
114045
- if (pluginDistCount === 1) {
114087
+ if (pluginDistCount === 1 && surface.frozenPluginRoot === ".") {
114046
114088
  const observedReceipt = createSkillResourceClosureReceipt(closureResult, {
114047
114089
  unitId: surface.unitId,
114048
114090
  preparedAt: expectedUnitReceipt.preparedAt ?? null,
@@ -129636,10 +129678,11 @@ async function runPrepareSkillResourceClosureGate({
129636
129678
  });
129637
129679
  if (binding) surfaceHostBindings.push(binding);
129638
129680
  }
129681
+ const { checkerBindings, coverageClaims } = groupSurfaceHostBindings(surfaceHostBindings);
129639
129682
  const closureResult = await checkSkillResourceClosure({
129640
129683
  snapshotDir: manifest.outputDir,
129641
129684
  host: "root",
129642
- surfaceHostBindings
129685
+ surfaceHostBindings: checkerBindings
129643
129686
  });
129644
129687
  const receipt = createSkillResourceClosureReceipt(closureResult, {
129645
129688
  unitId: unit.id,
@@ -129684,7 +129727,8 @@ async function runPrepareSkillResourceClosureGate({
129684
129727
  }
129685
129728
  const hostCoverage = evaluateDeclaredHostSurfaceCoverage(
129686
129729
  expectedHosts,
129687
- closureResult.surfaces
129730
+ closureResult.surfaces,
129731
+ coverageClaims
129688
129732
  );
129689
129733
  if (!hostCoverage.passed) {
129690
129734
  await evidence.append({
@@ -129708,7 +129752,7 @@ async function runPrepareSkillResourceClosureGate({
129708
129752
  }
129709
129753
  );
129710
129754
  }
129711
- for (const binding of surfaceHostBindings) {
129755
+ for (const binding of coverageClaims) {
129712
129756
  const boundSurface = closureResult.surfaces.find(
129713
129757
  (surface) => surface.id === binding.surfaceId
129714
129758
  );
@@ -133318,10 +133362,11 @@ async function publishRelease(options) {
133318
133362
  });
133319
133363
  if (binding) surfaceHostBindings.push(binding);
133320
133364
  }
133365
+ const { checkerBindings, coverageClaims } = groupSurfaceHostBindings(surfaceHostBindings);
133321
133366
  const closureResult = await checkSkillResourceClosure({
133322
133367
  snapshotDir,
133323
133368
  host: "root",
133324
- surfaceHostBindings
133369
+ surfaceHostBindings: checkerBindings
133325
133370
  });
133326
133371
  if (closureResult.findings.length > 0) {
133327
133372
  await evidence.append({
@@ -133337,6 +133382,31 @@ async function publishRelease(options) {
133337
133382
  { unitId, findings: closureResult.findings }
133338
133383
  );
133339
133384
  }
133385
+ const expectedHosts = [];
133386
+ for (const distribution of frozenUnit?.distributions ?? []) {
133387
+ const platform = PLATFORMS.find((item) => item.distributionType === distribution.type);
133388
+ if (platform) expectedHosts.push(await normalizeHostId(platform.buildAdapter.name));
133389
+ }
133390
+ const hostCoverage = evaluateDeclaredHostSurfaceCoverage(
133391
+ expectedHosts,
133392
+ closureResult.surfaces,
133393
+ coverageClaims
133394
+ );
133395
+ if (!hostCoverage.passed) {
133396
+ await evidence.append({
133397
+ phase: "safety-gate",
133398
+ gate: "skill-resource-closure",
133399
+ status: "failed",
133400
+ unitId,
133401
+ reason: "declared-host-surface-missing",
133402
+ missingHosts: hostCoverage.missing
133403
+ });
133404
+ throw new ReleaseError(
133405
+ GATE_FAILED,
133406
+ `skill resource closure recheck failed for unit "${unitId}": declared host surface(s) missing or empty: ${hostCoverage.missing.map((item) => item.host).join(", ")}`,
133407
+ { unitId, missingHosts: hostCoverage.missing }
133408
+ );
133409
+ }
133340
133410
  const observed = createSkillResourceClosureReceipt(closureResult, {
133341
133411
  unitId,
133342
133412
  preparedAt: expected.preparedAt ?? null,