feat(helm): template authCaptureUnlock so the paid unlock gate survives a sync - #818

Open
bussyjd wants to merge 1 commit into
mainfrom
feat/helm-authcapture-unlock
Open

feat(helm): template authCaptureUnlock so the paid unlock gate survives a sync#818
bussyjd wants to merge 1 commit into
mainfrom
feat/helm-authcapture-unlock

Conversation

@bussyjd

Copy link
Copy Markdown
Contributor

Problem

x402-pricing is a Helm-managed static ConfigMap (internal/embed/infrastructure/base/templates/x402.yaml) shipping routes: [] and no authCaptureUnlock. The only way to turn the paid unlock gate on was to patch the live ConfigMap by hand — which the next obol stack up reverts to the chart default, silently disabling the fee split.

This is not hypothetical. On a live stack the ConfigMap's last-applied-configuration still carries a fully configured canary:

authCaptureUnlock:
enabled: trueofferPrefix: "/services/authcap-canary"price: "0.01"minFeeBps: 50maxFeeBps: 50

…while the live data is the untouched chart default. The configured fee address holds exactly 0.000050 USDC — precisely 50 bps of one 0.01 unlock — and nothing since. The mechanism worked; a reconcile turned it off and nobody noticed.

Change

authCaptureUnlock and facilitatorURL now render from values, defaulted off in both base/values.yaml and the helmfile's state values, and passed through to the base release.

With the defaults the rendered pricing.yaml is byte-identical to what ships today, so no existing stack changes behaviour.

facilitatorURL is templated in the same change because it is load-bearing for this feature — see below.

The mainnet trap

The hosted facilitator advertises auth-capture on Base Sepolia only. Straight from its /supported:

auth-capture @ eip155:84532 ← testnet only
batch-settlement @ eip155:8453
exact @ eip155:8453

So enabling the unlock on network: base while pointed at https://x402.gcp.obol.tech lands on a facilitator that cannot settle the scheme. Mainnet needs the in-cluster sidecar (http://localhost:8090), whose config declares v2-eip155-auth-capture for eip155:8453 — which is exactly how the canary worked.

Worth flagging: the rc2 notes said the hosted facilitator made the gate "usable on this release". True for testnet, not mainnet. The docs added here state the constraint explicitly.

Docs

The seller-facing x402-pricing.md reference had no mention of this feature at all, which is why it has been read as "an opt-in platform fee on everything the seller receives".

It isn't. It turns onegate: auth offer from free wallet sign-in into pay-once-to-mint-a-session, and splits that single payment two ways. It does not apply to normal paid requests, and it cannot route a share to an upstream provider — the split has exactly two legs (payTo, feeRecipient) and fires only on the unlock.

The doc also records both current ceilings, so they stop being rediscovered:

  • One unlock offer per stackofferPrefix is global, matched by exact string comparison (unlockgate.go:23).
  • Per-offer config is impossible todayServiceOfferPayment.Scheme is +kubebuilder:validation:Enum=exact, with TODO(auth-capture) above it (monetizeapi/types.go:307).

Verification

  • helm template with defaults reproduces the current pricing.yaml byte-for-byte.
  • With the canary values it reproduces the exact config that produced the real on-chain fee.
  • The CI helm-template-smoke command (placeholder substitution + full chart render) exits 0 at 3407 lines.
  • go build ./... and go test ./internal/embed/... ./internal/x402/... pass.

Not in scope

Per-offer authCaptureUnlock via the CRD, which the TODO(auth-capture) names as the follow-up.

…es a sync
x402-pricing is a Helm-managed static ConfigMap that ships `routes: []` and
no authCaptureUnlock. The only way to turn the unlock gate on was to patch
the live ConfigMap by hand — which the next `obol stack up` reverts to the
chart default, silently disabling the fee split.
That already happened on a live stack: the ConfigMap's
last-applied-configuration still carries a fully configured canary
(offerPrefix /services/authcap-canary, 50/50 bps) while the live data is the
untouched chart default. The fee address collected exactly one payment —
0.000050 USDC, precisely 50 bps of one 0.01 unlock — and nothing since.
authCaptureUnlock and facilitatorURL now render from values, defaulted off
in both base/values.yaml and the helmfile's state values, and passed through
to the base release. With the defaults the rendered pricing.yaml is
byte-identical to what ships today, so no existing stack changes behaviour.
facilitatorURL is templated in the same change because it is load-bearing
for this feature: the hosted facilitator advertises auth-capture on Base
Sepolia ONLY (eip155:84532, confirmed against its /supported), so a mainnet
unlock must point at the in-cluster sidecar on :8090. Enabling the gate
without that lands you on a facilitator that cannot settle the scheme.
Also documents the feature in the seller-facing x402-pricing reference,
which had no mention of it at all. That gap is why it has been read as "an
opt-in platform fee on everything the seller receives". It is not: it turns
ONE `gate: auth` offer from free wallet sign-in into pay-once-to-mint-a-
session, and splits that single payment two ways. It cannot route a share to
an upstream provider. The doc records both current ceilings — one unlock
offer per stack, and ServiceOffer.scheme being enum=exact so per-offer
config is impossible today.
Verified: `helm template` with defaults reproduces the current pricing.yaml
byte-for-byte; with the canary values it reproduces the exact config that
produced the real on-chain fee; and the CI helm-template-smoke command
renders the whole chart clean (3407 lines, exit 0).
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@bussyjd
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

