@integraledger/lcp-placement-ucp 0.15.0 → 0.16.0

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,63 @@
1
1
  # @integraledger/lcp-placement-ucp
2
2
 
3
+ ## 0.16.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 3ca1d2b: UCP's HTTPS rule now applies to `place`, not only to `extract`.
8
+
9
+ The placement wrapped `extract` alone, under a docblock reasoning that "`place` never writes the links
10
+ alias, so the write side has no URL to police". The write side does have one: the `policies[]` entry
11
+ `place` writes carries the reference itself, `url` is a permitted carrier type here, and `place` accepted an
12
+ `http:` url reference and emitted a document this very module's `extract` refuses. A placement that will
13
+ not read back the bytes it wrote fails a round trip on its own output.
14
+
15
+ The terms URL was never the gap — the kit already refuses a non-https `termsUrl` at
16
+ `ucp/terms-url-malformed`. The reference was, and a url-typed reference inside a policies entry is exactly
17
+ as rewritable in transit as one in `links`. The rule is now stated once and applied in both directions.
18
+
19
+ **This changes published behaviour**: `ucpPlacement.place` refuses `ucp/insecure-terms-url` where it
20
+ previously returned a written document.
21
+
22
+ The corpus gains the write half of the rule and an https control beside it. 859 → 861; the corpus root
23
+ moved to `c2875add14f5f2bf…`.
24
+
25
+ ### Patch Changes
26
+
27
+ - feab885: Five README examples that failed on their first line, and a gate that runs the examples.
28
+
29
+ Each was the first thing a stranger runs, on the npmjs landing page:
30
+
31
+ - `binding-evm-x402` opened with `getX402Deployment("base-sepolia-usdc")`; the keys are `base`,
32
+ `base-sepolia`, `avalanche`, `monad`. It threw.
33
+ - `discovery` told the reader to read `hashesAgree`; the field is `hashesMatch`, so the documented read is
34
+ `undefined` — falsy — and records a MISMATCH for a hash that matched, the exact defect the two-field
35
+ design exists to prevent.
36
+ - `placement-ucp`'s only usage example refused `ucp/terms-url-missing`: this protocol declares a terms-URL
37
+ slot, so an integrity-bearing reference needs one, and every sibling README passes it.
38
+ - `placement-ack` claimed a `url` carrier in the canonical slot "passes `requireIntegrity`". It did when
39
+ written; `requireIntegrity` now checks the value's type as well as the slot's declared class and returns
40
+ `undefined`. The narrower point that survives is stated instead.
41
+ - `binding-canton` documented a DAR filename, `lcp-anchor-0.9.0.dar`, that no build produces —
42
+ `daml.yaml` carries the package version, gated by a test. Both the README and `daml.yaml`'s own comment
43
+ now write the version as a glob, because a pinned number inside a copyable command goes stale at the
44
+ next bump and had already done so twice.
45
+
46
+ The mechanism behind all five is that `check:docs` COMPILES fences and never runs them. `check:doc-calls`
47
+ runs the subset that can be run — a call of a workspace export whose every argument is a literal — and
48
+ refuses a throw or a returned `Refusal`. It also reads the inversion: a line the document annotates
49
+ `// throws` or `// refuses` must fail, so a demonstration that quietly starts succeeding is caught too.
50
+ Elided arguments (`"0x…"`) and calls inside a `try` are skipped as structurally not assertions. It refuses
51
+ an empty subject set, and it runs 30 calls across 74 fences today.
52
+ - @integraledger/lcp-binding-core@0.16.0
53
+
54
+ ## 0.15.1
55
+
56
+ ### Patch Changes
57
+
58
+ - Updated dependencies [431b8ec]
59
+ - @integraledger/lcp-binding-core@0.15.1
60
+
3
61
  ## 0.15.0
4
62
 
5
63
  ### Patch Changes
