xytara 3.1.11 → 3.1.12
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/RELEASE_NOTES.md +4 -10
- package/lib/adapter_depth_contract.js +70 -8
- package/package.json +1 -1
- package/scripts/verify_provider_network.js +32 -1
- package/server.js +2 -2
package/RELEASE_NOTES.md
CHANGED
|
@@ -1,11 +1,5 @@
|
|
|
1
|
-
`xytara` 3.1.
|
|
1
|
+
`xytara` 3.1.12 makes the public adapter-depth surface report open-network providers truthfully.
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
-
|
|
6
|
-
- **Registration-scoped ledgers** — ledger rows and payouts belong to one registration of a `provider_id`. A removed and re-registered id never sees, inherits, or is credited by a previous owner's rows, and removal cancels that registration's pending payouts.
|
|
7
|
-
- **In-flight payout guard** — a payout being sent by the external signer cannot be cancelled mid-dispatch (so no freed reservation can ever be re-sent); a payout cancelled before a late tx report is reinstated for reconciliation instead of being lost.
|
|
8
|
-
- **One execution budget per call** — cold-start ride-out retries and failover candidates share a single wall-clock budget inside the x402 authorization window, and per-target timeouts are capped at 30s, so a routed call can always still settle.
|
|
9
|
-
- **Provider endpoint policy** — on hosted deploys, provider endpoints must be public `https` (loopback, private, link-local and metadata hosts are refused and re-checked by DNS at dispatch); redirects are never followed. Providers receive only a sanitized payment context — never the buyer's signed authorization.
|
|
10
|
-
- The MCP executor's bearer check is timing-safe and fails closed on a hosted deploy; adapter execution truth counts only enabled targets; rate-limit identity compares are timing-safe.
|
|
11
|
-
- Repository hygiene: a complete `.gitignore`, the publish workflow waits for the live deploy before registry publication, and `.env.example` documents every runtime knob.
|
|
3
|
+
- `/v1/adapter-depth` and `/v1/adapter-depth/summary` now count ACTIVE open-network providers that declared an adapter task as provider-live paths, alongside operator env targets. Each is labelled `routing: open_provider_registry`, and the pack lists its `depth_sources`. A pending provider never counts, and a provider is shown as shadowed (not counted) when an operator env target pins the whole lane, because env targets are routed first.
|
|
4
|
+
- Previously the surface only looked at env targets, so it reported `provider_wiring_required` even while paid MCP calls were being served by the live registry provider. It now reports `initial_provider_live_path` for the task that provider serves.
|
|
5
|
+
- Internal callers without runtime state keep the env-only view, so no other surface changes.
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
const packageJson = require("../package.json");
|
|
4
4
|
const { catalog } = require("../fixtures/catalog");
|
|
5
5
|
const { loadExecutionTargetRegistry } = require("./external_execution_runtime");
|
|
6
|
+
const { listProviders } = require("./provider_registry");
|
|
6
7
|
|
|
7
8
|
function normalizeString(value, fallback = "") {
|
|
8
9
|
const raw = typeof value === "string" ? value.trim() : "";
|
|
@@ -59,10 +60,60 @@ function summarizeTarget(target) {
|
|
|
59
60
|
};
|
|
60
61
|
}
|
|
61
62
|
|
|
62
|
-
|
|
63
|
-
|
|
63
|
+
// ACTIVE open-network providers that declared this task_ref. Env targets resolve before the
|
|
64
|
+
// registry at call time, so a provider is shadowed (not routed) when an enabled env target pins
|
|
65
|
+
// the WHOLE lane (task_ref with no tool/integration selector); it is then listed but not counted.
|
|
66
|
+
function listRegistryProvidersForTask(state, taskRef, envTargets) {
|
|
67
|
+
if (!state) return [];
|
|
68
|
+
const normalizedTaskRef = normalizeString(taskRef);
|
|
69
|
+
const wholeLanePinned = envTargets.some((target) =>
|
|
70
|
+
target.enabled !== false
|
|
71
|
+
&& normalizeString(target.task_ref) === normalizedTaskRef
|
|
72
|
+
&& !normalizeString(target.tool_name)
|
|
73
|
+
&& !normalizeString(target.integration_id)
|
|
74
|
+
);
|
|
75
|
+
return listProviders(state, { status: "active" })
|
|
76
|
+
.filter((provider) => Array.isArray(provider.task_refs) && provider.task_refs.includes(normalizedTaskRef))
|
|
77
|
+
.map((provider) => {
|
|
78
|
+
const health = (provider.health && provider.health.status) || "healthy";
|
|
79
|
+
return {
|
|
80
|
+
target_id: `registry:${provider.provider_id}`,
|
|
81
|
+
provider: provider.provider_id,
|
|
82
|
+
routing: "open_provider_registry",
|
|
83
|
+
task_ref: normalizedTaskRef,
|
|
84
|
+
tool_name: null,
|
|
85
|
+
tool_names: Array.isArray(provider.tool_names) ? provider.tool_names.slice() : [],
|
|
86
|
+
integration_id: null,
|
|
87
|
+
enabled: !wholeLanePinned,
|
|
88
|
+
shadowed_by_env_target: wholeLanePinned,
|
|
89
|
+
health_status: health,
|
|
90
|
+
timeout_ms: provider.timeout_ms,
|
|
91
|
+
endpoint_configured: Boolean(normalizeString(provider.endpoint_url)),
|
|
92
|
+
auth_configured: Boolean(normalizeString(provider.auth_token)),
|
|
93
|
+
operational_coverage: {
|
|
94
|
+
execute_endpoint: Boolean(normalizeString(provider.endpoint_url)),
|
|
95
|
+
bearer_auth: Boolean(normalizeString(provider.auth_token)),
|
|
96
|
+
bounded_timeout: Number(provider.timeout_ms || 0) >= 500,
|
|
97
|
+
// The provider-network execution contract fixes the deliverable shape
|
|
98
|
+
// (result.output / output_payload), and activation is operator-vetted against it.
|
|
99
|
+
proof_fact_compatible: true,
|
|
100
|
+
deterministic_retry_surface: true,
|
|
101
|
+
tool_level_binding: Array.isArray(provider.tool_names) && provider.tool_names.length > 0,
|
|
102
|
+
operator_health_surface: "runtime_tracked_provider_health",
|
|
103
|
+
operator_tool_catalog_surface: null
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function summarizeAdapterTaskDepth(task, state) {
|
|
110
|
+
const envTargets = listTargetsForTask(task.task_ref).map(summarizeTarget);
|
|
111
|
+
const registryTargets = listRegistryProvidersForTask(state, task.task_ref, loadExecutionTargetRegistry());
|
|
112
|
+
const targets = envTargets.concat(registryTargets);
|
|
64
113
|
const enabledTargets = targets.filter((target) => target.enabled);
|
|
65
|
-
const toolNames = Array.from(new Set(enabledTargets
|
|
114
|
+
const toolNames = Array.from(new Set(enabledTargets
|
|
115
|
+
.flatMap((target) => [target.tool_name].concat(target.tool_names || []))
|
|
116
|
+
.filter(Boolean))).sort();
|
|
66
117
|
const allTargetsCovered = enabledTargets.length > 0 && enabledTargets.every((target) =>
|
|
67
118
|
target.operational_coverage.execute_endpoint
|
|
68
119
|
&& target.operational_coverage.bounded_timeout
|
|
@@ -80,6 +131,8 @@ function summarizeAdapterTaskDepth(task) {
|
|
|
80
131
|
provider_live: enabledTargets.length > 0,
|
|
81
132
|
configured_target_count: targets.length,
|
|
82
133
|
enabled_target_count: enabledTargets.length,
|
|
134
|
+
env_target_count: envTargets.length,
|
|
135
|
+
registry_provider_count: registryTargets.filter((target) => target.enabled).length,
|
|
83
136
|
configured_tool_count: toolNames.length,
|
|
84
137
|
configured_tools: toolNames,
|
|
85
138
|
execution_targets: targets,
|
|
@@ -89,11 +142,17 @@ function summarizeAdapterTaskDepth(task) {
|
|
|
89
142
|
};
|
|
90
143
|
}
|
|
91
144
|
|
|
92
|
-
|
|
93
|
-
|
|
145
|
+
// `state` (optional): the live runtime state. When given, ACTIVE open-network providers count as
|
|
146
|
+
// provider-live paths alongside operator env targets (each labelled routing:open_provider_registry).
|
|
147
|
+
// Without it the pack is env-target-only, exactly as before.
|
|
148
|
+
function buildAdapterDepthPack(state) {
|
|
149
|
+
const adapterTasks = listAdapterTasks().map((task) => summarizeAdapterTaskDepth(task, state));
|
|
94
150
|
const providerLiveTasks = adapterTasks.filter((task) => task.provider_live);
|
|
95
151
|
const deepenedTasks = adapterTasks.filter((task) => task.provider_depth_state === "provider_live_path_deepened");
|
|
96
152
|
const configuredTargets = loadExecutionTargetRegistry().filter((target) => target && target.enabled !== false);
|
|
153
|
+
const registryProviderIds = new Set(adapterTasks.flatMap((task) =>
|
|
154
|
+
task.execution_targets.filter((target) => target.routing === "open_provider_registry" && target.enabled).map((target) => target.provider)
|
|
155
|
+
));
|
|
97
156
|
return {
|
|
98
157
|
ok: true,
|
|
99
158
|
product: packageJson.name,
|
|
@@ -110,8 +169,10 @@ function buildAdapterDepthPack() {
|
|
|
110
169
|
deepened_provider_live_task_count: deepenedTasks.length,
|
|
111
170
|
configured_execution_target_count: configuredTargets.length,
|
|
112
171
|
configured_provider_count: new Set(configuredTargets.map((target) => normalizeString(target.provider))).size,
|
|
113
|
-
configured_tool_count: new Set(configuredTargets.map((target) => normalizeString(target.tool_name)).filter(Boolean)).size
|
|
172
|
+
configured_tool_count: new Set(configuredTargets.map((target) => normalizeString(target.tool_name)).filter(Boolean)).size,
|
|
173
|
+
registry_provider_count: registryProviderIds.size
|
|
114
174
|
},
|
|
175
|
+
depth_sources: state ? ["operator_env_targets", "open_provider_registry"] : ["operator_env_targets"],
|
|
115
176
|
adapter_tasks: adapterTasks,
|
|
116
177
|
production_depth_requirements: [
|
|
117
178
|
"at_least_one_enabled_execution_target_for_provider_backed_task",
|
|
@@ -136,8 +197,8 @@ function buildAdapterDepthPack() {
|
|
|
136
197
|
};
|
|
137
198
|
}
|
|
138
199
|
|
|
139
|
-
function summarizeAdapterDepthPack() {
|
|
140
|
-
const pack = buildAdapterDepthPack();
|
|
200
|
+
function summarizeAdapterDepthPack(state) {
|
|
201
|
+
const pack = buildAdapterDepthPack(state);
|
|
141
202
|
return {
|
|
142
203
|
ok: true,
|
|
143
204
|
product: pack.product,
|
|
@@ -145,6 +206,7 @@ function summarizeAdapterDepthPack() {
|
|
|
145
206
|
summary_version: "xytara-adapter-depth-summary-v1",
|
|
146
207
|
adapter_depth_state: pack.adapter_depth_state,
|
|
147
208
|
counts: pack.counts,
|
|
209
|
+
depth_sources: pack.depth_sources,
|
|
148
210
|
public_claim_boundary: pack.public_claim_boundary,
|
|
149
211
|
linked_surfaces: pack.linked_surfaces
|
|
150
212
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "xytara",
|
|
3
|
-
"version": "3.1.
|
|
3
|
+
"version": "3.1.12",
|
|
4
4
|
"description": "x402 pay-per-call agent-commerce runtime: gasless USDC on Base, an open settling provider network with a ledger-reconciled revenue split and automated on-chain payouts (key-less runtime, delegated signer), and bounded cryptographic delegated spend. Proven live on Base mainnet.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -769,7 +769,38 @@ async function hardeningChecks() {
|
|
|
769
769
|
} finally {
|
|
770
770
|
global.fetch = orig;
|
|
771
771
|
}
|
|
772
|
-
|
|
772
|
+
// 19. ADAPTER DEPTH counts active open-network providers (labelled registry-routed) when given
|
|
773
|
+
// state; without state it stays env-target-only; a whole-lane env pin shadows the registry.
|
|
774
|
+
const { buildAdapterDepthPack, summarizeAdapterDepthPack } = require("../lib/adapter_depth_contract");
|
|
775
|
+
const prevTargets = process.env.XYTARA_EXECUTION_TARGETS_JSON;
|
|
776
|
+
delete process.env.XYTARA_EXECUTION_TARGETS_JSON;
|
|
777
|
+
try {
|
|
778
|
+
const ad = {};
|
|
779
|
+
assert.strictEqual(summarizeAdapterDepthPack(ad).adapter_depth_state, "provider_wiring_required", "no env targets + no providers -> wiring required");
|
|
780
|
+
reg.registerProvider(ad, { provider_id: "ad_mcp", endpoint_url: "https://ad.example/execute", task_refs: ["adapter.mcp.invoke"], tool_names: ["keccak256"], revenue_share_bps: 7000, auth_token: "t" });
|
|
781
|
+
assert.strictEqual(summarizeAdapterDepthPack(ad).adapter_depth_state, "provider_wiring_required", "a PENDING provider is not a live path");
|
|
782
|
+
reg.setProviderStatus(ad, "ad_mcp", "active");
|
|
783
|
+
let pack = buildAdapterDepthPack(ad);
|
|
784
|
+
assert.strictEqual(pack.adapter_depth_state, "initial_provider_live_path", "one active registry provider -> initial live path");
|
|
785
|
+
const invoke = pack.adapter_tasks.find((t) => t.task_ref === "adapter.mcp.invoke");
|
|
786
|
+
assert.strictEqual(invoke.registry_provider_count, 1, "registry provider counted on its declared task");
|
|
787
|
+
assert.strictEqual(invoke.execution_targets[0].routing, "open_provider_registry", "labelled registry-routed");
|
|
788
|
+
assert.strictEqual(invoke.execution_targets[0].auth_token, undefined, "no auth_token leaks into the depth pack");
|
|
789
|
+
assert.deepStrictEqual(pack.public_claim_boundary.live_task_refs, ["adapter.mcp.invoke"], "claim limited to the declared task");
|
|
790
|
+
assert.strictEqual(buildAdapterDepthPack().adapter_depth_state, "provider_wiring_required", "no state -> env-only (unchanged for internal callers)");
|
|
791
|
+
reg.registerProvider(ad, { provider_id: "ad_mcp2", endpoint_url: "https://ad2.example/execute", task_refs: ["adapter.mcp.invoke"], revenue_share_bps: 7000 });
|
|
792
|
+
reg.setProviderStatus(ad, "ad_mcp2", "active");
|
|
793
|
+
assert.strictEqual(summarizeAdapterDepthPack(ad).adapter_depth_state, "provider_live_path_deepened", "two covered live paths -> deepened");
|
|
794
|
+
process.env.XYTARA_EXECUTION_TARGETS_JSON = JSON.stringify([{ target_id: "pin", task_ref: "adapter.mcp.invoke", endpoint_url: "https://pin.example/execute", provider: "pin_provider", enabled: true }]);
|
|
795
|
+
pack = buildAdapterDepthPack(ad);
|
|
796
|
+
const pinned = pack.adapter_tasks.find((t) => t.task_ref === "adapter.mcp.invoke");
|
|
797
|
+
assert.ok(pinned.execution_targets.filter((t) => t.routing === "open_provider_registry").every((t) => t.shadowed_by_env_target && !t.enabled), "whole-lane env pin shadows registry providers");
|
|
798
|
+
assert.strictEqual(pinned.registry_provider_count, 0, "shadowed providers are not counted");
|
|
799
|
+
} finally {
|
|
800
|
+
if (prevTargets === undefined) delete process.env.XYTARA_EXECUTION_TARGETS_JSON; else process.env.XYTARA_EXECUTION_TARGETS_JSON = prevTargets;
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
console.log(" hardening: epoch-isolation | in-flight guard | timeout cap | settlement basis | endpoint policy | budget | adapter-depth registry");
|
|
773
804
|
}
|
|
774
805
|
|
|
775
806
|
async function main() {
|
package/server.js
CHANGED
|
@@ -4945,12 +4945,12 @@ async function routeRequest(req, res) {
|
|
|
4945
4945
|
}
|
|
4946
4946
|
|
|
4947
4947
|
if (req.method === "GET" && url.pathname === "/v1/adapter-depth") {
|
|
4948
|
-
sendJson(res, 200, buildAdapterDepthPack());
|
|
4948
|
+
sendJson(res, 200, buildAdapterDepthPack(state));
|
|
4949
4949
|
return;
|
|
4950
4950
|
}
|
|
4951
4951
|
|
|
4952
4952
|
if (req.method === "GET" && url.pathname === "/v1/adapter-depth/summary") {
|
|
4953
|
-
sendJson(res, 200, summarizeAdapterDepthPack());
|
|
4953
|
+
sendJson(res, 200, summarizeAdapterDepthPack(state));
|
|
4954
4954
|
return;
|
|
4955
4955
|
}
|
|
4956
4956
|
|