feat(builder): launch options must appear in the research sources
Validate game templates / validate (push) Successful in 19s
Validate game templates / boot-test (push) Skipped
Validate game templates / publish (push) Skipped

The Valheim draft in #13 passed -maxplayers, an option Valheim doesn't have.
The server ignores unknown options, so the draft booted and passed every
boot test while its MaxPlayers setting did nothing.

build now reads the pages research based the variant on, in full, and the
drafter rejects any launch option in the startup command that none of them,
nor the image's own scripts, mention. The model gets it back to remove or
spell correctly. Options of shell tools (mkdir -p, [ -n ...]) are skipped.
The check is off when there are no sources (draft run by hand, no reader).

Against #13's 11 real sources it flags -maxplayers and nothing else.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
gregandClaude Opus 5.5 committed 2026-10-25 17:47:33 -04:00
1 parent dd92b6be4c
commit 8b49895d5e
6 files changed
+158 -3

No files matched your search

+44
View File
@@ -105,3 +105,47 @@ func TestPortSettings(t *testing.T) {
t.Errorf("got %v", p)
}
}
func TestUndocumentedOptionsCatchesMaxPlayers(t *testing.T) {
// PR #13's startup: every option is in Valheim's docs except -maxplayers
game := map[string]any{"defaultStartupCommand": `args=(-name "${SERVER_NAME:-GBRHosting - Valheim}" -port 2456 -world "${WORLD_NAME:-Dedicated}" -savedir /server); ` +
`[ -n "${SERVER_PASSWORD}" ] && args+=(-password "${SERVER_PASSWORD}"); [ "${CROSSPLAY}" = "true" ] && args+=(-crossplay); ` +
`[ -n "${MAX_PLAYERS}" ] && args+=(-maxplayers "${MAX_PLAYERS}"); ./valheim_server.x86_64 "${args[@]}"`}
docs := "Launch with `-name`, `-port`, `-world`, `-password`, `-savedir <path>` and `-crossplay` to allow consoles."
got := undocumentedOptions(game, docs, nil)
if len(got) != 1 || !strings.Contains(got[0], "passes -maxplayers,") {
t.Fatalf("want only -maxplayers flagged, got %v", got)
}
// Once removed, nothing is left to flag
game["defaultStartupCommand"] = strings.Replace(game["defaultStartupCommand"].(string), `[ -n "${MAX_PLAYERS}" ] && args+=(-maxplayers "${MAX_PLAYERS}"); `, "", 1)
if got := undocumentedOptions(game, docs, nil); len(got) != 0 {
t.Errorf("got %v", got)
}
}
func TestUndocumentedOptionsIgnoresShellAndUsesImageScripts(t *testing.T) {
game := map[string]any{"defaultStartupCommand": `mkdir -p /server/.config; cp -f /a /b; [ -n "$X" ] && [ "$Y" -eq 1 ] && ` +
`exec ./server --listen-port=7777 -ServerPlatform=ALL -logs`}
facts := &imageFacts{Scripts: map[string]string{"/start.sh": `exec "$@" -logs`}}
got := strings.Join(undocumentedOptions(game, "Use --listen-port and -ServerPlatform=ALL for crossplay.", facts), "\n")
if got != "" {
t.Errorf("shell options, documented ones and ones the image's script uses must pass, got %q", got)
}
// Without sources the check is off (draft run by hand, or no reader configured)
game["defaultStartupCommand"] = "./server -madeup"
if p := undocumentedOptions(game, "", nil); p != nil {
t.Errorf("got %v", p)
}
if p := undocumentedOptions(game, "unrelated page", nil); len(p) != 1 {
t.Errorf("want -madeup flagged, got %v", p)
}
}
func TestUndocumentedOptionsWholeWords(t *testing.T) {
// "-port" in the docs doesn't document "-portal", and "-port" isn't documented by "-portal"
game := map[string]any{"defaultStartupCommand": "./server -port 1 -portal x"}
got := strings.Join(undocumentedOptions(game, "options: -port", nil), "")
if !strings.Contains(got, "passes -portal,") || strings.Contains(got, "-port,") {
t.Errorf("got %q", got)
}
}