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
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ hyperwheel.html # built artifact — gitignored, generated by build.py
public/index.html # built artifact for Vercel — gitignored, built on deploy
build.py # assembler (concatenates src/ → hyperwheel.html);
# also injects {{VERSION}} / {{VERSION_CLEAN}} from
# `git describe --tags --always --dirty`
# `git describe --tags --always`
api/sync.js # Vercel serverless: KV-backed cloud sync of HOLDINGs
api/chain-sync.js # Vercel serverless: CORS proxy to Rysk + Hypersurface
src/
Expand Down
15 changes: 9 additions & 6 deletions CONTEXT.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,12 +133,15 @@ where the wheel-strategy invariants are written prose-style.

### Version
The git tag of the deployed build, displayed in the footer and the first-visit
wallet popup. Source of truth is `git describe --tags --always --dirty`,
substituted into a `{{VERSION}}` placeholder by `build.py`. A `-dirty` suffix
means the build contains uncommitted changes — useful for spotting
not-from-a-clean-tag deploys. Tags are created automatically by a GitHub Action
on every merge to `main` (see ADR 0001), so the footer always reflects current
shipped code without manual bookkeeping.
wallet popup. Source of truth is `git describe --tags --always`, substituted
into a `{{VERSION}}` placeholder by `build.py`. The `--dirty` flag was
deliberately dropped: Vercel's build environment auto-runs `npm install` and
rewrites tracked files mid-build, so every deploy looked `-dirty` regardless
of source state — the signal was noise, not a "not-from-a-clean-tag" tell.
Tags are created automatically by a GitHub Action on every merge to `main`
(see ADR 0001), and `vercel.json` runs `git fetch --tags` before the build so
the deploy can resolve them. The footer always reflects current shipped code
without manual bookkeeping.

### Trade accounting snapshot
A per-trade record of the lot state **at the moment that trade was processed**
Expand Down
12 changes: 6 additions & 6 deletions build.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,12 @@ def resolve_version(cwd=BASE):
"""Return git-tag version string for the repo at *cwd*.

Order of preference:
1. ``git describe --tags --always --dirty`` (tag, or short SHA if no tag).
1. ``git describe --tags --always`` (tag, or short SHA if no tag).
2. ``unknown`` if git is unavailable or *cwd* is not a repo.
"""
try:
result = subprocess.run(
['git', 'describe', '--tags', '--always', '--dirty'],
['git', 'describe', '--tags', '--always'],
cwd=cwd, capture_output=True, text=True,
)
except (FileNotFoundError, OSError):
Expand Down Expand Up @@ -80,11 +80,11 @@ def build():
+ '</html>\n'
)

# Inject git-tag version. {{VERSION}} keeps the -dirty suffix for display;
# {{VERSION_CLEAN}} strips it so release links resolve to a real tag.
# Inject git-tag version. {{VERSION}} and {{VERSION_CLEAN}} are now
# identical (we no longer surface the -dirty suffix); kept as separate
# placeholders so existing template references still resolve.
version = resolve_version()
version_clean = version[:-len('-dirty')] if version.endswith('-dirty') else version
output = output.replace('{{VERSION_CLEAN}}', version_clean)
output = output.replace('{{VERSION_CLEAN}}', version)
output = output.replace('{{VERSION}}', version)

# Write local copy
Expand Down
7 changes: 5 additions & 2 deletions test/build/test_resolve_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,15 @@ def test_commits_past_tag(self):
v = build.resolve_version(d)
self.assertTrue(v.startswith('v1.2.3-1-g'), f'got {v!r}')

def test_dirty_tree(self):
def test_dirty_tree_does_not_append_suffix(self):
# We deliberately don't surface -dirty: Vercel checkouts can dirty
# tracked files mid-build (e.g. npm install rewriting package-lock),
# which has nothing to do with the source the user is looking at.
with tempfile.TemporaryDirectory() as d:
init_repo(d)
git(d, 'tag', 'v1.2.3')
open(os.path.join(d, 'a.txt'), 'w').write('changed')
self.assertEqual(build.resolve_version(d), 'v1.2.3-dirty')
self.assertEqual(build.resolve_version(d), 'v1.2.3')

def test_no_tags_returns_short_sha(self):
with tempfile.TemporaryDirectory() as d:
Expand Down
2 changes: 1 addition & 1 deletion vercel.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"buildCommand": "python3 build.py --check",
"buildCommand": "git fetch --tags --depth=1 origin || true; python3 build.py --check",
"outputDirectory": "public",
"framework": null,
"headers": [
Expand Down
Loading