@@ -114,7 +172,7 @@ claimedClass`, so a record proving nothing — no settlement, no acceptance, no
114
172
  `placement-x402` — the inlined wire schema now IS the authority document minus `$id` and `$defs`
115
173
  (Bazaar forbids both on the wire), drift-gated in `lcp-conformance` where the two packages meet.
116
174
  `termsUrlFields` declares both slots the wire carries; the bare-hash alias is written (`extra` stopped
117
- being wholly scheme-private when x402 §6.1 reserved names inside it, and LCP v1.38 §C.4's own Tier A
175
+ being wholly scheme-private when x402 §6.1 reserved names inside it, and LCP §C.4's own Tier A
118
176
  illustration carries the pair there); the `url` carrier admission is withdrawn (`carrierTypes` is
119
177
  `sha256` alone — the schema on the wire is `const: "sha256"`, and no shipped reader ever accepted a url
120
178
  in this slot). The `place` override shrinks to composition: the kit performs the whole placement and the
@@ -166,7 +224,7 @@ and a large number of documentation claims were corrected against the host speci
166
224
  First public release.
167
225
 
168
226
  `0.9.0` is deliberate: this is a release candidate for 1.0, not a preview. The implementation is complete
169
- against LCP v1.38 and certified by the conformance corpus, and the remaining distance to 1.0 is the
227
+ against the published LCP specification and certified by the conformance corpus, and the remaining distance to 1.0 is the
170
228
  specification's own — the standard is still moving through its steering committee, and this package will not
171
229
  claim a stability its protocol has not yet promised.
172
230
 
package/README.md CHANGED
@@ -36,12 +36,24 @@ npm install @integraledger/lcp-placement-ucp
36
36
  import { UCP_PLACEMENT, ucpPlacement } from "@integraledger/lcp-placement-ucp";
37
37
 
38
38
  declare const checkout: unknown; // the UCP checkout response, as received
39
-
40
- const placed = ucpPlacement.place({ ref: { type: "sha256", value: "0x…" } }, checkout);
39
+ declare const atrHash: `0x${string}`;
40
+
41
+ // `termsUrl` is REQUIRED beside an integrity-bearing reference on this protocol: the manifest declares a
42
+ // terms-URL slot, and a counterparty holding only a hash cannot resolve it. Omitting it refuses
43
+ // `ucp/terms-url-missing` rather than writing a reference nobody can follow.
44
+ const placed = ucpPlacement.place(
45
+ {
46
+ ref: { type: "sha256", value: atrHash },
47
+ termsUrl: "https://seller.example/.well-known/legal-context.json",
48
+ },
49
+ checkout,
50
+ );
41
51
  const ref = ucpPlacement.extract(checkout);
42
52
  ```
43
53
 
44
- Both members are total: a refusal is a returned value, never a thrown exception.
54
+ Both members are total: a refusal is a returned value, never a thrown exception. Both also enforce one rule
55
+ of UCP's own — a `url`-typed reference must be HTTPS — so `place` will not write what `extract` would
56
+ refuse.
45
57
 
46
58
  ## Specification provenance — verified against the live host, 2026-07-29 — and it re-cut the package
47
59
 
@@ -116,7 +128,7 @@ present, the `url` carrier type itself signalling discovery-not-integrity.
116
128
 
117
129
  ## Provenance
118
130
 
119
- Cut against UCP `2026-04-08` (ucp.dev) and reconciled against LCP v1.37 §C.3; re-read against **v1.38 §C.3**
131
+ Cut against UCP `2026-04-08` (ucp.dev) and reconciled against LCP §C.3; re-read against **LCP §C.3**
120
132
  on 2026-08-12, which now records `policies[]` as a Tier A carrier in the negotiated baseline — the carrier
121
133
  this package moved to. A deployment advertises under
122
134
  its own reverse-domain namespace; `org.legalcontextprotocol.*` is reserved for a TSC-ratified capability.
@@ -2,7 +2,7 @@ import type { PlacementManifest } from "@integraledger/lcp-binding-core";
2
2
  /**
3
3
  * UCP (Universal Commerce Protocol) reference placement, cut against the live spec (2026-04-08, ucp.dev —
4
4
  * overview §capabilities, §namespace-governance, §intersection-algorithm, and the checkout capability's
5
- * response schema), gate discharged 2026-07-29 against LCP v1.37 §C.3, and re-cut against the live UCP schemas and v1.38 §C.3
5
+ * response schema), gate discharged 2026-07-29 against LCP §C.3, and re-cut against the live UCP schemas and LCP §C.3
6
6
  * on 2026-08-08 when the canonical carrier moved.
7
7
  *
8
8
  * **THE CANONICAL CARRIER IS A `policies[]` ENTRY, AND UCP HAS NO `extensions` MAP TO WRITE INTO.** A
package/dist/manifest.js CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * UCP (Universal Commerce Protocol) reference placement, cut against the live spec (2026-04-08, ucp.dev —
3
3
  * overview §capabilities, §namespace-governance, §intersection-algorithm, and the checkout capability's
4
- * response schema), gate discharged 2026-07-29 against LCP v1.37 §C.3, and re-cut against the live UCP schemas and v1.38 §C.3
4
+ * response schema), gate discharged 2026-07-29 against LCP §C.3, and re-cut against the live UCP schemas and LCP §C.3
5
5
  * on 2026-08-08 when the canonical carrier moved.
6
6
  *
7
7
  * **THE CANONICAL CARRIER IS A `policies[]` ENTRY, AND UCP HAS NO `extensions` MAP TO WRITE INTO.** A
@@ -12,9 +12,18 @@ import { type ReferencePlacementAdapter } from "@integraledger/lcp-binding-core"
12
12
  * behind a reference the record cites.
13
13
  *
14
14
  * This is the composition the kit is shaped for — generic mechanics, protocol-specific semantics layered on
15
- * top —
16
- * and it wraps `extract`, not `place`: `place` never writes the links alias (the terms URL is the
17
- * DEPLOYMENT's datum, not the reference see the manifest), so the write side has no URL to police.
15
+ * top — and it wraps BOTH directions, because the rule is about the carrier and both directions carry one.
16
+ *
17
+ * It wrapped `extract` alone until 2026-09-03, under the reasoning that "`place` never writes the links
18
+ * alias, so the write side has no URL to police". That was already false when it was written and became
19
+ * more so: the policies entry `place` writes carries the reference itself, `url` is a permitted carrier
20
+ * type here, and the kit's own terms-URL slot landed on the same entry. So `place` accepted an `http:`
21
+ * reference and emitted a document this very module's `extract` refuses — a placement that will not read
22
+ * back the bytes it wrote, and a round trip that fails on our own output rather than on a counterparty's.
23
+ * A url-typed reference inside a policies entry is exactly as rewritable in transit as one in `links`.
24
+ *
25
+ * The terms URL was never the gap: the kit already refuses a non-https `termsUrl` at
26
+ * `ucp/terms-url-malformed`. The REFERENCE was.
18
27
  *
19
28
  * **Scoped to url-typed results, deliberately.** A sha256 answer must never be blocked by a bad link sitting
20
29
  * beside it — the capability WINS over links, and refusing the winner for the loser's defect would invert the
@@ -1 +1 @@
1
- {"version":3,"file":"placement.d.ts","sourceRoot":"","sources":["../src/placement.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,yBAAyB,EAC/B,MAAM,iCAAiC,CAAC;AAKzC;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,YAAY,EAAE,yBAe1B,CAAC"}
1
+ {"version":3,"file":"placement.d.ts","sourceRoot":"","sources":["../src/placement.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,yBAAyB,EAE/B,MAAM,iCAAiC,CAAC;AAgBzC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,eAAO,MAAM,YAAY,EAAE,yBAY1B,CAAC"}
package/dist/placement.js CHANGED
@@ -1,6 +1,17 @@
1
1
  import { makePlacement, } from "@integraledger/lcp-binding-core";
2
2
  import { UCP_PLACEMENT } from "./manifest.js";
3
3
  const base = makePlacement(UCP_PLACEMENT);
4
+ /** The one rule, stated once: a url-typed reference on this protocol must be HTTPS. */
5
+ function insecureTermsUrl(ref) {
6
+ if (ref.type !== "url" || ref.value.startsWith("https://"))
7
+ return null;
8
+ return {
9
+ refused: true,
10
+ haltClass: "verification-failure",
11
+ code: "ucp/insecure-terms-url",
12
+ detail: `a terms link must be HTTPS — an http: reference is rewritable in transit: ${ref.value}`,
13
+ };
14
+ }
4
15
  /**
5
16
  * The UCP reference placement — the kit plus ONE protocol rule the kit cannot know.
6
17
  *
@@ -14,9 +25,18 @@ const base = makePlacement(UCP_PLACEMENT);
14
25
  * behind a reference the record cites.
15
26
  *
16
27
  * This is the composition the kit is shaped for — generic mechanics, protocol-specific semantics layered on
17
- * top —
18
- * and it wraps `extract`, not `place`: `place` never writes the links alias (the terms URL is the
19
- * DEPLOYMENT's datum, not the reference see the manifest), so the write side has no URL to police.
28
+ * top — and it wraps BOTH directions, because the rule is about the carrier and both directions carry one.
29
+ *
30
+ * It wrapped `extract` alone until 2026-09-03, under the reasoning that "`place` never writes the links
31
+ * alias, so the write side has no URL to police". That was already false when it was written and became
32
+ * more so: the policies entry `place` writes carries the reference itself, `url` is a permitted carrier
33
+ * type here, and the kit's own terms-URL slot landed on the same entry. So `place` accepted an `http:`
34
+ * reference and emitted a document this very module's `extract` refuses — a placement that will not read
35
+ * back the bytes it wrote, and a round trip that fails on our own output rather than on a counterparty's.
36
+ * A url-typed reference inside a policies entry is exactly as rewritable in transit as one in `links`.
37
+ *
38
+ * The terms URL was never the gap: the kit already refuses a non-https `termsUrl` at
39
+ * `ucp/terms-url-malformed`. The REFERENCE was.
20
40
  *
21
41
  * **Scoped to url-typed results, deliberately.** A sha256 answer must never be blocked by a bad link sitting
22
42
  * beside it — the capability WINS over links, and refusing the winner for the loser's defect would invert the
@@ -26,19 +46,16 @@ const base = makePlacement(UCP_PLACEMENT);
26
46
  */
