Skip to content

docs: credential status convention + W3C DID resolution#58

Open
aguilar1x wants to merge 4 commits into
devfrom
docs/spec-credential-status-and-resolution
Open

docs: credential status convention + W3C DID resolution#58
aguilar1x wants to merge 4 commits into
devfrom
docs/spec-credential-status-and-resolution

Conversation

@aguilar1x
Copy link
Copy Markdown
Contributor

@aguilar1x aguilar1x commented Jun 5, 2026

Closes two W3C-conformance gaps in the did:stellar spec found in the contract/spec audit. No contract changes — both are spec/convention only.

1. Credential Status (Annex B.4) — StellarStatusRegistryEntry

The vc-vault tracks per-VC status on-chain (verify_vc), but a third-party verifier had no standard way to discover it. Adds a W3C VC Data Model 2.0 §4.10 credentialStatus method:

"credentialStatus": {
  "type": "StellarStatusRegistryEntry",
  "statusPurpose": "revocation",
  "network": "testnet",
  "statusContract": "C...",
  "vcId": "vc-123"
}

The verifier resolves it via a read-only verify_vc(vcId) RPC call (Valid/Revoked/Invalid). Custom status types are explicitly permitted by §4.10, and the read-only ledger lookup never notifies the issuer — satisfying the §4.10 privacy MUST against holder tracking.

2. DID Resolution (§5.7)

The spec defined DID Document construction (§5) but not resolution per W3C DID Resolution v0.3. Adds §5.7:

  • resolve() three-tuple result + resolution algorithm
  • didResolutionMetadata (contentType, error)
  • didDocumentMetadata (created/updated/versionId/deactivated mapped from DidRecord ledger fields)
  • Error model with HTTP bindings (invalidDid 400, notFound 404, deactivated 410, representationNotSupported 406, …)

Both close gaps documented in the audit; the resolver/verifier that consume these conventions remain off-chain work.

Summary by CodeRabbit

Release Notes

  • Documentation
    • Specified DID Resolution process including resolver contract behavior, validation, and document construction requirements.
    • Specified Credential Revocation Status with on-chain verification procedures and privacy guarantees.

aguilar1x added 2 commits June 5, 2026 02:10
…ention

The vc-vault tracks per-VC status on-chain (verify_vc) but a third-party
verifier had no standard way to discover it. Add Annex B.4 defining a
W3C VC Data Model 2.0 §4.10 credentialStatus method (StellarStatusRegistryEntry):
the status entry points to the vault contract + vc_id, and the verifier
resolves it via a read-only verify_vc RPC call.

Custom status types are explicitly permitted by §4.10. The read-only
ledger lookup never notifies the issuer, satisfying the §4.10 privacy
MUST against holder tracking. No contract changes.
The spec defined DID Document construction (5) but not resolution per
W3C DID Resolution v0.3. Add 5.7 covering the resolve() three-tuple
result, the resolution algorithm, didResolutionMetadata (contentType +
error), didDocumentMetadata (created/updated/versionId/deactivated
mapped from DidRecord ledger fields), and the error model with HTTP
bindings (invalidDid 400, notFound 404, deactivated 410, etc.). Add the
DID Resolution reference. No contract changes.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 5, 2026

Review Change Stack

Warning

Review limit reached

@aguilar1x, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 45 minutes and 43 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 66336333-9714-477b-bc26-bfd7783f2e45

📥 Commits

Reviewing files that changed from the base of the PR and between fe02d9b and f0181bd.

📒 Files selected for processing (2)
  • docs/did-spec/did-stellar-v0.1.md
  • docs/did-spec/test-vectors/vectors.json
📝 Walkthrough

Walkthrough

This PR adds two specification sections to the Stellar DID method specification: a complete DID Resolution algorithm defining how resolvers retrieve and construct DID documents from on-chain registry data, and a Credential Status integration pattern for verifying verifiable credential revocation status through on-chain vault contracts.

Changes

Stellar DID Resolution and Credential Status Specifications

