Gallery › robotparts › robotparts sources

robotparts sources

Every source robotparts.dev holds an asset from, grouped by kind, with a stale badge where an asset or a link check has aged past its kind's threshold: the freshness table, in a .base file.

robotpartstablelistrecord4 views of one sources.json

The .base file and its data

Every tab above is one entry of this file; the views read these rows. ⋯ in the toolbar copies the current view as YAML.

# Sources: robotparts' /sources/ page (build/site_pages.py sources_page, site/static/site.js freshness) as a .base
# file. One row per source, grouped by kind, each with its freshness badge as of 2026-11-25 (source/make.py says why).
# Obsidian Bases grammar plus data-ui's keys (docs/CONTRACT.md §5).
data: sources.json
facets:
  - kind
  - freshness
  - rule
  - { property: assets, as: range }
views:
  - type: table
    name: By kind
    order: [name, freshness, stale_kinds, rule, parts, assets, last_accessed, first_seen, links_checked, dead, moved, refresh]
    groupBy: { property: kind, direction: ASC }
    sort:
      - { property: last_accessed, direction: ASC }
    summaries: { parts: Sum, assets: Sum }
  - type: table
    name: Needs refresh
    filters: 'freshness == "needs refresh"'
    order: [name, stale_kinds, last_accessed, age_days, assets, refresh]
    groupBy: { property: kind, direction: ASC }
    sort:
      - { property: last_accessed, direction: ASC }
  - type: list
    name: List
    order: [name, freshness, last_accessed, assets, rule]
    groupBy: { property: kind, direction: ASC }
    sort:
      - { property: last_accessed, direction: ASC }
    separator: " · "
  - type: record
    name: Source page
    record:
      sections:
        - { name: The source, properties: [kind, rule, hosts, parts, assets] }
        - { name: Freshness, properties: [freshness, stale_kinds, last_accessed, via_atlas, age_days, first_seen, oldest] }
        - { name: Links, properties: [links, links_checked, oldest_check, dead, moved] }
        - { name: Refresh, properties: [refresh] }
// sources.json: 43 rows, 29 KB; the first 3
{
 "id": "robotparts-sources",
 "title": "Sources",
 "titleProperty": "name",
 "linkProperty": "page",
 "source": "robotparts dist/site/v2/sources.json, release 2026.10.25.1; 43 of 196 sources, at most 8 per kind, oldest access first; freshness as of 2026-11-25",
 "properties": {
  "name": {
   "type": "text",
   "label": "Source"
  },
  "id": {
   "type": "text",
   "label": "Id",
   "hidden": true
  },
  "kind": {
   "type": "text",
   "label": "Kind",
   "display": "badge",
   "note": "maker: a maker's own site (makers.toml); seller: a shop that sells the part; distributor: a distributor (an atlas labels its values distributor); atlas: an atlas: the repository that owns the records; registry/API: a package registry or an API a reading came from; code host: a code host: repositories, pinned files and evidence; robotparts: robotparts.dev itself; image host: a host that serves only images; web: any other web page"
  },
  "rule": {
   "type": "text",
   "label": "Rule",
   "note": "may robotparts read it"
  },
  "hosts": {
   "type": "list",
   "label": "Other hosts"
  },
  "parts": {
   "type": "number",
   "label": "Parts"
  },
  "assets": {
   "type": "number",
   "label": "Assets"
  },
  "last_accessed": {
   "type": "date",
   "label": "Last accessed",
   "note": "the newest date among its assets"
  },
  "via_atlas": {
   "type": "boolean",
   "label": "Dated by atlas commit"
  },
  "first_seen": {
   "type": "date",
   "label": "First seen"
  },
  "age_days": {
   "type": "number",
   "label": "Age",
   "unitText": "days",
   "note": "days from last access to 2026-11-25"
  },
  "links": {
   "type": "number",
   "label": "URLs"
  },
  "links_checked": {
   "type": "number",
   "label": "Checked"
  },
  "oldest_check": {
   "type": "date",
   "label": "Oldest link check"
  },
  "dead": {
   "type": "number",
   "label": "Dead"
  },
  "moved": {
   "type": "number",
   "label": "Moved"
  },
  "freshness": {
   "type": "text",
   "label": "Freshness",
   "display": "badge",
   "colors": {
    "needs refresh": 8,
    "fresh": 0,
    "date not recorded": 0
   },
   "note": "as of 2026-11-25, by freshness.toml's thresholds"
  },
  "stale_kinds": {
   "type": "list",
   "label": "Stale",
   "display": "badge",
   "colors": {
    "link": 8,
    "spec value": 8,
    "citation": 8,
    "port": 8,
    "photo": 8,
    "CAD": 8,
    "sim model": 8,
    "document": 8,
    "software": 8,
    "software reading": 8,
    "price observation": 8,
    "measurement": 8,
    "logo": 8,
    "link checks": 8
   },
   "note": "the kinds whose oldest asset is past its threshold"
  },
  "oldest": {
   "type": "text",
   "label": "Oldest asset by kind",
   "hidden": true
  },
  "refresh": {
   "type": "text",
   "label": "How it refreshes"
  },
  "page": {
   "type": "text",
   "label": "Page",
   "hidden": true
  }
 },
 "rows": [
  {
   "id": "cdn.shopify.com",
   "name": "cdn.shopify.com",
   "kind": "web",
   "rule": "not reviewed",
   "hosts": [],
   "parts": 1145,
   "assets": 1445,
   "last_accessed": "2026-10-08",
   "via_atlas": false,
   "first_seen": "2026-10-08",
   "age_days": 48,
   "links": 1326,
   "links_checked": 1326,
   "oldest_check": "2026-10-26",
   "dead": null,
   "moved": null,
   "freshness": "fresh",
   "stale_kinds": [],
   "oldest": "photo 2026-10-08, spec value 2026-10-09",
   "refresh": "python3 ~/robotparts/tools/live.py ingest cdn.shopify.com",
   "page": "https://robotparts.dev/sources/cdn.shopify.com/"
  },
  {
   "id": "shop.smc-powers.com",
   "name": "shop.smc-powers.com",
   "kind": "seller",
   "rule": "not reviewed",
   "hosts": [],
   "parts": 1,
   "assets": 23,
   "last_accessed": "2026-10-08",
   "via_atlas": false,
   "first_seen": "2026-10-08",
   "age_days": 48,
   "links": 2,
   "links_checked": 0,
   "oldest_check": null,
   "dead": null,
   "moved": null,
   "freshness": "needs refresh",
   "stale_kinds": [
    "price observation"
   ],
   "oldest": "link 2026-10-08, price observation 2026-10-08, spec value 2026-10-08",
   "refresh": null,
   "page": "https://robotparts.dev/sources/shop.smc-powers.com/"
  },
  {
   "id": "actuator-atlas",
   "name": "actuator-atlas",
   "kind": "atlas",
   "rule": "atlas",
   "hosts": [],
   "parts": 1146,
   "assets": 21764,
   "last_accessed": "2026-10-09",
   "via_atlas": true,
   "first_seen": "2026-10-09",
   "age_days": 47,
   "links": null,
   "links_checked": null,
   "oldest_check": null,
   "dead": null,
   "moved": null,
   "freshness": "fresh",
   "stale_kinds": [],
   "oldest": "spec value 2026-10-09",
   "refresh": null,
   "page": "https://robotparts.dev/sources/actuator-atlas/"
  }
 ]
}
skin.css, README.md
/* robotparts' skin: its own tokens (site/static/site.css, release 2026.10.25), then the one block that maps them onto
   data-ui's --data-* (docs/SPEC.md §10). The gallery scopes a skin to .data-ui-skin; on robotparts.dev the same
   mapping sits at :root. */
