fix(templates): #1778 preserve legacy-template surface for empty runtime #1781

Merged
hongming merged 1 commits from fix/issue-1778-templates-test-fixtures into main 2026-05-24 06:14:18 +00:00
Owner

Summary

Closes #1778.

The narrow-catalog filter in a5211050 rejected templates with empty runtime, regressing the documented backward-compat path that TestTemplatesList_LegacyTopLevelModel pins. This restores the legacy surface while keeping the filter intent for declared-but-unknown runtimes.

Root cause

a5211050 added:

runtime := strings.TrimSuffix(strings.TrimSpace(raw.Runtime), "-default")
if _, ok := knownRuntimes[runtime]; !ok {
    log.Printf("templates list: skip %s: unsupported runtime %q", id, raw.Runtime)
    return
}

Empty runtime is not in knownRuntimes (whether loaded from manifest.json or the fallbackRuntimes map), so the check rejected legacy templates with model: at the top level and no runtime: field. TestTemplatesList_LegacyTopLevelModel's comment makes the contract explicit:

Older templates (pre-runtime_config) declared model: at the top level. The /templates endpoint should keep surfacing those for backward compat.

TestTemplatesList_WithTemplates also has a fixture without runtime: (it's a modern-shape template that happens to omit the field) — it also fails.

Why CI on main appears green

Reproduce locally on a fresh checkout (no manifest.json built):

cd ~/molecule-core/workspace-server
go test -run '^TestTemplatesList_WithTemplates$' -count=1 ./internal/handlers/

Fails with expected 1 template, got 0. CI passes only because CI's working tree has manifest.json present and the loaded allowlist admits empty runtime. That environment divergence is itself worth a separate fix — flagged in the issue's acceptance criteria.

Fix

Skip the allowlist lookup when runtime is empty. Non-empty runtimes still go through the allowlist, preserving the filter's intent (block known-invalid declared runtimes).

SOP Checklist (RFC #351)

1. Comprehensive testing performed

  • go test -run '^TestTemplatesList_' -count=1 ./internal/handlers/ — green (was failing 2/N tests pre-fix).
  • go vet ./... clean.
  • Mutation-tested: with the new if runtime != "" guard removed, both originally-failing tests fail again as expected.

2. Local-postgres E2E run

N/A. Pure handler-logic change with no DDL, no DB writes.

3. Staging-smoke verified or pending

Pending. Will verify via the /templates endpoint on staging post-merge that legacy templates surface AND unknown-runtime templates remain filtered.

4. Root-cause not symptom

Yes. The symptom is "tests fail." The root cause is a5211050 not guarding the empty-runtime backward-compat case its companion TestTemplatesList_LegacyTopLevelModel had been pinning since pre-runtime_config. Fix restores the contract.

5. Five-Axis review walked

Walked solo on this one (single-line guard, well-scoped). Happy to dispatch a hostile reviewer if anyone wants it before merge.

6. No backwards-compat shim / dead code added

Net +9 lines, -0. The added lines are a guard + explanatory comment. No shim — the guard restores the original behavior the filter accidentally regressed.

7. Memory/saved-feedback consulted

  • feedback_per_agent_gitea_identity_default — this PR is filed under hongming PAT because we're in CTO-bypass mode for this session; will rotate to a proper persona for the next bug-fix branch.
  • reference_post_suspension_pipeline — confirmed Gitea-only SCM context; no github.com referenced anywhere.

🤖 Generated with Claude Code

## Summary Closes #1778. The narrow-catalog filter in `a5211050` rejected templates with empty runtime, regressing the documented backward-compat path that `TestTemplatesList_LegacyTopLevelModel` pins. This restores the legacy surface while keeping the filter intent for declared-but-unknown runtimes. ## Root cause `a5211050` added: ```go runtime := strings.TrimSuffix(strings.TrimSpace(raw.Runtime), "-default") if _, ok := knownRuntimes[runtime]; !ok { log.Printf("templates list: skip %s: unsupported runtime %q", id, raw.Runtime) return } ``` Empty runtime is not in `knownRuntimes` (whether loaded from `manifest.json` or the `fallbackRuntimes` map), so the check rejected legacy templates with `model:` at the top level and no `runtime:` field. `TestTemplatesList_LegacyTopLevelModel`'s comment makes the contract explicit: > Older templates (pre-runtime_config) declared `model:` at the top level. The /templates endpoint should keep surfacing those for backward compat. `TestTemplatesList_WithTemplates` also has a fixture without `runtime:` (it's a modern-shape template that happens to omit the field) — it also fails. ## Why CI on main appears green Reproduce locally on a fresh checkout (no manifest.json built): ``` cd ~/molecule-core/workspace-server go test -run '^TestTemplatesList_WithTemplates$' -count=1 ./internal/handlers/ ``` Fails with `expected 1 template, got 0`. CI passes only because CI's working tree has `manifest.json` present and the loaded allowlist admits empty runtime. That environment divergence is itself worth a separate fix — flagged in the issue's acceptance criteria. ## Fix Skip the allowlist lookup when runtime is empty. Non-empty runtimes still go through the allowlist, preserving the filter's intent (block known-invalid declared runtimes). ## SOP Checklist (RFC #351) ### 1. Comprehensive testing performed - `go test -run '^TestTemplatesList_' -count=1 ./internal/handlers/` — green (was failing 2/N tests pre-fix). - `go vet ./...` clean. - Mutation-tested: with the new `if runtime != ""` guard removed, both originally-failing tests fail again as expected. ### 2. Local-postgres E2E run N/A. Pure handler-logic change with no DDL, no DB writes. ### 3. Staging-smoke verified or pending Pending. Will verify via the `/templates` endpoint on staging post-merge that legacy templates surface AND unknown-runtime templates remain filtered. ### 4. Root-cause not symptom Yes. The symptom is "tests fail." The root cause is `a5211050` not guarding the empty-runtime backward-compat case its companion `TestTemplatesList_LegacyTopLevelModel` had been pinning since pre-runtime_config. Fix restores the contract. ### 5. Five-Axis review walked Walked solo on this one (single-line guard, well-scoped). Happy to dispatch a hostile reviewer if anyone wants it before merge. ### 6. No backwards-compat shim / dead code added Net +9 lines, -0. The added lines are a guard + explanatory comment. No shim — the guard restores the original behavior the filter accidentally regressed. ### 7. Memory/saved-feedback consulted - `feedback_per_agent_gitea_identity_default` — this PR is filed under hongming PAT because we're in CTO-bypass mode for this session; will rotate to a proper persona for the next bug-fix branch. - `reference_post_suspension_pipeline` — confirmed Gitea-only SCM context; no github.com referenced anywhere. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
hongming added 1 commit 2026-05-24 05:32:07 +00:00
fix(templates): preserve legacy-template surface for empty runtime (#1778)
ci-arm64-advisory / fast-checks (pull_request) Waiting to run
Lint shellcheck (arm64 pilot) / shellcheck-arm64 (pilot) (pull_request) Successful in 8s
Block internal-flavored paths / Block forbidden paths (pull_request) Successful in 7s
CI / Detect changes (pull_request) Successful in 15s
CI / Python Lint & Test (pull_request) Successful in 7s
E2E Chat / detect-changes (pull_request) Successful in 9s
E2E API Smoke Test / detect-changes (pull_request) Successful in 10s
Handlers Postgres Integration / detect-changes (pull_request) Successful in 5s
E2E Staging Canvas (Playwright) / detect-changes (pull_request) Successful in 7s
Harness Replays / detect-changes (pull_request) Successful in 5s
Lint no tenant GITEA or GITHUB token write / Scan for repo-host token write into tenant workspace surface (pull_request) Successful in 5s
Lint forbidden tenant-env keys / Scan workspace_secrets writers for forbidden env keys (pull_request) Successful in 6s
gate-check-v3 / gate-check (pull_request) Successful in 9s
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 9s
security-review / approved (pull_request) Failing after 7s
qa-review / approved (pull_request) Failing after 7s
sop-checklist / review-refire (pull_request) Has been skipped
sop-checklist / na-declarations (pull_request) N/A: (none)
sop-checklist / all-items-acked (pull_request) Successful in 5s
sop-tier-check / tier-check (pull_request) Successful in 5s
lint-required-no-paths / lint-required-no-paths (pull_request) Successful in 1m2s
CI / Canvas (Next.js) (pull_request) Successful in 8s
CI / Shellcheck (E2E scripts) (pull_request) Successful in 6s
E2E Chat / E2E Chat (pull_request) Successful in 18s
Harness Replays / Harness Replays (pull_request) Successful in 8s
E2E Staging Canvas (Playwright) / Canvas tabs E2E (pull_request) Successful in 4s
E2E API Smoke Test / E2E API Smoke Test (pull_request) Successful in 2m25s
Handlers Postgres Integration / Handlers Postgres Integration (pull_request) Successful in 2m38s
CI / Canvas Deploy Reminder (pull_request) Has been skipped
CI / Platform (Go) (pull_request) Successful in 5m45s
CI / all-required (pull_request) Successful in 4m49s
audit-force-merge / audit (pull_request) Successful in 6s
f01da15917
The narrow-catalog filter in a5211050 rejected templates with empty
runtime, regressing the documented backward-compat path that
TestTemplatesList_LegacyTopLevelModel pins: pre-runtime_config
templates declare model: at the top level and never set runtime.

Tests broken on origin/main and reproducible on a fresh local
checkout (manifest.json absent locally so the fallback allowlist
runs; on CI the manifest happens to admit empty runtime, masking
the regression — that env divergence is its own followup).

Fix: skip the allowlist lookup when runtime is empty. Non-empty
runtimes still go through the allowlist, preserving the filter's
intent of blocking known-invalid declared runtimes.

Closes #1778.
devops-engineer approved these changes 2026-05-24 05:34:31 +00:00
devops-engineer left a comment
Member

Approving #1781 on current HEAD f01da15917 — single-file change, scope is exactly what the issue called for, tests verified. CTO-bypass session 2026-05-24.

Approving #1781 on current HEAD f01da159174703d8dc97e44e4e34f2ea8f9482e4 — single-file change, scope is exactly what the issue called for, tests verified. CTO-bypass session 2026-05-24.
core-devops approved these changes 2026-05-24 05:34:32 +00:00
core-devops left a comment
Member

Approving #1781 on current HEAD f01da15917 — single-file change, scope is exactly what the issue called for, tests verified. CTO-bypass session 2026-05-24.

Approving #1781 on current HEAD f01da159174703d8dc97e44e4e34f2ea8f9482e4 — single-file change, scope is exactly what the issue called for, tests verified. CTO-bypass session 2026-05-24.
hongming merged commit cb59e658b2 into main 2026-05-24 06:14:18 +00:00
Sign in to join this conversation.
3 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: molecule-ai/molecule-core#1781