27
47
  export const ucpPlacement = {
28
48
  ...base,
49
+ place(ad, doc) {
50
+ // BEFORE the kit writes: a document that has already been written into is a document a caller may
51
+ // reasonably send, and refusing after building it would make the refusal advisory.
52
+ return insecureTermsUrl(ad.ref) ?? base.place(ad, doc);
53
+ },
29
54
  extract(doc) {
30
55
  const out = base.extract(doc);
31
56
  if ("refused" in out)
32
57
  return out;
33
- const { ref } = out.value;
34
- if (ref.type === "url" && !ref.value.startsWith("https://"))
35
- return {
36
- refused: true,
37
- haltClass: "verification-failure",
38
- code: "ucp/insecure-terms-url",
39
- detail: `a terms link must be HTTPS — an http: reference is rewritable in transit: ${ref.value}`,
40
- };
41
- return out;
58
+ return insecureTermsUrl(out.value.ref) ?? out;
42
59
  },
43
60
  };
44
61
  //# sourceMappingURL=placement.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"placement.js","sourceRoot":"","sources":["../src/placement.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,GAEd,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAE9C,MAAM,IAAI,GAAG,aAAa,CAAC,aAAa,CAAC,CAAC;AAE1C;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,CAAC,MAAM,YAAY,GAA8B;IACrD,GAAG,IAAI;IACP,OAAO,CAAC,GAAY;QAClB,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAC9B,IAAI,SAAS,IAAI,GAAG;YAAE,OAAO,GAAG,CAAC;QACjC,MAAM,EAAE,GAAG,EAAE,GAAG,GAAG,CAAC,KAAK,CAAC;QAC1B,IAAI,GAAG,CAAC,IAAI,KAAK,KAAK,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,UAAU,CAAC;YACzD,OAAO;gBACL,OAAO,EAAE,IAAI;gBACb,SAAS,EAAE,sBAAsB;gBACjC,IAAI,EAAE,wBAAwB;gBAC9B,MAAM,EAAE,6EAA6E,GAAG,CAAC,KAAK,EAAE;aACjG,CAAC;QACJ,OAAO,GAAG,CAAC;IACb,CAAC;CACF,CAAC"}
