Skip to content

feat(core): preserve non-standard SP registry capabilities in PDPOffering#687

Open
rvagg wants to merge 2 commits intomasterfrom
rvagg/extra-capabilities
Open

feat(core): preserve non-standard SP registry capabilities in PDPOffering#687
rvagg wants to merge 2 commits intomasterfrom
rvagg/extra-capabilities

Conversation

@rvagg
Copy link
Copy Markdown
Collaborator

@rvagg rvagg commented Mar 23, 2026

We shouldn't have been stripping theses, there's potentially useful signals in here downstream from our consumption of the capabilities providers publish. One example is FilOzone/dealbot#364 where the "serviceStatus" capability still has some use, but there's plenty more where clients have needs that align with what service providers want to dump in their capabilities field that we don't know or care about.

…ring

There's potentially useful signals in here downstream from our consumption of
the capabilities providers publish.
@rvagg rvagg requested a review from SgtPooki March 23, 2026 02:56
@rvagg rvagg requested a review from hugomrdias as a code owner March 23, 2026 02:56
@github-project-automation github-project-automation bot moved this to 📌 Triage in FOC Mar 23, 2026
@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages bot commented Mar 23, 2026

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
❌ Deployment failed
View logs
synapse-dev 62b69fb Mar 30 2026, 04:02 PM

@rvagg
Copy link
Copy Markdown
Collaborator Author

rvagg commented Mar 23, 2026

CI failing due to ABI changes, fixing that separately #688

@BigLep BigLep moved this from 📌 Triage to 🐱 Todo in FOC Mar 23, 2026
@BigLep BigLep moved this from 🐱 Todo to 🔎 Awaiting review in FOC Mar 27, 2026
@BigLep BigLep requested a review from Copilot March 27, 2026 15:47
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates PDP capability decoding to preserve non-standard Service Provider Registry capability entries (e.g., serviceStatus) so downstream consumers can access them without needing synapse-core to explicitly model every possible capability.

Changes:

  • Allow unknown capability keys through PDP offering schema validation and surface them via PDPOffering.extraCapabilities.
  • Add logic in decodePDPCapabilities to separate known/typed capability fields from extra/untyped ones.
  • Add tests to verify extra capabilities are preserved and omitted when none exist.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

File Description
packages/synapse-core/src/utils/pdp-capabilities.ts Allows unknown capabilities through validation and returns them in extraCapabilities during decode.
packages/synapse-core/src/sp-registry/types.ts Extends PDPOffering with optional extraCapabilities field.
packages/synapse-core/test/pdp-capabilities.test.ts Adds unit tests covering preservation/omission/filtering of extraCapabilities.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

ipniIpfs: zHex.optional(),
ipniPeerId: zHex.optional(),
})
.passthrough()
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PDPOfferingSchema uses .passthrough(), which means any non-standard capability values are accepted without validation. Since extraCapabilities is exposed as Record<string, Hex>, consider switching to .catchall(zHex) (or otherwise validating unknown keys) so extra capability values are guaranteed to be valid hex strings.

Suggested change
.passthrough()
.catchall(zHex)

Copilot uses AI. Check for mistakes.
Comment on lines 45 to +49
const parsed = PDPOfferingSchema.safeParse(capabilities)
if (!parsed.success) {
throw new ZodValidationError(parsed.error)
}
return decodePDPCapabilities(parsed.data)
return decodePDPCapabilities(parsed.data as Record<string, Hex>)
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

parsed.data is being cast to Record<string, Hex> before calling decodePDPCapabilities. With .passthrough() this can mask invalid extra capability values (typed as unknown by Zod) and silently violate the Hex contract. Prefer adjusting the schema typing/validation (e.g., .catchall(zHex)) so this cast can be removed.

Copilot uses AI. Check for mistakes.
Comment on lines +80 to +85
const extraCapabilities: Record<string, Hex> = {}
let hasExtra = false
for (const key of Object.keys(capabilities)) {
if (!KNOWN_CAPABILITY_KEYS.has(key)) {
extraCapabilities[key] = capabilities[key]
hasExtra = true
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

extraCapabilities is built with a normal object literal and then assigned arbitrary, provider-controlled keys. Keys like __proto__/constructor can trigger prototype mutation in JS objects. Consider using Object.create(null) for extraCapabilities (or explicitly guarding against these keys) to avoid prototype-pollution style issues when consuming or serializing this map later.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Member

@juliangruber juliangruber Mar 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 to the copilot request

@SgtPooki
Copy link
Copy Markdown
Contributor

sorry i didn't get to this. heading on vacation so i wont be able to look until 2026 APR 8+

@rjan90 rjan90 added this to the M4.2: mainnet GA milestone Mar 30, 2026
@rvagg rvagg requested a review from juliangruber March 30, 2026 11:05
Copy link
Copy Markdown
Member

@hugomrdias hugomrdias left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM but copilot's first suggestion seems to be good

@github-project-automation github-project-automation bot moved this from 🔎 Awaiting review to ✔️ Approved by reviewer in FOC Mar 30, 2026
Comment on lines +80 to +85
const extraCapabilities: Record<string, Hex> = {}
let hasExtra = false
for (const key of Object.keys(capabilities)) {
if (!KNOWN_CAPABILITY_KEYS.has(key)) {
extraCapabilities[key] = capabilities[key]
hasExtra = true
Copy link
Copy Markdown
Member

@juliangruber juliangruber Mar 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 to the copilot request

Comment on lines +81 to +89
let hasExtra = false
for (const key of Object.keys(capabilities)) {
if (!KNOWN_CAPABILITY_KEYS.has(key)) {
extraCapabilities[key] = capabilities[key]
hasExtra = true
}
}

return { ...required, ...optional, ...(hasExtra ? { extraCapabilities } : {}) }
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
let hasExtra = false
for (const key of Object.keys(capabilities)) {
if (!KNOWN_CAPABILITY_KEYS.has(key)) {
extraCapabilities[key] = capabilities[key]
hasExtra = true
}
}
return { ...required, ...optional, ...(hasExtra ? { extraCapabilities } : {}) }
for (const key of Object.keys(capabilities)) {
if (!KNOWN_CAPABILITY_KEYS.has(key)) {
extraCapabilities[key] = capabilities[key]
}
}
return { ...required, ...optional, ...({ extraCapabilities }) }

this produces a more stable schema and is a simpler implementation


const result = decodePDPCapabilities(capabilities)

assert.strictEqual(result.extraCapabilities, undefined)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
assert.strictEqual(result.extraCapabilities, undefined)
assert.deepStrictEqual(result.extraCapabilities, {})

(if you merge above suggestion)

}

/** Capability keys that are decoded into typed PDPOffering fields, derived from the schema */
const KNOWN_CAPABILITY_KEYS = new Set([...Object.keys(PDPOfferingSchema.shape), CAP_IPNI_PEER_ID_LEGACY])
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This array likely becomes a maintenance burden, and is hard to test in integration.

Would it be easier to expose all capabilities in one object, and not differentiate standard and non-standard capabilities?

@github-project-automation github-project-automation bot moved this from ✔️ Approved by reviewer to ⌨️ In Progress in FOC Mar 30, 2026
@hugomrdias
Copy link
Copy Markdown
Member

i will rebase and finish this tomorrow

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: ⌨️ In Progress

Development

Successfully merging this pull request may close these issues.

7 participants