feat: teach the public v1 beta
Resolve the immutable Beta 1 runtime first, verify the exact compiler identity on Linux and Windows, and commit generated outputs from the released ABI. Material implementation and review were assisted by OpenAI Codex. Cole Speelman reviewed the public tutorial and accepts human responsibility. Signed-off-by: Cole Speelman <crspeelman@gmail.com>
This commit is contained in:
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
# SPDX-License-Identifier: 0BSD
|
# SPDX-License-Identifier: 0BSD
|
||||||
|
|
||||||
# The current preview runtime is connected through a local workspace only.
|
# Local workspaces must not override the published tutorial dependencies.
|
||||||
go.work
|
go.work
|
||||||
go.work.sum
|
go.work.sum
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -3,8 +3,8 @@
|
|||||||
# Generated code
|
# Generated code
|
||||||
|
|
||||||
Every `*.sando.go` file is an owned output of the neighboring `*.sando` source.
|
Every `*.sando.go` file is an owned output of the neighboring `*.sando` source.
|
||||||
Commit both files so production builds need only ordinary Go and the small
|
The exact generator is `himesan v1.0.0-beta.1`. Commit both files so production
|
||||||
`sando` runtime.
|
builds need only ordinary Go and the small `sando` runtime.
|
||||||
|
|
||||||
Never hand-edit a generated neighbor. Run `himesan generate internal/views`,
|
Never hand-edit a generated neighbor. Run `himesan generate internal/views`,
|
||||||
review the deterministic diff, and use `himesan check internal/views` in local
|
review the deterministic diff, and use `himesan check internal/views` in local
|
||||||
|
|||||||
@@ -25,34 +25,43 @@ The starter demonstrates the boundary plainly:
|
|||||||
time through `Server-Timing`.
|
time through `Server-Timing`.
|
||||||
- Production imports the Apache-2.0 `sando` runtime, not the compiler.
|
- Production imports the Apache-2.0 `sando` runtime, not the compiler.
|
||||||
|
|
||||||
## Run the current source preview
|
## Walk the path with Beta 1
|
||||||
|
|
||||||
Sandwich Hime does not have immutable public release tags yet. Do not invent a
|
Install Go 1.25 or newer, then resolve the tiny runtime before installing the
|
||||||
version-shaped install command: clone the compiler and this starter side by
|
immutable classroom compiler:
|
||||||
side, then use a local Go workspace as an explicit preview bridge.
|
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
mkdir sandwich-hime-walk
|
|
||||||
cd sandwich-hime-walk
|
|
||||||
|
|
||||||
git clone https://gitea.speelman.ca/gamertan/sandwich-hime.git
|
|
||||||
git clone https://gitea.speelman.ca/gamertan/sandwich-hime-tutorial.git
|
git clone https://gitea.speelman.ca/gamertan/sandwich-hime-tutorial.git
|
||||||
|
cd sandwich-hime-tutorial
|
||||||
cd sandwich-hime
|
GOWORK=off go mod download gamertan.com/sandwich-hime/sando@v1.0.0-beta.1
|
||||||
go install ./cmd/himesan
|
go install gamertan.com/sandwich-hime/cmd/himesan@v1.0.0-beta.1
|
||||||
|
|
||||||
cd ../sandwich-hime-tutorial
|
|
||||||
go work init .
|
|
||||||
go work edit -replace=gamertan.com/sandwich-hime/sando=../sandwich-hime/sando
|
|
||||||
|
|
||||||
./scripts/verify.sh
|
./scripts/verify.sh
|
||||||
|
GOWORK=off go run ./cmd/site
|
||||||
|
```
|
||||||
|
|
||||||
|
On Windows PowerShell, use the native verifier:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
git clone https://gitea.speelman.ca/gamertan/sandwich-hime-tutorial.git
|
||||||
|
Set-Location sandwich-hime-tutorial
|
||||||
|
$env:GOWORK = "off"
|
||||||
|
go mod download gamertan.com/sandwich-hime/sando@v1.0.0-beta.1
|
||||||
|
go install gamertan.com/sandwich-hime/cmd/himesan@v1.0.0-beta.1
|
||||||
|
.\scripts\verify.ps1
|
||||||
go run ./cmd/site
|
go run ./cmd/site
|
||||||
```
|
```
|
||||||
|
|
||||||
Make sure `$(go env GOPATH)/bin` is on `PATH`, or set `HIMESAN_BIN` to the
|
Make sure Go's install directory—normally `$(go env GOPATH)/bin`—is on
|
||||||
compiler executable when running the verification script. `go.work` and
|
`PATH`, or set `HIMESAN_BIN` to the full compiler path before running either
|
||||||
`go.work.sum` are intentionally ignored: they are local preview wiring, not a
|
verifier. The starter deliberately runs with `GOWORK=off`: it proves the
|
||||||
claim that `v0.0.0` was published.
|
application resolves the published Apache-2.0 runtime rather than a neighboring
|
||||||
|
development checkout. The verification scripts also reject any compiler or
|
||||||
|
runtime version other than `v1.0.0-beta.1`.
|
||||||
|
|
||||||
|
Beta 1 is intended for classrooms, learning, prototypes, and evaluation. Its
|
||||||
|
interfaces may still change before final v1. Linux and Windows have been
|
||||||
|
maintainer-tested; macOS is provisional while native maintainer testing is
|
||||||
|
pending. Useful Mac compatibility reports are welcome on canonical Gitea.
|
||||||
|
|
||||||
Open [http://127.0.0.1:8080/?name=Hime-san](http://127.0.0.1:8080/?name=Hime-san),
|
Open [http://127.0.0.1:8080/?name=Hime-san](http://127.0.0.1:8080/?name=Hime-san),
|
||||||
refresh it, and watch the request number and UTC time change. Then try:
|
refresh it, and watch the request number and UTC time change. Then try:
|
||||||
@@ -74,6 +83,7 @@ internal/views/views.go typed template contracts
|
|||||||
internal/views/*.sando templates people edit
|
internal/views/*.sando templates people edit
|
||||||
internal/views/*.sando.go committed generated Go
|
internal/views/*.sando.go committed generated Go
|
||||||
scripts/verify.sh generation, tests, build, and dependency gate
|
scripts/verify.sh generation, tests, build, and dependency gate
|
||||||
|
scripts/verify.ps1 the same gate for native Windows PowerShell
|
||||||
```
|
```
|
||||||
|
|
||||||
The application owns the server, routing, headers, data, and deployment.
|
The application owns the server, routing, headers, data, and deployment.
|
||||||
@@ -83,9 +93,9 @@ before accepting real user content.
|
|||||||
|
|
||||||
## What the verification gate proves
|
## What the verification gate proves
|
||||||
|
|
||||||
`./scripts/verify.sh` checks committed output, generates twice and compares
|
`./scripts/verify.sh` and `scripts/verify.ps1` check committed output, generate
|
||||||
digests, runs all tests and `go vet`, builds the server into a temporary
|
twice and compare digests, run all tests and `go vet`, build the server into a
|
||||||
directory, and inspects its Go dependency graph. The only production
|
temporary directory, and inspect its Go dependency graph. The only production
|
||||||
Sandwich Hime package allowed by that graph is
|
Sandwich Hime package allowed by that graph is
|
||||||
`gamertan.com/sandwich-hime/sando`.
|
`gamertan.com/sandwich-hime/sando`.
|
||||||
|
|
||||||
|
|||||||
@@ -4,4 +4,4 @@ module gitea.speelman.ca/gamertan/sandwich-hime-tutorial
|
|||||||
|
|
||||||
go 1.25
|
go 1.25
|
||||||
|
|
||||||
require gamertan.com/sandwich-hime/sando v0.0.0
|
require gamertan.com/sandwich-hime/sando v1.0.0-beta.1
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
gamertan.com/sandwich-hime/sando v1.0.0-beta.1 h1:WHe6LnVKvOz7CQr9OIWI78pCzIFIAGgoXlGfjYVAVoU=
|
||||||
|
gamertan.com/sandwich-hime/sando v1.0.0-beta.1/go.mod h1:awOXo4t2zNxxgH60qkTpMOdhYnultm9AfpjlN9gOEis=
|
||||||
Generated
+2
-2
@@ -1,5 +1,5 @@
|
|||||||
// Code generated by himesan; DO NOT EDIT.
|
// Code generated by himesan; DO NOT EDIT.
|
||||||
// himesan:compiler 0.1.0-dev
|
// himesan:compiler v1.0.0-beta.1
|
||||||
// himesan:runtime-abi sando.v1
|
// himesan:runtime-abi sando.v1
|
||||||
// himesan:source-sha256 241093d3b845d20c38e5a0fe5cf2213d6bb9114138818dbe98d8b3a99ff19d24
|
// himesan:source-sha256 241093d3b845d20c38e5a0fe5cf2213d6bb9114138818dbe98d8b3a99ff19d24
|
||||||
|
|
||||||
@@ -11,7 +11,7 @@ import (
|
|||||||
__himesan_io "io"
|
__himesan_io "io"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ = __himesan_sando.ABI
|
var _ = __himesan_sando.ABISandoV1
|
||||||
|
|
||||||
func Badge(label string) __himesan_sando.Component {
|
func Badge(label string) __himesan_sando.Component {
|
||||||
return __himesan_sando.ComponentFunc(func(__himesan_render_context __himesan_context.Context, __himesan_writer __himesan_io.Writer) error {
|
return __himesan_sando.ComponentFunc(func(__himesan_render_context __himesan_context.Context, __himesan_writer __himesan_io.Writer) error {
|
||||||
|
|||||||
Generated
+2
-2
@@ -1,5 +1,5 @@
|
|||||||
// Code generated by himesan; DO NOT EDIT.
|
// Code generated by himesan; DO NOT EDIT.
|
||||||
// himesan:compiler 0.1.0-dev
|
// himesan:compiler v1.0.0-beta.1
|
||||||
// himesan:runtime-abi sando.v1
|
// himesan:runtime-abi sando.v1
|
||||||
// himesan:source-sha256 2f04e0f2e6caae73ea3d419a88c53afcaf25d300e76dc522ae2f418a03a68def
|
// himesan:source-sha256 2f04e0f2e6caae73ea3d419a88c53afcaf25d300e76dc522ae2f418a03a68def
|
||||||
|
|
||||||
@@ -11,7 +11,7 @@ import (
|
|||||||
__himesan_io "io"
|
__himesan_io "io"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ = __himesan_sando.ABI
|
var _ = __himesan_sando.ABISandoV1
|
||||||
|
|
||||||
func Home(view HomeView) __himesan_sando.Component {
|
func Home(view HomeView) __himesan_sando.Component {
|
||||||
return __himesan_sando.ComponentFunc(func(__himesan_render_context __himesan_context.Context, __himesan_writer __himesan_io.Writer) error {
|
return __himesan_sando.ComponentFunc(func(__himesan_render_context __himesan_context.Context, __himesan_writer __himesan_io.Writer) error {
|
||||||
|
|||||||
Generated
+2
-2
@@ -1,5 +1,5 @@
|
|||||||
// Code generated by himesan; DO NOT EDIT.
|
// Code generated by himesan; DO NOT EDIT.
|
||||||
// himesan:compiler 0.1.0-dev
|
// himesan:compiler v1.0.0-beta.1
|
||||||
// himesan:runtime-abi sando.v1
|
// himesan:runtime-abi sando.v1
|
||||||
// himesan:source-sha256 e56b373194349ae32dcbad4a26c1d1a3d133e335ff916cef064e12ca2901adf3
|
// himesan:source-sha256 e56b373194349ae32dcbad4a26c1d1a3d133e335ff916cef064e12ca2901adf3
|
||||||
|
|
||||||
@@ -11,7 +11,7 @@ import (
|
|||||||
__himesan_io "io"
|
__himesan_io "io"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ = __himesan_sando.ABI
|
var _ = __himesan_sando.ABISandoV1
|
||||||
|
|
||||||
func Layout(view LayoutView) __himesan_sando.Component {
|
func Layout(view LayoutView) __himesan_sando.Component {
|
||||||
return __himesan_sando.ComponentFunc(func(__himesan_render_context __himesan_context.Context, __himesan_writer __himesan_io.Writer) error {
|
return __himesan_sando.ComponentFunc(func(__himesan_render_context __himesan_context.Context, __himesan_writer __himesan_io.Writer) error {
|
||||||
|
|||||||
@@ -0,0 +1,89 @@
|
|||||||
|
# SPDX-License-Identifier: 0BSD
|
||||||
|
|
||||||
|
[CmdletBinding()]
|
||||||
|
param()
|
||||||
|
|
||||||
|
$ErrorActionPreference = "Stop"
|
||||||
|
Set-StrictMode -Version Latest
|
||||||
|
|
||||||
|
$repoRoot = Split-Path -Parent $PSScriptRoot
|
||||||
|
Set-Location $repoRoot
|
||||||
|
$env:GOWORK = "off"
|
||||||
|
|
||||||
|
$himesan = if ($env:HIMESAN_BIN) { $env:HIMESAN_BIN } else { "himesan" }
|
||||||
|
$expectedVersion = "v1.0.0-beta.1"
|
||||||
|
if (-not (Get-Command $himesan -ErrorAction SilentlyContinue)) {
|
||||||
|
throw "himesan was not found; install v1.0.0-beta.1 or set HIMESAN_BIN"
|
||||||
|
}
|
||||||
|
|
||||||
|
function Assert-LastExitCode([string]$Step) {
|
||||||
|
if ($LASTEXITCODE -ne 0) {
|
||||||
|
throw "$Step failed with exit code $LASTEXITCODE"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-GeneratedDigest {
|
||||||
|
$lines = Get-ChildItem internal/views -Recurse -File -Filter *.sando.go |
|
||||||
|
Sort-Object FullName |
|
||||||
|
ForEach-Object {
|
||||||
|
$hash = (Get-FileHash -Algorithm SHA256 -LiteralPath $_.FullName).Hash.ToLowerInvariant()
|
||||||
|
"$($_.FullName):$hash"
|
||||||
|
}
|
||||||
|
return ($lines -join "`n")
|
||||||
|
}
|
||||||
|
|
||||||
|
$versionLine = (& $himesan version | Select-Object -First 1)
|
||||||
|
Assert-LastExitCode "himesan version"
|
||||||
|
if ($versionLine -notmatch '^himesan ([^ ]+) ') {
|
||||||
|
throw "could not parse himesan version output: $versionLine"
|
||||||
|
}
|
||||||
|
if ($Matches[1] -ne $expectedVersion) {
|
||||||
|
throw "himesan version is $($Matches[1]); expected $expectedVersion"
|
||||||
|
}
|
||||||
|
|
||||||
|
$runtimeVersion = (go list -m -f '{{.Version}}' gamertan.com/sandwich-hime/sando | Select-Object -First 1)
|
||||||
|
Assert-LastExitCode "sando runtime version"
|
||||||
|
if ($runtimeVersion -ne $expectedVersion) {
|
||||||
|
throw "sando runtime version is $runtimeVersion; expected $expectedVersion"
|
||||||
|
}
|
||||||
|
|
||||||
|
& $himesan check internal/views
|
||||||
|
Assert-LastExitCode "himesan check"
|
||||||
|
$before = Get-GeneratedDigest
|
||||||
|
& $himesan generate internal/views
|
||||||
|
Assert-LastExitCode "first himesan generate"
|
||||||
|
$afterFirst = Get-GeneratedDigest
|
||||||
|
& $himesan generate internal/views
|
||||||
|
Assert-LastExitCode "second himesan generate"
|
||||||
|
$afterSecond = Get-GeneratedDigest
|
||||||
|
& $himesan check internal/views
|
||||||
|
Assert-LastExitCode "final himesan check"
|
||||||
|
|
||||||
|
if ($before -ne $afterFirst -or $afterFirst -ne $afterSecond) {
|
||||||
|
throw "generated output was stale or nondeterministic"
|
||||||
|
}
|
||||||
|
|
||||||
|
go test ./...
|
||||||
|
Assert-LastExitCode "go test"
|
||||||
|
go vet ./...
|
||||||
|
Assert-LastExitCode "go vet"
|
||||||
|
|
||||||
|
$buildDir = Join-Path ([System.IO.Path]::GetTempPath()) ("sandwich-hime-tutorial-" + [guid]::NewGuid().ToString("N"))
|
||||||
|
New-Item -ItemType Directory -Path $buildDir | Out-Null
|
||||||
|
try {
|
||||||
|
go build -trimpath -o (Join-Path $buildDir "site.exe") ./cmd/site
|
||||||
|
Assert-LastExitCode "go build"
|
||||||
|
} finally {
|
||||||
|
Remove-Item -LiteralPath $buildDir -Recurse -Force -ErrorAction SilentlyContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
$dependencies = @(go list -deps ./cmd/site)
|
||||||
|
Assert-LastExitCode "go list -deps"
|
||||||
|
if ($dependencies -notcontains "gamertan.com/sandwich-hime/sando") {
|
||||||
|
throw "production dependency graph does not contain the sando runtime"
|
||||||
|
}
|
||||||
|
if ($dependencies | Where-Object { $_ -match '^gamertan\.com/sandwich-hime$|^gamertan\.com/sandwich-hime/(cmd|internal)(/|$)' }) {
|
||||||
|
throw "production dependency graph contains the Sandwich Hime compiler"
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Output "verified Beta 1 identity, deterministic generation, tests, vet, build, and runtime-only production dependencies"
|
||||||
+15
-4
@@ -7,12 +7,23 @@ repo_root=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)
|
|||||||
cd "$repo_root"
|
cd "$repo_root"
|
||||||
|
|
||||||
himesan_bin=${HIMESAN_BIN:-himesan}
|
himesan_bin=${HIMESAN_BIN:-himesan}
|
||||||
|
expected_version=v1.0.0-beta.1
|
||||||
if ! command -v "$himesan_bin" >/dev/null 2>&1; then
|
if ! command -v "$himesan_bin" >/dev/null 2>&1; then
|
||||||
echo "himesan was not found; install it from the neighboring Sandwich Hime checkout or set HIMESAN_BIN" >&2
|
echo "himesan was not found; install v1.0.0-beta.1 or set HIMESAN_BIN" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
if [[ ! -f go.work ]]; then
|
|
||||||
echo "go.work is missing; follow the README preview bridge commands first" >&2
|
export GOWORK=off
|
||||||
|
|
||||||
|
actual_version=$("$himesan_bin" version | awk 'NR == 1 { print $2 }')
|
||||||
|
if [[ "$actual_version" != "$expected_version" ]]; then
|
||||||
|
echo "himesan version is $actual_version; expected $expected_version" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
runtime_version=$(go list -m -f '{{.Version}}' gamertan.com/sandwich-hime/sando)
|
||||||
|
if [[ "$runtime_version" != "$expected_version" ]]; then
|
||||||
|
echo "sando runtime version is $runtime_version; expected $expected_version" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -53,4 +64,4 @@ if grep -Eq '^gamertan\.com/sandwich-hime$|^gamertan\.com/sandwich-hime/(cmd|int
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "verified deterministic generation, tests, vet, build, and runtime-only production dependencies"
|
echo "verified Beta 1 identity, deterministic generation, tests, vet, build, and runtime-only production dependencies"
|
||||||
|
|||||||
Reference in New Issue
Block a user