diff --git a/docs/features/query-results.mdx b/docs/features/query-results.mdx
index 308e891f4..f156d20c2 100644
--- a/docs/features/query-results.mdx
+++ b/docs/features/query-results.mdx
@@ -36,11 +36,11 @@ The results panel expands itself when a query runs. The toolbar's trash button c
## The row cap
-A `SELECT` or `WITH` query with no `LIMIT`, `FETCH FIRST` or `TOP` of its own stops at the row cap. , and `EXPLAIN`, `SHOW`, writes and DDL are never capped.
+A `SELECT` or `WITH` query with no `LIMIT`, `FETCH FIRST` or `TOP` of its own stops at the row cap.
-When the cap trims a result the status bar reads **Showing N rows** and offers **Fetch All**, which extends the result in place. To skip the cap for one run, press `Cmd+Option+Enter` or choose **Execute Without Limit** from the Execute button's menu.
+
-The cap and its off switch are in [Settings > Data](/customization/data-settings#query-result-row-cap).
+When the cap trims a result the status bar reads **Showing N rows** and offers **Fetch All**, which extends the result in place. To skip the cap for one run, press `Cmd+Option+Enter` or choose **Execute Without Limit** from the Execute button's menu.
## Statements that return no rows
diff --git a/docs/features/table-structure.mdx b/docs/features/table-structure.mdx
index fc4776535..3ebbc0e4a 100644
--- a/docs/features/table-structure.mdx
+++ b/docs/features/table-structure.mdx
@@ -55,7 +55,7 @@ Right-click a foreign key and choose **Open [table]** to jump to the referenced
## Saving changes
-; see [Change Tracking](/features/change-tracking) for the queue, undo (`Cmd+Z`) and redo (`Cmd+Shift+Z`). A save runs on the tab's own connection, database, and schema, the ones it was opened on, and never moves the sidebar or the toolbar.
+ [Change Tracking](/features/change-tracking) covers the queue, undo (`Cmd+Z`) and redo (`Cmd+Shift+Z`). A save runs on the tab's own connection, database, and schema, the ones it was opened on, and never moves the sidebar or the toolbar.
- **Save Changes** (`Cmd+S` or the toolbar checkmark) applies the queue. Changes that can lose data, dropping a column, changing a type, adding NOT NULL, changing the primary key, first show a confirmation listing each one.
- **Preview SQL** (`Cmd+Shift+P`) shows the generated statements without executing them.
diff --git a/docs/scripts/check-links.py b/docs/scripts/check-links.py
index 3d4a4d2eb..289286dcc 100755
--- a/docs/scripts/check-links.py
+++ b/docs/scripts/check-links.py
@@ -28,6 +28,44 @@ def nav_pages(node, out, collecting=False):
out.add(node)
+IMPORT = re.compile(r'^import\s+(\w+)\s+from\s+"(/snippets/[^"]+)"', re.M)
+CONTINUES = re.compile(r"^[,;:)]|^(and|or|but|so|then|which|while|with)\b")
+
+
+def check_snippets(path, raw, failures):
+ """A snippet may end a line, but the sentence may not carry on past it.
+
+ Snippets are block content: several sentences, sometimes a markdown link that wraps. Starting a
+ new sentence after one on the same line renders fine. Continuing the same sentence does not:
+ `features/query-results.mdx` shipped `, and ...`, which built green under
+ `mint validate` and returned HTTP 500 in production.
+ """
+ rel = path.relative_to(DOCS)
+ declared = {}
+ for name, source in IMPORT.findall(raw):
+ declared[name] = source
+ if not (DOCS / source.lstrip("/")).exists():
+ failures.append(f"{rel} imports {source}, which is not in docs/snippets")
+ if not declared:
+ return
+
+ used = "|".join(re.escape(n) for n in declared)
+ in_fence = False
+ for line_no, line in enumerate(raw.splitlines(), 1):
+ if line.lstrip().startswith("```"):
+ in_fence = not in_fence
+ continue
+ if in_fence:
+ continue
+ for match in re.finditer(rf"<({used})\b[^>]*/>", line):
+ trailing = line[match.end():].strip()
+ if trailing and CONTINUES.match(trailing):
+ failures.append(
+ f"{rel}:{line_no} carries the sentence on past <{match.group(1)} />; "
+ f"a snippet is block content, so start a new sentence or a new line"
+ )
+
+
def main() -> int:
config = json.loads((DOCS / "docs.json").read_text())
pages = set()
@@ -62,6 +100,7 @@ def main() -> int:
continue
rel = path.relative_to(DOCS)
body = FENCE.sub("", path.read_text())
+ check_snippets(path, body, failures)
for line_no, line in enumerate(body.splitlines(), 1):
for target in LINK.findall(line):
page, _, anchor = target.partition("#")