Open questions
This page collects each unresolved design question in the Future Work section. Each question is also at the point in the text where it first applies. A reader who finds a gap in context sees the question at that point, and not only on this page.
An entry on this page has one of two meanings. In the first meaning, the project has not made the design decision. In the second meaning, the project made the decision for the prototype, and that decision does not apply to a production deployment. No meaning shows that the project rejects the capability.
Most of these questions apply to the movement of the Vultron ActivityStreams 2.0 (AS2) vocabulary between organizations. They also apply to the obligations of a production deployment that the prototype does not obey.
Four more acronyms occur across the entries below:
- Uniform Resource Identifier (URI)
- Uniform Resource Locator (URL)
- JavaScript Object Notation for Linked Data (JSON-LD)
- Domain Name System (DNS)
Federation
Open question: how much of ActivityPub does a deployment implement?
Vultron uses AS2 as its message vocabulary. It also uses the actor, inbox, and outbox primitives from ActivityPub. The prototype stops there. It does not supply the other parts of an ActivityPub server:
- a NodeInfo document
- followers and following collections
- a shared inbox
- a client-to-server Application Programming Interface (API)
The prototype does supply a readable outbox collection for each actor. The project does not reject the missing parts. The prototype does not need them to show coordination between known peers. Thus the correct depth of ActivityPub conformance for a production deployment is open. Full conformance gives interoperability with existing fediverse tools. It also has a cost. A deployment makes endpoints that a closed group of trusted peers does not read, and it gives them protection.
There are two possible paths (#2068). A deployment can make the current AS2 endpoints fully conformant to ActivityPub. As an alternative, it can put Vultron above an existing ActivityPub server. Four criteria apply to this selection: conformance test coverage, maintainability, agreement with the behavior-tree core, and deployment footprint.
Open question: how do actors find each other?
Coordination starts when one party can contact another. An actor needs the inbox address of a peer. It also needs the public key of that peer, its embargo policy, and its disclosure policy. The protocol does not say how an actor finds this data.
The problem is older than the protocol. An embargo divides the world into the Participants who belong in a case and everyone else, and knowing who a party is does not say why it is relevant to a case. Authentication is not authorization. In a small case the answer is a web search for the affected Vendor's disclosure contact. In a case with many Vendors that approach does not scale, for reasons the 2022 Vultron technical reports set out:
- Contact information for every relevant party is slow to collect by hand.
- Vendors accept reports through different channels, such as email, a web form, or an account on their own bug tracker, which prevents automated notification.
- Which other Vendors' products contain an affected component is often unknown, so a case cannot follow the software supply chain.
- A vulnerability in a protocol or a specification affects every implementation, and the implementers are hard to enumerate.
- Some Vendors treat the components of their products as confidential, which hides that a product is affected.
Community directories show the value of a shared answer.
The FIRST member list and Disclose.io each publish disclosure contacts, and Disclose.io accepts community contributions.
A Vendor can also publish a security.txt file (RFC 9116) so that a Reporter finds its contact without a directory.
Standard contact records with an interface to read them, standard contact methods, publication and aggregation of software bills of materials, and a way for Vendors to register interest in a technology would each remove one of the obstacles above.
The last of these has a cost: an adversary, or a competitor, can register interest in a technology to receive reports about products it does not make.
Discovery has two levels, and the two levels are open. At the actor level, an actor cannot resolve a name to an actor profile. A WebFinger-compatible mechanism is the expected shape, because it fits existing fediverse tools (#1189). The profile record is already an ActivityStreams actor with a small number of Vultron extensions. At the instance level, a voluntary public registry lets operators find each other at all. A registry is useful, but it is secondary to the peering protocol.
A registry has questions that the peering protocol does not have. The operator of a registry is unsettled, and a neutral foundation, a git repository, and a DNS zone are all possible answers. The content is also unsettled. A registry can hold only domain names, with DNS TXT records as the trust anchor, or it can hold more data. The method to retire stale or offline instances is a third open point.
The reference implementation reserves the seam. Its behavior trees have an actor-discovery call-out (#2469), and the backend that answers it is not built. Demo deployments do not have this problem. Each container receives the URL of each other container at start-up (CP-08). This is an alternative to a directory service, and the specification records it as one.
Open question: who controls the Vultron vocabulary?
Vultron adds its own object and activity types to AS2.
It declares them as JSON-LD @context extensions.
An extension vocabulary that more than one organization uses needs a version and governance model.
Vultron does not have one.
Three parts are unresolved.
The first part is the procedure to propose and to ratify a new activity type or object type, and the group that does it.
The second part is the method for two instances to agree at peering time on the vocabulary versions that both instances support.
A peer that does not recognize a type cannot act on that type.
The third part is the URI of the @context document and the operator that hosts it.
A @context document that a peer can resolve makes the vocabulary interoperable instead of local.
Concern #3368 records this question.
Open question: should the protocol add other wire forms for attaching a case record or a note?
ActivityStreams lets a sender attach a new object in more than one way. The protocol names one way for each act (ADR-0137):
- A case status is attached by
Add(CaseStatus), and a participant status byAdd(ParticipantStatus). - A proposed embargo event travels on the
Invitethat proposes it. - A participant record is made by the Case Manager as a consequence of an act it records.
- A note is attached by
Add(Note)with the case astarget.
A received Create of any of these objects is not a protocol message, and its receiver does not change the case file because of it.
The protocol defers four other forms. It does not reject them:
- A
Createthat mints the object, then anAddthat attaches it. - A
Createwhosecontextnames the case, which attaches the object in one message. ActivityPub servers post content this way withCreate(Note). - A note that is not part of any case.
- A private note from the Case Manager to one participant about a case, which the case record does not carry. Because the note does not travel through the case record, it could also reach an inert participant, which receives no case content. If the protocol adds this form, the Case Manager may send it but is never required to.
A participant that a precondition guard refused already learns why from the refusal notice, which is sent to that participant alone and is not recorded in the case.
The open question is whether the protocol adds any of these forms.
Each Create form changes the case file, so it needs its own committed ledger entry and a replica apply step.
The Create then Add form also needs a definition for an object that exists but is not attached.
A receiver must accept every form the protocol names, so each added form is a cost to every implementation.
Issue #4550 records the convention that one act names one form.
Cases and participants
Open question: where is the enacting actor after an ownership transfer?
A case ownership transfer moves the CASE_OWNER role from one actor to another actor.
It uses an Offer and Accept handshake through the CASE_MANAGER (ADR-0053).
The handshake does not set the location of the actor that enacts CASE_MANAGER.
If the organization of the new owner administers the case, there are two results.
The enacting actor moves to that organization, or it stays in position and the previous organization continues to hold a part in the case.
There are four possible methods, and the project has not selected one.
Migration changes the URI of the actor and tells each participant the new URI. This method is clear. It also controls the messages that are in transit and the replicas that use the previous URI.
A proxy keeps the previous instance, which forwards each message to the new instance. This method is simple. But if a second ownership transfer occurs, the chain of proxies becomes longer.
A Hyper Text Transfer Protocol (HTTP) 301 redirect with an AS2 Move keeps the initial URI as the canonical URI.
A new instance answers at that URI.
The fediverse uses Move and movedTo for actor migration, and ActivityPub itself does not define the mechanism.
A new actor, with the previous actor in a frozen condition, is the minimum work to build. It is also the largest risk to verification. New key material breaks the continuity of signatures across the transfer.
The redirect method is the most practical method from the current data. This is a working preference, not a decision.
Concern #3362 records this question.
Open question: what occurs when one Report becomes two Cases?
A Report is not a Case.
A Report is the object of the initial Offer.
A Case exists only after a recipient accepts that Offer.
Two Report formats are possible: plain text and JavaScript Object Notation (JSON) in the Common Security Advisory Framework (CSAF) format.
The project has not specified either format, and more formats can follow.
The CSAF 2.1 crosswalk compares the two object models, and Idea #5131 tracks how Vultron reads CSAF content in a Report.
The condition occurs when the same Report goes to more than one recipient. Each recipient can accept the Report and make its own Case from it. The protocol lets this condition occur, and this behavior is intentional. A recipient that wants more than one vendor in the coordination can make one Case and invite each vendor to it.
The frequent form of this condition is sequential, not concurrent.
A Reporter receives no answer to an Offer, and then it asks a Coordinator for aid.
The recipient of the second Offer accepts before the recipient of the first Offer accepts.
Therefore each Offer has an identifier that is unique to a minimum of the Report and the recipient.
The Reporter keeps a different record of each recipient and of the Case that each recipient makes.
The Reporter cannot join two Cases into one Case, because the Reporter owns neither Case. A merge becomes possible when the owner of one Case learns that the other Case exists. A proposed design is in ADR-0105. In that design, the owner of one Case offers to merge it into the other Case, and the owner of the other Case accepts or rejects the offer. The offered Case then becomes read-only. A redirect sends each request for the frozen Case to the Case that remains. The Case that remains invites each participant of the frozen Case. Two items are still open. The first item is the embargo obligations of a participant that declines the invitation. The second item is a design that keeps both Cases open and connects them.
Concern #3366 records this question.
Open question: which activities does each Participant receive?
A Participant holds case-scoped roles. The protocol settles the largest part of this question already. An Observer receives full case content, and no reduced delivery tier applies to a role (CM-25-003, ADR-0057). The gate on case content is admission to the case plus consent to the embargo, and it is not the role (MV-10-005).
The open part is smaller. It covers the single Activity, and it does not cover case content. A reduced tier for some Participants is a deferred mechanism, and the project has not specified it.
There are two possible locations for a routing policy of this type. The policy can be on the Participant, as metadata for a test against each activity. As an alternative, the policy can be with the CASE_MANAGER, as a set of role-based rules for fan-out. The second location agrees better with the other parts of the protocol. It keeps one actor responsible for the knowledge of each Participant.
For the two locations, the fan-out of the CASE_MANAGER continues to be a simple loop across the Participants. The per-Participant send makes the decision to relay an activity or not to relay it. A prototype can relay each activity to each Participant and stay correct. But the structure gives space for a complete set of rules.
Concern #3365 records this question.
Open question: acquiring a role after joining a case
This specification says how the Case Owner assigns a role and how a role is offered and accepted. It does not say how a participant already in a case asks for an additional one.
A participant admitted as a Vendor that later also needs the Coordinator
role has no protocol path to request it. In practice the request is made out
of band, or as a Add(Note) on the case, and the Case Owner then issues a
role offer. Neither is a specified mechanism.
Open: whether the protocol should define a role-request activity, whether a participant may decline a role it was assigned, and how a role that is removed rather than added is represented in the case history.
Protocol state
Open question: CS ordering constraints are unspecified
CS ordering constraints — including the pX→PX invariant (exploit-public
implies public-aware) and the rule that CP must precede ET where public
disclosure triggers embargo teardown — exist in three non-normative places:
a code docstring, a measurement-oriented reference document
(Possible Histories),
and a design note. No spec group covers them normatively.
A conformance claim cannot meaningfully cover CS ordering until this gap is closed. Treat the material cited here as informative until a normative spec is issued.
Open question: who may assert that a vendor became aware
The first VFD transition — v→V, vendor becomes aware — has no
trigger-side specification and no implementation. Design intent is a
third-party assertion ("I notified this Vendor"), not a self-report.
Open questions: who may assert it, whether the subject Vendor may dispute it, and whether transport-level delivery success, a Hypertext Transfer Protocol (HTTP) 200 response, suffices to constitute the assertion.
Do not infer a rule from this document's silence.
Open question: Case Owner discretion once a termination condition is canonical
Terminating a case-level embargo requires Case Owner authorization by default, and the CASE_MANAGER effects the teardown as the single writer of canonical case state. What is settled is who may terminate: any Participant may initiate termination (report a public/exploit/attacks condition, or notify intent to exit) and may terminate its own compliance, but only the Case Owner authorizes ending the embargo for the case.
What is not settled is whether the Case Owner retains any discretion once
a termination condition has been adopted as canonical case state. When public
awareness or exploit publication (\(q^{cs} \in \{\cdots P \cdots, \cdots X
\cdot\}\)) is canonical, VP-14-001/VP-14-002 read as a mandatory consequence —
the embargo no longer protects anything — and the working position of this
specification is that teardown is then mandatory, with the Case Owner's
authority exercised at the point the condition is adopted (guarding against
a false report) rather than as a second, separate decision to keep the
embargo. This matches the automatic-teardown path (a canonical CS.P set by
the Case Owner triggers teardown).
Open: whether the Case Owner may decline to tear down even after the
condition is canonical; whether the "attacks" condition (SHOULD, VP-11-006)
differs from the "public/exploit" condition (SHALL) in this respect; and how
a deliberate decision to keep an otherwise-terminable embargo would be
recorded. This is expected to be a matter of discussion; the resolution MUST
be reflected in this reference and in specs/vultron-protocol-spec.yaml
(VP-11, VP-14) once reached.
History and delivery
Open question: does a case ledger need distributed consensus?
Each case has one writer. The actor that enacts CASE_MANAGER is the only author of the canonical hash-chained case ledger. Each Participant Case Replica is a projection of that ledger (PCR-03-001, PCR-03-002). This is an intentional simplification. This single-writer regime needs no consensus protocol. The hash chain also keeps the history tamper-evident, and each Participant can verify it independently.
It is not clear if one writer is correct for each case. A case that has two parties, a finder and a vendor, has too few Participants for useful consensus. A case can also have many vendors, coordinators, and deployers. Such a case can possibly divide the coordination authority across the Participants, and not hold it in one actor. The append-only hash-chained ledger has properties now that a consensus artifact needs.
The working position is that a simple case keeps one CASE_MANAGER. A distributed model adds to that position, and it does not replace it. Epic #1158 records this research. The project defers the work until the current protocol model becomes stable.
Open question: how strong are the necessary ordering guarantees?
Ledger fanout does not occur immediately. The CASE_MANAGER relays a Case Ledger Entry to Participants on more than one instance. For a short time, those Participants can see the activities in different sequences.
The current position is that eventual consistency is sufficient.
The project knows of no part of the protocol that uses the sequence of arrival.
The logIndex value of each entry holds the correct sequence.
A Participant that receives entries 1, 2, 3, and 5 finds that entry 4 is missing.
It buffers entry 5, and ledger reconciliation delivers entry 4 (SYNC-00-007, ADR-0037).
The Participant does not use a history that has missing entries.
Gap detection replaces delivery order.
One point is not tested. The project does not know if a coordination decision needs a stronger guarantee than eventual consistency.
Task #5102 audits the protocol decisions for a dependency on the sequence of arrival.
Open question: do Participants acknowledge delivery?
The delivery log of the CASE_MANAGER records each message that it sent, and the time. It cannot record which messages the Participants received. A Participant can send a receipt activity when a message arrives. The log then shows the difference between confirmed delivery and best-effort delivery. Retry logic then has better data than a time-out.
Receipts have a cost in message volume. Thus receipts are optional, not mandatory. A prototype can record its delivery attempts and supply no receipts. But the architecture lets a later version add receipts without a change to the core protocol.
The activity type for a receipt is unsettled.
Read is too strong, because it shows that the Participant processed the activity.
A Receive or Ack activity is the weaker statement.
It also gives the delivery log the data that the log needs.
Concern #3363 records this question.
Open question: negative-acknowledgment semantics are unspecified
Error message types (RE, EE, CE) are deliberately unmodeled
(ADR-0049). Unprocessable inbound messages are dead-lettered with no sender
notification. The three-way fault partition
(§4.6 Error and Acknowledgment Messages, ADR-0083) provides
structured error signaling where it is implemented, but whether the
protocol needs a normative negative-acknowledgment facet — and if so,
what the expected sender behavior (retry, suppress, escalate) should be —
remains open.
Open question: which HTTP responses a receiving actor returns
This version does not say which HTTP status code a receiving actor returns when it refuses a message. For example, it does not say whether an invalid activity gets 422, an activity addressed only to other actors gets 400, or a message that cannot be decrypted gets 400.
One option is for the protocol to specify these responses, so that a sending actor can rely on them and act on them. The other is to leave them to each server implementation. A Vultron actor built on a stock ActivityPub server returns whatever that server returns, so a protocol rule could conflict with the server it runs on.
Until this is settled, these codes are recorded as the reference implementation's choices, not as protocol requirements. The codes that HTTP itself defines, such as 405 for an unsupported method and 413 for a body that is too large, are not part of this question.
Security
Open question: what does a deployment sign and encrypt?
The prototype does not sign or encrypt its messages. Activities move as plaintext AS2 JSON on HTTP. The adapter for signed remote delivery is a stub (OX-10). The prototype is a demonstration of coordination logic, not a service for deployment. Concern #509 records this gap.
Encryption has a design.
specs/encryption.yaml (ENC-01 through ENC-03) gives each actor a key pair.
It publishes the public key in the actor profile.
It also puts decryption in the inbox handler, before semantic extraction.
Each handler thus continues to receive typed and validated activities.
Each requirement in that file has scope: production.
The requirements apply to a deployment, and the prototype is not a deployment.
Signing has no specification. The intended shape puts two signatures on a relayed activity. The inner signature comes from the Participant that originated the activity. The outer signature comes from the CASE_MANAGER that relayed it. A recipient can thus verify the source and the relay position independently. HTTP Message Signatures is the candidate transport mechanism, and Request for Comments (RFC) 9421 defines it (#892, #1163).
Three points are open. First, the project has not selected the requirements that apply to a deployment that claims Vultron conformance. Second, per-recipient encryption (ENC-02-002) can be sufficient for a case that has many Participants, or a multi-recipient envelope format can be necessary. Third, key material applies to an actor identity, not to a case. The quantity of cases that one CASE_MANAGER actor holds thus sets the separation between the keys of those cases. Epic #1156 records this work, and the actor identity model is open (#2841).