Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
df101f0
Merge development to main (Release) (#146)
milosh86 May 21, 2026
19ee065
Merge pull request #149 from aragon/development
evanaronson May 27, 2026
458faf3
refactor: normalize token data into content atoms with composed read …
thekidnamedkd Jun 5, 2026
49d8b1a
fix: pin round-trip tests to frozen content fixtures
thekidnamedkd Jun 5, 2026
d2fce63
feat: add canonical token JSON endpoints with provenance envelope
thekidnamedkd Jun 5, 2026
040f992
chore: exclude composer-owned generated data from biome formatting
thekidnamedkd Jun 5, 2026
0aa34d2
refactor: retire per-token deployment filtering
thekidnamedkd Jun 5, 2026
072fc66
fix: enforce canonical evaluation status vocabulary
thekidnamedkd Jun 5, 2026
30174a5
chore: apply formatter to remaining unformatted components
thekidnamedkd Jun 5, 2026
d4a0b2c
fix: prevent nested paragraph hydration mismatch in metric summaries
thekidnamedkd Jun 5, 2026
e897481
feat: serve app data from published API with SSR query hydration
thekidnamedkd Jun 5, 2026
aa26ed5
refactor: source published content from otf-cms
thekidnamedkd Jun 6, 2026
167347d
fix: upgrade vitest past CVE-2026-47429
thekidnamedkd Jun 6, 2026
a9db938
feat: add CI with vendored schema integrity gate
thekidnamedkd Jun 6, 2026
4f95cd9
feat: version published API under /api/v1 and add llms.txt agent guide
thekidnamedkd Jun 9, 2026
12ab530
feat: compose published data from otf-cms at build time by ref
thekidnamedkd Jun 9, 2026
38048bb
fix: remove shell from build-data fetch to close command-injection fi…
thekidnamedkd Jun 9, 2026
92c757a
docs: clarify count/status mapping and add response example to agent …
thekidnamedkd Jun 10, 2026
672bb07
feat: cache and harden /api/v1 endpoints against request floods
thekidnamedkd Jun 10, 2026
81e7332
chore: add lefthook pre-commit/pre-push rails mirroring CI
thekidnamedkd Jun 10, 2026
e734f0d
feat: carry last_updated freshness through the API provenance envelope
thekidnamedkd Jun 16, 2026
344ac3b
feat: validate composed data against the schema contract before writing
thekidnamedkd Jun 16, 2026
082e986
refactor: vendor the TypeScript composer and drop the JS type shim
thekidnamedkd Jun 16, 2026
ecb96d1
feat: serve published content from the release at runtime behind a da…
thekidnamedkd Jun 16, 2026
7d585d8
docs: note the dark-launch flag is removable post-migration
thekidnamedkd Jun 16, 2026
3f97f1e
fix: name the runtime provenance source release not kv
thekidnamedkd Jun 16, 2026
c1a112b
docs: define vendoring in plain terms at the script and file touchpoints
thekidnamedkd Jun 16, 2026
ef7677c
fix: read SSR data through the same published source as the API
thekidnamedkd Jun 16, 2026
e75c144
fix: surface release published_at and gate snapshots on token-set com…
thekidnamedkd Jun 16, 2026
827e31b
fix: revalidate SSR published reads in release mode instead of pinnin…
thekidnamedkd Jun 16, 2026
b54be43
fix: cap API edge cache to the release revalidation window in release…
thekidnamedkd Jun 16, 2026
015511e
fix: bound the release fetch with a timeout so a hung GitHub falls back
thekidnamedkd Jun 16, 2026
852de96
feat: make the content repo overridable via OTF_CONTENT_REPO for forks
thekidnamedkd Jun 18, 2026
db3326c
feat: add self-contained Vercel CLI deploy workflow (no git-integration)
thekidnamedkd Jun 18, 2026
d59979f
feat: support posting preview URL back to the triggering content PR
thekidnamedkd Jun 18, 2026
2db1e38
Merge remote-tracking branch 'origin/development' into app-556-decoup…
thekidnamedkd Jun 18, 2026
2d66b5c
fix: confirm settings on first deploy of a fresh Vercel project
thekidnamedkd Jun 18, 2026
4517f14
feat: live preview status comment + teardown-on-close in deploy workflow
thekidnamedkd Jun 18, 2026
df5d18d
Add OpenAPI contract, discovery root, and ETag to /api/v1
thekidnamedkd Jun 19, 2026
298596f
Vendor TK schema and render TK/empty as placeholder
thekidnamedkd Jun 19, 2026
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
26 changes: 0 additions & 26 deletions .github/workflows/check-development-to-clients.yml

This file was deleted.

39 changes: 39 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
name: CI

on:
pull_request:
push:
branches: [development, main]

permissions:
contents: read

jobs:
checks:
runs-on: ubuntu-latest
steps:
# Third-party actions pinned to full commit SHAs (supply-chain policy)
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3

- uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8

- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: "22"

- run: pnpm install --frozen-lockfile

- name: Vendored schema integrity
run: node scripts/check-schema-drift.mjs

- name: Lint and format
run: pnpm exec biome check src tests

- name: Type check
run: pnpm type-check

- name: Tests
run: pnpm test

- name: Build
run: pnpm build
196 changes: 196 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
name: Deploy

# Self-contained Vercel deploy — no Vercel git-integration, so no contributor
# needs Vercel membership. The Action deploys on behalf of one VERCEL_TOKEN,
# building the app and uploading the prebuilt output via the Vercel CLI.
#
# Ways in:
# - workflow_dispatch: manual or cross-repo (otf-cms triggers a content
# preview, or a teardown when the content PR closes).
# - push to main: production deploy of the app's own code. Production content
# arrives at runtime from the published Release.
#
# When a content preview is requested with comment_repo/comment_pr, it posts a
# single status comment on that PR and updates it through the lifecycle
# (generating → ready/failed), mimicking a native Vercel PR comment. On
# action=teardown it removes that PR's preview deployment.
#
# Required repo secrets (your fork for testing, aragon/* for real):
# VERCEL_TOKEN, VERCEL_ORG_ID, VERCEL_PROJECT_ID Vercel CLI auth + target
# OTF_CONTENT_TOKEN read otf-cms for build-from-ref
# CMS_COMMENT_TOKEN comment on the content PR
# Optional repo variable:
# OTF_CONTENT_REPO defaults to aragon/otf-cms; set to <you>/otf-cms on a fork

on:
workflow_dispatch:
inputs:
action:
description: deploy or teardown
type: choice
options: [deploy, teardown]
default: deploy
environment:
description: Vercel target
type: choice
options: [preview, production]
default: preview
content_ref:
description: otf-cms ref for a build-from-ref preview (blank = committed/runtime data)
type: string
default: ""
comment_repo:
description: "owner/repo of a PR to post status to (optional, e.g. the otf-cms content PR)"
type: string
default: ""
comment_pr:
description: PR number in comment_repo to post status to (optional)
type: string
default: ""
push:
branches: [main]

permissions:
contents: read

concurrency:
group: deploy-${{ github.event.inputs.comment_pr || github.event.inputs.environment || github.ref }}
cancel-in-progress: true

jobs:
deploy:
if: ${{ github.event.inputs.action != 'teardown' }}
runs-on: ubuntu-latest
# The Vercel CLI reads these from the environment (equivalent to --token /
# project linking), so nothing sensitive is ever inlined into a run script.
env:
VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
TARGET: ${{ github.event.inputs.environment || 'production' }}
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
steps:
# Third-party actions pinned to full commit SHAs (supply-chain policy)
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3

- uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8

- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: "22"

- run: pnpm install --frozen-lockfile

# Status comment: post "generating" up front so the editor sees the build
# is underway (native-Vercel-bot feel). Captures the comment id to update.
- name: Open status comment
id: comment
if: ${{ github.event.inputs.comment_pr != '' }}
env:
GH_TOKEN: ${{ secrets.CMS_COMMENT_TOKEN }}
COMMENT_REPO: ${{ github.event.inputs.comment_repo }}
COMMENT_PR: ${{ github.event.inputs.comment_pr }}
CONTENT_REF: ${{ github.event.inputs.content_ref }}
run: |
printf -v body '### 🔄 Preview — building…\nFrom content branch `%s`. ([build logs](%s))' \
"${CONTENT_REF:-this content}" "$RUN_URL"
id=$(gh api "repos/$COMMENT_REPO/issues/$COMMENT_PR/comments" -f body="$body" --jq '.id')
echo "id=$id" >> "$GITHUB_OUTPUT"

# Gate: never ship code that doesn't type-check or pass tests.
- run: pnpm type-check
- run: pnpm test

# Pin a specific version once confirmed on the fork; latest is fine while
# experimenting.
- name: Install Vercel CLI
run: pnpm add -g vercel@latest

- name: Pull Vercel project config
run: vercel pull --yes --environment="$TARGET"

# build-data reads OTF_CONTENT_REF: set → build-from-ref preview; blank →
# committed data (production, where content comes from the Release).
- name: Build
env:
OTF_CONTENT_REF: ${{ github.event.inputs.content_ref }}
OTF_CONTENT_TOKEN: ${{ secrets.OTF_CONTENT_TOKEN }}
OTF_CONTENT_REPO: ${{ vars.OTF_CONTENT_REPO }}
run: |
if [ "$TARGET" = production ]; then
vercel build --prod
else
vercel build
fi

- name: Deploy prebuilt output
id: deploy
# --yes confirms default settings for a never-deployed project (sets
# skipAutoDetectionConfirmation) so a fresh project deploys non-interactively.
run: |
if [ "$TARGET" = production ]; then
url=$(vercel deploy --prebuilt --prod --yes)
else
url=$(vercel deploy --prebuilt --yes)
fi
echo "url=$url" >> "$GITHUB_OUTPUT"
echo "Deployed ($TARGET): $url" >> "$GITHUB_STEP_SUMMARY"

# Finalize the status comment — runs even if the build/deploy failed, so a
# broken preview is surfaced on the PR instead of failing silently.
- name: Finalize status comment
if: ${{ always() && github.event.inputs.comment_pr != '' }}
env:
GH_TOKEN: ${{ secrets.CMS_COMMENT_TOKEN }}
COMMENT_REPO: ${{ github.event.inputs.comment_repo }}
COMMENT_PR: ${{ github.event.inputs.comment_pr }}
COMMENT_ID: ${{ steps.comment.outputs.id }}
URL: ${{ steps.deploy.outputs.url }}
CONTENT_REF: ${{ github.event.inputs.content_ref }}
DEPLOY_OK: ${{ steps.deploy.outcome == 'success' }}
run: |
if [ "$DEPLOY_OK" = "true" ] && [ -n "$URL" ]; then
printf -v body '### ✅ Preview ready\nContent branch `%s`.\n\n**👉 [Open the preview](%s)**' \
"${CONTENT_REF:-this content}" "$URL"
else
printf -v body '### ❌ Preview build failed\nContent branch `%s`. [See logs](%s)' \
"${CONTENT_REF:-this content}" "$RUN_URL"
fi
if [ -n "$COMMENT_ID" ]; then
gh api -X PATCH "repos/$COMMENT_REPO/issues/comments/$COMMENT_ID" -f body="$body"
else
gh api "repos/$COMMENT_REPO/issues/$COMMENT_PR/comments" -f body="$body"
fi

teardown:
if: ${{ github.event.inputs.action == 'teardown' }}
runs-on: ubuntu-latest
env:
VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
steps:
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: "22"

- name: Install Vercel CLI
run: npm i -g vercel@latest

# Find the preview URL we posted on the (now-closed) content PR and remove
# that deployment, then note it on the PR.
- name: Remove preview deployment
env:
GH_TOKEN: ${{ secrets.CMS_COMMENT_TOKEN }}
COMMENT_REPO: ${{ github.event.inputs.comment_repo }}
COMMENT_PR: ${{ github.event.inputs.comment_pr }}
run: |
host=$(gh api "repos/$COMMENT_REPO/issues/$COMMENT_PR/comments" \
--jq '[.[].body | capture("https://(?<h>[a-z0-9.-]+\\.vercel\\.app)")? | .h] | map(select(. != null)) | last // empty')
if [ -n "$host" ]; then
vercel rm "$host" --yes || true
gh api "repos/$COMMENT_REPO/issues/$COMMENT_PR/comments" \
-f body="🗑️ Preview torn down (content PR closed)."
else
echo "No preview URL found on PR #$COMMENT_PR — nothing to remove."
fi
75 changes: 0 additions & 75 deletions .github/workflows/update-token-timestamps.yml

This file was deleted.

2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,5 @@ output
.agents
.tempor
.playwright-mcp
.env.otf-app-secrets
.pnpm-store
3 changes: 2 additions & 1 deletion biome.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
"**/index.html",
"**/vite.config.js",
"!**/src/routeTree.gen.ts",
"!**/src/styles.css"
"!**/src/styles.css",
"!**/src/data/generated"
]
},
"formatter": {
Expand Down
28 changes: 28 additions & 0 deletions lefthook.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Local rails — same gates as CI (.github/workflows/ci.yml), run on your
# machine so a red build is caught before it leaves it.
#
# pre-commit fast: format/lint only the staged files, auto-fix and re-stage
# pre-push full: the exact checks CI runs (build stays CI-only — too heavy
# for every push)
#
# Skip in a pinch with `git commit --no-verify` / `git push --no-verify`.

pre-commit:
parallel: true
commands:
biome:
glob: "*.{ts,tsx,js,jsx,json,jsonc,css}"
run: pnpm exec biome check --write --no-errors-on-unmatched --files-ignore-unknown=true {staged_files}
stage_fixed: true

pre-push:
parallel: true
commands:
schema-drift:
run: node scripts/check-schema-drift.mjs
biome:
run: pnpm exec biome check src tests
type-check:
run: pnpm type-check
test:
run: pnpm test
Loading