From 3f883fef78dd39043666719d49ffa8c940dd0930 Mon Sep 17 00:00:00 2001 From: bigboateng Date: Mon, 10 Aug 2026 11:54:13 +0100 Subject: [PATCH 1/5] Improve developer setup and mirror stable releases --- .changeset/self-serve-private-mirror.md | 7 + .github/workflows/npm-publish.yml | 138 ++++++++ .github/workflows/release-finalize.yml | 17 +- README.md | 8 +- cmd/yskill/agents.go | 67 +++- cmd/yskill/agents_test.go | 39 +++ cmd/yskill/main_test.go | 40 ++- cmd/yskill/scaffold.go | 20 ++ docs/agent-setup.md | 4 +- docs/convert-existing-skill.md | 2 +- docs/quickstart.md | 8 +- packaging/private-mirror.mjs | 326 ++++++++++++++++++ packaging/private-mirror.test.mjs | 61 ++++ scripts/check-release-control.mjs | 31 +- scripts/readme.test.mjs | 6 +- sdk/python/README.md | 6 +- .../release-yield/src/release-controller.mjs | 2 +- 17 files changed, 752 insertions(+), 30 deletions(-) create mode 100644 .changeset/self-serve-private-mirror.md create mode 100644 packaging/private-mirror.mjs create mode 100644 packaging/private-mirror.test.mjs diff --git a/.changeset/self-serve-private-mirror.md b/.changeset/self-serve-private-mirror.md new file mode 100644 index 0000000..c28a6c0 --- /dev/null +++ b/.changeset/self-serve-private-mirror.md @@ -0,0 +1,7 @@ +--- +"@operatorstack/yield": patch +--- + +Make non-Git onboarding commands explicit, generate commit-ready Rust lockfiles, +add exact local-runtime recovery to Go and Rust adapters, and require verified +Artifact Registry parity for stable releases. diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml index 86e52a8..1eb7a4c 100644 --- a/.github/workflows/npm-publish.yml +++ b/.github/workflows/npm-publish.yml @@ -381,6 +381,144 @@ jobs: path: dist/crates-receipt/ if-no-files-found: error + private-mirror: + name: Mirror stable release to Artifact Registry + needs: [resolve, build, npm, pypi, crates] + if: needs.resolve.outputs.channel == 'stable' + runs-on: ubuntu-latest + environment: private-production + permissions: + contents: read + id-token: write + env: + VERSION: ${{ needs.resolve.outputs.version }} + SOURCE_SHA: ${{ needs.resolve.outputs.source_sha }} + AR_NPM_URL: https://${{ vars.AR_LOCATION }}-npm.pkg.dev/${{ vars.AR_PROJECT }}/${{ vars.AR_NPM_REPO }}/ + AR_PYTHON_URL: https://${{ vars.AR_LOCATION }}-python.pkg.dev/${{ vars.AR_PROJECT }}/${{ vars.AR_PYTHON_REPO }}/ + steps: + - name: Check out mirror control code + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + with: + persist-credentials: false + ref: ${{ github.sha }} + path: control + - name: Check out exact release source + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + with: + fetch-depth: 0 + persist-credentials: false + ref: ${{ needs.resolve.outputs.source_sha }} + path: source + - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5 + with: + name: packages-${{ needs.resolve.outputs.version }}-${{ needs.resolve.outputs.source_sha }} + path: dist/release-unit + - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5 + with: + name: crates-${{ needs.resolve.outputs.version }}-${{ needs.resolve.outputs.source_sha }} + path: dist/crates + - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6 + with: + node-version: "24" + package-manager-cache: false + - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6 + with: + python-version: "3.12" + - id: auth + uses: google-github-actions/auth@7c6bc770dae815cd3e89ee6cdf493a5fab2cc093 # v3 + with: + workload_identity_provider: ${{ vars.WIF_PROVIDER }} + service_account: ${{ vars.DEPLOYER_SA_EMAIL }} + - uses: google-github-actions/setup-gcloud@aa5489c8933f4cc7a4f7d45035b3b1440c9c10db # v3 + with: + install_components: package-go-module + - name: Inspect immutable release unit + run: >- + node control/packaging/private-mirror.mjs inspect + --version "$VERSION" + --source-sha "$SOURCE_SHA" + --release-unit dist/release-unit + --crates dist/crates + --manifest "$RUNNER_TEMP/private-mirror-manifest.json" + - id: remote + name: Refuse drift and select missing private artifacts + run: >- + node control/packaging/private-mirror.mjs status + --manifest "$RUNNER_TEMP/private-mirror-manifest.json" + --status "$RUNNER_TEMP/private-mirror-status.json" + --output "$GITHUB_OUTPUT" + - name: Configure Artifact Registry npm authentication + if: steps.remote.outputs.npm_state != 'matched' + run: | + gcloud artifacts print-settings npm \ + --project="${{ vars.AR_PROJECT }}" --location="${{ vars.AR_LOCATION }}" \ + --repository="${{ vars.AR_NPM_REPO }}" --scope=@operatorstack > "$RUNNER_TEMP/yield.npmrc" + npx -y google-artifactregistry-auth "$RUNNER_TEMP/yield.npmrc" + - name: Mirror exact npm archives + if: steps.remote.outputs.npm_state != 'matched' + env: + NPM_CONFIG_USERCONFIG: ${{ runner.temp }}/yield.npmrc + shell: bash + run: | + set -euo pipefail + jq -r '.missing.npm[].file' "$RUNNER_TEMP/private-mirror-status.json" | while read -r file; do + npm publish "dist/release-unit/npm/${file}" --registry="$AR_NPM_URL" + done + - name: Mirror exact Python wheels + if: steps.remote.outputs.python_state != 'matched' + run: | + python -m pip install --disable-pip-version-check twine==6.2.0 keyrings.google-artifactregistry-auth==1.1.2 + jq -r '.missing.python[].file' "$RUNNER_TEMP/private-mirror-status.json" | while read -r file; do + python -m twine upload --repository-url "$AR_PYTHON_URL" "dist/release-unit/pypi/${file}" + done + - name: Mirror exact tagged Go source + if: steps.remote.outputs.go_state == 'missing' + shell: bash + run: | + set -euo pipefail + test "$(git -C source rev-parse HEAD)" = "$SOURCE_SHA" + source_dir="$(mktemp -d)" + git -C source archive "$SOURCE_SHA" | tar -x -C "$source_dir" + gcloud artifacts go upload \ + --project="${{ vars.AR_PROJECT }}" --location="${{ vars.AR_LOCATION }}" \ + --repository="${{ vars.AR_GO_REPO }}" \ + --module-path=github.com/operatorstack/yield \ + --version="v${VERSION}" --source="$source_dir" + - name: Prepare exact crates.io mirror records + if: steps.remote.outputs.rust_state != 'matched' + run: >- + node control/packaging/private-mirror.mjs prepare-cargo + --manifest "$RUNNER_TEMP/private-mirror-manifest.json" + --status "$RUNNER_TEMP/private-mirror-status.json" + --crates dist/crates + --output "$RUNNER_TEMP/private-cargo" + - name: Mirror exact Rust crate archives and index records + if: steps.remote.outputs.rust_state != 'matched' + run: >- + gcloud artifacts generic upload + --project="${{ vars.AR_PROJECT }}" --location="${{ vars.AR_LOCATION }}" + --repository="${{ vars.AR_GENERIC_REPO }}" + --package=yield-rust --version="$VERSION" + --source-directory="$RUNNER_TEMP/private-cargo" + - name: Verify complete private mirror + shell: bash + run: | + set -euo pipefail + for attempt in {1..12}; do + if node control/packaging/private-mirror.mjs verify \ + --manifest "$RUNNER_TEMP/private-mirror-manifest.json" \ + --receipt "$RUNNER_TEMP/private-mirror.json"; then + exit 0 + fi + test "$attempt" -lt 12 + sleep 10 + done + - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 + with: + name: private-mirror-${{ needs.resolve.outputs.version }}-${{ needs.resolve.outputs.source_sha }} + path: ${{ runner.temp }}/private-mirror.json + if-no-files-found: error + selfhost-canary: name: Release skill against exact canary needs: [resolve, npm] diff --git a/.github/workflows/release-finalize.yml b/.github/workflows/release-finalize.yml index 539293f..ba08bd3 100644 --- a/.github/workflows/release-finalize.yml +++ b/.github/workflows/release-finalize.yml @@ -93,11 +93,14 @@ jobs: version="${TAG#v}" package_receipt="packages-${version}-${SOURCE_SHA}" crates_receipt="crates-${version}-${SOURCE_SHA}" + private_receipt="private-mirror-${version}-${SOURCE_SHA}" run_id="" while read -r candidate; do test -n "$candidate" || continue artifact_names="$(gh api "/repos/${GITHUB_REPOSITORY}/actions/runs/${candidate}/artifacts?per_page=100" --jq '.artifacts[].name')" - if grep -Fqx "$package_receipt" <<< "$artifact_names" && grep -Fqx "$crates_receipt" <<< "$artifact_names"; then + if grep -Fqx "$package_receipt" <<< "$artifact_names" && \ + grep -Fqx "$crates_receipt" <<< "$artifact_names" && \ + grep -Fqx "$private_receipt" <<< "$artifact_names"; then run_id="$candidate" break fi @@ -108,6 +111,18 @@ jobs: --name "$package_receipt" --dir "$RUNNER_TEMP/release-unit" gh run download "$run_id" --repo "$GITHUB_REPOSITORY" \ --name "$crates_receipt" --dir "$RUNNER_TEMP/crates-receipt" + gh run download "$run_id" --repo "$GITHUB_REPOSITORY" \ + --name "$private_receipt" --dir "$RUNNER_TEMP/private-mirror" + jq -e \ + --arg version "$version" --arg source_sha "$SOURCE_SHA" \ + '.schema_version == 1 and .version == $version and .source_sha == $source_sha and + (.targets | length == 6) and + (.packages.npm | length == 8) and (.packages.python | length == 6) and + (.packages.go | length == 1) and (.packages.rust | length == 7) and + ([.states[]] | all(. == "matched")) and + ([.endpoints.npm, .endpoints.python, .endpoints.go, + .endpoints.rust_index, .endpoints.rust_download] | all(type == "string"))' \ + "$RUNNER_TEMP/private-mirror/private-mirror.json" for package in \ @operatorstack/yield \ @operatorstack/create-yield \ diff --git a/README.md b/README.md index 38202b4..c60b33c 100644 --- a/README.md +++ b/README.md @@ -192,13 +192,13 @@ Registration is the discovery step. This command detects installed verified agents and writes a small adapter for each one: ```bash -npm exec -- yskill register skills/release +npm exec -- yskill register skills/release --root . ``` Select verified agents explicitly when you do not want automatic detection: ```bash -npm exec -- yskill register skills/release \ +npm exec -- yskill register skills/release --root . \ --agent cursor,codex,claude-code ``` @@ -239,8 +239,8 @@ helper: | Language | Command | | ---------- | ------------------------------------------------------------------------------------------------------------------- | -| TypeScript | `npm exec -- yskill helper install --language typescript` | -| Python | `python -m yieldskill helper install --language python` | +| TypeScript | `npm exec -- yskill helper install --root . --language typescript` | +| Python | `python -m yieldskill helper install --root . --language python` | | Rust | `cargo install yieldskill --root .yield --locked`, then `.yield/bin/yskill helper install --root . --language rust` | | Go | `go run github.com/operatorstack/yield/cmd/yskill@latest helper install --root . --language go` | diff --git a/cmd/yskill/agents.go b/cmd/yskill/agents.go index 4e7576c..e2a4a1e 100644 --- a/cmd/yskill/agents.go +++ b/cmd/yskill/agents.go @@ -205,7 +205,7 @@ func cmdRegisterAll(args []string) error { if launcherErr != nil { return launcherErr } - content := renderAdapter(metadata, sourceRel, digest, launcher) + content := renderAdapter(metadata, sourceRel, digest, launcher, manifest.Language) for _, agent := range selectedAgents { path := filepath.Join(repoRoot, filepath.FromSlash(agent.ProjectDir), metadata.Name, "SKILL.md") plan := plansByPath[path] @@ -345,7 +345,7 @@ func registerSkill(skillArg, rootArg string, requested []string) ([]registration return nil, err } } - content := renderAdapter(metadata, sourceRel, digest, launcher) + content := renderAdapter(metadata, sourceRel, digest, launcher, manifest.Language) byDestination := map[string][]string{} for _, agent := range selected { destination := filepath.Join(repoRoot, filepath.FromSlash(agent.ProjectDir), metadata.Name, "SKILL.md") @@ -687,12 +687,16 @@ func verifyLocalRuntime(path, expected, language string) error { } func localRuntimeInstallCommand(language, expected string) string { + return localRuntimeInstallCommandFor(language, expected, runtime.GOOS) +} + +func localRuntimeInstallCommandFor(language, expected, goos string) string { switch language { case "go": - if runtime.GOOS == "windows" { - return fmt.Sprintf(`New-Item -ItemType Directory -Force .yield\bin | Out-Null; $env:GOBIN="$PWD\.yield\bin"; $env:GOPROXY="https://get.operatorstack.systems/go,direct"; go install github.com/operatorstack/yield/cmd/yskill@v%s`, expected) + if goos == "windows" { + return fmt.Sprintf(`New-Item -ItemType Directory -Force .yield\bin | Out-Null; $env:GOBIN="$PWD\.yield\bin"; $env:GOPROXY="https://proxy.golang.org,direct"; go install github.com/operatorstack/yield/cmd/yskill@v%s`, expected) } - return fmt.Sprintf(`mkdir -p .yield/bin && GOBIN="$PWD/.yield/bin" GOPROXY=https://get.operatorstack.systems/go,direct go install github.com/operatorstack/yield/cmd/yskill@v%s`, expected) + return fmt.Sprintf(`mkdir -p .yield/bin && GOBIN="$PWD/.yield/bin" GOPROXY=https://proxy.golang.org,direct go install github.com/operatorstack/yield/cmd/yskill@v%s`, expected) case "rust": return fmt.Sprintf(`cargo install yieldskill@%s --root .yield --locked`, expected) default: @@ -799,8 +803,52 @@ func shellQuote(value string) string { return "'" + strings.ReplaceAll(value, "'", "'\"'\"'") + "'" } -func renderAdapter(metadata skillMetadata, sourceRel, digest, launcher string) string { +func renderAdapter(metadata skillMetadata, sourceRel, digest, launcher, language string) string { path := shellQuote(sourceRel) + if language == "go" || language == "rust" { + posixInstall := localRuntimeInstallCommandFor(language, runtimeVersion(), "linux") + windowsInstall := localRuntimeInstallCommandFor(language, runtimeVersion(), "windows") + return fmt.Sprintf(`--- +name: %s +description: %s +--- + +%s%s; digest: %s; version: %s --> + +This adapter exposes the canonical Yield workflow at %s. +Read its SKILL.md, then run from the repository root. + +On macOS or Linux, if .yield/bin/yskill is missing, run: + + %s + +Then start or resume the workflow with .yield/bin/yskill. + +On Windows PowerShell, if .yield\bin\yskill.exe is missing, run: + + %s + +Then start or resume the workflow with .\.yield\bin\yskill.exe. + +Start the workflow: + + .yield/bin/yskill run %s + +On Windows PowerShell use: + + .\.yield\bin\yskill.exe run %s + +If installation was required, retry the matching run command above. +Follow each returned operation exactly. Answer each operation directly with +the same launcher: + + respond --value --skill %s + +For structured agent results, use --result-json instead of --value. + +Do not skip an operation or invent its response. +`, metadata.Name, yamlString(metadata.Description), generatedAdapterPrefix, sourceRel, digest, runtimeVersion(), "`"+sourceRel+"`", posixInstall, windowsInstall, path, path, path) + } return fmt.Sprintf(`--- name: %s description: %s @@ -813,11 +861,12 @@ Read its SKILL.md, then run from the repository root: %s run %s - Follow each returned operation exactly. Answer each operation directly: - %s respond --value --skill %s +Follow each returned operation exactly. Answer each operation directly: + + %s respond --value --skill %s - For structured agent results, use --result-json instead of --value. +For structured agent results, use --result-json instead of --value. Do not skip an operation or invent its response. `, metadata.Name, yamlString(metadata.Description), generatedAdapterPrefix, sourceRel, digest, runtimeVersion(), "`"+sourceRel+"`", launcher, path, launcher, path) diff --git a/cmd/yskill/agents_test.go b/cmd/yskill/agents_test.go index 5ffa3b0..3a494dd 100644 --- a/cmd/yskill/agents_test.go +++ b/cmd/yskill/agents_test.go @@ -414,6 +414,45 @@ func TestRepositoryRuntimeRejectsMissingAndWrongVersions(t *testing.T) { } } +func TestLocalRuntimeRecoveryUsesPublicRegistries(t *testing.T) { + goUnix := localRuntimeInstallCommandFor("go", "0.5.1", "linux") + goWindows := localRuntimeInstallCommandFor("go", "0.5.1", "windows") + for _, command := range []string{goUnix, goWindows} { + if !strings.Contains(command, "https://proxy.golang.org,direct") || !strings.Contains(command, "@v0.5.1") { + t.Fatalf("Go recovery is not public and exact: %s", command) + } + if strings.Contains(command, "get.operatorstack.systems") { + t.Fatalf("Go recovery still uses the private mirror: %s", command) + } + } + if got := localRuntimeInstallCommandFor("rust", "0.5.1", "windows"); got != "cargo install yieldskill@0.5.1 --root .yield --locked" { + t.Fatalf("Rust recovery = %q", got) + } +} + +func TestGeneratedLocalRuntimeAdapterIsPortableAndActionable(t *testing.T) { + previousVersion := version + version = "0.5.1" + t.Cleanup(func() { version = previousVersion }) + adapter := renderAdapter( + skillMetadata{Name: "safe-change", Description: "Check a safe change."}, + "skills/safe-change", + "sha256:test", + ".yield/bin/yskill", + "rust", + ) + for _, want := range []string{ + "cargo install yieldskill@0.5.1 --root .yield --locked", + ".yield/bin/yskill run 'skills/safe-change'", + `.\.yield\bin\yskill.exe run 'skills/safe-change'`, + "If installation was required, retry", + } { + if !strings.Contains(adapter, want) { + t.Fatalf("adapter missing %q:\n%s", want, adapter) + } + } +} + func TestLocalStateIgnoreFileCoversRuntimeAndRuns(t *testing.T) { repo := t.TempDir() if err := ensureLocalStateIgnored(repo); err != nil { diff --git a/cmd/yskill/main_test.go b/cmd/yskill/main_test.go index 5c9750b..d026910 100644 --- a/cmd/yskill/main_test.go +++ b/cmd/yskill/main_test.go @@ -2,6 +2,7 @@ package main import ( "encoding/json" + "errors" "flag" "io" "os" @@ -18,6 +19,16 @@ import ( "github.com/operatorstack/yield/internal/runlog" ) +func stubRustLockfile(t *testing.T) { + t.Helper() + previous := generateRustLockfile + generateRustLockfile = func(dir string) error { + writeTestFile(t, filepath.Join(dir, "Cargo.lock"), "version = 4\n") + return nil + } + t.Cleanup(func() { generateRustLockfile = previous }) +} + func TestPrintProgressKeepsCompleteStructuredResult(t *testing.T) { result := `{"summary":"` + strings.Repeat("x", 300) + `","count":42}` read, write, err := os.Pipe() @@ -168,6 +179,7 @@ func TestParseOnePositionalKeepsFlagFirstOrder(t *testing.T) { } func TestScaffoldSkillWritesLanguageSpecificEntrypoints(t *testing.T) { + stubRustLockfile(t) previousVersion := version previousTidyGoModule := tidyGoModule version = "0.1.9" @@ -191,7 +203,7 @@ func TestScaffoldSkillWritesLanguageSpecificEntrypoints(t *testing.T) { {"typescript", []string{"main.ts", "package.json", "skill.json"}, "npm exec -- yskill run .", `"@operatorstack/yield": "0.1.9"`, ""}, {"python", []string{"main.py", "requirements.txt", "skill.json"}, "python -m yieldskill run .", "yieldskill==0.1.9", ""}, {"go", []string{"main.go", "go.mod", "skill.json"}, "yskill run .", "github.com/operatorstack/yield v0.1.9", ""}, - {"rust", []string{"src/main.rs", "Cargo.toml", "skill.json", ".gitignore"}, "yskill run .", `version = "=0.1.9"`, rustSkillGitignore}, + {"rust", []string{"src/main.rs", "Cargo.toml", "Cargo.lock", "skill.json", ".gitignore"}, "yskill run .", `version = "=0.1.9"`, rustSkillGitignore}, } for _, tt := range tests { t.Run(tt.language, func(t *testing.T) { @@ -263,6 +275,7 @@ func TestScaffoldSkillWritesLanguageSpecificEntrypoints(t *testing.T) { } func TestRustScaffoldPreservesExistingGitignore(t *testing.T) { + stubRustLockfile(t) dir := filepath.Join(t.TempDir(), "safe-change") if err := os.MkdirAll(dir, 0o755); err != nil { t.Fatal(err) @@ -341,6 +354,7 @@ func TestShellQuoteForPlatform(t *testing.T) { } func TestRustScaffoldNamesPrimaryBinary(t *testing.T) { + stubRustLockfile(t) previousVersion := version version = "0.1.28" t.Cleanup(func() { version = previousVersion }) @@ -358,6 +372,7 @@ func TestRustScaffoldRunsPrimaryBinaryWhenFixtureAddsAnotherBinary(t *testing.T) if _, err := exec.LookPath("cargo"); err != nil { t.Skip("cargo is not installed") } + stubRustLockfile(t) dir := filepath.Join(t.TempDir(), "safe-change") if err := scaffoldSkill(dir, "rust", "", "Check a safe change before applying it."); err != nil { t.Fatal(err) @@ -400,6 +415,7 @@ func TestGoScaffoldCanResolveItsPinnedModuleOnFirstRun(t *testing.T) { } func TestLocalGoAndRustScaffoldsKeepTheInvokedRuntime(t *testing.T) { + stubRustLockfile(t) previousVersion := version previousTidyGoModule := tidyGoModule previousExecutable := currentExecutable @@ -435,6 +451,7 @@ func TestLocalGoAndRustScaffoldsKeepTheInvokedRuntime(t *testing.T) { } func TestRustScaffoldPinsTheInvokedRuntimeWithoutPrivateRegistryConfig(t *testing.T) { + stubRustLockfile(t) previousVersion := version previousExecutable := currentExecutable previousInspect := inspectRuntimeVersion @@ -515,11 +532,32 @@ func TestCmdInitRustScaffoldIsDoctorValid(t *testing.T) { if err := cmdInit([]string{"--language", "rust", "--description", "Check a safe change before applying it.", dir}); err != nil { t.Fatal(err) } + if _, err := os.Stat(filepath.Join(dir, "Cargo.lock")); err != nil { + t.Fatalf("Rust scaffold lockfile: %v", err) + } if err := cmdDoctor([]string{dir, "--root", root}); err != nil { t.Fatalf("doctor rejected Rust scaffold: %v", err) } } +func TestRustScaffoldPreservesExistingCargoLock(t *testing.T) { + previous := generateRustLockfile + generateRustLockfile = func(string) error { + return errors.New("lockfile generation must not run") + } + t.Cleanup(func() { generateRustLockfile = previous }) + + dir := filepath.Join(t.TempDir(), "safe-change") + const existing = "user-owned-lockfile\n" + writeTestFile(t, filepath.Join(dir, "Cargo.lock"), existing) + if err := scaffoldSkill(dir, "rust", "", "Check a safe change before applying it."); err != nil { + t.Fatal(err) + } + if got := readTestFile(t, filepath.Join(dir, "Cargo.lock")); got != existing { + t.Fatalf("existing Cargo.lock changed: %q", got) + } +} + func TestPythonScaffoldUsesRelocatableInterpreter(t *testing.T) { previousVersion := version version = "0.1.9" diff --git a/cmd/yskill/scaffold.go b/cmd/yskill/scaffold.go index 3977323..b38c3b8 100644 --- a/cmd/yskill/scaffold.go +++ b/cmd/yskill/scaffold.go @@ -26,6 +26,16 @@ var tidyGoModule = func(dir string) error { return nil } +var generateRustLockfile = func(dir string) error { + cmd := exec.Command("cargo", "generate-lockfile", "--manifest-path", filepath.Join(dir, "Cargo.toml")) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { + return fmt.Errorf("prepare Rust scaffold dependencies: %w", err) + } + return nil +} + func defaultLanguage() string { if language := strings.TrimSpace(os.Getenv("YIELD_LANGUAGE")); language != "" { return language @@ -146,6 +156,16 @@ func scaffoldSkill(dir, language, sdkPath, description string) error { return err } } + if language == "rust" { + lockfile := filepath.Join(dir, "Cargo.lock") + if _, err := os.Stat(lockfile); os.IsNotExist(err) { + if err := generateRustLockfile(dir); err != nil { + return err + } + } else if err != nil { + return err + } + } if _, err := readSkillMetadata(dir); err != nil { return fmt.Errorf("validate SKILL.md: %w", err) } diff --git a/docs/agent-setup.md b/docs/agent-setup.md index 010852d..b399ebe 100644 --- a/docs/agent-setup.md +++ b/docs/agent-setup.md @@ -76,10 +76,10 @@ manual workflow, install the guided helper explicitly from the repository root: ```bash # TypeScript -npm exec -- yskill helper install --language typescript +npm exec -- yskill helper install --root . --language typescript # Python -python -m yieldskill helper install --language python +python -m yieldskill helper install --root . --language python # Rust cargo install yieldskill --root .yield --locked diff --git a/docs/convert-existing-skill.md b/docs/convert-existing-skill.md index 5409c69..17d6af4 100644 --- a/docs/convert-existing-skill.md +++ b/docs/convert-existing-skill.md @@ -9,7 +9,7 @@ Package installation does not add the helper. Install it explicitly for the project language. For example: ```bash -npm exec -- yskill helper install --language typescript +npm exec -- yskill helper install --root . --language typescript ``` See the [quickstart](quickstart.md) for Python, Rust, and Go commands. diff --git a/docs/quickstart.md b/docs/quickstart.md index fa125e0..d706f4b 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -49,8 +49,8 @@ This runs the fixture to a terminal outcome without leaving a run journal. ## 4. Register it ```bash -npm exec -- yskill register skills/release -npm exec -- yskill doctor skills/release --agent codex,cursor,claude-code --test +npm exec -- yskill register skills/release --root . +npm exec -- yskill doctor skills/release --root . --agent codex,cursor,claude-code --test ``` Registration creates only small discovery adapters. The canonical workflow, @@ -71,10 +71,10 @@ After learning the manual flow, install guided assistance explicitly: ```bash # TypeScript -npm exec -- yskill helper install --language typescript +npm exec -- yskill helper install --root . --language typescript # Python -python -m yieldskill helper install --language python +python -m yieldskill helper install --root . --language python # Rust .yield/bin/yskill helper install --root . --language rust diff --git a/packaging/private-mirror.mjs b/packaging/private-mirror.mjs new file mode 100644 index 0000000..aa84bc8 --- /dev/null +++ b/packaging/private-mirror.mjs @@ -0,0 +1,326 @@ +#!/usr/bin/env node +import { createHash } from "node:crypto" +import { copyFile, mkdir, readFile, readdir, writeFile } from "node:fs/promises" +import { basename, join, resolve } from "node:path" +import process from "node:process" +import { pathToFileURL } from "node:url" +import { crateNames, indexPath, registryRecord } from "./crates-release.mjs" +import { inspectLocalRelease } from "./pypi-release.mjs" +import { targets } from "./targets.mjs" + +const stableVersion = /^\d+\.\d+\.\d+$/ +const fullSHA = /^[0-9a-f]{40}$/ +const defaultBase = "https://get.operatorstack.systems" + +function expect(condition, message) { + if (!condition) throw new Error(message) +} + +async function sha256(path) { + return createHash("sha256") + .update(await readFile(path)) + .digest("hex") +} + +async function responseSHA256(response) { + expect(response.ok, `download returned HTTP ${response.status}`) + return createHash("sha256") + .update(Buffer.from(await response.arrayBuffer())) + .digest("hex") +} + +export function classifyCollection(expected, remote, label) { + const expectedByName = new Map(expected.map((item) => [item.name, item.sha256])) + expect(expectedByName.size === expected.length, `${label}: expected identities are not unique`) + const remoteByName = new Map() + for (const item of remote) { + expect(!remoteByName.has(item.name), `${label}: duplicate remote artifact ${item.name}`) + expect(expectedByName.has(item.name), `${label}: unexpected remote artifact ${item.name}`) + expect( + expectedByName.get(item.name) === item.sha256, + `${label}: checksum drift for ${item.name}`, + ) + remoteByName.set(item.name, item.sha256) + } + if (remoteByName.size === 0) return "missing" + return remoteByName.size === expectedByName.size ? "matched" : "partial" +} + +function missingArtifacts(expected, remote) { + const present = new Set(remote.map((item) => item.name)) + return expected.filter((item) => !present.has(item.name)) +} + +export function validateMirrorIdentity({ version, sourceSHA, npmRelease }) { + expect(stableVersion.test(version), "version must be stable semver") + expect(fullSHA.test(sourceSHA), "source SHA must be a full commit SHA") + expect(npmRelease?.schema_version === 1, "npm release schema must be 1") + expect(npmRelease.version === version, "npm release version does not match") + expect(npmRelease.source_sha === sourceSHA, "npm release source SHA does not match") +} + +async function localCrates(directory, version) { + const names = new Set(await readdir(directory)) + const crates = [] + for (const name of crateNames) { + const file = `${name}-${version}.crate` + expect(names.has(file), `missing crate archive ${file}`) + crates.push({ name, file, sha256: await sha256(join(directory, file)) }) + } + expect( + [...names].filter((name) => name.endsWith(".crate")).length === crateNames.length, + "crate archive directory contains unexpected files", + ) + return crates +} + +export async function inspectMirrorUnit({ version, sourceSHA, releaseUnit, crates }) { + const npmRoot = join(releaseUnit, "npm") + const npmRelease = JSON.parse(await readFile(join(npmRoot, "npm-release.json"), "utf8")) + validateMirrorIdentity({ version, sourceSHA, npmRelease }) + expect(npmRelease.archives.length === 8, "private mirror requires eight npm archives") + const npm = [] + for (const archive of npmRelease.archives) { + expect(archive.version === version, `${archive.name}: npm version does not match`) + const digest = await sha256(join(npmRoot, archive.file)) + expect(digest === archive.sha256, `${archive.name}: npm archive checksum drift`) + npm.push({ name: archive.name, file: archive.file, sha256: digest }) + } + const python = (await inspectLocalRelease(join(releaseUnit, "pypi"), version)).map((file) => ({ + name: file.filename, + file: file.filename, + sha256: file.sha256, + })) + const rust = await localCrates(crates, version) + return { + schema_version: 1, + version, + source_sha: sourceSHA, + targets: targets.map((target) => target.id), + npm, + python, + rust, + go: { module: "github.com/operatorstack/yield", version: `v${version}` }, + } +} + +async function remoteNPM(manifest, base, fetchImpl) { + const remote = [] + for (const expected of manifest.npm) { + const path = expected.name.replace("/", "%2F") + const response = await fetchImpl(`${base}/npm/${path}`, { cache: "no-store" }) + if (response.status === 404) continue + expect(response.ok, `${expected.name}: private npm returned HTTP ${response.status}`) + const packument = await response.json() + const record = packument.versions?.[manifest.version] + if (!record) continue + expect(record.dist?.tarball, `${expected.name}: private npm tarball URL is missing`) + remote.push({ + name: expected.name, + sha256: await responseSHA256(await fetchImpl(record.dist.tarball)), + }) + } + return remote +} + +async function remotePython(manifest, base, fetchImpl) { + const response = await fetchImpl(`${base}/pip/simple/yieldskill/`, { cache: "no-store" }) + if (response.status === 404) return [] + expect(response.ok, `private Python index returned HTTP ${response.status}`) + const expected = new Set(manifest.python.map((file) => file.name)) + const remote = [] + for (const match of (await response.text()).matchAll(/href=["']([^"']+)["']/gi)) { + const url = new URL(match[1], `${base}/pip/simple/yieldskill/`) + const name = decodeURIComponent(basename(url.pathname)) + if (!expected.has(name)) continue + const digest = url.hash.match(/^#sha256=([0-9a-f]{64})$/)?.[1] + remote.push({ name, sha256: digest ?? (await responseSHA256(await fetchImpl(url))) }) + } + return remote +} + +async function remoteRust(manifest, base, fetchImpl) { + const remote = [] + for (const expected of manifest.rust) { + const response = await fetchImpl(`${base}/cargo/index/${indexPath(expected.name)}`, { + headers: { "User-Agent": "operatorstack-yield-private-mirror/1" }, + cache: "no-store", + }) + if (response.status === 404) continue + expect(response.ok, `${expected.name}: private Cargo index returned HTTP ${response.status}`) + const record = (await response.text()) + .split("\n") + .filter(Boolean) + .map((line) => JSON.parse(line)) + .find((item) => item.vers === manifest.version) + if (!record) continue + expect(record.cksum === expected.sha256, `${expected.name}: private Cargo index checksum drift`) + const download = `${base}/cargo/crates/${expected.name}/${manifest.version}/download` + const archive = await fetchImpl(download) + if (archive.status === 404) continue + expect(archive.ok, `${expected.name}: private Cargo download returned HTTP ${archive.status}`) + remote.push({ name: expected.name, sha256: await responseSHA256(archive) }) + } + return remote +} + +async function remoteGo(manifest, base, fetchImpl) { + const privateZip = `${base}/go/github.com/operatorstack/yield/@v/v${manifest.version}.zip` + const response = await fetchImpl(privateZip, { cache: "no-store" }) + if (response.status === 404) return [] + expect(response.ok, `private Go proxy returned HTTP ${response.status}`) + const privateDigest = await responseSHA256(response) + const publicResponse = await fetchImpl( + `https://proxy.golang.org/github.com/operatorstack/yield/@v/v${manifest.version}.zip`, + { cache: "no-store" }, + ) + const publicDigest = await responseSHA256(publicResponse) + expect(privateDigest === publicDigest, "private Go module zip differs from the public module") + return [{ name: manifest.go.module, sha256: privateDigest }] +} + +export async function inspectRemote(manifest, { base = defaultBase, fetchImpl = fetch } = {}) { + const [npm, python, rust, go] = await Promise.all([ + remoteNPM(manifest, base, fetchImpl), + remotePython(manifest, base, fetchImpl), + remoteRust(manifest, base, fetchImpl), + remoteGo(manifest, base, fetchImpl), + ]) + const goExpected = go.length ? go : [] + return { + states: { + npm: classifyCollection(manifest.npm, npm, "npm"), + python: classifyCollection(manifest.python, python, "Python"), + rust: classifyCollection(manifest.rust, rust, "Cargo"), + go: goExpected.length === 0 ? "missing" : "matched", + }, + remote: { npm, python, rust, go }, + missing: { + npm: missingArtifacts(manifest.npm, npm), + python: missingArtifacts(manifest.python, python), + rust: missingArtifacts(manifest.rust, rust), + go: go.length ? [] : [manifest.go], + }, + } +} + +export async function prepareCargoMirror( + manifest, + { crates, output, names = crateNames, fetchImpl = fetch }, +) { + await mkdir(output, { recursive: true }) + const selected = new Set(names) + for (const item of manifest.rust.filter((candidate) => selected.has(candidate.name))) { + const record = await registryRecord(item.name, manifest.version, fetchImpl) + expect(record, `${item.name}@${manifest.version}: crates.io index record is missing`) + expect( + record.cksum === item.sha256, + `${item.name}: crates.io checksum differs from release unit`, + ) + await copyFile(join(crates, item.file), join(output, item.file)) + await writeFile(join(output, `${item.name}-index.json`), `${JSON.stringify(record)}\n`) + } +} + +function receipt(manifest, remote, base) { + return { + schema_version: 1, + version: manifest.version, + source_sha: manifest.source_sha, + registry: base, + targets: manifest.targets, + endpoints: { + npm: `${base}/npm/`, + python: `${base}/pip/simple/yieldskill/`, + go: `${base}/go/${manifest.go.module}/@v/v${manifest.version}.zip`, + rust_index: `${base}/cargo/index/`, + rust_download: `${base}/cargo/crates/{crate}/{version}/download`, + }, + packages: { + npm: remote.remote.npm, + python: remote.remote.python, + go: remote.remote.go, + rust: remote.remote.rust, + }, + states: remote.states, + } +} + +function parseArgs(argv) { + const [command, ...rest] = argv + const values = {} + for (let index = 0; index < rest.length; index += 2) { + const key = rest[index] + expect(key?.startsWith("--") && rest[index + 1] !== undefined, `invalid argument ${key ?? ""}`) + values[key.slice(2)] = rest[index + 1] + } + expect(["inspect", "status", "prepare-cargo", "verify"].includes(command), "unknown command") + return { command, ...values } +} + +async function appendOutput(path, states) { + if (!path) return + await writeFile( + path, + Object.entries(states) + .map(([key, value]) => `${key}_state=${value}\n`) + .join(""), + { + flag: "a", + }, + ) +} + +async function main() { + const options = parseArgs(process.argv.slice(2)) + if (options.command === "inspect") { + expect( + options.version && options["source-sha"] && options["release-unit"] && options.crates, + "inspect inputs are required", + ) + const manifest = await inspectMirrorUnit({ + version: options.version, + sourceSHA: options["source-sha"], + releaseUnit: resolve(options["release-unit"]), + crates: resolve(options.crates), + }) + expect(options.manifest, "--manifest is required") + await writeFile(options.manifest, `${JSON.stringify(manifest, null, 2)}\n`) + return + } + expect(options.manifest, "--manifest is required") + const manifest = JSON.parse(await readFile(options.manifest, "utf8")) + if (options.command === "prepare-cargo") { + expect(options.crates && options.output, "prepare-cargo requires --crates and --output") + const status = options.status ? JSON.parse(await readFile(options.status, "utf8")) : null + await prepareCargoMirror(manifest, { + crates: resolve(options.crates), + output: resolve(options.output), + names: status?.missing?.rust?.map((item) => item.name) ?? crateNames, + }) + return + } + const remote = await inspectRemote(manifest, { base: options.base ?? defaultBase }) + if (options.command === "status") { + await appendOutput(options.output, remote.states) + if (options.status) await writeFile(options.status, `${JSON.stringify(remote, null, 2)}\n`) + process.stdout.write(`${JSON.stringify(remote.states, null, 2)}\n`) + return + } + expect( + Object.values(remote.states).every((state) => state === "matched"), + "private mirror is incomplete", + ) + expect(options.receipt, "verify requires --receipt") + await writeFile( + options.receipt, + `${JSON.stringify(receipt(manifest, remote, options.base ?? defaultBase), null, 2)}\n`, + ) +} + +if (process.argv[1] && import.meta.url === pathToFileURL(resolve(process.argv[1])).href) { + main().catch((error) => { + console.error(`private-mirror: ${error.message}`) + process.exit(1) + }) +} diff --git a/packaging/private-mirror.test.mjs b/packaging/private-mirror.test.mjs new file mode 100644 index 0000000..aa3ed00 --- /dev/null +++ b/packaging/private-mirror.test.mjs @@ -0,0 +1,61 @@ +import test from "node:test" +import assert from "node:assert/strict" +import { classifyCollection, inspectRemote, validateMirrorIdentity } from "./private-mirror.mjs" + +const expected = [ + { name: "one", sha256: "a".repeat(64) }, + { name: "two", sha256: "b".repeat(64) }, +] + +test("classifies a wholly missing or byte-identical private release", () => { + assert.equal(classifyCollection(expected, [], "fixture"), "missing") + assert.equal(classifyCollection(expected, expected, "fixture"), "matched") +}) + +test("reports partial releases and refuses checksum drift", () => { + assert.equal(classifyCollection(expected, expected.slice(0, 1), "fixture"), "partial") + assert.throws( + () => classifyCollection(expected, [{ name: "one", sha256: "c".repeat(64) }], "fixture"), + /checksum drift/, + ) +}) + +test("binds the mirror to one stable version and source revision", () => { + const input = { + version: "0.5.1", + sourceSHA: "1".repeat(40), + npmRelease: { schema_version: 1, version: "0.5.1", source_sha: "1".repeat(40) }, + } + assert.doesNotThrow(() => validateMirrorIdentity(input)) + assert.throws( + () => validateMirrorIdentity({ ...input, version: "0.5.0" }), + /version does not match/, + ) + assert.throws( + () => validateMirrorIdentity({ ...input, sourceSHA: "2".repeat(40) }), + /source SHA does not match/, + ) +}) + +test("treats a missing private crate payload as recoverable", async () => { + const checksum = "a".repeat(64) + const manifest = { + version: "0.5.1", + npm: [], + python: [], + go: { module: "github.com/operatorstack/yield", version: "v0.5.1" }, + rust: [{ name: "yieldskill", sha256: checksum }], + } + const fetchImpl = async (url) => { + if (String(url).includes("/cargo/index/")) { + return new Response( + `${JSON.stringify({ name: "yieldskill", vers: "0.5.1", cksum: checksum })}\n`, + ) + } + return new Response("missing", { status: 404 }) + } + + const result = await inspectRemote(manifest, { base: "https://mirror.test", fetchImpl }) + assert.equal(result.states.rust, "missing") + assert.deepEqual(result.missing.rust, manifest.rust) +}) diff --git a/scripts/check-release-control.mjs b/scripts/check-release-control.mjs index 9aa0979..631ff4d 100644 --- a/scripts/check-release-control.mjs +++ b/scripts/check-release-control.mjs @@ -152,6 +152,28 @@ export async function checkReleaseControl(root = resolve(import.meta.dirname, ". publisher.jobs?.crates?.environment === "crates-production", "stable crates.io publishing must use the protected crates-production environment", ) + const privateMirror = publisher.jobs?.["private-mirror"] + expect(privateMirror?.environment === "private-production", "private mirroring must be protected") + expect( + privateMirror?.permissions?.contents === "read" && + privateMirror?.permissions?.["id-token"] === "write", + "private mirroring must use read-only source plus WIF", + ) + expect( + ["build", "npm", "pypi", "crates"].every((job) => privateMirror?.needs?.includes(job)), + "private mirroring must follow every immutable public release unit", + ) + expect( + privateMirror?.if === "needs.resolve.outputs.channel == 'stable'", + "private mirroring must exclude canary releases", + ) + expect( + raw["npm-publish.yml"].includes("packaging/private-mirror.mjs verify") && + raw["npm-publish.yml"].includes( + "name: private-mirror-${{ needs.resolve.outputs.version }}-${{ needs.resolve.outputs.source_sha }}", + ), + "private mirroring must emit an exact verified receipt", + ) expect( publisher.jobs?.["selfhost-canary"]?.needs?.includes("npm"), "canary self-hosting must follow successful npm publication", @@ -261,7 +283,8 @@ export async function checkReleaseControl(root = resolve(import.meta.dirname, ". expect( raw["release-finalize.yml"].includes("artifacts?per_page=100") && raw["release-finalize.yml"].includes('grep -Fqx "$package_receipt"') && - raw["release-finalize.yml"].includes('grep -Fqx "$crates_receipt"'), + raw["release-finalize.yml"].includes('grep -Fqx "$crates_receipt"') && + raw["release-finalize.yml"].includes('grep -Fqx "$private_receipt"'), "finalization must select the publisher receipt by its exact source-bound artifact names", ) expect( @@ -302,6 +325,12 @@ export async function checkReleaseControl(root = resolve(import.meta.dirname, ". raw["release-finalize.yml"].includes('--name "$crates_receipt"'), "finalization must consume the publisher-produced crates receipt", ) + expect( + raw["release-finalize.yml"].includes( + 'private_receipt="private-mirror-${version}-${SOURCE_SHA}"', + ) && raw["release-finalize.yml"].includes('--name "$private_receipt"'), + "finalization must consume the verified private mirror receipt", + ) expect( raw["release.yml"].includes("gh workflow run npm-publish.yml"), "the release controller must dispatch the trusted-publishing event after tagging", diff --git a/scripts/readme.test.mjs b/scripts/readme.test.mjs index e963e9b..0e3def4 100644 --- a/scripts/readme.test.mjs +++ b/scripts/readme.test.mjs @@ -251,7 +251,7 @@ test("Python README presents a public five-step workflow", async () => { assert.match(readme, /python -m pip install yieldskill/) assert.match(readme, /python -m yieldskill init skills\/env-doctor/) assert.match(readme, /python -m yieldskill doctor skills\/env-doctor --test/) - assert.match(readme, /python -m yieldskill register skills\/env-doctor/) + assert.match(readme, /python -m yieldskill register skills\/env-doctor --root \./) assert.match(readme, /^\/env-doctor$/m) assert.match( readme, @@ -371,8 +371,8 @@ test("README and quickstart use the public documentation and package registries" /\[public documentation\]\(https:\/\/yield\.operatorstack\.systems\/docs\/\)/, ) const helperCommands = [ - "npm exec -- yskill helper install --language typescript", - "python -m yieldskill helper install --language python", + "npm exec -- yskill helper install --root . --language typescript", + "python -m yieldskill helper install --root . --language python", ".yield/bin/yskill helper install --root . --language rust", "go run github.com/operatorstack/yield/cmd/yskill@latest helper install --root . --language go", ] diff --git a/sdk/python/README.md b/sdk/python/README.md index ebd22ea..bdd73bd 100644 --- a/sdk/python/README.md +++ b/sdk/python/README.md @@ -143,14 +143,14 @@ fixture. A successful test reaches `completed` without leaving a run journal. Registration lets installed coding agents discover the workflow: ```bash -python -m yieldskill register skills/env-doctor +python -m yieldskill register skills/env-doctor --root . ``` Select the verified agents explicitly when you do not want automatic detection: ```bash -python -m yieldskill register skills/env-doctor \ +python -m yieldskill register skills/env-doctor --root . \ --agent cursor,codex,claude-code ``` @@ -229,7 +229,7 @@ Installing `yieldskill` does not create skills or coding-agent adapters. After learning the manual workflow above, install guided assistance explicitly: ```bash -python -m yieldskill helper install --language python +python -m yieldskill helper install --root . --language python ``` Review the plan and restart the coding agent after installation. The helper diff --git a/skills/release-yield/src/release-controller.mjs b/skills/release-yield/src/release-controller.mjs index 12e1bd8..c8cea49 100644 --- a/skills/release-yield/src/release-controller.mjs +++ b/skills/release-yield/src/release-controller.mjs @@ -300,7 +300,7 @@ async function monitorController(values) { async function monitorPublisher(values) { const info = await waitRun( values["run-id"], - new Set(["npm-production", "pypi-production", "crates-production"]), + new Set(["npm-production", "pypi-production", "crates-production", "private-production"]), ) return { run_id: String(info.databaseId), run_url: info.url, environments: info.environments } } From 136955389c8fb6c92faa3a2c15f3e774109276f5 Mon Sep 17 00:00:00 2001 From: bigboateng Date: Mon, 10 Aug 2026 11:56:29 +0100 Subject: [PATCH 2/5] Refresh release workflow adapters --- .agents/skills/release-yield/SKILL.md | 2 +- .claude/skills/release-yield/SKILL.md | 2 +- .cursor/skills/release-yield/SKILL.md | 2 +- cmd/yskill/agents.go | 7 +++---- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/.agents/skills/release-yield/SKILL.md b/.agents/skills/release-yield/SKILL.md index f8dd746..3ee76c1 100644 --- a/.agents/skills/release-yield/SKILL.md +++ b/.agents/skills/release-yield/SKILL.md @@ -3,7 +3,7 @@ name: release-yield description: "Release Yield through its protected GitHub workflows and verify every public registry." --- - + This adapter exposes the canonical Yield workflow at `skills/release-yield`. Read its SKILL.md, then run from the repository root: diff --git a/.claude/skills/release-yield/SKILL.md b/.claude/skills/release-yield/SKILL.md index f8dd746..3ee76c1 100644 --- a/.claude/skills/release-yield/SKILL.md +++ b/.claude/skills/release-yield/SKILL.md @@ -3,7 +3,7 @@ name: release-yield description: "Release Yield through its protected GitHub workflows and verify every public registry." --- - + This adapter exposes the canonical Yield workflow at `skills/release-yield`. Read its SKILL.md, then run from the repository root: diff --git a/.cursor/skills/release-yield/SKILL.md b/.cursor/skills/release-yield/SKILL.md index f8dd746..3ee76c1 100644 --- a/.cursor/skills/release-yield/SKILL.md +++ b/.cursor/skills/release-yield/SKILL.md @@ -3,7 +3,7 @@ name: release-yield description: "Release Yield through its protected GitHub workflows and verify every public registry." --- - + This adapter exposes the canonical Yield workflow at `skills/release-yield`. Read its SKILL.md, then run from the repository root: diff --git a/cmd/yskill/agents.go b/cmd/yskill/agents.go index e2a4a1e..3cc8dba 100644 --- a/cmd/yskill/agents.go +++ b/cmd/yskill/agents.go @@ -861,12 +861,11 @@ Read its SKILL.md, then run from the repository root: %s run %s + Follow each returned operation exactly. Answer each operation directly: -Follow each returned operation exactly. Answer each operation directly: + %s respond --value --skill %s - %s respond --value --skill %s - -For structured agent results, use --result-json instead of --value. + For structured agent results, use --result-json instead of --value. Do not skip an operation or invent its response. `, metadata.Name, yamlString(metadata.Description), generatedAdapterPrefix, sourceRel, digest, runtimeVersion(), "`"+sourceRel+"`", launcher, path, launcher, path) From dac79ddad44c86b8662cd7e2726d5dad00c760a0 Mon Sep 17 00:00:00 2001 From: bigboateng Date: Mon, 10 Aug 2026 11:59:20 +0100 Subject: [PATCH 3/5] Refresh workflow evaluation evidence --- evals/results/latest.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/evals/results/latest.json b/evals/results/latest.json index 986f527..84b5753 100644 --- a/evals/results/latest.json +++ b/evals/results/latest.json @@ -1,8 +1,8 @@ { "schema_version": 2, "methodology_version": "1.1", - "generated_at": "2026-08-09T13:40:24.575Z", - "source_digest": "9a3f7e52d3321fc41bd5792f185db8d9aac235f4031cc1d0651bb60e8de076c1", + "generated_at": "2026-08-10T10:58:49.971Z", + "source_digest": "6ccebc2b9b62e4c1677cad2d7f48e6b3a2e0c3dc06711f3ee6debdee22251ed0", "status": "passed", "workflow_conformance": { "passed": 40, From 70e346eeb28b4de271e246fea004214558f9061d Mon Sep 17 00:00:00 2001 From: bigboateng Date: Mon, 10 Aug 2026 12:02:59 +0100 Subject: [PATCH 4/5] Advance example contracts to Yield 0.5.1 --- evals/results/latest.json | 4 ++-- evals/scripts/run.mjs | 2 +- examples/convert-skill/skill.json | 2 +- examples/data-migration/skill.json | 2 +- examples/env-doctor/skill.json | 2 +- examples/investigate/skill.json | 2 +- examples/library/go/audit-security/skill.json | 2 +- examples/library/go/investigate-failure/skill.json | 2 +- examples/library/go/migrate-database/skill.json | 2 +- examples/library/go/publish-ios/skill.json | 2 +- examples/library/go/qa-web-change/skill.json | 2 +- examples/library/go/release-package/skill.json | 2 +- examples/library/go/repair-ci/skill.json | 2 +- examples/library/go/review-branch/skill.json | 2 +- examples/library/go/triage-issue/skill.json | 2 +- examples/library/go/upgrade-dependency/skill.json | 2 +- examples/library/python/audit-security/skill.json | 2 +- examples/library/python/investigate-failure/skill.json | 2 +- examples/library/python/migrate-database/skill.json | 2 +- examples/library/python/publish-ios/skill.json | 2 +- examples/library/python/qa-web-change/skill.json | 2 +- examples/library/python/release-package/skill.json | 2 +- examples/library/python/repair-ci/skill.json | 2 +- examples/library/python/review-branch/skill.json | 2 +- examples/library/python/triage-issue/skill.json | 2 +- examples/library/python/upgrade-dependency/skill.json | 2 +- examples/library/rust/audit-security/skill.json | 2 +- examples/library/rust/investigate-failure/skill.json | 2 +- examples/library/rust/migrate-database/skill.json | 2 +- examples/library/rust/publish-ios/skill.json | 2 +- examples/library/rust/qa-web-change/skill.json | 2 +- examples/library/rust/release-package/skill.json | 2 +- examples/library/rust/repair-ci/skill.json | 2 +- examples/library/rust/review-branch/skill.json | 2 +- examples/library/rust/triage-issue/skill.json | 2 +- examples/library/rust/upgrade-dependency/skill.json | 2 +- examples/library/typescript/audit-security/skill.json | 2 +- examples/library/typescript/investigate-failure/skill.json | 2 +- examples/library/typescript/migrate-database/skill.json | 2 +- examples/library/typescript/publish-ios/skill.json | 2 +- examples/library/typescript/qa-web-change/skill.json | 2 +- examples/library/typescript/release-package/skill.json | 2 +- examples/library/typescript/repair-ci/skill.json | 2 +- examples/library/typescript/review-branch/skill.json | 2 +- examples/library/typescript/triage-issue/skill.json | 2 +- examples/library/typescript/upgrade-dependency/skill.json | 2 +- examples/release-checklist/skill.json | 2 +- 47 files changed, 48 insertions(+), 48 deletions(-) diff --git a/evals/results/latest.json b/evals/results/latest.json index 84b5753..c7694ab 100644 --- a/evals/results/latest.json +++ b/evals/results/latest.json @@ -1,8 +1,8 @@ { "schema_version": 2, "methodology_version": "1.1", - "generated_at": "2026-08-10T10:58:49.971Z", - "source_digest": "6ccebc2b9b62e4c1677cad2d7f48e6b3a2e0c3dc06711f3ee6debdee22251ed0", + "generated_at": "2026-08-10T11:02:26.511Z", + "source_digest": "a39e924e95ccc2c6485a758109cc4d3429d82d0008352da22a567966fdf29254", "status": "passed", "workflow_conformance": { "passed": 40, diff --git a/evals/scripts/run.mjs b/evals/scripts/run.mjs index fb8392c..1fc3e88 100644 --- a/evals/scripts/run.mjs +++ b/evals/scripts/run.mjs @@ -59,7 +59,7 @@ const runtimeCases = [ "changed source is refused until the user accepts the change", ], ] -const workflowRuntimeVersion = "0.5.0" +const workflowRuntimeVersion = "0.5.1" const excludedDirectories = new Set([ ".git", ".yield", diff --git a/examples/convert-skill/skill.json b/examples/convert-skill/skill.json index c09c290..95c2241 100644 --- a/examples/convert-skill/skill.json +++ b/examples/convert-skill/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.0", + "yield_version": "0.5.1", "language": "go", "run": ["go", "run", "."] } diff --git a/examples/data-migration/skill.json b/examples/data-migration/skill.json index 88e0ff9..137df58 100644 --- a/examples/data-migration/skill.json +++ b/examples/data-migration/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.0", + "yield_version": "0.5.1", "language": "rust", "run": ["cargo", "run", "--quiet"] } diff --git a/examples/env-doctor/skill.json b/examples/env-doctor/skill.json index d08bec8..63c7924 100644 --- a/examples/env-doctor/skill.json +++ b/examples/env-doctor/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.0", + "yield_version": "0.5.1", "language": "python", "run": ["python3", "main.py"] } diff --git a/examples/investigate/skill.json b/examples/investigate/skill.json index c09c290..95c2241 100644 --- a/examples/investigate/skill.json +++ b/examples/investigate/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.0", + "yield_version": "0.5.1", "language": "go", "run": ["go", "run", "."] } diff --git a/examples/library/go/audit-security/skill.json b/examples/library/go/audit-security/skill.json index 4239fa7..2304e61 100644 --- a/examples/library/go/audit-security/skill.json +++ b/examples/library/go/audit-security/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.0", + "yield_version": "0.5.1", "language": "go", "run": [ "go", diff --git a/examples/library/go/investigate-failure/skill.json b/examples/library/go/investigate-failure/skill.json index 1da451b..9025fd9 100644 --- a/examples/library/go/investigate-failure/skill.json +++ b/examples/library/go/investigate-failure/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.0", + "yield_version": "0.5.1", "language": "go", "run": [ "go", diff --git a/examples/library/go/migrate-database/skill.json b/examples/library/go/migrate-database/skill.json index d0a864d..2b613c4 100644 --- a/examples/library/go/migrate-database/skill.json +++ b/examples/library/go/migrate-database/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.0", + "yield_version": "0.5.1", "language": "go", "run": [ "go", diff --git a/examples/library/go/publish-ios/skill.json b/examples/library/go/publish-ios/skill.json index 7a79980..4fab691 100644 --- a/examples/library/go/publish-ios/skill.json +++ b/examples/library/go/publish-ios/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.0", + "yield_version": "0.5.1", "language": "go", "run": [ "go", diff --git a/examples/library/go/qa-web-change/skill.json b/examples/library/go/qa-web-change/skill.json index 27c23cd..3904f48 100644 --- a/examples/library/go/qa-web-change/skill.json +++ b/examples/library/go/qa-web-change/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.0", + "yield_version": "0.5.1", "language": "go", "run": [ "go", diff --git a/examples/library/go/release-package/skill.json b/examples/library/go/release-package/skill.json index fcb1a7f..94e27eb 100644 --- a/examples/library/go/release-package/skill.json +++ b/examples/library/go/release-package/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.0", + "yield_version": "0.5.1", "language": "go", "run": [ "go", diff --git a/examples/library/go/repair-ci/skill.json b/examples/library/go/repair-ci/skill.json index bdeb6f4..7ffe778 100644 --- a/examples/library/go/repair-ci/skill.json +++ b/examples/library/go/repair-ci/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.0", + "yield_version": "0.5.1", "language": "go", "run": [ "go", diff --git a/examples/library/go/review-branch/skill.json b/examples/library/go/review-branch/skill.json index 3024736..69312e2 100644 --- a/examples/library/go/review-branch/skill.json +++ b/examples/library/go/review-branch/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.0", + "yield_version": "0.5.1", "language": "go", "run": [ "go", diff --git a/examples/library/go/triage-issue/skill.json b/examples/library/go/triage-issue/skill.json index b3edb96..725dadf 100644 --- a/examples/library/go/triage-issue/skill.json +++ b/examples/library/go/triage-issue/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.0", + "yield_version": "0.5.1", "language": "go", "run": [ "go", diff --git a/examples/library/go/upgrade-dependency/skill.json b/examples/library/go/upgrade-dependency/skill.json index 44274b5..45a4348 100644 --- a/examples/library/go/upgrade-dependency/skill.json +++ b/examples/library/go/upgrade-dependency/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.0", + "yield_version": "0.5.1", "language": "go", "run": [ "go", diff --git a/examples/library/python/audit-security/skill.json b/examples/library/python/audit-security/skill.json index 1d95a1d..a9f8746 100644 --- a/examples/library/python/audit-security/skill.json +++ b/examples/library/python/audit-security/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.0", + "yield_version": "0.5.1", "language": "python", "run": [ "python3", diff --git a/examples/library/python/investigate-failure/skill.json b/examples/library/python/investigate-failure/skill.json index 3427672..c8cca12 100644 --- a/examples/library/python/investigate-failure/skill.json +++ b/examples/library/python/investigate-failure/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.0", + "yield_version": "0.5.1", "language": "python", "run": [ "python3", diff --git a/examples/library/python/migrate-database/skill.json b/examples/library/python/migrate-database/skill.json index 2d25dff..855c2bb 100644 --- a/examples/library/python/migrate-database/skill.json +++ b/examples/library/python/migrate-database/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.0", + "yield_version": "0.5.1", "language": "python", "run": [ "python3", diff --git a/examples/library/python/publish-ios/skill.json b/examples/library/python/publish-ios/skill.json index b7369ee..3609c31 100644 --- a/examples/library/python/publish-ios/skill.json +++ b/examples/library/python/publish-ios/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.0", + "yield_version": "0.5.1", "language": "python", "run": [ "python3", diff --git a/examples/library/python/qa-web-change/skill.json b/examples/library/python/qa-web-change/skill.json index edcfc44..27c5a11 100644 --- a/examples/library/python/qa-web-change/skill.json +++ b/examples/library/python/qa-web-change/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.0", + "yield_version": "0.5.1", "language": "python", "run": [ "python3", diff --git a/examples/library/python/release-package/skill.json b/examples/library/python/release-package/skill.json index f628c14..a6c866f 100644 --- a/examples/library/python/release-package/skill.json +++ b/examples/library/python/release-package/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.0", + "yield_version": "0.5.1", "language": "python", "run": [ "python3", diff --git a/examples/library/python/repair-ci/skill.json b/examples/library/python/repair-ci/skill.json index 82174dd..0f8aec3 100644 --- a/examples/library/python/repair-ci/skill.json +++ b/examples/library/python/repair-ci/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.0", + "yield_version": "0.5.1", "language": "python", "run": [ "python3", diff --git a/examples/library/python/review-branch/skill.json b/examples/library/python/review-branch/skill.json index 0a095cd..deb1d3f 100644 --- a/examples/library/python/review-branch/skill.json +++ b/examples/library/python/review-branch/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.0", + "yield_version": "0.5.1", "language": "python", "run": [ "python3", diff --git a/examples/library/python/triage-issue/skill.json b/examples/library/python/triage-issue/skill.json index 89bff56..e927988 100644 --- a/examples/library/python/triage-issue/skill.json +++ b/examples/library/python/triage-issue/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.0", + "yield_version": "0.5.1", "language": "python", "run": [ "python3", diff --git a/examples/library/python/upgrade-dependency/skill.json b/examples/library/python/upgrade-dependency/skill.json index 1fc34e6..bb49af0 100644 --- a/examples/library/python/upgrade-dependency/skill.json +++ b/examples/library/python/upgrade-dependency/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.0", + "yield_version": "0.5.1", "language": "python", "run": [ "python3", diff --git a/examples/library/rust/audit-security/skill.json b/examples/library/rust/audit-security/skill.json index a37b7eb..b340a13 100644 --- a/examples/library/rust/audit-security/skill.json +++ b/examples/library/rust/audit-security/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.0", + "yield_version": "0.5.1", "language": "rust", "run": [ "cargo", diff --git a/examples/library/rust/investigate-failure/skill.json b/examples/library/rust/investigate-failure/skill.json index 554551a..678199a 100644 --- a/examples/library/rust/investigate-failure/skill.json +++ b/examples/library/rust/investigate-failure/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.0", + "yield_version": "0.5.1", "language": "rust", "run": [ "cargo", diff --git a/examples/library/rust/migrate-database/skill.json b/examples/library/rust/migrate-database/skill.json index 5b49899..b2d98fe 100644 --- a/examples/library/rust/migrate-database/skill.json +++ b/examples/library/rust/migrate-database/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.0", + "yield_version": "0.5.1", "language": "rust", "run": [ "cargo", diff --git a/examples/library/rust/publish-ios/skill.json b/examples/library/rust/publish-ios/skill.json index 4d5db27..56a22db 100644 --- a/examples/library/rust/publish-ios/skill.json +++ b/examples/library/rust/publish-ios/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.0", + "yield_version": "0.5.1", "language": "rust", "run": [ "cargo", diff --git a/examples/library/rust/qa-web-change/skill.json b/examples/library/rust/qa-web-change/skill.json index 41f1063..d6807b5 100644 --- a/examples/library/rust/qa-web-change/skill.json +++ b/examples/library/rust/qa-web-change/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.0", + "yield_version": "0.5.1", "language": "rust", "run": [ "cargo", diff --git a/examples/library/rust/release-package/skill.json b/examples/library/rust/release-package/skill.json index 5a29e89..4c613b1 100644 --- a/examples/library/rust/release-package/skill.json +++ b/examples/library/rust/release-package/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.0", + "yield_version": "0.5.1", "language": "rust", "run": [ "cargo", diff --git a/examples/library/rust/repair-ci/skill.json b/examples/library/rust/repair-ci/skill.json index 5d4df6c..188baa8 100644 --- a/examples/library/rust/repair-ci/skill.json +++ b/examples/library/rust/repair-ci/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.0", + "yield_version": "0.5.1", "language": "rust", "run": [ "cargo", diff --git a/examples/library/rust/review-branch/skill.json b/examples/library/rust/review-branch/skill.json index b780c9b..e74c59e 100644 --- a/examples/library/rust/review-branch/skill.json +++ b/examples/library/rust/review-branch/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.0", + "yield_version": "0.5.1", "language": "rust", "run": [ "cargo", diff --git a/examples/library/rust/triage-issue/skill.json b/examples/library/rust/triage-issue/skill.json index 6e54199..6e351a1 100644 --- a/examples/library/rust/triage-issue/skill.json +++ b/examples/library/rust/triage-issue/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.0", + "yield_version": "0.5.1", "language": "rust", "run": [ "cargo", diff --git a/examples/library/rust/upgrade-dependency/skill.json b/examples/library/rust/upgrade-dependency/skill.json index f1af2ac..809a8e1 100644 --- a/examples/library/rust/upgrade-dependency/skill.json +++ b/examples/library/rust/upgrade-dependency/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.0", + "yield_version": "0.5.1", "language": "rust", "run": [ "cargo", diff --git a/examples/library/typescript/audit-security/skill.json b/examples/library/typescript/audit-security/skill.json index 5285e40..5610d5e 100644 --- a/examples/library/typescript/audit-security/skill.json +++ b/examples/library/typescript/audit-security/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.0", + "yield_version": "0.5.1", "language": "typescript", "run": [ "node", diff --git a/examples/library/typescript/investigate-failure/skill.json b/examples/library/typescript/investigate-failure/skill.json index 7e6901a..594c00d 100644 --- a/examples/library/typescript/investigate-failure/skill.json +++ b/examples/library/typescript/investigate-failure/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.0", + "yield_version": "0.5.1", "language": "typescript", "run": [ "node", diff --git a/examples/library/typescript/migrate-database/skill.json b/examples/library/typescript/migrate-database/skill.json index 19723b6..6176ab1 100644 --- a/examples/library/typescript/migrate-database/skill.json +++ b/examples/library/typescript/migrate-database/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.0", + "yield_version": "0.5.1", "language": "typescript", "run": [ "node", diff --git a/examples/library/typescript/publish-ios/skill.json b/examples/library/typescript/publish-ios/skill.json index f6aa62a..7a44f74 100644 --- a/examples/library/typescript/publish-ios/skill.json +++ b/examples/library/typescript/publish-ios/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.0", + "yield_version": "0.5.1", "language": "typescript", "run": [ "node", diff --git a/examples/library/typescript/qa-web-change/skill.json b/examples/library/typescript/qa-web-change/skill.json index 4b5e274..4a2f798 100644 --- a/examples/library/typescript/qa-web-change/skill.json +++ b/examples/library/typescript/qa-web-change/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.0", + "yield_version": "0.5.1", "language": "typescript", "run": [ "node", diff --git a/examples/library/typescript/release-package/skill.json b/examples/library/typescript/release-package/skill.json index b9bea81..1145c0a 100644 --- a/examples/library/typescript/release-package/skill.json +++ b/examples/library/typescript/release-package/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.0", + "yield_version": "0.5.1", "language": "typescript", "run": [ "node", diff --git a/examples/library/typescript/repair-ci/skill.json b/examples/library/typescript/repair-ci/skill.json index 1f3cd3f..74e2b09 100644 --- a/examples/library/typescript/repair-ci/skill.json +++ b/examples/library/typescript/repair-ci/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.0", + "yield_version": "0.5.1", "language": "typescript", "run": [ "node", diff --git a/examples/library/typescript/review-branch/skill.json b/examples/library/typescript/review-branch/skill.json index 99f2765..01cf281 100644 --- a/examples/library/typescript/review-branch/skill.json +++ b/examples/library/typescript/review-branch/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.0", + "yield_version": "0.5.1", "language": "typescript", "run": [ "node", diff --git a/examples/library/typescript/triage-issue/skill.json b/examples/library/typescript/triage-issue/skill.json index b2b577d..60dcfd7 100644 --- a/examples/library/typescript/triage-issue/skill.json +++ b/examples/library/typescript/triage-issue/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.0", + "yield_version": "0.5.1", "language": "typescript", "run": [ "node", diff --git a/examples/library/typescript/upgrade-dependency/skill.json b/examples/library/typescript/upgrade-dependency/skill.json index c92e909..4dec39f 100644 --- a/examples/library/typescript/upgrade-dependency/skill.json +++ b/examples/library/typescript/upgrade-dependency/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.0", + "yield_version": "0.5.1", "language": "typescript", "run": [ "node", diff --git a/examples/release-checklist/skill.json b/examples/release-checklist/skill.json index 1ceedde..2f018bb 100644 --- a/examples/release-checklist/skill.json +++ b/examples/release-checklist/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.0", + "yield_version": "0.5.1", "language": "typescript", "run": ["node", "main.ts"] } From 42f0ea4a2cce147c7ccfb11feb27c153bad02704 Mon Sep 17 00:00:00 2001 From: bigboateng Date: Mon, 10 Aug 2026 12:08:32 +0100 Subject: [PATCH 5/5] Keep evaluations manual and version-pinned --- .github/workflows/release-finalize.yml | 1 - .github/workflows/verify.yml | 22 ++----------------- docs/formatting.md | 4 ++-- evals/README.md | 9 ++++---- evals/results/latest.json | 4 ++-- evals/scripts/run.mjs | 2 +- examples/convert-skill/skill.json | 2 +- examples/data-migration/skill.json | 2 +- examples/env-doctor/skill.json | 2 +- examples/investigate/skill.json | 2 +- examples/library/go/audit-security/skill.json | 2 +- .../library/go/investigate-failure/skill.json | 2 +- .../library/go/migrate-database/skill.json | 2 +- examples/library/go/publish-ios/skill.json | 2 +- examples/library/go/qa-web-change/skill.json | 2 +- .../library/go/release-package/skill.json | 2 +- examples/library/go/repair-ci/skill.json | 2 +- examples/library/go/review-branch/skill.json | 2 +- examples/library/go/triage-issue/skill.json | 2 +- .../library/go/upgrade-dependency/skill.json | 2 +- .../library/python/audit-security/skill.json | 2 +- .../python/investigate-failure/skill.json | 2 +- .../python/migrate-database/skill.json | 2 +- .../library/python/publish-ios/skill.json | 2 +- .../library/python/qa-web-change/skill.json | 2 +- .../library/python/release-package/skill.json | 2 +- examples/library/python/repair-ci/skill.json | 2 +- .../library/python/review-branch/skill.json | 2 +- .../library/python/triage-issue/skill.json | 2 +- .../python/upgrade-dependency/skill.json | 2 +- .../library/rust/audit-security/skill.json | 2 +- .../rust/investigate-failure/skill.json | 2 +- .../library/rust/migrate-database/skill.json | 2 +- examples/library/rust/publish-ios/skill.json | 2 +- .../library/rust/qa-web-change/skill.json | 2 +- .../library/rust/release-package/skill.json | 2 +- examples/library/rust/repair-ci/skill.json | 2 +- .../library/rust/review-branch/skill.json | 2 +- examples/library/rust/triage-issue/skill.json | 2 +- .../rust/upgrade-dependency/skill.json | 2 +- .../typescript/audit-security/skill.json | 2 +- .../typescript/investigate-failure/skill.json | 2 +- .../typescript/migrate-database/skill.json | 2 +- .../library/typescript/publish-ios/skill.json | 2 +- .../typescript/qa-web-change/skill.json | 2 +- .../typescript/release-package/skill.json | 2 +- .../library/typescript/repair-ci/skill.json | 2 +- .../typescript/review-branch/skill.json | 2 +- .../typescript/triage-issue/skill.json | 2 +- .../typescript/upgrade-dependency/skill.json | 2 +- examples/release-checklist/skill.json | 2 +- scripts/check-release-control.mjs | 15 +++++++++++++ 52 files changed, 72 insertions(+), 75 deletions(-) diff --git a/.github/workflows/release-finalize.yml b/.github/workflows/release-finalize.yml index ba08bd3..96dc7b7 100644 --- a/.github/workflows/release-finalize.yml +++ b/.github/workflows/release-finalize.yml @@ -146,7 +146,6 @@ jobs: --source-sha "$SOURCE_SHA" \ --attempts 3 \ --delay-ms 10000 - node evals/scripts/run.mjs --check test "$(git rev-list -n 1 "$TAG")" = "$SOURCE_SHA" assets="$RUNNER_TEMP/release-assets" mkdir -p "$assets" diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml index cea9d54..75644f7 100644 --- a/.github/workflows/verify.yml +++ b/.github/workflows/verify.yml @@ -143,7 +143,7 @@ jobs: - run: go test ./... examples: - name: Example workflows and evaluations + name: Example workflows runs-on: ubuntu-latest steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 @@ -166,29 +166,11 @@ jobs: examples/data-migration examples/library/rust - run: npm ci --ignore-scripts - - name: Rerun first-party evaluations - working-directory: evals - run: | - npm ci - npm test - - name: Validate semantic conversion receipt when required - working-directory: evals - env: - EVAL_BASE_SHA: ${{ github.event.pull_request.base.sha || github.event.before }} - EVAL_HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }} - run: npm run test:conversion - name: Run every example fixture run: | base_tag="$(git tag --merged HEAD --list 'v[0-9]*' --sort=-v:refname | head -n1)" test -n "$base_tag" - pending_changesets="$(git diff --name-only --diff-filter=A "$base_tag"..HEAD -- '.changeset/*.md')" - if [[ -n "$pending_changesets" ]]; then - plan="$RUNNER_TEMP/example-release-plan.env" - node scripts/release-plan.mjs --bump auto --output "$plan" --notes "$RUNNER_TEMP/example-release-notes.md" - . "$plan" - else - version="${base_tag#v}" - fi + version="${base_tag#v}" go build -ldflags "-X main.version=$version" -o "$RUNNER_TEMP/yskill" ./cmd/yskill "$RUNNER_TEMP/yskill" test examples/investigate "$RUNNER_TEMP/yskill" test examples/release-checklist diff --git a/docs/formatting.md b/docs/formatting.md index 06fe456..684b772 100644 --- a/docs/formatting.md +++ b/docs/formatting.md @@ -27,5 +27,5 @@ The command pins third-party formatter versions. Go and Rust use the repository toolchain versions. GitHub Actions runs the check and does not rewrite files. The formatter skips generated files. It also skips evaluation sources whose -exact bytes belong to a committed receipt. Run the relevant generator or -evaluation when you change those sources. +exact bytes belong to a committed receipt. Evaluation receipts remain frozen +until an evaluation is intentionally run and reviewed. diff --git a/evals/README.md b/evals/README.md index 76ea90b..a3b542c 100644 --- a/evals/README.md +++ b/evals/README.md @@ -25,7 +25,7 @@ cd evals npm run eval ``` -Check that the published result still matches the current source: +Check a deliberately refreshed result against the current source: ```bash npm test @@ -49,9 +49,10 @@ judgment is correct, or that illustrative commands are production-safe. The fixed test data supplies agent and human responses so the suite can test only the code-controlled workflow layer. -`results/latest.json` is a compact, website-safe result. Its source hash is -computed from the CLI, engine, protocol, SDKs, example workflows, fixtures, and -evaluation harness. CI reruns the suite instead of trusting that file alone. +`results/latest.json` is a compact, website-safe result pinned to the Yield +version that was explicitly evaluated. CI does not rerun evaluations or require +their source hashes to follow ordinary product changes. Run the evaluation +manually when new evidence is needed, then review and commit its receipt. ## Coding-agent workflow check diff --git a/evals/results/latest.json b/evals/results/latest.json index c7694ab..986f527 100644 --- a/evals/results/latest.json +++ b/evals/results/latest.json @@ -1,8 +1,8 @@ { "schema_version": 2, "methodology_version": "1.1", - "generated_at": "2026-08-10T11:02:26.511Z", - "source_digest": "a39e924e95ccc2c6485a758109cc4d3429d82d0008352da22a567966fdf29254", + "generated_at": "2026-08-09T13:40:24.575Z", + "source_digest": "9a3f7e52d3321fc41bd5792f185db8d9aac235f4031cc1d0651bb60e8de076c1", "status": "passed", "workflow_conformance": { "passed": 40, diff --git a/evals/scripts/run.mjs b/evals/scripts/run.mjs index 1fc3e88..fb8392c 100644 --- a/evals/scripts/run.mjs +++ b/evals/scripts/run.mjs @@ -59,7 +59,7 @@ const runtimeCases = [ "changed source is refused until the user accepts the change", ], ] -const workflowRuntimeVersion = "0.5.1" +const workflowRuntimeVersion = "0.5.0" const excludedDirectories = new Set([ ".git", ".yield", diff --git a/examples/convert-skill/skill.json b/examples/convert-skill/skill.json index 95c2241..c09c290 100644 --- a/examples/convert-skill/skill.json +++ b/examples/convert-skill/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.1", + "yield_version": "0.5.0", "language": "go", "run": ["go", "run", "."] } diff --git a/examples/data-migration/skill.json b/examples/data-migration/skill.json index 137df58..88e0ff9 100644 --- a/examples/data-migration/skill.json +++ b/examples/data-migration/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.1", + "yield_version": "0.5.0", "language": "rust", "run": ["cargo", "run", "--quiet"] } diff --git a/examples/env-doctor/skill.json b/examples/env-doctor/skill.json index 63c7924..d08bec8 100644 --- a/examples/env-doctor/skill.json +++ b/examples/env-doctor/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.1", + "yield_version": "0.5.0", "language": "python", "run": ["python3", "main.py"] } diff --git a/examples/investigate/skill.json b/examples/investigate/skill.json index 95c2241..c09c290 100644 --- a/examples/investigate/skill.json +++ b/examples/investigate/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.1", + "yield_version": "0.5.0", "language": "go", "run": ["go", "run", "."] } diff --git a/examples/library/go/audit-security/skill.json b/examples/library/go/audit-security/skill.json index 2304e61..4239fa7 100644 --- a/examples/library/go/audit-security/skill.json +++ b/examples/library/go/audit-security/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.1", + "yield_version": "0.5.0", "language": "go", "run": [ "go", diff --git a/examples/library/go/investigate-failure/skill.json b/examples/library/go/investigate-failure/skill.json index 9025fd9..1da451b 100644 --- a/examples/library/go/investigate-failure/skill.json +++ b/examples/library/go/investigate-failure/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.1", + "yield_version": "0.5.0", "language": "go", "run": [ "go", diff --git a/examples/library/go/migrate-database/skill.json b/examples/library/go/migrate-database/skill.json index 2b613c4..d0a864d 100644 --- a/examples/library/go/migrate-database/skill.json +++ b/examples/library/go/migrate-database/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.1", + "yield_version": "0.5.0", "language": "go", "run": [ "go", diff --git a/examples/library/go/publish-ios/skill.json b/examples/library/go/publish-ios/skill.json index 4fab691..7a79980 100644 --- a/examples/library/go/publish-ios/skill.json +++ b/examples/library/go/publish-ios/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.1", + "yield_version": "0.5.0", "language": "go", "run": [ "go", diff --git a/examples/library/go/qa-web-change/skill.json b/examples/library/go/qa-web-change/skill.json index 3904f48..27c23cd 100644 --- a/examples/library/go/qa-web-change/skill.json +++ b/examples/library/go/qa-web-change/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.1", + "yield_version": "0.5.0", "language": "go", "run": [ "go", diff --git a/examples/library/go/release-package/skill.json b/examples/library/go/release-package/skill.json index 94e27eb..fcb1a7f 100644 --- a/examples/library/go/release-package/skill.json +++ b/examples/library/go/release-package/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.1", + "yield_version": "0.5.0", "language": "go", "run": [ "go", diff --git a/examples/library/go/repair-ci/skill.json b/examples/library/go/repair-ci/skill.json index 7ffe778..bdeb6f4 100644 --- a/examples/library/go/repair-ci/skill.json +++ b/examples/library/go/repair-ci/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.1", + "yield_version": "0.5.0", "language": "go", "run": [ "go", diff --git a/examples/library/go/review-branch/skill.json b/examples/library/go/review-branch/skill.json index 69312e2..3024736 100644 --- a/examples/library/go/review-branch/skill.json +++ b/examples/library/go/review-branch/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.1", + "yield_version": "0.5.0", "language": "go", "run": [ "go", diff --git a/examples/library/go/triage-issue/skill.json b/examples/library/go/triage-issue/skill.json index 725dadf..b3edb96 100644 --- a/examples/library/go/triage-issue/skill.json +++ b/examples/library/go/triage-issue/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.1", + "yield_version": "0.5.0", "language": "go", "run": [ "go", diff --git a/examples/library/go/upgrade-dependency/skill.json b/examples/library/go/upgrade-dependency/skill.json index 45a4348..44274b5 100644 --- a/examples/library/go/upgrade-dependency/skill.json +++ b/examples/library/go/upgrade-dependency/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.1", + "yield_version": "0.5.0", "language": "go", "run": [ "go", diff --git a/examples/library/python/audit-security/skill.json b/examples/library/python/audit-security/skill.json index a9f8746..1d95a1d 100644 --- a/examples/library/python/audit-security/skill.json +++ b/examples/library/python/audit-security/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.1", + "yield_version": "0.5.0", "language": "python", "run": [ "python3", diff --git a/examples/library/python/investigate-failure/skill.json b/examples/library/python/investigate-failure/skill.json index c8cca12..3427672 100644 --- a/examples/library/python/investigate-failure/skill.json +++ b/examples/library/python/investigate-failure/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.1", + "yield_version": "0.5.0", "language": "python", "run": [ "python3", diff --git a/examples/library/python/migrate-database/skill.json b/examples/library/python/migrate-database/skill.json index 855c2bb..2d25dff 100644 --- a/examples/library/python/migrate-database/skill.json +++ b/examples/library/python/migrate-database/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.1", + "yield_version": "0.5.0", "language": "python", "run": [ "python3", diff --git a/examples/library/python/publish-ios/skill.json b/examples/library/python/publish-ios/skill.json index 3609c31..b7369ee 100644 --- a/examples/library/python/publish-ios/skill.json +++ b/examples/library/python/publish-ios/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.1", + "yield_version": "0.5.0", "language": "python", "run": [ "python3", diff --git a/examples/library/python/qa-web-change/skill.json b/examples/library/python/qa-web-change/skill.json index 27c5a11..edcfc44 100644 --- a/examples/library/python/qa-web-change/skill.json +++ b/examples/library/python/qa-web-change/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.1", + "yield_version": "0.5.0", "language": "python", "run": [ "python3", diff --git a/examples/library/python/release-package/skill.json b/examples/library/python/release-package/skill.json index a6c866f..f628c14 100644 --- a/examples/library/python/release-package/skill.json +++ b/examples/library/python/release-package/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.1", + "yield_version": "0.5.0", "language": "python", "run": [ "python3", diff --git a/examples/library/python/repair-ci/skill.json b/examples/library/python/repair-ci/skill.json index 0f8aec3..82174dd 100644 --- a/examples/library/python/repair-ci/skill.json +++ b/examples/library/python/repair-ci/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.1", + "yield_version": "0.5.0", "language": "python", "run": [ "python3", diff --git a/examples/library/python/review-branch/skill.json b/examples/library/python/review-branch/skill.json index deb1d3f..0a095cd 100644 --- a/examples/library/python/review-branch/skill.json +++ b/examples/library/python/review-branch/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.1", + "yield_version": "0.5.0", "language": "python", "run": [ "python3", diff --git a/examples/library/python/triage-issue/skill.json b/examples/library/python/triage-issue/skill.json index e927988..89bff56 100644 --- a/examples/library/python/triage-issue/skill.json +++ b/examples/library/python/triage-issue/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.1", + "yield_version": "0.5.0", "language": "python", "run": [ "python3", diff --git a/examples/library/python/upgrade-dependency/skill.json b/examples/library/python/upgrade-dependency/skill.json index bb49af0..1fc34e6 100644 --- a/examples/library/python/upgrade-dependency/skill.json +++ b/examples/library/python/upgrade-dependency/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.1", + "yield_version": "0.5.0", "language": "python", "run": [ "python3", diff --git a/examples/library/rust/audit-security/skill.json b/examples/library/rust/audit-security/skill.json index b340a13..a37b7eb 100644 --- a/examples/library/rust/audit-security/skill.json +++ b/examples/library/rust/audit-security/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.1", + "yield_version": "0.5.0", "language": "rust", "run": [ "cargo", diff --git a/examples/library/rust/investigate-failure/skill.json b/examples/library/rust/investigate-failure/skill.json index 678199a..554551a 100644 --- a/examples/library/rust/investigate-failure/skill.json +++ b/examples/library/rust/investigate-failure/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.1", + "yield_version": "0.5.0", "language": "rust", "run": [ "cargo", diff --git a/examples/library/rust/migrate-database/skill.json b/examples/library/rust/migrate-database/skill.json index b2d98fe..5b49899 100644 --- a/examples/library/rust/migrate-database/skill.json +++ b/examples/library/rust/migrate-database/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.1", + "yield_version": "0.5.0", "language": "rust", "run": [ "cargo", diff --git a/examples/library/rust/publish-ios/skill.json b/examples/library/rust/publish-ios/skill.json index 56a22db..4d5db27 100644 --- a/examples/library/rust/publish-ios/skill.json +++ b/examples/library/rust/publish-ios/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.1", + "yield_version": "0.5.0", "language": "rust", "run": [ "cargo", diff --git a/examples/library/rust/qa-web-change/skill.json b/examples/library/rust/qa-web-change/skill.json index d6807b5..41f1063 100644 --- a/examples/library/rust/qa-web-change/skill.json +++ b/examples/library/rust/qa-web-change/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.1", + "yield_version": "0.5.0", "language": "rust", "run": [ "cargo", diff --git a/examples/library/rust/release-package/skill.json b/examples/library/rust/release-package/skill.json index 4c613b1..5a29e89 100644 --- a/examples/library/rust/release-package/skill.json +++ b/examples/library/rust/release-package/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.1", + "yield_version": "0.5.0", "language": "rust", "run": [ "cargo", diff --git a/examples/library/rust/repair-ci/skill.json b/examples/library/rust/repair-ci/skill.json index 188baa8..5d4df6c 100644 --- a/examples/library/rust/repair-ci/skill.json +++ b/examples/library/rust/repair-ci/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.1", + "yield_version": "0.5.0", "language": "rust", "run": [ "cargo", diff --git a/examples/library/rust/review-branch/skill.json b/examples/library/rust/review-branch/skill.json index e74c59e..b780c9b 100644 --- a/examples/library/rust/review-branch/skill.json +++ b/examples/library/rust/review-branch/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.1", + "yield_version": "0.5.0", "language": "rust", "run": [ "cargo", diff --git a/examples/library/rust/triage-issue/skill.json b/examples/library/rust/triage-issue/skill.json index 6e351a1..6e54199 100644 --- a/examples/library/rust/triage-issue/skill.json +++ b/examples/library/rust/triage-issue/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.1", + "yield_version": "0.5.0", "language": "rust", "run": [ "cargo", diff --git a/examples/library/rust/upgrade-dependency/skill.json b/examples/library/rust/upgrade-dependency/skill.json index 809a8e1..f1af2ac 100644 --- a/examples/library/rust/upgrade-dependency/skill.json +++ b/examples/library/rust/upgrade-dependency/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.1", + "yield_version": "0.5.0", "language": "rust", "run": [ "cargo", diff --git a/examples/library/typescript/audit-security/skill.json b/examples/library/typescript/audit-security/skill.json index 5610d5e..5285e40 100644 --- a/examples/library/typescript/audit-security/skill.json +++ b/examples/library/typescript/audit-security/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.1", + "yield_version": "0.5.0", "language": "typescript", "run": [ "node", diff --git a/examples/library/typescript/investigate-failure/skill.json b/examples/library/typescript/investigate-failure/skill.json index 594c00d..7e6901a 100644 --- a/examples/library/typescript/investigate-failure/skill.json +++ b/examples/library/typescript/investigate-failure/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.1", + "yield_version": "0.5.0", "language": "typescript", "run": [ "node", diff --git a/examples/library/typescript/migrate-database/skill.json b/examples/library/typescript/migrate-database/skill.json index 6176ab1..19723b6 100644 --- a/examples/library/typescript/migrate-database/skill.json +++ b/examples/library/typescript/migrate-database/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.1", + "yield_version": "0.5.0", "language": "typescript", "run": [ "node", diff --git a/examples/library/typescript/publish-ios/skill.json b/examples/library/typescript/publish-ios/skill.json index 7a44f74..f6aa62a 100644 --- a/examples/library/typescript/publish-ios/skill.json +++ b/examples/library/typescript/publish-ios/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.1", + "yield_version": "0.5.0", "language": "typescript", "run": [ "node", diff --git a/examples/library/typescript/qa-web-change/skill.json b/examples/library/typescript/qa-web-change/skill.json index 4a2f798..4b5e274 100644 --- a/examples/library/typescript/qa-web-change/skill.json +++ b/examples/library/typescript/qa-web-change/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.1", + "yield_version": "0.5.0", "language": "typescript", "run": [ "node", diff --git a/examples/library/typescript/release-package/skill.json b/examples/library/typescript/release-package/skill.json index 1145c0a..b9bea81 100644 --- a/examples/library/typescript/release-package/skill.json +++ b/examples/library/typescript/release-package/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.1", + "yield_version": "0.5.0", "language": "typescript", "run": [ "node", diff --git a/examples/library/typescript/repair-ci/skill.json b/examples/library/typescript/repair-ci/skill.json index 74e2b09..1f3cd3f 100644 --- a/examples/library/typescript/repair-ci/skill.json +++ b/examples/library/typescript/repair-ci/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.1", + "yield_version": "0.5.0", "language": "typescript", "run": [ "node", diff --git a/examples/library/typescript/review-branch/skill.json b/examples/library/typescript/review-branch/skill.json index 01cf281..99f2765 100644 --- a/examples/library/typescript/review-branch/skill.json +++ b/examples/library/typescript/review-branch/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.1", + "yield_version": "0.5.0", "language": "typescript", "run": [ "node", diff --git a/examples/library/typescript/triage-issue/skill.json b/examples/library/typescript/triage-issue/skill.json index 60dcfd7..b2b577d 100644 --- a/examples/library/typescript/triage-issue/skill.json +++ b/examples/library/typescript/triage-issue/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.1", + "yield_version": "0.5.0", "language": "typescript", "run": [ "node", diff --git a/examples/library/typescript/upgrade-dependency/skill.json b/examples/library/typescript/upgrade-dependency/skill.json index 4dec39f..c92e909 100644 --- a/examples/library/typescript/upgrade-dependency/skill.json +++ b/examples/library/typescript/upgrade-dependency/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.1", + "yield_version": "0.5.0", "language": "typescript", "run": [ "node", diff --git a/examples/release-checklist/skill.json b/examples/release-checklist/skill.json index 2f018bb..1ceedde 100644 --- a/examples/release-checklist/skill.json +++ b/examples/release-checklist/skill.json @@ -1,6 +1,6 @@ { "version": 1, - "yield_version": "0.5.1", + "yield_version": "0.5.0", "language": "typescript", "run": ["node", "main.ts"] } diff --git a/scripts/check-release-control.mjs b/scripts/check-release-control.mjs index 631ff4d..503bb05 100644 --- a/scripts/check-release-control.mjs +++ b/scripts/check-release-control.mjs @@ -84,6 +84,17 @@ export async function checkReleaseControl(root = resolve(import.meta.dirname, ". verify.jobs?.validate?.name === "Release authority and full validation", "the protected validation context must remain stable", ) + expect( + verify.jobs?.examples?.name === "Example workflows" && + raw["verify.yml"].includes('version="${base_tag#v}"'), + "example verification must stay pinned to the latest released Yield version", + ) + expect( + !raw["verify.yml"].includes("evals/scripts/run.mjs") && + !raw["verify.yml"].includes("test:conversion") && + !raw["verify.yml"].includes("working-directory: evals"), + "automatic verification must not run manual evaluations", + ) const release = workflows["release.yml"] expect(release, "release.yml is required") @@ -311,6 +322,10 @@ export async function checkReleaseControl(root = resolve(import.meta.dirname, ". raw["release-finalize.yml"].includes("package-contract.mjs"), "finalization must create the website package contract before release publication", ) + expect( + !raw["release-finalize.yml"].includes("evals/scripts/run.mjs"), + "release finalization must consume frozen evidence without rerunning evaluations", + ) expect( raw["release-finalize.yml"].indexOf("gh release upload") < raw["release-finalize.yml"].indexOf("--draft=false"),