Skip to content

feat: Add KindInfo to Extension Upsert - BED-8764#2986

Open
LawsonWillard wants to merge 25 commits into
mainfrom
BED-8764
Open

feat: Add KindInfo to Extension Upsert - BED-8764#2986
LawsonWillard wants to merge 25 commits into
mainfrom
BED-8764

Conversation

@LawsonWillard

@LawsonWillard LawsonWillard commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Description

  • Adds kindInfo to the Upsert Extension endpoint, allowing extension authors to add contextual information to specific kinds.
  • Adds unit and integration tests to cover the changeset.

Motivation and Context

Resolves: BED-8764

As an OpenGraph Extension Author, I want the /api/v2/extensions API to support KindInfo entries for node and relationship kinds so that I can keep those definitions in sync with my extension.

How Has This Been Tested?

  • Added new unit and integration tests to cover the feature
  • Tested locally to ensure kind info was added as expected

Types of changes

  • New feature (non-breaking change which adds functionality)

Checklist:

Summary by CodeRabbit

Summary

  • New Features
    • Added configurable “info” panels (title, position, markdown) for both node kinds and relationship kinds, keyed per entry.
    • Kind info is now fully reconciled during graph extension ingest (create/update/delete).
  • Bug Fixes
    • Stricter server-side validation for panel keys, counts, positions, and markdown shape, with consistent API error mapping.
    • Kind identifiers are reliably returned/persisted; empty markdown content now defaults to the expected structure.
  • Documentation
    • Updated OpenAPI schemas and endpoint examples to include the new info panels.
  • Tests
    • Expanded unit and integration coverage for parsing, validation, and reconciliation edge cases.

@LawsonWillard LawsonWillard self-assigned this Jul 13, 2026
@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

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

OpenGraph extensions now accept per-kind information panels with titled, positioned markdown. The API converts and validates these panels, database upserts reconcile panel records, and OpenAPI schemas and examples document the payload.

Changes

Kind info support

