Skip to content

feat: State of Affairs (SoA) ontology for knowledge representation#704

Open
data-bot-coasys wants to merge 6 commits intodevfrom
feature/soa-schemas
Open

feat: State of Affairs (SoA) ontology for knowledge representation#704
data-bot-coasys wants to merge 6 commits intodevfrom
feature/soa-schemas

Conversation

@data-bot-coasys
Copy link
Contributor

@data-bot-coasys data-bot-coasys commented Mar 2, 2026

Fix applied: Node 18-compatible path resolution in esbuild.ts

Summary by CodeRabbit

New Features

  • Added State of Affairs (SoA) ontology module for knowledge representation with six distinct modalities: belief, observation, intention, vision, plan, and skill
  • Introduced standard relationship types for linking knowledge units: supports, contradicts, similar, same, requires, enables, parent, refines, and blocks
  • Implemented self-documenting SoA language with built-in provenance tracking (authorship and timestamp)

Introduces the SoA schema as a top-level AD4M project with:

- StateOfAffair: universal base class for propositions with modalities
  (belief, observation, intention, vision, plan, skill)
- SoARelationship: typed edges between SoA nodes
  (supports, contradicts, similar, same, requires, enables, parent, refines, blocks)
- TypeScript model classes using Ad4mModel decorators (for UIs/Flux)
- JSON schemas with x-ad4m extensions (for MCP/programmatic access)

Designed to work for both human and AI agent knowledge trees,
supporting the Eve collective intelligence architecture.

Part of the State of Affairs trees concept from the Eve vision.
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 2, 2026

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

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: bd5cff74-85f9-4d30-aceb-d490c465292f

📥 Commits

Reviewing files that changed from the base of the PR and between 51c128f and 2c33d30.

📒 Files selected for processing (2)
  • soa/language/esbuild.ts
  • soa/language/src/adapter.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • soa/language/esbuild.ts

📝 Walkthrough

Walkthrough

Adds a new State of Affairs (SoA) ontology package: TypeScript Ad4mModel for SoA, canonical soa:// expressions registry, a read-only language adapter and UI wiring, package manifests and build scripts, TypeScript configs, and documentation for predicates, modalities, and usage.

Changes

Cohort / File(s) Summary
Documentation
soa/README.md
New ontology README describing SoA concepts, modalities, relationship predicates, SHACL generation from Ad4mModel decorators, usage examples, and design principles.
Package Manifests
soa/package.json, soa/language/package.json, package.json
New package manifests for @coasys/soa and @coasys/soa-language, workspace entries added, build scripts and dependencies declared.
Model & Exports
soa/src/StateOfAffair.ts, soa/src/index.ts
Adds StateOfAffair Ad4mModel and SoAModality type with property decorators mapped to soa:// predicates; exports SoA predicate constants and SoARelationshipType.
Language: expressions registry
soa/language/src/expressions.ts
Adds SoADocumentation interface and SOA_EXPRESSIONS mapping providing canonical documentation for property and relationship expressions.
Language: adapter & wiring
soa/language/src/adapter.ts, soa/language/src/index.ts
Implements SoAExpressionAdapter and SoAReadOnly, resolves soa:// addresses to signed documentation expressions; wires a read-only Language with UI and immutability enforcement.
Build & Config
soa/tsconfig.json, soa/language/esbuild.ts
Adds TypeScript config for soa package and esbuild bundling script for the language package; build targets and externals configured.

Sequence Diagram(s)

mermaid
sequenceDiagram
participant Client as Client
participant Lang as Language
participant Adapter as SoAExpressionAdapter
participant Registry as SOA_EXPRESSIONS
Client->>Lang: request expression for soa://<key>
Lang->>Adapter: get(address)
Adapter->>Registry: lookup key
alt key found
Registry-->>Adapter: SoADocumentation
Adapter-->>Lang: signed SoADocumentation Expression
else key unknown
Registry-->>Adapter: not found
Adapter-->>Lang: null
end
Lang-->>Client: return Expression / null

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • lucksus
  • jhweir

Poem

🐇 I nibble soa:// leaves at dawn,
predicates shining on the lawn,
modalities bloom, relations sing,
I sign the docs and do a spring,
Hooray — knowledge carrots all day long! 🥕

