Skip to content

v1.2.0: Access groups, join cycles, and Trino

Choose a tag to compare

@ZmeiGorynych ZmeiGorynych released this 12 Oct 13:23
bd41f99

SLayer 1.2.0

A release about access control, messier real-world schemas, and one more Tier 1 database.

Per-caller model access. You can now tag models with access_tags and give each caller a filtered view of your store. A caller sees a model only if it is untagged or shares one of their tags. Models that read a hidden model are hidden as well, and so are memories that only mention hidden models. For that caller, a hidden model behaves exactly like one that does not exist.

Trino is Tier 1. Install it with pip install 'motley-slayer[trino]'. Date shifts, relative date ranges, week buckets and time spines now work on Trino, and the same fixes apply to Presto and Athena. Query timeouts and HTTPS logins on any port now work on Trino.

Schemas with foreign-key cycles ingest fully. A single FK cycle used to strip every join from the whole schema. Now every FK becomes a join. When two FKs point at the same table, ingestion names the joins after their columns, so you can query billing_address.city and shipping_address.city from orders.

Better join routing. When several join paths are possible, SLayer now picks the one with the fewest fan-out joins. A saved measure that joins back to your query's source model now works instead of failing with a round-trip error.

Also: Postgres uuid and jsonb columns ingest as text without warnings, and MCP query validation errors now name the actual problem instead of three unrelated ones.

Breaking: query-backed models no longer store backing_query_sql. Run a dry_run query to see the SQL. Saving a derived column or model filter whose path crosses an ambiguous join is now an error.

Additional technical details
  • Access control: wrap a backend with TagFilteredStorage(backend, tags={...}, bypass=False) and pass it as the engine's storage. Every reader (listing, search, inspect, root inference, the SQL facade catalog, validate_models) sees the filtered view. Writes by non-bypass callers merge onto the full stored model; a write that conflicts with hidden content raises HiddenContentConflictError, and only bypass callers may set or change access_tags (AccessTagsEditError). Saving a model that reads a more narrowly tagged model emits a narrowed_access warning, collected into MCP create_model / edit_model replies.
  • Storage backends: new StorageBackend.cache_identity(); the default graph_fingerprint() is now None (never reused). The YAML and SQLite backends compute exact fingerprints. The v15 migration drops backing_query_sql from stored models.
  • Joins: edit_model accepts remove.join_edges: [{target_model, name, join_pairs}] to remove one of several joins to the same target. Schema drift drops only the broken edge. Canonical paths in recommend_root_model, routing suggestions, the facade catalog and the OSI converter now use edge names. Ambiguous derived-column paths raise DerivedColumnAmbiguousError at save time.
  • MCP: the query argument's JSON schema changes from anyOf to oneOf (string = saved model name, object = query, array = stages).
  • cypher_filter now has a 10 s timeout and runs off the event loop.