Skip to content

Docs/ad4m model api refactor#740

Merged
lucksus merged 10 commits intodevfrom
docs/ad4m-model-api-refactor
Mar 11, 2026
Merged

Docs/ad4m model api refactor#740
lucksus merged 10 commits intodevfrom
docs/ad4m-model-api-refactor

Conversation

@jhweir
Copy link
Copy Markdown
Contributor

@jhweir jhweir commented Mar 10, 2026

PR: Update documentation for Ad4mModel API refactor

Branch: docs/ad4m-model-api-refactor
Files changed: 6 | +1,060 / −944 lines

Summary

Updates all developer-facing documentation to reflect the Ad4mModel decorator API refactoring (PR #717). Covers API renames, structural improvements, accuracy fixes, and new feature documentation.

Commits

1. docs: update documentation for Ad4mModel API refactor

Systematic rename pass across all 6 doc files:

  • @Subject@Model, @SubjectProperty@Property, @SubjectCollection@HasMany, @SubjectFlag@Flag
  • SubjectEntityAd4mModel, .baseExpression.id
  • SDNAClass.generateSDNA()Ad4mModel.generateSDNA()
  • Updated import paths, constructor signatures, query builder methods
  • Fixed getter syntax errors (FROM $parent → raw SurrealQL expression)

Files: model-classes.mdx, surreal-queries.mdx, batch-operations.mdx, hooks.mdx, index.mdx, social-dna.mdx

2. docs: restructure batch-operations, model-classes, and surreal-queries guides

Structural improvements for clarity and scannability:

  • batch-operations.mdx — Promoted transaction() as the primary pattern; demoted manual createBatch()/commitBatch() to an "Advanced" section
  • model-classes.mdx — Moved "How It Works Under the Hood" earlier in the page; condensed the JSON Schema section from ~330 lines to ~135 using a resolution cascade table
  • surreal-queries.mdx — Merged two overlapping graph traversal sections into one progressive section; fixed inaccurate index claims against actual DEFINE INDEX statements in source

3. docs: add missing API documentation to model-classes guide

Filled documentation gaps found by auditing the source code:

  • Built-in instance properties.author, .createdAt, .updatedAt (with usage in order queries)
  • RelationSubQuery — Filtering, sorting, and paginating eager-loaded relations via include
  • Full PropertyOptions tabletransform, local, initial (sentinel behavior), getter (Base placeholder, SurrealQL wrapping)
  • @Optional decorator — Mentioned as explicit alias for @Property with required: false
  • Default through — Documented that omitting through on relations defaults to 'ad4m://has_child'
  • IntrospectiongetModelMetadata(), generateSDNA(), generateSHACL() with usage example

Files changed

File Summary
model-classes.mdx Full rewrite + new sections (1,103 lines)
surreal-queries.mdx Merged graph traversal, fixed index docs (657 lines)
batch-operations.mdx Restructured around transaction() (227 lines)
hooks.mdx API renames only
index.mdx API renames, fixed getter syntax
social-dna.mdx API renames only

Summary by CodeRabbit

  • Documentation
    • Rewrote developer guides to promote a transaction-first workflow with updated examples, best practices, migration notes, and an advanced manual-batch section.
  • New Patterns
    • Transactional API introduced as the recommended automatic commit/rollback pattern; manual batch control retained as an advanced option.
  • API & Examples
    • Hook replaced by a live/reactive query API (returns "data", supports single-instance mode); model decorators and relation patterns simplified with updated examples and usage.
  • SurrealQL
    • Query guide reorganized with clearer fields/indexes, traversal guidance, and updated result aliasing.

jhweir added 3 commits March 10, 2026 18:37
- @modeloptions@model, @optional@Property, @Collection → @hasmany
- baseExpression → id, .update() → .save(), useModel → useLiveQuery
- ensureSDNASubjectClass → Model.register()
- New sections: relations, relation filtering, eager loading, parent-scoped
  queries, transactions, dirty tracking, model inheritance, JSON Schema
- Fix getter syntax (remove invalid SELECT...FROM $parent pattern)
- Add clarifying note on 'through' for computed properties
- Update SHACL mapping table with new ad4m:// predicates
…s guides

- batch-operations: promote transaction() as primary pattern, demote manual batch control to Advanced section
- model-classes: move 'How It Works' earlier, condense JSON Schema section with resolution table, restore propertyMapping and array relation examples
- surreal-queries: merge overlapping graph traversal sections, fix index documentation accuracy
- Add .author, .createdAt, .updatedAt built-in instance properties
- Document RelationSubQuery for filtering/sorting eager-loaded relations
- Add full PropertyOptions reference table (transform, local, initial, getter)
- Document default through value ('ad4m://has_child') on relation decorators
- Add @optional decorator mention
- Expand getter option with SurrealQL details and Base placeholder
- Document transform option with example
- Add introspection section (getModelMetadata, generateSDNA, generateSHACL)
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 10, 2026

Important

Review skipped

Too many files!

This PR contains 248 files, which is 98 over the limit of 150.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 76c9f397-4bcc-4676-8f0c-4c88e00b65a2

📥 Commits

Reviewing files that changed from the base of the PR and between 481047a and f18b990.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (248)
  • .gitignore
  • docs-src/next.config.js
  • docs-src/package.json
  • docs/404.html
  • docs/404/index.html
  • docs/_next/static/chunks/nextra-data-en-US.json
  • docs/agents.html
  • docs/agents/index.html
  • docs/auth.html
  • docs/developer-guides/ai.html
  • docs/developer-guides/batch-operations.html
  • docs/developer-guides/batch-operations/index.html
  • docs/developer-guides/cli.html
  • docs/developer-guides/hooks.html
  • docs/developer-guides/mcp.html
  • docs/developer-guides/model-classes.html
  • docs/developer-guides/model-classes/index.html
  • docs/developer-guides/surreal-queries.html
  • docs/expressions.html
  • docs/index.html
  • docs/installation.html
  • docs/jsdoc/README.html
  • docs/jsdoc/classes/AIClient.html
  • docs/jsdoc/classes/AIModelLoadingStatus.html
  • docs/jsdoc/classes/AIModelLoadingStatus/index.html
  • docs/jsdoc/classes/AIPromptExamples.html
  • docs/jsdoc/classes/AIPromptExamples/index.html
  • docs/jsdoc/classes/AIPromptExamplesInput.html
  • docs/jsdoc/classes/AIPromptExamplesInput/index.html
  • docs/jsdoc/classes/AITask.html
  • docs/jsdoc/classes/AITask/index.html
  • docs/jsdoc/classes/AITaskInput.html
  • docs/jsdoc/classes/AITaskInput/index.html
  • docs/jsdoc/classes/Ad4mClient.html
  • docs/jsdoc/classes/Ad4mClient/index.html
  • docs/jsdoc/classes/Ad4mModel.html
  • docs/jsdoc/classes/Ad4mModel/index.html
  • docs/jsdoc/classes/Agent.html
  • docs/jsdoc/classes/Agent/index.html
  • docs/jsdoc/classes/AgentClient.html
  • docs/jsdoc/classes/AgentExpression.html
  • docs/jsdoc/classes/AgentExpression/index.html
  • docs/jsdoc/classes/AgentSignature.html
  • docs/jsdoc/classes/AgentSignature/index.html
  • docs/jsdoc/classes/AgentStatus.html
  • docs/jsdoc/classes/AgentStatus/index.html
  • docs/jsdoc/classes/Apps.html
  • docs/jsdoc/classes/Apps/index.html
  • docs/jsdoc/classes/AuthInfo.html
  • docs/jsdoc/classes/AuthInfo/index.html
  • docs/jsdoc/classes/AuthInfoInput.html
  • docs/jsdoc/classes/AuthInfoInput/index.html
  • docs/jsdoc/classes/Capability.html
  • docs/jsdoc/classes/Capability/index.html
  • docs/jsdoc/classes/CapabilityInput.html
  • docs/jsdoc/classes/CapabilityInput/index.html
  • docs/jsdoc/classes/Dna.html
  • docs/jsdoc/classes/Dna/index.html
  • docs/jsdoc/classes/EntanglementProof.html
  • docs/jsdoc/classes/EntanglementProof/index.html
  • docs/jsdoc/classes/EntanglementProofInput.html
  • docs/jsdoc/classes/EntanglementProofInput/index.html
  • docs/jsdoc/classes/ExceptionInfo.html
  • docs/jsdoc/classes/ExceptionInfo/index.html
  • docs/jsdoc/classes/Expression.html
  • docs/jsdoc/classes/Expression/index.html
  • docs/jsdoc/classes/ExpressionProof.html
  • docs/jsdoc/classes/ExpressionProof/index.html
  • docs/jsdoc/classes/ExpressionProofInput.html
  • docs/jsdoc/classes/ExpressionProofInput/index.html
  • docs/jsdoc/classes/ExpressionRef.html
  • docs/jsdoc/classes/ExpressionRef/index.html
  • docs/jsdoc/classes/ExpressionRendered.html
  • docs/jsdoc/classes/ExpressionRendered/index.html
  • docs/jsdoc/classes/Icon.html
  • docs/jsdoc/classes/Icon/index.html
  • docs/jsdoc/classes/ImportResult.html
  • docs/jsdoc/classes/ImportResult/index.html
  • docs/jsdoc/classes/ImportStats.html
  • docs/jsdoc/classes/ImportStats/index.html
  • docs/jsdoc/classes/InteractionCall.html
  • docs/jsdoc/classes/InteractionCall/index.html
  • docs/jsdoc/classes/InteractionMeta.html
  • docs/jsdoc/classes/InteractionMeta/index.html
  • docs/jsdoc/classes/InteractionParameter.html
  • docs/jsdoc/classes/InteractionParameter/index.html
  • docs/jsdoc/classes/LanguageExpression.html
  • docs/jsdoc/classes/LanguageExpression/index.html
  • docs/jsdoc/classes/LanguageHandle.html
  • docs/jsdoc/classes/LanguageHandle/index.html
  • docs/jsdoc/classes/LanguageLanguageInput.html
  • docs/jsdoc/classes/LanguageLanguageInput/index.html
  • docs/jsdoc/classes/LanguageMeta.html
  • docs/jsdoc/classes/LanguageMeta/index.html
  • docs/jsdoc/classes/LanguageMetaInput.html
  • docs/jsdoc/classes/LanguageMetaInput/index.html
  • docs/jsdoc/classes/LanguageMetaInternal.html
  • docs/jsdoc/classes/LanguageMetaInternal/index.html
  • docs/jsdoc/classes/LanguageRef.html
  • docs/jsdoc/classes/LanguageRef/index.html
  • docs/jsdoc/classes/Link.html
  • docs/jsdoc/classes/Link/index.html
  • docs/jsdoc/classes/LinkExpression.html
  • docs/jsdoc/classes/LinkExpression/index.html
  • docs/jsdoc/classes/LinkExpressionInput.html
  • docs/jsdoc/classes/LinkExpressionInput/index.html
  • docs/jsdoc/classes/LinkExpressionMutations.html
  • docs/jsdoc/classes/LinkExpressionMutations/index.html
  • docs/jsdoc/classes/LinkExpressionUpdated.html
  • docs/jsdoc/classes/LinkExpressionUpdated/index.html
  • docs/jsdoc/classes/LinkInput.html
  • docs/jsdoc/classes/LinkInput/index.html
  • docs/jsdoc/classes/LinkMutations.html
  • docs/jsdoc/classes/LinkMutations/index.html
  • docs/jsdoc/classes/LinkQuery.html
  • docs/jsdoc/classes/LinkQuery/index.html
  • docs/jsdoc/classes/Literal.html
  • docs/jsdoc/classes/Literal/index.html
  • docs/jsdoc/classes/ModelQueryBuilder.html
  • docs/jsdoc/classes/Neighbourhood.html
  • docs/jsdoc/classes/Neighbourhood/index.html
  • docs/jsdoc/classes/NeighbourhoodExpression.html
  • docs/jsdoc/classes/NeighbourhoodExpression/index.html
  • docs/jsdoc/classes/NeighbourhoodProxy.html
  • docs/jsdoc/classes/NeighbourhoodProxy/index.html
  • docs/jsdoc/classes/Notification.html
  • docs/jsdoc/classes/Notification/index.html
  • docs/jsdoc/classes/NotificationInput.html
  • docs/jsdoc/classes/NotificationInput/index.html
  • docs/jsdoc/classes/OnlineAgent.html
  • docs/jsdoc/classes/OnlineAgent/index.html
  • docs/jsdoc/classes/Perspective.html
  • docs/jsdoc/classes/Perspective/index.html
  • docs/jsdoc/classes/PerspectiveAction.html
  • docs/jsdoc/classes/PerspectiveAction/index.html
  • docs/jsdoc/classes/PerspectiveDiff.html
  • docs/jsdoc/classes/PerspectiveDiff/index.html
  • docs/jsdoc/classes/PerspectiveDiffExpression.html
  • docs/jsdoc/classes/PerspectiveDiffExpression/index.html
  • docs/jsdoc/classes/PerspectiveExpression.html
  • docs/jsdoc/classes/PerspectiveExpression/index.html
  • docs/jsdoc/classes/PerspectiveHandle.html
  • docs/jsdoc/classes/PerspectiveHandle/index.html
  • docs/jsdoc/classes/PerspectiveInput.html
  • docs/jsdoc/classes/PerspectiveInput/index.html
  • docs/jsdoc/classes/PerspectiveProxy.html
  • docs/jsdoc/classes/PerspectiveUnsignedInput.html
  • docs/jsdoc/classes/PerspectiveUnsignedInput/index.html
  • docs/jsdoc/classes/QuerySubscriptionProxy.html
  • docs/jsdoc/classes/Resource.html
  • docs/jsdoc/classes/Resource/index.html
  • docs/jsdoc/classes/ResourceInput.html
  • docs/jsdoc/classes/ResourceInput/index.html
  • docs/jsdoc/classes/RuntimeInfo.html
  • docs/jsdoc/classes/RuntimeInfo/index.html
  • docs/jsdoc/classes/SHACLFlow.html
  • docs/jsdoc/classes/SHACLShape.html
  • docs/jsdoc/classes/SentMessage.html
  • docs/jsdoc/classes/SentMessage/index.html
  • docs/jsdoc/classes/SmartLiteral.html
  • docs/jsdoc/classes/SmartLiteral/index.html
  • docs/jsdoc/classes/Subject.html
  • docs/jsdoc/classes/Subject/index.html
  • docs/jsdoc/classes/TriggeredNotification.html
  • docs/jsdoc/classes/TriggeredNotification/index.html
  • docs/jsdoc/classes/UserCreationResult.html
  • docs/jsdoc/classes/UserStatistics.html
  • docs/jsdoc/classes/VerificationRequestResult.html
  • docs/jsdoc/enums/ExceptionType.html
  • docs/jsdoc/enums/ExceptionType/index.html
  • docs/jsdoc/enums/PerspectiveState.html
  • docs/jsdoc/enums/PerspectiveState/index.html
  • docs/jsdoc/interfaces/AD4MAction.html
  • docs/jsdoc/interfaces/Ad4mModelLike.html
  • docs/jsdoc/interfaces/AgentService.html
  • docs/jsdoc/interfaces/AgentService/index.html
  • docs/jsdoc/interfaces/CollectionMetadata/index.html
  • docs/jsdoc/interfaces/CollectionOptions/index.html
  • docs/jsdoc/interfaces/ConformanceCondition.html
  • docs/jsdoc/interfaces/DirectMessageAdapter.html
  • docs/jsdoc/interfaces/DirectMessageAdapter/index.html
  • docs/jsdoc/interfaces/ExpressionAdapter.html
  • docs/jsdoc/interfaces/ExpressionAdapter/index.html
  • docs/jsdoc/interfaces/ExpressionUI.html
  • docs/jsdoc/interfaces/ExpressionUI/index.html
  • docs/jsdoc/interfaces/FlagOptions.html
  • docs/jsdoc/interfaces/FlagOptions/index.html
  • docs/jsdoc/interfaces/FlowState.html
  • docs/jsdoc/interfaces/FlowTransition.html
  • docs/jsdoc/interfaces/GetAllAdapter.html
  • docs/jsdoc/interfaces/GetAllAdapter/index.html
  • docs/jsdoc/interfaces/GetByAuthorAdapter.html
  • docs/jsdoc/interfaces/GetByAuthorAdapter/index.html
  • docs/jsdoc/interfaces/HolochainLanguageDelegate.html
  • docs/jsdoc/interfaces/HolochainLanguageDelegate/index.html
  • docs/jsdoc/interfaces/IncludeMap.html
  • docs/jsdoc/interfaces/InitializeArgs.html
  • docs/jsdoc/interfaces/InitializeArgs/index.html
  • docs/jsdoc/interfaces/InstanceQueryParams/index.html
  • docs/jsdoc/interfaces/Interaction.html
  • docs/jsdoc/interfaces/Interaction/index.html
  • docs/jsdoc/interfaces/Language.html
  • docs/jsdoc/interfaces/Language/index.html
  • docs/jsdoc/interfaces/LanguageAdapter.html
  • docs/jsdoc/interfaces/LanguageAdapter/index.html
  • docs/jsdoc/interfaces/LanguageContext.html
  • docs/jsdoc/interfaces/LanguageContext/index.html
  • docs/jsdoc/interfaces/LinkPattern.html
  • docs/jsdoc/interfaces/LinkSyncAdapter.html
  • docs/jsdoc/interfaces/LinkSyncAdapter/index.html
  • docs/jsdoc/interfaces/ModelConfig.html
  • docs/jsdoc/interfaces/ModelMetadata.html
  • docs/jsdoc/interfaces/ModelMetadata/index.html
  • docs/jsdoc/interfaces/ModelOptionsOptions/index.html
  • docs/jsdoc/interfaces/PropertyMetadata.html
  • docs/jsdoc/interfaces/PropertyMetadata/index.html
  • docs/jsdoc/interfaces/PropertyMetadataEntry.html
  • docs/jsdoc/interfaces/PropertyOptions.html
  • docs/jsdoc/interfaces/PropertyOptions/index.html
  • docs/jsdoc/interfaces/PublicSharing.html
  • docs/jsdoc/interfaces/PublicSharing/index.html
  • docs/jsdoc/interfaces/ReadOnlyLanguage.html
  • docs/jsdoc/interfaces/ReadOnlyLanguage/index.html
  • docs/jsdoc/interfaces/RelationMetadata.html
  • docs/jsdoc/interfaces/RelationMetadataEntry.html
  • docs/jsdoc/interfaces/RelationOptions.html
  • docs/jsdoc/interfaces/SHACLPropertyShape.html
  • docs/jsdoc/interfaces/SettingsUI.html
  • docs/jsdoc/interfaces/SettingsUI/index.html
  • docs/jsdoc/interfaces/SignaturesService.html
  • docs/jsdoc/interfaces/SignaturesService/index.html
  • docs/jsdoc/interfaces/TelepresenceAdapter.html
  • docs/jsdoc/interfaces/TelepresenceAdapter/index.html
  • docs/jsdoc/modules.html
  • docs/languages.html
  • docs/neighbourhoods.html
  • docs/perspectives.html
  • docs/social-dna.html
  • docs/social-dna/index.html
  • docs/spanning-layer.html
  • docs/tutorial/1-perspective.html
  • docs/tutorial/1-perspective/index.html
  • docs/tutorial/2-neighbourhood-publish.html
  • docs/tutorial/2-neighbourhood-publish/index.html
  • docs/tutorial/3-neighbourhood-join.html
  • docs/tutorial/3-neighbourhood-join/index.html
  • docs/tutorial/4-change-listener.html
  • docs/tutorial/4-change-listener/index.html

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR refactors developer docs: replaces manual batch APIs with a transaction-centric pattern (Ad4mModel.transaction), renames/expands the hooks API (useModel → useLiveQuery) with new return shapes and modes, and updates model examples from ModelOptions/Collection/Optional to Model/Property/HasMany with registration/query pattern changes.

Changes

Cohort / File(s) Summary
Transactions & Batch Docs
docs-src/pages/developer-guides/batch-operations.mdx
Replaces manual batch examples (createBatch/commitBatch) with Ad4mModel.transaction(...); updates examples, best practices, migration notes; adds “Advanced: Manual Batch Control” showing lower-level PerspectiveProxy usage.
Hooks / Live Query
docs-src/pages/developer-guides/hooks.mdx
Renames useModeluseLiveQuery; changes return shape (entriesdata), adds collection vs single-instance modes, Vue parity, new return types (LiveCollectionResult/LiveInstanceResult) and updated examples and typing guidance.
Model Classes & SHACL
docs-src/pages/developer-guides/model-classes.mdx
Replaces decorator examples with @Model, @Property, @HasMany; documents Model.register(perspective), relation decorators, SHACL guidance, and removes legacy ModelOptions-based flows in examples.
SurrealDB Queries Guide
docs-src/pages/developer-guides/surreal-queries.mdx
Reworks indexing/traversal wording (renames “Indexed Fields” → “Fields & Indexes”), replaces baseExpressionid in query examples, and updates example decorators (@ModelOptions@Model).
Site Examples & Social DNA
docs-src/pages/index.mdx, docs-src/pages/social-dna.mdx
Updates top-level examples to use Model/Property/HasMany, removes legacy static helpers (all/allDone) in favor of findAll/query(...).where(...).get(), replaces ensureSDNASubjectClass with Model.register(perspective), and adjusts SHACL wording (writablereadOnly).

Sequence Diagram(s)

sequenceDiagram
  participant Dev as Developer Code
  participant Ad4m as Ad4mModel
  participant Pers as PerspectiveProxy
  participant DB as Storage/DB

  Dev->>Ad4m: Ad4mModel.transaction(perspective, async (tx) => { ... })
  Ad4m->>Pers: createBatch() / create transactional context
  Pers->>DB: stage writes (batch)
  Dev->>Ad4m: perform model create/save/link operations via tx
  Ad4m->>Pers: enqueue operations into batch
  alt no error
    Ad4m->>Pers: commitBatch()
    Pers->>DB: persist batch -> committed
    Ad4m->>Dev: transaction resolves
  else error
    Ad4m->>Pers: rollbackBatch()
    Pers->>DB: discard staged changes
    Ad4m->>Dev: transaction rejects (error)
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • lucksus

Poem

🐰 I hopped through docs both new and bright,
Swapped batches for transactions overnight.
useLiveQuery sings and Models wear new bows,
HasMany hugs Property where data grows.
A rabbit cheers — the docs now glow.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Docs/ad4m model api refactor' accurately summarizes the main objective of the PR: updating documentation to reflect the Ad4mModel decorator API refactor.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch docs/ad4m-model-api-refactor

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.

Copy link
Copy Markdown
Contributor

@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: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
docs-src/pages/social-dna.mdx (1)

242-252: ⚠️ Potential issue | 🟠 Major

The table should use the generated SHACL predicate, not the decorator option name.

The documentation currently lists ad4m://readOnly, but the generated SHACL shape emits ad4m://writable with a boolean value. This mismatch misdescribes what's actually stored in the perspective—developers following this table would search for the wrong predicate name.

Suggested fix
- | `ad4m://readOnly` | Property is read-only | Computed/immutable property |
+ | `ad4m://writable` | Whether the property can be written | `literal://boolean:false` for computed/immutable properties |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs-src/pages/social-dna.mdx` around lines 242 - 252, The table incorrectly
lists the decorator option ad4m://readOnly; update the table entry to use the
actual generated SHACL predicate ad4m://writable (which is emitted with a
boolean value) and adjust the AD4M Meaning cell to say "Property writable flag
(boolean)" or similar so it reflects that the shape stores a boolean writable
predicate rather than a readOnly decorator; update the Example cell accordingly
(e.g., `ad4m://writable: true/false`) and ensure any surrounding text that
references ad4m://readOnly is changed to ad4m://writable.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs-src/pages/developer-guides/batch-operations.mdx`:
- Around line 21-22: Update the docs to stop describing Ad4mModel.transaction()
as performing an explicit rollback: change wording to state that transaction()
creates a batch, runs the callback, and only commits on success, and that if the
callback throws the batch is not committed and no changes are persisted
(PerspectiveProxy does not expose a rollback API); search for references to
Ad4mModel.transaction and any mentions of "rollback" (including the sections
around lines referencing the earlier and later mentions) and replace those
sentences to say "changes are not committed" or "no commit occurs on error"
instead of claiming a rollback occurs.

In `@docs-src/pages/developer-guides/hooks.mdx`:
- Around line 267-270: The docs incorrectly reference a nonexistent
Model.register(perspective) API; replace that line to instruct users to call the
generated model class’s static register method (e.g.,
Recipe.register(perspective) or TestPost.register(perspective)) once at app
startup, and update the wording to explicitly state “Call
<ModelClass>.register(perspective) once at app startup — the hook does not
register models automatically” so readers know to use the concrete generated
class (Recipe, TestPost, etc.) rather than the `@Model` decorator.

In `@docs-src/pages/developer-guides/model-classes.mdx`:
- Around line 189-223: The snippet uses undeclared symbols Ad4mModel, Image, and
Category (while importing decorators like Model, Property, HasMany, HasOne,
BelongsToOne, BelongsToMany); fix by either adding explicit imports/definitions
for Ad4mModel, Image, and Category at the top of the snippet or mark the example
as a partial snippet (e.g., add a comment "partial: Ad4mModel, Image, Category
defined elsewhere") so readers know those types are defined elsewhere; ensure
references in the Recipe, Comment, and Author classes remain consistent with the
chosen approach.
- Around line 112-114: The docs incorrectly state that the framework supplies a
sentinel value for required properties; update the example and table to reflect
that `@Property`({ required: true }) mandates an explicit initial value (the
decorator implementation checks if (opts.required && !opts.initial) and will
throw), remove or replace references to the sentinel string
"literal://string:uninitialized", and change the sample property declaration
(the `@Property` usage at the example lines and the table description) to include
an explicit initial value so it matches the actual API contract (e.g., show
`@Property`({ through: "recipe://category", required: true, initial: "" }) or
equivalent).

In `@docs-src/pages/developer-guides/surreal-queries.mdx`:
- Around line 329-338: The participantsQuery is selecting and grouping by the
outer `author` instead of the nested item authors; update the query string in
`participantsQuery` to SELECT the nested traversal expression (`out->link[WHERE
predicate = 'ad4m://has_child'].author`) and also change the GROUP BY to use
that same nested expression (or remove GROUP BY if using SELECT VALUE to return
unique values) so the query returns the authors from the nested items rather
than the outer subgroup links.

In `@docs-src/pages/index.mdx`:
- Around line 273-275: The `@ReadOnly` decorator example is missing the required
through predicate for computed-property metadata/SHACL generation; update the
example so the ReadOnly declaration includes a through predicate (or
alternatively a prologGetter) alongside the existing getter expression (the
getter: 'count(->link[WHERE predicate = "flux://has_reaction" AND out.uri =
"flux://thumbsup"]) > 0'), e.g. add a through: 'flux://has_reaction' (or an
appropriate prologGetter) so the computed property definition is valid for
metadata/SHACL generation.

---

Outside diff comments:
In `@docs-src/pages/social-dna.mdx`:
- Around line 242-252: The table incorrectly lists the decorator option
ad4m://readOnly; update the table entry to use the actual generated SHACL
predicate ad4m://writable (which is emitted with a boolean value) and adjust the
AD4M Meaning cell to say "Property writable flag (boolean)" or similar so it
reflects that the shape stores a boolean writable predicate rather than a
readOnly decorator; update the Example cell accordingly (e.g., `ad4m://writable:
true/false`) and ensure any surrounding text that references ad4m://readOnly is
changed to ad4m://writable.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e9ab3d0a-b29b-455e-bbb6-23e396491615

📥 Commits

Reviewing files that changed from the base of the PR and between 91b08ba and 8099877.

📒 Files selected for processing (6)
  • docs-src/pages/developer-guides/batch-operations.mdx
  • docs-src/pages/developer-guides/hooks.mdx
  • docs-src/pages/developer-guides/model-classes.mdx
  • docs-src/pages/developer-guides/surreal-queries.mdx
  • docs-src/pages/index.mdx
  • docs-src/pages/social-dna.mdx

Comment on lines +112 to +114
// Required property — a placeholder link is created on save
@Property({ through: "recipe://category", required: true })
category: string = "";
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot Mar 10, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# Find the decorators file
find . -type f -name "decorators.ts" | head -20

