diff --git a/package.json b/package.json index 3e978e900..86c7bde4a 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,9 @@ "dapp", "ad4m-hooks/react", "ad4m-hooks/vue", - "ad4m-hooks/helpers" + "ad4m-hooks/helpers", + "soa", + "soa/language" ], "private": true, "scripts": { diff --git a/soa/README.md b/soa/README.md new file mode 100644 index 000000000..6ab10ee10 --- /dev/null +++ b/soa/README.md @@ -0,0 +1,136 @@ +# State of Affairs (SoA) — AD4M Ontology + +A universal ontology for representing knowledge, beliefs, intentions, and plans as structured trees within AD4M perspectives. + +## Overview + +A **State of Affairs** (SoA) is a proposition about how things are, could be, or should be. It is the fundamental unit of knowledge representation in this ontology. + +Every node in a SoA tree is a `StateOfAffair` with a **modality** that describes its epistemic status: + +| Modality | Meaning | Example | +|---|---|---| +| `belief` | Something we hold as true | "Holochain handles P2P sync" | +| `observation` | Something directly verified | "CI is green on commit abc123" | +| `intention` | Something we want to make true | "AD4M has MCP support" | +| `vision` | A high-level desired future | "Distributed collective intelligence" | +| `plan` | Steps to reach an intended SoA | "Merge branches → release → prototype" | +| `skill` | A capability an agent has | "Can query perspectives via MCP" | + +## Relationships + +Relationships between SoA nodes are expressed as **standard AD4M links** using the `soa` language for predicates. No separate model needed — link expressions natively carry author and timestamp. + +| Predicate | Meaning | +|---|---| +| `soa://rel_supports` | Evidence or argument for | +| `soa://rel_contradicts` | Evidence or argument against | +| `soa://rel_similar` | Related but not identical | +| `soa://rel_same` | Equivalent propositions | +| `soa://rel_requires` | Dependency (target requires source) | +| `soa://rel_enables` | Capability (source enables target) | +| `soa://rel_parent` | Tree structure (source is parent of target) | +| `soa://rel_refines` | More specific version of | +| `soa://rel_blocks` | Prevents or blocks | + +The `soa` language is a static language — these expressions resolve to documentation describing the relationship semantics. + +## Authorship & Provenance + +SoA nodes do **not** store author or timestamp fields. Every link that constitutes a SoA shape is an AD4M `LinkExpression` which natively includes: +- `author` — the DID of the agent who created the link +- `timestamp` — when the link was created + +A single SoA can have multiple authors — when different agents independently create the same state of affairs, the link graph naturally represents this. + +## Structure + +```text +soa/ +├── README.md # This file +├── src/ # TypeScript model classes +│ ├── index.ts # Exports + relationship predicate constants +│ └── StateOfAffair.ts +├── language/ # Static SoA language (ReadOnlyLanguage) +│ └── src/ +│ ├── index.ts # Language entry point +│ ├── adapter.ts # ExpressionAdapter — resolves soa:// to docs +│ └── expressions.ts # Registry of all soa:// expressions + docs +└── package.json +``` + +SHACL shapes are auto-generated from the `Ad4mModel` decorators — no separate schema files needed. The TypeScript classes ARE the source of truth. + +## Usage + +### TypeScript (UI / Flux) +```typescript +import { StateOfAffair, SoA } from '@coasys/soa'; + +// Create a belief +const belief = new StateOfAffair(); +belief.title = "SHACL is the source of truth for subject classes"; +belief.modality = "belief"; +belief.confidence = 0.95; + +// Create an intention +const goal = new StateOfAffair(); +goal.title = "Migrate Data's memory to AD4M perspectives"; +goal.modality = "intention"; + +// Link them with a relationship (just an AD4M link!) +perspective.addLink({ + source: belief.baseExpression, + predicate: SoA.REL_SUPPORTS, + target: goal.baseExpression, +}); + +// Tree structure +perspective.addLink({ + source: parentSoA.baseExpression, + predicate: SoA.REL_PARENT, + target: childSoA.baseExpression, +}); +``` + +### MCP / Programmatic Access +SoA instances can be created via MCP tools using the auto-generated SHACL shape. Relationships are just `add_link` calls with `soa://rel_*` predicates. + +## Design Principles + +1. **No flags** — the graph shape + `soa://` namespace is sufficient for type identification +2. **No separate relationship model** — relationships are native AD4M links with typed predicates +3. **No author/timestamp fields** — link expressions handle provenance natively +4. **Works for humans AND agents** — same schema for personal memory, shared task boards, Eve's worldview +5. **Trees AND graphs** — `rel_parent` gives hierarchy; other predicates give cross-links +6. **Fractal** — same pattern at individual, group, and network levels +7. **Evolvable** — new modalities and relationship predicates can be added without breaking existing trees + +## The `soa` Language + +The `soa` language is a **static ReadOnlyLanguage** — it defines fixed expressions that resolve to structured documentation. When any agent (human or AI) resolves a `soa://` URL, they get back a rich object explaining what it means and how to use it: + +```typescript +// Resolving soa://rel_supports returns: +{ + "@type": "SoADocumentation", + "address": "soa://rel_supports", + "name": "Supports", + "kind": "relationship", + "description": "Source provides evidence, argument, or backing for target...", + "example": "link(evidence_soa, \"soa://rel_supports\", claim_soa)", + "agentNotes": "Directional: A supports B means A is evidence FOR B..." +} +``` + +This makes the ontology **self-documenting and discoverable**. AI agents encountering `soa://` predicates for the first time can resolve them to understand the ontology without external documentation. + +### Pattern for other languages + +The soa language serves as a template for how AD4M languages can act as **self-documenting semantic vocabularies**. Any domain can create a similar static language to define its own predicates — just map addresses to documentation objects. + +Implementation: `soa/language/src/` + +## Connection to Eve + +In the Eve vision, every agent (human or AI) builds their own SoA tree — their worldview. Shared neighbourhoods allow SoA subtrees to be synchronized, enabling distributed consensus through Eve-to-Eve communication. The same ontology powers personal memory, collaborative task tracking, and collective intelligence. diff --git a/soa/language/esbuild.ts b/soa/language/esbuild.ts new file mode 100644 index 000000000..e3d5b32b0 --- /dev/null +++ b/soa/language/esbuild.ts @@ -0,0 +1,18 @@ +import * as esbuild from "esbuild"; +import { fileURLToPath } from "url"; +import { dirname, join } from "path"; + +const __dirname = dirname(fileURLToPath(import.meta.url)); + +const result = await esbuild.build({ + entryPoints: [join(__dirname, "src", "index.ts")], + bundle: true, + outfile: join(__dirname, "dist", "index.js"), + format: "esm", + platform: "node", + target: "es2020", + sourcemap: true, + external: ["@perspect3vism/ad4m"], +}); + +console.log("Build completed:", result); diff --git a/soa/language/package.json b/soa/language/package.json new file mode 100644 index 000000000..3e946485d --- /dev/null +++ b/soa/language/package.json @@ -0,0 +1,23 @@ +{ + "name": "@coasys/soa-language", + "version": "0.1.0", + "description": "Static self-documenting vocabulary for State of Affairs ontology", + "type": "module", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "default": "./dist/index.js" + } + }, + "scripts": { + "build": "node esbuild.ts" + }, + "dependencies": { + "@perspect3vism/ad4m": "^0.5.0" + }, + "devDependencies": { + "esbuild": "^0.19.0" + } +} diff --git a/soa/language/src/adapter.ts b/soa/language/src/adapter.ts new file mode 100644 index 000000000..b1de6bc39 --- /dev/null +++ b/soa/language/src/adapter.ts @@ -0,0 +1,65 @@ +import type { + Address, + Expression, + ExpressionAdapter, + ReadOnlyLanguage, + LanguageContext, + AgentService, +} from "https://esm.sh/v135/@perspect3vism/ad4m@0.5.0"; +import { SOA_EXPRESSIONS } from "./expressions.ts"; + +/** + * SoA Expression Adapter + * + * Resolves soa:// addresses to structured documentation. + * This is a ReadOnlyLanguage — expressions are predefined, + * not created by users. + * + * When an AI agent or application resolves "soa://rel_supports", + * they get back a rich documentation object explaining what + * "supports" means, how to use it, and example link triples. + */ +export default class SoAExpressionAdapter implements ExpressionAdapter { + #agent: AgentService; + putAdapter: ReadOnlyLanguage; + + constructor(context: LanguageContext) { + this.#agent = context.agent; + this.putAdapter = new SoAReadOnly(); + } + + async get(address: Address): Promise { + // Strip the soa:// prefix if present + const key = address.replace(/^soa:\/\//, ''); + + const doc = SOA_EXPRESSIONS[key]; + if (!doc) { + // Return null for unknown addresses per ExpressionAdapter contract + return null; + } + + // Return the documentation as a signed expression + const expression = await this.#agent.createSignedExpression({ + '@type': 'SoADocumentation', + address: `soa://${key}`, + ...doc, + }); + return expression; + } +} + +class SoAReadOnly implements ReadOnlyLanguage { + async addressOf(content: object): Promise
{ + // 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'); + } + // Canonicalize to soa:// form + if (addr.startsWith('soa://')) { + return addr; + } + return `soa://${addr}`; + } +} diff --git a/soa/language/src/expressions.ts b/soa/language/src/expressions.ts new file mode 100644 index 000000000..c9ccaa030 --- /dev/null +++ b/soa/language/src/expressions.ts @@ -0,0 +1,188 @@ +/** + * SoA Language Expression Registry + * + * Static documentation for every soa:// expression. + * When an agent resolves a soa:// URL, they get back structured + * documentation that helps them understand what it means and + * how to use it in context. + * + * This is the canonical reference for the SoA ontology — + * a pattern for how AD4M languages can serve as + * self-documenting semantic vocabularies. + */ + +export interface SoADocumentation { + /** Human-readable name */ + name: string; + /** What this expression represents */ + description: string; + /** Whether this is a property (on a node) or a relationship (between nodes) */ + kind: 'property' | 'relationship'; + /** Expected data type for properties, or role description for relationships */ + valueType?: string; + /** Usage example as an AD4M link triple */ + example: string; + /** Additional notes for AI agents working with this expression */ + agentNotes?: string; +} + +/** + * All known soa:// expressions and their documentation. + * + * Properties are used as predicates in links from a StateOfAffair + * base expression to literal values: + * link(soa_instance, "soa://title", "literal://string:My Belief") + * + * Relationships are used as predicates in links between two + * StateOfAffair instances: + * link(soa_A, "soa://rel_supports", soa_B) + */ +export const SOA_EXPRESSIONS: Record = { + // ── Properties ────────────────────────────────────────────── + + 'title': { + name: 'Title', + kind: 'property', + description: 'Short summary of a State of Affairs — the core proposition or claim.', + valueType: 'string (via literal:// language)', + example: 'link(soa, "soa://title", "literal://string:Distributed systems are more resilient")', + agentNotes: 'Every StateOfAffair must have exactly one title. Keep it concise — use description for details.', + }, + + 'modality': { + name: 'Modality', + kind: 'property', + description: 'Epistemic status of this State of Affairs — what kind of knowledge it represents.', + valueType: 'enum: belief | observation | intention | vision | plan | skill', + example: 'link(soa, "soa://modality", "literal://string:belief")', + agentNotes: 'Modality determines how to interpret confidence and status. A "belief" with 0.3 confidence is uncertain; an "intention" with 0.3 confidence is weakly committed. "vision" and "plan" are related: visions are high-level desired futures, plans are concrete steps toward them.', + }, + + 'description': { + name: 'Description', + kind: 'property', + description: 'Extended description, evidence, reasoning, or body text for a State of Affairs.', + valueType: 'string (via literal:// language)', + example: 'link(soa, "soa://description", "literal://string:Based on 20 years of distributed systems research...")', + agentNotes: 'Optional. Use for context that doesn\'t fit in the title. Can be long-form.', + }, + + 'confidence': { + name: 'Confidence', + kind: 'property', + description: 'Confidence level from 0.0 to 1.0. Meaning depends on modality: certainty (beliefs), reliability (observations), commitment (intentions).', + valueType: 'number 0.0-1.0 (via literal:// language)', + example: 'link(soa, "soa://confidence", "literal://number:0.85")', + agentNotes: 'Optional. When absent, no confidence judgment is implied. Useful for epistemic humility — an agent that tracks confidence can reason about what it knows vs. what it assumes.', + }, + + 'status': { + name: 'Status', + kind: 'property', + description: 'Current lifecycle status. Values depend on modality: intentions/plans use active|completed|abandoned|blocked; beliefs use held|revised|retracted; observations use current|outdated.', + valueType: 'string (via literal:// language)', + example: 'link(soa, "soa://status", "literal://string:active")', + agentNotes: 'Optional. Tracks the evolution of knowledge over time. "revised" means the belief has been updated (look for a newer version via rel_refines). "retracted" means it was wrong.', + }, + + 'tags': { + name: 'Tags', + kind: 'property', + description: 'Comma-separated tags for categorization, filtering, and search.', + valueType: 'string, comma-separated (via literal:// language)', + example: 'link(soa, "soa://tags", "literal://string:architecture,distributed,resilience")', + agentNotes: 'Optional. Use for cross-cutting concerns that don\'t fit the tree structure. Enables flat queries across the SoA graph.', + }, + + 'priority': { + name: 'Priority', + kind: 'property', + description: 'Priority level from 1 (highest) to 5 (lowest). Most useful for intentions and plans.', + valueType: 'number 1-5 (via literal:// language)', + example: 'link(soa, "soa://priority", "literal://number:1")', + agentNotes: 'Optional. Only meaningful for actionable SoAs (intentions, plans). A priority-1 intention should be worked on before priority-3.', + }, + + 'source': { + name: 'Source', + kind: 'property', + description: 'Source of evidence or origin of this State of Affairs. Could be a URL, document reference, person, or description of how it was learned.', + valueType: 'string (via literal:// language)', + example: 'link(soa, "soa://source", "literal://string:https://arxiv.org/abs/...")', + agentNotes: 'Optional. Crucial for provenance tracking. When an AI agent creates a SoA from external information, always set the source so humans can verify.', + }, + + // ── Relationships ─────────────────────────────────────────── + + 'rel_supports': { + name: 'Supports', + kind: 'relationship', + description: 'Source provides evidence, argument, or backing for target. The source SoA makes the target SoA more likely or justified.', + example: 'link(evidence_soa, "soa://rel_supports", claim_soa)', + agentNotes: 'Directional: A supports B means A is evidence FOR B. Multiple SoAs can support the same target, building a body of evidence. Combined with rel_contradicts, enables argument mapping.', + }, + + 'rel_contradicts': { + name: 'Contradicts', + kind: 'relationship', + description: 'Source provides evidence or argument against target. The source SoA undermines, challenges, or refutes the target SoA.', + example: 'link(counter_evidence, "soa://rel_contradicts", claim_soa)', + agentNotes: 'Directional: A contradicts B means A is evidence AGAINST B. Use with confidence scores to build nuanced worldviews — a belief with high-confidence contradictions should lower its own confidence.', + }, + + 'rel_similar': { + name: 'Similar', + kind: 'relationship', + description: 'Source and target are related but not identical propositions. They share themes, domains, or implications.', + example: 'link(soa_A, "soa://rel_similar", soa_B)', + agentNotes: 'Symmetric in meaning (if A is similar to B, B is similar to A), though the link itself is directional. Use for clustering related ideas. NOT the same as rel_same.', + }, + + 'rel_same': { + name: 'Same', + kind: 'relationship', + description: 'Source and target express the same proposition, possibly worded differently or from different perspectives. Semantic equivalence.', + example: 'link(soa_A, "soa://rel_same", soa_B)', + agentNotes: 'Use for deduplication and cross-referencing when the same insight appears in different contexts. If two agents independently arrive at the same SoA, linking them with rel_same enables collective intelligence without merging.', + }, + + 'rel_requires': { + name: 'Requires', + kind: 'relationship', + description: 'Target depends on source — target cannot be true/achieved without source. Logical or practical prerequisite.', + example: 'link(prerequisite_soa, "soa://rel_requires", dependent_soa)', + agentNotes: 'Directional: A requires B means B is needed for A. Useful for planning — find all unmet requirements by traversing rel_requires to SoAs with status != "completed". Forms a dependency graph.', + }, + + 'rel_enables': { + name: 'Enables', + kind: 'relationship', + description: 'Source creates conditions or capability for target. Softer than requires — source helps but isn\'t strictly necessary.', + example: 'link(capability_soa, "soa://rel_enables", goal_soa)', + agentNotes: 'Directional: A enables B means A makes B possible or easier. The inverse of blocks. Use for mapping how capabilities connect to goals.', + }, + + 'rel_parent': { + name: 'Parent', + kind: 'relationship', + description: 'Tree structure: source is the parent of target. Creates hierarchical organization of States of Affairs into trees.', + example: 'link(parent_soa, "soa://rel_parent", child_soa)', + agentNotes: 'This is the primary structural relationship for SoA trees. A vision breaks down into intentions, which break down into plans. Each SoA should have at most one parent (tree, not DAG). Root SoAs with no parent are top-level worldview anchors.', + }, + + 'rel_refines': { + name: 'Refines', + kind: 'relationship', + description: 'Source is a more specific, detailed, or updated version of target. Tracks epistemic evolution.', + example: 'link(refined_soa, "soa://rel_refines", original_soa)', + agentNotes: 'Directional: A refines B means A is a better version of B. Use when updating beliefs — create a new SoA, link it with rel_refines to the old one, and set the old one\'s status to "revised". This preserves history while showing current thinking.', + }, + + 'rel_blocks': { + name: 'Blocks', + kind: 'relationship', + description: 'Source prevents, inhibits, or blocks target. The source SoA is an obstacle to the target SoA.', + example: 'link(blocker_soa, "soa://rel_blocks", blocked_soa)', + agentNotes: 'Directional: A blocks B means A is an obstacle to B. The inverse of enables. Particularly useful for intentions with status "blocked" — the blocking SoA explains why. Resolving the blocker should unblock the target.', + }, +}; diff --git a/soa/language/src/index.ts b/soa/language/src/index.ts new file mode 100644 index 000000000..7064e8703 --- /dev/null +++ b/soa/language/src/index.ts @@ -0,0 +1,75 @@ +import type { + Address, + Language, + LanguageContext, + Interaction, + ExpressionUI, +} from "https://esm.sh/v135/@perspect3vism/ad4m@0.5.0"; +import SoAExpressionAdapter from "./adapter.ts"; + +function iconFor(_expression: Address): string { + return ""; +} + +function constructorIcon(): string { + return ""; +} + +function interactions(_expression: Address): Interaction[] { + return []; +} + +export class UI implements ExpressionUI { + icon(): string { + return ""; + } + + constructorIcon(): string { + return ""; + } +} + +//!@ad4m-template-variable +export const name = "soa-language"; + +/** + * SoA Language — a static, self-documenting vocabulary for + * State of Affairs ontology. + * + * This language defines the semantic predicates used in SoA trees: + * - Properties: title, modality, description, confidence, status, tags, priority, source + * - Relationships: rel_supports, rel_contradicts, rel_similar, rel_same, + * rel_requires, rel_enables, rel_parent, rel_refines, rel_blocks + * + * Every soa:// expression resolves to structured documentation + * that helps AI agents and humans understand the ontology. + * + * This is a ReadOnlyLanguage — no new expressions can be created. + * The vocabulary is fixed and versioned with AD4M. + * + * Pattern: This serves as an example for how AD4M languages can + * act as self-documenting semantic vocabularies. Any domain can + * create a similar language to define its own predicates. + */ +export default async function create( + context: LanguageContext +): Promise { + const expressionAdapter = new SoAExpressionAdapter(context); + const expressionUI = new UI(); + + // All expressions are immutable (static documentation) + const isImmutableExpression = (_expression: Address): boolean => { + return true; + }; + + const language = { + name, + expressionAdapter, + expressionUI, + iconFor, + constructorIcon, + isImmutableExpression, + interactions, + } satisfies Language; + return language; +} diff --git a/soa/package.json b/soa/package.json new file mode 100644 index 000000000..4ed6b71a0 --- /dev/null +++ b/soa/package.json @@ -0,0 +1,33 @@ +{ + "name": "@coasys/soa", + "version": "0.1.0", + "description": "State of Affairs ontology for AD4M — universal knowledge representation as trees and graphs", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "default": "./dist/index.js" + } + }, + "scripts": { + "build": "tsc" + }, + "files": [ + "dist/", + "src/" + ], + "keywords": [ + "ad4m", + "state-of-affairs", + "ontology", + "knowledge-graph", + "eve", + "collective-intelligence" + ], + "author": "Coasys", + "license": "CAL-1.0", + "peerDependencies": { + "@coasys/ad4m": ">=0.11.0" + } +} diff --git a/soa/src/StateOfAffair.ts b/soa/src/StateOfAffair.ts new file mode 100644 index 000000000..0923a7457 --- /dev/null +++ b/soa/src/StateOfAffair.ts @@ -0,0 +1,135 @@ +import { ModelOptions, Ad4mModel, Property } from '@coasys/ad4m'; + +/** + * Modality of a State of Affairs — its epistemic status. + * + * - belief: SoA we hold as true + * - observation: SoA we have directly verified + * - intention: SoA we want to make true (goal) + * - vision: High-level desired future state + * - plan: Steps connecting current SoA to intended SoA + * - skill: SoA about a capability an agent possesses + */ +export type SoAModality = 'belief' | 'observation' | 'intention' | 'vision' | 'plan' | 'skill'; + +/** + * StateOfAffair — the fundamental unit of knowledge representation. + * + * A proposition about how things are, could be, or should be. + * Forms the nodes of State of Affairs trees, which represent + * an agent's worldview, goals, plans, and capabilities. + * + * Used by both humans and AI agents in the Eve architecture. + * Same schema works for personal memory, shared task boards, + * and collective intelligence networks. + * + * Note: author and timestamp come from the link expressions + * themselves — every AD4M link carries this metadata natively. + * A SoA can have multiple authors (when created independently + * by different agents). + * + * Relationships between SoA nodes are expressed as AD4M links + * using the soa language for predicates: + * link(soaA, "soa://rel_supports", soaB) + * link(soaA, "soa://rel_contradicts", soaB) + * link(soaA, "soa://rel_similar", soaB) + * link(soaA, "soa://rel_same", soaB) + * link(soaA, "soa://rel_requires", soaB) + * link(soaA, "soa://rel_enables", soaB) + * link(soaA, "soa://rel_parent", soaB) // soaA is parent of soaB + * link(soaA, "soa://rel_refines", soaB) + * link(soaA, "soa://rel_blocks", soaB) + */ +@ModelOptions({ name: 'StateOfAffair' }) +export default class StateOfAffair extends Ad4mModel { + /** + * Short summary of this state of affairs. + */ + @Property({ + through: 'soa://title', + resolveLanguage: 'literal', + writable: true, + required: true, + }) + title: string; + + /** + * Epistemic modality: belief, observation, intention, vision, plan, skill. + */ + @Property({ + through: 'soa://modality', + resolveLanguage: 'literal', + writable: true, + required: true, + }) + modality: SoAModality; + + /** + * Longer description or body text. + */ + @Property({ + through: 'soa://description', + resolveLanguage: 'literal', + writable: true, + }) + description?: string; + + /** + * Confidence level (0.0 to 1.0). + * For beliefs: how certain we are. + * For intentions: how committed we are. + * For observations: reliability of the observation. + */ + @Property({ + through: 'soa://confidence', + resolveLanguage: 'literal', + writable: true, + }) + confidence?: number; + + /** + * Current status of this SoA. + * For intentions/plans: 'active' | 'completed' | 'abandoned' | 'blocked' + * For beliefs: 'held' | 'revised' | 'retracted' + * For observations: 'current' | 'outdated' + */ + @Property({ + through: 'soa://status', + resolveLanguage: 'literal', + writable: true, + }) + status?: string; + + /** + * Optional tags for categorization and search. + * Stored as comma-separated values. + */ + @Property({ + through: 'soa://tags', + resolveLanguage: 'literal', + writable: true, + }) + tags?: string; + + /** + * Optional priority level (1-5, where 1 is highest). + * Primarily useful for intentions and plans. + */ + @Property({ + through: 'soa://priority', + resolveLanguage: 'literal', + writable: true, + }) + priority?: number; + + /** + * Source or evidence for this SoA. + * Could be a URL, file path, or description. + */ + @Property({ + through: 'soa://source', + resolveLanguage: 'literal', + writable: true, + }) + source?: string; +} diff --git a/soa/src/index.ts b/soa/src/index.ts new file mode 100644 index 000000000..0483b74b9 --- /dev/null +++ b/soa/src/index.ts @@ -0,0 +1,36 @@ +export { default as StateOfAffair } from './StateOfAffair'; +export type { SoAModality } from './StateOfAffair'; + +/** + * SoA Relationship Predicates + * + * Relationships between StateOfAffair nodes are expressed as + * standard AD4M links using these soa language expressions + * as predicates. No separate Relationship model needed — + * the link expression itself carries author and timestamp. + * + * Usage: + * perspective.addLink({ source: soaA, predicate: SoA.REL_SUPPORTS, target: soaB }) + */ +export const SoA = { + /** Evidence or argument for */ + REL_SUPPORTS: 'soa://rel_supports', + /** Evidence or argument against */ + REL_CONTRADICTS: 'soa://rel_contradicts', + /** Related but not identical */ + REL_SIMILAR: 'soa://rel_similar', + /** Equivalent propositions */ + REL_SAME: 'soa://rel_same', + /** Dependency: target requires source */ + REL_REQUIRES: 'soa://rel_requires', + /** Capability: source enables target */ + REL_ENABLES: 'soa://rel_enables', + /** Tree structure: source is parent of target */ + REL_PARENT: 'soa://rel_parent', + /** Source is a more specific version of target */ + REL_REFINES: 'soa://rel_refines', + /** Source prevents/blocks target */ + REL_BLOCKS: 'soa://rel_blocks', +} as const; + +export type SoARelationshipType = typeof SoA[keyof typeof SoA]; diff --git a/soa/tsconfig.json b/soa/tsconfig.json new file mode 100644 index 000000000..1af16e941 --- /dev/null +++ b/soa/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "ESNext", + "moduleResolution": "node", + "lib": ["ES2020"], + "outDir": "./dist", + "rootDir": "./src", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "declaration": true, + "declarationMap": true, + "sourceMap": true + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist"] +}