This document describes the versioning strategy for tb-solid-pod and how build version information is tracked and displayed in the demo application.
- SHA (Secure Hash Algorithm) — Git commit identifier (e.g.,
abc1234); we use the short 7-character form. - SemVer (Semantic Versioning) — Version numbering scheme: MAJOR.MINOR.PATCH (e.g.,
0.1.0). - CI (Continuous Integration) — Automated build and deployment via GitHub Actions.
- UTC (Coordinated Universal Time) — The primary time standard; all timestamps are generated and stored in UTC, then converted to local time for display.
The project tracks three types of version information:
- Release version — Semantic version from
package.json(0.1.0) - Build metadata — Git commit hash, branch, build timestamp (UTC)
- Release tag — Optional git tag for production releases (e.g.,
v0.1.0)
This information is injected at build time via Vite's define feature and displayed on the demo page.
Time handling: All timestamps are generated and stored in UTC (Coordinated Universal Time) using ISO 8601 format. When displayed to users, timestamps are converted to the user's local timezone for readability. The raw UTC timestamp is always available for debugging and programmatic access.
Development build footer:
tb-solid-pod v0.1.0 • Build abc1234 • Jan 31, 2026
Release build footer:
tb-solid-pod Release v0.2.0 • Build def5678 • Feb 15, 2026
Detailed view (About tab):
┌─────────────────────────────────────────────────────────┐
│ Version Information │
├─────────────────────────────────────────────────────────┤
│ Version: Release v0.2.0 │
│ Commit: def5678 (view on GitHub) │
│ Branch: main │
│ Built: Jan 31, 2026, 10:30:45 AM │
│ Build Timestamp: 2026-01-31T18:30:45.123Z (UTC) │
│ Environment: production │
│ │
│ [View release notes →] │
└─────────────────────────────────────────────────────────┘
Note: The "Built" field shows local time (user's timezone), while "Build Timestamp" shows the original UTC timestamp for reference.
The application exposes version metadata through global constants:
// Available at runtime in the browser
__APP_VERSION__ // "0.1.0" from package.json
__GIT_COMMIT_SHA__ // "abc1234" (short SHA)
__GIT_BRANCH__ // "main" or feature branch name
__BUILD_TIMESTAMP__ // ISO 8601: "2026-01-31T10:30:00.000Z"
__BUILD_ENV__ // "development" | "production"
__RELEASE_TAG__ // "v0.1.0" | undefined (set in CI for tagged releases)The __BUILD_TIMESTAMP__ constant captures the exact moment the build was executed:
- Format: ISO 8601 string in UTC (e.g.,
"2026-01-31T18:30:45.123Z") - Timezone: Always UTC (Coordinated Universal Time) for storage
- Precision: Milliseconds included
- Generated: At the start of the Vite build process
- Display: Converted to user's local timezone for readability
Display formats:
// Parse the timestamp
const buildDate = new Date(__BUILD_TIMESTAMP__)
// User-friendly local time (preferred for UI)
buildDate.toLocaleString() // "1/31/2026, 10:30:45 AM" (user's timezone)
buildDate.toLocaleDateString() // "1/31/2026"
buildDate.toLocaleTimeString() // "10:30:45 AM"
// More readable format with options
buildDate.toLocaleString('en-US', {
year: 'numeric',
month: 'short',
day: 'numeric',
hour: '2-digit',
minute: '2-digit',
second: '2-digit'
}) // "Jan 31, 2026, 10:30:45 AM"
// ISO format (for debugging, logs, programmatic access)
buildDate.toISOString() // "2026-01-31T18:30:45.123Z" (always UTC)
// Relative time (timezone-agnostic)
const hoursAgo = Math.floor((Date.now() - buildDate.getTime()) / (1000 * 60 * 60))
`Built ${hoursAgo}h ago`Best practices:
- User-facing displays: Use
toLocaleString()ortoLocaleDateString()to show time in user's timezone - Technical displays: Show both local time and UTC timestamp for reference
- Logs and storage: Always use ISO 8601 UTC format (
toISOString()) - API responses: Return UTC ISO 8601; let clients convert to local time
Why store in UTC, display in local?
- Storage consistency: UTC ensures all builds have unambiguous timestamps
- User experience: Local time is more intuitive for users ("2:30 PM" vs "19:30 UTC")
- Debugging: Always keep UTC available for troubleshooting across timezones
- Standard practice: Matches industry best practices (databases, APIs, logs use UTC)
Build age indicator: For development builds, showing how old the build is helps developers know if they need to rebuild:
function BuildAge({ timestamp }: { timestamp: string }) {
const age = Date.now() - new Date(timestamp).getTime()
const hours = Math.floor(age / (1000 * 60 * 60))
const days = Math.floor(hours / 24)
if (days > 0) return <span>{days}d ago</span>
if (hours > 0) return <span>{hours}h ago</span>
return <span>Just built</span>
}The vite.config.js defines global constants using Vite's define option:
- Reads
versionfrompackage.json - Executes git commands (
git rev-parse,git branch) to capture commit and branch - Generates ISO 8601 build timestamp
- Checks for
VITE_RELEASE_TAGenvironment variable (set in CI for releases)
// vite.config.js
export default defineConfig({
define: {
__APP_VERSION__: JSON.stringify(pkg.version),
__GIT_COMMIT_SHA__: JSON.stringify(gitSHA),
__GIT_BRANCH__: JSON.stringify(gitBranch),
__BUILD_TIMESTAMP__: JSON.stringify(new Date().toISOString()),
__BUILD_ENV__: JSON.stringify(process.env.NODE_ENV || 'development'),
__RELEASE_TAG__: JSON.stringify(process.env.VITE_RELEASE_TAG),
},
// ... other config
})Add global type declarations so TypeScript recognizes these constants:
// src/vite-env.d.ts
/// <reference types="vite/client" />
declare const __APP_VERSION__: string
declare const __GIT_COMMIT_SHA__: string
declare const __GIT_BRANCH__: string
declare const __BUILD_TIMESTAMP__: string
declare const __BUILD_ENV__: 'development' | 'production'
declare const __RELEASE_TAG__: string | undefinedCreate a reusable component that formats and displays version information:
// src/components/VersionInfo.tsx
export function VersionInfo() {
const isRelease = !!__RELEASE_TAG__
const buildDate = new Date(__BUILD_TIMESTAMP__)
// Format build date/time in user's local timezone
const localDateStr = buildDate.toLocaleDateString()
const localTimeStr = buildDate.toLocaleTimeString([], {
hour: '2-digit',
minute: '2-digit'
})
return (
<div className="version-info">
<div className="version-primary">
{isRelease ? `Release ${__RELEASE_TAG__}` : `v${__APP_VERSION__}`}
</div>
<div className="version-meta">
Build: {__GIT_COMMIT_SHA__} on {__GIT_BRANCH__}
<br />
Built: {localDateStr} at {localTimeStr}
</div>
</div>
)
}Compact version for footer:
// src/components/VersionBadge.tsx
export function VersionBadge() {
const buildDate = new Date(__BUILD_TIMESTAMP__)
const version = __RELEASE_TAG__ || `v${__APP_VERSION__}`
// Show local date for user readability
const localDateStr = buildDate.toLocaleDateString()
return (
<div className="version-badge">
{version} • Build {__GIT_COMMIT_SHA__} • {localDateStr}
</div>
)
}Detailed version for About tab:
// src/components/VersionDetail.tsx
export function VersionDetail() {
const isRelease = !!__RELEASE_TAG__
const buildDate = new Date(__BUILD_TIMESTAMP__)
const repoUrl = 'https://github.com/devalbo/tb-solid-pod'
// Format for display: local time for users, UTC for reference
const localDateTime = buildDate.toLocaleString('en-US', {
year: 'numeric',
month: 'short',
day: 'numeric',
hour: '2-digit',
minute: '2-digit',
second: '2-digit'
})
return (
<div className="version-detail">
<h3>Version Information</h3>
<dl>
<dt>Version</dt>
<dd>{isRelease ? __RELEASE_TAG__ : `${__APP_VERSION__} (development)`}</dd>
<dt>Commit</dt>
<dd>
<a href={`${repoUrl}/commit/${__GIT_COMMIT_SHA__}`} target="_blank">
{__GIT_COMMIT_SHA__}
</a>
</dd>
<dt>Branch</dt>
<dd>{__GIT_BRANCH__}</dd>
<dt>Built</dt>
<dd>{localDateTime}</dd>
<dt>Build Timestamp (UTC)</dt>
<dd><code>{buildDate.toISOString()}</code></dd>
<dt>Environment</dt>
<dd>{__BUILD_ENV__}</dd>
</dl>
{isRelease && (
<a href={`${repoUrl}/releases/tag/${__RELEASE_TAG__}`} target="_blank">
View release notes
</a>
)}
</div>
)
}Note: The "Built" field shows local time for user convenience, while "Build Timestamp (UTC)" shows the original UTC value for debugging and reference.
### 4. Integration in App
The version info appears in the demo page (`App.tsx`), typically in:
- **Footer** — Always visible, subtle styling
- **About tab** — Detailed build information with links
- **CLI info command** — Terminal output for programmatic access
```tsx
// App.tsx
<footer className="app-footer">
<VersionInfo />
</footer>
The .github/workflows/pages.yml workflow builds on every push to main:
- name: Build
env:
BASE_PATH: "/tb-solid-pod/"
run: npm run buildDevelopment builds show:
- Version from
package.json(e.g.,v0.1.0) - Latest commit SHA on
main - "Development build" indicator
- Build timestamp: UTC time when GitHub Actions runner executed the build
Build time considerations:
- GitHub Actions runs in UTC timezone
- Build time is stored in UTC (ISO 8601 format)
- Users see build time converted to their local timezone in the UI
- Typical build takes 2-3 minutes from push to deployment
Example timeline:
18:30:00 UTC — Developer pushes to main (10:30 AM PST)
18:30:05 UTC — GitHub Actions starts workflow
18:30:45 UTC — Build completes (timestamp: 2026-01-31T18:30:45.123Z)
18:31:30 UTC — Deployed to GitHub Pages
18:32:00 UTC — User visits page
- PST user sees: "Built: 1/31/2026 at 10:30 AM"
- EST user sees: "Built: 1/31/2026 at 1:30 PM"
- UTC user sees: "Built: 1/31/2026 at 6:30 PM"
- All can view UTC timestamp for reference: 2026-01-31T18:30:45.123Z
For tagged releases, extend the workflow to detect tags:
- name: Build release
if: startsWith(github.ref, 'refs/tags/')
env:
BASE_PATH: "/tb-solid-pod/"
VITE_RELEASE_TAG: ${{ github.ref_name }}
run: npm run buildRelease builds show:
- Release tag (e.g.,
Release v0.1.0) - Commit SHA and branch
- Build timestamp: UTC time when release build executed
- Link to GitHub releases page
Release build timing:
When you push a tag, the build is triggered immediately:
# Developer pushes tag at 19:00 UTC (2:00 PM EST on Jan 31, 2026)
git push origin v0.2.0
# GitHub Actions starts: ~19:00 UTC
# Build completes: ~19:03 UTC
# Build timestamp: 2026-01-31T19:03:15.456Z (stored in UTC)
# Users see in their local timezone:
# EST: "Built: Jan 31, 2026, 2:03 PM"
# PST: "Built: Jan 31, 2026, 11:03 AM"
# UTC: "Built: Jan 31, 2026, 7:03 PM"
# With UTC reference always available: 2026-01-31T19:03:15.456ZTimestamp accuracy:
- Commit time vs Build time: The git commit has its own timestamp. The build timestamp is when the CI system compiled the code, typically a few minutes later.
- Build vs Deploy: GitHub Pages deployment adds another 30-60 seconds after the build completes.
- Users care about build time (when the code was compiled), not deploy time.
- Timestamps stored in UTC, displayed in user's local timezone for better UX.
To build on tags, update the workflow trigger:
on:
push:
branches: [main]
tags:
- 'v*' # Trigger on version tags (v0.1.0, v1.2.3, etc.)We follow Semantic Versioning (MAJOR.MINOR.PATCH):
- MAJOR (0.x.x → 1.0.0) — Breaking changes, incompatible API changes
- MINOR (0.1.x → 0.2.0) — New features, backward-compatible additions
- PATCH (0.1.0 → 0.1.1) — Bug fixes, backward-compatible fixes
The project is currently 0.1.0 (pre-release):
- API is not stable
- Breaking changes may occur in minor versions
- Once stable, we'll release 1.0.0
Follow these steps to cut a new release:
Before you start:
- All changes merged to
main - Tests passing locally
- Build succeeds locally
- You've decided on version number (patch/minor/major)
To release:
- Run
npm version [patch|minor|major]to bump version and create tag - Push commits:
git push origin main - Push tag:
git push --tags - Wait for GitHub Actions to complete
- Create GitHub Release with notes
- Verify live demo shows correct version
- Ensure all changes are merged — All features and fixes for the release should be merged to
main - Run tests locally — Verify all tests pass:
npm run test:run npm run test:e2e
- Build locally — Ensure the build succeeds:
npm run build
- Review changes — Look at commits since last release:
(Replace
git log v0.1.0..HEAD --oneline
v0.1.0with the last release tag)
Choose the appropriate version bump based on changes:
- Patch (0.1.0 → 0.1.1) — Bug fixes only, no new features
- Minor (0.1.0 → 0.2.0) — New features, backward-compatible
- Major (0.1.0 → 1.0.0) — Breaking changes
Use npm version commands (recommended):
# For a minor release (new features)
npm version minor -m "Release v%s"
# This does three things:
# 1. Updates package.json version (0.1.0 → 0.2.0)
# 2. Creates a git commit with message "Release v0.2.0"
# 3. Creates a git tag "v0.2.0"Or manually:
# 1. Edit package.json, change version: "0.2.0"
# 2. Commit the change
git add package.json
git commit -m "Bump version to 0.2.0"
# 3. Create annotated tag
git tag -a v0.2.0 -m "Release v0.2.0"# Push the commit
git push origin main
# Push the tag (triggers release build in CI)
git push origin v0.2.0
# Or push all tags at once
git push --tagsImportant: The tag push triggers the GitHub Actions workflow to build the release with VITE_RELEASE_TAG set.
- Go to the repository on GitHub
- Click Releases (right sidebar)
- Click Draft a new release
- Select the tag you just pushed (e.g.,
v0.2.0) - Set release title:
Release v0.2.0orv0.2.0 - Add release notes:
## What's New in v0.2.0 ### Features - Added version display to demo page - Implemented contact search ### Bug Fixes - Fixed persona form validation ### Internal - Updated dependencies - Improved build process **Full Changelog**: https://github.com/devalbo/tb-solid-pod/compare/v0.1.0...v0.2.0
- Optionally attach artifacts (e.g.,
dist.zipof built files) - Click Publish release
-
Check GitHub Actions — Verify the workflow completed successfully:
- Go to Actions tab in GitHub
- Look for the workflow triggered by the tag push
- Ensure "Deploy to GitHub Pages" succeeded
-
Check the live demo — Visit the deployed page and verify version:
- Open browser console, look for version log
- Check footer shows correct version
- Verify "Release v0.2.0" appears (not "Development build")
-
Test the tagged build — Clone fresh and test:
git clone https://github.com/devalbo/tb-solid-pod.git test-release cd test-release git checkout v0.2.0 npm install npm run build npm run preview
- Update README.md if needed (version number, new features)
- Notify users/collaborators
- Update any external documentation
# Patch release (0.1.0 → 0.1.1) - Bug fixes
npm version patch -m "Release v%s"
# Minor release (0.1.0 → 0.2.0) - New features
npm version minor -m "Release v%s"
# Major release (0.1.0 → 1.0.0) - Breaking changes
npm version major -m "Release v%s"
# Always push the tag after versioning
git push origin main && git push --tagsThese commands update package.json and create a git tag automatically.
For urgent bug fixes on a released version:
-
Create hotfix branch from tag:
git checkout -b hotfix-0.1.1 v0.1.0
-
Apply fixes and test:
# Make fixes, commit changes git commit -m "Fix critical bug in contact form"
-
Version bump (patch only):
npm version patch -m "Hotfix v%s" -
Merge back to main:
git checkout main git merge hotfix-0.1.1
-
Push tag:
git push origin main git push origin v0.1.1
For alpha/beta releases, use npm version with pre-release identifier:
# Alpha release (0.2.0-alpha.1)
npm version prerelease --preid=alpha -m "Release v%s"
# Beta release (0.2.0-beta.1)
npm version prerelease --preid=beta -m "Release v%s"
# Release candidate (0.2.0-rc.1)
npm version prerelease --preid=rc -m "Release v%s"Pre-release versions should be tagged but typically don't get a full GitHub Release.
Visible on all tabs, minimal design:
tb-solid-pod v0.1.0 • Build abc1234 • Jan 31, 2026
Implementation:
// App.tsx footer
<footer className="app-footer">
<VersionBadge />
</footer>CSS styling:
.app-footer {
padding: 1rem;
text-align: center;
font-size: 0.875rem;
color: #666;
border-top: 1px solid #eee;
}
.version-badge {
font-family: monospace;
}Note: Date shown in user's local format. For detailed timestamp, see About tab.
Detailed version panel with:
- Full version and release status
- Git commit with link to GitHub commit
- Branch name
- Build date/time in user's local timezone
- Build timestamp in UTC for reference
- Environment (dev/prod)
- Link to GitHub releases page
Example output:
Version Information
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Version: Release v0.2.0
Commit: abc1234 (view on GitHub)
Branch: main
Built: Jan 31, 2026, 10:30:45 AM
Build Timestamp (UTC): 2026-01-31T18:30:45.123Z
Environment: production
[View release notes →]
Note: "Built" shows local time for user convenience. "Build Timestamp (UTC)" shows the original UTC value for debugging.
Implementation:
// App.tsx - About tab content
<div className="about-tab">
<h2>About tb-solid-pod</h2>
<p>Browser-based Solid-style data pod...</p>
<VersionDetail />
</div>Terminal command for programmatic access:
> info version
tb-solid-pod v0.1.0
Build: abc1234 on main
Built: 2026-01-31T18:30:45.123Z (6h ago)
Environment: productionImplementation:
// src/cli/commands/info.tsx
export function InfoCommand() {
const buildDate = new Date(__BUILD_TIMESTAMP__)
const hoursAgo = Math.floor((Date.now() - buildDate.getTime()) / (1000 * 60 * 60))
return (
<Box flexDirection="column">
<Text>tb-solid-pod v{__APP_VERSION__}</Text>
<Text>Build: {__GIT_COMMIT_SHA__} on {__GIT_BRANCH__}</Text>
<Text>Built: {__BUILD_TIMESTAMP__} ({hoursAgo}h ago)</Text>
<Text>Environment: {__BUILD_ENV__}</Text>
</Box>
)
}JSON output option:
> info version --json
{
"version": "0.1.0",
"commit": "abc1234",
"branch": "main",
"buildTimestamp": "2026-01-31T18:30:45.123Z",
"environment": "production",
"releaseTag": "v0.1.0"
}Note: CLI output shows UTC ISO 8601 format (not local time) for consistency with logs and programmatic use. The relative time ("6h ago") is timezone-agnostic.
For debugging, version info is logged on app load (all times in UTC):
console.log('tb-solid-pod', {
version: __APP_VERSION__,
commit: __GIT_COMMIT_SHA__,
branch: __GIT_BRANCH__,
built: __BUILD_TIMESTAMP__, // ISO 8601 UTC: "2026-01-31T18:30:45.123Z"
environment: __BUILD_ENV__,
})Console output example:
tb-solid-pod {
version: "0.1.0",
commit: "abc1234",
branch: "main",
built: "2026-01-31T18:30:45.123Z",
environment: "production"
}
When tb-solid-pod is used as a library (installed via npm install github:devalbo/tb-solid-pod):
- Version constants are not included in library exports
- Consumers use
package.jsonversion directly - Build metadata is relevant only for the demo app
- Library consumers should implement their own versioning for their apps
The version display component (VersionInfo) is not exported from src/index.ts since it references build-time constants that don't exist in library context.
# Short SHA (7 characters)
git rev-parse --short=7 HEAD
# Output: abc1234# Current branch name
git rev-parse --abbrev-ref HEAD
# Output: main (or feature-branch-name)In CI, the repository may be in "detached HEAD" state:
# Check if HEAD is detached
if git symbolic-ref --short HEAD 2>/dev/null; then
# Normal branch
BRANCH=$(git rev-parse --abbrev-ref HEAD)
else
# Detached HEAD (use tag or SHA)
BRANCH=$(git describe --tags --exact-match 2>/dev/null || echo "detached")
fiThe build process requires git to be available:
- Local development: git is typically installed
- CI: GitHub Actions runners include git
- Docker: Include git in the build image if building in containers
If git is unavailable, fall back to safe defaults:
- SHA:
"unknown" - Branch:
"unknown" - Log a build warning but don't fail the build
Link version display to CHANGELOG.md:
<a href={`${getAssetBase()}/CHANGELOG.md#v${__APP_VERSION__}`}>
Release notes
</a>Compare current version with latest from GitHub API:
async function checkForUpdates() {
const res = await fetch('https://api.github.com/repos/devalbo/tb-solid-pod/releases/latest')
const latest = await res.json()
if (latest.tag_name !== `v${__APP_VERSION__}`) {
showUpdateNotification(latest.tag_name)
}
}Store version history in LocalStorage to track updates:
const versionHistory = [
{ version: '0.1.0', firstSeen: '2026-01-15T...' },
{ version: '0.2.0', firstSeen: '2026-01-31T...' },
]Add CI build number for traceability:
env:
VITE_BUILD_NUMBER: ${{ github.run_number }}Include commit message in build info:
git log -1 --pretty=%BUseful for "What changed in this build?" context.
- AGENTS.md — Project overview and conventions
- PRINCIPLES_AND_GOALS.md — Core principles
- SDLC_PROCESS.md — Development lifecycle and release process
- GitHub Actions documentation
- Vite define documentation
- Semantic Versioning
Problem: Build timestamp shows an old date or incorrect time.
Causes:
- Cached build artifacts — Vite cached the previous build
- Browser caching — Browser is showing an old version of the page
- Incorrect local timezone interpretation — Browser timezone settings may be wrong
Solutions:
# Clear Vite cache and rebuild
rm -rf node_modules/.vite dist/
npm run build
# For browser caching
# Hard refresh: Ctrl+Shift+R (Windows/Linux) or Cmd+Shift+R (Mac)
# Or open DevTools → Network → Disable cache
# Check browser timezone (if local time seems wrong)
# JavaScript console: Intl.DateTimeFormat().resolvedOptions().timeZone
# Should return your expected timezone like "America/New_York"If local time display seems wrong:
// In browser console, check the timestamp and your timezone:
console.log('Stored UTC:', __BUILD_TIMESTAMP__)
console.log('As Date:', new Date(__BUILD_TIMESTAMP__))
console.log('Local string:', new Date(__BUILD_TIMESTAMP__).toLocaleString())
console.log('Your timezone:', Intl.DateTimeFormat().resolvedOptions().timeZone)Problem: Pushed a tag but version shows "Development build" instead of "Release v0.2.0"
Checklist:
- ✓ Tag was pushed:
git ls-remote --tags origin - ✓ Workflow triggered on tag: Check GitHub Actions → workflow run shows tag name
- ✓
VITE_RELEASE_TAGwas set in workflow - ✓ Build completed successfully
- ✓ Deployment to GitHub Pages succeeded
Verify workflow trigger:
# .github/workflows/pages.yml should include:
on:
push:
branches: [main]
tags:
- 'v*'Check environment variable:
# Build step should set VITE_RELEASE_TAG for tags
- name: Build
if: startsWith(github.ref, 'refs/tags/')
env:
VITE_RELEASE_TAG: ${{ github.ref_name }}
run: npm run buildProblem: Building in Docker container, git commands in vite.config.js fail.
Solution: Install git in the Docker image:
FROM node:20-alpine
RUN apk add --no-cache git
WORKDIR /app
COPY . .
RUN npm ci && npm run buildFallback: Modify vite.config.js to handle git failures gracefully:
function getGitSHA() {
try {
return execSync('git rev-parse --short=7 HEAD').toString().trim()
} catch (e) {
console.warn('Git not available, using fallback SHA')
return 'unknown'
}
}Problem: Updated package.json to 0.2.0 but app still shows v0.1.0.
Causes:
- Didn't rebuild after updating
package.json - Browser cached old bundle
- Deployed wrong branch/commit
Solutions:
# 1. Rebuild
npm run build
# 2. Check package.json is correct
cat package.json | grep version
# 3. Verify bundle has new version (after build)
grep -r "__APP_VERSION__" dist/assets/*.js
# 4. Hard refresh browserProblem: Build timestamp shows a date in the future (in user's local time).
Causes:
- Clock skew on build machine (rare with GitHub Actions)
- Browser timezone is incorrect
- System clock is wrong on user's machine
Verification:
# Check build server time (GitHub Actions uses UTC, should be correct)
date -u
# Check your local system time
date
# Verify timezone setting
# macOS: System Preferences → Date & Time
# Linux: timedatectl
# Windows: Settings → Time & LanguageFix for local builds with wrong time:
# macOS: Enable automatic time sync
sudo systemsetup -setusingnetworktime on
# Linux: Sync with NTP
sudo ntpdate -s time.nist.gov
# Verify
date -u # Should show correct UTC timeImportant: Build systems should use UTC (GitHub Actions does). User browsers convert UTC to local time for display.
Problem: Tagged release but GitHub Actions failed, or build succeeded but deployment failed.
Recovery:
# If workflow failed, fix the issue and re-run the workflow:
# 1. Go to GitHub Actions → Failed workflow
# 2. Click "Re-run failed jobs"
# If you need to delete and recreate the tag:
git tag -d v0.2.0 # Delete local tag
git push origin :refs/tags/v0.2.0 # Delete remote tag
# Fix the issue, then recreate tag
git tag v0.2.0
git push origin v0.2.0Important: Deleting and recreating tags should be done carefully and only before anyone has installed/used that release.