Kyle: "Fold them into the plan." What changed and why is in docs/P6.md §14. In short:
- FetchFunc gets the *auth.Caller (the given api test could not compile, and a fetch with no
caller would bypass per-caller gates, the pool limit, the cache class and redaction);
- store reads never bump the lease (task 01's rule contradicted its own test); the API Touches;
- 1-2 workers round-robin over live jobs, so a batch holds at most 2 of the 8 global slots;
busy targets retry in the runner (bounded); batch PDFs use their own pool name; 210 s deadline;
- the api tests no longer touch the network or race the cancel; private names via fake DNS;
- failed/cancelled jobs are not reused; GET is a summary plus GET …/{idx} and ?results=1;
- the 256 KiB body cap moves into ServeHTTP; a fixed metrics label for /v1/batch/{id};
- guard.PreCheck (given verbatim) replaces guard.ParseURL at submit;
- 5 tasks became 8 (refactor, wiring, endpoints and serve/config split), each restating the
APIs it uses; every given test compiles against a panic-only skeleton and fails on it.
P6 starts after P5c: task 04 moves v1fetch, which P5b changes. Recheck the api given tests
against post-P5c master before the run.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
3.9 KiB
3.9 KiB
P6 task 08: 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:
_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(onecase "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)readsclient.toml;searchcmd.gois 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 06):
POST /v1/batch{"targets":[…]}→202 {"success","job_id","status","targets","reused"};GET /v1/batch/{id}(summary;?results=1inlines results);GET /v1/batch/{id}/{idx}(one result);DELETE /v1/batch/{id}.
Interfaces added here
// 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
parseBatchArgsaccepts exactly the forms above:submitwith one argument (-means stdin);statuswith a job id, optionally preceded by--results;getwith a job id and anidxthat is a non-negative integer;cancelwith a job id. Anything else (no verb, a missing or extra argument, an unknown verb, a badidx) is an error.restis the arguments after the verb, unchanged.
submitreads the file and checks it locally before calling the server: it must be a JSON object with a non-emptytargetsarray. It may also be a bare array of targets or of URL strings; wrap either into{"targets": […]}, turning each string into{"url": s}.- 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), asfetchdoes. 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.
skill/SKILL.md, a short section:- for several URLs you will read later,
sift batch submitthem once, rather than a loop ofsift fetch; - poll with
sift batch status, and read each result withsift batch get <job> <idx>; - don't use
--resultsunless 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.
- for several URLs you will read later,
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/08-cli-docs; commit.
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 gateok; the given file is byte-identical.