Layer / File(s) Summary
DID Resolution specification
docs/did-spec/did-stellar-v0.1.md
Resolver interface contract returning didDocument, didResolutionMetadata, and didDocumentMetadata; resolution algorithm with syntax validation, base32 decoding, registry lookup, and tombstone handling for deactivated DIDs; HTTP error/status mappings.
Credential status and revocation verification
docs/did-spec/did-stellar-v0.1.md
StellarStatusRegistryEntry payload type and verification binding statusContract to issuance contract; on-chain verify_vc(vcId) calls via Stellar RPC with outcome mapping and privacy statements; updated references.

Estimated Code Review Effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 A rabbit hops through specs so clear,
Where DIDs resolve without a fear,
And credentials checked on-chain above,
Revocation tracked with Stellar's love. ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title 'docs: credential status convention + W3C DID resolution' accurately summarizes the two main specification additions: credential status (Annex B.4) and DID Resolution (§5.7), matching the changeset content.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch docs/spec-credential-status-and-resolution

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@aguilar1x aguilar1x changed the title docs(did-spec): credential status convention + W3C DID resolution docs: credential status convention + W3C DID resolution Jun 5, 2026
@aguilar1x aguilar1x self-assigned this Jun 5, 2026
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
docs/did-spec/did-stellar-v0.1.md (1)

387-389: 💤 Low value

Consider clarifying "successful resolution" vs HTTP 410 for deactivated DIDs.

The text states that a deactivated DID results in "a successful resolution (no error)" but then notes "an HTTP binding MUST map it to 410 Gone." This juxtaposition might confuse readers about whether the resolution succeeded or failed.

Consider rephrasing to clarify that the DID Resolution protocol-level result is successful (document returned, no error in metadata) but the HTTP status reflects the deactivated state:

✏️ Optional clarification
-   Document (Annex A.3) with `didDocumentMetadata.deactivated = true`. This is a
-   successful resolution (no `error`), but an HTTP binding MUST map it to `410 Gone`.
+   Document (Annex A.3) with `didDocumentMetadata.deactivated = true`. At the DID 
+   Resolution protocol level this is successful (no `error` in `didResolutionMetadata`),
+   but HTTP bindings MUST return `410 Gone` to reflect the deactivated state.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/did-spec/did-stellar-v0.1.md` around lines 387 - 389, Clarify the
wording so readers understand protocol vs transport: state that when
DidRecord.deactivated == true the DID Resolution operation itself is considered
successful (it returns the tombstone DID Document with
didDocumentMetadata.deactivated = true and no protocol-level `error`), but an
HTTP binding MUST translate that protocol-level successful resolution into an
HTTP 410 Gone response; update the sentence to explicitly mention "resolution
result" vs "HTTP transport status" and include the symbols
DidRecord.deactivated, didDocumentMetadata.deactivated, and HTTP 410 in the
revised text.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/did-spec/did-stellar-v0.1.md`:
- Line 820: The table's `id` row incorrectly references this spec's §4.4; update
the text for the `id` field to point to the correct external authority (e.g.,
"MUST be a single URL (see W3C VC Data Model 2.0 §4.4)" or similar), or remove
the intra-spec section marker and replace it with a clear citation to the W3C VC
Data Model section about credential identifiers; ensure the change is applied to
the `id` table cell text so the `id` field reference is unambiguous.
- Around line 403-404: The spec's description for created/updated (fields
`created`/`updated` mapping
`DidRecord.created_ledger`/`DidRecord.updated_ledger`) is ambiguous about which
Stellar API and field to use and how to convert to ISO 8601 UTC; update the text
to explicitly state either (a) use Horizon's ledger endpoint and its `closed_at`
ISO 8601 field (no conversion required), or (b) if using the RPC `getLedgers`
method, read the `ledgerCloseTime` Unix timestamp and convert it to an ISO 8601
UTC string (e.g., use UTC epoch seconds -> ISO 8601), and include that clear
method/field and conversion rule for `created` and `updated`.

---

Nitpick comments:
In `@docs/did-spec/did-stellar-v0.1.md`:
- Around line 387-389: Clarify the wording so readers understand protocol vs
transport: state that when DidRecord.deactivated == true the DID Resolution
operation itself is considered successful (it returns the tombstone DID Document
with didDocumentMetadata.deactivated = true and no protocol-level `error`), but
an HTTP binding MUST translate that protocol-level successful resolution into an
HTTP 410 Gone response; update the sentence to explicitly mention "resolution
result" vs "HTTP transport status" and include the symbols
DidRecord.deactivated, didDocumentMetadata.deactivated, and HTTP 410 in the
revised text.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 079def65-8354-434e-8511-26ae67940f76

📥 Commits

Reviewing files that changed from the base of the PR and between b813345 and fe02d9b.

📒 Files selected for processing (1)
  • docs/did-spec/did-stellar-v0.1.md

Comment on lines +403 to +404
| `created` | `DidRecord.created_ledger` | The resolver maps the ledger sequence to its close time (ISO 8601 UTC) via Stellar RPC. |
| `updated` | `DidRecord.updated_ledger` | Same mapping. Equals `created` until the first mutation. |
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Verify Stellar RPC provides ledger close time mapping

# Check if Stellar documentation describes ledger close time retrieval
rg -i "close.*time|ledger.*timestamp" --type md -C3

Repository: ACTA-Team/contracts-acta

Length of output: 763


🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE="docs/did-spec/did-stellar-v0.1.md"

# Show the exact section around the cited lines
sed -n '380,430p' "$FILE" | nl -ba

echo "----"

# See if the spec already mentions any specific Stellar RPC/Horizon method names (e.g., getLedger)
rg -n --hidden --no-ignore-vcs "getLedger|ledger.*close|close.*time|horizon|rpc" "$FILE"

Repository: ACTA-Team/contracts-acta

Length of output: 111


🌐 Web query:

Stellar Horizon API getLedger ledger close time field name

💡 Result:

In the Stellar Horizon API, the field name for the ledger close time is closed_at [1][2][3]. This field returns an ISO 8601 formatted string indicating the time when the specific ledger was closed and committed to the network [1][4][2]. Note: This field name is specific to the Horizon API [2]. If you are using the Stellar RPC API (often used for Soroban and other low-level network interactions), the equivalent field is typically named ledgerCloseTime [5].

Citations:


🌐 Web query:

Stellar RPC getLedger returns ledger closed time timestamp

💡 Result:

In the Stellar RPC API, specifically for the getLedgers method, the ledger closed time is returned as a Unix timestamp [1][2][3]. For an individual ledger object within the getLedgers response, this field is named ledgerCloseTime and is returned as a number (Unix timestamp) [1][4], though in some implementation documentation it may be noted as a string or a 64-bit integer [2]. Additionally, the top-level getLedgers response includes fields for the latest and oldest ledgers, which use the following timestamp formats: - latestLedgerCloseTime: A Unix timestamp representing the close time of the latest ledger [1][5]. - oldestLedgerCloseTime: A Unix timestamp representing the close time of the oldest ledger ingested by the RPC node [1][5]. Note that this differs from the Stellar Horizon API, which typically returns closed_at timestamps in ISO-8601 string format [6]. If you are working with other RPC methods like getEvents, you may encounter ledgerClosedAt as an ISO-8601 string [7], so it is recommended to verify the specific method documentation as formats can vary across the RPC interface [8].

Citations:


Clarify ledger-to-timestamp mapping for created/updated.

