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
14 changes: 14 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
root = true

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

[*.py]
indent_style = space
indent_size = 4

[*.{json,yml,yaml,md,html}]
indent_style = space
indent_size = 2
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
2 changes: 2 additions & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Default owners for everything in this repository.
* @Seungpyo1007
13 changes: 13 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!-- PR title follows Conventional Commits, e.g. data(game): add <name>. Target `develop`; only a release PR targets `main`. -->

## What & why

<!-- What does this change and why? Use "Closes #123" for the issue it resolves. -->

## Checklist

- [ ] Targets `develop`
- [ ] `python -m app.validate --changed-since develop` and `python -m pytest -q` pass locally
- [ ] Every new or changed record has `slug`, `name`, `source_urls` and `verified`, and cites at least one public reference in `source_urls`
- [ ] Records live at `data/game/<bucket>/<slug>.json`, where the bucket is the first two characters of the slug
- [ ] Sidebar filled in by hand: assignees, labels, milestone, projects
1 change: 1 addition & 0 deletions .github/workflows/deploy-pages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ jobs:
deploy:
needs: build
runs-on: ubuntu-latest
timeout-minutes: 10
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
__pycache__/
*.py[cod]
.pytest_cache/
.venv/
venv/
.idea/
Expand Down
40 changes: 28 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,22 @@ Hardware stays in TechAPI; games live here.
Games are unscored and are not part of the verification layer — they were not
in TechEngine's scoring or verify categories before the split either.

The records moved out of TechAPI on 2026-09-17. TechAPI keeps a pointer to this
repository at `site/public/v1/games/index.json`, and its site reads this
repository's `summary.json` for the game count.

## Layout

```
data/game/<bucket>/<slug>.json # bucket = first two slug characters
app/validate.py # schema / slug / range checks
site/build.py # summary.json + history.json for the site
```
| Path | What it is |
|---|---|
| `data/game/<bucket>/<slug>.json` | One record per file; the bucket is the first two characters of the slug |
| `app/validate.py` | Validator: required fields, slug, filename and bucket, duplicate slugs, date and rating ranges |
| `site/build.py` | Writes `site/summary.json` and `site/history.json` (generated, not committed) |
| `site/index.html` | The Pages landing page; shows the count from `summary.json` |
| `tests/` | pytest tests for the validator |
| `.github/workflows/validate-data.yml` | Validator and tests on pull requests and on pushes to `develop` and `main` |
| `.github/workflows/final-check.yml` | Label-triggered full check of a pull request (see [Final check](#final-check)) |
| `.github/workflows/deploy-pages.yml` | Builds `site/` and deploys it to GitHub Pages on pushes to `main` |

A record needs `slug`, `name`, `source_urls` and `verified`. Optional fields
follow TechEngine's game model: `release_date`, `rating` (0-5), `rating_count`,
Expand All @@ -37,14 +46,19 @@ follow TechEngine's game model: `release_date`, `rating` (0-5), `rating_count`,
## Self-check

```bash
python -m app.validate # every record (~2h on Windows)
python -m app.validate # every record
python -m app.validate --changed-since develop # only records your branch touched
python -m pytest -q
```

The validator reads records one at a time, so the full run fits in a runner's
memory; on a CI runner it took 3 minutes for 962,384 records on 2026-10-31.

CI runs the scoped check on pull requests and the full check on pushes to
`develop` and `main`. Workflows use `GITHUB_TOKEN` only — no personal access
tokens, bot accounts, schedules or writes back to any repository.
`develop` and `main`. `validate-data` and `deploy-pages` use `GITHUB_TOKEN`
only. No workflow runs on a schedule, opens pull requests or issues, or pushes
to a repository. The one other secret is `TECHENGINEBOT_TOKEN`, which only the
comment job of the final check sees.

## Final check

Expand All @@ -54,15 +68,17 @@ site build on the PR merged into its base. **TechEngineBot** then leaves one
comment with the verdict, and adding the label again edits that comment.
Only the comment job sees `TECHENGINEBOT_TOKEN`, a fine-grained TechEngineBot
token with Pull requests: read and write. Without it, the verdict appears
only in the job summary.
only in the job summary. Pull requests from forks never get a comment.

## Site

`python site/build.py` writes two files that the TechAPI homepage reads so the
count still appears there:
`python site/build.py` writes two files into `site/`. They are not committed;
`deploy-pages` rebuilds and publishes them on every push to `main`. The TechAPI
site reads `summary.json`, so the count still appears there:

- `summary.json` — `{"count": N, "generated_at": "..."}`
- `history.json` — `{"points": [{"sha", "date", "count"}]}`, one point per data commit
- `history.json` — `{"points": [{"sha", "date", "count"}]}`, one point per
commit that added or removed records

There is no `catalog.json` listing every record, and the page does not render
one: a million rows cannot be fetched or drawn in a browser.
Expand Down
Loading