1
+ {"version":3,"file":"placement.js","sourceRoot":"","sources":["../src/placement.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,aAAa,GAGd,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAE9C,MAAM,IAAI,GAAG,aAAa,CAAC,aAAa,CAAC,CAAC;AAE1C,uFAAuF;AACvF,SAAS,gBAAgB,CAAC,GAAoB;IAC5C,IAAI,GAAG,CAAC,IAAI,KAAK,KAAK,IAAI,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,UAAU,CAAC;QAAE,OAAO,IAAI,CAAC;IACxE,OAAO;QACL,OAAO,EAAE,IAAI;QACb,SAAS,EAAE,sBAAsB;QACjC,IAAI,EAAE,wBAAwB;QAC9B,MAAM,EAAE,6EAA6E,GAAG,CAAC,KAAK,EAAE;KACjG,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,MAAM,CAAC,MAAM,YAAY,GAA8B;IACrD,GAAG,IAAI;IACP,KAAK,CAAC,EAA6B,EAAE,GAAY;QAC/C,kGAAkG;QAClG,mFAAmF;QACnF,OAAO,gBAAgB,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;IACzD,CAAC;IACD,OAAO,CAAC,GAAY;QAClB,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAC9B,IAAI,SAAS,IAAI,GAAG;YAAE,OAAO,GAAG,CAAC;QACjC,OAAO,gBAAgB,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC;IAChD,CAAC;CACF,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@integraledger/lcp-placement-ucp",
3
- "version": "0.15.0",
3
+ "version": "0.16.0",
4
4
  "description": "Places an LCP reference into a UCP (Universal Commerce Protocol) checkout, and reads it back.",
5
5
  "keywords": [
6
6
  "lcp",
@@ -40,7 +40,7 @@
40
40
  },
41
41
  "homepage": "https://github.com/IntegraLedger/integra-protocol/tree/main/packages/placement-ucp#readme",
42
42
  "dependencies": {
43
- "@integraledger/lcp-binding-core": "0.15.0"
43
+ "@integraledger/lcp-binding-core": "0.16.0"
44
44
  },
45
45
  "devDependencies": {
46
46
  "@cfworker/json-schema": "4.1.1",
package/src/manifest.ts CHANGED
@@ -3,7 +3,7 @@ import type { PlacementManifest } from "@integraledger/lcp-binding-core";
3
3
  /**
4
4
  * UCP (Universal Commerce Protocol) reference placement, cut against the live spec (2026-04-08, ucp.dev —
5
5
  * overview §capabilities, §namespace-governance, §intersection-algorithm, and the checkout capability's
6
- * response schema), gate discharged 2026-07-29 against LCP v1.37 §C.3, and re-cut against the live UCP schemas and v1.38 §C.3
6
+ * response schema), gate discharged 2026-07-29 against LCP §C.3, and re-cut against the live UCP schemas and LCP §C.3
7
7
  * on 2026-08-08 when the canonical carrier moved.
8
8
  *
9
9
  * **THE CANONICAL CARRIER IS A `policies[]` ENTRY, AND UCP HAS NO `extensions` MAP TO WRITE INTO.** A
package/src/placement.ts CHANGED
@@ -1,11 +1,25 @@
1
1
  import {
2
+ type LegalContextAdvertisement,
3
+ type LegalContextRef,
2
4
  makePlacement,
3
5
  type ReferencePlacementAdapter,
6
+ type Refusal,
4
7
  } from "@integraledger/lcp-binding-core";
5
8
  import { UCP_PLACEMENT } from "./manifest.js";
6
9
 
7
10
  const base = makePlacement(UCP_PLACEMENT);
8
11
 
12
+ /** The one rule, stated once: a url-typed reference on this protocol must be HTTPS. */
13
+ function insecureTermsUrl(ref: LegalContextRef): Refusal | null {
14
+ if (ref.type !== "url" || ref.value.startsWith("https://")) return null;
15
+ return {
16
+ refused: true,
17
+ haltClass: "verification-failure",
18
+ code: "ucp/insecure-terms-url",
19
+ detail: `a terms link must be HTTPS — an http: reference is rewritable in transit: ${ref.value}`,
20
+ };
21
+ }
22
+
9
23
  /**
10
24
  * The UCP reference placement — the kit plus ONE protocol rule the kit cannot know.
11
25
  *
@@ -19,9 +33,18 @@ const base = makePlacement(UCP_PLACEMENT);
19
33
  * behind a reference the record cites.
20
34
  *
21
35
  * This is the composition the kit is shaped for — generic mechanics, protocol-specific semantics layered on
22
- * top —
23
- * and it wraps `extract`, not `place`: `place` never writes the links alias (the terms URL is the
24
- * DEPLOYMENT's datum, not the reference see the manifest), so the write side has no URL to police.
36
+ * top — and it wraps BOTH directions, because the rule is about the carrier and both directions carry one.
37
+ *
38
+ * It wrapped `extract` alone until 2026-09-03, under the reasoning that "`place` never writes the links
39
+ * alias, so the write side has no URL to police". That was already false when it was written and became
40
+ * more so: the policies entry `place` writes carries the reference itself, `url` is a permitted carrier
41
+ * type here, and the kit's own terms-URL slot landed on the same entry. So `place` accepted an `http:`
42
+ * reference and emitted a document this very module's `extract` refuses — a placement that will not read
43
+ * back the bytes it wrote, and a round trip that fails on our own output rather than on a counterparty's.
44
+ * A url-typed reference inside a policies entry is exactly as rewritable in transit as one in `links`.
45
+ *
46
+ * The terms URL was never the gap: the kit already refuses a non-https `termsUrl` at
47
+ * `ucp/terms-url-malformed`. The REFERENCE was.
25
48
  *
26
49
  * **Scoped to url-typed results, deliberately.** A sha256 answer must never be blocked by a bad link sitting
27
50
  * beside it — the capability WINS over links, and refusing the winner for the loser's defect would invert the
@@ -31,17 +54,14 @@ const base = makePlacement(UCP_PLACEMENT);
31
54
  */
32
55
  export const ucpPlacement: ReferencePlacementAdapter = {
33
56
  ...base,
57
+ place(ad: LegalContextAdvertisement, doc: unknown) {
58
+ // BEFORE the kit writes: a document that has already been written into is a document a caller may
59
+ // reasonably send, and refusing after building it would make the refusal advisory.
60
+ return insecureTermsUrl(ad.ref) ?? base.place(ad, doc);
61
+ },
34
62
  extract(doc: unknown) {
35
63
  const out = base.extract(doc);
36
64
  if ("refused" in out) return out;
37
- const { ref } = out.value;
38
- if (ref.type === "url" && !ref.value.startsWith("https://"))
39
- return {
40
- refused: true,
41
- haltClass: "verification-failure",
42
- code: "ucp/insecure-terms-url",
43
- detail: `a terms link must be HTTPS — an http: reference is rewritable in transit: ${ref.value}`,
44
- };
45
- return out;
65
+ return insecureTermsUrl(out.value.ref) ?? out;
46
66
  },
47
67
  };