diff --git a/CHANGELOG.md b/CHANGELOG.md index 00e0a471..0fb12aae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,9 @@ Each release of Research-Kit, newest first. The version is `KIT_VERSION` in ## Unreleased +- `collect-remote` refuses empty repository, topic, client-ref, prior and prefer + values by name before creating an output directory or reading a token (#287). + - ZIP archives declare UTF-8 names in both headers, so ordinary extractors preserve non-ASCII paths declared by the package manifest (#345). - Machine config saves preserve unpatched raw role and posture values, including typos diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index a35be350..2c001830 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -64,6 +64,12 @@ about defects that were already fixed. Nothing was deleted; it was moved and lin ## Search and collection invocation +`bin/collect-remote.mjs` applies the existing value checker to `--repository`, `--topic`, +`--client-ref`, `--prior` and `--prefer`, as well as its workflow and budget flags. +An empty equals/separate value or bare optional value flag is refused by name with +exit 3 before output-directory creation, token lookup or dispatch (#287). Absent +required flags keep their existing refusal, including the repository-only pickup path. + The CLI chooses providers before invoking its coordinator. `transport.mjs` returns the fetch adapter, search adapter or merged adapters, selection reasons, and selection readiness metadata. Automatic fetch selection may perform a memoized Firecrawl CLI `--status` probe when the executable is present. Selection does not search or fetch a page. The coordinators decide which queries and pages to attempt; the shared search session and collection writer carry out those decisions. ```mermaid diff --git a/research-kit/README.md b/research-kit/README.md index c06356d9..466832c7 100644 --- a/research-kit/README.md +++ b/research-kit/README.md @@ -568,7 +568,7 @@ node research-kit/bin/selftest.mjs # all of it node research-kit/bin/selftest.mjs gate hook # just these files ``` -1845 tests, offline, no key and no network. The runner **awaits** every test, so `ok` means +1846 tests, offline, no key and no network. The runner **awaits** every test, so `ok` means the assertions settled (ADR-0021), and each test is raced against a watchdog (`RESEARCH_KIT_TEST_TIMEOUT`, default 60s). diff --git a/research-kit/bin/collect-remote.mjs b/research-kit/bin/collect-remote.mjs index d0166a30..b1884b6c 100644 --- a/research-kit/bin/collect-remote.mjs +++ b/research-kit/bin/collect-remote.mjs @@ -150,12 +150,9 @@ checkFlagValues(flags, { 'search-transport': { choices: ['auto', 'serpapi', 'firecrawl-cli'] }, timeout: { int: true, min: 1 }, out: {}, workflow: {}, ref: {}, + repository: {}, topic: {}, 'client-ref': {}, prior: {}, prefer: {}, }, { exit: EXIT.CANNOT_START }); -if (flags['client-ref'] === true) { - process.stderr.write('--client-ref needs a value\n'); - process.exit(EXIT.CANNOT_START); -} const clientReference = checkClientRef(flags['client-ref']); if (!clientReference.ok) { process.stderr.write(`${redact(clientReference.detail)}\n`); diff --git a/research-kit/test/cli.test.mjs b/research-kit/test/cli.test.mjs index 3f6c7a1d..d0fc75e4 100644 --- a/research-kit/test/cli.test.mjs +++ b/research-kit/test/cli.test.mjs @@ -33,7 +33,7 @@ test('collect-remote refuses unsafe client references before token lookup or cre const bare = run('collect-remote.mjs', ['--repository', 'o/r', '--topic', 't', '--client-ref'], { root }); assert.equal(bare.status, 3); assert.match(bare.err, /--client-ref needs a value/); - for (const clientRef of ['', 'job-1.a_b', 'a'.repeat(64)]) { + for (const clientRef of ['job-1.a_b', 'a'.repeat(64)]) { const r = run('collect-remote.mjs', ['--repository', 'o/r', '--topic', 't', '--client-ref', clientRef, '--no-wait'], { root }); assert.equal(r.status, 3); assert.match(r.err, /no GitHub token/, 'valid input must reach the existing missing-token refusal'); @@ -841,6 +841,24 @@ test('collect-remote refuses a bare --out, --workflow or --ref before it creates } }); +test('collect-remote refuses empty required and optional values before token lookup or creating out', () => { + for (const flag of ['repository', 'topic', 'client-ref', 'prior', 'prefer']) { + const required = flag === 'repository' ? ['--topic', 't'] + : flag === 'topic' ? ['--repository', 'o/r'] : ['--repository', 'o/r', '--topic', 't']; + const spellings = [[`--${flag}=`], [`--${flag}`, '']]; + if (!['repository', 'topic'].includes(flag)) spellings.push([`--${flag}`]); + for (const spelling of spellings) { + const root = project(); + const out = path.join(root, 'not-created'); + const r = run('collect-remote.mjs', [...required, '--out', out, ...spelling], { root }); + assert.equal(r.status, 3, r.all); + assert.equal(r.err.split('\n')[0], `--${flag} needs a value`, r.all); + assert.doesNotMatch(r.all, /no GitHub token/); + assert.equal(fs.existsSync(out), false, 'invalid flags must not create the output directory'); + } + } +}); + // Found 2026-10-01: lib/dispatch.mjs told the caller to "retry with --run-id ", exit 4 said // "the run id is on stdout", and collect-remote had no --run-id - it refused it as an unknown // option. A watch that ended (a timeout, a dropped connection, a closed laptop) could not be