Files
msd-core/tests/bug-2530-valid-config-keys.test.cjs
Tom Boucher 607813f5d0 feat(#1136): consume resolved capability state (#1153)
* feat(#1136): consume resolved capability state

* chore(#1136): add capability state changeset
2026-06-12 23:43:07 -04:00

119 lines
5.0 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
*/
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('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}`
);
});
});