mirror of
https://github.com/Kaelio/ktx.git
synced 2026-06-07 07:55:13 +02:00
docs: clarify KTX product mechanics
This commit is contained in:
parent
e43664693e
commit
8b61e56dfd
3 changed files with 510 additions and 41 deletions
402
docs-site/components/product-mechanics.tsx
Normal file
402
docs-site/components/product-mechanics.tsx
Normal file
|
|
@ -0,0 +1,402 @@
|
|||
import type { ReactNode } from "react";
|
||||
|
||||
const sourceInputs = [
|
||||
{
|
||||
name: "Warehouse schema",
|
||||
detail: "tables, columns, types, constraints, row counts",
|
||||
signal: "grounds definitions in live database structure",
|
||||
accent: "border-fd-primary",
|
||||
},
|
||||
{
|
||||
name: "Metabase and query history",
|
||||
detail: "historic SQL, questions, dashboards, usage patterns",
|
||||
signal: "extracts joins, filters, grain, and trusted examples",
|
||||
accent: "border-orange-500",
|
||||
},
|
||||
{
|
||||
name: "dbt, MetricFlow, LookML",
|
||||
detail: "models, metrics, dimensions, explores, joins",
|
||||
signal: "maps existing modeling logic into semantic entities",
|
||||
accent: "border-amber-500",
|
||||
},
|
||||
{
|
||||
name: "Notion and docs",
|
||||
detail: "definitions, policies, caveats, analyst notes",
|
||||
signal: "links business language back to semantic references",
|
||||
accent: "border-slate-500 dark:border-cyan-200",
|
||||
},
|
||||
];
|
||||
|
||||
const ingestSteps = [
|
||||
{
|
||||
title: "extract evidence",
|
||||
body: "Pull structured facts from schemas, SQL, BI metadata, and docs.",
|
||||
},
|
||||
{
|
||||
title: "reconcile entities",
|
||||
body: "Merge names, measures, joins, and caveats into one project model.",
|
||||
},
|
||||
{
|
||||
title: "validate references",
|
||||
body: "Check semantic fields and joins against database context before agents use them.",
|
||||
},
|
||||
];
|
||||
|
||||
const artifacts = [
|
||||
{
|
||||
path: "semantic-layer/*.yaml",
|
||||
title: "Typed query model",
|
||||
body: "sources, grain, joins, dimensions, measures, filters, segments",
|
||||
},
|
||||
{
|
||||
path: "wiki/*.md",
|
||||
title: "Business context",
|
||||
body: "rules and caveats with sl_refs back to semantic-layer entities",
|
||||
},
|
||||
{
|
||||
path: "raw-sources/",
|
||||
title: "Evidence trail",
|
||||
body: "scan artifacts, extracted metadata, relationship evidence",
|
||||
},
|
||||
{
|
||||
path: ".ktx/",
|
||||
title: "Local indexes",
|
||||
body: "embeddings and search indexes, not the source of truth",
|
||||
},
|
||||
];
|
||||
|
||||
const runtimeSteps = [
|
||||
{
|
||||
title: "Search wiki",
|
||||
body: "Find business rules, caveats, synonyms, and sl_refs.",
|
||||
},
|
||||
{
|
||||
title: "Resolve semantic refs",
|
||||
body: "Map measure and dimension names to approved entities.",
|
||||
},
|
||||
{
|
||||
title: "Validate fields",
|
||||
body: "Check source, columns, joins, grain, filters, and segments.",
|
||||
},
|
||||
{
|
||||
title: "Build query plan",
|
||||
body: "Create a semantic query plan before SQL is generated.",
|
||||
},
|
||||
{
|
||||
title: "Compile dialect SQL",
|
||||
body: "Generate warehouse-shaped SQL instead of copying examples.",
|
||||
},
|
||||
{
|
||||
title: "Execute with bounds",
|
||||
body: "Optionally run with bounded rows and return provenance.",
|
||||
},
|
||||
];
|
||||
|
||||
export function ProductMechanics() {
|
||||
return (
|
||||
<section
|
||||
className="not-prose my-12 w-full max-w-full min-w-0 space-y-5"
|
||||
aria-labelledby="mechanics-title"
|
||||
>
|
||||
<div className="max-w-3xl">
|
||||
<p className="mb-2 text-xs font-semibold uppercase tracking-wide text-fd-primary">
|
||||
Product mechanics
|
||||
</p>
|
||||
<h2
|
||||
id="mechanics-title"
|
||||
className="text-xl font-semibold tracking-normal text-fd-foreground sm:text-2xl"
|
||||
style={{ fontFamily: "var(--font-display)" }}
|
||||
>
|
||||
A semantic compiler for analytics agents
|
||||
</h2>
|
||||
<p className="mt-3 text-sm leading-6 text-fd-muted-foreground">
|
||||
KTX builds typed semantic files, links wiki context back to those
|
||||
entities, validates the model against database evidence, then compiles
|
||||
agent requests into executable SQL.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="space-y-4">
|
||||
<IngestionDiagram />
|
||||
<RuntimeDiagram />
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
function IngestionDiagram() {
|
||||
return (
|
||||
<article
|
||||
className="max-w-full min-w-0 overflow-hidden rounded-lg border border-fd-border bg-fd-card shadow-sm"
|
||||
aria-labelledby="ingestion-diagram-title"
|
||||
>
|
||||
<DiagramHeader
|
||||
eyebrow="Ingestion"
|
||||
id="ingestion-diagram-title"
|
||||
title="Messy source evidence becomes structured state"
|
||||
body="The important step is reconciliation: KTX turns loose evidence into files agents can validate, edit, and compile against."
|
||||
/>
|
||||
|
||||
<div className="grid gap-0 lg:grid-cols-[minmax(0,0.9fr)_minmax(0,1.1fr)]">
|
||||
<section className="border-b border-fd-border p-4 lg:border-r lg:border-b-0">
|
||||
<ColumnLabel>Inputs KTX reads</ColumnLabel>
|
||||
<div className="grid gap-2 sm:grid-cols-2">
|
||||
{sourceInputs.map((source) => (
|
||||
<div
|
||||
key={source.name}
|
||||
className={`border-l-2 bg-fd-background px-3 py-2 ${source.accent}`}
|
||||
>
|
||||
<p className="text-sm font-semibold text-fd-foreground">
|
||||
{source.name}
|
||||
</p>
|
||||
<p className="mt-0.5 text-xs leading-5 text-fd-muted-foreground">
|
||||
{source.detail}
|
||||
</p>
|
||||
<p className="mt-1 text-xs leading-5 text-fd-primary">
|
||||
{source.signal}
|
||||
</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="bg-fd-muted/35 p-4">
|
||||
<ColumnLabel>KTX builds the model</ColumnLabel>
|
||||
<div className="grid gap-3 xl:grid-cols-[minmax(0,0.85fr)_minmax(0,1fr)]">
|
||||
<div className="rounded-md border border-fd-border bg-[#102226] p-4 text-white dark:bg-[#0b181b]">
|
||||
<p className="mb-3 text-[11px] font-semibold uppercase tracking-wide text-cyan-200">
|
||||
Ingest pipeline
|
||||
</p>
|
||||
<ol className="space-y-3">
|
||||
{ingestSteps.map((step, index) => (
|
||||
<PipelineStep
|
||||
key={step.title}
|
||||
index={index + 1}
|
||||
title={step.title}
|
||||
body={step.body}
|
||||
dark
|
||||
/>
|
||||
))}
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-2 sm:grid-cols-2 xl:grid-cols-1">
|
||||
{artifacts.map((artifact) => (
|
||||
<Artifact key={artifact.path} {...artifact} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</article>
|
||||
);
|
||||
}
|
||||
|
||||
function RuntimeDiagram() {
|
||||
return (
|
||||
<article
|
||||
className="max-w-full min-w-0 overflow-hidden rounded-lg border border-fd-border bg-fd-card shadow-sm"
|
||||
aria-labelledby="runtime-diagram-title"
|
||||
>
|
||||
<DiagramHeader
|
||||
eyebrow="Runtime"
|
||||
id="runtime-diagram-title"
|
||||
title="A tiny semantic request becomes a planned, executable query"
|
||||
body="The agent names the business intent. KTX resolves the semantic model, checks the shape, compiles SQL, and can execute with row limits."
|
||||
/>
|
||||
|
||||
<div className="grid gap-0 lg:grid-cols-[minmax(0,0.82fr)_minmax(0,1.18fr)]">
|
||||
<section className="border-b border-fd-border p-4 lg:border-r lg:border-b-0">
|
||||
<ColumnLabel>Agent sends</ColumnLabel>
|
||||
<CodeBox>
|
||||
<div>connection: warehouse</div>
|
||||
<div>measure: orders.total_revenue</div>
|
||||
<div>dimension: customers.segment</div>
|
||||
<div>filter: orders.created_date >= '2024-01-01'</div>
|
||||
</CodeBox>
|
||||
<p className="mt-3 text-xs leading-5 text-fd-muted-foreground">
|
||||
This is the API surface agents should use: compact semantic intent,
|
||||
not hand-written warehouse SQL.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section className="bg-fd-muted/35 p-4">
|
||||
<ColumnLabel>KTX planning and execution</ColumnLabel>
|
||||
<div className="grid gap-2 sm:grid-cols-2">
|
||||
{runtimeSteps.map((step, index) => (
|
||||
<PipelineStep
|
||||
key={step.title}
|
||||
index={index + 1}
|
||||
title={step.title}
|
||||
body={step.body}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-0 border-t border-fd-border lg:grid-cols-[minmax(0,1fr)_minmax(0,1fr)]">
|
||||
<section className="border-b border-fd-border p-4 lg:border-r lg:border-b-0">
|
||||
<ColumnLabel>Semantic query plan</ColumnLabel>
|
||||
<div className="rounded-md border border-fd-border bg-fd-card p-3 text-xs leading-5 text-fd-muted-foreground">
|
||||
<p>
|
||||
<strong className="text-fd-foreground">source:</strong>{" "}
|
||||
orders joined to customers as many_to_one
|
||||
</p>
|
||||
<p>
|
||||
<strong className="text-fd-foreground">measure:</strong>{" "}
|
||||
total_revenue = sum(amount) with refund filter
|
||||
</p>
|
||||
<p>
|
||||
<strong className="text-fd-foreground">grain:</strong> segment
|
||||
group-by with date predicate
|
||||
</p>
|
||||
<p>
|
||||
<strong className="text-fd-foreground">result:</strong> dialect
|
||||
SQL, bounded rows, and provenance
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="p-4">
|
||||
<ColumnLabel>KTX returns</ColumnLabel>
|
||||
<CodeBox>
|
||||
<div>select</div>
|
||||
<div className="pl-3">customers.segment,</div>
|
||||
<div className="pl-3">sum(orders.amount) as total_revenue</div>
|
||||
<div>from analytics.orders</div>
|
||||
<div>join analytics.customers</div>
|
||||
<div className="pl-3">on orders.customer_id = customers.id</div>
|
||||
<div>where orders.status != 'refunded'</div>
|
||||
<div className="pl-3">and orders.created_date >= '2024-01-01'</div>
|
||||
<div>group by 1</div>
|
||||
</CodeBox>
|
||||
<p className="mt-3 text-xs leading-5 text-fd-muted-foreground">
|
||||
The output can be SQL-only or executed results with provenance, so
|
||||
the agent can show where the answer came from.
|
||||
</p>
|
||||
</section>
|
||||
</div>
|
||||
</article>
|
||||
);
|
||||
}
|
||||
|
||||
function DiagramHeader({
|
||||
body,
|
||||
eyebrow,
|
||||
id,
|
||||
title,
|
||||
}: {
|
||||
body: string;
|
||||
eyebrow: string;
|
||||
id: string;
|
||||
title: string;
|
||||
}) {
|
||||
return (
|
||||
<div className="border-b border-fd-border bg-fd-muted/35 px-5 py-4">
|
||||
<p className="text-xs font-semibold uppercase tracking-wide text-fd-primary">
|
||||
{eyebrow}
|
||||
</p>
|
||||
<h3
|
||||
id={id}
|
||||
className="mt-1 text-base font-semibold tracking-normal text-fd-foreground sm:text-lg"
|
||||
style={{ fontFamily: "var(--font-display)" }}
|
||||
>
|
||||
{title}
|
||||
</h3>
|
||||
<p className="mt-2 max-w-3xl text-xs leading-5 text-fd-muted-foreground">
|
||||
{body}
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function Artifact({
|
||||
body,
|
||||
path,
|
||||
title,
|
||||
}: {
|
||||
body: string;
|
||||
path: string;
|
||||
title: string;
|
||||
}) {
|
||||
return (
|
||||
<div className="rounded-md border border-fd-border bg-fd-card px-3 py-2">
|
||||
<p className="font-mono text-xs font-semibold text-fd-foreground">
|
||||
{path}
|
||||
</p>
|
||||
<p className="mt-1 text-sm font-semibold text-fd-foreground">{title}</p>
|
||||
<p className="mt-0.5 text-xs leading-5 text-fd-muted-foreground">
|
||||
{body}
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function PipelineStep({
|
||||
body,
|
||||
dark = false,
|
||||
index,
|
||||
title,
|
||||
}: {
|
||||
body: string;
|
||||
dark?: boolean;
|
||||
index: number;
|
||||
title: string;
|
||||
}) {
|
||||
return (
|
||||
<li
|
||||
className={
|
||||
dark
|
||||
? "flex gap-3 text-sm"
|
||||
: "flex gap-3 rounded-md border border-fd-border bg-fd-card px-3 py-2"
|
||||
}
|
||||
>
|
||||
<span
|
||||
className={
|
||||
dark
|
||||
? "flex h-5 w-5 flex-none items-center justify-center rounded-full bg-cyan-200 text-[11px] font-semibold text-[#102226]"
|
||||
: "flex h-5 w-5 flex-none items-center justify-center rounded-full bg-fd-primary text-[11px] font-semibold text-fd-primary-foreground"
|
||||
}
|
||||
>
|
||||
{index}
|
||||
</span>
|
||||
<span className="min-w-0">
|
||||
<span
|
||||
className={
|
||||
dark
|
||||
? "block text-sm font-semibold text-white"
|
||||
: "block text-xs font-semibold text-fd-foreground"
|
||||
}
|
||||
>
|
||||
{title}
|
||||
</span>
|
||||
<span
|
||||
className={
|
||||
dark
|
||||
? "mt-0.5 block break-words text-xs leading-5 text-cyan-50/75"
|
||||
: "mt-0.5 block break-words text-xs leading-5 text-fd-muted-foreground"
|
||||
}
|
||||
>
|
||||
{body}
|
||||
</span>
|
||||
</span>
|
||||
</li>
|
||||
);
|
||||
}
|
||||
|
||||
function ColumnLabel({ children }: { children: ReactNode }) {
|
||||
return (
|
||||
<p className="mb-3 text-[11px] font-semibold uppercase tracking-wide text-fd-muted-foreground">
|
||||
{children}
|
||||
</p>
|
||||
);
|
||||
}
|
||||
|
||||
function CodeBox({ children }: { children: ReactNode }) {
|
||||
return (
|
||||
<div className="max-w-full min-w-0 overflow-x-auto rounded-md border border-fd-border bg-[#0c1417] p-3 font-mono text-[11px] leading-5 text-cyan-50 shadow-sm">
|
||||
<div className="[overflow-wrap:anywhere]">{children}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -3,10 +3,12 @@ title: Introduction
|
|||
description: How KTX gives analytics agents trusted context for warehouse work.
|
||||
---
|
||||
|
||||
<div className="not-prose mb-14">
|
||||
<div className="mb-8">
|
||||
import { ProductMechanics } from "@/components/product-mechanics";
|
||||
|
||||
<div className="not-prose mb-10">
|
||||
<div>
|
||||
<h1
|
||||
className="text-4xl font-extrabold tracking-tight lg:text-5xl"
|
||||
className="max-w-full text-3xl font-extrabold tracking-tight break-words sm:text-4xl lg:text-5xl"
|
||||
style={{
|
||||
fontFamily: 'var(--font-display)',
|
||||
background: 'linear-gradient(180deg, var(--color-fd-foreground) 0%, color-mix(in oklch, var(--color-fd-foreground) 75%, var(--color-fd-primary)) 100%)',
|
||||
|
|
@ -18,63 +20,43 @@ description: How KTX gives analytics agents trusted context for warehouse work.
|
|||
letterSpacing: '0',
|
||||
}}
|
||||
>
|
||||
Make analytics context{'\n'}usable by agents
|
||||
Make analytics context usable by agents
|
||||
</h1>
|
||||
<p className="mt-4 text-lg text-fd-muted-foreground max-w-2xl" style={{ lineHeight: '1.7' }}>
|
||||
KTX turns warehouse metadata, semantic definitions, and business knowledge
|
||||
into reviewable project files that agents can use while planning, querying,
|
||||
and updating analytics work.
|
||||
<p className="mt-4 max-w-2xl text-lg text-fd-muted-foreground" style={{ lineHeight: '1.7' }}>
|
||||
{'KTX turns warehouse metadata, semantic definitions, and business knowledge into reviewable project files that agents can use while planning, querying, and updating analytics work.'}
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex flex-wrap gap-3">
|
||||
<a
|
||||
href="/docs/getting-started/quickstart"
|
||||
className="inline-flex h-10 items-center rounded-lg bg-fd-primary px-5 text-sm font-medium text-fd-primary-foreground transition-colors hover:opacity-90"
|
||||
>
|
||||
Get Started
|
||||
</a>
|
||||
<a
|
||||
href="/docs/concepts/the-context-layer"
|
||||
className="inline-flex h-10 items-center rounded-lg border border-fd-border bg-fd-background px-5 text-sm font-medium text-fd-foreground transition-colors hover:bg-fd-muted"
|
||||
>
|
||||
The Context Layer
|
||||
</a>
|
||||
<a
|
||||
href="/docs/guides/building-context"
|
||||
className="inline-flex h-10 items-center rounded-lg border border-fd-border bg-fd-background px-5 text-sm font-medium text-fd-foreground transition-colors hover:bg-fd-muted"
|
||||
>
|
||||
Building Context
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
## Who KTX is for
|
||||
<ProductMechanics />
|
||||
|
||||
## What agents can do with KTX
|
||||
|
||||
KTX is built for analytics engineers and data teams who want data agents to
|
||||
work on real analytics systems - not just generate one-off SQL.
|
||||
work on real analytics systems, not just generate one-off SQL.
|
||||
|
||||
Use KTX when you want agents to:
|
||||
Use it when agents need to:
|
||||
|
||||
- **Generate SQL** from approved measures and joins
|
||||
- **Repair semantic definitions** through reviewable diffs
|
||||
- **Explain metric provenance** with warehouse evidence
|
||||
- **Work alongside** dbt, LookML, MetricFlow, Looker, Metabase, and modern BI platforms
|
||||
- **Generate SQL** from approved measures, dimensions, joins, and filters
|
||||
- **Explain provenance** with wiki context and warehouse evidence
|
||||
- **Repair context** through reviewable YAML and Markdown diffs
|
||||
- **Work alongside** dbt, LookML, MetricFlow, Looker, Metabase, and warehouses
|
||||
|
||||
Works with SQLite, PostgreSQL, Snowflake, BigQuery, ClickHouse, MySQL, and SQL
|
||||
Server.
|
||||
KTX works with SQLite, PostgreSQL, Snowflake, BigQuery, ClickHouse, MySQL, and
|
||||
SQL Server.
|
||||
|
||||
## Explore the docs
|
||||
## Read next
|
||||
|
||||
<Cards>
|
||||
<Card title="Quickstart" href="/docs/getting-started/quickstart">
|
||||
Set up KTX and build your first context in under 10 minutes.
|
||||
</Card>
|
||||
<Card title="Concepts" href="/docs/concepts/the-context-layer">
|
||||
Understand what a context layer is and why agents need one.
|
||||
</Card>
|
||||
<Card title="Guides" href="/docs/guides/building-context">
|
||||
Hands-on workflows for scanning, ingesting, writing, and serving.
|
||||
</Card>
|
||||
<Card title="Writing Context" href="/docs/guides/writing-context">
|
||||
Edit semantic-layer YAML and wiki Markdown safely.
|
||||
</Card>
|
||||
<Card title="CLI Reference" href="/docs/cli-reference/ktx-setup">
|
||||
Complete flag and subcommand reference for every KTX command.
|
||||
</Card>
|
||||
|
|
|
|||
85
docs-site/tests/product-mechanics-content.test.mjs
Normal file
85
docs-site/tests/product-mechanics-content.test.mjs
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
import assert from "node:assert/strict";
|
||||
import { readFile } from "node:fs/promises";
|
||||
import { dirname, join } from "node:path";
|
||||
import { test } from "node:test";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const docsSiteDir = join(dirname(fileURLToPath(import.meta.url)), "..");
|
||||
|
||||
async function readDocsFile(path) {
|
||||
return readFile(join(docsSiteDir, path), "utf8");
|
||||
}
|
||||
|
||||
test("docs introduction shows the ingestion and runtime mechanics early", async () => {
|
||||
const introduction = await readDocsFile(
|
||||
"content/docs/getting-started/introduction.mdx",
|
||||
);
|
||||
|
||||
assert.match(
|
||||
introduction,
|
||||
/import\s+\{\s*ProductMechanics\s*\}\s+from\s+"@\/components\/product-mechanics";/,
|
||||
);
|
||||
assert.match(introduction, /<ProductMechanics\s*\/>/);
|
||||
|
||||
const heroIndex = introduction.indexOf("Make analytics context");
|
||||
const mechanicsIndex = introduction.indexOf("<ProductMechanics />");
|
||||
const useCaseIndex = introduction.indexOf("## What agents can do with KTX");
|
||||
const heroSource = introduction.slice(0, mechanicsIndex);
|
||||
|
||||
assert.ok(heroIndex >= 0, "introduction should include the custom hero");
|
||||
assert.ok(
|
||||
mechanicsIndex > heroIndex,
|
||||
"mechanics component should appear after the hero",
|
||||
);
|
||||
assert.ok(
|
||||
mechanicsIndex < useCaseIndex,
|
||||
"mechanics component should appear before use-case sections",
|
||||
);
|
||||
assert.doesNotMatch(heroSource, /Get Started/);
|
||||
assert.doesNotMatch(heroSource, /The Context Layer/);
|
||||
assert.doesNotMatch(heroSource, /Building Context/);
|
||||
assert.doesNotMatch(heroSource, /flex flex-wrap gap-3/);
|
||||
});
|
||||
|
||||
test("product mechanics component covers source-specific context and SQL expansion", async () => {
|
||||
const component = await readDocsFile("components/product-mechanics.tsx");
|
||||
|
||||
for (const expectedText of [
|
||||
"A semantic compiler for analytics agents",
|
||||
"Ingestion",
|
||||
"Runtime",
|
||||
"wiki/",
|
||||
"semantic-layer/",
|
||||
"raw-sources/",
|
||||
".ktx/",
|
||||
"sl_refs",
|
||||
"Notion",
|
||||
"Metabase",
|
||||
"query history",
|
||||
"extract evidence",
|
||||
"reconcile entities",
|
||||
"validate references",
|
||||
"semantic query plan",
|
||||
"dialect SQL",
|
||||
"bounded rows",
|
||||
"provenance",
|
||||
"measure: orders.total_revenue",
|
||||
"dimension: customers.segment",
|
||||
"select",
|
||||
]) {
|
||||
assert.ok(
|
||||
component.includes(expectedText),
|
||||
`component should include: ${expectedText}`,
|
||||
);
|
||||
}
|
||||
|
||||
assert.doesNotMatch(component, /KTX does more than retrieve Markdown/);
|
||||
assert.doesNotMatch(component, /Plain Markdown \+ RAG/);
|
||||
assert.doesNotMatch(component, /comparisonRows/);
|
||||
assert.doesNotMatch(component, /ComparisonTable/);
|
||||
assert.doesNotMatch(component, /Not just retrieval/);
|
||||
assert.doesNotMatch(component, /KTX works in two moments/);
|
||||
assert.doesNotMatch(component, /w-\[calc\(100vw/);
|
||||
assert.doesNotMatch(component, /xl:grid-cols-2/);
|
||||
assert.doesNotMatch(component, /lg:grid-cols-\[[^\]]*_2rem_/);
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue