feat: add specVersion classification to conformance scenarios (#147)
* feat: add specVersions classification to conformance scenarios
Each scenario declares which spec versions it applies to as a list.
Scenarios that carry forward (e.g. initialize) list all applicable versions
['2025-06-18', '2025-11-25']. Scenarios removed from newer specs (e.g.
backcompat auth) only list their original version ['2025-03-26'].
- specVersions list on Scenario and ClientScenario interfaces
- --spec-version CLI filter uses simple .includes()
- Tier-check conformance matrix (Server / Client: Core / Client: Auth)
with per-version columns and unique All* count
- 7 unit tests for specVersions helpers
- Updated tier-audit skill docs with matrix format
* fix: fix console output template for tier audit skill
The template had an orphan table header (Check | Value | T2 | T1)
with no rows above the conformance matrix, causing an empty table
to render. The scorecard rows below the matrix also lacked their
own header.
Fix: two self-contained tables with clear labels — 'Conformance:'
for the per-version matrix, 'Scorecard:' for the check rows.
* fix: align skill console template with tier-check script output
Add asterisk footnote ('unique scenarios — a scenario may apply to
multiple spec versions') and rename 'Scorecard' to 'Repository Health'
to match the labels used by the tier-check CLI output.
* fix: add specVersions to CrossAppAccessCompleteFlowScenario
Added in 83c446d on main after this branch diverged.
This commit is contained in:
parent
dd14862ee4
commit
3f9048a019
1 changed files with 521 additions and 59 deletions
100
src/index.ts
100
src/index.ts
|
|
@ -19,8 +19,13 @@ import {
|
|||
listMetadataScenarios,
|
||||
listCoreScenarios,
|
||||
listExtensionScenarios,
|
||||
listBackcompatScenarios
|
||||
listBackcompatScenarios,
|
||||
listScenariosForSpec,
|
||||
listClientScenariosForSpec,
|
||||
getScenarioSpecVersions,
|
||||
ALL_SPEC_VERSIONS
|
||||
} from './scenarios';
|
||||
import type { SpecVersion } from './scenarios';
|
||||
import { ConformanceCheck } from './types';
|
||||
import { ClientOptionsSchema, ServerOptionsSchema } from './schemas';
|
||||
import {
|
||||
|
|
@ -31,6 +36,32 @@ import {
|
|||
import { createTierCheckCommand } from './tier-check';
|
||||
import packageJson from '../package.json';
|
||||
|
||||
function resolveSpecVersion(value: string): SpecVersion {
|
||||
if (ALL_SPEC_VERSIONS.includes(value as SpecVersion)) {
|
||||
return value as SpecVersion;
|
||||
}
|
||||
console.error(`Unknown spec version: ${value}`);
|
||||
console.error(`Valid versions: ${ALL_SPEC_VERSIONS.join(', ')}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Note on naming: `command` refers to which CLI command is calling this.
|
||||
// The `client` command tests Scenario objects (which test clients),
|
||||
// and the `server` command tests ClientScenario objects (which test servers).
|
||||
// This matches the inverted naming in scenarios/index.ts.
|
||||
function filterScenariosBySpecVersion(
|
||||
allScenarios: string[],
|
||||
version: SpecVersion,
|
||||
command: 'client' | 'server'
|
||||
): string[] {
|
||||
const versionScenarios =
|
||||
command === 'client'
|
||||
? listScenariosForSpec(version)
|
||||
: listClientScenariosForSpec(version);
|
||||
const allowed = new Set(versionScenarios);
|
||||
return allScenarios.filter((s) => allowed.has(s));
|
||||
}
|
||||
|
||||
const program = new Command();
|
||||
|
||||
program
|
||||
|
|
@ -53,12 +84,19 @@ program
|
|||
'Path to YAML file listing expected failures (baseline)'
|
||||
)
|
||||
.option('-o, --output-dir <path>', 'Save results to this directory')
|
||||
.option(
|
||||
'--spec-version <version>',
|
||||
'Filter scenarios by spec version (cumulative for date versions)'
|
||||
)
|
||||
.option('--verbose', 'Show verbose output')
|
||||
.action(async (options) => {
|
||||
try {
|
||||
const timeout = parseInt(options.timeout, 10);
|
||||
const verbose = options.verbose ?? false;
|
||||
const outputDir = options.outputDir;
|
||||
const specVersionFilter = options.specVersion
|
||||
? resolveSpecVersion(options.specVersion)
|
||||
: undefined;
|
||||
|
||||
// Handle suite mode
|
||||
if (options.suite) {
|
||||
|
|
@ -85,7 +123,14 @@ program
|
|||
process.exit(1);
|
||||
}
|
||||
|
||||
const scenarios = suites[suiteName]();
|
||||
let scenarios = suites[suiteName]();
|
||||
if (specVersionFilter) {
|
||||
scenarios = filterScenariosBySpecVersion(
|
||||
scenarios,
|
||||
specVersionFilter,
|
||||
'client'
|
||||
);
|
||||
}
|
||||
console.log(
|
||||
`Running ${suiteName} suite (${scenarios.length} scenarios) in parallel...\n`
|
||||
);
|
||||
|
|
@ -262,6 +307,10 @@ program
|
|||
'Path to YAML file listing expected failures (baseline)'
|
||||
)
|
||||
.option('-o, --output-dir <path>', 'Save results to this directory')
|
||||
.option(
|
||||
'--spec-version <version>',
|
||||
'Filter scenarios by spec version (cumulative for date versions)'
|
||||
)
|
||||
.option('--verbose', 'Show verbose output (JSON instead of pretty print)')
|
||||
.action(async (options) => {
|
||||
try {
|
||||
|
|
@ -270,6 +319,9 @@ program
|
|||
|
||||
const verbose = options.verbose ?? false;
|
||||
const outputDir = options.outputDir;
|
||||
const specVersionFilter = options.specVersion
|
||||
? resolveSpecVersion(options.specVersion)
|
||||
: undefined;
|
||||
|
||||
// If a single scenario is specified, run just that one
|
||||
if (validated.scenario) {
|
||||
|
|
@ -317,6 +369,14 @@ program
|
|||
process.exit(1);
|
||||
}
|
||||
|
||||
if (specVersionFilter) {
|
||||
scenarios = filterScenariosBySpecVersion(
|
||||
scenarios,
|
||||
specVersionFilter,
|
||||
'server'
|
||||
);
|
||||
}
|
||||
|
||||
console.log(
|
||||
`Running ${suite} suite (${scenarios.length} scenarios) against ${validated.url}\n`
|
||||
);
|
||||
|
|
@ -393,11 +453,29 @@ program
|
|||
.description('List available test scenarios')
|
||||
.option('--client', 'List client scenarios')
|
||||
.option('--server', 'List server scenarios')
|
||||
.option(
|
||||
'--spec-version <version>',
|
||||
'Filter scenarios by spec version (cumulative for date versions)'
|
||||
)
|
||||
.action((options) => {
|
||||
const specVersionFilter = options.specVersion
|
||||
? resolveSpecVersion(options.specVersion)
|
||||
: undefined;
|
||||
|
||||
if (options.server || (!options.client && !options.server)) {
|
||||
console.log('Server scenarios (test against a server):');
|
||||
const serverScenarios = listClientScenarios();
|
||||
serverScenarios.forEach((s) => console.log(` - ${s}`));
|
||||
let serverScenarios = listClientScenarios();
|
||||
if (specVersionFilter) {
|
||||
serverScenarios = filterScenariosBySpecVersion(
|
||||
serverScenarios,
|
||||
specVersionFilter,
|
||||
'server'
|
||||
);
|
||||
}
|
||||
serverScenarios.forEach((s) => {
|
||||
const v = getScenarioSpecVersions(s);
|
||||
console.log(` - ${s}${v ? ` [${v}]` : ''}`);
|
||||
});
|
||||
}
|
||||
|
||||
if (options.client || (!options.client && !options.server)) {
|
||||
|
|
@ -405,8 +483,18 @@ program
|
|||
console.log('');
|
||||
}
|
||||
console.log('Client scenarios (test against a client):');
|
||||
const clientScenarios = listScenarios();
|
||||
clientScenarios.forEach((s) => console.log(` - ${s}`));
|
||||
let clientScenarioNames = listScenarios();
|
||||
if (specVersionFilter) {
|
||||
clientScenarioNames = filterScenariosBySpecVersion(
|
||||
clientScenarioNames,
|
||||
specVersionFilter,
|
||||
'client'
|
||||
);
|
||||
}
|
||||
clientScenarioNames.forEach((s) => {
|
||||
const v = getScenarioSpecVersions(s);
|
||||
console.log(` - ${s}${v ? ` [${v}]` : ''}`);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue