Repository navigation
feat(lawful-basis): emit lawful basis and external media on every platform - #12
Merged
Merged
Conversation
howethomas
added this pull request to stack #13
September 25, 2026 21:49
howethomas
force-pushed
the
thomashowe/con-1083-lawful-basis-all-platforms
branch
from
September 25, 2026 21:49
7bb6768 to
e6d16b7
Compare
Base automatically changed from
thomashowe/con-1084-packaging-container
to
main
September 25, 2026 21:53
… to 0 vcon-lib 0.9.6's add_lawful_basis_attachment() emits `body` as the attachment dict itself, not the JSON string `encoding: "json"` implies and the vCon schema requires (`body` is `type: string`). Stringify the attachment vcon-lib just appended rather than hand-rolling the shape. Also default party_index/dialog_index to 0 instead of leaving them unset: every adapter builder here produces exactly one dialog and treats party 0 as the recording's subject, and the vCon schema requires both fields on every attachment. Updates the existing lawful-basis tests to decode the body before asserting on its contents. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…hooks Asterisk, Bandwidth, FreeSWITCH and Twilio built their vCon builders without lawful_basis or publisher, so only Telnyx ever emitted a lawful_basis attachment or re-hosted media instead of embedding it inline. The per-platform config classes already had build_lawful_basis()/build_publisher() via BaseConfig, and the builders already accepted both kwargs; only the webhook factories were missing the wiring, so this follows the same pattern already used in adapters/telnyx/webhook.py. Unset LAWFUL_BASIS keeps prior behaviour: no attachment, a startup warning. MEDIA_BACKEND=embed (the default) keeps prior behaviour too. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Asterisk, Bandwidth, FreeSWITCH and Twilio each get the same coverage Telnyx already had: a configured LAWFUL_BASIS produces a correctly shaped attachment (string body, purpose/party/dialog/encoding, extensions), an unset one produces neither an attachment nor a warning-free log, and MEDIA_BACKEND=filesystem produces a dialog with url + content_hash and no inline body. Twilio's file lives at the tests/ top level rather than under tests/adapters/, matching how its other tests are already organized in this repo. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Both apply to every adapter now, not just Telnyx. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ment The official schema (draft-ietf-vcon-vcon-core, Attachment Object) lists start, party, and dialog as required on every attachment, not optional. vcon-lib's own add_tag() already sets party/dialog on the tags attachment it creates but never start, and its own validator does not check for any of the three, so every vCon this monorepo produced was schema-invalid on that attachment regardless of lawful basis. BaseVconBuilder.build() now backfills all three on every attachment it emits, once, after tags and lawful_basis are both added: start from the vCon's own created_at (the attachment is produced at conversion time, which is what "sent/exchanged" means here, in the same ISO 8601 + timezone format created_at already uses), party/dialog defaulting to 0. Uses setdefault, so an attachment that already carries a value (the lawful_basis attachment already sets its own party/dialog) is never overwritten. Regenerating sample vCons per platform against the official schema (vcon_json_schema.json) confirms the start/party/dialog gap is closed, but surfaces two further, distinct, pre-existing schema mismatches this fix does not touch: - The embedded-audio path sets dialog.encoding = "base64", which is not in the schema's enum (base64url | json | none). - The tags attachment's body is a JSON array (vcon-lib's own add_tag() shape), not the string the schema requires for `body`. Stringifying it here would silently break vcon-lib's own Vcon.get_tag() (which iterates body expecting list items) and any later Vcon.add_tag() call on the same vCon (which appends to body expecting a list), so it is left alone rather than worked around. Both are unrelated to lawful basis and out of scope for this card. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…core-04 Reverts the earlier json.dumps stringification of the lawful_basis attachment body: -04 §2.3.2 (CDDL body: any) makes body the raw JSON value for encoding: "json", not a string. That fix was written against a stale schema fork that typed body as a string; the working group's current schema (vendored at vcon-adapter-template's tests/schema) does not. vcon-lib 0.9.6's object body was already correct and is left untouched. mediatype is required whenever body is present (-04's Attachment Object). vcon-lib sets it on neither the lawful_basis attachment nor the tags attachment from add_tag(), so LawfulBasisConfig.apply() and the attachment backfill loop in BaseVconBuilder.build() both now setdefault mediatype to "application/json" (every attachment either of them touches is encoding: "json"). Updates every test that asserted body was a JSON string to assert it is the JSON object/array instead, and adds mediatype coverage alongside the existing start/party/dialog checks. README: documents that JSON-encoded attachment bodies are raw values under -04, not json.dumps strings. Regenerated sample vCons (asterisk, bandwidth, freeswitch, twilio, telnyx) with LAWFUL_BASIS set and MEDIA_BACKEND=filesystem, validated against the vendored working-group schema (main @ fdcf2f5): all five VALID. (The embedded-audio dialog.encoding="base64" mismatch is unrelated and tracked separately as CON-1100.) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
howethomas
force-pushed
the
thomashowe/con-1083-lawful-basis-all-platforms
branch
from
September 25, 2026 21:53
e6d16b7 to
10e6621
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #11 (which is stacked on #10). Base is that branch, so this diff shows only this change. Merge in order.
The shared core already supported a lawful basis attachment and external media, but only Telnyx turned them on. Asterisk, Bandwidth, FreeSWITCH and Twilio emitted vCons with no lawful basis and always inlined or referenced media.
Changes
add_lawful_basis_attachmentemitsbodyas an object and omitsparty/dialog/mediatype.core/lawful_basis.pysetsparty: 0,dialog: 0, andmediatype: "application/json", and leavesbodyas the object vcon-lib already produces: under -04 §2.3.2 (CDDLbody: any),bodyforencoding: "json"is the raw JSON value, not ajson.dumpsstring. (An earlier revision of this PR stringified it against a stale schema fork that typedbodyas a string; that was wrong for -04 and has been reverted.) Result:purpose: "lawful_basis",encoding: "json", object body,"lawful_basis"inextensions.LAWFUL_BASISbehaves as before: a warning and no attachment. No default basis in code.start,party,dialog, andmediatype, which draft-ietf-vcon-vcon-core-04's Attachment Object requires (mediatypewheneverbodyis present). Missing values are backfilled incore/base_builder.pywith the vCon'screated_at, index 0, andapplication/jsonrespectively; existing values are never overwritten.LAWFUL_BASIS*andMEDIA_*as applying to every platform, and documents that JSON-encoded attachment bodies are raw values under -04, notjson.dumpsstrings.Tests
15 new tests: per platform, lawful basis configured (exact attachment shape, including
mediatype), lawful basis unset (no attachment, warning logged), andMEDIA_BACKEND=filesystem(dialog hasurl+content_hash, no inline body); plus required attachment fields (start/party/dialog/mediatypeon every attachment). Full stack: 539 passed.Schema validation
One sample vCon per platform, built with
LAWFUL_BASIS=consentandMEDIA_BACKEND=filesystemfrom test fixtures, validated withjsonschemaagainst the working group's current schema (vendored atvcon-adapter-template'stests/schema/vcon_json_schema.json, WG main @fdcf2f5, matching the -04 appendix):All five pass. The
start/party/dialogandmediatypegaps are closed, and retargeting to -04 (raw JSONbody, not a string) also resolves what looked like a second defect in the tags attachment: itsbodyis a JSON array from vcon-lib'sadd_tag, which is a validbodyvalue under -04'sbody: any— it only failed against the stale schema fork'sbody: stringconstraint.One remaining, separate defect:
MEDIA_BACKEND=embed(the default) still fails schema validation —dialog[0].encodingis"base64", which is not in the schema's["base64url", "json", "none"]enum. That's in the inline-audio path incore/base_builder.py, unrelated to lawful basis or attachments, tracked separately as CON-1100.Refs CON-1083
🤖 Generated with Claude Code