.data-ui-skin {
  --bg: #ffffff; --bg2: #f6f7f8; --hover: #f1f5fb; --ink: #15181c; --ink2: #545c66;
  --rule: #d9dde2; --rule2: #e9ebee; --accent: #0a5bb5; --on-accent: #ffffff; --warn: #9a3412;
  --sans: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Liberation Sans", sans-serif;
  --mono: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", "DejaVu Sans Mono", monospace;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .data-ui-skin {
    --bg: #111317; --bg2: #181b20; --hover: #1a2433; --ink: #e6e8eb; --ink2: #a4abb4;
    --rule: #30353c; --rule2: #252930; --accent: #6ea8ec; --on-accent: #0b1220; --warn: #f0a070;
  }
}
:root[data-theme="dark"] .data-ui-skin {
  --bg: #111317; --bg2: #181b20; --hover: #1a2433; --ink: #e6e8eb; --ink2: #a4abb4;
  --rule: #30353c; --rule2: #252930; --accent: #6ea8ec; --on-accent: #0b1220; --warn: #f0a070;
}
/* the mapping: this is all a vanilla app writes */
.data-ui-skin {
  --data-bg: var(--bg); --data-fg: var(--ink); --data-muted: var(--ink2); --data-subtle: var(--bg2);
  --data-border: var(--rule); --data-rule: var(--rule2); --data-hover: var(--hover); --data-accent: var(--accent);
  --data-on-accent: var(--on-accent); --data-warn: var(--warn); --data-font: var(--sans); --data-mono: var(--mono);
  --data-radius: 6px;
}
# robotparts sources

Every source robotparts.dev holds an asset from, grouped by kind, with a stale badge where an asset or a link check
has aged past its kind's threshold: the freshness table, in a `.base` file.

- **App:** robotparts
- **Replaces:** robotparts' hand-rolled `/sources/` page: `sources_page()` in `build/site_pages.py` in `~/robotparts`
  (the table, its facet form and its counts) and the freshness script in `site/static/site.js` that adds the
  "needs refresh" badges in the browser. Here the table, the grouping, the rail and the badges are the kit's.
- **Shows:** the table grouped by kind with Sum summaries, a badge column whose colour is a slot (`colors`), a preset
  that filters to what needs a refresh, the `list` view of the same rows, and the `record` view as a source page.
- **Data:** `sources.json`, 43 of the release's 196 sources (at most 8 per kind, oldest access first), written by
  `source/make.py` from robotparts' `dist/site/v2/sources.json` (release 2026.10.25.1). The verdict is
  computed once, there, with freshness.toml's thresholds, as of 2026-11-25: one month after the release, so prices
  and software readings (stale after 30 days) have aged out. On the release day itself every source reads fresh.
- **Skin:** `skin.css`, robotparts' token mapping.

The original UI it replaces

robotparts' hand-rolled /sources/ page: sources_page() in build/site_pages.py in ~/robotparts (the table, its facet form and its counts) and the freshness script in site/static/site.js that adds the "needs refresh" badges in the browser. Here the table, the grouping, the rail and the badges are the kit's.

What it shows

the table grouped by kind with Sum summaries, a badge column whose colour is a slot (colors), a preset that filters to what needs a refresh, the list view of the same rows, and the record view as a source page.

Data

sources.json, 43 of the release's 196 sources (at most 8 per kind, oldest access first), written by source/make.py from robotparts' dist/site/v2/sources.json (release 2026.10.25.1). The verdict is computed once, there, with freshness.toml's thresholds, as of 2026-11-25: one month after the release, so prices and software readings (stale after 30 days) have aged out. On the release day itself every source reads fresh.

Skin

skin.css, robotparts' token mapping.