feat(helm): template authCaptureUnlock so the paid unlock gate survives a sync - #818

Open
bussyjd wants to merge 1 commit into
mainfrom
feat/helm-authcapture-unlock
Open

feat(helm): template authCaptureUnlock so the paid unlock gate survives a sync#818
bussyjd wants to merge 1 commit into
mainfrom
feat/helm-authcapture-unlock

Conversation

@bussyjd

Copy link
Copy Markdown
Contributor

Problem

x402-pricing is a Helm-managed static ConfigMap (internal/embed/infrastructure/base/templates/x402.yaml) shipping routes: [] and no authCaptureUnlock. The only way to turn the paid unlock gate on was to patch the live ConfigMap by hand — which the next obol stack up reverts to the chart default, silently disabling the fee split.

This is not hypothetical. On a live stack the ConfigMap's last-applied-configuration still carries a fully configured canary:

authCaptureUnlock:
enabled: trueofferPrefix: "/services/authcap-canary"price: "0.01"minFeeBps: 50maxFeeBps: 50

…while the live data is the untouched chart default. The configured fee address holds exactly 0.000050 USDC — precisely 50 bps of one 0.01 unlock — and nothing since. The mechanism worked; a reconcile turned it off and nobody noticed.

Change

authCaptureUnlock and facilitatorURL now render from values, defaulted off in both base/values.yaml and the helmfile's state values, and passed through to the base release.

With the defaults the rendered pricing.yaml is byte-identical to what ships today, so no existing stack changes behaviour.

facilitatorURL is templated in the same change because it is load-bearing for this feature — see below.

The mainnet trap

The hosted facilitator advertises auth-capture on Base Sepolia only. Straight from its /supported:

auth-capture @ eip155:84532 ← testnet only
batch-settlement @ eip155:8453
exact @ eip155:8453

So enabling the unlock on network: base while pointed at https://x402.gcp.obol.tech lands on a facilitator that cannot settle the scheme. Mainnet needs the in-cluster sidecar (http://localhost:8090), whose config declares v2-eip155-auth-capture for eip155:8453 — which is exactly how the canary worked.

Worth flagging: the rc2 notes said the hosted facilitator made the gate "usable on this release". True for testnet, not mainnet. The docs added here state the constraint explicitly.

Docs

The seller-facing x402-pricing.md reference had no mention of this feature at all, which is why it has been read as "an opt-in platform fee on everything the seller receives".

It isn't. It turns onegate: auth offer from free wallet sign-in into pay-once-to-mint-a-session, and splits that single payment two ways. It does not apply to normal paid requests, and it cannot route a share to an upstream provider — the split has exactly two legs (payTo, feeRecipient) and fires only on the unlock.

The doc also records both current ceilings, so they stop being rediscovered:

  • One unlock offer per stackofferPrefix is global, matched by exact string comparison (unlockgate.go:23).
  • Per-offer config is impossible todayServiceOfferPayment.Scheme is +kubebuilder:validation:Enum=exact, with TODO(auth-capture) above it (monetizeapi/types.go:307).

Verification

  • helm template with defaults reproduces the current pricing.yaml byte-for-byte.
  • With the canary values it reproduces the exact config that produced the real on-chain fee.
  • The CI helm-template-smoke command (placeholder substitution + full chart render) exits 0 at 3407 lines.
  • go build ./... and go test ./internal/embed/... ./internal/x402/... pass.

Not in scope

Per-offer authCaptureUnlock via the CRD, which the TODO(auth-capture) names as the follow-up.

…es a sync
x402-pricing is a Helm-managed static ConfigMap that ships `routes: []` and
no authCaptureUnlock. The only way to turn the unlock gate on was to patch
the live ConfigMap by hand — which the next `obol stack up` reverts to the
chart default, silently disabling the fee split.
That already happened on a live stack: the ConfigMap's
last-applied-configuration still carries a fully configured canary
(offerPrefix /services/authcap-canary, 50/50 bps) while the live data is the
untouched chart default. The fee address collected exactly one payment —
0.000050 USDC, precisely 50 bps of one 0.01 unlock — and nothing since.
authCaptureUnlock and facilitatorURL now render from values, defaulted off
in both base/values.yaml and the helmfile's state values, and passed through
to the base release. With the defaults the rendered pricing.yaml is
byte-identical to what ships today, so no existing stack changes behaviour.
facilitatorURL is templated in the same change because it is load-bearing
for this feature: the hosted facilitator advertises auth-capture on Base
Sepolia ONLY (eip155:84532, confirmed against its /supported), so a mainnet
unlock must point at the in-cluster sidecar on :8090. Enabling the gate
without that lands you on a facilitator that cannot settle the scheme.
Also documents the feature in the seller-facing x402-pricing reference,
which had no mention of it at all. That gap is why it has been read as "an
opt-in platform fee on everything the seller receives". It is not: it turns
ONE `gate: auth` offer from free wallet sign-in into pay-once-to-mint-a-
session, and splits that single payment two ways. It cannot route a share to
an upstream provider. The doc records both current ceilings — one unlock
offer per stack, and ServiceOffer.scheme being enum=exact so per-offer
config is impossible today.
Verified: `helm template` with defaults reproduces the current pricing.yaml
byte-for-byte; with the canary values it reproduces the exact config that
produced the real on-chain fee; and the CI helm-template-smoke command
renders the whole chart clean (3407 lines, exit 0).
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@bussyjd
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(helm): template authCaptureUnlock so the paid unlock gate survives a sync - #818

