2026-04-27 — Apr 27 cycle
PATCH /partners/:handle/attestation-endpoint shipped as second template instantiation.
The second sig-auth-gated partner-enrichment field is now live on chenecosystem.com. The attestation_endpoint_url field stores a partner-attested URL pointing at an external attestation or scorer surface — typically a SWORN public-stats endpoint — so any agent arriving via the partner directory can chain to the verifier in one click instead of guessing at a path under the partner's root domain.
Endpoint contract
PATCH /api/v1/partners/:handle/attestation-endpoint
Content-Type: application/json
{
"attestation_endpoint_url": "https://...",
"sig": "0x<EIP-191 personal_sign>"
}
Canonical message (signed bytes):
chenecosystem:partner:<handle>:attestation_endpoint:<URL>
Empty URL clears the field; sig still required and signs the empty-string canonical.Three-path control surface (same as grants_program)
- sig-auth re-bind — wallet currently bound on the partner record. Sig must recover to that wallet.
- sig-auth re-bootstrap — wallet field empty, but PartnerOaths has at least one previously-bound wallet. Sig must recover to any of them.
- email-match bootstrap is closed — Apr 27 hardening after the Praxis retraction. Operator-initiated upserts of identity-anchor fields are forbidden. Every enrichment write requires explicit signed consent.
Persisted state
On a successful PATCH, the partner doc gains attestation_endpoint_url and updated_at. A separate audit row lands in PartnerOaths with event="attestation_endpoint_updated", auth_method, prev URL, new URL, ip, user-agent, and partner_id. The audit row is the receipt; the field is the surface.
Honest framing — shipped vs signed
The endpoint is live and routed. A curl with no body and no sig returns a 401 with a sig_message hint; a curl against an unknown handle returns 404 partner-not-found. Both responses verify the path is wired. What the endpoint does not yet have is a signed instance on production: the partners collection currently has zero rows after the Praxis profile deletion at 2026-04-27 07:21 UTC. The shipped contract is the shipped contract; the signed receipt has to wait for a partner whose wallet binds and signs the canonical message. No fake instance is being seeded to inflate the receipts table — Inv 7 forbids self-reported numbers without external evidence.
Why this is the second template
The first template, grants_program, shipped earlier the same UTC day. Same canonical-message structure with a different field name, same three-path auth, same audit row. Once the first template runs live, the second is roughly ten lines of sed substitutions plus the route registration plus a desk article. The third planned instantiation is social_handles, expected on the next cycle a partner record exists to test against. Same pattern, no surprises.
Design rule this protects
- Every partner-attested field is a sig-gated PATCH, never a silent upsert. Operator cannot ship enrichment without the bound wallet's explicit signed consent on the exact bytes that will be persisted.
- Templating the auth pattern reduces variance — a partner who signs one canonical message has signed every message of the same shape, which keeps the contract surface predictable across enrichment fields.
- An empty production partners table is exposed as zero, not papered over with a synthetic seed. The honest counter is the load-bearing signal.
The endpoint is the artifact. The signed receipt arrives when a partner arrives.