Client-side wire helpers for the capability Trust Task families —
governance/capability/* (enable / disable / list a community capability)
and git-trust/* (grant / revoke commit-signing trust).
This crate owns the documents, not a transport: it builds request
documents, parses inbound envelope replies, classifies them, and (behind
the signing feature) attaches a Data-Integrity proof. Each consumer keeps
its own send/receive plumbing but shares this wire layer, so a capability
producer (a community service) and a management UI cannot drift on the
contract.
Layers
- Envelope: capability documents travel as the
trust-tasks-didcommbinding envelope ([TRUST_TASK_ENVELOPE_TYPE]); [parse_envelope_document] turns an inbound body into(threadId, document). - Builders: [
build_document] plus the family-specific [build_list_document], [build_toggle_document], [build_git_trust_grant], [build_git_trust_revoke]. - Replies: [
classify_git_trust_reply] (for grant/revoke writers) and [parse_capability_reply] (for governance management UIs).
Retries versus fresh attempts
This crate is a producer, and the producer half of SPEC §7.2 item 11 is
§8.4: a retry is a bit-for-bit identical resend. As of trust-tasks-rs
0.12.0 there is a consumer that enforces it — the record is keyed on the
document id and compared against the whole document — and the DIDComm and
TSP bindings now keep that record by default. So the two ways of sending a
request again have become genuinely different operations:
| Intent | What to send | What the consumer does |
|---|---|---|
| The first send may not have arrived | previous itself, unchanged |
Absorbs it; returns whatever the first execution determined |
| Something about the request changed | new_attempt(&previous) |
Treats it as the new document it is |
Anything else under a reused id |
— | Rejects it with idConflict |
"Something about the request changed" is wider than it sounds: a re-stamped
issuedAt or a re-signed proof over identical content is already a
different document. That is deliberate — §8.4 says a producer that
"retries" by re-signing "has not retried", and the whole point of item 11's
comparison is that an id alone cannot tell the retry it must absorb from
the conflict it must reject.
[build_document] and every builder over it mint a fresh id per call, so
a caller that rebuilds is already minting a new attempt. [new_attempt]
covers the case where the document has already been built (and possibly
signed) and is about to be sent again.
Signing is deliberately not here — it is a thin Data-Integrity call
each consumer makes with its own signer (a service reuses its credential
signer; a client signs with the persona key), so this crate stays free of
any crypto dependency. Sign the built document over its canonical form
(the document minus its proof member, eddsa-jcs-2022) and set the
proof member.
Versioning
This crate exposes trust-tasks-rs types in its own public API, so a
breaking change there breaks this crate's callers even when nothing here
changes. cargo-semver-checks cannot catch that: it compares each crate's
rustdoc against that crate's own published baseline, and does not track
type identity across dependency versions. The crates that share
trust-tasks-rs in their public API are therefore released as one
compatibility unit with a single shared version — see version_group in
release-plz.toml.