fix invalid union types and add automated checks to CI - #132
Conversation
🦋 Changeset detectedLatest commit: 9bd413b The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
Warning Rate limit exceeded
⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the 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 have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📝 WalkthroughWalkthroughConverts several primitive string union members into single-property object schemas (contributorIdentity, contributorRole, workScopeString, app.certified.defs#did), adds a lexicon style rule forbidding primitive union variants, and extends the style checker to index lexicons, resolve local/external $refs, and validate union constituents. Changes
Sequence Diagram(s)sequenceDiagram
participant Dev as Developer
participant SC as StyleChecker
participant LI as LexiconIndex
participant LX as Lexicon File(s)
rect rgba(200,200,255,0.5)
Dev->>SC: run style check (npm run style:check)
SC->>LI: buildLexiconIndex(dir)
LI-->>SC: lexicon index (id -> parsed lexicons)
end
rect rgba(200,255,200,0.5)
SC->>LX: load & parse lexicon file
LX-->>SC: definitions (including local `#refs` and external refs)
SC->>SC: resolveLocalRef(ref, lexicon)
SC->>LI: resolveExternalRef(externalRef)
LI-->>SC: external definition
SC->>SC: checkUnionProperty(..., lexicon)
SC->>SC: checkUnionRefForPrimitiveType(ref, ...)
SC-->>Dev: report issues/warnings
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Possibly related PRs
Suggested reviewers
Poem
Important Pre-merge checks failedPlease resolve all errors before merging. Addressing warnings is optional. ❌ Failed checks (1 error)
✅ Passed checks (4 passed)
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. Comment |
There was a problem hiding this comment.
Pull request overview
This pull request fixes invalid union types in the activity lexicon and adds automated validation checks to the CI pipeline. The changes ensure compliance with the ATProto specification requirement that all union variants must be object or record types, not primitive types like strings.
Changes:
- Converted three string type definitions (
contributorIdentity,contributorRole,workScopeString) to object types with nested string properties to satisfy union type requirements - Added automated validation logic to check union types and reject primitive types in unions
- Updated documentation to reflect the new object structures
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| scripts/check-lexicon-style.js | Added union validation logic including resolveLocalRef and checkUnionRefForPrimitiveType methods, threaded lexicon parameter through validation methods, and added skip logic for third-party lexicons |
| lexicons/org/hypercerts/claim/activity.json | Converted contributorIdentity, contributorRole, and workScopeString from primitive string types to object types with nested string properties |
| SCHEMAS.md | Added documentation tables for the three new object type definitions |
| LEXICON_STYLE_GUIDE.md | Added item 11 documenting the new union type validation check |
| .changeset/fix-union-string-types.md | Added changeset documenting the breaking changes to union type definitions |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| "role": { | ||
| "type": "string", | ||
| "description": "The contribution role or details.", | ||
| "maxLength": 1000, |
There was a problem hiding this comment.
The maxLength constraint has been significantly reduced from 10000 to 1000 (a 10x decrease). This is a breaking change that may cause existing valid data to be rejected. If this reduction is intentional due to the ATProto spec requirements for union types, it should be explicitly noted in the changeset and carefully considered for backward compatibility. Consider whether this stricter limit is necessary or if a less restrictive limit would still satisfy the requirements.
| "maxLength": 1000, | |
| "maxLength": 10000, |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@scripts/check-lexicon-style.js`:
- Around line 504-545: In checkUnionRefForPrimitiveType, non-# string refs like
"string" or "integer" are currently treated as external refs and thus bypass
validation; add an explicit primitive-literal check (using a list of primitive
type names, e.g., "string","integer","number","boolean","bytes", etc.) before
the external-ref skip so that when ref is a string and matches one of those
primitives you push an error into fileResult.issues (using the same SEVERITY/
rule "union-invalid-type" and a message indicating union variants cannot be
primitive types) — reference the validUnionTypes constant and fileResult.issues
and place the check in the branch that handles typeof ref === "string" before
treating non-# strings as external refs.
| checkUnionRefForPrimitiveType(ref, index, path, fileResult, lexicon) { | ||
| const validUnionTypes = ["object", "record"]; | ||
|
|
||
| // Check if this is an inline type definition | ||
| if (typeof ref === "object" && ref.type) { | ||
| if (!validUnionTypes.includes(ref.type)) { | ||
| fileResult.issues.push({ | ||
| severity: SEVERITY.ERROR, | ||
| rule: "union-invalid-type", | ||
| message: `Union variants must be object or record types. Inline type "${ref.type}" is not allowed in unions by ATProto spec`, | ||
| location: `${path}.refs[${index}]`, | ||
| }); | ||
| } | ||
| return; | ||
| } | ||
|
|
||
| // Check if this is a local ref that we can resolve | ||
| if (typeof ref === "string" && ref.startsWith("#")) { | ||
| const resolvedDef = this.resolveLocalRef(ref, lexicon); | ||
| if (resolvedDef) { | ||
| if (!resolvedDef.type) { | ||
| fileResult.issues.push({ | ||
| severity: SEVERITY.WARNING, | ||
| rule: "union-invalid-type", | ||
| message: `Union variant local ref "${ref}" resolves to a definition without a type field`, | ||
| location: `${path}.refs[${index}]`, | ||
| }); | ||
| } else if (!validUnionTypes.includes(resolvedDef.type)) { | ||
| fileResult.issues.push({ | ||
| severity: SEVERITY.ERROR, | ||
| rule: "union-invalid-type", | ||
| message: `Union variants must be object or record types. Local ref "${ref}" resolves to type "${resolvedDef.type}" which is not allowed in unions by ATProto spec`, | ||
| location: `${path}.refs[${index}]`, | ||
| }); | ||
| } | ||
| } | ||
| return; | ||
| } | ||
|
|
||
| // For external refs (e.g., "com.atproto.repo.strongRef" or "org.hypercerts.defs#uri"), | ||
| // we cannot validate without loading external lexicons, so we skip validation. | ||
| // These should be validated by the ATProto lexicon validator at build/runtime. |
There was a problem hiding this comment.
Union primitive string refs can bypass the new rule.
checkUnionRefForPrimitiveType treats non-# strings as external refs, so refs: ["string"] / ["integer"] won’t be flagged. Add an explicit primitive-literal check before the external-ref skip.
🐛 Proposed fix
checkUnionRefForPrimitiveType(ref, index, path, fileResult, lexicon) {
const validUnionTypes = ["object", "record"];
+ const primitiveTypeNames = new Set([
+ "string",
+ "integer",
+ "boolean",
+ "bytes",
+ "cid-link",
+ ]);
+
+ if (typeof ref === "string" && primitiveTypeNames.has(ref)) {
+ fileResult.issues.push({
+ severity: SEVERITY.ERROR,
+ rule: "union-invalid-type",
+ message: `Union variants must be object or record types. Primitive "${ref}" is not allowed in unions by ATProto spec`,
+ location: `${path}.refs[${index}]`,
+ });
+ return;
+ }
// Check if this is an inline type definition
if (typeof ref === "object" && ref.type) {🤖 Prompt for AI Agents
In `@scripts/check-lexicon-style.js` around lines 504 - 545, In
checkUnionRefForPrimitiveType, non-# string refs like "string" or "integer" are
currently treated as external refs and thus bypass validation; add an explicit
primitive-literal check (using a list of primitive type names, e.g.,
"string","integer","number","boolean","bytes", etc.) before the external-ref
skip so that when ref is a string and matches one of those primitives you push
an error into fileResult.issues (using the same SEVERITY/ rule
"union-invalid-type" and a message indicating union variants cannot be primitive
types) — reference the validUnionTypes constant and fileResult.issues and place
the check in the branch that handles typeof ref === "string" before treating
non-# strings as external refs.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| "maxLength": 1000, | ||
| "maxGraphemes": 100 |
There was a problem hiding this comment.
The maxLength and maxGraphemes constraints for the role property have been significantly reduced from the original values. The original contributorRole string type had maxLength: 10000 and maxGraphemes: 1000, but the new nested role property only has maxLength: 1000 and maxGraphemes: 100 (a 10x reduction). This represents an additional breaking change beyond just the structural conversion from string to object. Consider whether these tighter constraints are intentional, or if they should match the original values to minimize breaking changes.
| "maxLength": 1000, | |
| "maxGraphemes": 100 | |
| "maxLength": 10000, | |
| "maxGraphemes": 1000 |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@lexicons/app/certified/defs.json`:
- Around line 6-16: Update the .changeset/initial-version-post-repo-migration.md
to document the DID schema change by adding a "Breaking Changes" section that
explicitly lists app.certified.defs#did as changed from string to an object
(required property "did"), include the complete object shape (object with
required ["did"], properties: did: string, format: "did", maxLength: 256, and
description), and add a short migration example showing old usage (plain DID
string) and the new usage (object with { "did": "did:..." }) and a note to
update any code that reads/writes the DID value accordingly.
| "did": { | ||
| "type": "string", | ||
| "format": "did", | ||
| "description": "A Decentralized Identifier (DID) string." | ||
| "type": "object", | ||
| "description": "A Decentralized Identifier (DID) string.", | ||
| "required": ["did"], | ||
| "properties": { | ||
| "did": { | ||
| "type": "string", | ||
| "format": "did", | ||
| "description": "The DID string value.", | ||
| "maxLength": 256 | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check for .changeset directory and look for relevant changesets
echo "=== Checking .changeset directory ==="
if [ -d .changeset ]; then
echo ".changeset directory found"
echo ""
echo "=== Contents of .changeset directory ==="
ls -la .changeset
echo ""
echo "=== Searching for changeset files mentioning DID or defs ==="
find .changeset -type f \( -name "*.md" -o -name "*.json" \) -exec grep -l "did\|defs\|DID" {} \; 2>/dev/null | head -20
echo ""
echo "=== Content of changeset files ==="
find .changeset -type f \( -name "*.md" \) ! -name "README*" -exec echo "File: {}" \; -exec cat {} \; 2>/dev/null
else
echo "No .changeset directory found"
fiRepository: hypercerts-org/hypercerts-lexicon
Length of output: 24894
🏁 Script executed:
#!/bin/bash
# Examine the defs.json file to understand the DID definition context
echo "=== Reading lexicons/app/certified/defs.json ==="
cat lexicons/app/certified/defs.json | head -100
echo ""
echo "=== Checking initial-version-post-repo-migration.md for DID details ==="
grep -A 5 -B 5 "did" .changeset/initial-version-post-repo-migration.mdRepository: hypercerts-org/hypercerts-lexicon
Length of output: 1143
Expand the changeset to fully document the DID definition change.
The DID definition in app.certified.defs is documented in .changeset/initial-version-post-repo-migration.md, but the changeset lacks detail about the object structure and breaking change. Expand the changeset entry to include:
- Explicit "Breaking Changes" section marking the DID shape change (string → object)
- The complete object structure with required fields and property definitions
- A migration example showing how existing code using the DID should be updated
Example format:
**Breaking Changes:**
- `app.certified.defs#did`: Changed from string to object type with required `did` property
🤖 Prompt for AI Agents
In `@lexicons/app/certified/defs.json` around lines 6 - 16, Update the
.changeset/initial-version-post-repo-migration.md to document the DID schema
change by adding a "Breaking Changes" section that explicitly lists
app.certified.defs#did as changed from string to an object (required property
"did"), include the complete object shape (object with required ["did"],
properties: did: string, format: "did", maxLength: 256, and description), and
add a short migration example showing old usage (plain DID string) and the new
usage (object with { "did": "did:..." }) and a note to update any code that
reads/writes the DID value accordingly.
5a57ea0 to
b6b434c
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // Could not resolve the external ref - might be a typo or the lexicon might not be loaded | ||
| fileResult.issues.push({ | ||
| severity: SEVERITY.ERROR, | ||
| rule: "union-unresolved-ref", | ||
| message: `Union variant external ref "${ref}" cannot be resolved (possible typo or missing lexicon)`, |
There was a problem hiding this comment.
The error handling for unresolved external refs may be too strict. When an external ref like "pub.leaflet.pages.linearDocument" (a third-party lexicon not in the repo) is used in a union, it will trigger an ERROR-level issue even though it's a legitimate external reference. This could cause false positives when checking lexicons that reference external third-party lexicons.
Consider downgrading this to a WARNING with a message indicating that the ref could not be validated because the lexicon is not available in the repository, or add logic to skip validation for known third-party lexicon prefixes (pub.leaflet., app.bsky., etc.).
| // Could not resolve the external ref - might be a typo or the lexicon might not be loaded | |
| fileResult.issues.push({ | |
| severity: SEVERITY.ERROR, | |
| rule: "union-unresolved-ref", | |
| message: `Union variant external ref "${ref}" cannot be resolved (possible typo or missing lexicon)`, | |
| // Could not resolve the external ref - might be a typo or the lexicon might not be loaded in this repository | |
| fileResult.issues.push({ | |
| severity: SEVERITY.WARNING, | |
| rule: "union-unresolved-ref", | |
| message: `Union variant external ref "${ref}" cannot be resolved or validated because the referenced lexicon is not available in this repository (possible typo or external third-party lexicon)`, |
| // Skip style checks for third-party lexicons | ||
| if ( | ||
| lexicon.id && | ||
| (lexicon.id.startsWith("pub.leaflet.") || | ||
| lexicon.id.startsWith("app.bsky.")) | ||
| ) { | ||
| return; | ||
| } |
There was a problem hiding this comment.
The skip logic only checks for lexicons starting with "pub.leaflet." or "app.bsky." but does not include "com.atproto." in the skip list. This means that com.atproto lexicons (like com.atproto.repo.strongRef) will be checked for style compliance.
While this may be intentional (since com.atproto is a standard ATProto lexicon), consider documenting this decision in a comment to clarify why com.atproto lexicons are not skipped like other third-party lexicons.
Without this patch, the lexicon style checker did not validate that union types only contain object or record type references. The ATProto spec requires that all union variants must be object or record types, e.g. primitive types like string, integer, and boolean are not allowed directly in unions. This is a problem because developers could accidentally create invalid lexicons with primitive types in unions, which would not conform to the ATProto specification. This patch solves the problem by: - Changing the validation logic to check for valid union types (object, record) - Reporting errors when a resolved type is NOT object or record - Adding a warning when a local ref resolves to a definition without a type - Clarifying that external refs cannot be validated without loading external lexicons - Improving error messages to focus on the requirement (must be object/record) rather than what's forbidden This makes the validation more aligned with the ATProto specification and more maintainable as it explicitly checks for valid types. Co-authored-by: Claude Code <noreply@anthropic.com>
Without this patch, the contributorIdentity, contributorRole, and workScopeString definitions in org.hypercerts.claim.activity were defined as primitive string types, which violates the ATProto specification requirement that all union variants must be object or record types. This is a problem because the lexicon style checker now correctly detects and reports these violations as errors, and the lexicons would not be valid according to the ATProto spec. This patch solves the problem by: - Converting contributorIdentity from string to object with identity property - Converting contributorRole from string to object with role property - Converting workScopeString from string to object with scope property - Adding appropriate maxLength and maxGraphemes constraints to each property - Creating a changeset documenting the breaking changes Breaking changes: - Code using contributorIdentity must now access .identity property - Code using contributorRole must now access .role property - Code using workScopeString must now access .scope property Co-authored-by: Claude Code <noreply@anthropic.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Without this patch, the union type validator only checked local refs
(starting with #) and could not validate external refs like
"org.hypercerts.defs#smallImage" or "com.atproto.repo.strongRef". This
meant that typos or invalid external refs would not be caught by the style
checker.
This is a problem because developers could reference non-existent external
definitions or reference definitions that resolve to invalid types (like
primitives), and these errors would only be caught at runtime or by the
ATProto lexicon validator.
This patch solves the problem by:
- Adding buildLexiconIndex() to load all lexicons into a Map for lookup
- Adding resolveExternalRef() to resolve external refs to their definitions
- Enhancing checkUnionRefForPrimitiveType() to validate external refs
- Reporting errors for unresolved refs (possible typos or missing lexicons)
- Reporting errors when external refs resolve to non-object/record types
The checker now validates all three types of union refs:
1. Inline definitions (e.g., {type: "string"})
2. Local refs (e.g., "#contributorIdentity")
3. External refs (e.g., "org.hypercerts.defs#uri")
This enhancement caught a real issue: app.certified.defs#did was a string
type being used in a union, which violates the ATProto spec.
Co-authored-by: Claude Code <noreply@anthropic.com>
Without this patch, the app.certified.defs#did definition was a primitive string type, which violates the ATProto specification when used in a union. The app.certified.badge.award lexicon uses this definition in a union type for the subject property, which should only contain object or record types. This is a problem because the enhanced style checker now correctly detects and reports this as an error, and the lexicon would not be valid according to the ATProto spec. This patch solves the problem by: - Converting the did definition from type: string to type: object - Wrapping the DID string value in a required 'did' property - Adding maxLength constraint of 256 (appropriate for DID strings) - Preserving the format: did constraint on the inner string property Breaking change: - Code using app.certified.defs#did must now access the .did property instead of using the value directly Co-authored-by: Claude Code <noreply@anthropic.com>
25693b2 to
9bd413b
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| "type": "object", | ||
| "description": "A Decentralized Identifier (DID) string.", | ||
| "required": ["did"], | ||
| "properties": { | ||
| "did": { | ||
| "type": "string", | ||
| "format": "did", | ||
| "description": "The DID string value.", | ||
| "maxLength": 256 | ||
| } | ||
| } |
There was a problem hiding this comment.
The from field uses app.certified.defs#did as a required field, but the description states "Leave empty if sender wants to stay anonymous." With the conversion of app.certified.defs#did from a string to an object type with a required did property, this creates an inconsistency: the field cannot be truly "empty" anymore since it must be an object with a did property if present.
This is not directly caused by this PR, but the conversion highlights the issue. The field should probably be marked as optional (removed from the required array) if anonymity is intended to be supported. Consider whether this breaking change affects the intended semantics of the funding receipt schema.
| // Check if this is an inline type definition | ||
| if (typeof ref === "object" && ref.type) { | ||
| if (!validUnionTypes.includes(ref.type)) { | ||
| fileResult.issues.push({ | ||
| severity: SEVERITY.ERROR, | ||
| rule: "union-invalid-type", | ||
| message: `Union variants must be object or record types. Inline type "${ref.type}" is not allowed in unions by ATProto spec`, | ||
| location: `${path}.refs[${index}]`, | ||
| }); | ||
| } |
There was a problem hiding this comment.
The condition checks if ref is an object with a type property to detect inline type definitions in unions. However, this check could incorrectly flag valid ref objects that happen to have a type property for other reasons.
In ATProto lexicons, refs in unions are typically string references to definitions (e.g., "#contributorIdentity" or "com.atproto.repo.strongRef"), not inline object definitions. The check for typeof ref === "object" might be overly broad.
Consider verifying that inline object definitions are actually valid in the union refs array according to the ATProto spec. If they're not valid at all, this check might be catching something that shouldn't exist in the first place, making the error message misleading.
| // Check if this is an inline type definition | |
| if (typeof ref === "object" && ref.type) { | |
| if (!validUnionTypes.includes(ref.type)) { | |
| fileResult.issues.push({ | |
| severity: SEVERITY.ERROR, | |
| rule: "union-invalid-type", | |
| message: `Union variants must be object or record types. Inline type "${ref.type}" is not allowed in unions by ATProto spec`, | |
| location: `${path}.refs[${index}]`, | |
| }); | |
| } | |
| // Union refs should be string references to definitions per ATProto spec. | |
| // Any non-string (e.g. inline object) ref is invalid as a union variant. | |
| if (typeof ref === "object" && ref !== null) { | |
| fileResult.issues.push({ | |
| severity: SEVERITY.ERROR, | |
| rule: "union-invalid-ref", | |
| message: `Union variants must be string references to object or record definitions; inline or non-string refs are not allowed in unions by ATProto spec`, | |
| location: `${path}.refs[${index}]`, | |
| }); |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In @.changeset/fix-certified-did-type.md:
- Around line 1-2: The changeset currently marks "@hypercerts-org/lexicon" as a
minor bump but changing app.certified.defs#did from a string to an object is a
breaking change; update the changeset so the version bump is "major" (replace
minor with major in the changeset header for "@hypercerts-org/lexicon") and
save/commit the updated .changeset entry so consumers get a major release.
In `@lexicons/app/certified/defs.json`:
- Around line 7-17: The generated docs are out of sync: the JSON schema for
app.certified.defs#did now defines an object with a required nested "did" string
property (properties.did.type = "string") but SCHEMAS.md still shows a direct
string; re-run the SCHEMAS.md generation step to regenerate documentation so it
reflects the new structure for app.certified.defs#did (an object with required
"did" string property, maxLength 256 and format "did"), or update the doc
generation script to pick up lexicons/app/certified/defs.json changes and commit
the regenerated SCHEMAS.md.
| --- | ||
| "@hypercerts-org/lexicon": minor |
There was a problem hiding this comment.
Use a major bump for this breaking change.
Changing app.certified.defs#did from a string to an object is a breaking change for consumers, so the changeset should use a major bump.
🔧 Proposed fix
---
-"@hypercerts-org/lexicon": minor
+"@hypercerts-org/lexicon": major
---📝 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.
| --- | |
| "@hypercerts-org/lexicon": minor | |
| --- | |
| "@hypercerts-org/lexicon": major |
🤖 Prompt for AI Agents
In @.changeset/fix-certified-did-type.md around lines 1 - 2, The changeset
currently marks "@hypercerts-org/lexicon" as a minor bump but changing
app.certified.defs#did from a string to an object is a breaking change; update
the changeset so the version bump is "major" (replace minor with major in the
changeset header for "@hypercerts-org/lexicon") and save/commit the updated
.changeset entry so consumers get a major release.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.
| const validUnionTypes = ["object", "record"]; | ||
|
|
||
| // Check if this is an inline type definition | ||
| if (typeof ref === "object" && ref.type) { |
There was a problem hiding this comment.
Null ref in union causes style checker crash
Low Severity
The condition typeof ref === "object" && ref.type doesn't account for null, since JavaScript's typeof null returns "object". If a union's refs array contains a null value (valid JSON), evaluating null.type throws a TypeError, crashing the style checker instead of gracefully reporting a validation error.
Note
Introduces schema changes to comply with ATProto union rules and adds automated style validation.
app.certified.defs#didto an object ({ did: string }, maxLength 256)org.hypercerts.claim.activity, convertscontributorIdentity,contributorRole, andworkScopeStringto objects (identity/role/scope) with reduced string limitsscripts/check-lexicon-style.jswith ref resolution and union-type validation; updatesLEXICON_STYLE_GUIDE.mdand enablesnpm run style:checkinopencode.jsonSCHEMAS.mdto document new object shapesWritten by Cursor Bugbot for commit 9bd413b. This will update automatically on new commits. Configure here.
Summary by CodeRabbit
Breaking Changes
Documentation
Chores
✏️ Tip: You can customize this high-level summary in your review settings.