Layer / File(s) Summary
API payload conversion
cmd/api/src/api/v2/opengraphschema.go, cmd/api/src/api/v2/*test.go
Node and relationship payloads convert info panels into model inputs, normalize markdown, validate positions, and report malformed payload errors.
Model validation and contracts
cmd/api/src/model/graphschema.go, cmd/api/src/model/graphschema_test.go
Graph extension inputs carry kind information and validate entry counts, key formats, positions, and markdown content.
Database kind identifiers and CRUD projections
cmd/api/src/database/graphschema.go, cmd/api/src/database/*integration_test.go
Kind identifiers are returned consistently, empty kind-info content defaults to markdown structure, and CRUD behavior is tested.
Kind information persistence and reconciliation
cmd/api/src/database/upsert_schema_extension.go, cmd/api/src/database/upsert_schema_extension_integration_test.go, cmd/api/src/services/opengraphschema/extension.go
Extension upserts create, update, and delete kind-info records and translate related database errors into graph-extension validation errors.
OpenAPI schemas and extension examples
packages/go/openapi/src/schemas/*, packages/go/openapi/src/paths/opengraph.extensions.yaml, packages/go/openapi/doc/openapi.json, schemas/open_graph/dog-park-schema.json
OpenAPI definitions and graph schema examples document named information panels with markdown content for node and relationship kinds.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant OpenGraphClient
  participant OpenGraphSchemaIngest
  participant GraphExtensionInput
  participant UpsertOpenGraphExtension
  participant KindInfoRepository
  OpenGraphClient->>OpenGraphSchemaIngest: submit info panels
  OpenGraphSchemaIngest->>GraphExtensionInput: convert and validate KindInfoInputs
  GraphExtensionInput->>UpsertOpenGraphExtension: provide validated extension input
  UpsertOpenGraphExtension->>KindInfoRepository: reconcile create, update, and delete records
  KindInfoRepository-->>UpsertOpenGraphExtension: return persistence result
Loading

Possibly related PRs

Suggested labels: api, enhancement, documentation, go

Suggested reviewers: mvlipka, urangel

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 31.58% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately summarizes the main change: adding KindInfo support to extension upsert.
Description check ✅ Passed The description matches the template well with Description, Motivation, Testing, Types of changes, and Checklist sections.
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch BED-8764

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.

@coderabbitai coderabbitai Bot added api A pull request containing changes affecting the API code. dbmigration documentation Improvements or additions to documentation enhancement New feature or request go Pull requests that update go code labels Jul 13, 2026

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🧹 Nitpick comments (2)
cmd/api/src/database/upsert_schema_extension_integration_test.go (1)

400-428: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider adding a position-swap update case. The update fixtures keep positions distinct (overview:1, examples:3), so they don't exercise reordering existing infos. A case that swaps two positions within one upsert would cover the reconcile/unique-constraint concern flagged in cmd/api/src/database/upsert_schema_extension.go.

🤖 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 `@cmd/api/src/database/upsert_schema_extension_integration_test.go` around
lines 400 - 428, The update fixtures in the test setup should exercise
reordering existing infos by swapping the positions of at least two retained
entries within the same upsert. Adjust the relevant KindInfoInputs in the update
case around the existing overview/examples reconciliation so their positions
exchange while preserving the expected add, update, and delete assertions.
cmd/api/src/services/opengraphschema/extension.go (1)

39-48: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider consolidating the two error-translation checks.

Both branches perform the same wrap (fmt.Errorf("%w: %w", model.ErrGraphExtensionValidation, err)); a single slice of translatable sentinel errors checked with errors.Is in a loop (or errors.Join-based matcher) would reduce duplication and make it easier to add future kind-info error translations.

♻️ Suggested refactor
-		if model.ErrIsGraphSchemaDuplicateError(err) {
-			return schemaExists, fmt.Errorf("%w: %w", model.ErrGraphExtensionValidation, err)
-		}
-		// Translate kind info database errors to validation errors
-		if errors.Is(err, model.ErrKindInfoKindNotFound) ||
-			errors.Is(err, model.ErrKindInfoDuplicatePosition) ||
-			errors.Is(err, model.ErrKindInfoDuplicateInfoKey) {
-			return schemaExists, fmt.Errorf("%w: %w", model.ErrGraphExtensionValidation, err)
-		}
+		if model.ErrIsGraphSchemaDuplicateError(err) || isKindInfoValidationError(err) {
+			return schemaExists, fmt.Errorf("%w: %w", model.ErrGraphExtensionValidation, err)
+		}
🤖 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 `@cmd/api/src/services/opengraphschema/extension.go` around lines 39 - 48,
Consolidate the duplicate error translation branches in the surrounding
error-handling function by defining one collection or matcher for the
graph-schema duplicate error and the listed kind-info errors, then perform a
single check before applying the existing validation-error wrap. Preserve the
current matching behavior and return values while making future translatable
errors easy to add.
🤖 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/go/openapi/src/schemas/model.graph-extension.kind-info-definition.yaml`:
- Around line 17-26: Align the additionalProperties schema with its description
by updating the required list for each panel object to include markdown
alongside title and position, ensuring every KindInfo panel requires markdown
content.

---

Nitpick comments:
In `@cmd/api/src/database/upsert_schema_extension_integration_test.go`:
- Around line 400-428: The update fixtures in the test setup should exercise
reordering existing infos by swapping the positions of at least two retained
entries within the same upsert. Adjust the relevant KindInfoInputs in the update
case around the existing overview/examples reconciliation so their positions
exchange while preserving the expected add, update, and delete assertions.

In `@cmd/api/src/services/opengraphschema/extension.go`:
- Around line 39-48: Consolidate the duplicate error translation branches in the
surrounding error-handling function by defining one collection or matcher for
the graph-schema duplicate error and the listed kind-info errors, then perform a
single check before applying the existing validation-error wrap. Preserve the
current matching behavior and return values while making future translatable
errors easy to add.
🪄 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 YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: f3795cd8-4331-45df-8046-0379e4d17ab6

📥 Commits

Reviewing files that changed from the base of the PR and between 2e7b71b and 0a6a7a9.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (17)
  • cmd/api/src/api/v2/opengraphschema.go
  • cmd/api/src/api/v2/opengraphschema_internal_test.go
  • cmd/api/src/api/v2/opengraphschema_test.go
  • cmd/api/src/database/customnode_integration_test.go
  • cmd/api/src/database/graphschema.go
  • cmd/api/src/database/graphschema_integration_test.go
  • cmd/api/src/database/upsert_schema_extension.go
  • cmd/api/src/database/upsert_schema_extension_integration_test.go
  • cmd/api/src/model/graphschema.go
  • cmd/api/src/model/graphschema_test.go
  • cmd/api/src/services/opengraphschema/extension.go
  • go.mod
  • packages/go/openapi/doc/openapi.json
  • packages/go/openapi/src/paths/opengraph.extensions.yaml
  • packages/go/openapi/src/schemas/model.graph-extension.kind-info-definition.yaml
  • packages/go/openapi/src/schemas/model.graph-extension.payload.yaml
  • schemas/open_graph/dog-park-schema.json

Comment on lines +17 to +26
description: |
A map of named info panels used in extension definitions.
Each property key is a stable panel identifier, and each property value
must be a valid KindInfo object with title, position, and content.
propertyNames:
pattern: '^[a-z0-9_-]{1,128}$'
description: "Keys may only include lowercase alphanumeric characters, hyphens, and underscores"
additionalProperties:
type: object
required: [title, position]

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.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Schema description and required list are inconsistent.

The description states each panel "must be a valid KindInfo object with title, position, and content," but required only includes [title, position]. The markdown object (which contains content) is not required. If every info panel is expected to have markdown content, add markdown to the required list. If markdown is intentionally optional, update the description to reflect that.

🔧 Proposed fix: add `markdown` to required list
 additionalProperties:
   type: object
-  required: [title, position]
+  required: [title, position, markdown]
   properties:
📝 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
description: |
A map of named info panels used in extension definitions.
Each property key is a stable panel identifier, and each property value
must be a valid KindInfo object with title, position, and content.
propertyNames:
pattern: '^[a-z0-9_-]{1,128}$'
description: "Keys may only include lowercase alphanumeric characters, hyphens, and underscores"
additionalProperties:
type: object
required: [title, position]
description: |
A map of named info panels used in extension definitions.
Each property key is a stable panel identifier, and each property value
must be a valid KindInfo object with title, position, and content.
propertyNames:
pattern: '^[a-z0-9_-]{1,128}$'
description: "Keys may only include lowercase alphanumeric characters, hyphens, and underscores"
additionalProperties:
type: object
required: [title, position, markdown]
🤖 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
`@packages/go/openapi/src/schemas/model.graph-extension.kind-info-definition.yaml`
around lines 17 - 26, Align the additionalProperties schema with its description
by updating the required list for each panel object to include markdown
alongside title and position, ensuring every KindInfo panel requires markdown
content.

@coderabbitai coderabbitai 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.

🧹 Nitpick comments (1)
cmd/api/src/model/graphschema.go (1)

143-158: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add duplicate InfoKey and Position validation in validateKindInfo

The function doesn't check for duplicate InfoKey or Position values within the same kind's Info list. The database catches these via uniqueness constraints (confirmed by integration tests error_-_update_to_duplicate_info_key and error_-_update_to_duplicate_position), but model-layer validation would provide clearer error messages and avoid unnecessary database round-trips.

This requires adding two new exported error variables (e.g., ErrDuplicateKindInfoKey, ErrDuplicateKindInfoPosition).

♻️ Proposed refactor: add duplicate detection
 func validateKindInfo(kindName string, info KindInfoInputs) error {
+	var (
+		seenKeys      = make(map[string]struct{})
+		seenPositions = make(map[int32]struct{})
+	)
+
 	if len(info) > 100 {
 		return fmt.Errorf("%w for kind %s: has %d entries", ErrTooManyKindInfoEntries, kindName, len(info))
 	}
 
 	for _, infoEntry := range info {
 		if !kindInfoKeyPattern.MatchString(infoEntry.InfoKey) {
 			return fmt.Errorf("%w: key '%s' in kind %s", ErrInvalidKindInfoKey, infoEntry.InfoKey, kindName)
 		} else if infoEntry.Position < 1 {
 			return fmt.Errorf("%w: position %d for info key '%s' in kind %s", ErrInvalidKindInfoPosition, infoEntry.Position, infoEntry.InfoKey, kindName)
 		} else if err := validateKindInfoContent(infoEntry.Content); err != nil {
 			return fmt.Errorf("info key '%s' in kind %s: %w", infoEntry.InfoKey, kindName, err)
+		} else if _, exists := seenKeys[infoEntry.InfoKey]; exists {
+			return fmt.Errorf("%w: duplicate key '%s' in kind %s", ErrDuplicateKindInfoKey, infoEntry.InfoKey, kindName)
+		} else if _, exists := seenPositions[infoEntry.Position]; exists {
+			return fmt.Errorf("%w: duplicate position %d in kind %s", ErrDuplicateKindInfoPosition, infoEntry.Position, kindName)
 		}
+
+		seenKeys[infoEntry.InfoKey] = struct{}{}
+		seenPositions[infoEntry.Position] = struct{}{}
 	}
 	return nil
 }
🤖 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 `@cmd/api/src/model/graphschema.go` around lines 143 - 158, Update
validateKindInfo to track previously seen InfoKey and Position values while
iterating through info, returning dedicated exported errors such as
ErrDuplicateKindInfoKey and ErrDuplicateKindInfoPosition when either value
repeats within the same kind. Preserve the existing validation order and error
context, and define the new error variables alongside the other model validation
errors.
🤖 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.

Nitpick comments:
In `@cmd/api/src/model/graphschema.go`:
- Around line 143-158: Update validateKindInfo to track previously seen InfoKey
and Position values while iterating through info, returning dedicated exported
errors such as ErrDuplicateKindInfoKey and ErrDuplicateKindInfoPosition when
either value repeats within the same kind. Preserve the existing validation
order and error context, and define the new error variables alongside the other
model validation errors.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: f076f1b7-cfba-40b1-a769-de46e0e2c164

📥 Commits

Reviewing files that changed from the base of the PR and between 957c90c and 0690c35.

📒 Files selected for processing (5)
  • cmd/api/src/api/v2/opengraphschema.go
  • cmd/api/src/database/graphschema.go
  • cmd/api/src/database/graphschema_integration_test.go
  • cmd/api/src/model/graphschema.go
  • cmd/api/src/model/graphschema_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • cmd/api/src/api/v2/opengraphschema.go

Info: infoInputs,
})
}
/*

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.

thanks for cleaning this up!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I think im going to cut another ticket to get all the old property stuff removed, there's an unused table as well as db functions, but its a little much to include here.


result = append(result, model.KindInfoInput{
InfoKey: key,
Title: payload.Title,

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.

Should we include validation on Title key? Currently the API is returning 500 status on missing the key or passing an empty string.

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.

Yeah I think we should either return a 400 with a descriptive error message if we want to have non-empty titles or allow empty titles and avoid the 500. Probably the former

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Whoops, thought i had a validation check for title, definitely need that and I agree with @urangel that we should be returning a 400.

Will get this added in a min

Comment thread cmd/api/src/model/graphschema.go Outdated

@urangel urangel 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.

Nice work!

Comment thread schemas/open_graph/dog-park-schema.json Outdated
}
}
],
"properties": [],

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.

I know this isn't apart of your PR but properties in the upsert extension schema is dead now, right?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes! Thank you for reminding me, i add a commit to remove this in a sec

@kpowderly

Copy link
Copy Markdown
Contributor

need a corresponding enterprise branch but looks good! excited to see the entity panel work for OG!!

Position: math.MaxInt32 + 1, // would silently wrap when cast to int32
Markdown: []byte(`{"content":"# Test"}`),
},
},

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Might be worth a test case for zero position too - I don't think it would throw an error as it is now, but it probably should?

@AD7ZJ AD7ZJ left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

One nit on the position validation, otherwise looks good to me!

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

Labels

api A pull request containing changes affecting the API code. documentation Improvements or additions to documentation enhancement New feature or request go Pull requests that update go code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants