Background
PR #2498 added spec requirement VM-10-002 (specs/vocabulary-model.yaml):
Wire-layer classes whose _vocab_ns is VocabNamespace.VULTRON MUST
default context_ to the Vultron context URI
(https://certcc.github.io/Vultron/ns/context.jsonld) rather than the
ActivityStreams namespace URI.
ADR-0069 records the namespace URI decision. The AGENTS.md pitfall was also
added in that PR.
Consequence today: every outbound VulnerabilityCase, EmbargoEvent, etc. claims
to be a pure AS2 object. The AS2 namespace does not declare those types, so a
receiver cannot resolve them — the message is unresolvable by external
implementations.
Current state
vultron/wire/as2/vocab/base/base.py:56 still defaults context_ to
ACTIVITY_STREAMS_NS = "https://www.w3.org/ns/activitystreams" for all
wire-layer objects. VultronAS2Object (in
vultron/wire/as2/vocab/objects/base.py) does not override context_.
Verified during G02 planning (#2830): VULTRON_CONTEXT_URI appears nowhere in
vultron/, and grep -rn "VM-10-00" test/ returns nothing — VM-10-001 and
VM-10-002 are entirely unimplemented with zero test coverage.
Implementation sketch
-
Add constant in vultron/wire/as2/vocab/base/base.py:
VULTRON_CONTEXT_URI = "https://certcc.github.io/Vultron/ns/context.jsonld"
-
Override context_ in VultronAS2Object
(vultron/wire/as2/vocab/objects/base.py):
context_: str = Field(
default=VULTRON_CONTEXT_URI,
validation_alias="@context",
serialization_alias="@context",
)
Acceptance criteria
VultronAS2Object.context_ defaults to
"https://certcc.github.io/Vultron/ns/context.jsonld" (not the AS2
namespace).
as_Base.context_ (the non-Vultron base) retains its existing
ACTIVITY_STREAMS_NS default — do not change the base class.
- Serialization tests in
test/wire/as2/vocab/base/ verify that:
- A
VultronAS2Object subclass instance serializes with the correct
Vultron context URI in @context.
- An
as_Base (non-Vultron) instance still serializes with the AS2
namespace URI in @context.
- Round-trip:
from_json(obj.to_json()) preserves the Vultron @context.
- The existing test
test_as_base_context_is_as2_namespace
(test_wire_base_hierarchy.py) continues to pass unmodified — it tests
as_Base, which should keep the AS2 default.
- A test asserts that every wire type whose
type_ is not an ActivityStreams
vocabulary term is annotated VocabNamespace.VULTRON. See "the _vocab_ns
gap" below — without this, a _vocab_ns-driven fix silently skips two types.
- Tests carry
@pytest.mark.spec("VM-10-001") / @pytest.mark.spec("VM-10-002")
so the requirements stop being uncovered.
uv run spec-lint passes; uv run pytest passes.
The _vocab_ns gap (found in G02, #2830)
VM-10-002 is scoped to "classes whose _vocab_ns is VocabNamespace.VULTRON". The
actual defect is "emits a Vultron-specific type alongside the bare AS2 @context",
and the two sets are not identical. Measured on main:
type_ |
class |
_vocab_ns |
CaseParticipant |
as_CaseParticipant |
VULTRON |
CaseStatus |
as_CaseStatus |
VULTRON |
VulnerabilityCase |
as_VulnerabilityCase |
VULTRON |
VulnerabilityReport |
as_VulnerabilityReport |
VULTRON |
VulnerabilityCase |
VulnerabilityCaseStub |
VULTRON |
EmbargoEvent |
as_EmbargoEvent |
AS ← a literal fix misses this |
as_EmbargoEvent inherits _vocab_ns = VocabNamespace.AS from as_Event and never
overrides it. But EmbargoEvent is not an ActivityStreams term, and
docs/ns/context.jsonld correctly declares it as vultron:EmbargoEvent — so
receivers still could not resolve it after a _vocab_ns-driven fix. AC-6 makes the
annotation itself testable rather than relying on each new subclass remembering to
override it.
Spec references
- VM-10-001 — outbound Vultron messages MUST declare the Vultron context URI
- VM-10-002 — VULTRON-namespace wire classes MUST default
context_ to it
- ADR-0069 —
docs/adr/0069-vultron-namespace-uri.md (provisional)
Files to change
vultron/wire/as2/vocab/base/base.py — add VULTRON_CONTEXT_URI constant
vultron/wire/as2/vocab/objects/base.py — override context_ in VultronAS2Object
vultron/wire/as2/vocab/objects/embargo_event.py — override _vocab_ns to VULTRON
test/wire/as2/vocab/base/ — add or extend serialization tests
Source
Background
PR #2498 added spec requirement VM-10-002 (
specs/vocabulary-model.yaml):ADR-0069 records the namespace URI decision. The AGENTS.md pitfall was also
added in that PR.
Consequence today: every outbound
VulnerabilityCase,EmbargoEvent, etc. claimsto be a pure AS2 object. The AS2 namespace does not declare those types, so a
receiver cannot resolve them — the message is unresolvable by external
implementations.
Current state
vultron/wire/as2/vocab/base/base.py:56still defaultscontext_toACTIVITY_STREAMS_NS = "https://www.w3.org/ns/activitystreams"for allwire-layer objects.
VultronAS2Object(invultron/wire/as2/vocab/objects/base.py) does not overridecontext_.Verified during G02 planning (#2830):
VULTRON_CONTEXT_URIappears nowhere invultron/, andgrep -rn "VM-10-00" test/returns nothing — VM-10-001 andVM-10-002 are entirely unimplemented with zero test coverage.
Implementation sketch
Add constant in
vultron/wire/as2/vocab/base/base.py:Override
context_inVultronAS2Object(
vultron/wire/as2/vocab/objects/base.py):Acceptance criteria
VultronAS2Object.context_defaults to"https://certcc.github.io/Vultron/ns/context.jsonld"(not the AS2namespace).
as_Base.context_(the non-Vultron base) retains its existingACTIVITY_STREAMS_NSdefault — do not change the base class.test/wire/as2/vocab/base/verify that:VultronAS2Objectsubclass instance serializes with the correctVultron context URI in
@context.as_Base(non-Vultron) instance still serializes with the AS2namespace URI in
@context.from_json(obj.to_json())preserves the Vultron@context.test_as_base_context_is_as2_namespace(
test_wire_base_hierarchy.py) continues to pass unmodified — it testsas_Base, which should keep the AS2 default.type_is not an ActivityStreamsvocabulary term is annotated
VocabNamespace.VULTRON. See "the_vocab_nsgap" below — without this, a
_vocab_ns-driven fix silently skips two types.@pytest.mark.spec("VM-10-001")/@pytest.mark.spec("VM-10-002")so the requirements stop being uncovered.
uv run spec-lintpasses;uv run pytestpasses.The
_vocab_nsgap (found in G02, #2830)VM-10-002 is scoped to "classes whose
_vocab_nsisVocabNamespace.VULTRON". Theactual defect is "emits a Vultron-specific
typealongside the bare AS2@context",and the two sets are not identical. Measured on
main:type__vocab_nsCaseParticipantas_CaseParticipantCaseStatusas_CaseStatusVulnerabilityCaseas_VulnerabilityCaseVulnerabilityReportas_VulnerabilityReportVulnerabilityCaseVulnerabilityCaseStubEmbargoEventas_EmbargoEventas_EmbargoEventinherits_vocab_ns = VocabNamespace.ASfromas_Eventand neveroverrides it. But
EmbargoEventis not an ActivityStreams term, anddocs/ns/context.jsonldcorrectly declares it asvultron:EmbargoEvent— soreceivers still could not resolve it after a
_vocab_ns-driven fix. AC-6 makes theannotation itself testable rather than relying on each new subclass remembering to
override it.
Spec references
context_to itdocs/adr/0069-vultron-namespace-uri.md(provisional)Files to change
vultron/wire/as2/vocab/base/base.py— addVULTRON_CONTEXT_URIconstantvultron/wire/as2/vocab/objects/base.py— overridecontext_inVultronAS2Objectvultron/wire/as2/vocab/objects/embargo_event.py— override_vocab_nsto VULTRONtest/wire/as2/vocab/base/— add or extend serialization testsSource
implementation snippets, round-trip test AC, and VM-10-001 reference are folded in
above.
_vocab_nsgap and coverage findings: G02: Wire/core boundary contract #2830 (G02),docs/adr/0081-wire-core-boundary-pairing-registry.mddocs/ns/context.jsonld+ CI drift check)