Repository: coasys/ad4m

Length of output: 85


🏁 Script executed:

# Check the markdown file exists and read relevant sections
ls -la docs-src/pages/developer-guides/model-classes.mdx 2>/dev/null && wc -l docs-src/pages/developer-guides/model-classes.mdx

Repository: coasys/ad4m

Length of output: 209


🏁 Script executed:

# Read the specific lines mentioned in the review (112-114, 140-143)
sed -n '105,150p' docs-src/pages/developer-guides/model-classes.mdx

Repository: coasys/ad4m

Length of output: 2582


🏁 Script executed:

# Read the decorators.ts file around lines 310-336
sed -n '300,350p' core/src/model/decorators.ts

Repository: coasys/ad4m

Length of output: 1895


🏁 Script executed:

# Get broader context to understand the property decorator logic
sed -n '280,370p' core/src/model/decorators.ts

Repository: coasys/ad4m

Length of output: 3192


🏁 Script executed:

sed -n '185,230p' docs-src/pages/developer-guides/model-classes.mdx

Repository: coasys/ad4m

Length of output: 1474


required: true requires an explicit initial value — the decorator throws at class definition if omitted.

The decorator implementation explicitly checks if (opts.required && !opts.initial) and throws an error. The documentation incorrectly claims the framework inserts a sentinel value ("literal://string:uninitialized"). The example code at lines 112–114 and the table description at lines 140–143 must be corrected to reflect the actual API contract.