Open
bussyjd wants to merge 1 commit into
mainfrom
feat/helm-authcapture-unlock
Open

feat(helm): template authCaptureUnlock so the paid unlock gate survives a sync#818
bussyjd wants to merge 1 commit into
mainfrom
feat/helm-authcapture-unlock

Conversation

@bussyjd

Copy link
Copy Markdown
Contributor

Problem

x402-pricing is a Helm-managed static ConfigMap (internal/embed/infrastructure/base/templates/x402.yaml) shipping routes: [] and no authCaptureUnlock. The only way to turn the paid unlock gate on was to patch the live ConfigMap by hand — which the next obol stack up reverts to the chart default, silently disabling the fee split.

This is not hypothetical. On a live stack the ConfigMap's last-applied-configuration still carries a fully configured canary:

authCaptureUnlock:
enabled: trueofferPrefix: "/services/authcap-canary"price: "0.01"minFeeBps: 50maxFeeBps: 50

…while the live data is the untouched chart default. The configured fee address holds exactly 0.000050 USDC — precisely 50 bps of one 0.01 unlock — and nothing since. The mechanism worked; a reconcile turned it off and nobody noticed.

Change

authCaptureUnlock and facilitatorURL now render from values, defaulted off in both base/values.yaml and the helmfile's state values, and passed through to the base release.

With the defaults the rendered pricing.yaml is byte-identical to what ships today, so no existing stack changes behaviour.

facilitatorURL is templated in the same change because it is load-bearing for this feature — see below.

The mainnet trap

The hosted facilitator advertises auth-capture on Base Sepolia only. Straight from its /supported:

auth-capture @ eip155:84532 ← testnet only
batch-settlement @ eip155:8453
exact @ eip155:8453

So enabling the unlock on network: base while pointed at https://x402.gcp.obol.tech lands on a facilitator that cannot settle the scheme. Mainnet needs the in-cluster sidecar (http://localhost:8090), whose config declares v2-eip155-auth-capture for eip155:8453 — which is exactly how the canary worked.

Worth flagging: the rc2 notes said the hosted facilitator made the gate "usable on this release". True for testnet, not mainnet. The docs added here state the constraint explicitly.

Docs

The seller-facing x402-pricing.md reference had no mention of this feature at all, which is why it has been read as "an opt-in platform fee on everything the seller receives".

It isn't. It turns onegate: auth offer from free wallet sign-in into pay-once-to-mint-a-session, and splits that single payment two ways. It does not apply to normal paid requests, and it cannot route a share to an upstream provider — the split has exactly two legs (payTo, feeRecipient) and fires only on the unlock.

The doc also records both current ceilings, so they stop being rediscovered:

  • One unlock offer per stackofferPrefix is global, matched by exact string comparison (unlockgate.go:23).
  • Per-offer config is impossible todayServiceOfferPayment.Scheme is +kubebuilder:validation:Enum=exact, with TODO(auth-capture) above it (monetizeapi/types.go:307).

Verification

  • helm template with defaults reproduces the current pricing.yaml byte-for-byte.
  • With the canary values it reproduces the exact config that produced the real on-chain fee.
  • The CI helm-template-smoke command (placeholder substitution + full chart render) exits 0 at 3407 lines.
  • go build ./... and go test ./internal/embed/... ./internal/x402/... pass.

Not in scope

Per-offer authCaptureUnlock via the CRD, which the TODO(auth-capture) names as the follow-up.

…es a sync
x402-pricing is a Helm-managed static ConfigMap that ships `routes: []` and
no authCaptureUnlock. The only way to turn the unlock gate on was to patch
the live ConfigMap by hand — which the next `obol stack up` reverts to the
chart default, silently disabling the fee split.
That already happened on a live stack: the ConfigMap's
last-applied-configuration still carries a fully configured canary
(offerPrefix /services/authcap-canary, 50/50 bps) while the live data is the
untouched chart default. The fee address collected exactly one payment —
0.000050 USDC, precisely 50 bps of one 0.01 unlock — and nothing since.
authCaptureUnlock and facilitatorURL now render from values, defaulted off
in both base/values.yaml and the helmfile's state values, and passed through
to the base release. With the defaults the rendered pricing.yaml is
byte-identical to what ships today, so no existing stack changes behaviour.
facilitatorURL is templated in the same change because it is load-bearing
for this feature: the hosted facilitator advertises auth-capture on Base
Sepolia ONLY (eip155:84532, confirmed against its /supported), so a mainnet
unlock must point at the in-cluster sidecar on :8090. Enabling the gate
without that lands you on a facilitator that cannot settle the scheme.
Also documents the feature in the seller-facing x402-pricing reference,
which had no mention of it at all. That gap is why it has been read as "an
opt-in platform fee on everything the seller receives". It is not: it turns
ONE `gate: auth` offer from free wallet sign-in into pay-once-to-mint-a-
session, and splits that single payment two ways. It cannot route a share to
an upstream provider. The doc records both current ceilings — one unlock
offer per stack, and ServiceOffer.scheme being enum=exact so per-offer
config is impossible today.
Verified: `helm template` with defaults reproduces the current pricing.yaml
byte-for-byte; with the canary values it reproduces the exact config that
produced the real on-chain fee; and the CI helm-template-smoke command
renders the whole chart clean (3407 lines, exit 0).
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@bussyjd
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(helm): template authCaptureUnlock so the paid unlock gate survives a sync - #818

