Skip to content

fix(core): send contextId, the name the schema gives it - #124

Merged
stormer78 merged 1 commit into
mainfrom
fix/wire-casing-and-trust-tasks-0.12
Aug 20, 2026
Merged

fix(core): send contextId, the name the schema gives it#124
stormer78 merged 1 commit into
mainfrom
fix/wire-casing-and-trust-tasks-0.12

Conversation

@stormer78

Copy link
Copy Markdown
Contributor

The defect

vtaListDids sent { context_id } for vta/webvh/dids/list/1.0. That schema
names contextId and sets additionalProperties: false, so the old
spelling was never a tolerated synonym — it made the whole payload malformed,
and a conforming agent refuses it as malformedRequest.

The failure mode before the schema existed is the part worth pausing on.
Nothing rejected the payload, so the filter was simply ignored: a caller
asking for one context got every context. An unfiltered list looks exactly like
a working one until you count the rows, so no amount of "does it return DIDs"
testing would have found it.

The test was pinning the bug

vault.ops.mjs asserted { context_id: "work" } — so the suite was holding the
drift in place rather than catching it.

Its stubbed reply stays snake_case on purpose. Emitting the canonical
spelling and accepting either are separate moves: the read path folds both while
agents migrate, and dropping that fold would leave contextId undefined against
an agent that hasn't taken it.

Audited the rest, and checked the audit

The other 107 buildTrustTask call sites carry no keys of this class. 106
modules build payloads from the generated bindings, so they're camelCase by
construction.

I ran the audit against the pre-fix tree first:

pre-fix hits:  [('src/vta/list-dids.ts', 'context_id')]
post-fix hits: none

So "no other hits" means the check works, rather than that it was looking in the
wrong place.

Remaining snake_case in src/ is externally-owned names carried verbatim per
SPEC §4.10 — vp_token, dcql_query, credential_offer, id_token — plus the
DIDComm pickup fields live_delivery / message_id_list. Correct as-is.

Library bump

Takes @openvtc/trust-tasks ^0.10.0^0.12.1. That's the version whose
schema index would begin catching this class client-side. The equivalent move on
the Rust side (trust-tasks-rs 0.9 → 0.11) exposed four defects of exactly
this shape — see OpenVTC/verifiable-trust-infrastructure#1015 — which is what
prompted looking here.

Typechecks clean on 0.12.1 with no other source changes needed.

Test

Lint (tsc -b) clean. 530 passing, 0 failing. Three new tests cover the send
path, the no-filter case, and that the read-path fold still works.

Checklist (stack guide §9)

  • No new bare fetch(); timeouts applied where fetch is injected (R1.2)
  • No lock held across a network await (R1.3)
  • No local state committed before its remote effect (R2.1)
  • Every retry bounded + backed off (R1.4)
  • Accept/poll/listen loops survive transient errors (R1.5)
  • Acks/deletes happen only after durable handoff (R1.6)
  • New/changed wire types: camelCase, schema registered, consumers updated
    (R3.*)
    — the whole PR; the send path now matches the published schema
    while intake keeps tolerating the old spelling
  • Config absence = most restrictive (R5.*)
  • Logs/status claim only what was verified (R6.*)
  • Deviations flagged with rule numbers

`vtaListDids` sent `{ context_id }` for `vta/webvh/dids/list/1.0`. That schema
names `contextId` and sets `additionalProperties: false`, so the old spelling
was never a tolerated synonym — it made the whole payload malformed, and a
conforming agent refuses it as `malformedRequest`.

The failure mode before the schema existed is why this is worth a test of its
own. Nothing rejected the payload, so the filter was simply ignored: callers
asking for one context got every context, and an unfiltered list looks exactly
like a working one until you count the rows.

`vault.ops.mjs` asserted the old spelling, so it was pinning the drift rather
than catching it. Updated — and its stubbed REPLY stays snake_case on purpose,
because the read path folds both while agents migrate. Emitting the canonical
spelling and accepting either are separate moves; dropping the fold would leave
`contextId` undefined against an agent that has not taken it.

Audited the other 107 `buildTrustTask` call sites for the same class and found
none: 106 modules build payloads from the generated bindings, so they are
camelCase by construction. The audit was checked against the pre-fix tree first
— it reports this defect there and nothing after, so "no other hits" means the
check works rather than that it looked in the wrong place. Remaining snake_case
in `src/` is externally-owned names carried verbatim per SPEC §4.10 (`vp_token`,
`dcql_query`, `credential_offer`, `id_token`) and the DIDComm pickup fields
`live_delivery` / `message_id_list`.

Also takes `@openvtc/trust-tasks` ^0.10.0 -> ^0.12.1. That is the version whose
schema index would begin catching this class client-side; the same move on the
Rust side exposed four defects of exactly this shape (VTI #1015).

Lint clean; 530 tests passing.

Signed-off-by: Glenn Gore <glenn.g@affinidi.com>
@stormer78
stormer78 merged commit ae95321 into main Aug 20, 2026
3 checks passed
@stormer78
stormer78 deleted the fix/wire-casing-and-trust-tasks-0.12 branch August 20, 2026 11:47
Sign up for free to 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