🚥 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 'feat: State of Affairs (SoA) ontology for knowledge representation' accurately describes the main change: introducing a new SoA ontology system as a top-level AD4M project with TypeScript models, language implementation, and documentation.
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 docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/soa-schemas

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
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

🧹 Nitpick comments (1)
soa/src/Relationship.ts (1)

51-57: Use SoARelationshipType for relationshipType instead of string.

The union already exists but isn’t applied, so invalid relationship values compile.

Type-safe field
-  relationshipType: string;
+  relationshipType: SoARelationshipType;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@soa/src/Relationship.ts` around lines 51 - 57, The relationshipType property
in Relationship (the `@Property-decorated` field) is incorrectly typed as string;
change its TypeScript type to the existing union SoARelationshipType (i.e.,
relationshipType: SoARelationshipType) and add the appropriate import for
SoARelationshipType if not already in the file so invalid relationship values
fail type checking.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@soa/package.json`:
- Around line 5-6: The package.json currently points "main" and "types" at
TypeScript sources (main/types) which will break consumers; add a tsconfig.json
at the soa root that emits compiled JS and declaration files to dist (set outDir
to ./dist and declaration true, include src), add a "build" script in
soa/package.json that runs tsc, update "main" to "dist/index.js" and "types" to
"dist/index.d.ts", and add an "exports" field mapping "." to { "types":
"./dist/index.d.ts", "default": "./dist/index.js" } so Node resolution works for
published packages.

In `@soa/README.md`:
- Around line 67-70: The TypeScript snippet uses incorrect field names on
SoARelationship; update the assignment lines that set rel.type, rel.source, and
rel.target to use the correct properties rel.relationshipType, rel.sourceRef,
and rel.targetRef respectively, keeping the same values (e.g.,
belief.baseExpression and goal.baseExpression) so the example matches the
SoARelationship interface/implementation.
- Around line 24-33: The README relationship table lists a `child` relationship
that isn't present in the exported type/schema; update the docs to match the
schema by removing the `child` entry (or replacing the "parent / child" row with
just `parent`) in the Relationship table so only supported relationships (e.g.,
`parent`) are documented; ensure you edit the table row containing the "`parent`
/ `child`" text in the README to reflect the actual exported symbol `parent`.
- Around line 36-47: The README.md fenced directory block lacks a language
identifier and triggers markdownlint MD040; update the opening fence for the
block shown (the triple-backtick block containing the soa/ tree) to include a
language identifier such as "text" (i.e., change ``` to ```text) so the code
block is explicitly typed and the linter warning is resolved.

In `@soa/src/Relationship.ts`:
- Around line 82-117: The TypeScript model currently marks strength, note,
author, and createdAt as required but the JSON schema makes them optional;
update the Relationship model by adding the optional marker to those properties
(change strength, note, author, createdAt to strength?, note?, author?,
createdAt?) where they are declared with the `@Property` decorator in
Relationship.ts so the TS model aligns with soa/schemas/Relationship.json.

In `@soa/src/StateOfAffair.ts`:
- Around line 47-152: The class properties currently use incorrect types and
requiredness: change the modality property's type from string to SoAModality
(import SoAModality where needed) and mark all other properties except title and
modality as optional (use ? on description, confidence, status, author,
createdAt, updatedAt, tags, priority, source) so the TypeScript class aligns
with soa/schemas/StateOfAffair.json; ensure Property decorators remain but
update the TypeScript signatures for modality and the optional fields (refer to
symbols modality, title, description, confidence, status, author, createdAt,
updatedAt, tags, priority, source).

---

Nitpick comments:
In `@soa/src/Relationship.ts`:
- Around line 51-57: The relationshipType property in Relationship (the
`@Property-decorated` field) is incorrectly typed as string; change its TypeScript
type to the existing union SoARelationshipType (i.e., relationshipType:
SoARelationshipType) and add the appropriate import for SoARelationshipType if
not already in the file so invalid relationship values fail type checking.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e94f4b9 and cca8ad4.

📒 Files selected for processing (7)
  • soa/README.md
  • soa/package.json
  • soa/schemas/Relationship.json
  • soa/schemas/StateOfAffair.json
  • soa/src/Relationship.ts
  • soa/src/StateOfAffair.ts
  • soa/src/index.ts

