@cynodia/axiom 0.11.2-alpha.1 → 0.12.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/README.md +3 -2
- package/docs/ACTIONS_TRANSACTIONS.md +1 -1
- package/docs/AGENT_API.md +1 -1
- package/docs/AGENT_REFERENCE.md +71 -1
- package/docs/ANTI_PATTERNS.md +128 -1
- package/docs/AUTHORITY.md +1 -1
- package/docs/CONSTRAINTS.md +1 -1
- package/docs/DISTRIBUTED_AUTHORITY.md +370 -0
- package/docs/EFFECTS.md +1 -1
- package/docs/EVENTS.md +1 -1
- package/docs/EXPRESSIONS.md +1 -1
- package/docs/GRAPH_MODEL.md +1 -1
- package/docs/INTEGRATIONS.md +1 -1
- package/docs/LOCATIONS.md +1 -1
- package/docs/MIGRATIONS.md +1 -1
- package/docs/PRESENTATION.md +1 -1
- package/docs/QUERIES.md +1 -1
- package/docs/RUNTIME.md +1 -1
- package/docs/SEMANTIC_CONTRACT.md +1 -1
- package/docs/STATE.md +1 -1
- package/docs/STORAGE.md +1 -1
- package/docs/SUBSCRIPTIONS.md +1 -1
- package/docs/TRIGGERS.md +1 -1
- package/docs/UI.md +1 -1
- package/docs/VALIDATION.md +1 -1
- package/llms.txt +1 -1
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -33,7 +33,7 @@ Shorter forms of the same routing: [`AGENTS.md`](AGENTS.md) and [`llms.txt`](llm
|
|
|
33
33
|
at this package's root.
|
|
34
34
|
|
|
35
35
|
**Status: experimental / alpha.** The API may change between alpha releases. The
|
|
36
|
-
documentation in `docs/` describes this exact version, `0.
|
|
36
|
+
documentation in `docs/` describes this exact version, `0.12.0-alpha.1`.
|
|
37
37
|
|
|
38
38
|
## Installation
|
|
39
39
|
|
|
@@ -47,7 +47,7 @@ Every release of this project is a pre-release and npm's `latest` tag points at
|
|
|
47
47
|
plain command above installs the current version. **There is no `alpha` dist-tag** — the tag
|
|
48
48
|
was removed once it stopped tracking releases, and `npm install @cynodia/axiom@alpha` now
|
|
49
49
|
fails with a 404. Pin the exact version instead when one is needed:
|
|
50
|
-
`npm install @cynodia/axiom@0.
|
|
50
|
+
`npm install @cynodia/axiom@0.12.0-alpha.1`.
|
|
51
51
|
|
|
52
52
|
These are ES modules compiled to ES2022; import them with `import`, not `require`. There is
|
|
53
53
|
no published Axiom CLI. `@cynodia/axiom-server`'s SQLite persistence adapter additionally
|
|
@@ -191,6 +191,7 @@ focused document when the reference is not specific enough for the question at h
|
|
|
191
191
|
| Binary data: `BlobRef`, upload, download, authorization, orphans | [`docs/STORAGE.md`](docs/STORAGE.md) |
|
|
192
192
|
| Large authoritative datasets: `QueryDef`, relationships, read policy, providers, cursors, cache | [`docs/QUERIES.md`](docs/QUERIES.md) |
|
|
193
193
|
| Evolving a deployed schema: `MigrationDef`, fingerprint, the startup gate, `executeMigration`, providers | [`docs/MIGRATIONS.md`](docs/MIGRATIONS.md) |
|
|
194
|
+
| Running N authority processes at once: ownership, leases, fencing, delivery guarantees, version skew | [`docs/DISTRIBUTED_AUTHORITY.md`](docs/DISTRIBUTED_AUTHORITY.md) |
|
|
194
195
|
| Machine queries, mutation impact and graph transformations | [`docs/AGENT_API.md`](docs/AGENT_API.md) |
|
|
195
196
|
|
|
196
197
|
`docs/AGENT_REFERENCE.md` plus the `.d.ts` declarations are intended to be sufficient on
|
package/docs/AGENT_API.md
CHANGED
package/docs/AGENT_REFERENCE.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Agent reference
|
|
2
2
|
|
|
3
|
-
Axiom 0.
|
|
3
|
+
Axiom 0.12.0-alpha.1. Compressed operational contract. Read this plus the `.d.ts`
|
|
4
4
|
declarations before authoring or modifying an Axiom application.
|
|
5
5
|
|
|
6
6
|
Formal guarantees: [`SEMANTIC_CONTRACT.md`](SEMANTIC_CONTRACT.md). Mistakes that compile:
|
|
@@ -964,6 +964,76 @@ Diagnostics: `SCHEMA_MIGRATION_REQUIRED` `SCHEMA_INCOMPATIBLE` `MIGRATION_IN_PRO
|
|
|
964
964
|
`MIGRATION_DESTRUCTIVE_UNMARKED` `INVALID_MIGRATION_OPERATION` `MIGRATION_TRANSFORM_IMPURE`
|
|
965
965
|
`MIGRATION_TRANSFORM_TYPE_MISMATCH`.
|
|
966
966
|
|
|
967
|
+
## DISTRIBUTED AUTHORITY
|
|
968
|
+
|
|
969
|
+
Full model: [`DISTRIBUTED_AUTHORITY.md`](DISTRIBUTED_AUTHORITY.md).
|
|
970
|
+
|
|
971
|
+
The authoritative runtime may run as **N processes at once** over one shared persistence
|
|
972
|
+
provider, with **no graph change and no application code that knows a cluster exists**. One
|
|
973
|
+
authority and N authorities produce the same committed state and the same framework-owned
|
|
974
|
+
async work. Deployment topology is not application semantics.
|
|
975
|
+
|
|
976
|
+
Quick answers:
|
|
977
|
+
|
|
978
|
+
| Question | Answer |
|
|
979
|
+
| --- | --- |
|
|
980
|
+
| Do I write locking code? | **No.** Never an application lock, never `SETNX` in a `native` op. |
|
|
981
|
+
| Do I need Redis? | **No.** `memory` and `SQLite` reference providers ship; 0.12 semantics use no provider's vocabulary. |
|
|
982
|
+
| Are external effects generically exactly-once? | **No.** Exactly-once *logical* creation and *durable completion*; at-least-once *physical* execution unless the provider is idempotent. |
|
|
983
|
+
| Can multiple authorities race work safely? | **Yes**, with a capable `coordination` provider — activated automatically, no flag. |
|
|
984
|
+
| Can a stale owner commit after losing ownership? | **No.** Every durable-work write is fenced on a per-resource generation; a reclaim advances it. |
|
|
985
|
+
| Is deployment topology graph semantics? | **No.** No node kind, operation or IR field is added; a distributed graph compiles byte-identically. |
|
|
986
|
+
|
|
987
|
+
`createAxiomServer({ coordination, workStorage, distributed: { instanceId, leaseDurationMs,
|
|
988
|
+
renewIntervalMs, workerConcurrency, claimBatchSize, pollIntervalMs } })` — an unsafe combo
|
|
989
|
+
(`renewIntervalMs >= leaseDurationMs`) **throws**. `server.authority()` →
|
|
990
|
+
`{ instanceId, distributed, coordination: capabilities|null, config, compatibilityKey }`;
|
|
991
|
+
`server.inspectDistributedWork()` → live effect work items + incompatible items.
|
|
992
|
+
|
|
993
|
+
Every framework-owned async unit — outbox effect, scheduled firing, subscription cursor — is
|
|
994
|
+
a leased, fenced, per-item ownership claim: `pending → claimed(ownerId, generation) →
|
|
995
|
+
succeeded/failed/retry`. Lease expiry authorises nothing; only a reclaim (which mints a
|
|
996
|
+
higher generation) fences the prior owner (`WORK_FENCED`). `logicalEffectId` (= the effect
|
|
997
|
+
intent id) never changes across retries; `idempotencyKey` defaults to it (§7 of the full
|
|
998
|
+
doc). Retry backoff is durable, not a process timer. An attempt whose outcome was never
|
|
999
|
+
recorded increments `uncertainAttempts` and is retried with the same key — Axiom never
|
|
1000
|
+
claims physical exactly-once.
|
|
1001
|
+
|
|
1002
|
+
Scheduled `interval` / `delay` firings are gated on a fenced claim keyed by
|
|
1003
|
+
`"<scheduleId>@<dueInstant>"` (epoch-aligned for intervals; the constant `afterMs` for a
|
|
1004
|
+
delay), so N pollers cause one firing. Missed firings: `catchUp` = `latest` (default) / `all`
|
|
1005
|
+
/ N, always caught up by one authority.
|
|
1006
|
+
|
|
1007
|
+
External event ingestion deduplicates on `source + externalEventId` (durable payload
|
|
1008
|
+
fingerprint): `accepted` / `duplicate` / `EVENT_ID_CONFLICT` (same id, different payload) /
|
|
1009
|
+
`unidentified` (no stable id → at-least-once). An id is **never synthesised** from a
|
|
1010
|
+
timestamp, an instance id or a UUID.
|
|
1011
|
+
|
|
1012
|
+
Subscription cursors: per-subscription monotonic `sequence` (no cross-subscription order),
|
|
1013
|
+
fenced + monotonic advancement (`fenced` / `stale-sequence`), reconnect from the durable
|
|
1014
|
+
cursor through any authority.
|
|
1015
|
+
|
|
1016
|
+
Cache coherence: durable revision observation — each entry records `observedRevision`,
|
|
1017
|
+
re-checked against `persistence.revision()` before every authoritative read → staleness
|
|
1018
|
+
bound **0** revisions; correctness does not depend on broadcast. `CACHE_COHERENCE` states it.
|
|
1019
|
+
|
|
1020
|
+
Version skew: the **compatibility key** is `{ schemaVersion, schemaFingerprint,
|
|
1021
|
+
serverContract, semanticFingerprint }`, compared **fail-closed**. `semanticFingerprint`
|
|
1022
|
+
(core, versioned) hashes executable meaning — action bodies, operations, triggers, policies,
|
|
1023
|
+
queries, expression defs — and excludes names / UI / routes / themes / metadata / order;
|
|
1024
|
+
distinct from `schemaFingerprint`. Durable work is stamped with its creator's key; an
|
|
1025
|
+
authority whose key differs refuses to claim it (`INCOMPATIBLE_AUTHORITY`). Migration
|
|
1026
|
+
ownership stays 0.11 host-controlled — no second coordination system.
|
|
1027
|
+
|
|
1028
|
+
Providers advertise capabilities (`distributed-lease`, `fencing`, `atomic-work-claim`,
|
|
1029
|
+
`durable-retry`, `event-dedup`, `durable-subscription-cursor`, `revision-observation`); a
|
|
1030
|
+
missing one **fails explicitly**, never a silent single-node fallback. Portable
|
|
1031
|
+
`axiom.conformance.v6` fixtures (`conformance/distributed/`) + `runCoordinationConformanceSuite`.
|
|
1032
|
+
Server IR stays `axiom.server.v7`.
|
|
1033
|
+
|
|
1034
|
+
Diagnostics: `WORK_IN_PROGRESS` `WORK_FENCED` `WORK_NOT_CLAIMABLE` `INCOMPATIBLE_AUTHORITY`
|
|
1035
|
+
`EVENT_ID_CONFLICT`.
|
|
1036
|
+
|
|
967
1037
|
## Metadata classes
|
|
968
1038
|
|
|
969
1039
|
```ts
|
package/docs/ANTI_PATTERNS.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Anti-patterns
|
|
2
2
|
|
|
3
|
-
Axiom 0.
|
|
3
|
+
Axiom 0.12.0-alpha.1. Each of these compiles. Each is wrong. Each is followed by the correct
|
|
4
4
|
alternative.
|
|
5
5
|
|
|
6
6
|
## 1. Field names as entity runtime keys
|
|
@@ -682,3 +682,130 @@ The stored version, fingerprint and step history are written only by the migrati
|
|
|
682
682
|
executor, atomically with the work they describe. Hand-editing them produces
|
|
683
683
|
`MIGRATION_FINGERPRINT_MISMATCH` or `MIGRATION_STATE_CORRUPTED` at startup — the gate's
|
|
684
684
|
whole purpose is to catch exactly this.
|
|
685
|
+
|
|
686
|
+
## 52. An application-written distributed lock (or `SETNX` in a `native` operation)
|
|
687
|
+
|
|
688
|
+
```ts
|
|
689
|
+
// WRONG — the graph now encodes a deployment fact, and a second lock system exists.
|
|
690
|
+
{ kind: 'native', name: 'acquireRedisLock', arguments: { key: literal('reboot:dev-1') } }
|
|
691
|
+
```
|
|
692
|
+
|
|
693
|
+
Multi-authority safety is the framework's job, not the application's. `createAxiomServer` is
|
|
694
|
+
given a `coordination` provider and every class of framework-owned async work is leased and
|
|
695
|
+
fenced automatically. There is no `native` operation for locking and there will not be one;
|
|
696
|
+
`SETNX` / `Redlock` / a Postgres advisory lock are provider techniques that never appear in
|
|
697
|
+
a graph. See [`DISTRIBUTED_AUTHORITY.md`](DISTRIBUTED_AUTHORITY.md).
|
|
698
|
+
|
|
699
|
+
## 53. A process-local "already executed" `Set` as deduplication
|
|
700
|
+
|
|
701
|
+
```ts
|
|
702
|
+
// WRONG — resets on restart, and authority B has never heard of it.
|
|
703
|
+
const done = new Set<string>();
|
|
704
|
+
if (done.has(effectId)) return;
|
|
705
|
+
done.add(effectId);
|
|
706
|
+
```
|
|
707
|
+
|
|
708
|
+
Deduplication for an authoritative server must be durable and shared. The outbox keys the
|
|
709
|
+
logical effect by its committed intent id and claims it with a fenced lease; external event
|
|
710
|
+
ingestion deduplicates on `source + externalEventId` against a durable payload fingerprint.
|
|
711
|
+
An in-memory set is neither durable nor cross-authority.
|
|
712
|
+
|
|
713
|
+
## 54. `leader`-only application branches
|
|
714
|
+
|
|
715
|
+
```ts
|
|
716
|
+
// WRONG — "am I the leader?" is not a question the graph may ask.
|
|
717
|
+
conditional(call('isLeaderInstance'), doTheWork, doNothing)
|
|
718
|
+
```
|
|
719
|
+
|
|
720
|
+
Axiom is leaderless: ownership is per work item, and any healthy compatible authority may
|
|
721
|
+
claim any item. There is no leader for an application to branch on. If work should happen
|
|
722
|
+
once, model it as framework-owned async work (an effect, a trigger) and let the claim make
|
|
723
|
+
it once.
|
|
724
|
+
|
|
725
|
+
## 55. A random UUID (or timestamp, or instance id) as an external-event dedup key
|
|
726
|
+
|
|
727
|
+
```ts
|
|
728
|
+
// WRONG — every "duplicate" gets a fresh id, so nothing is ever deduplicated.
|
|
729
|
+
fireEvent(EVENT_STATUS, { ...payload, dedupKey: crypto.randomUUID() })
|
|
730
|
+
```
|
|
731
|
+
|
|
732
|
+
Deduplication needs the *provider's* stable delivery id. If the source has no stable id,
|
|
733
|
+
ingestion is honestly at-least-once (`unidentified`) — synthesising uniqueness from a
|
|
734
|
+
receive timestamp, a random UUID or the authority instance id is not deduplication, it just
|
|
735
|
+
hides the fact that duplicates get through.
|
|
736
|
+
|
|
737
|
+
## 56. A retry that creates a new logical effect
|
|
738
|
+
|
|
739
|
+
```ts
|
|
740
|
+
// WRONG — every attempt is a new effect, so the external system is hit N times with N keys.
|
|
741
|
+
async function retry(effect) {
|
|
742
|
+
await outbox.enqueue({ ...effect, id: createNodeId() });
|
|
743
|
+
}
|
|
744
|
+
```
|
|
745
|
+
|
|
746
|
+
`logicalEffectId` is the committed intent id and is stable for the life of the effect. A
|
|
747
|
+
retry re-claims the *same* work item under a new fencing generation and re-runs the physical
|
|
748
|
+
attempt with the *same* idempotency key. A new id defeats provider idempotency entirely.
|
|
749
|
+
|
|
750
|
+
## 57. A completion write that is not conditional on the fencing generation
|
|
751
|
+
|
|
752
|
+
```ts
|
|
753
|
+
// WRONG — a stalled owner that wakes after a reclaim overwrites the new owner's result.
|
|
754
|
+
await store.markComplete(effectId, result);
|
|
755
|
+
```
|
|
756
|
+
|
|
757
|
+
Every durable-work completion / retry / cursor write must be conditional on the current
|
|
758
|
+
`(ownerId, generation)`. Lease expiry alone does not fence — but once another authority
|
|
759
|
+
reclaims (advancing the generation), the old owner's write must be rejected (`WORK_FENCED`).
|
|
760
|
+
Unconditional completion is a release-blocking defect.
|
|
761
|
+
|
|
762
|
+
## 58. Assuming a global order across unrelated entities or events
|
|
763
|
+
|
|
764
|
+
```ts
|
|
765
|
+
// WRONG — there is no total order to observe.
|
|
766
|
+
assert(eventA.sequence < eventB.sequence); // eventA and eventB from different subscriptions
|
|
767
|
+
```
|
|
768
|
+
|
|
769
|
+
Ordering is **per semantic stream** only: monotonic `sequence` within one subscription.
|
|
770
|
+
There is no ordering across subscriptions, and none between a subscription and any other
|
|
771
|
+
event source. Code that depends on a global order is depending on an accident of which
|
|
772
|
+
authority happened to process what first.
|
|
773
|
+
|
|
774
|
+
## 59. Relying on pub/sub delivery for cache correctness
|
|
775
|
+
|
|
776
|
+
```ts
|
|
777
|
+
// WRONG — a dropped invalidation message leaves this authority serving stale data forever.
|
|
778
|
+
bus.on('invalidate', (key) => cache.delete(key));
|
|
779
|
+
// ...and nothing else checks freshness.
|
|
780
|
+
```
|
|
781
|
+
|
|
782
|
+
Cache coherence is a *durable revision* mechanism, not a broadcast: each cache entry records
|
|
783
|
+
the store revision it was computed at, and every authoritative read re-checks the persisted
|
|
784
|
+
revision before serving. A broadcast invalidation is a latency optimisation; correctness
|
|
785
|
+
must survive it being lost entirely.
|
|
786
|
+
|
|
787
|
+
## 60. Swallowing an uncertain external effect outcome
|
|
788
|
+
|
|
789
|
+
```ts
|
|
790
|
+
// WRONG — "we didn't see a success, so it didn't happen" — then a non-idempotent retry.
|
|
791
|
+
if (!recordedSuccess) await chargeCardAgain(amount);
|
|
792
|
+
```
|
|
793
|
+
|
|
794
|
+
If an authority sent the request and crashed before recording completion, Axiom cannot know
|
|
795
|
+
whether the effect happened. The contract is: retry per the delivery policy **reusing the
|
|
796
|
+
same idempotency key**, and mark the attempt uncertain (`uncertainAttempts`). Never assume
|
|
797
|
+
not-done, and never claim the physical side effect is exactly-once — with a non-idempotent
|
|
798
|
+
provider it may occur twice, and that must be visible, not hidden.
|
|
799
|
+
|
|
800
|
+
## 61. Executing durable work under an incompatible build
|
|
801
|
+
|
|
802
|
+
```ts
|
|
803
|
+
// WRONG — authority B, running an older graph, claims and runs work authority A queued.
|
|
804
|
+
await workStore.claim('effect', { ignoreCompatibilityKey: true });
|
|
805
|
+
```
|
|
806
|
+
|
|
807
|
+
Durable work records the **compatibility key** of the build that created it —
|
|
808
|
+
`{ schemaVersion, schemaFingerprint, serverContract, semanticFingerprint }`. An authority
|
|
809
|
+
whose key differs refuses to claim it (`INCOMPATIBLE_AUTHORITY`); the item waits for a
|
|
810
|
+
compatible authority. A rolling deploy that lets an old build run new-schema work is exactly
|
|
811
|
+
the mixed-semantic execution the fail-closed check exists to prevent.
|
package/docs/AUTHORITY.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Authority
|
|
2
2
|
|
|
3
|
-
Axiom 0.
|
|
3
|
+
Axiom 0.12.0-alpha.1. How an application crosses the trust boundary.
|
|
4
4
|
|
|
5
5
|
Until 0.5.x an Axiom application executed locally. 0.6 adds an **authority**: a generic
|
|
6
6
|
runtime that owns state, decides mutations and persists them. The same semantic graph
|
package/docs/CONSTRAINTS.md
CHANGED
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
# Distributed authority
|
|
2
|
+
|
|
3
|
+
*This document describes Axiom `0.12.0-alpha.1`.*
|
|
4
|
+
|
|
5
|
+
The authoritative runtime (`docs/AUTHORITY.md`) may run as **more than one process at the
|
|
6
|
+
same time**, over one shared persistence provider, without any change to the
|
|
7
|
+
`ApplicationGraph` and without any application code that knows a cluster exists. This is the
|
|
8
|
+
0.12 "distributed authority" layer.
|
|
9
|
+
|
|
10
|
+
The whole of it is one sentence:
|
|
11
|
+
|
|
12
|
+
> **One authority instance and N authority instances produce the same committed state and
|
|
13
|
+
> the same framework-owned asynchronous work.** Deployment topology is not application
|
|
14
|
+
> semantics.
|
|
15
|
+
|
|
16
|
+
`docs/AGENT_REFERENCE.md` has the compressed Q&A. This is the full contract.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## 1. Topology transparency
|
|
21
|
+
|
|
22
|
+
An application is a graph. Running it on one process or on eight is an operational choice,
|
|
23
|
+
made entirely outside the graph. There is:
|
|
24
|
+
|
|
25
|
+
- no cluster-mode toggle an application calls, no `distributed: true` in the graph, no
|
|
26
|
+
leader election an application can observe;
|
|
27
|
+
- no node kind, operation, expression kind or Server IR field added by 0.12 — a distributed
|
|
28
|
+
graph compiles to the exact same `axiom.server.vN` document a single-authority one does;
|
|
29
|
+
- no `NativeOperation` for locking, and none will be added.
|
|
30
|
+
|
|
31
|
+
Distributed execution **activates automatically** when `createAxiomServer` is given a
|
|
32
|
+
`coordination` provider together with a durable `persistence` adapter. Given neither, the
|
|
33
|
+
authority runs exactly as it did before — single writer, in-process outbox.
|
|
34
|
+
|
|
35
|
+
## 2. Ownership
|
|
36
|
+
|
|
37
|
+
Every unit of **framework-owned asynchronous work** — a transactional-outbox effect, a
|
|
38
|
+
scheduled trigger firing, a subscription delivery cursor — is executed by **exactly one
|
|
39
|
+
authority at a time** through a durable, leased, fenced, per-work-item ownership claim:
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
work item
|
|
43
|
+
↓ created once by a committed transaction
|
|
44
|
+
durable "pending" state
|
|
45
|
+
↓ an authority acquires a lease
|
|
46
|
+
"claimed" by (ownerId, generation)
|
|
47
|
+
↓ the authority performs one physical attempt
|
|
48
|
+
durable "completion" / "retry" state (written only while the claim is still current)
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Ownership is **exclusive, leased, recoverable, observable, bounded in time and crash-safe**.
|
|
52
|
+
There is no global leader; any healthy, compatible authority may reclaim an expired claim.
|
|
53
|
+
A process crash never permanently owns work.
|
|
54
|
+
|
|
55
|
+
## 3. Leases
|
|
56
|
+
|
|
57
|
+
A lease is portable plain data:
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
Lease { resourceId, ownerId, token, generation, acquiredAt, expiresAt }
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Operations: `acquire`, `renew`, `release`, `inspect`, `checkOwnership`, `list`.
|
|
64
|
+
|
|
65
|
+
- `acquire` succeeds when the resource is unclaimed or the current lease window has closed.
|
|
66
|
+
It never grants while a live lease is held — an owner that wants to keep working calls
|
|
67
|
+
`renew`.
|
|
68
|
+
- `renew` and `release` are **owner-specific**: they require the opaque per-acquisition
|
|
69
|
+
`token`, so they are safe even between two claims by the same `ownerId`.
|
|
70
|
+
- Lease timing uses the wall clock of whichever authority (or the coordination provider)
|
|
71
|
+
performs the operation. A safe renew cadence — `renewIntervalMs <= leaseDurationMs / 2`,
|
|
72
|
+
enforced by config validation — tolerates one lost renewal and bounded clock skew. Axiom
|
|
73
|
+
does **not** attempt distributed clock synchronisation; a deployment with unbounded skew
|
|
74
|
+
across authority hosts is unsupported and must be rejected operationally.
|
|
75
|
+
|
|
76
|
+
## 4. Fencing
|
|
77
|
+
|
|
78
|
+
**Lease expiry authorises nothing.** It only makes a claim reclaimable. The stale-owner
|
|
79
|
+
problem —
|
|
80
|
+
|
|
81
|
+
```
|
|
82
|
+
A owns the work → A pauses → A's lease expires → B acquires → A wakes up → A keeps writing
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
— is solved by a **fencing generation**: a strictly-increasing, per-resource, crash-durable
|
|
86
|
+
integer minted on every acquisition. Every durable-work mutation carries the generation it
|
|
87
|
+
was claimed under. A mutation whose generation is not the current one is **rejected**
|
|
88
|
+
(`WORK_FENCED`). A stale authority can never commit a semantic completion after ownership
|
|
89
|
+
has moved.
|
|
90
|
+
|
|
91
|
+
A lease that merely expired without anyone reclaiming it does **not** fence its owner: if B
|
|
92
|
+
never took over, A's own completion still applies. Only a reclaim advances the generation.
|
|
93
|
+
|
|
94
|
+
## 5. Logical effect vs physical attempt
|
|
95
|
+
|
|
96
|
+
```
|
|
97
|
+
LogicalEffect — the semantic work a committed transaction created. Stable identity.
|
|
98
|
+
EffectAttempt — one physical attempt to perform it. Numbered; may repeat.
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
`logicalEffectId` is the committed effect-intent id and **never changes across retries**. A
|
|
102
|
+
retry never creates a second logical effect. `attemptNumber` counts physical attempts;
|
|
103
|
+
`ownerGeneration` is the fencing generation of the current attempt.
|
|
104
|
+
|
|
105
|
+
## 6. Delivery guarantees
|
|
106
|
+
|
|
107
|
+
The contract is precise, documented and machine-inspectable — not "exactly-once", which is
|
|
108
|
+
impossible for a generic external side effect:
|
|
109
|
+
|
|
110
|
+
| Layer | Guarantee |
|
|
111
|
+
| --- | --- |
|
|
112
|
+
| Logical effect creation | **exactly-once** — one committed transaction, one logical effect; idempotent enqueue collapses duplicates. |
|
|
113
|
+
| Physical execution | **at-least-once**, unless the external provider is idempotent. The Axiom-supplied idempotency key (`= logicalEffectId`, see §7) is what lets an idempotent provider collapse retries to one side effect. |
|
|
114
|
+
| Durable Axiom completion transition | **exactly-once** — fenced; only the current owner's generation moves the item to `succeeded` / `failed`, so the declared success/failure event fires once. |
|
|
115
|
+
|
|
116
|
+
A follow-up: dispatching that declared event after the completion commit is at-most-once
|
|
117
|
+
across a crash in the sub-window between the two — unchanged from single-authority 0.8+,
|
|
118
|
+
where the event dispatch was always post-commit and non-durable.
|
|
119
|
+
|
|
120
|
+
## 7. Effect idempotency
|
|
121
|
+
|
|
122
|
+
An external effect provider *should* accept an Axiom-supplied stable idempotency key. Axiom
|
|
123
|
+
supplies `effect.idempotencyKey = logicalEffectId` whenever the graph declares none; an
|
|
124
|
+
author-declared key (a payment reference, say) is preserved. The application never invents a
|
|
125
|
+
distributed execution id. An adapter maps the key to an HTTP `Idempotency-Key`, a
|
|
126
|
+
payment-provider idempotency key, a message-deduplication id, and so on.
|
|
127
|
+
|
|
128
|
+
## 8. Effect claiming, retry and uncertain outcomes
|
|
129
|
+
|
|
130
|
+
Multiple authorities may race to claim a pending effect. Exactly one wins the active attempt
|
|
131
|
+
generation; the others observe it as unavailable (`WORK_IN_PROGRESS`) and move on. If the
|
|
132
|
+
owner crashes, its lease expires and another authority claims a **new** generation and
|
|
133
|
+
retries.
|
|
134
|
+
|
|
135
|
+
Retry state is **durable** (`attemptNumber`, last-attempt time, `nextEligibleAt` backoff
|
|
136
|
+
floor, last failure classification, completion state). The backoff floor lives in the store,
|
|
137
|
+
never in a process-local timer — a restart or failover resumes it. The graph-owned retry
|
|
138
|
+
policy (`maxAttempts`, backoff shape, `retryable`) is honoured exactly; infrastructure only
|
|
139
|
+
chooses poll cadence, claim batch size and lease-renew interval.
|
|
140
|
+
|
|
141
|
+
**Uncertain external effect outcome (important).** Suppose an authority sends the external
|
|
142
|
+
request, the external system processes it, and the authority crashes *before* recording
|
|
143
|
+
completion. Axiom cannot generally know whether the effect happened. Required behaviour:
|
|
144
|
+
retry according to the delivery contract, reusing the **same** idempotency key —
|
|
145
|
+
`uncertainAttempts` on the durable work item is incremented so the reclaim is observably a
|
|
146
|
+
retry-after-uncertainty. Axiom never pretends this collapses to a physical exactly-once
|
|
147
|
+
side effect; with a non-idempotent provider the effect may happen twice.
|
|
148
|
+
|
|
149
|
+
## 9. Crash recovery
|
|
150
|
+
|
|
151
|
+
For a crash at **every** ownership boundary the recovery is defined:
|
|
152
|
+
|
|
153
|
+
| Crash point | Durable state after | Reclaimable | Duplication boundary | Stale owner if it resumes |
|
|
154
|
+
| --- | --- | --- | --- | --- |
|
|
155
|
+
| before claim | pending | yes (claimable) | excluded | n/a |
|
|
156
|
+
| during claim | pending / claimed(dead gen) | after lease expiry | excluded | fenced |
|
|
157
|
+
| after claim, before work | claimed | after lease expiry | excluded (no effect ran) | fenced |
|
|
158
|
+
| during work / after physical effect, before completion | claimed | after lease expiry | **at-least-once** | fenced |
|
|
159
|
+
| before completion commit | claimed | after lease expiry | excluded (no partial completion) | fenced |
|
|
160
|
+
| after completion commit, before release | succeeded / failed (durable) | no (terminal) | excluded | `already-terminal` |
|
|
161
|
+
| during lease renewal | claimed | after lease expiry | excluded | fenced |
|
|
162
|
+
| after lease expiry, before anyone reclaims | claimed | yes | excluded | **self-recovers** — expiry alone does not fence |
|
|
163
|
+
|
|
164
|
+
Durable work has no sub-attempt checkpoint: the unit of progress is the whole attempt.
|
|
165
|
+
|
|
166
|
+
## 10. Scheduling
|
|
167
|
+
|
|
168
|
+
A scheduled trigger (`interval` / `delay`) fires on a host timer, and every authority runs
|
|
169
|
+
its own timers. Each **logical firing** is a durable work item with a derived, stable id:
|
|
170
|
+
|
|
171
|
+
```
|
|
172
|
+
workId = "<scheduleId>@<dueInstant>"
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
`dueInstant` is a wall-clock millisecond every authority derives identically — an `interval`
|
|
176
|
+
boundary is epoch-aligned to a multiple of `everyMs`; a `delay` fires once, so its instant
|
|
177
|
+
is the constant `afterMs`. Because the id is derived, not minted, two authorities observing
|
|
178
|
+
the same due schedule converge on **one** firing. Exactly one authority claims it (fenced);
|
|
179
|
+
a crash permits reclaim of *the same* firing id — no second firing identity is ever created.
|
|
180
|
+
|
|
181
|
+
Missed firings (an outage): a `catchUp` policy (`latest` (default), `all`, or a number)
|
|
182
|
+
decides how many elapsed boundaries are enqueued. Whichever it is, the claim lease
|
|
183
|
+
guarantees each missed firing is caught up by **one** authority, never N. Catch-up state
|
|
184
|
+
vocabulary: `due`, `late`, `currently-owned`, `expired-owner`, `already-fired`,
|
|
185
|
+
`terminally-completed`.
|
|
186
|
+
|
|
187
|
+
## 11. Event deduplication
|
|
188
|
+
|
|
189
|
+
When more than one authority can receive the same external delivery **and the provider
|
|
190
|
+
contract says it carries a stable id**, ingestion deduplicates on `source + externalEventId`
|
|
191
|
+
against a durable record of a payload fingerprint (a canonical-JSON SHA-256):
|
|
192
|
+
|
|
193
|
+
| Input | Outcome |
|
|
194
|
+
| --- | --- |
|
|
195
|
+
| first `(source, externalEventId)` | `accepted` — dispatch one semantic event |
|
|
196
|
+
| same, byte-equal payload | `duplicate` — dispatch nothing |
|
|
197
|
+
| same id, different payload | **`EVENT_ID_CONFLICT`** — never a silent second event |
|
|
198
|
+
| no `externalEventId` | `unidentified` — at-least-once ingestion, dedup impossible |
|
|
199
|
+
|
|
200
|
+
A stable id is **never synthesised** from a receive timestamp, an authority instance id or a
|
|
201
|
+
random UUID. The window per source is bounded; an id that has fallen out of the window is
|
|
202
|
+
treated as new (bounded, not exactly-once).
|
|
203
|
+
|
|
204
|
+
## 12. Subscriptions
|
|
205
|
+
|
|
206
|
+
A `SubscriptionDef` separates three things: the semantic subscription (durable), the
|
|
207
|
+
physical client connection (belongs to whichever authority the client reached, may drop),
|
|
208
|
+
and the **delivery cursor** (durable, owned by exactly one authority at a time via a fenced
|
|
209
|
+
lease).
|
|
210
|
+
|
|
211
|
+
- **Ordering** is per subscription only: `sequence` is monotonic within one subscription.
|
|
212
|
+
There is deliberately **no** ordering across subscriptions or against any other event
|
|
213
|
+
source. `subscriptionOrderingGuarantee()` states this machine-readably.
|
|
214
|
+
- **Cursor advancement is fenced and monotonic**: a write carries the generation its owner
|
|
215
|
+
was claimed under; a lower-generation write is rejected (`fenced`), a lower-sequence write
|
|
216
|
+
is rejected (`stale-sequence`). A stalled owner that resumes after takeover can never move
|
|
217
|
+
the cursor.
|
|
218
|
+
- **Reconnect** follows the durable cursor, not process memory: a new authority `acquire`s
|
|
219
|
+
ownership and is handed the durable position to resume from. Reconnect does not depend on
|
|
220
|
+
reaching the same authority instance.
|
|
221
|
+
- Delivery is **at-least-once**; duplicate delivery is possible.
|
|
222
|
+
|
|
223
|
+
## 13. Cache coherence
|
|
224
|
+
|
|
225
|
+
A cached authoritative read must never be served stale indefinitely because *another*
|
|
226
|
+
authority committed. The correctness mechanism is **durable revision observation**, not
|
|
227
|
+
broadcast:
|
|
228
|
+
|
|
229
|
+
- persistence exposes a monotonic store `revision` that every committed transaction advances
|
|
230
|
+
(on any authority);
|
|
231
|
+
- each cache entry records the `observedRevision` it was computed at;
|
|
232
|
+
- before serving a cached authoritative read, the authority re-observes the persisted
|
|
233
|
+
revision; a behind entry is dropped and the result recomputed.
|
|
234
|
+
|
|
235
|
+
Because the check happens on every authoritative read and any commit advances the revision,
|
|
236
|
+
the **staleness bound is zero revisions** — a read after a committed write, on any
|
|
237
|
+
authority, never observes the pre-write state. A local broadcast invalidation (an authority
|
|
238
|
+
clearing its own cache on its own commit) is a latency optimisation only; a dropped
|
|
239
|
+
notification changes nothing about correctness.
|
|
240
|
+
|
|
241
|
+
`CACHE_COHERENCE` = `{ mechanism: 'durable-revision-observation', stalenessBoundRevisions:
|
|
242
|
+
0, requiresBroadcast: false, checkPerRead: true }`.
|
|
243
|
+
|
|
244
|
+
## 14. Version skew
|
|
245
|
+
|
|
246
|
+
Two authorities with different application builds may temporarily coexist during a rolling
|
|
247
|
+
deploy. Axiom **fails closed** when semantic compatibility cannot be established.
|
|
248
|
+
|
|
249
|
+
An authority's **compatibility key** is four fields:
|
|
250
|
+
|
|
251
|
+
```
|
|
252
|
+
{ schemaVersion, schemaFingerprint, serverContract, semanticFingerprint }
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
- `schemaVersion` / `schemaFingerprint` — the 0.11 persistence-relevant identity. A schema
|
|
256
|
+
mismatch is already fatal per 0.11 migration safety.
|
|
257
|
+
- `serverContract` — the Server IR contract the document declares.
|
|
258
|
+
- `semanticFingerprint` — a **new**, versioned, deterministic hash over the *executable
|
|
259
|
+
server-side meaning*: action bodies, guards and operations, integration operation
|
|
260
|
+
definitions, triggers, events, subscription policy, read-policy predicates, query
|
|
261
|
+
semantics, expression definitions, constraints. It **excludes** everything a rename
|
|
262
|
+
touches — names, descriptions, labels, free-form metadata, all UI / routes / themes /
|
|
263
|
+
presentation, and declaration order. It is distinct from `schemaFingerprint`, which
|
|
264
|
+
deliberately excludes executable meaning: two graphs whose actions do entirely different
|
|
265
|
+
things but store the same shapes have the same `schemaFingerprint` and different
|
|
266
|
+
`semanticFingerprint`s.
|
|
267
|
+
|
|
268
|
+
Durable work records the compatibility key of the build that created it. An authority whose
|
|
269
|
+
key differs **refuses to claim** that work (`INCOMPATIBLE_AUTHORITY` / the item is simply
|
|
270
|
+
not claimed and stays visible as incompatible). A compatible authority runs it. During a
|
|
271
|
+
schema migration, incompatible workers stop claiming new work, ordinary serving is refused
|
|
272
|
+
per 0.11, the migration completes, and compatible new authorities resume — migration
|
|
273
|
+
ownership stays host-controlled and separate from ordinary distributed-work ownership; there
|
|
274
|
+
is no second migration coordination system.
|
|
275
|
+
|
|
276
|
+
`AgentAPI.inspectDistributedSemantics()` exposes the compatibility key and, per work class,
|
|
277
|
+
the guarantee, the provider capability it needs, and where the live runtime state is —
|
|
278
|
+
keeping the semantic guarantee, the runtime state, the provider capability and the
|
|
279
|
+
operational tuning separate.
|
|
280
|
+
|
|
281
|
+
## 15. Provider capabilities
|
|
282
|
+
|
|
283
|
+
A `CoordinationProvider` advertises capabilities:
|
|
284
|
+
|
|
285
|
+
```
|
|
286
|
+
distributed-lease · fencing · atomic-work-claim · durable-retry ·
|
|
287
|
+
event-dedup · durable-subscription-cursor · revision-observation
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
A runtime that needs a capability the provider does not advertise **fails explicitly** with
|
|
291
|
+
a capability diagnostic. There is no silent single-node fallback and no "works as long as
|
|
292
|
+
only one server is running".
|
|
293
|
+
|
|
294
|
+
Two reference providers ship:
|
|
295
|
+
|
|
296
|
+
- **memory** — a full *semantic* reference: every fencing, reclaim and ownership rule holds,
|
|
297
|
+
deterministic with an injected clock and token source, able to simulate an N-authority
|
|
298
|
+
cluster in one process. `physicalDurability: false` — it does not survive across OS
|
|
299
|
+
processes.
|
|
300
|
+
- **SQLite** — the real cross-process reference: independent OS processes, independent
|
|
301
|
+
connections, one database file. `physicalDurability: true`. SQLite provides no independent
|
|
302
|
+
server clock (§3); physical `SQLITE_BUSY` / `SQLITE_LOCKED` contention is absorbed and, if
|
|
303
|
+
sustained, surfaces as a typed contention error — never as a coordination outcome.
|
|
304
|
+
|
|
305
|
+
A future production provider may use PostgreSQL, Redis, DynamoDB, etc. 0.12 semantics are
|
|
306
|
+
**not** defined in any provider's terminology: `SETNX`, `Redlock`, "Redis TTL", "conditional
|
|
307
|
+
check failed" and the like are provider techniques, never Axiom vocabulary.
|
|
308
|
+
|
|
309
|
+
## 16. Failure semantics — release invariants
|
|
310
|
+
|
|
311
|
+
The following always hold, and each is covered by a real-OS-process test:
|
|
312
|
+
|
|
313
|
+
- Two authorities never validly own the same `(resourceId, generation)`.
|
|
314
|
+
- A stale owner cannot commit completion / retry / cursor state after the generation
|
|
315
|
+
advances.
|
|
316
|
+
- One logical schedule firing never becomes two because N authorities poll.
|
|
317
|
+
- A duplicate stable external event never becomes two semantic events; a same-id /
|
|
318
|
+
different-payload event is an explicit `EVENT_ID_CONFLICT`.
|
|
319
|
+
- An effect retry never creates a second `logicalEffectId`.
|
|
320
|
+
- A crash never permanently strands durable work; failover never loses committed work.
|
|
321
|
+
- An incompatible / older-build authority never executes new-schema work.
|
|
322
|
+
- Ordinary multi-authority operation needs no application SQL, locks or `NativeOperation`.
|
|
323
|
+
- Provider-native contention never leaks as a semantic result.
|
|
324
|
+
- The authoritative cache is never stale past the declared bound (one revision check).
|
|
325
|
+
- A subscription's stale owner never overwrites a newer cursor.
|
|
326
|
+
- Physical external-effect exactly-once is never claimed.
|
|
327
|
+
|
|
328
|
+
## 17. Host configuration
|
|
329
|
+
|
|
330
|
+
Infrastructure knobs, passed as `createAxiomServer({ distributed: { … } })`. None changes a
|
|
331
|
+
semantic guarantee.
|
|
332
|
+
|
|
333
|
+
| Knob | Meaning | Default |
|
|
334
|
+
| --- | --- | --- |
|
|
335
|
+
| `instanceId` | This authority's identity. | `host.uuid()` at startup |
|
|
336
|
+
| `leaseDurationMs` | Lease window; an unrenewed claim becomes reclaimable after this. | 30000 |
|
|
337
|
+
| `renewIntervalMs` | Renew cadence. MUST be `< leaseDurationMs`; `<= /2` recommended. | 10000 |
|
|
338
|
+
| `workerConcurrency` | Max in-flight durable work items per authority. | 4 |
|
|
339
|
+
| `claimBatchSize` | Max items claimed per poll. | 32 |
|
|
340
|
+
| `pollIntervalMs` | Durable-state re-observation cadence. | 1000 |
|
|
341
|
+
|
|
342
|
+
`createAxiomServer` **throws** on an unsafe combination (e.g. `renewIntervalMs >=
|
|
343
|
+
leaseDurationMs`) rather than start with probabilistically-unsafe fencing.
|
|
344
|
+
|
|
345
|
+
## 18. Conformance
|
|
346
|
+
|
|
347
|
+
The portable `axiom.conformance.v6` fixture tier (`packages/server/conformance/distributed/`)
|
|
348
|
+
covers lease acquisition, lease fencing, effect claiming, effect reclaim, effect completion,
|
|
349
|
+
schedule firing, schedule reclaim, event deduplication, subscription cursor fencing, cache
|
|
350
|
+
revision visibility and mixed-build refusal. Each fixture is a deterministic step list
|
|
351
|
+
against the memory reference providers with a fixed clock and token sequence; the public
|
|
352
|
+
`runCoordinationConformanceFixture` / `runCoordinationConformanceSuite` runner executes them.
|
|
353
|
+
Server IR stays `axiom.server.v7` — 0.12 adds no IR vocabulary.
|
|
354
|
+
|
|
355
|
+
## 19. Anti-patterns
|
|
356
|
+
|
|
357
|
+
See `docs/ANTI_PATTERNS.md` for the full list with fixes. In short, none of these belongs in
|
|
358
|
+
an application graph or in application code:
|
|
359
|
+
|
|
360
|
+
- an application-written distributed lock, or Redis `SETNX` in a `native` operation;
|
|
361
|
+
- a process-local "already executed" `Set` used as deduplication;
|
|
362
|
+
- `leader`-only application branches;
|
|
363
|
+
- a random UUID (or a timestamp, or an instance id) used as an external-event dedup key;
|
|
364
|
+
- a retry that constructs a new logical effect id;
|
|
365
|
+
- a completion write that is not conditional on the current fencing generation;
|
|
366
|
+
- assuming a global order across unrelated entities or events;
|
|
367
|
+
- relying on pub/sub delivery for cache correctness;
|
|
368
|
+
- treating an uncertain external effect outcome as definitely-not-done;
|
|
369
|
+
- claiming physical exactly-once for a generic external side effect;
|
|
370
|
+
- executing durable work under a build whose compatibility key does not match.
|
package/docs/EFFECTS.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Effects
|
|
2
2
|
|
|
3
|
-
Axiom 0.
|
|
3
|
+
Axiom 0.12.0-alpha.1. External effects are not rollback-capable state mutations. This file
|
|
4
4
|
is the delivery model; [`AUTHORITY.md`](AUTHORITY.md#external-effects) is the load-bearing
|
|
5
5
|
statement of why, and [`INTEGRATIONS.md`](INTEGRATIONS.md) is the operation vocabulary this
|
|
6
6
|
builds on.
|
package/docs/EVENTS.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Events
|
|
2
2
|
|
|
3
|
-
Axiom 0.
|
|
3
|
+
Axiom 0.12.0-alpha.1. An event is a typed fact — something that happened — never work
|
|
4
4
|
itself. [`AUTHORITY.md`](AUTHORITY.md#external-events) is the load-bearing statement;
|
|
5
5
|
this file is the vocabulary and the webhook delivery mechanism. A **subscription** is the
|
|
6
6
|
other way an external fact becomes an `EventDef` payload — see
|
package/docs/EXPRESSIONS.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Expressions
|
|
2
2
|
|
|
3
|
-
Axiom 0.
|
|
3
|
+
Axiom 0.12.0-alpha.1. An expression describes **what value is computed**. It is a tree of
|
|
4
4
|
plain data, never source text and never a callback. Evaluation is pure: an expression MUST
|
|
5
5
|
NOT change state.
|
|
6
6
|
|
package/docs/GRAPH_MODEL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Graph model
|
|
2
2
|
|
|
3
|
-
Axiom 0.
|
|
3
|
+
Axiom 0.12.0-alpha.1. The `ApplicationGraph` is the authoritative representation of an
|
|
4
4
|
application. Everything else — the IR, the page, the DOM — is derived from it and is never
|
|
5
5
|
edited.
|
|
6
6
|
|
package/docs/INTEGRATIONS.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Integrations
|
|
2
2
|
|
|
3
|
-
Axiom 0.
|
|
3
|
+
Axiom 0.12.0-alpha.1. How an application declares and calls an external system, without
|
|
4
4
|
embedding a transport, an SDK or a secret in the graph. The authority boundary this
|
|
5
5
|
depends on is [`AUTHORITY.md`](AUTHORITY.md#external-systems); this file is the vocabulary.
|
|
6
6
|
|
package/docs/LOCATIONS.md
CHANGED
package/docs/MIGRATIONS.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Schema evolution & semantic migrations
|
|
2
2
|
|
|
3
|
-
Axiom 0.
|
|
3
|
+
Axiom 0.12.0-alpha.1. The operational contract for evolving a deployed application's
|
|
4
4
|
semantic model and its persisted canonical data over time — adding a required field,
|
|
5
5
|
splitting one field into two, removing an obsolete one, migrating millions of
|
|
6
6
|
provider-backed rows — **without** an application-authored SQL migration, an ORM migration,
|
package/docs/PRESENTATION.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Presentation
|
|
2
2
|
|
|
3
|
-
Axiom 0.
|
|
3
|
+
Axiom 0.12.0-alpha.1. Presentation is **semantic UX intent**, expressed as data on a UI
|
|
4
4
|
node. It names roles, tokens and device classes. It never names a colour, a length, a media
|
|
5
5
|
query or a CSS property.
|
|
6
6
|
|
package/docs/QUERIES.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Semantic data access & the query layer
|
|
2
2
|
|
|
3
|
-
Axiom 0.
|
|
3
|
+
Axiom 0.12.0-alpha.1. The operational contract for demand-driven reads over authoritative
|
|
4
4
|
data that is too large to materialize as a `StateDef` — 500,000 orders, 5,000,000 order
|
|
5
5
|
lines, years of audit rows. `axiom.server.v6`.
|
|
6
6
|
|
package/docs/RUNTIME.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Semantic contract
|
|
2
2
|
|
|
3
|
-
Axiom 0.
|
|
3
|
+
Axiom 0.12.0-alpha.1. Runtime guarantees, stated formally. This file defines behavior; it
|
|
4
4
|
does not teach. Where this file and any specification in `../specs/` disagree, this file
|
|
5
5
|
describes the implementation and is authoritative.
|
|
6
6
|
|
package/docs/STATE.md
CHANGED
package/docs/STORAGE.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Storage and blobs
|
|
2
2
|
|
|
3
|
-
Axiom 0.
|
|
3
|
+
Axiom 0.12.0-alpha.1. How an application stores, references, serves and deletes binary data —
|
|
4
4
|
an attachment, a document, a photograph, a diagnostic log — with no filesystem path, no
|
|
5
5
|
upload route and no download route anywhere in it.
|
|
6
6
|
|
package/docs/SUBSCRIPTIONS.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Subscriptions
|
|
2
2
|
|
|
3
|
-
Axiom 0.
|
|
3
|
+
Axiom 0.12.0-alpha.1. How an application receives a stream of external events — an MQTT
|
|
4
4
|
topic, a WebSocket feed, a queue consumer, a filesystem watcher, a serial port — without a
|
|
5
5
|
client, a socket or a callback anywhere in the graph.
|
|
6
6
|
|
package/docs/TRIGGERS.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Triggers
|
|
2
2
|
|
|
3
|
-
Axiom 0.
|
|
3
|
+
Axiom 0.12.0-alpha.1. A `TriggerDef` says **when** an action should be invoked, without
|
|
4
4
|
embedding callback code. `docs/AUTHORITY.md`
|
|
5
5
|
[§ Triggers](AUTHORITY.md#triggers) is the load-bearing statement of the execution model;
|
|
6
6
|
this file is the vocabulary.
|
package/docs/UI.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# UI
|
|
2
2
|
|
|
3
|
-
Axiom 0.
|
|
3
|
+
Axiom 0.12.0-alpha.1. Eleven semantic UI node kinds describe **what exists and what it does**.
|
|
4
4
|
How it looks is [presentation](PRESENTATION.md).
|
|
5
5
|
|
|
6
6
|
All eleven share `UIBase`:
|
package/docs/VALIDATION.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Validation
|
|
2
2
|
|
|
3
|
-
Axiom 0.
|
|
3
|
+
Axiom 0.12.0-alpha.1. Validation is authoring-time structural checking. It is not the same
|
|
4
4
|
as runtime constraint evaluation — see [`CONSTRAINTS.md`](CONSTRAINTS.md) for the four
|
|
5
5
|
layers of correctness.
|
|
6
6
|
|
package/llms.txt
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Axiom
|
|
2
2
|
|
|
3
|
-
> AI-native semantic application framework, version 0.
|
|
3
|
+
> AI-native semantic application framework, version 0.12.0-alpha.1. An Axiom application is a
|
|
4
4
|
> typed semantic graph — state, behavior, constraints, UI structure, presentation and
|
|
5
5
|
> authority as structured data — executed by generic runtimes. The JavaScript, HTML and CSS
|
|
6
6
|
> that reach a browser are compiler output and are never authored or edited. The primary
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cynodia/axiom",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0-alpha.1",
|
|
4
4
|
"description": "AI-native semantic web application framework.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "AskTech AS",
|
|
@@ -34,10 +34,10 @@
|
|
|
34
34
|
}
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@cynodia/axiom-core": "0.
|
|
38
|
-
"@cynodia/axiom-runtime": "0.
|
|
39
|
-
"@cynodia/axiom-compiler": "0.
|
|
40
|
-
"@cynodia/axiom-agent-api": "0.
|
|
37
|
+
"@cynodia/axiom-core": "0.12.0-alpha.1",
|
|
38
|
+
"@cynodia/axiom-runtime": "0.12.0-alpha.1",
|
|
39
|
+
"@cynodia/axiom-compiler": "0.12.0-alpha.1",
|
|
40
|
+
"@cynodia/axiom-agent-api": "0.12.0-alpha.1"
|
|
41
41
|
},
|
|
42
42
|
"scripts": {
|
|
43
43
|
"build": "tsc -b tsconfig.json"
|