Skip to content

Support FEP-ef61 portable ActivityPub IRIs in vocab codecs#850

Open
dahlia wants to merge 34 commits into
fedify-dev:mainfrom
dahlia:feat/fep-ef61/ap-iris
Open

Support FEP-ef61 portable ActivityPub IRIs in vocab codecs#850
dahlia wants to merge 34 commits into
fedify-dev:mainfrom
dahlia:feat/fep-ef61/ap-iris

Conversation

@dahlia

@dahlia dahlia commented Jun 29, 2026

Copy link
Copy Markdown
Member

Fixes #826.

Why this is shaped this way

Fedify vocabulary objects already use URL as the internal representation for IRI-like fields. This PR keeps that contract instead of introducing a parallel portable IRI type. The awkward part of FEP-ef61 is that the readable form uses a decoded DID authority, such as ap+ef61://did:key:.../actor, while the platform URL parser needs that authority to be URL-safe. The new runtime helpers in packages/vocab-runtime/src/url.ts make that boundary explicit: parse portable ActivityPub IRIs into normal URL objects with encoded authorities, then format those URL objects back to canonical ap+ef61: strings when JSON-LD is emitted.

That keeps the generated vocabulary classes from having to know the details of portable IRI parsing. packages/vocab-tools/src/codec.ts and packages/vocab-tools/src/type.ts now call the shared helpers wherever generated code previously reached for new URL(), URL.canParse(), or .href on an IRI field. This also preserves the existing at:// workaround in one place instead of duplicating it in the generated code.

The JSON-LD cache path needed a small extra guard. When an object is built from JSON-LD that already contains portable IRIs, returning the raw cached document would skip the formatter and leak the input spelling back out. Generated codecs now only reuse the raw JSON-LD cache when the input does not contain ap: or ap+ef61: portable IRI syntax.

Scope

This PR handles parsing and formatting for generated vocab codecs. It accepts ap: and ap+ef61: values with decoded or percent-encoded DID authorities, stores them internally as URL-safe URL objects, and emits canonical ap+ef61: values with decoded DID authorities.

It intentionally does not add comparison canonicalization that ignores query components. That belongs to the follow-up comparison work tracked separately in #828.

Verification

I covered the behavior at both levels: focused tests for the runtime helpers in packages/vocab-runtime/src/url.test.ts, and generated vocab behavior in packages/vocab/src/vocab.test.ts. The vocab test exercises object IDs, link-like properties, collection page links, decoded DID authorities, percent-encoded DID authorities, uppercase schemes, query strings, and JSON-LD round-tripping through toJsonLd().

I also regenerated the vocab-tools snapshots and updated the manual and changelog.

Commands run:

mise run test:update_snapshots
deno test packages/vocab-runtime/src/url.test.ts
deno test -A packages/vocab/src/vocab.test.ts --filter 'portable ActivityPub IRIs'
mise check && mise test

@dahlia dahlia added this to the Fedify 2.4 milestone Jun 29, 2026
@dahlia dahlia self-assigned this Jun 29, 2026
@dahlia dahlia added component/vocab Activity Vocabulary related activitypub/compliance Specification compliance component/vocab-tools Vocabulary code generation (@fedify/vocab-tools) labels Jun 29, 2026
@netlify

netlify Bot commented Jun 29, 2026

Copy link
Copy Markdown

Deploy Preview for fedify-json-schema canceled.

Name Link
🔨 Latest commit 6809204
🔍 Latest deploy log https://app.netlify.com/projects/fedify-json-schema/deploys/6a4478f8255fba000830dfa5

@dahlia

dahlia commented Jun 29, 2026

Copy link
Copy Markdown
Member Author

@codex review

@coderabbitai

coderabbitai Bot commented Jun 29, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds portable ap:/ap+ef61: IRI support in vocab-runtime, updates generated vocab codecs and scalars to use the new helpers, and adds regression tests, documentation, and release-note updates.

Changes

FEP-ef61 Portable ActivityPub IRI Support