soa/package.json Outdated
Comment on lines +5 to +6
"main": "src/index.ts",
"types": "src/index.ts",
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -e
jq '{main,types,exports,files}' soa/package.json
echo "---- tsconfig compiler options ----"
fd 'tsconfig.*json' soa | xargs -r -I{} sh -c 'echo "## {}"; jq ".compilerOptions | {outDir,declaration,emitDeclarationOnly,module,target}" "{}"'
echo "---- existing built entry artifacts ----"
fd 'index.(js|d.ts)$' soa

Repository: coasys/ad4m

Length of output: 251


🏁 Script executed:

#!/bin/bash
# Check for root-level tsconfig
echo "---- Root tsconfig ----"
jq ".compilerOptions | {outDir,declaration,emitDeclarationOnly,module,target}" tsconfig.json 2>/dev/null || echo "No root tsconfig.json"

# Check soa package.json build scripts
echo "---- soa package.json build scripts ----"
jq '.scripts' soa/package.json

# Check if dist/ exists at root or soa level
echo "---- Checking for dist/ ----"
ls -la soa/dist 2>/dev/null || echo "No soa/dist/"
ls -la dist 2>/dev/null || echo "No root dist/"

# Check workspaces/monorepo setup
echo "---- Root package.json workspaces ----"
jq '.workspaces // .packages // "no workspaces field"' package.json

Repository: coasys/ad4m

Length of output: 465


🏁 Script executed:

#!/bin/bash
# Check README or package.json description for soa
echo "---- soa package.json description ----"
jq '.description // "no description"' soa/package.json

# Check if soa is referenced as a dependency elsewhere
echo "---- References to soa in other packages ----"
rg '"soa"' --type json | head -20

# Check if there's any .npmignore or publish config
echo "---- Files in soa root ----"
ls -la soa/ | grep -E "npm|publish"

# Check git history or README in soa
echo "---- soa/README if exists ----"
cat soa/README.md 2>/dev/null || echo "No README.md"
</parameter>

Repository: coasys/ad4m

Length of output: 3888


Publishing entrypoints require a build process and proper output configuration.

The main and types fields point to TypeScript source, which breaks consumers expecting transpiled JavaScript and type definitions. This package appears intended for npm publishing (per the README usage examples), but lacks the build infrastructure to support it.

To fix this, the package needs:

  1. A TypeScript configuration (tsconfig.json in soa/)
  2. A build script in package.json to generate dist/ with compiled JS and .d.ts files
  3. Update main/types to point to dist/ outputs
  4. Add the exports field for modern Node.js resolution:
Example configuration

soa/tsconfig.json (minimal):

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "ESNext",
    "declaration": true,
    "outDir": "./dist",
    "rootDir": "./src"
  },
  "include": ["src"]
}

soa/package.json:

{
  "main": "dist/index.js",
  "types": "dist/index.d.ts",
  "exports": {
    ".": {
      "types": "./dist/index.d.ts",
      "default": "./dist/index.js"
    }
  },
  "scripts": {
    "build": "tsc"
  }
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@soa/package.json` around lines 5 - 6, The package.json currently points
"main" and "types" at TypeScript sources (main/types) which will break
consumers; add a tsconfig.json at the soa root that emits compiled JS and
declaration files to dist (set outDir to ./dist and declaration true, include
src), add a "build" script in soa/package.json that runs tsc, update "main" to
"dist/index.js" and "types" to "dist/index.d.ts", and add an "exports" field
mapping "." to { "types": "./dist/index.d.ts", "default": "./dist/index.js" } so
Node resolution works for published packages.

Comment on lines +82 to +117
@Property({
through: 'soa://relationship_strength',
resolveLanguage: 'literal',
writable: true,
})
strength: number;

/**
* Optional annotation explaining the relationship.
*/
@Property({
through: 'soa://relationship_note',
resolveLanguage: 'literal',
writable: true,
})
note: string;

/**
* Who asserted this relationship.
*/
@Property({
through: 'soa://relationship_author',
resolveLanguage: 'literal',
writable: true,
})
author: string;

/**
* ISO 8601 timestamp of creation.
*/
@Property({
through: 'soa://relationship_created_at',
resolveLanguage: 'literal',
writable: true,
})
createdAt: string;
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

find . -path "*/soa/schemas/Relationship.json" -type f

Repository: coasys/ad4m

Length of output: 86


🏁 Script executed:

find . -path "*/soa/src/Relationship.ts" -type f

Repository: coasys/ad4m

Length of output: 80


🏁 Script executed:

cat -n ./soa/schemas/Relationship.json

Repository: coasys/ad4m

Length of output: 3191


🏁 Script executed:

cat -n ./soa/src/Relationship.ts

Repository: coasys/ad4m

Length of output: 3643


Model requiredness is stricter than schema requiredness.

The fields strength, note, author, and createdAt are optional in soa/schemas/Relationship.json (only relationshipType, sourceRef, and targetRef are in the required array), but typed as required in the TypeScript model. Add the optional marker ? to align with the schema.

Align TS model with schema optional fields
-  strength: number;
+  strength?: number;
...
-  note: string;
+  note?: string;
...
-  author: string;
+  author?: string;
...
-  createdAt: string;
+  createdAt?: string;
📝 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
@Property({
through: 'soa://relationship_strength',
resolveLanguage: 'literal',
writable: true,
})
strength: number;
/**
* Optional annotation explaining the relationship.
*/
@Property({
through: 'soa://relationship_note',
resolveLanguage: 'literal',
writable: true,
})
note: string;
/**
* Who asserted this relationship.
*/
@Property({
through: 'soa://relationship_author',
resolveLanguage: 'literal',
writable: true,
})
author: string;
/**
* ISO 8601 timestamp of creation.
*/
@Property({
through: 'soa://relationship_created_at',
resolveLanguage: 'literal',
writable: true,
})
createdAt: string;
`@Property`({
through: 'soa://relationship_strength',
resolveLanguage: 'literal',
writable: true,
})
strength?: number;
/**
* Optional annotation explaining the relationship.
*/
`@Property`({
through: 'soa://relationship_note',
resolveLanguage: 'literal',
writable: true,
})
note?: string;
/**
* Who asserted this relationship.
*/
`@Property`({
through: 'soa://relationship_author',
resolveLanguage: 'literal',
writable: true,
})
author?: string;
/**
* ISO 8601 timestamp of creation.
*/
`@Property`({
through: 'soa://relationship_created_at',
resolveLanguage: 'literal',
writable: true,
})
createdAt?: string;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@soa/src/Relationship.ts` around lines 82 - 117, The TypeScript model
currently marks strength, note, author, and createdAt as required but the JSON
schema makes them optional; update the Relationship model by adding the optional
marker to those properties (change strength, note, author, createdAt to
strength?, note?, author?, createdAt?) where they are declared with the
`@Property` decorator in Relationship.ts so the TS model aligns with
soa/schemas/Relationship.json.

"flag": {
"through": "soa://entry_type",
"value": "soa://relationship"
}
Copy link
Member

Choose a reason for hiding this comment

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

Do we really need a flag? I actually think that's an anti-pattern. The graph shape with used language ('soa' here) already provides enough constraints.

"through": "soa://relationship_type",
"resolveLanguage": "literal",
"writable": true
}
Copy link
Member

Choose a reason for hiding this comment

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

I think what might be more elegant would be to just use one link for relationships and have the 'soa' language have those types as expressions. I.e. soa://rel_supports, soa://rel_contradicts..

Copy link
Member

Choose a reason for hiding this comment

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

