Skip to content

fix: add foaf:isPrimaryTopicOf to WebID profile - #300

Merged
melvincarvalho merged 2 commits into
gh-pagesfrom
issue-299-profile-document-predicates
Apr 22, 2026
Merged

fix: add foaf:isPrimaryTopicOf to WebID profile#300
melvincarvalho merged 2 commits into
gh-pagesfrom
issue-299-profile-document-predicates

Conversation

@melvincarvalho

Copy link
Copy Markdown
Contributor

Summary

  • WebID profiles now include foaf:isPrimaryTopicOf pointing from #me to the document, per the Solid WebID Profile spec
  • Uses empty string "" as a relative URI reference to the document itself (standard JSON-LD pattern)
  • Keeps existing schema:mainEntityOfPage for schema.org-aware consumers

Why

Apps dereferencing the document URL need a way to find the subject WebID inside it. foaf:isPrimaryTopicOf (forward direction from agent to doc) is what the Solid WebID Profile spec recommends.

Closes #299

Test plan

  • All 414 tests pass (1 new test)
  • Generated profile matches spec

Per the Solid WebID Profile spec, profiles link the agent to the
document via foaf:isPrimaryTopicOf. Empty string is a relative URI
reference to the document itself. Keeps schema:mainEntityOfPage for
schema.org compatibility.

Closes #299

Copilot AI 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.

Pull request overview

Updates the generated WebID JSON-LD profile to include a foaf:isPrimaryTopicOf link from the #me subject to the profile document, aligning output more closely with Solid WebID Profile expectations.

Changes:

  • Add foaf:isPrimaryTopicOf (as isPrimaryTopicOf) to generated profile JSON-LD and set it to "" (document-relative IRI).
  • Change schema:mainEntityOfPage (as mainEntityOfPage) to also use "" instead of an absolute document URL.
  • Extend WebID profile tests to assert presence of the new field and adjust existing mainEntityOfPage assertion to allow empty string values.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
src/webid/profile.js Adds isPrimaryTopicOf context + output and changes mainEntityOfPage to be document-relative.
test/webid.test.js Updates assertions for mainEntityOfPage and adds a new test for isPrimaryTopicOf.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/webid/profile.js
Comment on lines 46 to 49
'foaf:name': name,
'mainEntityOfPage': profileDoc,
'isPrimaryTopicOf': '',
'mainEntityOfPage': '',
'inbox': `${pod}inbox/`,

Copilot AI Apr 22, 2026

Copy link

Choose a reason for hiding this comment

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

mainEntityOfPage was changed from an absolute document IRI to an empty string. While "" can resolve to the document IRI in JSON-LD when a base IRI is provided, many schema.org-oriented consumers treat this value as a plain string and may not resolve relative IRIs, which would be a behavior change/regression versus the previous absolute URL. Consider restoring the absolute document URL for mainEntityOfPage (or explicitly setting @base in the JSON-LD context so relative IRIs are unambiguous) while keeping foaf:isPrimaryTopicOf as needed.

Copilot uses AI. Check for mistakes.
Comment thread src/webid/profile.js
Comment on lines 44 to +48
'@id': webId,
'@type': ['foaf:Person', 'schema:Person'],
'foaf:name': name,
'mainEntityOfPage': profileDoc,
'isPrimaryTopicOf': '',
'mainEntityOfPage': '',

Copilot AI Apr 22, 2026

Copy link

Choose a reason for hiding this comment

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

This change adds foaf:isPrimaryTopicOf on the #me node, but it still does not describe the profile document itself (e.g., <> a foaf:PersonalProfileDocument; foaf:primaryTopic <#me>; foaf:maker <#me>). If this PR is intended to close #299 and support clients that discover a user by dereferencing the document URL and following foaf:primaryTopic, the profile generator likely needs to emit a document node (typically via @graph) in addition to foaf:isPrimaryTopicOf.

Copilot uses AI. Check for mistakes.
Comment thread test/webid.test.js Outdated
Comment on lines +86 to +99
@@ -87,7 +87,16 @@ describe('WebID Profile', () => {
const res = await request(profilePath);
const jsonLd = await res.json();

assert.ok(jsonLd['mainEntityOfPage'], 'Should have mainEntityOfPage');
// Empty string is a relative URI reference to the document itself
assert.ok('mainEntityOfPage' in jsonLd, 'Should have mainEntityOfPage');
});

it('should have isPrimaryTopicOf pointing to the document', async () => {
const res = await request(profilePath);
const jsonLd = await res.json();

// Empty string is a relative URI reference to the document itself
assert.ok('isPrimaryTopicOf' in jsonLd, 'Should have foaf:isPrimaryTopicOf');

Copilot AI Apr 22, 2026

Copy link

Choose a reason for hiding this comment

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

The new assertions only check that mainEntityOfPage / isPrimaryTopicOf keys exist, but not that they actually point to the profile document. Since the implementation relies on "" being interpreted as a relative IRI to the document, add a stronger assertion (e.g., that the value is "", or that it expands/resolves to the request URL) to prevent silent regressions where these fields are present but incorrect.

Copilot uses AI. Check for mistakes.

Copilot AI 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.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread test/webid.test.js
Comment on lines +86 to 100
it('should have mainEntityOfPage pointing to the document', async () => {
const res = await request(profilePath);
const jsonLd = await res.json();

assert.ok(jsonLd['mainEntityOfPage'], 'Should have mainEntityOfPage');
// Empty string is a relative URI reference to the document itself (JSON-LD)
assert.strictEqual(jsonLd['mainEntityOfPage'], '', 'mainEntityOfPage should be "" (self)');
});

it('should have isPrimaryTopicOf pointing to the document', async () => {
const res = await request(profilePath);
const jsonLd = await res.json();

// Empty string is a relative URI reference to the document itself (JSON-LD)
assert.strictEqual(jsonLd['isPrimaryTopicOf'], '', 'isPrimaryTopicOf should be "" (self)');
});

Copilot AI Apr 22, 2026

Copy link

Choose a reason for hiding this comment

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

These tests assert an exact empty-string value for mainEntityOfPage/isPrimaryTopicOf, which tightly couples the tests to a specific JSON-LD serialization choice. If the implementation is adjusted to emit an explicit document IRI (or a different relative form) for compatibility, these tests will fail even though the RDF meaning is unchanged; consider asserting that the fields are present and point to the profile document (e.g., accept "" or the expected absolute URL).

Copilot uses AI. Check for mistakes.
@melvincarvalho
melvincarvalho merged commit fe1478a into gh-pages Apr 22, 2026
4 checks passed
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.

WebID profile document missing foaf:PersonalProfileDocument, primaryTopic, maker

2 participants