Layer / File(s) Summary
parseIri / formatIri / canParseIri implementation
packages/vocab-runtime/src/url.ts, packages/vocab-runtime/src/mod.ts
Adds portable IRI parsing and formatting helpers, internal authority normalization helpers, and runtime re-exports.
Unit tests for parseIri / formatIri / canParseIri
packages/vocab-runtime/src/url.test.ts
Adds tests for portable ap: and ap+ef61: parsing, canonical formatting, non-DID rejection, and round-trip preservation.
Portable IRI detection in generators
packages/vocab-tools/src/class.ts
Updates generator wiring to collect portable-IRI keys and emit portable IRI detection logic.
Codec and scalar updates
packages/vocab-tools/src/codec.ts, packages/vocab-tools/src/type.ts
Replaces direct URL handling with portable IRI helpers in JSON-LD codec and scalar generation, and skips cached JSON-LD cloning for portable-IRI payloads.
Integration tests and release docs
packages/vocab/src/vocab.test.ts, docs/manual/vocab.md, CHANGES.md, SPONSORS.md
Adds portable-IRI round-trip tests, documents the JSON-LD behavior, adds the changelog entry, and adjusts sponsor whitespace.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related issues

Suggested labels

type/enhancement

Suggested reviewers

  • 2chanhaeng
  • sij411
🚥 Pre-merge checks | ✅ 2 | ❌ 3

❌ Failed checks (3 warnings)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The PR implements portable IRI parsing and formatting, but it omits the requested comparison canonicalization helper that ignores query components. Add the query-insensitive comparison canonicalization helper in @fedify/vocab-runtime and wire it into the portable IRI comparison path.
Out of Scope Changes check ⚠️ Warning SPONSORS.md was changed only with whitespace adjustments, which is unrelated to the portable IRI codec work. Remove the unrelated SPONSORS.md whitespace-only edits unless they were intentionally included for another approved change.
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main change: adding FEP-ef61 portable ActivityPub IRI support in vocab codecs.
Description check ✅ Passed The description is directly about the portable IRI codec changes and their supporting tests, docs, and changelog updates.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces support for FEP-ef61 portable ActivityPub IRIs (using ap: and ap+ef61: schemes) within the generated vocabulary codecs. It adds new utility functions (canParseIri, parseIri, and formatIri) to handle parsing and canonical serialization of these IRIs, updates the vocabulary generation tools to integrate these utilities, and includes comprehensive tests. The review feedback suggests refining the PORTABLE_IRI_PATTERN regular expression in the class generator to prefix it with a double quote, ensuring it only matches the start of JSON string values and avoiding false positives in text properties.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread packages/vocab-tools/src/class.ts Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5c67df65fe

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/vocab-tools/src/codec.ts Outdated
@codecov

codecov Bot commented Jun 29, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 96.02273% with 7 lines in your changes missing coverage. Please review.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
packages/vocab-runtime/src/url.ts 92.70% 3 Missing and 4 partials ⚠️
Files with missing lines Coverage Δ
packages/vocab-runtime/src/mod.ts 100.00% <100.00%> (ø)
packages/vocab-tools/src/class.ts 99.00% <100.00%> (+0.41%) ⬆️
packages/vocab-tools/src/codec.ts 97.65% <100.00%> (ø)
packages/vocab-tools/src/property.ts 95.85% <ø> (ø)
packages/vocab-tools/src/type.ts 84.40% <100.00%> (-0.21%) ⬇️
packages/vocab/src/lookup.ts 96.44% <100.00%> (+0.04%) ⬆️
packages/vocab-runtime/src/url.ts 90.22% <92.70%> (+1.12%) ⬆️

... and 1 file with indirect coverage changes

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

dahlia added a commit to dahlia/fedify-fork that referenced this pull request Jun 29, 2026
Generated codecs now look for portable ActivityPub IRIs only in
ID-valued JSON-LD positions before deciding whether to bypass the raw
JSON-LD cache. This keeps ordinary text such as post content from
causing cache misses and dropping extension properties on default
serialization.

fedify-dev#850 (comment)
fedify-dev#850 (comment)

Assisted-by: Codex:gpt-5.5
@dahlia

dahlia commented Jun 29, 2026

Copy link
Copy Markdown
Member Author

@codex review

@dahlia

dahlia commented Jun 29, 2026

Copy link
Copy Markdown
Member Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request adds support for FEP-ef61 portable ActivityPub IRIs in generated vocabulary codecs, allowing "ap:" and "ap+ef61:" schemes to be parsed, serialized, and validated. Feedback on the changes highlights a potential Denial of Service (DoS) vulnerability in the generated "hasPortableIri" recursive function, which traverses JSON-LD objects without a depth limit or skipping the "@context" property. It is recommended to implement a recursion depth limit and skip "@context" to prevent stack overflow errors.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread packages/vocab-tools/src/class.ts Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6f9581bd2a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/vocab-runtime/src/url.ts
Comment thread packages/vocab-tools/src/codec.ts Outdated
dahlia added a commit to dahlia/fedify-fork that referenced this pull request Jun 29, 2026
Portable IRI formatting now preserves pct-encoded DID authority
boundaries, and generated cache detection now inspects expanded JSON-LD
with bounded traversal. That keeps alias-expanded portable IRIs from
being cached in their raw form while avoiding unnecessary context walks.

fedify-dev#850 (comment)
fedify-dev#850 (comment)
fedify-dev#850 (comment)

Assisted-by: Codex:gpt-5.5
@dahlia

dahlia commented Jun 29, 2026

Copy link
Copy Markdown
Member Author

@codex review

@dahlia

dahlia commented Jun 29, 2026

Copy link
Copy Markdown
Member Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces support for FEP-ef61 portable ActivityPub IRIs in the generated vocabulary codecs. It adds utility functions (canParseIri, parseIri, and formatIri) to handle ap: and ap+ef61: schemes with DID authorities, ensuring they are correctly parsed into URL objects and serialized back to canonical ap+ef61: formats. The code generator and runtime codecs have been updated to integrate these utilities, and comprehensive tests have been added. The feedback suggests minor code simplifications: optimizing parseAtUri to avoid redundant string searches and using optional chaining in canContainIriValue to improve readability.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread packages/vocab-runtime/src/url.ts
Comment thread packages/vocab-tools/src/class.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 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 `@packages/vocab-runtime/src/url.ts`:
- Around line 67-71: Route URL inputs through the same portable-authority
normalization used by parsePortableIri(). In normalizePortableUrl(), do not
reconstruct the URL directly from iri.host/pathname; instead apply the same
did:-only authority validation and encodeURIComponent re-encoding logic so URL
and string inputs behave identically. Preserve the existing ap:/ap+ef61:
protocol acceptance in normalizePortableUrl(), but ensure the returned URL uses
the same internal portable-authority form as the parser.
🪄 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: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: f66ccc6c-1f52-48ea-ac0a-c389348f1a57

📥 Commits

Reviewing files that changed from the base of the PR and between 6f9581b and 8108116.

