@cynodia/axiom-agent-api 0.12.0-alpha.1 → 0.13.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/api.d.ts CHANGED
@@ -4,6 +4,7 @@ import { Transaction } from './transaction.js';
4
4
  import type { ChangeSet } from './changes.js';
5
5
  import type { MigrationImpact, SchemaInspection } from './migration.js';
6
6
  import type { DistributedSemanticsInspection } from './distributed.js';
7
+ import type { LiveQueryAnalysis } from './live-query.js';
7
8
  /**
8
9
  * The machine-facing interface to an application. Agents query semantics and apply
9
10
  * structural transformations; they never edit generated code.
@@ -42,5 +43,13 @@ export declare class AgentAPI extends PresentationQueries {
42
43
  * `inspectDistributedWork()`.
43
44
  */
44
45
  inspectDistributedSemantics(serverContract?: string): DistributedSemanticsInspection;
46
+ /**
47
+ * The live-query semantics of one `QueryDef` (spec13 §38, §148, §149): whether it can be
48
+ * observed live and how (incremental deltas, whole resets, or not at all), the conservative
49
+ * set of committed changes that invalidate it, its row identity field, and what a resume
50
+ * cursor is bound to. Static over the graph; live runtime state is
51
+ * `AxiomServer.inspectLiveQueries()`.
52
+ */
53
+ analyzeLiveQuery(queryId: string): LiveQueryAnalysis;
45
54
  }
46
55
  //# sourceMappingURL=api.d.ts.map
package/dist/api.js CHANGED
@@ -3,6 +3,7 @@ import { PresentationQueries } from './presentation-queries.js';
3
3
  import { Transaction } from './transaction.js';
4
4
  import { inspectSchema, migrationImpact } from './migration.js';
5
5
  import { inspectDistributedSemantics } from './distributed.js';
6
+ import { analyzeLiveQuery } from './live-query.js';
6
7
  /**
7
8
  * The machine-facing interface to an application. Agents query semantics and apply
8
9
  * structural transformations; they never edit generated code.
@@ -61,4 +62,14 @@ export class AgentAPI extends PresentationQueries {
61
62
  inspectDistributedSemantics(serverContract) {
62
63
  return inspectDistributedSemantics(this.graph, serverContract);
63
64
  }
65
+ /**
66
+ * The live-query semantics of one `QueryDef` (spec13 §38, §148, §149): whether it can be
67
+ * observed live and how (incremental deltas, whole resets, or not at all), the conservative
68
+ * set of committed changes that invalidate it, its row identity field, and what a resume
69
+ * cursor is bound to. Static over the graph; live runtime state is
70
+ * `AxiomServer.inspectLiveQueries()`.
71
+ */
72
+ analyzeLiveQuery(queryId) {
73
+ return analyzeLiveQuery(this.graph, queryId);
74
+ }
64
75
  }
@@ -37,11 +37,26 @@ export interface DistributedSemanticsInspection {
37
37
  note: string;
38
38
  };
39
39
  workClasses: DistributedWorkClassInfo[];
40
+ /**
41
+ * How a query result cache stays coherent across authorities (spec12 §32-§34).
42
+ */
40
43
  cacheCoherence: {
41
44
  mechanism: 'durable-revision-observation';
42
45
  stalenessBoundRevisions: 0;
43
46
  requiresBroadcast: false;
44
47
  };
48
+ /**
49
+ * How a running authority's in-memory `StateDef` view stays coherent with state another
50
+ * authority committed (spec12.1 §6-§9, §54). The in-memory view is an authority-local
51
+ * cache; the durable persistence revision is re-observed before every authoritative
52
+ * operation and the view is reloaded when behind.
53
+ */
54
+ stateCoherence: {
55
+ mechanism: 'durable-revision-observation';
56
+ stalenessBoundRevisions: 0;
57
+ requiresBroadcast: false;
58
+ refreshBeforeAuthoritativeOperation: true;
59
+ };
45
60
  operationalTuning: string[];
46
61
  }
47
62
  /**
@@ -53,7 +53,7 @@ export function inspectDistributedSemantics(graph, serverContract = 'axiom.serve
53
53
  orderingScope: 'per-subscription',
54
54
  delivery: { guarantee: 'at-least-once', duplicatesPossible: true },
55
55
  providerCapabilityRequired: ['distributed-lease', 'fencing', 'durable-subscription-cursor', 'event-dedup'],
56
- runtimeStateAvailableFrom: 'AxiomServer.subscriptionLog() + inspectDistributedWork().subscriptionCursors',
56
+ runtimeStateAvailableFrom: 'AxiomServer.subscriptionLog()',
57
57
  });
58
58
  }
59
59
  return {
@@ -73,6 +73,12 @@ export function inspectDistributedSemantics(graph, serverContract = 'axiom.serve
73
73
  stalenessBoundRevisions: 0,
74
74
  requiresBroadcast: false,
75
75
  },
76
+ stateCoherence: {
77
+ mechanism: 'durable-revision-observation',
78
+ stalenessBoundRevisions: 0,
79
+ requiresBroadcast: false,
80
+ refreshBeforeAuthoritativeOperation: true,
81
+ },
76
82
  operationalTuning: [
77
83
  'instanceId',
78
84
  'leaseDurationMs',
package/dist/index.d.ts CHANGED
@@ -2,6 +2,7 @@ export * from './changes.js';
2
2
  export * from './queries.js';
3
3
  export * from './migration.js';
4
4
  export * from './distributed.js';
5
+ export * from './live-query.js';
5
6
  export * from './presentation-queries.js';
6
7
  export * from './transaction.js';
7
8
  export * from './api.js';
package/dist/index.js CHANGED
@@ -2,6 +2,7 @@ export * from './changes.js';
2
2
  export * from './queries.js';
3
3
  export * from './migration.js';
4
4
  export * from './distributed.js';
5
+ export * from './live-query.js';
5
6
  export * from './presentation-queries.js';
6
7
  export * from './transaction.js';
7
8
  export * from './api.js';
@@ -0,0 +1,57 @@
1
+ import { type ApplicationGraph, type LiveCapability } from '@cynodia/axiom-core';
2
+ /**
3
+ * Static, graph-derivable live-query analysis (spec13 §38, §148, §149, §189 Q37/Q38).
4
+ *
5
+ * The AgentAPI works over an `ApplicationGraph`, not a running authority, so it answers the
6
+ * *semantic* questions — can this `QueryDef` be observed live, incrementally or only as whole
7
+ * resets, what committed changes invalidate it, and what a resume cursor is bound to — not
8
+ * the live runtime state (that is `AxiomServer.inspectLiveQueries()`).
9
+ *
10
+ * Nothing here names a transport. A live query is a persistent semantic observation of a
11
+ * canonical `QueryDef`; the runtime may poll and the provider may push, but the meaning is
12
+ * fixed by the graph (spec13 §195).
13
+ */
14
+ export interface LiveQueryAnalysis {
15
+ queryId: string;
16
+ /** `live-capable` (incremental), `live-capable-reset-only` (whole resets), or `not-live-capable`. */
17
+ capability: LiveCapability;
18
+ /** Ordered result — a sort-key change produces an explicit `move` (spec13 §16). */
19
+ ordered: boolean;
20
+ /** Aggregate / grouped — delivered only as `reset` (spec13 §14, §19). */
21
+ aggregate: boolean;
22
+ /** The row identity field the canonical delta model keys on, or `null` for a reset-only query. */
23
+ identityFieldId: string | null;
24
+ /**
25
+ * Conservative static invalidation set (spec13 §26-§31): a committed change to any of these
26
+ * entities or `StateDef`s may move the result. `broad` means the dependency is not
27
+ * statically enumerable, so every commit re-evaluates.
28
+ */
29
+ dependencies: {
30
+ entityIds: string[];
31
+ stateIds: string[];
32
+ broad: boolean;
33
+ /** The read policy AND-ed into every evaluation, if one governs the source entity. */
34
+ readPolicyId: string | null;
35
+ };
36
+ /**
37
+ * What a `axiom.live-query-cursor.v1` resume token is bound to — a mismatch on any of these
38
+ * is refused fail-closed on reconnect (spec13 §33-§35, §79-§81).
39
+ */
40
+ cursorBinding: string[];
41
+ /** The delivery contract, stated honestly (spec13 §33, §41, §85). */
42
+ delivery: {
43
+ guarantee: 'at-least-once-logical';
44
+ updateIdentity: 'subscriptionId + toRevision';
45
+ ordering: 'per-subscription-monotonic-by-revision';
46
+ revisionsMayBeCoalesced: true;
47
+ cursorAcknowledgement: 'server-sent-no-ack';
48
+ };
49
+ /** Present when `capability` is not `live-capable` — why, in one line. */
50
+ reason?: string;
51
+ }
52
+ /**
53
+ * Analyze one `QueryDef`'s live-query semantics. Pure over the graph. Throws if `queryId`
54
+ * does not name a `query` node.
55
+ */
56
+ export declare function analyzeLiveQuery(graph: ApplicationGraph, queryId: string): LiveQueryAnalysis;
57
+ //# sourceMappingURL=live-query.d.ts.map
@@ -0,0 +1,60 @@
1
+ import { queryDependencies, queryLiveCapability, readPolicyForEntity, } from '@cynodia/axiom-core';
2
+ /**
3
+ * Analyze one `QueryDef`'s live-query semantics. Pure over the graph. Throws if `queryId`
4
+ * does not name a `query` node.
5
+ */
6
+ export function analyzeLiveQuery(graph, queryId) {
7
+ const query = graph
8
+ .getNodesByKind('query')
9
+ .find((node) => String(node.id) === String(queryId));
10
+ if (!query) {
11
+ throw new Error(`analyzeLiveQuery: no query node "${queryId}"`);
12
+ }
13
+ const entities = graph.getNodesByKind('entity');
14
+ const relationships = graph.getNodesByKind('relationship');
15
+ const readPolicies = graph.getNodesByKind('read-policy');
16
+ const stateIds = new Set(graph.getNodesByKind('state').map((state) => String(state.id)));
17
+ const source = entities.find((entity) => String(entity.id) === String(query.source));
18
+ const sourceIdentityFieldId = source?.identityFieldId ? String(source.identityFieldId) : undefined;
19
+ // Mirror the authority's `policyForQuery`: an explicit `readPolicyId` wins, else the policy
20
+ // that governs the source entity.
21
+ const policy = query.readPolicyId
22
+ ? readPolicies.find((candidate) => String(candidate.id) === String(query.readPolicyId))
23
+ : readPolicyForEntity(readPolicies, query.source);
24
+ const capability = queryLiveCapability(query, sourceIdentityFieldId);
25
+ const aggregate = (query.aggregate?.length ?? 0) > 0 || (query.groupBy?.length ?? 0) > 0;
26
+ const ordered = (query.sort?.length ?? 0) > 0;
27
+ const deps = queryDependencies(query, policy, relationships, stateIds);
28
+ const analysis = {
29
+ queryId: String(query.id),
30
+ capability,
31
+ ordered,
32
+ aggregate,
33
+ identityFieldId: capability.capability === 'live-capable' && sourceIdentityFieldId ? sourceIdentityFieldId : null,
34
+ dependencies: {
35
+ entityIds: [...deps.entityIds].sort(),
36
+ stateIds: [...deps.stateIds].sort(),
37
+ broad: deps.broad,
38
+ readPolicyId: policy ? String(policy.id) : null,
39
+ },
40
+ cursorBinding: [
41
+ 'queryId',
42
+ 'argumentsFingerprint',
43
+ 'principalFingerprint',
44
+ 'policyFingerprint',
45
+ 'compatibilityFingerprint (serverContract + schemaFingerprint + semanticFingerprint)',
46
+ 'hmac-sha256 integrity signature',
47
+ ],
48
+ delivery: {
49
+ guarantee: 'at-least-once-logical',
50
+ updateIdentity: 'subscriptionId + toRevision',
51
+ ordering: 'per-subscription-monotonic-by-revision',
52
+ revisionsMayBeCoalesced: true,
53
+ cursorAcknowledgement: 'server-sent-no-ack',
54
+ },
55
+ };
56
+ if (capability.capability !== 'live-capable') {
57
+ analysis.reason = capability.reason;
58
+ }
59
+ return analysis;
60
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cynodia/axiom-agent-api",
3
- "version": "0.12.0-alpha.1",
3
+ "version": "0.13.0-alpha.1",
4
4
  "description": "Semantic queries and transactional graph transformations for AI agents.",
5
5
  "license": "MIT",
6
6
  "author": "AskTech AS",
@@ -31,7 +31,7 @@
31
31
  }
32
32
  },
33
33
  "dependencies": {
34
- "@cynodia/axiom-core": "0.12.0-alpha.1"
34
+ "@cynodia/axiom-core": "0.13.0-alpha.1"
35
35
  },
36
36
  "scripts": {
37
37
  "build": "tsc -b tsconfig.json tsconfig.test.json",