refactor: keep compiler source standalone

Signed-off-by: Cole Speelman <crspeelman@gmail.com>
This commit is contained in:
2026-08-11 23:58:25 -04:00
parent 0941075baa
commit 7b839f8155
40 changed files with 130 additions and 1581 deletions
+2 -1
View File
@@ -13,13 +13,14 @@ Sandwich Hime follows semantic versioning after v1. Compiler and nested runtime
- Read-only stale-output checking and structured diagnostics. - Read-only stale-output checking and structured diagnostics.
- Independent Apache-2.0 `sando` component/runtime ABI. - Independent Apache-2.0 `sando` component/runtime ABI.
- Loopback-only last-good development supervisor with SSE reload and diagnostic overlay. - Loopback-only last-good development supervisor with SSE reload and diagnostic overlay.
- Synthetic EQL-shaped proof fixture and production pilot plan. - Compiler-owned deterministic golden fixture and standalone release gates.
- Multi-license, security, governance, trademark, AI contribution, and release policies. - Multi-license, security, governance, trademark, AI contribution, and release policies.
### Removed ### Removed
- Unpublished `.go.hime` syntax and 2025 generated API. - Unpublished `.go.hime` syntax and 2025 generated API.
- Injected helper directories, nested demo modules, Go plugins, and manually repaired generated output. - Injected helper directories, nested demo modules, Go plugins, and manually repaired generated output.
- Repository-bundled application examples and deployment-specific evidence.
- Placeholder novelty commands that did not perform project work. - Placeholder novelty commands that did not perform project work.
Private prototype history is intentionally outside the sanitized public repository. The public changelog begins with the pre-1.0 source preview. Private prototype history is intentionally outside the sanitized public repository. The public changelog begins with the pre-1.0 source preview.
+7 -3
View File
@@ -2,7 +2,11 @@
# Contributing # Contributing
The canonical public project and only contribution venue is the Gamertan Gitea repository. Repository maintainers may temporarily disable issue or patch intake during the pre-1.0 preview; do not route around a closed intake channel by sending unsolicited private patches. The canonical public project and only contribution venue is the
[founder-controlled Gitea repository](https://gitea.speelman.ca/gamertan/sandwich-hime).
Repository maintainers may temporarily disable issue or patch intake during the
pre-1.0 preview; do not route around a closed intake channel by sending
unsolicited private patches.
Public pre-1.0 contributions use Developer Certificate of Origin 1.1 sign-off. The proposed `CLA.md` is an inactive draft, is not a condition of contribution, and creates no contributor or project obligations. If a contribution agreement is ever activated after legal review, the project will announce its prospective terms rather than silently applying the draft. Public pre-1.0 contributions use Developer Certificate of Origin 1.1 sign-off. The proposed `CLA.md` is an inactive draft, is not a condition of contribution, and creates no contributor or project obligations. If a contribution agreement is ever activated after legal review, the project will announce its prospective terms rather than silently applying the draft.
@@ -13,10 +17,10 @@ go test ./...
go test -race ./... go test -race ./...
go vet ./... go vet ./...
(cd sando && go test -race ./... && go vet ./...) (cd sando && go test -race ./... && go vet ./...)
go run ./cmd/himesan check ./examples/eql-shaped ./scripts/check-licenses.sh
``` ```
Changes require focused tests, stable diagnostics, formatted generated goldens when applicable, documentation for public behavior, and a signed-off commit (`git commit -s`). The sign-off certifies the [DCO](DCO.txt); it is not a copyright assignment or acceptance of the inactive CLA. Do not commit an EQL database, production data, secrets, build candidates, or developer cache files. Changes require focused tests, stable diagnostics, formatted generated goldens when applicable, documentation for public behavior, and a signed-off commit (`git commit -s`). The sign-off certifies the [DCO](DCO.txt); it is not a copyright assignment or acceptance of the inactive CLA. Do not commit production data, private application fixtures, secrets, build candidates, or developer cache files.
The project requires no copyright assignment. Ownership remains determined by applicable law and any employer or other agreement. Contributors submit each file under the license identified for that repository area, and the DCO records their certification that they have the right to do so. Material AI assistance must follow [AI_CONTRIBUTIONS.md](AI_CONTRIBUTIONS.md). Review considers provenance, safety, maintenance cost, compatibility, and fit—not just whether code passes tests. The project requires no copyright assignment. Ownership remains determined by applicable law and any employer or other agreement. Contributors submit each file under the license identified for that repository area, and the DCO records their certification that they have the right to do so. Material AI assistance must follow [AI_CONTRIBUTIONS.md](AI_CONTRIBUTIONS.md). Review considers provenance, safety, maintenance cost, compatibility, and fit—not just whether code passes tests.
+10 -5
View File
@@ -7,10 +7,9 @@ Sandwich Hime deliberately separates the development tool from application runti
| Path or material | License | | Path or material | License |
| --- | --- | | --- | --- |
| Project-authored files in the repository root, `cmd/**`, `internal/**`, `docs/**`, `scripts/**`, and `site/**`, except the legal texts listed below | AGPL-3.0-only | | Project-authored files in the repository root, `cmd/**`, `internal/**`, `docs/**`, and `scripts/**`, except the legal texts listed below | AGPL-3.0-only |
| Nested `sando/**` runtime module, except its verbatim license text | Apache-2.0 | | Nested `sando/**` runtime module, except its verbatim license text | Apache-2.0 |
| Copyable `examples/**`, except their generated-file treatment described below | 0BSD | | `LICENSE`, `sando/LICENSE`, and `DCO.txt` | Their own stated copying terms and notices |
| `LICENSE`, `sando/LICENSE`, example `LICENSE` files, and `DCO.txt` | Their own stated copying terms and notices |
| User-authored `.sando` templates | Chosen by their author, subject to rights in their inputs | | User-authored `.sando` templates | Chosen by their author, subject to rights in their inputs |
| Generated application `.sando.go` files | Chosen by the template/application author, subject to rights in their inputs and dependencies | | Generated application `.sando.go` files | Chosen by the template/application author, subject to rights in their inputs and dependencies |
@@ -18,13 +17,19 @@ Sandwich Hime claims no copyright in a user's template merely because the compil
The AGPL compiler is a separately installed development process. The Apache runtime must never import an AGPL package. Importing the Apache runtime or using generated output does not, by itself, incorporate the compiler into an application. Redistribution of the runtime remains subject to Apache-2.0 and any other applicable third-party obligations. The AGPL compiler is a separately installed development process. The Apache runtime must never import an AGPL package. Importing the Apache runtime or using generated output does not, by itself, incorporate the compiler into an application. Redistribution of the runtime remains subject to Apache-2.0 and any other applicable third-party obligations.
`COPYRIGHT` identifies Cole Speelman's original project work without claiming contributor-owned work. The nested runtime carries its own `sando/COPYRIGHT`, and the example identifies its original author in `examples/eql-shaped/LICENSE`. The project requires no copyright assignment; ownership of contributions remains determined by applicable law and existing agreements. The `.sando` source and committed `.sando.go` output under
`internal/compiler/testdata/golden/**` are non-copyable compiler test fixtures
covered by the AGPL `internal/**` map above. The generated fixture intentionally
has no inline SPDX header because that absence is one of the generator's tested
application-output properties.
`COPYRIGHT` identifies Cole Speelman's original project work without claiming contributor-owned work. The nested runtime carries its own `sando/COPYRIGHT`. The project requires no copyright assignment; ownership of contributions remains determined by applicable law and existing agreements.
A compiler contribution that adds text intended to be copied into generated output must record the `Himesan-Output-Permission: v1.0` grant required by [CONTRIBUTING.md](CONTRIBUTING.md). Without that grant, the contribution must be designed so its contributor-owned text is not emitted. DCO sign-off alone does not grant the additional output permission. A compiler contribution that adds text intended to be copied into generated output must record the `Himesan-Output-Permission: v1.0` grant required by [CONTRIBUTING.md](CONTRIBUTING.md). Without that grant, the contribution must be designed so its contributor-owned text is not emitted. DCO sign-off alone does not grant the additional output permission.
Official flags, mascots, and badges are not covered merely because they use a project mark. Each published asset must identify its copyright holder and reuse license. Official flags, mascots, and badges are not covered merely because they use a project mark. Each published asset must identify its copyright holder and reuse license.
SPDX identifiers state the applicable license for comment-capable source and documentation. Directory-level maps cover generated files and formats such as JSON that cannot safely carry comments. Full license texts are at `LICENSE` and `sando/LICENSE`; examples carry their own `LICENSE` and `LICENSES.md`. License texts and the verbatim `DCO.txt` retain their own notices and are not relicensed as project documentation. SPDX identifiers state the applicable license for comment-capable source and documentation. Directory-level maps cover generated files and formats such as JSON that cannot safely carry comments. Full license texts are at `LICENSE` and `sando/LICENSE`. Copyable examples are maintained in separate repositories and must declare their own licenses; official copyable examples are intended to use 0BSD. License texts and the verbatim `DCO.txt` retain their own notices and are not relicensed as project documentation.
The snapshot exporter's `PUBLIC-SNAPSHOT.json` and `PUBLIC-SNAPSHOT.sha256` are generated factual provenance records and intentionally carry no inline SPDX comment. They do not change the license of any listed file. The snapshot exporter's `PUBLIC-SNAPSHOT.json` and `PUBLIC-SNAPSHOT.sha256` are generated factual provenance records and intentionally carry no inline SPDX comment. They do not change the license of any listed file.
+1 -1
View File
@@ -1 +1 @@
{"schema_version":2,"project":"sandwich-hime","export_policy":"exact-allowlist-v1","export_mode":"release","file_count":98,"allowlist_sha256":"91213f72ddef67aaed7764f08f89fd13281bb79855f3680e1ec0d05cda0e133d","manifest_sha256":"e2eec9fed86828dff900a09f39a05021c48f295bf87a1a9b2896d673886c9a69"} {"schema_version":2,"project":"sandwich-hime","export_policy":"exact-allowlist-v1","export_mode":"release","file_count":77,"allowlist_sha256":"db978285858ba5a1fefeb732d716338d8c652c5fc583f465d08f80b9ec74f0a9","manifest_sha256":"6bc38ff6e8ee243f840dbd768769f5be718f5fd01ba26855038fa15c5e518cc9"}
+16 -37
View File
@@ -2,53 +2,35 @@
658ba4b4645426f8c3249337f47669074ae9249a31703dcd9ea4c1afec45e20b ./.gitattributes 658ba4b4645426f8c3249337f47669074ae9249a31703dcd9ea4c1afec45e20b ./.gitattributes
d5ae411fb422b2388cac220f9655900eecbc49ece961b2bb2a6610347733b756 ./.gitignore d5ae411fb422b2388cac220f9655900eecbc49ece961b2bb2a6610347733b756 ./.gitignore
98f663ab0f376b4550094465ec2e06192d1e0b0707604ec6794f20b0d10952c1 ./AI_CONTRIBUTIONS.md 98f663ab0f376b4550094465ec2e06192d1e0b0707604ec6794f20b0d10952c1 ./AI_CONTRIBUTIONS.md
cf2e75a6e087570064dc3d8d8ed313676c4e8df1d422bf483d33d81751174bdc ./CHANGELOG.md 7f4414fed21e9578b8d1a0d109ba807cb79d28a9290d58df49cc75145d9d1068 ./CHANGELOG.md
b696cab3cf482ff5737501371cca749369b119351383e698ced42bcdbcbfc8ae ./CLA.md b696cab3cf482ff5737501371cca749369b119351383e698ced42bcdbcbfc8ae ./CLA.md
af0a256657e192641b3d7cee24ece36a76287baf225f2a045da16327214ac7ec ./CONTRIBUTING.md 2d98826969cd492cc4dd10c595be21a608def5aacbec40ea5e25f1c3a617d8e6 ./CONTRIBUTING.md
86d7e49d5d90e0f98a4ad0f14b5d8b9f11ed09a1e29ecdf27388316b28e195e8 ./COPYRIGHT 86d7e49d5d90e0f98a4ad0f14b5d8b9f11ed09a1e29ecdf27388316b28e195e8 ./COPYRIGHT
f7ac75b443f4ca16b503241344b41aeff9503b0c30bedc2b119551d83cb0fa90 ./DCO.txt f7ac75b443f4ca16b503241344b41aeff9503b0c30bedc2b119551d83cb0fa90 ./DCO.txt
73cb1b092a40c56e522c5a0ebddf2b44f347cdb57bf6994cdb305d0e5697b55e ./GENERATED_CODE.md 73cb1b092a40c56e522c5a0ebddf2b44f347cdb57bf6994cdb305d0e5697b55e ./GENERATED_CODE.md
048f96acecd3af84d6abc4f8c38108dff2171445417e5132318a1d18de4279fe ./GOVERNANCE.md 048f96acecd3af84d6abc4f8c38108dff2171445417e5132318a1d18de4279fe ./GOVERNANCE.md
0d96a4ff68ad6d4b6f1f30f713b18d5184912ba8dd389f86aa7710db079abcb0 ./LICENSE 0d96a4ff68ad6d4b6f1f30f713b18d5184912ba8dd389f86aa7710db079abcb0 ./LICENSE
1b398f6e2679a4c1d6c5a03468f66b86be34e82ed40e3a029935c74742502e7a ./LICENSES.md 6587e439cb3c39dce9aaa5b51facdbd78c0e86c24e9e3fb9537b944435a74410 ./LICENSES.md
b6aa08e5ccaec3c5dccdc19d7cd7f54a70adae4d57966263c7aa353c7ba70e08 ./MAINTAINERS.md b6aa08e5ccaec3c5dccdc19d7cd7f54a70adae4d57966263c7aa353c7ba70e08 ./MAINTAINERS.md
6638db2f1fba831c79de835ce95c847a5b36c5b5c693b99a28655b2d096cc440 ./OUTPUT_EXCEPTION.md 6638db2f1fba831c79de835ce95c847a5b36c5b5c693b99a28655b2d096cc440 ./OUTPUT_EXCEPTION.md
88150b7ae8759b62829f3a0ba2b03b1c44abc2f688349d5b3ad39ebf654a29d4 ./README.md 531b3c183892c71974e25f790e8570ba72519f9299aab4031d23b62952a7682c ./README.md
6007b80cd80f8f238a1e77de6417aa0c69c159dce6f5a5bd085ef87b8865f5c9 ./RELEASE.md 00ac24b5bc5cd2b62f6176f85d4be29087c59c17f4f670edacf408d56ccc7f23 ./RELEASE.md
f5fe4d5bf5f8b72ad974060faf458ad26bb4b2c05c2bd9539533247b7462f76b ./ROADMAP.md 370c948b267527fdc2309c808b99089da33ac81346043dd54692ebb0843f6c0a ./ROADMAP.md
2c86f5b983dfeb97a02d46850fa42e18cab1ed23201822aa3c344b9d2e1b0c3f ./SECURITY.md 2c86f5b983dfeb97a02d46850fa42e18cab1ed23201822aa3c344b9d2e1b0c3f ./SECURITY.md
53bd6eda804d6b782bdb07115ec197c890813cf2d5d0125dfe8f47f5f92f75b0 ./SPEC.md 53bd6eda804d6b782bdb07115ec197c890813cf2d5d0125dfe8f47f5f92f75b0 ./SPEC.md
842beff8afa72d120fcad0ac73afb2049d580ff3000975f3b1786c4ade6a14d4 ./TRADEMARKS.md 842beff8afa72d120fcad0ac73afb2049d580ff3000975f3b1786c4ade6a14d4 ./TRADEMARKS.md
136a6d82db842547b342f8b0c9ffdc7c04f7c9b473b4ef6dca9dbc940cb24b54 ./cmd/himesan/main.go 136a6d82db842547b342f8b0c9ffdc7c04f7c9b473b4ef6dca9dbc940cb24b54 ./cmd/himesan/main.go
3011a435aaeb572d34e2d2b582865fd63268c92a9ae3f0ae1a56d1a59d83cd43 ./cmd/himesan/main_test.go 3011a435aaeb572d34e2d2b582865fd63268c92a9ae3f0ae1a56d1a59d83cd43 ./cmd/himesan/main_test.go
1ecbba46f8b1b2d548a01d7e98afae17b2dd17a814338ff1f88db885655d1c07 ./docs/ARCHITECTURE.md 1ecbba46f8b1b2d548a01d7e98afae17b2dd17a814338ff1f88db885655d1c07 ./docs/ARCHITECTURE.md
318ffcf2463036cd533b1c694f1f4840ef4b0c7c15bc049ec714bbcf4850ba15 ./docs/BENCHMARKS.md 9c598559a89fa4a9bdd2311bd1ed8330992d0a0f74ec8b29ac151fc0ff8fef16 ./docs/BENCHMARKS.md
5c3a62fed80ca28d56558b8c75e8b5be8ba7d2554127adf4609d96da314e85b0 ./docs/BRAND.md 5c3a62fed80ca28d56558b8c75e8b5be8ba7d2554127adf4609d96da314e85b0 ./docs/BRAND.md
35f5b4b7d195a7b5c071d4665505afef189c7b386d4e3079e9ce8a96ace07f3a ./docs/COMPATIBILITY.md 35f5b4b7d195a7b5c071d4665505afef189c7b386d4e3079e9ce8a96ace07f3a ./docs/COMPATIBILITY.md
e4021b554ebc479954321586012add57a5fbfb58a1f7fce001d5638880912fc6 ./docs/DEVELOPMENT_SERVER.md e4021b554ebc479954321586012add57a5fbfb58a1f7fce001d5638880912fc6 ./docs/DEVELOPMENT_SERVER.md
51aa57a81131b64f76c45552122de842f22be92d81c8bba8f6fd38a18a7670d6 ./docs/DIAGNOSTICS.md 51aa57a81131b64f76c45552122de842f22be92d81c8bba8f6fd38a18a7670d6 ./docs/DIAGNOSTICS.md
f1a8e78c5aa521324ad2fcb386512158d0c0f9956e97f9a1bc8f97aa5d5e9844 ./docs/THREAT_MODEL.md f1a8e78c5aa521324ad2fcb386512158d0c0f9956e97f9a1bc8f97aa5d5e9844 ./docs/THREAT_MODEL.md
7e2406acc98391ec126b13d512c00b930bbc2c19f4d5b0fe52286ae41bfbc92d ./examples/eql-shaped/LICENSE
eaf381627e6020d7b87b3058ee9c2882bcca5280a8bd409547ecc955a33346db ./examples/eql-shaped/LICENSES.md
78c58c00b93f8029cee67d8facdc81a30cc69feb7683952d1e72b54086485eb0 ./examples/eql-shaped/README.md
2decbbebb78da922d39d0b74ad8358601526c1d36494c857d66d69116403b7ca ./examples/eql-shaped/cmd/example/main.go
385bf9bd6a301723d123c2a52667d320889c47495f018fe0e7daa520c9fa89b0 ./examples/eql-shaped/go.mod
6b53c55daf538b25fba2a60be9887fce086b8635a38120ab3f5bf6e9fcb67867 ./examples/eql-shaped/himesan.json
2c0063ed8724520f146d6717bb7d828ce69be17b41cbfb8f4866664ba09a58a8 ./examples/eql-shaped/views/badge.sando
6befc3b1bd216bb41c7da96e0e2f1c851f5531d2c6ac800f3d06b11de01c2878 ./examples/eql-shaped/views/badge.sando.go
c5b402971618747c906c84508d5af9fd00aa33391b9b59f093b001a3cb0b2164 ./examples/eql-shaped/views/browse_results.sando
065a88f19de5ba15fb7f9d2104e2a74fe2830f95b16c432e27e40f8aba000df9 ./examples/eql-shaped/views/browse_results.sando.go
696c391538cdc50c5ab1abea23b561fa354e56eaf73b7ad6aabe130389715a8c ./examples/eql-shaped/views/home.sando
cdfe566844319accf7a9eaae4b5b43ea32b7a0cb3d4fec2dad086d98fb3e9d0b ./examples/eql-shaped/views/home.sando.go
c9a8102588cb94f946a36414291d12cb681e605acc93c2b5dc8d74fd33ae5603 ./examples/eql-shaped/views/layout.sando
fea981d626bd696068b2384707a217527ad5e24e909d2358cc95444145c424fd ./examples/eql-shaped/views/layout.sando.go
120fd733237ef1f15ce60b6ea27c21ce509f6ddc1a9727a9375bf2bb22b3629b ./examples/eql-shaped/views/model.go
a8e647d7a9cff4804f97e2175c760cf04be6580a85a5eb946b733b46111b2e06 ./examples/eql-shaped/views/render_test.go
8d59b45799d0ed2e9e6997f286315f2cb794ea660940978ec39efa3b9a3b94ab ./examples/eql-shaped/views/security_probe.sando
9d5144c39442e29aded227828099cb4b1a32a69112559f8682b43fa04cfaae65 ./examples/eql-shaped/views/security_probe.sando.go
f27c46ca63707bb8cc570eab1ea521824e94bc59b1d153998a5e91c2c7340d16 ./go.mod f27c46ca63707bb8cc570eab1ea521824e94bc59b1d153998a5e91c2c7340d16 ./go.mod
07d161772e9c6eec0dcc12179286e5c686dcabdc4e56a7cb8d112f640b072563 ./internal/compiler/backend.go 07d161772e9c6eec0dcc12179286e5c686dcabdc4e56a7cb8d112f640b072563 ./internal/compiler/backend.go
0cb82706496f80e2a852917c047fb1f29138144c96323a23ba2565055aadcf03 ./internal/compiler/compiler_test.go 28123757d27298dd81cf13ebd9242b24556734a35e36c2ac731f2a8475d70d28 ./internal/compiler/compiler_test.go
d99ba263bf501ca81ed38ba88216c063d2fc22f4b45a3f28d5105957f449c4de ./internal/compiler/context.go d99ba263bf501ca81ed38ba88216c063d2fc22f4b45a3f28d5105957f449c4de ./internal/compiler/context.go
b2a96ef1ad572ad9cd0e9247328ca261de6f9f3689da41e3f3e111d405a6dee6 ./internal/compiler/diagnostic.go b2a96ef1ad572ad9cd0e9247328ca261de6f9f3689da41e3f3e111d405a6dee6 ./internal/compiler/diagnostic.go
42ccf512381e130bf593b065dccd7697560fb00240818efde6321c9095f6b4a6 ./internal/compiler/discover.go 42ccf512381e130bf593b065dccd7697560fb00240818efde6321c9095f6b4a6 ./internal/compiler/discover.go
@@ -59,6 +41,8 @@ eefb05a35bd07660a293c8af97949cd6f69a22709728f3fe2cc9132b863b7d5a ./internal/com
d7d8181455d5f37ef9bcc6bdbf86e0630f20e8a5b3b81688d12742687b434c99 ./internal/compiler/parse.go d7d8181455d5f37ef9bcc6bdbf86e0630f20e8a5b3b81688d12742687b434c99 ./internal/compiler/parse.go
80cf170514a3b955d24440cb086d34e19f3a305510e3c5db95cb897be91f922a ./internal/compiler/replace_unix.go 80cf170514a3b955d24440cb086d34e19f3a305510e3c5db95cb897be91f922a ./internal/compiler/replace_unix.go
0fff1c67447bf5353ed1df6e7dfc4b14581b67adc1bf02f7a4a7c1f2680c392f ./internal/compiler/replace_windows.go 0fff1c67447bf5353ed1df6e7dfc4b14581b67adc1bf02f7a4a7c1f2680c392f ./internal/compiler/replace_windows.go
f4ba01010ed5f5ba1e979702d82e95312bc0a4b13cc205c098926839be4ecb73 ./internal/compiler/testdata/golden/basic.sando
b190a6a8aed288378ea13d12ec06bac68890c473c03c60016f7fa7534f142008 ./internal/compiler/testdata/golden/basic.sando.go
eafbe9f7d8abb8fa792ec9e01f56655f9ec9d67279ffaac66d6035f9b2bfc404 ./internal/devserver/config.go eafbe9f7d8abb8fa792ec9e01f56655f9ec9d67279ffaac66d6035f9b2bfc404 ./internal/devserver/config.go
99807040a870dd38ad1e04ae179243316778f94a41feb5d2c3076d463f52f9fe ./internal/devserver/config_test.go 99807040a870dd38ad1e04ae179243316778f94a41feb5d2c3076d463f52f9fe ./internal/devserver/config_test.go
eddac51aecaac99bd11cfcf98f8a47cec5d51672efedad75d6f2a862c5d57fc1 ./internal/devserver/events.go eddac51aecaac99bd11cfcf98f8a47cec5d51672efedad75d6f2a862c5d57fc1 ./internal/devserver/events.go
@@ -85,14 +69,9 @@ ff76daee5b642ad84af31701833246d68b54d09580192312d750a7a2e893a692 ./sando/go.mod
80ff53787919e809b8085d6ad9c3e183c9c7c1d74cfeda73369ac5c4607c236f ./sando/trust.go 80ff53787919e809b8085d6ad9c3e183c9c7c1d74cfeda73369ac5c4607c236f ./sando/trust.go
85621a44c730582f4410ac2c70418b739fb55e916f7e6b73a1a619982c459572 ./sando/write.go 85621a44c730582f4410ac2c70418b739fb55e916f7e6b73a1a619982c459572 ./sando/write.go
b188917e258890e6b6e4840a6fd946fc9a77cabc2068da3764f221e4a6a5df97 ./sando/write_test.go b188917e258890e6b6e4840a6fd946fc9a77cabc2068da3764f221e4a6a5df97 ./sando/write_test.go
2d92e1578d8907ab434f1924f698b586f47d6c9bc6fab989639a5332fd235163 ./scripts/README.md 2655a3f62772f7b3ef694aea2d03bd99e157d2449c232c7439c258ec36367fb1 ./scripts/README.md
032832440431a532771054bcbfb6c46944ead61bfdb38ca11a049aae14459bc3 ./scripts/check-licenses.sh 0bc796f71c863aa898674a26c56f055e3d81cf20629ca7b32fbae87d8841e0a8 ./scripts/check-licenses.sh
e35895423494018d5e380c447a8fb9bd5410af82a4a12f9fbaae391c286dd32a ./scripts/check-site.sh 502da1760bc87f260d474d81fe8f015a6e198f8d1ebf96db6b3f460ce4ef3b02 ./scripts/release-check.sh
d53d93df7e355ec45e6540703c6098c3fb49a610cb35600c5d525afa0f0d48cb ./scripts/release-check.sh 6be2fc6b8c3e0a7dd85437fa4089e75b772baa7556675081e6956a1b9f207fb4 ./scripts/verify-public-install.sh
be79b6bd1d18ce53a1b4cf301f7c4fa41342728d0a6333a766171cfc586a65d5 ./scripts/verify-public-install.sh 24ed3c9a1d37e46a856cbbd68e5c58ae04c6c9852902b99ed675e1f428339a9f ./scripts/verify.ps1
b52ff6d1e0db9c4a72a587fc063d8022c51a439158679029c8df613b51905e51 ./scripts/verify.ps1 f0cbd86759fa729064cb1c69991db2ac291792dadb6b1e1ba83794f2e390404d ./scripts/verify.sh
5163a360b212de5abadeaa48db415e6f605e8b2a7f2fd2dc9ab7c1da19cec079 ./scripts/verify.sh
7750a055be12b18c826d033f266a615bc1acdbddcfe5193f70521f7270a3e333 ./site/README.md
1b28cf572543d61f89e7636f74b94fe96916c0dc80847831a9f42b57bebb83cb ./site/assets/site.css
ecb00ac7fac0e161a3e4629c17209ddfaf0fbb8c78fd2615c2a7372808ae7cf7 ./site/index.html
63cf8fc6f059c6a1164a70e9fd35564ff107282e01030d997f4e3e1e3dc0fdda ./site/sando/index.html
+11 -13
View File
@@ -36,22 +36,18 @@ request object, or production server.
## Status ## Status
This repository is an unsupported public pre-1.0 source preview, not a supported v1 release. EQL Wiki remains the proof-of-production proving ground, and v1 is gated on security testing, cross-platform determinism, and a 14-day production soak with no renderer, security, or accessibility regression. This repository is an unsupported public pre-1.0 source preview, not a
supported v1 release. V1 is gated only by repository-owned compiler, runtime,
[sandwichhime.com](https://sandwichhime.com/) is the running self-hosted proof: security, compatibility, and release checks. Application-specific deployments,
its pages begin as `.sando`, compile into ordinary Go, and ship in an ordinary examples, and case studies live in their own repositories and are not imported
Go service whose production binary links only the `sando` runtime—not this as release evidence here.
compiler.
For repository development: For repository development:
```sh ```sh
go install ./cmd/himesan go install ./cmd/himesan
himesan generate ./examples/eql-shaped ./scripts/verify.sh
himesan check ./examples/eql-shaped ./scripts/check-licenses.sh
go test ./...
(cd sando && go test ./...)
(cd examples/eql-shaped && himesan dev --config himesan.json)
``` ```
The portable path is `generate`, `check`, and the project's normal Go tools. The portable path is `generate`, `check`, and the project's normal Go tools.
@@ -123,5 +119,7 @@ participation does not confer ownership of the identity or project.
The fuller origin, Japanese craft inspirations, family dedication, human-art The fuller origin, Japanese craft inspirations, family dedication, human-art
commitment, and stewardship boundary live on the commitment, and stewardship boundary live on the
[project site](https://sandwichhime.com/docs/project/). Performance claims will [project site](https://sandwichhime.com/docs/project/). Tutorials and copyable
follow published measurements, never precede them. applications are maintained separately from this compiler repository.
Performance claims will follow repository-owned measurements, never precede
them.
+19 -2
View File
@@ -6,11 +6,23 @@ Sandwich Hime uses separate root and runtime version lines. Compiler tags are `v
The public pre-1.0 source snapshot is not a supported release and does not imply that the v1 gates below have passed. The public pre-1.0 source snapshot is not a supported release and does not imply that the v1 gates below have passed.
No v1.0.0 release occurs until every gate in this repository is evidenced, including cross-platform deterministic generation, temporary-module compilation, fuzz/adversarial suites, race/vet/vulnerability/license checks on the latest two supported Go lines, development-supervisor failure tests, an EQL differential pilot, and a completed 14-day production soak without Hime render failures or security/accessibility regression. No v1.0.0 release occurs until every gate in this repository is evidenced,
including cross-platform deterministic generation, temporary-module
compilation, fuzz/adversarial suites, race/vet/vulnerability/license checks on
the latest two supported Go lines, development-supervisor failure tests, and
reproducible repository-owned benchmark and security results. A deployment,
example, or case study in another repository is neither imported nor required
as release evidence.
Release candidates require a clean canonical checkout, reviewed changelog, compatible vanity-import metadata, reproducible binaries, signed annotated tags, checksums, SBOMs, vulnerability results, and verification on Linux, macOS, and Windows. The runtime is tagged and published independently before the compiler that references its ABI. Release candidates require a clean canonical checkout, reviewed changelog, compatible vanity-import metadata, reproducible binaries, signed annotated tags, checksums, SBOMs, vulnerability results, and verification on Linux, macOS, and Windows. The runtime is tagged and published independently before the compiler that references its ABI.
Gitea is the only canonical public forge. Public source is exported into a separate, sanitized Gitea repository with fresh history; private development history and the private-to-public commit mapping are not published. Release binaries and provenance are built from the reviewed public commit. Publishing documentation, binaries, runtime tag, EQL mark, and case study is one coordinated v1 launch step. Gitea is the only canonical public forge. Public source is exported into a
separate, sanitized Gitea repository with fresh history; private development
history and the private-to-public commit mapping are not published. Release
binaries and provenance are built from the reviewed public commit. Compiler
documentation, binaries, checksums, SBOMs, and the independently versioned
runtime tag form the coordinated v1 release. Example applications and product
sites keep their own history, deployment, and evidence.
The hosting configuration must answer exact package discovery requests, not The hosting configuration must answer exact package discovery requests, not
only module-root pages. In particular, only module-root pages. In particular,
@@ -22,3 +34,8 @@ fresh direct-fetch and public-proxy caches. This post-publication check is
separate from the pre-tag, read-only `scripts/release-check.sh`. separate from the pre-tag, read-only `scripts/release-check.sh`.
Release notes report hardware, commit, datasets, commands, `ns/op`, allocations, response latency, and methodology for performance claims. “Fastest” or equivalent language is prohibited without durable, reproducible evidence. Release notes report hardware, commit, datasets, commands, `ns/op`, allocations, response latency, and methodology for performance claims. “Fastest” or equivalent language is prohibited without durable, reproducible evidence.
Production applications compile and deploy their committed `.sando.go` files
with the Apache-2.0 `sando` runtime. They do not need the AGPL compiler or the
local development supervisor. Release checks verify that boundary without
executing or inspecting an unrelated application repository.
+9 -10
View File
@@ -6,7 +6,7 @@ Unchecked items are release blockers, not aspirational marketing.
## Compiler and runtime ## Compiler and runtime
- [ ] Deterministic golden output repeated across Linux, macOS, and Windows. - [ ] Compiler-owned deterministic golden output repeated across Linux, macOS, and Windows.
- [ ] Temporary consumer modules compile using committed Go and only the Apache runtime. - [ ] Temporary consumer modules compile using committed Go and only the Apache runtime.
- [ ] Parser, delimiter, context, path, and source-map fuzz targets survive the release campaign. - [ ] Parser, delimiter, context, path, and source-map fuzz targets survive the release campaign.
- [ ] Adversarial escaping and filesystem cases are evidenced. - [ ] Adversarial escaping and filesystem cases are evidenced.
@@ -20,19 +20,18 @@ Unchecked items are release blockers, not aspirational marketing.
- [ ] CSP hash injection, fragment/API/download exclusion, and cache disabling pass. - [ ] CSP hash injection, fragment/API/download exclusion, and cache disabling pass.
- [ ] Replaced and interrupted child processes leave no descendants on supported systems. - [ ] Replaced and interrupted child processes leave no descendants on supported systems.
## EQL Wiki proof ## Repository-owned release evidence
- [ ] Separate `codex/himesan-pilot` worktree created after compiler gates. - [ ] Contextual escaping is differentially tested against Go's documented `html/template` safety baseline.
- [ ] Shared layout/home, browse fragment, and item page reach differential parity. - [ ] Repository-owned synthetic benchmark cases and methodology are reproducible from a clean checkout.
- [ ] Accessibility, CSP, links/forms, malicious values, status, caching, and fragments pass. - [ ] Generated output is reviewed for stable provenance, source mappings, and absence of compiler-license headers.
- [ ] Blue/green renderer flag and slot-switch rollback verified. - [ ] Production application boundaries are documented: committed generated Go plus the Apache runtime, with no compiler or development supervisor in the deployed binary.
- [ ] Fourteen continuous production days complete with zero Hime renderer failure or security/accessibility regression. - [ ] Unsupported or unmeasured performance and production claims are absent from release materials.
- [ ] Honest before/after case study and reproducible benchmark report approved.
## Public launch ## Public launch
- [ ] Ownership notices, output permission, DCO contribution process, and pre-registration trademark terms receive final human review. - [ ] Ownership notices, output permission, DCO contribution process, and pre-registration trademark terms receive final human review.
- [ ] Name clearance, security mailbox, two-person credential recovery, and signing keys complete. - [ ] Name clearance, security mailbox, two-person credential recovery, and signing keys complete.
- [ ] Gamertan vanity metadata and documentation verified from a clean machine. - [ ] `gamertan.com` vanity-import metadata and documented installs verified from a clean machine.
- [ ] Sanitized fresh-history public Gitea snapshot contains no private paths, identifiers, history, or unsupported release claims. - [ ] Sanitized fresh-history public Gitea snapshot contains no private paths, identifiers, history, or unsupported release claims.
- [ ] Canonical public Gitea source preview and Gamertan documentation launch together with no secondary forge mirror. - [ ] Canonical public Gitea source and project documentation launch with no secondary forge mirror.
+8 -2
View File
@@ -4,6 +4,12 @@
Benchmarks compare equivalent typed views and output against Go's `html/template` baseline. Reports include hardware, operating system, Go version, repository commit, dataset identity, exact commands, warmup/run counts, `ns/op`, bytes and allocations per operation, end-to-end response latency where relevant, output size, and statistical method. Benchmarks compare equivalent typed views and output against Go's `html/template` baseline. Reports include hardware, operating system, Go version, repository commit, dataset identity, exact commands, warmup/run counts, `ns/op`, bytes and allocations per operation, end-to-end response latency where relevant, output size, and statistical method.
The v1 gate is no material regression for the selected EQL pages under the published method. Only reproduced improvements become marketing claims. Microbenchmarks do not justify claims about request throughput, database-heavy pages, or whole-application latency. The v1 gate is no material regression against equivalent repository-owned
synthetic cases under the published method. Only reproduced improvements become
marketing claims. Microbenchmarks do not justify claims about request
throughput, database-heavy pages, or whole-application latency.
Benchmark fixtures must contain synthetic or approved public data. The EQL production database is never copied into this repository or a public artifact. Benchmark fixtures must be self-contained, synthetic, reviewable, and committed
to this repository. Application-specific datasets and deployment measurements
belong with their applications and are neither copied here nor treated as core
release gates.
-14
View File
@@ -1,14 +0,0 @@
Zero-Clause BSD
Copyright (c) 2025-2026 Cole Speelman
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
-15
View File
@@ -1,15 +0,0 @@
<!-- SPDX-FileCopyrightText: 2025-2026 Cole Speelman -->
<!-- SPDX-License-Identifier: 0BSD -->
# Example license map
The original files in this synthetic, copyable example are licensed under the
0BSD terms in `LICENSE`, including `.sando` templates, handwritten Go,
`himesan.json`, and committed `.sando.go` output.
The generated files intentionally have no inline SPDX header because Hime-san
replaces the whole file. This module-level license map covers them. Generator
scaffolding copied into those files also has the additional permission in the
root repository's `OUTPUT_EXCEPTION.md`; that permission is not required to
keep this example under 0BSD when the example author already owns the relevant
input code.
-15
View File
@@ -1,15 +0,0 @@
<!-- SPDX-License-Identifier: 0BSD -->
# Synthetic EQL-shaped fixture
This copyable 0BSD example exercises a shared document layout, typed page data,
component composition, loops, text escaping, attribute escaping, and URL
policy without containing EQL Wiki code, data, routes, or its database.
From the repository root:
```sh
go run ./cmd/himesan generate ./examples/eql-shaped
go run ./cmd/himesan check ./examples/eql-shaped
(cd examples/eql-shaped && go test ./... && go run ./cmd/example)
```
-83
View File
@@ -1,83 +0,0 @@
// SPDX-License-Identifier: 0BSD
package main
import (
"bytes"
"context"
"errors"
"fmt"
"net/http"
"os"
"time"
"example.com/eql-shaped/views"
"gamertan.com/sandwich-hime/sando"
)
func main() {
address := os.Getenv("HIMESAN_LISTEN_ADDR")
if address != "" {
serve(address)
return
}
output, err := renderPage(context.Background())
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
_, _ = output.WriteTo(os.Stdout)
}
func serve(address string) {
mux := http.NewServeMux()
mux.HandleFunc("GET /healthz", func(response http.ResponseWriter, _ *http.Request) {
response.Header().Set("Content-Type", "text/plain; charset=utf-8")
response.WriteHeader(http.StatusOK)
_, _ = response.Write([]byte("ok\n"))
})
mux.HandleFunc("GET /", func(response http.ResponseWriter, request *http.Request) {
output, err := renderPage(request.Context())
if err != nil {
http.Error(response, "render failed", http.StatusInternalServerError)
return
}
response.Header().Set("Content-Type", "text/html; charset=utf-8")
response.Header().Set("Content-Security-Policy", "default-src 'none'; style-src 'self'")
response.WriteHeader(http.StatusOK)
_, _ = output.WriteTo(response)
})
server := &http.Server{Addr: address, Handler: mux, ReadHeaderTimeout: 5 * time.Second}
if err := server.ListenAndServe(); !errors.Is(err, http.ErrServerClosed) {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}
func renderPage(ctx context.Context) (*bytes.Buffer, error) {
body := views.Home(views.HomeView{
Heading: "EQL-shaped records",
Intro: "Typed markup without making the template compiler your web framework.",
Browse: views.BrowseView{
Query: "pioneer & archivist",
Records: []views.RecordView{
{URL: "/items/1?from=home&kind=book", Title: "A <field> guide", Kind: "book", Featured: true},
{URL: "/items/2", Title: "Community memory", Kind: "archive"},
},
},
})
page := views.Layout(views.LayoutView{
SiteName: "EQL Wiki Fixture",
Title: "Home",
Body: body,
})
var output bytes.Buffer
if err := sando.Render(ctx, &output, page); err != nil {
return nil, err
}
return &output, nil
}
-9
View File
@@ -1,9 +0,0 @@
// SPDX-License-Identifier: 0BSD
module example.com/eql-shaped
go 1.25
require gamertan.com/sandwich-hime/sando v0.0.0
replace gamertan.com/sandwich-hime/sando => ../../sando
-9
View File
@@ -1,9 +0,0 @@
{
"version": 1,
"sourceRoots": ["views"],
"goPackage": "./cmd/example",
"listenAddressEnv": "HIMESAN_LISTEN_ADDR",
"healthPath": "/healthz",
"proxyAddress": "127.0.0.1:7331",
"additionalWatchRoots": []
}
-7
View File
@@ -1,7 +0,0 @@
<?sando go
package views
func Badge(label string)
?>
<?# SPDX-License-Identifier: 0BSD ?>
<strong class="badge"><?= label ?></strong>
@@ -1,17 +0,0 @@
<?sando go
package views
func BrowseResults(view BrowseView)
?>
<?# SPDX-License-Identifier: 0BSD ?>
<section aria-label="Browse results" data-query="<?= view.Query ?>">
<ul>
<? for _, record := range view.Records { ?>
<li>
<a href="<?= record.URL ?>"><?= record.Title ?></a>
<span class="kind"><?= record.Kind ?></span>
<? if record.Featured { ?><?~ Badge("featured") ?><? } ?>
</li>
<? } ?>
</ul>
</section>
@@ -1,85 +0,0 @@
// Code generated by himesan; DO NOT EDIT.
// himesan:compiler 0.1.0-dev
// himesan:runtime-abi sando.v1
// himesan:source-sha256 c5b402971618747c906c84508d5af9fd00aa33391b9b59f093b001a3cb0b2164
package views
import (
__himesan_context "context"
__himesan_sando "gamertan.com/sandwich-hime/sando"
__himesan_io "io"
)
var _ = __himesan_sando.ABI
func BrowseResults(view BrowseView) __himesan_sando.Component {
return __himesan_sando.ComponentFunc(func(__himesan_render_context __himesan_context.Context, __himesan_writer __himesan_io.Writer) error {
_ = __himesan_render_context
//line views/browse_results.sando:5:3
if __himesan_error := __himesan_sando.WriteString(__himesan_writer, "\n"); __himesan_error != nil {
return __himesan_error
}
//line views/browse_results.sando:6:37
if __himesan_error := __himesan_sando.WriteString(__himesan_writer, "\n<section aria-label=\"Browse results\" data-query=\""); __himesan_error != nil {
return __himesan_error
}
//line views/browse_results.sando:7:54
if __himesan_error := __himesan_sando.WriteAttr(__himesan_writer, (view.Query)); __himesan_error != nil {
return __himesan_error
}
//line views/browse_results.sando:7:67
if __himesan_error := __himesan_sando.WriteString(__himesan_writer, "\">\n <ul>\n "); __himesan_error != nil {
return __himesan_error
}
//line views/browse_results.sando:9:6
for _, record := range view.Records {
//line views/browse_results.sando:9:46
if __himesan_error := __himesan_sando.WriteString(__himesan_writer, "\n <li>\n <a href=\""); __himesan_error != nil {
return __himesan_error
}
//line views/browse_results.sando:11:20
if __himesan_error := __himesan_sando.WriteURL(__himesan_writer, (record.URL)); __himesan_error != nil {
return __himesan_error
}
//line views/browse_results.sando:11:33
if __himesan_error := __himesan_sando.WriteString(__himesan_writer, "\">"); __himesan_error != nil {
return __himesan_error
}
//line views/browse_results.sando:11:39
if __himesan_error := __himesan_sando.WriteText(__himesan_writer, (record.Title)); __himesan_error != nil {
return __himesan_error
}
//line views/browse_results.sando:11:54
if __himesan_error := __himesan_sando.WriteString(__himesan_writer, "</a>\n <span class=\"kind\">"); __himesan_error != nil {
return __himesan_error
}
//line views/browse_results.sando:12:30
if __himesan_error := __himesan_sando.WriteText(__himesan_writer, (record.Kind)); __himesan_error != nil {
return __himesan_error
}
//line views/browse_results.sando:12:44
if __himesan_error := __himesan_sando.WriteString(__himesan_writer, "</span>\n "); __himesan_error != nil {
return __himesan_error
}
//line views/browse_results.sando:13:10
if record.Featured {
//line views/browse_results.sando:13:37
if __himesan_error := __himesan_sando.Render(__himesan_render_context, __himesan_writer, (Badge("featured"))); __himesan_error != nil {
return __himesan_error
}
//line views/browse_results.sando:13:60
}
//line views/browse_results.sando:13:64
if __himesan_error := __himesan_sando.WriteString(__himesan_writer, "\n </li>\n "); __himesan_error != nil {
return __himesan_error
}
//line views/browse_results.sando:15:6
}
//line views/browse_results.sando:15:10
if __himesan_error := __himesan_sando.WriteString(__himesan_writer, "\n </ul>\n</section>\n"); __himesan_error != nil {
return __himesan_error
}
return nil
})
}
-11
View File
@@ -1,11 +0,0 @@
<?sando go
package views
func Home(view HomeView)
?>
<?# SPDX-License-Identifier: 0BSD ?>
<section aria-labelledby="home-heading">
<h1 id="home-heading"><?= view.Heading ?></h1>
<p><?= view.Intro ?></p>
<?~ BrowseResults(view.Browse) ?>
</section>
-53
View File
@@ -1,53 +0,0 @@
// Code generated by himesan; DO NOT EDIT.
// himesan:compiler 0.1.0-dev
// himesan:runtime-abi sando.v1
// himesan:source-sha256 696c391538cdc50c5ab1abea23b561fa354e56eaf73b7ad6aabe130389715a8c
package views
import (
__himesan_context "context"
__himesan_sando "gamertan.com/sandwich-hime/sando"
__himesan_io "io"
)
var _ = __himesan_sando.ABI
func Home(view HomeView) __himesan_sando.Component {
return __himesan_sando.ComponentFunc(func(__himesan_render_context __himesan_context.Context, __himesan_writer __himesan_io.Writer) error {
_ = __himesan_render_context
//line views/home.sando:5:3
if __himesan_error := __himesan_sando.WriteString(__himesan_writer, "\n"); __himesan_error != nil {
return __himesan_error
}
//line views/home.sando:6:37
if __himesan_error := __himesan_sando.WriteString(__himesan_writer, "\n<section aria-labelledby=\"home-heading\">\n <h1 id=\"home-heading\">"); __himesan_error != nil {
return __himesan_error
}
//line views/home.sando:8:29
if __himesan_error := __himesan_sando.WriteText(__himesan_writer, (view.Heading)); __himesan_error != nil {
return __himesan_error
}
//line views/home.sando:8:44
if __himesan_error := __himesan_sando.WriteString(__himesan_writer, "</h1>\n <p>"); __himesan_error != nil {
return __himesan_error
}
//line views/home.sando:9:10
if __himesan_error := __himesan_sando.WriteText(__himesan_writer, (view.Intro)); __himesan_error != nil {
return __himesan_error
}
//line views/home.sando:9:23
if __himesan_error := __himesan_sando.WriteString(__himesan_writer, "</p>\n "); __himesan_error != nil {
return __himesan_error
}
//line views/home.sando:10:7
if __himesan_error := __himesan_sando.Render(__himesan_render_context, __himesan_writer, (BrowseResults(view.Browse))); __himesan_error != nil {
return __himesan_error
}
//line views/home.sando:10:36
if __himesan_error := __himesan_sando.WriteString(__himesan_writer, "\n</section>\n"); __himesan_error != nil {
return __himesan_error
}
return nil
})
}
-20
View File
@@ -1,20 +0,0 @@
<?sando go
package views
func Layout(view LayoutView)
?>
<?# SPDX-License-Identifier: 0BSD ?>
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title><?= view.Title ?> · <?= view.SiteName ?></title>
</head>
<body>
<a href="#main">Skip to content</a>
<header><a href="/"><?= view.SiteName ?></a></header>
<main id="main"><?~ view.Body ?></main>
<footer>Built with Sandwich Hime.</footer>
</body>
</html>
-61
View File
@@ -1,61 +0,0 @@
// Code generated by himesan; DO NOT EDIT.
// himesan:compiler 0.1.0-dev
// himesan:runtime-abi sando.v1
// himesan:source-sha256 c9a8102588cb94f946a36414291d12cb681e605acc93c2b5dc8d74fd33ae5603
package views
import (
__himesan_context "context"
__himesan_sando "gamertan.com/sandwich-hime/sando"
__himesan_io "io"
)
var _ = __himesan_sando.ABI
func Layout(view LayoutView) __himesan_sando.Component {
return __himesan_sando.ComponentFunc(func(__himesan_render_context __himesan_context.Context, __himesan_writer __himesan_io.Writer) error {
_ = __himesan_render_context
//line views/layout.sando:5:3
if __himesan_error := __himesan_sando.WriteString(__himesan_writer, "\n"); __himesan_error != nil {
return __himesan_error
}
//line views/layout.sando:6:37
if __himesan_error := __himesan_sando.WriteString(__himesan_writer, "\n<!doctype html>\n<html lang=\"en\">\n<head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n <title>"); __himesan_error != nil {
return __himesan_error
}
//line views/layout.sando:12:14
if __himesan_error := __himesan_sando.WriteRCDATA(__himesan_writer, (view.Title)); __himesan_error != nil {
return __himesan_error
}
//line views/layout.sando:12:27
if __himesan_error := __himesan_sando.WriteString(__himesan_writer, " · "); __himesan_error != nil {
return __himesan_error
}
//line views/layout.sando:12:35
if __himesan_error := __himesan_sando.WriteRCDATA(__himesan_writer, (view.SiteName)); __himesan_error != nil {
return __himesan_error
}
//line views/layout.sando:12:51
if __himesan_error := __himesan_sando.WriteString(__himesan_writer, "</title>\n</head>\n<body>\n <a href=\"#main\">Skip to content</a>\n <header><a href=\"/\">"); __himesan_error != nil {
return __himesan_error
}
//line views/layout.sando:16:27
if __himesan_error := __himesan_sando.WriteText(__himesan_writer, (view.SiteName)); __himesan_error != nil {
return __himesan_error
}
//line views/layout.sando:16:43
if __himesan_error := __himesan_sando.WriteString(__himesan_writer, "</a></header>\n <main id=\"main\">"); __himesan_error != nil {
return __himesan_error
}
//line views/layout.sando:17:23
if __himesan_error := __himesan_sando.Render(__himesan_render_context, __himesan_writer, (view.Body)); __himesan_error != nil {
return __himesan_error
}
//line views/layout.sando:17:35
if __himesan_error := __himesan_sando.WriteString(__himesan_writer, "</main>\n <footer>Built with Sandwich Hime.</footer>\n</body>\n</html>\n"); __himesan_error != nil {
return __himesan_error
}
return nil
})
}
-29
View File
@@ -1,29 +0,0 @@
// SPDX-License-Identifier: 0BSD
package views
import "gamertan.com/sandwich-hime/sando"
type LayoutView struct {
SiteName string
Title string
Body sando.Component
}
type HomeView struct {
Heading string
Intro string
Browse BrowseView
}
type BrowseView struct {
Query string
Records []RecordView
}
type RecordView struct {
URL string
Title string
Kind string
Featured bool
}
-131
View File
@@ -1,131 +0,0 @@
// SPDX-License-Identifier: 0BSD
package views
import (
"bytes"
"context"
"errors"
"html/template"
"io"
"strings"
"testing"
"gamertan.com/sandwich-hime/sando"
)
func TestBrowseResultsEscapesUntrustedValues(t *testing.T) {
t.Parallel()
component := BrowseResults(BrowseView{
Query: `"><script>alert(1)</script>`,
Records: []RecordView{{
URL: `/item?q=" onclick="alert(1)`,
Title: `<img src=x onerror=alert(1)>`,
Kind: `" aria-label="injected`,
}},
})
var output bytes.Buffer
if err := sando.Render(context.Background(), &output, component); err != nil {
t.Fatal(err)
}
got := output.String()
if strings.Contains(got, "<script>") || strings.Contains(got, "<img") || strings.Contains(got, `" onclick=`) {
t.Fatalf("untrusted markup survived escaping: %s", got)
}
}
func TestBrowseResultsRejectsDangerousURL(t *testing.T) {
t.Parallel()
component := BrowseResults(BrowseView{Records: []RecordView{{
URL: " JaVaScRiPt:\talert(1)",
Title: "unsafe",
}}})
var output bytes.Buffer
err := sando.Render(context.Background(), &output, component)
if !errors.Is(err, sando.ErrUnsafeURL) {
t.Fatalf("expected unsafe URL error, got %v", err)
}
}
func TestGeneratedComponentPropagatesWriterFailures(t *testing.T) {
t.Parallel()
component := Badge("proof")
if err := sando.Render(context.Background(), shortWriter{}, component); !errors.Is(err, io.ErrShortWrite) {
t.Fatalf("short writer error = %v, want io.ErrShortWrite", err)
}
want := errors.New("connection closed")
if err := sando.Render(context.Background(), errorWriter{err: want}, component); !errors.Is(err, want) {
t.Fatalf("writer error = %v, want %v", err, want)
}
}
func TestContextEscapingAgainstHTMLTemplateBaseline(t *testing.T) {
t.Parallel()
baseline := template.Must(template.New("probe").Parse(`<a href="{{ .URL }}" title="{{ .Title }}">{{ .Text }}</a>`))
tests := []struct {
name string
url string
title string
text string
}{
{name: "entities", url: "/items?q=one&kind=book", title: `say "hello" & goodbye`, text: `<strong>not markup</strong>`},
{name: "unicode", url: "/items/cole", title: "Café & 雪", text: "Cole's archive ♥"},
}
for _, test := range tests {
test := test
t.Run(test.name, func(t *testing.T) {
t.Parallel()
data := struct{ URL, Title, Text string }{test.url, test.title, test.text}
var legacy bytes.Buffer
if err := baseline.Execute(&legacy, data); err != nil {
t.Fatal(err)
}
var generated bytes.Buffer
if err := sando.Render(context.Background(), &generated, SecurityProbe(test.url, test.title, test.text)); err != nil {
t.Fatal(err)
}
if got, want := strings.TrimSpace(generated.String()), legacy.String(); got != want {
t.Fatalf("generated escaping differs from html/template baseline\n got: %s\nwant: %s", got, want)
}
})
}
}
func TestDangerousURLIsBlockedAtLeastAsStrictlyAsHTMLTemplate(t *testing.T) {
t.Parallel()
const dangerous = " JaVaScRiPt:\talert(1)"
baseline := template.Must(template.New("probe").Parse(`<a href="{{ . }}">link</a>`))
var legacy bytes.Buffer
if err := baseline.Execute(&legacy, dangerous); err != nil {
t.Fatal(err)
}
if !strings.Contains(legacy.String(), "#ZgotmplZ") {
t.Fatalf("html/template baseline unexpectedly accepted dangerous URL: %s", legacy.String())
}
var generated bytes.Buffer
err := sando.Render(context.Background(), &generated, SecurityProbe(dangerous, "title", "link"))
if !errors.Is(err, sando.ErrUnsafeURL) {
t.Fatalf("generated renderer error = %v, want ErrUnsafeURL", err)
}
}
type shortWriter struct{}
func (shortWriter) Write(value []byte) (int, error) {
if len(value) == 0 {
return 0, nil
}
return len(value) - 1, nil
}
type errorWriter struct{ err error }
func (writer errorWriter) Write([]byte) (int, error) { return 0, writer.err }
@@ -1,7 +0,0 @@
<?sando go
package views
func SecurityProbe(url string, title string, text string)
?>
<?# SPDX-License-Identifier: 0BSD ?>
<a href="<?= url ?>" title="<?= title ?>"><?= text ?></a>
@@ -1,53 +0,0 @@
// Code generated by himesan; DO NOT EDIT.
// himesan:compiler 0.1.0-dev
// himesan:runtime-abi sando.v1
// himesan:source-sha256 8d59b45799d0ed2e9e6997f286315f2cb794ea660940978ec39efa3b9a3b94ab
package views
import (
__himesan_context "context"
__himesan_sando "gamertan.com/sandwich-hime/sando"
__himesan_io "io"
)
var _ = __himesan_sando.ABI
func SecurityProbe(url string, title string, text string) __himesan_sando.Component {
return __himesan_sando.ComponentFunc(func(__himesan_render_context __himesan_context.Context, __himesan_writer __himesan_io.Writer) error {
_ = __himesan_render_context
//line views/security_probe.sando:5:3
if __himesan_error := __himesan_sando.WriteString(__himesan_writer, "\n"); __himesan_error != nil {
return __himesan_error
}
//line views/security_probe.sando:6:37
if __himesan_error := __himesan_sando.WriteString(__himesan_writer, "\n<a href=\""); __himesan_error != nil {
return __himesan_error
}
//line views/security_probe.sando:7:14
if __himesan_error := __himesan_sando.WriteURL(__himesan_writer, (url)); __himesan_error != nil {
return __himesan_error
}
//line views/security_probe.sando:7:20
if __himesan_error := __himesan_sando.WriteString(__himesan_writer, "\" title=\""); __himesan_error != nil {
return __himesan_error
}
//line views/security_probe.sando:7:33
if __himesan_error := __himesan_sando.WriteAttr(__himesan_writer, (title)); __himesan_error != nil {
return __himesan_error
}
//line views/security_probe.sando:7:41
if __himesan_error := __himesan_sando.WriteString(__himesan_writer, "\">"); __himesan_error != nil {
return __himesan_error
}
//line views/security_probe.sando:7:47
if __himesan_error := __himesan_sando.WriteText(__himesan_writer, (text)); __himesan_error != nil {
return __himesan_error
}
//line views/security_probe.sando:7:54
if __himesan_error := __himesan_sando.WriteString(__himesan_writer, "</a>\n"); __himesan_error != nil {
return __himesan_error
}
return nil
})
}
+2 -3
View File
@@ -63,10 +63,9 @@ func TestCommittedGoldenOutput(t *testing.T) {
if !ok { if !ok {
t.Fatal("runtime.Caller failed") t.Fatal("runtime.Caller failed")
} }
root := filepath.Clean(filepath.Join(filepath.Dir(thisFile), "..", "..")) sourcePath := filepath.Join(filepath.Dir(thisFile), "testdata", "golden", "basic.sando")
sourcePath := filepath.Join(root, "examples", "eql-shaped", "views", "badge.sando")
wantPath := sourcePath + ".go" wantPath := sourcePath + ".go"
compiled, diagnostics := compileWithMapping(sourcePath, mustRead(t, sourcePath), "views/badge.sando") compiled, diagnostics := compileWithMapping(sourcePath, mustRead(t, sourcePath), "internal/compiler/testdata/golden/basic.sando")
assertNoErrorDiagnostics(t, diagnostics) assertNoErrorDiagnostics(t, diagnostics)
if want := mustRead(t, wantPath); !bytes.Equal(compiled.Code, want) { if want := mustRead(t, wantPath); !bytes.Equal(compiled.Code, want) {
t.Fatalf("committed golden output is stale; run himesan generate\n--- got ---\n%s\n--- want ---\n%s", compiled.Code, want) t.Fatalf("committed golden output is stale; run himesan generate\n--- got ---\n%s\n--- want ---\n%s", compiled.Code, want)
+7
View File
@@ -0,0 +1,7 @@
<?sando go
package golden
func Greeting(name string)
?>
<?# SPDX-License-Identifier: AGPL-3.0-only ?>
<p class="greeting">Hello, <?= name ?>.</p>
@@ -1,9 +1,9 @@
// Code generated by himesan; DO NOT EDIT. // Code generated by himesan; DO NOT EDIT.
// himesan:compiler 0.1.0-dev // himesan:compiler 0.1.0-dev
// himesan:runtime-abi sando.v1 // himesan:runtime-abi sando.v1
// himesan:source-sha256 2c0063ed8724520f146d6717bb7d828ce69be17b41cbfb8f4866664ba09a58a8 // himesan:source-sha256 f4ba01010ed5f5ba1e979702d82e95312bc0a4b13cc205c098926839be4ecb73
package views package golden
import ( import (
__himesan_context "context" __himesan_context "context"
@@ -13,23 +13,23 @@ import (
var _ = __himesan_sando.ABI var _ = __himesan_sando.ABI
func Badge(label string) __himesan_sando.Component { func Greeting(name 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 {
_ = __himesan_render_context _ = __himesan_render_context
//line views/badge.sando:5:3 //line internal/compiler/testdata/golden/basic.sando:5:3
if __himesan_error := __himesan_sando.WriteString(__himesan_writer, "\n"); __himesan_error != nil { if __himesan_error := __himesan_sando.WriteString(__himesan_writer, "\n"); __himesan_error != nil {
return __himesan_error return __himesan_error
} }
//line views/badge.sando:6:37 //line internal/compiler/testdata/golden/basic.sando:6:46
if __himesan_error := __himesan_sando.WriteString(__himesan_writer, "\n<strong class=\"badge\">"); __himesan_error != nil { if __himesan_error := __himesan_sando.WriteString(__himesan_writer, "\n<p class=\"greeting\">Hello, "); __himesan_error != nil {
return __himesan_error return __himesan_error
} }
//line views/badge.sando:7:27 //line internal/compiler/testdata/golden/basic.sando:7:32
if __himesan_error := __himesan_sando.WriteText(__himesan_writer, (label)); __himesan_error != nil { if __himesan_error := __himesan_sando.WriteText(__himesan_writer, (name)); __himesan_error != nil {
return __himesan_error return __himesan_error
} }
//line views/badge.sando:7:35 //line internal/compiler/testdata/golden/basic.sando:7:39
if __himesan_error := __himesan_sando.WriteString(__himesan_writer, "</strong>\n"); __himesan_error != nil { if __himesan_error := __himesan_sando.WriteString(__himesan_writer, ".</p>\n"); __himesan_error != nil {
return __himesan_error return __himesan_error
} }
return nil return nil
+2 -4
View File
@@ -4,11 +4,9 @@
These scripts are intentionally understandable shell and PowerShell rather than a release framework with hidden defaults. These scripts are intentionally understandable shell and PowerShell rather than a release framework with hidden defaults.
- `verify.sh` runs root and nested-module tests and vet, builds `himesan`, tests each example module, checks committed generated output, and proves two generation passes leave the same bytes and unchanged modification times. Set `HIMESAN_RACE=1` for race tests. - `verify.sh` runs root and nested-module tests and vet, builds `himesan`, checks the compiler-owned golden output, and proves two generation passes leave the same bytes and unchanged modification times. Set `HIMESAN_RACE=1` for race tests.
- `verify.ps1` provides the equivalent native Windows lane; pass `-Race` to include the race detector. - `verify.ps1` provides the equivalent native Windows lane; pass `-Race` to include the race detector.
- `check-licenses.sh` enforces the AGPL compiler / Apache runtime / 0BSD example boundary and prevents generated application Go from inheriting an AGPL identifier. - `check-licenses.sh` enforces the AGPL compiler / Apache runtime boundary and prevents generated application Go from inheriting an AGPL identifier.
- `check-site.sh` verifies vanity metadata, no-script/local-asset policy, pre-release honesty, and baseline accessibility scaffolding for the static site.
- `eql-integration.sh` is opt-in. Until a repository-owned `internal/integration/eql` test exists it exits successfully without inspecting EQL. Later it requires external `HIMESAN_EQL_ROOT` and `HIMESAN_EQL_DB` paths and passes a read-only-mode contract to that package. It never copies a database.
- `release-check.sh --version vX.Y.Z` is a clean-checkout technical preflight. Add `--public` and point `HIMESAN_RELEASE_EVIDENCE_DIR` at a human-reviewed evidence bundle for the public-launch gate. It never tags, pushes, publishes, or deploys. - `release-check.sh --version vX.Y.Z` is a clean-checkout technical preflight. Add `--public` and point `HIMESAN_RELEASE_EVIDENCE_DIR` at a human-reviewed evidence bundle for the public-launch gate. It never tags, pushes, publishes, or deploys.
- `verify-public-install.sh --version vX.Y.Z` is a post-tag/publication check. It verifies exact `go-get=1` package routes and runs the documented compiler install and runtime get from fresh direct-fetch and public-proxy caches without interactive Git credentials. - `verify-public-install.sh --version vX.Y.Z` is a post-tag/publication check. It verifies exact `go-get=1` package routes and runs the documented compiler install and runtime get from fresh direct-fetch and public-proxy caches without interactive Git credentials.
+2 -30
View File
@@ -15,9 +15,6 @@ fail() {
expected_spdx() { expected_spdx() {
case "$1" in case "$1" in
examples/*)
printf '0BSD\n'
;;
sando/*) sando/*)
printf 'Apache-2.0\n' printf 'Apache-2.0\n'
;; ;;
@@ -77,7 +74,6 @@ list_project_files() {
[[ -f LICENSE ]] || fail 'root LICENSE is missing' [[ -f LICENSE ]] || fail 'root LICENSE is missing'
[[ -f sando/LICENSE ]] || fail 'sando/LICENSE is missing' [[ -f sando/LICENSE ]] || fail 'sando/LICENSE is missing'
[[ -f examples/eql-shaped/LICENSE ]] || fail 'example LICENSE is missing'
[[ -f DCO.txt ]] || fail 'DCO.txt is missing' [[ -f DCO.txt ]] || fail 'DCO.txt is missing'
if [[ -f LICENSE ]]; then if [[ -f LICENSE ]]; then
@@ -86,16 +82,11 @@ fi
if [[ -f sando/LICENSE ]]; then if [[ -f sando/LICENSE ]]; then
check_sha256 sando/LICENSE c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4 check_sha256 sando/LICENSE c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4
fi fi
if [[ -f examples/eql-shaped/LICENSE ]]; then
check_sha256 examples/eql-shaped/LICENSE 7e2406acc98391ec126b13d512c00b930bbc2c19f4d5b0fe52286ae41bfbc92d
grep -Fq 'Copyright (c) 2025-2026 Cole Speelman' examples/eql-shaped/LICENSE || \
fail 'example LICENSE must identify its original author'
fi
if [[ -f DCO.txt ]]; then if [[ -f DCO.txt ]]; then
check_sha256 DCO.txt f7ac75b443f4ca16b503241344b41aeff9503b0c30bedc2b119551d83cb0fa90 check_sha256 DCO.txt f7ac75b443f4ca16b503241344b41aeff9503b0c30bedc2b119551d83cb0fa90
fi fi
for required in COPYRIGHT OUTPUT_EXCEPTION.md sando/COPYRIGHT examples/eql-shaped/LICENSES.md; do for required in COPYRIGHT OUTPUT_EXCEPTION.md sando/COPYRIGHT; do
[[ -f $required ]] || fail "$required is required for ownership/output licensing" [[ -f $required ]] || fail "$required is required for ownership/output licensing"
done done
@@ -126,7 +117,7 @@ while IFS= read -r -d '' path; do
[[ -f $path ]] || continue [[ -f $path ]] || continue
case "$path" in case "$path" in
LICENSE | sando/LICENSE | examples/*/LICENSE | DCO.txt) LICENSE | sando/LICENSE | DCO.txt)
# These are reviewed legal texts with their own notices. # These are reviewed legal texts with their own notices.
continue continue
;; ;;
@@ -161,9 +152,7 @@ while IFS= read -r -d '' path; do
continue continue
;; ;;
*.json) *.json)
if [[ $path != examples/eql-shaped/himesan.json ]]; then
fail "$path cannot carry a comment and needs an explicit license-map entry" fail "$path cannot carry a comment and needs an explicit license-map entry"
fi
continue continue
;; ;;
esac esac
@@ -178,23 +167,6 @@ while IFS= read -r -d '' path; do
fail "$path must carry exactly one SPDX identifier: $expected" fail "$path must carry exactly one SPDX identifier: $expected"
done < <(list_project_files) done < <(list_project_files)
if [[ -f examples/eql-shaped/LICENSES.md ]]; then
grep -Fq '`himesan.json`' examples/eql-shaped/LICENSES.md || \
fail 'example license map must cover himesan.json'
grep -Fq '`.sando.go`' examples/eql-shaped/LICENSES.md || \
fail 'example license map must cover generated output'
fi
if [[ -d examples ]] && find examples -type f -name go.mod -print -quit | grep -q .; then
while IFS= read -r -d '' module_file; do
module_dir=$(dirname -- "$module_file")
license_file=$module_dir/LICENSE
map_file=$module_dir/LICENSES.md
[[ -f $license_file ]] || fail "example module $module_dir needs a local 0BSD LICENSE"
[[ -f $map_file ]] || fail "example module $module_dir needs a local license map"
done < <(find examples -type d \( -name .git -o -name vendor \) -prune -o -type f -name go.mod -print0)
fi
if find sando -type f -name '*.go' -exec grep -En \ if find sando -type f -name '*.go' -exec grep -En \
'"gamertan\.com/sandwich-hime/(cmd|internal)(/|"|$)' {} + | grep -q .; then '"gamertan\.com/sandwich-hime/(cmd|internal)(/|"|$)' {} + | grep -q .; then
fail 'the Apache runtime imports AGPL compiler or CLI code' fail 'the Apache runtime imports AGPL compiler or CLI code'
-75
View File
@@ -1,75 +0,0 @@
#!/usr/bin/env bash
# SPDX-License-Identifier: AGPL-3.0-only
set -euo pipefail
repo_root=$(CDPATH= cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)
cd "$repo_root"
public_version=''
if (( $# > 0 )); then
if [[ "$1" != --public || $# -ne 2 ]]; then
printf 'usage: scripts/check-site.sh [--public vX.Y.Z]\n' >&2
exit 2
fi
public_version=$2
fi
fail() {
printf 'site error: %s\n' "$*" >&2
exit 1
}
for page in site/index.html site/sando/index.html; do
[[ -f "$page" ]] || fail "missing $page"
grep -Fq '<html lang="en">' "$page" || fail "$page needs a document language"
grep -Fq '<meta name="viewport"' "$page" || fail "$page needs responsive viewport metadata"
grep -Fq 'class="skip-link"' "$page" || fail "$page needs a keyboard skip link"
grep -Fq '<main id="main">' "$page" || fail "$page needs the skip-link target"
grep -Fq '<h1>' "$page" || grep -Fq '<h1 ' "$page" || fail "$page needs an h1"
grep -Fq 'Content-Security-Policy' "$page" || fail "$page needs a preview CSP"
grep -Fq '<meta name="himesan-release-status" content="' "$page" || \
fail "$page needs machine-readable release status"
done
grep -Fq '<meta name="go-import" content="gamertan.com/sandwich-hime git https://gitea.speelman.ca/gamertan/sandwich-hime.git">' \
site/index.html || fail 'compiler vanity-import metadata is missing or changed'
grep -Fq '<meta name="go-import" content="gamertan.com/sandwich-hime/sando git https://gitea.speelman.ca/gamertan/sandwich-hime.git sando">' \
site/sando/index.html || fail 'nested runtime vanity-import metadata is missing or changed'
if find site -type f -name '*.html' -exec grep -Ein '<script([[:space:]>])' {} + | grep -q .; then
fail 'the static project site must not contain JavaScript'
fi
if find site -type f -name '*.html' -exec grep -Ein \
'(src|href)="https?://[^" ]+\.(js|css)([?"#])' {} + | grep -q .; then
fail 'the static project site must not load remote JavaScript or CSS'
fi
if find site -type f -name '*.css' -exec grep -Ein \
"(@import|url\\()[[:space:]\"']*https?://" {} + | grep -q .; then
fail 'the static project site must not load remote CSS assets'
fi
grep -Fq 'prefers-reduced-motion' site/assets/site.css || fail 'site CSS needs a reduced-motion preference'
grep -Fq 'forced-colors' site/assets/site.css || fail 'site CSS needs a forced-colors fallback'
grep -Fq 'class="wordmark" role="img"' site/index.html || \
fail 'the ASCII wordmark needs an accessible semantic role'
grep -Fq 'class="code" tabindex="0" role="region"' site/index.html || \
fail 'the scrollable code example needs keyboard access and a region role'
if [[ -n "$public_version" ]]; then
for page in site/index.html site/sando/index.html; do
grep -Fq "<meta name=\"himesan-release-status\" content=\"$public_version\">" "$page" || \
fail "$page release status does not match $public_version"
done
if grep -Eiq 'not a public release|not released yet|private pre-release|public pre-1\.0|unsupported pre-1\.0|no (supported )?public .*tag' \
site/index.html site/sando/index.html; then
fail 'public-release site still contains a pre-release warning'
fi
else
if grep -Fq '<meta name="himesan-release-status" content="pre-release">' site/index.html; then
grep -Eiq 'public pre-1\.0|unsupported pre-1\.0|not released yet' site/index.html || \
fail 'the pre-release landing page must state its status in human-readable text'
fi
fi
printf 'Static site metadata, local-asset policy, and accessibility scaffolding are present.\n'
+6 -14
View File
@@ -64,7 +64,7 @@ case "$origin_url" in
https://gitea.speelman.ca/gamertan/sandwich-hime.git) https://gitea.speelman.ca/gamertan/sandwich-hime.git)
;; ;;
*) *)
printf 'error: origin is not the canonical Gamertan Gitea repository: %s\n' "$origin_url" >&2 printf 'error: origin is not the canonical Gitea repository: %s\n' "$origin_url" >&2
exit 1 exit 1
;; ;;
esac esac
@@ -131,9 +131,6 @@ for target in \
done done
for required in \ for required in \
site/index.html \
site/sando/index.html \
site/README.md \
scripts/verify-public-install.sh \ scripts/verify-public-install.sh \
RELEASE.md \ RELEASE.md \
SECURITY.md \ SECURITY.md \
@@ -142,11 +139,6 @@ for required in \
[[ -f "$required" ]] || { printf 'error: required release file is missing: %s\n' "$required" >&2; exit 1; } [[ -f "$required" ]] || { printf 'error: required release file is missing: %s\n' "$required" >&2; exit 1; }
done done
if ! grep -Fq 'gamertan.com/sandwich-hime/sando git' site/sando/index.html; then
printf 'error: nested runtime vanity-import metadata is missing\n' >&2
exit 1
fi
if (( public_release == 1 )); then if (( public_release == 1 )); then
evidence_dir=${HIMESAN_RELEASE_EVIDENCE_DIR:-} evidence_dir=${HIMESAN_RELEASE_EVIDENCE_DIR:-}
if [[ -z "$evidence_dir" || ! -d "$evidence_dir" ]]; then if [[ -z "$evidence_dir" || ! -d "$evidence_dir" ]]; then
@@ -154,18 +146,18 @@ if (( public_release == 1 )); then
exit 1 exit 1
fi fi
for evidence in \ for evidence in \
counsel-review.md \ legal-review.md \
cross-platform.md \ cross-platform.md \
eql-production-soak.md \ security.md \
security-and-accessibility.md \ development-supervisor.md \
benchmark-methodology.md \ benchmark-methodology.md \
vanity-and-mirror.md; do vanity-imports.md \
signing-and-recovery.md; do
if [[ ! -s "$evidence_dir/$evidence" ]]; then if [[ ! -s "$evidence_dir/$evidence" ]]; then
printf 'error: public release evidence is missing or empty: %s\n' "$evidence_dir/$evidence" >&2 printf 'error: public release evidence is missing or empty: %s\n' "$evidence_dir/$evidence" >&2
exit 1 exit 1
fi fi
done done
./scripts/check-site.sh --public "$version"
printf '\nHuman review is still required; evidence presence is not automatic approval.\n' printf '\nHuman review is still required; evidence presence is not automatic approval.\n'
else else
printf '\nTechnical preflight passed. Public launch remains blocked until --public evidence review passes.\n' printf '\nTechnical preflight passed. Public launch remains blocked until --public evidence review passes.\n'
+1 -1
View File
@@ -7,7 +7,7 @@ usage() {
cat <<'EOF' cat <<'EOF'
Usage: scripts/verify-public-install.sh --version vX.Y.Z Usage: scripts/verify-public-install.sh --version vX.Y.Z
Post-publication verification for Gamertan vanity metadata and the exact Post-publication verification for gamertan.com vanity metadata and the exact
documented install commands. It uses fresh temporary Go caches and never writes documented install commands. It uses fresh temporary Go caches and never writes
to the repository. Signed compiler and sando tags must already be public. to the repository. Signed compiler and sando tags must already be public.
EOF EOF
+7 -28
View File
@@ -43,12 +43,11 @@ function Invoke-ModuleChecks {
} }
function Get-SandoSources { function Get-SandoSources {
if (-not (Test-Path "examples" -PathType Container)) { if (-not (Test-Path "internal/compiler/testdata/golden" -PathType Container)) {
return @() return @()
} }
return @(Get-ChildItem "examples" -Recurse -File -Filter "*.sando" | return @(Get-ChildItem "internal/compiler/testdata/golden" -File -Filter "*.sando" |
Where-Object { $_.FullName -notmatch '[\\/](vendor|\.git)[\\/]' } |
Sort-Object FullName) Sort-Object FullName)
} }
@@ -80,29 +79,20 @@ try {
} }
Invoke-ModuleChecks "sando" "sando runtime module" Invoke-ModuleChecks "sando" "sando runtime module"
if (Test-Path "examples" -PathType Container) {
$ExampleModules = @(Get-ChildItem "examples" -Recurse -File -Filter "go.mod" |
Where-Object { $_.FullName -notmatch '[\\/](vendor|\.git)[\\/]' } |
Sort-Object FullName)
}
else {
$ExampleModules = @()
}
$Sources = @(Get-SandoSources) $Sources = @(Get-SandoSources)
if ($Sources.Count -eq 0) { if ($Sources.Count -eq 0) {
Write-Host "`n==> generation: no .sando examples exist yet; skipping deterministic-generation check" throw "compiler-owned golden .sando fixture is missing"
} }
else { else {
$SourcePaths = @($Sources | ForEach-Object { $_.FullName }) $SourcePaths = @($Sources | ForEach-Object { $_.FullName })
$CheckArgs = @("run", "./cmd/himesan", "check") + $SourcePaths $CheckArgs = @("run", "./cmd/himesan", "check") + $SourcePaths
$GenerateArgs = @("run", "./cmd/himesan", "generate") + $SourcePaths $GenerateArgs = @("run", "./cmd/himesan", "generate") + $SourcePaths
Invoke-Checked "generation: read-only freshness check" { Invoke-Checked "golden generation: read-only freshness check" {
& go $CheckArgs & go $CheckArgs
} }
$Before = Get-GeneratedManifest $Before = Get-GeneratedManifest
Invoke-Checked "generation: first deterministic pass" { Invoke-Checked "golden generation: first deterministic pass" {
& go $GenerateArgs & go $GenerateArgs
} }
$First = Get-GeneratedManifest $First = Get-GeneratedManifest
@@ -110,7 +100,7 @@ try {
throw "generation changed committed output after check declared it fresh" throw "generation changed committed output after check declared it fresh"
} }
Invoke-Checked "generation: second deterministic pass" { Invoke-Checked "golden generation: second deterministic pass" {
& go $GenerateArgs & go $GenerateArgs
} }
$Second = Get-GeneratedManifest $Second = Get-GeneratedManifest
@@ -118,22 +108,11 @@ try {
throw "repeated generation changed output bytes or an unchanged timestamp" throw "repeated generation changed output bytes or an unchanged timestamp"
} }
Invoke-Checked "generation: final freshness check" { Invoke-Checked "golden generation: final freshness check" {
& go $CheckArgs & go $CheckArgs
} }
} }
# Do not execute generated application code until check and both generation
# passes prove that it is compiler-owned, current, and deterministic.
if ($ExampleModules.Count -eq 0) {
Write-Host "`n==> examples: no example module exists yet; skipping module tests"
}
else {
foreach ($module in $ExampleModules) {
Invoke-ModuleChecks $module.Directory.FullName "example module $($module.Directory.FullName)"
}
}
if ($Race) { if ($Race) {
Invoke-Checked "compiler module: race tests" { go test -race ./... } Invoke-Checked "compiler module: race tests" { go test -race ./... }
Push-Location "sando" Push-Location "sando"
+9 -37
View File
@@ -27,24 +27,11 @@ run_module_checks() {
) )
} }
example_sources() { golden_sources() {
if [[ ! -d examples ]]; then find internal/compiler/testdata/golden \
return 0
fi
find examples \
-type d \( -name .git -o -name vendor \) -prune -o \
-type f -name '*.sando' -print | LC_ALL=C sort -type f -name '*.sando' -print | LC_ALL=C sort
} }
example_modules() {
if [[ ! -d examples ]]; then
return 0
fi
find examples \
-type d \( -name .git -o -name vendor \) -prune -o \
-type f -name go.mod -print | LC_ALL=C sort
}
generated_manifest() { generated_manifest() {
local source output digest modified local source output digest modified
while IFS= read -r source; do while IFS= read -r source; do
@@ -68,7 +55,7 @@ generated_manifest() {
modified=$(stat -f '%m' -- "$output") modified=$(stat -f '%m' -- "$output")
fi fi
printf '%s %s %s\n' "$digest" "$modified" "$output" printf '%s %s %s\n' "$digest" "$modified" "$output"
done < <(example_sources) done < <(golden_sources)
} }
log "repository scripts: shell syntax" log "repository scripts: shell syntax"
@@ -92,18 +79,16 @@ if [[ ! -f sando/go.mod ]]; then
fi fi
run_module_checks sando "sando runtime module" run_module_checks sando "sando runtime module"
log "static project site"
./scripts/check-site.sh
sources=() sources=()
while IFS= read -r source; do while IFS= read -r source; do
[[ -n "$source" ]] || continue [[ -n "$source" ]] || continue
sources[${#sources[@]}]=$source sources[${#sources[@]}]=$source
done < <(example_sources) done < <(golden_sources)
if (( ${#sources[@]} == 0 )); then if (( ${#sources[@]} == 0 )); then
log "generation: no .sando examples exist yet; skipping deterministic-generation check" printf 'error: compiler-owned golden .sando fixture is missing\n' >&2
exit 1
else else
log "generation: read-only freshness check" log "golden generation: read-only freshness check"
go run ./cmd/himesan check "${sources[@]}" go run ./cmd/himesan check "${sources[@]}"
manifest_before="$build_dir/generated-before.txt" manifest_before="$build_dir/generated-before.txt"
@@ -111,7 +96,7 @@ else
manifest_second="$build_dir/generated-second.txt" manifest_second="$build_dir/generated-second.txt"
generated_manifest >"$manifest_before" generated_manifest >"$manifest_before"
log "generation: first deterministic pass" log "golden generation: first deterministic pass"
go run ./cmd/himesan generate "${sources[@]}" go run ./cmd/himesan generate "${sources[@]}"
generated_manifest >"$manifest_first" generated_manifest >"$manifest_first"
if ! cmp -s "$manifest_before" "$manifest_first"; then if ! cmp -s "$manifest_before" "$manifest_first"; then
@@ -120,7 +105,7 @@ else
exit 1 exit 1
fi fi
log "generation: second deterministic pass" log "golden generation: second deterministic pass"
go run ./cmd/himesan generate "${sources[@]}" go run ./cmd/himesan generate "${sources[@]}"
generated_manifest >"$manifest_second" generated_manifest >"$manifest_second"
if ! cmp -s "$manifest_first" "$manifest_second"; then if ! cmp -s "$manifest_first" "$manifest_second"; then
@@ -132,19 +117,6 @@ else
go run ./cmd/himesan check "${sources[@]}" go run ./cmd/himesan check "${sources[@]}"
fi fi
# Generated application code is not executed until the read-only freshness
# check and both deterministic passes prove it is compiler-owned and current.
module_count=0
while IFS= read -r module_file; do
[[ -n "$module_file" ]] || continue
module_count=$((module_count + 1))
module_dir=$(dirname -- "$module_file")
run_module_checks "$module_dir" "example module $module_dir"
done < <(example_modules)
if (( module_count == 0 )); then
log "examples: no example module exists yet; skipping module tests"
fi
if [[ "${HIMESAN_RACE:-0}" == 1 ]]; then if [[ "${HIMESAN_RACE:-0}" == 1 ]]; then
log "compiler module: race tests" log "compiler module: race tests"
go test -race ./... go test -race ./...
-74
View File
@@ -1,74 +0,0 @@
<!-- SPDX-License-Identifier: AGPL-3.0-only -->
# Gamertan site and vanity imports
This directory is a static, no-JavaScript site for the unsupported Sandwich Hime pre-1.0 public source preview. It is source material only: repository automation must not deploy it. The page is deliberately honest that no supported v1 version exists yet.
## Intended routes
The hosting layer must serve these files over HTTPS without an authentication challenge:
| Request path | File | Purpose |
| --- | --- | --- |
| `/sandwich-hime` and `/sandwich-hime/` | `index.html` | Project page and compiler-module `go-import` metadata |
| `/sandwich-hime/sando` and `/sandwich-hime/sando/` | `sando/index.html` | Nested-runtime metadata using the Go 1.25 `subdirectory` field |
| `/sandwich-hime/assets/site.css` | `assets/site.css` | Local-only presentation |
The Go command requests the exact import path; it does not retry at a parent
path after a 404. The hosting layer therefore needs query-scoped metadata
fallbacks:
- any `/sandwich-hime/...` request with `go-get=1`, except the nested runtime
subtree, returns the compiler `index.html` with HTTP 200;
- `/sandwich-hime/sando` and every path below it with `go-get=1` return
`sando/index.html` with HTTP 200;
- ordinary browser requests for nonexistent paths continue to return 404.
This includes `/sandwich-hime/cmd/himesan?go-get=1`, which is the path queried
by the documented `go install` command. The `go-import` tags occur early in
each document because the Go command uses a restricted HTML parser.
The nested metadata is intentionally:
```html
<meta name="go-import" content="gamertan.com/sandwich-hime/sando git https://gitea.speelman.ca/gamertan/sandwich-hime.git sando">
```
The fourth field maps the vanity path to the repositorys `sando` subdirectory. It is supported by the projects minimum Go line, Go 1.25. Runtime versions must use tags such as `sando/v1.0.0`.
## Hosting setup
1. Keep the public DNS and TLS authority for `gamertan.com` under founder control. Use an `A`/`AAAA` record or a narrowly scoped `CNAME` appropriate to the chosen static host; do not delegate the whole zone to a project contributor.
2. Configure the exact browser routes plus the query-scoped `go-get=1`
fallbacks above. Preserve ordinary 404 behavior and do not use a client-side
redirect for metadata requests.
3. Return `Content-Type: text/html; charset=utf-8` for HTML and `text/css; charset=utf-8` for CSS.
4. Add server headers at least equivalent to `Content-Security-Policy: default-src 'none'; style-src 'self'; base-uri 'none'; form-action 'none'; frame-ancestors 'none'`, `Referrer-Policy: no-referrer`, `X-Content-Type-Options: nosniff`, and a conservative `Permissions-Policy`.
5. Keep deployment credentials outside this repository. A future deploy workflow needs a separately reviewed, least-privilege credential and protected environment approval.
6. Verify from an uncached public network before announcing installs:
```sh
curl -fsS 'https://gamertan.com/sandwich-hime?go-get=1'
curl -fsS 'https://gamertan.com/sandwich-hime/cmd/himesan?go-get=1'
curl -fsS 'https://gamertan.com/sandwich-hime/sando?go-get=1'
./scripts/verify-public-install.sh --version v1.0.0
```
## Launch blockers
Do not deploy or remove the pre-release warning until all of these are evidenced:
- canonical Gitea is public, the security contact works, and protected release-key controls are active;
- root `v1.0.0` and nested `sando/v1.0.0` are signed and accompanied by checksums, SBOMs, release binaries, and reproducibility notes;
- Go 1.25 and Go 1.26 pass deterministic generation and tests on Linux, macOS, and Windows, including the canonical manual cross-platform workflow;
- vulnerability, race, fuzz, adversarial, license, accessibility, and CSP checks pass;
- EQL Wiki completes its differential pilot and 14-day production soak without Hime render, security, or accessibility regressions;
- the DCO contribution process, license map, governance, output permission, and trademark policy have final human review;
- `scripts/release-check.sh --version v1.0.0 --public` passes against a human-reviewed evidence bundle;
- the exact public `go install` and `go get` commands pass
`scripts/verify-public-install.sh` from clean direct-fetch and public-proxy
caches without repository credentials.
At launch, replace each pages `himesan-release-status` value with the exact compiler release (for example, `v1.0.0`), replace the human-facing pre-release copy with verified install information, and run `scripts/check-site.sh --public v1.0.0`. The public release preflight enforces that transition so a green evidence bundle cannot accidentally publish a page that still says the runtime does not exist.
Gitea is the sole public forge. Cross-platform evidence must come from reviewed local or Gitea-runner execution; no secondary mirror or hosted workflow is part of the release plan.
-398
View File
@@ -1,398 +0,0 @@
/* SPDX-License-Identifier: AGPL-3.0-only */
:root {
color-scheme: dark;
--ink: #fff9eb;
--muted: #c9c2dd;
--night: #100a25;
--deep: #251849;
--panel: #30235a;
--panel-light: #453476;
--pink: #ff74b8;
--cyan: #70e6e1;
--yellow: #ffe38a;
--line: #8e75c4;
--shadow: #090617;
--focus: #fff3a8;
font-family: Verdana, Geneva, Tahoma, sans-serif;
font-size: 16px;
}
* {
box-sizing: border-box;
}
html {
min-width: 20rem;
background: var(--night);
scroll-behavior: smooth;
}
body {
margin: 0;
color: var(--ink);
background-color: var(--night);
background-image:
linear-gradient(45deg, rgb(112 230 225 / 4%) 25%, transparent 25%),
linear-gradient(-45deg, rgb(255 116 184 / 4%) 25%, transparent 25%),
linear-gradient(45deg, transparent 75%, rgb(112 230 225 / 4%) 75%),
linear-gradient(-45deg, transparent 75%, rgb(255 116 184 / 4%) 75%);
background-position: 0 0, 0 8px, 8px -8px, -8px 0;
background-size: 16px 16px;
line-height: 1.65;
}
a {
color: var(--cyan);
text-underline-offset: 0.18em;
text-decoration-thickness: 0.1em;
}
a:hover {
color: var(--yellow);
}
a:focus-visible {
color: var(--night);
background: var(--focus);
outline: 0.2rem solid var(--focus);
outline-offset: 0.2rem;
}
code,
pre {
font-family: "Courier New", Courier, monospace;
}
code {
color: var(--yellow);
}
.skip-link {
position: fixed;
z-index: 10;
top: 0.8rem;
left: 0.8rem;
padding: 0.65rem 0.9rem;
color: var(--night);
background: var(--focus);
transform: translateY(-180%);
}
.skip-link:focus {
transform: translateY(0);
}
.masthead {
border-bottom: 0.3rem ridge var(--pink);
background:
radial-gradient(circle at 20% 20%, rgb(112 230 225 / 16%), transparent 28rem),
linear-gradient(180deg, var(--deep), var(--night));
text-align: center;
}
.status-strip {
padding: 0.45rem 1rem;
color: var(--night);
background: repeating-linear-gradient(
-45deg,
var(--yellow),
var(--yellow) 0.7rem,
#ffd35a 0.7rem,
#ffd35a 1.4rem
);
border-bottom: 0.15rem solid #6c5414;
font-size: 0.78rem;
font-weight: 700;
letter-spacing: 0.03em;
text-transform: uppercase;
}
.masthead-inner,
main,
footer {
width: min(70rem, calc(100% - 2rem));
margin-inline: auto;
}
.masthead-inner {
padding: 4rem 0 4.5rem;
}
.compact .masthead-inner {
padding-block: 3rem;
}
.eyebrow {
margin: 0 0 0.8rem;
color: var(--pink);
font-size: 0.82rem;
font-weight: 700;
letter-spacing: 0.16em;
text-transform: uppercase;
}
.wordmark {
width: fit-content;
max-width: 100%;
margin: 0 auto 1.5rem;
overflow: hidden;
color: var(--cyan);
font-size: clamp(0.72rem, 2.8vw, 1.05rem);
font-weight: 700;
line-height: 1.15;
text-align: left;
text-shadow: 0.12rem 0.12rem 0 var(--pink);
}
h1,
h2,
h3,
p {
overflow-wrap: anywhere;
}
h1 {
max-width: 19ch;
margin: 0 auto;
font-family: Georgia, "Times New Roman", serif;
font-size: clamp(2.25rem, 7vw, 4.8rem);
line-height: 1.02;
text-wrap: balance;
text-shadow: 0.18rem 0.18rem 0 var(--shadow);
}
.compact h1 {
font-size: clamp(2rem, 6vw, 3.8rem);
}
.lede {
max-width: 47rem;
margin: 1.5rem auto 0;
color: var(--muted);
font-size: clamp(1.05rem, 2.5vw, 1.28rem);
}
.button-row {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 0.8rem;
margin-top: 2rem;
}
.button-row a {
padding: 0.7rem 1rem;
color: var(--night);
background: var(--cyan);
border: 0.15rem outset #c6ffff;
box-shadow: 0.18rem 0.18rem 0 var(--shadow);
font-weight: 700;
text-decoration: none;
}
.button-row a:nth-child(2) {
background: var(--pink);
border-color: #ffc2df;
}
.button-row a:active {
border-style: inset;
box-shadow: none;
transform: translate(0.12rem, 0.12rem);
}
.mirror-note {
margin: 1rem auto 0;
color: var(--muted);
font-size: 0.85rem;
}
main {
display: grid;
gap: 1.5rem;
padding-block: 2rem 4rem;
}
.panel {
position: relative;
padding: clamp(1.25rem, 4vw, 2.5rem);
background: linear-gradient(135deg, var(--panel), #271c4a);
border: 0.2rem ridge var(--line);
box-shadow: 0.35rem 0.35rem 0 var(--shadow);
}
.panel h2 {
margin: 0 0 1rem;
color: var(--yellow);
font-family: Georgia, "Times New Roman", serif;
font-size: clamp(1.55rem, 4vw, 2.35rem);
line-height: 1.15;
}
.panel h3 {
margin-top: 0;
font-size: 1.15rem;
}
.panel p:last-child {
margin-bottom: 0;
}
.code-panel {
display: grid;
grid-template-columns: minmax(0, 0.8fr) minmax(20rem, 1.2fr);
gap: 2rem;
align-items: center;
}
.sticker {
display: inline-block;
margin: 0 0 1rem;
padding: 0.25rem 0.55rem;
color: var(--night);
background: var(--pink);
border: 0.12rem outset #ffd2e8;
font: 700 0.72rem/1 Verdana, sans-serif;
text-transform: uppercase;
transform: rotate(-2deg);
}
.code {
margin: 0;
padding: 1.25rem;
overflow-x: auto;
color: var(--ink);
background: #0c0919;
border: 0.15rem inset var(--line);
font-size: clamp(0.78rem, 1.8vw, 0.96rem);
line-height: 1.5;
tab-size: 2;
}
.code code {
color: inherit;
}
.cards {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 1rem;
}
.cards article {
padding: 1rem;
background: rgb(16 10 37 / 55%);
border: 0.1rem solid var(--line);
}
.origin {
display: grid;
grid-template-columns: auto minmax(0, 1fr);
gap: 1.5rem;
align-items: center;
}
.pixel-heart {
color: var(--pink);
font-family: "Courier New", monospace;
font-size: clamp(4rem, 12vw, 7rem);
line-height: 1;
text-shadow:
0.16rem 0 var(--pink),
-0.16rem 0 var(--pink),
0 0.16rem var(--pink),
0.3rem 0.3rem 0 var(--shadow);
}
.checklist {
display: grid;
gap: 0.55rem;
padding: 0;
list-style: none;
}
.checklist span {
margin-right: 0.5rem;
color: var(--cyan);
}
.honesty-box {
padding: 1rem;
color: var(--night);
background: var(--yellow);
border: 0.18rem outset #fff0b9;
font-weight: 700;
}
.names dl {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 0.7rem;
}
.names dl div {
padding: 0.8rem;
background: rgb(16 10 37 / 55%);
border-left: 0.3rem solid var(--pink);
}
.names dt {
color: var(--cyan);
font-size: 0.78rem;
font-weight: 700;
letter-spacing: 0.08em;
text-transform: uppercase;
}
.names dd {
margin: 0.2rem 0 0;
}
footer {
padding-block: 2rem 3rem;
color: var(--muted);
border-top: 0.1rem dashed var(--line);
text-align: center;
}
.fine-print {
font-size: 0.78rem;
}
@media (max-width: 48rem) {
.code-panel,
.cards,
.names dl {
grid-template-columns: 1fr;
}
.origin {
grid-template-columns: 1fr;
text-align: center;
}
}
@media (prefers-reduced-motion: reduce) {
html {
scroll-behavior: auto;
}
*,
*::before,
*::after {
scroll-behavior: auto !important;
transition-duration: 0.01ms !important;
}
}
@media (forced-colors: active) {
.panel,
.cards article,
.names dl div,
.button-row a,
.honesty-box {
border: 0.12rem solid CanvasText;
box-shadow: none;
}
}
-166
View File
@@ -1,166 +0,0 @@
<!doctype html>
<!-- SPDX-License-Identifier: AGPL-3.0-only -->
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="go-import" content="gamertan.com/sandwich-hime git https://gitea.speelman.ca/gamertan/sandwich-hime.git">
<meta name="go-source" content="gamertan.com/sandwich-hime https://gitea.speelman.ca/gamertan/sandwich-hime https://gitea.speelman.ca/gamertan/sandwich-hime/src/branch/main{/dir} https://gitea.speelman.ca/gamertan/sandwich-hime/src/branch/main{/dir}/{file}#L{line}">
<meta name="himesan-release-status" content="pre-release">
<meta name="description" content="Sandwich Hime is an HTML-first, PHP-feeling Go component compiler published as an unsupported pre-1.0 source preview.">
<meta name="theme-color" content="#251849">
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src 'self'; img-src 'self'; base-uri 'none'; form-action 'none'">
<title>Sandwich Hime — typed Go templates with a hand-built-web heart</title>
<link rel="stylesheet" href="./assets/site.css">
</head>
<body>
<a class="skip-link" href="#main">Skip to the sandwich</a>
<header class="masthead">
<div class="status-strip" role="status">
<span aria-hidden="true"></span>
Public pre-1.0 source preview — unsupported, no v1 release
<span aria-hidden="true"></span>
</div>
<div class="masthead-inner">
<p class="eyebrow">Gamertan dot com presents</p>
<pre class="wordmark" role="img" aria-label="Sandwich Hime">
╭────────────────────────╮
│ SANDWICH HIME-SAN │
╰──────────┬─────────────╯
HTML ♥ GO
</pre>
<h1>A tiny compiler for people who still want to touch the web.</h1>
<p class="lede">
Sandwich Hime turns one <code>.sando</code> component into ordinary,
reviewable Go. It aims for the immediacy of classic mixed markup,
while keeping typed data, contextual safety, and boring deployments.
</p>
<nav aria-label="Project destinations" class="button-row">
<a href="https://gitea.speelman.ca/gamertan/sandwich-hime">Canonical Gitea</a>
<a href="#status">Read the release status</a>
</nav>
<p class="mirror-note">
Source and contributions live only on canonical Gitea.
</p>
</div>
</header>
<main id="main">
<section class="panel code-panel" aria-labelledby="taste-heading">
<div>
<p class="sticker" aria-hidden="true">view source!</p>
<h2 id="taste-heading">A taste of <code>.sando</code></h2>
<p>
Markup is the main language. Go appears exactly where the page needs
it, and every rendered value is escaped for its known HTML context.
</p>
</div>
<pre class="code" tabindex="0" role="region" aria-label="Profile component template example"><code>&lt;?sando go
package views
func Profile(page ProfileView)
?&gt;
&lt;section class="profile"&gt;
&lt;h1&gt;&lt;?= page.Name ?&gt;&lt;/h1&gt;
&lt;? if page.IsAdmin { ?&gt;
&lt;?~ AdminBadge() ?&gt;
&lt;? } ?&gt;
&lt;/section&gt;</code></pre>
</section>
<section class="panel" aria-labelledby="boundary-heading">
<h2 id="boundary-heading">Compiler at the workbench. Small runtime in production.</h2>
<div class="cards">
<article>
<h3><code>himesan</code></h3>
<p>
A globally installed development tool that checks, generates, and
supervises a local server. It does not own your router or app.
</p>
</article>
<article>
<h3><code>page.sando.go</code></h3>
<p>
Deterministic generated Go, committed beside its source so code
review and production builds do not need the compiler.
</p>
</article>
<article>
<h3><code>sando</code></h3>
<p>
A deliberately small Apache-2.0 runtime: components, error-aware
rendering, and stable escaping helpers—no production server.
</p>
</article>
</div>
</section>
<section class="panel origin" aria-labelledby="origin-heading">
<div class="pixel-heart" aria-hidden="true"></div>
<div>
<h2 id="origin-heading">From a 2004 PSO game-club page, with love</h2>
<p>
The spirit is personal-site webmaking: open the file, understand the
page, change the page. Sandwich Hime is a love letter to a first
Geocities-era site last updated in 2004—rebuilt with the safety and
repeatability expected from a serious modern Go project.
</p>
<p>
The checkerboard, bevels, and tiny status lights are intentional.
The security model is also intentional.
</p>
</div>
</section>
<section class="panel" id="status" aria-labelledby="status-heading">
<h2 id="status-heading">Proof first. Release second.</h2>
<p>
Hime-san has no supported tagged public version yet. EQL Wiki is the
production proving ground, and v1 remains unreleased until the compiler,
runtime, development supervisor, and contextual escaping have durable
evidence behind them.
</p>
<ul class="checklist">
<li><span aria-hidden="true"></span> Cross-platform deterministic generation on Go 1.25 and 1.26</li>
<li><span aria-hidden="true"></span> Adversarial, fuzz, race, vulnerability, and accessibility gates</li>
<li><span aria-hidden="true"></span> EQL differential pilot and a clean 14-day production soak</li>
<li><span aria-hidden="true"></span> Working security contact and human-reviewed project policies</li>
<li><span aria-hidden="true"></span> Signed tags, checksums, SBOMs, binaries, and vanity paths</li>
</ul>
<p class="honesty-box">
No “fastest template engine” promises live here. Any performance claim
will ship with the hardware, commit, dataset, commands, latency, and
allocation results needed to reproduce it.
</p>
</section>
<section class="panel names" aria-labelledby="names-heading">
<h2 id="names-heading">Please keep the name tags on the right guests</h2>
<dl>
<div><dt>Project</dt><dd>Sandwich Hime / Hime-san</dd></div>
<div><dt>Command</dt><dd><code>himesan</code></dd></div>
<div><dt>Template</dt><dd><code>page.sando</code></dd></div>
<div><dt>Runtime</dt><dd><code>sando</code></dd></div>
<div><dt>San language</dt><dd><code>.san</code>—reserved, separate, and never a Hime-san template</dd></div>
</dl>
<p>
“Hime” on its own already belongs to an unrelated Go framework. The
compound Sandwich Hime and Hime-san identity avoids stepping on it.
</p>
</section>
</main>
<footer>
<p>
<span aria-hidden="true">[</span>
Hand-built for the web by Gamertan
<span aria-hidden="true">]</span>
</p>
<p class="fine-print">
Unsupported pre-1.0 preview. Compiler sources are AGPL-3.0-only; the
nested runtime is Apache-2.0; copyable examples are 0BSD.
</p>
</footer>
</body>
</html>
-47
View File
@@ -1,47 +0,0 @@
<!doctype html>
<!-- SPDX-License-Identifier: AGPL-3.0-only -->
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="go-import" content="gamertan.com/sandwich-hime/sando git https://gitea.speelman.ca/gamertan/sandwich-hime.git sando">
<meta name="go-source" content="gamertan.com/sandwich-hime/sando https://gitea.speelman.ca/gamertan/sandwich-hime/src/branch/main/sando https://gitea.speelman.ca/gamertan/sandwich-hime/src/branch/main/sando{/dir} https://gitea.speelman.ca/gamertan/sandwich-hime/src/branch/main/sando{/dir}/{file}#L{line}">
<meta name="himesan-release-status" content="pre-release">
<meta name="description" content="Vanity import metadata for the Apache-2.0 Sandwich Hime sando runtime.">
<meta name="theme-color" content="#251849">
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src 'self'; base-uri 'none'; form-action 'none'">
<title>sando runtime — Sandwich Hime</title>
<link rel="stylesheet" href="../assets/site.css">
</head>
<body>
<a class="skip-link" href="#main">Skip to the runtime note</a>
<header class="masthead compact">
<div class="status-strip" role="status">Public source-preview metadata — no public runtime tag yet</div>
<div class="masthead-inner">
<p class="eyebrow">Sandwich Hime / Hime-san</p>
<h1><code>sando</code> is the small production runtime.</h1>
<p class="lede">
This page carries Go 1.25+ vanity-import metadata for the nested module
at <code>gamertan.com/sandwich-hime/sando</code>.
</p>
</div>
</header>
<main id="main">
<section class="panel">
<h2>Not released yet</h2>
<p>
The runtime will be tagged independently as <code>sando/vX.Y.Z</code>
and licensed Apache-2.0. Do not add this vanity path to production until
a signed release exists and the install check is published.
</p>
<p>
<a href="../">Return to the Sandwich Hime project page</a> or inspect
the <a href="https://gitea.speelman.ca/gamertan/sandwich-hime/src/branch/main/sando">canonical runtime source on Gitea</a>.
</p>
</section>
</main>
<footer>
<p>HTML-first templates. Ordinary Go. A hand-built-web heart.</p>
</footer>
</body>
</html>