Semana agentic: los fixes de x402 vinieron de fuera
Se mergearon treinta y siete pull requests en x402 entre el 28 de agosto y el 4 de septiembre. Diecisiete vinieron de cuentas fuera del set de maintainers, y casi todas eran correcciones.
La semana pasada el tema era el tiempo: todo cambio sustantivo movia una parte del pago fuera del round trip HTTP unico. Esta semana el tema es quien hace el trabajo. El core team envio features — un authorizer delegado para SVM upto, una pasada de latencia en el facilitator, direcciones canonicas de contratos. El resto envio bugs que encontro leyendo el codigo.
Esa distribucion importa mas que cualquier parche individual. Un rail de pago vale exactamente lo que valga el numero de personas independientes que intentaron romperlo. Contando por autor sobre el set mergeado: doce PRs de phdargen, tres de CarsonRoscoe, dos de PhilBot402 y tres del bot de docs. Los diecisiete restantes vinieron de trece cuentas externas distintas. Las releases que cargan la semana son @x402/core 2.25.0 en npm, publicada el 3 de septiembre, y x402 2.22.0 en PyPI, publicada el 4 de septiembre. Para escala: @x402/core registro 997.660 descargas de npm en los treinta dias terminados el 29 de agosto.
1. El SDK de Java servia contenido pago antes de cobrar
PR #3074 se mergeo el 4 de septiembre: seis archivos, 277 lineas agregadas. Cierra el issue #3068, abierto el 6 de agosto por Sertug17: PaymentFilter entrega contenido antes del settlement.
El mecanismo es el que mapeamos cuando auditamos el hueco de dos fases. El PaymentFilter.doFilter() de Java llamaba a chain.doFilter() contra el HttpServletResponse real. El handler protegido escribia su salida — y en un servlet container, normalmente la commiteaba — antes de que corriera facilitator.settle(). Si el settlement fallaba despues por un timeout de RPC o una caida del facilitator, el comprador ya tenia los bytes del paywall y el vendedor no tenia nada.
Habia un fallback. respond402() disparaba ante fallo de settlement. Pero solo era alcanzable mientras response.isCommitted() siguiera en false, cosa que despues de que un handler escribio un body normalmente no ocurre. La red de seguridad estaba condicionada a una carrera que el SDK no controlaba.
FilterIntegrationTest. Su facilitator stub devolvia un SettlementResponse por defecto con success = false, y su test validHeaderGets200 pasaba gracias al bug: el contenido ya estaba entregado antes de que el settle siempre-fallido pudiera importar. La suite de tests no solo no detectaba el defecto. Lo ratificaba.
El fix agrega un BufferingHttpServletResponseWrapper. Los status codes y headers siguen reenviandose al response real de inmediato; el body se acumula en memoria y solo se vuelca despues de que el settlement tuvo exito. Ante fallo el buffer se descarta y sale un 402, de forma deterministica en vez de condicional. La evidencia presentada es la parte que deberia ser practica estandar: el nuevo test de integracion se corrio contra el codigo pre-fix y reprodujo el bug como expected 402 but was 200 con el body filtrado.
El middleware de Express en TypeScript, en el mismo repositorio, bufferizaba correctamente desde hacia mucho. El port de Java nunca recibio el equivalente. Esa es la leccion real: en un SDK de protocolo multi-lenguaje, las garantias de la implementacion de referencia no se heredan. Se re-implementan, y cada re-implementacion es una oportunidad nueva de perder plata.
2. Una ola de hardening, un lector a la vez
El fix de Java no estuvo aislado. Otros cuatro contribuidores externos aterrizaron defectos en la misma ventana, cada uno encontrado leyendo y no fallando en produccion.
PR #2973 acota la lectura de bodies HTTP en el SDK de Go. El cliente de pago, el de facilitator y el de Bazaar llamaban a io.ReadAll directamente, asi que un facilitator o un resource server podia hacer que el SDK bufferizara una respuesta arbitrariamente grande antes de validar el status o decodificar JSON. El fix limita las lecturas a 4 MiB mas un byte y exporta ErrResponseBodyTooLarge. Los bodies sobredimensionados se cierran sin drenar el resto de datos no confiables.
PR #2962 es mas chico y peor. ResolveSettlementOverrideAmount parseaba la parte entera de un porcentaje a un int64, ignoraba errores de parseo y luego multiplicaba por 100. Valores grandes hacian overflow hacia un monto de settlement negativo o cero.
PR #3051 cambia @x402/core para que buildPaymentRequirements() lance cuando no hay scheme server registrado para el scheme y la network pedidos. Antes logueaba un console.warn y resolvia con un array vacio, lo que producia un 402 que le decia al cliente que se requeria pago y le ofrecia cero formas de pagarlo. La misma funcion ya lanzaba quince lineas mas abajo cuando el facilitator no anunciaba el scheme. Veintiun tests entre @x402/express, @x402/fastify, @x402/hono y @x402/next dependian del camino permisivo.
PR #3282 hace que el cliente EIP-3009 de Go use now + paymentRequirements.maxTimeoutSeconds para validBefore en vez de una hora hardcodeada. El camino de Permit2 y el SDK de TypeScript ya lo hacian. La vida util de una authorization es un parametro de seguridad, y el cliente de Go estaba ignorando el valor declarado por el servidor.
Dos correcciones mas completaron la superficie. EXTENSION-RESPONSES se decodificaba solo para hacer console.log de campos allowlisted y despues se descartaba, asi que los resource servers no podian ramificar segun resultados de extensiones tras verify o settle; #3278 en TypeScript, #3306 en Python y #3301 en Go ahora lo exponen como sidechannel interno del servidor, deliberadamente fuera del PAYMENT-RESPONSE que ve el comprador. Y el issue #3299 — un cliente v2 podia setear el campo de app attribution onchain a que el resource server nunca habia declarado — se cerro en los tres SDKs, dejando al resource server como autoridad sobre ese campo.
3. upfront estreno sus familias de transferencia, y Lightning consiguio una puerta
PR #3145 se mergeo el 2 de septiembre. Un archivo, treinta y siete lineas agregadas a specs/schemes/exact/scheme_exact.md. Es el cambio mas chico de la semana y probablemente el mas consecuente.
La semana pasada aterrizo el payment flow upfront — liquidar antes de que corra el handler. Ese PR envio la maquinaria y dejo deliberadamente sin especificar las propiedades agnosticas de red de los metodos client-prepaid. #3145 llena ese hueco con dos familias de asset transfer method:
// signed-transaction
// El cliente firma, el facilitator envia durante settle.
// Replay safety heredada de la red. Sin dedup del lado del facilitator.
// Stateless. Preferida donde la red y el tooling del pagador lo permitan.
// payment-proof
// El cliente ejecuta el pago y presenta una prueba.
// settle valida la prueba y la vincula. Requiere un consumed-proof store.
// Stateful. Claim atomico de uso unico antes de ejecutar el recurso.
El argumento de naming es la parte interesante. La discusion previa habia convergido en transaction-proof. El autor lo mantuvo como valor valido pero llamo payment-proof a la familia, especificamente para que entre Lightning: una prueba de Lightning es un payment preimage, verificado como sha256(preimage) == payment_hash. No hay transaccion, no hay hash de transaccion y no hay nada que consultar onchain. Llamar a la familia transaction-proof habria hecho que cada requisito compartido se leyera como especifico de onchain y habria empujado a Lightning fuera de la estructura otra vez.
Es un acto deliberado de consolidacion. Hay cuatro drafts de Lightning abiertos, cada uno escrito como su propio scheme exact, mas otras tres propuestas con la misma forma. Un flow, un discriminador de transfer method por mecanismo, requisitos compartidos en un solo archivo. Cuando auditamos L402, el hueco era que el pago Lightning-nativo no tenia asiento dentro de la estructura de schemes de x402. Este es ese asiento en construccion.
4. La semana del core team: delegacion, latencia, direcciones canonicas
PR #3346 (TypeScript, 26 archivos, +1.287/−146) y #3347 (Go) aterrizaron el 3 de septiembre. SVM upto ahora puede delegar el rol de receiverAuthorizer al facilitator, como ya podia el batch-settlement de EVM. Un servidor que omite receiverAuthorizerSigner ya no necesita ninguna clave de firma de vouchers. El facilitator firma el claim voucher solo despues de vincular el deposito a una identidad de caller y hacer coincidir esa misma identidad en el claim — y un binding perdido falla cerrado. Los vouchers self-managed del servidor siguen siendo el default. El ruteo de settle prefiere un payload.type estampado por el servidor con valor deposit o claim, cayendo a la inferencia existente cuando no esta, asi que los servidores que no delegan siguen funcionando.
PR #3355 es una pasada de latencia en cuatro partes sobre el facilitator de Go. Simulacion de verify en paralelo para EVM exact y Permit2 — opt-in y apagada por defecto, porque el tradeoff es un eth_call desperdiciado por cada pago rechazado por firma. Un cache de contrato de asset con scope por red: quince minutos, 4.096 entradas, solo resultados positivos para que un token en pleno deploy se auto-sane. Reuso del lookup de GetCode del pagador hecho en verify dentro de la rama de settle ERC-6492, en vez de traerlo dos veces. Y backoff lineal para las lecturas de channel account en SVM: 200/400/600/800/1000ms en seis lecturas, reemplazando 200/400/800/1600ms en cinco, mismo presupuesto de tres segundos pero con una espera maxima individual de un segundo en vez de 1,6 — aproximadamente 2,5 slots de Solana en lugar de cuatro.
En paralelo, PR #3354 apunto los clientes de TypeScript y Go a los deployments canonicos de los contratos de commerce v1.1, cerrando la reescritura de auth-capture de la semana pasada. Dos cambios en el directorio de facilitators merecen mencion: se listo un facilitator FTP Canton el 2 de septiembre, vivo en Canton mainnet con Canton Coin y tokens CIP-56, y el mecanismo de Stellar aprendio a aceptar credenciales de address CAP-71 V2 para el Protocol 28.
5. A2A se mudo con MCP
El 27 de agosto el proyecto A2A anuncio que Agent2Agent fue aceptado como proyecto Growth Stage en la Agentic AI Foundation. El post plantea la division con claridad: MCP es la capa de integracion vertical que conecta agentes con herramientas y bases de datos; A2A es el protocolo horizontal de colaboracion peer-to-peer. Los proyectos hermanos bajo la AAIF, dirigida por la Linux Foundation, incluyen ahora MCP, goose y AGENTS.md.
No es un evento de propiedad. A2A ya estaba en governance neutral; se mudo a una casa mas estrecha. Pero la consolidacion es direccionalmente significativa para quien construye sobre ambos, porque pone el protocolo de acceso a herramientas y el protocolo agente-a-agente bajo un mismo proceso de roadmap. Auditamos A2A v1.0 cuando aterrizaron los breaking changes en marzo; la pregunta de governance que marcamos entonces ya tiene respuesta.
Del lado de MCP, el charter del Enterprise Interest Group se mergeo el 29 de agosto. Su declaracion de scope es inusualmente disciplinada para un charter: el mandato del grupo es exponer huecos de requisitos a nivel protocolo y entregarlos a los Working Groups, y escribir o poseer SEPs esta explicitamente fuera de scope. La lista in-scope se lee como un threat model — propagacion de identidad entre agentes spawned y delegados, linaje de identidad, minimo privilegio para agentes hijos, revocacion de descendientes y evidencia de auditoria para SOC 2, HIPAA, GDPR y el EU AI Act. Tambien reconoce que el core stateless de 2026-07-28 cambio el problema de gateway: de afinidad de sesion a propagacion de headers y contexto entre proxies.
Que significa para LLM4Agents
El bug de Java es el que hay que internalizar, porque LLM4Agents es un vendedor. Toda integracion x402 del lado vendedor tiene la misma forma: verify, correr el trabajo, settle, responder. El modo de fallo no es exotico — es un settlement que falla cuando el body de la respuesta ya esta en el cable. Para un gateway que media inferencia de modelos la exposicion es peor que para un paywall estatico, porque para cuando el settlement falla, la cosa cara ya se le compro a un proveedor upstream. La postura correcta es que ningun byte pago sale del proceso hasta que settle devuelva exito, y la evidencia correcta es un test que falla contra el codigo pre-fix.
La segunda leccion es sobre procedencia de SDKs. LLM4Agents no necesita enviar una integracion en Java para verse afectado — necesita ser integrado por una. Un agente comprador corriendo el SDK de Go antes de #3282 firmaba authorizations EIP-3009 validas por una hora sin importar lo que dijera nuestro maxTimeoutSeconds. Un comprador sobre @x402/core antes de #3051 podia recibir un 402 con un accepts vacio desde un vendedor mal configurado y no tener idea de por que. El skew de versiones del SDK del comprador es superficie de soporte, y es una que podemos medir.
payment-proof es la senal mas interesante a mediano plazo. Si un mecanismo Lightning aterriza dentro de exact en vez de al lado, un gateway que ya habla upfront obtiene una segunda red de settlement casi gratis — otra finalidad, otra curva de costo, mismo scheme. Es exactamente el tipo de opcionalidad que una capa de routing deberia querer.
Que A2A entre a AAIF es neutro a positivo. Governance consolidada hace de la extension x402 de A2A algo mas seguro sobre lo cual construir, porque la extension de pago y el protocolo que extiende dejan de estar en orbitas politicas separadas.
Como mantenerse en la frontera
Concreto, en orden.
Primero, escribir el test de free-riding. No una revision: un test. Levantar un facilitator stub que siempre verifica y siempre falla al liquidar, apuntarlo a una ruta de inferencia paga y afirmar que cero bytes de completion llegan al cliente. Correrlo contra el codigo actual antes de escribir cualquier fix. Si pasa al primer intento, la afirmacion esta mal.
Segundo, pinear y publicar pisos de version de SDK para compradores. Documentar las versiones minimas de @x402/core, Go, Python y Java contra las que esta validado nuestro gateway, y declarar que se rompe debajo de cada linea — la semantica de validBefore bajo el piso de Go, el camino de accepts vacio bajo el de TypeScript. Los compradores no pueden actualizar lo que no saben que esta roto.
Tercero, acotar toda lectura no confiable. #2973 es una leccion de cuatro lineas: cualquier ReadAll contra un facilitator o un resource server es un primitivo de agotamiento de memoria. Auditar nuestros propios caminos de cliente buscando la misma forma y ponerles techo.
Cuarto, tratar al resource server como autoridad sobre los campos que le pertenecen. El bug de builder-code attribution generaliza: cualquier campo que un cliente pueda setear y que tenga consecuencia onchain o de facturacion debe verificarse por echo contra una declaracion del servidor, no aceptarse porque parsea.
Quinto, seguir payment-proof. Un consumed-proof store con claim atomico de uso unico antes de ejecutar el recurso es una pieza de infraestructura, no un flag de configuracion. Si la consolidacion de Lightning aterriza, tener ese store ya disenado es la diferencia entre enviar en una semana y enviar en un trimestre. La capa de extensiones es donde corresponde ese trabajo.
Sexto, leer los PRs de afuera. Diecisiete de treinta y siete cambios mergeados esta semana vinieron de gente sin ninguna obligacion con el proyecto. Es la investigacion de seguridad mas barata que existe, publicada completa y con pasos de reproduccion. Suscribirse a eso es un habito semanal, no un proyecto.
Pagar por llamada, liquidar por llamada
Un gateway compatible con OpenAI donde el pago se confirma antes de que salgan los tokens.
Registrar agente