* fix(#1747): register four search-provider keys in the config schema buildNewProjectConfig emits seven search-provider availability flags and research-provider.cts providerAvailability() consumes all seven, but only three were registered in VALID_CONFIG_KEYS (config-schema.manifest.json). config-loader.cts then printed an 'unknown config key(s)' warning for the four unregistered keys (tavily_search, ref_search, perplexity, jina) on every freshly generated .planning/config.json. Register the four missing keys in the schema manifest and document them alongside brave/exa/firecrawl in CONFIGURATION.md. Add a regression test plus a structural drift guard that requires every config-driven research-provider flag to be in VALID_CONFIG_KEYS, so a future provider addition cannot silently reintroduce the drift. * fix(#1747): move regression into owning test file + add changeset lint-regression-test-names rejects new bug-NNNN-*.test.cjs files; move the #1747 regression (four provider keys in VALID_CONFIG_KEYS + provider-flag drift guard) into tests/bug-2530-valid-config-keys.test.cjs, the canonical home for VALID_CONFIG_KEYS regressions, and delete the standalone file. Add the missing .changeset fragment — config-schema.manifest.json lives under gsd-core/ (user-facing), so changeset-lint requires a fragment. * test(#1747): regenerate golden-install-parity fixtures for schema change Adding four provider keys to config-schema.manifest.json shifts its shipped content hash (65dea848 -> 7d398e94); recapture all 16 runtime fixtures via UPDATE_GOLDEN=1. Each fixture changes exactly one line — the manifest hash.
164 lines
7.3 KiB
JavaScript
164 lines
7.3 KiB
JavaScript
'use strict';
|
|
|
|
/**
|
|
* Regression tests for config key bugs:
|
|
* #2530 — workflow._auto_chain_active is internal state, must not be in VALID_CONFIG_KEYS
|
|
* #2531 — hooks.workflow_guard is used by hook and documented but missing from VALID_CONFIG_KEYS
|
|
* #2532 — workflow.ui_review is used in autonomous.md but missing from config validation
|
|
* #2533 — workflow.max_discuss_passes is used in discuss-phase.md but missing from VALID_CONFIG_KEYS
|
|
* #2535 — sub_repos and plan_checker legacy keys need CONFIG_KEY_SUGGESTIONS migration hints
|
|
* #3162 — resolve_model_ids missing from VALID_CONFIG_KEYS; workflow._auto_chain_active must be
|
|
* accepted by isValidConfigKey (written by workflows) without being user-visible
|
|
* #1747 — buildNewProjectConfig emits four search-provider keys (tavily_search, ref_search,
|
|
* perplexity, jina) that research-provider.cts consumes but were missing from
|
|
* VALID_CONFIG_KEYS, causing /gsd-settings unknown-key warnings on fresh projects
|
|
*/
|
|
|
|
const { describe, test } = require('node:test');
|
|
const assert = require('node:assert/strict');
|
|
const { createTempProject, cleanup, runGsdTools } = require('./helpers.cjs');
|
|
|
|
const {
|
|
VALID_CONFIG_KEYS,
|
|
isCentralConfigKey,
|
|
isValidConfigKey,
|
|
} = require('../gsd-core/bin/lib/config-schema.cjs');
|
|
|
|
const capabilityRegistry = require('../gsd-core/bin/lib/capability-registry.cjs');
|
|
|
|
describe('VALID_CONFIG_KEYS correctness', () => {
|
|
test('#2530: workflow._auto_chain_active must not be in VALID_CONFIG_KEYS (internal state)', () => {
|
|
assert.ok(
|
|
!VALID_CONFIG_KEYS.has('workflow._auto_chain_active'),
|
|
'workflow._auto_chain_active is internal runtime state and must not be user-settable'
|
|
);
|
|
});
|
|
|
|
test('#2531: hooks.workflow_guard must be in VALID_CONFIG_KEYS (used by hook, documented)', () => {
|
|
assert.ok(
|
|
VALID_CONFIG_KEYS.has('hooks.workflow_guard'),
|
|
'hooks.workflow_guard is read by gsd-workflow-guard.js hook and documented in CONFIGURATION.md'
|
|
);
|
|
});
|
|
|
|
test('#2532: workflow.ui_review must remain valid but is no longer centrally owned', () => {
|
|
assert.strictEqual(
|
|
isValidConfigKey('workflow.ui_review'),
|
|
true,
|
|
'workflow.ui_review is still user-facing config and must validate'
|
|
);
|
|
assert.strictEqual(
|
|
isCentralConfigKey('workflow.ui_review'),
|
|
false,
|
|
'workflow.ui_review is owned by the UI capability after ADR-857 Phase 6 cutover'
|
|
);
|
|
});
|
|
|
|
test('#2533: workflow.max_discuss_passes must be in VALID_CONFIG_KEYS (used in discuss-phase.md)', () => {
|
|
assert.ok(
|
|
VALID_CONFIG_KEYS.has('workflow.max_discuss_passes'),
|
|
'workflow.max_discuss_passes is read in discuss-phase.md via gsd-sdk query config-get'
|
|
);
|
|
});
|
|
|
|
test('#3162: resolve_model_ids must be in VALID_CONFIG_KEYS (documented user-facing key)', () => {
|
|
assert.ok(
|
|
VALID_CONFIG_KEYS.has('resolve_model_ids'),
|
|
'resolve_model_ids is documented in CONFIGURATION.md and read by core.cjs/session-runner.ts'
|
|
);
|
|
});
|
|
|
|
test('#3162: workflow._auto_chain_active must be accepted by isValidConfigKey (written by workflows)', () => {
|
|
assert.strictEqual(
|
|
isValidConfigKey('workflow._auto_chain_active'),
|
|
true,
|
|
'workflow._auto_chain_active is written by plan-phase, execute-phase, discuss-phase, transition workflows via config-set'
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('#1747: new-project config emits only schema-recognized provider keys', () => {
|
|
// buildNewProjectConfig emits seven search-provider availability flags and
|
|
// research-provider.cts providerAvailability() consumes all seven, but only
|
|
// three were in VALID_CONFIG_KEYS → /gsd-settings warned on the four
|
|
// unregistered keys (tavily_search, ref_search, perplexity, jina) for every
|
|
// freshly generated .planning/config.json.
|
|
|
|
// The four keys that were emitted + consumed but missing from the schema.
|
|
const MISSING_KEYS = ['tavily_search', 'ref_search', 'perplexity', 'jina'];
|
|
|
|
// Every config-driven provider flag read by providerAvailability() in
|
|
// src/research-provider.cts. context7/websearch are excluded: hardcoded
|
|
// `true`, not config-gated, so no config key to register.
|
|
const PROVIDER_CONFIG_KEYS = [
|
|
'brave_search',
|
|
'firecrawl',
|
|
'exa_search',
|
|
'tavily_search',
|
|
'ref_search',
|
|
'perplexity',
|
|
'jina',
|
|
];
|
|
|
|
test('the four previously-missing provider keys are in VALID_CONFIG_KEYS', () => {
|
|
const absent = MISSING_KEYS.filter((k) => !VALID_CONFIG_KEYS.has(k));
|
|
assert.deepStrictEqual(
|
|
absent,
|
|
[],
|
|
`These provider keys are emitted by buildNewProjectConfig and consumed by research-provider.cts but missing from VALID_CONFIG_KEYS:\n ${absent.join('\n ')}\n\nAdd them to gsd-core/bin/shared/config-schema.manifest.json (validKeys).`
|
|
);
|
|
});
|
|
|
|
test('every config-driven research-provider flag is registered in the schema (drift guard)', () => {
|
|
const drifted = PROVIDER_CONFIG_KEYS.filter((k) => !VALID_CONFIG_KEYS.has(k));
|
|
assert.deepStrictEqual(
|
|
drifted,
|
|
[],
|
|
`These research-provider config flags are not in VALID_CONFIG_KEYS — a fresh /gsd-new-project config would trigger an unknown-key warning under /gsd-settings:\n ${drifted.join('\n ')}\n\nWhen you add a provider to providerAvailability() in src/research-provider.cts, also register its config key in gsd-core/bin/shared/config-schema.manifest.json.`
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('ADR-857 Phase 6 capability config ownership', () => {
|
|
test('migrated capability config keys are valid through the registry, not central schema residue', () => {
|
|
const capabilityKeys = Object.keys(capabilityRegistry.configSchema || {}).sort();
|
|
assert.ok(capabilityKeys.length > 0, 'expected generated registry config schema keys');
|
|
|
|
for (const key of capabilityKeys) {
|
|
assert.strictEqual(isValidConfigKey(key), true, `${key} must remain accepted by config validation`);
|
|
assert.strictEqual(isCentralConfigKey(key), false, `${key} must be capability-owned, not central`);
|
|
assert.strictEqual(VALID_CONFIG_KEYS.has(key), false, `${key} must not remain in central VALID_CONFIG_KEYS`);
|
|
}
|
|
});
|
|
});
|
|
|
|
describe('CONFIG_KEY_SUGGESTIONS migration hints (#2535)', () => {
|
|
let tmpDir;
|
|
|
|
test('config-set sub_repos emits "Did you mean planning.sub_repos?" suggestion', (t) => {
|
|
tmpDir = createTempProject();
|
|
t.after(() => cleanup(tmpDir));
|
|
|
|
const result = runGsdTools(['config-set', 'sub_repos', '[]'], tmpDir);
|
|
assert.ok(!result.success, 'config-set sub_repos should fail');
|
|
const combined = result.error + result.output;
|
|
assert.ok(
|
|
combined.includes('Did you mean') && combined.includes('planning.sub_repos'),
|
|
`Expected "Did you mean planning.sub_repos?" in error, got:\nstdout: ${result.output}\nstderr: ${result.error}`
|
|
);
|
|
});
|
|
|
|
test('config-set plan_checker emits "Did you mean workflow.plan_check?" suggestion', (t) => {
|
|
tmpDir = createTempProject();
|
|
t.after(() => cleanup(tmpDir));
|
|
|
|
const result = runGsdTools(['config-set', 'plan_checker', 'true'], tmpDir);
|
|
assert.ok(!result.success, 'config-set plan_checker should fail');
|
|
const combined = result.error + result.output;
|
|
assert.ok(
|
|
combined.includes('Did you mean') && combined.includes('workflow.plan_check'),
|
|
`Expected "Did you mean workflow.plan_check?" in error, got:\nstdout: ${result.output}\nstderr: ${result.error}`
|
|
);
|
|
});
|
|
});
|