⛔ Files ignored due to path filters (3)
  • packages/vocab-tools/src/__snapshots__/class.test.ts.deno.snap is excluded by !**/*.snap
  • packages/vocab-tools/src/__snapshots__/class.test.ts.node.snap is excluded by !**/*.snap
  • packages/vocab-tools/src/__snapshots__/class.test.ts.snap is excluded by !**/*.snap
📒 Files selected for processing (5)
  • packages/vocab-runtime/src/url.test.ts
  • packages/vocab-runtime/src/url.ts
  • packages/vocab-tools/src/class.ts
  • packages/vocab-tools/src/codec.ts
  • packages/vocab/src/vocab.test.ts

Comment thread packages/vocab-runtime/src/url.ts

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8108116bdd

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/vocab-runtime/src/url.ts Outdated
Comment thread packages/vocab-tools/src/codec.ts Outdated
dahlia added a commit to dahlia/fedify-fork that referenced this pull request Jun 29, 2026
Portable URL instances now use the same authority validation and
encoding path as string inputs, so DID boundaries and DID-internal
percent escapes round-trip consistently. Generated cache detection also
treats fedify:url scalar values as IRI-bearing fields without disabling
caching for plain text fields.

fedify-dev#850 (comment)
fedify-dev#850 (comment)
fedify-dev#850 (comment)
fedify-dev#850 (comment)
fedify-dev#850 (comment)

Assisted-by: Codex:gpt-5.5
@dahlia

dahlia commented Jun 29, 2026

Copy link
Copy Markdown
Member Author

@codex review

@dahlia

dahlia commented Jun 29, 2026

Copy link
Copy Markdown
Member Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces support for FEP-ef61 portable ActivityPub IRIs in the generated vocabulary codecs, allowing both ap: and ap+ef61: schemes to be parsed as URL objects and serialized canonically. To support this, new utility functions canParseIri, parseIri, and formatIri were added to the runtime and integrated into the vocabulary generation tools. Feedback on the changes highlights a potential TypeError in formatIri when processing relative URI strings, as it attempts to instantiate a URL without a base URL; a fallback check is recommended to improve robustness.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread packages/vocab-runtime/src/url.ts Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4b6047f952

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/vocab-runtime/src/url.ts
dahlia added a commit to dahlia/fedify-fork that referenced this pull request Jun 29, 2026
Pathless portable ActivityPub IRIs are now rejected before URL
normalization, matching FEP-ef61's required path component. Non-portable
relative strings passed to formatIri now remain unchanged instead of
raising from the fallback URL formatter.

fedify-dev#850 (comment)
fedify-dev#850 (comment)

Assisted-by: Codex:gpt-5.5
dahlia added 28 commits July 1, 2026 11:18
Portable URL instances now use the same authority validation and
encoding path as string inputs, so DID boundaries and DID-internal
percent escapes round-trip consistently. Generated cache detection also
treats fedify:url scalar values as IRI-bearing fields without disabling
caching for plain text fields.

fedify-dev#850 (comment)
fedify-dev#850 (comment)
fedify-dev#850 (comment)
fedify-dev#850 (comment)
fedify-dev#850 (comment)

Assisted-by: Codex:gpt-5.5
Pathless portable ActivityPub IRIs are now rejected before URL
normalization, matching FEP-ef61's required path component. Non-portable
relative strings passed to formatIri now remain unchanged instead of
raising from the fallback URL formatter.

fedify-dev#850 (comment)
fedify-dev#850 (comment)

Assisted-by: Codex:gpt-5.5
Portable IRI authority validation now treats the DID scheme
case-insensitively while preserving the authority spelling for
round-tripping. This keeps raw and percent-encoded DID authorities on
the same validation path.

fedify-dev#850 (comment)
fedify-dev#850 (comment)

Assisted-by: Codex:gpt-5.5
Portable IRI detection now treats JSON-LD value, list, and set
containers as identifier positions when their parent property can hold
IRIs. When a source document already uses those positions, the cached
clone is normalized instead of being discarded, so extension data stays
available without leaking raw portable IRI spelling.

fedify-dev#850 (comment)
fedify-dev#850 (comment)

Assisted-by: Codex:gpt-5.5
Inline JSON-LD contexts can alias a known IRI property, so raw
cache checks need to treat those aliases as portable IRI positions.
The cached clone can then keep extension fields while still
formatting the portable IRI value before it is reused.

fedify-dev#850 (comment)

Assisted-by: Codex:gpt-5.5
Compact IRI aliases in inline JSON-LD contexts need the same raw cache
handling as full IRI aliases. Expanding local prefixes lets the cached
clone preserve caller terms and extension fields while still formatting
portable IRI values before reuse.

fedify-dev#850 (comment)

Assisted-by: Codex:gpt-5.5
JSON-LD extension terms typed as @id can carry portable IRI values even
when the term is not generated as a Fedify vocabulary property. Treating
those terms as portable IRI positions keeps the cached JSON-LD clone and
normalizes the value before it is reused.

fedify-dev#850 (comment)

Assisted-by: Codex:gpt-5.5
Remote JSON-LD contexts can mark compacted extension terms as IRI
values even when the cached JSON-LD only carries a context URL.  Load
those contexts while deciding which cached fields need portable IRI
formatting, so unknown extension fields stay cached without rewriting
plain text that merely mentions an ap:// string.

Also treat @type: @id term definitions as IRI-valued even when the term
has no explicit @id mapping, matching JSON-LD term definition semantics.

fedify-dev#850 (comment)
fedify-dev#850 (comment)

Assisted-by: Codex:gpt-5.5
Cached JSON-LD can hide portable IRIs behind a remote context on a
nested extension object.  Make the cache scan and normalization path
loader-aware at every object boundary, so nested aliases are discovered
without rewriting plain text fields.

fedify-dev#850 (comment)

Assisted-by: Codex:gpt-5.5
Repeated remote contexts should still contribute aliases to each object
that references them.  Cache the loaded context body by URL instead of
only remembering that the URL was seen, so sibling extension objects can
reuse the same @id aliases without another fetch.

This also keeps failed custom loaders from crashing the cache scan when
they return a nullish remote document.

fedify-dev#850 (comment)
fedify-dev#850 (comment)

Assisted-by: Codex:gpt-5.5
Portable IRI cache normalization should not reimplement JSON-LD
context handling over compact input.  Normalize the expanded values
produced by the JSON-LD processor, then compact them with the input
context when one was supplied, so extension data is kept without a
parallel context resolver.

fedify-dev#850

Assisted-by: Codex:gpt-5.5
Portable IRI cache normalization already visits every expanded JSON-LD
value.  Return whether that pass changed anything so callers can decide
whether to compact the normalized values without first scanning the same
object graph with a separate predicate.

fedify-dev#850

Assisted-by: Codex:gpt-5.5
Portable ActivityPub IRIs require a DID authority with a method and
method-specific identifier.  The previous scheme-only check accepted
partial authorities that could not be real DIDs.

fedify-dev#850 (comment)

Assisted-by: Codex:gpt-5.5
Normalize portable IRIs with lazy cloning so unchanged JSON-LD subtrees are
not copied or mutated.  Cache normalization now runs on the expanded input
shape before parser-side mutations, which preserves contextless expanded
arrays and their sibling graph nodes.

fedify-dev#850 (comment)
fedify-dev#850 (comment)
fedify-dev#850 (comment)
fedify-dev#850 (comment)

Assisted-by: Codex:gpt-5.5
Avoid overlapping DID method-specific-id matches by keeping colons as
segment separators.  Normalize portable string bases before resolving
relative IRIs so decoded portable bases behave like parsed portable URLs.

fedify-dev#850 (comment)
fedify-dev#850 (comment)

Assisted-by: Codex:gpt-5.5
When portable IRI normalization requires expand and compact, carry back
original top-level terms that JSON-LD expansion intentionally ignores.
This keeps cache-only extension data round-tripping while still allowing
context-aware portable IRI normalization.

fedify-dev#850 (comment)

Assisted-by: Codex:gpt-5.5
When compacted cache data already represents an original JSON-LD term
through a canonical alias, do not copy the original alias back as an
unmapped extension field.  This keeps portable IRI normalization from
leaving duplicate alias keys in the cached document.

fedify-dev#850 (comment)

Assisted-by: Codex:gpt-5.5
Validate portable IRI authorities again after decoding encoded colons
and percent signs.  This keeps encoded DID authorities from accepting
invalid percent escapes that the decoded spelling would reject.

fedify-dev#850 (comment)

Assisted-by: Codex:gpt-5.5
Batch unmapped JSON-LD term checks into a single expansion so portable IRI
cache merging does not expand each original key separately.  Also await the
merge before assigning the cached JSON-LD value so merge failures stay inside
the cache fallback path.

fedify-dev#850 (comment)
fedify-dev#850 (comment)

Assisted-by: Codex:gpt-5.5
Reject DID authorities whose literal DID path would expose malformed
percent escapes after decoding an encoded percent sign.  Also avoid
mutating compacted JSON-LD objects while preserving unmapped terms, and
clone normalized expanded cache data before subtype decoding mutates the
working values object.

fedify-dev#850 (comment)
fedify-dev#850 (comment)
fedify-dev#850 (comment)

Assisted-by: Codex:gpt-5.5
Normalize at:// string bases before resolving relative IRIs, so raw
DID colons do not make standard URL construction reject a valid base.
Also keep single-element compact JSON-LD array cache entries compact by
reading the element-level context and wrapping the compacted cache back in
an array.

fedify-dev#850 (comment)
fedify-dev#850 (comment)

Assisted-by: Codex:gpt-5.5
Return the original JSON-LD subtree reference from generated portable IRI normalization when no values change, so the decoder can detect cache rewrites by reference instead of allocating wrapper objects at every recursive step.

Also leave encoded at:// bases on the standard URL path during relative IRI resolution, avoiding double-encoding of already URL-safe DID authorities.

fedify-dev#850 (comment)
fedify-dev#850 (comment)
fedify-dev#850 (comment)
fedify-dev#850 (comment)

Assisted-by: Codex:gpt-5.5
Avoid wrapping normalized expanded JSON-LD arrays again when the original input was already a single expanded node. The cache now only re-wraps compact array input after context-based compaction, keeping expanded cache output stable.

Also keep generated portable IRI key discovery robust for redundant property metadata and restore alphabetical runtime import order in the generated classes.

fedify-dev#850 (comment)
fedify-dev#850 (comment)
fedify-dev#850 (comment)

Assisted-by: Codex:gpt-5.5
Keep generated portable IRI cache normalization from collapsing compact JSON-LD single-item arrays after context-based compaction. The cache now reapplies the original compact array shape to the compacted result, so toJsonLd() preserves caller-provided array structure while still rewriting portable IRI strings.

fedify-dev#850 (comment)

Assisted-by: Codex:gpt-5.5
Handle portable IRI cache compaction for multi-node compact JSON-LD arrays by reusing contexts found inside array items and reshaping @graph output back to the caller-provided array form.

Also bound the recursive shape pass and skip @context traversal while keeping the lazy clone behavior for unchanged subtrees.

fedify-dev#850 (comment)
fedify-dev#850 (comment)

Assisted-by: Codex:gpt-5.5
Keep portable IRI cache compaction best effort by leaving malformed portable-looking extension IRIs unchanged instead of letting cache normalization throw.

Compact JSON-LD array cache entries item by item so later nodes can use their own extension contexts and preserve caller-provided aliases.

fedify-dev#850 (comment)
fedify-dev#850 (comment)

Assisted-by: Codex:gpt-5.5
Portable ActivityPub IRIs use custom URL schemes, so URL.origin is
"null" even when the DID authorities differ.  Compare custom-scheme
IRIs by protocol and authority before trusting embedded objects, and
parse fetched document URLs through parseIri() so portable bases are
normalized consistently.

Also accept DID method names that start with digits, matching the DID
Core method-name grammar.

fedify-dev#850 (comment)
fedify-dev#850 (comment)

Assisted-by: Codex:gpt-5.5
Note that the readable ap://did:... authority form is not RFC 3986
compliant, and that Fedify currently accepts it by normalizing the DID
authority into a percent-encoded URL authority internally.

Assisted-by: Codex:gpt-5.5
@dahlia dahlia force-pushed the feat/fep-ef61/ap-iris branch from 65a50ed to 6809204 Compare July 1, 2026 02:18
@dahlia

dahlia commented Jul 1, 2026

Copy link
Copy Markdown
Member Author

@sij411 Just rebased!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

activitypub/compliance Specification compliance component/vocab Activity Vocabulary related component/vocab-tools Vocabulary code generation (@fedify/vocab-tools)

Development

Successfully merging this pull request may close these issues.

Support ap: and ap+ef61: URI schemes in vocabulary codecs

2 participants