# AshArcadic v0.1.0 - Table of Contents

> Ash Framework DataLayer for ArcadeDB — native OpenCypher over the HTTP command API.

## Pages

- [AshArcadic](readme.md)
- [ash_arcadic usage rules](usage-rules.md)
- [Changelog](changelog.md)
- [Contributing to AshArcadic](contributing.md)
- [LICENSE](license.md)

- DSL Reference
  - [AshArcadic.DataLayer](dsl-asharcadic-datalayer.md)

## Modules

- [AshArcadic](AshArcadic.md): Ash Framework integration for [ArcadeDB](https://arcadedb.com).
- [AshArcadic.Aggregate](AshArcadic.Aggregate.md): Pure aggregate Cypher builder + decoder for AshArcadic. Builds ONE parameterized
statement per `Ash.Query.Aggregate` (each carries its own filter/field/uniq?/
include_nil?/default_value); RETURN uses SYNTHETIC aliases (`agg<i>`), never the
caller name (Rule 1). Value-reading aggregates over non-summable/non-orderable/
sensitive (`:binary`) storage fail closed value-free — a correctness guard mirroring
`{:sort, :binary}` AND a leak guard (a `min`/`list` over an encrypted-binary attr
would order-by / return ciphertext into the result; §6.4). A `list`/`first` requesting
`include_nil?: true` also fails closed value-free (ArcadeDB `collect` drops nulls; §6.5).
Empty sets — and value-reading sets with no non-null field values — decode to the
aggregate struct's own `.default_value` (spec §6.3).

- [AshArcadic.Cast](AshArcadic.Cast.md): Value serialization and flat-JSON-row decode for the ArcadeDB wire.
- [AshArcadic.Changes.CreateEdge](AshArcadic.Changes.CreateEdge.md): Ash change that persists a graph edge from the action's record to a destination
named by an argument, after the vertex write, inside the action's transaction.
- [AshArcadic.Changes.DestroyEdge](AshArcadic.Changes.DestroyEdge.md): Ash change that removes a graph edge from the action's record to a destination
named by an argument, after the vertex write, inside the action's transaction.
- [AshArcadic.Client](AshArcadic.Client.md): A host module that supplies the `Arcadic.Conn` a resource's data layer executes
through — the `repo` analog for `ash_postgres`/`ash_age`. The host owns
`base_url`, `auth`, transport, and pool; AshArcadic asks only for the handle.
- [AshArcadic.DataLayer](AshArcadic.DataLayer.md): Ash `DataLayer` for ArcadeDB — the "ash_postgres of ArcadeDB". Executes through
the tenant-blind `arcadic` transport. Exposes an `arcade do … end` resource
section and implements the `Ash.DataLayer` behaviour.
- [AshArcadic.DataLayer.Info](AshArcadic.DataLayer.Info.md): Introspection for the `arcade do … end` DSL section.
- [AshArcadic.DataLayer.Verifiers.ValidateEdge](AshArcadic.DataLayer.Verifiers.ValidateEdge.md): Build-blocking compile verifier: an `edge`'s `label` or any `properties` key that
is not a valid `Arcadic.Identifier` raises a `Spark.Error.DslError` (surfaced as a
compiler diagnostic under `--warnings-as-errors`). Edge labels are interpolated
into Cypher (`MERGE (a)-[e:LABEL]->(b)`) and property keys into `SET e.<key>`, so
both are validated at declaration time.

- [AshArcadic.DataLayer.Verifiers.ValidateMultitenancyAttr](AshArcadic.DataLayer.Verifiers.ValidateMultitenancyAttr.md): Compile-verifier for `:attribute` multitenancy. Two fail-open holes turned into
compile errors (AshArcadic has no `rls_guc`; those ash_age clauses are dropped —
ArcadeDB has no row-level security)
- [AshArcadic.DataLayer.Verifiers.ValidateRelationshipFk](AshArcadic.DataLayer.Verifiers.ValidateRelationshipFk.md): Compile-verifier (build-blocking under `--warnings-as-errors`): a relationship's LOCAL join
attribute must not be `sensitive`. A sensitive attribute is app-side-encrypted binary
(`ValidateSensitive` R2); an encrypted-binary FK cannot be `IN`-joined — Slice-5 relationship
loading builds `dest.<fk> IN [<plaintext pks>]`, so a sensitive join key silently breaks loading
and leaks via filter presence/absence. Fail closed, value-free (names the attribute atom only).
- [AshArcadic.DataLayer.Verifiers.ValidateSensitive](AshArcadic.DataLayer.Verifiers.ValidateSensitive.md): Compile-verifier for `arcade do sensitive [...] end` (build-blocking under
`--warnings-as-errors`)
- [AshArcadic.DataLayer.Verifiers.ValidateSkip](AshArcadic.DataLayer.Verifiers.ValidateSkip.md): Compile-verifier: a primary-key attribute must not appear in `arcade do skip [...] end`.
A skipped PK is never written as a property, so every update/destroy MATCH on the
full primary key matches zero rows (perpetual StaleRecord) and reads decode a nil PK.
- [AshArcadic.DataLayer.Verifiers.ValidateSparseVectorIndex](AshArcadic.DataLayer.Verifiers.ValidateSparseVectorIndex.md): Compile-verifier for `arcade do sparse_vector_index … end` (build-blocking under
`--warnings-as-errors`). A sparse index declares a `(tokens, weights)` attribute PAIR; BOTH
attributes must be
- [AshArcadic.DataLayer.Verifiers.ValidateVectorIndex](AshArcadic.DataLayer.Verifiers.ValidateVectorIndex.md): Compile-verifier for `arcade do vector_index … end` (build-blocking under
`--warnings-as-errors`). Each declared `vector_index` `name` must be
- [AshArcadic.Edge](AshArcadic.Edge.md): Edge configuration for an ArcadeDB relationship declared in an `arcade do … end`
block. The `%AshArcadic.Edge{}` struct is the target of the `edge` DSL entity;
`AshArcadic.Changes.{CreateEdge,DestroyEdge}` read it by `name`.
- [AshArcadic.Identifier](AshArcadic.Identifier.md): Identifier validation for values AshArcadic interpolates into Cypher or a
database name (labels, database names, sort/PK/attribute field names). The
allowlist is single-sourced in `Arcadic.Identifier` (letter-first, ≤128) — the
same guard the transport applies — so labels and DB names satisfy the URL-path
and statement rules by construction. Never interpolate a VALUE; values ride
`params`. A failure carries the invalid-SHAPE fact only, never the offending
string (AGENTS.md Rules 1 & 4).

- [AshArcadic.ManualRelationships.Traverse](AshArcadic.ManualRelationships.Traverse.md): Bounded variable-length graph traversal as an Ash manual relationship.
- [AshArcadic.Multitenancy](AshArcadic.Multitenancy.md): Resolves the ArcadeDB **database name** for a `:context`-multitenant resource +
tenant. The name reaches a URL path, so it must be a valid `Arcadic.Identifier`
(letter-first, ≤128 bytes), injective (distinct tenants → distinct databases — a
hard isolation invariant), and deterministic.
- [AshArcadic.Preparations.VectorSearch](AshArcadic.Preparations.VectorSearch.md): Read-action preparation that turns an Ash read into a vector search — **dense** kNN, **sparse**
(learned-sparse / BM25-style) kNN, or **hybrid** fusion (dense/sparse/full-text arms). Attach it
to a read action whose arguments carry the query data
- [AshArcadic.Query](AshArcadic.Query.md): Query structure for AshArcadic. Accumulates filters/sort/limit/offset; compiled
to Cypher by `to_cypher/1` (Plan 2). `client`/`database`/`label` come from the
resource's `arcade` DSL; `database` is overridden per-tenant by `set_tenant/3`
for `:context` resources (Plan 2).

- [AshArcadic.Query.Expression](AshArcadic.Query.Expression.md): Translates an Ash value-expression (an expression calculation's body, or a compound
operand of a filter/sort) into a parameterized Cypher SCALAR. Used by
`AshArcadic.Query.Filter` (WHERE operands) and the sort path (ORDER BY) — NOT the load
path (loaded calculations compute in Elixir, `AshArcadic.DataLayer.run_query`).
- [AshArcadic.Query.Filter](AshArcadic.Query.Filter.md): Translates an `Ash.Filter` expression into a parameterized Cypher `WHERE`
fragment. Only operators ArcadeDB can push down are emitted; anything else
returns `{:error, %UnsupportedFilter{}}` carrying operator/field only (never the
value — AGENTS.md Rule 4).
- [AshArcadic.Query.Write](AshArcadic.Query.Write.md): Builds the Cypher `SET` clause for a query-scoped bulk write (`update_query`) and for the
atomic surface of `create`/`upsert`, from an Ash changeset's atomic + static changes. Pure —
no transport.
- [AshArcadic.SparseVectorIndex](AshArcadic.SparseVectorIndex.md): Sparse (learned-sparse / BM25-style) vector-index configuration declared in an
`arcade do … end` block. The `%AshArcadic.SparseVectorIndex{}` struct is the target of the
`sparse_vector_index` DSL entity; it is **declaration only** — metadata the read path reads at
query time (the `Type[tokens,weights]` reference), plus compile-time validation
(`ValidateSparseVectorIndex`). AshArcadic does NOT create the index — the host app runs
`Arcadic.Vector.create_sparse_index/5` (there is no migration/DDL machinery here).
- [AshArcadic.TraversalAggregate](AshArcadic.TraversalAggregate.md): Post-authorization Elixir fold for traversal aggregates (Slice 4). Folds a source's
ALREADY-authorized, node-deduped, tenant-scoped, filtered, sorted destination records
(from `Traverse.load`'s Read B) into one aggregate value — never a DB-side aggregate
(which would count policy-denied nodes and double-count multi-path nodes for sum/avg).
- [AshArcadic.VectorIndex](AshArcadic.VectorIndex.md): Dense vector-index configuration declared in an `arcade do … end` block. The
`%AshArcadic.VectorIndex{}` struct is the target of the `vector_index` DSL entity;
it is **declaration only** — metadata the read path reads at query time (the
`Type[property]` reference, and `similarity` for `distance`/threshold semantics),
plus compile-time validation (`ValidateVectorIndex`). AshArcadic does NOT create
the index — the host app runs `Arcadic.Vector.create_dense_index/5` (there is no
migration/DDL machinery here, by the same precedent that leaves endpoint-PK indexes
to the host).

- Exceptions
  - [AshArcadic.Errors.CreateFailed](AshArcadic.Errors.CreateFailed.md): Error for failed create operations. Carries only resource + structural reason.
  - [AshArcadic.Errors.QueryFailed](AshArcadic.Errors.QueryFailed.md): Error for failed queries/reads/destroys. Carries only query label + structural reason.
  - [AshArcadic.Errors.UnsupportedFilter](AshArcadic.Errors.UnsupportedFilter.md): Error for a filter operation AshArcadic cannot push down to Cypher. Carries ONLY
the operator/function module and the referenced field name — the filtered value
is never captured, so neither the message nor a log line built from it leaks
PII/secrets (AGENTS.md Rule 4).

  - [AshArcadic.Errors.UpdateFailed](AshArcadic.Errors.UpdateFailed.md): Error for failed update operations. Carries only resource + structural reason.