The spec says created/updated map DidRecord.*_ledger to ISO 8601 UTC “via Stellar RPC” but doesn’t name the method/field or the required timestamp conversion. Stellar Horizon exposes ledger close time as closed_at (ISO 8601), while Stellar RPC (e.g., getLedgers) returns ledgerCloseTime as a Unix timestamp—so the spec should either (a) reference the Horizon endpoint/closed_at, or (b) name the exact RPC method/field and state the conversion to ISO 8601 UTC. (docs/did-spec/did-stellar-v0.1.md:403-404)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/did-spec/did-stellar-v0.1.md` around lines 403 - 404, The spec's
description for created/updated (fields `created`/`updated` mapping
`DidRecord.created_ledger`/`DidRecord.updated_ledger`) is ambiguous about which
Stellar API and field to use and how to convert to ISO 8601 UTC; update the text
to explicitly state either (a) use Horizon's ledger endpoint and its `closed_at`
ISO 8601 field (no conversion required), or (b) if using the RPC `getLedgers`
method, read the `ledgerCloseTime` Unix timestamp and convert it to an ISO 8601
UTC string (e.g., use UTC epoch seconds -> ISO 8601), and include that clear
method/field and conversion rule for `created` and `updated`.

| Property | Requirement | Meaning |
|---|---|---|
| `type` | MUST | Fixed `"StellarStatusRegistryEntry"`. (Per §4.10, `type` is REQUIRED.) |
| `id` | MAY | If present, MUST be a single URL (§4.4). Optional human/resolver endpoint. |
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Clarify the section reference for the id field.

The table states that the optional id field "MUST be a single URL (§4.4)," but §4.4 in this document refers to "Mutation Semantics" in the Contract Operations section, which is unrelated to credential status.

This reference likely refers to W3C VC Data Model 2.0 §4.4 (or a similar section about credential identifiers), not this specification's §4.4.

📝 Proposed clarification
-| `id` | MAY | If present, MUST be a single URL (§4.4). Optional human/resolver endpoint. |
+| `id` | MAY | If present, MUST be a single URL (W3C VC Data Model §4.4). Optional human/resolver endpoint. |
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
| `id` | MAY | If present, MUST be a single URL (§4.4). Optional human/resolver endpoint. |
| `id` | MAY | If present, MUST be a single URL (W3C VC Data Model §4.4). Optional human/resolver endpoint. |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/did-spec/did-stellar-v0.1.md` at line 820, The table's `id` row
incorrectly references this spec's §4.4; update the text for the `id` field to
point to the correct external authority (e.g., "MUST be a single URL (see W3C VC
Data Model 2.0 §4.4)" or similar), or remove the intra-spec section marker and
replace it with a clear citation to the W3C VC Data Model section about
credential identifiers; ensure the change is applied to the `id` table cell text
so the `id` field reference is unambiguous.

aguilar1x added 2 commits June 5, 2026 02:22
- Pin challenge_jcs_hex (canonical RFC 8785 form) in vectors 5-6 so every
  implementation MUST canonicalize to exactly these bytes before signing.
  The Ed25519 signatures still await the off-chain reference impl.
- Add vector 7 (multi-key: exercises #auth-2 index numbering).
- Add vectors 8-9 (DID Resolution errors: notFound 404 / invalidDid 400)
  per the new 5.7 resolution section.

Closes the vector coverage gaps from the audit (no contract changes).
DID Core 1.1 §7.3 requires documenting the RFC 3552 attack forms; §7.4
requires discussing each applicable RFC 6973 §5 privacy category. The
spec previously covered only replay (security) and correlation/disclosure
(privacy).

- 7.9 Attack Surface: enumerate all 8 mandated attack forms (eavesdropping,
  replay, message insertion/deletion/modification, DoS, amplification, MITM)
  with method-specific treatment.
- 7.10 Operation integrity, authentication, unique assignment (DidAlreadyExists
  + 128-bit id), and which data is cryptographically protected.
- 7.11 Verifiable-data-registry / DLT trust assumptions and residual risk.
- 8.6 RFC 6973 coverage: all 9 categories mapped (surveillance, stored-data
  compromise, unsolicited traffic, misattribution, correlation, identification,
  secondary use, disclosure, exclusion).
- Fix the §7/§8 citations to the normative §7.3/§7.4 titles.

No contract changes.
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