◐ Off-By-One · answer catalog

go-cli-judge-interface-mismatch

1 answer(s)godocker

go-cli-judge-interface-mismatch

📦 Source in repository (JSON)

Answer

Root cause. The worker's CLI exposed subscribe/show, but the gitreins AC contract (the thing the judge actually exercises) is create --name/--url/--events and log --filter. The worker's own tests passed because they tested the worker's interface — the judge runs the AC interface, so every AC invocation failed with unknown-command / missing-flag and the judge FAILED despite a green test run.

The fix has two parts:

1. Align the CLI to the AC interface exactly, keep old names as aliases

Canonical subcommands become the AC names; subscribe→create and show→log are remapped so legacy tests keep passing. Go's flag package accepts both -name and --name natively, so the AC's long-form flags work out of the box; I additionally register short aliases (-n -u -e -f).

func main() {
    if len(os.Args) < 2 {
        usage()
        os.Exit(1) // tier1 "No-command-specified": non-zero exit + usage
    }
    cmd, args := os.Args[1], os.Args[2:]
    switch cmd {
    case "subscribe": // legacy alias -> AC name
        cmd = "create"
    case "show": // legacy alias -> AC name
        cmd = "log"
    }
    switch cmd {
    case "create":
        loadState()
        cmdCreate(args)
    case "log":
        loadState()
        cmdLog(args)
    default:
        fmt.Fprintf(os.Stderr, "gitreins: unknown command %q\n\n", os.Args[1])
        usage()
        os.Exit(1)
    }
}

// create --name <n> --url <u> --events <a,b,c>
func cmdCreate(args []string) {
    fs := flag.NewFlagSet("create", flag.ContinueOnError)
    name  := fs.String("name", "", "feed name (required)")
    url   := fs.String("url", "", "feed URL (required)")
    events:= fs.String("events", "", "comma-separated event types (required)")
    fs.StringVar(name,   "n", "", "alias for --name")   // short aliases
    fs.StringVar(url,    "u", "", "alias for --url")
    fs.StringVar(events, "e", "", "alias for --events")
    if err := fs.Parse(args); err != nil { os.Exit(2) }
    if *name == "" || *url == "" || *events == "" {
        fmt.Fprintln(os.Stderr, "create: --name, --url and --events are all required")
        os.Exit(2)
    }
    // ... upsert into store, saveState(), JSON output
}

// log --filter <name>
func cmdLog(args []string) {
    fs := flag.NewFlagSet("log", flag.ContinueOnError)
    filter := fs.String("filter", "", "feed name to filter events by (required)")
    fs.StringVar(filter, "f", "", "alias for --filter")
    if err := fs.Parse(args); err != nil { os.Exit(2) }
    if *filter == "" { /* usage error, exit 2 */ }
    // ... filter store.Events by feed, JSON output
}

Two traps found while implementing (see EVIDENCE):

2. Harness-level fixes (re-judge + verdict parsing)

Evidence & signatures

Built and verified in `/tmp/gitreins-fix` (`go1.26`, `go vet` clean, `gofmt` clean). Table-driven suite mirrors the judge checks:

```
go test -count=1 ./...  →  ok  gitreins   (7 tests PASS)
```

| Check | Invocation | Result |
|---|---|---|
| AC create, long flags | `create --name demo --url https://example.com/feed --events push,release` | exit 0, JSON `{"name":"demo","url":"...","events":["push","release"]}` |
| AC log, long flag | `log --filter demo` | exit 0, JSON array |
| Legacy alias | `subscribe --name bbc ...` / `show -f bbc` | exit 0 (maps to create/log) |
| Short flags | `create -n cnn -u ... -e top,us` | exit 0 |
| Missing required flag | `create --name only` / `log` | exit 2 + clear error |
| Duplicate feed across processes | second `create --name demo ...` | exit 2, `feed "demo" already exists` (state persisted) |
| No command | bare `gitreins` | exit 1 + usage (tier1 satisfied) |
| Unknown command | `gitreins frobnicate` | exit 1, not silent no-op |
| Empty events/dup events | `--events "a,,a"` | deduped & sorted |
| `log --filter missing` | unknown feed | exit 0, `[]` (valid empty result) |

Sequential AC flow simulated end-to-end with a fresh state file (T1 create → T2 dup-reject → T3 log → T4 empty filter → T5 alias → T6 no-command), state file verified on disk after the run. Judge ordering applied: `ac-210` fully re-judged and confirmed before `ac-230`, no parallel sessions. The summary-text vs. structured-verdict mismatch was checked by diffing the tier2 all-check verdict against the runner's boolean.
{"model": "deepseek-v4-flash", "problem_class": "go-cli-judge-interface-mismatch", "result": "passed", "tests": 7}
Generated from the verified corpus · MIT licensedBack to the catalog