Then we don't need a Relationship type at all. But we should talk about actually implementing that soa language (as a static language - just defining those static expressions which resolve to documentation :))

}
},
"author": {
"type": "string",
Copy link
Member

Choose a reason for hiding this comment

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

not needed. every link that constitutes this shape is a link expression with author and timestamp. and there could be multiple authors (by multiple users creating that SoA even independently).

Copy link
Member

@lucksus lucksus left a comment

Choose a reason for hiding this comment

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

Should the json be a shacl JSON representation?

- Remove Flag decorator (anti-pattern; graph shape + soa:// namespace suffices)
- Remove Relationship model entirely — relationships are just AD4M links
  with soa://rel_* predicates (supports, contradicts, parent, etc.)
- Remove author/createdAt/updatedAt fields — link expressions carry provenance
- Remove JSON schema files — SHACL is auto-generated from decorators
- Export relationship predicate constants (SoA.REL_SUPPORTS, etc.)
- Mark optional fields with ? to match intended schema
- Use SoAModality type instead of string for modality field

Much simpler and more AD4M-native. The soa language should be
implemented as a static language with these expressions resolving
to documentation.
Copy link
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.

♻️ Duplicate comments (1)
soa/package.json (1)

5-12: ⚠️ Potential issue | 🟠 Major

Entrypoints still target TypeScript source instead of build artifacts.

main/types point to src/index.ts, and published files only include src/. That will break plain Node/JS consumers unless they transpile your package themselves.

Suggested packaging fix
-  "main": "src/index.ts",
-  "types": "src/index.ts",
+  "main": "dist/index.js",
+  "types": "dist/index.d.ts",
+  "exports": {
+    ".": {
+      "types": "./dist/index.d.ts",
+      "default": "./dist/index.js"
+    }
+  },
@@
-  "files": [
-    "src/"
-  ],
+  "files": [
+    "dist/",
+    "src/"
+  ],
#!/bin/bash
set -e
echo "== package entrypoints =="
jq '{main,types,exports,files,scripts}' soa/package.json

echo "== tsconfig under soa =="
fd 'tsconfig.*json' soa --exec sh -c 'echo "## $1"; jq ".compilerOptions | {outDir,declaration,emitDeclarationOnly,module,target}" "$1"' sh {}

echo "== built artifacts =="
fd 'index.(js|d.ts)$' soa/dist || true
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@soa/package.json` around lines 5 - 12, The package.json currently points
entry fields ("main" and "types") at the TypeScript source (src/index.ts) and
publishes only src/, which breaks consumers; update package.json to point "main"
to the compiled JS artifact (e.g. dist/index.js) and "types" to the generated
declaration file (e.g. dist/index.d.ts), add dist to "files", and ensure the
"build" script and tsconfig produce JS + .d.ts (enable declaration and set
outDir) so the published package contains transpiled artifacts consumers can
require.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@soa/package.json`:
- Around line 5-12: The package.json currently points entry fields ("main" and
"types") at the TypeScript source (src/index.ts) and publishes only src/, which
breaks consumers; update package.json to point "main" to the compiled JS
artifact (e.g. dist/index.js) and "types" to the generated declaration file
(e.g. dist/index.d.ts), add dist to "files", and ensure the "build" script and
tsconfig produce JS + .d.ts (enable declaration and set outDir) so the published
package contains transpiled artifacts consumers can require.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cca8ad4 and 036dbc4.

📒 Files selected for processing (4)
  • soa/README.md
  • soa/package.json
  • soa/src/StateOfAffair.ts
  • soa/src/index.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • soa/src/index.ts
  • soa/README.md

@data-bot-coasys
Copy link
Contributor Author

Hey Nico — all your review points are addressed in commit 036dbc46d:

  1. Removed is_relationship flag — you're right, the graph shape + language provides enough constraints
  2. Relationships via soa://rel_* predicates — e.g. soa://rel_supports, soa://rel_contradicts, etc. as link predicates (no separate Relationship type needed)
  3. Removed author/createdAt — link expressions already carry those natively
  4. Removed the JSON schema files — the TypeScript model with @ModelOptions/@Property decorators is the source of truth (these generate SHACL SDNA automatically via the AD4M model system)

The SoA language itself (defining those static expressions like soa://rel_supports) is documented in the README but not yet implemented as an actual AD4M Language. Happy to discuss the design for that — a static language that just resolves to documentation sounds clean.

Adds the soa:// language as a static, self-documenting vocabulary.
Every soa:// expression resolves to structured documentation with:
- name, description, kind (property vs relationship)
- valueType for properties, examples as AD4M link triples
- agentNotes: guidance specifically for AI agents

This is a ReadOnlyLanguage — no new expressions can be created.
All expressions are immutable and cacheable.

Also serves as a pattern/template for how AD4M languages can act
as self-documenting semantic vocabularies for any domain.
Copy link
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

🧹 Nitpick comments (4)
soa/language/src/index.ts (2)

9-9: Unused import: SOA_EXPRESSIONS.

SOA_EXPRESSIONS is imported but never used in this file. It's only needed in adapter.ts.

♻️ Remove unused import
 import SoAExpressionAdapter from "./adapter.ts";
-import { SOA_EXPRESSIONS } from "./expressions.ts";
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@soa/language/src/index.ts` at line 9, Remove the unused import
SOA_EXPRESSIONS from soa/language/src/index.ts; it’s not referenced in this file
(only used in adapter.ts), so delete the import line "import { SOA_EXPRESSIONS }
from \"./expressions.ts\";" to eliminate the unused symbol and any linter
warnings.

66-74: Use satisfies Language to validate object shape while preserving type safety.

The current as Language type assertion suppresses type checking. Using satisfies Language instead validates that the object conforms to the Language interface at compile-time without hiding potential type mismatches, which is the preferred TypeScript pattern.

♻️ Use satisfies for type safety
-  return {
+  const language = {
     name,
     expressionAdapter,
     expressionUI,
     iconFor,
     constructorIcon,
     isImmutableExpression,
     interactions,
-  } as Language;
+  } satisfies Language;
+  return language;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@soa/language/src/index.ts` around lines 66 - 74, Replace the type assertion
"as Language" on the returned object with the TypeScript "satisfies Language"
operator so the compiler validates the object shape without widening types;
update the return expression that currently includes name, expressionAdapter,
expressionUI, iconFor, constructorIcon, isImmutableExpression, interactions to
end with "satisfies Language" instead of "as Language".
soa/language/src/adapter.ts (2)

58-63: addressOf implementation could produce unexpected addresses.

The fallback to JSON.stringify(content) when neither key nor address is present may produce addresses that don't match any entry in SOA_EXPRESSIONS. Consider validating the address format or documenting the expected content structure.

♻️ Proposed improvement for type safety
 class SoAReadOnly implements ReadOnlyLanguage {
   async addressOf(content: object): Promise<Address> {
-    // For a read-only language, the address is the key itself
-    const c = content as Record<string, string>;
-    return c.key || c.address || JSON.stringify(content);
+    // For a read-only language, the address is the key itself
+    const c = content as { key?: string; address?: string };
+    const addr = c.key ?? c.address;
+    if (!addr) {
+      throw new Error('SoA content must have a "key" or "address" property');
+    }
+    return addr;
   }
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@soa/language/src/adapter.ts` around lines 58 - 63, The current
SoAReadOnly.addressOf implementation can return unpredictable JSON-stringified
addresses which may not match SOA_EXPRESSIONS; update addressOf (class
SoAReadOnly implementing ReadOnlyLanguage) to validate input and returned
address: check for content.key or content.address and if absent either throw a
clear validation error or normalize/derive a predictable address format, or
validate the derived address against the expected pattern or membership in
SOA_EXPRESSIONS before returning; include a brief error message referencing the
missing key/address to aid callers and ensure the function never returns an
arbitrary JSON string as the final Address.

31-55: Consider whether returning an error expression vs. null is the intended behavior.

Currently, unknown addresses return a signed error expression rather than null. This is helpful for discoverability but may cause issues if callers expect null for non-existent addresses (the standard pattern for get() in most AD4M languages). Ensure consumers of this language handle both cases.

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

In `@soa/language/src/adapter.ts` around lines 31 - 55, The get(address: Address)
method currently returns a signed error expression for unknown keys from
SOA_EXPRESSIONS rather than the conventional null; change this to return null
for unknown addresses to follow standard get() semantics, and move the signed
error-expression creation into a separate helper (e.g.,
createNotFoundExpression) or keep the existing createSignedExpression call
available for callers who want a verbose error; update get() to first strip the
prefix, look up SOA_EXPRESSIONS[key], and if missing simply return null (while
preserving createSignedExpression usage for any explicit callers that need an
error payload).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@soa/language/package.json`:
- Around line 6-11: The package.json in soa/language is misconfigured: change
"main" to point to the compiled output (e.g., dist/index.js) rather than
src/index.ts, fix the "build" script so it references a real build entry (create
esbuild.ts in soa/language or change scripts.build to call an existing build
file), add esbuild to devDependencies so the build can run, declare the runtime
dependency for `@perspect3vism/ad4m` in dependencies (or remove/replace the CDN
import in source), and add soa/language to the root package.json workspaces
array so the monorepo recognizes the package; update the package.json fields
"main", "scripts.build", "devDependencies", and "dependencies" accordingly and
ensure a corresponding esbuild.ts or build task exists.

---

Nitpick comments:
In `@soa/language/src/adapter.ts`:
- Around line 58-63: The current SoAReadOnly.addressOf implementation can return
unpredictable JSON-stringified addresses which may not match SOA_EXPRESSIONS;
update addressOf (class SoAReadOnly implementing ReadOnlyLanguage) to validate
input and returned address: check for content.key or content.address and if
absent either throw a clear validation error or normalize/derive a predictable
address format, or validate the derived address against the expected pattern or
membership in SOA_EXPRESSIONS before returning; include a brief error message
referencing the missing key/address to aid callers and ensure the function never
returns an arbitrary JSON string as the final Address.
- Around line 31-55: The get(address: Address) method currently returns a signed
error expression for unknown keys from SOA_EXPRESSIONS rather than the
conventional null; change this to return null for unknown addresses to follow
standard get() semantics, and move the signed error-expression creation into a
separate helper (e.g., createNotFoundExpression) or keep the existing
createSignedExpression call available for callers who want a verbose error;
update get() to first strip the prefix, look up SOA_EXPRESSIONS[key], and if
missing simply return null (while preserving createSignedExpression usage for
any explicit callers that need an error payload).

In `@soa/language/src/index.ts`:
- Line 9: Remove the unused import SOA_EXPRESSIONS from
soa/language/src/index.ts; it’s not referenced in this file (only used in
adapter.ts), so delete the import line "import { SOA_EXPRESSIONS } from
\"./expressions.ts\";" to eliminate the unused symbol and any linter warnings.
- Around line 66-74: Replace the type assertion "as Language" on the returned
object with the TypeScript "satisfies Language" operator so the compiler
validates the object shape without widening types; update the return expression
that currently includes name, expressionAdapter, expressionUI, iconFor,
constructorIcon, isImmutableExpression, interactions to end with "satisfies
Language" instead of "as Language".

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3bc01b33-f3fc-4faf-acaf-2cce0dfbe158

📥 Commits

Reviewing files that changed from the base of the PR and between 036dbc4 and 270171e.

📒 Files selected for processing (5)
  • soa/README.md
  • soa/language/package.json
  • soa/language/src/adapter.ts
  • soa/language/src/expressions.ts
  • soa/language/src/index.ts
✅ Files skipped from review due to trivial changes (1)
  • soa/README.md

Comment on lines +6 to +11
"main": "src/index.ts",
"scripts": {
"build": "node esbuild.ts"
},
"dependencies": {},
"devDependencies": {}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check if esbuild.ts exists in the language directory
fd -t f "esbuild.ts" soa/language

# Check if there's a shared esbuild config at repo root
fd -t f "esbuild" -d 2

Repository: coasys/ad4m

Length of output: 74


🏁 Script executed:

# Check the soa/language directory structure
ls -la soa/language/

# Look at root package.json for dependencies
cat -n package.json | head -50

# Check if there's an esbuild.ts in soa/language
ls -la soa/language/esbuild.ts 2>/dev/null || echo "esbuild.ts not found in soa/language"

# Check the imports in soa/language/src/index.ts
cat -n soa/language/src/index.ts

Repository: coasys/ad4m

Length of output: 5393


🏁 Script executed:

# Find where soa/language actually is in the repo
find . -type d -name "soa" 2>/dev/null

# Check if there's a bootstrap-languages directory
ls -la bootstrap-languages/ 2>/dev/null || echo "No bootstrap-languages directory at root"

# Check git status to see file structure
git ls-files | grep -E "(soa|bootstrap)" | head -20

Repository: coasys/ad4m

Length of output: 2333


🏁 Script executed:

# Check perspective-language structure
ls -la soa/perspective-language/

# Check if perspective-language has esbuild.ts
ls -la soa/perspective-language/esbuild.ts 2>/dev/null || echo "No esbuild.ts in perspective-language"

# Check perspective-language package.json
cat -n soa/perspective-language/package.json

Repository: coasys/ad4m

Length of output: 252


Package configuration is incomplete and build script will fail.

  1. The main field points to TypeScript source (src/index.ts) rather than compiled output, which consumers may not be able to import directly.
  2. The build script references esbuild.ts, but this file does not exist in soa/language/.
  3. devDependencies is empty, but esbuild is required for the build script to execute.
  4. The code imports @perspect3vism/ad4m via CDN (https://esm.sh/...) but no dependency is declared in package.json.

Additionally, soa/language is not included in the root package.json workspaces configuration, which may cause issues with monorepo tooling.

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

In `@soa/language/package.json` around lines 6 - 11, The package.json in
soa/language is misconfigured: change "main" to point to the compiled output
(e.g., dist/index.js) rather than src/index.ts, fix the "build" script so it
references a real build entry (create esbuild.ts in soa/language or change
scripts.build to call an existing build file), add esbuild to devDependencies so
the build can run, declare the runtime dependency for `@perspect3vism/ad4m` in
dependencies (or remove/replace the CDN import in source), and add soa/language
to the root package.json workspaces array so the monorepo recognizes the
package; update the package.json fields "main", "scripts.build",
"devDependencies", and "dependencies" accordingly and ensure a corresponding
esbuild.ts or build task exists.

- Remove unused SOA_EXPRESSIONS import from language/src/index.ts
- Use 'satisfies Language' instead of 'as Language' for type safety
- Improve addressOf to throw error instead of returning JSON.stringify fallback
- Fix soa/package.json main/types to point to dist/, add exports field
- Add tsconfig.json for proper TypeScript compilation
- Fix soa/language/package.json with proper dependencies and devDependencies
- Add esbuild.ts build script for language package
Copy link
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

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

Inline comments:
In `@soa/language/esbuild.ts`:
- Around line 1-7: The build script uses import.meta.dirname (seen in the
esbuild.build call for entryPoints and outfile) which is unsupported on Node
16–20.10; replace usage with a Node-compatible resolution: derive a file path
from import.meta.url using fileURLToPath and path.dirname (import fileURLToPath
from "url" and use path.join) and then use that derived dirname in the
esbuild.build entryPoints and outfile options so the script runs on Node 16+.

In `@soa/language/src/adapter.ts`:
- Around line 36-45: ExpressionAdapter.get() currently creates and returns a
signed error expression for unknown addresses (inside the branch where doc is
falsy), but the method's contract requires returning null for unresolved
addresses; change the branch that builds an expression via
this.#agent.createSignedExpression(...) to simply return null when doc is not
found (remove the signed-expression creation in that path). Keep SOA_EXPRESSIONS
and knownKeys logic if you want to expose a dedicated discovery/known-address
endpoint, but do not return a truthy/expressive result from
ExpressionAdapter.get() — ensure the function returns null for unknown keys so
callers can distinguish "missing" from "found".
- Around line 59-66: The addressOf function currently returns the raw key or
address which creates duplicate identities; update the addressOf(content:
object): Promise<Address> implementation to canonicalize the result to the
soa:// form: extract the candidate from content.key or content.address (same
selection logic is fine), validate it exists, and if it does not already start
with the "soa://" scheme, prepend "soa://" before returning so both bare keys
and full addresses normalize to the same canonical Address; ensure you avoid
double-prefixing if the input already includes "soa://".

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: bb967fb6-4a43-4d46-af0c-b849605d3cda

📥 Commits

Reviewing files that changed from the base of the PR and between 270171e and 51c128f.

📒 Files selected for processing (7)
  • package.json
  • soa/language/esbuild.ts
  • soa/language/package.json
  • soa/language/src/adapter.ts
  • soa/language/src/index.ts
  • soa/package.json
  • soa/tsconfig.json
✅ Files skipped from review due to trivial changes (1)
  • soa/tsconfig.json
🚧 Files skipped from review as they are similar to previous changes (3)
  • soa/package.json
  • soa/language/src/index.ts
  • soa/language/package.json

- Replace import.meta.dirname with Node 16+ compatible path resolution
- Return null for unknown addresses per ExpressionAdapter contract
- Canonicalize addressOf to soa:// scheme to avoid duplicate identities
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