Suggested fix
-  `@Property`({ through: "recipe://category", required: true })
+  `@Property`({ through: "recipe://category", required: true, initial: "recipe://uncategorized" })
   category: string = "";
- | `initial` | `any` | — | Default value written on creation. When `required: true` with no `initial`, the framework uses a sentinel value (`"literal://string:uninitialized"`) |
+ | `initial` | `any` | — | Default value written on creation. Required properties must include an explicit `initial` value. |

Also applies to: 140–143

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs-src/pages/developer-guides/model-classes.mdx` around lines 112 - 114,
The docs incorrectly state that the framework supplies a sentinel value for
required properties; update the example and table to reflect that `@Property`({
required: true }) mandates an explicit initial value (the decorator
implementation checks if (opts.required && !opts.initial) and will throw),
remove or replace references to the sentinel string
"literal://string:uninitialized", and change the sample property declaration
(the `@Property` usage at the example lines and the table description) to include
an explicit initial value so it matches the actual API contract (e.g., show
`@Property`({ through: "recipe://category", required: true, initial: "" }) or
equivalent).

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.

The docs are correct on this one:

The public Property decorator (core/src/model/decorators.ts lines 1033–1038) wraps the internal applyPropertyMetadata and fills in the sentinel before the check runs:

export function Property(opts: PropertyOptions) {
    const required = opts.required ?? false;
    return applyPropertyMetadata({
        ...opts,
        required,
        initial: opts.initial ?? (required ? "literal://string:uninitialized" : undefined),
    });
}

So calling @Property({ through: "recipe://category", required: true }) without an explicit initial:

  1. Property sets initial to "literal://string:uninitialized" automatically
  2. applyPropertyMetadata then sees opts.initial is truthy → the if (opts.required && !opts.initial) check passes → no throw

The applyPropertyMetadata guard at decorators.ts line 315 only catches direct internal callers that bypass the Property wrapper. The public API never throws here.

The docs at model-classes.mdx line 113 (@Property({ through: "recipe://category", required: true })) and the table at line 143 (describing the sentinel behavior) both correctly describe this behavior.

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.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify the Property decorator implementation at lines 1033-1038
sed -n '1025,1050p' core/src/model/decorators.ts

Length of output: 947


@jhweir, you're right — I apologize for the incorrect review. The script output confirms exactly what you described:

export function Property(opts: PropertyOptions) {
    const required = opts.required ?? false;
    return applyPropertyMetadata({
        ...opts,
        required,
        readOnly: opts.readOnly ?? false,
        resolveLanguage: opts.resolveLanguage ?? "literal",
        initial: opts.initial ?? (required ? "literal://string:uninitialized" : undefined),
    });
}

The public Property wrapper injects the "literal://string:uninitialized" sentinel before applyPropertyMetadata is ever called, so the internal guard at line 315 is never triggered for public API consumers. The docs at line 113 and the table description at line 143 are both correct.


✏️ Learnings added
Learnt from: jhweir
Repo: coasys/ad4m PR: 740
File: docs-src/pages/developer-guides/model-classes.mdx:112-114
Timestamp: 2026-03-10T22:34:39.792Z
Learning: In `core/src/model/decorators.ts`, the public `Property` decorator (around line 1029) automatically injects a sentinel value `"literal://string:uninitialized"` as the `initial` when `required: true` and no `initial` is explicitly provided, before delegating to `applyPropertyMetadata`. The internal `applyPropertyMetadata` guard (`if (opts.required && !opts.initial)`) only fires for direct internal callers that bypass the `Property` wrapper. Therefore, calling `Property({ through: "...", required: true })` without an explicit `initial` is valid and does NOT throw — the sentinel is auto-supplied by the public wrapper. Documentation describing this sentinel behavior for `required: true` properties is correct.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 Learnings used
Learnt from: lucksus
Repo: coasys/ad4m PR: 644
File: core/src/model/Ad4mModel.ts:814-822
Timestamp: 2026-01-15T17:30:01.739Z
Learning: In core/src/model/Ad4mModel.ts, when parsing literal URLs with Literal.fromUrl(value).get() in the getData() method's SurrealDB fallback path (around lines 814-822), the code correctly checks for a `data` property (`parsed.data !== undefined ? parsed.data : parsed`) to handle two cases: Expression objects (which have a data property that should be extracted when we want just the value) and other literal types (which should be used as-is). This conditional is intentional and correct *in this specific context* where we want to reduce Expressions to their data values. Note that this is not a universal pattern—Expression shapes are preserved with full metadata in other contexts where that's needed.

…predicate

- batch-operations: remove inaccurate rollback references (transaction has no rollback API)
- hooks: fix Model.register() → <ModelClass>.register(perspective) with concrete class example
- model-classes: add Ad4mModel import and inline Image/Category definitions to relations snippet
- surreal-queries: fix participantsQuery to SELECT nested item authors instead of outer link author
- index: add missing through predicate to @readonly getter example
Copy link
Copy Markdown
Contributor

@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: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
docs-src/pages/developer-guides/hooks.mdx (1)

275-279: ⚠️ Potential issue | 🟡 Minor

Avoid !data as the generic loading guard.

useLiveQuery collection mode always returns an array ([] initially), so this pattern never renders a loading state there. Use loading explicitly, or show separate examples for collection vs. instance-mode hooks.

✏️ Suggested doc tweak
-  if (!data) return <LoadingComponent />;
+  if (loading) return <LoadingComponent />;
+  // For useLiveQuery collections:
+  // if (loading && data.length === 0) return <LoadingComponent />;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs-src/pages/developer-guides/hooks.mdx` around lines 275 - 279, The
example using "if (error) ..." / "if (!data) ..." is misleading for useLiveQuery
because collection-mode returns [] initially; update the docs to check the
hook's loading state explicitly (e.g., use the returned loading boolean) or show
two examples: one for collection-mode (check data.length === 0 or loading) and
one for instance-mode (check !data). Mention the hook name useLiveQuery and
example components ErrorComponent and LoadingComponent so readers know where to
apply the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs-src/pages/developer-guides/batch-operations.mdx`:
- Around line 185-187: Update the doc text to remove the claim that
Ad4mModel.transaction handles failed-batch cleanup and explicitly state its
current behavior: transaction() calls createBatch(), invokes the callback, then
calls commitBatch(), but if the callback throws the batch remains uncommitted
(no automatic rollback/cleanup). Reference Ad4mModel.transaction and the
createBatch/commitBatch flow so readers know they must handle try/catch/cleanup
for errors when using manual batches or transaction() until the implementation
adds error-path cleanup.

In `@docs-src/pages/developer-guides/model-classes.mdx`:
- Line 393: The phrasing "must be set on creation" for `sh:minCount 1` is too
strict; update the line to say "must exist on creation" and add a short
parenthetical note that when `@Property({ required: true })` is used without an
explicit `initial`, the public wrapper auto-supplies the sentinel value
`literal://string:uninitialized` (i.e., a placeholder is inserted before
creation), so callers don't always need to populate the field themselves.

In `@docs-src/pages/developer-guides/surreal-queries.mdx`:
- Around line 181-186: The current example collects friendsOfFriends via
perspective.querySurrealDB where the selected friend_of_friend is an array per
row, so using [...new Set(friendsOfFriends.map(f => f.friend_of_friend))]
deduplicates arrays not inner URIs; update the docs to flatten the results first
(e.g., use flatMap or map(...).flat()) on the friendsOfFriends result before
constructing a Set so you deduplicate individual URIs produced by querySurrealDB
for friend_of_friend.

---

Outside diff comments:
In `@docs-src/pages/developer-guides/hooks.mdx`:
- Around line 275-279: The example using "if (error) ..." / "if (!data) ..." is
misleading for useLiveQuery because collection-mode returns [] initially; update
the docs to check the hook's loading state explicitly (e.g., use the returned
loading boolean) or show two examples: one for collection-mode (check
data.length === 0 or loading) and one for instance-mode (check !data). Mention
the hook name useLiveQuery and example components ErrorComponent and
LoadingComponent so readers know where to apply the change.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a432662c-aa93-4045-aa70-c9e3457a9858

📥 Commits

Reviewing files that changed from the base of the PR and between 8099877 and 1da3376.

📒 Files selected for processing (5)
  • docs-src/pages/developer-guides/batch-operations.mdx
  • docs-src/pages/developer-guides/hooks.mdx
  • docs-src/pages/developer-guides/model-classes.mdx
  • docs-src/pages/developer-guides/surreal-queries.mdx
  • docs-src/pages/index.mdx

Comment on lines +185 to +187
3. **Error Handling**: With `transaction()`, errors thrown inside the callback automatically prevent commit. With manual batches, wrap operations in try/catch.

4. **Resource Management**: Don't keep batches open longer than necessary. With `transaction()` this is handled for you.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot Mar 10, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Don’t claim transaction() handles failed-batch cleanup.

The current Ad4mModel.transaction() implementation only does createBatch() → callback → commitBatch(). If the callback throws, the batch is left uncommitted; there is no error-path cleanup in core/src/model/Ad4mModel.ts:3590-3598. Line 187 should document that limitation instead of implying lifecycle management is automatic.

✏️ Suggested doc tweak
-4. **Resource Management**: Don't keep batches open longer than necessary. With `transaction()` this is handled for you.
+4. **Resource Management**: Don't keep batches open longer than necessary. `transaction()` keeps the happy path short, but its current implementation does not clean up a batch when the callback throws.
📝 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
3. **Error Handling**: With `transaction()`, errors thrown inside the callback automatically prevent commit. With manual batches, wrap operations in try/catch.
4. **Resource Management**: Don't keep batches open longer than necessary. With `transaction()` this is handled for you.
3. **Error Handling**: With `transaction()`, errors thrown inside the callback automatically prevent commit. With manual batches, wrap operations in try/catch.
4. **Resource Management**: Don't keep batches open longer than necessary. `transaction()` keeps the happy path short, but its current implementation does not clean up a batch when the callback throws.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs-src/pages/developer-guides/batch-operations.mdx` around lines 185 - 187,
Update the doc text to remove the claim that Ad4mModel.transaction handles
failed-batch cleanup and explicitly state its current behavior: transaction()
calls createBatch(), invokes the callback, then calls commitBatch(), but if the
callback throws the batch remains uncommitted (no automatic rollback/cleanup).
Reference Ad4mModel.transaction and the createBatch/commitBatch flow so readers
know they must handle try/catch/cleanup for errors when using manual batches or
transaction() until the implementation adds error-path cleanup.

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.