Open
bussyjd wants to merge 1 commit into
mainfrom
feat/helm-authcapture-unlock
Open

feat(helm): template authCaptureUnlock so the paid unlock gate survives a sync#818
bussyjd wants to merge 1 commit into
mainfrom
feat/helm-authcapture-unlock

Conversation

@bussyjd

Copy link
Copy Markdown
Contributor

Problem

x402-pricing is a Helm-managed static ConfigMap (internal/embed/infrastructure/base/templates/x402.yaml) shipping routes: [] and no authCaptureUnlock. The only way to turn the paid unlock gate on was to patch the live ConfigMap by hand — which the next obol stack up reverts to the chart default, silently disabling the fee split.

This is not hypothetical. On a live stack the ConfigMap's last-applied-configuration still carries a fully configured canary:

authCaptureUnlock:
enabled: trueofferPrefix: "/services/authcap-canary"price: "0.01"minFeeBps: 50maxFeeBps: 50

…while the live data is the untouched chart default. The configured fee address holds exactly 0.000050 USDC — precisely 50 bps of one 0.01 unlock — and nothing since. The mechanism worked; a reconcile turned it off and nobody noticed.

Change

authCaptureUnlock and facilitatorURL now render from values, defaulted off in both base/values.yaml and the helmfile's state values, and passed through to the base release.

With the defaults the rendered pricing.yaml is byte-identical to what ships today, so no existing stack changes behaviour.

facilitatorURL is templated in the same change because it is load-bearing for this feature — see below.

The mainnet trap

The hosted facilitator advertises auth-capture on Base Sepolia only. Straight from its /supported:

auth-capture @ eip155:84532 ← testnet only
batch-settlement @ eip155:8453
exact @ eip155:8453

So enabling the unlock on network: base while pointed at https://x402.gcp.obol.tech lands on a facilitator that cannot settle the scheme. Mainnet needs the in-cluster sidecar (http://localhost:8090), whose config declares v2-eip155-auth-capture for eip155:8453 — which is exactly how the canary worked.

Worth flagging: the rc2 notes said the hosted facilitator made the gate "usable on this release". True for testnet, not mainnet. The docs added here state the constraint explicitly.

Docs

The seller-facing x402-pricing.md reference had no mention of this feature at all, which is why it has been read as "an opt-in platform fee on everything the seller receives".

It isn't. It turns onegate: auth offer from free wallet sign-in into pay-once-to-mint-a-session, and splits that single payment two ways. It does not apply to normal paid requests, and it cannot route a share to an upstream provider — the split has exactly two legs (payTo, feeRecipient) and fires only on the unlock.

The doc also records both current ceilings, so they stop being rediscovered:

  • One unlock offer per stackofferPrefix is global, matched by exact string comparison (unlockgate.go:23).
  • Per-offer config is impossible todayServiceOfferPayment.Scheme is +kubebuilder:validation:Enum=exact, with TODO(auth-capture) above it (monetizeapi/types.go:307).

Verification

  • helm template with defaults reproduces the current pricing.yaml byte-for-byte.
  • With the canary values it reproduces the exact config that produced the real on-chain fee.
  • The CI helm-template-smoke command (placeholder substitution + full chart render) exits 0 at 3407 lines.
  • go build ./... and go test ./internal/embed/... ./internal/x402/... pass.

Not in scope

Per-offer authCaptureUnlock via the CRD, which the TODO(auth-capture) names as the follow-up.

…es a sync
x402-pricing is a Helm-managed static ConfigMap that ships `routes: []` and
no authCaptureUnlock. The only way to turn the unlock gate on was to patch
the live ConfigMap by hand — which the next `obol stack up` reverts to the
chart default, silently disabling the fee split.
That already happened on a live stack: the ConfigMap's
last-applied-configuration still carries a fully configured canary
(offerPrefix /services/authcap-canary, 50/50 bps) while the live data is the
untouched chart default. The fee address collected exactly one payment —
0.000050 USDC, precisely 50 bps of one 0.01 unlock — and nothing since.
authCaptureUnlock and facilitatorURL now render from values, defaulted off
in both base/values.yaml and the helmfile's state values, and passed through
to the base release. With the defaults the rendered pricing.yaml is
byte-identical to what ships today, so no existing stack changes behaviour.
facilitatorURL is templated in the same change because it is load-bearing
for this feature: the hosted facilitator advertises auth-capture on Base
Sepolia ONLY (eip155:84532, confirmed against its /supported), so a mainnet
unlock must point at the in-cluster sidecar on :8090. Enabling the gate
without that lands you on a facilitator that cannot settle the scheme.
Also documents the feature in the seller-facing x402-pricing reference,
which had no mention of it at all. That gap is why it has been read as "an
opt-in platform fee on everything the seller receives". It is not: it turns
ONE `gate: auth` offer from free wallet sign-in into pay-once-to-mint-a-
session, and splits that single payment two ways. It cannot route a share to
an upstream provider. The doc records both current ceilings — one unlock
offer per stack, and ServiceOffer.scheme being enum=exact so per-offer
config is impossible today.
Verified: `helm template` with defaults reproduces the current pricing.yaml
byte-for-byte; with the canary values it reproduces the exact config that
produced the real on-chain fee; and the CI helm-template-smoke command
renders the whole chart clean (3407 lines, exit 0).
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@bussyjd
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

feat(helm): template authCaptureUnlock so the paid unlock gate survives a sync - #818

Open
bussyjd wants to merge 1 commit into
mainfrom
feat/helm-authcapture-unlock
Open

feat(helm): template authCaptureUnlock so the paid unlock gate survives a sync#818
bussyjd wants to merge 1 commit into
mainfrom
feat/helm-authcapture-unlock

Conversation

@bussyjd

Copy link
Copy Markdown
Contributor

Problem

x402-pricing is a Helm-managed static ConfigMap (internal/embed/infrastructure/base/templates/x402.yaml) shipping routes: [] and no authCaptureUnlock. The only way to turn the paid unlock gate on was to patch the live ConfigMap by hand — which the next obol stack up reverts to the chart default, silently disabling the fee split.

This is not hypothetical. On a live stack the ConfigMap's last-applied-configuration still carries a fully configured canary:

authCaptureUnlock:
enabled: trueofferPrefix: "/services/authcap-canary"price: "0.01"minFeeBps: 50maxFeeBps: 50

…while the live data is the untouched chart default. The configured fee address holds exactly 0.000050 USDC — precisely 50 bps of one 0.01 unlock — and nothing since. The mechanism worked; a reconcile turned it off and nobody noticed.

Change

authCaptureUnlock and facilitatorURL now render from values, defaulted off in both base/values.yaml and the helmfile's state values, and passed through to the base release.

With the defaults the rendered pricing.yaml is byte-identical to what ships today, so no existing stack changes behaviour.

facilitatorURL is templated in the same change because it is load-bearing for this feature — see below.

The mainnet trap

The hosted facilitator advertises auth-capture on Base Sepolia only. Straight from its /supported:

auth-capture @ eip155:84532 ← testnet only
batch-settlement @ eip155:8453
exact @ eip155:8453

So enabling the unlock on network: base while pointed at https://x402.gcp.obol.tech lands on a facilitator that cannot settle the scheme. Mainnet needs the in-cluster sidecar (http://localhost:8090), whose config declares v2-eip155-auth-capture for eip155:8453 — which is exactly how the canary worked.

Worth flagging: the rc2 notes said the hosted facilitator made the gate "usable on this release". True for testnet, not mainnet. The docs added here state the constraint explicitly.

Docs

The seller-facing x402-pricing.md reference had no mention of this feature at all, which is why it has been read as "an opt-in platform fee on everything the seller receives".

It isn't. It turns onegate: auth offer from free wallet sign-in into pay-once-to-mint-a-session, and splits that single payment two ways. It does not apply to normal paid requests, and it cannot route a share to an upstream provider — the split has exactly two legs (payTo, feeRecipient) and fires only on the unlock.

The doc also records both current ceilings, so they stop being rediscovered:

  • One unlock offer per stackofferPrefix is global, matched by exact string comparison (unlockgate.go:23).
  • Per-offer config is impossible todayServiceOfferPayment.Scheme is +kubebuilder:validation:Enum=exact, with TODO(auth-capture) above it (monetizeapi/types.go:307).

Verification

  • helm template with defaults reproduces the current pricing.yaml byte-for-byte.
  • With the canary values it reproduces the exact config that produced the real on-chain fee.
  • The CI helm-template-smoke command (placeholder substitution + full chart render) exits 0 at 3407 lines.
  • go build ./... and go test ./internal/embed/... ./internal/x402/... pass.

Not in scope

Per-offer authCaptureUnlock via the CRD, which the TODO(auth-capture) names as the follow-up.

…es a sync
x402-pricing is a Helm-managed static ConfigMap that ships `routes: []` and
no authCaptureUnlock. The only way to turn the unlock gate on was to patch
the live ConfigMap by hand — which the next `obol stack up` reverts to the
chart default, silently disabling the fee split.
That already happened on a live stack: the ConfigMap's
last-applied-configuration still carries a fully configured canary
(offerPrefix /services/authcap-canary, 50/50 bps) while the live data is the
untouched chart default. The fee address collected exactly one payment —
0.000050 USDC, precisely 50 bps of one 0.01 unlock — and nothing since.
authCaptureUnlock and facilitatorURL now render from values, defaulted off
in both base/values.yaml and the helmfile's state values, and passed through
to the base release. With the defaults the rendered pricing.yaml is
byte-identical to what ships today, so no existing stack changes behaviour.
facilitatorURL is templated in the same change because it is load-bearing
for this feature: the hosted facilitator advertises auth-capture on Base
Sepolia ONLY (eip155:84532, confirmed against its /supported), so a mainnet
unlock must point at the in-cluster sidecar on :8090. Enabling the gate
without that lands you on a facilitator that cannot settle the scheme.
Also documents the feature in the seller-facing x402-pricing reference,
which had no mention of it at all. That gap is why it has been read as "an
opt-in platform fee on everything the seller receives". It is not: it turns
ONE `gate: auth` offer from free wallet sign-in into pay-once-to-mint-a-
session, and splits that single payment two ways. It cannot route a share to
an upstream provider. The doc records both current ceilings — one unlock
offer per stack, and ServiceOffer.scheme being enum=exact so per-offer
config is impossible today.
Verified: `helm template` with defaults reproduces the current pricing.yaml
byte-for-byte; with the canary values it reproduces the exact config that
produced the real on-chain fee; and the CI helm-template-smoke command
renders the whole chart clean (3407 lines, exit 0).
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@bussyjd
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(helm): template authCaptureUnlock so the paid unlock gate survives a sync - #818

Open
bussyjd wants to merge 1 commit into
mainfrom
feat/helm-authcapture-unlock
Open

feat(helm): template authCaptureUnlock so the paid unlock gate survives a sync#818
bussyjd wants to merge 1 commit into
mainfrom
feat/helm-authcapture-unlock

Conversation

@bussyjd

Copy link
Copy Markdown
Contributor

Problem

x402-pricing is a Helm-managed static ConfigMap (internal/embed/infrastructure/base/templates/x402.yaml) shipping routes: [] and no authCaptureUnlock. The only way to turn the paid unlock gate on was to patch the live ConfigMap by hand — which the next obol stack up reverts to the chart default, silently disabling the fee split.

This is not hypothetical. On a live stack the ConfigMap's last-applied-configuration still carries a fully configured canary:

authCaptureUnlock:
enabled: trueofferPrefix: "/services/authcap-canary"price: "0.01"minFeeBps: 50maxFeeBps: 50

…while the live data is the untouched chart default. The configured fee address holds exactly 0.000050 USDC — precisely 50 bps of one 0.01 unlock — and nothing since. The mechanism worked; a reconcile turned it off and nobody noticed.

Change

authCaptureUnlock and facilitatorURL now render from values, defaulted off in both base/values.yaml and the helmfile's state values, and passed through to the base release.

With the defaults the rendered pricing.yaml is byte-identical to what ships today, so no existing stack changes behaviour.

facilitatorURL is templated in the same change because it is load-bearing for this feature — see below.

The mainnet trap

The hosted facilitator advertises auth-capture on Base Sepolia only. Straight from its /supported:

auth-capture @ eip155:84532 ← testnet only
batch-settlement @ eip155:8453
exact @ eip155:8453

So enabling the unlock on network: base while pointed at https://x402.gcp.obol.tech lands on a facilitator that cannot settle the scheme. Mainnet needs the in-cluster sidecar (http://localhost:8090), whose config declares v2-eip155-auth-capture for eip155:8453 — which is exactly how the canary worked.

Worth flagging: the rc2 notes said the hosted facilitator made the gate "usable on this release". True for testnet, not mainnet. The docs added here state the constraint explicitly.

Docs

The seller-facing x402-pricing.md reference had no mention of this feature at all, which is why it has been read as "an opt-in platform fee on everything the seller receives".

It isn't. It turns onegate: auth offer from free wallet sign-in into pay-once-to-mint-a-session, and splits that single payment two ways. It does not apply to normal paid requests, and it cannot route a share to an upstream provider — the split has exactly two legs (payTo, feeRecipient) and fires only on the unlock.

The doc also records both current ceilings, so they stop being rediscovered:

  • One unlock offer per stackofferPrefix is global, matched by exact string comparison (unlockgate.go:23).
  • Per-offer config is impossible todayServiceOfferPayment.Scheme is +kubebuilder:validation:Enum=exact, with TODO(auth-capture) above it (monetizeapi/types.go:307).

Verification

  • helm template with defaults reproduces the current pricing.yaml byte-for-byte.
  • With the canary values it reproduces the exact config that produced the real on-chain fee.
  • The CI helm-template-smoke command (placeholder substitution + full chart render) exits 0 at 3407 lines.
  • go build ./... and go test ./internal/embed/... ./internal/x402/... pass.

Not in scope

Per-offer authCaptureUnlock via the CRD, which the TODO(auth-capture) names as the follow-up.

…es a sync
x402-pricing is a Helm-managed static ConfigMap that ships `routes: []` and
no authCaptureUnlock. The only way to turn the unlock gate on was to patch
the live ConfigMap by hand — which the next `obol stack up` reverts to the
chart default, silently disabling the fee split.
That already happened on a live stack: the ConfigMap's
last-applied-configuration still carries a fully configured canary
(offerPrefix /services/authcap-canary, 50/50 bps) while the live data is the
untouched chart default. The fee address collected exactly one payment —
0.000050 USDC, precisely 50 bps of one 0.01 unlock — and nothing since.
authCaptureUnlock and facilitatorURL now render from values, defaulted off
in both base/values.yaml and the helmfile's state values, and passed through
to the base release. With the defaults the rendered pricing.yaml is
byte-identical to what ships today, so no existing stack changes behaviour.
facilitatorURL is templated in the same change because it is load-bearing
for this feature: the hosted facilitator advertises auth-capture on Base
Sepolia ONLY (eip155:84532, confirmed against its /supported), so a mainnet
unlock must point at the in-cluster sidecar on :8090. Enabling the gate
without that lands you on a facilitator that cannot settle the scheme.
Also documents the feature in the seller-facing x402-pricing reference,
which had no mention of it at all. That gap is why it has been read as "an
opt-in platform fee on everything the seller receives". It is not: it turns
ONE `gate: auth` offer from free wallet sign-in into pay-once-to-mint-a-
session, and splits that single payment two ways. It cannot route a share to
an upstream provider. The doc records both current ceilings — one unlock
offer per stack, and ServiceOffer.scheme being enum=exact so per-offer
config is impossible today.
Verified: `helm template` with defaults reproduces the current pricing.yaml
byte-for-byte; with the canary values it reproduces the exact config that
produced the real on-chain fee; and the CI helm-template-smoke command
renders the whole chart clean (3407 lines, exit 0).
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@bussyjd
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(helm): template authCaptureUnlock so the paid unlock gate survives a sync - #818

Open
bussyjd wants to merge 1 commit into
mainfrom
feat/helm-authcapture-unlock
Open

feat(helm): template authCaptureUnlock so the paid unlock gate survives a sync#818
bussyjd wants to merge 1 commit into
mainfrom
feat/helm-authcapture-unlock

Conversation

@bussyjd

Copy link
Copy Markdown
Contributor

Problem

x402-pricing is a Helm-managed static ConfigMap (internal/embed/infrastructure/base/templates/x402.yaml) shipping routes: [] and no authCaptureUnlock. The only way to turn the paid unlock gate on was to patch the live ConfigMap by hand — which the next obol stack up reverts to the chart default, silently disabling the fee split.

This is not hypothetical. On a live stack the ConfigMap's last-applied-configuration still carries a fully configured canary:

authCaptureUnlock:
enabled: trueofferPrefix: "/services/authcap-canary"price: "0.01"minFeeBps: 50maxFeeBps: 50

…while the live data is the untouched chart default. The configured fee address holds exactly 0.000050 USDC — precisely 50 bps of one 0.01 unlock — and nothing since. The mechanism worked; a reconcile turned it off and nobody noticed.

Change

authCaptureUnlock and facilitatorURL now render from values, defaulted off in both base/values.yaml and the helmfile's state values, and passed through to the base release.

With the defaults the rendered pricing.yaml is byte-identical to what ships today, so no existing stack changes behaviour.

facilitatorURL is templated in the same change because it is load-bearing for this feature — see below.

The mainnet trap

The hosted facilitator advertises auth-capture on Base Sepolia only. Straight from its /supported:

auth-capture @ eip155:84532 ← testnet only
batch-settlement @ eip155:8453
exact @ eip155:8453

So enabling the unlock on network: base while pointed at https://x402.gcp.obol.tech lands on a facilitator that cannot settle the scheme. Mainnet needs the in-cluster sidecar (http://localhost:8090), whose config declares v2-eip155-auth-capture for eip155:8453 — which is exactly how the canary worked.

Worth flagging: the rc2 notes said the hosted facilitator made the gate "usable on this release". True for testnet, not mainnet. The docs added here state the constraint explicitly.

Docs

The seller-facing x402-pricing.md reference had no mention of this feature at all, which is why it has been read as "an opt-in platform fee on everything the seller receives".

It isn't. It turns onegate: auth offer from free wallet sign-in into pay-once-to-mint-a-session, and splits that single payment two ways. It does not apply to normal paid requests, and it cannot route a share to an upstream provider — the split has exactly two legs (payTo, feeRecipient) and fires only on the unlock.

The doc also records both current ceilings, so they stop being rediscovered:

  • One unlock offer per stackofferPrefix is global, matched by exact string comparison (unlockgate.go:23).
  • Per-offer config is impossible todayServiceOfferPayment.Scheme is +kubebuilder:validation:Enum=exact, with TODO(auth-capture) above it (monetizeapi/types.go:307).

Verification

  • helm template with defaults reproduces the current pricing.yaml byte-for-byte.
  • With the canary values it reproduces the exact config that produced the real on-chain fee.
  • The CI helm-template-smoke command (placeholder substitution + full chart render) exits 0 at 3407 lines.
  • go build ./... and go test ./internal/embed/... ./internal/x402/... pass.

Not in scope

Per-offer authCaptureUnlock via the CRD, which the TODO(auth-capture) names as the follow-up.

…es a sync
x402-pricing is a Helm-managed static ConfigMap that ships `routes: []` and
no authCaptureUnlock. The only way to turn the unlock gate on was to patch
the live ConfigMap by hand — which the next `obol stack up` reverts to the
chart default, silently disabling the fee split.
That already happened on a live stack: the ConfigMap's
last-applied-configuration still carries a fully configured canary
(offerPrefix /services/authcap-canary, 50/50 bps) while the live data is the
untouched chart default. The fee address collected exactly one payment —
0.000050 USDC, precisely 50 bps of one 0.01 unlock — and nothing since.
authCaptureUnlock and facilitatorURL now render from values, defaulted off
in both base/values.yaml and the helmfile's state values, and passed through
to the base release. With the defaults the rendered pricing.yaml is
byte-identical to what ships today, so no existing stack changes behaviour.
facilitatorURL is templated in the same change because it is load-bearing
for this feature: the hosted facilitator advertises auth-capture on Base
Sepolia ONLY (eip155:84532, confirmed against its /supported), so a mainnet
unlock must point at the in-cluster sidecar on :8090. Enabling the gate
without that lands you on a facilitator that cannot settle the scheme.
Also documents the feature in the seller-facing x402-pricing reference,
which had no mention of it at all. That gap is why it has been read as "an
opt-in platform fee on everything the seller receives". It is not: it turns
ONE `gate: auth` offer from free wallet sign-in into pay-once-to-mint-a-
session, and splits that single payment two ways. It cannot route a share to
an upstream provider. The doc records both current ceilings — one unlock
offer per stack, and ServiceOffer.scheme being enum=exact so per-offer
config is impossible today.
Verified: `helm template` with defaults reproduces the current pricing.yaml
byte-for-byte; with the canary values it reproduces the exact config that
produced the real on-chain fee; and the CI helm-template-smoke command
renders the whole chart clean (3407 lines, exit 0).
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@bussyjd
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

feat(helm): template authCaptureUnlock so the paid unlock gate survives a sync - #818

Open
bussyjd wants to merge 1 commit into
mainfrom
feat/helm-authcapture-unlock
Open

feat(helm): template authCaptureUnlock so the paid unlock gate survives a sync#818
bussyjd wants to merge 1 commit into
mainfrom
feat/helm-authcapture-unlock

Conversation

@bussyjd

Copy link
Copy Markdown
Contributor

Problem

x402-pricing is a Helm-managed static ConfigMap (internal/embed/infrastructure/base/templates/x402.yaml) shipping routes: [] and no authCaptureUnlock. The only way to turn the paid unlock gate on was to patch the live ConfigMap by hand — which the next obol stack up reverts to the chart default, silently disabling the fee split.

This is not hypothetical. On a live stack the ConfigMap's last-applied-configuration still carries a fully configured canary:

authCaptureUnlock:
enabled: trueofferPrefix: "/services/authcap-canary"price: "0.01"minFeeBps: 50maxFeeBps: 50

…while the live data is the untouched chart default. The configured fee address holds exactly 0.000050 USDC — precisely 50 bps of one 0.01 unlock — and nothing since. The mechanism worked; a reconcile turned it off and nobody noticed.

Change

authCaptureUnlock and facilitatorURL now render from values, defaulted off in both base/values.yaml and the helmfile's state values, and passed through to the base release.

With the defaults the rendered pricing.yaml is byte-identical to what ships today, so no existing stack changes behaviour.

facilitatorURL is templated in the same change because it is load-bearing for this feature — see below.

The mainnet trap

The hosted facilitator advertises auth-capture on Base Sepolia only. Straight from its /supported:

auth-capture @ eip155:84532 ← testnet only
batch-settlement @ eip155:8453
exact @ eip155:8453

So enabling the unlock on network: base while pointed at https://x402.gcp.obol.tech lands on a facilitator that cannot settle the scheme. Mainnet needs the in-cluster sidecar (http://localhost:8090), whose config declares v2-eip155-auth-capture for eip155:8453 — which is exactly how the canary worked.

Worth flagging: the rc2 notes said the hosted facilitator made the gate "usable on this release". True for testnet, not mainnet. The docs added here state the constraint explicitly.

Docs

The seller-facing x402-pricing.md reference had no mention of this feature at all, which is why it has been read as "an opt-in platform fee on everything the seller receives".

It isn't. It turns onegate: auth offer from free wallet sign-in into pay-once-to-mint-a-session, and splits that single payment two ways. It does not apply to normal paid requests, and it cannot route a share to an upstream provider — the split has exactly two legs (payTo, feeRecipient) and fires only on the unlock.

The doc also records both current ceilings, so they stop being rediscovered:

  • One unlock offer per stackofferPrefix is global, matched by exact string comparison (unlockgate.go:23).
  • Per-offer config is impossible todayServiceOfferPayment.Scheme is +kubebuilder:validation:Enum=exact, with TODO(auth-capture) above it (monetizeapi/types.go:307).

Verification

  • helm template with defaults reproduces the current pricing.yaml byte-for-byte.
  • With the canary values it reproduces the exact config that produced the real on-chain fee.
  • The CI helm-template-smoke command (placeholder substitution + full chart render) exits 0 at 3407 lines.
  • go build ./... and go test ./internal/embed/... ./internal/x402/... pass.

Not in scope

Per-offer authCaptureUnlock via the CRD, which the TODO(auth-capture) names as the follow-up.

…es a sync
x402-pricing is a Helm-managed static ConfigMap that ships `routes: []` and
no authCaptureUnlock. The only way to turn the unlock gate on was to patch
the live ConfigMap by hand — which the next `obol stack up` reverts to the
chart default, silently disabling the fee split.
That already happened on a live stack: the ConfigMap's
last-applied-configuration still carries a fully configured canary
(offerPrefix /services/authcap-canary, 50/50 bps) while the live data is the
untouched chart default. The fee address collected exactly one payment —
0.000050 USDC, precisely 50 bps of one 0.01 unlock — and nothing since.
authCaptureUnlock and facilitatorURL now render from values, defaulted off
in both base/values.yaml and the helmfile's state values, and passed through
to the base release. With the defaults the rendered pricing.yaml is
byte-identical to what ships today, so no existing stack changes behaviour.
facilitatorURL is templated in the same change because it is load-bearing
for this feature: the hosted facilitator advertises auth-capture on Base
Sepolia ONLY (eip155:84532, confirmed against its /supported), so a mainnet
unlock must point at the in-cluster sidecar on :8090. Enabling the gate
without that lands you on a facilitator that cannot settle the scheme.
Also documents the feature in the seller-facing x402-pricing reference,
which had no mention of it at all. That gap is why it has been read as "an
opt-in platform fee on everything the seller receives". It is not: it turns
ONE `gate: auth` offer from free wallet sign-in into pay-once-to-mint-a-
session, and splits that single payment two ways. It cannot route a share to
an upstream provider. The doc records both current ceilings — one unlock
offer per stack, and ServiceOffer.scheme being enum=exact so per-offer
config is impossible today.
Verified: `helm template` with defaults reproduces the current pricing.yaml
byte-for-byte; with the canary values it reproduces the exact config that
produced the real on-chain fee; and the CI helm-template-smoke command
renders the whole chart clean (3407 lines, exit 0).
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@bussyjd