P6 during the run: split the runner task (02 core, 03 workers); guard.PreCheck as an owner commit; AGENTS.md: write code into files early
Task 02 (the whole runner) ended at 21:08 with no file and no commit: Ornith wrote the
implementation out in its reply (~700 lines), OpenCode compacted the session, and the model
then emitted a malformed tool call. It had also looked for the given test at a wrong path
("_files/…" relative to the plan: my ambiguity).
- 02-runner → 02-runner-core (types, Submit, Status, Touch, Cancel; no goroutines) and
03-runner-workers; the given test split to match (runner_core_test.go gains three tests:
queued storage, cancel while queued, Status never moves the lease); later tasks renumbered
04-09 and every cross-reference checked.
- Copy paths spelled from the repo root.
- guard.PreCheck (+ its test) is committed here by the owner: the old task 05 told the
implementer to edit internal/guard/, which AGENTS.md forbids. My contradiction.
- AGENTS.md rule 6: write code into files early, in small steps.
Both runner test files compile against a panic-only skeleton (the core file also alone) and
fail there on panic: todo.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
# P6 task 09: `sift batch`, README and skill
|
||||
|
||||
**Branch:** `p6` (`git switch p6`; `git status --short` must be empty, otherwise stop)
|
||||
**Commit subject:** `cli: sift batch submit|status|get|cancel; README and skill`
|
||||
|
||||
## Goal
|
||||
|
||||
Agents reach the batch endpoint through the CLI, as they do `fetch` and `search`. There is no
|
||||
Hermes plugin.
|
||||
|
||||
## Files
|
||||
|
||||
- Copy: `docs/plans/p6/_files/cmd_sift/batch_test.go` → `cmd/sift/batch_test.go`
|
||||
- Create: `cmd/sift/batchcmd.go` (`batchMain`, `parseBatchArgs`, one small function per verb)
|
||||
- Modify: `cmd/sift/main.go` (one `case "batch":` line and the usage text), `README.md`,
|
||||
`skill/SKILL.md`, `docs/implementer-log.md`
|
||||
|
||||
## What already exists
|
||||
|
||||
- `cmd/sift`: `loadClient() (base, key string, err error)` reads `client.toml`; `searchcmd.go` is the
|
||||
pattern for a verb (build the request with the bearer header, decode the JSON envelope, exit
|
||||
non-zero on a non-2xx). Never put a key on the command line.
|
||||
- The endpoints (task 07):
|
||||
- `POST /v1/batch` `{"targets":[…]}` → `202 {"success","job_id","status","targets","reused"}`;
|
||||
- `GET /v1/batch/{id}` (summary; `?results=1` inlines results);
|
||||
- `GET /v1/batch/{id}/{idx}` (one result);
|
||||
- `DELETE /v1/batch/{id}`.
|
||||
|
||||
## Interfaces added here
|
||||
|
||||
```go
|
||||
// parseBatchArgs validates a `sift batch` command line (without "batch").
|
||||
func parseBatchArgs(args []string) (verb string, rest []string, err error)
|
||||
```
|
||||
|
||||
```
|
||||
sift batch submit <targets.json|-> # prints {"job_id", "status", "reused"}
|
||||
sift batch status [--results] <job_id> # prints the status body (a summary unless --results)
|
||||
sift batch get <job_id> <idx> # prints one target's result, as `sift fetch --json` would
|
||||
sift batch cancel <job_id> # prints {"success", "status"}
|
||||
```
|
||||
|
||||
## Rules
|
||||
|
||||
1. `parseBatchArgs` accepts exactly the forms above:
|
||||
- `submit` with one argument (`-` means stdin);
|
||||
- `status` with a job id, optionally preceded by `--results`;
|
||||
- `get` with a job id and an `idx` that is a non-negative integer;
|
||||
- `cancel` with a job id.
|
||||
Anything else (no verb, a missing or extra argument, an unknown verb, a bad `idx`) is an
|
||||
error. `rest` is the arguments after the verb, unchanged.
|
||||
2. `submit` reads the file and checks it locally before calling the server: it must be a JSON
|
||||
object with a non-empty `targets` array. It may also be a bare array of targets or of URL
|
||||
strings; wrap either into `{"targets": […]}`, turning each string into `{"url": s}`.
|
||||
3. Every verb prints the server's JSON on stdout, and on a non-2xx prints the error envelope to
|
||||
stderr and exits with `exitFor(status, msg)`, as `fetch` does.
|
||||
4. **`README.md`**, a short "Batch" section:
|
||||
- the four endpoints;
|
||||
- the model: serial per job, one worker by default, round-robin across jobs;
|
||||
- the caps (32 targets, 1 live job per caller, 8 in all) and the 256 KiB body;
|
||||
- idempotency: the same list from the same caller returns the same job while it is live or
|
||||
has results;
|
||||
- the lease/TTL and restart semantics;
|
||||
- the summary-vs-results reads;
|
||||
- restricted-caller redaction;
|
||||
- the `sift_batch_*` metrics.
|
||||
5. **`skill/SKILL.md`**, a short section:
|
||||
- for several URLs you will read later, `sift batch submit` them once, rather than a loop of
|
||||
`sift fetch`;
|
||||
- poll with `sift batch status`, and read each result with `sift batch get <job> <idx>`;
|
||||
- don't use `--results` unless you need every result at once (it can be large);
|
||||
- a batch is slow on purpose: for one URL you need now, use `sift fetch`.
|
||||
|
||||
## Steps
|
||||
|
||||
- [ ] **1.** `git switch p6`; copy the given test. **2. See it fail.**
|
||||
- [ ] **3.** `batchcmd.go`. **4.** `main.go`. **5.** README and skill.
|
||||
- [ ] **6.** `gofmt -w`; `go test -race -count=3 ./cmd/sift/` → `ok`. **7.** `make gate`.
|
||||
- [ ] **8.** Row `p6/09-cli-docs`; commit.
|
||||
|
||||
```sh
|
||||
git add cmd/sift README.md skill/SKILL.md docs/implementer-log.md
|
||||
git commit -F .state/commit-msg.txt
|
||||
```
|
||||
|
||||
## Done when
|
||||
|
||||
- The given test and every existing cmd test pass under `-race -count=3`; `make gate` ok; the
|
||||
given file is byte-identical.
|
||||
Reference in New Issue
Block a user