diff --git a/.gitea/workflows/phase0-build.yml b/.gitea/workflows/phase0-build.yml new file mode 100644 index 0000000..79c1284 --- /dev/null +++ b/.gitea/workflows/phase0-build.yml @@ -0,0 +1,23 @@ +name: Phase 0 build gate + +on: + push: + pull_request: + +permissions: read-all + +jobs: + verify: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + persist-credentials: false + - name: Set up Go 1.25 + uses: actions/setup-go@v5 + with: + go-version: "1.25.0" + cache: false + - name: Run Phase 0 verification + run: bash scripts/verify_phase0.sh diff --git a/docs/00-ai-start-here.md b/docs/00-ai-start-here.md index 1b9d2ab..fc437f4 100644 --- a/docs/00-ai-start-here.md +++ b/docs/00-ai-start-here.md @@ -45,12 +45,12 @@ SoftBox 软件盒子是一个使用 Go + Gio 开发的 Windows 桌面客户端, ## 当前阶段 -当前项目处于:**MVP 起步(Phase 0 工程骨架建设中)**。 +当前项目处于:**M1 已完成(Phase 0 工程骨架、双 Gio 窗口与双目标编译闸门已建立),准备进入 Phase 1 高风险原型**。 优先路径: -1. Phase 0:monorepo 骨架 + 双目标编译 + 空 Gio 窗口。 -2. Phase 1:三大高风险原型(清单验签、ZIP 安全解压、原子切换回滚)。 +1. 已完成 Phase 0:monorepo 骨架 + 双目标编译 + 空 Gio 窗口。 +2. 下一步 Phase 1:三大高风险原型(清单验签、ZIP 安全解压、原子切换回滚)。 3. Phase 2-3:清单/列表 → 下载/安装。 4. Phase 4-5:启动/更新/自更新 → 授权。 5. Phase 6:Win7 加固与双通道发布。 @@ -133,17 +133,17 @@ MVP 不做: ## 验证命令 -统一启动与验证入口收敛到根目录 `./init.sh` / `./init.ps1`;脚本会同步工作区依赖并运行 core 基础验证。标准命令: +统一启动与验证入口收敛到根目录 `./init.sh` / `./init.ps1`;脚本会同步工作区依赖并运行完整 Phase 0 闸门。也可直接运行 `bash scripts/verify_phase0.sh` / `./scripts/verify_phase0.ps1`。标准分项命令: ```bash # core 测试(Linux 无头可跑) cd core && go vet ./... && go test -count=1 ./... # 现代版构建 -cd app-modern && GOTOOLCHAIN=go1.25.0 GOOS=windows GOARCH=amd64 go build ./cmd/softbox +cd app-modern && GOTOOLCHAIN=go1.25.0 CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -trimpath -ldflags="-H=windowsgui" ./cmd/softbox # Win7 版构建(强制 Go 1.20) -cd app-win7 && GOTOOLCHAIN=go1.20.14 GOOS=windows GOARCH=amd64 go build ./cmd/softbox +cd app-win7 && GOTOOLCHAIN=go1.20.14 CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -trimpath -ldflags="-H=windowsgui" ./cmd/softbox ``` 说明: diff --git a/docs/03-tech-stack.md b/docs/03-tech-stack.md index d4fc736..bcf78e1 100644 --- a/docs/03-tech-stack.md +++ b/docs/03-tech-stack.md @@ -21,7 +21,7 @@ | Windows API | golang.org/x/sys/windows + 动态加载(LoadLibrary) | 已定 | Win10 专属 API 动态加载并降级,不进导入表 | | EXE 签名 | Authenticode | 已定 | 主程序与 Updater 均签名;证书采购待确认 | | 测试 | go test(core 无头可测) + fake/stub 注入 | 已定 | domain/application 不依赖 Gio 与 Windows API | -| CI | 待定(Gitea Actions 或本地脚本) | 待定 | 需同时编译 modern 与 win7 双目标 | +| CI | Gitea Actions 模板 + 本地 Phase 0 脚本 | 部分已定 | `.gitea/workflows/phase0-build.yml` 复用本地入口;远端 runner 可用性待确认 | | 静态检查 | go vet(+ 待定 golangci-lint) | 部分已定 | vet 必跑;lint 工具后续确认 | ## 二、决策记录与演进 @@ -37,13 +37,15 @@ > 工程骨架由 T-001 建立;根目录 `init.sh`/`init.ps1` 统一执行依赖同步与 core 基础验证,并打印双目标构建命令。 -| 用途 | 命令(计划) | +| 用途 | 命令 | | --- | --- | +| Phase 0 完整闸门(Unix) | `bash scripts/verify_phase0.sh` | +| Phase 0 完整闸门(Windows) | `./scripts/verify_phase0.ps1` | | 同步工作区依赖 | `go work sync` | | core 测试 | `cd core && go test -count=1 ./...` | | core 静态检查 | `cd core && go vet ./...` | -| 现代版构建 | `cd app-modern && GOTOOLCHAIN=go1.25.0 GOOS=windows GOARCH=amd64 go build -o ../dist/SoftBox.exe ./cmd/softbox` | -| Win7 版构建 | `cd app-win7 && GOTOOLCHAIN=go1.20.14 GOOS=windows GOARCH=amd64 go build -o ../dist/SoftBox-win7.exe ./cmd/softbox` | +| 现代版构建 | `cd app-modern && GOTOOLCHAIN=go1.25.0 CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -trimpath -ldflags="-H=windowsgui" -o ../dist/SoftBox.exe ./cmd/softbox` | +| Win7 版构建 | `cd app-win7 && GOTOOLCHAIN=go1.20.14 CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -trimpath -ldflags="-H=windowsgui" -o ../dist/SoftBox-win7.exe ./cmd/softbox` | | 本地运行(开发) | Windows 下直接 `go run ./cmd/softbox`(WSL 中构建 EXE 后到 Windows 侧运行) | 根 `go.work` 纳入三个模块并使用 modern 所需的 Go 1.25 workspace 版本;`app-win7/go.work` 是就近的 Go 1.20 workspace,只纳入 `app-win7` 与 `core`,确保 Go 1.20.14 不需要解析 modern 模块。 diff --git a/docs/current-state.md b/docs/current-state.md index 74dda95..c6c44ae 100644 --- a/docs/current-state.md +++ b/docs/current-state.md @@ -13,15 +13,15 @@ ## 当前快照 - 日期:2026-07-16 -- 阶段:MVP 起步(Phase 0 工程骨架建设中) +- 阶段:M1 已完成(Phase 0 工程骨架、状态/事件模型、双 Gio 窗口、平台 stub 与双目标验证闸门全部落地) - 技术栈:根 Go workspace 纳入 core/app-modern/app-win7 三模块;`app-win7/go.work` 隔离 Go 1.20.14 构建;modern Gio v0.10.1 与 win7 Gio v0.6.0 已实际接入 - 生产代码:core 已有状态模型与事件 runtime;modern/win7 均可打开最小 AppShell,并有平台接口、Windows 实现与非 Windows stub -- 测试:core 覆盖状态/事件 runtime;两个 app 覆盖 AppShell 布局尺寸与平台 stub 契约 +- 测试:core 覆盖状态/事件 runtime;两个 app 覆盖 AppShell 布局尺寸与平台 stub 契约;Phase 0 脚本统一执行全部验证 - 数据:无;Catalog 清单与测试样例待建 -- 标准启动路径:`./init.sh` / `./init.ps1`(同步依赖、验证 core、打印 modern/win7 双目标构建命令) -- 标准验证路径:`go -C core vet ./...` + `go -C core test -count=1 ./...`;双目标构建命令见下文 +- 标准启动路径:`./init.sh` / `./init.ps1`(同步依赖、执行完整 Phase 0 闸门、打印双目标构建命令) +- 标准验证路径:`bash scripts/verify_phase0.sh` / `./scripts/verify_phase0.ps1` - 版本管理:git 已初始化,main 分支,远端 origin 为 Gitea `opc/soft_quay`;harness 文档已提交 -- 当前 blocker:无;下一步按路线图落成并领取 T-004 +- 当前 blocker:无;下一步按路线图落成并领取 T-101 ## 当前目录要点 @@ -29,7 +29,7 @@ | --- | --- | --- | | `docs/` | 已有 | harness coding 文档集(本次初始化完成) | | `docs/tasks/` | 已有 | 任务目录;T-001 已完成,T-002 待按路线图落成 | -| `scripts/` | 已有 | harness 治理脚本 + `check_core_boundaries.py`;Phase 0 构建闸门待 T-004 | +| `scripts/` | 已有 | harness 治理、core 边界、Go 版本检查与 Phase 0 双平台验证入口 | | `core/` | 已建 | Go 1.20 兼容共享模块;已有 domain 状态模型与 application 事件 runtime | | `app-modern/` | 已建 | Go 1.25.0 + Gio v0.10.1;可打开 Modern AppShell | | `app-win7/` | 已建 | Go 1.20 + Gio v0.6.0;可打开带 Legacy 标识的 AppShell | @@ -40,23 +40,20 @@ 任务状态以 `docs/tasks/` 各任务文件 frontmatter 的 `status` 为准。本节只写项目级摘要: -- 已完成:`T-001 初始化 monorepo 骨架`、`T-002 建立 domain 状态模型与事件总线`、`T-003 Gio 空窗口 + 平台层 stub`。 +- 已完成:Phase 0 的 `T-001`、`T-002`、`T-003`、`T-004`。 - 正在进行:无。 -- 下一个可领取任务:按路线图落成并领取 `T-004 CI 双目标编译闸门`。 +- 下一个可领取任务:按路线图落成并领取 `T-101 签名清单验签与缓存回退原型`。 ## 当前可运行内容 ```bash -# 统一依赖同步 + core 验证: +# 统一依赖同步 + 完整 Phase 0 验证: ./init.sh # Windows PowerShell 使用 ./init.ps1 -# 独立验证: -go -C core vet ./... -go -C core test -count=1 ./... -python scripts/check_core_boundaries.py -GOTOOLCHAIN=go1.25.0 GOOS=windows GOARCH=amd64 go -C app-modern build ./cmd/softbox -GOTOOLCHAIN=go1.20.14 GOOS=windows GOARCH=amd64 go -C app-win7 build ./cmd/softbox +# 直接运行验证闸门: +bash scripts/verify_phase0.sh +# Windows PowerShell 使用 ./scripts/verify_phase0.ps1 ``` ## 开始编码前检查 diff --git a/docs/tasks/T-004.md b/docs/tasks/T-004.md new file mode 100644 index 0000000..1710194 --- /dev/null +++ b/docs/tasks/T-004.md @@ -0,0 +1,67 @@ +--- +id: T-004 +title: 建立 Phase 0 双目标编译与依赖版本闸门 +phase: 0 +deps: [T-001] +status: DONE +created: 2026-07-16 +issue: null +context_ref: 6f920eb4578c17c0962b6e593177cd2a3ca57f1b +claim_branch: null +work_branch: agent/codex/T-004 +write_paths: + - docs/tasks/T-004.md + - scripts/check_go_versions.py + - scripts/verify_phase0.ps1 + - scripts/verify_phase0.sh + - .gitea/workflows/phase0-build.yml + - init.ps1 + - init.sh + - docs/00-ai-start-here.md + - docs/03-tech-stack.md + - docs/current-state.md +--- + +## 问题 / 背景 + +Phase 0 已有可编译骨架、core 状态/事件模型和两个 Gio 窗口,但验证命令仍分散在文档与人工操作中。需要一个可重复执行的本地/CI 闸门,防止 modern、Win7 或 core 兼容性在后续任务中悄然破坏。 + +## 方案 + +1. 新增 Windows PowerShell 与 Unix shell 两个等价入口,统一运行治理检查、core 边界检查、Go 1.20 core vet/test、modern UI/platform 测试与构建、win7 UI/platform 测试与构建。 +2. 新增 Python 标准库依赖版本检查:校验 go/workspace 指令与 Gio 锁定版本,并用 Go 1.20.14 的 `go list -m -json all` 拒绝 core/win7 依赖声明 Go 1.21+。 +3. Windows 构建统一使用 `CGO_ENABLED=0`、`-trimpath` 与 Windows GUI subsystem linker flag。 +4. 根 init 脚本的 VERIFY 命令改为调用 Phase 0 闸门。 +5. 新增 Gitea Actions workflow 模板,在 push/PR 使用同一 Unix 验证入口;runner 未启用时以本地同命令为验收证据。 + +## 验收要点 + +- `scripts/verify_phase0.ps1` 在当前 Windows 环境全绿。 +- Git Bash `scripts/verify_phase0.sh` 在当前环境全绿。 +- 闸门包含 core vet/test、core 边界、modern 构建、win7 Go 1.20.14 构建、UI/platform 测试和治理检查。 +- 版本检查能拒绝 core/win7 的 Go 1.21+ 模块,并验证 Gio v0.10.1/v0.6.0 锁定。 +- `.gitea/workflows/phase0-build.yml` 只读权限、关闭 checkout 凭据持久化,调用同一本地入口。 +- `./init.ps1` 与 Git Bash `./init.sh` 通过新的完整 VERIFY 路径。 + +## 边界(不改什么) + +- 不启用或配置远端 runner,不宣称远端 CI 已运行。 +- 不升级 Go、Gio 或其他依赖版本。 +- 不实现 Phase 1 业务功能。 +- 不写入密钥、token 或真实发布配置。 + +## 协作约束 + +未启用 Gitea;本任务在 `agent/codex/T-004` 分支串行执行。CI 与本地必须复用同一脚本,不得维护两套不同验证逻辑。 + +## 执行记录 + +- 2026-07-16:新增 `scripts/verify_phase0.ps1` 与 `scripts/verify_phase0.sh`,统一运行治理、core 边界、Go 1.20 core vet/test、modern/win7 adapter 测试与双目标 GUI 构建。 +- 2026-07-16:新增 `scripts/check_go_versions.py`,校验 root/core/modern/win7 的 go 指令与 Gio 锁定版本,并强制使用 Go 1.20.14 扫描 core/win7 完整模块图。 +- 2026-07-16:版本检查确认 13 个模块记录均声明 Go 1.20 或更低;内置 self-check 明确接受 1.20、拒绝 1.21。 +- 2026-07-16:Windows 构建统一使用 `CGO_ENABLED=0`、`-trimpath`、`-H=windowsgui`;根 init 脚本 VERIFY 已切换到完整 Phase 0 闸门。 +- 2026-07-16:新增 `.gitea/workflows/phase0-build.yml`,使用只读权限、禁用 checkout 凭据持久化并复用 Unix 本地入口。远端 runner 未启用/未验证,不宣称远端 CI 已跑绿。 +- 验证通过:`./scripts/verify_phase0.ps1`。 +- 验证通过:Git Bash `bash scripts/verify_phase0.sh`。 +- 验证通过:`./init.ps1` 与 Git Bash `./init.sh`,均执行完整 Phase 0 闸门。 +- 验证结果:core Go 1.20.14 vet/test、modern Go 1.25.0 Windows amd64 GUI 构建、win7 Go 1.20.14 Windows amd64 GUI 构建、两个 adapter 测试、治理与边界检查全部通过。 diff --git a/init.ps1 b/init.ps1 index e04effe..bd91302 100644 --- a/init.ps1 +++ b/init.ps1 @@ -7,11 +7,14 @@ # 三个命令是仓库统一入口;换工具链时同步更新文档与这里。 $ErrorActionPreference = "Stop" +$Utf8 = [System.Text.UTF8Encoding]::new($false) +[Console]::OutputEncoding = $Utf8 +$OutputEncoding = $Utf8 Set-Location -Path $PSScriptRoot $InstallCmd = "go work sync" -$VerifyCmd = 'go -C core vet ./...; if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }; go -C core test -count=1 ./...' -$StartCmd = '$env:GOTOOLCHAIN="go1.25.0"; $env:GOOS="windows"; $env:GOARCH="amd64"; go build -C app-modern -o ../dist/SoftBox.exe ./cmd/softbox; if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }; $env:GOTOOLCHAIN="go1.20.14"; go build -C app-win7 -o ../dist/SoftBox-win7.exe ./cmd/softbox' +$VerifyCmd = "./scripts/verify_phase0.ps1" +$StartCmd = '$env:CGO_ENABLED="0"; $env:GOOS="windows"; $env:GOARCH="amd64"; $env:GOTOOLCHAIN="go1.25.0"; go build -C app-modern -trimpath "-ldflags=-H=windowsgui" -o ../dist/SoftBox.exe ./cmd/softbox; if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }; $env:GOTOOLCHAIN="go1.20.14"; go build -C app-win7 -trimpath "-ldflags=-H=windowsgui" -o ../dist/SoftBox-win7.exe ./cmd/softbox' Write-Host "==> 当前目录: $($PWD.Path)" diff --git a/init.sh b/init.sh index 5228b5b..d645ebf 100755 --- a/init.sh +++ b/init.sh @@ -12,8 +12,8 @@ ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" cd "$ROOT_DIR" INSTALL_CMD="go work sync" -VERIFY_CMD="go -C core vet ./... && go -C core test -count=1 ./..." -START_CMD="GOTOOLCHAIN=go1.25.0 GOOS=windows GOARCH=amd64 go -C app-modern build -o ../dist/SoftBox.exe ./cmd/softbox && GOTOOLCHAIN=go1.20.14 GOOS=windows GOARCH=amd64 go -C app-win7 build -o ../dist/SoftBox-win7.exe ./cmd/softbox" +VERIFY_CMD="bash scripts/verify_phase0.sh" +START_CMD="GOTOOLCHAIN=go1.25.0 CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go -C app-modern build -trimpath -ldflags=-H=windowsgui -o ../dist/SoftBox.exe ./cmd/softbox && GOTOOLCHAIN=go1.20.14 CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go -C app-win7 build -trimpath -ldflags=-H=windowsgui -o ../dist/SoftBox-win7.exe ./cmd/softbox" echo "==> 当前目录: $PWD" diff --git a/scripts/check_go_versions.py b/scripts/check_go_versions.py new file mode 100644 index 0000000..4127f64 --- /dev/null +++ b/scripts/check_go_versions.py @@ -0,0 +1,179 @@ +#!/usr/bin/env python3 +"""Validate toolchain pins and Go 1.20 compatibility of core/win7 modules.""" + +import json +import os +import pathlib +import re +import subprocess +import sys + + +MAX_LEGACY_GO_VERSION = (1, 20) + + +def version_tuple(value): + match = re.fullmatch(r"(\d+)\.(\d+)(?:\.(\d+))?", value) + if not match: + raise ValueError("invalid Go version {!r}".format(value)) + return tuple(int(part or 0) for part in match.groups()) + + +def decode_json_stream(text): + decoder = json.JSONDecoder() + index = 0 + while index < len(text): + while index < len(text) and text[index].isspace(): + index += 1 + if index >= len(text): + return + value, index = decoder.raw_decode(text, index) + yield value + + +def read_text(path): + return path.read_text(encoding="utf-8") + + +def go_directive(path): + match = re.search(r"(?m)^go\s+(\d+\.\d+(?:\.\d+)?)\s*$", read_text(path)) + if not match: + raise ValueError("{} has no go directive".format(path)) + return match.group(1) + + +def required_version(path, module_path): + pattern = r"(?m)^\s*{}\s+(v[^\s]+)".format(re.escape(module_path)) + match = re.search(pattern, read_text(path)) + if not match: + raise ValueError( + "{} does not require {}".format(path, module_path) + ) + return match.group(1) + + +def run_go(repo_root, cwd, arguments, go_work): + environment = os.environ.copy() + environment["GOWORK"] = str(go_work) if go_work else "off" + result = subprocess.run( + ["go"] + arguments, + cwd=str(cwd), + env=environment, + check=False, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + universal_newlines=True, + ) + if result.returncode != 0: + print(result.stderr, file=sys.stderr, end="") + raise SystemExit(result.returncode) + return result.stdout + + +def validate_pins(repo_root): + expected_go_directives = { + repo_root / "go.work": "1.25.0", + repo_root / "core" / "go.mod": "1.20", + repo_root / "app-modern" / "go.mod": "1.25.0", + repo_root / "app-win7" / "go.mod": "1.20", + repo_root / "app-win7" / "go.work": "1.20", + } + violations = [] + + for path, expected in expected_go_directives.items(): + actual = go_directive(path) + if actual != expected: + violations.append( + "{} go directive is {}, want {}".format( + path.relative_to(repo_root), actual, expected + ) + ) + + gio_pins = { + repo_root / "app-modern" / "go.mod": "v0.10.1", + repo_root / "app-win7" / "go.mod": "v0.6.0", + } + for path, expected in gio_pins.items(): + actual = required_version(path, "gioui.org") + if actual != expected: + violations.append( + "{} pins gioui.org {}, want {}".format( + path.relative_to(repo_root), actual, expected + ) + ) + + return violations + + +def validate_go20_toolchain(repo_root): + output = run_go(repo_root, repo_root, ["version"], None).strip() + if "go1.20.14" not in output: + return ["compatibility scan uses {!r}, want go1.20.14".format(output)] + return [] + + +def validate_module_versions(repo_root): + module_sets = ( + ("core", repo_root / "core", None), + ( + "win7", + repo_root / "app-win7", + repo_root / "app-win7" / "go.work", + ), + ) + violations = [] + checked = 0 + + for label, cwd, go_work in module_sets: + output = run_go( + repo_root, + cwd, + ["list", "-m", "-json", "all"], + go_work, + ) + for module in decode_json_stream(output): + checked += 1 + go_version = module.get("GoVersion") + if not go_version: + continue + if version_tuple(go_version)[:2] > MAX_LEGACY_GO_VERSION: + violations.append( + "{} module {} declares go {}, exceeds 1.20".format( + label, module["Path"], go_version + ) + ) + + return violations, checked + + +def self_check(): + if version_tuple("1.20")[:2] > MAX_LEGACY_GO_VERSION: + raise AssertionError("Go 1.20 should be accepted") + if version_tuple("1.20.14")[:2] > MAX_LEGACY_GO_VERSION: + raise AssertionError("Go 1.20.14 should be accepted") + if not version_tuple("1.21")[:2] > MAX_LEGACY_GO_VERSION: + raise AssertionError("Go 1.21 should be rejected") + + +def main(): + self_check() + repo_root = pathlib.Path(__file__).resolve().parents[1] + violations = validate_pins(repo_root) + violations.extend(validate_go20_toolchain(repo_root)) + module_violations, checked = validate_module_versions(repo_root) + violations.extend(module_violations) + + if violations: + for violation in violations: + print("ERROR: " + violation, file=sys.stderr) + raise SystemExit(1) + + print( + "Go version check passed: pins valid; {} module records are Go 1.20-compatible.".format( + checked + ) + ) + + +if __name__ == "__main__": + main() diff --git a/scripts/verify_phase0.ps1 b/scripts/verify_phase0.ps1 new file mode 100644 index 0000000..7f6698a --- /dev/null +++ b/scripts/verify_phase0.ps1 @@ -0,0 +1,95 @@ +#!/usr/bin/env pwsh + +$ErrorActionPreference = "Stop" +$Utf8 = [System.Text.UTF8Encoding]::new($false) +[Console]::OutputEncoding = $Utf8 +$OutputEncoding = $Utf8 +$Root = Split-Path -Parent $PSScriptRoot +Set-Location -Path $Root + +function Assert-NativeSuccess { + param([string]$Step) + if ($LASTEXITCODE -ne 0) { + throw "$Step failed with exit code $LASTEXITCODE" + } +} + +function Invoke-Step { + param( + [string]$Name, + [scriptblock]$Command + ) + Write-Host "==> $Name" + & $Command + Assert-NativeSuccess -Step $Name +} + +$GoPath = (& go env GOPATH).Trim() +Assert-NativeSuccess -Step "Locate GOPATH" +$GoBin = Join-Path $GoPath "bin" +if (Test-Path (Join-Path $GoBin "go1.20.14.exe")) { + $env:PATH = "$GoBin;$env:PATH" +} + +New-Item -ItemType Directory -Force -Path (Join-Path $Root "dist") | Out-Null + +Invoke-Step "Sync root workspace" { + $env:GOTOOLCHAIN = "go1.25.0" + Remove-Item Env:GOWORK -ErrorAction SilentlyContinue + go work sync +} + +Invoke-Step "Validate harness governance" { + python scripts/validate_agent_context.py + Assert-NativeSuccess -Step "Validate agent context" + python -m unittest discover -s tests -p "test_*.py" + Assert-NativeSuccess -Step "Run governance tests" + python scripts/validate_harness_governance.py +} + +Invoke-Step "Validate core architecture boundary" { + python scripts/check_core_boundaries.py --self-test + Assert-NativeSuccess -Step "Self-test core boundary matcher" + python scripts/check_core_boundaries.py +} + +Invoke-Step "Validate Go and dependency pins" { + $env:GOTOOLCHAIN = "go1.20.14" + python scripts/check_go_versions.py +} + +Invoke-Step "Vet and test core with Go 1.20.14" { + $env:GOTOOLCHAIN = "go1.20.14" + $env:GOWORK = "off" + go -C core vet ./... + Assert-NativeSuccess -Step "Vet core" + go -C core test -count=1 ./... +} + +Invoke-Step "Test and build modern target with Go 1.25.0" { + $env:GOTOOLCHAIN = "go1.25.0" + $env:GOWORK = (Resolve-Path "go.work").Path + Remove-Item Env:GOOS -ErrorAction SilentlyContinue + Remove-Item Env:GOARCH -ErrorAction SilentlyContinue + $env:CGO_ENABLED = "0" + go -C app-modern test -count=1 ./ui/gio ./platform/windows + Assert-NativeSuccess -Step "Test modern adapters" + $env:GOOS = "windows" + $env:GOARCH = "amd64" + go -C app-modern build -trimpath "-ldflags=-H=windowsgui" -o ../dist/SoftBox.exe ./cmd/softbox +} + +Invoke-Step "Test and build Win7 target with Go 1.20.14" { + $env:GOTOOLCHAIN = "go1.20.14" + $env:GOWORK = (Resolve-Path "app-win7/go.work").Path + Remove-Item Env:GOOS -ErrorAction SilentlyContinue + Remove-Item Env:GOARCH -ErrorAction SilentlyContinue + $env:CGO_ENABLED = "0" + go -C app-win7 test -count=1 ./ui/gio ./platform/windows + Assert-NativeSuccess -Step "Test Win7 adapters" + $env:GOOS = "windows" + $env:GOARCH = "amd64" + go -C app-win7 build -trimpath "-ldflags=-H=windowsgui" -o ../dist/SoftBox-win7.exe ./cmd/softbox +} + +Write-Host "Phase 0 verification passed." diff --git a/scripts/verify_phase0.sh b/scripts/verify_phase0.sh new file mode 100644 index 0000000..5a5e931 --- /dev/null +++ b/scripts/verify_phase0.sh @@ -0,0 +1,63 @@ +#!/usr/bin/env bash + +set -euo pipefail + +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +cd "$ROOT_DIR" + +if python3 --version >/dev/null 2>&1; then + PYTHON=python3 +elif python --version >/dev/null 2>&1; then + PYTHON=python +else + echo "ERROR: Python 3 is required." >&2 + exit 2 +fi + +GO_PATH="$(go env GOPATH)" +if command -v cygpath >/dev/null 2>&1; then + GO_PATH="$(cygpath -u "$GO_PATH")" +fi +GO_BIN="$GO_PATH/bin" +if [ -x "$GO_BIN/go1.20.14" ] || [ -x "$GO_BIN/go1.20.14.exe" ]; then + export PATH="$GO_BIN:$PATH" +fi + +mkdir -p dist + +echo "==> Sync root workspace" +GOTOOLCHAIN=go1.25.0 go work sync + +echo "==> Validate harness governance" +"$PYTHON" scripts/validate_agent_context.py +"$PYTHON" -m unittest discover -s tests -p "test_*.py" +"$PYTHON" scripts/validate_harness_governance.py + +echo "==> Validate core architecture boundary" +"$PYTHON" scripts/check_core_boundaries.py --self-test +"$PYTHON" scripts/check_core_boundaries.py + +echo "==> Validate Go and dependency pins" +GOTOOLCHAIN=go1.20.14 "$PYTHON" scripts/check_go_versions.py + +echo "==> Vet and test core with Go 1.20.14" +GOTOOLCHAIN=go1.20.14 GOWORK=off go -C core vet ./... +GOTOOLCHAIN=go1.20.14 GOWORK=off go -C core test -count=1 ./... + +echo "==> Test and build modern target with Go 1.25.0" +GOTOOLCHAIN=go1.25.0 GOWORK="$ROOT_DIR/go.work" CGO_ENABLED=0 \ + go -C app-modern test -count=1 ./ui/gio ./platform/windows +GOTOOLCHAIN=go1.25.0 GOWORK="$ROOT_DIR/go.work" CGO_ENABLED=0 \ + GOOS=windows GOARCH=amd64 \ + go -C app-modern build -trimpath -ldflags="-H=windowsgui" \ + -o ../dist/SoftBox.exe ./cmd/softbox + +echo "==> Test and build Win7 target with Go 1.20.14" +GOTOOLCHAIN=go1.20.14 GOWORK="$ROOT_DIR/app-win7/go.work" CGO_ENABLED=0 \ + go -C app-win7 test -count=1 ./ui/gio ./platform/windows +GOTOOLCHAIN=go1.20.14 GOWORK="$ROOT_DIR/app-win7/go.work" CGO_ENABLED=0 \ + GOOS=windows GOARCH=amd64 \ + go -C app-win7 build -trimpath -ldflags="-H=windowsgui" \ + -o ../dist/SoftBox-win7.exe ./cmd/softbox + +echo "Phase 0 verification passed."