@graphit/cli 0.2.322 → 0.2.330
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/.claude-plugin/marketplace.json +3 -3
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/bin/graphit +1 -1
- package/bin/graphit.ps1 +1 -1
- package/dist/api/client.js +15 -0
- package/dist/api/client.js.map +1 -1
- package/dist/commands/ds-config.js +2 -2
- package/dist/commands/ds-config.js.map +1 -1
- package/dist/commands/ds.js +2 -2
- package/dist/commands/ds.js.map +1 -1
- package/dist/commands/kb.js +347 -15
- package/dist/commands/kb.js.map +1 -1
- package/dist/commands/query.js +7 -7
- package/dist/commands/query.js.map +1 -1
- package/dist/index.js +0 -8
- package/dist/index.js.map +1 -1
- package/dist/skill-guard.js +2 -1
- package/dist/skill-guard.js.map +1 -1
- package/package.json +1 -1
- package/scripts/verb-policy-source.json +31 -103
- package/skills/graphit/SKILL.md +32 -39
- package/skills/graphit/VERSION.json +1 -1
- package/skills/graphit/references/attached-docs.md +74 -0
- package/skills/graphit/references/data-source-refresh.md +38 -0
- package/skills/graphit/references/data-sources.md +39 -111
- package/skills/graphit/references/filters-advanced.md +2 -2
- package/skills/graphit/references/governance-explained.md +18 -29
- package/skills/graphit/references/governance.md +20 -83
- package/skills/graphit/references/kb-actions.md +28 -81
- package/skills/graphit/references/kb-discovery.md +35 -64
- package/skills/graphit/references/kb-scope.md +17 -15
- package/skills/graphit/references/kb-structure.md +28 -54
- package/skills/graphit/references/kb-traversal.md +24 -96
- package/skills/graphit/references/metric-families.md +19 -0
- package/skills/graphit/references/migration.md +2 -2
- package/skills/graphit/references/onboarding.md +5 -4
- package/skills/graphit/references/presentations.md +1 -1
- package/skills/graphit/references/runtime.md +6 -6
- package/skills/graphit/references/semantic-authoring.md +81 -0
- package/skills/graphit/references/sql-reference.md +19 -20
- package/dist/commands/kb-constraints.d.ts +0 -14
- package/dist/commands/kb-constraints.js +0 -53
- package/dist/commands/kb-constraints.js.map +0 -1
- package/dist/commands/kb-create.d.ts +0 -2
- package/dist/commands/kb-create.js +0 -296
- package/dist/commands/kb-create.js.map +0 -1
- package/dist/commands/kb-delete.d.ts +0 -2
- package/dist/commands/kb-delete.js +0 -37
- package/dist/commands/kb-delete.js.map +0 -1
- package/dist/commands/kb-read.d.ts +0 -2
- package/dist/commands/kb-read.js +0 -223
- package/dist/commands/kb-read.js.map +0 -1
- package/dist/commands/kb-shared.d.ts +0 -43
- package/dist/commands/kb-shared.js +0 -81
- package/dist/commands/kb-shared.js.map +0 -1
- package/dist/commands/kb-update.d.ts +0 -2
- package/dist/commands/kb-update.js +0 -240
- package/dist/commands/kb-update.js.map +0 -1
- package/dist/commands/sl/index.d.ts +0 -2
- package/dist/commands/sl/index.js +0 -263
- package/dist/commands/sl/index.js.map +0 -1
- package/skills/graphit/references/parameterized-metrics.md +0 -77
|
@@ -1,100 +1,37 @@
|
|
|
1
1
|
# Query Governance
|
|
2
2
|
|
|
3
|
-
Load
|
|
3
|
+
Load when writing a governed query, explaining a refusal, or reporting provenance.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## References
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
| Reference | Meaning |
|
|
8
|
+
|---|---|
|
|
9
|
+
| `{{ Metric('revenue') }}` | Reusable metric |
|
|
10
|
+
| `{{ Dimension('order__channel') }}` | Qualified grouping/filter field |
|
|
11
|
+
| `{{ Measure('order_total') }}` | Graphit's model-owned measure extension |
|
|
8
12
|
|
|
9
|
-
|
|
13
|
+
Legacy token grammar is refused. Keep references inside complete executable SQL and canvas `data-graphit-sql`.
|
|
10
14
|
|
|
11
|
-
|
|
12
|
-
|--------|-----------|---------|
|
|
13
|
-
| `{{metric:NAME}}` | Metric calculation (aggregation) | `{{metric:CPI}}` |
|
|
14
|
-
| `{{metric:NAME(K=V)}}` | Parameterized metric | `{{metric:ARPU(DAY=7)}}` |
|
|
15
|
-
| `{{metric_raw:NAME}}` | Raw expression, no outer aggregate | `{{metric_raw:REVENUE}}` |
|
|
16
|
-
| `{{dim:NAME}}` | Dimension expression | `{{dim:INSTALL_MONTH}}` |
|
|
17
|
-
|
|
18
|
-
```bash
|
|
19
|
-
graphit query "SELECT {{dim:INSTALL_MONTH}}, {{metric:CPI}} AS cpi FROM MARKETING_UA_DS GROUP BY 1" --ds MARKETING_UA_DS --verbose
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
`--verbose` prints the expanded SQL and trust tier, so you can confirm the reference resolved before presenting the result.
|
|
23
|
-
|
|
24
|
-
## Parameterized metrics
|
|
25
|
-
|
|
26
|
-
Some metrics (for example ARPU, ROAS, RETENTION) carry required parameters and cannot resolve without a value. Run `graphit kb list metric` and read the `params` column for the names a metric requires, then supply them inline as `{{metric:ARPU(DAY=7)}}`. Pre-baked variants such as `ARPU_D7` or `ROAS_D30` have the value fixed and need none. Omitting a required parameter returns a clear error naming the exact syntax, so read `params` first.
|
|
15
|
+
The governed fragment path serves simple, ratio, and derived metrics. Cumulative, conversion, shifted, time-spine, and null-fill shapes are not yet supported. Use a supported decomposition or explicitly labeled free SQL.
|
|
27
16
|
|
|
28
17
|
## Trust tiers
|
|
29
18
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|------|---------|-------|
|
|
34
|
-
| `governed` | Query used `{{metric:X}}` / `{{dim:X}}` references | Teal dot |
|
|
35
|
-
| `verified` | Raw SQL whose expressions match KB definitions | Amber dot |
|
|
36
|
-
| `ad_hoc` | Inline formulas with no KB match | Gray dot |
|
|
37
|
-
|
|
38
|
-
Prefer the governed tier. The server may upgrade matching raw SQL to verified, but reach for references first so the result is governed by intent.
|
|
39
|
-
|
|
40
|
-
## The ad-hoc gate
|
|
41
|
-
|
|
42
|
-
This is the hard frontier - the rules below are what the QueryGateway does.
|
|
43
|
-
|
|
44
|
-
A query lands at the `ad_hoc` tier when it uses no `{{metric:NAME}}` / `{{dim:NAME}}` reference and its raw expressions match no KB definition. On the CLI (`graphit query`, cached `--ds` or `--warehouse`), **every** ad-hoc query must be justified - business measures (an aggregate or `GROUP BY`) and plain exploration alike (`SELECT *`, `COUNT(*)`, `DISTINCT` peeks). Governed and verified results are exempt.
|
|
45
|
-
|
|
46
|
-
- **EXPLORE access is a hard prerequisite for ad-hoc business measures.** If the user lacks EXPLORE access to any queried table scope, the server blocks that measure. An ad-hoc reason cannot bypass that denial.
|
|
47
|
-
- **Justification floor.** The ad-hoc query is withheld and asks for a justification. Preferred path first: rewrite with `{{metric:NAME}}` / `{{dim:NAME}}` references - genuinely search the KB (`graphit kb explore`, `graphit kb list metric`, `graphit kb list dimension`), and if the metric or dimension you need does not exist, CREATE it first. A filter's value list belongs in a `{{dim:NAME}}`, not a raw `SELECT DISTINCT` peek. Only if nothing fits and the user needs the raw run, pass `--adhoc-reason "<text>"` stating what you searched, what you found, and why it does not fit - pass it on the first call when you already know the query is ad-hoc. A trivial or empty reason is rejected server-side and recorded in the audit log, so it must be honest.
|
|
48
|
-
|
|
49
|
-
When the gate fires, do not narrate around it or pretend the query ran. Report truthfully: it was blocked or needs approval, name the governed rewrite, and let the user decide.
|
|
50
|
-
|
|
51
|
-
## Enforceable rules and overrides
|
|
52
|
-
|
|
53
|
-
Rules with typed constraints are enforced automatically, rewriting the SQL before it runs:
|
|
54
|
-
|
|
55
|
-
| Type | What it does |
|
|
56
|
-
|------|-------------|
|
|
57
|
-
| `required_where` | Injects a WHERE predicate |
|
|
58
|
-
| `forbidden_column` | NULLifies a column in SELECT |
|
|
59
|
-
| `value_restriction` | Restricts a column to allowed values |
|
|
60
|
-
| `required_filter` | Validates a column appears in WHERE |
|
|
61
|
-
| `required_aggregation` | Validates GROUP BY includes a column |
|
|
62
|
-
|
|
63
|
-
User-context variables (`${user.team_id}`, `${user.email}`) resolve server-side for row-level security. Override a rule only when the user explicitly asks; the server honors it only if the user holds EXPLORE on every queried scope. A rule that masks a column (a `forbidden_column` constraint) can never be overridden. Every override is logged. Pass several names to override more than one.
|
|
64
|
-
|
|
65
|
-
```bash
|
|
66
|
-
graphit query "SELECT * FROM EVENTS" --ds EVENTS --override-rules EXCLUDE_RETARGETING
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
## Conditionally-enforced rules
|
|
70
|
-
|
|
71
|
-
A rule's mode is Advisory (guidance), Always (every query), or **Conditional** - fires only when its plain-language body (the condition) holds for the query you wrote. No server classifier decides that; you do. Read a table's rules first (`graphit kb explore table <name>`), judge your query against each conditional rule's body, and declare it up front:
|
|
72
|
-
|
|
73
|
-
- `--apply-conditional RULE` - enforce it for this query.
|
|
74
|
-
- `--skip-conditional RULE:"reason"` - skip it; a reason is required and audit-logged.
|
|
75
|
-
|
|
76
|
-
Declare up front so a clean query never stalls. An undeclared conditional returns a retryable prompt naming each unresolved rule and its condition - read it, decide, re-run. A saved tile stores your decision and replays it every refresh.
|
|
77
|
-
|
|
78
|
-
## Data-source row caps
|
|
79
|
-
|
|
80
|
-
An admin can set a `max_rows` cap per data source. A cap limits the result set; it does not change authorization, trust-tier classification, or the ad-hoc justification floor.
|
|
19
|
+
- **governed:** verified semantic references compiled through the gateway.
|
|
20
|
+
- **verified:** known safe stored query without semantic references.
|
|
21
|
+
- **ad hoc:** raw SQL at the frontier.
|
|
81
22
|
|
|
82
|
-
|
|
23
|
+
Prefer governed. Never present ad-hoc SQL as the team's definition.
|
|
83
24
|
|
|
84
|
-
|
|
25
|
+
## Rules
|
|
85
26
|
|
|
86
|
-
|
|
27
|
+
Rules target model, entity, dimension, metric, or group identities. Verified constraints enforce; verified body-only rules guide; drafts do nothing. Modes and EXPLORE behavior remain server-owned.
|
|
87
28
|
|
|
88
|
-
|
|
89
|
-
**Trust tier:** governed - 2 KB refs, 1 rule enforced (**EXCLUDE_INTERNAL**), max rows 10000
|
|
90
|
-
~~~
|
|
29
|
+
The gateway runs before caches, injects constraints, verifies resolved SQL, and returns a transparency receipt. Do not claim a rule applied merely because it exists.
|
|
91
30
|
|
|
92
|
-
|
|
31
|
+
## Ad-hoc gate
|
|
93
32
|
|
|
94
|
-
|
|
33
|
+
Search the KB genuinely, explain why visible definitions do not fit, and prefer an approved reusable supported definition. Use a truthful ad-hoc reason only for a real one-off. Never use it to bypass a rule.
|
|
95
34
|
|
|
96
|
-
|
|
97
|
-
**Blocked by governance.**
|
|
35
|
+
## Reporting
|
|
98
36
|
|
|
99
|
-
|
|
100
|
-
~~~
|
|
37
|
+
Report tier, semantic references, row cap, visible rules that changed the query, and any refusal or override. Read the receipt rather than inferring. A blocked or partial result is not success.
|
|
@@ -1,97 +1,44 @@
|
|
|
1
|
-
# KB Actions
|
|
1
|
+
# KB Actions
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Load when an approved gap must be authored or an existing semantic asset changed.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## Approval gate
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Before writing, present the missing concept, proposed root, exact definition, group/access scope, and verification state. Do not write until the user approves.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
## Authoring contract
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
- Create semantic models, metrics, groups, and retained rules from JSON.
|
|
12
|
+
- Use exactly one of `--file` or `--json`.
|
|
13
|
+
- Names are lowercase snake case; reserve `__` for qualified dimensions.
|
|
14
|
+
- Entities, dimensions, and measures mutate only through semantic-model update.
|
|
15
|
+
- A supplied nested list replaces the stored list whole. Read first and include every sibling that must remain.
|
|
16
|
+
- Explicit `meta` replaces author metadata whole. Preserve family, axes, topics, and other author fields.
|
|
17
|
+
- Use dedicated verify/unverify actions. Never patch metadata merely to change verification.
|
|
13
18
|
|
|
14
|
-
|
|
15
|
-
|---|---|---|---|---|
|
|
16
|
-
| **ROAS_D7** | metric | `SUM(revenue_d7) / NULLIF(SUM(cost), 0)` | MARKETING_UA | ATTRIBUTION |
|
|
17
|
-
| **CPI** | metric | `SUM(cost) / NULLIF(SUM(installs), 0)` | MARKETING_UA | ACQUISITION |
|
|
18
|
-
| **MEDIA_SOURCE** | dimension | `media_source` | MARKETING_UA | ACQUISITION |
|
|
19
|
+
Read `semantic-authoring.md` for model/metric shapes and `metric-families.md` for concrete variants.
|
|
19
20
|
|
|
20
|
-
|
|
21
|
-
Create these so the dashboard runs on governed references? (Approve / adjust.)
|
|
22
|
-
~~~
|
|
21
|
+
## Rules
|
|
23
22
|
|
|
24
|
-
|
|
23
|
+
Rules remain Graphit objects. Create them from JSON with body/constraints plus `apply_on` targets. Final targets are model, entity, dimension, metric, or group identities. A rule without targets is refused.
|
|
25
24
|
|
|
26
|
-
|
|
25
|
+
Constraints keep their five semantics: required predicate, forbidden column, required filter, required aggregation, and value restriction. Use declared semantic identities and typed values.
|
|
27
26
|
|
|
28
|
-
|
|
29
|
-
|---|---|
|
|
30
|
-
| Metric | `graphit kb create metric --name X --sql "<expr>" --table T` (optional `--topics "A,B"`, `--default-dimensions "D1,D2"`, `--parameters`/`--parameters-file` for templates, `--skip-validate`) |
|
|
31
|
-
| Dimension | `graphit kb create dimension --name X --expr "<expr>" --table T` (type auto-inferred; override with `--type` / `--output-type`; `--skip-validate`) |
|
|
32
|
-
| Rule | `graphit kb create rule --name X --sql "<text>" --table T` (optional `--constraint`, `--apply-on`, `--topics`, `--skip-validate`) |
|
|
33
|
-
| Synonym | `graphit kb create synonym --term X --canonical Y --type metric` |
|
|
34
|
-
| Domain | `graphit kb create domain --name X` (optional `--color "#4DB6AC"`) |
|
|
35
|
-
| Topic | `graphit kb create topic --name X` |
|
|
36
|
-
| Relationship | `graphit kb create relationship --name X --primary-table T --primary-column C --related-table T2 --related-column C2` |
|
|
27
|
+
## Update
|
|
37
28
|
|
|
38
|
-
|
|
29
|
+
1. Read the target through the current principal.
|
|
30
|
+
2. Preserve complete nested and metadata structures.
|
|
31
|
+
3. Apply the smallest patch.
|
|
32
|
+
4. Re-read immediately.
|
|
33
|
+
5. Verify/unverify separately when intended.
|
|
34
|
+
6. Inspect receipts; a degraded write may have landed and must not be retried blindly.
|
|
39
35
|
|
|
40
|
-
|
|
36
|
+
## Delete
|
|
41
37
|
|
|
42
|
-
|
|
38
|
+
Confirm with the user and inspect usage first. The server checks known definition dependencies, not every canvas reference. A green guard is not exhaustive impact proof.
|
|
43
39
|
|
|
44
|
-
|
|
40
|
+
## Permissions
|
|
45
41
|
|
|
46
|
-
|
|
47
|
-
graphit kb create rule --name FILTER_VERIFIED_PURCHASES --sql "Only count verified purchases" --table ORDERS --constraint required_where:"is_verified = true"
|
|
48
|
-
```
|
|
42
|
+
Read access is the ceiling for writes. `kb_write` comes from the effective policy key. Group lifecycle is admin-only. Hidden and missing targets return the same absence.
|
|
49
43
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
Every rule must apply to at least one asset; a targetless rule is rejected. `--table` is required, and without `--apply-on` the rule governs that **whole table** - which cascades to every metric and dimension on it (it fires on any query touching the table). To narrow instead, pass `--apply-on metric:NAME` / `--apply-on dimension:NAME` so the rule applies only when that asset is used. The two are mutually exclusive: never mix a table target with metric/dimension targets on one rule. To govern several tables, list each: `--apply-on table:A table:B`.
|
|
53
|
-
|
|
54
|
-
```bash
|
|
55
|
-
# Whole table - cascades to every metric/dimension on ORDERS
|
|
56
|
-
graphit kb create rule --name ORDERS_ACTIVE_ONLY --sql "Exclude cancelled orders" --table ORDERS
|
|
57
|
-
# Narrowed - applies only when the ARPU metric is used
|
|
58
|
-
graphit kb create rule --name ARPU_TRIM --sql "Cap ARPU outliers" --table USERS --apply-on metric:ARPU
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
## Pre-Creation Validation
|
|
62
|
-
|
|
63
|
-
Metric, dimension, and rule creates validate the formula against real data before writing; the response carries a `validation` object (status `pass` / `skipped` / `fail`). Surface it to the user - per-type result templates are in `kb-traversal.md`. A `fail` returns HTTP 422 and the asset is NOT created: show the error and failing SQL, fix the formula, retry. Validation is skipped (asset still created) for `${PARAM:X}` templates, constraint-based rules, and tables with no ready data source. Pass `--skip-validate` to bypass it on bulk creates.
|
|
64
|
-
|
|
65
|
-
## Update and Delete
|
|
66
|
-
|
|
67
|
-
- Update a field: `graphit kb update <type> NAME --<field> value` (e.g. `--sql`, `--expr`, `--description`, `--table`).
|
|
68
|
-
- Delete: `graphit kb delete <type> NAME --yes`. Deleting a parameterized parent cascades to all its children - confirm the blast radius first (see `parameterized-metrics.md`).
|
|
69
|
-
|
|
70
|
-
## Lists REPLACE - read before you write
|
|
71
|
-
|
|
72
|
-
`--topics`, `--secondary-tables`, `--default-dimensions`, and `--constraint` REPLACE the existing list, they do not append. To change one value, read the current list first (`graphit kb get metric NAME`), then write the full intended list: add a topic with `--topics "EXISTING1,EXISTING2,NEW"`; remove one by writing the list minus that value.
|
|
73
|
-
|
|
74
|
-
Reference a **metric or dimension** onto another table with `graphit kb update metric NAME --secondary-tables "OTHER_TABLE"` (also dimension). This is a read-only pointer marked `*` in the tree; every referenced column must exist on the target. For **rules**, govern several tables by listing them in `--apply-on` (`--apply-on table:A table:B`), not `--secondary-tables`. Topics are horizontal - one topic can tag assets across many domains (see `kb-structure.md`).
|
|
75
|
-
|
|
76
|
-
## Domain home (set on the table, cascades)
|
|
77
|
-
|
|
78
|
-
Domain is set on the TABLE, never per asset, and cascades to every asset on it (model in `kb-structure.md`). To re-home a whole table at once: `graphit kb update table NAME --domain MARKETING`. Change it once on the table, never asset by asset.
|
|
79
|
-
|
|
80
|
-
## Who can write what
|
|
81
|
-
|
|
82
|
-
Reads are open to every member; writes are scoped by the caller's data access profile. Check `graphit status` before presenting a gap plan, so the plan is one they can execute.
|
|
83
|
-
|
|
84
|
-
| Write | Needs |
|
|
85
|
-
|---|---|
|
|
86
|
-
| Metric, dimension, rule, synonym, relationship, table | `kb_write` in the asset's domain |
|
|
87
|
-
| Moving an asset or table to another domain | `kb_write` in BOTH domains - the one it leaves and the one it enters |
|
|
88
|
-
| Domain and topic create / update / delete | Org admin; a profile never grants it |
|
|
89
|
-
| Template create / update / delete | Org admin, OR `kb_write` in any one domain - never a per-template or per-domain grant |
|
|
90
|
-
|
|
91
|
-
Every member can read and use templates. Status is advisory; a denial with `retryable: false` is a stop, not a retry (`operations.md`).
|
|
92
|
-
|
|
93
|
-
To find what exists and how it connects, use the read recipes in `kb-traversal.md`.
|
|
94
|
-
|
|
95
|
-
## UI-Only (no CLI command)
|
|
96
|
-
|
|
97
|
-
Platform-UI state, not KB data the CLI changes: view mode (Tree / By Topic / By Table / Flat), filter dropdowns, expand / collapse, drag-drop onto a topic, and a synonym's cross-cutting domains (extra relevance beyond its home domain has no CLI flag yet).
|
|
44
|
+
Group `access` is stored dbt metadata; it does not grant Graphit visibility.
|
|
@@ -1,79 +1,50 @@
|
|
|
1
1
|
# KB Discovery
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Load before querying, authoring, or building a dashboard.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Group-first discovery
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
1. Read visible groups and effective status.
|
|
8
|
+
2. Choose a group and confirm the audience.
|
|
9
|
+
3. Explore semantic models and root metrics.
|
|
10
|
+
4. Read model-owned entities, dimensions, and measures.
|
|
11
|
+
5. Inspect retained rules and dashboard usage.
|
|
12
|
+
6. Reuse definitions before proposing a gap.
|
|
8
13
|
|
|
9
|
-
|
|
10
|
-
2. **Explore that domain.** `graphit kb explore domain <NAME>` returns the domain's data sources plus the metrics, dimensions, and rules defined on them, in one traversal. This is your working set, and it is the primary discovery call.
|
|
11
|
-
3. **Reuse the assets.** If a metric fits, read its formula with `graphit kb get metric REVENUE` and reference it by name in SQL as `{{metric:REVENUE}}`.
|
|
12
|
-
4. **Handle gaps.** If the domain's data source is missing something, check `graphit kb list relationships` for a connection to another data source you can join; if the data genuinely does not exist, propose creating the asset or a new data source (see below).
|
|
13
|
-
5. **Broaden only as a fallback.** Use `graphit kb search "<concept>"` only when an exploration came up empty or the concept name is too fuzzy to match a domain or topic. Search is semantic (matches by meaning, ranked by a relevance `score`) merged with name/text matching, and capped by `--limit` - the result carries `total` and `truncated`. So an empty or unexpected result means *maybe ranked-out or truncated*, never proof an asset is absent: raise `--limit`, narrow `--type`, or confirm a specific name with `kb get` before concluding it doesn't exist. `graphit kb list` carries `total`/`truncated` too - fewer rows than `total` means the list was capped, not that assets are missing; raise `--limit`. (`graphit kb list domains` enumerates domain names when you need to pick one; it is a name lookup, not the asset-discovery path - explore the domain to see its assets.)
|
|
14
|
+
The lowercase group name is the semantic label. Use the server-provided uppercase `domain_keys`/status key for data-source `--domain`.
|
|
14
15
|
|
|
15
|
-
|
|
16
|
+
## Choosing the object
|
|
16
17
|
|
|
17
|
-
|
|
18
|
+
| Need | Object |
|
|
19
|
+
|---|---|
|
|
20
|
+
| Modeled relation, grain, joins, columns | semantic model |
|
|
21
|
+
| Join identity or grain | entity inside a model |
|
|
22
|
+
| Grouping/filter field | dimension inside a model |
|
|
23
|
+
| Aggregation input | measure inside a model |
|
|
24
|
+
| Reusable business calculation | metric |
|
|
25
|
+
| Organizational placement | group |
|
|
26
|
+
| Governance guidance/enforcement | rule |
|
|
27
|
+
| D7/D30 or gross/net variant | concrete family member |
|
|
18
28
|
|
|
19
|
-
|
|
20
|
-
|---|---|---|
|
|
21
|
-
| Formula | Aggregation required (SUM, COUNT, AVG, MIN, MAX) | Row-level only (no aggregates) |
|
|
22
|
-
| Table scope | Can reference multiple tables | Exactly one table |
|
|
23
|
-
| Purpose | Measures - what you count or sum | Grouping axes - how you slice |
|
|
24
|
-
| Example | `SUM(ORDERS.AMOUNT)` | `DATE_TRUNC('month', EVENTS.EVENT_TS)` |
|
|
25
|
-
| Invalid | `ORDERS.AMOUNT` (no aggregate) | `SUM(EVENTS.DURATION)` (has aggregate) |
|
|
29
|
+
Entities replace relationship assets. Topics are metadata, not roots. Synonyms are removed; search names/descriptions and ask when wording is ambiguous.
|
|
26
30
|
|
|
27
|
-
##
|
|
31
|
+
## Read roles
|
|
28
32
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
- `list` inventories a root noun.
|
|
34
|
+
- `tree` shows the collapsed hierarchy.
|
|
35
|
+
- `search` covers models, metrics, groups, and nested components; not retained rules.
|
|
36
|
+
- `get` reads one exact root.
|
|
37
|
+
- `entity` reads one entity across visible declaring models.
|
|
38
|
+
- `family` expands/resolves concrete members.
|
|
39
|
+
- `explore` accepts semantic-model, metric, or group.
|
|
40
|
+
- `usage` answers dashboard placement and rule impact.
|
|
35
41
|
|
|
36
|
-
|
|
42
|
+
A capped or empty search is not proof of absence.
|
|
37
43
|
|
|
38
|
-
##
|
|
44
|
+
## Governed references
|
|
39
45
|
|
|
40
|
-
|
|
46
|
+
Use `{{ Metric('revenue') }}`, `{{ Dimension('order__channel') }}`, and `{{ Measure('order_total') }}` only for Graphit's measure extension. Legacy token grammar is refused.
|
|
41
47
|
|
|
42
|
-
|
|
43
|
-
|---|---|---|
|
|
44
|
-
| `TOTAL_*` | `TOTAL_REVENUE`, `TOTAL_ORDERS` | Sum aggregations |
|
|
45
|
-
| `AVG_*` | `AVG_ORDER_VALUE` | Average metrics |
|
|
46
|
-
| `COUNT_*` | `COUNT_ACTIVE_USERS` | Count metrics |
|
|
47
|
-
| `*_RATE` | `CONVERSION_RATE`, `CHURN_RATE` | Ratios / percentages |
|
|
48
|
+
## Gap decision
|
|
48
49
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
## Formula Syntax
|
|
52
|
-
|
|
53
|
-
Metrics reference `TABLE.COLUMN` with UPPERCASE naming:
|
|
54
|
-
|
|
55
|
-
```sql
|
|
56
|
-
-- Metric formulas (aggregation required)
|
|
57
|
-
SUM(ORDERS.AMOUNT)
|
|
58
|
-
COUNT(DISTINCT EVENTS.USER_ID) WHERE EVENTS.EVENT_TS >= DATEADD(day, -30, CURRENT_DATE)
|
|
59
|
-
SUM(ORDERS.REVENUE) / NULLIF(SUM(ORDERS.COST), 0)
|
|
60
|
-
|
|
61
|
-
-- Dimension formulas (no aggregates)
|
|
62
|
-
EVENTS.PLATFORM
|
|
63
|
-
DATE_TRUNC('month', EVENTS.EVENT_TS)
|
|
64
|
-
CASE WHEN USERS.AGE >= 18 THEN 'adult' ELSE 'minor' END
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
Use CASE WHEN for conditionals (Snowflake has no FILTER WHERE). Always guard division with NULLIF.
|
|
68
|
-
|
|
69
|
-
When creating assets, pass `--topics` to tag the business concept (check existing topic names first) and `--default-dimensions` on a metric to declare its natural grouping axes. Dimension types are auto-inferred from the column schema; override with `--type` / `--output-type` only when the inference is wrong. Full create / update / delete matrix: `kb-actions.md`.
|
|
70
|
-
|
|
71
|
-
## Reuse Over Reinvention
|
|
72
|
-
|
|
73
|
-
When several graphs share a concept, propose ONE KB asset instead of repeating the formula: 3 graphs using `SUM(ORDERS.AMOUNT)` become one `TOTAL_REVENUE` metric; 2 graphs grouping by `DATE_TRUNC('month', TS)` become one `MONTHLY` dimension.
|
|
74
|
-
|
|
75
|
-
For the same concept on a sibling table with identical columns, **reference** it rather than duplicating: `graphit kb update metric TOTAL_REVENUE --secondary-tables "ORDERS_12M"`. This is a pointer, not a copy - edits propagate to all placements, and referenced placements show a `*` in the KB tree. Metrics and dimensions require every referenced column to exist on the target table (checked on save); rules only require the table to exist. Suggest it when the user has sibling sources (e.g. 6M and 12M windows) or asks to make a metric available on another table.
|
|
76
|
-
|
|
77
|
-
**Where is a known asset already shown?** `explore` shows *where* ambiently (`presented_on` lists the dashboards); `graphit kb usage metric REVENUE` is the directed deep dive: per-chart hits - reuse them, don't rebuild. `--metric X --dimension Y` finds co-occurrence (not a proven `GROUP BY`); only governed `{{metric:}}`/`{{dim:}}` usage is indexed. `graphit kb usage rule X` lists every chart a rule is enforced on (impact analysis).
|
|
78
|
-
|
|
79
|
-
For the graph model and structural questions (vertical home vs horizontal topics), see `kb-structure.md`; for read commands and result templates, see `kb-traversal.md`.
|
|
50
|
+
Propose authoring only when no visible definition fits and business meaning is clear. State formula, grain, binding, group, rule impact, and verification. Ask when any is ambiguous.
|
|
@@ -1,23 +1,25 @@
|
|
|
1
|
-
# KB Scope
|
|
1
|
+
# KB Scope
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Load when deciding who may see or change semantic work.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|---|---|---|
|
|
7
|
-
| The org commons | Everyone in the organization. It always exists, cannot be deleted, and is where an org-wide asset belongs | Definitions the whole company shares, and anything with no narrower home |
|
|
8
|
-
| A shared business domain | Whoever has been granted it. `graphit status` shows the caller's own access, advisory only - the server decides | The normal case: work a team owns and reuses |
|
|
9
|
-
| A private space | Its owner alone. Invisible to everyone else, admins included, and shown simply as "Private" | Scratch work, or data someone is not ready to share |
|
|
5
|
+
## Two names, two purposes
|
|
10
6
|
|
|
11
|
-
**
|
|
7
|
+
- **Group name:** lowercase semantic placement, such as `finance`.
|
|
8
|
+
- **Policy domain key:** uppercase access key returned by status or `domain_keys`, such as `FINANCE`. Data-source `--domain` uses this key.
|
|
12
9
|
|
|
13
|
-
|
|
10
|
+
Never invent the key when the server returned it.
|
|
14
11
|
|
|
15
|
-
|
|
12
|
+
## Visibility
|
|
16
13
|
|
|
17
|
-
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
14
|
+
- Org commons is a synthetic shared scope.
|
|
15
|
+
- A private workspace is visible only to its owner; admins are concealed too.
|
|
16
|
+
- Hidden and missing assets are the same absence.
|
|
17
|
+
- Models and metrics inherit visibility from group placement.
|
|
18
|
+
- Group `access` is dbt metadata and does not grant Graphit access.
|
|
19
|
+
- Rules use server-owned target-derived domain keys.
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
## Writes
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
Read access is the ceiling. A user also needs `kb_write` for the affected key; group lifecycle is admin-only. Moving an asset requires authority over current and destination scopes.
|
|
24
|
+
|
|
25
|
+
Before authoring confirm audience, group, policy key, shared/private scope, and write capability. Never name concealed groups, assets, targets, or counts.
|
|
@@ -1,68 +1,42 @@
|
|
|
1
|
-
# KB Structure
|
|
1
|
+
# KB Structure
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Load when planning, explaining, or locating semantic assets.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## Root model
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
|
10
|
-
|
|
11
|
-
| metric |
|
|
12
|
-
|
|
|
13
|
-
| rule | Free-text business constraint, optionally scoped to one or more tables |
|
|
14
|
-
| synonym | Maps a business term to a canonical metric, dimension, or column |
|
|
15
|
-
| table | Physical data location in the warehouse, with typed columns |
|
|
16
|
-
| topic | Business-concept tag applied to assets (e.g., REVENUE, ACQUISITION) |
|
|
17
|
-
| domain | High-level business area (e.g., MARKETING, SALES, PRODUCT), and the boundary that decides who can see what sits in it |
|
|
18
|
-
| relationship | Documented JOIN pattern between two tables |
|
|
19
|
-
| memory | Org-level context notes, always global scope |
|
|
20
|
-
|
|
21
|
-
## Edge Types
|
|
22
|
-
|
|
23
|
-
| Edge | From | To | Meaning |
|
|
24
|
-
|------|------|----|---------|
|
|
25
|
-
| depends_on | metric, dimension | table | Asset's SQL references columns in this table |
|
|
26
|
-
| tagged_with | metric, dimension, rule, synonym | topic | Asset carries this business-concept tag |
|
|
27
|
-
| in_domain | table, metric, dimension, rule, synonym | domain | A table has one home domain; assets inherit it from their primary table, plus any cross-cutting extras |
|
|
28
|
-
| joins | relationship | table, table | Two tables have a documented JOIN on specific columns |
|
|
29
|
-
| references | rule, synonym | table, column | Rule or synonym references a specific table or column name |
|
|
30
|
-
|
|
31
|
-
## How Membership Works
|
|
32
|
-
|
|
33
|
-
Two different axes organize the KB - keep them separate:
|
|
34
|
-
|
|
35
|
-
- **Vertical: the home (domain -> data source -> assets).** Containment that cascades. An asset has ONE home domain, inherited from its primary table (the data source its SQL reads). Set the domain on the **table** (`graphit kb update table NAME --domain MARKETING`) and every asset on it inherits it; the asset carries no domain tag of its own. To move an asset's home, change its table's domain. Domain-first discovery walks this axis downward.
|
|
36
|
-
- **Horizontal: the concept (topics).** Topics cut ACROSS domains. The same topic (e.g. RETENTION) can tag assets in different domains, grouping them by business meaning regardless of where they sit. An asset can carry several topics at once (`graphit kb update metric NAME --topics "REVENUE,RETENTION"`), and a topic never moves an asset's home. When a concept spans domains, the by-topic view is how you find everything about it.
|
|
7
|
+
| Type | Meaning |
|
|
8
|
+
|---|---|
|
|
9
|
+
| group | Organizational placement; Graphit access still comes from profiles and policy keys |
|
|
10
|
+
| semantic model | One modeled relation and the aggregate root for entities, dimensions, and measures |
|
|
11
|
+
| metric | Reusable simple, ratio, or derived calculation |
|
|
12
|
+
| rule | Retained Graphit governance object targeting semantic identities |
|
|
37
13
|
|
|
38
|
-
|
|
39
|
-
- **Multiple tables**: a metric or dimension can depend on several tables (a JOIN across ORDERS and CUSTOMERS) and appears under each. Table dependency is structural, derived from the SQL, never tagged manually.
|
|
40
|
-
- **Referencing (`secondary_tables`)**: an asset can be referenced onto extra tables; it shows under the target with a `*` suffix, links back to the original, and stays editable only from its home table. Table-backed assets derive domain membership from all their tables (primary plus `secondary_tables`).
|
|
41
|
-
- **Cross-cutting domains**: synonyms can carry extra domains in `extra_domain_ids` for relevance beyond their home, without moving the asset in the tree.
|
|
14
|
+
Nested components are not independent CRUD roots:
|
|
42
15
|
|
|
43
|
-
|
|
16
|
+
- **Entity:** join/grain identity. Primary or unique entities prove the keyed side; foreign entities connect models.
|
|
17
|
+
- **Dimension:** model-owned grouping/filter field. Address cross-model dimensions as `entity__dimension`.
|
|
18
|
+
- **Measure:** model-owned aggregation input used by simple metrics.
|
|
44
19
|
|
|
45
|
-
A
|
|
20
|
+
A metric family is a set of concrete metrics carrying the same family name plus axis values. It is not a template asset.
|
|
46
21
|
|
|
47
|
-
##
|
|
22
|
+
## Relationships
|
|
48
23
|
|
|
49
|
-
|
|
24
|
+
- A group's models and metrics are placed by their `group` field.
|
|
25
|
+
- A semantic model owns all nested components.
|
|
26
|
+
- Metrics reach models through referenced measures and metrics.
|
|
27
|
+
- Models join through shared entities. There is no relationship asset.
|
|
28
|
+
- Rules may target a model, entity, dimension, metric, or group.
|
|
29
|
+
- Topics remain metadata in `meta.graphit`; they are not roots.
|
|
30
|
+
- Dashboard usage is a reverse lookup, not a stored placement.
|
|
50
31
|
|
|
51
|
-
##
|
|
32
|
+
## Names and visibility
|
|
52
33
|
|
|
53
|
-
|
|
34
|
+
Semantic names are lowercase snake case. Double underscore is reserved for qualified dimensions. A group name is displayed lowercase; data-access status exposes the uppercase policy key used by data-source `--domain`.
|
|
54
35
|
|
|
55
|
-
|
|
56
|
-
|---|---|
|
|
57
|
-
| What is a topic / domain / table / relationship? | Use the Node Types descriptions above, in plain language |
|
|
58
|
-
| Why is [metric] under [table]? | Its SQL depends on that table's columns (or it is referenced there via `secondary_tables`, shown as `*`) |
|
|
59
|
-
| Why is [asset] in [topic]? | Someone tagged it - topics are manual, not derived. Check its topics list |
|
|
60
|
-
| Why is [asset] in [domain]? | Its primary table's domain cascades to it; it was not tagged directly |
|
|
61
|
-
| What is a relationship? | A documented JOIN between two tables (which columns, which join type) used to build correct cross-table SQL |
|
|
62
|
-
| What is memory? | Org-level context notes (goals, terminology, conventions), global scope, shown at the tree root |
|
|
36
|
+
Concealment is absence. A hidden asset is exactly like a missing one. Private workspaces are visible only to their owner, including from admins.
|
|
63
37
|
|
|
64
|
-
|
|
38
|
+
## Tree and graph
|
|
65
39
|
|
|
66
|
-
|
|
40
|
+
Tree order is group → semantic model → nested components, with root metrics and rules alongside. Families collapse in tree/search/family views; `list metric` returns concrete metrics.
|
|
67
41
|
|
|
68
|
-
|
|
42
|
+
Graph edges show group placement, model ownership, entity joins, metric composition, governance, and dashboard usage. Use exploration for semantic reach and usage for reverse dashboard impact.
|