Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
root = true

[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true

[*.py]
indent_style = space
indent_size = 4

[*.{yml,yaml,json,astro,md,mjs}]
indent_style = space
indent_size = 2

[*.md]
trim_trailing_whitespace = false
3 changes: 3 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Every tracked text file is stored with LF; keep working trees the same on
# Windows and macOS.
* text=auto eol=lf
1 change: 0 additions & 1 deletion .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
# Default owners for everything in the repo.
# TODO: replace with the maintainer's GitHub handle or org team before Phase 1.
* @GetTechAPI/maintainers

/data/ @GetTechAPI/maintainers
Expand Down
11 changes: 3 additions & 8 deletions .github/ISSUE_TEMPLATE/bug_report.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: "🐛 Bug report"
description: Report a bug in the API or tooling
description: Report a bug in the static API, the site or the validator
labels: ["type:bug"]
body:
- type: textarea
Expand All @@ -13,9 +13,9 @@ body:
id: reproduce
attributes:
label: Steps to reproduce
description: Include the exact request (curl) where possible.
description: Include the exact URL or command where possible.
placeholder: |
curl https://api.techapi.dev/v1/smartphones/galaxy-s25
curl https://gettechapi.github.io/TechAPI/v1/smartphones/galaxy-s25/index.json
validations:
required: true
- type: textarea
Expand All @@ -24,8 +24,3 @@ body:
label: Expected behavior
validations:
required: true
- type: input
id: request-id
attributes:
label: request_id (if any)
description: The `request_id` from the error response helps us trace it.
8 changes: 8 additions & 0 deletions .github/ISSUE_TEMPLATE/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
blank_issues_enabled: true
contact_links:
- name: Collectors, verification or the API generator
url: https://github.com/GetTechAPI/TechEngine/issues
about: The engine that validates and publishes this data has its own repository.
- name: Video games
url: https://github.com/GetTechAPI/game-catalog/issues
about: Game records moved to the game-catalog repository.
17 changes: 13 additions & 4 deletions .github/ISSUE_TEMPLATE/data_addition.yml
Original file line number Diff line number Diff line change
@@ -1,16 +1,25 @@
name: "📥 Data addition"
description: Request a new device, SoC, or GPU
description: Request a record that is missing from the dataset
labels: ["type:data", "data:missing"]
body:
- type: dropdown
id: category
attributes:
label: Category
options:
- smartphone
- brand
- soc
- cpu
- gpu
- brand
- smartphone
- tablet
- watch
- pda
- laptop
- monitor
- device_catalog
- software
- website
validations:
required: true
- type: input
Expand All @@ -24,6 +33,6 @@ body:
id: sources
attributes:
label: Source URLs (at least one)
description: Manufacturer spec sheet preferred (§9.2).
description: The manufacturer's product page or datasheet is preferred; a Wikipedia article also works.
validations:
required: true
21 changes: 21 additions & 0 deletions .github/ISSUE_TEMPLATE/data_correction.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,27 @@ name: "✏️ Data correction"
description: Correct an existing spec value
labels: ["type:data", "data:incorrect"]
body:
- type: dropdown
id: category
attributes:
label: Category
description: Slugs are unique only within a category.
options:
- brand
- soc
- cpu
- gpu
- smartphone
- tablet
- watch
- pda
- laptop
- monitor
- device_catalog
- software
- website
validations:
required: true
- type: input
id: slug
attributes:
Expand Down
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/feature_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,5 @@ body:
attributes:
label: Scope check
options:
- label: This is generalizable to all consumers (not TechPicks-specific, see ADR-008).
- label: This is useful to anyone who reads the data, not only to one app or site.
required: true
2 changes: 1 addition & 1 deletion .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@
- [ ] Files live at the correct `data/<category>/<...>/<slug>.json` path
- [ ] Slugs are kebab-case and unique within the category
- [ ] `source_urls` cites at least one canonical reference
- [ ] Sidebar filled in by hand (nothing fills it automatically): assignees, labels, milestone, projects, Copilot review, and the tracker under Development
- [ ] Sidebar filled in by hand (nothing fills it automatically): assignees, labels, milestone, projects, and the tracker under Development
2 changes: 1 addition & 1 deletion .github/scripts/build-api.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
# (data/_verify/status.json) with the pinned TechEngine, and check the result.
# pages.yml runs this before publishing.
#
# Needs the TechEngine submodule checked out (never recursively) and its
# Needs the TechEngine submodule checked out and its
# dependencies installed: python -m pip install -e ./TechEngine
set -euo pipefail

Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/collect.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ jobs:
inputs.task == 'ingest'
permissions:
contents: read
uses: GetTechAPI/TechEngine/.github/workflows/ingest.yml@45090a02409b2418d156c6c0af77395e97d32050 # main, TechEngine #133
uses: GetTechAPI/TechEngine/.github/workflows/ingest.yml@ff4e11ec294e2f7c428bcfc3a3298ce8163e7d6a # main, TechEngine #134
with:
category: ${{ inputs.category }}
limit: ${{ inputs.limit }}
Expand All @@ -86,7 +86,7 @@ jobs:
inputs.task == 'refresh'
permissions:
contents: read
uses: GetTechAPI/TechEngine/.github/workflows/refresh.yml@45090a02409b2418d156c6c0af77395e97d32050 # main, TechEngine #133
uses: GetTechAPI/TechEngine/.github/workflows/refresh.yml@ff4e11ec294e2f7c428bcfc3a3298ce8163e7d6a # main, TechEngine #134
with:
sleep: ${{ inputs.sleep }}

Expand All @@ -96,7 +96,7 @@ jobs:
inputs.task == 'promote'
permissions:
contents: read
uses: GetTechAPI/TechEngine/.github/workflows/verify-promote.yml@45090a02409b2418d156c6c0af77395e97d32050 # main, TechEngine #133
uses: GetTechAPI/TechEngine/.github/workflows/verify-promote.yml@ff4e11ec294e2f7c428bcfc3a3298ce8163e7d6a # main, TechEngine #134
with:
apply: ${{ inputs.apply }}
max_urls: ${{ inputs.max_urls }}
Expand Down
5 changes: 3 additions & 2 deletions .github/workflows/final-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,9 @@ jobs:
env:
PYTHONIOENCODING: utf-8
steps:
# The merge commit, as pages.yml would build it after merging. Not
# recursive: TechEngine carries TechAPI as its own submodule.
# The merge commit, as pages.yml would build it after merging. A plain,
# non-recursive submodule checkout is all it needs: TechEngine has no
# submodules of its own.
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 2
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/pages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ jobs:
steps:
# Full history: the dump stamps created_at/updated_at from git log of
# data/ (a shallow clone stamps every record with the tip time), and the
# growth chart reads old commits. Submodules are not recursive: TechEngine
# carries TechAPI as its own submodule.
# growth chart reads old commits. A plain, non-recursive submodule
# checkout is all it needs: TechEngine has no submodules of its own.
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/pr-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ jobs:
steps:
# The pull_request ref is GitHub's merge commit. Depth 2 brings both
# parents, so HEAD^1 is the base the PR merges into: no deepening, no
# second checkout. submodules: true is NOT recursive (TechEngine carries
# TechAPI as its own submodule; recursion re-clones ~1.8 GB).
# second checkout. submodules: true is a plain, non-recursive checkout,
# which is all it needs: TechEngine has no submodules of its own.
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 2
Expand Down
3 changes: 0 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,6 @@ __pycache__/
# Local-only handoff notes (private; never committed to the public repo)
*.local.md

# Local tooling/editor config (kept out of the public repo)
.claude/

# The static API is generated on every Pages deploy (.github/scripts/build-api.sh,
# then site/scripts/build-*.mjs). Only the hand-made games pointer is tracked.
/site/public/v1/*
Expand Down
77 changes: 67 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,65 @@ static-dump generator live in

## Layout

### Repository map

```text
data/brand/<country>/<slug>.json # e.g. data/brand/kr/samsung.json
data/soc/<manufacturer>/<year>/<slug>.json # data/soc/qualcomm/2024/snapdragon-8-elite.json
data/smartphone/<brand>/<year>/<slug>.json # data/smartphone/samsung/2025/galaxy-s25.json
data/gpu/<manufacturer>/<year>/<segment>/<slug>.json # data/gpu/nvidia/2025/consumer/geforce-rtx-5090.json
data/cpu/<manufacturer>/<year>/<segment>/<slug>.json # data/cpu/intel/2023/consumer/core-i9-14900k.json
data/ # the dataset: one JSON file per record (categories below)
app/ # the bundled validator, standard library only (python -m app.validate)
site/ # the Astro site that GitHub Pages serves, with the generated API
TechEngine/ # the engine, a submodule pinned to one commit: full validator,
# integrity gate, API dump, collectors and verification
.github/
workflows/
pr-checks.yml # read-only checks on every PR into develop or main
final-check.yml # full build and verification of a PR labelled final-check
collect.yml # runs one engine collector by hand; uploads a patch
pages.yml # builds the API and the site from main and deploys them
scripts/
build-api.sh # validates, then generates site/public/v1 and openapi.json
check_dump.py # compares the generated API with data/
open-collect-pr.sh # opens the PR for one collect.yml run
```

All paths use singular folder names. Slugs are kebab-case and unique within each category.
### Data

Every record is one JSON file named `<slug>.json`. Folder names are singular,
slugs are kebab-case and unique within their category. Counts are as of
November 2026.

| Category | Path under `data/` | Files | Example |
| --- | --- | ---: | --- |
| `brand` | `brand/<country>/<slug>.json` | 3,022 | `brand/kr/samsung.json` |
| `soc` | `soc/<manufacturer>/<year>/<slug>.json` | 2,117 | `soc/qualcomm/2024/snapdragon-8-elite.json` |
| `cpu` | `cpu/<manufacturer>/<year>/<consumer\|enterprise>/<slug>.json` | 4,517 | `cpu/intel/2023/consumer/core-i9-14900k.json` |
| `gpu` | `gpu/<manufacturer>/<year>/<consumer\|enterprise>/<slug>.json` | 2,076 | `gpu/nvidia/2025/consumer/geforce-rtx-5090.json` |
| `smartphone` | `smartphone/<brand>/<year>/<slug>.json` or `smartphone/<brand>/<year>/<base_model>/<slug>.json` | 92,824 | `smartphone/samsung/2025/galaxy-s25.json` |
| `tablet` | `tablet/<brand>/<year>/<base_model>/<slug>.json` | 3,305 | `tablet/huawei/2020/matepad-t8/matepad-t8.json` |
| `watch` | `watch/<brand>/<year>/<base_model>/<slug>.json` | 418 | `watch/samsung/2024/galaxy-watch-fe/…` |
| `pda` | `pda/<brand>/<year>/<base_model>/<slug>.json` | 112 | `pda/hp/2000/ipaq-h3600/ipaq-h3600-base.json` |
| `laptop` | `laptop/<brand>/<year>/<base_model>/<slug>.json` | 1,966 | `laptop/dell/2017/dell-inspiron-5567/…` |
| `monitor` | `monitor/<brand>/<year>/<base_model>/<slug>.json` | 231 | `monitor/samsung/2023/samsung-m50b/…` |
| `device_catalog` | `device_catalog/<brand>/<slug>.json` | 20,366 | `device_catalog/kazam/kazam-thunder-345-lte.json` |
| `software` | `software/<prefix>/<slug>.json` | 42,493 | `software/sw/sweble.json` |
| `website` | `website/<prefix>/<slug>.json` | 39,930 | `website/pc/pc-gamer-uk.json` |

- `<year>` is the release year, as in the record's `release_date`.
- `<country>` is the brand's ISO 3166 country code in lower case. A brand with
no sourced country lives under `brand/unknown/`; that is most of them (2,815).
- `<consumer|enterprise>` is a coarse folder split. A CPU record's own `segment`
field is finer: `desktop`, `laptop`, `hedt` or `server`.
- `<base_model>` groups the variants of one model (memory, storage, region).
About a third of the smartphones (31,093) and 44 laptops sit directly in the
year folder instead.
- `<prefix>` is the first two characters of the slug, or the whole slug when it
is one character long.
- `device_catalog` lists device identities (model numbers, codenames) whose
release date is unknown, so it has no year folder.
- `data/_verify/` is not a category. It holds the verification ledger
(`ledger.jsonl`), the status aggregate (`status.json`) and the caches under
`state/` that TechEngine's verify tools write. Don't edit it by hand.

### Site

The Astro site lives under `site/` and is the deploy target for GitHub Pages.
[`pages.yml`](.github/workflows/pages.yml) generates the static JSON API from
Expand All @@ -39,7 +89,7 @@ only the hand-made `site/public/v1/games/index.json` pointer is. To preview the
site with the API locally:

```bash
git submodule update --init TechEngine # never --recursive
git submodule update --init TechEngine
python -m pip install -e ./TechEngine
bash .github/scripts/build-api.sh # validates, then writes site/public/v1
cd site && npm ci && npm run dev
Expand Down Expand Up @@ -99,9 +149,16 @@ This repo follows git-flow:

A release is a PR from `develop` to `main`; merging it deploys the site.
The TechEngine pin and the pinned action SHAs are bumped by hand, in a PR into
`develop` that pr-checks validates like any other. Dependabot can't do it:
TechEngine carries TechAPI as its own submodule, and Dependabot's recursive
clone runs out of disk on that loop.
`develop` that pr-checks validates like any other; Dependabot is not used.

## Related repositories

| Repository | What it holds |
| --- | --- |
| [TechEngine](https://github.com/GetTechAPI/TechEngine) | The engine pinned here as a submodule: validation, the static API generator, the collectors and the verification tiers. |
| [game-catalog](https://github.com/GetTechAPI/game-catalog) | Video game records. They moved out of this repo in September 2026; `site/public/v1/games/index.json` points there. |
| [cpu-engineering-samples](https://github.com/GetTechAPI/cpu-engineering-samples) | Engineering-sample CPUs, kept apart from the retail CPUs in `data/cpu/`. |
| [TechMachine](https://github.com/GetTechAPI/TechMachine) | The organisation's repository health check and the scaffolder for new satellite data repos. |

## Contributing

Expand Down
Loading