No fix needed — the docs already accurately reflect the current behavior after the rollback fixes from commit 1da33767.

Current doc state

  • Line 181: "if the callback throws, the batch is not committed and no changes are persisted" — accurate. transaction() calls fn() before commitBatch(), so if fn throws, commitBatch is never reached.
  • Line 185: "errors thrown inside the callback automatically prevent commit" — accurate. Same reasoning: the exception propagates before commitBatch runs.
  • Line 219: The migration example shows transaction() without try/catch — accurate. The batch simply won't commit if fn throws; the error propagates to the caller.

Analysis

The finding asks us to "explicitly state... no automatic rollback/cleanup" and "they must handle try/catch/cleanup for errors." But looking at the source code (Ad4mModel.ts lines 3594–3598):

static async transaction<R = void>(
  perspective: PerspectiveProxy,
  fn: (tx: { batchId: string }) => Promise<R>,
): Promise<R> {
  const batchId = await perspective.createBatch();
  const result = await fn({ batchId });
  await perspective.commitBatch(batchId);
  return result;
}

There is nothing to clean up — an uncommitted batch is just an in-memory buffer that gets garbage-collected. There is no cancelBatch() or deleteBatch() API. The batch simply evaporates when it's never committed.

The docs correctly say "the batch is not committed and no changes are persisted" — that is the cleanup behavior. Adding warnings about manual cleanup would be misleading since there's nothing to manually clean up.

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.

@jhweir, you're absolutely right — I apologize for the incorrect finding. The key insight I missed is that uncommitted batches in AD4M are purely in-memory buffers with no persistent state to clean up. Since there's no cancelBatch()/deleteBatch() API, a thrown exception leaving the batch uncommitted is the cleanup — it simply gets garbage-collected. The existing doc language ("the batch is not committed and no changes are persisted") accurately describes the full lifecycle. No changes needed here.

- model-classes: update sh:minCount 1 description to 'must exist on creation' with sentinel note
- surreal-queries: fix friendsOfFriends dedup to use flatMap (traversal returns arrays per row)
Copy link
Copy Markdown
Contributor

@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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
docs-src/pages/developer-guides/surreal-queries.mdx (1)

557-575: ⚠️ Potential issue | 🟠 Major

Correct the traversal direction in both graph examples at lines 557-575.

When filtering with WHERE out.uri = 'user://alice' AND predicate = 'follows', in.uri represents the followers. The first query incorrectly labels followers as Post, and the second query traverses from out (Alice) instead of in (followers). Both should traverse from in->link to query follower activities.

Suggested fix
-// Use graph traversal to find posts liked by Alice's followers (2-hop)
-const results = await perspective.querySurrealDB(`
-  SELECT 
-    in.uri AS Post,
-    out.uri AS User
-  FROM link
-  WHERE out.uri = 'user://alice'
-    AND predicate = 'follows'
-    AND in->link[WHERE predicate = 'likes'].out.uri IS NOT NONE
-`);
+// Use graph traversal to find posts liked by Alice's followers (2-hop)
+const likedPosts = await perspective.querySurrealDB(`
+  SELECT
+    in.uri AS follower,
+    in->link[WHERE predicate = 'likes'].out.uri AS liked_posts
+  FROM link
+  WHERE out.uri = 'user://alice'
+    AND predicate = 'follows'
+`);

-// Alternative: Get all liked posts by traversing from followers
-const likedPosts = await perspective.querySurrealDB(`
-  SELECT 
-    out.uri AS follower,
-    out->link[WHERE predicate = 'likes'].out.uri AS liked_posts
-  FROM link
-  WHERE out.uri = 'user://alice' AND predicate = 'follows'
-`);
+// Alternative: flatten the liked post URIs in JavaScript if needed
+// [...new Set(likedPosts.flatMap(r => r.liked_posts))]
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs-src/pages/developer-guides/surreal-queries.mdx` around lines 557 - 575,
Both query examples passed to perspective.querySurrealDB use the wrong traversal
direction: when filtering WHERE out.uri = 'user://alice' AND predicate =
'follows', the followers are represented by in, so change the selections and
traversals to start from in. Update the first query to select in.uri as the
follower/user and traverse in->link[WHERE predicate = 'likes'].out.uri for the
posts (instead of in.uri AS Post), and update the second query to SELECT in.uri
AS follower and in->link[WHERE predicate = 'likes'].out.uri AS liked_posts
(traversing from in, not out). Ensure both query strings passed to
perspective.querySurrealDB reflect these in->link traversals.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs-src/pages/developer-guides/model-classes.mdx`:
- Around line 603-607: The nested include references an author relation on
Comment that doesn't exist; update the Comment model to declare the relation
(e.g., add a `@BelongsToOne`(() => Author) relation property named author and the
corresponding foreign key property) so the nested include in Recipe.query (the
comments include block) resolves, or alternatively change the nested include to
reference an existing Comment relation; modify the Comment class (the class
currently only defining body) to add the author relation and type Author so the
include { comments: { include: { author: true } } } is valid.
- Around line 231-233: The relation named "author" conflicts with the built-in
AD4M author field; rename the `@BelongsToOne` relation and its property from
author to a non-conflicting identifier (e.g., creator or recipeAuthor) in the
model declaration (`@BelongsToOne`(() => Author, { through: "recipe://author" })
creator: string = ""), and update all corresponding eager-load examples and
references that access the relation (the eager include/relationships shown in
the examples that currently reference author) to use the new name so the model
property and example usage stay consistent.

---

Outside diff comments:
In `@docs-src/pages/developer-guides/surreal-queries.mdx`:
- Around line 557-575: Both query examples passed to perspective.querySurrealDB
use the wrong traversal direction: when filtering WHERE out.uri = 'user://alice'
AND predicate = 'follows', the followers are represented by in, so change the
selections and traversals to start from in. Update the first query to select
in.uri as the follower/user and traverse in->link[WHERE predicate =
'likes'].out.uri for the posts (instead of in.uri AS Post), and update the
second query to SELECT in.uri AS follower and in->link[WHERE predicate =
'likes'].out.uri AS liked_posts (traversing from in, not out). Ensure both query
strings passed to perspective.querySurrealDB reflect these in->link traversals.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5a16e0f3-5383-49ec-be27-cf8c6330edfa

📥 Commits

Reviewing files that changed from the base of the PR and between 1da3376 and 1f4dc56.

📒 Files selected for processing (2)
  • docs-src/pages/developer-guides/model-classes.mdx
  • docs-src/pages/developer-guides/surreal-queries.mdx

- Author class → Chef (chef://name predicate)
- Recipe relation: creator → chef (recipe://chef)
- Comment relation: writer → chef (comment://chef)
- Updated nested include examples to reference chef
Copy link
Copy Markdown
Contributor

@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: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs-src/pages/developer-guides/model-classes.mdx`:
- Around line 118-122: The ReadOnly decorator example for averageRating is
inconsistent: update the getter to use the Base placeholder as explained later
(use Base as the current instance node). Replace the getter expression in the
`@ReadOnly` on averageRating so it uses Base->link (e.g., `math::mean(->link[WHERE
predicate = 'recipe://user_rating'].out.uri)` should become one that starts with
`Base->link`, matching the documented convention for Base; ensure the getter in
the `@ReadOnly` on the `averageRating: number = 0;` property uses the Base
placeholder syntax shown elsewhere.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4498ea32-13e5-4477-ad24-f3f25d425d10

📥 Commits

Reviewing files that changed from the base of the PR and between 1f4dc56 and 481047a.

📒 Files selected for processing (1)
  • docs-src/pages/developer-guides/model-classes.mdx

Comment on lines +118 to +122
@ReadOnly({
through: "recipe://rating",
getter: `math::mean(->link[WHERE predicate = 'recipe://user_rating'].out.uri)`
})
averageRating: number = 0;
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.

⚠️ Potential issue | 🟡 Minor

Inconsistent getter example — missing Base placeholder.

This example omits the Base placeholder, but the detailed explanation later (lines 162–167) explicitly states "Use Base as a placeholder for the current instance's node" and shows Base->link in the example. These should be consistent.

📝 Suggested fix
   `@ReadOnly`({
     through: "recipe://rating",
-    getter: `math::mean(->link[WHERE predicate = 'recipe://user_rating'].out.uri)`
+    getter: `math::mean(Base->link[WHERE predicate = 'recipe://user_rating'].out.uri)`
   })
   averageRating: number = 0;
📝 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
@ReadOnly({
through: "recipe://rating",
getter: `math::mean(->link[WHERE predicate = 'recipe://user_rating'].out.uri)`
})
averageRating: number = 0;
`@ReadOnly`({
through: "recipe://rating",
getter: `math::mean(Base->link[WHERE predicate = 'recipe://user_rating'].out.uri)`
})
averageRating: number = 0;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs-src/pages/developer-guides/model-classes.mdx` around lines 118 - 122,
The ReadOnly decorator example for averageRating is inconsistent: update the
getter to use the Base placeholder as explained later (use Base as the current
instance node). Replace the getter expression in the `@ReadOnly` on averageRating
so it uses Base->link (e.g., `math::mean(->link[WHERE predicate =
'recipe://user_rating'].out.uri)` should become one that starts with
`Base->link`, matching the documented convention for Base; ensure the getter in
the `@ReadOnly` on the `averageRating: number = 0;` property uses the Base
placeholder syntax shown elsewhere.

@lucksus lucksus merged commit 93945d8 into dev Mar 11, 2026
6 of 7 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.

2 participants